epubcheck-4.0.2/0000755000175000017500000000000013017276730012756 5ustar eugeneeugeneepubcheck-4.0.2/COPYING.txt0000644000175000017500000000205713017276730014633 0ustar eugeneeugeneCopyright (c) 2007 Adobe Systems Incorporated Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. epubcheck-4.0.2/docs/0000755000175000017500000000000013017276730013706 5ustar eugeneeugeneepubcheck-4.0.2/docs/ePubCheck-4.0-Preview.docx0000644000175000017500000042653613017276730020354 0ustar eugeneeugenePK!z [Content_Types].xml (ĖQo0ߑ_QnH{(W׾4m6Єe^*%;[^ݛ*9,+vGVYZ}\k Eېy%2Wy#B[.Eb`(Į^$ݲs/ZLUx"R ozĕ2lR!W"ྂH_Id1LH#zZ"{ۛu_8("l' shq X5QyOxr[#?[r"f3\ȾTI SWY ig@X6_]7~ fˉao.b*lIrj),l0%b 6iD_, |uZ^t٢yǯ;!Y,}{C/h>PK!N:C word/_rels/document.xml.rels (Vn0}@~nSInԇISċ1fM~7A!d%Dur}8pMm19 @r Y= e2crzsY)Ek"MLJkۏ^BLZ+0K]Ж@ dy3xb3<k{<>+5 d&G6L`criѵO % AvJBtZ!5n4I4dŚͣ0ϐ__ɓU֥JU)n5J[U =2m-.\cwX~֧R 6\ ozѠŏ & dC1 [Y\Wdפ1N8RLxmc͆! aTQCUC[ mbr>Ju'i//-HÒ>#'>1XxB; PBDUPL`-2zNZ">үLyyAñ+nȫGwPaݰy|(T|{D#VFhZ^hzH$t@yKtD:X y`_8|级^XjH$jo^ >v3ݮ H nf9쵎C:/U};^˄q6_"b@8m+ɪyVP|.rظ*EP W6jiXBKkEr8i ^u_ecRY >Җ;NCXTѨE~A2^SbjuԴPVӂ!fUY2Qa @s[=WO,3Rnll;>8jCbMPߩHj81\"o@0 oJH4|sЬ$'@`FU|Ȼ5H E(]*8J/aXE=C<*I==\ck"}TrP:P gӄh3phr^N}, XHƓ]z  HU*/D'0^NX7*]%J2?b4 L;z6N"&%8ֱ/tfCwh"p5&vzEv/ ~muo2"S4O~ӍE%ds'HI#X:^ QV-b;2fA`jJp2[@S>ސrAQPg+2q,x4 p =~*ܝ_WW '&\!7}Bz 7} BɄkRFJ m'=Q]V'%{4ĜIDDV-`:%^:XZ, j"K>ꍖqC Ĩh^kߊ3aFA%q?[ S g@TG{# Pq~&B;o;$ה:>]O< +} cJ27Pvp9h 4"Z }h㵦{ɼ(rZ]gL0D{aom--.6Ԋt32̐\V~R+S_qD$.5”pӒUTỎ6{B1 V,؄Mø"[g\,_Bv ,ARS L]9 0ǝüi#<~d3!wpFu$n1fSLlZhOO8=fg)5=Rq2 b{b+Ȳ3<gxPdlx`rx9rGf1CεɞmUqd|<.4!VxπDGЪK/pޟ; !*6J=\C`rݐoGW R UåM 5? X;BU?gY)Y  P1XY`Ff(eum5,|7Cab;xWkZ€Q@J?$;H /)s@(6$:>j^@M=LQ xEbDX ;9A/hiS݅{Z?OVgV]ʄQN# T#M1>fZSi{JG} ͞6_V]_,XZ Ծ q]O Ս^lmf>0k?Q8~`6~_`;#wzOPxyOdlmU]?+J^/}J&?}rȎ0<'D]ǺݛlYNtP%ѦH6w_q}~!HJU]%nH $R[bfe5+E5UFt/4ePU$[5\Ћ6^f_8.frPe-شs_@WF) ߐvzPv^ݪYٕ0%i%Sy(JZVR*d\Z#}:| lh˯G]L& y3D5->؉SdqoU8QmgUc/TNE`{^IRW`Pg9Uy`SndqES,e`/?ȧ2 b~mͺE.YcXt-QF >+hIԤ<2R,[7;^+DϟFz]GAæ?7a?Osؕa 7VEd6Mx-IQv*fhǍJ%WǮQcwWb@;Cc.*ch~n9& 9'r"h9ȿ%>HN20$}/<9$U0ͱhg*+ec[fw2g+x)oޥ񉮢OP !K@+`dAcQ X* kSԵT4[A.& .N43\z ׸7~x9?h-,tls"s+ҹgW'xu.W-:,TKe]oˆnڲg,4}=whQ1=~B%YAXbj4]Ybq0ԬЫX !Ckomc^R(PD\Q!81K{k]/|D*UYteDmy &QfHy*k;YP;Q? Ө< X]@xcF'<@1-ļ$mT+aX!PL~gr n ,kiN$:g0Ov[w9 t"tNt>a| q0>L q)cơpk5ZYf򺩴M rd%sJ5xa`hCFW;{cѼآiXb$hE 3i:!d!beSٸbYPVTr+vObM _,Nd7}35:CKI~-B7Q CB퉊9A.g`+'i_1Y,ڜpm=V|Ptנ$i=.*QUFP9=YEO{>`-֌IOLN;J ѣ L6g<"{(Hs&Y9<JkmB/*[G&M#Mg#Gu]|̲Ds8axkOԾГCo3KCGHŖU>D譀T6286>d Զ@ۀӶ.0Cj/0L}LݢUhuuрRn`ne%cX>#mFgYԄv#8@\sp-A%%EqwʲȲ$gc/o MoqރG\9X!t9[wĕb+ xpuBIEBN; "@d#v <7T*NSt;ʥdf<9;x͠mx :Cn2x|0d3Ir{/%o6{jFb-'d #b c(JH*Sؐ'NtzGkQ4E):jbJLjsc3^y.%4ƺj/υ#y&k zzMAG z@iGX]P;D4eoGUgRE7?UVlYG!%$oHqH =} t1\U,(wi2 |.H`7yM0βZa\?|i9ܺNqsYZv3/'-|rbKy:cf/y|(ިиfʐJYִ}Dik9!4yӛE&ݻ^XWg$U)] ^ɝzX_2htX>X3IoTRF.y=&2Ysx)F~xLYپ;65s%OGC+8=Jwzލ.nǝtFҭy0aP]t#V:?2k=_$rVE;85Tzǃ[CW.N7v|k^ҥb4J&u*6_F7V~wmU|˗l)<9nK_nɭr}5e/:j!uF"~/ǡ]z˘]=4EmTC/>kP|8Y/ץɰwފ o_~ױJK7F+Dz]>vsK51(7톢vY9bsy2cVzȏV+׺5/D1$ [XiV̚z(fiTj$ucTf4I%9mS=;Bx޼Odfe^n*侟\g?8UJSQt̏{a,LƯ bM4~a<7Ƞ/F&xv ҮPdB:$bmEJ^F}#Vd"i dD^Py ]" )/[+GIb#{D-^n7lVhnLymBskin֟c^d?ܚv&|6@*I]2_dṋ2Vfahi6M~r+s+2"s+2"DXAd PGm&JMh6^vw)H-(%)]{z/Pd~ЄB!>BRk) GJuYƁd2U2jW _3u@1(Jlؼ@rTH7H[-⪻[9TG,ًK8j PmԩO(ȿ+z]Բڿ ڿ3u ඁ'&2v)+.能Drǧ}7XڝrD僮CCt@5#SQK?@vFedȿ>+ _ ]g"4q,jϦƫF λD1hf2'>֤?0cw8~ʫ_R^͞cSDSgS0sWV V8m -> 5mDizLHńEA'DfzC "Kb;Y?df8bO2S7ͯ>#s .(AĞ*3]~\s{x3z#kw'8)1:{#ONi:ZUyWM,5 5(*NsdY󑫅?af|=*<*vL9IFzfJJА Konrs4 k1Eus|P3NڜyXOgxA [?GOe@ٛ rq\(l!ۑ%ҳ:82;tr`'ɥ~'7̕5|"ŒDCaScs[7ruGxս6!kUxQt$}''Y]}É.;Icq2Aץf4-Ŗz*>cq}m2i|#M dԋݑpPG9v.]X+KC7}'b"'Jҋ* n\kOT8qb\9g=o=fwpFl=V=uVWZ>4Tt2>ah F^2Fg;P@JCQOFFrH֞ߏEe Ow`珮.L69 m䙛svmB.y-BPt؃O؝[ύ=Icw1>+^?Dk۬z=€u8{ ]׉Y`zرDCa9kW܊D(ٕ++)?a aKEʵa0WvVSKڏpyQ,k)OyFuCP|8ʚ`i{*R61h>.epgAS~ rif`ˁ"Sˢ4rS %ʚl'3G lkgN12|*V U^enDZ -Iu9eMdc$R z| bG-.0R싀?Ý#?Ӆ{qCd vB0P!l7OrI3eX $OI aQt3HUHY/*]oV|6Jl 1S8z=G״IPkjd[ؘ$;Ϙ$K 4`*mS Zc? 9^`)IiK*k&O$pOptU R5p\ԌIo, ZHvS&MT6{Q~! 'HdJHXYXM}:y!9̖ T­rnX2D'qA&H[B`n>^h| a"lͧT;&-NLhèaN aqS3uX@gs&ҒEרg!Zͣ΢U*D3\];aNx}Pq׵ĉ^K0 c\ZMae/,Lsպ >OO%ZPlj^79_Kfq"R:U B8>E<;4v/dpC}i@1-!+HgPHzW)uJ%xBoԚ`K#>M ^1F) ށ$N>qVms ~WOD؀]Ia2%XH`8$5c u6XƇ;y =$mDZ$A-+OE+0O%̖?ixǟ]w[7k7{qjo⤯ p't ˜0<0Se2=|-11+D؀<Nh*|}<6ސH,XY/7n+j蚹?l qުaUҟu(D'YpBN/%$lSnRk\6?΋8SB4Ö2J⫰brR_ $lK{Xu3UskjSSY E=aD'ke\jGmTypb6\wʊv 9^eD+0_hpH#6`inSp'J}͝$E9ة68exzU$΍xm4/=%)xG; io4o{w!( *#"ImIihbyʐ "ԻY5$HM5|.g{Y6ΰeB-vVƺռ/$¶ݫ͒)V0-֔a`pwHpuz=9eWd:.&]_춬eS`MYgðRtR ty= •HR>ZHF$ i+]!d("g9+L^}p$_w"qB-//@M?kZ}0D4|-OS3Bo=oC>apv .vwm,TT:"KI3™n5ay+)S;P!-!` g\qXʸq 5Z.YRlō2c$>zuE5)?~9qo9*lIǨV)%0.M7jl#C_fSIc9^Sũ]T{Y f…s G "9 ^!j>u BړQGΖP2e* >29(~&y`hq\][Õ>kYsʧT1^ .:{&XrY@"`DĠm2Wkv@/SbDO8gPg8NPZ- !}vJ%s3A"S`x߃mQKAv=!7yP㪖"NAO[`zaF"5%\o#L_?lv4\djYP~MorR }fQy0X 6`k$B6Bd+8]+nR,<=K0F \F I> 1C/ !lf[h>R:F\ʗXT_Bx㏞E,e |hELa@s:SnMԜPfw6pxދ<< FO@P4<5g\"@3*Ė ݹÄt&NwX_E{gt!c[;z4o),\Hu}RH>vLhVS\N'wQCz1LbVE")':^zFE7!9ƥ5U ٜؓozWB,2A7|:L<˪70޹E?eԧv]~0˪QT_?|W+/wYrwof*; zW#/\}4wu2'RV r2ͻ3MIxg||[Eˬ_+.S!Kφ6"[ +KW)Y,?Ɗ_6!ÁU#UKG`V:)l XPؾ j]V?91ZyfWYmKV9ф߬ +E>HDCHV=]Zn? G`ʛd1N.qmR '%@@Ykڹ@J&{n6c_{B`#Z#Z0yƳ*#{xKǾz| {M!ݗxY~$B[[}=8剙f: `ZeJ<$LQiX>׳r}:fv: oU_N/+AʱS8e mB*A|J2)Z,BpRZ?Ý{jWHR fjPI6]3#~%Y96V4,+}L_/8379 |;nJ2FHdTCY%Y-$5~АjxՑ>Γ9&²Y ~e`Ivc"vuj_3#vJD!n}DΒ(axH,(`AŽNf?G^ QL:5NwqZ@HͦC%yH( GR "J{PsF04lڠJmT( vsT-UvFmb1 p,Z{:xe'.aAX%ll:qb6K줼3WP- ^<c nd*,zskڴDi¡]R$¨WzD/u;0Lå߂Yq4nyI=siwD`mP=` /ۢn,h 9/@~5e:7ɱ~my+YّbzhN%+iേfA%rwDР)Yhȍt]XybP{ilru ޕ$Bi|n+ ,IevdIH*߯>IJ|~ū#썽0SƅԎfTʭ5nd4pAAnIh&)6鶣h3PFmf"H@nKpf?΁<$s{@&/YЖVjh3v 33{Xؽ0؊{%ʁ8_ Ɓ;'ZIr|Z."W%2It(6+A 992;ZSpGa0x5A[~5\Ky圷="a;O*]X4ةFو4m:H`MuU9Fou4vqh b^ U7/%VzNb)$NSG Pq6$p ite'.> 6(0owL82IRRr?߉q_Y~vtW LR E>4zkuFÔfG\B:|Cwsުe]QҀQRӵ7vYP[wo3|DZAmnMo~;̩7YKr(sa mX%ԎNg.H+Yth-iyHO&fN\_IF4(w}iD,mM V+k_k΍sCAN &OelҌ;iڪcBR;\Xi{zD. ~1m8m!7կRPј2Х{ lC}$GiՐ!6^]+.$rR~ LcP 'TLRR xO$s ywH7:dԼTD,&";F=Nߓ,]P+ D8"oI1U]<Ft3ޮD򮊛:9m9Neg~)ZPm ST=x>U&l(M|tifS'?B:ё]Q[uz~NCklI' =/Nng~rosL~UMl퓆G4{ڢ@AͲR,wM0R% CctRz?BUu0 żyo!tڑv *,lfeIثyenV j{QR%v͏b5Z(=d-Z8K~;EY ][oSj_ۗ @J%|-T>ږսa=k@K߀f9X U?+a .Gi*5se9Ma4 4>Fi0%"׵ZגFjgܺm_KB""&-z MhRdќ We3PXee^4Xx3<\2 A[mF (nP'!it(IbKKA, iu]LE$؟hmze]8ltZ%D!-i=oe=*!)TR?edfўо$>8vSy wV߾}يΒ !b`bv%o/8kMbI8֫/(F+-d%lxBCf7 +]]h&0@dREuGHA!8icdsvf;.9v7k--8[@H?u#>aX:ƇHOiQS\k+ mFנb![Eے \A^'Q6͎l5t[MԘR/ \9T¹ڳ%z n"Rx6#x\cJ `z1l}G;?>ZO4XEی1Qِ,}cN2|*)D.ԟQHQm 0h %3~QšŸlQtJ tJ0^.Pi14~{hbu)RADذk2l@*c47v?AVbꇅ,g2Z' =EE/ JɌ8?ON98$iFk|9b=B '=C4`(o8A${"<rz'WhM,s-IHzs?jy|e1O\t 8|&;-fP$O$-t_1ϴF&1M.!%y3}2ٸJ_xh|jf` ӯXūՒ#t<"DNZlcZa)7|f?NgB9EM8v,xL4*q_ܑyYʝ(LtT=Gnw"AA@qpd]H>/gZ k<_}ȺTeW f 4.4,el&%LDdVHl'zK 8ʺPy-(LV(+@D-Mb&/!jM??"^BuDs6P~5?;_sйn8རN4}룥!3B{HvRMpISqg{ܑ ;Yo.Jw1,ے"iktKEqBq]_)XcE6ol4 UhpPqF4YxUk# -oOִ8 ޼4Y*gyj06BN1{tfw;tRR`E=Z E%EcPAqip&CM&j%CYQF9Y2n+O`y<D]L3HEE$S E)9 K\bk7NJ⢂?OL1#tC#af 0ͷ Zd4xLWA!YF!(c)`%u4 t*+4H1+wW(V*4'D䓠JK{h3Gr*AjFT'UetpZ^Gn5}xJWbVQS)}*5?/ҢH{wq"r˛Q Eի~2M!?V)Xi -B#,f3ASR#OCBE:( /PK!xx%word/footer3.xml]O0M4dwƏЕ2=M[{ 6P=ysz:"T0BS2V)xܢ:2"@mEwY>Z٤4Es:҂IbCɩ )H y)5 _DqԾiYS=U:@3s`$q6’u'K.xv41Ҩ45!VPf◼R2ڌ05;ҼŢTeWjo, }+vbd )uhObeH4GI0Ǖf~N9OJ=4ڳZf&PM۷fF @y*hN${Bu5EQtyOQirR x16)zp 0GNpjFhUU̻9}}i YHcuz"4 'tz vB3(}1F]%YGPb5P:\qPp5ro䖵X3B2I}B}U1Ĝ* FoẃbR0KbG|~ИC{/#Vhw0^KsSŌ ^e52jen$ٜEԦhp ,` dYҝ3aT2Bip3dM;}u{Gb:8^ftg8ڴ!]5-krhHG=O%~.7LFHau27l.EerM u`DY;juTr$6Y|m7=yo/U1<j6c8eZ,ǟ]7>`ڼC > )`2 W)ߒ5?PK!xx%word/footer1.xml]O0M4dwƏЕ2=M[{ 6P=ysz:"T0BS2V)xܢ:2"@mEwY>Z٤4Es:҂IbCɩ )H y)5 _DqԾiYS=U:@3s`$q6’u'K.xv41Ҩ45!VPf◼R2ڌ05;ҼŢTeWjo, }+vbd )uhObeH4GI0Ǖf~N9OJ=4ڳZf&PM۷fF @y*hN${Bu5EQtyOQirR x16)zp e:hIT+7.}N,d \#a1)K8^e6cLQsx 6+&IX \.l碦#'0;λzDP=1.4FKg{-]Зm{_z4-g-BSiD6oݮތ̣/{_ dn`W) vsM%MVi?:v="Y!mc+xv>olHn۶HyqۀVZǵn߭\c!m'P›; }RǾ71-gVhb7,'w!CǑQ_ζ-(u[qV yæq5vPK! Ubword/header3.xmln0E`#P ט`XkH i`3x<HX*Eq) 9WMQ`Q9X̢yvz2k27V6i4MQN0dPrjBB CQpp&gQuoeTDĢ-Ni 08YbI̪Ow.[{v41ʨd+h2jCGy7 duakeKw6K^RZ~_Qoz0G7ARlw8̶#-b _sJ$j4p7PAj`3eѴ}kO辔D3H<..&2OI?(ί ?-XA*tO[^Z0&"E Ͱg;ڵ{(PK!e+word/header2.xmlN M| 4Lܢ+8h^ڭݴxES8;pݼ+U::E񘠈kЛ܍Q<yܡŬNF!Z6,E&ر+J0 r?f0``3kvNǜVa8~[(MoLjh+ֳ32m'85'`t j8KV epTWQs#<&dO)"d ;Z]Vp2Ef"97+mG)#aUX%c5.uLƻjNKI"HƘ;' 'f rY3/ }\~0I/Pe(BS?d 6|Ze[cFA7s͹NW2I={i\-ƦHcqw@ͨ!\?V"*((*xLfXKgTQ9ՑC9fqOE[*2 gxTqPId5"R?f hcgG#(Nje Z.aaD yo gquzC";>'k8`4|pPzO^Yض4>Ŷ}C*Mc\@A#1vJfT(,uC9-mQ"!,b{ٽ5^o ?u~'ACz͜{ЖÂp#ʅ"R^+8Y昆Ռ<5n3$V9 ){ }Ͼ^oxAVS)XUj1HA.oo9>Ua>#R#r6l$u{~rɱ'xLT4jgG~14{UW"ˡ4hgR#WOA c=%olRfR&ٚlJMHM1dX&-#-J9W!$1'!]H=# %n޺urh[:= YfYlSqIR3\TdbUZ2{4 DGMn9c /Tӱ::Vp+8@ÏXӔcoE}U7 a"7 SOeṣZCdL1bXPstl#l[yCѬqf@ PGx V!!h*+#L翂9:R1! 3)cjz#j/3"Z#dbЊËV&<]F{e#tF@я10(|H(Fv>DOj$HRDHhb3 A(Xemg4Κ.5Ś+ 1RWDnBz&!8I4~L~!u Ec}#=q|A/406D;cM0tdU =TyjrB%P 1 0m0(jGl!{dz98+nX))Ȥb%gpVm_+ZM-ibPblQ"&35]\iA=8=>=xp8 ?PS61۵>ކٗ* 8뻯KE{_ˏ?пߛUqBs㙆ϼԹq}sx/ՄY0!2EH}%'}i8=raÅa_ȍ7 )f0{jI6a Y$LR8s ;mӦKkwUeB F8BST3Fx@VXJ|*syA1{C Em%z-V7}@ ШHE}_JDHiأY=oXG/fϗ/YgS Bj(dZFHЪ*#_R/%5:R,$hY^zxOGTZ7+vծ˭nե:Yk_} I5~]|+z-B7\ߗ3:icoލOD{Cij<y/xՎ=t7 SkZ{./w߰xwgo:fUASJp3G Ӹ!^pJ؃ACԮMe9{c&HKOގ,TpV5)?Gz H$zDɩq 2}S86rGB( A d@:刐KTBPJw9@KY #ޠǛ=??A {j"۴PhDtck j<kո?~cۍvt߿AN% F!UD =!@043YC+U\)i eBi)#+ۚfKK1f|Rh{-(;$'>)56wr NB̻BHEŠy^Q]b(ԅzBPeI5{DK8? ;Zx8C怀yN:Ѓ=*20LfZ7C|H#*mp3_Xp▭٣Wp%)HioGIbTϴOv_| +22Wvuս{} nha#cb"#cEچ7qO&ᨀNE?x*OMM`qҐѪӬl=jWO>fkHꭔ{7ܹ{;n@e[gycKlؖ|j\CNMwC}lBH/_ܳt7!'pz$m^e~ef/"O|7|3Dq,H¿+F En̨q̃/y8qLz4D-d3 YnXLc<[X,u>{-Clogt=$z)nсg{{ۀqb# 8drsxNXm*\\5D E+Ҵf|~JmlXL({SJNrpV*}f6u(F5@MIFlxJIPd+Jz+-.:D2oI {],Z-*,/Ta^^Ћ+RB=]6Rݐ9_Z;‘p#%pE`lʒN{lN@W=W^,\/_@ Exp0\J*lICwd!oSRKe.#= N.Qx*XoN70n䫿u/tXZ㣡=>Ueʦ380 * x#nXI1I;xri `#(uЉb{6$`!1 JvK]~JJr%wL-}q``U:vc͈#" =7yIs a nZG<aH i0; G?:$^J!2SpꕑD0(͋At* _{: O~;$@`5錐\m9tv;CFMhPjrHo3>sHx=܈ ۉ CƸs!!὘;$#x(F 6A R!Q CBrE?}VbL LPʦCkH|G zy䤄VTbФY+gj!KѲoc R*42#BZyFb`BG<~{lQj@w8E0{.^%ܚ?/&}j͘)xz+ݼ{/!~Bk4JȡT:u4[wc"]ze߮kv]ݿwysڷwnٻ=v߶nw=[Sn]3)) Snͫwlg ݛ|{;7Eܵ]tuk\ݾ-wweǖgc\WN; e,>Km'[/Pddwe{r#J ڦb3& МH/Ӿ`B@6MM2:D\rB Dx]+_Ђ7;g2!:RLk`q  Θ11w̾PW^N}TcXc/3\8Z(|BX?\ m >A"BG d72Y< !CQPBrOgai|Odʊ;Szle@KyೃvÁl(N6IWn.0//u~ՋfM7+ O>4_< ߗXnƺp6 )^rǦu"CvVdBEHvIwtuʂ,+G1EP-&T~PL@,WXq2%Ἣ%nsxGt|iJ>eeOWyxsNѭ8eN~.G5:T l&4tu $%UJ u"}eH8SSGusOqn߼NT|j _{̔*Dpҟ 'r"%;ǭ11v[AFakPy#*>iQbT(&ʈfuؑz89j@4Fo!]e!}oX+-6VSU/نSS _bSQ$(9&^dI֕hhLW "'C;%{Po||ɽfz.!Ǿ>b &4a| ,n @ؕbN#[(W@ 9BKHNf/ձ@HϤZҺ=߮`|T05]?)&Bٓ^~@AhTO҉f;D۷s~p;6۹WLo׺vDpuЕ׶nI6#vDIBFVI*CeX*.6*P%7FxRG@X3ݘggyB=,z+ԭO\@T7O_DէH] $zMDB q8[ 2@O`y.E 0O|_tołNe`Xp9oAA`S@% l 2aF=GKg4Ŏ;Q3=T`5 d 0@B~ށ~f_K %5g&JeM'J_F@_sPs}0ƛ3iToHcqnɈ =?'A vT{d1d)V;XV>M| #w!^asf6OON* 6>l6Khy>B{?Ta'78!)8b#7w"f5݋%:.Sc=0a_y?X:x_qS9{(Ꮾ{"! h0nƮhC4РZټ7>}H#&$;p;1zf|<p!>A>l g S05|&Lv¤o?MM߄kďǟ|A,  B-EyߢkGG4Vn4C,ZӬy߱K#7 (B^j љt]ͪUC 6^F 0a7S'6{ª߾Y7/P`UdV.c`k7X7te]U-_쒽Qp$0g"(D4ve*<ώXq{=|ޱ&߰^QI&:W1Mn,vaK]Lz@l?4k ,`YPEǬ1%FTyvl/+PeMemaUS# j=&G}¤AeϲRÁGLb3ޔ| vP7Mj`@h^299rt܀41#ਃoGBz|I'?OH ެ^VA?Yݺ&Z1Gܖ kWiO?Ɉ@Ʃk O7h";V7r ᨻ5\ssfZ.VW3+,(;G9ašQ&xxyQ&^B#sm-h n[ `Z\NhÑc;vd@'a;IϦZ+P{e&l?17抅%hhʔ1lͣ)J&R 4e$q-4n޺Kpm4k6m I"G{@r5jkߵWv=L)mOhOHOHOhoP0\!a^,CCBC,Bsk:8=pCk;ȓ1@m h;,%4+8;nB7$++8;87,7 @onn ꃋ)̻zImѿ'ܫrIhS ѬZ4MN8ɩogOemE/Lܠ l7!G¯#$.@"` ݹ~pߕ+Uzq}]pzetO9^9ki"\=/%Z>.l ApW $Sa|{Yg0y&zۥ:kDR@ŦZraNmjF K'T~Sْcǘs8km"'{IzcڒmF$$(#'fuXp(֛$];rv>ȁϿrkTڹu#וNa$>EP(>J @7<{h?hG~2ӚG$ y\=V}o^@ :jsǦu*A~fћ_Az'_8{*7V.t󖱺?Vܽ{}_L?[&TxC^!8YV]MtRR1 ye cz|QD(<p8M'hIp0l4vg JZuJa?ъr 1!+4W5#5XfKܠU93  AMHI~RӞ_}s \h.0or /WXwXn%.G&eo o||D H&}r`F@h vJs~wAG㹲箟u߼BK,abJƵW <,<4YjUՓ^6i sx[.-T!QL)!@%+?^)TX%8`zUP3:Ie|ht]iF9{M0Okw:10>W!a4h2 P0QsSuuOVO<}з3|##D;&%p%wֱ2ٶB<! 5|Po)WL[Čx;ϼ*jx^:o@^/U%/ ?Urێ]Ki۱7^NIqs92E4x]nuRزs~70F P{9ԉO a W1IwD}6RT ݮ1i4Ǥ3M1X&(ܭ+ȳ!IŴ|kJ` AG4Xt((+5\L ^PW{<r,\:ooߠ/@~B}CBC}#Xu"Qx :r J9_7!!! @%Ĝ/ ) *X$_jnԨY5j@g.Qw!z=y]ǿ Ǧîw7r'ѯjx7,19*A=9f ]ίt}|U3?Aó}9bć?f~RzQsA&[ч|f/}( ETZhazvL _N\,d) 6'ԩVP oˋ(Tģ0JHP[c<atPnn΀y-9ܑ}wMq^!8ttĆ Yh&>jOH-=+T)ES"a񑮊2UW`bn7Q7MxrKN؝? 5`fF.l{WXpUDN. BYIdD$_ɲuo`p.l[ErU.UL.Iްj$9'J<x8`EhKpFzͮ,;iUn#)?Kkz*wHAfޮ\'kwI[ j1QT6G_ރ//3QYKQE\ thy hHK0F5ƴzyLL9y.rO,1=>j6ׯ^J5  `OsMy8Kz}׻`*kޚͮ'/2,H?g㈽\}{Ǘ_O߾?Q{zO֡͘6Q>w.E󿟢Ғ5j8dɻU!oAcϟ;^~ nu@`c ,YH#+>/?^z -,? ?|!I%Rq 9D^6_T/!}RtL% </P'IA`eMU||y]i8\!'@81lD=W0:cwUMAa 1՞ dRUܴҦSaRS)8Hq/? ",$$IdGuJle9_e*W<9an+Q?_ac$ +1&P@i$!A?_]Kks&J!΃qÁv-܌ʡͫbZdFv{ӂ:u7jV2q xڍ^BN.;>@p|KЋ7vrf)T?#`</H=+|A*Tn>wկa*ͦWi.eSR2~3DNK3`=Wj'lrI4{]Ƒ|cǎ珗|o%5U|Ŵ=zD~Cȯ}*Eh2^ȋ$3:M1 s .l e7VӶbG`gNBA}VGX%K=٠2H/ob܈I0~727rXU&U({l2&aPSQn+^0=.`y)֕fgWx7~l_V7A@&h؍m"k8%-%&ʤڂr'ON>ve: IBśsس/W@X$d EGpD/&QKYQ0Ҹ(~Xt #SA۵lms څH-Nzwis q`9 r-gYZdިg.~ t>Ȫ\1ʔ,GW>Pl7Kna;jF==x,8j#ͥvCRZBU&n(l m7r@&iO I;˭J:NJYsrW)8d%K8[=A֨/n`2wvtz Y/wr/A~fŦMmOV]cǎ|x&B -DQĠ=BaEwm\վ݋np@oK.za ”'wnK' iHՎ~鋢MXVǠHxF'+x0I0&`hȆL7 'S'DVpo).l75{L_B^6d.Yb!7Ufhd w"CqClNÉ:Y4S0I%q"N?2oABf٥"ǰ(Ay<˟ Bqh(9c^XdBʤ\>s ErK8أ^ib:2 @ݡu7c,&i72Wd tZb6\rxwU&F$4 +]- $am#A7"}(2SoO48NU|t,a9}n%i7Ú=>=eAQBO7"?4_s4rjN> 7nTiM%~d ӀX!W3U.Hw;7n׮-Lڹ'Tx˗-yhT|Fxy''&2ZSƊЈ%t*/͆Žh=e2LM+p8*==0s=`(dzSP`Φ+6Oň( Sq3܎٠]|Ob <9NNI ,F%r1R"eeBmuUP@Fz|I)LJz՟`[`.,&a|X.Cpn7&SaIM0q Oݗ8\=.PkCѤb 쥧`=' -T9u؂0Ȯ8`~N`;I#FU3z]Y;5{Ǐ? &BҲa.uTIA5TVqvlXݦm%k\Ԟ]pz** YXRQKUSOVAUDȨ}~7m K ̢EA<:Qa]9)#B1ɢ,w6cmӒ1S@*[fr)G؋iHCŇ: ! ؙpuBbUC2z| [I@PI@$.=iI'& ^/EL%, 푵䝂,1XN ,  ] Sɥq- 9RcZ*# |[-1'rN5*STb?+CRbTׇE&~Qv ?Q#9fBta1G$\Fdԧ4b)!|$m[Io>G?ݵ>s(7嶴g=[dAToY996r_]>ݐ9۳kQ[*1 =r8$iQ4xE'G`u c†.mJ;v7?0@~ȀBx7u8z AܿNB9?;;1v$`pZ5l\76m:v~.ES={T@=E>yKC= 9:v? ST93KK$7d)!Ǜ[I! g ԑ{Udl_X&GG#Z7')i xPDHdԈ B#!-1Er@\O HR^9I"˃x($rjYCI8mtl7iqs| l(ѦKc|37Xz⟘7Ň+hbVQ0u8A\ Hrx 2g8Ø2uzCi'\"y_b;c]ixbzE;{&#f0~0KuWfg+lVXGܩ)>ʡ=XЉaʖ#x.r.NuUay4q9YUQha}mǩ.9hȇӪ"6,mFNJI d f  4v^. ʣX)^pV sE?@NEh5O)}b*>ٹNsqEaډ8 m#i?e%x֊mȍTBXr%#6)_&j2ؕ:eQWjOSFpZB=vr( 5̩hXalvԞtrT=4jDU<8&[`r(䢋M07 EŤPH6>&`;2`_ !4 J?>b-nh xÜz#r0F09dăa^ 0$8#D)2@pC9( B,AC6(AȱaY @@DW&{(q0;Q] dO(1C"%xƐi 4Ê*KW 4Bd.|e%a0 oӗ!: 'y_9d~fQgXo;HE=ȧW`k-*cöCrp!a?]AeI itP=HcJ5wpxQ /)*ٖąk1# nB#6=F|T|*ho`yOc*{I} ސ)aUh#i2LL;4CW>3nݸX _ 3Ad*l\E$t9ip2#}%L}v8^̈́IP*+@jga2%:*ZM e!>pKo>5Cgi?(#DbN| [V%q Q!pS =!J5lJXae4:"7cDq Z8 >*Qp!2ŭ`NpH4\c #$"(NF"f5 Y[lĆ!O},ȡ8OQJPf dhُRiGtjRF)`)4G# מ!4S瘍d\9V@4:# zy*?X_6Z @d-+G4 63 s8PzHpÁLrV-!B,ST딑FߣA_jt/a>#4IUN0O 7) d (XhL#t:ԪX##6ls̲Kfܽ:wq@T~./_=XwFVjodư++IA_ܿaVN+,n9$NcʢV2VXKJq\k*Чp!T!=Ѐ/[S QG Vl q&y\䀢9w5m5Q2酧;Q]S4r5-Ɠ}A/$fEl c.#;T2;1n3q@ky}HSg~ɞ@kR*FlΠիTձy C$Eʣ:$^DqEUb F4İvGvjԓ-p☓Q3CDy53D*uDf5XOW"%,ПLŅ%HtȋMƁ@}LC-?`*B,tRD@!B<'Ѩ4 4w$()3_`@pcwT f!OIG|Z, %ҲCbV5uXmwX*@aSZ5Xɋ`(1F*^"ÔN0Ph@c#>v;UF#%S)H⍝&qq O棳 tnx:m/r|Ǔ&\޸'KpoO}Pu=Wl',`m9Sɬ+2ir@ oʺϚR3C1wpG#VT79SV3td^;֛^'Ol0u`- f_~ٱk7ʓNP1A76Tp{tF.):hjpF7gbD6kl 17TQlc=QЎK:(A;i('PKy !kRB@.Mz2Za .prTCRgXO!v @J%f HaY,FB~e&a ˂j+/Jerxڌ+d8:g:`O^SrAsוXAB` I Ecx+26F)$BDp wED=4z>z89{ Qz4swXDMH~|H kwOĊvXK:.s A@݊=jDBkI)noJ7OW3''Xg*OIP9 `۶Ml,xR Iu.EF:s[>8>He?:vtb/Jyg|3^]쥵ňeKH(8bdQYBa䓯ޔrpUNYẎ%7v(%GYt@sʬpi#W]J済X9}ۅPr>3-^Rxǰ 4.EBBy#.jixIV`5ufe<7:ylb+Ҷjڴޛr uzISolD[f0@7RoY; $ 'tHb.&0*Nd*P{!5PՙP5d^SI) T\sɱýSPF@YX_ Zn=o#hAg0~j={%g1ўARQR bpGe|x*P?X'ΒXs Н+% K⢚='h^4J3ePhpuY?\PĽU^h#SLTM,>xS&憘Bˎ` 0Fĸ%qL2* w3FL jLdUY? e9߸BFӴd3 @99p$^iTH>"Rd]Šhԑ {5f0^j4…d 6DŒ (n4y9%C΃'@Vݧ2RاA2э6؅=oG^zGQ8V•JG\nZ.ELJC'i<{ K1'kX: 'h|ŵ3؍`t8WnRr9=n h ! ޳\*}nqh=_JJ#@u澌?Ua9C'nsp yN{lDGHl c;a'@p 0[5 iZO>i7w|I!p=Y56$&D* 5G)d$1zh& a*e? l`7) TA)bo#*S8;`$^&j O8eiT0D|J4v֚:I4cpF8 oIrϕ 4۩g+RD(q:(eq qq"5K9ȍU.o@`8L11ˍkay`K}M:qi(-h. $o޳]GSsɊ$k 9XKɓ]H&O%qfOGd$tCߑz oED,){؃&^1|{Wїصv59)3lXi( n /b sC)Oi6C M bHё+Ҏ@{Rbƌh(1*QH(‰%D'$鲘?k:!Eol<Αc~P2) $SN.lsH4.A t9)a|؍ 8U4ZTxg"Z`Eށ0zeOPDg-p6[ҩz3U#YQ޸15}6 T11L#&Bwg`vUHn҂&AD!H䵘$rSXH \(Ww.t!@uNQ ؃{5]bBK*:̑sAV- kYM}ݩl${)#hOT% [ WQTH/dig=?z@С6 }IIIl};E췢aqsBAjgY{^+8CTŷuZШ@;UT&6(񨖐ދik2R2 +yé:5|mFO5b^ٰp()M:>E#= QYk(<+*J6.[d؉ C3~GzJqф؊0TX߬J{6e̮+Oh<P 9)G)z ۍN@+U6}sLJQW}]rƃ1Kw ཚݾ-ԧ`S w|y U?K"*4-u[L㦭;bŨj֩װiKRC؆B=^jq&}GxL}GrsoH92 <1\ɧSM\ģ?fe+TGQT'C#6\ ")@ǐGgH9BBoik,QQ8ԅ^E\,*xY:G` 04+ {,,]Hz382s J o*x`">s"߫!(.&VMғJY ;0Ͷd|JqRC䙖&>Ё!%t{ȕUk*vx<4<ӣ1y3wik1`yqoԮ^3;A2qg?/RA><_='M* P=0 ?p?^?À׺zQ͝#ez~sG閜f=OՈfOHFNmRu[3GM` Qs#ۇ6ȸv.u%J§njZ4gsxͪlhA] yèG(_}lwdLV.[L?9n.Ą}rK{۽K`B捸#;ɉ# v{<6uTT%&Rtn֩]ԍH,8M]d}9nJ$@zy$% ڕ=& I7<8Q*Y-'xv\4}5nxNNߛ;orPG';[J;72,dNW'ۮӜ!KH06=64Bȶ SI|PmFOy_;|DS&C a$ޛfF-'zOsNwꇜs8 Nﮯmn_=g 1{a4 eG|+T`21K!Gj E1 m^EJp7Nrٍ?y`%3 :WvmD?~^+V#"f2|7wMȘ'c1^RcNmGJ~;1sE!||bX|l` Y7(&2w 7JB?J@G!Jrԃ]2։ ,_ uwJ}6;~!!!2<*S`2dN )5 p ? 6@'XC)SQo!Lch"{'A] {9R4TE~?>ja q ̒2`[5rNs`yRe~(Qǟ<(4)= U/'wyϟn?~p/K {oX杌87z8o:{qg,3QĢ7_ѷw~}zZ^typ]_Xr_]d}zs-҅o ?sg !:P vDqG6V9܎2ur:UWE"-b(5@7=W5"L=sSR!T'͛ '!XP߆ | 4V>ܮ_=sR6A9/дCg^,#-u܈?؏ZUֱu]:t1>wO;nϝyWW4մO;Nワ 7&bp H4[3uwGN;r9: ha7jߢU+{sgAvrkFڄ_l+ҌlFse3:\-"57 6t͗E())_/1ژG=r ~'u^w%>%'%ӽ# ~f߫@!#gWN㵴{t0CB./_(c^D!ԶᅥI t]STpVT(NMv Ւ?:uKoW:h73OF;zh߉c?;}իmΝ%Q =ԪIalVXg 5kx^x `?|3}>}QCEKIe M'0u1kD~WH dSIeծ+jݵ,`c~ANԏG n|}pW,7 qz zI^ݙ楳2 :8Cp[kHo/sG_}>a$2.) llɔxaaiƘH\ag/HرBy~ޣѳYi&؇CAx+!#vl G7%GeG`dgp΢ys2wt_Ur~׎mPU|7A(r)l-ΛձsW!㷀Xhu+m?yS?MH 3?RYFRG7DbYv-7PCKݼa]pphy#6mvfmL9}4C{C  u5l:mwyжcG'Cc1=1k8/ <G~~[K,um|-x+FFۇ1AK ܁'$ {jtq 9o&Q%bP!6=Z~G "^foMkW-ԕ~j)@DR u2Ԡ/26u䑿!qspÏ4ʼxJA`D<%Un-Ytܥ|-5Yoj"g؂-J5:WPP `6u._<**}2ܽ{٤<˼yry冗{=~K]{mݾSv"$A,5pps ~i6N~l]cF ԮMZ:)aTNUy߿N7:?C?_#cØ  O84~ =0߻g^n޹M;hoW^l>UĄ؋@7WPܾuD4~ؽ2;M&<5뷂{ZhoH0І+P`%, H٩m#?[}6NZ0*ۉhY_h-ayW2C aܦYW^|J0m&lh-#Ƈxbcڴ|2vD {{۶ "Q5*y];F }}g7m@Gb@gQ?x[ ᨬ;yg_ChۮKݹ{vHIeI+m6m3*H?~H_tV8Z^[*۴6JM:~llňڵh+0];wn@X580/7|9ipO@GbT| β=Tvt$B\@ ġ5{e_>KEta^p&eb.}ʍLI:= %c{՞ ZDJ _N/l=Psfgǖ%M֍ὂ4H&t ]p#Z˛Y6#vHkY|! )1V/pl=I38ȕiZd{%n`֏ kVj0rTlyS(]Q8} %Kݣ z9{Śx)&pPQI}OB˗.^b/P^. CBA|:p5|iU?J塃/]t?.Dh2)Z<߻~) gxX/c[9Q){.ZX҂,]{D1Vdڕ0@|-]'!f9%xw\fea)/:9޳ vl}" j,~ּ޸~ĆUnŊAߢEl?\YDxŨ{bU; 0bT$ 1H˪{NJ\̀YZqq'Sឪ4)y􆑷nӚu #E+$yQ.`PWu {Dq9z -Np~+']VvgB ]Fкͫmhт\ÄL5l{OՒu69he'˕-cT"% C 4jMA(_"X69HB#gE^,؅4 ^~ +CjR),l{C fH?"+,T/$F6+H2["ɬ~*jd %OZSqxk1[!:O(k.v8;Pv'Qݡ-[n=5{Jy6J f"1t^*a!g⡚t593`@GȂ19_rf߰Tlٍq{g8sέ&݁\=[!&Ȋ/XUH*!K,=q|b>>Qm%8>.^|LBJB{xzy[3Yۓ ZC!QrnjA A({ ruuȅB!19c/Af`Ǐ6tM\Op_PaP9aM~>>'[G J!fl3'O˗H"pZ>|yDϾmĽ,@.T0d_բE/;)S`#}BvbNVh0i #O@ *o-[Hq8`{[?.!!e#/__ГT R ē}_~S\yZmf*r~IqF'U܈LPD"̔? 5jUv\'nو5"K^$V"2E?=XiBEFfA# 'b|@!?_cbFG<[̡!!*U0ބ 5 #ZՍy;vqHR%7QC7{ZĻo *Xw6~%JA_ z ޫ7lq>YAtx"]Gf(Bpv___o_Xѻ(20*>6|t_ΖRxxA~^~$*/M7pIbV͡t=VB)ӿz,= ?l낫\D}ӜYϝwx{Q>>!.k]ڷnjYx_OXR>=WinxOg|"D)@Qn]a; <'`czf6/v`/tga7NL/8o.Q",u,N?v.Y3  AlY#*=k5=.ݔf"[p99AK:o<OCg*^>&k!S7c*e}9T}С W,_s1"c0mGFMy6NċI*WhmxLG 3*czV$G x3Nm唚Jf94@ʋB8|8r4lc;ܶl$V2[`QII\)9IY${ (FY;CWK-G Oe]C,8ƥp\zHSf`[C'W R襄8j?$H> fmu+|%^V&I $my0{pG$CZ1֫\] p֋[]\o'䉋K ~eK{BH %_j eAy)XM_|4ú~oK>ETE54'+NjoXnչ)) t:͠d30G7ҭ8]̒mдikquprGv y10cp+ {jL"!1q箽n=@z.6W֓{cG}?i)hA TZƩ񱃹gxfX]EO{;GF%b># mJn\r.1Y❾/y3C,6V4fhWNw;.nG, P8w笞:Q ؈f&U#R6kR՜JRMښe4N[d Y f %Ꝅ?6[+/ӣgǀ67A׹i"#= Te)P1}=0hǴWIPyT(&tc`n𥦥Pge=[Xv>f0T~aٞۗE.>>/aO| a/Pi9Hکoz3Nj qB*y ټ8T6N9$T,6HiY3*6Uɶ~=`FD!#^VQHÍ^#c5`Z4Q ~JG&dZk`&1-TzP63i=rt \i1靫h<׆*]M-|y0m~l\rC^6it"TGUqvi뚞1N+a;jUSur`XZ`3Ӵ)W;̋W3QXJĥA` ݹȗ`.zu]jn2`g@!#p,e(guia$6U^A3MKXSATlRb<>TǟN2rcsӜt.lf%:&ԿXЂs#zkh30vvmu_:z}p-rbdʋ( EFeplѨ^k̩),Q:z^ d#,z R$UU1g ])iZё7K8?=Ϣ`e ^OGyJP=pG:)N<`3&qZdiˡԫƃK1q5ZI;:N/s[Ur0eM|& JM]m~YhɽMTh7"2DcdQ bB-ugҫOT%|a8h%@TJN1i`d k|O@ H2exeY}2|+[/}O`3[}#j#N[}־<HH-K%$a@vYuh'gUƣ&5"PQ4O+RkQk'a<:X~ kKkiy'-R)rKvx /Uk'FE7!.(@[1,B_t,v fVU1*Lceq<(%(!3uϏׅ .-#kq˰Y:h:wLpB#u.@窥hPL0b0N;*FȂ&࠴'UI2BJj`T8N!3<$LjIm͒rѺepؑ ]Te{XLD%}V ي8 E O4>*5'P7m R53_h&x$q]#!X9 " ޑQKL&4žy.RN(#s 9Eune%E3m1=N5_m/){ H5,ۖڥ[Lϼ3Puxz&4d΃!G% (LjGSu"/e NtՎDES0oJ|RTBmb{Ktf'xi63V^$kRZ)9*%ˮv K&H%*Efrńٴ-A5"rM S)Ems.$E2bot22cMΤ f<ա]Zt6H $ɉW :Y! )(cEI>1-Cr^!CJCApI@33r8gjww@f%3E9QUY, *:aN$p ŎC*Ȇ r/[X-O_~sy=M~Nl=g 7dȐ{%ibk嚸^E@7͒ jUr#097@Aޘdʭͻ'0J@Ie{Rףf:_jRcnvF! ^HN;ui%MPX+7"QAp /k:{eٮk%2L{V%k|C$Жr]ڳT-bO5X|襠:}ڵĶ{ C'Va] ڝgEvtE3ʆ 1"mS"22y`RSm;%l׃(>Xs3YdT:7axsQ|NY`f]g+Y\yVOj;]ޜEN3wjj{N sƋp:m{.^xK[^R^ A ܐQm;"@u*N.c@r*V⥽.>SVg`ޞ:O*[^u "#*k}^N{0ᘰ>fs?"-z0yRp<!o\&X  Z\=HRz R~K)%VoIl\ I+NoSx#gImRۻs{.1ioٽW˪dP뗋9}JmuLiAo?KGAKVq)yt3u:,nНLfi"Mwb~d9 ߜ#"se!kvYd8TR+ɪݎ.zΜn'>r6LV$zoBa$ۻ{Kڵ *p%#260}{Kօ_/jD-a5 "}ɧMT,RGe:wN܈Yt&#/0aeăG-b?w|%[LF sq-9G>E(bV[#'9nH乖% c߮>, Ͳ(}}\D&<vl;V]YPL<bwj/6l?{6sBeIT*/9F =oJ2ɐ.c̝'Kx܄q˯KE6/fVq>|fP/^hy&E-[ $mnd;Dƅx\ nJ_6gʆ(G k0aVH]r0,в7[if[6e:rt9SSS3rSq>#=1;c|~wZzLq9qq2Nd$VhFz#Bvnj{q s 1`yh[ W͙!b,)?x`@)Z-7wMy:NwY/=3CȑOܢ^0FJڙ'i D?9-LM} ?kA?F|z Mq)F}~2}egIߺ7h_w~?E}}a:`{O/-Z!0ETQRC -X,4Gs)iѩW?;z:S#Lj9{١{X S}[B.e}9t><((LXY74}. {2 lR ){oND 0k%жXӟR3eCHˣv%ȹqf aVˍ]|ӑ6CEsK+ {[stKw 4s |NDb"5T K6ݐNJ=y-Czև#444'=$hf벍67b;a g5~sOg[q, k߾)dK;7,f9֏A:rv96̅ ڦz@@KZ,d.ݗ\[JVnrH՚U;6,{݇Te,]tݬWBBB\՚dJoW#͘ ۏ|ړ@ C v<[cӭiiࢿZ(HkMeM25[B@"bfKSf WќLaPAgի{ 8!G|1V 4M!SR0OEswѣ)T`O7vs76.w.;vtYAV;άP+g-OPBM:3\f"̎"7b.XrG!KJ oo>y/%b֥6Fӣh-tOHΈ=a};1(JFvvCHɠJ|xX: 6_U7O<*u'9/0ڇ֔wcoHNl)eꑠ>qdW ;哟o@` WwfWe?{3XmyM4ަ]<#iKӭ^ DAcn5[̥B1?r1o{W^3FpU3&h}nߍ͛;W)'d=z4D@@{"ЋI&?kеTmm{>a'& +5F8!Oۛ W4Yj-x5`ڌ~gK!^ހn4#q%99111>!tZ.%1@<`c d5{kMT= Zx#ԇ{3oh{;8r=!+_ y3켰n%J[]tW}Q-W9] /ۛ%7Hh 8 W"? x[H* [+n3=o'{S<cLܢ4Տ oXU/_OݒE/&|Z"H7Adx 0$a>ҝ(08YJLR @G7xYpj/nf99"d=`ڲ%.7&!YxCǪ̞"p!A{/}ʙC!((8 L+6^ ~8Y?sn"n. åf^K}޷у8TSz쭠^ؘkHji:&[̷O[}[jyH0yY^hΜ/5v9s [m BG|8 I{wcb =:uaXFe O7t$ bݼ };~ &oҪcǎ/vжmZмYf͚?{}v5jԨRrU*U\R*jqۯ>V=_y}͚5kРփW[ty=/\ 7J=Uɔ&E2Z? ~1,,L{<$;&%&” ք}m^ -z'v;+fKl$f#~x)lMl''m(fԌs󟓞U$: Ґ!pTϼlV[7Udƞ,u*Y.AFay7o&Olx4{1S7Gae!3ՖO5xlY{{En-ft޺/w. % S؅71:s)-gOۛAhZ1Ҍ8BN԰hG#J32|vqσR '*8y$sl(ʔ@^)wNiձaT:e 0L$AW񡞔Ο=1Ge:oNJ[pQqڎDI hiB[$ӀJ#9h X'][q'}TpO`=/M7qvk+K¿sNyV{sFp;sƅϝ;7eAl_.__3[q))))] H$LNNNKUVJʟ?y~:oOj%ݺ+W!rѣ@op:ZddKoIK=u2؃G? 8 ;d[ٚB ps)S+NѺG9q5{G2m\4{T]WyH-Q^#X<6ne` =ޤNNڶe+e,p#)2'&kGY;"', d-a,6z!A-Df]`b/2C\v:7b{͝4xcrZGh(o7Җ^ %?w]|}{s7 c{ycn3֞^hdwo|Rz\mSLZ  hm}&l2U|;~̵9:,BtffL$[իWݷ|0`ڴi?|… Һw`sS6H&Ӏ9=>pkOJǿR@C!dDeM8/ f )9njD6o ?sڝ㷯F6m '-sJ49#Yk_c`r׸ar3ˆ\6^V\6h&k/G7h6 Ggn)r`UQevjפjg\ׄߗ٩S/7եexwUƠ8g#c"<4?P0˴[{2)N+3yn&>{q  {vF=s2m|!3+TeO׾gWz6^0*Ft8iȡ~rp`&IN+iąMk6] ۥlJ瑍ya5ipB֏0]fC*/) p Vp3hpb{Ӧ>ϝp[\͵xFLqP ^61lMA޵ 鉊tJa(~gG 3#E&Sn*}WL6]l)"Q &Лw[g {qIK6D6x(l/ G2hG/F2wv؏$ `/-१,ƍWP‚W@z APƒUhFq(s z3kb˰ 3Έ5ƙRM) SZ:5Ѥ±DҋP_57_lbРA`y YX.Ga΍4KlE+z`U{|eMbMd`ðpd^޲G(c(MˏMV80@ 0t1آފ`XC 8dr bYm DA)a9?ܡ5U*U(ZHtt4`ǎ G_7%#X$CL]xbsz]bq$ i|{ {$^~wl9y}rq;菟ko?;w9U0PHJبQJ*#>3+HtV1|Ѕs) nRCNUYR(8.ܨcޱj۬FT>۾qbh"ꫯ5ix/vK A] Phmr8lK_9=I`FF7G~ ꃺ9 `;i`.=af+krA %+60ו^oߥ6hu&mܸT1MQ]ܯL') }ԫPxǍGJ&x̫wӵm/m-XJr3Xc+t틆У3XZJ[cI%7'h=a=,߼y3-̛cժUp$+W. Run.ry)dQs=Ȇ#ĶRO|dFË^p/u\fʻ.7hv)~Y#sy> l!ޅ ρf/ Q䗴4~]rd|wȻ>иq{͇حc'o]w@z*W3_5CRY;fݓ|zNpjx™ 6˩ ۊXB6@{Ĥ3fVW\BD:i}r}JR5>3Y9^!m+zp`V,l&bȠ@81]ec?^[t[~ w?kl6QeRΐC:49W)+x!!˗-ᘙ|aaCpvGL==v>x`?5|*zSSzPȲ$c+݋ӿxvF߼yNO,p͒*T_ܸq7n߾` =">;{u;m1!۷ox &A2ѿݻwO0Nuy"?=_]Q{S'=u?mXĄJ?yĈrF?坑4tQ9)e7h)h CK[| 5^i3bϝ>}{QG^:wA[vR~l s]/OdоiAlY b^D\ &²Y}Q&4\v` .$o\8ZP8a3tQ-b!/68Wr_~a. #O"&AYYDikȐ!-Zf7˗<$f-5/_޼qIVGzfI!R:a:=?sh);쁕>{ F_Ҥ;ɦ{ n5q`J@\bf 0GW\r OtJO ߤtkm& ғ\'wܹӴk7X.r:n5B Jc2FM/zBMCCCKnpFzi'ҸZK8W̲oܯ{kb.ӭiS{/[v5O\ukr.đgPM7?s2: l\{o_:׶%?Y9$~78={@GX%i{{gֶZ?p Pk%ãςM5 #3aP\ 7͝3w-^hS@Ax js΋(UA )ʹiClP9m+7FZ5߄S~檍_?}gΞ-Uwhky{n  `ni^7m9@7CŞ>7t|޵q6O9Sfʥ]v=Г%^8x OR׭ꋠ_,^O?D,L=wi/YÇGçpk- kc:{>…+TjUs2#3 p!Ne=L?S' %Xt?^Aⷿ6/vҀ{SXޏ[ O:j_R;oH|FKkئ*O];h# tf#1;ӢSof|~<`:\;Sjx*(b>^:m/8& 5ʔ,VREKG- EJG)])Z*lз,s=6Q#GUV".;VAcݻw6 8pm9sAE7k2[/gí7%ׇO"[.U+Ux(H(uly(2*dȘ= "#ts*AQ,l`NhhCh8G!=ܳg~X5o{b`i< f/۩]Ba4k2=9[/]ʁ2YrrUTPx_\^W.D_)R5;Q3t;7/HMh۸F&5)ucB߷~ǽY7׻ȞU_'x6{o_GݺDdW;wlt1BBap36XoUAz+=|鲥@'4W*J 2_2V,1lAP 8{^i1 Lqе|[֎-1vkŸK.=mk-5_o Om襄 nМUC,5ɇ=):'p u.|~r. |> 3;Ȫ,f"L$ 8үov 5m\ߍ6o޼C*E<: E$b2\Ss%'OE?3ygL{i&┍Y^GF˞=1l@pcƌ4&M7}KN*l⁓j=rNVbYXXm 1d;쮤fCXҲe&Md޽0}O?F1o. \=GZ I zl ssXDTEŃ*Gz.4fJOĜRur[,\RKڴmW ]mKO >D;Xtc͋=3zN06pEe~دSkgwooݴy|uz" 2|zR v{I;KIܻ}}t8/Y]p#%9ܷn$GdZ8kJ4YST)S\tb{|4j:u'(%ݒa'OIJ3%2bgnj4SzŚ`~25% l $_Եnn.bZʤ*aui?7nhRa&?n/g-XEڣfgMO3wq, ŠMYŐ_0n|-6vlOcgZ5ͱ8s=״s/dt1g6=K\A=> ga'Dl؅.P񁽧=#z7M<*h}HN=S `&] =KFڗ&[b&hvNa盔wma^1y*t7H)ǻXR?QV'C,:/;i6]Z+ٍϑ-](䭁v~jŲ8݈q b|F҅YWhn$~uE.\w~}t n^۲`>h ;r0]&̲ j㙵ւ5{._NHL?~\ܐqYWF^kW/5ݔaN[4 uءgoШu yٳ;B.V~>yB˗{"%kyy?~\jiCo4kz3;^\(+לL[IIIbrr=HLv҂WuHmԮw'Go90ݜR`^0}-+MI1̵֞5.Ô^#u%W[;yN];w7zɓv\>[$p^;so^NEHk3['ț6u~^+M@ 2ߥ~esyPw>5uǚ-^gj~ybm&ۣ_z 2_|p NBbܣ9M;ݗSO_xɠn*Wc`[< k6r}VacBW;5E )SK4js7o٦:at^4Kp.xpp٬ 3`/|=xD.m],9Va]vSL~9i#sV_k⥤$Ge~s!5=Hk{B/-޼K0jԜ\9 0gjqܕG.AAA0ҕָ0̛,n;Eoj޺^lƹQgMiRރ{GDv  6r7g({%`on7 &'xaC/P&8(;}+c̠(|栈3@`^&!AWlSqf\;ۺ>eWsG=!_lr{ּkƙB I/VRbXo\ /]٨gU̓Up\i=L`/Js5{uv.\g('\m)P _ZMs7z";F)%Mxvfl1js%~ڿ 3 "Z` ض|tz^؃K׀9`Aa3\y2riXQC${Y۹Jt3߳~kV' k,&#CLY~cb(^|k{5Ɠ.[r`KWLyGEcGFJ޲٫X PYJAؠp %16]5LP:$1!_wϷGxS]U;TtJ*\y۩&^]t;N!KLq+g-^}[5bPhKzADzhIa9xjжd={i_ڵ1߼u'}$:5Ǧ8k gMwpA’t4f#-I0spif ါnl\nv_OExDaٰ֬6LIIcܔ7bѬn͞"[Nӽӓ5`nߪesW-Tlh7fi,Kt !v*h a.zk&د% fFQ2נX T4xy%^vI:弽(`n h@o {kG%DޱJ1: ƒ lՠj…DVlsj MQ̯;RWB2w5-`HI:5׍٩?-Jkh/&",l@gb,}Y3ůۦңsM jT~%6<=\l\ƃ$S$320 ,eϠtp`hnk4fA _ux`|  6hEIŜܸƯܿj&yIEa!e82qOX(wL )A&BIjm@%hLN/4Ll$ ]?-_K֛S #fl!nb,dkͽ!$Sa=/A3NX'W\ڼSi鉚6==p\}=G szS GÅɚqx*q^=trXl:0ANoPٞz|m;Sم,{zQ98t9~㵯KLDAvgI +ՁT.9F8ZP~!/H4~2=q֞|{p+تs#ۂ[v8MsFT%j#>2ǚ>>xRp#r9(yQ<>x*#T֞z +Iu ڂYitJי6p-ܠxLx-7nN"+CR\DAGp6NΚZ~# sw' h;$ƚ4TT~ٛ,*X7Vbڗ>k=õv0#CxD.gC)OEx(lw/QOaǷd( 1tG0SMsf8՟L 9ܯǽyFQtxHWA Ҕ*=$tP:Kz'^CG!C"H!t5H esMyMyff@K$03Y.QC(9Qf41'1{nxZN`Ɏ,\@>#[0N%+8]8EORFONI% 25ʹEix8@jfxK2[ǃm1ӅpL#J]Nnptf ҹPF5]-3NdS}'׶$篃 'I끚lO 6ϔ4LU\4tî5#T lYxK2[ǃ` 'Ldhz<M`Mi$Γߚ{,O .|_>a[Vεi gJ7"2.?54p5΂a>+b?_}ޫֱIi*MG;K+sM1qNխY͸ί~N ?}ۭVQ3-le[n[f Q뷘-S;_f6`f5)2EegݸB둹*~E:Ne:^_P y5$tҼ';P/hzC|2}xs6U-/^ pߊ2US_1f3Z&MM@۶[Yފ*A3UC0[Z[4ƒ\My0b6U%Xq pN7!DGuL"c4Usy7_RȚJUe0'n:9URQIk{x F 0Eސz* !buVU.ЁNV#{迕A 2"GD]X_ƇLŋ=pxPiq 6,YmM~'j"g/aFNmV9MÄ&ߺukwzJ8A``3C8vߍR9ogZ5NъD=ɚT-g0|eDn ~4:?궲aYyG:pX o]("y& ffq n qάZӞIf䋨N gwuAWAw=Q,{-)`QMPT eU}<>_ze:sj>-Ĭ Ҙ]2ʠGc¢3-N(_.|\.?,}Al*- aT`ڒf}$fKSdDJ2E^*`kLL<N.`Qc"ጊsȨ-60 s A/'wol[Zv{w 2ĶDK~/mŠg_Ϲ˾ߴ-njФILa%]QcL|.Z !}A d V>3l2C[|{ӱ\S cIM[z sϱ|hi:M}&j>MmĠ69,sʗpn/%~ 6L::rސQHd=UJ*=k!BF.X=~:-cktt"4ԯ4%IN6dWfذ8]`y\nXmիgwsI|T#P'@#+epuW__i͆p#&>9H"bR2\dOWMQz渴44  Rbq쥿 j'=zwGp~;U^+\ s ɉ󷬊VEKOK3qjJQ,/ٛ_&R|X-{ȕѸ/__p ~蹴S Il A֍WNn9 7׷CT?c`@p_?~feKZJI3#_Ul)3zӠ⋔oIhS9+D I mڴ.L'L f meneե.:0߮uyG~̠Sr~Mڑȍ(b$["ȼo>J/&.^W?rHGV+ѸKBYݨIUWs@~}:-9șX%v^?"fj\X[pйjs`eʕ+⺶{E5 DU#A{Q /'WvHnh|&e͖MiB17EbF Xzgױ]/7(rvworr1@Pf3oܸ1k,P#222>&~˖DEE¥Q e6MXp}=BZqa k>CAWkx D`CLoGb,\Ǡ㽹fyBU;eX^lNƾ\M(m-ӟ>1q7͙_JݦY1|1p޽?O|̦a֭'O6|ٳDb={g7ZhД_Y_AU[A0R1JA ;K$ʣX6w Tk]&uƮ-\!1hcLx%;njPAj&,k*d mHK>3D8itky 1 Xr.97 #$j0Zwk^z r7f͚|>}44Ă$UtWHnjGoJʏ"}n Kqa!l%w<:QJ* =wJ?o1Ub;_o{;}ӰuԂ}\Il3dH$&jܞ6( w:N6D7 />cޔˠz%ΛwZcJ]_ E-=6U)W%_|0\jG@ ٲeK`׭$4WRH wn2 ~K:CG f?sb*DDg@f>%%pĐ;n緤;dX]]*fБGxdHE#\MGUXb쯳:aҁ'5HUp\rep%om5=Ps{̝}M|*pa:- fc0kP:B l*axPF J 쨏(j 6b{y4d .z>_ܭ+6W$$-_ &S VdC.E-LTvbHf+T= `R)N_gn/jpq{~=˅9B8[du;eѢ|wEj$?!A$\ˉ>!~_&DUNc₰p~ * zjOY1l"C54}<^MizfyfĪe ˠF1Լ'K=~Pú^B_ mj;Ir E]}9=*5\?y= QSD32Zv,Ѡ{D"Nx0 cphΝtf lIJ G[>._{ G#Io`t # wsr Yev[SānP Jأc6*h\(SaANJy1w#"a!aojZrC7i?ŋ/^O+~:sٲ6+T9rȓ'O%&&.̦e/J(T5J1QYfc0kdUhvkiA`I#0"'BRm2Cebʛ:!|-R l<2[j'~|,_N e6>|Au}ge(i-`w :Y[a!k@!;|"TBg2m螛D)]s?3Yǻo?ڦŋw8ݜq*qԭQ%#k -7L:{$AΗ;"ݽ>N۫oOJ}B$~,N5k#LO+qzҝ~c6E{7L섷2k^]3鋖Wn[o#yL Z KU~ULV=zްGǶ)d'=ڶe.GYӆ4wM/JR|Rⴥ17nq#XuV`PHʬpYaGo{6U{J;9M`O\1HD?d Yԍ5Y#(xx~zq[Y/t2 5d+ڴk _ͦ+!rV[~ ۛo'\/_K򄚡YgE`jd`,0}-lYK*~-KOg9~VuN6[q[fqW# $T9؄]aB17E4r$&VӚ@B骤M5j}%jw▘Ĩ- bsn1A t qbE#$}:ƒ4G!Oçs0(r *rĄ"_bGIwtS n@k FX;'w4o}:lܸ1_Sy֜ 5bk \ .zЭ{w5ɰ jZT؅Wci۸?khV_E Mw/+T/hN؂.cvfBgQ[HJ,*Äh:5U`Ӌ%i/8رRْmW^ŅKc ő-J!15iz-'{u:yҹ{>od7hӊ9ǫ8zeS'& V%&rM^Dq^u>_9)y'NG&hvhwҬqQʴ HK3x@גf5roAx*1%ƾZG1Iw|}k4Gt](_{{Q25vq1)Ib6]!`jժ:S9u4l4I6F gφAJԴHbҤI X6ꭔǐ):W-赬$݅;wc\,/+~vcs8W10$Ϟpe'W?CE [n-^ UT)mTѪDr0V:,TiZ7_JMASl.l3mӔ#Ge4BWhA @O<ܼyp_5Ik3xZmoF>f尿 Xjz\tt`=lm)R}(l y}R}V|/ v32e)8:;Ac3|eoM~VZ~/+pч:gkOGYHq^ڢnXS̀sRh1 ,+oBӛp+LƬ&Qp<ߋFY2ilA y uGIJǎrewЦ(۠%Z/CR/R.y`߃)矵:qbWC}FkBnhqZMx#;yל˗fz0-C7T.ƜJePƜf*FT`W@»)\:?wQ뷨'-R}f`-h)f㴡u4 td-uLAl2qu& ,:K(qKDHN &׊}M/12J`c1XM=M*Z~Fߪ|5}Q)ⳮOzzaIϞ=wS-'3MMOE4Cٛ:hz0@|+nӉJx$ٸuvjf\K''n; Q }\|Tw{nuM'e_#mE/R`یGwag Rނ/'y1&=yu+.x9Jm"_/1-ֶbN"SU955ʠ~YPj b (TΟ߶Hiؙ-xjf ׂb6Nz0WXodm$\CxHN] MŲ./-}֌IK5UC6] JAͣ'yKp S]ES~:tzF lJp$OI?/' 7}|\C$9ӣLMC(@X )<&Xq_IQJ(# 5LNX/yө :HZ7 d#K(0ߟx*cMABHԤ*-} JYUT0SZ͘|UIxUa>%3m" 7'c$A[hQ`Ãh5z=~v']f9jp?SRf͜iel,xBxW%2&饐h'KžzPێ^PܷS`7MBrCf/v-'aZBN8aA-O;&Ž,SGYE}BJ>M/&`Xc`i`A5STftanGe3Q[fkA6` jLL66b{*Gn\%磔dQ&`'ME[^뀦 slz I&pҗ;!;h&$UΥ = x|TAlnTʦ hPۿɵqtQbCGRo*APF(xmdd :S N7Gix\DA'/i2\Mv dgێ=C"#ᓜ=u?f{?W[ć h;y`9sHO˚1%5AmU3dU 5M%*y DSU - _<~Gt~4^{?Oi*2jvs^FM[}ڮK`tlBM0b$N25oqƍ5gXR Űv&&;Kz4]׊1tF/*.*u7zNxX% G 2~a FŜ U_n@a"MEfJ)q>>~%1h|)c2w*4Ȑ1#on0RSɕJO=S<*{ZYa͗\l+SLDnOB?0aUSt;[uAwm fbTSQ[Tţ '^$?|n=UZ:䖼g/=a2{Qtsʙ27 i}fte=6gg/pL]y*Xm)ړ\3dOM)L#ݧn9j那F]x[? *|ܹ<ҴAϞk Y xlnTXXnTX5U̖_{#ygܡWӧy} C; H,{QK}xO'TݓU s llTl3"l!uj;wĬG7k7߳~?"Luf_5&ypb}ba9\GV2[~YCYqlcﱕyKQe;8̿^ bBFݲD,摡2[eluJ%3x}OeOT ]-f.T1~a@SGk:쵰͊2[elu%0V+vnٛ~SΎD0$U;BO afʐ밊d6!w$,8%=i4 <8K 0ʩg>=67*\,,7*,{*Cf˯ݑd0u#v,̻csfCv.^P"zS_f}]g&r*ALaUv8*bds;uzCW[mq@;GN/,{dJ?N8Gް 33 v NSvίޘmpRDGobrʔ6?QlR2-ay$|&`fG\i?X}>z=˯{ ޺>7 8#6p؃wPamWE~ONKYdX/.yW*xߺfQ_u5z  +X{₶8vַ/ܣљk Zn^V"dE/w@A5jɘsyѵRI7P Ȃh%/RpmuT޵l1B;grȳػynײ0\tޝj:}!fZUnܖ Yo_y_EU,Hoo8;Z2Ⱦ+YIXʏo#四r3+S+-۫Ƚg4i}1H____??R <̑Ͽ7+U1z'(3. ZB2nܦ3ܳk"44e$>R>ݞMھГu8nB, B=ڽw&ޥ) Uwznu CC {mʝݞi5VCt8rKHt% CaYK1AZҞ$>o ' N`޹{1{44kxsetI'[ě5lm= ˮu6~R ¬% +JH}ȻW"v\~UDv5ɍ(d;j;58fkUAnhĿ]f81RN|o x߻|/t}ԁw}HKKcq}[lܸItY*g]uF6jE=j7m]nUX-#ҷ9wxE}e+q/\|+KHR~<2jv;]vfbwRVR5XA2lV0]+lnoxeODmH|Qc&[@bԷ<c{@uj9?q o1mg+L\.dT楔& \O>mli.,"Ydɧ͗AM|% ^AES=*a82dr֔.VXFW+vk)P H&lC:P,4m7ib%)ӱs;-']ʁyYd\t**_,jM2M ˞rn۱a/X@/`4Rm@ yiQ܀tSbaGvͯE5$rwCq%-i[ MC;yѬdTqؖe _è훒\9+D}x.ԩ_Z PqG͝!h}8A=ab:ѭ7'[ º+r-pЁ w" J fʐ "Ek,;6"<@H $@H)L3Ft"g&0Sƹ ,{lYx񳧅8EPL $@H $0x4({ѰfP}+Xt^_T#39PeUOO"@ >5 @H $<*{nMa'<_LӃCT~@`d rr\~`ޣG~4=ZC<]H?k؈1ODH $@N#@^&@Eo'uum9 ,]G1D󹰅ӊI H]HǏܾߣGL NPCFCO޻{5DH $@H ,YNQgG;@3T<@ӓ+ 32ʸv!:ZIy'_>iO>;w.hɴ>͈/I{ $@H (iisn:X8<1H=DMC˞f>b-$;퓐#c'w ɓ9rHݽocp#8^۴{^\ܿ@H $ܔ@~?{ӈPP<~$kT-+4hm"d5=7oޗ/^J+ (z8ZY5ޭ"5xqHkБTۼݻv8i@H $@v%:9tGOE A۞yz>yS޳1OIӃ`&؀f͖;Wμy'|G4}jX?|@ $@H xs)‹S ,{<__No׌GSضӳdO{Is:#ez%;z/GvT\#g/:uu?Yn߉?sj/ $@H K oЂ7{VXkz%GH $@A *Oi~ {^>˟:yFzOЪig`\'ʾҶ#AH $@H 8{BC'?o" qgjժW畽)JÔƁmH1-$@H $D`ʔ)H=敽[8Oj@H $pu)){ds\Q`JH $@H  8Oš=iO^v @H $@H XH4NYeO&%죏>al*|qS;w[SaH W#ʃJ ! "*SRl5w*{zFH pۮsaH W y*ᕅ?Ȇæ'q z .g22 $@H $Pٳ!ƀ@H $p9\@H $@H 2+;鑅"J~SOX"$@H $fFԳe4h'gC', rᒷ#9Ι']NB - 5lm Ȭ I4̬EB` <=ʞ5=;v,֯~ߡߎi~}i㶟6{plʚG<_ :\g6,rά{x֦d.f $aҶF784(=1_:ɓ'M UxeO:S]x_8C:D Xq7`qĀH@ plԃGjSw(~ִĄ@H!%X( y*!GOf='hzw򷃾uk-V_%tkPc@E:?yOP48xB.>#Jaϝ;g"*ׇ>ia/{IYOc@H x=1 H drϞ,Av^^Ɵę?hɓ&pիWвf޼Ι83y`@H $@%`\1u$@H $8w]{vܵm-[os˶Mpn޺M[6q3'O6=O!/$@H $ܒ@ҭ~۫{z}٥Gݻt]סm۶'oȡ5{n BosvC%@H $@Hk e{-ыCA'ʬSTfOd+R|ɬLZu|[ v|"@H ؐv6Q!$BnkYB ϴ޽= rکCKTV+#GH 8VmT,)ݱCK!oʞ֜bO$cXp1E $ڙ7{&eo@Pi۠%4i?5 tϼ >]>  $S'VO:4Oem `?.OA9p@M-` N}R $",̭Ȁ5K:쫣uOk_̴={:e2ϳaUQ^әb7\U,~h8^VDP }F? zشm7ۍw~O?"vM J3 yeePn_׬})ᖿuP 6EG\ `aRNÄ8ANN6LӾx1ctiNn$PFcwt:_W;0zn/肗..S"(C@لT%S0V$mXՙ޶-vsޑ:޶npv'B~?ئba,H 8|enz XJMM*J&/Rafj !W̟;Srַ 9"p0vjrOC,bzWdUHl910DF YJ32bϟ<}o9%B=MzP煊_S)iz4S(~1@'(8Sa ""(5~@F\%t2#},+v-[ A;)=|ϑ?0'zxX $R,̭Ȇe8HPE䇖O\T=+dOuWB4.,ޣ3N.'h+8+]J fLy4#\5ӭ>$t?F"A6GG{_H_tf-/=OPn"?0'Mo޼?Ɉqi2m4Jk,?IrH91Ҁ 2Nۃ3GH 89}2Ίlo8 pEVwdʵ?J`!C>}\;cB==$yH! 2gF\HP 9R!bf0͕&48Y%dݥR=x@K|wƁͫ'?P1Bxl|ޔ$u6$ Y<@ ߜ/ qL 2(tne%$_ѳ:n`q11^I1\_,ABVm@jlH]e*Y7!F>YO;ePk Q,*c$Bˤ2iAkѠ$@VHM{ %$KX6UR0r[ !gV3{lCl23o vl& .pU+K N^TTPnQƎLmIuV imhWຄm}R6Uf[*:ymС&i+)A靼ڞ`!ZkUo o'YK^T5Y>\6+ԭ8EH $`c+/YtՊeW._*j׬ij5X%ЏE'.[J^Ғ ӓ˄uPܞ]|F4.ܚ`Z#{)-Lb˞j:1ymyɧψܡzY 'M>rōUǫ3љ*%p~p{J "7 9h)N6w|pvqqR+q]ܚ`I*Ij4*d1{.D 6$|MRȦ-qĺ$)8uIThLN͢99u@>S&qx܍kB`ON\ ()>:OQWC {0ÄVoGv˘@H x6/{ޣw>}{ΞKM-Q|KNg)ٮ%In^ab~ڳ$YGDo\ʔ8N{_~'YGu"+8#ff5O`vKr+Yr'ܼ@fQ`V^0rS7ծ΋ktrF@3h wǰnHӧs{Ћq*)XguEL/!eHBN!H|znTh LzJ@ 1Vj;ldMXtP)\uCpC顋 %ҕ;-w Ʃ#.)}$=n6f@$Ze) T)g '87j.k6p9E) *{04Vo˘@H x6f[dKع|ْ˗)ZoK=e]r\Z:o#s l-7@sL0%rkduVP^)Q-NezޠF"iX`a`"vKejҡEAQ);uehb2R|lBXehj '$J-K3F)ǯ}.bmx,t鬧{%)uTGjT?6UgإOr%RpqIm:?y X?VLjE!d}rZz`ZV $v,{/_HكɛS=r>-{Z%r{"u*ΑݿG}I}nQ dUKiG M%Zc1_= Y-IA> Y*,´du_ٙۖ000 G yp{XiX%FpAcSP|p+mbӞ㠥\m]FK%Yñ%k): [ +تԣg]b-\v(/fO]MFc7k$*u85&dUb`$@& h|*{:yXǥ6i`qM@߃Q8Ȏ[dh/2qe~qDAp~(g n4 Ileahz~DC6'dH &5缲V)dW -ak~ E ^G+b 8-G V:Бl xO5ZǸG~*%&#ŰZZ /H`zlj~ŲAH $dɣR9{*].dCEQ> &tָ;ud"/:uwfWɧ'3X@9{$Unlp6.T!>!~BXh8r%%}XO$5ZFA:aSyaى;gld3V[H&)%MJ6ף$r8E ˑZWc,lp9t%TTq͞\eAx%EШ'S.A Ꚍb˗FĸSz/@H -=è|+ɟ)_hp&)&}gU&Oiϝ;û! q_KެZ=,Obn6RJ&2b̰6u7Ka@$۶\3m~16$8_/3xM~-7z<~<==}?о'O.iGO?^E={jzsD5Psb>Lyl\xP&;`naZ $B>/_,ؑo.ʟ㣩 .Gcu]ct.h57Ѭ@r^` &.j\$ul T$!^K}G(499Q]ZLBQPw| {J @CZ"gIWI *QgBZT; I~zVƣ&5&~VO+ Buin jVd "$N@Weݹm3oik ݴ B~v;{͟.צ72qCZ)r g^[݃+WW#?rM0>…j_ids;x#c)d>Xr"=4f@T*1=[/"g4v>+ߛN?7j0AZڕI{vyt1b7O[Znfvppj9@H "^ѩ^ug9L;guc̈́WcuM8zj}0Kܷ e-ǸViQ{trmߝhovUNywoIK=ab\~{MK%1 #~91lK&%Hz39c]?xB2_]'o(VBˣ|pcE0!qPbbZ#>nF?Z9xv*> 靪I$ :+L šz+6#䔫fECt"+/Spꀨo>I*,FdԶw1+O=uw$@$ɲ(lgDd$y% *e 0vMcG]h{f1~Id~м)nAqQA~Fp4*naIZ>Ŝ)uw'+q(@TԲ݀[I Kdz$S4fYWzah o(|*p=>!<ק*LpR'ǐ8Y=HuNqM@MWPsA:/l:*R͔qq dx*5-WC H> .zj!/F-i2 0]YU{7:n\;:m8l:L#@H x0S;=w3% yu77Ƿ~2ݱ+[V4>}mRB겎G0Ey@GrlhN=b0yA+N2`AEHj7]Є F>џ1#*8yM]%Nk֯:L"ǗrUBNSNJ ,=Ǵw 04<%-FʶTCxd@)\^$Ie0d]]hM3a#츈*JPEUn٢&֢-HH5L~wR:"-To"I a)7!_pZRsHX͟\@{mԷw%~>$j}. $-ꛁgtm[LldBa㗎!G6('?(`!5UH`*V֑ONd>-;bwsMʉ92:PfrQ0^x:9ڭ&uO)ijq?ŧ ]`+jFПȜEtEV>9r0&p~m`VU:ջ‚O]c1fLvbH:5YJ[LVWc5ꝱ}5_1}+`pԐ@H eOpbZEswNӔDG6˂{0Jq:AYO0h((}lڄyV)|ԏ ]>!SMԄȾvń;R\kԴIר9o Dk RS>Y#:op@ 2lĈ$.]MTScW-~\?3lep!29zOhqю̢;+)p@Էwc-휡c?Eu@LukzAͪz[jj8 $= dHgp҄[kIߪlk"{q>{dN:OQ>adN :B֚QW\ʒ5{0:dŷHP7eiKΜbAvv&g0vmg}1o/#C-bM*6h109#$K싛@Aâ>-_>=|1s;_CHc FjIKʬ:A\ҝu肔U2l D2`Q .ٿGqC2ɣ?.GP֢{ m@Էwyy5Do΅0C%˦ru cLNՐ#@H ;yɓ'SLȿb &l(ixBE&-ƫwUޭʎl*m3E~㚝3lASނn"ou?VCvk_סF mPQh ?]!n{%L!uMIͫ gD4qs>[ h?!A֑'4B6dD#4bB*QcQ+xsV(>$2( @gYZ`0*ved-F@H w"Ek(!x.q]^4rm!~ 7e &aՄX9$ڟN{n1ېwj,z)Ԉ\̽=> oQ#iɌʅmfVL<o]UՉk#wއgPa=X6e%TܨM˦SJ :*9x-)[x٩7.ex5JD n.wD zS`)>0*( aўIF*fS( mš˾hel9J-o5$ lN$iqإ5`H $p}*{=i/=K^>03۲6o_8*7^Jzl.@Qϻx@2c+^K!o1+S׺_{J֑h `Vúb1!*673_tLNl+(;R?h 7f?Lej!4/>I:pJӘ͓+~ӧ5PXYԲTw]qrR삅Ygd^"8l0:$@H ˔p|6zoޝ=ÕC?pu3Hqn$ SF/fw/S\jH'p*89QO/jG j8 uMBOUv,-&qe&`!KMXmtNlղCSpoU1 ")ǬJ dT+ʦz>}RBkߧ.:)m==1B%dN@)MU/ͻO)rTw8D9e ]VxPYg@H $<%^<>׀9{_3f` |5fao^SNu+I@Г~OM1ؾܦTQgI颻!e7uX& 0dlpՉ;cKl"a<)p0d)_|U8Mٴ2!TebUHnں&S gW% O^5")@H O$`sѤl?8oGfq@qCN2Rq<ǯʓ ]N–̧#($d޴ JUޚ=#,tA=lpR81aTҒWEN7KLg/Lr+2\e] U(\p+KDJ"p1|FSM$K!H.,]ɤb&/oϑUwз /[,8y $@6!dEs#9g8a>7{e^Y#ڄ7qq+r8͕퇸No+ jr~\ &tn'xŒ !#X`9Lʱ ɶeFhͱP1LzAg[[`^_4Wb@>&6)m!u2!A謚eS6rS5$l2-0o@XXO [VfSmֵ- XNpy9\1@H $\@=;4L^>;yO+0aCäM؅MyG{Zs=w\jqM?|6 5eTͪs`3QRCʒ2{Jӫ1-JDZfy [Pa kPj:sD@N"yecO"?WA&O5[F5WղtOAtA=u6F{^gك=Eq6XI @H ;"B¦OA>f 4 mrKCiffbvqΈ DH $\s@ߛ9Wi…@H $@N 0qTN='&@H $7 Zv̆i=ਦO2rޚH ʼW_&@ =bH Gx:+$'n¶c1$D,AKؾ7hQTz|&===-UZu:uFGf~i7r^Yf͚˚-[6{vQcFH $@H S0T#*{}tHcz^Zk8@`Aك364:h{GB=KZ<# $@H $NR|*{hzTK jEAL< Jбy>G- h9, $@H $ L o_SgΥS=sVp)ϝ:t)yfG1 $ޅ i?)֍)zFHzoVI8[`s/Qhi:H2,5j| AH ,W/cޚ>[u  =#$`={<_Qa 6'p=+{Bm.c"<~stLrKVL| ԃ:F=ș3s̵kq~jmR< jz6ቑ $\cI)S@+\&vշWwMA3@"xʖUl ܽsVgO(mAun=|[ ʊ$l N;pτ3gAs?y}폹pmE1Y #$o=LHəd.x"$ YM =[Lݾeo҄ ɬO-A_wn =f#f8g7%7fj=R֮A^ !O -;O#oi=c8R?h9uI"6`rҼ"l`{]3wqMw/-{ۡ;pnNZڊm|UG_v@MAMO %ɜ~[2NdB ҽ1BEw{X`$lxSРIcZigqrgW&>k k5TϴǪEM^7ίQיּ?ѻgA_;VX,&TTsܶU%l<{3嵠~'\V廷e*?n=}bPQ3= $֭[mv>$=lOnL+ի!Ɵ[g\˃}+ gȡ̜߆eN5uAp]XY:<%,6 Ov>䘼yL!31*w}T3 szU~Er|e7;"hpN{O tT'|ka}ho]j仺s#yseVGZ@ӃаN//Nx9|zUzTW^J{^/M'@_H x5' d#]ddYO,J#@zB} о } =dv\YDͭX`;o lhKXLM/h}B`ߥ$w9k7e\}Gfa`M$jzukX .ʝܹW$yǝ͙=_ѭy[ܹ᧪3l̸ŊOiZXgn+"u5̑iz ;V*2kzIJ])֠ޑe/ӈ/A{F>xD񢦧w$zT2r$x_Q_VR2wljUŊW$$ݖuTEɛկlgp+n{ 3X'u"  {-{Jk$>{_ɑ8s'Ia "g7ew0Y(ZYlQf%Mxq/ɻ?\Y7İk`#9A{A/_P*Jl  % }ڶpLiFdā7js遞`EvHǯ0†w^R~âS+j=vXQ9=~vfz4DM/^mSws\gMs">ݻ͝\0pW\B$zy:1U<|ۭٳI4=WpKpW2-Xe6IKO+9󗯞|zӟ='_leAMφF[P5Aq! 8eO,J#xRDikq*})iYjɛbj=63MjL%~ך3pdk-8tm+7o[,6=> Q8Lռ#YGdesۄ0s;gv鹄Œs;wO@e6t 5_MfL{:TFMςA$G(Nɲ܎Nt"S po.r6/hP 1gG>٭Anwmk@ ޿fux11YEEALe;2l`Ŋ!!TTQ+KsWL{ӻ)Yrd#w鹂L]NGǹ 2(t:HD5o6[n3tAxPS $M7xy{;r!Ȝ!yɓ'Sٿb &DN  =~(!ٳ-kV9ww!;|sŷ@c~ZU8kqr;-:8 2?ի4e~Hx%`v!cZxsܽs}7ӝ5woW^Yu( 1l#S[; OHI?=x#[.鹊}L~r|/%2T3{iB%OwjYx`[r[wz/_ܹq^@bBMO/H xW/3f Q]|pʔ)n 2iæڶ4@$&6nYvn"9ow_{4%JД<9l߉4QzQz5U &t,jz5j|TH %x֔ ]fެ/_1֣"V¦,p̛ jz*+ zCH# ʞ4w=ʞPڶ#)aز}'*{YL){YWˏWtkfެTɬO{`Z|2}YD,.^|(@Hz6TXY/ƀ&r 5Bώ!`7y߉k̬esVɌSaF'GkY,M~@@=Y1'ltNЄkRWw˟t)??6K#@BBE8({[$BH $@H ؾ{ɠ5{0ce2>>q㘂JY30AI@H $-yCkZ[mjݪd.>-M8q(ـZEF_(^U?WU]F]J[~_Ә4c^xǰjm 6FGyn֦MǏF祾.hz1119}c*Gf=,$ل,DH $۝-ۑ jh\R@a_v7.v3\_ؤ%իWjGOupKsǏowgQK\Ggi<{A@{`ŋWPG~?u+n5lWϫ,Θ6vMZ}a;p8Ye/P u! O*y3q[mXhSSSI*.5lz.O.5o.*yTKRLR2_jr^MDX $@HoW ?&8A=5zQcFڰc:\3 /]̾ݿЁ_GYQAfj"H"7fN1ŁKQF̌a-ٕW!2q_Ċ*A 6]8mQqc7jV 6o[fmbP!sL oIB:Ny6`c?5,[XҖ,Ϸp+lBj0AH $p[ʁM ;wp=9tczC$B`(ْE/V5l֟'W={936k .{vl4ؠuz+5{k@* 9͝\7mp w&pƭ #Gv6Ei`z2w9wi%Eo&8i) !L&sMmHUy~{.?bq5mWQ=wZY6Z6oPH\{;vlPe2|\bݚե㎝x*wOvwY>\Td2HؠEoéT6PMeNW5i!z3;u'v93q7_z0S"q.SʙMb H $@6$`<~{ya@Y17~x}`8{9{KZw,{bp$ϠaařEmHò.\ۻ`W̹=X}˒k]|NL*R6gǟ VS^ۚC?߅J.b&T=˛'֭[۴i3Y^J)4$@H $c.o@bBOz?XDfF»E5}wl@ q>,3ZgPi q@ǀ2 ^K(VH{#[6`t;eJmK++quAlҵMPko)ZF:rʹ߾MXJ射  $@=遪G=Bk}eȁK^L< rٳ}U>~+/xxߓs%)Q4on\lζ/?H>v!^0r;+1wΜqG֩,ʞrIL $@F@fxmSPvz^p5q{1tњ~S:.O~; |WkT߀]نϘMM)\9s;{Jַ;1#$@H S=ؙz*;0M =ɜq{HS+iBu [W(|^O~)eo}bVW,:a„a_ȓ㯿^iػƮR9,!#GH $@! ?~{kggCH 'O$HדBrNʟWeL4V N뭼yܹ]Hi+Qx@H $ xyy'c3*}Xd8{|_٠e},y:;>~p];,d'?=B_ٲfF~Y,<A P?@(0W"}-yFgR;dc'1 AJր++ I ,EBIсI%Q 1Z"1%(?Y!0%@Q7,)P,N= T$ ' P$p<zwf 7;(ثիWw*{ -N\ٳ:>;bf! aa<5YU C:^#Q!8,2E>݋xidO82'z ɡa:U%F գ1+{ԛNCި@(0DF6x!>=LvDҡDn'AU"Q/b*|X,Bgϙ#W9sș \yLeh\i^ q9}6Z%E-c$ 3@K{ŋ/_z^o'(IR`mP[@`ˑ#WN~${:ɴ7`L5蝉 (Z1E ,ʌtJcH؂. ⭠4lolF3)LTߓd '9IPx];o$1HoaՙeU4o z.e°#EĂYT0 5T']V3q{Ĭ#$s HdK:y"U<'Hċ[0_ޗwG~?ݫe붗qgt̹[ Sńl7Reth{9 =f]1H6? xkԲgf='|_4 6OA=P[He9V'ZzGT#/@Ph_N\"njdL=ANY_i(\J-"A|^(ZeiL4 AS3ňVLrC>xsM;~V*oyb`)]D7#Q jݧSw`A&KʂJf)t8?So41@H }e<6R@ gojEfթK#3jD.]2rzaZ`0Ve/`c^\Ԋ,{yF]BQ͋(=WXxsUPiGj=PL{'S՘/D#z /5K#,#7^k{[^~E>HZ=*}j=#S%vD5e}XV'舂QPJ#;2UI~ G};bt Dod n#SD 휂OR p )@]=apN$YW'|q f $^*{WLN:ݯDo&'ߊ=|d䰺Z^ E<nDc o f2} 1ȳdj88 y@0Qz=^!0 TT>`z$jbli=~F47ќE3W˨ V)j{eyQ}Z\FHw(3Ӳز:Se%{PӠxwڕ-2ޒ?aANd%UT&SDTUZ:zsR%lJ>YٴR?A3-FH  Qf2EY6}8?d՞Ul8.ѵX["ȉ'#'d( X┍P) ^I*,PŧҢO$@6" ucM~䖷3_L/YPr6?~|O\농h6iㅾ-! 7*dv*TP) 8$=KY?5$4XŌfIɅ틦)O5='@H 8e)Z0_ܹ (fY>QtIENDB`PK!0C)word/theme/theme1.xmlYOo6w toc'vuر-MniP@I}úama[إ4:lЯGRX^6؊>$ !)O^rC$y@/yH*񄴽)޵߻UDb`}"qۋJחX^)I`nEp)liV[]1M<OP6r=zgbIguSebORD۫qu gZo~ٺlAplxpT0+[}`jzAV2Fi@qv֬5\|ʜ̭NleXdsjcs7f W+Ն7`g ȘJj|h(KD- dXiJ؇(x$( :;˹! I_TS 1?E??ZBΪmU/?~xY'y5g&΋/ɋ>GMGeD3Vq%'#q$8K)fw9:ĵ x}rxwr:\TZaG*y8IjbRc|XŻǿI u3KGnD1NIBs RuK>V.EL+M2#'fi ~V vl{u8zH *:(W☕ ~JTe\O*tHGHY}KNP*ݾ˦TѼ9/#A7qZ$*c?qUnwN%Oi4 =3N)cbJ uV4(Tn 7_?m-ٛ{UBwznʜ"Z xJZp; {/<P;,)''KQk5qpN8KGbe Sd̛\17 pa>SR! 3K4'+rzQ TTIIvt]Kc⫲K#v5+|D~O@%\w_nN[L9KqgVhn R!y+Un;*&/HrT >>\ t=.Tġ S; Z~!P9giCڧ!# B,;X=ۻ,I2UWV9$lk=Aj;{AP79|s*Y;̠[MCۿhf]o{oY=1kyVV5E8Vk+֜\80X4D)!!?*|fv u"xA@T_q64)kڬuV7 t '%;i9s9x,ڎ-45xd8?ǘd/Y|t &LILJ`& -Gt/PK!TcTword/settings.xmlXn8}_`&)R: ]ͶX@K-TJ~nqL>]KU.m SY.t;y/m\nۛsꮃc 6uMZQW67RlaU)\ejTW슲Vqc˓ *2kZzEYȽdjSnqeu :=M;U?&gq_3qwr2ll(#5n[PUVa{kpj{C8qE|!D{bg kQeCmڕTg–7Q_6 A:oVW^45*cFAᦪQv@ȶe9tVj ÃUdz9R\թnۙ+SPgT#;*Nm2@KLYSrl %Uyc¶'L7PSu^tPiMWz{9| qtG{gށE^^gɣ дy:<˹e\m@ #u*[>'[ȡWs2 "RoRKѶڧƻS@ ?@{hԪ;A6O 'ˢ-5mCe"pw! ſusGģ/zr)>Ch1AqxL칁Հ4NP4"YDOT79297 x6O\u F!TO.0Y}vzT,n;ca c@tPK!zHhword/styles.xml]Ys8~ߪ*;G2e['rf) 8H-II~6  "W%c> ˯_~ b/ ~niߋ'X9~i~yo>{A_ni$ݰ w,0: FO['zpso^xxr2n"J/z&t[$8b>io/^hB1LznRG[ύ8\'`2bDǼ+h>8_[ۺOA9K2߃V{Ob~=DPy$q҉]{B[ bW'WT^*q6V^#ߡ/?k>9 s,8G2SKwwզMp(;eN=n3qiP`w ,UlH´XpCq1m;ob_[nX9fs4~٣?9C+WBׁ57uh88F(J sp@8}k!>j]wqھ 4v8k? Y%]I 01YޢdE-JFآd#-J&آd-J olQoc:k[WъF( c?zxZ:jzNk47#י^~~pf 6k'VHڃsٻr]xrة.2@V@AgZ)XZAV;&Ol5yd R>Ls衁(,ĬGC<&I;  |@"PPhdsΣb"}pe|f .t7 {ͶPk&Z;X&I2D tNuԁT&@Q7Mꆼ @ݐ7=y7tG,knP7oyW@:yA\3JRpyPT&ovLM[l, y!oP7Mꆼ @ݐ7=y7tG,knP7ȚN ņ*ɛb2yPS TTRM[lAbqL&̨&uCnțԞA#o57(NɛdM H'o57T7:㫓7ZAe&Xk@X *`)&`&or(͌!oŒ!oP7MjO ݑ7˚M7Ț*}ɛb2yPS TE,k!ofk&-٨&̨&'fțe Su&YӃɛd |-%oO @D,"+ּ;%`:C DyP8 mc` d(o{!ntBYM%׽;QSj&yCz'!gm%;tg9 x],{(e=1J~"6lR H>+AIZx;Csz>8oV#+8@W J%f2뙱G1PQߊ0qz $u5VbK冠9 c' x>[zF!}«>| ^"zdii1j%~qZhh!GTX` {2p8=B90'yaBƼam05 7*Dk7Tbm,nd@$ZN7⮆t r qpBA}*kB,$S{{ f h)β q_A0!HxU͘6-OgŪz@K_Iqq1$i]k;UpaGjqupOa[s ,C> e78ڒEP9]#!"+qԛy!@1J< Dyj1ͥqE{^vUiJ ,a g%,9F2s*VO *5E>$z_;;3pPsڃg7tMZE IJb1$}O'a02~ y*I0u ,ဵ{0oKm Ljpu1>5ǝ ٹ 2 yv $Y#&D!Ԁi-NX5>՚4Z\jkMeM3 0 p8yM|oưN)մ ~|45<}(V!P|?Eiل[G{N%-|pgK\saQukkVQiZe=Py!]rOfх|{#Ŗ{1tsnFM˘o^"]=鶂KJbpz~%?]]ÇBC߉5OOq_Vb_ͧ+^ Z>bw\4ૠ']oEaّp/7_;)G g,cg Og O)|wMwF%Mou7fo+&/_8wi?k[A G*]{Q-b*t r+jy`)ܳj{–gW o! {K\"ި`%LN3p|Xx2]rbBRTKjg,:$nï}@8{  Od>r>LŤjuu3EbN٭L&%AxB?cЍr[+B݅w+FuVo4?PK!L |word/numbering.xml]n6_`!0`Io;hNnmw,ZD-c7}>>V_#QV$"5,3MnY8ȏ3wZ^xDMOz~8Ax7wz[F{7/սÍFޯ7v}}u?+os qhu=<sjŋ+Cӵq47hg;o˚[ѭEk?w=Dn.j???Cko`mkΡY>J&))%ONb }S~C5ХOjyo-}u`{{XVKd|_GE] HDއ:](Гy3r)* ľG;Ykwy[ 2=ӜyE6(~}~b5{ ػ_BuXd f{Oϫҿ7=-% m-a&5꽫r巗>?&-Ƚzycbۓɭ_$oݮ0h64MOs]=<&:w_^.m7~C+K!}8&17 )t^cLFvyyeuOc[BB $V/Ȟ ҄\Ve)b=ǁ_ 8:>ӒAin 'CIFk0JVuXr)_)ĤráBCECN )-A)9BTCPT% +)= (UA@rn=J"]m ؊yXSn-2 S B^I4c:uWW5&VzPtk6rf5y2vǤ2'd6Wg_[~TI(Zbh兹L%YqTͲE͌)Χ0"wI=^ܧ;4KsI|&.k[`e{cq,֐p="bZHR m"hD-E'4T$nD|P\$F7`5:aENNgtCHb'3K"Q@4 0ҹ]@z»a۳qX@BMľ$_>GNzCɐh/캆eHnJ$fnE2oSD2%9=Bs0O}/A Ww'0O}-ECklNM]c !jm"lÚc&>,pi`}WaC 2hlЕ90zE?8 ?tJ5IlDl'nO,1vɭ#h_S,ҷ%kIAJsF\*zܰ$v I6)rAә |ߎ$kHՇ< %04lݬ$z+C[W zU}uI NizYxkA#-ֵ&kIqZԄ5:ǚiَqFs\+xx4!(rri<6PZ{S3X/M:BIGFzf^u8Uɻ ֓eE"kОfzwf;s0"6[3b Pmt΁E ,BQĊ">wR,"B!*EɌN et49[|PhZF"QdF<]͟(Pat  YJ;v́uOl:-Py{uˇ*-bMH*~ovܔNjnNEF"v(i.GTLGg)r"bB@UևG"XhwC[- "eOU=NˇH_*2ReV3kr /u"?bwn5@j}c0RƐkVq9+S Cx/>0#5lŽ[}0"XLA-n >DLT\#ﭔ+ (;mi-La;}́Uk^u+Ɉ QF ~ .CGwAbvv{(ER^g˺*"UD/+fz{7t-){冼}V>XE][GS [Cҟpԧv3fkvfcPohLIʹ.Y_'vJ.w Bl L"|'%D1PQ\tFwJl("u\KB|>'1:Jd L[$K$D$0W`w5Ӟ4[ vM%Ϛ$X+Q~5D4R1Q~(WDRA!JJ$08Rb:BAEĺK(o(hnHGD%'"FEEABC_}NVǽulb@h=Գm/NTT|5UidҌ3YwT~T$ T. 5,ɧI3*U*7=iXp%KC>/ܚЩs$~.f=FƊf>Y#v~  {#ҏ~#:d?UJ_^!+Iӭ~,u^vI-Y ")^?L}fu5@= {SY-]}sLNaByeafGAtn20=:֩=TIa*êUح4hpA+S( Z) iJpFV G$R8P*kEOLiq) g:g:I'F{?/PK!1FdocProps/app.xml (N0HC;u"(hk8[&pl6=Aiw?:}bU^Ί8^~*'|z ̡?qLU\䱁g`\Pϋ%u+<(pR$ .:eO;YlGiGp-[8Z]rJ=~~-NSBRr\,G`ChPf%\A_wC|(/Og};j{ng|;PK!t?9z(customXml/_rels/item1.xml.rels (1 ;ܝxxYt23iS(O+,1 ?¬S4T5(zG?)'2=l,D60& +Jd2:Yw#u]otm@aCo J6 wE0X(\|̔6(`x k PK!MU(customXml/itemProps1.xml $( Ak0 {jKZ:k`WQClc};u]$Pu0yG VNہ9{E~|pd!:$C~i9|ĚlDI'Mv@ڦ3|4 7My#c~֩ŠtXIՒLPy~؇{F[/ov Ԫ^QPK!\(customXml/item1.xml $( I /-JN-VNIM.IM .IUq pԋQR %bJ 9yVIJ%%Vzy@ (]??--39%?475DL?)3)'3?( jUч{Ǝ PK!D|I word/fontTable.xmlԖ]o0'?Doㄴ|بv]L6klӔc'|tkդ 9؏= ^ Pb, •cݾwӌ*%IyiF(MMKUS ҂X 纾(esƙݤ9רKɢ*ׂJO5QIbfk(*1g|0KG+2]QRwDK4s`d%HǍ+5 #| }| +GKP6&m"6 -W̭2l k3 2齌>)@]fX~*Č jI Ɂ5>9a"m|"Au=a <fT;&A}䠋jAuH {cud,~9]Q2AW[a]BV Lgs͂ rw<3 +YA8 @HMC*;k:7为- {GEGpͱCKlLCe㌾yHIN5Twr*Fat72 ,l.PK!7 word/webSettings.xmlQo0'; 7@JQi4MkcNXw!m{h'ݟ;l\^6:Jؚ %eW5uwsQnʚ'Wϟ.[FU:c/p?NZlխb`:RivqBiNe[Tm 6F0NjTתOj[zpM@Hz+,òWBF 0fCE^ ,IdDueYF8}gWI,ϋ,ƗǶ\#q6ݵqwߍXV;mjEFnʼnRܦ,mV,8IEO'zm@I7}2IŰiCGCɥJ-oxaǑ@Xm6Ci^ Lm e,EM Y(qpR7i.B҅+Y|ZZd3OZl%4ukg{)dG=b[o$C$0{K'v}(l|*>\8}UyōMڵ12_`37s>\ɴN-@DG+.Ԇ +[Dž8*񀄀8NsπWKAÂƁ悱᪷go9O´XpChtڿprmr!} 2; YJt.L3 ^}u-I:Ÿx00Yoĉ*_ 96DY{i=-zhGZu^ĸ"y}/ ikWҍ0W8E%/jlQr%ilQr%hlQ2xc}u^4Bm&'nВd=89ubr[$"N$buv>dM@-USokԩpҘ01 azk,}h"h\K~IBr&5!cAm4$dÉ/nL[]Wј<G @C@b/ۘO\G5²J4ά Xh3 hCJ>$άgp>{W On?Eƣ((8c6J#6PkhՎk-IE``,r<2hB)sǒzh<*}%ף 3&I;  |@"PPhdsΣb"}pe|f .t7 a}7 (*Mu LMVgqefj3(븩L0nț y!oP{n鎼 Xܠ8U'ob󨯀t&Ys`;f=RpyP T&ouLM[l< y!oP7Mꆼ @ݐ7=y7tG,knP7ȚN ņ*g7@e&X[@*I%`Yț8BT7MQ7Mꆼ @ݐ7=y7tG,knP7ȚN kn$oNkɛbm*#`YțҚ @xˡ@6#ꆼ #ꆼ @ݐ7=y7tG,knP7ȚN kn$o#Nkɛbm*&`Y y1[7o9g!oˆ!oP{n鎼 Xܠ8U'o5=( @~Qԁ ] dHT@9ʋk0=CfG=28_>-pV0:$xAڡKw@^.Ip|B6YΥA%@XzA7u>p#UV p9V2DX8P5*<\=S f=# }ŰTBn'k\{={cG(mDArf}Pr`9 c'[yF!.Ue_I~Au7DTY]S/=\ˬ$JōІ7MNgX͇, p=2; :gbZyzF+s0r^84z,*$zzQ^8$xa>BIf<GwB):7wLYȘw̲.|p}]QǍ+<.X=n$qǍdv*'AFUryvD=w9ƽF_.4DžJ. ^,#+tCNrUgڄ/W Ő$ªXU{1Og1U-ru=ٽzI#D/~w0&l aGjqupOQ $lcnanwFAo}D[x,2zIPoU disr>bP͜T4W^ zr*HSzxg o0'?.!5SѴzBU0)&'dO7!h%2 +3qܺ.LAoXdyv P 7j\3CC4%V6V$fİ.R8D3J5_==b?g?,1$}Ú9Ȝ2+%SOߪ9'HVnxFRʀ+e$.˰o$.|3hvN "gS5hF(V ֜yT ]:aе~w *[bOplK0_ÕCi5_UC7Eh!)eEebH>\ݜN&*橼V<&m|'k<6v_zb3ܒ_ Mߧ<<:a}ߕ/VWϽM_ 0(ì yByCTYӐ5P~O+4ԟWR~"٤yᙊ-&?+ Uf~U> S?lwd8W$.y7u ۆϿs ( "*obǤam[w^5Ká=:9U

x;;.apzÕ ~=Ó>@ɍ2u0))~t~viXE/bx%M3uq9|c>ӱ^χԮTH//pRrfZXg QʥvX}#G]m6yPK!fCmdocProps/core.xml (QO M -:5{r33ۈuv[gs.8S"TfS<}@H^7JtfM!,7XpAO"x&l!X[gQap8C,[.{!p0#RH 41(p_=OΔZvR Qjmyo#sGMv%UL8qUϋ;^+O8ҋ-;սKE{XFvedͱ!iʟ_sTMSRS6!_١O$CRPK-!z [Content_Types].xmlPK-!N 7_rels/.relsPK-!N:C [word/_rels/document.xml.relsPK-!*mN# word/document.xmlPK-!xx%Yword/footer3.xmlPK-! Ub[word/header1.xmlPK-!IFy]word/endnotes.xmlPK-!BlL_word/footnotes.xmlPK-!xx%aword/footer1.xmlPK-!R,cword/footer2.xmlPK-! Ublgword/header3.xmlPK-!e+>>> endobj 2 0 obj <> endobj 3 0 obj <>/ExtGState<>/XObject<>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI] >>/Annots[ 27 0 R] /MediaBox[ 0 0 612 792] /Contents 4 0 R/Group<>/Tabs/S/StructParents 0>> endobj 4 0 obj <> stream xLÑ׀1qbv2l{\MsAlǞKc:G8P uDZS?C3~ |Z `Hr\HW`cЯkdwr(="A|*?@a5x `L$ G+_0 nd-TwPDɘNܖ?j5Y)! c$h?s ?>q׽`;gO K2c.sqam_io[]a%@`LHA`#Lk>(N>`B!dK1a',Ib@^}hk\ ~`7JXnPC8;izvҮcsOD g sſ_َ}/۽ׯO ~`PVv@`8d /puSpQ 7e@7B9}2~,P+\nj|{'Z@F>E!?ߠ5=Jme,Hާ7-VcnTդfIYxxC\#xb E셿P^dNnx/hRNV6v'OC+Loޡ[~ȷye묰)#_!; 6A %QꙢN~NHnP;x0!B঵r"ARݹ4ĊDwDŽ4Xhk# Aq &xD]ٰpKT\quKV_/׆_)!F'uaYvKKٌl.bk1Sja3mng S=&\k 'Z{ íڈj':Wg !S.7"myV\Lmf{]5rj-#⟺wX'5J??"#k"7djJS+u_̔ *=H^5k7?-=DC% 4w9R\sru 'L]zBWx=X ajg rU[ ..x>BT XљNnjrFJK7rحJW2yVt(աdUIxp 7*5j^~*e=+C1^Sƞ*~_O\DB;D] BR=TR>> 8PűG8 Kh|M".{Ny>@1l~=11q,gKOENDF>{JO *t\Un qڈ{^'*k\F BvF&1PAySEYI˴?VՂDOX։xfh*1d5Dl#3ބ  A/TmޔXT]U3|jDdq^`! u/ yX~sWEy6S]%2!kR[yTSHxO:s_y{b< **STyX{++c(v{1ԧ6hxFR"$WJD7ʝcCߐ=3GD|BgHVHn狟*ɑ&iTNMtW7ZQ98ȕorV$`ySe^{̼x4H=!TaCӣ< a?:N]).>(}.Nb(WU C0كΰ$XD{pў4gכG['|VS& BtyY1(AP,2@jrpb2T 16g| |k$X ]?pEݚi}E* -qqO/dreJhQzFN nA_a[W֖T]m-ґOoik$֟ +hTb.FlX\KEyMc/iqյ6,9  Ϋxl*QF:mx<*$_E6l  vMK->=tuxrFnw .Zn+yS`i4Bnh{tm24cpY+/3kIȗ|v$b@1)X}[-@9UFҙppWmŭ`A@K 4PI>3jBzyW^Dr3'a1)!5LaP;3FE8cXDO<8]u{Cڲ\ =n1ûfǭ_qXhV+tE':S$KǙ|:d3Bh;1&6[E[g+ -X%您qr"JG I-oCđYA@:>Ǘ;C&gaC:8RY].1$Bp_H;r0$Yp/J#cyC,R`te#h3p̲ay(2ϏlZuDm10EOÄ-88qw-nRFxz 5hADrbN܁1Ry x^*A.Xe6`oGW#lG NccOFU*)LGMlszF@h?#?yc&^Aa̳kТ&WvނhRTKR~%siĺ㶽h`_f z8n0[,EBQ$q,b.oѯ!~0wSf;JCi_lQE<"~\J}S5bŽĀ}du' eߡ5wiQDUpNюgPEt/}%{Qcڷl 4wơ6"v FT9;pA596ȏ YJ]ʬFMWydO3hD6EQ@ϖK64>ئN9s&6clOrjMhdPޭoa7ݰGFU|IVNo~EAOH>̈́ xi*?$CI53$$Ȧ> endobj 6 0 obj <> endobj 7 0 obj <> endobj 8 0 obj <> endobj 9 0 obj <> endobj 10 0 obj <> stream x ۃA+ PW" endstream endobj 11 0 obj <> stream xva H@@*2hYHDi0۽v'к^uzw~? As[zvȮQ`Xi}62:66>>/FGvv6vz5591؋M+̡ssC3Sco5m'i#w.[\ZZZv;Zzo]~kk兹ى_|܅˟^5w+^pniI=xϮ}u׷׷n~uN.{#i#SXwn{/8zhj|פ;>p `=aޭ|9r-|?Y'O[Z}87fF3K׮֓g_v/?{[WN/ FHū|? ׯ^>{Wg'NڑKl<||hv;M{ƝkV!i\Iiڋ]>s&=}Sv;M{wKI"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@!H"i@#i[/^4 `/6,iKNݏvڥ?&m~y뛏|Gag7o_|qۍ`=z`7~c#&Իڕn߻nue_wj|oI=+7n~}o;wyVN鹅_7n| 0nܸ~ʧϟ:07==sƴc'VΞpOK/?r/SnL:SgΜ~gά:‘CS#ߒ6261uhť'K y3i{ML:<7=C36:>/f&oDml|0/񱝠h{Mۍ(~2miU>r`g(Qe~VA]?Nɑ endstream endobj 12 0 obj <> stream x ۃA#,P! endstream endobj 13 0 obj <> stream x}${mWufUJ3$wntf@G]Rԥ.uK]Rԥ.uK]Rԥ.uK]Rԥ.uK]Rԥ.mi4:QF]/F]hė~t|?X_~?QW]O]ՍDxRWH]ok07^}ޒӷZQv؃x+?PǟJ?/ZVBTitЊUQvE߀wZQꥺjt'E7N $#EŦʗ (hvވQ|@-Tm~oʪ#p:R+?w0*~H}"o(>'ݬP[JݍJ4xoe0p(^u;?^uFFbo-N&_b F R [j~AkP}QƇώb0r?9Ϧ}(l41ץ._+59lRAu97 vNڨئ 0FA}T  w6[O^U9D*RuC|Οч}@ *hJNQi7Q`d8_ҿJC.ʫXjeV1}}'2֥.[A˫{6w +Vq "/&t2a_wSZO_hb[Oպ.pD6qRJWFF6bRu*YIϨHVm%pϗt:CϬf&0gڙױAEeթ$ SjCjEN6>To{8y?h=CX1вev wDzl fgu"{Uq`fҀU)L@e<Ju+QDRH6\0aPA `V3;@ugU&j[NNח~Cyyƒ>vYf(;.HSfSl4,g_NX^cmA*Vz9fl;E4}N̞N`IbBS$ļzЉxhHxT0 $, |MLF{ͧ(7g"Q9e`5 bZ]~φ">mJ4^ [`HEBvJRlD{9m]PC蛊g+^r`بhmI K ɶ80yQD׏%oIUWj3hiB҇X QdٰH&?>_Tw*o>)NOЪo vrQ)͆2tK.E*hCRh_ pb q\Cϰ㰟N6}LZW#{JwqLǤܑumKZ^N=,Ŕl"#2Z^`AF)=oo"P@3jRT@#ሼ𨺑l3ŊLn7ۏb9$BQ4m9?'NW j)j ?Ǽ%Xjx$-ݨ1q8KMe!#zg+(_@~!y_n7Revob %/q.U=2Sr!äXh!7Uww9:lA45p ն6kf* 3o[YS}bG sIO>}r XBS>:Aݠ0PT[qNJ3濩 Do 8Y)ot / :rpo0̫*͚.ojeopc::ز| xv \D.ru UIN rQ *Yh@KҰ$*maq!,pX9w:*=uWg28]nxv*6L};`4♋qKpizAm/o+lƋmHbY:25>N 'y()L$iSO W(1OwQ;3@QmwI75o -UpF׀\Enڊ'l1r.5ީjfvej劮7OuoUƽ*[T7 `C\shySKO45qΠ@- -E8/Mr%$/C|SX>-5qxw$x?քW8uz/+yr+27!ada*Ma֠PSKU80MuBZ#b`SNtaAӽz=3D2meQ3,mN<2C4k lAl7$Y\כ}V@R\5MOyJE\:2F|ŻW]Be#P}L32GmBC i7E]nWDhc&N1xѺᎽo_ߘ%YA|ϼ(HUT!3~&Ǔ212:2@m/gu" Pֺ-.[#PkZ^*Q"O#CРt3 n!>Q+DW$@Jý/=E.dDH l3xwJθ?PN-l" B7+\yM(`,p1I0#m9x5&8Uܙs{yK8K5dIL MՄX&E>*kYRY^|H8Sg|b&"-c^x?Ԍ,&Y9H1Ag$ȅ67MjaQjI(QakSH8uyb&TkE/+iH'년i3sS_2s>XVAtں $DZxPI-iʈ G@0l#Z#bGGTst}Œa'!65^Rd:gG?*\N+ږLbNՇtuk"^V73 CDVƜ89]֖M'c] <= 6)[ɘ U-EjXˣcYbj!!Y[%7*Hd$#˻!:512pz{7O9a0Lt)Z[t|F9l|:73 pOsn.G`yx!Ʌdir3dxlu3%Bn.*V+ny~ CM|>X7C>2IXzgi(2=y苔BaP#3uSfcbf5d09wRf8߈xyb\'B (!Ot7?F9_6#g,@E"a+ԓ"HɉӉ۹ +ha7x9b!v̢ Sdm0,N1Kg^4gkݱʓ5kųfg`7?AT|L_pX{ߙO,Q3.RarҤ&"Fr 1Bg4J]xl9p|c+:vPA֙%<NK*:C.BVJ@4 J:vTFmf~`R,1B bt}L\L1~I?hk(-s՝L\|jt@-DsГp]t+ ^M2 v;TkNIɜ.xV{П~0=lW'\Fxip@w.Eq@#FHUȈP: šb9wV+(L Y8ٺcUÙk/eiA_*pA&cCX_]!b0~0,=Vș(r lgvh cŖRueXV8(Bm$`"ymWZګ.Ds)t;fJѸFsdbPL1Ӎ8 o?i]KSV'wYkiӴw?y ce*vIQY'G-O'!k`T!%I8jv8<9ZJF<2PFX =( l$w#Ғl7Ng"J7V -y-q  {ӳ 홼q 7fAΓhd;e 1<1%e-n&́ %2]sSk},ѧyo'ypfZ|IjqD_ wF`FFϜ+[l \R<A# [!`ԉ{]rV)yK֏f ޒ,պ84Qb^WRn,B$ےl ĉ@b ?K1L?4 [Cgjyr6"%flkc,FTqx9Gg$\ztFjGeFLej&i1 AKS2}"-O׻;);Tf,Z+iMujWCVdLyR/2 U =; F<[nO1y],Y.f 1 OCsڣFU#ɥ%-ㆦ!M[hMHNgTJm5Ң$W7TQJİaܺI@blͦi{VU؞(Jntgnf!SQۘmHxx2? t.J<@HBf9x&Ys e@Mdc+R0Y'_LO]}̸MHؖ9dT`f[b+-0;go͖$wNp܃+Z3VoJe| JErehG3qQ5Փ^1 _֖ʲw-xFp7Xr3je{d 򇞕67`T<NW$z7 >7Rȶ,هblȍjg[͖"?s[Ovgt|•"_%}ۂ5Vٽ;٧2L ?Wxk ~Hx B1#իn0979y$e#A*''=0㢰=V3Mth<ӏˠLP41$2fTx;;+3Fų&֔hg3L+KK5Ρ@^޻ θ֑eӶ:V66ތңB?ٸ9W) Ezޒշ01+G1 ${5d4{ۍ%c%bVAqܯ~ ,)v@t_!*eG{k 9փrfU=M., m5鐯@g-^i?VR 'b7Ϯ ܦϐ1_OUq=9,Kr]nsiZG01g<330/77c`kl%7wLG@äJ4?](TJR R1qI ڀgGWbM.PJM[Nsƅ}ܝJml'## ?{ʁH@e_ܢ29X+hȚ]ѹ'iޜz!+J"hc#s F[pLd1;aώ8&[V {I0S:!T<4ȱ~R@H{&z#28dz8`پ?//F'v xvۯT8o9;0F,Y, h8Ԍ>_"|t/?3= WAEHnVFpr1i$ϣ6I^f;#&d,7eYBӡf=^d]Jn7we\9Sm8U٭b9Ϙ]1ݲ{{vƙHoJNj@4P7S9)PP%_h`|\iC@](ԯTmF'|WLv}k2ITZE*y J)^%Y͊g2^{P H8d_g`tVD9}yu)DŽ1v~<3 8QƞJHũƱV6'iw -u6og˩i #5eWl )H$(I"R3e>|ڼFTרHβkv`jGЂMorQlɵ(J#邽g*3*|t4 dzv'(в)N?!8i<45*ß2An)@$]GЈg2Tg|Hf p;J gډWg* ="cYzvO)ש2g+|*ʅ-5vu.k)0Jb)gԮW"[@8wY1p x\d^l h0@0-;LwL6uYkf K`ݖ#@S4.HDQB+1U~ =dvRM\Vf^iqujRPlav|!/ʉ/*-Q&Rpfw=9Y S2qJϞYiptlR6sکXM'l}t>W#z5Q~Vs_{мRy^ߓZ~vrcϣ$IT~7!7ތ~- ]gnj,+ C!کv+|).!UօHV8EvXE2g͖k(ܺoBɴ]fZw"/#=(/x_ '>0z@; MĎ2ҾC9TTwpTB<3m>컹ch\ZRKe^/L<;"l6sXɐ:ƹi.6#|`-!# Ԑuy+ˮp"[Ŗ9s֠9nIE(-dךl$3[7 /&uA:cg& LTN+xSli3,Z*ckNr! :5 H3lDg+i1Og{4[M).Ccָo_lX'Cn,pLᶱ4`8j{2fn"w2cdfLоb9}DƸ&!%RlTҊ\#!o}sA\@5wb1z1>K(D7zn'~4p#5-{A~lDvdAh@ dZ9. U%|W8CFqt9d*GJe UZ+4p~Ƽu\5T%aǓ4mM5rb+g*/A@h8q+k-%cuT!O@]vkJ!)fijvF +:C9n1Wid:3Z[Q V, ,^ݓkn ʅo & +v:*0ĴҼf04%te l w[jh"&›Z)#Oa+X< L<CcׯB,C_6C;y=ܧ{Dj.kL6ZJ2vV.g3;c |2yWV#6Fg%o" =~K@VFi`3=]_DmUQV;Wp0Qb>-T=óF)+z//fN\u>tRLM$}aX%Aj27#@+ F`BW$f[OKEF=zL8\m|Rk߇4+9=p8 F_]mK yb ݸ\2@|2O_۷q;jоRÇFb$̐ <+-m8_4ܸe ^QKG7w"L;]]s-~E;~?J%W[%NHѣJZS]63ZYi&̇OV +Bt`mV@GR,o_c&5ݣnCV#, O >,͚fp%W[/3AVgΎۊ;~*sb:nlo% G#uz}EAڏsR,]=< w.m9 ==܎?qhvŵ3e>+_eéE&1*.g4ᆸܪ,X yH 0m Ѱ˟& b4r[4oi+|¸N'\ܑ?fno~(v` &KnU~\#ǵ;眃e{w?%%όdqJ,<~ڏd`#)ÃxnGT[>v4hhrN^LUf)6kH{]9j$2GϏ@βfIYųv6}B;<n]1OOy>wMAߐb[ȣXpg t&ZEbGqzF8U;m+)DEu<םjxDҲ,:(j{!|*O.0ҫHqJn &~m kw+9삌nV>RSc>23Rn۶"7'/\i%=V`ѥYZpmqx ź5Ҝ[p 86΢*tI/*e4}lm+XꘝJG^gxq`*zZ8-Fqo8+y{^ݯ x',YՂۨ)}KVX)2֒BScd%'XS>cݞjrՊT-R4)r R,S0guv+YSXmL.w٥rf\%p YϋH<:AyOV`L$_u6~࠶ |V{nG {co) k-# /QL*cMJVrVjQqsP(d:z}Y^9-_eM\- !&éB`}Ar-Џ,36MmyKlDV[+@kP`>Y'' qR' bS-OXי;w:·YI +Z)sTJlיִԽIYE5jt9:7*P䗇譁ۨ©>-FvxmP}lcV3}UҦ<[X;aw}؂Q($,q_ <#\ذe%o$4;Q ?H0KsݒU|O4j k̫o-p;i++5vٶ,{bfn\޵⪺V\13뎋n3!thײ5pi\>G\JSN5XI\} ʜx)=1{ї;kRȣKg 5-*O]5d3KƽdF˜E:stѷ'/ ܰVM'Hlr0MbS%o}y'\℅\y— OXHjK_ %AVxF$slE5G=2M7- /WzLU|'1a_vtB,I|nRW3{6=p2VjJRNG6fs$H ,~R0;R2XWOܖu&G$^?Hp%bԋLl: zʑ=-jֳBɶ`\XL;C>U ž@P79d,/ t!J<߶}@CX@#hF*P4#,f|XsCŢ]O[=~5vQ_b0J<['#h.)X2ZG3.bY؍["EcgT;3򳍉 I_|37Sȷuc}~JircfH#vhL#I>xv< .+VWo/[k#{#Nxvig<8^Qfx;PRMV*jY /0p/UL 7{9d^IewDʷp^5P,%<3,pObמּ7'|S kDh':{3O z'x( b$%s;_<.A:k8y@̸ zḁO<3(#s`8y+҄(JW:m~O D{xO~ 0*93OxS _j1Oئ$( (LyAëy /lxԵti_.-ZKmO_ƕL b 㰂c0_d77uxvK 8:^'+񌺃x6BVfL&'jx)kxC¨Bt] jx{}}[BXIϤK-,zrDWfx6xFnˍLS#ӻ9L'beڑ҉eW $I}v[&^3Pi+OƛtR%VYzgq`A!>|;b{F|x~U>*cǃLr<~ljۡ?oa5;I=Z1֊I:+y3 `{䌦.ҦѬ|Sx}FY.xrRnYM1Z:= k FI@3ub<g@f0AuԴ)45ň/z=ؕP[Eu|sXyC 6UΖG2u]azT$J@]QS]2L_|vY \b,NJ\ʽ<ǭrU=5/z o ,`ojhz.kZnH=VSVV3 pդ#z <),낕` %拾Fc*$kvg~*IlTĀZo^.{T[a" ?:(UЀja*)rG-Sڔ_~ wj8}4% _& <N‚SyRWZR͗X# ,Xmr(~mW1QB%*ZiQoTp-G;6E_4"y+pG.FxCuz8-VNղ֯!>LbU5> Y{X UdեM2D?tQŻ`"nӄAsis CITsrjXNCԭ@*^CEe=vYnLEg[SaY5pw{•Fyk'-ߙN,u XQz7(j̋e~udn; lHlQ sx5]hRǝןW@Z5߿[Tgqt?y* OjI_jqu6UŮXj[٨u{YUjDv eƠg_*wzi˯Kjwqf6m8Q04tI5_+o*Wt*vZa8>YY4~.̸7E4/.F,헱7WXcME/';)BjXkdS0늡ĔW S7@] ҲJWm#A͛se7Ӧo_8тWfP_nW/ YaBKU56j7A^WZZw:א#.w:{lGZ"#>q(=}jU+ypvҩAS?0D\ߍ>Nsž}?֑<`RZuˍW~D?Env~2φEw nxEy`$@.nO;Uu} @XMaZh8\EyO7EC$+D()7c̚ 6+&Nw6\PyNwSF ؗ_vb*^3`|@ KxZJffd"}9 ,- lªpGuwxry%[|J^.k`U>Y.A1)*\"Iy#Y KD, e<}Ї7~N-İOxQ&x O:J$R@"[zFclR{x;!$QbJ { Pv$a @k#5RV.#L6!݁1 ӀftT=pI{w*OXzqoc]$g4WɊ̕:] Qt Bs2䱝ّY/KȐ5"fd%<a}gp/鿺JÖ,7P Y6p\< xQNenKx.k11G?yIc S#g4>xZ;2tGXS fc<# 3[QeZg9̓Si&MFԾ}/GWPݥGk%()  3}Ϭ}%\=R ,IܷZB 7 B:K˵\8$fPCr;4i<ዏi)gDӼZS[!P\>~tJ [xG}y#]e֋v8(B?GtW5TOQ-J<؝pUOnq0")k9\@?3_-!^U&"m'y+#(eJ9O-y&;% ,CEg{cR*fw1c8U>8&Tϖ'yȥXSߗbd#X*]/iKp=#R(79A(fD1F179lizX&nFк =ihK:H ČR`SnI[-ёhqߤ]14@).Ըt'v('i `(|3xTfJ䕓nJD8;.ۂH#B %07R6z,IVM83?21Z#o%^-K 4] K x+EI=(1 "t(px"P%ϬV6 yrQ3@;j\SXpG,$ șml#V`Q JVte]҂] |Q*zXk.y䥦,iICП*)'I vn,HsUؽZBo3P bk/a' б=,ŏmdnre FyZdRw[`Md)ÈZK@nVg6C+ynZUuWؤ݈>uk7?ؤkW}}fr nU!?]5?{s(?%7ȉ;}p;BTogP([.M( }QCGD BO"Ǡm#BϥK'- }2^ `ǭ BO!, rg܋PSI\nc3 B׊]cqƀ}~P(Jgی>jm B@BпFlP+l o >t>ݬBFBP3R=`BF"B$1!q5"BOP BD-ڛ5G8 BK0 2糰 BUa BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP(P(o?B2 šPW3m/H^ Kw:"?oۼ!Tq0=RPK3 ^#fnvEj-- UNiݴ:0 vȓ"M0& ějsʱ"^`SP٭DiPE^8Ox4$6S27z~*Oy9I&z]}P()7Ϻx:_$ͦFq{us fh4rʑ):Al>ͦ0&Ŷm>}tYBϭz),Vf\#ͩ>2~jn%S1r4-j&YٔvjA-& B_B|j1KNRNQ5yD=1a?KlX&S-6rv 6W7oP(vqp4]n߬Hd<)&|N]H,k\mRJp:(*Q.ֻx<췛j\"Eq I\^3] PӊxN]/SJMZ,s):!V&[/&#n>Sp:}jm6m lam,Ǵ151% >-|9LQ&MVa!Kӷ+Iz>lg/;OŅ#ZRvvh -P(뒾aj!bBI.S{뒔1Ns+}Jv:v?L]شݝD=s@[[.hW4b3 I)ƍsonr8S+šsZEԩ\sJ>Hzwpwޯg"(Ny.Ű 3NP譒?^%pvͫzקC)$xvxv'sRxqݎ}ÞhMNqU( pgfJu?I࢐vbg_%=o9V],doMA2϶4FGΣol2,B BB9Y,G("6Oׇvۏ?Kk>}Yp]Nh}nQ656XLJ<HBeW 'RoM.5ľSzpQ(p}zKꜧ1m5S7h4@5N)-gG@ BŖLn>pz>t}|?9}-7.eW/ꥏ>P(zjk- I(TD?9P(feCQLm~6 }.Wyp(vt8CQijP(bHK#i BP:@au >X,1BKb Bp(HsP(伀`l>BP C h+- $+%P([/BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BAq~/Ɓ. 5*F/…oƞ^8+JooZ,k{grʅ>}+iUk?Yˡ?v䛗iQ Gi[Gn/Ex!nn M@g/U_?s֎\í wUu:ݬK*0WhS>H8vksjG[c҆J6|*޺^臘JY7K!3 V szlw9{7G^ o:`J)iIGrD=j;}ݵ|DN=^? ظ[S}izg_ +[C4Щ>!őϦuVR>Z}rl7X;ho-}NCT1_Zo}yGkEϙ+6n͋T2HWC pv|[[y$|lt}!p_tt>HpO'vvu%ZDu+]49_`3k@M*\=#[g{U~Oo9BA塥#Wז_}UCjCߴ>۳s?GmJޫ^fz?ƽjM/^SQW@t)h˔2y2G~]*kODqmcIqcnUr;:GIb|I15temMFCٶen8ȗvo 3]NU+NvT+Ђh}VQKدTW[KY?;`+Uzr}vϒ1QNSˢV /]n=ʒˈ8*>3?|Vm Q5cuS3gd4SH?M|6ֺ QFc #*?nJC,i:\" WT hzϛZRo-L1ҕ)w6_i ;/\a&qucO˅^m ^>iߏTiw5ѴT xOu8BѕCu6:4wg=7~+tr?"TʺsZ"3BDCԯgڡv^9t\tl?m U' *wfۛWl&Itڅ%-:5`-&\ !fd LcJҡªz`3R-Vh'!3cyU5@=!67S\%yݪaa#?W 4.hpSuhl2-wm^43FR_'\.z(OPoEbZ11  FBF `CíhZ39`Y_D G=IhnT7$'C>d(:0tӷg`E &Fifnr'͵~kAI /2>%{L}xʡF֋.fWC]*x)9ބ>M:U餅SF06RW[!Ac N:eNy7DC BN#J#=%y-%Gd,P99v!Af*"-yɨG+R Aݠ a0't1e:l u9(-QrMEWvVxSv(J%\R@ G: u~Q} oSt[lur;Zgӱ*mM ыc7-j>%x}#-KOF0GVE/٩f.BGTKUp</Nϥb8Hߎ3~X 1hޕ?̉yS^ wm"UCg CMI^^o^' #3 vQO? 1Q3n'٘m@S (&G:1P^^jhKq{tGcNb2hUNUN/xd4񌿰Ote_ @tR3EZjQ =ZqXRB҇av 13kV d-W)Vux:;fV(|p:7 ʏgt.}#Tkl>  ࣾz Vu 8!;1L%?D6K(04j]ch)RDO(Ғl1GH@T}AeX/gegD6h?7͖NV6h(Lت/\jv/߾<62~<YUTD5ߤ_^Ã(/1I$pk'#$ѫkɕ6+pĸDn 4Z-t10nX`W5XZ{}~دԒP\ZL+X[zhJ;P`Tհ5Ff@dX1`CoJnMxs]4* 5w]8-Ek1i"덋7(MNƆ4Fppz&8M5]II] OoS ܊biy8KIs3m|ֳ9ea2PxN] WUUaeV)XM'x8ä7վgk{ :޾~߷O'Sg!(!Ly[L0|]joEMlyAI]cq6bX&~ qps_[=XyLlȃ3CÓItVQd{{yVZ3!O qq22g\@(mqD[,{ų#Y۷|&&O>.OF#<mPmrk)95gn#_kɐRV,@toF(7F!ۀg:6k ,Eb0J^xQ5vAT#=#;WDcuRvwb‚M:]I/VOdתi'fmy6ORak{PУߜ-4uR+InE͡˗oQ (+gxG Q\3xMbָܳ!Qc>2Ϟ_ޞ?&uh!$=3Du!<FqV37UdzU$LB˲HTB^!$y5g2G<.^3&| Sg\gpY74x8S,go3.X4S)S7tI> Εs㳙gψgcN e<%uۑ(t6ShR ҝ@gŤ.}yE N=$x'Qojbtla:gV뽪v2cao׀<3%2XnxT<ՊS}|ՍAxF0,![[p(8$T%#AéjΚ5 >t1.g\lM:OvGϏ7_cI 77v0α ]uٸg6S餴bEp**xK{1 )oaDJ2Z.# 1ܟiƞ]i8gJl2J蠰ʼuz.ʤ1G?6SljrC~[k^?^o=.kڳ1 z!3^32 1]I~dZisX+yxvnM(LB9ך;t\b Di޸|1Ƶ 3{sc<ק$WE)ڣ=rE - CS41^}GLo-wẋBFY]MFq܃UF7Xqfs{ &.{3co N*x)hu` '(rlץ{_CE嘛5T[BS஺&Vfj,}{i;k [NAm ןO1b4i;JlխgVtnl,l# [/o,U[KSm[,|ɬ #^Ai|lG^p+('[մn ܁@#k*+4P!70͎"'7ILU|K Y۰>I6 Dѵe- 4$.a>{6FM}qa@t6,ϑ?fpQk `Y0 Ǟ`MK=d 7Zq'5y{ʙ[C<)[zqiRU!ڶQFG|,{>QBڶҼtJ˟a}6zF? {96W-Lz(l* CFg}j5Dt]a3sR#0t4e b>ܣhJP@=*81+ bi̡w].c'`Ѵ,=} 8Ωg4N5E98=+t{ rc6}xW߁l3yl O!++Me/Vr@TǤC#wZ# 1͐w=6@liAޤJ VSU#]V:O./:VΎ'c1j9&!xk%[dǖt_kaHXT B7TOg `+3 Ƣی-aqanY Zb^/e~oSޓGWePqJ?eQCX 3RavH؅Zcȭͤxumb)m|+&,PZl.TJFU^@_R"u^.Z VS'{9$X24¶N&a$l%w;y畞Y |}/qc|OL6l!FWJY|/1H~SwB ߄N] T^6c! THH6?c AR%aꕠc}h*{ J+5WOT^ǒ,ԅ],j0p1mzIBd@{RR$4-y', €&IrG|oEYƁ!H怪l[,,F"ﺊ=n4 v/d߄TP۷vm>x8QzeɼXjwvm1^򣗖 Ca."nm=XG]+]y:0v{4D=i (yl s^U%j u+CV'4/IANMV;*x΍A:^ůV?V^%?c3FghT+(^Z/Vm BPl@{NScWk,ctQ RmvJϕbc۾M,aaSK 1ԋ:N 5tBwGD TcE{Uު|&ӪEF 8k@X(T=&d1\K<}LysZ:\l%m"+-cPjZ%a 0+L!HO2I.>hR04L7$48g$f #E+#N+Yj/q H[5C!>mzhф'o"/EYk-*Yܫh,a6 R9d j$/rzqVmZ:!ı>˪ܤNWx,ZZ ߀y*s>mv6& ζP>i6T4+ x90wU.ڬ].ESl;hHJ# Uj:*mkX.(vˣ>47qm򱎮24}S@i_eAvW6_3AןÏI;g^@Js~JʏoBS酒D>Pʳ&/٬Yہ&\A"#MVoRZw$|S?qsɟ(fk3QÛ>Nj&?}Y=vU<$'A_:T5WK:# Jt[Е.Q5gߧڝVH{Zk31ITnTت^}W.^G7ΞQz>G_S]nȾCgZyҒ{j_*׍]zݺ%'sr j|N9167I7‰K/^MwHhT#b _;yCn[M}|yCE ˗b~@xyT^>Ƶ;5ؗ&(uԺg'ϊT~qUyM$8]HzJW_j{Jw&w6a2 [B"qwZxµ޻DV/\v׏~I{_/ iϒFŨh.ӕϵ(Sɺu )i]t!/̆!Ӟ#m ]'~\F6iw}Z?? i]Y!{1TT d@S.~ =ڨD 5K3e9m| .1]ta]>,Z퐌|͔Y6dj.BfnBTc?~?,E-Q7{1ۓxȬ%;MώtjOw`{ws2d|ol1K혎|aGY87dj*[0T%3YI&?q̲qsq]䤮. \pjֱ,Q* zا dɒ僈:7;$8dj%G^qD Է~Ѳ(dɒgICw jk5PO8Ḓ.6jMP!7E :guٳd3T'7ڳ'ʡ_R@lEB'(DP~IN-j(e YdoI@oDU:ԘM@u2@C"GB[2$@˒%OóqR9%O{1Qw#}ƹhY-:Ÿ;**ʩQhfɒ%ϒg^>S-.Vt$)u +_TY`mx%K_'oz,ʓr"~fDa+ٖKby 4rTY#("%bɒ%ǐFPMQ*5ϜMP۷g?;ZL6}[G<+#[~,Yĵ*,9X}D_@EǓj[ Čzn(%K_! 2)&i*w6SYԬYp |{yUMo##ml:-",YdyӘf$9s쏂@ŦM84MͳÖ[+BZF0V,ѳd_'+Es0m}k[x~z8쐧]VTDrYdωG$u>~$ryY@qY НڪsyHJ"\Β%ˇ]#npzA3<O88;A7oէ͒%K}*e O͘q t@I]9 %p,Y<? _4@`?*XJPLa}[% E,Yd ןsϥґ t9;} Pgɒ%OFMR M[L9+<βd+i?('8+Ί{8K,Y~Tœ͙Ԩm>OIm%K?S  5Jm&dɒ凤VWͲdK5R&K,Yd0˒%K,Ydɒ%K,Ydɒ%K,Ydɒ%K,Ydɒ%K,Ydɒ%K,Ydɒ%K,Ydɒ%K,Ydɒ%K,YLwkDYd5R;7meɒSI\QQeˈ%K%FB2 WMs~cK۽ߗqdɒفUHRwsIҞR⡵k?,Y|2Q8ovuNfP\ʤHI:i[N׬ndD˒% ^0sggYꟓcnrv zޔRXr7,YHƅx<gZt=E g3OԂܛܥ'snZ`8 nu_]&6?Lڞ%K?Lg|>+h(SCPSi30E>OBe55, (b2);;kw2TpIXnk#X̒%˧_fz٬Wt2i@P#'1KqDL|> G`("go\4g`<)gN5qiD\eT&&34-Z,R`x<弜a@Et#jݾ`tg IOw >|1ʯRVd:pّ>JӃlm "rϲd|B{7*(RP8`87O7|"IzxvK@Sws0.˕42SZ"Z NN&S$x57`>1mW%KYglxzy}}}yD;[<瀏Dt?J |)LZ YݪB 'hݨ98(ʅV@*L]~HdUul)FcҜQ]bZ,P n#@""tR IP*Ě*V1Ld#ATmr,=1jxU@[IH폧TVF[,7|%uqQ9fɒóbs||8JDStT$Yj`z͞&nzsǓOsc1`4ݘx6rAEDGEfN@g.tCe,KO)gb=<) =j.)58ZSг B*9yî;XJ(S.L^#d 32d,KO-\OjM&"BDkk&f攘r"8UAP??=OޮQvo8-yYW`}8#}D̄ݨzꥊ(gGx%gƖbы9zgnb[)ψgaET',,x(ڝжgDCmO#>{ d5dr#^]'AƳ,Y>x*7[&#- B hk♈/%fNng7g㩸;[>&K7Xt|ե=9yF8+F¢܆L,K+%BzzA1iBFgpaq!Ahrh!s _H''\PR`0WijeY 5_C2e) /,3:č1wyf3mmEt|:xx&<,ئˤǃye3M |oS:gY|Ja~7j?3|ESr2ARs&IHeIϞ5cgɸ*ˌ hwv&jB;(qͶcbļW}g/~nyVӜ%r46F1!&kbf> 7W#V hu.PւpU5zV`6 rkz t1 U;亨{vX7TY\_#KO+D/ʌ,0ƚEٻV -<Ɠrάi#+ cCg~+ʟuI;uil!C1.VfYh%K(^q%5`S⦣A3ߐ{0Vsl{/uSf(nhD=CM ;e۝IW9 4I7Y,YAn8Xq${ݎi4$^J@V>h%EwPp u]7`&6bbݴTby &vfU>4ݎ2Yd gJuPD'm}RFJIĤOlnsŌ)(rj"oS[e(IRJ8lx]= 9ʜe,Yal@gVP8{54ϯ{y2eɒ&)ET34Pf23Q@F(.,3@3bℙNJ+wgƳ,YK3uș Mp(M9"hQ_[:g(((<_y3uFiZ\wF<(A|74ϲdRq=d4KqQNq[ 닉i~.9/Fju$&~{U u`i1nܔ,K,uͩ`/-h.#{>7[t NͲq}y{L<~<[&V@ &~y97UjxwX<'$Yd"af9Ẅ́e3pajؒ6)K|6-N Ů]  7s5+'= &^+P==OƮ\ zydɒJ$f3!De B`e*/n|>PFY &1gՈXsC,Kc Jf,YKrqQopfGn#5;$5lg^7 ك$&><`5ߊ+˭ =+%ofɒ.^V f"([˺VY9Fv!a; ׳V7%0CΔ:[-fiAi@36?8YU1QD:T:^['X#I % pvQDbbd; Y)B_ ChVq?4R/8߾߸Y׮|yS_N/+(We H[ږc] J(#&n9Viݠ;ӱlJj) @7M]9_Ȩpe]1\]ӧ\x/{/˟wG 5QB^ULrk$&k ]@nJL|wC)? O_:i~UVe2#Qw~B#zs nUt8#g 8+U/WE ۤ*[.tœ#~ɉ^vz`s.@g7\ymAUr걱ҫUĒo/]9fU.Ш?nsb_d9Lk$*V|ʔc6u(VZ>R"`3mF9պTl㖯CM މ{]j-48eBj'+Re7o)ޗk_| Z!}[M[hE# ߽_"˕wq>?eTAX/v'.?N'e`NhҨfic P=Y7_F[ww V%^@ex]kV<ut;HnY[Cm v  <2b>:<7/G@-iMȰAX~t]K熬n#&pgϠcKdk{b]` n7=5 bL1gYOl6SZ>[lvȹsC鮺@z(_ofYѸɞL5ZUh3PF$"L v@ga>xQ]]CGد`k6vT4=#F3Q.'劙(#7;ڋm.A!3Ngw4Eto9Brtf0ik NVi=(NeIǺТ4!xdy9- 7.5zJnsC'>L} |1qL=R0s2uU?wZ mk~nϯ ugq FAN,bZSt?JڪfR~CB5Vyy&xqjl`jnj>{2ces7u`w} 06:Lk.F9`-$k:#Ɓ̃A!q5peF;X44ͳ#gРxn;\Og̯wmct, B.5ݿ}oUY.~r'Bbl_M>+N^ձV_vSsɸe}9h{MQعȷtg0V/~XĬdgE|j9[ /w46U_bY3$ 5Rg3QT2)o"?tи9Qhi#iE2]5{֌ڮu`Gq[A&3OJޚ, 1V%؇@bMc7+.az.L+kZ=Ŭ{WR AծO\Ͳ ʂUZ|VYOips RKIx5+E'k k$M=g@C쑲%ny+ nWAI/A!8!** Á^+/zo${|ٞɌI^9b YkJʌ8OYr:(C+3=os$4欴\߷ ^lOhVj/CdbmCz[GP d;B 4xM/XQd8q-tt=$^Z׺f[o'OCdBGͥ%iz Bn2h,Y̙+8k? YɹTbی8k*m&05aS17n2VU3^wWFtix*f|u>S@#Fmm[N% J >*H#=y ƉFYӅ6a3-Gca`X[ SºpgM>_^_vܡ.(3g {@s@v L`kK\ E=w+8m3|-8{flF<͙9!O DͬdݣfE;^^ (Y!gOIo1>ͻs@V}% 1{dl 7٭9+24> 7w cɦ?:+لHrwK!N0K}%}*\_zǃd{1R_Nx|5Dni;7ԑY.|u rNy⽙"Bfٛޜ V:ABo7ŸކNO&7T%X,VV1_Y5 [gL @APVuz=ĩ MIMiF@Ӊ}7yR|VXlHHs)mݬzvG Ѷ._YKhQfZ5e0ӨH`ϚYx yg߅@FۛhÅA~Bg;o3x2:$&9 14 HP8P^n5a\?O_+/(7aq@^ڸ=C rxH=r.311 Kph\Z^t||XyG3-9nPP(g.aG?*8\-}l|'I@_z RvA΍f+6<>O ȖP(Z5 l$h36zѧVKyMQֽo-a?LX2U[< ŠZtĶ? v~5{t8@l aDPEo;OnYg}?dh/G(GDk uLBXd.g+ VKؖ]cf Z+w6halGEp CV 3$4n){$lM)V2 F 3 G.r\lRf}U̼"lf{ b{o̞-VL8@z PjKx4ۖzo &ٞ>t HZ8!Ϧ]O}U]UǮx\c}D3ظ8J,+|'ۭ& 9b2T90 ø_hRJ[_4_lcZO Ŀjr.{8#"=#voNkzZBӾ??ޛܞ|2;fgʞ~}x |l`lXo:dx"1C\ljLPYwn& Qd3 Y 4lA'lvh6C'ؘrx\8g5HhZ4+DRKFg*bXJw ։G{U"WL=6&ĵ]Zohd'm +,9۳??l\[0a dەI#gMG|iU:6g/<%;?pA 8 usJqw }? '0LbZo,x*nK0dZKiwBh?[. v۶wABFtcmư"~Ʉloi[a Uo`a3qz^RU;_{=f+g^V&3hJs\[6*7D A'{C9^{z&/GS,-b:UwqhXq0I+JP*\Lߩv[t'.nAdN!%oRcM+`-e=5LLGxUVA_6̶1ʶ,cL~XeTb>+uAX_wrI/'ϧ=jk6,A*BA Kتͣ277{'22X!j rUӥIu) F%Nr^ViWo-|R/Ig>e#29JwI`Z #a*RY@#-{ lAu'y=𹀝4FGB;cYMJ@z$͸7}lzX3=֝lHniO=Gߢg9K6aQ)f$1jj,͹wJGF'9''O{ɭK&6}{ ct:dGψVeuux 7mJMyZqVJAq#+[3> ,(V⫻ʒj?/۶,qa%6e-H+ۜqL˨X-i 5Zq dJoHF=H΅T,b hcn5 _ ,˞ d#{fGo9PWԈM,RDaT5XyTi#M&8B g]n>5υoOV=QgκИ(h5M ( -[Mr6AXOMlRw_l3ٳY -D+wg$-(l*4 }1nX`l'9;Um=s6V}ldB#ym'׫x>@B LYiUwRցҏY"QѾ.< ދk4c<٭^W($؀^n-h">mxc43 #ٞ~s|(X%ԣ֫x;]@zwH (ܳ̕ *Y ]1"ɼwQwsY˻_?gnzUjH+GB=JSܭ}$|ꮽk֫i)DY(w"x* ^i00HM!bw+i_rj}Qq\I/#XRVx$_^N.SaemdU''q'vb<<(.;ڞyz|=xL`D-IXnGnꣲn%*KC7_ڊPywJJ4 @)HЕ%OeK?%un CaѪaKw CL;"9}9t_DL?Nji{\ܹNb|_Vaw L!# b$c_,+*$dJ_{q8%gnYdTJH a,.m;`vO|ZWVTaKl=3hitY?sekS7YOYHh/E= ۭ-JZmϪm?z wzsL+u6k{&T;eS 2Af?U05"غgQ/ݝlC0mΨC m@ -1d< YYЮP>|1YiŘU P3j_ (ʒõPI6d>rO˨D~DVJ[k5#{Gf([GZ# "{CQ>^)Qnr;_z<Ƥ( mr8YPܝNt4q7w\H*%G0F1rBfHK;dN7@ۜTgq5}QlֹZRb@Z~xry|< Qsl+pt1dRRKQg},nzú%䘉Áς"6(s(+ssjsٔǺΔKY]$U$QдL(~X)yϭIʃ.Y~5skν-oqfXv"u9z/^ϞXY71$V%Cڃ8J_'-MΨo҆g锃%Mm|hh๨Wysu q35٥)wDBSU~A*Ok"W}Fa\,3% U0&k`zř@Ŏ5h8qU~Ǟ:APDJC8'S-Y2lKc|B_왵'cOxĪ~ s/:YBz7!bR>җE(Gqm%"`{)}jYSVTTu4U 8AEi^;ZOal,PlP/*8Eo:'/He}G‹FQ,ETx9{WEd O`#B9VFR'kQ6ޯ;µ1)!b_܊Rf1%Qp)'bfηj FDəJAb jʷ(/zSOx浵**=#g^/*VV3զr{"ޣ럙8z(.Wa}^.q.K ת\F/ӄ+?Qq:uv?rM8F^kt)ť#M)LNN*b&^FMP_bS)*[&nUR\r'ŠK0ere / Zs] Bg, =1 vIg^.$ Ct}5؄NNkQij!<7hu` C'b&# $yщTE52W=# jcBsAbPF~(W;xgˣ{:l‰ŭ68rIVѤE5DrGU<sXlclRR=Hy|:&.Ô 9P0NV"&(8rTMkҳUh&]I\`ɱu^& "hiWv%-70Իۛtd j!ȍ|")&\ȼEѼ楚а- ꘔ@DQJ5Ӆ7 9DW &fSutg+ctխ l9$7>9Vz| f#{bP p(w(Fy}sY|k#Y:&Ȝy9!0.+g!t~~h^\P[!`̞];1(~,Ƒ]dcAy~-F7. tIu0~mG[۪T3*XQ%'{S1ґc<`|q_68is{&7Pg\ yqjD1X9F=={/ =(G'@?Rd9q 4Bt撜}'*A7K&!4ǎ5ss\b ?D q0j|'/X߾9dI- `;,g"kZW }aqT f4 _i5Sc^f x `wi >OPx [ _O&Uh ȍAL&_㡈@Mw֛?{Cr>|F7 * 'N0Wn~){'` ?>rȬuHq4h_^l{$rEHәx1F^I@4}^f6A3g=Yk${6`6;z>;x Hf|i(drgsќ*bИ=# ߿ˢ%/zpꐁ;REcyX7%Ę[7 [LeXQɩ87=l7IkCIS확$UNfQQ29Ywy™  ݞkCC\C =23%(o~!em<l9jw G3i^že\-CU6ўtq4L[W {0Y3qOqОHd9"ڀ=VtB7+>gEL|Bf1*γZ`O@ܚK)| Jҵk1c,BCgN{FJ}X0N :VgsE[0)4q9W|)SYz ];ػ eTBv_x홐UAM2xr'QF{_7n쏧O\_wc4ك39[̯Y'/@0ch=v+h۹~%G'rFGF=#[ιxg^? ʢn93@;G8nU gnsEpJXdA)(f]5Z=Y߾9V2]N!dVি9*vس?y$pM @P{%u nvyW;CyX=gG:x—<'<ᵌ(N{Ua'Ge'3ػ!p쮲 Stf{VozFh+6!hW%8!cZW0tB.|MB]madˋ3J"Z9~ ˀƊ["1<~^"yv^b,{62"H{o [(={vAwN|۲rczkx4wwB@b. s=c|_~cH4\Hfdhp,8 zb H_2a%}}ǞƯfb eٳKB3GmYz"Zb% kZ3^FJ8m8T=cڬ=@gkI3A;OmOHcċ3OxWx‡ {x±/!LiJ}]ך&"yy)u Ox@F#yA/ ͎1jҼ&vJ!,*pnVx*V<|% STjFg,vTp ,uZ!̩fS5FEv|1#<[@uzw":&a-vynϜX-2@s&T"IǺYGKcfNtt+?R9X#gMղL7-pQOx!Ox c^œm(Cz ⯂OZ]I;D jW2{ oo0}]MibZТbs]ԟx}>Pj'-, %6U&:5a=ڸN+t咕-MʷiiYyPSxY/:O1;Ӫߤ])|3ХmZEGDݤ%(z.YLP=ԞNgr&0ܺ^^rTz jbx9-Sjd@=S./P U4Qv_}'M 2E!*E!V[Eݖ XL2E7ߤ.l]Hm,rc=XR-=)B=~z%)2ZQl<jVO0'E2-ϰ`3]btngW:ʇ{^Zx>'RL+bgLK}>{'_Wzk!O-otC8D? Tk%tvzgEo-6eQGmmRo IeDez"kTjT8ƭV]{+ -3T~~=.M\W %eXx<kS&R'u˶J#[h~2rO !i_{7hjM[Eo;YC7~m Hpp[R-gM6ǒŕŪSWhBnQ JvS!>1Gf@"ﰜQbzrtLݪpc/[5B52pZ Ƕ5Gm<(CgdBk1wNN'z>t/iP/Q*BSV'2t+tsPtl/3Sݪh U?DHKv+V=doW>Lwt1hXkj@)V&+ڍݚ?ns]57oӳ>YG-Y7%w)<+@'\"[ 1FTD4 5H/܊Y?ۅE2LAai^(zpm-1Ѻ3`x]kDm'i9xwK)ZK0VIe_mn&.ֽL@1gx[f^GC掷^Vݣ39fI+a>EOqoJ/aK9noNNgW_^Zx, w3V632B5>g7ֳ] [`ߕPB? 3D{ 1Yz1ő֓;CN9Kgi"'fZ?ٿ^yĊn|>(ϼW^6}O[ֽInEf@:n7.Ý`OZY# ^ceUF 7XtEUjNJ9FiI^(.6Piwl^N_y%#j2}ײ</[!"p6S jY[5B>1=$ FB.{fh$SP74:[hLg{y'hVjϞ%\o +wɮ[V0RMbsسC8͹Cj="l,ʲMմPBЅ=y+*IhG~gdDW뽁YI1'?N' { ϩ./_'*S'Bg BCJVviƔuZ Y\BLH,g&Ч6'~ة%NG26+;Ou/!kX0uUeF{zJ˩e =EÏTt OJVlլ@zN f-GVjO'{߽ nz,dUU 5'ּeo $xF9|ȴUzNF˶JvDsw̉Sy:RF߮g.7Vk>{ɕ\g-|BS%%;/M@ue8GHl-ij64!~ӗf^*_䅒GnkA%]he4|Q?DK] zg!gi4|ZJ*AtҾBON)t$N`]ˣ@l^=Z37f귏RDy[pp.CX[ ,ɞr`;YLŝ8wQ{5V ?v**m_2:|9HR9?T$9zoF09x(#:ա :Q"Ƀo땜u!\0 "k4n*szIzż>Jq9U*j+w־kr遨Xúյ-WSAiRBN8S)3nIP%S%wK-o93MS2{P О{18{E:x>QT0}0^~(Vӽ1= }u@]2ߪ| k !'3M;+D>t_f9++HF@k<84ٍ:ik(Z7>I4+Ή8{E7js.SwjwZ e ÿK pu:ܢUƉK_.Y)AS{lUV(t!g2Q_͚C!Й{s"Sl0o}IRY9za8"86gNXbGq/ 6OQ6 B,tjj,OCv_]9{c …uC^֎ 4t&\Q~@OX-ּMEI'3, Ae\:MB]XBe%`kW1t["@a}i|/C`IaaE1ʡyOŇ#VxtT!~  QWEp6a5tV\v̮VS XF=CMm GvÝB`]& |Ys?C;p~0O55ICh;w6;rJS[Q@m$jrthK3U {+Vci׽6.8,qðyO)Cw Pvm{`:m31q2z& lDup-ǭ` ʉ.g4\3!g?֣l>&uu:`o0fie{ۃhϠGjI43=`@Voi7УGg6 ,h;$ lXV=:7bЍ7=D56p{„_-XigATkTQt7 y_>F  <-^u15W ;1flMxɶvc[T=bq% *NA;d"ȏO)>=8YiQ[ks#nTz@3/(C,@SGWRR[Yj@' z]U 뷁cF_OF~}_gl8&(YqWGW/*mJf L/ ?3R_u|g] RnHnZɊ$dѾ^-윿 g|@?1Q8ǣ6S 3 ?@Pywy9QYo# :(1r0c&=L\МKlQ ,; :\F6tD|ZP9:hζk ڤg+dg-)2q~,N}uxR> wz|CG=PPǺ&̩׼)Wz%T !zF(W/A1MzPjQT _}5=cSGEv,n;}B rd"]F:8Kg1><׍lγܯP*"㤩;pȜu%;W<8A$@Dp&y1V.3:X<ط9_LZ/v_(7blW4@,23szV .`L.F p3}n=KУ,Q՜h/Mj|^TJ=2=c>i ,04:C`_^K* zU] GH'd{>i#_~<I?؟xS'!:뜊c 91G?R8pt3$n Z,ѳxx?>iN ?N`Y DM—>bOXw#8V}ӣQgv[IX,{Ig_bgR$zG~X@v Ǝ'0"`wYi%JWōL ?>Ɗ{ji b1 ȩXfkw"'eU\bwB?0d:׳b> ",l( z3vp2@qhc>r{C=[e<3&̸-W J9[~g  |Gk: G31xl~SeT_ 1{2z~p0GH ;G3 @EOό7lW}V_GQt4K)@P]LmCW%S270M{2j$I3}:ʭFwA+i9xRϘr2'sx˱4Yۼ›):F{U/y2XE֓6={~Ng0 =.ʢx؜(-Ĩ3u,l11`+y3Y#MN'bJTݣ׮g6cLBLF,>o?!z+skzh~~biUW:=SYn'[jpΓ%_+vt=72Mw0`n0`1i!cSze1'ai H|Ȉx  (Ӿ6EQ$CǴΐrh族YAi]Z8ADk1w5-I2d^R# )U:k$ʁUZЪi]08Sg1s7Ιg;2pRtkAK ki=@_M^_tJ%ޔg^7A9혢ƴVp =C@v oJ#ԋX"64C(|`8LWUkas}JzV{uov}RsIXrESlg GԵ!/OXE%kW{: &ڢdacMjMs8ƫl.-`= n-ѐ.tJWBF¨-I 'V4SYtԨ7B\fS~*ƒ_dR9/vp,i3rfz[!ؽf48}{MA\vUf~TBp.t+[3sZOVMM} Ұ.8a(.ּ6&f?SR€}׉U󙍫97כz3Ѕo:w4soY/X(EC dб==Fyw[wéE5k]NsXE.nW^g/ۜ[;i]f.JݟO?kpGLόI/U{t^*ڭݯ xDBbsU7]!LoW`揻7qtMǩzv`3,xHUo٦$[F$_ziltF=X :ٔ}۠ h|rEc Ƿjͮg);;4 ^]ўk?D;d_3Ee0&K"a`WpB,Kϣhg81M&Ԛ4j!K;M65ҴY'~5ǘ߷לMÚ.!:fx` ͌s7+Q |;SY'2liw}?>ӫut/єolu'XF_/È}@lx&}Z+aw/c]a4sSkOGM'b=k}z~Z8FBnf/: 8[@7%Jul}n+]kj40M~6tJ= w際vB=3n]}1Z]A )Vw~\ ;J+64vw4X~Jޟfr[aՖ1&hڋ<{6UM=6dU]Sm{;yqsPv؄m;>xv8y?[NsK@c-(qo`fqAv}(wi%u@h8I(cE?ž˯xp(*:,鼝ȡ,rq:rL *S4'F6߫qM{A%'Nܬkt'F\}P f5[@H lOH2w.yk U; p4u7]_퉇fy?7nGvn䬐N֔߄p`]A̰7&H-Jپ#jjl#?AbғZl 1tO!~ I$-{`xynB.g&at3%1+idu4`>UN]7|N'8tO?JqC"p2J栺u#wq73m;i%8/ sSl5ivn4d~u~*Z j*/3cߎzL$^IMqZ{ 7[n=xVn*[.4a†] 1DHz ,o+vu )tVkMtoz+aRClT'3VT;he|+v'w7Jp/#m\5J'k3ǔ[L\;'vs+WK#u];1%.|tw%= {K#6n[,IѠ UlB=%؆~<ׅ|ҩ8W.^;zIw6RׁKriow S@Ҥgi)^3Moxo2Mo-7Vzw躀6S7V~[mmͅpm !t˘8g;5mjzgo I|ϕB`V{kf% pJBbb&OrCb!guV%@F>~ԅTnbk7m_?K36gl׎]ݚ:5|v6sIxb.ʾ>WbGonƮv⹸*ټ t_EEҰNnGڕyx3˾FΘE L;K2"-S=9Ռq :5Jí1~k{ŔfHv,Iw$劔Bt RNwf%,إ٘Lʚ%| 5ʼnDs.L!ߦ]x}|Kuiڻv0R# SM~[T:sn<LknHaX)VeD᠐h XDD&?Hc*uR.}Z0Gb j)3L'MY`vmB,GnEG-}qëJW[}_ 8OG,< ?;&*nD}qv|W}shxPѢ,?:R 0yrW)=Hd"#5uxBtD?feΖgk~E FSr\ j cmt0h=+N;ڡ80L_t3,hJ9tkzv>,N DnԽwA6zjX.\&^:dNPd$|y 8o?_/7vf/yt,ZqD8:LSRiAG-ī|y3!(h@f>_ ,Tm婝5\3 sPkг2S$JO€V,ٷBșdXITib8-{G%+|崖{85CSw|?@e?؄dYl%pyG|!횏GӞضD#L B/6 dH=GSÏҟ7̒[҂+ NթGwJqCFOLD4TC>- a8wc/Ea7#Ivfye0+P#Q 7ll(8Үp4QZǬ]pP=:J`!̓ [Yx퐂6-64l>ofr15M_zֶmsq:QnxdniY P8TkbuU5 3xM-T4 =C*Ŝn!O4IwE<p~|$@#G3V? 05>[ M=ޚOmVG3$TECM"ylP 7xI zaT6BlUh돸sTw{Nm"}k ʈ{5,_~ǫ} B)oU?p 3ˆ!1*#lsJ8[}uw |w=4@1z~1z:(LK6v% F/[ H9sǍrtwGgJ:^v[ؘ{WN{25lAe/Iψ-voɅǰ` 3GUe1-|t5w¥Lp|l>xcQ!1䲆wm?@ hX6Wa0'ӳuAg*i*gFr zmBӪIO[fB 0ᠿs=`li'~QAz$ʞW^9Gr&0{ouCL({x;P ޒx nz{/ C{WvtPz>M&gV3m8Z~r}>M"v'EVz65=C?tA 1 l' zlA٭ .@tƅLNBN#>SF$AʹO^5[rwp`/{Z*}*l,p#+K=s~m{(:)Y|`avLB x/!z&/1خͶ/a>crIPޏzkGPb ʆ9''n5N  aNS|ffN>>DO!@ROJMt/žgJ=q\.:33po3$)U`$ƋPQrq3+t]m #oΦ%)m~B˟<8yE3 .՝w %Y‚Q,c5F敁QgڪUSk` Xtlq|ϥ$y1Q@ (2&AdM'1zxHgikMB}_}j &VWʫ6'k!wVCKoHd Be" [-ֶ¦F2uPveРOGV91JXiޙQGD_\ )FqSn#/!GlLgajx1(d~"AࠟJ$DΜr=b5`44P F/Mw"vf$:/o6jkRC:hO4d;6FuoTa6MJoQSLn&(#_dkx`fv9s3=Ӆech6 'F,g>YUf#5Vĸ%OʶmdKR\v*N$H27 /sWHBЁЍX>KrH]Ю0mr1նhp6]@8NGᕝzM2T+[#Ir=,Qn@?hיY{v/6+*km-۵rֶ:nsq')tNf:}ksnt$gn {b/L|Q7A2'M3=TX$ sO}nU9.)T Nw5Ѽ[6׶o[q/3:CFY ->7-Udn`A4n꼽Gy -Old)NEsὺ*U۰]43ىwVm[}ѥu5hÕAwϿmu[|]߇-?WE{Z]֊Z;1Dslj|i_>_V+ZuI[ƯƑk_.l|K}zL״?Y7~8жFw~YD?wa9~F=t+{)Em{ֶ맧mDnעWK#ݔ/o|]k[ۢyo"/ⶵm`ommpÌmHm[ֶRɧ%H3j[Z֫(Lm%~V mk[>Teb&<=( J렶mmm4;y>ζmzֶLsV3Wkl[њ>>Wmk[>VmrcvֶmoWܶmuYֶ:PI׭q_ֶ~AU=l[ֶf7lUCj[gsmjvmT;Ӱ[ cJ/ہ- r0W۹pֶ?u2&U.R5ROS^$A ϶_z:ֶ†dZk#Hhrh_z~vj)g^6}>gVֶ]k*TUp4L-0PH5st"a虖7VMkֶ?\1U`*aЪd:_Tm>MM~?N. Vǣa 蝲Wjo8\Z6>jh[&xUQB+JŢzn7kjPi+bYUdoʍ}ڧ@=ymI.^_eUWضm?#"7U-[a"Sp<~/U&Uf_mY[rh"ZКc O'IuagJzwڳuQ_+hmk*+XCPէǧLJGA4MU {xx8z9 xa \l-̉n p~Xv. GpչgvgԶmmMwtΣȔhS%]<=<>|&y~|8zUj$}~~zbf=dI}ZCUiΫtPGV'VUͥ7P]EWö~ƺ=鏶ֶM7W'D*yzҨ緷ϟ___?K{5E9A;T*{A[pV٭nb[)_ժeѪ0OdIC•hD&T20[߫Rk`Nvm W EHճl2| 'MկXTD*]{}/տ޾TMS=³gWѻv5:g7wjw ᴝFjҦQk֘8v':ubڻ#mhpFb2JT^sTV}x4>ZҪ_t8ڣ7gıZ[+QIDaUwU?KGS-.HnXx/˘fzֶM~8[UUQ>K/U*@3=$>__E?oVᔪ'N/o~AaUN#2۪'X*d|u)Eh K48B2ogmkڠg&@þILV6xx+9ߕ}iuգTz&j/0=zm?NZr>k(-/|:j4LVֶ?ufgO_h 1 # %~CA!@[Nu-zX%bt0mQ=A2YEbEFgGYbIkmmsog*g2V=O  m&Z%hCLSl:P2%;f=;Atz&:X^>LV.g*@zֶMtt JHSYb٣6M^Q`|J=J=Sl:S V+%Z;i=7KCǷW$H|6AAgmk۟ڤ ҹ`6hd#_2%td`I")dأݏKI A>stvsyLjvt/C¤ݼ0'8fG7NpN:9BCݦd(@2-d9fVE~ #Z|RbeM3[T"EB5]v~&gH\1D j %V+m,xf̈́-fj׫M4AF>V{վiu l*7VK5l.I1Ϩk=>!;[Z@+Tmkڴ Z%JIKH,(/ǒҧO~QIC!-˜iQX4jomMC3Pxi~NV9N1?l[G5LݲQy<\+cr68H0(}b!7׸O+̦i_s[Fjr'3//0J￧}5o[APi`L>pQUQ }2.Ge.ׇ:LmlڪmfMeC]( uQ9J@V~w-{q6.\3߹ sp־~1؄21m5 b&W9#榛_ڢh2tyjY,wpv4+hM'OyWom][t\;kGpTs7sdڟCtؤ˺c>Z[QѽN>A)ޖs=.d" G:[k9u~vcqH;xm˥ֿkܥ﮲Xky."i..O\{vSkha_ l%aܓԮ4a9-]A%9)ILN PJ'j8$U|RgY2(]x2%ߋ.կ~m y/<|;{phԫ9X6i|_Nb|+^ֻkbs\Gb+ZNvoElA0W[hW34|KX 7 ^-)qE$7KwtA(Wc3T ԕv&\N;ڥl k5b WgYk:W>wIM>Ͼ~(vW߸ҟڮ#mwh.L(%=+ #^ 23v1 6EٰGL: *xpֽb$;%a˰*ˏd(wr:oCMGRnzb ʵbn!<+kk5Q55 zPx|m ʃMR#R߼)G1#=j Q;Gc.p,É1Ci<==[- }(hُ>;pӸZҼ/~cHrN>[E!Mg{oZBw BEkjz^[ &g &wZ}/NdᅪP3;,ۃi .uw'S:-VE`ˠn2 s gYbFOgJ^Ҕ}fYXt2<{ױ? J:NwpIb&"![&wv̸C͡Q&Ujf ֳu~缠-0l@&^ % ?yE(:2 5CW <:ڠoXZF,[Z֚)KvA-e(I>Sj"xH<!!]Fu'꫙.t{'a10+GE&mD Bh@usMx.MԣI͒Y=mmvtTw"`Z2Qס@[xsjpBHZ25Sҏb^3ʑ-}0@}<ATnw9ny(P@C(:w$g*xjM3[n!8RC$nVg B:4!P+x֭#_\x_-eNM*ya^x;v0{%πg)ij3H-KvO^l KBϳ}fڳ7}dR @Rs!˅(0t*ƭ 6Gf讻Ӌmߨz]4F7„{ϰz_|,mw[x Dh_aѾ `(g ];.SŲ'*8N/liiX Oslpd;c9[ OFY|U,_"ve 7=mƖga}'g{”z:f1χOԄ'yp#tމL v~A /I$a>y\|ODp7 PV%hK xƘ&sAWi) '#v{m^`&0n !{xfjg]a'}kx̑9l*=򓘧8L~6S"a%ymO*7?Ug/ϱU=NUёΏP!g@̒!9_|#v[:=Oqlh)N߄3MG7^@jmdfj^βdJqskh>,o2QxdM%y-ԬoO ̍]aI;M#Ӷciiu9~ADG5RȇrvĜ˽fx?9t$4*`a/ںakƬQY3pDI !cV`GF_w~ثϰx/YK${rgTZzG_&?y2)=|a/$ k RD9d`>k9Gn6tw:2Ⱥy<`Ğ(y#!ű9^^mQĬظ'`s,xQ5} kb(me6fU!-lWɛf8eoGe19f.,%|yd:{MB,rn0̐}V{>G>rM>c[Jai]X!}+ak8iqoS/>!3LgvO#!4EQ9( Me!fiy?,7YR ^>D%̤c|K%`viA#?jJ$P858T?y4i*ƲtWp/4Ux (֯2.,ݍRV n>TAE _n#+77S|s&rC`#򮽶G'd?$ ^R%A2{bͳzI+K֤3wM%3rw53F|A(ELCXLWr28#H(nmeSȂB0˘ yv!Z-/ W!ZSF01g,.Zhʖӆ|sVfY:li%j*uG"4ũPx<)ޥ`=f[ī(4{Uo`U,,%d`"X󚻥 Z?x\& Xka8|,?DOg]&*ˑA[z!pٚ#˟6^fFm$TFyL$ [}3X"0"l&\dRhM;Ug\p"IM;*;nZ\fm™lz9 & dhp0! "r`߀HF=7ncIR!@6D0>"J8lK&JfAq :?hWr!Y!Ol]^)+"b&(Fy0| kiMt/z֔]#iy?2q%eP]zVIS5Lw;$=;YZ#}lnQ4IcGILxZIEr,2]=%Vg;6H +Bޜ˾O^{ q%'@NkMGY-PN3H^B<3ِl1*I>?, ;nZ?'j_-FI-XuPrONg$(8EǣGC t@:eX6zaF S0۸." :A.T?%KR*T["t۴0,#S(VsGQ?Pp*b-\!J&l!(èYeİwQ%y6 .p}|nqO'E-?twS=u CNyOmcX*:-D"VP[J螏xtNTe/UCCZe%`pU>Yp*zwWt2Ba\3g7ٻ:ڀbOI 0y/6>Eh>LNZ`1XZàe=u]B8 #`̮HNMXWlOKx&Sj{1eZlgl}siqV< )>ڝ2?es`JJXpoZ/W2q*5W ]\wŽްCiޢޡ4Z5h~R~Fp{_3KLUj߅)ԾiM0M ;~>es_Tk뵮֕j^AX!)6pyCOO8};kZGnRkpAڐp^辵+5mW*VKOQsX'wuϡI{gP%ࣣĤ fQKUB?OE{W`PPdJ}XɣÜҦVgn CѺPz7W.F_Pwc?X춶oև?տ&˼7UA8pXsV|"VZ:hJ@]'ZEU+n83#<S{L;>7@ov.%a!כ&Ju皵eN=)ՕDnICd< n♸6a7C=.U5xD~r\ZD(3')V cS,kftwq6>(5K7.C>xs=*9Hs(SgIZfъޚNh-t .#h}wd1br6sV 5T}R"c*>DѽA52>z6,^M_)gByw - %*y1Ϡ.L`yfO襾p|sKkTmPV-PrWzԠM Ť ̌^W߳‘4}X,$9P~"K=BjЖ5fپ%0\i7Nj>>1c{D]<($#}q8_ h(a'HwP?4!Ԑr<9vs;ZQ iv kM+FiTjVJB5˩iOYzϜcϗ @y]=4B; lHC 둁MM9gP_'qEWv辇ޏdr?$]s}].2Q4Cz¨;1u9CSPiK倯tT*D/qk:uLJ:H&M:I1m 2ǩcVYc8fG=߈B6ӵI6IćJ2sf?DZl c1{?=P!-bU5s{saDڭ&:B˿ ==lb/IpڊL|,_,i]):W9UR=l绉)Z;Gzq0tUtIb355%xeN41]g纰{62ܞ(H-W( rSY:`Hq'V=aɩqF&5QWhNyQOKۋ×LʚKcc2΄LE&ڊKsnqX LjE;eҤTVdFdad)wK0p*2̔T^rhC/^AxVf)嗤ZzfJƾm PjX(fqD[ᯑ%<6Qf82:lLYK3kCq(4KYLFh$ǡYQ3#1Hkn#0*Å'#fdO190Jc`R4o9mXI\kAh+ nl k2T$UO-Nv8:Uk{ϒk!.ZYb T&,,N&8ksyVP8{jX׺ȋ Ү7)RN{sxQ^|JZD!vri hQiTfxL=a:zk ǸN⟊EжB d'H&,d^\W  y.Cх 1,58~i17ÎFrQk9u䦑&]:m1rnt9Zx~J2xr6&3pdk?䋃-k< ey1;d*/w0KBe "- pN.`@ z0su9|p0E݄J'D5Vg$opt],+~H5\OTzJ (N~Br2&B=sLڑkS𧃈]nGn)vd*MOLH(Ҏʬma%%B9݄Z?^W6dXlO-$Tmm3=ᷞ0xLDs_,52wH@NMA'K}l)EeʢsiMDb`^߂4As\ s~r`S| qKUF])6amwG}'҂n/' c\7 ݿȠ%ٻ__iA7E<ӌ6)O?,- P"=F(1բۤn m^@NJ{]$moXA;gjbCP;'I)@'ݾzK R]M" سl'W!G<;("Q5XXA?ڊ4DSBDK_Ups=܍_[x4E2{Q ( ѿd\x`,̕ ϞBH ςcn,} p^]f< ϰ?QzPς t? w*hD١WYLtT 2b]'S]Q,&{+!EM"}5v"}Hl%! u|rE| Csg>3Ls*\g^f}$s^v`~qnmI'WyOz(C@.zfKm&w1sG{aW(~iT>{uW⊦ LGF$i:yDBnqww1e\CWîη9B@ xJ9KKSΣ[0I(YLCH5 NuϘy\ꄏh:5e3@z"aB [`hlRu]()x*%2v<Yb߆v>kZלtۤ1&ε'O?}8+§J}#M+Y_PHxsA/?n]_ۉ墨KbC2߈nbgbSqɽ,ވgP=CY˙hE?@&gOh޺ā U p.-XDQ"m/0;"']\m].{N*~8} ,WwdȏkrVxЦ:)lzq:EY 3UYh/R-I+{*m]Pq'0Ya_\37phEk[-z”~5<דtN)BE)~xҹ䉅 c.6X 3o8ިR}7x W) 1?téE5O419~93Lej;Bp x8e}tm0"__?BR LfSF\{E0  ;|U >E@<ױFup8eo_nۄb_4~vsCZ=֔cžM| ^ہ > }@=kB鑧t}A!`ypΪVOR&@Gc㩃3;ÑTѬ s]6l$n=>IsxF&n<!$t8>%-<8spp麿y͘/*/Lpọ3?Ggq}Kxzn xl1C#*կw@:s@o,y A 64Yg>N#Oa!lO*Y|úL0 g&<e3hN<]gfsx yh]0Y>qk[]3u2ng)=^NtPm<^ e]wzyqA}kFR0>N.ΊPd-)OT|7{]Φ2)p$~qO^*55&f{7<skxhJqp,_[Q4u+5Zgh8nnVPq b"N%&ZR; qeٷZ<39zM7(N k7phۥo_` fTMt }W[8=oϰG e&<{9~SS(Z}8䃸, ⢞i Y柩ʑW*8LscL]ǟR!g6'<)gM‘iKwxU' !^cv(Zro\z-nVH1{WH/Iq\{ 7^EOZWgӇؖ1"n&覢ؠMfYK2wd|ErV._ԍD݃WP!LLu 3UG|\2rs8f(eϏ]!yI@O0a(TCdt**A@-*;"ny7&7!_ug>o(8A톲iTq 71Д*L/_1Sx?^hu>ŚOGBX9Pj*8椧`Ru']R5CQlEO8ѣe R)[zz›,y*J+}գSZ❴=6@e!+6X7f*VBXQnnou(!$7,yH2JČ)zuP{7*}6e!Pfamw8)KV$cg;( 3.YԲZ֗N̗̹]P S^!nR1\1HD6,l6|VQdM1XUFذx}oo*2Uy';׿eij[fLņ4&8b[LYkF9|׈*pWnDIпWiNBRәg{rtFfQ;j>k}p͓J'%W)QW)ml PR劥,߄ݢUb(Yg^Quz㨁3eʓ#D gC*r]!E/Zv8Y@MXnRDDK$umN9I9T"btQ;Ӗ1זT )C%bULu4Mf76 VwG$VvU1oM+lhvId2^x) Z#@l s.ʵ[W떈%hQ9МtOnî ,ɯRp!<]ihy /)f/HTS6Dc. C,~1ot'!(9{; Wdqq(SX*HCWtPPِ願E 3f*ItY8>5IB?T礚@8Y".:"I̋hGʒRLg;84b$f")r̥!j^?A|mL˥?i/hFԘ9Hb4ƫP5cO l#+*:H8iE^(QɢqZ)?Kvd Z*\[e$yjhc8N4xm~ ?)oA=yAP%ǵֺU0p%k̖oMЌ)f|+XE\qhVlS}컈l(G"'֢(=*::O&ur>I.D]cnBIb@[EkxFg&Y{\T)pr!p<(T![> ɥAZED !;MR8Sޣ!o#x}"I5LU(ib~Ob?^c*ܵ3?BE<-2'?"U"vˑӕv+.-\Y>~JPPw:{__W>u<7:YzzlOvMcW-XPm a-B@϶O E#Vt'ʊeb畞5=2b5&qյ7}tvnt*#uӍ3?zFww`}c=pPsK--|?\)H߆1Q'} /+,Z.yŲUpx׬em$/q894GC&l0[IIJϕ 7D5a+kdGWr0Htu/>҉25{"j~:i`w$!;iVH9Gthn4 ^9K!є(6)zK'[d>Rkwf#ESDž-Ÿm:(@{JRF޼Gfmf`nظt$&򬞅:%B3LLt':GIfpgͰT ql:d{h\9m^95MRs.6YaX:@lkIryEѤL-Xg*jxF'U@q7\3]pƵpԛ[ԋ$ssԎ=LWǑT, p>1@YC_*/%a'y]R\{'$u™>2bl) 5iGlH^yY T1:([[9vW Ib^$3,] wȝwւA BezO!'AP1 0`$sRw@~.HFFe/I:b,섴S㚧B]Ǘ4 "Kb3T4/ܺjxϿzXĊGp]ڞ{[yUH>;** &-s  ) ME -<-=V{RRŔ;|;f Ԋ%U`ZKOr֌FqehHWv/QT6ׯ[k Fق;הs6'QIvpμ <}f(rFx|­uq;NUͦr{T&`cCK k`.ѳ)m!nBŹ=[rA]ڡ*^\bF>GޒE {f7 3F <)ӑ Ds7NP:oL6Egb{s!> RD({z<$J~A<,ތ[ r .|rCrhԧO hWH53FoRx\ 6~xjo5R()F2H8.wyva&{P wmgq̭p Ԩ72^Y `Y,9N՞)fu%(46jICp{f<9 RF?GGa40m;{!ML.>ٶtF1Y6Qo3|7h4h|8$~!B[|$M'Q3Ǘ3ڮHO4r6)Nv( $Ne'w㸍|:^6;3?#rzGcaLMtaVs3G< %kL<`"#UI:@T]ɖoi *W :x6E@\b*Uyk=&dv8 |˵Rդoc1Gw+CF Cc[)$vW7hn "3`3ĺU|p7ograiwW?Ndx[ԃ 9r``hȖH1 x=*?O&&k 9p"Ƚx]H/^Y~))}*M{ kj7 z̒=U ^" 9!w./oST?9VCG+*J8I)Wמ%si4mz}6 _V&نXP*l\.&ٳ!^ 8&LO+O riiȨr&t7MnZ="1ifѠC;vV=CiezNއG M 왛b!{svVRmb3?{mXO%IDi=hϖ E1"2%iosgr{QѨuӞ 4w>&o#q0#IK@Tx0gbtg)Ů ]`Ș5?ht Fog.H= W9hf~=sB"y )Vc^=viEq)2v6Cf3o6v֟N_Eܝf- {Ը<"9,}#H\ j\h`3Qu`Ü9yaAZ:Ns J >0Vr@Bbg-#(iTg"[yǵxOB8TS Xs0~Q2ĮXl .VҧR戂׋>\jw̃5O JuèY)5茟i xg=lE\t&ky` yώhs&1O{ϽfN<{iM-W}Kk0=wXsِKz^/R1۽v< (Z;p3g0VÕ䗗<~rFR Bh",IF<!9po3_}ee!Gfv|6dfvkJ&Ҿ)pKCJ2"! ^/" aNOfTO_?}xe<(bUZ}i9Kpȃ SďwJ2DnVZx?*.!;?ԧE^mK峜D{VO^85G42 HZT(T,v2g/i3C &.H`OBCRײbQ)oop*mcRp6~HЦ5ZHqGd.^Ib$.ʚiJ6|l]܍$Zq_6gM5$^̪觇N9Y-l7K0R_*+G) t:WG쩪9g*uU?9I* |NyZǁ 0\iPAi!^H'w,N.R@ f6ʐz!͠(T᱉^QF -#wG&NnSBUЎyQ#P끁O"KsV]:&8DK&nG窶_5x+Fx^0BA" 89c }D^tjR048JnȐjcFPtuJ(P-)$|-9KRa#%HŌ }T6ڞlw ]?KO`mbtpl/sy$HL(<۳FkS@okdÂ憷a0y<0z\_p1/N̞4.5_ꬣbUVpMNxk2<[.! ] {J Oѕo-ڝfad:sc+Ԡl&| ^aˢ1ǁM=KR:U\lnݝ^NDtU*OL|ݱN{QmFΧ.|_m8ʰ…gh: :Mb΍N3t:7a9si Al[k3~;v}}0Dw4{ȀAj¶Lޛ3ZeD醈~i[ae^-Y P?x'aH /Ył=g:Ӗ\ 羈YN+ܚM}v+UsU'i ,7z[ȫםF7=>EOz랦D61jewa\H9r18=ewmXZ[\We/4!ُ}PZ;w<^ij~Wo={3/17B+Q{k=s6/g%KeD|-eߟ!mH~kЙ]H&?]e7V}:Z80e_մ:Mhw,uuu<[ &2^fQ^;_quMPy n.S75vGw")A {(=6 }x((x@ܵc/>' =<趱gnqf0e?Eh;I>h:'|Eݴw|ˈI5P'0g+҂/;ZnZh6oҝ勖M j'U[`KΩ#p`t%NMMG\{Oǃ13t yeYFKfV &!?r2U_pG8XRw{+А@We^n<՞Y-xBVܯF;F"ґ9j%^\wgŸhY?EG(W/݋~uf?Ɉ(T&Zɜ,uľJK;@y؏(nc0$QYRUeG39&]4CgqP[^'ՠ<* 3h069Zn:ў~+G:2jrKoc]y/uyσwѯE' }N4ws;CXAy} ˝zgs#(VZ9<`"^rl&)>nE^(r}L ̦uq"[_l^$, '\_5U%({hB6wqgtG.ab{M"Gy L^)H1 ##=LJJ*n]}( c?"ǯ 9{1TLf G8l;p.mHANXTBsww635?7Y|ή/~ꘪiP>GujIyX ('̪pP"g&r@3Cnq#aMQs"@2V)͇3) '8؏1&Q,9hđh4 Z&x(p\lo*=Kb3 9KԬ'AIU#泉{2g '3CP1x"&S=DL\䕒Ծ{2KyliEʷ PioNT7tq&yˍg]ڭ31 cnϕmB4*gCz|k,>, ВnlrLGpbj$gqSc+l[iɇvFiTV5, T1Q %RQS?rBn Ir y`(Aʹ"G!Xrq^'Br2I,cX+*<H;U:[`Kj|[#y&CT,ѰA9ܱѥa P~1jKSXAXw$ht#o^$(ca3>``tN(rCϡuZc=كja쑙9c~&Q7Qb8 C9$Q8@ucۥ.-{&?dCйGTbVhܜ:Ii,΂? >R@nr-)ʴu%P$ !w Md ,O5=åzVRKü< 2[9}Cyw_u$2 4hXҹYƌ{qyk5Nq%lax_ (DVrby TOg;3h~Pt&=M "T,}P1&̼Fg ]-^ԂK'{cd @<1}է yD]D">(${bO af'J2$oj3t]|KZo|yy̻0X6ŽCni>D1:elB]^8] q(?rwg~] GE+ |U_=7s8#zЬ Dm5ˠ s "¡]$OD u@/pdf[(LϞLK ɹ56Qa嚄`:܁_PAf.tҟ4X_9*ײfZ*/02ޢU"$B{N}1 =#h`q&țEC"bד;Y3;a[W'1Q<Mgfb5oSɿ3ptbG'==y_7+x Oۋ+uL)[ fz3ul/,A:Czx`]0}j9Y{jx&#i͈sڳ5 4,XP~Bkdlaa+dVr5=c h| ̠]Qk֞+혝Y8$11,iKDW ;GΞ_@6:%Gij=d(g4,̲ki}yO$F[elX\ .՗O-31Q[oS*=懷Cgg?;ozDzǘ@p&mcbۖng|1OZ2E<rdv95> -G'bNZjClg/e6o/5mh2QQICg%qL/[Ӟ7>k8v/wڳ3W5l2Gmqm wp;&gÞ:W'9{kvc؟8s3>xթvڹL "Rz}p#fC=GË? )b2K^ @y\qlmB +" tOP]{QYSo.ψ7C,9p ?y3a>:NjVr_V53n7t?C[L)1q{-֠ɬh1,58c3ZbܱA莁u%~tnF%A ě=صOgA3ℾ iE p?s|[F>8gq]g ϟ{zGFnS 왾S^gȬA֜s߄=G߯žU,B9Hsȫ嶚 Sɞ =dϬOi]8#1,sĖA4`n%6pφ=p%F-#CqD$>h}p?wW)D&&;ݞ!rD2XV##gke;4WO[li6sxl<e4ԍ<gK3%cD|{CϣjGWE|sC,o ž`/]CqcF~"dZ GGy1"a%Z`'byS -BXsX0~.VZW9;u2(Xʜc\Bi+lqD Tr\=20,iCO.^ n,agX\nstz"ۍS[mJE;4?ZcyObcmL!g[ٞVŚ9 -àE@(gL"fށ&3ߴg.?^( (D?q{{Ԅo$#]YMwdqSz] t 'N2Þٞ q  zhJ+ACͧ-7cda: Cb䟡ǰ1W_*gyƓ08| gvRҗ6Lula?s1]B˅lj>)AHS pTX(+r{}W?WKY̤cژ obb.8ø6o%S"f)4^Y,RH ^Gg3G*ip}cP}=Di8b(R@[>})i ,HJv=4{/IGpcd5"9,^r,ԒދWaZ{F*x3|ن$,GIT0i}{s3KFYSxJkcJ#f=PV5G^ժQ.8&bR[mqP\ºnGG4l*1+K27kpv,U,#*2K/zH^Z2`F#u]2$ Z`dfUv j4ZHo^@0E4*M}HsRVƪjh{3 8EIf`N+|G@æײP瞢O {"x̗ FkcBIk@yI򒃁Y4D%3eFg3Di-Tհ4)lgJ ūʒpV8XG |V_P/ ߬zA,Ð48Lf%@/(KiQ>ҺY ;IL֔ҼWz(npl^e< *_8* F-wYf7J5R\YxsRkᲰγ8Q. jgDi6V29dq; )7z?*C7| {u>+41`%HFN|n 0l5T"c=t.SHN$TA iޮ=͓"O$<_8$2FQ =|")e)jvv$ߢՏyRSb4JƱKv`7Lْ ;CuQN1~eA#D8V~Ԍ9 garҀS_cDikӧ>_R9ƭPG(=GmIkAؠx4E+`X_QN$(Zޓ{wgQJkh Z' )U'>E@3hߥ٘^C[ej/EۮH`CO\L> ? %4V,>E!H(;QzW2&=]ԄyIpeOe|d~s `w_{eԜ9HʣF=U_9Ӥ?tڧ\K$rP0dxˋj%NRBy-'S(_G]]`P壘u{Ҡa hO 7J@YB0T}M$,ư wWYPsH 4l5n*wKq^-tnH Z{:|wp7{mΨýh_Oz/ ծygl*QmI8{uz E9Vf.?ݜU5h B:`B-BzUPU}MB8/QBg몽3u ~@w4jte0DRxֺ%* nPHWgw+lq͏v:"U>tu-bM }i`̅x ּg.:hr>`\ ]-]I7Ԋ>i^˛><.ȸy8r AgeIZssϗ-j^C&go ,6+*w ֖tõ/}-=2I L`8g8h\E:zguwz?MUq瓼<͆Tacyfpeo9H:--/0tp̮0N]܋]ήN㊟{o Xt wCbk.}F;ƴ]F:K|WyW#qCDV;!;(ݓ_h?J[1YsؗX^ٜ)Vc},wxA-رXg$7)n0M|6́vqb&1J0h%!Da6ģ~cv :qC,^<..@X">HDDZeHoF)VgTx}IZ<R{#[k:l|'^.?742f xI;6흫ߤR䪝AJ̇:}+IQ9dM3la%.>Tlj!NL&m'LkЏύKYE ˢ CҌK[9)0l(CcVo7-\Ț eV3280*UgˑR$.x;]*6ɕ !iFo gUaf8By#aYȁmLO. oB~;OxЋx´"O80X TӒ̳U\f I/b&)n'[عblC4[`o/;f2flܪvnxKZ` "!sd 齘ۆT $vxRTVMӾC÷yǒwPbWJr Ͱ1.cb*e2hMU,΍; ,Ɇ֯\q^y³R~OxYxfQ9[J8PS7+ož ߳ J5EO߅l_MtG/I4\Όg Bi)Nк,Ǐ>g G{6Ԓ:өz@HGEpbjH? D_ /'II2r,W}TeҺY0aQG3cSX hS:!g\ ˜;)خ[E:Y |L \_?~ub|7DZJٯ~:$cѕv ៑,|/g<x„w0ş sC]x$)X?MO;LrcZUqAbggؕ0`%C|xB @!wb>-pS}q XgW|Gt)n.Ø]>5Eg/-}MlT׽Gec-!~P{1 :WjLYn2nv~'X4 nLsӞ}Nj4!͸R==s-Źt N7g5? jjބਲg G@}$ =HLq,ց?SE{sLH {J /tOcA Jb(})bB7<]s>Qo/WX#W`'ݎ?Ok̥q޿ϧdddl آ}m s$s}g ~[k3?L\mn ~<p6߉'|g{O gڳ' ڂ?ε,=m ž@t@cY ۳5ȼ{vdX}L?J!8=xSoBg|8Ÿ9숅ɠ0 WI`^Dg\@J,Q1v T6p̙B& 7&Mdϟe"jI: v!5`}!B65vKWϖy˜Vf'|mf8B4@mĹg6t.$"bJ'%d0g%lI&]\7ZqrrueKTΎ:'R0&2g@g綾Y6|ߴ;,&i|UjTZ](;BI:_ k"AP cyלWvFƾX$(N`]FԺȀV2Cz4f% vv'ZVG^ĸas";[bMaNVǖ|\gib=ҧE'L_>tv@bm*>?lJjgoҽOß!ymMq d%;@H;`{y-X۽0ڛr#`^5QD|nGJiNoJ\bŁ 8 NALַz_ [[xJΨk^]t-w[]7gQٍsTM\ʔnj B#g SdzB{ Ǜ|YDCB[NEMÔL.5'ԓT0] N&xqLӈme$*k Oeyc0557LPJ`^if5˺xc0ƭՇ$Nfׅe&0ȭ&_[J5s1^ 'l"t3R_ xhkrʝV۲c05ڟ0B%?s++X Q,YM+ 䑳+jB5{&xfO E9rAWKb|;R2ػ۱,\ʌ *A} ь8 ЬESRB Ixj5uEs[ 16̭o4\д4}LJ;$"ٔ*VYu _d%.+a60pfzC]^v! jK'X 3א\f*(8{%7)I(#Rӳ#ɸ,I[+LBW_WNeP 9$19\|M:dm0 ef]'_K55 zntzFR2B`:Ksm+﨎f8u<.df}a` mkUĠ?tWȗR+}3+^^wm³Wp=)Sl|tҍ)Ζ?@(Q@\Bz?eAu]6CsNx-_bwo4[ s$>twEz'ɡ7Gy{?0/iq}yZ 1>t7+l]iTv:/+}ų]PnGWw|7N|NG+"&+*aR_-h 5d4Athl,;[np"&_Z[yF 7 msMt<+y}. ,C1nu-ؗth9[,q-_Fy|gB;e*χ }P_s z2Wftic8Y3#/Z7{$c+h}W;<3NPk֛kla%oʼnnH48[gtPDb 6KѫtdZqʛNsq wg?܁?F ҧ^lM:Om,2 n!2VKtwO*FJn܃6DvE+îHJQIV̙e_(Îa'\i-j~2BŁ 'zsee<\ _ãx ~ M*1 'PE'Z?|i lEq=+5͉XRAqYuD8D`ƞ&Q q^{d>)$qEtzX(c/d2g傓,M`D)wäH/Ap'uca{FziOt)GZƼ#,|7ţnkaabG.-Ǫ?hŵQjlCO -9hoشHuuLݙ1Yp3‰|՘I0 I/ : 68f6Nw}hΗ?Cqu7$۞ҏ#7{ Ű˃aΓ2wog;fKɽi s <퓱$kHf|&oAͳŇk@B WHoa}~owhS2tg|@G]8ril DN|1.{SM]sa+s5\ }m$.!4 Q+L>r˜HUĢܸX͇h=.u^Vݠʛ+ge:>UTeJыo[vA( c4aHY1y+7*ˣR+IάIyzW U.(-S-k4;d*þam9[O!wuɬQhG@XwS%±–ðb?Њ67K^|mw&W<᜖2 `O4X$]&.@d TtL} i];D ͖[)>>M dTqsuKҦs2QvY{0[:`ն]*RC.r͠lv(*Pl|njJʟ?Y|sVJ.6[-tٌY⨷yU^wLܙ.O ,/ XY3Y`XgI`$F5ݘEöF~P/N GS+s(!^KD5> gP-[LdCv8sLάYQMMn"t߬w,7L.YbI(Fԑ7B P3].9fzqK^fv%N Y=w?Ncuz@9bFn7`e T!^ z LJ1FXlhmLG|{5?[rL8v39 ">jr UnQbv!gCs-u.M hg%X(4)"Jb#Q *)>]J )0MX|Zșvx9 \rnJcB;x>ENWlSD)QL8vs8cp]͋b[FDd쫤{f;C+,VqfXl(@ 9. &!=D_ X- ZaMIx¦oB5G:[wn F톢d9chI^`W ,J,$FB҄k''=R \"uGO4ib':O Aƕ7୤V=Ԁ6, Y׉A6?yJsI"3jARg%KפO 7Y4 qG. $J WМd)6+\ +Iɟi bMgC T0 vzWx.ۘE3Y{po Dfi(4;9J9L`cq)!CZ.G+f[qKAOT7YtHfhY>;oIp+3V1FfXDdzϐP7$i[NţgyI feBʐ?G|@Χ \Dq +R4 dakS .`\xA^|Ӭ=HOr^ K֏zHY;-Rҋ<&ִS1ox|B<PJۭ֡nۧҡMځk 245L>\QEPF)|p ! qt> kS?@L /Յ+&l ZFB+o gU(}:oGI<&yk@lXkMy7.`5?YryŸ?%ZYbF5d?$p# $bfp)|09f!:3Cg0K%p|UFO (͞18 D?6)ǩYg+>)3k[RaR#? qLJs !>ojς\n࠹g'3RdOILW1>*Q~zC@g0v3\˓W5؉ᩯW'r|·'f{; Ga\9G F}˟;x K| DIPixnlg9ag5]`^[WkkglOu}HKY`Ksr<2|GM6$( !Tqs'l9VMSG@)ʟٸMby)&Y5?q|@Xc&QԀꈘ|lV}">7; 2)2`n+Gx"ue| O_ŀHgl<=ڻҟdqOxXX!F2XPNG7}3i}3s+CD:#N G.{)B{=WǠGڗYlQ(7J-?c|3rпv)9sgC3{ú9RWӝ$7#9P lg;'?ӣ0K@idbJ J IbΉ (hs#d$͟%-œdՒ ' vum9>c,N \F?2rx K. \6 _'ܮMDf }?_A腸'GQSEOF{OL =["W5Mɭ*Z gɝYýW绿I94`/0?K=+㳖?I  lH\(bDh2:?{p-#Ʃ%f,q`bLbG#!w3Rz`2mH1ЦåaDt@oC_~g7Kn@QsAo#9ߤ!m )C 4.x7ǀqp0Y?ݡ*.tLb{BoZ|Uj)@Lt/?१Xdu2)'7 Yz~,T(ƜڏRtf/nfRrfĈ7#!g([F-FuJsI\7n<\k7О8wٚ;rV5,gX'LkϘ'p-W;[=>ѝaY~nIgansjA GfZ܇39D9A{-|:A[=FZ[&.1x>OGעϟyVUS3oUyRJZmz.3g7\ҁ?[0o;f1t i@ܟYW-Us85Rid3RI]#Qmydb.'6n6d-r^j5[BvRY?Y=Bk6%(G~Иo ciaL":2,ˋEd#GmS"XgVQ#59 !0{( rt T&nVn5EJGH1pk`R):enF 쯭Xk" X(tοXLUN逊gԳU1`Ѣnv g j%B9HN l  [ o{smLuB;9w9gY{ohH+gaV >Mˣ[VSƷu0cb Dk/[73Ϛ HXeW֗cF#7~t꟥1G<(\"t/2%JXOxv.IZ)s9\p:}:Sdnc& ܊:~_0ɂnw#Wϰ EA+,Q*>]7DHd9FFuiq@ƞ"..QB,Az0N8W,ZJG| 's`(SZvXM6.G2ܕPQtl-~ӛ5[*4H n =HT7YͭC9+jM`M^mrtn\ؔT' pt]F,-*bF/.'W?3]Jou Swg.%Ēr<:/ 2$E;k׈p#ipr\xUu<\z8yJŮf @s!rd}>/ePv.0gH ^~8u:EaRcAv x NyRqBj0a!b$LGgd%[.ixE'Ƣ:>M\Ou4pP sY 5BRS*TA\sU!D} CEH<'t ;Ԑx5'l:P`_^.U+\#bsJ6./>Pځ\ CJk:Q)10k@:ZҮGPZV,"98M_M*B7/Ǟ[>PB>?[LT*֓::.6T G܎aS(fN O/Wo}.)|~.iQdLrޅE]VX Yriv<'E-la3 >tk3QjTwC;g3}9rа3]y[Zξ, o$ѵaOsG|U#gvV~J-WfP.6pds1w5J-?=Cq-i 'mVs#QzF/(C(Gn\7*Ǒ}'zC3 ?;rk$&ύҺ8zkKυowN{٥ws_IMAԳrŸ~y%V JٝxwqHIof1t73,Qؓ $Ҵ$d5ȡCڵ{z7`جs=ɪSF(JU{8< =N.eQ4*fB0MzNoMen._#V a1^kޖ[zڻthN}`/?j~zE ]B) +Qo sP,w.Uj-lw%dBBXQ.-lBCC-ju ԝDw+mx$.=] UPbc7}.zCyL@;ߖG $t zh0?AEeTp6h7yphD2) Zx+A*/Vv^>1wW# V'?-.Xz=M¯_Ajm9a-\o|zT`_.:` ?=:.<tzd@*/ `כGإQ..Uot6HԶO\}gýϛ8 U\>. un[Oգrh%u >N/߉-RE9.G ~t_[}7P8t/]v{v׾{^).F "_?hGZm&xDRl|I yxuyWn|S7]^G囏z{[xpq/5[{]GVdO*^pY^#[Fch׎_ kh0gKWveE$߲;Ʒ\Ʒ -IkyD}VsqiH0 .O%W̅p6NЅ;3!{7-g!/T^OuZqOXE<ׯYtx0ZC!Uv4MG6TWKmkok{v|o;wے ;v~anO:j|:H<җWC`hSd&YZ$GN3tZv4IAu׆vяW;<.By]b+W*vWE!U[͋7[}? WD{娕'?,5a SQf$B@bDhCB Sqޜ;zthfBy _\:,ͰQ9 87͘*+긤z|ΕGdvCXf$U?c bseRvfi ,yb}q IOL:f{I?0nK{'k҃?Z{W}%lГ'hq#TR⣸d(6~|3BRԠt/V[]τo%\5@\`LП9Ѥgs Vl`x*JR = kBYx ־7D90j?K[U/ʡq;_Bx8Mӟ?*0="54H)q/㮳8zfp ҶhD7FFgIZq@V 0-CF3@T` /&>3w@?[lnz"H2{yِ{skK\O% w;q,[ez3yRd%uCAՊ4^lODn, Y l#(j 1x<.5UjվKm68UǛ'&d.PIpi3I6'ͻg3h٤AaiD7M1Iȼ?[L&YA#}.5Ht6ϪUQf}~dX5iMY|},p \0 )Ǜ5$ظip(3ch ܙ7To'Pv=NAgoႠ݊π%;([-5 4_a!%a]˟xZ5B2တVq1o!_lG1Zbkfh> eZ%Eg12->MʪH&lyPz@jg\ ` T^7q5iYl "$|`8{C R[i 3RNS9\c:)lFͰiX8+ &x&`-_0r$kLh)|iv<{2mCƭ.ol2Ng7j~]S'<ъIV뒈X$M4sd$xY]Hp,u/lcce:UzGY,s8bўw@mGL%QcGY'v-\(' |ښVwXz$"6TH;([vuD nXY I0MI'&mPzcVmuaZ42=@Yys\>9<5'-Vrи]]XuA (ص@-YzIԒe ,RYja-DkRDo @X;x0h|ha``Ij/r9g5/ aB ^ eI6PFE@Ku%fu6I"mkfvRZi9uA?9TK[/Jh٬Gat|-X|xp%Fa(ft(8NFà(f"SwLT[ꀏ='w4&4b*} AoPZYQ8]%𸻂]&@ b7U_2פv| Ts8,H zeߞN'd:[@dY<̉TQX9P @hA?<^H_i٤wΨ-LYf^XCsvp٫U'M]ZK6'*}gA u;S p-jݷX wAH6"e5fJBdj;ކ&2q+ժUsCv䄾h,-4vf\F:#1:#%VDNثtgD_޴PGI?i4B<W/k֫N/{کVNfݴNhd_E%$0?.7笠.[Z> G߶˴U}%/fWq.W=//LT_zBwyy-+n#뺇 =arjվ.z_۾Kgk{i_ v3rﺼ+^\9XZ^__?fǮ_8dJw:'c7b:&4 ȵ~ݮ׫Zj 1)fb1O'c) Ǚm494Fzy(v7sh_ۻ0[]VZ˒ Mgr^o"yƅƖk<2׬j^.f]Zcƛ3XS2BiqTRk|Zje1%ge~Mgf~ܬlvb:`gJ:j q2D)\^?]^rF!IK2~=ΚBDVZ0g,^MñþqhwxoWӿff9k 83K̼IF(kb㦭)[ͯVVU_ Əq^燇)9U;7vH5qgbm.EtM4*nk '_l~;;]ت:[jբ!̖4Crh&^;޿<7.-Z͚b:?Mtn6;ݧ. VW6XJstW-BRTƴ ,?%wґv;qni[3ݦ08G'|;oWiQ Ъ?V[>k 1;K(,w\´^^?tD8r{xx~sɚ=1y'[KHQXҠrwzS>а9{;̨qh ?VZaЌiw`tK3f/}̣%xϚ@o4]OO/?}J[7>탹4L4v/^jBƝ+n[畵'}t' (;].NϩXECf{~l`j>'2y҂)' = &veeht_ggg>Cxu5`)g@k֎Ŧ|>=7O?|hhǝ8h0J,--e?5x8Az,SV9}5xgϚc^bt{xt3?,g+*Cϰuxb:},_|ߎq9`HkP0 T5H%> ~On6x6NJMȘ! G'7Y~cu~YͱiiiƂx@0kh ?"_/uIflc,nVlL_hQz%h^OsCAupuloJBmplCqX!  /Rn'-ge3eu=쨙wڢS @* -r4b/D"]Z*A\(m}>}G#.Wt逖 -K*&hmh Y$THMlmLYk 3!`"?{:7ƛxPi";ji k~q?m. 2&fA[D w >>A=B+:GJ K6T-r7fkuޅߛ.շe|o 8ƾTgtfʡlQh+n7[즷D)d׊.UQ1"R[UJi|4rt Z:]K[#biz>僫 uvUScsYNQb`c;[_4 ;4 +Mڕo# S+ GbNSdL"epV_ zRGJR"͓8ݶ^{OLpN!~M:ZK-l?lMlPTl~:[637%?z/g':usĝ)N$]f6ݰCnѰ8&V)7uT՝ƒh&B:u{QK%.H Zd\\0_G ]ҍKeܜ~׻|zUi=N>bL,gc*k Af4|P7}zV1H4MNqG־BVmjᱟ]6:3l=@ 0wk dIN$髤p0i&> )xv\ +Kcި{'bo؟}"k Ӯ̢!_Ll8yʈҤ[NěfmݐI)0XdČ|o=sCT%m۷:dָ+aycOUQd\@"#`]صC&%ML b 0nDƪ]X"J} j)9I*>GY{F*!0TKsM)&Ţ(:j~u|4XO!]CT *H``)qinCj%$ijJ//A]Xp%^䑭/}๚6@){^,L.SO-E<w\`j[Npu!UtPF.KG/j.JjU8|:=~x&cå[oROaxyC ͫG1uTcJo O٘2a;y(NudՀht)Ea[ 68X˩bZ6_B~Up=!dRH $(W("/c]"Nڗt9%\gfʠ8x%SA{2:1݁ T2EH|*@>l Ƽ-uPGr !Qգ\&4B#s`Z)UIU"Uq~4zhZM^7s,PIBk"K.@+"&)v//0&Lm 44KK:hēZE)`8!*+V[Y$f.FYQ(G>؏B6M|)J\Xkl~}W 7% @a"(x`Rf8<@$^H(ÄZn i@&Nij)mѲ&(:;bW24)%h Hhv愻5pL$cL]LV~68t$L $QrƩ-N@RsM I ^ UT<`ų NETpZa(j,q~" L;On)T)d[x[qi!X]QcϷ1*4\0ka=veF 0 y,nu-(.C (qMg$f4x&""_SLEA3AoO%߫:DEH&Ϩ#' eTxVoNDڙx;L$j?D.Ӏg^+xXgEdm %g`<͋ٚ{w[|ϞSO.P(*ރf{@3!SZ^r Ad/֣)Qt&ozno.|?l&ޤ6\+M\qۥ %+qŖ(hG^.$p:2I,)M##p[;Qcpδʁ= e@/IyU U`Ϯ:Ϛ|aU;7tlfXy9Q'0j- ϸ|lGC6 p+3?۹VCN#ԇdg/WGvly?da3MpcgKGFF[W@>\# $QV4Rj4!Mb UdtoL1  xxzr8Fk^ʖ1c5|ŖNџS<;rd.[LS T xp!O(>!oH[wƙK܂62_7=f֊g>D>?( q1S¶-~ew e{؟/I1[a캃3k\\!G2 !_\)O3g "3,ztITt5uMhg͊$RM=af:8?#pr.dϦ%9rJrgpg@ѓhϮd36٭Ziʵ5u|,U};. J69Y>-gcڗK'KFSA>&;iB3MtMGr<99SxЕЙyk#6Wq[˂gvV, nm˾dZJT&4^Agw5M%[L%3:^X63Te^3,y1DΗo.mjn ㉕cO u))Sa2<[-==GzS^ɽ\ 3iXH1e[ɓnQ5v%QH}_wK=qUd.h#=?n,υW, 39)i; BbE~8K9Bȗ<#/U?ijw1P4bGk)̩ͼTƲQI{u1at,.4[`F0DƊj6EK6YԫdžZ/Z(;XK֗fٵ;(ZA\Бe&-Z#cD0//Wj |Z2Sw..z q_tr ߵJfᨡ0IUR-XLwbn&"GiE 2*,,:.]95Ze=O$=8KfS2TiX*tM%!مףXg([aN-5֥1(EH hgKZ.T1ӦyVjӲ^x1~JV %:L 5j1`fX> !p0^dW$в>D NjhIRrҞePI.)[Y_cb#݄\Q\YOmȳq,#WzvaZFp͉EaV9dyb?Lڸ68uLMzPߏ5ȍ6sdGNŽu`3N:RGbV<+o&^\cNV\n^9!T^ 68Eґ`Dv2ݑ( Y7'Ԋe^n1𜆲kLzVC(ql$ÀaS+EؿOScuP{{s b1wsB…-n"SiI>ٌBH"`:eRsϤ ldM"Wu""bޙL$D*?h虔܏҈T!7:NLzkϋ:tJ<x 6Y[_YNM!\]pJ2C%~C`diPy'X?RiAppz3.NRy1[oxPָ=;Y;;Cg;򸇇Al}ߩ1[H :\`I,hcӺ|fgș/4gϴIF6ȧ=O[})?<8]sUrB&Q-qw&e`Tdpe;: ܢv]jR窭 JkPq[ZL<@[$QZ;ONm!37ƇM&y "`P\DtTm Z ,`OԔ.xP^+ ehQ:c[xҢ9M;3zf=R~osJ%5Syv} w9:&'ipj]|*.k&9x/H6G"l+m!/RfkCno>8 )VxvnL{gSx♟ںX-K"hհD[(꼓.]7Fϴ~}mg]u|?^^y/3L%\4Oϲwkp&#{=wO(jjEecWع!~:Ԗ9AIIdRGƔ y#Pտݴ/lRs$UZ3$h`MPTx>kjk%|iMWV ij1,^Q G`KZX$-4l{KxO{QNB A;\EZe:1 8 %|\bo/G"찢 ԭ!hyT>ymkW 1n lWc7F$Α+vQ9tZk@MKsn|I^]ok Lo?$-j&Fz Rg*c.3,%K^FL@0rQȪ4"U}Y6I*Fɢ&KBȻe-S ,>oRIߩV"lSCtLsN<ۣJphڸ+>Ĩ9m׭&Ҳc !)W/1cnOyTeՂb/>Y}g̚vV3}TZ-I Y9Dw8Nͭ H\ ;p(I0^*Rmk.XTS:&mU~]sQΰz*A6f)Z'Zpd֮wٽ[.Q*׸>K&Gbq`tmp9"_҆EŖB1yS9gjÓ1WaNNLF}-&M3z7^ YEi1}ԯ' v)*"JW(HAALZ5,@%KNS Mմ0q%zU4.#5y"Yd3Vcݐi՚<0]ɩbk43Mʉ]rԶjb5aꈉk)O&ZX:{R3Gbq֤5(WjYkKlJ&XQMm|lmma-N =%%^d1*儃pNYUٴG^kg  G8HaDԧ'~Fa Pq69J[=RkPR~6z 4d ۙs%PZQyѫUBہ2j W5!NRn*$09PUשN_Cq])20dZv&yUE{-l212p$72s< !u<"_H[E B z峋BbEqa kU[3Ob1.a'TVra /3H>8GI@T[v=➭vϯOPMD U:R0UYPՅT.y*"K6bH=Z~ldLU q=q;:i~cWnD1u|sejmTZնc49ݑWS` l!i̵$kڦe|K#4Êٽ7 [+t&t{<ȅPR)6j.hBY-F[Ug(VROLC@s38̯wW6i?>|}j40T#D\d uTBiBh+TF8Ro!دv4 G6)r(pϔl$䤠\JYM5Zt9ϥrձΕIm( Vtܝx}&Z =@ W)9Pr3G!P3tL \ WŖP,;os^L  ?i,].t O t=iɔ@\> "o?B]ػMm7T*u&`D?lE&K?oUɳ05Ǡ>0Ǒ?H!Z %7tGcR M7pr1̓s[72&x! E`t5u0'A?@39 X [ 3OT.!?Ek:Q Yn+G^*V{S@.W;\[RC(ǭ ߨc^U"R,v<{|Πv?Gs}9jYsߚ(OLW`I!3 xFdW~Q8J.Vg4 `̅,P422`ËgϯQ 5L^ghc3o+Yn6G*}6&KI^yE@ a. @"/ .8X{{7D`o ;TFNfL0/8Ž?4 H rų"r4zMFЀb7O\(jbܰ1<ֹ~e[ ϨXӠK |'U q'ڶ&ғEuP Z{:l%A7ggsrU'TCHrgϸkN/eZӝJx6ow9V*(m>h0OWI18ۺhxXpaX킈jl( / [|E9R(?,3_?m]mhY{7]=͕eEaJX<:@06ȉ7?(P4Q=3<' nBE[xoxUg[#lI!lt\7* Ug zszWle-u@ LfĨq#"P; ŨN,%]OX5~?݀/4Pg{/™bn`1(ugJf.}*gdv>j6[ԙĎ4rUrOW\ojWb {*i)w55M"Hs %;/F< GI9"PL'F?,lL>G<]\kx&z' -/ᙬ$FܠFqgB! LUk4k$.d p97ބGX <&FTL}fP\=Эz>vɶh쪒\ML]̉Uh4.EPq^vG^_kݣ*yƚ0DGG\3m%DSW7iFS1gxVVA%fxFpMLwtKz5 =AbjzK=&k" RVC!OGuQF &Ʒ$& 5|<)&5Lwk* l-m^Y:)Iܻu]FIM"Un$ٌ~ V*>׶~ˌ*–.j$S 5Sf(D@WqR(6ߑ[Lƪiⵦ ㎠#J"ryӽkQP\69c|z3`"H8nU^Ɗhu.e̓V4dAKեBt(OS ~KooI%{GDX J ٻ{D 'h8*g(Ү"Y(̞+T g]ۜ@U迌*J:TW먞r2]}} bbhQf7H?1LX'5pQQ=zRއ~\ʍBz9aS9JԊ*y,u9fJjٮksFoOTGȉ*Z[ol*Rƽ~&^.tskQicgǍgFh?Ԋ̜BCzYUy#m[ kn[l$C,EkZ"l<}L(Q  jnԚGh`ٱL IͅǥRWA*0P,*oO(y K/Um6m`Qtm#j*IxV9_m-ƾema:YW2 C'h.FEZ{Sz,]•TAF[)T-ExZ @dÿqvܻ^E덽iWc;*Jgz lqYSLFfc=|pc\ gWkC3ż _9k{ ;V_+晊^[[vvp;W#jW3v@uhg?WqNYqj)`Po1>_jFP{4~LIگb|7[bN[kUWkٗV|8}%.|׾ިw5uZW Mmǜ:>%ſx /7c&rUӮd]~ڳ8ѷ.S|חrOO·2*WK^%e]uæЅ:q4_,y4eNZZ/i3w#8---kEZZZ/aa& ĔFKKKKMYiiii%6&NDLKK8#ѴS}2d ^kZVd2XH=KKK)($Jfw & ~I3λ(ґAiii%cZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZڻ7~tҾR8--7NKKM,~KyഴR8--wNKK],~K9ʹ~KyഴR8--wNKKm,~KyഴR8--NKK},.#z endstream endobj 14 0 obj <> stream x ۃCA_=>s endstream endobj 15 0 obj <> stream x j endstream endobj 16 0 obj <> endobj 17 0 obj <> endobj 18 0 obj <> endobj 19 0 obj <> endobj 20 0 obj <> endobj 21 0 obj [ 22 0 R] endobj 22 0 obj <> endobj 23 0 obj <> endobj 24 0 obj <> endobj 25 0 obj <> endobj 26 0 obj <> endobj 27 0 obj <>/F 4/Dest[ 30 0 R/XYZ 69 720 0] /StructParent 9>> endobj 28 0 obj <>/ExtGState<>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI] >>/MediaBox[ 0 0 612 792] /Contents 36 0 R/Group<>/Tabs/S/StructParents 1>> endobj 29 0 obj <>/ExtGState<>/XObject<>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI] >>/MediaBox[ 0 0 612 792] /Contents 38 0 R/Group<>/Tabs/S/StructParents 2>> endobj 30 0 obj <>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI] >>/MediaBox[ 0 0 612 792] /Contents 45 0 R/Group<>/Tabs/S/StructParents 3>> endobj 31 0 obj <> endobj 32 0 obj [ 33 0 R] endobj 33 0 obj <> endobj 34 0 obj <> endobj 35 0 obj <> endobj 36 0 obj <> stream x=ko9?4p,/v~˹,&_b}HYjۺ+KxcQ$["E}nNXU,֋"j=/^Gv|;X=9]Ot8=M޼{x$K.^ IGeIŊ(9J^Ȓkq/_|$K.{N2ymrar^ѤIY }[}"–i&,rFEJ2/CB- Vl0_giMU.,W(6$mȖ Q/HZEwu wg>4ycrr؀kOC-;b>PJ2N-Үpe0ʋu,RBQ $YfU,uZ.=+Kpa^LI7pBA&(PɎ\#Tu, kX&.XFA(!9mvվ|q'.XÃli'N?,89DOo?K2%n-Txgܘ*]uw.<#kܡ\$\')(,k+7} I6#&)ϹUfdiox~@Nʥ ܵHvy1!Jn}L |̱l -cd8{+8bgDŽU v;Ɍc)\ R؈˦vrLْ!ܫHhd kN=ǕZ]xkq*(Jj /KGcy9kals';Pc3;`&[ݩjN}흜(yown'тShWX'g߼:O+d䌞/YFӊSqY sٔAә]a>DsuNJh!VԚ괁3E(fCb_ 5|5b⍂WsIr Þ:&K h6 RNEd?ZrB!!R8Hhꮄ3IKQ8i|vEǂIugTSVY(Pa;y7G97".y:=pY."vZ+pray3p/uYS9+^nַOġb) $CI&O*f-)IJ>Jg\2G B4w>H6k"" ~e0#|\TIF6g 7狏RʥtZ  Nn*!q53BXєܦn:#E)ZE4T5i ^|D z4&fu)` ʻr% R $Xذ@6n.ΩQFÞ2MA{ QZ&(77,-~G"%h#wj*w~O/%bcxx YK56Fp]})#59 ȿ'{m$iY"(/{ҩ)~r ;Hpcw1bM`uetS̍WWh1Pj˂AU)#. WO 2Y3W.DE9 oh﷘\bGʩGT8d@WrlCQ޻Mrcf"^5\5d<{igUJCznW1Qz5Ջ?E1HpRIi[T`PvP0'PY8%Upb}J`wW.\'{uѥhn;"k۰D :yNyl$lNC&n W.`X9qwO?5WXzg %.QgY9Y9PZWqh_xYU ꢴD# GRzeTM`UpvS%YZXd678!mYLeYnkrTbuMTPR0:r 9 +k3f_C͑se kq`w7bՐM#mM<*b2ԏ|$VB /+ ̯eLc 4vAJOlL21Sp$QPM((A$(֘%OVAzOVhlW~,P11 uYZ6Wt͹\*M- muxhj4y6^xL) _#;w=@Hg,`lQp` +zmp[Ǩ!8ʺ3%غ>[{C )_\|cMמi^`SB=$h3Viach` &JF3gJvSM%ޚ9eC{;ЗRRw܃*)lTZɪ,**w0"(%̮NLh@M Dj Ye6h Pxe] \F(#Ow,pvś s~HFE1Ašˠ L`O.ZeyPԋ@Q4H+P<'JF}Nf>wcr`Qض(}f^2 wdу iRdcT1Ŧ6O3l9w=Gy{{GS-2r$=~ ~Lc=Z gB693 zU"dLv@ *hySv!1@(CŐHuNr0zhĜ5RpG3R 1B+yDgztI\%;9aUNރȫ@4ƈA{r4b{p4x٤Ѱ1u9xOGf;l(GOGS9q4b{p41a!n{?Z45m]skd\Vq92|4$CNᔓ{vR-#٥Wl~ v-D'R:'uzpR\c\$T*9~@7b6VR]u#17s ҄k9wT{gykR~!1lv9@x Gv 8KWOwr-í1KLKn77l-Ѧrn>BEn`Ÿ#uƙ̛ (Ԅ}HOFS֕Ǐr}-#}K@m!A3Qq}x%m*WƨcX`*o**"Cau`*I&cۡz4,(cp FxT%c/t*`Ȳ_4,t~Ajw qZͲ5/ qd9AWKSq'~C'Up9;u.n8;-8%pwVܮ4E?b)]sOAe6o蓏w8gj8㛽1fTm;b+^&x!g>zc/Z*}җI iNY ;$Sc0Yaٵ1}5zumnz0wN015YvBm"5ÄY[m6}ns\s@#j[ Oh]xGG#5M3y#\ki-4k)[ZxX s_fexz,Tmmesm"bv`y 6CR?~hƠ;^g9788  .R6Yߌ 29y娰JlʹS>Z޶5#CQ+lI_|:!]IzhJu&m2 %Pr?B 32TG>0PBqNO팫%]J$R|7-tgs sbz \nr$^WYmX- zS`jR&UJWFY#xRjk#,Z^xԷhpIݥ;V[p endstream endobj 37 0 obj <> endobj 38 0 obj <> stream x\mo8^joz[4v7 p8µWrtf)٢r=6fd3g#ǯWl:իE1f:rt3[Y<9aog pͮϟ ?bpY xgo _oϟÔ;sEϑdi6"H@ .k4qI/;WZ*K@8N#|`j5ԃlGj1!@me޾q&;g(,G$C3Aȃad*T/ %⿾q -;@R4o [iD;!9ohru2&PՀ2`xG0[R__!MX` wU< xZ&A5^>dQ9>b8$‡@L'蘺5}_`ZX)02j+q;148*{lc:@V"n*H1r]Ǘo~zxذ1T ûcYAjН@kQ yD"y tr^D(*NJy"@ꃥ6"Q,ٖ8AVIf  W,h/)L z υo(PRasatFzh|lDhǎ^tzѩ僡 +TxS~@+6!DU/ɥA$|8E&}Egc$]O_f*+96>fpә МQ6%`n 7yB=^cQz?6YGYBۄpdn ^mw"|uD;Ja+*:fVeR)6cl&yS>16%6SN#(ܑ?~v͕as5טDݡwcV|Ľ*@Q~gl`_yPN`K̢@[`4!ϰziqtUg"G,&D &EՌvBX`@zDž! IΫ"nA)ҿ16h&K qb`7(̹ E 6M4!SXX7E'zzpmb>a͌ mgw %>:dyC鴍3+7v cRy}: 7r _(Q!uleN ZyܠoTa7ل+ f?X)l|=cgXF{q*O]]v{MaFz()Ho/[ղ4$%C׹#pB o':-E'*~ `ڛEywʮzY٣UFq<6NEC91 eN rN#&lw;[ʗKGMGq1TٛSjRQ_~NyF/s'+Tesg4c6(oUei8@xuu(kp!g…]4Εyf=-X3Ŕg"zߩQ=r18VLXQlpqC_L]ݷwa3# ʇ`JLabS 5qBm#7Fx16'ͩoJݛ՛o^\+weY;I󿤵~6}w4yim&_f6P]"vN?tR7zfeiԸܤX* '(K!jgS,>.rl|L46z .ȫ.e 2 >ͫ+u#X%;Fg']{]]Sl;ģGs]&TmC]jؽG,]USV9E)b]z+^(ĵHn7}xO}]v{AWQ s񧲢?yeDWhw`D\t>ҮRxdң.Kyd 풊TbzI+3J E4s##"aaǷ0OM5{ɪ]a8siOK9gՉ_ɑgit"+;In1|SD}n4hvr~r$k,wBl"3kŌJ“cq.Ήyi{~"8}丙K\mIDԈ;nʿ4Z%5%xºxdːѮ֪i뽗D뱹F>.ߕjR'+ ;fD(GBiVHJ,zsR[i8P5Yry=fF M¬0uQ&&k:;oy䝄JiܚKT)XB'4kFo]uiڮvŽzu8sN񮪀.Z&{Bd1!<.*k~6ܐ[UCMJ'BXϏpg^_&Iǚ54n#k5VlLtEqn3]r8n@JK+X}J._۳]Xfh  '2XA$i(ͳ $PB$Tn k"&/H1Vs?+]96+3~ds-zd8a$\ی1gUtT źueJ`N>ji3Y=H$/{jX*A[Ns4oVE: :#eҰ|Fm69vR؅gKQ^:;S$k/[4 o5\L!|F8]}DHX#.䓌QqkSm s,Ãu ̴n3WƂ1|h-]AS (Ey XWսr|9݊r!7Jz4Ъ.#cp{I/0KJ:ft̼t 9a 0O2f(iwUVƨ6%CbCѼԒ_0 9 S(:\wE-yY%.'`0CqU1ҰN"<Ƌ{V,%J:b#Ca WAzpKQ~s ^Vp?2iVVEFy+-]]NF9G@( x3J?U~K"tPt/ ): ^Ѱ@LМX{ݘxI ///:0𤕛 zVC { ɫW 1։eLU]FPnp1.[ (MUM1n Eﮏb|᧐]'[ 1tkFI-` u"$ _rXЅaC>; ԡ..:wDW]/aDžDnH ӻTM -WBz61%"r.2v AAuN!eSqo%ߞKh|7;|,l˗;R\ \@*{ge endstream endobj 39 0 obj <> endobj 40 0 obj [ 41 0 R] endobj 41 0 obj <> endobj 42 0 obj <> endobj 43 0 obj <> endobj 44 0 obj <> stream JFIFZExifMM*JQQQC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?_=gL8Ez|yPѿ Mz7Q.=gL8EPѿ Mz7Q.=gL8EPѿ Mz7Q.=gL8EPѿ Mz7Q.=gL8EPѿ Mz7Q.=gL8EPѿ Mz7Q.=gL8EPѿ Mz7Q.=gL8EPѿ Mz7Q.=gL8EPѿ Mz7Q.=gL8EPѿ Mz7Q.=gL8EPѿ Mz7Q.=gL8EPѿ Mz7Q.=gL8EPѿ Mz7Q.=gL8EPѿ Mz7Q.=gL8EPѿ Mz7Q.=gL8EPѿ Mz7Q.=gL8EgF6q5ilMiZj۔_MuMMsڷߤR}ke]iRߤinQ5:MQa>-gah??&ZH']_Z/t M]HgܥL8w@]3jisKv3S? M/@M3jiA] MVtE܍MZF2 +`ixX89Uaw? ?&i\ͭ똏$Ȳ+Hdd* BG vY8ۡw6o4?y)DY83ڛwh041&Yfr8aK[i k(C|?0K![ q F\4lwFS>#R,Lo*{óG 'T3d[Ѵ{x=LV q6d ߳ v3!yoM[tQAx|kk_DPl֕H_M$G0ha0ORvJ=/S#J~]i+ ڼm.es~Gk=ե~edžz I1>qs8ãiY/mh8[g5^~ujٮC6J I?DtZ1dkŜc ʠ?#vϣ;;Ĉ1aDZfdҙz¯c'iUuRchz_FYv/Ctee 0UAi~_v'K?L(6l*O9t bAqhcapK@?6j__:gjyiS@?6OFC0?6__K4lz_sTmtm2o:$O[]:ٷc8h? +/J-qJ:\=Vɂ [q!͜n=kC60C;/Xc,k\4kǙ?)><ⶢHbH$hUpJȳ;NIq Gxj3#?LTźh%MJ1 dҝU5əR, UslVu͒Jei#9źНܚ5>5)i%PW('UK{pOb Fv/l#}wQJm?ۘZB\0pya "x " -'H͖[4j4XIPph0ɻWn@$t楿M7[5EW+ ; 5ʖM`DA%WF޾` Fh.3aV?/xnp8Pe{1w\l*ŧt)m|7Ҁ#~U~8r;A>& [] QM%^勐n?ލCAd?: ,$f|eq-eKLI0CA;Qi[$.}$*1M_Uk D1jO%hDs-lB 32="phVe[#nKv\a9gKpC+]re9nf-WR5SNM,0i,0Le5H>jL{:VZzOj3ZJJRyR@ǥW?w73Kd$c?/AV.F Ӵe6ԞeWK 2mƓ\/FcKPOp|V&+K=3LӘEt"r7L[ZA9W>M܈%itՇ8Ҵ5 ٭VY6E>*ӻyj勆&dAm}j|Lt `I<ns $nuk..,nG2x h>JSXqflI,M&,1ۦJp ҄' Ӷjړæ`g/]oZCk?E6c"d;Tې@@ }a<f2iwFץFc 'iF 3I7,qM2}~lqmvdfwha*|$0`H+s1VSX8oCq!5,AgEAW%܌nb0JEϺV#3@ }(IJJi$Rh9,w#n-&_ J<j VKoj+#yXwc y0u9n{P{y<D7@bF@\{Ͻ$O ̨3P2I鑞̶x#mdA=8TrhKo䳾ҲvK Zt rq?8)#p۾xO@O$:SAUVSh:dz"nmEv,{z{d WUgVS+8W__2chw8x櫶.ne2UH'wY/-'4YΗoΛ?*L7O@oΗ{xuS>bӷxtCS8*@5*ͅ<}6Xύ_#k{߷A=z~a>6?|my~{k~W(ߕ =Ck~"zS?׮k~W(Q;p_[ߕ >a>6k~f^p_[`_G,?Qd/נ]_[`_G,?Q-zEx^Xύ_k~W(g`}M#[ +}|mmTΏ3gk~W(ϰ_G{?3/ק,?Q +{_0>px^a>6Xύ_گg`m{|mߕ =C!yt?`_G~>6k~fx^װ/ߕ ??QV?px^+}|mx^.#|_[`_G,?Q\Gߕ >a>6k~f5`/׮k~W(Q;Px^a>6Xύ_t=?_K_[`_G,?Q55XQυ_t=_Np/׭Xύ_k~W(g`}\/׭Xύ_k~W(Ck~"z>k~W(ߕ =C^§|_J/ #|_],?Q +{_0>7o,?Q +{_9{ 8]_[`_G,?QL?/ףx^a>6ύ_t=`_[a_Gl?/Q0~hBЪl?/QK{_}C=z>㑙[a_Gl?/Q|y|?:4~EK}|my,_Xڍߺ_owa_IkQ^>?7e[}em~3ӿRt+O!~f!^C?o}|ma_Ot^D?/׭ύ_6k~(As_G!^a>6ύ_}C?h~"z ߥ kZi2=Lj(ea X^a>V—6?k~(es?hBhq1o|m/l?/Q??ץ^a>6™-<{z" ѫ^i/Eziע_ZO?cY_i6?O]me~ֶOC{WVVHgl=ÂZ5`cYs^TZ$kSf?ߵ0ArQ hP;Vz9Q7~֏ٿO}&?]MKAs,d` "eb`)IIٳh͛kTED6K4rKsJ);O-0LΣ sHy\͛kGl'ZLb,H7*#*') I3?6oٳkB9Q7~֏ٿOE9Q7~֏ٿOE9Q7~֏ٿOE9Q7~֏ٿOE9Q7~֏ٿOE9Q7~֏ٿOE9Q7~֏ٿOE9Q7~ֳf8B}qӊ覦DZ7~֏ٿOE.v>Tgf?ߵ6ohQG;Tgf?ߵ6ohQG;Tgf?ߵ6ohQG;Tgf?ߵ6ohQG;Tgf?ߵ6ohQG;Tgf?ߵ6ohQG;Tgf?ߵ6ohQG;Tgf?ߵ6ohQG;Tgf?ߵ6ohQG;Tgf?ߵ6ohQG;Tf2?n~Zwl'Z'U n{,4T\G<)1rf?7~֨>MI6đBT7B@jiBZHEpTdʆ=EFl'Z?f?db[;n( ۈ'CVOZFY-biGϴe4^Ahf?7~֡Dln}fwvsǿd.}5DekJ}#'ߥ47f?7~֨OgnC', PT+^Gnx/5xbXdV1.Ҡ@+-l'Z?f?օQ7~֚|ʤkZT?յ\7~֏ٿO`&q5ɂHiV8.vf W@ڠ`d?:jR`EٿOf?ߵڪ$0B%ucVj|u Z#f?7~ִ(ʌٿOf?ߵ (aʌٿOf?ߵ (aʌٿOf?ߵ (aʌU۟;6o^Kyk0kFU=ON(bA7~֏ٿOIuՊdO>FcT\2IҧnwӒ9D@`2G^޽)BIf?7~ִ(Fl'Z?f?օsFl'Zo|gZ֕7ZhbEٿOf?ߵ (cFl'Z?f?օsG?Ynn ʔQޯyŹãFUΖ#ٳ' Nߗ ?'Cd$H a[q[m0@(21T rBpEKk?vޓQi[izOG/r˰r!bizOG/r˰s.剡K$QR30jgX,bf>Ir߭Ok?vޓQ.º(Xv`AؠWbNHqZVgO"9V?'Nߗ - KtUO;_I~_(ӵŽYv2[izOG/r˰s.*/izOG,2[izOG/r˰s.Cwjyn&CC!F'Nߗ 9e9rx{O*h 3!ʂC: .!i՟O9173Nӵ;_I~_(x誟vޓQk?>eܷETӵ;_I~_(`]tU? ZV dޓMnLZ(Š( xK ѫ^OqCiת@ ѫ^;=s(X _=շ@?VO[BF 7BZ+\k]Wzl Ig\77ʷr 7zcZ7IaZ4z{^NF1<.@sru/ig\t tU`|Ֆ)[kxBKq5#y,c$88==kb&[xŔ[ I$CUF%VD1dm`2RWKR~jVѵhg<.60]C,xbUR/iqIfvL$2)n| V,6g)دDR/<֚l,Ĭ-d8MYHg9> 5;ʶ$`ǏJh ,oEj`|w 5ŞZj2uE%xہ/My4җ7BԦ dqW:ky[LtK:\+yq1elr1Wtm6[֝%XV4 xT֩cЇ2.$WIq=oD1\X"%ñpgi\m<󆭏ko 2xXIhlsۑUb->LBcgŹUĊIN29= EQ]:3p&v(*89H ^(Ѭ靈 <%wX go8qڋOh*7RYp `~ j)_Z[yQ|$C}3V|%U:2%?uPq0͓9ВOIka**;|cF>U~涮u[+9$KG3^{y/qkjorw gUX;f70cO .rݟem/ ?ń*.0 E7HC.r&A(0*1KoषSk@<4H2>$w4Zv%yIR݀8f-]4=ЅDvW`FH @F-.F4RD4>PpF$ u/j^c=É I"YFU t xNgk"Nˍ8,M?Pj: ߤEl͕clSqc2G֫U$/W%!JU|->4'4QY. fl|#JPV~(ҼK-Y'a\@ w .s⣓ZV#:*}_3rX۸<! *ʻ$1tCdێrªQ]_qvfRatF1C7 +$C*GS)T5WL]/JY$(MZ}2hɣҌJ@4dуF4dуF4dуF4dуF4dуF4dуF4dуF4dуF5WQͦ[xʞZAUJdݳˈCZلV3##?Ċ.} I5z h1ȣ-'6 dڃ]R]zϽ@=O,6b3 E-nč /yuoGpq:c*LJ-nͬ+F`6qz .K}E2M;T7\w:.#ܤ&gX0ݎIJ>eR m浢-⿸էܠ(8CÖ ldѓF>dѓF>dѓF>dѓF>dn:(B(ifb1HPIҴ}*^9 $#`Ҁ).V #VMW'azg4Jl1#McdBl ̍ok ;@IzΖM7e;ueum[S(ܮoܹ&<66{j __Nх#\%d2جrzu֬i KUD"QR0(+KG#1[h{{ _կ'Ezi4{KoMc'![/5 bJoqwWM/ֺW TjŚdBp MoW# o%K8L(M.:+k/o$yd\4{# @,G @篥\%e 0굎 Q+mf8e2LFP(ܠIxJVՍ= D{iCETncZ]K@(n%fqnn 3\=Z];NO 1DcÖb~`^skṟ؋pɝzl+'\5 셊ξc:R H>"+]jtE'#.ǵP~OrGJ־qٓm=y;F9#'8[kVkZs_eQT}O;c(r}Õw;yEgRls,JZ e|ۀN?r:HtHe{{[IdL#vI,jqksݛfP6DQ=I=I.ʻּ3\_Ky=ܶX%S"$qle`$6OYtM^]=TY}3M][p8=v%)u`⎸CMJ'+J5c*x5-rSϧ .Ʋe[jS5#XVVk;'`ƎiwokNKm|`2+Ƞ,˞2+O*x5wDtK۫ӓqF`gtc-B;x#:uwd 5ek*"o'*=#*x5^4h&[FTesx"Eе+TO!OKvPNppTl)Ŭ4`Hվ.,q*ȻsX=]$Cr[#+?BFҵӬ&%Hrnv; n/ o62g-p$HOguoť,KYdwMK\vbvXiI<8ԻpQEo\iC Sn̤d`g9j_sKvEk<(^eJ'ZRǃ(2k [D":"&(SMxŻ1`Gf*x5;᷵*n, <$rUXéjT}٣>$qbnw"8KS:mS/HMŭ:IH^֩&ᗹhU 1  sT#:zK3(>|no9Q蚥 Ǧ\M}ɗ2FTBbO)krBMW@GՅԖ3%X"wg_#MsTXH[U}M+[Yhi3tіKӞW8[Zmy ̗ZG:Y7|U6G''OrS " TPf8 [<`zi:5nhKRI 2XsX6-~mLtF_+?3vkC]l~ժCs+}$qcZ''V9UwZ.ekms!`7ƟMi0Cu&`UI4,pp$·E }kc"=L@6 aR647Sa"Yg3CK lr@zj(|?%h Fișsȥ:X;C 9U{X즅%Ρ0W,> ?*x5x{Z[XZ)4tJ7#jǃs1Wm%srֱͧ}Lg&e9 r$,N*x4e}ƫnÖ670ű}:sߌVN*S˲v_oQ.ʻ>G]jsKr?/76vk,8woҪ"YYaE')wUةH6NY'ir[W1\4PBF Kkm}mI="It5R]:OXLo3I13ʋϱy6ov8: rI@!W9cx5,% R23z{HtH|^Hbҩd1 Rp94sKrŕ:Lfy9O$Qݭ w8=;Uxa}R ҩğVgM O% G<0?=sJۇ*Oo}EhpǥԴ0H$8V8t;U NXnIf܁ƗϫnmKA Ev\=);++lF[H[f$ q qIh ˢszԉfYb@73Vb~iЈ,JÿKV|7WLe !Ɨ.x5f%+ jzTnOVιm-y+$3X6|1:%`㊷=ݏ٠13 Y闳OrCh 6G]jsKr?/eԲ& IayjL[kp@'3(\mS})N*bه̘ c|ϸr6}/ 2gWP3[ +д+Ѣ#Kdl=G{=(EPWK?j׏|Rm?U^!H_J˖7K`XV)9QW (X udiM$RI.f%rOq#r4GG6{gk/ڇ5:+h!'0b;7/=9KpNJm#H֐as4r"1-P̪>; \kW@y s8rLr ~iyY[nHbZ6,ѿ?v5 th[ 6Xo=0]݇j;W^x|W@i,PdSy0w)jU׵˳okeȏ%]Am7,+}TpqCI\2=G=94\W70[y! 6Fg )9 NP+Vcu`/8vcJ{A4d5K׮tqgkⵁv>En96${X1imes^Xg\隷;^q`^ K6mrI(Wy k_Iqkw-#$ 6S4QE ( kH$Eu=UE:((((($q7MRFߵǟ񡁡Ic\ vW[[+m9;+6H3+Օ `^N:d ?o\[f")Ef^"Dl3i($Ƃ@@)o6%Bkn.zrďrqҭ|/h"VqQ:(23\=xy9!O1BH@@rHO*sX wr{g:\23Q\رėSGi\oheC[ELľ[۵xLW>CKQ?IC(8eSE葯v;iJG-ˇloG w ?:+t-4(!d0 &4tii 7Fώl0-rz\RYv}(/%IWɦ+AJ6.I#PC((((((23+aq Oq1 ,&0^ ~`Ttj>_]5&|YmKqBEr>/Wj[ʐH` z~5PB(( {Ac ѫ^Mm@E?zξqg ѫ^IbPhvk[CfR5 lt2'5(i?U޹]7BZ`Lm=VK9"_ae@ (8* v:((GA$[=W|g AXAgoLۙ$'$~j(((((((((@ X:E"¨Q)h ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (2@7i8Fyx<4a*i9?jד|Y}hZfro5 lt2'4(i?U޹]7BZ`QE ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (2A xFyr|QWk ѫ^Q}Eziֱ${;oMc'![/5 d oqwWM/ֺQH(((((((((((((((((((((((((((((((((((((((((( xK`ѫ^S~@hziתAC`ѫ^Klҭ#9|H endstream endobj 45 0 obj <> stream xn7=@>T.pH%5qE6!- Yjdɕ_9̡(("h3 sp<-3V%AyB=x;R<)ݶl?MR!9;@R%@Bw:yyꖥP8!dU$H(\uUP,K82j S.`/ҫ i³i D]mE'i][Im_ ߢyh n ;j GIKaid)}}a[0LTIrH=4F :;?񏿛F*C3ebM5BプA_wK6}5[`jɕt[q]Ɓ78^D7ETIػ&@< [扂&ac1%L YΙ,"Xr)M!/ " ˥\IslxU $lMl<-Ψyw=R{^ِ.1rF=p@! j%/<ų[<;(cC.Ό.jlQs#dQۂ dApD8,k[qOXQ$ W$"+\"z@RG[kpxC^֋7^6Ӛn71YSVxyMFdqpyNwž#i1hxOFK3 Xb`ׂ|1u2.bAį]J*% ͡clN *o)`˃.1] tAlLH_ʴkڍ6s)F W9Nv  ysر-Ldd6^.eq!cO:H-چO/9U<<O*㝛<"0VEݑF@weto(R,^b *C<[ ژrʡL{BuO<UXP}C(=i~po[ti<:3[d-(W3)N+9\IlTӃ)ѻ,66cBǒs~-&90Z`^ 74@h]w.C%pHDМEN[UZM("Zd&nfg 10^.U!:<^BC-sX-RD$^ "+Nh6'X_7kMiΎLPf r֖'Rn/ndŃ;^807qcS|y@꒴OIGw吰~ʖ(Y򲴇{q&W %:3AgeWLYjp+ 떒soi$ԎQR6tSAtVjSnk3ZL=Yxt`2g}.? C5,WUNv㈾)\i*WJW*e ;҉!MVWߘI,Od^M[)^F~ύh=tig7d>/& CvK}+X/F- Zz4:vN#zREm.u?,dضfg#_Rw;i5lуڤN*a+LT,-](]i>"<'k+:#!sc!0ɷ 5$/2f?55c)Htٶ$[]6+F@Cm&7YdU2!!2CSw} 2AKv2.w;Ox;?s}Ƿc1ؗR.f\2TLdwv2u>(S_񬿪ƯdoWJp QtEjrǘ&,&Mɝ.\լvi,WT+N^-'ys%Uʔ_Oˌv m*锚8L(,+8l/KS=eO5|tb!V1x4*w}HU KGDYbt? {[V"+ :&!wK7e=COoUO_0 vu Kz ~FyR!^F~ :d}C+q"0xU9-`mØ/`tpڻ1Fތ3YЎhYAcwY!hHef(% OS^~ oq M|/}_ `mO% x&ݫd7+z^N~h쭢x̡%-4j:r- NK^gi:[&>e&s!u,ۮVӓu :dΖ21Ԕ>O̓ P4:WO48#Xq<ۓ,`QU3{jdinU}SO+<@i1Cx/$S˘xruv/)pt'5zCܙGrXgyT ϏA~O YG/+`vɆ[x \x J$g#u5z@xw3KAڂ3=࿺YgK?=@GClj ~q~~QX6.@s4oB7fQ;foĴ_`6> fbI{ f7n5e,pG.h{S3`8Eƕ.V;>J8zP!KtVR3( ȣW") l3Ɉ;ʳDAu+4 7 igK"Ro_c>M4[ o*  =aN/@ednXaՒ(2M _`F endstream endobj 46 0 obj <>/XObject<>/ExtGState<>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI] >>/MediaBox[ 0 0 612 792] /Contents 47 0 R/Group<>/Tabs/S/StructParents 4>> endobj 47 0 obj <> stream xZn8}=Фx8 $dЋm`'*Jg/Eʢ-9cR7]5fU.Zvy9jr~kv빚}+6Oesv]ߟ$ Wg O<",׆{?ϾO/v[g_oluݶqs\Cޭ|o=Z^Bpd+ "^bLIPTOmUN/ej&cΤ4\Qٜ"f-F i2'3&ߘ9/ jȑJݍe+3g,0rn*GO`~Tcv3&eܞa_50z`FzOˍjevZ4@xOV E~ ^T'+@wTZ.TߡLND HUdNf$;̱3~=쐬DTу( 144lS~ UqiALB,HP߿'}Cz3%ITq,PL9ˍ8X1?sr~@zۂ)HB°X}sdy`;mY.pyϼ[d YC ̠黤9EOA/_va yu]RُQA SCF>U\Ch/sr.`eĠsuŞ'4GXCӽL/,vTE}zbUไѶb~l^`E~@*2BJ!t?X[p+dVcN!'%Hݠ=#[TF7Hz |fL=Ybflp-2IAW 64m64?@o PFV54Y ^a!hjRcj%qj譄`p ;|md``#ݢ݊{0lY͊S(N 3wA 9;WI5ip G0oRL̏exwaԅHg39]CvB[u!PV2ŕ Vm,uvyV6WY5ŷ\p/K5Ġ RK< _ʈK[\`R jyxg(K* TaK䐐y1OC!eÅM.E~NPv6vΑwYxG}}UQӸ̋xTp:46&ZQ".ި)Q.mMlcCׄIsioTT"joEqd̺ a@#N4;g9Ka\Kǟ>eņxH jbTx6ZPNpl5@ %TxydOנ\F`D2/A|{luk9;V"6yI%bW0=!_lpx;)u4pFb` q0h)_ (e3M|rxk-ǎ z ڷ,;sd˫K`"9f8n.=Id+1 ͐M<~?u;]QPcMI,&,Da# "{L@[D%7↘O<7rQC!d24Ӈch:1vs>DP#B] ihq@$D. Y.uz|Y |G]5z@JpMٖ!CAWhU7Pt:~;:x6M}5Qax¿A SЁdqEh࣮ZطlwibW'ue& &q*8O.#6BՎ G#Hb W wMh5 5r36E 55܋ܐ3OIӳ.Mu},DqT]T&5cRj'% fLױlʤC,A7 C uum2\ oǡWEz$Bd&y<ڶ0O^oS%$-MU8\G>/ExtGState<>>>/BBox[ 0 0 900.9 121.51] /Matrix[ 0.07992 0 0 0.59256 0 0] /Filter/FlateDecode/Length 1946>> stream xZ[6~?yL@@a>@Z. -²-m}c'$'Nݥ盱g}zU3յvNȂ1]pWzuNSpΤ5B00aJ8wK[~ͻՓm<>tMś׊Rzu xiae`rP Y jAȆjEgQo# L8Ɍ0/ >,D:56%%Mzexì([&+?E5`g >ǃ|~zፙ eh S!>y٨6n>,5s2LaYnk{>6N*\ Fƭљ qAjcaLO-Q|ܪd=vަh@XKHNzW09mcBͥtám7Zãn;i;):Z]v%T(!<³408$t5%c=Jt—mHJ* ڵ?po(Vô-!2$U+pVYqW8ESI L# VXxW@Q<R6ղ Y %df-҇Qk]GU5i5ӧXϔՇl#9óJ49=780;Uܳ/ɖalK3Q%x#SEŎZO0-VtoœsҸ]%/8m F8y^_m}epaQb< 梞ֺ @&:!uL=P@6-j5'jP;QԈ5x?QKnj#L"jQD(ji!j:(Gk3]̀ƶl1~v3q%&X\OJ, E占U窋V oa'}#;Fmy}c펀_}cKncgxL}#ӷjopqoio+uf[xj#Jn3OmSyj#3F̣0!o̼|aw好/vaHқEsr+ܪV?If[Vx?nMF괖¹5 QTR=[^\ t%/na/n%Xέt1qށ[ܺsqq뀭J:ĭ# JwnumKrE湕xLn%YdA|U K꒷8k' 0$ ˟42{X;Z;nZ9XuSyV%wbճ!Mta*.q?Nhm.̅(t6\eQF8m('G7:vcՕYH%CS3hjjBDK MS10--4!F--4eBPG--4i(KQEY M,]V`!`kRԂn <;:G XDMM&ނ< (7$!-Ld O4 ( pǞBERfogW RhS o&o9W"E m*^4P(og@ sP@ endstream endobj 49 0 obj <> endobj 50 0 obj <> endobj 51 0 obj <>/ExtGState<>>>/BBox[ 0 0 1018.05 121.51] /Matrix[ 0.070724 0 0 0.59256 0 0] /Filter/FlateDecode/Length 1979>> stream xZ[6~?yL@@a>@Z. -²-m}x8{vRJޓdf}}X6DJ\TPKT8%FU'/׫TG̓ꝶbWcF[KZw mVnTIY6amkT}eKupo} BSdrpQws0Jk0%ci"Y% $bq3f- G|^xL]c9䌴S!>ovlll9,.;SX\VJ]^џ qIlehXF :~; ʫ{h}l$eB-ѯa/ ! N SIn]3fSiبՒuZl7j(vhb?йѾN~PP"f|q Vܓ@7}{^@>o4 < h$-W^k"\%&涖Lm$T5.jvNxۡCU?w':QC..UԐsZETK]BQ{5%jlWQK؇ MEm'c<7vLXj"eٕ  *sE7] o`W}Q@A2շmwNۃ!-fj\Gf7R y>%X#}cqݿQ\'.Ӛ7o U,ߵM wm kY c#^S#//9xdes#݅[w5"9nٽN<"ʭ95qUJH&5uQdB[[QŒ'ZeAMDfV]4qwN%v`& +drwmo 97(i_ x>K ꂧ8w 4B(i,}lr8kH~+jFSªg7t+ n⌤ׇV MU.߫sjai"ZޮWǎՕjw?X~D$7-AlJH۠rA9t J{3Bl$]ܜ)Zqddێl/Xp|)TgBXoj1]߇  bMu.@ k @aH:6A 卢_HрYCi2Uj9 T Vȹ C҃!˺qʺS m d'tjDZhȠ.`h8Έq>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI] >>/MediaBox[ 0 0 612 792] /Contents 53 0 R/Group<>/Tabs/S/StructParents 5>> endobj 53 0 obj <> stream xko8{E"Gw@6m v?$l˶6ds %YDY-܇b3'gu^$hV~|]lMi_~IIz޼bon?sۑfgwmǕ̗V<%>٭&ϟ|4~E&ЖAu.@MDa=;hò vfvk/P6wxa\l1Ohr!DY&b+[2#oA*\(+G$ (Vh!CQR.&B~6-Tc2m9  Uޏ@]iX>0ȌK([a&XMAs V8`؁׆=Bpy=A?DK> ->83,BO] lL`6JRa"]cTDl?@2*l\9A`)_~[QU-Tjg rJ&(Rž,8hԟ&*VqnqB:<ޙФurQwl x^9,oA,/&[Hm8e j;gقej|ɉ H> JL L-m&h !"Ngqm'!dY{߳ &1 m95/ZW=y\zƟ^px- 77wW0I_g~S-!#ͥhdР>pǕ ~VP%yW`tlyjdKj7ZEƏNY_Ȼ g!;\D Ȉ1zl1 knL+tD bJ! ÊC).َlJ@nE*],$_kfר5PPT nɋ>0I^Q$ ֕H=>Uڠ7`ri,EWџVߠx~}=~ >V<nX^%X{½7[m.d1~Q-G!l=`Wa\Sp=6![i4M5K`h;kb;m$B3cw\ t~ ^k? M aճ{eB.7ظp 9喾MSK[,,QHڅZE-wpYKwM1h5j'P7AD|59>w + 0RHZy0qL:>8ƩyGJ0b+a2aaTq t  <@3I -~J jx)G[IE)%Zʵq~N0J䁾@a w9T ۾m(bELY1E/l1qT2TIPOSJ=}~*V嶉==KGf͊duI J'8]10kC2vlc)ts[B^q v[uCm۴=^Y4 Tp`Quㆻ,H;LVc# sdOI3^;&L=3>n`o_F [zNNz7"yxj"|>Yox=8)QIobOb3%HH خǰ-؆@5u?8wזǦ瘭YO`{[ҁ K\|r6*n?uE yQ;JB6ƪ>LWH ~89t 4|Dg*ycw_`" 34Z:nb)x {$[qR䪍ÖD˴tE;M^3S;JG #O^tB#xS "'c.aydNYu/]lum)dg8kf Uǁ,r] DR™N^l ,ll8.Nin015Q;1: endstream endobj 54 0 obj <>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI] >>/MediaBox[ 0 0 612 792] /Contents 55 0 R/Group<>/Tabs/S/StructParents 6>> endobj 55 0 obj <> stream x]Yo9~7>~D3G儉2Evzdw??eO.}g>Wy`엛~ϲ:oLG E^u$'\jm*S#iA5OĬY6'OlDBQ*s~6 -rg~bQ(3.C5 7J`YKWګRFPOav<~t?$jQyN UX%Ul*WH%۶iʎ}P`*RymrW Q(<{/sYYr0Z ݏzVT\YeXeR"(xhSeꚹ4HTN(2w-Q^\Jk,꠬*mUW>:>49Z+"$ŇW,B|lU^6%,/C#o;E`n?yJ&z^f/7/46ඬDi05q_/۬1_50.8Z){LQO_mVTWj>_\ MGZd_,<͝1Xe悹fnM\f^S?:ыBoDV!.(~LN1rz+,0U)è!XWhȑ+y;gXH!Wf^\ɚrkşi\~Ϯ79l*o&gkh(1 -6'3]2M􅈉)"# ļ/.߳NWE;nW*s8Ɣ0qe@Dt5'[If,_`7qna5`~Oܰ\:`|{ׄ\dz92g} Ԯƣ]/;p,kuPO(RVɷ>xOnj&Y(F7IA}QzX]=5Ci}sBz`ʈ0]C VF%kp*v\WX:aoYԮI6 N|_|ë1V6z z6'~jN"ϲR|_.Vl_VOٻg9t4|_y&3=jBKS/"▭rKՖЁB5mx4Y)VF "Ա֣ ;#*%  )M9t,(u_ it &{GK"A)#$<9AyV^|HV45 k<b4fħ^YENC!Fl_е{,Mo40fÓ" VEA?#D;DP4BJ?8PɠN/ $?٧p2;/ 4hmyk1 π漸Ͽoog0/ga]R#|xˎ}ևB "fY/Nv M(fylpmUyan5`;jAuD9_)@e=>3b_5j0@t d6]$A90 (%EBf[iћ]G^i!z ᇤ\UuKp,fN \Vnֵfr>[a =Tڕ(  .##$ð"X*NFǜ91>X[,©v} yT9LKQ%[D^C!FHVZ 9}#Yk]#m ΄xN9-]AұJ/l ` 3L4&N8$B[_A[Ti]|&qt=jcf(Y&v10B Ţl 1RОؗPc2꓆2YAg3815=t1<<ק76 ~v8k~قm3ǏҦ{1])T/`- 1Xr$Wb\I$$$\jJPWbu%^#Ju;,ƕ0TJCyk'qR0I3$흋t&\ܱ`e]~HKF!+]0~eVi< y(, O(C;{Ig }:E661&hcMIkWt6Pq$|#x(| zm`pt;1ZJ}q*E;"w Af9ӟW𛳗b%+x g N˛~B׋k3麎%;0D ~( -rljaEae(DG+J#G#vAĴy%¿׭ksžYi>mq!Ď5c kt2)x9< #^j}rqM{Z>0GdPX:<#^㻱ֵ%Xn"S3/Y7֙#vk,_O}Scm߾;7q:VqG`<,E}Ӌ7[OUY]m8e6b`94ۡm ڽ[:qs횛w<Ƈ= 58oҷO_7ϗ\W3}qD__)Q3_epLȡz:)Pl6b[lz(~X+oVQhKzǺٷpԃf^:pUla:sC W/5:]1]ڏb|u$k=&xP͙:ÙiÃM+/۟X0K3X| CFWo$H1ES<$jU}!ۑ`lS=MFh¢Wτ<%}w<+}"f2zyAo_Ao$@9ޡm ڽ^' "eNOWQ%.Y-FAb˃G9ӗ6<8]\#:ȨexKR5bH؆qr߁r68%fE ؆1mtwţkUا`#HF# 1D8NE6".GiˎBWkz|M<8GQҷ/K߾rE 9 y<t~ U0B c "C|h veGAܫā#@np_ekz\?&޻|w*o~U߶G@b@_ rm՝y0 vR]#֏_S'a@A ~Xչ;_n6;՛pB]0aEr\8ad($SN6 NFqb ‰WS;jo=p~k=o^dn5ߘ]st,y7MSÏrӚ:ׅgn>‘%:dduIrzjfaJ|Ь#NDi{lNvF%?W˒'w6lurnȅ#KEeq#YEVL*ZmcQ=AQQ=#6& ūȱ(#(m~D_~$=-Gv{͟MU'AoF-&A/9'fz˨ Z6 "GϨą^FLNZmSWtF׫g8;Nv#Z Nx, uqHrGLLZm('8({L2R#ȈWꎌtFyC!|~YdrD>[J嵰T^ [ JΏ洞WjEEiU- 3< 1ڦ@/CZ2tگEWϤ%G-wԂ>jQ0g828KX$K8bC$K,68n1PT]  lWOLCъ#QhWVQL"$B c<Qő #+H'؏Q&#*Г}Gw'#oVgdF!Чc:sX[DT3Qh|=98_>o9ue]\-t`''v)(;FcV#ecn%EhU]ڑD -dhMЖ8h[Bےm(&|kv$c>A:&!IČ2#+ 0ӯi Z"В@%R"΁QsX%;Ssp)u|KbL7]DRyT(-Q阔9`V9X}0n=Hfba|" jB+@󝿩" 9l\t Dh깫kZ?m5M;gaݻ2 ;uѝ]Fw]1Uiݩޕat 4.mw6ɉAh ;Ǐc >c☁(1@bL,al$T\ 0kMZ1:bc`3% -qz0=0 qHȥH8jCy6rGl zbb=cQF~QhF$8C mĭ4U/`B|J*B!>Ӣ|P> 3mQ븗M3ZUE endstream endobj 56 0 obj <>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI] >>/MediaBox[ 0 0 612 792] /Contents 57 0 R/Group<>/Tabs/S/StructParents 7>> endobj 57 0 obj <> stream xV[o8~G?crT/q. v#Ubw:)ž69[~˝q%[0\.e|03xOՏd2q,r,#N!`2vpHeIapxC|vn7#{lKk˗KX &?=,mB3"CP.L6;DHd˩*l򰧂P>cBhMXeGeAAK&qʣ@sϳ%32qDQ`Z P )`3O9e *' 0C2xA5~@{1fUɌ99E)͢T操8,1%.?4v[YS\~ RUc/WVy%U.ޖֵ6ʛoEEcs8Mh*eŲvxM%u>I|%evR46D5HwZ _a;j]8 Q0X60uM%5y1C/Pw"F(2nhǑCM~0ygk\/,\m^{hmQŚ (=]hM^8=`Tv UʲO|zq;r " i,m w" k!YzGRҵM Rl..ȋ#'n*t48"9~)~7I'/IfphT |o骺!Fsgaĺs?Z"ikj k]g&LrM] 43 ;m:wI?oi o"q؎f&:Ņ3ӗՅUM& Eg.dzW&hcs;vm KW ]3`=mY +C%NB}]7(.ʨ]W];ׂ endstream endobj 58 0 obj <>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI] >>/MediaBox[ 0 0 612 792] /Contents 59 0 R/Group<>/Tabs/S/StructParents 8>> endobj 59 0 obj <> stream x=r9?TKKRÇ"tؕ;6(hS$AfD,v6cm 3Aӝ{o}ֻ>O~?z.:wQg>勃 C?H^Axyi]=|xwǻ/w߽/_o'ށx>?#b,#@޹`0a NB{39GZt7 {xgaǵod9T\_ i?׸84\*@1:8w ?NWq-,)s?kpN(=T὆5(\a1Qq'I$FVS b8X72?M/2#cd^,_€p ,n?c.+Ec#V~Vݫ D i*oꔔJ~n_^JT Р|8JKVcSkhb/*?!i0q@%nf?+ ^&N罩ݜ>>Cgt}o#S^{BMa)_ 7~Y֦)@h{<_1IibO&40APRAGg/v&o ág9 H%=܇A>4\fP?-U";|1|%h]T0j \ai8>YjAxFChaq3<6SW%<X]Nźq_MDR ZFxFb[-CIjZ[d&;`S|dyV 毜*̞S+W{Yf6]ᒠ,DҌ( J%d7TМCMWW0;حjs zatc i>se8}Wa4==.tjikAs s='f#4~Q?]f2MFHNTypKu 7ѹWeoD`džT?/Iqdw<]M}Mg54\@ @.=@τ'6WH'bUy{0bKɽF:Cͅ#/ C=niyzi1oIJwzR0<h# qϸN3 iJ<=wN $Q$/#V6=+eM"j5qYqۣzjT ǯg b|b^_S|drun1$!D3=OE45:b9B۵:Zn[h'Ƣ))QHbRCR~APDh<һuY0!Bϋ*DC e'(95a,e T\q+Fl8Y)Ă z"x{Z&\$`e<-ģ8Z\Iڨ霖*65 ـJ=]Fyg.Acn 暗 ժ1Z5^M&@BWsRUgcLFtWg"G I/kꢣ~\H(P[oe 318G}6x8@/ 1uJL Lg+ 0L ) IS eI \CeŅn^Hb"Rz7ю|T+혱/hsh~3h.g/LS̛{2D`p5jyLJO^GeeV>hOV;?hXӝ9! _ 9׷5nGH5D4),8hUq0P1]ʚv߾WƩkXzH G&7 K)!nYt\iF7BQEsзk}A7]#CS!xm]DU-M%TWdGߏ3eF킥S)+y[ser=Tb, $ c%Չ QPnTtm3(gY֜ F{5]`G=У[=ʆZV[΁0nM> Rl;n]ڶcrxv{h_7d[yxo`/V,,.ZS (3?sB1>B-L֨ƻ^MrZQm+@af{A^zkTȚyc+VZ2_|s&cQ8vֈ1[ѹ5V_6}媣 L[pYoY}%P@j+,[& *PERVUSQSg~*~27X;7&)걚%\}2a瓏dZ@B21r?ݎlnd#x@D-X)*ےteЭ15j0N'x  Y+ ޾W+&0VPde!a㥗Zc{0 ۓ\3'ֻ1a U?$r"~B*-y4Gغ*bV(!4 ~E<=)5$2ple',u[h.yНP4[B&DE^L EY|E @(a;$^0w''<]U1<duSНHNDž^go9dX("OaA@rvMAWU9R&wMd]@Sk!]2g, /W^iYzbn^ ILd=lqȢB>-,b_ˣfޓGy鷐s7&YYT6jg GSOڷ;42Myg 'F74%utxuGRQFplj#c#fUdo=Bo6] , #$,a/AO:S3VsJvt\AU'e^Qt}DX +\SZp2dMП 26UYB;J"w=X3|ߵ G56o*d-6kvdLf\Pq1g&ׯaP "FDYfP $Tn _x47̣S#e^_)!gsқa'eQݵ.ǟQ1ɊW.SrЀ/MLӅq:kn' k k$]TexH9q'{f\9zsX Ʌ҉M3BF0TAԖ@3[iú=zyչrȘQ|&Ѣs6Mlh7Bd޿G endstream endobj 60 0 obj <> endobj 61 0 obj <> endobj 62 0 obj <> endobj 63 0 obj <> endobj 64 0 obj <> endobj 65 0 obj <> endobj 66 0 obj <> endobj 67 0 obj <> endobj 68 0 obj <> endobj 75 0 obj <> stream x_%ő-;SWFD)ɲdmc zaFAodjs]iVDfeNDdIe]z[jYz_KߖR2bX/eŋ-/b-[Yeںlp˲-XZeۖnW\2J_ؘnx=^71n+6_ʊQ yf Vix3~Z+of*o>}=<z5 7Fob+ 6La Ӽ 6}6VcNxh-68<zv4ʡ}mR /mS;7ŝ|6hx=pssĥ =6N낡hO9Ax/}hs!(a_@).hҀV炇7cQ`֢qAʛ,KtN zX%K1sT{2W ǡ0UR=hcD u%9\19ύ`C]up`PW(LVݨ0by34 PE- xlsVfXB-WC(Y7LqG4-dund-ÓAafm$lҰ }hO`xN ;GgXxѳAAAܠ1 &{ Egh7 <6p7>)47>)pkEOoxA. aP0>)' 2O#|P NI! ft>i0Iq|Rhp >)486>)0b Tm+gf\662h4P os! co c`~6FCP~ʡ`5Yc8Z4 hˠm:6ƨuek `c`aaq%"c3\ ֙42(2WhZ1t5 ZA1Ac$Z3¸;D !؂(0N*mO6\c C8[|J `LB }4ecɀA#j졞-/dHP"3UC3ی3PΨc\9ӥ5ؚ^тbPgp4m3#9[3m`ـ2ycxÅ3s&ŕ3J#V( 8@0[9#n31o33" LAk>GcɼsL Ι c=++FיWg,1 3:$]ꙏNg]P*d\SzSΑu^+9mvdQBFJYN9yx3n$JsJ#>A7qDPQ,HuOK"$bDY1k Ae٥ۀ|WoT2+avfY6ڨճ":L9AwF;) 꼳V;YfJ eA6KV9>* ch>K0uK.jo>sdG̊>'+&|2˜J ShP5fL]wp>I<F!SHAD9r%q@u>X|R | 3XN":XyǬX1mAoAo3"Zg}ʪ,K+QfT3S>s }Pȟc0OAoϚ9-PʌDTb++}0K, pe>A`QYuf!≯scmbl@̘|YPxhE+VML;JT:,0`:jLI7=7n>ooo~g77mY| ǿSʙ?mT?zzx ڦZ&6t7ͳo|XΛI};i$7כM&zzr* 6%a$( J$(( JKp` ,%8XKp`_zi 9_fj9ޯEWu ]M׮U+W_"E333jO/~/N>}ޯ/lT1}yȑY,/T*?8wp^8]W|{U5piJOcCxzJc3wޭ*y_BD8wuNF_'yI;F󍞽kEx4\^d &i2;&|W”iiQv<>;}K}ڋ}l 墸}7.Qi`s:95qK]'l"1Hs!M?isZ¦~ym [:k9]et|r7QFx% Y% t% %J&jKJNiXJ(Y2aR"=K)7*-,#,#,Udn&,#wD#2R"L)# OI#,-,=,='=Om.2""<\OŽ_](vtԥ-} ?oOM-Ɖܿtհ33mgFhKYmx;)O1X~\m"Zv !_I|}l^gr^^#hOH1Ƨ=cvj/M?bhOSy#H<6y*~\ i  -aS2Q2s /x(CP28 %Da",2DX\JM$lj¦%lzf$lMZɐP2( %CP28 %Da",2DXa",Ce !3DxO !3Dx"L0ä>L0ä>L0ä>L0ä>L0ä>L0ä>L0ä>L0ä>L0CaGW.Mxw]ޚǓW.~]xuūW.^]xuūW.^]xuūW.^]xuūW.^]xuūW.^]xuūW.^]xuūW.^]xuūW.^]xuūW.^]xuxxxŷo!C|xxxCH!=y(GH!}GH!}GH!}GH!}GH!}GH!}GH!}GH!}GH!}GH!}GH!}GH!}DGU/Q~㻻7}}.$XG޾.8fi7^Ug/^|/|gn>{?}is/o}C~~qR߿z?1W_}zw> j_޾k<ۗx/_|~ƽ{?WϿ)zÔer"@,~]HX$8`o_8|cr8e.86s2gD<86m"l7 GX?VERQ~>꣘~P<G{۷ףX=ӫMٱv6omn޵c ݅FؠtCpk8=((z˃>6Y/]MڵG6cKk7OWo.mlr/g`f=qy{Cu}SXvW3YMMߛ4=ñ1eö_ٰl׶gl?F׿o;{ endstream endobj 464 0 obj <> endobj 465 0 obj <> stream x}SMo0 +r$R i q؇vvvH#@v]+s_^cG.UUWPRCלtlJY<`eUoQelzSuh͆ofe~%J# Nm59VF)oe˴4U?,M}h ĜM ]suk'd<YT?ѥS4Q8]J0eR|ky ~Dw[QΉȧ ݻ 4N<kפ +ɀl1bLXL!rkZte\1iDÃD;mp䬨p8bX6\[O- p\8im 8ujv_/I endstream endobj 466 0 obj <> stream x} |Te&fddI2L20$7$ IPHfX4.Ujl1.n7k}UpiBawgao;9;p V[4 `ͩQoPL ֽ? l8hj1_کse3ہ-XͬfOq˸KG=, @`_캺gY!{\AjhZt%8_dl,e@E/6 {q_֍ /Yݗ6T`О EWK~_ ˯JA>xy0{/0=WhOjQn(ACP_%]O`ǥ)K4Xæ S _eRZi{> :1NЃ"p_iw 2Pv|ؾ/ɟa1 3:2N2!`bkly@irO:;y H>-CO ,HAȹO` `5X[0FeoU'58[X~ =3P-@;)Ϡ"v3,z`){f,k䖁q+J&*@3w b%_ \tO]:%Ő~VgCM@vIzPG`a{ d`&go '=8?G8낁%\V {Vęߋ݁xb_m๮W8!qC8!qC8!qC8!qC8!qC8!q?(FB$Pb~|BQDȄ )0`:4 ` y=oOD_0Ƨx2vr1S;BK">EC{'$e0]^^G>&zQgPbW*jld (g49F0l XRy 6Fa v0p ߃nv½й0 j_gо(`kok4sFiS5UBeŔIe%bo ߝ7!7'ەtidbN2 z6QNP)r2Mմ.k:D33="y D[S: By(w?"urvV\qN M]6#Դ:vq3F;MG>*G%;ڐ6f[ۅ06z~&&(B0h>L/b ѣ$$}%H3s_eRhOG8Suec5yY'=f2"ۤa˂D~[kg7ăΟpn:B#&cY靰 S# -)l4lksDCEk.1ɭw} MAtzirf?rC5~Q{G Άّ,莑fDFKFKZuuNsdo;5^OmuD}G7$E.ܫkjMPݝQt3cZwaw_m`uuԌ`rzeѠ9x'ޕf\No ]uff4yh "O[GX ovkB B>;xxIOx@*oѪ&jimG$kZyDxsgK_w`|GP* mꑱCAZd:Mqמkha߰{" RV--Q/ۣ7UOrn/`9ĢWl)mryC9qI}g*CKX-iOu7]~-}0P=$[f dKs{>=uC,kZ 6j{4޾Oz9I!FH:eLGk1:.$]䭢֍.hubCz}[wGu6X" qV FE+2SY鏗WÉ p+IMa. z+C.ArqT*uuR;hw3 zQ++:i} .LN$/G_榛. <MsNّ5et#O[Y,=N.12F c7k8IA˻9jd',§:H{"7H J!B\?RksthQ8WF'wڂh*]f49WFK+)[LtwbWYk)%]ňVAO^h[Fvq|'>[ib!h?_!©<_(2 Jv)*LA7ʳ;K OOld:?BNƄ1ۘML8ń Gc‘EL]L4&|> ń1PLx;&ތ DŽbp & Ƅ[bŽĄ1aSLcB[Lh -11&̈ 1azL( E1 bB~LPEL cD=.c=*#\J~,@K=-у= W%D_~(%:*g%3DwK!DwHtDItD%zD7JtDoB*TLzZ.l6JtD%TWUAq+#ނng_GLc[EQ7!GT>\ՇpUU}W>\ hC .%8G] "CdA4qSpʎDӣo>ti.ѱ7z8= C9=sF"*T28Z"&6|貉)z*2= CǘfCk;Dru'W_$˯@r J]dN] Hu'uo2%yښd*/s܃@*|*10;{Algv0 g2@v؊GB!c1C"}}8~Hٱ'߇N*T072k1nz!_\.76ʯeJk%_#s#L;sq+PQܽ^_UU\ Ɉa4f)G3DA>tzԎ| sԿY7s5r_+|qt\/r~s{BU# l,@ff1Ftq6$0dPqOyg\•!"_  Rو!ƀrX]mz)VWeF=:f2+ߏnbt+}{LD; 9 ?vGyNVUc CI4 K2Ռ^ں 9]95}RT_eQ^|Dy(幌_RcV$cPԌIDdTL%oEk5Gbp+GN`JSpTN Db Qi&3EQ~1̉ȩ}67y/?%(?D1tZ=lF4#cO<vO~)tŞL>*MOwƔii1ejS&D>)* B [Q"TRU*fAUQ9ei~3]2Y.#D)oߓ'.#Ds27&>`2w~Ni20F2?s[޽F~ tɭe[sܒ)[qme~11>}|sCGK܍NS#< -8Hq&߁OnXOЪQ֓][6f M67odo$uIF'mefsXb̚bkY 'NE'mn.ϭw2,.=Cg@1)Zu7pO UZ#W(5,'B#gC=yDGԺVd{otr5Yn2LVTW½{t>&!Og'i6EJYoM4rIWxOqB^yB8x  SD D-r 9@~ /d2| =`1 @hhMyss7|XnUZ цZقE䶌0Ȍ5ZGH2ވߴ ib6 AX<[;b|eoT$ͮj;ڎ;D:yf >2"IK륚s^`:W;b|8&Vb0All%A 55:gu2g52j% DT7 LM0CɼyU]$ !rⷈF81@}z?^ЁЫWB/^ = =Yhoh8;PhWh0#=-591!tS/>.604;iC̘dds@}:"׫SӇ8{)HWacǙC?Ple<Ft=o k $O^x<~qŧan 05Ps`>,Ş+a<:*УQq .Wt/L*`O{t|WNX+aqn%L%h[zJXnx0܃ ?JFj̤?V=vt^-vSlvv v߃'_ϡoVcT0í;a3%>C豕G\y ډN‚%̅՘q7>W[a1f*݈RF*` FX?A}5ār?l!6wSǮ'H.)Xz^ If?Ճ%Yz@$Ix K섅?aIM7ߞGp ~Ewc *[E{k fsj xSs mS۰57.1Rzvv!]B-OtQ{s젴ج3/6s#֊8DzzNFƾSpyOۑ^\x.{L{?dOeYV,^cx3U=[ľf:8ູ.+`;U]ʅp5ݪr.دؓqr{6ݎ^glDZ 4.$wB>䧩%Bu~ WZE>ɤ ,T,,6A4-"% $ۙeҲ2_q:cN†5fg)18 rK^5ۮUk*RuY|>۬0JN-W^iNw64%eߘ^櫛]1*_OYx@`@gld@&J#SN3ɶLޑʴ,դTg& l€gy$a(.3f8y>>o,iQ~y|>h|>Q^Gi^q(rsjvo&Igf`bMs 3SS*sʛsȃ^g 6wV, ^UO7.j*T{Tf#_[aO<(˄sY^^[6 ir ؂4! ӌl6{@#hCA kXpx-y:o<%7b]ᏒI+.Mͽ1w `ǀڍZPP;0eMk]rqŞBA+bua%#!?ٗCM3 |aE-_\wx5L4ˇ ͝ͼK \E  <6بРL%ddXm Xu@H(Llt3mm@,, X@!kإ3mdhJD T4G#~6ϣtasD8PgN( n~C76yLNϴ&uN-lN-t鯓B/0% SI?T<,4V嵃ZQ+SZ(U* 3d<݆g 22 YU^j@U1Lϛ0Sʁsxqlzc\Hgg6Mi)]КYʅ ؖhqt*Jb4Je5Y5AlZV6AKa>ry-f*wnFzݓ&8INy|MsI7/\hL|4.$~)dAes9l+k(;,Yl+̒ Q5S>69lg}>xqOO7F礘q8-Fw2ACH,{?_½+÷tN, 7&YSDAU7O9cS£o@7Nbj!+ו rl}bqIP0U[šX*e?{l|S'_I^bX}LiPòeySeJUH \Vo G3i)ު2p&B_`6 _ !ѧ s-X!McR*.q͖iX+O?3"|0쮻-m)T";hW]~Ī =Ӫ4౽7)/]kڌ\ʇgLKS3?uk-XW7g8{'f\lt^)ПxQsZ@ńT6g㴬͖R 8 L&&ζkXQ(BQ "2ٌ /{L錯Xz)D/,k [/&wZ[rU[jwY7T- />z;Ll]vU+nP>5UœΚ [J/7iŭ<9Bh6 fdTɐ&cΰ.Vax3iDI!vL_irHqzVMZhqM^ʤ^R6u|š)fBoͪp`/mD۱rV{'*۩4 Xan3?#e?Z?HmR{p1R#1sL;Bk~|eq)Kv'L_i*.#VTEE [pAW?I(./2>6p 0V:oɦ69Mɲ&ƱQg0eNҩҊHdB^ >= d M% j Gh>i dO O"B* =V=ؓ3ibk;od@~SտZo> ?Ckl+5뻑G&WM4ifڲ:[ݪ> B܇2`%\1d}̩j/fm0nGX'Sa0@{\5✵fD0,)T4 | {X|$peyf/UVm DVh<5mT6cēw6;8Q͒b^>A՛SoNzM0ւ<.>a̜g0Lt#=wYyk>n^kղ>j΄x/qB6 EF3 vX mbM]%V4i/>(!"uEjK&6ŗEͿ%鍯v>fׂg:[QוVt2z@6Q,yjPw㴃q5!6D9ɰSobĔĽ|"Uʫobʆdn΃4c8.HYpd xV}Rִ|䉶SL)ع~c~yiC3ΊwOϱ)'(|#7ǧ-g^|Sa 컍s.=MtA6],2>JpǢG=n{R+ue`fۥ8 R<[ MS_/?r{}Ok͉Gy9{ ?٥۪u'=zA̿:ޭʤqӃӠ9 XͺMY&wfGGAӪ%'s8K aХ,ܳW]쬏_}gٺvvP4lMW-6"JEz<{gHwT?6L^3ZX:`)[\wpgo|gW >֭%}}?7`nxAeFq |,Sv%er0D3ٜܜ>Nuyd0^ʰjDpʅàύoNh9Ef#S]RkB@w6?Z26ר T$,j9ԘL?J%@kwJtR|NwDZs_cFSs0@<`Sm mfðPy|Ed meod heq;cdD҂" PGF[̎`MUfUcQEVq6q5i!X~x^WX x ՂZ"L&gGyY877r֊;K縘3tvH'LpjΏN` m;kc^GU=-[%SMb95gg<,'/mAGɲ *!6e@dQ>K+ g؋M/Z2_`^R%xN~$UVjzp_ & nzM%x-AMyux)W"_&n@"Q0qPAOZ^ 2:8آ%  R7$ѷk5alTNm:eiiL_0Ui=vMad:s%jϗXU$&|Tf*|M̻W'htΟNHxgxYklO.2ָ(D[Bb  2*Y399x6_ <:eEU>_:sV-ﳒ Snc9*ǮՔ?}tՆ/YS~6)H@?n E; ey<6W$Ϊpf[hd-VT kXtoÄRW,^r,DĚp"l}|]7U6喂iް!®I*RX}5ux~դ¿VjECYٲjb+<_ӘU0frjD͵XC wR WYx ^)+fC>·Lk͝njd P*d:s(< 9$> /Son<ضIj1ON}v]qO1x n|D;j_5/ vy)]e^^Qt}xjdwϩ/)@La$Qa7K9y'iA3b#As6\qU cdV쒓mcCltӘ=e~Z׌\A%s&NlM\EJ$$|ڑ3`>Z!ƙJK6˛*"l(Zqa ^_D. *-e%pIlzǐZgcϪÈ"%F]=+OO/pѴ@bl_g$ fk>:,.iQHkd=䷽z8"PKvY fpve,B0x11BJt^JF-eTC)/p#l VRVTj۝ka%kЂ-$ Ks }1J|g^I|Uv+m&.:< juP0f?MrR62s; %kN382@fk\.Bv'^TruZ"U3+Z x^~9BA'Z I \ ]mSMnhF nc]I~nnN;cR#qh:5cF;7v!%'r3h"kK}ӦӧO]}t}ŋ;,='F,eog,"産غؿ:DRe)=K^9-z&? aA>7RꖱNKx{z.Dо^ιe~UQD%Ls׭Z;b-xp=by>Áx$jR*S:6lS>ڞԅy{{׷#3L:tz7->aR=gfYI@ЏTvfb̯yDI(Ձv-5#'v:fCQIe*I!y# `82N/+=7|Q;{vYWß>̊5ͱ k>,13@V^M~ OSX[##:JC,vg^92~1LДEWb2-fR-V㍱`]ތ<_bQb74xg49ar(sB&+*\-+v)&ե2Dfc *ĄR< I!SUo&HK 'NH1Jjϓ< qPF ,6nxw9I0GI/##+:!et,I[˜ï3mD~@x%]ÓLAfe2Aѥy;;Jgt"D) ^7r)jv(C}Gdarax `y.$!WFCm.j= ~ϲ[W;ﷳy7/n ]u Q %>P,eJSkk{V٭{mضj-< hZ,sZB*Vd3،^/VX3Swg=2X퐆 ΐ/<#&(hİԛ:!VŌ:O},3逩<4.ӣ'>]" {d u*>C VQ/0V휓n\uMZSŪk9OZu:ub,yAgcmY߬cGk σ2Y)'ճX:Ly=8~;`$CE1 CStэy7v%_V: di뿚pw]Ϭxg%gW-CC!}11l^֝/=N~!b WѠ)|˄U* CJXCj3Jpj*t7D"qbqf5  IL3xDG)c63 ľ/hq'o7=0ʜՠ| NTV"`Eh?/3Xl"r JT}J`IImც26Ȋ[FI`d׍\Ĉ>jʴmW6T.ZɌM[Kj7MS]5i֖m'q0orז'i-;fg[έ™XTi.άߩYKN*<+@3fl3\/ryf,m} Eb/j>7O}c8rӋd׵x1&)@H|K\s^Ќʭo{?JAC]MΞuwkU.rۂns3j[, Hx/^ey{/křbFY)")S:͟Io$t/=V歽{K5U>mxf^fh`gq>Te_C mhG\lO>ؙ< bA!JP0{s9x(c~zH'Y ϑB>C*D8RC-*kZ$1Џz,uR6h:hߐ898 :STzs=չ,һ;)vQܝ={gJ| 8LfO!G@uC@=ړl4AIn+H Q8@hg.5W /$В 3O3 ](]Ys%;)vQY6`Y nzP=>L&-s { %[.vs0rl) Ƣ +0 Čj@ Ha '/(9{zCJ{?<=ځvʿ'8@)]4RuI5wf.vHn=q(^x p7`hh{{{{{{{(o{{{•^v$/vB}?.nJt{)GZ[<^^^PPPPPPPҚi̓AZ y bP(p7}Sw{(Bd> <x8 FǠw;@Ǡ ;)vQ$>Gq?nzb/x1vacc~eb?I$Y tPn(D3xk  Ն?8L :ô0s)@!*BOe 8 xKUz*rֹF\#WړBkkD+?ܫf#~b(EcaפhiR4Š)Z4Y'Sdu)Rq:EP:EQ*F+<,EPjQy_vhgR4\UfhѸ:bhɸRnM!p#/w>E+JR uͺ)Zb)= g,ЂZ4g.Y= g,ЂZг@S@hAѝh)͈+mh Z j&-ϒgȳ h.jFg7>m'ŵвEZ Ih<"kpEo;KފT_kS-,Ob!\Ynrr\-۸Zu4 j >o6I.7" Ko#Rھ r|\G z^zNWRnH @oO))[4+G!5ABk6rr-T˩mU&yN WS7B &ܬ{[R7O C)j7pz*F,CZgՔJ:6^Rjq"RS\A!Oxը~ףzPPKΈ{n@wR+RLxvWgX!|M!2NG8JN}xkEǥ]ۘ?6T镥ϑgۨ;pmm%b嵠+&io9gߏMX#BĔF4oH⣘fC6$a0~D"kJmHk" mc `cF3sm?=gμ;!,Zy81w|E ZzOfJÛU5'&9l% kvmJ+u-^-g)3;/`uٺy%ܻY/~^Y.xZOcW '<)'_t ţ+Ke㱽 9}I߻T*RުV aT5l(ԷX2K^D7,ɑYՎ6ReXLqpcb_e2uGYJ"C:ɖ%2r EHO,\DH_LjGB08j!ﲀ?IeXNy l%ôtxBH FX@]YOm[ʦ5sv{@8`UYvxaF`O|zO {WxBuUuf mD0E3o\z|ZKvBU_ֺ1B]NTV ruq@0< .NLk + )a0TչιY!OxDP,s6  ;:>iYȳ 9=la4(뽑ˁ:`'ug5^ߍ獵b%Ɛׇסsp  olޱ?<*qղOE!y ^^v Wk-H2AyXƠդry NSqf'45i=^.FS -qXIRQAԻ^&oE\Ym@?9U󼡀ck"ɓ'ժMrj']`QiTCUyU;PEmd 0IVz#Fn7=; %0Ij+tꫫ0s$:v^Q wW+_"^Ie%FL+} bM}W٥א#&HA*RDV ^4+Y N*O 96?$j,{Q"!Id  k'/BQGp^i}\i#X}MJ맧ؕ9$짤^ߵ "z|>0|b$3܉$HF2vIv,2&q2ɇhy&CEZI$Fo"ZzyI u4JQA1@&&{l![ld`';N! a=)EO B5XOFzNXI  /l !i1,$F7:S\*| FἸL$⃢kzU*/$^2ex/!/[e&xy|^ ^JVtr5x䃗"2 ^/[S%6x/3/d3|`/vr-x^n/R^|,/ex^<^|^>/bLr x nIEwo/K.xJK]  <^^//?Ab\Edr3x^xyDˣ t.b4( Gn04bm>"ƂF 1j`4WDc(Sz+)--eNpª+-(+5(e=:#љ~Mj9A3'Qy%1y4Ja縵5>Aޛ<)Ǡ8x\vBiwYY6,:/8$(6Ws슋D'tj)Պ(F!hJ "'VfFTjԖ%OmY.]?I/(۵kAK z>YLg=TJ g,  \`- hgbөvLt F1¢3F51m èF," (m(3Eh&FYdjj,}Ro}"*%IzQ*. ʕb&:jg1O}=:>fzzkkkdi]i'ZϞobrsӹVSQtyyG0 DǦTCQUR&/% I;JU`,h1d$r\6_&@IKMz,(W$&22c:IOM!褁ee E W d*_rBYTtWV|&mB>=֔,U=Ld9wEy͓3z*JLU⢓!Lo@lUX+UXJLi' ҿt#wKt^Gl  *z-ErFԌWR^vd(u%:`2$y1c4p(j2̲*2sToS@rl2f"'71(h4iz-ЩY`щ97N`8 4'nכǩYN5FPZnznqijzF!НF֝,cYrY E rR؉K' iR,LihSek6RE\.[U0e&&• CLK;ycujl$fӥeeOFgtbA骖e-j6訁٢a9g^|- ACѼ+j%I8QYQRgH5VbPqeC KԐmnWԍ,~%Ee;ʔ qM#kڤΰ2'y#i䃎|aC9Eg,kN.'`GyH`N9X `QEz5^HjX´`AljHY hy{|VT#E㑠?ITC`0l b142:25;***&jH䊮HH/8IN_&V3ZњO}]qE RA*rU$]+Y~ZuI!/Ug宒ST8Z{ x6{EHN{O!' :8sv8oww{$)/W4+O5(KnLj؂~N%y"cSx6XрOMtՇFݣ~eN60YHO) ī DVDZDnPX}ЅxЪ*VUT he#8WS<^W0ytwR<A[QAHO4Ī#$x#,⿵X㜟QӨ1/_?! Ƙm.^~F-"3=R`6ui9s_5yܜ3)pMh:?,/,$4bq~}=pa{KF#1ϣcxlgK;Cf;RъDg{!*hq9hZЬxX^zbՏ+w1jZDD_hU]l:ĞLGSj7l,|Ebs)%=)ԉCMSICǓ҂⡎ if{8B&\ 0KV_T[l=5-)"C>b[,!S}VyIROrOߑk1b&̲R2?8Ȥyw8488,(k1L^G1xB~-o)9~4!#Kj=OʼnQ،_|ρd$ffZ ?wWrbpi#dyt Q C'B:G}N;QKؿٿV݄&_Wj!F_}i\j~Z,5?}Ujȟ3=)%hj=iKS7O-_VZbO-oy-|+goH-q|v 99Gjs{SG!iRnb Bwe1J<\c-}棸? Y&X- -Z|Ժ45 $Rrqڧ$l.N !0yzVN@NY2F˶gɞ]0Zwl쨥Mt{^rq&2OIɉa#Zz=L0(K_McN+i",]뿶?{l|B-Y0?ٕ7u<{ &VoX;S{"}i|ɳ΍A#Lݸ7qTGUꕕĦ=ws^:c*JjJ֪Q:46sY9ΩSVZwXWiC~/-b׬ʦ }w]s*>OSA9<zǿ7הx55M^rjqkH`gt*<= 3ԍk{k4< #%|jMdV4Xbߊc+>EEUѧVڑƭǞ82weתN eGUV<\jT% _>ɺT=$Kc|{z*Zb, 6?EL>hV *K0+߃xZiG.Bh|ۡ;KXj_^Xml`{I~-ʎ<;qW\!%mb_؜ƼzC8]lŢس-eol[}U۶wHqώNδGp'@ɦO! D0=aޕ|':Čt{ɵOn1InzQ#kw5 {Բ-OY]f;7s೩O[i_bi77zF's}I%mR8:H&6<ҧDD˳ʳDԅ'sg\:n/N([(r>zQM[0q}i>J;PuònXA` `^d1څ]ۅ]) ld'K13!dq4Ϫ GN#An\\3G^F5WvWn{^ΠnPe?EӜŨ=kTȭV`ڍqv*8Z*2;R_,9%utf#PU`"5`0 (nwnSxj`Pqb` A P@[M[p߀Cxpң6WacX%xjQ@xa Kzie@z֟a?nA| I''2~ <^///Ke fNJ3҉L`LV eK2GRWf!/ Kpˁ(oZc{l3[mvq<|xW78&{ןwPމ.<{ρA@@ t0HlF `mi"-Ȕ޳(@xS:a{ k'G[/Il>;K'Y: \gO6d݊k#ˀ&!/VY+URGjYڗ:]GA< ~{ HK0f#t`$ɾEiPſjiԾ|IzE_58Z |ȕ"z`2#6rS|T@p0p3"6&P3;N  @E@ sA P,,r`+1U:ʗpuz 0_r  g+>*HxX <@;lz36[6`; t?UUUUUUUU ATٓq 3?zO>SDLDQRo ,|@U2p,!"L7"L7""̞̘nfc暹ͨ l;P"O3P`///Wk#o¶pSA!sw]_Gc@p8NNg? 8}dYp +7p^D^D^D^D^DnDnDnDnDDDDDD.D.DDHi-Ȕlһ,  ] Wl3 ea,Q:e,U_ɺ1D9kP hgL # "y'?\^ݝ9Ln$ωe\ 4r`x p)3<9:_]oHUNI!2%YY;Hq`TٟAY=8@ޱlN 3ݨ[(B Dn+f'xRf )zܑ'Pax܆Srh7}=b_9jF j5jodb,NOgqz:SN}9kaîه],vͳ5kŎه{z/Շ,v>bfzXجRW vv}xI~+YaG)mr&j; .^ͬ8Gyl[V?b%YRĻ3fϾ4nk=O /lvYր`G6p]< Pg#}6i;K~> (<^pf"u}Ng's9x9 N@pG1g*N$O~,p8|>a_0/ 34TNr*sVg.yp™ .n]ݺpʀd ؞3_>d|8 |~:p9#ӆh%xCv 0\zD | _lQ <Æn6]:cp3"'L ݉kp/Ɔ76Dln\kзW|appZ uآi% h3 ~fb|mO6m3 @N9܆sIgqGܝU?B"vR%@KaX*(K 4*4R$a  A˸0.˸8.jɨ#P@,l=9Syz|993?| }@]E" .Nwqze.~}?þ0's񟪅5s63Ȍ_`Ɍ!eĸ5[x1|.swM>|;|nU'A_}*,}~gY:o:CՉ:1S'^h~o# sѵ2keVNzbXb*ҩЩ9;ջTSN0Ue:UNmSH^.il!St]a?K4?Kk\~g|,2|,:XeOso:xYexYexs{_Dx_B/+~ͳώCεk&m|]|a#ڟz_h78Ǐ(7=wH[%GgTNaVM(;~) ߤ围|G1܁i>Yy9''喌ܒ[2rKFn-|_k:䚌\sگ75oA;]=|?AWrPFA9(#e䠌TZ*-L5ow ǿMBC9(-場rPZ?i'-埴O!d䟌OZpTZ*場rPZJArP-u="2<2RyCJO]Εn9(=u*Ef䟌!d䟌N$lrPZJO*&UNOg욖OOIDDTIDDJKU*%R.Oe{A)M+_TvJs>ϏR;nV;vܬv|' !O쩛ݹYWbbdz' MeW~q o{WC UviItw5ݞwTпzog?yz5kg83q ;1 q0_*ܬ%Õż a0;;|.5aw쁷aOLޘ)H > 5ZsiWf%oVf%oVf%oVf%oVf%oVV5{8'DSqN8gl uWTw_z77þMXXRsnc86%l JުJުJުJުJުJު'?>9)/L cOn2 {Ww燧c̾/|2G<)֎/_[[ÍVz,0|2Q a>11|!3$|%)!O +qUPE*i4 v\QI>1뗸0ц\pj|נ3a=MXᷬ*܌[pk8m?VcM_VKǍkĽXgLߝ9vO?l=c *+A}쬠ʿ Q#ʿ27+OMpc0MtxLN@t{2ჸzeZϿta*WdO>6P53,կi=폍v{6h7:Іa<@ bT;c"vߏ_'adLQŹGIС\/WE_/vpD?ؾ{D{\ۉaEd߉ˊ}konp5TWk*a[b[(˓AXJքd,\;ag&]lrװ?öd{f̞e$XdS0&Majؕ'\7\/\|{49Mt}cFIØí>Ƀ{q;ǻcܰ!yH8?yqñ@h;MsNӈþ)ƜjbO3tLכgmMlכÙs|,y-_`k=/Կi/;͸wqs.g\/y5+IJRT$sx/E/a qeW^6TXOYPv ՁkR꺰7u}M:>.J.O0fks.cn3#Ƭצָv|4̤>vRk;}R{qOd8uo0NSqg5s_}w^_ol 9up}18bI[&\CFF2,ed5ѐlrQN6F9('dlrQl]3K=2dp]/ >kd5g3$ >C?O9Ο?{9zr G999999kF.9ā{9p/^Á8p8pwsq!k8pr^3fg/0p ]mCܬܬܬuqzYYYY=ͺY7kf9nVfenVanͺY 7ܬrnn͆Y7ܬZnͺln6:Y?7+q7fkY7fFnVfenrnnfsܬܬfܬfCܬ q27+sY77f%nr.nͺgq³ |,-_`kD-{wTnzY7l#7+s27f=ܬuq%Q QJ%Q(]pG)p2G)G0G(]sG)qtq2l(eR(}e-G(]e6G(%R(=tqQ6r2G)s>Q9JG(%Q2ND kbcqٳT3 ' kUC ce[]-lPpPp\`Z+x-x]MZ 8 YLMLKN L݂9ݵ{hkS^'akSqJ&ݟr^WOwmõ3 ;mcksh5fMkwcwvx 'zI,r'vTbt8&Y=[۬\hq\]jE\2|еKj/3r}W8]Z!5P`Z n~X{V9֥M}RkߎvvN}wn|µOjծi}qY|εkeW9bwm{PX}2 2mW w6o oRؼq +Pجf 6-VYo8?*0NaBa@a  +/ +Ia)(@aBaEa wVCI 6dׂm5W3k72tFoLv]L;YF=b|my 2n.zؑqGM eܲ+v˸d܂Lvd2mAE ;2(öɰk\fYۢuzYdւQeQF].nQ2jYFQe2jA&ɤ]2t,eСqٳ9o-oվ132,ce^c\Ɯ$cd\T{Ȕe 2eY,˔2e׸L9],Ȑ9kG TQ熋էuch >\z.C-Yj顖4̦4^iug7y<~!ƉԸVݖQPrlT9)hʗ(r+{$ S^:)Ly?Vaj+T?%lJIU%T(ċJrr2D-3{ g9(sJ<" Q5%^I 9_/=gKWJ|p nvZٜ9l5 Vs,X+YΪWtVb؊+vJ [U2CVC?,Q %i~_n fdK}f;9`WfAq'}DqO+8}}eOY6٣*5DP]>qgՖ[6Y5X.hGXɥVJ.v&FP}Ϫ.mIm]>qg[6YJ7X.bq'}MVAE٥d&*hEqf>q'*:} e,Luq#{(R:)R(e}⾏jSܷPj}g\ܷP(}o\g(%PF]P& 5Q[M=GP^uR^5P$q'}vQaoWk29E>o:;'/梽ӍTZT4#hWOJir]pNeꗕ)eo?FcѾ׆^ImѾW_5Lqu[k?Fc>׆^Im>%Q⺨^}1JEUJJ}aJ;\}1JEJJsQXϵ.WRq\%J1J|8WF\}WFJY3UJ1J|}u)q޴UQ%QXU+#%V)q850Jov(q,U+)-ῳ5?ıhk]T)q޴UQ%QXU+]k UMvĞL޺˂Ǎ8j,˒ڽ wi.]=A{8nնi/^[ M[~T{:mVE헴_ Ʀ eW&܅Ta1~S3h h9 [ކ1 sx/E/a eW^6ak*@ |N|NjgL.awt`EZwXYCqyXwİ&$ Ap:<- fձCÂ< N6+ʆgs皍kᦱu:q3[XXy>%lM~{oIQk)vs[\N9p4pyd7M}S}pQ?jG5Q?jG5Q?jG5Q?jG5=~xAq55/%[5\]״ͱTp8#`>+;»kq'qJ[{94/Ir׃p!^]m/}ϳx?X ?//+l(7gBG'up"ރ$,)AsT,i8gL4,fpuJLDj ZpޏVR|Al %!qUX!\zҩOS=`{[g9H676WsN/?+1OԘ"\lL[0;v)2ܽWhr\k\kvZߵ*T5p}n-Z֢Zom %ͿF_#k5¿F_#k5¿F_#k5¿F}|÷}&TOTOTOTO|g9~ w~_a#xFo"*"*"*"*"*"*"*"*"*"*"*bj`voÞ 7&c H 0`_쇷cc;pf@wbf`]80|8G"p4Xw8>7s|n h`*1UcT,SEUEՃ-|QPʲyY/eY(eݢ[e._e._e._e._e._e._e._e._e._e._e._e._e._e._e._enX ΍F]*7,Gu%'{E%slYIOgT fԜm>jFMx"SjT`*zyڗ-yblqU`s8X`y6Uh+VqWg#{FTUԸϩβ}[QvTjKbv3YFpg,Ѷv{p%*-bKq5nh/fpyB{%r}j\zCUfGclp3n1V]AnE!|#Qur^׫Wի"oY鵇Csv!9d;lCsv!9d;lCsv!9d;l* /˪* _UeRO^çi|E|=| 2k GWGqut'qutKrA.9% 䒃\rPWGSԊ`Fp#hC< ~aC(Gg 90Qf+BO4X?4~OOvَ2Qf;lG(evَ2Qf;lG(evَ2Qf;lG(evَ2Qf;lG(_kMi57’i֜wk43{uظue(SݻbA6h3Dzs>v\ ! ηD&=2M0OhocK1jb곈#h'Oԍ-S&@Ex"^u0xӭi+^ϲN?CYU;KuNv%>;` :Si .`y޺J@_Ep8GHhN{"7  8sΦ ^ wB5L|+Y A+| _lP9Kq9zx M} f'_,*0vxUҰ\( 8P50@ &@(+P>/J𪒯1ox̤YxٛT"wKo%۫է71y6۫ ˡ:n&GoIxemhVKP 9Wa_ <Ճꗌu5 ^\&eⳭ#1=;w]|ץ׭̆c9zFx]! e [muV~` u4Ƿl9Η=yϖb8G0hy;sp&BpWwq'p'O.3.ۊ⿭o+ۊbM`꠭D\E\@ZY* a A &[Tn%]%]B ,B "* 5p)|\W50n;`2 @5L%Y%Y%iO+|Z V,Z[־QnA㶱Fb]= [K~z]{.~ħ_/-? 2^#܈7K?Jj%zc^ /4Ml#xO,/&rQv3lA|8۴f+zFW7W hC:ۡ={<,F>›ζD;6D{'dLiHD %R(BTO?4>GhZ6z۩#K7udHN&=J+&l7 JX5>r k+}:>KpcRo(⊨dTWJsR2Tm{3Z&]7d7ZP㍡C7o WԓLѬgD_fUx7Daj<^k؆F0EubYnDCd:QN;y5:JF|(mtZ)Ml|B9m^Kks=%!z&1VF>496cPԓH=T&td-bLn\<'Av!;D$pa/Yg!.U?x\f _SϽzj+_C=s̽'߰;xA ^!ϦmW9}?Ar?Ѿ5Yx_`Vղ7RP%hr] M eGܯ5\cڵ j=| I 6لm-T[6uwW-ÿ m ㏷Jhu68JGj< /9 xާ]M~v[jC^:uOh sbrn5R~_eWc_{[rna Co]M ǘ瓯 a00o$q5O}"-96}^]49vulC5k}tˀSnxclH,9dj2b5XMF.ٰ7Yܖ`|=drSe=CԙG^ cKZ&Je,}s8gJ^Jx ty ^c5L[eLSLZM0Y+AқDPCPCEMLڨ#C'P&S#+iV)3dTU UUK'r&ke,|5P19hYnac8kVVVVVGOAfh7 ]ծ"{&X-lE$C4t߃R)8T2lyQ2/RoZUPj(0k3H.e:ԢȩUgR" Zq+g{arjժk8я5*8á,Znb'qSURͫ>sꞥD}"F@rBVe\kRY5j,FS+r+=zkl?O B1 #YUMNX `֨r*O E{:˶e[+9JSMgouEHTSHzOr~G!8*рJ40GYMQY0F]P\BW̝~@70sl  ̫lj"Hk J_8XKb,j,3Gy~:v:RY+%kYZ.OkT WQ*[EunխUTVQ*XEbUTUQ*VEժZZUTѼ jNQ)*9E%՛zSToMQ)*7E妨BSThLWJnc6vd;:^m`nDOa'uHqnsSbjdFe ֞,w~L'*zEH)uO*lg5{y$EN&5(n M)T6Ԡ)5Pn}`6Ǜ<1wFc]K{G'ܳ S j(fW;k"7 .C󆛟5`.^e\٬;'Zts 1k kOKXb\f0NnsmA5b tYC*֐kH7I훤E9ftkk,Y^L0 V)c=1d `^y!*XŎaNTcXɎq6&```=3 1"|'`wB Uy%o:vp Uc`\2l:{4U*\ռߚ..vqaܺ>"}Fϧg0jQ B!W( \xƳ>o+ij,Mz9_Ȍ]q1:W_5΍qTqL##K ?ºк"$ͼNhdX{{+ވ76Zx_ZEGw{7e>c|aqN~y[͕7tC_ enF!nߢZTFjUJ&pDκe՛;^lmgkesnfj&fv1vҼԪǣ#8%q8Ԏ9bL 1߽8\ .~bn7^:oFQT3JT9E9NG:cΑurBow ۛ,rMDe;*`g+=Bg1*n>-}Wէw W&j\-a.ID~.9>F>*"_8'!"i_ܙnmϐ,9?U'ˢ<0KU,Џ$.FˑIlOoVI'm&bf"#t&Nϊ^ЋzQcГzR@O4b0Lo Š &tO i=Xnl9okY]=MO̦g6QM'ba9s[9Dy(//TTԃ"[|곹Épo[>`}B1yQC[cDvD Q"'Di0N,"ρ ߂Bs\ 8` 0[Vvw={~{>-b=C64i;v9dZ2E-QB1MFuioDZ=6#z.P.:6a"S+t); eg0C [o a4wi߃y0/orxsX `|J9[N_Yub]Q,j{-ʩ bEDp*hU) p,@KSCİz kc!1j5E"fiHB'k>5fx9 ۿ&9(P_A؅P\ ]k!a2~m9p 35OL>ɣL%/&*\B-ذF2rqžJ ӧR抍O@ _zNufЇS(6hy]`^W-m sB9?hpvS;ESwr*S *oSM1WǃӬ2삿{w=XD]_?AFSD2p*9K;xqlWUCE_=V^{}=ۓJ0>%VThY1c1r3`>\+ĸBwxG9gxzK-ce,w% h_Fo8JQOzen=ɂ^YV׋P=!47ֆB[Chk]k zBOCi= c-ѴcZCB7Cf !43fuWk:A'#d ^"ft2NB#Chd !1>BCc} z-ACb] !tQB(srFZB Cha-.h7sZ*B%VbU\Uy/?}љ{Ɓʂ=ͤQL*e|,R}Yj8ĬWB,w{vwx uAAsw5?DQ3YU-jX/]Q!ȿѬ*YXXT[b-VɊ'ƊGYml+J_!{YXUdcF7g^f Z%^[{;Γ3siŗ*fYm*MǬeܩZOUFs4%\.ChCm a!60&e9?C]) p,)ZF0&wa;L|0&vab;L\0q&uZ_ab=L!g U+3O~VNi?=O?5*Uga!8;HGaUiџٸٸ>2OwLO4ksi\aW WO_M\+40)_Dwq*gn';i4t~:?NCeyb$^dE6_'~%? ݟ7+;yΐ3QY2@.rAQM"'"'"'Tr9az9 [結Fy3=D\& ћ=s}w2Qd& øk: UZ{ÅfU^ީwzKWZӺSVE5s:#se.>eV]*$YEj1fvL*MSQcB!<$]}~U{^cB5!xyn L>?1?M0Ue;M6zۆ觲z;9]#G]E]g.zgzgvm.B"yό#.(׻6<sύ[B< f [SÄrϑw8@ 8*q%=@5*k@ʪǕ]} ƿ'+W?W%=Nk"*l}>lTR *+鼾@\BLLdqX< Wj*Gu1rRT<%fE1 "bH_#^˃{,!P,mir,f7X#eXH^,˰T$ZA^'o]w|H/ʾr|YeJ*7/ ȴ,`AxO' u:TR>'+QSjZ D-3r\^T+,JjDQzT)\erU|Wv9_e'-e)cKV_ ruU$WY5H*JzHkԪFɔ5'7[KKrZ"Z kzܻ@ɢE*WE3SꨢE3>.ڦ..룮|nSq$]ݾՏ}q_\Uݯ|G|վQ4ߣ1Tz Iߋߨ|3|W%_/wžooKA*aKԧaf0H>:ccW j}=JGۧY}}u}=k_aG{=bϾjG 0fk}}u=َYev܎['Z_bO*OZOZg[9;Rk^mUk5֝_]F{ubkkg﴿3WVk=coo_hMYm 1`aRQ2qSOWGYSZ/O^?ǚ?[wckY/H~z&$LWMn•DPDDDF~٢E6~١_tvMzwSt_鯜O:pcCKAoxTyxR@"Ozx^(px ,xS^^ x{{;[x[ |{foKcoX64,L65MI 1qLD?8d&M+8lڛAaM`M &~f`0 6#9ݜoƘ 9fB9L 61-̥`bn 6`b7̣ dy, 1Ϛ̿͋!erpyż<żj^ 7=#6z[L.H.-.$ ޅcϥgas-8r JPw1m{Mv.vu+?W⩬DgXv+η=%n&bi~ŒaO})>vmSZ`(WŶ#9g`1s'W5%ʭxu>ڪJ SZ9-Z[ہ ǏG|U(17mǣ<.GXV4>.~')Csp,($HC۱DȕavD%][K6?52l)@b2 JLA2\T; Zl)kcT􈅘s1Xb?mr9~FA٫G?a? bs?Z{gĎ(?:sL6R,3be kuM_X _v ;P.@OE{?F[R左12n]2zHh ccliEׄ(BRӼ7ٶHґ#c,.ԋض#򛜇=b ֒X]ǐ9$: OǶ29h߯B{t!\b۪(cb37g"W).)r5<7-n)\r+ u;ߛ[Z??k9ywbDcklY-w| e4*1QXFڛM N,gQhNŻcy~HLv[^xϾ?nY0;}6c6ϫrv(smiKӋ1u2]}G)YM ʿ޿z9&2+Ǻȕ7/[S˼Rkf=?هsdzAk6Z?g+q,;ͳglfzKf.die6sXv=m?!}eA7,I2~dzXۋY<۱c?^R0]HVo?ӕQq ?%vp֫1r.xߥ\udBKco%wI3bV:PõGt\|pἪx'/_dU3sQsyu_M),TL[fzJ5*w'}W]Fabu$gJ+}J_,3yՒJeۇczǽel h"Jb:yʥhZfeĥi@i+'Oj sB,ߤr>+Vǒ_TMJёUU%SjY3Z~_,c飶H-+oTj04n/{˸ʽj] n%ӏ_NQ*Kll cּ}Ueeϑ1g}V1./.~|zVTk;8͗3eEbK૤I8g&Q"ooPyV0ʗ?q3X.vWwW?)$ l}(:"_c)wcK؎ >o)vDp\yF>O.tm +oL{k\2 {^-ӻek1\%xn߶eBϐý;[ǻ;{k1.+gJ^n^rS䚻;ڏ7T-R)TJ8Uix(EVPcL7+ߙ5>?ʌ5϶晔&?C3QOG.Qҟnk/U1f&bzqov-/7NwVycWK !N/J9vDsI5Wkq~;G;p.PZ\Yl4=Y۽ؿhf{k~coccUƻ=wxoac~Y/]EPʻ. +*W,Z/藌rQVo.iUCi t# 4-44FJOP.E_nݰiIE +j:H'tYt=$&vB41YL#b-/$^d*hrh2W4+++̔me[1W54+-[O⺮ʰ;ɝ${{WdؽֽA6u5ZY{lgvqߕ}\#*'&\U^㿼* V*S T Qce\ʮ!aȽjuܯnP7j]Tw;R>Q8[mTs3PmQ[Aj Q*+a Sߪ=)j0FCsM;(!,^"Sɺn\[6u4^bݜs9zs'~q?~@-Aڸ.hNĉ8;>)Q[ԦTCA X -`"I"D=IhQKxU(%dDXGC DDD(U$dj(]4 H)tHX4 h$Z y])%:nեj܇!}JSIhyG v)% aWr?_O#j~Y\o7"ǛM;]LGG|ґ,2PᏓqא5GClCm?>~1b>zBBQ|COZ5 =z^&BoQF2jZZAC]hM(ڇ66B)Ўw$B{C?Q=B[íI Znn=jΥ\JgWRۥPRc<.{{ŻWW?ŝBqUUTt"kq::JtN; !wR lw6uqpvM*jqPW3ם4uN!CIr##}(<>p@OO33 EYz}i.v/KKݗq?PWW Y.A"א5qv߆ KݥT}}w>~~fq?r?B+ݕ]j\A k !?w?sw݉Rr~~\{!DCxڿj:HU tJTISS!*RT)O" =JVT_RjPJQ_TJ%m hn3ՌUsȆZdP+N:[|C]ovQ]qFʮonWCU/{Q'j_՗Z~?jR5) UC05 WOQ#~:OSj4BP:S aQ 5DP]H  u3,poNRw!߻սcK#W}SZ4^,zOc/¼D.o)[5:ջ>@ eHaZ+ P} _VR[J6AFVE֩uHaZOQj#MjIIYDjXDH-" o)dWHUB2RŅԮגHH8]5 RP'D4z1]OFiMMuX!O+!|NEƺ 4(Y7-ZKݒ$fk:q6; dGݑN$Y:tgݙRDꮸMw6r=t@~6TGz$ЧSQ±zJ~/Di'KrL_Ԧ?Q}|Mz:u3CߢgIzoշlC߁w;!K߅ܭ {=Hy!!~ L,V LtP/ H/fJRotB.3$;eI}<0 Sմh~-lzOa)6Px6PV\,%\ޝ.Ϡo{;؞~G {J'o0P.jWH`e1oTNj&Pr-`x H '0^g^x]1^x}a ( ȷHU>hۊ v=kw"Sd",@x$NO=EO-N'AK-zG q b$Si? L Lt3ZF:gVV0W778wz!xB=qx+.Pla2R13!`* LHFp%K3 o?ΐa,sS3eps3c09Yf09x c3Μ 3ap:s33f09iF1g89( 1g%:M&:A&$C2 IɆ!vy2SfMvMgspϓQPNNNS> fv\j!pR|B>A#3j") *_EZrᮕ@r\O2GHS$W~E쪸PS.5wj9vjSKS;!'Dd'n}>6s!eG8ݜnЙL~_p ܩ?8 KE^HHOwڂ)-K>#.`Mk_0l0 3<ʮB_5S NK0vhUA::ϡ)! Wqǁ}%}  [1>HM+KfV6YYfe6ܬs w;2D`uݫݫLl;.X5нŽ`;̩3Jd6Mg60DNHr̗)ifD g.\(\?sDfAh? !ZaӟO"Df2^0{E3{e(SD4`~̤ xNSX2.LUJnZQW''m3R4bCuRsUU |W0XRtdD-'~pv0X2d3cČ%K{0SpT-mtd҅yKG-'1oTgײ^RԹ\H,dGG&.R.VRu)e2ĽB]U*d1l'N#5]MGy,fVV'O{f>`>Q77s?XPGG q`A QEB]yJ:l*^7ԍTI̩j3R:MJB˩8U[ˬYԙ2+uw-2T#˩?V,pxZIZWoYV=fY.,,k!̲12̲e\ks-ZsYP?HCʶnõl*Tޢ9@qpO d]:3۫MAo7i4˼e}}D-U*W{i[CMfjOA~|ja)i$53LZ Hl io`:j ͜0͉67é9͜F:Ҍ1ch9Ӝ y_7G=cP>57Qrѷ sd:B³[`ϸ$t ͕VmC{諨s)?nte.&/>?٣ohYU-XƶȥbeYb5JOa0 4y\1޼~\0S_Q`tfIӶg{ue(T<*ScܞcQcc[|; Jiµs0|\E.{VA_J%`g<壎Uf*/-BiXSZd5r-GGnVEKb5⨰DYpCr]tHXY-ّ]8گaҘ^?ŔW>s[)t!?*(hbV+Xu]ZXg}U: ḭv,銷Gn ,w裂Z}qqW:C[ bgy:u{`QFԥ kr^6q.f3+K[?Wd\96jlN*Ni&B= 8XBVeWBM\~b#{;XW%<dCوek 6MlN IfQMEvxG$9DzrF!9ZAIMyS~o{5rH3ĤlzzYzYe<:PG1)PG]솫'p;jm[\kӹvfY ݶ\w3ܳ,{&x;\kp=\kp= uTKY96KMijy03P˃wC栮'q]u|޷Ym䓨Qkgi"&x I KګО!C#OrFk֍Y7C7Q : ГГp?4|w t9L#5D~ iك4{>ngӥ.%BSCRYBQa֨<8Ы<.Iv%C3tLд0kZ"4)i}So XjB>k]:k]:k] ֺкoaݓ{JaQT'|:1-kc&mJs'»j&9v?rPm+9N&̊$Rt Ij,%AcK){2{fWWz+)`DxF;oW7xn6"3i<9'sw3~g`:N syy ]LeI;G &|zR*K>t `5DŽ?8DͦJ{7*}JRoURWA͡J\ͦJ~ͤJ,*}JL͢J]T{/UJ{wUKUyߡˑ˲7p*) 2gc2"PDM&O(.?@q9T*/s&R##u %u^ϑsI_;4%D_ ขw_q<ÈHD`:y+n%n%n5)va2 #ڷQ]mTTH}7y0:bt"t+@2KfC~M/#u"9G΁_V0'RuyrƆ(jǓ c@@pω(R'"%_/.RUt"L~)vR6*wQUlUlEQXX x"p<p<:j)wc:Fq{,w Xjo|G;B[-RSX"45.?hiO?!U#T ݸ8kq8Aq?#_%)JX7~yx/S_"$AA X@Q~'&2`0^&2L!仗 1 ,eea4>:mU:hƀ(0HKG_V01 > QL~y0_ n#Q0BQ.JaX76q&61jTDKmTm{Rpt 0Wʛz<_ glaMLl+#8ɧ|9&$ EB b'2~?/) d1'Z l#`z038Y\ D/C`4-Hs҂$H56}- |,9`C3F9 ygN x8xOJGWJIW+p%|owO8_OOwEgCŐ7\{WGB1О@#|˂T`!4] U.cCؔ B#!4ˑk—'e"|$(',b.|ApB:_/ ¢`N\q j?-"6A' 3&PH.@uq8)-. _o@`?݁fOfׂ9uj?;L@9%0zi@I0޿'wz`(X_@e&0X_ dC::E˜*d mš(f"+ZF:X+]Z|uPPMA)8OO`mP5#8_)kqAߨ0_.-^~wwVr|HZh6 .\V[}*_ww?Ӆab\p#x# 冪C!C_ʵ:::Z C@X(-T__ m,91 k! BА(Tg@W?.KR,_"4 UQ*jb7H~Z@X-PSЧū'% nqX'0#^/{xS B!eK^/†p\8, C?.ڤRp\l\y "KIQ/ ]kHPX!5i#,_tW t.2!ѽaz FȍQFF4tecEcpnGDw<ށ#(h7ę(-:~?}])*,~=Jً1܄Pnmq܋Г떒|2o-B夘<݇*8TC`;Q- u|ѭ lMOZl@@޵hXHD;;R|E NihJCqz'<<<~ΆGG·lx\~skh^oʏVa-hQVioU Gto认eN1=)u~3zesuQ?sQ~Q݂[hSWM7_a@&|{$8CILM&/Y{ny@~PSE6M~\q_ӏii~ ok5J͏5pfDSg98Ĉ`nݸCu+{ ݉yލ0݉̽̽8~/l`N؏ ""22>˼ʼߓxf~k&ĄCff1|aFu f73yy y"f!aw1sd lH:g"^A'"_f7ɞMw :h|}~R"y*/Ƿ}۟^ r,%#dY?/[x#/@dX/4 zc\8/΋q$vFbX#6B.s?+*: ²PgӉna ~-r!q?+6 4)p)/xMtGœ1>qE6(eJEY 5H-6 e2䔤EiM}_/ͷ˗#iB:{$$I|D:',K!9)ߐTa!\󝒫*o{A?<͏"X&FP BXf,\M.SJz_)(~aR"yk//uY~o/K6bX_b' vPO C򒤔%FDAT%$#P&HkT.HW,/ R}Yj}w 5a ܐ6|e JZH4v1nh~D v5pIapw"8JFOKAO2t'z],4nnjP/JGQt/I$ 5&>9=B@MddaNj!o)j"\:·oA[oA᷆ߊ~z-|kV נGA(()^sOU#QAfT?@?QRB#V S 7>cq=gB5Eo>Q}Ψ;л|h a̛/5kVGtqݏ.й|tYֺt>}[[#2D ~kS8BsE^Qđ [l/q{I)E8YCb\/E5!_cJF~ƼW%CmړH<֒*4آ,J됭x0WOl$_U yB| A ag,< Y&poNb75Ua]š̼CrJr\PܧNVQ M{&0i᜘kI5-AωeR6%[g^Jy XZ)Fu~]hK 2+.ΚW . 4į׬<Οr"t`[ur.`|PdAkM[R-֛֛Bmڜusm;=)LvӅ.~S8%iiaͼ)dlrl5 3d`dKAʩIvXcWb[p7 Tmf@iWͫbPk޴ 7㪭w^DT@GGoY>>Gptorʞb}4q}׸*OVoVos-!)T[K[6 Oqow46{Oz|uR jm?/Z ЂFݤxyĆtoCA}hvc+JQ|VQ+{ ҽhˆ\xW-egI\K5²k4'lּ[-.x,uŕE@(5ʭHm{kzZ6uBpRFy|5_(yF(S-RAG1s=uCv{Ⱥ׻nb>`]H<`ߒ&8ŷKMy{L(7́^u;ٗȝ. z=##HO'2=7 Wڛ=Z3sSIts}Tg =S}=93YFߺ]qyho y%c粧\u }(,Z=w5FCS{vyʸ v^\d2㚇:<; XS7|(EqD$D p.~E{h ~"t --xJX¢hb!t"Cb^{m qOPlh(͇҆GLR#l9l%] [Ew}9J ݻ*_Eve;CفrN5k(W٭F_S({ne=4)M(OauӪշTB*U(_UBPUQFUQժjQNUUի^UGi~9*Ҽy=yK*ּy=DGOjѼJ5=yW*Zs}+dI݄S P]T^t4O8p=p& j~LcvE4Fmj|)v Jüٕz֞i8fow " )K> Tmc os={KisHvUZtA){QǢθcړ]EF*uu_q;];e2w]j\gɾyםf;k.;ʝ0.r{SXak82ilma֒3Y1LjKS@x_d<=YW:F:7]:e :G;VS?{SoG#{q=鞔Koq^j%n_..J6mkW ݣ({7cc8ݴs~37ݹJeٌ6oO_.Z;ZAT{sؙvn5(,n.$XEVs.ttxJl=MŘ/^6z{)d z 0`na̔lt:ktwc{luֹn_097WT%fAꮶs; +z8tqqOɽ=uڳ{t[gCEG5{; }oq1nt&:3 =;쀳0lgt W-qv6:#X<<~ՙ,wvZ>\ Us66\T6|y}eZs!}+Ž9g\>Ktn: #n[qNJĵ5]O }z~T㺧T[joMv.8XҾK?ٱu1l{+AÆ,W{]rwεͮEwCֻ"gͺa7/jj޼ G#͸dJrsuWa UW2{Ჹ$5]zνZsܭnf#r5~9SWK:eir%u,:̞wm8ԮQvYC$ͰIe>(_w .%еqpt-vDZW*^ Avt'r"e p=$|`g7(}5Bk4|1G(}[p *>Ӂ}~q>H q6QLKk}2_GeBW_,0'I$))q>?LUDU"|'V5Z36U'ޯzMՇU&*x^yk$ub U5zTfW^ĂZǢz:Ip.ʌT]cYgx\)e"C݅Vڨ6j_Qϩ'0_ԟԟ/PO(|Z<L7oR|< v7fEf6`<шl5D0)~$UsLsܥ7OIK|Y'#i$z.yD^%z.yTfdzc2%E2%뼤X^%O뼤D{J;ELK{9RV*wd9^^ jˤV^&ߕWI"L'zus/LAeU!iUY/Nڙm6cԌtJB3A&I%2&^>&yo08e0+kddu 10ϒ~YG~(strHG2G'2G'>2Ę+9cD&@ƀ7-fy9J>Fe~=`3C, /31|L.1;D-4)v`V.HOSܵd{)0r o]t@BTQEQ3"ƞ\0՛᩺)IxW֝e:OE x*0ujnx”m:24S$S<1}asa˴tIϫ"cMmSq5ST;cg 6_ck;L3n4ӾaPl;Үv-lW^217_YR,zA"XYNZf,hk5Ӛc-gkUq!Ni}2lYl~bFY9oㅪW }I3lj٣\6aOwę KUBzz.ւ՘3----G`|RZvуhۚ9*i}GiMc-kֶF [hzt< ٕxEg~Pk˚f[sxZZ{[ZxkIt$:F,dS$_g'2y" j|$Q`j79*R8%ղZ0K'mX[BXTaK3(GFB2yY:FO- 2Ц-#o?V_ `E#-cQ WDzĶֶ֤։L`mׁ]80mfmR mmE6{ud+AzO.55u EڮD`ƤiqϓdR"늠&E)_QթTx)ʡCNh bU$.EUu#Dۢ^U"[-u^]ʫE'h`pE#UG|n?hIKBKr$Auȇ-L?\hɔGyjH5udU-G"b*t:y@\}4fyL=DO;[2sZ4 ݮ/}eeeKe3oeB2|A̿iG QTE qts,)-mKymRƫ6IxonӖ4S-~)QJ2}q0C 4IRTT{ wWm"< 3'5d\@!?AeKWbɩײwI3##'9Z J۝) eZgj d!qKwE}*֎{^v j9T'8`q X#$ٷdvd(\`m^V}QoURǶ#&猷'{;J{>h }3?6)zIm2#jw}nkWB̮}{D}`Dwq_?O!~D2!u{Af6.lIw-Mu,{C@y)+Nb9y_%CV(gǮL !&} oDAہTj;p .D{P$>wN_ډE:`?&/K5Dc]U8(c$3" *$)gv=JJJ.3TN@).c}P>|9}⦔&})>'$xdv<Ǽ}. IiRIn7)˲`4GbE)/e]HT+"y$9KJsL(,eXF|.t\5rU|3rJA$G=Gqw}7GkO )[29@>8H E&ԌȱD϶fjqb]́jIlm<8Tȋuw&e kg*ℴ:f8W}/)rDIsB$>ې:}FXFq)kv[a]ٔGN/8?Cv`~|}VTDw W//$c<~F G(V|Z) 6\3K^ ]^EO X'iʋ %3hԒp  Ny YE^G^;.7~9 0I[BZF| Ȋ{Ŀ |xe+/1zl်Ȭ8`ƹ8xzl`]PjnV}IpyBE@z-̫K- rUdSZc6>*+Wd? feXQyDE0vsg g#9g]g]'?{ɁMJkjאd1Bk&2:ȤLIC&eF~MȤnC&u0"VȡhȡXȡ8ȡxȡȡDȡdȡȡTȡZ B 9TPuvw@VQ o=?ϣϣڞ`i*=;4}57hT lP/~E߂]1 Pi š2x=>T?B%PW: uGϞ={m=#m1 cB}SPu}0Fw_F_CE*1)uS] o0}=i*:v^Sѱ S߉k =9 8ơM3nh9V'̬'ƞ{h #r]AUa_zx ߀z0ÿ %G.Ǡ}ظT#T}rh|АnwFVqIƭ5nK;ƪ>RUŽ2U}+}?GP}xwZE親8q]xLjUGJT i: qrv&x ru:rՎQ0=_gv [Ã޶V*Ič8X=yG6*Ƌhy|mzuĹiGz t"Op:v"yYg\Ӆv)q]ħI<-!Z$a_2Z]R%vJ9R>hwҺHw pu~>7;ffAikwyO8ŇxWk|zh+4jOI)$$H)J<D|E6r,#*?!yL~.LY/h}*mH%#N9:oq e{Q[zq4d8Op*lhAZVwi6{XGH%SԐ{a.{ͤ(ijãnA17£p2Nf G "z U۽D1%+jZ6]oo7+du:^ R"rg0L%I~C ?N-J XK`OGb-V#$/>rq\%pi>LaSLUaXąGdxY8'.A9´xQ,n }F7+BcםŚ,n/09F;;,q)Y`9&(]!6mH%R!nIR/Z~ RwIW:#& :|J[˼k>>SxJte_c뢼7.n۽Sg%|ޘ, Od%F%Ejb҄4%ŀ @;,rLɂ'c2&4KҢ-ܖx~B=}$5H`vyZ:.iUړ/ȹino2/zJ_ӻ}X8vm2y HUQ穵N?R` f9 ^e;4#j2d_?ؤ#FoG)^˸0S O'3yM1a'eؽ| ֕~n; R[rZ{d30mLesy8woکfMqf9;]Yt[,<3l3 ;d1Zf J9\ }k3oi` I2蘤;fɠo >-z/@ԛQG!̈́!͂!Qo6D7O@ԛ Q ͇ 5B{޷ ꭁD ꭇ&DzoA{;Z/6s!oaF.j(yWCȿP,2Xh(<ס ub!{gtg};|&9:rFp .. -mD:nhg/tfCqPs BD~RChP?<ބ<*>/i=VCş? *,T9P/B_**T*fE9s$砎P_:wgHGKP?{P?ϡvKo5|q!u됫K4|jP+,Kk[}"_4N)pNC3ur{Ew̴L\̩i39ʾDV __}Ba?1NmQw5=Ρ;^zނЋ~OhKL}| k t%@Ԁ z>%(7-I|dYWT)Ssū ]YdmSnIjĘYP)jɨ_[1 ?Ffk K|5sEX)l yƜXt-Z-uXb TC /[Ӯ^%b|E,\KʛǢ"┸$i6S,Of1<?Z띆=nO0$="[cl`;l쬚c{9ױg ]D)bB뮘p(O]Z7/ӻzösJˌ"- ┳Xg;A3JمbPrCVGj O)L.e7M&2)n\SN=s.s!.Ds-sUZKkљZj:tՂw}==_-S0gͼqKVGE8{0KLo@2UB}^{V* .Ek>aKbHl쨴 KҎT:NmH}6֒*9KziK4[:p GkFHymy>sMW;Wk5A瘢+F:*д,u֖)zl,\mwFMS#(Ea:Yݥy J:uU0 L&ٰg_p?r]ˣ$z[Eӌj{|Keܶ۞e=1ԖFRKʒ?ffg?J[yf-YZ3mVǦ%^enL㏚uӫ ?*uRȜ] Y[7k6?L3k~EgHX,O-|Z8͛a_j4KD-A{Qcf⼸q.+,SZM ѣg"EE.qOVƮkyзJq5-aL̑ 7\]o9QXN3G TXbyڅdǗ:O.')Qs%ɥT?ܮm׉yc;C4(76yUw"l6_ΗJ\e^n~SG3t7K]|vc{9vS̘Wř׌ a.R_t3~,X]mGu̯ Nf('i8'_:窏WV&2+ 2<5@K]w sih3'0C+o:jt{gzo=(((ܿ 7<ꗨdǯeX0 $V;Os15sd-YǃHYL  8DX_rqF% k3>IfJ5}Dmb{Se2S_ꧼށS(SCXMdݩ;͔v7TXL g\up= ZEp+xJ dLƴ:|Qg(՝Tk5_TUgrǔƳ2#9kFFC|(?VCM|JXM2V?o:Nx㵻k#~}c@O ot%kK{[Ù2Ap%.0zjpq -Ug6e whfv-#m7?PPs%hMDԯ[V#V[[ٛh6]ޮZŠ#O/ )Nw0D/ꨌo*jD=gk}/+c֣P`zT`!Yh=Hk 5\!O(dBZ.XCE;d,B7CJb4*޲50 \/BHP'<$ ҧ6[{`eA> M[/Õϡ: yQ – #J5`W#6 ā}c_*'%K=F:tõ\`mivO3a0?^`/?Ǿ}~yu=P2_9z 5WøUO`ܪUO|L 33#VK*#V}F=ׅ¸U¸U?qVaܪ¸U ƭڀq~ VmU?q{yOBCu}.So hp2X߆Onޣog!}i=AET~*zPk~̀On}T) EB@fi?5͝g=#\OfcsAӽ|4-]p1Z!0)LTʚ-szdhuý멥C?'vf-D]V/=eEݙGM*\~rJ8m31O- 3.j:#JRhqM1C!2O!5v_mͨ4Z5`l{Yr&_t5*OkPTk&0tkzO;VQItfEp_Ͻ{h돔iS:܂'us?swֺJ"$=IDJ@lƚ5)R^->Urx`>ѓѴt;c,hTFp6@kTGO/WLI՚eԝ1#n3ʕKjgsdz๒9%O5>m$w4$$E5EmOt[xV$Kj 5'uv194.=6Th/=ƱWbꘋ JVn\θeSW)nŅ%mOwE[cuCqEOҬ]G4 mM^ <@mIRd4].՛~pzv^sO;>:<}Y[{R=[e7604[픣0},}QYutY}YU[XM Ӧ)zxq˛ͦ VNस+6[xuuVyOnXp62hs~~{SX{>`?h &=8Th|!TŊu`~)hzBݔbBw=NQL}~VLAB ݌kK;w^9XqHTeLd.8ȶf hцh9⼦8Ӎf{Kvuu;뎦٣xsyKs&Pc}?T^Kt7.6sc\wwڸ{IfavFsO[TpwJRJ\OigtGLj+N(cOhrz^;cd81dbf3:pʶvߋ6ikyՂ)|T"oզemfvǶi\ȸc[=ݵթ5)F9zǙ3.wVt!,Okc"Ǡ1k+}sKg9iՓYj~Ŕ>*p2+FURqDpL$=P^#\GiJΐ֘ڪfcm<^H8{ƫHO.;"4J;eޡTn$m&m,^ÿqٷyE̲p1 i䓍"rfS[SfTr4J>٘0r4s ~J_Z?M!G_O>9~5a;\f?ɗƱx-u{#[m߷m{${x~-ow]P;:unrTGlBϐ"=4gm#Ha|^![d5בHM' fGs$9]Ad#W = Ϥy]TYT-yx x`({<@(%xy<@9؇*՗_žyI23;~dnEqo9viw1|-n_^Z?$yme]oηG~W~鬸ɪdHY9NHNomݏV⭭*om[[⭭xkomu᭭[[=xkk3}GzHn2Do2|!SU5mg#^Go܏.z3 yįϓpDM#Ѱd l7H) {[*#! Sscd D~NC,ۿθ_gI~ف_g ǯ3߅_gLį3&񻌩]F-~1 ˨2/N-?1\+RbB &o Gx\ 6tN$u- q΃߇ψd@X(x\8q{b:0<]`?x | ӂGbIZ EA`"Ȃ`tb@u~HxfnhC2<xx{!&MH>ken@ |* bf#IeH^\gt"7Rp?p|v җ!͸ wN#ҿDkS` (`Us_>z#YnD~&iT38L)6;Ay nO\C1̾|7A<\}| p~PBn 1?C{{ųEy~q:bNAr9GA rd, [!~L_CDn9+Xp*x 5U4$0 q 8) rȞG8-Bα`9uCRª9/KyH&4yC~RRO؅@2-]π7!GۗR{aҏoבU\yb@X>e/!UXK:8sax!O)P]/_>"r8 sw| -pA}I'/#ϭOq6 R)R pXw?CcQ(uqw a Pz8kn {W>tE,D+ |xsۈ+/gA=xw1ꑥ{@]oJpà8?DIyjcw! Ⱥaa2z(g^`Lj#䜴_Q-u!??|Aܝ,אH~ >}Ji"Ԛ^C?"Lӊp؃>i> %8kѦxԾԪ!~O O1?DׇG 4ɥn%#7"&F1}k_H1HK?L/=5M>3E"n}IXC,?,8@AcbX 48[1b 87gOP xZ 0[HW,5OG%?Ȝ#UcV3DAnXg"a_"? d]`\}q, ̂so ,䞡!9qU#j/ z9p$Aҙœ dü ax,v@hŜ"%6N9t8~Zf'stKs(-ՃD'GUېN=Hw3l/tLD]@ Mp'q{gAܝGy5e^UW,6 } bNʢ۩zaa,Smci[@R@k\a]gW@& c1zt/w&%_jIY$DWC!dsX!~cestR)r|c9dzt^.^OK Pw 'Љ xk,, $qwV[ ,Qj3))]cAd֢edXoӞ"<|[!D ⱦA QN6MEr$(H)qh\$gi+M Is-KJ?w.PV碮G3=7Ey#[D@DT$! "QG"D!>(!9U_8sϺu:ud꿫zt_xSmqv:ޘnPn<@[xzh7cQoɀkz43zG{W<`bZd;ɥj F6@˒vݞ=?w8{X6){38']Ku-U.#ܑ4H>Nm>|UN4;߈e$a[x {T_kfjǑGQzg#Ԯ$<^]ՁY8k?__@ >zH MT#grqS=d6l| z rY=ġ&}sώvolaG[ o9Nl[UEr~p(Lr>aE[$ ]miCHfb10{wXO?;kOugu'BC* A~#cƼ寃S/'j|ҫxfpv8;%<H!L.G~ ش:/9qyn+`%ρI {H8VY}c[nseF=$|:‹`orU0a4Ñ_J_O'lGY{@HD!\Bї~G~"a q+;F$Pkr7s$m_| <'G} F^ O ƍ w 7'oى&|Hqu׎$WpG uUI)/5y$+G[:n b2VTA~g5'v&äÈKHP D^g L!i vp$IYe[#oMZ@gd^ۻDnfqfBZ5o8^e0DD8vEOw|'Q>XRIx2\@NDnƵ!9мh_XC)a_ȳv01pVKO ,^S!@^4lHR!w5ۓUGV7_u wHTXAs\s F}SO]H p>^뭐1aW6N1H= &q5ԖBT媱 ~o_m0;DZ{USAX+˴H3爗t0<^ ۳KTU\pǽ6o7 i輻U&|>pgݐUm9ڕ53׶9iJu;-uuҮM3;GρnPb&vkv!6eqU#ag*|}m،\Ǫj%&'u^fg}lXp؂uS,|띹cWkUaV: Zb- Mu?z2ݩ۝\ <cHkQҌvoΪZgsC4ù}aa~ixcwety]ݾ]lS?$ϋlLJ}J#])N&1]Kpcv)#[xaWj&-a57rv(leg:XJvllpW] +6;/"fk!1}c3[\yZ!s[UyVeV磙1<=sT"a-v}PSp"|rۉ jK_UgvOr2Aؒl<1 m|~Gmdڂ)䨙H.7~_\lhi8[SSS7ٽ|mR7wG:W&ktQ%Mզ!-O͆EuJ*/<:`Ԫlթ*eV ۰<ń%vrD^}A9;I4v75 ʎ֜+-(>>Y%4z0o4+U|nsHg;s/ 4ٞ|pq.RaT-O`U[+y6LɪH[DI2Gjn'u wK+pAX OkUi\ۘib뒿jO%yh+w_%|Q͈]6oZo[ kِl΂w%A8pt8Ig猖zWUS{/B`yasx:lTez ß_"#9YarՀ8gVIZwDgU2<6T.ٓ :oJlOkikw{ZRC,[~؜RmF{3 \jm[C[xWY[] ozĎaG 0sq8;+n ,GfL`6WyK]Fηam`Pª_xAVb2U.|S1y9f`Ovg!3뺏Uw> ;w!gcICya-d}ހ!Wմڻ;}^Er]a7W'ON xGC\aQBg7p̒nJʗC887ل;S9[=kfޗV5Ye{P^k\g `b_%> ٭5J'*OKWU ;,A{n-I }oAWdirv翓Dj`$xXkme*x?bZd=K 75ȱn\s2w5Tܝ?qHX0/Ԅg *}ȑY_#y Al~7,AKy|Yfٱvaqrd bӔ}swF\nUY>SXNGƙr4=TIv@x(Ѐ&W>V&,{Vc%nz g&=Ļ8s yw /ƻRb^౾a+wkO_9WcK軼sh}TҜ?qweLj`Vۏ +-CޣvR9.yk:oFWԶ>ʵ\w6gϦ]M PCޛKVa;5ծCg<kmTs]ޟ ? W-~h} C.c .'}֯}3>!4z051/%啴YzRKY.e :Hݍӽ=8c0nGvKؕSv C ->߽ۗ[j4o[Hpy;4\;*59\^R8δwr8rlx+Ok#iAi U.3O:>D#9܌ZBHx:bؖ o@ҙ\=%$sv [۽YޭHs0vް#<\aS{-r_S8{Eg1x7?^WVn=K/:>~] t9$J=S-H~E}i\E4\KWF8_%:v!r4ȃv5 RKu/xtg]jS!mMSF+EBӮ+3'֐T_e=HуY{ү So'<`kfwfjfOCÆZ1HZb\➅ISH|ڬO⣽`O su\;6ц>񭎶~PZ;KN;DBBݭIHf}S>(=0c-鵫I?@{Tn}c-྇b] §o:K>AT%l ϓ ˧(ZrB}H?\kjRxF$)=y$\Ҏ' M- !yAׂ^ep83-n6)ܷxNQ}_~WȾ{}>_[RIp9y֦-ٍ&PI ]O)A]2 Y~gs`F/ׂr)ozTYr='ycVn(U9X&@JVK UJۂ) SO25 {GcлI3F]nMhTJK/_Tl_]} /Erk?_!qĂokndZd/|Wm&"CP"#Eb 0T[)J9kѡ 絚^1_rU5nx $@{S~rI.r}k@|!jȽ_Wu\o@\b}B֡65K?ͨzw }vf ;[&/=HA`@_H9g{XںK}IlΒ6ϥMΨd lE`9\(q -Z\/ZnQ>c |΄/'{fisj/m&ɉf/_;M5WQ6M)!Z%ޑ{M]i'7%ڴP~h&'uї=;2#+ʌpnvqj ?=cۛ~΄7{gg&|B2y;NM2urjS2<1y|P47_ Qz[󪵫 ZxUYJ*|?J*<@J|*@J<*AJ*|BJ*=E_T_ b>)Xl+h%]EK W-Njq^DRqhdR;]t Eq3H'N9Z):n wFNvEX6-`~Fx]`/8 8gcp%\3~ p w#{0cD8΀p\G\=qp+1eˆIn~ YĔ)`a 1l X AmCh8N3)OXK j47p ߀{ykE?M@4 Y%57 Pid.GO]H&_V<+E'Sq*x-?ٟ3?Sڼx~z CO/_)S*iObG֟+b!Cl,e Gir\,Wyv3=(SUUPh5͌\UjR-t']f=_/kzޯǽWku*!xfQu\qZǕ?:6ʹ_X8Gq:=:T;iKo߾տCj^Hش֚$jܑ5ek7uܥu<ͪuZ<>=:X~Z|^j_yjuܳq~wNT~cտUbXPweﺚO=0]Ajoy|٢Z:^\xu5?:6=Zmby1G,y{g\3>3pfg~˙9D@,_6ZwVkqMx5ߘvݶ,}q?|-i^^lf׏eobwM/"e՚:?=J俭DuɈߖ$Wڏ$SFD~ퟄS~+:o@m~[퟉Yh=?w@~'wAh\ vG=yh { m*̈w'3ēbH8x_̜_̼[8,/Cq\-#`G^Al˱?x⇱:vG?-x:UuءU犝.^S K].UKե 5P o{VGmSd@ޕALײT}!^_A?(RT&)?'d^XWֱ_Y|I+Y;W3dPc2fRc3+3kJMȬάV32Ok3d>Vee3GՌܯ_s+<Gb']zj~Y~,1xq=#.)T~%L}kzV~s~yzv~{~=;3^>7<\WQп,-K !+ˆpujPaba^QT./n+ZڦkֿhZX@?YNl{)1߳jS&)7W/Fط͎jy_z_!7긶K+Z׾oۺ,ޱuYuYkrT~\gkxh񁭛b?u3D ztҖliWlili$(Δ|2enRӫ?ڧWM.ӷIߢ[4}K }K%Loҷ[-I4}K>$'BА>}© mo Nhb{ Ds7-}5Z~̏3mL'ڦvl+m+l+m+]l+V&V&V&γLTV&ηLLL̼M;2oBӎD_ێĥv$v$.-H\nۋbۋ¶1Զqm/*^^h^^X^8^x^^$^uɶm{7"f"~fۋͶqm/bm/N^]m{s[;^Wv{tuҧK/RtW}J~QM!/ %BPPPPPPPPE274(44424.4)4-tsЂ}U M͡m7B{CC }:@8NzFfppppp[ûo &|4|"EBD$iiiiTFFEFFFE&EEnY/4"*6!)9-3Fdodȡȗo#Ǣ"Fh>Z/(,:Z]]]]]]}15#;voG'b^,KIJ&VvXeolPlhldl\lRlZmbKc+bbkcbbcb;co>}6v,.x$NnayeuǷķw???.~<%X"(&''Z$$'$z$z%$$$'&&&&f$f%$'%$'V%&6$6%6''v%$%>J|8888Q故eٲe ʚ.+/T֭gYeˆ._6lz̲e-.[Vluٺe/m-Qlo}YmٱH$ctllll욬HV&&%&G&%'f27 y_rirErUrmrCrSrsr{rWrOr_oG'R^*J_ljj*7n>f2ČJǦ&ffMIOmLښڙړz?qpԉlnAIU]Ck"]dY9K+ҫkққ;M?/} }0E􉌗 elnQYu<)#+'3 3$3<3631353#s[f^fQfifEfUfmfC̖̮ۙO33G2egU$fͲNnٞa۲󲋲K+Ognn~4{8{$]xNJr\:W5εʕ:zz&iFܼܲܺӹs[rsro}6w,/NH/;{'o///?__h48$]xAJ BP,/4.()/t1B,/L-(*)/,*,),//u}|W}Ѿɾ9žuM|}Ov|{|{}}}}|'|}g.?o??_???˿п¿οiVlHd̀? ZzeaĆ[; =ÁcӁAW0=4`4ll,  +ビӃs ˂7_ 6_%x0x8x,x"x:x6 BfBCC]B=BB}CCePUhlhrhfh~hYhmhSГОбЉٰ+ a8 w   Õ9eo o 7_    Hj$#ؑ`$ii)GEEGEFF"c""S"3#"#+"k##F<y57r qXd+uGh0vvDâ i9ѕGnn6F_Xj,#ٱ`,kk+bbѱ i9eձcǞmm5^}gxL-p<o??)-^">$>"^9>6>)>->+>?42.)P|sxC|O|o|`pXd\WnFύ=?Sn>r;"2wLrݘ`O>Rn]o%`/rO'H"-D<26!5Q(NK\91>1%1+0,:>q-m}C#㉓3ILMf$I;LƓ-m]ddUrLrBrJrfr^rqrErmrc'%_J%_MKɣ2t߬I| ,p|Sf!L,~M@Awd uFtp5π hМ:`#pPmLhhQ-@gΆ'А ucnwCwH /LM-hlHڐaˆ-lزo$*^b8 &3f-]׀oȫ-Ը:;u6Άِ ՜VmVmjl .@Db A/a1. 4/A]%м%-Crƭ@g98ˡa9_ZBVjaVjaVX Va*Z5 k_ ZX_bHS'[ہUٖ4[[JkSНtȤk.nk@5 WFk@#cC mЖ9ہɂl'z@{<oXo@bOq+P?th/ly!酤-/lyՖ,1ʏQ~C>~ AC`7b, "IϑXN_N9X rc@W;N ZOT}2IT^= gz7BZbkP7{лOIrӪ! QT/o$=888 88سZjp:p&p?Mҕ: Ӡ1 Ӡ1Mk̀lh I@5sߧ"$q}ʞ[?G dPg{8X-5xpNa/8XTgk 7+T#$QQ߅仐|WsV2k4ΉPq$V'kcoܢމ~ăkUt5p"4kmhN8QwJ)ܬP;tx5*~SH6dSZ5ޢ A *Qwt}J?gwWАг^qLl.4,P+8)őV:$f=lA/2@ׂ=v}Cup5N>U;<f3 YXkocEFk2[] :sTd\ؘ]yXwc#*Jj,]Pa"DzF,ء!?]h78/ըF/sV%zDXZ99(ѷU X^3/ڗZFVb\eՠW ]kEZؘX*dk3\I< έTu@//P٥ ߌSOu֋w#ފlYV 8:[F֣G:t&LhSUUv o g-:CeY=vZoM7ET]Ue`κʫ'CLWᙢCWs].ԊVtd9,XT)Wvx䆬zX*АSYEhwݬ#$|$0rV-ZC豝xA_CC:>zՊX܉uV4!KaZ1耮BAzCܱ? 0+^I6 ׵_<| Xl>ܪP.(T"*vn_nNVj7+o$n *o> > ; 8 B> (fŨ(FE1* Q:c1èaT0g3F zQ=va;̰f3l aAqqqǵsEzZBCKhh -1%ƶBo;la $@ |Xɇ|XɇГ=Г=Г=ooooooooo%[V"o%[V""ף /h%c_>U_ u:xA/vLYt[guGZ_ e,B/ 1 1s+B=VͼWi0U$c_>"PC|(E>"iW(Dċ//h.h(RХ[酆Rh(o·Rh.RV J[AAAAA[TS^Oez=TS^Oez=TS^OÿrW_9+ÿr̶-rk\Z}-׾k_˵YLd1 ]@SP9T`W ]+!_ JWbΕUQU [ǾTVyVyVyVyVyVyVyVy&1$cǩN4SNܦ>AaA1I&UCݏߤ{(c<̓Fk=lγԳY繗>Hs>Ӟg<З={;=/xd5m|l}BeF/c߸(aA1EPa`mr3SYchi,f]ݬxOb#tBd-  iyks4[[yV+lUY]YSbkNk kߵ:ص:lqmZ\Yǭ\ZSGp=f f;s=a[nmu=mowt=kw;^G#\/7ڕv]zپiǺvѾݾ:Bh\esԅ@2 d Dyd)YM69C~6$!r g(4#g79;sv4ym}ΫhrvvWhr@[&چroݕm]hs!glܻhw@[6mChr>B[1چyj?Kˑ@ba|gtd|#sTGSc:"BGK:"_鈜ZG:"ꈜ^G:"?:9|"eND܉DěDěDěDY+t'2fNdNd͝x3x[8f9񺝈x=NDp"5xm'"'"^OGDKUDMJfxHHG$#uDruD:"I<:"ꈴr֊<:2mtdȴӑ9_G:"tD:t "1DR3"]tD.#rH7:"\#R#KGHGXGH:"%:"tD2@G2:2:2td:#"ȥj<*qE93;z8KaMX:k2Y6s3L6wF^G*~G[~O$^< O1i*?{Ia?҄TJ2" X E33H 6%ټ#H|xRB)!_fVxI:*R`Jf5_{:~/_7AGݱbꎕ@zOc2%q1ғMoQeh~l&އT+߯$?h /\q҂]|>_E|1_—2Rƅ̉I?.3Y&3R?/𞼘%?ʯp>_|$ᷮ ƻI=x9^ ry/".ޛ&)/KRy?ޏ4&W֭rnrtU$JAr~`~5¯ywib DZ{JżXZH%DZKCjJC~]ZDZ/K~oCN~_,JLGZ'JokH/eWg avWfsQ ?%] MMi:mF3hsI[,MC *I-j>!YDhhMRYQ~).eM1^NW2zLC5t(Veq-ӑZ!J:Vzfz Mocmt,GcH':NЩtN3L~IOS]FXUQnfV6ƲqlC0GOƧ13q8i261NgGG!e\"E&"M4颙EnDn!_+GV8>!1"!9Ggf'713yo"VԊYq+JXmvV޺`u.ZݬVb*zZ"o .Z֕Vu5غb]c Y#rzkuUahUEvc_jK~v{}=.ٗWWeU`j{}=ԾfUuv}=ҾPա=JV7{}od}XmO'ړ{Sit{=ӾӞe϶syOǼy{?~{i﷾~W5a0J4z~EәlG}>]gzL}>ӃCgzfyeٸԭߥ n5**}C4fFv}}.{Kg,yֻe6 2wd~gH ,bՉ0ےhH|źgbY[gH}6 Gq, mV_/Y%wX~37d|2yWX\f1YF,_j2NI;iG_dVVhueew*!)nI%kR*pRwMQZ^z8))+ړ8+`B[t‰<+3TG|#hYjk5њdXYlk5ךgeͷX *kZkc8Wluzoc]jJ=m'8o̽ lOd@%U"ҟ|JSȷX72`=4VYl D+5nv-Nְud̾!4R\))픴4NJzJ<3R2٭q %+#n3Ŕ'Imx yR/,'"",,&&j0FFHPgKyF[67.qQ@B/mo3ҋaFglL4n5ne8^-stXA+e&0xx>fmCk:EVIG_GvYLY}NZbfȨrq- a9¼\/ϗ&E$y~ty:$ry&!0l;w%#Od<)>5GAd6DPmڸF!6z(BQj[^^OCJcȞI53W3_ο2thWkFVPMALҎ~0FmmM<+gbIG"ƹF+5:Ijt%Fo7I%F IW<**Ruc“ÓZXmitXb z/xxn *s>xJ֥=:~~s nr)))$e9ESUCQκ^rNX7Sf- Ar\?f 36ݦ4L!f޼`v4;eV77[1RTf5ҭ}MuY5ffgc0%o!1=B4!ixii*IBRI I*% E$IRI=ӽOFzu3g眳Zߵ>kWi~5?ݯkNyX?"Q?ܟOgs Q{jBPߨ[uDUquFU"`OX5jH@VRjZĩC{R'+q>phv!Ũb`OӘ 6m ) c1X`,1^3VkVcg0'sG;3{'q,f2M͖fs!=͛`3STdN5gyBs\m371dJo4aEY1VT+ݪm5YvV+e!VkYk5zښcͷGd6X#+Z{C1u;:.cUv]ΰ;]v{=f{=˞k/د+F{m؇9G8sBNSIsj9NKtnv8lg3)p;ETg3ۙ,t:˝:gq;#)kQnd7Mwk fn+t{,wyn;Nwv2Mwnww{![*f ӶhAմZv@+i'dhCǑҮhGG{ _Бfiwt=p퉮F\O{ǒ e2Mތ/z~IFz ؆[ћ@znY` /~tށ[ w6:Y.N1ލA4̻Aa; d>ceKK0 d%U.l:wQȡqa>0ȣa,7aP@t" $<@|Ot &t&(OQ:xOc*},L :3sxL{~>_~=k|F J|A zwG{|M=o1-=C$p г8Jρy3?$ ON8C8K &SyjGuRTWC*&e@YT)(^\ZJEXb@㕢 * RhiKÊJ2*U4I%rʧ*D˫4EiH+*&hTReiJU9ZUi*VS>4C} h p\(_" +xut,1sOi`h޿h\<յxц itYW 20؆mųU#XųR{VN_wn7S仫3b8"GUk!8:ꦺHi'RzT2&//C DYFILdEY^J2UVUdU&ȕ;Ƚ"°#,7v3D{+݅QDLQE`` {{C"!"RGD8Rt(#H~$z"7Ljueqܷ$r.Z[hx)JJ́m]YSɺNtE]E5u-}躺膺n3tV_;κNwy#\o7P7-t7{uo}[uVxUwT]Y?<4R_[YsoUuuuqZQ"U]+ "[~% yl'3W4Ҹ|`#n/[Y(8DEε^.șU]kJ8[Knj%R+_~ξrXF^8>-Y9T%5dO (gw*/# xQ$͛-扅bX.V$oL)cf-Iܪ*MLsBBKBC[sXx endstream endobj 467 0 obj [ 0[ 658] 3[ 220 623 611 563 662 575 537] 12[ 324 307] 15[ 537 815 681 653 568] 21[ 621 496 593 648] 26[ 921] 131[ 488 547 441 555 488 303 494 552 278 266 524 271 832 558 531 556 547 414 430 338 552 504 774 483 504] 481[ 205 264 264 205] 486[ 332] 495[ 221] 498[ 375 375] 514[ 500] 523[ 382 382] 820[ 371] 882[ 554 554 554 554 554 554] 889[ 554 554 554] 945[ 554] ] endobj 468 0 obj [ 220 0 0 0 0 0 0 0 382 382 0 0 205 332 205 0 554 554 554 554 554 554 0 554 554 554 264 264 0 0 0 0 0 623 611 563 662 575 537 0 0 324 307 0 537 815 681 653 568 0 621 496 593 0 0 921 0 0 0 0 0 0 0 371 0 488 547 441 555 488 303 494 552 278 266 524 271 832 558 531 556 547 414 430 338 552 504 774 483 504] endobj 469 0 obj [ 278 0 0 0 0 0 0 0 0 0 0 0 0 323 219 281 500 500 500 500 500 500 500 500 500 500 219 0 0 0 0 0 0 667 563 708 750 0 469 0 729 250 0 0 490 781 0 823 510 0 604 458 0 0 0 0 0 0 0 0 0 0 0 0 0 427 500 438 510 479 250 427 500 219 0 479 219 771 500 552 500 500 396 385 333 500 438 0 0 438 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 740] endobj 470 0 obj <> stream x{ |Tյ13sΜye2L$@&`$#y I DބD ZDʧVE+DED[)ko]6~_kvfrK'}SJK)ǬY; N,vت%X ڏuޜqw>0t!ֹs!>54ްH%@n[)qX ݰpMΣ\9{nWmy.ϝSWCX`\x?`_˳ ]`β6XKfqܷfbufڢՍ| <͹sfҩ%WAsy9Ͻ{EԏerGlh08_)}N Pyxcƻ5SUxUSzIt 2?_3%p%=af`G-S:_C C8]_= o"CK랮:PDʆiAa$rP sQ"M41tZط_)@Q#AA#H *(hs Zh; +1  & )/)FLO p794D/`@f3H f ā8Ȃ! !xD`0<1 S0 bpaD B(BW"^#8!1W!TF!*(},шCE,G+qcq,\8= ߅Zkca"LA"NJps0!V*xLGwjbo4C- kz{ 7و0'&A,ij0"#<Xx,;̅E`1|@#BX{2Űq @l?RX, ?* Fj#&ĵM>aǰ 4 fěV Ђx l ܁،{~xlZq܉x;!ށ*"nm[nV؎x'{O]3ĭq܋x7I!w! ~G{ O]Po+ğn_(x?< AAWq7싽+@{`y@;^xq<{C<) >cAxƞ'C, C| (GEģ[gDix^B</#>p x%vë/ !@| ^? D|^3bUo ^/l xB|F#b; Ÿ<+kq8 # oC;|xq? "{ G%b| ׈7b,()Dc{o ~1 ~AHQ0_k!*ċo:t bcD@xje3ݢW${x*5rjPJM8? 9FMq,Kۆ/bǗZA<> =z|,g4 EcXUt|i(_ZЪuHųJዶ8Rڳ]n|]:Aq٪@* ɐ/U^(_*UU }T`0C78SwI/Zj )RX/JiZ?(>*b4}|itz.:4C5WOWCRs/5Wkj4MDQ{4]KS/ \^T$Sih;\^:p}$pW¯zlٓ d 몱4/L&_*v%t2_Ft=25:8 R Hm2Q~Y|pj jAߓ/4)|i9VKf3嫛! _.Ie#_Z0RDpkt|F/cX,Φ_("_"(_BOФt:^uȗҨu^TWՊ|U.IFApOe҃֯ :^ z#%MFp/QLȗnNo{*ʗ7Qȗ7]Cv%t% ȗL/{J:A'U:% Aj5B2Q~$8K2dKF3X˗^|)_:KT2 Ns\Ui]3dlނn`` *Q4:Quj2 )))ȗ'_b$2KVVh$䞡 DZFMDQ׉^T>*xn GJ]7= w{;9{nF(#VI$L?|u[8z% lfJ|%e2$KjI6 _t7n G]7d^NH5V&%I1[f(^>/f.F`ľJJ7v㲵zgG/UZ2Vh=VjV HKD%} p@\=]n V|v.ˢ /o7n 鍎.I^/0#9 ޣH2Xz>r8,fÆ~wI2 ÇcL>0 5c8 wr vѣ3ɕlcd!˙tZ3|`1bke6H)]27B7)T.ÐOJfNAJ{GeAJJJlM4uIb7w9%-%cJqXZzZ3ٖLTTTjf.I5KxY +|6 CzfO7cكH#2ed82HnS7]C&OLF=K@ WtfA G/Y>>Pedey=z7+L?Ȍ3 9R-9]vUz~(Kf@`{&Vls /2 r9}K<6WKAI XCIA(Kv`p0בsmW`̸>*?$]k$Wn )I6[6{#J, H?AޣҲcƎLxSV^WU&oeT8X:tK@/(0*XŰUl v)L:X{{?og(,7,28;ǩ4ǝr&;6,$h:F9!0DJ:N[=$q>¦Kz# N#wSsuM,r_I)x/sX"@BWE%آ'y"(}J|%stC^zaƽ|$Q2Lyو h CG^FHhS-f|>1_~;r{G.J"j彞yP]6y>r{jz_} dǸS(e4D8\'xzZ|RlX-jqFdELّXcsN,i޶4{"K: RP$?ՇKc}e:K|O˦9>+T(*WCZZKG{/(2J!-N%*NyR[ZOHŤ:0_]3n]%,(CG0;xf{"0ʇU ()y xUO|!Bj},Kҥρf}-->OyKmK]{l,G쭨hi,ŷNVC۫#R\2ZIbT}v[@C+$f-qAaJ׃DMv"OU4?+564m9]$^/M!7uV=0˹BlZȥ'֩ɺKO-fh2\6wDs#*Ts9]6z=[p^E_uYTL%MU\;SeKSʤK^$y/IR(N apO1'O2侏HG{>bGs|x(+!G0'$ OHO0AA >  0=poVo۞mOoc71t~{O8bSL2Ϯc>pohri:Nl"m)7\lΕ6r[]Klv%v%m%ϷЇya01g9gƥ|SVLw`ڄ6L͘6bڀi=&LaL{fhwh[1aiܛ0݆Jވix߄)iv= Sf=SU}w-tJL|kp5*AjZUVo!bVq 1#8 ]L=^1m`À1CF Q2 (huz!Rk Sa8Bf 5n(и'ID)"fɣ" mR$]QM^Vcinmg"L^NFk?x3qNWL4TG4%@H6/+$7$QZ@Q+W,^r+n>T,/Ƨ0ԞHz1=~؎iy~.O?a<3y60߰d'߇L#"$~i}w\X<+e@#<ϙY5w>l]gV`CVokn^ה@u<\WXGCz.V7e!19Yl#=*gPQM|iyÆ663ɓEd;fѭ5yseX<؂EdV}{F׳C{]!-Oi4)KfK$)dGߣH'H=Sdl+0lz'OF&YZugQ=ZΡ =,X^~<(- ˱%o7 Ʉa?!=vqF"`,(`qnk'A“;Do(űOgޓ`|(I#le85Mҥ,knU µl#X+,^%ZMGпtY2Ifh. Q1&Ij9oh\xѓͷX|stQgO(2l>=WwI#pP[22LKK}A{8MT9!CI ꕆ5I<8ϫ8 y+m,!&m /g _JGj15y|{%S~q/~}m5LytͳE7~)O}A&-p2JCRs`2O`&#'˙Zumv.WjNjYV*U6J$ZKpqDѻf\\jv Am N&Mr!_SQSCtTSŪ3lʳ'dᶍ m\'}wݻuMԱkdvjV>}oo橹eճ'yE-׎3ΰ P X m kV0ׁEmc Pp!&x^:"STN5!)h|&o^0g&l^fB) Arr ]OhX֚j0~ꉽU@ ,hjl,%arcsp:& O3#E$2بِ:Iit$ƄsV wp:qV v{[~M7f+Ec|/'{{>#7"W_gĪ7ϞNÙG}?ęBRȡ`X²˘90#l5M-s?B:%A1RC?$z} t}MMt?o< [UR枚2=5۳ܵܣru5lzJRSUlv&$fnK$촆UpnDd^``xD$꧐2ru\,\E<\CㄛbߞO}#端fևk~au-hnY<\_lj~tSiK횵uuk!#d"t̩,r~ ]>ds#p:.M*]ke. '[be2Ik!,9MWH yZz--\=Q3Φgb jn~̙v,cuBFu]/4ίW&&ٱa[ZwYnacrD/bXGi:)Ko?3&8tLyr]Θ`<üѣ1k)_ɇoǡ_klP3Wq*n,!c3J^ Nja;=j~ARqQQDHYrG"hIR.RcEH0Uw0KO|4r *f7:Hp*qN, kЯ3k4Dh Q#3LLm Fd-xJ. y5fn_ͪ>@Nn"|ERCm җvR3b,)NVI&rS,fſ~=^|dO|+Z5Xru3 =Ѳ‘ UkТmPK+yH$lKVAlmGH+ 2f^.7ʼG "*"]"xxQrG/~28g~Wjg٬_ .Ƕf{g"=V!L@3[i 8άY~ū-`Kn M$bJ p_:-5ښǎ]d`ʌiM6pw1yrALB%ZJ3@\} XS׶𙒐2Ȕ2Y&@rhH0CeZgj:^:hkGֶn{>{}gZ{50xv2 PvJBg)uBD^Acҳw{PIV@h?ij\ޟ?ZjWeUC]5`?/Χޛ(W6Շ`M=0!8{ Sj0mjʔz:T~$5[i|XXeR'^\V6}c9f/B.C><'ʍ>8(,~#HP b*,ĠHv:R/JmrX୍JJ`6CRFϓQ!j0M&.{~L^I"Ž Aq!hGb5##QHoii=qǶ|+=KwD w4#EFA1g] ` "hjk![2HI `eT/ E'!VD)qZ]DZL.IdRSb7۵ަJas~oO uc/hz6I舉$ek<> ?VQ`1J^ N3T!JU.+ķũz7X BO BC"vˈ ڒ6%QIav=Ƅm%'ϧDV*n&RO+xL24%hPh"dЙJ%η#4|"ξO (rv / Hgl\[4μvUu,ZWSTX[9-5&O9Zrr+ͽQQ 4Ч.a]C: ;&d fC3 *X!>QRj_ɐm#[UF.r)zy.0iO{W *[<)Wr"!\Ƀ2XNrV;.VhͿ mW`CF [uhVZL8 /0!蚀@ᴀP (Z@PHa P9,$#Z*tK~""bV|"HC1q2ϩ`O;Y3ˆJeoy7.z7M~@(p1JN ?hM 슣̡xeÉUz9I"!B d2jLIddAψ2 R(;!1lD 4H %GKIZgFtOʍhDʜJp.S%e !BAo?iQcMʜ5OݴsS]+P;z,P y;9ZD+X`b!˃:t= $E<@,8&*ND'>(MS]~[ ʹ֙'m3>=" zc">UCXTVBU$OiI|Fi_,oc՟>~{-v*=2~O{y MRf7P++0 -(:TРNR>U5CER2!vCoHTD18bblD2HQܣIJz2l͐"eLgJf*%*Sab@ Ha x PeQ;1{LNkP{t  h7 煼>O1&UQIH~^Uo]4dD.ZHכhi!KIE{~ZFmW#6ÈBb!`=iR`BiV3 $[ fJ8 )1Z0щ!SOyND'o-杗/[n4$Dې! F@gPt$$Aum) r(0#3"&撻PWK4Z+Ă\DgS;01bL2Ż_zSznGz VC.6O4Lg@:0P|zPćs!I"DBď=9?Q#la)#L` "'Us^bNaa1'G: g|ft<,hc}LL$ڹŔ6[nގᯬ9rz_&g>wwRGw=m Έjͫ]]D~ƻwo[d3deRzhw#4cZODJ?w(2 ./)T2ST"8' J <}UwȿBb.[;ѷ2cQRz %AC(bTL޳P΂r$7((G(zs(zC׋`#4PFA0,QE$BzrF1(g~6YPc\"< P΂2zJ#S},#i(PJ \0< 6 j.F43ވkLƄ_5PF\mCe2?PYӁ2b,(g`3"*{ѷ0jпjv '~@W@w}0M3~8/`!!!ED-p]bB~y;%ԧKD+HgaL1/D0s0, pb `x y a0$afpヅZXE9a F} >XJ@.h'%~|I2ebXhư `Y~;ms1<Ga2 bGs_~>Xkn"Zn3[hhvZkli:wsf9 muY]J.86fc1ur.Y\+Ԛvbͬipf|Qs^ul⠳Z9*n3yVZ]qFc3;9 SޣׅJNsC]sZ{DZS&-Vstk.b]*qAk͋vr8MT]Ǚw P bl^`ֈ ao \qunwCj||SSS\ouz[|zל&\Ms qpIfF؉fx" Cʀ& w;aIXIOЇ kX=XV,Q =5Np^Hnx߀k 4KtDJ"6}o~S0s5a^\ğb|Dgz|s5MŠxfWZ<ʊ[U$3y|׿ =-#J#ox$ldh_֨ub#Z`fcDASp&DyFc6AcUhúG-j_4aݘ~-xu>{_[X|sROqЧaJRoq>=I`Ϊ}\ HͿ6]XfX0}0]}f_~IUc[0۷x|=" F-h0 h0o ?G}sW/K҅Dpb׈*7oQMٱbiVkLo]G݀˺ob e˗_A~o'O^u;UoxzeַIߗ1,ڰPX~t:]@}<"ܖkSlɛ0|ypY4yWTais4 Q֫~n>n_H1}ډ$Vc^ D*9߾ _mtc-A+7k̝͇zG(w㾚93 сq63֝qqEn70sˤC`*3UvE!^M>|ZmS˅q+VD]mjBۦEN o(J$C)eԖhcj2bd͛_.-{{ᤨMϦ՜t~ݒjOֶQ3RVyb]m*ߨ h[ՅkÄt#Q@j5AH͖:=qnB Ub|{u.F;9@678J][7^cG3،)1)z1CR$]V31E)?;eN u-}5J\c[:YңʠWLNw"O>G"U@9[Tz JOyj Qζ~,YVA;{wƜ[/ScR?v'?+? 6WT\i1rje#3 ۞!~'nge*]} wp97إ=H~ok}SiOGjpS7=d֡ Zgj{?̕5W4/#˅_}9O(1Qi#=ד\mvܲKiu.Zmx|h(EsM]dSGS?g(Q'|\Fd99glcMwں)T٬:b2JNЎ%k*RRfjv"t9)|t юqr p6ggC[qS.'&i'$d0 e3\l"Z0@Gf۾ :V UTI*CJ2쪃vu Yvnv՚vK޹ $#u5{gKn:-87ȴ/!>Oy{Ǥf_bZ[ [yi'T,:8dCq秤iU!7f߯} ?f{0U&q]]V[G=RyqbQEzoI;;MK[+{#cԃe\h8Ή}[nE#.Z5K\*~ _^Jj7rg%c%ژmtٝ*izX!-p.p;)>4MHJIi4h䠢Ür+SȦ׎O2 .%%X|dÍMYҌ" 14?N7edfOa3|pq]_ʖeel8|.?'?+4GS1?`k*˜Uʖ&lc)??-1fdgeC;0FCLe0QVWlZ$}D8` K }4gWM&v+BQVA@.6fcF6'58- 2lIؔ_PJ2 q"S2 >? [ \)٦8֔-A|" X&t־w䧋|vUᆕQ$!oay8Ug=@:U ^Yp'0W :kFȻMEgI$,zWkѶ>, ˴׶h[ҹ+d"1*XАawǤZMP 9$r K:m kX%%kC,P&@+k{P`ws5#_~g;ŏ\tb0O̽]9ii<{C=a$o{5btҠ_5s^A/31bv^r^Wuw\8aᔴG;m /MO:q뇶H]LD`] ޖj;b' hŢ^olڿ֐ۛݛjgߒ_>la ~lTKQ]_5}gôDBbZr7OT<7o*&uƝY?xѤW% W9 SZ7}6Ql3ӪJX_>CMk.JbY=x{\vWqLHv;aS1BFbl[,~'G ?R0s9ٗ?]gI|YxwK=.m񄗖뎔4t:EԿo\K.KK}#BqicgF/[ֱo}`py)|#l=>[~b JFL$QO@r)_-O|NjmcHud~z3W6_ˮ9S[Q|hpgZ֯;FjWO?hY}s~۽ˆqvY\sn˽גcW<>vRS+3kyչ.}dŚOn)Lt7P endstream endobj 471 0 obj <> stream x]j >av]nBC>@ThsWǐT~ LRVJ+Gw;픖qh T­CoPn$yN]I-etHtt t8]b1e㌧HY/4|0a래aaBmf4/b8 endstream endobj 472 0 obj <> stream x `E;!LI$rdrGN@Lp%@P@DAe2L@4zBEDHf޷ޟ"~WUaPB/>TĜQ0ɷ&trBBsVB>yjܡ= 9UNH NTМt> >a˄-(t줲BB";uTkTmʚqjqEBAjkHz|Ӹ+?Z8ʓɄTVUQV~ɮ(?{T!C}ۨj{eƉc>D} M*&wH_wM2lw]S];y}y}t $8X{寿Z6ڻD =ڙغmz.:"pB:JUٺęt]F6R~H%24xRAr]JdU%]ND^ND\HDtzɨKJT-DrYI Yك fb%-RBzge-ePS`O0 4P `t@<[sq]Jq lp#)g}?w痸U?ŝM$ߨmD_xv%͹n]O4wGݴMc:-6 }@un WQ: Ti10 u+JW{mcЁ_3`!XM>^sW/8=ϝPw_h$(C+{Noscs?ykŭ+aunL_D &1}Chx`r3Ł et[Vn[Vn[VOx.ibܔV璃?瑯uߑ蛶k van7c+"Mջn[Vn$Zd "V&pB:~2&3,i MSK RcXz؀aaaa65Q syyyURI$ĒTRʔJsHϣ(m(J7Jle~*Eio<KazеƹR5 iT)SP7CM|_,YZ*IR.Cb:)RT%&HI]RTCGሟ]ډ^!>iT'-{KHJKer!ai􈴒h% n%w7בg*;geIѡ!Z#zb FOE_GI $A$vB\o(r?YHŤ,!R,' YIVGj%u_q8fJ$?>BzmDoܺh]#/=jdɈŶ‚ܡC8 VfFzZ5_>ܫg.q"ot1y{ zVV%R=ԮdgDZmK2ʮ(u1vsr#8#H#܇5gZs#g0RlS`ū OlDD sfpUNK͙Uu(hHWbIkwӎbΓ].GfslJIWʲkZ,xVg\FSQn)/+2T'g-;Y2f|&Wc- ɿvjWG,*o9͍9eM,k0auC ѾV%V2y6m&cBSlJٞbO@3Wvz%uUfgjU}s\,Dv9t*eu Bݚc-s5keά+deYlM$u9!t'ŬttJTf^ZYiFح_VQzbw:E(WTBn:ZZԙmR\z ,|X` ݥlMcP"UG0wC9ؐ#ӳ.Q?RNHLȸV'~[5~4P'sfEuPv=% qug%GEb,֋f;5,b Ɛ5boN%'oMm()aum٥t PѧvefM:%lqH̸}bMԀ%|f*`ɪ+ktSWodVaP^g) Uo:]ʗМ´XL0i0 0 0O|(œ0DŽ9*a=aa0o 0o0 09(L00/>a^Ea^f0{iQ-.av CzaYa M<#af0O I<)a 0yL¬f0 J<" a!a L<(L0Y$Baf0 3_y^af 3KLa 3U s0%$a& 3A;/L0ㄩBra 3F2aJ-(aF S"a s0Ä)P|af0C,@a%L0XI0I0=!L0݅I&Ant&^. ̤'RD>4[a]|Rj8;|s95S\|1 j,v5J:R]MLi<;5VER@5Q,)`Bɣ؞tpI`rZ4Oi*? 7,MNrj]RjqqEqEc%ŗJF7\~r4,(tW7f(JgӚl?VgSk6͊,ʈK/JK-6Jw9YMDi#!m~A^UJo3 -"Q;㩁 uuEKV.W@pe.?r.p.|[.|k._q\r.q9唣]/H \> |\C.p98c\r9 y{\7u.qy!.4sy\pe.{ĥ yn..qyv.۸l -\沙S\6q#\䲁z.Opy:.qYe \岊J.pYa.qYe\%\A!,Ⲑ\p|.2\.se6Y\fre:{L2.rprI\&rN.TqǥKr.cRƥh.Re\E; RĥK|.y\r 2`.pel.dq%KT.V.)\q˥\~%K/GHO.=$q% Iҍgvϥ 8?t% ̥×Dsv..Dp1;| \s s2 q ҎK`.A\pŗo.^\GOC8c^G>x o-&x^C h`]KE &.4n;sYl }lO) lO `=x<ց@Z֣:| X JX`Xj <LhM!R|pJ`9<(>(%H^#Hgj` خYP!ƛ˼{wxylꗖ%H>P4j]9v];]d,`ּv";)>VOz*}oe>Hra6aCXZq}.V]RS;yJ픘ZS;ermdo]MBk23yɐk`ji2ۚlkc }}Kr! ).m*~\߃ <| ΁o+%33p-$|>??8xax^W!p4WM<v]`'hP`xlV S`z8Xk< V< 2<b,x }tT9Lit2wjp& N0TqTr0eHPFb`wa|rP0 @*ɠ z$$ t )m_+KډrOgM'&#frh", syFܐԡė׷9Ng% F}/gsCW'+T:KV%f_]VWC:)-|Tk0b0T wZBFCd<~xL&St2$]d^2Oa9|2 뾏5G.PĝL9uw"+#[]+GޘY}l$[V39gNvzoTr#8UJ#0N ԗhKc֨ UJJRx*C梅mQbk9F-XV TxulSov3h8HIvvv??ȳcGT\o_mTywR#ic"%[+9HW[0"~5&yO(S[r|J΢>F!/GΓ }Պ;Sz*p$z+׹-i_gIc[6,WB\1JRg)=4]5FwĨN"u=5%rQ ^Wd%)i"~'n2i_r&?,:<'ZM*s1dM;ͣr;;VtI8rtOr|-ݺR/ɢD'&$u"Y,I %;tT^e[J`N*ܽ VKk*9#y}}ÃաWΨC\}B"(5qىyھNtkbq5%hkUzZ'Q=%fFoz$z2ijRj*&(?)hH^s 4$>1] [u&ɲm'Kb0iuh޶Ljė'Hz}H^R'S-o2bAgA0keYObB?O MqnS鮊Fgw"OFG߱c:f~a*pCաΗ\i:u9] =;ݍy:Fz7x>Wsa0Pz)#90b:Ej,f⃑e%=ӏow~ z@ұzpɓztA~gu<GG(S)#"rfUX/hMq{߹a%iݨLtXjRk:ԎIz]3PiOK3.ĵ?nMVz/p#BmoJm-R:ts*g?øst)뵒nzj )ZKR(Z2^?vLj~Ԣﴭlۃ(Is}+_Taf4Gx#:lGt8u[Fs(_A4ϯn``=\ |D%u퀵#6VZ/6iQx4oP{^/K5hm~ O]~dxWZ;Hu*wØ;+j鄅&5_8㎰ 4L/;pHֶEvBĢWأ\.7tfѨ1ѧ Hpq3y;"#kƩZz5^r(i#l@ a=t\YSgtR` n$WP*:/'-ߣ'Muzc\hM/}l:Ad5rnQ:0赍NJSQ%eILIL4'OOdC` UbWtpOJ zOJV}}TjT^@(wzAʹKY~6')O50OheWUont}` KZzh4F_OTH)1VD6%b)Ǘ&Dܜ&`(3-r,[z%kg{`fc_U{rϦx2SL7oXQwO#౒cdzk>k3FSzʽ}^\D\:d`rO!F.5SzY=,ꞡO FG] i x܆leS\|-nFܓ=xHMGV&(fLP}Wyב]=00}7ûuz&oĶpaKm9jf.w̗d]irr؊;&Q!^ $$PO773Um6C OS =9'g z+E0 }.I)х:M|F̟eyJEhkJ8 ;87z_ K.`wL5֡3$Udžf8p[=ԛD[=|;SGa iJ%Qٶ15͵ɲy _KQCg-W}9{ >һtܙ{Mm1xk,wg1#Eao4[RNn NCE?K!0rXҠ>ݺ+bI'&)4HlЫe:IuЅCBma䜽9[ޣujjIk:x*upP1Se'ᇕ"Qw['tst:qtMrutܴRͮ~z:(d#f 5N%R)`Ka+o2ECp"~pq'`GUcC^ri(zo]tRI=k$+*]Z/Ʉ MC0bU:o#Jo2̆\Izxc5zxT//-{ʒ}~njA'f|6}mg7ůtD'fΚB[ U‹3mns [e3~π2 {qn7ɲC*fc dcxvIV|"A=}JmTK7: 9asY|)ZC*1 H]z/jǷ s 9М`bcg"V!mi.oTZ6//ncD$gg@RxFD77oQ3@;thg hX}~j{Iٽޥcc39&ZE=SOVfW/gF14wR-"oWq>a]<6la^vાnO<k?m}]aI E6.Z& tF> V.C杫/pDF)ey޸j}#_ɜ=#l3XGP$ٵϤnn:D:g(Ȟ4c}qE@>'Fz9IƋW#[sO\7j aDy@uTyBI[%oX6[k{j,ꗺ0;}_/].O{.'0dsҺ;v2 ? =l(B VAb7 P*̈]=y}|)zRּ]]GXuw:&I[St=mt/Y=ql=ڝXeogwCx@')+Z=cZA aN, rp:RLMMGq?B6)(OSę m9fL/&kgAO .ldm5|E)6e#FKLҸߜ9 PX[t<@g-Z\Юܕ Ukv[bM kvX`0ڱaQiT#$Ͱgפl#jqȬ^7oGEǦQRj/^6-S:3xB<&1X؝jLĒR(_#/D$$&ڬhWnu9Tx &WɈ!2V ua7p˹)ʼn03&׹kjvݻX70s'h_I2}JG*<TpOP% 0P IؙVO X0 ZHMu< 08Ĝ<[`p#}}40liClZk=LG]>mnL>A BrDAh'$u߂0l"D ohQO8ZQEuV˫&IFζ-ZMv+|>LwR!߃u+Eǀ~uH"70DX!5I| %! 5'Gweٺ_Lҁ1eoO_S𺔲vQXՍU`huy_T̉dPo3-$d7CF"+J 9kmnR[-[ (HHu7rL~k4[2jNHehTǞ b/='єJxR2*SˆW zf. sb ddɍ& duZbA$օ”iL=O${͓yES&h^^Do75Oٽg,PպGcpKV ,~iiA8?aAquO#~Bw 9Bfqf%'q[gl|gAHӉa )v1Q4 V-ZydGb"4YQDwBQZsSg<%@:߻?ER93~9a7 ZdehE,%hEЊK!1_SK'IjC+Lh+(JpkYJ6j~`r?1Õ_ooRk<׺X?iLj1K_Z?=JlH-)X tutؼH"D̰y,=WOR juW5:6g/5Wyǣfc :bHH3]&$ZsEgH$b!鳲2J^98Y!\Z'>+YbzFaZlBxL~voKV/ӥ͝V1ӲgY홅S&C~ʊ h,LRj{̖k': SzZM`Y3#wdd*T R(DqPTG:-K6pc-jU^?m;gslb $v%qXp\e70A1D癇Zf~ì0$59L+kQ&PRu&`J07[ 7|#rmW(*nT6zo_`0ez4[8Cp.9٘3=g%nKm,3=?KȣPwQWzp6s Kg9R,Wʭ")qzjST*G:RG)* l2̓7n!QHmtGa>PWsWk4Zj]Kw\ۂMV?oITś|*@ |U~mV/+][owdZ>S7 b.VJ "ڤjHuCRzNZ]8cgQ4%,#Hn:;rPvkS JcN;P$ۓ!2qk2ׇYAnDb$N^~Щh '"B7d DCQ P"髧VUZ~! &;mjB'uԄWlkFf_x֎|r]OVM!;$`YB%B a?ŏSTbiW`K @KbɎ!֭>=}+FYjq$=,Q^ƈ=bqy&61#q5롊{v;&ůsrVLLo|1K{͛ŅӂfI!}n>~a)caHYq8n~H$S3M|Uu2)z[ N921ʯ+賜'*[vtfܻVRZ0o(}XöΪQS^ۣ#'IInz)&b4AaAd27<6"[\"aT5uΊK]02 &W?ڛXb_T"|3GtA!أBuA(?v;AKZ-g|6ijǽƜ,0ul6cDK*Rk %vڎ5E jd!\o/_Z0ALM YMCѵd!ը+FAvq[2< vMFMm(rM zm 3*4ꌙ9jS=y6'TaUg2fwHda'm!"rBƼ]f^>EXc@OQGoV ~!dsi<\u;\be]Iw }G"C Ii X-wj^Ó{ u"H9)=sH_K8b7t;?6{`tVٜm$L nNCZw߼Le~LrͤQ&Z^a*4G}9bquant}s0]'M!"` LKX\r̅9<;qR,d&eA"7d wy47@nMwk UQ=/'a6:bIֆpOt:=lf8ǒQ @bt ,\JZ_nބbD=~QO?%ڀ Cz@`%0m6ۺ;j5e0R8~Ƥ_/2?Yqh-Ϯ ` ID@ H)OK3 8FA@XC OkYl!5?1'_- v"+n3 [pFk߷Ub×(zկ^:YǤi|P({Çe&k}BLmlҼC~-f53iښ9'᾿?U,5j(!\ :gN</ 𘏅$4;-OK~+mcmcB_E_EŐD  r!J)s_s0al ߨLĔ=Rj |=z{dHZJ8LaW4H.KtO}+oY>Վqc/Irh+F`QAM'@p.N2@9B@ j]V ʣb\%Ph<7$أrJiE. cZhU5%R)vZ ?FᴴX_` ^SlC|& rw};t$~ᾉ%ܟ8w&p{?[Q~ [X +=&'y{H/M5V 0219X/f.ӳh+DSn}GV}yEQ W6dT' P*%T'Tj1v~3vfvzs聓mIcF"L@r Yu;-Xr3$KK͘%(KK:*kSg/[IR|dIqtz3y s:1kg}*Jm]gezu\u'Iža俠XCB(XLD /x Cv ~I'g ٚCC{d7ރ̙ܳETٝdƬG¿СV[ Y}Z7oNq|H4eɝgY]o[2r V`\KʧamYE9[7O#u'ܛyL]&z ke[HM3zc^1I, 4@&pƄjJ,71- -Ⱥ ֒Gۗ=#cqڜ/ao*76ǥN^^9mWmuN8̼Y5>ĢBiUԒYi=)snŲKSUݽ+YZWPJBP$2 ~CB*21VH܎:pVQ)4~9x@v':7R>cz <g$j,ulĤ,1Px DGaQ)t2gHcjarDi17cʨdb8s}O5=-'m{-<ǖ.XC=sNڂZRB$AV+e-f&]xNlfZwU;3KVDZ$z'7(\_sߝmxmZbAvԖ?($2$8̒-xfveunNΞ-ح4۵~Օ䮘CK̗8^E$[s ?LSdç0n G _Xĥd'7$*{O` P'6#EaK q O":9ΖH͎s OìQn&VB;W'3 w2ff;;{ٓk+kG͚2SeX<$QX\\jH.%~2[==$FT-==."2\Xg ;.ș{)!ۥ0釙 ;[ҾY;g-&3kfi-]SUbC߸+}v bH][=$s.*k-QUM GqA/oػ5Ƙ\8<Ɔc8'ab1X0JM1E{XJ ;n0+( U~iU)9vxk)?!~5$tWQE+>;bv8˖|6,ѽwUt >\959p gC(RI0RHX0RE̿d:T|PNM F@?*Ɵ TT]1'[u-U'77YuߤT.( 7js]Y&6fo̿ޥ*tӗj9"K5%bbLxsnYq {:FĻ#sJGtè3ޢ'j|aJtlfgg[D8=ҝLF#7їXB͢#t'nY8rz#_ Z9xHxD b֐6R͉Ej#s|@yȇ\ҊhLNE{d$ shJ1_8_ 2ycKFa y^,Ww'6|p|]ݿn[ؼvuX_afFV˚Ė—]|EE3J Eq*% 1)^z;s5iրDXbI>%3Qsg$]qʩ1v&@*U$Yw+EwY'_O=ҼjS=speE buN7o$QT㖿RKQ-Ce1g3[-l9glqvs,e[}V+۲s^y-@'q.:p)Z.$y2<nQ-I ٛf$Us';x3$UmW9z2c#k[2[qF-0&R#v잛ܶk~S񞺮\cT r.M_mP!SI,!!!aGsq} [:q]^OEC ~3Oaws>=\}_}19xp|U2lې (ߋ F~ ƒxBO2$^k0 }}W?ݔxc`cCdkJ>/3':Z~b~7AkSILD'0N4zF/"!FLJ3Q;M$3j 2wף7 89s7-imZmIjgOn:~(N2&r v%Y-nJ l&UNctFV+S,Ҩl+al"h@ i4 ؿ[4[Qz Wau&.+ȏv=K6_m32ucqA!ɀs͝@,- G,V/I2/~̥P@^$N8y-ז:=Wue˧; ۋRqDip]ZT"˘&+J3WGFʹ꘲s|ӄbO; la~7yY3%K֕ȱ "yw<~l>1)X2!:KBTZ25VH.]+W!U8nZ G_ʼlbZV80ZBR@L8C l7ζ}.㖥l6qʶl}W|92K'!PUui*xf ot#pJrW6L@9l"DC{6p>43쎦+h QփSjgpFv.n,e!|=L ܷ^>o.~MnƩ_{~!3b9_Qxx,y\d^J^|*Eef׺bҦxHWfΪR)Δb}'0+¦LH>,-mUW~X;c_e[);$d˖-;A[,I )MPj~ LJ;!)Pʣ)aRJIB&MS">^ʧ}̛YkKN{>ﹲ\=YnZkRݪjJ.e #e*e5DYI(kFX%h˜Q`5ٽ[fDuGǬ~qeT*5{SRtjf2$dy \w. NPZK,΍^տ.n_[KWY[X_YZ~~75vϣSeYe V4Ocm1,c7TE˕ϒ\p^AzͰd8өՄeoŭyߩNJ?+寨^[:ncـһ8z]=$'NM/\iWRԁ$@t7R.*uJ[bO"'2Ӹ.C@?z@^PS5ej;MYGn1;Ja<!u*RJFեcUrl7˪w3QUUQX8]tH526Sϧ{\]8*b~NP%dwv+=$>Hҏi?aʢ<,_{'kvPZB"] !;T%h񅂴:½~ ;vg抚9҄tث 0/mm gPf^VhEnpW/Zwse\^Q K-+byzO)A-쿱ϵZ!ʥR_"0}Z)^b̰fدTryiE$ulnC }>f>1G;&Ơޙc,jU3Z ZJh*%b"*U kt~>OE5}}0ײGatRI__OIѦiIwh1[E&{أӫ+JtE SgՕ] dj-vfT8LLRȧ! 6whU&DOmhEnEEfQ`;a03%͊aM~0jY諃7 jtJVCwcԳL~M2B(`ĜR$k5Z-mw-VTFK u_+ ՚YWg‰cEn+#9Y_I=ѳ_=ceʿwDTcZ6HuFr`"`-0-hN4=,ZEj&Wkjo[:tF}~<^ x?+(ZCG oؤ2KB`_b߸dh+L5]fJO\^cƔ.1P^=xsfM+ֵ6ΔX}-xNJOEl%%AХ}AU^NɊ  V. Y^#v<56-oCpCf 4sovNNX^$_5*YvܔPXӹ  K+҆Ԟf~QIZOB8XKxdh`odr?Y*Cg/x!8D:7Qժ/R ?))*SB4h4NHQ*YEbFEh N)N۽"u"#C nY5/V|!<>t-հmß@!瀷f*Lq)\jM9;yZ=}w4TtpI*R՚*Q(fo ֋ߪlp|<>4%V2Id>d g}*8Ãh ZAiaO6R"<{s죌5'[ N=tZo%n%!vIӒc.ڰbzi㨭| ڡ*>id0Iʲ8F&kQUe9o9&q6+7}OAWN\Y& =zpms{nyM}SwjFڼbu }뺶2Sf˷̋Ǵ;=HK!E9"'ڜ\NTl-5[l#b[FO@')[ѷe1Z̯^߷8k*+MٹmB%&}Pdw1.!u:Y3O5906wdU4Ufg7.P]U'e]V)K[.=VMv9]EֽWCCgh7bdc×<ooIz<[MEin'̼}amsYiKL# ]4>˗PwAg2h@KCN6 jpt DW?}"Z"J;e@lc*uioФe߰Af K3&45'.2FD+_gǦ[,CCVDikz<&=5 8P\za=i^CJKNQd*vs1^a( %0qr%w1g>lv^LVDt%9CctQp׶e{Y:K!+p3`}ozoOE@5v5htwF]q?4kRL&{*#TҹMUo*khMk.5^Pq<$vV o}S>+￁Vi>Eoo|X8bh]sGy= uu ؼnYA)-ysO:sAb JTwUL>e*+KIߥoDrhu|Wv\|˖@Hv_k[~,g~T5Odҝ\QҪW?PkY)^qݾ{8lnub9dE|T3Ԋ5nzS FgIћ?o3q߄dp$-5UE2.MЀ8ɖL:ٚ߈glg}Ӓ5׷%'6Ԛ3').pg;rڼEk2m\nkLaC#5sr/rKKvP+iRQ*(ηN4c$cKƎty-}fdޚx泙Wr4wY|V՗*ͻoloorrM.|m{)ߔ?  vtڂɂ-; n/ +~,)ea^aWEeEw}X,$,/R{J䱒̖H/KxRy$۔wn,_;cqwSGbK+_yԤ3ՙ etjZjT٤S՝b1C0rN,5Κo `[pRfw,^-Wr\-WRүm"8C xEqeK8G,C',Y '+r+IV WApo! ג cW<)zW/oYH8C$% %#twI8FF'$\P 7K(*b[%\>o!6 גt}@uCɢ' ,⢜E\rq>(g'ԋrqQ".YE9(g,⢜E\D R.##$D$ z6Bdj|H5YJP₺12x关Zo8 -۰ F(}La_"pyÑ'1y\^G$qBі#@{Dr)i ЂR( sz׋t!rN#@Ӄ<@Jup3JŃS.|@֛WJl{l/NӄzmL.>c /&z&yRAAcFPTBa@z{eH/͇jS&Inn3 5HiN(I-8:m'`/r201{DGP!d3A}EymK_'jS:vL&1+, <{%NH65+% Ez%ۈ) { ĉG QSNEoқB$C|*8ț uH=1תhcke+R J4bm=R$y nR<&OOaIb6E#?H܋-؏^1{N# K<1)E0jtF-q ƶmZccǠ[]$L H_K$n}M y!>i,D_nC$c}|w)2CLv+"cՇRH!J,qpqF#R:fqR JKmfh2sŜWKmv,M-PKs\j~=ƁƗ!Y[2e$i梫;&'P>1 5 ?9?c($45QJM|/Z$4 HK7/7/FH#*GgrX,MzF.A}^/+1љsx1Ź94Wg*sLcQRR7%c/F$ bx GŜOSQWd^򍄂 MC/76 .on A',‚7CT+d(8LLc7 & ȸ7$B#S'0 P<#o(,{6y &=^a77 ~F -鐏4 _ GL7E'E0#sSa_ #P F)B?㛀/0<“~G}c(2NEr HO@04#F#0O@<> j/BXS[p*('Tt0?э'x[hl !)#!TABz'23F &!?(AQ0DTAbTzrv@=qϤWC /*ЈPmv2 Pszx0E m R= 6 vyǦPܴ6P wbI4j!h; mp> ;(w+>*'E@@rT  W;Fp9"d<==]=#^ 6iSbHM)3m톂S`[)#h\av *Hٻfc)^ŎND(㾑񄾾Fž Gbc`F_& _#lV =(>:U%ZDT! =Sj*1 "SM4$@q }]&̣)|DϒK1B %($a }U0aI`K41Mcf[[V2K_,Y553퀯`Vncl;LL'xx7 n1.xx?fp7k# kgUW˽Hwp_99 Gy5x ! R _Lg+/ \}WUDBaN(Ye)ej0Z6^n|殶;w$t\Q,O؟)Soo3?g/;s<ee_^#Gq 0wkkpGŽwGG?> E;w  Ysσ`_/Xʗ,V*f pku6&-| Rm|kx@΃N,x'EL UJ\)jZ%ZW¬%ZLL+KB5 j(@Wh'ue. F$m,H,~O$@>fLk@w[/eNc藈#KT$p\.T:PO}]x0wDG4~;ޏ7qb#9< P0 a!B~KHǕ8 V2P;0%r^BsW?Y +]&x<+c"M:"-XMh)LqVg aӏGZn !?7KMp6ΐ#:Aݗ9?zY=;.gؗpmH5F|Xt|_sfqN~fWK<7ñ8zWKpf΀8?*[͗Jݼ":{ %tU_·$9Kgp< dzh;e܊HQGm΃\>#Xֿ3ǰ8Bx&?O K ˡE<a<+ \p qpx.t|89QÎ0#c],@=ݥ9^(.=´p wueӱ3]p hvY~=ǭ^`rЁ'Z$s7m"lOju,HA?ܽ5wt! ޏnlPfWw'You=ε8Z9۶n54ĹψÙ\e:lGݠ~_p㺁O_?fpšʹ6oBm9 :C < p ܇TCۿBK ;k>nr6 v˙nSwvbߵ8~Gn?=cmI6I>f!P˻ |c#"~{)bAICI~ #I܅8c>m>BH£<ۤڟAsJsz)GEBrs3/Y6?E01ė!Ɔ5E+zm8시\\/ &[M;7#'7k>r3;oÚ9xy!?"W<|g>G'؛}B vQt*@#6ޅjv~(z"|P}O6 wgEAsC {ޡ=x վ'Mjj>noilh3{L`a=@zۡ}36i7ƖX3v@jٳ[vi!]ҽvEYğ@=?Ry-s@?{|➴ԽJ96ឨ{G,IX̴CülE໽)۞͠Baѽ0ڽ~[BKcI|'f:q\17K#m;{T.~WZQQ{l3$3N#^9ӽp?,2~vNchOC{U Or{}_q)9?Lu/dֺEɼ[,VaOq} vF-s?1.RlY 屦 p >Ky#'فOρ9:7nD8{F]j}b ߌ76Amǭ}A-)<֗FN_6&OyFb;5!`|"OF/;;JLO*{v݂’<^%*Fs ﷭%dA%X[d,q08X%zppp$d"RBd͂%{/Jo+`vɆl!ΣJm}H'%ŊStG1 qz)EK|_Vwg1gi)R*CKmɰ`AȽ KCRJLM,XRcbl)@|p}$v˓|?Y{~Oo-h)g 8HgEM=YKɢLOvVdžkd7m Ğ(4Ͼzϻ4I?2ts-h,+OPO}T=U&iz짏3Oe^-nU/'__[կol&+TzNVv-CI~[CjWꔡz 7@H2c1\i4,Ò!*d|ȓ@5&SkFQ,cqql3b|M21ʨTvˌqR2Vd#~5k5xfiب2z[Zئ7&mxUhokCޚeƛd}Z<5zzVh b10Vx|ABdhA8ک% +984/Fd97AVoɷho\=* %ߗ\=%O\gK35SxZoCKh~Z,ziZ ӆ8m6RkZeiY"QcydĀ;c{~2Onrݑ;w/s={"tX ý(&SrGS¡pv8O ˈ. WQׄku&†VQhv(?u T P&jeg9n $. SpEhŋ$dZw?hՉ1Y1kqxBhϊsƉr u1V["_'D0YRJCb y(4NDq8#Jit14LC\o0{ifoL4Ey*n4-3 n2CfIk~ F"Or+)VQ\Lqj5kqln*`Ybs΅unؐ51)wgnsnKn+}>(v8i[ngn`m{x.q0lV\$~EoBPKt3]1G#EmfؤX^4*=̝N=Sb"Js7syZg7w?%Y弟Y?)OE~Rg?5z=?ϚgͿ_~Yr?o}}VCϷ_?3#[e~zm~sym$]4e\_;:Qѷ ֽ"ϺZk6XRXophf-Q2+2mk33+9^k?o촎Чc tt@@/ $#B?b8txB&v*aQH&S6ENYb?R|@*ȡYtZ/ғD̥b2ڶÒs97铁Z#(L'(XYt:rBVcSc=km]w6.cdCf9Q(}:௴SIC@L,E] s:L[xQ0ͧ@ 060.Gp..ϔuҹY80չ%0h3Hެ<7rY<]E#a`)&™N4½U417ڳdO;, J^T$>!(>mȲ4?}FƖtolYAa7͍6{s cf) x)=HQA-l"Y` 8șXN0%C) 9uF*d6vv]4V<#jƨL{?KKjXAgj:]F/zj-<$[<O2FFY):// B/ B/ Gf +Oj5GuH/g?_ÛO֭xo5:i~5_ J8b:pM1D1bb>)NIK?_rtK9:T:ΦUQX9i-u뜔?wDig+FG&;[>>~F~n)AbT?8)&}T4#`"f91ѧҎ{D^䌧8Owm׳)tPNq#\7lg\ʯzˌcNPPOZ|vo;ww2ETg jVfYJ9%%A?:d`2???`δGEiK-Kʼn+U/rUJWKx1AbUy{ ؽj"?l-2!h%;1ˉ9hJ&9ta7S"8Z1q3ə̫ItJqY;H ؘ8ۓv&pZTRٙԞBTGR'&dBɉIDpګt%= Џ_b:S񪟸X R!j U"Toc0O~L![-`4~#hg85gp 8:^jE{`/{QKFc;qcZiăG}(9@?p`&$d{cD#{oGz8ۄgFQKdH.rnGͷYSmpP8 ݮ96m| 4d B.LYL~n~%n1^pzdA+KQkx{8wA h .9#c,<˸z 5ѫ@oV7J>|5p4iб{md݌*ڌ\||W h~"T`|tJR/twaC XE[Ƕu$\ Ҡ=R;ʜugzGi7S\6BLc@g s wc޾vD]ޙ/Bmwq*j~Q6dr38W+:Żu&cWЪ}I_m%<Ȩ~x P`:8c~ t*PyѢ X3j9aq~cLkVpqy }M0Jʨٮ4 &:yWQwB!(ga28.ۭCȜNpV` nA ]Ke$45Խ5h<|XvλZED_0H~ tW=7n'aoY(V70wTu=u 1 {Z1ݒ __w}pbxUl,}@ BLث =[f249U eLU!fnM僟]@:T_)MhϣV ^<K.̥'Mkd~o6׵9{yV=F+ZkꎁVًw+eojZ"k|=CGFԍ|[osûҰB>I? 2O6A(s%6kQ?%|5ggռ̣ @^{Sp~ n=W7vNcYfh{e'5W] hsݿ6Z M>wgj> }$_ lAﺰ ا/^T` ,4ݏ&yˑ{Pb.ރx]()|dp,8%X+M8tooU@25g$|vUQe82V]6gNo3r@V2t#layto`)]FgWh 2c} '39/_>s)@KI>z]GEG893p O(g{ہ=Xp>dN`,ϝpAuѧI|zwDCG%rkS~QOb0rH2;U߉8zt~6*Й ?ruCMuz}30% :Hi`3N u_Z6lZl=ֶj?y'e߮tB[9&&Ugqq7{ϱ R>*T scٌ2Vb@#r_n. ,Xe' ؃7lZe~)z3Z+Z`!pBy HΆYhLmsN+Ӡ+? ?dGZz r < Ҭǵ,ao*ɒՒrLNEG5|%3p]=V}4n},5p43wy]""AM9OX+Ա6` l[qKۀɃ#݈ؿcTe9ųW80 3wj~ it,(g(f`-+PQiA/lޯ/gXHڭsg[g.{;UɐP\^ ȍ:cFa[9WF` 6fb C:Wٶ{ h#d~%Sk ĸ }eba× j?SNNCgBhFتtj b4C0'.HͶZ'ʫw.ց=̖,6H yv+g9j9F-|7F9ZBnz?w\1oAu쿇Uoؓ1 >g+~]^TeL 42.]uJi>ڸ<8Y+u}FNgt㉃ AJ2v0@ WCWOmx~d' 4;M}[dct% ~Oc&L[ Mp8 ϕ\.1Z#gwK?؅'D]vp5k$3muU.a'wa|~ Įص+lF1FUg?<%MbT9"KD!y-*)MO,2C|I\!&kD^$"n_9)p Xv_ˁEj`9~Uo6wgνkz lv;Y|RX`0 88ssX8`>po|m*ˁ+US5Z:`fUMd=?ֹA1 iFC?T&SC GÁ~X`8 XLig+ K F5X \Z&`p+I0-V`A4:QFS=>DLG(o' ߨoV/Sx89wɦ%wTy9~ɾh*SN8$s缱~h_G*!՝<0sQ̀/SIcy`y9Fit%MW*5bX/fE4bhE8)5rLr̒d,dϣr'BsQ9L']klxAݯ!܁3Ώ-=mYvx^Ii%NڂrZJ(ZvWP6@8S~?&8< sr'uDwB/l']m}뜴I9sNy7lqN;Xk\w)H}0c.Istvj5aȱr,WS~›b4ۣdY\});>'ҩ.NrD-͂vjM$d-&-Pgs$uBs 7ڹrbӫ{Ne6..-frF"grO5=Hߨ"NKau>'sJz>dSb>Nkcݩd ʿS*?yn2$=I@O47WtK ȶS;:6,l_ͯ:*5Wք_YʺW6~e=+~ecW'_+s s ~e¯l_DWv _ًW6 ~eW >M_ًW6~e/_+;~e¯0M_KW6~e/_+{9ʎ_ّ+; ~e3Wv4f¯~e- l~eC+;~eW  W¯l6^9+%8_.ʆWjW6~e'¯l>$~e'ï+;~e W~eW-?|ZJNbwiO^A9^G&q&VE[Q78&V5-[-[{[[Z~x ~Kx\%7fk|\>.';I|J<+m⏲I6El&!4-Mti- 8m8]]MN'KM{N{NZ$]. mCNmti]ҭvYkmGПԟSS{AQӟן L__C!-rUH@@&dL-Z3O^LeTnyz-8'2M%dyJQ)2]Tyj&/W*]Pp9RP#(EAfj/3U@_THZ*KeɀʠV2rTƩq2KUX^ƫrWJ5IMj,RS U*Vr\-;[^^x-'u.܆ې.Kc1CNrt׸{{8wWNqs׹B00Y1<,<.YROO99/{BdB@AAB37:ޢ.n{G3hfP* <6O1v>2UUԲ8:ݞϝq>B2u \]滮EZt҉D!*F*AZ*E:4]tk| H \eH'o{Eo]== Q$TBA P`Ā Q HEE Y0kU\ݳ{o;٧ wVr*BH: u_ב|u( |uAבuLA(/r"3qGfq !!"!!!!2CdH4BX8xD@Tp<ȢH2H H*b%"8Ds\Y!!Cfj5""8Dsl!!!Cd HH6HFd)fZȦH.HVm"9D 8D 9Dvpqsr)㸲Cf7L928Ds9!R!R!Lj`TCDqprq9!rCC8HH f"8DZ8Dp9q<28d.sTcD`D1"Y8+k@N>P0 ·10$ %*!тz zkFp: `D0@H ph.pBA7SQ m ;8-q>XHX"'D"HfWN?sܠ9P2;fB\>y=}J E؆ lLb3""#/bGf9d.Gn%|,$wEd1YB;2r,'{}d@r܀Ci_vЏK^=s{* W{Sv`FUQUݥXPG?Wکv`H]z0Y l֓j&bk pM!sSט_q-? `,XdUvu^w/`-1F¨1k)k)ĵĵRB!j7ZtC-D Y"QKPDACL7C춀K36##n FF,j!(Sp-K9$f D [;~lJݕUMUMհMձM{cj`jjjbac`A A0mFf A$c[0lAJ=KsRC8EFX)xރNH ]au`_t "b\}':QO "]H dB`aG%~[D*"_i D/85HK R@:BP㻨AE7!H= = T"ŀH- R p4"었Xt3uVۼ:}on nMpLL0!1 !00~ Vj{H&zh"SD q8O\$+j#d#yIdxr^<5Oy ]ϳxyCxCyxNf{z4x%ptUġ@e<"*P'HSIB7_؏y0ޒlf c%D5W=V c4 ~@N;`4$S\RʰM/yvNBBv|L9':/,0`XR%7,$<_j,RgTD㝐0oq`HH'w k c{JY[2"X2ĞRLyC@ Pp!!($BپtU1Z5i-\;mZ缊͹vcr7y:3d/e&e%5Gڀ2puGk32fml1w^ݰB;uG& (S1{wq|tQÍ{fhŬ)Wk嗥f&Y:QrfcǞ鮥]w*50WzZV y҇Bzٸq#.Piβ.+MTbI I7?/"4 /.[+;%Y`11]V|>?o8p,:#:&{fm vR_]߼74/vp/v0|nl1_!HU[GEMrϤW57=i1+4}w"AAug/i/_`1Sefŭ y ͬ]T|*]4m6)kfFē_TAh\$w'jjڿ%[HLL +c=D gQ64(PM `¿*6`]O Fj9*T[xqJuyw̰j#q&:v~5+$GT,{ͱzG1~/Ki>cg^8xD눓QtȕˬeUyokM?wؾw6LppwVܟwj[ROkk0Uq̶76xpϪ( R;_80Z~ +V:uP:?fގqvYn.:761 N?)N[kSnxp{(4(J@;B-yC H!bک:i֣c }Hex<Ԍ41 Jc^rN[9= \7r6%ڿj}HS"aSUS ?޽_i5ż`E=/kXԕC#&(}{8;91d vʚJ,xY kAe%UIzYy|r]Nj=Qފ^LC|Gdhӱ.gqּeثɰ-5B~mۡ9xE6yif9eꄚ6Of>Л7e--fš6&&a7$$tV j2}81#f!꫟! ###_Xj@Xmآ`5EO#GƴAc/mt*Q~` !ŭnv=zj8/1*9|%K5nL۷3P^'CsB#w&?iWU5 -TG':\pݵ6,̰}bE]_nXѾL_E%.՜)Z4_a+g5V%/LSMSvYZJe9verzQu:6f6I_fA6Om<A]զ?c-ψ,\{X)z-egtt34z8j8z 6r`dai5" [t5yS[KuO'siMգ>ߜt9X̻'/^ۘwMEC&WةOmjʹU] VZļuZО0/V^lkPGE{$?/R_eoӳ~teݝI'J)zuO +̢t[-PVX:!\e-Z?q&Ŋi?‚=MU7ZyYޮ~aXi[,u9ͦEW uMKR/vmnɷ9ra/<{ߑ">x@h(K[e|LMp5y&nU^>&'d/%I_v~n1UlV6}R}ℤކ#C2n|HoŬ/z ":n+_| n;dTzR{}{@uS0`y/*ENt8ڭRnEJ/ u\,ܳzey$'֫*I^_V̇Ɗ]c4UBYdְ'Ekv.c!ubNqZ}Եj~Xjz! ߣ(iD\(W ߢzyye29eez-=5tI2 י,~jNAsX_>o dԃ+~5TpW G)iE3wp[..,sŰ_y;H2q)쇹5VF H@Rm!1%HQ4}"iy"ıdC1RaY^)nqgvX/!xe@(po 0/G/V/WА04$ox<\pv7N Ua7^;0ӻ8{*ay=;ѥĹY7 d^SԷ~X°nCnJG]`c˖'ĔL5{C̣HҎ8G^@L`N\N/'~'AmgGQ.~dű&YU!olr{p{OK/Uivo7Q oP*x/%i_c'dҊ3ʇiD|XskiO+ȉ'z3wED7DS= G)RW&J~<ݡD2~T$N<; So ӸlҰf?iK׆zlzj-8.1l9!iexz=5|W?޾}rBxj3iA.:Ǜ;–r҃Wʞ*o# 65I+>[}v?f Tn͚1܋Tnm]ɴmpːc e4yַ 7Xze9.ŘZ ъpiP'ՔT/ { =-n9'*y{Y[.?Th=! endstream endobj 473 0 obj [ 0[ 550] 3[ 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550] 28[ 550 550] 131[ 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550] 345[ 550 550 550 550 550 550] 373[ 550] 380[ 550] 383[ 550 550] 387[ 550 550] 590[ 550 550 550 550] 612[ 550 550] 616[ 550 550 550 550 550 550 550 550 550] 688[ 550] 691[ 550 550] ] endobj 474 0 obj [ 550 0 550 550 0 0 0 550 550 550 0 0 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 0 0 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 0 550 550 550 550 550 0 550 0 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550] endobj 475 0 obj [ 457 0 0 0 0 0 0 0 0 0 507 527 0 407 0 345 0 0 0 0 460] endobj 476 0 obj <> stream x} |[ŵH-["oreَyW=-1NB8 HĶ$'1%,!lIJBRluhJR-HK,;3JJf|̙3gvTll[߹^+;LߐJ+V=u&[Ʈ.x - G_=u}E+:L"Wg=gkɳ-, =ؿoSh~u;49u?8Oԡ ?/. 7xj_~C[}aڋC xܻv!cߏҰ{wխ8uSH & ɤ#AȯvN|t]HZnRzc`{ ?87pK)N{T='-hC>IehZ80B!IZ"||DQuNރ>28AEA /7%I>'n5$\˘7Г/}L_*Ӡ_[+E&zv}soRJJ[eJ>XX$[XXXXXXXXXX_)iShț:r6u%yo79[/P/+ Qځ"EMئ>yfX > alzͱ ( m; ΌTjkl3tFgիN\eyҦƆښ%UeE KZ ,R~^n9;+3#ݔl4$%uqZ(R)goZ]f5J~۫+dH1[ɒYΒE ]r p9em52_duⲶᘮwYN{lqZ9LD%:wƨ(xwCf[ZI*fceq\䝛(4qlJk y}4~Rv4W}KB~؀7XOnG]kY6p|8pR~fAyZeGAp9U:a#]FG\mNE;NEr4N9j4-+mo3\k㈻F$W7+:ZoZx@q(E-SL1ov;RǸk=9sU2Z'vŸ KrǥN BD}KN]w:5U4VGRg$G{j̡c И71;j&1Cec YhC/Ƅ/k0V#s3Y_* =SuשTdbxd#\׫%l66БrٵLOHL,z=x:Sg)a*k3ll! fqUU6d)1F#3ϭ?&4BQ&M2It;QQG]<06c+=c,Yƕ٢8)','+a&]ǀ. Pc˒y&yr%WM(2bV][E}:Nt/u4 "<eӫjάFݫexT9h| <\LtT37c36V =r-\鯰gvW ceJp=7ƷiOOZ]-ΉB=,8TJv ;86| ILr qHєTAk{uTِ8 zuȜu4z9k-L ]CZk ?DC}e f.L݅+&1k5E9%Sp zBqS94wzr\!NuArl } ": 18v:en $ ߇VZdMS,U8Sq)vӛeQ͜zc!KBm Y(ӯxBS](+ެA 񲮜> '#C:[{x*ꤲnNY7 ThIrbQ>)ֺbHC UKOg/=cԊO^`wH81qͥ&2x\ }%F>MPN%u)pc݋/gnf◈mfh6[[ fGL9[cH3vJ?52> xn{< |L\40YDV-SOM=@m/J@1>ONElB !}i1W &H^>9uM.e-C߸XJX nGjZZRF6[eRffbG\ v&,Ux{YYMXJ}EJF 3e?Mǒ+<>َJd2vdq Zث8Svx)d]B-j5 3͆ˤ,Ke9¦RؤM*c >=hђYzkWwZauy˖vYJhWk>6<6`i4Q[K|kX#Y-MKMqZFl.k?+`]W/wRVq,K#dL ee7@f-923vS3+lv{%ȰwŒB0ݞLgI,Z-ј3TmjMU+[5sj: j-*ҘPl1M&ƕ-II(.NOߕ][_7U?2x}eu Uqi%\؞SV$TUi̕{jGfzJ^m`GBDkuS`\iYk'Q-/hЉ0x{uz_DꚚZ ?l8)|nDmR7׬4^j͊5{qEmpemLul^fZX$V}(\z{]5YStYan9]:o8hV?9~yY@z\>wÐ#IFpHE+As>G}!]dj:fS~(VI2+c'6q%qւrT)Mh=-5={O v3a}vO-tecw#,;?rn#9A,2pSS[S&q*E9GvVCCWd|7m8Luu+W8}W=etSG'ߟ_s@]4/tTV6j `*ca.J W;4{sdS%'%16;Jٱg%lzיF\j4I`AFeByd2n&/U{CcrSniUe5:m- R*)'/M}$Ϯk KkVʾ\}uwD<$&N¥|1򉉓ӯ;r2VΨxf&Oth9m94tٙcdZLv{>;S'k3C;Ck-V[#%_nПu?pAߖ%Ig)2_ ⚵n[9u*wULc9E@IG"G4ܻfi(55Δn8C2f.`~!x̛9A ?= a)> 88J/&5צZԮh-|$p7t_q@ʹW'4WגSJ}M`Nk-|{s_yJ T'?-UO]`J-\w#77GY %39}%gIpBvA^mD!7?"?YFf9,By#+:r ()sdR#rKgj9G_E@y%pV)t|BVx™+FV5zXln˴!yRsS=ʪ||xƽa~Wpw ]G|4?D͘~1/n۲J7UF~E/\;C|?"c}"Rb5V#Xzjjjjjjjjj__OJn6*<LEeWobًf嬥H+Y{9\Ӷ迏KAY *&}|d* '~EȌUA*8%lT:^Pq6>W/TJ8"39j*&?b4AotX$W";TAE*W8Lc*ց5٠x~Wt%WXig8J>[IP)jAYYYYYYY7P  cx#g c_?AGZiZm k3F觋b<9Kv}>A\Uw nU<*/kˑ2t|\>i>?$w/ԏ C8#ȴƖqI~#n_9+lvvI=gP[T k%&6v_93F*ngi|(WIW0q9* !(OW[pj˕Ph'4e-G^xFZ?:z>GA<=W9rp3O>c5˰j㾨~ <ۘQiIhُRAiAc1<憙3bzͲQ܏> ffb3g3lVe$ت!5Բ^ ?[TSFT< gFe9;xnSGsļ_:1A쓚dLj%ĬǃLQfϙԖQrI@a[" |l!AI4؍pۙe̗}g=ylRz1. Q53kPXl(ǘeNV9wխ8[y*1*G,#q0>+lMqPdw珒,r+F9 g8"zRH~fpo,":z?\*0Ov9 y>/<X5s֗Z?tTQ,zInv!vyqQjO17n?t^NܫòðՌ`-:8Iòj!e7y\On++~O0 @p$trin_󖷺6ni6|ÒR_ (B %}n_r{p@ JW>#Ap׸RhȍۄBRg1 Im814D،( ga a;np? 12C8xm1)KQOøxtE(ʃʩ74Vt-$|A)3=a_PqtwGMǐG5Aĸ7 }@[rS>G 1'4Rq0%3PHT0z4@u2beQ FT x̙XA_ht0S%^ⰢȂ5hH<$ lY?:J}tۡ.Hn ,0UҨkxadž6UIVneícA Zb7E樣@`BmQha?Qa{vp\@r|̡LHP}zo@ *O?V< Qv2i4*ҒuLany*E@Cno*Ȍn9"4ׇa%*h2`x=nu=0=`@A*@8B~>r<( )y 18⟑#%_'<7)Og?KEyy/]] <ۍx* |5o_?7 n /[[^x(zK|b;FyA'P.w68$è pP~68Ï?P?Fz8qz_68ï?PO#~zxKE驫9"~__@""x̿ĿUUį!;Ŀuu Ma nnB|p3AćConE|pA|p;bY&rp;=..w a0RE%i5#ƠzAB Ŀc Fw] O]-AyOw_(3x䗬b E"fTk D2dŬWv?kbs%Iu6Z6<9uh+氶m`m@7^;N$Z }n%QWI24 [ZC&dAgBfM0¥u c =!" 9\JoGc{oxGarӿ;'؝$j">I女I+2a8fXq۳oϞm'f[f_/nU7zkf_[n=~h;n}/5@~:2]g2Q3'B&0u|Ľ{g%J>+og9B>s?w܌kS;5qmORC#nKݝz* uX#u"_z֢鯦]<%p%njEH^z3{dLjsL_֊,w֏/5_~9{=cWgxm;uVll>%̃+J:wՔU3W_UwqΪR3GOY5e ٞ55 4]&zM̚kk]suMWvڪu=p] 5)Y7]m'luU(9mrrsL̙0'+gsΎ-g_Αsr\Jn5ũL N/rG<T|MNSEz(87B웇Mi~1*<sO|69wm-\r5jQr|O1h(ΓF?ffn ME{M6ԝ 6jjꍢ܀?b _`C׍`F Vgl^hck輱&盫|>4@/n{Cv7lHk78f?W:Ԗr^6䄧u\o 56vgRj"vچy}=ʒn6O;aZ@̫ ڄzV!b h fFF^xf5S> G653cF^2CTJxk`Q?F1dz¬mw>B eLd3 3o!N&- 5>hGn$-[hZfr=xf?dLzS+m[ƬM(QlCN1 ==z_puZXeF[\n.$45~ V? ۔uWuS_fΝcs'a>`1 3`A_ Űր] ٙ= |=@|-5{驥 jZ[@FمF,ai;[@ji Zj_ +P@i}Ų,o X6,pi] k`X_~`1Z8VFA6ԣ:9օlК[nI޲9nWZ6/?RwOW6a{W:T-7mLE;|*[wD^;}8郎|RZy|_!oFX2J.~-VH.)YN8:Jf;绠QYM;Eh ->c+5S38^XMYYf$Y#p+4VNKy\"n͚n Q< 4<0s0q&C"L0C`0 fx^d )0 ׅ!\*+uX ȆjzY,6F;n _>8_Ap#P Q b· 8:TA5sp~?\p ]!J,YPΟ ZZogOpso[fLEl s!|H],a1d[Uކ-a+lwa;gRŮZ8'BB*@ >4gm,[p4fZ@KYjm^YcC( YlHb0V|X+ae>̇5`>q6 ee`OPx KocƒYjE{ma{6TX !^uWB\X 7!̷m+y;?mE[}??8 ~ NlclctƸDeY{N >YF-QZr Z$ '\ޤY#18Xv(hv(a&0l )0WyUҀU[eb`%^*+脲{Ȇ5zyÛPܤ}D%W؇C2_9 GHw^U6Ge~&2_mMG< F :z9Hl:ӉRWgX%}N~sߜo=ωv9e,{H°aAYcFB`8a0lBXl3۳0Vf`2J~Rm^l54mcc Z~jZ~\R`̷>tX Kdl(ςH/ x~VWe-ב6Ľp]H\Mz+eHKz;{އb>G >n/{`/|`? |G('r8 ~<*'8 XP_@ey Sc%ބpVx>ѱ8>TGˏSp*er +c| ZD8ϊx4_E9x ⨘M꼥Rl"ÇKlQ0Ëg2xޅPD| ć0| GT̶%E(|KJgDwu:ˮiubw6[P;CJ>nSage>Onha71C([QڝvNJAݧëa+xIjhQk~/MiWK2㉕"zg<9%!y(>kmE}zf5M|(\X`7 B?]Nz%nΡ[/삏 h) =%"]бl1X,[ -.]бl1 7-yG@|??q'W\dNiҼ;5:Z5^ƋxКbƅ5hM1ZS5h q䋧⩣5EtvY%8T/6%->9))ͿTVZs~/EKtr !VP틏wtY@[vp'tN@w="! OG;= 7< @+LB3b48ETG3u4ӋfVW$pElWAJ"nJs^_CJm5 n n6(̍(̍(wҖQXWyA 0/ 0/&0/ I o$1u1z]/Dyb>Ca>|(+Qo?s $ I!:ƗIK1\n,\? 0&$ 04QfϤ, syxdƙsp=C*X!Rx2T;n*VV|JEyjlXkascoIf+o o"ETWg+h!6ʫPLQiҥ.2=ǖMD#'ٜ9_:;ιy7B>pEf8wt:| |=tYJ>}t}utl+a(^zްc`7#Qҍ ucCPUtG_0OlKRoHS ;tEt !VPaʱUتتrlr=-GO˃A*$a\>+Iy_I8ig~#fYr$/g}7_‹Yμw r9Wxr$oXy替IpqWƻs~h~F3w?O~z H $4B+tj185,6SB~1K%Vx0hݼDnaMG`"Lɐ`:$ɣܛ7_~mHKeyG=#_|fs|u_g|{0~83:댯3:댯[g7zjzjz\멚驚驚驚Z4 z z z0~Y@PAPAPAPAy3*!X@Sh]! 4< &Is>`2$ `:pWe J G΀[)WOu€QAKxqΞ=- NZړ::Agp`%-uX^$>'ͯ>b|A:PxS0ba8Y|'kħ4Tb=dZU%n͠L?a2e0f,k1kQٱpB 14[6h-%`iS.,m裭Wn*c̐2C^f y!/3e̐g-=!xc00 0FhDY8MNe LNey-3`&>|He4˲q2`2V̒I?Y{UjKmk?(CJeUU^V˪zYU/eUUZGa&2k|y0X_—LPCpt)wQ3){~(/d*eRMZeWyߥ |W XI+]Um^,fy&:Ag]R{+D}p?7< F#£~QyoT3*GeT=4G0g< 0zͿj2NT'LeȟN$f!y=VC!kĴODHG(a0FbscaZ( D.76hNy;hw@:B' ] .D_!TF! |H4X8 ab̀%ǎWЮV2;x}|Nӯs=~p=~p=~_fsR9>Nt8Ntz8CȪ y( !ɼfdy"d* !3 d~H:U-3]/=!І4Tm* ,@-\U֖Ah`a 'a<!FH!MFqmå6VFAo 6R-#ZNc>14FhlN$8}ZMrZ#D=y&{~9GENJeY^Uʥon*SSM̮v,;vR': -${c4RF^S`oFZPޒvӚ:SlmoKY8!dN9ޑ1;]` ]ww=ӕ~"'~ϽGYw7R<"5{/׏"{?ylfg .vi osOC~o& On8+3x[(eMӴx i7G7IODS)F9e'?I8~3 +TA5sp~?\;\?oWA9fr,-8~A:eo\,:2|̑*8dc :ˀ%2ѱT;^]v# ^/SWdUڽF?+T+)C:VSM5]+d3Gurecyod|ߔ.&ߢ|trq=Tq] daRs|g<I3a_JZVeX+ ka4ҰVJZiX+ kaVotHK:N. Tu*:2hX ,epc n FݨePv ePv ePv ePv ePv ePv ew.݅:nٍ:P2YC5YCQg uP2YC]:Qg uvJF(%v%`P$؅e(qJ\yQ:JۅyPD.G(]JtJt^NCJP](KDbQxNC(ۏB<(]"JţtE(~΃ҹPx.ۅAP([ҹPx.Bt(] Jt P:u:Z]wM?OW<~Q^;SރPh7GBuGQg4Sgey ԙH<ɔM!*LtL1K wϋ~G2\Q6TEehRIzYvQ e^'o%eoPg5eu吗K<6R&--ֲ |vz;;;*5$bQRvTΎaG aGbGcGbG?|\u 43u"RZ m6EhQ#Z~)Pݢ+jZEw\۫;JA?*#Ҍ`@ʀk})Խq̜d|_=3MĨZT3j!3jQMZĨj¨&F-bBFԌjanFg F51j2QĨ]jb"F-dTKͨFfT1j!ZjF0j73jZQ5Q 5Q 5Q-jaF`TQ JF0j2Q¨ 3jQ ¨F51jQ ¨jaTQMZȨEjaF0¨&F-dԢQ 5QCjb"F-dT 3QĨEZȨQ-ͨ&F-bBF0QMŨ&F-bBF0j>ZR4󆉼Of*HDަNlZVEuyH]VUjr'zz<^f]\.Vdw{yO]>z9y?Y%y٬cd FWa.֭a]u73´]L0miVa*Ů5MLĞaȣay5)gD ɟnv cD ˝UlfÈ7X1#Ff#>"_eVٲJ7#FwD ˓UFu1cD~ ɏ.7lFưXe*FkѪhU҈Q]FhQeTeĈFbHȆaٰʙq<]="SAs zYd/sϨ-|`&(,6 Fa|`4 Fc̈Q {z:|_go0XgFm-1{z(vŹFqQd37FVMZ\:|57FxYFyH/1o6 ޫl[U.sU6Y0|/؈^F2ˊ+jש֛X%,ieLL57YØ^զ5sY3߷|Ġe Z̠Vm17T`&}Ψ^}Y˘Ŭ̚ìI:}ϲZje\M]#Zocu3Y7|do03p {UVM:Qdckը_5*&9gyRjTԶO&lcf\!fV6fIaipҎ9u|qVL10W_b;^j_ytA84ۉ+3s23jLff73Ky=3Y9f*fv׮^̬]Wf*fv3s 3{9u|3 L7?ob6ȼ<ԩ*c:3WD嚙쪙3'3sn^fnbf'3W0:f׮Nfܚ̌:f33̜ 3{g3+lgf3$vyt=3{9dU_xskZ>V>sy$_YW\_z9skfv333''Gkv]+ j.+j]pETMw][Y8Tw],\Q몋,b6c ׮nbaC,Y+X9[X[Yx {Y,\R!nc,\,lgY8m,ױp Y]b0 Y8-,d2q ױd>V57N ,lgZ[X[XX,\­,bZ7+X,fne]y YUCkqw| 6p YfaC,Y+X9,­, ,v.fbne ֺM,\;C?X:#e5G;"SM\ka룱tڶ=$Y=v1`wؾ+YW؞e3/kS3G zt,oh,uJhia8|F`?ǝ;#x**5<-mxCA< #=n<*10 ߓ㈢p>1R4J rx=f`&Fg=JGR=ɪ}Yp7Eo IB|ur>w+wl_*KR3=1=wGZ=٫qˣQ3j|F= ϾJ5۽`Ï~?J4^r4jLFɨ15&dԘQc2jLFɨ15&dԘQc2jLFɨ15&dԘQc2jLFɨ15&dԘfD6qdT,b ]s|._9>[|1澧LY2-姲{8C?bQs61\$7S4>,> %|_܈R b[S3( S7~REox}7a3n-.n0MO??ď?ƿ')n ~sl/K*jL߁mk܉0`Qop/~~.f,%BDhY"4Kf,%BDhY"4Kf,%BDhY"4Kf,%BDh93[-:R: R3-f1xqV RA 'D8o͜EXhm8K6<s5Np6Ռy7=0W3j\͜X\tO:܀O >/_ėe|0N3k̚iB4\p5̚fBfZÝVp:ܕJ`jR5X+U::ժBQU( EU*UPTBQU( EU*UPTB^Uȫ yU!*UWB^Uȫ yU!*UWB^Uȫ yU!*UgmMɳ6y&Y됼uH^]%޺GHZ$+EBvP]i-S-*mA|~TMFpkb2*''sֈEA1TC1 oE*ka E"\.ۋϷYcYckv_>=ENWWTUP U"g}/ܨL7IA?(R?~(CJPR?~(CJPi~!T`ާ(v1T8$Q<1.]R\nf*ꯊ(*J^nf܌[]܊WQAQs=GAQs=GAQs=GAQs=GAQs=GAQsdn퐹2Cv!s;dn퐹2Cv!s;dn퐹2Cv!s;݃?cBf3e>S'u{oM}iC #0K.H]• XYmjJ,Rc wi׹c'վVi6}d~TNe5ܵR ^oHz xXH>U"1vv)$L } \k>~  |, |, |, |, |, |,׮RZkZk/}|{>}|{>}|{>t0jW*v+[Uà,OK3qV<~8G w;/X p!Tt.yR\WJXP]ӫ=s7|{65טB:0J o1>܏/W>7k3ZpUWY\5U_M*W~W~W~W~W~WSp61Nα8!=Qo0|j}Y+܁mk ѬLǯs; ^#؉]`oU> _¿NUXw[?Ec7Ly{yIo1qfIv}_A+*5ܝ|ߟ{nf܌[]܊W2lC_N܅!܍;0~{[wc'v9O:#}ɹZ`(|h6a9C{+Y!͝|\ qp1. Xq*\q Vc z\;~M،q 3T4#foe0ꔿJ/K}Dc9ܙ:mI PwZL; goދY_oܛ2|\ qp1. ݰw|ՙ:UgW3_u|ՙ:Ug{>㟰#!+G؂a?9e\&; !~;qp70J o1>܏إţd1ufLpOCJeo<2 8}W֦ߞYEhwpE|ݞW%WOBkG(;e|ͼJ2f'՜zJ[AuO3utݨp&йI:0y~kܞs*{mJh+9u`}>5o{۽^v׿ofپ]avVYadFVYadFVYadFVYadFVYadFVYadFVYadFVYadI2Y'syy]ğ*^oW z_[^k1"Xg|XCdş1xo,ڌEI6Ɛv0f1cS?c{{q1=ƽǸc{{q1=ƽǸc{{q1=ƽǸc{{q1=ƽǸ0wccsǘ;15v׾:/ZjvW+ 5ab׋־aMkTR^Ȥ7o!@z~{Jy4q^'_v'ѭMv:dhwo@X?́6VfoGg1Px9r33zs*kx1}e41 p8H=Yu9WճK!GBThLI1i4&cJ]S&{j] QW[Sմhup45(|_:vo{"`i<_Dtu>m3Y1S=6~_||itG0m9~ݸ'}8, 9u:?`mPN3ՙ~}ʨymٞygǨsl:#3پ30R-#0n=ֶ5+ڝ]]}/η.Ěh7j*j*6>=vO{2wjqLf&F;R֐Y]3y1?{~j&sCu?SGȢG>ΑfnQg1Q2N\T߻!ǍB7Jį܈:RUd0 X=ۢowZ!; 1iHqǞ#Lnn;Kjrg/l'|)ab3>e1m?~qU, W| ߌs]f[ķ?f܂^0xUt vwD`׶w}2xw{ߌ?ؿ?t.=`*}:q( OQcK̔lUȹncsƟxo+=e1TOӸFjFUͨp6|^*mf~<E|ɘ/u q1cd=p1\͌Gl7^o; HA1{KƟNAߙf }9=ax ?{Qs<ǚqyc?ζ~->>=]Qsb\k[v|Q؍8/7>?aSLN 8儸Gԅ̏ӫ|LQRųom|$J_E'k=Ql0FDE6'zh0 rITdS9~Z}l_F}>=T_PsIVdET&zܳco_J/c%*f fhJ٥Z]QHd9{cxh%_kx(ܻ{NW5?:ޗt_/ym=VsdH^hѸ6/#r_n $u|U}q_vV#{f-XoW'bg$uԋ>O>"UuW5BPՈ/Ԉ1cqAY]@#Ԁ55k"jEwP ~a8DDWud&$pۯ{]U==RG}:&忼/Kk|s':ww:&ds߃s=?RdDKy˩>``Ye-JR*CXơƠ-WcV->_ڹڹZ = D/x+P;,DvЖ`*|Y ꉬ+5^ŷA5̻{H 8pDܸyz:5K8/\Y3vKGɕҡss!Ol1R>~ep1WkC.F>|4 h$Ih{0Nh"/-+;HPIo`6lؕN\IQP]Pd bhsķt\DPG *Jgzs@{TK*% `Iz4.c;-ne^vMK=YʲW'У{+1=)Vt&~cuեgYIa:&&fֱ:83&r2QYNzNa@= #? c0=0{03 # c0,1 wa7a7a_Ƹ1^aWx1^aJ?0fc[U/w"`+ZjFDё;1!Zm\Ϸe#|0a6-"S\vg ד{@XZ)m>s^m82ɭfr9gGָ̠3(xkQaGgP1}8zJd(yt"^ jܰ @SzEfѧ3OU`~u}9Tqspqqr0|>s~cmM1m8йbp0&yhC,FԒ[^n5-N)#k>q:j7Q~+cUg*Y5rHyQ=^YE>,?u& qYEGQZ[P \7FjBm5Ϳ}};jṃ!?ct=qq6j?Mphw46u wxm/C^ר1c?Sէ"ԛj,SH^IA9ZYZ zkK'/7NVkU ~ ybgO~c51I'vP:IA~7s=)MxG[ØL!YpJY_b3˜2o0S1My{%,PN2e*s!Zk<ĒGX(IcTlo̦,{T&g4͔FI6ʂ?>,|XH(]63DߡLH?ouiȝ!\.ͅry 5.Ub\9ΪN' qTPTd4ze[kj{&`ڟEd D̸΢Lh)DK!Z U $4f=R8'A!Cf&2@oJU4elz/ꟅS ?lF@6#  jY6([R5# m,P,YYYв|P,P,PBP/fj!jjBqt|UQ )ԔP}}t6: C.LPT[ neвlhYOYgz`լ%K v3`Bl p'/1{9 qV6B.*Q ؃^*Ḿ))m1j5!kYn ^La|wA~]W Y(hu1I]sq׹\u.:w U [e!' j ?^jϤ38 p2@@G@'@g;a^0 W:#2&f܇$F:#6ee<[ɧ˓0)T*}>r)Nl^ ^~ Zo=|1Z ͇G}qjn47[5w$M<_5}z OΆΆΆΆΦ/Ҟ:Bo% eEجu0:(C!H  : Mx~3 _g`$þ)9bV;;舑-a'c?uA k!m趄nF p'pucQ p7 p`<]Bv oCn x * "d/D!`Wh4*jl/Ҍ֑8Ze\b^M }Gv-a׸ @ O<ӑ"/i**VX~/c Ux`!T#%A:`^ sa-xRՃ^TzQ=+{PEvONl#ܯSvs_F?Pw:MI^ݩ>G'ޘ \^ y´O>YY PGPi/Q/Q/^̋oEE1Şhy7"@>PL/#JM̫5x2Vb2=(5VNjTD@St@ex>jc$+\ \ۨ> }_U=:}\(υ`|[M=Vc4F0{Yh`+Ծ4 ۋcEei{Co=]]_UG#1D|ԫIGI&>6%J<^)~/_9 󀩀i`VP,_0̓b19A d%Kx3y  K/A^٧Q@^yA d%`nP̽#Z<`=_b f3#nϡT{aT0ж1Y2FX3^^ijt{:ў}HaX`I`Xx@G%G"aXqV`}7}1 77 z7 z,7 r,7 r6 j@}Xr%`Jz3HcrThjDN  w;A䔰)(֐Sz9e&c&c\Ll6S)͔fJ`3%☹N1|jye*P zye*|l>6 Vɇc1g+3WfoyeYh%AzW3rl_rlb+&A"q7:ٞmd #2IEJe-<~Fgc$\<\D@`&0 MWŀ%e4Z&{BS(`0ҭp_OCVJWu|׉5 +I8(@moEL23VҲtdjM ##PZFWpEjû5ʏ;vGEړ2`X ˀa둑),e4qfO+++++›!./G >  B#uemGóֺkkOx=Gf}? qЦzk̑̆rBAKӣ ɠʢ qT4PK96@zj]_"j_F~*uxV*_sW~9VĻyJ,hPg19wNF|-F{F{F{h-yyy;FFY{ؓ=F}Yq1`&@{%n .Bн)SΕ2pQ.ࠋe JTzY9W(݋ѻv 8 zz2Z"uw߂eB{=]܅]Jw!p.;pw!pw!pY!S>!'VWi2885i18M<-mp .WUrF,n$/UrU3eg<9EF.}rJ.z Q_U#FZ1k=bQ*]5jԳH+7"ԝTFݐhVU- HK({_/bl*_Φ+E~5؛|$>#~ +c=l>D? 79[_/E7g,&c\>mx N/d"̗5l?_:qo[x^b(~yߋodHCmv`61{W͑s9yfZ\,.߈L q-_-7ubobϷWL|xB\,^1Rkb\uƹLlc8(q4i JL1F&q9} /|_} }߈ɾ%"߷oBL3}}E9bl!ް}-ޱکvsnmttn)E}}Xl_d_$}2_|kk!b}}`oe0{jE8`O'_ov/O±&=~IZLlϲߐ[[=۞-[4CC؞/[ /e{lk/ {`o ;TO\F֟%/_c$o6&m$m~I:(jؠ_^𒆗`ǻO% ?E0~֜](٨)>)> x:A<)(cN/}A}ցen-R=~9ez=hjZ/ >Wo3yӴhZK/c|*n[;7 KuRZՉq{$_rF8_᾿Bm,띿:5*K\Vk ;Ʌ4&8Q#C]ps=˧ZlZy1cMݵ6eeζ:(Tϟ+p6՗.twE#1\6AsEydsֺ?rkXgv`VQrlh{M3jrJ4fj.u;.F%[#~Y}йŦxOcsg{IGE֐wvShK}zdmrƻOc_kVu0>G7lA#|Հպj{z";}ywUs9O]~eW5'jX)~v{,ϓatgOgluߣꈒQ )E(XU(򕣓s{j^W+u~ zpF.}ޥQ`7{TcAVh|Qe\UuAoL[̖QDɌP:-'zE) ?~HꏗoоFywiZ2Q_[T2qޭ$e1<Wf}Z(ghq5S>k9u9jߐsd-ו*uBC"ϗ K=,wAm"YܟeV\Y<,ߢe89x*8V;/CV~S;*~O۴7"O}kmGLw:V::|˜)W N*4'ag JRO7gUmcߜ\w~sZ=ؠ8xpꝻWUۜzd0fEq8;aVp0GU6穜! 6U+^;ޣ~Qo}.SMs `8?9kPz]kaRs3*NA}8tx牿ꫨc!z*#  #='&h=F[$ͦk/BEKi3A[QP9q DKY#ְ֘Zˮ`@֐ fpn4:+6d'֛`ߙ~g0p;#Իlln7;]T Kf2(wm6)c]cy|*[|oowyzKn|\~7/2$a~P1+ {:ݰ[F3WbɃ7NPVs 8KltWoaN1NlXwYwXZVcL6&(=W#OjL g4q~x~~(??6S{zx^d/2USϫYis/5^_ܘ`4Yo_k18[ 1 ER,jN P,颾_%Yj7FIQ\~95C9t@Ii('RK jEq(ԖN@ibpՑ:\N3$֜LW&+A*WŢ'Pǭ4XFXp2s~P%>A\; +Ct2EґA((GDKMUOtQΤgPY*9G1gsE.bzHzS+.>Ogŗ/-_ERW-!bkXN֋C؄,bFrQ 8" n`#^}TgPWguU:l:#h@OЎR9uGMe*64 |mr<:ȓd[i'[{y2vQvNe?MBϙr+E "%{*A} d,Nހtl h Z+D=Wd',ON/_"_W嫸5L}r&uŲNUZޒom6h͖q;W |ʥʥL9_Χ*sUFEQ%A^E-U^EU^E/[5TBL z?QY&7eLRn[ɖ6,g.{Ae_ }IC¨-Bj |BEj@YIjh5d+퍬FdZ)Ve|_s̘c0fC1b!&4$YIB_4cl+k$jH ZYɚfhRm=s=><Ϸ9b JQ+x#1 OkQKk HE&FHC-L2cd$;P-#GTnD^F73~ l 4nDCa:Íoj.mmw1OTb 篍_c 05D-q(..|q7j`LU+E VJJLc17E nTR @ȅr!lT8 JO\SNT*_EUnE *[U`V) l5{;z;S ezz"ovv\ox{S;kykqx-FvyQ_-[N3e.,X橱P;3C 55P1C 5j23|f.f9([qXp"?3ggf]q&0ƌ3g2sM 0xbV\slPsQ<\2qf3dٺq.Ah˼=Λwv`ّ9DȦrl)$oaFȡ dӴ`?l5^@hIE2B:د"݊!d v 7RA;w"( Mi/zz?ُ2}?`[aGm} $ ) B=co4xb5sg/lŘc1FXr (f1̒%1Kg\YrWf̒ %g̸ji[9%gjYcV&8tk\-5::[h]]]nZ7؅Z/Eu̼#݀x  ц[`ǀQQ“n.//`wi`^z}Sx? {s(6C-HZu`튯|:70_|}0Aod>`냘|}gޏ2_|뙯fއzo}fGDHhMD'`Njx "v]Q$Dh("n&!TO\EGC n!%FQ]܎xxTBK8¡j;j""\UbXFaEi}N<ϋxQ/(FK%[o7;(M-ކ["qP !qǑK%ψ3e j£TW+ q+b])i4Iw#=˕jPCttᚉxk>]#V'ڦ.tR50IfvtN;۝M-9J魠|r|:sw*3OwjEt w!}-Qi"@rC) (`%-.v#e{8ŸG@Ayn]PVwBSՅ x@_M{RCeŻggGݏYjqmĵ Փ$XW"ET5jAY݈D F>"bXRVɬY/Ų^J`zz)R,؈#DJ"e-'5O>XV;vYIJ 'N~IJe(YpY䳶e%Z%Ig']X$>I7'Y$>If q2"oʎ8qrXd 0iuHH5j$ZDQԁ5IG$$q6$I'+}דSOrOTV)RYJf2[BzTZ%JKe*ŒwцYtnAfݒú%OwCBu׻){!O^r~AJ?bp2Yt` 'N>\ )J%z lvZa߭ߍgO@9I? LwgqvP&<|htQj][U=kX#u`ԑ5RyyRc $Pil))Y#k33ggg(92`oҡYueuJzRv;FJFڍ{={+)RzI@/}2A5yY5EB5AN^h/PN^~RPQ)רE)/HVSu0` 7EJXMyYMկbXGNQF=ҕv_C;EvvvJjjid΄򰎊b5ra2Z~Zm`3nMŚ MRSqYMa5ՕTBVSYM%*YS_bdc{12{)VDSXHM&__q{܈{{P=i#SI$͍tLM̗͗ajJ̭V;mCך#Q =a@I$Re 92#Mj.dXKl2ڝ8+ %OB޲7ʾ/5멧YLy+w;qv ҧʩH_ޏ|)K(c-g#+!VJ-c%҂t!!ðl-W?SGVBA@On@j#-Аר!w }܇<2ǨudUٖUeel]!zl1ߋ5d 7x"}wޛ=kțXCvފj\2 2o% fwur. •O0~r;Ԝ9ˮFu%o&;{طg5?N/9 />?T~k~{^xݹ;5@xUoX3U wt0X?o2Ϸe&Ϸ[ ۩z vd*\%jf߅̅NTT20qz[g ms[{:f/]v j:级_U)&\JsR|{zB}uOK*h/]>;xzw}kH6:gM5.[jccDEw]Ti<{tբ XWMV{ҽj/UJr%4WcW*jjA]-]-a"G>;C'Q;t\7'S{s|7'_x\'O+<3瞧=4ڡSlgުݠv7K%ڣjNmڡS[vS;tj>CP;tjjNjNmڡS`~m^0+eڛSۢԶ9 $hޜ>7l%sFLǩ}ԾTqjRqj_88j?Na8ECEmQ/JEmRqK(D#W7WWՃA^Vɭ6 5Z\ Z-r扎8It|,nMgpm:=ۋвeC<#HURcHMŻ5nx->-~ }j_IMLCp<gCeBEbc1%Ŕ 4R{KYƱeXӚ-[?BYXy^& J$Kܗ/%/CϡG%rj=*{T*\l*^nEjɽj QAibQD%BLFBi=f#ޏٜ{f.&TBLU/1JV^'gM.rE4Fu\% 5̻"SHaXMvBo^Wϣ N@o^q}ks>eߐ{~i}|%dD'gSDZ8븦hMpZx4Z#C8^E;mk¿:Eh$h)#'^H5 wQ)M xO!Z:<;^ץ>P"}Ѐ#$/ PӵHkS4Gu9ZG#u]xpW֏ M VOD+kXM&S/!miOiOQf}EWѕ1Ϝzp4@h @,9pphs{Q_߂lfO~Bek%)IXIS.7\=Jv5&&u*z -^[˦W wWwWMwsߺЛi==rp?JxNM.ĐJ&t{i?\,}k|>՛M3ގzOGB}1>NAtZϧStF_靈jV\*Ԍ1%aZK53LO'Lze ]VsVF6Bzz1ָGa߸Ϙ]o<`<`K2|B>O?i)Zhk_.T^H|ED7"Z~!lyB՜$!:z{z{Bof" M:ᢿV(1;;Z-Z WДRѼhu֦NJ=;fA[~a=걩b;loO۝mNS uF8νf=bY`#T{=9:rk甩tVXG{\(k*yX>mEGcjgt¶;M _u:+_squnյ;9S?ןbmnS||Im67؛6k5%:-u3Ig9+q6yxS|}S|3ד5(a3w|}K&:\Z/uooo/;hmZ 4NpWt$.rvB8ҜҀYII2u@H.ԐzR/jD}R&t U^3М $4tm2EhGYȣ"忷(K0bhX#xVsy ^(Iuǹh {a-b =19b2=ۈҊD|Κ{=k"~M74Cvyͯ4Si-==>AVwޖ9`/N΍,8 ,`pNq1''Vk6=o Rp HpDk4.zX=3r%iueVSYk?:غ=oМ]~{gO-~qut`UFeT@]TK큎CIʊϲT]k3^*Jii&[+M^3QRx)A0\i"' d.-'ojSl;rb5 oj-vSs#>k+{%{|([wk8h?={n_{f=M%?xG?䬓|,Y>i液ΔM.ɳ&lPZy2,Degy|%+l\Rʰ a8k5ZdYS[`ҎYNpR\! rϴ/Qs`Rٳ9$rI܂3n ftiĈ, #F&fYDɲqsg}v19[uNs{ϡnx!2ܛ NyKouomhx4Xa˝ z)(BRLv[@oAo Us0zݰ);0XIP`0Ga_|_r000 e:o>y f v=KF~Vp-zv#2?v"G[䡘FE4XJax$MegbRw#G,>6Edd_{w޻{ӼXaY5S<:,zf:*̜=;Ky Ʋ"T4^/.Nz0!XdrXBko^cK¤\)WFd;Y>2 GKI2f7ۛ%lŽ*3E42 *`<}7 7be7b%\!"o D L *2 Bc7zk#023?-Rc#ћ3}`0pr P7n dphz?e*{obZVXAcG .Xj 9IVfg;ѾhN4'2'3v"ع(} n>&D UɌx V8*:e{-֢?!,`~13uE=Ѧ5F`~$,A2V k'Qmƴ1Ym XUi"Uk_־}JU7QاCOXS5s?c-?1`?+Ep{X$u*SyE +`D{?+V_R5۟,nTe)wrڤ8%l4ћ윔:5aXnuNnRw AKtn${jBFC!9tW-Ja$$$KҠ\-=*diC:q-lG*"uJG%COR8"ȐYp8}GBdEӹڮZ>+zj΋(䄳4 Ak [xkܛŤ:v@Ao93i8&f8' p8Hk};!i/<`LNx&Gw;KK҆')RfOmawp6Hi *kU9&k 47VnYk wɷU{|si6b*Η&y{8\I2y5>CLSy<:$F#Hn@E|oVTZ G0-gwBgHF_JfG V9$r..G룍ҰG;'I@"DR:йG/yk#C|T&Y~n964:ܦz&%FLtG)Gs͙]w!JE5ؕXAsޓxxŻf 2 8[ʣЕJX,KCR+nskڢKt9һJby@Byv,0$kB`j6uP\t7 &i`j &P6] NG(/hp]yxC~W*>:9*^\sH3=;]Cp6bP]YH=z*D`g(ܵ+ӹNݎN*E*޸ Ff;73 nqg}䆴xs"r..pINc`CPWȽ M (<< >却tD)r%"AG0 %]0 ӀZ9^N, ytT+v]8'Srr97o@|vYl3Ad&}yޑ-"NK$y{ju:M>yagkPwm{EpsIXIu-pIJld=oGS##.2y[d*-s>$;g:/yxDI |W>;éҢ\+IOBpy*,%oVh:4'l-`+!1`4I'e؃C`z_jNMPYDl DGS˨|. K@(EDasn~=6ZO(l'uY:٬04[Wf44viTLeb`O|}.%!csDtn(J疢q0~8&~qL\N14;4qDOM4?zx6?&^zGn bx)b3ueuI4'Id*3ԟRWԗxAmΊŠŠ[Š@&_RA}_]Ha!QsQj&NcxY 9|We^A+w4E"UYK*sz><|F|BYgk5$4#vV|ZU,>|_|W懚?Qzk`Go>[ۀϞ(L 0ZAh}I&Πo$ޢj%H9&R~H~W]jBh׵ć_Edt8Rr.@2Q.,bD%b'%LDjt5ĀVw":/HF|xqbqlj;:;Ρt.@yu:p1ĬnҽL,+2q_w`$Vu&sB]-t+įuLXu3>U>^zL< ջ~鏫.hboT\baWcX-F\0KkWwSLu햰%bK r_191xO=wWSU]E¿uUS06 FCk5DOL |q#1Q0esXMb?5nry&jvGE=ҼΗ5w7=Y&o7n} ߂֓>#h =~/36eubyʛr-{ޛg}9~wǻFF}j>CVҋb'z-^;)Ѹk\MԌ05މ8\π#z3%:;읆zoӗ8+7ف0o?Oa)0X < 6 gL/Ev T\`vubuˬnY#_ 9f{Y yR0 YjZxsR@vruea.t@ZǬ5f֌`=! %ɗ=O >dU=ţۦX_U*ߌo4_o|9`}{s !(P0 jˍg+>ΘE cמ0ŽA5u ȵ(7ۛ(B1?b2adUF[˦M]DwV#L(hڽWz@„wS)x]Z\ZMjcŌ+huɼ{i0Ƶ2Q)Hl@c[C  K>c@bZ{7U`w >eo8 t@u+|q,܁L 3>`EѲ;, =R-N<+4Ql$v*A&qJ H75aS`.sLY昻yq+R.O Ҟ :Sǟw:2M5Bd"r bbFNS]aaq,4xڙ8wNl`u#,y11;SaZai~MJ柕?+?)q*!WZLUC~=[2W97$[іZvho%44/ Mݖkşܶ&}yI mF1Vd/u7Vjz:bݱZ6 Y 7nʐZьeCs sܢ 7؁5&#wj_l-Km뇑]L,i,筎'Km_4k-u`B*OX]%KPꭩ0i˄x=V_r݇^yŒZZY7/]϶ 4OKxk}u fu%Ik hu,FMsuu`ݥkK֤NC𺛽޹cIp:ydjPl6̶ɶ$TOf%0'u[⁽bMbzs֡Y/x0SfYb/9y%54̉VBܬ2] ejj6Ҭ .ě|v^u:Q$ٶ%~ޱ̥ƅZ~2l}PrK)4q0'\`íuB1ifȟ˄'|!{3U%Z cJ?b1F{ng'R!h>Ixt=&mQ͖ m-amL8j%rU岥^kFkqJ3|-ot!P԰ b]kX8=ၰQIQӭ%4r^oLl%\NbDYRm[eJ5|cgklYZIv?isZ潶!{{r\-kmH׳y oi+ݰبf%ln+ۅrsm6j€ Ro2:͋Z,XV%rzVd[&@ؼh[J-)-vzϼeaczv:/ h^aƁp]E+$!ڤ_d]{hg_ɭ(;| _0g0\򿒓G#x6ow `j2:WbYRu)nv ˆ1bcYJ ȜQT(a "VdP(5J6l겒M}Zɦ`ly%WlXGu*yTGQJT(Zɣ?&YEeMx7 ׫6w(6oTk6o"ov yYgG_CgEEQYgk3>:_WymEeUTߠ S*ZCC~yF<{:O!e׼yxeYYkoB9Qr*eHG'Q6E<)eSs("Q6E|eSUȦ$sRh%EE P+ZhS>hMg-61N`?Q+ pBQ lg~{3 9UOJuTJr*!zʦTCٔ(RUlJ,ʦT(R}Ǫ*yUː~apSpiC!s"Vq_aW1=ցg*:Sp5,clxm<WpfouÕL߄{QTNÕBe;K%< Q?ќ_]._+[ZOS\!B.\9WsM6@]f.SIGnG.q;pwߢ>*ww^zu=:Oc<~ψg$2iLsgn3}fYa֙]}ҡOx{bZA4O:s=#tbON>Πzn ѹ/Lr]Ԇ)g.Y@sb؋"fg+am4#2S62W=WlkaVX;Kúzu;ӝt_r_~1ӭ^5,ŮIk+XU{}=s/6ާ[o! un/m?4.z%O{%0?S}(nqG=1v3rML?-w+lb0622̔+Mi^f2du6ާOۥ6^%N+w=l鸲A݀=jy1f\UΑ!z&^p&tI'jҹ1kCj-Zp8Igzu\%cy\xʙ O g3Yc?L-DS/(7f94xX“3X0s1U:S$xQ>af۞=H:{Maϳ`~c4L #xžG$sSv^v Ϊn{skE.[ݜT߳8)8hYY<\˥+zFjӄ鐮baIl=c/ #6-cw{qM*Xs_oܗ/ݍn͸>ùcjnP{=@jn5a)w7-n;uevv>dW#9'sW*Gfs87mr5\63n! z!s B!ɀ1`,.$^BqVqCX0bEXB9,\񲌇!0 0 q㰄e)NݪԖTw>: RYg+Vuw~Νν.W'8"cr\&7#;FRl*S ƜM*.]LxǖtiŬ-ߵ5t̓$]Kx<$ngeoGWefTdzKccpRjE䰇z=nV#+2(8A3(8Aq 0(XȠȠ$_gPA .fPA% 2(A:1(#W0(XϠJldPyPR[ v֟qBg2fɘ5KZӨg0w̻_00~EZcf0o~ü8@gl/ - `R6I243404 &2=n2=2Y4&9&݀s711'ofboabט&ۙ7Ro.a"L'L~ow<3Q¿aLӈŢ%+FDffC23AlHaf6hDJ%KN#J(Y>hSr>ed!@jJ2e}.sѤ G<"YG>Krp T\4+NH*d,I6`}X#KV R0}|nc5cn]YIytկ'!r%<YzM>v/;v\^RVF6y%J}w(Sx7k(pIpO(u_aNOfR-i2`kn0EX!s؝A2g6XH965GZM; پe}+ꧪA^,7(㲓OX5eݶPɽQ.[!?ӟ[aOFQ(cWn%Iw!o<wWq;#E{55xE8kT5wf2O=(}i q*T^b~'ߔqR +SS\SA+M/|K4io"_C8hZC4"J lHm2c5.{G)3ϼg^hrz귌F1xV<"%G !㶯$ǫEz4`(2˳et0ԷiluF\yjᣞ]d%+AK qMa4ԷsoONOvU cTŸ\2 Rk|9ffuv>7u._:Vw;chSŝΉpg"z׌{uB.F۽ QEo%UB2XDQC2wG|uuKyAPC n|FΓCIy:t!h;0, 葂t!`aEdyiܤ(.; U^e*FVIb|dZRDM.@E1+3&\luro78-t*B[/\!LWk̵Zr\+6UҶZ/tLgƜ*e +7UDt 1ੳU^C(x)E?i5%wD8ۦf۞--V6 gVe!D7gTJYW3P5p*y-P-%o[+ma[ bX"˱˷ZH-.-s'2:p3әߺwe6QGMM*[Ks/O9ci޶q:io:CݞsJYVD.k}4klZ44ڴ۴V;ںWIT)9}# xnZO*oUvJEqtxk ja32m)]BP[,b׼jmmma/(g!о֝}|+v]&vftHo[KB(*ꃁ|TKC^757| H;vn%.7l,bҒi H)HItM@C@M+< QݠukTߢ#^Y@%X;Z1.=Xrcص퉠[\m6}[umejIh%s] @]Emmm=mۢ]<ܶnZ i媔1ul˜ a~]) 5:ϦW2~P/~]  ̆9M&U_jbrXUԬP +ձnnAfmV.T*`@UYBVG 8㉝JJn&7`=LΫ?d-oP LLnaoXadoa2e 1ɔ5ngw@.1Yɚ#&k*5L֬bfm0Y~dbfɚu9C\p.S.ąes}srC'<f3+ED6慩C0]XFx^Z#x~׫R])7}7۲|Lͺ3IM5Fy{{!"G<~ C|eIQ?G=}t5?QL+sgc<*A5eI܌ FKt[<$|" }- J ϝ(;QM'`쑾_/ԛgkD- % 6M-|H7l(Nrgi{inbr \ 5$RR+jK'sǴ:NqNԙ-,=Չ+.n/V=aDVЍi~ ZI_9=%qѭ&A CWԼҼBSͻt!,&4m: cO 6/h&9znI1={`p>}0RĂ _/ 6/Bx ^ WU(^סMx@~S(8g?U t9o ;($?>C?@E/0{{= cOO8{{=E'ٓЗS)ϞfOCWسY(ކw;P4{ ~~ Ű{}>%PW_A?gO !} %gCJp9\(ǯ1㸘ǯ3㸄yd8_/rp$|e(sssrB78sއ8p>9q8HCN$r!\\nr)ɑqdPGΑCٜ4Nt(ns5dAyP~ZToo@_ ބ}Yaws"?q׻`LloWv>R_Gsvq|<>i;G>ö=~P ٖ-َyo=q˧%:G bMNFyRq0D$J?(Q(z9egdSf).֨qsjk+FfA+mvۀm-8&l˶׶s[>r. mHwϕJn. CxSS-QHsԦ>`T+feaӊS}y`iW_ܑԾs߾r pqRĚ; GfuACa}LV0_X\֠P 4/x1 ¼q) mȵ,g5 E c[-6lڴŌ竞^G^fąM\x7S)r9TJNr0\+pW<ޅwKz vp!.M5oUλ<<&ҏ .'d3eRHR$CYϴ#u'8 _LD([mۮF /3|VIY͞c[vCk;=zYM<"6mv`+J1&-HzJ`YC4ڦvoza`Th?ۺ]Q$Hfṯ ZJ7"oD^3ő Tf6+kX&#FdVj2oO5 Ќ3q2h! /4/D2N +2*Q . h5h1Bu,C' Q+>AAgxf/rS:AbHVg R'U')i]_O&łŔ›Aq1˛AA)Żoof /*XkU-llR:0L"ɍRԁh+Sf>Eٙ< 1"@sGkRG6ha\Bן,֟ʓ=k3S& #l4=y#c@G ˺19XgP# gm2[2:e]XD}Oiht,Y,W 7ƮSB#)eꉔ4|L~˄؄X~B,xC;nI%SŚԱzB D(/@TpT0+ƶmZIVȖn粥Yc$D*r9N(fE$Ə J)m#RPQBGYz.v$[RCHٖr3/x_R6Chytv¸$5Jm1Ask7 eBh:,n*o ~G%M}"X-D0nL 8~lH|BE%!1_ccr֮[{v) `DH)OjFqT8ɞ3 `ٚ^@Y4U:~cPW8U(/TNj ǧRA1bH]suFRm0ʐD/:\4P3X(ռH^q%髯eIݸ)Ԕ]iT3z-QX(:"O8ˋK,%PYz5a~_tH@˘:jvE+E=O:L/'?M)G=8,MDD EGhFki]6fFdr=EI)b]݀nnL@Z7D\1M^9U'GSGu2\NLO|!U\}vB:'ߕGE He+nJ$="uW'IO̱DHǥ*+U_M9IןEcWR6,:<4 iՆC2KOLD3E&yF(E ;(+kwWU"AfyC9$(""$8$FD Ab""DڿI߽Zc{3]U83izeE^j ͳ$[?kI'JfH>wYN;M,ZܹgZsr2,6GXhCYs+iӾ**3Ku{+mߐѨQe_} zf{iU.ﴣќKXPҍъ;*fT+\}u]VloJAJ9gY*6n=XvUvUֹ{r6)iSr4wO<=;ظꑟ8sЃ%EVe. b&Gw)ؙݢwѮX]3MM++g?!}XykK^v8=ZrzEU+'.^WO_9eʅ9J6흗><`s֖[*ˋdZ0.-ï? dOnnv9Jd_ߞ{4~dֻ+j竕 LܚUUSZΈ)3aEz--ݗؑs~U''#ʗǪԽ'3NFY\VkY?1,sDO(lUnyEY]ݢ.#:k=}iu)XtKG#s4wto 7Ћ؛y_GA>a9_դ~/4u_ 췑p?;4^z^]9n4o >{VNat>Poy1ӣ^~ PuR>j?OL1~֛n۶O;jv,@y[cB'eB> ؟P"'? Oh2'gB'tdB''tfB'teB7'tgB'\OO }؟pԊ_~s?o(/e?k rS{wON̦/%5_WPCyUF{-<'ɵu;#oGEg?7i&FfoHDdFM.)G8M;,E^PʿNj$|؏{Msmyv4q-S][~Eޭܖw+nޭ\Ȼxr1V.ʥ[V.yrޭܑw+wʝyrޭܕw+wyrޭ|Vɻ{n޼[Bޭ܇w+_Ļn~[ޭܟw+y ޭ8˨r}o|3l˄_m9ME-ǩy[6^>_fO>˥_J=r>ezX{ae -m꥖+[.b:rq˓뫟\]=riJF+ Ok #.cs&l i#]&s:fՋ8n Ϯ}4p1sucxiҐ" p|΀53m8&RI3_׮OqᕐB8a)y%BD&`i#Jޫaas+r7x' @@Ƒi 8RrpNj5Ax>CƎ2fK0jy )1)x4> {{}cEJkv/GkIQg -$"GSG:@MaħE|WKO^ ) $.4f4^`O*OOR[Iy7rw"[{o=OxTN!K6IѼ_ ͕BVo59OS&g5aW'.C~ 0W`^ypWy-{ x4!w&:ʓz:YȹϗK`'x.Ep+;Ë`kJ8Mղkj#Z S#ȕpR,rJۀ~ 2mO$7T3g ;.{9zf,G:_5=Bz2AIVÇ^\^?mi80܁ M`]xeEδ$=}BZ3H?Д48a҇=#r7&dZD Ҏp9|vGv7uK=nLV٣|"sz ~VS,+dfQshJR) u"֠yjo3mYz3&rZaϑN8vAzT oA&>/V] 2̒2S so9E'mj&9k< smk,<$%0]BOkmyya[gT"uJ|u\ZG)PW"c ({!WJgF=}^KMZQ6iCgaigU@ƩU*:ւ,!dLIװ) ,ּ @O;jud@z$ 5 dƣ~ 6 %7~#\QARbjlf|1< FxBArZWʠ;Ɍ);o L:fOAvv~qv,kߐo?/9 6z4Ԟqw6 {иGc/֏r8?y XњhSkh=>z2#9kT4ܽn yqֵ`4nM9\5h&x x(zk3/(VXr漚;6B|NFtEGF8hu m 輧^#%#"9NƔ~ſG 24=9p3 r+G3ʱfir&8o/p.!^hsy9Jx\r<WBu(wa߉|%\} lpG9sK_F4䎴˹; i2x]֧^8`?rlŹ#KѐR}9:v3`~p,xg?QF @b 24)\RZ}?rGU0L"|47"0|S.1(7b 7B+˜xq'0G.~ 1Z}]B̈8LW*4QaixpQ; ." ԌxbV4+bD+u1^%4vc] c'Gȹ>+rK $9ˆG3s}`73nhaVlyp-5YЭhh _5@|C\lfm4UB5z-Ʀَŵ\lA+GsbT#XwH?T.Jy+gױvg9G**a z!ZFX_!i8͐CMu+j6LK]=o~RVSآʕn%_#N[B"xa:W˳ 6Y`0.AS Ϥ'cPa"W{HH>!%7ؓ! 5$J0~-Y vP+3~JL).d B4dWVwCy =ٰf斐 :k)~VZ;J:gXx+q!t>5mgYюK8p?vnT,C#n8.4ṉff6;i%p9eN̠Y"xjn=o;\[;KuĸO o֣q}HGCf8{&54ZخX\;'m9F9#Z 5X)X})wmɊ :b?3m,@_rt1w.4Ä߰ Vp)XWNCgm:ek[9zeF},GjǔLsv2G` qDKs>aaf\YͼC @=ԇܻ$;6?RO$Xwf6 }j|q!$M@%)؞,)ף'7p>k Wq~ ޟ]7˙߄m!>B؈z|UCz2ͼ m~^ \'X%P(bO׬;2BC 5:p{r rnѰ~[>1<6̙DG[w+gqE4~qrU)A oÒDPȍ`3aWrnLIT1;rnx& D+A ,_>Vjg0օ֡$nb[hX7_-jHMgÇXGsw ZzߑE L)'+'s>y;2 {TԽ>,v"D:\U_r4̆+#p3> vyEh$2^lsȮBnu"?<4ɡ2=A&Qwl &d>;HMZ+vq)_ZJ h>'|ٕGIHG>BIoφ=965P+F!\Eɹp\ɓtxSseg~8&cD"!>175RQ#E?SmG|?P_˹5u9$lZđ:RSs>\Eo|̯ǡQKZ'N SNpʆ]jG/SiOJ=Z-=gkS'{$eؿT{o#m=TV[XCgȮou)|%1=ܦWكz9'OmeK^{MEs5s5ғzr9:d+?q<ؙsD@qȻ,qu]?YEͣws/moG~H[xZjY i޷<yĵm? k]06%{ /_ K>'Ez=3\&5.D(I7r\n9}nBn#EtKWJiյp~/W̲ {Օ;oEG o4k|꙾1DNUհ;lOߝю{Bnz#y&rS$D5h8gL#j4~v抧hEbטxByK4QbkEy0<$)Cۄqa\O}n7/[gXZԒJ '*-)Gx^qOxhx< \+292#J [ .@Pv5~I9fy_^S=ua*Į%S,B𝃛IHOGR)tiY&?9 g@vmE#Ic|;rO@P3D<S^C0~+\|+G^Mvq"K=y2XADZc x;nl ԕ 8*3.*rg4K4 ==8p;@w崾h W i)#`{xyI~.r[H`]o s~ ?"7SZ/ߠo ]\ /445#Uh( qO&t&+@@ s֗RћlaZ4Q D[*X䧥χ;~Ӊhd%)4ܯn)h"[? O_BM@O/5U.H4fQCw =nɳ%Q E“֔coR$6Ž$gmVv-7>l/2BvDx&:o!kv) scf}5=HմGiR>@x0 ڂZAj^1.T?L*<ݜF)"EPw=@^iAfj/ѯCf,Z2+7Byg)dY)|O֫cЫ[#ѻjS3>Ot:3g = Bv bBtu=3 kv*AMiϠ2{Bexٕi!TȮ!{.|kأ)t;XL@Ipp7(g'6J'M:IC9nn#2}[a3(߿u 2֔rv%/yhf\r_XN֎hMvMM8@b֒,>&3KZ ע'vjCC\\ м q5!Iubuu3xk>O^wN&^8<*?VՋ5W4̡}WO:c#w<6&%:C|;y|_][+^ ǗW"lWw[<=)ܫu؟D9i kߗ{qǿ&&W #nw=o||w #_Q<&#-G^-_^,;CMmC|l3~x7^[3}ϵYx[-rgÉx^(Rx?E\gizwśSv_ ἟(&j^i|d{)uRjyu#?x0oYiǜuc ,Ǟf א+ p|^f@fɆ9#aS'V@yL?!J@Y(5("i͡g0  fFm@ jB}h-#Ǜ`8{*^P%t0t, `̆ ;vzYYҫG粰s P@mhBQ; `H=oa:t:p 4\Shoi+͠ Ie.V0E-!P¥ڃ[<<`dCI|XU/7K ƀc cyYòz31`5,w8qƥ+&L3ne|ywrĈ&dƲk2cl4*gXj؉pƉWf=Lcĸ&0c鎀ح4Ѷ_VE~=w.ڽ8T -/5{ mW)_4J>Nfw߄tqxX좱?`ыɿlW)(OJaj5_"T]d{j%U},rQ؄RXKCq5c[#p*.5}x?ɢHmE/1BLKE< l";r%nK' TNj8y*)_bzfz *ܴlN'o\x=ehWoMj]OT{t|g+6oo7KWߜP:F:MQye2{J/> 7ך>5ov/SxY'ƱΨ|4*Gj]7)*SbTy{UwgzXo]|{r0W{|zͼ}>bQ3 0ET,)*+ʊXZVU!k`9U b UX5 X9j7Ij:n{pw7fy/-VCjo5>>oynTQPeE ]^W"Jj(Fn4\u=@4ЃPE=AO$ ;Y_#:kb~K'SqL._/ukz#'6km'tM2=x\'0's|$"RUdWpF9ʿ?+l)yޖTYesUfTSU&uݤj}վnmMlߵ;͞' 9HV;Ԡ/(Q;rARPE=T jG M c`z< ԓ` ƫ A:L C$]E(B#)6z<`EnRSgQt)B:LVe Qt(W3㘺)s薶BGǹ>I.OQ(Gç>Y.Q= \r';{Csh#\ _ro {ݫ\>{׹A{idhQ½"o-|+eމ(nD"ʼQ䃈"F(ȉ"G$ȧE>(yDSENG"ȗE(uDo"|Q<ju)r)rR仈""|Q|D"H 8eb"NS&┉yqt"1H) qbqS$H`"Bq G9qJw%1Ċ)+HX"qJ)+Q$5H"#(R.H"QRDeDQZDEjFQvD:qĒEb)LSb EFQ~D"DiQQDEDiQ҈"#(2H"m"(.HF+#t(1L2#ʤ1E0E1EZ;NqL\I?'GIH DHE!QDe3-'ȉr,+irBΐ3,9[Αs<9[[@-9{Ij,yߥkQ*7fy"[?_=wOp=Y" /֠liyhO| IlrF]\Jov Qm'ڊ /ފP@nkjy^ Zy\'$˛1= ]|P>H 8Ud{Qv),9Bh9Fww/(ʶt2Aβ3(y _G~EJc{~o;]~_?GS)}+F9>? 4"-e<)) Lhb&$&4Lal)nJʚr`*JbjajZcL]SԧX44Lc45̥iaZVicښv&ô7LGt6]e&t5Lwz^c~`Afb.7C03dfe3L2crT3͔4)mF1fgƛw̻=|bEs|l>13??O/3W7Y2*Ym m&D[&ق-lآ-nK[ҦRj궆ikڶo/ lC6MlS^jۖͰmv]e6vlwlo;{j̓AˠU:h AC1tAנ[= z>Aߠť`p0$ŧpOGPt:*t\0>Ȧub0)L r\TӃ+`V0; O "A&/A'?& v.ax/,3%,Y%.';s[[ynmjZ7s-z>3Y\ԏ ~ܯލ}*>W| Kv"2t _t[k2/*$( m.]6-(VCih[-;!hn9Eo*9#Ey]*[:E}|f١}#Q0Đ1bȥj6<-xqn~t'*1|oz/Y;ӯf,lUQl^ l[ܲHزdȆj~ Y_-U6ނZ3ay _xJ3DA}$;_/!8g'fwvͶD;NSl͵s<;. ".Wkj{`Z{oZLKYǦٺl/b ʶml<i=ϼֳ{ߵa1wV~8#GtOуlaKEs'Zv@`!zjG b,DlV6f(Q(To z8ojo7y?dN0Q amtuLbNŒ&FJw.:;nfMx=G\}n;L733fY;" 0+j|0s |=ėːWq|QIW[dn܌4]Es=ˆvvnO/u,3EXt`,:ЋtE#rW~ ꧁uLPgdc_} 䱻KB 8&nKvŵdW]׸#`븫HBd܇3YȶmНz7[?C?FWk5Z~mFw2G#Qh??`іelY[ΖlE[VmaGQvcqvf+ ;β^er®Uv]oo-vպ{F]F]F&,I~I)kKr88D7QȚb%L(ڲH]yߧ;fZ1acߘ'*!Oj[z Jߥ43I+5sef`m6nOjDk&/BD^!( ѯ8q()J)K^@9i ua]*ꢺ(Tt*PEiPU[!5x-PM^TWU@iz :[Odgz^(F=+:FL^-<݃g'6 BkgP-xZ]e9fEA3t Vox?>n|<(M|W/?ɏjڪսjOT]-zO}3uJ}Qg9L^W+x ^%Wͫxtk5{bcGbGcƎJOVZ'z^g$~VauDU^z2rZh>fa}'{ AjP>҃&%ePDԃ!錣f:E0U$M`gp'G7$_Bu aŰz6af+ GaN8#. õps->  #xx2< XKǪjcMb-c3}UQ b<(Nh #NBb H FAdq6DQT@D8Db!!8E߽v41uV{]>CoiQ0$Êcc%Y+X,V>UǪ`cbձf Vx s!l[6=6۟bfO`OdOfGcv:{-;].fd+UZv"ʾngwrw#8Njӛ33333ƙısb8qy$N2g'qJ998cS:y%N3syĥq],+j&'sA ܉(n,7Mfs ܽraqn5Ƚm>1xn<OSt< χ׏7 "yѼY"^*oo/W+UyF^ &6)wo{m|???͟ȟ̏ )tZ~6_?Wk Kf ~H@ܲHA```` L0I`Id A K/( v *ՂzAEpK.<<2BP&MBOM'cpa0Z8K \$\"L %2aJX'l6 oo ;OEL'T"C%- ".%/ ME18Q(C%JEEDcS:yQ薨]!z z*fHXY,\)ɒd)Uu\YDSV&; ;&eWd-۲{'rMΑ Nnr>1u:NS :nnnnn.L7IgttId ].K+ҕv*tttuKf ]SHOz^5zSo hDd}>V__Oѧbv^}RJ_oԷ;O L 0 i Caaaa!gX`XbXaXk5J cS:y%Cᆡpixd<(0ʌicq18m3.0.10f"cqqxxXg0h`4:x&r -uEDɨ9䡶g|V#bԒ%xqsDZ:1a{ewd'z'.iIc:_7@}(pB<rDCL͡uĦr̓ 9c_83 z!6WG +2kè,%yzdj]rW\+ vŒŠDuq:ă-~yC;dX)9Re5JG*r!EAJK jDRH2ZI\3Ulq2R/4%d%Ւ9j 9O @WQSs}ΰ3Q96db+a5\Ly#[V֑I"kfg45k gB΄9 rصˈ3R٧C{68q@ f`J&TT5ocdkF +șu]>+󞎝!V3JsVv5ȠvNC֠X yCZK*O,:d,+Az f5QCG2ɺl lĘ} *-'d.ZK|TN P[>=&p3ݤn%2Jdߥ).ə2܅.BdgiW"[&wq;q-)܏'99EEB6]#c/CMx 2Y=NZ:NZ uqe`}AD\  +q2ȡLóhH'x'xƒ';#>;#>;#>;#>;cvv*V;NjbSکX툕;!vC츇qb=Ď{1h!cFш>G#h>cAAAm>HC3g 5j18cqPqp# 7[@2Xcw,Eܱ;qRDӈ<cXb_,/=ģx O|v>Gtp+ d$|DooooooDj5J(ZDj5J(ZHQ$(k5Eb"FyUPe!UQz,,E `Xbt(#,B,TYL%T5T^Sk*zMEԝq* *r=USe U:zE5\^sk.z]O8\64C^fSoׁ<Q[LɗB ''D\K:uԧg@RP{$3ыQ :QI߉Z.%8 !Kmw~͍Fw ߡq'K^X77hw*a ,< /Έf0bij{qoor}Exy2rӾ|L.?_na/_XrE+UW1K/_Kp:Wq+UW?\k^h/~ϊNk)iZq8ikiٴZ1q凌ӎӪv|[4__|JGc;]d`~Bwquk{cgá[Z&%/4ܖ, s+N70Ź;ljp"\ܻЙ :(6XDE,#yE"N%nS7q/8cj;ޭ*S'k68v!dQ̜ۖlKvUD$" .~gZM-fWa츅ӧE'>3ѶsE8q2  7sϚ@tóqHuTٳs6#0ŋf^ucnKl, LsJsiޝL.|һ{wCs7-6mW1j|dgd7b{Oxk޻65;c^7=\>lG#y23iUf׎vؓ5XzZ|0hi򌲎-+\jM}v6ᠥRͫrߏ\U;qǩuVO90## 5D[sOZmMcWrωDQFw_;+e˅#SRi%Ӯ-e#_mBb:f&Fl]ggW''bRKg.ͷ-Y{|qE3o\ ڇ+ߟ~}K(ӟ1mNDaS SիSzm r֕2(#w]nK^#:xI~il w?KKs_qRϋ5/cS֔Mcy/}ɗGbcc[["i:{ؖw\QG4G' }x4˧zȔ$K^$ AE}F'$ kJ|k5e^q3^qMIkh-yt:6k#pr85O xC)Gc;d噬.277qcMG Ǯ_ _ȟ!O97x\eFnG^:Ԟ3u OZc 3O?XSC]vI!M3?wb@a;w'.)΄-_=W]oZT嬕Llm{]sy6dCrm46A?l&LP>mAp'^F.:{oTm0g#q,w>yc̻_ ӆ-V3ߓ{ټm{%C3a̩s"f:}g=6`YmCv9"3vُ}@U;6p՛>p~pclr֨.?t%]f!WCyδ9k?|iY͒bx[&zĹzYNjʳ%IwdOp}*Jj4YZ)Yde£}+7vOc7]^L7ׯz.edzJYeA ƴ}`ɘ8oČ^u\POb:^8(g~-P]o,{Ch b0YwZ=)d(3?Q8UIc36G9↭;w׺8|V1.dvmYu`d^9mNņ?ƖL2T "c~'~X}ܻ6koq<%eڡSN]?20rn~ŕrUUSG{X &s.:eƔEؾM>WٗLqafw3J3թG49%|y~cGDROCtOŷCCݱ-NCvA} \gOP;jȹNt =CMH|/ɗfv:=.zj.0dnXڳOf1&cBJ25~)Svs_qiO,o6{tjoS~L]]s:1%z"lj˗m1gư[UQ?wJ.v =Tߺݭ ]"OXk_bzd{}v.ziO{JrS&qAv}}a3e[Hѱ:9YP}9V205'2xxgƏu:ttC~#5YyuD]6{lZR'n6N~ nMoѣM_tmK+OL)anܔL鹧W/._uZ_Lc[|윢 WZ㶺s25i}Gy>,hEN󁕿{մ+~<˜hqۛ|Vw.87k+nt]Q>vD=˟Ue>_yw|l>s u0~wipڑΛWtLahftxP[ɯohKkWz}6fnAY޷Q|qP\;e¥'.nV_n\;Cszh+C"yĉAۖ^zȻl]Y/~FۋbGC7s{YkjM>ۭc_hM(\A MMf㣸(ZMG@[H#^M#M[ٲ4aaiq {\b&io?}2tT{eWm8۾7Br8Q%n}m=է?mĆ7=_k\;/ү;F+@I>Q`ѓWEp\}[9ߧl/8썓HѥvV6]vl"'=G"ҿA-KNPr_Z[;uD/[oksON$MIȌODžӼz~9'0@z^]Qt;,%CȌ[1RK7:tο<@sBYe9Yz^MmkWpGg{ endstream endobj 477 0 obj <> stream x]j0 ~ CqK{cClJfXd8d/t0 }i'7'8-B'uyv2QiuN84UנE{r!{ayqBJP x5.ؾus|068ȆFTu%@*($Oߨ~_xX{,yJCT>?!oP endstream endobj 478 0 obj <> stream x{ \TUsaM°o3 ( *%0(03Ro- .[ˬLU+-+L{f00 r9Y<9 .3ǫqq; 獞 -XЄT^R9gp C%ڒOhaqXapmfba啖9!o2 N{INCv/ \RJ1q6@i&‡Pn֛l~n8vY3λ2ikY viׇσR<1LvNYGZ_H9v Cұfܭ4r@ U]0@*>DGIJ׉1n{Pʸ;b1aTˆ 38\.Ie䍅JEGh&i f/C_i'*߭_M0=RBrk{理"{KX"fYwNg_z*A25D9 vpgDpAtW&u!;x z'x7 7\91!BrC0#r!@b("*A a#!Q ш1 U8xH@LHD$HBLd2HHA(@ b*`8 A3 a`8p?gHt012 Y0q$/(88"fC688r!& NaL ya TĩPX4t0^3ZցJRR(C,r[(f!B<a6bT VBL&9A5b5E3-`AZ,BbA0q.(·oq4 6xCðq1,A\K24,FFX+a%*x&&r"(F\ !>xZĵ5<O"> SOW4 <Ќt3ql俄 q<__͈a Vĭ"/!2 X؆ #n;`'9W_]v#`xuqG~88x@|?7!x -xކw߁w.{p0pE< #??cS>cH##/pDB ?ēp F4A<mi "Q8"-|{x~@.!?K3?Q~A/p2\UkpW :{﹁ xڑA'QXq( vXwNn>'J߳I仱gvwd#^ r{ ݵO>gßzL}>&7jع-lpsD$wa[lzLw1{I^)yv\f1z ;83rՇq)K U }o3}׻^R`-zfw_rz r왭Cls/ O.lꙭ w•޸MpC=ݻxuMwb";HO)gvwxuMw%-{fwگ~0T}LIAhS}Cl% LpI=k}5s/h4gvne14 w^3 뽟>ǔ;H;83z'"{IyI=G&~t5/ypy=k{?1}K*)Hms𨾷(虭{? }{bM8&⏷#C!/oW=nrswtB4 /~DB/Tr.{:x4Æ 2h@D*!>.6&:*2"Rr֣JLTLe!gHEЌ3fBB[YIeY[ޘU83zy|tD4aOdΨ_eSf *X,mu⤂̀8+)auU J2R*3r%@V:(K3 Pr3>s|bKYN66.͓ XX}`[&|dQHǡ4+yEr%U6,S4:(G(g7Z!>df7 gqe6_'4op~KZn6Ƕ '箄VhuνY"hatjRDRЧ@.a*$Z#b:d5* |UPrW#@yBwΑ+@ qr+ְZcbfh~@|\m+4)8|`"V[8X xy1c]88`hTVH(9Y5Y(YYry#y^VYĭ?WGV`+b<;O=iZXdmv~=>](€\X{!!E d)G@lMm,$2d 7j?,[ { Q<>&NS( ʎYi;-iu/Yp AL# xd+'㟆xly!Uqp^ xL /(gɗ0I0ˠq,!xغ?O>xNLj\@Mt0vf8! dVxBӅ72Q'Qy~.3a+Z}BYW G<[_o;R/A{њsX x5:9u>Lv,7*a,h:Xy2ƙYOHsƏ o Aj;fzDYd B1$,DVՄۊ7+8Y8Chkѐd2Iʈ%VE#@&2e0Mia3m/`65[7wُ/0NJ"F*LtItY!Vܾ#c:|^ALLQ oՠU&zhx}'xUh1Jޡ +8-%"!$$QxMq%BC?x _he3+Sns Gg%8(6Nge- IYv=`1jу&+wDCčxY;{g%IIU*:`;-#YJ^"X901 D*5 $3TVGH)ϰ X8""yDRypS&hō67:a3}3_H\ lbLj ZǘTnD3/V&`+6gP<+i?pn2p|)ڵ`aŅLl"l}_OnLFd~ ~E>LUCGg8p7gOypm*eY! T=Hǂ\"ֱ, ɢS|csƷ(W4NT'& D| |a. RV`wѿjE=fW*iÉ{jjCF ?09 RO2Ԟ}(@2BN3 餌1n8o&'$h4עf͸HaFE g+ɉA.:AưN"G<O\B $ He1:LXvhDi?sf^N('׷; S\nx=qxZZZ &^CK|qO.OjC<${C{fsI=["do;:̺ ۩_!ZQZbU WE2 YR UrʠPe+]>|TVbh||=}||Ho$с*/$ۋQEF8NO$s W~#!;qCCF,}Y "-M@TaR'vsM,QM !n>^! ?BBH2T*񺭔a';S¼sua'*ۯ7ޟfk-7Nhf-l}+H4 M؟ pN `CÔ$D$#$c*:ɩHw%/D%q{qWE^ )EEŶM0|/*ܨ|Ri\DDFf NFF(C%^>lSdD%'fXF%fY#ý慩43gz.7}/~{<ӥBٙ ȩ?,T-w]3>!rYm튣'/Y 5HܵkUQtĕӊ3= ^Di 0l40Q-u6%jJ9EU81F.6M @F&.(Rr N<"I!=00ZHl"͢E0&^/ '7pjԒ` A(xd{/^yCۧkW4"n`bC/~~9)xP͵5Qe̢zpÂ׾F/>^}g s}!d7dA ?'C"6MAG#bǜ8cǞX{I=O&U yn.&O=uLo]g@SoyNr̰Ӣ.uNW WOL3rLFz 9܄ܸ1Y9yY\ܬY9rgy*k\ rkhv`qYǥS/ SFg+7ʻŧJWQSMg%.5Uqqn ќXh{_U{TV/FRmqE<6AX̪6c]UQU(*ai<k, Wf)WnOGRȩ*q6FJuTcJ-[ީ ʰ1QMtN6r:Z*6Br0^%Gs*6:w֦S3r T :.vmWd= >첄^(d2w]"EZay«^ cL뢢+Q тuT3!gݴIU!D`!0F❁@O@0sF",! (Yx|p9 mcZ[zk2Xk]) #h=:KLt)A):ڣm, =ɵ tVU`T[tr]Ė p*a+[nPRQ.z:zҫ}K^rkf Ug Uvt` I#osUtRݼj[Ìv}UjkOΕO9jS/cgRg&:ڣӹ;:St7ﶻw?uE$JeF"bm-(xO,].]V̇,}ڄ^ iI9 M"qY$u5M|lrRy]w!Nqܘ*]Bb:&(:eyfAh "L!MGr_⒚K;r~:yuvƒ~_~8yCe Vg]tau/0_k+;77~W^잙T6]۸ywS=RtAon篇䒽3JL`\(Ds'?U[ΞyqE̛C}`fږ%VxCojmm"? sa}{? ;qhu3ZL2Cї־kο?|e!ۗðP/\_"Èμ,:)O0+hz‹dj >t,NQlߜXmoZehN-XE` W%!D>z8c'HmV׿+x#_'cox7,z^qNHX[bkL0%.iyʒϯ& xsdܗwiy{jOv>o-ӳv~2$7 %8yus>K}]z<̌?NGuJ8BUxЈބ e^䶉Q|C5,8Ժ^xz["|xM=g77怘h?:zw~j N͘_:`16d g^^:c4no:6EwnBa3K~38Rt]sNڜIUj"#_JO\7oYxXk,ڬyr[G_L;gd3;%zʹ׽FʏO=Zܭі#.m}pOX0Cdl<^_N$GddSǨ#i2ZxN?o:.dJi} d鋜\M~k{ۗ]>篏?\v{%G42?kģ["WyqtS?񗀉a ?VV^sNuǿxAsӯ,s[7>1om˵GP0:K;cuktv/qxuI2ymxsyhܜԾygyɕG>Wkܰ+qˏop BZ6_{|Ֆ}Ϙwi^R7q ͶAXaWuNjzL+sn3l /TIh*L ХHY( " HSDP#EM+^:"J]{g?g?9s23ya VpH4|+y=m5Y$&z\O  h&dr7Or'^cJs퀩hVI2))pՋ&1/4f }[ I u.kptVdߜ>蜔"إxJV{Ew oB^p(ċd~&8)% !ĹcTpV4a46͏EW+N6,Z J8meRYTc#bZs-o(Oivu҉f.$TBQ($&ੈB%a7X,ιP>Kl0bNg<=g-Y7e7bb;k⃦FM{좑i$UCk3u%|;kRw(szp-kq_+ؤw' 53MqG"k-08_TKpbJgt܋#ڦǤԝȯv uR}MK5Ck}aP2} n\l5>2}<@w)N5FPeQcܬꐍB#o%ל0żxVY:9}QEeXl$ֳ{L"X<$! 7 8/tnQrK|ַm67.w):ʶd :O uu]m}K`ώy1yʒ)VV "R5hSg|!! c-*to눏 Z f-r5Bnmd;}=cIE%[t*2w0iÓ!ɢfXEcF{ɫ^D<ܥ:fYBZgp&x=\̚B@5* |d̆U{3zަyoޛ.]~ gUj'(vjk ?S@ɡin MFaZKYIJB&cvhݫ"rm!ۏދn}XcD&?//x}T_sF윜d#!A)]N_G^Qxrod-Ky"H_CZhgpkK@FiV\k[Mc2v'f==?oS_Rτ}MИz<J\d>{'Gߎupד!L ZSن$"oR6 f޸704gؓy핟/vT J RsbAitt0̷;?/wWQms2 @jˮBNTPԶ(]}﯋>?7Hdn[3!:{2Afd+>ZFf> ]ӬI_06H^ 9:M+WUX|>%`ȢSdrD]R_œ@=݁X <2\ zLt٢b@WXF ;պ>VhgV].5O֭?5Ei`A=t'Oixh/3Wn,3n;beUcXcL:IQD 4v:aZPd;mzfmg+_Z@lD(:o%v|_JWk]{x q  pL`kɮ;Y2XI( j]58BҐ TY5'&4Wc~d!/j:1@$Yg2St3GI% YSNli{,t;/>nqETgd'p"6xn2SB_AO endstream endobj 479 0 obj [ 0[ 600] 120[ 460] ] endobj 480 0 obj [ 278] endobj 481 0 obj [ 306 252 386 507 507 507 507 507 507 507 507 507 507 268 0 0 498 0 0 0 579 544 533 615 488 459 0 0 0 0 520 420 855 646 662 517 0 543 459 487 642 567 0 0 0 0 0 386 0 0 498 0 479 525 423 525 498 305 471 525 230 0 455 230 799 525 527 525 0 349 391 335 525 452 715 433 453 395] endobj 482 0 obj <> stream x|xn˖d7M$aIBH @(H6ZBBBbEc"ĂcǣG9GPG$=ﳃ=^$wOE066]lweXkg5-z&3`qC/b}[X1u@/оJk | o\tYM߫8;շVtz}z԰Yu/~]g;ڶ9~d#(3|㱣Go8)銄%*1=T61%s9SuY2X}0STEw)~J᎝`^I2~(SG O{)#IKlj!s^=xr%W&]W o^г܏8FZ3u3~Y?2ԕdRdSh]]&κu'==%,폎2ـSOJj;y7_cɶw~/ƒDN})ϝܯO=,<0mzo+Yz/S5WוRWJ]?')pnӝUqq' E{RVw9ߓl3_%2?DZilnhJIVWk[;{uF`,}al8+f%$6}D/K£'ރOy-_|_/K|7O iԿFD^ ~;G-D ;{'Sg/~vQ\aw:y/ߔׯvӧN2:PUYQ>acF9?aC 4p@N^=Ӻy{b0 zp]+낺tȑDWC}'C] Su:~Ԝ}JM?alXlo|m˫jÚi]!ޒ KWm.+F-shW6k1[ -Pc8ׄңdHL6ؠVR?38؝ZXWP4j}y1ޖ}ٌ,LAՒMAGV0W\i<\|謬xPfyg-a!=Rx"L(al!KMcg3 n,p?'&ԉ}%eɉuT1U%usgx{e#wQ u3 +.UU%-}rPNa(N_!U+`^e$,, p`NI(WaZ{ݻrYV#-¤4WϜԹgb}VSW=F̒<ǥjOZSjsc[1[0xK+;Kˊ-n&)B2jZHQE#ݩ5~cHiAS0=jezKfwI TD,F ΑHM΅MA7Ib7&x}|5>!jᛈ6elWII9*ϣ\Xf",V-?B˟Ȏ)&R#)>)ޗ=)ޕ)*R%śR!R&ūR"R$ŋR R<'ųR<#R<%œR )1)IHIW#EHqO]Rh"(ŽR#RbwIqwHqIqHq&)n):))bWIqWHqۤ*eR\*%R\,ERlB)6K,R/&)Γ\)䵇k.=\^{py嵇k.=\^{py嵇koBpy.?\py.?\py.?\py.?\^{pym.o;\vpyËv [s(ewP t mDB)Vzʭ#ZKhu(*\ZIh9-R&2. %-* %N'G4hPR1hf5 '#N4Rn*D5DD&**ʉ&'G4h Q{hȐ{4hQi]* ǀ pӈQ͡DC`8GKF1DD*E1Fd2 (LDF"C(aHJ(T2*DL#AԮUm;Nt(DE*wJзk#T$:Ltʾ 'AtsϨ))>߈>&:@e}H'z]Jv(nPDЛDou׈^%zL_$zyʳDϐi$O|r#z!z%zhQ+|r&hW(6 N%nD; wR/wNeJt D!F멗눮k&Nt5rW]NʶR/]Je]Lt f5]@t>&Bzй! 9Dg\Agr@C.k hzjڭ%Zr櫈V ZNh)uD͗5\ "h|ӉQDshd,ThQ=Qtit-l*rz2u]C&DÝH P/UDDD!4!Or=.<46CUʈFQI4!PIȹ Tr* 97 Cѥ"?Q>P44 9j@Cbi & 9Fՠ!d*OrdQ;!pO!fQojދME$ʤze"J݉|g73:R/jLD&J$JkA!4P\>K"rES51(Fdi&cHdz#Jq"hjE>~G||7(#Wa_8||9ȹOOv!jyMtkЯڲ<//E^-<N(u!kguA2x(e` -@ײsen:Nz]m^[7A7Z{n:Zkk; ++ˁmV2]b˹–ۗ{eM4icSI74tIaMڱoW;_d. ,4XX4{at p^ޜsffhțϫ Lϫ LQ790e@M^u`O̫ vT*;>6,0fGY`t##J%p%ٓI] `\Fܼ>>1wнϭFG%z̨^4>/N8#5*x]rGq_bqKY=ocJ5/&;@ul/4ţ\Rqq88P]_+QQ<*#JGzT'R?(Ǧ"z̰N*x,J 2ޢ-E~K>L^TwyJwr=2+*ʂ S`ZO)-_T•SV˟e +L. &WVoL) n [bYaMִ˗fe-iKei"%{2r-ϲ~3Q5Hˤqo=?{?2(Pa33`=X V `9 X ,"`!s,`&:`:0 S@ P L& *r`0eh`0%@1PÀ`0 @. r@/ z@ HҀ^@ bbh؁( VtTc39lhǀOoo#WaOAs3'߀G{;_77ׁ׀WWgg'c>Qa!`/ hv{{.Nv6Vf/M u5v*J r` \l MylfFϱ9?csϱ9?csϱy3 883 883 883 883 883 883 883 88ϱ9?{cs}ϱ9>9j3^X֓|;-eu¶G{l;j;dA{2/dVf`1u8~Ъdي\)/۷v[ ̬)-o8+E^x}r6MaSY-c_-[EZns6rqhZY#Ėlsl_Vk[ְl[\Y֡d_l`g`fdgiJ2Yfs1k]pB5BE_˰*kصXW X3rXnД(}=v{ؽ~- EDeF`<<ӈ)~+ODk|5=]YZQ<5S"q | G\gkUNF u+u؁7SDU@Aӝן{n\ܮ)d vv]lۉugE|[ ka!݇=Z5o}W:ad{Bapۇ;R4Vd7\?-RlKQT WDo3(|s)QNA$Gf6wQ5TcPa%5:]&Str+al{Oy}"݂cTЩի&Eg0':jbT]g;bMhGԶ\I$j:6蝬Kga;g1ְHo8r"Ÿ(T]|ڴODqKOjwKmU#Gˏr˒-*g٢r-*g? YǾ,=ޅ#l]VV~ۍ}Œ]߾.--*8_[yNZE欬TgΗ-}TD%sV|>X1?KoX28l[CجhoK̛<:b`¸_::(/=mN.O Ov՚FET,RxΘI>R=Ӟ4qVqDgէ`ؕĆf KpTؑ,TγC1'-8,s}[IsF:mK+Mv9SXV:79׎c+x'MzUg"_2~▙4\2eQFA}pWu7wL(9uk> ='Hbha+&=* ]NXGۗklnr&Ln N`KMLm%1ILnV6>&PVScJ~ը`Kkh:1&}"YWYWYWYWYnUjYs^;ʔiVѶ?.Suw걛"I1da c;[>q99񉭿ҽj'Y" ө3ܻw?~Q٭BJ?QR*̽2t bO //6+JQr;*+6(1s$)b{Mىd<_x#.Ɠ6phI~+FnG7s\ u9wW= ( uY?':E bA9ū)^ex S?'c^)}Jun^,g*}bg'Jt9ꭽ:uGopeon.mdwƔ>ʦ%WO\qnG>o\qUӴoتooOc%L!!! -g;bK Α,“,“ldq?Liܼ`M.Wk7_%>_y1 T]=[8&sI7\3nNiwuk>/0Ƹ'?dO=F40XgY1ԟbd¨ /i^ ^ <@g;D(8¡qC!H1o; ؝Z>d;8KzIl\c18$:-^ë.µ'oAbq©{p.4OHϽBx}m"^zՖ7qqQCYm{zyqFCԡpڌ86`ߌba+ ?NCT]A)Ug8~~~׽/ںtTS|%vBG9fgAwX YAAa.p3+c[yfxb ;,+~.# N٠:Aކs)7 E+o-Xdl^+dm`XX# g4>H}}O*75Uy*߸~a%%vMkɈv^Cyee[ߴ z~+kklZ p~9. X!@G8_m%.O \RTp(Ψ uLx=PSWvRogq֒oɡ?~jRh[YDjDu אD 0MF8 9 ; ; ; ; ;2٩'8.Ѕ.@X0zx)5"bPQ9&7^Ze֦-Z8=ڟ x#74p:6!Ǘ-ciqKXgP% *Jm}QؒQ!qNBkEn\1EHi=WTD+irܮx,.ZX,dhpS1qĸ8?ZLrY vj[X-@j$ki–/~¥I;Ir tMx"zJ [--wV`Wl"3 3D+z^ꕵP~ъy?*i¨ WU.^BÜlIW^fs f `UzϑdǩVOՊuWZ8Yu8*+jjٴL o/nv85,7hx[Z߻u%o&ذ,k[;gsWy">[Ѣ]vY.h[ }Y .TD"#5 {J1赧{ <HdJF'Ȯq1: =uPݯ2$teie(aXp*i,u^b`-qAt7Lvwt$Wߵ$jl&ZwiuwF/q QY.L]0+"̻ѹ7Y [*.\xve@ FS{$P{"s˯ؽ$Y+&jGlMG5m w]{>{{9>LYClu ҜrBA^j)T Kk5jX&[$^l" j)Y߀>?ؚ^!ƃDڪ88{=}G Mqa/}=:ҴĘs3TPe#|=QC a&ܓO6Ý^2F_x鱭[b+eoiysD%v]cr[6Avٚo#mypv}%=kjIdP] <mUԙWa&/y\06& Zp!cs5`A} W~(X]3ڝҁc˦XUVϫ素\A&A H5],4x=_xl Ƒ$pY{0jX4Ch6ؼ$_=-vSԌn-n'R֮)iLI׷_5*V3˙Jp@5.R\z5XE<@>b (m1Q1savYƎ`/fu]|%iY*O: S):MA<}p*qQjVP%B'\ϚSAO$Le3ɯy^^svl^PRu[ٻHK+bh[z XX :\^Q\L߾{M6.)w"Z⏔0:&Դy򘸴*<)jZ xY1 M}ҵڎɡ4u$ʚ *\8zU;''h,;znDcS'!~nWՇm>iarBt\9Nhut5h4ѕ1{:m 3̘{Z&ʴΦVMu鏸_U(vNGG6EX˝[_,#W?ځLt'F\9:)}NK)P,F.aFB|!lE )?KvR2 mt^r]/^KCSFzz:+zdHn^.M3&9.g;Hn_!i&`#1n_śSrmb=?"`]nEY=MU)y+K$~G*aWFYT/æ+j-K3d8]%jk4=tZZ&wGl LkHZv0,-),o-h]X thW/\#_O<^Yk)eUL+*tG;3'v23ySB9%|@+>&ϛ@!3.I+.\C܀ZB0y.''Tu9 QfX&7yVXI (IL4V:fo7ԍp^k6߹5M߱5x ]uU+nuU]Э$}hCI4}7ٶˁ4 iFT/Iw 2T } @ޡdl1,yvUS_NHW@-z極|fۏnkU.ϰ,p ۟{p`NԾ;mA8(A8(A2 W$@ɒPPQ$g2EX ۊ;z t&E. ^S;yHcٝ>j4yr`,(k>WɵYvݢyWZ̈́39sbLSg}om-X;yڕ׼igZ;ҿd{l'Tp8!RMp45A0m!"I bAjC$S+H#+"іdgH nRYAjS?WN)<~j6N֦ ݎ:=I?6qSs*El<7ű_0:[[43h|9I.1XyB yezBjojEoA`jH`%x8qN$ X\߀qC1n$܎{%#UBYi&lI#L MM'VGPSl++bB'D~Prx:} (){zD*dBtf6CLTiv0̿#/sv͖ٕ-GzW8=Y0]Sj-Etܩ8%Ŭ ?yfPAkVeafXN3WS:<Dт# s&^좡 M5&&c1EƁN֩n%Kd%byxUvF_< Sy0ND+Dp˜Lm A2pgձ.՚%i^v 3Y +aB G3q=8=3Q [yYaNPWN+$GhH TWZvK=u`#gNo1hH(~Tkm6E Ŭ^mrX&#L>bNBvTLU1oD}6l<5yUcZ{$kM;< ǣo=jTjE](뽩Pح׻!&xVO%~7l?G 3w)0T\|r&#&A2 ߳``O&Cr Hx69Ȇ?ςPRLj˒XXB_^Z2>;N@]~AJK˜B˜q|3S3淃é>4h3<<#z4fz6;wZ_Y@nA2PcS4!32@9HJN9$Ϗ^25d]0<~ŃԷ8$" Grw`bZ,S#A$ŮeF3荷 r̈́8mjij./txw3ٵ -ﺲ7[FdZs~nͮ+ZFgzא@ۣ"GP q-d*DkV)-ՙLKU>Pa~t%ek2vn M1nѝJ:IyN%#~?9G͢"ΦQi$7:́Pg"O/z$>d[F\ :GKtڒtKf-ʠ[YtꪛTœs'B6\x< ^U%l6꒏ԱUqgM y$CTmX8q*b M݉W}Vo[ҸfCaxM~mۖ.ip`n*K7+. F`VW/Ji T}m%ݳB΢U9^RS $؊g#QsRg$_GXPS~\#81C"v.vPȁ)>TZenBz8zIv2.+9TP,p2C!9U*+P PHTy lW$8\'q5yB&WHe@4Hg|4)n" ge05 ²h4X5cX/:[0$qكY\PݥWt=="@6uz^Qjf3Cr-rE\={@YfMFz֖pj a4jҲ3꯮_S#1 m}`9֥&x`,n^TQ; A<6Y&;kdDe:N\rh{Ӻ:=# "Uyb=ID&p4c8b.s8%p)/*kb *;o&;%%˜+"~$bD d]Ł4uWVR!AЅ u**=F"^?^M<8Cy{3OL5F!9/½wcxs(> ԂeFJ8_0g&ĭ{@euL4&jqnoTcVjqrd: OBkE4bSMlť8Ts\{1ENy\ 8E 9*w':蔦pZ/#PwZZK(r#(G:n޿qe5faz}]ǜ%iҚuOʮc̡ J0_TS2q fx(@A]:KXAy2UgiVa,s AzE'QZI2+9ԡ+9ȻCuo{*.~ӯ&BJɺfyW͋O*^=U2;p¨ol*g>2jux!i+]Q[J$$U(C-Ǣp͠q\[i91f,r\WYMrL ڌ9 Ác݀[B6 l71)T1`PSqBb~✠PV0bmccDY}4SXz>ٴr]EL}+7|kib\.&,O[Vg/owZҽ9z`<Ie@Y ?;vJW7nY߲Ȉw4v|9) #pRNf,ci4yck^ne@2O-!)X8LwKͬ)"_^J(LU颞()5ro˅/dyp|uu}e~ŠVccbr^$ d wY'8,8",8IZ.O+>}aD697.]b|h? h|-!73қ;@ܛ/8NZGυ~1zhFqn@+!NGs8CeҀFina!([HG ~HF#|p҈QIwn{H?0ҖqAcw'aofҋzGkP3|@O341i pBڏgatau><)}aAKuҧ#о 1,yNXs!=0%xm L}Aph2{C"SH} |ptp\=129 p >>!W<&}838NO< - CG0#=^D#K䛸$`mw]|?AZ7ȷMHNJ[0Dp@ >*ۋ*h@@BۀC"#Px4k@A KGQ cqn{`<#0NRQ=F`TJ [11>&1#eBz H>cOHNIwXOw@r击~ 8!I=^=?SI>8Ne=ۀx 'sp>_`}9@?!Ni׸݀:2Je(5Qj,XF|P^H?KSzp\z{F =ҞGiϣQ(yffffff' xL Pl';I.RJ+|.RJ+rP~-~g7PwJM8 j:Wnu{ptp蹇~ij/O'O|P' kz-}poɕD?)&a tp9=0qB:qdwO<wPqN]a0`mI wMЙNLL㙀$M{`T'gIX;o*QqIXA2!ZC@`tpX*i;} ؇ǥgI?Hy#,_D)IoD~n%:p VWbci}"K}3&S,V\/Fs5h;OkQ!F(W:zR7B^e1 /?F*4W)u4}JAY"C\BUv jJ]MJGߥu/{eJ݀וkLF{ xr]\,e:u.r].Yt2Lg.Yt2LQU2TD䶢M`g7 \*ο?g&.ʆҀB!F%!$H#*ZRުj5QR()B9 `~}s33yyllp2+|oesbBTQD&ԒM4TZU|r]HYs9so .RZJBZ( )Kcj3OL5|d߶+UslG9#"uPĭ#~"*^sHj D@Wc ͶwR ԯ-R,P)9@d>lV|šq(n=dBճGtټPi+R*塙[Θ=<9~{^J5ȳݢk:}\*SFjEH{Q3,2KF[i\akΡ'٪P)b9g3F}mr B6v ZA?lfDʒ9- ٵ?RZZ=ŔS39"Yq:2Jn@c$\IRY"k?*+W#Yk~Re/a}71VRfL0L]ۧ } O`j#OBU7b[cO'~)skef\q\WReW~5eٺQzG&SKΔ֫34;Gë/Ts:/g=ޯ Q ȑcWp(عj*VkW9Ǘreyf9YPyͿ_tHʟ/*uhߕ9%e%e%@AIqoja/`@/3,tY^neم K |el_QIn^i,G~A/?ҷ WV0P+-)/-(^T+h ŹҲ̀/?/;P^W+.h#l(dU ~TR,/%[v텅%}鸯ȟr*‚b*-,X *T.X 2_Qvq/,lRZ]+fи;e+((a@䐲}˳K$9KX^iJfޢ 7}-0%)cGw"=PW]D@c_)aye)sˆr|W#G._<(\/#Eŕ#s%ŁPQyMKdJʡW^GtHfҢ@ /׷Ruy[On=,˹8<0[P/ɕ9+m3C}yE eUg*.Mi) i]IXՁZdOJ-Y^\X(}ζ{3\8yڗ2 \Bܼl?%_ynDY'([t.]O'StNz58Fk8Y^wt坩Z>!Aqv卌s-߽;9 TDu*D7G$'ƈ!Db,niU:q~k)V\+u5T"%ZMhhD-CFk7iSBmVݠk2mJ[ݥݩmjǵ?h/H7ZwN_ӯw$ꅎ t#E/uLW8z#SƱ@QsT͎u??׏;69O8^O:vNu40:8#xXAxx~o<샇# ^0F$xC><a <a3<< _a7<$C uk]m<)0 #Pxxu<|VHж9iێ C<, xXfx 7}xh~\ѿӻ'$>9UOÕ{!tx' Buxx6Ã%ʴxx.a.<,%p+<,xX 䬇Gx:*t1_!n.ip5 r9>up+Sp.ݡQ,b#F1>:X:6ɨ6;br<M44ЃrG1̈́`j*TǗj6]g7mڤFJD&5OR# iQӊZ5fB9RىV9)v;H01"h¶1׸49q?¶]gmfn n nFGtqfǥU񡽈Ym]h#7l#WfeFVMp 7V~63+;;[C.,]^MntqSݶ3{NUNDIt:[Vuu$'lN9V!Znv"*֨r۔ [ViieݺVZeyr[wZ#Z_V ou{4Oާd65gO{]wqJMvаT:QR8jXE%ܮGuS# 2Z9f9vSb4$Ǥ+Qejr: dm %P[0WRZ)RN*AO^ʣiܚة[T!U>[ \!GQұJ tR3 IشԴaA)]dfdT{blJstf94Nth8CNg;$Hq:5 5hw5|Br 95vl\\3fTfNq 3]HlS]o<ۉjÏ`[jb]ǭTK$9yM2iR}DӦ"KA6Iʤ+b"mXWU^߽ZD!([N.VU=+qk*Y 0Kẍ%6n }MTlamΕZJv2WT^"n"o zegYlH 9ZF9ڿP*Rb5Glfv"\MDh-G𘾈rb_j[$YĈJ(ʝ%;Hk#3k\tXxy򒒄љLui!U~k ;U}L{ZٞWUYM[0z6nH$G8-KmbmM53jfʌukMH R\T!UV?'BP6QuN(SQTHGWI/z3 ^u۞$W:~U2wxUw\Qrc7f\ 1;jiʫkh^3Qz5A3V3T[ sXeslGWgk05kKjw|b+dlڌWv[{/.e7gxի99ÁxJU+}{cޫL~XtZ)#;o֢թmv|}C{5~}4coƋxWEYke2yMiV_WWWusDmdqz4]PU es2ݦwh˩w׼o:YŒR׼ Tg!Rxi9}h *ͺgmQLW[gtX1,! 2.?NQ|p.Ɨe%W5c4kn1̗S~E 61KXYaL4[Rq@dHCD [ACHQWK*WJawh#ҧ|ձP u3E5Es嚢 =PXTD/hWgN,!ؤ)M8Oݷ8ؼva=>3#c9JuM,.# zN ]#ٱ`{RF]}se~:>/:$XP]ؠ:U&qq\5Cc:NSk%EKNVǍ:nQ"A9Ma|^s0q?,Y5}bxQ%C[­FjF$թx\>5Ni9?skwNnN>-X18|ChWL윞NRJܑ!8t|"6)boGF{dkore9*rnq9nMxG*B Hn^>FC,r"~@DHrN1$i)rwt͈GŖn")ȘGɓӤNj=vDdyRz:&Rzvk}ܯ䭳^߇%Gb$йCGY^ICDڟ%6;cJ9]{&ޯ>"[j+(q#2{`fDrCr xqAS cෆc%'#CC m11)C }ÿ?LjWHF䍋ct 2ylc+ƽՏk? 7~݄ %5R6τImܬRSS2"ק\~='إ97ۥfNfN>*}rYCd̺EIŬuX1]?ҏlE9. 94isJݩ䳹M೹-ι-7e8qr_r[9+dv^Ƶ_S4dsE}>/XP<_-KKG/M[Կt>ۗ)Wx(V6lae-ˌe#M_̲Ӗ_ѯbzEVEiţUP/W~wEVL[bˊ}5֛o}֧o=pkԕ+VXt Wz-֌_S`U/u^m:D#{+^OlK?^y::^tb}YOnfTk:v`}}(~sƸݑ5][ʺq/?Աv,:.5 ~s=yWŪ~ʇDqY7ScҶm_IGt:"f3VX=5Z*P;>+!54_McoydMdY3<$kt!R'}h`6:e^W\SC+w&{^?Z 6ʝČKi1u&fXUp Gnz:;"m2NYo&sYJ/nwRtG&knG/*jfT솆Pd=ۭgew01tb_&9f<6̱퉒MRwMDbF|os{?XlJ l-L9+ʶ4y6 N4چVQ)JdbjYBE( E܈YCF'*D"LIYntv%JO]Dڽ=?NY]7O2Lj/w=JjCtT&}vPɾ+~y%E펮W;+jܬG쎸zkRڝ#)[;[wF֛ eUyŐ9Ծ"$R9Cعb&wh:u}_(vjڬ)H⪀$C=-[Zt)= ?SЯ^.}mbn yդϳ )zF&[mZeLm$-WtՖ#wv ᤬])륬G;Bo[Y# ?$ ފX6 U_I?VY/b~DֿyڕwQ8rwI7IHT."]$brE(rP*W[J S-wjpX~6?iUu;PM d U \ bV/3Z1QQP(56o887'1h{T I>9h4q h1"b1ԸsQA (41ƀcy1x\Dp@ ue`)( npb뷜߂fOpph\E=DeG?Wa/a/amCX[v5ֶkq`/) WFeg՛8Ff12J /CK_CCAC?C=}Zch9\bDH G˅hJF|;h4lU#}E":DǛHXg$zg zF]#W[Fٝݎ釬]xW'!ah-@X^AhLFGxޕr 0J"W_ۭ&ց;A5 ?Vx]|@ O-K|!8 V??Np /Ų44*~:9:c59? `/|[ί |@3'8'}qz/+ju],0u y`>7ɕ%-\ \/JAηu\ =k8 ~<ǹ'-s`\̑9r1GFȓ9r1G̑+5ciX]߂c588Asp>E92s@.cnCE.]܍Æe!,tR3bи"ҰF,l2F,l2F,_biXZ+֊biXZ+VԄŴ`1-XL B{!M"F  ijFijFijFfla&[FfkaFfjaFf[a[a[a V`F[`aa.'?{&~H"(~f2+Iɷq*4|"'N&'I$dq28DL"N&'hRb b |mgٓI|$>{=I<gG#,-f7য়O?O/C&.8ڟ8ڟ8ڗؙDL"v&;I$bg3ؙDL"v&;#|؀|1.D|K"%ג#Ķ$b |- o?$u#u` Il10DK"%I{qgw[w03X?g=/g&f0&w~Tծ 5Rz?1VZH=ԽoS7 ԻA!?{)@t6))"c'.r_@44Q_>3ul?X JA'wn*&&7$z鯉Km!1}5nD>ge|ͽK6jdO9@tDb~}/=Kҳ/=Kҳ/=K,fjqԌf5G8jQ3qԌj^D!ԼHRKM/5RKM/5R9&Ts #Q j%G8[-* {7{7{7{7[)DNcEl҆a`8~RH0 \Fp Ox0Ld0` tpft0 W9`.x<& ~[oVx<ρ wE=Z۬[lګw{@I} |b>O+7[a'Q;;] ޷:w1]C1=y'Aoq1먱:flO_Ǚݦw[{(|p| :A`0bu][pa .5M&rδ됩'p/ Hm2nqd&6&7I$0 `0>Z{`RtpX@[DŠ[V5 (oO~I[fn6tzOh;hQC v4Qo3 8@" H@0 Cw/?!$"|1 ʺ+CĚ:p`/M ă. t@wCx@O $ޠ iO~L@0 ZߘyF~RHS0/:R0?el7t>~|uSx85ش(64zNpBKkatUqAxB2'vX;p'ݸ>܏%x!<x ?X2LBW>֟֟}a{'].NֿNW+)+_ǿ;a{,\+p%-!/bˋ-/bˋ-/bˋ-/bˋ-/bˋ-/bˋ-/bˋ-/|| 3e|_ Ş'C^MO|sx](]qXK{^':ZZڊÊ0ºZZZk]kkuֵ6:^T[ߘ Am%)+Iſ]*9sݥ;_'Feרե.eu)KY]RL5g9S͙jTs3՜L5g9S͙jTs3՜L5g9S͙jTs3՜L5g9S͙jTS ERHQ ERHq:Pŋ Tdžy{E?S3zQa:Nt*[oj6j6Pc&5fRc&5fRc&5fRUԨF5QE*jTQUԨF5QE*jTQUԨF5QE*jTQUԨF5QEԘIԘIԘIԘI\.8);E|"EuYGvڴջſNĿN.v񷋿]ovhvhvhvhW+Fc_.@>7K ù^Wg,&LXX7GzcBoL 17&ƄޘzcBoL }1/&ńbB_<`*J=3OOӭt~W7ݴMݴMݴ=oyk[{֞=oyk[{֞=oyk[{֞=oyk[{֞za _ RDET^[xoyoNބJGUJh?;?p-%zQ֋^e(EY/zQ֋^e(EY/zQ֋^e(EY/zQ֋^e(EY/ f=oǪc^Q{U@A$7QfF$zޭzޭzQՊVTUjEU+ZQՊVTUjEU+ZQՊVTUjEU+ZQՊVTUjEU+ZQժ &E\۪WE 6IM:\L{^4Il|_9[y".%..PY c6q%ոb\\0/<M9ۨcatS'cWPB(ev;NST.a v`)a v/RH"/RH"/RH"/RH"/RH"/RH"8ǩ?NqSv]`+ v]`+ -RH"u-RH"u-RH"u-RH"u-RH"u-RHݢNvj7K]I7~\O^Zy\|jDge~Vge~o |4:T@ Pj533حM}Xb}ñx?f8\=໸߃ ch=F1Zzch=F1ZzchO~+ZqVdTAFdTAfB?U7JlﳽG??Ϗ~~G??Ϗ~~G??Ϗ~~󣟂Y f)`Y f)`V5dTCF5dTCF5dTCF5dTCF5dTCF5dTCF5dTCF5dTC2p(á 2p(á 2p(á 2p(á 2p(á 2p(3MUWY&ۤi}I,48K,48K,48K,48K,48K,48KRY1fŘcVY1fŘcVY1fŘcVY1fŘc6Qʅ9s!Ęc6:H/yȴ['*O5bvΌT%U[jۮWiw:q nt_~k8 !.!O} kjC{Hv!= ɾ!7$dߐ}CoTT[)Rw[F\}m i[ѷo-xG>ѵ}tk]HF6ҵtmk#]HF6ҵtmk#]HF6ҵtmk#]ԠSrjPN ʩA95(G>ѽ}t{G>ѽ}t{G>ѽ}t{8:B߄{WB1:4:{|),b{874u^O +㧇;LB)On 9yWERh/\jNM Լ`xG'^8)7~j8N?+HVlД zDWɫ'$;83tvP^sz_~aX&t'\8)lB)lszo0$`,Trc:V;)Z|T/MH>|r- pzhzӧC}buOԯ>V)aOX2k'ɬ^ƼeU)ͱ=;eNSflevYGV{dDQFeDQFl EP ;9s{VSf\)X0N.zׇ8$g<#d}bG)MO%RhX>Rp[Эy;#U{B5;- 5^Ôĸ3R"Pbt]Rb4 +^&5DzKӹq @ Oܣ{^?{wOS^/uG;z)o>o>os*mJ[UÏ~ȧa=jXG>*!q{HCb_aeXo[2l9W z W\$Zbk8ڀ+uvŗJx\m|J9-X' o`[%ι1>GdK},]ʼAvkbCjYN)u=jclaM쏎.< 1d6eTEXO9fO8dyr 'KɒEdQrǏMOގbpK< q, 7'$W5sUչv2p \d>. xܳנ<~띷s55a#;7-^-ss*\{=7997!k0)Yn aXAŰ&~~r.)tRUÚɎS]b.1rt dX[Y| 8zӧ#H9 8c~p#܊BޮA&&]oWOV'ry\/VIyN^.28 vȵrm[j!ًZ:;j9n]~,c rw]UPr:6ʮש(.nY7ެo##cl.)Wȓڤ6MrM7ݢt:bBTI:`آ-:` ewz-^NעtN]SKbMX`[t-Uԩ;uNSԤ;5N[tN]sWjҍ:un;u.K9^w٦lA]EХ3t ]jT3um:@9լ8^巨ߢ[T|oQMIwNީڛT{jb*R]Kw'7[tuZP|kj𵗯+x+TDQy U@ e|Q/Kd^,EY^Kdټ^+B6 ZҪWVWLKzӧ>ylKzg-%2wR]Ǝ`G{=ۢlGi l@dCj2"kY&k=VdU{h Xр Xc5V3`5MVQu+mq+]{fWufWkv5Z]#q<-F\9iWNr#w]=ͮ^?LGئ_ uWu.C-vy{'JWz&M8eF<:Sf,YAS̤e( O0&ivGe~#{xOMc**EU|#tFmt,_o߈5^eZ}8]3xRs{IbEGX߰5 [.kڵV?`]ku춎ְ۵]{ص]wr]vnv] 겭t^JZ1"?W~OG]YW}U_vR}.scc,޿&v=怽pxݕ1m[5/h穴]3(ץ}Mj-R<﬷: .6)K9Dť*""Rm"%mb&m\m2[9R\nr;csyqorD8[uۈ.7dՃjŃV\g[*p[[[[]i[[[UU^G1Iio7ѰG} ra擜$gS)G1 v.cӍ׋vhșɋv1ۘm]4wlcv1sGΖ1{4cv1X4^Jw٥MWqq>>UG$'+?#:Pq:htwR"NN|)3BoevD{T~TB·Bۻ"D͎-؄D6*QFwӷ3wiw+߹_5_yv6gw&Smih J?1-LK9RΚ71 J߮ i(ǁ8+}!#KYzL=ft3`0 fL3IfM&ŀib *߸W,Wjګ^N>kb[;&tXh8Nw\Zzq|֤]8?x\NPR=IP"=F5zCjP=TBzGo 1!blf1nfj)6g2c̈ e)7eX6$3,xC oa6aEy|ђ@t k£Ѽpg4?@ nDoXD#޳7cI ͓N‡a|'8é8N8')|g9 8sw8_|2#& Oz!vҋx 2^ k&4հf#ɏ14yCrPx`!aSSS#p$BOsJ{1,; ၲٸǜhu{\֔)?1)+|0$|y)\_o;2x;hy6q!151SPTi@ITp0fuSysM;|萰1:_t8>!|%ė| \܇eѵai4a.ǼP'dslu6Nvq]^܇G|Q<𔎰qJ@7zRXO'VN͓.ddr1aQ>GR* ~Z/W|fPώ_ÅsV_񵘃?͸ꭜF4*Q9;.s\,PNr:ARk*JmPkw!>;yz>MLCw'_,\r|#gYr|%gE78ü0[ϖly>;np3n nmx&z_{yyuhG8ZPp5 mx ?X_ uxOW5cV?B=3>;5;8/̏}1\;_:, .r3µv64焖xs4%lmsWU{C]|Y$}0c_o9|mt9sq=n<PlbMс7mhGR؂NlE=e{lkO98yz) e2_=e_tpYrqR]!SqZ4]O]I?_|c1G*Ke meNmp,ޏS13ԩy*mJ)*:j,"܉=cTSM۱rNܣrQ9u*|0VnSA5cсS mSt#qރq uN֩:u8wb\oĂ6mRh \Sq!j n*MP7BT܎b1x+ݸ>܏%x!<S(8E&X&h!wB}'wB}'3a LXg:֙΄u&3a kLXc֘Ƅ5&1aG0 He*W7*T#Gfɉ] P?S I,i4t:M&N@ i4t:uCuCM@$1 dL@$1 dL@$%/%/%/rQ5f2\ٸǕ WP^^^^^VinZVinZV.n}˾evwuxO((o9o9o9oNJJ*s/ۏd Y "0F::::: f>eOSf>eOSf>eOSf>eOSf>eOSf>eOSf>eOSf>eOSf>eOSf>eOSMU# CNj'jډZDvV;QNj'jډZDvV;QNj'jډZDvV;QսD{K<^9ϹxνD{z%KOz-Ԅx=%bIX2vfQuyallnvQ.F]Zlv>mgegm{kxCt@[ܧoerxN\%rI\.%rI\.%rI\.4IgLt$1IgLt$1IgLt$1Ig&rw>"o]=]===! 7*(( *(ȥ %"  t!nP?}g>OwuU~OO2ς 9<&M9fff..겋..겋..g>~g>~g>~gn]h@)( v}ٙ33@r\_./@%$P [Q v𦑍G)$P v.]")Bћ{D$ɵ־-L N(("H{"H[%> \H433I*:xMGR^AoJNA{}nYSNpΞq~@;hx8.GCj(* ='|/ h m-|>R<xH=zԽ lp5kzxK=^[ꋷsh\~.Z?Esh\~.Z?Esx]9x]9x]9x]9x]9x]9x]9x]9x]9x]9x]9x]9x]9x]9x]9x]9x]9x]9O|=i :Pw';uO[rrr)3WN [Fƒˉ2h=#ZQuz{=]#|.tࠧGc<<><<><<><<><<><<><<>?z|_E1B_h͍:qq$.4:ͿfWql/_lK|L z,П-܊ڦEM1"@LKħz _6s4j?/1bMCҍi"Z-9C0/Y(VOB@iyܤi1uIi}pwz>I.ճdUySg3rǑ\LEr_>%ijw;AoWglNUw5|?y\7W?ّ3E9y~YmZ=*2.tړ(j)M*Y¨Mo7n%" 8 \4PN頱^%.ax<P0 #Yz^eH`@ T"@eP5A-PuA=P4 :h ׃` Cax<Qz1O`,Wg9 hg9T'VܕB Ν(Z`ce8Y KX{{%r_r,ն,KLu+,l}dM\m[d&V4ҳޠ~?A`0xI&)e x^oMo0 ;`xfG?g죟}~>G?g죟}~>G?g죟}~>G?g죟}~~-\gs]f-DY ѬΥΥΥ]}䁿:Zgufb"Qr-;p4444\! )~J|4fL>G3h h h hP6BuN,|~v:/N>>>>>j!j!Z |k7}h&멵9r)>Ro. +,P?Y&ʛqr8_7ˏ9r~ ?Z 55h #f9YOq*5 dz?I=>>Sdt#҈ER]FWߧKbu\Hbb,!Rv9[(%ո8|XC[#WDFIZ |[k%OLbkr7qU7jW_MD@D bqFDE=ƘX/z&Vo }A?  0X4A7A7A7A7A7A7A7A{7Ao7 "wfw25x{/d6\Ek,g23홇6j+w̵>z+ΕysLg[řV[Q5hf/Q-SklGߑ-{aaȅ{CY.JIaB,rf3JNE"KlE&>z)~w!w8/;Rxđ ]/C×eh24rڷ6[?TV k[wJG3^xzW8|,"mBڍoP[Fq75R.jRێ(Xg /|GГ^ %ئd1%(/`(Yʪ &JA;Bgv͢>=O=Y.Ɗ`2b,χ嬹LTξmQZ4d+T 80zX*"nb|c=˘ҳS^zv*fc8erHn.%>FJdSb#%)r͡-ѥ{%7r%hC{m;p +u`"8ƅỹ//A.IL /KރU~~r)RC&) QEt;mvpw jzcA Xff:>mA_nmJt#Rv7 AMK&P.5'9!aT XFVP8Zx9ڢ x%WJJ_ij3ԲZLj9>SK $%yGDJ_)+ҿRq,h*` $b9Za[Yf%*33!v9vz%vLG3! VЛEcluε& E4.Er.(ڧsA7w*Nٍ3W nӈiTT, \܎[ێ[k5Jnֺ%}b)鋩[r,fK)]7Y].c.r~GòĸaY_Rfe^LZQaS6Ieh$9Kݒi%JE ^ΥZe(YFI.z\h9]z#@Me`7V ][" j)$hj(۶A"J'))Y)<%GчKU.XA˰X\?Ae=եUVlEuN8(Լ>;EI{GL R{h;ϊnk9ȑO{L%ȑO,%GfgO> ǹ7$1|)ǜgfeUUMmU)S :$iOZXV-T% aUlZJKA]5I|m_x.r-ue/MV1@eQesu֠&3)ɪEzmPzO\ _%<дlIΣM.iH;Pd"E+So6cݯF[Ճq^Z!qIo@zC(77J^Nz:cAEzmP*f½!~vz#Yvqjdv,Kn}:j`V$FU՚[dvKn:j`Vf999Ūuf$^Ŭ4`V[5IZ p]|W| <4WQo7O^_ [h^\`taƭ;[ hl<_;Z ~iE{j+%?Ϙ*J>]Mz+3:qAHMr*1B!<-{C uQU,1jF3`06F;`tqY݌;OFoc(6m<ǻ1w5u 1Xd4460136s͋&y̦ͫ fsyWlk50;ی+.fjyi1ag>fh>n>at1Gcnx9|c0ˍqfxbn3fENĘi5KyXR qc,'3od4Y2X,k:rYO7reCyy yF%6szX^`lɋ|y"/[eS&F^6d%FRBL[L%q#i+ߕ1, \/udfkeZKVV/1ky5Ӛg[KM Vw#n5x60,4G~5s#"̼fsu \\iGvGĴ^s[4RjFs4NͤaW4]ٮ!]t?+d Jal?(ϵa=)oGcd'iiy=~Nn` ٓɲӞjϐws}G'r|^&Wعr){F>m[8{]&'(LR|C5PO"T].o R]UKRnP׫FuAnRmTYuReꪺJ_K'T?5HW,S=,5T l5RzPϩ jde)j9V%@}i5Rr Jv}VsUui`v9Z79tΰ98XVB"w*ifuqqZXtsZYw8797YݝNNN.ugq:{ǜǭ0g5錴w8cAU5k3ՙj u9ӬaN'kmp8{Q5&dԋVEDXU5)ZZkunuzvqvfrevwwvf}>,Ϛp[s7&w廫MV7m%cuc"bcb/FFޏ͋L-팼)rk4Hgd/n;z>}vgWxYo]卲zcFX4%%\o}}7Ǿоn}}a7ح/n-r훽~o~}}^=Kƅ=8nMN|U4uv~OGĬ_|ȷRۉ8oZoa=?^OPTu^7v6zJDSEғkLc9~Yx=Y`NPj.#Y ńjrA7Kz"!{:lPQ3}܇`,u(7Ǚ N"- HA<*R1N~ QpwhG/[Xcs~%q'V)K+^qK[g'`ENOGXG`G,;ҌL?zַ@ylDྜྷK/j(ҳC^:/:/:fb%aݿas T`{'zsʗ&7 I79)=, QκE*?9EfNhόx˝&>;#扳ç b8O"0DkQ܃hy'P^U1,0 cVshs1,6Kp,#m.F\Fē)vf(oEjɈdoķ0_&2e<(cU6xozoz0ZXh @kka !Ɩ@k?Zh cW5@Ge0:4Ӣi1SULdi{g +B1B1(qYlzB˼xE.5{C{*7*DeMl9^JUXۀb+~':'Q"=뉽b/Xd")CBn"]z]f`y"\m5:Q\o k^Z9׊fZԦ$jMDElW*2gv\;n'țXsG·` CM ZmmU`"fYD kU,Y%Vi_;WzhձLT51uLXrCp1Wi QװNNlKVK4\- Y3ijnT{^WXEUT>\E_&OՓ{=TToZP󽬴+?T?מKU)52QAWi=JDDM8&a G؄#l6pM+]Q^mD56KWSu[C)oDCR?Y?O^sU/7^@o Z{,< l'\^:fx>> jф^|sv>w|ߗQ{U.sŸ_1V̮>8d0%yXrEܣƃz0n۱.G?;:>Oɏ Oʪ{^@p/e觚؟bx.  x>_'e*A Vn`I1r<> C Sw/,zu.g]zR^k^PcԷ^4kZ5ӐSN3߾W#zu;yzzL=I c7rƵ&!{^yj*~X;'!U~^^ #*T"Oo:-G\{~;d]?<=^@`>s=Эz>cI~+= v/R>=FXSWYGҟ9mC`!eՇV8OAmmj8~y=,.G?闾$ !\2^iNԬ_ѻwLէ }AاA/:>?K;{TU*1w-QTl2y"$!D!1bH0`SD"db >"YCH)RDDJRD)"rRD\L)"PE2;Ġ(|{?53"iW?ZT[KrZ'~| ?#?ѷ7@z\u[il F[5j6^=Lᗘa?bn_~lB[9^7$m <R&<j ?j);$j̄4?7=㰕s~u$8K18wo~U (|GӜϗZ4V05j֖#^tNM~4W{T{]~x>)Ӷ>ok-mwwȫ~ק_? ]1#H%t-xV^0m\u?x{);څ/ ¿iijO /dƾO}qO+/\B=u^k^{Om-B?j#LaOv__r?|\u3q?`|G\s(T3fGutaVˮ~ZށVy7{z~( &&]}T>wZ]il^ҥõV;O?KF넟?_n~gM\reZgK+uپ ;GV%+תك8~b.gNOpO:u(_%^m-90liqmQz4k%ں94iGowwQkxRHIw%~g7+wo}Gߗ|72uU+>/oq:̼ͯw`ty6lW\%)i_U}V{ڼ|;h+ڟ@᣸S-S-r gUV+{3}Of=PufNP_ LBz8N: ߩXd_=AVh^s+͌tfcܢшtO_ ٠m=9`8~2hIƥx,wѓÙ0rH'+ivjr6N{a=shuE݆w bk鋌xLW_I*,g5W+.'/:hy3h|׊a޽ݨ]ݭt70+M uN7M7J{DMtO"Sa;-4 egwwYa}WQ>Vs9#9QOIaN&UH}>OErѤ*Krq'^?J.^?Fou. 6Fq7]WzUq7MD#\MW+ޛn{5r7t~"~!K8xogƛ9[5tƛ%5top7]4E>Wwt\M0pu7An PzAnBus]7! 7s]7iН+ qE7@XT(n&+ e\MnB?NPeA,F/GʑBPcx9^hDaY,LoS' &Lk“r/+&kS\wMxZ.p5Y&ko]6a&Vvna)W_^k2&$?!?!Ӆ'J&k+\}Mx ˯F]a[~_' M/(,?)l—\M8+k&WesU6\M3%RQ\MޔjǛzL9>>.~LEtSDi*5 blGm^}H}/n\M7WkjmzWk7p6}韈YvӦOyP?uNu Ff:mHfN3i3t:mb%C&i3r6Ci3u \0:m2f9i3 W* ʚa4WY3t|&X:0/Sѳ6Va(]4K7;bsoK.ezSLDŽ#Izs/_ < F,W7U7m>O I{́E^y^䵳_D~|w6|趰~toBvx"y.|D>=|@>=|z<;ȧJ>=|z2|Fau^~nV˧O%/^~=Sק _?]O!B~f}uG ?'YO}>y;fn }w|2|Z`?}?-  XwѻփANu) og:3YW963YV`xBi!yi(^^.pJ+)AZ^%k5*ku(%ߐ6bퟤM, c oIo,6i,oKovl1J;Q]]pƼ[nޗg}=GA~j},}֎JPSS\eHg7JY"17xLv,gl:Y1;^`9X1؝ma3bhJsP7; 諟 Xs&9 g3L@p&999Ls&ȵjY<@Z`N9 ̉q9!fEO,Fvu(`QE_@>(axPII+ϔgx ^5gdu\NZ*/ews L i??g˧S?X yM21vIgұDX'00#P6ɬ 6E"WL_S)ڙ`ioj MxtVd`{)嚒LIS'S'M襳3֦R`C#v@p; nXvvpXlL?~GD@1sۈȃ!2(U Bd@n, *he4<<)c1FŬ͊ET\)gzBBަPaaEq8+5,M+vU(TXR,Q'(`NR&%+>nRJ%SCJz ^f)O)Qf b`!ƹ2KWǢ&Ԩ(%,3(쫨QٍQ%,zF=+|i4| O,ifWL|@L:ě[3ď/ bƃ3B̸1Č'IG&{D {D"{DI'{D!{&{H={~ϽSF=I`Q(艬.I͙z>}u;t6 ۣu^I`}ȧ"p'(y_0gX1|6,|5?57A,X`LO,\߆ }7=¹ڑP;RG9qۄ'i?WgLˬfb]w\&ao"բ‡` Q& cc vK!e43\(]\8,9sw'f[`Y==g{{ވ"goC(" OJh,1N kofE7 @%m4Dd!MTF`>= xIH)&o$ ?~GbO Ɵ(O9/%No$NG8 IFbFbKSO$v^JHt 3BbE`眸8MƮl 1b3x.!ĀKoG\Q,D!RIE,TĆH*bqqzZb"iŐ="֞THE,TĒHEL$1TDR!mTbHE,TbHE,TDR!1H*b1"&X{RK"1TbHE,H*b1"VF*b"釉mD"I?~Ha1&~X 釉&~X 釉v7CaI?g6%2K"0!VF?L$$ôgX d=,_ΔoA%g-g<9G%OΓ<)aʥ]A=hm3*e}{e0D`-gelx* )1N5N\';юKvG;GGai} PlӉ()g3<ιBi^~ 扤.yʧh<axI1} IIw'`tSTDyTV`3O!>y+'fL/(/ydK0ED&, MI/LzSdXV+d(k5(<>UY$K٠l͈L)&ɥdMyk+;`Io]]1I!&鍘CI E&I'*WH0H{(ǔpTryNzIzx#鑦(V ځ`9 Hڤ)&ؙISHS043IGTtT \_0=}T{X` \k0Ik0ӢRR+`*)EUGU(H,@ǣG6WWzS5 qω˲)5/j\0 ;ra&)fra:)өd?ȯ>b2 ɂdCDs,ç4iL9H!-EZiF-Hۑv"A6JroFڍ1Hg3V. HHHIH]Bc(OP[9#uiphTgQhːF ß%c%B(҉p~7p\(X8IH RRRJl ʳ Tno硲=+w#yHS0=_ ;"-_^Nw,۳iS분y zMH[v BڋtHxϖΆ?mcXH_߯")?+mYjSʼni~J ~ۦ\?[+^T>bןÐFڍ9P32J pZmpfmpNm p~mpQmf^7ڲ6W1HMY1kF4#,lͯظsft!˺AB0hv?a`G= =[{7} ̹5մr#ZMz-~G| rof]>őDإ%e⚕j^tGbG&5kY\GG pc0p 1B^׷q8,p;Ny-.K=, >q8q8Y-)1ֺX^K}/a2a/ޒV. X_ TW("XW ԺRK<_RŌ!u|IlBu'Gyu#},y%(n Zȫr@Br_@*mI]5p9: X[WٓA un*p[ `sly}u .T[7 LKJ*@fP6DZid9`noTp1rakf_zTke˯T}<`UbGC-ʸsNvJv^f?oo?+s*Bgⴟ LUtLhA_EL'8ɜS+m<pFxgaJs psPhgyП[:)> *9GYibWtԼ9_pK+;a~T.rNPW.uɡc?|AΙ@u9|8C[ѹŹWF3Αq>W01N?xbtbJ?^!E{0nls&IƍX1f@u*;W;Օ{΍-*97<韄2{Ps?Xyy?*8gXeIlkL yu5%Y\y+Zj/1gY.j5ݕjteWYs\9!aw7X76sFl-qY_U2[\#GG`lѮ nkku?dV?a!N[.Ņx5ܕxukpk.X?6ΕWYfZ \+u1/i64.sąekScuk+q5G˓\Y׻\G[]4)pe.^?rc #f)бHr 5zQepC *]ȫu yX] ªd m GQ/B[U{XѪ UY19u[y'~~L&GYU Tj\U|80j{R`n5j;ɑVqO 1*{]U {^:~6n aU{!(i`{$0OΪ{:j{^ ιýܒ.{BX5ý9"ս g7U͘=Sݻ8lIq3hXB ߩ%ӁUgVyX|Z¾eG U<8%v8DŽ9,Ys ۜ>6s'TF83M 1Q sApei3!^\Flm< v-ͩ|]le0 ۢZ18bI}/Ӷ> KhG;z,d[W˱{Ev{ia! C00Cx,Kaӿ$a]B]]U]uՍ-C-!>s}>1a!>uYz|zq9g3Vu"1gwNrsoQu~{j*H<k/{)-"~ M7)׃;M fdN#7+7CzSn/fw1]ud;kEY-9k$)VqnTnJn[zNƉl(ルD; WtDt{VC҉wuFSÉu|D-xbXOOl.wO&QjL,]~*E=* wRqBbbԽ Na$X"ΊM8?RHqWYH]SHeOY 8#U_FjRy>WGp]ĘJR݁Hs47EZus,Ҟ\*kLDוFYE:RO? k%laŤqs t/W'GP[d{Ez`#8HBUb=}OȡYe=㑣?r9=:k.\7G"%'n$^wZ; LRiG#WCx,r Vݝ#sʊuwQZZ*^܂C:MR٪x&rWYW{f!p١U֘ק$]GMJw#w7ٰNUn+~#/:(T$:2(Ol#󲻅mXXpu쨍Nwle;m^}HQ5 o1-+~;Clp|4ǗcLX _%5p^Y:AX-,_m *_{oe^yng..ߊm;V[|w/bx0T$<k+Hc2iceo=X=>~o™4= tN 4T;mR| 2;˟ cs-):ʢz~*F9JH]毅<\H]Pdg+ԻEO+(xC8 nW"7Gvh_67t `Cñ%^X>0t!_:+u8C:!/4 CB?^PօNj R6t;^!l - x`ݏ [(IśmᬸU`9xzEћ.pEW }M9a_xS Mqp8lƣ1[8N[Ba8_8Άp>{a_0Cz9­po) +,Fxa!|$~ZX Cz?Tu{N]tT ǜ93?<΢d|YO;+3zX.|3> %@MM)Φr~sҥ/tByt֥/ ;'UK]ŻN٥twv*wA,Uٕw*pw5*vvwU]-tWwurjUC]$J@vQv;{ԝǭ㼺W@wv5;tuʉJډ6Pv(?s~9GW.+ Wqv{v ݮ.wvm sݳi"b~,# s 20HYѡg4jгl 9K<@ zASy)|[匦Q5_Dk|kp͏@G  *64ڑa}ÏPa}ϰ`XFW5_BZjAϢVԁ6#}P '34Y<~<ϼ0 IOޛd^f)dL`}L?0_nwYGti`"3=ojyOm_3q$u=i jN{}iOojgs_ioiRKc+y95/2}Oe~C`~A5,n]c}Mj uΧ)uQ͛4 jTm1|9٢˺)ݔƫtu5ݺ9ݜ&fyKW%MB{Di|I̗3_ufYg4'3?5c̽̿ˌofx.;#/W5g(qFy(,2g26d^˼QxK_?Ѣ3eo{9 BEkM'U w4BCWc7Ms'p > W5brȑIQD(MHut[ZIKXpΧ(¥BZq5Ûp܆mpGqA<#xƣx I G Ϡ:YԀޢouwϣ?Gm(maыHE~_\nZoPMW)B CEy cо ra͠FTyd~m/ziFd ZZe:x=Sļ>Ǽμ@l6l_tF櫌 }`:Kn_wZ`de:N 22jfv0h pgm:sfD__wn&=eFQdgƘ#gq?0I+ #WNvG)}7Z}- (H$w!M5ԥZ_M~YB< *Ufџ8.N8+2$1HRT,IRT#K QjZvC$K=RB#K ǥtA$MIWkҜtKJkZp!.xހkFFl[Vm"`Gp/އAtM'8Wx?L- S-ϦZR-jy|T_Z^HjGS-/Z:RZ^F G T?Au:럤g@5g~'Uhv?]OT?Oy/6 _I|jsf#_=6#,TTI-3Gjѷ;zIyʂ1mwU@=A=g4ZqZݠef|WZoѻI}mnfUZ e-qMZ~kxmXY/wKz(do}nz\Ǖb{q\=ۏ? ׊A}! nV@Ip#о#$8RN<OyOcqgz!a#O68/{WU ׽Oޛm']$qɻ4xc} 4:#'Hl)gr|+ȧ|_+u)J}eR1U=j_c?56& X}R Sk%'H^p og- av)y`PO_"0ۛp_N Ґo?m Zz|wÀ7s8;}ǟ,NK-4o]=Ӿ3Ҩ]}o*[ӹ8ɕ)gS4y$'󚜗{Rc;D8l3pgbԮ }'srx#?_\ky7W+U?E|k,vgw$?j]߮Fe2.*NR'uV 6m_p%%_X"'UHھ@@ MTOI&]mEy S >Ds^k2e⯨?$}1)@hVX,7J@|lү&:$HH3Uߘ+󑪟Lu 1}]QϝW,rW]wi LDq?wu]}roRy4t95=WgGP =[RƳUG! b B?AGw;Q(sT:5at4Chgq8:@plw8=C㎓-3s-S*{)89rUsr;:9rZn-q\ Wέ6pFѡI 0s[6^DdB"R\#σ'}玃nj ͡/}З>h^FBwC_t75: -orqZAwC?AwC+&:4)ZEwC?MwC?CwC/gѿ=?{JD?GD7==/0ELj{o=F'E'DDߦ{F'j{ffYЗ'e' mK>3P *}Wۯ_О` `0 #]CW7 K0:6a"*Yf qd؃vRVj&6VH[6F7ozCO4Fsh-hՕLД@Ȟ3mCD?Eɟ~IIDA}"zZp h@.KT AȬBg 39.fa_[Bu:̻ }0T0tJ:oY\G?|9#F_K ng{IaulZ)ld*[ؽpfC6G=Jsl%=n?)IZCU%{ogA:C)9Bʪ2Jq8OOG-T_)QdY148BY"B9k&cB#a<9;8E0Os %VV"%v5)Ph$αlYRb+W<.[EzC i}GV{ԱmxR٬ё6Dl" g:G9ۑVOJwX!%n6e0#ߎZMFc3 p:D"Uh4IsjM:wH;<`;au>(о>ͱ=8jA;xIʞpr?pw\tL@:.^`.㎫Pu=%[!8nCKpU;z68p\WJmE[O앫@6qM`XXʵЧ6{f(9\>G,p0蚁[\bl w-pΝr p7#W6@)n3 l7J5)CF 6 rp>=5,|._e|%W}kz7Dadrж|z"p-WۡF|)~/?ĕGw}tgss~ڹ, c0?ПЗAQ#E087ϋ|h,ĮAg`2R402asT)a. P;2P״h>j(gQl|asUB(n1@YPe2q2+_vN=bxuq/}e{CU ;B11! Y\X'ljl7K~}Q"ln z`D ϟxKl+A"l+ >{ 1pB8%e y \&3Ppd\ 7‚mE(y߉:{3 &l zT8@睥}vV8;Ka4jgs7lrZ-69X#[va()g!Aa9`i4W@+Ly[ y #kk; r$ssm μ;c2e简\!@n}[.AVc63e2h̫k5t1o&]*ry\hk14ͦkjEdn'ޡmblfk!ߢ}阭i`4B~ppV]AE*u7TV`IC~a<8":@}[sV @tTR/~:Xa߮l4)^U)h[6Vm§"z[-sO.u \#`xF~1*\駃36jwr7w`F!O`0ߥ8 `ޤVƀ?̜zlj=Ϙ} ê]vE[s6ҧ?Ł+mk]%%e[}j?{3o2)6O24r z߇qJ_Lͫq>>O<ΕUiƇlZFћA6W( ol^]4115~ yY1D YؓRcM*??ћPڻf3Էl3tlsT$_Y2n=QZZmc\KڮX!B dax?I<`X z^\+JN0FVt5H(8^TX'sm.P(QΧr: l4J=-[z^xR>'TZ,p^O~0 ('㣿 X=X,)A:|ͩeo}忝O>d y?(Bcj2YM-6Q`6EMqSi4d:h:b6NFMcqӤid4kicZ4-5f`5Pߕ U@l47[MvӰ,vs9acko>d>j>n> 13_0_2O̷{e%ےg)X-,,F\[,[-,Ex,%b XÖc&l9)Վς\LeUZS `Yܷ""˚>#RqAOqa-Ņ,  r/._\ȣ2 B>mh@o}΀ ^!`B&C԰}7B_6o[ᇆp黹±[092J7*,%*Tӎ jJZcR]=P!----IeɹiWC*=I eUu 4a\Y27!Δq”c7Jl/27UoL&U.&6 C i o ʤex4HUGņv.`>U_{wb ip&!rrISB5I2EIq҄n;9n9r;rK$Y_d"Yطd]9_fd+W;f߲بKB= e;t{"/ @>7O??a-;e[7fyԷSF [ NDKJG`,;0j {g2 3a0V^A,'7T"7"fL(}`@3<7"[.0Bohz)M DJNɆ0cYdRE ~xYl CxElL 1_9ɑ3v[ɪtzY 7q:E|xVxPDeIiv>xX-}V]%Oe6&FޥP88K|?bss 8^'ad>e(&S4o}~ujѭ"+aeap~נ˞9RׁGDnBnl~ht&h:V%+}%d/lG᧝ݑ;YXA_ V@Jcx˃ bȗ;`|g|g|!Kmij!؀ ȟ"*YKOxE\z]ăh$AmVx_6G&kӁX*$gr/V>=`k.Gnmd\a(6`]\+} ?a$Y Yuv7ur N)~fm?>e T XLn\7=L? f'h d^|""sUhl%g3&se0wv[<)m?"~ ; ٚ3)O~Ugd^꣱Qs`6̄[P]Τ:jfKP*y|'3gE\a&2g$Wc7aO/?3Y$y0xq̀!$OnaA,[T X\È&X[h6yQuBY"=|g4AxvTTTyԭ 3^7?~?"|90n6|ռ}oE<Ʊy~xMs` 7ac(W >b^+%t(f-TVGN'MF"!CfQN;j!UGlR yMa R|.V/F*Lγ4 ؿNJuT!;,Uۺf|rz5y0j"/=Jk k7;&z)6,ûxS$k5~>|S\=Dr^u.jͅ{+ `bw}b[%gdpl 8 SߦˬLфn>ss`w8/$;6ʉG. *ӉʯP?"k-8+dvMaQUDL-o,94b]{D-s3uam=kmʞRZcm̓dpJ(G#ϡ? ^xh{ n## yk>={LzYFrsYk6gjpEy.**O>v?g-aǐ103=~ur6"~ps+埄~~R49}!c3᭲qڶ'?KR[9I ^&G>x0з' *{r-};W˼ͩ?#z^Ve95sE &"y Cc). >%qXc+?- 3a9I? &;8: jƯf?Yq2|򽜗ֈݛrV`X䊥yoJ_%xG4ś`63nF7зB3F>+gO?gM|d4Wr'ÖT>t$?}ےfaGr%!9Qtw_nۑ5.⭣ܭ$*X>O쨜ZZ_hKla+0f0!ooPg;.[jd8Xv@B'ys㼥,r,GZ6,["?"rlxK$O&A`#j!ܒy&ؼ/Ò?YڸQb愌,F.<#VzUfi̗"4 RoXٴu2=P s29|V2^fLȋw0]0S~Kc? ٱ,B.A^E4 uy#z+Gf#PIJh π#Y~kdVz9x W]ќCvpK ?5x3شda!h Ы ~ `2rex y2$1.30E4;F^ wa%zBd ΅, Cgwt_4"_yrylƂ&N Ҝq%ؾ;Z4xcLwb|"6a ɩ0Ua Or-W" S-,!Nt5)zBn1aHO xȗ E1%m%Wx{~'rEV]Se47d15L,1|5t"}yFDDGOcB[޼Bkn#BWy{܌0ҷ]=#f)YvɕJf6`!~B ش/,ZM3C*1d/%֕e{ :1s#; Ti8~Ype>c,# iZgD~r"cI08ֹdj7uJO݊GEYlYY'v'w; I&=X@=قcAgJr߁}.~~Df'[lEm),u+d)6{7[}f՞) k{n߀OA^t/zɒw={)fH,GW*x|!I؉,]B.Fv{D>pQ~ݵPXab?owM\=NmpgM9,P-%v}ȋ@v*fSQ%s0<vDil /1^Ko3>ܕd1|+Éݧ}5ږ &d %Ú,E i]1 rF/Ѻ~Jμc~*oSOebvJCϻ-GoPgM=yC}7ss"-eXTV:!*sSWy7\-w6FSM샵:E"=5dA4|ȏ͗,21yWo֢*@zE֯Ȯ__d][m-^*4c3C]G=Ͳy#[̻wKV}]*կd-k,q_V\o,^'E~xɞwSK5aqܓ /%Mֲ'o8h5W=-s']GU=_=H썒 >wz ,{_H"Q'D*%B d"EoGSh}=aKxVhN Uha0܏e ؑJ}{`y z0VfZ<4\ q3 p#Zݔ/s'& fӺ #=~y̸\IijFgWC,y ri6N?',fGd,,ps$r*nмfJd 3/zܬ!5V*YGlppˉh=Qd1χM"Lxp3x7dԾ99*x A1P?*wDZyZ$a7ql3]TT5dMԆGXz=dV?@ϜBkԃfWQ3_eCudCv\9e 3RKZ3 !L*_ci7QGA?E=aKxVhN Uha0܏e ؑJ}{`y z0VfZ<4\ q3 p#Zݔ/s'& fӺ #=~y̸\IijFgWC,y ri6N-NWi@~} 2M8E\7]ןЗQ{ʈj2typ݌qU؃$|2*5pDZyn[@z%КP8 6mLu2Ŧ2Ɍ!~ uCftsKSG*/9Ck om؅]OŸ?~4r*~f"+;6nNW8$W|"WT5GS hg=߃ ѻ]DW /Ћ: \ͻѸ]+LlmL|wk*}ñz+Ȭ4<95?腞S WbCUn'Ev3lR!H͛iڋ4A%oEv=j5m9w f>o:WmI慄KѢB?U %B4_ }}3h=% "m,nmFe%(l8ͤG-mEi+I" ޅf#k<p!cOqd!ћykQL*} KO ӕ^-yCX4 l/Y;EZ :쐽m.V=imWzFSyCs4.'[)I:/iMABx/ נ5D# ..ZGZpVBU4rls/+30#=.5A!:+lp"#a:r_\ 6:?E."HYf5 iKkqUWڸ L(92M0}ix㍇>U]f6kW6uEϻ<_b+Y#7 }GRbouڱ$+|\qN  2 1kF!WOU~pU ' Ӕ0M*6'K ]DUY̵FyCVsR]NltI߱;$/!c bB56hz:$۩\%̔y3qy7;"'57N\}3hW,s!y ҚF240 u7bI|F?8>9V** o(UL8LgRj̠>Ç=۵E'UJ%PTIUKݦ;U{uz袞UU?zB=^싩*Tmzi:!{ծj`w*CP7]$`**YQ;T ;߯z+USՓi*LΝ۪];MֵC2ٽXW5Qw6nS=1jjLTYɝjЗU%lnT)[O5TMU+VݣP}lܷja5%zUTURUu롾jZv@ݪƩգjF2>|C8_Ap%py>1V`N~3 '5,+[`v]yb>Á0 ϟ< µq+C<5ρ'Yx^qazߠ,ŠqhPրu`m?`7> ApC F1pb'iu8· avp%p߰dž ã̅yʰ2BdXVÆթ6-aG -Ap8 ')pep6\p5hY?<O{< c&aOe %[`pXCag(O=ɿ᧱뼼J?]0Jo.Hݽg̈^o{ OjV_XW3H ?_PFK]wҪo i{~ޤ*UTӳw3*ֵO]Zj:O+I15Lc4(32v ʵ\͚N>-yJS/e~@ż_|.RωtZ=\J]TrU ٷ-WυSеKW+s#?u޵V_->g)>%o~Vs#m͕{UH+y(y)lϹ~WUfɅ>7־AB /cϝF-lfy3o6m_?eWt%WTab͉m6&O`5;Ww2I͓+?鮤}SAVFK뒺ȿ JxL1۳\ڞFjQWdC*9҉mZKRFWiPǞy$RF1IKss>Ync MQrlm?9~>Ϳ<Y~Y,OFv$޻-hοlIFۉpe-{hKV1mgYQ-.KجY5جOZB)0W'QM{X/ū߳zI oa9{^&{+LM5^].׼t) 5C:TDL]ZVo򺼚o7tu]]utg5GOw@YQ4mWwܾwfn.,9J.a 9I JX$aa A((Ar % J$"9 M1 (~;v͝;wz 2Rn;eoN`&&6˩r?lQA*T)Uj'oLl*qfk0[|f+ov2;XY0Q/ Y攕;o8fzGpʏ0J0 LI%WY1]EbN̩`ṋb ƨd(X bAJEJűJ*5R* 2*-V *6F*Jacs[bK b[c{ ,; *{{\8~UPyqSpPq$T8G8Ǫ8ǫB8'8'"88b8g8g8WqS%q.Pp.Rq .Qep.SeqPFոZUuNU AUQU͸YUUUmMUCUǝS?⏪ݪ&Ž6ăugZFh2=d,Um61c63Aln64[-!af.fǴ"0=>3B̌!)f, a6c.?>/Ra,4X@Z, oF,!6ĆbSx0` lY lAv c<.r{B~1{C / ȏgPP(q8/K(p188pN8 'A SUӠ$P g,(sp+(q>Åb\ p).C%\+2UP_U(w~)wnp e=eۚm-mmEYulCY.#Ψ3 (7oe *^Fx[xoד|kRlhHDc !(qqw}^EsesՖh;wcfka"̧ %RP jB/&)ˁ0JXO3 ){>϶s]Mt#OKzm@O vza9Зm@? d~>a90ml&~C>g9.l]A^TwK3 D#@Zv@d00?2De6itFz#dd6^q=3ɳOJJon"dZ6ÝRmh ,Fޓߍ4IdF܈v}G2B"#܈0Lgho ˰ h$2 w zIߑF188FI$ m(5]Ts;QmRU}jwg458f5G!)ʣ_gGF{͡+7[JVkZNW^|j:}ޑѿV w]?ܣȗ%~0fz'F}l'@_aO`]t0 ϩa0F0FQca 0&QSaL0fQ>s+_|X@a,%rXAVjXkae lMV#`;`')=~8)p1S9I8 s.E \ltnM܅{pCx)!kZ|]֑ue=Y_6o7eCH%ߖeT6ql![V|Gme;^vʉ<(ayD/Uɓ<-ȳzDҟ`=DC0=\_zz'zzz^Ez^~+JVҫVި7zުvCw]Gޭzޯg}HGQ}L_ >O>/;~/4=]3,=[_7M}K߶޳޷>>ZݬV#m]nvwel{=lGc8{=hO'S4{=Þiϲgsy|{^d/k:{ho;.G'{kI}>o_M}۾cߵ#p1s9rN;g9s\r.;W5sùrn;w=y q+/%M$fBA{+ՇOKOz" R}]oz}1wob="&szG}z&@6Ef_ؒ/l-yK4oV Qے" e9Y(+!`ZCೖY@[W+tc;őϳbIRx<\)O>)9&GQ["-7.rl"o:aNb'܉p"$NR'$wNJ'Iu9 NF'ydumo13b" b{+s~!})cRLƜ|/Yy09FK7;ع" eEڐgDd-D +ZVO#B~^|EW1ʈb4KNh";x&n!{BS"/`8_=%GH<T*3TU1 eÌGoN8g&6(yK$7wDyϼ'R.7H*FW|}Dvl7׷X-me|[|}}xwwL4!mP6cu\%jV6Οß[lcf?Vl[g{W6))__NWW?b@T4&VSgVbugLj ijkM;-7W#ip+. Eso( >O{d&MOHLc~Z}ZEPq.S t4 }؈J84-DB'$>|ɠ;%DD" RPT"H 4___@:{jF|L&Yt̢F}zY'bdCA=x4rbfvMŲijNxgsaysa9 T2FƐb2+Jkʚʺ`)wH1d ۚǹ0k5­}~HjCu:AZ{.3@VbI㐛>}S?O@' NC!g0PrEj#"g||I/d!Hh,cG&{#}4'./ _W5ϚO-B 1-:my2z=aOcӂh|0F%uy[PX!L\*WG]EMl \-ūIQ[O,ʢml2.>E3.~%@!Xͭ0FAUF!f4[ e(n]@i~Ж\Eܿq˹Wp|#`5GaUXO 68QtM:8JZ&"Ub%R*q|4(]w Y޷}'w9[0!מk-u^TO'IuIdVfCyHpR C&!!yy(y}O?ܵ^"ؖH$wZ Kv|@^R 1T-PX䥺 A姺:N(!JS(Ku @uQwE%;*TU+Q=ƌI&z|SÐA*? T?~$HK@VUo߶! a 0bxl;4@}ۻGEb)$bEQ ewsb65ö˶[b۷llllElb\K>v-y*Z>gȟcFגǙؖ&pM䖛-7[n Tni܊ӹfp䖛嶇?Oˆ'eē1QxrF<OdV+{H$j|O}C\Dk8Fv"?[jF{)XڽB&(CHBcHr~q9- E]Q_uDKO'².j|1qxk5њdMXS)׮[﬍&koDC~uϺo=Z6=s {=nGڣ2{^ickW?ۇ/o)}ξ`_c98ADNv'vBNs;NS)q:ŜN US)qʢAD ;xa L5<除*miDn4 D<* jZᾯ}!·̷ nnn $s*oZ'!;b!5ӟ0ٗ@im*4>U1wWg~swMZݵ_g]XFL݄3Gcs%4gZ_kJ;=m!F383)njyN<=fR7r%puKAQ$v9R#Eq =3ggbnpnnHn$ܞI=q{Fq{&vK)M|c>q Tr*ﻎF*yt 8Md͑2W-qSeRBfYUEg0[f _sbn|0*2Xa3l--w3&{bS_0#q48'T3q6y\+\pn͸܉?n܋ cx5{.C\J#܌%{ʩ'־wyv CٟLWp4z~Y(M/ߔ(Wuͽ^zQ^,\ܫ^KK?rJ?j|B|B!_,_V?^(ҋ?7CiA_/+ ֋%Jߓ#=7s%@*6?O' !0F?a&̣JX h B|./OfG2#qtuIy^"+%pZ!}{xyID\v+x㦸E˷]@<}Ŝ)}T[[}a2\Fr ^MA)e:ZN/i&3o Jd6Z.r7\}9ʱlE˭ݷW'{>fZk hy2_(R3h h"8;H:Z^H˛H LM:C|#<ʉdLOǙ[FB?s 5` "RDAk!X 5` "X 5ȓ3D+JDD+JDD+JDD+JDD+JDD+JDD+JDD+JDD+JDD+JDD+JDD+JDD+JDD+JDD+JDD+JDD+JDD+JDD+JDD+yFd#y-D d[rbҴ"|fvT2ڄPc' ѫZϭI99G)rNQM$^)J,#ʏ\jT-~73|^IrzCTJ )ɷn >;Iag^7|Z1Uqڵo.&,Jk5k۾]ԡ+"IVM;Ծy|;vh߱q|+FP:w~~{ZhGGMZ钡ɂ111PPz~_9`vF|CD1sՋ d/!%x+,IJscn6iҹoǍ9'2N?ג]+5RW0_ww9/L}vpmH"s̷au掼2afhi$<Z~;M-?Iujݫ=vo4|BCq?ijBܕHb;2EM8۲6$Ylψz+j *5XPs#*m|&Mh+MCzjĊ-2>CܹvlVմ}iݡcfwMLHaHV`μ19P條B FPPCoq'^qc)7rjcZh?PiMY,Vmdk) |xnŰ :T3~nT7>઱5Jb;^8?^ym؊kXuou:> "soiǥ;6,f&^>w?YU_g#W6ܾmʵ8Զjz| d|j|eM3%l2콳\_.59rqsfQOdfXl[ 5+FfsGoȬܸVR4GGp.M_8ШGvq9k7n *'P<1 ӏ72+LO>nWUqӖU6mZ *[`΂J -T&&S(RԣZqj3mEjMPfsyvΑSjza.E4i&v)bęJM2#e ؇*[77IVBfpS#.yfMգKz]?n$o# ?gT]%"&M EHP"RC5қJGK M`6t}dz;79gs7itVUʔÿ.DpSIqj3P\dKFDPs=t կơ:|͜=VPK{Wo<=~__y|46 Hۻ۶z._h4;فVpH丄#5Ρ}oOX .3N*.W0*DA#XK(n"*2A *@{UߞwSN/g>n׊qs~.caVNRubI"Պcjd|1bJ-MtKz%jk"V VbG/7 q"s;z / l~broߓZfy8fh"a:@\- sB?8.LS5+@ͺ!z:=RB B|NOSyQl5ƑMbSJY2*N8D-ƻ*=x4̲:DŇ $Ҿ%#̱W,YD_tP!/X<6rw'!A;'{'+/;>o/Gwv[)PAHP&)%)ﯨ)Ĝ`l+O\s7ώوea9uAzb3U7P z].Œc -{{5T6sbnZFW^W1n:=5.!XӸ(,I=;FXq7pb5zRaH6 4cD^ [D 4NT"PQVr8Ib*;,\|"59~O8Z*ƒ7jN{k '9v;8m&p0HIu l8~l,-!}Ӈ2p(v@A(7iR 7lieH^g>(*``7@ T>n߻1Ri6iض&ڗk"N8|IX3o]@y^-Sgi{RZF(*p2)8%8QVZ-,ST׷թ>=Jkm-ΤK!OGE&OO *gPAi8(*~Pb,A gk8&Zk2 ݡA`ӂ1%BkVO9ָ2jN P\xۆv w"f͸ŔUFa;Y?^ݲ>+6Z9Hn'9\S rM4SAG]a bډy T06Rs+}$\#Fq@bT&bCvI5(E5ސlLD9gp%2Zv U' &|PYWo?qqmH!i"y"<2<6#?"q&%7.gxwLO,]kvBHw E]jiV[ʶJ JE);o:%3d2R?G8J*fqO Il9`+eBVSjWz!tjG_8#W?PwL0@hT/o8hf(NՈ\ tf|uKloդ.燯q Qua4NWHYptx+ڥ~5$))|ѮAr5['ՋE#[aQFhtg MYrw ΕxnC 9f <_ĹC#Vd%t Mzƛ+hE#w޿ ?ͰS_ _M+(ChzLS(C,@23`?x&YѲ}aqm!K1tƇ"^{|+pU" ׉>VnDXF}Fic5IWmɐ᥃C%u6žƐ6It߬"B7ǻ0o)Lj7yJ:qS:K`;5N56!6-:p;V$#p" Fm^Bliv!Ev2oeo_@,-ѺOʭA{ 펯Bcx( d€ܷA^ >1 HǭHAXpп^Xw#g  - jH<(*.t[ vZŞײuDuѳSjuw:iulנk,9&*0f%ޟ;t:*)do QϺ&Wˎ}jr?"IIgEwSU6*/gxT Y}j%6F!n }ס(Y*q6~nc%ff#qdnT+輧G~a[e_&a@?~ҩd`y7j+82nGcp)82(v1OqT_Kp`Y?~ؽU!Ik2k.!eүF=';Je:)_[QeneҧY~K>ڎ+,%;RIѳ2Xɮzérz|O )7z7K|gM TCJhkr[k=Sɵ]9u7^qP*)tC4]^t} z-lz*,u~Ƽ7B=?QUjA9nA{ 3ν 9Bm™ޚbqw0S2[lO ِ endstream endobj 483 0 obj <] /Filter/FlateDecode/Length 1052>> stream x5wsj Z] aVJJ,3TFQh/mZ̄"22Y\|?|=~ l.gv'O K5QqjD )ֱL{DU:$zWL)1Xcz&WƮĀ~s'WT,K iىӺ`Vba[lĢؒX!OACU%mNԬ;/Q/}XA&gh3)i]DY0tGbXLI 1#1$}Ef~>2  V5ú*n JXCP5np4Fi}ʠ,8PPp*`T!8p#qq8':N‰8TZ8 uqDCEc4yh 9.D D+\hR\qD;UZ\7F܄θV܆.q;]=ݺ霛ιd]jvmfG]cvH܋QŃx00c&c bL<0 1c. <0 O<%xc)^2X2^x c%*6Vc >Ļxa->X؀1> a#؄/_[l7 ?c~  cvnDdȺ3+eȬYfPPPPPPPPPPPPPPPPPPPPPPPPPPPPPппппPпPпппPпииŐȐппPпPппппппппппппппппппппппппппппппппппппппппппппппппппппппппп]:cz^;1t͇$ZG-C~V%&SyDDˮXщ5'W'=,l}Jr endstream endobj xref 0 484 0000000069 65535 f 0000000017 00000 n 0000000141 00000 n 0000000253 00000 n 0000000640 00000 n 0000005661 00000 n 0000005830 00000 n 0000006071 00000 n 0000006124 00000 n 0000006302 00000 n 0000006551 00000 n 0000009891 00000 n 0000013999 00000 n 0000017246 00000 n 0000157968 00000 n 0000161072 00000 n 0000162248 00000 n 0000162420 00000 n 0000162661 00000 n 0000162840 00000 n 0000163093 00000 n 0000163218 00000 n 0000163248 00000 n 0000163401 00000 n 0000163475 00000 n 0000163706 00000 n 0000163867 00000 n 0000164092 00000 n 0000164223 00000 n 0000164520 00000 n 0000164854 00000 n 0000165145 00000 n 0000165278 00000 n 0000165308 00000 n 0000165469 00000 n 0000165543 00000 n 0000165785 00000 n 0000171888 00000 n 0000171942 00000 n 0000176470 00000 n 0000176604 00000 n 0000176634 00000 n 0000176796 00000 n 0000176870 00000 n 0000177111 00000 n 0000202014 00000 n 0000206216 00000 n 0000206563 00000 n 0000209205 00000 n 0000211371 00000 n 0000211542 00000 n 0000211783 00000 n 0000213985 00000 n 0000214266 00000 n 0000218006 00000 n 0000218267 00000 n 0000223957 00000 n 0000224208 00000 n 0000225450 00000 n 0000225711 00000 n 0000231417 00000 n 0000231480 00000 n 0000231581 00000 n 0000231705 00000 n 0000231866 00000 n 0000231983 00000 n 0000232098 00000 n 0000232199 00000 n 0000232327 00000 n 0000000070 65535 f 0000000071 65535 f 0000000072 65535 f 0000000073 65535 f 0000000074 65535 f 0000000075 65535 f 0000000076 65535 f 0000000077 65535 f 0000000078 65535 f 0000000079 65535 f 0000000080 65535 f 0000000081 65535 f 0000000082 65535 f 0000000083 65535 f 0000000084 65535 f 0000000085 65535 f 0000000086 65535 f 0000000087 65535 f 0000000088 65535 f 0000000089 65535 f 0000000090 65535 f 0000000091 65535 f 0000000092 65535 f 0000000093 65535 f 0000000094 65535 f 0000000095 65535 f 0000000096 65535 f 0000000097 65535 f 0000000098 65535 f 0000000099 65535 f 0000000100 65535 f 0000000101 65535 f 0000000102 65535 f 0000000103 65535 f 0000000104 65535 f 0000000105 65535 f 0000000106 65535 f 0000000107 65535 f 0000000108 65535 f 0000000109 65535 f 0000000110 65535 f 0000000111 65535 f 0000000112 65535 f 0000000113 65535 f 0000000114 65535 f 0000000115 65535 f 0000000116 65535 f 0000000117 65535 f 0000000118 65535 f 0000000119 65535 f 0000000120 65535 f 0000000121 65535 f 0000000122 65535 f 0000000123 65535 f 0000000124 65535 f 0000000125 65535 f 0000000126 65535 f 0000000127 65535 f 0000000128 65535 f 0000000129 65535 f 0000000130 65535 f 0000000131 65535 f 0000000132 65535 f 0000000133 65535 f 0000000134 65535 f 0000000135 65535 f 0000000136 65535 f 0000000137 65535 f 0000000138 65535 f 0000000139 65535 f 0000000140 65535 f 0000000141 65535 f 0000000142 65535 f 0000000143 65535 f 0000000144 65535 f 0000000145 65535 f 0000000146 65535 f 0000000147 65535 f 0000000148 65535 f 0000000149 65535 f 0000000150 65535 f 0000000151 65535 f 0000000152 65535 f 0000000153 65535 f 0000000154 65535 f 0000000155 65535 f 0000000156 65535 f 0000000157 65535 f 0000000158 65535 f 0000000159 65535 f 0000000160 65535 f 0000000161 65535 f 0000000162 65535 f 0000000163 65535 f 0000000164 65535 f 0000000165 65535 f 0000000166 65535 f 0000000167 65535 f 0000000168 65535 f 0000000169 65535 f 0000000170 65535 f 0000000171 65535 f 0000000172 65535 f 0000000173 65535 f 0000000174 65535 f 0000000175 65535 f 0000000176 65535 f 0000000177 65535 f 0000000178 65535 f 0000000179 65535 f 0000000180 65535 f 0000000181 65535 f 0000000182 65535 f 0000000183 65535 f 0000000184 65535 f 0000000185 65535 f 0000000186 65535 f 0000000187 65535 f 0000000188 65535 f 0000000189 65535 f 0000000190 65535 f 0000000191 65535 f 0000000192 65535 f 0000000193 65535 f 0000000194 65535 f 0000000195 65535 f 0000000196 65535 f 0000000197 65535 f 0000000198 65535 f 0000000199 65535 f 0000000200 65535 f 0000000201 65535 f 0000000202 65535 f 0000000203 65535 f 0000000204 65535 f 0000000205 65535 f 0000000206 65535 f 0000000207 65535 f 0000000208 65535 f 0000000209 65535 f 0000000210 65535 f 0000000211 65535 f 0000000212 65535 f 0000000213 65535 f 0000000214 65535 f 0000000215 65535 f 0000000216 65535 f 0000000217 65535 f 0000000218 65535 f 0000000219 65535 f 0000000220 65535 f 0000000221 65535 f 0000000222 65535 f 0000000223 65535 f 0000000224 65535 f 0000000225 65535 f 0000000226 65535 f 0000000227 65535 f 0000000228 65535 f 0000000229 65535 f 0000000230 65535 f 0000000231 65535 f 0000000232 65535 f 0000000233 65535 f 0000000234 65535 f 0000000235 65535 f 0000000236 65535 f 0000000237 65535 f 0000000238 65535 f 0000000239 65535 f 0000000240 65535 f 0000000241 65535 f 0000000242 65535 f 0000000243 65535 f 0000000244 65535 f 0000000245 65535 f 0000000246 65535 f 0000000247 65535 f 0000000248 65535 f 0000000249 65535 f 0000000250 65535 f 0000000251 65535 f 0000000252 65535 f 0000000253 65535 f 0000000254 65535 f 0000000255 65535 f 0000000256 65535 f 0000000257 65535 f 0000000258 65535 f 0000000259 65535 f 0000000260 65535 f 0000000261 65535 f 0000000262 65535 f 0000000263 65535 f 0000000264 65535 f 0000000265 65535 f 0000000266 65535 f 0000000267 65535 f 0000000268 65535 f 0000000269 65535 f 0000000270 65535 f 0000000271 65535 f 0000000272 65535 f 0000000273 65535 f 0000000274 65535 f 0000000275 65535 f 0000000276 65535 f 0000000277 65535 f 0000000278 65535 f 0000000279 65535 f 0000000280 65535 f 0000000281 65535 f 0000000282 65535 f 0000000283 65535 f 0000000284 65535 f 0000000285 65535 f 0000000286 65535 f 0000000287 65535 f 0000000288 65535 f 0000000289 65535 f 0000000290 65535 f 0000000291 65535 f 0000000292 65535 f 0000000293 65535 f 0000000294 65535 f 0000000295 65535 f 0000000296 65535 f 0000000297 65535 f 0000000298 65535 f 0000000299 65535 f 0000000300 65535 f 0000000301 65535 f 0000000302 65535 f 0000000303 65535 f 0000000304 65535 f 0000000305 65535 f 0000000306 65535 f 0000000307 65535 f 0000000308 65535 f 0000000309 65535 f 0000000310 65535 f 0000000311 65535 f 0000000312 65535 f 0000000313 65535 f 0000000314 65535 f 0000000315 65535 f 0000000316 65535 f 0000000317 65535 f 0000000318 65535 f 0000000319 65535 f 0000000320 65535 f 0000000321 65535 f 0000000322 65535 f 0000000323 65535 f 0000000324 65535 f 0000000325 65535 f 0000000326 65535 f 0000000327 65535 f 0000000328 65535 f 0000000329 65535 f 0000000330 65535 f 0000000331 65535 f 0000000332 65535 f 0000000333 65535 f 0000000334 65535 f 0000000335 65535 f 0000000336 65535 f 0000000337 65535 f 0000000338 65535 f 0000000339 65535 f 0000000340 65535 f 0000000341 65535 f 0000000342 65535 f 0000000343 65535 f 0000000344 65535 f 0000000345 65535 f 0000000346 65535 f 0000000347 65535 f 0000000348 65535 f 0000000349 65535 f 0000000350 65535 f 0000000351 65535 f 0000000352 65535 f 0000000353 65535 f 0000000354 65535 f 0000000355 65535 f 0000000356 65535 f 0000000357 65535 f 0000000358 65535 f 0000000359 65535 f 0000000360 65535 f 0000000361 65535 f 0000000362 65535 f 0000000363 65535 f 0000000364 65535 f 0000000365 65535 f 0000000366 65535 f 0000000367 65535 f 0000000368 65535 f 0000000369 65535 f 0000000370 65535 f 0000000371 65535 f 0000000372 65535 f 0000000373 65535 f 0000000374 65535 f 0000000375 65535 f 0000000376 65535 f 0000000377 65535 f 0000000378 65535 f 0000000379 65535 f 0000000380 65535 f 0000000381 65535 f 0000000382 65535 f 0000000383 65535 f 0000000384 65535 f 0000000385 65535 f 0000000386 65535 f 0000000387 65535 f 0000000388 65535 f 0000000389 65535 f 0000000390 65535 f 0000000391 65535 f 0000000392 65535 f 0000000393 65535 f 0000000394 65535 f 0000000395 65535 f 0000000396 65535 f 0000000397 65535 f 0000000398 65535 f 0000000399 65535 f 0000000400 65535 f 0000000401 65535 f 0000000402 65535 f 0000000403 65535 f 0000000404 65535 f 0000000405 65535 f 0000000406 65535 f 0000000407 65535 f 0000000408 65535 f 0000000409 65535 f 0000000410 65535 f 0000000411 65535 f 0000000412 65535 f 0000000413 65535 f 0000000414 65535 f 0000000415 65535 f 0000000416 65535 f 0000000417 65535 f 0000000418 65535 f 0000000419 65535 f 0000000420 65535 f 0000000421 65535 f 0000000422 65535 f 0000000423 65535 f 0000000424 65535 f 0000000425 65535 f 0000000426 65535 f 0000000427 65535 f 0000000428 65535 f 0000000429 65535 f 0000000430 65535 f 0000000431 65535 f 0000000432 65535 f 0000000433 65535 f 0000000434 65535 f 0000000435 65535 f 0000000436 65535 f 0000000437 65535 f 0000000438 65535 f 0000000439 65535 f 0000000440 65535 f 0000000441 65535 f 0000000442 65535 f 0000000443 65535 f 0000000444 65535 f 0000000445 65535 f 0000000446 65535 f 0000000447 65535 f 0000000448 65535 f 0000000449 65535 f 0000000450 65535 f 0000000451 65535 f 0000000452 65535 f 0000000453 65535 f 0000000454 65535 f 0000000455 65535 f 0000000456 65535 f 0000000457 65535 f 0000000458 65535 f 0000000459 65535 f 0000000460 65535 f 0000000461 65535 f 0000000462 65535 f 0000000463 65535 f 0000000000 65535 f 0000237417 00000 n 0000237622 00000 n 0000238092 00000 n 0000347526 00000 n 0000347929 00000 n 0000348253 00000 n 0000348655 00000 n 0000366239 00000 n 0000366600 00000 n 0000412994 00000 n 0000413443 00000 n 0000413809 00000 n 0000413887 00000 n 0000511121 00000 n 0000511422 00000 n 0000523734 00000 n 0000523778 00000 n 0000523806 00000 n 0000524102 00000 n 0000615876 00000 n trailer <] >> startxref 617133 %%EOF xref 0 0 trailer <] /Prev 617133/XRefStm 615876>> startxref 626974 %%EOFepubcheck-4.0.2/docs/BookReporter.docx0000644000175000017500000037736713017276730017231 0ustar eugeneeugenePK! o [Content_Types].xml (VM0#"_Q"!#D\]{XvdOw8inhوK~hgsv-XV:6gן, (vzj>Bېy%2Wy#B[׋;.Eb`'(ĮvO['ݲc/JLy/Lыاq O@+-Rު':2B6{BB\y\ǹkɝE?8rrg(2MOWZBlwB5U֭ OSq`d;i <4Y؝ـ'՟Q_ 1PAxy-HۢIwk1LH8"=FO/-"f3\ȾTI SWY ig@X6_]7~ fˉao.b*lIrj),l0%b 6iD_, |uZ^t٢yǯ;!Y,}{C/h>PK!.  word/_rels/document.xml.rels (MO0 H*wuuҮ0,uֈ&ؿ'[a ʥ]5~ڱ=}*y9I@sSH$.Xe4d̦'\)kSIXPx ԠabM5lt8mAGg&"'v^M#}Br5|@cG /$ fW9nlAO`>9p3*MNCc4MȆ1)J`E{,[Vj^%Xo%w q\tQ f|vhԋoB֔tAgT5a>)Vreb}GJ\Č~ j[pm9olJG0ѝs}sAIn3SnmvZ_/ ;!c e㺇c={"Kkv>1ݭ-gOPK!zlword/document.xml}nȲulԮnBU,[ER-n&̓5.py~"Iʒ,jj53{FD_S`ctKBibK\vj;|ReöLoj+#S|&,8qb2)͔]SW\۳{bI-9]5) V4C^"l|ښhٮ)ޮGZwd_ж#*ڙ^) 7'_jc <~׶ODC?cӈ8bIO~T]yxlIsk/FY]mQpF^2>n͛:,-}#g>G֎-"WLr[4U @U 4 g ,",W>9'q%ǾEͼZ0`\tgt@C=`+'jP T^Oێu(=MS2[b]5%Y۳G->\@F$߲AMmwy_B ߆?v^ (/*MfV=p+ן-_Od<{70hȃLG83%;@Ozȋׯga׶;eY.=*D9pF3]䀻 7;>qX90lrP2+6 : =II*T>-\XbH\< Х"MAlԱ.%Aw֡9:Kk8v8Ezi>$8.>>,AUrXkG* '# ]Qm+tۋ/chWlɫ7/}!w$1Ru~|G0g{.psaU2R N{r>>$OO( W@P^&?qy/R4:.]}A-{2W`KJ,Iz F)H<H] Z dc }jЎGt'u[% |74&5 w4q:-d @j 3ϧ#|5H~%^"o1bX-6!0Ief?$ n0.Ч\eѿaѥ7;]suºma2gWP@H>}ubzh$f]z:PNA>q٧ ޟv8*\gr9_ m勋nYׂKfɲu:0*&oR|T15*Fp-R1H(ܵLmP~qbCw,hO9闻;jF#u^nшV?p)ӂq+lgvFK#T',Kw@|u|\db1Q}#Ra>`E"@V'iVZ'go/Mz!ILP"vs2 %M6RZt?ո \]ֶqKrCdf-(Qdg'M 1~vhgUX:,+{'+ZX??1_yc|n!~/VdryE)'mձq~~EPEmhr/:3ؖbVR@Kn BGZ.]!1)-RC#ı!:62kgq3ooѬRV?5.BJ+C*EQ}a͖~(#˧Ru@0ܲGʌjk4\DVgªd@ /Zfp R@!:)Hc[rD4z6O Y0L?P)[AΑ `L&Ah `g |,kH(,2㘹|0ϚyHwϷYg,XñwFCW. ExrD3OJ>qQhM5,e|lbSݛ$9 E\ID  R.c#_.GV2GG. 'Mbq,i}Ĩ7_!\e)'=NH~}xCOEPCH6Kx(Cql!kҔqOҙ婺ww.>R|y ˲KȮi4x^l5,{MLǏYy6Oۮ! PM E.R>/ǔR%x[ :1+9Ϡd`/a~2nLQ]wJqpyJ$5.R TcG9cG S)qa/$!Rk=(H(K(J.]a)`:v[Q|ɄfNev'SaIڴ3sůc ={ApZA"PRx2c"rZ0<uA涏Atv@- N_!"*Fk_zp"$Wowh;)`ޔFPrt\¿㋊>N~-V#c\=~ݺUr?cZ )e6wQS-T3==|8tLC:ڭs![Dk~~tqmxnfx2)W'sd8npSfӶeۺnJf'iTv70:I3ځnJCj]%3 Neԙݖ˙^}/rSrcݍ|!l_6o&C#3mxNjVۗy:ɵ|.왭zA̦V>Oo:w77xhٽp}]͚yLNꥧUJ'GI&& nR'F>>N `1kR}0ڮo͡o.no?TuiW']^ [2o.&#eWΚ7Rm\-p;'f^>QN-g|p_OӃn[^mc[>ir'ۣCxrtdvz(~>Ss?6\ͺOJ]6ܦޞ^&)kM=ژώY,ky}R??VZi[N'׹K禞K0y\kw73E9yS/KVB:̡*N杠iSiާoٳY>xu]Fju;(k/PU[U:z[_[JNBldmldqLHL]H o0^*uזDϽrqwOυ:C u&*fE\fCSmo&9,4NnyZ:> USWZ+w={ӓa8l7JLަv~v=J`Lھ9κzz+hӇZ9j{۵RP:i}tj!][TN59\qvīM-\r}gOQRxsJ*,]Bn{2T ɑ*twKyTjT*V.?׬dc/rvQ,nKଥRpIuP(y 7Y--˒0j&qTCL{y)\Q/7ׅ9 w\1Z?}: ^n.5H'@̵8 < 痪t [̓,rLhPTݧAY#A)άɝ' ^b7Χ):*v\#fP5)MT%HPHU? (^RJRREI|NKW-#.noE oXWd0Kq*?Wx/q1_Y0.VA jdd xr~\qkvϏ(B\cufWWW^9 s ym6b\ȧ7<Qp\#ÂǓ=aYŕi16= b';M~|;\~`Q~U?u5ƒ|%YIX\\aŏpaq1y(^1$c?!6ߩ1W0is3ˍ~|zًl\5\;?/WL Ia p|XT, ^@e}_=֬-[wPm8(!Qw/ty% Ƌ\{\>RVPKb#ӊV$Pi<[v5yȻpl16PH6Q%ExP?=hgRDf.ƶM>LM龡5ldJ[щ:hSNu XNdo Q='P]ǵfbK#C},ڥcC2w_6h #cA_WQ2bA&# wz@T4WGe<=t1!\…)N9m;-$ǤZh`Ʈ6V_bH$%~?R/xenv,cLE3L|5fd|zcnƸh=š1˒XCy^Y!γq1Xld3@"YcP9Ff LLH#vq/}/P]؇+͋ջGƝ"w>M͗iS(ͣȤX5)[z %=-Jo2\]A)vrgs3y X3pJ28s:v|$ [F B4g;;YXݪɆmJOkwJ1=|8zu6B1kfMCanV'$lR/JS4} )xcZ뽖19 ZllCun*J6Nmwj=)q^'&$+;QK5jyG4d,cAhiq7|#b5AJr5}U[-|Ϻ#u[.Ed\Ǭ~Ƥ";ABUl,`?ښgm|I-C!cE]D6ҩbE\t@&#]c}(5A78؜0io. 1LtHF='L`,xę@GcObI|'Mj0Ȑf=6Ӝhj&Ya]ضmd[,>fVҙlV\OWtIK1 i÷-e^r8ҖkK[RR/>QӭNvꆃi5]N0Ð= [MX1eWmzl1OdӁ7BbrňΟ߰/]㻧ui;-"o]6b3b3cyf 6)þۖl4B]+fhOe):ucWamu >$ӅL)QJ Y$z=8gHL&RtA0x:4Eִmx=`ti>v#֗])\ :uIsIb&O0K摠0DY|4]5R fɦh?BTPLJ45Rs1l_r1#oRi $3!H~L&$) \P^[!+l,twn+<?_k+T =Vs:7@Z:'J R4Zsbj|\ L T'8:M:?In=gEi/ 2zӳ_ w+?n+3,6K xo [ׄ e'E~\$R1rїu#8G"+iw"' nB˲uz?I q;)=| pLd OZ#@05(̊_1t+4(Y%B lВX6_#5#@LhY>GԢ;_fDLz::ea 1= jmBl;=ϗ uvZ?+0 ib#1 Unc=D<-oՊHD{~}y_]wQ^FFmZ T:_x2(*dŽx{9sȉ"ry -?{"ܫm&tbyX!W(955YƊ>1OK?8%AKzϣƽI䫡dc2ڨtn"URPؑ&BYQceb]Fڨe_ .wdXv{G@0k#铒yŶ(]> ( A^!o?ҚRL>6OBMf"-CG8W؊Y;e}#-ZlzO4M\>sQz/-#}}o f(Ko$8{Ozk'}a~!^gͺA=!/^]%y.? oLICBzVuZJ6bv_e芧Y@o % R!Z=~ΐ(,@VJP= wP[~ *E[HFGM503I:Tk6Z]TK(& [U|y)xIOeEG&LUdP.ƾPc HGyŐo+!PDd3k(Օ!(۸QF?sPMK1?|ISnwE-Oo6g%OFp 4) ߵug\)w\&A4ヱ|>mldYp?{W_G[BHl3b!pC Іv<Ƚ'Y%izmgLіʪZ#̻W 24 W:߿&ɰ NEghV(rƷZaԊ }0YHiq1E.'5n}Zf6,"~礎ϥxr?۠k)U%wJA՞&Muu~"; H\gnxCk>\=܅=DrXOpxH,^ w⨁Pnb>~f.-e 51o3hk=q"M^o㇘Jh]fnҪOd:4֝vvQR,(W)w1҄IYt ,z^s8qKFI,.nVLU 6îK|UivSvwKhtTFD7ULUzIh/{mu! @ N[6FEZ踌t6~wZnMq֐<9Zr _ը9C:8©(C}yKMc~, "X9*', Á30A|X~j<,;RߓJ7yiAjR<=+dB!v^8NR]Yozs *ڡmE9MsԉM3Qexo;X!^ >u%⃂Qf$YՐ L3*%^NMɶPtؚ%фktLp` t  U0 TBeb},:hؙ[t0j$gL+A:J+jGHkwPD&'*ahyxv!vYI|r:kI`){`qvIzpF,QfX+*}!=\0bPqo9};Cҩ]NRMk0O,9U6;7Zď RQd5]ǘR1SY7):޻ p4^1 rTPصMpOÕ;hc^z\ag l;p=";;X{ͩct6sllj44`h3H˺N,cUUo'Ή=ñrVk7&U߯TǥDZ v9aP&LDD\zc iΌ^h'iJAʜx_/+.9sQIv1M얮Ů55.-r\ѹ*(Syد\6Ulz~H:9 9VBN>-W^ f &LQ%Wf{W׎$viÐt͇risĪW֤ GQUٮS0p}\X`͵ȓd[N6u. Cmo&"+˾a C}%VP_iO*$*:KԧZP'MSZLPzb]0ۑ'ýN -&槑5L :vtRaW 5d4Z)E#wF"! oɼ=lrrnK9-D՚jA}R9vĵ$[*G{j v':R_-E<9aLR reHpx0±vmlcnOEݤ{DR͝zmM9n72 le;, v7ȣZmV/?m \/rY0Jg~"u ;c e-v4&wDufp @ JlZru&.좌1y.Ok+H}M .,z"rH]7N`8P "ХA#~O &b͇!֤UnDbyVaXmO Cآb0WmPxR'0`Ra$.aW)=VQ.4͛X׸ƢtT_*[JL٪uwU_mpxǓKoJHf\0,BE!\WSw{~Y eG`XgS{$=3g;qdGY=ruem{L} J7c1=zu{XQ,0o=zM 7q}2! 2K~Ƽv¶pSoR5xV&o>N(e[ H  _dj9yU$c`,'(N|3/QY7HSscЗgsʯ_i!WO4S2pAB /5tƺRk,tVs0@`ѿk@Z]K5z Gd -` t;[/F_9n)F 4xHB膖$GLG;B'8s#+%m;`V LYs -I(Ie$I~Z0Li4\KK&SlQcwi+x)PBCNhX0Bi hVz/o.TKp_NFE"4{ižk>~ޝL%"elz8sZc+AZ|)[4Sڟ#, xB.uȾJOba6U[odD,sjB¤1ΥSSa ĺ P&Wpޝ;5`0%!- enn0jT ˾np.p/5uŵ={߃&FW4V $u6@5719K]c"赞 ɲ6$B\GQx#?H Dϭ* _w\h 6Y6<.TKz f6t>prO o.m2TyI TsМHU?!Wa~PyI!joxذpOeJïk|f\P?T:GK x~rx , <>3V}MNLSz?ҾMO937-j@:2<u_C䝸wl^|Wwj5Orw=o7Zŕ;_m]VO2sS6 'Q"W4G[&90Ʒ\M5W u;kO4X]F:[_J`"NS(.ĂK$D <YV@ڹ:$qKJrSYZ0iY{fUC>fp1[X'gõu_VѨctJ4h}ND940R_/A4V䘜[1{).Ϛ-7??`όYM)$\Sw?^ Ld呥~v1OTPgvQ1TH2_5&a`j9 \J̵!Okhf %u4=(%Fۊ41T׏"I&H#qFy e{ (uvkW{kC<=<5¡P.;莣]V2|#psN9ål и6\ lՆ;=Ѐ>~k uS L`r++)XئՆ8L /v1 I993ave"!p 2G`X~& v(BW' 2O=i=rM)DSpOWgIdJe~@pcgЧm@ʐ%U <?~~ $Pb)v>pcy>!Ỵ@hrvmUU?Z^^ j{Eb St~ACٚsF^Ձ8f&_C\%J.zRY`Fi'EasaNL;pό)NCD+VP;mAibǬJ˄~hzQٍF|9ḥjr$MW7S~&ZaWR%*4 )l-) SQuLlWF0MV:#%YՅ@&`68mX>Tjg2NLZߛ#Oشii6YChUʕ3'|UX :$L-5ep$EdV@MxbiB*k3dVent8ctb]odHQz~OvB+JK[< JĆz8I9w)of_f3hpN6ݒS'7D)h4ccUׇx1ҏ+LVԕÊ FEf1VC2.T2ͰfOx:5%ByBZak^ܗFN]1т-m3/TTÀP ފ ߢcgFhnQ¨1AbztV9\4fLNU"`DXa3\d"΢8Ss?Iܩ[RIQP*Co[{,̌遝ҔdΆT VhElqŒGMJMc?4/v{ѭ_=WUJ}#<7aJb=yX.^*E}1;EM?t;I{O]Ml$ž?R:J@WIN$~mL#i4[jtl; αO#?FpXĸ;R3홈 7a;5U}qckrtgT1lU3Դ1tU9/ܲ]r$1ulWZ]m;r2+-'QnTFjx; kVTvהq6TTg4"u#1Ez#S.S ҔjrI?kme7f6$]=VRZkmͪ8dWReQnQTޕɚ Pp8\EU9#(ae'5/MШ䲹BWb{7o͚=mHuJoXґn֦?V }*`LVd1AQ]#f"=nEcBC u$uZAm:I1 8:ݨUtu25WIb@`RYLJ&h E UK~I %Fάa9 e0$+sa6)1_VkbR0ܥ8*zkI^zYXP 6%J* ~P,|-״>nrޥުiB~m e*ّ&a=4Xmoɛl{G8} ª Ӄ[0,bA[o!ᠹcЅ/?/ ܮXWFF1瞒TT |^^`3텓Nu bY.cU6Eh_D\6sÄF=>[g'Kпa*b#ywبml*yZ޴W ع­+-j -_]-C2Jtp^) 2k"%(1[{y/]bL՛1U33;Pɴ˟JV+֫]0e+4G6ܺxV,Orz,^oH xCٳTpU1MCe sK%s =.eVR2>ŸrpRj 2$M_]nJh'jJۀ|Kr&'>`=($1Xl ?S/0/)K$T$KmվUӊl8~$<+`fGC2lFˍmT+a?j WFs~mJz`CO8~L6_EA22v`Gc gC͢]K։9>s}Q)_[ˎմ~qhP2d#>7dSRo(e)oW]+-׊?O谝.y88izZ+WK٠])y0h* 9a(ˆ(e=|?>"ˣe(dW5,s2~,[H mߓ)yWb[izocel:U"^kHEMvzvR(UMv|p;+Ėcsx>.kbXf(3aۃ0͍}ZW&4_&!–u8Gfl\_ªي3p@aR@*u8 yンWn7}cX.~ lss#拘Y .Z"e#a5Hi3 ̭͋ 'q,N;;v=n?Xl0׿D嘶Xtw~o|۾@fo㶸˥0]cۓ~kSo7O,k[𭘏oMI gϭ=1ܒ?|`"{_ 2Zbx.I T}?"]W1.ya:!k q .Šcujsō>ЍGŇRiTv5sAy.rcVd&E(G喃QU;(ӀDc:4a fs;[ Aȭk[v`{SXz>9*UH e0Ԛ.#ξ8 ``frBkQᬠiv,Q|)'>cFʵ*E%8<7䞅wo9qnTۀ\rĵ5w55{G|DD O]@;\Sޭk; L7%xl[%Ƞʧ_K D$o!&j'm}u99t"Jn&/>>q .Son^{坡h]gE+`}v0rRӁ8Vbq"@Zm4&rZ5 +/EǢ:> K+|8ӝ>p^ȵOBAQY)_QyF6im8hz=޷ r}+װJsb{>Vx8a[97$y֧f^刼(@ ǧ&a7Ϳ9sA$ukL]rtuECQĹ;FDc؃H9}͍) E.4# &y9YvÌcy}l5IMWRirP8 q/씎0x3; ܄ʵ;wPDa_Nǵy}rILJjS/R4( Uwiq4yl]iQ`,Y{p o;a.Ő&9$Wa&Cwn0p8@BQMsp:2,uRABuSՎ|:<<ޭU۵qJ`/ʼ|G]ީT)+u FCy<*o73oek;]a0Oo3v>&u7C߸b%ά- p"N J;N DTrn~eU[xӸC3^J9tw\ˊ/cӖx_<}!_cSpCZ}jkdࢳڈ{nߕ6Qo#3usEO(Wq]Ǻs9cPn;W>-xP&Y,iՃ[bn_^ӋQ๱H07T'xܼr:?yxCڜ2"Z$QI:e|U&Wf6ZaJCXm (`f^?$ynfL4{]}Ĺȴx(H'*)Dp~;>Ruʜ`//o/]A#E)Zi /0u9*x$"L]G!4E6a#+&Vk9R-p-vCt\&K0Hֆ#dY<s) #0yyGd{%?b tBO#5픽D6, +Hq"ad`Hxc3bصwkpY2k0=L]{a1\t@̉bU:~ QRo=dm qخr)I=/XZ=9ss*H=f g"q~[/rwL78@P"$) aErc0q ]4Z)Σ4O3ydOuWNض/?,hȦBоP8SQrM(DBLCҋ0Έhɟޡa) dQd'e:a RBdʹN1[ IZRT%3qu8]%j18W%5Ɨ8CxgHZ^* iMCPF<`!KE[AI{Mv^Js탅QG Z-uGe_)b2%1;G`>wmcf{4~)+ HNH㫋a#g0<. W0yJ==,HXZ@.52F+]l>46w삖Lg]u\qnqTRHO5^)k (:kS1 .ȫYN͔YT5N5̘% +#!&W{+s-W^y+ImpUx ԷFS5p V 2bVUƚn<UjIUlVaBۙkX<VzYU.W 2Y)± 2a(@&7v.}Ж**0rsK/jɊWnWXn?dwupry9(*.\#'$y-b)=Kz+8rkT9Q6Z}Zk?)s<!0`n6p#7QN3 +3ɡoS6ܐ q`E wLZC,X8#;tY#wI'+TQ]_Y}76vCmэGx`A/hO7\ks6nI$RT8˲Eng$ 뗿GlDmŮ;F _8#vH X0K'JM SLXqoKNd, A y&KN<춁X[=!bD%|'tW'ʶ\E/dĶw;D-ADmr"HܝO5P2D l=,oo,׳/@kb_Q}O&=JǍ 씝%jFeCͭTklѯf}}}NCt 1PRR6ϳe'fZǿ&_69 S&q'ȗ`&-FW,jyވ< %eXkaC9~m< Q쐽Q4l٢];_8j%)L L~+JV , mPJyE<64}BwV"O<8 &q=m5VasRKz#Syio\v9ZΐbXXf@B$ZgX!rك1)kr9*ΐru[ɻdh2D[Ae.TۑGѾ"Rjy;`YZw;K$ yܵB"bIDՀ?qa_"ϑ`N/Y2@R?IYWK")PU4䴑˜AHV_)!x iQ/ b$Z"3ދ`rl7"HR1: `d ,1__Ď[ FnFnM$k B.?{knƯt70^ $ILSoђ7iu8!ڐTo a@# jR3Y;`6DkhC$Z|w[{ R,I`BP#~> LqGh:kM|:/Tmz|R '\^ҋj)|?~:ÛԆftKi"T4m4h^*od<]u'Ca@":"2&E֛T@ F@u.$# ,[<POtYzS 8aD,[=XR4{tߋ$K^{ҹ20! wlDe| _6KBWFT'*;>S 8Rrc#e.ۿ$9S,ߏ?He;$<u$ԼZ4F ::糘Sl #kOj2>7\ee/QQ"CC{_Z&Ws3& 2U2:umP4T=2.u9cl^Q/qZ-Gyr%K$]A5*]w;9jRc̘ʓ_:x{z)7.ͧvi41Zi(6grfoxhhM/j#dw!|r1MB ")8Đwm,S]@RiGO~ieDiWi#Fd%jFej(1&~n |E)RTN I: !WP w.G *k-)SŅ؄>T"Ql]'.Ej $GJtGnT6:Q7+xS")VqXIv՛#M4PK!nrLword/footer3.xmln0Hﵰc=@-E=M[` at7@wΟ*f,h) W}/G3XGTF()qLࣕkMT8c--$v,95`!wc Csp &aoeTDUĢNir08;ŒR<]7\ppa AQAШԄ{A0g#@Kɔk3bÄ\mJNRuD%Ed, }+L1}:4=v71 /9tA"gN$\JsZ\? 9/JYL^,wj^ @xU`FxEu4 RO蠎%( q6}FݧI)ɟ6մ[+"p αg6;}(PK!word/endnotes.xmlTn0 }0H3am,B-Qx9<R<<d/W`r.IP(ɯ[Mk02'ۺͤ) 0>kI(V2,h e-X/@H1nܓNJJp.^UM4d#D B+F3y-FK9GECU$bx,$==:b+33( ]u{꿈)$fH1qxsF&+3|4ʼnw؉U_C{0oV7`n;?0-_kdԦIw#,6 N/-w<#hRENi/.)'nW1>MS>-x1A\3B7k:CB[w }&(tA+|PK!4lFword/footnotes.xmlĔn UU׊F[VǨAN=1 ?Ny&'霑D2~5##sܯmVAg9B^TRs?J8PM,WKYe=&͖{) 4ysp{o jvf9if.$_1M\;DA4ZgN֨=* -VQ֦7|`x8'Q ASv̾"b sF%+3b5Ǜ-࠱G{4# ۾}$"{pFEmzt'n⬗;RENfi/^GsN[-~ eɛ:Lglu/oӌ Zq~X S8-;i@ 4}˿DF4BѤ_PK!/ 5word/header2.xmlYWH~6⾰2af7$ yG"~OLN,Η'2gJR7 _7ٰB#2ymn7KH3-45? Jͤa:(cyβx@q-F}3l5,Iĭ8 +MaZ|_Ѣ a/;J-KECZ Zf7&'L̓pPM!$2z<%/ɾy`ޑH,t?ߢO?:DueL1_{;b!J0/p?!ìU?#Ra=wԼ'DyN5Ia,GK]j6c0q(t4*)<D(_LItsHl-w3Xbuv-XZhksli4YУCy`iI ]I#P @ߤ ɔQhx UEv q~f%Y( sZM, G2?lU6\H ߅ĵbngm FjnJ5@oy&ktO p70B!"^5( $CBm`P(g L; ^[v-gԚKϓkysJVVe.TT8㍶ZfV&V'>6q]&t1['Wpl{޳<z#]/Nwrz<_a)ud~ɫKzĀ4}t7F{G9|*S6I諠]YQ=Gg:TܹRT*n]F}RIDp(F ZJO^/r$LYNDxYWiKXI;6r{gʌPkb0 B1^hD6#:?W#~`m@en` +tsM%̈$5 C3 ܶ] bq|@TC^.$AOEʠsQ7@93/Jss<%=DQCEI[vw<~+HTQ6"v}X T#nd/E;~?Eh_6" c9݊p\DI_St-ft##Pyׅ)-k"G~r痨{Opzܛɪ1 hژѨ{fܗG9i W}7T!le^-0wb#O<ǫW8%r;[smrPLȊ}0 n`lɓާ75[Vh^"Z"ېmScDm5p Bx&[@tf׾:hݺ*?a~u3Ʒ*?8'PK!e_ word/header1.xmln0E`hB!Y$cW1l@ i&`3x<[|JTX*Eq) W}?LQ`QXv̢jV'EflRk9`li$Ԁ܅$<Lo8jߴʬDUĢ=Nir08`I̶O5<;HQiT45!I'hf◼] h)rmFl@ق냍sibK2QIu|77XOVԾK1.HM]I;  =gDy9.KRr4Evٓ}+f(4y(0d-: A%{MQtO+R?mċi7oH#3g3>M4PK !ȅ|word/media/image1.pngPNG  IHDR"sRGBgAMA a pHYs&?IDATx^%ǚ j5fvvomݗ%(1+(1JLbfS;>y%U]Ex۱@"H$va#xhSx'qqCއŽ>?0p:<<"r#OǞ8R'ҿ٠btOo=nį'?(ǘO*ۃ UPϰ8ݿ%wܷqlxlxE:C?Fh , &Yqmf#U)t_ffu̩̫,<P\*sĬʌ94.5:{ag^x=4 wwwH$D"4 DL2«R1Qxdu>CKp?'3q-p@Sp;쒀828$4#Bt"߸J;L$G+lA6 U%MGFB Y:ut&W ӑt+PK(ѽzZeЩBw̡cxVahD'w G=(aKYor= )|uއ"ݸLD"H$MB"%bHGT |EcB.,S>8F0m؇]̟#1dρux)H{/GxbjW%$P MkILUHfZR Hm5#]LJ&n&K%[c92 y:VSе"(^K^-jp%$ U>›x8p"͂|5,'Y!W!>8P4 s;%+҇Ɩ({'>>h Cn 1Dc! $ᇥBB}0GEmOb\ njOSzDhJǮO?Ak*gxϼ ^xE)%D""7) m,ϒb!HtG%wѭq3[/oU|k[oWޖ[oB|[ko҅辈QS*aMB\|\S[;HlyodZt g~wGְX9KΰU~Dw{{=2 .hrCډ7t=q1D#t=I?7{:j~a'OЗ?aZ]0F\1L a=~ϝD;B4S->hO>z@PַZHX9["H$-r s9n뱎莧IL n5›!a}]!m$Sؖzŷ&W p^%-IoCMYt\FC(ꙮQ{;IAsߔ!-$5g; '?tMx&IPx5ؾ8 PZZZF(,*éW^,k ssFk/jPd-D;ItĀ5a+tEѩ"(ǡp/=/AQe=wDݘ8ۅ'ډVht[ԆcDwe ju#OH-H$`7&]r][Htk\Mx_S|)5›!m)*#͘VE7QEv~bMGet-⇯C!TScuuB[0jGLƐVX]{NB;&&&1>60>% ͡dۇ9eo:7'= Qu4j.B-p$VIt=r gc'_/L5=3GΣU\fOA}>%vй|JW0Π ߿ihgH$Dr&-Q# p#\S|6ߖVoׄ^|_s lKrbd.4}ϣ}p =(Fa]]v0*I4Wu4oa,-}q@K*W@OΫI[}{Na>vQsq[U?(mcK:uvQdGPz8*Gչc>wugQ46:w*b1T?n{fHt/.-KHJ}1Lz?$ډVms=9=NqN߽=wlF6% @P:gŋϠHt?.ED"H$[GV!$ HtO F')=#HpYOx_S|3$ 7C"Rx[oHx3[U[,CgZר<9p˄Gtv¶G`c{5|oW{`,gAxZ1 J3*D}΁G$vcpu+o]Gm56{~ss3qN_bPĪn~."ق^C@c@cG#! ߠ(&T*WT>0rJ+1;;:|{OO J J)Lo2ş@={n(!qҏ 7.[nD"H$@t%m))5xF[cgH`_MUxk[pUxk{ -*-%.aѝO8.$Htf+vl%a~5!p N;,{Gza ,!2蜁K.vAt#?ΞpxQrDpZB>H4_!?v/6ދ$|'oooQ@eD蒧~sOlW_Byu7 wǮ'F@'Mxr "t(=N7fH}ǢRtK$D" EwnN#j[z n=[|Wߚ^O|kF{=Y,n{tyB݀p" #iD !ŇP@ ^z5/ݏgė$˫004[O|ܫ8r :Pڎ/Pҽ(EeR?qm@3CH5>pD"H~$~&-ҥ WHtk'W|녷^|EIx3W߫7&M"{&*t`NxĖ3v"s!N㳯vV_|a&‰-Aip&aM=<_BFQ<"s wߞyRo?(QVrCF@JVX$Uuӏ[$|_~ᛞEK$)o<7BS(z)ʈw@[OcGbv*Ϸ{S8k櫝ض v|x俔O.NGD=+'>|A)%D"H̢1zH0_ #ѭ'Q koo7dft[/-&5VJtaϱȪ"![Eqe&SLBiko+>'JOb8Vp$?n9D.#r)\|HGW)kd4/]|w'nGhSIpOVH[D\@AԚ~blGʞM$I[D*u}: x%_^C9QRO\ի(BqK'?{pM(br)l?8o"7m={TnD"H$?wc(h^#gfH\_R|Mz=&+v?mfu!()Ob%Id9ΕO_r&+R:9v"$!UN,Gs#H&RZauϪGhF2jԉ̆Q8}-Gc$~D-a rmF(&Jw~1j|$h |(V/5QG5DQIv}L}"ȥt84J7H)rA %ɷH$D"1D |5#skm7sQP7v e(mGq P8JH,AaðH˔P)T₽ mS61RRW8L(P\ƐVfM( hF"CQlz7{4ۣD=m~[ 26ƈfDW]Q8qL_.~S[>6Tw~XL%nq$D"2wc(5H4_ #ѭqoٖo!ګ,:m>3YmKBx!!aqwpTC#O(AgߐXP3~#,6a0tnЅ 7/Gdp('g;3.pvE]<ĸkxlYH8&d]~/#Y[DPޫn螖["H$.݌Cjn[߫7C"Uϙ$ ;PEbfsu놁L(44-fZ'uLm*$4Ct{zf'GcIj>[nD"H$Ptk nKH8_ #n&FVofZ<$O!nI5HR:a MlCV<H/"XB~DzB^P$X: AIϊt=H e["H$.ba$5ķf4m)&mhz-g! tgN#ѝJ:~B1֍#a$g2\y$;Q` V(fHBMn(c!j5`)o)%D"> DCjn K}3hˉv!Yd o!Yt7E$RjIt =snG\lV,۪&nfH4M"#m {EnD"H$?#ѭa(-!FY%طd&aߊ6n/aѝR?I$ KdD,Hpg.^D^xw~ ʽ6oWތfDznDb$o)%D"> E[zo #n$#-Y,ڠNSwIlSq%\Gt%m)jV-߆!{EnD"H$_f a$5,zt"%N!ѝT?M"sZ42Htg.^DeV kʏ(UmfVfHPa( P/ o}k1bѭ>Cw7 'H$λѭPtkx^#ѭctrDwZRIt'ד讛Fb-dB|OoEfof(ԡĒo&:k Ѽ7ي. Kk*x~B<_-X?-irSWg&eY 3_(4 ΂Ys'G8ߒ9$ !IV&JYh0mkB^34ܦq3YL b Z 'OZ8D%z UncAF/t_)$M#aKoYB0N(~|i܈uģG_D"H)3cpQyqz-WcC\J#HtITM >pKs\"aVA>lBU3}ׄjR^DU"xvNr^ճkNG`HXDijꭀtH~׊K$Hf6HıT K5[OU>BQҬYveJ*+jJ][#*VIzSWD}'OԓTr{MiT SqPz5PջyṬgU:zr7j=}­<%8J]8zÏ㞽mIF95ӳƟzaQ;ef)k} v®cEl?|g8tmǑI~?#Qa/ ?z[]I[\3J4a-[1g4%DgđK C3pLDZ fExfTḵvv_Rinq vsx~26!='I#"#^"vǘ%9~ {NXaI{O𽋂}yϜ+ . :sV_5(~#gmyV3SY8DZpE8\09n?~d#v zFfq?lI^atFuU2L2陂 \k2V7Jzհ΋z?QkѝU$D@FvRi~vD#(9pS`VUl ѝ$UἽ2(}_ _7(ujZR4RӍIc?Z81gfU%z!ԠI9h=d#FatY5X1œewEq&eIuȩBzU O q XTT&w=:? **a,8NcReb^e'Fg1B M>L/ W>}Kͨ|V_]o:S0B+H$?hɳ=< i쇏J:k' h;ˬ Q2sˣ0L&1@z >L"|BRaV"M%,;98f` L{C|_g0h'33@5w'07Kp}hEs:5rC+k#?/΃˔sJiş;lzQk{t_rO],G3EM,F H$䮇~19u4ʰcy7E jԨ=AQIzW:9o2pXor%1WůfDsvC4ޭV}b맸tpmyp\YGM(Am;:1fNЯCqW;/hŋAZ9 kK]d1C bQ1$h"$bTJ`FKl,тm5e9C 2`pLalb,',͊2/bԯi$5?N":uڨsm|P};cuhf? Ni08 **L!aEpw EÉcT ԱfL^->J[au"v#Jc"ŵ .Z/I n<@ЃG?AzPAWqtir#.V4 7fKwF=X=^3imzN@ϧXq}Lxh\g|,-s||_y2 s= ucUusH$x\?JħIڇ:G7Ac~0㱲G/8EwDN=]D\@x:t=Y6Z-`FswSנ0iA sM#ѯ缱ysQi^b؍$m㹁X1Ip8ǡxx[oc|%R3x>fßoNodXCV' i IM4 M0+hrO*p6]WBشs*I` LkiGP?!tOsi EX3>;C  #S<&)ɿR~nVJMdҚbO7֖xmVglYV E8M*Jo@EU AIU#4Mq-nę Wk!w)YLpF g5hyF@X D8%OB~DxNSħՍrO"FĦ{"GoUw==44ó+ZϬy$[<|JāUT)g/G (CWLrׅ]CpGni--V?c+眕}\musDٸ߰;;5MBp1Shh3$(lUT^ffEw5#,UzM1$nt_[噯'g1m9x-[[?@$o+©;(4m >d !DwSg?:(CC[/&56GgA Q/T_᯽>3|f=Dq-ҡ-vM78_+|+I:šXIX49&5kΏ^&O8|4xW5o"}M[ K :U?\'}o;,Z-\@oQGT>IeVi忀>z`̃ п/^{m?!Vm#@Pdjx`ã/GoRN$·רi40;}h2!y`x ?ӯC?&!⁀iK\uƋ/&չߊX$D%&/`lEG'xPǫGwHL%[ֈ^b<Â?8A ͯYtA.ZSex LcY%?>p􅋻&An!tH@:s^~uo|FLyrh~XǥdR]zurFecշ' Px䮺_n3.krFb-W=61M,:x6D›E5oNk&!=tm"&nt3ctD)3HL9Mx+™ kU~q<Ĉx(8"\/5T n /377<^ * W_Kq1bB7`71$ItW*sKXn!4Ih|n!| zFTLh^+0OWߑ@dQ9H] !#d [IHֵv,z;ǐ[\ǟ| Bts,4iq{?B+i!e!xwNzSX_m+nz->w 1W2m͔GzX凚~8;r4:OQ|]Aٿ[NزG [W^.b!}`W\E\OXx<|[Zh_B\jHk!: Iģ|#G /_3XK$ c, 4w\] F0Kc 7s+[X&an{8cA" V.b+-$9W5b|`1G01=e屛e4, (*hQ ?(IeKHa9=|Qң~ˬ=*A\||ZZ:-FI<}?]_^QU s8xG$R]䈹J%7ތg޲ư-[l?16pk,$|n *,q(*&f }eiD*+7QC+7Ip?gO}q3hǷu4 cz4( Xf+[XI=Yt?:y= M N?OU _,-aqJXħd?S.7(L c# ۚNc?܇͟} X9q=(|9Z#0<O<,h_|s ; T}p# ~7vތ>yTL%2Dq~u;%ۭ"}^ʺ oo.v?{:|f:v )pE>+ K10FPͿ7GB\B,ye$b/ Xo|g^$ ;WoGYյ?v|MlE7-| >ڃJlc?Oe;}ʿ]VO>:FbPr|}J}ʦ(qCp FhvtiM>|qV}S;w^ SR%q!?:xaW- Ҽ(@ liO~6@/,ִ4>yJğ]\'~0>revG)/U <M\ǧ02E"K- ,6p,ņ3y(8<5DT&HTL%w^# xHtQR'7/a}幃-.YK*3N9 "E eG'rHÏt+prBXf1[ObU@2F˂ZE% +-uEoI: y~wCqe;=6m?87}_ EuB\,ohQ30.V,(KLF7!I$j9Z,w(m- 4aM޹b`{%QOi"E7HO~OQ>H Ooݿ'|NŠn ށTϻKmeF?s>$ew?7Ƨ_.i?EiyqI<{Ȕg\o#.}$v+;LSϾ'os%#rJ׍?&h;ΖiZ&{_vFn%Z{PO[]%]&fhiAW6a["2Wu_u/ ߿'[ē0N7 #ѽH3mB=Kǽ3gN ns ȾC2vVav~QX9&+kqw/j׺-#@yEtE}+d&9E%$\iJ W/1W6t(efq$KIzxۏVlFCBR΢E(R8z+3HF'E'eӜo*ʏ_P8)HQ>eLVD7k.P4׎ yE l]~h Q;"E1w3jcc$hh=ysg?sS1i)q(:OH!VS%_g&~eBZ0:ϞGW_c}l5b!(zmOKVIozm[#vV$6e6{MtUoby%\GO?"*hu{?z+|#;-DۼGW֕]x烏Q^),ݼO|MycK_}'Qk3ᥗ7WOyRԉ%['E[>34h4D*Y_xdV‰|WxY{Mg:@ ^wV'}/ i[NKt/Yǎ)sKm1V]~ c?C(+{!;e\v;'gIx;%.msAsbfA9}^&gX7^$Lyۋ&`YFŧ <:QE(:`1I>[=}>h :!x ^tˋ'OSTb?4[˹NizlI!uƋx a֋n/ra*[RزBz KgI ;o -|;[f1ox^Ez$4Cw NY崘 $]2 _2 ,Yx6ު4ժm&&T1 l#m(M6nثE7ntO#a=1='4iA{ }boc+}?#_,rxXsZ4OAN(rǐ2%>$VzϿG!~ԑPf;Y’"&V]WSE-u+^,Y4%g2W7EnIܣu(<bP?;v<=Xb[I--x a_R$fͫ/Nq^D; MoW}K+?L%;ܧI$Ӫ[ࢵ=; o$E xDDBpKu!:1C7>?[マʺ6QjH-([I8Nq)iLpI\7Člxt#vqSk?IqHnD:_P[#V[+{4 v"Ö%6-b.^>|G'`<]XqPn+kq5p{iO(no!Rt,yl˗[=#ĞabF& cb3مBs<$r]ҭUoE9WAE!OP* q[ )_Te"n1i^=s) -Yf2(~a<%U*htr s!+=DXUB\G3 m!&\ڈG1Mm1Յ.Lb]_&a8NnK4qٸx+.,/ω=6q[jNP^4E "$tlle+9kGCݚ,M|=Mh{ oMHgC}5 nQ~6 oe_}&/NaQgap-~'f*iјF"wA$ ZPDj} Z[yoq54YC¢ZyOzߟͯů+qxOϾ{ٝE?=3;_>W! 6|56. Eٲuj:^rè3v}??# cS/>ꍷÞGE qEKb?wĶ];\vLPo"8*Qɿ #_l-uԿ\"zwpqsnŊzjEj#b5?\s+T X^V ŧ_|?Ң !]!a?urb7^w?L*5/ Xْ.-[1xIʗO=M,>jl[PX`e[NǗl.ECRF\?l()1&w\܅m^s: BpsE r|NwJĎ^ b iOHMWЂM8꘷Hr ?Lڨ낷 QB"L6mH kr{" cJFᭈnń+Rp36 oXx+5ml^# ~Dcʫ3_၏|pٿsx"F ;Oղ?IiY(oEY g.CI#FL&X`xC$ޤ<^mf:=- Vv.(iVh BV ~c?,+@l=m+Vr,Va";"Vx\₊z=ďYTW,^axI$$p8fZ,0,:ui<Äp (^qT^RaI"%zuF=xPY<ħ抭AT"\fAA(nuNu-׼יWկb}(bxwPUnUSQay}[^w*+g+;±Bݗ"8 g3'VCȭ;!L(\EO0 higؖVy{x3w'[XYPoNʥƶ;!<#q)_WÝ#?_kpɁ9D w ޷/ !ҥMįa8,L/ySE*LTE+yUa87>+P#Q5:/V\^.;1,qsY 5e|ScCI_Cy঴X$s2,DN,xp4)"?>o+eIe³n3 "QҢ؝sy8i5IJ>}Nq~9YKq\Z.q9Oxr}kٝ47Ӧd}ŒBOZN~5kWyK$ =K)-ak]"7>IX)hc0|i<9_6f_x䱕ecu3[YL`qF&6cK. U$ePn<\g.:5?z26c8b"7pxO :4Fٍg7yg?nä1?QE uWKX5{IQj\u#aPzUxyuExŴ "D* mB83\Óؼ}ߗ qjM=Zm@^S@fnzPIVi"Ҟ%r{BݼbD?Bݢ3N/X'~D<*|3kqj7=_ %9}bU4t԰FUhq)e1,Y7=] D"`acnG=ߢ_^Mt5=$ax캢FOvJxք'[Fk7 tEtie;[DŽV,'gV/ !΋YѾu*(EAC?ebEPAU'6< ᯁGcfMOp-z, xet-,1a [0ߺEUsW)u5(׏CCc>nt$DM<!]1a3A"Cַ_z?}Evx%)$S+{ D7Շahn⹪w|DY L-ي5ܐ`aam-n8ǘܩ{It"Сޕ-$ʯ֞Żpx! d&Mr: '$W1mO&_(S&=B{Dx= j פ15OӅeYZ-%,s*P0j$*TѽD7iM`vQ^P&nFcfcp׃Q\D"-ҤpS7"a(ͼ7tDem@zucR(ځ55 64eOKȔa-łyP% ץЀ,TDP5":Q5ȪFxf%2*F#IQY5Otn-Qs!ܙX&OE\"йđ{|S _DIzh\#)Z!)*|]TG"iLqKQ҈Fd5sV}P<ٕ(mAm2*x[ttv)1ݷ\heѱAػU1(͢)*}INXK~~ND5ȟF51 pa(쵰CMa:6an1}^ ]s&,ܩ]A[0u0 K$ '#yY/greA%ӿ"`s5Q3@ƈB5h |e?\WtG.BPg&~XFo5Q]ko%ҧtDjY#B?GR۞E 3zw0eUZkmAIoQIzs&ZU8w+yӰȣ螝UyaڄۃVԸ:7ƩkɬW[į7( WMCs!™_Wx}\?"o/,,ӳ7Z~FMcυ'%jETQm+)-QWtz0[I fmQ"re/[zlckq!'}p3 p>kGЙ;SNdRb [6QbnlD>|V1q"hVA%#)Gh$«fYETkSqVsB,4hL$䮑D$7- !Ϥ- ڹU!̯"[@žh_ QZ/ A_صBV(Y Dc4ADsR/RE.)4\_r7#WܔkEJiFV :QDlSu,u,14x\57>WɯoDuȢQ\& zWZ7OZ9=NK)'=aA:5ZzXMy#@͟.?p:Q zrTS(:D?ַJ4)l%mKSs?'Գ>N]~,kQFfUe3Z4t8D94OXԟ ʮ­KD)7~īMڂǖrzTY0=\ne֡u%ˤmςh]]Ę>4ˡM}AMKԕVߔԛ.PӶæDO\Bi>,gf'p9gsp;Gݒp)u:#Ag>I8MaJ(l-W/'ng?6NC?/B ЍAWy)o^?=}PjRz,>YgJ#dJ_+>em갖|6?]n.'SOQʠUc2QIy4/%>mLa˟ĈP1-/C+fD_1-618\>Y8ꑆ mb]tV,1$p;QX': aj?HVoZx~xN6Ƨ13cBQO[3bAJQ"B $HeH|DE8oqm-B/(_T $,gN3]+]@B)-,U :ѵ"KUxۋ o%OqʰB/#cPuw__CIU)餴tih{z gvc|Pr),Lޛ4ԆiO!vB04r0xUMy֣tla\(GՋVf쮆zhCz,9|JvU4h>:kp?-k+i8G_9a$ur_nsѯDpߠ|iry6Jjljur#hyu{OW-&2w^}SηV6a=)ub~D^|j.Q,rZ I$Q3Tr{Wq>!ۑ([+C)D=s,uAIGRan{(9 5^pGGoܧ4Lu/mX7j:8,?ZٸқfD$V"j tI5yceoV땶Is侮 ?>n*4,W}+ul)}Փ>ZS:ژVDJP1(),zz<D!8NG|9bJ%3_Ɩ=ius4&?9 n;f׉}x.gO/v:.8}\ICk{%*W2\N0T0j*Z|bXzTe h'̴L*[M svM2j8Oa<'IEJ[06^&l#a {(FAnOa(}ܞfD8R<880pRϊm)a+w-]p-H\_SE<)axVūG(DX_s *xtugB#_#X*.>-NֹhO*Rx( uG˯V΁ %m9l]=BqEK.'D\\VW;ʇDվg/KyJ%8Qצj2A I6()!಑lTJp}XSx5@˗o]_:>,FqR~D_s;SZ`ʣHTڀ#ڄ. s6`|u.RN%^E+a9o.;Z!9qPzJQ3Xc7--M7F?/!Gv@=.\ʝJQu"m֋_25?AyLz{\\>s3qSV~nn'??ţAZ}*}(}VMY5vi+exLq% !ɫp 0\oZRrr_~d N838m펓V:7gE+`p<pd{] 2~8&?es.RǺzV 9u:6gz ܆"nj\'R*~M$z&34Lrfw;0g54=\PՂ9 ;_#? p kv gn@< XGCNӜx#(Q>48pUqcB|WwUCe|'0>ʯhKkS<4-wp&խW@fw52FCG˃HQk%_j>E^]fe.VUKɣz}yM(.sިzbM̈E o/-}لsX6njyjDSݯS\KK+rmO˫ܜOowt54D1'8>!L P fCOW~rs_9 g8yo]>g%;^Jt#YVWӳ6eªyPAm>(,+3Ǐ(y^q!x^:nϏ_GC[&<ܖ)|IyCB{KlBN82ꆉtGHtRD"H$;9wl%]ȭlC~u;&0{$N|k~J8#tHKx"BD ,%c2(aT$S777xz tvqqEPh{:<M`I+Tw"m1Im72pxzD"H$;r6 kWd % S'g˸~jx!?Q)m@Y]u(NDn-NPZ_ # A]8;P:yO.Ǟ=ZI$D"H<؊_݁ށ1凣N)ȫh-vCYCNj'`fy0Οl䝄щi,.-g|821wãw{=4QFq_,WgWᣣx;†?#N-xe[Ze^>hoփӶ$'QڳEu-a`rm$R"H$DrgVԒԴ,9>8TX?|v7Bu}/nx8cNⵄy"{QG %ܥ$ ƐH$D"ܙ h˩jGK0 j:x;" İGX \Sތe8V /e_Cºn+a%t +{zks0la>l%$h6K$h;{/7H?ӛCT_O?mJ>;HNɁg@2OHt;[l/M7גNc$5ntEwc$$D"H$w&-}3(wD\4s'  4tǩ3Ev9en@nQiDLLluA ĞۓlrM}=AxXO6z<ix]/^ ăo3v(jⵤv{E7WD"H$ΤH+AAEr`(umjG,s0>K{I;9Y53H#7 S1.DVťE,.*ً}ae:V5T6 5z`OO8ok|Qæ8-.pri󂧣OnD"H$h'7gpCh욀_<skl=l̒o\7* ]#KqN6͘EwF'y,+`emm]U}x˵ybeԴV}3h"iR| ;}`>ϣu| FmZ"'l|zǭS_?}'+)Bxze=ht-H$Dr;#xFk$.y"&FXqY(eX`v)0OBtߝFs iŗo}S`坄83N8s!8q /yW<턋!b_: `oea1)wt=Oxxvo *T 㸌0ݬ%D"H$ R:3G,3{tY3^f߉7rǪ8n^E5O+@`xw &6cF}Ʀ0pYcQ4Aė"F)%~:{+y) q>y_ZAnF;n)\M^ %/ -FtQHt߷1)%|p fP?Y`zΌI$w+RtpH}m"Ej:ݨݝ&ÊBnzB|KZ%H}gm"E ݫzDP4aĕ Ht>Mt̛ݵH1/{[KZaךH9N#5HVv7*hO{䪢ۢVtBuzDQ:q$U#zóxf~H9==-HLL~Yp>ѽ 7?? (jyCZpr'=Dr'q}p聃y7اau:s|i.-"%8ech)΂{h 9pr"T3+WTvP|C$nj^=p>D7s=;Ў0g=>8~lQ=&LJd=-fx` w\. &QzP]ޭp&ѽT"i$&ͯ 4 I!?S׿Ɩ-[pa~~MtsGp| M5~Km@0ܩ#a?9H$ɭâ{Dw؜l{"$ 'XQjq,chkG?v[ ?Eah:Cg}6/7vG1>؇abYm b4Hoa9! B^MF0C aj U)©q5ho/ UH=Vw\6F&nD:rh2 +܎9twck}3S.^o\\}NݧmP1d6"e=q{D\\\vttDLL ㅵ333UtO VN{:3c[vX\Z@ڻi1E&155> M/be~}}0E ?]SXD"2_WtDxNHU*F8ՋsEs$gQ}:9164~H15>Itw >c$175N=CX4 g·V7!"-p9rj1a1?;1,b|xHghf'3RBB)&<S].̒'ZgCϲNLޕZnXtwM҂h"rڗ7 g2Fܼ)gmktO X*li>p'\3>Dy:ci;|v6E6ZCNN`sSpe|2&vp>N^}G/F#q~$Dr=M" 68s*xE+xUhoE#Vlɋxx\$ۦ0Y +}P1Mz ~ qxY`\X_`opihF+elT F(Smwu;pv!k-EisBXR<~o찁sA7+3p\,jhΚ,vQN$X=m^kvŁ^HE7 d[AM-Ps3ihFaEh>{N+44.baa%4r^*hǸX'm2< KMsey A>s! )g5fP kR[|<6}m aL4H9̡YeQKNab,Ջq303$ /#}+xFE7mM\*Ϸ[t_>eS6fxc0р.C89R.tI|lW%tg㻣h_D ~8дߎB)mD"\<ΐ_m!jmJ/D&6.GWs..A^ikؤ4\u4ˢ{in,.#ց84Qd'$J#|B2ZXVq1>TMmEDSq\vKr,Kc1h\"w*ZDf 2H }zsAጸ../Gh60\Ra6 ]b7],! U}OXph.t4dawְ/@\KBYge6a}7ǡCp, ( Yg]t븽(Vebw+~8`:~,MZAu읁&j$cYI`ܸ`q5~TSlxCDjnㅃvA8y!dpG7#1֞P56([g|u \p5 AŽb'ED"<NKd3O#cx}5Ű!@c~t7ѸY<7.:g"F͢{a<ʑϓ %GG0T+d .d&!F#^%1TgІ Z5S|U<s'+Zą'GĶDyw:;`{$ _IǹݴNw+䙇9֦Ԋ0@y#PᄋI\r Rn&&6Fkڇ!ŕ6+FEt;R1Tk@:sZ':Z;>Ztݗ{#Wyiໄw?sDl]rBӣAMqcZ zIt[POƏQ9x:l$iƹCa'1nZyH$“F1/gN'Ev*. " Gٚ:Kn-AG:n`#~ǯnnhd>sG]-U~d 0 2;Zx )(M +`ܚ1N y8/9Itw'̉X4- DfQ=Sn%bN-&-‹ދpMWDz #$0EIػN̷> nWb.q3hĻnnnU ˡ4Rc-Ne6()Z` ^pVG'#i>ώg I9,o?7j ^5>]S #V uŦq Y8"vZ`nk{I+8wǕ:Et7g ή`3Xۃqޛn'H$wu\uE㇏O.{rP?FVP{/a/`b1cmGRKح:wED"q!O㉤%L U ra9r؟9ⴛou&z{IE8%+, Fto?0ޞ/c1gtH3DEwhq^0էӽHk>Gy,8uv HrŖƎ㕇QiMmۢUM0Ս8>v?اsb%ၸZ|>鄝gӅ;jomZ]u8\lϵ^tEw΍Nttt&XCCC}[y`06\S2;^ ΐ45ܔ3>ϯpZ G@g&=BYyP;)lD"\,ItOZ-q|nz -(GqE+{XDGC=j5Qd1Bn`6]X݊֡u&5,aL`/0QA9QRӉ#?`16Ѝbr"g49JfxN, #3EsJZ4=TzS *b'Ӟ_\kI5s{18>EۈxvXTΪt?6T6X#@Ԗ3#ne/nw \G6FڅhO*ʔ>< eL op #hlnFyU* >֩홠x.읁Wvn#8Dpp! 2__d$12pK[HW˃D"9@-SF,mC[,=A"A 0S>[G}ſ2ŧ낷̲g\N3?72E"\XD{Y"EiZׄem{q$mֶeRtRז57s7ߞ Ž; [J@V8_StJqGGG +6Pyco=F{{Ip <<C$o]tK$caQLݓh_PD̵퉞Z8j yhs |=8"EmBFw>aݧmP9I{Kl[Aoa 6ћ9I҆ƦTU"'E@?FH$_"$y=/n}L6׫- ѽ_*7g4ѽ5Ǒ޲9:E7oa+7VQ Aaa)22rooo)% E)X}n}x˩QӾ{57gj4ѽJG\?I:ϠktAUU(-@AAD"H$_$}W1aUcx>䭋J)%D"H$X4ѽy E݈(C4x )%D"H$[;EvU'sӊM⁇["H$D"¶Yfe6! MRtK$D"H$l Mo ݌H$D"Hn >LMXYxe(;UtsȃfQ@ k*^Du#tc׾r vr}itWl۹G[#esӝ:cU-I8;݁SagG5{v+k#e8s;vC({y~ȩImzoκb\o, +MXțO"qR [Y(l_pshKB\D1DtWV؅DGG6bog%;zVf_` a4 O0Z4Mb*~OD4 hAtH ElVaI@Au+GP$cLL#4 4 )-4RL7sP?o~ IBHx*zf7Mu -O <`Iq,/b igDoUVB0|^BuF2"C!Td *H٘DVfvI$~hي^}8fK'=yܕp|_9V[?y&Ja-llҞ{BP!:KWOdLM0JԨ?0}^8 eiHyRٗ{NJdv+ftL. 7LeHt.MfT4}/yotAAq]3 /S zsN\rCDlpsE29ј`K8"*07ُXGF!4NţqJySMMFxDO_1ţ<(// "0vC""<WNb`F8q {w$|qXh4s^9V^t4Ɛm_|q$( <12Ҋ$WR{E"2=l(G9\@td]]A'qq>\ :VVx"aAڟSNBLb:zS]nL DW QX,pQqH/Er}q=BccQ!݊v@%x5`neɎH@@.qQY%ܯVѽE!d!E- |ɻCtwvv hhn:($d=cBqCDdp*^|.r/?{3}EZ ˝YF7");ވB9%>UJucOԓxۺut3e5IśF&y蘊;2Ts5s{'P5n|MxW$:ĵrdۅ>Bxmyoy!+vx; 8x(\ ˯L9'+Xܼb9&p~nĺ(N_TWq¿G՜"|?}bZU.3b:0]Ƃ.o"-Wf? E8r׆Y5mzy+_U1Q#"Ur'xbx9 m!09N1Յp|w5EE/,|)GqPW74 J侬-,*iqYE:|i6+ܹ,,s`}N_@yv"S03Quթ"]/? Fi&0&.2u^C@+w$Y #|ѱP nȧI_zJkv})\[:Nc"qb- Wlx3toj#3Jg[Sp S؅juBg{y_8JSe O+1D[A+BJ`!&X3ga6A:-*V4g\]|Zt,7"-M" nɏDc"읐&X@;P9)/Opሠde_΄QwT&+Ba&U1(:G;DwGG*QS]l%?UOO-D1*On8L'ćϿp9__C,pN~ vYSLDX`CŶq~nX'߆0 }4A)ۀJؾ=?Q~i;b8oz;Rsw<ûEvx?_^><&lE^@=0O1m|{ nG+YY{xާ@H8r/>pE\#~/R++پ 14݄+7b/Odk 8pxS6O)!tN+O eTa`RT7gsvCѝjbta|ld3ḧBxdi䎤0 cTSh ٳ8٭k/q6Fe/<O%Qʢ]pp']ލYn!vpw.xơ/~zsBS9 Ut;e1$!Vt]†Ǟ;Dw{{;S:DX#+|B 6j/$++S';j&<sr w$æv]G-Otj =C'Q&j s F&ka}oË9cE8pP^wXq9bttDn޼YH(0YJ!X ;olDeU@Š!|1 g^_?{oEPHls-+l'[q*\ö Vg)j+mӐ}+n-7ͯ\ѺԄx'Y/!j+{,H^y_TP>_+qw%栝z pWwHy!_Ao>g˕v+i=_wܷͭɟt,c??v?ŇlZq_ZꕣZ*W&+gk/᙭1Zig{m}۾IN.Frޅ ۅO_ߋ3'>ľ3(9 /'PviҪz0>1&ؾV_/0*>9U<~Es3N"%8 h=:C=X܎qMR:~ni1[{k6Ew 3BUNEPz7/^AGA \85[U⺻,(\l.VK~H\{ T+/3Hi!:2l?9ꈜ)v򸈽_}QM TaN:}3%z^x.fOwmHjZD" |[ƆwnkkCIq1kx;b|Y_{箹c{˪B$<BxOBz$= {/MPUo0;"vx"NsBMHyk?))it׮$.m\ˊٮ|*9 N\883Bbn}1ßn+[ʅOY!n)xȭELvv0 2\+:֮^ŻlyT7q7Oii >s*뛰M4AI҉1\Ht_%˫&Y;ݙ\z3LT[0;ɞMdrXv }~0L>˥{ ߰3L&+yV%X77s܋jF9k-Vx=SF=Ն=!N[<4hbjR9F5[ mLMQM@2 g)Hl[ DlIne=0~ Ԥ`oKLt=ݦo~EuJŤ[ũI''mH3m@ȻnQZbf|;ۙM\&.kWm' ݃sD9>׮p!FwxP&f !S<4q$Gʡ(3GOD:(_ʬXE;q>jHlPn8yRJ`1>w?uzUHxrbz6!wS=qHSn3*ZMwװ}jci,zs9@ 9\},2VO1Qs@HFV,>ꄯC"Au8&SGSXIEk~$űd$|$HNڭƚ*1x], =wz[QIww|"yjz+2DG[;9p8C ҽo5#yF/F݆Q:g"e|wyk,cm.$9$n[n#bn>jݺ~<7o{Te1ٚ}o%^#^(>G/X^ #9݌wwzI +#TgI <zm6V[|bXz=]$‘E@T(zy[j?4TSLAt cp-d`h?<է;QxvuKR"UM0#I^NUZ=$Z3#w~|ҭ֯V00|4FDBU/cx]A8r51ʆB}?R]d( ]FM}L̋Ƨ?'eS醥s`RBsq5q&gnXTӯf}?˳5=ĎZIIsw?VhO at_;q:cXx;AZb(+-!;15TWQV\A^N-.ᎊ'rgDoiőC'l9z١|Di\N]ŇrpR>MmOqNbVn6`;<"M|Bዏg|te%pmym1A̱5o?GqH7q-Az?o͉#:D"]9)޳6}CmkYa+:M(>gG_i.(Vw%DȳmLc ^^C-K^罍9xp;Vna [Օ9Aֽ2+>2SH/񦈷>}#9T5|i)Bڔl/_qU d#VOT&zk|v9 `m^YS4X|H5+wc,%`-/7/vBYW"N>\=+շ=bA"6ݷlZ`[غy;|K~> %˚V;r軫$p yW|_~I\ӿGߗ9s;Ʋ; 'Dn?t^J|+N%’YGn$(>ΈKyzDdUR%.ػ= IgՏ \3QAR= EN ݅噄Cs.EH),qJ}>[^}9ޜ;qSoDCUSHH!,Qˤ*9ՌS`0䳓޻j)&tmn$PGi_OmD!" N.8_ƀ'zrņVy84|QX'qx;8L~]][fD1SvL,f`Tt mrfٹaiSD-=$x%Ʃ)nN%dB:3\X=դy[q>bjWT!ҾŢT KT_qt BR”)p $eLM266RL/e?ƆY٪d#'!.)k Cc .:1Zy,,?+ EFςLR儑%=l וWM-6&JFdL1ؘMlt< )wpLF,ߔ\2ýTʶ?Vh-5 Ōs7F-[`2 WS#V6BE>1Twat#猬E[<)'z[CaJ9}3TĦ%0;f~m% 䖫$*!Mm'N(ChQF/ U*/b-w3pnIԶq \XHyO05f: qwa,E RD|R8eBEzlվ04"My{y 4hS?"-XS&h'VK7*ԥ~ufv1Iet/w/!S8<}ؘt&4!_{E'{dz'$]Ԧ`k)iaYwk>~>mbdXʢBfɓ>r$GtT$I󩪭%;>B&)Qx[1Gf A%r-ݘק&{-*u`G"ߢ2Zw'ꦻG[\衶A@{)ao6(~hf21i(GBwI!2Bmc徣p]TV!8bʘh(71j{ZYNms_+9/4VSUΈShOS-WS럴~::}82Ck/g%QmE2wT]wK\>M j%.h 5'=huaz\K$᳚u4R7ݟ:=Dy*;5]^'upHuPyR)~eH~ٯ ?qI 짵~/dhvyZ?<<=eܧ5 |bz* ܢ>G_\ M"(B]KcNu|>Xa_ B6WEz62X$O|)DoC"t' 'h[7obkkS,--RHy2m4>~c=+Y|9$f&cfiԓ4n\[/yFx?I}vv\ ,{lyԠł: 1XOuM /&ZHܙ2{D-!$GFU ԰\d>s`ѡa&q/)n?AUL16K[[Cʇ6~A 4'/҃IEm -DM4DM4oKqOq}H!bkg&@$rW(YMעA 4hРoq=Lk IA#jГnq&QFUN4?#!Qv#i&&WtBA舶D.E4hРA ^,H'[%,Sg Ȯ#laJGibO3zs ej|b+J~eLO^&h&h +/(Гs,>z燐{}IBJkk+9B(NjjwtkРA 4h𧆞t݄Vs?کw{1HwKK %%ϒ6ʫHLHz$+o;Y|]D<<ﻫ*g?> cʷ>KktDyu9Q~"dsQ ]2Fœoyvghj'n^j?U.Ogs9I_l,E66')d'=V S>@ΥSOS~/<"z_`ۛk*Ϗ'bN DZ.S9uQ99Ot'-xl}=}*R$>s՘fӚJi;!._bz{injvA;E9R NbJ x/xUX$ qX~:J2  0h2?m)'>X2sc]4wfi* HIJZu4; E9!w)[ ӗMƣRbDx`h 3LՑ ~ DNMϘxJFEJ* y]|mM`U&aAĦ5(ȚODp?8!D&7ԦDbvRKiU\x]e>vyLiR{NC9Ioc5e XX'}z)KK#'̎RFBnWH+ Ѩؿ*R1 wo/..Cu+v׮8ΙV#D@BRiW;r~3 Mɱ+9Gպw'l T8 D\Food96C#Uk19BN 'OEef"Jy ;k|-%"ED 4AP˚#Ӊ8'?VwRD]E(}:`{ yyy=^kqQůw3VCQnu (_6vFE:eډ~{\*Wf[(-WJM t MPNNnE9@1nʫ雐Y/s&ڨi`Xڌ(iU̗yǟOayH~a ĨT]I/,F5g@$]1$Z<He7|1Hws蘊r2 x̌LyDk[ ϑz1E1tKWko)2`ǟ'wdG,[/]vel ]#>T[/݂>a@q-֬x埝'+lD!,=Kp''|$b8\>XMnS̷_k^wvmO>zזzLC\>S݋C #-8\;oݗs.Z9cANP[qţHQR v6{:G~>_ gcnz=q'N!S Ĺ^>ɡ+"qJR6ew0_}aNpWj|뇅 ?BcUq8O>|Wän&r~*}wo:{0UxXw5N J*8P=?l {/CmXb?9M`$. ;wdYi~~iyeiB(sݿP8$)uO+2" nV i${ma+~k_Ъ.3ssC[:nc=^mBY.( Lҗӻ?y /܏[\ g;RպNҜ哶 "=ARB)SOvxK~H+<{+SL n!aF\t+{G k 3ʕgo\ԭIx w1}L۸ׯp?'ClqS6=*I~+ې<(V2#|p2. Jş/%`c|C_ $%.ل-a"k:F'O,GȎR\ +S+|c^-i~V\33kBWg gy/&5<4$K & W`egyN$ .mIҁƯ9p3P|x'YӇDž/bn\4 tU f>_pFeR0$}ۥju"@clKB~}Lhn~QbJĒ)iWKw] *o) ʙ+B=KбRiiw|t*Dm3}?J7yyĕ%1^/rk>h7+PhxsIkN񷏱wsY w&!Of( SՖiOP̡@1Jɝ|ەp1F>8IHb'IvLJҘ7Ò`HOd?6Ui)UoIyV(z+;B< Fk~=2~ ]GR1L/bIm#$nFKDwsk-NIDZrR,d[5[`6K\ĺXh[XNA&F/ϥDhbظ<5'Og٭hyJdW YI|g bQE`xC4 ?/'/;hM1إlNb^pg ͊;&{Lr\.q}PGrݚ" 3>ϡ<:5$MOȘGpE 7x\ve*CodzhU%ܼG D^$-Б eR&RFh&Z$P7F 3ʅf)Hw/iERYnW=4`hNc qZ7x >n`(x2脊EEX̓.yXO2SI %=ϸcY92p jYꤓT{~ޙK'L\\)h .,ZAc8ܘO"@rExTt@BJK)̥?ǔXQ zxSSN$ÔR[|39N:L pw1c2cN^^ ';řn!\ӷ\Jcau},m.#cJuz7++W`ѫd;o}Gt!ŽK,dt;8[0%0ȝc_|ɒw[Dw6&7XAU^V޾M.U'_Ìp-/Wl\09']I.~-;l4HmlOo7ULu޲a Kf5Ez,|l䦵'6N&E~t*o0EfqcFn s|F~gBF* b͗lڴs& bR;E[}8-d6GsC^9X䮨D)GV04M؍ظ ]X2"ǯ.u[K{laW'/RX?^^?8't[$+6[l̎7ΊeV5ATcU/NxUDK PuȮuw(VH,>/ASAZI{9t#\\yOZ-# ^ؖ4EO(Z<֝$TY꤄ێ`QQo)o4Wi79+-2O.ԫNq4E0iq"&IBDܮy(Ի|y8}1 PF_m*W̰c/6q9.&_I\[>T5@| q2Wx&ۉq0%C=B(m[SyFMϼ I=;<\LkRGSV0!b\Ji'ܖNwͥ 7 FcYjHVeyx׿ڎXHJ'r"&bBpRFͅi1xx7:[سl:b'kj sl}u [4!!n]n%ޓbu%?R"`DtYY-ۉꔇؙaI<2\X@{Ut#\P]er`1/k&˚DvMQIcLU(|F< 'DH\NOr~2~_4(,hNG|Šh)7;ױVZSԩqx( w'2|9"i#L,nbKQ!wqtNˡ6BM툯>?tFD/45H^dc}c!]ڮr\rfpj 2Rpqi.yrӽE6(\bڛ+Ǫ(2cM*y_&^ز%oJH N;c3Z9+gCN]n0?u]?{BK\Wou]ѓ7+;gT҂8f*`,ۑon P])ҞuTMwlv'(Lq!Db녇tj)uo%kn+^mN|I$_h] ~G9| ٽeX9;x8tKqM싿ͱoRUwᖣPo +9Jsi_#?{}%֬9nUe4ˬ_J#.[r8l{g=&QuM8nGv>!|~®1JxW9^9JsNfڲ9w)Rң_r9[It 2@aF6"4ڰ7x-GssX_ak h(&+#3]DMo kPwƆشiC{֙ib/eF{GJ1ݹV*aٖ(R,ɖ|:;EVaS&gv[^"}`L!=Up261,ʜkUFʂj2-}s+xlu/AMC 4f:OlL3Ji>^a(h*1RzC긽Sκk)4|R5;;D𥾩m !Ulbj@k,}S|z͆Tɣʉ %Z65dgN&4>%ڑ6jKn((nw1%wT[EUN n7Vk*(8ftނxR+ٝcªeaXSC(4=!H\.#b-?4q"\_X2u⚱ßt!HwpzRRDf 45GFzlFGSXDG >wy+YJq$jgmqN&#N1s9TN]/_k\v}Pf  pYܷ0"V^iNx;ɮ8;8`oCJi/8PZSGqr0 {QI{TH Sy&^0]WWG^N.|v~w/v5(HLLddddt`j\Of>2eb- 'I1:>1᫷j ܸk?$/ۉ G2½[;gR<^2E䵃|[U>;Nqlx6h2.Vn]>ٰeK!6~iS|gzy>lCO$+bkgH;Q&ZMXvW-y)1Lq1MRH 9GP +b"zlyY2~.z)ѓ`,r'm56'Vu n2 ӥPwLLؿ blh{pmcxhbSk-VוxsELսlR?ݝ> \%MzQ2;/zkIW#D >E)lf0o~1ak7s~!kvj{M C\lA!M<o8NrmD:=Uυ}K`iJ$ 0H[3-3>ٿwr!EUr5/51 w- #c6G?3Bw[l e$ǂ^і}4˴ hţ\yj"d#u Mԋm.l:uQC>3y7/?s5lN.^ t1U#|_)8lY,~?WqmҐȾW-il_%'QVr1(]'7/=[(`\v| [ dfF=}ՄR衙1jq {­t\n:+8F١6BR\np:p?C퍪XO\Rt~HsbtD`8|Z,`I^h;%tqd{vܺ:=q0Ni VvXYLOG%13SXۓX7Do}>f 'jIr;qs0!MXKrM%8GT*~H`>&΢ }ۙv!3Ԥxq뎢{1xI%#?I[J!Ub=>6!3𧂴 7wq$貐 Xٓѵ`TLi`ILz_ω.%8S3oAܝq,c IPtgqoM5RZeerי%%&@@tt UUhllE[%p>ngݸ)nbMS$J70KyUv-sNxLyTWn>8lì;gKvKwQWOkluA;Lxo!LoKF=E'lywt̋^y/g-o/[D ߾{o_|<[NQj$lg# d]\74ԑ8!w[]vN63*TP+o+1[߿_li\z7;dG>wYb؍{] =}8U^^gJpK7ןә;p|Cv>,a4Keu~w󭽼& rly[؍ 7Ex-KVs5Φ(N,{ ;+O,K_O\[ &~ɺoefy˿,qKc˩ [9~+I]{moDѵ(k.?ֵT }r7_OP ͣbG_rNB qs#w nId˯H&t//|-aKߜ)ڰ[#E?@}[ 9G_疫7ޞӘʧ;wc`lʱ{.\½o'>} jzIwCÕHy}biMê55`ϡ܎m2Ùۇ4Fu eKK,q&+|X>r8.캩.WOo_RIb#~6N`6www?[y{]x(l{ehWwEgDTHh8=?O#bAVؕc∙s|U:ϰd?}E*՜6/䯜tK_<9:LM~—gEcw/!+#U]:\x{<~DnI-f팰x,j;CQי[5A琝NQ]:y-ĝ.F:)z6tedzbL&蟁j2H' +]LRfg&i- +EbaX͋7q MV꒝/_E(HH!W-HQX1ɵT>͈(13#ۜ1{@4ܯX_?P kG?jyLXl33 w-(wsnNdD5M? 蘔V❯owUL]H'xU.g~rf4#TnEnn9 LJ C58Y0"'R7IenYbLZbAB4D:٧X)^2Iy;Fl!&} ¤9ʋ9Iwb/Hw|O Dˉ`vz LON*djrёa>|誐nq7ټaw}Gz/^񹅙o m¤3d lظ un) ٰrNQlynظˀR ? ٸqW}[d9dݻŃL'r:򃸾KܺR (KS+Atd:h=e N"5(/,{.Y غq#GC`4&8rtF6GyH_i'7:J}w")esaQMBLu$ǿĆeSi#)yX̶cjM@B-N ]W(|8#4{ΛLJ5)3כ#zݮxPǍ>#7qG=)+ vWܓ;&]ޱiF]F>(mSdڢaY'FiCLI)*}qM9 }ai\3?B9B=ljj&>,s7!;7 ww>nZTtp-[!L|fӾua7IGU0.ڲ<[~Ύ-T I%l}.3I\| mW㻭ضs۷nU5Wlæ71AEo粷j5baѯyEj|.Uƽu?fg١yH|jcf3"]{qJ;ٱ}>?JOR/ƶq.cW.٪k7ܨ&ʎ aׂqvn"]ʠ,~T m!Ȗ&9<] 7>mlVvqfMp`2s۽dDvbm JcLE}xr4 u ܛ&9_v)?7'\\`Wh w )6f Dڙ~ "ҊrmxTKy%$],Mww] :ZtQT ʳ J;8 ?gX\g(w2?;%j:Hz\,N桻].n(zVgFNT%r zj(-k >y>/qVW#Q .D#hbIQ N4dp {[keKSaljd\ku$?HyJ"[u/ƅ? =1G'P,KwсycH_LrbB/;Jq#j:+c'/qII, _A{~yxqT 6#BnBqB%VԔbP%."`pPU0ddPdD3OͧSKYgq?(jOh+kY޽cE2W>>K,<V׼4?<]6÷ȽeMWgj>W4?Y6n=/E'S\f( m|S˰Y_QS/YO_U5)BOWo!uk:^><21FI^##ҧIz:)/cH%jw)OInSip>ޜJ#eׅ=9WEn>Xڞs2S-m>:. /P=+(^~܏i}HD?5S~?ݕ# >wӜGU]Ńj:FX Br nnܽ"pW+n⚓wQtvo|9zXSګ\L|Y| Om| =E' e'g#֯-+ؐ.4! Sq] nw^1ʢIncvh3iРAßz}^K )#XkV'ݒ ʲ+**(--QRRտ|tONO]S_YCw?kEz0.!.,[o haq?.s>t}P~h<(u!ELO222|]bbBlnEQ1q3YHev"ywEnD2NQkI3t&KI;[)[irOIFQ&D9"l@~wrD 2&2\=&]x-{˲rFD{Rfi:?;GziuQ(ImCjmbѡ!F'q퇡E.[kn=& 2ۦknG4cH{bbtD1&qmzz1zGz?Sc r'馧)loS?6=/qRiwG/#ϾA)1.W'O~{ff1& /+?61>`}}􋱳pl1;26c>\ ؐnhdR֑)FG|"Sblx@ѯq9,oj\-kpIEyT㌌J]o~.L3ɸ6>T'DŽ~k1 =2Ey<6&ArHcn}e8q/~Noĵ)uh٦\-8*Ե\9 ~'D[ 1Ma "Ģ4~zcubFK=MHnРSxzq տ BEE9Yr2&,ACn7,S~/T!@)&"CR C9LNpZ\X'꟪q tQ KЪOMWn`K>O]!D{}13؆>^ӧxRT(Uy+cٮ-E*4KhM+`լ<;%trՏ1R+X,C6S pPdWc^?^zi%)z)d._f!E8'cH-M3N9YiEUdR]\!}8=]O0ٝEV09cHʦvF:ZvAz:z''uwKTF%= t11@T`"V8XMWInvX\0#KatDs=OL0ZuW2{E, 011JK +"M<,nabIn5շ'楦Ton=Janh1޷axYzF2n`Fbkr"+>U=jHJT[K=>aU%akHҞu0)H;X;M9&}"\঍- UfIkŠBUE ĸn+"yyz;Ip-evQ;p?jU$R3{q/ ~bloO@* ^ eAVA(BtU9D]g-^Txl%<~>Oul` ߍfY{xL5ae)c[hmyIC5$5ək?~ϕ۹WTiln`w`Uΰs9<;Z7٪ hGڋ.`G5u҃Ü-֕zu+rfzPbʞ.cc{C_ߤT:v'smR\܌ 14Kri(24\ Q&"?P[D28&TSkB1.<ЙZeNjz=3{!"t;l,\7*Ƌ9Wzˏ_\?KbݴY^2PJCCPjJQm?}uJXDUiFN? FȾ{OȾÇٸ]K?y^~ûgZU?Ʒ?˃ٿs-orL[r.x?+G_*dR˦͛8~(=):Jz<̎8~<3lItJ$|p-.*%^߿yݲ$7 I>g!57?& ل{P*!;$IK"{2}ܹaD Rwɕ/ݶ!a)' q)tQ^\]+WRHAazjvbby-˾mĪ^ >a$]X!Y_z*!߱Zj݆o_$KoR:=&V)ܓz%^{\dȊ)W8oӏyP8 ,ØǻDP={"Z3fs9!%Hm,H8Âtw M/ L@Wʪ8m? 0X]8>90}sBe=yd}S%6DqIؾH=q$^q\prqs`H-$%gne/.Q.琋?IDATFr|}6ex %#tN[Kz=*{"'֝Ư`!1s/-eLZAr>ω_#/{.8 ֳ߯ JLU"2w;yb*Hw8v:DL Ow'qN  <;_x@G=~Db{wUH)?Ǻw9OUqf2+?MLBIonh_ GOA$o= 3J0`UfhVb_֒ePo >$nF$|1v!*M&B22bˆ#88]* $$Ã/{jF16tR:kRLrbNR/ݼ(95Qkaklse=“T`Lbq9q^b@C4>c)k)塉#)BR9:#C .>9J- ݡ.&HgE=kSBAW-OnAܬ0 4:,FF(#]VBH!ۏ'`㋏M9FүgCßD)y\1%R_~M,]SmX4Ϝ](.TɆ|=11Q9'n(Ua e/hJ֬j}" Z Rą6pՎs!J/~ٗ-6/~C0S$9Ŗ͎fKj55}95@/ȭzO jx?_:$^o\wHTHw|u\ Rn'!nl;܎T&ZYDHX$+Hq~:֦I1ySLt磳ϰ[JZzoA-L+N~@Qٙ)dG!cMaz#6Y| +A'w϶a"/a_ќ{m+^}Ty+<.eHI28^Ak $=s1玷8q7K%:Qm'Krogto9ɖ C%(4Ȥ\;S.{v(vx3SSLNv{ ݉{҄f59~60< ݃xoeL\s-<Srޢ{~) hx̅W6#k:D,av |LJnK 뜦:Xlb%BJȹwWƒXhZp ?UŚq%dǼhdoz=CCM$zy!<3bHizdD"| 蜢$hj-4!C` ~$cPyh&̎7ɾ"8^2'FQv?ј^r`ytiu[7`dxG79\ [T%f+{[&xFS,T%I맽<{x]T8[ix0ͧD}^L)~Y VdH;WBnoo;.ӎg?[xIOŸ -T%)EEPg1#F5OOtq"8.\ѷN14*v/ 88 tiAvu7Q%bGD tdg205G=]CIRU^#t uCSCl+Kgi9>Dx03d=yXZG#'zڛe%a| {Ӓf\&*Ηwъ8bR\3H7~6?,W^30D:߿k6݈6&!|~"<Gbb/xUuܿt/wߣm{0tp!3 خY[Ѣt|mXT_zd==+Fb8ϿfyhLLXf:U9<epӥ,,jg|}/^vQ_eٛp5G\8|;)g'I ;?Zl-6\[ w]"@KC3b⏿ZKM=>%txo̷b{Z(]|yڏrSYvri >Aoʎ!czk5e;6ODc;.vw9J%ڋgu /|nꧣ&cbGQ _Q Nݏ}j%Me; VeX '$h[S tKMwU*.dӐG`>%s˓)ؘ>z.2XbExᄥ4>svt?nZ@O}C>~ D9qOq1uJǙaJݴcLyJXݝbk<KL`#ϗFim'? 0ښ ~ʫѺ:2+#Exݴ!Eu̔bcTK1>[&*5?.EդNda;-dV4 MU?VTi0ޤ7uk-dG8clHy4ٸ]#M%(%2]"_'(Uwԕ i!U]E`qӞ~F[𰞆$&GLa F^O B:7>b`Gn[S\MmfRcQo񨢃м.s::a;F`lpLAFTHt棣#)*[-ɓ,yw-W+ԇ gI1=7}i~K.'j 5o,y7_=˙wpys>\1=ۊ籵!|s5[:U㡕,y}; #ۻ#^ :et'[^Y˖U^2EW#GCPL'7KKXR| :<޵e|K^n^o=W¦ȼwu.dt鷂Q* X;QGnCRS1]!|.–z[PkְNchcٱQ,l!Qps3"P}v_ϝxIfg~5*u[UR:< 1)MRt^^vؚ8nM_~!^YQa yg|^2̽f&.+"^ 3غT6L#k~ <һDWLnȕBY&jp`2!ىyb73ؠ[h"ݘiF6q 1.6P"Vbi"\Yb)o/{C7BBe(~J7^$^?-n9 h{m ;UooEm5"v;cGD1ND.HGH6b3h-kWs蚴Na! Az8iMb!pm;oKq_>"+_u~cgtH|_e 6^!Yy`+fʮE MxHgu{AƂpA.ՃKbL֧cv㚰]3`HJV~004!I; $W9!&kLKn޼7p|ls˘;mϏ䆈{͹]DkS.V64'-C3"8^{Lrrv@k nq%]ۛf& Ԙ۷cAEKu~HA8)ؘڐP;Ym^^ˈw+C }3I/3C%b| &=ʫ&?*l)m1f``O~|ف\X8~~GTFrvSx+7DZ#miW!}BYJУVf6 4S1^ ]TTDXhOCP5ooo ƩIe/_G{%JԻ$,sN<&U}$q$_Nqy|@~@ [TN,S!_KqE2O]<ᇹȗ˂d|ꔯRah,b۷J.Rt.VVeT*(Q.(_IsJCWg5\:T]IO#bMϗ0 Yd66˙m%GCƕM+At(n}ѩڟraN:)PBWdӨ}\n[]B]JQܖER?]|i'Jeuz˸M뮖l^~B߬ȁ7)[,*(DĄH+Vuӕ%֗Y<r,q#erzƤv"_(mU~]X+_C9dT2"Sߞ[䧎woyMظ>o+PU\W[*ooH;Wxq(\#< u~@Y[=uҦ:d੶P-j7%lA*a2|yREi4YX3I\5"YFq?|{A100 :*P0É'RFH\ QVCC΀>YI` >L/rd|`.oV=:o^f'9c;P/R+OK /Ǘ4<%*<8qnJN7[߳Q".A3߮:˄ υ=F)_4F\;)J@:,sv^[>\6GRQR͌`q~V|V qUgoʸv3g: "b_Х+ylre.RSkOӅ\4 tP._Gw]F>'Õ|~ڏUe9"LA<}4 ~>>[T3/_<+Γ- ͋)*6^L[_-;hA#|&"$_&Yc7-mT3)iR݂IH&Ht@y ϊc&œ_~Fɓ_ }2y_Ɠ 4hOSZ n# YԴ /CYyhCkLaDϾs+O|u 4hРA 3WuQMhn;!)R [ 4hРA*-Krk{-"~{y4hРA 4'o[SP?@R8 ^hРA 4hScCQ$NT;E ox>A 4hРAOz}I!fI&~Y^n 4hРA  IwqN2tkРA 4h|Г t6* w$3 j[ 4hРA煞teE~})$U)ݭ3 4hРA z}9y5=$VP1, F5hРA 4hx>IMȭ$tزn闯 H 4hРA )tjLNE;1EW>Hsn 4hРA RbHvy+Dv[Oson 4hРA  Rtw[Ko>A 4hРAsA<^r1vSALq7Mc,}=tkРA 4h<W%Lȫ X%тt7HҽJ#4hРA 4<H S.&H|G#4hРA 4<&]DB}0o.H 4hРA υ9}ӌb;k"4A|{F5hРA 4hx,$ݹtw,Hw  tkРA 4h<'˝N" ZkRvv5hРA 4hx>I[uPKLIQE4t;֠A 4hРṠ' ,(l!fP!4=4hРA 4<+h{H`ցIzW" 4hРA =xǚ5M0.0IVH 4hРA σymCY- ~$ !)O^rC$y@/yH*񄴽)޵߻UDb`}"qۋJחX^)I`nEp)liV[]1M<OP6r=zgbIguSebORD۫qu gZo~ٺlAplxpT0+[}`jzAV2Fi@qv֬5\|ʜ̭NleXdsjcs7f W+Ն7`g ȘJj|h(KD- dXiJ؇(x$( :;˹! I_TS 1?E??ZBΪmU/?~xY'y5g&΋/ɋ>GMGeD3Vq%'#q$8K)fw9:ĵ x}rxwr:\TZaG*y8IjbRc|XŻǿI u3KGnD1NIBs RuK>V.EL+M2#'fi ~V vl{u8zH *:(W☕ ~JTe\O*tHGHY}KNP*ݾ˦TѼ9/#A7qZ$*c?qUnwN%Oi4 =3N)cbJ uV4(Tn 7_?m-ٛ{UBwznʜ"Z xJZp; {/<P;,)''KQk5qpN8KGbe Sd̛\17 pa>SR! 3K4'+rzQ TTIIvt]Kc⫲K#v5+|D~O@%\w_nN[L9KqgVhn R!y+Un;*&/HrT >>\ t=.Tġ S; Z~!P9giCڧ!# B,;X=ۻ,I2UWV9$lk=Aj;{AP79|s*Y;̠[MCۿhf]o{oY=1kyVV5E8Vk+֜\80X4D)!!?*|fv u"xA@T_q64)kڬuV7 t '%;i9s9x,ڎ-45xd8?ǘd/Y|t &LILJ`& -Gt/PK!b\word/media/image2.emfܜ_]Uw۱2`TRAЖ w2igRĉr t24ha1؇&s  <`'|M1 D$H;={K|oosg!L|rA 7TyP4+okw+†4i STjއBitE5Au+er+FV;( &ds]1Vjpm|em֫״ЪoϹ={6/TyLi eƞmקU1^!XcbcG?|9?:IgpPHj^M+575O y8) _n'q߯j.nXiW65|Ӿ/_ MG/Dd'ܵwq}kS\Yw]ծ?\aRv\GC`]c!YnEf7^)/Rt8ͅCjsVP^BpY1T9]j[4N<̅yV/Ҹ:{T랖x%F?qgd*=2kl\  ;ۊArL,rLd'xOgxSw+Z9&6}ZGVcƞ(NEq́>WTsb~sFRƕPxTzJ߭ ޓ5X!ByP]\ׅRgcg2JxˑZ xVzX. 8r!qqNs98 pX/|=Z^mU>qi!U}ާs!>$9bl/޳:b\)sp90[z)0[G[g﬙6l^|Ier<Νtj(oba;qYtNƪr3S<1t|`xR|zin}Dr`#~e>3j>{@l&_c\[eQMHsdYی}Y=mx[FInlbOhXչ>Cڱ^{BI\֮0-.ѐ}6<]q}8,1pZ~sq ll,|0VW[ ;0q)pJOl,` Յm&EޡoDbXSU73{Zm"r2qvwG}>~jثݛ)!88ΡNd/1ڔW61>Jdt:v{?qVˈ gؤ5ڝҼ\x.PT+z-| 2F3j^].Y sdջilXxn'-T[=0uI^5yyM^qvry/lFNǦe_eX;mTrf_mbӱȮkBؘ`'HnQ|/3vrzMGUj8]M'L4ygvgYY!߬g>9#1W<85pI\9^r-*3:s{_U'&Xpb}M,cUn 'k%֌ M72&hu%e 5"qOm\`eT3yFvZF\fؐ9a[kGk)aVkEk]DyavkfZz1b9Iq·&kAkDk7Z3a̜%'̱eF&֎Lb ^s_X⨾KloÏ},7x:Ƿd]QMs?htМ`yީ.@W͙2VI,4g buu9L9֍3ksyhԧ*[#Ӫ+L}Ig ]I,4grZP e##/mМphR6(ݷua֜7o9yCR\`<329SNƆ8 ;ߚhΔ?O Us͙Es]Dya4vpTѨҜ͙ ֻnzL>תN}>ݖ2fZ;L֎Lb{k~;S~ǦX$z3eX5D,'LcOb_m$>/Styޑ<_~WߏL/khƯ^U{4ƺK%E~UkzgD͒4Vs,ɽ.'%iF ͒B-GA'#/f{?4 q> ŗXla{ohi r愝oG4K=?%W͂o4KֹfAlo<K4KN4 ذ,ߓ7Xw#YX;% dy7ډf%f4jxL~ʒ:6Yh41~Os |KfI}[)AYޭ f޳iDOmz¹X33yFvZF\4Kؐ9aKt wo6"#o{M'z$͉o9X۬F-_{_Zjg:zOoZ`htoU=scf86 =A,FXUmSwRx b5Xƪ17k0zdkN}zPI|HvHÿ*gWtz=u3~9aX7}Q1{>5d AY{}& > up=6Ն1_X7$Z5ZYR -rУC>U$INУD>UJ,j  wegswhgϒ2ʴ>l  YؠVݦOJC 7 r:~!YӜU+6z_Kcr-~GZick24+qѳi\c ŝ֋4ouX'ugeu8i[{gڲ>uI^e僵yӼW./͋ slZ%Z7a،W C 2#]τ1Jܯ6zWK}Zg~y]>^{ԯ^sbzF/RƺY@5Vuj'Z%ip=OJXqNڦnB 2yp%X7(."4巨AyK,JǤ`Ee~IYgfFnEcuшe*'w]/z?^.Ǹ9›R9F\?/:cn=67J.~rFcnsFEOn7̍v((mBcnsF5!'h縁܎̍v(({s7J.~rk̍v(~r#Q, Ql˜~~ans&3s•nJjYpJdRPu%J ɐ_0$r V"E2B:M|׍F,Z3KQ*HՐ?s܈fĉl:lWŃ%9đQvv6B/?cV(qUA52D ^\\Ĝ=T6Q'D҄@[nυDjй&5qeAtFD3q_ MG􎛌нB7H%/ í;TSThlH\a([Z v_!j Y*ơxcWZНT1~qATMI =M1iK& PԮ?0 gj^['6=Q\jiMmj[*5uD1v TKr?L(Fj BSu8 䛎RA[a{`O ]T#UC:ڌK()Bjw Mru6 l?RM=9y& JmcG|oTo2)l¡dPnF xW?0Ocʵg[ f E/ ,ej0^6i/ u0{JJT4 ΅\B;gyvsٔ3\L:*B0X)C1M\@>'/+c9%Jq %$ν-sPK!. sword/numbering.xml]ݎ6w mfRMծ*T&L' Lc Đ &rqn9χӷ$p.H0rC'z\ya*\xuS?}Rword/styles.xml\r8}ߪȗe7M\x2]LQ5IhI*!$Ćf6/AvI}cYt|!_F|;eMW~?~y9ϋטH$؜%AoX 7W$N3x>0%N}QgwHL6.NA#gUFXݸștox'Z ^5 @ "}=p6%9hhcKQTC`3BӰL:ۼBJ,bTh^!7XB|c4f+Q$Ap'/ gظdf5#/v{d2<>`{.N45 ~-{=X=nmo*SlmQxƵ z8ɩFD»S}(!FؔlX((eU 9OkS܎B79e7 t3)4e55O-n@cDer p;gw{r.NCDՂ\l\ FFm,ޒcגrv4jA!Ցg:@m_7jjfy٬p/5}~r&F;M$bR{6l[wL&x*Be-60834–;STD_j3i0UNvknUӰ'`IOtP5h㞲Vh1k YSoLp~-| f!)iW̬v 6gӢTb6JBlb SպӾ[-84Dփo%]OJ=f U' 5'W6bL˰ @2`oc^% `YR JS6MHn/IqPK!pΆdocProps/app.xml (AO0HܩFhŁJ pIbؖm;&4dic0;ݔ* )mM:]EL*aMyX^' cHcA6n>%X=".hliҺ0Dmk[-ɷmb˪Z1HhS?{_Sd CcʥؤB0W$O D6₊|Zk"!/97-E"EצD͏٣| :ry Rz6/.G~vCN-0%&"on8E=Vd|n3Wgp9^w`OlPGo?KlxA5|<PK!t?9z(customXml/_rels/item1.xml.rels (1 ;ܝxxYt23iS(O+,1 ?¬S4T5(zG?)'2=l,D60& +Jd2:Yw#u]otm@aCo J6 wE0X(\|̔6(`x k PK!OIU(customXml/itemProps1.xml $( Mk0 k'mP┤`WqCl)c};uǝ#!=/*fDwvCնzm`秲 VDAS8|eۺa;gonv릠uqiX (m:8 1N{Ba&eӰsވul$9'y7#TKՅG\^rӷQދiRjWT?PK!\(customXml/item1.xml $( I /-JN-VNIM.IM .IUq pԋQR %bJ 9yVIJ%%Vzy@ (]??--39%?475DL?)3)'3?( jUч{Ǝ PK!rD word/fontTable.xmlԖێ0+"/qB8jaKKՋKkCd}9[̖J =8?ۻ'Ն)9AQT\Ofc\$=5nm1Δ&ҌE:AkqtC1S ҂Xס 6IȉeKƙ݇1}TdQYRN[A-ׇrȨٰ4يkJrRj ܳU>Ad쉮qE_tExI~]xBVU gKͼ baM|˔XKdPK! /Uword/stylesWithEffects.xml\[s~?U(ȗZe+UN69uGY#ȎoO0=V( o߷fyē?~=0 *JW,Y'sקxI~sSQl-_o 9_=uGO<[MF/x9]mJi֚g[Vyve.}SVD(g=beɹ+!qɹܐ(Z+xۆIGYxoR@MCJFU( ZlUM|U5ҳ]Rg'qz=SA :aßa7ȅ*.KlB&J?ZzMF(i"x_o?[42}="cÈJS 30=;Fu^+1yE#$:hD@ w^o w"`H\(5H}1:Uj/,cK7(m"nYжtr\fE:}1'ߦGЕw4h}Yk| 1i-a_b̻ K:\{ etn[oMAW(Jn'bt%(G3*]I>Y.Sv4nd&5a 5S \ ]1eP>apP>a:3=t˙uð#333k 0P$_BnPԬgj&R5>29E)iN0M @Ð7?yw G,gnМj7Oq@&yAzfT=rv&8;IgțDB KSk& Caț4 y!oP Xܠ9$o3=h @x 77f'oM@qNPuJrvP K7 Oq 0Mh& CațԟA#o37hN5ɛL$o377&'oM@qNP5TMxM <@. C!o0MO Ñ7˙4Mr d7șZs䇓7AM&8{F Xai#` C MS^Yaț0MO Ñ7˙4Mr d7ș{(Ա%o5''Q_uTavHORCDKxPU=*ZW-cazr`Ki\! LB8$`s #;ifBbKL qqJ- ՛ m@j<~ԀԱ> col_2VNd*ӘBE;L?)(XZa`w10Vo|z sa4^5lR&N춟N`jlg5r빵eǧ 56}}9&r 8^j/^Yk1(/\!'!VW2e%h~q-5 OczFIjqH"iCSڃtY*;Bcbx%N,CQZ18sS!ծ\ǘtvh}ط5kfo#;ىkŲ&uEYJV Z0rRR 1t`8tv{xahX&m!Xr>&IM &cIQp2O +DSqEGxgVE3\ _v{'2%N>sqGӠui@9Zھ6N*SlcSxUƽ fxS0>w }(!FhJv,Vcm bYqU1 3T3w] ! qSfInU7fRriK5؆oZW9L7Ssv'g!)~Q!xkè[RfZR֮V2Yr,V7[&}-]X,8oXGCD\5:F" aKiۛy{*Fwe Xtpmk4*SԃyPꙀAxv`;yknp `IOn2kei ֬5n0,dXڟooNn\n `1YYu KY洘-71)R< `W,HO9>P;vo m, `N{LZBoyxa |k|R5KR>i \{5k#Գ a_c+c?o{awƖ 6e}K Rn)(mu4}+>`'+$͗,PK!_@mdocProps/core.xml (_K0C{d@eO'o!ۂn޴{{97){d;AYS!ZV*jߣ,Dn$o  y}{S DŽ,L`UhcC& kS7q7'̰%w܍DtDJ1"ݏoz`bOp@?9Sj.e:=gK1 G>QضmN{?ş˗>jL+.`%>/2x@>J/Rword/styles.xmlPK-!pΆdocProps/app.xmlPK-!t?9z(customXml/_rels/item1.xml.relsPK-!OIUcustomXml/itemProps1.xmlPK-!\customXml/item1.xmlPK-!rD word/fontTable.xmlPK-!Nword/webSettings.xmlPK-! /U word/stylesWithEffects.xmlPK-!_@mdocProps/core.xmlPKLepubcheck-4.0.2/docs/ePubCheck-4.0-Preview.pdf0000644000175000017500000233307413017276730020164 0ustar eugeneeugene%PDF-1.5 % 1 0 obj <>>> endobj 2 0 obj <> endobj 3 0 obj <>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI] >>/Annots[ 29 0 R 30 0 R 32 0 R 34 0 R 35 0 R 36 0 R 37 0 R 38 0 R 42 0 R 43 0 R 45 0 R 47 0 R] /MediaBox[ 0 0 612 792] /Contents 4 0 R/Group<>/Tabs/S/StructParents 0>> endobj 4 0 obj <> stream x[[o۸~/@'(ME qA=!8Fm+tJ6)z%3|sP9>]UѸb>Vh0c7'Ǘl9f䄝}/88QBb+>"ly75^(z~:"Ԛ !jyI!_b04#K#hݮH M\ʫx}NBq]õ~pxe.8 ڽemBq<7yZyIq]ٷڒ p?|A0InL7 ƶ}58N)]'>ząhɷX8TR~%8̓9Jw AM WcSz~M#/$~fqދ܉ |S!iK nAIӂ]O$En\{3lʙы.-M Bd4Bfℛjn;vYͿ%-1LĿ;.4 RfA&~{tbGy'\6fE#5VXĘ{£1ϝ+"-T Bp]TvQNouQ.jS~mtJ]i\2#X` hV'7B 5li"/ZѲOKVRtG 87}Wpn32 )FG)"c){- [o,gٞM;-syL5UjٗDϱrȃM{C6B+!jSg4ո)7 aڍ=3 QVpѹ(qox7i҅z)~b1/n Z i: O.gEV]COq_30>gIU ZXԉ¯>2II3OjF_V>=2UvR4rçg{hX tf>go^ó3D.cY8+!Rl;c뀇@ &ptՑ`?7U8I~md$q3rRC 4ogso, 4ף W'{$JTV=į %)3uX?vT;s{v*Ύ-pЮڿfZ5YAqVc!Q'f $udW0Ē߅i4Mb3Q4;1|`y ے8¼oR Ѱ|M&Ҫs@pWS6:ez {E%YE Ot-Mb2tK=,C@Q l xF[oǔC ]l8c"7/ Pʋ•d*@a= q Skt7NCS"N߬]缃Qsh WۺAxY[5~ (ox y]'8DcP;_-`Hc0?`y{0w&A ?̽f턹 <`._M ;3Iخ٬&޴Ay./a f%(Ñ`n`0[N2vb`_ڵ/ybL>fzayGp ;%n.Z{6K:*o3|p<aÃ13OW۱XY{ZA&I"9nz:ވj<ɞJ=)ajӓ6u/E(z0+Y$QƃieYCSuL̅eKls…eDR%y掽tŮ*< ЕVV?= ;~aOvkN6!$<86M׊MGH~67AV'pàIOuFwgK<5#wو!csFB)S[i S{lb:ֻN@v`;خҽz[ֆUM[>g{7KXQї?\ J4 (qV5{=uµ lmµ b/ǵ~xWan{<<|DWDHxpǓ#M/t+^R[t7Cz Lya~RS><o4<n av9 :%!&'9zQgecNldcLP&nVAOzR-OrȂ;\8)ǿqp?tf9 endstream endobj 5 0 obj <> endobj 6 0 obj <> endobj 7 0 obj <> endobj 8 0 obj <> endobj 9 0 obj <> endobj 10 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <> endobj 13 0 obj <> endobj 14 0 obj <> endobj 15 0 obj <> endobj 16 0 obj <> endobj 17 0 obj <> endobj 18 0 obj [ 19 0 R] endobj 19 0 obj <> endobj 20 0 obj <> endobj 21 0 obj <> endobj 22 0 obj <> endobj 23 0 obj <> endobj 24 0 obj <> endobj 25 0 obj [ 26 0 R] endobj 26 0 obj <> endobj 27 0 obj <> endobj 28 0 obj <> endobj 29 0 obj <>/F 4/Dest[ 3 0 R/XYZ 69 687 0] /StructParent 3>> endobj 30 0 obj <>/F 4/Dest[ 31 0 R/XYZ 48 540 0] /StructParent 4>> endobj 31 0 obj <>/ExtGState<>/XObject<>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI] >>/Annots[ 59 0 R] /MediaBox[ 0 0 792 612] /Contents 54 0 R/Group<>/Tabs/S/StructParents 1>> endobj 32 0 obj <>/F 4/Dest[ 33 0 R/XYZ 69 710 0] /StructParent 5>> endobj 33 0 obj <>/ExtGState<>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI] >>/Annots[ 72 0 R] /MediaBox[ 0 0 612 792] /Contents 66 0 R/Group<>/Tabs/S/StructParents 15>> endobj 34 0 obj <>/F 4/Dest[ 33 0 R/XYZ 69 691 0] /StructParent 6>> endobj 35 0 obj <>/F 4/Dest[ 33 0 R/XYZ 69 595 0] /StructParent 7>> endobj 36 0 obj <>/F 4/Dest[ 33 0 R/XYZ 69 505 0] /StructParent 8>> endobj 37 0 obj <>/F 4/Dest[ 33 0 R/XYZ 69 388 0] /StructParent 9>> endobj 38 0 obj <>/F 4/Dest[ 39 0 R/XYZ 69 601 0] /StructParent 10>> endobj 39 0 obj <>/ExtGState<>/XObject<>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI] >>/Annots[ 78 0 R] /MediaBox[ 0 0 612 792] /Contents 73 0 R/Group<>/Tabs/S/StructParents 2>> endobj 40 0 obj <> endobj 41 0 obj <> endobj 42 0 obj <>/F 4/Dest[ 39 0 R/XYZ 69 487 0] /StructParent 11>> endobj 43 0 obj <>/F 4/Dest[ 44 0 R/XYZ 69 406 0] /StructParent 12>> endobj 44 0 obj <>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI] >>/MediaBox[ 0 0 612 792] /Contents 80 0 R/Group<>/Tabs/S/StructParents 18>> endobj 45 0 obj <>/F 4/Dest[ 46 0 R/XYZ 69 684 0] /StructParent 13>> endobj 46 0 obj <>/ExtGState<>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI] >>/MediaBox[ 0 0 612 792] /Contents 81 0 R/Group<>/Tabs/S/StructParents 19>> endobj 47 0 obj <>/F 4/Dest[ 48 0 R/XYZ 69 720 0] /StructParent 14>> endobj 48 0 obj <>/ExtGState<>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI] >>/Annots[ 88 0 R] /MediaBox[ 0 0 612 792] /Contents 82 0 R/Group<>/Tabs/S/StructParents 20>> endobj 49 0 obj <> endobj 50 0 obj [ 51 0 R] endobj 51 0 obj <> endobj 52 0 obj <> endobj 53 0 obj <> endobj 54 0 obj <> stream xksf1:#ĉMgHJbMX>$'_vw[*ӌg, G6xc/^^vlʮGWz6Wݼ\|^`F1=?,%!Y&<Lv=? ]1???-PD.Dr)pF߯ݮ\Yh<.)b^$ yjr=TLa`WL67,tH:#5*BB`kVg. j9wKPWZA3ҠYe`8Lo8%9eߨ e3R^FV#mk㓯k|OKmװaR~bF Tr.M5Thڅ y8ԭVZGRkvg~9MP BFbUβ( MdgM` klͻG:~őq9U8 =8cgcGVQt|N TPh0kW ۥFwɍ~꫟[I9몑50-zEsMl͹WdoM2=ǣ"y2|T/:fZQ#g|Lozk]N5[`8xmJ=sؖ&pǚd"! {Fu^}l5 X誦J%^LoiA AC~'|ԼRz*G*0sNGd*@B>JXGoL i./]bw&z̴wƣ6KM0%h2Dfv(Q{E$dɩUU:]/!fLUX;ֶ5tEn PÃn?0QO5 lBeGˎߒdQ$!MN_Vei}J9< mXA|C b6^Vr0+]A}yOT<3=ЌRB+?^jhb9[KHbi3kԝG3%#g,E%Q6hg3@IZ[V ryy?۠)a$[hm @>p@Ն̣(B꥘\J1Uj*iM?>2֨I@LjnB8搕Ȗ]Л8&[,Eߒs@g}- dq iGX UvIvO@T7nh\1$MΝ͵ D;w6(} IhUոiR'=f72߻&|1Xo ea~Dv[٠~ GZGf'#\LVe\lM?3x833F/pR_q"QdWM$`vCON3o@* t$EensלD~btjJv\*wEOE-a/cEa1 C!R Iqr L~"tBM5YbIr—l1_͂d^`f-ۯmv)ەlhZE(N^V#nc,xW 2~@O (!v%Ef?v>\f0Q5Ś |~^:Ee@Ԧ,s(C8jf_zlgLSXqS]hW YIM# ǟJHkcBWL k҄!-.UM[3TɲՒ<ԑFYu/"4-'RyY1%Ti|h9JH|T%wj9z S#duA#*(!Fs< QX›tH#D٨bY# =R h! C@D7/ endstream endobj 55 0 obj <> endobj 56 0 obj <> endobj 57 0 obj <> endobj 58 0 obj <> endobj 59 0 obj <>/F 4/A<>>> endobj 60 0 obj <> stream x  Omo> endstream endobj 61 0 obj <> stream xVfl PET㮲kUu!X#vaY;cx}7B] }.[o=_81=O bTQ*>ᤅre:44T9`|ÙNc(*Hфh תR:5Vk\/oW5K3WL_?ߨWKS Rn_t[_oOO5R!5ȅəsKﭬB[|{i䅑@I J}5}}ꃇ6=Z`hR?՞_=چ.ٯ;מ:?\-(]'[څ.jg緭'qyU*u_~}߷~έFl Zue~y÷G|<լuf*D{aew?@{󍕅D^щ.W5L^]԰{pԉ_:9vjX:_kޛN .ދ@S 5@B jP 5@B jP 5@B jP 5@B jP 5@B jP 5@B jP 5@B jP 5@B jP 5@B jP 5@B jP 5@B jP 5@B jP 5@B jP 5@B jP 5@B jP 5@B jP 5@B jP 5@B jP 5@B jP 5@B jP 5@B jP 5@B jP 5@B jP 5@B jP 5@B jP 5@B jP 5@B jP 5@B jP 5@B jP 5@B jP 5@B jP 5@B jP 5@B jP 5@B jP 5@B jP 5@B jP 5@B jP wwr.LJGWC{quc .c khNW6v^;[+5Ԛ+֟;x{tۃ_i5kP5g>|ܛ'͎7j35C#/qmW{.Ӎo^82T.UC_T=wk6<~t[ϞlXl8ɡXM\m_z իKcr4|BRn|;6ޚ091\ gk8͡cr=\.;-|i'=NZ2N$b}[W| endstream endobj 62 0 obj <> stream x1 Om ?C] endstream endobj 63 0 obj <> stream x}b8/s!!YNN揙%q?<ʣ<ʣ<ʣ<ʣ<ʣ<ʣ<ʣ<ʣ<ʣ<ʣ<ʣ<ʣ<ʣ<ʣ<ʣ|]DR.FZzJ5OB;>/}N%fRXߟRi%;͏Z?moU 5TI-CR'_<}at,n6>Qw/GTHSc%^bW*( GH}-sü4 r]^FW/eX SRb"2 kr@1^yUftZ Y4)-C~UJ&Uy#EFyy ||FyoMa:a IA(HlM*V=[OoQIL!HU^ԡ6~uX,l M7Oө}QzlbMj`hhzh<.дT`2M_/e5ɫKwK_r_LdL|r-V|^`nwv٬WkI&¸kq̅JQme'}޳/,ߥ{k5}4xI\,6p-&5mGm1"UAL[ngR/(3-rm\V^lT=U_oRP]2AqӓLDp.O*&5 /'_LFz?Te_v tS^㒅Qi:jPQ`]Ir> nO!SÙrMbuʊFRo\)ȏFE>-ƞRcuՒlP#ﱌ\Zg0B٧e%rݧ?y٨j6^픮3m7z5u2ETbZ[ ar{_Бmиr?Χa^L9e'˱LTeE5UΕ4AhR|Ф3r=[C;TLWӨ3j+6'q$nS_(JOp] + Ԙ+;LEE&pPHFw˫Ʀz} ݑ޿PiݲYɯ 4L 7}fL۪_>wiqCBbS;*I8' &YwI_imQFJ[V䊗+|%1>8D`\-єTr`؈ko)K$8~M`腭׬1;&aj՚!m(#Ts=-Cl-+I`Kla^ c[[ۍޡMtt*[x;{k#_lս^ArXAjB+WYC9h5n\nv-k϶ۯjWc}祊)ܟ~tVb=VϔnZ݌VUd9u5$n,a񚏤b }:xNY}\O&Ww`PG%<xVm#f&v=V 0'ugp MP'lz)19\iErRi|Wbf1_dnsPUSwϪOs5NM35#cncܮf0V$kYM?&kr +J5_J.Wv:7v.F\`'mMcZ.KoEtps-~R_TŐZ(f5b=ϝ%06lNf1-r`gD,0Ya+pj⭥)S&@ B5>=v.C)}ɆA/9vZZ[MW>kPzYI.W:Ե7]I_|NA}[Wk~n9pkljS~e;"/c%+έfvŷX+KD;mN4Lnw]leA ~4/}6{8y˸>L;v66` ='x!+Owj0N#"w@%+٦\:lR^ȁ yE_-X\\p@RqxeTpo:ήdU%հV+B{U^܃;叻+۠ {߿1mbϟo\NJ6E?~%9(_')8g\E[dRg &T3)ʪ6[0BΥs.EEU"A.)5|A}M*ч?Y3Y^0 ZDfɁLa  Ko?+U6vvtsI;Hۋ*9Ex.'1)՞ďWv6  B9}F^뢔2U-q9-lA?R$V+߅0e8\-@՛`".W%>~ 񇐃=o"i_tGr`틶شol;D:`Qy0fsˊO<Ⱥ:tSr2S,`{jΣ3&kǫ5m۶2_(ٷ<<).OتѿhJLd!uV3flEN+{^C`O5}ik{]`lhZv[;lN~V@~,?}>. r88lsU qXv)7<ϪGtoF2"pfKْu6+5653ocq>u3͉i_>XI7}cY]oqgmޘ\r?tqwК+(#Й %W.# ;zjh~V#oVVR KV]Ey%HpܖޜKQ$@H$HXqPa>9Mص>an7h4N0v;'X:ޓLbvw-~J[\@O vwM^H]4\B9\k2X-pZnRf6k/(ՍLXU Jy[3 sF#CaFCn<%rK7 !H[bbreµ֜0ο6 %vngmϠHNS+25wmfk]d́Y3u>U! SXZ|.d[,yׇNdKwRHw"XЩ T1Й|)k,6 %yw17ܖ=*=p+xUas̽[$L.&nFu-ZT}0 שE#1 i yHX2wx_~Sp}LH[rw?wFBڰ#<$g{4]+x,I )rۙ^';% qǷƧ twET$OOcj@Pߠ\^\,Xfu_/fŕl5Ou0?:J.䠣róA Хٸ>/*_r!.}O'CnNp@zy;wLxTkΛx ad/_~n:c/xTw)u 'RC}=Tf.~f26Om~*_hc<*)e\iʅYá?HjA:km13~Z-\3N (:Φ_9/01(?Bϸ&.JծQdK0p%ǔ`B-sDj'2?8FPHUJw-`i*6!JNLS)†ԹC,wy.Qҥ e5(9q-G׻9~6_ҋ#/E9Jhtj=E^NĠ= x`jeDK"j Ew%*B #QZӋeJ= Rf6'7Ϸޙk:5r+APNz(=q$PO9=E7JDZ{\i[+5ZKeAWօÜ6bIi; XF%[b;-/zTKR^ԧlEOGgo0e/(*3vy[r\ΕLo|t\ GO-Xka:47j$\$&{F ̷77DS:M4^>x\(>WO7~K"_Wv~0`sAzO6~|o\(u-OGY& 42Zr~nko[^VxQRھӋ7r=2Kɦ;PEb摸-oMRn^SUV:˜ivݨTCr`kzc^>v:u +'E-TesFXtd-v:2}|f$I$ͷ:蔺vIN|d[HNLUߙOsHny:'s :%~ բY|t:(OZ: ._ Ey sĦQ_ѝ$v<˾++B||zt $E:ve1ʓ]G.XVNިE?:z5,攆Sm|d[q}7]y8wv`p"0_Qkxk!SRGvp 6^xA_;VD9p- i {sA{JoZwͣ?yAG4KVkgI!Grcnj{TQX!Z|nkE;cQ_o'D ǎ:\z}TWT~5֑ጝk>nɾۢ l(W t6ONaI@ޭS3se[ '̤?h6nZ3EKf׫t'+ )-Tnv% R؊{c m*m}ft|^(uxҺz0j0@ޙY޾eDz/V e'D,R Ps5ZTnIƻK%PZ~WMh&2=I=e0'Ӓ[l3OOyx>)qthc8Q0UdA`nƐUD8f4ɓx{"ʇM^۳V"Uj#OE-5ǨF+DZuXKFNO+Joշ,%Ȝ))  Mz}XbgkDI8b K D#QrF1/ӱa1ƻ%(mv>* fr-lEGk{ľpTSbn7W_lvgM mT}ׂ 7CX]mlE&Dd1lX"`?!W6GG/9/lz9dE1ex#/%"|-Z:8B {Y+왿*Wdj o{NLL@͞,.oI#+1IWʣFd͍29lsCtdΔ&XHW[`ˊ1Bc 62E:+b6jz4F&=*] )gHx }v!$N@ywK2]W"'0Xo֒u9R0e =!O A~B_+Opటf_]TvH(M4ev HCz#\LUOr0($(%/n{jC:] .P3݈ʛ8؀>64{! UB 1/MG+؛@E<@=XWVxHU/:e6+%.:/[@&cF^Ɇx%D@H!ih7Yt6dRl24ك{VZd)$g_*|kS*U:59(j4 . pZX-DUmr<9,Yɖp #LpvH 0ط[;u7\Z(Č8_xX@ KjC%L.DZ>\"͈m qI{ou} kG#!ɾo994l"~O༁w t8^oZ`f}Q߷m1VDtQg?rwfHJf%W@d'ٯLxeB QJHc}0?컗MJݯu>:5sB T3{BEX7kr@LrEv;֘5B7 =ďDKR3^䠒]# Rť?o.5# uT85(v/U18&L h_+wF]ΦpǓ}vSًX2 iW@IuJ\2)9,Ke #1iw2@eg,xW/k:Y%EHIqH>F|#U*Y YAaa+N8ig.U1AʪE>Pjt^Չm Zu/2-l{`n<]cśW\85$=p+(G9o }9Nbө{o:J ֍v(u;^I 1$0Am#K͎j3aph ՗[rݓ 2 @w"b'd1}= 5tH* -.p^ouv&%S4L~qk" \&Эnӳ%.}o30q7n۱}Wc h|GxÞ k(}6@]V6zcd Y' 2~{ h \x:p! U >w`tI3`t6\mH}gPe;EPtlJO v%hQX,2o[I /!tqo28=L1T"nCGZ+hoX,FbmG+^cG4WAnCkgb Y~c򳲯c I Ox\tok4ѹbvmJSqbm3$'R}2v7O/]%`4X!9oXo4s\m&+w8j^Xu!pu.hm v<S=9'6 Y<`Y$I$ 5Zq23QR 0.RmNOrD\RˁJwKVܣˠŒv &cm:$XTM# M}rQrM'͂؀Z Հ& _͸؏B{Bdy;̉:H9"ƦX^ Ñ.n&H7Rt5wBiA!]:gS5b4)+ @ )S6w Ax*\( z5+֬\x(Pq`Ge LP<ΪXI) [ZkJ&SB򻯌f12YH]RU R?\$_HY j)$P$0ٮm-+ciqjZo1VpxۚHd1m@P7;^;u'xnT,O"=V Z_MYmAEbڲ\JU~5~(/빃y2ƫZyBb6sCWFWoOj`Jqd str,lpf :^\'Woi׈Ө[MsW[^SRĂl'D4x~;TTx:~kjOJ&{$<\ܣ<ʣ<ʣ<ʣ<ʣ<;oo$PkgZχEG[6鰱Kk_ӌ0lr.V!Q@Q;ѯo]Ej,q_o &^v[ky?QW/{/V n}_}R!%2{\4>($N_+^ARfIgKР;/]PJԃ$Ћ )B88%=(xL 2.I <ϳG^/ R!QA4*S<1R>CPW,?%65(OR;pX 41Kn4Kj;ÑC R+sq 1ryU`Z;ar4"֑{#l')1ywP<ѕΆ])ݡR|nYQXDS9ƣ‡] np+hdPȕlw-1_Ҥg/&"t*1]iUUWJxs&ΎG l[:5F=V !=Ruע‚OEՔAqEs0 1].'ܴLn_(=Y.2yeA*O? Vv2`s%wRaDYxF@/BlzfF6LeVdB4erӱ`z`9`I;%)x$Lț Q7FM68@7DK%ATm^-(XS wH~1$edeȦ3 + VlHVİw`\lKM3 0^ HutlM ^FnB¢n)-i܉ 9W T: %䔐߫Ȁ$k|9.q1cDϱ&B],1J,̉MJ*(D@gd*I_EHH׍T@@}p["skc9y$$3 E J,NɁo,?V׫8 ˎcHgi W w[y JZڣ@ބz$8*ҺK wkȩԠIo(FdPj7pׁ.cWV)**$1j<@\f.)6!qF1A$ ńώut2B̀1%p"@߄o=ߡeNMpJ {.7'Ax;Ȩ?|A o&%n֗PK;5=[3S~ xI_ gftbpJ z@-P ,{y.q ƍ8L ܶUe 8MO,̑aP𸐊"Ist/r,5!& 2f%/zw$ʶঋB(3+N©pY)ˈGP;-\u=>|n2ae9899湟'v8]TYRNM͋ߢωxb,rO@OΑ@<նr0,r` QXq 9p:̴lNG#J`K% q#ŌE870bo ܈Qy!B}zIcЖAr.;JU9(kڝ)$[k5\ݴg㺶j"ZMI,NZ%$\_I&j}3 4,;-G*jI?>pH" iZW]$3!,p,jI7C<ղd[ei{Њ^'&-]z݌#Ge׉^v`ֱElI 9Us|ZhҥrţAfk !0 ڽBVKXПli>:uȗ孭x8{:eepZ0|ҾfzR۵!C7 3~7JDS3!^dC$/e{}#,sM }wcn5;L*@<+Y*TzL":HUp+5IJw:e0$A JD(vX ETw53Й\)ml.$Q5xo>LLb2jG$˺4Ϗ|L_޳W"&*xsI9.s >#z ^D+ݶ \J:/8{U}w2m@3@_GwK,OxtbvUP8\xzFR R,wx3x3C9-ca=S`HmMB\:=Eu9!ywj#MW}[kR6 hӶ2SJU;əs7Tk+Š,PUpyL$IV (a^ymϧ9Ry'EG7cM_i(e8OlX#qxm]?O6@hؠMV4 և7!w/X21kNq d9֒ym_^lEd=3{,?&ĥnJ娜;~[oE\ӕׄ"nSKKyueΨ4%_!\5!nΦn_ɍw'*>Whz嫷6#Sa&p6o~8ϯTh+ե07֞9@䬼ңT8ή$>ے!_WfuW4i>m0 !@g,[=Mx8#6L QkO3F4•l*!MsY}Q?$cv=n$w EӫSbZ?9TJՈ|E/|qRk/y (q0}ժ0oDg0bZC\ oS}D~]fy|y|CjY저483/S k҆vԐL$"kfƥ#h!;{cQʿ`v" "ݔjռK-ql=ڦK)hў&!x@nԸhUoMo6 oǗ{ mm0aKM+Ӑ_EwN]3tzh/N@-5f\5 r}{2Lô-13?q]v:)g.p=^izo♄~RhYH%V d_HX'\2^;TAIi e-GTǂ爌p, !]Rv6=pZnYƮ+a)5]-U?e_k6[AN?庄)^JTM{~QnXgDV(9#ɢ"2NmrtT1$A'+ fׄ iٷ*z(%c;'lk׶ILnj5蒉[n4Nym38ĆݍQ}2tYGqƋ’'xVBD I)jtH*`9r3ya 9wv~i*>hd7 omY 8IPjI\DkhcS!v j4`= l֯6笙GB:_0j$P(:KXժ14>%QDi])#Ś'*=@= lAӉC 3C SKB1&+EEAQfoi2^<ȉtqt㠠@, cr4`lQ$R`.a3CHE׸;4yC)Ȱ67@ i;Hó*BĔRֈU*L*y"@8se#p8桞ґ&=L8{pː8x&tO9BAjHuɊź@وr4KdCM2]VھܮQmlW* 4 fSԣ6*/fbbRљ f,\,AtⳠgFET]v$) %NPcI襃 W.zIUJSi e% / UյcH]PBTT']@nQeIZWc40^+DXe)CMr )I|Ƶ6FSֺf0_G6 畵48RnSK6 gR/ 7Neq~': ;vJ:Y cܨǀ婊4Ǫ4F~EuZ0CU hI,XT/(jFj1"#AXI娝ȟ lf-3 k6!kE5~ATMRSxm:ʧv@7ewYep[z 4DH;:_sg%X;TD_m$P/QW SRD=ߨ}rC 0hG*P?ᯂ2:DzˆC٢֡ԃZwVņIz#(ZU$z~@n>3.@U9`hDK68RWHu'l! D&a]9tb ;H|ӛW"MTCӰr,e>'< *Rzg,@ eN{V>Qx@UD_͈WjF$6S9>w W]:Gw&Pu{x3o Z,-0$gr(boxؕs;pRW--*EI22^%5P4p Uȟ)AYfvp8:;C9kCrΘ[ JU;H'mL|՚sX?nŸ;t~N&nj4d6-{|`P2HBcl|F0rRͫP4bӒ[ Je^SiKfpsScFrߨpһ+ذpW(*LQœIA >cENO;y>^9xw{u`skPff@6R{OKyF5^lU`%b/$ђF;pP;);jdg8ƗӃg̛/7=R7LvMN #zaTI'8`], V Y;!̀Ϊ:#%BotlCd E`1~R:Y K6ܱԮŖ7m)b^b~GI '=?pқs"q恧|[1@Fc@ A.̥=@^EsrRw72oj1^/$K:|ywdLf%ɲ.%Axk\;aբU]1c+KW+U/@iLo_ όtj 2n$xP%^-:@e$oap̖Ȧ melҸ^ؐx!6'1BG0(㬨f|ܙxd4Y.NUg׵rek`q d KvrOƬ͢9FgIkRw#Y 'ۼl5ڢh66PKU59tI6H] r(ۺ&(U0|${xdE*q%,ۿgj b6F5Dv-ίoMY^ݵC4Zp iP] ب1Wp-ShysB-|3!:9k[3k9od*c=lrښ /pDʪƿeҏkr en>;HQhxsU1:#V⵻ϨwPn._[fz rՌ1 (v^BƒǢvkC8/je VMTeUw ߺĶ1qUiJG#5Osio[d"8Af zFJ$eOixm#8L=1Om7dOj.B$5f-ZڙKjJH "BZ6F)K7U9%Vk΁U\!5 ZR咔wk5}TCm[F /oY/7ΕjRt0_ʯjxy|QGb_K7W}3)d1kM9~xAnz&AzKrYIE>Z^yo-Uxߑ$Ms'[e+ѩ("54g\ҏgix4 5ΏwÇ?I?Ez!7u.˧U_~.nq~MOt%͗߶&#CߋOg,[}ho掭_;~ѕ7fZMWҕ } 7(m~N>86}vkB廯;`EG ,Z{wy.CE6M)'|N?ˁ>=4#2u.?jScjonXcym2A`cS>^y{v{v[Ё)︵< Y$(A*::LSifi&)Lg[#"ԃhZȌ.7o8^絡P,CDUR ~w?.$bl2,U_vr v^Q Pت!-W-&w-{Nem׷u-ZQ+X6( ]n.;)- ČYBgӫ ɾaxdAjxrZNJWc<~4!7&!26kr3HzVox0ԬUߋ73wfbFoq=μ5s?">f6 hN"L3bD$g"2bT APϟR@:qj]Z6d|+;Q{*ؓ,)owl]zn׍'ybi>! "C I(-Vk lam &3Q$e8N)H1+˦V*v+3n7 HFoV|~ j*k B4D(Z1(=Zwcgl/B W- ^0RRvܟɂ\k]Z{k\l`5gᶡ]37E/3mVDogHPZ*AEHh\΍LJhV/BP~v&#Ju FAfS/̓Y!]q ɪz:`af. tAXlg2i :4f@2=e>V2BZ$<3QCps~+ 0#`NR:Q o-dMtOT)cj+gGٰ%de@YT[}BcQ2 PkL ,> |- nΤ!rZCǔ7s'هID(${鿨]j[b* }ĤQ?SEڞLCeڒI=*K~p& Qiխ=#Az*jxpp0` JnTilYVA)1~4!yIEjk,:Cap! 2Dx3T sHKm_TE>LI۲VdaŧwphZ"0l<䘖suWs@`сWJ֩>[G*~.RQ}K5\09 ]uzhchs\- ȋɂq$,@DSbU݉Kg@d yN(0j MCmB8&ɼ@H ZQgnU+ִ()r,Uw0%A4j k 鳃 .AD!;E],&N+{a7F]W%Jj8Sh$bb6&N6Ԯ*BAsvN(-G51QG|-= B镪#٬W-UIQ%QRMb> ZS5b[S5`n+ɇ2𣃜6FZ_tE~d"~ IԙjETYJ}Kg`<1y&몤&&3w,НF /Ҫ*1iTT Bn⃻*CtFuТTiRȦz@0F3;c։woL^id,g=9G5!t-ȑ]g=l '`ըCmʛ2 0h妨,=ԓ9Ն*Uni$u&Oj"&24zT>'^иol~bǏTO.R.Rs:+ ?LǴ! 8?z&~0ԀBy#t>8g}eZ@q;ĝo\ }Ba 1 K5;+ق8g*`/Zp$Y DD@BlZM OF$ j@Z2ۯiC9ٻCNL{V}ݝL;s%cݤ*C>&؁``D>IS!Ys;?J64@kgxd)6 r\Drp5j2@1Z^󆎹Yp@8:BHӎ;7!QDPU2>4 d ;uޯA phbqw &|!|[q6 i VĖgUݦ@XBv4W JS9{f1;l6 4#E.=zE7 bKBtIB#% W6w`])# qw0#g̷7Р)Zy厢 "7E<;e[ K\zu`qٗS2bRیȢE%烣A0qUExqKNdT@3hR.9Z3JxVaɢX D^ ZQG9eMb8WZp׊e>غXfLd\sY`WRցP%0"V0'~*_ot2 eU9bB97fP7 AO^8tLUT֊Q;P~G`1S|&՘41˘۝l5| ZE5^ฮ+x-&2hAp9R!S@>yc?-B;P6W2 ;v𮓈.v;%pˣ[٧T>Cgv73ɥNN*:7v)sqҕ$*]v #s퓃8!i4O_'Uag k$u[G"gp4zw\c|ckvuhځM4a7oV3I ԃd##([3kbu8؁\gEF;d?*vB;=@Vֲ.R.{i>9Y vet;x{8j#e..hv$nԔֹHvmxiYT/Vpgw:KV^"@MHHt6 $ʑ%v p,ud>6'F){oZOpOvQȬt4 Qqű$G8kb|#\&,Ul͗x7ȭ|η>.?dDnau#]ZU;sn+j]Eʸa䤶}VibYj:cNďqF;[{.UŽM=ZOZx(Թ 关B*qeW SfifL_ڬK M i, HD)й_^t&/e8"dA4EԾ2!wC,BD|\TGFc8> "z<2 vRsSǐ%-V}PzHS>|і$b|[s.DdQ˴,n2BEGJ|7:dw\F6W%$_5*ƱE=Uۡי6dGH8fQ#H"e/^wԑϱ!45% b6#bՎtm"!Q* wޘ$~ hɽ|8n9KHRg1W@s O+i/.orzդ:a4i*ǜ:QLɴx=Pk6aT)6)kMeV≻|$F0m58/8}MujiʉãKeU78F+:Gl_Ӈ*-<҇$,,6r2P:K֏1ѰhYiIXpY 01{xRlv` " Pީ9{fztUu 1$=cKdSdy"fv< -LJ7i0͑MjH,z5 Тb$E@[܁] E o  Jn7204%[VZ$Y8 }+. ^ҡr'<7XJu-zRMϡلk~gj,kO/wM7[F f VtϦUb8 Rտu򡺎Y;Jkse)kKYY+UuS.Ϥ$`xt7\v{s  EvSPa*<>!} o\b3|_LEvzYA|\s~U>ewVn^P ZFAUSLA),=[8hHEǤ"ܕ]sם!QuY{pSN|>,܂we7ڻ"rVPO]ؼ$=5~ΎJ+@Fzo^=n1ȻY'N^|exhl=x+?UBw6KnaJ7,ƌ\p.({9$[F!ꪲwA3Pؤjf.TbH>=%i0Cha^4`GI4ZP% \ٮEDB n ܉^1=_ٓu. %FCEjITD,5nuXҤ?wm3-.LϺY=6fhuO{+e)vj Nj)UyCBFN'i]0FP;Wv4=DH_X72wDTdn%"ZQdBEK?}qJTDG!Z%i'TԦBXm)֯ ZM MFGRXP'$fxyIv(&F0H#IWH6-$S&V1 %߫!tw@l3,C~], wHJT\K*7iQ7ٸ` RPi RKx/`eajB"<"|2qay>{?*LXW5egXoKLJ8ɐ %ϜB>XQ †Ka4ЅNCd&2:]8D&4!nZ@5Hʽx?턈3 0(!^z _) ޅUG$ż”ȁ^q ]QˆJ1AZ+]Mɓ*ą_pD #@6 XHnIU qKd]8;}:8#>+ poUu^^ nWzKI`l{@_K<>e; D(My f!;غc!O7)ddeB:}+iJ<C;כ#GNoBAz Cs9z;)!-Щ&v"</]|J'P .,vu4e,VL5g&Uvٗ~U;,u _%VPds+f[Þ-`ܔIқ'2 i&lKXƉU??dPa9q6;)t.֋͝FW:oo6Ә}pNmEIj`^ISfr+8\A\(g'71p`MsNc v B_w£#AIJA[ @Iy)Ϟt̓K/A^vJyAZd]*g7`J"x/Fcla%)ak:no`e$x8Qa[-uQvq B'W`"Hd'ɻ,z+y~Num}8x ?D,ܠ6[v5Ο`C :vK~!/ Rp^gdK-;+lm'%]n窻gֻص:I{! /[b8K63~ OV[ o YnV/Vxa(x[;weISl\7O2s>Ö+xspIyݝa-V<4G=nO2]W*āNM0Y_+R0F5+}Wt%F5/ S!0eNZ,0LS~SJ jxN r8}%Orgƈ;Nz%*t SGhEUL Ddq=S( KOL;hbQ2%Bv!$J:zY_fJ!E i%h(7P_rnLu7h#V'8WZQȨFI7˳,dPHe͒8R_edv}ptv.pkC*HAgej, ;,3q)1  P~%Kf:Pj(!BFr||#D0 nYLff+ 50_q _|I_ DiN k9_zTNeRGiUN'מrTzTEVy\5郏]ө)KdlHž-QO: o ^^^^~:E[˖yUߧ??doT75_ /o(U[ʲ??SۦRƲ\/^mΝ?Zr|[*/g?ϣ>+ko"G}2yvźTYV꛳Tڠ؝h* ov1髒#|:6).?z4Qd?ʎK(#c%B\:ZRs= wFQݳJyLNo@/# k Y媵ټnhuZ77OVH.B~+xMN>\y==ڜ^bA lʓ{8N3?4/ 6p3mt?y

]SYE J%=ŢiH RtDKiyj3Z;:4; l@":>O8 "LJ× d.-YD,;]b{ PK\천yW,ڇϼ^ҼǕ[*a$P_Z12{yoT|[X 31.opfXS 6}u:uZrdQUII~c&$"AD]dsݐ_<>]̙&ш# V} ]CEbn=5/,C鮲 "pS3`8f .QߞzN;6gR<4'wJi a*Sa^nb%1f̯2Ycċ } M@p]`0'Lly9cBuTanqIv t7;/Zf}bԩr7xG ,h[JmY/cArN<+^/Xw&3:Չ-jLf"eZf["rO~DnxqI:2Z#"I_tua]Ye{s?V) +dJG)EnɺvP8Xnvam&]FF6of5FX< n(x(դUy;aL (L捼q9v\2A4eb}-yHVOQ}*g8h 0{lvSGucf>2MRXS!YRCt؃_&r VmDA2Qgg t,:ww[Lʙ*va2!0HjqsGW\ eўŪxMEFfO"xN$"7!3";w?+uiw ?7t{6e&]2Aˢ߂zn]1kY;[r`Ykqf8oil̉.U_(Gêh'mZ4&MQ=]sIs*9ٝe{M A[8tgNI`N`wwZNjf yL`0)iJ$,*Ә"mC# ss?}<"BИ@ېt-ʷ0%g_k4sϨO؉lIx}S}ٻb.6lQQ [8 "Ն`IH2CBVFǾ;B1k0b%3Xe #8wfE2ЯN^hRIC&in$\8ʣƗìJW4G\ٻ=z~3 B W(*Pgu O u}%D(IduӴG7FNJ `hщ^:fBq{ jh8r:lJ:jpVDsnc=Y@BEiZN̝"l1ov;lD&{L:zzU-Ҭ%pBխ": f&CP X`&5 >16TϚv9^b&^`%sMN4us4k 9lΖO:6:'il=x73 X)l⥞S=M/xb\u$dl0XzR$ eg XxᰴE#uwb%mUH29EC"RܜO6FcXUv(Abd]p`nF~qui@hHp[]NCZ PQZ`͇M:fFtmN%;FBJaw@2//%6"rl\+N/U3n/Z)`&e#=SNM( f fjc nlƭ<Ɂ D i G:X5nr\X5 IM5‘l5PʹSUh?;dBn 8nĔb@sgn\Ȍ7fk\Phƭ謉-`Rڙ#:muXi gTebݳMr>.W ocC[2T q NxDK|lpKd\h.U|vm:MsFM>{,1p`.\iv5FBR&`fr}¹ yu(h(V  a@aC+.ZWZ 5yjSCM Kǁ W6V'WR^uҚq܎i8#پpy׎1~盱X䫴1DŽoA\c#Lv`Gaf;cj &u&9QfЈ'@,9̒jE>AqG6t es(+h8FQ۴ڥv4 X!s-)ꓗvOֻ)\Ů}߮Sq'7s_Fi& Z+o8!I>%0l3K7E=!,,*|6 *]T7,<ƾMacƾi% F[Ts"m (S\x߉z[~02rh'` ]S-]ܜ,Ӹxw0V+Jbc8&?V&\аr- iMMƝiom'8x"6m MsL{|ϧi9wvjF^Q6 _rlÉeӠ裉LJؔn<’jY f(=BE߷.U }]}!-wRەepZ';0c?2c \bi[cƋOJi]<= u*>rT !Ohxl||>MҪ2W_V`7] ÞV| 8HwtH1yt?j 坩P+ u}ȗC٣^&һ-p0qx+g$.>cL\ˈӗuOy\}n;(~{O:QwBT ?YR8־Ԣy9ƸF϶r;zլ,g~%)ϙR?.#O0ȳ q~<`G<Ξeø*]Kǽ;?\>\\]??VZ ^+ ǿ9cVڈPߐ;n4g q !랗7R~*|PDcG0޳K<>KO&:pzxM~ 鳯*ھLZr%ƍ>}RO|`6Բ53g+`St{> stream x1 Oi  endstream endobj 65 0 obj <> stream x j\ endstream endobj 66 0 obj <> stream x[mo~X;"@6\}PlQ/-g3dQe)bes3Crg<>_y2Jnsz~,MgŅJ|{#Dz}q#lZ V56r-1,|~"߿>o'ϵ=m+qn6Ϸ~]wǖޘ ۲P' V`7Xbf5TMg$]MI̝-=mp"'?-Od~7vƶlNJ/ƶh6t$ 3t Mej|+jxƶf t8bqyMBfӄmh90e rjYC˖adE&N}yY sg: &6uzL%- 9$*;/; Nd$o\哰ui/'t.}҆.XZ]ږKjۖ'=->r97gltyVk#6\±T~`~?1M5M&&ɿzz?tt;ѐ[!Sر!dU4H~vQ!G3`S@e'*Mg$#n7fxZe=N_{`l%}I}@ߋa*UOjhٓvn2(b];E9 8blۏ.|z<"z l #E-k(/_2r> \ .fx?sm;^DŌF,\8}vp3Npy]99=4K6YFwRZɑ^58ڨZ]莍.YӲ5u A%ҭ M5ۊzAP((\7ՀU $;/br="m'#GpM~Io~(Ѕ"&])83 2݌T?["}y&7OrS(;EbQ %8?'>A%w9TiZvRƐي2(E~%ۮ+Hoy>;`[7TFiEttQLzg΢ Ⱟb_D DX*0FV e"͂0˹aGͪkI+Ww{c׶!DtC]%VLmዲn>*XYjN?U+YZY( d-E޾L=Զ8=y7Mp#U}䡇ۺ <8l wgXjd^%jz2\0&}[Cbl~4||A lazc&l5Ϸd_ 3UTrE7%WX"t|UlXDA{iyQe#SAEeW:Ժ:^S+1x_ r,D[%i׉jcv-|g(Zh3i..5}9WyʐC1_["D<'y(S\c(OPɲr䗯BV<._=Q}+ګgcotSrY큒? p! re8Y_bU9]) JKouFRy4Wbm015+57SIdKsɪ%na&g*svZl.{+9;0~+ﲟ1-"H0aNwddw'X(Vcl_"{=EZUU%cY[W̃ ЃU{bNla S#[q]㟺,W,J&Iz/y,idt0VϸD栵 ]+3څNDb~e7lP$ -*Hⅶ3|7E+n-zsA_I-xDuTkmV$&EHZ"+ _15V\,A5Z7'F9bS,UX4=9vn8pz%L9NhNgWջssnk&%͕,i{2UrBٴB῰4ȕxmˍ59˪8~>u q%PǬ@62v!ĺ̩h>ڧBΠ}AJ}Nx7Dv(7M]HQVC6l&{?),T̅*A<|BpB]=\ڕQ\,ej^ oh1M>wY8&G6cT7Mا9_aO N;A3խ:>)T%ưؙ[/P4ZuKDd|ߊJ2wm)| Wu Gb+T\V|S ?B2QM~VdV\2ۖQu2Tս@I"_y5dӣw"}֞ 䀢q[Mt_YCp|$ qp]ՍB.Ue.FEAq^ʋ(`b>j~=221ʁpcgn`p [] &Qp;1zܴY[߸ ՛gl Z0ru% hQfxCgNdtx? HKGY~SI:?swPT98|37p[+Uԧא^d;( uPD|4;F>PWִ߳m㞠Q6`$1.< uџ;2Fw3Nއmc7n =CȄ#C 2xꦀ W9 xV(ՄB.,|AIX(ۀRp*@-+bh+@Po( "/"SMx,_˻BHXQib&yɖ||U F,*\ X/\I``֭[{0DhbVԄB.L ADXۀH*]q́. Uƅz C"<g Hya2Υ )g0͛CWMx,ꢿá1:1zYT߸ H՛"y+é\4pϜ*?40ц;8{~+'ɎC]X+Vc@AH$+M;s˨jd['@.m0x oDCMx,ꢿ*z,"m@tG| ͹'>֪n'6>@ұ3a#9Nձ|<[Oż$Мi%LVUvAZf6lJK8;-75ଋޖ\ySXpg~˞qIY@o\)4ޓl%zx,TwqF/r>B W)ܴ;O)&=ۯ8㟨V7q[/ɝQfV$U26?s!69|q[|)od|5x'-)NG݃K5{5EOރ%?%.ejo|9/㫀6|19gM~WBKy~I_}T?oA~uc\-Gkm׸]*ٜUx,˥mw ,ϸRf:ƕL74+nc endstream endobj 67 0 obj <> endobj 68 0 obj [ 69 0 R] endobj 69 0 obj <> endobj 70 0 obj <> endobj 71 0 obj <> endobj 72 0 obj <>/F 4/Dest[ 46 0 R/XYZ 69 684 0] /StructParent 16>> endobj 73 0 obj <> stream x[[s6~όNL$Kǣۉ;twhT-*_9 Pw./xhUr>]5?/^Ň⩪jł]awg.n9<{<{YsFA $_>JɞvgB>&/g>OvWo&R~!%w,{]xxnڶL|u"c. dea {4{.=2p0f&A Xzdzr=ؕhnTϓY[¯tzqK'(d0ޱy!;VܡQ$7n}x>`]Ǔe ϊ;C Lޱ0J& OܱGҳoRٜIwl4fC9:$Ɗ$ 6Y|mBĿc\mY.\Bzzts>:h~ZxM$Fo޽a8^v4PD2 l1%ëę| 2E4:Uם"\p$At|a10k@ҞIh  ϓ r)8Ŭ{R9(\O^D I3h國ن}بkV%|`H= 9׏lkRw4=;"4I R%}`TkM8X?h̷BÇäN/;jnP&,Z!m P,MR6]s.g-Z`MCnS-pD~ArC A#jo Cc !ШlUQ;|3|A~(l8S֌/~X=`f5ՀJ\q$ ߡRhbXWKpS4,cw?6]V!PØ0$@H]G.y >URx|M&St:H27,<: *^#9Ftl`~Cvҧ \f3 6t@O^R 4.(ן[ƶ-Z;'IO Xp,pT%!y .^"8}j:ڙ=}_/!@n! (ө >5-=[~\z"Jإ`yp)p. c7 Wy6ͨgi6ܡ ^p\:K5RǏQ5ٴlYu޺]#}J(> Za'qqwݪf0(Dc/s*B\. J]>)7!U2AJ "~5W%_@r'F~'vۧ :Tn0]J-(R͇7WuIqg._;# !ߵ=ܱˍzuq\4 =$b4BxPX7k))XeoA!)Rt{ =v k3ȿ\f{38v`|ȁoZ/$xYvŎu4\R%ʼov2VwN4s0{a P\ R7R|}*XLËUQ/ v퉚{d]I^) =ak a%$4Չ Kx+nIVsۯ|RfztΡI]cG1T_3d$ty"ZcG$#k@`y`_*`WƶU~CY(ZaިE8L R }\v 0 "iEU2D s{[rZUg'fPaq) FCj]ZXu'@>pSBSD*A!(-U FB_k4>E"@0%9jcl^D 1pOyݲb[+MrӬ  Y{*2fz~#n'cTAyj[G+#@5,ȥorݱ<ܘT(yIHZp] 5yVFaAX蒑%۱ta%Fž&&QVv͡G~qrJwN'@'0cQ*z],t cpd/1dWqBĤ҃^Bӻ$hC͌bӹZ69I!"&й"Oj3Q7j#.ݥ{Nog;Thphh n_J ~j>dwMUXAs,aǙ"LOU0#>>#m['䌡ƄŌt٣MX )r<+x/v&#'e,ܠG|ї]C㐝[q!Ǘ=J3;nM`0.4:("NP+tc;ٸ)D$fm#rB!YA8rDl\;xLOC\.d~D{gw̝Y!JA*wk2/)فNLZ> J}<#dalE n5嘪00)Mk>-皎JMt}\,aqzVփq-`J.ĈsYmyO uiLrw쯳W_BP XB N%O>{%!FЊ?!eN1*<6Ҝiؿn endstream endobj 74 0 obj <> endobj 75 0 obj <> endobj 76 0 obj <> endobj 77 0 obj <> endobj 78 0 obj <>/F 4/Dest[ 44 0 R/XYZ 69 406 0] /StructParent 17>> endobj 79 0 obj <> stream xytWs3o{'9~=IwBB:&!!$,I &`@YC6b K` ^m x_&,d7K8󫺪UUI؆T;:[UR}bdCG{ KN7gt^~ L{ig_D̴}>㹗^}/xɃ<l*OӁRND|L@0/<L{}_+O~_&d^-tmTO4&j3jTùʙ3N].} y頮'0N8YM\ _&Ιalmv{{:{6h;!s/quxta0H0he.,\bWqf)0Hdx t :wj{Uxj7-сcwoC<46i_x{2u|xO|qCS+D"*0ɣD<\aakUpT5 `[6 !}P)[~2X{kq>3yvsujppm\ LnLc7oKP[`-{Y.|wdv@Hg_Xr۾n=sFU$k4u-l Iɗ6[8"InmNl@dF0jl6ՍczuCZ+@JSJr#(3&ZO(G @l A @>2P"Kڈ+  ypuu-!*{Q>*BuulsGM18u-2&ESي|0O҄>Bhf 3FL&} 4&=DJHFXZo׳a=1%TM> (1+҂D Xut=y\5BYއ 7笨e+{Y l/Lbw|Wl=0~)G?s!\%s3B{̅LK!ڈͅs sfW&o 8K7P<9M<(u6MvJH+G(M6a>+6a>*җi=!݌1+dKNL_^b1̘t݋+DJ,X Q1>Gz_m{N">vN2$,.2"Q!{<Ź,=yP,0]zJ7Ix&;Td4+'l\f]x&13M6SՏ׏9C~M߭U&Ԑ=%ǁ6+ 5~oUl-269Rk`~%xNmUKmz`>WsŘ}''v d vbiy@N Ϫxm)dףh & [@WpU_v2v^7uݝ =xOQK~24v_gnED'1E#B"BZ#B"B#B:#uG8X鶍.\2}H^ " y1bP녠 AM !~s~`_y qˮַv*oyK5dYZrv~3̜'x8ƫ_['TmqXn)?Gm>7d! uq`{ M:MIM:JxǽXkMGbG5$(ٴiiC8, rBg-09`:qǃ,xP%gi5;4u㲎qy'U,03א1D0 d!7!!1ush fprLj5pؤcyf&_{-GH׫Eڭwu{ uS?n^?}ghҚOvzAϠ%B,G$hnn nn n 8E+ݾ˷]cWgɎ^m^''MgOWW{:*:":J_+6W:\oƈԃ;jC7T+^/Q!j*sEФ $ FFFİy2X𼾘BitBGaAF@I$7Je:iRPk(5'"}T#}5 mNVK&)2{D\ [|19ullFb-'N9B.;n+e]k` X`Z t8Oư< ms/[){ 1s}aK>ێtV\;rIKu == ~'L'Ϟh?O {h%i=j|}ן9?}XsSu@zS|Sx@Ցg0@QN#"z;nݼ}zߤjn[R)nK 6}keBԷt (@?0e}u:D_jEw(Լ+ܼ+ȼ7h90\ mw=$TCVY\#(*TTԔUر?f#O1A޶B\[ߵ~뷒n-h|+ToՉ|1[Ȝ$6[vjቃ;1`)!s  LṀ|2'ɪ;Q& H'W%Ɨ% C2%9b]|ES+K9׏֏\ 8y8) )TzO˯?3qNj{]ϸ5J5Rnf>k? hz|iA{J8ϣ/Q$X 8+LtЭ:X GF؇uf vhik^%5;n"F8%z[ۓב}zh*3uȁvt`W Kv (ilFg]?l>HNW>:}TuÙ#G19|p ppC@;} _Nl; ^^NQ}t^ɑ{{*.?*5q+/0\oMǮw0pMDoK/v{mw͑[#G2U;,oo}Bcq=ANуÜ"1euz-^Fmyl1mygmZx w2RiC r5 m+k2ҲbcSSҊ KJK"}DjNMN%5 >Yy35m;d,j yjd ԙZWkYNI5# vXjhb1<#yAM@9dbBT_Sʅdнച I4,K*jUCHq0cFk8^fiD$&ry}c>oΙju6b5'n'1|{ (嵙`)l>к'eVûНЉ _48(VTUpt9Od8gK-C֌5ԉuNgs sj;;v+ [*5Tz֮yb[k'`H;,#dڥ0ufVhݴuzfWjlյp7JM. =,Po9 ڔUKyf^jI%E>*qtո---^\Pz VvOnn|bOI>'^6z2o-ۼEN]0;{~'z#V  6aԹE Z$z.z\ݎж ףSh";tD98%K$CKUm`o;Q/s9$'Xy.'㕄*@J ._J_LTLqA1_QZPR XD>S?t{e 5h|t/t} F _}\ ,]0 rs 3\ȅY,\"O}1O#?ϓeJBEi *нtQxv]d v29]ڝZ.AlMKN!Ymzrc߸DTl8_մ^HM$D`|rݏ|D⻋Lm?7!0ƪ{Vݣ:x8ل>q:X:qP,_`4!qoe԰$k c<4mzTF3^=KR SY.+ס> q1sBt{)6".~*RK1՞15'NCbA]8;q8[i63G\qn4;)3GY^'d`x|ێ}rcgV6ɗt@^Ɛ[oEOs0 2ؾZzYw%,mY۲5 ׸--Y5| ZXfl"BjU >]fj[z}o|(>X|;R9">~t%UEoe.xߛ{Ȭɺ'@H(ړ+wk[&ѻ~FQ=UNm?>HTi,D q@f~f^6*5$lat9$s9dv\+R&X`tS4xv"Jp= ^T\ ̫R%gK srmZ:<Cs"8!= OS6'z>l*We?lv )6#X:9 L,3?6&[%A ՗ Ty򈜺 5a‹ْbMb1MԒ-)^-)06.7ʉf֘^.<1q`ߚ;_1\@$U:M>OȉgH:B"l^}4'H׵P ڨPBXxtmч }LX@bG0#y`C~K  L-n$udk0,[f8(*Zͬ*C)'q\y8?3~tӍW {Ǥ&KL*|Ȑ[zTiI  zD>zfkr߲`[Ղ-˶ؼz*Ѧ\W7/Wn^ڴLEe&jsw_H->ۮXXv|"ZE \.xws$}vٕ'f'zu-.Ai.u]S[zԷHh^KnvKd{B]'1tlcȒO _ϊtw,&$ÊƊ ˡAAw3OUE z73%QQ} ֩!~l^K1t?ryX(F G]U2׹X/R*e"lrșs>guWc35Q* @ 9hY=g€Ǖ@墋QyK҈lE(9TbÄlpOx{R.ۋ3/G^ȚUaާN^'N8 @b@%Yy[P*sQ ܱIlNg+}t/= @4](''ƻTVD"x>Db Q2ȜR8:_WJ*]jȒ+{ke#U؅ˉ XDuSCKF &}{>vcOJ-zk|W8]QB>KC)22<٠`[`d磑9(BΏ D%0\os=t(P/] G5 O 4Ȝɰ1hѣOr=t7,SgJ8{v= w9ct`څHArrĭCg71f Xb2ތ :(7=rZmK%v3PbxS@Ġtbf s ,4 (sWNw;$u<UFK_lߦqnEw3M=7jؠ]ϔ+v~"W~N5o]蚱5cꚋs\z\#PPO)Y~'6{l>5^{HbS dՆbC7Ct Ν Ed vJUFxƢ}D_ɯw@tpGP\.(ڪ&r`>!~zbi '}j0Ojھl M`g"l> C{ ڣrʘF >ܐ\OhbUl<@'[++'hR p\9BU_zEJhum.YN~9Zmяv{9KpDOMFSO;j䤡p_0ArG/%d;zV )tfP Hg{B!Qt>@>4td w)߁WfV*5#; q6"_ZWm{r2%fHg84% d#fXFT)Zr{yB:a'2c'{\03Jt0ޣepx@I4~e&бdEsȝM%w*5ɳfB^NQARIQ]˭9_$Uv]s۲J ωBb3G|)}|j|h}}435Cpz7PCv{4'#8pC[oG+87_U/>ܚckǖV-y!^֑á-%\O٥Kaߋk9V]loc7,\yURߍ%ۺ}̵nL@:HbRScG2Ά^눀H㏀5 _AL;x'Do置FnEO(7Xfڝ/E< bEmBd8%2L)D8ZiRaH)'jJ |e|".6_WPWj+D|Y_Wn^xi6#xɃ?EĔLu?"2pf$w[̂ޜ//Q%n̰=*6[ƝX+-!2TX"GVCx`+kGhTǰ[ 򱆑(r̂.,@ /'EzXzdxJ3^9w<"az>tb *$ZWZޜ31439뚇 $PPGc}c׵ JJiG?vT?yбWFaqF@3vьs iX3AlaK̔/N }VNv .`-,:G. .fm1-N0_3 "g̃811דdBf0á x`3ffb, `%c#ے[`,dB^}Uw}3}YUYGkɖ̴UY_~U*UJ`\LX{ӥ6,/ɟ~֤d9cǬd;G>8`CG;+$3};؏{}?}ynCq-Ӯ^ ? O{>9zi]OHl‡@sSn=[S}⎗=:qW^\t 헶Xy q'5,`[`L,øЀ E7Ek /ґ<11W1< ؐ]'7~x'~)yʝ/ؓzOUʗybyEkloPB/={ii/9fY~5zyl1{ƑÍXg9[B7&l ? ~%ptKËqEjʁAd:+ [/G5vq2S/' pq-Rz#ZN]!d}v! u953RZ;9gw"mD4-RG `{s;H4EOv=9 ŷxȼwE&={hG ҝKpN0 P47Tf7LVy2^) 8l=|7TbC#!_ۃheƋx{YH%ĥyqq.4^,fgsKK @isekY44N#ONgNfNOds&N?u,|7GC_]<='/;1#^=&|p5zYggCOol]=}?拝^_mG Xٚ|*UǎkwP"K.`;w47h.4]%.zR{M͉gL9Q,/G=4@/.vO}B@zG>: C@&028+TaI-*<7ALa%z|%rե9˳_ϸ_vuptsl!pb9{Ε#DgUSp7&l sr`+@Jm7V)_#Yp&$ee *E&bˊW(W*CVJMc<*z TbrTZoM6> \.pq*)䑡kef~۶_;P7N&"Ԡ|pe L|(x5E,i^D.0F~μ(z5tvϦ0aEz(c#Q/w;Z4gKTgL>dv [?[>[>>ϟ7?o|ɏ}gLJ|kq#pnϯ~ö/m⯶m[mLWmQqTD0׻a5t^ϒ.WfŹ3s'S/Ǐ\OGY0B͎h|]^Cj{޿w^ (,0{홟P3j-Tdh yq!O`5~-9ɇՏދTuц#3LWoWw{ɛfiu 6s@5"X5;3peNJz͑:pt #[ݓ0uR [,zzǐ&Lo\GE ~!hg놘mg9|zsa5tס16Z/6Vy*r{Rj ~:J+[nuPK媋+jz?wcWlvŊD]/k(`[fWw>w3VQ㰰TIFkXZx1_דʇEdyzzٟ3>a'0ד폛Kc N5hP4@waΎȷ3 9~o5rr%tb)x|yϱY9ωEs#5-*x˚ZS}{z &l8’N‚:R@7U@{zuau6hBj/G[K"n, bmڐVCy˖ hNL JB(08X9u. R2l˕hF[LAg24#t)^2DO0O;nRm7YtE$q:lQ7 t. l4?ez^}HK)!n'<(fMߕ; @Γc}ʗ?]dQo)I== &Yh[ ӥ u~0~]aO? K.v␨1NiY?p=|ط]K.#y= cfq3g͏p3jvUW~~{++׶;pۖ-- z'QĊëUwԜ߳vK2.Q@;xѯ (v a5hv9-3Oa!P;p͍C,@[8U?/~("үf5Ƞ'uF)KIR]8gg-q8iϘ"WCV''X^ &(6pՒhS]wWMЫ@@nqtbYj +-B6W\haՠ6pTBhs 6sP  t%§%D J.G,hɞ9&oJvAudI WJf 4g\PB9R]GHvɶ]hë3:."'3XCǑlم=Ѵ%xF4@'DȅdHl Ju!M[a%ؤBI*hF=uK9rLhpq=uxi=shrܙ5Մ,+ >[IսT.hs'Oi\VK߄ #0pѼG)Cg ë1eyմ2O!IF\0c[b@Bt? PIߺg{^rw^zgt  `"')rH/Eo۪jfvYo[ !23@;v>gХ(tF '~rK Ǐ/ՀLvg?j7$L7Oo.c ИCg$gi0m^%YcYg͑3oW|gM!4cSj؅+;p Gpq\]gLj/GlRhEI ]",>ϰq`mɮ\Eѫ/syP|-E+$HBNv- Y! C(Q dHŖXD@* VFJ#8D:C4牜2SH<&Zx0D LPkB Hm%\]WW4D)ZP䏈0Br8 (k򦾎l_.&yIN\}#kAMi'b+`w9˓푀L'L!2qfrXpvI<IH;Ê6'K<8{Qz:zdrs=z\J-#&\u&:ӭ/wt֙[uCrQǨ H{3s|'=*;л+: \F  hD/D/xmU*m5z=mzT3BP _۽cÀU& ELIp=ݤ_5[Or@L_쑼3V3z`T%$VcU.q3n} RsǮ}4x:$+ߓ?%l,Dq:O扟EfU(21xHD1x ))90눟flikuKh.a#=Qwm1N'1xpɡ 9)l T>@mQ+qt8pUMR/0%r:E.2f@e)6t'z"zRA5"DrJ:SF&Bt אMuBv'&Thq!U4ԲJSWjt!|zE",Ā-ՕPyXޜ7?BW휷0CFȟAP vKԢ+&ĉ6N7v5Ng)YOx1%RIUG=pN5Y052ʟ<)VR.ѹEYc:R&}B .m%~ƥֽa7a܄ c3Y=dnn<]qu!SuC'rt\6'jOҽ#&_z;^,z33Ys \f\/5a4B.yqD XÉ^8]b]iWS !<:wWwB!j e`,os O O#f|-Mb 5U(<^yEH/^qɓZt'\¼31٣Ȭ=L_gcegMwt# _ĿtpHD{80f#pe WU3oaST%^z#r v9-0%#x]{ h4E:s!}N#|pe%D `@q)XX%{&5iPɂLq$E^VGHtxVI402X6Yߚ ,$ ȤJ]E/ossghPbgH6eKet"mz')cJB,L] KN<5jAs+`U-XՎѠ߰qn"dGr)Bzi(=C&?Z]رfE]/+9(T?5b=jh}I&)ozOֲ=\ߌ2(Q?3:Cr#m"G}Ƨ>|Cg8syףf )s&=/ 8z +F3H6l+oH~ʿ>P6!P8BpCdypǎU)$ ɵٳ`s酓9eɦX^UH#O;^Tzɠ9"6b CN;x5fU%N, آ+V}9F xœj`Gu|xZutb)4p(N )Rci rk1-H[ `=-D2]C}cp+B@a@ ʑQ-D0˫f{`ad(-@w>h2,m;Wj)Rނa2IQg01t4lMxP {a_0([“z@tO֘$zLGǥ!< Lu~̟ԭr֙!D~gSW^7>Tds|#oɳ{,zDĹY u=Ek_]o[/3};Ǘ cGT'wOO?tO ⡇bc 8dS"F+A 65gBY J_H/V(Eu$$&Q2ehbOә`iØ/-xvї[giznR Ik 5=+ r(l>||JZGh@{$@z#|(Wz,R6͊Kx>SB:m>dHR@@risXw *$i2@,$j#?&L  , IQƿr|stmC2484ާ<{C\owt{w߾So֏^ܲ̕ L6&Pxhun wȑ#j{LQxQ}0\Èb!Z w9[8k e% Z)?i f_A<7U d|7ZJxymW@.1k uWl1$A:,hekk`hmWH I NIN0ף- bACTӝİvB( + @*%uX#ؓ`h!0WG`Mf- 'j.LK`:"/IX)FJBzcXX )~B WX )bȇOʪKMr@Av#U3 8Խ9#? $$˴-ъ:[+JWʦn ȢAī\*TuKt ~Ig;|/Lp57&\lוR1fkE*oFȣ|x x#)K?5֛z[?4g[o~ʛW^z% Ck|b+$]hp=ZzTeGT$ (\b[pg4=Ҷh l#X+b-mE x/ѷTp {A :j8.ۢ$e{ū:U R0cN4f' *ST)Y%.(j,8 e{;ZpQZ[ip׀ 79=k1|YEI'* Bbd'{AbBy)=9L3[ i@糎4C*MτKBJXz%piAL3Vu i#ce"Q*J9=5-c]anƠdhE)$+:*'\I臦?B~C8t\&lWsltU ctF6ycdxHFצJd[g?ߺp/wZz1\/Ay>-7z|Fϸ7W ٿ ^ɺ71y #A5[\w ܓE/xbyw,f]3 w4 |b U e|+^ ~2HVK Pċ=p4bÛ!+^TȓD0tO)V8׉{ ,MN܉ İ\Ʒeg (kLW=R] Xz Zw)9(!Ĵ@|Ɨ@ʴX*V "r4)jrL( 'I 3$[+1bG "&)Ǫ||C b4]2ΥŤgH C["rZ:Fϩ KO^$sRɜRU0jt5uZ^R؟ ɭNNnD *kAnF1έ&Lo$FIe칹SC9K{o?ug[S!h/>^Ph3;P8כ\$_r=HKC[?0k%#"7P nCW@ְdX4J)I&%.F]н cFG߆Ԙ;2?N^rXxY_<R(]fB[(RA&FLY?^삚E?̀𥘭̉y|@Z$k'&J}X^YY h4z$^d՗eo!xJt#n,Ěʓ}8ΞxI(xY5"(cU#+є`d'X15`GLrȶ"6# O3Ide&HWj$}%QTcqYuyK,Y C:,5DDJKakJX%{&و 4h.T}XGCcol%$G6t o3}ċ=Á?<$cd}yՄ  o>#TN+qau 9WHcߜm۞ }:y[hjܭR(ˌ0>3vb|JNzޜzB-Ks>zz<zKhM|ncalF޷gn޾g߿wӵ{7_ou6_wu oaA]ݼmr H#Azdܤ9OZ4'rA g;|ˡP &DޟAu|S(uJ/]kkZVW?MK{bL,K (]iXe7aO$׊:cOUbu@l:H{BϷcf$#m YPԣF,ی皰/,GuD P%$-~N`2 R q T~)> Hb( K[ R X̷X`%x_vrv~zPqQF#a Rb%e3ݲj}Ӯls?˻ ?Et72͢NdJae8I7^J}\ϓ8d^ϙ|M7 >Kw=ϱy(׳]{7m1WR6]|Mڴmצ~ʞMtݞkVҭۡ$߹ vݯ"07_9RH ҃$z\M&me0pJC(^P@  e⹺Phʝt Dr68fbvV& (h0g+#V"m2^>A+T,yF,SkQ+a֡|"MbzT.|@ .V"Ԣ|&?U#jL@Ҙ,JFx.*) j@?@4%ZÏۅHD"jMMˆACN8U6ܑ!iępv ǔvة%%H:ɣWrù4I㫻Q_}d~d$cT=_OFw z6Z/H4\`19~eވC{z:VTd.dݻhC eVZ9>ٽy䓷ܦỻQn"J|^.xV^sÇz;6,h]SSMLmgLmwjSWpM]u;z߮޿{Zg.Ikvbav ԖLAM$>b\=I*-J"S|ȋObj jj Tbr4]X2bB*ҕnZO>A`Y0219z" m5T+J4u2Xjd)ْ&28 @T!"3F2WMd, X%*"1BOK18] HWG$VcAX8L[)R])o)pD=dDWx ;2@ Л+Y zq/*cCp^Qsoa*br;@~ֵe$NfEzUz ?'c0τ jc ͷ컅'6\u7--3Ǿ9ff7?T?{gű?{<=DpEDalny̢$q?Y1]EDXh"((>ouToC J>SK7A Ŭ8$>H#.3L $>6ȣSBGUcrv*wzH "njK!%aLX2(,<1ߤa9`10hs⣂}ޏ fFSk=1l]pncx)y1Tx3!AbEHW | iU7=oaV{f*T]JZ/XtQ;J/b豓QŠ6gX)@d{i |܃ZAIHiYF]B xX >Uͽ*c\ӀP\\)O{JMУ2S:2u xEo8%WOur:4 ѻ+5=K! ϒ/U*2C2-2ԍ>B2RZjP4^L G0dndpC8hFnlG Ʀg}&NX{h{vE4Q 7΋^&"E}0-b=~;%j>GxYr_P'QCPɩ.u=zz *GkvbfifC||ֻ#Q O@` @/"5*r}ɚi)aᱩa7m #QmPX3-EfMN 6!½d$RoAY:Gv)zu uSz!d[)'E[/\ Hh/G]tH}ڎ>֮ͣO>v=M zF1J=o0 tQ;HCS\ñ|̜hD(F0 . +Rچd^X*P MM2}%}- nkS/];w^[ v3ulYqGbu#MbQC({\ iZF6 !jSD, t!&D|qd'V]H6>KџB?}JSs94n{D!~X)n7R5ѭ$*po̝ރ=MMu* ځ -yڥt>uL!-/L8#I> ;ljDh<@F(PA㞊#3RVuVY/ZK)A7'=ƹ0Ncv1LŲ ,)#&#=zS |jύ{tH %}k{8.Y7X ztZ߄#8o.:3@Xv[xw}3s[+%-co&$p p]`gZ;]S)pg^oȯ62ipۣ#)tO{nm*CgpZˊUk*nZyā zSB¬਄ g֤JOI9}Y)(--3̷u)p xlęv4"l@$٥?jS}Zaz5+Wk%e 7ܩ4LNѡ6UzJoU,JY1evG4v`Rkz-_ϻ8O̜nKW Ո!sRuzrBY9GyJo˕hU-Qw-YvS3r[2s KN fMΫ73s6.Er2RaQ42I+SMOoᆪe ?ǕQ+_Y2b}:+ {O)tܜN&ƌl-X& tI_ŗO;{̩7+b[tjU@C/)uuCt8!1Hz)̹E=QIrS.ĥ_}Sb$ N l~,C \$\6EWx@/0 nCw/fyťE׮^` 25I|G2S|ץ3 \a1a腏K GpMN pl# 灚 vG7,9XocٚG *{5Ƨ݈>žTMyXy`k4F ArV A:D ȖyĕA0W%ך%z%w<\g ^8|%2`kB?1{.<"ˇ\6MOp+'dzKu7T^Zxoo !'Ro퐩?.!W `x#Un\Vu+ (1q2q0哏81o '2qp"`%6Rr)Ώ#:~ -5)K˥A җ@%0Mj_BN=ѡ1ZoS,nѣX-:b>YWdJ?t[fVJktwt |#O̅!qY7x/OZ 6kU1[e*\XRUYG7A= "dj$f@[[.Y9 )?27zhU_Ö0Dd2pu. anvAԍ jUZ z0Djƶu)8=f.NIt/P9o1n} y[[A[-A԰fjasT!+9=B,XQf=֊UG8._LqJrDW-z8ìY׳2zWQp_xwѭ|5%LX:ZC  (5|Lj8P^xZ'eO L0]5⥟X-(xWvM2áicƆQU@EPTkd IɊ%Szz>N`dF>)S QI=QPx4|*'&3Q܋SEDxTqJBBX+ڻ˕rImhQkV5 n}r۠C,\8N!~~xބkn5 RTtc.ud(RyDidFt HNb)RpZCmBB)]2yʼnD"u q &$s&Hߺ}/{i VAi>*[Ⱟ (v>_q:" hw@ԣ$&)Q -גC MO"<Wq+qϷ]T?"d o9=znv>I B7;UPT[: @fl^UvՈE~ Q A{Q:YOoVӰA}^oQF@H CFvlg5nR9#sEeh뻈N;#o9cXl>LkcSc6N~/wlTڄq2ǍUQ8vFLz Oz~`z #Wu" 1!q’RDN:''kp/ju@>{+:-ȍ&֤ۻd#s\[rp_\ :p2XbWUm%.\56L Ûl7\j {3&؛{u-AԤ lT.߅Emr"Xv~2{ T:ӊk'uO_*M MO/MUhh/ɛ2]#q8֭p,J}v=>"hj 1#Q(IbcHP˫X»,{\A-$VK8e{Q/~EUz/g~d=f4n#dXO z6do~qa6=u?]8wzy9vBf?>khB&N7qJ͓7OeҴ oPw3L|m~hxz#sscTU/șie"iM&Nț8) *5B f{UlÒe~g8B'փkEf uɔ7OGDGe!ȊUwt˯# ,ObN,)EDk3u_pJPL?f56c'NmF[?('o3^jZ/D-NL5Bག.lLHM: )FsJi38g# w݄2 "lĩJNdX2WC LU+=IݴTCB~`+YRZF<_-^{I3k$ֹB y95#"0xz55K9p͸ ʀӴ%#);**VpxŇ dIQZ9>ůcGFőɒғIBxWF,/ )}&ǭ01CVZS|M51~d;3؛׻ I Qyѐ;N0 HM=;BDD-][1]o<=9ߣ8k p9>zW 8?Yc0m&~_/h}LJ{#A;؂&Nʝț4ySS6GDmOmJ'Oιhͮ׶Nzswě&-3B>E^K;cz){,h딩SQPŔ-:&".6ZX nEl9^|RXـV$*+;7&&fU:{EfH즨 OsA6`t$K+>vBԅS\lbVvWBk4sg|\anúVͅQK&[ HA?#N|H9~\Aƀ72G@fŒp q0ZGIjV~?4CS bdfoJObp1 ':HIHCM EɔWS@'xerB:l^9q~2¦V-1GC~3%nc?X0j/#N4 ݖHQ['Go2u۔i#cwD팜+* r枨D32>'">c̼I37G;=Q3 wGA;#A1;"nAP5kRjRjXn8Z$\'Ͷ@$j JXjJkd՛ 3\ UkE?_2$ը6eEv!Jw>w}䯆cnX?}hѓ6al{&Oڡ ͓`z#k:@~*%{5D{ ^b;$Vyo)p6[_NȀU|viΘnsbL6مYoWmK[eУ~sid#^p^o.$go~qaNoeO"yV~KҴ[l+*Xlwt|A_;_c^7}1o:8-aYD?/: `7Ǽb^5սSg25~O4T/ 0 )p PH?@ +-cq {֭Z&a֬Oژ'#Q[4|=?wX$e-Qt'|K>Kw{B_Z-AdD!d7/='-8;^ԭDxdDκafq@b-t v7 yG!NsF|Er_%vvb, b,{Z7_&WD mlo 3?5fǬ<};=b}p/}rI= LsCb\:rrΦ$_ס-]\ecQ7H[nS.P=Jv}?cNby/aS69G - }' .Xpi+3_Eg6$~]bc'҂̰#iE<oq<fT4T~x3` :pzuJvKJJ̩:(+͜JZ3a=B]rXݳZJr < »b^a.=햹f  L"Y`*[SĤ6 &.j# KfBnɾS H֡Ѷvfz 9y}ғND.rCywONQc0aJg9$Χ=|CD+E9 dys7S6J3I?{)% AϢ6oY\&&<"wgлYRMpQ,Bk#Xmh.+_{N5qe:G/T΄Onn%qoY(<9( |ԺgTd^=zZٿcYwkJd=n {g')Is#杞ޙ)8ᅩ_ҴWb\]Xjg5Kj?WWjs [DZvfU\bp*RS9"kRºsA-+%@vo X.NJ*nH],'_^gw\ "ZژTĜ\ΰgZ Q+xpb0|cN\cmб9I9ԦV-TVOAjG%^[v$W#ӭK[7NH@ |1&OAtJSrūMg_!{Il+KEؤ ڄ Fa-oy$$2Kl sp q5[$S%%C KYA̗)2W2߀4Ԓ24nA&Tz\gi,=*Sѧ{.ۥ󠋧΁*N(;{ę 'N^zN/9y٢E'>ZzN:v`eWX{=K >X@;_ekqw}{ϻ6nٕygʦɛvl۾>wOl]cVY? o^imZޚy7JLeH^V07- ½ A֫pL;@ΈNg&TE|"&*Lw  l,̧ 4y O!?2VB3nNӑeEM3~Ndk?t{fe!=Q=C21UZnݳ:ޫYT^!ma+ZqF3E2M` #Z%/dx:a$py~t*0a#Yd^?Y D1B 7ىB:0-+eYOtRVB3 9WBo$`4h#fkԘەКI0qjZШCoc>~&{; O \Wg[[2N A<ɳhx6^N=?\9fAc=D:31C;V([ge ;k941rY#w0I..]Z0f ?$'\Q2JZz%C4.Jʼ~Y2,F-@[Yľ]a6^N=wVXO4B6ىB:0-+eYOjCRqGq3'İ@{/K ֨ aj941R9Ɲo!uf"-BK#mf{$y /yx& #w;'Ue$.;Po`' l|ag=/V,K ~7sp<'K+Bo9jK4ÄdFU茚9.=Zn9ɾ bA=3gB^' d3t` IEg𒇗m2l 0{~<=%* #Ȫn$֓lm( # Yy /yx& #˳z{uǿKTjoo/:q: 1 ~udyV`G֨nCXYN_`Ț0ȳhxɃP~^UKМksNm_mF ydS9)eCšރ-tN#/9͍dfdkzw**KҐkUIz屌ʒ x&eeg{z Af_gL/8R n˫jO+0^֑Zg$:4>FEu"v24Cل7FgOW֟t~yӕ#N}4̧yYKw(^7xş/ p Tnb?WNN^SFIyp8=@'/ߥ*EաZ~U܍g9}pySN/w{]ʞŗv]UxqWaw?'Ph-.kъ|GB'w%ʵ.L`{G:KW_KF7svtCsXSqjkJGZ]~7=jfEjz5V<{^((aY#حcL9Fǜ :4>̿nCİXi Cls 0w{vNӷHMf;`Bҙz-ewFo6ΪZZk yjAٝ6jsZl>Me2~pWS`.Ip.sZNf8LfDy;xhmZҖ}ex K4~\;sVѮ 'A.eOXP\g0Coo]Zd]a:N\e=N GN;&ybp,j~KEWg Ϣa0saS׎&ﮱ[kfw)ztnUS^Pxj77dtǮ.kΝ?]ǽ9Vz*6،;NP F}-a@A!u% IY` .t6JŘSwWy@ | E m¢pa)_䯿SF Nbp|ao;ٓzkœJҏE`]eM[M7BPEF2QRmϿӎI;︶l]'3)̽3i&ɤ8NLĎ؎ Ņn D ztM&@AwD0 8IȠd}m#-I}Wk=]|^Osl{PGXdה0|?~?qv(ca,O<^*X^ ھW52ݣ`=91dQb5=IkP82- LnjJfF&fx' ;<+X/Zi0rLi'w)數}߶Fma#Ѯ(ysWOw5'΁e{hv1m-YO 6lvKDPlR4.Z`4'E$E7Y/aqFzuǖPPc+ooXPo QD8>e[Ӡ1$7aD7#Z4-Қ;!6їNL/kFn.UY=cW7RRwMYEӯ/}w ag|gt ]G92'hz}}C@yEZH6ziuM:F?iᬷoe)M6hp:f%{FTh^+ѾvWEtҋLVTJzxPl ͬ2ĴNG;X#)#x g=U?g9cqFK-}[FG6"[#zW0M#[r4h lF\#m#ǬQļ+bUEޕ+5& ՗繗.W^ w V`qfhoHcsvE1ߖw"z lr:%볲k:陽z#*jjV|_Z~߫"k֯HWVqj2J֑-q\YI6>4G9[E!3  :Ǧ4OB i(1KB>yp?Y}W }}<{w9sֵ;.Д!eiQl\i𸞩/1E4HI5:$#\?k ,o^=*zMOLW} ͼ6? ɖc|ǯ T[S[ͭ*((`2sғbcc#""Л74˛ʙ[dM}2fRT=#ڸFv ɦC[A~~CҬM D74 ( z8P ᔮ᎘ѮިY˓*ثz%MQ^zWxAotT 8qHg[jп F4CD%]=AȩAoddlrz lr:%s2U N)e9Jk,'N|Ȭ^+O (o1ֺn[bfɶbYv(=_Ml} o@ƶ+ ;o;[x74870LcK-#JEK¥¥0I(f!lIK# 3~E޵%ش_ȶ1(sԒ/#ƸP ZPo=Gy;WA 9l_-grnz2SSS_>ⷩ>=zlllp痗W@萐PooWW7'''G;?hgiipw46˪dh_7_0 8/h$Ь knnY S7&pAI{{{ScS]]]muHjsAvY+WWUZW<0'$쩞$΃az\.3؎, D'|s\{G +5x24:?xx)SeS^;ƆN'GK&FƧ(ˉ[IڬWEfm{-ՕVGCVr|Ǖ؟? `Rc {G9 ",uçp%X|qKˑdsg"rs0dvA ޔ! zA, t zLz8͢ c9 1ݦyʥH`=z(a/WΤ?hV<33 Rϯ-..Ibyt''g={[VCCCjd' 'V-=nXD|vطί}nw-O99^O>~jԬF4556qMD9 -++ޏm~] ٞA_x>\TYěszK،M#aWƘzɣNizttIINjepxlc=CRhQkTl`owAY8/ȺM46t:IM_.1.}|8ޠG)L> TgWEf=-Zi|b5-vSf-1#U֣&z8a! Xϛ8-g`6 f#%ՋI2ݽiOfծo*5 cm zAzzyb?/cE _ $٫十sapp^Ķg=ҌM}q!*;lucy{Vn?U_H,qo]{\m?6ډLTWǯ),(D6#"܁nvq-+**ЛSEdU/zesiYp}'Ϳ Q|'<ɝ*tK6{WԚɩY3֟ WUUWVZPɩ,M)KU$W5q#ZڪڹU?r[߈x5?CtCyR`{GާNNRwwr^Zm뉦 =kDfu|.7&2:,2 g=Nڬ=$蛆̜X{p!1V77?xqփؘ cGUAr]K6kz EYƆN'ТӇc| >xpO80LYe\dd|~\o'{u_dSRQ M&$+P%lXkY@X6DP=d|P8@Rt/& H$OLp5˜Wė^&ziW"zk7sM n/WT)Gyc91{.=@Bs2jᵵ{;d\1cccSSSp}jwСWT7#m9ٗ=(Pl(JD͟Y~GOfsP1GVp!Y9$R69eYƆN'[ /!(?t萡N7UQE=rF|ҒFy$aV6OZJ}/=: DEf=-ZC.z,~xxX"Q;eqf-Q Vz-o 万^0=yD,cGFSว(o ;éґK̜~PS 5ß8TE@p\ yWWwuuMUUeNNn||BLLLHH/ޭ[X,ƠOmK֫Ϳmg}ry^/zH޻ְ_O~lfOU"mzzݨ8ʞF~S+ܓֲ-z)w%]z0C70HqPe?liҘb;FVgBoCpO?9S&x-CoF$ ooHx޶cd-z!撇VAww+oislr z=}D~YcCTVU208@y͟Dg͎*dWF[Ғ`kk6dWIp e:zyx>Y1j1`J_3̜NyM}8  /Oi,nrqQ!z;=ٮp33Ix6>fO[^){Z9ḯm`=^aQz)ΒJy<ôB>^A  =BY~4z,q}qB?= =="tKKkiXFdd`` Ʉ;=`=9zN6Ԁ4'GۊӒBH$S ' g=2ߠUkY뵀"d=r`q9i7y{uɷēSRJEK]i~h0G]o%kM/$mß&fwXO[[|zǎE{.,,T&Y; I8~]R-y5$*Kڪp܁pjNN:ށ}Df={)Ws[e{.gmH ߒ!"HB +S63g5Cڮֺ]egK]mSS֓ykv8[Dz/.o_o%@خXkG9^XB'b;neY_驩,__ӧO'$$ mOlv%Y zl43Eޔd_Ͻn%⤂^/_?NRvKGʊD"/B8??>00PQYf{677@offF!wYM{5_r%.#1JrSYfO6}x'c[uRkn5V"Qy ꯾Wz8mf=upwmNZPWy]=[n!ځtU\brH$ɏ ;|#BYo}U8o?Qnk99gNn WMjݡ|7BtJ pSHNRQ>?8oOR߈_t588~K>Q=)`sD@ b0YbS7𾜻 O][*߶M(PAa)yPmP묷#ݚ0N#w ıjlj'ۮn Te=3w9SqN*m)Y%r|%lqt$"/.>~`p0 CCCCOOԔ k\U<= i |cC82J҉$owc|$)(%%ellw<iQ@a;zi|@d J'=2>r|s!UR`PYo-!NIZC%k%yJ ((4<;Ozq95`1љܨ􊈴rSJCJB➺[{b=Yr|(%v3휾Г0,8B2qrn?ع(g.a:"yjAxߙoFOϿ%:*N47(,,!聬=Y>IMҎ!U.j{ _{5/+?@}UrjOOM%_$wR\~;Dq7ayLoEDSoY'CnbiZCys,^}Z ^DFi a5֛&TuP^2RnʤŽ.tэ//n n ^%ڼiWdRďHϰz2a>_z<QgkBS,&S)H%ZĒpYtm^oaqfIC>zfrpa= Dxҥ( 6h!gl!t[m"x:>S?9漽چ>|k%j.a F[ӁD㙙ȉ+/.>[{gNbqt:Iᬭ;r5 d@T]HY$WYO6.lܲeJqYJ5S% J۶чޖ"{- &4r +LͯoʋECGq=8+p$V(݉[ <{|LNkt+GAm'Y57Y fo墬,y(Kx8$lm?ߟ?_:!|wq[۵K.HwޯߟH$_oMK0r[ҚWy/DŽ=6QiGߴӨ$>DSsƜ7J?n] ,UhO랖!5fUk^YKfY+n0Y/Y^[@͝}M}}ƶ> Nz]ډtp/̐ F;_'-)m<|DI+'Kv}% :M,:kz6Ns]8Iz4t)͈ߚu]^QՇj-M┗UzK~„c*=7J֋˩"y=z%[o<=fz ㍇']cWG01%@iÇ|/#*e)qzMd2YUuٰlB6f%'D b> IkhQw@u8|RV,`04>=O gi}YOVR~ Fʨޟ? /dg9{_`N>6ISXom7=q0KZ v ),H~7Kϫo1.\w M*/zg/~wAQ##^Z\jnqEZByG/ P6)M-L2mz:~ Ӯt.//K$ t-o:ګ`zzȥXo` ##h7Xo3 Q>ӎ8mfCJiG'7*~#|t#) -eY\gJZ~uWM']FP-.{ΚxĴ9jJW߫ւ^^ȬWXߏ[A}꬗ [XD)u㍇)]c֖&LDhF7MXMNĉ8llLސ܏BԪĸ]=P9zDz|?M?f{u_dbW3~qizvi+֋άd7lq};+\4*=c+8~I+=X"F{+Ĕ.| 1* 3{g/`s˛wK' ľ9 ^Y W5gT}W*@,i P4 j[LF'z'g=iW۾_z7Cd&0 4QKLrnC.E}~ۯGkFFF2zyjQ2:iҀ"##'(Ƭ3־63~IE_w>m+տ2 &_BΆԲi7dp1Rկo;z&۲qh~35XOI\oOgڔEyG2kLK+`G3gХk %'C<3MZ˦ld7dӶ$ !ՠ:4CufOʊ}i]}a_6= &o3!*e]`,1/v _ML+<14)Ğt6˅;|C6gEs=wza)% YDgUAZe*O/d[Sc{ dt NYomV@w΁kJ'&4x˻/UXQ,31K⑙1D 򧥴4҅t sg˚!vܓ!s@qL^[68%ʒ8 [)_|xu3A}FCĒq|> #qzYZ9t;SSSaAGʸ[ESwRd}u>W`5G+˙_~9._ ?.rwl;yY,327 땥/P*ĢJ\_ݬ"Bb@cviGTo@[D?ТYOAMNĉP6 g.MXɦ"nxՠ22j^ꍨҊ+K{u_D^+YMƥI2J֋L\^͋WW'VGD ]cS_tůz܇g➺|,hfD$W3uvYWףoٚѾ ?u9T $^!c?//,Aٛ(8ֶo鏇qi/Hd߾vL0^zv73y׼jƳӘmv/vMQlllٍqd#es%RBQo)%P+3JE|_D~ z \OLG[^xXНE:pS9=W3qz<䷏f#555,-70ذz㼯6뻊/Ud|^'Q}=\^ZxʏE#3۱exnSc?~1 O?w{6k6/U~b}{+\}qS յ+8E8p:s  Eh;kQX_m\O0G9]=WJ+{ˉD,%E~ѷn`y+ KV#p_v?uW!lIkU%ý}hS ӥ.9Ohpʔhc cw[|]Aju] z6Ut3e.o󖽹ݫKzT #꾞3#zTy0}NKoopW8".킄y;ɜ<.^y|ӧ>qksc7p:ߏuǀ􍎎GlڴiѢEqz7kl'3~Lq奅s=cp;޹}siw/>%Ƿ}RNs?za>{{|h]8͹e~E^{uԬq֞o%>˻ޜNzuWsot-z'm\Ghx|z0n2A(k0FYdxFT\ 0 Y_a=)].yV!^{M37Nj}2Ρ8G=m}z:ƫ{gϿ={Lp=^~7?;Zyrǟ\y[{d[[W~C+|k\X RQӼm%}V/|87`]]]}}=ԝ"4]f`y$p;$_ f߾P (۫b?a\o2[T^V-;0&G~?}?P?ܵдG3>>/(p|px/:3_{aڛW:ZsKǮUMα z'.T=I>o hz 1lfFU\=9|\|md&ylg!,cm?P065,kc<೯KjF nέj-w{/Zw{Y޲E/nrPSSCӴ:RA⠂2cU@MV3wI ݓ^$Ƹ4GCDs=sqЋY|.?.ι>yO#b:~E ?d=_zhԟw7&現s?X/̛qK/D]v~/\E?x/?եu?tyo(頗뙲TףW ^Ai f]\z}0g8#oe EDa[Ú^6z7a"iX7\Y͘).3u|x _\$ۗKn-&YM*!,cmݗ?8|k`sijإQo_SXq\us8j໒ z*ܪlI/ydu鿽IkV<ǖr,&Y_UV" ڝEzA"F'GIюt#?3+]X\D[~!t(3>,(F#P8J^ :\|sj<5_x,?qϦώ7_[w Kc ݻp:?(jy8Յ /;ׯ]lêM}s={|W۷o/>_ >}?x껻ﮣ?[~ z3ji7ڹMU}\/Ɨ/rHćZ Φ& zAG&pU X V󳂷@sgxX{i0 `.' Z__x>@kjj|>˗ VTT1;P?9:z mg.V.!p\?4Rt| ,ɠK0qViq=h0rє&Hm qY\OE"%%̖ ,%63K쉐Db+9ɥ3)qD8'怷\OQ#!F"Ûz gzkف0+ BXYK%zg/ps=oy[Zbz N\7^1|;9=T,Ƒ]ؗ0[&Nl\,'Bm,[8QwD[r 9WRQ#!FEh9XAD—AP4Ie,5RWjX\By+²\O*F܎^h_/ +R\dKRr`,f+rbO$Xp Rܰ#yN|(J3@DIe,`} WWړ4\ϱ=$+ -`7pt\Ҹkh-*bu$IE'Bm,[8Qqᴮ;?p=`@!7$sh.rK2.; \)ձ-Z7pkshIe;Fqe{k`ptŽxa!@m דA"[s^+PI)5AVpJJMbbNԝA V//(DgNqxIe,5w2,|wpE[p8 X{ZrR">ӹ:$TRoMЭNVIU,>SlcI9C"G1갹IFO3Kg^N\#0O=^f V4Z'M.tpC"Z ^)SxR]-ne5Dχ焁znx1:!XaUXpjΠ_V,&L$i茹҆"zWj:Yt{5rU@QzJ=pf4MeV.7I93ib WEfgKQ]nfx#Z)jĀ\z9>`s7=}K2=L/os=w=bֳW$ߝިetvvf ŋ gUBtci4`{a%4k KoG賑Yֆrv Ső72&ő1[/.k,Pr1G]:[^Gs<=r G#9I|&Lsw}׮={wPW @qZzuGdQPؑAiM7u]uJ}$g8ܧ +boPMG vOi_p{0!'` pHG;鶹5fqպ?>}+82c"2kiNf;u)ں/7h\<84n>Ƣ'Jz'-8&OW&D-"E=]bb|W?J+W/9RQT=iviMM@BWŋ/:XcqU`tW6=PN,pc 3v3 ެg>Q].ә۔k q󍏯D=l'ޭ{ZtAM aW Q5ZTr5?ܸ`#?=ѥ{#<_eZ(g@*`,P)Do@NC L25MgUQo!NA0= fP (r9NIko< ~˫OÓ+UP"^(C¸Kvl; `b*Cɛ5o-V[xz>s4Nd dLdVeW}e7MI#3[ \lRcq+q =0H9lƆEY3E?cpSNuq;Ú>}S:f9ுP1(]2"Zt@DMzN&!|Lt3PchAU!!=].١nͶϏ5L5&Him}]-n|vNcFƠ/14P^H]ʅGLǸe0[Y+Hȕ;ξ}",{m]=l?̈́KJ FWg'; v̮2 }7?\8*3;&+pU)UQo!jY<\@fHC^--[/bG]:kBJ]¬_ֈ!q~a 8xݹV1Ԏ hH #/;&GmJjaӼWuvVb\nsƞuw\o,7je3jw:qt!̗T7U]ᯖˆ9׃4Evi@<oE/.- ֘J; DϹpDMR@ڝ;E 8=s&濲M|Shq93Xuk:2ntGh MY 4t#R BiC/4'|D Or9^UʭY㌬t.ݲHyB^rԪZ6Jß%dW]59Cg顮yD28|]wMw]?REd3h9_ VZkYzo'&.7H>}aV ~"*-h0]o 3vdBq| >TU_uI Vo-ːOyR.DhAF^:&(C#:t_rqXeS/?dqNp 0U]C"K;Hу ,2pbh  9G%Yƪ%ynRP/Wq{.|z3Kcko_ B5cvpu\56f!oքTIw㵧z[ݮjΦ@ߧg` 0n>. r6[3w9 2n˔0\z."D8KqNs,Zh"3{쨤I]8cT7b,Kܝ`xW;SQB,˄(s=]z&rTAF>*[_txv,ʋ7'zD6r=DSQ9/mԵ \.U5r0"wz|@p ZjB7tmTΤJ[."\{SLrnd_҄*y*Gai7q:7q`@ݬ]> zcO|{&}bbuiE#zg^B)m85Ś=tYԵ*lTZݢJuzY<#=t \ܾv Hh-O}h)}sBQӾY&N{ӦM۲eZf _thPcEҍ(Ϋ,$xUdYڦ\DiL٥ >5!qWL\OJAT )JO3G[vzD6ˌD3ݻ(:'R~۹]nI r\iAnaz= \o4pZMݴ+ t/F\Ҧ=]ǎ/ wNͩ!h{˦YSu I^e#KbѤ?sަ~~GwMpfu\ UòY ,2==XA̸$Y$==GԚsw֎pjw]ˌ$$*aЎΜluj(Ҳ&_ 1ѥT~}&%,Y_x$0Խ١unUudLZK䆺3WG|À7A@&)#HFľŗ}L ^w`y}GFCGj[X0xcGmM',%W*ܙtwϞ)Hy.J>sjԩϘ)Gl[}u5xSCpvYH_Hl;#eОQY:|Ob%xf>y˹Åi;]ft0Zr;h+k7ŚF K [yUm4a%Pʇ~w qH0B5;jř#-/< يU:^#sgjpPWK+&S%'g?8$f͚qw_' ߥ+z+8 @}(aE% k_0MuJkB/2[ʨ4lLn;M XBe%݉R4"E|WYk:MH𲃮w!1xyxcpʆN@Ucgecgzct{AF-/UoA/I,#zgϞZXƍo|O&]rRYUub@r5ŗ`]p751:TT7pUqm;_t15{7nnTs]=}wҵ n@]nqK2.;f \VuSFMsw`$:,n n<]n3m t&$ ѐ]˗'0o78F$xRqr}=&K:3,V(u[ڕޒEjzi t'"pqzO&-KU4xFZ:U\jڠT=X`Qwz@dWUq}G֬iph:֌lαw\+erB,I:-ɹ옥3p=fV]k3<2xSaFFKd0@aBE7;Gv)bv7қU꣡aA73^rZ fHE2x/^h_OaP^ >k]W}nñ ah7SNP9dtrtm,%'8T6;:zF t0u\ .[{7ce 'D*)xNo?2 *5݂Tڌ\/cY+ z4h)kzLQ!OQvаRtG%z'N0J3/dLzKeY̺!78 hd1<zc=~Lzn,Q, PLsrd1ܼ-߸a:3]JJ u3VpJJMbj,%:C4{8TTW@7|J.{La(E?+B+؊LQ4 ^IFڥ"BQ;lϮ>s1c\#zף'EJJTBTO;,*ÂbN+2DS.v3ƕ!$JFWCe`&*uNjlg;:gHFTAqpϸTrX0_ ~sG :$rַ&:ܲ)5g"΢̳65(J erj4P Ί9(#LiUB PMΝ(H=~qŠR"Uxjȹ4d;m{jhrv \O5=kz#0 LoE\30TrÃ&27M6̬S3ŰEeIu- i6U2;X s sSO;'ŧvn|Mn,r:4sG :$TRoMЭNVIU,>STJ9\Z=wlnrE-jD-JƼE& ACCdy'b?өK3םx3=v/zmA)$Hgy;J17QTDž * / "z1RvXk.r3ƣW^vM1@Wx-|~_ #}@`(<-r=d, ;MrcIIUcPRV 'r+joYVCUP\kU^15QV&~s >*\zmgo_@Mc ]$`k97 /ޞ 7SRF鼺Ո3mw*VoIY0 ɻޜwb\o(8pW۷g{Aw:Mr6l !j,pW 2ϰJR\KK U?]}.Ojڔ;!5*ɹ)ii"+t2 9ʇAdQ__lWǥ]=/^u Vz?!Ky]Bhe4.=$ѭe': %&*S5ޒ׫k9ȹp\g M^e6*{ XyG2=[co ,rl!ٝ"]Ά!{"$TņCУwCb\Z6y?^%LK ӕ\IS ՁUl[h䇂Sr&qFE""*Gi t*2 Mrz'ї:^K֗.Cqf us ¬dHj|uN ]irx+B֣%] zC{ _lwkh(tMlla= ImJtg{jL.;CٹxzMDFpUZ]g%׻VA.| 8\\=@o "'r_5"]ΆA{"$X۸M ™DrӉr2:dD"G^:MάǬ1[]n:qDz[).tMllaoOm,RRA2Y:#WՒrtWvAHM7>>sr6l퉐TeC9C:HƑ7Kg6W9D\#z;ܼQހVJwΙ|u5"]Ά{"$lcjΐjqep0ݓr= z;Ns\o09~|ellacIX683Zdytf^g0G8L)vɃkb#E` DH*Ʋ!՜!k$țs^qD<\ qX).fkb#E` DH*Ʋ!՜!k$ț3p+U͟?=)G*A#70R`B_5"]Ά>{"$lcjΐjqqOt8dYieU˛o&Vqn,r$K|Lx4[R4$!p- N`yB`~[/>3 +9jdoq$O!,mWed?D\@'l## Yނ tO8z~1мS(dZRR tA_G:rС DO%(Mz.;mܼeq>c~n0euq :=$`TFT1k[<$dNCXջ,=ľsy=EV9nGD\o1~!xZ&n5D3q~z[C\[6>dʖ=KQ# E8 568pYn<QJd6l9~yC'eW!JۂLpqC2Lޓ#WY7d*8R+f!$ꓫò'eOBfOf!VCي& tejbίE"d\Lty6ULyѬdȒK沔}󤤼E{ϱ\P8čU̾ 4EPSUrPq@ạb*3jwE[ d_H.+`a= ;܂Ҫ (cA]w嘆`n$DY62n&)8N]ERHc%J­9~C}!ZPIrɊ:|);DbϏj_TsULyE_rCGH8Gf[[׫hv=q/+q=^o߀'VsRwi4ل́ޢȣjw N| Nl#w E_ N:HӘ)m`\evS5a%63. l"r=qC2Le.G-]B2kbZ- 0P2Y^&' T v9ޘ-<ykSx.^ p\#z[q=y۝huv?޶sזm;ز v lg.uɊwmhE2Le+?{dEu/;nVY u=ԕ JԠx%HQDy2 #PpWxffAdݫWޏ{=kcիg{kn*Ԯ" '+64keH6,b]eH1+CpӛxH^b˳dr,_EwzО{.3DoFz:n8 n:HԊbI m<Թ2ƎN/Ϥ,8fVYmº7/s!7XvAqy>Pj tDU.US 4p#]Cp!Ov+v׮" '+68_̾pyBk#%z󧨕A \TQ* fU$b{KFyzºoky.oy}Kd3DoFzM׻xCI]BzBc1#/HYROY̳e&Ƃ_[u.Q7X.S)^KƬHA]]ˆ-ܧjpm62bَ.-P/g'*گv׮OVO\=!Ů g$(VX巺gQ j f&IĒ6>龖NK7{Վzݷ-]9)\WO $r9𱤳QBH,J vWKHG*1,s!z >ʸ^;wD㹭$44n TTpdo*[BH}άJ;cSir%Plެ sB}PO^ޮVܹ#΋xNBs! NXTZe-XIY> {}^|.uV¾xNB\BH,Pi[:ʳzn Iw{u[P,\ҽ˒7oڼ#  ތ@UN\^bM9=8pOEg>G\  HizG5׳tzz ;zLӧ/=0G>AA)<]O %z)vs~R%O朔߰u/91'VUO>44 o_~0KnAA9G/XҽKW{]N<8LF*?#WGO~|d!K\Vk>f'?  Tz_"=vgk\wzӗ~bs=-\ϊ>۴q6"1q Ä͘9+AADz/LkA~O<5?>vj=\3ӳ»؊<'W]{ׅܽHL=~F޽ձgW~AA Α<3|⩡qCC]0g^\Zֺyȱȱ=. ?!^Wkz y\  HWx ~z;3uOv=Kɡ}dO=m|)9Zb]{?ן79~JY  J YZٹu{3Eon^9DOOw~p|K[[,Ŀ"1qʴ3/ >=♽_  Epff;^8̖;1ezYԙsk?'͗:::o~-/Ŀ{\?/0oaݽO{?q=  "uo.ܲp=i2N*OD|WsML?^_o #  R9{8\onzD8u܊5>ߚ#yǧNi-6AAQʑMP<&\bb;ĕ-fAAD)Gzz_ߺtڏ?ۓzAAaDn}\W!t "AAD)G1\OWqk'bAAQ!-Yr=Cd׃Jc~ȮgzYW`m:KAAAŴi\'zg4 v6\ z   ҎװasIы'xH4_D"+TV~ EИ#' pLˉs'/\|ZvF.8с ) z@1H;^lz"hNT׻t%2W۵[o4h:)ߴtp=H4i'G[Rtu.97cY[ĢGWǷkPk_^LߧσsvgYy4P$aCceA8*_Xzz0wY}ǿs=;(_j*s(_l^z=L'^lzq{.^V=ȟ4PxF|z%Ns^Lu23:)g1@>J\*~}Ͻ~z^ы~'y_IpFņ-T4PzP)DgQ\O)zALrno F:PAИCR(8\3 bg\ Л 9/nK:4Pz^zX'}XG"@y9/I> Nu`ыc ^K)8Kc~ Oo:s) X~f0n؈) ͵;o]yK.^lnrK'δydnT]4+E^yyBcvpXއQIptJ s2 jK\ O]/=(5hʀyT׻7iMDXQrO܎$@)S~9@6^|ο“j׋z%=H"k̹@1r.￿#SN6GDճY3p~i}P}i}iaK7bo>7Mspq޷LLθ^@ݟf6wS_Wcmza]OL@Ƽ<]8O&4fܓO=-Ryd h,`NGxϒ^fG\6֑ǨLWMq,ݾG;fIkK|yD%~O^5D p=yY~Og!o|0я>~s/N ]>Yu/ Vk# =ЎދzG-U͐:UVZH'<ඥZ(MϽegcg 6tlക"8\9qu22ybI}YP78)\ʈy⿹ Gow&z"hNT׻\R9@ډzղmƒ#l@?Ig3%O:s'a׫]Uգ\oJuDu}fIe{Lܷc~!y3Wm:Lt%rUbhE*Ǚs\%;*Q Q,T]M.R9Ēz"Þf9nCn!sk]lp=ig*ۡ]Os%w/]=}re"9q#V&΃ئ,pg]cѽ\(m"%=pul zW]/S)]Udmhv=[$]u iTe71J]㕎D-'j\=¸0z2p={f`z!ez;f3)|GL9#jSgzd DMeIG-vPjyU@?+cp,7~*T)\2g9!~֓XRq(i#yjj[011Ǹzzz[WJ3?>׻`VM4Yq='D+4_;2ʖ|M)P)kw*Z9YjZݧ@T5[Ž}eY,@+[6]3GB8:\2z;LS3ܸaT Gom{݂>p]O"ʸ^9~_9}v=pIZ6zp:VO]/[bck3e J(?(e\<z|Jt\/m'AQ\OQ0`GGճzyX{݂>g^gcX\'"qCed"}z6cNW~]h,'KO:̔H>w@]OQg)U_דfzR2/輫 $mf+pɧ^>xW: ʧz|3ﳢGZ[~#BS罥Q^YZ0Toǧ%vr+iz&] ^ O cp2D?6>GO r7Ƹ+_OY2 rr=|2LrYx#U{ܩWWIӒ@;RgB2_.zKz’猬bMrM({s&pzgpPy݃s\xVŠsr#R"@1H;^lz"hNda) Du{#^p3P@zAAArSE^yQ 9@)C2 z@1H;^lz"hseҡ&|6J:hNRwrLy^="%Y]nH;,LTb/;Ӷ+jD3n57hfl9Z{2,[_KG^gCȧ)KY=jh]؅e_Š$SÍj$,TPs;aVą^,' r@I,o; ;f*n^mQ&*KqL4-+ s|koD%9>)kh+DN~^>9vK=bvE\琅DE91QYr9Az>iT$:"eI.l_>K:XfiGvN ruEd]WGiwzSu\oPxs}oct37]_W'uZ- '̆ymYbHҡ 5:' 9?nFd\{Q"Y,'/EO{t'/WZa WwggTLGds1s^Ma,b*(YRT0u̺:JVd̫D]$-X=g/|p&Rʋ0W4[K_ v"^u/ysf wn1&Dk3!]W7D@Kvzwƻvq=ǒrT69\6r:p=$\OY%_~;E%zK:eHy(3Ta'O]4i'qziČwbu z[pz"hs) 4p@AADD]aq_KzxAԫyBcvzg/ \/-=(hs) z@1H;+֬ u{ \x]UU}k@ 9r δ8zRp)˧mg-킳pUU=NnL5JuuakTWQ][;XJ<%4٠oƎawئzf6ڗ2QΕ%,>K&=seiHy2v=k'To+uSVH; T :5껉7zY\wѓVg:S=#5}ށ=yѩXRhnzp~'C׫|W`m\nqIy.iS~=K`\~CxrGڊ\Rzô\Zs_Ȏx8S*΀s5aSfV1.]y8p=뙃zkMLmnpuEwnɮgE# 86@iѻƖR8/sg50gOt'=1sՓ!UeLY;vUMO8Ro:Bڪ\ѕvG_0 :[c+^RQM "l!K~}Psô̻V*TfOU*\ $z]z;կOR;XJ\lד, ӑ;kL:(]ϻz2dw=-D[C_Ts/{v2ս騥YV;ESv”4hys^Dq=H+3< vtO&}'i}ZzNCt>$3ӝ|؈!vtI.yqt 9z0E5`"/ #S:L?S=?2^r.2[.ʧ ztz&@IzNSO\Gv<Ls{*I﬇?`=13ͅcORN ( B<a}7Л( % o.L/ѓUzSﲝVVW&ߑԫ+~KéܻY.%ɮG]^Yû]tSz2ALӱ׃H;ޓßA=]za~_/[qČx #u;,/;GxpC Y" PjL 99r|$-^yLso fĥ'.,C $g{~V ;8r9-\ҙ<~+dVщ@ {2\ Y;ڍzB-~~iI?{QɯW.WnBqK҅Y(65c x7qC Z%sZNwvɼt8g,ѻD)3>kxѴle{Kc56-z1BoRs}Q읺iޝ;w t]֎/\qXǣG2\Oiމ^~W_-\/Ν'7AT0!=9)wu=CY%s`.gn?ӵ4]olsoڋ#ڽ~-kIcpEOW$޴hzfT6 M&ZKh<+mWָޅ&\m[_tԅg>tyȨ7=L\\~$zyŜ7]oh0! -]ϲW%sw=f1'lNs@ebs8-kԡb _|ؑش|xA/o_oo}zY׍kRnkگvNOӄ⭝{qybsO^:zW;v|yqT&w%'c-ռ|yo PyaB X'ZHﻌ빲$zҼJivcmg}3_WSJ!M5v7?L@ø޴}#y/?܂!2`{QD*H'vh7!uz b߻9Òm){c{sz='(j=!zF\j&blƷ鉇VzX 6a„^xy=jjjFm,,2VKd/m`oиu}qO<+'30g̙9tvLeN7=F .(.A%D5Qc"V"R RUPV;;{-@Zc19ww}U*D|!MZ]4v481)yO~ 0CNW==崞c{sZWتcF c1̖N<}wߠM? Dܕ~'ooR-R*U,_d `0 ƚB7˿;UCHi'#cPy}J;Fыvh=ܢ9d[srrz it;39su+k|u VȺsJ>33;t`3k{.h7xl>w˝j=YqF:щ(ˠ9t>/XIazHT(J_d `0 ƚB7oUŋp;v!hwqqECRo`H%5j$ۢHQzs]>FV֖Z93i977w8O]k9[ah~^Qœ٧+3k{2T3hgO./P|`M|RțGR%8迴b0 `)t~sڏn6ݸÇ1z0/3g<h$MT999-Gvԏv⭕9pݖQ |-rQԤy2"0„_dh7xḽ3N|sZ'Ò&ԳYYdsaFQ}c>e`?M":_ g3E<Nh=@ `05n* ЃXzށa^}Aj^7z'O"!22:{5žJ6EFzx/U_,ɮ u$|y~rtbjf|yϝ?y󄳫;= 3DtOtAcSG5^>;u .>z>swVjez|[σD1B>+ h^UwRsj :{ΜEπjf/)8Xi+`0 XSow?Ξ=;=d|r xyy *G!z]\\ۻAsh3gPzbil"AGѧt;gy,!r,veڐC1兯^Pyǝ]ܜ,` \#@!n]njͭ1W.<|dC{998kj?UV uzr7ಅ{آyŽY\x收a,Kh:~>?>~7^0_'8i=@ `05n/tNOnj<Ƚ Öt__h'OR95$|ttɛڪ%rSfkk([|S5vԏv̥ %Z;f_"4V.= -+3kK} -h7xl-x/enփ\֫Ifdy)g}knDs.Y_Y0 4:l%W,ݎz>W&ES( ֻWj`0 |S=d#cB_'kum$׻7,ONMkUdY HMhРQ?ZHtԈ&ȟiEY7M#,MqIe FVf06׆ʽށa zj525xYsK7Wʄ5zǒ:C}zj*W Pq/w{vc%7)N}v>"<>ƞO,@P{ `0k -?C5ܼw􀛛[G@kgoS[ڀAAXFg'ztB֖J6++EЎ+j=ݎKBl=kB;^&-xG_tv / `cEPCYqnwعj^IE!}TE ֛V) QB4Bp6D@ `05nYjq6ޞ={` {5ZO#ܖnl"y~gI[ؔ,AGw2fuICiH^6Wʪ~x.}> +X%_]AZ"9y `0k -?d̓:RT V Q !%hA;¦ʽ覞lXq/ EvdG 8?=G֤hnXq 03x3x fn5ӮV Bʷ(_ `0/-?tKJ5xTޤ$4iYtǡ ~-$3?$+ŕ`` ~GOyZ/bPQU{.f `0 Ka-l*K5pJ5to3Ҏea; ~-'>9n0ﲯ_TpFjlPZY`0 RX"}1qPygTJN⍝%SWЂanoTAN20KB\WiZ/qڡ*<*k3`0 㥰ty~ ~! >4W_xv(,KLA `0 xq2sYG~/O_}j(v] c0^N Yjo3ͻ6c~--a氉>wǬy>i|jϑӶ.ׂ#9$vpNk[0L6mط'.͝<-bCqes`ޭbj~ɞm>eafi馭7m3!iٶ6f򯻬>n+1w|~ 'Rc8Ozf-&Mlf=MlvX.La;99 i}FaƘa ޭ)0. ,X lponmWgu!)4ک7 ÛfçtwiwxV Us>nmFC<[el@nnաo,콅`06Χlx!çƶ.2&ʭ\ah9^Uc/CѰR)2i[Զ*ЂSU =mc SMOfZ2^#Zggz&qõAqK,n2vwO{, ƾiyD]U7p] 4i[YmKHPT ō(Q/ dUr[XAIH}ׄ !Lb}6Ns>^1)kWJ^CHhk ^U 5}5M}"n5tUХRV!m(@eVֵÉxh(6mP27U7^̰3xr =U5^quVl+u9I;f[)D٨*c2n_uKbHҦ뤮sTڮm T7i+TZnq Þ,Q>y `0 \^'yT}縤}Db IM!2+uxn`ģ:m`$.Py=z|ocK.Up)"﫰 !9|y>p"Ċ;i"I5)'̆S lzTz$b ;-4%(ly@Q]>_5cf"pV7"L&Z3k3%Rp/Sr7/Nfbol5+ṗC]Ss),竐AY2.f~)'N!$1urȯFCqe}EylY@nb۱E o ;%~e+'WC2Ґ IpzMPZu`^bٝآ">|r=Nʜ97xJ+流2Bs"႖GA嘊$d`j<`*RE\9OZYRu?? ("$.'zlu>񥾉77n/nY9!NTy3VVrX9yN^i*e\`lYtIOTagX~kpnS@ >/NZT-8$!$n金Уm=1 dUe9`0 ƫlI2qCEŽɢk%Ȑ/hK<]~ɍ;o[cwޯnNW"S rdBs/h]7VǴFq-In Co kiDKN#Qpns,aȼyWS ZakK'::Ⱥ:94!A3p i/ T7 4-DM_ =(⋯-'/3q⼑K GD6vDW5{*jl0`0 ֋]J-zAri[67o Ȫ"'Oj$ S3 C`e[Obֵ.>>;<63< BCfp+A1 A j3:zA.-sy[C~`05>&L!%f06l| 0NcsK//\:urdmc0 卟'Q 8\;x{ouZ>5=ºWEHYj v|Kg6\]b<ϴo/0ĺw~I{%_{EE=wL B?YRb.m O>15cwY=~ endstream endobj 80 0 obj <> stream x\_o8/GQ4Yp ,$ڒaf}˛R2)p(T2 3r~l^w/*?-]e<"򲸸`?\woߜpƹKv g>,nˮ?]s<ߗUUo2dTx\䅉Ֆ/"v7:.TBEE3A쉤5t&&4,r: &쪄otM%|ē'\Zmlz"ׯvۏζVlb&}q5u-fלBzI{${\:)B%-Zq #EsXQly<7!DJǖ5x\[%^m3r**e9Z3KOgħ`;>'oؔIRw⍤SL>Ccf[-<'d-OW?028Qmp^.39yZaw|JKs[勶 pp=~d Gz6Kaeԏs W?Tp Q91vl^"춊=CŹ,s8-Qq)qm4b;ߏ6I.Iag]x-4 SwsywwFƱI׵uQ|'KW0nН`|>ºA8w1w0~ Sx7~}u g~#}†%r;"D&7NX_\t}d j7N$C{ \B5  wLQzq5 Cbd#rPyefe4KaUOY.ŒO,rbZn\$ m*Q#PMZC zbc ykf?8~e?s0B]0@`M2j?'m1jU)X(@7`t[*{A]D-2ңr}~=}QnWqz's*wal–0d{Ijn8$d6asvA/pbϷpo ]c%O~emQ2]mPqLVS^B `gPyTaic*mUBLf_MS4Ky4<cߺ/N '/:HPDžk?՞$'5=W/mu|FLSPj"eCTH~ ? L,XLJ2Ւȑ%8w[Ǡ8FpaC["@ۚ96ƛr>wXUs-IEnz(,BSP}_Sz7[K<^ڃz IE/sI{]0WЗ8> nD^"^嬃M tqSZ@z[}6l}D5#Mh [yb qq.A1Hw~ATU^[=jMpbjD *17kFtaGw}; q=rEu(DqN exs*bֆpCQ$8Yub|y=nz#1>jlAN*S<ٰzwǟGڂPՖ;A,m?mh%jep Ǵ"mUFVL(TT(Cx)9Ĝ)9 9f: pDD4.M njǓo8\^B~{MYnHy-:&@@nτLL.$~ JG[~p]]C#FaC^^R/R=6įENqc~M .1[#u &%Z W%GNUvtDY@h`cT 2紳 ap{9Z%읧:_()PRO0 0ApQ6yN>ZIkbUZ_3!P}tݼ9B]L>Nz%{exV.Yq/MΎI]G<+})ux$ ְ_vp' ^6Q)Up4%\d? ,;"mojb… q%!aj; 4^c؂iԲ”ʷnW]ەYnu_z'IW5E缩P)*]*8of _xRsX֧{+ DZ6VRk PHi2Gs0$D8<Ch]WZSMvB6]rL֞D=v7tA 2ù4|=eCUMZ\Q dH] UkIKIJ/~:vh ⴟiHhɶڕ #c*ka Ř Ţ_;K?ıX=q,VW:|4L~gUYQF¦$O {# [=y+9 Ns^EdE`:3:HtfpٙA –Ho ~CI*PzQlpil[gZ{fVXv}2GW<R馻Oőꍩ|]mުb5 <6)oqDӑ8܁Eټ> stream x[n۸/w$(Yi6:E8Pl%֖[6FgfHJd:e 9ynrֲӓ7m[9=Y=~rT\uS9;co/W'qF qa',Kdf Odׯ"~ׯn',||DCJ" )}ٻmWǬzRIj&12w(Dnfu'hıo@|:8jIUn8jtVMZ=pq[BFWD<3o$]vj& ŀufOR0.wL|0$^aڑ)틋{Oqt6gP훆<>5 찾IywU(S%Hl tƒc91răl"OrC\CBoO>&F<5޲ 8xc$fYTEܹqW c80"'0[ ,e8 0 g"2f_ǡ(Jҳ<3O$x$|3qMX5O$Vwjgɩjؖ&ּtHSk>^ j`#D\;9 D0\m/] ~|c XA)\+h^W&-8ݿN]߂ O^,ؼ<-=8-d(RƢVk4mFM Q$'w \:.KX<<̛ 3^w;&;,[T0UZ<- E& ӭvd'QI‘G3"3'Yf N>NZ]֋M[|D._nF" DPStW_=` `V-ʜ Pgj=QT(L-_W ~R%ސad',74`#%lE!S>֪y[5-J}7${_]^GV +)':Ș܁'(`dlMla''] 4 fEi;*n?"xep! О&iy]S.li+04lQʡ;OT36@$h#V#Aa"hivS9ՙnN( m W8ܹR[Z<: جhr-0|{(8x ~'1&u8CQUw@}H?!g lY.E?|"SA $bè IIxBPlwUgr %vTա ݾ-gOY$QRGB̦F%cBL S=nZ )\ .rzT츮߁:] /x3<׾<"ǵ6 rR h*/[`YU[mq[ b,u`OchދC)vr^BK[GdgG##beSLPgec>^cKs9RmC^a^VA:zcFea uQG|&]B[zG{ '2*QY8HE>EK3j@z&/_ N8wE?bKaKݫJ9[o7՞@ 8'"飅xSx$͈%~BL_ ~=LU~J_ڙȤY:;$`E='3 ;SBx>3^ØA6Y+/#~d&isOۻl 5֖vn3Hu:iC\ >t*/./0>9,i]+kޫ޹NhBʾNhJrX2_DT s,]N:!tOb]QSS"Uƅn fBs*0.LU(bM;ս["i".vHC_WiCAHez? znRfIʃ"/c{H#lS-? C~!t77EGPё-|-$u"*6^$sY]*jPaOEԥ@575#*~Wc=q;~sWVgrAÄe:Yi!>i!̐.4fN(wwXim+p5.5 XK:-{TׁÀ@gxv-ab7gB}9{l olwײ{VwnVJ2콠擙Y7nq:Nlx{J%mQ+[[a?cmoA`ϖ=ڻ7=lκYzQlW8|)`|z4b_>q,W몙ܐZܰ[zIsMw_bPqQ4.%"C8YF:Xs/+K]0'::|GJ]i;є moى׀m;8EǟHݡ@dz/o9}xGimwQ3!jAfP;vCeKrWYQ³>Zsfn6FݰtNugѨeD꾼[3U}1nRUҩ[}ù6d;8HqrW.{D1vp#1+(Mp.#<to]须- %ݖ='w[Х1Bʮ˽<]gnFZ)XW+1ן¡WuF^.5 ߵSyAS$,u!.$N~lG{ 6" Η} 5>5WRLgStzt >&}{5a]SYfA) ˮL]ڃ1tA&li| 8uhbsU{nj,ˆ5 ,k]?<@&l7b|wdy{ȕ.9"Gr ${GvihV;EuU~Pq:iYl;yhHԸxkKKPK]p:dx64$RL(V%\J RաjX^e#0B7{Y< @1޼;3\-N@{t;~@fNZ ZRfh Ȣ _xh`:f25W_X8ƛ(D`e> stream xVYoJ~G?G2xWdS+ޢ>8 3O꿼M ξ|3qeWOplm6[sxNpVldvUlF#\d S'W@1)f& ]k ~â^fy=~eܮ$1HR.oa}RX[c)Sx30h3. LgA{4p9!f2TPy(Wp`#O(d[/Q1ӡMԧɕ\$n~*&Zra@av1򱉴czfMZjt/l{9bI%":-:6-% jӌi4 !S7|Vx|2 K6=:-BU{L:4@M0g"IpMǡ26B4: F7_.Gay$ k,BX6)Tcw׻vnG4&ik0&/a~ SUHMP0GfzU4h҂Mι c*FsG1nGd4U3A;V\\FP ̴1(QTXsPXUXX2c¢뷹to@Pfec#nq.qK`63}p(7J ۬IDm,$)B[p72uvvYC[Ԭ~gH]~F:H8K9~e(pgh.{$3ry5 N3q:xb3;qıMTӸfY$ njE~m7qmNңZ:.+\壀Z6zs \2HW]q~|EQړYv;zF\rp猔MKw{> endobj 84 0 obj [ 85 0 R] endobj 85 0 obj <> endobj 86 0 obj <> endobj 87 0 obj <> endobj 88 0 obj <>/F 4/A<>/StructParent 21>> endobj 89 0 obj <> endobj 90 0 obj <> endobj 91 0 obj <> endobj 92 0 obj <> endobj 93 0 obj <> endobj 94 0 obj <> endobj 95 0 obj <> endobj 96 0 obj <> endobj 97 0 obj <) /Parent 92 0 R/First 98 0 R/Last 99 0 R/Count -2/Dest[ 39 0 R/XYZ 69 601 0] /Prev 96 0 R>> endobj 98 0 obj <> endobj 99 0 obj <> endobj 100 0 obj <> endobj 101 0 obj <> endobj 108 0 obj <> stream x\Kcrf ?! a-M䍥]ccgFf`5wWUny2sL =g\$'fdj'y\i&V<~"S $x?L~2I|L`TCvc-os_8G1. ><,n{Jr#x: ODs8gq 5$Ipd?Obg DNΓ8:á.s2Q0pu4򬣁z9΁Fp40sXh`Da40sNn1OX.N''40y h`J49Ks40 40}B 4@3bA &2s!g.l5% Hg0&NO Q`1D#D > #Cp*\ag)1s8pΑf"mD\e`YdvS)3D8:B1Ngh8h)bWN IkC48dxTp;!4W_` Bh)Q  [Z"O>AK 0 M4F@Fb)2 =A2쐄̰CZ/ -DҔ?A &9gDMr΁TbΉQ`LY)5 V`rqRÀ&LDNZ̞b23 r CŁr$S|-2s@o``d.k4)7[ci.ˬB!g":ofّ3$3]2e0!#aQFLdv&EF̊CzB!l)Z3SB C8Ag`gXlْ#&Ro(""ʍ5a5 a(#Cs+04*Њ9J!d),%URGeaF,R4RLum)c-9TR;K+PbY#lK%gD#rfųK5EBΉ.YXnY+ɕd Xie{` hYkj Ke*7"H tm#} lSkˎ!S?- ;8Xn_PeXf/W MLNaJb07V~ Ǖa)rDD9OI2b!(1ߑekaJ&∃XX! \֍%q)q}>"r<şn?={śۛo~M7?,|_rAY#2Doq)A?r շwDu4JgϨ]׆K/<:Cfp\/^{<|o`jlCUX2Oօ՟kvUJ897D1-2D1-2D1)=qHm},_CuNxݘ ?|V%8>.61aN G=xUnQ|֋Y_ɖ_&='m佒,W{"-셋9PxqmxqWE5wşŋW6^nk/~^|/ψxƋߍt_/~^B/a7^%(^B/~/^䪼/a^b/{"gy7t//rU /ᗸ/rwC/Qx rUލ /UnKT6^n\w%RWKrwc/IxrUM/zv,.^%^w%K+xgy7u///eby[lOz˖na떭nQjI%ܚbjHUUO@-:/꛵޷ƫm";BFQ!#Di(-$0a@aPa`apaaaa!Cؐ|1 † aC!Cؐ!l6dvvv aaaaaaaBc^J-}UDnH??"* TZwgxzr+dyX)bNa?#ʂWAu+hl,ѬcZ|1Lo~f41ї7v4Km@BcieOj0Rk }4Ah ]4zK@SI/uM&Y]qM&i嗞 4.d076:_5aVJ x5*8+\VV#GR mNw[ή1/Ӷх dzB͠Pj6P;(44uc*QcZ'Qvk{\q)f)6Os^yE7kv¨+YVV=^G{wQz**M#ˑݴaڹb>[hyд![P3nqBeChA)S gujTU;uDq(z13]khi\@bӈT?C= 9y=bw&+m]Z@z_ڤ,{Adma'oZt/ ڪ~k >ݺy9ˊ:Gcjm8wQv^U([Cn3ԍvߕrEYm z/+}zU|f} 9뻟Yg}># TD}`3O;E;(?K./WC姍R"OD6N(?S='"$VXD[eDu)|\}=IC:OKT9Q$;տUYԗ:o|<]Wju]>;.|~տVkտVjկ+U(U]-?z|KrUM9j ógoVKʺ}<ܗۥ䃟j`\ß_{{WWeL:/Ԓ?|rOwݿo1(ן~廷P/Ӓa}pg߳?}o^.r0[U[wT]RLi.,;w6p(tɧ>`Ntܞ<1__0?ܛx| [{)b.KVi}Z~I{lkkF-gǀƅ6VV[jWmMN6VR[Lj3GmM ޯGz֮GOnjS_|:V|Nm˶|:YO\S7.ފ;U.4v {=xQB @_?׏s|YNSk\kzDa]j0QƪRBĵЪOVlZxZUXm^X[ D endstream endobj 368 0 obj <> endobj 369 0 obj <> stream x}M0 m"H9CM{z 0Irȿ=~J3=mwD'q]2\}‧%Poٞ1ICvs!YE=,^&OpOIw{w?>:nYRUc(4g)=Oǐ6fڡشwd:\U[K:^J oWAWI5_W/?P*'&̔G j RXalJ y+ԊHLH ӜW0mJ"m6L5ضQdhKfI(Lz%6ÒmݍbR`XW?o+V"gM }ؠCjw Hal|}S8&Q1f(B endstream endobj 370 0 obj <> stream x{xTU9NKf&3̤M0$!!B E2QBKHBKHhBAĮAl`kd bA]]]۪bMĀ>>ON=)s7d`1EfLA%-/)7{9L)="z?c2fPV^c_3لk9ƯL jwL977 OGyESʬ;n&6+EW|T cyE%/nZRG}f_E36q,YCEs`D>cɊ>lǀXm=XW57g2vAҦhК>,weӊI>'чu\5k{ m [ݭt363LVY5fmcaI&&ҾO6='7vmQE6)X7ȑ>zogL&쬀-dqv_T].&BtFT)6(:Uѽ˔0TeZcL{̏/]/oKv5l٧쎣f;_ؤlgƣ^gw|~ k- ]1~M-};I՟7*[膱Wm<~߳eq'z 5毱3pT?\C ~2_zKy~tVkPbNxwںlP]rkـsX;ԟSO;IGں d}]z]$ q ~o +`gKRm?O&|N^L]@ ,~ԟSO?ԟSO?ԟSOgA EEJf:!yY H6Ul2jX[ZFvky==ZVfylOaըĖ>SP|{PSG=/xK"9Tv:y jPmS嘋ŲDƱ2V*,q۸'4g>/:~ |O's?'wER/' xzrL=~~VPTfOY_F?Ώ>'a3{~:I#{ Zϛ;gvC}]jiSTN4qBEyYi@Ǝ=hDnLF^**!cHM8H}M04140U]'mԪy@E P@oMnecy}e>o'o^izu~-cE&=-Kʼ!-U uK} 屎h3*k& 3YmCjfySKhFU]y;=^R4d.cfۼy_KӜڄFjy{Y!Gn(WA"0++Yeu xHiyۿaЧG["C&bP.50B/=]e[g-@&^f(JWPl%}Q7F~OXں;(~3roH7.h^"iaV[ A"s-\MRᆪP5P,ӚD!i*(/7E_ݎa^Bz1P|)eQn\sp_naxJ>{(].] s;,fn4yZ/ \|%cQ`Ҳ≖q7pH 5t(RE҉tJ0$wdL̐O_vzDCb@9e}xT#8ȍ$DYfb¦$b7fx| }>:17kV*괧Y%G娼r!bQJ+rj Z7;InUִ};6'5m+YWËg@qhчoRKn[kufFqXV+kK):욆vƼgօ6wdn/^{ͪ0WdDOȘƶj:͠;9l&i㬹S!]td h68n˽-l_X/6ǣ/q8R|:b} KBf_ {1 ngR{TssZS[P}:._9&4X_OrgE*#qeIb,= CUTuj,bZOFpS{3,"$sd5[w5߉}Ҡ#)"ŇR| RYxWwx[oJR.kR*A)~/+R,KR( R" UrP}=wџ$zr z=0 Z8a&Ud=+D/DU^$z=G,3Ti$D zj>JG=Le=HOjG{C;_ g:BDwEt'DnQ/Be7Dt# D#:kk+ 2jp).!h'^.". :Yx3lBO77?.ny u= \K (+s<?cx c;^ v<[öL`7v:v3#iM'W0z38z@.Ncg;zݝX*9+=#D^9 ڦxMݷ*f9l.kdM [–3rr+QEG-%* l;?k"9QZ˯c񳁝6&9r]Y6dla'ɜNՔdNgg੝fb^ζscS]].aa]\ɮ:zf]îŚerD fjl#/40[[0w1L7~j'D(j =c;/x뽷߳cTA{2;14+ó# S(m؈¡iꔖqs]exf>-JJb젱ٙcSѠM%*xHuŧƚLTM}̑/1ߗS5S^mRtCgZb1f:so2:,est>R\.k*9ۢwϮ2z>bS|9|,E4D YLZEy(3>%q@/uf[}^>ZYqqqQs:F9 CCx\zx,5]Q}#99SuLܞdEVux5:Ηi&YҼct'wŻctt?ec9Ƥ&y{I!+VWeE@'Χz6qhŋ](wyr'*yrLzfBxz7jEت-,XיsrC3ZV|X[x4 =KQTgΗ>?1lDa:9M!s܏R=EӛWO+!''l;~9]E JG$M˜#cJ|q tytfyj7NͯP=z O3uc=E)#gM=u}v)lLn+?^&JCyKg~p6wDĖ>xH28c- 6LSļŲYҤ-Ϟ?撗O.:mҫ:3t3|kٌ>{bl3']{W_s\ށXgJ\TVAVl: GvXec2[H-NqbĉĜb1D6nX9,|Mrd$GVLr7? cܝߡU"}qPD;jI,gtϴǟyWW3t{([>|'U13ufNHΊ<ѬȨ"Ί:+2Ny1Nn X~?~C* a]sWaZ1b~9+?Yt1Rݤv*LV^KM8tQnF&ĺcM4[Sv&ۍCL6#j-t";.2ȼ"üXSYZSdٻT%2F*8;;ȷZ=#MN4a@\ f1hw܎V^.1Ȍt3(`>KdRȤ,IY"D&e3%!,VYh8 Ѩc+,Np( ĉ݁O(|/V [Kn9%p;(qҏKanfs 6)u3LdԵ*I4)S5A%,I2QuoHuD1H-ge85߱Xw,;7g}>55WGDkȹT2PCIzg?H)[U22٨WT^$_g`&+nmesX,xX#jzJ$M\4Wd&L\"3qﳳ([F6-/x^.}bVbEuHȑ/Wu=xtG9R"Ԑ}77kXN((OLLXiC,hfŚk6ZhfŃ;$Rƈ*sb qH] %Y`oaD4^u\AaqLq ";j/k!/CIJH3)ٕ݅t9J3湗xg$Fz~9OZasYzn;FUW{7̰$gޜ60-z;;fsF-V g:#tjL*94&.8n U*vVTo%N}y?]Aadɐ,_|g&*+:29su/OQILĚS<>:u!}')kDlN;j󘉗L 957-kbJ1US9XM6Nug"0eVDiEVjZ$I>iC͒xNV;K }_s9z?ho>;yѫ&|{ɚ}Ykes b^r?t̟u]~3o궕nV{mM=$_ a:2 "1D! Hp -V>%Uʩ⋙̑ɣw LӼUeJb?;UШO߹aGT\z8U&sKWL3fܼk"CtʱژPrʹ,_ɜQakcL]e3 /ăC(l!fDzZ4sUG;crN~FzƔ FC13pL96cLbeAԆ#.qY3>J^ wh +ߪt]EE}$[ݶek%"566}c'p<<&$|o ƛ D码I Y!$SuoK-'|T{o-N:TҰfF"Uf# 'SL%G}t:Ѯy"沧q ##MRקMf%FBKs&Xlgb NhDd_(QLded_/wPtsoV-˛\&X m3FmEM${]1Τ77x߰Uܸ`(,񰿾~ASeum {,+yv *-YU=k6 Q"](lj2u ǜ8pbQ$,&L8TM}zxF_Yx9Q8L\웼6ނd0Ehvia'‚@L7;6a@d3)n?W ?c2W̥P5J遼99sX1!bS#41fDf;jQ[ 5$W*!'~ji\SS6xҶ+P1 s7sE9~:9ߠy9U0 V7VjZ^"WEY]UWϦ|7`mJoݰYa֚J2oβj|iI;X3{, ؼ25huvͯ ) %Ko]rUJ_<0p%~*&T Cuu/n9dLO$4)ҐcL a q| OD;|Ů dj"&x֟[c+5[$I=ԟl??t{Fw޻ ճu'>e'f)=ϧi-_N[4uӄGRQ\4M$QdX^h vmv"zt>=aSQqM@;Ojgae۳PM"Q5m:s"fvLq^#c0d2`_\vfd 5(Φri+erkPԠ aAJ_p}/2mɸkUz=k(mZK9t ar/(k}Ei\lzvFk:`ߛVꌎUj]1/SUz0$G/u18јӥ9嵦:5ͣ>U-'ffEe57>mkKPe(Y}{W5EIfW֯l+w-Lvwo;Á7/.)pepcdBV45o]ZY^QjQt̺&Z?%!pSS;f-h&0q\Kp&ؓZe_ `Qa"j_Ew#2E'uWcVb|蒫OSCAV\wY{EHPʽ]!ON[@Koؽog!nO/GBLYf95vz$ݩ14 _`K'"_8)]LjP[Y2Gㅝ,DA q 45&8 ػr;\XhA_KSu8Q+2,mf+aW+fb\= u"QU(&>ޞ?_ 8 gz;rct B/w] { ݞB`e›-&ꢂ# g-W ?ŻeD0S"ɡ 7(}2Zb͍6"مQO{zXzl ,=B'&mw(*4&u9Oډ0>~'18'x`'FXN +6vƟZ07ui3K<rȪA_H 6SWͥԄ?*!atT2ruGxtd9|>[đX-sW{{pgXX6t! K<{5u3퉹ËfۧiK1ٹZi,iXexh#HPy yEi!92WrܖlO5m(KtcN0\1|)P` E ٵN$!~WN;Zb6`4 Vܫ\dTOtBiS:cf* 75J#DhaT{ D7Ìd7P^1Yo#]#mX5\:v8UEk@RTy6XjZTR"fbrV9#zU ֢ 7x̹&LKjɁ9mԷ"y^UUuXXU\nCf(V7C$NVXL1"A1"A1EvEL:WW 8JZi5(П{i{{'5d~,q2X3aXRM]W?^.p $]BSkWy[Ey\Y_nZ`29DžE}K]ŸBJ/Om;~:kބ1GNt=f5R1y\Y8RCLp$47#A!"A Ar0kӻiD1D"D) /!ݤ*@z"Iu0~=19=@zvTr/fX&;Yq?r9lú vrg&'ϿGNq]n\@̯e &ZnCoBfAfEb'ע2 hG8q'X؄qS)Io5\FW1%6-\flvafJ\(nmbu{Q{\B)ڝmחT̃\W@dTj8\Շևh8٘ͱ<H.~Z\qcf0Oo<+P62# s`ydXyAaCd &!Ƽ#dK˸sWfG'W9H$>KFMe xǸK \ DZFޙ03aSdTLʊD;٣j ↔$c5c,rSY{Vs XvW^L" ؝؀`A8ȍRWP$3B̃7ۭ$~jpΨ u䴆)ϖ ,}Zt dp‡t㨵%Kr{fypc;SsR0u%7Ī]G 95}j; |9Lͺ*oPbt F<ǘD'#.{\xs7p]p[y`1& zٓ(N!z$Qw^k$0zl1jCI lQ;BHik =G71!uaGߟ= #3If=,n'CV#27d:c_׋`i1ب|%8_S|~ҙ 6:00v D xWe2f^g̟5>ɗ J=&T} @o#2>ir#Q^zx;tVt=ve&w뉸LjJ=:-6_P ȞV>_d4OPj45JL+Hw~`1$}3  Kɵt,R3àڽDGg3؄\Gؓ3% &ݟ(\jPz;ec])|] Mpj3o7ZXn؊0vb^= Š 3WOy3Fb}E v3Lϩ(#"碓jr'ZY'aG[=H梮tU1XoLѺ{&Xe>[9c^J ~sO{c㗿3g 6d٭W4X%km[mm ^Әo(]Oqo.TΧ#?H>pċ#,R ebU}F B<& LhgB3+x&/MM6p}()i3&i~G$,A:^^=]3J&H$>Մm߯Y82kDEZt[^7uF~ll[Dv{YIŜ.8 `g-$v+ +_3rKrfݏXÜޤp{;p|5ҖDNqIPUT59gJOTAB b L$f-h|DSWXlP9("qxPQ沣Oܷd7xеcVMmϖohk{j'097V4p-Lf;Y8w]. 6~dwcaa 6huDշk 2׃&xׇSh%,l%4S*J|$|dj O< Dh b.GUd}'jiդJ`m"sMijp7a*$Ijuؔ6/.C0ȷcchK.G7ɖ _VStѫ\T;mkYR\{/^g lhykzktUg뚽q/* 6lo_u B$?X,l^ZUߗ.{lx{] 6撬v%Zgmm01ڞAS?P1ҍ$Pc%8Ñ(.QSUE.uGpT0G8adU[:@87}G痕xB$O$!PHBm"1D=T] *gswFr~(sɐ(CKitf]Ū*+NjGr4 ~VƧ&UN!gy,]0H |c\ 9ɗ/:)Ob6cNNS~Gݙ _60-vd̍Kl:}uCܭe}fE݁fflAbˣ[#_F㶚%,$l9 E-@ FٯL/+JatspZOSHeBKEXO,Kq0(a6EoH|tH&N r#“LBk9yYw,}q .=5ѯTaQuZ,3Ҝf0h losEQ c_yU`~outi~8 \GsɕNt;HS/M iW+'i#/)h[.a:M4tNi:M4tNi:M4t[OED{ qHV>lD.N=!eıK W)O(Jo$)Q^D!8D 4T ;"?\V|6J`rps'SB,`|x ة 8cFy Pz~u2҇[泀BCϣ(|? B{ I嗀{(, % 臺P>9>%H-ڗFM=PB#<j/6"`3 0W3IaepD9a$U& 04 88 cG3Gj< -Nh-w76*;@;C_y;X,LJiA~ U `+<_ }pڼprpH5#AVh!`#h|p8<O3$2!vx~8IzЯ C_< 2('#===P#a"{ghΈf=c<!#ǀC2(6xa,>~ xXO@򮟾w8>qx@QWw@2 3G9 _y rpYpIiq;WMvYȏ{EIx-=8C8{@]b@ 7vru%JՕ+)WWR\PrЫ_ӀݍPGǕ_xkkkkkkk7}r7}r7}r7}r7}r7}r7}r?pXp??_<pA:pA*<}<(*B}=ޯ %!}0&@2A=}J* pt}=Boy8xXypFm!hh!ho!hy|H o\s%> u@KC]ޮ !x!]sgp)P<9[اB31ە0 CSC&5C> 0qj4P 00#Mk5Ɨ3P뀢S@9~90kZxjd} S ]W<%P>@ c#f#`O󉄏P.66m6oS@A]6@ Y[EJ{gFq3PC0g$8v`sAFv)KRШ;Pzh|e5FdT.}ІW{>(E!(JYJoW6qOex~&v[7F@OG؏ >yQ< xCya(/ xFy]m#k>@Koz+Qܯ<xr)ˤ_گ W+C~eh2_گ W+C~eh2_گ W+C~eh6BN6*D3))(oD3gVܤgT>nRgV*UZJ|Vi*YU>QXAMvNțK7@623mD z~Znu\xo#<6skw>>퀼hA~s=&vB]A7 6ѿqw=-eVNxbV'y"}B\OK;u;;wΝ%!aQ&(FE@X\jBd&2"bTEVZĥjݪ@h("K KD'sg&@KO;ܳs~?L7yoT/ꜧz)k#RuD՘FSJD);v'U_bVn|R9 _T(VoNakf?%^WvIժT9 g({HRURCet#fP_y(:@xo6Ώ ,Z{^#8>JyF[ڡ_1kΧ%yg(JNQ)y2~Kg(KOY6QsK˵Gvf#_+M@w*[ca ʧ:>/#Z* ZܕKKXk~˓!e/Q}d ° wvB5j 穲1.shPB?JvX v\g+q+PAe!K*zZ,Burre锒#%a^IkU)5Ff@t^ vw_N{l69]=bϲu" ԜU殼s^Mm/^ו*U7zd5?4B)h5?CUPT=9rTPyEyQ8pay(X e&f_.( -.,ȸ0x^8P\ yeҋEy%KK %PyeYAq@9YÅ,+䗇 CKÁ¼pe"*+ yF~@Ei- r-VTYVYZ"gEaXUPil6/ ,`^~8P\~2JxVyQ`^|UpaU 3n- Wy-GKjhimV*kZ2mvVݣ=J{Q{\^жj]ZCL}q*___Hop K#cv\t\rTϱPQG?כ_;ӏ:^пqlewvtEߡ:EkthC02a":Lנ|t tF_Ftx^F:t؉@4R!t?Fp9:\סC):@[txBWСާ:z.Ap:a:\ a):܆S*: :EZzFÅ0С~Q)txYGIk[.ޑpa&:\p#:TrtC_ïEtxvÇЄ_~TħGu$A^萎cbtPB't؍C3:XCK:@6p1:FynFatxNt؇ǴVa:\s!2tX?G0:lAWѡoЄt~D7a$:d,t) :Aa0^^E֣ftJ~t8.jnqS,tP+g :<DwtJ[еvY:Ǐt!= AZtx >@at8zHaR﩯҇/p5:,@*tF ^Ct8 2a::,wE;1txBb:Dp:a%:ԠC,:#tF+=JtBSt(EvtCa:|Ѕ>MO*}(=_K?/oЯKСC~O gt>տv:7A,cj/%%=={զK3jjeVGTMC35|Hq_C$Mf4ua:VfsEOij7|_پGw:Z>U-j6VͭdRjrMCƚS33N]c4lVUWnV- NpӃ)IVF"Uff5g &7gߔELM3awE5$Xqcfx_zv>vfnq5y.HK`63)NA̽a:''0͛T[L݁;k=x=71g2Ppە֬Y&"7EJ5v&ۛlt.Ǥ|擖N;4>OqrRZyEwyjO(K)1.4_K|JvJ'}ʧ9|1:Ŝ綝J^SeZɺKp*LVWEʧrx@ܯ0N ţU ptL. iGΕ W+[YU2gE|nK`>yvΖqoZVmUvX{Ͷ`4"S=Nm8J|jSkS7oLZ3U4n5o5WFB :p" N&WDVTՀXժUkg)Ey# ;TEݚc\aתR|],S/ʎ͖^IK]cRTrfkk?7#O3_WU,m]_{Pzh$\cZ톏UI&e6}˧N˚sTU ⩾hlFZtpVSs 8[1oǼկ5-n#Qwuܵb (3&j'Tj c.g J:[k,TNP2n{ml(|`O}"YQaddd$v\ooo{O#6!r{5Omgk.rB(;!m'|x{1+ZiFj!( N5ʁ6O5|oޒ7gر}u~U]{ ;mu[k>͟O,v:rk)[{%R6Q/TڎmNM(=P70vTuuEERS'թzXY_sq%yeH=hJ珗{iP_j&$Z1!7757U YڕXy#ZVxIn-#/wmn޻cG}4O<4CP{xNH]M'/۳b5ʭv]VK:_p>/rSo(0 ͩꋃ]j?}TBPhf2mIGgrE{j#LMHRIv E;vpEYTT[$_.L>2g\F&Z'#h߷?\f*.!?ʨVyn,Nx=iaL0[\Ym8[D"A^)U_-okQ튈&+69zP6?TP+ hW̞@daYgHbc@]ݷ8X ;ѼB4'g8{eluϪK:n[X*oNulP}x@cU8*1Cxc҅Ju\wzu|H7vG%u40P7@Cҿ}f*͘WN=bxNlAqTsm^S\7\Z?W e6ukA㝻tw}c'1>IǑ6!%:gًMo\)Z>ۑ#V9uUlJ48GF{ixoK՛E r,M*HǤUIۓɦcw㎿ -"1>Hzaa_' humrxH'#dnTa!iWRGƄ rkwwt7ZХiBat£vP)'nu{3vv?@8,CB]z#!ܫ¶ӆ]=n!;6pe1DG^xKkh^"ɵzt˽F÷A>wYY3fCA4H QǁYd=FlT6}.!8daCZC C{mþ5ix֝YMθj‡,͹uDO˜6qږTș~ UNc f,eAʙsos/g6nVDͳv&pVKsV M9ss${wU}.ʭ U=XtޥtKK.nYecMYVl7 )op7eye_[aZZm+{\rʦUVUz:=sK'Gg ?{|oOlK?yBǹ#Rih Д'R{RWMm(zCD'vM]<1['zi"M+*CC4X8'ogURo hHCYs+ҿ=zN/D_N;VXOD~H?ϭ/+kߥooP41 D!A[ߊJX K Xf7rX+ʯ[a-p;?u"^VO%h4a6\?b1Kq~_+f(""v>lvnG`|`|7.R\ݮ /m4cs|%{F)A9TZm 1Xhc<#* b;"R̀FGṗ(J#xO7OayzgJwyym6k[].ڲ(_iݩ_e-Ân~A fcZegk?̘W\/F$?SE?s^=ΥK{rZPK 2jA-#e ꠦtj*o-owTu:ҵWg@= Ꙥ[Rm2%@}N[Lˊ+-~uo᭟_D=3bjCQ@jL{0L"g-VXZ v~mU;/ޅ]^ep>QQ| ǠC+ bYMM͊sZG9ZG&{+셿>hwju~_? 4po8OebβZ43O?<~-\7XM\ I[9a@,%sͰۀqpŹ_\ p?M\?\?1r3Fn-˽#7cf(I_Kk+8BZ3u G[⌝q⌑Px9ĝZtq';Gu-i.ʷaBn2F,l2F,l2FrbiXZ+֊biXQӂŴ`1-XL ϓoriԯ.=aAXM#Vӈ4b5XM#Vӈ4b5XM#Vӈ4b5d #H0b##¨52jV #H52*F#z+z+j6h h *6b *6b#*6*'h9O6Y{=V!V=zw91軚*fLcLcLcLcLcLcLcL;Y+ l>ۀ~gc1.!|>{=2b:h#G?yb/f&ְc:ڇ333333333333 _HuXEnvR }FȵNk%yME;)eQr#GWs99M ZuPCa AL \ 0a pLIa \p\ TtL/Axl_ã x')-< ;xEvkZmPP7=ڛ |_`'b.Vv9Nހ7-xށks'kquAw=!zY~@!백:b<[qx^~gvƟe1'^[lH k{0[C[pc n='pm1AS'7/I 6IMmo~o~L0906=8Ͻ,.7siɷF$mUk?F->qOQz4t{Mq:hF u4PFe3t C {[AҠ? p ͈|Ca AL \ 0a pLIa \p\ Tt!Di3a7] ̡WUp5\w+aDfX mP |Po{_ƒ< G7X-8<OS[xk5Zw</6g;xނ8ycto“ t29xNf<'3Ɍds29xNf<|Gys</֗WUOP [av;w»,n='B/3Y_?^S~$@fI/oHm6h,m3mLSDP"+Ȣ eY\֪jb Un5NV@*lQE@J2MC6L'$L)=Vzy9ef~3\1χc v_ ;..M;~܊^.܉p7Kq?X)x?ãXlbBW> _} :q.b`~Ӡw^;^':׉Nž^ž^ž>q}XXUֵ޺[zZo]ku9@rdШ n+I[I:?/Ctr̝3o]kVե.muip35L gj8SÙp35L gj8SÙp35L gj8SÙp35L gj(@i )@i 9S} T&*TcS]!o0m0m~K5^m&^m&j̠ j̠ j̠ jTSԨF55QMjjTSԨF55QMjjTSԨF55QMjjTSԨF5513131313QUʅQD|"Asci>hN_-V% v񷋿]ou[Gu[Gu[Gu[GZ ~7w!jz>ۊ{u M~ pbō!nޘzcRoLI17&ƤޘbR_LI}1/&Ťz^g'^P5QOQQ`k/X{ ^`k/X{ ^`k/X{ ^`k/X{ ^rϺ0l+~U;꽾cxop v;ws*%!h?x;s !zQ֋^e(EY/zQ֋^e(EY/zQ֋^e(EY/zQ֋^e(EY/,f#o6jQRU@Q$7䘃SfF$FmFmFQՊVTUjEU+ZQՊVTUjEU+ZQՊVTUjEU+ZQՊVTUjEU+ZQժ 'E<˪DI6IM:ZLG{4I|ù[<.ǥ6.wPW`J\q l\9s1/<M9;;catc'cїPB(gNhQr%hM S4a&L%ꗨ_~%ꗨ_~%ꗨ_~%ꗨ_~%ꗨ_~%ꗨ_~%S8ǩ?NqShM)W4劦\є+rEꖨ[n%ꖨ[n%ꖨ[n%ꖨ[n%ꖨ[n%ꖨ[nI]'˵7CK]]I7~gnu/{c<^kDd~Nd~o |$:T@ Pj6ҵtmk#]HF6ҵtmk#]HF6ҵtmk#]HF6ʩA95(ԠSrjPN ҽ}t{G>ѽ}t{G>ѽ}t{G>%qu1B߄VB):26{ΎyyBX{)g’9㧻{=#$dmFeR*Naj{̱>wW/"^r͍/t[]ͱѴ؀J-0QWb*uF荟?PvC.uihJ]="=+UR8{T-LmP%^sz_>bXa_XzrSs-؂.8o0a,TUGc:V;:3CS=}uUFn x4䣿?j'JT UUwS5MjU;Y5G(9BJPq? T,P@A vR`LS?S `')8H Roz(7H +P@)5BJPjR#F(5BJuRjRJ(UHtR0?6 =F=2y6;6_igÆxEI<+G'Dߎ7\+O0|j܃O焋vVw_ xMXW%QNOzΔx/\u~pŌ+ !'UKgO#|cυ*+5ۻx&mmkK։zHh&zݻ#cuOԯ>AawX]2k;7ȬQƼݛeU]dc{-;vˎ2c)3vʊb'+Ɉ(Ɉ)J2$vsn7qCW[>a]̤E?G|H~>g$]V~w*罝zZ==֢5tk>#U8{Ȗ߆;)1NqK@уu5JX:29= .O1xNO{Þ|N9|՜z;JQKQ  KXB%Xz=NqjS;^KqSkG) R'Z5 xkݎ;}ƮpMU~_5%@%NTԡ%jU]Ua)*Jٸ}}}T*M~3:e/wUQz԰5,Q}TCX: /z˰2 aeZGsH+I W\,z;c8ڀK x)<* ĶxUnضLхװ#v܅^1>GeK},=ɼA~?u|(J=G"ܔyc-L=/+ 穪L2p \lp)0xyOyi=uh_F蹗皰>[Mc:{ŪԎ=]zWz='Sr0:aa}Ja*9ڋ! #(֥coBΥ䜮JUɻxXW5qJK%fWMxJUU8χ0#p i>mҧypαx'xsO{p9V7ZT04U7Gӫx]*^W݂[q sTb<<<]`nu^Ճ>gu?3+<9/5щպį'&EO/Q_WkUjU-gUllQp*ܪVe}C%V1UL*GlU / FMzJ~ebm6 Sxޜ{kBnr׳Mf^kM +QzN7]Vާ_Z^=UnO6XJ`^*X?<זԿ鴗&Zl VmAl|\}qlKF!n]Woi4ۢ÷jql|\-+J9=`'vLit\!/Wrq@k.5 .yK^m0Znz܄brˏc@~첃\'Kᷔm:ȅ]y|x=Tmjνu.nFGnoՍ[_ʑ1]S+IFgmYt&9ӦnE:VEGlnnEl[tu]EkҺX.֩u&]IK`tm6ݪSwԝ:uNݩIwjҝtmRy+5FQZ7ʝ:Kťڨ]v ;t.ݢKgt.N5sSͺS͜jV]ڨ[T|oQ-*Eŷ&ޤ;U{jTMSwqYw.Uޥʻ oDg}*jZ"U񵞯%^*R%UP"^,R%~,%YT/KyHdyI/Ke~z*ټVhK^Y^2y?}SOzy?iTOU${b 6;&uBxBn)}eD6  IȊIdMVꚬY]U}V4`EV4`5f X̀4YE^v : ͕2q~Q]m՚] jͮVpfZbU q+g\9Zz q7z0a~/*W]yt|𛉎[уPك  M(.L<*qwx>n8mO80Ş8S< δ8{)R^htx+߈3^ļJLE"NT_ͷ8BtAXEkx^wv}OQ:.wC+sOs>:iؚXӞk]{cu쵆=î={\wq=ǵΰkNO".J畮T誉A/=>"OӮ;͉+wScscLW•UWo~Ⱥw87\kr_nRi:Hy2):SkxU\lwkr .dHsI|Ϫwqwp~:GM\nzs3N wpi{GT>mDA^AoA+.3HnV8HTNTNTN4HNN뎛~G³QSF^hأDaJ'yI9fRc#ڳ ǗLI5L1iG/WKۘ6fwK&ۘ6fߑ7ٲyf̤3]Ƣif~+YfvuWsQ>:UtCNϊaDgN:svwr"NM|-OY]G'"^m|t"flvtAt"٨FfAߎߙvU2-B2oݍ/Cm;h[;NܩӶ3xz4Ix -vKykzҚVi 9~Ɂ_<}d#˻zffffnfnfz[ӓvvvvQڕb~W{^NNY6kCgٝ-ϡÊGq{vZ/9ݵ{9¶?qq:zCJPǺ~'CP=F5zCJP =TBONq&U[ŸU[TYU<[*vYfgYb*vYqlVq&İU [Űu⿢<9hitI?5h^#cn@oXF#nqopI83!|Y(>8')|9,>s8y=.? /&:fo&=/⥰nFlB#^&?0AǛ*:)N˞b=.{1xEOcJ9 wTp,|pu{Œ\U<5 /4|(,Wއx'vg,zmb}j,4Oc2vSNCIPCp(8Goº7mEp Z|ִ#폿6GGBtpޏ"/O*K2L.7D׆l\9BluN6Mq<܊,w.܍{p/H)a.nxu>>!Ͻ6WTӐ;p,ދSA :Ȏ8~lǿ |ո",9d2L snoxePѝ w܋ qKϊjCC܄~[p+aGqtGhG8Z:E ?,..@h x b~ q<_WXUXؙG?5 ekpEr\g ~q־7 ١%MDGŷ+oPm/ݱDGL6:|l\9s1}, X,b~1k[ъ6ilC' }l_̟rxhYSD e2_5@txErqZU~3h2c~"?lc1SY!*A.U*/*߅wgbFSiT<ʫqCDVM *.9sʹ[ԩhZe{?uTEN=*M=q ށcNaSuN֩'$S^|g]K0MkaA"&n&n&n'X!ĝ w܋~G":49܀m@}'wR}'w:֙Τu&3iILZg:֙Ƥ5&1iIkLZc֘@t!Ӑ@/_U)Q9&6G7KMTLCI&}J7Kttttttttttt|G|G dvY;@N k' dvY]2]2];!`&.{Wj\jt+u+u+u+u+usususususuӄnMiB7M 4&tӄn0w.s2w.s+*Qy5o͛y7o߼7o͛y7[_[_[_؃^ a#>11111]}>WWӧi{=}ڞ>mOOӧi{=}ڞ>mOOӧi{=}ڞ>mOOӧi{=}ڞ>mOOӧi{=}ڞ>mOOOR4}җ'3&QIjD&QIjD&QIjD&QIjD&QIjD&QIjD&Q{zϸxƽ3%q/{z%KԻJԄx5Jb)S,eb/7s}kt)55馘tLɬ3og3y̼}f~r!&1cԄ"o]=]IOF]c]]YE]DVQqAT@Q@Q7aGQ HkW @ GQQqEEg}EewC\=3hgg Gu!(8#<(8#ϡ3Cg<.<£.<z^ D{&ŋhƓv'odt̷2e 9gedKtoOdqdqdqdqdgg碅d碇g(x @] ~Ky] x+U[]ntAfM=^Н:{ƅvCÉ!4DV'z"@OxA}xAP<("@[hm-E;Rw|<>|<>|<>|<>|<>|<>WA YD3޺U<`&.:N&E([d+79[*fr 0Cpr%r"齢X %3/I~~AZ]^MCԍhbZ%9#0/Q VOB@GiyܤhuIh}z>Q.ճd6U승Ssr=ǒ\H%r_>>%Ϣͫ{_e7c'w i@f٫ş='S|R `+A?\==Rg`nDq9u'ʽ0f+x\2m⦃w !El0ݥׄ|`^IO4P@%RUY ӫzC`^ҋTtЫ?r>9J#IxSA^"tnJ9άUJWE;x. ==zޣ(=z>`$i xc8x/Ke0LSk@S \ @ OL`x<Gcq CP0 <`$ πg0zzZzp+[2GxX<+89~s~9@?s~9@?s~9@?s~9@?s~9@?e}N?h4kZ\\\jO#KhOc7a/kƣƣƣ phP?OqS4Sf L)@#GGGGCGChA(@u\a?q|8p8oooo>j׋$Zi: 7 R2XO8|qK)t? .Vd&xzUb_ǏŅrE~,ΓE%C)@~/eEG.Aۧlq.ϡ:~zb7_/iYJMI bH#+KywZ]D.9q6e?>Ĝn-[n5Q-5JbruyXC[ř#WDcFAZu~[+)Olbr7rUW W_E@(H>4Zl)*x@W4?p>~'zS4vz~~?A1Z1111111ڻ1znZeL>nc=#r1ZX̴c.[h#ۙk#Oo%z9F/NJ h'NÓ\(u6:%y͞&-m7-ŒklK[߁{ba?,p_B!w&93əB΀"SlE&z)~ww ԗ\F) =H.Fhb4r1[L-u~Ox:+EږݢQm:n'"2@{(vSiw MoP[:Fq5PnjLQZ~_`[<)=EeJc{)YL}IF"Vq6XAP!ء%ʥ>[-neηrAzɲ?v1F{{DhZYsI9סn'hIW֠ h'` X:OUHn{[c>@Ng;q1(c͓+DYcus))%6R")E,}l,o.)є6KК`8 V\/jxpLf 3_ _\BCKB /SއU~~{[KRG6)qQYt;pw%5jzaa Xff:>mA_nmzGl;ܮzԛMjSs\Ǩz빏 3Zx89ڢ5Z"+E(9jjYM-6NR>jIPKM5 ѿ"WD_+ELI4;@_D0P428+ "r 85f]f# *촩|SbL߰C/ V؛| E#lsq&&$h)+Fr.$AWڛ;i7W nyi4j2Wf2W&yyE/2&֢: Bb jX-2E.އ.WDM@"f^L8)¥l\В r6&6Jh,)YL nz\x"+vZԢ!ߴ ҅NPZS2?هyJ)]ҫ(Wdņ/Ǝaq їVVQ^'EgQr}Qѧq?ȕ aSj?m:1 u0Gb9h/8938u~q'?&/=`>8<ۤwE!R :YV2UNZ jVz'dBRkr= NEϢ*U".B;lJ2GRXW:IdST_:97Qgug?RKz' Urjɥm2}d-a\vV6L\zK~Uڪ$6uGz}0>F@Vr`v;Usu OMkCOl}ͼV##~mmO2CjxW4cJsIٓf%% E_kڀ]S J-/DFW rVpDp'6Wٌbj7ʽ-0i*LLjVاVVkD[`QUX(.wR[aNZMXˌɌƌT⺲3FaV3+ _MCGkդ|4WcQo7O.^_1-4j'juWXm;[hl</՝_r-4@ZabKQz nPTBFhx-׋sč&boƗH)pG{Z,E"u2IQVXbUKV3jn 6Ybj/V(Zw]V/kk=;zwk֛V5kȪamkeg_`k7Yۗ؍ M ++.ͬKVVƺnoawo;۝k.VSua笞=^h=ja/95{͚a?Y;}L]dͳ'ҖZ Y en}+3d̔YbYKֶ˺#Ӭ<ʕgɳ5yV'ϷF&yʓK-2yU6Mmlnd+Pݲf%dy-dv@9Vrk{rfG{=;U~(?}9K.c{®$mvmWjNIw2vK}3y߾˙̳89%&{hH4.R6nYYi/YkD6D6ع͑H~d&-.3΋#"mH]9FrnYp v+եtkQe5JYmgGe[IwlpGQh}}Vu_wI;ٝ,Ȼݩ y;W>~~*_Gܯe1w#Gq7.qWknUuwrʖ)j7U}uL].KեR+ZZP-uAnT7&ZUGI. ԿPU!zȱ QCPU#8Sϫtz)&N8jTT WNCX-wRNj:4SJ;7xN+wsG,wwλk..vn..u:zv:yMNgZswҹ˻ٻu:;w{xݝ^_7==<==zÜo7<;{y;Tg7͛ vzao3wF@|'qFtRR939JJugJJ͔룭7wwwF83y?-zAhhogVo3;?:ș}"qt~KgStYG'nrFf9:##5SGAȄE;#ʯ?ÿ<=ncn?G#h?ƟOr/s/?WMO/fgm~{׸uO.?DLbvv91}$b㱲LwXRt,+V}&V=VN r'=N ={ڝ{66Ɲ{.;=6>6}'b%kivZ;7-=UZj}i%Ž _V:PKfq'9z~wu eO%S>LݪwO:N;3'o?Q1i!3l_(/E}v"X:^5gy'Iwty=Tti&4<PwyU$cv3*  Qq;41 XP:Qs<'w2_G]}yru:OZ^} r_Wtt͡u6{Lʲ(&׳$c#=[v/a7c_IPgxDx+f"'>ҳ߿'c!?ZI7OxLaW:h[" #oaćxs1^eo|;_1.P6iYCd[yxNv"TZLGŷ;#w](~pŒPӉ9:B䆚NA$ֆN55j:-t@DM7QV㬔PYeBMg 5UNMVS򡦳*ΪiVsOzyQ{i֭^9ɫU:{Y^U.WYzxPm[PgPgCj"k@jԑCұeJ--30PkX+Caj kM5ְ6Zj PkX;BaU8֡PGvZJZ*Uig +Xbl,f bx/ o%^oKMŞ\cO.4UV5VŪ"k-R26Vz*Wgmj<wmKu~uqH ,j"HXEvenإo2j{(o׉z{do^{b쵒 ^Ey/2Z#/QUL3Wۊ܁tcհ\a9Mv6;yu@:nQe}Nej믆]d&HU˅`=DXWsPj&1uk&5FRm-jډz=YE*XETWu/yܧzJo՛gQO5Y{1y y'iwJ5j$FQyZ!fKOƩqİ>E4\3AMD5j2LQS9UM%-5o=f}5~V9jZWԹXaj& Uj֪ FO[[VQ[mSvPOj'}ޭvsC^}j=ٯPAuT5bQ^Rh=JEDM8&a G؄#l6pMpTFE9ZUel!U3WCoo-jkdGQ0 W, eOmYSc^.p8!InaJjNLnR]xjIΐnݢݲ`W8vTcgՙctahz\qPKRDV3L' E05ROĄ7Z&>>p_a=iXQ/z2z$/`yP:AMO/P?p σC֫`X/Ӱ^԰^Ez U6eXW.Jܗiᾬ$qpY%d [E)~~D )5P!b>&R O٩Sa ;\S_fɀYe1N.UmIYOEz;Ή-}B=/} 3<>D>J_\p=?;1V̮8d%qD8rDܣ"Ru?͑fxOcz^I1BWS#wy8\KwY9:'8',5Edi!C B_%ZVEFcs>ӹGx< 1HJ_z K;^W.}|se5/o(|q[/bCPn pq_pIwT\{'Y]=OOO~>'y&vC{*!n\k<6 $d|5X;'׆*g|Z/ߘ/|}o9#bғu7d_8WfOE뱟nK[c0X_H~>{dß~>3QǤԟ!_޲ꍿe) MGEo>!'?]0GNJRϡK }/oo{1qV;w~gKI/yL2ũ|~/})(1s.4 0#%!Vꟙ;S~E3aW7EAasb^p!M'J>?K;/dU2(v{kʱJWe]*Օ%aB(i}X '4Rc?Y }Eoo˺OY/Άb7zyXdo- ?4#I%-'w,Q%+χCIS({Gս۬t.exks_Euvgvgv6$"$!D!1bH0FD)""db ~D "H)EDJ)Rȋ"R""H)""R}'{3kfg{8Z?q}+?r]\zˏ_ő,߫8}9I5tdi?p6(]|~˝GxS I<拟髑6~,?10'.ܭjU1~9/vJ_a"}k᭭aFz~~#h+;F|R8myً^E_| GWƯO;9cG-JbHꏽ`3ZW~|ùSIW v g_xk_Cq}_v}{=jݥOW^Yk!0]+{F;~#J|=ZI+kUյex:|]J`3-`=ٞx?jFᚑ7;.\Av|geG+^owC]W‘pN˽naK-/C;z5E;ןtiO5-*'ϗmߙhU,o~jgK+uپ ;-GV%+](˯Uq=5=]ҝz5l|7[N[X{{T\y!GW?X.ٗڸZ}{6/Qz4W%"9"4jGowɕwQxRHIw%|g7}{-}_9LWLNmƹ Q/iFc5?߷t:0rCd[R.~ק(gI?M:>X^f;wZEUXtZW]a˛/uW9|GkO/jzF&'{D1=}} Gnu]MoWinF#(#A/џ]8惭K|{C'~qxoUZZŅhO#VO~~~u~Jy r^67{ wO_CB{1=Oay=;SufP_˃Lz$N:DܩYd_AV>s+݂tng|ACv~yAߪ%{sˤ׳s[EOV dgX%.GߩGf8%>ϡiu~lUw^/ ro>B3[~x>&ˤ ra=#m|}t2ߨs<&:7㻑Vwx8Vы؍؅؝(\lN7馒:4a)<$ktmVVӱw;ŻػKtgObq1;(N\)_fOv\,>"[ſ쌸[;0vq9#9ɐnHL0\!ߐ/Đ\,ʵ!Uxғkge_H01X]9! \M6l oBWzқ`Hm)Ix > ޛ &L>o &<5ބgƛk ƛx6p75&4Sw(pu7D&&*B91뺉\Mlu&uĮ_=b7&BCc+3&qE7+ 8QSDEĀD!%Ni#>$( b$SNJ'qr&>_p5q:W\Wz*=_q5q]kJe]k|&뮉p5qbWkor5y&.k cc e2]|Qy\)k*&WA\lT*w}ߕǸ*9We(Yl9&s9 iLC9ќk5\ommlck\lh0K YR M 9柙6346;.CQ"f wr6`fpr6CWk3Zѕ[{WZϪI3l:mwձ\p\h:m(f:mN1;q6cgf.V_0fq6ci3r6\؟p6\Xuڌ?:mA(fU֌p5cWY3*kq\eX+*FGk&'pe5c?7jq,N0(׋E0şc6Df.gĺbTX/SyG{Xq#P>|-a?u97yvk_{cz&ê,IbY2!Qh{|nWX2L#tC||qwo'$\˹{/OQx Sh1xԏ|a$#́I^'ysൟG~|w|[X_ MV$l7/&o.›{çېOɧ!@>67O/ <^\&.c߳iw__T;3<~3oS.x '$CaH6$> uLiZXPPk苵ņb`?C? zz_}_=ީ.e6.`gϲE߳$ Y2fY.Wey|^aE|^a*Wm6lVjzمbv ;;[wwQ#Iu,$/t]'} }bG#1c'X;tuszL%JӬX\c;#x@t//Y??yYddlddI0Y rhfUYerÊX9e0 .C:MP>YZNSW@&Q>]NG.r&wrw;=(gY,VIF77nz=Q&WE^r/}^ d_/Z(3I ߎr)3ww`w?v EV^.WJَvDZx =zz6P~Xdk/O'bd h'(BHGGXBy!Yy(^_.q+.AZ^%k52ku(%_7bM, c ool6y,oov-l1;QmmpƼ[nߕe}=GA~>j}(֎GQccT eN˧7>?X1xL 򱦶,oj:LX)є::`9]Y)ԍinLYdrL9h'JrQ;z M諯/T9 g3L@p& 8K有u n yp&V9KZ,[ @-0'XP 9sb} (*bZ8:B](P2NP "RBQa<`T(8Sf*3Q S :ek}-U;9ӂLEqi)[Iohpօo,f*f6ca9(s9gkncnm3cEse|+67w=ɜdv#) kSͩ!nv@p; nv,s;v+=ML7^GD@5%pˣQۨȃ!2(Eh1:Y +k7pD`Y'u:uVP`m1vjQ-FժZYZ3ZV!oW( ʌUǢ8u:TԪNq.u f0 _'RT`7A5d =NUtuZE/Y'(3G} cE;OkG7ou>>ú Յg,u1V-+Q#L]2//`XJ]/eu-뮾UUXw?Xfy]277PrlW߂Y݉6nu7]uU}h=u?<A ʹ2KWGb&%,+쫘11%,z<+|i4K|O,i fןt)it7_`̜?eXbƃ&fOx1Č;3N$fJG"{$H'{$H'{$HG"8H'{$﹓{"v3J=w~O$G71ѓXo!YHLLnVH\^`\``^ |͓Oe! (y0XplXj?5,>b /!~;Xx3 7ۈ }p0d$0Ԗ#N1qǕS缼"&/yb]779A)Hw=0\(Tݺ!kQxyo!~*De_ZG׋EQA0sݣ dGi~n6DM?xa96!?;Y,`OC/ @ &-)i(BĒ %K.w%K@,9Xr1Ēo'[~O~k9?31,?.$~||^>ʙq1b0sNܟ8 .l 1b3x.!ĀKLnE\Q,$#8RHE,TĆD*biizZbiő]"֎THE,TĒIEL"1T$R#vTHE,THE,T$R#1D*bq"&X;RK&1THE,D*bq"VF*bI$!8H?~Daq&~XI&~XIv'EaH?g6&2K&0"VJ?L"dôcX T*]d*=@RnBdÞD|%Wn%_W <)Q*}a*A]hm3 e+e0D)a-g+łT(VbN "j#XNqF-e)+Ҩ<)ئ#)7SSPfys;9Eʓ 9+(zN E;)+P<ߣ̋JK|?BM1 TN)2y //u<扦yPSDN>E;c!iSSBm܎=DLBS@MGg"^#F<7DS n ^)zD/# UF"EѰTFU~QQQぎ(z<@EזڒuEwiѵ%-(yt4vK蟳~ѶhNJuFvpz 1LaUanPRyrE,="T9ԫXFu:FՏ('](>AI7'`ntUWGyPT`SO">y 'FLggϩydG0yD&=, CIOLzQd%XVd7k5( <>Y]$[ݠn͈Lr(&ɣdM}k;`I/mm1Iwu/@L 1{hm?"TLr\OnV:`vW`Jiq\/0H/0H/z#MUȵT]$ts0@ISIMi`i f6iؘ8ع`FLvpLR>&1&k`i f`&i ǤŤa-W 4RLf7P$X"11<m*.}k'3P+f^Ҕ6L̉l,H "GGRlGԲ-m^iVH"@:?vɚэj5 #xucP-B;k=vGx-85C. Zqn{,O)s>KTlX;p|R^]L] L]\,gԮ[4ڍS,)55ݙ3 Қ5ZQ,g.aAK~p9Y\AZ_cR^hVITYт囜cA5[15;h BOK~Ӈjviw8-9En٫zhcCp tY s;4,oXⵚ|jX8khVK}aц5 yt&6ML9kتbͱajNj㫕|B^`r`cx^i Skkꬆ܆3XieèMXjZ`Ҵ6P=̗Ke+|wVc99`DYo9i:a\1Ib2yJTatouTkGNTD9'LqnNVQέy"͹kUs]{v9 ǀ's5DTRQ<<Vg+T lB[]^kc?=a a?^.X_TW("TuyuC9NcFOZKP~a_gˁ=EցUےjrUuNn?S'孃k&ZpsTයu-8R<`D;YԺUmSr:ϭ8[bֺJn[ucRk|uT,VcmW^W&֝םvw1`KƶgvA?xIeK%Vu㔿rsGWb rˬDPW:p8(WwՕH$Viw僟2+ǻT\\3x σJ5TK(PX95J.+sML]˯Kr˥m`H"\R\>Y5͟a ~\k>0][\Ke47Q=qOLNL57dbȲvbw 3 }| <㸑=L#@v׊rkurk]Yߵ1P_yȵq_Qƃ'\;Pfʜv*ϹD :munL8*8SΩqjUza!Ia\ zap$GZ+X535TlZNUg6vXya>pK= EH۫&yywV<˵US=NZp wƪim8giٍ<Ͼ!k {:+B+# |Ayڮe9}~F^Zc_TfU V,Ogٗ'WwhZo_]C@aR_C[[>Ov%k^s7fԘC{חՏ,6~c'#{h}~~~/h}3lMW=q*;=ia! C0 ac 1!$a]8vn7Ҷ ݴ(u3.e K,11.K>QƵq)3{mɘݪWWs.{};{[%<(:Mai Nˀ2n:e;p`g4':a5ts('<+yopX<9+t6:OŪc:'"Tdlxs:V/ޛ W:bzڮvMX;b;8 r"bUHpzHsPV̏sBĺ ÚKZ5. zU.3n1Tk.a8TKB2T;kBژ A%;"lzVZc Ȋ/Ԗx)]+ac+&i k Թ~PB-]cu@brP(vp0t vCcg cp_xsbSx04kjXY.  +hƮt]SnnK)>: =: k.7 7GCe'^$$^Z7 MiCCx"tVݛ'CץH#6ZtdٵCJ\讴[C§*p٭֘{7&$[C-Rvo#6NU^#~;;r;Lq;߯,fl]KՀ3rGp S-zç$E S!wI%#?r8Y42w/p,r[ ^'#2p&Ro">#p!St>/p)<D3kKW9|yZ4-bt#_XVh =[AULy6 ̉fʩ3E&>,t7X5`C A20FhOMAi3Akt?];z ! GWZ;#8(<=/G Ppy*x*ǣDtҖ c[~p::m+ Fgmm5|VwR[Cp%zf >dkPDL*$bkPGWL5=6SGVڑۣᎂ͇zԦζ`GYr{mᎪ,['QS`s/LZۆ:{*l:Z{HSK:ң,`;Z9y 4ڎvEJi&kV=m{Fb~eñ粼{CUlqH~xǮ/H^d+f)̯A*EBRUXkgTCϪ:В/'UP|Y5QTTs ꚢSu]u]RLuGx_Kղ"ZQ*zP32^P|+ŴWViXӰb"͓OgiC)Ϥ};m4y3)yii?J'c\ʦiR~)o'SԿ|ꕔj~|/Q/(|meLPq[=5lR;jp7,>_7/|_-}!񾷵o>qOg2ȑPH N+5x[\Xq&ΡET\q%[p6&܂M؊1v (ÃxG)F(>x%^J ~`WIgspiC2{ ?^gBJކǼʼ@6l_tz+ }icڐK_w`ddڙv1~fv5'י~.3 Я;wA1823̏L23xid+ .UvvSyuyյZ_wIUԡ6ͨZ_I~YB8L&2fe „0)L œ0/K DшYbX ebX%֊uVlVMEw]bL0qqL<-ϋxU.Ļ=qb%ހ3p6ÅMozىY,`'A? ~Eamyjy稖?OGy3SmB ͻ0{W_@Y)`Df#Ffx;3̠/Q-ڦ32`aFk'] P if@+9|Ng;h9eU#lvm9'Իě;e~;HaIjW-t.V ˊտ}K\gt) ؽw+,t!U{B~ܫXQ A!n@IpCоqŭ$8m RN8NNaQg\z!sM`C\ONAa5-\rͮ+9'?B \s?nn ]wâk)xeʓȭPN&5b;k-!I1ǝQpv:Eb]6+CԸk[ub[FZܭ ͋Xp d.O6-v{A.1z ߓ'Fݱ') %@aO9>$TC|ڳ?RQ#q 8=i>ٱ^{>ܧq0>/N/>iL2e8'sq+w&8GH摄$k|^ctLǟ&%)`%vuНK\\' 'y׮ bOΓ3<ٞ#_yc'텞I3iA26#WrEbxܕc{IyL-?Gw12yc,{ԁ#n(kG{SHbs4N:x;8#H7Q<Lj&SޥcܻBH@֤OAi:n&s,Ǽ/7an (;|e_=q5?は]᫥u}urvO۞kl5Z ||{^G} ' k}|]۵]/lo7jon}dqj;Mʷwζ|}I H?|3|)>gn]%>~wYorci]zopyE}ƿ???}_~_NƷ1U5ɝJf zg_oww$bp8 ;%~YysNgOĹrzoBW뀸cv)O!b41 BߣAY@w;%R`)Y*,U&΢4BlieW$X,<@tYb~>a˰eirreƢeeUK,-, {UҺaͶY %r&kuޢ [[wXwZԒXY`uB9?m!i)I>3A6tx$ɥ/Зnnh }JwCn'nkt7NwCKn'nh4*G3 o  4 D?C?GARMD~~n{{_`|TGDߦ{tOtOn{Z'{zf7їv'e' mKcQ }~S~/ )(XIdUV`+0 C]5CW7̷͋ 0*6ds|*Vn6ȆAl;أ;J-e7l -4m`6-'Aoސ&>h5+J +*+i)o=@;Z@~8Fas J967v4eJž6س>.yPB2VlSSXL۸y:,ۄy(Y#My<@~AŲxI0YIl%mҕ6 {#HZuF";jج\fs\}8qalq\b.[A |~բ6#9l=. Vkff"XtMC-Zz͵XGV)_-ˀu:a+cMCu: @ 8@K:Wh %Mlxк:ϩ9x6r\1Wc-pD߹*\#qY:\kb l-*]- WV.F6[a8sc74w%-OVxagS2((5q B9<65 Bk-X(*#BP Jc،Έm6.0:`ZRb`kVКFldPnڳ$)Uh3OX Z,(3Ff.! :a\18G8_u0O-L>\.n>!\*+OU%>OogJm$_ o}|Dά~:_|lIX_'MRCos[zlczIzAz?z|lj=郲]vE[s6+?kmk]%a[r={ӃoIփO4/s |GqZ_Lq!>>O c<̕Ićl\J@J ol(]1119~~E1mDؓcm 2?$?۠mPڻ fԷ ltl[X8_ʱYg@Ҹ!5Izf,Ƒ̣DV.ױIr#ĈF{ 3Bf񔑕(<7:/b!#@FƁCF e5B<` .7*aT Ag5Zt&ܺ.t!!Q݈nTwJ7Mu syMݒnE@Ы}>@_L.WjuzQ߬ԷFmz^w1}~~X\?֟՟_/owa!Ðm3J MjfCAO !d5 #c:l8!Iπ3\0L%YQ hX67""ݘ >cqAMqaŅt  2/.d_\Ȧ"i 4o4oiG` j:NA_D5=˚4@sui.ju__8q&qU&_X!VF m1XMa|Lʵm2x1l\ۗ9?,c8'S W״7@nvdY{_t*]$)].G+p>_QWmV]4L0W_@7676R4 ԼGJyO`ӈe[A]ݨPӭbYYTu͂f'ά-x=~IR6@)KϷߠV~7c7q#SZߪ|wRwqr IS}eEokS>{&$$R.CB; q\+ Irܢ&LQr4!əpͻɼ{:~|=Y~ֳ^{~0 c#7pF,_27Q-Z'*F7f\#" *zf(};9}۵D4fe]~=Ok: Lj "7qy5x/Bvf>fCw+[,vuQ`84=qj%4|׉'w,[c r2\/zoA3gTl =~zwBk"؟Zԭϭ/jyطSF &Z$EKJ߁0 ikB}y geSp9̆0O+g SB*a&eHhfw-l طr,cTL"y|'dL[ٱ2G\}<̅CYdĉ 4q<C8La4#*KXn6R3`w \Wc"JoOgzjtv,zTNE&՝*-7UTb;1><fE}e]^k.̀}&xσ=H6vm'L#Jgטx+* `53fTiBߦ-ǣ?^AJP,bÖ׳MeRlnf-|.@{cp~d#`/+DoٜQ'T6z>Rn?e%kskjHVGU,Z8x}'0 ɏB7_Ga_y##} SAg`Uls]im-lWў<]h/d vS;2N%Νp6YݒaV*7^VMAdN6k"+h"u(WyR2մwoUZ^dFdn+kyzLRf M"/r + k"*rќ&~ppuD;WWSG"rc9,OJ/I'QȮ"61Γfq!4i/ 6ɼx@ÄCޠ ;3UWsB_v?<3 iM仸ZHK6r_d~Gݔokۑ0"r]p3~6g3~~D34E=.H$_õ+#} dU:?r-ʰ"T |[>\ž->->-Yj+MM452C}*&3ÙHcY ]ȓzSWo{12c^`Oc\E42/v~E>F^*G4:0q{VsP\skY;;-JNrl>_$cgcy.};\_y,hzy/I'0V}<\:'sa>ܚCma}&sW62F,Ħ>U"f֠ Zy*x;`ɘ9$q#wy>1y"}{ǢSM~=k ~)Mp]! @W^p66 r yh)6+9 \ KlB%iuzLN k%9d:bCN6R &WJZ. -WP>jnOG{"A/υ=0KtE*'V + brwK{*NB%̾_3֝7G3ӘuVv"łr"+{B+i2_VݯVMKC;C?(ow\ŝrgWu\QX1'f.ׇ _$fٗY;,cuLncC$繨<0CZh^7>s~6_㭼[,$[fg6F9K o;Զ=ʼ¹M\`0^yB@`ߞ,cw}!/k۸b?mNp"|4/ɩܯEc+U0yf(y>7ʪ\闕iЖ1kzp$#K9eE)r0:MTظwe7 ՌX$_Is9|FNr[9˵I [<`X7[<ӺSAf*>GD9=X sE!8CrN7њO<"2$3au aC`RMNrr7ϓ?%¾QfV^&8gsɂ͝ %I'KNU՞Dx^` I#:#bYhZh諫8/yNa9߽)g%[ ^?7\ ϟBfx\2ȝf&Th1gigZ4I{s* *Çr;/q{CEJkpފe+"6d96f\61˭9xh~<$S.f9oWel`!X, M!!eyM['S;*1'gDo-/%V(/|Oy~D~ E3Q{pc,Rx[ C~l^w-7)plqBO U>tfL.{MlMWiͅp d)Wgo#,1,BM[BzD>7O),;!_B<)OăI4e&c޽pkNl\[X \yptLN\N׻+BƬuAN'h-/1YiGvS٭ɘޭ/[xxeIdmc]odgU<ߎn*/D@,by.>kg3¶6NwYnʿ <\Df'Z[lEӭ)-,s+d6{7[}f՞) k{n߀OF^t/zɒw={)fH,GW!jx;|!I ؙ,]@.AZGD>%pq~ݵ7SX=`[a?owM\=NmpgMy,R-vȋDv*fSQ%0eDSѾFmMSה]amD{ #E.}g9L#Nٗh?o1?7'21v|;)r C&Ξ99*,.+lY|Yyꥫɼ STY1DyRBsG%k GNdN#6ȷϽ7Hk؝^`p &)2ɘ(6" /\0f-WB[Qdi%otCkOa0 !8~l}NM^ct&z} MqʷEv [>h4z5jf̾Y@l6>MT`FHkO4m7(##o $KĶ\d/xAdhu7{Ƭ|jyuk+%rY"sv[ c|QOc^f.~ǒ5}_AoJpzYZ.G%5סմZ7Z{3*T? C;e;)}Dȋ섇8}| ~IIFkYۓ7v_+˗{+o/˞r%B^!w.{TX[hY#a)d#;3o~$xI"Woga2?Kȷ)>^<-4'aP%4ձy@ò&Dke~=<?U||4\ y $8ZnFȹbi݄nxzFd mGX6@f\F O3Ы[߀y.9Y|֠ןbVp#99HDs7Gh^u3%yx{bn֐IxK1Z+ c|Nlup;pˉh=Qd1/M"~L5x0p7 2jU\}U< ]ڻؼKWc-a0}P8 6mLF_QW'3[I+kC*\ܚnݑ}%Tx~>.ɧnAeYeG[\+d, :kU3]%sR#[+}w"C:<F|~WՃXYd^? (wſCW!i} 2/թ+En5Ŧsиy_Ll3L| [Ț zȬD,܏95?荞=gͮϧf&P?nʆE _cq_g/M)Ț2̣vkbO_$|.BvdfC\J0T>G/$p5FbAfvn0a 3bo!g="/#vp?zԐ7zVO%hvB\ U$iH!5oCj/gZ aX(y+ݶVq1Vӎs y`&=ƚ4~Ż-//^`_[0-kϧo'pA%ͨ 硙Ϳ(xr!ɼY~; ud<8 .bB= t7$: ϤبBW\?T ?Պ7$MD]ϱ2ѻżYKv{{Vk܋Vkc99 I474rҿR Ѻב˴*!rMZC䇑w1}bunl%TC*oyyZB Csy^Ŵ&|_! m'b; r |nr1ȕS7~ \|©B4%E1RBs'Q5`rh<"\aB {HՉ.%;vd%e,a9쏉&M/Wd;$R19F3.f"b{zؙ琍˧W] Xa:4{6М5 eiq/W߉rW3dp,1p3}VZR? .>vy c%WeЗ=] wJpJ">G%̓p:{LZ)XnW6 Z;G7ݎ%$e+syY2anbiTTeuUM6$3#x~}`]K3SeNE0MV+szk-Ob,iXvCTULfKijR7˿Ӊ4 U1Dh˷q=Hr=z{]z@G?&̷&<"˿}W_A@ hfoF(@)wdd !Wnb܈\V+7?<*AVN lXHl.  ^'9}%;]mxNu ˖\4LGӄ8eZ~*WJ.\+u"[_BF$@|~ b%ZGVmx\{yk ,MĜN幌'Z-|M ZֲNy6/Cލ|^"a:MA!2yߤK)`.7VsNZ J&&>Az^F,[ "_"JE|8~8J2N*CT> ;rXٓ=Z){(,TU UQRխCuP5QWՓȾ^Q WƪIv2(cIR vϨU]u]}GSO 2ti:t4կ{ij^7Cgjc=TݩڪT/2Ʃjj*}Qi&%w߫V^D_NyAo}H5SU;u_q߬zjzX U#jZu*C\QU[SEAMPϩG05Re?}D Qp\CFt8.K}G 4`nC31/5, +aC}o;n=> `GOp>̆:븯n{!Þc4</0<HP `%8<kº!l [vΰ;8889CSt:Ep;G2 n[vwģax|xy`2# V{848ò~8.2nln~x'G](KFo.Hݽg̈^o{ OfVX73H ?_QFk]w2)ETy_?={'9?zicP 2QQGU{^ FzBo+NzglJoI}3)ib:^fc&ۮAVYӹ~E>O+_}vW1W5s₫']r?VW/\s"|]s>p2Ջ|ROu{5WzsϵٮuO⳶C)7›}[se^U-~~~k6~6~~v:SeWھNϫ?+2 E>7(ygϻ|>]s՟UYar oب|Tsgq$L5țnOٕ:CyA:T>)']ƤI&~~vgy~~R&ER 'ݙtoJ=h|i]JDI)a{ֶp5G\uK1$ب*.e{,et%힜fO u홧i etIӿdOZ|9I{[$b**'X3'~>Ϝ_Y,,E#ۑx;]δMK_$m%mDݲݴEˬon%mVK۬6mm'Wi͔Qr o&ُzת^WQMg9VS!Pr7RMWYޛjzջ]PyxRju^׉:QשY.t5[ߨoTo.jTS)czڠ'j~^?6zo7fPS[L [5WL@MKJ\33HO{`W?x8xk<c0FXURQq*5Ţ*cqKbIKci_Tz,TTFUT&lMUf* V*+6*v*;vN*o \{`oba?@bp0V!?R888GB8G8Ǩ8TTQT1STqT 3TIT)sTiT\ r9~r\*J\**\*kqqqpq[pzVUvU w?ڸ w:x܇T]<xzxx/xx Fxox oW(xq\B(=){Lg>gZFh23dN,Um67c4[Ble4ۘm affwnj"03f>B ̎!%Ĝ scn¼Rc~? Xa, XK@F, 2oV!6&[` ȁ 95\Cn!vΐ1awM|b]|B~p8A!C0~C~@#(QP ?O8űPxq"8JT ep:Np&΄8gC9snlv g=0m il¶{#=CM |¶[`8l{z}HuT7Şw CfXq2=D&xL!2Cd4"3=Dfy!2CdBƂGX2|,짾w#FJ#e6gѾ7" 2l1Ɍ0Ý2ȷtwQ( Q( H JRsH}6ofڢW[6yejIG_ QBn#/ϤKZ֪:^mP|Yj}ޑ)tCs?_ 3X`1,9,Vrŗ5967 l<vvN. {`/prA8cp2 N)8 g,p.% W*epn- w.܃$xHa,dmYG˺eYO֗ dCH6&|U&沅l)d+Zme;l/;Ȏ,ߐS~y@,C<"cEʓ<-ȳ~_zC=D?C0Gz?cX=ND=IOST=MO3|@Ez^2\pWK^:^o7zVo-{Uozީ?]zޣ}z>!}XG1}\O_I}JgY}NE}I_WU}Mw=}_~gYzyo[ek޳X}~V~mg@{=bdl{=ɞlO {=˞mϱgB{^b/?uz{dkoo?;O.{k﷏'i}޾l_7-}Ǿk߳ۿ8‘r t| Ws9q:sɹ\q:ל s˹q:oNyʠ A3 ?ZA;A & Ã````T0u0:&6.>!1)9%5-=8>8!818)898%858-8=8#838+8;8>>ϱ%eP9Q/STc8W aYu#x} 5F_O2ob:ͼuyZV9f F1eZ"da" N3: K<~`Қi}-SY[;Ϻ7Y Q8&)qk);O@^ZK50H iy-T=w-?(HO Gw}aGa_t)#bJ="+M>mBh?%o -ɟ[Rh"!@+*ݷ%%@J(YUVC֒FX#gVXWxҜ#/q 70ˡ,o793\ԭt1˜3k0&fyqˎ1dŞ̆cg56|vċcfŲ>\Hy%Rw=qTGCRXsL&qEn\>NYtœND:)N*'ID;iN:'dr2;YN6'rr?m=o1.3b2 bwme}ac>Ɣ9_rҟy05FK 7;I \SH"'DD]s"֢5mE[($^$ކ81b4]d"e/xO}`|_  CpWђ=')Gd"aJrlWW*VUum1fre2o6D%>|C}#Df(77QM1eo[Qoxٷ׷W4 D!i:N_RX-cF?Vlwbbb{L|//'++  __W?[]bj!~6JǬVwqxv@3cXYPW8(8*qB*NS8#Ίs⼸`(PmuGU}JRgAg o<EEAZ*!< }i1Tjq҉%XP "8P B}*ɠ!4"}ؔJ8mDBWH 7;%Dd" Pt"H ___A&{j^|L6Mt좗E}zćb0K=xub=Ĉof6(MűƳNMy'saxsat2Vƒbq j:`I)I1b ۚe͆0k­>HiAu:AZ.d"B7C K0 ~("OBQ[bBqF_%+O|%?_b둒/X`LGhO _dٯHkR(@u3QtV"QV{(O"I/H ՝EUը"jP=NHQf$H7+Mw㾟<&? Io>n&OC$F_rQz=lOH3`,Ƕn8D# ԷyIQY)B"Nh"jRlD~"/Zllؾ*}M,b\,fB,aL,eR|6A,cʟεczגخgd֟m?3,l<ƶ7[n TnirӹfpV-7[n\=x F<%#bS3ьxF<-#.H|W\E2_4'{sBbo&JXK1{R7Kd4 2F D DiQ0H,ꋆ'X }=rƩj)IR~hM&[S4k5rzkd}km(Q&Pߺkݳ[YIMinGڣ{^iaW__k!}>eKp,v'蠓u9':N!q:ŜN S)q^p:N":DpHw^Σ>Iʡ:qZ;ٞX;FtE# <~Kƣ0{M%[[ wwtU ;V!}s:  i̾hԠAx&sw-k3wag2sw=  0bԽ?ӢZ Wq Y&01qL8feqym.kF~&鏖;[?⿎GCGHΑ)[ܞɸ=ø=s{s{Fp{Fr{L홊335g4[*H㝽mSg7yS8TyudO}7Tɓ,s^lr$kdQ*nH.S42̥-jv3{`&̂0<c0 aXK X+`l- n@P#q4q8'3pyJ\_Z\qn-w܇ ŋx ]sRBiVf'/OSN=Qz`{wWx̓hldhMu@ǼR܀ۤ ˢGyZWK֖dClI3e^5:Ӆl)^zȞ[Tr=SjWӞ._g liBL!-MJk*t~^<[-P2?[</﹉p$q}Ru9(~> e0 4s`!V:F@?~/zoR]_;hv!3@Yw,@\G5!r8ZۏSZ#ܷwOe *W;0n[|[eμO˿Po Ҡ3tjK #L[HZN!Sr*īih9D˙%dVıh9MydZ+F|_o/9'ʉed2YG-#kDO` "X 5AkDAkJV"`%"XV"`%"XV"`%"XV"`%"XV"`%"XV"`%"XV"`%"XV"`%"XV"`%"XV"`%"XV"`%"XV"`%"XV"`%"XV"`%"XV"`%"XV"`%"XV"`%"XV"`%"XV"`%"XV"3*mB[D cJ|v(SkNK^ZSjAs (&@"wJ2=u0#2Èʓ74]_힝 =o|ƔP_5pBJYm#[ONRt:o٩ _|9>6"7ڦm։:Ɔ]#t:ul>]cExm.vj|.;uiؖ%ݮ"2!c|_*_6>U0666**X@F`(P+ v;xKubP_iܷGtC-WxmYOkTk˜WS.s;aR[L/{wŧݷvZ?Zu~#rٜϼln7wb-e]z PbAz*ނ1W5EMӷHq)(7V_ː˶+?~m{u'rONWf.7vgZZr ]k_y>{w՚}ڢun*;>&ywC&#,Kkm:lBEn}uv|ʲqhT!ԡ2]6 Y>?ijBܕHb;2M|efaa/-\й^,`oPF>f%!2L:,{,إcU/mΉYy7RW#m\0nۂO&rԴ9L=si?<:~퐐/>YοgP -f #Ce{1}m;I蒱B|Ōk/VH|E *XBlPG}G ]m3ڮ%M0/{#~pyEF+J'͗>qIM0tM S0&cʜ*{ټo)*7*}- Mh^ TܗvqpW|]eDAE?egvܺ+kA#4.S|K:4_mP| \oqHߙ~6yhpLMVM͓Y2k:B}ngM^4FIώ2?~LW<4 J"&M'+0(DދHP""һ MTzQHo"(RI̽05O>;9g;} 6 E_E!.B'$ŭp=(K#MF gTDjVI3Īܡ.PڻR{T^Wzi= 2G ?WLZs3q1V×PEe6}3c3jOg\6D-}M.&B˼ I=b #/ h[nZ2L fVCL,[X+CmKG[U\Bꩂ "f% zNI }ImYJa-&IePԕN!lu{[/cS<FզEвDWK S!+HQzɊpY/4"b$mı@pl?6T8<>݉H˖_Q d2DdeJ|iʐ35%Sh',?j VƷx]| ~D@/o T4wT/"w.Eէ}iWz/V/jDk.GsH༝DͳŎ|{|,xk\Q`4<7.q~A%>#m2 Z튰h0|( Q1b 2ȨVe<=f=@Q>j;E.hTTH/;fKhRͣ 3;b0 9e=A;%͗U sb12Y>u" ŽK<{8ឣX8}b/d &<@*?F;Mx)jwj$ 0h*JobiTځdlڀ& 66҄Q|M_d`ЩCGD4 'ݕeʝ&ruV&-{iL2rQerʑ w{S봆uVnWh.]y6mEBjp(b*yX(D" 3Kų0dNhe4hIsM\3oFfW`Q[3OR4ԥ-^td6`#w2$7gԿ$Bc;ǧ[5ώngѹ/= := o.Жf&>+=yQ\;ӹT;im&7[iϴzeK5|dZr/VǭDȲ҇ 0Yro~6({!9݀*珬YIuVAt*G7xOxŘom*u"7"4&21/E:Qpyz#eW۝rɯ!{A:ۮ6Vc"j3dNێ)Ce {"%ٯ~:;rQlyY2!ԔHJ[~hR慎듎  3tNR0cщR.HD"@cQ1S-|ͲW%7/^5$ 7Ekt)(RXq{i\^LSJ4/ =#NQQەS@1K]EƮFeQAZv{ErFSfޫL<}w cHb4Ҭ*UAoI<|9`IVCWRn3^<}OU{;r?`ތ&5ߠ( (,ct'`R7(K׌ aOaKy3wBdT7SFU)Y?0iOyȴd2;ph^ǑPHCМ1{#N/k?.PJߔ9$EB5Qnv JB+&^WYkA 1 (l \oۤzg2k&iU/tcfJ_[9 L9qYRZHhqXGK!ؚ~V)r9|9gjצˇr+ 1*3Tc*--:jpKu;+؍2lHP?^"'/"-la6y{u\b'5eSsWkSKpF4+L6dHxȊEMe&n)üآl{xoΗW`ނ2nx}5&Ic3:oWh>MNhCoכr֥ӕN:72?!p " ƼFm^|P)})[rĞ{~o"ݽ, E8JQ+~o:ybJ`+{(/(: rY0 mh;d‚<-{qK; (ocYB`+#K V4a , \)[=ׇΆ3*tyEĢIy1Y{w>f,RCʖ/Ƅ߻3&_Kxez^ :MI'e⪗3r*vj7TG F u$ 6($ͼL|K N|8ros]%}Қmrr[ʸ$:ٱsoYW毇O^;tO2̜)Zn$A7z#5xrC~8/? C?xWA0yA,1\++ݑ2u>Xͤ(mrmڧIY?}c_')I>|R >ua3בy=ÓUfݭ By*a2iJ "<2ɵ^]%NÈĶy]JNs7Rm2|xɯZmV; @Hj2B4B_=}LN[j?ߌVrx~B!L,"Lg3OW endstream endobj 371 0 obj [ 0[ 507] 3[ 226 579] 17[ 544 533] 24[ 615] 28[ 488] 38[ 459] 44[ 623] 58[ 319] 62[ 420] 68[ 855 646] 75[ 662] 87[ 517] 90[ 543] 94[ 459] 121[ 519] 258[ 479] 271[ 525 423] 282[ 525] 286[ 498] 296[ 305] 336[ 471] 346[ 525] 349[ 230] 364[ 455] 367[ 230] 373[ 799 525] 381[ 527] 393[ 525] 396[ 349] 400[ 391] 410[ 335] 437[ 525] 448[ 452 715] 454[ 433 453] 460[ 395] 853[ 250] 855[ 268 252] 859[ 250] 862[ 418 418] 876[ 386] 882[ 306] 884[ 498] 894[ 303 303] 1005[ 507 507 507 507 507 507 507] ] endobj 372 0 obj [ 226 0 0 0 0 0 0 0 303 303 0 0 250 306 252 386 0 507 507 507 507 507 507 507 0 0 268 0 0 0 0 0 0 0 544 533 615 488 459 0 623 0 319 0 420 855 646 662 517 0 543 459 0 0 0 0 519 0 0 0 0 0 0 0 0 479 525 423 525 498 305 471 525 230 0 455 230 799 525 527 525 0 349 391 335 525 452 715 0 453 395] endobj 373 0 obj [ 278 0 0 0 0 0 0 0 0 0 0 0 0 323 0 281 500 500 500 500 500 500 500 500 500 500 219 0 0 0 0 0 0 667 0 708 750 0 469 0 0 250 0 0 0 781 0 0 510 0 0 458 0 0 0 0 0 0 0 0 0 0 0 0 0 427 0 0 510 479 250 427 0 0 0 0 219 0 500 552 0 0 396 385 333 0 438 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 740] endobj 374 0 obj <> stream x| |SUs=foIJ@[JRm,lRZB)``BE *ΨH@ Ƞ︡UD&snҢ~'=g;186qU'I挫'M0t0d[8m>UEEWp0a/Ǯ?kR׀ نT_P ?%Ր*|%\q@ܢʊ7z@{'@+gW=蜀W~%~ʅKo^?GT*܏.Lϙjf^E gd%@ ^/Z42^, ;#f߁CIGn > m;(]|>*ȁ(7W9Hl#?\πЌG{d†<sa4<al[7v d8G{&;ּ9 o&<9<Ƚ-V͆m*cEEN>{8sOEȣ,E3>&V: ;7= Fv/E=jypu=5u;ck@λ&/s! #E:".pNEO+/,eF Տj Z_)A-: E. a%0"9D#?IF3X-`C"6#A<]xp : 1$@b"8|5 d^9)x"~8+cHCig0 D?@}a H+dlÉ+sUWʘAx |2?XwGhđ0qg0!^)k8&F>0 8'Ia2LE,q LC,鑏J#TAtKZf,2aLaT"V f\90:X/sa<C5>,ň` b,Ee<., ĥ2.w`9BnBjW@-JķannF#"p h@nEFĵ.?íp;m)&4B:q=lF܀[7B3&؊"fp'܃#6ý[6.؁x7'={pU#}2"/È~xėA؅Gðq'쉼(<''w 8yG< {'d|F>xG9pO "p x^F|^< GUģ2'_#2 3*8x N!w_w# ߄,[7ē~) |x >D|>B|ޅӑ}W= d=$#~@PƏc'4| ^A "<#/;% ?FvWp \B8 D#=! H8ğdDB2 nj*v4ԡwjQ8COJ~0i:HrhL-SEY9b֦Fsv[4ttqDCby n:z!khF*mVuq/v#%wWGcd n,QMC]={NP$d^t[X;DG@/ݗDCx?`rd/!^/sG]t[k'2!< }hLKC3  Et EբdС`2;قL G1͊854cLviWdt+G/e|Vd_&WM)Wt[ӧC|-$A|Zj+]hD.SIT5Cٍ=jTTT@Bsq Cah c.wA*v9\[L /eFu[&Z3=@pH?% /~SWl񎄘scyd2dwZ#e5&MuovE"{ߟ_VÑPcԈg rVGϊ|/>_;s3}3'wJ/OLJLplVd4H^ըUJs,C? -mWxnd@l?~MκC`r㒋.Od?cl̡BaƻBbO]TP1S07dZQVW HPثޭQ v5`ϭM $r),̀R7 1) וa3 GLD|)#!ahH!?57,:׷H0̫TOGwRP9X@[Y+eptT!zU:ê C!74m,뢻 Ўk;uS,))n, fQtFVx *斻BgC_zJQ ~/#l}yTyue})STPWjl,-ȏ}h(8I2 HﰒP-qIt&zF_3Uaё)eR=/<ɕI䠄| ,<8ږ'krW$]_1J2>#iR xd0+"e1;SSϹg=; tIrT[|gtk_Ss&8kT=Tˎ%I7Zo&,:YZK%TYm lUj3Ӄ9s͖9s-9s+͎ٕ5{+ؚmmcö[-l+[K-6c ۆ)J:lak(V:a[j*W:gbNS:c+.R:`+taMC(X[, h}@aa-f?@+NJ=z[Lr(amEN ZNU5`Pjbu Q:V:!K'!h=)?d"{G#oB>0~ZnBn/sk @8tb~#-)&*FO,U'|)Bvbk;8nUbBK:Ծe)~,2d)xˋH%Ru%/(cZbm?9 mؖ\3]tj<uyvl'a'"zz>V;2½t +SP #{f&3C3+Em^1j* Ȋ6 )GίjZ3-r4 {㍜*Ě̻|%k<_I9hgeS{3g0 #G B\Pej7$_ z<|!;/;*Dُz١>8x4ǼRL"3 DZ찙5ˍt:#1r`X`LI22Z,"ǹ 1(91ԟn{ 6?䕶KZ}>5d7Ӽ|ē`#z{E&5BYOAI>I:yYȤ&/8kjӓU9VA*l jV9q0Fy;X 8C`jsFcj(֕1MHHj2R)d,J`HD]gJ g%jjNSmKqe5o0ft#*ٮHG'KʹRH:!kn_~];~w[f'\ad,tgxy׼Aҵ}=Y7Κx-2h6qoJ>n3lױS+V{A fԼj3Ӂ¨N*8WKROUmͦɳ1-L1Ԅۏfƅ~>3'Nj&-87sЗ֠5$.E!&AЂԙhhҚ5gvkT Jπ ۫1Щ@%FMΆ*ONCMzAk0 H;g1s qYeBpk;wlG/󫶘iTVFnXDY|KǣWcM 7!L3AZ/'IyeI)FqizZIժZ2$F ]/J9fIT+gV$`CWFA,fyŎ?gW-zC[󏻔/_5_sds9b!2xڒsoyd K9c`z_M9 "˙Ycp-!he]|tcv6?u()ᛤw{k[ihnjăȰYf}pfAbsrd笄Y% K\JX27eE $&$;ǻztq$I6[)K $הԯy@5Q95DRJC&ug,RىKыsћEyVD9(FRd2;~Ϯo{CJ0kjo>mᶅm`VV>yrɈӖ/6Um'e+VF$5FN0b@0D>LeZF˩xn7+JX-6,KPrFsXOkTAp$ %"+qjè#>O63:3wҔԮ3V\腟G˵ k˪ĶyW|lm?1[qwݬik/]Lv'fXV 1 $|v%_~317u8p^ñn/kw?$[Y8JŪyATͲkbfR  7jǰHX Ɲ.B?ޖ ./77,5VT4)\ B4q!L gk>|9_G dƓa!yXu+h!-fIZ0f9҄}MXkq"A2TD g4[fțrIbɽαǏ}/$=3#$0ލOQ@cɩ7N~ a@0QLXf0F s2jHo­Slp8,F!(c´⻒l'H"肊9 W'`Uڝ۲nf%] M߼O>=sV1; t+6WsT4˨2k^.}\-Ap+ˀwxpg{i}a.4p09xd{7:~cObl~1x% ,}ߖK_Z@4QqK hrHj[/y_WoxɕOOn=|xѱ _NMa=25a|_5)w`6 qRP ;0EoaՁcndne8%V$,kUXK^Pk\|x㏎}!9Lnř C1Y\},kbGԒmƷJ{ZOfK Z;f_9m`9 x)̐DZL 6K,l\b۶q'vݱ~]>{bO^[Ì>E6iNCoֆ2:  ?-~~uq2\jqj{+W/h.$sFLF[d7ىݞ6ϼ̜19AIM3ٚ$&?Y5a}Z;Hv{j8iT+'qrZ4 KmRK`~T8k=4(E^ f/`(4dݶ$5(hb܅W̲lu͒ܲaދ[&e_Y:fdoxE>ӧ֖MbXĉa;1ʖ3T1LtJE|n45Ljm=sX'Cwlk˥&u M7\ $:$g>^귑/<,wJy63ܻgc\ny3z"hX]  APm"Em߲pנܖXY'lN:tR& (CnW6F7!;9/opW`V(fITm{{P,9zXإxV* 3\vc%JAAKזKåNHOf3k3?ۻ=;is?{km!0Lss~.kc20>S@2}J24 1qt$hfehlLMx;zoa%,NT~D!s0Tiݺ^}y>NiS6mmYo%u;0̹;2̺qKܕ%&^ѷ.WN b㕤T:RCtZz G&-K+iF,accj&#,SɪMX1.OlQsƎreV?L큩9#֍Y֔~ucCr0L%s+ >翎WA{G"g䠍Uĺ3,le.~OBqO:&# :I(ed^ R)MeR-ĒMK^elXyOѝc,f~v۲{j;h7XVvՑ3;Gźq`s,(dqEԱO:K:(%Za9lg$9_{ц[ៈDwkںGPKtF.( @WJ( KBcTak.qM}?K'+wL}hI#|,'2 G4*Fr:}@ɮV-u&lw4tQK-V=Fk 55M&za{&gM[ڒlSNNZRJi`7dLlLZ"mAQETdS\* nAO'PQAϽ3iS}{%7g=s=Cԭ$ C!5}B-&?) PmAao h`4a\A;FqP2FXAA7yUv h+Cg3-9̚g[Zϝޕ7 Ǎn]i՚:?jXˣuk`]j9'S$_VsK xZGSA;vo4Ƒ h+N0jeqd5b[|Ӑ>*:-x<ט=m!{R+FTQ_˦2xUy@!W(>B?4!"vL5 Ufd*":I6&}b &ӌ,r"347;fuz+5]W!e;g+Hb,,*EGGɣ"ڼX+MK$g#6"16Q6֖PիYsHٝ&tU[vLIIokH6 3FL|"vNGk^ES(Vú )NH D b !|(1)ȧu&w1jW / 7AA> 030QT/%DIYb_F= 8M%XP- /*?9VETa^1ȃDZ鲙]oD_C5Fq0} K!8JOHP0pa'DDׯuej $2Hp1V9QRT`X~Xq;U܋0\>^PƯxXI*YeD/Uˉh V(EaAIpqD 0GHZI8s$8pFo°:DH$s0 GBp>E2a {eb8>?.‰!0m DCpC1~S1u9<THy$W "UfLlmY?fezT]f"4~l49ZRE~RgcAqjs YcgDz (1.ٲ`o`vj'Y!=z=v 1{)#M`(jp`LpX ¢48CQ\Yu "ɧP`~|~=1+ lb`̣kWl;g3t)L8bCH;}ٹz6Sp.p,b oa'#PN9Ϲ}. h-y AY=C!4 ҃bxQ|0=4 8$`Y6B^Z53~rj;RYCu1O>FE.xy-3Ρ9) 5<#6dz,Ј}.hCp<8,cbs.^[CNs nW[@?4oo`]PjQss1 QNx ?&s#/_i,qE؀Zc, S( h:9N cxo75tK|*bIK&d[ EsEF^t*\)=K"dKTl6ѕtJHɀpNAlqe(TO~؎'MwoGW-8斘k%׬h}ovJ߳}pz-%+:# U &6Ԕe~9+M"5)cRbEr7%l)}hj8ں^A7NǔWPF}hF CQ 56*'=OtN6Ki3sthjsRIț57Ǵy炔Tm󀽪gwFz|"p`g?9ֱ?Yut럗ڲa.g=TpG=Q3sj5y@{ݺԤ}nrIo-|!OV?tG#M.y`v뎬DkyX&% GTNLyuɻnjvEG2r M[ om~*srgTR%UǺj:ԙ UYakA놤?8d]Ç࿇%K ^p\%+ڋ]>'ޣA}1FP?$b>'AapG`V7ƥWB/,C.s{֔5n&zuJwHǍםPu'Ν~HYOF{'RfV,:b8/D{^B[ 1ĺ= Y{M/,UȟN8oM]xy)Cg]~Ǹ&*< daMYZ>՟}oV4ΤϜZy*vWêU_?V)ṩҏ# n7q2{B: X]dKETy*J8˃rT3..֧"DȪ: 5 ],K4En=ه&#oP2d$5 e۷ :KuG};ҳ>EUc믰Wt^wMoHY9jzˆ+<oS轭b7d+8I.<^4QrY+&tŴq'."ykmO]8rO㕋nNЋ]Wn 8ve+8ԏO?o]l \vtxGgs40m-OI;5 MБQ(2fy9z"MM«'Ȗ-C (eIB(HSчʯ{e(5ۀVh^O(BpԈE Ń7jN>ywcKy+>G1:I(js{^1.?g\j>`Ϩ=Ax36M05 ,:F$]tJ1:>֭7R4ImHuT?[`y5سOS̜ FfH}= eހ_TslC t!32/x.''vo2᦮Bɢ7M&}h0SEFsaXf(E!pӰVˍ%)$Ue6P͘X(x4[LBK4\U0Ph,D]m0ƒ|cE9UiZer 0UL0,ꠐ(l4f[+0ByaiU] IԲD-刼`=U J&TYa6FKK TjfÔ*ި/MrX-LTL_b0k)Fz(2V,]@I7@!uz[98nA/@dX@j+R?@:VtUv]lnj^n<I`k۲3a,wykZA7?FJѼnTN"^4a$ #U0(0&!0m”tB5! `[랉1V- z.]22W*5Rtkc)ᶕλ^|n~G7{N5)7Q䮨{!~SlZ3coλ4#D_&j?u쎫E!߿wu$?#r -}λ./Y=Rq_cKE :7Y onnuY)B X~]3Ѓ ފy?|4t=/s\E<)lb|$l44.&ts_QDzq[މm2ܺdΤ+_1L\=߼o .ғ/4мo; .i?Lڴ=8y[:gV5X8)=Sm}>#YՈcSĨTyӾ9tꕊgŽQ> stream x |SU{ofkIM&]&(JR ݢ-kKqA*Pݩ **/J0(0.h>>I)9~_Os, C ͵?}W$,*l1]6x :|rwtfȘXYU/_ }b۸ߙ/G6{w.BU 0g/uxkGL@5딅^{/*%]`?N9cwVOOܵ`^|ЭSZ1| ,\z٥꛰c\[|f0Q7E>ea9]9a~Ǚ Sp!], lO+Z<빃K=Qof[y_C`v~Em[vd:3V<| n#_: 4 _3SA.)x0XD6߅QX(^ 2!zn6(o]6I>!f=ң{gup'+Btcԟ_V)0*aBÿUWrd_0uJI5*+'JǗGt>Ie*\6<+fJX ^,x64b9ӗ1}Lĉ94ۓzEܧpB("}PKk[[ N(Z*7r$L7I;'tvvU:k;pF $ )#|J1#‡A 'LA&Ywo"IIQ FK+/?^!Lx"Ÿ?R %#턇 [ ABo01 l & "7pX^Gy 1?Bى(-87qk+F6嗓q!,#M&T>B0l"bv}w=& e7 \B3z@JB'L&&j 5jBJH;;!HVO0nBE9r{;C(ߢ|5W(|ʇ(Q^@QGyYgPv<҇vQlE>?@6^EXI85hģp e>aa.0Ah'&"$ L'L#Z 'N" -/C!d܄,B&!Np46i ''p"w22)UE+_P (/w\,8/<r j߼ƿfͫUVխ4lsWm^*ʚs7Vĭkټ̯YiϮtm={i5{Q{[n//{̸5WvqC7gnMtҚ%e ]_񹋹yLuqZF5K=j9ڰ8wopV"E-ZhӢW/Z߂>޷H>f݅C`@y p%? qNCC9ſ`)y;=svlL33<7OyZ'c<-~ߴ?3?:uIC 7S v4I]I|WIBWD~'NX kuuuU<+fM e\cs>+Fo3M-za~K}H/ۢD?r05zvhA‚ɫu^PՕ:ΧWtieکZai]_Cjާƈ/U!Rq p΀qj[͜ãEoK]ק 5fkP\魽wE[/W؋c)|uPTHjn ܖVXIf(osZҽdR7~Z+OdRt `O8b ChIn,#PDR,)Ou?ٓ~vٳ n7f ã$ pjhq>.S%g_/0x|!'@QpCȣi6`(^: ńO n|Iڃ\0_¡"/e~)A孃[7ל.X p,p.`5\pmZXWza\uF x q,|+\'Ų;@ wp/܇ߣPG ?vރZOz![a#>x#8;aq|G)I4Oϧa7<s<g "쁗_̐^?_p텿o;.qAby;=L|)1%4oIJ%żC. q<]' 8csdg6[0Fޡym ' 1x#q.Llbm\x$X9 }A J*Ef#X YbY0+22<,n?Z i$O%>W|b;'j?0Q8!fq8`V1Eq*Ni9(ٙϩՉhKSQt9J4b6=)MjT2&)/,&x=kfAB}>gΚ`ٓ_ݻ9Y3ɛTxy;mN-]HQF bU4WBW0+(ke'&4tIܞ8[0ӍGEsҲLrAeqXL%VMAИc؇qg06Eox8Ac2iM/UʥIHNjּn#r沗>IR_{Zl/N2ۮ_ZM@aLQN).`DlZɴBm.]y5Es6BUzOlWϯ(nhOK17wsд$-&ѕhJЊn=cTJ#fV™&ř >*$Xt؟Gݮ].52E}ǧ5KNgp|㧈yq{l"ɔbݪ-إ:jmҝ?p}t9Nq{18lC41fZ'LˢFGda#[R24JҍmugwڵӲOrc6Xcզ :CS*mZYURU6aٽݿxl\Shq8uܸiwV|+[|^~fg1-LM0 )j74|2g5IIuca6YkqsBz@%q޽zR0g~qYiG!o `B]+[ tZ{~ \v-. ݕoץ j?x_l7ތɪܵhUdE 5Ԇ&j,fQHӸku%kƱ!6M\@>kOcɆrs?bPr,+$eN(**-܅fUƨQ7j ?dOk7xΨVmLK.77U{,>~R~lݸǼF2wW(3bc2-=l6v!5l 6glXΰ>8646OIPX*L=jvgb8A&zR=Vxue̢UjOŨ] W\ōgr gEv8)'3p5`'?ᄣ+>nauO^xqPnm6w] m<_qACcF{gN[fM߻lB;v9e5+^$NLX>)vVk$I Nx]roU(bMsoBb-N lƄt^H_kM. BXsFQ.ǧ`g6ydf6Lئ6Ϧt.c_c+QYƣO)/xbI  js'J̭`N}nU6ό8:&zhmN`\7RhNNM$g%hR2RJ]ey3D[qbBRF61fr&)~ ]:,|3; >"&bb' vBܥZ]dw$eZG&S֚dϲj4,6kֆ>=' 7LJ\fͿH4|o=v 6V_+d69_:5&v/SԲe.rJahe Ϛt՞^)hi͸܃}J{q~/Zϧ&7Y1St c^ d o' s1Eƞ$lV(ܐVQa5drkI0Q#q(6)Uj=u'us(:N4AxhJ/aeV*Z %ZZ_ϢݔՔ+jި [\Sl11Ŵ_?uϸ%B6؂kA”U^P\#-I=}*Z\>tE9Ѳoub7;,*,Iz\d dS2rAc="ke:K -CN.7]EBpA1\}x'? 紗_SǦTkmȺj}*ˤl|ɑU^yӄϗe ? 9~h1.hE%Ȱj6Θ-`ճVc:&M1 yEzIMS/ڹKjƏ> +ksZs>ut[3;\>ݧ:YU :A^sh=k}I.QkLkX'ޣqgc/%??EC4NYNgǘrRdGVZ,3&QgwX4r/ԥ1U4dUk&2[?*֔W<7w ^]#w PVK /rM" =oqjeUs QxOu)E:ctffQ/2Z]NLק*xa#* wx) PO gBz+37ru/\~|YG&^rka"h>_e=t`K%MNw&QV?dLHB!"WN"٘@ZHRk["Zm AEpP"yw&Kw_<{,9y˜jquvĻ'ywJ69w 6˹0@, n[fY{hN-ZFi)ߜEJC^5{"grWEbɭ?S'w F8!AAǷ~h2ww7?Y?HCI.&Ք׈'&>}Zб(Bqrnzuz;-]blʈA yשkKu?BkW!=C´?=Դ?~#jC)+0=p_R ''z-"L*GNKd#;L6tIy2r@uCtHKd!W$j!s:C:C:C:C:C:C:C:C:C:C:CDnL_4k*>Y~0]?Lg}v^X̳DaGXRoO0W8Er%LjReNb5к?4Tψ4Cipuў#~KF_?J_o L;}e,0lyjy:Ϗt,Zr;=w娸Ԟb6ZNכilՋ䗡CP}Q@1ag酏6>jXK\>J]+ZCؙj'?3rEvW!e surc瓄>Џ!zeЬrČU F9(ky<>k cR,WțshIҟԟ| }Q?=bibfk u55b?5{_#Wylq Rq^ZsKo6yʟ&#G$*; O&UTGdd5K>xyePSi|e k =3T}00[)y<ťy/!0ߓU\XTYT/ʳEyoiyInawnuBSMDhh}ǹbnr4h\n(tĨ]N2돍U/+ E}"_vSa_=uHwɟ0X_otCśR[笾nwjyvyd~Vn>17i7kw_~5E?oև?? w>+W[@a>k]џk g. п뷌ӟDBDP{[=+@S ߋ~"Ws-?wEo8; џ_D'娸C3Zg1Ga蟀_-DF F/@C-"]T߂|sEпGIYXx1Sosi8}\'6nO뛿$?nL}=#Z2us?5g6aWmQWWnZ.Pa&4P}}#FEG;v*ԧJ)P 42ƦUe2z>eTZR_sE)Na)2\HQWjVKf1ޙ͚=b͚51Κ||RZTTUV-̨bpS=B 3*)vJݐ|d{jaF=bjvGQi5jYgB^Q͒ej%쮺B䚚a媒ahRmu4apFS)7!: Kņ 氫H6ҲUi2vưy]s8f쬭+s:B&BYK]}}CsDhk8"5GT# ٖQfgRk'?m 斕0wcY*V6 ;Ũ6Tq꽴#?ZזV558~}͢قq4gh2Lt9mҙU*BCct %z"rdU/ET68)%-=mAtpIjy 8iלαKY{hXu+2kݲc3{wlUBiTҜэeM|3egDCsF>A#[j09T!(vcUWPq~S͙*Npu=>iCe 3?,ϯϯِVVi"V> U"4eI WTіcfTiiEE--.WCD:Cf6Pi"Ơ!E~,+eoivAKKCN,nbgN*9\'TRȞ:U5_vGjQtfo-VQ6QZdLcjcjSEZھj-[╖A}?lX#ZK@5mҶm[jke6Vciac߮o}&YgVc7%"c#a9EjLMMw4W`3j%o8cl:.պ܄;BKOhpe#G.W#eh5Kk2krjH](,F\+1bd2W j !wUq2ז-ř躲Z%}\&5Jq EVK(\={45ɕj-2\QMHC̺-744D:4FHTN#ηlb8lUd9gJiEI{)s-وפE[>_c0RR[$cb; E2TDٵ(ϘGrtCBSe2EOEDhQvu^Q=M[ruR{v UߢYœS-y޼btQDL&Emvy:{;x Sύ'cx7킘oȸY>mG>=D2N׉;9 jH Z* %b wp ?Ua !8%Cͪn*LVT=kKT P3*\—Tm XҌ X.랙*d1]7F8;I8TO!͔siEm\m\\XhvZuu{]\WOzE8LaҭB7:DA)J1eO?-~ˋ]G56g#uz]զʨܨ{LZܴ)m7}]w=B?Cƺ+j%e;jʶKȉErPE?ӊ<&kZb'ʲ'Zɐ].!H0YmJ@ܿvolq"JZ.%,(J6^R>z6$nrCP&]R2 ^Ku0n ^ra .%F & ʷm"$U%?'U*2ӷ2WCSmJHxS4hAG$I됭ÐYww#a\*J})(SK:'4zf)V]Nc{}:(6_!O_p]nݔqmk~2-#&91jI+ңOWdɽӿ%OSSr4OicN}3e )VaU1UIfF dfTdd=T2n-H?OݪmnJcv=y຿,z(=Zx/V'c2V8*Qպ>FU.~6}&RL XwXcԋ]XADžNd#bdʮ,{UKPp (ĵ>?Mk9(K'j/L%j[O㻑ވLݩm;j*ۤںg.g>}ўSGC}!Ւeq@ڍ37dqcFJg֟$V%>WHuV uWS;Q]Ԟ?9&]U..vJ{ҺK\h)){/[ 2BsI\l?u^ Hsrq}.O ;Ji͓~[tT'it#ﮭ#M $yR2+Cԉh:MsSu&JT"%):-;*,.)x1I{ uJ)aUe$&#wKO2֬zC{vNΐ5Ie~^<^q'Z5)jO$hoOs|n>h>,?GIRo0nؕ_Ӛשi1j F^b RS"JpŽPxP$e< <?߃3[@ 2Dv+Lv(Ӵ:ѕ5i滄<Dy)=_1?(zZ^7[H1h=)|{aH7D4#cďC!:\Z7XJ\g]Ɗmƺ j]DmjsE-ax~F/D\ hp lhρ\ȃr!D-*=~kBƾdψ8v^ o냷mmx[v3k kw%Go~p5)ҕUE:+戴RgPxrg$P2DtX-NjE-%ԒF-i91Vۨ)W߫XSO xf <3g3xf {?vO;isx1<icfmG_nfBd럛s^kxM 5&^kxMlf$fF1(fF-fF 0*F#asXV?acXmƢX+b3V `V ]ذe*3sUE/Dg3Ѡ}(>5]}+BbtO'nI7}>ftO4{e7~~~>iiiii,j;S$2O3O1O3OE9Dnp}ftw;nN7{ftw;===̹̹̹̽=qn87;faosucas~?߇OŰ{i|~{fs3R#sS3ػfYF;3DYi}L'GV'%URve>)r/>r$y:eIyMtSHA Դ)6QSL/l(b(2X^bj\WJjd89Y1Y1/9Y}ų9)]8Y&ȝE"}l6箻Dy:KӲDZHiY"-Ke,%ҲDZ.Nls%nJ)馤nJ)馤nJxJxU21d %c(CJP21r#6y%m:)Z 6]889898989w -X3eQ)rZ~Ha$`H!Ca p5Q hip-` p=7D n[`dSa<~jx %_K2k:~ Xo[[xѿ" >m#& u<ߢ>lv;9.fKl>l쀝z "V?EA > ?Zu~ex^mrϹڬ@?h WzzC WA?vȺ5o a'm M7v~n Dl`8!\ : txHnz~;~{/ }/\h0 v0g`"sї5y+Bʩ>XKOriC: =8ÃUh& +pB$DA' pCt ׮UC"k C2  `8a$TFHka,\@gznp $H04пnp3Lfp}YKAX< uh+S~ OogYx5g<` _Z/+*jï7ހ&|lZa la| V"'XENJ?*]>ʟ>ƪŠgaųYX,xV< +ŠgaųY-ozxނ '3 56B-l"ƲvXp8]!Du~#V'?C|~S2f'kH/_FJ7/Zi/ {ZivZi' l#a;쀝𡈱B7oxV}erwgsi[>i(Wpk\i_w ,j?><+ 3\WQO9L}[9C_:4tY5WVv%GWC~ zȟHH]q .bb-[,Xlbb-[,Xlbb-[,Xlbb-[$Ƨi| ;}a+2]b_#5/yzhS=}׈}׈G=b{{ޓ2tq5o.걮걮걮걮,qrh)TAXHYoiIfdWEvUnFnFnF8ƙ6δq3miLg8ƙ6δq3miLg8ƙ6δq3miLg8ƙ6δq3miF(0B P`#L[*Rʏ͉FG~qN?>C6=WO'O[yWyW111JVjRhF+5ZJVjRhF+5ZJVjRhF+5ZJVjRhQ׈x"bt8M/ZhPV ?!'{+^Wkkkkje>uNJ|Vsqb\k\-3 7^r"\kqKm|zcب76ꍍzcب76ꍍzcب/6ꋍbب/6ꋍbxHQϛQXA5>HF5֪0vT[{l[{l[{l[{l[{l[{l[{l[{l^Ys6jg(zϪF-:UD~?$7&1鵿xUJJ'hOGT{?&94)QvCe(;D!QvCe(;D!QvCe(;D!QvCe(;D!ʎ fo6%GgWES$HS$G"Y*ywxwxITjUE.vQ]TjUE.vQ]TjUE.vQ]TjUE.vQ]Txn/-xr+VEoX{u#G<=Q}b!da4Ļo1WcĒ0b_JϵמߜNt@ﶗOޔwoőxx;< |q!.. _7p9`! XS55^oĢPK>qG(%s.B^)v\$÷p=DoK|'_1p8 b| R\ mWW QAa*&VWҒ<} 17dRS2qJ^Qr>L S2aJ&LɄ)Q?~L1cԏS?~L1cԏS?~L1cԏS?3 |gS4>.WUDžk2|nLݘ1ucԍS7fQwHOb9$MjP]FnwWiu.qJ]ĉkڰG{dRχ|ȇrbykةv*`ZzIoQ?yGyGyGyͣnuG.WUXcQE1XcQE1XlB 71XmjO꩓Qػc/ߑ72Aѧ(W\+_kj7¹OmVsŻNnW...2K/QDK/QDK/QDK/QDK/QDK/QDK,ʲ,ʲ,ʲ,ʜ8g93ΙqΌsf38g93ΙqΌsf38g93ΙqΌsfvZG[*Qvqҫ9+{t'[oqe]vwQZkRِt]:@ut]:@ut]:@ur,r,r,r,t/н@ t/н@ t(G>JQ}t(G>JQ}t(G>JQ}qU1X+gÂ/pcbx1F'aڷ$: 9N<_ ~^%N@!:81jI߇)WP`6z>yOi8#Iv6b"MF5􃦫. kp-{f݂piswNeO=>#L6=a s?ibj܋؂gkav CͳC`v COܷh-ay9v,Vu^Vf墨yn8URu+5K,RH"%,Rq+TPB2wPp+RpR0O<wP0 `Y f) `Y n^zeUW\bU(VTRJ)UTREJ)UTREJ)UivP*K *PX'ֆG(^BR!ϮKU2{~"2\yM&C&YV&wk>;<:0pS2r+@p7R|ar~X &WӀv"j#>'|ڀO3Yс=][kwUczOtku|B'G͵HsEx;NͻDw𮣧ߕm2]%4!&dј,eѨkEhTVʊQ1*#bˆX6eCY6e„L 2!2`BrlcenM8kio}j'kx+;W\J>?s>?tEu޵/χ<"ܟ|/%qG86-ϖ$qB+&9qkkeg{}xYO~g>sY:q~C?쫒FG%as;aKӅ,:PBeBYP,l_{7G4݂X=wz|9+=M?4$ou4x ?j!WnMO5S^M3V6◞ۄ4z}֋؂> ٯkoCn}*w١zUg7lM9æFC|;kx+ۼh?;q?-h6lQ oiu3y|n-au~ZSթu+}ν>>O ŵWu =vC:?VSٗ5Um*U.UU5> W[TT*s١JnR%U38=%_U&ֆcfڰQz@ztgugMgxX]Wխ=lS9+OW'U].+߮_g|R ^^UKazmhn`uGh^a\>W`;psxVWVWw߅}=>>]ay<XN̓y93%+Wsay|X..K[9Wծt;N_&\Zem09ˏ-4%֛:JMrӺyn^S5K-T"'~sQWl/e{F֡ ///ɑS~]vPޯ]:k%g6/tΗt:z^vY\u-zu:zm.6 bt.]K۠[[ NӠ4;uN]S4+ J]Rn4mЍ^NҧqCː2 }E3 }:Cpj C:@pjT_׫*~_׫.ޥUjT]}PW|*S}O9쌫{Tt*UTZ_C**ՒkkxkTD b^tCTw2>erY<՝rY\6:hV%Zd>zd>*OI6hFFƲw'Ub|6|GcMXpDGѠȆD6$^"{Ad/X]tս`ue{VT!+!)[Mjfj^U EGD\2j0e;䨶{ZUՄUs&\:&h1p WtAWńO:#l|7rszُuܭ:V=^wcTUo,<C^kɤHҪ[Z$iQU@^EIZ$"Ť ȫ ȫ ^6|DžlWO9/9/5omeԼx;I꫿dW^ګgP ;w띻]zg7w냻|Z޼TdMJtX'OswguzŞu=1Ʋch31k贆ְrz_iV59xzkߙDZfM۪kM#Vkq1su6z\okNۢ|yf@JZOә8Eꃮ}Vٽ^G+^{fW<{BS;r-Ԓ TZGN*U*$֓S:N')$'Y,4Tz7PIowitFoz/{#UWD^jZe KTr/{K^*RוJn/u{K^7|6[1*Lt}Fx%J+m}vFڷq0n^1iQe3qsx|[Ʊڷ]޿|8noq+0w&qspg%YTj Z8P[Y"lk>gx9_GEu>cg3NVw-~kwPajz<^):ؽ|XJkC%`f|vW~.nvݮ v4M]4׿zͰ#:f:K6=܄=܄=܄5=eMOQj}\>>g~o-oׇ:o/V+[S\e{=WٞlU*[SWe{ kz>lS)㔣+ǵonW뎎tn۬qWVQ~(鷯= p p4N}4nh4( p; Gi8jhzp4Ն6D,ֽͺ3H"YjdFYjdDCTR!K,, BM})&8 W/SOIע+wŒKZ,iqqőGA 1ŐC;m|xtWtNp>.pkt5E;O] ƽfXMU ffw]wdTqދS|g3|Ɵ,>_1q|>Q3Ws<<~ a~Lixnw_:}{C>뀷/Eɸ`6!8p"މw$Ƨi|y|p^xD>"s7F  WJ\͏GeѺC& UQp+nq;[zQx3U,0<~{<}uH0wxСݾnK28<"s9ȜGd΍2z֋W=:Ҫ6mT˱[Quj%6!ŋ؂>~d3 kș'HF>:}b>NXO+Q1TW}h}heϬu>:A/hP jA7u78z尮"`!&h@5H=k@:jmZ[֪> 1ujnm=ݺFf Bc57?J9R+khA|<_"ϗ%|oIubgX]5}p>gW7su)Wru)Wru'8%:)qaecaEltXb~X0\.I~1|׾߹]$МZ/F}7e;ú.ñɗݎE-u  WJ*\obDX_,-پT/K?(c_V/+%3_OBnXԿ)8-:IOYR>/+JcRXܯ_/ꯂ\zw{TxFPi+TWoo[5;09r֨5*L %>sVNzW>57H+(\&nR&nR&nR`)V7}܎;+p'V܋@~xutX7Z\oz,| .qn-Xe˱w.;00ͪ`gl哣WTYn֢ kDq } f`CQAdvYX8§|ya.@\PGq!..<0G7MstӔnMSiJ7M)4tӔn2wsn͙9s7gݜ3wsnǚbVߊ[1+obVߊ[ѭoӭoӭo01"v2Siiiii]}XW_/g3{=}ƞ>cOg3{=}ƞ>cOg3{=}ƞ>cOg3{=}ƞ>cOg3{=}ƞ>cOLts<?i(mMI6&Q$JDi(mMI6&Q$JDi(mMI6&Q$JDi(,,Yb:gu%:%:%:%:%:g2J؄46G)S;kI8d- gi<4b(&pZk2ddcUJcÃ.S왨9nHnr-\ʔ˛r0bҭEG˞fr-\)bʵr-\)bʵr-\)bʵIvy;鼝tN:o'Ivy;鼝tP wX{p/s9ǹӹӹM)S4eLє)2EShM)S4e3+̊}f>bYϬgV3+̊}f>R7&`?*~ 5a2/6 L|_/q8e2N YSB)!kϙ+TN Y|I`5ʹ&}Ԑ!T#@ɨŤoq:Qd(NYoq:YdڷXϽ:ed ԿOq{ZtSGaBG#u:yd gO4'{3Π`J%ڙߗ e=*}{lhgdwz4:{TMVS^}L=,;S'4Er%geiP5v6A>dp.`=SL/bHI'Ơ KāKāKā;Á;Á;Á;+ `l;mg nw!Npa`CapsЕ7\{2opU**|EDe7y_Uܬ喚2DnyVVה5S#kH5^-)/^󬗨)rjz璯p+n 0m=b[#m=b[#m=b[#m=b[#m=b[{KL 0o,6{%#,@),OAS| _?l8p,Cw;ɺm 3 Jv7Mo;0e`SpEh"4\ W3)~Jh"4SfLTN)B!hDTt5PK&Ogib4oDFĿoDFĿoDFĿoDFĿoDVVFĨ:ˈC#bJΈx3"ެ2bg1!,#, p0]'dS m'O7-S׉1e&z)ZҿʷDS9K-Ӣ }4}J~$:.6qN9KD'.>J̽δJ96XH;S8狄\.WΨ(*-7aO!7!RlYA1̖E̖%6D"4{O cqJ<7?Mϓ}7SD|}JĂ3&ޕfꭼ/ǀ@$@AE#/}iz!5}NMs7[` `p茖ffFF&kk114jR`45{_|G# {hG8Qϥ]!+K1,t} ߎʱXJI$/'8$qCR"v$-|E iy 'SbJ7Br96fb ,J %e~϶؟-%x""kmRE55Sc%5FgKHvvaG^X-UjJ%D,[EG T`H=Zq{qrעdnzȕeG쵙e[H/br#u{5@Dj, `ZKFUDz*,58avek16g3Χw*(OcjzfFغ-5—3vLX.gucRϲcYlŽt XIߴ ,+u( Gp*IcK6Z*c+aD{ߕyQJZW}:p=Son/qQs3ǙsݖU̙X]M+n}EՎt) q])ۍΨMsv_@¾"싰/¾"5[Z^Z\wL{ܧ RHߥ>5dW۩i.bz9y-Ѫ׆cGű;D^3hѶl2}5'OK{4uކvw#SmM6ǑM1v8Z5#9h! /EJ,>mxߖw Qudhȥ l5g hZL 7gs2c"^mϴ$W+z5԰@QHimy͹qek=B!-yڙ> <s4LgSk Nؑؑ}{$3ש!\{lYo;Sbcթ# F{BmMIiP:W9/\:6g%ohs lU<jm5ojYOdMM5j`#V;ދ׼rjfL?5հccz%=G^葦^˚XՁ^+$_%O;p$ړ"_GQj)4Y,Ut6 ?;,rq(ewb-P7=;ޱ͵׾{$Q'ܧ.qXTI/#ijzQ,L^b-JO '%rZNI,rq%\>qnpǹ::8 RwSpr^u׺izw3V;\-ttޓJ&eJ6v|,dKgl't>QNZQ@9͑`7cX7)ϻ)|͓WFr6i=B˯ܣe^uOc3SS^_oû{ٽ{{}7}ڛ-sVxڝKX Xc$V]4[[[ǖǖKb+b+ݥbnelSl:5]UQlsuw DŽcççs—3t3{~pAQ=\=:w! aMRnHzI'ɼd3xE?22,LvNvLvOޞ"9,trT!oGcG$O>?|"9!9)W\77ן8nn#s7n7~'3){]-ڈòJy<^GyU[xwB?_f-ګ9Z#^k-ڛ]zNo`|F#jkXQWOJrhP9ּDW;[ו{\i{RVر575z^&5!u=W/_ao>˒K*R^+ũ9P/[>7{oR֧!z({YQpW*=9=`lYO#:k=uzfgMzE/ lOVUzټ[*>[n|$;.DK-l뱻lw]-rJDL/8@fʾ9N߼ScO3Ļ>ȗ,e v:@%2]#.x&.תa=`͖ݾ܀Or^z+\ k.m|Yg^٣ՆױY8Ůd^)}>K/z#ܵ>S9fXmČCS&9{[So:.M)az][μG33Q c]\_fŏLPt=U[//쒢~=:]g7yWUNOYHM&᪾WfXc6J TI0.iGèJaj8L1$eIQjyRcHb85FH)|ROH&Qd5E}A@?^g^VSX'4wlꜧI@jZLmEZB,U+hkZ%کT%=ZZשؼQm$&Uj3lQ[FժڡvzVZ GX#kx5<a zX0LMgD8MD d=(q3"$P9rJE2"_D eh. pYL$r,+8"\!+ÕU*\p ׆kɳ.\G 7DAXVgsĐRI#DnGk9I6IQZIYhwlfKU5dyI"P"i&0Ec S4N6O6'&#Gh G,G,GYhG`TL?v?S Ow[K\Ӌ2O;RVG'zgIm麏jg=z}_,xNhz4Y%ZQ;z~k{Zw0 l}qm}O~ GX̺s5ØZؾ*Ou?ێσe"Ϙll5{,:P [w1e`;1<ώʆ>Wj蒉J뼯7NkO/:9}Xň^nuQIn{W`f߃\3>cgTYf-FMQ =/[y-ǎ0[r=˜-Ͱp73^y"#g3NԷwkz_yo A!2]hH5=)3fpٺJDQY<ճ1рπX}e"}v8{lv=|K<ӫͬ{βsMd]$f{Uin?[lirLA~R߭Gv5:E?=R?0][Z9]?yv~Jg, u>Cfj kl[vրϳlַ=Mͼ b]_գI!i8|Bîg7u}U;: >U_ l^IUbV9؅j%Vd*t]cv?dڂEu?/߳f_B_b#x*>U}_E|۾xoŃ[vjϏD-=lDYɜ5ށy>5s`?mviwgI=-d]9+8z(۾{׬f88-f-/F:3-߷k!euw |`jCيٳ]l[͞:-)m|xřkS(7%o9=r-Ֆbd<@랹a/. UZ~\{Z}|ŜG8!]/?}ZE橆FdnTniO۞NJlQfuXo۷_ߴZͯzk3=v[. HfOdU㔠NKkcؘ;Zo홖Gпn5}ݳ_3#2d{NE5i(tHߤiUqQ2""ADHP ""BXC5z², 1b,11ZCckk5ZZk|,R~?*̙wޝ=sy^[}o~Ek//湥O #b7R#t ~[6'0w?g8,^0K,?tԣO2ԉa(?zl7Cs21p{ V~_Wa+Yj! wz{zg淩7᳥ ,[zw:6^!0/0=x|7P~o=k?7s_7qYCg/>?'?{ƫL? |våIkg}GbEx?Z:;`_4ZHS(DB5K5ϰoh֑Ћf5tj^b;5ػ\SB쇚k~~$d Sq!Wc'P!`%I`YE&;'^`-vQF-~'#~/!=O[ !#N?kj= I.MӦit $P6OѓP iŒP.~]]-$g/4\Gĵz4YoG,Z=Jϣ<+Ԉ(7JUz4.ңi*=7WxJUz4+?kVqes\G͕y42̣y+hz2\G+h~ƕy42WseA<+"W$ipM!kù&5yq\G5y ҇!\GxTTW0Or54" |SdBWpW~Uqϸ*qUUqы9I,aڧvuVp+Y]pz8.pq=.T(ohpr=폹0ѾpG~pgWʯ_s5oWhhor5!F)Fދs!泘"al&BbǨP1DX,`mδX]G"F&OMd2Q"qD!־"6kj1BMGu[aq` Git`-l& e1aFjHOĢ>&>ND$]&kd >I3 ~&HYOz"H3SNFܣigS5!McvBU}hj^d4ݨYTafQ :^ɨ9Ú1X*TyT\ࣨqTfRͥ;u6VzY="@EGyU/"uy 凩.'.8PO=jѩ KQSHz*u"{D;J;ehIlQY:D`&ڍ Bm!NNk:DG?g7M͢gft3Q} BhgTLnhK=lxķ#6W"^eEl#-6T|(cXV$,)X N1  i4ӋK&b8Lj3 6,ȹ"^aߊeX?~458upx=WOXx[??ìw0?W ssV E F/ l"X$J"`1qIfRRʹ"),AKz# kj±('IY,c8v4*b&!GGCR$i2LH,?Ecl6U)N(.\I!/ P*ER Y*2W13g*q*ɄqjzV(%++lgtJ.6]jP7oJ+X*bnɋT! 0BP bJ]%X(6XŦJ]R+4%zXm }ee/m6:o6_6)\YX1LiǾ)1Nػ[ڍcߖF|J#X:rڏO"t9& 9'ɇ҇)i4K>>bӤ3y ?>8W;ArnKq>>|HH'X6~n8Ӎ`t,GKftct), lc"ץastI1].ɺ)q].#LMEf.9tӰ7Wxg)"HWtt?CᬅMkZ`-@ X K䬅’8k9ka#9kA>X |kZ4k8e܈0 8 2UY8~? Lf<*(p NӍK2.G~w\mlg9ܔob?D̹Q԰ ?6cdld,##YvCǹ Ē"GGqTYLԢELjW/Z kQ_$j) -LNv`N愜?Gk-D'bΟXnIXΟ u,YY,c_PQaÔr6V)WYbP lRT0RT7)&(5ȩUjS7+ aŢXcUlȱ+vmRl 8Y3-J `f@z/(~%6 Ae%RESYp. 9Ks҃q27(s{_Q^aM&9ηe(Qf([*yCy{T)gN {VGw"Lc KS~B{a6^y_yG#81gPNbLHZ9 H9ʯr| ~kvQ&pƀeh}>Wq8ClCkw!-}пL0Q63QǙ(82b,3Q6(lbq0 s!R_z_$NN%)"N@2qHz (pTDR="TDR=I@!TR=I`A,%Ճyz$Hph0NFOv-X.q .y{9}k י_gf\ss;%6Bxu2kbH!tH!헉>&tYWf &$)>L\v cB?C:)ZV"ҴV5#RH3"UFdxdbS1O#<_;Z8͓7gi'7O&%ݗ) )Glr:b8x68LO,!YL ib3A={ ,b3u3t30&[QHoE$V[hG#VDBBJ)ĒJ$Օ"H+"(;DuE!TWR]I+"("Q]IuE!TWbIue$!+"(RF+"CTWDR]"TWDR])"B+"("H+ 2TWJIu%TW3B%R \IV&9B?P(M.I\6fCYBlMrrNV"7͈xd| FU.uy O(_QOȥP~E~pv-̤niuGP=)y0C%ȗ??gөxb "HR_ rxp.b&u%E̊LL@122KQ1*2%2@ az%lDRt#E-C*EEQf%Eـ(+ĐN )đN)ĐN u c|9ztt*{,z^WXQ1z[0ƻ-:I,zIKy'>a OXȳnaw{rs=4cMzL4jmL3f]>a̰f`f24n; Vºa`a`;``{a`a`'ag1y2! vvvv &b箈%Rl' >3oYf`q:{S uv;lgKa8o&KU[<- xۖgs[-S[^b)(/,-0ЏT,K|*ms|.,uV$.;?Ŷ8 ij}(Tbu/z*m`c[qRn|+T*\yRIE\fmz[a \aq+T>rXe;-wYNKV|+lG=?b 7r,X,|+zmvwƲwb7r0]]SuM|iSˍky?|elM\s<[ɲwNc+7&j\јJ>G5fcs `jc)etN=k;-}7+ 6./-c9Srwq9q/i/?d9FT6ѥFVV\'ExJ Hkxkŏ ί;:}[ 95墚Pw5 x5[}G9__ݵ<__jr"Yi :_Mh]j]&w_RS˯[`B jVy}o-+SS[֖w[% 涮vKZ7K[7Z [wh`jA]jA*j c/o 4PKyd8>qD̐h.k=8^}9?p.gO8.^>\fk7 gic9U}ik4cn-[NK?_mw|-0޶,seKX`^> ✫paeZqS8#gmKҜLhpn5e;G$Ϲ#Zm.osh*r]3Ͳi :n[1-r1-u|M&IpK/mכ3*Udw^jdjq^mۊ뼍ڶV.YovŴ1mpŷG0XhNV7kNLVp6RZWUa?p-_ ݼk: ]7n&p9 6\P0 -%a8wJk.UO`oycpoM_*kX30 vzk[og}w6(oS;^e[!6ߝS]^mUm]ljuۭߩ5nmoE.*jKmԖo[{#jw.}wRmϝQmΩڇ j]RۏqW箩GSOp7SuEyhXX1lXw[>rW)>^n;|JmC YËPR8_J 'G2iÙ|q(/ï-T.+CU|uh]x _xW*佡 o΅y5$%+j P8 7-ܩKKPOx+ Cû@x/84> B?Ǡ!Tt64>ΏοtO&ZOCnCS~K3w %/ -9|EjikB)j9B*ڊ"iEmUR[aJTs,:mCG`6v$Vj)кSҔZ#Wԑ Puv,cymPvf֎i;N۱Zkv&hڡJO;ZZBX;ف6t.C5;s㰾W oig:ZL;2CtoBv[Ą]{KWLcՎ^_د]û[%K!-̧|2Ʋf}'  LbS6]Ffsا#o1kc^#)kbJRc}$-DZ?&V ku=ɰڭ5f}N޴oiX'׬9U+y,"KH%yT:RNɷH d+L/H$,&3ϘGIer }~YT3n&0t2ۙLm 0?gތ^o 0MVS2ul2ozi5}`=wLl6oL2]~t~b)>t E87 'Lצ_3M5;wi6fOñ3=>s95?e~i~ڜ|f~\ʚkY\Z_7׳iffY7[^+{o[a>m>6ϘXl7̿4_eAb3| o8 ~\b#w-c>.;v 8/{41n;qCy0q14qb8&>Oqc1+MĬ$c^d[TZ~艘Z?57xu01;1d|)%&9&<BRbrbr^SzLqL1Y2w<'aL"DJ#?HR/ULrJo%ARAi&u±vi[+J#qtF:']."]n±mo5͡2B2=3d+j6\Wɪug| fy-{gO'˃HPV(A|rWg|K~fװ%8')@1$ DS$ő/YH"R =@Jɫ`u7T㛃z Dy|8[t^]'H?P&h,Г0@9;&c_H.@y_%'7o`Sw92 <2qdl_>e} .aҙ'K2fyX,kh'[üԒ2uLy.3^KlȤ 0Abg'0/o1]M&o"o3(cRϜ`~J\?2H8g)£z %גKd|zNRk: YޱCam'-B1Hdr ,7P(&_St1KbZ\+JZ]PqEwbOQxJ<+UxK#@*%IR-IJD>@?`ʎx;? nz{}e]}R!8»/àuai,odTR֩ \SYik0ˤ;=,m_DŽ:b{GAީ+͂N,Ҿ)` ZO\H\Ɂ 1-- 13'(4nN@ɂ( R4R kv,Pyhܭ@'tACl pDѸWHSߨx@,  @xPxH.n m.3mz9s/ ܅!``.̟CcD^<N/8& ٠NF gb0( M .&g@_\aVS*^ ΃cZ`^-5{N7sp;h9)WN Hp:|FS c|ꯩߞ=_Vy"y>J"_g1WFȈ@~|!>@-s:T.鄢4|鬲i etQlǶ6]t{ueg-;Tr@(U+ED HmrHMvN9帚JmwTNo*g :ƙPrNV.y%@T%t&kPnmU AƸa#vi,1fyxz9lt-"NFJj#62ҺCmACb@fqf V?iNSi9,Eo'6gcq?9c iӌռҟ\Bys)uff;Q*ae3n0&{mc[W63јLjQ/zmnmtj[p\.8gm0" 5}!'\9צ6wa#09X-Eu3\H@loq،^"qWtEJ:91t!EcV5d5(4UZװ\PVZZjWC-ZjKEiTuEZPa:ܰE=Э4POGWq Խ~uaPz# GթtéiF@ΆxB f5\ %S).2񚯇rnNh)>6T䳄V5PG_Fh/;їV?_I(+ m߷.泇:UtjB}u>.'R`}-t: :;m #K7 hΣf#wk߸B7SMjYZoJ[ MZqbm5Xcփq7&k41Scoj5]Hj\k2m3R;ٸA릾q^m>jZ&m./ol<,4vjGj'<0ְ?O/(2>oN~+eGӠ_7UBd!j\Hu!KF , baV BP+TEo"t ;^~NBOz8>:"Zg3}lth &>ø&d)nc8~wC3p7 ]Y$>94n3:w@nh>/nh!%H~T{_=ѯK' D_=Wt&諸'D{kqO5]{h ]bcc#uhU?$_c>d>$ո'&{oEj[yuCI= 2]1}B8[JZfeK"\ep\P+Jujq=.nh↹cw#q'q~li[0:.JTng@n5&O%5z ʊ ʊe%$U!gd(O \$JC OTA I>tOrdcE { h|U:L׹Gd\guoqi\|KgԈ︺AzܹytY1CW"JNV̭G72$'^ΛxH7Snħs|')Bu_ͯmDX:%O u6R](}Tx B̝ծ8{/TRcbQtV$:J*ia?NAg1_毺u.G``T!Cܻ\GaP" P%%PZ8A&Ba]'pEB[ =.w>@!1aD8- Q5qa^0)i Rg'2g򤹇t mWfґxxo*&'} + 1$w'H\)xRnNUb A98"~Q[0XK&[=;]q8 =xLOy qR!NӒIȓK y kN<A~}2ǽkٜR{\4}6G/lu[+5qT 6ӧtx rypA9lc;Ak]quB (%]m^W&A~'' GG Heg!]a*zZvpkew{cc< @M غ nxO|8!=~pP9is:)zqCpP9ro8f&\`?0e) ,n̟.~@Q>za>hvHWAjCtbZH:#g~#_{op̓n S{B,̀- {.sm^F؞Y~\1#'Y D1ؔhٌpDh_;+5]a1ഫz9&#֏ЗƮLmok_e mmFbt[n/mz6'.8nabl FR?iY4;ϴ/[P-kь?1։E} ɶ=S_;so;n0꘢Q>vk0FOnrYlt]2 sk̂nˉ.xmWQ8'<θf\.GbD+5weG)sѭ-FJnk61dC9y9_9_Q {Yc~::__Xߨm,{; O2=my:h/D\T}nvD@cJ;s9vQatoxq0{XG6Svq{1}HtC؏Ν@,am}¨1bڧ]3aK' #Mptt@(ѱJQpؠ!ouMcm<>ϱ]ϱ[_sw@.ao#M`'u_=s{ s\e;nLe$<ҧ1M-@>`(*]X(8M6@'`+`;`'`7`/ 8$ ~] KFz%*Կ)v\/"3uQlJgQ =*F)bj?fXN)`T~Uj^xR@%wlqt;v8z}}ftvupru9.ˎ[;Ni: g3Y\,q:9*g srNGhVg8f:{{!sy9<ƝI sT"""""ȯXQQTbMEYbCƊ BiMm[+W]@Aġ#'+ U\@\RqͬV4LoW@ΩD(SeJe: 2 (hyeaeqk+m] _\XŅDB~q!5yRMszA,~c#Z`- &5$u=m[߶:Vy6 fɴYd[$#I$;3c`~1W`~s&屭/_Ƽg0:oVУXƔCy>A>ɔEylAGO{Qc+11u`Wc:ߏnіm:oh_>0_-?<Z,Wa%giwa~az/oEz=ozU=G!aXoV%clK  GNgrS̟Co?05{9KQ,y[p}ft1Tj)Zb<:%cXƒ,y,X$cMضKI%$y b~Pq8A3Xu=Gu:F bo[/֋Y 1yc3&a$OO~xe#ȿ]yq kG~ TYڹXgӄP]8VRI*aˡE!ԖS%JxS{RJ*$&.TEPrx]z?nֵٟ{ku{gi:_'2[Q-LZH9!;6I1ܓem(9Wj-'iC6l4ٴ0fRڟ=0wG|0p.ZY6#-bV\ud"/w|,,i #P1FYn/M1%D=c]râxQ~V6,obd< EZnkM0u`rdWɢ;Y -:Ou!^SrUr3S1pZDF=v=v% aUbV% aUVe=6UPGi,a.uwG5ޅdΛo#? #V ?ѐp,w<IZ[OyW;P}*JQ՜yz IG#V˃kd_RJly jv7T+ү//8|/iFK~Іr_lj-;Xf|o'sy8G9kiyU없5yNF ڬSh9V>nb퇇ZSE|Z_wXwczzkËaL,Kȅ)I>N1^P6h)ǦQ7Mẃ}s,`ƑgBaRrL`ye<{'۫gf8~ Sীh[^A7؋iz Q>?P==+%,wCmD5jlŲ=h9^AGB8L }T"{4EZ~AԂ9T6i^ T=!G%ǓxhN [6m٧γ6VD(BF(I~>@M6zިfN ZMԼu33d+]5ƴB|&)j{51 {TӨP9PJgEk9vR`ckpX7ީԇѽ/:6-ÁeQK daow˰&u;,ۉp]pއ)}ZOsWIX}_N5++a1lxT~.Fi"9&`Y`J/Ã;AÎ2`xT0sz=t"Nƛxz84 !:7` ~8:,EOOb&x:92Vd_ԓe ڝ%nNa[w[ÃI/Pwi-o]ԽH4J%4b_>O2jDgJ;~0h{k'B7qU>85}NhW GCubDh{]I`[8szȻ`Nex$'AvG>Pzm|,5X֎Lxx<:x 3Hh2eLƢ>Ϩ o߆[F6Yp}'4섦6rCGܼ q'I:Ňcm R̖ "wuWQ3:Ҟݹb_gYXF! ;e1y9=Fϙyh?|ZjgE1h̖<+N6XnE2TDd1&ԸOgߊ@Fyy;~6_R6F m@/}<6¾?GKE۹Jj%I8xn=V9v X9GRgE!b fLj4x%sgYJt؋R{{,DKVs`:+Is44;3B ~Yp{w Gt:k{xE\{RtwF>}|Uhg 7oRtJ{ACyS?˿ZoQNKxh8w#b'^XM6ػHw#M]"C{׺$G`4d,Ca 63yܣZ)1܊B)x'?L [)^g&-[H#Ü7{n=t) DRx?sl3%=ŏp]w=G/g!g(͜)BFKnh jYD,sŠ+ϘCȣ뤉hD7Uh4<<asF?nG45|41Sxm|&m>hMJ.`w`n36BYw J ;VлK~KmX?T<[(x 68Y*&&1.;9ջ{|x",lC |Íhhh4>5xC<\a=W]!Iúܗyxs9ٰ.yظ8p.暫.s6\̑#.Oj-b.7t>~!WE~6r}A\_pV|zзp>7Yj' E-/DB+o ؒ{u"0]l>MrZj7gf'nf&QY:V9ٌ8!X7ʧkѻZeȣ|j3r9&NtrZXHJ}. I,Jq8Tk\+Hq8,toRiRD=ԭހASjoYqꄕG3If4QQS|oM~)=3'[o cD{s)}" Fd"_^ X7 c~JsqدZfbx3ͽ7\d)f})~&=}9CRmie湥ޢ3GЧC–Pa?F>9Lmk }ɓ5 ޛ.Oy?-y }#ͱ}]jcR ȣ5\ꯥZ{665WK/m ͏巂= {bK>Jso~}R'yX.NE?K׆Uhfޤљ,9|ynwcV̱z0n䭔6E^vZh>F^i5m?YKR:}AjJكvJ=o܊wG $b=q~ ",w]d[ <'0ztFSҎOvZ/æ#p8Y]rc2FW]rħ>(I RZpZ[$WS mc哑|%rx<?wIeT}ηϑΙ}#w0jFN=g|r}'+kUL# o?/͒B}%1)yDfBbưA񖏟%i{P7Wva5cXhAȣ`ѫGv1f,.c ޢ9p_ 65Gg#׊z[ydQl[hOA4fS`O _-$u+;i*`}jTix}h'F i1 Ng pbZ:G}_ J9gy_5WgOIV_[Nm~*ޛL"r_3@>jLS;|x",?|Mm_Fק%{a~W?VV#L)uP(К\oWG,Q'1o{˶>+xvu<}0Bs<ҎR/fYϝ[f <uoqA-bA2%oM?o5/"|V<^l9^"FMU!bbĦ=+AMg-ѯmob wg!? {O{Cw$f#NS;`]4ñhoؔӑCJ߇tF^SEdp6W߆1waj}ܸH W;n$p8 oHQ|7^#Ha h Bۚ`O_‡\dH㏤=i+={7Rk+nksh-cGk?h?b9 f mcɽ:lnGvg39M;'OKĨ 3DWb_شRz=b %Ub -Bl>A@.,aO4iOy!Ul۩u yv8 Rw:rH0Ƚkj7Fހq p3l@ Y/F&>} и* Bf`T`sj]^M E8 v8ZD bpdc~ >QlzАbcVnBa]bPx2C(lbIy|Z^f t`z^Eu2$D υgЪdހNj߉8$X#Q>Y)@BfHH/BF6$_riL^ xQ7d^-"\qF.DY E\C.bs]ԝ ` tWȿB|hO2X5 UCOcJ÷Kv2;1}wNSEGDSQd)ro|iϐ>ei7HoN(F[İ#x(t@;o 1Bs}UI;ޘYZGh|%1C'۪)K8DZCݧ)mCi')Xcһ$'՞]I^ ެ l~Fs9TA,Ӑ3vI^_Bpo fu{TU:G;!IQOқ7͖vJ'R f<ދɈ 3A$d;k7V{il'm6Vﵤގ.U]_(_t i^oA֪ϡB+Ǐ3 Ǭrlf&5g&`c{EO&\ɵwFG9Fjk!wdvt_9Ko&A~7(/V1m0K4I;JiB-s/ױ*Sd#'D̢ͮp*Bs n3!^zXY{kdhw<fr_bU]cMmЌӉV֊Or6(D/&ChfCrfc,va&+Wۂq"VD>#ԧBJM4">Cʻ:H_t㥻{%˘9f{]1C A;J㥺W.'HFS8QZtcmx㊀I1p5Qg+LɇPL,ekWSL*I>ǡQd}u,~#1y/ͥ1جM>a}R]YM6Xĸ1Ki[.6[Mү 6k15"T4ߦDSkJڿSL6ҟ[XpoAɤƲ?IcpCwҐӑ#7F΋Yy# Lɉ44yvSlB~31>6$'+n/& K iO/~B8OcڷdEϯ%ENZQ}ZEɉt,O&M5J;үWz=gJ禝K`>/A3siȯR>->6En'<|YҞ\מx6Y_6Sn~܀40Aː dF/tE7Դ}&({PCqyI;еW26/J&Ħm*osd}\cƚ{Mn4SRg91grlz>f 0Me߯uu2M8umFoden6cl!fm&Խ{GsU~k=;2rG]l뱱}hk4Wަ Ì7 3Ԍ0w92>sͥjh@_Ŕq8T3ZML Tt4 mw=s`72Hs] *rsz3ٝnn4^Rff;Nva mp_od8>å~#&,aExD }Xր`CoSvn}X`XGqF+ 9p!|.oXMXa.~`R¡ayXְ#:06% v {ް/p[t'I?΄s|.KG1Õp?[Gz۠ 5 #aE0 րܑ#5/`XCp-bX pe^p77#aygDklXa#h[v*@mvk_I?fd+y1Uȕ=Sr?ψ֫>%nV<￱f-Z Ճ2-SU6UC$OGkϿo]Nci6rޔzY^/kxwxbo+v{GЯw'f?ՂUpU; O5{9t-sݿeg:,Se$\~??ו+e.c߱eӯ+_X{No\7͵]u)k懊^z9WSsR[vLqz+r?6;At=On\frs\畹2ߗ>xueVhUZ.[~U.e>-̴)3dƮFFT3:en蘹>sm:k񼟼 M675}~%2՞L[lO##|2ǽ,ۆ4۪k1#߲SƵ]ykB#{$s MwC=i~nj|{rCvM&dV3dm]kK̯un)=),δ +%(ےʹ=Z-WGl$|?W&6lTWڨ\kbۦu6Ry}W˳w+yۻ {ý;toy؛=nfz?z?Gw@YQ4mWwܾwfn ˲(H%)(K$,"dEdJ (I$ sM퀠o]ܩygv qF.tCFIhH2Q2 ɴ2-YeV ce,L!Y&$ V=;^}k9@r 96rlQA{* T9Uj$dLl) f(d6[f[(bv5xM5{=D1so(nճ[NSQL`J+?f* bV1J91XU󨔘TX (8 ca`1,bPiR4Vy|^erXNe XAe*XEefLeLPYRٰ QٱvP9vR9u|]nMbrʃʋʇʏq*q p(Uq8Wp$Tq4VEp,U8ǫ8'b8'888gR8 gpQqSep>W\*_<.%.e"~_ʸW*ש7j77[V]C{Uw.UU>U~"#!^K1^+ ^k%79g.!;=LIg&33-cd e2`- fVf+@.f7$Hav7CfLY0 l RaQ sAj̍!b^H1?`C( "bQȀű8dĒX2sd2Xr͆2dǦr`Kl 91!=Ǝ`g y1 v7@w!b_(pA8 CǏ#(#pQ8 %p8'P9S4NiP?Əy3,P\('P?O".ąP "q1Tr\p% WA /pIkEs-=7m6ʶ;ʶq'eʲ p7eن8H"h0Ŀ?2^ċ/ehW*:{%\Ke)mN e2)}G:b8rjK;P pEVFJ@9u ڑ~`a:̃E7 \!e']I7v Ŷ{l{zMw&zxm@o=FeǶ[?l{N fxmlJ7mR#v`#6HۇnTw|HuQyh12c=dyȌ!2Cd"!LܵP;";70R{|s~sߛHeDh#c5ѱ}lfDi maA0#p ]iç>9e/`1, _W VX (sla#lͰRvvN. {`/a?pa8?Q88'W8)sp.E)]kpnM܅{pC c!Ⱥ/_ dCH6MKeT6WesB 2QeV(;u9U(˟yP<*yBS<#sʒeˋ,ȫ.oț-Ȼ/ȇPP)*꨺^VMի^W}U?_ P#85Q-T/b\Pߩj^vjګ~:C:~VGF)7cod0gq8nb0Nq8o\0.q͸n0nqϸo<0A3Bty]AWԕte]EWtu]CkZz~Q7 u#X7/uSL_u ݒJ"Tv5^wu'Y:Iwu~SEmS{wuoG~Az~_P=LzG1z z')z ? gz\/_z^^W/Wz^z^7FIo[VVowzީ?]zޣ}G_>Q}L׿Uҧ}V}Q_җ}Kw]}OC?gzo֛[?;V/]zk߶{ؽwv=`ك!P{=ޞ`O'ٓ)T{=؞aϴgٳ9\{^hn/K5Z{`mo7N{{ci}Ѿl_M}۾cߵ8‘r t|qs9v8gsysѹ\v8Wkusӹv8w{}0AA4fA0v  S#T``t0M0&6.>!1)9%5-=#8!818)898%858-8=qpFpfpVpvp}}c%HʠMU#~ߣ^ ~ߧ`j^̦Tg#jX5~af?uyWS[R 0C3% 4-!3 q<^wwR!]X\kLkLmmnɂ<ނg_DCL_a[yi>/h! ٛi}VցD4d ;n[#TϻT1=#vg}t&@kѢz3O ='S{yO{$BvŤyIY$+UeU0d-Y Lk5|2khu'9>ͰúWyə:Am?\HY٬1Ӈ̓#]vLĿȊo>##d1/%~˒pGpuGmR=qTGcRYsL!qE+n\>NitNtR9QNj'I8itNz'dv8YlNv':ɶͷ@ ĺȻboeLG<>`VP-A: JSTSAhH% C҇ͨD@HhC%%t$Ho[zQICSBᐖh DOdZ2QmnYE{2E7r'AbĊ[  /z/֊uP@l!Nl۠7Ϛ:5YWυ}ͅ#8G1}? +b&b+bl(I'|x^#8 ~k,k6[saA:8iw 3G_23L? %)w[|/x'_2f~NCur=ϞƱi1⿙4>M2uE2 NtF&GUe;k QGQ=<<)EmRyi-<Ra"bpqьq m cs;Qjl5;F# `K!Z4-H$ 1:Zo:}(0~9 b𣰒#K8VqX"#v s|G' I䆓Jl@"\&eB! ;u綠"|GI/SHQW "POdoyIPDk}Zk Emۍ_W]ҷ+>p!yyHss p8ٜCy(P8CRrJy(5!GVQ+ vF KDUfEAQBD],v#H֩b/bZ|#v6 S₸&PIGFhAf xEXcۄϵMEqD l_6ϱm!Jm)ʰMDQm+Qm[Qm{bTv؎7SXjF]fq-ۮ5#k}3Av?}8l#\K%m0NR&#&v|@^R qT* R\ A:AS(RJs~MT=I^UJ]D Nj(jR=L ME2ӝ맆!O)OU~}ɯ~SIXU/߶'} ȧ6 iw?")b=RHċRMUDMʐMVfSl_m!m)>g\,b `(mOZ1kˌlW3]? l<ζ7[n*4nrs6ɭ8[n6nn{S2(F<5#͈acx:F\T\E/{k3 q7%8RsDEyƍ$7R>ͱµ{LSJBf"h$^ EcH4mF>Me7(GjZ>>_'Y)Tk5ؚAv`}mm6Y-x%*4Dj[;]uz`=)H{=cKer{^eڇc/I}>g_/Wc98A0'w 8!')r ;ExS)pJ:NyS)Tp*ADHL6{9x<3I9T'Nk'k'шΑ=iD䧟oa<* s9D>-H22HI*9lXwBjf qw /45h}^`]6sw3w݀!sw#vc'3uOfw11{JhWZ_kJ;=j!F38F0ily><=Þg0ygZf{a5puA'Q;t)}ܞ홂333%g*n(nܞܞi=cRCZmz$Xsǩ8c=hR%Ι{Gɑ9ɣXqYw=5BFɴ2UU͖flkv5=03fc11a ,y, 6lmvױ7~8q$Ʊ8'dq98% W܈q+~q~pxyW˿=s)!4+3KϔSO|x>+=U?>#9:|N6{?]?K]aZ('$9'.ߪT53}cI1gʠ*fsZnav/W7̾G͵uO/i)9 tQo:Z^H˛H @:C|#P5pBJym#[/Rt9oթ _|^\d(⏴6ڦmI:ƅݨ#uĄ:&esX^h۲KZ%e*ߩKN]'Od evȘ''$f׶uG:kˆ2ŅBC ,҄V z_`vۑ j}tC}D'1&>nh%^Z3E}?zXeIUNK]J?`_i._f丣*.ط.[/Ν"۷NZߵZqv#Ǿ7ɲx;m ϖd׀:}{ o0AM'l,GY.?&j踁rCh:Ռa]]6HD l䈗>S⺫i^)7$bJ2Ö|/M>;RӗZͻ0.^k+5{` Rtnyy;d6rQG-*Xc_U uHP$a>,4RF$2m]"6эV|\#7`0J̆An(ՈEaqT#hBQQ+j2d4j^UZuj$%u.Q@.wxԊ[vPkmݭ:wЭeR+ `~:(5 a U{K{_ѣGg}EbIvʍ/ŷ愶; >K!o?v*yq?b9wݵnƮ?5+~np:;=l=ro_ʶȶ^imkX ot=:q laZY:42Y',@پ^>:Sw?aU`Cffj>I_ҕ>ᅢƽ; 7m}AikV- 6Cguϭ%z|aKs ,o˽Fs4H?~1cc6̤VR(Gɹ9%d@m;$櫗ԼC2Th"C u3TAOVCP9CٓW3t,߶s.*ԫb%/lJE,R4=5٣t^bm[&ӌ64[-ɨns69˹e#%|4sƚϝ\v͵cV_vVex)'"/~T|œK3dox% -&MPUҤ= R,:Ҥw EPA. &]DRw+7^w~xS239sg?9"/VҽW'^v*{0WO8?r$Mz-^SHLl41ЋNkbH?ʚ4|C~aC)a ] C$nTkɓ=09Te@1S!S.?[3*¦w6@ p6̾ `*9˖*DU7Lo,~PHuFvK;ɗӤ-[V>&mܥ|˫BynVn{JF4 Wj5.SDzr1.˧--¤,r XcHV4-M,QxAWT-e>6}cWY|^ Y^mdbS!DMPN{99۩GYBϚNPYF&~ڡ%[>V3d,0eS~V(~ud2,aٞ|1*\ˑ %Zshw61ɢBte#+ ,+E\"c)CXS ӌ\_wnWazA\޳+4z", -~R55ek e^0qrGV_1*I2M}mȭ:(XmClT|sD*ciYOl)턫=Al  ?ϯ!vHєqWs**lD}6"ko0FOS.M׀p$?g HAl 1âpPyP2:#x^ڱKڅL<ԋ]y]kx8I~ڧv>zm;*n*36;mQ ZY,O! nqP$_AЮ]t4vH߹ӗX6͙xgFVS@lE'`8C⧖GLO{¦M*G_=(bClK=7T+L-s]߆6<ˆoz01Noz =_h/-rGUeE,ߨRYX$5])/9uI\"jH 'J.+ѼҪN3.2La}*\98, mP[ez31aڷC*h }A.ݍ dcc.5L0l|tp%Ys{HQmH5$i>E.bӼwQ캹>XEO(av`P%tKCi LKY$7͛'p/;&oWKTi6rzP脻^QR)++ְnz XM]enT95S&ۏUT12Yz8rƹ֏ϝvу.WϧK:aV?{L) PyRS8wUm:[0uZrTdEqEWND 8IYf 1\|2LuK-}sZ)6Ρl>8%#5X;EOHq"#_O̗;7AGؒ!)!gIme8^H$XX*,s9:$nG.DbLA_~d‚@  B(Yl@^x^_q{8[c\l8,!ƁA>cO?g*+FfͮTW@2vܹM]'8ڙ,D2%|%78V}~н2Lm. PN*7~L{!`UF6e/4#BR58v  =:sH?%b>)P5*C셖Ľ{Cgku{76!eΒZ}*BUb;ZەzĆf20G< G&U$ߝǑ&8po-P$Q "I%I_P )~0ۗnp ۖcw4QwTa|zX3/tC9ȓ73'" endstream endobj 377 0 obj <> stream xRn0+|LyBЇJ`/b,u*90ʳѾbr/iWm8qhhV.pmZzqa:om4eHKy`74]"mN-i -v<C ~|h ӳoL<-q0)Z~7j~θ endstream endobj 378 0 obj <> stream x| xTչZ{=$=ٙdf &d3$$!<&d @@(6>꣧%vcު"wV[h=mzmTdrg&$ݬZzEaG6BGr!uhwl)im~zHLh6618"!tQsMzR/k^uw Q/ tu`Yӿ<~f_ٷ~|!Qo]\BCy_{3B%i.۸7@[V-f Tub`e_⭵a|h*w@`ka+]k+^GBW={>P}׭7׼a]wJeeõ׌ݍ^ZlO"~Uߍ"w^YE*R NRvYq B(:FD gT)wKCP7CpS-hJr Qc<,ό=o!"+ 'øO~7~E~qSnSDK)q?Nj쌴%w˥V8i#=R? U@qٳh*[;vmǁt*IZP<2GԽNR $'P 5Zv?FZ%/|Il_K#@a 9$!y(tNi:K,4.D{}RAE用Qͥ!c:M4;݇ߝ$O(ʿzMi:M4tNi:M4tNi:_MrB2GԿ2ksFM S)x@FzvIHɐ)Jj-1Ȁy ^d7!݄hFv3݊nCt:D_F#.t74/h(`b!'PUԄZԎh=ڊ`s~ Q fNԇ@WCh>(%Q:9?copA+~MK->hpƁ.!}1`*K8CD艁q&8ENгu!(iYR r'Ժ%҇9 k\!" Mք(~+\&{}2fG.zӬLא%#l\_)n5WqMڏq}].!O:7%%`%Cp1Ae3}Xnt#5h,J ri ng\ǡXq1w/P =޷;އ|[8ۡp}GGm  dP+eԸi8Id*k7qlp|pG4qV4 wMb5p,ѽ6KDG=v m?:ms`憙?4lq5GC8,,l__,j蘻q4@3C|`G \Ğ (;;zRep<'525nR3S3=΁m ?G'3&c]3Ղ:-zSC9AVŎ'1} m9樍\6-~bAQ_~EfF:*wV 6Ӛ6q[ 1pA9R FyѽؕÕj1'&otÂ'3l#;@-bcQaɤ#SkŁKUj`;`+`ZZz\v-J2~6 |0!"~FD;"> ">$""AĻDS;D<("q[EBppv{P=W~< ( @=W~< AruSV[KzcY/ tz@kt:u;ξfْs@VZ9`vؽ!;kukCk 9s|۞ޗOjSxbyϑV~>L!@b9:,Ru-ځnFG^iTX}Ȣ)(gXd:hA%w6Թ<^]W3c37_?ԕ~Tz:}_ 83OAT52BCK)NmzJf(Jy G0:^FjZf*ctr3}t._!؅yށsvyشFY7[]y0i=@S[P_:kZKV_ҵ=ԅcj& ߅!o;JBMPK1 ^8^8 µ("ջ`c~ aܘPF2 `.\?5m&4*Q8ӸO87:t1.|E7j}BO(NO9gFj# v;u=GdrhpOpƅl.A?*{!~lܸ(E Poo\D ` z- @ H$ljwo'~x3z''~IDxıē#$$'7%v'7&nHJLH &':DKSzI!i7b_HRFpaT*?vz+%;SI1{Z>!E(o;zD$߁vh KiruW7с4 GMt݆6?SY֍"니bCK_://e:4 sނ8z88u<;/B+|HPfG!t53y2SHA]r9^&ԍg>o߆IIkct 8u@yv| 2X4 ~-J7c%Gm)@7IP! RT y gdw0_׌H-ViN3cfo(uTU]Qu 9) :bY lpPU2qgױYx}AmX['dt'VW \[y$7T䩛T x sd|0$[zj Et r"yX2zarRKtAj`RO-vZeS*UJd (dpp F.`! 2B̞cpy1dVR;)z.&]:@]]j<,{L$x<ͷBHs%}ޫDd%5B>2~  2GܩA>`UZ袃Vj9 <9CA=p2Ǜ/iQЏ~dO (uKp3Ga<+ %UfY.(7!TBq=q˹"Z뚒?M\=9ohAKm?M;"*[Q}),f"j۵ +-IMZ.υrҕs?LT|+t"T4# ^ul@Da=0b0}򥓨9gO(WSs.ylf1l)c$ d2.(7ʬ{]}[ZT{| ɿo;[5ie W$_L|/+bw^ųݓւb%yb`8͡tA=gG^o0wВfƛ/XY9tlI[207l&aЙJ"j`#W~rۚ5[׵U{g V=!._]Yb5g hk\wݷ:{-7Mbs%X1~RӢU0<|ƢЖĥ[Aipv\VzŻG]ZFR*ތ]f|$|NM`s~BĞ.()"Kg40%;be u=AF~@Ka.?z+pq铢g7xlVͬ䚚YUZ=哖$Nv"XN$S=O{$J; qz; : o1ZhR<Upy؉uE)|1i@9(xj'ϥsx 2Vĝ]sh~3r7l䗕<[Qo1H#/x KέoA)HW уi6Y}jtjhЯVt9Dlrc5uLW@4)^YtBmV&_hl2~i+ >VR@Azv^أDΪn|[*֓m|F3%t#W^ Q -Jsj5MfZrjss FV@)$Oit6KN*mg\ޒyfthR{yMT^_.(Z@I]]PN\VvWܜ\i1aoaxp8ho qA&{blj,4}OHa}'9m[*k#*;OZ6/=!jݕW:x(/D*./J.R:++,CME^Q*2HE4~a[޹Kbb9u&m„*HaNc,Qksc|RF[4wBwY&J+O[ZO5[pBjs3>VܙQnk%ϕLϩ!V֕}s 'AW9+ΖӜ-Rk<^lC+,& ϫ(廊Fe(m@3¢]d Jgs !B+iN˦I&zJ[Ixdi*!µQ,\hU0o/|龶G9wW͉?af8͚DXkNK=.KsȎn$&vv-O7TXv1 &eD1S2&"rčJz ~}?[ې[܃/{N~3ȓ= =9ݗ|/%J;ݒރ7Yisr4)_%Ur`AA dKXgM=*'%G#5ݗՃފU6jAC/g(h~ϓm[>vLn6Q2vha $3fJ[/w<9v75CT_8iE޻6mz2rzLA, f^Q'b0›dѨLTiOZBiP08F&*H(Hq宯E]tLNJarUIIQN?m0vٯVQ߱pරv:h^F|*3#~V8S>:yfQwnn79d!IMC' !eqe!N0}{߉" Ih%d|Wl :y\Ï~'u]@ܐ[Rë~nqD$/A +͗AE]5 E 7e,zd~~|FuƖqbw%VVyD?q`sM<I$%Kr??__U[ufp>wvM/ w6mlmn\P޾gF{VzI}1cq5ܰ;K|p0pK|.J|zp՛C9KcRWk.qP欦랠{U3.do!iuj2G6KeN٘2lsu|T]}ʔ"S!KavlTa\@]U9; Ѷ[fɘY2QȺbZƛIzvǴy6.[둮[NG1|~ E|LexLdQņ邑:Q/TNјa`U*dNj ]\dε>خsj&V6g;qSFnoFt9ۂQf_iޢgg,iҦLRҺة9U͘{S#Xm5N7j;~.3 _&?H96-_YYRIzK99%vZ,%;5iY>ե1WS9F:{ufҾDro92KLZJ-7\pulײ)-/u.׿#g/ku ?a̜j7XbsI^ͬ_mEqiXU|⏥66E0IRՒ4Y%$~0`4]|?NW D9#ɣ#|5>]>_qkM}Z(Ț^_:-yXqa"[ec~G+c$n2+{t1H Jri+?sX!(NLUE`R7WJp.ҕODi+q ;MM,^s&hЕ2ݲ۷Ucn/ \|[[P~]K'^\-^շEU׌~?U] e͉B!-]*QcˢscCg*׷Uʷr9ZS$\8Nk6& }οo5c>YY*,(W:1Oc&L+ ,U]-l\^8ev")]qUsi/yO5@S̶'٘?N uZnV=XoaYT̲2m$fx+I%\!JscR:wZ %:sҟ5=vC33-eؠAyNoKj gM.Ν7!Z̺*_6}ʵ/~+d,e*{qɌRLeeKT>ї1f ٧6h45l#ʑ+R8o!:yJ]/؆U8Wie;gKnH^3;iDc|մX|)cgBzQIllDŽp6#n\(UbX{b'e1vZKEX\ MM/`"ŵ7x]MR^R,\c/$eMțPztqe,ZXc( *wXc&L dB{|YQ5./*8_!nZ^S U񣅧x͂Ά%筬"ycZ5* i/Z>+aKV"ZN1:-L]Z2Hjzu,S*_~t:OCŬN +)gx* Os*!]u[ NJʅ\2`%*EψOK/ģδe΢}Z#4XUL˴K6A< ;.Ng!5yiQxJGD0s^ٟ]^Kq$IDL-QGGYţhy^dWo*aJlPG:I 䬗ϩ`&ˊ1gg3ς!Go6g!\jrudvo"#=ʖGn~T}ϓ-KQ2x߹FD-l޹Q;I޻wم SėнWry~[#V}q Iϋkۋ?R<hxlgl3@~g lt[> X+eMҰˑȮrzk޼/:늦7+vmleӿ a;1ESWmNb[t[)JB:8@: bn9^Θ9d xo|={?ƞJ"NQcyS%GӀ;* *-*{sߘij]z&[7I>8Ʒ]v1VevferWÌ*G6IxL뺡w!J%M0 6=g\^y!r-26'_"9|uCg/t΁%{^Yʩb\d-Rv^9-ζ^\MBL <2rHc>& ׋tc᯲8M )^?wUxܞ'Vv9jZX~׶wצ;NM+\}Ӫ}S;lvٰAX2qBaiCB)J INi4!I L5L{uر9e,יCgW"@|r%%M4+~rm3g%5r*ZZ]|Ο6/n7׽wՓݴnu ,*_߲uz˺o\yY4u:k3q7<6ثwh:f՘oj翝A"d?j\4zdqՙn8{|n\Nx\t|A_e˾Vwpt3W)nk T `ES5?o;>nڤ7ا8b:!BCN^“Ϭ->t"|[٘' (UF) esaFβ4a%_/TdIf)jűUEXs*Ye9uI 6&Msi\Gz_p_͘GN+8k*,ͭGwleL%㕹$}Vz>wCkK׶iJoWO62/kCO;{wuc{eb;b/z3o~j2E_tNX)>#ݩG3Y9]9ߦ!bȸ4Cci ~+K'ӯJ$c9I[O.'|VGq^N3icNDI%ofM>rŘyy'.r.r.r.r.r?_Iɘvt|7|oA3(3YН?v&Ct_S@R@⏁p.^:YLTh)>>h 9.D{VH}@BsL+}CYP ӝYv!zAA1оh?zY|G@wv&z7zѳ]A'νD{v$?< -h_<rJO߳tH{e2bd1Jj ɜnG H_"MtWCp2B߁Q < dA¿v&Ct? oOs`A-B_lh{t;v"M(ll(h_e~7@9#lxWV@&;HĿ_ #M r~n=ƺ0w̻r*8f¸/av=DT8Ƃc nBP&Ի nvt'4tv_<jB>yɼdOOOOOO%ijx^K<=4F=4F=4F=4F=dG#}Ŀ>~tfaAv;?=D#k!A~~<~9"Mt<H3riɪɪɪ- iGAv,C=D#C}y!(׹e}.xZdE(װ2O!zA捠\f<'Awz נ]DV pf~BO ]?'t~BO ]?'M& 1$vxp%apVoy^4bƂCf<*9/{6_ Ƽ$FI&(y 1 w+y5O(y G%cSk-1 ZC/#[gW&6ɔ+9)yiM)y 7+y5>%A%ewYeY_RzV.)y3ٗMMM,3=їYXVilVƏ_T;yr^,e;yr^,e;yr^,e;y &fo!0u,M;^jB:rԲ;&=R =U'[2_+%eOFpbo8Vn.G+G ޘ򱡹ʣ؃sLnک)[f.xp+?h!co|QOyW fY^-sZ*3H,DmDyhܚ!#SFb,3s"v{ݬSwkc싖bLG՘JFEwdm4YK^e9pc#f >VBmn'[p?C#4. (9)q=Io6?1S﹝!G̡fAwsty/CP{-<hu2 [Z^E܍ThKHmy!>D'kqvZy|9iuCqHP>Ƚnqm<<<@Vx~oͳCB3˯Ԗڔv{c]܈Fw+5)M ]P. qW' =~8;Gޗ=Az/7ZD 7]- &j*+=s6 P y *o!\b>'5 @0Ѐ5\H'y&c獆ḌjD4]"2`9YsIIƔnAt~Wj٥̴AGrL070=57c<-no`K 2|E/-wE|a6GiqfarsȄIyJ+>*d#f^*IKXԥ[_uR9ȥlOoRUogU337iqбnuogV^=²س,Ev:Oe, l`ga#,d ײ[^z;>a'{PxeKOxcGpBIH D0(NX)I\#Q RS,Ň0O *>5 Xu j,^N`돁&wSб.ƺZ suF` kX{0> kX ǀ~q/aZ3u^ k#kq`}X[ñw`I:mVgX_wze l`;m0X:`M>`!)'A1 q2;(fUO\`mX1wG"o7)$RXJ$Y%;WǪ"A%Su.5Z>` {c`e=X3X+u..֛Xn`=`} X֏si9:Xgb`Xc5U`Y.` Xֿ2`V֫F`moCX֏svhgc:`ֻu7G'`XϱÒE8! 'IGRpNe"VFI4Iw^`ǀzX:uR q:XoAm'X_ifXP2Xwc`8DzE+0oalx X;‡%3{P*e9쀴ndI]-/=oq`X?Ωt *Cd|ѨM,mRHª6գfQ]iz?t%uZ<\hjljj01Oc ՜{j.4u5^Hy;å?kj *SS>QbJt~@i0B||SP=?hXS҉MLx5z{FaMqSaz@]]k|:"pQI*A%R_{&m\U*ju8Έ3TEO]sJ8~ar3T*{Mʺ#ɇj^ٻ7{^S F1zӓn]4[iXeorNA5v6h'EOۘ󳈑cwNs7!@rFM׳HKN˞ WRGV|3 jfAU7Wy7sTol] 7O-FfT(|ycBg#Yެ yiLuM> htL;ERRY(JoV'؟46VW[GfCl,hTüY/ zٛw6(lݙ{2:DMOGkB4z f0 {; Y-[Y95!ʝ8f R/77?zWbDf#ejpAF`@$1rsdEdIdidQx4BR{\CL iR4#{_; Z]ǽt̠&UT|)2M"ΣxjXyMώVz%:fa+6,Qu ᕆQ+_ijѨ➌4uܨ+aگ0;4zf42GXˆC!DO 1E lk2cE .RPk4FXQ]M$FVB?WxD 4fCQDf)wSJc|%ZBHZYdL6B.95j֣/j` :wf"Mzf,CЭsjx5ĩeZ~EIIIfM“sjI3ugLtV˗`^PQ%STSL)qCZYR*>яN'}BG's ߪtyJԙ^/aJ/d#.bӑ`3ӥ V7X3GSl|ifʞfF1(h<(FM45VnGULzn%y|[բ)5)­j4ID(ƍhHxm74X c1rΣ%h5h(DuEl&c AZ(kQg#yhz6C:{l̦8 EpS4ٖ3^0E6!Xj l3Ynr(SPxWFF:s ݖΤ|`ا.J2'$4l=SQ݁y>IxHQom6G\ѳQǸq}x 1ܖ51Ey׆kvqAC 84k El;3)K|Q(բ̈?5cg{G_zCmkS-By[gh87SUlnJIՐ0vw.pQ f\ffx RIFԐ IxM!"5PKfeSMF-ێQ)ڤb4^``ny?9{to./rz+h5g텵M"Qdx?/ZױZ(Z=..q\e/BfॵW#Kcֲ&E9+b%eouOB1#qD(rLi4Y?Zp],H[h(;D^guMokDXbյ"", ]'1"-Ov=\$a,ҶG`2j/EagY*۬V;GA#$0ѰN>ɻ6MH-" /M>s>P?-rHN˛):>>o,qKԜ9(ML=R[ుo9p"XH/5uEik0D(ĢC`8;EGqͬX\:2sEpOCy=k3\?}ϛ;.D?׾=SjGI֞U# etf]+D^, UE`7t5hH2&2 K V.AߍjtE į!ag,3 Í۞k{i{T|[M06m-m'%-6VQxk_ءm~Idw;omhBIW/Ҷoq?!- ; kh˄aMe~4lEP5bgąёH_MKLop4h]ψZW^~͖S \=>v^~WTUԶQuQ:.:<Uzζ蛢7F{kIo>9:swyO:ߨxY<>-.\+kk+F΂ڢzt -@>}TDms$3..n`\b\23!?W;w!^Osׁ:=V.Ak9Yoס'Wׯj?;T-EQ& /11!4#wl:|-$KޒK OޒP=uw-cO=.}\ M(?;52uCM;Sn6yux͍qFL9s⌭L;--.n Aꡌ33dz2e쟝9.sϽ%ʬ׳{foޗݐ ߟzy'%g,?]\E₲?,8Zp C **^[Upq‚C+:"ĊŅW"^qpg!8G1G#Qp:6;\hv-R:u)~EehQ֡͊/z!ίR[Vk렭6+(痠>+Kuh3׋鈝:Դhc2BYMSG,4s6饲`_8n2]i@WKg(',DdDZz)*M[q"BuXs 47(oa>ujh*aU|pmqNq~⧋?<ҹm%αAj=Κvj*]σݠ}>i|˓)PKVWj5ME/~I5 (λV3,4<6Z)6kp-DUQ-)~hytT% +z+9e/hi( ǑxmE+|=͢6WI8LB_w_\MkEy+=fڶ>>߶bm↨qŨvq@Zqm%: ((P&\a\zN~ !)u-qY qY8cuYi\)\i\rWfo A;<1'CW O]nQJ=%;n@t΀jaJҔM^g)Cpр<;tT\P@qZ.Z zVtq@jT+Lsl} 6swMܳ7lC;</G{:ǖ(D}fԶeTαύ|.MW_<*o ;7m~qMb?OƻMJ{e^6o$OT2^C M1ҶY$^DR1XobRD`F.yid k JC;J 8EpZ彷LﶁIAã0&DFmI3f SS! y/O .K?p7\i?Q-y*|4R{^-j۴3LnusAC<ϗ_7rbe$SJD"cko/Af0„Ӿ "\j;@Ng6W3ke3L\'ݡ^XqxgU &np'Ca 0FHFA !@<cS10f0g7+ ?+ ?+ XAe2VPXF?r@D!Ͽ5RۆzB/ C,82p|}?K+;:(&8p ~l 8 <g(X~VguY~V7jꎲY,3+60d)p? rd1k,%ɔ]#ĸ51&Ɠ]ʮfeYeGV$'`M16MM1+|?+oE^&̖)29"LK_ 8·PON1p^VS~ Nm=W1(O3 {؍^ըW5UzQ/?GFQ^Ooxhc Lrµ}m| 2E4+͜)6 ɷE}{{e~TQGΈGo3\{[ DŽ; 0HCSa ̅, .x׉߀‡jHI삏>sLbHU<+)b*Bjm@j1ܶp[)[ moROrw~RfvDڎt[;H7c " %6fZx ĢK{zD3m/[R6MES)v Nc8Ŏ;Sqf\kqfv kN^ʹN鴜5dpfƵ2"1HP֚W/&m /ڰ4'FmL8^^SO顿Z`!/`?6 &yѾpyk8vF;h ]Z A tzBoyx=Bx w@`HLip3LyZ #ǕvE̽)ܛr-D{ǽ+\_ U\G: QnHO#A !'$ S=ž[aϭVfB&̆90 b, IcWqqD< ޠL ޸kzVaVaVaӏ$+ &X1&)!Or+<;(b#-L6*ᤵ*޸C:BgZt%:ywԉ' )s*hcdddͥ֨$Qv`(M{G}%srcaX ixg9>5.,!!21LdG՛ʎJeGRQTvT*;*ʎJeG- *]ʮJeWRUT n:r=vǎ;ޣ= c{xQ{TG{r'Q[y{*7 ^3*>1N**r]-OȽTq/UKRŽTq/UKRŽTPj}͝O 2(=C7;q 7\ V7r_7pp~Wg#`$0 R~ @|O{>C%4HL|.'{f~7fߤ_P~쀝SvC 8p/A.T)wZPNr|riW MffTcfL7w >i]:)ݡXxn` |3!n恙y`Ny00Ra4<oF{i qr!xX֙G0(}gB{vژJțƳ>NLּyA!̐W'2Z\(?QhR'v.rV]eAw=!@xF[0f03@ aqŰZ0rx@go s + B=P+ B=P+ BY_K̂LXH[ Җ2ȇ(M!]g!ݠ$$L уi!ibPH8!ss!O,%^G({6塱OC1h 8 8-?5v)k eu0d)p?  *FJigӣ4M~j0[V/U&vRn=FVVJ+gyXiM&V<2*󰲚̍4']棬c$c?!6Op)gsV1y9L+"d k,!r%TMԢg̱XM.Ho<x,(s5e:.kȏ\\c,-]ZR:b[QzF/r=C;qǓr#X;?|,7 Pf0$ʗ,Rfen#={zwp~'weu,)3zS}M&}R(w?@:,cxa,Q!=̳EݕV7k_Ku Nꮇ ?K{/2>]~ʽ~G8n2fm}r#ďB!grJ_1p%WrJ>\ɍ+q%7ƕܸWrJn\ɍ+q\)G*,\p!.ąrB>\ȇ 8 p.@Eݨ uWQv*FݨwnT܍Qq7*FݨwNT܉;QbW( %vN؇Qb7JFsPb7JF}(%vn؅Qb'JFu] uVCu}ꪨ>TׇVUUsjTmBP^BܨUsU͋yQ7QjT́jP5wPQUjNT́M@IV|6eeH#\Ce2Jl47oPwpL$'y"|9Y'3EΥj1$Kq nDE Ҭ60q#IkI@|5qG^CEht& t%:npzr '-q @Z?'o@ھ2>IxmDwE<È&o8uG>IEB|?eF?@1I#AGC?½'oa2iSStg.ZgL` V`fgu6ys8 ٤#OC\.|,&m Re[N^ bꕐ+a5ik399_ϒT ve̪e̪0Q^fT3fT3*lF n5Ì3Q.Q ̨$fT333Q 3Q~cFy3e3*ČJ`FycFyQZͨ8fT3*eFj5Z(e3*ČJ`FycFy/Q ̨$fT3/gԂvv\Sw3R\]k:tNܲ-5% t2+ᒍd.wt%c)XtG+qE'?|\u ?PA\] HU@եVH"Ru펍v͍{^cwslTjY4'#2 P: %n͹3އ3sd}gRI b< LNӰ4줄FӰ`3 )i `\g v`)I`\g o4L+~LMn}2i7`uv}]gyڵY7-r藳ri֩˛MM>SSvSS:`k4LNm46*SkԊՀiݴ3:/29q(qg~ Omve:}N/22fCP}LSG (\JXJ SJ)X8")b)EOS+e4Rr82I=E픱2ZU* iK)ؚS՜=qY^#8 ~ތ.?SR,?OB9y8_3wxN?ws5KZ))$ :z(h9m:VJjvJj(XJ.?uOJQHQ'QԱòS촎vNCBaK)~ 7uM)m QZ -U.7VQEw)[{ܡ sRZUnj(R{-[IDSڱIxMrS+%ĵH'(p)Hmj\>99yIao"5i3'Ajxf* ʘ"a Pu\ :_u}P !A._({;֡cv]kѵywεZۭ]]le8Auw<uCYܢ>n|3h}]j}|K[_-w;X3w Z߱":)b*ZetTa}N*L%TR> tRV{-մPM)h+FBAX߃4HIfjꠦa}꠬ZFY>{uTa}SZ ͫ|AuTک*ߺ Z߃I[Tu7GFEj|7};)s\\OMlccfCvPrj!J]0%vPb %vPb%Q%nVJ\N=N=8DC7Rb+%.3)+JJlč/ē((qRFJlx&%P%QZJHϤJl]8DC;VJ\N*w)q9%RrJ|{(qiN}*w=J)q)%ĭJāʝz%R⥔r>DC;Jl唸 p͔Nw>vSZw9XGzSndpEæh#孥V[Ny'U(oZ)o9-]7DyC;Jy˃OR\$%bM][kU94]~a9<_NVQ enJY(kST7EmqHQCI)V8%m]4IIRR'%mFJ NAj)rSN7lqXIM1[)fbz(f;lnjzI1b)nJZQ8lݔ2I)SR6VB)dkY!7FMhKkL)]w_v+tSVJYG)(eR&)e;lNJH)gR8Pv 馐ԻB&)dBz(B:)dcqQ2#X\,X'`Q}Wl RGʓ5u82ĵ6| _S]g!.Q.~{\3QC !znŏ%EK(WW1`!Gg0gqQ.8jouМ8/h}₨+nk㊨7UQ̉ǣl_;iVFM^e{ikvzfmٱx|mݏG~nk+.apnZ܁;q>uG隻q5{&Pg#Ob >?3lş#`:Yv>._5%5_kW>ƚdezg=_qWkjvk7-Ծf_cķm܏+jy}Gnxc1~Gfk~ <=x yLb c{Q؇'E<<<f sooěkk",F#~K\]S{)p.X#Xg˱J\ь\k[u QjDDyP+ŊDjy.ۍX q`hhhhh譁!D>!e!vuQ_nMz٭nYYpvZ]Xcێ[ĭ (%n];rrYWN ߃{}r;7uy2^un^cz/NS*;6&>`lM|6&>`lM|6&>`lM|6ɀe2zp ^%ˀ2` +ʀ2` +ʀ2` +ʀ2` +ʀ2` +ʀ2` ˃ӕ pt_ ̃+022/x2̓eGd4/N4/N4/N4/N4/N4/N4/N4/Nf@9؃ǐ$8<}xQS(ieNI8I'i$ 4pkFEj~F P8 GTñq8'`Nī;H$'5]q Ni8{8g"ΫgپY<> ׅ֝9mt@9mt@w8ўyO ή*rD/,;Y|׹5콶Wrc+ݽJ\&n5NRgwZVnnuvZVU8`2n"n">WMZ">^ᕰ +*vU2Xx}]O^>JOkp>.7Ͷr{CQUW\uռi9MizNs4=9MizNs4=9MizNs4=9MizNs֟^ "7›4(7V=G{*i|ȄDŽ21L{LiS廋Ϙ\q&iZǬ=zڷ`%DSu %Dr=)%kdMt Mt MS8læ(aSRnR)zJSæ8læ*EW)JqؐÆ6! i-! 90gÜusa:Y90gÜusa:Y%є$DShJMI)I4%$є$DShJMI)I4%$є$DShJMI)I4%$є$DShJMI)I4%$є$DShJMI)I4e=$є$DSVJMY_)+%$є$RhJMq(@! 9PȁBJ)I4|z.i.,g98G/H8'CI]2Lag9(׿2CFv!#;dNFv!Á2(Á2CFv!#;ddN!#;dd ʼ4\BEPΛT颚.颚.颚.颚.4cfӌy1O3i<͘4cfӌy1O3i<͘4cfӌy1O3i8PV=y{ JL(;$ [%&p:|qRns9ڧhp Wkjm\.0Sz7F&a nF;n0>|mkq]tOwjGn ]f2Ce.3ܬq6nڸY7kfmܬq6nڸY7kfmtE]tE]tE]tE]tE]tE]tE]tE]tE]tE]tE]tT%.8\XW _gēӠ2!CSm;5T_K _u/ϪPwC u7PwC u7PwC u7PwC u7 exU5.ёl#]H##1#1#1#1#1#1#1#1#1#1#1#1#Hn;A }#}#/kRJG+YUze+^YʪWVUze+^YʪWVUze+^YMe?^Q^>_qsW_e+W*vk735 ]Ve/ͳ;ɖ5ٲ*U%.;K5*ߊݯ?J UsL5f>1ͫh^E*UѬfU4YͪhVE*UѬfU4YͪhVE*UѬfU4YͪhVE55wc6܋ _u;5 u JJJJJJJJJJJœ&WٗC/ VF1(a}ʧ%$z0aoֻhzbHTJ2[If+l%$dVJ2[If+l%$dVJ2[If+l%$dVJ2[If+l%$j0}j߁wBj/Ex.ƻyha /f_V;V;|/ÿ=.l8X/.gGoǣavS훣a5k v_3f}p%/E.+vއx?V W-b5>!\N*\pM_m`z> ʻ wz|_4Sj9SgL)3z\ϔr=SVQ!aZĿqoox;aQՁ߻lEU=~>!z7s ;m BK(h_$xId^E/yoUU5}pDŵcZZgTpFgj| ?<~gJuA4RWu'۞1`!b%c iH;E)Œ.Œ.L=>Z*RT<.H`y}^-:JëP -V|5CooU-h(y 4$G?w8:VzI]*?`G'fY`loQZMty1TK ۬n+۹j׿^㧝h tgFzTUmt6[Gkݮ}zާz><}ܧ}M}&}ѶXm+;|7;*͙բrU,G+L N_k>Ws\UW+aXsm3Qc@jCJyly?>; Gl =jEDvO>~'>S<0O<񡹩dr.g6ZY^{}oBC]wZsyE^[qX&oÛg ߈VEfڝusDYVra%gXYܶ<9C#gh G[c*RJmڬTvK$giO0&!}YſygU*$pF5jpΈB?;XmXwB\w=+G >q nA< ?{7E}d5gW ÿD3/U㺨[+:*Sy:34U"MihϚkQhjp"*.WlM9-OFD& \ 8~CrP ܋~OuGS-&8&ɻ9IcW'U$m]}G_:q+[W\Qs _Q9 Vgp2\ W/p+mt*fo+-IDwzv$O9XvIM;<ϹϹ^CS.:z@Ѕt!KcE_,_-.Ό8`EX3V#8>EW':Qݨ<#3,?}t|\|TփuSJG<]A;rO| #Ty@cIy}&yzgO? |vdb|~*+Ye%,륺˫|JVOn3Wۮ˾uwwH޵o:^|kKko s[c=Ƕ-޹뱞/mK[/m +; x8¯-*Exu @./߽yn7ޙWϴϜ9>cZ_eNQޞ=yefԐ\x.3dOFm*o.w, .9%Q3=! rA # 0 xE, +e1^B"Q%"FLUӓL&u:^UW=ՏPV\Poڅ/%IZ_ݬZ܂lwoTk[NbdvP!܁Nܟ}!v]o ?Jn@Nl*9('Z 2ˠW9b-~J($SlJB-?ͤ<4)?])WV]ʳnailNy<m/+@~]{ &GQ?B| S5uJпAŠ7@oSٞe-( ; ͣtCGbk )G*wI/U6)Q9#4*{-=g, Vվ/= Oh!$!Z+/8W8ԒG@ foP9TӀ@AA@PSԢxxx(Pz6JF j+1i AC1AƐ&Tw/0 E"pPd͂MB(=ҋPzJ/ KBr!Yꫀ%ЅTn^1Nʐ(jlj)hZPjBCu!ZqnC= umH(unC2.I%PZ RQhͤ;j j:t-( tڻf_w    37oAk ;@;BVPC8w<`'j'W@BGҴ(Ԏ#< y2( #+ejo&$vRdBgʀι5tftFOҝKiۀs@R R2Ы[z Vh4s@\z%s} S& Y O":Eh"NQdRўrMTJŏ H(Ldԏ$ )- -o4(+;鯟 5$!=CB?$-*ܿ t9 Е F\y5׀r@ׂ&!L|\/=s@hs7k*"/9~`v? t1&ފv$vTn;6vNڰ@A[$EC~RZ\K2{9r/_rbrCMs=XTT,Aב^~Kj8( %=,ϳ L]E|t|1*^^,/SR|#e8388sK ɉšB`M7k؋쟘:| d"lc)&ZԬK^L] 4^VK}Qî891ro\NXFnEi8h}> '@9t@8 H$NӀi@4 p pAԦ)U FP7 hmh mP6tM]Ӏi@׀fhfk ki@P5T U@P5T UӀihH:pDJ<QP?  A@4MJ< yh) K8ӷXɨE&~hugA,HEgUΪy!?1>fV oyU&%f@DL2(Z UxW[ƌ=f9٘dcYN6f9<%dP KŒ'3lx15151ƌ73]5'3l|1'3lpMnYៅfwcf30 OQ5'P~(þ (}} k،b ^mcf .x]vtف.;W@_諣GR@'=- :@=v?Wte Ltс:Cz@=ttЁ:Adzhõ ,z(^mԸWe_гF 00 Qh0]YRZJ*`c0" ?`#1I''[ 2 +1Xm?AO0.VA2eFf̀yQ4`v o@㿎h57V"ggYTcn굣ª#G}WS㯲3#^u׬ LFf9zPR&z)[ެe[*@̇ >:2)a./fY犿&^BAS-GHHLu&X֑!吊rHE9;~WIWЫAr!9lHO_ĝ ݠy X IT0DŽ  cIP뀱Ɔlol耱AE{ X,Bw:=+f֜ƎR*UJ*WT h =_5R gI1#T=BD}^:Kx/चGP*G^,z<Ih&ؖ栖yh}4ɉ`_<0RBøT煐V*)CP`q(9:BHTD QPKQͨfOP5HY*  AS ʇn<Ѓ@[h ''Gd jRrSxR=;_p^P@6 Ȅ dV㐖.vOų&%MK< KX~VQvQ#.z6Qj/Q6x5 z5 VՄhro5$cj״'rN0FwUʌUP[{`< *AySkԪ@(R5jT6^dLTЃVӈYe{^[yhP)zY;iQN*ƿÜ 檧5Z=QĦR赘q+eYdYzs'!'!N-S;f{DIH4g{x>CXɨB'7aFoFlVXOB]qļ(E!1 JHp2M4X!"%zƴ5egl0 5g6g ֕=Ȟ`lmpY n0v n#Re.9ER^ax]^9.o yCv%o[Dv-oObyOcdvtޅ3xwv {i?M}xWޏ`P6#<~!XOأD8'Ezoai|:{CeU -"?X 2/g|%'m6+*ȾWS[:cm[2o6f}|?Wp4nCh$IlQϨ~5dzF#0Z-ahM$-F+g\igCLRsd-rVn r"eMF,[~cUJ2~ƯVCQad5S-j6FZ4kun]eM0Y9ufkuǺٚbYyfk5hY k9zziVYX[Vyy̶$$NHH3g$tIkޞpa悄v+}L4+Z&'|O|O|g=/z^-}|}b{ʷU\)&~W~,r|*ĵ6l ;A`'ډF;ɮ'nMTFmb}}jwwvwȷڙ>{%A{(ϵE%b=Ξ(oo)=Þ!^gڳr{}}xӞo?$Vُ؏B^$> B(_/Wu{Xga%6٫f3sJ|O{CE4#R/_,Ȥįɉ7zP/y:z*4;Ҫs}>E{crqW.OK,}漧ҷ>Lpmm8T29'pWrڷ9v9]M>Gʏ{\ך*iKDzj KV~r׺a;Ea;F <9frGut{J7Uy5Rb4e6 B2qR2|_pGpY_V#RFvֽBZzҎйzXє8qFiGi6G~hZe[1#AӖ~'@+|z,-c;7;`.V|XQiF}9»0yGJNoz_W)(=,o WW"c M{eݿT1 __1lڲ_}:G8+ p]S_Qs8Vto19~].D6[ƙ9*jS<SZNڊݕGR_B!S!USzv*XzvnqHȳZl1;]G[=[cs'qk;\ d+ц[܏OIs -*Wqr*~h8=w7^(Kk\cVjҳEw:ǯJVhEa+uo_d]afpx1^2{a\ȊSb1\+!S֫cZ/hn5~uVbf('UOcȺZ8v]Stx-SMz&r?f}'Is83[Qg6K$n(@-Ѕ1 wAgx)B.UYpY!VأP# _&2D,Twp)}TȺ1QBRc+룽fp5$Xr!Nڕ^̣Pn~QJUO[_*1/*Ǝۇ#d!lF#֪/q~sM 9ckڇPV5?KKmcy֫}FV7\ptjp2Jw71C^wzEWWsݫc9N>k dSXEGGm(!:5)[M -OsQTV{>X7N1)~Lwk囂Rz5W!\Uw>_?g& ߛ;][犙=xpjFxmSW^Bxxr5,3}Ux=;:92- {{2V[jU-hp]gu⾢Nvᾮ"-G7zo^ą *'_=IQV~­o«=-P_֏7_ƺk.vOZA_v7kOK zgew! ӣƌH~2 )DZ:;&ZB#] wWš-GLvx-^ iWy1uw0vջ5ji~y=!C*+ĭ?h )ZY'PL·sqrFZ5~дay:$ [̵,wV=}m/NӋ*js^w.t(;Jj}̚ϓ3iqk^b|gS =[~CnѾģRTx10ɊO*:&V|C j7FٵL__W_YKw{}>Z HV<#\}eO>UGu՛/տk{WyKz$7Xިm4LRJhMA4f^һgCJowpPܷqZKX]V~cDZAl9ˮfYAƱulȶ3M;;ܮwCrz j vͼ5G07oͩD+S'^"E^ AA#ygqwIW"K(B|'Wbv+[x3%ҐWI[6d y _';N|EVH=j  _79V5r|HG,P^Yc|^#rq|Yld}%Fu"h%=1V~ ?3.rqK˸QT.-d[FH1Oa,TG33jSsc]k3[њm6[wjL`G0ww=Ͼٞo7~__0RWc ~~pn&LvC0M)]=Ll3?j##&ϐ`3H 8|ک,%i7RpUikO xFp'Pc MM V3jE{|mU')TEπIh-\ m#0ƬS5fAgGRS7NL2IAi S ,Lc>jlfd~wuKfVWya),1;AnXC֐F5gYcJeMXjԓ5cͨkΚSoR%kZЉڣ89tf`gA, < f6<sq>Ngc,2<\Ʈ!nD7)(w*rXNgӑAV6y=DjeQG=N":BBֱu4gm;NYlACN]l en~D?:Kb68;Bn!9br]܎w!mȧVnq7s\/B"^q/rO܇8vX"m(@C|T<sx1Ϡ%ųEpX,Y)@o#;]{}SQ N_oķ诵b-֋ Gl&*!w{=r(eJ.#NʎyKg}N4"jcIY6tl,gL:I2:ʺ.b&/n#وdcلNMeS B@'[Kw[ֈFmei'OFu)-8eg:]Wy&t(CUr8+G",S凐#|\>Ea\<<%i4qeRe|Kdʥr)%(z*F\Aǩ"5V"*KNT;}Ȉ} 5oV%)d r(7!imARSB='+rrp YtI &5%%-2+Y>Gj3VH-:VIHrGMV}mh5Dx# vjY' Vk<:V[aݞFut ? qVbmV+yQs+҃;:zZ[P/B+z[Q("k4+y b֥g?uJܺ9_a]BH5raUS'eU NU}3unn6k aaSGeaSX7}3uRv6ΰ2ӞIY,jc϶g{gBXEYUYt:+7ΰtJwcDޅϠ6 Bw. ,u8,B PPāFG0HH؇9ڎOV{gvȓ-Womm,m7ֶx3mmqCNF\eymڪVumUVucmU7ӖtsmI;z&sGm=zgcQv鰛B|3nچ>]ݴ 6tm=1zް@M51’nKz1r+'`%? K;{3B$B@s1"" "RDD"U)RJH 잇}J!"EJ)"R~(")ZJTir? z{9f̙9gw}/ߙI%op5l⿃m^u݅ 3Y9_lƑ^c@|lG6?"}; wۃ#HKkȅ-^ mil;`q:?#އ z'wXyO}Yv οp:7sTK! ;X.W^c`ӃɎx4Ɒݽdǐ%=lw/voB{<~;wH{lTi< wl XY(ܼ , >tsQcw>χ x7^ aoA?A{?@/x^3D9шĀ x-揰8>ИЄ?c `x4ğ??~x,O-Ϣ~ H"Q|x[ԯAa0"QD9<@0a D9&rC0D9 rI"{F9$ra8=DÉ!r.D%E4-bE,q"xxH@hZd4JB.v]X3WE8RdCNj% ,&#%f!\$!"(926TRAxg/~v֌EX#j8q7A`X[,KwtHшsı֎I8ȣAG_G_11㘋p ˎ*j:jQ\\Ԍt&R@Gm3mHY``,R6H;z# `4t/*|gBV4u3hV0Lu7:#p|ⓜ$1x<&Y(_QY6QY'M`+%v q`A\w!EQ׽{YSHH֜+h?qT,qTSQ%ju=ze*jOKԔX(X?QP,QPsDA?|w]aVYE>͉|J2)q@A-w4'nI&2I| &Iswg9O]D&9zW=U?K#>I%>\R,Gt%VVe |J"6ך oVBCFҍX%X X5lbI!b"bJ҃+K>KUkԺkjD/7k}ș~Z?=A>?E\m.  *]k%V "CD"ZVD\4((&⢛ZnԞמW{€r Jɋڋ̫րI^^b:PAۀPQmDA^UU ڂt?MvDb$ܫEX l AG$qQ\$EC( tt)$i` )y/҇K^1jQ$OO]@EMI;Ib+)uǺcH) R)I"%/H5 xnn&Ejpw@<ӝɢݝx6K%APWԘة S4Oӑ| W=-F4p`+"'*@H2d80 hD}r V(WH\e U'7 SDzExXF1V &77VHd؏0՛eiā}Sӈ;yy!~00ww(xaāc ##XKpXWXXOw2FejkҙHVk_޺-/?+wP7Z4jӋ?yi+O׿U_tcuP_tUb_!w5[\Ԣ8\Ysh7ov^P_(e59I^sZKϞv}OrBR&UemPYuUj?%eW4yGa_8Ca=w'&ߗk z{_^Um]kңq( Mν53_}ڥz:|ïuW~u zU驟廜VrԠףc-/݆_o[wWl+ {f}wVJ]A/SK-݌WrEcֺ6~lȷGM a+~W͋vcwQ_Vg|lV|f4s1%[^(ow"Ykc9')zOy冺ڋJƹ9_͚RV;t_Zfv|e) ܷzm6󢾤je/+6}F~žnjKc ׫J6<'z_/Ӎ ߀~c5^Է]\l8r~6~7ъ]J*{"K**9Wfxyoa{ zͿ~V"K}~e]E ]\WWz |嵫oiǽyHWokgXR~Fg꟨nq!3"Sؽ/.}켺美+F߬W.3tϊlKz[oy*GC 6h%RWj3y/9Վ%DEO&WyDoїI_g`1E],F#aX/gqA15 W%SQ4"OVbR,Mڐ/TU ?P;mjm)X&g ,[Ju/Yw[[ClYOIlb}uWlX.v~jmV@S7?ZV(wq@ qXfqw6D0W|*>e#ſD=OFg898GcGw$D#Mtqcߺ˦~v_fOݗt2{Jf}cOO<.OR.ggCEu2o]*EUsԎ.7o\Mr)ȟNTHNtj$:It";d 퍳}.Kj.IjG$=IRBRٱbҕ^wH$_H=$Y$n'c3ҜEܙ91Isf%K㯹X J~ywOl )•f$1$(H|S$)$'Z3rH&IvjyxK^WA;.EHC+ƒ!akqڑ%C|ڊG9s:QωF4EG/jI(zQzyK1^dUFjvG6EOKM=-Vl2ۢSKz:I#\\uE}OPs1ӏ|CI07g%ó:I(=A2g{꽘GʲT_eBΒYScY걬 zz//}5"佒oѷv};?D+O^Ϭ^Śz-Eﳮ!r#??@\dHF@ 4~??aj?vϱLF/^X*g>,eIMzX{IRzYks;Q:)d3'欝l![lLb5Fc8Q~UdĕM7%X;k!{ʞ,^WY4tS_'dk)o7#g,[,|s7$١r(»-$GY,t?(DɇY|D>ʒD99$'I?&C\tS@XC,#p4GB +=jKn9XhP#݃|;tI>ҽGH!#ݛ|{tA>]G:|t.Hw%F>ҹ#ݙ|tgB>ҝG ?{> v~tG(P9[&nNQ: <.}?JB~h1cwnCtz|x mxN:A:xFF1cH7uX 7r8.ĕfucHǒf#O=4{1߽&19Aǐzx`Kwgwgpuν!tww6]]߁/ǀ0£ϡ CA>n8Lg.KQ!Y'YZ{cْFV2]#g{I4t$˖2[f+ҕfK#sPowj!F})F|ĕc-+XhT Mc.ȣF!arʟ.:~14f4!!=cï1Cǘ1 j FI$Rh,yƑh#e5QǢ!T-%yBƒ'dlFy,QFX έ(&HieZ^= U>{}>m {B`d`u$0ʶXcv4R! 8mthA(Z:nm o ׆τkVgU:Z=zqM s |!gxShLIV!%,F+@)Θ/UO ^+B T՛Q.AluvPVf  g/j^MuEC#"#PzCPobd7ꍊDFFNFN9 h+2-2'k#Q@ yl-o [X~k}.0e^gUZ{el{4J7z>Z^xK#yaL iͰvY3BCCCCGN{ OO -f)xC%T~N:^ރ7_:So /;> m .-C-ՅK!˪+ՙmy<ҝ \=Lo#H.W5{@AO`6. ̳_PnjT˺ m7DDS78:\Ð nSRΰDžCBB<{Єd;<X )IC*R*+/2*al(>g!H]$DGAȈHqĎ,,C lT쏜TE#"wFjkB6C=9"t4t"ɑΑua9-^p7KUv/k_`S`-{j ,0ޏcC 3!SSA+a *~kx`I`y`%zz˴gQ4{=.`T02#l{?B!\{=ɀ7ZY'vmSw*>)f2t [XCwAoq?`?֯rY-g5xGS@Up$p45bZc8q$ђ=ڊkKx&lhf?ޗe4&qYwB~7n٭>O`I|ȧv>c`Q"{x(wȆA6Vp6B`c~3l, ؇;Z6!V&3`c&qMZP|"β8`|3ܑ6:ZHs`A- GGg3љc;NDDs:ss{9,Cjh&[OY-+`5Z4ꐖ%Z ;B>yRG<- [ 6mP fgb}-Ӟgg=윚ZmLVNj%]x5g5wݷo7ǻݏA'O3,>3w)uV~{O=wOp~? [(T<y>3=?G񙰝g )aq7@<(e2IaEۑGdg9ƽ|+(t!G|+]rȓs7d,'dKC#i0?-sryT+y\%#|INFU<&O<-:"Û/{ "[ nR;D`V={ }.qw?pX& \ i)5s1of0L|좑0ˬx+"bq[V[[n5WTUY+^]anF^Z}uZ]5:|(ܼh$J0jg"vk vN;p=,gPY{5q)>nX@O"diy%rr07[[p՗l7u03ҷƷl]͜bN7g-\b8c|Qc8kD܆W1ܬK9f]C%{FCq#\n77;y#A4]4XQVQgx-,Ӝn-5+[ k3]ȩ[ hˀnfXfgsg Qmf-oy<ȏ@}ۗ/5Q#Fu+ZUZ|qE]U{^:_ԫjyQ锫vߗ\Lͨ㋛oהc1ؘ^^~c/_ èŷ)qdf @gLG% 9jƦKz,Z_2ϟ>_tdlQ?h|W ߶|U]_g2`a1x~Pn0 q F7qlYXԭ2ߢ8?nQFFŢ(q/%|)~$ jE|cKKUEEPnU0dĖR_Ym@kP/3㌹h$R`-L4EGN^jTyf3p*sHyFY\2?ͷj4^,/j8^\KY,C[5?AWKͩ S8sxZ%GyUYa%yg=sW0%;hrOYؿC![c@63,\/ͲUS++2eT-Qo2j z{h5՟W.6F VC:pA߾Ҫ}ey O,ӧU|͆ܮT|/Z%=ڧd ZOXS|qD#j1eFטM&[LwAŢER}{TyowO c1 !\-+c,kY1bcA,bb03f5~0/,-2+1e.,bcE22XD(Z'ιϽ$Ǫ]U}}?=HWDu;uttmm] C[[%2uk5uuwWW,sП?Od_@~~ȡHx%KD.e_#ߣG.}DGwD>?Hwub/AoO?F?N(֧ӈ~}>>SIwwgl}6>GCsG{{<}>_O OgDH!Ja@DL_F`#D1j/8QkLǍO1~3~g?#ꍯ_%>isDQ%y׈CNK}# +7 s[o~~7o5?Cѡ{:Z=dQ{|m!N+ѥ:-FwIbQZ e•Pf̒vkY2D;V=\ؓ(cD41$ē$U&2n(]eۂ#Jv r}b%v@-@J`͆7kFrYj:J& 7ψ hj1 HrtZʋ6 HH1:v? Z!-HIǴpuKv00!]d|2(nd<F4}iUK`^V3A"7oQ=CI٧PCz7vߔLa,n6N8'LA;5P2|m4($. O璓d{t 9R®eWx$$LɵFLUF֙V=kTﳃ1!/:T?#*Cv`Of\#vb3~]iS2oDZj+c+q"R`$gC ?B̆sɓ#Vz! Xz~p H+A3u.W61@}ZVjy,^{^R)kZa. `wJG>,0go9<1N| B9O|3Ώo(&"0|Z>?u|4Ly,i,ӆq_vc~ =_1AS:ɋ)]XSZS)? }j FF`1 NS%^ǚX4 5G ,sx%%uGX/t+?/"߯{wg$K$$?{Z Y[-tRG$$?'Y'd pM|iEo[%?NyPc}f Қ?BZ3U뫻F}Zv]5M뛻Q-h"պkvuewM讷vEu UzT'RcHvd=ʼksuX?Rvb~tʅvSk)Ig)/HqM6!MsSAĹS%M%]TyS5vRMԟ=ԫ:S=5vRG:x9˩˩L&5Mꂉ5$F]G}3ũ6P4 ^M MF~3UӷLCۦEjt0tzнy}m|~E?SCdGQo8$>UU`)`DHm *0TBn!ΝS+ ӤG:q 't'J e/\(bK~ viQw2N$How8lja5#/xsiIy͑ jwW ʷ(gemRSL(}A&m#lõᦰ',S[*)쏔AnsV g@R(m B o KAnLΪWC\:/3k"0KG1BeqSO#JH(AZB+7>hU@ۥJ1WB$F_EHzJި7꘿1c1SweAtg;tWqVesRлrur=v:Tj{l/mw$[+ݹ<<h .ZwGqcU, !1h=bm92S >e-r-0̎9_>^r̕]̨\Dm-lp:t9=5f]^蝇-sr̛slks guL<^櫙 ua6ǵ׹H7L,u3ᦴmQ#AixOQ-uX-[ d#F J"/YsBw\r9ʍRkC +ٜPJIi۝kN*UVjs1l<^ k y 28vP/Q?%p1 U9/Ǹs ^-Ch8.Î6BZGN㜽y ]i1'SYk{#VKZ[=rΌhG[t;¬*s3SYҦ9U\ ^:yNe1Np9d59\QSr8[3mAPM-9tm893 vgYfX hNsp\u?Ce=MMcbG-WnĨ=XJ :Kex:Zs*Yy]hp-/WCs}&J gfƤMO3y{豴ZFBl r>܀U2m{|u@l[d0hiMە,עk<̷\&[9z \oN3i̤Y/qK$3x&K؏'1y^%ap+:2ܐg]Pz9 ^(x2E:IvL{"wݡIq;1q+ A?$H A_'_Fz#RK{迧DGCȣE?& pWxZYP@xxxm ?ڧ;D(E QTOsfJkh39/bϱ>1_Fq*ۧT򯱖HcE}!ÇɟxgxSS))`5X)=(5(#(Cj9UrEOGQDUzEOT C(zZ zҨX0PD9VDZUxO`kXex%V`jju:mcֱWj~lzubw(ҥJti(ҽPttBѓ#(z!t(z}EO*=>Ӷb D7/뾏u"HMrHOwucu?<6 ?&skskF9XosM[j{ wW}{ v׊|?'}~pPp8rI 7z}YYˬ/חPvDz,|갫=<&xĂ .n&~@?.]>f Vk@ܿ#p=/;h<6gBW,YљWQ'}gOx=쨥Rq^ / Oou;9 (.̝|e΍m: Bae4w;ǝ6'`-XSnw\H:|σ%}#_#fηm~ǯ^&|}S`3`P~6W|U>?kjC%m@ߟO7p' &;rÈo--?®׎pe{BxlYgY@tMY<7+^'aωWXm57"Pẁ)P(wNO9_ Tq|_p9i ! jfJ3B_1^瀸 eqr>*5:@a{+ЍdA$E9@ }wZQJe˾@% l@j `dj8 N9^Ǘ|+#-Ľ0OM\Geh: +Fh㊄6L8(4̰Bso P湠XXfYof{1}BzwfĬa[Yof/aۈY0m¬CƬ#a''xzn'f"?73xO%XS@,UX_*:VU XXZ/ֿZ?yORmH%c;faA1}/9s=xdzxGAx'sArwcM`MXŚkN3XSĚ5} R2l1NJV促X.VvmA~1HXU_b~UGAB =_i_WxW؇$ " ˈARª S&?:-%tN{˽UzKS9wrV r7 Pyr]To><;k<¬8Tق\gjJL)c&fu=t_Y;\e;v[ﭰz^zoXoxz C,g-o\ly,Sϑl mdndcpmͼ #2apxރJXZ d<ml*=#G6[{:>Ya)&-šw=}'.G>}|}8lyecfZw\8v7oX6/Qbŷ>NйחbN|PF}cB e|Qsݑ#>^?tZ눷c>nud'YoX̍\;qC+k\+$wHwpXl9͉U;;b+&kwCZbk'kJՆi`DbǖL5[o/*WZ ,+NX GֳxӺ p_x<~~eۮw:bcbcc-pYu@!6g|,! x t6L^[Q:'~_ -vi3\i+Z[L+!!M27UM{aۻ6u߯0ݴ9~MPt퐿(8|%'!6%^ړS=8o%k !^EGo[DSp+( :VP@[,?w?{ڋ@7uNAaܿ? qCJ MNRg|lHkwHS!s;:;M͎wY[7בՑwwuj,adRm@}j`-5 :k CMPohȡb,4|3CeEjiܫ Blh:tP[O|)e mG"9Ps9i@Xֶh|cd5am 7ɰY^O_xtw, ?@IGgwjlak3I*i wÝq/;;+ʊ yh_[zN| Nˉ<>EBgO#r XǘJ =*{%I{) п/P>?sb(13۟7;3Ѓ`g(ϑYɲM(# cD=̙Qנ:bb5qJ DWvMuf8BbĵL{"/8U2A_A_;r6"ZE; TOWp=4J f~ *X3~eWA eј1?}ax;lx>yTGz(z]ҫ]ɻz[ V?YP { [ Ÿ^dě'uÀ79>ڈEɿ13]yjѹf]U^W#1(mDh#jЉk*\e*b&]pNFg(ë&#Pck6y}d'ަ(+fw75,SshLptkUtAֈzh~'k=C[uz+-̖+~fjdu 5:Ϡkt4ֳw^ڽUR8H'-}!Kc[4$LՉ)Yxv,2˵kDk7[Z|q18 x7꽋.b~r\]d#pz5S,J޲5=Y}5ŽlW5/+׀{]׮W׽!5{:beVNT\Z\׬ k:~҅KPPߦ{!ߎ̗޵0ZX}WM*נk}tzwH~7l#j#}:FihD暭hQ%Og0:vHk'-SoSs_s>?wۻ=~|/}k->op(w;ex|a_w[E.ˬ疭z|מniL&HXf,Dg3㣿W3  uצv݈|ӗ!9/ݨtetMƄnEkOݎhnŢ,B-JM %N/k ..kZ)S_k5PC4 ;z~??Z__@SO}$&?F迢 khhG+\F+\ڛG\h?ֹZֹqOuu~sshC!%55Яwbi-X6.mi Ji+F[@X -6^蛻7w 7w_K9Fw_%QhTe-שZ+Te-7Z8w82ZZiqq:iߢ2/cyh?SZNZMr~,mnPOedȴ*T)KSQvʼhm.,ZeFks\٠}DkjӾaoYGka h~ kk`O Xc0? 3Śa5뇬Jf@="YV6K7hn_MKw.ݥ=tKUhxR-m钉KKfhz@~  4A9Jegr|6ED);9 (֓$]N@IJAR]FVHbRl}! m̐r'Q +UĽ%~["J7*OJ.j+](e]]:V )E;j$R)ptCtޅ~wID1x@23!6i}`\j❾4TtHAޅUm&xؠYUh1Ry:Yvkf`aa3MJɇd2"u*J]"wKﯧwUH9(3 I=8Yuu^sZ\-IXBcg3RUtQvJj+5h%|,w6,Q>IUj4tGA>\T*ͫS@ի;" }*NSz<.K'E;Q@zU;09 Sz.$k (Jb3DmY8R! H:IzN=GRe!M&ڲ)4kUIGcCAڟ@tڏh?bhK%A[-CL m֠8mmѶh;#@b~S1]YϠ +1Pb_՘k()1?_@Ɍ!u0ca@`2Fc &c12&U$c0SPc1q[-(؆2;[WWP&c }cA<?1~gKH8a@B)1gxxeEcxv4.pyy a^f^̯02*$c~5̯Cyo03&$g^e^ i4HLgCJ淘߂T̏C7טנB)n1L1TbfA0JRR3eLTcAf^a@eU*t^u{iٛMRRRXcXh""1]i'@FlD)=qJh20.QLE+E@Ɉ bPY@mn*ċRrޑr]<59`.h-*]Dz!ِ'/O.::= r]yE^*aF槖.?%9F+ "@-q; 6#BTmB¡S7O;:_fd p-I_nw8銥Ee.~3q?tf8,?m[/1SW*1#vYYe*{=庼.8zjr·G"O6dqR6d~ĝ~S}-r9'{D|jov#yQRUQB~}OyE%uIHw\ LݩSru48HLEtQ!sR'] 6ǡuT^#HA\7{D!w*T|qh3E7|5lH9SKԶ$7Їc(&tmG1!BD}ed eb &'Z!t9ƭzǔUO\w)gwQwSH3Y>wJX,; 4RX|T5gw;$p$qbu9KYSBeYtLQc'&ضg/'QJ2)޷,<[Ea-]X"}k*l,kzf9ebE@mZ^j-]Yi@baD7[0@&Q=*̣/*J}\H!w,ˆrdRI@?u Q#rstN$Ӳ3 °!l46 .U.@9lϲfXjk:YnZx q-[ q_ '9|pN%8Yֺi=Vi=V yΙײl Ȅ@f|Qe_)nRJ9Yo蜨ԃ{MZ=Ԍt.pC\k9#6{'1g8w5o9*-' Qކ,^9bِj!Ijt)w~0LAiS&Ze\ fRH&kVfƟLzT0>vaEm#{UlV5 6j[6D20.;*Nϔ6d3gI!`@WJ@*rS`4`Jnzsk„&ޮ,x߷+ρ"*]2hpV[ H~2l[JvÖE>K9,ƑU?QMJ$IxaҺފZ~JG u"')J?'5l 3VgB08.U>G끔7`Y܎7 ]1W}7)%-\s_+G+{|GXG4 D/G&*Igq}y3Ɋrs U߷%l)6.~l-dC`f.%|)aɒaa{ۃ#R`H0$ +D~"2* v%]Mo#o9;|Sj&+spo6Nl&Sۄm6H!ö?^۴mBkZѧ#[x - ]`dVl lV-$?n\(){rSgW,*t$tnX-^[& y>Ywj8liEp L[fdɹ Ȩe ƥv~"uLɪY<E>Dn,HVr9zA001o:\&J-GrBS2Y+y'K,>oC0'@xG ]GFL~E~ynD A,LsDB )>~ _-ܑ|e"9@cC t>+G{!!*ÑcL\9ٔ:}gv|};X◮[r(3v s ݷĀUNQjnFAEl׭$@F-Pd Pܪ/㓾Xc.B$%]6ww?`$>qh7vSwe0ǸYqY\e3BȨM;26xIǍ/+-c86uDpA/U#~!ϐ[XV.'a U^mB* Pnr83Rʋܚ4˜ƴvu53/yW煘Te.x)[n$Trj 409Uykfg֥O6d yP0-5ʸ.afHRUw@>ZɄhmU5 A%I)gףn\T]qA؍ \ؓKjw'D}Hž90sC9'%7"8b9,^%82\\H'cv 5Kj$%WzsA"{>{ .jW$ K\ڔeMkZq/BCE_MڛdF(Os37i]e(JFDWa Y@k̼jeS'4E"UZy-ŕ:f)5)U)«Hg:!&JUBGȨ9V+sMBEŘ hJPKy!@s~x\#7[p'\J3H#(ʹY5Z_p3t `qॴZ5_t l<ʟ|[)y"bwuD2#fn"f13#p =S *HzmZ,s׍A<%25Z\{y^qa0i 07$Gܗs, 2o0 m @͟r^ Ew Eѐ-b,3ntIVlJK^`ht[GERd B^yqb=BQJ3\Ӫ9,t]D %#f@/5fS* YUnO3HQ =0fc Ls]IWF,ʝDS [vG7jvDy b 6c5;L؉dNxC~Ql^aGfH2MH%7_H.ֱ-̞#,sj%wY،$ %vfO1/&2ּ "kRElKM|zm<@݃o9k?4ݯh6,+q쟁ȳRp $@Le1hٗ~uUu " A@2Q`I$3DEET@DLT,"Ċ^Wg:sW6_{|sUN{^8Ҙ-J%mKv/;I8CT4S2'# 6™l!jڬ:ê:Ǫ:h:hĪXuИUMXuДUXup6ZVbAkVaA[VcA{Vt`AGV˪VtbAJRlϯǃe}gᝓѭE_<쑼g 'Ǘ݋f"U<IGGusq(s O/'}(^Uҡۺt`xxN 嵟׷]= a L)Ogbٞ &vN =P>U /^<+~b> 3"!\V,Mv9.>7`r܈]br܄]q3v9>]q v9n.q+v9n.m-cr܁];r.ǝ3wanrܝ]crܓ]{q_v9.Ǘv9],7'EgFl5u}l׷>%|;0y[ܟy֌{/ߏ||k{g^«x #X;)z)vK!Eu!5%!ǧgZK&iȿV_ZO_Z/5֚?k-6ZZ*?c ߄KLizV4^ {p-+a=}p# S ܄f"BR[Vg /.X@ a<<΂ ݙb;w:MSnJ't`9ρU\H!1thálx&ɝʅSsOM g{[ݏ<93% U>+rREȅoȫ2|> /G#p;qOV/DN:sfbK 1 fHO)R5r)O3p~P7-b#6))CʹG_kmA<܋tmup]M' 9wBU|9jY 0C` 4 y 乶tF>!7YFĽY8fgO:J68xĮ\(_VS"WE$%{S|C.|=WlV 垜\#4$1W'NPQʨO͇ucl/3}ygܛh Bq.%EE%ǡה_MOx}QЏGVFq><&6BfURFͩksn j ax<,)feUΆaGbaFp|ԅ%<=yi?OB Cݜu %rdRIs7W_t)!|: sMyhZrĠ6P>xG_FKp wY)GZKh(5w kws6SZc\'>8IaB'0g@r&ձ [p!YO 3NEb!(s#wNX~I(p9#nR5SڵөDzԷ_)xZsv%/={i+C'?y%?Dv<>BVP4ܑLmXH-m8 bun$?ކl4؀#<=z'@<:-zv2hi-#>iCɐExP3Y-? @/%Lħ=?h4x,=9iιy_KH]|U~'O'A*^}4*蹢 {3q)P{# O\tzĘqx׎Z18AjJ>DFړϐcAR՗S/{ !lG,GY΀PsiգnkC$·zq'C}.^㮽Su= SOJ\BwC Gx'E={ ]{YcϖYߥRkKԋ-Z缀GTxvbzVhi,<}H]VKtF܅UXQ31%=?c"ПCIdZ%K[lb~eox;i /Ɗ\Ad6xw ev˵p& ˔~SCֱ 1Jf <"x MZ6ԇg3L.+ʽ.q֕r2ko6=IOL9]G/%HP0z kTL]g4,;xc{m虊FnxfSS[͓^5O2Nc_xR(ךSkWz '1ckjָ_i CWQdp/pB$x1}y(hS/ )o9>ܗ,^Z-PkT)}}}Ni<מD@ڲDZvT4>)H(?ZDb^Ox)f\ZmVo;&s0;ï…fJ57`5XϪm6xFW6W!mq\aR~Xr?Fc$L#ypqCߘs?C>AM?*hM7_BғB8nE?Gp~f"? Ug2>iykx-݌ /?aJn䝐IkAX?[9#|ͩ}z4ZXpb( ~RXSxE ߑ7!j9&p̆g#$k GV{H'ZiW,.LoECw_?~ ML4Ԅ|ӑ ~`?~ڢwh?[-sߞ8h|Ai[)ahdxv4|m3HjӅ:R10%8XCyU~FuY<6ΐM{) mnA4߸VOjHGtDEgueu֯.N@s䧛@>LA3k89{9P3uFsAO/ϟzm:Kq}32K>@3&`/x|~m{8jy\I\ )_G;Jܝ&NaS!v6] JkR:5i3SK Mρma٭==tZe3уҫ; }O };=$Δs¦FhDry22ڹp{8k'*#wE#x!"c5='L[ȼ&X}Ѡ/UR]O=zRR8Je`/HV=Y͗5Wvu%}/!Ah\ͬ-Re4댌6ϥo.W/k|[<<–q L9K¶r]oY!BژZVxZ'Cwj2[grTswȹa ·w3"o ZoѼϝv#)`Ɂ>R,ع?bKsl ͝ٵ"[9oMXµFb{. w$yOcnuyU"r]L\]AsO*y> H)|$rQJV7r,>CxҗQ܍;ͣGy?)#[񜡲j.X5+`dQGRދ>C#Hl/c?p>"\b`bɹ=Pn!|e<} \\ #GXT ytځ+3O=f `)#nRa34ܵDWLYv=ruämVa;yF Q,Bzkf3N7nH&K*SSrTy UH NȏII+d^8EzwĠ3k.&JGG;Š-Jt&EGX 誒J3Qbr)9,wH^#O+w+3EJg%!/ZZ׵ Q^IId yU$TT%:} x#(V4gy.tF;ӿΪGHtĕu[\Yf8ǚcU`sHLy)ǧDQ+m|B_c'4vҒ,9 <1zOڗAy3zU)=dҷ9J@o:y{F3/:ώ[UCh*s/ 7߈_R?z +νSG٫y> s9& Y]{v%θ4eLLZQW6ig 1~'"_ѧuHL}<C֭l4ٔ#D:Ր0c":n#lVGQ̃Ɯcf*!ej1g,)E|@>6f#KYSkҘ55S un4Ֆg-յ.SRw_Z.,&aXz6zٱ;Rf%).zf9Sfb"Js([ȭCL3_o'd 6q*'#. fS'g')ä֤XB3l+nbJI]GKd{ C4+23Ŭk,te6][sm# _/6ar CKZR:AEoќ| G&|ҏ]p \q܌~:|W#*83\s2|<|}O͜[cݵB"x=9|~>B!xABr{Y>IlsC)< C_/m (kmx>N>]9S$Ǭ4ǡ6KҠ+1GHՖM `㏘e㎘Տe-]h*G._Fƿ -N32'yY`3-fF Qh`46͋GMѷ2m`^vkyv}~*3\Snr.߽>w}M}k},5wo}?zF~cEO*|>Gg>'e>6e>e>we>?.z+-b߷pQaXﻊŬqxH+}y^~cɾ?pQJJeZWBsn.|)|Ϲc÷seݞh+ w4']9;|Ϲ P&L5gBfқjs;ߏ͑{8GpKǿYƑYlns9p? [Y^ m$%6FFdA K'?OƿXӉXSmIl76E`5۶eee22Jac2XFY,qQ8˨eeWUV>*bG*q*qQ }}}>>jbG.Q}4>bG) 8h}>Zb`G-hOv\;RR9k'UvYy22f<=+ߛYfN8o[?U%mvIh^vt&6'i4VI+%t].IW-%+%Ui>/99',B F1la_dM@ F~a3ADDDDĀ FADՕ2wws*uޮ{NnuoѷPw6}Kߡ2zC=g3ԓfQ/6C65,ԟMeS6U% fVͪD{ MbodvEJ4Kzn_Ur%A~cdMcdh-PzK$%RRRR,EzK-][ K/^.&\\z,eK/2H  3o7o|NM_Tk,8IX!aAfÂV6 ENC(1lDFDa( ^t7lk(3l0l4l2,6,1,FF4,L5,0,4,T5,6,9B?a 0΂Qi33lM)@[r+Ǒ>+2+LMj1E8%DD44n11́}E5S%Xel: OR3u!;P  (8m44\O ʹ+i75et *ԁ V}DCQz Uc֠'S~ѯ9-U2Lyej֐3el;ہjI!βŚWp#<\˔Z׹ 1ދ (OGS|)YôI S0 s`=X_蕆&6B4%69l[x/V5lo*-l#,`gx4wRxP5wBt^X{ rW(B `8ÄGB1p,8QA8NCp:|΀3a|΂2!h(C4Bh ơx4MDd F3LTAgd!fe1g Œ,Xz>k Mkrͬ kX3Ϛ%+`Bv+kZ66Vڲv=:bI(Y ;Yvf=;'z> b6 clF1's17󰾬{gC+S#v}ΰOXrB@9|R>RN++grNT9|\P>W.*U.)ה7 [8t9&N9 \7s rswrw(8O,<&ވ7fބ7y-oxo#/xg~;/wR~'wwnޝx5_mP[-jzJmQoSԶj;AjzZީvzMGkSЧ:-W>T :DSS#RVWǨcqxu:QNV_տү_of`fl&fVC֭aupx^3`-TU-soju\m)A rmK5V+t9ɕ*CzJr=1zHD?yg v E,:C|"aW\~g x@縈oX%'y6 @$yK-淈t /RtD H%oJ"Ѣƨ P"A7DT-xEP kwv#ƓoEvʜYiz{&W|Gߢow9$m]2n1X5p1i .g&c~`4 ?f3;(#b0]t'\/"ZO0݈)f01F3;C@>CP>LJ|'A>OC1>?y|>/O$K~ xRL9ˆ?ɘg^Ȟ]ٳ-lȿV``P@h #8 ΁;gH}݊Z jf n`!Q_ D CJ%;dT4@j`b5]|tZLL@[ʠrA1 siZo”i;NigX*8?t`?6` 6M6nb9p'^{kǪxf_QJ (ITe 2)˔?.jkf:]*vZ;~NE+GsmkH(96)%@2TG,(M#sd.G'$YH"d1y,!"Kɯ2( sp.'$\p1|.K2> W\< ? <WG,/*s߭x,R'T/W*JE?Qwns׭~VcE""iDyZ"S|)"#s!ޓy^~?GQ|4c8ϧ >WG,("4_̟K% +xX][h滄$ _Ġ :vy3`Ed yG%'3S}&a8Y߄砭hs_n/p; V(<w{}?Ɵd9YA*J&kZl$G1r ') 9K>%%RKkI3MV4M^4MQSܔe6MM ML&:-:+:?8<*.)37z Z===^FFoHLbX(b6XXY<6(6<6&616-V[[[mmUŎNN..ǮA#Gxxn}8Xsٗ@JIRT$LOSTq4=UZZZLNKmLmKNKUNNΥ.. Qi_:NstQ8]^^^^^^ޔޑޓޟ>>>>>>oD}Env~VɴZE,(RY7G4n.7^+܊:J|LdZ-SS5SH5Y˳lzdL˴J25>ku, V)|m'vy,wk̽^D@)Ҽb,\@EE"1b(D媀((Ql (]lأQ +-E~kzzf={3g>>oZs5G9C9# @`)4!44!V@[/kHZC}Y/keRheVhe y;|{pѯ=d ,ˁ#j~9Bv-pbnYIК$&6 Z5 Z 2 Y sTkB^mV XmVAmu;63NETؐAsj6 iМi**:H $=d@CgKd ^KzB/Y| Aʁr𗃿灓h.Ir,ˁ#@~m !X $ 21r`%,~->7|Sh36S,Vm=ȘAC},@[ h-Qk~K跄~K{$^X(wo--$mї-E_˖6G ;#u9Q8pz)9v=d$ 1@?-0 Qcd'te\Q,ON;Gj0 Cǃ4"4^o!p$䟊ժS:%(T4"II< < <^Sl ꏢ^_ ШШ/4CZ 3۩$-!~ФZ M!i ISdS,e `b!u x#gA}@^$@ ^R45]Q[ &Y!Qp&ksb?$9`b!u x#gc>}/Ih Y\+f)xxxH,|(Gc1hH0HA2Lp&5[ ́p?D.[#r4SBI m_Z1hcA75hkF}$[}6\6;ُUpԁ'uc+ئ'{끯繞 wFM%Y%Le(E,\Q扒k{FpLf\`qN ;n'`,VC^ y5hF+5V-bj1BZP-F#Tb}X9f< Y a3,vΰ;bg!w* ]7q7q7hp7uCu .aMU/^Ћ///z%K̯_/1^b~3Yr ` 0G1tBV*2CY\,Q. Q2UKyPV_ [}a/􅕾A~cC[?іM?4p\fsˁ+)T N6 =`C6 =`Cq5p 0 Nxx@@s4@s4@C_L @ D@(jsˁ+k)T a[AAAAA[$SXOAb=$SXOAb=$SXOZا}Zا}Zا}Zا}Zا}ZاhVU+l [VU+lV;Xqw`w+l B0!ևXC`w 09 *  ? mDۥ@7L3L3L3L3L3L3L3LAC2`0 \$;aw8;vp.WW>Y9,X1pCz(莂(hhGC&t Ơm 9`*,%1$b-b-b-b-b-b1ױŊk+QFŊk+QFCq 5k4h(P\He(E+^֠FЧ8]|e9z._+DFJ7`j{Qm7glwƶglئ/19yƐ߈t"bX#vE]apRy)E"\cj)}޽CŤp{hAo^x{cCG>Koq>zG_; ssLyHz7FX1Nj$u|)@ |8_/RL)O7RK*t<d1?^8*Xy\5[h|(z + 0#w6\Ƽp`H]r"&kB_ѦmӔRv"Dq.Vid{X)'` d{|ӇaNSH%;ƎsrE*I}E0,ia_(<)QyNS$󜾬ʵQTC=rs"|eXQ(+=PF9}OKRlC@rs F%e41Yib/(=)jQ{NS\"F9MqDse41qOt8i/be(=)ֈQ{NS vqE1ʆ9('>)Qf|NS<$FY9MIrs"e紷7LJsN/0|1! _ abC/0|1!Lob^R QvxNSL(F9MQse(WmD+-/-kt {&>2az Vq1#NsSVGҌ5lT,[@MM78vhc :M7, taL~ "6\`IP$({V*Bajc ^_qUk{nJGs[D䴨q!N.N{;GEL-"*NnvMDԨЈ5T~]? ""ک萈i+'jeOp&7T3 sŕZ(> ԧ} &Nͻ1ӘSBo턈WaM4el߬׎q 7ku׭&5&^@t$e'q"1h̚׵qI6Ŕ=u\Y?Vuk?,>0s|yޣMz͚R_aiŤcuW?FjY/ǜ#ZΈ8gq{d/_4pt׶Y O;/e/'k[~Xji˞lwv5O>⬧%2}ZچI*:߶\:`l>yMCz^җeIJCHcӾXcϗ,s5Y͆I8m)/ׯz>iQǎWw~|bM=т* ~'ѩR-w}'_/okJo7n%؍}EM)H|wRBMgSt;XtqJE['})bU6&9lvy뷯'oZR>SvvN5iK_\JZ{4㉙y+|ǻL*j䒞I刐#$u]ٌN\M/^٫?[TТhW6sڱWc3m]/}%4i_{k75Ք13Z1tc/>xWӆӎ4۴ GS/: /]U@~^+B=Q ~[5"xpeNysvWo];T 1J1="t_xlٸU*4U`?ȯɓB vOuϻ^GG[=Xgm']W4~Եޑ.ɗ&?0spNw{I݆^'O^tOӿj2kpOŒ=n .bsl=3ӎ֡WnyiS&mZ>_ztYo6 &*kMHQIi{uDQ&#&G%{dTvJpdn|,MW2i\Hl!ļOᘨ74EsCaz,4 rNO0sM&G\<3|ZXΨGW_69a1)'5&[ƴ:(jnOw~1 )\ZkN7ڛYW~5#dOnXu_r[/<ӝ+ݏجT #]{:CPʱur6%i*ڵqz2E}~3u,MSֵROEE}se A;wS1 e+98rlp;  ~9{FODS*Muho0c_yII=s9}/skoۓ7]nyNn{0czᑺ7u&z=N6ܠy:y8"ۥk>H/7 ̅ψvގxhȅ(#0kg'.ٝ&R2v0)-mOܨlP=WR?e(=f8?䁥|Y?poӊdTxO꧛V}ۿqи|u 'Pw?9^r=z w=r'M)ȌxJy(֍N-h4yeg .L\F.Sa1%6w:.{}ƋuUwscRqv̓^u t&^qeԌw7nKڤ[YSJ/6;:3֘;DmkoPO(%#=۳ ߚ<=Gyɧt/WG4MSB#CD9;ݵg˶umپ{{O&S@Scokٌߖ?Ttů]̧qj۲ U0IHK?4vK[XSɣQ[j>h9ßg|sf÷vYȥ%˯0ŞjTʦk|2h[Pk}\il<6kLiܘ}ܪܣ=Wk, WMY`8jδo/7.˸ߝvCNc+64k̮8Rzvv;tn밙5R[ǔ}xoŲsꬺ?}7̬Š1v.wy~qDfWۖ-3w+]quMJ 4U-dlUi͜~WI5/jZ r8GE{=;R3!^]p$(F c/wo=b\=BcJ4z/}YQ?^ITO<}w!~z|rQIA^bDKdqh ,a/dGb.=[tCm~9ͫn<`qV^6ś3[~ vФM#v6,;{NXQ6uiGy? 7,~\WilX}ս󠳛fךN]4o}ԮNߺ6_efftt嚬.ޏčyvʻ~yHk:U7:{HA>׎]{^K3vm` _>ngB'9)zGvl:ݤ endstream endobj 379 0 obj [ 0[ 658] 3[ 220 652 651 573 705 578 551] 11[ 722] 13[ 341] 15[ 551 846 679 695 614] 21[ 662 513] 131[ 535 591 469 597 531 326 520 597 314] 141[ 592 308 890 604 569 597] 148[ 461 459 365 597 531 798 525 531 479] 483[ 280 232] 498[ 398 398] 512[ 505] 523[ 408 408] 883[ 592 592 592 592 592] ] endobj 380 0 obj [ 220 0 0 0 0 0 0 0 408 408 0 0 0 0 232 505 0 592 592 592 592 592 0 0 0 0 280 0 0 0 0 0 0 652 0 573 705 578 551 0 722 0 341 0 551 846 679 695 614 0 662 513 0 0 0 0 0 0 0 0 0 0 0 0 0 535 591 469 597 531 326 520 597 314 0 592 308 890 604 569 597 0 461 459 365 597 531 798 0 531 479] endobj 381 0 obj [ 278] endobj 382 0 obj <> stream x}SMo0 +rB*8Cc41Qnώyy+T30tՍl#k&1rh UwN0&lH0:g^Z\<'M =WjX,7ø5WǨq> #: JI<{,9+u@X ;lu͐^lw|ОP(ք"B;B[D> stream x} |Tյ93WLfI IH2I !oHh7>*7J֊'ھj{moۂ}j*k{%k!+ϗY}:{:kZk @'3͞uϑ?W,^ԼjH/[,'qk͝];FVbWWeX;X۵n>lxݲs{AM{~-؜XZz?1v`;t>Y9w \>^בwE(^ _톊K~v^?i˪?>kp/ܹK 86zйy=Rϒ-wl(QߵmMWgX TWڵsQtV%u#a̹[3x))a.q >|fߤ[jFYZ|ָf@$LEMq>X/$!`-c# p";y`0O;I o0ȩVDa,%#?<Ŷnn`;ʹy0m~NL.5{&Od!!Ϡybdh{ `OHõ.jgsG>⟀Z&:G޹xN %p5> 3C{?<Mug܄cG2(6xI! 46A,f0SSB?iN]N fT@A;ȪÊbed6TEԘ^QFUa|?qːrs]Y !6,hP1l:l6]wQ_ [X/*QU6kh]YLdͪRc~zaG\7ؼ) $,pMF /Opx6/zmnŬa袨^IQe]sjf˥Ž2n )^&Ebz l:.0N9fl}Y%IVi5f_lFmW<䠹YJd^8s?xV$Y\nS-j ;ʠl]rGbf%0<? Fש|Vb>ciwt^jO/(FNЕ@EU:DT^RA(?΋}t"σ|_( cr\~Փ^59t7u/1t.C:ͥ91͜?%07tҌeI- nS@^R$ZQ0m~N~+/_ZE~~~q SWQ&//OJ--ոճ^a\֣aSS*T:ur|*␌L cEр'?jSh*a:Ž2}~PZw|ø*A?0*˧+ihL'|x_ct</ŪQQ]bE#nWbNw:&C1%0,e9 ##FB(2|z wBliȡ-F^_9ӷ5*NUWUM.MNJNj cтH8? }^tmV]U$Ks,C1D;2\4ܜN,輨#Ģ;fLc˵2mkI` $J`3r͂Vn f ~sQŒl̐`ciƎq4#@QքiI`F7lid`P#`p(Su9{xMnE;Ϩ拙5cug4J=DB% WQp)5г!LG>/8WX7@ufٹx߶s/ptॕ/uǞZyTmO^]؟ҿ+.J11)R_1D'dN>OxMmk_;?@i0ݏi^FaӰiGytҸOcc'=1X: pzZ+/8n%[oe~ 8y$Щv㙀Fށ$:L0]i $2}U| _8/PyI~SϬ,lX:P5@lO.g0~gty9t,pdyM`@5JZƼ@֬vc]}M+Wgz%=Ч1 }2}}'>o9SN,_؇J֖kY谰d.?=khtJ^ ~\<2Črz 6H겮Tf! &EF*MH oAL t}<d@UM u̻ MM@$@J7\l>fk/+ٲ5LfB6ҋ0ALc:#0=Lt}aڍi+.L0mrLFݯf̛<̑ʹlff|6caOc:ULLG1o.VD~8d:-~O}P{-{{)_ JyRx'jx?W-x~`I. id&O'ϓAyKcL)eV0mQ-=˾%RA_? -#ygEuB P z a&>͕{a?|+5c8':I4ZROf㱘,#jr=FrO"}Is*9|e| pә9L'>ۘ<g~acl[dnxdg_M3s7qq?~ʝycX6&Pp;|}˰q=07-@`Z~6?03d1j= ZoXiMgj;|:sRIDoydB*^-(p"z="6[B8G(-ָ߃{€c%77ϓK'[Cւ5GAv4An{7d6'* _ р= /q8.͕v1ҳ%)׻rT}֡}MTң?u~[7.cl4RQY^r:DF#x+7%ZeX#Hdx!i$tMMUUe>ԪkӢ&v6<_hAu:hF}gv[U`X9l}=l҇R)7ɡ%d/Ɔ؋$eWkJx̨t1ՓS&{KS%wL"{޺SV VaEMv~ӡ9an|Osgh,Pɥ妿9kab/ڵ"E} kqE{RGM49sDRt(T((P2ʠr RWa䶭ל9I#iY˭!g%ﴒw,&G\H>y WegAf9I3 tr@ˮ8Nӝ5u=T9 5ܜhgA+uq.G#t|HnCLZzxܙ3՝QU+81K?|V>S GJMqw_!ey<\+h#  b&w#i  7fh*&V]dvǧN/.(iM&|]}h~L' f0ap3lr} ?q0[znr4=lKX-g07ٰVC7O7;Pq0z!gaLP0<־$CU,uVdP׶x!8D  .ZvڟEtc5GCU̿9bٿd~OWu{K'#͏1a;V|dÃ#H(a5uoØ'*:g*d=\p,t9] x|bMӓIqVf]ZM<# #y.^kl;-?t}gkӼ[Hd-!&^ʝ7r] hGJJ#$ /wݬDXw$UCCliN:^=@݃ns\UkG8ǫ;wn*JˬǨr܆vtnMqh(Sj;Woؼ/ܲ[V]5SVkYۃJdޱJQg~dO9ߛ ږ&mT=:ਮȾ/&urK6">lDL'~{s86:Uf+ĂJ  9-ID _Mk+r܂ [q*i^"z/Cw5ژ<ս,L9=T^eNRwyRd~z/%p,Ͽ*-{*?WT]cK f܇Ą;KIܗ$b$JI_`4NN=~SbG+՝MN0| =N$l;P;:hdV6FLD%3b]Jt%YVU%:5N0;/jΑX [wJf*E\[1*4WYOi6SEy o]k GG$&,:MXHU}șK?ƯLvml:ʊQfB hf5dxoۨ!G$ԛ/ v4DKEӦU2OE œ s^O-(Dz|°Y{ґAQI8 *Qn;L y]yyy< gt#,rZȺSP>׼llpEIibc S. .ӧNjO۸cEkyҙg4vN֗Q^7hI#Z[-Y-˛[/8rg$^b!!!iXB[JzI,mK \ mҒw\o$}gEi4c?9Iu0XUʯ|OꕖL ߅0jJBvS 6]4y.-!ZoZunx-Xr-9a7 vmcB[ؘq5 ] DCr#AH#s=Ҳ!YT\*vI`4>v,g,0F̍Q=`/7ۗٷٿggɕbc} o>s>7RmG6.oo]Q0 %`־LɁH_/^5]" y{rB,\%riY%ˮ? 𐔵ـ 033!=rr)m$ޝSDXxF2JjܖM}FG;?ڝ %"=I8%ٮp&%GUoK|53)œƘKxWGBRо]mg' ^dLʇq?[?5$O9%M)#4j08m_38ˏ𜑦TP-f54wW =<_*PmYȚcX qj;ϧs ZiL"c)h-}Dd $<ؤ֪j\=z6azM +FiS.㈑_2F@[zx;☍@$ p t j5};0ȅX2e0_Cx`iƶ0"j<|Li=-Ces7ť_R8TQ4i5ך-*̫/ u׾{52nw,P%cVzhBJFAo*A&(Yp#切f[KpWn! .>rnv3GΓ-m>-{翼 (8cbCI0O֐l 4g{wx~M_i/ԫ+za W,޹?,ْ *x\7_hB (K&s roq_#(Y~Pi2j>?`'{"P Om2yޔwKbp}΁sgY,}z rpdt …FЙa .VC~'#fi"~(H2G'+3Q铷mC›Wq3XedG>QÉ&78XhX#={q#4MÀ 6YH&Ȓ}O* KeCvߙ>iYQjüjzx#\?iS疮-ҖO\8D[bW-:Ɇ~ g`tMͬHY*fvY2NnLOAg#D,A9r.PJ|)yI^m0Vt(*,R?2g *;|Y@ƠTr\AQY2*mefQK@& L/埄Q`ܔd?_iTW5PI /WMqFLy耮WA(%z-d%QJNӫM'K9֪V8DJڲtjvs˻z%8o[l*!Z%x} rש 01JV NPi* 4NFA(hMδPS*(axc(NK+זt:bcK$` [ _:PdOHݟv-ߵW˗8}( 98.M#J5QCoL3sཔgLutkg\.&flUz0v8ŀq0p6_ͤ?9/D)r],6!oQKaʺBP;l2n|r!H}%2S 3!ǑōU4!Hޯ4D&B5K"Bz ̅Ϋ9IQunJ!s_ZRZESJS.nJpIƱb;9t]kQtⶀd+gg:2PSefsiKj<&$BTuJgTN ʅ/h:]F0$Xʕ'+E%v"/Oe*:wa9$ ϧ,ʠWMTQMbSiYӶMT90uˤZߥkDLF|&,Ap+gMz$!XVg%* ('Um@J^ӣhݻ7VtsF+LǐTм$OP%lW=; F5)W"k YRlpr[7uȏsA5p_J_||^xU\<ѨBp_bR&6S$xpggg΃':u*vH;|ǵwG{K10p]mQrv s[0MΚJ{[s *gLg@]ʑ+J|3/[ UAMf5k8$XΧdtfj͙ݿpAWS6 :^P_>Û{ kUXo")7Bk/?OV~._?~NxuD3?eLO9=|ϑSS=a ۦh#SQmǎݬZ`Y4&nP}p((s[ !*ڥ>/g}K{-pƴvH‡*mmI<8 x26QG6^i$S+'q't#d)-a;NᴹR"_KOX=GqK,*^^L^db$4;55f?.ϟNJd&') j&z"0,SΆ$ 0r2|7PZ@w䄕A^d5bwRŒZ!X[>BF黗R '̚ -ℳP)X4ye73r?f]aD2#V6:5yb$Pk膀_w5F`i_QjuZRCt! J _;0`ȫu'jWRJSz{GQGզ сD@P:o^lw'fZc{M<֢"o) TKq~^]]u^~=a@fgo[^kkc:SB["5zntv ]TeC}wW":%Gr%"dWrB'I'8zG7;T/ӽ}Gvofo}iL#@|;%(=KSur,ɫ"B5)69}2 s"mg= =`2!e#hhh@Pmd^FS@(raBCDVxٮAOGjѿ0èvgqfu8_ar`"i2UD7u0O+`^Pip:` 's *%J໅|5])+٪PߩޢWk 5Ф_[m_Ѽ-dbaux.zC, *aO .ƦA{x+w c1Δl(&ǏARE}"30sa$P%yxto_Qac/Db I"6A<]?RTXڃPP=Xڐ-:,V 3wTyLph {h_nO"WRl{.};~H@}e|H4:x?3WfCs;NT4Hޙׄ7}{JW) cuF+ņaOR%qQ|߃[,^_OH(R zvHAX?K<}x)EJfsuuuQ7{2ԭ݃U]ZwփqV~í)SHa'ғ9C^Ξ'ò҃zЮ^;We+S ,2dq\"IG]km! R$Fejmh[Tg= _5eqrukMM'G[bd4ZW3Tr8؜2IAU0P|z"v;$*E^#H@*hG.j f ,Ї'[D2!bajPh9( j8M>0zgmO?k6aV@>\ʃ[GvFKhjwy [&u"öJMȀmlP*&lcu#`D!_N%*E7FGߊ~esIAi膡MIEQ2rX;ܛvZE +)sƘaTŒzR_ zYdק++2r3fЁW3㧍:&dTf[ƎMRB}9= U(37gpU^; ]sjsNYrנڷpۦn퉇b pʢ<\iOOF %E>jnNݼm988Wϟ4 fBpT%~ ԕS5DK>&n<콟t: w eeR 2j[kEoU"PʕJ dTC 8v 3s{{#PQ$ܤ絕/VUIVV1SiĴtDEL4x^@F鶞e;$B`tL A)93C)h`bo 3F䀕ˈ@.R2yg1>w}̂$Np4JJ9q5*+%ĕֹ-A/(ܺ2ZI|v׮%eez7+CV^iZ˪U;+׵U,eo ߦJQSE^X.( YHrTO* :C/:tC:Jp`ʕݫ3LqqxB<-^?YG5GCGz!NuHH7^z푭)W@FZd7pz=?0*SNtg˓0E-YxcDL[ Ahwm@Հ١A'pzdT枇z^UA ʲ*Npm&8KSB4LWwcBkIH$Gū9 G#Id*@c~ ]߻~Oۡ1Cp8 #-ඓ`kP2zTUKay~GmLXJ]ɒ9 W*"#y8-uHAa0-<+ mǾPi}7S38ykg)}~X;s+MxӮ&)SɶHGr{3EbEn-TJ<U0J,\,CcDL!D."FglU %x3EXy&OQdӓ ~N#޿(-~}V7AJceQq!JnʞѧNSm|⡘nhʡUpiTJph9?Za恆c8e᫅iOa.qFX} W\e|&RTAuqHH.LLd{ *c^@ [iO=-bO|Բir~?ϞלXRqn)f0t +(SyTx"82KѬ9#|aBN."e"-%D)'"Bų5?&KpZ}Yg%鲜m_ŨHeZ9{H zo.߳řStƋcÜhH>Ұt]ۥSRFguvEhCҺi0kjs^I~r`nRkH5aJSLJ;"cwΨ8VzȍHyhpz~_f-ggKpgKh8a,$R~Q" ~ (5fp?5VZ+Wt &Jy%1 3 s5)kH%rϾ:$ģk̂ ̵qK.qz C /Z!Oh&_{_v0i$>RoH`X)K|pi"Zbe򢅸eBh-b)Y*;Ot)b\{Gx0I$ާz,oyxbxl1*!8i A| =ꖴvMW9q^=Bʽș}.Y&KJ7O_\y+&SHV6lu?_QW$9Pc y§`ygRn`lJF[ 8]CICQ6A@MA:{v>;S%)wxFnG.8O? .‚%o\_Q}؁<JDuA+>8Vq2BG׏?jf[y*oWxgN_\?ꈽlx䱗J-|H|AcX=T@vY5¢zl}6OYvoo}ߗ>e( 9^E9&H7`Y6_M$E$ ~ `8 N4d6K׮BQ=^33nN2SL'7İ\ަ)m^~@o'Q &^0)Rl[Rg>#/ukڿ<e0ϕܩhxcHY[g)H 4 LJ]~ 6u!B0X 8]"4h1gŽ>2 dƜKsجWL=`fli`d&\hr?V%6(j +2bXP40}6UJh램V ׻J1n4Qjn}l?`8>0O|jrv;|oZheZ[ U誋]ɇ@۹dc<+}_}HFtE5y(?283>xDfNuws|}7yJTgQdeД΢_ :s{ztA,.sF T`r,@D'" X 'E,7 uRה6xmRE6J^c`Z"~x*XӅu鵝 OܟjbKk7hN=&=9O#RW>{2CGGg+=mߺ'7l\ϗ5E]"'ɗRጢ%(U؆ gQb4lBjcC êe=}7}8KhEV:س>W.N^T_ʧ^df-/d<:K9Ӌ Ϯ]Q-C 5sr67}rV *w8Q.נhZM{R=ġrYnsǸ+;.E8{ H))gcEfɭlM{ѱ0EMM!p Vq7Ű +[4saw|Q 7E?2ަb될d|d icDc?wi$8bty[gt2EoM4ѬM34i& Ӳ C߸S Uڃ;v''hUܟlGm\{~OrvWN+yyy%Ãiq؛oR{ B%#n+h~]j*d*MSk{^mA박N"]^ѺfeB,׈%wME.gj$,9"syt$m ڽCX%:h*K#[[hkㆇˆEj,P/U2&кw\{3m+cƒ <@4Z!t Fi#G^E308-ѯ̭ 72YM9jmjZVk_ryZR)S/3KՁh~ٱv<`W?ljO6QsScsjnbnΧN5 SM$9D}VO8D(/̍ϛ2\eJQСJ-_עYXIjn¦T0р7ȃ5 !/˥8vY^жhݡxYve2dAZ%u{74rsHu›D_;/5Ƿv-4dоX䉣KW_ [֛4چ?^N3i$iKiE6Դn]WO^#h`ahU5PmgUvYVgSNzJYZi+d"->rT)t.*KRj!*F0cdaG߃e`$ov?oqfOowKoԮQ[j"NiwkW{Ms>30%Nؑ]ݽ{3y/ DPn"Js 6ׂ5ކݗ]3Sr+u{]lʛ+B+Q^^ɧwd."rVq/ؓRkhijĉ (b,'vEj$&X*`.wxw"ziZ$?St{'G~8?q@pevN|/|>=, Ek4EϢڵYi52|rck˥]M>۱ZF1vuþ<<.+2+ eY+6f ^?Љԫ)f}CvAWMh)# B-u]eT&u"ػAA6o7_hxSͳ͋KͿiE/JK nxa[Ş0bvl!`vJ1Ӡ MiH.!Xc%I^[Yj)RܲˁfPg5k8Q-N6dPF^fWuufgh}JID[$^c֮ПcRT+Bꙟ/~T}n|+u?ӱ՞ם2?ԽQ _ٮA]u2Dl UGzZ0ax3T,LW)&KJlTx* bhwȀ {xY̹2:K58hy_抻lQQQhF AWCkS_[1p̢չ9vV_\e¹AR#z ֎$h @T-3#5IHmhP~_P&T?%Xvd>1vt+g[kQ6{RUTL\bJ(uRIY[5x`b^Е}9BXQI.@;wHڗ) H>MT傖8U.Sʲ1SN|wQ-Hk_+$-N 䛯R4yb%Z@4+ ڀkG\a8m7yk5.__wwe\<>WH䂹 XwȒhb7O .kn[}?W;jcQ|8Cŕx6>?XϪ.kIQdSa#|jx˜3e=ns aq!{-J24.k zI[."=+&`j(dCeG1O`dCn/cgii6toK{ddĚLIٵGSή}I=L̓x[7OL[-x;tnϞ"[EQLpf+sfI499!^܃\Gjr^ݘx؉Ig<>3W`uuEP-Pzkй!.?teVYj̈́a kpntN:/8Y'K`:x2x{"|p N.yO!yb?ǞbϰWX}+y59*,OKwL$2*h+\+Ig1yly̶`],\ݽ8-0pDm)a]0/v:S0ćxX%F!z$0|1c,*YPۊdf\[IK^㼄x>˴j}e7+;&N6lFBP瘦sF`YpϸlMΡCi4fsX%Qn8I۸xB @e5iE[_}zw}z 07i^u|EH6Ob[^HшW6h8M֘jn`뾑Lk|^|q)_d\[\GrH~aq1226p,s,fÒL:cc3,PM[t$4T^>U/Z/ݐ;Hߋ;hڗ?4*pIZadra6WQ]bqr>E'|~iƾu+aԫlNrt.-C6KfWg\4{hlkȘ5õ^Xu%g]mQG+쮆xǤ21b6}jcJG[HafIbik{>ËJY u7'҂ioؽV?aY=½N <0duSjleYtc9Z/Z{x^^* v]n2tc+[UrHR},Zr56#7Jc3@ΤYtZDz###A)S%JK'EIyr-R;sf'!j{QH2q7 ΎC@:3@?*J:YI4heoo)i5ZHV| SMPZFs. lXL`6kmHhOK=e4,Ls?6-5]TEP$5jY3ki ƆZ$r6:h_n xkEb9,Y l CNLu :_rf꡾V o@;hAH;f[_zd-[?-Eq\~1sux;hi~Ď_7< p1;& T!ro') pY"*&݂Bƛ 0 | {"cԃ:vMo5Û*\5&"slTQgr>XB +\_,^ˤh[9abأ?ϻăIDy`/7XE=-(UO ۵eFBɔFT=SWID?Zpqk:m[m`凭Y3pN[Kda]&^y+ |PECPژV=M i>kӎۏES9ଔܼj &ioÕ^e/I՞K菱@EZLSϻY^BjFܪ;>>NE7x%Z rB]ˀ&|d T Jz MÎ;FEs3t9bZ"p6!Y7wDNy|^A@(Y;ٸ6VMJ㘺@SݟNL3(7Ik 19^eKe0Co|AW%/z{=YY ,K*+0$-2)PM]5cY)U/^: Vɣ4Wg5gӫC.も2Nar[|B e&'q1^%v|HȘ=L}OA2@6JWL B^4czFKpzRZ 4ާU}V?E{e"]@XD]|SBzEQҮ&e&M8\^iUy'׮Ȇ-Y(}q?9.+O ~h)>"Um.{[~`‡צ66˘Vo{7plYcϔ/y>ʟ+{CeK_i ԙfxlS3׃"?F!)JCO~6Bj@_;EFRb}qQxSAj 5T@6Lj][{9:B@_\@j\4P?'y B9FC75=!ש(59>5T7)PІj]JB{jGײ@ˡ~做 pׁvCK>:Nq೏i"%-B~(~B;bpj\~#H W/fׁ@7py){6ç '~ P#8?Tmq--m%ZB³7b:@Ôh@;:N>5c-;І4P#~(o U zڠU}rhjV:m*\gFm6A{p( p̈́n%4& 5B==ǁO. ͑:K{>dP^j80:A(.^9|Wia 4G'FhSg3@Yq>r 4C̖ R<}3>[Fx?y~T fxF$ᴍO`,0!t?LZ>Lڜ &r|j wxN@K%CuFHoPF7LFj3)$_%2 u ( b@=j7k*7$tBP+(Rn(RDAT $&],UQXf PdQ׊k]]aeUν!>~=?y2w3937x^ 6 k0l&H>ӑI= 1J(Ԃ;s5,aLxPz^8τ0H{.,г8Y,9 J-X6 6 <àM MΆf Z^d VZc(P;T@߮/JΩW,D]QDnu*bzuLyD Odi(4*F uyPפDú'"/u%XA)"D rNE*"4> CWD(u%Z)+#Chɺ m,uYWE*ɺוddV&CW#wFse,4/HrcĨ' 8(3Y1樯21vk\ {P!G&rؖҁ,!+c\BBCQÍAYh0!C#9B1 \c\)y"nN80#>- " CxH2@)tĂ-mBCؠ"lj.0Z ޕԟphw FP"cB+PQ|8`0az(藌/c }! W)o+p+.e3zBmX@G>ԭиp<.Axo񑨿%{pb@ p$.i4U %lExn8!q$@=E 6.W&w(K Qp5xYBcH%HA"R6>E'DPPG@%+M+\ǞQ+O*2rWk̓+~׵cv&d3 j$B'pԽg2aEXUsx+>;P8+5u6)W"- +A]D02q-pVb >!\xGW{ Cx;!>.Пe4a(p׏61]PSn卒;.opo獆uidL`q -(Hp4bz Z Hy8$F$Y8Pdh ΁G ~QJ"K\) Q!d>o w#1;!V_-|,aƃxx`c+PAnx'BkOY, ̅`C΃0:nw8}2G+O7RQ7̇=dD;! .$JN2Dvɜ}e<$PFƒev8.7YP kb|9${][`uY; \R2!{-Q.ݟ^|SR.R;"'2" #پ%(YyZpwdAв\2+kF\8|#wk[(㷄~Z .?n#ُPrg`< 8n}d[?}WO/(29DHx%0k H3f` 0Bs@He%c5\ iI]GZb$+eKZIfL䝬D>9us A>a=p`<Fh=8 ֱco=dXGܫw< щ$nHDI: vUIU/y;) K_e& dއ%l~CսgcǢ0/"yHt zhv[VQ[W-Ͳz,%&qNDO,qz ҙ4ʈܚCz  7NK! &id$iI!|zGKK.6|2x s"v8D2(6E9U2*by@H,/{{CI_/Y$l'4rz ~NQ >Bꂽ)?\un۱͖{-D(g n(* ?F*7XX *cşa/Ga0sa4C 򡞸//l 34ù/^zĶN7?Cw#A=Tܴ6SCwJBBRi r3]6~P7dEmUaȍ047@UV`ưfTuQH13›f&7ŠpyѨ+6daXc9ommgbA21a!!73Gy1hb"cI &r#9"| U(5\Y[TāohTG؆Nt[a^_,x;\ qj-ypryZSQ- |baj%MUsSbԜtbO*CD[`ky@΀1V{[]2L'T;9FS9o3޹>Z[5^EcsenY| !עܩ 7U[ aag+*ϼgϺ2V&ɮOc[wht^9j6j :U~>5t9.]X\+c^ߪBZ^yNnqDFpd1/NjYޤxGݐ<2uW͘zQ Sϋ5m"- ܯhM|!XCO̻Ȟ`ڱ!aʯܙVn/]V nl;IjӅ?Mp4|/%m޵vy-c{\}6cbbi]fo2B }QyN/L92-k~A)7峍ʲOoM~1e䁃r*&o>VI/lq$IsLGd ~oZwHʁӕ 6*droX$dg/"P_@r=@ :a J /UuuޫwumEOM[Қ6hӍkou4mwS L,r:Q3pK5阤s"2ψR2|_օ[=2ty')KF$UN(tC+xd.TܡO|uē?:*[|uU6߸ek=QY#<®W]ZS__T8{f['f7pck^,lw;W2hI@rYBMe-F Ķ[ݣ"Glۣ~H!_ďn|13$:l z6X&=i{ /F]1|!WÃ=``= چA/Hݭ\ꌠe[Qy[1;E QE * w};}e潷Ϸ-7[Uv~^J;F4(?e͍y#x8dr,~d'rY3[$>)g˝jP2+i0FeH<#O{^m`p:xrʴjM_ċf+ڟ2@9kQ*Jo:6n$ڽJ6w[|g`asJEX²eh&7]Xz!Zz.%Ms֯W\RuR ϯ_w|6kmѳ{ybR.,:o +.; {:t|KV;n̒LnI˵{/jd)=9 @{˯nf"ܫiSFhD}bv |G]~׌A@ 98L&9{nO->0$YK3mƴ#J(K1Gn#a_kH-ɾ5ñae[Tx0@ G%&KuU1u]NgY-ƚ'_~=/g;Ⓜrb} L&H'ϣ|pUy\ɱ3:*MYRʁmW|Uz{[GwGt,ݼT`q}W5Ss5i(@_sn`{|p!y'UUvYzPSY݅q]U'ӧ.8R2hӞw=e7Uw6un9mw4%.F`-sG.`Ra|9 hg&sdBhh[LASEѰ7?<ĺz[/boy3;U~i=ẘbJ5}ג+6N{Ie[v] kPUg;c~Og}J'/Rv3r.vu'_i7aWA!v;\X15獝Vgݑu-0*A5weaQj6\W>zrr֥|_?7pFͮjL.o6W]x<}IW"1ʠLqsBF֞Al6V:pA미 +iX~@ > s&Q/y\j% bO%so}(%z1r ɮڿ&Z|#5.~q];?~ 3|o<^EJWOv+x}0+mFݒwzjtݖxwWqes9Zi6j+Ro1^^N=arpgI+3nK[{CgKɳPdgzԍ_XClec*e嗫Ŧ 2+5 utv:-Z Lh>U{6El:eܐbh(, cL{ Ea(Rr|c$^P} Dީ21V]lt J,;T?]Ta^"] d1"i|̃( F˿_2(oeZZu;Vȵ 6VιT9$!f \8S?ܐzcdeՎCW\[5;sPi]{mǩ:{a#џ.8t2Pum ?ߚٌ1iC&\^=y.ճ*qhk ]y*/9ducYnP/= WjɼVY)eE nq6C%QeVϝ/tͮV^R\m7k_AHc2(Ƞ6ܹǐvd%g_\lDeg ե|^\ӱG?dp|a?W'ڭz i^:cAǴ#Ym 62'B>e6 z͜2WrWO,wx/ocPu?v*HkeoaŪ <̇s˪ԪNհG_Xy?^_֔`4kI^ endstream endobj 384 0 obj [ 0[ 750] 3[ 250] 5[ 406] 11[ 292 292] 14[ 667 219 313 219 500 469] 21[ 469 469 469 469 469] 29[ 219 219] 36[ 677 615 635 771 656 563 771] 44[ 354 333] 48[ 833 771 781 563] 53[ 625 479 615 708] 58[ 885] 68[ 406 510 417 500 417 323 448 510 229 229 469 229 771 510 510 510 490 333 365 292 490 469 667 458 417 427] 180[ 448 448] 183[ 219] ] endobj 385 0 obj [ 250 0 406 0 0 0 0 0 292 292 0 667 219 313 219 500 469 0 469 469 469 469 469 0 0 0 219 219 0 0 0 0 0 677 615 635 771 656 563 771 0 354 333 0 0 833 771 781 563 0 625 479 615 708 0 885 0 0 0 0 0 0 0 0 0 406 510 417 500 417 323 448 510 229 229 469 229 771 510 510 510 490 333 365 292 490 469 667 458 417 427] endobj 386 0 obj <> stream x]j0 ~ CqK{cClJfXd8d/t0 }i'7'8-B'uyv2QiuN84UנE{r!{ayqBJP x5.ؾus|068ȆFTu%@*($Oߨ~_xX{,yJCT>?!oP endstream endobj 387 0 obj <> stream x{ \TUsaM°o3 ( *%0(03Ro- .[ˬLU+-+L{f00 r9Y<9 .3ǫqq; 獞 -XЄT^R9gp C%ڒOhaqXapmfba啖9!o2 N{INCv/ \RJ1q6@i&‡Pn֛l~n8vY3λ2ikY viׇσR<1LvNYGZ_H9v Cұfܭ4r@ U]0@*>DGIJ׉1n{Pʸ;b1aTˆ 38\.Ie䍅JEGh&i f/C_i'*߭_M0=RBrk{理"{KX"fYwNg_z*A25D9 vpgDpAtW&u!;x z'x7 7\91!BrC0#r!@b("*A a#!Q ш1 U8xH@LHD$HBLd2HHA(@ b*`8 A3 a`8p?gHt012 Y0q$/(88"fC688r!& NaL ya TĩPX4t0^3ZցJRR(C,r[(f!B<a6bT VBL&9A5b5E3-`AZ,BbA0q.(·oq4 6xCðq1,A\K24,FFX+a%*x&&r"(F\ !>xZĵ5<O"> SOW4 <Ќt3ql俄 q<__͈a Vĭ"/!2 X؆ #n;`'9W_]v#`xuqG~88x@|?7!x -xކw߁w.{p0pE< #??cS>cH##/pDB ?ēp F4A<mi "Q8"-|{x~@.!?K3?Q~A/p2\UkpW :{﹁ xڑA'QXq( vXwNn>'J߳I仱gvwd#^ r{ ݵO>gßzL}>&7jع-lpsD$wa[lzLw1{I^)yv\f1z ;83rՇq)K U }o3}׻^R`-zfw_rz r왭Cls/ O.lꙭ w•޸MpC=ݻxuMwb";HO)gvwxuMw%-{fwگ~0T}LIAhS}Cl% LpI=k}5s/h4gvne14 w^3 뽟>ǔ;H;83z'"{IyI=G&~t5/ypy=k{?1}K*)Hms𨾷(虭{? }{bM8&⏷#C!/oW=nrswtB4 /~DB/Tr.{:x4Æ 2h@D*!>.6&:*2"Rr֣JLTLe!gHEЌ3fBB[YIeY[ޘU83zy|tD4aOdΨ_eSf *X,mu⤂̀8+)auU J2R*3r%@V:(K3 Pr3>s|bKYN66.͓ XX}`[&|dQHǡ4+yEr%U6,S4:(G(g7Z!>df7 gqe6_'4op~KZn6Ƕ '箄VhuνY"hatjRDRЧ@.a*$Z#b:d5* |UPrW#@yBwΑ+@ qr+ְZcbfh~@|\m+4)8|`"V[8X xy1c]88`hTVH(9Y5Y(YYry#y^VYĭ?WGV`+b<;O=iZXdmv~=>](€\X{!!E d)G@lMm,$2d 7j?,[ { Q<>&NS( ʎYi;-iu/Yp AL# xd+'㟆xly!Uqp^ xL /(gɗ0I0ˠq,!xغ?O>xNLj\@Mt0vf8! dVxBӅ72Q'Qy~.3a+Z}BYW G<[_o;R/A{њsX x5:9u>Lv,7*a,h:Xy2ƙYOHsƏ o Aj;fzDYd B1$,DVՄۊ7+8Y8Chkѐd2Iʈ%VE#@&2e0Mia3m/`65[7wُ/0NJ"F*LtItY!Vܾ#c:|^ALLQ oՠU&zhx}'xUh1Jޡ +8-%"!$$QxMq%BC?x _he3+Sns Gg%8(6Nge- IYv=`1jу&+wDCčxY;{g%IIU*:`;-#YJ^"X901 D*5 $3TVGH)ϰ X8""yDRypS&hō67:a3}3_H\ lbLj ZǘTnD3/V&`+6gP<+i?pn2p|)ڵ`aŅLl"l}_OnLFd~ ~E>LUCGg8p7gOypm*eY! T=Hǂ\"ֱ, ɢS|csƷ(W4NT'& D| |a. RV`wѿjE=fW*iÉ{jjCF ?09 RO2Ԟ}(@2BN3 餌1n8o&'$h4עf͸HaFE g+ɉA.:AưN"G<O\B $ He1:LXvhDi?sf^N('׷; S\nx=qxZZZ &^CK|qO.OjC<${C{fsI=["do;:̺ ۩_!ZQZbU WE2 YR UrʠPe+]>|TVbh||=}||Ho$с*/$ۋQEF8NO$s W~#!;qCCF,}Y "-M@TaR'vsM,QM !n>^! ?BBH2T*񺭔a';S¼sua'*ۯ7ޟfk-7Nhf-l}+H4 M؟ pN `CÔ$D$#$c*:ɩHw%/D%q{qWE^ )EEŶM0|/*ܨ|Ri\DDFf NFF(C%^>lSdD%'fXF%fY#ý慩43gz.7}/~{<ӥBٙ ȩ?,T-w]3>!rYm튣'/Y 5HܵkUQtĕӊ3= ^Di 0l40Q-u6%jJ9EU81F.6M @F&.(Rr N<"I!=00ZHl"͢E0&^/ '7pjԒ` A(xd{/^yCۧkW4"n`bC/~~9)xP͵5Qe̢zpÂ׾F/>^}g s}!d7dA ?'C"6MAG#bǜ8cǞX{I=O&U yn.&O=uLo]g@SoyNr̰Ӣ.uNW WOL3rLFz 9܄ܸ1Y9yY\ܬY9rgy*k\ rkhv`qYǥS/ SFg+7ʻŧJWQSMg%.5Uqqn ќXh{_U{TV/FRmqE<6AX̪6c]UQU(*ai<k, Wf)WnOGRȩ*q6FJuTcJ-[ީ ʰ1QMtN6r:Z*6Br0^%Gs*6:w֦S3r T :.vmWd= >첄^(d2w]"EZay«^ cL뢢+Q тuT3!gݴIU!D`!0F❁@O@0sF",! (Yx|p9 mcZ[zk2Xk]) #h=:KLt)A):ڣm, =ɵ tVU`T[tr]Ė p*a+[nPRQ.z:zҫ}K^rkf Ug Uvt` I#osUtRݼj[Ìv}UjkOΕO9jS/cgRg&:ڣӹ;:St7ﶻw?uE$JeF"bm-(xO,].]V̇,}ڄ^ iI9 M"qY$u5M|lrRy]w!Nqܘ*]Bb:&(:eyfAh "L!MGr_⒚K;r~:yuvƒ~_~8yCe Vg]tau/0_k+;77~W^잙T6]۸ywS=RtAon篇䒽3JL`\(Ds'?U[ΞyqE̛C}`fږ%VxCojmm"? sa}{? ;qhu3ZL2Cї־kο?|e!ۗðP/\_"Èμ,:)O0+hz‹dj >t,NQlߜXmoZehN-XE` W%!D>z8c'HmV׿+x#_'cox7,z^qNHX[bkL0%.iyʒϯ& xsdܗwiy{jOv>o-ӳv~2$7 %8yus>K}]z<̌?NGuJ8BUxЈބ e^䶉Q|C5,8Ժ^xz["|xM=g77怘h?:zw~j N͘_:`16d g^^:c4no:6EwnBa3K~38Rt]sNڜIUj"#_JO\7oYxXk,ڬyr[G_L;gd3;%zʹ׽FʏO=Zܭі#.m}pOX0Cdl<^_N$GddSǨ#i2ZxN?o:.dJi} d鋜\M~k{ۗ]>篏?\v{%G42?kģ["WyqtS?񗀉a ?VV^sNuǿxAsӯ,s[7>1om˵GP0:K;cuktv/qxuI2ymxsyhܜԾygyɕG>Wkܰ+qˏop BZ6_{|Ֆ}Ϙwi^R7q ͶAXaWuNjzL+sn3l /TIh*L ХHY( " HSDP#EM+^:"J]{g?g?9s23ya VpH4|+y=m5Y$&z\O  h&dr7Or'^cJs퀩hVI2))pՋ&1/4f }[ I u.kptVdߜ>蜔"إxJV{Ew oB^p(ċd~&8)% !ĹcTpV4a46͏EW+N6,Z J8meRYTc#bZs-o(Oivu҉f.$TBQ($&ੈB%a7X,ιP>Kl0bNg<=g-Y7e7bb;k⃦FM{좑i$UCk3u%|;kRw(szp-kq_+ؤw' 53MqG"k-08_TKpbJgt܋#ڦǤԝȯv uR}MK5Ck}aP2} n\l5>2}<@w)N5FPeQcܬꐍB#o%ל0żxVY:9}QEeXl$ֳ{L"X<$! 7 8/tnQrK|ַm67.w):ʶd :O uu]m}K`ώy1yʒ)VV "R5hSg|!! c-*to눏 Z f-r5Bnmd;}=cIE%[t*2w0iÓ!ɢfXEcF{ɫ^D<ܥ:fYBZgp&x=\̚B@5* |d̆U{3zަyoޛ.]~ gUj'(vjk ?S@ɡin MFaZKYIJB&cvhݫ"rm!ۏދn}XcD&?//x}T_sF윜d#!A)]N_G^Qxrod-Ky"H_CZhgpkK@FiV\k[Mc2v'f==?oS_Rτ}MИz<J\d>{'Gߎupד!L ZSن$"oR6 f޸704gؓy핟/vT J RsbAitt0̷;?/wWQms2 @jˮBNTPԶ(]}﯋>?7Hdn[3!:{2Afd+>ZFf> ]ӬI_06H^ 9:M+WUX|>%`ȢSdrD]R_œ@=݁X <2\ zLt٢b@WXF ;պ>VhgV].5O֭?5Ei`A=t'Oixh/3Wn,3n;beUcXcL:IQD 4v:aZPd;mzfmg+_Z@lD(:o%v|_JWk]{x q  pL`kɮ;Y2XI( j]58BҐ TY5'&4Wc~d!/j:1@$Yg2St3GI% YSNli{,t;/>nqETgd'p"6xn2SB_AO endstream endobj 388 0 obj [ 0[ 600] 120[ 460] ] endobj 389 0 obj [ 278] endobj 390 0 obj [ 550 0 0 0 0 0 0 0 0 0 0 0 0 550 0 0 0 0 0 0 0 0 0 0 0 0 0 0 550 0 550 0 0 0 0 0 0 0 550 0 0 0 0 0 0 550 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 550 0 550 0 550 0 550 0 550 0 0 550 550 0 550 0 0 0 550 550 550] endobj 391 0 obj <> stream x \T٘faQIAQTvpBRoF\7n{++KvfwnR.><(Zw}x}>9YsG%b >~NB"IJzX~A<["dHBkTIȝְGn$ԔTӆ=! vʜƲan)η~RU'D8qz[z?FAl8`opݴ5޽R+!gL$? 3fH:̘3ёBl4̛R7|3BB\s5¾unݜ_G!~@#7k9KLm"!i턄7޶qR3A%AҗCD݅[T֘NӉin)gGRiR~P Hd*!@itQ>b*$t*?AP8NrIUa'cd1 B-'щ ȉ ~y.I] }ҧ-ݶj|~|`'7u#]/c[~/_3UOI װII=' iXgOғzROI='ԓzRO$<BeK|+/yX[#׎%fcI='ԓ%Go!! ҉ g }H2LB2ԑd:IydLB[D^QFW>yyM=|{IgOP%ۏw iޫhz|}}ϴʈvʹ+E%o w8xz/$W]3t#XIn&nKo#k\/;ȝ.r?x_?i_^?:։sXƏvUUV5xayCs9C*k`fFrR߸[`1i*B(I*ZqnE(YPP׭mEQ۸f˷tbiWld[:/nIdprfuȷYiM ~M>)QW2Z6#ꦵw3 jq6ϖ7UDZ:XBe#-E tZ[PW.-s[2'˭scYgJ1[-I{n$k.XłUnS-ogaTw-h/F A'./bgd*^l& 6DEGK$q//sL=-Jk5!UҚ|kmRW~^>ٚ֗cVW;y I6YU|g-)vl_WJ̔lX>Yws)|).kAsm> P:Aޏ[X-m\ER`9Yq6Ը~#0Zs/R'A\ҾS1fp;("vA/Gƽ](5ZF7)]ngTI'W7 ׁ6v$~TXY5ZȧذjJ S*0DqSeJ"UKn8 ~%/]Xuu5 ^έms:D׭)};uj ~W!TiӽaIm)hHjvbagPbwHw}T-\vc+۽ۮlҝAҁM,pKLN\Yj5_ށpQBknXq_amn(7g7]ܜ7g 7?pn47o9 n|W||g|'cnq7G7rGn>}nssyܼܼn n^f?7q*7p27ys=ܼ * 7IXJr< xK1 G$,F~1ஃNX5gO|>rL1Q&b!?2a>L1y ȻL2yLbrɛL`:L^c*Wd^&{&3yn&t0io ˅?#}pؿ<x w-p 5*x ^g/9< v`;h09 zf!W4|)7_J7%\ BROyp?A'8~߃| Ng5 | p| Q'!#x w-p 5*x ^^σn tv, v 3` x<OcQx<6MA]Npl:րfp X Vӕ&W`,7\i\t>h׀y`.l0 3t0 L` @-& `< c@ 0#pP\9  Y`   RA ׹rU/I)!13\4D]1rjDVd+K^'FБw<~H[2yo?=UfJy,`+3YOgyyO NGP,!(I9MR O"QhId*ah d5Df"w5c>\G%z2,@~Cn$77]FVtJ~KuZ-Wl5X-е17nA\g==rG'߀m)^yP&Caz ]*yl!H K9N<<@#1N4cdQ5r+G% t<5M2Mmw/l鎴HH}  #DWBm:HQf]N[NMǦ(9Ji9r>W1FnL.rXeӻq K=@# E?jO8 jRkrըK/e!hStHfv)Wqٵ ǢSst3 htڀ@(R+a0 h+OP+DZRM}Vpjnr!h(%)fe}iY$5LjJMբME[#ȜPo e]Ҟ0?|ϝhY;~?pLi?ѽ+ߊ{E;)GA ug_Mj%}h>ֲvjΆ&u*IɜO YR?xūTK3q>*uQh/G L1VQ1KbkT=.6nԌmGs'?1ʊFȾiW8ۃzsoʮtxJ^BDz%荍-9A)*ҿ9ЀRN6FЈs"j 5%VHёjcn_;[wͻG(oàދ ?-}sqhD9jaH{|0&Z:54gDh ʰsr]"ꌲTjVyfMM brldTs W옗2!yOMsؤٓ^8q&z| c疼0kZэKv];.@$Gmz}gg[TH?u`* 1K Nj'+EnGOUh)!BfR:=ZR--'ʋjWZ੆!ZfMOP i= UrYϯz3yJJo&OW#Ad$%k#xAGFіgS.IL$alL~cǦͻO7qu OaQa$QA iPS1U%(9{)1W 'M4jXx(M|-dVF&"_pA5"eYˉMf3>|0/]?=7-Xx\>;!("D5}+6?6twTquAdtϹ0me\ʼn WwX{Eť Zs␼E2 &e $sRIAqҖZmLr#SsR&$&Q)lG'H3h4HTm}eQ/(~TH_LN:NcpQ09#?JD[K {@jnq&.OA$A;=G4‡tDvDZlHHlZO.<~ĥFN KŷRtq|qiaBntikׯ151IQKDI*Ir,mN߮L( Sn) /32xr0faF짳7hո u4HKIlPM}M0S5>%zJMxA1eaӝ maչ]K2v-OUj5O]xТ&A$WQL|)Im-V:tt'5ՠO<)dk:4MJt_.ށ"s(R>a}宭c_6s\~SeJ͋]~{FnufXHִ#i`zenHͽs, `GDgB,`bI/,<%4wdb&-F4fCj Sk %9'wpC0;nLw?wyҗﱘ Ma`&:rggm-د-"(ύ}F-b7tϚ⯓F?Z%$w= 4G} 9d/=<%2͕'^QA ;vƪB-;BVBFsQBРRYةra }+l^OGLQi@CWf\MBjMMB-6}uԉWit݀jȕm{%=ـFPT-HWTD&.Gףk]:b:{`k I` س}ݺa==b2Z//ȏտ [V Az^wW/= u?{忿g49n@),0mwX{TZNuN?* \z'}Hg;݊T<;xL}vʔ)s+FH]OǑ 8 G$c:FIP<ߡ3D:RTzɤS;t X;IOx3eCxh̙5Μ6Pb%lJEݼi;1tUUыK`A}Iq ov:d{KXFUNV+Xa5Qe;3}CDP}N>dQ>  3K~;3fe%,T_%dᭊ }CqѰl-911u(Tm٢J_R[ ;[T?բ:~BTi5QJO?09?1F'[?͐I+dݴH1aޫ:{%&&΋fEgF/L2R˒G6N ID M-E;I9F#ZDRM&vQ -WT Cj[_ѵFhO7.}!Od$*x' tJ ޢ=fxZ׿lJS3v|25ѣF צMSKxxZw{;c22{a ӳ ”/~ԄCb.:XƉ˿;ƘrϳBQOϋ勵6MGG=gbM |r+C3FPN767LxjZxZ8Q6<ǒeqF3_t}v!9cIΈ^@" G#F4wdxa´7B:5}W7{u{'4>-5j:_4:/f<=)J)}EbQCѶ--9 ḷŷ5F.,6~Ke,%ϛܘ'QM$iikP7?kd.AܺWֽj!Rwvgz]klnd'Je3/'}G`|ēEq·C>͟ P">pZfRSJJ;}xi9 _0k>q? rF eoiǚ+m%h<2qg'5M{ Vc\÷~ݹ[6|٨'TcUz"#_?e !”7uO翛q l>9 Gh#e6Wڧu==0lZRʇhg2  jRH iJ@%%& 4iG}I%[J 醩ʧL_m ҟ9OCL?sjynii|Id:?Th82s baJiii)NgfB. ,θ,4y?t|L:2#QemRy MSe׮Q!̘WeI|)SV0qS.UNcmo|.QeUYd)þng䰍,%ՑY7TYTV {Kul԰U!,=m*7g쪜FUyPUNc?- QȊY"+~Vd)gE&+~VdϊY?+gEVȊYJX1rkeM,"X?3H67 Eԏb$۹ pֆ{Z,CWkBgDݸ_ZF>hܚk(> Y\#=Ix(wPxl*3H4d1ic3y"b)F̽Xm:!db]K"*ǣbg͜21F(yBl g&GBdo#R,D>Gy|dIocHnZcGU.enz4ȫ!56cx:i: 6h%ws6.jT} :p,L)Dk)Է[ȶCcYUbYYFZ"x~Mw[סZg0aQ:1P-mXb%Gp|ۤFKh}4')FŨ~#" KGHu3b5p=-]#vY4̧Z۪ƌ:K@!uߩ1 e-hn'm}u'w;Cw 'PF(嗸f%/M)cL3]Sbq=UbXG+Jm&^_L}5Q~T&k9_iX]g.eGkqJC i~Ui>>DO{Ї>ڕHĨxGU,UbyУG9OY5#KݏCtGդTv}oOk] ". i:ؒ7%6cUkS43#юH4k 3ڌ-N'. 5#H[i #QcWg6vD# c(5 h 7#PmjMNbAc{$6p+5oEdGSK0lƖ࢐ʌqqksrik6ƖvG[yc{enKk },D&";P#q]Pg):;"fnaы~Z10 o 7Gw*66vvmmŸ46:[aQ~ζgEH=BKbA0lEͭJrB2&{+rKygd{kCۖ!h# 7C ;#C` #Ŵ5u5jEa.C`[c'&%\`lb|:e!D* a%R rE?➊6-m"m2Y4b<łqqQ0c`@wc0bGg'-Mv1<>ߍ’R0ʭ,ڃї4^;|1p­_`,DA"]f)/9c|>XhŅq兘"6__-Kb"jU.6F[_^t!ҢpV@8\C #~mjq6$mM H"h+*4z1w$k` azUiU(Fl=M JN~Uu)Q׊^bvh+z Eɝb) Db]XǡE<%NK}(jv K˩XⳗjAO>`éF*g LdVHS L1P&A.L\.C!̀ ?cOğ*xxHsxXsxDsxTsxLhkOhNOjNh{5kkۚ;;>M.x>{$K20EJ!Ӥ4`̔2c1,) -e?#}8^̕r ggJ"Di"p4 h@dN&HSӤit i.فI@)Ò[BIUbLjuR^$:ʌ+s2_̬NI@N ?^0j]֥0jHH`.8Fr!^C^4=QXгaiZmc YI[0f"{fYcX"}֩HQd)g"2Y[[*#zF:_$$N ci|;a>6U#r&]DF80)[O~esI)PAƲxV?OeU'Ur,$L0"E(h+1awXY1<|pPU^^ ^=xZ\|<fґ9ܖ# 5Xk5% /}gcցΠ)0%՞=`#ykꑟ6MaEenz ̝F5ȕ59(+QmQۻc۝{X%`[(ζ6`SQ]+~q>!|ר^# dkIq6IAVޫy'I7۽_xľc}_OEB}w%' ]|J^%Ax;I˱jUSJH1ń©wyqSg*'JV^n|j5}bsM_Ŷ;˶\Y%1FTJGc꽟c"by<>(g&p_u0P98\Y9[|!R̭lvTFd /+W#?*_#B%ہ*_OMƒj ¼+ՅjSju:@u9ճ0Օw=@>:@m҈$7.|HRA}-8Yr?}(Y?|-c k_ ${$J>|sV:'gdNv/"8T_:W ysq*:t vs|]EF_aj0p$5rd!g~M>b>PSL%xf*3I*jB%5%fpj|5z+մQ耵I%dɊD՚q{hD:*+5I~QR:{|koΙ5G&ΊJ"gU5ȫ+_36]EvuV׼D*TbM%&q[sGsjEyG}~96C)^꜇|u˝k67>Fd:\[BhCZdZgៅdWȵTֹvl%ꇩ>su22s]pnEtVt]j#e9ٹo=ʽT{"Aٲ C:__S |yHmxmU|SxtѾ<[KWw۾uԋ_W\DuT9^A}ݠaa%csھc.up 9r Eu,uu{.]UytPSZcNZ' @Ū=Rpg}TGRJWq3Yϊ=?4O>>b+cqLo@ ϊ^2zQ^uzbl jP2w|Eesxx['*C_Uc>np5ҳd__r9<Wry^Z.9iI~U:;3ճ|GwsP͇yy6߆}특K;|LH5s6ӿբޥT`f9´c/f`$6dWsw܇ez\+EU#<@Ϻ;ci+Y1 &r;(;,=VoSRzdxWw4Pޥ차1i>W{Q%$I2R?t6yoQ箔0Oz~~>F 5cp_c~=a7&_>3Pk׮1м ;Zq^?{TJQ]O.]/3]G/#n]ȴ\x{żG|y%^\=g-_'u|Ku"m^uٛ"V{qw5;+OX m Kv6,*{<-y; T"j{Q޻䵄P}ꬽ1PuW%ϩw;ӻ3ugy]}Ǽa>G^ʝS?K;{ooBe 0\`{10ch^ D%YہVg5׭-+R*7 = c|59r?7|{!Pmkp5L%yfVVz$#OF% Kx\5( ȓ MwsFq6 W6> (C.'8f(QnQVO[>Jl|4\gWK>=6.*qy.e˻y0%9K/엟 -۲Y6 ߗmtLVf/hjh3l3֬6 @?H3ao12Jzp7x[瀖α$\c_oV7<'A[|}}/x~~q_Ri?~: WKz/WطAf例uUHRMgE"V-ӖaԬT6R1+C`e8ׄ%b`g돫#}X2Ώ;ʿF(_}\=<2Ǹ_~yޏZkOv?*=j>8>﷍q>*~1|vH}|z}>|1{ia  Sg(z`>]0*̯_7m7 o1_23| g7wLs-EgʱyS%0yL妀EG))^?)7ϰ~z ʢ߉MOFx-e@Sm+64]!#4ÝfA{M嘖 IksrV <~= GjMAK?Qqk$j8cf NØA#ؗ@#ٗAO2/:ʾƞ:ecwA+i35}FS)lV֛֘ML[M;LL{MMLGM'LM= (텴m ,s%t=#}9 \߁^ s3*K;y!x!Xu,;L=m|̋qUDML}>SY2]7馭LYsTkM儹ܬGȼ=Ug߃d`Ufs:VhUB?0|4;ͻ\60Ta9en'ɯgsj{F7e/Rs9|jja+650s\QtZR)[FZX {,q~ς%Rlr z-TLKW1֣-"̉eu>æ]7--{,G,YF_A)ZZN"6zQb"Y΂[ K8r5M>hՙ-x[`un5:V3\hY5T`5grRڠEuk Ȇ> 0lZ}99Fk51>]Əe֕L+Vhuuuuu/l[eGA'<^8*1es嬵Qzz˴gInޖn˴S-˖clhV}6ڜg3J-MlYL>[Ce|efB[`[+߶r ,5g6޴@,rP;fϴUf6.smmm"JخnnNfS#'l<ꛜ?9ur1_^T:x'yւ{&ݤ+0 ˘ rʢE Vf.O\?qA^T  ڥPqg;KFlQB˺P]m=YDo&¢RM8}N4     ?S|E}mG|?ufGNs~'/F- o{y^:F%ΡȓG#Os8XG^ "Ou%ɖD(*DE `=ZuzG(uJBַw@Ej?ZǢute]Eu{"^6=\;?!TY/ㄎh?0 r6g ֠58A?a@..%00]>CYZ4qB@@C3 XKRt]OpHjNl>|Fh!s0x@6Sݤ1ڼu?$_jͽz0Ȥס)@g*J닖6KV2|8{4}Z%8Ehh)Pk|>wql?\kނnfF]ń|#Iw:F ]]tI8h]u̺u%7R+m\I2?cl2)iΡrOAm/a(+ԻgJGx9Ǟ8k.p$p2z Z!>C\o_ε٫tqf %k=<S&s ? T\n0P`?B`<ς5o}˴ĴncyOJB3Ǩk/2'3g'5!$]Fxz )XZ299*κaz y-i8:m~^_f]87>_qts׃m<"s!>a֖Egpx&_g//8:$P<=̾5htpxV44ld?`3Cٓ6lWfZr>0{@n\ȸX n?@xN0p5+؏?b?49eN? 2w;d~рYcm"wgR%^bJ:Bw% ?=ןs@S/җ:VAwFG2@ՍTs>j,A߃kl"/Tȳ{m x}y}EC3ka< K^ a@=!$0;=0 LZ3}g0Π Cӵ+ 9|,B% xFoӬg,q&0bvU߁h|Ez1SFj­:"s|%CuF!5>p*l. 9Jt$kŮ(vݮ [!6\34?B?湟{8gzqMɞWQEhfnn@o?Ahko;% I>˼y6: UgTsjJ3"aP]Q'^-.E-؉Yѻbs砟(6 FuI?Ju]6J Ż8] 6| H;m2zwtE(pBy/p؝tm%0 }t[ʉ`޻{ɦ^jwmɒޟyk 3]Jv t3U% F+`ݏi%DRKUWJĴ5_\U Ai6P۬|_~@ܗ@i]PB{H--WR8 %B{,BPFQZu>֧R¿0. +d i9B]]L-Љ ת7qq]mlͻM>֚9&@i%9GpVi6 x8nm㒁9]~E>zG0Pm AJY}\>ʌNr{pV.p$p!0|rQ `JV턘ks@$'bI?&Y<⾇L^*U2#%̗dDB~+ Zb\;YՌaLe-Y2yF*)lSl?oVHgA@SxTF$܍ȍ1F|? hQ^ƂSWJ}kL7eʅ|Kp.3Zۀ$p! p#rgr_+aK; z4 p o﷦3 tJ(Úe=S}mf?Qxg|2Jܐ%%]*9WqIg7w\gGs}B KG>DB2h#QAp>hJzC|be]ǴFB` u .Tҝp*ۿ ԒC0XK"c%lA8k֏30j1;|yh1@CɣJtx'yZ{ȮOHivϮL-ܞE8w>z1zXҏ 2CQZ;4׍}sh-zMd~7pVNkZ%2v}/}#Xl%K@KJpVxI^S0?A({As>`Ex옯 m}eŠb<lͣG4GXuypN3 6}!}.A'@G@لgDo'Z _td5 5s^ {L0Mȴw~K@sǞl#;@S@ g_mq@b"8-u=2 {.F8tat.hw ljNW;i V:-`wPdRcѶiU_m]}@HK^ bBT|s~1t̑l[1~*>>_տ[2^Uj}3kg46ތgæ*DMQ[xEKT"<@ boעLf$@1T/ƈnE 3GQNĉ:dDs.D7'}E&FĄ!vR/N2v,BE5"U4E At$|yBҵV]}oI%U"^$6"MdlCĽ9NL2u [Dљ5D'&Mt]DOq'sdQaV9``U`-`!<Ҁml``˷Em d0<>4c%5`I{k #5́{Q'gW0\nnIӯOώ<ax, mM/ -4iȩ0v te_~,_=fPUI6d#ʙ4̤#|W}aRH~E1|?zIWtIy7qv;W082_!2sJزlNE +b*XM1T(ّ4/I2h'7A,$+D;Ԟ0d50Jv8.Q7s< @N9~uPZ"J[4$C9B5֩,,oSS7{(#YHF#YHɿUBw/֚;dʯ)נ4甹'!Izn9n(TH>cncHþKPJ(2qeZ+WF\YʺWA\Y?ĕ ? l ʖC\ ĕ- l(ʆ!l8V@\ي+[ qe#W2VA\HĕB\٪+1+[ qecW:@\ٚ+[ qeW6qek#lA\DĕI+[qe+)+W6D\F+qe lSĕmWʦ!m+qeoF\6+qe!l{ĕMG\+W6qe;!lvF\l<qesW+vC\xҶY_Nh 4:&tL&_GH pw}c; i3ҎlJ;iw7H;{ t47 H; tEiGiw_{vtC@i& D4=iGH3]hݓ0}'aGw@#CtPaF3 737hdH(F#cF0g4xF&L2l4Rh4tHhd,42?4F#3F1i42hd9F35yhfF#F2Y`4hdb%F#KF,7Ya42y$4F#FV1yhhdz F#F6"gUWc]#{FrP>IC/G[c[c# ?9QN"t9J8#ψ*G`wOQ j&Bi|D T*sCWR|/D;|H(GQ$-j \jZjzFTԫ^Ҭ3JkZc=kuzkzd=om^X[mver*5j :wkk̵ɵzѵ]]]QTt5C=w+i&{]gҕ<|:Sb-KD]h_/U/RQ4Sfтj,""XRWjzwyOj!pQZP~ ʯ+!CQjPc8 I*:u)CB7Z5"MB9YNNC:E9gqf;sE󄳀kUTb %>Gv5ʵQrQn3ԹO:yHQuTAQRQY"vP45ux}sijﷆݔS4o_ֹ$'EMm sFQIg‰wR:/s9+oݖR`vN=r i"p r;FS\L m$|:g(ċ$[Gg" .߾F9 d5dL)Lmd̖doWK$oOק QeQ9]=^%)jf&[zDMMѐ#__ƸG҄#zyf;bX}z˩K,@O|JV{  =(#| ??zdY4iCu[FG@B Z4&e[$H͛X)4C(O3"fBY~ Zdd d3GJef-%Y^CWd7XY~G(ՂhI ; WWWG`+cܫ`L#1QӪhi ƴzVGok510qxim6NѴߜ@;ib.ȓ=K{MFuj>QNE/(Zo<l.[Rm$/OJCU$%I^IJ/~$%8>uB!$ȟ=IEZo"ɗH$J~D=xe?DD{H~? I^Cǐ-$y o8 !CHODxwG`+cԫ`#10U1ѰXw5XZ8G<6#Q H}ԃ}xaɰG}oɳKqPuHQG1uBTNkzzo[ǭW7?bTkҎA:XW:JX]SW솺n4Rmt;3u9].uc9v' rP'܉p<6ylGkm*e"[y| @V+ "V7%ee)gʶqI- )Wtv&D:)6|tH'>i|x)L=tZtz'+:[T*H6o>#x/k RIs֛\[euǎ<ނc4iipy#r bZOJ :'o='WFsZGܛ7bpXoՊMyF^]10ślPƖUU(=PJNܓٕ*7eV^8`WZ2-Sr5t\ꧢ >]us/֢cMwԫ֞v=iJ\ߤR[}6%haX8ud~gG&;5–xJZ,ַ=pyT?fW寻Ȥ]M/ux t)jܾnޣVzgOLm0y>&=Y퉧Vѧ׾uVz3&t9eᯚ\䝼;y%i3JɋL*DZoXV˄-~f+x Tj˲c7e2i3;B+|"{G5뽮a%5g%n|%!+ }Xς{t߃ϯ8PQͺ|&df͠~c¿8u⵿ ٿ1~3]ӻQj'}lx>:sm{ъ){[ //xkCl qlm{N4!E Tr''#@;EY9vۑݟ?t=B_o fYzx>%мoBR$?;T+Tu /N=#<|PUS[Pw s߬fkk=U%(d<<%Џy̙I\#ȋ亴Csv::KIҶp$tSD dNgy"v_qPvDޖ24مa9Y<*WZ@ͫ0%{颶I-~SKe !Tx]ǰHNb\ׅ1LlUiAQ⋎#c "i\If<],Oʸ$"ZR l rUx>]DFj9iq1cl|!ѯ#g~cThAЀ X5ejkScmw喺R>*1qRB#S]A9.IȦn2F{PZw"9z .3 \Gs_3_.쾺lV}4k:xኈw#Ϣ57,e}0a\f67+-:Yrû=afRf9}R a+S6 ݻRq)Ҁoရ&7I'V5omK*iJ.HnMKl>#B+=Z`jf́Ŷ$^eiRx|9kKo4&Fo{+m 6'[O S`ʈZ{VM8jAYI&J74d157QQC!wʪH|"xo??|\CUV)ez^C/XOYi$JRAo>Mbt:< t9T V|D?xjdVt$>F5,`^i$4TFT\0;ڴ,}7˗#Xޓ[F WT/{R3{U~FbN=n :S5M'-yV}e5[ /zRP߁d*GG3ȷ/G⁃?}dR󧆷0,zUE7tbp%ٰҖ[_xoUl==5N i 0&Ie>$ⴷJl$ޡcv+]3IcxUOW'UB^Nqu;3Z3rI9S[kxjGq+'APn ƺH^[|6S>L&ٚ5CQ8p,jVM^잌vs7t2پq_/nFMt q_`+A/n@%fS\o(@YB,W*Si:OjFZ O U{j$ yEܻk6 IF*.>{_ւu"[A`ru, O,T#қ$0ZO/lk`BOXNN闱!oNS G3>0Uo27jpA5dr~.]`mtt@PoTe?hgA~-kBc_Nw H|| }c>|ɢ@Bf?eԺ.CE\ ف ' Hd: ,GZ t:C*pߦWi#tZ'A@L-O'<j}c?zo0r=VX tFv N'J|7ձZ#lȰ[wIĆq+\UڡMٗXͅ S6޾ŻsnN'S,~2j4-z0qO P}WFOxlҚ;0Qh'ҫ㯍<)/ dNw*2A 5M* 7tN#ѕ_ne`{ ӊ.sFA`0hq@`'} DG_5 0.ZU,SMWgKmx~czd"&Q\kN`E~ ,G:qh_CqY?:SbΏ?Oo@ͺ+\ҹX; ^g,SCnoH:~}T+#h}9 [Q[1S4 AI~ ieyж|BgEkkxyS, G?msn0.E Ñxwuqn},cKě<2˖F%Vs٨YlEE֒m 5@$Ԝ >'x endstream endobj 392 0 obj <> stream x]PMk +=,&[R%C?h`t ;:ϑM:AF3_H#8Z'qCyד B[S/ s{ u#qk08E/* Af۱5۸\)F{sPIEUpP=so~ˇGsp;e]7~oEI}>_e,g4?腈)uO5\iح| endstream endobj 393 0 obj <> stream x `Tս'%L2Yf@ 3 KvLBU " ("@JhUI@ wqVָ"";wo/'|~L0Uc-8 5Ew{?G򲪷oϹ&| , I/JN+ݏ͗4K@9y4 o:=1X^_M[ N|o9w[> 0`ھYӛZzga6B:[?x% ^]s/kn2M\{IӕAכ0Lo3kZ\l/%<] ?Gsj2aC갩Ɯ@A-`Q{:-}V|ʯ{fS3Nz+[9u =M0&HFlf D a/(AUEF74ZA BG@W`Q  C`J)/&$ljRAU&:e%6iC%Z-㦡P:PpZ*8 QPrx \Nr ( wSݠw7\ϲk]Z|2,Kws[Ww6q994r& =Ovx1T^7~禣r3z%l,[/ =?o2qηa*|_϶4 r_o{w 7܀p bĭ`7bDpBA<@B9$ S`Bvc"GGTFFL=bkh[WWWoQYC F*rr1,-r'UnTRu?2,ú\ d=X, k0 lV&\YOL8rdM߇~oX=LFձ)]!LgX=Gɚ6a8RX*vBJ}B ^ؙ \VH -.gS Ԡ-@~؇0 #V0I%D]%g%\zX khÍ~ᷘfwp [ඟ~33lj6?ZWyR_Qs\ESLnT_W[S]UYQ^6acJ ܮѣrF<4iH\L`(kdJC EvOLG,)I~g4 h14{~vJqNJtd&{$ :N{':[/+b$?za/*{XSpV[ac׮;뒆@Nz9[Yh&q#z¦OyEmaᨓ _*ˣ쳹Ͱ>d_ۺNLkLkq45z&&=OUY=CD'6̣69m&9Dm-b_3a|=mh!ඬt4xVTԒlJN95Rs xVJ@Sm!?shxwF8s1Lb ދV:'!Wy-okV9VJ-|'y|E>Œ[rNh{9 ;N*fLڬa8/pis59q)jkr6piisV$*kٮ llu^\xڝlMEmߘW>jwqaB=Jh.RB ͝ 0MoNLa)(%q=dkmҺYmu|fA#c 9 *?9=ϣw\K*QB6_Hhq(">_uc΁U_&¯.t\\Y퀚ZW=lodG%h0EEԌ}(_ϊ:O]"h:i,*uud[-'ga++1u 2^1؀Ww ൑_r9to6xMA5DaYGSrO`K1RLx݊zC%u*JJ/,RRRڊJ2.DSWHשUX%,Xa)x݇$ UXZ$^QQ Ijf&ͨRӜ4)&1Q6fC=+g_3S}J}c81f_ [QFPTUzT UTZ% 9+*jʓjXT+HʯKr׸:K;Ƣ\⎴(_V0oGjfwu c;ΨN0P(& ;"|BMpr 9lB!0AFH'R )dЎTDa!@'b 1h`0 QHB!#<a#B VB& 3D0 AO AMPA$F Gz ?N~ $|O8Ap-ׄ_ t>'7gO >&#|D8appp}_ !]; oDxukW ^&Dxys.³gO"@+/?Czu6-ԟPo0Ez *˨P/^@=zՅz i>;)ԓ{8j7jQNTݿ!ʃz0!vԃPDݏ u/ݨP@mE݉{~snCmA݊;f&ͨPEmDAu~qz:(`ƈ '|_OJ) OQ $\پ .-e ο: / x9`PT:5T(6ZzbʋeWbaI,/DS@kwD")2`I0XSZ;Td4F2TeFQa4i|޸G QͯO^72(s eqNczGS2ګv}c=I]ůzj Omgƺv&W{Sɿjzȋuc=+o|x!W7S'NA$+ 1`~vA  \ aOKw}|$.#hP3 |_s)\ a,fa5 {xރcA5ogNi߷]W~=mPY|*;cIS@|g=_uoT3|񾯄l0X!| q)C9H)>K: unIGW*eY&l\l[V5z- 7cޅ׭x/}^jb{݃~mG x`moT.ϴ}woŸ9}Nv~vƖ:(<$'zL~$'jo޶`~ PNO8/&0n:̋>N= ?`1MxqtR4Lt~)}oj323Kd:lY,+gX*=:dLFK=Y+Ƙ Uyl_W=^u*&q0Wn6@5\{+ NTʢkj0h $?i2iO@ 6-V*vʐc_]t(ngZn9n~ݦSSadj6vloɘܦvi6GƅFx/'2cV1!ohTVwz 0"b0qEWnǐZWE$V5®Rj4~zӤh n@T(|'ӓӓsӱYa,;49==̺?m.&35ʲRSCtcoVqղ=/lg+{b/^#gDA,:%aQ(`ThЅ *C蟙;pCNܝ͒`AؕR.$ڝnvc# 3PkszhADe A5lۡCԺX񞷭U#7mʩʰtˉZV;R'O1k}%qWtNŻ-"=';2$ѻT?W&A4,z㛷I!3 @=nBx v{>pp6wVE+PCV>*òإb v~K?@FuI&=zT%;:ހS8z7O})S!Vs3_h,c{0.mPUYO..UAZI ,Wef8g ؐWެ[*jOM2(f_)Nv⮻cJTط$sgwhQQ -ji|\!\-ag=ݫ׹՝L!JDAP( uK WQ3#(-8q=!d|+:6nNJJǴJ>:RwX L˥>@IZ4p\" 0C~yfWTů"5lsk` |xZ5pԥW6&bb3"E޹f4EaDK+6g+ug o E`њ5)_>` ٷCboѥht:܄t,Si(5n[rqsdge妳49=4 Ƕ2dRWJ{»)<;{ [•=k?z6Ta~*a<"Z[YHp&G#:~!,|my'η$lli[>78jIzAVT AfBeN.AT^ԙnTtiJ==XҺx*>t<!E+@G%/bUqLuț.2?3s1,Eo>{E]sl47`[ugvj( 3.K)hVܔtox \ $:7WPf1cwfCâ=z(mUphѸqE5gL/B;*j|M[]C$'-}{QTMv={ae?*{dR1(HrtzVPkDxvr(^1?_Qzo|7RE>/3MѴl{GG` ?D>}-nec 'GQ2o6{ge4_k{  TI^eNA̢;+JoYLkh)F9r<|hKUٻYG]|E uuoPHNtsA*užpxQًGNXX?jٞWNȮrS35;_jPveh傢jFG?8=ikBfhwi!o/plQGK#HR]Zc~ڥInq7|~(v*h >ly=uq]M3MM5ɝ0z^nD͐S uv;•ޝ/O,YĊ-zCJr|_O+4Li#%\ffAvr21a$+~|w*|?OħKT/w}u-n^=|Fw؄sŅy׍ 6uG ZyEјZs?8c?;m3q7 dv 8R\u/o.X*CPpF 4@ =-cgJ8)q+ _2w[눓̞9&a^( -w(l {F`P]䲥l,˿r+nDV)l[ 7FMZN`1"2@{g5)V*hFhzvwx '_\X>^kyPd8z)lC&bNxcj[1.C%m|=O ?emC~e΍6(~0 ʡ>{/E^! 5aC"T.mz\z"8qjB̮!Φ5ߖ+էbV\QTS4/"'Q^'C4S4»i6uێ͕O{ oWT|[,3go_G0 dZnyzjJ}]rJ}˗0xxtjz@DLpt꨹jǢSsBFEZ?$bs|\͵Is|jbZ!itՓ5pd M4rx5zvYͪIZ}Ya YPA49XULL\352ڵ|%@]~]Ti>uˌE-c/>E&mhB᳥)?*8l‚ Z&,S=2.8}ʊ86(]-=j/Vt(k)[uQJ**NBhm_E{NUWwWu=^tN:! [Xa_ l(<DΝqF0+ 8Wu48bSUG$}}΂YAA]Tw;ec` ^0)L )[zqbbI͖^XnoPv|3oqݞ^gżw|o/AmBz?g|8Ɵ 3%7.ŻまxÀZٍ'v89c /'NptT Tc[&8~ޑʚ@|gSL1$les6>݋-c32DT5+W*L:1xCF\ZQ-ǴEa%,@Ě??&x9W^<˘|NmNeVK5FbAArT2v@Q"T} qDh7GF kv+2Ye{rE@6 n+ qF$GUȄCVۦңh8(暲MmO}mMmQ"'%#U_}+'ymSOR39sE 6"^ VOJFTU5"~߇Gg#7uH펉Nɷ0{/V,NCɀP6kӍ.bZ9[R D pY04`h;f Z**hjC&6ѫ3mk&1 .946vC%!-JmJSJ%R:3E˸jgq1b~a5 VulHL, QS LyیV$[%1rʝQSdpEM3E?o^Xxf-0/w Ng6[WcMőwgւlkRbW,$HĔ"{L;vVk lU<a@V!eht(3hlJ>>*'$~P_(LZJ}VZ_i 55]ob$O;G@oFE]jaHe"j뀓Zp}J( ā?=1T@7OyªUAᅚvR/V:R6K٨PҔ#RcJ+cȌTFvW2zUEbKeR)Ou^߀u&@oζQBπ^W-:FgsgC"Yʤ[5)^~^?z]XoUg7-+|gH+1+wz]=Yp,ceJWTBE!=Nဗ:Li2N!SJ9SRQ [(Zhk HХ#zL߸j??u8No m<UtDAa6yJl;-CGhBiᰛMլl>yRGCE \4涾C3݉@1y˜J_o/KjwOVQkQ=Nf?R Z:8\%E$9%NW3>|D :ZGN AY tVᅡLՌ >|jǥ_Gz[З#hvU(zG7QBղ9iF;!eBGuBPMz |fk^?}ǏOswr=2u;49fR;b8묆[ꊛWTp*"NIP0Ghրr}1aFj 01ǣW|7p,]ڧj3ehzZ~w,F:c)Ќ46n2O&b)B\hdIUK~,$ : ^㤁}ey?j_Ѝ*-)l&,Dz@Y,.48!&c @e]Xyw}`xmȨo.X̪,r'8s /P{ $Pır[z{_" 17wWjH3q %*'4 rQm& 4*vT,$1'2\]VHinJњjS QXW1 :cbo 5-km~vM6wИX`eZ6ȼ^2OO/17Qn'3(ќJ&xp[dB^,5o n@-z2a}mo8/ylT-kLYw$5NhYYb}~:&%ϗ+9/T=JZxZms> \B6>`EFSBdH+V!-Ǧy⋗-W@kRYfP"ƀ N"aM2LOTYx"&'r ~m5܀&3m 5 mZXlpU 4s:ݸ}(LoE*ꥨseDW%^ց & ѢDj=:@lE ŠC>%хh>پlEbm Q1rǼQcV+h!MZYxلp1,i@HvB̴|+"-eZ˕7 orWLw󧧤V䓯G^G@4ҷQ:#}EK*j3u35uA8(`ǒy? ia^|q>biS[$@%hB2)=3B&Y{kթB+5M鮐+:{c2%#Kڨ"B5mk7˛&-&T{z8vN-E[Z޶hh.Ɋϐ g_.]gVt{y,d ۆv0{7<zvuSbW7Έ 6zVh있qy a+U]9QXC.Krр\T^8ڰ5-rO oݷXsiZYTs2s&zqΒMUwE\X_8O#q9ydGN#qUdZ CRbx?Cfk5jasWDGϿMmlQ;n462"^1p@,``R:U#C2/WDpVLkn2b~S!P6؛ULI?VyxnQ77Vt=T]be[V[M*ia!;$]>[d̨kŸDl:۬#gL /or)5߁V8""_M\?5uOycTdx)>Q''[!_'   ş& Gk\3G 9Ξyͷڈ7Xisg`,=E"ic5ee->|YYK R״}bAXC< uNs(sRttp%tSIO;hv H^nPw"nɜ5{K [6O:iK>(:Y;3%m`H3 X:''sv笧pFj\l{fY}~jCvumRj @d,"zk"Qh."0O"(zOc;1ESΠxR؍#,9L<9϶ ߡ݈Ix$63ad+Ψ 1y|j/- ǿ+kuuc;Q2L[WP>?N[|rHW'#|C]EjMhyDj>< -?Z.gN0؂ZzrHϩ+ZH =rr'\BIc r;I }Dz]ڥ.fH?Ʈc>Y`}+Waa x]VsЛPj^stM^ƒ'֯9K| 9N}(;!n@)P9ȩBhoDr,YI,K͂9ؤjbtXOlXԥӬ^, ~MȫmNAcF#a'z'@9nx=oALC&{ڌ*]7Fi<9metD f6,Vھ{zi}һOGN_嶣E/#вnjr;P**6 h%ƴ2D={V*|_˯ ׿&?dNL3{lc8t_y)|% "+*88M6w=j[W Jb9PҁCb&1[I+/;paسBFޓb$qvór4_C23YpNԬh#r4 o94Ӹ!bQl[, I@T{+ 'kA𓝃>2SLywsw{PG+)+g27Sܑ8.Ñf?q$ fN:wI.d%3pcθT3ly`ڙ檬tū<ɓkdfhM=be<Ϫ\?g5v15 Wg;F8s6ZMA)s;;,)+gQn;`/oFْ=3ϐf 9}G6%g{ 9ya\Ue@v ;rVR-. t@>,?~ K<8am !э ,4jLƐVQP^Q@ЧHd}P8 i 9!A H'.q7F/FdB前/n1B?,(:D#NMRS:-/}nM菓t"69-pvƈF:AN'u!bruO`6qRYً -N] UǛfTM l䏙 ;,1XsCun@)(H:`CC;fYY`(kPd6i!,O23vRGo2>\breD:"b eLҢ9 QЇ0'+𕧟ӞOjnla$sd*+2Nƈd6Xd>`JF4~,j.cFO 6x4V]rc V8cRd ,9:P*aF!$ICBwXt]O 3h#]A_9 _8!,^ҡ E4b:Qw"Z M=zu0[ ׯ.%!Rq:J7C㪍h8\UrJC.pL?I & /PVkaaH}$Uꑩ));zuգ#юu+΂rH8hCdfqiFE,b$:HI耙hѪׯ$zA|0 ]P4ƨG8FB0B<4?(jmyzqoǞ*/HO\cV.ݐz_왓zdƄ(>䴚V,hZV~@kq^i>QHPX$*)3gL{h8'M?͋$]: KlNzOBv`/djP"UC JgٔF@ByTZ? I@( %3X,V+-Htq WKWNKfLgYeD|%>+uԘ1=N3LV{JfCmO"ڑcWcFB18He^ dLzYfNSIc~)̬m./3.;^;7R^LlKvvј4'f4PdrY%{6٣r 1^g8LinmsJk V͝IVc7t!.JnS(>G00"b %%z"J۴ r*;ّTul65jʦR +xV{~ ]<}u~ծDOf0Õ-x p_tWn[W%$;A(%m " ُ݁^؜W"bNEp*UmҪh L zL: DPK ?D z7 ;-p)|4};bOD›+ bQB<5p,.N FI\%*-'o5)0 )gx:}hD2tZHBW~{jݧ~|:nS?_+6R}tSP RؕqJ$:Y5[]uff_M&k7#Ro*#6SYԯє@,) ǘ=D.aBu9ޜMSwO\3;텥&|NB˝?=tn>ޑW[7`mN#!TLoU= vmbmjYj;bmv`c(p.[ U .9yJ[p_‰[唙7fZt7ɞ7.L St:#'LhKzJp^Չ֟iAj'03BvBD⾀D)#kp ER/Fyj{-qd׋F_Rfw:hLY u-pTJ5pQ]׾| ) "ꈨe0kc B: ~gԛ\&4?kXZkZZk^7M|Rkh4z}~g^{9V>J݉&E%&EDMO{:IlTlآhusMɪ)+rL![/3rf/&C!&.neE ׌)δY qpZZ UvϘ0lއ9sƖ'gfţMzz>wǎ/`0/*N&x g&ېW!]5sè}!#vͼ}w:WT(yL-|ۤ~VܨL8'm[b6񍹓f ~qet,=Zֱu(oc^K`L}~&弼yW1}Ĉ„^xۃ7_U  n~'F2}ou1,&7:G1)XS o~({zW rTx82eܜu#^h[ݐ蔤i9MURo`8w :l-4ŘLLO\'ԫ?a*::L9uZo3 vn,JY.H7{S*;=o2#߽1A{ +/0cs5vegDoWF7m;ii)ƘSSwq|:I5ȟDDDL"^~IgE=a[GP`# LGN~/.@=PK$)*Y_Q7?姦P:x!Y,Y_Fc< $$`A\'hKJhEyY IIL1ct8oyp`Ϸa &d9bzyDKBKqR'K_rQIT;雓cr% 1=.SS<ڙ9.$Sޣ{t=oht-"kJ60m {FOg<'h_E!ʵ=}#[r=GNib B ,8/2r^%6[٫2KQNh’w5^RtF׳t7LF`fYJmH֠/xj|GKxh k/29jKllԋ/m0Sw5^k:,6کFp[ljtƛP5>JެsrfgWU^ʫvVy*YU;jgWU^ʫvVy*ffy,4\%kg,\uzaDzqe>Y-6\3/^^lATK^Ѓc'1-.z./v.KN]|/q ɝtdHm=%!eT4Z)/5߅a"G3dzHfyQ5R<;ע2x~:pZ*jqdef ٥tX~˵ӸzٹK!Ck1I.!SMuĖkvk$9-YAB"XEsrjM&KVP^zdU=;hQ7XJe+ 8>R-$}='t2N{hlx!<Գa藍Wn} EUU/ul|4k{ɪ^7B}Si{ פT:xi&hc6njltXp擗)munY4|&ãح52>-,f ׮KUhY͚Oim𢽮?ռ9 =2dXursg+ۛnkмTZ`7`nn4tv=foyfwwyI/ȅwwy[$ x@ͳk0sk^l2w/-.@;/e,㺴Rb^ҹ %>O)vwkfhC͍nUǖ*ÿ=owR4 qS܎AtŠwe=BmFVh&伱nҿ5;=M/dV3{}-D-}׋! 掞/[Jh9_O7eƀy[-`wӺ ϙE9ty. ^RfC_/0KSV{d7ytg}b8H!wyym'Kv+vzԵawF|^pE}tuAOKz@6'= ;9=d~ `0'gŊٝ!x9j]mr-ZQηzx9s` \Fl=z4\䪯hkonV=148IwQ0͡>fF#2\/TQqrh)ӬNpdWMh%ULV_3QQ5^OSڻGivt֡349-VOOG0ݵR{~>3~63'|b &f3A#a0W ~0|P~0|P ~P*X  m ]*W |P F_+Ԃ;z BF%b9]< ~iIoH7J7F&ɑr$dC|=?G]zУuA?`Hd x0 dddd?8 l#n,3W-Y\п4!G⏀? ࿊ 7߀? |S|3gA txX: <"&Q(t x\:<)#$]^.HW}R_^KׁjIP$?RddO0Zʱ$9 ,'ST8yp<.'ɓS)T4y0G'.Ox|?p< 8G'Η V(˰lir *`\ r6ꈫc2_A6@Ah0Mm@ o&0 "e#$uFH@UH0e'gA&5 t2 Xufw,TV4"Xʫ˘2v3]s]dq X k |9Gv.\Ʈpdhd4,zFUi7mm)(Y<akyߦG^Soǔ8L=NIQ zd 0=Vk;7>aztVK4҅[԰tZ ti yXaT+bTc[xWV^h TlTvbmcrQ+z)g#&­;{~ ZdExCYj0 Z+߅$op%9duG,aRwsi\#Kvd\ *Sٶ|XgWpcV~tbBi 8&(g9bWfy1W.4y9cOF u|]/i[v]a߱/38H8ҁ{K$|OKʟ !y"tct2W&U47Vd$,ɣT~.a }R@r*ۆ W>J%¾x1YRԾ&[ti2:d}tŗVg;,U9kUUe.*R>Y%7T-Z$;V䵔N-dnQdT ZQv?"B<)SJrOx|~lH;D2H/?TuT]?AWO!Yf3T|H7/G,Ec Zy-9}|v6snZ=ȱ15I5.'rQmYKS -&JfS B/򈨶5%9mskjpVR8i0inbvcF%l3x+3Bwm )Py3B~0gҌ>;Eē?7߁qƊ2Op'T8k|i9|\x,htS4.Sb]l$bK}%jo;.n轖h]V2HzseTQ~43K~HWM9eUW)<%lP67(_FQQ^R.-Ѩ"F*ەIW !8R9QYĉu1b.^/:t/Ucka:oX$zmHWYʌoGX/r^U*Y#fx>& #r ꯄ_W/ _,7^ԉ:fc)& Q(%cX&Xq8ʼn9bbXȒ6 Kx$6 ;S/ɚaͶΰZ ke]lm>lܺ1֧Xd݂.v.>AqI^^YցRV^,5KKQ*L0 Qi.UǗZ٥ť]Zf=]@9'J,,]zxoR061Ӿ kl7^e6?X r_1gט]9IX &k(Wc^@5`$֨St s"ul.F%"x]._gaff"i$,VEKH}HHtĪӒKKKL=LZ>5cH\:Zl-:Nh!k+@R;peu-)#ދ5+@)F6} w*e2]+T$H1aT"PYVi?!: %u%GMv EE%"iGVN?'ٟD2?M??njz)ljnw{曟_;~r75't~T8}~|T}T }ϡǧyIۼ|(Om?ҽw]3;}4j엸-dAY?~'aEX-V .xm,"ZYvRHǝh/r| F~^~heGw@2z("P};}ec_ų`_%bOe6='~'Akuơ,̢,dZ-\2;RfqXٖ%VK%un!~KnJCHޭt9@K>tr} xEnUuޝ B;!~A"Bd#"#BPc@Q{9 22 ("rA$wu0g{%_kZ]UVW5,x !jW8Sv?>NQ]1MqK(S(Z_D5+q]vPi1^L%|4_χ#PQVj]n9{yHB:H}QLwuGM(#MmBo cތC]C]YCB=GC+ưBFs=p:FEhb0=4jI34k-54 B4C+К.{ȞBCCUmfNRCd`|h_`0Xϰ'TЉiSh45L#;-TYYG;-4ư:ƕ˖Om/Σ>Z9999*|M ̍#}HQnhN4)&CvR,JXy?&AvZfGѮ|Jzwhtxtd[GxptLtL$7:1:5:=:3:' Z- Z??I~ޘ7)9EBI:d鸣stxr<33gāOGS:`:5':UefggD$%Ji2v@<.biwv->ߺeWՔoPg3e.KR.KR.KfK'O*>Ko܉7l//?{{>8o #TxQoDJ~PʠM)L+)THiGpS#1&M4V>L#7 (zk+(URZCiҔo4nJji(N*?Kє|Sj\+OJi?'LJȹ?NR7J=)P@i0)4Ҹr3ҽ&Ӭy&-4Yb¿O]zURzVCi#g΋[/rggdˏZnɖgZ Gjdt?>wytD/rqr}Ogzzz T*?%' d?yOS <~Kiha!Ѫ..Ҏj .׍uqN-U)z<=Pܪ uWk1ޫ ' Od2^A">RI&uEsʣk?JC( TDi4b#7̛F|.5Zi-*Dxk8t,O^J%W$/M^e.>x)y5Q[w^8|$x) z%t.=~ Z_c:RF"usZҽD[=Hiz0]c*~;0|%g:z2sI(]pXf1dσ(p5dZ#< J$$t=У c@_2Q+zb=58wg23W W ֧stx,rB~X`,0>/GF7hr>dTAfs$m̻祗ۢpic ބ2zP@pw/0ƧnxI3(-Z`[/yggjx.ÈN+he"F| aS3{th̾Mk %|5fM]~~YznHs{VB@wּgQ6x>oAXj]|jvo[6DZ/o\ ;g=+yrɨ.дZ68 {@=h} دt -ρ!z+_^2mB˹ }αgBbeI'wF#tn3?u.5B郘<`\ 3 1XF: 4W0[]ߨo^u*gcxQ709| .:9 | ZwˀiĪiFCy.SL뫙=pڲtW~< Ԑyv>K D`/5(+< * )!SQx!'H68k V,cCȜbUnY ~ ~sgt6l#?V]wtcsafϠ]qtOsA3x#"ȄifmmX|VX'B^+ S87 IB{NYaW[Må Qop ֳ]كY3K8+̴nȞ_-㏰@tj x![Va{{:$W`oBolY1F Ʋ,A%වMk 2у{UiX lk]=,è]vV t7O,Egq=|3}| _`6O'HR55Q º"4,7U}|Թ|}NQ |ڻ>Ѡ}?W:N)2]iH~!ԇh Jo1Z?hv#FKN=:9jAG]X]O1~UVEr'$Wz8p>\Q%zrxs=wt%bn9=+؟<~|55(Vly/ϴ}sX oR`A_xcJW\;ұƗ.z^E?|V%RW!;|^e.׆U}$V{Z_YI!s9k ;yh}#<6$ڝl| g>h<?72I|_s8|: ̩/] 8|w+Ys?0F^>kwL5o >?g(2 J>X=@GE KГViG3jq\Rɭsj鳃PqnfAmϪӘ׀\s 5~z.C*wrƝxxR}P\w/tL~~\'qx7xŒD=c4sg}S[ՏlOoaQ6ʁ]OqU9<2@@Գk)J7wZ,ċ>բ+ t GP;B.qVpg4/5ab!D j[eYY9ZQa !^B~ z@OOB=˂g Ol$< -3* 6SOl*~P},Vm":545N@*FZNbj`=:7G0xW~܃wru>1ĭ8~@͈ d0}cqE]8VيpV s)%Ѭ+jG; ͪnXT_ڊ81|]s4|z[_{cŜkxUa55,Gʁymc)ÌR3zzsnCf |QB:cmc]?9x#>#*@~Pc< :ߍFȟ<$ᙢce=5]yݵEAO t+<ʞUő8w,ʯ*x,s]qu˭X\01z16:=TGs _CG.HdC'C:uBU8)pA5a!;ӄL xD||ۂ= W7/[-bwLs}oO6/8^ߒ-U`1l/6m6f/܋-Vۺ |Sg.FTĨZ}0I% .Q,DkNdn"*z1>BdqRMEKQG˝/eZ\+~)n;xqXW f/ꊶ="W䉾b aHb}<5JQG##,( #BJq-fKwnq?=9BwLDxg]J4i"St]E' P1\Dԩbi3Vآ*EGqBuDHČ[n=Ѫ l Lf r˝qi9% oͪn1fA'oL&SΣ2ZLXG'LO.ˁ++k'F`ppp?Є#Sm5aBV'&~`l; ,$̱GG'vˀJ.zF`pp7a<xxx0d0z4lL$SiL`g`t¤<݀='L738 88x/p~o\o;}Ғc,ֹHT&ܿK Tǟ о\BWm^]mKy3/䒼?Ǥ-//Fu 5{]FuAWbX&*ZATb8(T'eL2[Few/p4Y9J˩r, \[y&a&_7]]>䦉2ԺCI$TLZ CWP#ҡ/$%ukĴGmCb2Q%Y(xZ)h5NsU=O[pZFɀkJ4mP:)NTފsO<>߷H1Dr,dQ+֬iӖk ھξԎEk6 j Vl!VF`=E`c+؇XXu+.bCx nX #Vp nX+8#Vpb@d nX~  Vp bBT nXm+-b!Vp; NGX+8;"VpbwBl AΈB0bG+8X!Vp.b_X]+ Xu]X=+* X+8{#Vp>bA "V5X+Z XBP tLx|r)$6Sn:JbxDW+qJ _}x~8~_*5IV,ޒW&|UlK&7Inmr"wʝbD5T#!UJ*FuWuNʓR|EZj&ڡvH[RGVWQ{2FSOWe޴ޔuZufYzz[ַ޵ޕ VomˆNkL޷ޗc1\6M//e3++hlnL-8ڸL8㲥u d@{GI8T]Oדu@MtV7dn[vگ2]^֭en:]L3dG3eCv:[fκAuXeQԹ:WtWUu7MFtw]FuC^{2W|y.+t?Ov =Pu:y%GE=8#˞]r,ǒyزu2߉qbd'։Nکԓ}Nyi(9Fi&8mZ@畃|1YΕ 1w{NDDž7K>Ϭ3DXP .%;e'ELQz0ݩEEw^̝aq>Bzdj7y{{"^{u-ށ󽃐"/<~w|x"/Hy yo0ޛG^Ay݊y6}#x:| }y0m4sF3FL4d42h.)F#SF1h>iF#ӍF0a4H4<hnhS#3F6e42hhd\c+f~e43hQF3,4Yd4hhq%F#KF4)7yhiG`)F75hd gF30yhhd*F#1Ycl%F3/ͬ3yhfkF#l0yhd3ȋWMe4[MF#FF1yhdVmF#;Fv2n=F#5c+f~o4hF3oB#oC#ۡRo$RkQmrI z{n T=SiZ?iWtY˭ֳsVUiVY/ZXk:k)rY ϳIdJ*2jZoK˞uW&T=s:PYj6ޣ]RL;4…tEqNoWV+ _JoieulWoSŦ럽a$/By{6$P͢ngf~<:,X5٦9YO碑ʨh*jn&W߈D"I._-+ޥ%<''b7Vv!R++Dk;mL'L=OL=ɞ$2KsdDG{\dD'~/{Qt7/.;;"_!}\$o^QLLqdBsuS[Saam`maivtG{G#Ȇ}nSxUo8El7|EmS;.[Q{>zzzzjmvZ[Ǭϭ//Z Zkvt]O7Mt3Bunt3u'AQn{|]~zW;ge6YW5g1"3,%d+Ŗd/{("EPLo ]]zss9;>\cF~~EQH=ň Q(vFV4Mf@3Bw@wBՠZ\j ՃB=Cc#C&ӱ'I f,3XZ=iE߳Y fBQҠKA^Z%*$6 *kȗ,o#+r;1H Ҩ:$ƅ6thI:(JUAiƀ! “.ixAH7Uii Qs!{1."GRu@ET48 1C ۷G>R]{3 |)Y$'əE.ΓEr`Idח[}^*xc·~yͦTu5F;.Iy{ҡdՇG NbCIgGv(t%+GCoٲhQ/PC&S-H+fF 0 [:_sly%ˁ6z6r;/F o ?ӛ d aB#$ș߀# q@OSh*@tk9o5 .=S/õ߭V@"yZ]SmGT7m>%jmƠV^61HED6 hVRamEXdTܳZ}noYl$gU-7-hpӊ+RA3a P+g-(rZdqt w}/ j w|u/XkgpKO~b\J_}mH5d课RΰPR;mX]_ 5iRr gΧ2ꏖbf!P}}K lkV_qUἁk܏/W; s: mzyٿA0hh{Hz;nT'O7uC"[K_ P[ޟ5 jxZu,tP+ĩ6- gkk VrG-G':kapJ#-rC&BFJ @jOf0`n\$ xQ"گo~)gL+yyEx3y{U?sTJONÝ+?g?oRy[Q rqhm作kDV[ٲmknm?8;Tz^p~b)V'Ee.5>󤞤flA (iKYzBQ5h{,X Q 1(FJVqv7TxG  ЍPZNYC_q 0>4rb QOPU6P3dͨ/ H՛ơȎ?S=Q uXS."=6];9U@ ^@w7Ů&5 '*w{j-ਈ"R0(Yٺ\wZp}Š8z8˯h^u0 kqLҍЏcsFeFfY4 fkl&iAb]b񄐾;B(,!h?9CEvzIN6dg?OxCPc%\CVnEqq|ݰΉ9v?NXza8eW~n=IODnG_ck^fwhMlDng/xs~{?],u 戦$X@AEugs .\YQrxE5#L=2r'>+3Q2?NؖIˣέrXjK\ၜV%0es |/J'NJxX#Og-m[(-Cަ^3co:cmi/nbnVZeӳ]4k6We7S %0tT"jĬ"6pA6^ShRead\6sX- endstream endobj 394 0 obj [ 0[ 550] 3[ 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550] 21[ 550 550 550 550 550 550 550] 131[ 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550] 148[ 550 550 550 550 550 550 550 550 550] 345[ 550 550 550 550] 350[ 550] 355[ 550] 361[ 550 550] 373[ 550] 375[ 550] 383[ 550 550] 387[ 550 550] 591[ 550] 613[ 550] 617[ 550 550 550 550] 688[ 550] 691[ 550 550] ] endobj 395 0 obj [ 550 0 0 0 0 0 0 0 550 550 0 0 550 550 550 550 550 0 550 550 550 550 0 0 0 0 550 550 550 550 550 550 0 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 0 550 550 550 550 550 550 550 0 0 550 0 550 0 550 0 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 0 550 550 550 550 550 550 550 550 550] endobj 396 0 obj [ 250 0 0 0 0 0 0 0 0 0 0 0 0 0 260 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 479 0 469 552 469 302 0 552 281 0 0 260 844 552 521 0 0 0 417 313 552 458 708] endobj 397 0 obj <> stream x}{@\չ{sdx o CC aH H hHjUJ>fhm6VOXmmV9QTo=z[ 354oϷzo}k3W%GvKGemծ'..;/bޟX7=}|;-[Puoڻw\ bX^xs_o@kۦC7ms囹5Oa߷ Zsބ ;F¶%{v^6̳w_'fwC܍ۘv+pؼ|^qp}a o\Nܳy۰2A+j˖{٠~xX9]xq;1/CS^REt^JQxxt/C`A`gDH^-P%04·̯zyˊudͼN'^g9E]evB >2%yW>W)NB uxM b^|n|2^\OR#|?j3RHAKd(z+%~j&XN2§É|@x@G>D24Bhf.IRR(DhMKIt,,KEiKpc9(qn7q2]ae LfaSHJR27相pSDs R#7Yd6j*sS)npQ+a/%y$ sS%W\͆pA$Ź^ sdi )\)$J2& HLQwijb)]IM).MD6M1M!gB W N#3s$:rSEY"MN!$LSHJaHps_⦨9PܔHt^b)=0굟$:79s3ٮ)&$sskxnP)8Pou*$:/*E]S )\)Fp71N)ss3dnJW)\{ܜ^$:%(JX7肂W+=XMsj<6272ٮ)x^m$:5jhq$**gB Wt)HTj#NI#EDWDIlO!++ 1tn'iA*@/birZZfCS搙aCnye$IsSLsSf 'gvv>y$@[X^VZR\TX,pgeij1Nj*Bxeh@AeĘlwSS|EE~Wqmnw*cB=^&ޮƖbK;g-, n댉:ّS# Qn[gwУav|9:z+6s~j|F‚ȪLl;|K~U'J)LQ.(17/3ǡŖƯ+ "A`Ak'Vcgfʣ|D6Eldeg!Tƨ9eb]Nrxh|BbBV2۪b)ɛ8}®S mݑ3zGh83;1;ܣ"pG}vGhLF_cvGVtG{.N C}'b^UqB;3;IO }i v3QZJI1\n.̅P G69_|ozq6G O⥄BQ Tv:gy:vi1ǸcB]&v$kqs\(%(b!Bx$=MݏIRsRx' c`AQFPPQ8,|(S(QiN'1J╼ ,J:|\J+JJ eE%k)kЂFWbӑY|Y؀cQ^EyeE j+´G^:B;7;+C{:L=Np e exDy? l@UN]Ɂk}Tq_}sʆ~uvg;] cS x|d!w[`Ws嶮BEƻbQtB ȃ08v'D3H[A_"ؘ,+k( '(Oy=q| N[QnF9e/A(r{ 'ny]"8%}`o"LD9$s"0&C"']"P>rS(1(GO=@}z5;_RzG@4"6rJE&s{q(|n[8܍}x܏p Ni) u<|!G$_$ {,Z*H>u#u7eAQ<^?4N]t]Hw;8B/ҿ/AF-$("su l3maG`ȩ4.2e]{rO |3p~zn~?!? ? ~Qj-΄?<6[A"M`lRDptDo"VqgȌ-0]># )GR< P|uu\ZRy2u EO%ŸLbGg@Ne`2TpT§@\C#\Ǡ(!O?2Cfy31u@Ptxz8P|D(Bp@9 +/3< ;+ 0%r*|ZjBF}ӫXn7/ll5hq(.-!Mc :T]1se S[^Ҷ/9gSig:Ϻf>;ݶ)S,OY)![yY܈e:b8FFG2F#̑ZPOw5n-zPS@Wvx`v_xAV4ï܇llɍ(Y-ю@t$j*BuTPzML?OE7i8Pkw 8w5u"]! Ǥc/g5&$o gvH $;2d%ld9\tN继Hu@7I3o;1'ݢ) ["YTXԐH,3,{R(t98)o%!w_B95WΚllɠ,r!11ZK,fLț̃ "䳲YgX9>q-Q#TDYypYRi)#H(`Z[ҨsW3CaZؼ@F/jZAÃ8~mzPb',G",>kUAdT:/yodّY`I+w:.<,[aMZ~+> ^f^EnD\L&"aI)dɴmFgKg6r}-)Ћ6!u?seuU3tfLOҫ[Z y=b,|L^WY6i6;W \M%M&iCvuzwVBmf|~E`yb Km Fe8îpII! cY]k` oZ't7z1w˶xGPCk^ʋtGN 2=$!eddf5-MsYPդ#MLΉ+l ʤAB%أ!h:?^q2 ixv,"E+ mۘ^פ44 Ӷh|.u`Ǒֽ4e+ J3.̪̩?lnղkd6risn)0'oWyUEag+~-,V Ђ̾GP_GԯЁXrv=Gx=+7i"`1QL3 Cawv4vg7ZwML:+*MZkߵhdw;I'yAclVB,[LZ}a_zٶ# 4)|aNYPd E9%J65Z|D92RSf+rE7F4;>{} =4'fM{v2TTܯd\][FW֚Lq$J>g30=z(ϷK$v&nwc s7T|nZ:G \N<]x7x$'fVN%;"JK\n7#SV ̜+۱à~yAi:+ΫoPF$/- ҽÝ6P^x'Lr;N郡A7zݺ8dL',4f<:q6'8g4mw2^j =fCE4/Lx>Nl-ynd/"'Z'l |[[Kh)FlvGCj *vhBYmOmARXK!u/x0ƹj)fw쎍 erIdLGv=^@֬YU136UWVsfEъLE[ՂF3.=9U*l%cShpQl>++b?xi(>Thov'lջ\v 0C.2@}W^nes`2uhœf4Ikf,v-so|e1|G +zYƓK$O ]q>.ĥ*>@N]<,M_Gd25v4wtfH%䵊3ec&Y* fz{b"81" NL%F$UKG).57ς)rBX=*[6DXZ2Vb,`ڢfB'%X;KKF.llV6TOpRoVrڽ(WA\pD&~`(#E $ Nvu|&cd+(BOh nv@Y`.}[$ w[U#b:/aU* \ʊ"Gp4dN|:,lO獳\$r%:q3Ҁ,RRM+\NƋH>/VfͶJ$JEr%Ң"e_E޷5/VT.,+W\ǓQaϢduZO9,@Aؾ!1%0Gژee 2+x{u[8-[_\}5R' ZUP~y_IOQ]W*j">!I a壂ԠQAa^d9a6QW ..R&iMQi dHAM Hq.wjжmoZox =Tlu`_c#&m'`@/+&6NynƙFFH `WaelE=|@[ar>)-!Y^;XS_X47LE &REk#:o1rf JB.|p(^‡/[sR+U3k7BMM`ߠ4xG 8 sRJp%銈e|̸^`ѱ.\V[R'p zxQr w'G*!}T8H1[Z7}>-Lx,i lB!Mm 8q`G`ga_ ;S[fq<=j]ff k ''6$v$TajˏH~a1 %d) U_gK>>|YY` EQK8k@erP&xRWZ>k_>^AeQ~) 0ˁћ0Ⱦ{>?^D;^8M Is|7 >7~ E ⿈makZ l75٦8 zj(nkOi27ԴF:,S|< 鵵Tdm6Z- M:{el0Mf4`~xklU5:s :bkvXuzCaש-Mfa7?aRjmj Q fՌ5O013`pV;\ KCUV!Y7ǃ%b/ׁm kG=nj0`UMZ5kQ?v2+#Ȏf`P τŃÄ1P4X-8 nFwVpk+&|f-Xf5Pig|wh06c[VMhD/;͊^u23S4fP@?QÇ)2GګQ;+p#ky;[W73-M gR?U3o%@z5=>:[^ p]~+#5 u=^ P F *+gf3z-`}Z6D#f42Ag@ZZY0#~ 1NF!0r+GsiF gq)C٫E{$ 4-ǂe6p_t z4OU諒vn*a(>J$c4'vH9fSŀt_~ pMHkQݶJX8h霵hN[٘f$yf g-e2rMER:Ͷ Š@c43C[!= p ~Da-[fuFS.҃p1 / GYjuFpv:oVt׌Mb䁮kezQW'f8eOO(y,@& 1 -X6Gb* }`lG5-Wc@OlLX[!ku08"! Xv4Afu/HGfs%~hk0/Z4bX z1͈YU3kn`d  HkCk7 [z~+= x e`0*G؂8M`v^S→4Esp aoE};gSo g(*kAZEvY}gNB]meVc@ǜ=48 :r>^WKp(L=(A =q ZA,B6s8&ԈE?a-ƣ,fc5vZz(f&_03[ +[%,3G's2H&JMZJ[jK;SU Cguφm 5X飙npc<bCf?m@VYb(~53D[nz47=ѹm[2= #1hxH 7ĵhFh^51ZGsi*4'LX;a\BmAN*`?fdZY)brWgdB++⏓M5{=#V2G(Y;2`,Hi'$th ɯr lh4}1#I `?~?|ʃ!;XnK`i/'((E ѡ FA<$SD2!42#A:q jfPّ\g[r~ CkBpgߩN~8-@}qs!.ˍQf xg, 'PAX:F!dGz 5(נHO+v.} ϯ\N>a[,ivv٧2n^l@܅H(X&7 FL3MYӹ?>ȶ'՟%d#%+{Wnzj0u0kw-z?)YV{lS@A7?x3{BKSߌ{wǁ?"z!%tqRG:Y=_ ɠlĕ ?D3TG*n:'5Ra7(,6JQs泚y-Z]ߗj,NW|%v`agݺ%^Ͽ9gZ-9cI'ӱv- &};v0gDɥ;օ__Sѽ/TLeNvgپޏ&Nμ! KN•)an]ܔ7'c,v~=.׵V_m+ƼtW+Nj^ rv%cT=5' iW4F%Ss*)WII#ie nnSFGssXh g?Qk \ __ݭ]{M}EVR?;tդU3[xыG_X2Eu҉=pF ]7Z[{^9L?uyEe{͋u=[[t9_Sl(>1{yg.'~lmYJsĻmwz8Ο'}aJcǣsTIY_òO.\)љZmME{v[eRȩ_ >ruGz{oQ_i &%-Mٴ#hpP eXClv2M &ʝDj/ʓ^&ׁ"aHoq؛l6hc)bA""MEY{kx@zk7=7KG{>viGYڮmn=T˫/Z=zi>'I_I?}lOXʕ5+>M^EAJܲM>:<ɞ%͝3L>Ҋĕ&rτ^H~J9yۺZ[ueEYOw$\)~`ݗ[]?Z.lݓ'&Rұ?8Q=w:/nXڻȜ/5MH:Ώuvc+;؍ܵP/qrJjO~53z>\_ߑqd~'ԍWw'nLE)g,:pcQbbb[o]ꡏ^=҆{z\m~4㜬0G $/]~uo{:Q>#{SoԊG{/~3 K?׳5c|05`Q;@y?޵o~tj{b:]1zno7'?(wW%Xgfq/pZеeǺU8י`pŨ}WȎL[ O `QCްAAC0\GH8EV 2({4#LӇ6bEH Qb`xК5!kvjI!/A #u>7=ݭw<}~+YWOGS+G4O&d//~$Jsȇt[^>yj.Zu'/-KɏJb_3N>a&xSKVP-9櫢FjNtMxeGדlY qV`g;blfLZQy+WQ׿U}pN.b-Ż>L:2݊}sN`JZ79n'< :Q;X8*'w)$*s]H5 [k{^,uQE<)SB#Xlq[>zrO cwݱ{kew 㞈x;['8/|ӣy7?;n\U$ˣ };n^)>yK"K]㞐ε]O?6ig#l ů䟵\N[r3>BwkӰ՛}[=Y݀E |gnކ5WoҼ!g_ /Tcɞ/dV5߮sĩgߦ6揸GTq0fcv6fˬѮJ[3QTtt) Y?`  R?dL9Oº;'-Yqg7 ouKz_8HNWꥣ'3XfK>|ԉy=ĵœGZdsj}'׭>3rI#Qe|v}uxŰ 9Mxc;֌OY3!d92^_{xՙ+~Mǟ]`ݦLn}Ftq:;~2z骿?,n͸q>GY[,/޽s橨E%_%w|o=z[ŏ.KFxH̀A\biڢ1?LyCl&!管1%Yx>2ӿ *JNN?(si6564--Uf#T(̦y܈/#OI]|-ث=眸=nwֿ ?'͟Lcv_.^{}S >ca33]ȳ [N@L?ߴ,Q\y$;$9Y[ƽOC_ t<{I%Wh6Uh?<ˍ/O V3.>2e/'m"YUJ?<}Og,m,={+4sBOGx42Vć(1lb ,3124n2EJqz^@^j03A#49 yGNG eE Y f4[5{)R(Jɠ I aA;<SK5@Szyy9ZJ//ZGo412x\_vzթm56tkxb : 7]e- "]Q=ߣ|LhŽG|uՕt[o)0CկUo Z%0G1xõutu[l~7▟&/* ƙn7ݗ?5[/oxb%}GVny#ϩ|cyݡϽ<2|%Vg)WD;tHDgݕ &߈c3lb|zJ42 qYi 2$a5V&@hdh y$("q̍Ss9>=a!$ы/쓂Ú`~T8xųuR6tǞvfMW&$:љSFeuo_qcR"$xC͈y1w{ ?f]K"97)?:q?peȭ5@ͅ:/;u|Puff<߿ʆ>rg':ݢ0o%*G>0\u[BGK=[*Von"w2C6.J]sLf+Uz k| endstream endobj 398 0 obj [ 292 0 0 0 229 0 521 219 0 0 0 0 0 0 0 0 0 0 0 0 333] endobj 399 0 obj <> stream x} xŹ;~e7ɷ\7.Iȍlph&\!ޠh"UV[Eֺ,^J崧K}-sjkd}(p?dwfyg;% `7 m-[/p9fofft@5= @,]3Xx%V-JKV|QTS $^`+ Jl7,_sm߾W`֊޵*n 9X{LG(M|/}+^.N6a0ai=} (Zӿoz`S*fn>/Y/>板haHC~V=x= ي=NK=Z+ٕ gS*KJY_gf< X,{IV2@Ֆu6d8Ppḃc19 }D(,0(ܦgΞ5[ܔ3o mrJmb ElLr3Fvܼȧqn*$&^CD'' a4$+$q3N$7_#7 9W!$.h@Fqyؓbenf0l&#i"4%8)Lny`N,VJ<@s7'*$pXL%X%ёmI|Mp,H$"Xxȃ.iI9W!$.@&q""X(>8)''p; ybDGB-(ꦺȇXlGl7rqI\,\/_#7"P n'Eo&ė@i~..r|h6Hej4ĄpHTq^CD&;5R 1O3N I$qˊpէ~e.Y<`sqI\r\ ◯QX.9g S%񯍶j" %BCbq㤜rD`ьF\,`(f$gJϋqRN`9N" ;9[ޗ1/87 $by%L 0R8m_|R!;>&7Oi!5[- }f`aHoˀ VkQ&LE$_D_V(/+). rs2} [LOKu9Svb6 zVV)ϱ %mvlwڴ)AA9EMݲ|j]i>$wTOQ9𘜞),9Ōǃ5܍ 0v7^1݀STOƤS&>TMmjGA^{- a&7ރQH/t*}p3N4|g5J}WLLEڠ<[zm<0DB|H>  (͉]ˤ;.JqlGBelȈxuH`!} aWb~G%8.EB[1k1>(45$mtlroV&[Q:@OPSp\q]ǵW.;( ՋtJdh6FFMbbq*iQ1ry&li#C1zXOt d7"+僚P3ljS#MDzTfbFnx/sOn%2W!TGf%ZR~6QT[m ),"H2Vݶ:gO X-l۩GGQ|]폝W鮈t≡<7=-gd&Vz. vVݿg)5HtqSm7r%ψ`S YjF_dm툸ffԁ:~^2#,ž<l<$aC=О [h`¥1H;waDeEbw8]/`!HXH߀ѮHFmmd%#c(;ьHXH FaN )23$Z,"*f狑Qڱm_\S۳mDsؾ}6cxw[ŭ1ȈxU(YmU@uuvY!I$4D{A~T~ #?F #FF6 #FF"adSd(܊tE©p(l ¤0(t BP(x 5|d).q?m0#aS+ίsfՅF [9 r;nY(I]r8y{G7 Hk߈(w >% Fk* #ˆ00Wp׵ץuD45ns/j?@O Rԁ}'B9n壸A>S{j6]V#雨+#%5@uXkt[3(&2HփzT{m$=\93$} ;%}N/XXe_ox+tʗ$[Qg>ik4yok*\;C>757w4%5C5" _^5Zi\VkߧEx?U.OG0P-Y y裩W{렦7T (%iO8ntd%ikPJE,E:/r8:HPlI^\ +Wœ1 ´qE؍mG{"c.#.6W}r+Ad]9~_q?ô?u_7ƒыj֋}zZs10O(3|',E(Ë}ˀL(-0 1As ߤ=4}*ȃW/z"!x{nBL06klxl)`'0{n1σ>n'jP:q% c^^zT+JXu;</䛴bo%(0^&x4~}^l) eP=&* ߄a<Oau(}itIxWixЌm{5܌v>iU|gdah!̘Zf53ʥpkƻ=+?LЀ= pjMpl?<?W^}gI#B,2M4VEe!O`{FIv4jnY"[>\hu7d اzhc>y҅} dzdMhrh]G|!)!%w~Ļ9=ixЃPHx?+* aG&09L^@g~G|D>#HSefh N6z)]NW~433f!95{\76qwqۏa|K㿋M;F_ yC Z m$Yh ,> q48#@k](v]9CG!HĝDUʴ=%^2}~~~~~5|CEUwVvnu6 پY7|뮜w=~+A/dl@9IӠF[6?ex-nYu-n]i䒙r|á7!{2 Kpfb}FU[́5go6o~•y+[PE(BK։|w~}L{B1aZOZtzq&~ZOvwlO4`c [\ > O`Pu BF^1[A/SܤCqOoQb~I}Iz~zÇ?)~b`ikW "Q 5oU֩1jz85?* 洇Ro޼3Xf f66]?hY~0sǖ-p`&dصcˮ EK3C3c+Wo \InxSCUW 94] (QtrIV6'٥Ŷ"M "φjRf 2#&L$ii.z3btbiR^HH6)$Y1bE-BdZc;u)upf'Q4%m9UUFFT 4??wY}aR0) x! 2MR.*uVVpjfhUZcn@wUZ,V)SRkMQpjڼJgC_a8Ww,ª݄XE4+pp|JþCKhV^_jhdh}a?!nRj3)FSyc 9P5Jp9L)k'[6 R_5j+eݶ"&R]~7Webєbf Dkk&ϓyMMAVLE#f^{}V ; `MZXɨ5vpM. Z1?L(# 妚L]\Sٵm(CmԡSyx~i4+QrzGR9cm],wg.;Jtʹ݆RwiPJJ;`m˳^ة3*jƤ p}H3Mz\0U<'N @`YQ )lG\.-g]bViӒ$sEh]OtXphԌIKd ܃fv\Ewmq|gBGm %Wg3fN44Ϟ9)͜9UmΚ4Ӧ[?ݐ9Qΰ2ʅ] Js:>XRT=0G.Ϋ.[R*dĩ5lOKo<wVpJ[J+J̚刅X* }@mU^i)/TYd0Q6b !mnDU^I|L9?JL!YrݐH-t(S[] tu}9T!ttqHj[bY* )+pD6X/#n 󳭪 rv{j9ujQP[=iJIQ޲12)&o@jiҐrUY%AtUnsl3`e9r] u5vحEbCa%0t(:ζp}h7U'^hUvդw8{@U`jSSU3& B8#vɸҩTqɬƺZzT5̲\rɬ.R.9/t8FV-5 3,YosK,( x;ZT' =S^#uk=(g=8Κƚχt0Pw$1W1iѪ:5v4 $Kf{El]{ קb\ 41QR1g'-"mm5,˻cE7T./t%[jj3_4ui93Jѻ,rk"* "i\tQ?U*Tw4xAi?E^Fy 4aqC4XFvx]ތ*Oθ$Pf}MH{V)QmQk ]Ue IzTgtJ]K~eRɛ%-vI _.PzAݟL))>t8l&JVYkVۄ1h3L<BۢƻMߴkV.ĸU_/cn}a߾ұ6wmiiC=F]hh0֛f[--yMet Ǵ 0ڌFia-*+`s&ҋX++*0ʊ,eeE"W=1(`?DTd_H@6w.6!Bt:Nӧ]-bEH̪ <4IkƆ 8_(nnlR$kMw-F;x\~uDOKL8b3RpvJ6XBym)sS9KXis4Kh Spz:eW/kB7ne?-vhS39wJnǞV4Ogzs%q*MW؏7Ϙ" BiL)TP7mU"TbTjV:)n3QǺtKk%sGm5:oԺb+9Uw{hOecMJѥ?yѡSEK^"0JLM$9X[BA1q2$C2$Q.8aY0-S|_fϽz}ߧ;@3ogx8O3DX=9<O(}<-@?|*5`;:rM<͂,Ӝ,'4/=$,=rZiIVӒ=9ěix i+9p<+'Su5t4^+"Rn(RĂ)JQT Zb@E@l. `YDtEPU}]T;"e{{~$wwD%R$Kii>-h&SmYR=і#EJmy2 `5\d|% 誄hL.JDF2TöK6JDWmH/$}#l\Ujp|5muHo#0>}DQ :x = k~'&kL%ڀ1 EDfp gcm)1?KYJL)1ˉv[Nf1&C@8$;"Rxq8$. Or"x nd))`"t{{1Gbb8X|/41b9qRG`bh>2HvX$HBBYi/`v8$05*3a6'oɬ_ .`İx|04FE]fxXG+Aw,8məf}h4O&~|9b)CFQJaj,#@* raFHa`c"!yA>2@ PaF`r`\=d^tѲ!"ƛXtp>1X8.8KD@a?D6- \CLL(U}1ȧ}\l,rüi F{C6{̡ݢ`&>{>W̒8Y|s<\Phc<5C'Mo|Wl]9@\ȂQł3îEיMXKH>'l *$AKP2bq2ԯt!P*5u&W<"5 3lo3puQ |mBhEA Y` 7㓖qeܱq ,`˜ v`lv8}ufÕ|bH r~xyA?ITSoÉ#xD+1/lf'PG$""$OLaׇ,sOZ,b嘈uĽ[ 0JbAP aD5J܉kۃEC?Nj*[P!؂J\QXA9LeaK-8/־lv鱈du|B``ı  ؉ta/>A줘M$q3zx߇bْL񉸊$ ߳9~0bX3<avB;G,s=˅͇0~P->Pe YK8rcsMc3KHj`lנaĆ,"Zl1Zr >A}#&^M*Q >`;̂{?1 4S8 50 bQFaE!~W,ypz,)@2&@<*؃B? ub,QA -Ľ8bÀ6c\B2xqo%CG9(GI_='Ū呟t&ux ßMs͠9h#r),{?`ǣm1YUrg-WRs,\L\M%ֳLCBzݛC2WBMK>tP(9烗_ 5N8vfHQ)eY+)T-hzj-)"VBbL3AQ#=JԌ0><nƉB&ѤPIpIF39vd2%bmNJx8;Q0RPT)T#*b9Jhi 2j9@3X jz:#ق\tk'm8Lp|݂6 Kt|_ o.h4 U8vf]Vٓ'Hl6y`w ww5/ifZŮ懁}/~EnmnMѱq>4II&dkZJH/)HHf MGN<P j-X͔<9ĭVdjMũ5g Ì:LQSo>ߒL|0 IUtb[:rSmJ՛V:\$1eh9Sze;OӧW$'-:ѦcqDG[/^ 9J<}^ܾoOS2ysOR9`&3ZFksj!F n',c_ڌ9QtL;qR'ZѤY]8k>HHZ蘭|ca/f{+mYC_M~D`xx>'\8sx\s>V1LqDrxlA(VimLKuGs%zcC&\vuA;N +RO՞}әkSigݜeݒ'* q=ӶyRSj沔Ys`麖M42r63Z6]iem0'ii%l#^mNԱse©IgV\6MEpKbteKSDxW%/>/){JW:Vw~']FYOyI[Rav :=`V Cې-PKƞn  :nQ?bO*,඀羡?e OE-޹Fgf"];s/QϞSMOvnG[V~*۶zHlag]UuвOW ye̳nR[I5cZ>=ME;[S('~V3&˃3zxC6ua-c1F'Yg5,[0?5(Sȹur6Ů=Չ8WFc,gFU9=xaA<8395Lm6]q;QӆE=8dΨ:]8U8%^+h6F80K,e9yݳ<1}$r܇$l_V㯼ӝܾn^|p̌~W6KX?ˡ':Mr9ZyYsP*o]{ݏ*ݦtda\eS~rVvV#g]jQ퉪S%*͊y3mMvmj|'߬>R#vao>@KTgVIK\JU3*ye)oTh=t>}|`K w vzd0˗3hE!( = ߣ[ >*c#Tn,]UCLA?J59uܻ(i[M"GqBƿx{ӌhOLLidReDG/<~/s^Nnoa>۞^3aYfuus^*nh!g]CF^)б6&1oɱрw  o` iNwlZT]l %s-yvMϥGod-җY燏Ei M/Kx>X{-=\~`CJ7 CVo޷esCOkXoߔyG÷nת|zr/C940^Rߓ Փg_,#< q(; a]leI[48hu]Ecqr9 ;KJJe.H$_77DJ]ŗ5L4}nŪ{Ȕp\@ێY^xyʊV+av&Q:\+YT'E.T;[O|kġ0U]~lI觊Um6~T;Ҕ#HimޙRBv%Bυ9Gʭ?^:ް跬~)csB[s˺4SZ>#a5!//ݴ`e͋!U- endstream endobj 400 0 obj <<6DA3DBE4BBFA9240911AA4DB9B42A4B8>] /Filter/FlateDecode/Length 898>> stream x5w|W{or]ƈ B4VHBYmIHlޫH"AjjTPR{MchFbG~n?99s~g8͎d0epOŢEH#JD3 =» (D /ʆ`rS Kg"ˢ 3Qy8^5RT E )"`7Q}08D͉)B/("ODѼqB6068+)% f³^[w?XZb;1rHq'AKrf-aH"{)0:N1/.~W7 3Wf3h1KAŅ+g+X0y$BEC( J@q/( JC( #P*B%UA(@u5ԁZPBch4phM)' g> 1 Z@v:@G t/K tzAo}0`Ca| aH$ɐ·F 0&d` L- i0 ́a̅`>?o`1, X`%հalͰ `7쁽bQH_.28mcۉ8vspѴvKªZB&dz^g endstream endobj xref 0 401 0000000102 65535 f 0000000017 00000 n 0000000142 00000 n 0000000240 00000 n 0000000664 00000 n 0000004515 00000 n 0000004684 00000 n 0000004924 00000 n 0000005102 00000 n 0000005351 00000 n 0000005525 00000 n 0000005771 00000 n 0000005947 00000 n 0000006194 00000 n 0000006360 00000 n 0000006590 00000 n 0000006762 00000 n 0000007004 00000 n 0000007129 00000 n 0000007159 00000 n 0000007312 00000 n 0000007386 00000 n 0000007617 00000 n 0000007778 00000 n 0000008003 00000 n 0000008137 00000 n 0000008167 00000 n 0000008329 00000 n 0000008403 00000 n 0000008645 00000 n 0000008774 00000 n 0000008904 00000 n 0000009308 00000 n 0000009438 00000 n 0000009839 00000 n 0000009969 00000 n 0000010099 00000 n 0000010228 00000 n 0000010357 00000 n 0000010488 00000 n 0000010904 00000 n 0000011077 00000 n 0000011318 00000 n 0000011449 00000 n 0000011580 00000 n 0000011915 00000 n 0000012046 00000 n 0000012397 00000 n 0000012528 00000 n 0000012866 00000 n 0000012999 00000 n 0000013029 00000 n 0000013190 00000 n 0000013264 00000 n 0000013505 00000 n 0000017342 00000 n 0000017396 00000 n 0000017450 00000 n 0000017628 00000 n 0000017874 00000 n 0000018041 00000 n 0000019035 00000 n 0000021076 00000 n 0000022008 00000 n 0000060658 00000 n 0000061515 00000 n 0000061946 00000 n 0000066605 00000 n 0000066744 00000 n 0000066774 00000 n 0000066941 00000 n 0000067015 00000 n 0000067261 00000 n 0000067393 00000 n 0000071693 00000 n 0000071871 00000 n 0000072118 00000 n 0000072299 00000 n 0000072550 00000 n 0000072680 00000 n 0000151582 00000 n 0000156356 00000 n 0000160510 00000 n 0000161709 00000 n 0000161847 00000 n 0000161877 00000 n 0000162043 00000 n 0000162117 00000 n 0000162364 00000 n 0000162574 00000 n 0000162638 00000 n 0000162743 00000 n 0000162862 00000 n 0000163011 00000 n 0000163150 00000 n 0000163268 00000 n 0000163404 00000 n 0000163535 00000 n 0000163713 00000 n 0000163839 00000 n 0000164006 00000 n 0000164129 00000 n 0000000103 65535 f 0000000104 65535 f 0000000105 65535 f 0000000106 65535 f 0000000107 65535 f 0000000108 65535 f 0000000109 65535 f 0000000110 65535 f 0000000111 65535 f 0000000112 65535 f 0000000113 65535 f 0000000114 65535 f 0000000115 65535 f 0000000116 65535 f 0000000117 65535 f 0000000118 65535 f 0000000119 65535 f 0000000120 65535 f 0000000121 65535 f 0000000122 65535 f 0000000123 65535 f 0000000124 65535 f 0000000125 65535 f 0000000126 65535 f 0000000127 65535 f 0000000128 65535 f 0000000129 65535 f 0000000130 65535 f 0000000131 65535 f 0000000132 65535 f 0000000133 65535 f 0000000134 65535 f 0000000135 65535 f 0000000136 65535 f 0000000137 65535 f 0000000138 65535 f 0000000139 65535 f 0000000140 65535 f 0000000141 65535 f 0000000142 65535 f 0000000143 65535 f 0000000144 65535 f 0000000145 65535 f 0000000146 65535 f 0000000147 65535 f 0000000148 65535 f 0000000149 65535 f 0000000150 65535 f 0000000151 65535 f 0000000152 65535 f 0000000153 65535 f 0000000154 65535 f 0000000155 65535 f 0000000156 65535 f 0000000157 65535 f 0000000158 65535 f 0000000159 65535 f 0000000160 65535 f 0000000161 65535 f 0000000162 65535 f 0000000163 65535 f 0000000164 65535 f 0000000165 65535 f 0000000166 65535 f 0000000167 65535 f 0000000168 65535 f 0000000169 65535 f 0000000170 65535 f 0000000171 65535 f 0000000172 65535 f 0000000173 65535 f 0000000174 65535 f 0000000175 65535 f 0000000176 65535 f 0000000177 65535 f 0000000178 65535 f 0000000179 65535 f 0000000180 65535 f 0000000181 65535 f 0000000182 65535 f 0000000183 65535 f 0000000184 65535 f 0000000185 65535 f 0000000186 65535 f 0000000187 65535 f 0000000188 65535 f 0000000189 65535 f 0000000190 65535 f 0000000191 65535 f 0000000192 65535 f 0000000193 65535 f 0000000194 65535 f 0000000195 65535 f 0000000196 65535 f 0000000197 65535 f 0000000198 65535 f 0000000199 65535 f 0000000200 65535 f 0000000201 65535 f 0000000202 65535 f 0000000203 65535 f 0000000204 65535 f 0000000205 65535 f 0000000206 65535 f 0000000207 65535 f 0000000208 65535 f 0000000209 65535 f 0000000210 65535 f 0000000211 65535 f 0000000212 65535 f 0000000213 65535 f 0000000214 65535 f 0000000215 65535 f 0000000216 65535 f 0000000217 65535 f 0000000218 65535 f 0000000219 65535 f 0000000220 65535 f 0000000221 65535 f 0000000222 65535 f 0000000223 65535 f 0000000224 65535 f 0000000225 65535 f 0000000226 65535 f 0000000227 65535 f 0000000228 65535 f 0000000229 65535 f 0000000230 65535 f 0000000231 65535 f 0000000232 65535 f 0000000233 65535 f 0000000234 65535 f 0000000235 65535 f 0000000236 65535 f 0000000237 65535 f 0000000238 65535 f 0000000239 65535 f 0000000240 65535 f 0000000241 65535 f 0000000242 65535 f 0000000243 65535 f 0000000244 65535 f 0000000245 65535 f 0000000246 65535 f 0000000247 65535 f 0000000248 65535 f 0000000249 65535 f 0000000250 65535 f 0000000251 65535 f 0000000252 65535 f 0000000253 65535 f 0000000254 65535 f 0000000255 65535 f 0000000256 65535 f 0000000257 65535 f 0000000258 65535 f 0000000259 65535 f 0000000260 65535 f 0000000261 65535 f 0000000262 65535 f 0000000263 65535 f 0000000264 65535 f 0000000265 65535 f 0000000266 65535 f 0000000267 65535 f 0000000268 65535 f 0000000269 65535 f 0000000270 65535 f 0000000271 65535 f 0000000272 65535 f 0000000273 65535 f 0000000274 65535 f 0000000275 65535 f 0000000276 65535 f 0000000277 65535 f 0000000278 65535 f 0000000279 65535 f 0000000280 65535 f 0000000281 65535 f 0000000282 65535 f 0000000283 65535 f 0000000284 65535 f 0000000285 65535 f 0000000286 65535 f 0000000287 65535 f 0000000288 65535 f 0000000289 65535 f 0000000290 65535 f 0000000291 65535 f 0000000292 65535 f 0000000293 65535 f 0000000294 65535 f 0000000295 65535 f 0000000296 65535 f 0000000297 65535 f 0000000298 65535 f 0000000299 65535 f 0000000300 65535 f 0000000301 65535 f 0000000302 65535 f 0000000303 65535 f 0000000304 65535 f 0000000305 65535 f 0000000306 65535 f 0000000307 65535 f 0000000308 65535 f 0000000309 65535 f 0000000310 65535 f 0000000311 65535 f 0000000312 65535 f 0000000313 65535 f 0000000314 65535 f 0000000315 65535 f 0000000316 65535 f 0000000317 65535 f 0000000318 65535 f 0000000319 65535 f 0000000320 65535 f 0000000321 65535 f 0000000322 65535 f 0000000323 65535 f 0000000324 65535 f 0000000325 65535 f 0000000326 65535 f 0000000327 65535 f 0000000328 65535 f 0000000329 65535 f 0000000330 65535 f 0000000331 65535 f 0000000332 65535 f 0000000333 65535 f 0000000334 65535 f 0000000335 65535 f 0000000336 65535 f 0000000337 65535 f 0000000338 65535 f 0000000339 65535 f 0000000340 65535 f 0000000341 65535 f 0000000342 65535 f 0000000343 65535 f 0000000344 65535 f 0000000345 65535 f 0000000346 65535 f 0000000347 65535 f 0000000348 65535 f 0000000349 65535 f 0000000350 65535 f 0000000351 65535 f 0000000352 65535 f 0000000353 65535 f 0000000354 65535 f 0000000355 65535 f 0000000356 65535 f 0000000357 65535 f 0000000358 65535 f 0000000359 65535 f 0000000360 65535 f 0000000361 65535 f 0000000362 65535 f 0000000363 65535 f 0000000364 65535 f 0000000365 65535 f 0000000366 65535 f 0000000367 65535 f 0000000000 65535 f 0000168048 00000 n 0000168253 00000 n 0000168770 00000 n 0000260363 00000 n 0000260920 00000 n 0000261232 00000 n 0000261602 00000 n 0000276805 00000 n 0000276985 00000 n 0000358650 00000 n 0000359045 00000 n 0000464617 00000 n 0000464943 00000 n 0000465245 00000 n 0000465273 00000 n 0000465717 00000 n 0000499647 00000 n 0000500020 00000 n 0000500348 00000 n 0000500649 00000 n 0000512961 00000 n 0000513005 00000 n 0000513033 00000 n 0000513263 00000 n 0000545879 00000 n 0000546197 00000 n 0000590288 00000 n 0000590725 00000 n 0000591069 00000 n 0000591305 00000 n 0000611064 00000 n 0000611140 00000 n 0000627009 00000 n trailer <<6DA3DBE4BBFA9240911AA4DB9B42A4B8>] >> startxref 628111 %%EOF xref 0 0 trailer <<6DA3DBE4BBFA9240911AA4DB9B42A4B8>] /Prev 628111/XRefStm 627009>> startxref 636292 %%EOFepubcheck-4.0.2/pom.xml0000644000175000017500000005530113017276730014277 0ustar eugeneeugene 4.0.0 org.sonatype.oss oss-parent 7 org.idpf epubcheck 4.0.2 jar EpubCheck :: Validation Tool for EPUB EpubCheck is a tool to validate IDPF EPUB files. It can detect many types of errors in EPUB. OCF container structure, OPF and OPS mark-up, and internal reference consistency are checked. EpubCheck can be run as a standalone command-line tool, installed as a Java server-side web application or used as a Java library. http://code.google.com/p/epubcheck/ 2007 International Digital Publishing Forum http://www.idpf.org/ New BSD License http://www.opensource.org/licenses/bsd-license.php Peter Sorotokin sorotokin sorotokin@gmail.com http://www.adobe.com Adobe Systems Inc. Garth Conboy garthconboy garth@google.com Markus Gylling markus.gylling markus.gylling@gmail.com Piotr Kula PiotrFKula PiotrFKula@gmail.com Paul Norton cold.geek cold.geek@gmail.com Liza Daly liza31337 liza31337@gmail.com Jessica Hekman sorotokin sorotokin@gmail.com George Bina georgebina76 georgebina76@gmail.com Bogdan Iordache biordach biordach@gmail.com http://www.adobe.com Adobe Systems Inc. Ionut-Maxim Margelatu ionut.margelatu ionut.margelatu@gmail.com http://www.adobe.com Adobe Systems Inc. Romain Deltour rdeltour rdeltour@gmail.com Thomas Ledoux tledoux tledouxfr@gmail.com Tobias Fischer tofi86 tobias.carl.fischer@gmail.com Steve Antoch santoch http://www.barnesandnoble.com/ santoch6@gmail.com Arwen Pond apond http://www.barnesandnoble.com/ arwenpond@hotmail.com Masayoshi Takahashi takahashim maki@rubycolor.org Satoshi KOJIMA skoji skoji@mac.com epubcheck discussion http://groups.google.com/group/epubcheck/subscribe epubcheck+unsubscribe@googlegroups.com epubcheck@googlegroups.com https://groups.google.com/forum/#!forum/epubcheck scm:git:ssh://git@github.com:IDPF/epubcheck.git scm:git:ssh://git@github.com:IDPF/epubcheckgit https://github.com/IDPF/epubcheck v4.0.2 Github https://github.com/IDPF/epubcheck/issues 1.6 UTF-8 UTF-8 yyyy-MM-dd ${maven.build.timestamp} net.sf.saxon Saxon-HE 9.5.1-5 org.apache.commons commons-compress 1.5 org.tukaani xz org.daisy.libs jing 20120724.0.0 xml-apis xml-apis org.w3c.css sac 1.3 junit junit 4.10 test com.google.guava guava 14.0.1 com.twelvemonkeys.imageio imageio-jpeg 3.1.2 org.codehaus.jackson jackson-core-asl 1.9.12 org.codehaus.jackson jackson-mapper-asl 1.9.12 xmlunit xmlunit 1.3 test false src/tools ${project.build.directory} src/main/resources com/adobe/epubcheck/schema/30/*.sch com/thaiopensource/relaxng/pattern/resources/Messages.properties com/thaiopensource/datatype/xsd/resources/Messages.properties src/main/resources com/adobe/epubcheck/api/project.properties true org.apache.maven.plugins maven-dependency-plugin 2.6 copy package copy-dependencies ${project.build.directory}/lib false true org.apache.maven.plugins maven-compiler-plugin 2.3.2 ${java.version} ${java.version} org.apache.felix maven-bundle-plugin 2.3.7 true bundle-manifest process-classes manifest <_removeheaders>Include-Resource,Private-Package, Bnd-LastModified, Build-Jdk, Built-By org.apache.maven.plugins maven-surefire-plugin 2.12.4 -Xmx1g -Duser.language=en ${project.build.directory}/test-classes default-test test test **/message_coverage.java listener com.adobe.epubcheck.test.TestRunListener coverage-test package test **/message_coverage.java org.codehaus.mojo xml-maven-plugin 1.0 transform process-resources

src/main/resources/com/adobe/epubcheck/schema/30 *-30.sch src/main/util/sch/iso-sch-include.xsl ${project.build.directory}/generated-resources/intermediate-schema ${project.build.directory}/generated-resources/intermediate-schema *-30.sch src/main/util/sch/iso-sch-abstract.xsl ${project.build.outputDirectory}/com/adobe/epubcheck/schema/30 net.sf.saxon Saxon-HE 9.4 org.codehaus.mojo license-maven-plugin 1.3 thirdparty-licenses add-third-party runtime,compile src/main/licenses/third-party.ftl true src/main/licenses/third-party.properties false org.apache.maven.plugins maven-jar-plugin 2.4 ${project.artifactId} true true com.adobe.epubcheck.tool.Checker true lib/ ${project.build.directory}/classes/META-INF/MANIFEST.MF ${project.url} ${project.scm.developerConnection} org.apache.maven.plugins maven-javadoc-plugin 2.10.4 -Xdoclint:none org.apache.maven.plugins maven-release-plugin 2.4.2 org.apache.maven.scm maven-scm-provider-gitexe 1.8.1 v@{project.version} org.apache.maven.plugins maven-assembly-plugin 2.3 dist-assembly package single false false src/main/assembly/dist.xml src-assembly package single false src/main/assembly/src.xml org.eclipse.m2e lifecycle-mapping 1.0.0 org.codehaus.mojo xml-maven-plugin [1.0,) transform org.codehaus.mojo license-maven-plugin [1.0,) add-third-party org.apache.felix maven-bundle-plugin [2.3.7,) manifest epubcheck-4.0.2/README.md0000644000175000017500000000453513017276730014244 0ustar eugeneeugeneEpubCheck [![Release](https://img.shields.io/github/release/idpf/epubcheck.svg)](https://github.com/idpf/epubcheck/releases/latest) ========= EpubCheck is a tool to validate EPUB files. It can detect many types of errors in EPUB. OCF container structure, OPF and OPS mark-up, and internal reference consistency are checked. EpubCheck can be run as a standalone command-line tool or used as a Java library. ## Downloads Check the [releases page](https://github.com/IDPF/epubcheck/releases) to get the latest distribution. [EpubCheck 4.0.1](https://github.com/IDPF/epubcheck/releases/tag/v4.0.1) is the latest recommended version to validate both EPUB 2 and 3 files. ## Documentation Documentation on how to **use** EpubCheck, to **contribute** to the project or to **translate** messages is available on the [EpubCheck wiki](https://github.com/IDPF/epubcheck/wiki). Technical discussions are hosted on the [EpubCheck Google Group](https://groups.google.com/forum/#!forum/epubcheck) ## Credits EpubCheck is a project coordinated by [IDPF](http://idpf.org/). Most of the EpubCheck functionality comes from the schema validation tool [Jing](http://www.thaiopensource.com/relaxng/jing.html) and schemas that were developed by [IDPF](http://www.idpf.org/) and [DAISY](http://www.daisy.org/). Initial EpubCheck development was largely done at [Adobe Systems](http://www.adobe.com/). Authors and contributors to EpubCheck include: * Peter Sorotokin * Garth Conboy * Markus Gylling * Piotr Kula * Paul Norton * Jessica Hekman * Liza Daly * George Bina * Bogdan Iordache * Romain Deltour * Thomas Ledoux * Tobias Fischer * Steve Antoch * Arwen Pond * Masayoshi Takahashi * Satoshi KOJIMA ## License EpubCheck is made available under the terms of the [New BSD License](http://opensource.org/licenses/BSD-3-Clause) ---- ## Building EpubCheck [![Build Status](https://travis-ci.org/IDPF/epubcheck.svg?branch=master)](https://travis-ci.org/IDPF/epubcheck/) To build epubcheck from the sources you need Java Development Kit (JDK) 1.7 or above and [Apache Maven](http://maven.apache.org/) 2.3 or above installed. On Windows, you should build in a git bash shell (see http://github.com help) You will also need Python to be able to run the BookReporter and related tools. Build and run tests: ``` $ mvn install ``` Will copy `.*jar` files and packages to `target/` folder... epubcheck-4.0.2/src/0000755000175000017500000000000013017276730013545 5ustar eugeneeugeneepubcheck-4.0.2/src/main/0000755000175000017500000000000013017276730014471 5ustar eugeneeugeneepubcheck-4.0.2/src/main/java/0000755000175000017500000000000013017276730015412 5ustar eugeneeugeneepubcheck-4.0.2/src/main/java/org/0000755000175000017500000000000013017276730016201 5ustar eugeneeugeneepubcheck-4.0.2/src/main/java/org/idpf/0000755000175000017500000000000013017276730017123 5ustar eugeneeugeneepubcheck-4.0.2/src/main/java/org/idpf/epubcheck/0000755000175000017500000000000013017276730021054 5ustar eugeneeugeneepubcheck-4.0.2/src/main/java/org/idpf/epubcheck/util/0000755000175000017500000000000013017276730022031 5ustar eugeneeugeneepubcheck-4.0.2/src/main/java/org/idpf/epubcheck/util/saxon/0000755000175000017500000000000013017276730023161 5ustar eugeneeugeneepubcheck-4.0.2/src/main/java/org/idpf/epubcheck/util/saxon/Int64ValueSequence.java0000644000175000017500000000104713017276730027420 0ustar eugeneeugenepackage org.idpf.epubcheck.util.saxon; import net.sf.saxon.om.Item; import net.sf.saxon.om.Sequence; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.Int64Value; class Int64ValueSequence implements Sequence { private Int64Value item; public Int64ValueSequence(Int64Value item) { this.item = item; } public Item head() { return item; } @Override public SequenceIterator iterate() throws XPathException { return item.iterate(); } } epubcheck-4.0.2/src/main/java/org/idpf/epubcheck/util/saxon/ColumnNumberFunction.java0000644000175000017500000000360013017276730030137 0ustar eugeneeugenepackage org.idpf.epubcheck.util.saxon; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.lib.ExtensionFunctionCall; import net.sf.saxon.lib.ExtensionFunctionDefinition; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.Sequence; import net.sf.saxon.om.StructuredQName; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.Int64Value; import net.sf.saxon.value.SequenceType; public class ColumnNumberFunction extends ExtensionFunctionDefinition { private static final long serialVersionUID = -4202710868367933385L; public static StructuredQName QNAME = new StructuredQName("saxon", "http://saxon.sf.net/", "column-number"); @Override public StructuredQName getFunctionQName() { return QNAME; } @Override public int getMaximumNumberOfArguments() { return 1; } @Override public int getMinimumNumberOfArguments() { return 0; } @Override public SequenceType[] getArgumentTypes() { return new SequenceType[]{SequenceType.SINGLE_NODE}; } @Override public SequenceType getResultType(SequenceType[] suppliedArgumentTypes) { return SequenceType.SINGLE_INTEGER; } @Override public boolean dependsOnFocus() { return true; } @Override public boolean trustResultType() { return true; } @Override public ExtensionFunctionCall makeCallExpression() { return new ExtensionFunctionCall() { private static final long serialVersionUID = -4202710868367933385L; public Sequence call(XPathContext context, @SuppressWarnings("rawtypes") Sequence[] arguments) throws XPathException { if (context.getContextItem() instanceof NodeInfo) { return new Int64ValueSequence(new Int64Value(((NodeInfo) context.getContextItem()).getColumnNumber())); } throw new XPathException("Unexpected XPath context for saxon:column-number"); } }; } } epubcheck-4.0.2/src/main/java/org/idpf/epubcheck/util/saxon/SystemIdFunction.java0000644000175000017500000000441113017276730027273 0ustar eugeneeugenepackage org.idpf.epubcheck.util.saxon; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.lib.ExtensionFunctionCall; import net.sf.saxon.lib.ExtensionFunctionDefinition; import net.sf.saxon.om.Item; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.om.Sequence; import net.sf.saxon.om.StructuredQName; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.AnyURIValue; import net.sf.saxon.value.SequenceType; public class SystemIdFunction extends ExtensionFunctionDefinition { private static final long serialVersionUID = -4202710868367933385L; public static StructuredQName QNAME = new StructuredQName("saxon", "http://saxon.sf.net/", "system-id"); @Override public StructuredQName getFunctionQName() { return QNAME; } @Override public int getMaximumNumberOfArguments() { return 0; } @Override public int getMinimumNumberOfArguments() { return 0; } @Override public SequenceType[] getArgumentTypes() { return new SequenceType[]{}; } @Override public SequenceType getResultType(SequenceType[] suppliedArgumentTypes) { return SequenceType.SINGLE_STRING; } @Override public boolean dependsOnFocus() { return true; } @Override public boolean trustResultType() { return true; } @Override public ExtensionFunctionCall makeCallExpression() { return new ExtensionFunctionCall() { private static final long serialVersionUID = -4202710868367933385L; public Sequence call(XPathContext context, @SuppressWarnings("rawtypes") Sequence[] arguments) throws XPathException { if (context.getContextItem() instanceof NodeInfo) { return new SystemIdSequence(new AnyURIValue(((NodeInfo) context.getContextItem()).getSystemId())); } throw new XPathException("Unexpected XPath context for saxon:line-number"); } }; } class SystemIdSequence implements Sequence { private AnyURIValue item; public SystemIdSequence(AnyURIValue item) { this.item = item; } public Item head() { return item; } @Override public SequenceIterator iterate() throws XPathException { return item.iterate(); } } } epubcheck-4.0.2/src/main/java/org/idpf/epubcheck/util/saxon/LineNumberFunction.java0000644000175000017500000000357113017276730027600 0ustar eugeneeugenepackage org.idpf.epubcheck.util.saxon; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.lib.ExtensionFunctionCall; import net.sf.saxon.lib.ExtensionFunctionDefinition; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.Sequence; import net.sf.saxon.om.StructuredQName; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.Int64Value; import net.sf.saxon.value.SequenceType; public class LineNumberFunction extends ExtensionFunctionDefinition { private static final long serialVersionUID = -4202710868367933385L; public static StructuredQName QNAME = new StructuredQName("saxon", "http://saxon.sf.net/", "line-number"); @Override public StructuredQName getFunctionQName() { return QNAME; } @Override public int getMaximumNumberOfArguments() { return 1; } @Override public int getMinimumNumberOfArguments() { return 0; } @Override public SequenceType[] getArgumentTypes() { return new SequenceType[]{SequenceType.SINGLE_NODE}; } @Override public SequenceType getResultType(SequenceType[] suppliedArgumentTypes) { return SequenceType.SINGLE_INTEGER; } @Override public boolean dependsOnFocus() { return true; } @Override public boolean trustResultType() { return true; } @Override public ExtensionFunctionCall makeCallExpression() { return new ExtensionFunctionCall() { private static final long serialVersionUID = -4202710868367933385L; public Sequence call(XPathContext context, @SuppressWarnings("rawtypes") Sequence[] arguments) throws XPathException { if (context.getContextItem() instanceof NodeInfo) { return new Int64ValueSequence(new Int64Value(((NodeInfo) context.getContextItem()).getLineNumber())); } throw new XPathException("Unexpected XPath context for saxon:line-number"); } }; } } epubcheck-4.0.2/src/main/java/org/idpf/epubcheck/util/css/0000755000175000017500000000000013017276730022621 5ustar eugeneeugeneepubcheck-4.0.2/src/main/java/org/idpf/epubcheck/util/css/CssEscape.java0000644000175000017500000001215013017276730025334 0ustar eugeneeugene/* * Copyright (c) 2012 International Digital Publishing Forum * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package org.idpf.epubcheck.util.css; import com.google.common.base.CharMatcher; import com.google.common.base.Objects; import com.google.common.base.Optional; import org.idpf.epubcheck.util.css.CssExceptions.CssException; import org.idpf.epubcheck.util.css.CssToken.TokenBuilder; import java.io.IOException; import static com.google.common.base.Preconditions.checkArgument; import static org.idpf.epubcheck.util.css.CssExceptions.CssErrorCode.SCANNER_PREMATURE_EOF; import static org.idpf.epubcheck.util.css.CssScanner.*; /** * Represents a CSS escape sequence. * * @author mgylling */ class CssEscape { static final Optional ABSENT = Optional.absent(); private final boolean debug = false; private final CssReader reader; private final TokenBuilder err; /** * The original escape sequence */ private CharSequence sequence; /** * The character resulting from unescaping the original escape sequence */ int character; /** * Constructor. * * @param reader A CssReader whose current char is the backslash. * @param err token builder */ CssEscape(final CssReader reader, final TokenBuilder err) { this.reader = reader; this.err = err; } Optional create() throws IOException, CssException { if (debug) { checkArgument(reader.curChar == '\\', "must be backslash, was: %s", (char) reader.curChar); } /* * The incoming is either a hex escape or single char escape, max 8 chars long */ StringBuilder sb = new StringBuilder(); int[] eight = reader.peek(8); int first = eight[0]; if (first == -1) { err.error(SCANNER_PREMATURE_EOF, reader); return Optional.absent(); } else if (isNewLine(eight) > 0) { //"a backslash followed by a newline stands by itself" return Optional.absent(); } if (CssScanner.HEXCHAR.matches((char) first)) { //a hex escape, max six chars, + optionally single whitespace or cr+lf boolean seenSpace = false; for (int cur : eight) { if (cur == -1) { break; } char ch = (char) cur; boolean isHexChar = HEXCHAR.matches(ch); boolean isSpace = WHITESPACE.matches(ch); if (!isHexChar && !isSpace) { break; } if (HEXCHAR.matches(ch) && !seenSpace && sb.length() < 6) { sb.append((char) cur); } if (isSpace) { if (!seenSpace) { sb.append((char) cur); if (cur == '\r') { seenSpace = true; } else { break; } } else { //we have a prev space which is \r if (cur == '\f') { sb.append((char) cur); } break; } } } character = Integer.parseInt(WHITESPACE.trimTrailingFrom(sb.toString()), 16); sb.insert(0, '\\'); sequence = sb.toString(); } else { //a single char escape sb.append('\\').append((char) eight[0]); sequence = sb.toString(); character = eight[0]; } return Optional.of(this); } /** * Render this escape. * * @param builder The TokenBuilder to render into * @param asLiteral If given matcher matches this escapes literal, then render as literal, else as escape. * @return the length of the token in the input character stream */ int render(TokenBuilder builder, CharMatcher asLiteral) { char ch = (char) character; if (asLiteral.matches(ch)) { builder.append(ch); } else { //TODO could normalize space end chars builder.append(sequence); } return sequence.length() - 1; } @Override public String toString() { return Objects.toStringHelper(this) .add("escaped", sequence) .add("unescaped", (char) character) .toString(); } }epubcheck-4.0.2/src/main/java/org/idpf/epubcheck/util/css/CssErrorHandler.java0000644000175000017500000000303013017276730026520 0ustar eugeneeugene/* * Copyright (c) 2012 International Digital Publishing Forum * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package org.idpf.epubcheck.util.css; import org.idpf.epubcheck.util.css.CssExceptions.CssException; /** * ErrorHandler interface for CssParser. * * @author mgylling */ public interface CssErrorHandler { /** * Receive notification of an error in the CSS syntax. * * @param e CSSException * @throws CssException */ public void error(CssException e) throws CssException; } epubcheck-4.0.2/src/main/java/org/idpf/epubcheck/util/css/CssExceptions.java0000644000175000017500000001165413017276730026265 0ustar eugeneeugene/* * Copyright (c) 2012 International Digital Publishing Forum * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package org.idpf.epubcheck.util.css; import com.google.common.base.Objects; import com.google.common.base.Optional; import static com.google.common.base.Preconditions.checkNotNull; /** * Exception types and error codes. * * @author mgylling */ public final class CssExceptions { public enum CssErrorCode { SCANNER_ILLEGAL_SYNTAX(SCANNER_TOKEN_SYNTAX), //a general error code, below refines SCANNER_ILLEGAL_CHAR(SCANNER_TOKEN_SYNTAX + ".char"), SCANNER_ILLEGAL_FIRSTCHAR(SCANNER_TOKEN_SYNTAX + ".firstChar"), SCANNER_MALFORMED_ESCAPE(SCANNER_TOKEN_SYNTAX + ".escape"), SCANNER_ILLEGAL_URANGE(SCANNER_TOKEN_SYNTAX + ".urange"), SCANNER_PREMATURE_EOF(SCANNER + ".prematureEOF"), GRAMMAR_PREMATURE_EOF(GRAMMAR + ".prematureEOF"), GRAMMAR_UNEXPECTED_TOKEN(GRAMMAR_TOKEN + ".unexpected"), GRAMMAR_EXPECTING_TOKEN(GRAMMAR_TOKEN + ".expecting"), GRAMMAR_INVALID_SELECTOR(GRAMMAR + ".invalidSelector"),; final String value; CssErrorCode(String value) { this.value = value; } @Override public String toString() { return Objects.toStringHelper(this.getClass()).addValue(value).toString(); } } /** * An exception with grammatical origins. */ static class CssGrammarException extends CssException { CssGrammarException(final CssErrorCode errorCode, final CssLocation location, final Object... arguments) { super(errorCode, location, arguments); } private static final long serialVersionUID = -7470976690623543450L; } /** * An exception with lexical origins. */ static class CssScannerException extends CssException { CssScannerException(final CssToken token, final CssErrorCode errorCode, final CssLocation location, final Object... arguments) { super(token, errorCode, location, arguments); } CssScannerException(CssErrorCode errorCode, CssLocation location, Object... arguments) { super(errorCode, location, arguments); } private static final long serialVersionUID = 7105109387886737631L; } public static abstract class CssException extends Exception { final CssErrorCode errorCode; final CssLocation location; final Optional token; CssException(final CssToken token, final CssErrorCode errorCode, final CssLocation location, final Object... arguments) { super(Messages.get(errorCode.value, arguments)); this.errorCode = checkNotNull(errorCode); this.location = checkNotNull(location); this.token = token == null ? absent : Optional.of(token); } CssException(final CssErrorCode errorCode, final CssLocation location, final Object... arguments) { this(null, errorCode, location, arguments); } public CssErrorCode getErrorCode() { return errorCode; } public CssLocation getLocation() { return location; } @Override public String toString() { return Objects.toStringHelper(this.getClass()) .add("errorCode", errorCode) .add("location", location.toString()) .toString(); } @Override public boolean equals(Object obj) { if (obj instanceof CssException) { CssException exc = (CssException) obj; if (exc.errorCode.equals(this.errorCode) && exc.location.equals(this.location)) { return true; } } return false; } private static final long serialVersionUID = -4635263495562931206L; } private final static String SCANNER = "css.scanner"; private final static String SCANNER_TOKEN_SYNTAX = SCANNER + ".token.syntax"; private final static String GRAMMAR = "css.grammar"; private final static String GRAMMAR_TOKEN = GRAMMAR + ".token"; private static final Optional absent = Optional.absent(); } epubcheck-4.0.2/src/main/java/org/idpf/epubcheck/util/css/CssGrammar.java0000644000175000017500000011441313017276730025527 0ustar eugeneeugene/* * Copyright (c) 2012 International Digital Publishing Forum * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package org.idpf.epubcheck.util.css; import com.google.common.base.*; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; import org.idpf.epubcheck.util.css.CssExceptions.CssErrorCode; import org.idpf.epubcheck.util.css.CssExceptions.CssException; import org.idpf.epubcheck.util.css.CssExceptions.CssGrammarException; import org.idpf.epubcheck.util.css.CssParser.ContextRestrictions; import org.idpf.epubcheck.util.css.CssTokenList.CssTokenIterator; import java.util.List; import java.util.Map; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static org.idpf.epubcheck.util.css.CssExceptions.CssErrorCode.GRAMMAR_UNEXPECTED_TOKEN; import static org.idpf.epubcheck.util.css.CssToken.Matchers.*; import static org.idpf.epubcheck.util.css.CssTokenList.Filters.FILTER_NONE; /** * CSS grammar components. * * @author mgylling */ public class CssGrammar { /** * Abstract base for all CssConstructs. */ public static abstract class CssConstruct { final CssLocation location; final Type type; public CssConstruct(final Type type, final CssLocation location) { this.location = checkNotNull(location); this.type = checkNotNull(type); } public final CssLocation getLocation() { return location; } public final Type getType() { return type; } public abstract String toCssString(); public enum Type { //atomics STRING, KEYWORD, COMBINATOR, //space, plus, gt, tilde ATTRIBUTE_MATCH, // "~=", "|=", "^=","$=" "*=" HASHNAME, //#ident CLASSNAME, //.ident QUANTITY, URANGE, URI, SYMBOL, //a single char, eg operators TYPE_SELECTOR, //ns|E, *|E, |E, E, * PSEUDO, //element and class //composed ATRULE, FUNCTION, DECLARATION, SELECTOR, SIMPLE_SELECTOR_SEQ, ATTRIBUTE_SELECTOR, //[...] SCOPEDGROUP, //(...) and [...], the latter when not an attr selector segment } } /********************************************* * * atomics * ********************************************/ /** * A CssConstruct that is composed by a single token. */ static abstract class CssAtomicConstruct extends CssConstruct { final String value; public CssAtomicConstruct(final Type type, final String value, final CssLocation location) { super(type, location); this.value = checkNotNull(value); } @Override public String toString() { return Objects.toStringHelper(this).addValue(value).toString(); } @Override public String toCssString() { return value; } } /** * A CSS string. The returned value does not include start and end quotes. */ public final static class CssString extends CssAtomicConstruct { public CssString(final String value, final CssLocation location) { super(Type.STRING, value, location); } @Override public final String toCssString() { return "'" + value + "'"; } } /** * A CSS keyword. */ public final static class CssKeyword extends CssAtomicConstruct { public CssKeyword(final String value, final CssLocation location) { super(Type.KEYWORD, value, location); } } /** * A CSS hash name */ public final static class CssHashName extends CssAtomicConstruct { public CssHashName(final String value, final CssLocation location) { super(Type.HASHNAME, value, location); } } /** * A CSS class name */ public final static class CssClassName extends CssAtomicConstruct { public CssClassName(final String value, final CssLocation location) { super(Type.CLASSNAME, value, location); } } /** * A CSS unicode range */ public final static class CssUnicodeRange extends CssAtomicConstruct { public CssUnicodeRange(final String value, final CssLocation location) { super(Type.URANGE, value, location); } } /** * A CSS URI. */ public final static class CssURI extends CssAtomicConstruct { public CssURI(final String value, final CssLocation location) { super(Type.URI, value, location); } /** * The URI string itself (leading/trailing whitespace+quotes stripped, url function removed) */ public String toUriString() { StringBuilder builder = new StringBuilder(); boolean inStart = false; for (int i = 0; i < value.length(); i++) { if (i > 3 && i < value.length() - 1) { char ch = value.charAt(i); if (CssScanner.QUOTES.matches(ch) || CssScanner.WHITESPACE.matches(ch)) { if (inStart) { builder.append(ch); } } else { inStart = true; builder.append(ch); } } } while (true) { if (builder.length() == 0) { break; } int index = builder.length() - 1; char ch = builder.charAt(index); if (CssScanner.QUOTES.matches(ch) || CssScanner.WHITESPACE.matches(ch)) { builder.deleteCharAt(index); } else { break; } } return builder.toString(); } } /** * A CSS single-character symbol (e.g. operator) that is not * in the range of IDENT/KEYWORD and not '{', '}' or ';'. The value * is interned. */ public final static class CssSymbol extends CssAtomicConstruct { public CssSymbol(final String value, final CssLocation location) { super(Type.SYMBOL, value.intern(), location); checkArgument(value.length() == 1); } } /** * A CSS selector combinator (space, plus, greater or tilde). The value is interned. */ public final static class CssSelectorCombinator extends CssAtomicConstruct { final CssSelectorCombinator.Type subType; public CssSelectorCombinator(final char value, final CssLocation location) { super(CssConstruct.Type.COMBINATOR, String.valueOf(value).intern(), location); switch (value) { case ' ': this.subType = Type.DESCENDANT; break; case '>': this.subType = Type.CHILD; break; case '+': this.subType = Type.ADJACENT_SIBLING; break; case '~': this.subType = Type.GENERAL_SIBLING; break; default: throw new IllegalStateException(); } } public final CssSelectorCombinator.Type getCombinatorType() { return subType; } public enum Type { DESCENDANT, //S CHILD, //> ADJACENT_SIBLING, //+ GENERAL_SIBLING //~ } } /** * An attribute match selector ('=', '~=', '|=', '^=', '$=', '*=') */ public final static class CssAttributeMatchSelector extends CssAtomicConstruct { final CssAttributeMatchSelector.Type subType; public CssAttributeMatchSelector(final String value, final CssAttributeMatchSelector.Type type, final CssLocation location) { super(CssConstruct.Type.ATTRIBUTE_MATCH, value, location); this.subType = type; } public final CssAttributeMatchSelector.Type getAttributeMatchType() { return subType; } public enum Type { EQUALS, //"=" INCLUDES, //"~=" DASHMATCH, //"|=" PREFIXMATCH, //"^=" SUFFIXMATCH, //"$=" SUBSTRINGMATCH //"*=" } @Override public String toString() { return Objects.toStringHelper(this).addValue(subType.name()).addValue(value).toString(); } } /** * A type or universal ('*') selector, possibly with namespace bindings. */ public static class CssTypeSelector extends CssAtomicConstruct { public CssTypeSelector(final String value, final CssLocation location) { super(Type.TYPE_SELECTOR, value, location); } } /** * A CSS quantity. */ public final static class CssQuantity extends CssAtomicConstruct { final CssQuantity.Unit subType; public CssQuantity(final String value, final CssQuantity.Unit subtype, final CssLocation location) { super(CssConstruct.Type.QUANTITY, value, location); this.subType = checkNotNull(subtype); } public final CssQuantity.Unit getUnit() { return subType; } public enum Unit { DIMEN, PERCENTAGE, LENGTH, EMS, EXS, ANGLE, TIME, FREQ, RESOLUTION, NUMBER, INTEGER, REMS } @Override public String toString() { return Objects.toStringHelper(this).addValue(subType.name()).addValue(value).toString(); } } /********************************************* * * composed * ********************************************/ /** * A CssConstruct that is composed a list of atomic and/or composed CssConstructs, * and optionally a name. */ static abstract class CssComposedConstruct extends CssConstruct { final List components; final Optional name; public CssComposedConstruct(final Type type, final String name, final CssLocation location) { super(type, location); this.components = Lists.newArrayList(); this.name = name != null ? Optional.of(name) : absent; } public CssComposedConstruct(final Type type, final CssLocation location) { this(type, null, location); } /** * Get the components. The list may be empty but is never null. */ public List getComponents() { return components; } public Optional getName() { return name; } @Override public String toString() { return Objects.toStringHelper(this) .addValue(type) .addValue(name.isPresent() ? name.get() : "") .addValue(components.isEmpty() ? "" : Joiner.on(" ").join(components)) .toString(); } final Optional absent = Optional.absent(); } /** * An attribute selector ([name] or [name, match, ident/string] ) */ public final static class CssAttributeSelector extends CssComposedConstruct { public CssAttributeSelector(final CssLocation location) { super(Type.ATTRIBUTE_SELECTOR, location); } @Override public String toCssString() { StringBuilder sb = new StringBuilder().append('['); for (CssConstruct cc : components) { sb.append(cc.toCssString()); } return sb.append(']').toString(); } } /** * A CSS function. The function name is interned, and ASCII characters in the name * are guaranteed to be lower case. */ public final static class CssFunction extends CssComposedConstruct { public CssFunction(final String name, final CssLocation location) { super(Type.FUNCTION, Ascii.toLowerCase(checkNotNull(name)).intern(), location); } @Override public String toCssString() { StringBuilder sb = new StringBuilder().append(name.get()).append('('); for (CssConstruct cc : components) { sb.append(cc.toCssString()); } return sb.append(')').toString(); } } /** * A CSS at-rule. The at-rule name is interned, and ASCII characters in the name * are guaranteed to be lowercase. */ public final static class CssAtRule extends CssComposedConstruct { boolean hasBlock; public CssAtRule(final String name, final CssLocation location) { super(Type.ATRULE, checkNotNull( Ascii.toLowerCase(name).intern()), location); } public final boolean hasBlock() { return hasBlock; } @Override public String toCssString() { // Note that semi or braceblock is not included in the return StringBuilder sb = new StringBuilder().append(name.get()).append(' '); for (CssConstruct cc : components) { sb.append(cc.toCssString()).append(' '); //TODO get smarter re space, joint helper function } return sb.deleteCharAt(sb.length() - 1).toString(); } } /** * A CSS declaration. The property name is interned, and ASCII characters in the name * are guaranteed to be lowercase. */ public final static class CssDeclaration extends CssComposedConstruct { boolean important = false; public CssDeclaration(final String name, final CssLocation location) { super(Type.DECLARATION, Ascii.toLowerCase(name).intern(), location); } /** * Get the state of the important flag */ public final boolean getImportant() { return important; } @Override public String toCssString() { StringBuilder sb = new StringBuilder().append(name.get()).append(" : "); for (CssConstruct cc : components) { sb.append(cc.toCssString()).append(' '); //TODO get smarter re space, joint helper function } if (getImportant()) { sb.append("!important "); } return sb.deleteCharAt(sb.length() - 1).append(" ;").toString(); } } /** * A scoped group, aka (...) and [...]. */ public final static class CssScopedGroup extends CssComposedConstruct { final CssScopedGroup.Type subType; public CssScopedGroup(final CssScopedGroup.Type type, final CssLocation location) { super(CssConstruct.Type.SCOPEDGROUP, location); this.subType = type; } @Override public String toString() { return Objects.toStringHelper(this) .addValue(type) .addValue(subType) .addValue(Joiner.on(" ").join(components)) .toString(); } public final CssScopedGroup.Type getGroupType() { return subType; } @Override public String toCssString() { StringBuilder sb = new StringBuilder(); sb.append(subType == Type.PAREN ? '(' : '['); for (CssConstruct cc : components) { sb.append(cc.toCssString()).append(' '); //TODO get smarter re space, joint helper function } sb.deleteCharAt(sb.length() - 1); sb.append(subType == Type.PAREN ? ')' : ']'); return sb.toString(); } public enum Type { PAREN, BRACKET } } /** * A CSS pseudo selector (pseudo-element and pseudo-class). */ public final static class CssPseudoSelector extends CssComposedConstruct { final CssPseudoSelector.Type subType; CssFunction function = null; //may remain null String name = null; //may remain null public CssPseudoSelector(final CssPseudoSelector.Type type, final CssLocation location) { super(CssConstruct.Type.PSEUDO, location); this.subType = type; } /* * If this pseudo selector is a functional_pseudo, * return the function name, else :(:)ident. */ @Override public final Optional getName() { if (function != null) { return function.getName(); } return Optional.of(name); } @Override public String toString() { return Objects.toStringHelper(this) .addValue(getSubType().name()) .addValue(getName().get()) .addValue(function != null ? Joiner.on(" ").join(function.components) : "") .toString(); } /** * If this pseudo selector is a functional_pseudo, * return it as a function, else return null. */ public final CssFunction getFunction() { return function; } public final CssPseudoSelector.Type getSubType() { return subType; } @Override public String toCssString() { if (function != null) { return function.toCssString(); } return name; } public enum Type { PSEUDO_ELEMENT, PSEUDO_CLASS, } } /** * A CSS selector */ public final static class CssSelector extends CssComposedConstruct { public CssSelector(final CssLocation location) { super(Type.SELECTOR, location); } /** * Get the list of selector constructs, consisting of at least one * CssSimpleSelectorSequence, possibly followed by (CssSelectorCombinator, * CssSimpleSelectorSequence)* */ public final List getComponents() { return super.getComponents(); } @Override public String toCssString() { StringBuilder sb = new StringBuilder(); for (CssConstruct cc : components) { sb.append(cc.toCssString()); } return sb.toString(); } } /** * A CSS simple selector sequence * A sequence of simple selectors is a chain of simple selectors that are not * separated by a combinator. It always begins with a type selector or a universal * selector. No other type selector or universal selector is allowed in the sequence. * A simple selector is either a type selector, universal selector, attribute selector, * class selector, ID selector, or pseudo-class. */ public final static class CssSimpleSelectorSequence extends CssComposedConstruct { public CssSimpleSelectorSequence(final CssLocation location) { super(Type.SIMPLE_SELECTOR_SEQ, location); } @Override public String toCssString() { StringBuilder sb = new StringBuilder(); for (CssConstruct cc : components) { sb.append(cc.toCssString()); } return sb.toString(); } } /** * ****************************************** *

* helpers *

* ****************************************** */ static final class CssSelectorConstructFactory { /** * Create a simple selector sequence. If creation fails, * errors are issued, and null is returned. * * @throws CssException */ public static CssSimpleSelectorSequence createSimpleSelectorSequence(final CssToken start, final CssTokenIterator iter, final CssErrorHandler err) throws CssException { CssSimpleSelectorSequence seq = new CssSimpleSelectorSequence(start.location); CssConstruct seqItem = createSimpleSelector(start, iter, err); if (seqItem == null) { //errors already issued return null; } seq.components.add(seqItem); CssToken next = iter.peek(FILTER_NONE); while (next.type != CssToken.Type.S && !MATCH_COMMA.apply(next) && !MATCH_OPENBRACE.apply(next) && !MATCH_COMBINATOR_CHAR.apply(next)) { seqItem = createSimpleSelector(iter.next(FILTER_NONE), iter, err); if (seqItem == null) { //errors already issued return null; } seq.components.add(seqItem); next = iter.peek(FILTER_NONE); } return seq; } /** * Create one item in a simple selector sequence. If creation fails, * errors are issued, and null is returned. On return, the iterator * will return the next token after the constructs last token. */ static CssConstruct createSimpleSelector(final CssToken start, final CssTokenIterator iter, final CssErrorHandler err) throws CssException { // type and universal selector; ns|E, *|E, |E, E if (start.type == CssToken.Type.IDENT || MATCH_STAR_PIPE.apply(start)) { //note, we bundle universal selector in CssTypeSelector return createTypeSelector(start, iter, err); // hashname #{name} } else if (start.type == CssToken.Type.HASHNAME) { return new CssHashName(start.getChars(), start.location); // classname .{name} } else if (start.type == CssToken.Type.CLASSNAME) { return new CssClassName(start.getChars(), start.location); //attribute selector [...] } else if (MATCH_OPENSQUAREBRACKET.apply(start)) { return createAttributeSelector(iter.next(), iter, err); //pseudo selector } else if (MATCH_COLON.apply(start)) { return createPseudoSelector(start, iter, err); //keyframes percentage } else if(start.type == CssToken.Type.QNTY_PERCENTAGE) { //note, for now, "from" and "to" keywords become type selectors above, //this handles only the percentage TODO FIX CssSelector sel = new CssSelector(start.location); sel.components.add(new CssQuantity(start.chars, CssQuantity.Unit.PERCENTAGE, start.location)); return sel; } else { err.error(new CssGrammarException(GRAMMAR_UNEXPECTED_TOKEN, start.location, start.chars)); return null; } } /** * Create a combinator. Note that this method does not support the S combinator. * This method also returns null without issuing errors */ static CssSelectorCombinator createCombinator(final CssToken start, final CssTokenIterator iter, final CssErrorHandler err) { char symbol; if (start.type == CssToken.Type.CHAR) { char ch = start.getChar(); if (ch == '>') { symbol = ch; } else if (ch == '+') { symbol = ch; } else if (ch == '~') { symbol = ch; } else { return null; } } else { return null; } return new CssSelectorCombinator(symbol, start.location); } static CssPseudoSelector createPseudoSelector(final CssToken start, final CssTokenIterator iter, final CssErrorHandler err) throws CssException { CssPseudoSelector.Type type; CssPseudoSelector cps; StringBuilder sb = new StringBuilder(); sb.append(start.getChars()); CssToken next = iter.next(FILTER_NONE); if (MATCH_COLON.apply(next)) { type = CssPseudoSelector.Type.PSEUDO_ELEMENT; sb.append(next.getChars()); next = iter.next(FILTER_NONE); } else { type = CssPseudoSelector.Type.PSEUDO_CLASS; } cps = new CssPseudoSelector(type, start.location); if (next.type == CssToken.Type.IDENT) { sb.append(next.getChars()); cps.name = sb.toString(); } else if (next.type == CssToken.Type.FUNCTION) { //need to get the colons into the name so clone and mod the token CssToken tk = new CssToken(next.type, next.location, sb.toString() + next.chars, next.errors.isPresent() ? next.errors.get() : null); //general functional pseudos and negation pseudos have different contentmodels //functional: [ [ PLUS | '-' | DIMENSION | NUMBER | STRING | IDENT ] S* ]+ //pseudo: type_selector | universal | HASH | class | attrib | pseudo CssConstruct func; if (Ascii.toLowerCase(next.getChars()).startsWith("not")) { func = createNegationPseudo(tk, iter, err); } else { func = createFunctionalPseudo(tk, iter, MATCH_OPENBRACE, err); } if (func == null) { err.error(new CssGrammarException( CssErrorCode.GRAMMAR_UNEXPECTED_TOKEN, iter.last.location, iter.last.chars, next.getChars())); return null; } cps.function = (CssFunction) func; } return cps; } static CssConstruct createFunctionalPseudo(final CssToken start, final CssTokenIterator iter, final Predicate limit, final CssErrorHandler err) { String name = start.getChars().substring(0, start.getChars().length() - 1); CssFunction function = new CssFunction(name, start.location); CssToken tk = iter.next(); while (!MATCH_CLOSEPAREN.apply(tk)) { if (limit.apply(tk)) { return null; } CssConstruct cc = CssConstructFactory.create(tk, iter, limit, ContextRestrictions.PSEUDO_FUNCTIONAL); if (cc == null) { return null; } else { function.components.add(cc); } tk = iter.next(); } return function; } static CssConstruct createNegationPseudo(final CssToken start, final CssTokenIterator iter, final CssErrorHandler err) throws CssException { String name = start.getChars().substring(0, start.getChars().length() - 1); CssFunction negation = new CssFunction(name, start.location); CssToken tk = iter.next(); CssConstruct cc = CssSelectorConstructFactory.createSimpleSelector(tk, iter, err); if (cc == null || !ContextRestrictions.PSEUDO_NEGATION.apply(cc)) { return null; } else { negation.components.add(cc); iter.next(); } return negation; } static CssAttributeSelector createAttributeSelector(final CssToken start, final CssTokenIterator iter, final CssErrorHandler err) throws CssException { CssAttributeSelector cas = new CssAttributeSelector(start.location); CssTypeSelector cts = createTypeSelector(start, iter, err); if (cts == null) { //factory method has issued errors return null; } cas.components.add(cts); CssToken next = iter.next(); // ']' or string matcher if (!MATCH_CLOSESQUAREBRACKET.apply(next)) { if (MATCH_ATTRIBUTE_SELECTOR_MATCHERS.apply(next)) { CssAttributeMatchSelector casm = createAttributeMatchSelector(next, iter, err); cas.components.add(casm); next = iter.next(); CssConstruct val = CssConstructFactory.create(next, iter, MATCH_CLOSESQUAREBRACKET, ContextRestrictions.ATTRIBUTE_SELECTOR_VALUE); if (val != null) { cas.components.add(val); } else { err.error(new CssGrammarException( CssErrorCode.GRAMMAR_EXPECTING_TOKEN, next.location, next.chars, Messages.get("a_string_or_dentifier"))); return null; } iter.next(); // ']' } else { err.error(new CssGrammarException( CssErrorCode.GRAMMAR_EXPECTING_TOKEN, next.location, next.chars, Messages.get("an_attribute_value_matcher"))); return null; } } return cas; } static CssAttributeMatchSelector createAttributeMatchSelector(final CssToken tk, final CssTokenIterator iter, final CssErrorHandler err) { CssAttributeMatchSelector.Type type; switch (tk.type) { case INCLUDES: type = CssAttributeMatchSelector.Type.INCLUDES; break; case DASHMATCH: type = CssAttributeMatchSelector.Type.DASHMATCH; break; case PREFIXMATCH: type = CssAttributeMatchSelector.Type.PREFIXMATCH; break; case SUFFIXMATCH: type = CssAttributeMatchSelector.Type.SUFFIXMATCH; break; case SUBSTRINGMATCH: type = CssAttributeMatchSelector.Type.SUBSTRINGMATCH; break; default: type = CssAttributeMatchSelector.Type.EQUALS; break; } return new CssAttributeMatchSelector(tk.getChars(), type, tk.location); } private static CssTypeSelector createTypeSelector(final CssToken start, final CssTokenIterator iter, final CssErrorHandler err) throws CssException { if (start.type != CssToken.Type.IDENT && !MATCH_STAR_PIPE.apply(start)) { err.error(new CssGrammarException( CssErrorCode.GRAMMAR_EXPECTING_TOKEN, start.location, start.getChars(), Messages.get("a_type_or_universal_selector"))); return null; } StringBuilder sb = new StringBuilder(); sb.append(start.getChars()); if (MATCH_PIPE.apply(start)) { //|E CssToken next = iter.peek(FILTER_NONE); if (next.type != CssToken.Type.IDENT) { err.error(new CssGrammarException( CssErrorCode.GRAMMAR_EXPECTING_TOKEN, next.location, next.getChars(), Messages.get("a_type_or_universal_selector"))); return null; } else { sb.append(iter.next().getChars()); } } else if (MATCH_PIPE.apply(iter.peek(FILTER_NONE))) { //ns|E, *|E, sb.append(iter.next().getChars()); CssToken next = iter.next(FILTER_NONE); if (next.type != CssToken.Type.IDENT && !MATCH_STAR.apply(next)) { err.error(new CssGrammarException( CssErrorCode.GRAMMAR_EXPECTING_TOKEN, start.location, next.getChars(), Messages.get("a_type_or_universal_selector"))); return null; } else { sb.append(next.getChars()); } } else if (iter.peek(FILTER_NONE).type == CssToken.Type.IDENT) { sb.append(iter.next().getChars()); } return new CssTypeSelector(sb.toString(), start.location); } } static final class CssConstructFactory { static CssConstruct create(final CssToken start, final CssTokenIterator iter, final Predicate limit, final Predicate permitted) { CssTokenTransform transform = transformerMappings.get(start.type); return transform == null ? null : transform.build(start, iter, limit, permitted); } static final CssTokenTransform BUILDER_FUNCTION = new CssTokenTransform() { public CssFunction build(CssToken start, CssTokenIterator iter, Predicate limit, Predicate permitted) { String name = start.getChars().substring(0, start.getChars().length() - 1); CssFunction function = new CssFunction(name, start.location); CssToken tk = iter.next(); while (!MATCH_CLOSEPAREN.apply(tk)) { if (limit.apply(tk)) { return null; } CssConstruct cc = CssConstructFactory.create(tk, iter, limit, ContextRestrictions.FUNCTION); if (cc == null || !permitted.apply(cc)) { return null; } else { function.components.add(cc); } tk = iter.next(); } return function; } }; private static final CssTokenTransform BUILDER_ATOMIC = new CssTokenTransform() { public CssConstruct build(final CssToken start, final CssTokenIterator iter, final Predicate limit, final Predicate permitted) { CssConstruct.Type type = genericTypeMappings.get(start.type); CssConstruct cc; switch (type) { case KEYWORD: cc = new CssKeyword(start.getChars(), start.location); break; case URI: cc = new CssURI(start.getChars(), start.location); break; case STRING: cc = new CssString(start.getChars(), start.location); break; case URANGE: cc = new CssUnicodeRange(start.getChars(), start.location); break; case HASHNAME: cc = new CssHashName(start.getChars(), start.location); break; case CLASSNAME: cc = new CssClassName(start.getChars(), start.location); break; default: throw new IllegalStateException("CssTokenTransform BUILDER_ATOMIC"); } return permitted.apply(cc) ? cc : null; } }; private static final CssTokenTransform BUILDER_CHAR = new CssTokenTransform() { public CssConstruct build(CssToken start, CssTokenIterator iter, Predicate limit, Predicate permitted) { CssConstruct ret; char chr = start.getChar(); if (chr == '{' || chr == '}' || chr == ';') { return null; } else if (chr == '(' || chr == '[') { ret = BUILDER_SCOPEDGROUP.build(start, iter, limit, permitted); } else { ret = new CssSymbol(start.chars, start.location); } if (ret == null) { return null; } return permitted.apply(ret) ? ret : null; } }; /** * Builder for general scoped groups aka (...) and [...] */ static final CssTokenTransform BUILDER_SCOPEDGROUP = new CssTokenTransform() { public CssConstruct build(CssToken start, CssTokenIterator iter, Predicate limit, Predicate permitted) { CssScopedGroup.Type type; Predicate end; if (MATCH_OPENPAREN.apply(start)) { type = CssScopedGroup.Type.PAREN; end = MATCH_CLOSEPAREN; } else if (MATCH_OPENSQUAREBRACKET.apply(start)) { type = CssScopedGroup.Type.BRACKET; end = MATCH_CLOSESQUAREBRACKET; } else { throw new IllegalStateException(); } CssScopedGroup group = new CssScopedGroup(type, start.location); CssToken tk = iter.next(); while (!end.apply(tk)) { if (limit.apply(tk)) { return null; } CssConstruct cc = CssConstructFactory.create(tk, iter, limit, ContextRestrictions.FUNCTION); if (cc == null || !permitted.apply(cc)) { return null; } else { group.components.add(cc); } tk = iter.next(); } return group; } }; private static final CssTokenTransform BUILDER_QNTY = new CssTokenTransform() { public CssConstruct build(final CssToken start, final CssTokenIterator iter, final Predicate limit, final Predicate permitted) { CssQuantity cq = new CssQuantity(start.chars, quantityMappings.get(start.type), start.location); return permitted.apply(cq) ? cq : null; } }; private static final Map transformerMappings = new ImmutableMap.Builder() .put(CssToken.Type.FUNCTION, BUILDER_FUNCTION) .put(CssToken.Type.CHAR, BUILDER_CHAR) .put(CssToken.Type.IDENT, BUILDER_ATOMIC) .put(CssToken.Type.URI, BUILDER_ATOMIC) .put(CssToken.Type.STRING, BUILDER_ATOMIC) .put(CssToken.Type.AND, BUILDER_ATOMIC) .put(CssToken.Type.NOT, BUILDER_ATOMIC) .put(CssToken.Type.ONLY, BUILDER_ATOMIC) .put(CssToken.Type.URANGE, BUILDER_ATOMIC) .put(CssToken.Type.HASHNAME, BUILDER_ATOMIC) .put(CssToken.Type.CLASSNAME, BUILDER_ATOMIC) .put(CssToken.Type.QNTY_ANGLE, BUILDER_QNTY) .put(CssToken.Type.QNTY_DIMEN, BUILDER_QNTY) .put(CssToken.Type.QNTY_REMS, BUILDER_QNTY) .put(CssToken.Type.QNTY_EMS, BUILDER_QNTY) .put(CssToken.Type.QNTY_EXS, BUILDER_QNTY) .put(CssToken.Type.QNTY_FREQ, BUILDER_QNTY) .put(CssToken.Type.QNTY_LENGTH, BUILDER_QNTY) .put(CssToken.Type.QNTY_PERCENTAGE, BUILDER_QNTY) .put(CssToken.Type.QNTY_RESOLUTION, BUILDER_QNTY) .put(CssToken.Type.QNTY_TIME, BUILDER_QNTY) .put(CssToken.Type.NUMBER, BUILDER_QNTY) .put(CssToken.Type.INTEGER, BUILDER_QNTY) .build(); /* Map used by BUILDER_GENERIC to get type */ private static final Map genericTypeMappings = new ImmutableMap.Builder() .put(CssToken.Type.IDENT, CssConstruct.Type.KEYWORD) .put(CssToken.Type.URI, CssConstruct.Type.URI) .put(CssToken.Type.STRING, CssConstruct.Type.STRING) .put(CssToken.Type.AND, CssConstruct.Type.KEYWORD) .put(CssToken.Type.NOT, CssConstruct.Type.KEYWORD) .put(CssToken.Type.ONLY, CssConstruct.Type.KEYWORD) .put(CssToken.Type.URANGE, CssConstruct.Type.URANGE) .put(CssToken.Type.HASHNAME, CssConstruct.Type.HASHNAME) .put(CssToken.Type.CLASSNAME, CssConstruct.Type.CLASSNAME) .build(); /* Map used by BUILDER_QNTY to get subtype */ private static final Map quantityMappings = new ImmutableMap.Builder() .put(CssToken.Type.QNTY_ANGLE, CssQuantity.Unit.ANGLE) .put(CssToken.Type.QNTY_DIMEN, CssQuantity.Unit.DIMEN) .put(CssToken.Type.QNTY_REMS, CssQuantity.Unit.REMS) .put(CssToken.Type.QNTY_EMS, CssQuantity.Unit.EMS) .put(CssToken.Type.QNTY_EXS, CssQuantity.Unit.EXS) .put(CssToken.Type.QNTY_FREQ, CssQuantity.Unit.FREQ) .put(CssToken.Type.QNTY_LENGTH, CssQuantity.Unit.LENGTH) .put(CssToken.Type.QNTY_PERCENTAGE, CssQuantity.Unit.PERCENTAGE) .put(CssToken.Type.QNTY_RESOLUTION, CssQuantity.Unit.RESOLUTION) .put(CssToken.Type.QNTY_TIME, CssQuantity.Unit.TIME) .put(CssToken.Type.NUMBER, CssQuantity.Unit.NUMBER) .put(CssToken.Type.INTEGER, CssQuantity.Unit.INTEGER) .build(); interface CssTokenTransform { CssConstruct build(CssToken start, CssTokenIterator iter, Predicate limit, Predicate permitted); } } } epubcheck-4.0.2/src/main/java/org/idpf/epubcheck/util/css/CssToken.java0000644000175000017500000003371613017276730025227 0ustar eugeneeugene/* * Copyright (c) 2012 International Digital Publishing Forum * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package org.idpf.epubcheck.util.css; import com.google.common.base.*; import com.google.common.collect.Lists; import org.idpf.epubcheck.util.css.CssExceptions.CssErrorCode; import org.idpf.epubcheck.util.css.CssExceptions.CssException; import org.idpf.epubcheck.util.css.CssExceptions.CssScannerException; import java.util.Iterator; import java.util.List; import static com.google.common.base.Preconditions.checkState; /** * Represents a CSS token. * * @author mgylling * @see CssTokenList */ final class CssToken { final Type type; final CssLocation location; final String chars; //for tokens with string values Optional> errors = Optional.absent(); /** * Constructor for tokens with type other than CHAR */ CssToken(final Type type, final CssLocation location, final String chars, final List errors) { this.type = type; this.location = location; this.chars = chars; if (errors != null) { this.errors = Optional.of(errors); } } /** * Constructor for CHAR tokens */ CssToken(final Type type, final CssLocation location, final char chr, final List errors) { this.type = type; this.location = location; this.chars = String.valueOf(chr); if (errors != null) { this.errors = Optional.of(errors); } } public Type getType() { return type; } public CssLocation getLocation() { return location; } public String getChars() { return chars; } public char getChar() { checkState(chars.length() == 1); return chars.charAt(0); } boolean hasErrors() { return errors.isPresent(); } public Optional> getErrors() { if (hasErrors()) { return Optional.of(errors.get().iterator()); } return Optional.absent(); } @Override public String toString() { return Objects.toStringHelper(this) .add("type", type.name()) .add("value", chars) .add("errors", errors.isPresent() ? Joiner.on(", ").join(errors.get()) : "none") .toString(); } @Override public boolean equals(Object obj) { if (obj instanceof CssToken) { CssToken tk = (CssToken) obj; if (tk.type.equals(this.type) && tk.chars.equals(this.chars) && tk.location.equals(this.location)) { return true; } } return false; } /** * Token types. */ public static enum Type { S, COMMENT, CDO, // IDENT, // [-]?{nmstart}{nmchar}* FUNCTION, // [-]?{nmstart}{nmchar}*[(] ATKEYWORD, // [@][-]?{nmstart}{nmchar}* NUMBER, // [0-9]+|[0-9]*\.[0-9]+ INTEGER, // [0-9]+ STRING, // URI, // url\({w}{string}{w}\) | url\({w}([!#$%&*-\[\]-~]|{nonascii}|{escape})*{w}\) HASHNAME, // "#"{name} CLASSNAME, // "."{name} URANGE, // INCLUDES, // "~=" DASHMATCH, // "|=" PREFIXMATCH, // "^=" SUFFIXMATCH, // "$=" SUBSTRINGMATCH, // "*=" QNTY_DIMEN, // {num}{ident} QNTY_PERCENTAGE, // {num}% QNTY_LENGTH, // {num}cm, {num}px, {num}mm, {num}in, {num}pt, {num}pc QNTY_EMS, // {num}em QNTY_EXS, // {num}ex QNTY_ANGLE, // {num}deg, {num}rad, {num}grad QNTY_TIME, // {num}ms, {num}s QNTY_FREQ, // {num}Hz, {num}kHz QNTY_RESOLUTION, // {num}{D}{P}{I}, {num}{D}{P}{C}{M} QNTY_REMS, // {num}rem ONLY, // MediaQueries NOT, // MediaQueries AND, // MediaQueries IMPORTANT, // "!{w}important" CHAR, // any other character and not ' or " ; } /** * Token predicate matchers. */ static final class Matchers { /** * Matches a CssToken.Type.CHAR with values ';' or '{' */ static final Predicate MATCH_SEMI_OPENBRACE = new Predicate() { public final boolean apply(final CssToken input) { return input.type == CssToken.Type.CHAR && (input.getChar() == ';' || input.getChar() == '{'); } }; /** * Matches a CssToken.Type.CHAR with values ';' or '}' */ static final Predicate MATCH_SEMI_CLOSEBRACE = new Predicate() { public final boolean apply(final CssToken input) { return input.type == CssToken.Type.CHAR && (input.getChar() == ';' || input.getChar() == '}'); } }; /** * Matches a CssToken.Type.CHAR with values ',' or '}' */ static final Predicate MATCH_COMMA_OPENBRACE = new Predicate() { public final boolean apply(final CssToken input) { return input.type == CssToken.Type.CHAR && (input.getChar() == ',' || input.getChar() == '{'); } }; /** * Matches a CssToken.Type.CHAR with value ':' */ static final Predicate MATCH_COLON = new Predicate() { public final boolean apply(final CssToken input) { return input.type == CssToken.Type.CHAR && (input.getChar() == ':'); } }; /** * Matches a CssToken.Type.CHAR with value '|' */ static final Predicate MATCH_PIPE = new Predicate() { public final boolean apply(final CssToken input) { return input.type == CssToken.Type.CHAR && (input.getChar() == '|'); } }; /** * Matches a CssToken.Type.CHAR with value '}' */ static final Predicate MATCH_CLOSEBRACE = new Predicate() { public final boolean apply(final CssToken input) { return input.type == CssToken.Type.CHAR && (input.getChar() == '}'); } }; /** * Matches a CssToken.Type.CHAR with value '{' */ static final Predicate MATCH_OPENBRACE = new Predicate() { public final boolean apply(final CssToken input) { return input.type == CssToken.Type.CHAR && (input.getChar() == '{'); } }; /** * Matches a CssToken.Type.CHAR with value '>', '+' or '~'. Note that S is the fourth * CSS combinator which is not matched here. */ static final Predicate MATCH_COMBINATOR_CHAR = new Predicate() { public final boolean apply(final CssToken input) { return input.type == CssToken.Type.CHAR && (input.getChar() == '>' || input.getChar() == '+' || input.getChar() == '~'); } }; /** * Matches a CssToken.Type.CHAR with value ';' */ static final Predicate MATCH_SEMI = new Predicate() { public final boolean apply(final CssToken input) { return input.type == CssToken.Type.CHAR && (input.getChar() == ';'); } }; /** * Matches a CssToken.Type.CHAR with value ',' */ static final Predicate MATCH_COMMA = new Predicate() { public final boolean apply(final CssToken input) { return input.type == CssToken.Type.CHAR && (input.getChar() == ','); } }; /** * Matches a CssToken.Type.CHAR with value ')' */ static final Predicate MATCH_CLOSEPAREN = new Predicate() { public final boolean apply(final CssToken input) { return input.type == CssToken.Type.CHAR && (input.getChar() == ')'); } }; /** * Matches a CssToken.Type.CHAR with value '(' */ static final Predicate MATCH_OPENPAREN = new Predicate() { public final boolean apply(final CssToken input) { return input.type == CssToken.Type.CHAR && (input.getChar() == '('); } }; /** * Matches a CssToken.Type.CHAR with value '*' or '|' */ static final Predicate MATCH_STAR_PIPE = new Predicate() { public final boolean apply(final CssToken input) { return input.type == CssToken.Type.CHAR && (input.getChar() == '*' || input.getChar() == '|'); } }; /** * Matches a CssToken.Type.CHAR with value '*' */ static final Predicate MATCH_STAR = new Predicate() { public final boolean apply(final CssToken input) { return input.type == CssToken.Type.CHAR && (input.getChar() == '*'); } }; /** * Matches a CssToken.Type.CHAR with value '[' */ static final Predicate MATCH_OPENSQUAREBRACKET = new Predicate() { public final boolean apply(final CssToken input) { return input.type == CssToken.Type.CHAR && (input.getChar() == '['); } }; /** * Matches a CssToken.Type.CHAR with value ']' */ static final Predicate MATCH_CLOSESQUAREBRACKET = new Predicate() { public final boolean apply(final CssToken input) { return input.type == CssToken.Type.CHAR && (input.getChar() == ']'); } }; /** * Matches CssToken.Type.IDENT and CssToken.Type.STRING */ static final Predicate MATCH_STRING_IDENT = new Predicate() { public final boolean apply(final CssToken input) { return input.type == CssToken.Type.IDENT || input.type == CssToken.Type.STRING; } }; static final Predicate MATCH_ATTRIBUTE_SELECTOR_MATCHERS = new Predicate() { public final boolean apply(final CssToken input) { return (input.type == CssToken.Type.CHAR && input.getChar() == '=') || input.type == CssToken.Type.INCLUDES || input.type == CssToken.Type.DASHMATCH || input.type == CssToken.Type.PREFIXMATCH || input.type == CssToken.Type.SUFFIXMATCH || input.type == CssToken.Type.SUBSTRINGMATCH; } }; } static class TokenBuilder { Type type; final int line; final int col; final int offset; final String systemID; private final StringBuilder chars; final List errors; private final boolean debug = false; private final CssErrorHandler errorListener; TokenBuilder(final String systemID, final int line, final int col, final int offset, final CssErrorHandler errorListener) { this.systemID = systemID; this.line = line; this.col = col; this.offset = offset; this.chars = new StringBuilder(); this.errors = Lists.newArrayList(); this.errorListener = errorListener; } TokenBuilder(final CssReader reader, final CssErrorHandler errorListener) { this(reader.systemID, reader.line, reader.col, reader.offset, errorListener); } TokenBuilder append(int ch) { chars.append((char) ch); return this; } TokenBuilder append(CharSequence str) { chars.append(str); return this; } int getLength() { return chars.length(); } char getLast() { return chars.charAt(chars.length() - 1); } TokenBuilder append(int[] chrs) { for (int chr : chrs) { append(chr); } return this; } /** * All lexer-time errors are funnelled through this method. Reported errors are stored in * the resulting CssToken. This method also passes the error on to a CssErrorHandler, * which can opt to rethrow to terminate the scanning. */ void error(CssErrorCode errorCode, CssReader reader, Object... arguments) throws CssException { CssScannerException cse = new CssScannerException(errorCode, CssLocation.create(reader), arguments); errors.add(cse); errorListener.error(cse); } CssToken asToken() { String value = chars.toString(); if (debug) { checkState(type != null); if (type == Type.STRING || type == Type.COMMENT) { // empty STRING and COMMENT tokens are not forbidden checkState(value != null); } else { checkState(!Strings.isNullOrEmpty(value)); } } return new CssToken(type, new CssLocation(line, col, offset, systemID), value, errors); } /** * Return the chars appended so far to this builder. */ int[] toArray() { int[] arr = new int[chars.length()]; for (int i = 0; i < chars.length(); i++) { arr[i] = chars.charAt(i); } return arr; } /** * Return the chars appended so far to this builder. */ @Override public String toString() { return chars.toString(); } } interface CssTokenConsumer { public void add(CssToken token); } } epubcheck-4.0.2/src/main/java/org/idpf/epubcheck/util/css/CssScanner.java0000644000175000017500000010223613017276730025532 0ustar eugeneeugene/* * Copyright (c) 2012 International Digital Publishing Forum * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package org.idpf.epubcheck.util.css; import com.google.common.base.Ascii; import com.google.common.base.CharMatcher; import com.google.common.base.Optional; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.primitives.Ints; import org.idpf.epubcheck.util.css.CssExceptions.CssErrorCode; import org.idpf.epubcheck.util.css.CssExceptions.CssException; import org.idpf.epubcheck.util.css.CssReader.Mark; import org.idpf.epubcheck.util.css.CssToken.CssTokenConsumer; import org.idpf.epubcheck.util.css.CssToken.TokenBuilder; import org.idpf.epubcheck.util.css.CssToken.Type; import java.io.IOException; import java.io.Reader; import java.util.List; import java.util.Map; import static com.google.common.base.Preconditions.*; import static org.idpf.epubcheck.util.css.CssExceptions.CssErrorCode.SCANNER_ILLEGAL_CHAR; import static org.idpf.epubcheck.util.css.CssExceptions.CssErrorCode.SCANNER_PREMATURE_EOF; /** * A lexical scanner for CSS. *

* Lexical errors are stored as attributes on the tokens in which they occurred. * The supplied CssErrorHandler is also invoked when a lexical error occurs, so * that clients can terminate the scanning by a rethrow. *

* * @author mgylling */ final class CssScanner { private final CssReader reader; private final CssToken.CssTokenConsumer consumer; private final CssEscapeMemoizer escapes; private TokenBuilder builder; private final CssErrorHandler errHandler; private final boolean debug = false; private char cur; private CssScanner(final Reader in, final String systemID, final CssErrorHandler errHandler, final CssTokenConsumer consumer, final int pushbackBufferSize) { this.consumer = checkNotNull(consumer); this.errHandler = checkNotNull(errHandler); this.reader = new CssReader(in, systemID, pushbackBufferSize); this.escapes = new CssEscapeMemoizer(reader); } CssScanner(Reader in, final String systemID, final CssErrorHandler errHandler, final CssTokenConsumer consumer) { this(in, systemID, errHandler, consumer, CssReader.DEFAULT_PUSHBACK_BUFFER_SIZE); } void scan() throws IOException, CssException { int ch; int next; while (true) { ch = reader.next(); if (ch == -1) { break; } builder = new TokenBuilder(reader, /* this, */errHandler); cur = (char) ch; next = reader.peek(); escapes.reset(builder); if (WHITESPACE.matches(cur)) { _ws(); } else if (cur == '-' && equals(reader.peek(2), CDC_LL)) { _cdc(); } else if (O.matches(cur) && matchesOrEOF(reader.at(4), WHITESPACE) && equals(reader.peek(3), ONLY_LL, true)) { _only(); } else if (N.matches(cur) && matchesOrEOF(reader.at(3), WHITESPACE) && equals(reader.peek(2), NOT_LL, true)) { _not(); } else if (A.matches(cur) && matchesOrEOF(reader.at(3), WHITESPACE) && equals(reader.peek(2), AND_LL, true)) { _and(); } else if (U.matches(cur) && equals(reader.peek(3), URI_LL, true)) { _uri(); } else if (U.matches(cur) && next == '+' && matchesOrEOF(reader.at(2), URANGESTART)) { _urange(); } else if (NMSTART.matches(cur) || cur == '-' && matches(next, NMSTART) || escapes.get(0).isPresent() || (cur == '-' && escapes.get(1).isPresent())) { _ident(); if (reader.peek() == '(') { _function(); } } else if (cur == '@' && ((matches(next, NMSTART) || escapes.get(1).isPresent()) || (next == '-' && (matches(reader.at(2), NMSTART)) || escapes.get( 2).isPresent()))) { _atkeyword(); } else if (NUMEND.matches(cur) || NUMSTART.matches(cur) && matches(next, NUMEND) || UNARY.matches(cur) && next == '.' && matches(reader.at(2), NUMEND)) { _num(); } else if (cur == '<' && equals(reader.peek(3), CDO_LL)) { _cdo(); } else if (cur == '/' && next == '*') { _comment(); } else if (QUOTES.matches(cur)) { _string(); } else if (cur == '#' && (matches(next, NMCHAR) || escapes.get(1).isPresent())) { _hashname(); } else if (cur == '.' && (matches(next, NMCHAR) || escapes.get(1).isPresent())) { _classname(); } else if (cur == '!' && forwardMatch("important", true, false)) { _important(); } else if (cur == '~' && next == '=') { _includes(); } else if (cur == '|' && next == '=') { _dashmatch(); } else if (cur == '^' && next == '=') { _prefixmatch(); } else if (cur == '$' && next == '=') { _suffixmatch(); } else if (cur == '*' && next == '=') { _substringmatch(); } else { builder.type = Type.CHAR; builder.append(cur); } consumer.add(builder.asToken()); } } /** * FUNCTION {ident}\( * * @throws IOException */ private void _function() throws IOException { // Assumes that builder already contains an IDENT if (debug) { checkArgument('(' == reader.peek()); } builder.type = Type.FUNCTION; builder.append(reader.next()); } /** * URI url\({w}{string}{w}\) | * url\({w}([!#$%&*-\[\]-~]|{nonascii}|{escape})*{w}\) */ private void _uri() throws IOException, CssException { /* * Need to run this before IDENT and FUNCTION since the first three * chars match IDENT and the entire trigger token matches FUNCTION. */ builder.append("url("); reader.forward(3); if (debug) { checkArgument('(' == reader.curChar || -1 == reader.peek()); } reader.forward(NOT_WHITESPACE); int uristart = reader.next(); if (-1 == uristart) { builder.error(SCANNER_PREMATURE_EOF, reader); } else if (QUOTES.matches((char) uristart)) { builder.append('\''); _string(); builder.append('\''); if (debug && builder.errors.size() < 1) { checkArgument(QUOTES.matches((char) reader.curChar)); } reader.forward(NOT_WHITESPACE); if (reader.peek() > -1) { reader.next(); // ')' } } else { // unquoted uri builder.append(uristart); if (debug) { checkArgument(NOT_WHITESPACE.matches((char) reader.curChar)); } StringBuilder buf = new StringBuilder(); while (true) { CssReader.Mark mark = reader.mark(); int ch = reader.next(); if (ch == -1) { builder.error(SCANNER_PREMATURE_EOF, reader); reader.unread(ch, mark); break; } else if (ch == ')') { break; } buf.append((char) ch); } builder.append(WHITESPACE.trimTrailingFrom(buf.toString())); } builder.append(')'); builder.type = Type.URI; if (')' != reader.curChar && builder.errors.size() == 0) { builder.error(CssErrorCode.SCANNER_ILLEGAL_SYNTAX, reader, reader.curChar); } } /** * string1 \"([^\n\r\f\\"]|\\{nl}|{escape})*\" * string2 \'([^\n\r\f\\']|\\{nl}|{escape})*\' */ private void _string() throws IOException, CssException { if (debug) { checkState(QUOTES.matches((char) reader.curChar)); } /* * Note: resulting token excludes start+end quotes */ builder.type = Type.STRING; int quoteType = reader.curChar; // in strings, we let escapes in general pass through while (true) { CssReader.Mark mark = reader.mark(); int ch = reader.next(); if (ch == -1) { builder.error(SCANNER_PREMATURE_EOF, reader); reader.unread(ch, mark); break; } else if (ch == '\n' || ch == '\r' || ch == '\f') { builder.error(SCANNER_ILLEGAL_CHAR, reader, "NEWLINE", Type.STRING.name()); reader.forward(TERMINATOR); break; } else if (ch == '\\') { int[] peek = reader.peek(2); int nl = isNewLine(peek); if (nl > 0) { // in strings, ignore backslash followed by a literal // newline reader.forward(nl); continue; } } else if (ch == quoteType && reader.prevChar != '\\') { break; } builder.append(ch); } if (debug && builder.errors.size() == 0) { checkState(QUOTES.matches((char) reader.curChar)); } } /** * ATKEYWORD '@'[-]?{nmstart}{nmchar}* nmstart [_a-z]|{nonascii}|{escape} * nmchar [_a-z0-9-]|{nonascii}|{escape} * * @throws CssException */ private void _atkeyword() throws IOException, CssException { if (debug) { checkState('@' == reader.curChar); } builder.type = Type.ATKEYWORD; builder.append(cur); // @ append(NMSTART); append(NMCHAR); if (debug) { int nxt = reader.peek(); checkState(NMCHAR.matches((char) reader.curChar)); if (nxt > -1) { checkState(!NMCHAR.matches((char) nxt)); } } } /** * IDENT [-]?{nmstart}{nmchar}* */ private void _ident() throws IOException, CssException { builder.type = Type.IDENT; Optional esc = escapes.get(0); // first NMSTART char or '-' if (esc.isPresent()) { int length = esc.get().render(builder, NMSTART); reader.forward(length); } else { builder.append(cur); } if (cur == '-' || (esc.isPresent() && esc.get().character == '-')) { // The NMSTART that matched in the main loop if clause if (escapes.get(1).isPresent()) { reader.forward(escapes.get(1).get().render(builder, NMSTART)); } else { builder.append(reader.next()); } } append(NMCHAR); } /** * DASHMATCH |= */ private void _dashmatch() throws IOException { if (debug) { checkState(reader.curChar == '|'); } builder.type = Type.DASHMATCH; builder.append("|="); reader.next(); if (debug) { checkState(reader.curChar == '='); } } /** * INCLUDES ~= */ private void _includes() throws IOException { if (debug) { checkState(reader.curChar == '~'); } builder.type = Type.INCLUDES; builder.append("~="); reader.next(); if (debug) { checkState(reader.curChar == '='); } } /** * PREFIXMATCH ^= */ private void _prefixmatch() throws IOException { if (debug) { checkState(reader.curChar == '^'); } builder.type = Type.PREFIXMATCH; builder.append("^="); reader.next(); if (debug) { checkState(reader.curChar == '='); } } /** * SUFFIXMATCH $= */ private void _suffixmatch() throws IOException { if (debug) { checkState(reader.curChar == '$'); } builder.type = Type.SUFFIXMATCH; builder.append("$="); reader.next(); if (debug) { checkState(reader.curChar == '='); } } /** * SUBSTRINGMATCH *= */ private void _substringmatch() throws IOException { if (debug) { checkState(reader.curChar == '*'); } builder.type = Type.SUBSTRINGMATCH; builder.append("*="); reader.next(); if (debug) { checkState(reader.curChar == '='); } } /** * HASHNAME "#"{name} name {nmchar}+ [_a-z0-9-]|{nonascii}|{escape} * * @throws CssException */ private void _hashname() throws IOException, CssException { if (debug) { checkState(reader.curChar == '#'); checkState(NMCHAR.matches((char) reader.peek()) || isNextEscape()); } builder.type = Type.HASHNAME; builder.append('#'); append(NMCHAR); } /** * CLASSNAME "."{name} This is not part of formal lexical constructs, but * seems to be safe to do at scanner level. name {nmchar}+ * [_a-z0-9-]|{nonascii}|{escape} * * @throws CssException */ private void _classname() throws IOException, CssException { if (debug) { checkState(reader.curChar == '.'); checkState(NMCHAR.matches((char) reader.peek()) || isNextEscape()); } builder.type = Type.CLASSNAME; builder.append('.'); append(NMCHAR); } /** * IMPORTANT !{w}important */ private void _important() { /* * Note that #lex needs to use #forwardMatch to maintain correct * position */ builder.type = Type.IMPORTANT; builder.append("!important"); } /** * Builds a comment token, excluding the leading and trailing comment * tokens. */ private void _comment() throws IOException, CssException { if (debug) { checkState(reader.curChar == '/' && reader.peek() == '*'); } /* * badcomment1 \/\*[^*]*\*+([^/*][^*]*\*+)* badcomment2 * \/\*[^*]*(\*+[^/*][^*]*)* comment \/\*[^*]*\*+([^/*][^*]*\*+)*\/ * * * "comments can not nest" just close at first occurrence of comment * close and let the grammar level handle reporting */ builder.type = Type.COMMENT; reader.next(); // '*' while (true) { Mark mark = reader.mark(); int ch = reader.next(); if (ch == -1) { builder.error(SCANNER_PREMATURE_EOF, reader); reader.unread(ch, mark); break; } else if (ch == '*' && reader.peek() == '/') { reader.next(); break; } else { builder.append(ch); } } if (debug && builder.errors.size() < 1) { checkState('/' == reader.curChar && '*' == reader.prevChar); } } private void _cdo() throws IOException { if (debug) { checkState('<' == reader.curChar); } builder.type = Type.CDO; builder.append(""); reader.forward(2); if (debug) { checkArgument('>' == reader.curChar && '-' == reader.prevChar); } } /** * Whitespace w ::= wc wc ::= #x9 | #xA | #xC | #xD | #x20 */ private void _ws() throws IOException { builder.type = Type.S; // no need to preserve exact whitespace // but append an S char to keep the token // contract of always having a value builder.append(' '); reader.forward(NOT_WHITESPACE); if (debug) { int nxt = reader.peek(); checkArgument(WHITESPACE.matches((char) reader.curChar)); if (nxt > -1) { checkArgument(NOT_WHITESPACE.matches((char) nxt)); } } } private static final int QNT_TOKEN_MAXLENGTH = 4; // update when adding more // to map private static final Map quantities = new ImmutableMap.Builder() .put(new int[]{'d', 'p', 'c', 'm'}, Type.QNTY_RESOLUTION) .put(new int[]{'d', 'p', 'p', 'x'}, Type.QNTY_RESOLUTION) .put(new int[]{'g', 'r', 'a', 'd'}, Type.QNTY_ANGLE) .put(new int[]{'t', 'u', 'r', 'n'}, Type.QNTY_ANGLE) .put(new int[]{'v', 'm', 'i', 'n'}, Type.QNTY_LENGTH) .put(new int[]{'d', 'e', 'g'}, Type.QNTY_ANGLE) .put(new int[]{'k', 'h', 'z'}, Type.QNTY_FREQ) .put(new int[]{'r', 'a', 'd'}, Type.QNTY_ANGLE) .put(new int[]{'r', 'e', 'm'}, Type.QNTY_REMS) .put(new int[]{'d', 'p', 'i'}, Type.QNTY_RESOLUTION) .put(new int[]{'e', 'm'}, Type.QNTY_EMS) .put(new int[]{'c', 'm'}, Type.QNTY_LENGTH) .put(new int[]{'p', 'x'}, Type.QNTY_LENGTH) .put(new int[]{'m', 'm'}, Type.QNTY_LENGTH) .put(new int[]{'i', 'n'}, Type.QNTY_LENGTH) .put(new int[]{'p', 't'}, Type.QNTY_LENGTH) .put(new int[]{'p', 'c'}, Type.QNTY_LENGTH) .put(new int[]{'c', 'h'}, Type.QNTY_LENGTH) .put(new int[]{'v', 'w'}, Type.QNTY_LENGTH) .put(new int[]{'v', 'h'}, Type.QNTY_LENGTH) .put(new int[]{'e', 'x'}, Type.QNTY_EXS) .put(new int[]{'m', 's'}, Type.QNTY_TIME) .put(new int[]{'h', 'z'}, Type.QNTY_FREQ) .put(new int[]{'%'}, Type.QNTY_PERCENTAGE) .put(new int[]{'s'}, Type.QNTY_TIME).build(); /** * Builds a UNICODE_RANGE token. */ private void _urange() throws IOException, CssException { if (debug) { checkArgument((reader.curChar == 'U' || reader.curChar == 'u') && reader.peek() == '+'); } builder.type = Type.URANGE; reader.next(); // '+' List cbuf = Lists.newArrayList(); int count = 0; while (true) { Mark mark = reader.mark(); int ch = reader.next(); if (ch == -1) { reader.unread(ch, mark); break; } if (URANGECHAR.matches((char) ch)) { count = ch == '-' ? 0 : count + 1; if (count == 7) { builder.error(CssErrorCode.SCANNER_ILLEGAL_URANGE, reader, "U+" + toString(cbuf) + (char) ch); } cbuf.add(ch); } else { reader.unread(ch, mark); break; } } builder.append("U+"); builder.append(Ints.toArray(cbuf)); } /** * Returns true if reader next() is the start of a valid escape sequence. * * @return whether or not the reader is at the start of a valid escape sequence. * @throws IOException */ private boolean isNextEscape() throws IOException { boolean result = false; Mark mark = reader.mark(); int ch = reader.next(); if (ch == '\\') { try { Optional esc = new CssEscape(reader, builder) .create(); result = esc.isPresent(); } catch (CssException ignore) { } } reader.unread(ch, mark); return result; } /** * Parse forward and append to the TokenBuilder field all characters that * match matcher, or until the next character is EOF. Escapes are included * verbatim if they don't match matcher, else literal. * * @throws IOException * @throws CssException */ private void append(CharMatcher matcher) throws IOException, CssException { append(matcher, builder); } /** * Parse forward and append to the supplied builder all characters that * match matcher, or until the next character is EOF. Escapes are included * verbatim if they don't match matcher, else literal. */ private void append(CharMatcher matcher, TokenBuilder builder) throws IOException, CssException { while (true) { Mark mark = reader.mark(); int ch = reader.next(); if (ch > -1 && matcher.matches((char) ch)) { builder.append(ch); } else if (ch == '\\') { Optional escape = new CssEscape(reader, builder) .create(); if (escape.isPresent()) { reader.forward(escape.get().render(builder, matcher)); } else { reader.unread(ch, mark); break; } } else { reader.unread(ch, mark); break; } } } /** * Check if a forward scan will equal given match string * * @param match The string to match * @param ignoreCase Whether case should be ignored * @param resetOnTrue Whether the reader should be reset on found match * @throws IOException */ private boolean forwardMatch(String match, boolean ignoreCase, boolean resetOnTrue) throws IOException { Mark mark = reader.mark(); List cbuf = Lists.newArrayList(); StringBuilder builder = new StringBuilder(); boolean result = true; boolean seenChar = false; while (true) { cbuf.add(reader.next()); char ch = (char) reader.curChar; if (reader.curChar == -1) { result = false; break; } else if (WHITESPACE.matches(ch)) { if (seenChar) { builder.append(ch); } } else { if (builder.length() == 0) { seenChar = true; } builder.append(ch); int index = builder.length() - 1; if (!ignoreCase && (builder.charAt(index) == match.charAt(index))) { result = false; break; } if (ignoreCase && (Ascii.toLowerCase(builder.charAt(index)) != Ascii .toLowerCase(match.charAt(index)))) { result = false; break; } } if (builder.length() == match.length()) { if (!match.equalsIgnoreCase(builder.toString())) { result = false; } break; } } if (!result || resetOnTrue) { reader.unread(cbuf, mark); } return result; } private String toString(List ints) { StringBuilder builder = new StringBuilder(); for (int i : ints) { builder.append((char) i); } return builder.toString(); } /** * Like Arrays.equals, but does not return true when both are null. */ private static boolean equals(int[] a, int[] b) { return equals(a, b, false); } /** * Like Arrays.equals, but does not return true when both are null. * * @param ignoreAsciiCase If true, ascii case differences are ignored. */ private static boolean equals(int[] a, int[] b, boolean ignoreAsciiCase) { if ((a == null && b == null) || a == null || b == null || (a.length != b.length)) { return false; } for (int i = 0; i < a.length; i++) { if (!ignoreAsciiCase) { if (a[i] != b[i]) { return false; } } else { if (a[i] == -1 && b[i] == -1) { } else if (a[i] == -1 || b[i] == -1) { return false; } else if (Ascii.toLowerCase((char) a[i]) != Ascii .toLowerCase((char) b[i])) { return false; } } } return true; } /** * Return true if ch represents EOF (-1), or if it matches matcher. */ private static boolean matchesOrEOF(final int ch, CharMatcher matcher) { return ch == -1 || matcher.matches((char) ch); } /** * Return true if ch matches matcher, false if not or if ch represents EOF * (-1). */ private static boolean matches(final int ch, CharMatcher matcher) { return ch != -1 && matcher.matches((char) ch); } /** * Determine whether a sequence of chars begin with a CSS newline. * * @param chars An array with minimum two characters * @return 0 if there is no newline, else 1 or 2, representing the newline * length in characters. */ static int isNewLine(int[] chars) { checkArgument(chars.length > 1); // nl \n|\r\n|\r|\f if (chars[0] == '\r' && chars[1] == '\n') { return 2; } else if (chars[0] == '\n' || chars[0] == '\r' || chars[0] == '\f') { return 1; } return 0; } static final CharMatcher WHITESPACE = CharMatcher.anyOf(" \t\n\r\f") .precomputed(); private static final CharMatcher NOT_WHITESPACE = WHITESPACE.negate().precomputed(); static final CharMatcher QUOTES = CharMatcher.anyOf("\"'").precomputed(); private static final CharMatcher U = CharMatcher.anyOf("Uu").precomputed(); private static final CharMatcher O = CharMatcher.anyOf("Oo").precomputed(); private static final CharMatcher N = CharMatcher.anyOf("Nn").precomputed(); private static final CharMatcher A = CharMatcher.anyOf("Aa").precomputed(); /** * {nmstart} excluding {escape} */ private static final CharMatcher NMSTART = CharMatcher .inRange('A', 'Z') .or(CharMatcher.inRange('a', 'z').or( CharMatcher.is('_').or( CharMatcher.inRange('\u0080', '\uFFFF')))) .precomputed(); /** * {nmchar} excluding {escape} */ private static final CharMatcher NMCHAR = NMSTART.or( CharMatcher.inRange('0', '9').or(CharMatcher.is('-'))) .precomputed(); /** * start of quantities that followed after {num} excluding {escape} */ private static final CharMatcher QNTSTART = NMSTART.or(CharMatcher.is('%')) .precomputed(); /** * {num} end char cannot be period */ private static final CharMatcher NUMEND = CharMatcher.inRange('0', '9') .precomputed(); /** * {num} */ private static final CharMatcher NUM = NUMEND.or(CharMatcher.is('.')) .precomputed(); private static final CharMatcher UNARY = CharMatcher.anyOf("+-") .precomputed(); /** * {num} start char can be unary operators */ private static final CharMatcher NUMSTART = NUM.or(UNARY).precomputed(); static final CharMatcher HEXCHAR = CharMatcher.anyOf( "AaBbCcDdEeFf0123456789").precomputed(); private static final CharMatcher URANGESTART = HEXCHAR.or(CharMatcher .anyOf("?")); private static final CharMatcher URANGECHAR = HEXCHAR.or(CharMatcher .anyOf("?-")); static final CharMatcher TERMINATOR = CharMatcher.anyOf(";}{"); /** * The three last characters in the CDO token */ private static final int[] CDO_LL = new int[]{'!', '-', '-'}; // /** * The three last characters in the URI start token */ private static final int[] URI_LL = new int[]{'r', 'l', '('}; /** * The three last characters in the ONLY token */ private static final int[] ONLY_LL = new int[]{'n', 'l', 'y'}; /** * The three last characters in the NOT token */ private static final int[] NOT_LL = new int[]{'o', 't'}; /** * The three last characters in the AND token */ private static final int[] AND_LL = new int[]{'n', 'd'}; /** * Memoizer for escapes at forward reader positions. Owner must invoke * reset() every time the reader position changes (excluding closured * unreads). */ static class CssEscapeMemoizer { private final Map> map = Maps.newHashMap(); private TokenBuilder errFunnel; private final CssReader reader; CssEscapeMemoizer(final CssReader reader) { this.reader = reader; } CssEscapeMemoizer reset(final TokenBuilder errFunnel) { map.clear(); this.errFunnel = errFunnel; return this; } Optional get(final int n) throws IOException { checkNotNull(errFunnel); if (!map.containsKey(n)) { map.put(n, create(n)); } return map.get(n); } private Optional create(int n) throws IOException { List cbuf = Lists.newArrayList(); Mark mark = reader.mark(); for (int i = 0; i < n; i++) { int ch = reader.next(); cbuf.add(ch); if (ch == -1) { reader.unread(cbuf, mark); return CssEscape.ABSENT; } } if (reader.curChar == '\\') { try { Optional esc = new CssEscape(reader, errFunnel) .create(); reader.unread(cbuf, mark); return esc; } catch (CssException ignore) { } } reader.unread(cbuf, mark); return CssEscape.ABSENT; } } } epubcheck-4.0.2/src/main/java/org/idpf/epubcheck/util/css/Messages.java0000644000175000017500000000717113017276730025241 0ustar eugeneeugene/* * Copyright (c) 2012 International Digital Publishing Forum * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package org.idpf.epubcheck.util.css; import com.google.common.base.Charsets; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.URL; import java.net.URLConnection; import java.text.MessageFormat; import java.util.Locale; import java.util.MissingResourceException; import java.util.PropertyResourceBundle; import java.util.ResourceBundle; import java.util.ResourceBundle.Control; final class Messages { private static final String BUNDLE_NAME = "org.idpf.epubcheck.util.css.messages"; //$NON-NLS-1$ private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle.getBundle(BUNDLE_NAME, Locale.getDefault(), new UTF8Control()); static String get(String key) { try { return RESOURCE_BUNDLE.getString(key); } catch (MissingResourceException e) { return key; } } static String get(String key, Object... arguments) { try { return MessageFormat.format(RESOURCE_BUNDLE.getString(key), arguments); } catch (MissingResourceException e) { return key; } } private static class UTF8Control extends Control { public ResourceBundle newBundle (String baseName, Locale locale, String format, ClassLoader loader, boolean reload) throws IllegalAccessException, InstantiationException, IOException { // The below is a copy of the default implementation. String bundleName = toBundleName(baseName, locale); String resourceName = toResourceName(bundleName, "properties"); //$NON-NLS-1$ ResourceBundle bundle = null; InputStream stream = null; if (reload) { URL url = loader.getResource(resourceName); if (url != null) { URLConnection connection = url.openConnection(); if (connection != null) { connection.setUseCaches(false); stream = connection.getInputStream(); } } } else { stream = loader.getResourceAsStream(resourceName); } if (stream != null) { try { // Only this line is changed to make it to read properties files as UTF-8. bundle = new PropertyResourceBundle( new BufferedReader( new InputStreamReader(stream, Charsets.UTF_8))); } finally { stream.close(); } } return bundle; } } private Messages() { } } epubcheck-4.0.2/src/main/java/org/idpf/epubcheck/util/css/CssSource.java0000644000175000017500000000551713017276730025405 0ustar eugeneeugene/* * Copyright (c) 2012 International Digital Publishing Forum * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package org.idpf.epubcheck.util.css; import java.io.UnsupportedEncodingException; import com.google.common.base.Objects; import java.io.*; import static com.google.common.base.Preconditions.checkNotNull; /** * Represents a CSS source. * * @author mgylling */ public class CssSource { private final String systemID; private final CssInputStream stream; public CssSource(String systemID, InputStream input) throws IOException { this.systemID = checkNotNull(systemID); this.stream = checkNotNull(input) instanceof CssInputStream ? (CssInputStream) input : new CssInputStream(input); } public CssSource(String systemID, CharSequence input) throws IOException { this.systemID = checkNotNull(systemID); this.stream = new CssInputStream(new ByteArrayInputStream(input.toString().getBytes())); } public String getSystemID() { return systemID; } public CssInputStream getInputStream() { return stream; } public Reader newReader() { String enc = "utf-8"; if (stream.bom.isPresent()) { enc = stream.bom.get(); } else if (stream.charset.isPresent()) { enc = stream.charset.get(); } try { return new BufferedReader(new InputStreamReader(stream, enc)); } catch (UnsupportedEncodingException e) { //TODO log/errout return new BufferedReader(new InputStreamReader(stream)); } } @Override public String toString() { return Objects.toStringHelper(this).addValue(systemID).toString(); } @Override public boolean equals(Object obj) { if (obj instanceof CssSource) { CssSource cs = (CssSource) obj; return cs.systemID.equals(this.systemID); } return false; } } epubcheck-4.0.2/src/main/java/org/idpf/epubcheck/util/css/CssTokenList.java0000644000175000017500000001276113017276730026060 0ustar eugeneeugene/* * Copyright (c) 2012 International Digital Publishing Forum * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package org.idpf.epubcheck.util.css; import com.google.common.base.Predicate; import org.idpf.epubcheck.util.css.CssToken.Type; import java.util.ArrayList; import java.util.List; import java.util.NoSuchElementException; import static com.google.common.base.Preconditions.checkNotNull; final class CssTokenList extends ArrayList { public CssTokenList() { this(2048); } private CssTokenList(int initSize) { super(initSize); } CssTokenIterator iterator(final Predicate filter) { return new CssTokenIterator(filter, this); } class CssTokenIterator { private final Predicate filter; final List list; int next; // index of next element to return int lastRet = -1; // index of last element returned CssToken last = null; // last token returned /** * Constructor. * * @param filter A filter Predicate that is applied to all tokens unless * another Predicate is passed using #next(Predicate) */ CssTokenIterator(final Predicate filter, List list) { this.filter = checkNotNull(filter); this.list = list; } /** * Get the next token in the token list. This method uses the * constructor filter. */ CssToken next() { return next(filter); } /** * Get the next token in the token list that matches the given filter, * or NoSuchElementException if no more tokens exist. */ CssToken next(final Predicate filter) { while (true) { int i = next; if (i >= size()) { throw new NoSuchElementException(); } next = i + 1; CssToken tk = get(lastRet = i); if (filter.apply(tk)) { last = tk; return tk; } } } /** * Using the constructor filter. */ boolean hasNext() { return hasNext(filter); } /** * Using the supplied filter. */ boolean hasNext(final Predicate filter) { int i = next; while (true) { if (i == size()) { return false; } if (filter.apply(get(i))) { return true; } i++; } } /** * Get the next token without advancing the iterators position. */ public CssToken peek() { return peek(filter); } /** * Get the next token without advancing the iterators position. */ public CssToken peek(Predicate filter) { int _next = next; int _lastRet = lastRet; CssToken _last = last; if (hasNext(filter)) { CssToken tk = next(filter); next = _next; lastRet = _lastRet; last = _last; return tk; } throw new NoSuchElementException(); } /** * Get the list index of the last element returned prior to filtering, * or -1 if no element has yet been returned. */ int index() { return lastRet; } /** * Get the filter that is currently being used for invocations of next() * and hasNext() */ Predicate filter() { return filter; } } static final class Filters { /** * A filter that filters whitespace and comments */ static final Predicate FILTER_S_CMNT = new Predicate() { public boolean apply(final CssToken input) { return !(input.type == Type.S || input.type == Type.COMMENT); } }; /** * A filter that filters whitespace, comments, CDO and CDC */ static final Predicate FILTER_S_CMNT_CDO_CDC = new Predicate() { public boolean apply(final CssToken input) { return !(input.type == Type.S || input.type == Type.COMMENT || input.type == Type.CDO || input.type == Type.CDC); } }; /** * A filter that filters nothing. */ static final Predicate FILTER_NONE = new Predicate() { public boolean apply(final CssToken input) { return true; } }; } static final class PrematureEOFException extends RuntimeException { private static final long serialVersionUID = 343701466381708884L; } private static final long serialVersionUID = 924068097174100851L; } epubcheck-4.0.2/src/main/java/org/idpf/epubcheck/util/css/CssParser.java0000644000175000017500000005225413017276730025401 0ustar eugeneeugene/* * Copyright (c) 2012 International Digital Publishing Forum * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package org.idpf.epubcheck.util.css; import static com.google.common.base.Preconditions.*; import static org.idpf.epubcheck.util.css.CssExceptions.CssErrorCode.*; import static org.idpf.epubcheck.util.css.CssToken.Matchers.*; import static org.idpf.epubcheck.util.css.CssTokenList.Filters.FILTER_S_CMNT; import static org.idpf.epubcheck.util.css.CssTokenList.Filters.FILTER_S_CMNT_CDO_CDC; import java.io.IOException; import java.io.Reader; import java.util.List; import java.util.NoSuchElementException; import org.idpf.epubcheck.util.css.CssExceptions.CssException; import org.idpf.epubcheck.util.css.CssExceptions.CssGrammarException; import org.idpf.epubcheck.util.css.CssGrammar.CssAtRule; import org.idpf.epubcheck.util.css.CssGrammar.CssConstruct; import org.idpf.epubcheck.util.css.CssGrammar.CssConstructFactory; import org.idpf.epubcheck.util.css.CssGrammar.CssDeclaration; import org.idpf.epubcheck.util.css.CssGrammar.CssSelector; import org.idpf.epubcheck.util.css.CssGrammar.CssSelectorCombinator; import org.idpf.epubcheck.util.css.CssGrammar.CssSelectorConstructFactory; import org.idpf.epubcheck.util.css.CssGrammar.CssSimpleSelectorSequence; import org.idpf.epubcheck.util.css.CssToken.CssTokenConsumer; import org.idpf.epubcheck.util.css.CssTokenList.CssTokenIterator; import org.idpf.epubcheck.util.css.CssTokenList.PrematureEOFException; import com.google.common.base.Predicate; import com.google.common.collect.Lists; /** * A CSS parser. * * @author mgylling */ public final class CssParser { private final boolean debug = false; /* * TODOs * - pseudo-elements are restricted to one per selector and * occur only in the last simple_selector_sequence (testParserSelectorsFunctionalPseudoInvalid001). * - baduri 1 and 2 and 3 #buildURI * - check uc range in tokenbuilder#append * - cssreader#forward should be fully escape aware */ /** * Parse a CSS document. */ public void parse(final CssSource source, final CssErrorHandler err, final CssContentHandler doc) throws IOException, CssException { parse(source.newReader(), source.getSystemID(), err, doc); } /** * Parse a CSS document. */ public void parse(final Reader reader, final String systemID, final CssErrorHandler err, final CssContentHandler doc) throws IOException, CssException { CssTokenIterator iter = scan(reader, systemID, err); doc.startDocument(); while (iter.hasNext(FILTER_S_CMNT_CDO_CDC)) { CssToken tk = iter.next(FILTER_S_CMNT_CDO_CDC); try { if (tk.type == CssToken.Type.ATKEYWORD) { handleAtRule(tk, iter, doc, err); if (debug) { checkArgument(MATCH_SEMI_CLOSEBRACE.apply(iter.last)); } } else { handleRuleSet(tk, iter, doc, err); if (debug) { checkArgument(MATCH_CLOSEBRACE.apply(iter.last)); } } } catch (PrematureEOFException te) { // The subroutines report premature EOF to ErrHandler // on occurrence; if the listener rethrows it will // be a CssException so we don't catch it here. break; } } doc.endDocument(); } /** * Parse a CSS style attribute. */ public void parseStyleAttribute(final Reader reader, String systemID, final CssErrorHandler err, final CssContentHandler doc) throws IOException, CssException { CssTokenIterator iter = scan(reader, systemID, err); doc.startDocument(); while (iter.hasNext()) { CssToken tk = iter.next(); if(MATCH_SEMI.apply(tk)) { continue; //starting with ';' is allowed, Issue 238 } try { CssDeclaration decl = handleDeclaration(tk, iter, doc, err, true); if (decl != null) { doc.declaration(decl); } else { // #handleDeclaration has issued errors return; } } catch (PrematureEOFException te) { // The subroutines report premature EOF to ErrHandler // on occurrence; if the listener rethrows it will // be a CssException so we don't catch it here. break; } } doc.endDocument(); } private CssTokenIterator scan(Reader reader, String systemID, CssErrorHandler err) throws IOException, CssException { final CssTokenList tokens = new CssTokenList(); new CssScanner(reader, systemID, err, new CssTokenConsumer() { public void add(final CssToken token) { tokens.add(token); } }).scan(); return tokens.iterator(FILTER_S_CMNT); // default filter } /** * With the start token expected to be the first token of a selector group, * create and issue the group, then invoke handleDeclarationBlock. At exit * the last token returned from the iterator is expected to be '}'. */ private void handleRuleSet(CssToken start, final CssTokenIterator iter, final CssContentHandler doc, CssErrorHandler err) throws CssException { char errChar = '{'; try { List selectors = handleSelectors(start, iter, err); errChar = '}'; if (selectors == null) { // handleSelectors() has issued errors, we forward iter.next(MATCH_CLOSEBRACE); return; } if (debug) { checkState(iter.last.getChar() == '{'); checkState(!selectors.isEmpty()); } doc.selectors(selectors); handleDeclarationBlock(iter.next(), iter, doc, err); doc.endSelectors(selectors); } catch (NoSuchElementException nse) { err.error(new CssGrammarException(GRAMMAR_PREMATURE_EOF, iter.last.location, "'" + errChar + "'")); throw new PrematureEOFException(); } if (debug) { checkState(iter.last.getChar() == '}'); } } /** * With start token being the first non-ignorable token inside the * declaration block, iterate issuing CssDeclaration objects until the block * ends. */ private void handleDeclarationBlock(CssToken start, CssTokenIterator iter, final CssContentHandler doc, CssErrorHandler err) throws CssException { while (true) { if (MATCH_CLOSEBRACE.apply(start)) { return; } CssDeclaration decl = handleDeclaration(start, iter, doc, err, false); try { if (decl != null) { doc.declaration(decl); if (debug) { checkState(MATCH_SEMI_CLOSEBRACE.apply(iter.last)); } // continue or return: we may be at "; next decl" or "}" or ";}" if (MATCH_CLOSEBRACE.apply(iter.last)) { return; } else if (MATCH_SEMI.apply(iter.last) && MATCH_CLOSEBRACE.apply(iter.peek())) { iter.next(); return; } else { if (debug) { checkState(MATCH_SEMI.apply(iter.last)); } // we have ';', expect another decl start = iter.next(); // first token after ';' } } else { // #handleDeclaration returned null to signal error // #handleDeclaration has issued errors, we forward start = iter.next(MATCH_SEMI_CLOSEBRACE); if (MATCH_SEMI.apply(start)) { start = iter.next(); } } } catch (NoSuchElementException nse) { err.error(new CssGrammarException(GRAMMAR_PREMATURE_EOF, iter.last.location, "';' " + Messages.get("or") + " '}'")); throw new PrematureEOFException(); } } } /** * With start expected to be an IDENT token representing the property name, * build the declaration and return after hitting ';' or '}'. On error, * issue to errhandler, return null, caller forwards. */ private CssDeclaration handleDeclaration(CssToken name, CssTokenIterator iter, CssContentHandler doc, CssErrorHandler err, boolean isStyleAttribute) throws CssException { if (name.type != CssToken.Type.IDENT) { err.error(new CssGrammarException(GRAMMAR_EXPECTING_TOKEN, name.location, name .getChars(), Messages.get("a_property_name"))); return null; } CssDeclaration declaration = new CssDeclaration(name.getChars(), name.location); try { if (!MATCH_COLON.apply(iter.next())) { err.error(new CssGrammarException(GRAMMAR_EXPECTING_TOKEN, name.location, iter.last .getChars(), ":")); return null; } } catch (NoSuchElementException nse) { err.error(new CssGrammarException(GRAMMAR_PREMATURE_EOF, iter.last.location, ":")); throw new PrematureEOFException(); } try { while (true) { CssToken value = iter.next(); if (MATCH_SEMI_CLOSEBRACE.apply(value)) { if (declaration.components.size() < 1) { err.error(new CssGrammarException(GRAMMAR_EXPECTING_TOKEN, iter.last.location, value.getChar(), Messages .get("a_property_value"))); return null; } else { return declaration; } } else { if (!handlePropertyValue(declaration, value, iter, isStyleAttribute)) { err.error(new CssGrammarException(GRAMMAR_UNEXPECTED_TOKEN, iter.last.location, iter.last.getChars())); return null; } else { if (isStyleAttribute && !iter.hasNext()) { return declaration; } } } } } catch (NoSuchElementException nse) { err.error(new CssGrammarException(GRAMMAR_PREMATURE_EOF, iter.last.location, "';' " + Messages.get("or") + " '}'")); throw new PrematureEOFException(); } } /** * Append property value components to declaration.value, return false if * fail with iter.last at the the token which caused the fail. */ private boolean handlePropertyValue(CssDeclaration declaration, CssToken start, CssTokenIterator iter, boolean isStyleAttribute) { // we dont worry about EOF here, throw to caller while (true) { if (start.type == CssToken.Type.IMPORTANT) { declaration.important = true; } else { CssConstruct cc = CssConstructFactory.create( start, iter, MATCH_SEMI_CLOSEBRACE, ContextRestrictions.PROPERTY_VALUE); if (cc == null) { return false; } else { declaration.components.add(cc); } } //if isStyleAttribute, then parse as declaration-list grammar, //i.e. no braces if ((isStyleAttribute && !iter.hasNext()) || (MATCH_SEMI.apply(iter.peek())) || (!isStyleAttribute && MATCH_CLOSEBRACE.apply(iter.peek()))) { return declaration.components.size() > 0; } else { start = iter.next(); } } } /** * With start inparam being the first significant token in a selector, build * the selector group (aka comma separated selectors), expected return when * iter.last is '{'. On error, issue to errorlistener, and return * (caller will forward). * * @return A syntactically valid CssSelector list, or null if fail. * @throws CssException */ private List handleSelectors(CssToken start, CssTokenIterator iter, CssErrorHandler err) throws CssException { List selectors = Lists.newArrayList(); boolean end = false; while (true) { // comma loop CssSelector selector = new CssSelector(start.location); while (true) { //combinator loop CssSimpleSelectorSequence seq = CssSelectorConstructFactory .createSimpleSelectorSequence(start, iter, err); if (seq == null) { //errors already issued return null; } selector.components.add(seq); int idx = iter.index(); start = iter.next(); if (MATCH_OPENBRACE.apply(start)) { end = true; break; } if (MATCH_COMMA.apply(start)) { break; } CssSelectorCombinator comb = CssSelectorConstructFactory.createCombinator(start, iter, err); if (comb != null) { selector.components.add(comb); start = iter.next(); } else if (iter.list.get(idx + 1).type == CssToken.Type.S) { selector.components.add(new CssSelectorCombinator(' ', start.location)); } else { err.error(new CssGrammarException(GRAMMAR_UNEXPECTED_TOKEN, iter.last.location, iter.last.chars)); return null; } } //combinator loop selectors.add(selector); if (end) { break; } if (debug) { checkState(MATCH_COMMA.apply(start)); } start = iter.next(); } // comma loop return selectors; } /** * With start token required to be an ATKEYWORD, collect at-rule parameters if * any, and if the at-rule has a block, invoke those handlers. */ private void handleAtRule(CssToken start, CssTokenIterator iter, CssContentHandler doc, CssErrorHandler err) throws CssException { if (debug) { checkArgument(start.type == CssToken.Type.ATKEYWORD); checkArgument(iter.index() == iter.list.indexOf(start)); checkArgument(iter.filter() == FILTER_S_CMNT); } CssAtRule atRule = new CssAtRule(start.getChars(), start.location); CssToken tk; try { while (true) { tk = iter.next(); if (MATCH_SEMI_OPENBRACE.apply(tk)) { // ';' or '{', expected end atRule.hasBlock = tk.getChar() == '{'; break; } else { CssConstruct param = handleAtRuleParam(tk, iter, doc, err); if (param == null) { // issue error, forward, then return err.error(new CssGrammarException(GRAMMAR_UNEXPECTED_TOKEN, iter.last.location, iter.last.chars)); //skip to atrule closebrace, ignoring any inner blocks int stack = 0; while (true) { CssToken tok = iter.next(); if (MATCH_SEMI.apply(tok) && stack == 0) { return; //a non-block at rule } else if (MATCH_OPENBRACE.apply(tok)) { stack++; } else if (MATCH_CLOSEBRACE.apply(tok)) { if (stack == 1) { break; } stack--; } } return; } else { atRule.components.add(param); } } } } catch (NoSuchElementException nse) { // UAs required to close any open constructs on premature EOF doc.startAtRule(atRule); err.error(new CssGrammarException(GRAMMAR_PREMATURE_EOF, iter.last.location, "';' " + Messages.get("or") + " '{'")); doc.endAtRule(atRule.getName().get()); throw new PrematureEOFException(); } if (debug) { checkArgument(MATCH_SEMI_OPENBRACE.apply(iter.last)); checkArgument(iter.filter() == FILTER_S_CMNT); } // ending up here only on expected end doc.startAtRule(atRule); if (atRule.hasBlock) { try { if (hasRuleSet(atRule, iter)) { while (!MATCH_CLOSEBRACE.apply(iter.next())) { if (iter.last.type == CssToken.Type.ATKEYWORD) { handleAtRule(iter.last, iter, doc, err); } else { handleRuleSet(iter.last, iter, doc, err); } } } else { handleDeclarationBlock(iter.next(), iter, doc, err); } } catch (NoSuchElementException nse) { err.error(new CssGrammarException(GRAMMAR_PREMATURE_EOF, iter.last.location, "'}'")); doc.endAtRule(atRule.name.get()); throw new PrematureEOFException(); } } doc.endAtRule(atRule.name.get()); } /** * With inparam token being the first token of an atrule param, create the * construct and return it. * * @return A CssConstruct, or null if fail. */ private CssConstruct handleAtRuleParam(CssToken start, CssTokenIterator iter, CssContentHandler doc, CssErrorHandler err) { return CssConstructFactory.create(start, iter, MATCH_SEMI_OPENBRACE, ContextRestrictions.ATRULE_PARAM); } /** * With iter.last at '{', discover the at-rule type. The * contents is a ruleset if '{' comes before ';' or '}'. */ private boolean hasRuleSet(CssAtRule atRule, CssTokenIterator iter) { int debugIndex; if (debug) { checkArgument(iter.last.getChar() == '{'); debugIndex = iter.index(); } List list = iter.list; for (int i = iter.index() + 1; i < list.size(); i++) { CssToken tk = list.get(i); if (MATCH_OPENBRACE.apply(tk)) { return true; } else if (MATCH_SEMI_CLOSEBRACE.apply(tk)) { return false; } } if (debug) { checkState(iter.last.getChar() == '{'); checkState(iter.index() == debugIndex); } return false; } static final class ContextRestrictions { /** * A context restriction for the contents of a function. */ static final Predicate FUNCTION = new Predicate() { public boolean apply(CssConstruct cc) { checkNotNull(cc); return cc.type != CssConstruct.Type.ATRULE; //TODO; } }; /** * A context restriction for at-rule parameters. */ static final Predicate ATRULE_PARAM = new Predicate() { public boolean apply(CssConstruct cc) { checkNotNull(cc); return true; // atrule param space allows SYMBOL (aka DELIM) too } }; /** * A context restriction for property values. */ static final Predicate PROPERTY_VALUE = new Predicate() { public boolean apply(CssConstruct cc) { checkNotNull(cc); return cc.type != CssConstruct.Type.ATRULE; //TODO } }; /** * A context restriction for the value segment of an attribute selector ([name+match+value]). */ static final Predicate ATTRIBUTE_SELECTOR_VALUE = new Predicate() { public boolean apply(final CssConstruct cc) { checkNotNull(cc); return cc.type == CssConstruct.Type.KEYWORD || cc.type == CssConstruct.Type.STRING; } }; /** * A context restriction for elements inside a functional pseudo. */ static final Predicate PSEUDO_FUNCTIONAL = new Predicate() { public boolean apply(CssConstruct cc) { checkNotNull(cc); return cc.type == CssConstruct.Type.KEYWORD || cc.type == CssConstruct.Type.STRING || cc.type == CssConstruct.Type.QUANTITY || (cc.type == CssConstruct.Type.SYMBOL && cc.toCssString().equals("+")) || (cc.type == CssConstruct.Type.SYMBOL && cc.toCssString().equals("-")) ; } }; /** * A context restriction for elements inside a negation pseudo. */ static final Predicate PSEUDO_NEGATION = new Predicate() { public boolean apply(final CssConstruct cc) { checkNotNull(cc); return cc.type == CssConstruct.Type.TYPE_SELECTOR || cc.type == CssConstruct.Type.HASHNAME || cc.type == CssConstruct.Type.CLASSNAME || (cc.type == CssConstruct.Type.ATTRIBUTE_SELECTOR) || (cc.type == CssConstruct.Type.PSEUDO) ; } }; } } epubcheck-4.0.2/src/main/java/org/idpf/epubcheck/util/css/CssReader.java0000644000175000017500000002107313017276730025342 0ustar eugeneeugene/* * Copyright (c) 2012 International Digital Publishing Forum * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package org.idpf.epubcheck.util.css; import com.google.common.base.CharMatcher; import com.google.common.base.Objects; import com.google.common.collect.Lists; import com.google.common.primitives.Ints; import java.io.BufferedReader; import java.io.IOException; import java.io.Reader; import java.util.List; import static com.google.common.base.Preconditions.*; /** * A wrapper around java.io.Reader with a pushback buffer, offset and * line+column tracking. This is used by CssScanner. * * @author mgylling */ final class CssReader { static final int DEFAULT_PUSHBACK_BUFFER_SIZE = 8096; private final int[] buf; private int pos; private final Reader in; private int prevLine = 1; /** * The systemID of the resource being read. If the resource being read * is virtual the value is set to CssLocaton.NO_SID */ final String systemID; /** * The char that this reader is currently positioned at, or -1 if EOF is * reached. */ int curChar = 0; /** * The previous char, or 0 if curChar is the first character in the resource * being read. */ int prevChar = 0; /** * The offset (in characters) of prevChar from the start of the resource * being read. */ int offset = 0; /** * The current line in the resource being read */ int line = 1; /** * The current column in the resource being read */ int col = 1; CssReader(Reader reader, String systemID, int pushbackSize) { this.in = checkNotNull(reader) instanceof BufferedReader ? reader : new BufferedReader(reader); this.systemID = checkNotNull(systemID); checkArgument(pushbackSize >= 1); this.pos = pushbackSize; this.buf = new int[pushbackSize]; } /** * Returns the next character in the stream and advances the readers * position. If there are no more characters, -1 is returned the first time * this method is invoked in that state; multiple invocations at EOF will * yield an IllegalStateException. */ int next() throws IOException { prevChar = curChar; checkState(prevChar > -1); if (pos < buf.length) { curChar = buf[pos++]; } else { curChar = in.read(); } offset++; /* * Handle line and col * lf=\n, cr=\r */ if (curChar == '\r' || curChar == '\n') { if (curChar == '\n' && prevChar == '\r') { //second char in a windows CR+LF } else { prevLine = line; line++; } } else if (prevLine < line) { col = 1; prevLine = line; } else { if (prevChar != 0) { col++; } } return curChar; } /** * Returns the next character in the stream without advancing the readers * position. If there are no more characters, -1 is returned. */ int peek() throws IOException { Mark m = mark(); int ch = next(); unread(ch, m); return ch; } /** * Returns the the next n characters in the stream without advancing the * readers position. * * @param n the number of characters to read * @return An array with guaranteed length n, with -1 being the value for * all elements at and after EOF. * @throws IOException */ int[] peek(int n) throws IOException { int[] buf = new int[n]; Mark m = mark(); boolean seenEOF = false; for (int i = 0; i < buf.length; i++) { if (!seenEOF) { buf[i] = next(); } else { buf[i] = -1; } if (buf[i] == -1) { seenEOF = true; } } if (!seenEOF) { unread(buf, m); } else { List ints = Lists.newArrayList(); for (int aBuf : buf) { ints.add(aBuf); if (aBuf == -1) { break; } } unread(ints, m); } return buf; } /** * Peek and return the character at position n from current position, or -1 * if EOF is reached before or at that position. */ int at(int n) throws IOException { Mark mark = mark(); List cbuf = Lists.newArrayList(); for (int i = 0; i < n; i++) { cbuf.add(next()); if (curChar == -1) { break; } } unread(cbuf, mark); return cbuf.get(cbuf.size() - 1); } /** * Reads forward and returns the the next n characters in the stream. Escapes * are returned verbatim. At return, the reader is at positioned such that * next() will return n+1 or EOF (-1). * * @param n the number of characters to read * @return An array with guaranteed length n, with -1 being the value for * all elements at and after EOF. * @throws IOException */ int[] collect(int n) throws IOException { int[] buf = new int[n]; boolean seenEOF = false; for (int i = 0; i < buf.length; i++) { if (seenEOF) { buf[i] = -1; } else { buf[i] = next(); if (curChar == -1) { seenEOF = true; } } } return buf; } /** * Read forward until the next non-escaped character matches the given * CharMatcher or is EOF. * * @throws IOException */ CssReader forward(CharMatcher matcher) throws IOException { while (true) { Mark mark = mark(); next(); //TODO escape awareness if (curChar == -1 || (matcher.matches((char) curChar) && prevChar != '\\')) { unread(curChar, mark); break; } } return this; } /** * Read forward n characters, or until the next character is EOF. * * @throws IOException */ CssReader forward(int n) throws IOException { for (int i = 0; i < n; i++) { //TODO escape awareness Mark mark = mark(); next(); if (curChar == -1) { unread(curChar, mark); break; } } return this; } void unread(final int ch, final Mark mark) { checkState(pos > 0); buf[--pos] = ch; reset(mark); } void unread(final int cbuf[], final Mark mark) throws IOException { unread(cbuf, 0, cbuf.length, mark); } void unread(final List cbuf, final Mark mark) throws IOException { unread(Ints.toArray(cbuf), mark); } void unread(final int cbuf[], final int off, final int len, final Mark mark) { checkArgument(len < pos); pos -= len; System.arraycopy(cbuf, off, buf, pos, len); reset(mark); } Mark mark() { return new Mark(curChar, prevChar, line, col, prevLine, offset); } private CssReader reset(final Mark mark) { this.curChar = mark.mCur; this.prevChar = mark.mPrev; this.line = mark.mLine; this.col = mark.mCol; this.prevLine = mark.mPrevLine; this.offset = mark.mOffset; return this; } final class Mark { final int mLine; final int mCol; final int mPrev; final int mCur; final int mPrevLine; final int mOffset; private Mark(final int curChar, final int prevChar, final int line, final int col, final int prevLine, final int offset) { this.mCur = curChar; this.mPrev = prevChar; this.mLine = line; this.mCol = col; this.mPrevLine = prevLine; this.mOffset = offset; } } @Override public String toString() { return Objects.toStringHelper(this) .add("curChar", (char) curChar) .add("prevChar", (char) prevChar) .toString(); } }epubcheck-4.0.2/src/main/java/org/idpf/epubcheck/util/css/CssInputStream.java0000644000175000017500000001455013017276730026415 0ustar eugeneeugene/* * Copyright (c) 2012 International Digital Publishing Forum * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package org.idpf.epubcheck.util.css; import com.adobe.epubcheck.util.outWriter; import com.google.common.base.Optional; import com.google.common.base.Strings; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; import com.google.common.io.ByteStreams; import com.google.common.primitives.Bytes; import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; import java.io.PushbackInputStream; import java.util.List; import java.util.Map; import static org.idpf.epubcheck.util.css.CssScanner.QUOTES; import static org.idpf.epubcheck.util.css.CssScanner.TERMINATOR; /** * An InputStream for CSS files that detects and skips past BOMs, and * peeks for @charset rules. * * @author mgylling */ public class CssInputStream extends PushbackInputStream { Optional bom = Optional.absent(); Optional charset = Optional.absent(); private static final int MAX_PUSHBACK = 256; private static final Map boms = new ImmutableMap.Builder() .put("UTF-32BE", new byte[]{(byte) 0x00, (byte) 0x00, (byte) 0xFE, (byte) 0xFF}) .put("UTF-32LE", new byte[]{(byte) 0xFE, (byte) 0xFF, (byte) 0x00, (byte) 0x00}) .put("UTF-8", new byte[]{(byte) 0xEF, (byte) 0xBB, (byte) 0xBF}) .put("UTF-16BE", new byte[]{(byte) 0xFE, (byte) 0xFF}) .put("UTF-16LE", new byte[]{(byte) 0xFF, (byte) 0xFE}) .build(); private boolean debug = false; public CssInputStream(final InputStream in) throws IOException { super(in instanceof BufferedInputStream ? in : new BufferedInputStream(in), MAX_PUSHBACK); String enc = getBOM(); if (!Strings.isNullOrEmpty(enc)) { this.bom = Optional.of(enc); } enc = getCssCharset(enc); if (!Strings.isNullOrEmpty(enc)) { this.charset = Optional.of(enc); } if(debug) { String s = bom.isPresent() ? bom.get() : " none."; outWriter.println("detected BOM: " + s); s = charset.isPresent() ? charset.get() : " none."; outWriter.println("detected charset: " + s); } } private String getBOM() throws IOException { byte[] data = new byte[4]; int read, unread; read = ByteStreams.read(this, data, 0, data.length); String key = map(data); unread = key == null ? read : data.length - boms.get(key).length; if (unread > 0) { unread(data, read - unread, unread); } return key; } private String getCssCharset(final String bom) throws IOException { /* * Because each char can be represented by 1-4 bytes, and because * there can be any amount of whitespace between @charset and the * open quote, this is fiddly. * * We read maximally four bytes at a time (required to decode UTF32 to a single char) */ String enc = bom != null ? bom : "UTF-8"; int len = 1; if (enc.startsWith("UTF-16")) { len = 2; } else if (enc.startsWith("UTF-32")) { len = 4; } Endian endian = null; if (len != 1) { endian = enc.endsWith("BE") ? Endian.BIG : Endian.LITTLE; } String value = null; List unread = Lists.newArrayList(); //all bytes read StringBuilder sbuf = new StringBuilder(); //all chars read char openQuote = 0; int openQuotePos = -1; byte[] bbuf; while (true) { bbuf = new byte[len]; for (int i = 0; i < len; i++) { int b = read(); if (b == -1) { break; } unread.add((byte) b); bbuf[i] = (byte) b; } if (unread.size() == MAX_PUSHBACK) { break; } if (len == 1 || endian == Endian.LITTLE) { sbuf.append((char) bbuf[0]); } else { sbuf.append((char) bbuf[len - 1]); } char cur = sbuf.charAt(sbuf.length() - 1); if ((sbuf.length() == 1 && cur != '@') || (TERMINATOR.matches(cur)) || (sbuf.length() == 8 && !sbuf.toString().equals("@charset"))) { break; } else if (openQuote == 0 && QUOTES.matches(cur)) { openQuote = cur; openQuotePos = sbuf.length(); } else if (openQuote == cur) { if (QUOTES.matches(cur)) { value = sbuf.substring(openQuotePos, sbuf.length() - 1); } break; } } unread(Bytes.toArray(unread)); return value; } private static String map(byte[] data) { for (String name : boms.keySet()) { byte[] bom = boms.get(name); boolean match = true; for (int i = 0; i < bom.length; i++) { if (data[i] != bom[i]) { match = false; break; } } if (match) { return name; } } return null; } private enum Endian { LITTLE, BIG } /** * Get the character set as detected from a BOM. If present, the returned string * is one of 'UTF-32BE', 'UTF-32LE", 'UTF-8", 'UTF-16BE' or 'UTF-16LE". */ public final Optional getBomCharset() { return bom; } /** * Get the value of the CSS @charset rule, if present. */ public final Optional getCssCharset() { return charset; } }epubcheck-4.0.2/src/main/java/org/idpf/epubcheck/util/css/CssContentHandler.java0000644000175000017500000000451713017276730027054 0ustar eugeneeugene/* * Copyright (c) 2012 International Digital Publishing Forum * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package org.idpf.epubcheck.util.css; import org.idpf.epubcheck.util.css.CssGrammar.CssAtRule; import org.idpf.epubcheck.util.css.CssGrammar.CssDeclaration; import org.idpf.epubcheck.util.css.CssGrammar.CssSelector; import java.util.List; /** * ContentHandler interface for CssParser. * * @author mgylling */ public interface CssContentHandler { public void startDocument(); public void endDocument(); public void startAtRule(CssAtRule atRule); public void endAtRule(String name); public void selectors(List selectors); public void endSelectors(List selectors); public void declaration(CssDeclaration declaration); /** * A default, do-nothing implementation of CssContentHandler. */ public class CssDefaultHandler implements CssContentHandler { public void startDocument() { } public void endDocument() { } public void startAtRule(CssAtRule atRule) { } public void endAtRule(String name) { } public void selectors(List selectors) { } public void endSelectors(List selectors) { } public void declaration(CssDeclaration declaration) { } } } epubcheck-4.0.2/src/main/java/org/idpf/epubcheck/util/css/CssLocation.java0000644000175000017500000000543513017276730025714 0ustar eugeneeugene/* * Copyright (c) 2012 International Digital Publishing Forum * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package org.idpf.epubcheck.util.css; import com.google.common.base.Objects; import static com.google.common.base.Preconditions.checkNotNull; /** * Represents a location in a CSS file. * * @author mgylling */ public final class CssLocation { final int line; final int col; private final int charOffset; private final String systemID; CssLocation(final int line, final int col, final int charOffset, final String systemID) { this.line = checkNotNull(line); this.col = checkNotNull(col); this.charOffset = checkNotNull(charOffset); this.systemID = checkNotNull(systemID); } static CssLocation create(final CssReader reader) { return new CssLocation(reader.line, reader.col, reader.offset, reader.systemID); } public int getLine() { return line; } public int getColumn() { return col; } public int getCharOffset() { return charOffset; } public String getSystemID() { return systemID; } @Override public String toString() { return Objects.toStringHelper(this) .add("line", line) .add("col", col) .add("charOffset", charOffset) .toString(); } @Override public boolean equals(Object obj) { if (obj instanceof CssLocation) { CssLocation loc = (CssLocation) obj; if (loc.charOffset == this.charOffset && loc.line == this.line && loc.col == this.col && loc.systemID.equals(this.systemID)) { return true; } } return false; } /** * Canonical representation of the location system id * for virtual resources */ public static final String NO_SID = "VIRTUAL"; } epubcheck-4.0.2/src/main/java/com/0000755000175000017500000000000013017276730016170 5ustar eugeneeugeneepubcheck-4.0.2/src/main/java/com/adobe/0000755000175000017500000000000013017276730017242 5ustar eugeneeugeneepubcheck-4.0.2/src/main/java/com/adobe/epubcheck/0000755000175000017500000000000013017276730021173 5ustar eugeneeugeneepubcheck-4.0.2/src/main/java/com/adobe/epubcheck/dtbook/0000755000175000017500000000000013017276730022455 5ustar eugeneeugeneepubcheck-4.0.2/src/main/java/com/adobe/epubcheck/dtbook/DTBookHandler.java0000755000175000017500000001162513017276730025750 0ustar eugeneeugene/* * Copyright (c) 2007 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.dtbook; import java.net.URI; import java.net.URISyntaxException; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.messages.MessageId; import com.adobe.epubcheck.opf.XRefChecker; import com.adobe.epubcheck.util.FeatureEnum; import com.adobe.epubcheck.util.HandlerUtil; import com.adobe.epubcheck.util.PathUtil; import com.adobe.epubcheck.util.URISchemes; import com.adobe.epubcheck.xml.XMLElement; import com.adobe.epubcheck.xml.XMLHandler; import com.adobe.epubcheck.xml.XMLParser; import com.google.common.base.Preconditions; public class DTBookHandler implements XMLHandler { private final XMLParser parser; private final String path; private final XRefChecker xrefChecker; private boolean checkedUnsupportedXmlVersion = false; DTBookHandler(XMLParser parser, String path, XRefChecker xrefChecker) { this.parser = parser; this.path = path; this.xrefChecker = xrefChecker; } public void characters(char[] chars, int arg1, int arg2) { // do nothing } public void ignorableWhitespace(char[] chars, int arg1, int arg2) { // do nothing } public void startElement() { if (!checkedUnsupportedXmlVersion) { HandlerUtil.checkXMLVersion(parser); checkedUnsupportedXmlVersion = true; } XMLElement e = parser.getCurrentElement(); String ns = e.getNamespace(); String name = e.getName(); String id = e.getAttribute("id"); if (ns.equals("http://www.daisy.org/z3986/2005/dtbook/")) { // link@href, a@href, img@src String href = null; /* * This section checks to see if the references used are registered * schema-types and whether they point to external resources. The * resources are only allowed to be external if the attribute "external" * is set to true. */ if (name.equals("a")) { href = e.getAttribute("href"); String external = e.getAttribute("external"); if (href != null && external.equals("true")) { URI uri = checkURI(href); if (uri != null && URISchemes.contains(uri.getScheme())) { href = null; } else if (uri.getScheme() != null) { parser.getReport().message(MessageId.OPF_021, EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber()), href); href = null; } } } else if (name.equals("link")) { href = e.getAttribute("href"); } else if (name.equals("img")) { href = e.getAttribute("src"); } if (href != null) { // TODO check if dtbook uses xml:base of so set third param href = PathUtil.resolveRelativeReference(path, href, null); xrefChecker.registerReference(path, parser.getLineNumber(), parser.getColumnNumber(), href, name.equals("img") ? XRefChecker.Type.IMAGE : XRefChecker.Type.HYPERLINK); URI uri = checkURI(href); if (uri != null && "http".equals(uri.getScheme())) { parser.getReport().info(path, FeatureEnum.REFERENCE, href); } } if (id != null) { xrefChecker.registerAnchor(path, parser.getLineNumber(), parser.getColumnNumber(), id, XRefChecker.Type.HYPERLINK); } } } public void endElement() { // do nothing } public void processingInstruction(String arg0, String arg1) { // do nothing } // TODO duplicated from OPSHandler // should be in a URI utils class private URI checkURI(String uri) { try { return new URI(Preconditions.checkNotNull(uri).trim()); } catch (URISyntaxException e) { parser.getReport().message(MessageId.RSC_020, parser.getLocation(), uri); return null; } } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/dtbook/DTBookChecker.java0000755000175000017500000000511313017276730025732 0ustar eugeneeugene/* * Copyright (c) 2007 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.dtbook; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.messages.MessageId; import com.adobe.epubcheck.ocf.OCFPackage; import com.adobe.epubcheck.opf.ContentChecker; import com.adobe.epubcheck.opf.ValidationContext; import com.adobe.epubcheck.xml.XMLParser; import com.adobe.epubcheck.xml.XMLValidators; import com.google.common.base.Preconditions; public class DTBookChecker implements ContentChecker { private final ValidationContext context; private final Report report; private final String path; public DTBookChecker(ValidationContext context) { Preconditions.checkState("application/x-dtbook+xml".equals(context.mimeType)); this.context = context; this.report = context.report; this.path = context.path; } public void runChecks() { OCFPackage ocf = context.ocf.get(); if (!ocf.hasEntry(path)) { report.message(MessageId.RSC_001, EPUBLocation.create(ocf.getName()), path); } else if (!ocf.canDecrypt(path)) { report.message(MessageId.RSC_004, EPUBLocation.create(ocf.getName()), path); } else { XMLParser dtbookParser = new XMLParser(context); dtbookParser.addValidator(XMLValidators.DTBOOK_RNG.get()); DTBookHandler dtbookHandler = new DTBookHandler(dtbookParser, path, context.xrefChecker.get()); dtbookParser.addXMLHandler(dtbookHandler); dtbookParser.process(); } } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/dtbook/DTBookCheckerFactory.java0000755000175000017500000000322113017276730027260 0ustar eugeneeugene/* * Copyright (c) 2007 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.dtbook; import com.adobe.epubcheck.opf.ContentChecker; import com.adobe.epubcheck.opf.ContentCheckerFactory; import com.adobe.epubcheck.opf.ValidationContext; public class DTBookCheckerFactory implements ContentCheckerFactory { public ContentChecker newInstance(ValidationContext context) { return new DTBookChecker(context); } static private final DTBookCheckerFactory instance = new DTBookCheckerFactory(); static public DTBookCheckerFactory getInstance() { return instance; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/dict/0000755000175000017500000000000013017276730022116 5ustar eugeneeugeneepubcheck-4.0.2/src/main/java/com/adobe/epubcheck/dict/SearchKeyMapHandler.java0000644000175000017500000000310513017276730026572 0ustar eugeneeugenepackage com.adobe.epubcheck.dict; import com.adobe.epubcheck.opf.ValidationContext; import com.adobe.epubcheck.opf.XRefChecker.Type; import com.adobe.epubcheck.util.PathUtil; import com.adobe.epubcheck.xml.XMLElement; import com.adobe.epubcheck.xml.XMLHandler; import com.adobe.epubcheck.xml.XMLParser; public class SearchKeyMapHandler implements XMLHandler { private final ValidationContext context; private final String path; private final XMLParser parser; public SearchKeyMapHandler(ValidationContext context, XMLParser parser) { this.context = context; this.path = context.path; this.parser = parser; } public void startElement() { XMLElement e = parser.getCurrentElement(); String name = e.getName(); if ("http://www.idpf.org/2007/ops".equals(e.getNamespace())) { if ("search-key-group".equals(name)) { processRef(e.getAttribute("href")); } else if ("match".equals(name)) { processRef(e.getAttribute("href")); } } } private void processRef(String ref) { if (ref != null && context.xrefChecker.isPresent()) { ref = PathUtil.resolveRelativeReference(path, ref, null); context.xrefChecker.get().registerReference(path, parser.getLineNumber(), parser.getColumnNumber(), ref, Type.SEARCH_KEY); } } public void characters(char[] chars, int arg1, int arg2) { } public void endElement() { } public void ignorableWhitespace(char[] chars, int arg1, int arg2) { } public void processingInstruction(String arg0, String arg1) { } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/dict/SearchKeyMapChecker.java0000644000175000017500000000613513017276730026567 0ustar eugeneeugene/* * Copyright (c) 2011 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.dict; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.messages.MessageId; import com.adobe.epubcheck.ocf.OCFPackage; import com.adobe.epubcheck.opf.ContentChecker; import com.adobe.epubcheck.opf.DocumentValidator; import com.adobe.epubcheck.opf.ValidationContext; import com.adobe.epubcheck.xml.XMLParser; import com.adobe.epubcheck.xml.XMLValidators; import com.google.common.base.Preconditions; public class SearchKeyMapChecker implements ContentChecker, DocumentValidator { private final ValidationContext context; private final Report report; private final String path; public SearchKeyMapChecker(ValidationContext context) { Preconditions.checkState("application/vnd.epub.search-key-map+xml".equals(context.mimeType)); this.context = context; this.report = context.report; this.path = context.path; } public void runChecks() { OCFPackage ocf = context.ocf.get(); if (!ocf.hasEntry(path)) { report.message(MessageId.RSC_001, EPUBLocation.create(ocf.getName()), path); } else if (!ocf.canDecrypt(path)) { report.message(MessageId.RSC_004, EPUBLocation.create(ocf.getName()), path); } else if (!path.endsWith(".xml")) { report.message(MessageId.OPF_080, EPUBLocation.create(path)); } else { validate(); } } public boolean validate() { int fatalErrorsSoFar = report.getFatalErrorCount(); int errorsSoFar = report.getErrorCount(); int warningsSoFar = report.getWarningCount(); SearchKeyMapHandler handler; XMLParser parser = new XMLParser(context); handler = new SearchKeyMapHandler(context, parser); parser.addValidator(XMLValidators.SEARCH_KEY_MAP_RNC.get()); parser.addXMLHandler(handler); parser.process(); return fatalErrorsSoFar == report.getFatalErrorCount() && errorsSoFar == report.getErrorCount() && warningsSoFar == report.getWarningCount(); } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/dict/SearchKeyMapCheckerFactory.java0000644000175000017500000000332713017276730030117 0ustar eugeneeugene/* * Copyright (c) 2011 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.dict; import com.adobe.epubcheck.opf.ContentCheckerFactory; import com.adobe.epubcheck.opf.DocumentValidatorFactory; import com.adobe.epubcheck.opf.ValidationContext; public class SearchKeyMapCheckerFactory implements ContentCheckerFactory, DocumentValidatorFactory { static private final SearchKeyMapCheckerFactory instance = new SearchKeyMapCheckerFactory(); public SearchKeyMapChecker newInstance(ValidationContext context) { return new SearchKeyMapChecker(context); } static public SearchKeyMapCheckerFactory getInstance() { return instance; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/messages/0000755000175000017500000000000013017276730023002 5ustar eugeneeugeneepubcheck-4.0.2/src/main/java/com/adobe/epubcheck/messages/MessageDictionary.java0000644000175000017500000005636613017276730027277 0ustar eugeneeugenepackage com.adobe.epubcheck.messages; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.URL; import java.net.URLConnection; import java.nio.charset.Charset; import java.util.HashMap; import java.util.Locale; import java.util.Map; import java.util.NoSuchElementException; import java.util.PropertyResourceBundle; import java.util.ResourceBundle; import java.util.ResourceBundle.Control; import java.util.regex.Matcher; import java.util.regex.Pattern; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.util.PathUtil; import com.adobe.epubcheck.util.outWriter; import com.google.common.base.Charsets; /** * This is a dictionary that maps the text of a message to a severity. */ public class MessageDictionary { File overrideFile; Report report; static Map defaultSeverityMap = null; static Pattern parameterPattern = Pattern.compile("%(\\d+)\\$s"); public void setOverrideFile(File value) { overrideFile = value; initMessageMap(); } public MessageDictionary(File overrideFile, Report report) { this.report = report; this.overrideFile = overrideFile; initMessageMap(); } Map messages = new HashMap(); static final ResourceBundle labels = ResourceBundle.getBundle( "com.adobe.epubcheck.messages.MessageBundle", Locale.getDefault(), new UTF8Control()); public Message getMessage(MessageId id) { return this.messages.get(id); } static Map getDefaultSeverities() { if (defaultSeverityMap == null) { Map map = new HashMap(MessageId.values().length); // Accessibility map.put(MessageId.ACC_001, Severity.USAGE); map.put(MessageId.ACC_002, Severity.USAGE); map.put(MessageId.ACC_003, Severity.SUPPRESSED); map.put(MessageId.ACC_004, Severity.SUPPRESSED); map.put(MessageId.ACC_005, Severity.SUPPRESSED); map.put(MessageId.ACC_006, Severity.SUPPRESSED); map.put(MessageId.ACC_007, Severity.USAGE); map.put(MessageId.ACC_008, Severity.USAGE); map.put(MessageId.ACC_009, Severity.WARNING); map.put(MessageId.ACC_010, Severity.SUPPRESSED); map.put(MessageId.ACC_011, Severity.WARNING); map.put(MessageId.ACC_012, Severity.SUPPRESSED); map.put(MessageId.ACC_013, Severity.USAGE); map.put(MessageId.ACC_014, Severity.USAGE); map.put(MessageId.ACC_015, Severity.USAGE); map.put(MessageId.ACC_016, Severity.USAGE); map.put(MessageId.ACC_017, Severity.USAGE); // CHK map.put(MessageId.CHK_001, Severity.ERROR); map.put(MessageId.CHK_002, Severity.ERROR); map.put(MessageId.CHK_003, Severity.ERROR); map.put(MessageId.CHK_004, Severity.ERROR); map.put(MessageId.CHK_005, Severity.ERROR); map.put(MessageId.CHK_006, Severity.ERROR); map.put(MessageId.CHK_007, Severity.ERROR); // CSS map.put(MessageId.CSS_001, Severity.ERROR); map.put(MessageId.CSS_002, Severity.ERROR); map.put(MessageId.CSS_003, Severity.ERROR); map.put(MessageId.CSS_004, Severity.ERROR); map.put(MessageId.CSS_005, Severity.ERROR); map.put(MessageId.CSS_006, Severity.WARNING); map.put(MessageId.CSS_007, Severity.INFO); map.put(MessageId.CSS_008, Severity.ERROR); map.put(MessageId.CSS_009, Severity.USAGE); map.put(MessageId.CSS_010, Severity.ERROR); map.put(MessageId.CSS_011, Severity.SUPPRESSED); map.put(MessageId.CSS_012, Severity.USAGE); map.put(MessageId.CSS_013, Severity.USAGE); map.put(MessageId.CSS_015, Severity.ERROR); map.put(MessageId.CSS_016, Severity.SUPPRESSED); map.put(MessageId.CSS_017, Severity.WARNING); map.put(MessageId.CSS_019, Severity.WARNING); map.put(MessageId.CSS_020, Severity.USAGE); map.put(MessageId.CSS_021, Severity.USAGE); map.put(MessageId.CSS_022, Severity.USAGE); map.put(MessageId.CSS_023, Severity.USAGE); map.put(MessageId.CSS_024, Severity.USAGE); map.put(MessageId.CSS_025, Severity.USAGE); map.put(MessageId.CSS_027, Severity.USAGE); map.put(MessageId.CSS_028, Severity.USAGE); // HTML map.put(MessageId.HTM_001, Severity.ERROR); map.put(MessageId.HTM_002, Severity.WARNING); map.put(MessageId.HTM_003, Severity.ERROR); map.put(MessageId.HTM_004, Severity.ERROR); map.put(MessageId.HTM_005, Severity.USAGE); map.put(MessageId.HTM_006, Severity.USAGE); map.put(MessageId.HTM_007, Severity.WARNING); map.put(MessageId.HTM_008, Severity.ERROR); map.put(MessageId.HTM_009, Severity.ERROR); map.put(MessageId.HTM_010, Severity.USAGE); map.put(MessageId.HTM_011, Severity.ERROR); map.put(MessageId.HTM_012, Severity.USAGE); map.put(MessageId.HTM_013, Severity.USAGE); map.put(MessageId.HTM_014, Severity.WARNING); map.put(MessageId.HTM_014a, Severity.WARNING); map.put(MessageId.HTM_015, Severity.SUPPRESSED); map.put(MessageId.HTM_016, Severity.SUPPRESSED); map.put(MessageId.HTM_017, Severity.ERROR); map.put(MessageId.HTM_018, Severity.USAGE); map.put(MessageId.HTM_019, Severity.USAGE); map.put(MessageId.HTM_020, Severity.USAGE); map.put(MessageId.HTM_021, Severity.USAGE); map.put(MessageId.HTM_022, Severity.USAGE); map.put(MessageId.HTM_023, Severity.WARNING); map.put(MessageId.HTM_024, Severity.USAGE); map.put(MessageId.HTM_025, Severity.WARNING); map.put(MessageId.HTM_027, Severity.USAGE); map.put(MessageId.HTM_028, Severity.USAGE); map.put(MessageId.HTM_029, Severity.USAGE); map.put(MessageId.HTM_033, Severity.USAGE); map.put(MessageId.HTM_036, Severity.SUPPRESSED); map.put(MessageId.HTM_038, Severity.USAGE); map.put(MessageId.HTM_043, Severity.USAGE); map.put(MessageId.HTM_044, Severity.USAGE); map.put(MessageId.HTM_045, Severity.USAGE); map.put(MessageId.HTM_046, Severity.ERROR); map.put(MessageId.HTM_047, Severity.ERROR); map.put(MessageId.HTM_048, Severity.ERROR); map.put(MessageId.HTM_049, Severity.ERROR); map.put(MessageId.HTM_050, Severity.USAGE); map.put(MessageId.HTM_051, Severity.WARNING); map.put(MessageId.HTM_052, Severity.ERROR); // Media map.put(MessageId.MED_001, Severity.ERROR); map.put(MessageId.MED_002, Severity.ERROR); map.put(MessageId.MED_003, Severity.ERROR); map.put(MessageId.MED_004, Severity.ERROR); map.put(MessageId.MED_005, Severity.ERROR); map.put(MessageId.MED_006, Severity.USAGE); // NAV map.put(MessageId.NAV_001, Severity.ERROR); map.put(MessageId.NAV_002, Severity.USAGE); map.put(MessageId.NAV_003, Severity.ERROR); map.put(MessageId.NAV_004, Severity.USAGE); map.put(MessageId.NAV_005, Severity.USAGE); map.put(MessageId.NAV_006, Severity.USAGE); map.put(MessageId.NAV_007, Severity.USAGE); map.put(MessageId.NAV_008, Severity.USAGE); map.put(MessageId.NAV_009, Severity.ERROR); // NCX map.put(MessageId.NCX_001, Severity.USAGE); map.put(MessageId.NCX_002, Severity.ERROR); map.put(MessageId.NCX_003, Severity.USAGE); map.put(MessageId.NCX_004, Severity.USAGE); map.put(MessageId.NCX_005, Severity.USAGE); map.put(MessageId.NCX_006, Severity.USAGE); // OPF map.put(MessageId.OPF_001, Severity.ERROR); map.put(MessageId.OPF_002, Severity.FATAL); map.put(MessageId.OPF_003, Severity.WARNING); map.put(MessageId.OPF_004, Severity.WARNING); map.put(MessageId.OPF_004a, Severity.ERROR); map.put(MessageId.OPF_004b, Severity.ERROR); map.put(MessageId.OPF_004c, Severity.ERROR); map.put(MessageId.OPF_004d, Severity.ERROR); map.put(MessageId.OPF_004e, Severity.WARNING); map.put(MessageId.OPF_004f, Severity.WARNING); map.put(MessageId.OPF_005, Severity.ERROR); map.put(MessageId.OPF_006, Severity.ERROR); map.put(MessageId.OPF_007, Severity.WARNING); map.put(MessageId.OPF_007a, Severity.ERROR); map.put(MessageId.OPF_007b, Severity.WARNING); map.put(MessageId.OPF_008, Severity.ERROR); map.put(MessageId.OPF_009, Severity.ERROR); map.put(MessageId.OPF_010, Severity.ERROR); map.put(MessageId.OPF_011, Severity.ERROR); map.put(MessageId.OPF_012, Severity.ERROR); map.put(MessageId.OPF_013, Severity.ERROR); map.put(MessageId.OPF_014, Severity.ERROR); map.put(MessageId.OPF_015, Severity.ERROR); map.put(MessageId.OPF_016, Severity.ERROR); map.put(MessageId.OPF_017, Severity.ERROR); map.put(MessageId.OPF_018, Severity.WARNING); map.put(MessageId.OPF_019, Severity.FATAL); map.put(MessageId.OPF_020, Severity.SUPPRESSED); map.put(MessageId.OPF_021, Severity.WARNING); map.put(MessageId.OPF_025, Severity.ERROR); map.put(MessageId.OPF_026, Severity.ERROR); map.put(MessageId.OPF_027, Severity.ERROR); map.put(MessageId.OPF_028, Severity.ERROR); map.put(MessageId.OPF_029, Severity.ERROR); map.put(MessageId.OPF_030, Severity.ERROR); map.put(MessageId.OPF_031, Severity.ERROR); map.put(MessageId.OPF_032, Severity.ERROR); map.put(MessageId.OPF_033, Severity.ERROR); map.put(MessageId.OPF_034, Severity.ERROR); map.put(MessageId.OPF_035, Severity.WARNING); map.put(MessageId.OPF_036, Severity.USAGE); map.put(MessageId.OPF_037, Severity.WARNING); map.put(MessageId.OPF_038, Severity.WARNING); map.put(MessageId.OPF_039, Severity.WARNING); map.put(MessageId.OPF_040, Severity.ERROR); map.put(MessageId.OPF_041, Severity.ERROR); map.put(MessageId.OPF_042, Severity.ERROR); map.put(MessageId.OPF_043, Severity.ERROR); map.put(MessageId.OPF_044, Severity.ERROR); map.put(MessageId.OPF_045, Severity.ERROR); map.put(MessageId.OPF_046, Severity.ERROR); map.put(MessageId.OPF_047, Severity.USAGE); map.put(MessageId.OPF_048, Severity.ERROR); map.put(MessageId.OPF_049, Severity.ERROR); map.put(MessageId.OPF_050, Severity.ERROR); map.put(MessageId.OPF_051, Severity.SUPPRESSED); map.put(MessageId.OPF_052, Severity.ERROR); map.put(MessageId.OPF_053, Severity.WARNING); map.put(MessageId.OPF_054, Severity.ERROR); map.put(MessageId.OPF_055, Severity.WARNING); map.put(MessageId.OPF_056, Severity.USAGE); map.put(MessageId.OPF_057, Severity.SUPPRESSED); map.put(MessageId.OPF_058, Severity.USAGE); map.put(MessageId.OPF_059, Severity.USAGE); map.put(MessageId.OPF_060, Severity.ERROR); map.put(MessageId.OPF_061, Severity.WARNING); map.put(MessageId.OPF_062, Severity.USAGE); map.put(MessageId.OPF_063, Severity.WARNING); map.put(MessageId.OPF_064, Severity.INFO); map.put(MessageId.OPF_065, Severity.ERROR); map.put(MessageId.OPF_066, Severity.ERROR); map.put(MessageId.OPF_067, Severity.ERROR); map.put(MessageId.OPF_068, Severity.ERROR); map.put(MessageId.OPF_069, Severity.ERROR); map.put(MessageId.OPF_070, Severity.WARNING); map.put(MessageId.OPF_071, Severity.ERROR); map.put(MessageId.OPF_072, Severity.USAGE); map.put(MessageId.OPF_073, Severity.ERROR); map.put(MessageId.OPF_074, Severity.ERROR); map.put(MessageId.OPF_075, Severity.ERROR); map.put(MessageId.OPF_076, Severity.ERROR); map.put(MessageId.OPF_077, Severity.WARNING); map.put(MessageId.OPF_078, Severity.ERROR); map.put(MessageId.OPF_079, Severity.WARNING); map.put(MessageId.OPF_080, Severity.WARNING); map.put(MessageId.OPF_081, Severity.ERROR); map.put(MessageId.OPF_082, Severity.ERROR); map.put(MessageId.OPF_083, Severity.ERROR); map.put(MessageId.OPF_084, Severity.ERROR); // PKG map.put(MessageId.PKG_001, Severity.WARNING); map.put(MessageId.PKG_003, Severity.ERROR); map.put(MessageId.PKG_004, Severity.FATAL); map.put(MessageId.PKG_005, Severity.ERROR); map.put(MessageId.PKG_006, Severity.ERROR); map.put(MessageId.PKG_007, Severity.ERROR); map.put(MessageId.PKG_008, Severity.FATAL); map.put(MessageId.PKG_009, Severity.ERROR); map.put(MessageId.PKG_010, Severity.WARNING); map.put(MessageId.PKG_011, Severity.ERROR); map.put(MessageId.PKG_012, Severity.WARNING); map.put(MessageId.PKG_013, Severity.ERROR); map.put(MessageId.PKG_014, Severity.WARNING); map.put(MessageId.PKG_015, Severity.FATAL); map.put(MessageId.PKG_016, Severity.WARNING); map.put(MessageId.PKG_017, Severity.WARNING); map.put(MessageId.PKG_018, Severity.FATAL); map.put(MessageId.PKG_020, Severity.ERROR); map.put(MessageId.PKG_021, Severity.ERROR); map.put(MessageId.PKG_022, Severity.WARNING); map.put(MessageId.PKG_023, Severity.USAGE); // Resources map.put(MessageId.RSC_001, Severity.ERROR); map.put(MessageId.RSC_002, Severity.FATAL); map.put(MessageId.RSC_003, Severity.ERROR); map.put(MessageId.RSC_004, Severity.ERROR); map.put(MessageId.RSC_005, Severity.ERROR); map.put(MessageId.RSC_006, Severity.ERROR); map.put(MessageId.RSC_007, Severity.ERROR); map.put(MessageId.RSC_007w, Severity.WARNING); map.put(MessageId.RSC_008, Severity.ERROR); map.put(MessageId.RSC_009, Severity.ERROR); map.put(MessageId.RSC_010, Severity.ERROR); map.put(MessageId.RSC_011, Severity.ERROR); map.put(MessageId.RSC_012, Severity.ERROR); map.put(MessageId.RSC_013, Severity.ERROR); map.put(MessageId.RSC_014, Severity.ERROR); map.put(MessageId.RSC_015, Severity.ERROR); map.put(MessageId.RSC_016, Severity.FATAL); map.put(MessageId.RSC_017, Severity.WARNING); map.put(MessageId.RSC_018, Severity.WARNING); map.put(MessageId.RSC_019, Severity.WARNING); map.put(MessageId.RSC_020, Severity.ERROR); map.put(MessageId.RSC_021, Severity.ERROR); map.put(MessageId.RSC_022, Severity.INFO); // Scripting map.put(MessageId.SCP_001, Severity.USAGE); map.put(MessageId.SCP_002, Severity.USAGE); map.put(MessageId.SCP_003, Severity.USAGE); map.put(MessageId.SCP_004, Severity.ERROR); map.put(MessageId.SCP_005, Severity.ERROR); map.put(MessageId.SCP_006, Severity.USAGE); map.put(MessageId.SCP_007, Severity.USAGE); map.put(MessageId.SCP_008, Severity.USAGE); map.put(MessageId.SCP_009, Severity.USAGE); map.put(MessageId.SCP_010, Severity.USAGE); defaultSeverityMap = map; } return defaultSeverityMap; } void initDefaultMessageMap() { messages.clear(); for (Map.Entry entry : getDefaultSeverities().entrySet()) { this.addMessage(entry.getKey(), entry.getValue()); } } void initMessageMap() { initDefaultMessageMap(); loadOverriddenMessageSeverities(); } void loadOverriddenMessageSeverities() { if (overrideFile != null) { int lineNumber = -1; int columnNumber = -1; String line; FileInputStream fis = null; BufferedReader br = null; try { fis = new FileInputStream(overrideFile); br = new BufferedReader(new InputStreamReader(fis, Charset.forName("UTF-8"))); lineNumber = 1; while (null != (line = br.readLine())) { if (1 == lineNumber) { if (line.toLowerCase(Locale.ROOT).startsWith("id")) { // optionally eat the first line continue; } } columnNumber = 0; String[] fields = line.split("\t"); if (fields.length >= 2) { MessageId id; try { id = MessageId.fromString(fields[0]); } catch (NoSuchElementException unused) { report.message(MessageId.CHK_002, EPUBLocation.create("", lineNumber, 0), fields[0], PathUtil.removeWorkingDirectory(overrideFile.getAbsolutePath())); continue; } Severity newSeverity; try { columnNumber += 1 + fields[0].length(); newSeverity = Severity.fromString(fields[1]); } catch (NoSuchElementException ignored) { report.message(MessageId.CHK_003, EPUBLocation.create("", lineNumber, columnNumber), fields[1], PathUtil.removeWorkingDirectory(overrideFile.getAbsolutePath())); continue; } Message message = messages.get(id); String messageText = message.getMessage(); if (fields.length >= 3 && fields[2] != null && fields[2].length() > 0) { columnNumber += 1 + fields[1].length(); messageText = checkMessageForParameterCount(lineNumber, columnNumber, message.getMessage(), fields[2]); if (messageText == null) { report.message(MessageId.CHK_004, EPUBLocation.create("", lineNumber, 0, fields[2]), PathUtil.removeWorkingDirectory(overrideFile.getAbsolutePath())); continue; } } if (messageText != null) { Severity oldSeverity = getDefaultSeverities().get(message.getID()); if (newSeverity != oldSeverity) { messageText = String.format(" (severity overridden from %1$s) %2$s", oldSeverity, messageText); } } String suggestionText = message.getSuggestion(); if (fields.length >= 4 && fields[3] != null && fields[3].length() > 0) { columnNumber += 1 + fields[1].length(); suggestionText = checkMessageForParameterCount(lineNumber, columnNumber, message.getSuggestion(), fields[3]); if (suggestionText == null) { report.message(MessageId.CHK_005, EPUBLocation.create("", lineNumber, 0, fields[3]), PathUtil.removeWorkingDirectory(overrideFile.getAbsolutePath())); continue; } } if (message != null && ((newSeverity != message.getSeverity()) || (messageText.compareTo(message.getMessage()) != 0) || (suggestionText.compareTo(message.getSuggestion()) != 0))) { messages.put(id, new Message(message.getID(), newSeverity, message.getSeverity(), messageText, suggestionText)); } } ++lineNumber; } } catch (FileNotFoundException fnf) { report.message(MessageId.CHK_001, EPUBLocation.create(overrideFile.getAbsolutePath())); } catch (IOException ex) { report.message(MessageId.CHK_007, EPUBLocation.create("", lineNumber, columnNumber), PathUtil.removeWorkingDirectory(overrideFile.getAbsolutePath()), ex.getMessage()); } finally { try { if (br != null) { br.close(); } if (fis != null) { fis.close(); } } catch (IOException ignored) { } } } } String checkMessageForParameterCount(int lineNumber, int columnNumber, String originalText, String newText) { if (newText != null) { int maxOriginal = getParameterCount(lineNumber, columnNumber, originalText); int maxNew = getParameterCount(lineNumber, columnNumber, newText); if (maxNew <= maxOriginal) { return newText; } return null; } return originalText; } int getParameterCount(int lineNumber, int columnNumber, String text) { int max = 0; { Matcher m = parameterPattern.matcher(text); while (m.find()) { int absoluteColumnNumber = columnNumber + m.start(); String s = m.group(1); try { Integer number = Integer.parseInt(s); if (number > max) { max = number; } } catch (NumberFormatException ex) { String pathAdjustedFileName = PathUtil .removeWorkingDirectory(overrideFile.getAbsolutePath()); report.message(MessageId.CHK_006, EPUBLocation.create("", lineNumber, absoluteColumnNumber, text), pathAdjustedFileName); } } } return max; } void addMessage(MessageId messageId, Severity severity) { try { messages.put(messageId, new Message(messageId, severity, labels.getString(messageId.name()), getSuggestion(messageId))); } catch (Exception e) { outWriter.println("Couldn't locate message " + messageId.name()); } } String getSuggestion(MessageId messageId) { String result; try { result = labels.getString(messageId.name() + "_SUG"); } catch (Exception ignore) { result = ""; } return result; } public void dumpMessages(OutputStreamWriter outputStream) throws IOException { // Output the messages in a tab separated format outputStream.write("ID\tSeverity\tMessage\tSuggestion\n"); for (MessageId id : MessageId.values()) { StringBuilder sb = new StringBuilder(); sb.append(id.toString()); sb.append("\t"); Message message = this.getMessage(id); if (message != null) { sb.append(message.getSeverity()); sb.append("\t"); sb.append(message.getMessage()); sb.append("\t"); sb.append(message.getSuggestion()); } else { sb.append("null\tnull\tnull\tnull"); } sb.append("\n"); outputStream.write(sb.toString()); } } private static class UTF8Control extends Control { public ResourceBundle newBundle(String baseName, Locale locale, String format, ClassLoader loader, boolean reload) throws IllegalAccessException, InstantiationException, IOException { // The below is a copy of the default implementation. String bundleName = toBundleName(baseName, locale); String resourceName = toResourceName(bundleName, "properties"); //$NON-NLS-1$ ResourceBundle bundle = null; InputStream stream = null; if (reload) { URL url = loader.getResource(resourceName); if (url != null) { URLConnection connection = url.openConnection(); if (connection != null) { connection.setUseCaches(false); stream = connection.getInputStream(); } } } else { stream = loader.getResourceAsStream(resourceName); } if (stream != null) { try { // Only this line is changed to make it to read properties files as // UTF-8. bundle = new PropertyResourceBundle( new BufferedReader(new InputStreamReader(stream, Charsets.UTF_8))); } finally { stream.close(); } } return bundle; } } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/messages/Severity.java0000644000175000017500000000206513017276730025462 0ustar eugeneeugenepackage com.adobe.epubcheck.messages; import java.util.HashMap; import java.util.Map; import java.util.NoSuchElementException; public enum Severity { SUPPRESSED("SUPPRESSED"), USAGE("USAGE"), INFO("INFO"), WARNING("WARNING"), ERROR("ERROR"), FATAL("FATAL"); private final String name; Severity(String feature) { this.name = feature; } public String toString() { return name; } private static final Map map = new HashMap(); static { for (Severity type : Severity.values()) { map.put(type.name, type); } } public static Severity fromString(String name) { if (map.containsKey(name)) { return map.get(name); } throw new NoSuchElementException(name + " not found"); } public int toInt() { if (this.equals(SUPPRESSED)) return 0; if (this.equals(USAGE)) return 1; if (this.equals(INFO)) return 2; if (this.equals(WARNING)) return 3; if (this.equals(ERROR)) return 4; if (this.equals(FATAL)) return 5; return -1; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/messages/MessageId.java0000644000175000017500000001755213017276730025520 0ustar eugeneeugene/* * Copyright (c) 2011 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.messages; import java.util.HashMap; import java.util.Map; import java.util.NoSuchElementException; public enum MessageId implements Comparable { // Messages relating to accessibility ACC_001("ACC-001"), ACC_002("ACC-002"), ACC_003("ACC-003"), ACC_004("ACC-004"), ACC_005("ACC-005"), ACC_006("ACC-006"), ACC_007("ACC-007"), ACC_008("ACC-008"), ACC_009("ACC-009"), ACC_010("ACC-010"), ACC_011("ACC-011"), ACC_012("ACC-012"), ACC_013("ACC-013"), ACC_014("ACC-014"), ACC_015("ACC-015"), ACC_016("ACC-016"), ACC_017("ACC-017"), // Messages relating to the checker configuration CHK_001("CHK-001"), CHK_002("CHK-002"), CHK_003("CHK-003"), CHK_004("CHK-004"), CHK_005("CHK-005"), CHK_006("CHK-006"), CHK_007("CHK-007"), // Messages associated with styles CSS_001("CSS-001"), CSS_002("CSS-002"), CSS_003("CSS-003"), CSS_004("CSS-004"), CSS_005("CSS-005"), CSS_006("CSS-006"), CSS_007("CSS-007"), CSS_008("CSS-008"), CSS_009("CSS-009"), CSS_010("CSS-010"), CSS_011("CSS-011"), CSS_012("CSS-012"), CSS_013("CSS-013"), CSS_015("CSS-015"), CSS_016("CSS-016"), CSS_017("CSS-017"), CSS_019("CSS-019"), CSS_020("CSS-020"), CSS_021("CSS-021"), CSS_022("CSS-022"), CSS_023("CSS-023"), CSS_024("CSS-024"), CSS_025("CSS-025"), CSS_027("CSS-027"), CSS_028("CSS-028"), // Messages relating to xhtml markup HTM_001("HTM-001"), HTM_002("HTM-002"), HTM_003("HTM-003"), HTM_004("HTM-004"), HTM_005("HTM-005"), HTM_006("HTM-006"), HTM_007("HTM-007"), HTM_008("HTM-008"), HTM_009("HTM-009"), HTM_010("HTM-010"), HTM_011("HTM-011"), HTM_012("HTM-012"), HTM_013("HTM-013"), HTM_014("HTM-014"), HTM_014a("HTM-014a"), HTM_015("HTM-015"), HTM_016("HTM-016"), HTM_017("HTM-017"), HTM_018("HTM-018"), HTM_019("HTM-019"), HTM_020("HTM-020"), HTM_021("HTM-021"), HTM_022("HTM-022"), HTM_023("HTM-023"), HTM_024("HTM-024"), HTM_025("HTM-025"), HTM_027("HTM-027"), HTM_028("HTM-028"), HTM_029("HTM-029"), HTM_033("HTM-033"), HTM_036("HTM-036"), HTM_038("HTM-038"), HTM_043("HTM-043"), HTM_044("HTM-044"), HTM_045("HTM-045"), HTM_046("HTM-046"), HTM_047("HTM-047"), HTM_048("HTM-048"), HTM_049("HTM-049"), HTM_050("HTM-050"), HTM_051("HTM-051"), HTM_052("HTM-052"), // Messages associated with media (images, audio and video) MED_001("MED-001"), MED_002("MED-002"), MED_003("MED-003"), MED_004("MED-004"), MED_005("MED-005"), MED_006("MED_006"), // Epub3 based table of content errors NAV_001("NAV-001"), NAV_002("NAV-002"), NAV_003("NAV-003"), NAV_004("NAV-004"), NAV_005("NAV-005"), NAV_006("NAV-006"), NAV_007("NAV-007"), NAV_008("NAV-008"), NAV_009("NAV-009"), // Epub2 based table of content messages NCX_001("NCX-001"), NCX_002("NCX-002"), NCX_003("NCX-003"), NCX_004("NCX-004"), NCX_005("NCX-005"), NCX_006("NCX-006"), // Messages related to the markup in the OPF file OPF_001("OPF-001"), OPF_002("OPF-002"), OPF_003("OPF-003"), OPF_004("OPF-004"), OPF_004a("OPF-004a"), OPF_004b("OPF-004b"), OPF_004c("OPF-004c"), OPF_004d("OPF-004d"), OPF_004e("OPF-004e"), OPF_004f("OPF-004f"), OPF_005("OPF-005"), OPF_006("OPF-006"), OPF_007("OPF-007"), OPF_007a("OPF-007a"), OPF_007b("OPF-007b"), OPF_008("OPF-008"), OPF_009("OPF-009"), OPF_010("OPF-010"), OPF_011("OPF-011"), OPF_012("OPF-012"), OPF_013("OPF-013"), OPF_014("OPF-014"), OPF_015("OPF-015"), OPF_016("OPF-016"), OPF_017("OPF-017"), OPF_018("OPF-018"), OPF_019("OPF-019"), OPF_020("OPF-020"), OPF_021("OPF-021"), OPF_025("OPF-025"), OPF_026("OPF-026"), OPF_027("OPF-027"), OPF_028("OPF-028"), OPF_029("OPF-029"), OPF_030("OPF-030"), OPF_031("OPF-031"), OPF_032("OPF-032"), OPF_033("OPF-033"), OPF_034("OPF-034"), OPF_035("OPF-035"), OPF_036("OPF-036"), OPF_037("OPF-037"), OPF_038("OPF-038"), OPF_039("OPF-039"), OPF_040("OPF-040"), OPF_041("OPF-041"), OPF_042("OPF-042"), OPF_043("OPF-043"), OPF_044("OPF-044"), OPF_045("OPF-045"), OPF_046("OPF-046"), OPF_047("OPF-047"), OPF_048("OPF-048"), OPF_049("OPF-049"), OPF_050("OPF-050"), OPF_051("OPF-051"), OPF_052("OPF-052"), OPF_053("OPF-053"), OPF_054("OPF-054"), OPF_055("OPF-055"), OPF_056("OPF-056"), OPF_057("OPF-057"), OPF_058("OPF-058"), OPF_059("OPF-059"), OPF_060("OPF-060"), OPF_061("OPF-061"), OPF_062("OPF-062"), OPF_063("OPF-063"), OPF_064("OPF-064"), OPF_065("OPF-065"), OPF_066("OPF-066"), OPF_067("OPF-067"), OPF_068("OPF-068"), OPF_069("OPF-069"), OPF_070("OPF-070"), OPF_071("OPF-071"), OPF_072("OPF-072"), OPF_073("OPF-073"), OPF_074("OPF-074"), OPF_075("OPF-075"), OPF_076("OPF-076"), OPF_077("OPF-077"), OPF_078("OPF-078"), OPF_079("OPF-079"), OPF_080("OPF-080"), OPF_081("OPF-081"), OPF_082("OPF-082"), OPF_083("OPF-083"), OPF_084("OPF-084"), // Messages relating to the entire package PKG_001("PKG-001"), PKG_003("PKG-003"), PKG_004("PKG-004"), PKG_005("PKG-005"), PKG_006("PKG-006"), PKG_007("PKG-007"), PKG_008("PKG-008"), PKG_009("PKG-009"), PKG_010("PKG-010"), PKG_011("PKG-011"), PKG_012("PKG-012"), PKG_013("PKG-013"), PKG_014("PKG-014"), PKG_015("PKG-015"), PKG_016("PKG-016"), PKG_017("PKG-017"), PKG_018("PKG-018"), PKG_020("PKG-020"), PKG_021("PKG-021"), PKG_022("PKG-022"), PKG_023("PKG-023"), // Messages relating to resources RSC_001("RSC-001"), RSC_002("RSC-002"), RSC_003("RSC-003"), RSC_004("RSC-004"), RSC_005("RSC-005"), RSC_006("RSC-006"), RSC_007("RSC-007"), RSC_007w("RSC-007w"), RSC_008("RSC-008"), RSC_009("RSC-009"), RSC_010("RSC-010"), RSC_011("RSC-011"), RSC_012("RSC-012"), RSC_013("RSC-013"), RSC_014("RSC-014"), RSC_015("RSC-015"), RSC_016("RSC-016"), RSC_017("RSC-017"), RSC_018("RSC-018"), RSC_019("RSC-019"), RSC_020("RSC-020"), RSC_021("RSC-021"), RSC_022("RSC-022"), // Messages relating to scripting SCP_001("SCP-001"), SCP_002("SCP-002"), SCP_003("SCP-003"), SCP_004("SCP-004"), SCP_005("SCP-005"), SCP_006("SCP-006"), SCP_007("SCP-007"), SCP_008("SCP-008"), SCP_009("SCP-009"), SCP_010("SCP-010"); private final String messageId; MessageId(String feature) { this.messageId = feature; } public String toString() { return messageId; } private static final Map map = new HashMap(); static { for (MessageId type : MessageId.values()) { map.put(type.messageId, type); } } public static MessageId fromString(String messageId) { if (map.containsKey(messageId)) { return map.get(messageId); } throw new NoSuchElementException("MessageId." + messageId + " not found"); } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/messages/Message.java0000644000175000017500000000273113017276730025234 0ustar eugeneeugenepackage com.adobe.epubcheck.messages; import java.util.IllegalFormatException; /** * This is information associated with a check message. */ public class Message { private final MessageId ID; private final Severity severity; private final Severity originalSeverity; private final String message; private final String suggestion; public Message(MessageId messageId, Severity severity, String message, String suggestion) { this.ID = messageId; this.originalSeverity = this.severity = severity; this.message = message; this.suggestion = suggestion; } public Message(MessageId messageId, Severity severity, Severity originalSeverity, String message, String suggestion) { this.ID = messageId; this.severity = severity; this.originalSeverity = originalSeverity; this.message = message; this.suggestion = suggestion; } public MessageId getID() { return this.ID; } public Severity getSeverity() { return this.severity; } public Severity getOriginalSeverity() { return this.originalSeverity; } public String getSuggestion() { return this.suggestion; } public String getMessage(Object... args) { String result = this.getMessage(); try { result = String.format(result, args); } catch (IllegalFormatException e) { result = this.getMessage() + " :" + e.getMessage(); } return result; } public String getMessage() { return this.message; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ocf/0000755000175000017500000000000013017276730021742 5ustar eugeneeugeneepubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ocf/UnsupportedEncryptionFilter.java0000644000175000017500000000040713017276730030357 0ustar eugeneeugenepackage com.adobe.epubcheck.ocf; import java.io.InputStream; public class UnsupportedEncryptionFilter implements EncryptionFilter { public boolean canDecrypt() { return false; } public InputStream decrypt(InputStream in) { return null; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ocf/OCFZipPackage.java0000644000175000017500000001412613017276730025157 0ustar eugeneeugenepackage com.adobe.epubcheck.ocf; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.security.MessageDigest; import java.util.Collections; import java.util.Enumeration; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; import java.util.TreeSet; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.messages.MessageId; import com.adobe.epubcheck.util.FeatureEnum; public class OCFZipPackage extends OCFPackage { private final ZipFile zip; private List allEntries = null; private Set fileEntries; private Set dirEntries; public OCFZipPackage(ZipFile zip) { super(); this.zip = zip; } private void listEntries() throws IOException { synchronized (zip) { allEntries = new LinkedList(); fileEntries = new TreeSet(); dirEntries = new TreeSet(); try { for (Enumeration entries = zip.entries(); entries.hasMoreElements(); ) { ZipEntry entry = entries.nextElement(); allEntries.add(entry.getName()); if (entry.isDirectory()) { dirEntries.add(entry.getName()); } else { fileEntries.add(entry.getName()); } } } catch (IllegalArgumentException ex) { throw new IOException(ex.getMessage()); } } } /* (non-Javadoc) * @see com.adobe.epubcheck.ocf.OCFPackage#hasEntry(java.lang.String) */ public boolean hasEntry(String name) { return zip.getEntry(name) != null; } /* (non-Javadoc) * @see com.adobe.epubcheck.ocf.OCFPackage#getTimeEntry(java.lang.String) */ public long getTimeEntry(String name) { ZipEntry entry = zip.getEntry(name); if (entry == null) { return 0L; } return entry.getTime(); } /* * (non-Javadoc) * @see com.adobe.epubcheck.ocf.OCFPackage#getInputStream(java.lang.String) */ @Override public InputStream getInputStream(String name) throws IOException { ZipEntry entry = zip.getEntry(name); if (entry == null) { return null; } InputStream in = zip.getInputStream(entry); EncryptionFilter filter = enc.get(name); if (filter == null) { return in; } if (filter.canDecrypt()) { return filter.decrypt(in); } return null; } @Override public List getEntries() throws IOException { synchronized (zip) { if (allEntries == null) { listEntries(); } } return Collections.unmodifiableList(allEntries); } /* (non-Javadoc) * @see com.adobe.epubcheck.ocf.OCFPackage#getFileEntries() */ @Override public Set getFileEntries() throws IOException { synchronized (zip) { if (allEntries == null) { listEntries(); } return Collections.unmodifiableSet(fileEntries); } } /* (non-Javadoc) * @see com.adobe.epubcheck.ocf.OCFPackage#getDirectoryEntries() */ @Override public Set getDirectoryEntries() throws IOException { HashSet entryNames = new HashSet(); for (Enumeration entries = zip.entries(); entries.hasMoreElements(); ) { ZipEntry entry = entries.nextElement(); if (entry.isDirectory()) { entryNames.add(entry.getName()); } } return entryNames; } public void reportMetadata(String fileName, Report report) { ZipEntry entry = zip.getEntry(fileName); if (entry != null) { report.info(fileName, FeatureEnum.SIZE, String.valueOf(entry.getSize())); report.info(fileName, FeatureEnum.COMPRESSED_SIZE, String.valueOf(entry.getCompressedSize())); report.info(fileName, FeatureEnum.COMPRESSION_METHOD, this.getCompressionMethod(entry)); InputStream inputStream = null; try { inputStream = zip.getInputStream(entry); if (inputStream != null) { report.info(fileName, FeatureEnum.SHA_256, getSHAHash(inputStream)); } } catch (IOException e) { report.message(MessageId.PKG_008, EPUBLocation.create(fileName), fileName); } finally { if (inputStream != null) { try { inputStream.close(); } catch (Exception ignore) { } } } } } private String getCompressionMethod(ZipEntry entry) { if (entry == null) { return ""; } int method = entry.getMethod(); if (method == ZipEntry.DEFLATED) { return "Deflated"; } if (method == ZipEntry.STORED) { return "Stored"; } return "Unsupported"; } private static String getSHAHash(InputStream fis) { try { MessageDigest md = MessageDigest.getInstance("SHA-256"); byte[] dataBytes = new byte[1024]; int nread; while ((nread = fis.read(dataBytes)) != -1) { md.update(dataBytes, 0, nread); } byte[] bytes = md.digest(); //convert the byte to hex format method 1 //StringBuilder sb = new StringBuilder(); //for (int i = 0; i < bytes.length; i++) //{ // sb.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1)); //} //convert the byte to hex format method 2 StringBuilder hexString = new StringBuilder(); for (byte aByte : bytes) { hexString.append(Integer.toHexString(0xFF & aByte)); } return hexString.toString(); } catch (Exception e) { return "error!"; } finally { if (fis != null) { try { fis.close(); } catch (IOException ignored) { } } } } public String getName() { return new File(this.zip.getName()).getName(); } @Override public String getPackagePath() { return zip.getName(); } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ocf/EncryptionFilter.java0000644000175000017500000000026313017276730026106 0ustar eugeneeugenepackage com.adobe.epubcheck.ocf; import java.io.InputStream; public interface EncryptionFilter { public boolean canDecrypt(); public InputStream decrypt(InputStream in); } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ocf/EncryptionHandler.java0000644000175000017500000000760413017276730026244 0ustar eugeneeugene/* * Copyright (c) 2007 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.ocf; import com.adobe.epubcheck.util.HandlerUtil; import com.adobe.epubcheck.xml.XMLElement; import com.adobe.epubcheck.xml.XMLHandler; import com.adobe.epubcheck.xml.XMLParser; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; public class EncryptionHandler implements XMLHandler { private final OCFPackage ocf; private final XMLParser parser; private boolean checkedUnsupportedXmlVersion = false; EncryptionHandler(OCFPackage ocf, XMLParser parser) { this.ocf = ocf; this.parser = parser; } public void startElement() { if (!checkedUnsupportedXmlVersion) { HandlerUtil.checkXMLVersion(parser); checkedUnsupportedXmlVersion = true; } // if the element is , then the element name // is stripped of rootBase, and URLDecoded, and finally put into // encryptedItemsSet. XMLElement e = parser.getCurrentElement(); if (e.getName().equals("CipherReference")) { String algorithm = null; XMLElement parent = e.getParent(); if (parent != null) { parent = parent.getParent(); if (parent != null && parent.getName().equals("EncryptedData")) { algorithm = (String) parent.getPrivateData(); } } String entryName = e.getAttribute("URI"); try { entryName = URLDecoder.decode(entryName, "UTF-8"); } catch (UnsupportedEncodingException er) { // UTF-8 is guaranteed to be supported throw new InternalError(e.toString()); } if (algorithm == null) { algorithm = "unknown"; } if (algorithm.equals("http://www.idpf.org/2008/embedding")) { ocf.setEncryption(entryName, new IDPFFontManglingFilter(null)); } else if (algorithm.equals("http://ns.adobe.com/pdf/enc#RC")) { ocf.setEncryption(entryName, new AdobeFontManglingFilter(null)); } else { ocf.setEncryption(entryName, new UnsupportedEncryptionFilter()); } } else if (e.getName().equals("EncryptionMethod")) { String algorithm = e.getAttribute("Algorithm"); if (algorithm != null) { XMLElement parent = e.getParent(); if (parent != null) { String comp = parent.getAttributeNS( "http://ns.adobe.com/digitaleditions/enc", "compression"); if (comp == null) { parent.setPrivateData(algorithm); } } } } } public void endElement() { } public void ignorableWhitespace(char[] chars, int arg1, int arg2) { } public void characters(char[] chars, int arg1, int arg2) { } public void processingInstruction(String arg0, String arg1) { } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ocf/OCFPackage.java0000644000175000017500000001252113017276730024471 0ustar eugeneeugenepackage com.adobe.epubcheck.ocf; import java.io.IOException; import java.io.InputStream; import java.util.Collections; import java.util.HashMap; import java.util.Hashtable; import java.util.List; import java.util.Map; import java.util.Set; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.messages.MessageId; import com.adobe.epubcheck.opf.OPFData; import com.adobe.epubcheck.opf.OPFPeeker; import com.adobe.epubcheck.opf.ValidationContext.ValidationContextBuilder; import com.adobe.epubcheck.util.GenericResourceProvider; import com.adobe.epubcheck.util.InvalidVersionException; import com.adobe.epubcheck.xml.XMLParser; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.base.Suppliers; public abstract class OCFPackage implements GenericResourceProvider { final Hashtable enc; String uniqueIdentifier; private Report reporter; private final Supplier ocfData = Suppliers.memoize(new Supplier() { @Override public OCFData get() { Preconditions.checkNotNull(reporter); XMLParser containerParser = new XMLParser(new ValidationContextBuilder() .path(OCFData.containerEntry).resourceProvider(OCFPackage.this).report(reporter) .mimetype("xml").build()); OCFHandler containerHandler = new OCFHandler(containerParser); containerParser.addXMLHandler(containerHandler); containerParser.process(); return containerHandler; } }); private final Supplier> opfData = Suppliers .memoize(new Supplier>() { @Override public Map get() { Preconditions.checkNotNull(reporter); Map result = new HashMap(); for (String opfPath : ocfData.get().getEntries(OPFData.OPF_MIME_TYPE)) { OPFPeeker peeker = new OPFPeeker(opfPath, reporter, OCFPackage.this); try { result.put(opfPath, peeker.peek()); } catch (InvalidVersionException e) { reporter.message(MessageId.OPF_001, EPUBLocation.create(opfPath), e.getMessage()); } catch (IOException ignored) { // missing file will be reported later } } return Collections.unmodifiableMap(result); } }); public OCFPackage() { this.enc = new Hashtable(); } public void setEncryption(String name, EncryptionFilter encryptionFilter) { enc.put(name, encryptionFilter); } /** * @param name * the name of a relative file that is possibly in the container * @return true if the file is in the container, false otherwise */ public abstract boolean hasEntry(String name); public abstract long getTimeEntry(String name); /** * @param name * the name of a relative file to fetch from the container. * @return an InputStream representing the data from the named file, possibly * decrypted if an appropriate encryption filter has been set */ public abstract InputStream getInputStream(String name) throws IOException; /** * @return a list of all the entries in this container. May contain duplicate * entries (which is invalid in EPUB). * @throws IOException */ public abstract List getEntries() throws IOException; /** * @return a set of relative file names of files in this container * @throws IOException */ public abstract Set getFileEntries() throws IOException; /** * @return a set of relative directory entries in this container * @throws IOException */ public abstract Set getDirectoryEntries() throws IOException; /** * @param fileName * name of the file to test * @return true if I have an Encryption filter for this particular file. */ public boolean canDecrypt(String fileName) { EncryptionFilter filter = enc.get(fileName); return filter == null || filter.canDecrypt(); } /** * This method parses the container entry and stores important data, but does * /not/ validate the container against a schema definition. *

* The parsed OCFData objects are memoized. *

*

* This OCFPackage's reporter is used to report any error that may occur the * first time the OCFData is parsed. *

* */ public OCFData getOcfData() { return ocfData.get(); } /** * This method parses the OPF root files contained in an OCFContainer and * stores important data, but does /not/ validate the OPF file against a * schema definition. *

* The parsed OPFData objects are memoized. *

*

* This OCFPackage's reporter is used to report any error that may occur the * first time the OPFData is parsed. *

* * @return an map with the OPF root files as keys and the OPFData as values. */ public Map getOpfData() { return opfData.get(); } public abstract void reportMetadata(String fileName, Report report); public abstract String getName(); public abstract String getPackagePath(); public void setReport(Report reporter) { this.reporter = reporter; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ocf/OCFFilenameChecker.java0000644000175000017500000000654313017276730026152 0ustar eugeneeugenepackage com.adobe.epubcheck.ocf; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.messages.MessageId; import com.adobe.epubcheck.util.EPUBVersion; import java.util.HashSet; public final class OCFFilenameChecker { private static final HashSet restricted30CharacterSet; static { HashSet set = new HashSet(); set.add("PRIVATE_USE_AREA"); set.add("ARABIC_PRESENTATION_FORMS_A"); set.add("SPECIALS"); set.add("SUPPLEMENTARY_PRIVATE_USE_AREA_A"); set.add("SUPPLEMENTARY_PRIVATE_USE_AREA_B"); set.add("VARIATION_SELECTORS_SUPPLEMENT"); set.add("TAGS"); restricted30CharacterSet = set; } private OCFFilenameChecker() { // static util } public static String checkCompatiblyEscaped(final String str, Report report, EPUBVersion version) { // don't check remote resources if (str.matches("^[^:/?#]+://.*")) { return ""; } // the test string will be used to compare test result String test = checkNonAsciiFilename(str, report); if (str.endsWith(".")) { report.message(MessageId.PKG_011, EPUBLocation.create(str)); test += "."; } boolean spaces = false; final char[] ascciGraphic = new char[]{'<', '>', '"', '{', '}', '|', '^', '`', '*', '?' /* , ':','/', '\\' */}; String result = ""; char[] chars = str.toCharArray(); for (char c : chars) { for (char a : ascciGraphic) { if (c == a) { result += "\"" + Character.toString(c) + "\","; test += Character.toString(c); } } if (Character.isSpaceChar(c)) { spaces = true; test += Character.toString(c); } } if (result.length() > 1) { result = result.substring(0, result.length() - 1); report.message(MessageId.PKG_009, EPUBLocation.create(str), result); } if (spaces) { report.message(MessageId.PKG_010, EPUBLocation.create(str)); } if (version == EPUBVersion.VERSION_3) { checkCompatiblyEscaped30(str, test, report); } return test; } private static String checkNonAsciiFilename(final String str, Report report) { // TODO change this from warning to a compatibility hint message level String nonAscii = str.replaceAll("[\\p{ASCII}]", ""); if (nonAscii.length() > 0) { report.message(MessageId.PKG_012, EPUBLocation.create(str), nonAscii); } return nonAscii; } private static String checkCompatiblyEscaped30(String str, String test, Report report) { String result = ""; char[] chars = str.toCharArray(); for (char c : chars) { if (Character.isISOControl(c)) { result += "\"" + Character.toString(c) + "\","; test += Character.toString(c); } // DEL (U+007F) if (c == '\u007F') { result += "\"" + Character.toString(c) + "\","; test += Character.toString(c); } String unicodeType = Character.UnicodeBlock.of(c).toString(); if (restricted30CharacterSet.contains(unicodeType)) { result += "\"" + Character.toString(c) + "\","; } } if (result.length() > 1) { result = result.substring(0, result.length() - 1); report.message(MessageId.PKG_009, EPUBLocation.create(str), result); } return test; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ocf/OCFHandler.java0000755000175000017500000000721213017276730024517 0ustar eugeneeugene/* * Copyright (c) 2007 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.ocf; import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import com.adobe.epubcheck.util.HandlerUtil; import com.adobe.epubcheck.xml.XMLElement; import com.adobe.epubcheck.xml.XMLHandler; import com.adobe.epubcheck.xml.XMLParser; import com.google.common.base.Optional; import com.google.common.base.Strings; public class OCFHandler implements OCFData, XMLHandler { private final Map> entries = new HashMap>(); private final XMLParser parser; private String mappingDoc = null; private boolean checkedUnsupportedXmlVersion = false; OCFHandler(XMLParser parser) { this.parser = parser; } @Override public List getEntries(String mediatype) { if (entries.containsKey(mediatype)) { return Collections.unmodifiableList(entries.get(mediatype)); } else { return Collections.emptyList(); } } @Override public List getEntries() { LinkedList result = new LinkedList(); for (List paths : entries.values()) { result.addAll(paths); } return Collections.unmodifiableList(result); } @Override public Optional getMapping() { return Optional.fromNullable(mappingDoc); } public void startElement() { if (!checkedUnsupportedXmlVersion) { HandlerUtil.checkXMLVersion(parser); checkedUnsupportedXmlVersion = true; } XMLElement e = parser.getCurrentElement(); String ns = e.getNamespace(); if ("urn:oasis:names:tc:opendocument:xmlns:container".equals(ns)) { if ("rootfile".equals(e.getName())) { String mediaType = (e.getAttribute("media-type") != null) ? e.getAttribute("media-type").trim() : "unknown"; String fullPath = e.getAttribute("full-path"); if (!entries.containsKey(mediaType)) { entries.put(mediaType, new LinkedList()); } entries.get(mediaType).add(fullPath); } else if ("link".equals(e.getName())) { if ("mapping".equals(Strings.nullToEmpty(e.getAttribute("rel")).trim())) { mappingDoc = e.getAttribute("href"); } } } } public void endElement() { } public void ignorableWhitespace(char[] chars, int arg1, int arg2) { } public void characters(char[] chars, int arg1, int arg2) { } public void processingInstruction(String arg0, String arg1) { } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ocf/OCFData.java0000644000175000017500000000153113017276730024006 0ustar eugeneeugenepackage com.adobe.epubcheck.ocf; import java.util.List; import com.google.common.base.Optional; public interface OCFData { static final String containerEntry = "META-INF/container.xml"; static final String encryptionEntry = "META-INF/encryption.xml"; static final String metadataEntry = "META-INF/metadata.xml"; static final String signatureEntry = "META-INF/signatures.xml"; /** * @return the full paths of the root files of the container for the given * media type. */ public List getEntries(String type); /** * @return the full paths of all the root files of the container */ public List getEntries(); /** * @return the full path of the Rendition Mapping Document, or * {@link Optional#absent()} is no such document is declared. */ public Optional getMapping(); } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ocf/OCFChecker.java0000755000175000017500000003635113017276730024514 0ustar eugeneeugene/* * Copyright (c) 2007 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.ocf; import static com.adobe.epubcheck.opf.ValidationContext.ValidationContextPredicates.*; import java.io.IOException; import java.io.InputStream; import java.text.Normalizer; import java.text.Normalizer.Form; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Set; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.api.EPUBProfile; import com.adobe.epubcheck.api.FeatureReport; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.messages.MessageId; import com.adobe.epubcheck.opf.OPFChecker; import com.adobe.epubcheck.opf.OPFCheckerFactory; import com.adobe.epubcheck.opf.OPFData; import com.adobe.epubcheck.opf.OPFHandler; import com.adobe.epubcheck.opf.OPFHandler30; import com.adobe.epubcheck.opf.ValidationContext; import com.adobe.epubcheck.opf.ValidationContext.ValidationContextBuilder; import com.adobe.epubcheck.util.CheckUtil; import com.adobe.epubcheck.util.EPUBVersion; import com.adobe.epubcheck.util.FeatureEnum; import com.adobe.epubcheck.util.ValidatorMap; import com.adobe.epubcheck.vocab.EpubCheckVocab; import com.adobe.epubcheck.xml.XMLParser; import com.adobe.epubcheck.xml.XMLValidator; import com.adobe.epubcheck.xml.XMLValidators; import com.google.common.base.Preconditions; import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.collect.Iterables; public class OCFChecker { @SuppressWarnings("unchecked") private static final ValidatorMap validatorMap = ValidatorMap.builder() .put(Predicates.and(path(OCFData.containerEntry), version(EPUBVersion.VERSION_2)), XMLValidators.CONTAINER_20_RNG) .put(Predicates.and(path(OCFData.containerEntry), version(EPUBVersion.VERSION_3)), XMLValidators.CONTAINER_30_RNC) .put(Predicates.and(path(OCFData.containerEntry), version(EPUBVersion.VERSION_3)), XMLValidators.CONTAINER_30_RENDITIONS_SCH) .put(Predicates.and(path(OCFData.encryptionEntry), version(EPUBVersion.VERSION_3)), XMLValidators.ENC_30_RNC) .put(Predicates.and(path(OCFData.encryptionEntry), version(EPUBVersion.VERSION_2)), XMLValidators.ENC_20_RNG) .put(Predicates.and(path(OCFData.signatureEntry), version(EPUBVersion.VERSION_2)), XMLValidators.SIG_20_RNG) .put(Predicates.and(path(OCFData.signatureEntry), version(EPUBVersion.VERSION_3)), XMLValidators.SIG_30_RNC) .put( Predicates.and(path(OCFData.metadataEntry), hasProp(EpubCheckVocab.VOCAB.get(EpubCheckVocab.PROPERTIES.MULTIPLE_RENDITION))), XMLValidators.META_30_RNC) .put( Predicates.and(path(OCFData.metadataEntry), hasProp(EpubCheckVocab.VOCAB.get(EpubCheckVocab.PROPERTIES.MULTIPLE_RENDITION))), XMLValidators.META_30_SCH) .put(Predicates.and(path(OCFData.metadataEntry), hasProp(EpubCheckVocab.VOCAB.get(EpubCheckVocab.PROPERTIES.MULTIPLE_RENDITION)), profile(EPUBProfile.EDUPUB)), XMLValidators.META_EDUPUB_SCH) .putAll(hasProp(EpubCheckVocab.VOCAB.get(EpubCheckVocab.PROPERTIES.RENDITION_MAPPING)), XMLValidators.RENDITION_MAPPING_RNC, XMLValidators.RENDITION_MAPPING_SCH) .build(); private final ValidationContext context; private final OCFPackage ocf; private final Report report; public OCFChecker(ValidationContext context) { Preconditions.checkState(context.ocf.isPresent()); this.context = context; this.ocf = context.ocf.get(); this.report = context.report; } public void runChecks() { // Create a new validation context builder from the parent context // It will be augmented with detected validation version, profile, etc. ValidationContextBuilder newContextBuilder = new ValidationContextBuilder(context); ocf.setReport(report); if (!ocf.hasEntry(OCFData.containerEntry)) { report.message(MessageId.RSC_002, EPUBLocation.create(ocf.getName())); return; } long l = ocf.getTimeEntry(OCFData.containerEntry); if (l > 0) { Date d = new Date(l); String formattedDate = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'").format(d); report.info(OCFData.containerEntry, FeatureEnum.CREATION_DATE, formattedDate); } OCFData containerData = ocf.getOcfData(); // retrieve the paths of root files List opfPaths = containerData.getEntries(OPFData.OPF_MIME_TYPE); if (opfPaths == null || opfPaths.isEmpty()) { report.message(MessageId.RSC_003, EPUBLocation.create(OCFData.containerEntry)); return; } else if (opfPaths.size() > 0) { if (opfPaths.size() > 1) { report.info(null, FeatureEnum.EPUB_RENDITIONS_COUNT, Integer.toString(opfPaths.size())); } // test every element for empty or missing @full-path attribute // bugfix for issue 236 / issue 95 int rootfileErrorCounter = 0; for (String opfPath : opfPaths) { if (opfPath == null) { ++rootfileErrorCounter; report.message(MessageId.OPF_016, EPUBLocation.create(OCFData.containerEntry)); } else if (opfPath.isEmpty()) { ++rootfileErrorCounter; report.message(MessageId.OPF_017, EPUBLocation.create(OCFData.containerEntry)); } else if (!ocf.hasEntry(opfPath)) { report.message(MessageId.OPF_002, EPUBLocation.create(OCFData.containerEntry), opfPath); return; } } if (rootfileErrorCounter == opfPaths.size()) { // end validation at this point when @full-path attribute is missing in // container.xml // otherwise, tons of errors would be thrown // ("XYZ exists in the zip file, but is not declared in the OPF file") return; } } // // Compute the validation version // ------------------------------ // Detect the version of the first root file // and compare with the asked version (if set) EPUBVersion detectedVersion = null; final EPUBVersion validationVersion; OPFData opfData = ocf.getOpfData().get(opfPaths.get(0)); if (opfData == null) return;// The error must have been reported during // parsing detectedVersion = opfData.getVersion(); report.info(null, FeatureEnum.FORMAT_VERSION, detectedVersion.toString()); assert(detectedVersion != null); if (context.version != EPUBVersion.Unknown && context.version != detectedVersion) { report.message(MessageId.PKG_001, EPUBLocation.create(opfPaths.get(0)), context.version, detectedVersion); validationVersion = context.version; } else { validationVersion = detectedVersion; } newContextBuilder.version(validationVersion); // // Compute the validation profile // ------------------------------ EPUBProfile validationProfile = context.profile; // FIXME get profile from metadata.xml if available if (validationVersion == EPUBVersion.VERSION_2 && validationProfile != EPUBProfile.DEFAULT) { // Validation profile is unsupported for EPUB 2.0 report.message(MessageId.PKG_023, EPUBLocation.create(opfPaths.get(0))); } else if (validationVersion == EPUBVersion.VERSION_3) { // Override the given validation profile depending on the primary OPF // dc:type validationProfile = EPUBProfile.makeOPFCompatible(validationProfile, opfData, opfPaths.get(0), report); } newContextBuilder.profile(validationProfile); // // Check multiple renditions // ------------------------------ // EPUB 2.0 says there SHOULD be only one OPS rendition if (validationVersion == EPUBVersion.VERSION_2 && opfPaths.size() > 1) { report.message(MessageId.PKG_013, EPUBLocation.create(OCFData.containerEntry)); } // EPUB 3.0 Multiple Renditions recommends the presence of a metadata file if (validationVersion == EPUBVersion.VERSION_3 && opfPaths.size() > 1) { newContextBuilder .addProperty(EpubCheckVocab.VOCAB.get(EpubCheckVocab.PROPERTIES.MULTIPLE_RENDITION)); if (!ocf.hasEntry(OCFData.metadataEntry)) { report.message(MessageId.RSC_019, EPUBLocation.create(ocf.getName())); } if (containerData.getMapping().isPresent()) { validateRenditionMapping(new ValidationContextBuilder(newContextBuilder.build()) .mimetype("application/xhtml+xml").path(containerData.getMapping().get()) .addProperty(EpubCheckVocab.VOCAB.get(EpubCheckVocab.PROPERTIES.RENDITION_MAPPING)) .build()); } } // // Check the mimetype file // ------------------------------ // InputStream mimetype = null; try { mimetype = ocf.getInputStream("mimetype"); StringBuilder sb = new StringBuilder(2048); if (ocf.hasEntry("mimetype") && !CheckUtil.checkTrailingSpaces(mimetype, validationVersion, sb)) { report.message(MessageId.PKG_007, EPUBLocation.create("mimetype")); } if (sb.length() != 0) { report.info(null, FeatureEnum.FORMAT_NAME, sb.toString().trim()); } } catch (IOException ignored) { // missing file will be reported later } finally { try { if (mimetype != null) { mimetype.close(); } } catch (IOException ignored) { // eat it } } // // Check the META-INF files // ------------------------------ // validateMetaFiles(newContextBuilder.mimetype("xml").build()); // // Check each OPF (i.e. Rendition) // ------------------------------- // // Validate each OPF and keep a reference of the OPFHandler List opfHandlers = new LinkedList(); for (String opfPath : opfPaths) { OPFChecker opfChecker = OPFCheckerFactory.getInstance() .newInstance(newContextBuilder.path(opfPath).mimetype(OPFData.OPF_MIME_TYPE) .featureReport(new FeatureReport()).build()); opfChecker.runChecks(); opfHandlers.add(opfChecker.getOPFHandler()); } // // Check container integrity // ------------------------------- // try { Set entriesSet = new HashSet(); Set normalizedEntriesSet = new HashSet(); for (final String entry : ocf.getFileEntries()) { if (!entriesSet.add(entry.toLowerCase(Locale.ENGLISH))) { report.message(MessageId.OPF_060, EPUBLocation.create(ocf.getPackagePath()), entry); } else if (!normalizedEntriesSet.add(Normalizer.normalize(entry, Form.NFC))) { report.message(MessageId.OPF_061, EPUBLocation.create(ocf.getPackagePath()), entry); } ocf.reportMetadata(entry, report); // if the entry is not in the whitelist (META-INF/* + mimetype) // and not declared in (one of) the OPF document(s) if (!entry.startsWith("META-INF/") && !entry.startsWith("META-INF\\") && !entry.equals("mimetype") && !containerData.getEntries().contains(entry) && !entry.equals(containerData.getMapping().orNull()) && !Iterables.tryFind(opfHandlers, new Predicate() { @Override public boolean apply(OPFHandler opfHandler) { // found if declared as an OPF item // or in an EPUB 3 link element return opfHandler.getItemByPath(entry).isPresent() || (validationVersion == EPUBVersion.VERSION_3 && ((OPFHandler30) opfHandler).getLinkedResources().hasPath(entry)); } }).isPresent()) { report.message(MessageId.OPF_003, EPUBLocation.create(ocf.getName()), entry); } OCFFilenameChecker.checkCompatiblyEscaped(entry, report, validationVersion); } for (String directory : ocf.getDirectoryEntries()) { boolean hasContents = false; for (String file : ocf.getFileEntries()) { if (file.startsWith(directory)) { hasContents = true; break; } } if (!hasContents) { report.message(MessageId.PKG_014, EPUBLocation.create(ocf.getName()), directory); } } } catch (IOException e) { report.message(MessageId.PKG_015, EPUBLocation.create(ocf.getName()), e.getMessage()); } } private boolean validateMetaFiles(ValidationContext context) { // validate container validateMetaFile(new ValidationContextBuilder(context).path(OCFData.containerEntry).build()); // Validate encryption.xml if (ocf.hasEntry(OCFData.encryptionEntry)) { validateMetaFile(new ValidationContextBuilder(context).path(OCFData.encryptionEntry).build()); report.info(null, FeatureEnum.HAS_ENCRYPTION, OCFData.encryptionEntry); } // validate signatures.xml if (ocf.hasEntry(OCFData.signatureEntry)) { validateMetaFile(new ValidationContextBuilder(context).path(OCFData.signatureEntry).build()); report.info(null, FeatureEnum.HAS_SIGNATURES, OCFData.signatureEntry); } // validate signatures.xml if (ocf.hasEntry(OCFData.metadataEntry)) { validateMetaFile(new ValidationContextBuilder(context).path(OCFData.metadataEntry).build()); } return false; } private void validateMetaFile(ValidationContext context) { XMLParser parser = new XMLParser(context); if (context.path.equals(OCFData.encryptionEntry)) { parser.addXMLHandler(new EncryptionHandler(ocf, parser)); } else { parser.addXMLHandler(new OCFHandler(parser)); } for (XMLValidator validator : validatorMap.getValidators(context)) { parser.addValidator(validator); } parser.process(); } private void validateRenditionMapping(ValidationContext context) { XMLParser parser = new XMLParser(context); for (XMLValidator validator : validatorMap.getValidators(context)) { parser.addValidator(validator); } parser.process(); } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ocf/IDPFFontManglingFilter.java0000644000175000017500000000125513017276730027004 0ustar eugeneeugenepackage com.adobe.epubcheck.ocf; import java.io.InputStream; public class IDPFFontManglingFilter implements EncryptionFilter { private final String uniqueIdentifier; public IDPFFontManglingFilter(String Uid) { uniqueIdentifier = Uid; } public boolean canDecrypt() { //FIXME we force return true to not issue a false-positive warning (see Issue 220) // ultimately, we need to pass the concatenated publication IDs (encryption key) // and implement de-obfuscation. return true; // return uniqueIdentifier != null; } public InputStream decrypt(InputStream in) { // TODO implement this once we start to validate fonts return null; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ocf/AdobeFontManglingFilter.java0000644000175000017500000000126013017276730027270 0ustar eugeneeugenepackage com.adobe.epubcheck.ocf; import java.io.InputStream; public class AdobeFontManglingFilter implements EncryptionFilter { private final String uniqueIdentifier; public AdobeFontManglingFilter(String Uid) { uniqueIdentifier = Uid; } public boolean canDecrypt() { //FIXME we force return true to not issue a false-positive warning (see Issue 220) // ultimately, we need to pass the concatenated publication IDs (encryption key) // and implement de-obfuscation. return true; // return uniqueIdentifier != null; } public InputStream decrypt(InputStream in) { // TODO implement this once we start to validate fonts return null; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/vocab/0000755000175000017500000000000013017276730022265 5ustar eugeneeugeneepubcheck-4.0.2/src/main/java/com/adobe/epubcheck/vocab/DataNavVocab.java0000644000175000017500000000047213017276730025424 0ustar eugeneeugenepackage com.adobe.epubcheck.vocab; public class DataNavVocab { public static final String URI = "http://www.idpf.org/epub/vocab/structure/#"; public static final EnumVocab VOCAB = new EnumVocab(EPUB_TYPES.class, URI); public static enum EPUB_TYPES { REGION_BASED; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/vocab/AltStylesheetVocab.java0000644000175000017500000000062713017276730026702 0ustar eugeneeugenepackage com.adobe.epubcheck.vocab; public final class AltStylesheetVocab { public static final String PREFIX = ""; public static final String URI = ""; public static final EnumVocab VOCAB = new EnumVocab(PROPERTIES.class, URI, PREFIX); public static enum PROPERTIES { VERTICAL, HORIZONTAL, DAY, NIGHT; } private AltStylesheetVocab() { } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/vocab/StructureVocab.java0000644000175000017500000000262613017276730026111 0ustar eugeneeugenepackage com.adobe.epubcheck.vocab; public class StructureVocab { public static final String URI = "http://www.idpf.org/epub/vocab/structure/#"; public static final EnumVocab VOCAB = new EnumVocab(EPUB_TYPES.class, URI); public static enum EPUB_TYPES { ACKNOWLEDGMENTS, AFTERWORD, ANNOREF, ANNOTATION, APPENDIX, ASSESSMENT, BACKMATTER, BIBLIOENTRY, BIBLIOGRAPHY, BODYMATTER, BRIDGEHEAD, CHAPTER, COLOPHON, CONCLUDING_SENTENCE, CONCLUSION, CONTRIBUTORS, COPYRIGHT_PAGE, COVER, COVERTITLE, DEDICATION, DIVISION, EPIGRAPH, EPILOGUE, ERRATA, FIGURE, FOOTNOTE, FOOTNOTES, FOREWORD, FRONTMATTER, FULLTITLE, GLOSSARY, GLOSSDEF, GLOSSTERM, HALFTITLE, HALFTITLEPAGE, HELP, IMPRIMATUR, IMPRINT, INDEX, INTRODUCTION, KEYWORD, LANDMARKS, LEARNING_OBJECTIVE, LEARNING_RESOURCE, LIST, LIST_ITEM, LOA, LOI, LOT, LOV, MARGINALIA, NOTE, NOTEREF, NOTICE, OTHER_CREDITS, PAGEBREAK, PAGE_LIST, PART, PRACTICE, PREAMBLE, PREFACE, PROLOGUE, REARNOTE, REARNOTES, REVISION_HISTORY, SIDEBAR, SUBCHAPTER, SUBTITLE, TABLE, TABLE_CELL, TABLE_ROW, TITLE, TITLEPAGE, TOC, TOPIC_SENTENCE, VOLUME, WARNING, QNA } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/vocab/Vocab.java0000644000175000017500000000126713017276730024170 0ustar eugeneeugenepackage com.adobe.epubcheck.vocab; import com.google.common.base.Optional; /** * Represents a vocabulary of properties. * * @author Romain Deltour * */ public interface Vocab { /** * Returns whether a property in allowed in this vocabulary. * * @param name * the property name (unprefixed). * @return an {@link Property} reference which contains a {@link Property} if * the lookup was successful or nothing if the property was not found * in this vocabulary. */ Optional lookup(String name); /** * Returns the base URI of this vocabulary. * * @return the base URI of this vocabulary. */ String getURI(); }epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/vocab/IndexVocab.java0000644000175000017500000000113313017276730025150 0ustar eugeneeugenepackage com.adobe.epubcheck.vocab; public class IndexVocab { public static final String URI = "http://www.idpf.org/epub/vocab/structure/#"; public static final EnumVocab VOCAB = new EnumVocab(EPUB_TYPES.class, URI); public static enum EPUB_TYPES { INDEX, INDEX_EDITOR_NOTE, INDEX_ENTRY, INDEX_ENTRY_LIST, INDEX_GROUP, INDEX_HEADNOTES, INDEX_LEGEND, INDEX_LOCATOR, INDEX_LOCATOR_LIST, INDEX_LOCATOR_RANGE, INDEX_TERM, INDEX_TERM_CATEGORIES, INDEX_TERM_CATEGORY, INDEX_XREF_PREFERRED, INDEX_XREF_RELATED; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/vocab/DictVocab.java0000644000175000017500000000117613017276730024773 0ustar eugeneeugenepackage com.adobe.epubcheck.vocab; public class DictVocab { public static final String URI = "http://www.idpf.org/epub/vocab/structure/#"; public static final EnumVocab VOCAB = new EnumVocab(EPUB_TYPES.class, URI); public static enum EPUB_TYPES { ANTONYM_GROUP, CONDENSED_ENTRY, DEF, DICTENTRY, DICTIONARY, ETYMOLOGY, EXAMPLE, GRAM_INFO, IDIOM, PART_OF_SPEECH, PART_OF_SPEECH_GROUP, PART_OF_SPEECH_LIST, PHONETIC_TRANSCRIPTION, PHRASE_GROUP, PHRASE_LIST, SENSE_GROUP, SENSE_LIST, SYNONYM_GROUP, TRAN, TRAN_INFO; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/vocab/PrefixDeclarationParser.java0000644000175000017500000001434513017276730027717 0ustar eugeneeugenepackage com.adobe.epubcheck.vocab; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.net.URI; import java.net.URISyntaxException; import java.util.EnumSet; import java.util.List; import java.util.Map; import net.sf.saxon.om.Name10Checker; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.messages.MessageId; import com.google.common.base.CharMatcher; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; /** * Utility to parse a prefix declaration attribute into a map of prefixes to URI * strings. * * @author Romain Deltour * */ public class PrefixDeclarationParser { private enum State { START(CharMatcher.WHITESPACE, CharMatcher.NONE), PREFIX(CharMatcher.WHITESPACE.or(CharMatcher.is(':')).negate(), CharMatcher.ANY), PREFIX_END(CharMatcher.is(':'), CharMatcher.ANY), SPACE(CharMatcher.WHITESPACE, CharMatcher.is(' ')), URI(CharMatcher.WHITESPACE.negate(), CharMatcher.ANY), WHITESPACE(CharMatcher.WHITESPACE, CharMatcher.anyOf(" \t\r\n")); public final CharMatcher accepted; public final CharMatcher allowed; private State(CharMatcher accepted, CharMatcher allowed) { this.accepted = accepted; this.allowed = allowed; } }; private static EnumSet FINAL_STATES = EnumSet.of(State.START, State.PREFIX, State.WHITESPACE); /** * Parses a prefix declaration attribute into a map of prefixes to URI * strings. * * @param value * the string to parse (typically from a prefix * attribute. * @param report * to report errors on the fly. * @param location * the location of attribute in the validated file. * @return a map of prefixes to URI strings. */ public static Map parsePrefixMappings(String value, Report report, EPUBLocation location) { // ---- prefix attribute EBNF ---- // prefixes = mapping , { whitespace, { whitespace } , mapping } ; // mapping = prefix , ":" , space , { space } , ? xsd:anyURI ? ; // prefix = ? xsd:NCName ? ; // space = #x20 ; // whitespace = (#x20 | #x9 | #xD | #xA) ; ImmutableMap.Builder builder = new ImmutableMap.Builder(); if (value == null) return builder.build(); StringReader reader = new StringReader(value); String prefix = null; String uri = null; try { State state = State.START; int c; String chars = ""; String badChars; while ((c = reader.read()) != -1) { List parsed = consume(reader, c, state); chars = parsed.get(0); badChars = parsed.get(1); switch (state) { case START: prefix = null; uri = null; if (!chars.isEmpty()) report.message(MessageId.OPF_004, location); state = State.PREFIX; break; case PREFIX: if (chars.isEmpty()) { // empty prefix report.message(MessageId.OPF_004a, location); } else if (!Name10Checker.getInstance().isValidNCName(chars)) { // bad prefix report.message(MessageId.OPF_004b, location, chars); } else { prefix = chars; } state = State.PREFIX_END; break; case PREFIX_END: if (chars.isEmpty()) { c = skip(reader, c, CharMatcher.WHITESPACE, State.PREFIX_END.accepted); if (((char) c) == ':') { // some space before the colon char report.message(MessageId.OPF_004c, location, prefix); state = State.PREFIX_END; } else { // no colon report.message(MessageId.OPF_004c, location, prefix); state = State.URI; } prefix = null; break; } state = State.SPACE; break; case SPACE: if (chars.isEmpty()) { // no space report.message(MessageId.OPF_004d, location, prefix); prefix = null; } else if (!badChars.isEmpty()) { // unexpected whitespace report.message(MessageId.OPF_004e, location, prefix); } state = State.URI; break; case URI: try { uri = new URI(chars).toString(); if (prefix != null) builder.put(prefix, uri); } catch (URISyntaxException e) { // bad URI report.message(MessageId.OPF_006, location, chars, prefix); } prefix = null; state = State.WHITESPACE; break; case WHITESPACE: if (!badChars.isEmpty()) report.message(MessageId.OPF_004f, location, prefix); state = State.PREFIX; break; } } if (!FINAL_STATES.contains(state))// string ends with a single prefix report.message(MessageId.OPF_005, location, prefix); if (state == State.PREFIX && !chars.isEmpty())// trailing whitespace report.message(MessageId.OPF_004, location); } catch (IOException e) { throw new IllegalStateException(e);// Unexpected } finally { reader.close(); } return builder.build(); } private static List consume(Reader reader, int c, State state) throws IOException { StringBuilder sb = new StringBuilder(); StringBuilder illegal = new StringBuilder(); while (c != -1 && state.accepted.matches((char) c)) { reader.mark(1); sb.append((char) c); if (!state.allowed.matches((char) c)) { illegal.append((char) c); } reader.mark(1); c = reader.read(); } reader.reset(); return ImmutableList.of(sb.toString(), illegal.toString()); } private static int skip(Reader reader, int c, CharMatcher skipped, CharMatcher stopping) throws IOException { while (c != -1 && !stopping.matches((char) c) && skipped.matches((char) c)) { reader.mark(1); c = reader.read(); } reader.reset(); return c; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/vocab/EpubCheckVocab.java0000644000175000017500000000227713017276730025744 0ustar eugeneeugenepackage com.adobe.epubcheck.vocab; import java.util.Map; import com.google.common.collect.ImmutableMap; /** * A vocabulary used for storing (temporary) info into properties for * EpubCheck's internal use. * */ public final class EpubCheckVocab { public static final String PREFIX = "epubcheck"; public static final String URI = "http://www.idpf.org/epubcheck/#"; public static final EnumVocab VOCAB = new EnumVocab(PROPERTIES.class, URI, PREFIX); public static final Map VOCAB_MAP = ImmutableMap . of(EpubCheckVocab.PREFIX, EpubCheckVocab.VOCAB); public static enum PROPERTIES { /** * Property of OPF items representing Fixed Layout Content Documents */ FIXED_LAYOUT, /** * Property of OPF items referenced in 'index' collections */ IN_INDEX_COLLECTION, /** * Property of OCF entries in Multiple Renditions */ MULTIPLE_RENDITION, /** * Property of non-linear OPF items */ NON_LINEAR, /** * Property used to identify the Rendition Mapping Document in the OCF * checker */ RENDITION_MAPPING; } private EpubCheckVocab() { } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/vocab/EnumVocab.java0000644000175000017500000000657513017276730025024 0ustar eugeneeugenepackage com.adobe.epubcheck.vocab; import java.util.EnumSet; import java.util.Locale; import java.util.Map; import com.google.common.base.Function; import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.base.Strings; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Maps; import com.google.common.collect.Maps.EntryTransformer; /** * A {@link Vocab} implementation that is backed by an {@link Enum}. * *

* Property names will be computed from {@link Enum} constant names by applying * the following transformation: *

*
    *
  • The name is converted to lower case
  • *
  • The underscore character ('_') is replaced by the hyphen * character ('-').
  • *
* * @author Romain Deltour * */ public final class EnumVocab

> implements Vocab { public final static Function, String> ENUM_TO_NAME = new Function, String>() { @Override public String apply(Enum enumee) { return enumee.name().toLowerCase(Locale.ROOT).replace('_', '-'); } }; private final Map index; private final String uri; /** * Creates a new vocabulary backed by the given {@link Enum} class and with * properties having the common URI stem base. Properties of the * created vocabulary will have an empty prefix (in other words, this creates * a default vocabulary). * * @param clazz * the enumeration backing this vocabulary. * @param base * the common stem URI of properties in this vocabulary. */ public EnumVocab(final Class

clazz, final String base) { this(clazz, base, null); } /** * Creates a new vocabulary backed by the given {@link Enum} class and with * properties having the common URI stem base and prefix * prefix * * @param clazz * the enumeration backing this vocabulary. * @param base * the common stem URI of properties in this vocabulary. * @param prefix * the common prefix of properties in this vocabulary. */ public EnumVocab(final Class

clazz, final String base, final String prefix) { this.uri = Strings.nullToEmpty(base); this.index = ImmutableMap .copyOf(Maps.transformEntries(Maps.uniqueIndex(EnumSet.allOf(clazz), ENUM_TO_NAME), new EntryTransformer() { @Override public Property transformEntry(String name, P enumee) { return Property.newFrom(name, base, prefix, enumee); } })); } @Override public Optional lookup(String name) { return Optional.fromNullable(index.get(name)); } @Override public String getURI() { return uri; } /** * Returns an {@link Optional} containing the {@link Property} for the given * enum item if it is defined in this vocabulary, or {@link Optional#absent()} * otherwise. * * @param property * the property to look up, must not be null * @return the result of looking up property in * vocab. */ public Property get(Enum

property) { Preconditions.checkNotNull(property); return lookup(EnumVocab.ENUM_TO_NAME.apply(property)).get(); } }epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/vocab/RenditionVocabs.java0000644000175000017500000000175513017276730026231 0ustar eugeneeugenepackage com.adobe.epubcheck.vocab; public final class RenditionVocabs { public static final String PREFIX = "rendition"; public static final String URI = "http://www.idpf.org/vocab/rendition/#"; public static final EnumVocab META_VOCAB = new EnumVocab( META_PROPERTIES.class, URI); public enum META_PROPERTIES { FLOW, LAYOUT, ORIENTATION, SPREAD, VIEWPORT } public static final EnumVocab ITEMREF_VOCAB = new EnumVocab( ITEMREF_PROPERTIES.class, URI); public enum ITEMREF_PROPERTIES { ALIGN_X_CENTER, FLOW_AUTO, FLOW_PAGINATED, FLOW_SCROLLED_CONTINUOUS, FLOW_SCROLLED_DOC, LAYOUT_PRE_PAGINATED, LAYOUT_REFLOWABLE, ORIENTATION_AUTO, ORIENTATION_LANDSCAPE, ORIENTATION_PORTRAIT, PAGE_SPREAD_CENTER, SPREAD_AUTO, SPREAD_BOTH, SPREAD_LANDSCAPE, SPREAD_NONE, SPREAD_PORTRAIT } private RenditionVocabs() { } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/vocab/MediaOverlaysVocab.java0000644000175000017500000000073413017276730026653 0ustar eugeneeugenepackage com.adobe.epubcheck.vocab; public final class MediaOverlaysVocab { public static final String PREFIX = "media"; public static final String URI = "http://www.idpf.org/epub/vocab/overlays/#"; public static final EnumVocab VOCAB = new EnumVocab(PROPERTIES.class, URI, PREFIX); public static enum PROPERTIES { ACTIVE_CLASS, DURATION, NARRATOR, PLAYBACK_ACTIVE_CLASS; } private MediaOverlaysVocab() { } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/vocab/StagingEdupubVocab.java0000644000175000017500000000152713017276730026651 0ustar eugeneeugenepackage com.adobe.epubcheck.vocab; public class StagingEdupubVocab { public static final String URI = "http://www.idpf.org/epub/vocab/structure/#"; public static final EnumVocab VOCAB = new EnumVocab(EPUB_TYPES.class, URI); public static enum EPUB_TYPES { ABSTRACT, ANSWER, ANSWERS, ASSESSMENTS, BIBLIOREF, CASE_STUDY, CREDIT, CREDITS, FEEDBACK, FILL_IN_THE_BLANK_PROBLEM, GENERAL_PROBLEM, GLOSSREF, KEYWORD, KEYWORDS, LABEL, LEARNING_OBJECTIVES, LEARNING_OUTCOME, LEARNING_OUTCOMES, LEARNING_RESOURCES, LEARNING_STANDARD, LEARNING_STANDARDS, MATCH_PROBLEM, MULTIPLE_CHOICE_PROBLEM, ORDINAL, PRACTICE, PRACTICES, PULLQUOTE, QUESTION, REFERRER, SERIESPAGE, TOC_BRIEF, TRUE_FALSE_PROBLEM; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/vocab/AggregateVocab.java0000644000175000017500000000255413017276730025777 0ustar eugeneeugenepackage com.adobe.epubcheck.vocab; import java.util.List; import com.google.common.base.Optional; import com.google.common.base.Strings; import com.google.common.collect.ImmutableList; public class AggregateVocab implements Vocab { private final List vocabs; private final String uri; /** * Returns a vocabulary composed of the union of the vocabularies given as * parameter. The given vocabularies must have the same base URI. * * @param vocabs * the vocabularies to aggregate. * @return the aggregated vocabulary. */ public static Vocab of(Vocab... vocabs) { return new AggregateVocab(new ImmutableList.Builder().add(vocabs).build()); } private AggregateVocab(List vocabs) { this.uri = (!vocabs.isEmpty()) ? Strings.nullToEmpty(vocabs.get(0).getURI()) : ""; for (Vocab vocab : vocabs) { if (!uri.equals(Strings.nullToEmpty(vocab.getURI()))) { throw new IllegalArgumentException("Aggregated vocabs must share the same base URI"); } } this.vocabs = vocabs; } @Override public Optional lookup(String name) { for (Vocab vocab : vocabs) { Optional found = vocab.lookup(name); if (found.isPresent()) return found; } return Optional.absent(); } @Override public String getURI() { return uri; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/vocab/DCMESVocab.java0000644000175000017500000000074513017276730024744 0ustar eugeneeugenepackage com.adobe.epubcheck.vocab; public class DCMESVocab { public static final String URI = "http://purl.org/dc/elements/1.1/"; public static final EnumVocab VOCAB = new EnumVocab(PROPERTIES.class, URI, "dc"); public static enum PROPERTIES { CONTRIBUTOR, COVERAGE, CREATOR, DATE, DESCRIPTION, FORMAT, IDENTIFIER, LANGUAGE, PUBLISHER, RELATION, RIGHTS, SOURCE, SUBJECT, TITLE, TYPE; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/vocab/ForeignVocabs.java0000644000175000017500000000236213017276730025662 0ustar eugeneeugenepackage com.adobe.epubcheck.vocab; /** * Vocabularies which are known but not validated in EpubCheck. */ public final class ForeignVocabs { public static final String DCTERMS_PREFIX = "dcterms"; public static final String DCTERMS_URI = "http://purl.org/dc/terms/"; public static final Vocab DCTERMS_VOCAB = new UncheckedVocab(DCTERMS_URI, DCTERMS_PREFIX); public static final String MARC_PREFIX = "marc"; public static final String MARC_URI = "http://id.loc.gov/vocabulary/"; public static final Vocab MARC_VOCAB = new UncheckedVocab(MARC_URI, MARC_PREFIX); public static final String ONIX_PREFIX = "onix"; public static final String ONIX_URI = "http://www.editeur.org/ONIX/book/codelists/current.html#"; public static final Vocab ONIX_VOCAB = new UncheckedVocab(ONIX_URI, ONIX_PREFIX); public static final String SCHEMA_PREFIX = "schema"; public static final String SCHEMA_URI = "http://schema.org/"; public static final Vocab SCHEMA_VOCAB = new UncheckedVocab(SCHEMA_URI, SCHEMA_PREFIX); public static final String XSD_PREFIX = "xsd"; public static final String XSD_URI = "http://www.w3.org/2001/XMLSchema#"; public static final Vocab XSD_VOCAB = new UncheckedVocab(XSD_URI, XSD_PREFIX); private ForeignVocabs() { } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/vocab/Property.java0000644000175000017500000001114113017276730024752 0ustar eugeneeugenepackage com.adobe.epubcheck.vocab; import java.util.EnumSet; import java.util.Set; import com.google.common.base.Function; import com.google.common.base.Preconditions; import com.google.common.base.Predicates; import com.google.common.base.Strings; import com.google.common.collect.Collections2; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; /** * Represents a value of the property datatype, as listed in * vocabulary of properties. * * @author Romain Deltour * */ public final class Property { private final String name; private final String prefixedName; private final String fullName; private final Enum enumee; /** * Creates a new instance from a short name, a prefix, and a stem URI. * * @param name * the short name of the property (aka "reference"). * @param base * the stem URI used to compute the full URI value. * @param prefix * the prefix used in the CURIE form. * @return */ public static Property newFrom(String name, String base, String prefix) { return new Property(name, base, prefix, null); } /** * Creates a new instance from a short name, a prefix, and a stem URI, and an * optional {@link Enum} item used to represent this property in known * vocabularies. * * @param name * the short name of the property (aka "reference"). * @param base * the stem URI used to compute the full URI value. * @param prefix * the prefix used in the CURIE form. * @return */ public static Property newFrom(String name, String base, String prefix, Enum enumee) { return new Property(name, base, prefix, enumee); } /** * Filters the given set of {@link Property} values and keeps the values * backed by an {@link Enum} constant of the given type. * * @param properties * the properties to filter * @param clazz * the class of a vocabulary-backing enum * @return An immutable {@link EnumSet} representing the filtered properties */ public static > Set filter(Set properties, final Class clazz) { Preconditions.checkNotNull(clazz); if (properties == null) return ImmutableSet.of(); return Sets.immutableEnumSet(Collections2.filter( Collections2.transform(properties, new Function() { @Override public E apply(Property input) { try { return clazz.cast(input.toEnum()); } catch (Exception e) { return null; } } }), Predicates.notNull())); } private Property(String name, String base, String prefix, Enum enumee) { this.name = name; this.fullName = base + name; this.prefixedName = (Strings.isNullOrEmpty(prefix)) ? name : prefix + ':' + name; this.enumee = enumee; } /** * Returns the short name (afa "reference") of this property. * * @return the short name (afa "reference") of this property. */ public String getName() { return name; } /** * Returns the full URI value of this property. * * @return the full URI value of this property. */ public String getFullName() { return fullName; } /** * Returns the prefixed name (aka CURIE) of this property. * * @return the prefixed name (aka CURIE) of this property. */ public String getPrefixedName() { return prefixedName; } /** * Returns the {@link Enum} item that is used to represent this property in * enum-based vocabularies. * * @return the {@link Enum} item that is used to represent this property. * @throws UnsupportedOperationException * if this property doesn't represent a property from an enum-based * vocabulary. */ public Enum toEnum() { if (enumee == null) throw new UnsupportedOperationException(); return enumee; } @Override public String toString() { return "Property [" + prefixedName + "]"; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((fullName == null) ? 0 : fullName.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Property other = (Property) obj; if (fullName == null) { if (other.fullName != null) return false; } else if (!fullName.equals(other.fullName)) return false; return true; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/vocab/PackageVocabs.java0000644000175000017500000000470313017276730025625 0ustar eugeneeugenepackage com.adobe.epubcheck.vocab; import java.util.Set; import com.google.common.collect.ImmutableSet; public final class PackageVocabs { public static final String PACKAGE_VOCAB_URI = "http://idpf.org/epub/vocab/package/#"; public static EnumVocab META_VOCAB = new EnumVocab( META_PROPERTIES.class, PACKAGE_VOCAB_URI); public static enum META_PROPERTIES { ALTERNATE_SCRIPT, BELONGS_TO_COLLECTION, COLLECTION_TYPE, DISPLAY_SEQ, DICTIONARY_TYPE, // DICT FILE_AS, GROUP_POSITION, IDENTIFIER_TYPE, META_AUTH, ROLE, SOURCE_LANGUAGE, // DICT SOURCE_OF, TARGET_LANGUAGE, // DICT TITLE_TYPE } public static EnumVocab ITEM_VOCAB = new EnumVocab( ITEM_PROPERTIES.class, PACKAGE_VOCAB_URI); public static enum ITEM_PROPERTIES { COVER_IMAGE("image/gif", "image/jpeg", "image/png", "image/svg+xml"), DATA_NAV("application/xhtml+xml"), DICTIONARY("application/vnd.epub.search-key-map+xml"), GLOSSARY("application/vnd.epub.search-key-map+xml", "application/xhtml+xml"), INDEX("application/xhtml+xml"), MATHML("application/xhtml+xml", "image/svg+xml"), NAV("application/xhtml+xml"), REMOTE_RESOURCES("application/xhtml+xml", "application/smil+xml", "image/svg+xml", "text/css"), SCRIPTED("application/xhtml+xml", "image/svg+xml"), SEARCH_KEY_MAP("application/vnd.epub.search-key-map+xml"), SVG("application/xhtml+xml"), SWITCH("application/xhtml+xml", "image/svg+xml"); private final Set types; private ITEM_PROPERTIES(String... types) { this.types = new ImmutableSet.Builder().add(types).build(); } public Set allowedOnTypes() { return types; } } public static EnumVocab ITEMREF_VOCAB = new EnumVocab( ITEMREF_PROPERTIES.class, PACKAGE_VOCAB_URI); public static enum ITEMREF_PROPERTIES { PAGE_SPREAD_RIGHT, PAGE_SPREAD_LEFT } public static final String LINKREL_VOCAB_URI = "http://idpf.org/epub/vocab/package/link/#"; public static EnumVocab LINKREL_VOCAB = new EnumVocab( LINKREL_PROPERTIES.class, LINKREL_VOCAB_URI); public static enum LINKREL_PROPERTIES { ACQUIRE, MARC21XML_RECORD, MODS_RECORD, ONIX_RECORD, RECORD, XML_SIGNATURE, XMP_RECORD } private PackageVocabs() { } }epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/vocab/UncheckedVocab.java0000644000175000017500000000254113017276730025776 0ustar eugeneeugenepackage com.adobe.epubcheck.vocab; import com.google.common.base.Optional; /** * A {@link Vocab} implementation which always return a successful lookup * result. In other words, this represents an "unchecked" vocabulary which * assumes that all property names are allowed. It is used to represent * user-declared custom vocabularies that are not known to EpubCheck. * * @author Romain Deltour * */ public final class UncheckedVocab implements Vocab { private final String base; private final String prefix; /** * Creates a new unchecked vocabulary representing properties whose URIs start * with base and short names have the prefix prefix. * * @param base * the URI stem used to generate URIs of properties in this * vocabulary. * @param prefix * the prefix used for property names. */ public UncheckedVocab(String base, String prefix) { this.base = base; this.prefix = prefix; } /** * Returns a reference to a new {@link Property} with the short name * name, the same prefix and stem URI as was given when creating * this vocabulary. */ @Override public Optional lookup(String name) { return Optional.of(Property.newFrom(name, base, prefix)); } @Override public String getURI() { return base; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/vocab/ScriptedCompVocab.java0000644000175000017500000000073513017276730026504 0ustar eugeneeugenepackage com.adobe.epubcheck.vocab; public final class ScriptedCompVocab { public static final String PREFIX = "epubsc"; public static final String URI = "http://idpf.org/epub/vocab/sc/#"; public static final EnumVocab VOCAB = new EnumVocab(PROPERTIES.class, URI, PREFIX); public static enum PROPERTIES { NETWORK_ACCESS_REQUIRED, REQUIRED_PARAMS, STORAGE_REQUIRED, VERSION; } private ScriptedCompVocab() { } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/vocab/VocabUtil.java0000644000175000017500000001575213017276730025032 0ustar eugeneeugenepackage com.adobe.epubcheck.vocab; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.api.QuietReport; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.messages.MessageId; import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.base.Splitter; import com.google.common.base.Strings; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.common.collect.Maps; import com.google.common.collect.Sets; /** * Utilities related to property values, vocabularies, and prefix declarations. * * @author Romain Deltour * */ public final class VocabUtil { public static Vocab EMPTY_VOCAB = new EnumVocab(EMPTY.class, ""); private enum EMPTY { } private static Pattern propertyPattern = Pattern.compile("(([^:]*):)?(.*)"); private static Splitter whitespaceSplitter = Splitter.onPattern("\\s+").omitEmptyStrings(); /** * Parses a single property value and report validation errors on the fly. * * @param value * the value to parse. * @param vocabs * a map of prefix to vocabularies. * @param report * used to report validation errors. * @param location * the location in the validated file. * @return an {@link Optional} containing the property if it was parsed * successfully or nothing if there was a parsing error */ public static Optional parseProperty(String value, Map vocabs, Report report, EPUBLocation location) { return Optional.fromNullable( Iterables.get(parseProperties(value, vocabs, false, report, location), 0, null)); } /** * Parses a space-separated list of property values, and report validation * errors on the fly. * * @param value * the value to parse. * @param vocabs * a map of prefix to vocabularies. * @param report * used to report validation errors. * @param location * the location in the validated file. * @return */ public static Set parsePropertyList(String value, Map vocabs, Report report, EPUBLocation location) { return parseProperties(value, vocabs, true, report, location); } /** * Parses a space-separated list of property values silently, and returns a * set the properties as a set of Enum values. * * @param properties * the properties string to parse * @param vocabs * a map of prefix to vocabularies. * @param clazz * the class of the Enum holding the returned properties * @return */ public static > Set parsePropertyListAsEnumSet(String properties, Map vocabs, Class clazz) { return Sets.newEnumSet(Property.filter(VocabUtil.parsePropertyList(properties, vocabs, QuietReport.INSTANCE, EPUBLocation.create("")), clazz), clazz); } private static Set parseProperties(String value, Map vocabs, boolean isList, Report report, EPUBLocation location) { Preconditions.checkNotNull(vocabs); Preconditions.checkNotNull(report); Preconditions.checkNotNull(location); if (value == null) { return ImmutableSet.of(); } ImmutableSet.Builder builder = ImmutableSet.builder(); // split properties, report error if a list is found but not allowed Iterable properties = whitespaceSplitter.split(value); if (!isList && !Iterables.isEmpty(Iterables.skip(properties, 1))) { report.message(MessageId.OPF_025, location, value); return ImmutableSet.of(); } for (String property : properties) { // parse prefix and local name, report error if malformed Matcher matcher = propertyPattern.matcher(property); matcher.matches(); if (matcher.group(1) != null && (matcher.group(2).isEmpty() || matcher.group(3).isEmpty())) { report.message(MessageId.OPF_026, location, property); continue; } String prefix = Strings.nullToEmpty(matcher.group(2)); String name = matcher.group(3); // lookup property in the vocab for its prefix // report error if not found try { Optional found = vocabs.get(prefix).lookup(name); if (found.isPresent()) { builder.add(found.get()); } else { report.message(MessageId.OPF_027, location, property); continue; } } catch (NullPointerException e) { // vocab not found (i.e. prefix undeclared), report warning report.message(MessageId.OPF_028, location, prefix); continue; } } return builder.build(); } /** * Parses a prefix attribute value and returns a map of prefixes to * vocabularies, given a pre-existing set of reserved prefixes, known * vocabularies, and default vocabularies that cannot be re-declared. * * @param value * the prefix declaration to parse. * @param predefined * a map of reserved prefixes to associated vocabularies. * @param known * a map of known URIs to known vocabularies. * @param forbidden * a set of URIs of default vocabularies that cannot be re-declared. * @param report * to report errors on the fly. * @param location * the location of the attribute in the source file. * @return */ public static Map parsePrefixDeclaration(String value, Map predefined, Map known, Set forbidden, Report report, EPUBLocation location) { Map vocabs = Maps.newHashMap(predefined); Map mappings = PrefixDeclarationParser.parsePrefixMappings(value, report, location); for (Entry mapping : mappings.entrySet()) { String prefix = mapping.getKey(); String uri = mapping.getValue(); if ("_".equals(prefix)) { // must not define the '_' prefix report.message(MessageId.OPF_007a, location); } else if (forbidden.contains(uri)) { // must not declare a default vocab report.message(MessageId.OPF_007b, location, prefix); } else { if (predefined.containsKey(prefix) && !Strings.nullToEmpty(predefined.get(prefix).getURI()).equals(uri)) { // re-declaration of reserved prefix report.message(MessageId.OPF_007, location, prefix); } Vocab vocab = known.get(uri); vocabs.put(mapping.getKey(), (vocab == null) ? new UncheckedVocab(uri, prefix) : vocab); } } return ImmutableMap.copyOf(vocabs); } private VocabUtil() { } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/vocab/ComicsVocab.java0000644000175000017500000000056213017276730025323 0ustar eugeneeugenepackage com.adobe.epubcheck.vocab; public class ComicsVocab { public static final String URI = "http://www.idpf.org/epub/vocab/structure/#"; public static final EnumVocab VOCAB = new EnumVocab(EPUB_TYPES.class, URI); public static enum EPUB_TYPES { BALLOON, PANEL, PANEL_GROUP, TEXT_AREA, SOUND_AREA } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/overlay/0000755000175000017500000000000013017276730022654 5ustar eugeneeugeneepubcheck-4.0.2/src/main/java/com/adobe/epubcheck/overlay/OverlayChecker.java0000644000175000017500000000606213017276730026431 0ustar eugeneeugene/* * Copyright (c) 2011 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.overlay; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.messages.MessageId; import com.adobe.epubcheck.ocf.OCFPackage; import com.adobe.epubcheck.opf.ContentChecker; import com.adobe.epubcheck.opf.DocumentValidator; import com.adobe.epubcheck.opf.ValidationContext; import com.adobe.epubcheck.xml.XMLParser; import com.adobe.epubcheck.xml.XMLValidators; import com.google.common.base.Preconditions; public class OverlayChecker implements ContentChecker, DocumentValidator { private final ValidationContext context; private final Report report; private final String path; public OverlayChecker(ValidationContext context) { Preconditions.checkState("application/smil+xml".equals(context.mimeType)); this.context = context; this.report = context.report; this.path = context.path; } public void runChecks() { OCFPackage ocf = context.ocf.get(); if (!ocf.hasEntry(path)) { report.message(MessageId.RSC_001, EPUBLocation.create(ocf.getName()), path); } else if (!ocf.canDecrypt(path)) { report.message(MessageId.RSC_004, EPUBLocation.create(ocf.getName()), path); } else { validate(); } } public boolean validate() { int fatalErrorsSoFar = report.getFatalErrorCount(); int errorsSoFar = report.getErrorCount(); int warningsSoFar = report.getWarningCount(); OverlayHandler overlayHandler; XMLParser overlayParser = new XMLParser(context); overlayHandler = new OverlayHandler(context, overlayParser); overlayParser.addValidator(XMLValidators.MO_30_RNC.get()); overlayParser.addValidator(XMLValidators.MO_30_SCH.get()); overlayParser.addXMLHandler(overlayHandler); overlayParser.process(); return fatalErrorsSoFar == report.getFatalErrorCount() && errorsSoFar == report.getErrorCount() && warningsSoFar == report.getWarningCount(); } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/overlay/OverlayHandler.java0000644000175000017500000001003213017276730026432 0ustar eugeneeugenepackage com.adobe.epubcheck.overlay; import java.util.Map; import java.util.Set; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.messages.MessageId; import com.adobe.epubcheck.opf.OPFChecker30; import com.adobe.epubcheck.opf.ValidationContext; import com.adobe.epubcheck.opf.XRefChecker; import com.adobe.epubcheck.util.EpubConstants; import com.adobe.epubcheck.util.HandlerUtil; import com.adobe.epubcheck.util.PathUtil; import com.adobe.epubcheck.vocab.StructureVocab; import com.adobe.epubcheck.vocab.Vocab; import com.adobe.epubcheck.vocab.VocabUtil; import com.adobe.epubcheck.xml.XMLElement; import com.adobe.epubcheck.xml.XMLHandler; import com.adobe.epubcheck.xml.XMLParser; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; public class OverlayHandler implements XMLHandler { private static Map RESERVED_VOCABS = ImmutableMap. of("", StructureVocab.VOCAB); private static Map KNOWN_VOCAB_URIS = ImmutableMap.of(); private static Set DEFAULT_VOCAB_URIS = ImmutableSet.of(StructureVocab.URI); private final ValidationContext context; private final String path; private final Report report; private final XMLParser parser; private boolean checkedUnsupportedXMLVersion; private Map vocabs = RESERVED_VOCABS; public OverlayHandler(ValidationContext context, XMLParser parser) { this.context = context; this.path = context.path; this.report = context.report; this.parser = parser; checkedUnsupportedXMLVersion = false; } public void startElement() { if (!checkedUnsupportedXMLVersion) { HandlerUtil.checkXMLVersion(parser); checkedUnsupportedXMLVersion = true; } XMLElement e = parser.getCurrentElement(); String name = e.getName(); if (name.equals("smil")) { vocabs = VocabUtil.parsePrefixDeclaration( e.getAttributeNS(EpubConstants.EpubTypeNamespaceUri, "prefix"), RESERVED_VOCABS, KNOWN_VOCAB_URIS, DEFAULT_VOCAB_URIS, report, EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber())); } else if (name.equals("seq")) { processSeq(e); } else if (name.equals("text")) { processSrc(e); } else if (name.equals("audio")) { processRef(e.getAttribute("src"), XRefChecker.Type.AUDIO); } else if (name.equals("body") || name.equals("par")) { checkType(e.getAttributeNS(EpubConstants.EpubTypeNamespaceUri, "type")); } } private void checkType(String type) { VocabUtil.parsePropertyList(type, vocabs, report, EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber())); } private void processSrc(XMLElement e) { processRef(e.getAttribute("src"), XRefChecker.Type.HYPERLINK); } private void processRef(String ref, XRefChecker.Type type) { if (ref != null && context.xrefChecker.isPresent()) { ref = PathUtil.resolveRelativeReference(path, ref, null); if (type == XRefChecker.Type.AUDIO) { String mimeType = context.xrefChecker.get().getMimeType(ref); if (mimeType != null && !OPFChecker30.isBlessedAudioType(mimeType)) { report.message(MessageId.MED_005, EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber()), ref, mimeType); } } context.xrefChecker.get().registerReference(path, parser.getLineNumber(), parser.getColumnNumber(), ref, type); } } private void processSeq(XMLElement e) { processRef(e.getAttributeNS(EpubConstants.EpubTypeNamespaceUri, "textref"), XRefChecker.Type.HYPERLINK); checkType(e.getAttributeNS(EpubConstants.EpubTypeNamespaceUri, "type")); } public void characters(char[] chars, int arg1, int arg2) { } public void endElement() { } public void ignorableWhitespace(char[] chars, int arg1, int arg2) { } public void processingInstruction(String arg0, String arg1) { } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/overlay/OverlayCheckerFactory.java0000644000175000017500000000327513017276730027764 0ustar eugeneeugene/* * Copyright (c) 2011 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.overlay; import com.adobe.epubcheck.opf.ContentCheckerFactory; import com.adobe.epubcheck.opf.DocumentValidatorFactory; import com.adobe.epubcheck.opf.ValidationContext; public class OverlayCheckerFactory implements ContentCheckerFactory, DocumentValidatorFactory { public OverlayChecker newInstance(ValidationContext context) { return new OverlayChecker(context); } static private final OverlayCheckerFactory instance = new OverlayCheckerFactory(); static public OverlayCheckerFactory getInstance() { return instance; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/nav/0000755000175000017500000000000013017276730021757 5ustar eugeneeugeneepubcheck-4.0.2/src/main/java/com/adobe/epubcheck/nav/NavCheckerFactory.java0000644000175000017500000000324013017276730026162 0ustar eugeneeugene/* * Copyright (c) 2011 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.nav; import com.adobe.epubcheck.opf.ContentCheckerFactory; import com.adobe.epubcheck.opf.DocumentValidatorFactory; import com.adobe.epubcheck.opf.ValidationContext; public class NavCheckerFactory implements ContentCheckerFactory, DocumentValidatorFactory { static private final NavCheckerFactory instance = new NavCheckerFactory(); public NavChecker newInstance(ValidationContext context) { return new NavChecker(context); } static public NavCheckerFactory getInstance() { return instance; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/nav/NavHandler.java0000644000175000017500000000345013017276730024646 0ustar eugeneeugenepackage com.adobe.epubcheck.nav; import java.util.Set; import com.adobe.epubcheck.opf.ValidationContext; import com.adobe.epubcheck.ops.OPSHandler30; import com.adobe.epubcheck.util.FeatureEnum; import com.adobe.epubcheck.vocab.StructureVocab.EPUB_TYPES; import com.adobe.epubcheck.xml.XMLElement; import com.adobe.epubcheck.xml.XMLParser; public class NavHandler extends OPSHandler30 { private boolean inToc = false; NavHandler(ValidationContext context, XMLParser parser) { super(context, parser); } @Override public void startElement() { super.startElement(); XMLElement e = parser.getCurrentElement(); String name = e.getName(); if (inToc && "a".equals(name)) { context.featureReport.report(FeatureEnum.TOC_LINKS, parser.getLocation()); } } @Override public void endElement() { super.endElement(); XMLElement e = parser.getCurrentElement(); String name = e.getName(); if (inToc && "nav".equals(name)) { inToc = false; } } protected void checkTypes(Set types) { super.checkTypes(types); if (types.contains(EPUB_TYPES.TOC)) { inToc = true; } if (types.contains(EPUB_TYPES.PAGE_LIST)) { context.featureReport.report(FeatureEnum.PAGE_LIST, parser.getLocation()); } if (types.contains(EPUB_TYPES.LOI)) { context.featureReport.report(FeatureEnum.LOI, parser.getLocation()); } if (types.contains(EPUB_TYPES.LOT)) { context.featureReport.report(FeatureEnum.LOT, parser.getLocation()); } if (types.contains(EPUB_TYPES.LOA)) { context.featureReport.report(FeatureEnum.LOA, parser.getLocation()); } if (types.contains(EPUB_TYPES.LOV)) { context.featureReport.report(FeatureEnum.LOV, parser.getLocation()); } } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/nav/NavChecker.java0000644000175000017500000001161713017276730024641 0ustar eugeneeugene/* * Copyright (c) 2011 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.nav; import static com.adobe.epubcheck.opf.ValidationContext.ValidationContextPredicates.*; import static com.google.common.base.Predicates.*; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.api.EPUBProfile; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.messages.MessageId; import com.adobe.epubcheck.opf.ContentChecker; import com.adobe.epubcheck.opf.DocumentValidator; import com.adobe.epubcheck.opf.OPFData; import com.adobe.epubcheck.opf.ValidationContext; import com.adobe.epubcheck.util.EPUBVersion; import com.adobe.epubcheck.util.ValidatorMap; import com.adobe.epubcheck.vocab.EpubCheckVocab; import com.adobe.epubcheck.vocab.PackageVocabs; import com.adobe.epubcheck.xml.XMLHandler; import com.adobe.epubcheck.xml.XMLParser; import com.adobe.epubcheck.xml.XMLValidator; import com.adobe.epubcheck.xml.XMLValidators; import com.google.common.base.Preconditions; import com.google.common.base.Predicates; public class NavChecker implements ContentChecker, DocumentValidator { @SuppressWarnings("unchecked") private final static ValidatorMap validatorMap = ValidatorMap.builder() .putAll(XMLValidators.NAV_30_RNC, XMLValidators.XHTML_30_SCH, XMLValidators.NAV_30_SCH) .putAll(and(Predicates.or(profile(EPUBProfile.EDUPUB), hasPubType(OPFData.DC_TYPE_EDUPUB)), not( hasProp(EpubCheckVocab.VOCAB.get(EpubCheckVocab.PROPERTIES.FIXED_LAYOUT))), not(hasProp(EpubCheckVocab.VOCAB.get(EpubCheckVocab.PROPERTIES.NON_LINEAR)))), XMLValidators.XHTML_EDUPUB_STRUCTURE_SCH, XMLValidators.XHTML_EDUPUB_SEMANTICS_SCH, XMLValidators.XHTML_IDX_SCH) .putAll( and(or(profile(EPUBProfile.DICT), hasPubType(OPFData.DC_TYPE_DICT)), mimetype("application/xhtml+xml"), version(EPUBVersion.VERSION_3)), XMLValidators.XHTML_DICT_SCH) .putAll( and(or(profile(EPUBProfile.IDX), hasPubType(OPFData.DC_TYPE_INDEX), hasProp(PackageVocabs.ITEM_VOCAB.get(PackageVocabs.ITEM_PROPERTIES.INDEX)), hasProp(EpubCheckVocab.VOCAB.get(EpubCheckVocab.PROPERTIES.IN_INDEX_COLLECTION))), mimetype("application/xhtml+xml"), version(EPUBVersion.VERSION_3)), XMLValidators.XHTML_IDX_SCH, XMLValidators.XHTML_IDX_INDEX_SCH) .build(); private final ValidationContext context; private final Report report; private final String path; public NavChecker(ValidationContext context) { Preconditions.checkState("application/xhtml+xml".equals(context.mimeType)); this.context = context; this.report = context.report; this.path = context.path; if (context.version == EPUBVersion.VERSION_2) { context.report.message(MessageId.NAV_001, EPUBLocation.create(path)); } } @Override public void runChecks() { if (!context.ocf.get().hasEntry(path)) { report.message(MessageId.RSC_001, EPUBLocation.create(context.ocf.get().getName()), path); } else if (!context.ocf.get().canDecrypt(path)) { report.message(MessageId.RSC_004, EPUBLocation.create(context.ocf.get().getName()), path); } else { validate(); } } public boolean validate() { int fatalErrors = report.getFatalErrorCount(); int errors = report.getErrorCount(); int warnings = report.getWarningCount(); XMLParser navParser = new XMLParser(context); XMLHandler navHandler = new NavHandler(context, navParser); navParser.addXMLHandler(navHandler); for (XMLValidator validator : validatorMap.getValidators(context)) { navParser.addValidator(validator); } navParser.process(); return ((fatalErrors == report.getFatalErrorCount()) && (errors == report.getErrorCount()) && (warnings == report.getWarningCount())); } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ncx/0000755000175000017500000000000013017276730021763 5ustar eugeneeugeneepubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ncx/NCXChecker.java0000755000175000017500000000642513017276730024555 0ustar eugeneeugene/* * Copyright (c) 2007 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.ncx; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.messages.MessageId; import com.adobe.epubcheck.ocf.OCFPackage; import com.adobe.epubcheck.opf.ContentChecker; import com.adobe.epubcheck.opf.ValidationContext; import com.adobe.epubcheck.util.EPUBVersion; import com.adobe.epubcheck.xml.XMLParser; import com.adobe.epubcheck.xml.XMLValidators; import com.google.common.base.Preconditions; public class NCXChecker implements ContentChecker { private final ValidationContext context; private final Report report; private final String path; public NCXChecker(ValidationContext context) { Preconditions.checkState("application/x-dtbncx+xml".equals(context.mimeType)); this.context = context; this.report = context.report; this.path = context.path; } public void runChecks() { OCFPackage ocf = context.ocf.get(); if (!ocf.hasEntry(path)) { report.message(MessageId.RSC_001, EPUBLocation.create(ocf.getName()), path); } else if (!ocf.canDecrypt(path)) { report.message(MessageId.RSC_004, EPUBLocation.create(ocf.getName()), path); } else { // relaxng XMLParser ncxParser; NCXHandler ncxHandler; ncxParser = new XMLParser(context); ncxParser.addValidator(XMLValidators.NCX_RNG.get()); ncxParser.addValidator(XMLValidators.NCX_SCH.get()); ncxHandler = new NCXHandler(ncxParser, path, context.xrefChecker.get()); ncxParser.addXMLHandler(ncxHandler); ncxParser.process(); if (context.version == EPUBVersion.VERSION_2) { String ncxId = ncxHandler.getUid(); if (ncxId != null && !ncxId.equals(ncxId.trim())) { report.message(MessageId.NCX_004, ncxParser.getLocation()); } // FIXME improve way to get this EPUB 2's single OPF String uid = ocf.getOpfData().values().iterator().next().getUniqueIdentifier(); if (uid != null && ncxId != null && !uid.equals(ncxId.trim())) { report.message(MessageId.NCX_001, ncxParser.getLocation(), ncxHandler.getUid(), uid); } } } } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ncx/NCXCheckerFactory.java0000755000175000017500000000317713017276730026106 0ustar eugeneeugene/* * Copyright (c) 2007 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.ncx; import com.adobe.epubcheck.opf.ContentChecker; import com.adobe.epubcheck.opf.ContentCheckerFactory; import com.adobe.epubcheck.opf.ValidationContext; public class NCXCheckerFactory implements ContentCheckerFactory { static private final NCXCheckerFactory instance = new NCXCheckerFactory(); public ContentChecker newInstance(ValidationContext context) { return new NCXChecker(context); } static public NCXCheckerFactory getInstance() { return instance; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ncx/NCXHandler.java0000755000175000017500000001004713017276730024561 0ustar eugeneeugene/* * Copyright (c) 2007 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.ncx; import com.adobe.epubcheck.messages.MessageId; import com.adobe.epubcheck.opf.XRefChecker; import com.adobe.epubcheck.util.FeatureEnum; import com.adobe.epubcheck.util.HandlerUtil; import com.adobe.epubcheck.util.PathUtil; import com.adobe.epubcheck.xml.XMLElement; import com.adobe.epubcheck.xml.XMLHandler; import com.adobe.epubcheck.xml.XMLParser; public class NCXHandler implements XMLHandler { private final XMLParser parser; private final String path; private final XRefChecker xrefChecker; String uid; boolean checkedUnsupportedXmlVersion = false; NCXHandler(XMLParser parser, String path, XRefChecker xrefChecker) { this.parser = parser; this.path = path; this.xrefChecker = xrefChecker; } public void characters(char[] chars, int start, int len) { XMLElement e = parser.getCurrentElement(); String name = e.getName(); String ns = e.getNamespace(); boolean keepValue = ("http://www.daisy.org/z3986/2005/ncx/".equals(ns) && "text".equals(name)); if (keepValue) { String val = (String) e.getPrivateData(); String text = new String(chars, start, len); e.setPrivateData((val == null) ? text : val + text); } } public void ignorableWhitespace(char[] chars, int arg1, int arg2) { } public void startElement() { if (!checkedUnsupportedXmlVersion) { HandlerUtil.checkXMLVersion(parser); checkedUnsupportedXmlVersion = true; } XMLElement e = parser.getCurrentElement(); String ns = e.getNamespace(); String name = e.getName(); if (ns.equals("http://www.daisy.org/z3986/2005/ncx/")) { if ("content".equals(name)) { String href = e.getAttribute("src"); if (href != null) { href = PathUtil.resolveRelativeReference(path, href, null); if (href.startsWith("http:")) { parser.getReport().info(path, FeatureEnum.REFERENCE, href); } xrefChecker.registerReference(path, parser.getLineNumber(), parser.getColumnNumber(), href, XRefChecker.Type.HYPERLINK); } } else if ("meta".equals(name)) { String metaName = e.getAttribute("name"); if ("dtb:uid".equals(metaName)) { uid = e.getAttribute("content"); } } } } public void endElement() { XMLElement e = parser.getCurrentElement(); String ns = e.getNamespace(); String name = e.getName(); if (ns.equals("http://www.daisy.org/z3986/2005/ncx/")) { if ("text".equals(name)) { String text = (String) e.getPrivateData(); if (text == null || text.trim().isEmpty()) { parser.getReport().message(MessageId.NCX_006, parser.getLocation()); } } } } public void processingInstruction(String arg0, String arg1) { } /** * @return the uid */ public String getUid() { return uid; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/reporting/0000755000175000017500000000000013017276730023204 5ustar eugeneeugeneepubcheck-4.0.2/src/main/java/com/adobe/epubcheck/reporting/ItemMetadata.java0000644000175000017500000001154113017276730026410 0ustar eugeneeugenepackage com.adobe.epubcheck.reporting; import java.util.Map; import java.util.SortedSet; import java.util.TreeSet; import org.codehaus.jackson.annotate.JsonProperty; import com.adobe.epubcheck.util.FeatureEnum; @SuppressWarnings("FieldCanBeLocal") public class ItemMetadata implements Comparable { @JsonProperty private String id = ""; @JsonProperty private String fileName; @JsonProperty private String media_type; @JsonProperty private long compressedSize; @JsonProperty private long uncompressedSize; @JsonProperty private String compressionMethod; @JsonProperty private String checkSum; @JsonProperty private boolean isSpineItem; @JsonProperty private Integer spineIndex; @JsonProperty private boolean isLinear; @JsonProperty private Integer navigationOrder = null; @JsonProperty private boolean isHTML5; @JsonProperty private Boolean isFixedFormat = null; @JsonProperty private boolean isScripted; @JsonProperty private boolean scriptSrc; @JsonProperty private boolean scriptTag; @JsonProperty private boolean scriptInline; @JsonProperty private String renditionLayout; @JsonProperty private String renditionOrientation; @JsonProperty private String renditionSpread; @SuppressWarnings("MismatchedQueryAndUpdateOfCollection") @JsonProperty private final SortedSet referencedItems = new TreeSet(); public static ItemMetadata getItemByName(Map metadata, String fileName) { ItemMetadata result = metadata.get(fileName); if (result == null) { result = new ItemMetadata(); result.fileName = fileName; metadata.put(fileName, result); } return result; } public String getId() { return this.id; } public void setId(String value) { this.id = value; } public String getFileName() { return this.fileName; } public String getRenditionLayout() { return this.renditionLayout; } public void setRenditionLayout(String value) { this.renditionLayout = value; } public String getRenditionOrientation() { return this.renditionOrientation; } public void setRenditionOrientation(String value) { this.renditionOrientation = value; } public String getRenditionSpread() { return this.renditionSpread; } public void setRenditionSpread(String value) { this.renditionSpread = value; } public Boolean getIsFixedFormat() { return this.isFixedFormat; } public void setIsFixedFormat(Boolean value) { this.isFixedFormat = value; } public boolean getIsSpineItem() { return this.isSpineItem; } public void handleInfo(FeatureEnum feature, String value) { switch (feature) { case DECLARED_MIMETYPE: this.media_type = value; break; case HAS_SCRIPTS: this.isScripted = true; break; case HAS_FIXED_LAYOUT: this.isFixedFormat = true; break; case IS_SPINEITEM: this.isSpineItem = true; break; case UNIQUE_IDENT: this.id = value != null ? value : ""; break; case IS_LINEAR: this.isLinear = Boolean.parseBoolean(value.trim()); break; case RESOURCE: if (!value.equals(this.fileName)) { this.referencedItems.add(value); } break; case SIZE: this.uncompressedSize = Long.parseLong(value.trim()); break; case COMPRESSED_SIZE: this.compressedSize = Long.parseLong(value.trim()); break; case COMPRESSION_METHOD: this.compressionMethod = value; break; case SHA_256: this.checkSum = value; break; case SPINE_INDEX: this.spineIndex = Integer.parseInt(value.trim()); break; case HAS_HTML5: this.isHTML5 = true; break; case SCRIPT: if (value.equals("inline")) { this.scriptInline = true; } else if (value.equals("external")) { this.scriptSrc = true; } else if (value.equals("javascript")) { this.scriptSrc = true; } else if (value.equals("tag")) { this.scriptTag = true; } break; case RENDITION_LAYOUT: this.renditionLayout = value; break; case RENDITION_ORIENTATION: this.renditionOrientation = value; break; case RENDITION_SPREAD: this.renditionSpread = value; break; case NAVIGATION_ORDER: this.navigationOrder = Integer.parseInt(value.trim()); break; default: //System.err.printf("unhandled info message feature: found '%s' with value '%s'", feature.toString(), value != null ? value : "null"); break; } } public int compareTo(ItemMetadata item) { return this.id.compareTo(item.id); } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/reporting/CheckingReport.java0000644000175000017500000001173113017276730026761 0ustar eugeneeugenepackage com.adobe.epubcheck.reporting; import com.adobe.epubcheck.api.EpubCheck; import com.adobe.epubcheck.api.MasterReport; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.messages.Message; import com.adobe.epubcheck.util.FeatureEnum; import com.adobe.epubcheck.util.JsonWriter; import com.adobe.epubcheck.util.PathUtil; import com.adobe.epubcheck.util.outWriter; import org.codehaus.jackson.annotate.JsonProperty; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.PrintStream; import java.util.*; public class CheckingReport extends MasterReport { @JsonProperty final CheckerMetadata checker; @JsonProperty final PublicationMetadata publication; Map itemIndex = null; @JsonProperty List items = null; @JsonProperty final List messages = new ArrayList(); final String outputFile; public CheckingReport(String epubPath, String outFile) { this.checker = new CheckerMetadata(); this.publication = new PublicationMetadata(); this.outputFile = outFile; this.setEpubFileName(epubPath); } void setParameters() { outWriter.println("Epub Name: " + PathUtil.removeWorkingDirectory(this.getEpubFileName())); this.checker.setCheckerVersion(EpubCheck.version()); File f = new File(this.getEpubFileName()); this.checker.setFileInfo(f); this.checker.setMessageTypes(this.messages); boolean defaultFixedFormat = this.publication.getRenditionLayout().equals("pre-paginated"); for (ItemMetadata item : this.getItems()) { String id = item.getId(); if (id == null || id.equals("")) { item.setId("ePubCheck.NoManifestRef:" + item.getFileName()); } if (item.getIsSpineItem()) { String layout = item.getRenditionLayout(); if (layout == null || layout.equals("")) { item.setRenditionLayout(this.publication.getRenditionLayout()); } String orientation = item.getRenditionOrientation(); if (orientation == null || orientation.equals("")) { item.setRenditionOrientation(this.publication.getRenditionOrientation()); } String spread = item.getRenditionSpread(); if (spread == null || spread.equals("")) { item.setRenditionSpread(this.publication.getRenditionSpread()); } Boolean isFixed = item.getIsFixedFormat(); if (isFixed == null) { item.setIsFixedFormat(defaultFixedFormat); } } } } public int generate() { this.setStopDate(); this.setParameters(); try { this.getJsonReport(this.outputFile); } catch (IOException e) { outWriter.println("Incorrect path to save JsonFile."); return 1; } long duration = this.getProcessDuration(); outWriter.println("Process duration: " + duration + "ms"); return 0; } public void initialize() { this.setStartDate(); } void getJsonReport(String path) throws IOException { sortCollections(); OutputStream out = null; try { if (path == null) { out = new PrintStream(System.out); } else { out = new FileOutputStream(path); } JsonWriter jw = JsonWriter.createJsonWriter(true); jw.writeJson(this, out); } finally { if (out != null) { out.close(); } } } void sortCollections() { Collections.sort(getItems()); Collections.sort(messages); for (CheckMessage m : messages) { m.sortLocations(); } } long getProcessDuration() { return this.checker.getProcessDuration(); } void setStartDate() { this.checker.setStartDate(); } void setStopDate() { this.checker.setStopDate(); } @Override public void message(Message message, EPUBLocation location, Object... args) { CheckMessage.addCheckMessage(messages, message, location, args); } @Override public void info(String resource, FeatureEnum feature, String value) { this.publication.handleInfo(resource, feature, value); if (resource != null && !resource.equals("")) { ItemMetadata item = ItemMetadata.getItemByName(getItemIndex(), resource); item.handleInfo(feature, value); } } List getItems() { if (this.items == null) { if (this.itemIndex != null) { this.items = new ArrayList(itemIndex.values()); } else { this.items = new ArrayList(); } } return items; } Map getItemIndex() { if (this.itemIndex == null) { this.itemIndex = new HashMap(); if (this.items != null && this.items.size() > 0) { for (ItemMetadata item : items) { itemIndex.put(item.getFileName(), item); } } } return itemIndex; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/reporting/CheckMessage.java0000644000175000017500000001210213017276730026365 0ustar eugeneeugenepackage com.adobe.epubcheck.reporting; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.codehaus.jackson.annotate.JsonProperty; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.messages.Message; import com.adobe.epubcheck.messages.Severity; @SuppressWarnings("FieldCanBeLocal") public class CheckMessage implements Comparable { private static final int MAX_LOCATIONS = 25; @JsonProperty private final String ID; @JsonProperty private final Severity severity; @JsonProperty private String message; @JsonProperty private int additionalLocations = 0; @JsonProperty private final List locations = new ArrayList(); @JsonProperty private final String suggestion; private CheckMessage(Message message, EPUBLocation location, Object... args) { this.ID = message.getID().toString(); this.message = message.getMessage(args); this.locations.add(location); this.severity = message.getSeverity(); this.suggestion = ("".equals(message.getSuggestion())) ? null : message.getSuggestion(); } public static CheckMessage addCheckMessage(List checkMessages, Message message, EPUBLocation location, Object... args) { CheckMessage result = findCheckMessage(checkMessages, message.getID().toString(), message.getMessage(args)); if (result == null) { result = new CheckMessage(message, location, args); checkMessages.add(result); } else { result.addLocation(location); } return result; } void addLocation(EPUBLocation location) { if (this.findLocation(location) == null) { if (this.locations.size() == CheckMessage.MAX_LOCATIONS) { ++additionalLocations; this.locations.add(EPUBLocation.create("There is 1 additional location for this message.")); } else if (this.locations.size() < CheckMessage.MAX_LOCATIONS) { this.locations.add(location); } else { ++additionalLocations; EPUBLocation infoLocation = this.locations.remove(this.locations.size() - 1); this.locations.add(EPUBLocation.create(String.format("There are %1$s additional locations for this message.", additionalLocations), infoLocation.getLine(),infoLocation.getLine(),infoLocation.getContext().orNull())); } } } private static CheckMessage findCheckMessage(List checkMessages, String id, String text) { for (CheckMessage message : checkMessages) { if (message.ID.equals(id)) { if (message.message.equals(text)) { return message; } } } return null; } public Severity getSeverity() { return this.severity; } private EPUBLocation findLocation(EPUBLocation location) { for (EPUBLocation l : this.locations) { if (l.equals(location)) { return l; } } return null; } public String toString() { EPUBLocation location = this.locations.get(this.locations.size() - 1); String lineSeparator = System.getProperty("line.separator"); String text; text = "ID: " + ID + lineSeparator + "SEVERITY: " + (severity != null ? severity : "-UNDEFINED-") + lineSeparator + lineSeparator + "ERRONEOUS FILE NAME: " + location.getPath() + lineSeparator; if (location.getLine() > 0 && location.getColumn() > 0) { text += "LINE NUMBER: " + location.getLine() + lineSeparator; } text += "COLUMN NUMBER: " + location.getColumn() + lineSeparator; text += "DESCRIPTION (long): " + this.message + lineSeparator; text += "==========================================================================================================================" + lineSeparator; return text; } int safeCompare(String a, String b) { if (a == null && b != null) return -1; if (a != null && b == null) return 1; if (a == null /* && b == null */) return 0; return a.compareTo(b); } @Override public int compareTo(CheckMessage o) { int comp = safeCompare(this.ID, o.ID); if (comp != 0) { return comp; } comp = severity.toInt() - o.severity.toInt(); if (comp != 0) { return comp < 0 ? -1 : 1; } comp = safeCompare(message, o.message); if (comp != 0) { return comp; } comp = safeCompare(suggestion, o.suggestion); if (comp != 0) { return comp; } comp = additionalLocations - o.additionalLocations; if (comp != 0) { return comp < 0 ? -1 : 1; } comp = (locations.size() - o.locations.size()); if (comp != 0) { return comp < 0 ? -1 : 1; } return 0; } public void sortLocations() { Collections.sort(locations); } public String getID() { return ID; } public String getMessage() { return message; } public int getAdditionalLocations() { return additionalLocations; } public List getLocations() { return locations; } public String getSuggestion() { return suggestion; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/reporting/CheckerMetadata.java0000644000175000017500000000502013017276730027051 0ustar eugeneeugenepackage com.adobe.epubcheck.reporting; import com.adobe.epubcheck.util.PathUtil; import com.adobe.epubcheck.util.outWriter; import org.codehaus.jackson.annotate.JsonProperty; import java.io.File; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; /** * This describes properties about the checker. It is intended to be serialized into json. */ @SuppressWarnings("FieldCanBeLocal") class CheckerMetadata { @JsonProperty private String path; @JsonProperty private String filename; @JsonProperty private String checkerVersion; @JsonProperty private String checkDate; @JsonProperty private long elapsedTime = -1; // Elapsed Time in Seconds @JsonProperty private int nFatal = 0; @JsonProperty private int nError = 0; @JsonProperty private int nWarning = 0; @JsonProperty private int nUsage = 0; private final String workingDirectory = System.getProperty("user.dir"); public void setFileInfo(File epubFile) { this.path = PathUtil.removeWorkingDirectory(epubFile.getAbsolutePath()); this.filename = epubFile.getName(); } private Date processStartDateTime; private Date processEndDateTime; private static final SimpleDateFormat dateFormat = new SimpleDateFormat("MM-dd-yyyy HH:mm:ss"); public CheckerMetadata() { } public void setCheckerVersion(String value) { this.checkerVersion = value; //this.checkerVersion = "${pom.version}"; } public long getProcessDuration() { if (elapsedTime == -1) { setElapsedTime(); } return this.elapsedTime; } public void setStartDate() { this.processStartDateTime = new Date(); this.checkDate = CheckerMetadata.dateFormat.format(this.processStartDateTime); } public void setStopDate() { this.processEndDateTime = new Date(); this.setElapsedTime(); } private void setElapsedTime() { this.elapsedTime = this.processEndDateTime.getTime() - this.processStartDateTime.getTime(); } public void setMessageTypes(List messages) { for (CheckMessage message : messages) { if (message.getSeverity() != null) { switch (message.getSeverity()) { case FATAL: nFatal++; break; case ERROR: nError++; break; case WARNING: nWarning++; break; case USAGE: nUsage++; break; } } else { outWriter.print("message with no severity"); } } } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/reporting/PublicationMetadata.java0000644000175000017500000001132113017276730027757 0ustar eugeneeugenepackage com.adobe.epubcheck.reporting; import com.adobe.epubcheck.util.FeatureEnum; import org.codehaus.jackson.annotate.JsonProperty; import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; /** * This is information about the publication in general. It is intended to be serialized into json. */ @SuppressWarnings({"FieldCanBeLocal", "MismatchedQueryAndUpdateOfCollection"}) class PublicationMetadata { @JsonProperty private String publisher; @JsonProperty private String title; @JsonProperty private final List creator = new ArrayList(); @JsonProperty private String date; @JsonProperty private final List subject = new ArrayList(); @JsonProperty private String description; @JsonProperty private String rights; @JsonProperty private String identifier; @JsonProperty private String language; @JsonProperty private int nSpines; @JsonProperty private long checkSum; @JsonProperty private String renditionLayout = "reflowable"; @JsonProperty private String renditionOrientation = "auto"; @JsonProperty private String renditionSpread = "auto"; @JsonProperty private String ePubVersion; @JsonProperty private boolean isScripted = false; @JsonProperty private boolean hasFixedFormat = false; @JsonProperty private boolean isBackwardCompatible = true; @JsonProperty private boolean hasAudio = false; @JsonProperty private boolean hasVideo = false; @JsonProperty private long charsCount = 0; @JsonProperty private final Set embeddedFonts = new LinkedHashSet(); @JsonProperty private final Set refFonts = new LinkedHashSet(); @JsonProperty private boolean hasEncryption; @JsonProperty private boolean hasSignatures; @JsonProperty private final Set contributors = new LinkedHashSet(); public PublicationMetadata() { } public String getRenditionLayout() { return this.renditionLayout; } public String getRenditionOrientation() { return this.renditionOrientation; } public String getRenditionSpread() { return this.renditionSpread; } public void handleInfo(String resource, FeatureEnum feature, String value) { switch (feature) { case DC_TITLE: this.title = value; break; case DC_LANGUAGE: this.language = value; break; case DC_PUBLISHER: this.publisher = value; break; case DC_CREATOR: this.creator.add(value); break; case DC_RIGHTS: this.rights = value; break; case DC_SUBJECT: this.subject.add(value); break; case DC_DESCRIPTION: this.description = value; break; case MODIFIED_DATE: this.date = value; break; case UNIQUE_IDENT: if (resource == null) { this.identifier = value; } break; case FORMAT_VERSION: this.ePubVersion = value; break; case HAS_SCRIPTS: this.isScripted = true; this.isBackwardCompatible = false; break; case HAS_FIXED_LAYOUT: this.hasFixedFormat = true; this.isBackwardCompatible = false; break; case HAS_HTML5: if (resource == null) { this.isBackwardCompatible = false; } break; case IS_SPINEITEM: this.nSpines++; break; case HAS_NCX: if (!Boolean.parseBoolean(value)) { this.isBackwardCompatible = false; } break; case RENDITION_LAYOUT: if (resource == null) { this.renditionLayout = value; } break; case RENDITION_ORIENTATION: if (resource == null) { this.renditionOrientation = value; } break; case RENDITION_SPREAD: if (resource == null) { this.renditionSpread = value; } break; case CHARS_COUNT: this.charsCount += Long.parseLong(value); break; case DECLARED_MIMETYPE: if (value != null && value.startsWith("audio/")) { this.hasAudio = true; } else if (value != null && value.startsWith("video/")) { this.hasVideo = true; } break; case FONT_EMBEDDED: this.embeddedFonts.add(value); break; case FONT_REFERENCE: this.refFonts.add(value); break; case HAS_SIGNATURES: this.hasSignatures = true; break; case HAS_ENCRYPTION: this.hasEncryption = true; break; case DC_CONTRIBUTOR: this.contributors.add(value); break; } } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/opf/0000755000175000017500000000000013017276730021757 5ustar eugeneeugeneepubcheck-4.0.2/src/main/java/com/adobe/epubcheck/opf/LinkedResource.java0000644000175000017500000000773313017276730025552 0ustar eugeneeugenepackage com.adobe.epubcheck.opf; import static com.google.common.base.Preconditions.checkNotNull; import java.util.Set; import com.adobe.epubcheck.vocab.Property; import com.google.common.base.Optional; import com.google.common.base.Strings; import com.google.common.collect.ImmutableSet; /** * Represents a linked resource in a Package Document, i.e. a resource * referenced from a link element (either at the package level or * in collections). */ public final class LinkedResource { private final Optional id; private final String uri; private final String path; private final Set rel; private final Optional refines; private final Optional mimetype; /** * Returns an {@link Optional} containing the value of the ID of the * link , or {@link Optional#absent()} if the element has no ID. */ public Optional getId() { return id; } /** * Returns the URI of the linked resource as defined in the href * attribute of the link element. Guaranteed non-null. */ public String getURI() { return uri; } /** * Returns the "path" of the linked resource, i.e. its URI minus a possible * fragment. Guaranteed non-null. */ public String getPath() { return path; } /** * Returns the set of properties defining the nature of the resource, as * defined in the rel attribute. * * @return the set of rel properties (may be empty for collection resources). * Guaranteed non-null. */ public Set getRel() { return rel; } /** * Returns an {@link Optional} containing the value of the * refines attribute of the link , or * {@link Optional#absent()} if the element has no such attribute. */ public Optional getRefines() { return refines; } /** * Returns an {@link Optional} containing the declared media type of this * resource as specified in the media-type attribute, or * {@link Optional#absent()} if the media type is not declared. */ public Optional getMimeType() { return mimetype; } private LinkedResource(Optional id, String uri, String resource, Set rel, Optional refines, Optional mimetype) { this.id = checkNotNull(id); this.uri = checkNotNull(uri); this.path = checkNotNull(resource); this.rel = checkNotNull(rel); this.refines = checkNotNull(refines); this.mimetype = checkNotNull(mimetype); } /** * A builder for {@link LinkedResource}. */ public static final class Builder { private final String uri; private String id = null; private Set rel = null; private String refines = null; private String mimetype = null; /** * Creates a new builder for a resource of the given URI (must not be null). */ public Builder(String uri) { this.uri = checkNotNull(uri).trim(); } public Builder id(String id) { this.id = id; return this; } public Builder rel(Set rel) { this.rel = rel; return this; } public Builder refines(String refines) { this.refines = refines; return this; } public Builder mimetype(String mimetype) { this.mimetype = mimetype; return this; } /** * Returns a newly created {@link LinkedResource}. */ public LinkedResource build() { return new LinkedResource(optional(id), uri, uri.replaceFirst("#.*$", ""), rel == null ? ImmutableSet. of() : ImmutableSet.copyOf(rel), optional(refines), optional(mimetype)); } // Returns an optional containing the given string // or absent if the string is null or empty or space-only private Optional optional(String string) { return Optional.fromNullable(Strings.emptyToNull(Strings.nullToEmpty(id).trim())); } } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/opf/OPFReference.java0000644000175000017500000000353613017276730025074 0ustar eugeneeugene/* * Copyright (c) 2007 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.opf; public class OPFReference { private final String type; private final String title; private final String href; private final int lineNumber; private final int columnNumber; OPFReference(String type, String title, String href, int lineNumber, int columnNumber) { this.type = type; this.title = title; this.href = href; this.lineNumber = lineNumber; this.columnNumber = columnNumber; } public String getType() { return type; } public String getTitle() { return title; } public String getHref() { return href; } public int getLineNumber() { return lineNumber; } public int getColumnNumber() { return columnNumber; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/opf/OPFHandler.java0000755000175000017500000005730013017276730024554 0ustar eugeneeugene/* * Copyright (c) 2007 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.opf; import java.text.SimpleDateFormat; import java.util.Collections; import java.util.Date; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Vector; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.messages.MessageId; import com.adobe.epubcheck.util.DateParser; import com.adobe.epubcheck.util.EPUBVersion; import com.adobe.epubcheck.util.FeatureEnum; import com.adobe.epubcheck.util.HandlerUtil; import com.adobe.epubcheck.util.InvalidDateException; import com.adobe.epubcheck.util.PathUtil; import com.adobe.epubcheck.xml.XMLElement; import com.adobe.epubcheck.xml.XMLHandler; import com.adobe.epubcheck.xml.XMLParser; import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.base.Strings; import com.google.common.collect.ImmutableList; import com.google.common.collect.Maps; public class OPFHandler implements XMLHandler { protected final String path; protected final XMLParser parser; protected final Report report; protected final ValidationContext context; protected String pageMapId = null; protected EPUBLocation pageMapReferenceLocation = null; // Map of ID to OPFItem builders // Final OPFItem objects will be built after parsing protected final Map itemBuilders = Maps.newLinkedHashMap(); protected final Map itemBuildersByPath = Maps.newLinkedHashMap(); // A list of all spine item IDs private final List spineIDs = new LinkedList(); // Represents the set of items in this Package Doc private OPFItems items = null; // Hashtable encryptedItems; private final Vector refs = new Vector(); private static final HashSet validRoles = new HashSet(); // This string holds the value of the element's unique-identifier // attribute // that will be used to make sure that the unique-identifier references an // existing // id attribute private String uniqueIdent; // This boolean specifies whether or not there has been a // element // parsed that has an id attribute that corresponds with the // unique-identifier attribute // from the packaging element. The default value is false. private boolean uniqueIdentExists = false; // This string holds the value of the element detected String uid; private boolean opf12PackageFile = false; private boolean checkedUnsupportedXmlVersion = false; static { String[] list = { "acp", "act", "adp", "aft", "anl", "anm", "ann", "ant", "app", "aqt", "arc", "ard", "arr", "art", "asg", "asn", "att", "auc", "aud", "aui", "aus", "aut", "bdd", "bjd", "bkd", "bkp", "bnd", "bpd", "bsl", "ccp", "chr", "clb", "cli", "cll", "clr", "clt", "cmm", "cmp", "cmt", "cng", "cnd", "cns", "coe", "col", "com", "cos", "cot", "cov", "cpc", "cpe", "cph", "cpl", "cpt", "cre", "crp", "crr", "csl", "csp", "cst", "ctb", "cte", "ctg", "ctr", "cts", "ctt", "cur", "cwt", "dfd", "dfe", "dft", "dgg", "dis", "dln", "dnc", "dnr", "dpc", "dpt", "drm", "drt", "dsr", "dst", "dtc", "dte", "dtm", "dto", "dub", "edt", "egr", "elg", "elt", "eng", "etr", "exp", "fac", "fld", "flm", "fmo", "fpy", "fnd", "frg", "gis", "grt", "hnr", "hst", "ill", "ilu", "ins", "inv", "itr", "ive", "ivr", "lbr", "lbt", "ldr", "led", "lee", "lel", "len", "let", "lgd", "lie", "lil", "lit", "lsa", "lse", "lso", "ltg", "lyr", "mcp", "mfr", "mdc", "mod", "mon", "mrk", "msd", "mte", "mus", "nrt", "opn", "org", "orm", "oth", "own", "pat", "pbd", "pbl", "pdr", "pfr", "pht", "plt", "pma", "pmn", "pop", "ppm", "ppt", "prc", "prd", "prf", "prg", "prm", "pro", "prt", "pta", "pte", "ptf", "pth", "ptt", "rbr", "rce", "rcp", "red", "ren", "res", "rev", "rps", "rpt", "rpy", "rse", "rsg", "rsp", "rst", "rth", "rtm", "sad", "sce", "scl", "scr", "sds", "sec", "sgn", "sht", "sng", "spk", "spn", "spy", "srv", "std", "stl", "stm", "stn", "str", "tcd", "tch", "ths", "trc", "trl", "tyd", "tyg", "vdg", "voc", "wam", "wdc", "wde", "wit" }; Collections.addAll(validRoles, list); } public OPFHandler(ValidationContext context, XMLParser parser) { this.context = context; this.path = context.path; this.report = context.report; this.parser = parser; } public boolean getOpf12PackageFile() { return (opf12PackageFile); } public boolean getOpf20PackageFile() { return (!opf12PackageFile); } /** * Search the list of item by ID. * * @param id * the ID of the item to search * @return an {@link Optional} containing the item of the given ID if found, * or {@link Optional#absent()} */ public Optional getItemById(String id) { return (items != null) ? items.getItemById(id) : Optional. absent(); } /** * Search the list of item by path. * * @param id * the path of the item to search * @return an {@link Optional} containing the item of the given path if found, * or {@link Optional#absent()} */ public Optional getItemByPath(String path) { return (items != null) ? items.getItemByPath(path) : Optional. absent(); } /** * Returns an immutable list of the items in the spine. May contain duplicates * if several itemref elements point to the same item. *

* Returns the empty list if the items have not been parsed yet. *

* * @return the list of items in the spine, guaranteed non-null. */ public List getSpineItems() { return (items != null) ? items.getSpineItems() : ImmutableList. of(); } /** * Returns an immutable list of all the items in the OPF, in document order, * including those represented by link elements pointing to local * resources. * *

* Returns the empty list if the items have not been parsed yet. *

* * @return the list of all items, guaranteed non-null. */ public List getItems() { return (items != null) ? items.getItems() : ImmutableList. of(); } public int getReferenceCount() { return refs.size(); } public OPFReference getReference(int index) { return refs.elementAt(index); } /** * Checks to see if the unique-identifier attribute of the package element * references an existing DC metadata identifier element's id attribute * * @return true if there is an identifier with an id attribute that matches * the value of the unique-identifier attribute of the package * element. False otherwise. */ public boolean checkUniqueIdentExists() { return uniqueIdentExists; } public String getUid() { return uid; } // public void setEncryptedItems(Hashtable encryptedItems) { // this.encryptedItems = encryptedItems; // } private static boolean isValidRole(String role) { return validRoles.contains(role) || role.startsWith("oth."); } public void startElement() { if (!checkedUnsupportedXmlVersion) { HandlerUtil.checkXMLVersion(parser); checkedUnsupportedXmlVersion = true; } XMLElement e = parser.getCurrentElement(); String ns = e.getNamespace(); if (ns == null || ns.equals("") || ns.equals("http://openebook.org/namespaces/oeb-package/1.0/") || ns.equals("http://www.idpf.org/2007/opf")) { String name = e.getName(); if (name.equals("package")) { if (!ns.equals("http://www.idpf.org/2007/opf")) { report.message(MessageId.OPF_047, EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber())); opf12PackageFile = true; } /* * This section checks to see the value of the unique-identifier * attribute and stores it in the String uniqueIdent or reports an error * if the unique-identifier attribute is missing or does not have a * value */ String uniqueIdentAttr = e.getAttribute("unique-identifier"); if (uniqueIdentAttr != null && !uniqueIdentAttr.equals("")) { uniqueIdent = uniqueIdentAttr; } else { report.message(MessageId.OPF_048, EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber())); } } else if (name.equals("item")) { String id = e.getAttribute("id"); if (id != null) { String href = e.getAttribute("href"); if (href != null && !(context.version == EPUBVersion.VERSION_3 && href.matches("^[^:/?#]+://.*"))) { try { href = PathUtil.resolveRelativeReference(path, href, null); } catch (IllegalArgumentException ex) { report .message(MessageId.OPF_010, EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber(), href), ex.getMessage()); href = null; } } if (href != null && href.matches("^[^:/?#]+://.*")) { report.info(path, FeatureEnum.REFERENCE, href); } String mimeType = e.getAttribute("media-type"); String fallback = e.getAttribute("fallback"); // dirty fix for issue 271: treat @fallback attribute in EPUB3 like // fallback-style in EPUB2 // then all the epubcheck mechanisms on checking stylesheet fallbacks // will work as in EPUB 2 String fallbackStyle = (context.version == EPUBVersion.VERSION_3) ? e .getAttribute("fallback") : e.getAttribute("fallback-style"); if (context.version == EPUBVersion.VERSION_3 && href.matches("^[^:/?#]+://.*") && !OPFChecker30.isBlessedAudioType(mimeType) && !OPFChecker30.isBlessedVideoType(mimeType)) { if (OPFChecker30.isCoreMediaType(mimeType)) { report .message(MessageId.RSC_006, EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber()), href); } else { // mgy 20120414: this shouldn't even be a warning // report.warning( // path, // parser.getLineNumber(), // parser.getColumnNumber(), // "Remote resource not validated"); } } OPFItem.Builder itemBuilder = new OPFItem.Builder(id, href, mimeType, parser.getLineNumber(), parser.getColumnNumber()).fallback(fallback).fallbackStyle( fallbackStyle); itemBuilders.put(id.trim(), itemBuilder); itemBuildersByPath.put(href, itemBuilder); report.info(href, FeatureEnum.UNIQUE_IDENT, id); } } else if (name.equals("reference")) { String type = e.getAttribute("type"); String title = e.getAttribute("title"); String href = e.getAttribute("href"); if (href != null && context.xrefChecker.isPresent()) { try { href = PathUtil.resolveRelativeReference(path, href, null); context.xrefChecker.get().registerReference(path, parser.getLineNumber(), parser.getColumnNumber(), href, XRefChecker.Type.GENERIC); } catch (IllegalArgumentException ex) { report.message(MessageId.OPF_010, EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber(), href), ex.getMessage()); href = null; } } if (href != null && href.startsWith("http")) { report.info(path, FeatureEnum.REFERENCE, href); } OPFReference ref = new OPFReference(type, title, href, parser.getLineNumber(), parser.getColumnNumber()); refs.add(ref); } else if (name.equals("spine")) { String pageMap = e.getAttribute("page-map"); if (pageMap != null) { pageMapId = pageMap; pageMapReferenceLocation = EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber(), String.format("page-map=\"%1$s\"", pageMapId)); report.message(MessageId.OPF_062, pageMapReferenceLocation); } String idref = e.getAttribute("toc"); if (idref != null) { if (itemBuilders.containsKey(idref.trim())) { OPFItem.Builder toc = itemBuilders.get(idref.trim()); toc.ncx(); } else { report.message(MessageId.OPF_049, EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber()), idref); report.info(null, FeatureEnum.HAS_NCX, "false"); } } else { report.info(null, FeatureEnum.HAS_NCX, "false"); } } else if (name.equals("itemref")) { String idref = e.getAttribute("idref"); if (idref != null) { if (itemBuilders.containsKey(idref.trim())) { spineIDs.add(idref.trim()); OPFItem.Builder item = itemBuilders.get(idref.trim()); if (item != null) { item.inSpine(); String linear = e.getAttribute("linear"); if (linear != null && "no".equals(linear.trim())) { item.nonlinear(); } } } else { report.message(MessageId.OPF_049, EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber()), idref); } } } else if (name.equals("dc-metadata") || name.equals("x-metadata")) { if (!opf12PackageFile) { report.message(MessageId.OPF_049, EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber()), name); } } } else if (ns.equals("http://purl.org/dc/elements/1.1/")) { // in the DC metadata, when the element is parsed, if // it has a non-null and non-empty id attribute value that is the // same as the value of the unique-identifier attribute of the // package element, set uniqueIdentExists = true (to make sure that // the unique-identifier attribute references an existing // id attribute String name = e.getName(); if (name.equals("identifier")) { String idAttr = e.getAttribute("id"); if (idAttr != null && !idAttr.equals("") && idAttr.equals(uniqueIdent)) { uniqueIdentExists = true; } } else if (name.equals("creator")) { String role = e.getAttributeNS("http://www.idpf.org/2007/opf", "role"); if (role != null && !role.equals("") && !isValidRole(role)) { report.message(MessageId.OPF_052, EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber()), role); } } } } public String getIdentId() { return uniqueIdent; } public void endElement() { XMLElement e = parser.getCurrentElement(); String ns = e.getNamespace(); if (ns == null || ns.equals("") || ns.equals("http://openebook.org/namespaces/oeb-package/1.0/") || ns.equals("http://www.idpf.org/2007/opf")) { String name = e.getName(); // 2012-02-27T16:38:35Z // pre-paginated if ("meta".equals(name)) { String attr = e.getAttribute("property"); if ("dcterms:modified".equals(attr)) { String val = (String) e.getPrivateData(); report.info(null, FeatureEnum.MODIFIED_DATE, val); } } else if ("package".equals(name)) { buildItems(); if (pageMapId != null && !getItemById(pageMapId).isPresent()) { report.message(MessageId.OPF_063, pageMapReferenceLocation, pageMapId); } } } else if (e.getNamespace().equals("http://purl.org/dc/elements/1.1/")) { String name = e.getName(); if (name.equals("identifier")) { String idAttr = e.getAttribute("id"); if (idAttr != null && !idAttr.equals("") && idAttr.trim().equals(uniqueIdent)) { String idval = (String) e.getPrivateData(); // if (idval != null && ocf != null) // ocf.setUniqueIdentifier(idval); if (idval != null) { report.info(null, FeatureEnum.UNIQUE_IDENT, idval.trim()); } } } else if (name.equals("date")) { String dateval = (String) e.getPrivateData(); boolean valid = true; String detail = null; if (dateval == null || "".equals(dateval)) { valid = false; detail = "zero-length string"; } else { DateParser dateParser = new DateParser(); try { Date date = dateParser.parse(dateval.trim()); /* * mg: DateParser does not enforce four-digit years, which * http://www.w3.org/TR/NOTE-datetime seems to want */ String year = new SimpleDateFormat("yyyy").format(date); if (year.length() > 4) { throw new InvalidDateException(year); } report.info(null, FeatureEnum.DC_DATE, dateval); } catch (InvalidDateException d) { valid = false; detail = d.getMessage(); } } if (!valid) { if (context.version == EPUBVersion.VERSION_3) { report.message(MessageId.OPF_053, EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber()), (dateval == null ? "" : dateval), detail); } else { report.message(MessageId.OPF_054, EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber()), (dateval == null ? "" : dateval), detail); } } } else if (name.equals("title") || name.equals("language")) { // issue 138: issue a warning if dc:title and dc:language is // empty for 2.0 and 2.0.1 // note that an empty dc:identifier is checked in opf20.rng and // will // therefore be reported as an error, that may or may not be a // good idea. if ("language".equals(name)) { String value = (String) e.getPrivateData(); if (value != null) { report.info(null, FeatureEnum.DC_LANGUAGE, value.trim()); } } else if ("title".equals(name)) { String value = (String) e.getPrivateData(); if (value != null) { report.info(null, FeatureEnum.DC_TITLE, value.trim()); } } if (context.version == EPUBVersion.VERSION_2) { String value = (String) e.getPrivateData(); if (value == null || value.trim().length() < 1) { report.message(MessageId.OPF_055, EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber()), name); } } } else { Optional value = Optional.fromNullable(Strings.emptyToNull(Strings.nullToEmpty( (String) e.getPrivateData()).trim())); // Check for empty metadta (USAGE) in EPUB 2 // Empty metadata is forbidden and checked with schema in EPUB 3 if (context.version == EPUBVersion.VERSION_2 && !value.isPresent()) { report.message(MessageId.OPF_072, EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber()), "dc:" + name); } // Report metadata else if (value.isPresent()) { if (name.equals("creator")) { report.info(null, FeatureEnum.DC_CREATOR, value.get()); } else if (name.equals("contributor")) { report.info(null, FeatureEnum.DC_CONTRIBUTOR, value.get()); } else if (name.equals("publisher")) { report.info(null, FeatureEnum.DC_PUBLISHER, value.get()); } else if (name.equals("rights")) { report.info(null, FeatureEnum.DC_RIGHTS, value.get()); } else if (name.equals("subject")) { report.info(null, FeatureEnum.DC_SUBJECT, value.get()); } else if (name.equals("description")) { report.info(null, FeatureEnum.DC_DESCRIPTION, value.get()); } } } } } public void ignorableWhitespace(char[] chars, int arg1, int arg2) { } public void characters(char[] chars, int start, int len) { XMLElement e = parser.getCurrentElement(); String name = e.getName(); String ns = e.getNamespace(); boolean keepValue = ("http://www.idpf.org/2007/opf".equals(ns) && "meta".equals(name)) || "http://purl.org/dc/elements/1.1/".equals(ns); if (keepValue) { String val = (String) e.getPrivateData(); String text = new String(chars, start, len); if (val == null) { val = text; } else { val = val + text; } e.setPrivateData(val); } } public void processingInstruction(String arg0, String arg1) { } // Build the final items from the item builders private void buildItems() { Preconditions.checkState(items == null); items = OPFItems.build(itemBuilders.values(), spineIDs); for (OPFItem item : items.getItems()) { reportItem(item); } } /** * Report features or messages for a given item. * * @param item * the item to report. */ protected void reportItem(OPFItem item) { if (item.isInSpine()) { report.info(item.getPath(), FeatureEnum.IS_SPINEITEM, "true"); report.info(item.getPath(), FeatureEnum.IS_LINEAR, String.valueOf(item.isLinear())); } if (item.isNcx()) { report.info(item.getPath(), FeatureEnum.HAS_NCX, "true"); if (!item.getMimeType().equals("application/x-dtbncx+xml")) { report.message(MessageId.OPF_050, EPUBLocation.create(path, item.getLineNumber(), item.getColumnNumber())); } } } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/opf/GenericContentChecker.java0000755000175000017500000000364513017276730027031 0ustar eugeneeugene/* * Copyright (c) 2007 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.opf; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.messages.MessageId; import com.adobe.epubcheck.ocf.OCFPackage; public class GenericContentChecker implements ContentChecker { private final OCFPackage ocf; private final Report report; private final String path; GenericContentChecker(OCFPackage ocf, Report report, String path) { this.ocf = ocf; this.report = report; this.path = path; } public void runChecks() { if (!ocf.hasEntry(path)) { report.message(MessageId.RSC_001, EPUBLocation.create(this.ocf.getName()), path); } else if (!ocf.canDecrypt(path)) { report.message(MessageId.RSC_004, EPUBLocation.create(this.ocf.getName()), path); } } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/opf/GenericContentCheckerFactory.java0000755000175000017500000000310613017276730030351 0ustar eugeneeugene/* * Copyright (c) 2007 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.opf; public class GenericContentCheckerFactory implements ContentCheckerFactory { static private final GenericContentCheckerFactory instance = new GenericContentCheckerFactory(); public ContentChecker newInstance(ValidationContext context) { return new GenericContentChecker(context.ocf.get(), context.report, context.path); } static public GenericContentCheckerFactory getInstance() { return instance; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/opf/MetadataSet.java0000644000175000017500000004242313017276730025023 0ustar eugeneeugenepackage com.adobe.epubcheck.opf; import java.util.HashSet; import java.util.LinkedList; import java.util.Map; import java.util.Set; import com.adobe.epubcheck.vocab.Property; import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.base.Predicate; import com.google.common.base.Strings; import com.google.common.base.Supplier; import com.google.common.base.Suppliers; import com.google.common.collect.HashMultimap; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSetMultimap; import com.google.common.collect.Iterables; import com.google.common.collect.LinkedListMultimap; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multimap; import com.google.common.collect.SetMultimap; /** * Represents a set of metadata as declared in the metadata element * in an EPUB Publication document (OPF). *

* The graph of refines is resolved when building the metadata set. *

* * @author Romain Deltour * */ public final class MetadataSet { // multimap of all metadata expressions, by property private final SetMultimap all; // multimap of all metadata primary expressions, by property private final SetMultimap primary; // multimap of metadata expressions refining a given ID private final SetMultimap refiners; // map of refining metadata to refined metadata private final Map refines; // memoized view of the set of all metadata expressions private final Supplier> allSet = Suppliers.memoize(new Supplier>() { @Override public Set get() { return ImmutableSet.copyOf(all.values()); } }); // memoized view of the set of all metadata primary expressions private final Supplier> primarySet = Suppliers .memoize(new Supplier>() { @Override public Set get() { return ImmutableSet.copyOf(primary.values()); } }); private MetadataSet(Multimap all, Multimap primary, Map refines, Multimap refiners) { this.all = ImmutableSetMultimap.copyOf(all); this.primary = ImmutableSetMultimap.copyOf(primary); this.refines = ImmutableMap.copyOf(refines); this.refiners = ImmutableSetMultimap.copyOf(refiners); } /** * Returns a set of all primary metadata expressions. * * @return an immutable set (possibly empty) of all primary metadata * expressions. */ public Set getPrimary() { return primarySet.get(); } /** * Returns a set of all metadata expressions (primary+subexpressions). * * @return an immutable set (possibly empty) of all metadata expressions. */ public Set getAll() { return allSet.get(); } /** * Returns true if this metadata set contains a primary * expression for the given property * * @param property * a property from a metadata vocabulary * @return true if this metadata set contains a primary * expression for the given property */ public boolean containsPrimary(Property property) { return primary.containsKey(property); } /** * Returns true if this metadata set contains a primary * expression for the given property and the given value * * @param property * a property from a metadata vocabulary * @param value * the value to search * @return true if this metadata set contains a primary * expression for the given property and value */ public boolean containsPrimary(Property property, String value) { for (Metadata meta : primary.get(property)) { if (meta.getValue().equals(value)) { return true; } } return false; } /** * Returns true if this metadata set contains an expression * (primary or subexpression) for the given property * * @param property * a property from a metadata vocabulary * @return true if this metadata set contains an expression for * the given property */ public boolean containsAny(Property property) { return all.containsKey(property); } /** * Returns the set of metadata primary expressions for the given property. * * @param property * a property from a metadata vocabulary * @return the set of metadata primary expressions for the given property, or * an empty set if none exist. */ public Set getPrimary(Property property) { return primary.get(property); } /** * Returns the set of all metadata expressions (primary and subexpressions) * for the given property. * * @param property * a property from a metadata vocabulary * @return the set of all metadata expressions for the given property, or an * empty set if none exist. */ public Set getAny(Property property) { return all.get(property); } /** * Returns an optional metadata expression refined by the given metadata * expression. * * @param meta * a metadata expression * @return {@link Optional#absent()} if the given metadata expression does not * refine another metadata expression or a * {@link Optional#of(Metadata)} containing the refined metadata * expression */ public Optional getRefinedBy(Metadata meta) { return Optional.fromNullable(refines.get(meta)); } /** * Returns the set of all metadata subexpressions refining the metadata or * resource identified by the given ID. * * @param id * a string ID * @return the set of all metadata subexpressions refining the given ID, or an * empty set if none exist. */ public Set getRefining(String id) { return refiners.get(id); } /** * Search all refining expressions of the given metadata expressions, and * return the first one that matches the given property and value (if * present). *

* If value is {@link Optional#absent()} *

* , only the property is used in the lookup. * * @param metas * A set of metadata expressions to search * @param property * The property of the searched expression * @param value * The value of the searched expression, can be absent if the value * is not relevant in the search * @return an {@link Optional} containing an expression refining one of the * expressions in metas and matching the given property * and value, or {@link Optional#absent()} if none is found. */ public static Optional tryFindInRefines(Set metas, final Property property, final Optional value) { Preconditions.checkNotNull(metas); Preconditions.checkNotNull(property); Preconditions.checkNotNull(value); return Iterables.tryFind(metas, new Predicate() { @Override public boolean apply(Metadata meta) { return tryFind(meta.getRefiners(), property, value).isPresent(); } }); } /** * Search all the given expressions and return the first one that matches the * given property and value (if present). *

* If value is {@link Optional#absent()} *

* , only the property is used in the lookup. * * @param metas * A set of metadata expressions to search * @param property * The property of the searched expression * @param value * The value of the searched expression, can be absent if the value * is not relevant in the search * @return an {@link Optional} containing an expression in the * metas set matching the given property and value, or * {@link Optional#absent()} if none is found. */ public static Optional tryFind(Set metas, final Property property, final Optional value) { Preconditions.checkNotNull(metas); Preconditions.checkNotNull(property); Preconditions.checkNotNull(value); return Iterables.tryFind(metas, new Predicate() { @Override public boolean apply(Metadata meta) { return property.equals(meta.getProperty()) && (!value.isPresent() || value.get().equals(meta.getValue())); } }); } /** * Represents a metadata expression. * */ public static final class Metadata { private final Optional id; private final Property property; private final String value; private final Optional refines; private final Set refiners; private Metadata(String id, Property property, String value, String refines, Set refiners) { Preconditions.checkNotNull(property); this.id = Optional.fromNullable(id); this.property = property; this.value = value == null ? "" : value.trim(); this.refines = refines == null ? Optional. absent() : refines.startsWith("#") ? Optional.fromNullable(Strings.emptyToNull(refines .substring(1))) : Optional.of(refines); this.refiners = refiners == null ? ImmutableSet. of() : refiners; } /** * The ID of the element holding the expression. * * @return the ID of the element holding the expression (possibly absent). */ public Optional getId() { return id; } /** * The property representing the statement of the expression. * * @return the property representing the statement of the expression. */ public Property getProperty() { return property; } /** * The value of the assertion of the expression. * * @return the value of the assertion of the expression. */ public String getValue() { return value; } /** * The ID of the resource or expression refined by this expression. * * @return the ID of the resource or expression refined by this expression * (possibly absent). */ public Optional getRefines() { return refines; } /** * The set of metadata expressions refining this metadata expression. * * @return the set (possibly empty) of metadata expressions refining this * metadata expression. */ public Set getRefiners() { return refiners; } @Override public String toString() { return "Metadata [id=" + id + ", property=" + property + ", value=" + value + ", refines=" + refines + "]"; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((id == null) ? 0 : id.hashCode()); result = prime * result + ((property == null) ? 0 : property.hashCode()); result = prime * result + ((refines == null) ? 0 : refines.hashCode()); result = prime * result + ((value == null) ? 0 : value.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Metadata other = (Metadata) obj; if (id == null) { if (other.id != null) return false; } else if (!id.equals(other.id)) return false; if (property == null) { if (other.property != null) return false; } else if (!property.equals(other.property)) return false; if (refines == null) { if (other.refines != null) return false; } else if (!refines.equals(other.refines)) return false; if (value == null) { if (other.value != null) return false; } else if (!value.equals(other.value)) return false; return true; } } /** * Creates a new builder. Calling this method is identical to calling the * empty {@link Builder} constructor. * * @return a newly created builder. */ public static Builder builder() { return new Builder(); } /** * A builder for sets of metadata expressions. * */ public static final class Builder { // Primary metadata expressions, mapped by properties private final Multimap primary = HashMultimap.create(); // All metadata expressions (primary+subexpressions), mapped by properties private final Multimap all = HashMultimap.create(); // A list of temporary incomplete metadata objects to build private final LinkedList tempMetas = Lists.newLinkedList(); // A map of (possibly temporary) metadata objects refining the given IDs private final Multimap refinersMap = LinkedListMultimap.create(); // A map of refining-to-refined metadata objects private final Map refines = Maps.newHashMap(); // A map of the status of metadata being visited by DFS private final Map visits = Maps.newHashMap(); // holds the status of visited metadata in the DFS sort private static enum Visit { UNVISITED, VISITED, VISITING; public static Visit safe(Visit visit) { return visit != null ? visit : UNVISITED; } } /** * Builds the set. Must be called after all metadata expressions have been * added. * * @return an immutable metadata set * @throws IllegalStateException * if a cycle is found in the graph of refining expressions */ public MetadataSet build() { // DFS recursive build of metadata and their refining metadata // Note: metadata consistency (e.g. whether @refines point to valid IDs) // has already been checked in schemas for (Metadata metadata : tempMetas) { build(metadata); } return new MetadataSet(all, primary, refines, refinersMap); } // builds a metadata and all its refining metadata recursively private Metadata build(Metadata meta) { Preconditions.checkArgument(meta.getId().isPresent()); switch (Visit.safe(visits.get(meta))) { case VISITED: // has already been built return meta; case VISITING: throw new IllegalStateException("Not a DAG"); default: break; } visits.put(meta, Visit.VISITING); Set refiners = new HashSet(); // recursively build the current metadata's refining metadata for (Metadata refiner : refinersMap.get(meta.getId().get())) { // add the refining metadata to the "refiners" set // - if the refining metadata has no ID, it's final already // - otherwise, build it recursively refiners.add((refiner.getId().isPresent()) ? build(refiner) : refiner); } // build the finalized metadata and put it in the final maps Metadata result = new Metadata(meta.getId().get(), meta.getProperty(), meta.getValue(), meta .getRefines().orNull(), refiners); for (Metadata refiner : refiners) { refines.put(refiner, result); } if (result.getRefines().isPresent()) { // re-add built metadata to the refiners map refinersMap.remove(result.getRefines().get(), meta); refinersMap.put(result.getRefines().get(), result); } else { primary.put(result.getProperty(), result); } all.put(result.getProperty(), result); visits.put(meta, Visit.VISITED); return result; } /** * Adds a metadata expression to the set being built. * * @param id * the ID of the element holding the expression, can be null. * @param property * the property representing the statement of the expression (must * not be null) * @param value * the value representing the assertion of the expression (can, but * should not, be null) * @param refines * the ID of the expression or resource refined by this expression. * If the given string starts with the character '#' (relative * fragment URI), it is stripped to get the ID. Can be null * @return this builder */ public Builder meta(String id, Property property, String value, String refines) { // create a (possibly temporary) metadata from the given fields Metadata meta = new Metadata(id, property, value, refines, null); if (id == null) { // the metadata cannot be refined, put it in the final maps if (!meta.refines.isPresent()) { primary.put(property, meta); } all.put(property, meta); } else { // the metadata may be refined, store it to the temporary list tempMetas.add(meta); } if (meta.refines.isPresent()) { // if the metadata refines something, store it to the map of "refiners" refinersMap.put(meta.refines.get(), meta); } return this; } } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/opf/OPFChecker30.java0000644000175000017500000004076213017276730024707 0ustar eugeneeugene/* * Copyright (c) 2007 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.opf; import java.net.URI; import java.net.URISyntaxException; import java.util.HashMap; import java.util.Iterator; import java.util.Set; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.api.EPUBProfile; import com.adobe.epubcheck.api.FeatureReport.Feature; import com.adobe.epubcheck.bitmap.BitmapCheckerFactory; import com.adobe.epubcheck.css.CSSCheckerFactory; import com.adobe.epubcheck.dict.SearchKeyMapCheckerFactory; import com.adobe.epubcheck.dtbook.DTBookCheckerFactory; import com.adobe.epubcheck.messages.MessageId; import com.adobe.epubcheck.opf.MetadataSet.Metadata; import com.adobe.epubcheck.opf.ResourceCollection.Roles; import com.adobe.epubcheck.ops.OPSCheckerFactory; import com.adobe.epubcheck.overlay.OverlayCheckerFactory; import com.adobe.epubcheck.util.EPUBVersion; import com.adobe.epubcheck.util.FeatureEnum; import com.adobe.epubcheck.vocab.DCMESVocab; import com.adobe.epubcheck.vocab.PackageVocabs; import com.google.common.base.Optional; import com.google.common.base.Predicate; import com.google.common.collect.Iterables; import com.google.common.io.Files; public class OPFChecker30 extends OPFChecker implements DocumentValidator { public OPFChecker30(ValidationContext context) { super(context); } @Override protected void initContentCheckerFactoryMap() { HashMap map = new HashMap(); map.put("application/vnd.epub.search-key-map+xml", SearchKeyMapCheckerFactory.getInstance()); map.put("application/smil+xml", OverlayCheckerFactory.getInstance()); map.put("application/xhtml+xml", OPSCheckerFactory.getInstance()); map.put("application/x-dtbook+xml", DTBookCheckerFactory.getInstance()); map.put("image/jpeg", BitmapCheckerFactory.getInstance()); map.put("image/gif", BitmapCheckerFactory.getInstance()); map.put("image/png", BitmapCheckerFactory.getInstance()); map.put("image/svg+xml", OPSCheckerFactory.getInstance()); map.put("text/css", CSSCheckerFactory.getInstance()); contentCheckerFactoryMap.clear(); contentCheckerFactoryMap.putAll(map); } @Override public void initHandler() { opfHandler = new OPFHandler30(context, opfParser); } @Override public void runChecks() { super.runChecks(); checkCollectionsContent(); checkPagination(); checkSemantics(); checkNav(); checkSpecifics(); } @Override public boolean validate() { int fatalErrorsSoFar = report.getFatalErrorCount(); int errorsSoFar = report.getErrorCount(); int warningsSoFar = report.getWarningCount(); super.validate(); checkLinkedResources(); checkCollections(); return fatalErrorsSoFar == report.getFatalErrorCount() && errorsSoFar == report.getErrorCount() && warningsSoFar == report.getWarningCount(); } @Override protected void checkItem(OPFItem item, OPFHandler opfHandler) { String mimeType = item.getMimeType(); if (mimeType == null || mimeType.equals("")) { // report.error(path, item.getLineNumber(), item.getColumnNumber(), // "empty media-type attribute"); return; } if (!mimeType.matches("[a-zA-Z0-9!#$&+-^_]+/[a-zA-Z0-9!#$&+-^_]+")) { // report.error(path, item.getLineNumber(), item.getColumnNumber(), // "invalid content for media-type attribute"); return; } if ("application/xhtml+xml".equals(mimeType) && !"xhtml".equals(Files.getFileExtension(item.getPath()))) { report.message(MessageId.HTM_014a, EPUBLocation.create(path, item.getLineNumber(), item.getColumnNumber()), item.getPath()); } // Note: item fallback existence is checked in schematron, i.e.: // opfHandler.getItemById(item.getFallback().get()).isPresent() == true } @Override protected void checkSpineItem(OPFItem item, OPFHandler opfHandler) { String mimeType = item.getMimeType(); if (item.getProperties() .contains(PackageVocabs.ITEM_VOCAB.get(PackageVocabs.ITEM_PROPERTIES.DATA_NAV))) { report.message(MessageId.OPF_077, EPUBLocation.create(path, item.getLineNumber(), item.getColumnNumber())); } if (isBlessedItemType(mimeType, version)) { return; } if (!item.getFallback().isPresent()) { report.message(MessageId.OPF_043, EPUBLocation.create(path, item.getLineNumber(), item.getColumnNumber()), mimeType); } else if (!new FallbackChecker().checkItemFallbacks(item, opfHandler, false)) { report.message(MessageId.OPF_044, EPUBLocation.create(path, item.getLineNumber(), item.getColumnNumber()), mimeType); } } @Override protected void checkBindings() { Set mimeTypes = context.xrefChecker.get().getBindingsMimeTypes(); Iterator it = mimeTypes.iterator(); String mimeType; while (it.hasNext()) { mimeType = it.next(); String handlerId = context.xrefChecker.get().getBindingHandlerId(mimeType); OPFItem handler = opfHandler.getItemById(handlerId).get(); if (!handler.isScripted()) { report.message(MessageId.OPF_046, EPUBLocation.create(handler.getPath(), handler.getLineNumber(), handler.getColumnNumber())); } } } // protected boolean checkItemFallbacks(OPFItem item, OPFHandler opfHandler) { // String fallback = item.getFallback(); // if (fallback != null) { // OPFItem fallbackItem = opfHandler.getItemById(fallback); // if (fallbackItem != null) { // String mimeType = fallbackItem.getMimeType(); // if (mimeType != null) { // if (OPFChecker.isBlessedItemType(mimeType, version)) // return true; // if (checkItemFallbacks(fallbackItem, opfHandler)) // return true; // } // } // } // return false; // } private void checkCollections() { for (ResourceCollection collection : ((OPFHandler30) opfHandler).getCollections().asList()) { if (collection.hasRole(ResourceCollection.Roles.DICTIONARY)) { checkDictCollection(collection); } if (collection.hasRole(ResourceCollection.Roles.INDEX)) { checkIndexCollection(collection); } if (collection.hasRole(ResourceCollection.Roles.PREVIEW)) { checkPreviewCollection(collection); } } } private void checkCollectionsContent() { for (ResourceCollection collection : ((OPFHandler30) opfHandler).getCollections().asList()) { if (collection.hasRole(ResourceCollection.Roles.DICTIONARY)) { checkDictCollectionContent(collection); } } } private void checkDictCollection(ResourceCollection collection) { if (collection.hasRole(Roles.DICTIONARY)) { boolean skmFound = false; for (LinkedResource resource : collection.getResources().asList()) { Optional item = opfHandler.getItemByPath(resource.getPath()); if (!item.isPresent()) { report.message(MessageId.OPF_081, EPUBLocation.create(path), resource.getPath()); } else if ("application/vnd.epub.search-key-map+xml".equals(item.get().getMimeType())) { if (skmFound) { // More than one Search Key Map report.message(MessageId.OPF_082, EPUBLocation.create(path)); } skmFound = true; } else if (!"application/xhtml+xml".equals(item.get().getMimeType())) { report.message(MessageId.OPF_084, EPUBLocation.create(path), resource.getPath()); } } if (!skmFound) { // No Search Key Map report.message(MessageId.OPF_083, EPUBLocation.create(path)); } } } private void checkDictCollectionContent(ResourceCollection collection) { if (collection.hasRole(Roles.DICTIONARY)) { boolean dictFound = false; for (LinkedResource resource : collection.getResources().asList()) { final Optional item = opfHandler.getItemByPath(resource.getPath()); if (!dictFound && item.isPresent() && "application/xhtml+xml".equals(item.get().getMimeType())) { // Search if this resource was reported as DICTIONARY content dictFound = Iterables.tryFind(context.featureReport.getFeature(FeatureEnum.DICTIONARY), new Predicate() { @Override public boolean apply(Feature dict) { return item.get().getPath().equals(dict.getLocation().get().getPath()); } }).isPresent(); } } if (!dictFound) { // No Dictionary content report.message(MessageId.OPF_078, EPUBLocation.create(path)); } } } private void checkIndexCollection(ResourceCollection collection) { if (collection.hasRole(Roles.INDEX) || collection.hasRole(Roles.INDEX_GROUP)) { for (LinkedResource resource : collection.getResources().asList()) { Optional item = opfHandler.getItemByPath(resource.getPath()); if (!item.isPresent() || !"application/xhtml+xml".equals(item.get().getMimeType())) { report.message(MessageId.OPF_071, EPUBLocation.create(path)); } } for (ResourceCollection childCollection : collection.getCollections().asList()) { checkIndexCollection(childCollection); } } } private void checkPreviewCollection(ResourceCollection collection) { if (collection.hasRole(Roles.PREVIEW)) { for (LinkedResource resource : collection.getResources().asList()) { Optional item = opfHandler.getItemByPath(resource.getPath()); if (!item.isPresent() || !("application/xhtml+xml".equals(item.get().getMimeType()) || "image/svg+xml".equals(item.get().getMimeType()))) { report.message(MessageId.OPF_075, EPUBLocation.create(path)); } else { try { URI uri = new URI(resource.getURI()); if (Optional.fromNullable(uri.getFragment()).or("").startsWith("epubcfi(")) { report.message(MessageId.OPF_076, EPUBLocation.create(path)); } } catch (URISyntaxException e) { report.message(MessageId.RSC_020, EPUBLocation.create(path)); } } } } } private void checkLinkedResources() { LinkedResources links = ((OPFHandler30) opfHandler).getLinkedResources(); for (LinkedResource link : links.asList()) { if (opfHandler.getItemByPath(link.getPath()).isPresent()) { report.message(MessageId.OPF_067, EPUBLocation.create(path), link.getPath()); } } } private void checkPagination() { if (context.profile == EPUBProfile.EDUPUB || context.pubTypes.contains(OPFData.DC_TYPE_EDUPUB)) { if (context.featureReport.hasFeature(FeatureEnum.PAGE_BREAK)) { // Check there is a page list if (!context.featureReport.hasFeature(FeatureEnum.PAGE_LIST)) { report.message(MessageId.NAV_003, EPUBLocation.create(path)); } // Search a "dc:source" metadata expression Set dcSourceMetas = ((OPFHandler30) opfHandler).getMetadata() .getPrimary(DCMESVocab.VOCAB.get(DCMESVocab.PROPERTIES.SOURCE)); if (dcSourceMetas.isEmpty()) { report.message(MessageId.OPF_066, EPUBLocation.create(path)); } else { // Search a "source-of : pagination" expression refining a "dc:source" if (!MetadataSet.tryFindInRefines(dcSourceMetas, PackageVocabs.META_VOCAB.get(PackageVocabs.META_PROPERTIES.SOURCE_OF), Optional.of("pagination")).isPresent()) { report.message(MessageId.OPF_066, EPUBLocation.create(path)); } } } } } private void checkSemantics() { if (context.profile == EPUBProfile.EDUPUB || context.pubTypes.contains(OPFData.DC_TYPE_EDUPUB)) { if (context.featureReport.hasFeature(FeatureEnum.HAS_MICRODATA) && !context.featureReport.hasFeature(FeatureEnum.HAS_RDFA)) { report.message(MessageId.HTM_051, context.featureReport .getFeature(FeatureEnum.HAS_MICRODATA).iterator().next().getLocation().get()); } } } private void checkNav() { if (context.profile == EPUBProfile.EDUPUB || context.pubTypes.contains(OPFData.DC_TYPE_EDUPUB)) { Set sections = context.featureReport.getFeature(FeatureEnum.SECTIONS); Set tocLinks = context.featureReport.getFeature(FeatureEnum.TOC_LINKS); if (sections.size() != tocLinks.size()) { report.message(MessageId.NAV_004, tocLinks.isEmpty() ? EPUBLocation.create(path) : tocLinks.iterator().next().getLocation().get()); } if (context.featureReport.hasFeature(FeatureEnum.AUDIO) && !context.featureReport.hasFeature(FeatureEnum.LOA)) { report.message(MessageId.NAV_005, tocLinks.isEmpty() ? EPUBLocation.create(path) : tocLinks.iterator().next().getLocation().get()); } if (context.featureReport.hasFeature(FeatureEnum.FIGURE) && !context.featureReport.hasFeature(FeatureEnum.LOI)) { report.message(MessageId.NAV_006, tocLinks.isEmpty() ? EPUBLocation.create(path) : tocLinks.iterator().next().getLocation().get()); } if (context.featureReport.hasFeature(FeatureEnum.TABLE) && !context.featureReport.hasFeature(FeatureEnum.LOT)) { report.message(MessageId.NAV_007, tocLinks.isEmpty() ? EPUBLocation.create(path) : tocLinks.iterator().next().getLocation().get()); } if (context.featureReport.hasFeature(FeatureEnum.VIDEO) && !context.featureReport.hasFeature(FeatureEnum.LOV)) { report.message(MessageId.NAV_008, tocLinks.isEmpty() ? EPUBLocation.create(path) : tocLinks.iterator().next().getLocation().get()); } } } private void checkSpecifics() { if (context.featureReport.hasFeature(FeatureEnum.DICTIONARY) && !context.pubTypes.contains(OPFData.DC_TYPE_DICT)) { report.message(MessageId.OPF_079, context.featureReport.getFeature(FeatureEnum.DICTIONARY) .iterator().next().getLocation().get()); } if (context.profile == EPUBProfile.DICT || context.pubTypes.contains(OPFData.DC_TYPE_DICT)) { if (!context.featureReport.hasFeature(FeatureEnum.DICTIONARY)) { report.message(MessageId.OPF_078, EPUBLocation.create(path)); } } } public static boolean isBlessedAudioType(String type) { return type.equals("audio/mpeg") || type.equals("audio/mp4"); } public static boolean isBlessedVideoType(String type) { return type.startsWith("video/h264") || type.startsWith("video/webm") || type.startsWith("video/mp4"); } public static boolean isBlessedFontType(String type) { return type.equals("application/vnd.ms-opentype") || type.equals("application/font-woff") || type.equals("image/svg+xml"); } public static boolean isCoreMediaType(String type) { return isBlessedAudioType(type) || isBlessedVideoType(type) || isBlessedFontType(type) || isBlessedItemType(type, EPUBVersion.VERSION_3) || isBlessedImageType(type) || type.equals("text/javascript") || type.equals("application/pls+xml") || type.equals("application/smil+xml") || type.equals("image/svg+xml"); } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/opf/XRefChecker.java0000755000175000017500000003137013017276730024762 0ustar eugeneeugene/* * Copyright (c) 2007 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.opf; import java.util.Enumeration; import java.util.HashSet; import java.util.Hashtable; import java.util.Set; import java.util.Vector; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.messages.MessageId; import com.adobe.epubcheck.ocf.OCFPackage; import com.adobe.epubcheck.util.EPUBVersion; import com.adobe.epubcheck.util.FeatureEnum; import com.adobe.epubcheck.vocab.PackageVocabs; import com.google.common.base.Optional; import com.google.common.base.Preconditions; public class XRefChecker { public static enum Type { GENERIC, HYPERLINK, LINK, IMAGE, OBJECT, STYLESHEET, AUDIO, VIDEO, SVG_PAINT, SVG_CLIP_PATH, SVG_SYMBOL, REGION_BASED_NAV, SEARCH_KEY; } private static class Reference { public final String resource; public final int lineNumber; public final int columnNumber; public final String refResource; public final String fragment; public final Type type; public Reference(String srcResource, int srcLineNumber, int srcColumnNumber, String refResource, String fragment, Type type) { this.fragment = fragment; this.lineNumber = srcLineNumber; this.columnNumber = srcColumnNumber; this.refResource = refResource; this.resource = srcResource; this.type = type; } } private static class Anchor { public final String id; public final int lineNumber; public final int columnNumber; public final Type type; public Anchor(String id, int lineNumber, int columnNumber, Type type) { this.id = id; this.lineNumber = lineNumber; this.columnNumber = columnNumber; this.type = type; } } private static class Resource { public final OPFItem item; public final Hashtable anchors; public final boolean hasValidItemFallback; public final boolean hasValidImageFallback; Resource(OPFItem item, boolean hasValidItemFallback, boolean hasValidImageFallback) { this.item = item; this.hasValidItemFallback = hasValidItemFallback; this.hasValidImageFallback = hasValidImageFallback; this.anchors = new Hashtable(); } } private final Hashtable resources = new Hashtable(); private final HashSet undeclared = new HashSet(); private final Vector references = new Vector(); private final Hashtable bindings = new Hashtable(); private final Report report; private final OCFPackage ocf; private final EPUBVersion version; public XRefChecker(OCFPackage ocf, Report report, EPUBVersion version) { this.ocf = ocf; this.report = report; this.version = version; } public String getMimeType(String path) { return resources.get(path) != null ? resources.get(path).item.getMimeType() : null; } /** * Returns an {@link Optional} containing a boolean indicating whether the * resource at the given path has a valid item fallback, or * {@link Optional#absent()} if no resource has been registered for the given * path. */ public Optional hasValidFallback(String path) { return resources.get(path) != null ? Optional.of(resources.get(path).hasValidItemFallback) : Optional. absent(); } public Set getBindingsMimeTypes() { return bindings.keySet(); } public String getBindingHandlerId(String mimeType) { return bindings.get(mimeType); } public void registerBinding(String mimeType, String handlerId) { bindings.put(mimeType, handlerId); } public void registerResource(OPFItem item, boolean hasValidItemFallback, boolean hasValidImageFallback) { // Note: Duplicate manifest items are already checked in OPFChecker. if (!resources.contains(item.getPath())) { resources.put(item.getPath(), new Resource(item, hasValidItemFallback, hasValidImageFallback)); } } public void registerAnchor(String path, int lineNumber, int columnNumber, String id, Type type) { Resource res = Preconditions.checkNotNull(resources.get(path)); // Note: duplicate IDs are checked in schematron if (!res.anchors.contains(id)) { res.anchors.put(id, new Anchor(id, lineNumber, columnNumber, type)); } } public void registerReference(String srcResource, int srcLineNumber, int srcColumnNumber, String ref, Type type) { if (ref.startsWith("data:")) { return; } // see http://code.google.com/p/epubcheck/issues/detail?id=190 // see http://code.google.com/p/epubcheck/issues/detail?id=261 int query = ref.indexOf('?'); if (query >= 0 && !ref.matches("^[^:/?#]+://.*")) { ref = ref.substring(0, query).trim(); } int hash = ref.indexOf("#"); String refResource; String refFragment; if (hash >= 0) { refResource = ref.substring(0, hash); refFragment = ref.substring(hash + 1); } else { refResource = ref; refFragment = null; } report.info(srcResource, FeatureEnum.RESOURCE, refResource); references.add( new Reference(srcResource, srcLineNumber, srcColumnNumber, refResource, refFragment, type)); } public void checkReferences() { Enumeration refs = references.elements(); while (refs.hasMoreElements()) { Reference ref = refs.nextElement(); checkReference(ref); } } private void checkReference(Reference ref) { Resource res = resources.get(ref.refResource); Resource host = resources.get(ref.resource); // Check undeclared resources if (res == null) { if (version == EPUBVersion.VERSION_3 && ref.type == Type.LINK) { if (ref.refResource.matches("^[^:/?#]+://.*") || ocf.hasEntry(ref.refResource)) { return; } else { report.message(MessageId.RSC_007w, EPUBLocation.create(ref.resource, ref.lineNumber, ref.columnNumber, ref.refResource)); } } else if (ref.refResource.matches("^[^:/?#]+://.*") && !(version == EPUBVersion.VERSION_3 && (ref.type == Type.AUDIO || ref.type == Type.VIDEO))) { report.message(MessageId.RSC_006, EPUBLocation.create(ref.resource, ref.lineNumber, ref.columnNumber, ref.refResource)); } else if (!ocf.hasEntry(ref.refResource) && !ref.refResource.matches("^[^:/?#]+://.*")) { report.message(MessageId.RSC_007, EPUBLocation.create(ref.resource, ref.lineNumber, ref.columnNumber, ref.refResource)); } else if (!undeclared.contains(ref.refResource)) { undeclared.add(ref.refResource); report.message(MessageId.RSC_008, EPUBLocation.create(ref.resource, ref.lineNumber, ref.columnNumber, ref.refResource)); } return; } // Type-specific checks switch (ref.type) { case HYPERLINK: // if mimeType is null, we should have reported an error already if (!OPFChecker.isBlessedItemType(res.item.getMimeType(), version) && !OPFChecker.isDeprecatedBlessedItemType(res.item.getMimeType()) && !res.hasValidItemFallback) { report.message(MessageId.RSC_010, EPUBLocation.create(ref.resource, ref.lineNumber, ref.columnNumber, ref.refResource + ((ref.fragment != null) ? '#' + ref.fragment : ""))); } if (/* !res.mimeType.equals("font/opentype") && */!res.item.isInSpine()) { report.message(MessageId.RSC_011, EPUBLocation.create(ref.resource, ref.lineNumber, ref.columnNumber, ref.refResource + ((ref.fragment != null) ? '#' + ref.fragment : ""))); } break; case IMAGE: if (ref.fragment != null) { report.message(MessageId.RSC_009, EPUBLocation.create(ref.resource, ref.lineNumber, ref.columnNumber, ref.refResource + "#" + ref.fragment)); return; } // if mimeType is null, we should have reported an error already if (!OPFChecker.isBlessedImageType(res.item.getMimeType()) && !res.hasValidImageFallback) { report.message(MessageId.MED_003, EPUBLocation.create(ref.resource, ref.lineNumber, ref.columnNumber), res.item.getMimeType()); } break; case REGION_BASED_NAV: if (!res.item.isFixedLayout()) { report.message(MessageId.NAV_009, EPUBLocation.create(ref.resource, ref.lineNumber, ref.columnNumber)); } return; case SEARCH_KEY: // TODO update when we support EPUB CFI if ((ref.fragment == null || !ref.fragment.startsWith("epubcfi(")) && !res.item.isInSpine()) { report.message(MessageId.RSC_021, EPUBLocation.create(ref.resource, ref.lineNumber, ref.columnNumber), ref.refResource); } break; case STYLESHEET: if (ref.fragment != null) { report.message(MessageId.RSC_013, EPUBLocation.create(ref.resource, ref.lineNumber, ref.columnNumber, ref.refResource + "#" + ref.fragment)); return; } // if mimeType is null, we should have reported an error already // Implementations are allowed to process any stylesheet // language they desire; so this is an // error only if no fallback is available. // Since the presence of a 'text/css' stylesheet link can be considered // a valid "built-in" fallback for a non-standard stylesheet (e.g. // XPGT), the fallback chain test is performed in OPSHandler instead. // See also: // https://github.com/IDPF/epubcheck/issues/244 // https://github.com/IDPF/epubcheck/issues/271 // https://github.com/IDPF/epubcheck/issues/541 break; case SVG_CLIP_PATH: case SVG_PAINT: case SVG_SYMBOL: if (ref.fragment == null) { report.message(MessageId.RSC_015, EPUBLocation.create(ref.resource, ref.lineNumber, ref.columnNumber, ref.refResource)); return; } break; default: break; } // Fragment integrity checks if (ref.fragment != null) { // EPUB CFI if (ref.fragment.startsWith("epubcfi(")) { // FIXME epubcfi currently not supported (see issue 150). return; } // Media fragments in Data Navigation Documents else if (ref.fragment.contains("=") && host != null && host.item.getProperties() .contains(PackageVocabs.ITEM_VOCAB.get(PackageVocabs.ITEM_PROPERTIES.DATA_NAV))) { // Ignore, return; } // Fragment Identifier (by default) else { Anchor anchor = res.anchors.get(ref.fragment); if (anchor == null) { report.message(MessageId.RSC_012, EPUBLocation.create(ref.resource, ref.lineNumber, ref.columnNumber, ref.refResource + "#" + ref.fragment)); return; } switch (ref.type) { case SVG_PAINT: case SVG_CLIP_PATH: if (anchor.type != ref.type) { report.message(MessageId.RSC_014, EPUBLocation.create(ref.resource, ref.lineNumber, ref.columnNumber, ref.refResource + "#" + ref.fragment)); } break; case SVG_SYMBOL: case HYPERLINK: if (anchor.type != ref.type && anchor.type != Type.GENERIC) { report.message(MessageId.RSC_014, EPUBLocation.create(ref.resource, ref.lineNumber, ref.columnNumber, ref.refResource + "#" + ref.fragment)); } break; default: break; } } } } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/opf/ResourceCollections.java0000644000175000017500000000631013017276730026610 0ustar eugeneeugenepackage com.adobe.epubcheck.opf; import java.util.LinkedHashSet; import java.util.List; import com.adobe.epubcheck.opf.ResourceCollection.Roles; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableListMultimap; import com.google.common.collect.ListMultimap; import com.google.common.collect.Sets; /** * Represents a set of collections (as defined by collection * elements in a Package Document), with predictable iteration order. */ public final class ResourceCollections { private final List collections; private final ListMultimap collectionsByRole; private ResourceCollections(Iterable collections) { ImmutableList.Builder listBuilder = ImmutableList.builder(); ImmutableListMultimap.Builder byRoleBuilder = ImmutableListMultimap .builder(); for (ResourceCollection collection : collections) { listBuilder.add(collection); for (String role : collection.getRoles()) { byRoleBuilder.put(role, collection); } } this.collections = listBuilder.build(); this.collectionsByRole = byRoleBuilder.build(); } /** * Returns the list of all collections in this set. */ public List asList() { return collections; } /** * Returns the list of collections in this set with the given role. */ public List getByRole(String role) { return collectionsByRole.get(role); } /** * Returns the list of collections in this set with the given IDPF-reserved * role. */ public List getByRole(Roles role) { return role == null ? ImmutableList. of() : getByRole(role.toString()); } /** * Returns true if this set contains one or more collections with * the given role. */ public boolean hasRole(String role) { return !collectionsByRole.get(role).isEmpty(); } /** * Returns true if this set contains one or more collections with * the given IDPF-reserved role. */ public boolean hasRole(Roles role) { return role != null && hasRole(role.toString()); } /** * Creates a new builder. Calling this method is identical to calling the * empty {@link Builder} constructor. * * @return a newly created builder. */ public static final Builder builder() { return new Builder(); } /** * A builder for {@link ResourceCollections}. * * @author Romain Deltour * */ public static final class Builder { private final LinkedHashSet collections = Sets.newLinkedHashSet(); /** * Add the given collection to the list of collections to build. * * @param collection * the collection to add. * @return this builder. */ public Builder add(ResourceCollection collection) { if (collection != null) collections.add(collection); return this; } /** * Returns a newly created list of collections. */ public ResourceCollections build() { return new ResourceCollections(collections); } } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/opf/ResourceCollection.java0000644000175000017500000001345313017276730026433 0ustar eugeneeugenepackage com.adobe.epubcheck.opf; import java.util.HashSet; import java.util.Locale; import java.util.Set; import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.base.Strings; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; /** * Represent a collection of resources as defined by the collection * element in Package Documents. */ public final class ResourceCollection { /** * The collection roles reserved by IDPF. See
http://www.idpf.org/epub/vocab/package/roles/ * */ public static enum Roles { DICTIONARY, DISTRIBUTABLE_OBJECT, INDEX, INDEX_GROUP, MANIFEST, PREVIEW, SCRIPTABLE_COMPONENT; /** * Returns the role name as defined by IDPF. */ @Override public String toString() { return name().toLowerCase(Locale.ROOT).replace('_', '-'); } /** * Returns an {@link Optional} containing the enum constant for the given * role name or {@link Optional#absent()} if none is found. */ public static Optional fromString(String role) { try { return Optional .of(Roles.valueOf(Strings.nullToEmpty(role).toUpperCase(Locale.ROOT).replace('-', '_'))); } catch (IllegalArgumentException e) { return Optional.absent(); } } } private final Set roles; private final MetadataSet metadata; private final LinkedResources metadataLinks; private final ResourceCollections collections; private final LinkedResources resources; private ResourceCollection(Set roles, MetadataSet metadata, LinkedResources metadataLinks, ResourceCollections collections, LinkedResources resources) { this.roles = roles; this.metadata = metadata; this.metadataLinks = metadataLinks; this.collections = collections; this.resources = resources; } /** * Returns the roles of this collection. */ public Set getRoles() { return roles; } /** * Returns true if this collection has the given role. */ public boolean hasRole(String role) { return role != null && roles.contains(role); } /** * Returns true if this collection has the given IDPF-reserved * role. */ public boolean hasRole(Roles role) { return role != null && roles.contains(role.toString()); } /** * Returns the metadata of this collection. Guaranteed non-null (can be * empty). */ public MetadataSet getMetadata() { return metadata; } /** * Returns the linked resources defined as metadata in this collection. * Guaranteed non-null (can be empty). */ public LinkedResources getMetadataLinks() { return metadataLinks; } /** * Returns the set of this collection's sub collections. Guaranteed non-null * (can be empty). */ public ResourceCollections getCollections() { return collections; } /** * Returns the set of this collection's resources. Guaranteed non-null (can be * empty). */ public LinkedResources getResources() { return resources; } /** * Creates a new builder. Calling this method is identical to calling the * empty {@link Builder} constructor. * * @return a newly created builder. */ public static final Builder builder() { return new Builder(); } /** * A builder for {@link ResourceCollection}. * */ public static final class Builder { private final Set roles = new HashSet(); private MetadataSet metadata = null; private LinkedResources metadataLinks = null; private final ResourceCollections.Builder collections = ResourceCollections.builder(); private LinkedResources resources = null; /** * Add the given roles to the collection to build. * * @param iterable * a set of roles. * @return this builder. */ public Builder roles(Iterable roles) { Iterables.addAll(this.roles, roles); return this; } /** * Add the given metadata set to the collection to build. * * @param metadata * a set of EPUB metadata. * @return this builder. */ public Builder metadata(MetadataSet metadata) { this.metadata = metadata; return this; } /** * Add the given linked resources as metadata links to the collection to * build. * * @param resources * the resources to add. * @return this builder. */ public Builder metadataLinks(LinkedResources metadataLinks) { this.metadataLinks = metadataLinks; return this; } /** * Add the given collection as a sub-collection of the collection to build. * * @param collection * a collection. * @return this builder. */ public Builder collection(ResourceCollection collection) { this.collections.add(collection); return this; } /** * Add the given resources to the collection to build. * * @param resources * the resources to add. * @return this builder. */ public Builder resources(LinkedResources resources) { this.resources = resources; return this; } /** * Returns a newly created collection. */ public ResourceCollection build() { Preconditions.checkState(roles != null); return new ResourceCollection(ImmutableSet.copyOf(roles), metadata != null ? metadata : MetadataSet.builder().build(), metadataLinks != null ? metadataLinks : LinkedResources .builder().build(), collections.build(), resources != null ? resources : LinkedResources .builder().build()); } } }epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/opf/OPFItems.java0000644000175000017500000000715213017276730024255 0ustar eugeneeugenepackage com.adobe.epubcheck.opf; import java.util.List; import java.util.Map; import com.adobe.epubcheck.opf.OPFItem.Builder; import com.google.common.base.Function; import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.base.Predicates; import com.google.common.collect.FluentIterable; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; import com.google.common.collect.Maps; /** * Represents the set of Publication Resources in a Package Document (OPF). * */ public final class OPFItems { private final List items; private final List spine; private final Map itemsById; private final Map itemsByPath; /** * Search the item with the given ID. * * @param id * the ID of the item to search, can be null. * @return An {@link Optional} containing the item if found, or * {@link Optional#absent()} if not found. */ public Optional getItemById(String id) { return Optional.fromNullable(itemsById.get(id)); } /** * Search the item with the given path. * * @param id * the path of the item to search, can be null. * @return An {@link Optional} containing the item if found, or * {@link Optional#absent()} if not found. */ public Optional getItemByPath(String path) { return Optional.fromNullable(itemsByPath.get(path)); } /** * Returns the list of items in the spine. A single {@link OPFItem} instance * can appear multiple times in the list. * * @return the list of items in the spine. */ public List getSpineItems() { return spine; } /** * Returns the list of items in this set, in document order. * * @return the list of items in this set. */ public List getItems() { return items; } private OPFItems(Iterable items, Iterable spineIDs) { this.items = ImmutableList.copyOf(Preconditions.checkNotNull(items)); // Build the by-ID and by-Paths maps // We use temporary HashMaps to ignore potential duplicate keys Map itemsById = Maps.newHashMap(); Map itemsByPath = Maps.newHashMap(); for (OPFItem item : this.items) { itemsById.put(item.getId(), item); itemsByPath.put(item.getPath(), item); } this.itemsById = ImmutableMap.copyOf(itemsById); this.itemsByPath = ImmutableMap.copyOf(itemsByPath); // Build the spine view this.spine = FluentIterable.from(spineIDs).transform(new Function() { @Override public OPFItem apply(final String id) { return OPFItems.this.itemsById.get(id.trim()); } }).filter(Predicates.notNull()).toList(); } /** * Creates a consolidated set of {@link OPFItem} from item builders and a list * of spine item IDs. * * @param itemBuilders * the builders of the {@link OPFItem} in the set. * @param spineIDs * the IDs of the items in the spine. * @return a consolidated set of {@link OPFItem}s. */ public static OPFItems build(Iterable itemBuilders, Iterable spineIDs) { return new OPFItems(Iterables.transform(Preconditions.checkNotNull(itemBuilders), new Function() { @Override public OPFItem apply(Builder builder) { return builder.build(); } }), Preconditions.checkNotNull(spineIDs)); } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/opf/OPFData.java0000644000175000017500000000321013017276730024034 0ustar eugeneeugenepackage com.adobe.epubcheck.opf; import java.util.Set; import com.adobe.epubcheck.util.EPUBVersion; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; public final class OPFData { public static final String OPF_MIME_TYPE = "application/oebps-package+xml"; public static final String DC_TYPE_DICT = "dictionary"; public static final String DC_TYPE_EDUPUB = "edupub"; public static final String DC_TYPE_INDEX = "index"; public static final String DC_TYPE_PREVIEW = "preview"; public static class OPFDataBuilder { private EPUBVersion version; private Set types = Sets.newHashSet(); private String uniqueId; public OPFData build() { return new OPFData(version, uniqueId, types); } public OPFDataBuilder withUniqueId(String uniqueId) { this.uniqueId = uniqueId; return this; } public OPFDataBuilder withVersion(EPUBVersion version) { this.version = version; return this; } public OPFDataBuilder withType(String type) { this.types.add(type); return this; } } private final EPUBVersion version; private final Set types; private final String uniqueId; private OPFData(EPUBVersion version, String uniqueId, Set types) { this.version = version; this.uniqueId = uniqueId; this.types = ImmutableSet.copyOf(types); } public EPUBVersion getVersion() { return version; } public Set getTypes() { return types; } public String getUniqueIdentifier() { // Note: can be null, correctness is checked in OPFHandler return uniqueId; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/opf/OPFItem.java0000755000175000017500000002410513017276730024072 0ustar eugeneeugene/* * Copyright (c) 2007 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.opf; import java.util.Set; import com.adobe.epubcheck.vocab.EpubCheckVocab; import com.adobe.epubcheck.vocab.PackageVocabs; import com.adobe.epubcheck.vocab.Property; import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.base.Strings; import com.google.common.collect.ImmutableSet; /** * Immutable representation of an item in a Package Document (OPF). Can * represent a item element or link elements pointing * to a container resource. */ public class OPFItem { private final String id; private final String path; private final String mimetype; private final int lineNumber; private final int columnNumber; private final Optional fallback; private final Optional fallbackStyle; private final Set properties; private final boolean ncx; private final boolean inSpine; private final boolean nav; private final boolean scripted; private final boolean linear; private final boolean fixedLayout; private OPFItem(String id, String path, String mimetype, int lineNumber, int columnNumber, Optional fallback, Optional fallbackStyle, Set properties, boolean ncx, boolean inSpine, boolean nav, boolean scripted, boolean linear, boolean fxl) { this.id = id; this.path = path; this.mimetype = mimetype; this.lineNumber = lineNumber; this.columnNumber = columnNumber; this.fallback = fallback; this.fallbackStyle = fallbackStyle; this.properties = properties; this.ncx = ncx; this.inSpine = inSpine; this.nav = nav; this.scripted = scripted; this.linear = linear; this.fixedLayout = fxl; } /** * Returns the ID of this item. * * @return the ID of this item, guaranteed non-null. */ public String getId() { return id; } /** * The path of this item (cannot be null). * * @return the path of this item, relative to the container. */ public String getPath() { return path; } /** * Returns the media type of this item. * * @return the media type of this item, guaranteed non-null. */ public String getMimeType() { return mimetype; } /** * The line where this item is declared in the OPF. * * @return */ public int getLineNumber() { return lineNumber; } /** * The column where this item is declared in the OPF. * * @return */ public int getColumnNumber() { return columnNumber; } /** * Returns an {@link Optional} containing the ID of the fallback item for this * item, if it has one. * * @return An optional containing the ID of the fallback item for this item if * it has one, or {@link Optional#absent()} otherwise. */ public Optional getFallback() { return fallback; } /** * Returns An {@link Optional} containing the ID of the fallback stylesheet * for this item, if it has one. * * @return An optional containing the ID of the fallback stylesheet for this * item if it has one, or {@link Optional#absent()} otherwise. */ public Optional getFallbackStyle() { return fallbackStyle; } /** * Returns the set of {@link Property} declared on this item or any * itemref pointing to this item. * * @return the properties of this item, or an empty set if none is declared. */ public Set getProperties() { return properties; } /** * Returns true iff this item is an NCX document. * * @return true iff this item is an NCX document. */ public boolean isNcx() { return ncx; } /** * Returns true iff this item is a scripted document. * * @return true iff this item is a scripted document. */ public boolean isScripted() { return scripted; } /** * Returns true iff this item is a Navigation Document. * * @return true iff this item is an Navigation Document. */ public boolean isNav() { return nav; } /** * Returns true iff this item is in the spine. * * @return true iff this item is in the spine. */ public boolean isInSpine() { return inSpine; } /** * Returns true iff this item is a spine item part of the linear * reading order, as declared by the itemref/@linear attribute. * * @return true iff this item is in the spine and is linear. * @throws IllegalStateException * if this item is not in the spine. */ public boolean isLinear() { if (!inSpine) { throw new IllegalStateException("linear"); } return linear; } /** * Returns true iff this item is a Fixed-Layout Document. * * @return true iff this item is a Fixed-Layout Document. */ public boolean isFixedLayout() { return fixedLayout; } @Override public String toString() { return path + "[" + id + "]"; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((id == null) ? 0 : id.hashCode()); result = prime * result + ((path == null) ? 0 : path.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; OPFItem other = (OPFItem) obj; if (id == null) { if (other.id != null) return false; } else if (!id.equals(other.id)) return false; if (path == null) { if (other.path != null) return false; } else if (!path.equals(other.path)) return false; return true; } /** * A builder for {@link OPFItem} */ public static final class Builder { private String id; private String path; private String mimeType; private int lineNumber; private int columnNumber; private String fallback = null; private String fallbackStyle = null; private boolean ncx = false; private boolean linear = true; private boolean inSpine = false; private boolean fxl = false; private ImmutableSet.Builder propertiesBuilder = new ImmutableSet.Builder(); /** * Creates a new builder * * @param id * the item ID, can be null * @param path * the item path,, cannot be null * @param mimeType * the item media type, can be null * @param lineNumber * the line number of the corresponding item or * link element * @param columnNumber * the column number of the corresponding item or * link element */ public Builder(String id, String path, String mimeType, int lineNumber, int columnNumber) { this.id = Preconditions.checkNotNull(id).trim(); this.path = Preconditions.checkNotNull(path).trim(); this.mimeType = Optional.fromNullable(mimeType).or("undefined").trim(); this.lineNumber = lineNumber; this.columnNumber = columnNumber; } public Builder fallback(String fallback) { this.fallback = fallback; return this; } public Builder fallbackStyle(String fallbackStyle) { this.fallbackStyle = fallbackStyle; return this; } public Builder fixedLayout() { this.fxl = true; return this; } public Builder ncx() { this.ncx = true; return this; } public Builder nonlinear() { this.linear = false; return this; } public Builder inSpine() { this.inSpine = true; return this; } public Builder properties(Set properties) { if (properties != null) { this.propertiesBuilder.addAll(properties); } return this; } /** * Builds a new immutable {@link OPFItem} from this builder. */ public OPFItem build() { if (!inSpine || !linear) { this.propertiesBuilder.add(EpubCheckVocab.VOCAB.get(EpubCheckVocab.PROPERTIES.NON_LINEAR)); } if (fxl) { this.propertiesBuilder .add(EpubCheckVocab.VOCAB.get(EpubCheckVocab.PROPERTIES.FIXED_LAYOUT)); } Set properties = propertiesBuilder.build(); return new OPFItem(id, path, mimeType, lineNumber, columnNumber, Optional.fromNullable(Strings.emptyToNull(Strings.nullToEmpty(fallback).trim())), Optional.fromNullable(Strings.emptyToNull(Strings.nullToEmpty(fallbackStyle).trim())), properties, ncx, inSpine, properties.contains(PackageVocabs.ITEM_VOCAB.get(PackageVocabs.ITEM_PROPERTIES.NAV)), properties.contains(PackageVocabs.ITEM_VOCAB.get(PackageVocabs.ITEM_PROPERTIES.SCRIPTED)), linear, fxl); } } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/opf/OPFCheckerFactory.java0000644000175000017500000000325013017276730026063 0ustar eugeneeugene/* * Copyright (c) 2011 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.opf; import com.adobe.epubcheck.util.EPUBVersion; public class OPFCheckerFactory implements DocumentValidatorFactory, ContentCheckerFactory { static private final OPFCheckerFactory instance = new OPFCheckerFactory(); static public OPFCheckerFactory getInstance() { return instance; } public OPFChecker newInstance(ValidationContext context) { if (context.version == EPUBVersion.VERSION_2) { return new OPFChecker(context); } else { return new OPFChecker30(context); } } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/opf/LinkedResources.java0000644000175000017500000000745413017276730025735 0ustar eugeneeugenepackage com.adobe.epubcheck.opf; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import com.google.common.base.Optional; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableListMultimap; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ListMultimap; import com.google.common.collect.Maps; import com.google.common.collect.Sets; /** * Represents a set of linked resources (i.e. resources defined by * link elements in a Package Document), with predictable iteration * order. */ public final class LinkedResources { private final List resources; private final Map resourcesById; private final ListMultimap resourcesByPath; /** * Search the linked resource with the given ID. * * @param id * the ID of the resource to search, can be null. * @return An {@link Optional} containing the linked resource if found, or * {@link Optional#absent()} if not found. */ public Optional getById(String id) { return Optional.fromNullable(resourcesById.get(id)); } /** * Search the linked resource with the given path. All resource whose * href URI minus fragment is equal to the given path are * returned, in document order. * * @param path * the URI (without fragment) of the resource to search, can be * null. * @return A list of linked resources referencing the resource at * path or a fragment thereof ; an empty list is returned * if no such resource is found. */ public List getByPath(String path) { return resourcesByPath.get(path); } /** * Returns the list of all linked resources in this set, in document order. * * @return the list of all linked resources in this set. */ public List asList() { return resources; } /** * Returns true if this set contains a linked resource * referencing the given path (or fragment thereof). */ public boolean hasPath(String path) { return !getByPath(path).isEmpty(); } private LinkedResources(Iterable resources) { ImmutableList.Builder listBuilder = ImmutableList.builder(); ImmutableListMultimap.Builder byPathBuilder = ImmutableListMultimap .builder(); Map byIdMap = Maps.newHashMap(); for (LinkedResource resource : resources) { listBuilder.add(resource); byPathBuilder.put(resource.getPath(), resource); if (resource.getId().isPresent()) byIdMap.put(resource.getId().get(), resource); } this.resources = listBuilder.build(); this.resourcesByPath = byPathBuilder.build(); this.resourcesById = ImmutableMap.copyOf(byIdMap); } /** * Creates a new builder. Calling this method is identical to calling the * empty {@link Builder} constructor. * * @return a newly created builder. */ public static Builder builder() { return new Builder(); } /** * A builder for {@link LinkedResources}. * */ public static final class Builder { private final LinkedHashSet resources = Sets.newLinkedHashSet(); /** * Add a new linked resource to this builder. * * @param resource * the resource to add. * @return this builder. */ public Builder add(LinkedResource resource) { if (resource != null) resources.add(resource); return this; } /** * Returns a newly created set of linked resources. */ public LinkedResources build() { return new LinkedResources(resources); } } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/opf/DocumentValidator.java0000644000175000017500000000234013017276730026245 0ustar eugeneeugene/* * Copyright (c) 2011 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.opf; public interface DocumentValidator { public boolean validate(); } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/opf/OPFPeeker.java0000644000175000017500000001720513017276730024407 0ustar eugeneeugene/* * Copyright (c) 2011 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.opf; import java.io.IOException; import java.io.InputStream; import java.io.StringReader; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.xml.sax.Attributes; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.messages.MessageId; import com.adobe.epubcheck.opf.OPFData.OPFDataBuilder; import com.adobe.epubcheck.util.EPUBVersion; import com.adobe.epubcheck.util.EpubConstants; import com.adobe.epubcheck.util.GenericResourceProvider; import com.adobe.epubcheck.util.InvalidVersionException; import com.google.common.io.Closer; public final class OPFPeeker { private final static String FINISHED_PARSING = "FINISHED_PARSING"; private final Report report; private final String path; private final GenericResourceProvider resourceProvider; public OPFPeeker(String path, Report report, GenericResourceProvider resourceProvider) { this.path = path; this.report = report; this.resourceProvider = resourceProvider; } public OPFData peek() throws InvalidVersionException, IOException { Closer closer = Closer.create(); try { InputStream in = resourceProvider.getInputStream(path); if (in == null) throw new IOException("Couldn't find resource " + path); in = closer.register(resourceProvider.getInputStream(path)); return peek(in); } catch (Throwable e) { throw closer.rethrow(e, InvalidVersionException.class); } finally { closer.close(); } } private OPFData peek(InputStream inputStream) throws InvalidVersionException { OPFDataBuilder builder = new OPFDataBuilder(); SAXParserFactory factory = SAXParserFactory.newInstance(); factory.setNamespaceAware(true); factory.setValidating(false); try { factory.setFeature("http://xml.org/sax/features/validation", false); factory.setFeature("http://xml.org/sax/features/external-general-entities", false); factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false); } catch (Exception ignored) { } SAXParser parser; try { ParserHandler handler = new ParserHandler(builder); parser = factory.newSAXParser(); parser.getXMLReader().setEntityResolver(handler); parser.getXMLReader().setErrorHandler(handler); parser.getXMLReader().setContentHandler(handler); parser.getXMLReader().parse(new InputSource(inputStream)); } catch (ParserConfigurationException e) { report.message(MessageId.RSC_005, EPUBLocation.create(path), e.getMessage()); } catch (InvalidVersionException e) { throw e; } catch (SAXException e) { if (FINISHED_PARSING.equals(e.getMessage())) { OPFData data = builder.build(); return data; } else { report.message(MessageId.RSC_005, EPUBLocation.create(path), e.getMessage()); } } catch (IOException e) { report .message(MessageId.PKG_008, EPUBLocation.create(path), path); } throw new InvalidVersionException(InvalidVersionException.VERSION_NOT_FOUND); } private static class ParserHandler extends DefaultHandler { private static final String VERSION_3 = "3.0"; private static final String VERSION_2 = "2.0"; private final OPFDataBuilder builder; private boolean isPackageRoot = false; private String currentText = null; private String uniqueId = null; private boolean isUniqueId = false; public ParserHandler(OPFDataBuilder builder) { this.builder = builder; } @Override public InputSource resolveEntity(String publicId, String systemId) throws IOException, SAXException { return new InputSource(new StringReader("")); } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if ("package".equals(localName)) { processPackage(attributes); isPackageRoot = true; } else if (!isPackageRoot) { throw new InvalidVersionException( InvalidVersionException.PACKAGE_ELEMENT_NOT_FOUND); } else if ("type".equals(localName) && EpubConstants.DCElements.equals(uri)) { currentText = ""; } else if ("identifier".equals(localName) && EpubConstants.DCElements.equals(uri)) { String id = attributes.getValue("id"); isUniqueId = id!=null && id.trim().equals(uniqueId); if (isUniqueId) { currentText = ""; } } } @Override public void characters(char[] ch, int start, int length) throws SAXException { if (currentText != null) { currentText += String.valueOf(ch, start, length); } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { if ("metadata".equals(localName) || "package".equals(localName)) { throw new SAXException(OPFPeeker.FINISHED_PARSING); } else if ("type".equals(localName) && EpubConstants.DCElements.equals(uri)) { currentText = currentText.trim(); if (currentText.length() > 0) builder.withType(currentText); currentText = null; } else if (isUniqueId && "identifier".equals(localName) && EpubConstants.DCElements.equals(uri)) { currentText = currentText.trim(); if (currentText.length() > 0) builder.withUniqueId(currentText); isUniqueId = false; currentText = null; } } private void processPackage(Attributes attributes) throws SAXException { String version = attributes.getValue("version"); if (version == null) { throw new InvalidVersionException( InvalidVersionException.VERSION_ATTRIBUTE_NOT_FOUND); } else if (VERSION_3.equals(version)) { builder.withVersion(EPUBVersion.VERSION_3); } else if (VERSION_2.equals(version)) { builder.withVersion(EPUBVersion.VERSION_2); } else { throw new InvalidVersionException( InvalidVersionException.UNSUPPORTED_VERSION); } String uniqueId = attributes.getValue("unique-identifier"); if (uniqueId != null) this.uniqueId = uniqueId; } } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/opf/ContentChecker.java0000755000175000017500000000233313017276730025525 0ustar eugeneeugene/* * Copyright (c) 2007 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.opf; public interface ContentChecker { public void runChecks(); } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/opf/OPFChecker.java0000755000175000017500000004510713017276730024545 0ustar eugeneeugene/* * Copyright (c) 2007 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.opf; import static com.adobe.epubcheck.opf.ValidationContext.ValidationContextPredicates.*; import java.util.HashSet; import java.util.Hashtable; import java.util.List; import java.util.Set; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.api.EPUBProfile; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.bitmap.BitmapCheckerFactory; import com.adobe.epubcheck.css.CSSCheckerFactory; import com.adobe.epubcheck.dtbook.DTBookCheckerFactory; import com.adobe.epubcheck.messages.MessageId; import com.adobe.epubcheck.nav.NavCheckerFactory; import com.adobe.epubcheck.ncx.NCXCheckerFactory; import com.adobe.epubcheck.ocf.OCFFilenameChecker; import com.adobe.epubcheck.ocf.OCFPackage; import com.adobe.epubcheck.opf.ValidationContext.ValidationContextBuilder; import com.adobe.epubcheck.ops.OPSCheckerFactory; import com.adobe.epubcheck.util.EPUBVersion; import com.adobe.epubcheck.util.FeatureEnum; import com.adobe.epubcheck.util.PathUtil; import com.adobe.epubcheck.util.ValidatorMap; import com.adobe.epubcheck.xml.XMLParser; import com.adobe.epubcheck.xml.XMLValidator; import com.adobe.epubcheck.xml.XMLValidators; import com.google.common.base.Optional; import com.google.common.base.Predicates; public class OPFChecker implements DocumentValidator, ContentChecker { private final static ValidatorMap validatorMap = ValidatorMap.builder() .put(version(EPUBVersion.VERSION_2), XMLValidators.OPF_20_RNG) .put(version(EPUBVersion.VERSION_2), XMLValidators.OPF_20_SCH) .put(version(EPUBVersion.VERSION_3), XMLValidators.OPF_30_RNC) .put(version(EPUBVersion.VERSION_3), XMLValidators.OPF_30_SCH) .put(version(EPUBVersion.VERSION_3), XMLValidators.OPF_30_COLLECTION_DO_SCH) .put(version(EPUBVersion.VERSION_3), XMLValidators.OPF_30_COLLECTION_DICT_SCH) .put(version(EPUBVersion.VERSION_3), XMLValidators.OPF_30_COLLECTION_IDX_SCH) .put(version(EPUBVersion.VERSION_3), XMLValidators.OPF_30_COLLECTION_MANIFEST_SCH) .put(version(EPUBVersion.VERSION_3), XMLValidators.OPF_30_COLLECTION_PREVIEW_SCH) .put(Predicates.or(profile(EPUBProfile.DICT), hasPubType(OPFData.DC_TYPE_DICT)), XMLValidators.OPF_DICT_SCH) .put(Predicates.or(profile(EPUBProfile.EDUPUB), hasPubType(OPFData.DC_TYPE_EDUPUB)), XMLValidators.OPF_EDUPUB_SCH) .put(Predicates.or(profile(EPUBProfile.PREVIEW), hasPubType(OPFData.DC_TYPE_PREVIEW)), XMLValidators.OPF_PREVIEW_SCH) .build(); protected final ValidationContext context; protected final Report report; protected final String path; protected final EPUBVersion version; protected OPFHandler opfHandler = null; protected XMLParser opfParser = null; protected final Hashtable contentCheckerFactoryMap = new Hashtable(); protected void initContentCheckerFactoryMap() { Hashtable map = new Hashtable(); map.put("application/xhtml+xml", OPSCheckerFactory.getInstance()); map.put("application/x-dtbook+xml", DTBookCheckerFactory.getInstance()); map.put("image/jpeg", BitmapCheckerFactory.getInstance()); map.put("image/gif", BitmapCheckerFactory.getInstance()); map.put("image/png", BitmapCheckerFactory.getInstance()); map.put("image/svg+xml", OPSCheckerFactory.getInstance()); map.put("text/css", CSSCheckerFactory.getInstance()); map.put("text/html", OPSCheckerFactory.getInstance()); map.put("text/x-oeb1-document", OPSCheckerFactory.getInstance()); contentCheckerFactoryMap.putAll(map); } public OPFChecker(ValidationContext context) { // The following context fields are not overridden from the parent context this.report = context.report; this.path = context.path; this.version = context.version; // Create a new validation context from the parent ValidationContextBuilder newContext = new ValidationContextBuilder(context); if (context.ocf.isPresent()) { // Get the OPFData peeked from the OCF OPFData opfData = context.ocf.get().getOpfData().get(context.path); newContext.pubTypes(opfData != null ? opfData.getTypes() : null); newContext.xrefChecker(new XRefChecker(context.ocf.get(), context.report, context.version)); newContext.profile(EPUBProfile.makeOPFCompatible(context.profile, opfData, path, report)); } this.context = newContext.build(); // Initialize validators and factories initContentCheckerFactoryMap(); } public void runChecks() { OCFPackage ocf = context.ocf.get(); XRefChecker xrefChecker = context.xrefChecker.get(); if (!ocf.hasEntry(path)) { report.message(MessageId.PKG_020, EPUBLocation.create(ocf.getName()), path); return; } validate(); if (!opfHandler.checkUniqueIdentExists()) { report.message(MessageId.OPF_030, EPUBLocation.create(path), opfHandler.getIdentId()); } List items = opfHandler.getItems(); report.info(null, FeatureEnum.ITEMS_COUNT, Integer.toString(items.size())); for (OPFItem item : items) { xrefChecker.registerResource(item, new FallbackChecker().checkItemFallbacks(item, opfHandler, true), new FallbackChecker().checkImageFallbacks(item, opfHandler)); report.info(item.getPath(), FeatureEnum.DECLARED_MIMETYPE, item.getMimeType()); } checkGuide(); checkBindings(); for (OPFItem item : items) { if (!item.getPath().matches("^[^:/?#]+://.*")) { checkItemContent(item); } } xrefChecker.checkReferences(); } protected void checkBindings() { } protected void checkGuide() { int refCount = opfHandler.getReferenceCount(); for (int i = 0; i < refCount; i++) { OPFReference ref = opfHandler.getReference(i); String itemPath = PathUtil.removeAnchor(ref.getHref()); Optional item = opfHandler.getItemByPath(itemPath); if (!item.isPresent()) { report.message(MessageId.OPF_031, EPUBLocation.create(path, ref.getLineNumber(), ref.getColumnNumber()), ref.getHref()); } else { if (!isBlessedItemType(item.get().getMimeType(), version) && !isDeprecatedBlessedItemType(item.get().getMimeType())) { report.message(MessageId.OPF_032, EPUBLocation.create(path, ref.getLineNumber(), ref.getColumnNumber()), ref.getHref()); } } } } protected void initHandler() { opfHandler = new OPFHandler(context, opfParser); } public OPFHandler getOPFHandler() { return opfHandler; } @Override public boolean validate() { int fatalErrorsSoFar = report.getFatalErrorCount(); int errorsSoFar = report.getErrorCount(); int warningsSoFar = report.getWarningCount(); opfParser = new XMLParser(new ValidationContextBuilder(context).mimetype("opf").build()); initHandler(); opfParser.addXMLHandler(opfHandler); for (XMLValidator validator : validatorMap.getValidators(context)) { opfParser.addValidator(validator); } opfParser.process(); for (OPFItem item : opfHandler.getItems()) { // only check Filename CompatiblyEscaped when in "-mode opf" // this is when 'xrefChecker' Object is null which is an indicator for // single file validation // (Had no better possibility in mind since "mode" isn't available in // OPFChecker.java) // // bugfix for issue 239 if (!context.xrefChecker.isPresent()) { OCFFilenameChecker.checkCompatiblyEscaped(item.getPath(), report, version); } if (!item.equals(opfHandler.getItemByPath(item.getPath()).orNull())) { report.message(MessageId.OPF_074, EPUBLocation.create(path, item.getLineNumber(), item.getColumnNumber()), item.getPath()); } else { checkItem(item, opfHandler); } } if (!opfHandler.getSpineItems().isEmpty()) { boolean linearFound = false; int spineIndex = 0; for (OPFItem item : opfHandler.getSpineItems()) { checkSpineItem(item, opfHandler); if (item.isLinear()) { linearFound = true; } report.info(item.getPath(), FeatureEnum.SPINE_INDEX, Integer.toString(spineIndex++)); } if (!linearFound) { report.message(MessageId.OPF_033, EPUBLocation.create(path)); } } if (version == EPUBVersion.VERSION_2) { // check for >1 itemrefs to any given spine item // http://code.google.com/p/epubcheck/issues/detail?id=182 Set seen = new HashSet(); for (OPFItem item : opfHandler.getSpineItems()) { if (seen.contains(item)) { report.message(MessageId.OPF_034, EPUBLocation.create(path, item.getLineNumber(), item.getLineNumber()), item.getId()); } else { seen.add(item); } } } return fatalErrorsSoFar == report.getFatalErrorCount() && errorsSoFar == report.getErrorCount() && warningsSoFar == report.getWarningCount(); } public static boolean isBlessedItemType(String type, EPUBVersion version) { if (version == EPUBVersion.VERSION_2) { return type.equals("application/xhtml+xml") || type.equals("application/x-dtbook+xml"); } else { return type.equals("application/xhtml+xml") || type.equals("image/svg+xml"); } } public static boolean isDeprecatedBlessedItemType(String type) { return type.equals("text/x-oeb1-document") || type.equals("text/html"); } public static boolean isBlessedStyleType(String type) { return type.equals("text/css"); } public static boolean isDeprecatedBlessedStyleType(String type) { return type.equals("text/x-oeb1-css"); } public static boolean isBlessedImageType(String type) { return type.equals("image/gif") || type.equals("image/png") || type.equals("image/jpeg") || type.equals("image/svg+xml"); } public static boolean isBlessedFontMimetype20(String mime) { return mime != null && (mime.startsWith("font/") || mime.startsWith("application/font") || mime.startsWith("application/x-font") || "application/vnd.ms-opentype".equals(mime)); } protected void checkItem(OPFItem item, OPFHandler opfHandler) { String mimeType = item.getMimeType(); Optional fallback = item.getFallback(); if (!mimeType.matches("[a-zA-Z0-9!#$&+-^_]+/[a-zA-Z0-9!#$&+-^_]+")) { /* * Ensures that media-type attribute has correct content. The media-type * must have a type and a sub-type divided by '/' The allowable content * for the media-type attribute is defined in RFC4288 section 4.2 */ // report.error(path, item.getLineNumber(), item.getColumnNumber(), // "invalid content for media-type attribute"); } else if (isDeprecatedBlessedItemType(mimeType) || isDeprecatedBlessedStyleType(mimeType)) { if (opfHandler.getOpf20PackageFile() && mimeType.equals("text/html")) { report.message(MessageId.OPF_035, EPUBLocation.create(path, item.getLineNumber(), item.getColumnNumber(), item.getId())); } else if (opfHandler.getOpf12PackageFile() && mimeType.equals("text/html")) { report.message(MessageId.OPF_038, EPUBLocation.create(path, item.getLineNumber(), item.getColumnNumber(), item.getId()), mimeType); } else if (opfHandler.getOpf20PackageFile()) { report.message(MessageId.OPF_037, EPUBLocation.create(path, item.getLineNumber(), item.getColumnNumber(), item.getId()), mimeType); } } if (opfHandler.getOpf12PackageFile() && !fallback.isPresent()) { if (isBlessedItemType(mimeType, version)) { report.message(MessageId.OPF_038, EPUBLocation.create(path, item.getLineNumber(), item.getColumnNumber(), item.getId()), mimeType); } else if (isBlessedStyleType(mimeType)) { report.message(MessageId.OPF_039, EPUBLocation.create(path, item.getLineNumber(), item.getColumnNumber(), item.getId()), mimeType); } } if (fallback.isPresent()) { Optional fallbackItem = opfHandler.getItemById(fallback.get()); if (!fallbackItem.isPresent()) { report.message(MessageId.OPF_040, EPUBLocation.create(path, item.getLineNumber(), item.getColumnNumber(), item.getId())); } } if (item.getFallbackStyle().isPresent()) { Optional fallbackStyleItem = opfHandler.getItemById(item.getFallbackStyle().get()); if (!fallbackStyleItem.isPresent()) { report.message(MessageId.OPF_041, EPUBLocation.create(path, item.getLineNumber(), item.getColumnNumber(), item.getId())); } } } protected void checkItemContent(OPFItem item) { String mimetype = item.getMimeType(); ContentCheckerFactory checkerFactory; if (item.isNcx()) { checkerFactory = NCXCheckerFactory.getInstance(); } else if (item.isNav()) { checkerFactory = NavCheckerFactory.getInstance(); } else { checkerFactory = contentCheckerFactoryMap.get(mimetype); } if (checkerFactory == null) { checkerFactory = GenericContentCheckerFactory.getInstance(); } if (checkerFactory != null) { // Create the content checker with an overridden validation context ContentChecker checker = checkerFactory.newInstance(new ValidationContextBuilder(context) .path(item.getPath()).mimetype(mimetype).properties(item.getProperties()).build()); // Validate checker.runChecks(); } } protected void checkSpineItem(OPFItem item, OPFHandler opfHandler) { // These checks are okay to be done on items, but they really // should be done on all // items instead. I am avoiding making this change now // pending a few issue // resolutions in the EPUB Maint Working Group (e.g. embedded fonts not // needing fallbacks). // [GC 11/15/09] String mimeType = item.getMimeType(); if (isBlessedStyleType(mimeType) || isDeprecatedBlessedStyleType(mimeType) || isBlessedImageType(mimeType)) { report.message(MessageId.OPF_042, EPUBLocation.create(path, item.getLineNumber(), item.getColumnNumber()), mimeType); } else if (!isBlessedItemType(mimeType, version) && !isDeprecatedBlessedItemType(mimeType) && !item.getFallback().isPresent()) { report.message(MessageId.OPF_043, EPUBLocation.create(path, item.getLineNumber(), item.getColumnNumber()), mimeType); } else if (!isBlessedItemType(mimeType, version) && !isDeprecatedBlessedItemType(mimeType) && !new FallbackChecker().checkItemFallbacks(item, opfHandler, true)) { report.message(MessageId.OPF_044, EPUBLocation.create(path, item.getLineNumber(), item.getColumnNumber()), mimeType); } } class FallbackChecker { private final Set checked; public FallbackChecker() { checked = new HashSet(); } boolean checkItemFallbacks(OPFItem item, OPFHandler opfHandler, boolean checkFallbackStyle) { if (item.getFallback().isPresent()) { String fallback = item.getFallback().get(); if (checked.contains(fallback)) { report.message(MessageId.OPF_045, EPUBLocation.create(path, item.getLineNumber(), item.getColumnNumber())); return false; } else { checked.add(fallback); } Optional fallbackItem = opfHandler.getItemById(fallback); if (fallbackItem.isPresent()) { String mimeType = fallbackItem.get().getMimeType(); if (isBlessedItemType(mimeType, version) || isDeprecatedBlessedItemType(mimeType)) { return true; } if (checkItemFallbacks(fallbackItem.get(), opfHandler, checkFallbackStyle)) { return true; } } } if (!checkFallbackStyle) { return false; } if (item.getFallbackStyle().isPresent()) { String fallbackStyle = item.getFallbackStyle().get(); Optional fallbackStyleItem = opfHandler.getItemById(fallbackStyle); if (fallbackStyleItem.isPresent()) { String mimeType = fallbackStyleItem.get().getMimeType(); return (isBlessedStyleType(mimeType) || isDeprecatedBlessedStyleType(mimeType)); } } return false; } boolean checkImageFallbacks(OPFItem item, OPFHandler opfHandler) { if (item.getFallback().isPresent()) { String fallback = item.getFallback().get(); if (checked.contains(fallback)) { report.message(MessageId.OPF_045, EPUBLocation.create(path, item.getLineNumber(), item.getColumnNumber())); return false; } else { checked.add(fallback); } Optional fallbackItem = opfHandler.getItemById(fallback); if (fallbackItem.isPresent()) { String mimeType = fallbackItem.get().getMimeType(); if (isBlessedImageType(mimeType)) { return true; } if (checkImageFallbacks(fallbackItem.get(), opfHandler)) { return true; } } } return false; } } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/opf/OPFHandler30.java0000644000175000017500000005240213017276730024712 0ustar eugeneeugene/* * Copyright (c) 2011 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.opf; import static com.adobe.epubcheck.vocab.ForeignVocabs.*; import static com.adobe.epubcheck.vocab.PackageVocabs.*; import java.net.URI; import java.net.URISyntaxException; import java.util.Deque; import java.util.List; import java.util.Map; import java.util.Set; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.api.QuietReport; import com.adobe.epubcheck.messages.MessageId; import com.adobe.epubcheck.opf.ResourceCollection.Roles; import com.adobe.epubcheck.opf.XRefChecker.Type; import com.adobe.epubcheck.util.EpubConstants; import com.adobe.epubcheck.util.FeatureEnum; import com.adobe.epubcheck.util.PathUtil; import com.adobe.epubcheck.vocab.DCMESVocab; import com.adobe.epubcheck.vocab.EnumVocab; import com.adobe.epubcheck.vocab.EpubCheckVocab; import com.adobe.epubcheck.vocab.MediaOverlaysVocab; import com.adobe.epubcheck.vocab.PackageVocabs.ITEM_PROPERTIES; import com.adobe.epubcheck.vocab.Property; import com.adobe.epubcheck.vocab.RenditionVocabs; import com.adobe.epubcheck.vocab.ScriptedCompVocab; import com.adobe.epubcheck.vocab.Vocab; import com.adobe.epubcheck.vocab.VocabUtil; import com.adobe.epubcheck.xml.XMLElement; import com.adobe.epubcheck.xml.XMLParser; import com.google.common.base.Optional; import com.google.common.base.Splitter; import com.google.common.base.Strings; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; public class OPFHandler30 extends OPFHandler { private static final Map RESERVED_VOCABS = new ImmutableMap.Builder() .put(DCTERMS_PREFIX, DCTERMS_VOCAB).put(MARC_PREFIX, MARC_VOCAB).put(ONIX_PREFIX, ONIX_VOCAB) .put(SCHEMA_PREFIX, SCHEMA_VOCAB).put(XSD_PREFIX, XSD_VOCAB).build(); private static final Map RESERVED_META_VOCABS = new ImmutableMap.Builder() .put("", META_VOCAB).put(MediaOverlaysVocab.PREFIX, MediaOverlaysVocab.VOCAB) .put(RenditionVocabs.PREFIX, RenditionVocabs.META_VOCAB) .put(ScriptedCompVocab.PREFIX, ScriptedCompVocab.VOCAB).putAll(RESERVED_VOCABS).build(); private static final Map RESERVED_ITEM_VOCABS = new ImmutableMap.Builder() .put("", ITEM_VOCAB).put(MediaOverlaysVocab.PREFIX, VocabUtil.EMPTY_VOCAB) .put(RenditionVocabs.PREFIX, VocabUtil.EMPTY_VOCAB).putAll(RESERVED_VOCABS).build(); private static final Map RESERVED_ITEMREF_VOCABS = new ImmutableMap.Builder() .put("", ITEMREF_VOCAB).put(MediaOverlaysVocab.PREFIX, VocabUtil.EMPTY_VOCAB) .put(RenditionVocabs.PREFIX, RenditionVocabs.ITEMREF_VOCAB).putAll(RESERVED_VOCABS).build(); private static final Map RESERVED_LINKREL_VOCABS = new ImmutableMap.Builder() .put("", LINKREL_VOCAB).put(MediaOverlaysVocab.PREFIX, VocabUtil.EMPTY_VOCAB) .put(RenditionVocabs.PREFIX, VocabUtil.EMPTY_VOCAB).putAll(RESERVED_VOCABS).build(); private static final Map KNOWN_VOCAB_URIS = new ImmutableMap.Builder() .put(DCTERMS_URI, DCTERMS_VOCAB).put(MARC_URI, MARC_VOCAB).put(ONIX_URI, ONIX_VOCAB) .put(SCHEMA_URI, SCHEMA_VOCAB).put(XSD_URI, XSD_VOCAB).build(); private static final Map KNOWN_META_VOCAB_URIS = new ImmutableMap.Builder() .putAll(KNOWN_VOCAB_URIS).put(MediaOverlaysVocab.URI, MediaOverlaysVocab.VOCAB) .put(RenditionVocabs.URI, RenditionVocabs.META_VOCAB).build(); private static final Map KNOWN_ITEM_VOCAB_URIS = new ImmutableMap.Builder() .putAll(KNOWN_VOCAB_URIS).put(MediaOverlaysVocab.URI, VocabUtil.EMPTY_VOCAB) .put(RenditionVocabs.URI, VocabUtil.EMPTY_VOCAB).build(); private static final Map KNOWN_ITEMREF_VOCAB_URIS = new ImmutableMap.Builder() .putAll(KNOWN_VOCAB_URIS).put(MediaOverlaysVocab.URI, VocabUtil.EMPTY_VOCAB) .put(RenditionVocabs.URI, RenditionVocabs.ITEMREF_VOCAB).build(); private static final Map KNOWN_LINKREL_VOCAB_URIS = new ImmutableMap.Builder() .putAll(KNOWN_VOCAB_URIS).put(MediaOverlaysVocab.URI, VocabUtil.EMPTY_VOCAB) .put(RenditionVocabs.URI, VocabUtil.EMPTY_VOCAB).build(); private static final Set DEFAULT_VOCAB_URIS = ImmutableSet.of(PACKAGE_VOCAB_URI, LINKREL_VOCAB_URI); private static final Splitter TOKENIZER = Splitter.onPattern("\\s+"); private Map itemrefVocabs; private Map itemVocabs; private Map metaVocabs; private Map linkrelVocabs; private final Deque metadataBuilders = Lists.newLinkedList(); private MetadataSet metadata = null; private final Deque linkedResourcesBuilders = Lists.newLinkedList(); private LinkedResources linkedResources = null; private final Deque collectionBuilders = Lists.newLinkedList(); private final ResourceCollections.Builder collectionsBuilder = ResourceCollections.builder(); private ResourceCollections collections = null; OPFHandler30(ValidationContext context, XMLParser parser) { super(context, parser); } @Override public void startElement() { super.startElement(); XMLElement e = parser.getCurrentElement(); String name = e.getName(); if (EpubConstants.OpfNamespaceUri.equals(e.getNamespace())) { if (name.equals("package")) { // Note: the #parsePrefixDeclaration is called once for each "class" of // properties (meta+scheme, itemref, item, and link) so that default and // reserved vocabs can be set appropriately (e.g. the default vocab or // rendition vocab for 'meta' properties is not the same as for the // 'item' // properties) // Messages are reported only on the first invocation; a quiet reporter // is // used for subsequent invocations. String prefixDecl = e.getAttribute("prefix"); EPUBLocation loc = EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber()); metaVocabs = VocabUtil.parsePrefixDeclaration(prefixDecl, RESERVED_META_VOCABS, KNOWN_META_VOCAB_URIS, DEFAULT_VOCAB_URIS, report, loc); itemVocabs = VocabUtil.parsePrefixDeclaration(prefixDecl, RESERVED_ITEM_VOCABS, KNOWN_ITEM_VOCAB_URIS, DEFAULT_VOCAB_URIS, QuietReport.INSTANCE, loc); itemrefVocabs = VocabUtil.parsePrefixDeclaration(prefixDecl, RESERVED_ITEMREF_VOCABS, KNOWN_ITEMREF_VOCAB_URIS, DEFAULT_VOCAB_URIS, QuietReport.INSTANCE, loc); linkrelVocabs = VocabUtil.parsePrefixDeclaration(prefixDecl, RESERVED_LINKREL_VOCABS, KNOWN_LINKREL_VOCAB_URIS, DEFAULT_VOCAB_URIS, QuietReport.INSTANCE, loc); } else if (name.equals("metadata")) { metadataBuilders.addFirst(MetadataSet.builder()); linkedResourcesBuilders.addFirst(LinkedResources.builder()); } else if (name.equals("link")) { processLink(e); } else if (name.equals("item")) { String id = e.getAttribute("id"); OPFItem.Builder itemBuilder = itemBuilders.get(id); if (itemBuilder != null) { processItemProperties(itemBuilder, e.getAttribute("properties"), e.getAttribute("media-type")); } } else if (name.equals("itemref")) { String idref = e.getAttribute("idref"); OPFItem.Builder itemBuilder = itemBuilders.get(idref); if (itemBuilder != null) { processItemrefProperties(itemBuilder, e.getAttribute("properties")); } } else if (name.equals("mediaType")) { processBinding(e); } else if (name.equals("collection")) { collectionBuilders.addFirst( ResourceCollection.builder().roles(processCollectionRole(e.getAttribute("role")))); linkedResourcesBuilders.addFirst(LinkedResources.builder()); } } } @Override public void endElement() { XMLElement e = parser.getCurrentElement(); String name = e.getName(); if (EpubConstants.OpfNamespaceUri.equals(e.getNamespace())) { if (name.equals("package")) { collections = collectionsBuilder.build(); for (ResourceCollection collection : getCollections().getByRole(Roles.INDEX)) { processItemsInIndexCollection(collection); } } else if (name.equals("meta")) { processMeta(e); } else if (name.equals("metadata")) { // else peek collection builder and add it // Build metadata declared in this metadata element MetadataSet metadata = null; try { if (!metadataBuilders.isEmpty()) metadata = metadataBuilders.removeFirst().build(); } catch (IllegalStateException ex) { report.message(MessageId.OPF_065, EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber())); } // Build linked resources declared in this metadata element LinkedResources linkedResources = (linkedResourcesBuilders.isEmpty()) ? null : linkedResourcesBuilders.removeFirst().build(); // if we're not building a collection, assign to package-level objects if (collectionBuilders.isEmpty()) { this.metadata = metadata; this.linkedResources = linkedResources; reportMetadata(); } // else assign to the collection being built else { collectionBuilders.peekFirst().metadata(metadata).metadataLinks(linkedResources); } } else if (name.equals("collection")) { if (!collectionBuilders.isEmpty()) { // Build linked resources declared in this collection if (!linkedResourcesBuilders.isEmpty()) { collectionBuilders.peekFirst().resources(linkedResourcesBuilders.removeFirst().build()); } // build this collection ResourceCollection collection = collectionBuilders.removeFirst().build(); // if it's a top-level collection (no remaining parent collection) // assign to the set of Package collections if (collectionBuilders.isEmpty()) { collectionsBuilder.add(collection); } // else add as a sub-collection of the collection being built else { collectionBuilders.peekFirst().collection(collection); } } } } else if (EpubConstants.DCElements.equals(e.getNamespace())) { processDCElem(e); } super.endElement(); } /** * Returns the metadata for the Rendition represented by the current Package * Document. Must be called after the parsing. * * @return the metadata for the Rendition represented by the current Package * Document */ public MetadataSet getMetadata() { return (metadata == null) ? new MetadataSet.Builder().build() : metadata; } /** * Returns the list of linked resources (i.e. resources referenced from * link elements) declared in the current Package Document at the * package level (i.e. in the package metadata element). Must be * called after the parsing. * * @return the linked resources for the Rendition represented by the current * Package Document */ public LinkedResources getLinkedResources() { return (linkedResources == null) ? LinkedResources.builder().build() : linkedResources; } /** * Returns the list of collections (as defined in collection * elements) declared in the current Package Document. Must be called after * the parsing. * * @return the linked resources for the Rendition represented by the current * Package Document */ public ResourceCollections getCollections() { return (collections == null) ? ResourceCollections.builder().build() : collections; } private void processBinding(XMLElement e) { String mimeType = e.getAttribute("media-type"); String handlerId = e.getAttribute("handler"); if ((mimeType != null) && (handlerId != null)) { if (OPFChecker30.isCoreMediaType(mimeType)) { report.message(MessageId.OPF_008, EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber()), mimeType); return; } if (context.xrefChecker.isPresent() && context.xrefChecker.get().getBindingHandlerId(mimeType) != null) { report.message(MessageId.OPF_009, EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber()), mimeType, context.xrefChecker.get().getBindingHandlerId(mimeType)); return; } if (itemBuilders.containsKey(handlerId) && context.xrefChecker.isPresent()) { context.xrefChecker.get().registerBinding(mimeType, handlerId); } } } private List processCollectionRole(String roleAtt) { ImmutableList.Builder rolesBuilder = ImmutableList.builder(); for (String role : TOKENIZER.split(Strings.nullToEmpty(roleAtt))) { if (role.matches("^[^:/?#]+://.*")) { // Role is an absolute IRI // check that the host component doesn't contain 'idpf.org' try { URI uri = new URI(role); if (uri.getHost() != null && uri.getHost().contains("idpf.org")) { report.message(MessageId.OPF_069, parser.getLocation(), role); } else { rolesBuilder.add(role); } } catch (URISyntaxException e) { report.message(MessageId.OPF_070, parser.getLocation(), role); } } else { // Role is a NMTOKEN // Check that it's in the reserved role list if (ResourceCollection.Roles.fromString(role).isPresent()) { rolesBuilder.add(role); } else { report.message(MessageId.OPF_068, parser.getLocation(), role); } } } return rolesBuilder.build(); } private void processLink(XMLElement e) { String href = e.getAttribute("href"); if (href != null && !href.matches("^[^:/?#]+://.*")) { try { href = PathUtil.resolveRelativeReference(path, href, null); } catch (IllegalArgumentException ex) { report.message(MessageId.OPF_010, EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber(), href), ex.getMessage()); href = null; } } if (href != null && href.matches("^[^:/?#]+://.*")) { report.info(path, FeatureEnum.REFERENCE, href); } if (context.xrefChecker.isPresent()) { context.xrefChecker.get().registerReference(path, parser.getLineNumber(), parser.getColumnNumber(), href, Type.LINK); } if (!linkedResourcesBuilders.isEmpty()) { LinkedResource resource = new LinkedResource.Builder(href).id(e.getAttribute("id")) .rel(processLinkRel(e.getAttribute("rel"))).mimetype(e.getAttribute("media-type")) .refines(e.getAttribute("refines")).build(); linkedResourcesBuilders.peekFirst().add(resource); } } private void processItemrefProperties(OPFItem.Builder builder, String property) { Set properties = VocabUtil.parsePropertyList(property, itemrefVocabs, report, EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber())); builder.properties(properties); if (properties .contains(RenditionVocabs.ITEMREF_VOCAB .get(RenditionVocabs.ITEMREF_PROPERTIES.LAYOUT_PRE_PAGINATED)) || !properties.contains( RenditionVocabs.ITEMREF_VOCAB.get(RenditionVocabs.ITEMREF_PROPERTIES.LAYOUT_REFLOWABLE)) && getMetadata().containsPrimary( RenditionVocabs.META_VOCAB.get(RenditionVocabs.META_PROPERTIES.LAYOUT), "pre-paginated")) { builder.fixedLayout(); } // NOTE: // Checked with Schematron, although the code below is more prefix-safe // Set propSet = Property.filter(properties, // ITEMREF_PROPERTIES.class); // if (propSet.contains(ITEMREF_PROPERTIES.PAGE_SPREAD_LEFT) // && propSet.contains(ITEMREF_PROPERTIES.PAGE_SPREAD_RIGHT)) // { // report.message(MessageId.OPF_011, // new EPUBLocation(path, parser.getLineNumber(), // parser.getColumnNumber())); // } } private void processItemProperties(OPFItem.Builder builder, String property, String mimeType) { if (property == null) { return; } Set properties = VocabUtil.parsePropertyList(property, itemVocabs, report, EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber())); Set itemProps = Property.filter(properties, ITEM_PROPERTIES.class); mimeType = mimeType.trim(); for (ITEM_PROPERTIES itemProp : itemProps) { if (!itemProp.allowedOnTypes().contains(mimeType)) { report.message(MessageId.OPF_012, EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber()), EnumVocab.ENUM_TO_NAME.apply(itemProp), mimeType); } } builder.properties(properties); } private Set processLinkRel(String rel) { return VocabUtil.parsePropertyList(rel, linkrelVocabs, report, EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber())); } private void processMeta(XMLElement e) { // get the property Optional prop = VocabUtil.parseProperty(e.getAttribute("property"), metaVocabs, report, EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber())); if (prop.isPresent() && !metadataBuilders.isEmpty()) { metadataBuilders.peekFirst().meta(e.getAttribute("id"), prop.get(), (String) e.getPrivateData(), e.getAttribute("refines")); } // just parse the scheme for vocab errors VocabUtil.parseProperty(e.getAttribute("scheme"), metaVocabs, report, EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber())); } private void processDCElem(XMLElement e) { // get the property Optional prop = DCMESVocab.VOCAB.lookup(e.getName()); if (prop.isPresent() && !metadataBuilders.isEmpty()) { metadataBuilders.peekFirst().meta(e.getAttribute("id"), prop.get(), (String) e.getPrivateData(), null); } } private void processItemsInIndexCollection(ResourceCollection collection) { if (collection.hasRole(Roles.INDEX) || collection.hasRole(Roles.INDEX_GROUP)) { for (LinkedResource resource : collection.getResources().asList()) { OPFItem.Builder itemBuilder = itemBuildersByPath.get(resource.getPath()); if (itemBuilder != null) { itemBuilder.properties(ImmutableSet .of(EpubCheckVocab.VOCAB.get(EpubCheckVocab.PROPERTIES.IN_INDEX_COLLECTION))); } } for (ResourceCollection childCollection : collection.getCollections().asList()) { processItemsInIndexCollection(childCollection); } } } protected void reportMetadata() { if (getMetadata().containsPrimary( RenditionVocabs.META_VOCAB.get(RenditionVocabs.META_PROPERTIES.LAYOUT), "pre-paginated")) { report.info(null, FeatureEnum.HAS_FIXED_LAYOUT, "pre-paginated"); } } @Override protected void reportItem(OPFItem item) { super.reportItem(item); boolean isFixed = getMetadata().containsPrimary( RenditionVocabs.META_VOCAB.get(RenditionVocabs.META_PROPERTIES.LAYOUT), "pre-paginated"); if (item.getProperties().contains( RenditionVocabs.ITEMREF_VOCAB.get(RenditionVocabs.ITEMREF_PROPERTIES.LAYOUT_PRE_PAGINATED))) { isFixed = true; } else if (item.getProperties().contains( RenditionVocabs.ITEMREF_VOCAB.get(RenditionVocabs.ITEMREF_PROPERTIES.LAYOUT_REFLOWABLE))) { isFixed = false; } if (isFixed) { report.info(item.getPath(), FeatureEnum.HAS_FIXED_LAYOUT, String.valueOf(true)); } } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/opf/ValidationContext.java0000644000175000017500000002300313017276730026257 0ustar eugeneeugenepackage com.adobe.epubcheck.opf; import static com.google.common.base.Preconditions.checkNotNull; import java.util.Set; import com.adobe.epubcheck.api.EPUBProfile; import com.adobe.epubcheck.api.FeatureReport; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.ocf.OCFPackage; import com.adobe.epubcheck.util.EPUBVersion; import com.adobe.epubcheck.util.GenericResourceProvider; import com.adobe.epubcheck.vocab.Property; import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.base.Predicate; import com.google.common.base.Strings; import com.google.common.collect.ImmutableSet; /** * Holds various contextual objects used during validation. This validation * context is used by both {@link ContentChecker} and {@link DocumentValidator} * instances. * */ public final class ValidationContext { /** * The path to the validated resource. Guaranteed non-null. */ public final String path; /** * The media type of the validated resource. Guaranteed non-null. */ public final String mimeType; /** * The EPUB version being used for validation. Guaranteed non-null. */ public final EPUBVersion version; /** * The validation profile in use (e.g. DEFAULT, EDUPUB, etc.). Guaranteed * non-null. */ public final EPUBProfile profile; /** * The report object used to log validation messages. Guaranteed non-null. */ public final Report report; /** * Used to report some features of the validated resource, without logging. * Guaranteed non-null. */ public final FeatureReport featureReport; /** * Used to open resource streams. Guaranteed non-null. */ public final GenericResourceProvider resourceProvider; /** * The OCF Package the resource being validated belongs to. Is absent for * single-file validations. */ public final Optional ocf; /** * The cross-reference checker, absent for single-file validation. */ public final Optional xrefChecker; /** * The set of 'dc:type' values declared at the OPF level. Guaranteed non-null, * can be empty. */ public final Set pubTypes; /** * The set of properties associated to the resource being validated. */ public final Set properties; private ValidationContext(String path, String mimeType, EPUBVersion version, EPUBProfile profile, Report report, FeatureReport featureReport, GenericResourceProvider resourceProvider, Optional ocf, Optional xrefChecker, Set pubTypes, Set properties) { super(); this.path = path; this.mimeType = mimeType; this.version = version; this.profile = profile; this.report = report; this.featureReport = featureReport; this.resourceProvider = resourceProvider; this.ocf = ocf; this.xrefChecker = xrefChecker; this.pubTypes = pubTypes; this.properties = properties; } /** * Builds a new {@link ValidationContext} from various member objects or by * copying a parent context. * */ public static final class ValidationContextBuilder { private String path = null; private String mimeType = null; private EPUBVersion version = null; private EPUBProfile profile = null; private Report report = null; private FeatureReport featureReport = null; private GenericResourceProvider resourceProvider = null; private OCFPackage ocf = null; private XRefChecker xrefChecker = null; private Set pubTypes = null; private ImmutableSet.Builder properties = ImmutableSet. builder(); public ValidationContextBuilder() { } public ValidationContextBuilder(ValidationContext context) { copy(context); } public ValidationContextBuilder copy(ValidationContext context) { path = context.path; mimeType = context.mimeType; version = context.version; profile = context.profile; report = context.report; featureReport = context.featureReport; resourceProvider = context.resourceProvider; ocf = context.ocf.orNull(); xrefChecker = context.xrefChecker.orNull(); pubTypes = context.pubTypes; properties = ImmutableSet. builder().addAll(context.properties); return this; } public ValidationContextBuilder path(String path) { this.path = path; return this; } public ValidationContextBuilder mimetype(String mimetype) { this.mimeType = mimetype; return this; } public ValidationContextBuilder version(EPUBVersion version) { this.version = version; return this; } public ValidationContextBuilder profile(EPUBProfile profile) { this.profile = profile; return this; } public ValidationContextBuilder report(Report report) { this.report = report; return this; } public ValidationContextBuilder featureReport(FeatureReport featureReport) { this.featureReport = featureReport; return this; } public ValidationContextBuilder resourceProvider(GenericResourceProvider resourceProvider) { this.resourceProvider = resourceProvider; return this; } public ValidationContextBuilder ocf(OCFPackage ocf) { this.ocf = ocf; return this; } public ValidationContextBuilder xrefChecker(XRefChecker xrefChecker) { this.xrefChecker = xrefChecker; return this; } public ValidationContextBuilder pubTypes(Set pubTypes) { this.pubTypes = pubTypes; return this; } public ValidationContextBuilder properties(Set properties) { this.properties = ImmutableSet.builder(); if (properties != null) { this.properties.addAll(properties); } return this; } public ValidationContextBuilder addProperty(Property property) { properties.add(Preconditions.checkNotNull(property)); return this; } public ValidationContext build() { resourceProvider = (resourceProvider == null && ocf != null) ? ocf : resourceProvider; checkNotNull(resourceProvider); checkNotNull(report); return new ValidationContext(Strings.nullToEmpty(path), Strings.nullToEmpty(mimeType), version != null ? version : EPUBVersion.Unknown, profile != null ? profile : EPUBProfile.DEFAULT, report, featureReport != null ? featureReport : new FeatureReport(), resourceProvider, Optional.fromNullable(ocf), Optional.fromNullable(xrefChecker), pubTypes != null ? ImmutableSet.copyOf(pubTypes) : ImmutableSet. of(), properties.build()); } } /** * Utility to create {@link Predicate}s applying to {@link ValidationContext} * instances. * */ public static final class ValidationContextPredicates { /** * Returns a predicate that evaluates to true if the given * property is declared in the context being tested. */ public static Predicate hasProp(final Property property) { return new Predicate() { @Override public boolean apply(ValidationContext input) { return input.properties.contains(property); } }; } /** * Returns a predicate that evaluates to true if the given * publication dc:type is declared in the context being tested. */ public static Predicate hasPubType(final String type) { return new Predicate() { @Override public boolean apply(ValidationContext input) { return input.pubTypes.contains(type); } }; } /** * Returns a predicate that evaluates to true if the context * being tested has the given media type. */ public static Predicate mimetype(final String mimetype) { return new Predicate() { @Override public boolean apply(ValidationContext input) { return input.mimeType.equals(mimetype); } }; } /** * Returns a predicate that evaluates to true if the context * being tested has the given path. */ public static Predicate path(final String path) { return new Predicate() { @Override public boolean apply(ValidationContext input) { return input.path.equals(path); } }; } /** * Returns a predicate that evaluates to true if the context * being tested declares the given validation profile. */ public static Predicate profile(final EPUBProfile profile) { return new Predicate() { @Override public boolean apply(ValidationContext input) { return input.profile.equals(profile); } }; } /** * Returns a predicate that evaluates to true if the context * being tested declares the given EPUB version. */ public static Predicate version(final EPUBVersion version) { return new Predicate() { @Override public boolean apply(ValidationContext input) { return input.version.equals(version); } }; } private ValidationContextPredicates() { } } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/opf/ContentCheckerFactory.java0000755000175000017500000000241013017276730027051 0ustar eugeneeugene/* * Copyright (c) 2007 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.opf; public interface ContentCheckerFactory { public ContentChecker newInstance(ValidationContext context); } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/opf/VersionRetriever.java0000644000175000017500000001366113017276730026146 0ustar eugeneeugene/* * Copyright (c) 2011 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.opf; import java.io.IOException; import java.io.InputStream; import java.io.StringReader; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.xml.sax.Attributes; import org.xml.sax.EntityResolver; import org.xml.sax.ErrorHandler; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; import org.xml.sax.helpers.DefaultHandler; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.messages.MessageId; import com.adobe.epubcheck.util.EPUBVersion; import com.adobe.epubcheck.util.FeatureEnum; import com.adobe.epubcheck.util.InvalidVersionException; public class VersionRetriever implements EntityResolver, ErrorHandler { private static final String VERSION_3 = "3.0"; private static final String VERSION_2 = "2.0"; private final Report report; private final String path; public VersionRetriever(String path, Report report) { this.path = path; this.report = report; } public EPUBVersion retrieveOpfVersion(InputStream inputStream) throws InvalidVersionException { SAXParserFactory factory = SAXParserFactory.newInstance(); factory.setNamespaceAware(true); factory.setValidating(false); try { factory.setFeature("http://xml.org/sax/features/validation", false); factory.setFeature("http://xml.org/sax/features/external-general-entities", false); factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false); } catch (Exception ignored) { } SAXParser parser; try { parser = factory.newSAXParser(); parser.getXMLReader().setEntityResolver(this); parser.getXMLReader().setErrorHandler(this); parser.getXMLReader().setContentHandler(new OPFhandler()); parser.getXMLReader().parse(new InputSource(inputStream)); } catch (ParserConfigurationException e) { report.message(MessageId.RSC_005, EPUBLocation.create(path), e.getMessage()); } catch (SAXException e) { if (VERSION_3.equals(e.getMessage())) { report.info(null, FeatureEnum.FORMAT_VERSION, EPUBVersion.VERSION_3.toString()); return EPUBVersion.VERSION_3; } else if (VERSION_2.equals(e.getMessage())) { report.info(null, FeatureEnum.FORMAT_VERSION, EPUBVersion.VERSION_2.toString()); return EPUBVersion.VERSION_2; } else if (InvalidVersionException.UNSUPPORTED_VERSION.equals(e.getMessage())) { throw new InvalidVersionException(InvalidVersionException.UNSUPPORTED_VERSION); } else if (InvalidVersionException.VERSION_ATTRIBUTE_NOT_FOUND.equals(e.getMessage())) { throw new InvalidVersionException(InvalidVersionException.VERSION_ATTRIBUTE_NOT_FOUND); } else if (InvalidVersionException.PACKAGE_ELEMENT_NOT_FOUND.equals(e.getMessage())) { throw new InvalidVersionException(InvalidVersionException.PACKAGE_ELEMENT_NOT_FOUND); } else { report.message(MessageId.RSC_005, EPUBLocation.create(path), e.getMessage()); } } catch (IOException e) { report.message(MessageId.PKG_008, EPUBLocation.create(path), path); } throw new InvalidVersionException(InvalidVersionException.VERSION_NOT_FOUND); } @Override public InputSource resolveEntity(String arg0, String arg1) throws SAXException, IOException { return new InputSource(new StringReader("")); } @Override public void error(SAXParseException arg0) throws SAXException { } @Override public void fatalError(SAXParseException arg0) throws SAXException { } @Override public void warning(SAXParseException arg0) throws SAXException { } private class OPFhandler extends DefaultHandler { @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if ("package".equals(localName)) { processPackage(attributes); } else { throw new SAXException( InvalidVersionException.PACKAGE_ELEMENT_NOT_FOUND); } } private void processPackage(Attributes attributes) throws SAXException { String version = attributes.getValue("version"); if (version == null) { throw new SAXException( InvalidVersionException.VERSION_ATTRIBUTE_NOT_FOUND); } else if (VERSION_3.equals(version)) { throw new SAXException(VERSION_3); } else if (VERSION_2.equals(version)) { throw new SAXException(VERSION_2); } throw new SAXException(InvalidVersionException.UNSUPPORTED_VERSION); } } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/opf/DocumentValidatorFactory.java0000644000175000017500000000320213017276730027573 0ustar eugeneeugene/* * Copyright (c) 2011 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.opf; import com.adobe.epubcheck.api.EPUBProfile; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.util.EPUBVersion; import com.adobe.epubcheck.util.GenericResourceProvider; public interface DocumentValidatorFactory { public DocumentValidator newInstance(ValidationContext context); // public DocumentValidator newInstance(Report report, String path, // GenericResourceProvider resourceProvider, String mimeType, // EPUBVersion version, EPUBProfile profile); } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/api/0000755000175000017500000000000013017276730021744 5ustar eugeneeugeneepubcheck-4.0.2/src/main/java/com/adobe/epubcheck/api/QuietReport.java0000644000175000017500000000111313017276730025066 0ustar eugeneeugenepackage com.adobe.epubcheck.api; import com.adobe.epubcheck.messages.Message; import com.adobe.epubcheck.util.FeatureEnum; public final class QuietReport extends MasterReport { public static final Report INSTANCE = new QuietReport(); private QuietReport() { super(); } @Override public void message(Message message, EPUBLocation location, Object... args) { } @Override public void info(String resource, FeatureEnum feature, String value) { } @Override public int generate() { return 0; } @Override public void initialize() { } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/api/EpubCheckFactory.java0000644000175000017500000000412513017276730025772 0ustar eugeneeugene/* * Copyright (c) 2011 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.api; import java.io.File; import java.io.IOException; import com.adobe.epubcheck.opf.DocumentValidator; import com.adobe.epubcheck.opf.DocumentValidatorFactory; import com.adobe.epubcheck.opf.ValidationContext; public class EpubCheckFactory implements DocumentValidatorFactory { static private final EpubCheckFactory instance = new EpubCheckFactory(); static public EpubCheckFactory getInstance() { return instance; } public DocumentValidator newInstance(ValidationContext context) { if (context.path.startsWith("http://") || context.path.startsWith("https://")) { try { return new EpubCheck(context.resourceProvider.getInputStream(context.path), context.report, context.path, context.profile); } catch (IOException e) { throw new RuntimeException(e); } } else { return new EpubCheck(new File(context.path), context.report, context.profile); } } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/api/MasterReport.java0000644000175000017500000000610113017276730025234 0ustar eugeneeugenepackage com.adobe.epubcheck.api; import java.io.File; import java.util.HashSet; import java.util.Set; import org.codehaus.jackson.annotate.JsonProperty; import com.adobe.epubcheck.messages.Message; import com.adobe.epubcheck.messages.MessageDictionary; import com.adobe.epubcheck.messages.MessageId; import com.adobe.epubcheck.messages.Severity; import com.adobe.epubcheck.util.ReportingLevel; /** * Reports are derived from this so that we can test for message Id coverage as well as have a centralized location for * severity reporting level testing. */ public abstract class MasterReport implements Report { public static Set allReportedMessageIds = new HashSet(); int errorCount, warningCount, fatalErrorCount, usageCount = 0; int reportingLevel = ReportingLevel.Info; private String ePubName; private MessageDictionary dictionary = new MessageDictionary(null, this); @Override public MessageDictionary getDictionary() { return dictionary; } protected MasterReport() { } @Override public void setOverrideFile(File overrideFile) { getDictionary().setOverrideFile(overrideFile); } @JsonProperty String customMessageFileName = null; private void reportMessageId(MessageId id) { allReportedMessageIds.add(id); } @Override public void message(MessageId id, EPUBLocation location, Object... args) { Message message = getDictionary().getMessage(id); assert (message != null); Severity severity = message.getSeverity(); if (ReportingLevel.getReportingLevel(severity) >= getReportingLevel()) { if (severity.equals(Severity.ERROR)) { errorCount++; } else if (severity.equals(Severity.WARNING)) { warningCount++; } else if (severity.equals(Severity.FATAL)) { fatalErrorCount++; } else if (severity.equals(Severity.USAGE)) { usageCount++; } this.message(message, location, args); } reportMessageId(id); } @Override public void setCustomMessageFile(String customMessageFileName) { this.customMessageFileName = customMessageFileName; } @Override public String getCustomMessageFile() { return this.customMessageFileName; } @Override public int getReportingLevel() { return reportingLevel; } @Override public void setReportingLevel(int reportingLevel) { if (reportingLevel >= ReportingLevel.Usage && reportingLevel <= ReportingLevel.Fatal) { this.reportingLevel = reportingLevel; } else { System.err.printf("Attempted to set invalid reporting level: %1d", reportingLevel); } } @Override public String getEpubFileName() { return this.ePubName; } @Override public void setEpubFileName(String value) { this.ePubName = value; } @Override public int getErrorCount() { return errorCount; } @Override public int getWarningCount() { return warningCount; } @Override public int getFatalErrorCount() { return fatalErrorCount; } @Override public void close() { } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/api/EpubCheck.java0000644000175000017500000002100613017276730024437 0ustar eugeneeugene/* * Copyright (c) 2007 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.api; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.util.Properties; import java.util.zip.ZipFile; import com.adobe.epubcheck.ctc.CheckManager; import com.adobe.epubcheck.messages.MessageId; import com.adobe.epubcheck.ocf.OCFChecker; import com.adobe.epubcheck.ocf.OCFPackage; import com.adobe.epubcheck.ocf.OCFZipPackage; import com.adobe.epubcheck.opf.DocumentValidator; import com.adobe.epubcheck.opf.ValidationContext.ValidationContextBuilder; import com.adobe.epubcheck.util.CheckUtil; import com.adobe.epubcheck.util.DefaultReportImpl; import com.adobe.epubcheck.util.ResourceUtil; import com.adobe.epubcheck.util.WriterReportImpl; /** * Public interface to epub validator. */ public class EpubCheck implements DocumentValidator { private static String VERSION = null; private static String BUILD_DATE = null; final private File epubFile; final private EPUBProfile profile; final private Report report; public static String version() { if (VERSION == null) { Properties prop = new Properties(); InputStream in = EpubCheck.class.getResourceAsStream("project.properties"); try { prop.load(in); } catch (Exception e) { System.err.println("Couldn't read project properties: " + e.getMessage()); } finally { if (in != null) { try { in.close(); } catch (IOException ignored) { } } } VERSION = prop.getProperty("version"); BUILD_DATE = prop.getProperty("buildDate"); } return VERSION; } public static String buildDate() { return BUILD_DATE; } /** * Create an epub validator to validate the given file. Issues will be * reported to standard error. */ public EpubCheck(File epubFile) { this(epubFile, new DefaultReportImpl(epubFile.getName())); } /** * Create an epub validator to validate the given file. Issues will be * reported to the given PrintWriter. */ public EpubCheck(File epubFile, PrintWriter out) { this(epubFile, new WriterReportImpl(out)); } /** * Create an epub validator to validate the given file and report issues to a * given Report object. */ public EpubCheck(File epubFile, Report report) { this(epubFile, report, null); } /** * Create an epub validator to validate the given file and report issues to a * given Report object. Can validate a specific EPUB profile (e.g. EDUPUB, * DICT, IDX, etc). * */ public EpubCheck(File epubFile, Report report, EPUBProfile profile) { this.epubFile = epubFile; this.report = report; this.profile = profile == null ? EPUBProfile.DEFAULT : profile; } public EpubCheck(InputStream inputStream, Report report, String uri) { this(inputStream, report, uri, EPUBProfile.DEFAULT); } public EpubCheck(InputStream inputStream, Report report, String uri, EPUBProfile profile) { File epubFile; OutputStream out = null; try { epubFile = File.createTempFile("epub", "." + ResourceUtil.getExtension(uri)); epubFile.deleteOnExit(); out = new FileOutputStream(epubFile); byte[] bytes = new byte[1024]; int read; while ((read = inputStream.read(bytes)) != -1) { out.write(bytes, 0, read); } this.epubFile = epubFile; this.profile = profile == null ? EPUBProfile.DEFAULT : profile; this.report = report; } catch (IOException e) { throw new RuntimeException(e); } finally { if (inputStream != null) { try { inputStream.close(); } catch (IOException ignored) { } } if (out != null) { try { out.flush(); out.close(); } catch (IOException ignored) { } } } } /** * Validate the file. Return true if no errors or warnings found. */ public boolean validate() { int validateResult = doValidate(); return validateResult == 0; } public int doValidate() { ZipFile zip = null; FileInputStream epubIn = null; try { String extension = ResourceUtil.getExtension(epubFile.getName()); checkExtension(extension); if (!epubFile.exists()) { report.message(MessageId.PKG_018, EPUBLocation.create(epubFile.getName())); return 2; } epubIn = new FileInputStream(epubFile); checkEpubHeader(epubIn); zip = new ZipFile(epubFile); OCFPackage ocf = new OCFZipPackage(zip); OCFChecker checker = new OCFChecker(new ValidationContextBuilder().ocf(ocf).report(report) .profile(profile).build()); checker.runChecks(); /*** Here are called custom checks (CTC Package) **/ CheckManager c = new CheckManager(zip, report); c.checkPackage(); } catch (IOException e) { report.message(MessageId.PKG_008, EPUBLocation.create(epubFile.getName(), ""), e.getMessage()); } finally { try { if (epubIn != null) { epubIn.close(); } if (zip != null) { zip.close(); } } catch (IOException ignored) { } } int returnValue = 0; if (report.getFatalErrorCount() != 0) returnValue |= 4; if (report.getErrorCount() != 0) returnValue |= 2; if (report.getWarningCount() != 0) returnValue |= 1; return returnValue; } void checkExtension(String extension) { if (extension != null) { if (!extension.equals("epub")) { if (extension.matches("[Ee][Pp][Uu][Bb]")) { report.message(MessageId.PKG_016, EPUBLocation.create(epubFile.getName())); } else { report.message(MessageId.PKG_017, EPUBLocation.create(epubFile.getName(), extension)); } } } } void checkEpubHeader(FileInputStream epubIn) throws IOException { byte[] header = new byte[58]; int readCount = epubIn.read(header); if (readCount != -1) { while (readCount < header.length) { int read = epubIn.read(header, readCount, header.length - readCount); // break on eof if (read == -1) { break; } readCount += read; } } if (readCount != header.length) { report.message(MessageId.PKG_003, EPUBLocation.create(epubFile.getName(), "")); } else { int fnsize = getIntFromBytes(header, 26); int extsize = getIntFromBytes(header, 28); if (header[0] != 'P' && header[1] != 'K') { report.message(MessageId.PKG_004, EPUBLocation.create(epubFile.getName())); } else if (fnsize != 8) { report.message(MessageId.PKG_006, EPUBLocation.create(epubFile.getName())); } else if (extsize != 0) { report.message(MessageId.PKG_005, EPUBLocation.create(epubFile.getName()), extsize); } else if (!CheckUtil.checkString(header, 30, "mimetype")) { report.message(MessageId.PKG_006, EPUBLocation.create(epubFile.getName())); } } } private int getIntFromBytes(byte[] bytes, int offset) { int hi = 0xFF & bytes[offset + 1]; int lo = 0xFF & bytes[offset]; return hi << 8 | lo; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/api/EPUBLocation.java0000644000175000017500000000566113017276730025043 0ustar eugeneeugenepackage com.adobe.epubcheck.api; import org.codehaus.jackson.annotate.JsonProperty; import org.codehaus.jackson.map.annotate.JsonSerialize; import com.adobe.epubcheck.util.JsonWriter; import com.google.common.base.Optional; import com.google.common.base.Preconditions; public final class EPUBLocation implements Comparable { public static EPUBLocation create(String fileName) { return new EPUBLocation(fileName, -1, -1, null); } public static EPUBLocation create(String fileName, String context) { return new EPUBLocation(fileName, -1, -1, context); } public static EPUBLocation create(String fileName, int lineNumber, int column) { return new EPUBLocation(fileName, lineNumber, column, null); } public static EPUBLocation create(String fileName, int lineNumber, int column, String context) { return new EPUBLocation(fileName, lineNumber, column, context); } @JsonProperty private final String path; @JsonProperty private final int line; @JsonProperty private final int column; @JsonProperty @JsonSerialize(using = JsonWriter.OptionalJsonSerializer.class) private final Optional context; private EPUBLocation(String path, int lineNumber, int column, String context) { Preconditions.checkNotNull(path); this.path = path; this.line = lineNumber; this.column = column; this.context = Optional.fromNullable(context); } public String getPath() { return this.path; } public int getLine() { return this.line; } public int getColumn() { return this.column; } public Optional getContext() { return this.context; } @Override public String toString() { return path + "[" + line + "," + column + "]"; } @Override public boolean equals(Object obj) { if (obj == this) { return true; } if (obj == null || obj.getClass() != this.getClass()) { return false; } EPUBLocation other = (EPUBLocation) obj; return !(this.getContext() == null && other.getContext() != null) && this.getPath().equals(other.getPath()) && this.getLine() == other.getLine() && this.getColumn() == other.getColumn() && (this.getContext() == null || this.getContext().equals(other.getContext())); } int safeCompare(String a, String b) { if (a == null && b != null) return -1; if (a != null && b == null) return 1; if (a == null /* && b == null */) return 0; return a.compareTo(b); } @Override public int compareTo(EPUBLocation o) { int comp = safeCompare(this.path, o.path); if (comp != 0) { return comp; } comp = line - o.line; if (comp != 0) { return comp < 0 ? -1 : 1; } comp = column - o.column; if (comp != 0) { return comp < 0 ? -1 : 1; } comp = safeCompare(context.orNull(), o.context.orNull()); if (comp != 0) { return comp; } return 0; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/api/Report.java0000755000175000017500000000631013017276730024065 0ustar eugeneeugene/* * Copyright (c) 2007 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.api; import com.adobe.epubcheck.messages.Message; import com.adobe.epubcheck.messages.MessageDictionary; import com.adobe.epubcheck.messages.MessageId; import com.adobe.epubcheck.util.FeatureEnum; import java.io.File; /** * Interface that is used to report issues found in epub. */ public interface Report { /** * Called when a violation of the standard is found in epub. * * @param id Id of the message being reported * @param location location information for the message * @param args Arguments referenced by the format * string for the message. */ public void message(MessageId id, EPUBLocation location, Object... args); /** * Called when a violation of the standard is found in epub. * * @param message The message being reported * @param location location information for the message * @param args Arguments referenced by the format * string for the message. */ void message(Message message, EPUBLocation location, Object... args); /** * Called when when a feature is found in epub. * * @param resource name of the resource in the epub zip container that has this feature * or null if the feature is on the container level. * @param feature a keyword to know what kind of feature has been found * @param value value found */ public void info(String resource, FeatureEnum feature, String value); public int getErrorCount(); public int getWarningCount(); public int getFatalErrorCount(); /** * Called to create a report after the checks have been made */ public int generate(); /** * Called when a report if first created */ public void initialize(); public void setEpubFileName(String value); public String getEpubFileName(); void setCustomMessageFile(String customMessageFileName); String getCustomMessageFile(); public int getReportingLevel(); public void setReportingLevel(int level); void close(); void setOverrideFile(File customMessageFile); MessageDictionary getDictionary(); } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/api/FeatureReport.java0000644000175000017500000000710613017276730025402 0ustar eugeneeugenepackage com.adobe.epubcheck.api; import java.util.Set; import com.adobe.epubcheck.util.FeatureEnum; import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.base.Strings; import com.google.common.collect.ImmutableSet; import com.google.common.collect.LinkedHashMultimap; import com.google.common.collect.Multimaps; import com.google.common.collect.SetMultimap; /** * A feature report holds a list of noteworthy EPUB features. Features are * typically reported by handlers at parsing time. The report can be looked-up * after the parsing phase to enable checks that depend on conditions spanning * over multiple documents. * */ public final class FeatureReport { private final SetMultimap features = Multimaps .synchronizedSetMultimap(LinkedHashMultimap. create()); /** * Add a new feature to this report. * * @param name * The name of the feature (must not be null) * @param path * The location of the feature (can be null) */ public void report(FeatureEnum name, EPUBLocation location) { features.put(name, new Feature(name, location, null)); } /** * Add a new feature to this report. * * @param name * The name of the feature (must not be null) * @param path * The location of the feature (can be null) * @param value * The value of the feature (can be null) */ public void report(FeatureEnum name, EPUBLocation location, String value) { features.put(name, new Feature(name, location, value)); } /** * Returns true iff this reports contains data for a feature * name. * * @param feature * the feature name to look-up * @return true iff this reports contains data for a feature * name. */ public boolean hasFeature(FeatureEnum feature) { return features.containsKey(feature); } /** * Returns the set of {@link Feature} stored in this report for the given * feature name. * * @param feature * the feature name to look-up * @return the (possibly empty) set of {@link Feature} stored in this report * for the given feature name. */ public Set getFeature(FeatureEnum feature) { return ImmutableSet.copyOf(features.get(feature)); } /** * A noteworthy feature in an EPUB Rendition (e.g. presence of page breaks, * encryption, subject, etc.) */ public static final class Feature { private FeatureEnum name; private Optional location; private Optional value; private Feature(FeatureEnum name, EPUBLocation location, String value) { Preconditions.checkNotNull(name); Preconditions.checkNotNull(location); this.name = name; this.location = Optional.fromNullable(location); this.value = Optional.fromNullable(Strings.emptyToNull(value)); } /** * The name of the feature * * @return the name of the feature */ public FeatureEnum getName() { return name; } /** * The location of the feature. * * @return the path to the document containing the feature (can be absent). */ public Optional getLocation() { return location; } /** * The value of the feature, when relevant (can be absent). * * @return the value of the feature if it has one, or * {@link Optional#absent()}. */ public Optional getValue() { return value; } } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/api/EPUBProfile.java0000644000175000017500000000455713017276730024676 0ustar eugeneeugenepackage com.adobe.epubcheck.api; import java.util.Set; import com.adobe.epubcheck.messages.MessageId; import com.adobe.epubcheck.opf.OPFData; import com.google.common.collect.ImmutableSet; public enum EPUBProfile { DEFAULT, IDX, DICT, EDUPUB, PREVIEW; /** * Checks a given validation profile against the dc:type(s) declared in an OPF * and returns a possibly overriden profile. *

* For instance, if the publication has a 'edupub' dc:type and the DEFAULT * validation profile is given, the EDUPUB profile will be returned instead. *

*

* If the given validation profile is modified, report an INFO message * OPF_064. *

* * @param profile * a validation profile. * @param opfData * the parsed OPF data (contains the publication's dc:type(s)). * @param path * the path to use for reporting messages. * @param report * the message report. * @return The given profile if it's compatible with the OPF dc:type(s), or * else a compatible non-null validation profile. */ public static EPUBProfile makeOPFCompatible(EPUBProfile profile, OPFData opfData, String path, Report report) { Set pubTypes = opfData != null ? opfData.getTypes() : ImmutableSet. of(); if (pubTypes.contains(OPFData.DC_TYPE_DICT) && profile != EPUBProfile.DICT) { report.message(MessageId.OPF_064, EPUBLocation.create(path), OPFData.DC_TYPE_DICT, EPUBProfile.DICT); return EPUBProfile.DICT; } else if (pubTypes.contains(OPFData.DC_TYPE_EDUPUB) && profile != EPUBProfile.EDUPUB) { report.message(MessageId.OPF_064, EPUBLocation.create(path), OPFData.DC_TYPE_EDUPUB, EPUBProfile.EDUPUB); return EPUBProfile.EDUPUB; } else if (pubTypes.contains(OPFData.DC_TYPE_INDEX) && profile != EPUBProfile.IDX) { report.message(MessageId.OPF_064, EPUBLocation.create(path), OPFData.DC_TYPE_INDEX, EPUBProfile.IDX); return EPUBProfile.IDX; } else if (pubTypes.contains(OPFData.DC_TYPE_PREVIEW) && profile != EPUBProfile.PREVIEW) { report.message(MessageId.OPF_064, EPUBLocation.create(path), OPFData.DC_TYPE_PREVIEW, EPUBProfile.PREVIEW); return EPUBProfile.PREVIEW; } else { return profile != null ? profile : EPUBProfile.DEFAULT; } } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ops/0000755000175000017500000000000013017276730021774 5ustar eugeneeugeneepubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ops/OPSHandler30.java0000644000175000017500000005301413017276730024744 0ustar eugeneeugenepackage com.adobe.epubcheck.ops; import java.util.Collections; import java.util.EnumSet; import java.util.HashSet; import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.api.EPUBProfile; import com.adobe.epubcheck.messages.MessageId; import com.adobe.epubcheck.opf.OPFChecker; import com.adobe.epubcheck.opf.OPFChecker30; import com.adobe.epubcheck.opf.ValidationContext; import com.adobe.epubcheck.opf.XRefChecker; import com.adobe.epubcheck.util.EpubConstants; import com.adobe.epubcheck.util.FeatureEnum; import com.adobe.epubcheck.util.PathUtil; import com.adobe.epubcheck.vocab.AggregateVocab; import com.adobe.epubcheck.vocab.AltStylesheetVocab; import com.adobe.epubcheck.vocab.ComicsVocab; import com.adobe.epubcheck.vocab.DataNavVocab; import com.adobe.epubcheck.vocab.DictVocab; import com.adobe.epubcheck.vocab.EnumVocab; import com.adobe.epubcheck.vocab.EpubCheckVocab; import com.adobe.epubcheck.vocab.IndexVocab; import com.adobe.epubcheck.vocab.PackageVocabs; import com.adobe.epubcheck.vocab.PackageVocabs.ITEM_PROPERTIES; import com.adobe.epubcheck.vocab.Property; import com.adobe.epubcheck.vocab.StagingEdupubVocab; import com.adobe.epubcheck.vocab.StructureVocab; import com.adobe.epubcheck.vocab.StructureVocab.EPUB_TYPES; import com.adobe.epubcheck.vocab.Vocab; import com.adobe.epubcheck.vocab.VocabUtil; import com.adobe.epubcheck.xml.XMLAttribute; import com.adobe.epubcheck.xml.XMLElement; import com.adobe.epubcheck.xml.XMLParser; import com.google.common.base.Joiner; import com.google.common.base.Strings; import com.google.common.collect.Collections2; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; public class OPSHandler30 extends OPSHandler { private static final Pattern DATA_URI_PATTERN = Pattern.compile("^data:([^;]*)[^,]*,.*"); private static Map RESERVED_VOCABS = ImmutableMap. of("", AggregateVocab.of(StructureVocab.VOCAB, StagingEdupubVocab.VOCAB, DataNavVocab.VOCAB, DictVocab.VOCAB, IndexVocab.VOCAB, ComicsVocab.VOCAB)); private static Map ALTCSS_VOCABS = ImmutableMap. of("", AltStylesheetVocab.VOCAB); private static Map KNOWN_VOCAB_URIS = ImmutableMap.of(); private static Set DEFAULT_VOCAB_URIS = ImmutableSet.of(StructureVocab.URI); private Map vocabs = RESERVED_VOCABS; private final Set requiredProperties = EnumSet.noneOf(ITEM_PROPERTIES.class); private final Set allowedProperties = EnumSet.noneOf(ITEM_PROPERTIES.class); private final boolean isLinear; protected boolean inVideo = false; protected boolean inAudio = false; protected boolean hasValidFallback = false; protected int imbricatedObjects = 0; protected int imbricatedCanvases = 0; protected boolean anchorNeedsText = false; protected boolean inMathML = false; protected boolean inSvg = false; protected boolean inBody = false; protected boolean inRegionBasedNav = false; protected boolean hasAltorAnnotation = false; protected boolean hasTitle = false; static protected final String[] scriptEventsStrings = { "onafterprint", "onbeforeprint", "onbeforeunload", "onerror", "onhaschange", "onload", "onmessage", "onoffline", "onpagehide", "onpageshow", "onpopstate", "onredo", "onresize", "onstorage", "onundo", "onunload", "onblur", "onchange", "oncontextmenu", "onfocus", "onformchange", "onforminput", "oninput", "oninvalid", "onreset", "onselect", "onsubmit", "onkeydown", "onkeypress", "onkeyup", "onabort", "oncanplay", "oncanplaythrough", "ondurationchange", "onemptied", "onended", "onerror", "onloadeddata", "onloadedmetadata", "onloadstart", "onpause", "onplay", "onplaying", "onprogress", "onratechange", "onreadystatechange", "onseeked", "onseeking", "onstalled", "onsuspend", "ontimeupdate", "onvolumechange", "onwaiting" }; static protected HashSet scriptEvents; public static HashSet getScriptEvents() { if (scriptEvents == null) { scriptEvents = new HashSet(); Collections.addAll(scriptEvents, scriptEventsStrings); Collections.addAll(scriptEvents, mouseEventsStrings); } return scriptEvents; } static protected final String[] mouseEventsStrings = { "onclick", "ondblclick", "ondrag", "ondragend", "ondragenter", "ondragleave", "ondragover", "ondragstart", "ondrop", "onmousedown", "onmousemove", "onmouseout", "onmouseover", "onmouseup", "onmousewheel", "onscroll" }; static protected HashSet mouseEvents; public static HashSet getMouseEvents() { if (mouseEvents == null) { mouseEvents = new HashSet(); Collections.addAll(mouseEvents, mouseEventsStrings); } return mouseEvents; } public OPSHandler30(ValidationContext context, XMLParser parser) { super(context, parser); checkedUnsupportedXMLVersion = false; isLinear = !context.properties .contains(EpubCheckVocab.VOCAB.get(EpubCheckVocab.PROPERTIES.NON_LINEAR)); } protected void checkType(XMLElement e, String type) { if (type == null) { return; } Set propList = VocabUtil.parsePropertyList(type, vocabs, report, EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber())); checkTypes(Property.filter(propList, StructureVocab.EPUB_TYPES.class)); // Check the 'region-based' property (Data Navigation Documents) if (propList.contains(DataNavVocab.VOCAB.get(DataNavVocab.EPUB_TYPES.REGION_BASED))) { if (!"nav".equals(e.getName()) || !context.properties .contains(PackageVocabs.ITEM_VOCAB.get(PackageVocabs.ITEM_PROPERTIES.DATA_NAV))) { report.message(MessageId.HTM_052, parser.getLocation()); } else { inRegionBasedNav = true; } } // Store whether the doc containt DICT content if (propList.contains(DictVocab.VOCAB.get(DictVocab.EPUB_TYPES.DICTIONARY))) { context.featureReport.report(FeatureEnum.DICTIONARY, parser.getLocation(), null); } } protected void checkTypes(Set types) { if (types.contains(EPUB_TYPES.PAGEBREAK)) { context.featureReport.report(FeatureEnum.PAGE_BREAK, parser.getLocation(), null); } if (types.contains(EPUB_TYPES.INDEX)) { allowedProperties.add(ITEM_PROPERTIES.INDEX); context.featureReport.report(FeatureEnum.INDEX, parser.getLocation(), null); } } protected void checkSSMLPh(String ph) { // issue 139; enhancement is to add real syntax check for IPA and x-SAMPA if (ph == null) { return; } if (ph.trim().length() < 1) { report.message(MessageId.HTM_007, EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber())); } } @Override public void characters(char[] chars, int arg1, int arg2) { super.characters(chars, arg1, arg2); String str = new String(chars, arg1, arg2); str = str.trim(); if (!str.equals("") && (inAudio || inVideo || imbricatedObjects > 0 || imbricatedCanvases > 0)) { hasValidFallback = true; } if (anchorNeedsText) { anchorNeedsText = false; } } public void startElement() { super.startElement(); XMLElement e = parser.getCurrentElement(); String name = e.getName(); processSemantics(e); processSectioning(e); if (name.equals("html")) { vocabs = VocabUtil.parsePrefixDeclaration( e.getAttributeNS(EpubConstants.EpubTypeNamespaceUri, "prefix"), RESERVED_VOCABS, KNOWN_VOCAB_URIS, DEFAULT_VOCAB_URIS, report, EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber())); } else if (name.equals("link")) { processLink(e); } else if (name.equals("object")) { processObject(e); } else if (name.equals("math")) { requiredProperties.add(ITEM_PROPERTIES.MATHML); inMathML = true; hasAltorAnnotation = (null != e.getAttribute("alttext")); } else if (!context.mimeType.equals("image/svg+xml") && name.equals("svg")) { requiredProperties.add(ITEM_PROPERTIES.SVG); processStartSvg(e); } else if (name.equals("script")) { requiredProperties.add(ITEM_PROPERTIES.SCRIPTED); } else if (!context.mimeType.equals("image/svg+xml") && name.equals("switch")) { requiredProperties.add(ITEM_PROPERTIES.SWITCH); } else if (name.equals("audio")) { processAudio(); } else if (name.equals("video")) { processVideo(e); } else if (name.equals("figure")) { processFigure(e); } else if (name.equals("table")) { processTable(e); } else if (name.equals("canvas")) { processCanvas(); } else if (name.equals("img")) { processImg(); } else if (name.equals("a")) { anchorNeedsText = true; processAnchor(e); } else if (name.equals("annotation-xml")) { hasAltorAnnotation = true; } else if ("http://www.w3.org/2000/svg".equals(e.getNamespace()) && name.equals("title")) { hasTitle = true; } processInlineScripts(e); processSrc(("source".equals(name)) ? e.getParent().getName() : name, e.getAttribute("src")); checkType(e, e.getAttributeNS(EpubConstants.EpubTypeNamespaceUri, "type")); checkSSMLPh(e.getAttributeNS("http://www.w3.org/2001/10/synthesis", "ph")); } protected void processInlineScripts(com.adobe.epubcheck.xml.XMLElement e) { HashSet scriptEvents = getScriptEvents(); HashSet mouseEvents = getMouseEvents(); for (int i = 0; i < e.getAttributeCount(); ++i) { XMLAttribute attr = e.getAttribute(i); String name = attr.getName().toLowerCase(Locale.ROOT); if (scriptEvents.contains(name) || mouseEvents.contains(name)) { requiredProperties.add(ITEM_PROPERTIES.SCRIPTED); return; } } } protected void processLink(XMLElement e) { String classAttribute = e.getAttribute("class"); if (classAttribute == null) { return; } Set properties = VocabUtil.parsePropertyList(classAttribute, ALTCSS_VOCABS, report, EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber())); Set altClasses = Property.filter(properties, AltStylesheetVocab.PROPERTIES.class); if (properties.size() == 1) { return; } boolean vertical = altClasses.contains(AltStylesheetVocab.PROPERTIES.VERTICAL); boolean horizontal = altClasses.contains(AltStylesheetVocab.PROPERTIES.HORIZONTAL); boolean day = altClasses.contains(AltStylesheetVocab.PROPERTIES.DAY); boolean night = altClasses.contains(AltStylesheetVocab.PROPERTIES.NIGHT); if (vertical && horizontal || day && night) { report.message(MessageId.CSS_005, EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber()), classAttribute); } } protected void processAnchor(XMLElement e) { if (e.getAttribute("href") == null) { anchorNeedsText = false; } if (inSvg || context.mimeType.equals("image/svg+xml")) { hasTitle = Strings .emptyToNull(e.getAttributeNS(EpubConstants.XLinkNamespaceUri, "title")) != null; } } protected void processImg() { if ((inAudio || inVideo || imbricatedObjects > 0 || imbricatedCanvases > 0)) { hasValidFallback = true; } } protected void processCanvas() { imbricatedCanvases++; } protected void processAudio() { inAudio = true; context.featureReport.report(FeatureEnum.AUDIO, parser.getLocation()); } protected void processVideo(XMLElement e) { inVideo = true; context.featureReport.report(FeatureEnum.VIDEO, parser.getLocation()); String posterSrc = e.getAttribute("poster"); String posterMimeType = null; if (xrefChecker.isPresent() && posterSrc != null) { posterMimeType = xrefChecker.get().getMimeType(PathUtil.resolveRelativeReference(path, posterSrc, base == null ? null : base.toString())); } if (posterMimeType != null && !OPFChecker.isBlessedImageType(posterMimeType)) { report.message(MessageId.MED_001, EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber())); } if (posterSrc != null) { hasValidFallback = true; processSrc(e.getName(), posterSrc); } } protected void processHyperlink(String href) { super.processHyperlink(href); if (inRegionBasedNav && xrefChecker.isPresent()) { xrefChecker.get().registerReference(path, parser.getLineNumber(), parser.getColumnNumber(), href, XRefChecker.Type.REGION_BASED_NAV); } } protected void processSrc(String name, String src) { if (src != null) { src = src.trim(); if (src.equals("")) { report.message(MessageId.HTM_008, EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber(), name)); } } if (src == null || !xrefChecker.isPresent()) { return; } String srcMimeType = null; Matcher matcher = DATA_URI_PATTERN.matcher(src); if (matcher.matches()) { srcMimeType = matcher.group(1); } else { if (src.matches("^[^:/?#]+://.*")) { requiredProperties.add(ITEM_PROPERTIES.REMOTE_RESOURCES); } else { src = PathUtil.resolveRelativeReference(path, src, base == null ? null : base.toString()); } XRefChecker.Type refType; if ("audio".equals(name)) { refType = XRefChecker.Type.AUDIO; } else if ("video".equals(name)) { refType = XRefChecker.Type.VIDEO; } else { refType = XRefChecker.Type.GENERIC; } if (!"img".equals(name)) // img already registered in super class { xrefChecker.get().registerReference(path, parser.getLineNumber(), parser.getColumnNumber(), src, refType); } srcMimeType = xrefChecker.get().getMimeType(src); } if (srcMimeType == null) { return; } if (!context.mimeType.equals("image/svg+xml") && srcMimeType.equals("image/svg+xml")) { allowedProperties.add(ITEM_PROPERTIES.SVG); } if ((inAudio || inVideo || imbricatedObjects > 0 || imbricatedCanvases > 0) && OPFChecker30.isCoreMediaType(srcMimeType) && !name.equals("track")) { hasValidFallback = true; } } protected void processObject(XMLElement e) { imbricatedObjects++; String type = e.getAttribute("type"); String data = e.getAttribute("data"); if (data != null) { processSrc(e.getName(), data); data = PathUtil.resolveRelativeReference(path, data, base == null ? null : base.toString()); } if (type != null && data != null && xrefChecker.isPresent() && !type.equals(xrefChecker.get().getMimeType(data))) { String context = " itemProps = Property.filter(context.properties, ITEM_PROPERTIES.class); for (ITEM_PROPERTIES requiredProperty : Sets.difference(requiredProperties, itemProps)) { report.message(MessageId.OPF_014, EPUBLocation.create(path), EnumVocab.ENUM_TO_NAME.apply(requiredProperty)); } Set uncheckedProperties = Sets.difference(itemProps, requiredProperties) .copyInto(EnumSet.noneOf(ITEM_PROPERTIES.class)); uncheckedProperties.remove(ITEM_PROPERTIES.NAV); uncheckedProperties.remove(ITEM_PROPERTIES.DATA_NAV); uncheckedProperties.remove(ITEM_PROPERTIES.COVER_IMAGE); uncheckedProperties.removeAll(allowedProperties); if (uncheckedProperties.contains(ITEM_PROPERTIES.REMOTE_RESOURCES)) { uncheckedProperties.remove(ITEM_PROPERTIES.REMOTE_RESOURCES); report.message(MessageId.OPF_018, EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber())); } if (!uncheckedProperties.isEmpty()) { report.message(MessageId.OPF_015, EPUBLocation.create(path), Joiner.on(", ") .join(Collections2.transform(uncheckedProperties, EnumVocab.ENUM_TO_NAME))); } } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ops/OPSCheckerFactory.java0000755000175000017500000000324113017276730026120 0ustar eugeneeugene/* * Copyright (c) 2007 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.ops; import com.adobe.epubcheck.opf.ContentCheckerFactory; import com.adobe.epubcheck.opf.DocumentValidatorFactory; import com.adobe.epubcheck.opf.ValidationContext; public class OPSCheckerFactory implements ContentCheckerFactory, DocumentValidatorFactory { public OPSChecker newInstance(ValidationContext context) { return new OPSChecker(context); } static private final OPSCheckerFactory instance = new OPSCheckerFactory(); static public OPSCheckerFactory getInstance() { return instance; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ops/OPSHandler.java0000755000175000017500000003712213017276730024606 0ustar eugeneeugene/* * Copyright (c) 2007 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.ops; import java.net.URI; import java.net.URISyntaxException; import java.util.Locale; import java.util.Stack; import javax.xml.XMLConstants; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.css.CSSCheckerFactory; import com.adobe.epubcheck.messages.MessageId; import com.adobe.epubcheck.opf.OPFChecker; import com.adobe.epubcheck.opf.ValidationContext; import com.adobe.epubcheck.opf.XRefChecker; import com.adobe.epubcheck.util.EPUBVersion; import com.adobe.epubcheck.util.EpubConstants; import com.adobe.epubcheck.util.FeatureEnum; import com.adobe.epubcheck.util.HandlerUtil; import com.adobe.epubcheck.util.PathUtil; import com.adobe.epubcheck.util.URISchemes; import com.adobe.epubcheck.xml.XMLElement; import com.adobe.epubcheck.xml.XMLHandler; import com.adobe.epubcheck.xml.XMLParser; import com.google.common.base.Optional; import com.google.common.base.Preconditions; public class OPSHandler implements XMLHandler { class ElementLocation { int lineNumber; int columnNumber; public ElementLocation(int line, int column) { this.lineNumber = line; this.columnNumber = column; } int getLineNumber() { return lineNumber; } int getColumnNumber() { return columnNumber; } } /** * null unless head/base or xml:base is given */ protected URI base; protected final ValidationContext context; protected final XMLParser parser; protected final String path; protected final Report report; protected final Optional xrefChecker; protected long openElements; protected long charsCount; protected int tableDepth = 0; protected boolean hasTh = false; protected boolean hasThead = false; protected boolean hasCaption = false; protected Optional nonStandardStylesheetLink = Optional.absent(); protected boolean hasCss = false; protected boolean epubTypeInUse = false; protected boolean checkedUnsupportedXMLVersion = false; protected StringBuilder textNode; protected Stack elementLocationStack = new Stack(); public OPSHandler(ValidationContext context, XMLParser parser) { this.context = context; this.path = context.path; this.xrefChecker = context.xrefChecker; this.report = context.report; this.parser = parser; } protected void checkPaint(XMLElement e, String attr) { String paint = e.getAttribute(attr); if (xrefChecker.isPresent() && paint != null && paint.startsWith("url(") && paint.endsWith(")")) { String href = paint.substring(4, paint.length() - 1); href = PathUtil.resolveRelativeReference(path, href, base == null ? null : base.toString()); xrefChecker.get().registerReference(path, parser.getLineNumber(), parser.getColumnNumber(), href, XRefChecker.Type.SVG_PAINT); } } protected void checkImage(XMLElement e, String attrNS, String attr) { String href = e.getAttributeNS(attrNS, attr); if (xrefChecker.isPresent() && href != null) { href = PathUtil.resolveRelativeReference(path, href, base == null ? null : base.toString()); xrefChecker.get().registerReference(path, parser.getLineNumber(), parser.getColumnNumber(), href, XRefChecker.Type.IMAGE); } } protected void checkObject(XMLElement e, String attrNS, String attr) { String href = e.getAttributeNS(attrNS, attr); if (xrefChecker.isPresent() && href != null) { href = PathUtil.resolveRelativeReference(path, href, base == null ? null : base.toString()); xrefChecker.get().registerReference(path, parser.getLineNumber(), parser.getColumnNumber(), href, XRefChecker.Type.OBJECT); } } protected void checkLink(XMLElement e, String attrNS, String attr) { String href = e.getAttributeNS(attrNS, attr); String rel = e.getAttributeNS(attrNS, "rel"); if (xrefChecker.isPresent() && href != null && rel != null && rel.toLowerCase(Locale.ROOT).contains("stylesheet")) { href = PathUtil.resolveRelativeReference(path, href, base == null ? null : base.toString()); xrefChecker.get().registerReference(path, parser.getLineNumber(), parser.getColumnNumber(), href, XRefChecker.Type.STYLESHEET); // Check the mimetype to record possible non-standard stylesheets // with no fallback String mimetype = xrefChecker.get().getMimeType(href); if (mimetype != null) { if (OPFChecker.isBlessedStyleType(mimetype) || OPFChecker.isDeprecatedBlessedStyleType(mimetype)) { hasCss = true; } else { nonStandardStylesheetLink = Optional.of( EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber(), href)); } } } } protected void checkStylesheetFallback() { // stylesheet is considered as having "built-in" fallback if // at least one is found with a blessed CMT (i.e. text/css). // Implem note: xrefChecker is necessarily present if // nonStandardStylesheetLink is present. if (nonStandardStylesheetLink.isPresent() && !hasCss && !xrefChecker.get() .hasValidFallback(nonStandardStylesheetLink.get().getContext().get()).or(false)) { report.message(MessageId.CSS_010, nonStandardStylesheetLink.get()); } } // end head: if no-css stylesheet found AND no css present, report CSS_010 protected void checkSymbol(XMLElement e, String attrNS, String attr) { String href = e.getAttributeNS(attrNS, attr); if (xrefChecker.isPresent() && href != null) { href = PathUtil.resolveRelativeReference(path, href, base == null ? null : base.toString()); xrefChecker.get().registerReference(path, parser.getLineNumber(), parser.getColumnNumber(), href, XRefChecker.Type.SVG_SYMBOL); } } protected void checkHRef(XMLElement e, String attrNS, String attr) { String href = e.getAttributeNS(attrNS, attr); if (href == null) { return; } href = href.trim(); if (href.isEmpty()) { // if href="" then selfreference which is valid, // but as per issue 225, issue a hint report.message(MessageId.HTM_045, EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber(), href)); return; } else if (href.contains("#epubcfi")) { return; // temp until cfi implemented } else if (".".equals(href)) { // selfreference, no need to check return; } URI uri = checkURI(href); if (uri == null) return; if ("http".equals(uri.getScheme())) { report.info(path, FeatureEnum.REFERENCE, href); } /* * mgy 20120417 adding check for base to initial if clause as part of * solution to issue 155 */ if (URISchemes.contains(uri.getScheme()) || (null != base && URISchemes.contains(base.getScheme()))) { return; } // This if statement is needed to make sure XML Fragment identifiers // are not reported as non-registered URI scheme types else if (uri.getScheme() != null) { report.message(MessageId.HTM_025, EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber(), href)); return; } try { href = PathUtil.resolveRelativeReference(path, href, base == null ? null : base.toString()); } catch (IllegalArgumentException err) { report.message(MessageId.OPF_010, EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber(), href), err.getMessage()); return; } processHyperlink(href); } protected void processHyperlink(String href) { if (xrefChecker.isPresent()) { xrefChecker.get().registerReference(path, parser.getLineNumber(), parser.getColumnNumber(), href, XRefChecker.Type.HYPERLINK); } } public void startElement() { openElements++; XMLElement e = parser.getCurrentElement(); ElementLocation currentLocation = new ElementLocation(parser.getLineNumber(), parser.getColumnNumber()); elementLocationStack.push(currentLocation); if (!checkedUnsupportedXMLVersion) { HandlerUtil.checkXMLVersion(parser); checkedUnsupportedXMLVersion = true; } String id = e.getAttribute("id"); String baseTest = e.getAttributeNS(XMLConstants.XML_NS_URI, "base"); if (baseTest != null) { base = checkURI(baseTest); } if (!epubTypeInUse) { String eNS = e.getAttributeNS(EpubConstants.EpubTypeNamespaceUri, "type"); if (eNS != null) { epubTypeInUse = true; } } String ns = e.getNamespace(); String name = e.getName().toLowerCase(Locale.ROOT); XRefChecker.Type resourceType = XRefChecker.Type.GENERIC; if (ns != null) { if (ns.equals("http://www.w3.org/2000/svg")) { if (name.equals("lineargradient") || name.equals("radialgradient") || name.equals("pattern")) { resourceType = XRefChecker.Type.SVG_PAINT; } else if (name.equals("clippath")) { resourceType = XRefChecker.Type.SVG_CLIP_PATH; } else if (name.equals("symbol")) { resourceType = XRefChecker.Type.SVG_SYMBOL; } else if (name.equals("a")) { checkHRef(e, "http://www.w3.org/1999/xlink", "href"); } else if (name.equals("use")) { checkSymbol(e, "http://www.w3.org/1999/xlink", "href"); } else if (name.equals("image")) { checkImage(e, "http://www.w3.org/1999/xlink", "href"); } checkPaint(e, "fill"); checkPaint(e, "stroke"); } else if (ns.equals(EpubConstants.HtmlNamespaceUri)) { if (name.equals("a")) { checkHRef(e, null, "href"); } else if (name.equals("img")) { checkImage(e, null, "src"); } else if (name.equals("object")) { checkObject(e, null, "data"); } else if (name.equals("link")) { checkLink(e, null, "href"); } else if (name.equals("base")) { base = checkURI(e.getAttribute("href")); } else if (name.equals("style")) { textNode = new StringBuilder(); } else if (name.equals("iframe")) { checkIFrame(e); } else if (name.equals("table")) { ++tableDepth; } else if (name.equals("th") && tableDepth > 0) { hasTh = true; } else if (name.equals("thead") && tableDepth > 0) { hasThead = true; } else if (name.equals("caption") && tableDepth > 0) { hasCaption = true; } else if (name.equals("i") || name.equals("b") || name.equals("em") || name.equals("strong")) { checkBoldItalics(e); } resourceType = XRefChecker.Type.HYPERLINK; String style = e.getAttribute("style"); if (style != null && style.length() > 0) { CSSCheckerFactory.getInstance() .newInstance(context, style, currentLocation.getLineNumber(), true).runChecks(); } } } if (xrefChecker.isPresent() && id != null) { xrefChecker.get().registerAnchor(path, currentLocation.getLineNumber(), currentLocation.getColumnNumber(), id, resourceType); } } protected void checkBoldItalics(XMLElement e) { report.message(MessageId.HTM_038, EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber(), e.getName())); } protected void checkIFrame(XMLElement e) { report.message(MessageId.HTM_036, EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber(), e.getName())); } protected URI checkURI(String uri) { try { return new URI(Preconditions.checkNotNull(uri).trim()); } catch (URISyntaxException e) { report.message(MessageId.RSC_020, parser.getLocation(), uri); return null; } } public void endElement() { openElements--; XMLElement e = parser.getCurrentElement(); String ns = e.getNamespace(); String name = e.getName(); if (openElements == 0) { report.info(path, FeatureEnum.CHARS_COUNT, Long.toString(charsCount)); if (!epubTypeInUse) { if (context.version == EPUBVersion.VERSION_3) { report.message(MessageId.ACC_007, EPUBLocation.create(path)); } } else { epubTypeInUse = false; } } ElementLocation currentLocation = elementLocationStack.pop(); if (EpubConstants.HtmlNamespaceUri.equals(ns)) { if ("script".equals(name)) { String attr = e.getAttribute("type"); report.info(path, FeatureEnum.HAS_SCRIPTS, (attr == null) ? "" : attr); } else if ("style".equals(name)) { String style = textNode.toString(); if (style.length() > 0) { CSSCheckerFactory.getInstance() .newInstance(context, style, currentLocation.getLineNumber(), false).runChecks(); } textNode = null; } else if ("head".equals(name)) { checkStylesheetFallback(); } else if ("table".equals(name)) { if (tableDepth > 0) { --tableDepth; EPUBLocation location = EPUBLocation.create(path, currentLocation.getLineNumber(), currentLocation.getColumnNumber(), "table"); checkDependentCondition(MessageId.ACC_005, tableDepth == 0, hasTh, location); checkDependentCondition(MessageId.ACC_006, tableDepth == 0, hasThead, location); checkDependentCondition(MessageId.ACC_012, tableDepth == 0, hasCaption, location); hasTh = hasThead = hasCaption = false; } } } } // Report the message id when primary condition1 is true but dependent // condition2 is false. protected void checkDependentCondition(MessageId id, boolean condition1, boolean condition2, EPUBLocation location) { if (condition1 && !condition2) { report.message(id, location); } } public void ignorableWhitespace(char[] chars, int arg1, int arg2) { } public void characters(char[] chars, int start, int length) { charsCount += length; if (textNode != null) { textNode.append(chars, start, length); } } public void processingInstruction(String arg0, String arg1) { } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ops/OPSChecker.java0000755000175000017500000001355413017276730024600 0ustar eugeneeugene/* * Copyright (c) 2007 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.ops; import static com.adobe.epubcheck.opf.ValidationContext.ValidationContextPredicates.*; import static com.google.common.base.Predicates.*; import java.io.IOException; import java.util.List; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.api.EPUBProfile; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.messages.MessageId; import com.adobe.epubcheck.ocf.OCFPackage; import com.adobe.epubcheck.opf.ContentChecker; import com.adobe.epubcheck.opf.DocumentValidator; import com.adobe.epubcheck.opf.OPFData; import com.adobe.epubcheck.opf.ValidationContext; import com.adobe.epubcheck.util.EPUBVersion; import com.adobe.epubcheck.util.ValidatorMap; import com.adobe.epubcheck.vocab.EpubCheckVocab; import com.adobe.epubcheck.vocab.PackageVocabs; import com.adobe.epubcheck.xml.XMLParser; import com.adobe.epubcheck.xml.XMLValidator; import com.adobe.epubcheck.xml.XMLValidators; import com.google.common.base.Predicates; public class OPSChecker implements ContentChecker, DocumentValidator { @SuppressWarnings("unchecked") private final static ValidatorMap validatorMap = ValidatorMap.builder() .putAll(Predicates.and(mimetype("application/xhtml+xml"), version(EPUBVersion.VERSION_2)), XMLValidators.XHTML_20_NVDL, XMLValidators.XHTML_20_SCH, XMLValidators.IDUNIQUE_20_SCH) .putAll(Predicates.and(mimetype("application/xhtml+xml"), version(EPUBVersion.VERSION_3)), XMLValidators.XHTML_30_RNC, XMLValidators.XHTML_30_SCH) .putAll(Predicates.and(mimetype("image/svg+xml"), version(EPUBVersion.VERSION_2)), XMLValidators.SVG_20_RNG, XMLValidators.IDUNIQUE_20_SCH) .putAll(Predicates.and(mimetype("image/svg+xml"), version(EPUBVersion.VERSION_3)), XMLValidators.SVG_30_RNC, XMLValidators.SVG_30_SCH) .putAll( and(or(profile(EPUBProfile.DICT), hasPubType(OPFData.DC_TYPE_DICT)), mimetype("application/xhtml+xml"), version(EPUBVersion.VERSION_3)), XMLValidators.XHTML_DICT_SCH) .putAll( and(or(profile(EPUBProfile.EDUPUB), hasPubType(OPFData.DC_TYPE_EDUPUB)), not(hasProp(EpubCheckVocab.VOCAB.get(EpubCheckVocab.PROPERTIES.FIXED_LAYOUT))), not(hasProp(EpubCheckVocab.VOCAB.get(EpubCheckVocab.PROPERTIES.NON_LINEAR))), mimetype("application/xhtml+xml"), version(EPUBVersion.VERSION_3)), XMLValidators.XHTML_EDUPUB_STRUCTURE_SCH, XMLValidators.XHTML_EDUPUB_SEMANTICS_SCH, XMLValidators.XHTML_IDX_SCH) .putAll( and(or(profile(EPUBProfile.IDX), hasPubType(OPFData.DC_TYPE_INDEX), hasProp(PackageVocabs.ITEM_VOCAB.get(PackageVocabs.ITEM_PROPERTIES.INDEX)), hasProp(EpubCheckVocab.VOCAB.get(EpubCheckVocab.PROPERTIES.IN_INDEX_COLLECTION))), mimetype("application/xhtml+xml"), version(EPUBVersion.VERSION_3)), XMLValidators.XHTML_IDX_SCH, XMLValidators.XHTML_IDX_INDEX_SCH) .put(hasProp(PackageVocabs.ITEM_VOCAB.get(PackageVocabs.ITEM_PROPERTIES.DATA_NAV)), XMLValidators.XHTML_DATANAV_SCH) .build(); private final ValidationContext context; private final Report report; private final String path; public OPSChecker(ValidationContext context) { this.context = context; this.path = context.path; this.report = context.report; } public void runChecks() { OCFPackage ocf = context.ocf.get(); if (!ocf.hasEntry(path)) { report.message(MessageId.RSC_001, EPUBLocation.create(ocf.getName()), path); } else if (!ocf.canDecrypt(path)) { report.message(MessageId.RSC_004, EPUBLocation.create(ocf.getName()), path); } else { validate(); } } public boolean validate() { int fatalErrorsSoFar = report.getFatalErrorCount(); int errorsSoFar = report.getErrorCount(); int warningsSoFar = report.getWarningCount(); List validators = validatorMap.getValidators(context); try { validate(validators); } catch (IOException e) { report.message(MessageId.PKG_008, EPUBLocation.create(path), path); } return fatalErrorsSoFar == report.getFatalErrorCount() && errorsSoFar == report.getErrorCount() && warningsSoFar == report.getWarningCount(); } void validate(List validators) throws IOException { OPSHandler opsHandler; XMLParser opsParser = new XMLParser(context); if (context.version == EPUBVersion.VERSION_2) { opsHandler = new OPSHandler(context, opsParser); } else { opsHandler = new OPSHandler30(context, opsParser); } opsParser.addXMLHandler(opsHandler); for (XMLValidator validator : validators) { opsParser.addValidator(validator); } opsParser.process(); } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/util/0000755000175000017500000000000013017276730022150 5ustar eugeneeugeneepubcheck-4.0.2/src/main/java/com/adobe/epubcheck/util/EpubConstants.java0000644000175000017500000000150113017276730025600 0ustar eugeneeugenepackage com.adobe.epubcheck.util; public class EpubConstants { public static final String EpubTypeNamespaceUri = "http://www.idpf.org/2007/ops"; public static final String XmlNamespaceUri = "http://www.w3.org/XML/1998/namespace"; public static final String HtmlNamespaceUri = "http://www.w3.org/1999/xhtml"; public static final String XLinkNamespaceUri = "http://www.w3.org/1999/xlink"; public static final String OpfNamespaceUri = "http://www.idpf.org/2007/opf"; public static final String OpenDocumentContainerNamespaceUri ="urn:oasis:names:tc:opendocument:xmlns:container"; public static final String DCElements = "http://purl.org/dc/elements/1.1/"; public static final String ElementLineNumberAttribute = "elementLineNumber"; public static final String ElementColumnNumberAttribute = "elementColumnNumber"; } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/util/ValidatorMap.java0000644000175000017500000001125313017276730025400 0ustar eugeneeugenepackage com.adobe.epubcheck.util; import java.util.List; import java.util.Map; import java.util.Map.Entry; import com.adobe.epubcheck.opf.ValidationContext; import com.adobe.epubcheck.xml.XMLValidator; import com.adobe.epubcheck.xml.XMLValidators; import com.google.common.base.Function; import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.collect.FluentIterable; import com.google.common.collect.ImmutableMap; import com.google.common.collect.LinkedListMultimap; import com.google.common.collect.Maps; /** * A utility to store {@link XMLValidator} references and return a list of * validators applicable to a given {@link ValidationContext}. */ public final class ValidatorMap { /** * Returns a new builder. */ public static Builder builder() { return new Builder(); } // internal immutable map of validators to predicates private Map> validators; private ValidatorMap(Map> validators) { this.validators = validators; } /** * Returns a list of {@link XMLValidator}s applicable to the given * {@link ValidationContext}, as determined by the {@link Predicate} used to * build this map. The validators are returned in the order in which they have * been added to the builder. *

* XMLValidator instances are built dynamically, only when the * context satisfies the underlying predicate. *

* * @param context * a validation context * @return the list of validators applicable to context */ public List getValidators(final ValidationContext context) { return FluentIterable .from(validators.entrySet()) .transform( new Function>, XMLValidator>() { @Override public XMLValidator apply( Entry> entry) { return entry.getValue().apply(context) ? entry.getKey().get() : null; } }).filter(Predicates.notNull()).toList(); } /** * A builder for the {@link ValidatorMap} */ public static final class Builder { // we use an ordered multimap internally // so that client code can add the same validator more than once // (e.g. with different predicates) private LinkedListMultimap> validatorsBuilder = LinkedListMultimap .create(); /** * Puts the given validator in this map and determines its applicability to * a validation context by the given predicate. */ public Builder put(Predicate predicate, XMLValidators validator) { validatorsBuilder.put(validator, predicate); return this; } /** * Puts all the given validators in this map and determines their * applicability to a validation context by the given predicate. */ public Builder putAll(Predicate predicate, XMLValidators... validators) { for (XMLValidators validator : validators) { put(predicate, validator); } return this; } /** * Puts the given validator in this map, applicable to any validation * context. */ public Builder put(XMLValidators validator) { return put(Predicates. alwaysTrue(), validator); } /** * Puts all the given validators in this map, applicable to any validation * context. */ public Builder putAll(XMLValidators... validators) { return putAll(Predicates. alwaysTrue(), validators); } /** * Returns a newly created {@link ValidatorMap} from the validators added to * this builder. */ public ValidatorMap build() { // builds the final immutable map of validators // if a validator is mapped to multiple predicates, // they are combined with an 'or' operation return new ValidatorMap( ImmutableMap.copyOf(Maps.transformValues( validatorsBuilder.asMap(), new Function>, Predicate>() { @Override public Predicate apply( Iterable> predicates) { return Predicates. or(predicates); } }))); } } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/util/XmlReportImpl.java0000644000175000017500000002242213017276730025573 0ustar eugeneeugenepackage com.adobe.epubcheck.util; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.reporting.CheckMessage; public class XmlReportImpl extends XmlReportAbstract { public XmlReportImpl(PrintWriter out, String ePubName, String versionEpubCheck) { super(out, ePubName, versionEpubCheck); } @SuppressWarnings("unchecked") public int generateReport() { if (out == null) return 1; int returnCode = 1; generationDate = fromTime(System.currentTimeMillis()); try { setNamespace("http://hul.harvard.edu/ois/xml/ns/jhove"); List> attrs = new ArrayList>(); attrs.add(KeyValue.with("name", epubCheckName)); attrs.add(KeyValue.with("release", epubCheckVersion)); attrs.add(KeyValue.with("date", epubCheckDate)); startElement("jhove", attrs); generateElement("date", generationDate); startElement("repInfo", KeyValue.with("uri", getNameFromPath(getEpubFileName()))); generateElement("created", creationDate); generateElement("lastModified", lastModifiedDate); if (formatName == null) { generateElement("format", "application/octet-stream"); } else { generateElement("format", formatName); //application/epub+zip } generateElement("version", formatVersion); String customMessageFileName = this.getCustomMessageFile(); if (customMessageFileName != null && !customMessageFileName.isEmpty()) { generateElement("customMessageFileName", customMessageFileName); } if (fatalErrors.isEmpty() && errors.isEmpty()) { generateElement("status", "Well-formed"); } else { generateElement("status", "Not well-formed"); } if (!warns.isEmpty() || !fatalErrors.isEmpty() || !errors.isEmpty() || !hints.isEmpty()) { startElement("messages"); for (CheckMessage c : fatalErrors) { String m = c.getID() + ", FATAL, [" + c.getMessage() + "], "; for (EPUBLocation ml : c.getLocations()) { String loc = ""; if (ml.getLine() > 0 || ml.getColumn() > 0) { loc = " (" + ml.getLine() + "-" + ml.getColumn() + ")"; } generateElement("message", m + PathUtil.removeWorkingDirectory(ml.getPath()) + loc, KeyValue.with("subMessage", c.getID()), KeyValue.with("severity", "error")); } } for (CheckMessage c : errors) { String m = c.getID() + ", ERROR, [" + c.getMessage() + "], "; for (EPUBLocation ml : c.getLocations()) { String loc = ""; if (ml.getLine() > 0 || ml.getColumn() > 0) { loc = " (" + ml.getLine() + "-" + ml.getColumn() + ")"; } generateElement("message", m + PathUtil.removeWorkingDirectory(ml.getPath()) + loc, KeyValue.with("subMessage", c.getID()), KeyValue.with("severity", "error")); } } for (CheckMessage c : warns) { String m = c.getID() + ", WARN, [" + c.getMessage() + "], "; for (EPUBLocation ml : c.getLocations()) { String loc = ""; if (ml.getLine() > 0 || ml.getColumn() > 0) { loc = " (" + ml.getLine() + "-" + ml.getColumn() + ")"; } generateElement("message", m + PathUtil.removeWorkingDirectory(ml.getPath()) + loc, KeyValue.with("subMessage", c.getID()), KeyValue.with("severity", "error")); } } for (CheckMessage c : hints) { String m = c.getID() + ", HINT, [" + c.getMessage() + "], "; for (EPUBLocation ml : c.getLocations()) { String loc = ""; if (ml.getLine() > 0 || ml.getColumn() > 0) { loc = " (" + ml.getLine() + "-" + ml.getColumn() + ")"; } generateElement("message", m + PathUtil.removeWorkingDirectory(ml.getPath()) + loc, KeyValue.with("subMessage", c.getID()), KeyValue.with("severity", "info")); } } endElement("messages"); } generateElement("mimeType", formatName); startElement("properties"); generateProperty("PageCount", pagesCount); generateProperty("CharacterCount", charsCount); generateProperty("Language", language, "String"); startElement("property"); generateElement("name", "Info"); startElement("values", KeyValue.with("arity", "List"), KeyValue.with("type", "Property")); generateProperty("Identifier", identifier, "String"); generateProperty("CreationDate", creationDate, "Date"); generateProperty("ModDate", lastModifiedDate, "Date"); if (!titles.isEmpty()) { String[] cs = titles.toArray(new String[titles.size()]); generateProperty("Title", cs, "String"); } if (!creators.isEmpty()) { String[] cs = creators.toArray(new String[creators.size()]); generateProperty("Creator", cs, "String"); } if (!contributors.isEmpty()) { String[] cs = contributors.toArray(new String[contributors.size()]); generateProperty("Contributor", cs, "String"); } generateProperty("Date", date, "String"); generateProperty("Publisher", publisher, "String"); if (!subjects.isEmpty()) { String[] cs = subjects.toArray(new String[subjects.size()]); generateProperty("Subject", cs, "String"); } if (!rights.isEmpty()) { String[] cs = rights.toArray(new String[rights.size()]); generateProperty("Rights", cs, "String"); } endElement("values"); endElement("property"); if (!embeddedFonts.isEmpty() || !refFonts.isEmpty()) { startElement("property"); generateElement("name", "Fonts"); startElement("values", KeyValue.with("arity", "List"), KeyValue.with("type", "Property")); for (String f : embeddedFonts) { startElement("property"); generateElement("name", "Font"); startElement("values", KeyValue.with("arity", "List"), KeyValue.with("type", "Property")); generateProperty("FontName", getNameFromPath(f), "String"); generateProperty("FontFile", false); endElement("values"); endElement("property"); } for (String f : refFonts) { startElement("property"); generateElement("name", "Font"); startElement("values", KeyValue.with("arity", "List"), KeyValue.with("type", "Property")); generateProperty("FontName", getNameFromPath(f), "String"); generateProperty("FontFile", false); endElement("values"); endElement("property"); } endElement("values"); endElement("property"); } if (!references.isEmpty()) { startElement("property"); generateElement("name", "References"); startElement("values", KeyValue.with("arity", "List"), KeyValue.with("type", "Property")); for (String r : references) { generateProperty("Reference", r, "String"); } endElement("values"); endElement("property"); } if (!mediaTypes.isEmpty()) { String[] cs = mediaTypes.toArray(new String[mediaTypes.size()]); generateProperty("MediaTypes", cs, "String"); } if (hasEncryption) { generateProperty("hasEncryption", hasEncryption); } if (hasSignatures) { generateProperty("hasSignatures", hasSignatures); } if (hasAudio) { generateProperty("hasAudio", hasAudio); } if (hasVideo) { generateProperty("hasVideo", hasVideo); } if (hasFixedLayout) { generateProperty("hasFixedLayout", hasFixedLayout); } if (hasScripts) { generateProperty("hasScripts", hasScripts); } endElement("properties"); endElement("repInfo"); endElement("jhove"); returnCode = 0; } catch (Exception e) { System.err.println("Exception encountered: " + e.getMessage()); returnCode = 1; } return returnCode; } @SuppressWarnings("unchecked") private void generateProperty(String name, String[] value, String type) { if (value == null || value.length == 0) { return; } startElement("property"); generateElement("name", name); startElement("values", KeyValue.with("arity", value.length == 1 ? "Scalar" : "Array"), KeyValue.with("type", type)); for (String v : value) { generateElement("value", v); } endElement("values"); endElement("property"); } @SuppressWarnings("unchecked") private void generateProperty(String name, String value, String type) { if (value == null || value.trim().length() == 0) { return; } startElement("property"); generateElement("name", name); startElement("values", KeyValue.with("arity", "Scalar"), KeyValue.with("type", type)); generateElement("value", value); endElement("values"); endElement("property"); } private void generateProperty(String name, long value) { if (value == 0) { return; } generateProperty(name, Long.toString(value), "Long"); } private void generateProperty(String name, boolean value) { generateProperty(name, value ? "true" : "false", "Boolean"); } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/util/PathUtil.java0000755000175000017500000000734013017276730024554 0ustar eugeneeugene/* * Copyright (c) 2007 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.util; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.util.Stack; import java.util.StringTokenizer; public class PathUtil { static final String workingDirectory = System.getProperty("user.dir"); public static String resolveRelativeReference(String base, String ref, String baseRewrite) throws IllegalArgumentException { //baseRewrite is null unless head/base or xml:base is set in the instance String actualBase = base; if (baseRewrite != null && baseRewrite.length() > 0 && !baseRewrite.equals(".")) { actualBase = baseRewrite; } if (ref.startsWith("data:") || ref.startsWith("http:")) { return ref; } try { ref = URLDecoder.decode(ref.replace("+", "%2B"), "UTF-8"); } catch (UnsupportedEncodingException e) { // UTF-8 is guaranteed to be supported throw new InternalError(e.toString()); } if (ref.startsWith("#")) { int index = actualBase.indexOf("#"); if (index < 0) { ref = actualBase + ref; } else { ref = actualBase.substring(0, index) + ref; } } else { int index = actualBase.lastIndexOf("/"); ref = actualBase.substring(0, index + 1) + ref; } return normalizePath(ref); } public static String normalizePath(String path)throws IllegalArgumentException { // Test for any ../ or ./ if (!path.contains("./")) { return path; } Stack pathSegments = new Stack(); StringTokenizer tokenizer = new StringTokenizer(path, "/"); while (tokenizer.hasMoreTokens()) { String pathSegment = tokenizer.nextToken(); if (".".equals(pathSegment)) { continue; } if ("..".equals(pathSegment)) { if (pathSegments.size() == 0) { throw new IllegalArgumentException("Invalid path: " + path); } pathSegments.pop(); } else { pathSegments.push(pathSegment); } } StringBuilder sb = new StringBuilder(path.length()); int len = pathSegments.size(); for (int i = 0; i < len; i++) { if (i != 0) { sb.append('/'); } sb.append(pathSegments.elementAt(i)); } return sb.toString(); } public static String removeWorkingDirectory(String path) { if (path == null || path.length() == 0) { return path; } return path.replace(workingDirectory, "."); } public static String removeAnchor(String href) { int index = href.indexOf("#"); if (index == -1) { return href; } return (href.substring(0, index)); } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/util/OPSType.java0000644000175000017500000000336113017276730024321 0ustar eugeneeugene/* * Copyright (c) 2011 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.util; public class OPSType { private final EPUBVersion version; private final String mimeType; public OPSType(String mimeType, EPUBVersion version) { if (mimeType == null) { mimeType = ""; } this.mimeType = mimeType; this.version = version; } public boolean equals(Object obj) { if (!(obj instanceof OPSType)) { return false; } OPSType Obj = (OPSType) obj; return this.version == Obj.version && this.mimeType.equals(Obj.mimeType); } public int hashCode() { return (mimeType.hashCode() * version.ordinal()); } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/util/KeyValue.java0000644000175000017500000000064113017276730024541 0ustar eugeneeugenepackage com.adobe.epubcheck.util; public final class KeyValue { private final A key; private final B value; public static KeyValue with(final A key, final B value) { return new KeyValue(key,value); } public KeyValue(final A key, final B value) { this.key = key; this.value = value; } public A getKey() { return this.key; } public B getValue() { return this.value; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/util/outWriter.java0000644000175000017500000000147113017276730025022 0ustar eugeneeugenepackage com.adobe.epubcheck.util; public class outWriter { static boolean isQuiet = false; public outWriter(){} public static void setQuiet(boolean isQuiet) { outWriter.isQuiet = isQuiet; } public static boolean isQuiet() { return isQuiet; } public static void printf(String format, Object...args) { if (!isQuiet()) { System.out.printf(format, args); } } public static void println(Object x) { if (!isQuiet()) { System.out.println(x); } } public static void println(String x) { if (!isQuiet()) { System.out.println(x); } } public static void println() { System.out.println(); } public static void print(String s) { System.out.print(s); } public static void flush() { System.out.flush(); } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/util/CheckUtil.java0000755000175000017500000000655113017276730024700 0ustar eugeneeugene/* * Copyright (c) 2007 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.util; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.security.InvalidParameterException; public class CheckUtil { public static boolean checkString(byte[] arr, int offset, String string) { try { byte[] bytes = string.getBytes("UTF-8"); if (bytes.length + offset > arr.length) { return false; } for (int i = 0; i < bytes.length; i++) { if (arr[offset + i] != bytes[i]) { return false; } } return true; } catch (UnsupportedEncodingException e) { e.printStackTrace(); // internal problem: UTF-8 not supported??! return false; } } /* * MimeType already verified to match application/epub+zip. Depending on * version, verifying trailing spaces. */ public static boolean checkTrailingSpaces(InputStream input, EPUBVersion version, StringBuilder sb) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(2048); int c; for (int i = 0; i < 20; i++) { if ((c = input.read()) == -1) { return false; } else { baos.write(c); } } int ch = input.read(); if (version == EPUBVersion.VERSION_2 && ch != -1) { return false; } if (version == EPUBVersion.VERSION_3 && ch != ' ' && ch != -1) { return false; } int len; byte[] buf = new byte[1024]; while ((len = input.read(buf)) > 0) { for (int i = 0; i < len; i++) { if (buf[i] != ' ') { return false; } else { baos.write(buf[i]); } } } sb.append(baos.toString()); baos.close(); return true; } public static int readBytes(InputStream in, byte[] b, int off, int len) throws IOException { if (len < 1) { throw new InvalidParameterException(Integer.toString(len)); } int total = 0; while (total < len) { int result = in.read(b, off + total, len - total); if (result == -1) { break; } total += result; } return total; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/util/ResourceUtil.java0000755000175000017500000000455613017276730025455 0ustar eugeneeugene/* * Copyright (c) 2007 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.util; import java.io.InputStream; import java.net.URL; public class ResourceUtil { public static String getResourcePath(String localName) { String classPath = ResourceUtil.class.getName().replace('.', '/'); String classPackage = classPath .substring(0, classPath.lastIndexOf("/")); String projectPackage = classPackage.substring(0, classPackage.lastIndexOf("/")); return projectPackage + "/" + localName; } public static String getExtension(String path) { int index = path.lastIndexOf("."); if (index > 0) { return path.substring(index + 1); } return null; } public static InputStream getResourceStream(String resourcePath) { ClassLoader loader = ResourceUtil.class.getClassLoader(); if (loader == null) { return ClassLoader.getSystemResourceAsStream(resourcePath); } else { return loader.getResourceAsStream(resourcePath); } } public static URL getResourceURL(String resourcePath) { ClassLoader loader = ResourceUtil.class.getClassLoader(); if (loader == null) { return ClassLoader.getSystemResource(resourcePath); } else { return loader.getResource(resourcePath); } } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/util/JsonWriter.java0000644000175000017500000000354113017276730025124 0ustar eugeneeugenepackage com.adobe.epubcheck.util; import java.io.IOException; import java.io.OutputStream; import org.codehaus.jackson.JsonFactory; import org.codehaus.jackson.JsonGenerator; import org.codehaus.jackson.JsonProcessingException; import org.codehaus.jackson.map.JsonSerializer; import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.map.SerializationConfig; import org.codehaus.jackson.map.SerializerProvider; import com.google.common.base.Optional; /** * This is used to create json output */ public class JsonWriter { public static class OptionalJsonSerializer extends JsonSerializer> { @Override public void serialize(Optional value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException { // jgen.writeStartObject(); jgen.writeString(value.orNull()); // jgen.writeEndObject(); } } private ObjectMapper objectMapper; private JsonWriter(ObjectMapper objectMapper) { if (objectMapper == null) { throw new IllegalArgumentException("objectMapper argument is required."); } this.objectMapper = objectMapper; } public static JsonWriter createJsonWriter(boolean pretty) { JsonFactory jf = new JsonFactory(); ObjectMapper om = new ObjectMapper(jf); om.configure(JsonGenerator.Feature.AUTO_CLOSE_TARGET, false); om.configure(JsonGenerator.Feature.ESCAPE_NON_ASCII, true); om.configure(SerializationConfig.Feature.INDENT_OUTPUT, pretty); om.configure(SerializationConfig.Feature.AUTO_DETECT_GETTERS, false); om.configure(SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS, false); return new JsonWriter(om); } public void writeJson(Object content, OutputStream os) throws IOException { this.objectMapper.writeValue(os, content); } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/util/TextSearchDictionaryEntry.java0000644000175000017500000000151613017276730030140 0ustar eugeneeugenepackage com.adobe.epubcheck.util; import com.adobe.epubcheck.messages.MessageId; import java.util.regex.Pattern; public class TextSearchDictionaryEntry { private String searchedValue; private String regexExp; private MessageId errorCode; private Pattern pattern; public TextSearchDictionaryEntry(String searchedValue, String regex, MessageId errorCode) { this.searchedValue = searchedValue; this.regexExp = regex; this.errorCode = errorCode; this.pattern = null; } public String getSearchedValue() { return searchedValue; } public String getRegexExp() { return regexExp; } public MessageId getErrorCode() { return errorCode; } public Pattern getPattern() { if (pattern == null) { pattern = Pattern.compile(this.getRegexExp()); } return pattern; } }epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/util/InvalidVersionException.java0000644000175000017500000000335013017276730027627 0ustar eugeneeugene/* * Copyright (c) 2007 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.util; import org.xml.sax.SAXException; public class InvalidVersionException extends SAXException { private static final long serialVersionUID = 1L; public final static String UNSUPPORTED_VERSION = "Version not supported"; public final static String VERSION_NOT_FOUND = "Version not found"; public final static String VERSION_ATTRIBUTE_NOT_FOUND = "Version attribute not found"; public final static String PACKAGE_ELEMENT_NOT_FOUND = "Package element must be the first element in the package file"; public InvalidVersionException(String message) { super(message); } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/util/DefaultReportImpl.java0000644000175000017500000000767713017276730026436 0ustar eugeneeugene/* * Copyright (c) 2007 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.util; import com.adobe.epubcheck.api.MasterReport; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.messages.Message; import com.adobe.epubcheck.messages.Severity; public class DefaultReportImpl extends MasterReport { static boolean DEBUG = false; boolean quiet; boolean saveQuiet; public static String ePubVersion; public DefaultReportImpl(String ePubName) { this(ePubName, null, false); } public DefaultReportImpl(String ePubName, String info, boolean quiet) { this.quiet = quiet; String adjustedPath = PathUtil.removeWorkingDirectory(ePubName); this.setEpubFileName(adjustedPath); if (info != null) { //warning("", 0, 0, info); } } String fixMessage(String message) { if (message == null) { return ""; } return message.replaceAll("[\\s]+", " "); } boolean pushQuiet() { saveQuiet = outWriter.isQuiet(); outWriter.setQuiet(quiet); return saveQuiet; } void popQuiet() { outWriter.setQuiet(saveQuiet); } @Override public void message(Message message, EPUBLocation location, Object... args) { Severity severity = message.getSeverity(); String text = formatMessage(message, location, args); if (severity.equals(Severity.USAGE)) { pushQuiet(); outWriter.println(text); popQuiet(); } else { System.err.println(text); } } String formatMessage(Message message, EPUBLocation location, Object... args) { String fileName = (location.getPath() == null ? "" : "/" + location.getPath()); fileName = PathUtil.removeWorkingDirectory(fileName); return String.format("%1$s(%2$s): %3$s%4$s(%5$s,%6$s): %7$s", message.getSeverity(), message.getID(), PathUtil.removeWorkingDirectory(this.getEpubFileName()), fileName, location.getLine(), location.getColumn(), fixMessage(args != null && args.length > 0 ? message.getMessage(args) : message.getMessage())); } @Override public void info(String resource, FeatureEnum feature, String value) { if (ReportingLevel.Info >= getReportingLevel()) { switch (feature) { case FORMAT_VERSION: if (!quiet) { outWriter.println(String.format(Messages.get("validating_version_message"), value)); } break; default: if (DEBUG && !quiet) { if (resource == null) { outWriter.println("INFO: [" + feature + "]=" + value); } else { outWriter.println("INFO: [" + feature + " (" + resource + ")]=" + value); } } break; } } } public int generate() { return 0; } public void initialize() { } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/util/Messages.java0000644000175000017500000000717113017276730024570 0ustar eugeneeugene/* * Copyright (c) 2011 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.util; import com.google.common.base.Charsets; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.URL; import java.net.URLConnection; import java.text.MessageFormat; import java.util.Locale; import java.util.MissingResourceException; import java.util.PropertyResourceBundle; import java.util.ResourceBundle; import java.util.ResourceBundle.Control; public class Messages { private static final String BUNDLE_NAME = "com.adobe.epubcheck.util.messages"; //$NON-NLS-1$ private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle.getBundle(BUNDLE_NAME, Locale.getDefault(), new UTF8Control()); private Messages() { } public static String get(String key) { try { return RESOURCE_BUNDLE.getString(key); } catch (MissingResourceException e) { return key; } } public static String get(String key, Object... arguments) { try { return MessageFormat.format(RESOURCE_BUNDLE.getString(key), arguments); } catch (MissingResourceException e) { return key; } } private static class UTF8Control extends Control { public ResourceBundle newBundle (String baseName, Locale locale, String format, ClassLoader loader, boolean reload) throws IllegalAccessException, InstantiationException, IOException { // The below is a copy of the default implementation. String bundleName = toBundleName(baseName, locale); String resourceName = toResourceName(bundleName, "properties"); //$NON-NLS-1$ ResourceBundle bundle = null; InputStream stream = null; if (reload) { URL url = loader.getResource(resourceName); if (url != null) { URLConnection connection = url.openConnection(); if (connection != null) { connection.setUseCaches(false); stream = connection.getInputStream(); } } } else { stream = loader.getResourceAsStream(resourceName); } if (stream != null) { try { // Only this line is changed to make it to read properties files as UTF-8. bundle = new PropertyResourceBundle( new BufferedReader( new InputStreamReader(stream, Charsets.UTF_8))); } finally { stream.close(); } } return bundle; } } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/util/EPUBVersion.java0000644000175000017500000000262313017276730025117 0ustar eugeneeugene/* * Copyright (c) 2011 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.util; public enum EPUBVersion { Unknown("unknown"), VERSION_2("2.0.1"), VERSION_3("3.0.1"); private final String version; EPUBVersion(String version) { this.version = version; } public String toString() { return version; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/util/WriterReportImpl.java0000644000175000017500000001127413017276730026312 0ustar eugeneeugene/* * Copyright (c) 2007 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.util; import com.adobe.epubcheck.api.MasterReport; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.messages.Message; import com.adobe.epubcheck.messages.Severity; import java.io.PrintWriter; public class WriterReportImpl extends MasterReport { static boolean DEBUG = false; boolean quiet; final PrintWriter out; public WriterReportImpl(PrintWriter out) { this(out, "", false); } public WriterReportImpl(PrintWriter out, String info) { this(out, info, false); } public WriterReportImpl(PrintWriter out, String info, boolean quiet) { this.out = out; warning("", 0, 0, info); this.quiet = quiet; } String fixMessage(String message) { if (message == null) return ""; return message.replaceAll("[\\s]+", " "); } @Override public void message(Message message, EPUBLocation location, Object... args) { if (message.getSeverity().equals(Severity.ERROR)) { error(PathUtil.removeWorkingDirectory(location.getPath()), location.getLine(), location.getColumn(), message.getMessage(args)); } else if (message.getSeverity().equals(Severity.WARNING)) { warning(PathUtil.removeWorkingDirectory(location.getPath()), location.getLine(), location.getColumn(), message.getMessage(args)); } else if (message.getSeverity().equals(Severity.FATAL)) { fatalError(PathUtil.removeWorkingDirectory(location.getPath()), location.getLine(), location.getColumn(), message.getMessage(args)); } } void error(String resource, int line, int column, String message) { message = fixMessage(message); out.println("ERROR: " + (resource == null ? "[top level]" : resource) + (line <= 0 ? "" : "(" + line + (column <= 0 ? "" : "," + column) + ")") + ": " + message); } void fatalError(String resource, int line, int column, String message) { message = fixMessage(message); out.println("ERROR: " + (resource == null ? "[top level]" : resource) + (line <= 0 ? "" : "(" + line + (column <= 0 ? "" : "," + column) + ")") + ": " + message); } void warning(String resource, int line, int column, String message) { message = fixMessage(message); out.println("WARNING: " + (resource == null ? "[top level]" : resource) + (line <= 0 ? "" : "(" + line + (column <= 0 ? "" : "," + column) + ")") + ": " + message); } @Override public void info(String resource, FeatureEnum feature, String value) { if (ReportingLevel.Info >= getReportingLevel()) { switch (feature) { case FORMAT_VERSION: if (DEBUG && !quiet) { outWriter.println(String.format(Messages.get("validating_version_message"), value)); } break; default: if (!quiet) { if (resource == null) { outWriter.println("INFO: [" + feature + "]=" + value); } else { outWriter.println("INFO: [" + feature + " (" + resource + ")]=" + value); } } break; } } } public void initialize() { } public void hint(String resource, int line, int column, String message) { if (!quiet) { out.println("HINT: " + (resource == null ? "[top level]" : resource) + (line <= 0 ? "" : "(" + line + (column <= 0 ? "" : "," + column) + ")") + ": " + message); } } public int generate() { out.flush(); return 0; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/util/InvalidDateException.java0000755000175000017500000000067013017276730027064 0ustar eugeneeugenepackage com.adobe.epubcheck.util; /** * Invalid date exception. * Exception to signal an invalid date. */ public class InvalidDateException extends Exception { /** * Creates an exception to signal an invalid date. * * @param message message associated with the exception */ public InvalidDateException(String message) { super(message); } private static final long serialVersionUID = -8476118619257777307L; } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/util/FileResourceProvider.java0000644000175000017500000000337413017276730027124 0ustar eugeneeugene/* * Copyright (c) 2011 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.util; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.InputStream; public class FileResourceProvider implements GenericResourceProvider { private final String fileName; public FileResourceProvider(String fileName) { this.fileName = fileName; File file = new File(fileName); if (!file.exists()) { throw new RuntimeException("File " + fileName + " does not exist"); } } public InputStream getInputStream(String ignore) throws FileNotFoundException { return new FileInputStream(new File(fileName)); } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/util/XmlReportAbstract.java0000644000175000017500000003042513017276730026437 0ustar eugeneeugenepackage com.adobe.epubcheck.util; import java.io.PrintWriter; import java.text.CharacterIterator; import java.text.SimpleDateFormat; import java.text.StringCharacterIterator; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.HashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.w3c.dom.Attr; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import com.adobe.epubcheck.api.MasterReport; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.messages.Message; import com.adobe.epubcheck.messages.Severity; import com.adobe.epubcheck.reporting.CheckMessage; /** * Abstract class to generate a report in XML. * * It collects the information needed for the report and provides helper methods to generate proper XML. * In order to generate a specific XML, the generateReport method should be provided in a derived class. * */ public abstract class XmlReportAbstract extends MasterReport { protected PrintWriter out; protected String epubCheckName = "epubcheck"; protected String epubCheckVersion; protected String epubCheckDate = "2012-10-31"; // default date to be // overridden by the property protected String generationDate; protected String creationDate; protected String lastModifiedDate; protected String identifier; protected Set titles = new LinkedHashSet(); protected final Set creators = new LinkedHashSet(); protected final Set contributors = new LinkedHashSet(); protected final Set subjects = new LinkedHashSet(); protected String publisher; protected final Set rights = new LinkedHashSet(); protected String date; protected final Set mediaTypes = new LinkedHashSet(); protected String formatName; protected String formatVersion; protected long pagesCount; protected long charsCount; protected String language; protected final Set embeddedFonts = new LinkedHashSet(); protected final Set refFonts = new LinkedHashSet(); protected final Set references = new LinkedHashSet(); protected boolean hasEncryption; protected boolean hasSignatures; protected boolean hasAudio; protected boolean hasVideo; protected boolean hasFixedLayout; protected boolean hasScripts; protected final List warns = new ArrayList(); protected final List errors = new ArrayList(); protected final List fatalErrors = new ArrayList(); protected final List hints = new ArrayList(); public XmlReportAbstract(PrintWriter out, String ePubName, String versionEpubCheck) { this.out = out; this.setEpubFileName(PathUtil.removeWorkingDirectory(ePubName)); this.epubCheckVersion = versionEpubCheck; } public void initialize() { } @Override public void close() { } @Override public void message(Message message, EPUBLocation location, Object... args) { Severity s = message.getSeverity(); switch (s) { case FATAL: CheckMessage.addCheckMessage(fatalErrors, message, location, args); break; case ERROR: CheckMessage.addCheckMessage(errors, message, location, args); break; case WARNING: CheckMessage.addCheckMessage(warns, message, location, args); break; case USAGE: CheckMessage.addCheckMessage(hints, message, location, args); break; case INFO: break; case SUPPRESSED: break; default: break; } } @Override public void info(String resource, FeatureEnum feature, String value) { switch (feature) { case TOOL_DATE: if (value != null && !value.startsWith("$")) { this.epubCheckDate = value; } break; case TOOL_NAME: this.epubCheckName = value; break; case TOOL_VERSION: this.epubCheckVersion = value; break; case FORMAT_NAME: this.formatName = value; break; case FORMAT_VERSION: this.formatVersion = value; break; case CREATION_DATE: this.creationDate = value; break; case MODIFIED_DATE: this.lastModifiedDate = value; break; case PAGES_COUNT: this.pagesCount = Long.parseLong(value); break; case CHARS_COUNT: this.charsCount += Long.parseLong(value); break; case DECLARED_MIMETYPE: mediaTypes.add(value); if (value != null && value.startsWith("audio/")) { this.hasAudio = true; } else if (value != null && value.startsWith("video/")) { this.hasVideo = true; } break; case FONT_EMBEDDED: this.embeddedFonts.add(value); break; case FONT_REFERENCE: this.refFonts.add(value); break; case REFERENCE: this.references.add(value); break; case DC_LANGUAGE: this.language = value; break; case DC_TITLE: this.titles.add(value); break; case DC_CREATOR: this.creators.add(value); break; case DC_CONTRIBUTOR: this.contributors.add(value); break; case DC_PUBLISHER: this.publisher = value; break; case DC_SUBJECT: this.subjects.add(value); break; case DC_RIGHTS: this.rights.add(value); break; case DC_DATE: this.date = value; break; case UNIQUE_IDENT: if (resource == null) { this.identifier = value; } break; case HAS_SIGNATURES: this.hasSignatures = true; break; case HAS_ENCRYPTION: this.hasEncryption = true; break; case HAS_FIXED_LAYOUT: this.hasFixedLayout = true; break; case HAS_SCRIPTS: this.hasScripts = true; break; case SPINE_INDEX: break; default: break; } } protected String getNameFromPath(String path) { if (path == null || path.length() == 0) { return null; } int lastSlash = path.lastIndexOf('/'); if (lastSlash == -1) { return path; } else { return path.substring(lastSlash + 1); } } /** * Method to implement effective report generation. * @return errorCode */ public abstract int generateReport(); // Variables for report generation private Document doc; private Element currentEl; private String namespaceURI; private Map namespaces; public void setNamespace(String uri) { namespaceURI = uri; } public void addPrefixNamespace(String prefix, String uri) { namespaces.put(prefix, uri); } public int generate() { namespaces = new HashMap(); int returnCode = 1; try { // Initialize the DOM DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder docBuilder; docBuilder = docFactory.newDocumentBuilder(); doc = docBuilder.newDocument(); // Calculate the report returnCode = generateReport(); if (returnCode == 0) { // Output the report TransformerFactory transformerFactory = TransformerFactory.newInstance(); Transformer transformer = transformerFactory.newTransformer(); transformer.setOutputProperty(OutputKeys.INDENT, "yes"); DOMSource source = new DOMSource(doc); StreamResult result = new StreamResult(out); transformer.transform(source, result); } } catch (ParserConfigurationException e) { e.printStackTrace(); returnCode = 1; } catch (TransformerException e) { //System.err.println(Messages.get("error_generating_report")); System.err.println("Error while generating the XML report " + e.getMessage()); e.printStackTrace(); returnCode = 1; } finally { if (out != null) { out.flush(); out.close(); } } return returnCode; } protected String capitalize(String in) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < in.length(); i++) { char c = in.charAt(i); if (i == 0) sb.append(Character.toUpperCase(c)); else sb.append(c); } return sb.toString(); } private Element makeElement(String name) { Element el; int index = name.indexOf(':'); if (index == -1) { if (namespaceURI == null) { el = doc.createElement(name); } else { el = doc.createElementNS(namespaceURI, name); } } else { String prefix = name.substring(0, index); String uri = namespaces.get(prefix); if (uri == null) { el = doc.createElement(name); } else { el = doc.createElementNS(uri, name); } } return el; } private Attr makeAttribute(KeyValue kv) { Attr attr; String attName = kv.getKey(); int iAttr = attName.indexOf(':'); if (iAttr == -1) { attr = doc.createAttribute(attName); } else { String prefix = attName.substring(0, iAttr); String uri = namespaces.get(prefix); if (uri == null) { attr = doc.createAttribute(attName); } else { attr = doc.createAttributeNS(uri, attName); } } attr.setValue(kv.getValue()); return attr; } protected void startElement(String name, List> attrs) { if (name == null || name.trim().length() == 0) { return; } Element el = makeElement(name.trim()); if (attrs != null && attrs.size() != 0) { for (KeyValue attr : attrs) { el.setAttributeNode(makeAttribute(attr)); } } if (currentEl == null) { doc.appendChild(el); } else { currentEl.appendChild(el); } currentEl = el; } protected void startElement(String name, KeyValue... attrs) { startElement(name, Arrays.asList(attrs)); } protected void startElement(String name) { startElement(name, (List>) null); } protected void endElement(String name) { if (currentEl == null) return; Node parent = currentEl.getParentNode(); if (parent == null || parent == doc) { currentEl = null; } else if (parent instanceof Element) { currentEl = (Element)currentEl.getParentNode(); } else { System.out.println("Pb at Element [" + currentEl.getLocalName() + "] with parent " + parent); } } protected void generateElement(String name, String value) { if (name == null || name.trim().length() == 0 || value == null || value.trim().length() == 0) { return; } Element el = makeElement(name.trim()); el.appendChild(doc.createTextNode(correctToUtf8(value.trim()))); currentEl.appendChild(el); } protected void generateElement(String name, String value, KeyValue... attrs) { generateElement(name, value, Arrays.asList(attrs)); } protected void generateElement(String name, String value, List> attrs) { if (name == null || name.trim().length() == 0) { return; } Element el = makeElement(name); if (attrs != null && attrs.size() != 0) { for (KeyValue attr : attrs) { el.setAttributeNode(makeAttribute(attr)); } } if (value != null && value.trim().length() != 0) { el.appendChild(doc.createTextNode(correctToUtf8(value.trim()))); } currentEl.appendChild(el); } /** * Make sure the string contains valid UTF-8 characters * @param inputString * @return escaped String */ protected static String correctToUtf8(String inputString) { final StringBuilder result = new StringBuilder(inputString.length()); final StringCharacterIterator it = new StringCharacterIterator(inputString); char ch = it.current(); boolean modified = false; while (ch != CharacterIterator.DONE) { if (Character.isISOControl(ch)) { if (ch == '\r' || ch == '\n') { result.append(ch); } else { modified = true; result.append(String.format("0x%x", (int) ch)); } } else { result.append(ch); } ch = it.next(); } if (!modified) return inputString; return result.toString(); } /** * Transform time into ISO 8601 string. */ protected static String fromTime(final long time) { Date date = new Date(time); // Waiting for Java 7: SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX"); String formatted = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").format(date); return formatted.substring(0, 22) + ":" + formatted.substring(22); } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/util/GenericResourceProvider.java0000644000175000017500000000263613017276730027621 0ustar eugeneeugene/* * Copyright (c) 2011 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.util; import java.io.IOException; import java.io.InputStream; public interface GenericResourceProvider { /* * added parameter to fit with OCFPackage.getInputStream(path) */ public InputStream getInputStream(String path) throws IOException; } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/util/SearchDictionary.java0000644000175000017500000001027013017276730026246 0ustar eugeneeugenepackage com.adobe.epubcheck.util; import com.adobe.epubcheck.messages.MessageId; import java.util.Vector; public class SearchDictionary { public enum DictionaryType { VALID_TEXT_MEDIA_TYPES, CSS_FILES, CSS_VALUES, LINK_VALUES, SVG_MEDIA_TYPES } public SearchDictionary(DictionaryType dt) { if (dt.equals(DictionaryType.VALID_TEXT_MEDIA_TYPES)) { buildValidTypesDictionary(); } if (dt.equals(DictionaryType.CSS_VALUES)) { buildCssSearchDictionary(); } if (dt.equals(DictionaryType.CSS_FILES)) { buildCSSTypesDictionary(); } if (dt.equals(DictionaryType.LINK_VALUES)) { buildLinkSearchDictionary(); } if (dt.equals(DictionaryType.SVG_MEDIA_TYPES)) { buildSVGSearchDictionary(); } } private final Vector v = new Vector(); private final Vector e = new Vector(); /* String[] validTypes = new String[] { "application/xhtml+xml", "application/x-dtbncx+xml", "text/css" }; */ void buildCSSTypesDictionary() { String description; String value; TextSearchDictionaryEntry de; //search eval() expression description = "text/css"; value = "text/css"; de = new TextSearchDictionaryEntry(description, value, MessageId.CSS_009); v.add(de); } void buildCssSearchDictionary() { String description; String value; TextSearchDictionaryEntry de; //search eval() expression description = "rotateX()"; value = "rotateX()"; de = new TextSearchDictionaryEntry(description, value, MessageId.CSS_009); v.add(de); description = "rotateY()"; value = "rotateY()"; de = new TextSearchDictionaryEntry(description, value, MessageId.CSS_009); v.add(de); description = "column-count"; value = "column-count"; de = new TextSearchDictionaryEntry(description, value, MessageId.CSS_009); v.add(de); description = "column-gap"; value = "column-gap"; de = new TextSearchDictionaryEntry(description, value, MessageId.CSS_009); v.add(de); description = "column-rule"; value = "column-rule"; de = new TextSearchDictionaryEntry(description, value, MessageId.CSS_009); v.add(de); description = "keyframes"; value = "keyframes"; de = new TextSearchDictionaryEntry(description, value, MessageId.CSS_009); v.add(de); description = "transition"; value = "transition"; de = new TextSearchDictionaryEntry(description, value, MessageId.CSS_009); v.add(de); } void buildValidTypesDictionary() { String description; String value; TextSearchDictionaryEntry de; description = "application/xhtml+xml"; value = "application/xhtml+xml"; de = new TextSearchDictionaryEntry(description, value, null); v.add(de); } void buildLinkSearchDictionary() { String description; String value; TextSearchDictionaryEntry de; description = "Http:"; value = "[Hh][Tt][Tt][Pp]*\\:"; de = new TextSearchDictionaryEntry(description, value, MessageId.HTM_005); v.add(de); description = "Ftp:"; value = "[Ff][Tt][Pp]*\\:"; de = new TextSearchDictionaryEntry(description, value, MessageId.HTM_005); v.add(de); description = "File:"; value = "[Ff][Ii][Ll][Ee]*\\:"; de = new TextSearchDictionaryEntry(description, value, MessageId.HTM_005); v.add(de); } public Vector getDictEntries() { return v; } public Vector getExceptionEntries() { return e; } void buildSVGSearchDictionary() { String description; String value; TextSearchDictionaryEntry de; description = "image/svg+xml"; value = "image/svg+xml"; de = new TextSearchDictionaryEntry(description, value, null); v.add(de); } public boolean isValidMediaType(String typeToCheck) { if (typeToCheck == null) { return false; } for (int i = 0; i < getDictEntries().size(); i++) { if ((getDictEntries().get(i).getRegexExp()).compareToIgnoreCase(typeToCheck) == 0) { return true; } } return false; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/util/ReportingLevel.java0000644000175000017500000000157313017276730025762 0ustar eugeneeugenepackage com.adobe.epubcheck.util; import com.adobe.epubcheck.messages.Severity; public class ReportingLevel { static public final int Fatal = 5; static public final int Error = 4; static public final int Warning = 3; static public final int Info = 2; static public final int Usage = 1; static public final int Suppressed = 0; public static int getReportingLevel(Severity severity) { if (severity == Severity.FATAL) { return Fatal; } else if (severity == Severity.ERROR) { return Error; } else if (severity == Severity.WARNING) { return Warning; } else if (severity == Severity.INFO) { return Info; } else if (severity == Severity.USAGE) { return Usage; } else if (severity == Severity.SUPPRESSED) { return Suppressed; } else { return -1; } } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/util/LocationImpl.java0000644000175000017500000000170313017276730025406 0ustar eugeneeugenepackage com.adobe.epubcheck.util; import javax.xml.stream.Location; public class LocationImpl implements Location { private final int lineNumber; private final int columnNumber; private final int characterOffset; private final String publicId; private final String systemId; public LocationImpl(int lineNumber, int columnNumber, int characterOffset, String publicId, String systemId) { this.lineNumber = lineNumber; this.columnNumber = columnNumber; this.characterOffset = characterOffset; this.publicId = publicId; this.systemId = systemId; } @Override public int getLineNumber() { return lineNumber; } @Override public int getColumnNumber() { return columnNumber; } @Override public int getCharacterOffset() { return characterOffset; } @Override public String getPublicId() { return publicId; } @Override public String getSystemId() { return systemId; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/util/DateParserTest.java0000755000175000017500000000757713017276730025730 0ustar eugeneeugenepackage com.adobe.epubcheck.util; /** * Test for the DateParser class. */ public class DateParserTest { /** * Test the ISO8601 date. * Date grammar: * Year: * YYYY (eg 1997) * Year and month: * YYYY-MM (eg 1997-07) * Complete date: * YYYY-MM-DD (eg 1997-07-16) * Complete date plus hours and minutes: * YYYY-MM-DDThh:mmTZD (eg 1997-07-16T19:20+01:00) * Complete date plus hours, minutes and seconds: * YYYY-MM-DDThh:mm:ssTZD (eg 1997-07-16T19:20:30+01:00) * Complete date plus hours, minutes, seconds and a decimal fraction of a second * YYYY-MM-DDThh:mm:ss.sTZD (eg 1997-07-16T19:20:30.45+01:00) * where: * * YYYY = four-digit year * MM = two-digit month (01=January, etc.) * DD = two-digit day of month (01 through 31) * hh = two digits of hour (00 through 23) (am/pm NOT allowed) * mm = two digits of minute (00 through 59) * ss = two digits of second (00 through 59) * s = one or more digits representing a decimal fraction of a second * TZD = time zone designator (Z or +hh:mm or -hh:mm) * * @throws Exception */ public void testisISO8601Date() throws Exception { DateParser p = new DateParser(); p.parse( "2011" ); p.parse( "2011-02" ); p.parse( "2011-02-12" ); p.parse( "2011-03-01T13" ); p.parse( "2011-02-01T13:00" ); p.parse( "2011-02-01T13:00:00" ); p.parse( "2011-02-01T13:00:00Z" ); p.parse( "2011-02-01T13:00:00+01:00" ); p.parse( "2011-02-01T13:00:00-03:00" ); try { p.parse( "" ); throw new Exception("Invalid date passed!"); } catch (InvalidDateException e) {} try { p.parse( "2011-" ); throw new Exception("Invalid date passed!"); } catch (InvalidDateException e) {} try { p.parse( "2011-02-" ); throw new Exception("Invalid date passed!"); } catch (InvalidDateException e) {} try { p.parse( "2011-02-01T" ); throw new Exception("Invalid date passed!"); } catch (InvalidDateException e) {} try { p.parse( "2011-02-01T13:" ); throw new Exception("Invalid date passed!"); } catch (InvalidDateException e) {} try { p.parse( "2011-02-01T13:00:" ); throw new Exception("Invalid date passed!"); } catch (InvalidDateException e) {} try { p.parse( "2011-02-01T13:00:00T" ); throw new Exception("Invalid date passed!"); } catch (InvalidDateException e) {} try { p.parse( "2011-02-01T13:00:00+01" ); throw new Exception("Invalid date passed!"); } catch (InvalidDateException e) {} try { p.parse( "2011-02-01T13:00:00+01:" ); throw new Exception("Invalid date passed!"); } catch (InvalidDateException e) {} try { p.parse( "2011-02-01T13:00:00-03" ); throw new Exception("Invalid date passed!"); } catch (InvalidDateException e) {} try { p.parse( "2011-02-01T13:00:00-03:" ); throw new Exception("Invalid date passed!"); } catch (InvalidDateException e) {} try { p.parse( "2011-02-01T13:00:00-03:AA" ); throw new Exception("Invalid date passed!"); } catch (InvalidDateException e) {} try { p.parse( "20a1" ); throw new Exception("Invalid date passed!"); } catch (InvalidDateException e) {} try { p.parse( " 2" ); throw new Exception("Invalid date passed!"); } catch (InvalidDateException e) {} try { p.parse( "2011-02-29" ); throw new Exception("Invalid date passed!"); } catch (InvalidDateException e) {} try { p.parse( "2011-02-01T13:00:00.123aqb" ); throw new Exception("Invalid date passed!"); } catch (InvalidDateException e) {} try { p.parse( "1994-11-05T13:15:30Zab" ); throw new Exception("Invalid date passed!"); } catch (InvalidDateException e) {} } public static void main(String[] args) { try { new DateParserTest().testisISO8601Date(); outWriter.println("Passed all tests!"); } catch (Exception e) { outWriter.println("Fail:"); e.printStackTrace(); } } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/util/FeatureEnum.java0000644000175000017500000000623213017276730025236 0ustar eugeneeugene/* * Copyright (c) 2011 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.util; public enum FeatureEnum { AUDIO("audio element"), CHARS_COUNT("characters count"), COMPRESSED_SIZE("compressed size"), COMPRESSION_METHOD("compression method"), CREATION_DATE("creation date"), DC_CONTRIBUTOR("contributor"), DC_CREATOR("creator"), DC_DATE("date"), DC_DESCRIPTION("description"), DC_LANGUAGE("language"), DC_PUBLISHER("publisher"), DC_RIGHTS("rights"), DC_SUBJECT("subject"), DC_TITLE("title"), DECLARED_MIMETYPE("declared mimetype"), DICTIONARY("dictiobary"), EPUB_RENDITIONS_COUNT("EPUB renditions count"), EXEC_MODE("execution mode"), FIGURE("figure element"), FONT_EMBEDDED("font embedded"), FONT_REFERENCE("font reference"), FORMAT_NAME("format name"), FORMAT_VERSION("format version"), HAS_ENCRYPTION("hasEncryption"), HAS_FIXED_LAYOUT("hasFixedLayout"), HAS_HTML4("html 4"), HAS_HTML5("html 5"), HAS_MICRODATA("microdata"), HAS_NCX("Has ncx file"), HAS_RDFA("RDFa"), HAS_SCRIPTS("hasScripts"), HAS_SIGNATURES("hasSignatures"), INDEX("index"), IS_LINEAR("linear"), IS_SPINEITEM("is spine item"), ITEMS_COUNT("items count"), LOA("list of audios"), LOI("list of illustrations"), LOT("list of tables"), LOV("list of videos"), MODIFIED_DATE("modification date"), NAVIGATION_ORDER("navigation order"), PAGE_BREAK("epub:page-break"), PAGE_LIST("epub:page-list"), PAGES_COUNT("pages count"), REFERENCE("reference"), RENDITION_LAYOUT("rendition:layout"), RENDITION_ORIENTATION("rendition:orientation"), RENDITION_SPREAD("rendition:spread"), RESOURCE("resource"), SCRIPT("script"), SECTIONS("sections"), SHA_256("SHA-256"), SIZE("size"), SPINE_INDEX("spine index"), TABLE("table element"), TOC_LINKS("ToC links"), TOOL_DATE("tool date"), TOOL_NAME("tool name"), TOOL_VERSION("tool version"), UNIQUE_IDENT("unique identifier"), VIDEO("video element"); private final String feature; FeatureEnum(String feature) { this.feature = feature; } public String toString() { return feature; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/util/NamespaceHelper.java0000644000175000017500000002006613017276730026053 0ustar eugeneeugenepackage com.adobe.epubcheck.util; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.messages.MessageId; import org.xml.sax.Attributes; import org.xml.sax.Locator; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Stack; import java.util.regex.Matcher; import java.util.regex.Pattern; public class NamespaceHelper { private long id = 0; private static HashSet expectedNamespaces = new HashSet(); static { expectedNamespaces.add(""); // don't report on the default (empty) namespace expectedNamespaces.add(EpubConstants.EpubTypeNamespaceUri); expectedNamespaces.add(EpubConstants.XmlNamespaceUri); expectedNamespaces.add(EpubConstants.HtmlNamespaceUri); expectedNamespaces.add(EpubConstants.OpfNamespaceUri); expectedNamespaces.add(EpubConstants.OpenDocumentContainerNamespaceUri); expectedNamespaces.add(EpubConstants.DCElements); } private class IdHashMap extends HashMap { final long id; public long getId() { return id; } public IdHashMap(long id) { super(); this.id = id; } public IdHashMap(long id, Map m) { super(m); this.id = id; } } private static boolean isExpectedNamespace(String uri) { return (uri != null) ? expectedNamespaces.contains(uri) : false; } private class NamespaceInstance { private long id; private String prefix; private String uri; private EPUBLocation location; private boolean inUse; private Pattern prefixPattern; public NamespaceInstance(long id, String prefix, String uri, EPUBLocation location) { setId(id); setPrefix(prefix); setUri(uri); setLocation(location); setInUse(false); setPrefixPattern(Pattern.compile("^" + prefix + ":.+")); } public long getId() { return id; } public void setId(long id) { this.id = id; } public String getPrefix() { return prefix; } public void setPrefix(String prefix) { this.prefix = prefix; } public String getUri() { return uri; } public void setUri(String uri) { this.uri = uri; } public EPUBLocation getLocation() { return location; } public void setLocation(EPUBLocation location) { this.location = location; } public boolean isInUse() { return inUse; } public void setInUse(boolean inUse) { this.inUse = inUse; } public Pattern getPrefixPattern() { return prefixPattern; } public void setPrefixPattern(Pattern prefixPattern) { this.prefixPattern = prefixPattern; } @Override public String toString() { if (getUri() != null && getUri().length() > 0) { return "xmlns" + this.getPrefix() + "=" + getUri(); } else { return "xmlns" + this.getPrefix(); } } } private class NamespaceContext { private long id; private int useCount; private IdHashMap prefixMap; private IdHashMap uriMap; public NamespaceContext(long id) { this.useCount = 1; this.id = id; this.prefixMap = new IdHashMap(id); this.uriMap = new IdHashMap(id); } public NamespaceContext(long id, NamespaceContext other) { other.decrementUseCount(); this.useCount = 1; this.id = id; this.prefixMap = new IdHashMap(id, other.getPrefixMap()); this.uriMap = new IdHashMap(id, other.getUriMap()); } public long getId() { return id; } public int getUseCount() { return useCount; } public int incrementUseCount() { return ++useCount; } public int decrementUseCount() { return --useCount; } public IdHashMap getPrefixMap() { return prefixMap; } public IdHashMap getUriMap() { return uriMap; } } private Stack contexts = new Stack(); public NamespaceHelper() { contexts.push(new NamespaceContext(id++)); } private void pushContext() { ++id; NamespaceContext currentContext = contexts.peek(); currentContext.incrementUseCount(); } private String findMatchingPrefix(String qName) { NamespaceContext currentContext = contexts.peek(); for (NamespaceInstance instance : currentContext.getUriMap().values()) { Pattern p = instance.getPrefixPattern(); Matcher m = p.matcher(qName); if (m.find()) { return instance.getPrefix(); } } return null; } public String findPrefixForUri(String uri) { String prefix = null; NamespaceContext currentContext = contexts.peek(); if (uri != null) { NamespaceInstance instance = currentContext.getUriMap().get(uri); if (instance != null) { prefix = instance.getPrefix(); } } return prefix; } private void recordPrefixUse(String prefix) { NamespaceContext currentContext = contexts.peek(); String uri = currentContext.getPrefixMap().get(prefix); if (uri != null) { NamespaceInstance instance = currentContext.getUriMap().get(uri); if (instance != null && !instance.isInUse()) { instance.setInUse(true); } } } private void recordUriUse(String uri) { NamespaceContext currentContext = contexts.peek(); if (uri != null) { NamespaceInstance instance = currentContext.getUriMap().get(uri); if (instance != null && !instance.isInUse()) { instance.setInUse(true); } } } private void popContext(Report report) { NamespaceContext currentContext = contexts.peek(); if (0 == currentContext.decrementUseCount()) { for (NamespaceInstance instance : currentContext.getUriMap().values()) { // report on namespaces that are in this scope (ie, its id matches) and its not in use if (currentContext.getId() == instance.getId() && !instance.isInUse()) { report.message(MessageId.HTM_044, instance.getLocation(), instance.getUri()); } } contexts.pop(); } } public void declareNamespace(String prefix, String uri, EPUBLocation location, Report report) { NamespaceContext currentContext = contexts.peek(); if (id != currentContext.getId()) { NamespaceContext newContext = new NamespaceContext(id, currentContext); contexts.push(newContext); currentContext = newContext; } currentContext.getPrefixMap().put(prefix, uri); currentContext.getUriMap().put(uri, new NamespaceInstance(id, prefix, uri, location)); if (!isExpectedNamespace(uri)) { report.message(MessageId.HTM_010, location, uri); } } static final Pattern xmlnsUriPattern = Pattern.compile("xmlns:([a-zA-Z]+)"); public void onStartElement(String fileName, Locator locator, String uri, String qName, Attributes attributes, Report report) { pushContext(); for (int i = 0; i < attributes.getLength(); ++i) { String aqName = attributes.getQName(i); Matcher m = xmlnsUriPattern.matcher(aqName); if (m.matches()) { // the group holds the prefix, the value holds the uri declareNamespace(m.group(1), attributes.getValue(i), EPUBLocation.create(fileName, locator.getLineNumber(), locator.getColumnNumber(), aqName), report); } else { String foundPrefix = findMatchingPrefix(aqName); if (foundPrefix != null) { recordPrefixUse(foundPrefix); } } } String prefix = findMatchingPrefix(qName); if (prefix != null && prefix.length() > 0) { recordPrefixUse(prefix); } if (uri != null && uri.length() > 0) { recordUriUse(uri); } } public void onEndElement(Report report) { popContext(report); } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/util/Archive.java0000644000175000017500000001547613017276730024411 0ustar eugeneeugenepackage com.adobe.epubcheck.util; import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.util.ArrayList; import java.util.zip.CRC32; import java.util.zip.CheckedInputStream; public class Archive { private ArrayList paths; private ArrayList names; private final File baseDir; private File epubFile; private String epubName; public Archive(String base, boolean save) { boolean deleteOnExit = !save; baseDir = makeCanonical(new File(base)); if (!baseDir.exists() || !baseDir.isDirectory()) { throw new RuntimeException("The path specified for the archive is invalid"); } epubName = baseDir.getName() + ".epub"; epubFile = new File(baseDir.getParent() + File.separator + epubName); if (deleteOnExit) { epubFile.deleteOnExit(); } paths = new ArrayList(); names = new ArrayList(); } public Archive(String base) { this(base, false); } public String getEpubName() { return epubName; } public File getEpubFile() { return epubFile; } public void deleteEpubFile() { if (!epubFile.delete()) { System.err.println("Unable to delete generated archive."); } } public void createArchive(File absoluteEpubFilePath) { this.epubFile = absoluteEpubFilePath; createArchive(); } public void createArchive() { // using commons compress to allow setting filename encoding pre java7 ZipArchiveOutputStream out = null; try { collectFiles(baseDir, ""); //make mimetype the first entry int mimetype = names.indexOf("mimetype"); if (mimetype > -1) { String name = names.remove(mimetype); String path = paths.remove(mimetype); names.add(0, name); paths.add(0, path); } else { System.err.println("No mimetype file found in expanded publication, output archive will be invalid"); } out = new ZipArchiveOutputStream(epubFile); out.setEncoding("UTF-8"); for (int i = 0; i < paths.size(); i++) { ZipArchiveEntry entry = new ZipArchiveEntry(new File(paths.get(i)), names.get(i)); if (i == 0 && mimetype > -1) { entry.setMethod(ZipArchiveEntry.STORED); entry.setSize(getSize(paths.get(i))); entry.setCrc(getCRC(paths.get(i))); } else { entry.setMethod(ZipArchiveEntry.DEFLATED); } out.putArchiveEntry(entry); FileInputStream in = null; try { in = new FileInputStream(paths.get(i)); byte[] buf = new byte[1024]; int len; while ((len = in.read(buf)) > 0) { out.write(buf, 0, len); } out.closeArchiveEntry(); } finally { if (in != null) { in.close(); } } } } catch (Exception e) { throw new RuntimeException(e.getMessage()); } finally { try { if (out != null) { out.flush(); out.finish(); out.close(); } } catch (IOException ignored) { } } } private File makeCanonical(File f) { if (f == null) { return null; } try { return f.getCanonicalFile(); } catch (IOException ignored) { return f.getAbsoluteFile(); } } private long getSize(String path) throws IOException { FileInputStream in = null; try { in = new FileInputStream(path); byte[] buf = new byte[1024]; int len; int size = 0; while ((len = in.read(buf)) > 0) { size += len; } return size; } finally { if (in != null) { in.close(); } } } private long getCRC(String path) throws IOException { CheckedInputStream cis = null; FileInputStream fis = null; try { fis = new FileInputStream(path); cis = new CheckedInputStream(fis, new CRC32()); byte[] buf = new byte[128]; while (cis.read(buf) >= 0) { // TODO: why is this loop empty? } } finally { if (fis != null) { fis.close(); } if (cis != null) { cis.close(); } } return cis.getChecksum().getValue(); } // public void createArchiveOld() { // collectFiles(baseDir, ""); // byte[] buf = new byte[1024]; // try { // // ZipOutputStream out = new ZipOutputStream((new FileOutputStream( // epubName))); // // int index = names.indexOf("mimetype"); // if (index >= 0) { // FileInputStream in = new FileInputStream(paths.get(index)); // // ZipEntry entry = new ZipEntry(names.get(index)); // entry.setMethod(ZipEntry.STORED); // int len, size = 0; // while ((len = in.read(buf)) > 0) // size += len; // // in = new FileInputStream(paths.get(index)); // // entry.setCompressedSize(size); // entry.setSize(size); // // CRC32 crc = new CRC32(); // entry.setCrc(crc.getValue()); // out.putNextEntry(entry); // // while ((len = in.read(buf)) > 0) { // crc.update(buf, 0, len); // out.write(buf, 0, len); // } // // entry.setCrc(crc.getValue()); // // paths.remove(index); // names.remove(index); // } // // for (int i = 0; i < paths.size(); i++) { // FileInputStream in = new FileInputStream(paths.get(i)); // // out.putNextEntry(new ZipEntry(names.get(i))); // // int len; // while ((len = in.read(buf)) > 0) { // out.write(buf, 0, len); // } // // out.closeEntry(); // in.close(); // } // // out.close(); // } catch (IOException e) { // } // } private void collectFiles(File dir, String dirName) { if (!dirName.equals("") && !dirName.endsWith("/")) { dirName = dirName + "/"; } File files[] = dir.listFiles(); assert files != null; for (int i = 0; i < files.length; i++) { // issue 256: ignore '.DS_Store', '._DS_Store', 'Thumbs.db' and 'ehthumbs.db' files if (files[i].isFile() && !files[i].getName().equals(".DS_Store") && !files[i].getName().equals("._DS_Store") && !files[i].getName().equals("Thumbs.db") && !files[i].getName().equals("ehthumbs.db")) { names.add(dirName + files[i].getName()); paths.add(files[i].getAbsolutePath()); // issue 256: ignore .git/ and .svn/ folders } else if (files[i].isDirectory() && !files[i].getName().equals(".svn") && !files[i].getName().equals(".git")) { collectFiles(files[i], dirName + files[i].getName() + "/"); } } } public void listFiles() { for (String name : names) { outWriter.println(name); } } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/util/URISchemes.java0000644000175000017500000000203613017276730024763 0ustar eugeneeugenepackage com.adobe.epubcheck.util; import java.util.Locale; import com.google.common.base.Enums; import com.google.common.base.Strings; public enum URISchemes { AAA, AAAS, ACAP, CAP, CID, CRID, DATA, DAV, DICT, DNS, FAX, FILE, FTP, GO, GOPHER, H323, HTTP, HTTPS, ICAP, IM, IMAP, INFO, IPP, IRC, IRIS, IRIS_BEEP, IRIS_XPC, IRIS_XPCS, IRIS_LWZ, JAVASCRIPT, LDAP, MAILTO, MID, MODEM, MSRP, MSRPS, MTQP, MUPDATE, NEWS, NFS, NNTP, OPAQUELOCKTOKEN, POP, PRES, RTSP, SERVICE, SHTTP, SIP, SIPS, SNMP, SOAP_BEEP, SOAP_BEEPS, TAG, TEL, TELNET, TFTP, THISMESSAGE, TIP, TV, URN, VEMMI, XMLRPC_BEEP, XMLRPC_BEEPS, XMPP, Z39_50R, Z39_50S, AFS, DTN, IAX, MAILSERVER, PACK, TN3270, PROSPERO, SNEWS, VIDEOTEX, WAIS; public static boolean contains(String scheme) { return Enums.getIfPresent(URISchemes.class, Strings.nullToEmpty(scheme).toUpperCase(Locale.ROOT).replace('.', '_')).isPresent(); } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/util/HandlerUtil.java0000644000175000017500000000270213017276730025227 0ustar eugeneeugenepackage com.adobe.epubcheck.util; import org.w3c.dom.Element; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.messages.MessageId; import com.adobe.epubcheck.xml.XMLParser; public class HandlerUtil { public static void checkXMLVersion(XMLParser parser) { String version = parser.getXMLVersion(); //I don't think it is possible for this to be null. A null version would cause a SAX parser error. if (version == null) { parser.getReport().message(MessageId.HTM_002, EPUBLocation.create(parser.getResourceName(), parser.getLineNumber(), parser.getColumnNumber())); } else if (!"1.0".equals(version)) { parser.getReport().message(MessageId.HTM_001, EPUBLocation.create(parser.getResourceName(), parser.getLineNumber(), parser.getColumnNumber()), version); } } public static int getElementLineNumber(Element e) { return getElementIntAttribute( e, EpubConstants.ElementLineNumberAttribute); } public static int getElementColumnNumber(Element e) { return getElementIntAttribute( e, EpubConstants.ElementColumnNumberAttribute); } static int getElementIntAttribute(Element e, String whichAttribute) { int val = -1; String number = e.getAttribute(whichAttribute); if (number != null) { try { val = Integer.parseInt(number.trim()); } catch (NumberFormatException ex) { val = -1; } } return val; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/util/DateParser.java0000755000175000017500000002512613017276730025056 0ustar eugeneeugenepackage com.adobe.epubcheck.util; import java.util.*; /** * Date parser for the ISO 8601 format. * * Initial code taken from the jigsaw project (W3C license [1]) and modified consistently to * apply further checks that were missing, for example the initial code reported * 2011- as valid date. * See also: * http://www.w3.org/TR/1998/NOTE-datetime-19980827 * * @author mircea@oxygenxml.com Initial version and fixes. * @author mihaela@sync.ro Initial version and fixes. * * @author george@oxygenxml.com Additional fixes. */ /** * **** [1] W3C license (jigsaw license) ***** *

* Jigsaw Copying Conditions *

* W3C IPR SOFTWARE NOTICE *

* Copyright \u00a9 1995-1998 World Wide Web Consortium, (Massachusetts Institute of * Technology, Institut National de Recherche en Informatique et en * Automatique, Keio University). All Rights Reserved. * http://www.w3.org/Consortium/Legal/ *

* This W3C work (including software, documents, or other related items) is * being provided by the copyright holders under the following license. By * obtaining, using and/or copying this work, you (the licensee) agree that you * have read, understood, and will comply with the following terms and * conditions: *

* Permission to use, copy, and modify this software and its documentation, * with or without modification, for any purpose and without fee or royalty is * hereby granted, provided that you include the following on ALL copies of the * software and documentation or portions thereof, including modifications, * that you make: *

* 1. The full text of this NOTICE in a location viewable to users of the * redistributed or derivative work. * 2. Any pre-existing intellectual property disclaimers, notices, or terms * and conditions. If none exist, a short notice of the following form * (hypertext is preferred, text is permitted) should be used within the * body of any redistributed or derivative code: "Copyright \u00a9 World Wide * Web Consortium, (Massachusetts Institute of Technology, Institut * National de Recherche en Informatique et en Automatique, Keio * University). All Rights Reserved. http://www.w3.org/Consortium/Legal/" * 3. Notice of any changes or modifications to the W3C files, including the * date changes were made. (We recommend you provide URIs to the location * from which the code is derived). *

* In addition, creators of derivitive works must include the full text of this * NOTICE in a location viewable to users of the derivitive work. *

* THIS SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS * MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT * LIMITED TO, WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR * PURPOSE OR THAT THE USE OF THE SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE * ANY THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. *

* COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR * CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR * DOCUMENTATION. *

* The name and trademarks of copyright holders may NOT be used in advertising * or publicity pertaining to the software without specific, written prior * permission. Title to copyright in this software and any associated * documentation will at all times remain with copyright holders. *

* ____________________________________ *

* This formulation of W3C's notice and license became active on August 14 * 1998. See the older formulation for the policy prior to this date. Please * see our Copyright FAQ for common questions about using materials from our * site, including specific terms and conditions for packages like libwww, * Amaya, and Jigsaw. Other questions about this notice can be directed to * site-policy@w3.org . *

*

*

*

* webmaster * (last updated 14-Aug-1998) * **** end W3C license (jigsaw license) ***** */ public class DateParser { /** * Check if the next token, if exists, has a given value and that the * provided string tokenizer has more tokens after that. It consumes * the token checked against the expected value from the string tokenizer. * * @param st The StringTokenizer to check. * @param token The value expected for the next token. * @return true if the token matches the value and there are more tokens. * false if there are no more tokens and we do not have a token to check. * @throws InvalidDateException If the token does not match the value or if there are no * more tokens after the token that matches the expected value. */ private boolean checkValueAndNext(StringTokenizer st, String token) throws InvalidDateException { if (!st.hasMoreTokens()) { return false; } String t = st.nextToken(); if (!t.equals(token)) { throw new InvalidDateException("Unexpected: " + t); } if (!st.hasMoreTokens()) { throw new InvalidDateException("Incomplete date."); } return true; } /** * Check if a given date is an iso8601 date. * * @param iso8601Date The date to be checked. * @return true if the date is an iso8601 date. * @throws InvalidDateException */ private Calendar getCalendar(String iso8601Date) throws InvalidDateException { // YYYY-MM-DDThh:mm:ss.sTZD StringTokenizer st = new StringTokenizer(iso8601Date, "-T:.+Z", true); if (!st.hasMoreTokens()) { throw new InvalidDateException("Empty Date"); } Calendar calendar = new GregorianCalendar(TimeZone.getTimeZone("UTC")); calendar.clear(); try { // Year if (st.hasMoreTokens()) { int year = Integer.parseInt(st.nextToken()); calendar.set(Calendar.YEAR, year); } else { return calendar; } // Month if (checkValueAndNext(st, "-")) { int month = Integer.parseInt(st.nextToken()) - 1; calendar.set(Calendar.MONTH, month); } else { return calendar; } // Day if (checkValueAndNext(st, "-")) { int day = Integer.parseInt(st.nextToken()); calendar.set(Calendar.DAY_OF_MONTH, day); } else { return calendar; } // Hour if (checkValueAndNext(st, "T")) { int hour = Integer.parseInt(st.nextToken()); calendar.set(Calendar.HOUR_OF_DAY, hour); } else { calendar.set(Calendar.HOUR_OF_DAY, 0); calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.SECOND, 0); calendar.set(Calendar.MILLISECOND, 0); return calendar; } // Minutes if (checkValueAndNext(st, ":")) { int minutes = Integer.parseInt(st.nextToken()); calendar.set(Calendar.MINUTE, minutes); } else { calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.SECOND, 0); calendar.set(Calendar.MILLISECOND, 0); return calendar; } if (!st.hasMoreTokens()) { return calendar; } // Not mandatory now // Seconds String tok = st.nextToken(); if (tok.equals(":")) { // seconds if (st.hasMoreTokens()) { int secondes = Integer.parseInt(st.nextToken()); calendar.set(Calendar.SECOND, secondes); if (!st.hasMoreTokens()) { return calendar; } // decimal fraction of a second tok = st.nextToken(); if (tok.equals(".")) { String nt = st.nextToken(); while (nt.length() < 3) { nt += "0"; } if (nt.length() > 3) { // check the other part from the decimal fraction to be formed only from digits for (int i = 3; i < nt.length(); i++) { if (!Character.isDigit(nt.charAt(i))) { throw new InvalidDateException("Invalid digit in the decimal fraction of a second: " + nt.charAt(i)); } } } nt = nt.substring(0, 3); //Cut trailing chars.. int millisec = Integer.parseInt(nt); calendar.set(Calendar.MILLISECOND, millisec); if (!st.hasMoreTokens()) { return calendar; } tok = st.nextToken(); } else { calendar.set(Calendar.MILLISECOND, 0); } } else { throw new InvalidDateException("No secondes specified"); } } else { calendar.set(Calendar.SECOND, 0); calendar.set(Calendar.MILLISECOND, 0); } // Time zone if (!tok.equals("Z")) { // UTC if (!(tok.equals("+") || tok.equals("-"))) { throw new InvalidDateException("only Z, + or - allowed"); } boolean plus = tok.equals("+"); if (!st.hasMoreTokens()) { throw new InvalidDateException("Missing hour field"); } int tzhour = Integer.parseInt(st.nextToken()); int tzmin; if (checkValueAndNext(st, ":")) { tzmin = Integer.parseInt(st.nextToken()); } else { throw new InvalidDateException("Missing minute field"); } if (plus) { calendar.add(Calendar.HOUR, -tzhour); calendar.add(Calendar.MINUTE, -tzmin); } else { calendar.add(Calendar.HOUR, tzhour); calendar.add(Calendar.MINUTE, tzmin); } } else { if (st.hasMoreTokens()) { throw new InvalidDateException("Unexpected field at the end of the date field: " + st.nextToken()); } } } catch (NumberFormatException ex) { throw new InvalidDateException("[" + ex.getMessage() + "] is not an integer"); } return calendar; } /** * @param iso8601DateAsString The date parameter as a String. * @return The corresponding Date object representing the result of parsing the date parameter. * @throws InvalidDateException In case of an invalid date. */ public Date parse(String iso8601DateAsString) throws InvalidDateException { Calendar calendar = getCalendar(iso8601DateAsString); try { calendar.setLenient(false); return calendar.getTime(); } catch (Exception e) { throw new InvalidDateException(iso8601DateAsString + " " + e.getClass().toString() + " " + e.getMessage()); } } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/util/URLResourceProvider.java0000644000175000017500000000323213017276730026700 0ustar eugeneeugene/* * Copyright (c) 2011 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.util; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; public class URLResourceProvider implements GenericResourceProvider { private URL url; public URLResourceProvider(String url) { try { this.url = new URL(url); } catch (MalformedURLException e) { throw new RuntimeException(e); } } public InputStream getInputStream(String ignore) throws IOException { return url.openStream(); } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/util/XmpReportImpl.java0000644000175000017500000002302113017276730025573 0ustar eugeneeugenepackage com.adobe.epubcheck.util; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.reporting.CheckMessage; public class XmpReportImpl extends XmlReportAbstract { public XmpReportImpl(PrintWriter out, String ePubName, String versionEpubCheck) { super(out, ePubName, versionEpubCheck); } @SuppressWarnings("unchecked") public int generateReport() { if (out == null) return 1; int returnCode = 1; generationDate = fromTime(System.currentTimeMillis()); try { // Declared the wanted prefix addPrefixNamespace("x", "adobe:ns:meta/"); addPrefixNamespace("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#"); addPrefixNamespace("dc", "http://purl.org/dc/elements/1.1/"); addPrefixNamespace("xmp", "http://ns.adobe.com/xap/1.0/"); addPrefixNamespace("xmpTPg", "http://ns.adobe.com/xap/1.0/t/pg/"); addPrefixNamespace("stFnt", "http://ns.adobe.com/xap/1.0/sType/Font#"); addPrefixNamespace("extended-properties", "http://schemas.openxmlformats.org/officeDocument/2006/extended-properties/"); addPrefixNamespace("premis", "http://www.loc.gov/premis/rdf/v1#"); // Generate the information startElement("x:xmpmeta", KeyValue.with("xmlns:x", "adobe:ns:meta/"), KeyValue.with("x:xmptk", "Adobe XMP Core 5.1.0-jc003")); startElement("rdf:RDF", KeyValue.with("xmlns:rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#")); List> attrs = new ArrayList>(); attrs.add(KeyValue.with("rdf:about", "")); attrs.add(KeyValue.with("xmlns:dc", "http://purl.org/dc/elements/1.1/")); attrs.add(KeyValue.with("xmlns:xmp", "http://ns.adobe.com/xap/1.0/")); attrs.add(KeyValue.with("xmlns:xmpTPg", "http://ns.adobe.com/xap/1.0/t/pg/")); attrs.add(KeyValue.with("xmlns:stFnt", "http://ns.adobe.com/xap/1.0/sType/Font#")); // Unused core-properties like keywords, lastModifiedBy, revision, category // attrs.add(KeyValue.with("xmlns:cp", "http://schemas.openxmlformats.org/package/2006/metadata/core-properties/")); // Used extended-properties for Characters // but could be for Words, Lines, Paragraphs, CharactersWithSpaces, Template, DocSecurity, Application, AppVersion attrs.add(KeyValue.with("xmlns:extended-properties", "http://schemas.openxmlformats.org/officeDocument/2006/extended-properties/")); attrs.add(KeyValue.with("xmlns:premis", "http://www.loc.gov/premis/rdf/v1#")); if (formatName == null) { attrs.add(KeyValue.with("dc:format", "application/octet-stream")); } else { if (formatVersion == null) { attrs.add(KeyValue.with("dc:format", formatName)); } else { attrs.add(KeyValue.with("dc:format", formatName + ";version=" + formatVersion)); } } if (creationDate != null) { attrs.add(KeyValue.with("xmp:CreateDate", creationDate)); } if (charsCount != 0) { attrs.add(KeyValue.with("extended-properties:Characters", Long.toString(charsCount))); } if (pagesCount != 0) { attrs.add(KeyValue.with("xmpTPg:NPages", Long.toString(pagesCount))); } if (publisher != null) { attrs.add(KeyValue.with("dc:publisher", publisher)); } attrs.add(KeyValue.with("dc:identifier", identifier)); if (language != null) { attrs.add(KeyValue.with("dc:language", language)); } startElement("rdf:Description", attrs); // DC if (!creators.isEmpty()) { startElement("dc:creator"); startElement("rdf:Seq"); for (String creator : creators) { generateElement("rdf:li", creator); } endElement("rdf:Seq"); endElement("dc:creator"); } if (!titles.isEmpty()) { startElement("dc:title"); startElement("rdf:Alt"); boolean first = true; for (String title : titles) { if (first) { generateElement("rdf:li", title.trim(), KeyValue.with("xml:lang", "x-default")); first = false; } else { generateElement("rdf:li", title); } } endElement("rdf:Alt"); endElement("dc:title"); } if (!subjects.isEmpty()) { startElement("dc:subject"); startElement("rdf:Bag"); for (String subject : subjects) { generateElement("rdf:li", subject); } endElement("rdf:Bag"); endElement("dc:subject"); } // Fonts if (!embeddedFonts.isEmpty() || !refFonts.isEmpty()) { startElement("xmpTPg:Fonts"); startElement("rdf:Bag"); for (String font : embeddedFonts) { generateFont(font, true); } for (String font : refFonts) { generateFont(font, false); } endElement("rdf:Bag"); endElement("xmpTPg:Fonts"); } // Premis:event startElement("premis:hasEvent", KeyValue.with("rdf:parseType", "Resource")); generateElement("premis:hasEventDateTime", generationDate, KeyValue.with("rdf:datatype", "http://www.w3.org/2001/XMLSchema#dateTime")); generateElement("premis:hasEventType", null, KeyValue.with("rdf:resource", "http://id.loc.gov/vocabulary/preservation/eventType/val")); if (fatalErrors.isEmpty() && errors.isEmpty()) { generateElement("premis:hasEventDetail", "Well-formed"); } else { generateElement("premis:hasEventDetail", "Not well-formed"); } if (fatalErrors.size() + errors.size() + warns.size() + hints.size() != 0) { startElement("premis:hasEventOutcomeInformation"); startElement("rdf:Seq"); generateEventOutcome(fatalErrors, "FATAL"); generateEventOutcome(errors, "ERROR"); generateEventOutcome(warns, "WARN"); generateEventOutcome(hints, "HINT"); endElement("rdf:Seq"); endElement("premis:hasEventOutcomeInformation"); } startElement("premis:hasEventRelatedAgent", KeyValue.with("rdf:parseType", "Resource")); generateElement("premis:hasAgentType", null, KeyValue.with("rdf:resource", "http://id.loc.gov/vocabulary/preservation/agentType/sof")); if (epubCheckVersion == null) { generateElement("premis:hasAgentName", epubCheckName); } else { generateElement("premis:hasAgentName", epubCheckName + " " + epubCheckVersion); } endElement("premis:hasEventRelatedAgent"); endElement("premis:hasEvent"); // Significant properties startElement("premis:hasSignificantProperties"); startElement("rdf:Bag"); generateSignificantProperty("renditionLayout", hasFixedLayout ? "fixed-layout" : "reflowable"); generateSignificantProperty("isScripted", Boolean.toString(hasScripts)); generateSignificantProperty("hasEncryption", Boolean.toString(hasEncryption)); generateSignificantProperty("hasAudio", Boolean.toString(hasAudio)); generateSignificantProperty("hasVideo", Boolean.toString(hasVideo)); generateSignificantProperty("hasSignatures", Boolean.toString(hasSignatures)); generateSignificantProperty("hasAllFontsEmbedded", Boolean.toString(refFonts.isEmpty())); int nRefs = 0; for (String ref : references) { nRefs++; if (nRefs > 50) { generateSignificantProperty("reference", "" + (references.size() - 50) + " more references"); break; } generateSignificantProperty("reference", ref); } endElement("rdf:Bag"); endElement("premis:hasSignificantProperties"); endElement("rdf:Description"); endElement("rdf:RDF"); endElement("x:xmpmeta"); returnCode = 0; } catch (Exception e) { System.err.println("Exception encountered: " + e.getMessage()); returnCode = 1; } return returnCode; } protected void generateFont(String font, boolean embeded) { // stFnt:fontName, stFnt:fontType, stFnt:versionString, stFnt:composite, stFnt:fontFileName String[] elFont = font.split(","); List> attrs = new ArrayList>(); attrs.add(KeyValue.with("stFnt:fontFamily", capitalize(elFont[0]))); String fontFace = ""; for (int i = 1; i < elFont.length; i++) { fontFace += capitalize(elFont[i]) + " "; } fontFace = fontFace.trim(); if (fontFace.length() == 0) { attrs.add(KeyValue.with("stFnt:fontFace", "Regular")); } else { attrs.add(KeyValue.with("stFnt:fontFace", fontFace)); } generateElement("rdf:li", null, attrs); } @SuppressWarnings("unchecked") private void generateEventOutcome(List messages, String sev) { for (CheckMessage c : messages) { startElement("rdf:li", KeyValue.with("rdf:parseType", "Resource")); generateElement("premis:hasEventOutcome", c.getID() + ", " + sev + ", " + c.getMessage()); if (c.getLocations().size() != 0) { startElement("premis:hasEventOutcomeDetail"); startElement("rdf:Seq"); String previousValue = ""; for (EPUBLocation ml : c.getLocations()) { String value = PathUtil.removeWorkingDirectory(ml.getPath()); if (ml.getLine() > 0 || ml.getColumn() > 0) { value += " (" + ml.getLine() + "-" + ml.getColumn() + ")"; } if (!previousValue.equals(value)) { generateElement("rdf:li", null, KeyValue.with("premis:hasEventOutcomeDetailNote", value)); previousValue = value; } } endElement("rdf:Seq"); endElement("premis:hasEventOutcomeDetail"); } endElement("rdf:li"); } } private void generateSignificantProperty(String property, String value) { // Significant property List> attrs = new ArrayList>(); attrs.add(KeyValue.with("premis:hasSignificantPropertiesType", property)); attrs.add(KeyValue.with("premis:hasSignificantPropertiesValue", value)); generateElement("rdf:li", null, attrs); } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/bitmap/0000755000175000017500000000000013017276730022447 5ustar eugeneeugeneepubcheck-4.0.2/src/main/java/com/adobe/epubcheck/bitmap/BitmapChecker.java0000755000175000017500000002356713017276730026033 0ustar eugeneeugene/* * Copyright (c) 2007 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.bitmap; import java.awt.image.BufferedImage; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.Iterator; import javax.imageio.ImageIO; import javax.imageio.ImageReader; import javax.imageio.stream.ImageInputStream; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.messages.MessageId; import com.adobe.epubcheck.ocf.OCFPackage; import com.adobe.epubcheck.ocf.OCFZipPackage; import com.adobe.epubcheck.opf.ContentChecker; import com.adobe.epubcheck.util.CheckUtil; public class BitmapChecker implements ContentChecker { private final OCFPackage ocf; private final Report report; private final String path; private final String mimeType; private static final int HEIGHT_MAX = 2 * 1080; private static final int WIDTH_MAX = 2 * 1920; private static final long IMAGESIZE_MAX = 4 * 1024 * 1024; BitmapChecker(OCFPackage ocf, Report report, String path, String mimeType) { this.ocf = ocf; this.report = report; this.path = path; this.mimeType = mimeType; } private void checkHeader(byte[] header) { boolean passed; if (mimeType.equals("image/jpeg")) { passed = header[0] == (byte) 0xFF && header[1] == (byte) 0xD8; } else if (mimeType.equals("image/gif")) { passed = header[0] == (byte) 'G' && header[1] == (byte) 'I' && header[2] == (byte) 'F' && header[3] == (byte) '8'; } else { passed = !mimeType.equals("image/png") || header[0] == (byte) 0x89 && header[1] == (byte) 'P' && header[2] == (byte) 'N' && header[3] == (byte) 'G'; } if (!passed) { report.message(MessageId.OPF_029, EPUBLocation.create(this.ocf.getName()), path, mimeType); } } /** * Gets image dimensions for given file * * @param imgFileName image file * @return dimensions of image * @throws IOException if the file is not a known image */ public ImageHeuristics getImageSizes(String imgFileName) throws IOException { int pos = imgFileName.lastIndexOf("."); if (pos == -1) { throw new IOException("No extension for file: " + imgFileName); } String suffix = imgFileName.substring(pos + 1); File tempFile = null; if ("svg".compareToIgnoreCase(suffix) == 0) { tempFile = getImageFile(ocf, imgFileName); if (tempFile != null) { long tempFileLength = tempFile.length(); if (ocf.getClass() == OCFZipPackage.class) { tempFile.delete(); } return new ImageHeuristics(0, 0, tempFileLength); } return null; } // Determine format by file extension and by inspecting the file tempFile = getImageFile(ocf, imgFileName); String formatFromInputStream = null; String formatFromSuffix = null; ImageInputStream imageInputStream = ImageIO.createImageInputStream(tempFile); Iterator imageReaderIteratorFromInputStream = ImageIO.getImageReaders(imageInputStream); while (imageReaderIteratorFromInputStream.hasNext()) { ImageReader imageReaderFromInputStream = imageReaderIteratorFromInputStream.next(); formatFromInputStream = imageReaderFromInputStream.getFormatName(); Iterator imageReaderIteratorFromSuffix = ImageIO.getImageReadersBySuffix(suffix); while (imageReaderIteratorFromSuffix.hasNext()) { ImageReader reader = imageReaderIteratorFromSuffix.next(); formatFromSuffix = reader.getFormatName(); if (formatFromSuffix != null && formatFromSuffix.equals(formatFromInputStream)) break; } if (formatFromSuffix != null && formatFromSuffix.equals(formatFromInputStream)) break; } imageInputStream.close(); if (formatFromSuffix != null && formatFromSuffix.equals(formatFromInputStream)) { // file format and file extension matches; read image file try { BufferedImage image = ImageIO.read(tempFile); if (image == null) { report.message(MessageId.PKG_021, EPUBLocation.create(imgFileName)); return null; } else { int width = image.getWidth(); int height = image.getHeight(); return new ImageHeuristics(width, height, tempFile.length()); } } catch (IOException e) { report.message(MessageId.PKG_021, EPUBLocation.create(imgFileName)); return null; } catch (IllegalArgumentException argex) { report.message(MessageId.PKG_021, EPUBLocation.create(imgFileName)); return null; } finally { if (ocf.getClass() == OCFZipPackage.class) { tempFile.delete(); } } } else { if (ocf.getClass() == OCFZipPackage.class) { tempFile.delete(); } if (formatFromSuffix != null) { // file format and file extension differs report.message(MessageId.PKG_022, EPUBLocation.create(imgFileName), formatFromInputStream, suffix); return null; } else { // file format could not be determined throw new IOException("Not a known image file: " + imgFileName); } } } private File getImageFile(OCFPackage ocf, String imgFileName) throws IOException { if (ocf.getClass() == OCFZipPackage.class) { return getTempImageFile((OCFZipPackage) ocf, imgFileName); } else { return new File(ocf.getPackagePath() + File.separator + imgFileName); } } public class ImageHeuristics { public int width; public int height; public long length; public ImageHeuristics(int width, int height, long length) { this.width = width; this.height = height; this.length = length; } } private File getTempImageFile(OCFZipPackage ocf, String imgFileName) throws IOException { File file = null; FileOutputStream os = null; InputStream is = null; try { int pos = imgFileName.lastIndexOf("."); if (pos == -1) { throw new IOException("No extension for file: " + imgFileName); } String suffix = imgFileName.substring(pos); String prefix = "img"; file = File.createTempFile(prefix, suffix); os = new FileOutputStream(file); is = ocf.getInputStream(imgFileName); if (is == null) { return null; } byte[] bytes = new byte[32 * 1024]; int read; while ((read = is.read(bytes)) > 0) { os.write(bytes, 0, read); } } finally { if (os != null) { os.flush(); os.close(); } if (is != null) { is.close(); } } return file; //To change body of created methods use File | Settings | File Templates. } private void checkImageDimensions(String imageFileName) { try { ImageHeuristics h = getImageSizes(imageFileName); if (h != null) { if (h.height >= HEIGHT_MAX || h.width >= WIDTH_MAX) { report.message(MessageId.OPF_051, EPUBLocation.create(imageFileName)); } if (h.length >= IMAGESIZE_MAX) { report.message(MessageId.OPF_057, EPUBLocation.create(imageFileName)); } } } catch (IOException ex) { report.message(MessageId.PKG_021, EPUBLocation.create(imageFileName) ); } catch (LinkageError error) { report.message(MessageId.RSC_022, EPUBLocation.create(imageFileName)); } } public void runChecks() { if (!ocf.hasEntry(path)) { report.message(MessageId.RSC_001, EPUBLocation.create(this.ocf.getName()), path); } else if (!ocf.canDecrypt(path)) { report.message(MessageId.RSC_004, EPUBLocation.create(this.ocf.getName()), path); } else { InputStream in = null; try { in = ocf.getInputStream(path); if (in == null) { report.message(MessageId.RSC_001, EPUBLocation.create(this.ocf.getName()), path); } byte[] header = new byte[4]; int rd = CheckUtil.readBytes(in, header, 0, 4); if (rd < 4) { report.message(MessageId.MED_004, EPUBLocation.create(path)); } else { checkHeader(header); } checkImageDimensions(path); } catch (IOException e) { report.message(MessageId.PKG_021, EPUBLocation.create(path, path)); } finally { try { if (in != null) { in.close(); } } catch (IOException ignored) { // eat it } } } } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/bitmap/BitmapCheckerFactory.java0000755000175000017500000000323313017276730027347 0ustar eugeneeugene/* * Copyright (c) 2007 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.bitmap; import com.adobe.epubcheck.opf.ContentCheckerFactory; import com.adobe.epubcheck.opf.ValidationContext; public class BitmapCheckerFactory implements ContentCheckerFactory { static private final BitmapCheckerFactory instance = new BitmapCheckerFactory(); public BitmapChecker newInstance(ValidationContext context) { return new BitmapChecker(context.ocf.get(), context.report, context.path, context.mimeType); } static public BitmapCheckerFactory getInstance() { return instance; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/xml/0000755000175000017500000000000013017276730021773 5ustar eugeneeugeneepubcheck-4.0.2/src/main/java/com/adobe/epubcheck/xml/XMLNode.java0000755000175000017500000000312013017276730024103 0ustar eugeneeugene/* * Copyright (c) 2007 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.xml; public class XMLNode { private final String namespace; private final String name; private final String prefix; XMLNode(String namespace, String prefix, String name) { this.namespace = namespace; this.prefix = prefix; this.name = name; } public String getName() { return name; } public String getNamespace() { return namespace; } public String getPrefix() { return prefix; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/xml/XMLValidators.java0000644000175000017500000000513713017276730025335 0ustar eugeneeugenepackage com.adobe.epubcheck.xml; public enum XMLValidators { CONTAINER_20_RNG("schema/20/rng/container.rng"), CONTAINER_30_RNC("schema/30/ocf-container-30.rnc"), CONTAINER_30_RENDITIONS_SCH("schema/30/multiple-renditions/container.sch"), DTBOOK_RNG("schema/20/rng/dtbook-2005-2.rng"), ENC_20_RNG("schema/20/rng/encryption.rng"), ENC_30_RNC("schema/30/ocf-encryption-30.rnc"), IDUNIQUE_20_SCH("schema/20/sch/id-unique.sch"), META_30_RNC("schema/30/ocf-metadata-30.rnc"), META_30_SCH("schema/30/ocf-metadata-30.sch"), META_EDUPUB_SCH("schema/30/edupub/edu-ocf-metadata.sch"), MO_30_RNC("schema/30/media-overlay-30.rnc"), MO_30_SCH("schema/30/media-overlay-30.sch"), NAV_30_RNC("schema/30/epub-nav-30.rnc"), NAV_30_SCH("schema/30/epub-nav-30.sch"), NCX_RNG("schema/20/rng/ncx.rng"), NCX_SCH("schema/20/sch/ncx.sch"), OPF_20_RNG("schema/20/rng/opf.rng"), OPF_20_SCH("schema/20/sch/opf.sch"), OPF_30_RNC("schema/30/package-30.rnc"), OPF_30_SCH("schema/30/package-30.sch"), OPF_30_COLLECTION_DICT_SCH("schema/30/dict/dict-collection.sch"), OPF_30_COLLECTION_DO_SCH("schema/30/collection-do-30.sch"), OPF_30_COLLECTION_IDX_SCH("schema/30/idx/idx-collection.sch"), OPF_30_COLLECTION_MANIFEST_SCH("schema/30/collection-manifest-30.sch"), OPF_30_COLLECTION_PREVIEW_SCH("schema/30/previews/preview-collection.sch"), OPF_DICT_SCH("schema/30/dict/dict-opf.sch"), OPF_EDUPUB_SCH("schema/30/edupub/edu-opf.sch"), OPF_PREVIEW_SCH("schema/30/previews/preview-pub-opf.sch"), RENDITION_MAPPING_RNC("schema/30/multiple-renditions/mapping.rnc"), RENDITION_MAPPING_SCH("schema/30/multiple-renditions/mapping.sch"), SEARCH_KEY_MAP_RNC("schema/30/dict/search-key-map.rnc"), SIG_20_RNG("schema/20/rng/signatures.rng"), SIG_30_RNC("schema/30/ocf-signatures-30.rnc"), SVG_20_RNG("schema/20/rng/svg11.rng"), SVG_30_RNC("schema/30/epub-svg-30.rnc"), SVG_30_SCH("schema/30/epub-svg-30.sch"), XHTML_20_NVDL("schema/20/rng/ops20.nvdl"), XHTML_20_SCH("schema/20/sch/xhtml.sch"), XHTML_30_SCH("schema/30/epub-xhtml-30.sch"), XHTML_30_RNC("schema/30/epub-xhtml-30.rnc"), XHTML_EDUPUB_STRUCTURE_SCH("schema/30/edupub/edu-structure.sch"), XHTML_EDUPUB_SEMANTICS_SCH("schema/30/edupub/edu-semantics.sch"), XHTML_DATANAV_SCH("schema/30/datanav/datanav-xhtml.sch"), XHTML_DICT_SCH("schema/30/dict/dict-xhtml.sch"), XHTML_IDX_SCH("schema/30/idx/idx-xhtml.sch"), XHTML_IDX_INDEX_SCH("schema/30/idx/idx-xhtml-index.sch"); private final XMLValidator val; private XMLValidators(String schemaName) { val = new XMLValidator(schemaName); } public XMLValidator get() { return val; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/xml/DocumentLocatorImpl.java0000644000175000017500000000177613017276730026575 0ustar eugeneeugenepackage com.adobe.epubcheck.xml; import org.xml.sax.Locator; import org.xml.sax.ext.Locator2; class DocumentLocatorImpl implements Locator2 { private final Locator locator; private Locator2 locator2 = null; public DocumentLocatorImpl(Locator locator) { this.locator = locator; if (locator instanceof Locator2) { locator2 = (Locator2) locator; } } @Override public int getColumnNumber() { return locator.getColumnNumber(); } @Override public int getLineNumber() { return locator.getLineNumber(); } @Override public String getPublicId() { return locator.getPublicId(); } @Override public String getSystemId() { return locator.getSystemId(); } @Override public String getEncoding() { if (locator2 != null) { return locator2.getEncoding(); } return null; } @Override public String getXMLVersion() { if (locator2 != null) { return locator2.getXMLVersion(); } return null; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/xml/Namespaces.java0000644000175000017500000000402713017276730024720 0ustar eugeneeugenepackage com.adobe.epubcheck.xml; import javax.xml.XMLConstants; public class Namespaces { public static final String PACKAGE = "http://www.idpf.org/2007/opf"; //$NON-NLS-1$ public static final String MEDIA_OVERLAYS = "http://www.w3.org/ns/SMIL"; //$NON-NLS-1$ public static final String OPS = "http://www.idpf.org/2007/ops"; //$NON-NLS-1$ public static final String CONTAINER = "urn:oasis:names:tc:opendocument:xmlns:container"; //$NON-NLS-1$ public static final String XINCLUDE = "http://www.w3.org/2001/XInclude"; //$NON-NLS-1$ public static final String XLINK = "http://www.w3.org/1999/xlink"; //$NON-NLS-1$ public static final String XHTML = "http://www.w3.org/1999/xhtml"; //$NON-NLS-1$ public static final String MATHML = "http://www.w3.org/1998/Math/MathML"; //$NON-NLS-1$ public static final String SVG = "http://www.w3.org/2000/svg"; //$NON-NLS-1$ public static final String ISOSCH = "http://purl.oclc.org/dsdl/schematron"; //$NON-NLS-1$ public static final String SCH = "http://www.ascc.net/xml/schematron"; //$NON-NLS-1$ public static final String NCX = "http://www.daisy.org/z3986/2005/ncx/"; //$NON-NLS-1$ public static final String PLS = "http://www.w3.org/2005/01/pronunciation-lexicon"; //$NON-NLS-1$ public static final String DSIG_DS = "http://www.w3.org/2000/09/xmldsig#"; //$NON-NLS-1$ public static final String DSIG_DS11 = "http://www.w3.org/2009/xmldsig11#"; //$NON-NLS-1$ public static final String DSIG_DSP = "http://www.w3.org/2009/xmldsig-properties"; //$NON-NLS-1$ public static final String DSIG_EC = "http://www.w3.org/2001/10/xml-exc-c14n#"; //$NON-NLS-1$ public static final String XENC = "http://www.w3.org/2001/04/xmlenc#"; //$NON-NLS-1$ public static final String XENC11 = "http://www.w3.org/2009/xmlenc11#"; //$NON-NLS-1$ public static final String XMLEVENTS = "http://www.w3.org/2001/xml-events"; //$NON-NLS-1$ public static final String SSML = "http://www.w3.org/2001/10/synthesis"; //$NON-NLS-1$ public static final String XML = XMLConstants.XML_NS_URI; //$NON-NLS-1$ private Namespaces() {} } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/xml/XMLParser.java0000755000175000017500000007431113017276730024464 0ustar eugeneeugene/* * Copyright (c) 2007 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.xml; import java.io.BufferedInputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.StringReader; import java.util.ArrayList; import java.util.HashSet; import java.util.Hashtable; import java.util.List; import java.util.Locale; import java.util.Set; import java.util.Vector; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.xml.sax.Attributes; import org.xml.sax.ContentHandler; import org.xml.sax.DTDHandler; import org.xml.sax.InputSource; import org.xml.sax.Locator; import org.xml.sax.SAXException; import org.xml.sax.SAXNotRecognizedException; import org.xml.sax.SAXNotSupportedException; import org.xml.sax.SAXParseException; import org.xml.sax.XMLReader; import org.xml.sax.ext.DeclHandler; import org.xml.sax.ext.LexicalHandler; import org.xml.sax.ext.Locator2; import org.xml.sax.helpers.AttributesImpl; import org.xml.sax.helpers.DefaultHandler; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.messages.MessageId; import com.adobe.epubcheck.opf.ValidationContext; import com.adobe.epubcheck.util.EPUBVersion; import com.adobe.epubcheck.util.ResourceUtil; import com.google.common.io.Closer; import com.thaiopensource.util.PropertyMapBuilder; import com.thaiopensource.validate.ValidateProperty; import com.thaiopensource.validate.Validator; public class XMLParser extends DefaultHandler implements LexicalHandler, DeclHandler { private static final String SAXPROP_LEXICAL_HANDLER = "http://xml.org/sax/properties/lexical-handler"; private static final String SAXPROP_DECL_HANDLER = "http://xml.org/sax/properties/declaration-handler"; private SAXParser parser; private final ValidationContext context; private final Report report; private final String path; private final Vector contentHandlers = new Vector(); private XMLElement currentElement; private final Vector validatorContentHandlers = new Vector(); private final Vector validatorDTDHandlers = new Vector(); private final Vector validatorLexicalHandlers = new Vector(); private final Vector validatorDeclHandlers = new Vector(); private Locator2 documentLocator; private static final String zipRoot = "file:///epub-root/"; private static final Hashtable systemIdMap; private final HashSet entities = new HashSet(); private boolean firstStartDTDInvocation = true; public XMLParser(ValidationContext context) { this.context = context; this.report = context.report; this.path = context.path; // XML predefined entities.add("gt"); entities.add("lt"); entities.add("amp"); entities.add("quot"); entities.add("apos"); SAXParserFactory factory = SAXParserFactory.newInstance(); factory.setNamespaceAware(true); factory.setValidating(false); try { factory.setFeature("http://xml.org/sax/features/external-general-entities", false); factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false); factory.setFeature("http://xml.org/sax/features/validation", false); if (context.version == EPUBVersion.VERSION_3) { factory.setXIncludeAware(false); } } catch (Exception ignored) { } try { parser = factory.newSAXParser(); XMLReader reader = parser.getXMLReader(); reader.setDTDHandler(this); reader.setContentHandler(this); reader.setEntityResolver(this); reader.setErrorHandler(this); try { reader.setProperty(SAXPROP_LEXICAL_HANDLER, this); reader.setProperty(SAXPROP_DECL_HANDLER, this); } catch (SAXNotRecognizedException e) { e.printStackTrace(); } catch (SAXNotSupportedException e) { e.printStackTrace(); } } catch (ParserConfigurationException e) { e.printStackTrace(); } catch (SAXException e) { e.printStackTrace(); } } public void addXMLHandler(XMLHandler handler) { if (handler != null) { contentHandlers.add(handler); } } public void addValidator(XMLValidator xv) { PropertyMapBuilder propertyMapBuilder = new PropertyMapBuilder(); propertyMapBuilder.put(ValidateProperty.ERROR_HANDLER, this); Validator validator = xv.schema.createValidator(propertyMapBuilder.toPropertyMap()); ContentHandler contentHandler = validator.getContentHandler(); if (contentHandler != null) { validatorContentHandlers.add(contentHandler); } DTDHandler dtdHandler = validator.getDTDHandler(); if (dtdHandler != null) { validatorDTDHandlers.add(dtdHandler); } } public void addDeclHandler(DeclHandler handler) { if (handler != null) { validatorDeclHandlers.add(handler); } } public void addLexicalHandler(LexicalHandler handler) { if (handler != null) { validatorLexicalHandlers.add(handler); } } public void process() { try { Closer closer = Closer.create(); try { InputStream in = closer.register(context.resourceProvider.getInputStream(path)); // System.err.println("DEBUG XMLParser#process on" + resource); if (!in.markSupported()) { in = new BufferedInputStream(in); } String encoding = sniffEncoding(in); if (encoding != null && !encoding.equals("UTF-8") && !encoding.equals("UTF-16")) { report.message(MessageId.CSS_003, EPUBLocation.create(path, ""), encoding); } InputSource ins = new InputSource(in); ins.setSystemId(zipRoot + path); parser.parse(ins, this); } catch (Throwable e) { // ensure that any checked exception types other than IOException that // could be thrown are // provided here, e.g. throw closer.rethrow(e, // CheckedException.class); // throw closer.rethrow(e); throw closer.rethrow(e, SAXException.class); } finally { closer.close(); } } catch (FileNotFoundException e) { String message = e.getMessage(); message = new File(message).getName(); int p = message.indexOf("("); if (p > 0) { message = message.substring(0, message.indexOf("(")); } message = message.trim(); report.message(MessageId.RSC_001, EPUBLocation.create(path), message); } catch (IOException e) { report.message(MessageId.PKG_008, EPUBLocation.create(path), path); } catch (IllegalArgumentException e) { report.message(MessageId.RSC_005, EPUBLocation.create(path), e.getMessage()); } catch (SAXException e) { report.message(MessageId.RSC_005, EPUBLocation.create(path), e.getMessage()); } } public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException { // if (systemId.startsWith(zipRoot)) // { // InputStream inStream = // this.thePackage.getInputStream(systemId.substring(zipRoot.length())); // if (inStream != null) // { // InputSource source = new InputSource(inStream); // source.setPublicId(publicId); // source.setSystemId(systemId); // return source; // } // } // outWriter.println("DEBUG XMLParser#resolveEntity ==> "+ publicId + ", " + // systemId + ", " ); String resourcePath = systemIdMap.get(systemId); if (resourcePath != null) { InputStream resourceStream = ResourceUtil.getResourceStream(resourcePath); InputSource source = new InputSource(resourceStream); source.setPublicId(publicId); source.setSystemId(systemId); return source; } else if (systemId.equals("about:legacy-compat")) { // special case return new InputSource(new StringReader("")); } else { // check for a system prop that turns off online fetching // the default is to attempt online fetching, as this has been the default // forever boolean offline = Boolean.parseBoolean(System.getProperty("epubcheck.offline")); // outWriter.println("offline value is " + offline); if (systemId.startsWith("http:") && offline) { return new InputSource(new StringReader("")); } // else return null and let the caller try to fetch the goods return null; } } public void notationDecl(String name, String publicId, String systemId) throws SAXException { int len = validatorDTDHandlers.size(); for (int i = 0; i < len; i++) { (validatorDTDHandlers.elementAt(i)).notationDecl(name, publicId, systemId); } } public void unparsedEntityDecl(String name, String publicId, String systemId, String notationName) throws SAXException { int len = validatorDTDHandlers.size(); for (int i = 0; i < len; i++) { (validatorDTDHandlers.elementAt(i)) .unparsedEntityDecl(name, publicId, systemId, notationName); } } public void error(SAXParseException ex) throws SAXException { String message = ex.getMessage().trim(); if (message != null && message.startsWith("WARNING:")) { report.message(MessageId.RSC_017, EPUBLocation.create(path, ex.getLineNumber(), ex.getColumnNumber()), message.substring(9, message.length())); } else { report.message(MessageId.RSC_005, EPUBLocation.create(path, ex.getLineNumber(), ex.getColumnNumber()), message); } } public void fatalError(SAXParseException ex) throws SAXException { report.message(MessageId.RSC_016, EPUBLocation.create(path, ex.getLineNumber(), ex.getColumnNumber()), ex.getMessage()); } public void warning(SAXParseException ex) throws SAXException { report.message(MessageId.RSC_017, EPUBLocation.create(path, ex.getLineNumber(), ex.getColumnNumber()), ex.getMessage()); } public void characters(char[] arg0, int arg1, int arg2) throws SAXException { int vlen = validatorContentHandlers.size(); for (int i = 0; i < vlen; i++) { (validatorContentHandlers.elementAt(i)).characters(arg0, arg1, arg2); } int len = contentHandlers.size(); for (int i = 0; i < len; i++) { (contentHandlers.elementAt(i)).characters(arg0, arg1, arg2); } } public void endDocument() throws SAXException { int len = validatorContentHandlers.size(); for (int i = 0; i < len; i++) { (validatorContentHandlers.elementAt(i)).endDocument(); } } public void endElement(String arg0, String arg1, String arg2) throws SAXException { int vlen = validatorContentHandlers.size(); for (int i = 0; i < vlen; i++) { (validatorContentHandlers.elementAt(i)).endElement(arg0, arg1, arg2); } int len = contentHandlers.size(); for (int i = 0; i < len; i++) { (contentHandlers.elementAt(i)).endElement(); } currentElement = currentElement.getParent(); } public void endPrefixMapping(String arg0) throws SAXException { int vlen = validatorContentHandlers.size(); for (int i = 0; i < vlen; i++) { (validatorContentHandlers.elementAt(i)).endPrefixMapping(arg0); } } public void ignorableWhitespace(char[] arg0, int arg1, int arg2) throws SAXException { int vlen = validatorContentHandlers.size(); for (int i = 0; i < vlen; i++) { (validatorContentHandlers.elementAt(i)).ignorableWhitespace(arg0, arg1, arg2); } int len = contentHandlers.size(); for (int i = 0; i < len; i++) { (contentHandlers.elementAt(i)).ignorableWhitespace(arg0, arg1, arg2); } } public void processingInstruction(String arg0, String arg1) throws SAXException { int vlen = validatorContentHandlers.size(); for (int i = 0; i < vlen; i++) { (validatorContentHandlers.elementAt(i)).processingInstruction(arg0, arg1); } int len = contentHandlers.size(); for (int i = 0; i < len; i++) { (contentHandlers.elementAt(i)).processingInstruction(arg0, arg1); } } public void setDocumentLocator(Locator locator) { int vlen = validatorContentHandlers.size(); for (int i = 0; i < vlen; i++) { (validatorContentHandlers.elementAt(i)).setDocumentLocator(locator); } documentLocator = new DocumentLocatorImpl(locator); } public void skippedEntity(String arg0) throws SAXException { int vlen = validatorContentHandlers.size(); for (int i = 0; i < vlen; i++) { (validatorContentHandlers.elementAt(i)).skippedEntity(arg0); } } public void startDocument() throws SAXException { int vlen = validatorContentHandlers.size(); for (int i = 0; i < vlen; i++) { (validatorContentHandlers.elementAt(i)).startDocument(); } } public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException { AttributesImpl attribs = new AttributesImpl(atts); if ("application/xhtml+xml".equals(context.mimeType) && context.version == EPUBVersion.VERSION_3) { try { int len = attribs.getLength(); List removals = new ArrayList(); for (int i = 0; i < len; i++) { if (attribs.getLocalName(i).startsWith("data-")) { removals.add(attribs.getQName(i)); } else if (isCustomNamespaceAttr(attribs.getURI(i))) { removals.add(attribs.getQName(i)); } } for (String remove : removals) { int rmv = attribs.getIndex(remove); // System.out.println("removing attribute " + attribs.getQName(rmv)); attribs.removeAttribute(rmv); } } catch (Exception e) { System.err.println("data-* removal exception: " + e.getMessage()); } } int vlen = validatorContentHandlers.size(); for (int i = 0; i < vlen; i++) { (validatorContentHandlers.elementAt(i)).startElement(namespaceURI, localName, qName, attribs); } int index = qName.indexOf(':'); String prefix; String name; if (index < 0) { prefix = null; name = qName; } else { prefix = qName.substring(0, index); name = qName.substring(index + 1); } int count = attribs.getLength(); XMLAttribute[] attributes = count == 0 ? null : new XMLAttribute[count]; for (int i = 0; i < count; i++) { String attName = attribs.getLocalName(i); String attNamespace = attribs.getURI(i); String attQName = attribs.getQName(i); int attIndex = attQName.indexOf(':'); String attPrefix; if (attIndex < 0) { attPrefix = null; attNamespace = null; } else { attPrefix = attQName.substring(0, attIndex); } String attValue = attribs.getValue(i); assert attributes != null; attributes[i] = new XMLAttribute(attNamespace, attPrefix, attName, attValue); } currentElement = new XMLElement(namespaceURI, prefix, name, attributes, currentElement); int len = contentHandlers.size(); for (int i = 0; i < len; i++) { (contentHandlers.elementAt(i)).startElement(); } } // 3.0.1 custom attributes handling private static final Set knownXHTMLContentDocsNamespaces = new HashSet(); static { knownXHTMLContentDocsNamespaces.add(Namespaces.MATHML); knownXHTMLContentDocsNamespaces.add(Namespaces.OPS); knownXHTMLContentDocsNamespaces.add(Namespaces.SSML); knownXHTMLContentDocsNamespaces.add(Namespaces.SVG); knownXHTMLContentDocsNamespaces.add(Namespaces.XHTML); knownXHTMLContentDocsNamespaces.add(Namespaces.XMLEVENTS); knownXHTMLContentDocsNamespaces.add(Namespaces.XML); knownXHTMLContentDocsNamespaces.add(Namespaces.XLINK); } private boolean isCustomNamespaceAttr(String nsuri) { if (nsuri == null || nsuri.trim().length() == 0) { return false; } for (String ns : knownXHTMLContentDocsNamespaces) { if (ns.equals(nsuri)) { return false; } } return true; } public void startPrefixMapping(String arg0, String arg1) throws SAXException { int vlen = validatorContentHandlers.size(); for (int i = 0; i < vlen; i++) { (validatorContentHandlers.elementAt(i)).startPrefixMapping(arg0, arg1); } } public void comment(char[] text, int arg1, int arg2) throws SAXException { if (validatorLexicalHandlers.size() > 0) { for (LexicalHandler h : this.validatorLexicalHandlers) { h.comment(text, arg1, arg2); } } } public void endCDATA() throws SAXException { if (validatorLexicalHandlers.size() > 0) { for (LexicalHandler h : this.validatorLexicalHandlers) { h.endCDATA(); } } } public void endDTD() throws SAXException { if (validatorLexicalHandlers.size() > 0) { for (LexicalHandler h : this.validatorLexicalHandlers) { h.endDTD(); } } } public void endEntity(String ent) throws SAXException { if (validatorLexicalHandlers.size() > 0) { for (LexicalHandler h : this.validatorLexicalHandlers) { h.endEntity(ent); } } } public void startCDATA() throws SAXException { if (validatorLexicalHandlers.size() > 0) { for (LexicalHandler h : this.validatorLexicalHandlers) { h.startCDATA(); } } } public void startDTD(String root, String publicId, String systemId) throws SAXException { if (validatorLexicalHandlers.size() > 0) { for (LexicalHandler h : this.validatorLexicalHandlers) { h.startDTD(root, publicId, systemId); } } handleDocTypeUserInfo(root, publicId, systemId); } private void handleDocTypeUserInfo(String root, String publicId, String systemId) { final String mimeType = context.mimeType; // outWriter.println("DEBUG doctype ==> "+ root + ", " + publicId + ", " + // systemId + ", " ); // for modular DTDs etc, just issue a warning for the top level IDs. if (!firstStartDTDInvocation) { return; } if (context.version == EPUBVersion.VERSION_2) { if (mimeType != null && "application/xhtml+xml".equals(mimeType) && root.equals("html")) { // OPS 2.0(.1) String complete = ""; if (matchDoctypeId("-//W3C//DTD XHTML 1.1//EN", publicId, complete)) { matchDoctypeId("http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd", systemId, complete); } } if (mimeType != null && "opf".equals(mimeType) && (publicId != null || systemId != null)) { // 1.2: // http://http://idpf.org/dtds/oeb-1.2/oebpkg12.dtd if ("package".equals(root) && (publicId == null || publicId .equals("+//ISBN 0-9673008-1-9//DTD OEB 1.2 Package//EN")) && (systemId == null || systemId .equals("http://openebook.org/dtds/oeb-1.2/oebpkg12.dtd"))) { // for heritage content collections, dont warn about this, as its not // explicitly forbidden by the spec } else { report.message(MessageId.HTM_009, EPUBLocation.create(path)); } } if (mimeType != null && "application/x-dtbncx+xml".equals(mimeType)) { String complete = ""; if (matchDoctypeId("-//NISO//DTD ncx 2005-1//EN", publicId, complete)) { matchDoctypeId("http://www.daisy.org/z3986/2005/ncx-2005-1.dtd", systemId, complete); } } } else if (context.version == EPUBVersion.VERSION_3) { if (mimeType != null && "application/xhtml+xml".equals(mimeType) && "html".equalsIgnoreCase(root)) { String complete = ""; // warn for obsolete or unknown doctypes if (publicId == null && (systemId == null || systemId.equals("about:legacy-compat"))) { // we assume to have have or } else { report.message(MessageId.HTM_004, EPUBLocation.create(path), publicId, complete); } } else if (publicId != null || systemId != null) { report.message(MessageId.OPF_073, getLocation()); } } firstStartDTDInvocation = false; } boolean checkDTD(String expectedPublicId, String expectedSystemId, String actualPublicId, String actualSystemId) { if ((actualPublicId == null || (actualPublicId != null && expectedPublicId .equalsIgnoreCase(actualPublicId))) && (actualSystemId == null || (actualSystemId != null && expectedSystemId .equalsIgnoreCase(actualSystemId)))) { return true; } return false; } boolean matchDoctypeId(String expected, String given, String messageParam) { if (!expected.equals(given)) { report.message(MessageId.HTM_004, EPUBLocation.create(path), given==null?"":given, messageParam); return false; } return true; } public void startEntity(String ent) throws SAXException { if (validatorLexicalHandlers.size() > 0) { for (LexicalHandler h : this.validatorLexicalHandlers) { h.startEntity(ent); } } if (!entities.contains(ent) && !ent.equals("[dtd]")) { // This message may never be reported. Undeclared entities result in a Sax // Parser Error and message RSC_005. report.message(MessageId.HTM_011, EPUBLocation.create(path, getLineNumber(), getColumnNumber(), ent)); } } public void attributeDecl(String name, String name2, String type, String mode, String value) throws SAXException { if (validatorDeclHandlers.size() > 0) { for (DeclHandler h : this.validatorDeclHandlers) { h.attributeDecl(name, name2, type, mode, value); } } } public void elementDecl(String name, String model) throws SAXException { if (validatorDeclHandlers.size() > 0) { for (DeclHandler h : this.validatorDeclHandlers) { h.elementDecl(name, model); } } } public void externalEntityDecl(String name, String publicId, String systemId) throws SAXException { if (validatorDeclHandlers.size() > 0) { for (DeclHandler h : this.validatorDeclHandlers) { h.externalEntityDecl(name, publicId, systemId); } } if (context.version == EPUBVersion.VERSION_3) { report.message(MessageId.HTM_003, EPUBLocation.create(path, getLineNumber(), getColumnNumber(), name), name); return; } entities.add(name); } public void internalEntityDecl(String name, String value) throws SAXException { if (validatorDeclHandlers.size() > 0) { for (DeclHandler h : this.validatorDeclHandlers) { h.internalEntityDecl(name, value); } } entities.add(name); } public XMLElement getCurrentElement() { return currentElement; } public Report getReport() { return report; } public int getLineNumber() { return documentLocator.getLineNumber(); } public int getColumnNumber() { return documentLocator.getColumnNumber(); } public EPUBLocation getLocation() { return EPUBLocation.create(path, documentLocator.getLineNumber(), documentLocator.getColumnNumber()); } public String getXMLVersion() { return documentLocator.getXMLVersion(); } public String getResourceName() { return path; } private static final byte[][] utf16magic = { { (byte) 0xFE, (byte) 0xFF }, { (byte) 0xFF, (byte) 0xFE }, { 0, 0x3C, 0, 0x3F }, { 0x3C, 0, 0x3F, 0 } }; private static final byte[][] ucs4magic = { { 0, 0, (byte) 0xFE, (byte) 0xFF }, { (byte) 0xFF, (byte) 0xFE, 0, 0 }, { 0, 0, (byte) 0xFF, (byte) 0xFE }, { (byte) 0xFE, (byte) 0xFF, 0, 0 }, { 0, 0, 0, 0x3C }, { 0, 0, 0x3C, 0 }, { 0, 0x3C, 0, 0 }, { 0x3C, 0, 0, 0 } }; private static final byte[] utf8magic = { (byte) 0xEF, (byte) 0xBB, (byte) 0xBF }; private static final byte[] ebcdicmagic = { 0x4C, 0x6F, (byte) 0xA7, (byte) 0x94 }; private static boolean matchesMagic(byte[] magic, byte[] buffer) { for (int i = 0; i < magic.length; i++) { if (buffer[i] != magic[i]) { return false; } } return true; } private static String sniffEncoding(InputStream in) throws IOException { // see http://www.w3.org/TR/REC-xml/#sec-guessing byte[] buffer = new byte[256]; in.mark(buffer.length); int len = in.read(buffer); in.reset(); if (len < 4) { return null; } for (byte[] magic : utf16magic) { if (matchesMagic(magic, buffer)) { return "UTF-16"; } } for (byte[] anUcs4magic : ucs4magic) { if (matchesMagic(anUcs4magic, buffer)) { return "UCS-4"; } } if (matchesMagic(utf8magic, buffer)) { return "UTF-8"; } if (matchesMagic(ebcdicmagic, buffer)) { return "EBCDIC"; } // some ASCII-compatible encoding; read ASCII int asciiLen = 0; while (asciiLen < len) { int c = buffer[asciiLen] & 0xFF; if (c == 0 || c > 0x7F) { break; } asciiLen++; } // read it into a String String header = new String(buffer, 0, asciiLen, "ASCII"); int encIndex = header.indexOf("encoding="); if (encIndex < 0) { return null; // probably UTF-8 } encIndex += 9; if (encIndex >= header.length()) { return null; // encoding did not fit! } char quote = header.charAt(encIndex); if (quote != '"' && quote != '\'') { return null; // confused... } int encEnd = header.indexOf(quote, encIndex + 1); if (encEnd < 0) { return null; // encoding did not fit! } String encoding = header.substring(encIndex + 1, encEnd); return encoding.toUpperCase(Locale.ROOT); } static { Hashtable map = new Hashtable(); // OEB 1.2 map.put("http://openebook.org/dtds/oeb-1.2/oebpkg12.dtd", ResourceUtil.getResourcePath("schema/20/dtd/oebpkg12.dtd")); map.put("http://http://idpf.org/dtds/oeb-1.2/oebpkg12.dtd", ResourceUtil.getResourcePath("schema/20/dtd/oebpkg12.dtd")); map.put("http://openebook.org/dtds/oeb-1.2/oeb12.ent", ResourceUtil.getResourcePath("schema/20/dtd/oeb12.dtdinc")); map.put("http://openebook.org/dtds/oeb-1.2/oebdoc12.dtd", ResourceUtil.getResourcePath("schema/20/dtd/oebdoc12.dtd")); // 2.0 dtd, probably never published map.put("http://www.idpf.org/dtds/2007/opf.dtd", ResourceUtil.getResourcePath("schema/20/dtd/opf20.dtd")); // xhtml 1.1 map.put("http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd", ResourceUtil.getResourcePath("schema/20/dtd/xhtml1-transitional.dtd")); map.put("http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd", ResourceUtil.getResourcePath("schema/20/dtd/xhtml1-strict.dtd")); map.put("http://www.w3.org/TR/xhtml1/DTD/xhtml-lat1.ent", ResourceUtil.getResourcePath("schema/20/dtd/xhtml-lat1.dtdinc")); map.put("http://www.w3.org/TR/xhtml1/DTD/xhtml-symbol.ent", ResourceUtil.getResourcePath("schema/20/dtd/xhtml-symbol.dtdinc")); map.put("http://www.w3.org/TR/xhtml1/DTD/xhtml-special.ent", ResourceUtil.getResourcePath("schema/20/dtd/xhtml-special.dtdinc")); // svg 1.1 map.put("http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd", ResourceUtil.getResourcePath("schema/20/dtd/svg11.dtd")); // dtbook map.put("http://www.daisy.org/z3986/2005/dtbook-2005-2.dtd", ResourceUtil.getResourcePath("schema/20/dtd/dtbook-2005-2.dtd")); // ncx map.put("http://www.daisy.org/z3986/2005/ncx-2005-1.dtd", ResourceUtil.getResourcePath("schema/20/dtd/ncx-2005-1.dtd")); // xhtml 1.1: just reference the character entities, as we validate with rng map.put("http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd", ResourceUtil.getResourcePath("schema/20/dtd/xhtml11-ent.dtd")); map.put("http://www.w3.org/MarkUp/DTD/xhtml11.dtd", ResourceUtil.getResourcePath("schema/20/dtd/xhtml11-ent.dtd")); // non-resolved names; Saxon (which schematron requires and registers as // preferred parser, it seems) passes us those (bad, bad!), work around it map.put("xhtml-lat1.ent", ResourceUtil.getResourcePath("dtd/xhtml-lat1.dtdinc")); map.put("xhtml-symbol.ent", ResourceUtil.getResourcePath("dtd/xhtml-symbol.dtdinc")); map.put("xhtml-special.ent", ResourceUtil.getResourcePath("dtd/xhtml-special.dtdinc")); systemIdMap = map; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/xml/XMLElement.java0000755000175000017500000000463213017276730024620 0ustar eugeneeugene/* * Copyright (c) 2007 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.xml; public class XMLElement extends XMLNode { private final XMLAttribute[] attributes; private final XMLElement parent; private Object privateData; XMLElement(String namespace, String prefix, String name, XMLAttribute[] attributes, XMLElement parent) { super(namespace, prefix, name); this.attributes = attributes; this.parent = parent; } public int getAttributeCount() { if (attributes == null) { return 0; } return attributes.length; } public XMLAttribute getAttribute(int i) { return attributes[i]; } public XMLElement getParent() { return parent; } public String getAttributeNS(String ns, String name) { if (attributes == null) { return null; } for (XMLAttribute attr : attributes) { String ans = attr.getNamespace(); if (attr.getName().equals(name) && (ans == null ? ns == null : ns != null && ans.equals(ns))) { return attr.getValue(); } } return null; } public String getAttribute(String attr) { return getAttributeNS(null, attr); } public Object getPrivateData() { return privateData; } public void setPrivateData(Object privateData) { this.privateData = privateData; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/xml/XMLAttribute.java0000755000175000017500000000265713017276730025177 0ustar eugeneeugene/* * Copyright (c) 2007 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.xml; public class XMLAttribute extends XMLNode { private final String value; XMLAttribute(String namespace, String prefix, String name, String value) { super(namespace, prefix, name); this.value = value; } public String getValue() { return value; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/xml/XMLValidator.java0000755000175000017500000001745113017276730025157 0ustar eugeneeugene/* * Copyright (c) 2007 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.xml; import java.io.IOException; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import javax.xml.transform.TransformerFactory; import org.idpf.epubcheck.util.saxon.ColumnNumberFunction; import org.idpf.epubcheck.util.saxon.LineNumberFunction; import org.idpf.epubcheck.util.saxon.SystemIdFunction; import org.xml.sax.ErrorHandler; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; import com.adobe.epubcheck.util.ResourceUtil; import com.thaiopensource.resolver.Identifier; import com.thaiopensource.resolver.Input; import com.thaiopensource.resolver.Resolver; import com.thaiopensource.resolver.ResolverException; import com.thaiopensource.util.PropertyMapBuilder; import com.thaiopensource.validate.Schema; import com.thaiopensource.validate.SchemaReader; import com.thaiopensource.validate.ValidateProperty; import com.thaiopensource.validate.auto.AutoSchemaReader; import com.thaiopensource.validate.auto.SchemaReaderFactorySchemaReceiverFactory; import com.thaiopensource.validate.rng.CompactSchemaReader; import com.thaiopensource.validate.schematron.NewSaxonSchemaReaderFactory; import net.sf.saxon.Configuration; import net.sf.saxon.TransformerFactoryImpl; import net.sf.saxon.sxpath.IndependentContext; import net.sf.saxon.sxpath.XPathStaticContext; public class XMLValidator { Schema schema; /** * Basic Resolver from Jing modified to add support for resolving zip and * jar relative locations. * * @author george@oxygenxml.com */ static public class BasicResolver implements Resolver { static private final BasicResolver theInstance = new BasicResolver(); BasicResolver() { } public static BasicResolver getInstance() { return theInstance; } public void resolve(Identifier id, Input input) throws IOException, ResolverException { if (!input.isResolved()) { input.setUri(resolveUri(id)); } } public void open(Input input) throws IOException, ResolverException { if (!input.isUriDefinitive()) { return; } URI uri; try { uri = new URI(input.getUri()); } catch (URISyntaxException e) { throw new ResolverException(e); } if (!uri.isAbsolute()) { throw new ResolverException("cannot open relative URI: " + uri); } URL url = new URL(uri.toASCIIString()); // XXX should set the encoding properly // XXX if this is HTTP and we've been redirected, should do // input.setURI with the new URI input.setByteStream(url.openStream()); } public static String resolveUri(Identifier id) throws ResolverException { try { String uriRef = id.getUriReference(); URI uri = new URI(uriRef); if (!uri.isAbsolute()) { String base = id.getBase(); if (base != null) { // OXYGEN PATCH START // Use class URL in order to resolve protocols like zip // and jar. URI baseURI = new URI(base); if ("zip".equals(baseURI.getScheme()) || "jar".equals(baseURI.getScheme())) { uriRef = new URL(new URL(base), uriRef) .toExternalForm(); // OXYGEN PATCH END } else { uriRef = baseURI.resolve(uri).toString(); } } } return uriRef; } catch (URISyntaxException e) { throw new ResolverException(e); } catch (MalformedURLException e) { throw new ResolverException(e); } } } /** * Extends Jing's Saxon 9 schema reader factory by registering * extension functions. */ static public class ExtendedSaxonSchemaReaderFactory extends NewSaxonSchemaReaderFactory { public void initTransformerFactory(TransformerFactory factory) { super.initTransformerFactory(factory); if (factory instanceof TransformerFactoryImpl) { Configuration configuration = ((TransformerFactoryImpl) factory).getConfiguration(); XPathStaticContext xpathContext = new IndependentContext(configuration); if (!xpathContext.getFunctionLibrary().isAvailable(LineNumberFunction.QNAME, -1)) { configuration.registerExtensionFunction(new LineNumberFunction()); } if (!xpathContext.getFunctionLibrary().isAvailable(ColumnNumberFunction.QNAME, -1)) { configuration.registerExtensionFunction(new ColumnNumberFunction()); } if (!xpathContext.getFunctionLibrary().isAvailable(SystemIdFunction.QNAME, -1)) { configuration.registerExtensionFunction(new SystemIdFunction()); } } } } // handles errors in schemas private class ErrorHandlerImpl implements ErrorHandler { public void error(SAXParseException exception) throws SAXException { exception.printStackTrace(); } public void fatalError(SAXParseException exception) throws SAXException { exception.printStackTrace(); } public void warning(SAXParseException exception) throws SAXException { exception.printStackTrace(); } } public XMLValidator(String schemaName) { try { String resourcePath = ResourceUtil.getResourcePath(schemaName); URL systemIdURL = ResourceUtil.getResourceURL(resourcePath); if (systemIdURL == null) { throw new RuntimeException("Could not find resource " + resourcePath); } InputSource schemaSource = new InputSource(systemIdURL.toString()); PropertyMapBuilder mapBuilder = new PropertyMapBuilder(); mapBuilder.put(ValidateProperty.RESOLVER, BasicResolver.getInstance()); mapBuilder.put(ValidateProperty.ERROR_HANDLER, new ErrorHandlerImpl()); SchemaReader schemaReader; if (schemaName.endsWith(".rnc")) { schemaReader = CompactSchemaReader.getInstance(); } else if (schemaName.endsWith(".sch")) { schemaReader = new AutoSchemaReader( new SchemaReaderFactorySchemaReceiverFactory( new ExtendedSaxonSchemaReaderFactory())); } else { schemaReader = new AutoSchemaReader(); } schema = schemaReader.createSchema(schemaSource, mapBuilder.toPropertyMap()); } catch (RuntimeException e) { throw e; } catch (Exception e) { e.printStackTrace(); throw new Error("Internal error: " + e + " " + schemaName); } } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/xml/XMLHandler.java0000755000175000017500000000267613017276730024612 0ustar eugeneeugene/* * Copyright (c) 2007 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.xml; public interface XMLHandler { public void characters(char[] chars, int arg1, int arg2); public void ignorableWhitespace(char[] chars, int arg1, int arg2); public void startElement(); public void endElement(); public void processingInstruction(String arg0, String arg1); } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ctc/0000755000175000017500000000000013017276730021744 5ustar eugeneeugeneepubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ctc/EpubSpineCheck.java0000644000175000017500000000566113017276730025447 0ustar eugeneeugenepackage com.adobe.epubcheck.ctc; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.ctc.epubpackage.EpubPackage; import com.adobe.epubcheck.ctc.epubpackage.MetadataElement; import com.adobe.epubcheck.ctc.epubpackage.SpineItem; import com.adobe.epubcheck.messages.MessageId; import com.adobe.epubcheck.opf.DocumentValidator; import com.adobe.epubcheck.util.EpubConstants; import com.adobe.epubcheck.util.outWriter; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; public class EpubSpineCheck implements DocumentValidator { private static final int MAX_SPINE_ITEM_THRESHOLD = 100; private final EpubPackage epubPack; private final Document doc; private final String pathRootFile; private final Report report; public EpubSpineCheck(EpubPackage epubPack, Report report) { this.epubPack = epubPack; this.doc = epubPack.getPackDoc(); pathRootFile = epubPack.getPackageMainFile(); this.report = report; } public boolean validate() { boolean resExists = isSpineDefined(doc, pathRootFile); boolean resElements = tooManySpineElements(doc, pathRootFile, MAX_SPINE_ITEM_THRESHOLD); return (resExists && resElements); } private boolean isSpineDefined(Document doc, String pathRootFile) { NodeList spines = doc.getElementsByTagNameNS(EpubConstants.OpfNamespaceUri, "spine"); Node spine = spines.getLength() > 0 ? spines.item(0) : null; if (spine == null) { report.message(MessageId.OPF_019, EPUBLocation.create(pathRootFile)); outWriter.println("Spine element not found within package root document " + pathRootFile); return false; } return true; } private boolean tooManySpineElements(Document doc, String pathRootFile, int maxSpineElements) { boolean isFixedFormat = false; for (SpineItem si : epubPack.getSpine().getItems()) { String val = si.getProperties(); if (val != null && val.equalsIgnoreCase("rendition:layout-pre-paginated")) { isFixedFormat = true; break; } } if (!isFixedFormat) { for (MetadataElement e : epubPack.getMetadata().getMetaElements()) { if (e.getName().equals("meta")) { String val = e.getAttribute("property"); { if (val != null && val.equalsIgnoreCase("rendition:layout")) { isFixedFormat = e.getValue().equalsIgnoreCase("pre-paginated"); break; } } } } } if (!isFixedFormat) { NodeList spine = doc.getElementsByTagName("spine"); if (spine.getLength() > 0) { NodeList spineElements = spine.item(0).getChildNodes(); if (spineElements.getLength() > maxSpineElements) { report.message(MessageId.OPF_020, EPUBLocation.create(pathRootFile)); return false; } } } return true; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ctc/EpubTocCheck.java0000644000175000017500000000203113017276730025102 0ustar eugeneeugenepackage com.adobe.epubcheck.ctc; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.ctc.epubpackage.EpubPackage; import com.adobe.epubcheck.ctc.epubpackage.PackageSpine; import com.adobe.epubcheck.messages.MessageId; import com.adobe.epubcheck.opf.DocumentValidator; import com.adobe.epubcheck.util.EPUBVersion; public class EpubTocCheck implements DocumentValidator { private final String pathRootFile; private final EpubPackage epack; private final Report report; public EpubTocCheck(EpubPackage epack, Report report) { this.pathRootFile = epack.getPackageMainFile(); this.epack = epack; this.report = report; } @Override public boolean validate() { boolean result = true; PackageSpine spine = epack.getSpine(); if (spine == null || (spine.getToc() == null && epack.getVersion() == EPUBVersion.VERSION_2)) { report.message(MessageId.NCX_002, EPUBLocation.create(pathRootFile)); result = false; } return result; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ctc/EpubSpanCheck.java0000644000175000017500000000373213017276730025267 0ustar eugeneeugenepackage com.adobe.epubcheck.ctc; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.ctc.epubpackage.EpubPackage; import com.adobe.epubcheck.ctc.epubpackage.ManifestItem; import com.adobe.epubcheck.ctc.xml.SpanTagHandler; import com.adobe.epubcheck.ctc.xml.XMLContentDocParser; import com.adobe.epubcheck.messages.MessageId; import com.adobe.epubcheck.opf.DocumentValidator; import com.adobe.epubcheck.util.SearchDictionary; import com.adobe.epubcheck.util.SearchDictionary.DictionaryType; public class EpubSpanCheck implements DocumentValidator { private final ZipFile zip; private final Report report; private final EpubPackage epack; public EpubSpanCheck(EpubPackage epack, Report report) { this.zip = epack.getZip(); this.report = report; this.epack = epack; } @Override public boolean validate() { boolean result = false; SearchDictionary vtsd = new SearchDictionary(DictionaryType.VALID_TEXT_MEDIA_TYPES); for (int i = 0; i < epack.getManifest().itemsLength(); i++) { ManifestItem mi = epack.getManifest().getItem(i); if (vtsd.isValidMediaType(mi.getMediaType())) { XMLContentDocParser parser = new XMLContentDocParser(this.zip, report); SpanTagHandler sh = new SpanTagHandler(); String fileToParse = epack.getManifestItemFileName(mi); ZipEntry entry = this.zip.getEntry(fileToParse); if (entry == null) { // already reported in core checkers // report.message(MessageId.RSC_001, EPUBLocation.create(this.epack.getFileName()), fileToParse); continue; } parser.parseDoc(fileToParse, sh); sh.countNestedElements(sh.getTopElement()); if (sh.getGenerateMessage() > 0) { report.message(MessageId.HTM_022, EPUBLocation.create(mi.getHref())); } } } return result; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ctc/EpubStyleSheetsCheck.java0000644000175000017500000000323513017276730026640 0ustar eugeneeugenepackage com.adobe.epubcheck.ctc; import java.util.zip.ZipEntry; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.ctc.epubpackage.EpubPackage; import com.adobe.epubcheck.ctc.epubpackage.ManifestItem; import com.adobe.epubcheck.ctc.xml.LinkTagHandler; import com.adobe.epubcheck.ctc.xml.XMLContentDocParser; import com.adobe.epubcheck.opf.DocumentValidator; import com.adobe.epubcheck.util.SearchDictionary; import com.adobe.epubcheck.util.SearchDictionary.DictionaryType; public class EpubStyleSheetsCheck implements DocumentValidator { private final Report report; private final EpubPackage epack; public EpubStyleSheetsCheck(EpubPackage epack, Report report) { this.epack = epack; this.report = report; } public boolean validate() { SearchDictionary validTypes = new SearchDictionary(DictionaryType.VALID_TEXT_MEDIA_TYPES); for (int i = 0; i < epack.getManifest().itemsLength(); i++) { ManifestItem mi = epack.getManifest().getItem(i); if (validTypes.isValidMediaType(mi.getMediaType())) { String fileToParse = epack.getManifestItemFileName(mi); ZipEntry entry = epack.getZip().getEntry(fileToParse); if (entry == null) { // already reported in core checkers // report.message(MessageId.RSC_001, EPUBLocation.create(this.epack.getFileName()), fileToParse); continue; } XMLContentDocParser parser = new XMLContentDocParser(epack.getZip(), report); LinkTagHandler h = new LinkTagHandler(report); parser.parseDoc(fileToParse, h); h.checkForMultipleStyleSheets(fileToParse); } } return true; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ctc/EpubRenditionCheck.java0000644000175000017500000001054013017276730026314 0ustar eugeneeugenepackage com.adobe.epubcheck.ctc; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.ctc.epubpackage.EpubPackage; import com.adobe.epubcheck.ctc.epubpackage.ManifestItem; import com.adobe.epubcheck.opf.DocumentValidator; import com.adobe.epubcheck.util.FeatureEnum; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; public class EpubRenditionCheck implements DocumentValidator { private final Document doc; private final EpubPackage epack; private final Report report; public EpubRenditionCheck(EpubPackage epack, Report report) { this.epack = epack; this.doc = epack.getPackDoc(); this.report = report; } @Override public boolean validate() { return isRenditionDefined(doc); } private boolean isRenditionDefined(Document doc) { boolean result = false; NodeList nList = doc.getElementsByTagName("metadata"); if (nList.getLength() > 0) { Node metadata = nList.item(0); NodeList metaNodes = metadata.getChildNodes(); for (int i = 0; i < metaNodes.getLength(); i++) { if (metaNodes.item(i).getNodeName().compareToIgnoreCase("meta") == 0) { Node n = metaNodes.item(i); String nodeValue; if (n.hasChildNodes()) { nodeValue = n.getFirstChild().getNodeValue(); } else { nodeValue = n.getNodeValue(); } NamedNodeMap attrs = n.getAttributes(); Node p = attrs.getNamedItem("property"); if (p != null) { if (p.getNodeValue().contains("rendition:layout")) { report.info(null, FeatureEnum.RENDITION_LAYOUT, nodeValue); result = true; } if (p.getNodeValue().contains("rendition:orientation")) { report.info(null, FeatureEnum.RENDITION_ORIENTATION, nodeValue); result = true; } if (p.getNodeValue().contains("rendition:spread")) { report.info(null, FeatureEnum.RENDITION_SPREAD, nodeValue); result = true; } } } } } NodeList mList = doc.getElementsByTagName("spine"); if (mList.getLength() > 0) { Node manifest = mList.item(0); NodeList itemNodes = manifest.getChildNodes(); String renditionLayout = "rendition:layout-"; String renditionOrientation = "rendition:orientation-"; String renditionSpread = "rendition:spread-"; for (int i = 0; i < itemNodes.getLength(); i++) { if (itemNodes.item(i).getNodeName().compareToIgnoreCase("itemref") == 0) { Node n = itemNodes.item(i); String nodeValue; NamedNodeMap attrs = n.getAttributes(); Node p = attrs.getNamedItem("properties"); Node idrefNode = attrs.getNamedItem("idref"); String idref; ManifestItem manifestItem; String href = ""; if (idrefNode != null) { idref = idrefNode.getNodeValue(); manifestItem = epack.getManifest().getItem(idref); if (manifestItem != null) { href = epack.getManifestItemFileName(manifestItem); } } if (p != null) { // if (p.hasChildNodes()) { nodeValue = p.getFirstChild().getNodeValue(); } else { nodeValue = p.getNodeValue(); } if (p.getNodeValue().contains(renditionLayout)) { report.info(href, FeatureEnum.RENDITION_LAYOUT, nodeValue.substring(renditionLayout.length())); result = true; } if (p.getNodeValue().contains(renditionOrientation)) { report.info(href, FeatureEnum.RENDITION_ORIENTATION, nodeValue.substring(renditionOrientation.length())); result = true; } if (p.getNodeValue().contains(renditionSpread)) { report.info(href, FeatureEnum.RENDITION_SPREAD, nodeValue.substring(renditionSpread.length())); result = true; } } } } } return result; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ctc/CheckManager.java0000644000175000017500000000447513017276730025131 0ustar eugeneeugenepackage com.adobe.epubcheck.ctc; import java.util.zip.ZipFile; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.ctc.ContentValidator.ValidationType; import com.adobe.epubcheck.ctc.epubpackage.EpubPackage; import com.adobe.epubcheck.util.EPUBVersion; public class CheckManager { private final EpubPackage epack; private final EpubCheckContentFactory factory; private Report report; public CheckManager(ZipFile zip, Report report) { setReport(report); PackageReader pr = new PackageReader(zip, report); epack = pr.readPackageData(); factory = EpubCheckContentFactory.getInstance(); } private void setReport(Report report) { this.report = report; } public void checkPackage() { if (epack == null) { return; } EPUBVersion version = epack.getVersion(); if (version != null && version.equals(EPUBVersion.VERSION_3)) { factory.newInstance(report, ValidationType.RENDITION, epack).validate(); factory.newInstance(report, ValidationType.CFI, epack).validate(); factory.newInstance(report, ValidationType.METADATA_V3, epack).validate(); factory.newInstance(report, ValidationType.NAV, epack).validate(); } else if (version != null && EPUBVersion.VERSION_2.equals(version)) { factory.newInstance(report, ValidationType.EPUB3_STRUCTURE, epack).validate(); factory.newInstance(report, ValidationType.METADATA_V2, epack).validate(); } factory.newInstance(report, ValidationType.NCX, epack).validate(); factory.newInstance(report, ValidationType.MULTIPLE_CSS, epack).validate(); factory.newInstance(report, ValidationType.HTML_STRUCTURE, epack).validate(); factory.newInstance(report, ValidationType.LINK, epack).validate(); factory.newInstance(report, ValidationType.CSS_SEARCH, epack).validate(); factory.newInstance(report, ValidationType.TOC, epack).validate(); factory.newInstance(report, ValidationType.LANG, epack).validate(); factory.newInstance(report, ValidationType.SPINE, epack).validate(); factory.newInstance(report, ValidationType.TEXT, epack).validate(); factory.newInstance(report, ValidationType.SCRIPT, epack).validate(); factory.newInstance(report, ValidationType.SPAN, epack).validate(); factory.newInstance(report, ValidationType.SVG, epack).validate(); } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ctc/epubpackage/0000755000175000017500000000000013017276730024213 5ustar eugeneeugeneepubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ctc/epubpackage/PackageSpine.java0000644000175000017500000000171113017276730027410 0ustar eugeneeugenepackage com.adobe.epubcheck.ctc.epubpackage; import java.util.Vector; public class PackageSpine { private String toc; private String id; private String pageProgressionDirection; private final Vector items = new Vector(); public Vector getItems() { return items; } public int itemsLength() { return items.size(); } public void addItem(SpineItem mi) { items.add(mi); } public SpineItem getItem(int i) { return items.get(i); } public String getToc() { return toc; } public void setToc(String toc) { this.toc = toc; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getPageProgressionDirection() { return pageProgressionDirection; } public void setPageProgressionDirection(String pageProgressionDirection) { this.pageProgressionDirection = pageProgressionDirection; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ctc/epubpackage/EpubPackage.java0000644000175000017500000000740413017276730027232 0ustar eugeneeugenepackage com.adobe.epubcheck.ctc.epubpackage; import com.adobe.epubcheck.util.EPUBVersion; import com.adobe.epubcheck.util.PathUtil; import org.w3c.dom.Document; import java.io.File; import java.util.zip.ZipFile; public class EpubPackage { private String packageMainFilePath; private ZipFile zip; private Document packDoc; private String packageMainPath = ""; private PackageManifest manifest = new PackageManifest(); private PackageSpine spine = new PackageSpine(); private PackageMetadata metadata = new PackageMetadata(); private EPUBVersion version; private final String fileName; public String getFileName() { return this.fileName; } public Document getPackDoc() { return packDoc; } void setPackDoc(Document packDoc) { this.packDoc = packDoc; } public PackageMetadata getMetadata() { return metadata; } public void setMetadata(PackageMetadata metadata) { this.metadata = metadata; } public EPUBVersion getVersion() { return version; } public void setVersion(EPUBVersion version) { this.version = version; } public EpubPackage(String packageMainFile, ZipFile zip, Document doc) { setPackageMainFile(packageMainFile); setZip(zip); setPackDoc(doc); if (packageMainFile.lastIndexOf('/') > 0) { setPackageMainPath(packageMainFile.substring(0, packageMainFile.lastIndexOf('/'))); } setManifest(new PackageManifest()); setSpine(new PackageSpine()); File file = new File(zip.getName()); this.fileName = file.getName(); } public String getPackageMainFile() { return packageMainFilePath; } public void setPackageMainFile(String packageMainFile) { this.packageMainFilePath = packageMainFile; } public String getPackageMainPath() { return packageMainPath; } void setPackageMainPath(String packageMainPath) { this.packageMainPath = packageMainPath; } public PackageManifest getManifest() { return manifest; } public void setManifest(PackageManifest manifest) { this.manifest = manifest; } public PackageSpine getSpine() { return spine; } public void setSpine(PackageSpine spine) { this.spine = spine; } public ZipFile getZip() { return zip; } void setZip(ZipFile zip) { this.zip = zip; } public boolean isSpineItem(String id) { if (id == null || id.equals("")) { return false; } for (SpineItem item : spine.getItems()) { if (id.equals(item.getIdref())) { return true; } } return false; } public static boolean isGlobalFixed(EpubPackage epack) { for (MetadataElement me : epack.getMetadata().getMetaElements()) { if ("rendition:layout".equals(me.getName())) { return ("pre-paginated".equals(me.getValue())); } else if ("meta".equals(me.getName())) { String property = me.getAttribute("property"); if ("rendition:layout".equals(property)) { return ("pre-paginated".equals(me.getValue())); } } } return false; } public String getManifestItemFileName(ManifestItem mi) { if (mi != null) { return getManifestItemFileName(mi.getHref()); } return ""; } public String getManifestItemFileName(String entryName) { if (entryName == null) return ""; String fileToParse; if (this.getPackageMainPath() != null && this.getPackageMainPath().length() > 0) { fileToParse = PathUtil.resolveRelativeReference(this.getPackageMainFile(), entryName, null); } else { fileToParse = entryName; } int hash = fileToParse.lastIndexOf("#"); if (hash > 0) { fileToParse = fileToParse.substring(0, hash); } return fileToParse; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ctc/epubpackage/PackageMetadata.java0000644000175000017500000000051313017276730030051 0ustar eugeneeugenepackage com.adobe.epubcheck.ctc.epubpackage; import java.util.Vector; public class PackageMetadata { private final Vector m = new Vector(); public Vector getMetaElements() { return m; } public void addMetaElement(MetadataElement meta) { m.add(meta); } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ctc/epubpackage/PackageManifest.java0000644000175000017500000000130313017276730030075 0ustar eugeneeugenepackage com.adobe.epubcheck.ctc.epubpackage; import java.util.Vector; public class PackageManifest { private final Vector items = new Vector(); public Vector getItems() { return items; } public int itemsLength() { return items.size(); } public void addItem(ManifestItem mi) { items.add(mi); } public ManifestItem getItem(int i) { return items.get(i); } public ManifestItem getItem(String id) { if (id == null || id.trim().equals("")) { return null; } for (ManifestItem item : items) { if (id.trim().equals(item.getId().trim())) { return item; } } return null; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ctc/epubpackage/SpineItem.java0000644000175000017500000000125613017276730026757 0ustar eugeneeugenepackage com.adobe.epubcheck.ctc.epubpackage; public class SpineItem { private String idref; private String id; private String linear; private String properties; public String getIdref() { return idref; } public void setIdref(String idref) { this.idref = idref; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getLinear() { return linear; } public void setLinear(String linear) { this.linear = linear; } public String getProperties() { return properties; } public void setProperties(String properties) { this.properties = properties; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ctc/epubpackage/ManifestItem.java0000644000175000017500000000127713017276730027452 0ustar eugeneeugenepackage com.adobe.epubcheck.ctc.epubpackage; public class ManifestItem { private String id; private String href; private String mediaType; private String properties; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getHref() { return href; } public void setHref(String href) { this.href = href; } public String getMediaType() { return mediaType; } public void setMediaType(String mediaType) { this.mediaType = mediaType; } public String getProperties() { return properties; } public void setProperties(String properties) { this.properties = properties; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ctc/epubpackage/MetadataElement.java0000644000175000017500000000137113017276730030112 0ustar eugeneeugenepackage com.adobe.epubcheck.ctc.epubpackage; import java.util.HashMap; public class MetadataElement { private final HashMap attributes = new HashMap(); private String value = ""; private String name = ""; public void addAttribute(String attrName, String attrValue) { attributes.put(attrName, attrValue); } public HashMap getAllAttributes() { return attributes; } public String getAttribute(String attrName) { return attributes.get(attrName); } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ctc/Epub3StructureCheck.java0000644000175000017500000000362113017276730026446 0ustar eugeneeugenepackage com.adobe.epubcheck.ctc; import java.util.zip.ZipEntry; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.ctc.epubpackage.EpubPackage; import com.adobe.epubcheck.ctc.epubpackage.ManifestItem; import com.adobe.epubcheck.ctc.xml.Epub3StructureHandler; import com.adobe.epubcheck.ctc.xml.XMLContentDocParser; import com.adobe.epubcheck.opf.DocumentValidator; import com.adobe.epubcheck.util.SearchDictionary; import com.adobe.epubcheck.util.SearchDictionary.DictionaryType; public class Epub3StructureCheck implements DocumentValidator { private final Report report; private final EpubPackage epack; public Epub3StructureCheck(EpubPackage epack, Report report) { this.report = report; this.epack = epack; } @Override public boolean validate() { boolean result = false; SearchDictionary vtsd = new SearchDictionary(DictionaryType.VALID_TEXT_MEDIA_TYPES); for (int i = 0; i < epack.getManifest().itemsLength(); i++) { ManifestItem mi = epack.getManifest().getItem(i); if (vtsd.isValidMediaType(mi.getMediaType())) { XMLContentDocParser parser = new XMLContentDocParser(epack.getZip(), report); Epub3StructureHandler epub3StructureHandler = new Epub3StructureHandler(); String fileToParse = epack.getManifestItemFileName(mi); ZipEntry entry = epack.getZip().getEntry(fileToParse); if (entry == null) { // already reported in core checkers // report.message(MessageId.RSC_001, EPUBLocation.create(epack.getFileName()), fileToParse); continue; } epub3StructureHandler.setFileName(epack.getFileName()); epub3StructureHandler.setReport(report); parser.parseDoc(fileToParse, epub3StructureHandler); if (epub3StructureHandler.getSpecificTagsCount() > 0) { result = true; } } } return result; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ctc/EpubCSSCheck.java0000644000175000017500000001570713017276730025023 0ustar eugeneeugenepackage com.adobe.epubcheck.ctc; import java.io.IOException; import java.io.InputStream; import java.util.Collection; import java.util.Hashtable; import java.util.Vector; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import org.idpf.epubcheck.util.css.CssParser; import org.idpf.epubcheck.util.css.CssSource; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.ctc.css.EpubCSSCheckCSSHandler; import com.adobe.epubcheck.ctc.epubpackage.EpubPackage; import com.adobe.epubcheck.ctc.epubpackage.ManifestItem; import com.adobe.epubcheck.ctc.xml.CSSStyleAttributeHandler; import com.adobe.epubcheck.ctc.xml.XMLContentDocParser; import com.adobe.epubcheck.messages.MessageId; import com.adobe.epubcheck.ocf.EncryptionFilter; import com.adobe.epubcheck.opf.DocumentValidator; import com.adobe.epubcheck.util.PathUtil; import com.adobe.epubcheck.util.SearchDictionary; import com.adobe.epubcheck.util.SearchDictionary.DictionaryType; import com.adobe.epubcheck.util.TextSearchDictionaryEntry; public class EpubCSSCheck implements DocumentValidator { final ZipFile zip; final Report report; final EpubPackage epack; final Hashtable enc; static final int EXCESSIVE_CSS_THRESHOLD = 10; final boolean isGlobalFixed; public EpubCSSCheck(EpubPackage epack, Report report) { this.epack = epack; this.zip = epack.getZip(); this.enc = new Hashtable(); this.report = report; this.isGlobalFixed = EpubPackage.isGlobalFixed(epack); } public boolean validate() { boolean hasFixedFormatItems = getHasFixedFormatItems(epack); SearchDictionary tsd = new SearchDictionary(DictionaryType.CSS_VALUES); SearchDictionary cssTypes = new SearchDictionary(DictionaryType.CSS_FILES); SearchDictionary validTypes = new SearchDictionary(DictionaryType.VALID_TEXT_MEDIA_TYPES); EpubCSSCheckCSSHandler handler = new EpubCSSCheckCSSHandler(report, isGlobalFixed, hasFixedFormatItems); int numCssFiles = 0; for (int i = 0; i < epack.getManifest().itemsLength(); i++) { ManifestItem itemEntry = epack.getManifest().getItem(i); if (cssTypes.isValidMediaType(itemEntry.getMediaType())) { ++numCssFiles; String fileToParse = getEntryFileName(itemEntry, epack); ZipEntry entry = epack.getZip().getEntry(fileToParse); if (entry == null) { // already reported in core checkers // report.message(MessageId.RSC_001, EPUBLocation.create(epack.getFileName()), fileToParse); continue; } try { InputStream inputStream = getInputStream(fileToParse); CssSource source = new CssSource(fileToParse, inputStream); CssParser parser = new CssParser(); handler.setPath(fileToParse); parser.parse(source, handler, handler); } catch (Exception e) { e.printStackTrace(); } } } for (int i = 0; i < epack.getManifest().itemsLength(); i++) { ManifestItem itemEntry = epack.getManifest().getItem(i); if (validTypes.isValidMediaType(itemEntry.getMediaType())) { String fileToParse = getEntryFileName(itemEntry, epack); ZipEntry entry = epack.getZip().getEntry(fileToParse); if (entry == null) { // already reported in core checkers // report.message(MessageId.RSC_001, EPUBLocation.create(epack.getFileName()), fileToParse); continue; } XMLContentDocParser parser; String properties = itemEntry.getProperties(); boolean itemIsFixedFormat = (properties != null && properties.contains("rendition:layout-pre-paginated")); parser = new XMLContentDocParser(epack.getZip(), report); CSSStyleAttributeHandler h = new CSSStyleAttributeHandler(isGlobalFixed, itemIsFixedFormat); h.setCssHandler(handler); h.setReport(report); h.setFileName(fileToParse); parser.parseDoc(fileToParse, h); Vector styleTags = h.getStyleTagValues(); for (int t = 0; t < styleTags.size(); t++) { CSSStyleAttributeHandler.StyleAttribute value = styleTags.elementAt(t); searchInsideValue(value, tsd, fileToParse); } Collection styleAttributes = h.getStyleAttributesValues(); for (CSSStyleAttributeHandler.StyleAttribute value : styleAttributes) { searchInsideValue(value, tsd, fileToParse); report.message(MessageId.ACC_013, EPUBLocation.create(fileToParse, value.getLine(), value.getColumn(), value.getValue())); } } } CheckUnusedCSSClassSelectors(handler, report); if (numCssFiles > EXCESSIVE_CSS_THRESHOLD) { report.message(MessageId.CSS_011, EPUBLocation.create(epack.getFileName())); } return true; } boolean getHasFixedFormatItems(EpubPackage epack) { for (int i = 0; i < epack.getManifest().itemsLength(); i++) { ManifestItem itemEntry = epack.getManifest().getItem(i); String properties = itemEntry.getProperties(); if (properties != null && properties.contains("rendition:layout-pre-paginated")) { return true; } } return false; } void CheckUnusedCSSClassSelectors(EpubCSSCheckCSSHandler handler, Report report) { if (handler != null) { handler.CheckUnusedCSSClassSelectors(report); } } static String getEntryFileName(ManifestItem itemEntry, EpubPackage epack) { String fileToParse; if (epack.getPackageMainPath() != null && epack.getPackageMainPath().length() > 0) { fileToParse = PathUtil.resolveRelativeReference(epack.getPackageMainFile(), itemEntry.getHref(), null); } else { fileToParse = itemEntry.getHref(); } return fileToParse; } InputStream getInputStream(String name) throws IOException { ZipEntry entry = zip.getEntry(name); if (entry == null) { return null; } InputStream in = zip.getInputStream(entry); EncryptionFilter filter = enc.get(name); if (filter == null) { return in; } if (filter.canDecrypt()) { return filter.decrypt(in); } return null; } void searchInsideValue(CSSStyleAttributeHandler.StyleAttribute entry, SearchDictionary tds, String file) { for (int s = 0; s < tds.getDictEntries().size(); s++) { TextSearchDictionaryEntry de = tds.getDictEntries().get(s); MessageId messageCode = de.getErrorCode(); Pattern p = de.getPattern(); Matcher matcher = p.matcher(entry.getValue()); int position = 0; while (matcher.find(position)) { position = matcher.end(); report.message(messageCode, EPUBLocation.create(file, entry.getLine(), entry.getColumn(), entry.getValue().trim())); } } } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ctc/XmlDocParser.java0000644000175000017500000001736113017276730025162 0ustar eugeneeugenepackage com.adobe.epubcheck.ctc; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.Hashtable; import java.util.Stack; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.xml.sax.Attributes; import org.xml.sax.Locator; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.messages.MessageId; import com.adobe.epubcheck.ocf.EncryptionFilter; import com.adobe.epubcheck.util.EpubConstants; import com.adobe.epubcheck.util.NamespaceHelper; class XmlDocParser { private final ZipFile zip; private final Hashtable enc; private final Report report; public XmlDocParser(ZipFile zip, Report report) { this.zip = zip; this.enc = new Hashtable(); this.report = report; } public Document parseDocument(String fileEntry) { Document doc = null; InputStream is = null; try { is = getInputStream(fileEntry); if (is == null) { String fileName = new File(zip.getName()).getName(); report.message(MessageId.RSC_001, EPUBLocation.create(fileName), fileEntry); } else { doc = readXML(report, fileEntry, is, EpubConstants.ElementLineNumberAttribute, EpubConstants.ElementColumnNumberAttribute); } } catch (IOException e) { // Ignore, should have been reported earlier // report.message(MessageId.PKG_008, EPUBLocation.create(fileEntry), // fileEntry); } catch (SAXException e) { // Ignore, should have been reported earlier // report.message(MessageId.RSC_005, EPUBLocation.create(fileEntry), // e.getMessage()); doc = null; } finally { if (is != null) { try { is.close(); } catch (Exception ignore) { } } } return doc; } InputStream getInputStream(String name) throws IOException { ZipEntry entry = zip.getEntry(name); if (entry == null) { return null; } InputStream in = zip.getInputStream(entry); EncryptionFilter filter = enc.get(name); if (filter == null) { return in; } if (filter.canDecrypt()) { return filter.decrypt(in); } return null; } private Document readXML(Report report, String fileEntry, InputStream is, final String lineNumAttribName, final String columnNumAttribName) throws IOException, SAXException { final Document doc; SAXParser parser; try { SAXParserFactory factory = SAXParserFactory.newInstance(); factory.setFeature("http://xml.org/sax/features/namespaces", true); //default false factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);//default true factory.setFeature("http://xml.org/sax/features/external-general-entities", false); factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false); parser = factory.newSAXParser(); //tell parser about the lexical handler DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance(); docBuilderFactory.setFeature("http://xml.org/sax/features/external-general-entities", false); docBuilderFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", false); DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder(); doc = docBuilder.newDocument(); } catch (ParserConfigurationException e) { throw new RuntimeException("Can't create SAX parser / DOM builder.", e); } MyHandler handler = new MyHandler(doc, report, fileEntry, lineNumAttribName, columnNumAttribName); parser.parse(is, handler); return doc; } static public int getElementLineNumber(Element element) { return getElementAttributeAsInt(element, EpubConstants.ElementLineNumberAttribute); } static public int getElementColumnNumber(Element element) { return getElementAttributeAsInt(element, EpubConstants.ElementColumnNumberAttribute); } static int getElementAttributeAsInt(Element whichElement, String whichAttribute) { int result = -1; String attr = whichElement.getAttribute(whichAttribute); if (attr != null && attr.length() > 0) { result = Integer.parseInt(attr); } return result; } class MyHandler extends DefaultHandler { private Locator locator; private final NamespaceHelper namespaceHelper = new NamespaceHelper(); private Report report; private String fileName; private Document doc; private String lineNumAttribName; private String columnNumAttribName; final Stack elementStack = new Stack(); final StringBuilder textBuffer = new StringBuilder(); public MyHandler(Document doc, Report report, String fileName, String lineNumAttribName, String columnNumAttribName) { this.doc = doc; this.report = report; this.fileName = fileName; this.lineNumAttribName = lineNumAttribName; this.columnNumAttribName = columnNumAttribName; } @Override public void setDocumentLocator(Locator locator) { this.locator = locator; //Save the locator, so that it can be used later for line tracking when traversing nodes. } public void setReport(Report report) { this.report = report; } @Override public void startPrefixMapping (String prefix, String uri) throws SAXException { namespaceHelper.declareNamespace(prefix, uri, EPUBLocation.create(fileName, locator.getLineNumber(), locator.getColumnNumber(), prefix), report); } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { namespaceHelper.onStartElement(fileName, locator, uri, qName, attributes, report); addTextIfNeeded(); Element el = doc.createElementNS(uri, qName); for (int i = 0; i < attributes.getLength(); i++) { String attributeURI = attributes.getURI(i); if (attributeURI == null || attributeURI.equals("")) { attributeURI = uri; } el.setAttributeNS(attributeURI, attributes.getQName(i), attributes.getValue(i)); } el.setAttribute(lineNumAttribName, String.valueOf(locator.getLineNumber())); el.setAttribute(columnNumAttribName, String.valueOf(locator.getColumnNumber())); elementStack.push(el); } @Override public void endElement(String uri, String localName, String qName) { addTextIfNeeded(); Element closedEl = elementStack.pop(); if (elementStack.isEmpty()) { // Is this the root element? doc.appendChild(closedEl); } else { Element parentEl = elementStack.peek(); parentEl.appendChild(closedEl); } namespaceHelper.onEndElement(report); } @Override public void characters(char ch[], int start, int length) throws SAXException { textBuffer.append(ch, start, length); } // Outputs text accumulated under the current node private void addTextIfNeeded() { if (textBuffer.length() > 0) { Element el = elementStack.peek(); Node textNode = doc.createTextNode(textBuffer.toString()); el.appendChild(textNode); textBuffer.delete(0, textBuffer.length()); } } }; } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ctc/EpubSVGCheck.java0000644000175000017500000001077413017276730025031 0ustar eugeneeugenepackage com.adobe.epubcheck.ctc; import java.util.Hashtable; import java.util.zip.ZipEntry; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.ctc.epubpackage.EpubPackage; import com.adobe.epubcheck.ctc.epubpackage.ManifestItem; import com.adobe.epubcheck.ctc.epubpackage.SpineItem; import com.adobe.epubcheck.messages.MessageId; import com.adobe.epubcheck.opf.DocumentValidator; import com.adobe.epubcheck.util.SearchDictionary; public class EpubSVGCheck implements DocumentValidator { private static final String svgNS = "http://www.w3.org/2000/svg"; private static final String xlinkNS = "http://www.w3.org/1999/xlink"; private final XmlDocParser docParser; private final Report report; private final EpubPackage epack; private boolean isGlobalFixedFormat; public EpubSVGCheck(EpubPackage epack, Report report) { this.report = report; this.epack = epack; docParser = new XmlDocParser(epack.getZip(), report); this.isGlobalFixedFormat = EpubPackage.isGlobalFixed(epack); } @Override public boolean validate() { SearchDictionary validTypes = new SearchDictionary(SearchDictionary.DictionaryType.SVG_MEDIA_TYPES); boolean isGlobalFixed = EpubPackage.isGlobalFixed(this.epack); Hashtable spineItems = new Hashtable(); for (int i = 0; i < epack.getSpine().itemsLength(); ++i) { SpineItem si = epack.getSpine().getItem(i); spineItems.put(si.getIdref(), si); } for (int i = 0; i < epack.getManifest().itemsLength(); i++) { ManifestItem itemEntry = epack.getManifest().getItem(i); if (validTypes.isValidMediaType(itemEntry.getMediaType())) { String fileToParse = epack.getManifestItemFileName(itemEntry); ZipEntry entry = epack.getZip().getEntry(fileToParse); if (entry == null) { // already reported in core checkers // report.message(MessageId.RSC_001, EPUBLocation.create(epack.getFileName()), fileToParse); continue; } SpineItem si = spineItems.get(itemEntry.getId()); boolean itemIsFixedFormat = isGlobalFixed; if (si != null) { String properties = si.getProperties(); if (properties != null) { if (properties.length() != 0) { properties = properties.replaceAll("[\\s]+", " "); String propertyArray[] = properties.split(" "); for (String prop : propertyArray) { if (prop.equals("rendition:layout-pre-paginated")) { itemIsFixedFormat = true; } else if (prop.equals("rendition:layout-reflowable")) { itemIsFixedFormat = false; } } } } if (itemIsFixedFormat) { checkSvgDoc(fileToParse); } } } } return true; } void checkSvgDoc(String svgDocEntry) { Document doc = docParser.parseDocument(svgDocEntry); if (doc != null) { checkViewBox(svgDocEntry, doc); checkImageXlinkHrefInline(svgDocEntry, doc); } } void checkViewBox(String svgDocEntry, Document doc) { NodeList n = doc.getElementsByTagNameNS(svgNS, "svg"); for (int i = 0; i < n.getLength(); i++) { Element svgElement = (Element) n.item(i); String viewport = svgElement.getAttributeNS(svgNS, "viewBox"); if (viewport == null || viewport.length() == 0) { report.message(MessageId.HTM_048, EPUBLocation.create(svgDocEntry, XmlDocParser.getElementLineNumber(svgElement), XmlDocParser.getElementColumnNumber(svgElement))); } } } void checkImageXlinkHrefInline(String svgDocEntry, Document doc) { NodeList n = doc.getElementsByTagNameNS(svgNS, "image"); for (int i = 0; i < n.getLength(); i++) { Element svgElement = (Element) n.item(i); String href = svgElement.getAttributeNS(xlinkNS, "href"); if (href != null && href.length() > 0) { if (!href.startsWith("data:image")) { report.message(MessageId.MED_006, EPUBLocation.create(svgDocEntry, XmlDocParser.getElementLineNumber(svgElement), XmlDocParser.getElementColumnNumber(svgElement))); } } } } public boolean isGlobalFixedFormat() { return isGlobalFixedFormat; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ctc/EpubHTML5StructureCheck.java0000644000175000017500000002302513017276730027135 0ustar eugeneeugenepackage com.adobe.epubcheck.ctc; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.Hashtable; import java.util.Scanner; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.ctc.epubpackage.EpubPackage; import com.adobe.epubcheck.ctc.epubpackage.ManifestItem; import com.adobe.epubcheck.ctc.epubpackage.SpineItem; import com.adobe.epubcheck.ctc.xml.HTMLTagsAnalyseHandler; import com.adobe.epubcheck.ctc.xml.XMLContentDocParser; import com.adobe.epubcheck.messages.MessageId; import com.adobe.epubcheck.ocf.EncryptionFilter; import com.adobe.epubcheck.opf.DocumentValidator; import com.adobe.epubcheck.util.EPUBVersion; import com.adobe.epubcheck.util.FeatureEnum; import com.adobe.epubcheck.util.SearchDictionary; import com.adobe.epubcheck.util.SearchDictionary.DictionaryType; public class EpubHTML5StructureCheck implements DocumentValidator { static final int hasHtml = 1; static final int hasPublic = 2; static final int hasW3C = 4; static final int hasXhtml = 8; static final int hasHTML5 = hasHtml; static final int hasHTML4 = hasPublic | hasW3C | hasXhtml; final ZipFile zip; final Report report; final EpubPackage epubPackage; final Hashtable enc; public EpubHTML5StructureCheck(EpubPackage epack, Report report) { this.zip = epack.getZip(); this.report = report; this.epubPackage = epack; this.enc = new Hashtable(); } @Override public boolean validate() { boolean result = false; SearchDictionary vtsd = new SearchDictionary(DictionaryType.VALID_TEXT_MEDIA_TYPES); int landmarkNavCount = 0; boolean isGlobalFixed = EpubPackage.isGlobalFixed(this.epubPackage); Hashtable spineItems = new Hashtable(); for (int i = 0; i < epubPackage.getSpine().itemsLength(); ++i) { SpineItem si = epubPackage.getSpine().getItem(i); spineItems.put(si.getIdref(), si); } for (int i = 0; i < epubPackage.getManifest().itemsLength(); i++) { ManifestItem mi = epubPackage.getManifest().getItem(i); if (vtsd.isValidMediaType(mi.getMediaType())) { XMLContentDocParser parser = new XMLContentDocParser(epubPackage.getZip(), report); HTMLTagsAnalyseHandler sh = new HTMLTagsAnalyseHandler(); sh.setReport(report); SpineItem si = spineItems.get(mi.getId()); boolean itemIsFixedFormat = isGlobalFixed; if (si != null) { String properties = si.getProperties(); if (properties != null) { if (properties != null && !properties.equals("")) { properties = properties.replaceAll("[\\s]+", " "); String propertyArray[] = properties.split(" "); for (String prop : propertyArray) { if (prop.equals("rendition:layout-pre-paginated")) { itemIsFixedFormat = true; } else if (prop.equals("rendition:layout-reflowable")) { itemIsFixedFormat = false; } } } } sh.setIsFixed(itemIsFixedFormat); } String fileToParse = epubPackage.getManifestItemFileName(mi); ZipEntry entry = zip.getEntry(fileToParse); if (entry == null) { // already reported in core checkers // String fileName = new File(zip.getName()).getName(); // report.message(MessageId.RSC_001, EPUBLocation.create(fileName), fileToParse); continue; } sh.setVersion(epubPackage.getVersion()); sh.setFileName(fileToParse); //parser.parseDoc(fileToParse, sh); /***VALIDATE FILE EXTENSION***/ String fileExtension = mi.getHref().substring(mi.getHref().lastIndexOf('.') + 1, mi.getHref().length()); if (epubPackage.getVersion() == EPUBVersion.VERSION_2 && !(fileExtension.compareToIgnoreCase("html") == 0 || fileExtension.compareToIgnoreCase("htm") == 0 || fileExtension.compareToIgnoreCase("xhtml") == 0)) { // Note: extension is already checked in OPFChecker30 for EPUB 3 report.message(MessageId.HTM_014, EPUBLocation.create(epubPackage.getPackageMainPath() + "/" + mi.getHref())); } /***VALIDATE DOCTYPE***/ int docTypeMatches = findMatchingDocumentTypePatterns(fileToParse); if ((0 != (docTypeMatches & hasHTML4)) && (epubPackage.getVersion() == EPUBVersion.VERSION_3)) { report.message(MessageId.HTM_015, EPUBLocation.create(epubPackage.getPackageMainPath() + "/" + mi.getHref())); } else if ((0 != (docTypeMatches & hasHTML5)) && ((hasXhtml != (docTypeMatches & hasXhtml))) && (epubPackage.getVersion() == EPUBVersion.VERSION_2)) { report.message(MessageId.HTM_016, EPUBLocation.create(epubPackage.getPackageMainPath() + "/" + mi.getHref())); } parser.parseDoc(fileToParse, sh); if (sh.getHtml5SpecTagsCounter() > 0) { report.info(fileToParse, FeatureEnum.HAS_HTML5, "true"); if (epubPackage.isSpineItem(mi.getId())) { // Report that there is HTML5 for the entire publication only if it is in a spine item. // This is used for the 'is backward compatible' check. // This is so the HTML5 (nav tag) in a toc document will be ignored for backwards compatibility testing. report.info(null, FeatureEnum.HAS_HTML5, "true"); } } landmarkNavCount += sh.getLandmarkNavCount(); } } if (landmarkNavCount != 1 && epubPackage.getVersion() == EPUBVersion.VERSION_3) { File zipFile = new File(zip.getName()); report.message(MessageId.ACC_008, EPUBLocation.create(zipFile.getName())); } return result; } InputStream getInputStream(String name) throws IOException { ZipEntry entry = zip.getEntry(name); if (entry == null) { return null; } InputStream in = zip.getInputStream(entry); EncryptionFilter filter = enc.get(name); if (filter == null) { return in; } if (filter.canDecrypt()) { return filter.decrypt(in); } return null; } static final Pattern patternDocTypeElement = Pattern.compile("<*!*[Dd][Oo][Cc][Tt][Yy][Pp][Ee]"); static final Pattern patternHtmlElement = Pattern.compile("([^Xx][Hh][Tt][Mm][Ll])"); static final Pattern patternPublicElement = Pattern.compile("[Pp][Uu][Bb][Ll][Ii][Cc]"); static final Pattern patternW3CElement = Pattern.compile("[Ww][3][Cc]//[Dd][Tt][Dd]"); static final Pattern patternXhtmlElement = Pattern.compile("[Xx][Hh][Tt][Mm][Ll]"); int findMatchingDocumentTypePatterns(String entry) { InputStream is = null; Scanner in = null; int matchingPatterns = 0; try { is = getInputStream(entry); if (is == null) { throw new IOException("Input Stream not found: '" + entry + "'"); } in = new Scanner(is); StringBuilder sb = new StringBuilder(); int numBracketsToClose = 0; String line = null; // skip over every line until we find the !DOCTYPE while (in.hasNextLine()) { line = in.nextLine(); Matcher matcher = patternDocTypeElement.matcher(line); if (matcher.find()) { numBracketsToClose = 1; int i = matcher.start(); if (i >= 0) { // prime it here so we can enter the loop below sb.append("<"); line = line.substring(i + 1); break; } } } // now start appending characters until we close all nested '<' with matching '>' while ((numBracketsToClose > 0) && (line != null)) { int i = 0; while ((numBracketsToClose > 0) && (i < line.length())) { Character ch = line.charAt(i); if (ch == '<') { ++numBracketsToClose; } else if (ch == '>') { --numBracketsToClose; } sb.append(ch); ++i; } if (in.hasNextLine()) { sb.append(" "); line = in.nextLine(); } else { line = null; } } if (numBracketsToClose > 0) { // There's an error. We ran out of characters before finding the matching '>' return -1; } line = sb.toString(); matchingPatterns |= checkPattern(line, patternHtmlElement, hasHtml); matchingPatterns |= checkPattern(line, patternPublicElement, hasPublic); matchingPatterns |= checkPattern(line, patternW3CElement, hasW3C); matchingPatterns |= checkPattern(line, patternXhtmlElement, hasXhtml); } catch (Exception e) { e.printStackTrace(); report.message(MessageId.PKG_008, EPUBLocation.create(entry), e.getMessage()); } finally { if (is != null) { try { is.close(); } catch (Exception ignore) { } } if (in != null) { in.close(); } } return matchingPatterns; } int checkPattern(String line, Pattern patternElement, int mask) { Matcher matcherElement = patternElement.matcher(line); return (matcherElement.find()) ? mask : 0; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ctc/EpubCfiCheck.java0000644000175000017500000000522713017276730025070 0ustar eugeneeugenepackage com.adobe.epubcheck.ctc; import java.io.File; import java.util.Vector; import java.util.zip.ZipEntry; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.ctc.epubpackage.EpubPackage; import com.adobe.epubcheck.ctc.epubpackage.ManifestItem; import com.adobe.epubcheck.ctc.xml.AnchorTagHandler; import com.adobe.epubcheck.ctc.xml.XMLContentDocParser; import com.adobe.epubcheck.messages.MessageId; import com.adobe.epubcheck.opf.DocumentValidator; import com.adobe.epubcheck.util.SearchDictionary; import com.adobe.epubcheck.util.SearchDictionary.DictionaryType; public class EpubCfiCheck implements DocumentValidator { private final Report report; private final EpubPackage epack; public EpubCfiCheck(EpubPackage epack, Report report) { this.epack = epack; this.report = report; } public boolean validate() { SearchDictionary validTypes = new SearchDictionary(DictionaryType.VALID_TEXT_MEDIA_TYPES); for (int i = 0; i < epack.getManifest().itemsLength(); i++) { ManifestItem itemEntry = epack.getManifest().getItem(i); if (validTypes.isValidMediaType(itemEntry.getMediaType())) { String fileToParse = epack.getManifestItemFileName(itemEntry); ZipEntry entry = epack.getZip().getEntry(fileToParse); if (entry == null) { // already reported in core checkers // report.message(MessageId.RSC_001, EPUBLocation.create(epack.getFileName()), fileToParse); continue; } XMLContentDocParser parser = new XMLContentDocParser(epack.getZip(), report); AnchorTagHandler h = new AnchorTagHandler(); parser.parseDoc(fileToParse, h); Vector v = h.getHrefAttributesValues(); for (int e = 0; e < v.size(); e++) { AnchorTagHandler.DocTagContent value = v.elementAt(e); searchInsideValue(value, fileToParse); } } } return true; } private void searchInsideValue(AnchorTagHandler.DocTagContent entry, String file) { String url = entry.getValue(); int frag = entry.getValue().indexOf("#epubcfi"); if (frag > -1) { String fileName = url.substring(0, frag); fileName = new File(fileName).getName(); if (entry.getValue().contains(".epub") && fileName.compareTo(file) != 0) { report.message(MessageId.HTM_012, EPUBLocation.create(file, entry.getLine(), entry.getColumn(), entry.getValue())); } else { report.message(MessageId.HTM_013, EPUBLocation.create(file, entry.getLine(), entry.getColumn(), entry.getValue())); } } } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ctc/EpubMetaDataV2Check.java0000644000175000017500000000144013017276730026250 0ustar eugeneeugenepackage com.adobe.epubcheck.ctc; import org.w3c.dom.Document; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.ctc.epubpackage.EpubPackage; import com.adobe.epubcheck.opf.DocumentValidator; public class EpubMetaDataV2Check implements DocumentValidator { private final Document doc; private final String pathRootFile; @SuppressWarnings("unused") private final Report report; public EpubMetaDataV2Check(EpubPackage epack, Report report) { this.doc = epack.getPackDoc(); this.pathRootFile = epack.getPackageMainFile(); this.report = report; } @Override public boolean validate() { return isMetaDataValid(doc, pathRootFile); } private boolean isMetaDataValid(Document doc, String pathRootFile) { return true; // no custom checks } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ctc/EpubScriptCheck.java0000644000175000017500000001621613017276730025633 0ustar eugeneeugenepackage com.adobe.epubcheck.ctc; import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.Locale; import java.util.regex.Matcher; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.ctc.epubpackage.EpubPackage; import com.adobe.epubcheck.ctc.epubpackage.ManifestItem; import com.adobe.epubcheck.ctc.xml.ScriptTagHandler; import com.adobe.epubcheck.ctc.xml.XMLContentDocParser; import com.adobe.epubcheck.messages.MessageId; import com.adobe.epubcheck.opf.DocumentValidator; import com.adobe.epubcheck.util.EPUBVersion; import com.adobe.epubcheck.util.FeatureEnum; import com.adobe.epubcheck.util.SearchDictionary; import com.adobe.epubcheck.util.SearchDictionary.DictionaryType; public class EpubScriptCheck implements DocumentValidator { private final ZipFile zip; private final Report report; private final EpubPackage epack; public EpubScriptCheck(EpubPackage epack, Report report) { this.zip = epack.getZip(); this.report = report; this.epack = epack; } @Override public boolean validate() { boolean result = false; SearchDictionary vtsd = new SearchDictionary(DictionaryType.VALID_TEXT_MEDIA_TYPES); for (int i = 0; i < epack.getManifest().itemsLength(); i++) { ManifestItem mi = epack.getManifest().getItem(i); if (vtsd.isValidMediaType(mi.getMediaType())) { XMLContentDocParser parser = new XMLContentDocParser(this.zip, report); ScriptTagHandler sh = new ScriptTagHandler(this.report); String fileToParse = epack.getManifestItemFileName(mi); ZipEntry entry = this.zip.getEntry(fileToParse); if (entry == null) { // already reported in core checkers // report.message(MessageId.RSC_001, EPUBLocation.create(this.epack.getFileName()), fileToParse); continue; } sh.setFileName(fileToParse); sh.setVersion(epack.getVersion()); parser.parseDoc(fileToParse, sh); if (sh.getScriptElementCount() > 0 || sh.getInlineScriptCount() > 0) { if (sh.getInlineScriptCount() > 0) { report.info(fileToParse, FeatureEnum.SCRIPT, "inline"); } if (sh.getScriptElementCount() > 0) { report.info(fileToParse, FeatureEnum.SCRIPT, "tag"); } if (epack.getVersion() != EPUBVersion.VERSION_2) { report.message(MessageId.SCP_010, EPUBLocation.create(fileToParse)); if (mi.getProperties() == null || !mi.getProperties().contains("scripted")) { report.message(MessageId.SCP_005, EPUBLocation.create(fileToParse)); } } } } checkJavascript(mi); } return result; } void checkJavascript(ManifestItem mi) { InputStream is = null; BufferedReader reader = null; String mediaType = mi.getMediaType(); if (mediaType != null && "text/javascript".equalsIgnoreCase(mediaType)) { String fileToParse = epack.getManifestItemFileName(mi); ZipEntry entry = this.zip.getEntry(fileToParse); if (entry == null) { // already reported in core checkers // report.message(MessageId.RSC_001, EPUBLocation.create(fileToParse), fileToParse); return; } report.info(fileToParse, FeatureEnum.SCRIPT, "javascript"); report.info(fileToParse, FeatureEnum.HAS_SCRIPTS, ""); if (epack.getVersion() == EPUBVersion.VERSION_2) { report.message(MessageId.SCP_004, EPUBLocation.create(fileToParse)); } else { report.message(MessageId.SCP_010, EPUBLocation.create(fileToParse)); } try { is = zip.getInputStream(entry); reader = new BufferedReader(new InputStreamReader(is)); int lineNumber = 0; while (reader.ready()) { String line = reader.readLine(); ++lineNumber; CheckForInner(fileToParse, lineNumber, line); } reader.close(); is.close(); } catch (FileNotFoundException ex) { report.message(MessageId.RSC_001, EPUBLocation.create(fileToParse), fileToParse); } catch (IOException ex) { report.message(MessageId.PKG_008, EPUBLocation.create(fileToParse), fileToParse); } finally { if (reader != null) { try { reader.close(); } catch (IOException ignored) { } } if (is != null) { try { is.close(); } catch (IOException ignored) { } } } } } public void CheckForInner(String fileName, int line, String script) { String lower = script.toLowerCase(Locale.ROOT); int column = lower.indexOf("innerhtml"); if (column >= 0) { report.message(MessageId.SCP_007, EPUBLocation.create(fileName, line, column, trimContext(script, column))); } column = lower.indexOf("innertext"); if (column >= 0) { report.message(MessageId.SCP_008, EPUBLocation.create(fileName, line, column, trimContext(script, column))); } // the exact pattern is very complex and it slows down all script checking. // what we can do here is use a blunt check (for the word "eval"). if it is not found, keep moving. // If it is found, look closely using the exact pattern to see if the line truly matches the exact eval() function and report that. Matcher m = null; if (script.contains("eval")) { m = ScriptTagHandler.evalPattern.matcher(script); if (m.find()) { report.message(MessageId.SCP_001, EPUBLocation.create(fileName, line, m.start(0), trimContext(script, m.start()))); } } m = ScriptTagHandler.localStoragePattern.matcher(script); if (m.find()) { report.message(MessageId.SCP_003, EPUBLocation.create(fileName, line, m.start(0), trimContext(script, m.start()))); } m = ScriptTagHandler.sessionStoragePattern.matcher(script); if (m.find()) { report.message(MessageId.SCP_003, EPUBLocation.create(fileName, line, m.start(0), trimContext(script, m.start()))); } m = ScriptTagHandler.xmlHttpRequestPattern.matcher(script); if (m.find()) { report.message(MessageId.SCP_002, EPUBLocation.create(fileName, line, m.start(0), trimContext(script, m.start()))); } m = ScriptTagHandler.microsoftXmlHttpRequestPattern.matcher(script); if (m.find()) { report.message(MessageId.SCP_002, EPUBLocation.create(fileName, line, m.start(0), trimContext(script, m.start()))); } } static public String trimContext(String context, int start) { String trimmed = context.substring(start).trim(); int end = trimmed.indexOf("\n"); if (end < 0 && trimmed.length() < 60) { return trimmed; } else { int newEnd = Math.min(60, (end > 0 ? end : trimmed.length())); return trimmed.substring(0, newEnd); } } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ctc/xml/0000755000175000017500000000000013017276730022544 5ustar eugeneeugeneepubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ctc/xml/LinkTagHandler.java0000644000175000017500000001076713017276730026251 0ustar eugeneeugenepackage com.adobe.epubcheck.ctc.xml; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.messages.MessageId; import com.adobe.epubcheck.util.LocationImpl; import org.xml.sax.Attributes; import org.xml.sax.Locator; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; import javax.xml.stream.Location; import java.util.Vector; public class LinkTagHandler extends DefaultHandler { private final Report report; private Vector linkTags = new Vector(); public LinkTagHandler(Report report) { this.report = report; } private Locator locator; public void setDocumentLocator(Locator locator) { this.locator = locator; } private int styleSheetsCount = 0; public int getStyleSheetsCount() { return styleSheetsCount; } public void checkForMultipleStyleSheets(String fileName) { LinkMarkup firstOne = null; for (LinkMarkup linkTag : linkTags) { if (linkTag.relAttribute.compareToIgnoreCase("stylesheet") == 0) { if (++styleSheetsCount == 1) { firstOne = linkTag; } else if (styleSheetsCount > 1) { if (firstOne != null) { report.message(MessageId.CSS_012, EPUBLocation.create(fileName, firstOne.getLocation().getLineNumber(), firstOne.getLocation().getColumnNumber(), firstOne.getHrefAttribute())); firstOne = null; } report.message(MessageId.CSS_012, EPUBLocation.create(fileName, linkTag.getLocation().getLineNumber(), linkTag.getLocation().getColumnNumber(), linkTag.getHrefAttribute())); } } if (linkTag.relAttribute.compareToIgnoreCase("alternate stylesheet") == 0) { String title = linkTag.getTitleAttribute(); if (title == null || title.trim().equals("")) { report.message(MessageId.CSS_015, EPUBLocation.create(fileName, linkTag.getLocation().getLineNumber(), linkTag.getLocation().getColumnNumber(), linkTag.getHrefAttribute())); } if (styleSheetsCount == 0) { report.message(MessageId.CSS_016, EPUBLocation.create(fileName, linkTag.getLocation().getLineNumber(), linkTag.getLocation().getColumnNumber(), linkTag.getHrefAttribute())); } } } } public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if (qName.compareToIgnoreCase("link") == 0) { LinkMarkup la = new LinkMarkup(); for (int i = 0; i < attributes.getLength(); i++) { String attrName = attributes.getQName(i); String attrValue = attributes.getValue(i); if (attrName.compareToIgnoreCase("rel") == 0) { la.setRelAttribute(attrValue); } else if (attrName.compareToIgnoreCase("type") == 0) { la.setTypeAttribute(attrValue); } else if (attrName.compareToIgnoreCase("href") == 0) { la.setHrefAttribute(attrValue); } else if (attrName.compareToIgnoreCase("class") == 0) { la.setClassAttribute(attrValue); } else if (attrName.compareToIgnoreCase("title") == 0) { la.setTitleAttribute(attrValue); } la.setLocation(new LocationImpl(locator.getLineNumber(), locator.getColumnNumber(), -1, locator.getPublicId(), locator.getSystemId())); } linkTags.add(la); } } class LinkMarkup { String relAttribute = ""; String typeAttribute = ""; String hrefAttribute = ""; String classAttribute = ""; String titleAttribute = ""; Location location; public void setRelAttribute(String relAttribute) { this.relAttribute = relAttribute; } public void setTypeAttribute(String typeAttribute) { this.typeAttribute = typeAttribute; } public String getHrefAttribute() { return hrefAttribute; } public void setHrefAttribute(String hrefAttribute) { this.hrefAttribute = hrefAttribute; } public void setClassAttribute(String classAttribute) { this.classAttribute = classAttribute; } public String getTitleAttribute() { return titleAttribute; } public void setTitleAttribute(String value) { titleAttribute = value; } public Location getLocation() { return location; } public void setLocation(Location location) { this.location = location; } } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ctc/xml/XMLContentDocParser.java0000644000175000017500000000634713017276730027217 0ustar eugeneeugenepackage com.adobe.epubcheck.ctc.xml; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.util.Hashtable; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import org.xml.sax.helpers.DefaultHandler; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.messages.MessageId; import com.adobe.epubcheck.ocf.EncryptionFilter; public class XMLContentDocParser { private final ZipFile zip; private final Hashtable enc; private final Report report; public XMLContentDocParser(ZipFile zip, Report report) { this.zip = zip; this.enc = new Hashtable(); this.report = report; } public void parseDoc(String fileEntry, DefaultHandler handler) { InputStream is = null; try { is = getInputStream(fileEntry); SAXParserFactory factory = SAXParserFactory.newInstance(); factory.setFeature("http://xml.org/sax/features/external-general-entities", false); factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false); //factory.setValidating(false); //factory.setFeature("resolve-dtd-uris", false); SAXParser saxParser = factory.newSAXParser(); final XMLReader parser = saxParser.getXMLReader(); parser.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); parser.setFeature("http://xml.org/sax/features/validation", false); parser.setDTDHandler(handler); saxParser.parse(is, handler); } catch (FileNotFoundException e) { String message = e.getMessage(); message = new File(message).getName(); int p = message.indexOf("("); if (p > 0) { message = message.substring(0, message.indexOf("(")); } message = message.trim(); report.message(MessageId.RSC_001, EPUBLocation.create(fileEntry), message); } catch (IOException e) { // Ignore, should have been reported earlier // report.message(MessageId.PKG_008, EPUBLocation.create(fileEntry), // fileEntry); } catch (SAXException e) { // Ignore, should have been reported earlier // report.message(MessageId.RSC_005, EPUBLocation.create(fileEntry), // e.getMessage()); } catch (ParserConfigurationException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { if (is != null) { try { is.close(); } catch (Exception ignore) { } } } } InputStream getInputStream(String name) throws IOException { ZipEntry entry = zip.getEntry(name); if (entry == null) { return null; } InputStream in = zip.getInputStream(entry); EncryptionFilter filter = enc.get(name); if (filter == null) { return in; } if (filter.canDecrypt()) { return filter.decrypt(in); } return null; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ctc/xml/SpanTagHandler.java0000644000175000017500000000545113017276730026247 0ustar eugeneeugenepackage com.adobe.epubcheck.ctc.xml; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; import java.util.LinkedList; import java.util.Queue; import java.util.Vector; public class SpanTagHandler extends DefaultHandler { private Element currentElement = null; private Element topElement = null; private int generateMessage = 0; private long characterCount = 0; public Element getTopElement() { return topElement; } public int getGenerateMessage() { return generateMessage; } public void countNestedElements(Element e) { Queue elementQueue = new LinkedList(); int divElementsCounter = 0; int spanElementsCounter = 0; elementQueue.add(e); while (!elementQueue.isEmpty()) { e = elementQueue.remove(); if (e != null && e.elementName != null) { if (e.elementName.compareToIgnoreCase("DIV") == 0) { divElementsCounter++; } else if (e.elementName.compareToIgnoreCase("SPAN") == 0) { spanElementsCounter++; } for (int i = 0; i < e.nestedElements.size(); i++) { Element childElement = e.nestedElements.get(i); elementQueue.add(childElement); } } } long numWords = 1 + (characterCount / 6); if (numWords > 50) { if (((double) divElementsCounter / numWords > .10) || ((double) spanElementsCounter / numWords > .1)) { generateMessage++; } } } public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { Element newElement = new Element(qName); newElement.setParentElement(currentElement); if (currentElement != null) { currentElement.addNestedElement(newElement); currentElement = newElement; } else { currentElement = newElement; topElement = currentElement; } } public void endElement(String uri, String localName, String qName) throws SAXException { currentElement = currentElement.getParentElement(); } public void characters(char ch[], int start, int length) throws SAXException { characterCount += (long) length; //outWriter.println("-----Tag value----------->" + new String(ch, start, length)); } class Element { Element parentElement; final Vector nestedElements = new Vector(); final String elementName; public Element(String name) { elementName = name; } public void setParentElement(Element e) { parentElement = e; } public Element getParentElement() { return parentElement; } public void addNestedElement(Element e) { nestedElements.add(e); } } }epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ctc/xml/CSSStyleAttributeHandler.java0000644000175000017500000002234313017276730030246 0ustar eugeneeugenepackage com.adobe.epubcheck.ctc.xml; import java.io.ByteArrayInputStream; import java.io.InputStream; import java.util.Collection; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Locale; import java.util.Stack; import java.util.Vector; import org.idpf.epubcheck.util.css.CssParser; import org.idpf.epubcheck.util.css.CssSource; import org.xml.sax.Attributes; import org.xml.sax.Locator; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.ctc.css.EpubCSSCheckCSSHandler; import com.adobe.epubcheck.messages.MessageId; import com.adobe.epubcheck.util.LocationImpl; public class CSSStyleAttributeHandler extends DefaultHandler { String fileName; Stack tagStack = new Stack(); private Locator locator; private boolean inStyleTag = false; private boolean isGlobalFixedFormat = false; private boolean documentIsFixedFormat = false; private CSSStyleAttributeHandler.StyleAttribute currentStyleTag = null; private final HashMap styleAttributesValues = new LinkedHashMap(); private final Stack> localStyles = new Stack>(); private final Stack styleLevels = new Stack(); private EpubCSSCheckCSSHandler cssHandler; private Report report; public CSSStyleAttributeHandler(boolean isGlobalFixedFormat, boolean documentIsFixedFormat) { this.isGlobalFixedFormat = isGlobalFixedFormat; this.documentIsFixedFormat = documentIsFixedFormat; } public Report getReport() { return report; } public void setReport(Report report) { this.report = report; } public EpubCSSCheckCSSHandler getCssHandler() { return cssHandler; } public void setCssHandler(EpubCSSCheckCSSHandler value) { cssHandler = value; } public String getFileName() { return fileName; } public void setFileName(String fileName) { this.fileName = fileName; } public Collection getStyleAttributesValues() { return styleAttributesValues.values(); } private final Vector styleTagValues = new Vector(); public Vector getStyleTagValues() { return styleTagValues; } public void setDocumentLocator(Locator locator) { this.locator = locator; } public void startDocument() { localStyles.clear(); styleLevels.clear(); } public void endDocument() { while (!localStyles.isEmpty()) { HashMap localStyleMap = localStyles.pop(); for (String key : localStyleMap.keySet()) { EpubCSSCheckCSSHandler.ClassUsage cu = localStyleMap.get(key); if (cu.Count == 0) { assert (cu.Name != null && !cu.Name.isEmpty()); report.message(MessageId.CSS_024, EPUBLocation.create(getFileName(), cu.Location.getLineNumber(), cu.Location.getColumnNumber(), key)); } } } } public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { tagStack.push(qName.toLowerCase(Locale.ROOT)); if (qName.compareToIgnoreCase("style") == 0) { HashMap localStyleMap = new LinkedHashMap(); localStyles.push(localStyleMap); this.styleLevels.push(tagStack.size() - 1); // we are pushing the depth of the style's PARENT node here, not the depth of the STYLE node inStyleTag = true; currentStyleTag = new CSSStyleAttributeHandler.StyleAttribute(); currentStyleTag.setLine(locator.getLineNumber()); currentStyleTag.setColumn(locator.getColumnNumber()); currentStyleTag.setValue(""); } else { for (int i = 0; i < attributes.getLength(); i++) { String attrName = attributes.getQName(i); if (attrName.compareToIgnoreCase("style") == 0) { String attrValue = attributes.getValue(i); StyleAttribute sa = new StyleAttribute(); sa.setValue(attrValue); sa.setLine(locator.getLineNumber()); sa.setColumn(locator.getColumnNumber()); styleAttributesValues.put(attrValue, sa); } else if (attrName.compareToIgnoreCase("class") == 0) { String attrValue = attributes.getValue(i); if (attrValue != null && attrValue.length() > 0) { String[] attrValues = attrValue.split("\\s+"); for (String value : attrValues) { if (value.length() > 0) { String styleName = "." + value; if (!IncrementLocalCssClassCount(styleName) && !IncrementGlobalCssClassCount(styleName)) { report.message(MessageId.CSS_025, EPUBLocation.create(getFileName(), locator.getLineNumber(), locator.getColumnNumber(), styleName)); } } } } } } } } private boolean IncrementGlobalCssClassCount(String attrValue) { EpubCSSCheckCSSHandler handler = getCssHandler(); return handler != null && handler.IncrementGlobalCssClassCount(attrValue); } private boolean IncrementLocalCssClassCount(String className) { for (int i = localStyles.size() - 1; i >= 0; --i) { HashMap h = localStyles.get(i); if (h != null) { EpubCSSCheckCSSHandler.ClassUsage cu = h.get(className); if (cu != null) { ++cu.Count; return true; } } } return false; } public void endElement(String uri, String localName, String qName) throws SAXException { tagStack.pop(); if (inStyleTag && "style".compareToIgnoreCase(qName) == 0) { parseCurrentStyleTag(currentStyleTag); styleTagValues.add(currentStyleTag); inStyleTag = false; } if (styleLevels.size() > 0 && tagStack.size() < styleLevels.peek()) { HashMap localStyleMap; if (!tagStack.empty() && "head".compareToIgnoreCase(qName) != 0) { styleLevels.pop(); localStyleMap = localStyles.pop(); } else { localStyleMap = localStyles.peek(); } // don't look for unused ones when we are only closing the head tag, because they are "in scope" for the whole doc if ("head".compareToIgnoreCase(qName) != 0) { for (String key : localStyleMap.keySet()) { EpubCSSCheckCSSHandler.ClassUsage cu = localStyleMap.get(key); if (cu != null && cu.Count == 0) { EPUBLocation location = EPUBLocation.create(cu.FileName, cu.Location.getLineNumber(), cu.Location.getColumnNumber(), key); if (cu != null) { assert (cu.Name != null && !cu.Name.isEmpty()); } assert (key != null && !key.isEmpty()); report.message(MessageId.CSS_024, location); } } } } } private void parseCurrentStyleTag(StyleAttribute currentStyleTag) { EpubCSSCheckCSSHandler handler = new EpubCSSCheckCSSHandler(report, currentStyleTag.getLine(), currentStyleTag.getColumn(), isGlobalFixedFormat, documentIsFixedFormat); try { String s = currentStyleTag.getValue(); InputStream inputStream = new ByteArrayInputStream(s.getBytes("UTF-8")); CssSource source = new CssSource(this.getFileName(), inputStream); CssParser parser = new CssParser(); handler.setPath(this.getFileName()); HashMap localStyleMap = localStyles.peek(); parser.parse(source, handler, handler); HashMap map = handler.getClassMap(); for (String key : map.keySet()) { EpubCSSCheckCSSHandler.ClassUsage cu = map.get(key); int line = cu.Location.getLineNumber(); int column = cu.Location.getColumnNumber(); cu.Location = new LocationImpl(line, column, cu.Location.getCharacterOffset(), cu.FileName, cu.FileName); cu.Count = 0; cu.Name = key; localStyleMap.put(cu.Name, cu); } } catch (Exception e) { e.printStackTrace(); } } public void characters(char ch[], int start, int length) throws SAXException { if (inStyleTag) { currentStyleTag.setValue(currentStyleTag.getValue() + new String(ch, start, length)); } } public class StyleAttribute { int line; int column; String value = ""; public int getLine() { return line; } public void setLine(int line) { this.line = line; } public int getColumn() { return column; } public void setColumn(int column) { this.column = column; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ctc/xml/Epub3StructureHandler.java0000644000175000017500000000333113017276730027604 0ustar eugeneeugenepackage com.adobe.epubcheck.ctc.xml; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.util.NamespaceHelper; import org.xml.sax.Attributes; import org.xml.sax.Locator; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; public class Epub3StructureHandler extends DefaultHandler { Locator locator; String fileName; Report report; NamespaceHelper namespaceHelper = new NamespaceHelper(); final String[] HTMLEpub3SpecTags = new String[]{"audio", "nav", "video"}; int specificTagsCount = 0; public int getSpecificTagsCount() { return specificTagsCount; } @Override public void startPrefixMapping (String prefix, String uri) throws SAXException { namespaceHelper.declareNamespace(prefix, uri, EPUBLocation.create(fileName, locator.getLineNumber(), locator.getColumnNumber(), prefix), report); } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { namespaceHelper.onStartElement(fileName, locator, uri, qName, attributes, report); //outWriter.println("Start Tag -->:<" +qName+">"); for (String HTMLEpub3SpecTag : HTMLEpub3SpecTags) { if (qName.compareToIgnoreCase(HTMLEpub3SpecTag) == 0) { specificTagsCount++; } } } @Override public void setDocumentLocator(Locator locator) { this.locator = locator; } @Override public void endElement (String uri, String localName, String qName) { namespaceHelper.onEndElement(report); } public void setFileName(String fileName) { this.fileName = fileName; } public void setReport(Report report) { this.report = report; } }epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ctc/xml/ScriptElement.java0000644000175000017500000000057613017276730026175 0ustar eugeneeugenepackage com.adobe.epubcheck.ctc.xml; import java.util.HashMap; public class ScriptElement { private final HashMap attrs = new HashMap(); private boolean isExternal = false; public void addAttribute(String name, String value) { attrs.put(name, value); } public String getAttribute(String name) { return attrs.get(name); } }epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ctc/xml/HTMLTagsAnalyseHandler.java0000644000175000017500000003273413017276730027616 0ustar eugeneeugenepackage com.adobe.epubcheck.ctc.xml; import static com.adobe.epubcheck.opf.OPFChecker30.isBlessedAudioType; import static com.adobe.epubcheck.opf.OPFChecker30.isBlessedVideoType; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Locale; import java.util.Stack; import org.xml.sax.Attributes; import org.xml.sax.Locator; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.messages.MessageId; import com.adobe.epubcheck.util.EPUBVersion; import com.adobe.epubcheck.util.EpubConstants; import com.adobe.epubcheck.util.NamespaceHelper; public class HTMLTagsAnalyseHandler extends DefaultHandler { private String fileName; private Report report; private final HashSet html5SpecTags; private final HashSet html4SpecTags; private final HashSet nonTextTagsAlt; private final HashSet nonTextTagsTitle; private final HashSet headerTags; private final Stack tagStack; private int html4SpecTagsCounter = 0; private int html5SpecTagsCounter = 0; private final ArrayList listItemCounters; private HashMap formInputMarks; private Locator locator; private boolean hasTitle; private boolean inTitle; private boolean inFigure; private boolean inBlockQuote; private NamespaceHelper namespaceHelper = new NamespaceHelper(); private final int HAS_INPUT = 1; private final int HAS_LABEL = 2; private boolean hasViewport = false; private boolean isFixed = false; private int landmarkNavCount = 0; private EPUBVersion version; public int getLandmarkNavCount() { return landmarkNavCount; } public int getHtml5SpecTagsCounter() { return html5SpecTagsCounter; } public HTMLTagsAnalyseHandler() { String[] HTML5SpecTags = { "article", "aside", "audio", "bdi", "canvas", "command", "datalist", "details", "dialog", "embed", "figcaption", "figure", "footer", "header", "hgroup", "keygen", "mark", "meter", "nav", "output", "progress", "rp", "rt", "ruby", "section", "source", "summary", "time", "track", "wbr", "video" }; String[] HTML4SpecTags = { "acronym", "applet", "basefont", "big", "center", "dir", "font", "frame", "frameset", "noframes", "strike" }; String[] NonTextTagsAlt = { "img", "area", // images }; String[] NonTextTagsTitle = { "map", "figure", // images "audio", // audio "video", // video }; String[] HeaderTags = { "h1", "h2", "h3", "h4", "h5", "h6", // headers }; this.html4SpecTags = new HashSet(); Collections.addAll(html4SpecTags, HTML4SpecTags); this.html5SpecTags = new HashSet(); Collections.addAll(html5SpecTags, HTML5SpecTags); this.nonTextTagsAlt = new HashSet(); Collections.addAll(nonTextTagsAlt, NonTextTagsAlt); this.nonTextTagsTitle = new HashSet(); Collections.addAll(nonTextTagsTitle, NonTextTagsTitle); this.headerTags = new HashSet(); Collections.addAll(headerTags, HeaderTags); tagStack = new Stack(); listItemCounters = new ArrayList(); formInputMarks = new HashMap(); } String getFileName() { return fileName; } public void setFileName(String fileName) { this.fileName = fileName; } public void setVersion(EPUBVersion version) { this.version = version; } public EPUBVersion getVersion() { return version; } private class ControlMark { public String controlId; public int mark; public EPUBLocation location; } public void setDocumentLocator(Locator locator) { this.locator = locator; } public void setReport(Report report) { this.report = report; } public boolean isFixed() { return isFixed; } public void setIsFixed(boolean isFixed) { this.isFixed = isFixed; } @Override public void notationDecl (String name, String publicId, String systemId) throws SAXException { System.out.printf("%1$s : %2$s : %3$s ", name, publicId, systemId); } @Override public void unparsedEntityDecl (String name, String publicId, String systemId, String notationName) throws SAXException { System.out.printf("%1$s : %2$s : %3$s : %4$s", name, publicId, systemId, notationName); } @Override public void startPrefixMapping (String prefix, String uri) throws SAXException { namespaceHelper.declareNamespace(prefix, uri, EPUBLocation.create(fileName, locator.getLineNumber(), locator.getColumnNumber(), prefix), report); } public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { namespaceHelper.onStartElement(fileName, locator, uri, qName, attributes, report); //outWriter.println("Start Tag -->:<" +qName+">"); String tagName = qName.toLowerCase(Locale.ROOT); if (html5SpecTags.contains(tagName)) { html5SpecTagsCounter++; } if (html4SpecTags.contains(tagName)) { html4SpecTagsCounter++; } if (("source".compareTo(tagName) == 0) && ("video".compareTo(tagStack.peek()) == 0)) { String mimeType = attributes.getValue("type"); if (mimeType == null || !isBlessedVideoType(mimeType)) { if (mimeType == null) { mimeType = "null"; } report.message(MessageId.OPF_036, EPUBLocation.create(this.getFileName(), locator.getLineNumber(), locator.getColumnNumber()), mimeType); } } else if (("source".compareTo(tagName) == 0) && ("audio".compareTo(tagStack.peek()) == 0)) { String mimeType = attributes.getValue("type"); if (mimeType == null || !isBlessedAudioType(mimeType)) { if (mimeType == null) { mimeType = "null"; } report.message(MessageId.OPF_056, EPUBLocation.create(this.getFileName(), locator.getLineNumber(), locator.getColumnNumber()), mimeType); } } else if (("ul".compareTo(tagName) == 0) || ("ol".compareTo(tagName) == 0) || ("Dl".compareTo(tagName) == 0)) { listItemCounters.add(0); } else if (("li".compareTo(tagName) == 0) && (("ul".compareTo(tagStack.peek()) == 0) || ("ol".compareTo(tagStack.peek()) == 0))) { listItemCounters.set(listItemCounters.size() - 1, 1 + listItemCounters.get(listItemCounters.size() - 1)); } else if (("dh".compareTo(tagName) == 0) && ("dl".compareTo(tagStack.peek()) == 0)) { listItemCounters.set(listItemCounters.size() - 1, 1 + listItemCounters.get(listItemCounters.size() - 1)); } else if ("input".compareTo(tagName) == 0) { String id = attributes.getValue("id"); String type = attributes.getValue("type"); if (id != null) { ControlMark mark = formInputMarks.get(id); if (mark == null) { mark = new ControlMark(); mark.controlId = id; } mark.location = EPUBLocation.create(this.getFileName(), locator.getLineNumber(), locator.getColumnNumber(), id); mark.mark |= HAS_INPUT; formInputMarks.put(id, mark); } else if (type == null || "submit".compareToIgnoreCase(type) != 0) // submit buttons don't need a label { report.message(MessageId.HTM_028, EPUBLocation.create(this.fileName, locator.getLineNumber(), locator.getColumnNumber()), tagName); } } else if ("label".compareTo(tagName) == 0) { String id = attributes.getValue("for"); if (id != null) { ControlMark mark = formInputMarks.get(id); if (mark == null) { mark = new ControlMark(); mark.controlId = id; // only set the location if we are creating the entry here. This location will be overwritten // by the input control location, but if there is no input that overrides it, the label location will // be the one reported. mark.location = EPUBLocation.create(this.getFileName(), locator.getLineNumber(), locator.getColumnNumber(), id); } mark.mark |= HAS_LABEL; formInputMarks.put(id, mark); } else { report.message(MessageId.HTM_029, EPUBLocation.create(this.getFileName(), locator.getLineNumber(), locator.getColumnNumber(), tagName)); } } else if ("form".compareTo(tagName) == 0) { this.formInputMarks = new HashMap(); } else if ("html".compareTo(tagName) == 0) { String ns = attributes.getValue("xmlns"); if (ns == null || EpubConstants.HtmlNamespaceUri.compareTo(ns) != 0) { report.message(MessageId.HTM_049, EPUBLocation.create(this.getFileName(), locator.getLineNumber(), locator.getColumnNumber(), tagName)); } } else if ("body".compareTo(tagName) == 0) { String title = attributes.getValue("title"); if (title != null && title.length() > 0) { hasTitle = true; } } else if (("title".compareTo(tagName) == 0) && ("head".compareTo(tagStack.peek()) == 0)) { inTitle = true; } else if ("nav".compareTo(tagName) == 0) { String type = attributes.getValue(EpubConstants.EpubTypeNamespaceUri, "type"); if (type != null && "landmark".compareToIgnoreCase(type) == 0) { ++landmarkNavCount; } } else if ("blockquote".compareTo(tagName) == 0) { inBlockQuote = true; } else if ("figure".compareTo(tagName) == 0) { inFigure = true; } else if ("meta".compareTo(tagName) == 0) { String nameAttribute = attributes.getValue("name"); if (nameAttribute != null && "viewport".compareTo(nameAttribute) == 0) { hasViewport = true; String contentAttribute = attributes.getValue("content"); if (isFixed && (contentAttribute == null || !(contentAttribute.contains("width") && contentAttribute.contains("height")))) { report.message(MessageId.HTM_047, EPUBLocation.create(this.getFileName(), locator.getLineNumber(), locator.getColumnNumber(), tagName)); } } } if (headerTags.contains(tagName)) { if (inBlockQuote || inFigure) { report.message(MessageId.ACC_010, EPUBLocation.create(getFileName(), locator.getLineNumber(), locator.getColumnNumber(), tagName)); } } if (nonTextTagsAlt.contains(tagName)) { if (null != this.getFileName() && null == attributes.getValue("alt")) { report.message(MessageId.ACC_001, EPUBLocation.create(this.getFileName(), locator.getLineNumber(), locator.getColumnNumber(), tagName)); } } if (nonTextTagsTitle.contains(tagName)) { if (null != this.getFileName() && null == attributes.getValue("title")) { report.message(MessageId.ACC_003, EPUBLocation.create(this.getFileName(), locator.getLineNumber(), locator.getColumnNumber(), tagName)); } } String epubPrefix = namespaceHelper.findPrefixForUri(EpubConstants.EpubTypeNamespaceUri); if (epubPrefix != null) { String typeAttr = attributes.getValue(epubPrefix+":type"); if (typeAttr != null) { if (typeAttr.contains("pagebreak")) { report.message(MessageId.HTM_050, EPUBLocation.create(this.getFileName(), locator.getLineNumber(), locator.getColumnNumber(), "pagebreak")); } } } tagStack.push(tagName); } public void endElement(String uri, String localName, String qName) throws SAXException { namespaceHelper.onEndElement(report); String tagName = qName.toLowerCase(Locale.ROOT); String top = tagStack.pop(); if (top.compareTo(tagName) == 0) { if (("ul".compareTo(tagName) == 0) || ("ol".compareTo(tagName) == 0) || ("Dl".compareTo(tagName) == 0)) { Integer count = listItemCounters.remove(listItemCounters.size() - 1); if (count < 1) { report.message(MessageId.HTM_027, EPUBLocation.create(this.getFileName(), locator.getLineNumber(), locator.getColumnNumber(), qName) ); } } if ("body".compareTo(tagName) == 0) { for (String id : formInputMarks.keySet()) { ControlMark mark = formInputMarks.get(id); if (((mark.mark & HAS_LABEL) != HAS_LABEL) && (mark.mark & HAS_INPUT) == HAS_INPUT) { report.message(MessageId.ACC_002, mark.location, id); } } } if (inTitle && "title".compareTo(tagName) == 0) { inTitle = false; } else if ("head".compareTo(tagName) == 0) { if (!hasTitle) { report.message(MessageId.HTM_033, EPUBLocation.create(this.getFileName(), locator.getLineNumber(), locator.getColumnNumber())); } if (isFixed() && !hasViewport) { report.message(MessageId.HTM_046, EPUBLocation.create(this.getFileName(), locator.getLineNumber(), locator.getColumnNumber())); } } else if ("blockquote".compareTo(tagName) == 0) { inBlockQuote = false; } else if ("figure".compareTo(tagName) == 0) { inFigure = false; } } } public void characters(char ch[], int start, int length) throws SAXException { if (inTitle && (length > 0)) { hasTitle = true; } } }epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ctc/xml/AnchorTagHandler.java0000644000175000017500000001341013017276730026552 0ustar eugeneeugenepackage com.adobe.epubcheck.ctc.xml; import org.xml.sax.Attributes; import org.xml.sax.Locator; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; import java.util.HashMap; import java.util.Vector; public class AnchorTagHandler extends DefaultHandler { public static final String MATH_ML_NAMESPACE = "http://www.w3.org/1998/Math/MathML"; private Vector tagsContent = new Vector(); private DocTagContent currentScriptTag = null; private boolean scriptReading = false; private Locator locator; private HashMap prefixes = new HashMap(); public Vector getHrefAttributesValues() { return tagsContent; } public void setDocumentLocator(Locator locator) { this.locator = locator; } @Override public void endDocument() { prefixes.clear(); } public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if (qName.compareToIgnoreCase("script") == 0) { scriptReading = true; currentScriptTag = new DocTagContent(); currentScriptTag.setLine(locator.getLineNumber()); currentScriptTag.setColumn(locator.getColumnNumber()); currentScriptTag.setType("script"); currentScriptTag.setContext("script"); tagsContent.add(currentScriptTag); } if (qName.compareToIgnoreCase("html") == 0) { for (int i = 0; i < attributes.getLength(); i++) { String attrName = attributes.getQName(i); String attrValue = attributes.getValue(i); if (attrName.startsWith("xmlns:") && attrValue.compareToIgnoreCase(MATH_ML_NAMESPACE) == 0) { String prefix = attrName.substring("xmlns:".length()); startPrefixMapping (prefix, attrValue); } } } else if (qName.compareToIgnoreCase("A") == 0) { for (int i = 0; i < attributes.getLength(); i++) { String attrName = attributes.getQName(i); String attrValue = attributes.getValue(i); if (attrName.compareToIgnoreCase("href") == 0) { DocTagContent sa = new DocTagContent(); sa.setValue(attrValue); sa.setType("A"); sa.setLine(locator.getLineNumber()); sa.setColumn(locator.getColumnNumber()); sa.setContext("href"); tagsContent.add(sa); } } } else if (qName.compareToIgnoreCase("iframe") == 0) { for (int i = 0; i < attributes.getLength(); i++) { String attrName = attributes.getQName(i); String attrValue = attributes.getValue(i); if (attrName.compareToIgnoreCase("src") == 0) { DocTagContent sa = new DocTagContent(); sa.setValue(attrValue); sa.setType("iframe:src"); sa.setLine(locator.getLineNumber()); sa.setColumn(locator.getColumnNumber()); sa.setContext("src"); tagsContent.add(sa); } } } else if (qName.compareToIgnoreCase("img") == 0) { for (int i = 0; i < attributes.getLength(); i++) { String attrName = attributes.getQName(i); String attrValue = attributes.getValue(i); if (attrName.compareToIgnoreCase("src") == 0) { DocTagContent sa = new DocTagContent(); sa.setValue(attrValue); sa.setType("img"); sa.setLine(locator.getLineNumber()); sa.setColumn(locator.getColumnNumber()); sa.setContext("img"); tagsContent.add(sa); } } } else if (isMath(qName)) { int imageIndex = attributes.getIndex("altimg"); if (imageIndex >= 0) { String attrValue = attributes.getValue(imageIndex); DocTagContent sa = new DocTagContent(); sa.setValue(attrValue); sa.setType("altimg"); sa.setLine(locator.getLineNumber()); sa.setColumn(locator.getColumnNumber()); sa.setContext("altimg"); tagsContent.add(sa); } } } private boolean isMath(String qName) { return prefixes.containsKey(qName); } public void startPrefixMapping (String prefix, String uri) throws SAXException { if (uri.compareToIgnoreCase(MATH_ML_NAMESPACE) == 0) { prefix = prefix + ":math"; Integer count = prefixes.get(prefix); if (count == null) { count = 0; } prefixes.put(prefix, ++count); } } public void endPrefixMapping (String prefix) throws SAXException { prefix = prefix + ":math"; Integer count = prefixes.get(prefix); if (count != null) { prefixes.put(prefix, --count); } } public void characters(char ch[], int start, int length) throws SAXException { if (scriptReading) { currentScriptTag.value = new String(ch, start, length); tagsContent.add(currentScriptTag); scriptReading = false; } } public class DocTagContent { String type; int line; int column; String context = ""; String value = ""; public int getLine() { return line; } public void setLine(int line) { this.line = line; } public int getColumn() { return column; } public void setColumn(int column) { this.column = column; } public String getType() { return type; } public void setType(String type) { this.type = type; } public void setContext(String context) { this.context = context; } public String getContext() { return context; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ctc/xml/ScriptTagHandler.java0000644000175000017500000001642713017276730026617 0ustar eugeneeugenepackage com.adobe.epubcheck.ctc.xml; import java.util.HashSet; import java.util.Locale; import java.util.Vector; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.xml.sax.Attributes; import org.xml.sax.Locator; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.messages.MessageId; import com.adobe.epubcheck.ops.OPSHandler30; import com.adobe.epubcheck.util.EPUBVersion; import com.adobe.epubcheck.util.FeatureEnum; public class ScriptTagHandler extends DefaultHandler { private Locator locator; private String fileName; private int inlineScriptCount = 0; private boolean inScript = false; private EPUBVersion version = EPUBVersion.Unknown; private final Report report; public static final Pattern xmlHttpRequestPattern = Pattern.compile("new[\\s]*XMLHttpRequest[\\s]*\\("); public static final Pattern microsoftXmlHttpRequestPattern = Pattern.compile("Microsoft.XMLHTTP"); public static final Pattern evalPattern = Pattern.compile("((^eval[\\s]*\\()|([^a-zA-Z0-9]eval[\\s]*\\()|([\\s]+eval[\\s]*\\())"); public static final Pattern localStoragePattern = Pattern.compile("localStorage\\."); public static final Pattern sessionStoragePattern = Pattern.compile("sessionStorage\\."); public void setFileName(String fileName) { this.fileName = fileName; } public ScriptTagHandler(Report report) { this.report = report; } public void setDocumentLocator(Locator locator) { this.locator = locator; } public void setVersion(EPUBVersion version) { this.version = version; } private final Vector scriptElements = new Vector(); public int getScriptElementCount() { return scriptElements.size(); } public Vector getScriptElements() { return scriptElements; } public int getInlineScriptCount() { return inlineScriptCount; } public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if (qName.compareToIgnoreCase("SCRIPT") == 0) { inScript = true; if (this.version == EPUBVersion.VERSION_2) { report.message(MessageId.SCP_004, EPUBLocation.create(fileName, locator.getLineNumber(), locator.getColumnNumber(), qName)); } ScriptElement scriptElement = new ScriptElement(); boolean isExternal = false; for (int i = 0; i < attributes.getLength(); i++) { String attrName = attributes.getQName(i); String attrValue = attributes.getValue(i); if (attrName.equalsIgnoreCase("src")) { isExternal = true; } scriptElement.addAttribute(attrName, attrValue); } if (isExternal) { report.info(this.fileName, FeatureEnum.SCRIPT, "external"); } else { report.info(this.fileName, FeatureEnum.SCRIPT, "tag"); } scriptElements.add(scriptElement); } else { HashSet scriptEvents = OPSHandler30.getScriptEvents(); HashSet mouseEvents = OPSHandler30.getMouseEvents(); for (int i = 0; i < attributes.getLength(); i++) { String attrName = attributes.getLocalName(i).toLowerCase(Locale.ROOT); if (scriptEvents.contains(attrName)) { this.inlineScriptCount++; if (this.version == EPUBVersion.VERSION_2) { report.message(MessageId.SCP_004, EPUBLocation.create(fileName, locator.getLineNumber(), locator.getColumnNumber(), attrName)); } report.message(MessageId.SCP_006, EPUBLocation.create(this.fileName, locator.getLineNumber(), locator.getColumnNumber(), attrName)); String attrValue = attributes.getValue(i); CheckForInner(attrValue); } if (mouseEvents.contains(attrName)) { if (this.version == EPUBVersion.VERSION_2) { report.message(MessageId.SCP_004, EPUBLocation.create(fileName, locator.getLineNumber(), locator.getColumnNumber(), attrName)); } report.message(MessageId.SCP_009, EPUBLocation.create(this.fileName, locator.getLineNumber(), locator.getColumnNumber(), attrName)); } } } } public void endElement(String uri, String localName, String qName) throws SAXException { //outWriter.println("End Tag -->:"); if (qName.compareToIgnoreCase("SCRIPT") == 0) { inScript = false; } } public void characters(char ch[], int start, int length) throws SAXException { //outWriter.println("-----Tag value----------->"+new String(ch, start, length)); if (inScript) { String script = new String(ch, start, length); CheckForInner(script); } } public void CheckForInner(String script) { String lower = script.toLowerCase(Locale.ROOT); int column = lower.indexOf("innerhtml"); if (column >= 0) { report.message(MessageId.SCP_007, EPUBLocation.create(fileName, locator.getLineNumber(), locator.getColumnNumber(), trimContext(script, column))); } column = lower.indexOf("innertext"); if (column >= 0) { report.message(MessageId.SCP_008, EPUBLocation.create(fileName, locator.getLineNumber(), locator.getColumnNumber(), trimContext(script, column))); } // the exact pattern is very complex and it slows down all script checking. // what we can do here is use a blunt check (for the word "eval"). if it is not found, keep moving. // If it is found, look closely using the exact pattern to see if the line truly matches the exact eval() function and report that. Matcher m = null; if (script.contains("eval")) { m = evalPattern.matcher(script); if (m.find()) { report.message(MessageId.SCP_001, EPUBLocation.create(fileName, locator.getLineNumber(), locator.getColumnNumber(), trimContext(script, m.start()))); } } m = localStoragePattern.matcher(script); if (m.find()) { report.message(MessageId.SCP_003, EPUBLocation.create(fileName, locator.getLineNumber(), locator.getColumnNumber(), trimContext(script, m.start()))); } m = sessionStoragePattern.matcher(script); if (m.find()) { report.message(MessageId.SCP_003, EPUBLocation.create(fileName, locator.getLineNumber(), locator.getColumnNumber(), trimContext(script, m.start()))); } m = xmlHttpRequestPattern.matcher(script); if (m.find()) { report.message(MessageId.SCP_002, EPUBLocation.create(fileName, locator.getLineNumber(), locator.getColumnNumber(), trimContext(script, m.start()))); } m = microsoftXmlHttpRequestPattern.matcher(script); if (m.find()) { report.message(MessageId.SCP_002, EPUBLocation.create(fileName, locator.getLineNumber(), locator.getColumnNumber(), trimContext(script, m.start()))); } } static public String trimContext(String context, int start) { String trimmed = context.substring(start).trim(); int end = trimmed.indexOf("\n"); if (end < 0 && trimmed.length() < 60) { return trimmed; } else { int newEnd = Math.min(60, (end > 0 ? end : trimmed.length())); return trimmed.substring(0, newEnd); } } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ctc/xml/LangAttributeHandler.java0000644000175000017500000000256713017276730027464 0ustar eugeneeugenepackage com.adobe.epubcheck.ctc.xml; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; public class LangAttributeHandler extends DefaultHandler { private String xmlLangAttr = null; private String langAttr = null; public String getXmlLangAttr() { return xmlLangAttr; } public String getLangAttr() { return langAttr; } public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { //outWriter.println("Start Tag -->:<" +qName+">"); if (qName.compareToIgnoreCase("HTML") == 0) { for (int i = 0; i < attributes.getLength(); i++) { String attrName = attributes.getQName(i); String attrValue = attributes.getValue(i); if (attrName.compareToIgnoreCase("xml:lang") == 0) { xmlLangAttr = attrValue; } if (attrName.compareToIgnoreCase("lang") == 0) { langAttr = attrValue; } } } } public void endElement(String uri, String localName, String qName) throws SAXException { //outWriter.println("End Tag -->:"); } public void characters(char ch[], int start, int length) throws SAXException { //outWriter.println("-----Tag value----------->"+new String(ch, start, length)); } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ctc/EpubNCXCheck.java0000644000175000017500000001566613017276730025027 0ustar eugeneeugenepackage com.adobe.epubcheck.ctc; import java.util.HashSet; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.ctc.epubpackage.EpubPackage; import com.adobe.epubcheck.ctc.epubpackage.ManifestItem; import com.adobe.epubcheck.ctc.epubpackage.PackageManifest; import com.adobe.epubcheck.ctc.epubpackage.PackageSpine; import com.adobe.epubcheck.ctc.epubpackage.SpineItem; import com.adobe.epubcheck.messages.MessageId; import com.adobe.epubcheck.opf.DocumentValidator; import com.adobe.epubcheck.reporting.CheckingReport; import com.adobe.epubcheck.util.EPUBVersion; import com.adobe.epubcheck.util.EpubConstants; import com.adobe.epubcheck.util.FeatureEnum; import com.adobe.epubcheck.util.PathUtil; public class EpubNCXCheck implements DocumentValidator { private final XmlDocParser docParser; private final Document doc; private final String pathRootFile; private final Report report; private final EpubPackage epack; private String ncxDoc; public EpubNCXCheck(EpubPackage epack, Report report) { this.doc = epack.getPackDoc(); this.report = report; this.pathRootFile = epack.getPackageMainFile(); this.epack = epack; docParser = new XmlDocParser(epack.getZip(), report); } @Override public boolean validate() { boolean result = isNCXDefined(doc); if (result) { String fileToParse = epack.getManifestItemFileName(ncxDoc); checkNcxDoc(fileToParse); } if (!result && epack.getVersion() != EPUBVersion.VERSION_2) { if (report.getClass() == CheckingReport.class) { report.message(MessageId.NCX_003, EPUBLocation.create(pathRootFile)); } else { report.info(pathRootFile, FeatureEnum.HAS_NCX, "false"); } } return result; } private boolean isNCXDefined(Document doc) { boolean isNCXdefined = false; NodeList spineList = doc.getElementsByTagName("spine"); if (spineList.getLength() > 0) { for (int i = 0; i < spineList.getLength(); i++) { NamedNodeMap attrs = spineList.item(i).getAttributes(); Node n = attrs.getNamedItem("toc"); if (n != null) { String tocID = n.getNodeValue(); NodeList manifestList = doc.getElementsByTagName("manifest"); for (int m = 0; m < manifestList.getLength(); m++) { Node manifestNode = manifestList.item(m); NodeList itemNodes = manifestNode.getChildNodes(); for (int it = 0; it < itemNodes.getLength(); it++) { NamedNodeMap itemNodeAttributes = itemNodes.item(it).getAttributes(); if (itemNodeAttributes != null) { String manifestNodeID = itemNodeAttributes.getNamedItem("id").getNodeValue(); if (manifestNodeID != null && manifestNodeID.compareToIgnoreCase(tocID) == 0 && itemNodeAttributes.getNamedItem("href").getNodeValue() != null) { isNCXdefined = true; this.ncxDoc = itemNodeAttributes.getNamedItem("href").getNodeValue(); } } } } } } } return isNCXdefined; } private void checkNcxDoc(String navDocEntry) { Document doc = docParser.parseDocument(navDocEntry); if (doc != null) { HashSet tocLinkSet = new HashSet(); String ncxNS = "http://www.daisy.org/z3986/2005/ncx/"; NodeList n = doc.getElementsByTagNameNS(ncxNS, "navPoint"); for (int i = 0; i < n.getLength(); i++) { Element navElement = (Element) n.item(i); String playOrder = navElement.getAttributeNS(ncxNS, "playOrder"); NodeList contentNodes = navElement.getElementsByTagNameNS(ncxNS, "content"); if (contentNodes.getLength() > 0) { Element content = (Element) contentNodes.item(0); String path = content.getAttributeNS(ncxNS, "src"); int hash = path.indexOf("#"); if (hash >= 0) { path = path.substring(0, hash); } try { path = PathUtil.resolveRelativeReference(navDocEntry, path, null); } catch (IllegalArgumentException ex) { // safe to ignore, was already reported as RSC_005 in NCXHandler } if (!path.equals("")) { tocLinkSet.add(path); playOrder = playOrder != null ? playOrder.trim() : playOrder; if (validateInt(playOrder)) { report.info(path, FeatureEnum.NAVIGATION_ORDER, playOrder); } } } } n = doc.getElementsByTagNameNS(ncxNS, "pageList"); if (n.getLength() > 0) { Element pageList = (Element) n.item(0); report.message(MessageId.NCX_005, EPUBLocation.create(navDocEntry, getElementLineNumber(pageList), getElementColumnNumber(pageList), pageList.getTagName())); } PackageManifest manifest = epack.getManifest(); PackageSpine spine = epack.getSpine(); if (spine != null) { String tocFileName = spine.getToc(); for (int i = 0; i < spine.itemsLength(); ++i) { SpineItem si = spine.getItem(i); ManifestItem mi = manifest.getItem(si.getIdref()); if (mi != null) { String path = mi.getHref(); path = PathUtil.resolveRelativeReference(navDocEntry, path, null); if (path != null && !path.equals(tocFileName) && !path.equals(navDocEntry) && !tocLinkSet.contains(path)) { report.message(MessageId.OPF_059, EPUBLocation.create(navDocEntry, path)); } } else { // id not found in manifest report.message(MessageId.OPF_049, EPUBLocation.create(navDocEntry, epack.getPackageMainPath()), si.getIdref()); } } } } } private boolean validateInt(String number) { if (number == null || number.length() == 0) { return false; } try { Integer.parseInt(number); return true; } catch (NumberFormatException ex) { return false; } } public static int getElementLineNumber(Element e) { return getElementIntAttribute( e, EpubConstants.ElementLineNumberAttribute); } public static int getElementColumnNumber(Element e) { return getElementIntAttribute( e, EpubConstants.ElementColumnNumberAttribute); } static int getElementIntAttribute(Element e, String whichAttribute) { int val = -1; String number = e.getAttribute(whichAttribute); if (number != null) { try { val = Integer.parseInt(number.trim()); } catch (NumberFormatException ex) { val = -1; } } return val; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ctc/EntitySearch.java0000644000175000017500000001706313017276730025220 0ustar eugeneeugenepackage com.adobe.epubcheck.ctc; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.util.Collections; import java.util.HashSet; import java.util.Hashtable; import java.util.Scanner; import java.util.Vector; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.messages.MessageId; import com.adobe.epubcheck.ocf.EncryptionFilter; import com.adobe.epubcheck.util.EPUBVersion; class EntitySearch { private final ZipFile zip; private final Hashtable enc; private final Report report; private final EPUBVersion version; static final Pattern entityPattern = Pattern.compile("&([A-Za-z0-9]+)([;|\\s])"); static final HashSet legalEntities2_0; static final HashSet legalEntities3_0; MessageId ENTITY_INVALID = MessageId.HTM_023; MessageId ENTITY_OK = MessageId.HTM_006; MessageId ENTITY_IMPROPER = MessageId.HTM_024; static { legalEntities3_0 = new HashSet(); Collections.addAll(legalEntities3_0, "&", "'", """, "<", ">"); legalEntities2_0 = new HashSet(); Collections.addAll(legalEntities2_0, " ", "¡", "¢", "£", "¤", "¥", "¦", "§", "¨", "©", "ª", "«", "¬", "­", "®", "¯", "°", "±", "²", "³", "´", "µ", "¶", "·", "¸", "¹", "º", "»", "¼", "½", "¾", "¿", "À", "Á", "Â", "Ã", "Ä", "Å", "Æ", "Ç", "È", "É", "Ê", "Ë", "Ì", "Í", "Î", "Ï", "Ð", "Ñ", "Ò", "Ó", "Ô", "Õ", "Ö", "×", "Ø", "Ù", "Ú", "Û", "Ü", "Ý", "Þ", "ß", "à", "á", "â", "ã", "ä", "å", "æ", "ç", "è", "é", "ê", "ë", "ì", "í", "î", "ï", "ð", "ñ", "ò", "ó", "ô", "õ", "ö", "÷", "ø", "ù", "ú", "û", "ü", "ý", "þ", "ÿ", "Œ", "œ", "Š", "š", "Ÿ", "ƒ", "ˆ", "˜", "Α", "Β", "Γ", "Δ", "Ε", "Ζ", "Η", "Θ", "Ι", "Κ", "Λ", "Μ", "Ν", "Ξ", "Ο", "Π", "Ρ", "Σ", "Τ", "Υ", "Φ", "Χ", "Ψ", "Ω", "α", "β", "γ", "δ", "ε", "ζ", "η", "θ", "ι", "κ", "λ", "μ", "ν", "ξ", "ο", "π", "ρ", "ς", "σ", "τ", "υ", "φ", "χ", "ψ", "ω", "ϑ", "ϒ", "ϖ", " ", " ", " ", "‌", "‍", "‎", "‏", "–", "—", "‘", "’", "‚", "“", "”", "„", "†", "‡", "•", "…", "‰", "′", "″", "‹", "›", "‾", "⁄", "€", "ℑ", "℘", "ℜ", "™", "ℵ", "←", "↑", "→", "↓", "↔", "↵", "⇐", "⇑", "⇒", "⇓", "⇔", "∀", "∂", "∃", "∅", "∇", "∈", "∉", "∋", "∏", "∑", "−", "∗", "√", "∝", "∞", "∠", "∧", "∨", "∩", "∪", "∫", "∴", "∼", "≅", "≈", "≠", "≡", "≤", "≥", "⊂", "⊃", "⊄", "⊆", "⊇", "⊕", "⊗", "⊥", "⋅", "⋮", "⌈", "⌉", "⌊", "⌋", "⟨", "⟩", "◊", "♠", "♣", "♥", "♦"); } public EntitySearch(EPUBVersion version, ZipFile zip, Report report) { this.zip = zip; this.enc = new Hashtable(); this.report = report; this.version = version; } InputStream getInputStream(String name) throws IOException { ZipEntry entry = zip.getEntry(name); if (entry == null) { return null; } InputStream in = zip.getInputStream(entry); EncryptionFilter filter = enc.get(name); if (filter == null) { return in; } if (filter.canDecrypt()) { return filter.decrypt(in); } return null; } public Vector Search(String entry) { Vector result = new Vector(); InputStream is = null; Scanner in = null; try { is = getInputStream(entry); in = new Scanner(is); int lineCounter = 1; while (in.hasNextLine()) { String line = in.nextLine(); Matcher matcher = entityPattern.matcher(line); int position = 0; while (matcher.find(position)) { MessageId messageCode = ENTITY_INVALID; position = matcher.end(); String matchedText = line.substring(matcher.start(), matcher.end()); if (version == EPUBVersion.VERSION_2) { if (legalEntities3_0.contains(matchedText) || legalEntities2_0.contains(matchedText)) { // its in either the legal 2.0 list or the 3.0 list. Simply emit a usage message messageCode = ENTITY_OK; } } else if (version == EPUBVersion.VERSION_3) { if (legalEntities3_0.contains(matchedText)) { // its in the 3.0 list. just emit a usage message messageCode = ENTITY_OK; } else if (legalEntities2_0.contains(matchedText)) { // its in the 2.0 list. Emit a usage message saying that only & ' etc. are allowed messageCode = ENTITY_IMPROPER; } } int contextStart = Math.max(0, matcher.start() - 20); int contextEnd = Math.min(contextStart + 40, line.length() - 1); String context = line.substring(contextStart, contextEnd); if (messageCode == ENTITY_INVALID) { // emit the erroneous text along with the message report.message(messageCode, EPUBLocation.create(entry, lineCounter, matcher.start(), context.trim()), matchedText); } else { report.message(messageCode, EPUBLocation.create(entry, lineCounter, matcher.start(), context.trim())); } } lineCounter++; } } catch (FileNotFoundException e1) { String fileName = new File(zip.getName()).getName(); report.message(MessageId.RSC_001, EPUBLocation.create(fileName), entry); } catch (IOException e1) { String fileName = new File(zip.getName()).getName(); report.message(MessageId.PKG_008, EPUBLocation.create(fileName), entry); } catch (Exception e) { e.printStackTrace(); report.message(MessageId.RSC_005, EPUBLocation.create(entry), e.getMessage()); } finally { if (is != null) { try { is.close(); } catch (Exception ignored) { } } if (in != null) { in.close(); } } return result; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ctc/EpubExtLinksCheck.java0000644000175000017500000001020713017276730026122 0ustar eugeneeugenepackage com.adobe.epubcheck.ctc; import java.util.Vector; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.zip.ZipEntry; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.ctc.epubpackage.EpubPackage; import com.adobe.epubcheck.ctc.epubpackage.ManifestItem; import com.adobe.epubcheck.ctc.xml.AnchorTagHandler; import com.adobe.epubcheck.ctc.xml.XMLContentDocParser; import com.adobe.epubcheck.messages.MessageId; import com.adobe.epubcheck.opf.DocumentValidator; import com.adobe.epubcheck.util.PathUtil; import com.adobe.epubcheck.util.SearchDictionary; import com.adobe.epubcheck.util.SearchDictionary.DictionaryType; import com.adobe.epubcheck.util.TextSearchDictionaryEntry; public class EpubExtLinksCheck implements DocumentValidator { private final Report report; private final EpubPackage epack; public EpubExtLinksCheck(EpubPackage epack, Report report) { this.epack = epack; this.report = report; } public boolean validate() { SearchDictionary tsd = new SearchDictionary(DictionaryType.LINK_VALUES); SearchDictionary validTypes = new SearchDictionary(DictionaryType.VALID_TEXT_MEDIA_TYPES); for (int i = 0; i < epack.getManifest().itemsLength(); i++) { ManifestItem itemEntry = epack.getManifest().getItem(i); if (validTypes.isValidMediaType(itemEntry.getMediaType())) { String fileToParse = epack.getManifestItemFileName(itemEntry); XMLContentDocParser parser; parser = new XMLContentDocParser(epack.getZip(), report); AnchorTagHandler h = new AnchorTagHandler(); ZipEntry entry = epack.getZip().getEntry(fileToParse); if (entry == null) { // already reported in core checkers // report.message(MessageId.RSC_001, EPUBLocation.create(epack.getFileName()), fileToParse); continue; } parser.parseDoc(fileToParse, h); Vector v = h.getHrefAttributesValues(); for (int e = 0; e < v.size(); e++) { AnchorTagHandler.DocTagContent value = v.elementAt(e); searchInsideValue(value, tsd, fileToParse); String type = value.getType(); if ("img".compareToIgnoreCase(type) == 0 || "altimg".compareToIgnoreCase(type) == 0) { // ensure that this image is in the manifest String imageFile = value.getValue(); if (imageFile.matches("^[^:/?#]+:.*")) { // Already reported in OPFHandler // report.message(MessageId.RSC_006, new EPUBLocation(fileToParse, value.getLine(), value.getColumn(), value.getContext()), value.getValue()); continue; } imageFile = PathUtil.resolveRelativeReference(fileToParse, imageFile, null); int index = imageFile.lastIndexOf("#"); if (index > 0) { imageFile = imageFile.substring(0, index); } ZipEntry imgentry = epack.getZip().getEntry(imageFile); if (imgentry == null && "altimg".equalsIgnoreCase(type)) { // missing "img" already reported in XRefChecker // MessageId id = "img".compareToIgnoreCase(type) == 0 ? MessageId.RSC_001 : MessageId.RSC_018; report.message(MessageId.RSC_018, EPUBLocation.create(fileToParse, value.getLine(), value.getColumn(), value.getContext()), value.getValue()); } } } } } return true; } private void searchInsideValue(AnchorTagHandler.DocTagContent entry, SearchDictionary tds, String file) { for (int s = 0; s < tds.getDictEntries().size(); s++) { TextSearchDictionaryEntry de = tds.getDictEntries().get(s); MessageId messageCode = de.getErrorCode(); Pattern p = de.getPattern(); Matcher matcher = p.matcher(entry.getValue()); int position = 0; while (matcher.find(position)) { position = matcher.end(); report.message(messageCode, EPUBLocation.create(file, entry.getLine(), entry.getColumn(), entry.getValue())); } } } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ctc/PackageReader.java0000644000175000017500000002320413017276730025266 0ustar eugeneeugenepackage com.adobe.epubcheck.ctc; import java.util.Vector; import java.util.zip.ZipFile; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.ctc.epubpackage.EpubPackage; import com.adobe.epubcheck.ctc.epubpackage.ManifestItem; import com.adobe.epubcheck.ctc.epubpackage.MetadataElement; import com.adobe.epubcheck.ctc.epubpackage.PackageManifest; import com.adobe.epubcheck.ctc.epubpackage.PackageSpine; import com.adobe.epubcheck.ctc.epubpackage.SpineItem; import com.adobe.epubcheck.util.EPUBVersion; import com.adobe.epubcheck.util.EpubConstants; class PackageReader { private static final String containerEntry = "META-INF/container.xml"; private ZipFile zip; private Report report; private String version; private EpubPackage epack; private String mainPackageFile; public PackageReader(ZipFile zip, Report report) { this.zip = zip; this.report = report; } public EpubPackage readPackageData() { Vector pathToRootFile = getPathToRootFile(); XmlDocParser p = new XmlDocParser(zip, report); for (String path : pathToRootFile) { setMainPackageFile(path); Document doc = p.parseDocument(path); if (doc != null) { epack = new EpubPackage(path, zip, doc); epack.setPackageMainFile(getMainPackageFile()); epack.setVersion(getEpubVersion(doc)); getMetadata(doc, epack); getManifest(doc, epack); getSpine(doc, epack); } } return epack; } String getMainPackageFile() { return mainPackageFile; } void setMainPackageFile(String mainPackageFile) { this.mainPackageFile = mainPackageFile; } private Vector getPathToRootFile() { Vector rootFiles = new Vector(); XmlDocParser p = new XmlDocParser(zip, report); Document doc = p.parseDocument(containerEntry); if (doc != null) { NodeList nList = doc.getElementsByTagName("rootfiles"); for (int i = 0; i < nList.getLength(); i++) { Node n = nList.item(i); if (n.getNodeName().compareToIgnoreCase("rootfiles") == 0) { NodeList cn = n.getChildNodes(); for (int j = 0; j < cn.getLength(); j++) { Node currentNode = cn.item(j); if (currentNode.getNodeName().compareToIgnoreCase("rootfile") == 0) { NamedNodeMap attr = currentNode.getAttributes(); Node path = attr.getNamedItem("full-path"); if (path != null && !path.getNodeValue().isEmpty()) { String nodeValue = path.getNodeValue(); rootFiles.add(nodeValue); } } } } } } return rootFiles; } private void getMetadata(Document doc, EpubPackage epack) { NodeList nList = doc.getElementsByTagNameNS(EpubConstants.OpfNamespaceUri, "metadata"); if (nList.getLength() > 0) { Node metadata = nList.item(0); NodeList metaNodes = metadata.getChildNodes(); for (int i = 0; i < metaNodes.getLength(); i++) { String nodeName = metaNodes.item(i).getLocalName(); if (nodeName != null && !nodeName.startsWith("#")) { MetadataElement meta = new MetadataElement(); Node n = metaNodes.item(i); meta.setName(n.getNodeName()); if (n.hasChildNodes()) { //outWriter.println("Dodaje element o nazwie "+metaNodes.item(i).getNodeName()+" z wartoscia "+n.getFirstChild().getNodeValue()); meta.setValue(n.getFirstChild().getNodeValue()); } else { //outWriter.println("Dodaje element o nazwie "+metaNodes.item(i).getNodeName()+" z wartoscia "+n.getNodeValue()); meta.setValue(n.getNodeValue()); } NamedNodeMap attrs = metaNodes.item(i).getAttributes(); for (int a = 0; a < attrs.getLength(); a++) { //outWriter.println(" Dodaje attrybut "+attrs.item(a).getNodeName()+" z wartoscia "+attrs.item(a).getNodeValue()); if (attrs.item(a).getNodeName().compareToIgnoreCase("elementLineNumber") != 0 && attrs.item(a).getNodeName().compareToIgnoreCase("elementColumnNumber") != 0) { meta.addAttribute(attrs.item(a).getNodeName(), attrs.item(a).getNodeValue()); } } epack.getMetadata().addMetaElement(meta); } } } } private void getManifest(Document doc, EpubPackage epack) { NodeList nList = doc.getElementsByTagNameNS(EpubConstants.OpfNamespaceUri, "manifest"); for (int i = 0; i < nList.getLength(); i++) { Node n = nList.item(i); String ln = n.getLocalName(); if (ln.compareToIgnoreCase("manifest") == 0) { PackageManifest manifest = new PackageManifest(); epack.setManifest(manifest); NodeList cn = n.getChildNodes(); for (int j = 0; j < cn.getLength(); j++) { Node currentNode = cn.item(j); String childName = currentNode.getLocalName(); if (childName != null && childName.compareToIgnoreCase("item") == 0) { ManifestItem item = new ManifestItem(); NamedNodeMap attr = currentNode.getAttributes(); Node hrefNode = attr.getNamedItem("href"); String hrefValue; if (hrefNode != null) { hrefValue = hrefNode.getNodeValue(); item.setHref(hrefValue); } Node mediaTypeNode = attr.getNamedItem("media-type"); String mediaTypeValue; if (mediaTypeNode != null) { mediaTypeValue = mediaTypeNode.getNodeValue(); item.setMediaType(mediaTypeValue); } Node propertiesNode = attr.getNamedItem("properties"); String propertiesValue; if (propertiesNode != null) { propertiesValue = propertiesNode.getNodeValue(); item.setProperties(propertiesValue); } Node idNode = attr.getNamedItem("id"); String idValue; if (idNode != null) { idValue = idNode.getNodeValue(); item.setId(idValue); } manifest.addItem(item); } } } } } private void getSpine(Document doc, EpubPackage epack) { NodeList nList = doc.getElementsByTagNameNS(EpubConstants.OpfNamespaceUri, "spine"); for (int i = 0; i < nList.getLength(); i++) { Node n = nList.item(i); String ln = n.getLocalName(); if (ln.compareToIgnoreCase("spine") == 0) { PackageSpine spine = new PackageSpine(); epack.setSpine(spine); NamedNodeMap spineAttrs = n.getAttributes(); Node idNode = spineAttrs.getNamedItem("id"); if (idNode != null) { spine.setId(idNode.getNodeValue()); } Node tocNode = spineAttrs.getNamedItem("toc"); if (tocNode != null) { spine.setToc(tocNode.getNodeValue()); } Node pageProgressionDirectionNode = spineAttrs.getNamedItem("page-progression-direction"); if (pageProgressionDirectionNode != null) { spine.setPageProgressionDirection(pageProgressionDirectionNode.getNodeValue()); } NodeList cn = n.getChildNodes(); for (int j = 0; j < cn.getLength(); j++) { Node currentNode = cn.item(j); String itemRefName = currentNode.getLocalName(); if (itemRefName != null && "itemref".compareToIgnoreCase(itemRefName) == 0) { SpineItem item = new SpineItem(); NamedNodeMap attr = currentNode.getAttributes(); Node idrefNode = attr.getNamedItem("idref"); if (idrefNode != null) { String idRef = idrefNode.getNodeValue(); if (idRef != null && idRef.length() > 0) { item.setIdref(idrefNode.getNodeValue()); } else { continue; } } Node idSpineNode = attr.getNamedItem("id"); if (idSpineNode != null) { item.setId(idSpineNode.getNodeValue()); } Node linearNode = attr.getNamedItem("linear"); if (linearNode != null) { item.setLinear(linearNode.getNodeValue()); } Node propertiesNode = attr.getNamedItem("properties"); if (propertiesNode != null) { item.setProperties(propertiesNode.getNodeValue()); } spine.addItem(item); } } } } } private EPUBVersion getEpubVersion(Document doc) { NodeList packageNode = doc.getElementsByTagNameNS(EpubConstants.OpfNamespaceUri, "package"); if (packageNode == null) { return EPUBVersion.Unknown; } Node firstItem = packageNode.item(0); if (firstItem == null) { return EPUBVersion.Unknown; } NamedNodeMap packageNodeAttr = firstItem.getAttributes(); if (packageNodeAttr == null) { return EPUBVersion.Unknown; } Node node = packageNodeAttr.getNamedItem("version"); if (node != null) { version = node.getNodeValue(); } if (version != null && version.startsWith("3")) { return EPUBVersion.VERSION_3; } else if (version != null && version.startsWith("2")) { return EPUBVersion.VERSION_2; } return EPUBVersion.Unknown; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ctc/EpubCheckContentFactory.java0000644000175000017500000000474413017276730027334 0ustar eugeneeugenepackage com.adobe.epubcheck.ctc; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.ctc.epubpackage.EpubPackage; import com.adobe.epubcheck.opf.DocumentValidator; public class EpubCheckContentFactory implements ContentValidator { static private final EpubCheckContentFactory instance = new EpubCheckContentFactory(); static public EpubCheckContentFactory getInstance() { return instance; } @Override public DocumentValidator newInstance(Report report, ValidationType vt, EpubPackage epack) { if (vt.equals(ValidationType.METADATA_V3)) { return new EpubMetaDataV3Check(epack, report); } if (vt.equals(ValidationType.METADATA_V2)) { return new EpubMetaDataV2Check(epack, report); } if (vt.equals(ValidationType.TEXT)) { return new EpubTextContentCheck(report, epack); } else if (vt.equals(ValidationType.NAV)) { return new EpubNavCheck(epack, report); } else if (vt.equals(ValidationType.NCX)) { return new EpubNCXCheck(epack, report); } else if (vt.equals(ValidationType.SPINE)) { return new EpubSpineCheck(epack, report); } else if (vt.equals(ValidationType.SCRIPT)) { return new EpubScriptCheck(epack, report); } else if (vt.equals(ValidationType.SPAN)) { return new EpubSpanCheck(epack, report); } else if (vt.equals(ValidationType.LANG)) { return new EpubLangCheck(epack, report); } else if (vt.equals(ValidationType.CSS_SEARCH)) { return new EpubCSSCheck(epack, report); } else if (vt.equals(ValidationType.LINK)) { return new EpubExtLinksCheck(epack, report); } else if (vt.equals(ValidationType.RENDITION)) { return new EpubRenditionCheck(epack, report); } else if (vt.equals(ValidationType.CFI)) { return new EpubCfiCheck(epack, report); } else if (vt.equals(ValidationType.HTML_STRUCTURE)) { return new EpubHTML5StructureCheck(epack, report); } else if (vt.equals(ValidationType.MULTIPLE_CSS)) { return new EpubStyleSheetsCheck(epack, report); } else if (vt.equals(ValidationType.EPUB3_STRUCTURE)) { return new Epub3StructureCheck(epack, report); } else if (vt.equals(ValidationType.TOC)) { return new EpubTocCheck(epack, report); } else if (vt.equals(ValidationType.SVG)) { return new EpubSVGCheck(epack, report); } else { return null; } } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ctc/ContentValidator.java0000644000175000017500000000102113017276730026061 0ustar eugeneeugenepackage com.adobe.epubcheck.ctc; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.ctc.epubpackage.EpubPackage; import com.adobe.epubcheck.opf.DocumentValidator; public interface ContentValidator { public enum ValidationType { TEXT, CONTENT, SPINE, NCX, NAV, SCRIPT, SPAN, STYLE, METADATA_V3, METADATA_V2, LANG, CSS_SEARCH, LINK, RENDITION, CFI, HTML_STRUCTURE, MULTIPLE_CSS, EPUB3_STRUCTURE, TOC, SVG } public DocumentValidator newInstance(Report report, ValidationType vt, EpubPackage epack); } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ctc/EpubLangCheck.java0000644000175000017500000002005113017276730025240 0ustar eugeneeugenepackage com.adobe.epubcheck.ctc; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.ctc.epubpackage.EpubPackage; import com.adobe.epubcheck.ctc.epubpackage.ManifestItem; import com.adobe.epubcheck.ctc.xml.LangAttributeHandler; import com.adobe.epubcheck.ctc.xml.XMLContentDocParser; import com.adobe.epubcheck.messages.MessageId; import com.adobe.epubcheck.opf.DocumentValidator; import com.adobe.epubcheck.util.SearchDictionary; import com.adobe.epubcheck.util.SearchDictionary.DictionaryType; public class EpubLangCheck implements DocumentValidator { private final ZipFile zip; private final Report report; private final EpubPackage epack; public EpubLangCheck(EpubPackage epack, Report report) { this.zip = epack.getZip(); this.report = report; this.epack = epack; } @Override public boolean validate() { boolean result = false; SearchDictionary vtsd = new SearchDictionary(DictionaryType.VALID_TEXT_MEDIA_TYPES); for (int i = 0; i < epack.getManifest().itemsLength(); i++) { ManifestItem mi = epack.getManifest().getItem(i); if (vtsd.isValidMediaType(mi.getMediaType())) { XMLContentDocParser parser = new XMLContentDocParser(this.zip, report); LangAttributeHandler sh = new LangAttributeHandler(); String fileToParse = epack.getManifestItemFileName(mi); ZipEntry entry = this.zip.getEntry(fileToParse); if (entry == null) { // already reported in core checkers // report.message(MessageId.RSC_001, EPUBLocation.create(this.epack.getFileName()), fileToParse); continue; } parser.parseDoc(fileToParse, sh); String langAttribute = sh.getLangAttr(); String xmlLangAttribute = sh.getXmlLangAttr(); if (langAttribute != null && xmlLangAttribute != null) { if (xmlLangAttribute.compareToIgnoreCase(langAttribute) != 0) { report.message(MessageId.HTM_017, EPUBLocation.create(fileToParse)); } if (!isValidLanguageDefinition(xmlLangAttribute)) { report.message(MessageId.HTM_018, EPUBLocation.create(fileToParse)); } if (!isValidLanguageDefinition(langAttribute)) { report.message(MessageId.HTM_019, EPUBLocation.create(fileToParse)); } } else { if (xmlLangAttribute == null) { report.message(MessageId.HTM_020, EPUBLocation.create(fileToParse)); } if (langAttribute == null) { report.message(MessageId.HTM_021, EPUBLocation.create(fileToParse)); } } } } return result; } private boolean isValidLanguageDefinition(String language) { // ignore language subclasses like en-us or fr-ca. int pos = language.indexOf("-"); if (pos >= 0) { language = language.substring(0, pos); } for (String[] langValue : langValues) { if (language.compareToIgnoreCase(langValue[1]) == 0) { return true; } } return false; } private final String[][] langValues = new String[][] { {"Abkhazian", "ab"}, {"Afar", "aa"}, {"Afrikaans", "af"}, {"Albanian", "sq"}, {"Amharic", "am"}, {"Arabic", "ar"}, {"Aragonese", "an"}, {"Armenian", "hy"}, {"Assamese", "as"}, {"Aymara", "ay"}, {"Azerbaijani", "az"}, {"Bashkir", "ba"}, {"Basque", "eu"}, {"Bengali (Bangla)", "bn"}, {"Bhutani", "dz"}, {"Bihari", "bh"}, {"Bislama", "bi"}, {"Breton", "br"}, {"Bulgarian", "bg"}, {"Burmese", "my"}, {"Byelorussian (Belarusian)", "be"}, {"Cambodian", "km"}, {"Catalan", "ca"}, {"Cherokee", " "}, {"Chewa", " "}, {"Chinese (Simplified)", "zh"}, {"Chinese (Traditional)", "zh"}, {"Corsican", "co"}, {"Croatian", "hr"}, {"Czech", "cs"}, {"Danish", "da"}, {"Divehi", " "}, {"Dutch", "nl"}, {"Edo", " "}, {"English", "en"}, {"Esperanto", "eo"}, {"Estonian", "et"}, {"Faeroese", "fo"}, {"Farsi", "fa"}, {"Fiji", "fj"}, {"Finnish", "fi"}, {"Flemish", " "}, {"French", "fr"}, {"Frisian", "fy"}, {"Fulfulde", " "}, {"Galician", "gl"}, {"Gaelic (Scottish)", "gd"}, {"Gaelic (Manx)", "gv"}, {"Georgian", "ka"}, {"German", "de"}, {"Greek", "el"}, {"Greenlandic", "kl"}, {"Guarani", "gn"}, {"Gujarati", "gu"}, {"Haitian Creole", "ht"}, {"Hausa", "ha"}, {"Hawaiian", "haw"}, {"Hebrew", "he"}, {"Hindi", "hi"}, {"Hungarian", "hu"}, {"Ibibio", " "}, {"Icelandic", "is"}, {"Ido", "io"}, {"Igbo", " "}, {"Indonesian", "id, in"}, {"Interlingua", "ia"}, {"Interlingue", "ie"}, {"Inuktitut", "iu"}, {"Inupiak", "ik"}, {"Irish", "ga"}, {"Italian", "it"}, {"Japanese", "ja"}, {"Javanese", "jv"}, {"Kannada", "kn"}, {"Kanuri", " "}, {"Kashmiri", "ks"}, {"Kazakh", "kk"}, {"Kinyarwanda (Ruanda)", "rw"}, {"Kirghiz", "ky"}, {"Kirundi (Rundi)", "rn"}, {"Konkani", " "}, {"Korean", "ko"}, {"Kurdish", "ku"}, {"Laothian", "lo"}, {"Latin", "la"}, {"Latvian (Lettish)", "lv"}, {"Limburgish ( Limburger)", "li"}, {"Lingala", "ln"}, {"Lithuanian", "lt"}, {"Macedonian", "mk"}, {"Malagasy", "mg"}, {"Malay", "ms"}, {"Malayalam", "ml"}, {" ", " "}, {"Maltese", "mt"}, {"Maori", "mi"}, {"Marathi", "mr"}, {"Moldavian", "mo"}, {"Mongolian", "mn"}, {"Nauru", "na"}, {"Nepali", "ne"}, {"Norwegian", "no"}, {"Occitan", "oc"}, {"Oriya", "or"}, {"Oromo (Afaan Oromo)", "om"}, {"Papiamentu", " "}, {"Pashto (Pushto)", "ps"}, {"Polish", "pl"}, {"Portuguese", "pt"}, {"Punjabi", "pa"}, {"Quechua", "qu"}, {"Rhaeto-Romance", "rm"}, {"Romanian", "ro"}, {"Russian", "ru"}, {"Sami (Lappish)", " "}, {"Samoan", "sm"}, {"Sangro", "sg"}, {"Sanskrit", "sa"}, {"Serbian", "sr"}, {"Serbo-Croatian", "sh"}, {"Sesotho", "st"}, {"Setswana", "tn"}, {"Shona", "sn"}, {"Sichuan Yi", "ii"}, {"Sindhi", "sd"}, {"Sinhalese", "si"}, {"Siswati", "ss"}, {"Slovak", "sk"}, {"Slovenian", "sl"}, {"Somali", "so"}, {"Spanish", "es"}, {"Sundanese", "su"}, {"Swahili (Kiswahili)", "sw"}, {"Swedish", "sv"}, {"Syriac", " "}, {"Tagalog", "tl"}, {"Tajik", "tg"}, {"Tamazight", " "}, {"Tamil", "ta"}, {"Tatar", "tt"}, {"Telugu", "te"}, {"Thai", "th"}, {"Tibetan", "bo"}, {"Tigrinya", "ti"}, {"Tonga", "to"}, {"Tsonga", "ts"}, {"Turkish", "tr"}, {"Turkmen", "tk"}, {"Twi", "tw"}, {"Uighur", "ug"}, {"Ukrainian", "uk"}, {"Urdu", "ur"}, {"Uzbek", "uz"}, {"Venda", " "}, {"Vietnamese", "vi"}, {"Volapük", "vo"}, {"Wallon", "wa"}, {"Welsh", "cy"}, {"Wolof", "wo"}, {"Xhosa", "xh"}, {"Yi", " "}, {"Yiddish", "yi, ji"}, {"Yoruba", "yo"}, {"Zulu", "zu"}, }; } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ctc/css/0000755000175000017500000000000013017276730022534 5ustar eugeneeugeneepubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ctc/css/EpubCSSCheckCSSHandler.java0000644000175000017500000006723113017276730027461 0ustar eugeneeugenepackage com.adobe.epubcheck.ctc.css; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Queue; import java.util.Vector; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.xml.stream.Location; import org.idpf.epubcheck.util.css.CssContentHandler; import org.idpf.epubcheck.util.css.CssErrorHandler; import org.idpf.epubcheck.util.css.CssExceptions; import org.idpf.epubcheck.util.css.CssGrammar; import org.idpf.epubcheck.util.css.CssLocation; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.messages.MessageId; import com.adobe.epubcheck.util.LocationImpl; import com.adobe.epubcheck.util.TextSearchDictionaryEntry; import com.google.common.base.Optional; public class EpubCSSCheckCSSHandler implements CssContentHandler, CssErrorHandler { String path; Report report; boolean isGlobalFixedFormat; boolean hasIndividualFixedFormatDocuments; int scopeId; boolean isBody; boolean inKeyFrames; CSSSelectorCollection currentFileSelectorCollection; CSSSelectorCollection inProgressSelectorCollection; final Vector declarationComponentItems = new Vector(); final Vector functionComponentItems = new Vector(); final Vector atRuleComponentItems = new Vector(); int startingLineNumber; int startingColumnNumber; boolean inFontFace; boolean hasFontFaceDeclarations; CssGrammar.CssAtRule atRule; public HashMap getClassMap() { return classMap; } public boolean IncrementGlobalCssClassCount(String attrValue) { ClassUsage val = getClassMap().get(attrValue); if (val != null) { ++val.Count; return true; } return false; } public void CheckUnusedCSSClassSelectors(Report report) { HashMap map = getClassMap(); for (ClassUsage cu : map.values()) { if (cu.Count == 0) { assert (cu.Name != null && !cu.Name.isEmpty()); report.message(MessageId.CSS_024, getCorrectedEPUBLocation(cu.FileName, cu.Location.getLineNumber(), cu.Location.getColumnNumber(), cu.Name)); } } } int correctedLineNumber(int lineNumber) { return startingLineNumber + lineNumber; } int correctedColumnNumber(int lineNumber, int columnNumber) { if (lineNumber != 0) { return columnNumber; } return startingColumnNumber + columnNumber; } public class ClassUsage { public String Name; public Location Location; public String FileName; public int Count; } HashMap classMap = new LinkedHashMap(); public EpubCSSCheckCSSHandler(Report report, boolean isGlobalFixedFormat, boolean hasIndividualFixedFormatDocuments) { startingLineNumber = 0; startingColumnNumber = 0; this.isGlobalFixedFormat = isGlobalFixedFormat; this.hasIndividualFixedFormatDocuments = hasIndividualFixedFormatDocuments; setReport(report); setScopeId(0); buildCssSearchDictionaries(); } public EpubCSSCheckCSSHandler(Report report, int startingLineNumber, int startingColumnNumber, boolean isGlobalFixedFormat, boolean hasIndividualFixedFormatDocuments) { this.startingLineNumber = startingLineNumber - 1; // To get the right final Line number need to be added using 0 based starting point instead of 1 based. this.startingColumnNumber = startingColumnNumber; this.isGlobalFixedFormat = isGlobalFixedFormat; this.hasIndividualFixedFormatDocuments = hasIndividualFixedFormatDocuments; setReport(report); setScopeId(0); buildCssSearchDictionaries(); } public String getPath() { return path; } public void setPath(String path) { this.path = path; } Report getReport() { return report; } void setReport(Report report) { this.report = report; } void setScopeId(int scopeId) { this.scopeId = scopeId; } void buildCssSearchDictionaries() { String description; String value; TextSearchDictionaryEntry de; //search eval() expression description = "rotateX()"; value = "rotatex"; de = new TextSearchDictionaryEntry(description, value, MessageId.CSS_009); functionComponentItems.add(de); description = "rotateY()"; value = "rotatey"; de = new TextSearchDictionaryEntry(description, value, MessageId.CSS_009); functionComponentItems.add(de); description = "columns"; value = "columns"; de = new TextSearchDictionaryEntry(description, value, MessageId.CSS_009); declarationComponentItems.add(de); description = "column-count"; value = "column-count"; de = new TextSearchDictionaryEntry(description, value, MessageId.CSS_009); declarationComponentItems.add(de); description = "column-gap"; value = "column-gap"; de = new TextSearchDictionaryEntry(description, value, MessageId.CSS_009); declarationComponentItems.add(de); description = "column-rule"; value = "column-rule"; de = new TextSearchDictionaryEntry(description, value, MessageId.CSS_009); declarationComponentItems.add(de); description = "keyframes"; value = "keyframes"; de = new TextSearchDictionaryEntry(description, value, MessageId.CSS_009); atRuleComponentItems.add(de); description = "transition"; value = "transition"; de = new TextSearchDictionaryEntry(description, value, MessageId.CSS_009); declarationComponentItems.add(de); description = "box-sizing"; value = "box-sizing"; de = new TextSearchDictionaryEntry(description, value, MessageId.CSS_009); declarationComponentItems.add(de); } @Override public void startDocument() { currentFileSelectorCollection = new CSSSelectorCollection(path, new LocationImpl(-1, -1, -1, path, path), scopeId); } @Override public void endDocument() { currentFileSelectorCollection = null; ++scopeId; } static final Pattern keyframesPattern = Pattern.compile("@((keyframes)|(-moz-keyframes)|(-webkit-keyframes)|(-o-keyframes))"); @Override public void startAtRule(CssGrammar.CssAtRule atRule) { this.atRule = atRule; if (atRule.getName() != Optional.absent()) { String ruleName = atRule.getName().get().toLowerCase(Locale.ROOT); CssLocation location = atRule.getLocation(); if (ruleName.startsWith("@media")) { getReport().message(MessageId.CSS_023, getCorrectedEPUBLocation(path, location.getLine(), location.getColumn(), atRule.toCssString())); } else if (keyframesPattern.matcher(ruleName).matches()) { inKeyFrames=true; } else if (ruleName.equals("@font-face")) { inFontFace = true; } searchInsideValue(ruleName, atRule.getLocation().getLine(), location.getColumn(), atRuleComponentItems, path, atRule.toCssString()); } } EPUBLocation getCorrectedEPUBLocation(String fileName, int lineNumber, int columnNumber, String context) { lineNumber = correctedLineNumber(lineNumber); columnNumber = correctedColumnNumber(lineNumber, columnNumber); return EPUBLocation.create(fileName, lineNumber, columnNumber, context); } @Override public void endAtRule(String ruleName) { if (ruleName.equals("@font-face")) { if (!hasFontFaceDeclarations) { getReport().message(MessageId.CSS_019, getCorrectedEPUBLocation(path, atRule.getLocation().getLine(), atRule.getLocation().getColumn(), atRule.toCssString()), atRule.toCssString()); } } inKeyFrames = false; inFontFace = false; hasFontFaceDeclarations=false; atRule = null; } @Override public void selectors(List selectors) { inProgressSelectorCollection = new CSSSelectorCollection(path, getCorrectedLocationFromCssLocation(selectors.get(0).getLocation()), scopeId); Queue selectorQueue = new LinkedList(); isBody = getIsBody(selectors, selectorQueue); while (!selectorQueue.isEmpty()) { CssGrammar.CssConstruct construct = selectorQueue.remove(); CssGrammar.CssConstruct.Type type = construct.getType(); switch (type) { case CLASSNAME: {//.ident CssGrammar.CssClassName className = ((CssGrammar.CssClassName) construct); Location location = getCorrectedLocationFromCssLocation(className.getLocation()); CSSSelector newSelector = new CSSSelector(className.toCssString(), location, true); inProgressSelectorCollection.addSelector(newSelector); addClassSelector(newSelector, path, location); break; } case STRING: case KEYWORD: case COMBINATOR: //space, plus, gt, tilde break; case ATTRIBUTE_MATCH: // "~=", "|=", "^=","$=" "*=" { CssGrammar.CssAttributeMatchSelector attributeMatchSelector = ((CssGrammar.CssAttributeMatchSelector) construct); Location location = getCorrectedLocationFromCssLocation(attributeMatchSelector.getLocation()); CSSSelector newSelector = new CSSSelector(attributeMatchSelector.toCssString(), location, false); inProgressSelectorCollection.addSelector(newSelector); break; } case HASHNAME: //#ident {//.ident CssGrammar.CssHashName hashName = ((CssGrammar.CssHashName) construct); Location location = getCorrectedLocationFromCssLocation(hashName.getLocation()); CSSSelector newSelector = new CSSSelector(hashName.toCssString(), location, false); inProgressSelectorCollection.addSelector(newSelector); break; } case ATRULE: case QUANTITY: case URANGE: case URI: case SYMBOL: //a single char, eg operators case FUNCTION: case DECLARATION: break; case PSEUDO: //element and class { CssGrammar.CssPseudoSelector psuedoSelector = ((CssGrammar.CssPseudoSelector) construct); Location location = getCorrectedLocationFromCssLocation(psuedoSelector.getLocation()); CSSSelector newSelector = new CSSSelector(psuedoSelector.toCssString(), location, false); inProgressSelectorCollection.addSelector(newSelector); break; } case TYPE_SELECTOR: //ns|E, *|E, |E, E, * { CssGrammar.CssTypeSelector typeSelector = ((CssGrammar.CssTypeSelector) construct); Location location = getCorrectedLocationFromCssLocation(typeSelector.getLocation()); CSSSelector newSelector = new CSSSelector(typeSelector.toCssString(), location, false); inProgressSelectorCollection.addSelector(newSelector); break; } case SELECTOR: { CssGrammar.CssSelector selector = ((CssGrammar.CssSelector) construct); for (CssGrammar.CssConstruct c : selector.getComponents()) { selectorQueue.add(c); } break; } case SIMPLE_SELECTOR_SEQ: { CssGrammar.CssSimpleSelectorSequence sequence = ((CssGrammar.CssSimpleSelectorSequence) construct); for (CssGrammar.CssConstruct c : sequence.getComponents()) { selectorQueue.add(c); } break; } case ATTRIBUTE_SELECTOR: //[...] { CssGrammar.CssAttributeSelector attributeSelector = ((CssGrammar.CssAttributeSelector) construct); Location location = getCorrectedLocationFromCssLocation(attributeSelector.getLocation()); CSSSelector newSelector = new CSSSelector(attributeSelector.toCssString(), location, false); inProgressSelectorCollection.addSelector(newSelector); break; } case SCOPEDGROUP: //(...) and [...], the latter when not an attr selector segment break; } } } static boolean getIsBody(List selectors, Queue selectorQueue) { boolean isBody = false; for (CssGrammar.CssSelector selector : selectors) { selectorQueue.add(selector); if (!isBody) { String selectorName = selector.toCssString(); if ("body".equalsIgnoreCase(selectorName)) { isBody = true; } } } return isBody; } void addClassSelector(CSSSelector selector, String path, Location location) { if (selector.isClass()) { String name = selector.getName(); ClassUsage c = getClassMap().get(name); if (c == null) { c = new ClassUsage(); c.Count = 0; c.FileName = path; c.Location = location; c.Name = selector.getName(); getClassMap().put(name, c); } } } Location getCorrectedLocationFromCssLocation(CssLocation location) { return new LocationImpl(correctedLineNumber(location.getLine()), correctedColumnNumber(location.getLine(), location.getColumn()), location.getCharOffset(), location.getSystemID(), location.getSystemID()); } @Override public void endSelectors(List selectors) { for (CSSSelector selector : inProgressSelectorCollection.getSelectors().values()) { currentFileSelectorCollection.addSelector(selector); } inProgressSelectorCollection = null; isBody = false; } @Override public void declaration(CssGrammar.CssDeclaration declaration) { if (declaration.getName() != Optional.absent()) { String text = declaration.getName().get(); searchInsideValue(text, declaration.getLocation().getLine(), declaration.getLocation().getColumn(), declarationComponentItems, path, declaration.toCssString()); checkTermsAndValues(declaration); boolean isImportant = CheckImportant(declaration); boolean added = false; boolean isFontSize = ("font-size".equalsIgnoreCase(text)); boolean isFont = ("font".equalsIgnoreCase(text)); StringBuilder sb = new StringBuilder(); if (isFont) { CheckFont(declaration); } if (isBody) { CheckBody(declaration); } for (CssGrammar.CssConstruct construct : declaration.getComponents()) { Vector searchItems; String searchText; if (isFontSize) { CheckFontSize(construct, declaration); } switch (construct.getType()) { case FUNCTION: { CssGrammar.CssFunction function = (CssGrammar.CssFunction) construct; searchItems = functionComponentItems; searchText = function.getName().isPresent() ? function.getName().get() : null; break; } default: { searchItems = declarationComponentItems; searchText = construct.toCssString(); if (inProgressSelectorCollection != null && searchText != null) { if (added) { sb.append(" "); } sb.append(searchText); added = true; } break; } } if (searchText != null) { searchInsideValue(searchText, construct.getLocation().getLine(), construct.getLocation().getColumn(), searchItems, path, declaration.toCssString()); } } if (inProgressSelectorCollection != null) { String value = sb.toString(); for (CSSSelector selector : inProgressSelectorCollection.getSelectors().values()) { CSSSelectorAttribute attribute = new CSSSelectorAttribute(text, value, isImportant, selector); selector.addAttribute(attribute); } } if (inFontFace) { hasFontFaceDeclarations = true; } } } void checkTermsAndValues(CssGrammar.CssDeclaration declaration) { if (!isGlobalFixedFormat || hasIndividualFixedFormatDocuments) { MessageId id = hasIndividualFixedFormatDocuments ? MessageId.CSS_027 : MessageId.CSS_017; if ("position".compareToIgnoreCase(declaration.getName().get()) == 0) { for (CssGrammar.CssConstruct construct : declaration.getComponents()) { if (construct.getType() == CssGrammar.CssConstruct.Type.KEYWORD && "absolute".compareToIgnoreCase(construct.toCssString()) == 0) { getReport().message(id, getCorrectedEPUBLocation(path, declaration.getLocation().getLine(), declaration.getLocation().getColumn(), declaration.toCssString()), declaration.getName().get()); break; } } } } } boolean CheckImportant(CssGrammar.CssDeclaration declaration) { boolean isImportant = declaration.getImportant(); if (isImportant) { getReport().message(MessageId.CSS_013, getCorrectedEPUBLocation(path, declaration.getLocation().getLine(), declaration.getLocation().getColumn(), declaration.toCssString())); } return isImportant; } void CheckBody(CssGrammar.CssDeclaration declaration) { String declarationName = declaration.toCssString().toLowerCase(Locale.ROOT); if (declarationName.startsWith("margin-") || declarationName.equals("margin")) { getReport().message(MessageId.CSS_022, getCorrectedEPUBLocation(path, declaration.getLocation().getLine(), declaration.getLocation().getColumn(), declaration.toCssString()), declarationName); } } void CheckFontSize(CssGrammar.CssConstruct construct, CssGrammar.CssDeclaration declaration) { MessageId id = hasIndividualFixedFormatDocuments ? MessageId.ACC_016 : MessageId.ACC_014; switch (construct.getType()) { case KEYWORD: { if (!isGlobalFixedFormat || hasIndividualFixedFormatDocuments) { String value = construct.toCssString().toLowerCase(Locale.ROOT); if (("smaller".compareTo(value) != 0) && ("larger".compareTo(value) != 0) && ("inherit".compareTo(value) != 0)) { getReport().message(id, getCorrectedEPUBLocation(path, declaration.getLocation().getLine(), declaration.getLocation().getColumn(), declaration.toCssString())); } } break; } case QUANTITY: if (!isGlobalFixedFormat || hasIndividualFixedFormatDocuments) { CssGrammar.CssQuantity quantity = (CssGrammar.CssQuantity) construct; switch (quantity.getUnit()) { case EMS: case REMS: case PERCENTAGE: break; default: getReport().message(id, getCorrectedEPUBLocation(path, declaration.getLocation().getLine(), declaration.getLocation().getColumn(), declaration.toCssString())); break; } } break; default: break; } } void CheckFont(CssGrammar.CssDeclaration declaration) { boolean assignedFontStyle = false; boolean assignedFontVariant = false; boolean assignedFontWeight = false; int i = 0; List components = declaration.getComponents(); CssGrammar.CssConstruct construct; if (!matchesSystemFont(declaration)) { while (i < components.size()) { construct = components.get(i); if (!assignedFontStyle && isFontStyle(construct)) { assignedFontStyle = true; ++i; continue; } if (!assignedFontVariant && isFontVariant(construct)) { assignedFontVariant = true; ++i; continue; } if (!assignedFontWeight && isFontWeight(construct)) { assignedFontWeight = true; ++i; continue; } if (!assignedFontStyle || !assignedFontVariant || !assignedFontWeight) { String value = construct.toCssString(); if (isNormal(value) || isInherit(value)) { if (!assignedFontStyle) { assignedFontStyle = true; ++i; continue; } else if (!assignedFontVariant) { assignedFontVariant = true; ++i; continue; } else { assignedFontWeight = true; ++i; continue; } } } if (isFontSize(construct)) { CheckFontSize(construct, declaration); if (i <= components.size() - 2) { construct = components.get(++i); if (construct.getType() == CssGrammar.CssConstruct.Type.SYMBOL && construct.toCssString().equals("/")) { construct = components.get(++i); CheckLineHeight(construct, declaration); } } return; } else { // we got into a state where we didn't recognize the token as a font-size, but it didn't match style/variant/weight either. getReport().message(MessageId.CSS_020, getCorrectedEPUBLocation(path, declaration.getLocation().getLine(), declaration.getLocation().getColumn(), declaration.toCssString()), construct.toCssString()); return; } } } } HashSet fontSizes; boolean isFontSize(CssGrammar.CssConstruct construct) { if (null == fontSizes) { String[] fontSizeStrings = { "xx-small", "x-small", "small", "medium", "large", "x-large", "xx-large", "larger", "smaller", }; fontSizes = getHashSetFromStrings(fontSizeStrings); } if (valueMatchesLowercaseLegalValues(construct, fontSizes)) { return true; } if (construct.getType() == CssGrammar.CssConstruct.Type.QUANTITY) { CssGrammar.CssQuantity quantity = (CssGrammar.CssQuantity) (construct); CssGrammar.CssQuantity.Unit unit = quantity.getUnit(); switch (unit) { case PERCENTAGE: case EMS: case LENGTH: return true; } } return false; } void CheckLineHeight(CssGrammar.CssConstruct construct, CssGrammar.CssDeclaration declaration) { if (!isGlobalFixedFormat || hasIndividualFixedFormatDocuments) { MessageId id = hasIndividualFixedFormatDocuments ? MessageId.ACC_017 : MessageId.ACC_015; if (construct.getType() == CssGrammar.CssConstruct.Type.QUANTITY) { CssGrammar.CssQuantity quantity = (CssGrammar.CssQuantity) (construct); CssGrammar.CssQuantity.Unit unit = quantity.getUnit(); switch (unit) { case PERCENTAGE: case EMS: break; case NUMBER: break; case LENGTH: getReport().message(id, getCorrectedEPUBLocation(path, declaration.getLocation().getLine(), declaration.getLocation().getColumn(), declaration.toCssString())); break; } } } } HashSet fontVariants; boolean isFontVariant(CssGrammar.CssConstruct construct) { if (null == fontVariants) { final String[] fontVariantsStrings = { "small-caps", }; fontVariants = getHashSetFromStrings(fontVariantsStrings); } return valueMatchesLowercaseLegalValues(construct, fontVariants); } HashSet fontStyles; boolean isFontStyle(CssGrammar.CssConstruct construct) { if (null == fontStyles) { final String[] fontStylesStrings = { "italic", "oblique", }; fontStyles = getHashSetFromStrings(fontStylesStrings); } return valueMatchesLowercaseLegalValues(construct, fontStyles); } boolean isNormal(String value) { return "normal".compareToIgnoreCase(value) == 0; } boolean isInherit(String value) { return "inherit".compareToIgnoreCase(value) == 0; } HashSet fontWeightStrings; boolean isFontWeightString(String value) { if (fontWeightStrings == null) { final String[] fontWeights = { "bold", "bolder", "lighter", "100", "200", "300", "400", "500", "600", "700", "800", "900", }; fontWeightStrings = getHashSetFromStrings(fontWeights); } return valueMatchesLowercaseLegalValues(value, fontWeightStrings); } HashSet getHashSetFromStrings(String[] strings) { HashSet hashSet = new HashSet(); Collections.addAll(hashSet, strings); return hashSet; } boolean valueMatchesLowercaseLegalValues(CssGrammar.CssConstruct construct, HashSet legalValues) { return valueMatchesLowercaseLegalValues(construct.toCssString(), legalValues); } boolean valueMatchesLowercaseLegalValues(String value, HashSet legalValues) { if (null == value || value.isEmpty()) { return false; } return legalValues.contains(value.toLowerCase(Locale.ROOT)); } boolean isFontWeight(CssGrammar.CssConstruct construct) { switch (construct.getType()) { case KEYWORD: case STRING: return isFontWeightString(construct.toCssString()); case QUANTITY: CssGrammar.CssQuantity quantity = (CssGrammar.CssQuantity) construct; if (quantity.getUnit() == CssGrammar.CssQuantity.Unit.INTEGER) { return isFontWeightString(quantity.toCssString()); } break; } return false; } HashSet validSystemFontNames; boolean matchesSystemFont(CssGrammar.CssDeclaration declaration) { List components = declaration.getComponents(); if (components.size() == 1 && components.get(0).getType() == CssGrammar.CssConstruct.Type.KEYWORD) { String name = components.get(0).toCssString(); if (!isValidSystemFontName(name)) { // report error here = missing size or font family getReport().message(MessageId.CSS_021, getCorrectedEPUBLocation(path, declaration.getLocation().getLine(), declaration.getLocation().getColumn(), declaration.toCssString())); } return true; // return true here because we have handled the case of only 1 attribute in the list } return false; } boolean isValidSystemFontName(String name) { if (validSystemFontNames == null) { String[] validSystemFontNamesStrings = {"caption", "icon", "menu", "message-box", "small-caption", "status-bar", "fantasy", "inherit"}; validSystemFontNames = getHashSetFromStrings(validSystemFontNamesStrings); } return valueMatchesLowercaseLegalValues(name, validSystemFontNames); } static final Pattern invalidTokenStringFinder = Pattern.compile("Token '[0-9]+%' not allowed here"); @Override public void error(CssExceptions.CssException e) throws CssExceptions.CssException { // Already handled in com.adobe.epubcheck.css.CSSHandler // String message = e.getMessage(); // // if (inKeyFrames) // { // Matcher m = invalidTokenStringFinder.matcher(message); // if (m.matches()) // { // return; // } // } // CssLocation location = e.getLocation(); // report.message(MessageId.CSS_008, new EPUBLocation(path, location.getLine(), location.getColumn()), message); } void searchInsideValue(String entry, int line, int column, Vector tds, String file, String context) { for (TextSearchDictionaryEntry de : tds) { Pattern p = de.getPattern(); Matcher matcher = p.matcher(entry); int position = 0; while (matcher.find(position)) { position = matcher.end(); report.message(de.getErrorCode(), getCorrectedEPUBLocation(file, line, column, context)); } } } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ctc/css/CSSSelectorAttribute.java0000644000175000017500000000132513017276730027415 0ustar eugeneeugenepackage com.adobe.epubcheck.ctc.css; class CSSSelectorAttribute { private final String name; private final String value; private final boolean isImportant; private final CSSSelector originatingSelector; public CSSSelectorAttribute(String name, String value, boolean isImportant, CSSSelector originatingSelector) { this.name = name; this.value = value; this.isImportant = isImportant; this.originatingSelector = originatingSelector; } public String getName() { return name; } public String getValue() { return value; } public boolean isImportant() { return isImportant; } public CSSSelector getOriginatingSelector() { return originatingSelector; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ctc/css/CSSSelector.java0000644000175000017500000000156213017276730025534 0ustar eugeneeugenepackage com.adobe.epubcheck.ctc.css; import javax.xml.stream.Location; import java.util.HashMap; public class CSSSelector { private final String name; private final Location location; private final boolean isClass; private final HashMap attributes = new HashMap(); public CSSSelector(String name, Location location, boolean isClass) { this.name = name; this.location = location; this.isClass = isClass; } public String getName() { return name; } public boolean isClass() { return isClass; } public Location getLocation() { return location; } public HashMap getAttributes() { return attributes; } public void addAttribute(CSSSelectorAttribute attribute) { attributes.put(attribute.getName(), attribute); } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ctc/css/CSSSelectorCollection.java0000644000175000017500000000165713017276730027555 0ustar eugeneeugenepackage com.adobe.epubcheck.ctc.css; import javax.xml.stream.Location; import java.util.HashMap; public class CSSSelectorCollection { private final String name; private final int scopeId; private final Location location; private final HashMap selectors = new HashMap(); public CSSSelectorCollection(String name, Location location, int scopeId) { this.name = name; this.location = location; this.scopeId = scopeId; } public HashMap getSelectors() { return selectors; } public void addSelector(CSSSelector selector) { CSSSelector existing = selectors.get(selector.getName()); if (existing != null) { for (CSSSelectorAttribute attribute : selector.getAttributes().values()) { existing.addAttribute(attribute); } selector = existing; } selectors.put(selector.getName(), selector); } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ctc/EpubNavCheck.java0000644000175000017500000001367613017276730025122 0ustar eugeneeugenepackage com.adobe.epubcheck.ctc; import java.util.HashSet; import java.util.Vector; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.ctc.epubpackage.EpubPackage; import com.adobe.epubcheck.ctc.epubpackage.ManifestItem; import com.adobe.epubcheck.ctc.epubpackage.PackageManifest; import com.adobe.epubcheck.ctc.epubpackage.PackageSpine; import com.adobe.epubcheck.ctc.epubpackage.SpineItem; import com.adobe.epubcheck.messages.MessageId; import com.adobe.epubcheck.opf.DocumentValidator; import com.adobe.epubcheck.util.EpubConstants; import com.adobe.epubcheck.util.FeatureEnum; import com.adobe.epubcheck.util.HandlerUtil; import com.adobe.epubcheck.util.PathUtil; public class EpubNavCheck implements DocumentValidator { private final XmlDocParser docParser; private final Document packageMainDocument; private final EpubPackage epack; private final Report report; public EpubNavCheck(EpubPackage epack, Report report) { ZipFile zip = epack.getZip(); this.packageMainDocument = epack.getPackDoc(); this.epack = epack; docParser = new XmlDocParser(zip, report); this.report = report; } @Override public boolean validate() { boolean result = false; Vector navDocPath = getNAVDocuments(packageMainDocument); if (navDocPath != null && navDocPath.size() > 0) { for (String navDoc : navDocPath) { if (navDoc != null) { String fileToParse; if (epack.getPackageMainPath() != null && epack.getPackageMainPath().length() > 0) { fileToParse = PathUtil.resolveRelativeReference(epack.getPackageMainFile(), navDoc, null); } else { fileToParse = navDoc; } ZipEntry entry = epack.getZip().getEntry(fileToParse); if (entry == null) { // already reported in core checkers // report.message(MessageId.RSC_001, EPUBLocation.create(epack.getFileName()), fileToParse); continue; } checkNavDoc(fileToParse); } } } return result; } private Vector getNAVDocuments(Document doc) { Vector navItems = new Vector(); NodeList manifestList = doc.getElementsByTagName("manifest"); for (int m = 0; m < manifestList.getLength(); m++) { Node manifestNode = manifestList.item(m); NodeList itemNodes = manifestNode.getChildNodes(); for (int it = 0; it < itemNodes.getLength(); it++) { NamedNodeMap itemNodeAttributes = itemNodes.item(it).getAttributes(); if (itemNodeAttributes != null && itemNodeAttributes.getNamedItem("properties") != null) { String nodePropertiesAttr = itemNodeAttributes.getNamedItem("properties").getNodeValue(); if (nodePropertiesAttr != null && nodePropertiesAttr.compareToIgnoreCase("nav") == 0) { String hrefValue = null; if (itemNodeAttributes.getNamedItem("href").getNodeValue() != null) { hrefValue = itemNodeAttributes.getNamedItem("href").getNodeValue(); } navItems.add(hrefValue); } } } } return navItems; } private boolean checkNavDoc(String navDocEntry) { HashSet tocLinkSet = new HashSet(); boolean containsNavElements = false; Document doc = docParser.parseDocument(navDocEntry); if (doc == null) { // no need to report an error here because it was already reported inside of the docParser. return false; } NodeList n = doc.getElementsByTagName("nav"); for (int i = 0; i < n.getLength(); i++) { Element navElement = (Element) n.item(i); String type = navElement.getAttributeNS(EpubConstants.EpubTypeNamespaceUri, "type"); if (type != null) { if(type.equals("toc")) { containsNavElements = true; NodeList links = navElement.getElementsByTagName("a"); int navOrder = 1; for (int j = 0; j < links.getLength(); j++) { Element link = (Element) links.item(j); String href = link.getAttribute("href"); String path = href; int hash = href.indexOf("#"); if (hash >= 0) { path = href.substring(0, hash); } path = PathUtil.resolveRelativeReference(navDocEntry, path, null); if (!path.equals("") && !tocLinkSet.contains(path)) { report.info(path, FeatureEnum.NAVIGATION_ORDER, String.valueOf(navOrder)); navOrder++; tocLinkSet.add(path); } } } else if (type.equals("page-list")) { report.message(MessageId.NAV_002, EPUBLocation.create(navDocEntry, HandlerUtil.getElementLineNumber(navElement), HandlerUtil.getElementColumnNumber(navElement), "page-list")); } } } PackageManifest manifest = epack.getManifest(); PackageSpine spine = epack.getSpine(); if (spine != null) { String tocFileName = spine.getToc(); for (int i = 0; i < spine.itemsLength(); ++i) { SpineItem si = spine.getItem(i); ManifestItem mi = manifest.getItem(si.getIdref()); if (mi != null) { String path = mi.getHref(); path = PathUtil.resolveRelativeReference(epack.getPackageMainFile(), path, null); if (path != null && !path.equals(tocFileName) && !path.equals(navDocEntry) && !tocLinkSet.contains(path)) { report.message(MessageId.OPF_058, EPUBLocation.create(navDocEntry, -1, -1, path)); } } } } return containsNavElements; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ctc/EpubMetaDataV3Check.java0000644000175000017500000000144113017276730026252 0ustar eugeneeugenepackage com.adobe.epubcheck.ctc; import org.w3c.dom.Document; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.ctc.epubpackage.EpubPackage; import com.adobe.epubcheck.opf.DocumentValidator; public class EpubMetaDataV3Check implements DocumentValidator { private final Document doc; private final String pathRootFile; @SuppressWarnings("unused") private final Report report; public EpubMetaDataV3Check(EpubPackage epack, Report report) { this.doc = epack.getPackDoc(); this.pathRootFile = epack.getPackageMainFile(); this.report = report; } @Override public boolean validate() { return isMetaDataValid(doc, pathRootFile); } private boolean isMetaDataValid(Document doc, String pathRootFile) { return true; // no custom checks } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/ctc/EpubTextContentCheck.java0000644000175000017500000000300413017276730026635 0ustar eugeneeugenepackage com.adobe.epubcheck.ctc; import java.util.zip.ZipEntry; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.ctc.epubpackage.EpubPackage; import com.adobe.epubcheck.ctc.epubpackage.ManifestItem; import com.adobe.epubcheck.opf.DocumentValidator; import com.adobe.epubcheck.util.SearchDictionary; import com.adobe.epubcheck.util.SearchDictionary.DictionaryType; public class EpubTextContentCheck implements DocumentValidator { private final Report report; private final EpubPackage epack; private final EntitySearch search; public EpubTextContentCheck(Report report, EpubPackage epack) { this.epack = epack; this.search = new EntitySearch(epack.getVersion(), epack.getZip(), report); this.report = report; } public boolean validate() { SearchDictionary validScriptTypes = new SearchDictionary(DictionaryType.VALID_TEXT_MEDIA_TYPES); for (int i = 0; i < epack.getManifest().itemsLength(); i++) { ManifestItem itemEntry = epack.getManifest().getItem(i); if (validScriptTypes.isValidMediaType(itemEntry.getMediaType())) { String fileToParse = epack.getManifestItemFileName(itemEntry); ZipEntry entry = epack.getZip().getEntry(fileToParse); if (entry == null) { // already reported in core checkers // report.message(MessageId.RSC_001, EPUBLocation.create(this.epack.getFileName()), fileToParse); continue; } this.search.Search(fileToParse); } } return true; } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/tool/0000755000175000017500000000000013017276730022150 5ustar eugeneeugeneepubcheck-4.0.2/src/main/java/com/adobe/epubcheck/tool/EpubChecker.java0000644000175000017500000005773013017276730025207 0ustar eugeneeugene/* * Copyright (c) 2007 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * */ package com.adobe.epubcheck.tool; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.util.HashMap; import java.util.Locale; import java.util.Map; import com.adobe.epubcheck.api.EPUBProfile; import com.adobe.epubcheck.api.EpubCheck; import com.adobe.epubcheck.api.EpubCheckFactory; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.nav.NavCheckerFactory; import com.adobe.epubcheck.opf.DocumentValidator; import com.adobe.epubcheck.opf.DocumentValidatorFactory; import com.adobe.epubcheck.opf.OPFCheckerFactory; import com.adobe.epubcheck.opf.ValidationContext.ValidationContextBuilder; import com.adobe.epubcheck.ops.OPSCheckerFactory; import com.adobe.epubcheck.overlay.OverlayCheckerFactory; import com.adobe.epubcheck.reporting.CheckingReport; import com.adobe.epubcheck.util.Archive; import com.adobe.epubcheck.util.DefaultReportImpl; import com.adobe.epubcheck.util.EPUBVersion; import com.adobe.epubcheck.util.FeatureEnum; import com.adobe.epubcheck.util.FileResourceProvider; import com.adobe.epubcheck.util.GenericResourceProvider; import com.adobe.epubcheck.util.InvalidVersionException; import com.adobe.epubcheck.util.Messages; import com.adobe.epubcheck.util.OPSType; import com.adobe.epubcheck.util.ReportingLevel; import com.adobe.epubcheck.util.URLResourceProvider; import com.adobe.epubcheck.util.XmlReportImpl; import com.adobe.epubcheck.util.XmpReportImpl; import com.adobe.epubcheck.util.outWriter; public class EpubChecker { String path = null; String mode = null; EPUBProfile profile = null; EPUBVersion version = EPUBVersion.VERSION_3; boolean expanded = false; boolean keep = false; boolean jsonOutput = false; boolean xmlOutput = false; boolean xmpOutput = false; File fileOut; File listChecksOut; File customMessageFile; boolean listChecks = false; boolean useCustomMessageFile = false; boolean failOnWarnings = false; int reportingLevel = ReportingLevel.Info; private static final HashMap modeMimeTypeMap; static { HashMap map = new HashMap(); map.put(new OPSType("xhtml", EPUBVersion.VERSION_2), "application/xhtml+xml"); map.put(new OPSType("xhtml", EPUBVersion.VERSION_3), "application/xhtml+xml"); map.put(new OPSType("svg", EPUBVersion.VERSION_2), "image/svg+xml"); map.put(new OPSType("svg", EPUBVersion.VERSION_3), "image/svg+xml"); map.put(new OPSType("mo", EPUBVersion.VERSION_3), "application/smil+xml"); map.put(new OPSType("nav", EPUBVersion.VERSION_3), "application/xhtml+xml"); modeMimeTypeMap = map; } private static final HashMap documentValidatorFactoryMap; private static final String E_PUB_CHECK_CUSTOM_MESSAGE_FILE = "ePubCheckCustomMessageFile"; static { HashMap map = new HashMap(); map.put(new OPSType(null, EPUBVersion.VERSION_2), EpubCheckFactory.getInstance()); map.put(new OPSType(null, EPUBVersion.VERSION_3), EpubCheckFactory.getInstance()); map.put(new OPSType("opf", EPUBVersion.VERSION_2), OPFCheckerFactory.getInstance()); map.put(new OPSType("opf", EPUBVersion.VERSION_3), OPFCheckerFactory.getInstance()); map.put(new OPSType("xhtml", EPUBVersion.VERSION_2), OPSCheckerFactory.getInstance()); map.put(new OPSType("xhtml", EPUBVersion.VERSION_3), OPSCheckerFactory.getInstance()); map.put(new OPSType("svg", EPUBVersion.VERSION_2), OPSCheckerFactory.getInstance()); map.put(new OPSType("svg", EPUBVersion.VERSION_3), OPSCheckerFactory.getInstance()); map.put(new OPSType("mo", EPUBVersion.VERSION_3), OverlayCheckerFactory.getInstance()); map.put(new OPSType("nav", EPUBVersion.VERSION_3), NavCheckerFactory.getInstance()); documentValidatorFactoryMap = map; } int validateFile(String path, EPUBVersion version, Report report, EPUBProfile profile) { GenericResourceProvider resourceProvider; if (path.startsWith("http://") || path.startsWith("https://")) { resourceProvider = new URLResourceProvider(path); } else { File f = new File(path); if (f.exists()) { resourceProvider = new FileResourceProvider(path); } else { System.err.println(String.format(Messages.get("file_not_found"), path)); return 1; } } OPSType opsType = new OPSType(mode, version); DocumentValidatorFactory factory = documentValidatorFactoryMap.get(opsType); if (factory == null) { outWriter.println(Messages.get("display_help")); System.err.println(String.format(Messages.get("mode_version_not_supported"), mode, version)); throw new RuntimeException(String.format(Messages.get("mode_version_not_supported"), mode, version)); } DocumentValidator check = factory.newInstance(new ValidationContextBuilder().path(path) .report(report).resourceProvider(resourceProvider).mimetype(modeMimeTypeMap.get(opsType)) .version(version).profile(profile).build()); if (check.getClass() == EpubCheck.class) { int validationResult = ((EpubCheck) check).doValidate(); if (validationResult == 0) { outWriter.println(Messages.get("no_errors__or_warnings")); return 0; } else if (validationResult == 1) { System.err.println(Messages.get("there_were_warnings")); return failOnWarnings ? 1 : 0; } System.err.println(Messages.get("there_were_errors")); return 1; } else { if (check.validate()) { outWriter.println(Messages.get("no_errors__or_warnings")); return 0; } System.err.println(Messages.get("there_were_errors")); } return 1; } int validateEpubFile(String path, EPUBVersion version, Report report) { GenericResourceProvider resourceProvider; if (path.startsWith("http://") || path.startsWith("https://")) { resourceProvider = new URLResourceProvider(path); } else { File f = new File(path); if (f.exists()) { resourceProvider = new FileResourceProvider(path); } else { System.err.println(String.format(Messages.get("file_not_found"), path)); return 1; } } OPSType opsType = new OPSType(mode, version); DocumentValidatorFactory factory = documentValidatorFactoryMap.get(opsType); if (factory == null) { outWriter.println(Messages.get("display_help")); System.err.println(String.format(Messages.get("mode_version_not_supported"), mode, version)); throw new RuntimeException(String.format(Messages.get("mode_version_not_supported"), mode, version)); } DocumentValidator check = factory.newInstance( new ValidationContextBuilder().path(path) .report(report).resourceProvider(resourceProvider).mimetype(modeMimeTypeMap.get(opsType)) .version(version).profile(profile).build()); if (check.validate()) { outWriter.println(Messages.get("no_errors__or_warnings")); return 0; } System.err.println(Messages.get("there_were_errors")); return 1; } public int run(String[] args) { int returnValue = 1; try { if (processArguments(args)) { Report report = createReport(); report.initialize(); if (listChecks) { dumpMessageDictionary(report); return 0; } if (useCustomMessageFile) { report.setCustomMessageFile(customMessageFile.getAbsolutePath()); } returnValue = processFile(report); int returnValue2 = report.generate(); if (returnValue == 0) { returnValue = returnValue2; } } } catch (Exception ignored) { returnValue = 1; } finally { outWriter.println(Messages.get("epubcheck_completed")); outWriter.setQuiet(false); } return returnValue; } private void dumpMessageDictionary(Report report) throws IOException { OutputStreamWriter fw = null; try { if (listChecksOut != null) { fw = new FileWriter(listChecksOut); } else { fw = new OutputStreamWriter(System.out); } report.getDictionary().dumpMessages(fw); } catch (Exception e) { if (listChecksOut != null) { System.err.println(String.format(Messages.get("error_creating_config_file"), listChecksOut.getAbsoluteFile())); } System.err.println(e.getMessage()); } finally { if (fw != null) { try { fw.close(); } catch (IOException ignored) { } } } } private Report createReport() throws IOException { Report report; if (listChecks) { report = new DefaultReportImpl("none"); } else if (jsonOutput) { report = new CheckingReport(path, (fileOut == null) ? null : fileOut.getPath()); } else if (xmlOutput) { PrintWriter pw = null; if (fileOut == null) { pw = new PrintWriter(System.out, true); } else { pw = new PrintWriter(fileOut, "UTF-8"); } report = new XmlReportImpl(pw, path, EpubCheck.version()); } else if (xmpOutput) { PrintWriter pw = null; if (fileOut == null) { pw = new PrintWriter(System.out, true); } else { pw = new PrintWriter(fileOut, "UTF-8"); } report = new XmpReportImpl(pw, path, EpubCheck.version()); } else { report = new DefaultReportImpl(path); } report.setReportingLevel(this.reportingLevel); if (useCustomMessageFile) { report.setOverrideFile(customMessageFile); } return report; } public int processEpubFile(String[] args) { int returnValue = 1; try { if (processArguments(args)) { Report report = createReport(); report.initialize(); if (listChecks) { dumpMessageDictionary(report); return 0; } if (useCustomMessageFile) { report.setCustomMessageFile(customMessageFile.getAbsolutePath()); } returnValue = processEpubFile(report); int returnValue2 = report.generate(); if (returnValue == 0) { returnValue = returnValue2; } } } catch (Exception ignored) { returnValue = 1; } finally { outWriter.println(Messages.get("epubcheck_completed")); outWriter.setQuiet(false); } return returnValue; } int processEpubFile(Report report) { report.info(null, FeatureEnum.TOOL_NAME, "epubcheck"); report.info(null, FeatureEnum.TOOL_VERSION, EpubCheck.version()); report.info(null, FeatureEnum.TOOL_DATE, EpubCheck.buildDate()); int result; try { if (!expanded) { if (mode != null) { report.info(null, FeatureEnum.EXEC_MODE, String.format(Messages.get("single_file"), mode, version.toString(), profile)); } result = validateFile(path, version, report, profile); } else { System.err.println(Messages.get("error_processing_unexpanded_epub")); return 1; } return result; } catch (Throwable e) { e.printStackTrace(); return 1; } finally { report.close(); } } private int processFile(Report report) { report.info(null, FeatureEnum.TOOL_NAME, "epubcheck"); report.info(null, FeatureEnum.TOOL_VERSION, EpubCheck.version()); report.info(null, FeatureEnum.TOOL_DATE, EpubCheck.buildDate()); int result = 0; try { if (expanded) { Archive epub; try { epub = new Archive(path, true); } catch (RuntimeException ex) { System.err.println(Messages.get("there_were_errors")); return 1; } epub.createArchive(); report.setEpubFileName(epub.getEpubFile().getAbsolutePath()); EpubCheck check = new EpubCheck(epub.getEpubFile(), report, profile); int validationResult = check.doValidate(); if (validationResult == 0) { outWriter.println(Messages.get("no_errors__or_warnings")); result = 0; } else if (validationResult == 1) { System.err.println(Messages.get("there_were_warnings")); result = failOnWarnings ? 1 : 0; } else if (validationResult >= 2) { System.err.println(Messages.get("there_were_errors")); result = 1; } if (keep) { if ((report.getErrorCount() > 0) || (report.getFatalErrorCount() > 0)) { // keep if valid or only warnings System.err.println(Messages.get("deleting_archive")); epub.deleteEpubFile(); } } else { epub.deleteEpubFile(); } } else { if (mode != null) { report.info(null, FeatureEnum.EXEC_MODE, String.format(Messages.get("single_file"), mode, version.toString(), profile)); } result = validateFile(path, version, report, profile); } return result; } catch (Throwable e) { e.printStackTrace(); return 1; } finally { report.close(); } } /** * This method iterates through all of the arguments passed to main to find * accepted flags and the name of the file to check. This method returns the * last argument that ends with ".epub" (which is assumed to be the file to * check) Here are the currently accepted flags:
*
* -? or -help = display usage instructions
* -v or -version = display tool version number * * @param args * String[] containing arguments passed to main * @return the name of the file to check */ private boolean processArguments(String[] args) { // Exit if there are no arguments passed to main if (args.length < 1) { System.err.println(Messages.get("argument_needed")); return false; } setCustomMessageFileFromEnvironment(); for (int i = 0; i < args.length; i++) { if (args[i].equals("--version") || args[i].equals("-version") || args[i].equals("-v")) { if (i + 1 < args.length) { ++i; if (args[i].equals("2.0") || args[i].equals("2")) { version = EPUBVersion.VERSION_2; } else if (args[i].equals("3.0") || args[i].equals("3")) { version = EPUBVersion.VERSION_3; } else { outWriter.println(Messages.get("display_help")); throw new RuntimeException(new InvalidVersionException( InvalidVersionException.UNSUPPORTED_VERSION)); } } else { outWriter.println(Messages.get("display_help")); throw new RuntimeException(Messages.get("version_argument_expected")); } } else if (args[i].equals("--mode") || args[i].equals("-mode") || args[i].equals("-m")) { if (i + 1 < args.length) { mode = args[++i]; expanded = mode.equals("exp"); } else { outWriter.println(Messages.get("display_help")); throw new RuntimeException(Messages.get("mode_argument_expected")); } } else if (args[i].equals("--profile") || args[i].equals("-profile") || args[i].equals("-p")) { if (i + 1 < args.length) { String profileStr = args[++i]; try { profile = EPUBProfile.valueOf(profileStr.toUpperCase(Locale.ROOT)); } catch (IllegalArgumentException e) { System.err.println(Messages.get("mode_version_ignored", profileStr)); profile = EPUBProfile.DEFAULT; } } else { outWriter.println(Messages.get("display_help")); throw new RuntimeException(Messages.get("profile_argument_expected")); } } else if (args[i].equals("--save") || args[i].equals("-save") || args[i].equals("-s")) { keep = true; } else if (args[i].equals("--out") || args[i].equals("-out") || args[i].equals("-o")) { if ((args.length > (i + 1)) && !(args[i + 1].startsWith("-"))) { fileOut = new File(args[++i]); } else if ((args.length > (i + 1)) && (args[i + 1].equalsIgnoreCase("-"))) { fileOut = null; i++; } else { File pathFile = new File(path); if (pathFile.isDirectory()) { fileOut = new File(pathFile.getAbsoluteFile().getParentFile(), pathFile.getName() + "check.xml"); } else { fileOut = new File(path + "check.xml"); } } xmlOutput = true; } else if (args[i].equals("--json") || args[i].equals("-json") || args[i].equals("-j")) { if ((args.length > (i + 1)) && !(args[i + 1].startsWith("-"))) { fileOut = new File(args[++i]); } else if ((args.length > (i + 1)) && (args[i + 1].equalsIgnoreCase("-"))) { fileOut = null; i++; } else { File pathFile = new File(path); if (pathFile.isDirectory()) { fileOut = new File(pathFile.getAbsoluteFile().getParentFile(), pathFile.getName() + "check.json"); } else { fileOut = new File(path + "check.json"); } } jsonOutput = true; } else if (args[i].equals("--xmp") || args[i].equals("-xmp") || args[i].equals("-x")) { if ((args.length > (i + 1)) && !(args[i + 1].startsWith("-"))) { fileOut = new File(args[++i]); } else if ((args.length > (i + 1)) && (args[i + 1].equalsIgnoreCase("-"))) { fileOut = null; i++; } else { File pathFile = new File(path); if (pathFile.isDirectory()) { fileOut = new File(pathFile.getAbsoluteFile().getParentFile(), pathFile.getName() + "check.xmp"); } else { fileOut = new File(path + "check.xmp"); } } xmpOutput = true; } else if (args[i].equals("--info") || args[i].equals("-i")) { reportingLevel = ReportingLevel.Info; } else if (args[i].equals("--fatal") || args[i].equals("-f")) { reportingLevel = ReportingLevel.Fatal; } else if (args[i].equals("--error") || args[i].equals("-e")) { reportingLevel = ReportingLevel.Error; } else if (args[i].equals("--warn") || args[i].equals("-w")) { reportingLevel = ReportingLevel.Warning; } else if (args[i].equals("--usage") || args[i].equals("-u")) { reportingLevel = ReportingLevel.Usage; } else if (args[i].equals("--quiet") || args[i].equals("-q")) { outWriter.setQuiet(true); } else if (args[i].startsWith("--failonwarnings")) { String fw = args[i].substring("--failonwarnings".length()); failOnWarnings = (fw.compareTo("-") != 0); } else if (args[i].equals("--redir") || args[i].equals("-r")) { if (i + 1 < args.length) { fileOut = new File(args[++i]); } } else if (args[i].equals("--customMessages") || args[i].equals("-c")) { if (i + 1 < args.length) { String fileName = args[i + 1]; if ("none".compareTo(fileName.toLowerCase(Locale.ROOT)) == 0) { customMessageFile = null; useCustomMessageFile = false; ++i; } else if (!fileName.startsWith("-")) { customMessageFile = new File(fileName); useCustomMessageFile = true; ++i; } else { System.err.println(String.format(Messages.get("expected_message_filename"), fileName)); displayHelp(); return false; } } } else if (args[i].equals("--listChecks") || args[i].equals("-l")) { if (i + 1 < args.length) { if (!args[i + 1].startsWith("-")) { listChecksOut = new File(args[++i]); } else { listChecksOut = null; } } listChecks = true; } else if (args[i].equals("--help") || args[i].equals("-help") || args[i].equals("-h") || args[i].equals("-?")) { displayHelp(); // display help message } else { if (path == null) { path = args[i]; } else { System.err.println(String.format(Messages.get("unrecognized_argument"), args[i])); displayHelp(); return false; } } } if ((xmlOutput && xmpOutput) || (xmlOutput && jsonOutput) || (xmpOutput && jsonOutput)) { System.err.println(Messages.get("output_type_conflict")); return false; } if (path != null) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < path.length(); i++) { if (path.charAt(i) == '\\') { sb.append('/'); } else { sb.append(path.charAt(i)); } } path = sb.toString(); } if (path == null) { if (listChecks) { return true; } else { System.err.println(Messages.get("no_file_specified")); return false; } } else if (path.matches(".+\\.[Ee][Pp][Uu][Bb]")) { if (mode != null || version != EPUBVersion.VERSION_3) { System.err.println(Messages.get("mode_version_ignored")); mode = null; } } else if (mode == null) { outWriter.println(Messages.get("mode_required")); return false; } return true; } private void setCustomMessageFileFromEnvironment() { Map env = System.getenv(); String customMessageFileName = env.get(E_PUB_CHECK_CUSTOM_MESSAGE_FILE); if (customMessageFileName != null && customMessageFileName.length() > 0) { File f = new File(customMessageFileName); if (f.exists()) { customMessageFile = f; useCustomMessageFile = true; } } } /** * This method displays a short help message that describes the command-line * usage of this tool */ private static void displayHelp() { outWriter.println(String.format(Messages.get("help_text"), EpubCheck.version())); } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/tool/Checker.java0000755000175000017500000000252013017276730024361 0ustar eugeneeugene/* * Copyright (c) 2007 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * */ package com.adobe.epubcheck.tool; public class Checker { public static void main(String[] args) { EpubChecker checker = new EpubChecker(); System.exit(checker.run(args)); } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/css/0000755000175000017500000000000013017276730021763 5ustar eugeneeugeneepubcheck-4.0.2/src/main/java/com/adobe/epubcheck/css/CSSChecker.java0000644000175000017500000001252213017276730024545 0ustar eugeneeugene/* * Copyright (c) 2011 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.css; import java.io.IOException; import java.io.InputStream; import java.io.StringReader; import java.util.Locale; import org.idpf.epubcheck.util.css.CssExceptions; import org.idpf.epubcheck.util.css.CssParser; import org.idpf.epubcheck.util.css.CssSource; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.messages.MessageId; import com.adobe.epubcheck.opf.ContentChecker; import com.adobe.epubcheck.opf.ValidationContext; public class CSSChecker implements ContentChecker { private final ValidationContext context; private final Report report; private final String path; // css file path when Mode.FILE, host path when // Mode.STRING private final Mode mode; // Below only used when checking css strings private final String value; // css string private int line; // where css string occurs in host private final boolean isStyleAttribute; private enum Mode { FILE, STRING } /** * Constructor for CSS files. */ public CSSChecker(ValidationContext context) { this(context, Mode.FILE, null, -1, false); } public CSSChecker(ValidationContext context, String value, int line, boolean isStyleAttribute) { this(context, Mode.STRING, value, line, isStyleAttribute); } /** * Constructor for CSS strings (html style attributes and elements) . */ private CSSChecker(ValidationContext context, Mode mode, String value, int line, boolean isStyleAttribute) { this.context = context; this.report = context.report; this.path = context.path; this.mode = mode; this.value = value; this.line = line; this.isStyleAttribute = isStyleAttribute; } public void runChecks() { CssSource source = null; try { if (this.mode == Mode.FILE && !context.ocf.get().hasEntry(path)) { report.message(MessageId.RSC_001, EPUBLocation.create(context.ocf.get().getName()), path); return; } CSSHandler handler = new CSSHandler(path, context.xrefChecker.orNull(), report, context.version); if (this.mode == Mode.STRING && this.line > -1) { handler.setStartingLineNumber(this.line); } source = getCssSource(); parseItem(source, handler); handler.setStartingLineNumber(-1); this.line = -1; } catch (Exception e) { report.message(MessageId.PKG_008, EPUBLocation.create(path), e.getMessage()); } finally { if (source != null) { try { InputStream iStream = source.getInputStream(); if (iStream != null) { iStream.close(); } } catch (IOException ignored) { // eat it } } } } CssSource getCssSource() throws IOException { CssSource source = null; if (this.mode == Mode.FILE) { source = new CssSource(this.path, context.resourceProvider.getInputStream(this.path)); String charset; if (source.getInputStream().getBomCharset().isPresent()) { charset = source.getInputStream().getBomCharset().get().toLowerCase(Locale.ROOT); if (!charset.equals("utf-8") && !charset.startsWith("utf-16")) { report.message(MessageId.CSS_004, EPUBLocation.create(path), charset); } } if (source.getInputStream().getCssCharset().isPresent()) { charset = source.getInputStream().getCssCharset().get().toLowerCase(Locale.ROOT); if (!charset.equals("utf-8") && !charset.startsWith("utf-16")) { report.message(MessageId.CSS_003, EPUBLocation.create(path, ""), charset); } } } return source; } void parseItem(CssSource source, CSSHandler handler) throws IOException, CssExceptions.CssException { if (!isStyleAttribute) { if (this.mode == Mode.FILE) { new CssParser().parse(source, handler, handler); } else { new CssParser().parse(new StringReader(this.value), this.path, handler, handler); } } else { new CssParser() .parseStyleAttribute(new StringReader(this.value), this.path, handler, handler); } } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/css/CSSHandler.java0000644000175000017500000002447313017276730024566 0ustar eugeneeugenepackage com.adobe.epubcheck.css; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.idpf.epubcheck.util.css.CssContentHandler; import org.idpf.epubcheck.util.css.CssErrorHandler; import org.idpf.epubcheck.util.css.CssExceptions.CssException; import org.idpf.epubcheck.util.css.CssGrammar.CssAtRule; import org.idpf.epubcheck.util.css.CssGrammar.CssConstruct; import org.idpf.epubcheck.util.css.CssGrammar.CssDeclaration; import org.idpf.epubcheck.util.css.CssGrammar.CssSelector; import org.idpf.epubcheck.util.css.CssGrammar.CssURI; import org.idpf.epubcheck.util.css.CssLocation; import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.api.Report; import com.adobe.epubcheck.messages.MessageId; import com.adobe.epubcheck.opf.OPFChecker; import com.adobe.epubcheck.opf.OPFChecker30; import com.adobe.epubcheck.opf.XRefChecker; import com.adobe.epubcheck.util.EPUBVersion; import com.adobe.epubcheck.util.FeatureEnum; import com.adobe.epubcheck.util.PathUtil; import com.google.common.base.CharMatcher; public class CSSHandler implements CssContentHandler, CssErrorHandler { final String path; final XRefChecker xrefChecker; final Report report; final EPUBVersion version; int startingLineNumber = 0; //append to line info from css parser int startingColumnNumber = 0; static final CharMatcher SPACE_AND_QUOTES = CharMatcher.anyOf(" \t\n\r\f\"'").precomputed(); //vars for font-face info String fontFamily; String fontStyle; String fontWeight; String fontUri; boolean inFontFace = false; boolean hasFontFaceDeclarations = false; boolean inKeyFrames = false; CssAtRule atRule = null; public CSSHandler(String path, XRefChecker xrefChecker, Report report, EPUBVersion version) { this.path = path; this.xrefChecker = xrefChecker; this.report = report; this.version = version; } private EPUBLocation getCorrectedEPUBLocation(String fileName, int lineNumber, int columnNumber, String context) { lineNumber = correctedLineNumber(lineNumber); columnNumber = correctedColumnNumber(lineNumber, columnNumber); return EPUBLocation.create(fileName, lineNumber, columnNumber, context); } private int correctedLineNumber(int lineNumber) { return startingLineNumber + lineNumber; } private int correctedColumnNumber(int lineNumber, int columnNumber) { if (lineNumber != 0) { return columnNumber; } return startingColumnNumber + columnNumber; } static final Pattern invalidTokenStringFinder = Pattern.compile("Token '[0-9]+%' not allowed here"); @Override public void error(CssException e) throws CssException { String message = e.getMessage(); if (inKeyFrames) { Matcher m = invalidTokenStringFinder.matcher(message); if (m.matches()) { return; } } CssLocation location = e.getLocation(); report.message(MessageId.CSS_008, getCorrectedEPUBLocation(path, location.getLine(), location.getColumn(), null), e.getMessage()); } @Override public void startDocument() { } @Override public void endDocument() { } static final Pattern keyframesPattern = Pattern.compile("@((keyframes)|(-moz-keyframes)|(-webkit-keyframes)|(-o-keyframes))"); @Override public void startAtRule(CssAtRule atRule) { String ruleName = atRule.getName().get(); this.atRule = atRule; if (ruleName.equals("@import")) { CssConstruct uriOrString = atRule.getComponents().get(0); if (uriOrString != null) { int line = uriOrString.getLocation().getLine(); int col = uriOrString.getLocation().getColumn(); String uri = null; if (uriOrString.getType() == CssConstruct.Type.URI) { uri = ((CssURI) uriOrString).toUriString(); } else if (uriOrString.getType() == CssConstruct.Type.STRING) { uri = CharMatcher.anyOf("\"'").trimFrom(uriOrString.toCssString()); } else { //syntax error, url must be first parameter } if (uri != null) { resolveAndRegister(uri, line, col, atRule.toCssString()); } } } else if(atRule.getName().get().equals("@namespace")) { //do not register namespace URIs as resources... } else { //check generically for urls in other atrules registerURIs(atRule.getComponents(), atRule.getLocation().getLine(), atRule.getLocation().getColumn()); } if (ruleName.equals("@font-face")) { inFontFace = true; } else if (keyframesPattern.matcher(ruleName).matches()) { inKeyFrames=true; } } @Override public void endAtRule(String name) { if (inFontFace) { inFontFace = false; handleFontFaceInfo(); if (!hasFontFaceDeclarations) { report.message(MessageId.CSS_019, EPUBLocation.create(path, atRule.getLocation().getLine(), atRule.getLocation().getColumn(), atRule.toCssString())); } hasFontFaceDeclarations = false; } if (inKeyFrames) { inKeyFrames = false; } atRule = null; } @Override public void selectors(List selectors) { } @Override public void endSelectors(List selectors) { } @Override public void declaration(CssDeclaration declaration) { registerURIs(declaration.getComponents(), declaration.getLocation().getLine(), declaration.getLocation().getColumn()); String propertyName = declaration.getName().get(); if (propertyName == null) { return; } if (propertyName.equals("position")) { CssConstruct cns = declaration.getComponents().get(0); if (cns != null) { String value = cns.toCssString(); if (value != null && value.equalsIgnoreCase("fixed")) { report.message(MessageId.CSS_006, getCorrectedEPUBLocation(path, declaration.getLocation().getLine(), declaration.getLocation().getColumn(), declaration.toCssString())); } } } if (version == EPUBVersion.VERSION_3) { if (propertyName.equals("direction") || propertyName.equals("unicode-bidi")) { report.message(MessageId.CSS_001, getCorrectedEPUBLocation(path, declaration.getLocation().getLine(), declaration.getLocation().getColumn(), declaration.toCssString()), propertyName); } } if (inFontFace) { hasFontFaceDeclarations = true; //collect for info if (propertyName.equals("font-family")) { CssConstruct cc = declaration.getComponents().get(0); if (cc != null) { fontFamily = SPACE_AND_QUOTES.trimFrom(cc.toCssString()); } } else if (propertyName.equals("font-style")) { CssConstruct cc = declaration.getComponents().get(0); fontStyle = cc.toCssString(); } else if (propertyName.equals("font-weight")) { CssConstruct cc = declaration.getComponents().get(0); fontWeight = cc.toCssString(); } else if (propertyName.equals("src")) { for (CssConstruct construct : declaration.getComponents()) { if (construct.getType() == CssConstruct.Type.URI) { fontUri = ((CssURI) construct).toUriString(); fontUri = PathUtil.resolveRelativeReference(path, fontUri, null); //check font mimetypes String fontMimeType = xrefChecker.getMimeType(fontUri); if (fontMimeType != null) { boolean blessed = true; if (version == EPUBVersion.VERSION_2) { blessed = OPFChecker.isBlessedFontMimetype20(fontMimeType); } else if (version == EPUBVersion.VERSION_3) { blessed = OPFChecker30.isBlessedFontType(fontMimeType); } if (!blessed) { report.message(MessageId.CSS_007, getCorrectedEPUBLocation(path, declaration.getLocation().getLine(), declaration.getLocation().getColumn(), declaration.toCssString()), fontUri, fontMimeType); } } else { //errors sb reported elsewhere } } } } report.message(MessageId.CSS_028, getCorrectedEPUBLocation(path, declaration.getLocation().getLine(), declaration.getLocation().getColumn(), fontUri != null ? fontUri : "null") ); } } private void registerURIs(List constructs, int line, int col) { for (CssConstruct construct : constructs) { if (construct.getType() == CssConstruct.Type.URI) { resolveAndRegister(((CssURI) construct).toUriString(), line, col, construct.toCssString()); } } } private void resolveAndRegister(String relativeRef, int line, int col, String context) { if (relativeRef != null && relativeRef.trim().length() > 0) { String resolved = PathUtil.resolveRelativeReference(path, relativeRef, null); xrefChecker.registerReference(path, line + startingLineNumber, col, resolved, XRefChecker.Type.GENERIC); } else { report.message(MessageId.CSS_002,getCorrectedEPUBLocation(path, line, col, context)); } } private void handleFontFaceInfo() { if (fontFamily != null) { if (fontUri != null && !fontUri.startsWith("http")) { report.info(path, FeatureEnum.FONT_EMBEDDED, fontFamily + (((fontStyle != null) && !"normal".equalsIgnoreCase(fontStyle)) ? "," + fontStyle : "") + (((fontWeight != null) && !"normal".equalsIgnoreCase(fontWeight)) ? "," + fontWeight : "") ); } else { report.info(path, FeatureEnum.FONT_REFERENCE, fontFamily + (((fontStyle != null) && !"normal".equalsIgnoreCase(fontStyle)) ? "," + fontStyle : "") + (((fontWeight != null) && !"normal".equalsIgnoreCase(fontWeight)) ? "," + fontWeight : "") ); report.info(path, FeatureEnum.REFERENCE, fontUri); } } } public void setStartingLineNumber(int offset) { this.startingLineNumber = offset - 1; if (this.startingLineNumber < 0) { this.startingLineNumber = 0; } } } epubcheck-4.0.2/src/main/java/com/adobe/epubcheck/css/CSSCheckerFactory.java0000644000175000017500000000431713017276730026100 0ustar eugeneeugene/* * Copyright (c) 2011 Adobe Systems Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.adobe.epubcheck.css; import com.adobe.epubcheck.opf.ContentChecker; import com.adobe.epubcheck.opf.ValidationContext; import com.adobe.epubcheck.opf.ContentCheckerFactory; public class CSSCheckerFactory implements ContentCheckerFactory { /* * (non-Javadoc) * @see com.adobe.epubcheck.opf.ContentCheckerFactory#newInstance(com.adobe.epubcheck.ocf.OCFPackage, com.adobe.epubcheck.api.Report, java.lang.String, java.lang.String, java.lang.String, com.adobe.epubcheck.opf.XRefChecker, com.adobe.epubcheck.util.EPUBVersion) */ public ContentChecker newInstance(ValidationContext context) { return new CSSChecker(context); } /** * Additional constructor for validating CSS strings (style attributes and elements) */ public ContentChecker newInstance(ValidationContext context, String value, int line, boolean isStyleAttribute) { return new CSSChecker(context, value, line, isStyleAttribute); } static private final CSSCheckerFactory instance = new CSSCheckerFactory(); static public CSSCheckerFactory getInstance() { return instance; } } epubcheck-4.0.2/src/main/util/0000755000175000017500000000000013017276730015446 5ustar eugeneeugeneepubcheck-4.0.2/src/main/util/sch/0000755000175000017500000000000013017276730016223 5ustar eugeneeugeneepubcheck-4.0.2/src/main/util/sch/iso-sch-include.xsl0000644000175000017500000000716413017276730021751 0ustar eugeneeugene Unable to open referenced included file: Invalid href attribute value for include: Unable to open referenced included file: The Schematron include should not point to a schema element, it should point to an element that is valid when it replaces the include: Invalid empty href attribute value for include. epubcheck-4.0.2/src/main/util/sch/iso-sch-abstract.xsl0000644000175000017500000000714113017276730022124 0ustar eugeneeugene Cannot find abstract pattern referred from pattern . More than one definitions for abstract pattern referred from pattern . epubcheck-4.0.2/src/main/scripts/0000755000175000017500000000000013017276730016160 5ustar eugeneeugeneepubcheck-4.0.2/src/main/scripts/epubcheck.sh0000644000175000017500000000040313017276730020442 0ustar eugeneeugene#!/bin/bash # If JAVA_HOME is not set, use the java in the execution path if [ -z "$JAVA_HOME" ] ; then JAVA=java else JAVA="$JAVA_HOME/bin/java" fi EPUBCHECK_HOME=$(dirname "$0") "${JAVA}" -jar "$EPUBCHECK_HOME/epubcheck-${project.version}.jar" "$@" epubcheck-4.0.2/src/main/scripts/epubcheck.bat0000644000175000017500000000060113017276730020576 0ustar eugeneeugene@ECHO OFF REM If JAVA_HOME is not set, use the java in the execution path if "%JAVA_HOME%" == "" ( set JAVA=java ) else ( set JAVA="%JAVA_HOME%\bin\java" ) SET EPUBCHECK_HOME=%~dp0 REM Loop to read all the arguments SET ARGS= :WHILE IF "%1"=="" GOTO LOOP SET ARGS=%ARGS% %1 SHIFT GOTO WHILE :LOOP "%JAVA%" -jar "%EPUBCHECK_HOME%\epubcheck-${project.version}.jar" %ARGS% epubcheck-4.0.2/src/main/resources/0000755000175000017500000000000013017276730016503 5ustar eugeneeugeneepubcheck-4.0.2/src/main/resources/org/0000755000175000017500000000000013017276730017272 5ustar eugeneeugeneepubcheck-4.0.2/src/main/resources/org/idpf/0000755000175000017500000000000013017276730020214 5ustar eugeneeugeneepubcheck-4.0.2/src/main/resources/org/idpf/epubcheck/0000755000175000017500000000000013017276730022145 5ustar eugeneeugeneepubcheck-4.0.2/src/main/resources/org/idpf/epubcheck/util/0000755000175000017500000000000013017276730023122 5ustar eugeneeugeneepubcheck-4.0.2/src/main/resources/org/idpf/epubcheck/util/css/0000755000175000017500000000000013017276730023712 5ustar eugeneeugeneepubcheck-4.0.2/src/main/resources/org/idpf/epubcheck/util/css/messages_de.properties0000644000175000017500000000215013017276730030305 0ustar eugeneeugenecss.scanner.token.syntax=Ungültige Syntax syntax "{0}" css.scanner.token.syntax.char=Das Zeichen "{0}" ist in folgendem Ausdruck nicht erlaubt: "{1}" css.scanner.token.syntax.firstChar=Das Zeichen "{0}" ist an erster Stelle des folgenden Ausdrucks nicht erlaubt: "{1}" css.scanner.token.syntax.escape=Ungültige Escape-Sequenz "{0}" css.scanner.token.syntax.urange=Ungültiger Unicode-Bereich-Ausdruck "{0}" css.scanner.prematureEOF=Vorzeitiges Ende der CSS-Datei. css.grammar.prematureEOF=Vorzeitiges Ende der CSS-Datei. Erwartet wird {0} css.grammar.token.unexpected=Die Zeichenkette "{0}" ist an dieser Stelle nicht erlaubt. css.grammar.token.expecting=Die Zeichenkette "{0}" ist an dieser Stelle nicht erlaubt. Erwartet wird {1} css.grammar.invalidSelector=Ungültiger Selektor: "{0}" or=oder a_property_name=eine CSS-Eigenschaft a_property_value=ein Eigenschaftswert a_type_or_universal_selector=ein Typ- oder Universal-Selektor a_string_or_dentifier=ein String oder eine ID an_attribute_value_matcher=ein Ausdruck der auf den Attributwert matcht negation_arguments=Argumente der not()-Funktion a_selectors=ein Selektor epubcheck-4.0.2/src/main/resources/org/idpf/epubcheck/util/css/messages_it.properties0000644000175000017500000000210713017276730030333 0ustar eugeneeugenecss.scanner.token.syntax=Sintassi non valida ''{0}'' css.scanner.token.syntax.char=Il carattere ''{0}'' non è consentito in espressioni ''{1}'' css.scanner.token.syntax.firstChar=Il carattere ''{0}'' non è consentito come primo carattere di espressioni ''{1}'' css.scanner.token.syntax.escape=Sequenza di escape non valida ''{0}'' css.scanner.token.syntax.urange=Intervallo Unicode non valido ''{0}'' css.scanner.prematureEOF=Fine prematura del file css.grammar.prematureEOF=Fine prematura della grammatica (atteso: {0}) css.grammar.token.unexpected=Parola ''{0}'' non consentita in questo punto css.grammar.token.expecting=Parola ''{0}'' non consentita in questo punto, (attesa: {1}) css.grammar.invalidSelector=Selettore non valido: ''{0}'' or=o a_property_name=un nome di proprietà a_property_value=un valore di proprietà a_type_or_universal_selector=un tipo o un selettore universale a_string_or_dentifier=una stringa o un identificatore an_attribute_value_matcher=un simbolo di valore di attributo negation_arguments=argomenti per una funzione di negazione a_selectors=un selettore epubcheck-4.0.2/src/main/resources/org/idpf/epubcheck/util/css/messages_es.properties0000644000175000017500000000212713017276730030330 0ustar eugeneeugenecss.scanner.token.syntax=Sintaxis no válida ''{0}'' css.scanner.token.syntax.char=El carácter ''{0}'' no está permitido en expresiones ''{1}'' css.scanner.token.syntax.firstChar=El carácter ''{0}'' no está permitido como primer carácter en expresiones ''{1}'' css.scanner.token.syntax.escape=Secuencia de salida no válida ''{0}'' css.scanner.token.syntax.urange=Expresión de rango unicode no válida ''{0}'' css.scanner.prematureEOF=Final de archivo anticipado css.grammar.prematureEOF=Final de gramática anticipado (se esperaba: {0}) css.grammar.token.unexpected=El token ''{0}'' no está permitido aquí css.grammar.token.expecting=El token ''{0}'' no está permitido aquí; se esperaba {1} css.grammar.invalidSelector=Selector no válido: ''{0}'' or=o a_property_name=un nombre de propiedad a_property_value=un valor de propiedad a_type_or_universal_selector=un selector de tipo o universal a_string_or_dentifier=una cadena o un identificador an_attribute_value_matcher=un valor de atributo que concuerde con el símbolo negation_arguments=argumentos de función negativa a_selectors=un selector epubcheck-4.0.2/src/main/resources/org/idpf/epubcheck/util/css/messages.properties0000644000175000017500000000175513017276730027647 0ustar eugeneeugenecss.scanner.token.syntax=Invalid syntax ''{0}'' css.scanner.token.syntax.char=The character ''{0}'' is not allowed in ''{1}'' expressions css.scanner.token.syntax.firstChar=The character ''{0}'' is not allowed as the first character in ''{1}'' expressions css.scanner.token.syntax.escape=Invalid escape sequence ''{0}'' css.scanner.token.syntax.urange=Invalid unicode range expression ''{0}'' css.scanner.prematureEOF=Premature end of file css.grammar.prematureEOF=Premature end of grammar (expecting: {0}) css.grammar.token.unexpected=Token ''{0}'' not allowed here css.grammar.token.expecting=Token ''{0}'' not allowed here, expecting {1} css.grammar.invalidSelector=Invalid selector: ''{0}'' or=or a_property_name=a property name a_property_value=a property value a_type_or_universal_selector=a type or universal selector a_string_or_dentifier=a string or an identifier an_attribute_value_matcher=an attribute value match symbol negation_arguments=negation function arguments a_selectors=a selector epubcheck-4.0.2/src/main/resources/org/idpf/epubcheck/util/css/messages_fr.properties0000644000175000017500000000220513017276730030325 0ustar eugeneeugenecss.scanner.token.syntax=Syntaxe non valide "{0}" css.scanner.token.syntax.char=Le caractère "{0}" n'est pas autorisé dans les expressions "{1}" css.scanner.token.syntax.firstChar=Le caractère "{0}" n'est pas autorisé comme premier caractère dans les expressions "{1}" css.scanner.token.syntax.escape=Séquence d'échappement non valide "{0}" css.scanner.token.syntax.urange=Expression de séquence Unicode non valide "{0}" css.scanner.prematureEOF=Fin de fichier prématurée css.grammar.prematureEOF=Fin de grammaire prématurée (attendu: {0}) css.grammar.token.unexpected=Le token "{0}" n'est pas autorisé à cet endroit css.grammar.token.expecting=Le token "{0}" n'est pas autorisé à cet endroit, {1} attendu css.grammar.invalidSelector=Sélecteur non valide: "{0}" or=ou a_property_name=un nom de propriété a_property_value=une valeur de propriété a_type_or_universal_selector=un type ou sélecteur universel a_string_or_dentifier=une chaîne de caractère ou un identificateur an_attribute_value_matcher=un symbole de concordance de valeur d'attribut negation_arguments=des arguments de fonction de négation a_selectors=un sélecteur epubcheck-4.0.2/src/main/resources/org/idpf/epubcheck/util/css/messages_nl.properties0000644000175000017500000000210113017276730030322 0ustar eugeneeugenecss.scanner.token.syntax=Ongeldige syntaxis "{0}" css.scanner.token.syntax.char=Karakter "{0}" is niet toegestaan in "{1}" expressies css.scanner.token.syntax.firstChar=Karakter "{0}" is niet toegestaan als eerste karakter in "{1}" expressies css.scanner.token.syntax.escape=Ongeldige escapevolgorde "{0}" css.scanner.token.syntax.urange=Ongeldige unicode bereiksexpressie "{0}" css.scanner.prematureEOF=Onverwacht einde van het bestand css.grammar.prematureEOF=Onverwacht einde van de grammatica (verwacht werd: "{0}") css.grammar.token.unexpected=Token "{0}" is hier niet toegestaan css.grammar.token.expecting=Token "{0}" is hier niet toegestaan, {1} werd verwacht css.grammar.invalidSelector=Ongeldige selector: "{0}" or=of a_property_name=de naam van een eigenschap a_property_value=de waarde van een eigenschap a_type_or_universal_selector=een type of een universele selector a_string_or_dentifier=een string of een identifier an_attribute_value_matcher=een symbool dat een attribuut aan een waarde koppelt negation_arguments=ontkennende functieargumenten a_selectors=een selector epubcheck-4.0.2/src/main/resources/org/idpf/epubcheck/util/css/messages_ja.properties0000644000175000017500000000232713017276730030315 0ustar eugeneeugenecss.scanner.token.syntax=不正な構文 ''{0}'' があります. css.scanner.token.syntax.char=文字 ''{0}'' は、式 ''{1}'' 内では使用できません. css.scanner.token.syntax.firstChar=文字 ''{0}'' は、式 ''{1}'' の最初の文字としては使用できません. css.scanner.token.syntax.escape=不正なエスケープシーケンス ''{0}'' があります. css.scanner.token.syntax.urange=不正なユニコード範囲式 ''{0}'' があります. css.scanner.prematureEOF=ファイルが途中で終わっています. css.grammar.prematureEOF=構文が途中で終わっています ({0} がありません) css.grammar.token.unexpected=トークン ''{0}'' はここでは使用できません. css.grammar.token.expecting={1} がありません. トークン ''{0}'' はここでは使用できません. css.grammar.invalidSelector=不正なセレクタ ''{0}'' があります. or=または a_property_name=プロパティ名 a_property_value=プロパティ値 a_type_or_universal_selector=要素型 または 全称セレクタ a_string_or_dentifier=文字列 または 識別子 an_attribute_value_matcher=属性値比較演算子 negation_arguments=否定疑似クラスの引数 a_selectors=セレクタ epubcheck-4.0.2/src/main/resources/com/0000755000175000017500000000000013017276730017261 5ustar eugeneeugeneepubcheck-4.0.2/src/main/resources/com/thaiopensource/0000755000175000017500000000000013017276730022311 5ustar eugeneeugeneepubcheck-4.0.2/src/main/resources/com/thaiopensource/relaxng/0000755000175000017500000000000013017276730023751 5ustar eugeneeugeneepubcheck-4.0.2/src/main/resources/com/thaiopensource/relaxng/pattern/0000755000175000017500000000000013017276730025426 5ustar eugeneeugeneepubcheck-4.0.2/src/main/resources/com/thaiopensource/relaxng/pattern/resources/0000755000175000017500000000000013017276730027440 5ustar eugeneeugeneepubcheck-4.0.2/src/main/resources/com/thaiopensource/relaxng/pattern/resources/Messages.properties0000644000175000017500000002747613017276730033345 0ustar eugeneeugene# First two blocks doesn't need to be translated for epubcheck, as @murata0204 noted in # https://github.com/IDPF/epubcheck/pull/472#issuecomment-58265808 # # Non-unicode chars (german umlauts, etc..) must be escaped like \u00DF # because otherwise Jing can't parse them. Bad UTF8-support # Properties file specifying messages illegal_href_attribute=illegal \"href\" attribute ns_attribute_ignored=\"ns\" attribute ignored reference_to_undefined=reference to undefined pattern \"{0}\" missing_start_element=missing \"start\" element recursive_reference=bad recursive reference to pattern \"{0}\" recursive_include=recursive inclusion of URL \"{0}\" duplicate_define=multiple definitions of \"{0}\" without \"combine\" attribute duplicate_start=multiple definitions of start without \"combine\" attribute conflict_combine_define=conflicting values of \"combine\" attribute for definition of \"{0}\" conflict_combine_start=conflicting values of \"combine\" attribute for definition of start missing_start_replacement=\"start\" in \"include\" does not override anything missing_define_replacement=definition of \"{0}\" in \"include\" does not override anything interleave_string=interleave of \"string\" or \"data\" element group_string=group of \"string\" or \"data\" element one_or_more_string=repeat of \"string\" or \"data\" element unrecognized_datatype=datatype \"{1}\" from library \"{0}\" not recognized unsupported_datatype_detail=datatype \"{1}\" from library \"{0}\" not supported: {2} unrecognized_datatype_library=datatype library \"{0}\" not recognized unrecognized_builtin_datatype=no such builtin datatype \"{0}\": must be \"string\" or \"token\" invalid_value=\"{0}\" is not a valid value of the datatype parent_ref_outside_grammar=reference to non-existent parent grammar ref_outside_grammar=reference to non-existent grammar expected_one_name_class=found \"{0}\" element but expected no further content builtin_param=builtin datatypes do not have any parameters invalid_param_display=invalid parameter:\n{0} invalid_param_detail_display=invalid parameter: {0}:\n{1} display_param={0}>>>>{1} invalid_param_detail=invalid parameter: {0} invalid_param=invalid parameter invalid_params_detail=invalid parameters: {0} invalid_params=invalid parameters datatype_requires_parameter=datatype cannot be used without parameters datatype_requires_parameter_detail=datatype cannot be used without parameters: {0} attribute_contains_attribute=an attribute pattern must not contain an attribute pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path attribute//attribute) attribute_contains_element=an attribute pattern must not contain an element pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path attribute//ref) data_except_contains_attribute=a data pattern must not exclude an attribute pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path data/except//attribute) data_except_contains_element=a data pattern must not exclude an element pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path data/except//ref) data_except_contains_empty=a data pattern must not exclude an empty pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path data/except//empty) data_except_contains_group=a data pattern must not exclude a group (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path data/except//group) data_except_contains_interleave=a data pattern must not exclude an interleaved group (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path data/except//interleave) data_except_contains_list=a data pattern must not exclude a list pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path data/except//list) data_except_contains_one_or_more=a data pattern must not exclude a repetition (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path data/except//oneOrMore) data_except_contains_text=a data pattern must not exclude a text pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path data/except//text) list_contains_attribute=a list pattern must not contain an attribute pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path list//attribute) list_contains_element=a list pattern must not contain an element pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path list//ref) list_contains_list=a list pattern must not contain a list pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path list//list) list_contains_text=a list pattern must not contain a text pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path list//text) list_contains_interleave=a list pattern must not contain an interleave pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path list//interleave) one_or_more_contains_group_contains_attribute=a group of attributes must not be repeatable (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path oneOrMore//group//attribute) one_or_more_contains_interleave_contains_attribute=an interleaved group of attributes must not be repeatable (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path oneOrMore//interleave//attribute) start_contains_attribute=found element matching the prohibited path start//attribute in the simplified XML form of the schema (see section 7.1 of the RELAX NG specification) start_contains_data=found element matching the prohibited path start//data in the simplified XML form of the schema (see section 7.1 of the RELAX NG specification) start_contains_empty=found element matching the prohibited path start//empty in the simplified XML form of the schema (see section 7.1 of the RELAX NG specification) start_contains_group=found element matching the prohibited path start//group in the simplified XML form of the schema (see section 7.1 of the RELAX NG specification) start_contains_interleave=found element matching the prohibited path start//interleave in the simplified XML form of the schema (see section 7.1 of the RELAX NG specification) start_contains_list=found element matching the prohibited path start//list in the simplified XML form of the schema (see section 7.1 of the RELAX NG specification) start_contains_one_or_more=found element matching the prohibited path start//oneOrMore in the simplified XML form of the schema (see section 7.1 of the RELAX NG specification) start_contains_text=found element matching the prohibited path start//text in the simplified XML form of the schema (see section 7.1 of the RELAX NG specification) start_contains_value=found element matching the prohibited path start//value in the simplified XML form of the schema (see section 7.1 of the RELAX NG specification) duplicate_attribute=duplicate attribute duplicate_attribute_name=duplicate attribute {0} duplicate_attribute_ns=attributes from namespace \"{0}\" can occur more than once interleave_element_overlap=overlapping element names in operands of \"interleave\" interleave_element_overlap_name=the element {0} can occur in more than one operand of \"interleave\" interleave_element_overlap_ns=elements from namespace \"{0}\" can occur in more than one operand of \"interleave\" interleave_text_overlap=both operands of \"interleave\" contain \"text\" open_name_class_not_repeated=attribute using \"nsName\" or \"anyName\" must be in \"oneOrMore\" xmlns_uri_attribute=attribute must not have namespace URI \"http://www.w3.org/2000/xmlns\" xmlns_attribute=attribute must not be named \"xmlns\" # Validation errors unknown_element=element {0} not allowed anywhere{1} unexpected_element_required_element_missing=element {0} not allowed yet; missing required element {1} unexpected_element_required_elements_missing=element {0} not allowed yet; missing required elements {1} element_not_allowed_yet=element {0} not allowed yet{1} out_of_context_element=element {0} not allowed here{1} no_attributes_allowed=found attribute {0}, but no attributes allowed here invalid_attribute_name=attribute {0} not allowed here{1} invalid_attribute_value=value of attribute {0} is invalid{1} required_attributes_missing_expected=element {0} missing one or more required attributes{1} required_attribute_missing=element {0} missing required attribute {1} required_attributes_missing=element {0} missing required attributes {1} incomplete_element_required_elements_missing_expected=element {0} incomplete{1} incomplete_element_required_element_missing=element {0} incomplete; missing required element {1} incomplete_element_required_elements_missing=element {0} incomplete; missing required elements {1} text_not_allowed=text not allowed here{0} document_incomplete=document incompletely matched invalid_element_value=character content of element {0} invalid{1} blank_not_allowed=empty content for element {0} not allowed{1} schema_allows_nothing=schema does not allow anything: it is equivalent to # ID correctness errors id_element_name_class=an \"element\" pattern containing an \"attribute\" pattern with a non-null ID-type must have a name class that contains only \"choice\" and \"name\" elements id_attribute_name_class=an \"attribute\" pattern with a non-null ID-type must have a name class that is a single name id_parent=a \"data\" or \"value\" pattern with non-null ID-type must occur as the child of an \"attribute\" pattern id_type_conflict=conflicting ID-types for attribute {1} of element {0} # ID soundness errors id_no_tokens=value of attribute of type ID contained no tokens id_multiple_tokens=value of attribute of type ID contained multiple tokens idref_no_tokens=value of attribute of type IDREF contained no tokens idref_multiple_tokens=value of attribute of type IDREF contained multiple tokens idrefs_no_tokens=value of attribute of type IDREFS contained no tokens missing_id=IDREF \"{0}\" without matching ID duplicate_id=ID \"{0}\" has already been defined first_id=first occurrence of ID \"{0}\" # Fragments name_absent_namespace=\"{0}\" name_with_namespace=\"{1}\" from namespace \"{0}\" qname=\"{0}\" qnames_nsdecls={0} (with {1}) or_list_pair={0} or {1} or_list_many_first={0} or_list_many_middle={0}, {1} or_list_many_last={0} or {1} and_list_pair={0} and {1} and_list_many_first={0} and_list_many_middle={0}, {1} and_list_many_last={0} and {1} expected=; expected {0} element_end_tag=the element end-tag text=text data=data element_list=element {0} element_other_ns=an element from another namespace expected_attribute=; expected attribute {0} expected_attribute_or_other_ns=; expected attribute {0} or an attribute from another namespace data_failures=; {0} token_failures=; token {0} invalid; {1} missing_token=; missing token; {0} expected_data=; expected data require_values=must be equal to {0} require_qnames=must be a QName equal to {0} require_datatype=must be a valid instance of datatype {0} ././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootepubcheck-4.0.2/src/main/resources/com/thaiopensource/relaxng/pattern/resources/Messages_ja.propertiesepubcheck-4.0.2/src/main/resources/com/thaiopensource/relaxng/pattern/resources/Messages_ja.properti0000644000175000017500000003527513017276730033463 0ustar eugeneeugene# First two blocks doesn't need to be translated for epubcheck, as @murata0204 noted in # https://github.com/IDPF/epubcheck/pull/472#issuecomment-58265808 # # Non-unicode chars (german umlauts, etc..) must be escaped like \u00DF # because otherwise Jing can't parse them. Bad UTF8-support # Properties file specifying messages illegal_href_attribute=illegal \"href\" attribute ns_attribute_ignored=\"ns\" attribute ignored reference_to_undefined=reference to undefined pattern \"{0}\" missing_start_element=missing \"start\" element recursive_reference=bad recursive reference to pattern \"{0}\" recursive_include=recursive inclusion of URL \"{0}\" duplicate_define=multiple definitions of \"{0}\" without \"combine\" attribute duplicate_start=multiple definitions of start without \"combine\" attribute conflict_combine_define=conflicting values of \"combine\" attribute for definition of \"{0}\" conflict_combine_start=conflicting values of \"combine\" attribute for definition of start missing_start_replacement=\"start\" in \"include\" does not override anything missing_define_replacement=definition of \"{0}\" in \"include\" does not override anything interleave_string=interleave of \"string\" or \"data\" element group_string=group of \"string\" or \"data\" element one_or_more_string=repeat of \"string\" or \"data\" element unrecognized_datatype=datatype \"{1}\" from library \"{0}\" not recognized unsupported_datatype_detail=datatype \"{1}\" from library \"{0}\" not supported: {2} unrecognized_datatype_library=datatype library \"{0}\" not recognized unrecognized_builtin_datatype=no such builtin datatype \"{0}\": must be \"string\" or \"token\" invalid_value=\"{0}\" is not a valid value of the datatype parent_ref_outside_grammar=reference to non-existent parent grammar ref_outside_grammar=reference to non-existent grammar expected_one_name_class=found \"{0}\" element but expected no further content builtin_param=builtin datatypes do not have any parameters invalid_param_display=invalid parameter:\n{0} invalid_param_detail_display=invalid parameter: {0}:\n{1} display_param={0}>>>>{1} invalid_param_detail=invalid parameter: {0} invalid_param=invalid parameter invalid_params_detail=invalid parameters: {0} invalid_params=invalid parameters datatype_requires_parameter=datatype cannot be used without parameters datatype_requires_parameter_detail=datatype cannot be used without parameters: {0} attribute_contains_attribute=an attribute pattern must not contain an attribute pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path attribute//attribute) attribute_contains_element=an attribute pattern must not contain an element pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path attribute//ref) data_except_contains_attribute=a data pattern must not exclude an attribute pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path data/except//attribute) data_except_contains_element=a data pattern must not exclude an element pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path data/except//ref) data_except_contains_empty=a data pattern must not exclude an empty pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path data/except//empty) data_except_contains_group=a data pattern must not exclude a group (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path data/except//group) data_except_contains_interleave=a data pattern must not exclude an interleaved group (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path data/except//interleave) data_except_contains_list=a data pattern must not exclude a list pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path data/except//list) data_except_contains_one_or_more=a data pattern must not exclude a repetition (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path data/except//oneOrMore) data_except_contains_text=a data pattern must not exclude a text pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path data/except//text) list_contains_attribute=a list pattern must not contain an attribute pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path list//attribute) list_contains_element=a list pattern must not contain an element pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path list//ref) list_contains_list=a list pattern must not contain a list pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path list//list) list_contains_text=a list pattern must not contain a text pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path list//text) list_contains_interleave=a list pattern must not contain an interleave pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path list//interleave) one_or_more_contains_group_contains_attribute=a group of attributes must not be repeatable (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path oneOrMore//group//attribute) one_or_more_contains_interleave_contains_attribute=an interleaved group of attributes must not be repeatable (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path oneOrMore//interleave//attribute) start_contains_attribute=found element matching the prohibited path start//attribute in the simplified XML form of the schema (see section 7.1 of the RELAX NG specification) start_contains_data=found element matching the prohibited path start//data in the simplified XML form of the schema (see section 7.1 of the RELAX NG specification) start_contains_empty=found element matching the prohibited path start//empty in the simplified XML form of the schema (see section 7.1 of the RELAX NG specification) start_contains_group=found element matching the prohibited path start//group in the simplified XML form of the schema (see section 7.1 of the RELAX NG specification) start_contains_interleave=found element matching the prohibited path start//interleave in the simplified XML form of the schema (see section 7.1 of the RELAX NG specification) start_contains_list=found element matching the prohibited path start//list in the simplified XML form of the schema (see section 7.1 of the RELAX NG specification) start_contains_one_or_more=found element matching the prohibited path start//oneOrMore in the simplified XML form of the schema (see section 7.1 of the RELAX NG specification) start_contains_text=found element matching the prohibited path start//text in the simplified XML form of the schema (see section 7.1 of the RELAX NG specification) start_contains_value=found element matching the prohibited path start//value in the simplified XML form of the schema (see section 7.1 of the RELAX NG specification) duplicate_attribute=duplicate attribute duplicate_attribute_name=duplicate attribute {0} duplicate_attribute_ns=attributes from namespace \"{0}\" can occur more than once interleave_element_overlap=overlapping element names in operands of \"interleave\" interleave_element_overlap_name=the element {0} can occur in more than one operand of \"interleave\" interleave_element_overlap_ns=elements from namespace \"{0}\" can occur in more than one operand of \"interleave\" interleave_text_overlap=both operands of \"interleave\" contain \"text\" open_name_class_not_repeated=attribute using \"nsName\" or \"anyName\" must be in \"oneOrMore\" xmlns_uri_attribute=attribute must not have namespace URI \"http://www.w3.org/2000/xmlns\" xmlns_attribute=attribute must not be named \"xmlns\" # Validation errors unknown_element=\u8981\u7D20 {0} \u306F\u3069\u3053\u306B\u3082\u66F8\u3051\u307E\u305B\u3093. {1} unexpected_element_required_element_missing=\u8981\u7D20 {0} \u306F\u3053\u3053\u306B\u306F\u66F8\u3051\u307E\u305B\u3093. \u624B\u524D\u306B\u4EE5\u4E0B\u306E\u8981\u7D20\u304C\u5FC5\u8981\u3067\u3059: {1} unexpected_element_required_elements_missing=\u8981\u7D20 {0} \u306F\u3053\u3053\u306B\u306F\u66F8\u3051\u307E\u305B\u3093. \u624B\u524D\u306B\u4EE5\u4E0B\u306E\u8981\u7D20\u304C\u5FC5\u8981\u3067\u3059: {1} element_not_allowed_yet=\u8981\u7D20 {0} \u306F\u307E\u3060\u3053\u3053\u306B\u306F\u66F8\u3051\u307E\u305B\u3093. {1} out_of_context_element=\u8981\u7D20 {0} \u3092\u3053\u3053\u306B\u66F8\u3044\u3066\u306F\u3044\u3051\u307E\u305B\u3093. {1} no_attributes_allowed=\u5C5E\u6027 {0} \u304C\u66F8\u304B\u308C\u3066\u3044\u307E\u3059\u304C\u3001\u3053\u3053\u306B\u306F\u5C5E\u6027\u306F\u66F8\u3051\u307E\u305B\u3093. invalid_attribute_name=\u5C5E\u6027 {0} \u306F\u3053\u3053\u306B\u306F\u66F8\u3051\u307E\u305B\u3093. {1} invalid_attribute_value=\u5C5E\u6027 {0} \u306E\u5024\u304C\u4E0D\u6B63\u3067\u3059. {1} required_attributes_missing_expected=\u8981\u7D20 {0} \u306B\u306F1\u3064\u307E\u305F\u306F\u305D\u308C\u4EE5\u4E0A\u306E\u5FC5\u8981\u306A\u5C5E\u6027\u304C\u66F8\u304B\u308C\u3066\u3044\u307E\u305B\u3093. {1} required_attribute_missing=\u8981\u7D20 {0} \u306B\u5FC5\u8981\u306A\u5C5E\u6027\u304C\u66F8\u304B\u308C\u3066\u3044\u307E\u305B\u3093. {1} required_attributes_missing=\u8981\u7D20 {0} \u306B\u5FC5\u8981\u306A\u5C5E\u6027\u304C\u66F8\u304B\u308C\u3066\u3044\u307E\u305B\u3093. {1} incomplete_element_required_elements_missing_expected=\u8981\u7D20 {0} \u306E\u5185\u5BB9\u304C\u4E0D\u5B8C\u5168\u3067\u3059. {1} incomplete_element_required_element_missing=\u8981\u7D20 {0} \u306E\u5185\u5BB9\u304C\u4E0D\u5B8C\u5168\u3067\u3059. \u4EE5\u4E0B\u306E\u5FC5\u8981\u306A\u8981\u7D20\u304C\u66F8\u304B\u308C\u3066\u3044\u307E\u305B\u3093 {1} incomplete_element_required_elements_missing=\u8981\u7D20 {0} \u306E\u5185\u5BB9\u304C\u4E0D\u5B8C\u5168\u3067\u3059. \u4EE5\u4E0B\u306E\u5FC5\u8981\u306A\u8981\u7D20\u304C\u66F8\u304B\u308C\u3066\u3044\u307E\u305B\u3093 {1} text_not_allowed=\u30C6\u30AD\u30B9\u30C8\u306F\u3053\u3053\u306B\u306F\u66F8\u3051\u307E\u305B\u3093. {0} document_incomplete=\u6587\u66F8\u304C\u4E0D\u5B8C\u5168\u306B\u30DE\u30C3\u30C1\u3057\u3066\u3044\u307E\u3059. invalid_element_value=\u8981\u7D20 {0} \u306E\u30C6\u30AD\u30B9\u30C8\u5185\u5BB9\u304C\u4E0D\u6B63\u3067\u3059. {1} blank_not_allowed=\u8981\u7D20 {0} \u306F\u7A7A\u306E\u5185\u5BB9\u306B\u3057\u3066\u306F\u3044\u3051\u307E\u305B\u3093. {1} schema_allows_nothing=\u6587\u66F8\u306B\u4F55\u3082\u66F8\u3044\u3066\u306F\u3044\u3051\u307E\u305B\u3093. \u30B9\u30AD\u30FC\u30DE\u304C\u305D\u306E\u3088\u3046\u306B\u5B9A\u7FA9\u3055\u308C\u3066\u3044\u307E\u3059( \u304C\u66F8\u304B\u308C\u3066\u3044\u308B\u30B9\u30AD\u30FC\u30DE\u3068\u540C\u5024\u3067\u3059). # ID correctness errors id_element_name_class=an \"element\" pattern containing an \"attribute\" pattern with a non-null ID-type must have a name class that contains only \"choice\" and \"name\" elements id_attribute_name_class=an \"attribute\" pattern with a non-null ID-type must have a name class that is a single name id_parent=a \"data\" or \"value\" pattern with non-null ID-type must occur as the child of an \"attribute\" pattern id_type_conflict=conflicting ID-types for attribute {1} of element {0} # ID soundness errors id_no_tokens=ID\u578B\u5C5E\u6027\u306E\u5024\u306B\u30C8\u30FC\u30AF\u30F3\u304C\u542B\u307E\u308C\u3066\u3044\u307E\u305B\u3093. id_multiple_tokens=ID\u578B\u5C5E\u6027\u306E\u5024\u306B\u8907\u6570\u306E\u30C8\u30FC\u30AF\u30F3\u304C\u542B\u307E\u308C\u3066\u3044\u307E\u3059. idref_no_tokens=IDREF\u578B\u5C5E\u6027\u306E\u5024\u306B\u30C8\u30FC\u30AF\u30F3\u304C\u542B\u307E\u308C\u3066\u3044\u307E\u305B\u3093. idref_multiple_tokens=IDREF\u578B\u5C5E\u6027\u306E\u5024\u306B\u8907\u6570\u306E\u30C8\u30FC\u30AF\u30F3\u304C\u542B\u307E\u308C\u3066\u3044\u307E\u3059. idrefs_no_tokens=IDREFS\u578B\u5C5E\u6027\u306E\u5024\u306B\u30C8\u30FC\u30AF\u30F3\u304C\u542B\u307E\u308C\u3066\u3044\u307E\u305B\u3093. missing_id=IDREF \"{0}\" \u306B\u5BFE\u5FDC\u3059\u308BID\u304C\u3042\u308A\u307E\u305B\u3093. duplicate_id=ID \"{0}\" \u306F\u65E2\u306B\u5B9A\u7FA9\u3055\u308C\u3066\u3044\u307E\u3059. first_id=ID \"{0}\" \u306F\u3001\u3053\u3053\u306B\u6700\u521D\u306B\u66F8\u304B\u308C\u3066\u3044\u307E\u3059. # Fragments name_absent_namespace=\"{0}\" name_with_namespace=\u540D\u524D\u7A7A\u9593 \"{0}\" \u306E \"{1}\" qname=\"{0}\" qnames_nsdecls={0}(\u540D\u524D\u7A7A\u9593\u5BA3\u8A00 {1}) or_list_pair={0} \u307E\u305F\u306F {1} or_list_many_first={0} or_list_many_middle={0}, {1} or_list_many_last={0} \u307E\u305F\u306F {1} and_list_pair={0} \u304B\u3064 {1} and_list_many_first={0} and_list_many_middle={0}, {1} and_list_many_last={0} \u304B\u3064 {1} expected=; \u3053\u3053\u306B\u66F8\u304B\u308C\u308B\u3079\u304D\u3082\u306E\u306F {0} \u3067\u3059. element_end_tag=\u8981\u7D20\u306E\u7D42\u4E86\u30BF\u30B0 text=\u30C6\u30AD\u30B9\u30C8 data=\u30C7\u30FC\u30BF element_list=\u8981\u7D20 {0} element_other_ns=\u4ED6\u306E\u540D\u524D\u7A7A\u9593\u306E\u8981\u7D20 expected_attribute=; \u3053\u3053\u306B\u66F8\u304B\u308C\u308B\u3079\u304D\u5C5E\u6027\u306F {0} \u3067\u3059. expected_attribute_or_other_ns=; \u3053\u3053\u306B\u66F8\u304B\u308C\u308B\u3079\u304D\u5C5E\u6027\u306F {0} \u307E\u305F\u306F\u4ED6\u306E\u540D\u524D\u7A7A\u9593\u306E\u5C5E\u6027\u3067\u3059. data_failures=; {0} token_failures=; \u30C8\u30FC\u30AF\u30F3 {0} \u304C\u4E0D\u6B63\u3067\u3059. ; {1} missing_token=; \u30C8\u30FC\u30AF\u30F3\u304C\u3042\u308A\u307E\u305B\u3093. ; {0} expected_data=; \u671F\u5F85\u3055\u308C\u308B\u30C7\u30FC\u30BF require_values={0} \u3068\u7B49\u3057\u304F\u306A\u304F\u3066\u306F\u306A\u308A\u307E\u305B\u3093. require_qnames={0} \u3068\u7B49\u3057\u3044 QName \u3067\u306A\u304F\u3066\u306F\u306A\u308A\u307E\u305B\u3093. require_datatype=\u30C7\u30FC\u30BF\u30BF\u30A4\u30D7{0}\u306E\u59A5\u5F53\u306A\u30A4\u30F3\u30B9\u30BF\u30F3\u30B9\u3067\u306A\u304F\u3066\u306F\u306A\u308A\u307E\u305B\u3093. ././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootepubcheck-4.0.2/src/main/resources/com/thaiopensource/relaxng/pattern/resources/Messages_fr.propertiesepubcheck-4.0.2/src/main/resources/com/thaiopensource/relaxng/pattern/resources/Messages_fr.properti0000644000175000017500000003470213017276730033472 0ustar eugeneeugene# First two blocks doesn't need to be translated for epubcheck, as @murata0204 noted in # https://github.com/IDPF/epubcheck/pull/472#issuecomment-58265808 # # Non-unicode chars (german umlauts, etc..) must be escaped like \u00DF # because otherwise Jing can't parse them. Bad UTF8-support # Properties file specifying messages illegal_href_attribute=attribut \"href\" ill\u00E9gal. ns_attribute_ignored=attribut \"ns\" ignor\u00E9 reference_to_undefined=r\u00E9f\u00E9rence \u00E0 un patron ind\u00E9termin\u00E9 \"{0}\" missing_start_element=\u00E9l\u00E9ment \"start\" manquant recursive_reference=mauvais r\u00E9f\u00E9rence r\u00E9cursive au patron \"{0}\" recursive_include=inclusion r\u00E9cursive de l'URL \"{0}\" duplicate_define=plusieurs d\u00E9finitions de \"{0}\" sans attribut \"combine\" duplicate_start=plusieurs d\u00E9finitions de start sans attribut \"combine\" conflict_combine_define=valeurs conflictuelles de l'attribut \"combine\" pour la d\u00E9finition de \"{0}\" conflict_combine_start=valeurs conflictuelles de l'attribut \"combine\" pour la d\u00E9finition de start missing_start_replacement=\"start\" dans \"include\" ne remplace rien missing_define_replacement=d\u00E9finition de \"{0}\" dans \"include\" ne remplace rien interleave_string=entrelacement d'\u00E9l\u00E9ment \"string\" ou \"data\" group_string=groupe d'\u00E9l\u00E9ment \"string\" ou \"data\" one_or_more_string=r\u00E9p\u00E9tition d'\u00E9l\u00E9ment \"string\" ou \"data\" unrecognized_datatype=type de donn\u00E9es \"{1}\" de la librairie \"{0}\" non reconnu unsupported_datatype_detail=type de donn\u00E9es \"{1}\" de la librairie \"{0}\" non support\u00E9 : {2} unrecognized_datatype_library=librairie de type de donn\u00E9es \"{0}\" non reconnue unrecognized_builtin_datatype=aucun type \"{0}\" pr\u00E9d\u00E9fini : doit \u00EAtre \"string\" ou \"token\" invalid_value=\"{0}\" n'est pas une valeur valide de type de donn\u00E9es parent_ref_outside_grammar=r\u00E9f\u00E9rence \u00E0 une grammaire parent inexistante ref_outside_grammar=r\u00E9f\u00E9rence \u00E0 une grammaire inexistante expected_one_name_class=\u00E9l\u00E9ment \"{0}\" trouv\u00E9 mais aucun autre contenu attendu builtin_param=les types de donn\u00E9es int\u00E9gr\u00E9s n'ont aucun param\u00E8tres invalid_param_display=param\u00E8tre invalide :\n{0} invalid_param_detail_display=param\u00E8tre invalide : {0}\n{1} display_param={0}>>>>{1} invalid_param_detail=param\u00E8tre invalide : {0} invalid_param=param\u00E8tre invalide invalid_params_detail=param\u00E8tres invalides : {0} invalid_params=param\u00E8tres invalides datatype_requires_parameter=le type de donn\u00E9es ne peut pas \u00EAtre utilis\u00E9 sans param\u00E8tre datatype_requires_parameter_detail=le type de donn\u00E9es ne peut pas \u00EAtre utilis\u00E9 sans les param\u00E8tres : {0} attribute_contains_attribute=un motif d'attribut ne doit pas contenir d'autre motif d'attribut (la section 7.1 de la sp\u00E9cification RELAX NG requiert que la forme XML simplifi\u00E9e du sch\u00E9ma ne contienne aucun \u00E9l\u00E9ment satisfaisant le chemin attribute//attribute) attribute_contains_element=un motif d'attribut ne doit pas contenir de motif d'\u00E9l\u00E9ment (la section 7.1 de la sp\u00E9cification RELAX NG requiert que la forme XML simplifi\u00E9e du sch\u00E9ma ne contienne aucun \u00E9l\u00E9ment satisfaisant le chemin attribute//ref) data_except_contains_attribute=un motif de donn\u00E9e ne doit pas exclure de motif d'attribut (la section 7.1 de la sp\u00E9cification RELAX NG requiert que la forme XML simplifi\u00E9e du sch\u00E9ma ne contienne aucun \u00E9l\u00E9ment satisfaisant le chemin data/except//attribute) data_except_contains_element=un motif de donn\u00E9e ne doit pas exclure de motif d'\u00E9l\u00E9ment (la section 7.1 de la sp\u00E9cification RELAX NG requiert que la forme XML simplifi\u00E9e du sch\u00E9ma ne contienne aucun \u00E9l\u00E9ment satisfaisant le chemin data/except//ref) data_except_contains_empty=un motif de donn\u00E9e ne doit pas exclure de motif vide (la section 7.1 de la sp\u00E9cification RELAX NG requiert que la forme XML simplifi\u00E9e du sch\u00E9ma ne contienne aucun \u00E9l\u00E9ment satisfaisant le chemin data/except//empty) data_except_contains_group=un motif de donn\u00E9e ne doit pas exclure un groupe (la section 7.1 de la sp\u00E9cification RELAX NG requiert que la forme XML simplifi\u00E9e du sch\u00E9ma ne contienne aucun \u00E9l\u00E9ment satisfaisant le chemin data/except//group) data_except_contains_interleave=un motif de donn\u00E9e ne doit pas exclure un groupe entrelac\u00E9 (la section 7.1 de la sp\u00E9cification RELAX NG requiert que la forme XML simplifi\u00E9e du sch\u00E9ma ne contienne aucun \u00E9l\u00E9ment satisfaisant le chemin data/except//interleave) data_except_contains_list=un motif de donn\u00E9e ne doit pas exclure un motif de liste (la section 7.1 de la sp\u00E9cification RELAX NG requiert que la forme XML simplifi\u00E9e du sch\u00E9ma ne contienne aucun \u00E9l\u00E9ment satisfaisant le chemin data/except//list) data_except_contains_one_or_more=un motif de donn\u00E9e ne doit pas exclure une r\u00E9p\u00E9tition (la section 7.1 de la sp\u00E9cification RELAX NG requiert que la forme XML simplifi\u00E9e du sch\u00E9ma ne contienne aucun \u00E9l\u00E9ment satisfaisant le chemin data/except//oneOrMore) data_except_contains_text=un motif de donn\u00E9e ne doit pas exclure un motif de texte (la section 7.1 de la sp\u00E9cification RELAX NG requiert que la forme XML simplifi\u00E9e du sch\u00E9ma ne contienne aucun \u00E9l\u00E9ment satisfaisant le chemin data/except//text) list_contains_attribute=un motif de liste ne doit pas contenir un motif d'attribut (la section 7.1 de la sp\u00E9cification RELAX NG requiert que la forme XML simplifi\u00E9e du sch\u00E9ma ne contienne aucun \u00E9l\u00E9ment satisfaisant le chemin list//attribute) list_contains_element=un motif de liste ne doit pas contenir un motif d'\u00E9l\u00E9ment (la section 7.1 de la sp\u00E9cification RELAX NG requiert que la forme XML simplifi\u00E9e du sch\u00E9ma ne contienne aucun \u00E9l\u00E9ment satisfaisant le chemin list//ref) list_contains_list=un motif de liste ne doit pas contenir un autre motif de liste (la section 7.1 de la sp\u00E9cification RELAX NG requiert que la forme XML simplifi\u00E9e du sch\u00E9ma ne contienne aucun \u00E9l\u00E9ment satisfaisant le chemin list//list) list_contains_text=un motif de liste ne doit pas contenir un motif de texte (la section 7.1 de la sp\u00E9cification RELAX NG requiert que la forme XML simplifi\u00E9e du sch\u00E9ma ne contienne aucun \u00E9l\u00E9ment satisfaisant le chemin list//text) list_contains_interleave=un motif de liste ne doit pas contenir un motif entrelac\u00E9 (la section 7.1 de la sp\u00E9cification RELAX NG requiert que la forme XML simplifi\u00E9e du sch\u00E9ma ne contienne aucun \u00E9l\u00E9ment satisfaisant le chemin list//interleave) one_or_more_contains_group_contains_attribute=un groupe d'attributs ne doit pas \u00EAtre pouvoir \u00EAtre r\u00E9p\u00E9t\u00E9 (la section 7.1 de la sp\u00E9cification RELAX NG requiert que la forme XML simplifi\u00E9e du sch\u00E9ma ne contienne aucun \u00E9l\u00E9ment satisfaisant le chemin oneOrMore//group//attribute) one_or_more_contains_interleave_contains_attribute=un groupe d'attributs entrelac\u00E9s ne doit pas \u00EAtre pouvoir \u00EAtre r\u00E9p\u00E9t\u00E9 (la section 7.1 de la sp\u00E9cification RELAX NG requiert que la forme XML simplifi\u00E9e du sch\u00E9ma ne contienne aucun \u00E9l\u00E9ment satisfaisant le chemin oneOrMore//interleave//attribute) start_contains_attribute=un \u00E9l\u00E9ment satisfaisant le chemin non-autoris\u00E9 start//attribute a \u00E9t\u00E9 trouv\u00E9 dans la forme XML simplifi\u00E9e du sch\u00E9ma (voir la section 7.1 de la sp\u00E9cification RELAX NG) start_contains_data=un \u00E9l\u00E9ment satisfaisant le chemin non-autoris\u00E9 start//data a \u00E9t\u00E9 trouv\u00E9 dans la forme XML simplifi\u00E9e du sch\u00E9ma (voir la section 7.1 de la sp\u00E9cification RELAX NG) start_contains_empty=un \u00E9l\u00E9ment satisfaisant le chemin non-autoris\u00E9 start//empty a \u00E9t\u00E9 trouv\u00E9 dans la forme XML simplifi\u00E9e du sch\u00E9ma (voir la section 7.1 de la sp\u00E9cification RELAX NG) start_contains_group=un \u00E9l\u00E9ment satisfaisant le chemin non-autoris\u00E9 start//group a \u00E9t\u00E9 trouv\u00E9 dans la forme XML simplifi\u00E9e du sch\u00E9ma (voir la section 7.1 de la sp\u00E9cification RELAX NG) start_contains_interleave=un \u00E9l\u00E9ment satisfaisant le chemin non-autoris\u00E9 start//interleave a \u00E9t\u00E9 trouv\u00E9 dans la forme XML simplifi\u00E9e du sch\u00E9ma (voir la section 7.1 de la sp\u00E9cification RELAX NG) start_contains_list=un \u00E9l\u00E9ment satisfaisant le chemin non-autoris\u00E9 start//list a \u00E9t\u00E9 trouv\u00E9 dans la forme XML simplifi\u00E9e du sch\u00E9ma (voir la section 7.1 de la sp\u00E9cification RELAX NG) start_contains_one_or_more=un \u00E9l\u00E9ment satisfaisant le chemin non-autoris\u00E9 start//oneOrMore a \u00E9t\u00E9 trouv\u00E9 dans la forme XML simplifi\u00E9e du sch\u00E9ma (voir la section 7.1 de la sp\u00E9cification RELAX NG) start_contains_text=un \u00E9l\u00E9ment satisfaisant le chemin non-autoris\u00E9 start//text a \u00E9t\u00E9 trouv\u00E9 dans la forme XML simplifi\u00E9e du sch\u00E9ma (voir la section 7.1 de la sp\u00E9cification RELAX NG) start_contains_value=un \u00E9l\u00E9ment satisfaisant le chemin non-autoris\u00E9 start//value a \u00E9t\u00E9 trouv\u00E9 dans la forme XML simplifi\u00E9e du sch\u00E9ma (voir la section 7.1 de la sp\u00E9cification RELAX NG) duplicate_attribute=attribut en double duplicate_attribute_name=attribut {0} en double duplicate_attribute_ns=attributs de l'espace de noms \"{0}\" peut appara\u00EEtre plus d'une fois interleave_element_overlap=noms d'\u00E9l\u00E9ments surcharg\u00E9s dans les op\u00E9randes de \"interleave\" interleave_element_overlap_name=l'\u00E9l\u00E9ment {0} peut se trouver dans plus d'une op\u00E9rande de \"interleave\" interleave_element_overlap_ns=des \u00E9l\u00E9ments dans le namespace \"{0}\" peuvent se trouver dans plus d'une op\u00E9rande de \"interleave\" interleave_text_overlap=les deux op\u00E9randes de \"interleave\" contiennent \"text\" open_name_class_not_repeated=un attribut utilisant \"nsName\" ou \"anyName\" doit \u00EAtre dans \"oneOrMore\" xmlns_uri_attribute=un attribut ne doit pas avoir pour namespace \"http://www.w3.org/2000/xmlns\" xmlns_attribute=un attribut ne doit pas \u00EAtre nomm\u00E9 \"xmlns\" # Validation errors unknown_element=l'\u00E9l\u00E9ment {0} n'est autoris\u00E9 nulle part {1} unexpected_element_required_element_missing=l'\u00E9l\u00E9ment {0} n'est pas encore autoris\u00E9\u00A0; il manque l'\u00E9l\u00E9ment {1} unexpected_element_required_elements_missing=l'\u00E9l\u00E9ment {0} n'est pas encore autoris\u00E9\u00A0; il manque les \u00E9l\u00E9ments {1} element_not_allowed_yet=l'\u00E9l\u00E9ment {0} n'est pas encore autoris\u00E9 {1} out_of_context_element=l'\u00E9l\u00E9ment {0} n'est pas autoris\u00E9 ici {1} no_attributes_allowed=l'attribut {0} a \u00E9t\u00E9 trouv\u00E9, mais aucun attribut n'est autoris\u00E9 ici invalid_attribute_name=l'attribut {0} n'est pas autoris\u00E9 ici {1} invalid_attribute_value=la valeur de l'attribut {0} n'est pas valide {1} required_attributes_missing_expected=il manque un ou plusieurs attributs obligatoires {1} \u00E0 l'\u00E9l\u00E9ment {0} required_attribute_missing=il manque l'attribut obligatoire {1} \u00E0 l'\u00E9l\u00E9ment {0} required_attributes_missing=il manque les attributs obligatoires {1} \u00E0 l'\u00E9l\u00E9ment {0} incomplete_element_required_elements_missing_expected=l'\u00E9l\u00E9ment {0} est incomplet {1} incomplete_element_required_element_missing=l'\u00E9l\u00E9ment {0} est incomplet\u00A0; il manque l'\u00E9l\u00E9ment obligatoire {1} incomplete_element_required_elements_missing=l'\u00E9l\u00E9ment {0} est incomplet\u00A0; il manque les \u00E9l\u00E9ments obligatoires {1} text_not_allowed=aucun texte n'est autoris\u00E9 ici {0} document_incomplete=le document n'est pas enti\u00E8rement satisfait invalid_element_value=l'\u00E9l\u00E9ment {0} contient des caract\u00E8res non valides {1} blank_not_allowed=l'\u00E9l\u00E9ment {0} ne doit pas avoir un contenu vide {1} schema_allows_nothing=le sch\u00E9ma n'autorise aucun contenu\u00A0: il est \u00E9quivalent \u00E0 # ID correctness errors id_element_name_class=un motif \"element\" contenant un motif \"attribut\" avec un type d'identificateur non nul doit avoir une classe de nom contenant seulement des \u00E9l\u00E9ments \"choice\" et \"name\" id_attribute_name_class=un motif \"attribut\" avec un type d'identificateur non nul doit avoir une classe de nom \u00E9tant un nom unique id_parent=un motif \"data\" ou \"value\" avec un type d'identificateur non nul doit avoir pour parent un motif \"attribute\" id_type_conflict=types d'identificateurs conflictuels pour l'attribut {1} de l'\u00E9l\u00E9ment {0} # ID soundness errors id_no_tokens=valeur d'un attribut de type ID ne contenant aucun token id_multiple_tokens=valeur d'un attribut de type ID contenant plusieurs tokens idref_no_tokens=valeur d'un attribut de type IDREF ne contenant aucun token idref_multiple_tokens=valeur d'un attribut de type ID ne contenant plusieurs tokens idrefs_no_tokens=valeur d'un attribut de type IDREFS ne contenant aucun token missing_id=aucun ID correspondant \u00E0 l'IDREF \"{0}\" duplicate_id=l'ID \"{0}\" a d\u00E9j\u00E0 \u00E9t\u00E9 d\u00E9fini first_id=premi\u00E8re occurence de l'ID \"{0}\" # Fragments name_absent_namespace=\"{0}\" name_with_namespace=\"{1}\" dans le namespace \"{0}\" qname=\"{0}\" qnames_nsdecls={0} (avec {1}) or_list_pair={0} ou {1} or_list_many_first={0} or_list_many_middle={0}, {1} or_list_many_last={0} ou {1} and_list_pair={0} et {1} and_list_many_first={0} and_list_many_middle={0}, {1} and_list_many_last={0} et {1} expected=; {0} est attendu element_end_tag=la balise fermante de l'\u00E9l\u00E9ment text=du texte data=des donn\u00E9es element_list=l'\u00E9l\u00E9ment {0} element_other_ns=un \u00E9l\u00E9ment dans un autre namespace expected_attribute=; l'attribut {0} est attendu expected_attribute_or_other_ns=; l'attribut {0} ou un attrribut dans un autre namespace est attendu data_failures=; {0} token_failures=; token {0} non valide\u00A0; {1} missing_token=; token manquant\u00A0; {0} expected_data=; donn\u00E9es attendues require_values=doit \u00EAtre \u00E9gal \u00E0 {0} require_qnames=doit \u00EAtre un QName \u00E9gal \u00E0 {0} require_datatype=doit \u00EAtre une instance valide du type {0} ././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootepubcheck-4.0.2/src/main/resources/com/thaiopensource/relaxng/pattern/resources/Messages_es.propertiesepubcheck-4.0.2/src/main/resources/com/thaiopensource/relaxng/pattern/resources/Messages_es.properti0000644000175000017500000003164513017276730033475 0ustar eugeneeugene# First two blocks doesn't need to be translated for epubcheck, as @murata0204 noted in # https://github.com/IDPF/epubcheck/pull/472#issuecomment-58265808 # # Non-unicode chars (german umlauts, etc..) must be escaped like \u00DF # because otherwise Jing can't parse them. Bad UTF8-support # Properties file specifying messages illegal_href_attribute=atributo \"href\" no permitido ns_attribute_ignored=atributo \"ns\" ignorado reference_to_undefined=referencia a patr\u00F3n \"{0}\" no definido missing_start_element=elemento \"start\" ausente recursive_reference=referencia recursiva err\u00F3nea a patr\u00F3n \"{0}\" recursive_include=inclusi\u00F3n recursiva de URL \"{0}\" duplicate_define=definiciones m\u00FAltiples de \"{0}\" sin atributo \"combine\" duplicate_start=definiciones m\u00FAltiples de inicio sin atributo \"combine\" conflict_combine_define=valores conflictivos de atributo \"combine\" para la definici\u00F3n de \"{0}\" conflict_combine_start=valores conflictivos de atributo \"combine\" para definici\u00F3n de inicio missing_start_replacement=\"start\" en \"include\" no sobreescribe nada missing_define_replacement=definici\u00F3n de \"{0}\" en \"include\" no sobreescribe nada interleave_string=entrelazado de elementos \"string\" o \"data\" group_string=grupo de elementos \"string\" o \"data\" one_or_more_string=repetici\u00F3n de elementos \"string\" o \"data\" unrecognized_datatype=no se reconoce datatype \"{1}\" de biblioteca \"{0}\" unsupported_datatype_detail=datatype \"{1}\" de biblioteca \"{0}\" no soportado: {2} unrecognized_datatype_library=biblioteca datatype \"{0}\" no reconocida unrecognized_builtin_datatype=datatype integrado incorrecto \"{0}\": debe ser \"string\" o \"token\" invalid_value=\"{0}\" no es un valor de datatype v\u00E1lido parent_ref_outside_grammar=referencia a una gram\u00E1tica superior inexistente ref_outside_grammar=referencia a una gram\u00E1tica inexistente expected_one_name_class=hallado elemento \"{0}\" cuando no se esperaba m\u00E1s contenido builtin_param=los datatypes integrados no tienen ning\u00FAn par\u00E1metro invalid_param_display=par\u00E1metro no v\u00E1lido:\n{0} invalid_param_detail_display=par\u00E1metro no v\u00E1lido: {0}:\n{1} display_param={0}>>>>{1} invalid_param_detail=par\u00E1metro no v\u00E1lido: {0} invalid_param=par\u00E1metro no v\u00E1lido invalid_params_detail=par\u00E1metros no v\u00E1lidos: {0} invalid_params=par\u00E1metros no v\u00E1lidos datatype_requires_parameter=datatype no puede utilizarse sin par\u00E1metros datatype_requires_parameter_detail=datatype no puede utilizarse sin par\u00E1metros: {0} attribute_contains_attribute=un modelo de atributo no puede contener otro modelo de atributo (la secci\u00F3n 7.1 de la especificaci\u00F3n RELAX NG requiere que la forma XML simplificada del esquema no contenga elementos que tengan la ruta attribute//attribute) attribute_contains_element=un modelo de atributo no puede contener un modelo de elemento (la secci\u00F3n 7.1 de la especificaci\u00F3n RELAX NG requiere que la forma XML simplificada del esquema no contenga elementos que tengan la ruta attribute//ref) data_except_contains_attribute=un modelo de datos no puede excluir un modelo de atributo (la secci\u00F3n 7.1 de la especificaci\u00F3n RELAX NG requiere que la forma XML simplificada del esquema no contenga elementos que tengan la ruta data/except//attribute) data_except_contains_element=un modelo de datos no puede excluir un modelo de elemento (la secci\u00F3n 7.1 de la especificaci\u00F3n RELAX NG requiere que la forma XML simplificada del esquema no contenga elementos que tengan la ruta data/except//ref) data_except_contains_empty=un modelo de datos no puede excluir un modelo vac\u00EDo (la secci\u00F3n 7.1 de la especificaci\u00F3n RELAX NG requiere que la forma XML simplificada del esquema no contenga elementos que tengan la ruta data/except//empty) data_except_contains_group=un modelo de datos no puede excluir un grupo (la secci\u00F3n 7.1 de la especificaci\u00F3n RELAX NG requiere que la forma XML simplificada del esquema no contenga elementos que tengan la ruta data/except//group) data_except_contains_interleave=un modelo de datos no puede excluir un grupo intercalado (la secci\u00F3n 7.1 de la especificaci\u00F3n RELAX NG requiere que la forma XML simplificada del esquema no contenga elementos que tengan la ruta data/except//interleave) data_except_contains_list=un modelo de datos no puede excluir un modelo de lista (la secci\u00F3n 7.1 de la especificaci\u00F3n RELAX NG requiere que la forma XML simplificada del esquema no contenga elementos que tengan la ruta data/except//list) data_except_contains_one_or_more=un modelo de datos no puede excluir una repetici\u00F3n (la secci\u00F3n 7.1 de la especificaci\u00F3n RELAX NG requiere que la forma XML simplificada del esquema no contenga elementos que tengan la ruta data/except//oneOrMore) data_except_contains_text=un modelo de datos no puede excluir un modelo de texto (la secci\u00F3n 7.1 de la especificaci\u00F3n RELAX NG requiere que la forma XML simplificada del esquema no contenga elementos que tengan la ruta data/except//text) list_contains_attribute=un modelo de lista no puede contener un modelo de atributo (la secci\u00F3n 7.1 de la especificaci\u00F3n RELAX NG requiere que la forma XML simplificada del esquema no contenga elementos que tengan la ruta list//attribute) list_contains_element=un modelo de lista no puede contener un modelo de elemento (la secci\u00F3n 7.1 de la especificaci\u00F3n RELAX NG requiere que la forma XML simplificada del esquema no contenga elementos que tengan la ruta list//ref) list_contains_list=un modelo de lista no puede contener otro modelo de lista (la secci\u00F3n 7.1 de la especificaci\u00F3n RELAX NG requiere que la forma XML simplificada del esquema no contenga elementos que tengan la ruta list//list) list_contains_text=un modelo de lista no puede contener un modelo de texto (la secci\u00F3n 7.1 de la especificaci\u00F3n RELAX NG requiere que la forma XML simplificada del esquema no contenga elementos que tengan la ruta list//text) list_contains_interleave=un modelo de lista no puede contener un modelo intercalado (la secci\u00F3n 7.1 de la especificaci\u00F3n RELAX NG requiere que la forma XML simplificada del esquema no contenga elementos que tengan la ruta list//interleave) one_or_more_contains_group_contains_attribute=un grupo de atributos no puede repetirse (la secci\u00F3n 7.1 de la especificaci\u00F3n RELAX NG requiere que la forma XML simplificada del esquema no contenga elementos que tengan la ruta oneOrMore//group//attribute) one_or_more_contains_interleave_contains_attribute=un grupo de atributos intercalado no puede repetirse (la secci\u00F3n 7.1 de la especificaci\u00F3n RELAX NG requiere que la forma XML simplificada del esquema no contenga elementos que tengan la ruta oneOrMore//interleave//attribute) start_contains_attribute=se ha encontrado un elemento con la ruta start//attribute, prohibida en la forma XML simplificada del esquema (v\u00E9ase secci\u00F3n 7.1 de la especificaci\u00F3n RELAX NG) start_contains_data=se ha encontrado un elemento con la ruta start//data, prohibida en la forma XML simplificada del esquema (v\u00E9ase secci\u00F3n 7.1 de la especificaci\u00F3n RELAX NG) start_contains_empty=se ha encontrado un elemento con la ruta start//empty, prohibida en la forma XML simplificada del esquema (v\u00E9ase secci\u00F3n 7.1 de la especificaci\u00F3n RELAX NG) start_contains_group=se ha encontrado un elemento con la ruta start//group, prohibida en la forma XML simplificada del esquema (v\u00E9ase secci\u00F3n 7.1 de la especificaci\u00F3n RELAX NG) start_contains_interleave=se ha encontrado un elemento con la ruta start//interleave, prohibida en la forma XML simplificada del esquema (v\u00E9ase secci\u00F3n 7.1 de la especificaci\u00F3n RELAX NG) start_contains_list=se ha encontrado un elemento con la ruta start//list, prohibida en la forma XML simplificada del esquema (v\u00E9ase secci\u00F3n 7.1 de la especificaci\u00F3n RELAX NG) start_contains_one_or_more=se ha encontrado un elemento con la ruta start//oneOrMore, prohibida en la forma XML simplificada del esquema (v\u00E9ase secci\u00F3n 7.1 de la especificaci\u00F3n RELAX NG) start_contains_text=se ha encontrado un elemento con la ruta start//text, prohibida en la forma XML simplificada del esquema (v\u00E9ase secci\u00F3n 7.1 de la especificaci\u00F3n RELAX NG) start_contains_value=se ha encontrado un elemento con la ruta start//value, prohibida en la forma XML simplificada del esquema (v\u00E9ase secci\u00F3n 7.1 de la especificaci\u00F3n RELAX NG) duplicate_attribute=atributo duplicado duplicate_attribute_name=atributo duplicado {0} duplicate_attribute_ns=atributos de un espacio de nombre \"{0}\" pueden darse m\u00E1s de una vez interleave_element_overlap=nombres de elemento superpuestos en operandos de \"interleave\" interleave_element_overlap_name=el elemento {0} puede darse en m\u00E1s de un operando de \"interleave\" interleave_element_overlap_ns=elementos de un espacio de nombre \"{0}\" pueden darse en m\u00E1s de un operando de \"interleave\" interleave_text_overlap=ambos operandos de \"interleave\" contienen \"text\" open_name_class_not_repeated=el atributo que utiliza \"nsName\" o \"anyName\" debe estar en \"oneOrMore\" xmlns_uri_attribute=el atributo no puede contener un espacio de nombre URI \"http://www.w3.org/2000/xmlns\" xmlns_attribute=el atributo no puede denominarse \"xmlns\" # Validation errors unknown_element=el elemento {0} no se permite en ning\u00FAn {1} unexpected_element_required_element_missing=no se permite a\u00FAn el elemento {0}; el elemento obligatorio {1} no se encuentra unexpected_element_required_elements_missing=no se permite a\u00FAn el elemento {0}; los elementos obligatorios {1} no se encuentran element_not_allowed_yet=el elemento {0} no se permite a\u00FAn {1} out_of_context_element=el elemento {0} no se permite aqu\u00ED{1} no_attributes_allowed=encontrado atributo {0}, pero aqu\u00ED no se permiten atributos invalid_attribute_name=el atributo {0} no se permite aqu\u00ED{1} invalid_attribute_value=el valor del atributo {0} no es v\u00E1lido{1} required_attributes_missing_expected=el elemento {0} carece de uno o m\u00E1s atributos obligtorios{1} required_attribute_missing=el element {0} carece del atributo obligatorio {1} required_attributes_missing=el element {0} carece de los atributos obligatorios {1} incomplete_element_required_elements_missing_expected=elemento {0} incompleto{1} incomplete_element_required_element_missing=elemento {0} incompleto; carece del elemento obligatorio {1} incomplete_element_required_elements_missing=elemento {0} incompleto; carece de los elementos obligatorios {1} text_not_allowed=no se permite texto aqu\u00ED{0} document_incomplete=documento no coincidente invalid_element_value=contenido de car\u00E1cter de elemento {0} no v\u00E1lido{1} blank_not_allowed=contenido vac\u00EDo para elemento {0} no permitido{1} schema_allows_nothing=el esquema no permite nada: es equivalente a # ID correctness errors id_element_name_class=un modelo \"element\" que contenga un modelo \"attribute\" con un tipo de ID distinto de "nulo" debe tener un nombre de clase que contenga solo elementos \"choice\" y \"name\" id_attribute_name_class=un modelo \"attribute\" con un tipo de ID distinto de "nulo" debe tener un nombre de clase que sea un nombre simple id_parent=modelos \"data\" o \"value\" con un tipo de ID distinto de "nulo" deben darse como hijos de un modelo \"attribute\" id_type_conflict=tipos de ID en conflicto para el atributo {1} del elemento {0} # ID soundness errors id_no_tokens=el valor de atributo del tipo de ID no tiene tokens id_multiple_tokens=el valor de atributo del tipo de ID contiene m\u00FAltiples tokens idref_no_tokens=el valor de atributo del tipo de IDREF no contiene tokens idref_multiple_tokens=el valor de atributo del tipo de IDREF contiene m\u00FAltiples tokens idrefs_no_tokens=el valor de atributo del tipo de IDREFS no contiene tokens missing_id=IDREF \"{0}\" sin concordancia de ID duplicate_id=ID \"{0}\" ya ha sido definido first_id=primera aparici\u00F3n del ID \"{0}\" # Fragments name_absent_namespace=\"{0}\" name_with_namespace=\"{1}\" de un espacio de nombre \"{0}\" qname=\"{0}\" qnames_nsdecls={0} (con {1}) or_list_pair={0} o {1} or_list_many_first={0} or_list_many_middle={0}, {1} or_list_many_last={0} o {1} and_list_pair={0} y {1} and_list_many_first={0} and_list_many_middle={0}, {1} and_list_many_last={0} y {1} expected=; se esperaba {0} element_end_tag=el elemento final de etiqueta text=texto data=datos element_list=elemento {0} element_other_ns=un elemento de otro espacio de nombre expected_attribute=; se esperaba atributo {0} expected_attribute_or_other_ns=; se esperaba atributo {0} o un atributo de otro espacio de nombre data_failures=; {0} token_failures=; token {0} no v\u00E1lido; {1} missing_token=; token ausente; {0} expected_data=; se esperaban datos require_values=debe ser igual a {0} require_qnames=debe ser un QName igual a {0} require_datatype=debe ser una instancia v\u00E1lida de datatype {0} ././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootepubcheck-4.0.2/src/main/resources/com/thaiopensource/relaxng/pattern/resources/Messages_it.propertiesepubcheck-4.0.2/src/main/resources/com/thaiopensource/relaxng/pattern/resources/Messages_it.properti0000644000175000017500000003026713017276730033501 0ustar eugeneeugene# This is the Italian translation of org/thaiopensource/relaxng/pattern/resources/Messages.properties file. # Translation by Alberto Pettarin (https://github.com/pettarin) # # The first block doesn't need to be translated for epubcheck, as @murata0204 noted in # https://github.com/IDPF/epubcheck/pull/472#issuecomment-58265808 # # Non-unicode chars (german umlauts, etc..) must be escaped like \u00DF # because otherwise Jing can't parse them. (Bad UTF-8 support.) # Properties file specifying messages illegal_href_attribute=illegal \"href\" attribute ns_attribute_ignored=\"ns\" attribute ignored reference_to_undefined=reference to undefined pattern \"{0}\" missing_start_element=missing \"start\" element recursive_reference=bad recursive reference to pattern \"{0}\" recursive_include=recursive inclusion of URL \"{0}\" duplicate_define=multiple definitions of \"{0}\" without \"combine\" attribute duplicate_start=multiple definitions of start without \"combine\" attribute conflict_combine_define=conflicting values of \"combine\" attribute for definition of \"{0}\" conflict_combine_start=conflicting values of \"combine\" attribute for definition of start missing_start_replacement=\"start\" in \"include\" does not override anything missing_define_replacement=definition of \"{0}\" in \"include\" does not override anything interleave_string=interleave of \"string\" or \"data\" element group_string=group of \"string\" or \"data\" element one_or_more_string=repeat of \"string\" or \"data\" element unrecognized_datatype=datatype \"{1}\" from library \"{0}\" not recognized unsupported_datatype_detail=datatype \"{1}\" from library \"{0}\" not supported: {2} unrecognized_datatype_library=datatype library \"{0}\" not recognized unrecognized_builtin_datatype=no such builtin datatype \"{0}\": must be \"string\" or \"token\" invalid_value=\"{0}\" is not a valid value of the datatype parent_ref_outside_grammar=reference to non-existent parent grammar ref_outside_grammar=reference to non-existent grammar expected_one_name_class=found \"{0}\" element but expected no further content builtin_param=builtin datatypes do not have any parameters invalid_param_display=invalid parameter:\n{0} invalid_param_detail_display=invalid parameter: {0}:\n{1} display_param={0}>>>>{1} invalid_param_detail=invalid parameter: {0} invalid_param=invalid parameter invalid_params_detail=invalid parameters: {0} invalid_params=invalid parameters datatype_requires_parameter=datatype cannot be used without parameters datatype_requires_parameter_detail=datatype cannot be used without parameters: {0} attribute_contains_attribute=an attribute pattern must not contain an attribute pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path attribute//attribute) attribute_contains_element=an attribute pattern must not contain an element pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path attribute//ref) data_except_contains_attribute=a data pattern must not exclude an attribute pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path data/except//attribute) data_except_contains_element=a data pattern must not exclude an element pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path data/except//ref) data_except_contains_empty=a data pattern must not exclude an empty pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path data/except//empty) data_except_contains_group=a data pattern must not exclude a group (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path data/except//group) data_except_contains_interleave=a data pattern must not exclude an interleaved group (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path data/except//interleave) data_except_contains_list=a data pattern must not exclude a list pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path data/except//list) data_except_contains_one_or_more=a data pattern must not exclude a repetition (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path data/except//oneOrMore) data_except_contains_text=a data pattern must not exclude a text pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path data/except//text) list_contains_attribute=a list pattern must not contain an attribute pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path list//attribute) list_contains_element=a list pattern must not contain an element pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path list//ref) list_contains_list=a list pattern must not contain a list pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path list//list) list_contains_text=a list pattern must not contain a text pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path list//text) list_contains_interleave=a list pattern must not contain an interleave pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path list//interleave) one_or_more_contains_group_contains_attribute=a group of attributes must not be repeatable (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path oneOrMore//group//attribute) one_or_more_contains_interleave_contains_attribute=an interleaved group of attributes must not be repeatable (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path oneOrMore//interleave//attribute) start_contains_attribute=found element matching the prohibited path start//attribute in the simplified XML form of the schema (see section 7.1 of the RELAX NG specification) start_contains_data=found element matching the prohibited path start//data in the simplified XML form of the schema (see section 7.1 of the RELAX NG specification) start_contains_empty=found element matching the prohibited path start//empty in the simplified XML form of the schema (see section 7.1 of the RELAX NG specification) start_contains_group=found element matching the prohibited path start//group in the simplified XML form of the schema (see section 7.1 of the RELAX NG specification) start_contains_interleave=found element matching the prohibited path start//interleave in the simplified XML form of the schema (see section 7.1 of the RELAX NG specification) start_contains_list=found element matching the prohibited path start//list in the simplified XML form of the schema (see section 7.1 of the RELAX NG specification) start_contains_one_or_more=found element matching the prohibited path start//oneOrMore in the simplified XML form of the schema (see section 7.1 of the RELAX NG specification) start_contains_text=found element matching the prohibited path start//text in the simplified XML form of the schema (see section 7.1 of the RELAX NG specification) start_contains_value=found element matching the prohibited path start//value in the simplified XML form of the schema (see section 7.1 of the RELAX NG specification) duplicate_attribute=duplicate attribute duplicate_attribute_name=duplicate attribute {0} duplicate_attribute_ns=attributes from namespace \"{0}\" can occur more than once interleave_element_overlap=overlapping element names in operands of \"interleave\" interleave_element_overlap_name=the element {0} can occur in more than one operand of \"interleave\" interleave_element_overlap_ns=elements from namespace \"{0}\" can occur in more than one operand of \"interleave\" interleave_text_overlap=both operands of \"interleave\" contain \"text\" open_name_class_not_repeated=attribute using \"nsName\" or \"anyName\" must be in \"oneOrMore\" xmlns_uri_attribute=attribute must not have namespace URI \"http://www.w3.org/2000/xmlns\" xmlns_attribute=attribute must not be named \"xmlns\" # Validation errors unknown_element=elemento {0} non ammesso in questo punto {1} unexpected_element_required_element_missing=elemento {0} non ammesso in questo punto, richiesto: {1} unexpected_element_required_elements_missing=elemento {0} non ammesso in questo punto, richiesti: {1} element_not_allowed_yet=elemento {0} non ammesso in questo punto {1} out_of_context_element=elemento {0} non ammesso in questo punto {1} no_attributes_allowed=trovato attributo {0}, non permesso in questo punto invalid_attribute_name=trovato attributo {0}, non permesso per l''elemento {1} invalid_attribute_value=valore {1} dell''attributo {0} non valido required_attributes_missing_expected=l''elemento {0} non ha i seguenti attributi obbligatori: {1} required_attribute_missing=l''elemento {0} non ha l''attributo obbligatorio {1} required_attributes_missing=l''elemento {0} non ha i seguenti attributi obbligatori: {1} incomplete_element_required_elements_missing_expected=elemento {0} non completo: mancano gli elementi figli obbligatori {1} incomplete_element_required_element_missing=elemento {0} non completo: manca l''elemento figlio obbligatorio {1} incomplete_element_required_elements_missing=elemento {0} non completo: mancano gli elementi figli obbligatori {1} text_not_allowed=testo non ammesso in questo punto {0} document_incomplete=il documento pare incompleto invalid_element_value=valore {1} dell''elemento {0} non valido blank_not_allowed=l''elemento {0} deve avere un valore non nullo {1} schema_allows_nothing=lo schema non ammette un elemento in questo punto () # ID correctness errors id_element_name_class=an \"element\" pattern containing an \"attribute\" pattern with a non-null ID-type must have a name class that contains only \"choice\" and \"name\" elements id_attribute_name_class=an \"attribute\" pattern with a non-null ID-type must have a name class that is a single name id_parent=a \"data\" or \"value\" pattern with non-null ID-type must occur as the child of an \"attribute\" pattern id_type_conflict=conflicting ID-types for attribute {1} of element {0} # ID soundness errors id_no_tokens=il valore dell''attributo non contiene un id valido id_multiple_tokens=il valore dell''attributo contiene molteplici id idref_no_tokens=il valore dell''attributo non contiene un id valido idref_multiple_tokens=il valore dell''attributo contiene molteplici id idrefs_no_tokens=il valore dell''attributo non contiene un id valido missing_id=l''idref \"{0}\" non contiene un id valido duplicate_id=id \"{0}\" gia'' definito first_id=prima occorrenza dell''id \"{0}\" # Fragment name_absent_namespace=\"{0}\" name_with_namespace=\"{1}\" dal namespace \"{0}\" qname=\"{0}\" qnames_nsdecls={0} (con {1}) or_list_pair={0} o {1} or_list_many_first={0} or_list_many_middle={0}, {1} or_list_many_last={0} o {1} and_list_pair={0} e {1} and_list_many_first={0} and_list_many_middle={0}, {1} and_list_many_last={0} e {1} expected=. Atteso {0} element_end_tag=tag di chiusura dell''elemento text=testo data=data element_list=elemento {0} element_other_ns=un elemento di un altro namespace expected_attribute=. Ammesso solo l''attributo {0} expected_attribute_or_other_ns=. Ammesso attributo {0} o attributi di un altro namespace data_failures=; {0} token_failures=; espressione non valida {0}; {1} missing_token=; token mancante; {0} expected_data=; attesa una data require_values=deve essere {0} require_qnames=deve essere un nome qualificato (QName) come {0} require_datatype=deve essere una data valida di tipo {0} ././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootepubcheck-4.0.2/src/main/resources/com/thaiopensource/relaxng/pattern/resources/Messages_de.propertiesepubcheck-4.0.2/src/main/resources/com/thaiopensource/relaxng/pattern/resources/Messages_de.properti0000644000175000017500000003023013017276730033443 0ustar eugeneeugene# First two blocks doesn't need to be translated for epubcheck, as @murata0204 noted in # https://github.com/IDPF/epubcheck/pull/472#issuecomment-58265808 # # Non-unicode chars (german umlauts, etc..) must be escaped like \u00DF # because otherwise Jing can't parse them. Bad UTF8-support # Properties file specifying messages illegal_href_attribute=illegal \"href\" attribute ns_attribute_ignored=\"ns\" attribute ignored reference_to_undefined=reference to undefined pattern \"{0}\" missing_start_element=missing \"start\" element recursive_reference=bad recursive reference to pattern \"{0}\" recursive_include=recursive inclusion of URL \"{0}\" duplicate_define=multiple definitions of \"{0}\" without \"combine\" attribute duplicate_start=multiple definitions of start without \"combine\" attribute conflict_combine_define=conflicting values of \"combine\" attribute for definition of \"{0}\" conflict_combine_start=conflicting values of \"combine\" attribute for definition of start missing_start_replacement=\"start\" in \"include\" does not override anything missing_define_replacement=definition of \"{0}\" in \"include\" does not override anything interleave_string=interleave of \"string\" or \"data\" element group_string=group of \"string\" or \"data\" element one_or_more_string=repeat of \"string\" or \"data\" element unrecognized_datatype=datatype \"{1}\" from library \"{0}\" not recognized unsupported_datatype_detail=datatype \"{1}\" from library \"{0}\" not supported: {2} unrecognized_datatype_library=datatype library \"{0}\" not recognized unrecognized_builtin_datatype=no such builtin datatype \"{0}\": must be \"string\" or \"token\" invalid_value=\"{0}\" is not a valid value of the datatype parent_ref_outside_grammar=reference to non-existent parent grammar ref_outside_grammar=reference to non-existent grammar expected_one_name_class=found \"{0}\" element but expected no further content builtin_param=builtin datatypes do not have any parameters invalid_param_display=invalid parameter:\n{0} invalid_param_detail_display=invalid parameter: {0}:\n{1} display_param={0}>>>>{1} invalid_param_detail=invalid parameter: {0} invalid_param=invalid parameter invalid_params_detail=invalid parameters: {0} invalid_params=invalid parameters datatype_requires_parameter=datatype cannot be used without parameters datatype_requires_parameter_detail=datatype cannot be used without parameters: {0} attribute_contains_attribute=an attribute pattern must not contain an attribute pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path attribute//attribute) attribute_contains_element=an attribute pattern must not contain an element pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path attribute//ref) data_except_contains_attribute=a data pattern must not exclude an attribute pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path data/except//attribute) data_except_contains_element=a data pattern must not exclude an element pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path data/except//ref) data_except_contains_empty=a data pattern must not exclude an empty pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path data/except//empty) data_except_contains_group=a data pattern must not exclude a group (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path data/except//group) data_except_contains_interleave=a data pattern must not exclude an interleaved group (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path data/except//interleave) data_except_contains_list=a data pattern must not exclude a list pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path data/except//list) data_except_contains_one_or_more=a data pattern must not exclude a repetition (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path data/except//oneOrMore) data_except_contains_text=a data pattern must not exclude a text pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path data/except//text) list_contains_attribute=a list pattern must not contain an attribute pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path list//attribute) list_contains_element=a list pattern must not contain an element pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path list//ref) list_contains_list=a list pattern must not contain a list pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path list//list) list_contains_text=a list pattern must not contain a text pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path list//text) list_contains_interleave=a list pattern must not contain an interleave pattern (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path list//interleave) one_or_more_contains_group_contains_attribute=a group of attributes must not be repeatable (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path oneOrMore//group//attribute) one_or_more_contains_interleave_contains_attribute=an interleaved group of attributes must not be repeatable (section 7.1 of the RELAX NG specification requires that the simplified XML form of the schema not contain any elements matching the path oneOrMore//interleave//attribute) start_contains_attribute=found element matching the prohibited path start//attribute in the simplified XML form of the schema (see section 7.1 of the RELAX NG specification) start_contains_data=found element matching the prohibited path start//data in the simplified XML form of the schema (see section 7.1 of the RELAX NG specification) start_contains_empty=found element matching the prohibited path start//empty in the simplified XML form of the schema (see section 7.1 of the RELAX NG specification) start_contains_group=found element matching the prohibited path start//group in the simplified XML form of the schema (see section 7.1 of the RELAX NG specification) start_contains_interleave=found element matching the prohibited path start//interleave in the simplified XML form of the schema (see section 7.1 of the RELAX NG specification) start_contains_list=found element matching the prohibited path start//list in the simplified XML form of the schema (see section 7.1 of the RELAX NG specification) start_contains_one_or_more=found element matching the prohibited path start//oneOrMore in the simplified XML form of the schema (see section 7.1 of the RELAX NG specification) start_contains_text=found element matching the prohibited path start//text in the simplified XML form of the schema (see section 7.1 of the RELAX NG specification) start_contains_value=found element matching the prohibited path start//value in the simplified XML form of the schema (see section 7.1 of the RELAX NG specification) duplicate_attribute=duplicate attribute duplicate_attribute_name=duplicate attribute {0} duplicate_attribute_ns=attributes from namespace \"{0}\" can occur more than once interleave_element_overlap=overlapping element names in operands of \"interleave\" interleave_element_overlap_name=the element {0} can occur in more than one operand of \"interleave\" interleave_element_overlap_ns=elements from namespace \"{0}\" can occur in more than one operand of \"interleave\" interleave_text_overlap=both operands of \"interleave\" contain \"text\" open_name_class_not_repeated=attribute using \"nsName\" or \"anyName\" must be in \"oneOrMore\" xmlns_uri_attribute=attribute must not have namespace URI \"http://www.w3.org/2000/xmlns\" xmlns_attribute=attribute must not be named \"xmlns\" # Validation errors unknown_element=Element {0} ist nicht erlaubt{1} unexpected_element_required_element_missing=Das Element {0} ist an dieser Stelle noch nicht erlaubt. Es fehlt das Element {1} unexpected_element_required_elements_missing=Das Element {0} ist an dieser Stelle noch nicht erlaubt. Es fehlen die Elemente {1} element_not_allowed_yet=Element {0} ist an dieser Stelle noch nicht erlaubt{1} out_of_context_element=Element {0} ist an dieser Stelle nicht erlaubt{1} no_attributes_allowed=Attribut {0} vorhanden. Attribute sind an dieser Stelle jedoch nicht erlaubt! invalid_attribute_name=Attribut {0} ist an diesem Element nicht erlaubt{1} invalid_attribute_value=Der Wert des Attributs {0} ist ung\u00FCltig{1} required_attributes_missing_expected=Dem Element {0} fehlen ein oder mehrere erforderliche Attribute{1} required_attribute_missing=Dem Element {0} fehlt das erforderliche {1} Attribut required_attributes_missing=Dem Element {0} fehlen die folgenden erforderlichen Attribute: {1} incomplete_element_required_elements_missing_expected=Das Element {0} ist nicht vollst\u00E4ndig{1} incomplete_element_required_element_missing=Das Element {0} ist nicht vollst\u00E4ndig. Es fehlt das erforderliche Kind-Element {1} incomplete_element_required_elements_missing=Das Element {0} ist nicht vollst\u00E4ndig. Es fehlen die erforderlichen Kind-Elemente {1} text_not_allowed=Text ist an dieser Stelle nicht erlaubt{0} document_incomplete=Dokument scheint unvollst\u00E4ndig zu sein invalid_element_value=Der Inhalt des Elements {0} ist ung\u00FCltig{1} blank_not_allowed=Das Element {0} muss Inhalt besitzen{1} schema_allows_nothing=Das Schema erlaubt an dieser Stelle keine Elemente: # ID correctness errors id_element_name_class=an \"element\" pattern containing an \"attribute\" pattern with a non-null ID-type must have a name class that contains only \"choice\" and \"name\" elements id_attribute_name_class=an \"attribute\" pattern with a non-null ID-type must have a name class that is a single name id_parent=a \"data\" or \"value\" pattern with non-null ID-type must occur as the child of an \"attribute\" pattern id_type_conflict=conflicting ID-types for attribute {1} of element {0} # ID soundness errors id_no_tokens=Attributwert enth\u00E4lt keinen ID-Aufruf id_multiple_tokens=Attributwert enth\u00E4lt mehrere ID-Aufrufe idref_no_tokens=Attributwert enth\u00E4lt keinen IDREF-Aufruf idref_multiple_tokens=Attributwert enth\u00E4lt mehrere IDREF-Aufrufe idrefs_no_tokens=Attributwert enth\u00E4lt keine IDREF-Aufrufe missing_id=IDREF \"{0}\" ohne zugeh\u00F6rige ID duplicate_id=die ID \"{0}\" wurde bereits definiert first_id=erste Fundstelle der ID \"{0}\" # Fragments name_absent_namespace=\"{0}\" name_with_namespace=\"{1}\" aus dem Namespace \"{0}\" qname=\"{0}\" qnames_nsdecls={0} (mit {1}) or_list_pair={0} oder {1} or_list_many_first={0} or_list_many_middle={0}, {1} or_list_many_last={0} oder {1} and_list_pair={0} und {1} and_list_many_first={0} and_list_many_middle={0}, {1} and_list_many_last={0} und {1} expected=. Erwartet wird {0} element_end_tag=das Element-Ende-Tag text=Text data=Daten element_list=Element {0} element_other_ns=ein Element aus einem anderen Namespace expected_attribute=. Erlaubt ist nur das Attribut {0} expected_attribute_or_other_ns=. Erlaubte Attribute sind {0} oder Attribute aus einem anderen Namespace data_failures=; {0} token_failures=; Ausdruck {0} ist ung\u00FCltig; {1} missing_token=; fehlender Ausdruck; {0} expected_data=; erwartet werden Daten require_values=muss {0} gleichen require_qnames=muss ein QName sein, der {0} gleicht require_datatype=muss ein valider Datentyp vom Typ {0} sein epubcheck-4.0.2/src/main/resources/com/thaiopensource/datatype/0000755000175000017500000000000013017276730024124 5ustar eugeneeugeneepubcheck-4.0.2/src/main/resources/com/thaiopensource/datatype/xsd/0000755000175000017500000000000013017276730024722 5ustar eugeneeugeneepubcheck-4.0.2/src/main/resources/com/thaiopensource/datatype/xsd/resources/0000755000175000017500000000000013017276730026734 5ustar eugeneeugeneepubcheck-4.0.2/src/main/resources/com/thaiopensource/datatype/xsd/resources/Messages.properties0000644000175000017500000000741713017276730032632 0ustar eugeneeugene# First block doesn't need to be translated for epubcheck, as @murata0204 noted in # https://github.com/IDPF/epubcheck/pull/472#issuecomment-58265808 # # Non-unicode chars (german umlauts, etc..) must be escaped like \u00DF # because otherwise Jing can't parse them. Bad UTF8-support # Properties file specifying messages enumeration_param=\"enumeration\" facet is not allowed as a parameter: use \"value\" element instead whiteSpace_param=\"whiteSpace\" facet is not allowed as a parameter unrecognized_param=unrecognized parameter \"{0}\" invalid_regex=invalid regular expression: {0} not_ordered=parameter can only be applied to ordered datatype invalid_limit=\"{0}\" is not allowed by the base type: {1} no_length=base datatype does not define a units of length scale_not_derived_from_decimal=\"scale\" parameter can only be applied to datatype derived from \"decimal\" scale_not_non_negative_integer=\"scale\" parameter must be non negative integer length_not_non_negative_integer=\"length\" parameter must be non negative integer precision_not_derived_from_decimal=\"precision\" parameter can only be applied to datatype derived from \"decimal\" precision_not_positive_integer=\"precision\" parameter must be positive integer regex_impl_not_found=cannot find regular expression implementation; use JDK 1.4 or add Xerces2 to your classpath regex_internal_error=internal error in regular expression for datatype {0} # validation errors length_violation=must be {0} with length equal to {1} (actual length was {2}) max_length_violation=must be {0} with length at most {1} (actual length was {2}) min_length_violation=must be {0} with length at least {1} (actual length was {2}) min_inclusive_violation=must be {0} greater than or equal to {1} min_exclusive_violation=must be {0} greater than {1} max_inclusive_violation=must be {0} less than or equal to {1} max_exclusive_violation=must be {0} less than {1} pattern_violation=must be {0} matching the regular expression \"{1}\" entity_violation=must be a name declared in the DTD as an unparsed entity undeclared_prefix=must be a QName whose prefix, if any, is declared (prefix \"{0}\" is not declared) precision_violation=must be {0} with at most {1} significant digits (found {2} digits) precision_1_violation=must be {0} with exactly one significant digit (found {1} digits) # part of the point is to avoid ugly "digit(s)" in the error message scale_violation=must be a decimal number with at most {0} significant digits after the decimal point (found {1} digits) scale_0_violation=must be a decimal number without any significant digits after the decimal point scale_1_violation=must be a decimal number with at most one significant digit after the decimal point (found {0} digits) lexical_violation=must be {0} # fragments substituted in above lexical_space_string=a string lexical_space_uri=a URI lexical_space_boolean=a boolean lexical_space_decimal=a decimal number lexical_space_float=a floating-point number lexical_space_duration=a duration lexical_space_hex=a hexadecimal string lexical_space_base64=a base64 string lexical_space_integer=an integer lexical_space_name=an XML name lexical_space_ncname=an XML name without colons lexical_space_nmtoken=an XML NMTOKEN lexical_space_qname=an XML QName lexical_space_list=a whitespace-delimited list lexical_space_list_ncname=a list of XML names without colons lexical_space_list_nmtoken=a list of XML NMTOKENs lexical_space_date_y_m_d_time=an ISO date and time lexical_space_time=an ISO time lexical_space_date_y_m_d=an ISO date lexical_space_date_y_m=an ISO year and month lexical_space_date_y=a year lexical_space_date_m_d=an ISO month and day (of the form --MM-DD) lexical_space_date_m=an ISO month (of the form --MM) lexical_space_date_d=an ISO day of the month (of the form ---DD) lexical_space_language=an RFC 3066 language identifierepubcheck-4.0.2/src/main/resources/com/thaiopensource/datatype/xsd/resources/Messages_ja.properties0000755000175000017500000001305513017276730033302 0ustar eugeneeugene# First block doesn't need to be translated for epubcheck, as @murata0204 noted in # https://github.com/IDPF/epubcheck/pull/472#issuecomment-58265808 # # Non-unicode chars (german umlauts, etc..) must be escaped like \u00DF # because otherwise Jing can't parse them. Bad UTF8-support # Properties file specifying messages enumeration_param=\"enumeration\" facet is not allowed as a parameter: use \"value\" element instead whiteSpace_param=\"whiteSpace\" facet is not allowed as a parameter unrecognized_param=unrecognized parameter \"{0}\" invalid_regex=invalid regular expression: {0} not_ordered=parameter can only be applied to ordered datatype invalid_limit=\"{0}\" is not allowed by the base type: {1} no_length=base datatype does not define a units of length scale_not_derived_from_decimal=\"scale\" parameter can only be applied to datatype derived from \"decimal\" scale_not_non_negative_integer=\"scale\" parameter must be non negative integer length_not_non_negative_integer=\"length\" parameter must be non negative integer precision_not_derived_from_decimal=\"precision\" parameter can only be applied to datatype derived from \"decimal\" precision_not_positive_integer=\"precision\" parameter must be positive integer regex_impl_not_found=cannot find regular expression implementation; use JDK 1.4 or add Xerces2 to your classpath regex_internal_error=internal error in regular expression for datatype {0} # validation errors length_violation={0}\u306E\u9577\u3055\u306F {1} \u3067\u306A\u304F\u3066\u306F\u306A\u308A\u307E\u305B\u3093. (\u9577\u3055\u304C {2} \u3067\u3057\u305F) max_length_violation={0}\u306E\u9577\u3055\u306F\u6700\u5927 {1} \u307E\u3067\u3067\u3059. (\u9577\u3055\u304C {2} \u3067\u3057\u305F) min_length_violation={0}\u306E\u9577\u3055\u306F\u6700\u4F4E\u3067\u3082 {1} \u5FC5\u8981\u3067\u3059. (\u9577\u3055\u304C {2} \u3067\u3057\u305F) min_inclusive_violation={0}\u306F {1} \u3088\u308A\u5927\u304D\u3044\u304B\u307E\u305F\u306F\u7B49\u3057\u304F\u306A\u304F\u3066\u306F\u306A\u308A\u307E\u305B\u3093. min_exclusive_violation={0}\u306F {1} \u3088\u308A\u5927\u304D\u304F\u306A\u304F\u3066\u306F\u306A\u308A\u307E\u305B\u3093. max_inclusive_violation={0}\u306F {1} \u3088\u308A\u5C0F\u3055\u3044\u304B\u307E\u305F\u306F\u7B49\u3057\u304F\u306A\u304F\u3066\u306F\u306A\u308A\u307E\u305B\u3093. max_exclusive_violation={0}\u306F {1} \u3088\u308A\u5C0F\u3055\u304F\u306A\u304F\u3066\u306F\u306A\u308A\u307E\u305B\u3093. pattern_violation={0}\u306F\u4EE5\u4E0B\u306E\u6B63\u898F\u8868\u73FE\u306B\u30DE\u30C3\u30C1\u3057\u306A\u304F\u3066\u306F\u306A\u308A\u307E\u305B\u3093. \"{1}\" entity_violation=DTD\u3067\u5B9A\u7FA9\u3055\u308C\u305F\u89E3\u6790\u5BFE\u8C61\u5916\u5B9F\u4F53\u306E\u540D\u524D\u3067\u306A\u304F\u3066\u306F\u306A\u308A\u307E\u305B\u3093. undeclared_prefix=\u4FEE\u98FE\u540D(QName)\u3067\u306A\u304F\u3066\u306F\u306A\u308A\u307E\u305B\u3093. \u63A5\u982D\u8F9E\u304C\u3042\u308B\u306A\u3089\u5BA3\u8A00\u6E08\u307F\u3067\u306A\u304F\u3066\u306F\u306A\u308A\u307E\u305B\u3093. (\u63A5\u982D\u8F9E \"{0}\" \u304C\u5BA3\u8A00\u3055\u308C\u3066\u3044\u307E\u305B\u3093) precision_violation={0} \u306E\u6709\u52B9\u6841\u306F\u6700\u5927 {1} \u307E\u3067\u3067\u3059. ({2} \u6841\u3042\u308A\u307E\u3057\u305F) precision_1_violation={0} \u306E\u6709\u52B9\u6841\u306F\u3061\u3087\u3046\u3069 1 \u6841\u3067\u306A\u304F\u3066\u306F\u306A\u308A\u307E\u305B\u3093. ({1} \u6841\u3042\u308A\u307E\u3057\u305F) # part of the point is to avoid ugly "digit(s)" in the error message scale_violation=\u5C0F\u6570\u70B9\u4EE5\u4E0B\u306E\u6709\u52B9\u6841\u304C\u6700\u5927 {0} \u6841\u306E10\u9032\u6570\u3067\u306A\u304F\u3066\u306F\u306A\u308A\u307E\u305B\u3093. ({1} \u6841\u3042\u308A\u307E\u3057\u305F) scale_0_violation=\u5C0F\u6570\u70B9\u4EE5\u4E0B\u306E\u6841\u304C\u306A\u304410\u9032\u6570\u3067\u306A\u304F\u3066\u306F\u306A\u308A\u307E\u305B\u3093. scale_1_violation=\u5C0F\u6570\u70B9\u4EE5\u4E0B\u306E\u6709\u52B9\u6841\u304C\u6700\u5927 1 \u6841\u306E10\u9032\u6570\u3067\u306A\u304F\u3066\u306F\u306A\u308A\u307E\u305B\u3093. ({0} \u6841\u3042\u308A\u307E\u3057\u305F) lexical_violation={0}\u3067\u306A\u304F\u3066\u306F\u306A\u308A\u307E\u305B\u3093. # fragments substituted in above lexical_space_string=\u6587\u5B57\u5217 lexical_space_uri=URI lexical_space_boolean=\u771F\u507D\u5024(boolean) lexical_space_decimal=10\u9032\u6570 lexical_space_float=\u6D6E\u52D5\u5C0F\u6570\u70B9\u6570(float) lexical_space_duration=\u671F\u9593(duration) lexical_space_hex=16\u9032\u6587\u5B57\u5217 lexical_space_base64=BASE64\u6587\u5B57\u5217 lexical_space_integer=\u6574\u6570 lexical_space_name=XML\u540D(Name) lexical_space_ncname=\u30B3\u30ED\u30F3\u3092\u542B\u307E\u306A\u3044XML\u540D(NCName) lexical_space_nmtoken=XML\u306ENMTOKEN lexical_space_qname=XML\u4FEE\u98FE\u540D(QName) lexical_space_list=\u7A7A\u767D\u3067\u533A\u5207\u3089\u308C\u305F\u30EA\u30B9\u30C8 lexical_space_list_ncname=\u30B3\u30ED\u30F3\u3092\u542B\u307E\u306A\u3044XML\u540D\u306E\u30EA\u30B9\u30C8 lexical_space_list_nmtoken=XML\u306ENMTOKEN\u306E\u30EA\u30B9\u30C8 lexical_space_date_y_m_d_time=ISO\u5F62\u5F0F\u306E\u65E5\u6642 lexical_space_time=ISO\u5F62\u5F0F\u306E\u6642\u523B lexical_space_date_y_m_d=ISO\u5F62\u5F0F\u306E\u65E5\u4ED8 lexical_space_date_y_m=ISO\u5F62\u5F0F\u306E\u5E74\u6708 lexical_space_date_y=\u5E74 lexical_space_date_m_d=ISO\u5F62\u5F0F\u306E\u6708\u65E5(--MM-DD \u5F62\u5F0F) lexical_space_date_m=ISO\u5F62\u5F0F\u306E\u6708(--MM \u5F62\u5F0F) lexical_space_date_d=ISO\u5F62\u5F0F\u306E\u6708\u306E\u65E5(---DD \u5F62\u5F0F) lexical_space_language=RFC3066\u5F62\u5F0F\u306E\u8A00\u8A9E\u30B3\u30FC\u30C9 epubcheck-4.0.2/src/main/resources/com/thaiopensource/datatype/xsd/resources/Messages_fr.properties0000644000175000017500000001125713017276730033316 0ustar eugeneeugene# First block doesn't need to be translated for epubcheck, as @murata0204 noted in # https://github.com/IDPF/epubcheck/pull/472#issuecomment-58265808 # # Non-unicode chars (german umlauts, etc..) must be escaped like \u00DF # because otherwise Jing can't parse them. Bad UTF8-support # Properties file specifying messages enumeration_param=la facette \"enumeration\" n''est pas autoris\u00E9e en tant que param\u00E8tre : utiliser l'\u00E9l\u00E9ment \"value\". whiteSpace_param=la facette \"whiteSpace\" n''est pas autoris\u00E9e en tant que param\u00E8tre unrecognized_param=param\u00E8tre \"{0}\" non reconnu invalid_regex=expression r\u00E9guli\u00E8re invalide\u00A0: {0} not_ordered=le param\u00E8tre peut seulement \u00EAtre appliqu\u00E9 \u00E0 un type de donn\u00E9e ordonn\u00E9 invalid_limit=\"{0}\" n'est pas autoris\u00E9 par le type de base\u00A0: {1} no_length=le type de base ne d\u00E9finit pas une unit\u00E9 de longueur scale_not_derived_from_decimal=le param\u00E8tre \"scale\" ne peut \u00EAtre appliqu\u00E9 qu'aux types d\u00E9riv\u00E9s de \"decimal\" scale_not_non_negative_integer=le param\u00E8tre \"scale\" doit \u00EAtre un entier non n\u00E9gatif length_not_non_negative_integer=le param\u00E8tre \"length\" doit \u00EAtre un entier non n\u00E9gatif precision_not_derived_from_decimal=le param\u00E8tre \"precision\" ne peut \u00EAtre appliqu\u00E9 qu'aux types d\u00E9riv\u00E9s de \"decimal\" precision_not_positive_integer=le param\u00E8tre \"precision\" doit \u00EAtre un entier non n\u00E9gatif regex_impl_not_found=Aucun moteur d'expressions r\u00E9guli\u00E8res n'a pu \u00EAtre trouv\u00E9; utilisez JDK 1.4 ou ajoutez Xerces2 \u00E0 votre classpath regex_internal_error=erreur interne dans l'expression r\u00E9guli\u00E8re pour le type de donn\u00E9es {0} # validation errors length_violation=doit \u00EAtre {0} avec une longueur \u00E9gale \u00E0 {1} (la longueur trouv\u00E9e est {2}) max_length_violation=doit \u00EAtre {0} avec une longueur d'au plus {1} (la longueur trouv\u00E9e est {2}) min_length_violation=doit \u00EAtre {0} avec une longueur d'au moins {1} (la longueur trouv\u00E9e est {2}) min_inclusive_violation=doit \u00EAtre {0} sup\u00E9rieur ou \u00E9gal \u00E0 {1} min_exclusive_violation=doit \u00EAtre {0} sup\u00E9rieur \u00E0 {1} max_inclusive_violation=doit \u00EAtre {0} inf\u00E9rieur ou \u00E9gal \u00E0 {1} max_exclusive_violation=doit \u00EAtre {0} inf\u00E9rieur \u00E0 {1} pattern_violation=doit \u00EAtre {0} satisfaisant l'expression r\u00E9guli\u00E8re \"{1}\" entity_violation=doit \u00EAtre un nom d\u00E9clar\u00E9 dans la DTD en tant qu'entit\u00E9 non-pars\u00E9e undeclared_prefix=doit un \u00EAtre un QName avec un pr\u00E9fixe, si sp\u00E9cifi\u00E9, d\u00E9clar\u00E9 (le pr\u00E9fixe \"{0}\" n'est pas d\u00E9clar\u00E9) precision_violation=doit \u00EAtre {0} avec au plus {1} chiffres significatifs ({2} chiffres ont \u00E9t\u00E9 trouv\u00E9s) precision_1_violation=doit \u00EAtre {0} avec exactement un chiffre significatif ({1} chiffres ont \u00E9t\u00E9 trouv\u00E9s) # part of the point is to avoid ugly "digit(s)" in the error message scale_violation=doit \u00EAtre un nombre d\u00E9cimal avec au plus {0} chiffres significatifs apr\u00E8s la virgule ({1} chiffres ont \u00E9t\u00E9 trouv\u00E9s) scale_0_violation=doit \u00EAtre un nombre d\u00E9cimal sans aucun chiffre significatif apr\u00E8s la virgule scale_1_violation=doit \u00EAtre un nombre d\u00E9cimal avec au plus un chiffre significatif apr\u00E8s la virgule ({0} chiffres ont \u00E9t\u00E9 trouv\u00E9s) lexical_violation=doit \u00EAtre {0} # fragments substituted in above lexical_space_string=une cha\u00EEne de caract\u00E8res lexical_space_uri=une URI lexical_space_boolean=un bool\u00E9en lexical_space_decimal=un nombre d\u00E9cimal lexical_space_float=un nombre en virgule flottante lexical_space_duration=une dur\u00E9e lexical_space_hex=une cha\u00EEne hexad\u00E9cimale lexical_space_base64=une cha\u00EEne base64 lexical_space_integer=un entier lexical_space_name=un nom XML lexical_space_ncname=un nom XML sans double point lexical_space_nmtoken=un NMTOKEN XML lexical_space_qname=un QName XML lexical_space_list=une liste d\u00E9limit\u00E9e pas espaces blancs lexical_space_list_ncname=une liste de noms XML sans doubles points lexical_space_list_nmtoken=une liste de NMTOKENs XML lexical_space_date_y_m_d_time=une date et heure ISO lexical_space_time=une heure ISO lexical_space_date_y_m_d=une date ISO lexical_space_date_y_m=une ann\u00E9e et mois ISO lexical_space_date_y=une ann\u00E9e lexical_space_date_m_d=un mois et jour ISO (de forme --MM-DD) lexical_space_date_m=un mois ISO (de forme --MM) lexical_space_date_d=un jour ISO (de forme --DD) lexical_space_language=un identificateur de langage RFC 3066 epubcheck-4.0.2/src/main/resources/com/thaiopensource/datatype/xsd/resources/Messages_es.properties0000644000175000017500000001013613017276730033311 0ustar eugeneeugene# First block doesn't need to be translated for epubcheck, as @murata0204 noted in # https://github.com/IDPF/epubcheck/pull/472#issuecomment-58265808 # # Non-unicode chars (german umlauts, etc..) must be escaped like \u00DF # because otherwise Jing can't parse them. Bad UTF8-support # Properties file specifying messages enumeration_param=\"enumeration\" no es un par\u00E1metro v\u00E1lido: utilice el elemento \"value\" en su lugar whiteSpace_param=\"whiteSpace\" no es un par\u00E1metro v\u00E1lido unrecognized_param=\"{0}\" es un par\u00E1metro desconocido invalid_regex=expresi\u00F3n regular no v\u00E1lida: {0} not_ordered=el par\u00E1metro solo puede aplicarse al datatype ordenado invalid_limit=\"{0}\" no est\u00E1 permitido por el tipo base: {1} no_length=el datatype base no define la unidad de longitud scale_not_derived_from_decimal=el par\u00E1metro \"scale\" solo puede aplicarse al datatype derivado de \"decimal\" scale_not_non_negative_integer=el par\u00E1metro \"scale\" debe ser un n\u00FAmero entero no negativo length_not_non_negative_integer=el par\u00E1metro \"length\" debe ser un n\u00FAmero entero no negativo precision_not_derived_from_decimal=el par\u00E1metro \"precision\" solo se aplica al datatype derivado de \"decimal\" precision_not_positive_integer=el par\u00E1metro \"precision\" debe ser un n\u00FAmero entero positivo regex_impl_not_found=no se ha encontrado la implementaci\u00F3n de la expresi\u00F3n regular; utilice JDK 1.4 o a\u00F1ada Xerces2 a su ruta regex_internal_error=error interno en la expresi\u00F3n regular para el datatype {0} # validation errors length_violation=debe ser {0} con una longitud igual a {1} (la longitud es de {2}) max_length_violation=debe ser {0} con una longitud m\u00E1xima de {1} (la longitud es de {2}) min_length_violation=debe ser {0} con una longitud de al menos {1} (la longitud es de {2}) min_inclusive_violation=debe ser {0} mayor o igual que {1} min_exclusive_violation=debe ser {0} mayor que {1} max_inclusive_violation=debe ser {0} menor o igual que {1} max_exclusive_violation=debe ser {0} menor que {1} pattern_violation=debe ser {0} que concuerde con la expresi\u00F3n regular \"{1}\" entity_violation=debe ser un nombre declarado en e DTD como entidad no analizada undeclared_prefix=debe ser un QName cuyo prefijo, si existe, se haya declarado (el prefijo \"{0}\" no se ha declarado) precision_violation=debe ser {0} con un m\u00E1ximo de {1} d\u00EDgito (hay {2} d\u00EDgitos) precision_1_violation=debe ser {0} con un solo d\u00EDgito (hay {1} d\u00EDgitos) # part of the point is to avoid ugly "digit(s)" in the error message scale_violation=debe ser un n\u00FAmero decimal con un m\u00E1ximo de {0} d\u00EDgitos despu\u00E9s del punto (hay {1} d\u00EDgitos) scale_0_violation=debe ser un n\u00FAmero decimal sin d\u00EDgitos despu\u00E9s del punto scale_1_violation=debe ser un n\u00FAmero decimal con un m\u00E1ximo de 1 d\u00EDgito despu\u00E9s del punto (hay {0} d\u00EDgitos) lexical_violation=debe ser {0} # fragments substituted in above lexical_space_string=una cadena lexical_space_uri=un URI lexical_space_boolean=un operador booleano lexical_space_decimal=un n\u00FAmero decimal lexical_space_float=un n\u00FAmero de punto flotante lexical_space_duration=una duraci\u00F3n lexical_space_hex=una cadena hexadecimal lexical_space_base64=una cadena base64 lexical_space_integer=un n\u00FAmero entero lexical_space_name=un nombre XML lexical_space_ncname=un nombre XML sin dos puntos lexical_space_nmtoken=un NMTOKEN XML lexical_space_qname=un QName XML lexical_space_list=una lista delimitada por espacios en blanco lexical_space_list_ncname=una lista de nombres XML sin puntos lexical_space_list_nmtoken=una lista de NMTOKENs XML lexical_space_date_y_m_d_time=una fecha y hora ISO lexical_space_time=una hora ISO lexical_space_date_y_m_d=una fecha ISO lexical_space_date_y_m=un a\u00F1o y mes ISO lexical_space_date_y=un a\u00F1o lexical_space_date_m_d=un d\u00EDa y mes ISO (con el formato --MM-DD) lexical_space_date_m=un mes ISO (con el formato --MM) lexical_space_date_d=un d\u00EDa del mes ISO (con el formato ---DD) lexical_space_language=un identificador de idioma RFC 3066 epubcheck-4.0.2/src/main/resources/com/thaiopensource/datatype/xsd/resources/Messages_it.properties0000644000175000017500000001046613017276730033324 0ustar eugeneeugene# This is the Italian translation of org/thaiopensource/datatype/xsd/resources/Messages.properties file. # Translation by Alberto Pettarin (https://github.com/pettarin) # # The first block doesn't need to be translated for epubcheck, as @murata0204 noted in # https://github.com/IDPF/epubcheck/pull/472#issuecomment-58265808 # # Non-unicode chars (german umlauts, etc..) must be escaped like \u00DF # because otherwise Jing can't parse them. (Bad UTF-8 support.) # Properties file specifying messages enumeration_param=\"enumeration\" facet is not allowed as a parameter: use \"value\" element instead whiteSpace_param=\"whiteSpace\" facet is not allowed as a parameter unrecognized_param=unrecognized parameter \"{0}\" invalid_regex=invalid regular expression: {0} not_ordered=parameter can only be applied to ordered datatype invalid_limit=\"{0}\" is not allowed by the base type: {1} no_length=base datatype does not define a units of length scale_not_derived_from_decimal=\"scale\" parameter can only be applied to datatype derived from \"decimal\" scale_not_non_negative_integer=\"scale\" parameter must be non negative integer length_not_non_negative_integer=\"length\" parameter must be non negative integer precision_not_derived_from_decimal=\"precision\" parameter can only be applied to datatype derived from \"decimal\" precision_not_positive_integer=\"precision\" parameter must be positive integer regex_impl_not_found=cannot find regular expression implementation; use JDK 1.4 or add Xerces2 to your classpath regex_internal_error=internal error in regular expression for datatype {0} # validation errors length_violation=espressione non valida: {0} deve avere lunghezza {1} (ora: {2}) max_length_violation=espressione non valida: {0} deve avere una lunghezza massima di {0} (ora: {2}) min_length_violation=espressione non valida: {0} deve avere una lunghezza minima di {0} (ora: {2}) min_inclusive_violation=espressione non valida: {0} deve essere maggiore o uguale a {1} min_exclusive_violation=espressione non valida: {0} deve essere maggiore di {1} max_inclusive_violation=espressione non valida: {0} deve essere minore o uguale a {1} max_exclusive_violation=espressione non valida: {0} deve essere minore di {1} pattern_violation=espressione non valida: {0} non soddisfa l''espressione regolare {1} entity_violation=espressione non valida: {0} deve essere un nome dichiarato nel DTD come \"unparsed entity\" undeclared_prefix=espressione non valida: {0} deve essere un nome qualificato dichiarato precision_violation=espressione non valida: {0} deve avere almeno {1} cifre decimali (ora: {2}) precision_1_violation=espressione non valida: {0} deve avere al massimo una cifra decimale (ora: {1}) # part of the point is to avoid ugly "digit(s)" in the error message scale_violation=espressione non valida: deve essere un numero con almeno {0} cifre decimali (ora: {1}) scale_0_violation=espressione non valida: deve essere un numero senza cifre decimali scale_1_violation=espressione non valida: deve essere un numero con al massimo una cifra decimale (ora: {1}) lexical_violation=espressione non valida: {0} costrutto non riconosciuto # fragments substituted in above lexical_space_string=una stringa lexical_space_uri=uno URI lexical_space_boolean=un booleano lexical_space_decimal=un numero decimale lexical_space_float=un numero decimale (float) lexical_space_duration=una durata temporale lexical_space_hex=una stringa esadecimale lexical_space_base64=una stringa in Base64 lexical_space_integer=un intero lexical_space_name=un nome XML lexical_space_ncname=un nome XML senza due punti (ncname) lexical_space_nmtoken=un token XML (nmtoken) lexical_space_qname=un nome XML qualificato (qname) lexical_space_list=una lista di nomi XML separati da uno spazio lexical_space_list_ncname=una lista di nomi XML senza due punti (ncname) lexical_space_list_nmtoken=una lista di token XML (nmtoken) lexical_space_date_y_m_d_time=una data e ora in formato ISO lexical_space_time=una ora in formato ISO lexical_space_date_y_m_d=una data (YYYY-MM-DD) in formato ISO lexical_space_date_y_m=una data (YYYY-MM) in formato ISO lexical_space_date_y=una data (YYYY) in formato ISO lexical_space_date_m_d=una data (MM-DD) in formato ISO lexical_space_date_m=una data (MM) in formato ISO lexical_space_date_d=una data (DD) in formato ISO lexical_space_language=un codice lingua in formato RFC 3066 epubcheck-4.0.2/src/main/resources/com/thaiopensource/datatype/xsd/resources/Messages_de.properties0000644000175000017500000001013713017276730033273 0ustar eugeneeugene# First block doesn't need to be translated for epubcheck, as @murata0204 noted in # https://github.com/IDPF/epubcheck/pull/472#issuecomment-58265808 # # Non-unicode chars (german umlauts, etc..) must be escaped like \u00DF # because otherwise Jing can't parse them. Bad UTF8-support # Properties file specifying messages enumeration_param=\"enumeration\" facet is not allowed as a parameter: use \"value\" element instead whiteSpace_param=\"whiteSpace\" facet is not allowed as a parameter unrecognized_param=unrecognized parameter \"{0}\" invalid_regex=invalid regular expression: {0} not_ordered=parameter can only be applied to ordered datatype invalid_limit=\"{0}\" is not allowed by the base type: {1} no_length=base datatype does not define a units of length scale_not_derived_from_decimal=\"scale\" parameter can only be applied to datatype derived from \"decimal\" scale_not_non_negative_integer=\"scale\" parameter must be non negative integer length_not_non_negative_integer=\"length\" parameter must be non negative integer precision_not_derived_from_decimal=\"precision\" parameter can only be applied to datatype derived from \"decimal\" precision_not_positive_integer=\"precision\" parameter must be positive integer regex_impl_not_found=cannot find regular expression implementation; use JDK 1.4 or add Xerces2 to your classpath regex_internal_error=internal error in regular expression for datatype {0} # validation errors length_violation=es muss {0} sein, mit einer exakten L\u00E4nge von {1} (L\u00E4nge ist derzeit {2}) max_length_violation=es muss {0} sein, mit einer maximalen L\u00E4nge von {1} (L\u00E4nge ist derzeit {2}) min_length_violation=es muss {0} sein, mit einer minimalen L\u00E4nge von {1} (L\u00E4nge ist derzeit {2}) min_inclusive_violation=es muss {0} sein, gr\u00F6\u00DFer gleich {1} min_exclusive_violation=es muss {0} sein, gr\u00F6\u00DFer als {1} max_inclusive_violation=es muss {0} sein, kleiner gleich {1} max_exclusive_violation=es muss {0} sein, kleiner als {1} pattern_violation=es muss {0} sein, der auf folgenden regul\u00E4ren Ausdruck zutrifft: \"{1}\" entity_violation=es muss ein Name sein, der in der DTD als 'unparsed entity' deklariert ist undeclared_prefix=es muss ein QName sein, dessen Pr\u00E4fix deklariert ist, falls vorhanden (Pr\u00E4fix \"{0}\" ist nicht deklariert) precision_violation=es muss {0} sein, mit mindestens {1} signifikanten Stellen (gefundene Stellen: {2}) precision_1_violation=es muss {0} sein, mit genau einer signifikanten Stelle (gefundene Stellen: {1}) # part of the point is to avoid ugly "digit(s)" in the error message scale_violation=es muss eine Dezimalzahl mit mindestens {0} Nachkommastellen sein (gefundene Stellen: {1}) scale_0_violation=es muss eine Dezimalzahl ohne Nachkommastellen sein scale_1_violation=es muss eine Dezimalzahl mit maximal einer Nachkommastelle sein (gefundene Stellen: {1}) lexical_violation=es muss {0} sein # fragments substituted in above lexical_space_string=ein String lexical_space_uri=eine URI lexical_space_boolean=ein Boolean lexical_space_decimal=eine Dezimalzahl lexical_space_float=eine Flie\u00DFkommazahl lexical_space_duration=eine Zeitangabe lexical_space_hex=ein hexadezimaler String lexical_space_base64=ein Base64-String lexical_space_integer=ein Integer-Wert lexical_space_name=ein XML-Name lexical_space_ncname=ein XML-Name ohne Doppelpunkt lexical_space_nmtoken=ein XML-NMTOKEN lexical_space_qname=ein XML-QName lexical_space_list=eine Leerzeichen-separierte Liste lexical_space_list_ncname=eine Liste von XML-Namen ohne Doppelpunkt lexical_space_list_nmtoken=eine Liste von XML-NMTOKENs lexical_space_date_y_m_d_time=ein Datums- und Zeitangabe im ISO-Format lexical_space_time=eine Zeitangabe im ISO-Format lexical_space_date_y_m_d=ein Datum im ISO-Format lexical_space_date_y_m=Jahr und Monat im ISO-Format lexical_space_date_y=eine Jahresangabe lexical_space_date_m_d=eine Datumsangabe im ISO-Format f\u00FCr Monat und Tag (in der Form --MM-DD) lexical_space_date_m=ein Monat im ISO-Format (in der Form --MM) lexical_space_date_d=ein Tage im Monat im ISO-Format (in der Form ---DD) lexical_space_language=eine Sprachangabe im RFC-3066-Format epubcheck-4.0.2/src/main/resources/com/thaiopensource/validate/0000755000175000017500000000000013017276730024102 5ustar eugeneeugeneepubcheck-4.0.2/src/main/resources/com/thaiopensource/validate/schematron/0000755000175000017500000000000013017276730026245 5ustar eugeneeugeneepubcheck-4.0.2/src/main/resources/com/thaiopensource/validate/schematron/resources/0000755000175000017500000000000013017276730030257 5ustar eugeneeugene././@LongLink0000644000000000000000000000015000000000000011577 Lustar rootrootepubcheck-4.0.2/src/main/resources/com/thaiopensource/validate/schematron/resources/Messages.propertiesepubcheck-4.0.2/src/main/resources/com/thaiopensource/validate/schematron/resources/Messages.propert0000644000175000017500000000115013017276730033440 0ustar eugeneeugeneunexpected_schema_creation_error=could not create schema (please file a bug report) # these messages are used in schematron.xsl extends_cycle=cannot extend rule \"{0}\" because the extends chain has a cycle active_missing=cannot activate non-existent pattern \"{0}\" extends_missing=cannot extend non-existent rule \"{0}\" extends_concrete=cannot extend rule \"{0}\" because it is not abstract phase_missing=the schema does not define a phase \"{0}\" default_phase_missing=the schema does not define its default phase \"{0}\" diagnostic_missing=reference to non-existent diagnostic \"{0}\" report= failed_assertion= ././@LongLink0000644000000000000000000000015300000000000011602 Lustar rootrootepubcheck-4.0.2/src/main/resources/com/thaiopensource/validate/schematron/resources/Messages_ja.propertiesepubcheck-4.0.2/src/main/resources/com/thaiopensource/validate/schematron/resources/Messages_ja.prop0000644000175000017500000000254013017276730033403 0ustar eugeneeugeneunexpected_schema_creation_error=\u30B9\u30AD\u30FC\u30DE\u3092\u4F5C\u308B\u3053\u3068\u304C\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F(epubcheck\u306E\u30D0\u30B0\u306E\u305F\u3081\u3001\u958B\u767A\u8005\u306B\u3054\u5831\u544A\u304F\u3060\u3055\u3044) # these messages are used in schematron.xsl extends_cycle=\u62E1\u5F35\u30C1\u30A7\u30A4\u30F3\u306B\u5FAA\u74B0\u304C\u898B\u3064\u304B\u3063\u305F\u305F\u3081\u3001\u30EB\u30FC\u30EB \"{0}\" \u3092\u62E1\u5F35\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F active_missing=\u5B58\u5728\u3057\u306A\u3044\u30D1\u30BF\u30FC\u30F3 \"{0}\" \u3092\u30A2\u30AF\u30C6\u30A3\u30D9\u30FC\u30C8\u3067\u304D\u307E\u305B\u3093 extends_missing=\u5B58\u5728\u3057\u306A\u3044\u30EB\u30FC\u30EB \"{0}\" \u3092\u62E1\u5F35\u3067\u304D\u307E\u305B\u3093 extends_concrete=abstract\u3067\u306F\u306A\u3044\u30EB\u30FC\u30EB \"{0}\" \u3092\u62E1\u5F35\u3067\u304D\u307E\u305B\u3093 phase_missing=\u30B9\u30AD\u30FC\u30DE\u306F\u30D5\u30EC\u30FC\u30BA \"{0}\" \u3092\u5B9A\u7FA9\u3057\u3066\u3044\u307E\u305B\u3093 default_phase_missing=\u30B9\u30AD\u30FC\u30DE\u306F\u30C7\u30D5\u30A9\u30EB\u30C8\u306E\u30D5\u30EC\u30FC\u30BA \"{0}\" \u3092\u5B9A\u7FA9\u3057\u3066\u3044\u307E\u305B\u3093 diagnostic_missing=\u5B58\u5728\u3057\u306A\u3044diagnostic \"{0}\" \u3092\u53C2\u7167\u3057\u3066\u3044\u307E\u3059 report= failed_assertion= ././@LongLink0000644000000000000000000000015300000000000011602 Lustar rootrootepubcheck-4.0.2/src/main/resources/com/thaiopensource/validate/schematron/resources/Messages_fr.propertiesepubcheck-4.0.2/src/main/resources/com/thaiopensource/validate/schematron/resources/Messages_fr.prop0000644000175000017500000000144013017276730033416 0ustar eugeneeugeneunexpected_schema_creation_error=la cr\u00E9ation de schema a \u00E9chou\u00E9 (merci d'envoyer un rapport de bug) # these messages are used in schematron.xsl extends_cycle=la r\u00E8gle \"{0}\" ne peut pas \u00EAtre \u00E9tendue pour cause de cycle dans l'extension active_missing=le motif \"{0}\" n'existe pas et ne peut pas \u00EAtre activ\u00E9 extends_missing=la r\u00E8gle \"{0}\" n'existe pas et ne peut pas \u00EAtre \u00E9tendue extends_concrete=la r\u00E8gle \"{0}\" n'est pas abstraite donc ne peut pas \u00EAtre \u00E9tendue phase_missing=le sch\u00E9ma ne d\u00E9finit pas la phase \"{0}\" default_phase_missing=le sch\u00E9ma ne d\u00E9finit pas sa phase par d\u00E9faut \"{0}\" diagnostic_missing=r\u00E9f\u00E9rence au diagnostique \"{0}\" qui n'existe pas report= failed_assertion= ././@LongLink0000644000000000000000000000015300000000000011602 Lustar rootrootepubcheck-4.0.2/src/main/resources/com/thaiopensource/validate/schematron/resources/Messages_es.propertiesepubcheck-4.0.2/src/main/resources/com/thaiopensource/validate/schematron/resources/Messages_es.prop0000644000175000017500000000124013017276730033414 0ustar eugeneeugeneunexpected_schema_creation_error=no se ha podido crear el esquema (env\u00EDe reporte de errores) # these messages are used in schematron.xsl extends_cycle=no se pudo extender la regla \"{0}\" porque la cadena de extensiones tiene un ciclo active_missing=no se pudo activar el patr\u00F3n inexistente \"{0}\" extends_missing=no se pudo extender la regla inexistente \"{0}\" extends_concrete=no se pudo extender la regla \"{0}\" porque no es abstracta phase_missing=el esquema no define una fase \"{0}\" default_phase_missing=el esquema no define su fase por defecto \"{0}\" diagnostic_missing=referencia a un diagn\u00F3stico inexistente \"{0}\" report= failed_assertion= ././@LongLink0000644000000000000000000000015300000000000011602 Lustar rootrootepubcheck-4.0.2/src/main/resources/com/thaiopensource/validate/schematron/resources/Messages_de.propertiesepubcheck-4.0.2/src/main/resources/com/thaiopensource/validate/schematron/resources/Messages_de.prop0000644000175000017500000000146613017276730033407 0ustar eugeneeugeneunexpected_schema_creation_error=Konnte das Schematron-Schema nicht erstellen. Bitte erstelle einen Bug-Report auf https://github.com/IDPF/epubcheck/issues/new # these messages are used in schematron.xsl extends_cycle=Kann die Regel \"{0}\" nicht erweitern, da die Erweiterungs-Verkettung eine zirkul\u00E4re Verkettung enth\u00E4lt. active_missing=Kann das Pattern \"{0}\" nicht aktivieren, da es nicht existiert. extends_missing=Kann die Regel \"{0}\" nicht erweitern, da sie nicht existiert. extends_concrete=Kann die Regel \"{0}\" nicht erweitern, da sie nicht abstrakt ist. phase_missing=Das Schematron-Schema besitzt keine Phase \"{0}\" default_phase_missing=Das Schematron-Schema definiert keine Standard-Phase \"{0}\" diagnostic_missing=Referenz auf 'diagnostic' \"{0}\" existiert nicht. report= failed_assertion= epubcheck-4.0.2/src/main/resources/com/adobe/0000755000175000017500000000000013017276730020333 5ustar eugeneeugeneepubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/0000755000175000017500000000000013017276730022264 5ustar eugeneeugeneepubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/messages/0000755000175000017500000000000013017276730024073 5ustar eugeneeugeneepubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/messages/MessageBundle_es.properties0000644000175000017500000005737713017276730031441 0ustar eugeneeugene# This is the default MessageBundle.properties file #Accessibility ACC_001=los elementos HTML 'img' o 'area' no tienen atributo 'alt'. ACC_002=el elemento HTML 'input' no se referencia adecuadamente mediante un elemento que lo etiquete. ACC_003=los elementos HTML no textuales deben incluir un atributo 'title' para favorecer la accesibilidad. ACC_004=el elemento HTML 'a' debe contener texto. ACC_005=Las celdas de cabecera de tabla deben identificarse con etiquetas 'th' para favorecer la accesibilidad. ACC_006=Las tablas debe tener un elemento 'thead' para favorecer la accesibilidad. ACC_007=Los archivos de contenido no utilizan el atributo 'epub:type' para asignar semántica. ACC_008=El archivo de navegación o índice no contiene un elemento 'landmarks nav'. ACC_009=MathML debe tener un atributo de texto 'alt' o un elemento annotation-xml hijo. ACC_010=Los encbezados no deben utilizarse dentro de etiquetas 'blockquote' o 'figure'. ACC_011=Los enlaces SVG deberían tener un título legible (mediante el uso del elemento-hijo 'title' o el atributo 'xlink:title'). ACC_012=Las tablas deben incluir un elemento 'caption'. ACC_013=Un archivo de contenido tiene al menos una declaración interna de estilo. ACC_013_SUG=Los estilos internos no son compatibles con las opciones de accesibilidad y ajustes personalizados. Utilice estilos CSS. ACC_014=El valor de la propiedad CSS 'font-size' no usa medidas relativas. ACC_014_SUG=Los valores válidos incluyen porcentajes, unidades em, 'larger', 'smaller', 'normal' o 'inherit'. ACC_015=El valor de la propiedad CSS 'line-height' no usa medidas relativas. ACC_015_SUG=Los valores válidos incluyen porcentajes, unidades numéricas, 'larger', 'smaller', 'normal' o 'inherit'. ACC_016=El valor de la propiedad CSS 'font-size' debe usar medidas relativas. ACC_016_SUG=Los valores válidos incluyen porcentajes, unidades em, 'larger', 'smaller', 'normal' o 'inherit'. ACC_017=El valor de la propiedad CSS 'line-height' debe usar medidas relativas. ACC_017_SUG=Los valores válidos incluyen porcentajes, unidades numéricas, 'larger', 'smaller', 'normal' o 'inherit'. #Checker Errors CHK_001=El archivo de mensajes persoanlizado no se encuentra. CHK_002=Id de mensaje personalizado no reconocido %1$s hallado en archivo de mensajes personalizado '%2$s'. CHK_003=Gravedad de mensaje personalizad no reconocido '%1$s' hallado en archivo de mensajes personalizado '%2$s'. CHK_004=El mensaje personalizado contiene demasiados parámetros en archivo de mensajes personalizado '%1$s'. CHK_005=La sugerencia personalizada contiene demasiados parámetros en archivo de mensajes personalizado '%1$s'. CHK_006=No es posible analizar el parámetro de formato hallado en archivo de mensajes personalizado '%1$s'. CHK_007=Error hallado en archivo de mensajes personalizado '%1$s': "%2$s". #CSS CSS_001=La propiedad \'%1$s\' no debe incluirse en la hoja de estilos del EPUB. CSS_002=Se ha encontrado una referencia vacía o NULL. CSS_003=Solo se permiten codificaciones UTF-8 y UTF-16: detectado %1$s. CSS_004=Solo se permiten codificaciones UTF-8 y UTF-16: detectado %1$s BOM. CSS_005=Se han encontrado conflictos con alternancias de estilos: %1$s. CSS_006=La propiedad CSS 'position:fixed' no debe utilizarse en EPUBs. CSS_007=La propiedad 'font-face' %1$s hace referencia a un tipo de fuente no estándar %2$s. CSS_008=Ha ocurrido un error analizando el archivo CSS: %1$s. CSS_009=El uso de elementos CSS como columnas, transformaciones, transiciones, modelos de caja o KeyFrames puede causar errores de paginación. CSS_010=Una hoja de estilos de tipo distinto a "text/css" debe contar con un fallback. CSS_011=Número excesivo de archivos CSS. CSS_011_SUG=Valore la posibilidad de combinar archivos CSS en un solo archivo. CSS_012=El documento enlaza a múltiples archivos CSS. CSS_013=La propiedad CSS se declara como !important. CSS_015=La hoja de estilos alternativa no tiene un título. CSS_016=La hoja de estilos alternativa precede a la principal. CSS_017=El selector CSS especifica una posición absoluta. CSS_019=La propiedad CSS 'font-face' no contiene atributos. CSS_020=La declaración CSS de selección de fuente utilizada un valor 'font-size' no válido: '%1$s'. CSS_020_SUG=Acceptable values include percentages, em multiples, 'larger', 'smaller', 'normal' or 'inherit'. CSS_021=La propiedad CSS 'font-family' especifica una fuente de sistema no válida. CSS_021_SUG=Los valores válidos incluyen 'caption', 'icon', 'menu', 'message-box', 'small-caption', 'status-bar' o 'inherit'. CSS_022=El selector CSS especifica un valor de margen global. CSS_023=El selector CSS especifica un media query. CSS_024=El selector de clase CSS no se utiliza. CSS_024_SUG=Elimine los selectores CSS no usados. CSS_025=No se encuentra el selector de clase CSS. CSS_025_SUG=Compruebe la sintaxis o defina un selector de clase para documentar el uso de la clase. CSS_027=El selector CSS especifica una posición absoluta. CSS_028=Uso de declaración 'font-face'. #HTM - XHTML related messages HTM_001=Los recursos con media type basados en XML deben ser documentos XML 1.0 válidos. La versión XML utilizada es: %1$s. HTM_002=El analizador XML instalado no soporta la verificación de versiones XML. Los archivos XML deben ser documentos XML 1.0 válidos. HTM_003=No se permiten entidades externas en documentos EPUB v3. Se ha encontrado la siguiente entidad externa: %1$s. HTM_004=El DOCTYPE no es válido: se ha encontrado '%1$s', y se esperaba '%2$s'. HTM_005=Se ha encontrado una referencia externa. HTM_006=Se ha encontrado una entidad XHTML. HTM_007=El valor del atributo ssml:ph está vacío o solo contiene espacios. HTM_008=El atributo src es obligatorio. HTM_009=El DOCTYPE incluido es obsoleto o irregular y puede ser eliminado. HTM_010=Se ha encontrado el espacio de nombre '%1$s'. HTM_011=No se ha declarado la entidad. HTM_011_SUG=Defina la entidad o utilice la entidad numerada en su lugar. HTM_012=Se ha encontrado un enlace al CFI en un libro externo. HTM_013=Se han encontrado CFIs interno en el documento. HTM_014=Extensión de archivo no válida en el archivo HTML: se esperaba html, htm o xhtml. HTM_014a=El bombre de archivo para el documento XHTML '%1$s' dbería tener la extensión '.xhtml'. HTM_015=Definición HTML4 DOCTYPE incluida en EPUB v3. HTM_016=Definición HTML5 DOCTYPE incluida en EPUB v2. HTM_017=El archivo tiene valores de idioma diferentes en los atributos xml:lang y lang. HTM_018=El archivo tiene una definición de idioma no válida en el atributo xml:lang. HTM_019=El archivo tiene una definición de idioma no válida en el atributo lang. HTM_020=El archivo no contiene un atributo xml:lang. HTM_021=El archivo no contiene un atributo lang. HTM_022=El documento puede contener un número excesivo de etiquetas

o . HTM_022_SUG=Combine las etiquetas
y cuando sean consecutivas y utilice el mismo estilo. HTM_023=Se ha encontrado una entidad XHTML no válida: '%1$s'. HTM_023_SUG=Compruebe la sintaxis o utilice entidades numeradas en su lugar. HTM_024=Se ha encontrado una entidad XHTML. Solo se permiten '&' ''' '"e;' '<' o '>'. HTM_024_SUG=Compruebe la sintaxis o utilice entidades numeradas en su lugar. HTM_025=Se ha encontrado un tipo de esquema URI no registrado en el atributo href. HTM_027=La lista contiene menos de 2 elementos. HTM_027_SUG=Las listas deberían tener más de un elemento para favorecer la accesibilidad. HTM_028=Los elementos HTML input deben incluir una id. HTM_029=Los elementos HTML label deben incluir un atributo 'for' que haga referencia a la id de un elemento input. HTM_033=El elemento HTML 'head' no tiene un elemento hijo 'title'. HTM_036=Se desaconseja el uso de iframes. HTM_038=Asegúrese que los elementos b, i, em y strong se utilizan de acuerdo con las directivas HTML5 del W3C. HTM_038_SUG=Los estilos CSS son más apropiados para marcar el texto en negritas o cursivas. HTM_043=Los elementos SVG deben incluir atributos xml:lang y lang. HTM_044=El espacio de nombre URI '%1$s' está incluido, pero no se ha utilizado. HTM_044_SUG=Elimine espacios de nombre URI no utilizados. HTM_045=Se ha encontrado un href vacío. HTM_045_SUG=Los hrefs vacíos son auto-referencias válidas. Deben ser validados para asegurarse de que se incluyen intencionadamente. HTM_046=Un elemento con formato fijo no tiene medidas definidas para el viewport. HTM_046_SUG=Una declaración viewport es obligatoria para elementos con formato fijo. HTM_047=El viewport HTML no tiene atributo height y/o width. HTM_047_SUG=El viewport debe declarar tanto la anchura (width) como la altura (height). HTM_048=El SVG ViewBox no se encuentra en el documento de formato fijo. HTM_048_SUG=La declaración viewBox es obligtoria para documentos con formato fijo. HTM_049=El elemento html no tiene una declaración xmlns que apunte a 'http://www.w3.org/1999/xhtml'. HTM_049_SUG=Añada xmlns="http://www.w3.org/1999/xhtml" al elemento html. HTM_050=Se ha encontrado un atributo epub:type="pagebreak" en el documento. HTM_051=Se han encontrado enriquecimientos semánticos Microdata pero no RDFa. EDUPUB recomienda utilizar RDFa Lite. HTM_052=La propiedad 'region-based' solo está permitida para elementos nav en Documentos de Datos de Navegación. #media MED_001=El poster de vídeo debe ser un tipo de imagen soportado. MED_002=El elemento %1$s no incluye fallback. MED_003=Se ha encontrado un recurso de imagen no estándar de tipo %1$s. MED_004=La cabecera del archivo de imagen puede estar dañada. MED_005=Se ha encontrado un recurso de audio Media Overlay %1$s que hace referencia a un tipo de audio no estándar %2$s. MED_006=Algunos navegadores no soportan imágenes SVG que utilizan nombres de archivo en la propiedad xlink:href. #NAV EPUB v3 Table of contents NAV_001=El archivo nav no está soportado en EPUB v2. NAV_002=Se ha encontrado epub:type="page-list" en el archivo nav. NAV_003=El Documento de Navegación debe tener un listado de páginas si algún archivo de contenido contiene saltos de página (epub:type="pagebreak"). NAV_004=El Documento de Navegación debe contener la jerarquía de encabezado de documento completa en EDUPUB. NAV_005=Archivos de contenido contienen elementos 'audio' pero el Documento de Navegación no tiene un listado de clips de audio (epub:type="loa"). NAV_006=Archivos de contenido contienen elementos 'figure' pero el Documento de Navegación no tiene un listado de figuras (epub:type="loi"). NAV_007=Archivos de contenido contienen elementos 'table' pero el Documento de Navegación no tiene un listado de tablas (epub:type="lot"). NAV_008=Archivos de contenido contienen elementos 'video' pero el Documento de Navegación no tiene un listado de clips de vídeo (epub:type="lov"). NAV_009=Los enlaces 'region-based' de navegación deben apuntar a documentos Fixed-Layout. #NCX EPUB v2 Table of Contents NCX_001=El identificador NCX ('%1$s') no concuerda con el identificador OPF ('%2$s'). NCX_002=No se ha encontrado un atributo toc en el elemento spine. NCX_003=Se requiere un archivo .NCX para la navegación TOC en lectores EPUB v2. NCX_004=El identificador NCX ('dtb:uid' metadata) no puede contener espacios en blanco. NCX_005=Se ha encontrado un elemento ncx "page-list" en un archivo .ncx NCX_006=Etiqueta "text" vacía en el documento NCX. #OPF OPF_001=Ha ocurrido un error analizando la versión del EPUB: %1$s. OPF_002=No se ha encontrado el archivo OPF '%1$s' en el EPUB. OPF_003=El elemento '%1$s' existe en el EPUB, pero no está declarado en la sección del archivo OPF. OPF_004=Prefijo de declaración no válido: no está permitidos espacios iniciales o finales. OPF_004a=Prefijo de declaración no válido: se ha encontrado un prefijo vacío. OPF_004b=Prefijo no válido '%1$s': debe ser un nombre válido sin puntuación ('NCName'). OPF_004c=Prefijo de declaración no válido: el prefijo '%1$s' debe estar inmediatemente seguido de dos puntos (':'). OPF_004d=Prefijo de declaración no válido: el prefijo '%1$s' debe estar separado de su URI por un espacio. OPF_004e=Prefijo de declaración no válido: se ha encontrado un espacio no permitido entre el prefijo y la URI. OPF_004f=Prefijo de declaración no válido: se ha encontrado un espacio no permitido entre los mapeados del prefijo. OPF_005=Prefijo de declaración no válido: el URI para el prefijo '%1$s' no existe. OPF_006=Prefijo de declaración no válido: el URI '%1$s' no es un URI válido. OPF_007=Se ha declarado de nuevo un prefijo reservado: '%1$s'. OPF_007a=Mapeado de prefijo no válido: el prefijo '_' no se debe declarar. OPF_007b=Mapeado de prefijo no válido: el término por defecto '%1$s' no debe volver a declararse. OPF_008=El manejador vinculado a los media-type por defecto '%1$s' no está permitido. OPF_009=El tipo de archivo multimedia '%1$s' ya tiene asignado un manejador, con ID '%2$s'. OPF_010=Se ha producido un error con la referencia: '%1$s'. OPF_011=El elemento itemref no puede tener asignadas a la vez las propiedades page-spread-right y page-spread-left. OPF_012=La propiedad de elemento '%1$s' no está definida con el media-type '%2$s'. OPF_013=La propiedad type '%1$s' en la etiqueta objeto no concuerda con el media-type '%2$s' declarado en la sección del archivo OPF. OPF_014=La propiedad '%1$s' debe declararse en el archivo OPF. OPF_015=La propiedad '%1$s' no debe estar declarada en el archivo OPF. OPF_016=El elemento \"rootfile\" no presenta su atributo \"full-path\", el cual es obligatorio. OPF_017=El atributo \"full-path\" del elemento \"rootfile\" no debe estar vacío. OPF_018=La propiedad 'remote-resources' se ha declarado en el archivo OPF, pero no se han encontrado referencias a recursos externos. Compruebe que la propiedad es necesaria. OPF_019=No se ha encontrado la etiqueta en el archivo OPF. OPF_020=Hay un número excesivo de elementos dentro de la sección . OPF_021=Uso de un esquema URI no registrado en href: '%1$s'. OPF_025=La propiedad '%1$s' solo puede tener un valor. OPF_026=Se ha encontrado un valor de propiedad erróneo: '%1$s'. OPF_027=Propiedad no definida: '%1$s'. OPF_028=Prefijo no declarado: '%1$s'. OPF_029=El archivo '%1$s' no concuerda con el media-type %2$s tal y como se especifica en el archivo OPF. OPF_030=No se ha encontrado el identificador único '%1$s'. OPF_031=El archivo mencionado en la sección no se ha declarado en la sección del archivo OPF: %1$s. OPF_032=La referencia en '%1$s' no es válida según 'OPS Content Document'. OPF_033=La sección contiene recursos no lineales. OPF_034=La sección contiene múltiples referencias al elemento con id '%1$s' de la sección . OPF_035=La declaración media-type 'text/html' no es correcta para XHTML/OPS. OPF_035_SUG=Utilice en su lugar 'application/xhtml+xml'. OPF_036=El formato de vídeo '%1$s' podría no estar soportado por algunos sistemas de lectura. OPF_036_SUG=Utilice en su lugar 'video/mp4', 'video/h264' o 'video/webm'. OPF_037=Se ha encontrado un media-type obsoleto: '%1$s'. OPF_038=El media-type '%1$s' no es recomendable en un contexto OEBPS 1.2: utilice en su lugar 'text/x-oeb1-document'. OPF_039=El media-type '%1$s' no es recomendable en un contexto OEBPS 1.2: utilice en su lugar 'text/x-oeb1-css'. OPF_040=No se ha encontrado ningún elemento fallback. OPF_041=No se ha encontrado ningún elemento fallback de estilo. OPF_042='%1$s' no es un media-type permitido en . OPF_043=El elemento '%1$s' de con un media-type no estándar carece de fallback. OPF_044=El elemento '%1$s' de con un media-type no estándar tiene un fallback que apunta a un media-type no estándar. OPF_045=Se ha encontrado una referencia recursiva en la cadena de fallback. OPF_046=La propiedad con script no está definida en el manejador del media-type. OPF_047=El archivo OPF utiliza la sintaxis OEBPS 1.2 que permite compatibilidad retroactiva. OPF_048=La etiqueta package no tiene atributo unique-identifier ni valor para el mismo: ambos son oligatorios. OPF_049=La id '%1$s' de elemento no se ha encontrado en . OPF_050=El atributo TOC hace referencia a un recurso con un mime type que no es ncx: se esperaba 'application/x-dtbncx+xml'. OPF_051=Las dimensiones de la imagen exceden el tamaño recomendado. OPF_052=El valor de role '%1$s' no es válido. OPF_053=El valor de date '%1$s' no sigue la sintaxis recomendada por http://www.w3.org/TR/NOTE-datetime:%2$s. OPF_054=El valor de date '%1$s' no es válido según http://www.w3.org/TR/NOTE-datetime:%2$s. OPF_055=La etiqueta %1$s está vacía. OPF_056=El tipo de archivo multimedia '%1$s' no es un tipo de audio recomendado. OPF_057=El tamaño del archivo de imagen excede el tamaño recomendado. OPF_058=Un elmento de no tiene referencia en una entrada del TOC. OPF_058_SUG=Cada elemento de debe estar referenciado por al menos una entrada del TOC. OPF_059=El elemento en no tiene una referencia NCX. OPF_059_SUG=Cada uno de los elementos en deben estar referenciados por, al menos, una entrada NCX. OPF_060=Entrada duplicada en el archivo ZIP: '%1$f'. OPF_061=Entrada duplicada en el archivo ZIP (tras la normalización Unicode NFC) '%1$f'. OPF_062=Se ha encontrado un atributo page-map de Adobe en un elemento de en el archivo OPF. OPF_063=El elemento page-map de Adobe '%1$s' referenciado no se ha encontrado en . OPF_064=OPF declara el tipo '%1$s'; se valida con el perfil '%2$s'. OPF_065=Declaración errónea; es probable que se deba a un bucle en elementos 'refines'. OPF_066=No se encuentran metadatos de paginación 'dc:source' o 'source-of'. El origen de paginación debe identificarse usando las propiedades 'dc:source' y 'source-of' si el contenido incluye marcadores de salto de página. OPF_067=El recurso '%1$s' no puede incluirse como elemento 'link' en la sección y como en la sección . OPF_068=Rol de colección '%1$s' desconocido. OPF_069=El rol de colección personalizado '%1$s' no debe incluir la cadena 'idpf.org' en su componente anfitrión. OPF_070=El rol de coleccción personalizado '%1$s' es un URI incorrecto. OPF_071=Las colecciones de índice solo deben contener recursos que apunten a archivos de contenido XHTML. OPF_072=El elemento '%1$s' en la sección está vacío. OPF_073=Los identificadores externos no pueden aparecer en la declaración de tipo de documento. OPF_074=El recurso '%1$s' se ha declarado en múltiples de la sección . OPF_075=Previsualización de colecciones solo debe apuntar a archivos de contenido EPUB. OPF_076=URI de elementos de previsualización de colecciones no debe incluir identificadores de fragmentos canónicos EPUB. OPF_077=El Documento de Datos de Navegación no debe incluirse en . OPF_078=Un Diccionario EPUB debe contener al menos un archivo de contenido con diccionario (epub:type 'dictionary'). OPF_079=Se ha encontrado contenido de Diccionario (epub:type 'dictionary'); el Documento de Empaquetado debe declarar un dc:type 'dictionary'. OPF_080=El nombre de archivo de un documento de Mapa de Búsqueda debe tener la extensión '.xml'. OPF_081=No se ha encontrado el recurso '%1$s' (referenciado en una colección de diccionario EPUB). OPF_082=Se ha encontrado una colección de diccionario EPUB que contiene más de un Documento de Mapa de Búsqueda. OPF_083=Se ha encontrado una colección de diccionario EPUB que no contiene un Documento de Mapa de Búsqueda. OPF_084=Se ha encontrado una colección de diccionario EPUB que contiene el recurso '%1$s', que no es ni un Documento de Mapa de Búsqueda ni un Archivos de Contenido XHTML. #Package PKG_001=Validando el EPUB con la versión %1$s pero se ha detectado la versión %2$s. PKG_003=No se puede leer la cabecera del archivo EPUB. Este archivo EPUB podría estar corrupto. PKG_004=Cabecera del archivo ZIP corrupta. PKG_005=El archivo mimetype tiene una campo extra de longitud %1$s. No se permiten campos extra en el formato ZIP para el archivo mimetype. PKG_006=El archivo mimetype no existe o no ocupa el primer lugar dentro del ePub. PKG_007=El archivo mimetype solo puede contener la cadena 'application/epub+zip' y no puede estar comprimido. PKG_008=No se puede leer el archivo '%1$s'. PKG_009=El nombre de archivo contiene caracteres no permitidos para nombres de archivo OCF: '%1$s'. PKG_010=El nombre de archivo contiene espacios, por lo que deben incluirse en el URI. Es recomendable eliminar los espacios del nombre de archivo. PKG_011=El nombre de archivo no puede terminar con '.'. PKG_012=El nombre de archivo contiene los siguientes caracteres no ascii: %1$s. Es recomendable cambiar el nombre de archivo. PKG_013=El archivo EPUB incluye múltiples interpretaciones OPS. PKG_014=El EPUB contiene un directorio vacío: '%1$s'. PKG_015=No se pueden leer los contenidos del EPUB: %1$s PKG_016=Utilice solo minúsculas para la extensión del archivo EPUB para asegurar la compatibilidad. PKG_016_SUG=Para asegurar la compatibilidad utilice '.epub'. PKG_017=Extensión de archivo EPUB no estándar. PKG_017_SUG=Para asegurar la compatibilidad utilice '.epub'. PKG_018=No se encuentra el archivo EPUB. PKG_020=No se encuentra el archivo OPF '%1$s'. PKG_021=Se ha encontrado un archivo de imagen corrupto. PKG_022=Extensión de archivo de imagen incorrecto. La imagen es un archivo '%1$s' pero tiene una extensión '%2$s'. PKG_023=Validando el EPUB con la versión 2.0; se usará el perfil de validación por defecto. #Resources RSC_001=No se encuentra el archivo '%1$s'. RSC_002=No se encuentra el archivo obligatorio META-INF/container.xml. RSC_003=No se ha encontrado en el contenedor una etiqueta de archivo raíz con media type 'application/oebps-package+xml'. RSC_004=El archivo '%1$s' no se ha podido desencriptar. RSC_005=Error al analizar el archivo '%1$s'. RSC_006=No se permite la referencia al recurso remoto: el recurso debe estar en el OCF. RSC_006_SUG=Solo están permitidos recursos remotos de audio y vídeo. RSC_007=El recurso referenciado no se ha encontrado en el EPUB. RSC_007w=El recurso referenciado no se ha encontrado en el EPUB. RSC_008=El recurso referenciado no está declarado en el del archivo OPF. RSC_009=No se debe utilizar un identificador fragmentado con un atributo img src. RSC_010=Se ha encontrado una referencia a un tipo de recurso no estándar. RSC_011=Se ha encontrado una referencia a un recurso que no es un elemento incluido en . RSC_012=No se ha definido el identificador fragmentado. RSC_013=Se ha utilizado el identificador fragmentado como referencia a un recurso de hoja de estilos. RSC_014=El identiicador fragmentado define un tipo de recurso incompatible. RSC_015=Es obligatorio el uso de un identificador fragmentado para referencias a etiquetas svg. RSC_016=Error fatal al analizar el archivo '%1$s'. RSC_017=Aviso al analizar el archivo '%1$s'. RSC_018=No se encuentra el archivo Altimg '%1$s'. RSC_019=EPUBs con Multiple Renditions deben contener un archivo META-INF/metadata.xml. RSC_020='%1$s' no es una URI válida. RSC_021=El documento de mapeado de búsqueda debe apuntar a archivos de contenido (no se encontró '%1$s' en la sección ). RSC_022=No se pueden comprobar detalles de imagen (requiere la versión 7 de Java o superior). #Scripting SCP_001=La utilización de la función Javascript eval() en los scripts de un archivo EPUB constituye un riesgo de seguridad. SCP_002=La utilización de XMLHttpRequest en los scripts de un archivo EPUB constituye un riesgo de seguridad. SCP_003=El almacenamiento local o de sesión no está soportado por ahora. SCP_004=El archivo de contenido contiene scripts no soportados en EPUB v2. SCP_005=El archivo contiene scripts, pero no se ha especificado en el archivo OPF. SCP_006=Se han encontrado scripts integrados. SCP_007=El script hace referencia a 'innerHtml'. SCP_007_SUG=Utilice en su lugar el DOM. SCP_008=El script hace referencia a 'innerText'. SCP_008_SUG=Utilice en su lugar 'textContent'. SCP_009=El archivo utiliza manejadores de eventos de ratón. SCP_009_SUG=Asegúrese de que las funcionalidades relativas al ratón son accesibles mediante teclado o acciones táctiles. SCP_010=El archivo Epub 3 contiene script. epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/messages/MessageBundle_nl.properties0000644000175000017500000006066413017276730031434 0ustar eugeneeugene# This is the default MessageBundle.properties file #Accessibility ACC_001=HTML element 'img' of 'area' mist een 'alt' attribuut. ACC_002=HTML element 'input' mist een verwijzend label element dat ermee correspondeert. ACC_003=HTML elementen die niet met tekst te maken hebben zouden een 'title' attribuut moeten bevatten. Dit helpt met de toegankelijkheid. ACC_004=HTML 'a' element moet tekst bevatten. ACC_005=Kopcellen van een tabel zouden moeten worden geidentificeerd door 'th' elementen. Dit komt de toegankelijkheid ten goede. ACC_006=Tabellen zouden een 'thead' elementen moeten bevatten. Dit komt de toegankelijkheid ten goede. ACC_007=Contentdocumenten gebruiken geen 'epub:type' attributen. Dit komt de toegankelijkheid ten goede. ACC_008=Het navigatiedocument bevat geen 'landmarks nav' element. ACC_009=MathML zou een 'alt' tekstattribuut of een 'annotation-xml' kind-element moeten bevatten. ACC_010=Binnen 'blockquote' en 'figure' elementen zouden headings niet gebruikt moeten worden. ACC_011=Hyperlinks binnen SVG zouden een voor mensen leesbare titel moeten bevatten (gebruik daarvoor het 'title' child element of het 'xlink:title' attribuut). ACC_012='table' elementen zouden een 'caption' element moeten bevatten. ACC_013=Contentbestand bevat tenminste 1 inline style verklaring. ACC_013_SUG=Inline stijlen zijn niet verenigbaar met de instellingen voor toegankelijkheid en het leesgenot van de gebruiker. Gebruikt u liever CSS stijlen. ACC_014=De waarde van 'font-size' in uw CSS gebruikt geen relatieve grootte. ACC_014_SUG=Acceptabele waarden omvatten percentages, meervouden van em, 'larger', 'smaller, 'normal' of 'inherit'. ACC_015=De waarde van 'line-height' in uw CSS gebruikt geen relatieve grootte. ACC_015_SUG=Acceptabele waarden omvatten percentages, nummers, meervouden van em, 'normal' of 'inherit'. ACC_016=De waarde van 'font-size' in uw CSS zou een relatieve grootte moeten gebruiken. ACC_016_SUG=Acceptabele waarden omvatten percentages, meervouden van em, 'larger', 'smaller, 'normal' of 'inherit'. ACC_017=De waarde van 'line-height' in uw CSS gebruikt geen relatieve grootte. ACC_017_SUG=Acceptabele waarden omvatten percentages, nummers, meervouden van em, 'normal' of 'inherit'. #Checker Errors CHK_001=Het bestand met aangepaste boodschappen is niet gevonden. CHK_002=Niet-herkend aangepast bericht met id %1$s gevonden in het bestand met aangepaste boodschappen '%2$s'. CHK_003=Niet-herkend aangepast bericht met zwaarte %1$s gevonden in het bestand met aangepaste boodschappen '%2$s'. CHK_004=Het aangepaste bericht bevat teveel parameters. Het gaat om het aangepaste berichtenbestand '%1$s'. CHK_005=De aangepaste suggestie bevat teveel parameters. Het gaat om het aangepaste berichtenbestand '%1$s'. CHK_006=Het is niet gelukt om de instelling van het aangepaste formaat te verwerken uit het aangepaste berichtenbestand '%1$s'. CHK_007=Foutmelding tegengekomen bij het verwerken van het aangepaste berichtenbestand '%1$s': "%2$s". #CSS CSS_001=Eigenschap \'%1$s\' mag niet in een EPUB Style Sheet opgenomen worden. CSS_002=Lege of NULL reference gevonden. CSS_003=Alleen UTF-8 en UTF-16 coderingen zijn toegestaan, terwijl %1$s is aangetroffen. CSS_004=Alleen UTF-8 en UTF-16 coderingen zijn toegestaan, terwijl %1$s BOM is aangetroffen. CSS_005=Er zijn conflicterende stijlattributen aangetroffen: %1$s. CSS_006=De CSS eigenschap 'position:fixed' zou niet gebruikt moeten worden in een ePub. CSS_007=Font-face verwijzing %1$s verwijst naar een niet-standaard font type %2$s. CSS_008=Foutmelding bij het verwerken van het CSS: %1$s. CSS_009=Het gebruik van de volgende CSS definities kan paginatie-problemen veroorzaken: Columns, Transforms, Transitions, box-sizing, KeyFrames. CSS_010=Fallback alternatief benodigd voor een stylesheet dat geen 'text/css' als type heeft. CSS_011=Teveel verschillende CSS bestanden. CSS_011_SUG=Overweeg het samenvoegen van CSS bestanden om het aantal CSS bestanden te verminderen. CSS_012=Het document roept meerdere CSS bestanden aan. CSS_013=De CSS eigenschap is !important verklaard. CSS_015=Het alternatieve stylesheet mist een titel. CSS_016=Het alternatieve stylesheet wordt eerder geladen dan het hoofd-stylesheet. CSS_017=De CSS selector specificeert een absolute positie. CSS_019=De CSS font-face verklaring heeft geen attributen. CSS_020=CSS font selector verklaring gebruikt een onverwachte font-size waarde: '%1$s'. CSS_020_SUG=Acceptabele waarden omvatten percentages, meervouden van em, 'larger', 'smaller, 'normal' of 'inherit'. CSS_021=CSS afkorting 'font-family' specificeert een ongeldig systeemfont. CSS_021_SUG=Acceptabele waarden omvatten 'caption', 'icon', 'menu', 'message-box', 'small-caption', 'status-bar', en 'inherit'. CSS_022=De CSS selector specificeert een globale instelling voor de marges. CSS_023=De CSS selector specificeert een media query. CSS_024=CSS class - bijvoorbeeld .voorbeeld - wordt niet gebruikt. CSS_024_SUG=Verwijder ongebruikte CSS selectors. CSS_025=De CSS class selector werd niet aangetroffen. CSS_025_SUG=Controleer op typefouten of definieer een class selector om het gebruik van de class te documenteren. CSS_027=De CSS selector specificeert een absolute positie. CSS_028=Gebruik van font-face verklaring. #HTM - XHTML related messages HTM_001=Ieder uitgeefdocument dat op XML gebaseerd is moet een geldig XML versie 1.0 document zijn. De gevonden XML versie: %1$s. HTM_002=XML versie-verificatie wordt niet ondersteund door de geinstalleerde xml verwerker. XML bestanden moeten geldige XML 1.0 documenten zijn. HTM_003=Externe entiteiten zijn niet toegestaan in ePub v3 documenten. Aangetroffen externe verwijzing: %1$s. HTM_004=Onbekende DOCTYPE: verklaring gevonden: '%1$s'. Verwacht werd: '%2$s'. HTM_005=Er werd een externe verwijzing gevonden. HTM_006=Een XHMTL Named Entity werd aangetroffen. Alleen '&', ''', '<', en '>' zijn toegestaan. HTM_007=Lege waarde of witruimte in attribuut ssml:ph. HTM_008=Het src attribuut is verplicht. HTM_009=De DOCTYPE verklaring is verouderd of onbekend en kan worden verwijderd. HTM_010=De namespace uri '%1$s' werd aangetroffen. HTM_011=De entiteit is niet gedefinieerd. HTM_011_SUG=Definieer de entiteit of gebruik de genummerde entiteit. HTM_012=Link naar een Canonical Fragment Identifier -CFI- gevonden in een extern boek. HTM_013=Canonical Fragment Identifiers -CFIs- binnen het boek aangetroffen in het document. HTM_014=Ongeldige bestandsextensie voor een HTML bestand (verwacht wordt: html, htm of xhtml). HTM_014a=XHTML bestand met de naam '%1$s' heeft de extensie '.xhtml' nodig. HTM_015=HTML4 DOCTYPE verklaring aangetroffen binnen deze ePub v3. HTM_016=HTML5 DOCTYPE verklaring aangetroffen binnen deze ePub v2. HTM_017=Contentbestand heeft verschillende waardes voor de taal in de attributen xml:lang en lang. HTM_018=Contentbestand heeft een ongeldige waarde bij attribuut xml:lang. HTM_019=Contentbestand heeft een ongeldige waarde bij attribuut lang. HTM_020=Contentbestand mist het attribuut xml:lang. HTM_021=Contentbestand mist het attribuut lang. HTM_022=Het contentdocument bevat waarschijnlijk teveel DIV of SPAN tags. HTM_022_SUG=Voeg opvolgende DIV of SPAN tags samen en gebruik dezelfde style. HTM_023=Een ongeldige XHMTL Named Entity werd aangetroffen: '%1$s'. Alleen '&', ''', '<', en '>' zijn toegestaan. HTM_023_SUG=Controleer de spelling of gebruik genummerde entiteiten. HTM_024=Een XHMTL Named Entity werd aangetroffen. Alleen '&', ''', '<', en '>' zijn toegestaan. HTM_024_SUG=Controleer de spelling of gebruik genummerde entiteiten. HTM_025=Ongeregistreerd URI scheme type gevonden in href attribuut. Controleer de link. HTM_027=De lijst bevat minder dan 2 items. HTM_027_SUG=Lijsten zouden meer dan 1 item moeten bevatten. Dit komt de toegankelijkheid van uw boek ten goede. HTM_028=INPUT elementen binnen HTML zouden een 'id' moeten bevatten. HTM_029=LABEL elementen binnen HTML zouden een 'for' attribuut moeten bevatten dat naar het 'id' van een INPUT element verwijst. HTM_033=HEAD element mist een 'title' kind-element. HTM_036=Het gebruik van iFrames wordt sterk ontmoedigd. HTM_038=Als u 'b', 'i', 'em' of 'strong' elementen gebruikt, verzeker u er dan van dat dit gebruik afgestemd is met de richtlijnen van W3C inzake HTML5. HTM_038_SUG=Het gebruik van CSS styles is doorgaans meer geschikt voor schuine of vetgedrukte tekst. HTM_043=SVG elementen zouden een xml:lang en lang attribuut moeten bevatten. HTM_044=De namespace uri '%1$s' is aangeroepen doch niet gebruikt. HTM_044_SUG=Verwijder ongebruikte namespace URI's. HTM_045=Leeg href attribuut tegengekomen. HTM_045_SUG=Lege href attributen zijn geldige verwijzingen naar zichzelf. Het is zaak deze te controleren om u ervan te vergewissen dat dit ook de bedoeling is. HTM_046=Dit fixed format item heeft geen gedefinieerde viewport. HTM_046_SUG=Bij het gebruiken van een fixed format item dient u de viewport te definieren. HTM_047=HTML viewport mist een 'height' en/of 'width' attribuut. HTM_047_SUG=De verklaring van de viewport zou zowel het 'height' als het 'width' attribuut moeten instellen. HTM_048=SCG ViewBox ontbreekt bij dit fixed format document. HTM_048_SUG=Een viewBox verklaring is nodig voor een fixed format document. HTM_049=Uw HTML element mist een xmlns. Deze dient ingesteld te zijn op 'http://www.w3.org/1999/xhtml'. HTM_049_SUG=Voeg xmlns="http://www.w3.org/1999/xhtml" toe aan het HTML element. HTM_050=Het attribuut epub:type="pagebreak" is aangetroffen in het contentbestand. HTM_051=Microdata semantische verrijkingen aangetroffen zonder RDFa. De EDUPUB standaard raadt aan om een RDFa Lite te gebruiken. HTM_052=Eigenschap 'region-based' alleen toegestaan bij nav elementen in Data Navigation Documents. #media MED_001=De poster van de video dient een core media image type te zijn. Toegestane types zijn png, jpg, svg en gif. MED_002=%1$s element heeft geen fallback ingesteld. MED_003=Niet-standaard beeldbestand van type %1$s aangetroffen. MED_004=De header van dit beeldbestand is wellicht kapot. Vervang of herstel het beeldbestand. MED_005=De aangetroffen audioreferentie van Media Overlay %1$s naar audio type %2$s is niet-standaard. MED_006=Sommige browsers hebben geen ondersteuning voor het weergeven van SVG beelden die een bestandsnaam in de xlink:href eigenschap gebruiken. #NAV EPUB v3 Table of contents NAV_001=Het nav bestand wordt in ePub v2 niet ondersteund. NAV_002=Eigenschap epub:type="page-list" in nav document aangetroffen. NAV_003=Wanneer een of meer contentbestand(-en) binnen uw epub pagina-afbrekingen bevat (epub:type="pagebreak"), dient het Navigatiedocument een page list te bevatten. NAV_004=Binnen de EDUPUB specificatie zou het navigatiedocument de volledige hierarchie van het document moeten bevatten. NAV_005=Contentbestanden bevatten 'audio' elementen maar het navigatiedocument heeft geen lijst van audioclips (epub:type="loa"). NAV_006=Contentbestanden bevatten 'figure' elementen - illustraties - maar het navigatiedocument heeft geen lijst van figures (epub:type="loi"). NAV_007=Contentbestanden bevatten 'table' elementen - tabellen - maar het navigatiedocument heeft geen lijst van tables (epub:type="lot"). NAV_008=Contentbestanden bevatten 'video' elementen maar het navigatiedocument heeft geen lijst van videoclips (epub:type="lov"). NAV_009=Navigatielinks die regio-gebonden zijn moeten verwijzen naar Fixed-Layout Documenten. #NCX EPUB v2 Table of Contents NCX_001=NCX identifier ('%1$s') komt niet overeen met OCF identifier ('%2$s'). NCX_002=Het SPINE element mist een TOC attribuut. NCX_003=Bij een ePub v2 is een .NCX bestand verplicht voor het weergeven van de inhoudsopgave. NCX_004=NCX identifier ('dtb:uid' metadata) behoort geen witruimte te bevatten. Waarschijnlijk staat er een spatie teveel. NCX_005=NCX "page-list" aangetroffen in .ncx bestand. NCX_006=Het NCX bestand mag geen lege "text" labels bevatten. Deze is wel aangetroffen. #OPF OPF_001=Foutmelding bij het verwerken van de ePub versie: %1$s. OPF_002=Het OPF bestand '%1$s' werd niet aangetroffen in de ePub. OPF_003=Item '%1$s' bestaat in de ePub, doch is niet aangegeven in het OPF manifest. OPF_004=Ongeldige prefix verklaring: witruimte voorafgaand of volgend aan de prefix zijn niet toegestaan. OPF_004a=Ongeldige prefix verklaring: lege prefix aangetroffen. OPF_004b=Ongeldige prefix '%1$s': een prefix moet een geldige naam zijn zonder speciale tekens erin. Alleen letters, cijfers, liggende streepjes, streepjes en punten zijn toegestaan. ('geenDubbelePunten', bijvoorbeeld.) OPF_004c=Ongeldige prefix verklaring: prefix '%1$s' moet direct worden gevolgd door een dubbele punt (':'). OPF_004d=Ongeldige prefix verklaring: prefix '%1$s' moet gescheiden zijn van zijn URI door een spatie. OPF_004e=Ongeldige prefix verklaring: illegale witruimte aangetroffen tussen prefix en URI. OPF_004f=Ongeldige prefix verklaring: illegale witruimte aangetroffen tussen prefix-mappings. OPF_005=Ongeldige prefix verklaring: URI voor prefix '%1$s' bestaat niet. OPF_006=Ongeldige prefix verklaring: URI '%1$s' is geen geldige URI. OPF_007=Her-verklaring van een gereserveerde prefix '%1$s'. U mag deze prefix niet gebruiken. OPF_007a=Ongeldige prefix mapping: prefix '_' mag niet worden gedefinieerd. OPF_007b=Ongeldige prefix mapping: standaard vocabulaire '%1$s' mag niet opnieuw gedefinieerd worden. OPF_008=U kunt aan het core Media-type '%1$s' zelf geen handler binden. OPF_009=Het media-type %1$s heeft al een handler toegewezen gekregen, met het ID '%2$s'. OPF_010=Foutmelding bij het verwerken van verwijzing: '%1$s'. OPF_011=itemref kan niet zowel page-spread-right als page-spread-left als eigenschappen hebben. OPF_012=Eigenschap van item '%1$s' is niet gedefinieerd voor het media-type '%2$s'. OPF_013=De type eigenschap '%1$s' van het object tag komt niet overeen met het verklaarde media-type '%2$s' in het OPF manifest. OPF_014=De eigenschap '%1$s' moet aangegeven worden in het OPF bestand. OPF_015=De eigenschap '%1$s' dient niet aangegeven te worden in het OPF bestand. OPF_016=Het element \"rootfile\" ontbeert het verplichte attribuut \"full-path\". OPF_017=Het attribuut \"full-path\" van het element \"rootfile\" mag niet leeg zijn. OPF_018=De eigenschap 'remote-resources' is in het OPF gedefinieerd, maar er is geen verwijzing aangetroffen naar bronnen die zich buiten het boek bevinden. Zorgt u ervoor dat deze eigenschap op een legitieme wijze wordt gebruikt. OPF_019=De SPINE code werd niet aangetroffen in het OPF bestand. OPF_020=Er bevinden zich teveel items in de SPINE. OPF_021=Er wordt een niet-geregistreerde URI scheme gebruikt in href: '%1$s'. OPF_025=Eigenschap '%1$s' kan maar 1 waarde hebben. OPF_026=Niet goed gevormde eigenschap-waarde aangetroffen: '%1$s'. OPF_027=Ongedefinieerde eigenschap: '%1$s'. OPF_028=Onverkaarde prefix: '%1$s'. OPF_029=Het bestand '%1$s' lijkt niet overeen te komen met het media type %2$s, zoals gespecificeerd in het OPF bestand. OPF_030=De unieke identifier '%1$s' werd niet aangetroffen. OPF_031=Het volgende bestand uit het referentie-element in de GUIDE is niet aangegeven in het OPF manifest: %1$s. OPF_032=De GUIDE verwijst naar '%1$s' hetgeen geen geldig 'OPS contentdocument' betreft. OPF_033=De SPINE bevat geen lineaire bronnen. OPF_034=De SPINE bevat meerdere verwijzingen naar het manifest item met het volgende id: '%1$s'. OPF_035=Het mediat type 'text/html' is niet toepasselijk op XHTML/OPS bestanden. OPF_035_SUG=Gebruik in plaats daarvan 'application/xhtml+xml'. OPF_036=Het kan zijn dat ereadingsystemen het video type '%1$s' niet ondersteunen. OPF_036_SUG=Gebruik in plaats daarvan 'vide/mp4', 'video/h264' of 'video/webm'. OPF_037=Afgeschaft media-type '%1$s' aangetroffen. OPF_038=Media type '%1$s' is niet geschikt voor een OEBPS 1.2 context; gebruik in plaats daarvan 'text/x-oeb1-document'. OPF_039=Media type '%1$s' is niet geschikt in een OEBPS 1.2 context; gebruik in plaats daarvan 'text/x-oeb1-css'. OPF_040=Het fallback item werd niet aangetroffen. OPF_041=Het fallback-style item werd niet aangetroffen. OPF_042='%1$s' is geen toegestaan media-type voor in de SPINE. OPF_043=Het SPINE item met het niet-standaard media-type '%1$s' heeft geen fallback. OPF_044=Het SPINE item met het niet-standaard media-type '%1$s' heeft een fallback naar een niet-standaard media-type. OPF_045=Kringloopreferentie aangetroffen in de fallback ketting. OPF_046=Scripted property is not set on mediaType handler. OPF_047=OPF bestand maakt gebruik van OEBPS 1.2 syntaxis om ervoor te zorgen dat de epub ook leesbaar is op oudere systemen. OPF_048=Package code mist het verplichte unique-identifier attribuut en bijbehorende waarde. OPF_049=Item met het id '%1$s' werd niet aangetroffen in het manifest. OPF_050=Verkeerd mime-type van het TOC bestand. Verwacht wordt 'application/x-dtbncs+xml'. OPF_051=De afmetingen van de afbeelding overschrijden de aangeraden grenzen. OPF_052=De waarde '%1$s' voor het role attribuut is ongeldig. OPF_053=De waarde voor de datum '%1$s' volgt niet de aangeraden syntaxis, zie http://www.w3.org/TR/NOTE-datetime:%2$s. OPF_054=De waarde voor de datum '%1$s' is ongeldig, zie http://www.w3.org/TR/NOTE-datetime:%2$s. OPF_055=Lege %1$s code. OPF_056=Media type '%1$s' is geen core audio type. OPF_057=Beeldbestand is groter dan de aangeraden omvang. OPF_058=SPINE item heeft geen verwijzing in de inhoudsopgave TOC. OPF_058_SUG=Elk SPINE item in het manifest zou door tenminste 1 TOC item moeten zijn verwezen. OPF_059=SPINE item heeft geen verwijzing in de NCX inhoudsopgave. OPF_059_SUG=Elk SPINE item in het manifest zou door tenminste 1 NCX item moeten zijn verwezen. OPF_060=Dubbel aanwezig in het ZIP bestand: '%1$f'. OPF_061=Dubbel aanwezig in het ZIP bestand (na de Unicode NFC normalisatie): '%1$f'. OPF_062=Adobe page-map attribuut aangetroffen in het SPINE element in het OPF bestand. OPF_063=Het Adobe page-map item waarnaar wordt verwezen '%1$s' is niet aangetroffen in het manifest. OPF_064=Het OPF bestand verklaart type '%1$s', maar er wordt gevalideerd volgens het profiel van type '%2$s'. OPF_065=Ongeldige metadata verklaring. Waarschijnlijk komt dit door een lus in 'refines' metadata. OPF_066='dc:source' of 'source-of' metadata mist voor de paginatie. Wanneer de content page break markeringen bevat moet de bron van de paginatie worden geidentificeerd met behulp van de 'dc:source' en 'source-of' eigenschappen. OPF_067=Het bronbestand '%1$s' mag niet tegelijkertijd als een 'link' element in de metadata van het pakket en als een manifest item worden opgenomen. Kies er een en elimineer de ander. OPF_068=Collectierol '%1$s' onbekend. OPF_069=Aangepaste collectierol '%1$s' mag de term 'idpf.org' niet bevatten in zijn host component. OPF_070=Aangepaste collectieorl '%1$s' is een ongeldige URI. OPF_071=Index collections mogen alleen bronnen bevatten die verwijzen naar XHMTL contentbestanden. OPF_072=Metadata element '%1$s' is leeg. OPF_073=Externe identifiers mogen niet voorkomen in de document type verklaring. OPF_074=Bronbestand is meerdere malen aangegeven in het manifest. OPF_075=Preview collections mogen alleen verwijzen naar XHMTL contentbestanden. OPF_076=De URI van de link elementen van preview collections mogen geen ePub canonical fragment identifiers bevatten. OPF_077=De spine mag geen Data Navigation Document bevatten. OPF_078=Een ePub Dictionary moet tenminste een contentbestand met woordenboek content bevatten (epub:type 'dictionary'). OPF_079=Woordenboek content gevonden (epub:type 'dictionary'), het Package Document zou het dc:type 'dictionary' moeten aangeven. OPF_080=De bestandsnaam van een Search Key Map document moet de extensie '.xml' bevatten. OPF_081=Bronbestand '%1$s' (aangegeven vanuit een ePub Dictionary collection) werd niet aangetroffen. OPF_082=ePub Dictionary collection aangetroffen die meer dan een Search Key Map Document bevat. OPF_083=ePub Dictionary collection aangetroffen die geen Search Key Map Document bevat. OPF_084=ePub Dictionary collection aangetroffen dat het bestand '%1$s' bevat. Dit is noch een Search Key Map Document, noch een XHTML contentbestand. #Package PKG_001=Het ePub bestand wordt gevalideerd tegen versie %1$s maar wordt gedetecteerd als zijnde versie %2$s. PKG_003=Niet in staat om de header van de ePub te lezen. Waarschijnlijk is het ePub bestand beschadigd. PKG_004=Beschadigde ePub ZIP header. PKG_005=Het mimetype bestand heeft een extra veld met de lengte %1$s. Het gebruik van de mogelijkheid voor een extra veld van het ZIP formaat is voor het mimetype bestand niet toegestaan. PKG_006=Mimetype bestand vermist of is niet het eerste bestand in het ePub archief. PKG_007=Het mimetype bestand zou alleen de string 'application/epub+zip' mogen bevatten en zou niet gecomprimeerd moeten zijn. PKG_008=Niet in staat om bestand '%1$s' te lezen. PKG_009=Bestandsnaam bevat karakters die niet zijn toegestaan in OCF bestandsnamen: '%1$s'. PKG_010=Bestandsnaam bevat spaties en daarom is het escapen van URI's noodzakelijk. Overweeg om de spaties uit de bestandsnaam te verwijderen. PKG_011=De bestandsnaam mag niet eindigen op een punt - '.'. PKG_012=Bestandsnaam bevat de volgende niet-ascii karakters: %1$s. Overweeg het wijzigen van de bestandsnaam. PKG_013=Het ePub bestand herbergt meerdere verschillende OPS renditions. PKG_014=De ePub herbergt een lege map '%1$s'. PKG_015=Niet in staat de inhoud van de ePub te lezen: %1$s PKG_016=Gebruik alleen kleine letters voor de extensie van het ePub bestand. Dit komt de compatibiliteit ten goede. PKG_016_SUG=Voor de maximale compatibiliteit, gebruik altijd '.epub'. PKG_017=Ongebruikelijke ePub bestandsextensie. PKG_017_SUG=Voor de maximale compatibiliteit, gebruik altijd '.epub'. PKG_018=Het ePub bestand werd niet aangetroffen. PKG_020=Het OPF bestand '%1$s' werd niet aangetroffen. PKG_021=Beschadigd beeldbestand aangetroffen. PKG_022=Verkeerde bestandsextensie voor het beeldbestand. Het beeld is een '%1$s' bestand maar heeft de extensie '%2$s'. PKG_023=De ePub wordt gevalideerd als versie 2.0; het standaard validatieprofiel wordt gebruikt. #Resources RSC_001=Bestand '%1$s' niet aangetroffen. RSC_002=Vereist bestand META-INF/container.xml niet aangetroffen. RSC_003=Geen rootfile code met het mediatype 'application/oebps-package+xml' aangetroffen. RSC_004=Bestand '%1$s' kon niet worden ontcijferd. RSC_005=Foutmelding bij het verwerken van bestand '%1$s'. RSC_006=Remote resource verwijzing is niet toegestaan; het bronbestand moet in de OCF worden opgenomen. RSC_006_SUG=De enige remote resources die zijn toegestaan zijn audio en video bestanden. RSC_007=Bronbestand waarnaar verwezen wordt is niet aangetroffen in de ePub. RSC_007w=Bronbestand waarnaar verwezen wordt is niet aangetroffen in de ePub. RSC_008=Bronbestand waarnaar verwezen wordt is niet aangetroffen in het OPF manifest. RSC_009=Een fragmentidentifier - CFI - kan niet worden gebruikt in combinatie met een img src attribuut. RSC_010=Verwijzing naar een niet-standaard brontype is aangetroffen. RSC_011=Verwijzing naar een bronbestand dat geen SPINE item is aangetroffen. RSC_012=Fragmentidentifier - CFI - niet gedefinieerd. RSC_013=Fragmentidentifier - CFI - gebruikt in een verwijzing naar een CSS bestand. RSC_014=Fragmentidentifier - CFI - definieert een niet-compatibel brontype. RSC_015=Bij het gebruiken van de SVG code USE is een fragmentidentifier - CFI - benodigd. RSC_016=Fatale fout bij het verwerken van bestand '%1$s'. RSC_017=Waarschuwing bij het verwerken van bestand '%1$s'. RSC_018=Altimg bestand '%1$s' werd niet aangetroffen. RSC_019=Uw ePub maakt gebruik van Multiple Renditions. Dat is prettig voor de verschillende mogelijke schermen en schermresoluties waarop uw boek kan worden vertoond. Het is dan wel nodig om een META-INF/metadata.xml bestand op te nemen in uw ePub bestand. RSC_020='%1$s' is geen geldige URI. RSC_021=Een Search Key Map Document moet verwijzen naar contentbestanden ('%1$s' werd niet aangetroffen in de spine). RSC_022=Kan de details van het beeldbestand niet controleren (daarvoor heeft het programma Java versie 7 of hoger nodig). #Scripting SCP_001=Het gebruik van de Javascript functie eval() behelst beveiligingsrisico's. SCP_002=Het gebruik van XMLHttpRequest binnen ePub scripts vormt een beveiligingsrisico. SCP_003=Local en Session Storage worden momenteel niet ondersteund. SCP_004=Contentbestand bevat een script dat niet wordt ondersteund in ePub v2. SCP_005=Contentbestand bevat een script maar staat niet te boek als zodanig. SCP_006=Scripts binnen de html code aangetroffen. SCP_007=Script verwijst naar 'innerHtml'. SCP_007_SUG=Gebruik toch liever een DOM. SCP_008=Script verwijst naar 'innerText'. SCP_008_SUG=Gebruik liever 'textContent'. SCP_009=Contentbestand gebruikt mouse event handlers. SCP_009_SUG=Vergewis u ervan dat alle functionaliteit waarvoor een muis wordt gebruikt OOK toegankelijk is vanaf het toetsenbord EN apparaten die met aanraking werken. SCP_010=ePub 3 contentbestand bevat een script. epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/messages/MessageBundle_it.properties0000644000175000017500000005277713017276730031445 0ustar eugeneeugene# This is the Italian translation of MessageBundle.properties file. | Questa è la traduzione italiana del file MessageBundle.properties. #Accessibility | Accessibilità ACC_001=L'elemento HTML 'img' o 'area' non ha un attributo 'alt'. ACC_002=L'elemento HTML 'input' non ha un corrispondente elemento 'label'. ACC_003=Gli elementi HTML non testuali dovrebbero avere un attributo 'title'. ACC_004=L'elemento HTML 'a' dovrebbe avere una descrizione testuale. ACC_005=Le celle dell'intestazione di una tabella dovrebbero essere indicate da elementi 'th'. ACC_006=Le tabelle dovrebbero includere un'intestazione indicata da un elemento 'thead'. ACC_007=I documenti non hanno attributi 'epub:type' che ne specifichino la semantica. ACC_008=Il documento di navigazione (Navigation Document) non ha un elemento 'nav' di tipo 'landmarks'. ACC_009=Gli elementi MathML dovrebbero avere un attributo 'alt' o un elemento figlio 'annotation'. ACC_010=Gli elementi titolo non dovrebbero essere usati dentro elementi 'blockquote' e 'figure'. ACC_011=Gli elementi 'link' in un documento SVG dovrebbero includere un attributo 'xlink:title'. ACC_012=Gli elementi 'table' dovrebbero includere un elemento 'caption'. ACC_013=Il documento contiene almeno una dichiarazione di stile in linea ('style'). ACC_013_SUG=Gli stili in linea ('style') possono confliggere con le impostazioni di accessibilità. È preferibile usare regole CSS al loro posto. ACC_014=Il valore della proprietà CSS 'font-size' non usa un'unità di misura relativa. ACC_014_SUG=Valori accettabili includono percentuali, multipli di em, 'larger', 'smaller', 'normal' o 'inherit'. ACC_015=Il valore della proprietà CSS 'line-height' non usa un'unità di misura relativa. ACC_015_SUG=Valori accettabili includono percentuali, numeri, multipli di em, 'normal' o 'inherit'. ACC_016=Il valore della proprietà CSS 'font-size' dovrebbe usare un'unità di misura relativa. ACC_016_SUG=Valori accettabili includono percentuali, numeri, multipli di em, 'larger', 'smaller', 'normal' o 'inherit'. ACC_017=Il valore della proprietà CSS 'line-height' dovrebbe usare un'unità di misura relativa. ACC_017_SUG=Valori accettabili includono percentuali, numeri, multipli di em, 'normal' o 'inherit'. #Checker Errors | Errori del validatore CHK_001=Il file delle regole personalizzate non è stato trovato. CHK_002=La regola personalizzata con ID '%1$s' nel file '%2$s' non è riconosciuta. CHK_003=L'impostazione '%1$s' nel file '%2$s' non è riconosciuta. CHK_004=La regola personalizzata contiene troppi parametri nel file '%1$s'. CHK_005=Il suggerimento personalizzato nel file '%1$s' contiene troppi parametri. CHK_006=Impossibile interpretare il parametro formato personalizzato nel file '%1$s'. CHK_007=È occorso un errore analizzando il file '%1$s': %2$s. #CSS CSS_001=La proprietà '%1$s' non deve essere inclusa in un CSS per EPUB. CSS_002=È stato trovato un riferimento vuoto o NULL. CSS_003=Sono consentiti solo gli encoding UTF-8 e UTF-16, invece è stato trovato '%1$s'. CSS_004=Sono consentiti solo gli encoding UTF-8 e UTF-16 senza BOM, invece è stato trovato '%1$s' con BOM. CSS_005=Sono stati trovati attributi alternativi in conflitto: '%1$s'. CSS_006=La proprietà CSS 'position:fixed' non dovrebbe essere utilizzata negli EPUB. CSS_007=Il riferimento 'font-face' '%1$s' punta a una font non standard '%2$s'. CSS_008=È occorso un errore analizzando il file CSS: %1$s. CSS_009=L'uso di certe direttive CSS come 'Columns', 'Transforms', 'Transitions', 'box-sizing' or 'KeyFrames' può causare problemi di paginazione. CSS_010=È stato trovato un file foglio di stile (CSS?) non standard. CSS_011=È stato trovato un numero di CSS eccessivo. CSS_011_SUG=È consigliabile unire più file CSS per ridurne il numero. CSS_012=Il documento punta più file CSS. CSS_013=La proprietà CSS è dichiarata come '!important'. CSS_015=Il foglio di stile alternativo non ha titolo. CSS_016=Il foglio di stile alternativo è dichiarato prima del foglio di stile principale. CSS_017=La regola CSS specifica una posizione assoluta. CSS_019=La regola CSS 'font-face' non ha attributi. CSS_020=La regola CSS specifica 'font-size' di valore inatteso '%1$s'. CSS_020_SUG=Valori accettabili includono percentuali, numeri, multipli di em, 'larger', 'smaller', 'normal' o 'inherit'. CSS_021=La regola CSS 'font-family' specifica una font di sistema non valida. CSS_021_SUG=Valori accettabili includono 'caption', 'icon', 'menu', 'message-box', 'small-caption', 'status-bar' o 'inherit'. CSS_022=La regola CSS specifica un valore per i margini globali. CSS_023=La regola CSS specifica una media query. CSS_024=La regola CSS 'class' non è usata. CSS_024_SUG=È consigliabile rimuovere le regole CSS non usate. CSS_025=La regola CSS 'class' non è stata trovata. CSS_025_SUG=È consigliabile controllare di non aver compiuto un errore nel nome della classe o definire una 'class' effettivamente usata. CSS_027=La regola CSS specifica una posizione assoluta. CSS_028=La regola CSS specifica una 'font-face'. #HTM - XHTML related messages | Messaggi riguardanti i file XHTML HTM_001=Le risorse di tipo XML (o derivate da XML) devono essere documenti XML 1.0 validi. È stata trovata la versione XML: '%1$s'. HTM_002=Il parser XML installato non supporta la verifica della versione XML. Le risorse di tipo XML (o derivate da XML) devono essere documenti XML 1.0 validi. HTM_003=Le entità esterne non sono consentite in EPUB 3. È stata trovata la seguente dichiarazione di entità esterna: '%1$s'. HTM_004=È stato trovato un 'DOCTYPE' errato: '%1$s' mentre era atteso '%2$s'. HTM_005=È stato trovato un riferimento a una risorsa remota. HTM_006=È stata trovata un'entità XHTML con nome (XHTML Named Entity). HTM_007=È stato trovato un attributo 'ssml:ph' vuoto o con soli spazii. HTM_008=L'attributo 'src' è richiesto. HTM_009=L'attributo 'DOCTYPE' fornito è obsoleto e può essere rimosso. HTM_010=È stato trovato il namespace URI '%1$s'. HTM_011=L'entità con nome non è dichiarata. HTM_011_SUG=Dichiarare l'entità con nome o usare un'entità numerica (XHTML Numbered Entity). HTM_012=È stato trovato un link a un CFI di una pubblicazione terza. HTM_013=È stato trovato un link a un CFI all'interno della medesima pubblicazione. HTM_014=È stata trovata un'estensione invalida per il file HTML, era atteso 'html', 'htm' o 'xhtml'. HTM_014a=Il file (XHTML Content Document) '%1$s' dovrebbe avere estensione '.xhtml'. HTM_015=È stata trovata una definizione 'DOCTYPE' HTML 4 nel file EPUB 3. HTM_016=È stata trovata una definizione 'DOCTYPE' HTML 5 nel file EPUB 2. HTM_017=Il documento ha due valori differenti per gli attributi 'xml:lang' e 'lang'. HTM_018=Il documento ha un valore non valido per l'attributo 'xml:lang'. HTM_019=Il documento ha un valore non valido per l'attributo 'lang'. HTM_020=Il documento non ha un attributo 'xml:lang'. HTM_021=Il documento non ha un attributo 'lang'. HTM_022=Il documento potrebbe contenere troppi elementi 'div' o 'span'. HTM_022_SUG=È consigliabile unire elementi 'div' o 'span' che siano consecutivi e usino lo stesso stile. HTM_023=È stata trovata un'entità XHTML con nome (XHTML Named Entity) non valida: '%1$s'. HTM_023_SUG=Controllare che il nome dell'entità sia scritto correttamente o usare un'entità numerica (XHTML Numbered Entity). HTM_024=È stata trovata un'entità XHTML con nome (XHTML Named Entity). Solo '&' ''' '"e;' '<' o '>' sono consentite. HTM_024_SUG=Controllare che il nome dell'entità sia scritto correttamente o usare un'entità numerica (XHTML Numbered Entity). HTM_025=È stato trovato uno schema URI non definito nell'attributo 'href'. HTM_027=La lista contiene meno di due elementi. HTM_027_SUG=Le liste dovrebbero contenere almeno due elementi per favorirne l'accessibilità. HTM_028=Gli elementi HTML 'input' dovrebbero includere un attributo 'id'. HTM_029=Gli elementi HTML 'label' dovrebbero includere un attributo 'for' che punti all'elemento 'input' corrispondente. HTM_033=L'elemento HTML 'head' non ha un elemento figlio 'title'. HTM_036=L'utilizzo di elementi 'iframe' è sconsigliato. HTM_038=Controllare che l'utilizzo degli elementi 'b', 'i', 'em' e 'strong' sia in linea con i suggerimenti W3C HTML5. HTM_038_SUG=È consigliabile utilizzare stili CSS per il testo corsivo o grassetto. HTM_043=Gli elementi SVG dovrebbero includere gli attributi 'xml:lang' e 'lang'. HTM_044=Il namespace URI '%1$s' è definito ma mai usato. HTM_044_SUG=È consigliabile rimuovere namespace URI non utilizzati. HTM_045=È stato trovato un attributo 'href' vuoto. HTM_045_SUG=Gli attributi 'href' vuoti sono validi e puntano a se stessi. Controllare che questa sia realmente l'intenzione e non si tratti di un'omissione accidentale del valore. HTM_046=Il documento HTML a layout fisso non definisce il 'viewport'. HTM_046_SUG=La definizione del 'viewport' è obbligatoria per i documenti HTML a layout fisso. HTM_047=L'elemento HTML 'viewport' non specifica entrambi i valori di 'height' e 'width'. HTM_047_SUG=La definizione di un 'viewport' deve specificare entrambi i valori di 'height' e 'width'. HTM_048=Il documento SVG a layout fisso non definisce il 'ViewBox'. HTM_048_SUG=La definizione del 'ViewBox' è obbligatoria per i documenti SVG a layout fisso. HTM_049=L'elemento 'html' non ha l'attributo 'xmlns' con valore 'http://www.w3.org/1999/xhtml'. HTM_049_SUG=Aggiungere l'attributo 'xmlns="http://www.w3.org/1999/xhtml"' all'elemento 'html'. HTM_050=È stato trovato un attributo 'epub:type="pagebreak"' nel documento. #media | Multimedia MED_001=L'immagine 'poster' di un 'video' deve essere di tipo fondamentale (Core Media Type). MED_002=L'elemento '%1$s' non fornisce un fallback. MED_003=È stata trovata un'immagine di tipo non standard '%1$s'. MED_004=L'header dell'immagine potrebbe essere danneggiato. MED_005=È stato trovato un file Media Overlay contenente il riferimento '%1$s' a un file audio di tipo non standard %2$s. MED_006=Alcuni browser non visualizzano immagini SVG che abbiano un nome di file come valore della proprietà 'xlink:href'. #NAV ePub v3 Table of contents | EPUB 3 Indice NAV NAV_001=EPUB 2 non prevede l'uso di documenti di navigazione 'nav' (Navigation Document). NAV_002=È stato trovato un 'epub:type="page-list"' nel documento di navigazione 'nav' (Navigation Document). #NCX ePub v2 Table of Contents | EPUB 2 Indice NCX NCX_001=È occorso un errore eseguendo il test NCX: %1$s. NCX_002=L'elemento 'spine' non contiene un attributo 'toc'. NCX_003=Un file NCX è richiesto per la navigazione dell'indice in EPUB 2. NCX_004=L'identificatore NCX non corrisponde all'identificatore OCF: '%1$s'. NCX_005=È stato trovato l'elemento "page-list" nel file NCX. #OPF OPF_001=È occorso un errore analizzando l'attributo 'version' del file OPF: %1$s. OPF_002=Impossibile trovare il file OPF '%1$s'. OPF_003=L'elemento '%1$s' esiste nel contenitore EPUB ma non è dichiarato nel 'manifest' OPF. OPF_004=Dichiarazione 'prefix' non valida: il valore non può contenere spazi all'inizio o alla fine. OPF_004a=Dichiarazione 'prefix' non valida: il valore non può essere vuoto. OPF_004b=Dichiarazione 'prefix' non valida: il prefisso non può contenere caratteri ':' (e.g., 'NCName'), trovato: '%1$s'. OPF_004c=Dichiarazione 'prefix' non valida: il prefisso '%1$s' deve essere seguito immediatamente da un carattere ':'. OPF_004d=Dichiarazione 'prefix' non valida: il prefisso '%1$s' deve essere separato dal corrispondente URI da uno spazio. OPF_004e=Dichiarazione 'prefix' non valida: non è ammesso uno spazio tra prefisso e URI. OPF_004f=Dichiarazione 'prefix' non valida: non è ammesso uno spazio tra le mappe prefisso. OPF_005=Dichiarazione 'prefix' non valida: l'URI per il prefisso '%1$s' non esiste. OPF_006=Dichiarazione 'prefix' non valida: '%1$s' non è uno URI valido. OPF_007=Il prefisso riservato '%1$s' è ridichiarato. OPF_007a=Mappa prefisso non valida: il prefisso '_' non deve essere dichiarato. OPF_007b=Mappa prefisso non valida: il vocabolario predefinito '%1$s' non deve essere ridichiarato. OPF_008=Gestore binding (handler binding) per il tipo fondamentale '%1$s' non consentito. OPF_009=È già stato definito il gestore binding '%2$s' per il tipo '%1$s'. OPF_010=È occorso un errore tentando di risolvere il riferimento '%1$s'. OPF_011=L'elemento 'itemref' non può avere entrambe le proprietà 'page-spread-right' e 'page-spread-left'. OPF_012=La proprietà '%1$s' non è definita per il tipo '%2$s'. OPF_013=La proprietà tipo '%1$s' dell'elemento non corrisponde al tipo definito dall'attributo 'media-type' '%2$s' nel 'manifest' OPF. OPF_014=La proprietà '%1$s' dovrebbe essere dichiarata nel file OPF. OPF_015=La proprietà '%1$s' non dovrebbe essere dichiarata nel file OPF. OPF_016=L'elemento 'rootfile' non ha l'attributo obbligatorio 'full-path'. OPF_017=L'attributo 'full-path' dell'elemento 'rootfile' non può essere vuoto. OPF_018=La proprietà 'remote-resources' è stata dichiarata nel file OPF ma non è stato trovato alcun riferimento a risorse remote. Controllare che non sia un'omissione accidentale. OPF_019=L'elemento 'spine' non è stato trovato nel file OPF. OPF_020=Numero eccessivo di elementi nella 'spine'. OPF_021=È stato rilevato l'uso di uno schema URI non registrato nell'attributo 'href': '%1$s'. OPF_022=Percorso non valido: '%1$s'. OPF_024=È stato rilevato un valore sconosciuto per l'attributo EPUB 'version': '%1$s'. OPF_025=La proprietà '%1$s' può assumere solo un valore. OPF_026=È stato trovato un valore non valido per la proprietà: '%1$s'. OPF_027=Proprietà non definita: '%1$s'. OPF_028=Prefisso non definito: '%1$s'. OPF_029=Il file '%1$s' non sembra essere di tipo '%2$s' come dichiarato nel file OPF. OPF_030=L'identificatore univoco 'unique-identifier' '%1$s' non è stato trovato. OPF_031=Il file '%1$s' indicato dall'elemento 'reference' nella 'guide' non è dichiarato nel 'manifest' OPF. OPF_032=L'elemento 'guide' contiene un elemento 'reference' '%1$s' che non è un documento OPS valido. OPF_033=L'elemento 'spine' non contiene elementi con attributo 'linear' 'yes' (esplicito o omesso). OPF_034=L'elemento 'spine' cintiene riferimenti plurimi all'elemento del 'manifest' con ID '%1$s'. OPF_035=Il tipo 'text/html' non è consentito per un file XHTML/OPS. OPF_035_SUG=Usare invece 'application/xhtml+xml'. OPF_036=Il tipo video '%1$s' potrebbe non essere supportato da alcuni sistemi di lettura. OPF_036_SUG=Usare invece 'video/mp4', 'video/h264' o 'video/webm'. OPF_037=È stato rilevato il tipo deprecato '%1$s'. OPF_038=Il tipo '%1$s' non è consentito in un contesto OEBPS 1.2. Usare invece 'text/x-oeb1-document'. OPF_039=Il tipo '%1$s' non è consentito in un contesto OEBPS 1.2. Usare invece 'text/x-oeb1-css'. OPF_040=Impossibile trovare l'elemento di fallback. OPF_041=Impossibile trovare lo stile di fallback. OPF_042=Il valore '%1$s' non è un tipo ammesso per un elemento della 'spine'. OPF_043=L'elemento con tipo non fondamentale '%1$s' non ha fallback. OPF_044=L'elemento con tipo non fondamentale '%1$s' ha un fallback di tipo non fondamentale. OPF_045=È stata trovata una sequenza di riferimenti circolari nella catena di fallback. OPF_046=La proprietà 'scripted' non è stata dichiarata nel gestore di tipo. OPF_047=Il file OPF usa la sintassi OEBPS 1.2 per garantire retrocompatibilità. OPF_048=L'elemento 'package' non ha l'attributo obbligatorio 'unique-identifier'. OPF_049=L'elemento con ID '%1$s' non è stato dichiarato nel 'manifest'. OPF_050=L'attributo 'toc' punta a una risorsa con tipo diverso da 'application/x-dtbncx+xml'. OPF_051=Le dimensioni dell'immagine eccedono le misure consigliate. OPF_052=Il valore '%1$s' per l'attributo 'role' non è valido. OPF_053=La data '%1$s' non segue la sintassi raccomandata da http://www.w3.org/TR/NOTE-datetime: %2$s. OPF_054=La data '%1$s' non è valida secondo http://www.w3.org/TR/NOTE-datetime: %2$s. OPF_055=L'elemento '%1$s' è vuoto. OPF_056=Il tipo '%1$s' non è un tipo audio valido. OPF_056_SUG=Usare 'audio/mp3', 'audio/mp4' o 'audio/ogg' instead. OPF_057=La dimensione dell'immagine supera la dimensione massima consigliata. OPF_058=L'elemento della 'spine' non ha un corrispondente elemento nell'indice (NCX). OPF_058_SUG=Ogni elemento della 'spine' dovrebbe avere almeno un corrispondente elemento nell'indice (NCX). OPF_059=L'elemento della 'spine' non ha un corrispondente elemento nel documento di navigazione 'nav toc' (Navigation Document). OPF_059_SUG=Ogni elemento della 'spine' dovrebbe avere almeno un corrispondente elemento nel documento di navigazione 'nav toc' (Navigation Document). OPF_060=Elemento duplicato nel contenitore ZIP: '%1$f'. OPF_061=Elemento duplicato nel contenitore ZIP dopo la normalizzazione Unicode NFC dei percorsi: '%1$f'. OPF_062=È stato trovato l'attributo Adobe 'page-map' in un elemento della 'spine'. OPF_063=L'elemento Adobe 'page-map' '%1$s' non è dichiarato nel 'manifest' OPF. #Package | Contenitore PKG_001=È stato richiesto il controllo EPUB versione '%1$s' ma l'input pare avere versione '%2$s'. PKG_003=Impossibile leggere l'header del file EPUB. È probabile che il file sia danneggiato. PKG_004=L'header del file EPUB è danneggiato. PKG_005=Il file 'mimetype' ha un campo ZIM 'extra' di %1$s bytes. L'uso del campo ZIP 'extra' non è permesso per il file 'mimetype'. PKG_006=Il file 'mimetype' manca oppure non è il primo file del contenitore EPUB. Controlla di aver compresso il file correttamente. PKG_007=Il file 'mimetype' deve contenere la sola stringa 'application/epub+zip' (20 caratteri). Controlla che non ci siano altri caratteri come ritorni a capo o spazi. PKG_008=Impossibile leggere il file '%1$s'. PKG_009=Il nome del file contiene caratteri non consentiti dalla specifica OCF: '%1$s'. PKG_010=Il nome del file contiene spazi, quindi è richiesto l'escaping. È consigliabile rimuovere gli spazi dai nomi di file. PKG_011=Il nome del file non può terminare con il carattere '.'. PKG_012=Il nome del file contiene i seguenti caratteri non ASCII: '%1$s'. È consigliabile usare nomi di file contenenti solo caratteri ASCII. PKG_013=Il file EPUB contiene più pacchetti OPF (Multiple Renditions). PKG_014=Il file EPUB contiene la directory vuota '%1$s'. PKG_015=Impossibile leggere i contenuti del file EPUB: '%1$s'. PKG_016=L'estensione del file EPUB non usa solamente lettere minuscole. PKG_016_SUG=Per la massima compatibilità, è consigliabile usare '.epub'. PKG_017=L'estensione del file EPUB è non standard. PKG_017_SUG=Per la massima compatibilità, è consigliabile usare '.epub'. PKG_018=File EPUB non trovato. PKG_020=File OPF '%1$s' non trovato. PKG_021=L'immagine è danneggiata. PKG_022=L'immagine ha un'estensione non corrispondente al suo formato. L'immagine è un file '%1$s' ma ha estensione '%2$s'. #Resources | Risorse RSC_001=Il file '%1$s' non è stato trovato. RSC_002=Il file (obbligatorio) 'META-INF/container.xml' non è stato trovato. RSC_003=Non è stato trovato alcun elemento 'rootfile' con 'media-type' di tipo 'application/oebps-package+xml'. RSC_004=Il file '%1$s' non può essere decrittato. RSC_005=È occorso un errore durante la lettura del file: %1$s. RSC_006=Riferimento a risorsa remota non consentito; la risorsa deve essere inclusa nel contenitore EPUB. RSC_006_SUG=Solo risorse audio e video possono essere dichiarate remote. RSC_007=La risorsa non è stata trovata nel contenitore EPUB. RSC_008=La risorsa non è dichiarata nell'elemento 'manifest' del file OPF. RSC_009=Un identificatore di frammento non dovrebbe essere usato come attributo 'src' di un elemento 'img'. RSC_010=È stato trovato un riferimento a una risorsa di tipo non standard. RSC_011=È stato trovato un riferimento a una risorsa non elencata nell'elemento 'spine'. RSC_012=L'identificatore di frammento è non definito. RSC_013=L'identificatore di frammento è usato in un riferimento a un foglio di stile. RSC_014=L'identificatore di frammento definisce una risorsa di tipo incompatibile. RSC_015=Un identificatore di frammento è richiesto per i riferimenti a elementi SVG 'use'. RSC_016=È occorso un errore fatale durate la lettura del file: %1$s. RSC_017=È occorso un potenziale errore durate la lettura del file: %1$s. RSC_018=Il file altimg '%1$s' non è stato trovato. #Scripting | Script SCP_001=L'uso della funzione 'eval()' in un file EPUB può comportare problemi di sicurezza. SCP_002=L'uso dell'oggetto 'XMLHttpRequest' in un file EPUB può comportare problemi di sicurezza. SCP_003=Local e Session Storage non sono attualmente supportati. SCP_004=Il documento contiene uno script che non è supportato in EPUB 2. SCP_005=Il documento contiene uno script ma non è marcato come 'scripted'. SCP_006=È stato trovato uno script in linea ('script'). SCP_007=Lo script utilizza 'innerHtml'. SCP_007_SUG=È consigliabile usare l'oggetto DOM corrispondente. SCP_008=Lo script utilizza 'innerText'. SCP_008_SUG=È consigliabile usare 'textContent'. SCP_009=Lo script prevede degli handler per eventi del mouse. SCP_009_SUG=È consigliabile controllare che tutte le funzioni attivabili tramite il mouse siano accessibili anche tramite la tastiera e gli eventi tocco. SCP_010=Il documento EPUB 3 contiene uno o più script. # # Adopted translations for common terms # # Navigation Document = documento di navigazione 'nav' # inline style = stile in linea # inline script = script in linea # SVG document/file = documento SVG # HTML document/file = documento HTML # XHTML document/file = documento XHTML # Content Document = documento # Publication = pubblicazione # Media Type = tipo # Core Media Type = tipo fondamentale # Named Entity = entità con nome # Numbered Entity = entità numerica # EPUB/ePub v2 = EPUB 2 # EPUB/ePub v3 = EPUB 3 # warning = potenziale errore # error = errore # fatal error = errore fatale epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/messages/MessageBundle_de.properties0000644000175000017500000005671513017276730031415 0ustar eugeneeugene# This is the default MessageBundle.properties file #Accessibility ACC_001=Einem 'img' oder 'area' HTML-Element fehlt das 'alt'-Attribut. ACC_002=Ein 'input' HTML-Element wird von keinem zugehörigen 'label'-Element referenziert. ACC_003=HTML-Elemente ohne Text-Inhalt sollten ein 'title'-Attribut für bessere Barrierefreiheit besitzen. ACC_004=Ein 'a'-Element darf nicht leer sein. ACC_005=Tabellenkopfzellen sollten für bessere Barrierefreiheit mit 'th'-Elementen ausgezeichnet werden. ACC_006=Tabellen sollten für bessere Barrierefreiheit ein 'thead'-Element besitzen. ACC_007=Das Dokument nutzt keine 'epub:type'-Attribute für semantische Auszeichnung. ACC_008=Die Navigationsdatei enthält kein 'landmarks nav'-Element. ACC_009=MathML sollte entweder ein 'alt'-Attribut besitzen oder ein 'annotation-xml'-Kindelement. ACC_010=Überschriften sollten nicht innerhalb von 'blockquote' oder 'figure'-Elementen benutzt werden. ACC_011=SVG-Hyperlinks sollten einen für Menschen lesbaren Titel besitzen ('title' Kindelement oder 'xlink:title'-Attribut). ACC_012=Tabellen sollten ein 'caption'-Element besitzen. ACC_013=Die Datei enthält mindestens eine Inline-CSS-Deklaration. ACC_013_SUG=Inline-Styles sind nicht kompatibel mit Einstellungen für Barrierefreiheit und benutzerspezifische Display-Anpassungen. Stattdessen sollten CSS-Klassen verwendet werden. ACC_014=Wert der CSS-Eigenschaft 'font-size' ist keine relative Größenangabe. ACC_014_SUG=Erlaubte Werte sind Prozentangaben, 'em'-Werte, 'larger', 'smaller', 'normal' oder 'inherit'. ACC_015=Wert der CSS-Eigenschaft 'line-height' ist keine relative Größenangabe. ACC_015_SUG=Erlaubte Werte sind Prozentangaben, Zahlen, 'larger', 'smaller', 'normal' oder 'inherit'. ACC_016=CSS-Eigenschaft 'font-size' sollte in einer relativen Größe angegeben werden. ACC_016_SUG=Erlaubte Werte sind Prozentangaben, 'em'-Werte, 'larger', 'smaller', 'normal' oder 'inherit'. ACC_017=Wert der CSS-Eigenschaft 'line-height' ist keine relative Größenangabe. ACC_017_SUG=Erlaubte Werte sind Prozentangaben, Zahlen, 'larger', 'smaller', 'normal' oder 'inherit'. #Checker Errors CHK_001=Die benutzerspezifische Datei zum Überschreiben von Warnungen und Fehlermeldungen wurde nicht gefunden. CHK_002=Unbekannte benutzerdefinierte Message-ID '%1$s' in Datei zum Überschreiben von Warnungen und Fehlermeldungen '%2$s'. CHK_003=Unbekannter benutzerdefinierter Fehlerlevel '%1$s' in Datei zum Überschreiben von Warnungen und Fehlermeldungen '%2$s'. CHK_004=Die benutzerdefinierte Meldung enthält zu viele Parameter in der Datei zum Überschreiben von Warnungen und Fehlermeldungen '%1$s'. CHK_005=Der benutzerdefinierte Vorschlag enthält zu viele Parameter in der Datei zum Überschreiben von Warnungen und Fehlermeldungen '%1$s'. CHK_006=Der benutzerdefinierte Formatierungs-Parameter ist ungültig in der Datei zum Überschreiben von Warnungen und Fehlermeldungen '%1$s'. CHK_007=Fehler beim Einlesen der Datei zum Überschreiben von Warnungen und Fehlermeldungen '%1$s': %2$s #CSS CSS_001=Die CSS-Eigenschaft '%1$s' darf im EPUB nicht verwendet werden! CSS_002=Leere oder Keine Referenz gefunden. CSS_003=Es sind nur UTF-8 und UTF-16 Zeichenkodierungen erlaubt, die Datei ist aber '%1$s' kodiert. CSS_004=Es sind nur UTF-8 und UTF-16 Zeichenkodierungen erlaubt, die Datei ist aber '%1$s' kodiert (mit 'Byte Order Mark'). CSS_005=Unverträgliche Style-Eigenschaften gefunden: '%1$s' CSS_006=CSS-Eigenschaft 'position:fixed' sollte in EPUBs nicht verwendet werden. CSS_007=Die 'font-face' Deklaration '%1$s' referenziert einen nicht-standardisierten Schriftentyp: '%2$s' CSS_008=CSS-Validierungsfehler: %1$s CSS_009=Die Verwendung spezieller CSS-Eigenschaften wie etwa Columns, Transforms, Transitions, box-sizing oder KeyFrames kann Fehler bei der Paginierung erzeugen! CSS_010=Alle Nicht-CSS-Stylesheets müssen ein Fallback besitzen! CSS_011=Zu viele CSS-Dateien! CSS_011_SUG=Denke darüber nach, einige CSS-Dateien zusammenzufassen um die Anzahl der Dateien zu verringern. CSS_012=Im Dokument sind zu viele CSS-Dateien referenziert! CSS_013=CSS-Eigenschaft wurde mit '!important' markiert. CSS_015=Alternatives Stylesheet hat keinen Titel! CSS_016=Alternatives Stylesheet wird vor dem Haupt-Stylesheet aufgerufen! CSS_017=CSS-Selektor enthält Anweisungen zu absoluter Positionierung. CSS_019=CSS-Deklaration 'font-face' enthält keine Anweisungen! CSS_020=CSS-Eigenschaft enthält unerwartete Schriftgröße '%1$s'. CSS_020_SUG=Erlaubte Werte sind Prozentangaben, 'em'-Werte, 'larger', 'smaller', 'normal' oder 'inherit'. CSS_021=CSS-Eigenschaft referenziert eine ungültige Systemschrift! CSS_021_SUG=Erlaubte Werte sind 'caption', 'icon', 'menu', 'message-box', 'small-caption', 'status-bar' oder 'inherit'. CSS_022=CSS-Selektor enthält globale 'margin'-Anweisungen. CSS_023=CSS-Selektor deklariert eine MediaQuery. CSS_024=CSS-Klasse wird nicht verwendet. CSS_024_SUG=Entferne unbenutzte CSS-Selektoren/-Klassen. CSS_025=CSS-Klasse wurde nicht gefunden. CSS_025_SUG=Überprüfe die Angabe der CSS-Klasse auf Schreibfehler oder definiere einen neuen Klassen-Selektor im CSS. CSS_027=CSS-Selektor enthält Anweisungen zu absoluter Positionierung. CSS_028=Eine 'font-face'-Deklaration wird genutzt. #HTM - XHTML related messages HTM_001=Jede EPUB-Ressource mit XML-basiertem MIME-Type muss ein valides XML 1.0 Dokument sein. Gefundene XML-Version: '%1$s' HTM_002=Der installierte XML-Parser unterstützt die Verifikation von XML-Versionen nicht. XML-Dateien müssen valide XML 1.0 Dokumente sein. HTM_003=Externe Entity-Deklaration gefunden: '%1$s'. Externe Entities sind in EPUB 3 Dokumenten jedoch nicht erlaubt! HTM_004=Ungültiger DOCTYPE '%1$s'. Erwartet wird '%2$s' HTM_005=Eine externe Referenz wurde gefunden. HTM_006=Ein benanntes XHTML-Entity wurde gefunden. HTM_007=Leeres Attribut 'ssml:ph'. HTM_008=Das 'src'-Attribut ist verpflichtend! HTM_009=Der angegebene DOCTYPE ist veraltet oder ungültig und kann entfernt werden. HTM_010=Namespace-URI '%1$s' wurde gefunden. HTM_011=Entity ist nicht deklariert! HTM_011_SUG=Deklariere das benannte Entity oder nutze die nummerische Variante. HTM_012=CFI-Link zu einem externen Buch gefunden. HTM_013=Interner CFI-Link wurde in diesem Dokument gefunden. HTM_014=Ungültige Dateiendung für HTML-Dateien. Erwartet wird 'html', 'htm' oder 'xhtml'. HTM_014a=Die XHTML-Datei '%1$s' sollte die Endung '.xhtml' tragen. HTM_015=HTML4 DOCTYPE innerhalb eines EPUB 3 ist nicht erlaubt. HTM_016=HTML5 DOCTYPE innerhalb eines EPUB 2 ist nicht erlaubt. HTM_017=Datei hat verschiedene Sprachangaben in den Attributen 'xml:lang' und 'lang'. HTM_018=Datei enthält ungültige Sprachangabe im Attribut 'xml:lang'. HTM_019=Datei enthält ungültige Sprachangabe im Attribut 'lang'. HTM_020=Datei enthält das 'xml:lang'-Attribut nicht! HTM_021=Datei enthält das 'lang'-Attribut nicht! HTM_022=Datei enthält offenbar zu viele 'div' oder 'span'-Elemente. HTM_022_SUG=Denke darüber nach, 'div' oder 'span'-Elemente zusammenzufassen wenn sie aufeinanderfolgen und das gleiche Aussehen haben. HTM_023=Ein ungültiges benanntes XHTML-Entity wurde gefunden: '%1$s'. HTM_023_SUG=Prüfe die Schreibweise oder nutze die nummerische Variante. HTM_024=Ein benanntes XHTML-Entity wurde gefunden. Erlaubt sind nur '&' ''' '"e;' '<' und '>'. HTM_024_SUG=Prüfe die Schreibweise oder nutze die nummerische Variante. HTM_025=Nicht-definiertes URI-Schema im 'href'-Attribut gefunden. HTM_027=Liste enthält weniger als 2 Listeneinträge. HTM_027_SUG=Listen sollten mehr als einen Listeneintrag besitzen. HTM_028='input'-Elemente sollten ein 'id'-Attribut besitzen. HTM_029='label'-Elemente sollten ein 'for'-Attribut besitzen und damit die ID des zugehörigen 'input'-Elements referenzieren. HTM_033=Das 'head'-Element besitzt kein 'title'-Kindelement! HTM_036=Von der Nutzung von IFrames wird stark abgeraten! HTM_038=Stelle sicher, dass die Elemente 'b', 'i', 'em' und 'strong' auch korrekt nach den W3C HTML5 Richtlinien eingesetzt werden. HTM_038_SUG=Normalerweise sind CSS-Stile der bessere Weg um Text zu fetten oder zu kursivieren. HTM_043=SVG-Elemente sollten die Attribute 'xml:lang' und 'lang' besitzen. HTM_044=Namespace-URI '%1$s' ist deklariert, wird aber nicht genutzt. HTM_044_SUG=Entferne ungenutzte Namespaces. HTM_045=Leeres 'href'-Attribut gefunden! HTM_045_SUG=Leere 'href'-Attribute sind gültige Selbst-Referenzen. Bitte prüfe, ob das so gewollt ist. HTM_046=FixedLayout-Dokument ohne 'viewport'-Deklaration! HTM_046_SUG=Diese ist erforderlich für FixedLayout-Dokumente. HTM_047=Der HTML-'viewport'-Angabe fehlt die Breiten oder Höhenangabe. HTM_047_SUG=Die 'viewport'-Deklaration muss 'width' und 'height' enhalten. HTM_048=Die SVG-'ViewBox'-Angabe fehlt für das FixedLayout-Dokument. HTM_048_SUG=Diese ist erforderlich für FixedLayout-Dokumente. HTM_049=Das 'html'-Element besitzt kein Namespace-Attribut 'xmlns' mit dem Wert 'http://www.w3.org/1999/xhtml'. HTM_049_SUG=Füge das Attribut am 'html'-Element hinzu: xmlns="http://www.w3.org/1999/xhtml". HTM_050=Das Attribut epub:type="pagebreak" wurde im Dokument gefunden. HTM_051=Semantische 'Microdata'-Erweiterungen wurden gefunden, aber kein RDFa. EDUPUB empfiehlt die Nutzung von RDFa Lite. HTM_052=Die Eigenschaft 'region-based' ist nur an 'nav'-Elementen in EPUB 3-Navigationsdokumenten erlaubt. #media MED_001=Das Video-Standbild muss in einem vom OPF-Standard unterstützten Dateiformate für Bilder vorliegen! MED_002=Für das '%1$s'-Element ist kein Fallback definiert! MED_003=Bilder vom Typ '%1$s' sind laut OPF-Standard nicht erlaubt. MED_004=Der Datei-Header des Bildes scheint fehlerhaft zu sein. MED_005=Im MediaOverlay wurde eine Audio-Referenz '%1$s' zu einem nicht unterstützten Audio-MimeType '%2$s' gefunden. MED_006=Hinweis: Einige Browser unterstützen die Darstellung von SVG-Grafiken nicht, die einen Dateinamen im 'xlink:href'-Attribut verwenden. #NAV EPUB v3 Table of contents NAV_001=Die EPUB 3-Navigationsdatei wird von EPUB 2 nicht unterstützt. NAV_002=Attribut epub:type="page-list" in der Navigationsdatei gefunden. NAV_003=Das EPUB 3-Navigationsdokument muss eine PageList enthalten, wenn ein oder mehrere Inhaltsdokumente Seitenumbrüche (epub:type="pagebreak") enthalten. NAV_004=Das EPUB 3-Navigationsdokument sollte für EDUPUB die komplette Überschriftshierarchie des EPUBs enthalten. NAV_005=Inhaltsdokumente enthalten 'audio'-Elemente aber das EPUB 3-Navigationsdokument enthält keine Liste der Audio-Clips (epub:type="loa"). NAV_006=Inhaltsdokumente enthalten 'figure'-Elemente aber das EPUB 3-Navigationsdokument enthält kein Abbildungsverzeichnis (epub:type="loi"). NAV_007=Inhaltsdokumente enthalten 'table'-Elemente aber das EPUB 3-Navigationsdokument enthält kein Tabellenverzeichnis (epub:type="lot"). NAV_008=Inhaltsdokumente enthalten 'video'-Elemente aber das EPUB 3-Navigationsdokument enthält keine Liste der Video-Clips (epub:type="lov"). NAV_009=Regionale Navigationslinks müssen auf 'Fixed-Layout'-Dokumente verweisen. #NCX EPUB v2 Table of Contents NCX_001=ID im NCX ('%1$s') gleicht nicht der OPF-ID ('%2$s'). NCX_002=Das 'spine'-Element enthält kein 'toc'-Attribut! NCX_003=Eine NCX-Datei ist für die TOC-Navigation in EPUB 2-Dokumenten erforderlich. NCX_004=Die NCX-ID ('dtb:uid' metadata) sollte keine führenden oder anhängenden Leerzeichen enthalten. NCX_005=NCX "page-list" in der .ncx-Datei gefunden NCX_006=Leeres "text"-Element im NCX-Dokument sollte vermieden werden. #OPF OPF_001=Fehler beim Parsen der EPUB-Version: %1$s OPF_002=Die OPF-Datei '%1$s' wurde nicht im EPUB gefunden. OPF_003=Die Datei '%1$s' ist im EPUB vorhanden, wurde jedoch nicht in der OPF-Datei deklariert. OPF_004=Ungültige Präfix-Deklaration: Führende oder anhängende Leerzeichen sind nicht erlaubt. OPF_004a=Ungültige Präfix-Deklaration: Leerer Präfix gefunden. OPF_004b=Ungültiger Präfix '%1$s': Muss ein gültiger NCName sein ('non-colonized name'). OPF_004c=Ungültige Präfix-Deklaration: Auf das Präfix '%1$s' muss direkt ein Doppelpunkt folgen. OPF_004d=Ungültige Präfix-Deklaration: Präfix '%1$s' muss von der zugehörigen URI durch ein Leerzeichen getrennt sein. OPF_004e=Ungültige Präfix-Deklaration: Ungültige Leerzeichen zwischen Präfix und URI. OPF_004f=Ungültige Präfix-Deklaration: Ungültige Leerzeichen zwischen Präfix-Mappings. OPF_005=Ungültige Präfix-Deklaration: Die URI für den Präfix '%1$s' existiert nicht! OPF_006=Ungültige Präfix-Deklaration: Die URI '%1$s' ist keine gültige URI! OPF_007=Erneute Deklaration eines reservierten Präfixes: '%1$s' OPF_007a=Ungültiges Präfix-Mapping: Präfix '_' darf nicht deklariert werden! OPF_007b=Ungültiges Präfix-Mapping: Standard-Vokabular '%1$s' darf nicht erneut deklariert werden! OPF_008=Die Bindung eines Handlers ist für den Core-MediaType '%1$s' nicht erlaubt. OPF_009=Der MIME-Type '%1$s' wurde bereits dem Handler mit folgender ID zugeordnet: '%2$s' OPF_010=Fehler beim Auflösen der Referenz: '%1$s' OPF_011=Element 'itemref' darf die Eigenschaften 'page-spread-right' und 'page-spread-left' nicht gleichzeitig aufweisen. OPF_012=Die Eigenschaft '%1$s' ist für den MimeType '%2$s' nicht definiert. OPF_013=Die 'type'-Eigenschaft '%1$s' am 'object'-Element entspricht nicht dem MimeType '%2$s' aus dem OPF-Manifest. OPF_014=Die Eigenschaft '%1$s' sollte in der OPF-Datei deklariert werden. OPF_015=Die Eigenschaft '%1$s' sollte NICHT in der OPF-Datei deklariert sein. OPF_016=Am Element 'rootfile' fehlt das erforderliche Attribut 'full-path'. OPF_017=Das Attribut 'full-path' am Element 'rootfile' darf nicht leer sein. OPF_018=Diese Datei weist die Eigenschaft 'remote-resources' auf, es wurden jedoch keine Referenzen auf entfernte Ressourcen gefunden. OPF_019=Das 'spine'-Element wurde in der OPF-Datei nicht gefunden. OPF_020=Sehr viele 'spine'-Einträge gefunden! OPF_021=Nicht-definiertes URI-Schema im 'href'-Attribut benutzt: '%1$s' OPF_025=Der Eigenschaft '%1$s' kann nur ein einziger Wert zugewiesen werden. OPF_026=Ungültigen Eigenschaftswert gefunden: '%1$s' OPF_027=Nicht definierte Eigenschaft: '%1$s' OPF_028=Nicht definierter Präfix: '%1$s' OPF_029=Die Datei '%1$s' scheint nicht vom MimeType '%2$s' zu sein, welcher in der OPF-Datei für diese Datei deklariert wurde. OPF_030=Das 'unique-identifier'-Attribut mit dem Wert '%1$s' wurde nicht gefunden. OPF_031=Der EPUB-'Guide' referenziert die Datei '%1$s' welche aber nicht im OPF-Manifest deklariert wurde. OPF_032=Der EPUB-'Guide' referenziert die Datei '%1$s' welche kein gültiges EPUB-Inhaltsdokument ist. OPF_033=Der EPUB-'Spine' enthält keine Einträge die als 'linear' gekennzeichnet sind. OPF_034=Der EPUB-'Spine' enthält mehrfache Referenzen auf die manifestierte Datei mit der ID '%1$s'. OPF_035=Der MimeType 'text/html' ist für XHTML/OPS nicht gültig. OPF_035_SUG=Verwende stattdessen 'application/xhtml+xml'. OPF_036=Der Video-MimeType '%1$s' wird unter Umständen nicht von allen Lesegeräten unterstützt. OPF_036_SUG=Erlaubt sind 'video/mp4', 'video/h264' oder 'video/webm'. OPF_037=Veralteter MimeType '%1$s'. OPF_038=Der MimeType '%1$s' ist im Kontext von OEBPS 1.2 nicht gültig. Bitte stattdessen 'text/x-oeb1-document' verwenden. OPF_039=Der MimeType '%1$s' ist im Kontext von OEBPS 1.2 nicht gültig. Bitte stattdessen 'text/x-oeb1-css' verwenden. OPF_040=Der Fallback-Eintrag konnte nicht gefunden werden. OPF_041=Der 'style'-Fallback-Eintrag konnte nicht gefunden werden. OPF_042='%1$s' ist kein im 'Spine' erlaubter MimeType (laut OPF-Standard). OPF_043=Ein 'spine'-Eintrag mit MimeType '%1$s' ist nicht erlaubt und enthält auch kein Fallback. OPF_044=Ein 'spine'-Eintrag mit MimeType '%1$s' ist nicht erlaubt und er enthält einen Fallback zu einem im 'Spine' nicht erlaubten MimeType. OPF_045=Nicht erlaubter zirkulärer/gegenseitiger Bezug von Fallback-Referenzen. OPF_046=Die "scripted"-Eigenschaft ist am mediaType-Handler nicht gesetzt. OPF_047=Die OPF-Datei nutzt OEBPS-1.2-Syntax, welche Abwärtskompatibilität gewährleistet. OPF_048=Am 'package'-Element fehlt das erforderliche 'unique-identifier'-Attribut. OPF_049=Die Datei '%1$s' wurde nicht im OPF-Manifest gefunden. OPF_050=Das TOC-Attribut referenziert eine Ressource ohne NCX-MimeType; erwartet wird aber der MimeType 'application/x-dtbncx+xml'. OPF_051=Die Bild-Abmessungen überschreiten die empfohlenen Maße. OPF_052=Wert des 'role'-Attributs am Element 'dc:creator' ist ungültig: '%1$s' OPF_053=Datumseintrag '%1$s' folgt nicht dem vorgegebenen Schema aus http://www.w3.org/TR/NOTE-datetime : %2$s OPF_054=Datumseintrag '%1$s' ist invalide per Definition (siehe http://www.w3.org/TR/NOTE-datetime): %2$s OPF_055='%1$s'-Element ist leer. OPF_056=MimeType '%1$s' ist kein gültiger Audio-MimeType. OPF_057=Die Bild-Dateigröße überschreiten die empfohlenen Vorgaben. OPF_058='spine'-Eintrag wird nicht aus der '.ncx'-Datei referenziert. OPF_058_SUG=Jeder 'spine'-Eintrag im OPF-Manifest sollte von mindestens einem TOC-Eintrag in der '.ncx'-Datei referenziert werden. OPF_059='spine'-Eintrag wird nicht in der NCX-Datei referenziert. OPF_059_SUG=Jeder 'spine'-Eintrag im OPF-Manifest sollte von mindestens einem Eintrag in der NCX-Datei referenziert werden. OPF_060=Doppelte Datei im EPUB-Archiv: '%1$f' OPF_061=Doppelte Datei im EPUB-Archiv (nach Unicode-NFC-Normalisierung): '%1$f' OPF_062=Adobe "page-map" Attribut am 'spine'-Element der OPF-Datei gefunden. OPF_063=Die in der Adobe 'page-map' referenzierte Datei '%1$s' wurde nicht im OPF-Manifest gefunden. OPF_064=Im OPF wird der Typ '%1$s' deklariert, deshalb wird mit dem Profil '%2$s' validiert. OPF_065=Ungültige Metadaten, eventuell aufgrund eines zirkulären/gegenseitigen Bezugs von 'refines'-Metadaten zueinander. OPF_066=Es fehlen die 'dc:source' oder 'source-of' Metadaten. Die Quelle der Paginierung muss über ein 'dc:source'-Element oder 'source-of'-Attribute an den Meta-Elementen angegeben werden, wenn die Inhaltsdokumente Seitenumbrüche enthalten. OPF_067=Die Ressource '%1$s' darf nicht gleichzeitg als 'link'-Element in den Paket-Metadaten und als 'manifest'-Eintrag gelistet sein. OPF_068=Unbekanntes 'role'-Attribut: %1$s OPF_069=Das benutzerspezifisches 'role'-Attribut '%1$s' darf die Zeichenkette 'idpf.org' im Host-Part nicht enthalten. OPF_070=Das benutzerspezifische 'role'-Attribut '%1$s' ist keine gültige URI. OPF_071=Indize dürfen nur Ressourcen enthalten, die auf XHTML-Inhaltsdokumente verweisen. OPF_072=Metadaten-Element '%1$s' ist leer. OPF_073=Externe Doctype-Deklarationen (SYSTEM/PUBLIC) sind nicht erlaubt. OPF_074=Die Ressource '%1$s' wird in mehreren 'manifest'-Elementen im OPF referenziert. OPF_075=Leseproben dürfen nur aus EPUB-Inhaltsdokumenten bestehen. OPF_076=Die URI von Leseproben-Links darf keine 'fragment identifier' (ID-Referenzen) enthalten. OPF_077=Das maschinenlesbare Navigationsdokument sollte nicht im 'Spine' gelistet sein. OPF_078=Ein EPUB-Lexikon muss mindestens ein Inhaltsdokument mit Lexikon-Inhalt (epub:type='dictionary') besitzen. OPF_079=Lexikon-Inhalt wurde gefunden (epub:type='dictionary'), im 'Package Document' sollte deshalb dc:type='dictionary' gesetzt sein. OPF_080=Die Stichwortverzeichnis-Datei sollte die Dateiendung '.xml' haben. OPF_081=Die Ressource '%1$s', die aus einem EPUB-Lexikon referenziert wird, wurde nicht gefunden, OPF_082=Ein EPUB-Lexikon mit mehr als einem Stichwortverzeichnis wurde gefunden. OPF_083=Ein EPUB-Lexikon ohne Stichwortverzeichnis wurde gefunden. OPF_084=Ein EPUB-Lexikon mit der Ressource '%1$s' wurde gefunden, die weder ein Stichwortverzeichnis noch ein XHTML-Inhaltsdokument ist. #Package PKG_001=Validierung gegen den EPUB-Standard Version %1$s, es wurde aber die EPUB-Version %2$s entdeckt. PKG_003=Der EPUB Datei-Header kann nicht ausgelesen werden. Diese EPUB-Datei scheint kaputt zu sein. PKG_004=Fehlerhafter EPUB ZIP-Header. PKG_005=Die 'mimetype'-Datei hat ein Extra Field der Länge %1$s. Die Verwendung des Extra-Field-Features des ZIP-Formats ist für die 'mimetype'-Datei nicht erlaubt. PKG_006=MimeType-Eintrag fehlt oder ist nicht der Erste im EPUB-Archiv. PKG_007=Die Mimetype-Datei darf nur den String 'application/epub+zip' als Inhalt haben und nicht komprimiert sein! PKG_008=Kann die Datei '%1$s' nicht lesen. PKG_009=Dateiname enthält Zeichen die nicht in OCF-Dateinamen erlaubt sind: %1$s PKG_010=Dateiname enthält Leerzeichen! Leerzeichen sollten vermieden werden. PKG_011=Dateiname darf nicht mit einem Punkt '.' enden. PKG_012=Dateiname enthält die folgenden Nicht-ASCII-Zeichen: '%1$s'. Versuche den Dateinamen zu ändern! PKG_013=Das EPUB enthält mehrere OPS-Darstellungen ('renditions'). PKG_014=Das EPUB enthält ein leeres Verzeichnis: %1$s PKG_015=Folgende Inhalte des EPUBs können nicht gelesen werden: %1$s PKG_016=Benutze nur Kleinbuchstaben für die EPUB-Dateiendung um die Kompatibilität zu erhöhen. PKG_016_SUG=Es sollte '.epub' verwendet werden. PKG_017=Unbekannte EPUB-Dateiendung. PKG_017_SUG=Es sollte '.epub' verwendet werden. PKG_018=Die EPUB-Datei wurde nicht gefunden. PKG_020=Die OPF-Datei '%1$s' wurde nicht gefunden. PKG_021=Fehlerhafte Bild-Datei gefunden. PKG_022=Falsche Dateiendung für das Bild. Es ist eine '%1$s'-Datei, besitzt aber die Dateiendung '%2$s'. PKG_023=Validierung gegen den EPUB-Standard 2.0 mit dem Standard-Validierungsprofil. #Resources RSC_001=Datei '%1$s' wurde nicht gefunden. RSC_002=Erforderliche Datei 'META-INF/container.xml' fehlt. RSC_003=Es wurde kein 'rootfile'-Element mit MimeType 'application/oebps-package+xml' im EPUB gefunden. RSC_004=Die DRM-geschützte Datei '%1$s' kann nicht entschlüsselt werden. RSC_005=Validierungsfehler: %1$s RSC_006=Verlinkte Ressourcen sind nicht erlaubt. Platzieren Sie den Inhalt stattdessen im EPUB selbst. RSC_006_SUG=Remote-Ressourcen sind nur für Audio und Video erlaubt! RSC_007=Die referenzierte Datei wurde im EPUB nicht gefunden. RSC_007w=Die Datei wurde im EPUB nicht gefunden. RSC_008=Die referenzierte Datei ist im OPF-Manifest nicht deklariert. RSC_009=Im 'src'-Attribut am 'img'-Element darf keine 'fragment identifier' (ID-Referenz) angegeben werden. RSC_010=Referenz auf eine Ressource gefunden, die laut Standard nicht erlaubt ist. RSC_011=Referenz auf eine Ressource gefunden, die nicht im OPF 'Spine' deklariert ist. RSC_012=Fragmentbezeichner ist nicht angegeben. RSC_013=Fragmentbezeichner wird in einem Link zu einem Stylesheet-Dokument genutzt. RSC_014=Fragmentbezeichner an einer inkompatiblen Ressource. RSC_015=Das SVG-Element benötigt zwingend einen Fragmentbezeichner zur Referenzierung. RSC_016=Schwerer Fehler beim Parsen der Datei '%1$s'. RSC_017=Warnung beim Parsen der Datei '%1$s'. RSC_018=Alternativabbildung '%1$s' wurde nicht gefunden. RSC_019=EPUBs mit mehreren Darstellungen ('renditions') sollten eine Datei 'META-INF/metadata.xml' enthalten. RSC_020='%1$s' ist keine gültige URI. RSC_021=Das Stichwortverzeichnis muss auf Inhaltsdokumente verweisen ('%1$s' wurde nicht im 'Spine' gefunden). RSC_022=Bilddetails können nicht geprüft werden (Java 7 oder neuer wird benötigt). #Scripting SCP_001=Die Nutzung der JavaScript-Funktion 'eval()' in EPUBs ist ein Sicherheitsrisiko! SCP_002=Die Nutzung der JavaScript-Funktionalität 'XMLHttpRequest' in EPUBs ist ein Sicherheitsrisiko! SCP_003="Local Storage" und "Session Storage" werden derzeit nicht unterstützt. SCP_004=Datei enthält ein Skript welches in EPUB 2 derzeit nicht unterstützt wird. SCP_005=Datei enthält ein Skript, wurde aber im OPF nicht als 'scripted' gekennzeichnet. SCP_006=Inzeilige JavaScript-Anweisungen gefunden. SCP_007=Skript nutzt 'innerHtml'. SCP_007_SUG=Benutze besser einen DOM-Handler. SCP_008=Skript nutzt 'innerText'. SCP_008_SUG=Benutze besser 'textContent'. SCP_009=Datei nutzt Maus-EventHandler. SCP_009_SUG=Stelle sicher, dass alle Maus-basierten Events auch per Tastatur oder Touch-Eingabe funktionieren. SCP_010=EPUB 3 Inhaltsdatei enthält Skripte. epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/messages/MessageBundle.properties0000644000175000017500000005045713017276730030742 0ustar eugeneeugene# This is the default MessageBundle.properties file #Accessibility ACC_001='img' or 'area' HTML element has no 'alt' attribute. ACC_002='input' HTML element is not referenced by a corresponding label element. ACC_003=Non-text html elements should include a 'title' attribute for accessibility. ACC_004=Html 'a' element must have text. ACC_005=Table heading cells should be identified by 'th' elements for accessibility. ACC_006=Tables should include a 'thead' element for accessibility. ACC_007=Content Documents do not use 'epub:type' attributes for semantic inflection. ACC_008=Navigation Document has no 'landmarks nav' element. ACC_009=MathML should either have an 'alttext' attribute or 'annotation-xml' child element. ACC_010=Headings should not be used within blockquote and figure elements. ACC_011=SVG hyperlinks should have a human-readable title (using the 'title' child element or the 'xlink:title' attribute). ACC_012=Table elements should include a caption element. ACC_013=Content file contains at least one inline style declaration. ACC_013_SUG=Inline styles are not compatible with accessibility settings and display personalization. Use CSS Styles instead. ACC_014=Value of CSS property 'font-size' does not use a relative size. ACC_014_SUG=Acceptable values include percentages, em multiples, 'larger', 'smaller', 'normal' or 'inherit'. ACC_015=Value of CSS property 'line-height' does not use a relative size. ACC_015_SUG=Acceptable values include percentages, numeric multiples, em multiples, 'normal', or 'inherit'. ACC_016=Value of CSS property 'font-size' should use a relative size. ACC_016_SUG=Acceptable values include percentages, em multiples, 'larger', 'smaller', 'normal' or 'inherit'. ACC_017=Value of CSS property 'line-height' does not use a relative size. ACC_017_SUG=Acceptable values include percentages, numeric multiples, em multiples, 'normal', or 'inherit'. #Checker Errors CHK_001=The custom message overrides file was not found. CHK_002=Unrecognized custom message id %1$s encountered in message overrides file '%2$s'. CHK_003=Unrecognized custom message severity '%1$s' encountered in message overrides file '%2$s'. CHK_004=The custom message contains too many parameters in message overrides file '%1$s'. CHK_005=The custom suggestion contains too many parameters in message overrides file '%1$s'. CHK_006=Unable to parse the custom format parameter in message overrides file '%1$s'. CHK_007=Error encountered while processing custom message file '%1$s': "%2$s". #CSS CSS_001=The \'%1$s\' property must not be included in an EPUB Style Sheet. CSS_002=Empty or NULL reference found. CSS_003=Only UTF-8 and UTF-16 encodings are allowed, detected %1$s. CSS_004=Only UTF-8 and UTF-16 encodings are allowed, detected %1$s BOM. CSS_005=Conflicting alternate style attributes found: %1$s. CSS_006=CSS position:fixed property should not be used in EPUBs. CSS_007=Font-face reference %1$s refers to non-standard font type %2$s. CSS_008=An error occurred while parsing the CSS: %1$s. CSS_009=Use of certain CSS such as Columns, Transforms, Transitions, box-sizing or KeyFrames can cause pagination issues. CSS_010=Stylesheet of type other than 'text/css' must have a fallback. CSS_011=Excessive number of css files. CSS_011_SUG=Consider merging CSS files to reduce the number of CSS files. CSS_012=Document links to multiple CSS files. CSS_013=CSS property is declared !Important. CSS_015=Alternate Stylesheet has no title. CSS_016=Alternate Stylesheet precedes primary stylesheet. CSS_017=CSS selector specifies absolute position. CSS_019=CSS font-face declaration has no attributes. CSS_020=CSS font selector declaration uses unexpected font-size value '%1$s'. CSS_020_SUG=Acceptable values include percentages, em multiples, 'larger', 'smaller', 'normal' or 'inherit'. CSS_021=Shorthand CSS property 'font-family' specifies an invalid System Font. CSS_021_SUG=Acceptable values include 'caption', 'icon', 'menu', 'message-box', 'small-caption', 'status-bar', or 'inherit'. CSS_022=CSS selector specifies global margin setting. CSS_023=CSS selector specifies media query. CSS_024=CSS class Selector is not used. CSS_024_SUG=Remove unused CSS selectors. CSS_025=CSS class Selector could not be found. CSS_025_SUG=Check for typos or define a class selector to document the use of the class. CSS_027=CSS selector specifies absolute position. CSS_028=Use of Font-face declaration. #HTM - XHTML related messages HTM_001=Any publication resource that is an XML-based media type must be a valid XML 1.0 document. XML version found: %1$s. HTM_002=The installed xml parser doesn't support xml version verification. Xml files must be a valid XML 1.0 document. HTM_003=External entities are not allowed in EPUB v3 documents. External entity declaration found: %1$s. HTM_004=Irregular DOCTYPE: found '%1$s', expected '%2$s'. HTM_005=An external reference was found. HTM_006=An XHTML Named Entity was found. HTM_007=Empty or whitespace-only value of attribute ssml:ph. HTM_008=The src attribute is required. HTM_009=The DOCTYPE provided is obsolete or irregular and can be removed. HTM_010=Namespace uri '%1$s' was found. HTM_011=Entity is undeclared. HTM_011_SUG=Define the entity or use the numbered entity instead. HTM_012=Found a link to a CFI in an external book. HTM_013=Intra-Publication CFIs found in document. HTM_014=Invalid file extension for HTML file, expecting (html, htm or xhtml). HTM_014a=XHTML Content Document file name '%1$s' should have the extension '.xhtml'. HTM_015=HTML4 DOCTYPE definition within EPUB v3. HTM_016=HTML5 DOCTYPE definition within EPUB v2. HTM_017=Content file has different language value in attributes xml:lang and lang. HTM_018=Content file has invalid language value at attribute xml:lang. HTM_019=Content file has invalid language definition at attribute lang. HTM_020=Content file doesn't contain xml:lang attribute. HTM_021=Content file doesn't contain lang attribute. HTM_022=Document may contain excessive DIV or SPAN tags. HTM_022_SUG=Merge DIV or SPAN tags when they are consecutive and use the same style. HTM_023=An invalid XHTML Named Entity was found: '%1$s'. HTM_023_SUG=Check the spelling or use numbered entities instead. HTM_024=An XHTML Named Entity was found. Only '&' ''' '"e;' '<' or '>' are allowed. HTM_024_SUG=Check the spelling or use numbered entities instead. HTM_025=Non-registered URI scheme type found in href. HTM_027=List contains less than 2 items. HTM_027_SUG=Lists should have more than one item for accessibility. HTM_028=Input html elements should include an id. HTM_029=Label html elements should include a 'for' attribute referencing the id of an input element. HTM_033=HTML 'head' element does not have a 'title' child element. HTM_036=IFrames are highly discouraged. HTM_038=Ensure b, i, em, and strong elements are used in compliance with W3C HTML5 directives. HTM_038_SUG=CSS styles are usually more appropriate for italics or bold text. HTM_043=SVG elements should include an xml:lang and lang attributes. HTM_044=Namespace uri '%1$s' was included but not used. HTM_044_SUG=Remove unused Namespace URIs. HTM_045=Encountered empty href. HTM_045_SUG=Empty hrefs are valid self-references. These should be validated to ensure that this is the desired intent. HTM_046=Fixed format item has no viewport defined. HTM_046_SUG=A viewport declaration is required for fixed format items. HTM_047=Html viewport is missing height and/or width. HTM_047_SUG=The viewport declaration must declare both width and height. HTM_048=SVG ViewBox is missing on fixed format document. HTM_048_SUG=A viewBox declaration is required for fixed format documents. HTM_049=Html element does not have an xmlns set to 'http://www.w3.org/1999/xhtml'. HTM_049_SUG=Add xmlns="http://www.w3.org/1999/xhtml" to the html element. HTM_050=Found epub:type="pagebreak" attribute in content document. HTM_051=Found Microdata semantic enrichments but no RDFa. EDUPUB recommends using RDFa Lite. HTM_052=The property 'region-based' is only allowed on nav elements in Data Navigation Documents. #media MED_001=Video poster must have core media image type. MED_002=%1$s element doesn't provide fallback. MED_003=Non-standard image resource of type %1$s found. MED_004=Image file header may be corrupted. MED_005=Media Overlay audio reference %1$s to non-standard audio type %2$s found. MED_006=Some browsers do not support rendering SVG images which use a filename in the xlink:href property. #NAV EPUB v3 Table of contents NAV_001=The nav file is not supported for EPUB v2. NAV_002=Found epub:type="page-list" in nav document NAV_003=The Navigation Document must have a page list when content document(s) contain page breaks (epub:type="pagebreak"). NAV_004=The Navigation Document should contain the full document heading hierarchy in EDUPUB. NAV_005=Content documents contain 'audio' elements but the Navigation Document does not have a listing of audio clips (epub:type="loa"). NAV_006=Content documents contain 'figure' elements but the Navigation Document does not have a listing of figures (epub:type="loi"). NAV_007=Content documents contain 'table' elements but the Navigation Document does not have a listing of tables (epub:type="lot"). NAV_008=Content documents contain 'video' elements but the Navigation Document does not have a listing of video clips (epub:type="lov"). NAV_009=Region-based navigation links must point to Fixed-Layout Documents. #NCX EPUB v2 Table of Contents NCX_001=NCX identifier ('%1$s') does not match OPF identifier ('%2$s'). NCX_002=toc attribute was not found on the spine element. NCX_003=An .NCX file is required for TOC navigation on EPUB v2 readers. NCX_004=NCX identifier ('dtb:uid' metadata) should not contain leading or trailing whitespace. NCX_005=Found ncx "page-list" in .ncx file NCX_006=Empty "text" label in the NCX document #OPF OPF_001=There was an error when parsing the EPUB version: %1$s. OPF_002=The OPF file '%1$s' was not found in the EPUB. OPF_003=Item '%1$s' exists in the EPUB, but is not declared in the OPF manifest. OPF_004=Invalid prefix declaration: leading or trailing whitespace is not allowed. OPF_004a=Invalid prefix declaration: found empty prefix. OPF_004b=Invalid prefix '%1$s': must be a valid non-colonized name (aka 'NCName'). OPF_004c=Invalid prefix declaration: prefix '%1$s' must be immediately followed by a colon character (':'). OPF_004d=Invalid prefix declaration: prefix '%1$s' must be separated by its URI with a space. OPF_004e=Invalid prefix declaration: found illegal whitespace between prefix and URI. OPF_004f=Invalid prefix declaration: found illegal whitespace between prefix mappings. OPF_005=Invalid prefix declaration: URI for prefix '%1$s' doesn't exist. OPF_006=Invalid prefix declaration: URI '%1$s' is not a valid URI. OPF_007=Re-declaration of reserved prefix '%1$s'. OPF_007a=Invalid prefix mapping: prefix '_' must not be declared. OPF_007b=Invalid prefix mapping: default vocabulary '%1$s' must not be re-declared. OPF_008=Handler binding for core Media-type '%1$s' is not allowed. OPF_009=The media-type '%1$s' has already been assigned a handler, with ID '%2$s'. OPF_010=Error resolving reference: '%1$s'. OPF_011=itemref can't have both page-spread-right and page-spread-left properties. OPF_012=Item property '%1$s' is not defined for media type '%2$s'. OPF_013=The type property '%1$s' on the object tag does not match the declared media-type '%2$s' in the OPF manifest. OPF_014=The property '%1$s' should be declared in the OPF file. OPF_015=The property '%1$s' should not be declared in the OPF file. OPF_016=The element \"rootfile\" is missing its required attribute \"full-path\". OPF_017=The attribute \"full-path\" on element \"rootfile\" must not be empty. OPF_018=The 'remote-resources' property was declared in the OPF, but no reference to remote resources has been found. Make sure this property is legitimate. OPF_019=Spine tag was not found in the OPF file. OPF_020=Excessive number of spine items. OPF_021=Use of non-registered URI scheme type in href: '%1$s'. OPF_025=Property '%1$s' can take only one value. OPF_026=Found malformed property value: '%1$s'. OPF_027=Undefined property: '%1$s'. OPF_028=Undeclared prefix: '%1$s'. OPF_029=The file '%1$s' does not appear to match the media type %2$s, as specified in the OPF file. OPF_030=The unique-identifier '%1$s' was not found. OPF_031=File listed in reference element in guide was not declared in OPF manifest: %1$s. OPF_032=Guide references '%1$s' which is not a valid 'OPS Content Document'. OPF_033=The spine contains no linear resources. OPF_034=The spine contains multiple references to the manifest item with id '%1$s'. OPF_035=Media type 'text/html' is not appropriate for XHTML/OPS. OPF_035_SUG=Use 'application/xhtml+xml' instead. OPF_036=Video type '%1$s' might not be supported by reading systems OPF_036_SUG=Use 'video/mp4', 'video/h264' or 'video/webm' instead. OPF_037=Found deprecated media-type '%1$s'. OPF_038=Media type '%1$s' is not appropriate for an OEBPS 1.2 context; Use 'text/x-oeb1-document' instead. OPF_039=Media-type '%1$s' is not appropriate in an OEBPS 1.2 context. Use 'text/x-oeb1-css' instead. OPF_040=Fallback item could not be found. OPF_041=Fallback-style item could not be found. OPF_042='%1$s' is not a permissible spine media-type. OPF_043=Spine item with non-standard media-type '%1$s' has no fallback. OPF_044=Spine item with non-standard media-type '%1$s' has a fallback to non-standard media-type. OPF_045=Encountered circular reference in fallback chain. OPF_046=Scripted property is not set on mediaType handler. OPF_047=OPF file is using OEBPS 1.2 syntax allowing backwards compatibility. OPF_048=Package tag is missing its required unique-identifier attribute and value. OPF_049=Item id '%1$s' was not found in the manifest. OPF_050=TOC attribute references resource with non-NCX mime type; 'application/x-dtbncx+xml' is expected. OPF_051=Image dimensions exceed recommended size. OPF_052=Role value '%1$s' is not valid. OPF_053=Date value '%1$s' does not follow recommended syntax as per http://www.w3.org/TR/NOTE-datetime:%2$s. OPF_054=Date value '%1$s' is not valid as per http://www.w3.org/TR/NOTE-datetime:%2$s. OPF_055=%1$s tag is empty. OPF_056=Media type '%1$s' is not a core audio type. OPF_057=Image file length exceeds recommended size. OPF_058=Spine item has no TOC entry reference. OPF_058_SUG=Every spine item in the manifest should be referenced by at least one TOC entry. OPF_059=Spine item has no NCX entry reference. OPF_059_SUG=Every spine item in the manifest should be referenced by at least one NCX entry. OPF_060=Duplicate entry in the ZIP file: '%1$f'. OPF_061=Duplicate entry in the ZIP file (after Unicode NFC normalization) '%1$f'. OPF_062=Found Adobe page-map attribute on spine element in opf file. OPF_063=Referenced Adobe page-map item '%1$s' was not found in the manifest. OPF_064=OPF declares type '%1$s', validating using profile '%2$s'. OPF_065=Invalid metadata declaration, probably due to a cycle in 'refines' metadata. OPF_066=Missing 'dc:source' or 'source-of' pagination metadata. The pagination source must be identified using the 'dc:source' and 'source-of' properties when the content includes page break markers. OPF_067=The resource '%1$s' must not be listed both as a 'link' element in the package metadata and as a manifest item. OPF_068=Unknown collection role '%1$s'. OPF_069=Custom collection role URI '%1$s' must not include the string 'idpf.org' in its host component. OPF_070=Custom collection role '%1$s' is an invalid URI. OPF_071=Index collections must only contain resources pointing to XHTML Content Documents. OPF_072=Metadata element '%1$s' is empty. OPF_073=External identifiers must not appear in the document type declaration. OPF_074=Package resource '%1$s' is declared in several manifest item. OPF_075=Preview collections must only point to EPUB Content Documents. OPF_076=The URI of preview collections link elements must not include EPUB canonical fragment identifiers. OPF_077=A Data Navigation Document should not be included in the spine. OPF_078=An EPUB Dictionary must contain at least one Content Document with dictionary content (epub:type 'dictionary'). OPF_079=Dictionary content was found (epub:type 'dictionary'), the Package Document should declare the dc:type 'dictionary'. OPF_080=A Search Key Map document file name should have the extension '.xml'. OPF_081=Resource '%1$s' (referenced from an EPUB Dictionary collection) was not found. OPF_082=Found an EPUB Dictionary collection containing more than one Search Key Map Document. OPF_083=Found an EPUB Dictionary collection containing no Search Key Map Document. OPF_084=Found an EPUB Dictionary collection containing resource '%1$s' which is neither a Search Key Map Document nor an XHTML Content Document. #Package PKG_001=Validating the EPUB against version %1$s but detected version %2$s. PKG_003=Unable to read EPUB file header. This is likely a corrupted EPUB file. PKG_004=Corrupted EPUB ZIP header. PKG_005=The mimetype file has an extra field of length %1$s. The use of the extra field feature of the ZIP format is not permitted for the mimetype file. PKG_006=Mimetype file entry is missing or is not the first file in the archive. PKG_007=Mimetype file should only contain the string 'application/epub+zip' and should not be compressed. PKG_008=Unable to read file '%1$s'. PKG_009=File name contains characters that are not allowed in OCF file names: '%1$s'. PKG_010=Filename contains spaces, therefore URI escaping is necessary. Consider removing spaces from filename. PKG_011=Filename is not allowed to end with '.'. PKG_012=File name contains the following non-ascii characters: %1$s. Consider changing the filename. PKG_013=The EPUB file includes multiple OPS renditions. PKG_014=The EPUB contains empty directory '%1$s'. PKG_015=Unable to read EPUB contents: %1$s PKG_016=Use only lowercase characters for the EPUB file extension for maximum compatibility. PKG_016_SUG=For maximum compatibility, use '.epub'. PKG_017=Uncommon EPUB file extension. PKG_017_SUG=For maximum compatibility, use '.epub'. PKG_018=The EPUB file could not be found. PKG_020=OPF file '%1$s' could not be found. PKG_021=Corrupted image file encountered. PKG_022=Wrong file extension for image. The image is a '%1$s' file but has the file extension '%2$s'. PKG_023=Validating the EPUB against version 2.0, default validation profile will be used. #Resources RSC_001=File '%1$s' could not be found. RSC_002=Required META-INF/container.xml resource could not be found. RSC_003=No rootfile tag with media type 'application/oebps-package+xml' was found in the container. RSC_004=File '%1$s' could not be decrypted. RSC_005=Error while parsing file '%1$s'. RSC_006=Remote resource reference not allowed; resource must be placed in the OCF. RSC_006_SUG=Only audio and video remote resources are permitted. RSC_007=Referenced resource could not be found in the EPUB. RSC_007w=Referenced resource could not be found in the EPUB. RSC_008=Referenced resource is not declared in the OPF manifest. RSC_009=A fragment identifier should not be used with an img src attribute. RSC_010=Reference to non-standard resource type found. RSC_011=Found a reference to a resource that is not a spine item. RSC_012=Fragment identifier is not defined. RSC_013=Fragment identifier is used in a reference to a stylesheet resource. RSC_014=Fragment identifier defines an incompatible resource type. RSC_015=A fragment identifier is required for svg use tag references. RSC_016=Fatal Error while parsing file '%1$s'. RSC_017=Warning while parsing file '%1$s'. RSC_018=Alternative image file '%1$s' could not be found. RSC_019=EPUBs with Multiple Renditions should contain a META-INF/metadata.xml file. RSC_020='%1$s' is not a valid URI. RSC_021=A Search Key Map Document must point to Content Documents ('%1$s' was not found in the spine). RSC_022=Cannot check image details (requires Java version 7 or higher). #Scripting SCP_001=Use of Javascript eval() function in EPUB scripts is a security risk. SCP_002=Use of XMLHttpRequest in EPUB scripts is a security risk. SCP_003=Local and Session Storage is not currently supported. SCP_004=Content file contains script which is not supported in EPUB v2. SCP_005=Content file contains script but it is not marked as scripted. SCP_006=Inline scripts found. SCP_007=Script references 'innerHtml'. SCP_007_SUG=Use a DOM instead. SCP_008=Script references 'innerText'. SCP_008_SUG=Use 'textContent' instead. SCP_009=Content file uses mouse event handlers. SCP_009_SUG=Ensure that all mouse driven functionality is accessible from the keyboard and touch devices. SCP_010=Epub 3 content file contains script. epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/messages/MessageBundle_ja.properties0000644000175000017500000006736113017276730031416 0ustar eugeneeugene# This is the default MessageBundle.properties file #Accessibility ACC_001=imgやarea要素がalt属性を持っていません. ACC_002=HTMLのinput要素は対応するlabel要素から参照されるべきです. ACC_003=テキストではないHTML要素はアクセシビリティのため 'title' 属性を持つべきです. ACC_004=HTMLの 'a' 要素にはテキスト内容が必要です. ACC_005=tableの見出しのセルはアクセシビリティのため 'th' 要素で識別されるべきです. ACC_006=tableはアクセシビリティのため 'thead' 要素を持つべきです. ACC_007=コンテンツ文書がepub:type属性を意味変化のために使っていません. ACC_008=ナビゲーション文書が、landmarks nav要素を持っていません. ACC_009=MathMLはalt属性のテキストか、annotation-xml子要素を持つべきです. ACC_010=blockquote要素かfigure要素内では見出しを使うべきではありません. ACC_011=SVG内のlink要素はxlink:title属性を持つべきです. ACC_012=table要素はcaption要素を含むべきです. ACC_013=コンテンツファイルは少なくとも1つのインラインスタイル宣言を含むべきです. ACC_013_SUG=インラインスタイルはアクセシビリティ設定と表示のパーソナライゼーションに適合しません. 代わりにCSSスタイルを使って下さい. ACC_014=CSSセレクタのfont-size属性値に相対サイズを使っていません. ACC_014_SUG=取りうる値はパーセンテージか、em単位か、'larger'、'smaller'、'normal'、または 'inherit' です. ACC_015=CSSセレクタのフォントのline-height属性値に相対サイズを使っていません. ACC_015_SUG=取りうる値はパーセンテージか、数値単位か、em単位か、'normal'、または 'inherit' です. ACC_016=CSSセレクタのfont-size属性値には相対サイズを使うべきです. ACC_016_SUG=取りうる値はパーセンテージか、em単位か、'larger'、'smaller'、'normal'、または 'inherit' です. ACC_017=CSSセレクタのフォントのline-height属性値に相対サイズを使っていません. ACC_017_SUG=取りうる値はパーセンテージか、数値単位か、em単位か、'normal'、または 'inherit' です. #Checker Errors CHK_001=ファイルを上書きしているカスタムメッセージが見つかりませんでした. CHK_002=認識できないカスタムメッセージid '%1$s' がファイル '%2$s' を上書きしたメッセージ内で見つかりました. CHK_003=認識できないカスタムメッセージ重要度 '%1$s' がファイル '%2$s' を上書きしたメッセージ内で見つかりました. CHK_004=ファイル '%1$s' を上書きしたメッセージ内のカスタムメッセージのパラメタが多すぎます. CHK_005=ファイル '%1$s' を上書きするメッセージ内のカスタムサジェッションに含まれるパラメタが多すぎます. CHK_006=ファイル '%1$s' を上書きするメッセージ内のカスタムフォーマットパラメタが解析できません. CHK_007=カスタムメッセージファイル '%1$s' の処理中にエラーが発生しました: "%2$s". #CSS CSS_001=プロパティ \'%1$s\' は EPUBのスタイルシートに含めることはできません. CSS_002=空またはNULLの参照が見つかりました. CSS_003=文字エンコード %1$s が検知されました. UTF-8またはUTF-16のみ許可されています. CSS_004=文字エンコード %1$s BOMが検知されました. UTF-8またはUTF-16のみ許可されています. CSS_005=矛盾する代替スタイル属性が見つかりました: %1$s. CSS_006=CSSのposition:fixedプロパティはEPUBでは使用すべきではありません. CSS_007=Font-face 参照 %1$s は、非標準のフォントタイプ %2$s を参照しています. CSS_008=CSSパース中にエラーが発生しました: %1$s. CSS_009=Columns、 Transforms、 Transitions、 box-sizingやKeyFramesなどのCSSを使うとページネーションの問題が起きる可能性があります. CSS_010=メディアタイプ 'text/css' 以外のスタイルシートにはフォールバックが必要です. CSS_011=CSSファイルが多すぎます. CSS_011_SUG=CSSのファイル数を減らすため、CSSファイルをマージすることを検討してください. CSS_012=文書が複数のCSSファイルへリンクしています. CSS_013=CSSセレクタ属性が!Important宣言されています. CSS_015=代替スタイルシートにタイトルがありません. CSS_016=代替スタイルシートが基本スタイルシートより優先されています. CSS_017=CSSセレクタでabsolute positionを指定しています. CSS_019=CSS font-face宣言に属性がありません. CSS_020=CSS font selector宣言が予期しないfont-size値 '%1$s' を使用しています. CSS_020_SUG=取りうる値はパーセンテージか、em単位か、'larger'、'smaller'、'normal'、または 'inherit' です. CSS_021=CSSセレクタ fontショートハンドで無効なシステムフォントが指定されています. CSS_021_SUG=取りうる値は 'caption'、 'icon'、 'menu'、 'message-box'、 'small-caption'、 'status-bar' または 'inherit' です. CSS_022=CSSセレクタがグローバルマージン設定を指定しています. CSS_023=CSSセレクタがメディアクエリを指定しています. CSS_024=CSSクラスセレクタが使われていません. CSS_024_SUG=使用していないCSSセレクタを削除してください. CSS_025=CSSクラスセレクタが見つけられませんでした. CSS_025_SUG=タイプミスをチェックするか、クラスを利用するセレクタを定義してください. CSS_027=CSSセレクタでabsolute positionを指定しています. CSS_028=Font-face宣言が使われています. #HTM - XHTML related messages HTM_001=XMLベースのメディアタイプであるpublication resouceはすべて、validなXML 1.0文書でなくてはなりません. XMLバージョンが検出されました: %1$s. HTM_002=XMLパーサがXMLバージョンのverificationをサポートしていません. XMLファイルはvalidなXML 1.0の文書でなくてはなりません. HTM_003=EPUB v3文書では外部エンティティは許可されていません. 外部エンティティの宣言が見つかりました: %1$s. HTM_004=不正なDOCTYPE '%1$s' が見つかりました. '%2$s' であるべきです. HTM_005=外部参照が見つかりました. HTM_006=XHTML 名前付き実体が見つかりました. HTM_007=属性ssml:phが空か、空白文字のみの値です. HTM_008=src属性が必要です. HTM_009=DOCTYPEがobsoleteであるか不正なので、削除可能です. HTM_010=名前空間URI '%1$s' が見つかりました. HTM_011=実体が宣言されていません. HTM_011_SUG=実体を宣言するか、数値文字参照を使って下さい. HTM_012=外部の書籍のCFIへのリンクが見つかりました. HTM_013=パブリケーション内CFIが文書に見つかりました. HTM_014=HTML5に対する不正な拡張子が使われています. html、htmまたはxhtmlを使うべきです. HTM_014a=XHTMLコンテンツ文書 '%1$s'は拡張子.xhtmlを持つべきです. HTM_015=HTML4のDOCTYPE宣言がEPUB v3に含まれています. HTM_016=HTML5のDOCTYPE宣言がEPUB v2に含まれています. HTM_017=コンテンツファイルのxml:lang属性とlang属性に指定された言語が異なっています. HTM_018=コンテンツファイルのxml:lang属性の値が不正な言語になっています. HTM_019=コンテンツファイルのlang属性の値が不正な言語定義になっています. HTM_020=コンテンツファイルにxml:lang属性が含まれていません. HTM_021=コンテンツファイルにlang属性が含まれていません. HTM_022=文書が余分なDIVまたはSPANタグを含んでいます. HTM_022_SUG=複数のDIVまたはSPANタグが連続していて、かつ同じスタイルを使っているなら、マージしてください. HTM_023=不正な XHTML 名前付き実体が見つかりました : '%1$s'. HTM_023_SUG=スペルを確認するか、代わりに数値実体を使ってください. HTM_024=XHTML 名前付き実体が見つかりました. '&' ''' '"e;' '<' または '>' のみが許可されています. HTM_024_SUG=スペルを確認するか、代わりに数値実体を使ってください. HTM_025=登録されていないURI schemeがhrefで検出されました. HTM_027=リストが2つ以下の子しか持っていません. HTM_027_SUG=アクセスビリティのために、リストは1つ以上の要素を含んでいなくてはなりません. HTM_028=input HTML要素はidを含んでいなくてはなりません. HTM_029=label HTML要素は、input要素のidを参照するfor属性を含んでいなくてはなりません. HTM_033=HTML head要素にtitleが含まれていません. HTM_036=IFRAMEは強く非推奨です. HTM_038=b、i、em、strong要素がW3C HTML5の規定に従って使われていることを確認してください. HTM_038_SUG=イタリックやボールドのテキストは、CSSのスタイルで指定するほうが通常は適切です. HTM_043=SVG要素はxml:langまたはlang属性を含んでいなくてはなりません. HTM_044=名前空間URI '%1$s' が含まれていますが、使われていません. HTM_044_SUG=使われていない名前空間URIは削除してください. HTM_045=空のhrefを検出しました. HTM_045_SUG=空のhrefは、有効な自己参照ですが,意図してそう指定したのか確認してください. HTM_046=固定フォーマットのitemにviewportが宣言されていません. HTM_046_SUG=固定フォーマットのitemにはvieport宣言が必要です. HTM_047=HTML viewportにheightまたはwidthがありません. HTM_047_SUG=viewport宣言にはwidthとheightの両方が宣言されている必要があります. HTM_048=SVG ViewBoxが固定フォーマット文書にありません. HTM_048_SUG=固定フォーマット文書にはSVG ViewBox宣言が必要です. HTM_049=html要素の名前空間が 'http://www.w3.org/1999/xhtml' になっていません. HTM_049_SUG=html要素に xmlns="http://www.w3.org/1999/xhtml" を追加してください. HTM_050=epub:type="pagebreak" 属性をコンテンツ文書中に発見しました. HTM_051=RDFaではないMicrodata semantic enrichmentsが見つかりました. EDUPUBではRDFa Liteの使用が推奨されています. HTM_052='region-based'プロパティはデータナビゲーション文書中のnav要素でのみ許可されています. #media MED_001=video posterにはcore media image typeが必要です. MED_002=%1$s 要素にフォールバックが与えられていません. MED_003=非標準的な画像タイプのリソース %1$s が見つかりました. MED_004=画像ファイルのヘッダが壊れている可能性があります. MED_005=非標準の音声タイプ %2$s へのメディアオーバーレイの音声の参照 %1$s が見つかりました. MED_006=いくつかのブラウザではxlink:hrefプロパティ内でファイル名を使ったSVG画像の描画をサポートしていません. #NAV EPUB v3 Table of contents NAV_001=navファイルはEPUB v2ではサポートされていません. NAV_002=nav文書中にepub:type="page-list"を発見しました. NAV_003=コンテンツ文書(群)中に改ページ(epub:type="pagebreak")を含む場合、ナビゲーション文書はpage-listを含まなければなりません. NAV_004=ナビゲーション文書はEDUPUBの全ての文書のヘッダ階層構造を含むべきです. NAV_005=コンテンツ文書に'audio'要素が含まれていますが、ナビゲーション文書にはオーディオクリップ一覧(epub:type="loa")がありません. NAV_006=コンテンツ文書に'figure'要素が含まれていますが、ナビゲーション文書には画像一覧(epub:type="loi")がありません. NAV_007=コンテンツ文書に'table'要素が含まれていますが、ナビゲーション文書には表一覧(epub:type="lot")がありません. NAV_008=コンテンツ文書に'video'要素が含まれていますが、ナビゲーション文書には動画一覧(epub:type="lov")がありません. NAV_009=領域に基づく(region-based)ナビゲーションのリンクは固定レイアウト文書を指示しなければなりません #NCX EPUB v2 Table of Contents NCX_001=NCX識別子 ('%1$s') がOPF識別子('%2$s')と一致しません. NCX_002=spine要素にtoc属性が見つかりませんでした. NCX_003=EPUB v2リーダでのTOCナビゲーションのためには.NCX ファイルが必要です. NCX_004=NCX識別子 ('dtb:uid' メタデータ) の前後には余計な空白を含めてはいけません. NCX_005=.ncxファイル中にncx "page-list" があります. NCX_006=NCX文書中に空の"text"ラベルがあります #OPF OPF_001=EPUBバージョン: %1$s の解析時にエラーが発生しました. OPF_002=OPFファイル '%1$s' がEPUB内に見つかりませんでした. OPF_003=アイテム '%1$s' がEPUB内に存在しますが、OPFマニフェストで宣言されていません. OPF_004=prefixの宣言が誤っています.空白文字を先頭や末尾においてはいけません. OPF_004a=prefixの宣言が誤っています.空のprefixです. OPF_004b=prefixの宣言が誤っています. '%1$s'は、コロン(:)を含んではいけません. OPF_004c=prefixの宣言が誤っています. prefix '%1$s' の直後にコロン(':')が必要です. OPF_004d=prefixの宣言が誤っています.prefix '%1$s' と対応するURIの間にはスペースが必要です。 OPF_004e=prefixの宣言が誤っています.prefixとURIの間に許されない空白文字があります. OPF_004f=prefixの宣言が誤っています.prefixの対応付けの間に、許されない空白文字があります. OPF_005=prefixの宣言が誤っています. prefix '%1$s'に対するURLが存在しません. OPF_006=prefixの宣言が誤っています. URI '%1$s'は正しくありません. OPF_007=予約されたプリフィックス '%1$s' が再宣言されています. OPF_007a=prefixの宣言が誤っています.prefix '_'を宣言してはいけません. OPF_007b=prefixの対応付けが誤っています.デフォルトの語彙である '%1$s'を再宣言してはいけません. OPF_008=コアメディアタイプ '%1$s' のハンドラーバインディングは許されていません. OPF_009=メディアタイプ '%1$s' はすでにID '%2$s'のハンドラーにアサイン済みです. OPF_010=参照の解決に失敗しました: '%1$s'. OPF_011=itemref は spread-right と page-spread-left 属性を同時に持つことはできません. OPF_012=メディアタイプ '%2$s' に対して、アイテムのプロパティ '%1$s' が定義されていません. OPF_013=オブジェクトタグのタイププロパティ '%1$s' がOPFマニフェストで宣言されたメディアタイプ '%2$s' と合っていません. OPF_014=プロパティ '%1$s' をOPFで宣言してください. OPF_015=プロパティ '%1$s' はOPFで宣言すべきではありません. OPF_016=\"rootfile\" が必要な属性 \"full-path\" を持っていません. OPF_017=\"rootfile\" 要素の \"full-path\" 属性は空ではいけません. OPF_018=OPFで 'remote-resources' プロパティが宣言されていますが、リモートリソースへの参照が見当たりません.このプロパティが正しいかどうか確認してください. OPF_019=OPFファイルにspineタグが見当たりません. OPF_020=spineアイテムの数が多すぎます. OPF_021=href '%1$s' の中で登録されていないURIスキーマが使われています. OPF_025='%1$s' プロパティは一つの値しか取ることができません. OPF_026=プロパティの値が不正です: '%1$s'. OPF_027=未定義のプロパティ: '%1$s'. OPF_028=未定義のプレフィックス '%1$s'. OPF_029=ファイル '%1$s' がOPFファイルで指定されたメディアタイプ %2$s と一致していないようです. OPF_030=ユニークID '%1$s' が見つかりません. OPF_031=guide要素のreference要素で指定された以下のファイルがOPFのマニフェストで宣言されていません: %1$s. OPF_032=guide要素が '%1$s' を参照していますが、これは有効なOPFコンテンツドキュメントではありません. OPF_033=spine要素にlinear指定されたリソースが含まれていません. OPF_034=spine要素に '%1$s' というIDを持ったマニフェストのアイテムへの重複した参照が含まれています. OPF_035=XHTML/OPSに適したメディアタイプは 'text/html' です. OPF_035_SUG='application/xhtml+xml' を代わりに使ってください. OPF_036=ビデオの種別'%1$s'は閲覧システムがサポートしていないかもしれません. OPF_036_SUG='video/mp4' or 'video/h264' or 'video/webm' を代わりに使ってください. OPF_037=廃止予定のメディアタイプ '%1$s' を見つけました. OPF_038=メディアタイプ '%1$s' はOEBPS 1.2には適していません. 'text/x-oeb1-document' を使ってください. OPF_039=メディアタイプ '%1$s' はOEBPS 1.2には適していません. 'text/x-oeb1-css' を使ってください. OPF_040=フォールバック用アイテムが見つかりません. OPF_041=フォールバックスタイルのアイテムが見つかりません. OPF_042='%1$s' はspine要素に使用可能なメディアタイプではありません. OPF_043=非標準のメディアタイプ '%1$s' を持ったspine要素はフォールバックできません. OPF_044=非標準のメディアタイプ '%1$s' を持ったspine要素は非標準のメディアタイプにフォールバックします. OPF_045=フォールバックチェーンに循環参照がありました. OPF_046=記述されたプロパティはメディアタイプハンドラにセットされていません. OPF_047=OPFのファイルは後方互換性のためにOEBPS 1.2を使っています. OPF_048=packageタグに必須のユニークID属性と値がありません. OPF_049=ID '%1$s' のアイテムがマニフェストにありません. OPF_050=TOC属性がNCXではないmime typeのリソースを参照しています. 'application/x-dtbncx+xml' ではないでしょうか. OPF_051=画像のサイズが推奨サイズを超過しています. OPF_052=roleの値 '%1$s' は有効ではありません. OPF_053=dateの値 '%1$s' は http://www.w3.org/TR/NOTE-datetime:%2$s で推奨されている文法に従っていません. OPF_054=dateの値 '%1$s' は http://www.w3.org/TR/NOTE-datetime:%2$s によると有効ではありません. OPF_055=%1$sタグが空です. OPF_056=メディアタイプ '%1$s' は標準のオーディオ用メディアタイプではありません. OPF_057=画像の辺の長さが推奨のサイズを超えています. OPF_058=spineアイテムにTOCエントリからの参照がありません. OPF_058_SUG=マニフェストのspineアイテムは少なくとも一つのTOCエントリーによって参照されなければなりません. OPF_059=spineアイテムにNCXエントリーからの参照がありません. OPF_059_SUG=マニフェストのどのspineアイテムも、少なくとも一つのNCXエントリから参照されなければなりません. OPF_060=ZIPファイル中の以下のエントリが重複しています: '%1$f' OPF_061=ZIPファイル中の以下のエントリが重複しています(UnicodeのNFC正規化後): '%1$f'. OPF_062=Adobeのpage-map属性がopfファイルのspine要素にあります. OPF_063=Adobeのpage-map項目'%1$s'はmanifestに存在しません. OPF_064=OPFでタイプ '%1$s'が宣言されているため、'%2$s' プロファイルを使って検証します. OPF_065=不正なメタデータ宣言があります. これは'refines'メタデータの循環参照によるものと思われます. OPF_066='dc:source' または 'source-of' のページネーションメタデータがありません. コンテンツが改ページマーカを含む場合、ページネーションソースは'dc:source' か 'source-of' 属性を使って一意に指定されなければいけません. OPF_067=リソース '%1$s' はパッケージのmetadata内の'link'要素としても, minifestのアイテムとしてもリストされていません. OPF_068=collection要素のrole属性が不明な値 '%1$s' です. OPF_069=collection要素のrole属性として指定されているカスタムのURI '%1$s'には, ホストコンポーネントとして'idpf.org' という文字列を含んではいけません. OPF_070=collection要素のrole属性として指定されているカスタムのURI '%1$s'は, 不正なURIです. OPF_071=Index collectionはXHTMLコンテンツ文書を指示するリソースのみを含まなければなりません. OPF_072=メタデータ要素 '%1$s' が空です. OPF_073=文書型宣言では外部識別子を使用できません. OPF_074=パッケージリソース '%1$s' は複数のmanifest要素内のitemで宣言されています. OPF_075=Preview collectionではEPUBコンテンツ文書のみを指示しなければなりません. OPF_076=preview collectionのlink要素のURIはEPUBのカノニカルフラグメント識別子を含んではいけません. OPF_077=データナビゲーション文書はspine内に含まれるべきではありません. OPF_078=EPUBディクショナリはディクショナリコンテンツ(epub:type 'dictionary')を持つコンテンツ文書を最低1つ含まなければなりません. OPF_079=ディクショナリコンテンツ(epub:type 'dictionary')が見つかりました. パッケージ文書は dc:type 'dictionary' で宣言するべきです. OPF_080=Search Key Map文書のファイル名は拡張子 '.xml' を使うべきです. OPF_081=(EPUBディクショナリのcollectionから参照されている)リソース '%1$s' が見つかりませんでした. OPF_082=複数のSearch Key Map文書を含んでいるEPUBディクショナリのcollectionが見つかりました. OPF_083=Search Key Map文書を含まないEPUB Dictionary collectionが見つかりました. OPF_084=Search Key Map文書でもXHTMLコンテンツ文書でもないリソース '%1$s' を含んでいるEPUBディクショナリのcollectionが見つかりました. #Package PKG_001=EPUBバージョン %1$s として検証していますが、バージョン %2$s を検知しました. PKG_003=EPUBファイルヘッダーが読めません. EPUBファイルが破損していると思われます. PKG_004=EPUB ZIPヘッダが破損しています. PKG_005=mimetypeファイルに長さ%1$sの拡張フィールドがあります. mimetypeファイルでZIPフォーマットの拡張フィールド属性を使うことは許可されていません. PKG_006=mimetypeファイルエントリが存在しないか、アーカイブの先頭以外の場所に存在しています. PKG_007=mimetypeファイルは文字列 'application/epub+zip' だけを含み、また圧縮してはいけません. PKG_008=ファイル '%1$s' が読み込めません. PKG_009=OCFファイル名で許可されていない文字がファイル名に含まれています: '%1$s'. PKG_010=ファイル名に空白文字が含まれているため、URIエスケープが必要です. ファイル名から空白文字を削除することを検討してください. PKG_011=ファイル名が '.' で終わってはいけません. PKG_012=ファイル名が次のnon-ascii文字を含んでいます: %1$s. ファイル名の変更を検討してください. PKG_013=EPUBファイルが複数のOPS renditionを含んでいます. PKG_014=EPUBが空のディレクトリ '%1$s' を含んでいます. PKG_015=EPUBコンテンツ: %1$s を読み込めません. PKG_016=互換性を最大限高めるため, EPUBファイルの拡張子には小文字だけを使ってください. PKG_016_SUG=互換性のため、'.epub' を使って下さい. PKG_017=一般的ではないEPUBファイル拡張子です. PKG_017_SUG=互換性のため、'.epub' を使って下さい. PKG_018=EPUBファイルが見つかりません. PKG_020=OPFファイル '%1$s' が見つかりません. PKG_021=壊れた画像ファイルがありました. PKG_022=イメージへの拡張子が間違っています.イメージは'%1$s'ファイルですが、拡張子'%2$s'を持っています。 PKG_023=EPUBバージョン2.0として検証するため, デフォルトの検証用プロファイルが使われます. #Resources RSC_001=ファイル '%1$s' が見つかりません. RSC_002=必須の META-INF/container.xml リソースが見つかりません. RSC_003=コンテナ内にメディアタイプ 'application/oebps-package+xml' を持つルートファイルタグが見つかりませんでした. RSC_004=ファイル '%1$s' が復号できませんでした. RSC_005=ファイル解析時のエラー '%1$s'. RSC_006=外部リソースへの参照は許されていません; リソースはOCF内になければいけません. RSC_006_SUG=音声と画像の外部リソースのみ許可されています. RSC_007=参照されているリソースがEPUB内に見つかりません. RSC_007w=参照されたリソースがEPUB内に見つかりませんでした. RSC_008=参照されているリソースがOPF manifest内で宣言されていません. RSC_009=フラグメント識別子はimg要素のsrc属性で使うべきではありません. RSC_010=標準ではないリソースタイプへの参照が見つかりました. RSC_011=spine項目ではないリソースへの参照が見つかりました. RSC_012=フラグメント識別子が定義されていません. RSC_013=スタイルシートへの参照の中でフラグメント識別子が使われています. RSC_014=不適合なリソースタイプ内でフラグメント識別子が定義されています. RSC_015=タグリファレンスを使ったSVGにはフラグメント識別子が必要です. RSC_016=ファイル解析時の致命的なエラー '%1$s'. RSC_017=ファイル解析時の警告 '%1$s'. RSC_018=代替画像ファイル '%1$s' が見つかりません. RSC_019=Renditionを複数持つEPUBはMETA-INF/metadata.xmlを含むべきです. RSC_020='%1$s' は正しいURIではありません. RSC_021=Search Key Map文書はコンテンツ文書を指示していなければいけません('%1$s' はspine内では見つかりませんでした). RSC_022=画像の詳細情報が確認できません(Java version 7以降が必要です). #Scripting SCP_001=EPUBスクリプト内でのJavascript eval()関数の使用にはセキュリティ上のリスクがあります. SCP_002=EPUBスクリプト内でのXMLHttpRequest関数の使用にはセキュリティ上のリスクがあります. SCP_003=ローカルストレージとセッションストレージは現状サポートされていません. SCP_004=EPUB v2ではサポートされていないスクリプトがコンテンツファイルに含まれています. SCP_005=スクリプトを含むコンテンツファイルがscriptedとしてマークされていません. SCP_006=インラインスクリプトが見つかりました. SCP_007=スクリプトが 'innerHtml' を参照しています. SCP_007_SUG=代わりにDOMを使って下さい. SCP_008=スクリプトが 'innerText' を参照しています. SCP_008_SUG=代わりに 'textContent' を使って下さい. SCP_009=コンテンツファイルがmouse event handlerを使っています. SCP_009_SUG=全てのマウスを使った機能がキーボードやタッチデバイスからも利用可能か確認してください. SCP_010=EPUB 3 コンテンツファイルがスクリプトを含んでいます. epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/messages/MessageBundle_fr.properties0000644000175000017500000006174413017276730031432 0ustar eugeneeugene# This is the default MessageBundle.properties file #Accessibility ACC_001=Les éléments HTML 'img' ou 'area' n'ont pas d'attribut 'alt'. ACC_002=L'élément HTML 'input' n'est pas référencé par un élément 'label' correspondant. ACC_003=Les éléments HTML non-textuels devraient inclure un attribut 'title' pour l'accessibilité. ACC_004=L'élément HTML 'a' doit avoir du texte. ACC_005=Les cellules de l'en-tête du tableau devraient être identifiées par des éléments 'th' pour l'accessibilité. ACC_006=Les tableaux devraient inclure un élément 'thead' pour l'accessibilité. ACC_007=Les documents de contenu (Content Documents) n'utilisent pas l'attribut 'epub:type' pour l'inflexion sémantique (semantic inflection). ACC_008=Le document de navigation (Navigation Document) n'a pas d'élément 'landmarks nav'. ACC_009=MathML devrait avoir soit un attribut 'alttext' soit un élément fils 'annotation-xml'. ACC_010=Les titrailles ne devrait pas être utilisées au sein des éléments 'blockquote' et 'figure'. ACC_011=Les liens hypertexte SVG devraient avoir un titre lisible (défini dans l'élément 'title' ou l'attribut 'xlink:title'). ACC_012=Les éléments 'table' devraient inclure un élément 'caption'. ACC_013=Le contenu du fichier contient au moins une déclaration de style en ligne (inline style declaration). ACC_013_SUG=Les styles en ligne (inline styles) ne sont pas compatibles avec les paramètres d'accessibilité et de personnalisation de l'affichage. Utilisez les styles CSS à la place. ACC_014=La valeur de la propriété CSS 'font-size' n'utilise pas une taille relative. ACC_014_SUG=Les valeurs acceptées sont les pourcentages, les multiples em, 'larger', 'smaller', 'normal' ou 'inherit'. ACC_015=La valeur de la propriété CSS 'line-height' n'utilise pas une taille relative. ACC_015_SUG=Les valeurs acceptées sont les pourcentages, les multiples numériques, les multiples em, 'normal' ou 'inherit'. ACC_016=La valeur de la propriété CSS 'font-size' devrait utiliser une taille relative. ACC_016_SUG=Les valeurs acceptées sont les pourcentages, les multiples em, 'larger', 'smaller', 'normal' ou 'inherit'. ACC_017=La valeur de la propriété CSS 'line-height' n'utilise pas une taille relative. ACC_017_SUG=Les valeurs acceptées sont les pourcentages, les multiples numériques, les multiples em, 'normal' ou 'inherit'. #Checker Errors CHK_001=Le fichier personnalisé des remplacements de message est introuvable. CHK_002=Id du message personnalisé '%1$s' rencontré dans le fichier des remplacements de message '%2$s' non reconnu. CHK_003=La gravité du message personnalisé '%1$s' rencontrée dans le fichier des remplacements de message '%2$s' non reconnue. CHK_004=Le message personnalisé contient trop de paramètres dans le fichier des remplacements de message '%1$s'. CHK_005=La suggestion personnalisée contient trop de paramètres dans le fichier des remplacements de message '%1$s'. CHK_006=Impossible de parcourir le paramètre de format personnalisé dans le fichier des remplacements de message '%1$s'. CHK_007=Une erreur s'est produite lors du traitement du fichier de message personnalisé '%1$s': "%2$s". #CSS CSS_001=La propriété \'%1$s\' ne doit pas être incluse dans une feuille de style ePub. CSS_002=Référence vide ou NULL présente. CSS_003=Seuls les encodages UTF-8 et UTF-16 sont autorisés, '%1$s' détecté. CSS_004=Seuls les encodages UTF-8 et UTF-16 sont autorisés, '%1$s' BOM détecté. CSS_005=Attributs de style alternatif contradictoires trouvés : '%1$s'. CSS_006=La propriété CSS position:fixed ne devrait pas être utilisée dans des EPUBs. CSS_007=La référence font-face '%1$s' se réfère à une fonte de type non-standard '%2$s'. CSS_008=Une erreur s'est produite lors de l'analyse de la CSS : '%1$s'. CSS_009=L'utilisation de certaines parties CSS comme Columns, Transforms, Transitions, box-sizing ou KeyFrames peut causer des problèmes de pagination. CSS_010=Le feuille de style d'un type différent de 'text/css' doivent avoir un fallback. CSS_011=Nombre excessif de fichiers CSS. CSS_011_SUG=Considérez la fusion de fichiers CSS pour réduire le nombre de fichiers CSS. CSS_012=Le document est relié à plusieurs fichiers CSS. CSS_013=La propriété CSS est déclarée !Important. CSS_015=La feuille de style alternative (Alternate Stylesheet) n'a pas de titre. CSS_016=La feuille de style alternative (Alternate Stylesheet) précède la feuille de style principale. CSS_017=Le sélecteur CSS spécifie une position absolue. CSS_019=La déclaration CSS font-face n'a pas d'attribut. CSS_020=La déclaration du sélecteur CSS font utilise une valeur 'font-size' '%1$s' inattendue. CSS_020_SUG=Les valeurs acceptées sont les pourcentages, les multiples em, 'larger', 'smaller', 'normal' ou 'inherit'. CSS_021=La propriété CSS raccourcie 'font-family' spécifie une Fonte Système (System Font) incorrecte. CSS_021_SUG=Les valeurs acceptées sont 'caption', 'icon', 'menu', 'message-box', 'small-caption', 'status-bar' ou 'inherit'. CSS_022=Le sélecteur CSS spécifie le paramétrage de la marge globale. CSS_023=Le sélecteur CSS spécifie des media query. CSS_024=Le sélecteur CSS de classe n'est pas utilisé. CSS_024_SUG=Supprimez les sélecteurs CSS inutilisés. CSS_025=Le sélecteur CSS de classe est introuvable. CSS_025_SUG=Vérifiez les fautes de frappe ou définissez un sélecteur de classe pour attester de l'utilisation de la classe. CSS_027=Le sélecteur CSS spécifie une position absolue. CSS_028=Utilisation d'une déclaration font-face. #HTM - XHTML related messages HTM_001=Tout document de référence qui a un mediatype basé sur XML doit être un document valide XML 1.0. Version XML trouvée : '%1$s'. HTM_002=Le parseur XML installé ne supporte pas la vérification de la version de XML. Les fichiers XML doivent être des documents valides XML 1.0. HTM_003=Les entités externes ne sont pas autorisées dans des documents EPUB v3. Déclaration d'une entité externe trouvée : '%1$s'. HTM_004=DOCTYPE anormal : '%1$s' trouvé, '%2$s' attendu. HTM_005=Une référence externe a été trouvée. HTM_006=Une entité XHTML a été trouvée. HTM_007=Valeur de l'attribut ssml:ph vide ou composée uniquement d'espace(s). HTM_008=L'attribut src est requis. HTM_009=Le DOCTYPE fourni est obsolète ou anormal et peut être supprimé. HTM_010=L'URI de l'espace de noms '%1$s' a été trouvé. HTM_011=L'entité n'est pas déclarée. HTM_011_SUG=Définissez l'entité ou utilisez l'entité numérique à la place. HTM_012=Un lien vers un CFI dans un livre externe est présent. HTM_013=des Intra-Publication CFIs ont été trouvés dans le document. HTM_014=Extension de fichier incorrecte pour un fichier HTML, (html, htm ou xhtml) attendus. HTM_014a=Le nom de fichier du XHTML Content Document '%1$s' devrait avoir l'extension '.xhtml'. HTM_015=Définition de DOCTYPE HTML4 au sein d'un EPUB v3. HTM_016=Définition de DOCTYPE HTML5 au sein d'un EPUB v2. HTM_017=Le fichier de contenu a différentes valeurs de langage dans les attributs 'xml:lang' et 'lang'. HTM_018=Le fichier de contenu a une valeur de langage incorrecte dans l'attribut 'xml:lang'. HTM_019=Le fichier de contenu a une définition de langage incorrecte dans l'attribut 'lang'. HTM_020=Le fichier de contenu ne contient pas d'attribut xml:lang. HTM_021=Le fichier de contenu ne contient pas d'attribut lang. HTM_022=Le document pourrait contenir des balises DIV ou SPAN excessives. HTM_022_SUG=Fusionnez les éléments DIV ou SPAN quand ils sont consécutifs et utilisez le même style. HTM_023=Une entité XHTML incorrecte a été trouvée : '%1$s'. HTM_023_SUG=Vérifiez l'orthographe ou utilisez des entités numériques à la place. HTM_024=Une entité XHTML a été trouvé. Seules '&', ''', '"e;', '<' ou '>' sont autorisées. HTM_024_SUG=Vérifiez l'orthographe ou utilisez des entités numériques à la place. HTM_025=Type de protocole URI non-autorisé trouvé dans 'href'. HTM_027=La liste contient moins de 2 items. HTM_027_SUG=Les listes devraient avoir plus d'un item pour l'accessibilité. HTM_028=Les éléments HTML 'input' devraient inclure un id. HTM_029=Les éléments HTML 'label' devraient inclure un attribut 'for' référençant l'id d'un élément 'input'. HTM_033=L'élément HTML 'head' ne possède pas d'élément fils 'title'. HTM_036=Les iframes sont fortement déconseillés. HTM_038=Assurez vous que les éléments 'b', 'i', 'em' et 'strong' sont utilisés en accord avec les directives HTML5 du W3C. HTM_038_SUG=Les styles CSS sont généralement plus appropriés pour le texte italique ou gras. HTM_043=Les éléments 'svg' devraient inclure des attributs xml:lang et lang. HTM_044=L'URI de l'espace de nom '%1$s' est inclus mais pas utilisé. HTM_044_SUG=Supprimez les URI des espaces de noms inutilisés. HTM_045=href vide rencontré. HTM_045_SUG=href vides sont des auto-références valides. Ceux-ci devraient être validés pour s'assurer qu'il s'agit de l'intention voulue. HTM_046=L'item de format 'fixed' n'a pas de 'viewport' défini. HTM_046_SUG=Une déclaration de 'viewport' est requise pour les items de format 'fixed'. HTM_047=Il manque la hauteur (height) et/ou la largeur (width) pour le 'viewport' HTML. HTM_047_SUG=La déclaration du 'viewport' doit déclarer à la fois la largeur (width) et la hauteur (height). HTM_048=Le 'viewBox' SVG est manquant sur le document de format 'fixed'. HTM_048_SUG=Une déclaration de 'viewBox' est requise pour les documents de format 'fixed'. HTM_049=L'élément 'html' n'a pas de 'xmlns' déterminé par 'http://www.w3.org/1999/xhtml'. HTM_049_SUG=Ajoutez xmlns="http://www.w3.org/1999/xhtml" pour l'élément 'html'. HTM_050=Un attribut epub:type="pagebreak" est présent dans le document de contenu. HTM_051=Enrichissements sémantiques trouvés en Microdata mais pas en RDFa. EDUPUB recommande l'utilisation de RDFa Lite. HTM_052=La propriété 'region-based' n'est autorisée que dans les éléments nav dans les Documents de Navigation de Données (Data Navigation Documents) #media MED_001=Le 'poster' de 'video' doit être un type d'image Core Media Type. MED_002=L'élément %1$s ne fournit pas de fallback. MED_003=Une ressource image non-standard de type '%1$s' a été trouvée. MED_004=L'en-tête du fichier image pourrait être corrompu. MED_005=La référence audio Media Overlay %1$s d'un type audio non-standard %2$s a été trouvée. MED_006=Certains navigateurs ne supportent pas les images rendues en SVG qui utilisent un nom de fichier dans la propriété xlink:href. #NAV EPUB v3 Table of contents NAV_001=Le fichier nav n'est pas supporté pour les EPUB v2. NAV_002=epub:type="page-list" a été trouvé dans le document nav. NAV_003=Le Document de Navigation doit avoir une page-list quand le(s) document(s) de contenu contienne(nt) des ruptures de page (epub:type="pagebreak"). NAV_004=Le Document de Navigation devrait contenir l'ensemble des titres et sous-titres hiérarchiques dans EDUPUB. NAV_005=Les Documents de Contenu contiennent des éléments 'audio' mais le Document de Navigation n'a pas une liste des clips audio (epub:type="loa"). NAV_006=Les Documents de Contenu contiennent des éléments 'figure' mais le Document de Navigation n'a pas une liste des figures (epub:type="loi"). NAV_007=Les Documents de Contenu contiennent des éléments 'table' mais le Document de Navigation n'a pas de liste des tableaux (epub:type="lot"). NAV_008=Les Documents de contenu contiennent des éléments 'video' mais le Document de Navigation n'a pas de liste des clips vidéo (epub:type="lov"). NAV_009=Les liens de navigation basés sur une région doivent pointer vers des Documents Fixed-Layout. #NCX EPUB v2 Table of Contents NCX_001=L'identifiant NCX ('%1$s') ne correspond pas à l'identifiant OPF ('%2$s'). NCX_002=L'attribut 'toc' est introuvable sur l'élément 'spine'. NCX_003=Un fichier .NCX est requis pour la navigation TOC au sein des lecteurs EPUB v2. NCX_004=L'identifiant NCX (métadonnée 'dtb:uid') ne devrait pas contenir des espaces de début ou de fin. NCX_005="page-list" a été trouvé dans le fichier .ncx. NCX_006=Label "text" vide dans le document NCX #OPF OPF_001=Une erreur a été constatée lors du traitement de la version EPUB : %1$s. OPF_002=Le fichier OPF '%1$s' est introuvable dans l'EPUB. OPF_003=L'item '%1$s' existe dans l'EPUB, mais n'est pas déclaré dans le manifest de l'OPF. OPF_004=Déclaration de préfixe incorrecte : les espaces avant ou après ne sont pas autorisés. OPF_004a=Déclaration de préfixe incorrecte : un préfixe vide a été trouvé. OPF_004b=Préfixe incorrect '%1$s' : il doit avoir un nom correct sans séparateur (alias 'NCName'). OPF_004c=Déclaration de préfixe incorrecte : le préfixe '%1$s' doit être immédiatement suivi par un caractère double point (':'). OPF_004d=Déclaration de préfixe incorrecte : '%1$s' doit être séparé par son URI avec un espace. OPF_004e=Déclaration de préfixe incorrecte : espace non-autorisé trouvé entre le préfixe et l'URI. OPF_004f=Déclaration de préfixe incorrecte : espace non-autorisé entre les mises en correspondance de préfixe. OPF_005=Déclaration de préfixe incorrecte : l'URI pour le préfixe '%1$s' n'existe pas. OPF_006=Déclaration de préfixe incorrecte : l'URI '%1$s' n'est pas une URI valide. OPF_007=Redéclaration du préfixe réservé '%1$s'. OPF_007a=Mise en correspondance de préfixe incorrecte : le préfixe '_' ne doit pas être déclaré. OPF_007b=Mise en correspondance de préfixe incorrecte : le vocabulaire par défaut ''%1$s'' ne doit pas être redéclaré. OPF_008=L'handler binding pour le Core Media Type '%1$s' n'est pas autorisé. OPF_009=Le media-type '%1$s' a déjà été attribué à un handler avec l'ID '%2$s'. OPF_010=Erreur de résolution de la référence : '%1$s'. OPF_011=itemref ne peut pas avoir à la fois une propriété 'page-spread-right' et 'page-spread-left'. OPF_012=La propriété d'item '%1$s' n'est pas définie pour le media-type '%2$s'. OPF_013=Le type de propriété '%1$s' sur l'élément object ne correspond pas au media-type '%2$s' déclaré dans le manifest de l'OPF. OPF_014=La propriété '%1$s' devrait être déclarée dans le fichier OPF. OPF_015=La propriété '%1$s' ne devrait pas être déclarée dans le fichier OPF. OPF_016=L'élément \"rootfile\" n'a pas son attribut obligatoire \"full-path\". OPF_017=L'attribut \"full-path\" sur l'élément \"rootfile\" ne doit pas être vide. OPF_018=La propriété 'remote-resources' a été déclaré dans l'OPF, mais aucune référence de ressource à distance n'a été trouvée. Assurez-vous que cette propriété est valable. OPF_019=L'élément 'spine' est introuvable dans le fichier OPF. OPF_020=Nombre excessif d'items du spine. OPF_021=Type de protocole URI non-autorisé trouvé dans 'href' : '%1$s'. OPF_025=La propriété '%1$s' ne peut prendre qu'une seule valeur. OPF_026=Valeur de la propriété malformée trouvée : '%1$s'. OPF_027=Propriété non-définie : '%1$s'. OPF_028=Préfixe non-déclaré : '%1$s'. OPF_029=Le fichier '%1$s' ne semble pas correspondre au media-type %2$s, comme spécifié dans le fichier OPF. OPF_030=Le 'unique-identifier' '%1$s' est introuvable. OPF_031=Le fichier déclaré dans l'élément 'reference' dans le guide n'a pas été déclaré dans le manifest de l'OPF : %1$s. OPF_032=Le guide référence '%1$s' qui n'est pas un 'OPS Content Document' valide. OPF_033=Le spine des ressources non linéaires. OPF_034=Le spine contient de multiples références à l'item du manifest avec l'id '%1$s'. OPF_035=Le media type 'text/html' ne convient pas pour XHTML/OPS. OPF_035_SUG=Utilisez 'application/xhtml+xml' à la place. OPF_036=le type de vidéo '%1$s' pourrait ne pas être supporté par les systèmes de lecture. OPF_036_SUG=Utilisez 'video/mp4', 'video/h264' ou 'video/webm' à la place. OPF_037=Media-type obsolète '%1$s' trouvé. OPF_038=Le media type '%1$s' ne convient pas pour un contexte OEBPS 1.2; utilisez 'text/x-oeb1-document' à la place. OPF_039=Le media type '%1$s' ne convient pas pour un contexte OEBPS 1.2; utilisez 'text/x-oeb1-css' à la place. OPF_040=l'item de repli (fallback) n'a pu être trouvé. OPF_041=L'item de repli de style (fallback-style) n'a pu être trouvé. OPF_042='%1$s' n'est pas un media-type du spine permis. OPF_043=L'item du spine avec un media-type '%1$s' non-standard n'a pas de repli (fallback). OPF_044=L'item du spine avec un media-type '%1$s' non-standard a un repli (fallback) pour un media-type non-standard. OPF_045=Référence bouclée rencontrée dans la chaîne de repli (fallback). OPF_046=La propriété scripted n'est pas définie sur le mediaType handler. OPF_047=Le fichier OPF utilise une syntaxe OEBPS 1.2 permettant la rétrocompatibilité. OPF_048=L'élément 'package' n'a pas son attribut unique-identifier obligatoire. OPF_049=L'id de l'élément '%1$s' est introuvable dans le manifest. OPF_050=L'attribut TOC désigne une ressource avec un mimetype non-NCX : ''application/x-dtbncx+xml'' est attendu. OPF_051=Les dimensions de l'image dépassent la taille recommandée. OPF_052=La valeur de 'role' '%1$s' n'est pas correcte. OPF_053=La valeur de la date ne suit pas la syntaxe recommandé selon http://www.w3.org/TR/NOTE-datetime : %2$s. OPF_054=La valeur de la date n'est pas correcte selon http://www.w3.org/TR/NOTE-datetime : %2$s. OPF_055=L'élément %1$s est vide. OPF_056=Le media type '%1$s' n'est pas un type audio principal. OPF_057=La longueur du fichier image dépasse la taille recommandée. OPF_058=L'élément du spine n'a pas de référence d'entrée de TOC. OPF_058_SUG=Chaque élément du spine dans le manifest devrait être référencé par au moins une entrée de TOC. OPF_059=L'item du spine n'a pas de référence d'entrée NCX. OPF_059_SUG=Chaque élément du spine dans le manifest devrait être référencé par au moins une entrée NCX. OPF_060=Double entrée dans le fichier ZIP : '%1$f'. OPF_061=Double entrée dans le fichier ZIP (après normalisation Unicode NFC) : '%1$f'. OPF_062=L'attribut Adobe 'page-map' a été trouvé sur l'élément spine dans le fichier OPF. OPF_063=L'élément '%1$s' référencé par Adobe 'page-map' est introuvable dans le manifest. OPF_064=Le type '%1$s' est déclaré dans l'OPF ; utilisation du profil de validation '%2$s'. OPF_065=Déclaration de métadonnées invalide, probablement due à un cycle de métadonnée 'raffinées' ('refines'). OPF_066=Metadonnée de pagination 'dc:source' ou 'source-of' manquante. La source de la pagination doit être identifiée avec les propriétés 'dc:source' et 'source-of' lorsque le contenu contient des marqueurs de sauts de page. OPF_067=La ressource '%1$s' ne doit pas être listée à la fois en tant qu'élément 'link' dans metadata et en tant qu'item du manifest. OPF_068=Rôle de la collection inconnu '%1$s'. OPF_069=L'URI du rôle de collection personnalisé '%1$s' ne doit pas inclure la chaîne de caractères 'idpf.org' dans son composant hôte. OPF_070=Le rôle de collection personnalisé '%1$s' est une URI invalide. OPF_071=Les collections Index ne doivent contenir que des ressources pointant sur des Documents de Contenu XHTML. OPF_072=L'élément de métadonnée '%1$s' est vide. OPF_073=Les identifiants externes ne doivent pas apparaître dans le doctype (document type declaration). OPF_074=La ressource du package '%1$s' est déclarée dans plusieurs item du manifest. OPF_075=Les collections Preview ne doivent pointer que sur des Documents de Contenu EPUB. OPF_076=L'URI des éléments 'link' d'une collection d'aperçu 'preview' ne doit pas contenir d'identificateur de fragment canonique (EPUB CFI). OPF_077=Un Document de Navigation de Données ne devrait pas être inclus dans le spine. OPF_078=Un Dictionnaire EPUB doit contenir au moins un Document de Contenu avec un contenu dictionnaire (epub:type 'dictionary'). OPF_079=Un contenu dictionnaire a été trouvé (epub:type 'dictionary'), le Document de Package devrait déclarer le dc:type 'dictionary'. OPF_080=Le nom de fichier d'un document d'index de clés de recherche (Search Key Map) devrait avoir l'extension '.xml'. OPF_081=La ressource '%1$s' (référencée à partir d'une collection EPUB Dictionnaire) est introuvable. OPF_082=Une collection de dictionnaire EPUB contenant plus d'un index de clés de recherche (Search Key Map) a été trouvée. OPF_083=Une collection de dictionnaire EPUB ne contenant pas d'index de clés de recherche (Search Key Map) a été trouvée. OPF_084=La ressource '%1$s' a été trouvée dans une collection de dictionnaire EPUB mais n'est ni un index de clés de recherche (Search Key Map) ni un document de contenu XHTML. #Package PKG_001=Validation de l'EPUB selon la version %1$s mais version %2$s détectée. PKG_003=Impossible de lire l'en-tête du fichier EPUB. C'est probablement un fichier EPUB corrompu. PKG_004=En-tête EPUB ZIP corrompu. PKG_005=Le fichier mimetype a une extension de longueur %1$s. Aucune extension de nom de fichier n'est autorisée pour le fichier mimetype. PKG_006=Le fichier mimetype est manquante ou n'est pas le premier fichier de l'archive. PKG_007=Le fichier mimetype ne devrait contenir que la chaîne de caractères 'application/epub+zip'. PKG_008=Impossible de lire le fichier '%1$s'. PKG_009=Le nom de fichier contient des caractères qui ne sont pas autorisés dans les noms de fichier OCF : '%1$s'. PKG_010=Le nom de fichier contient des espaces, par conséquent l'échappement de l'URI est nécessaire. Envisagez de supprimer les espaces des noms de fichier. PKG_011=Le nom de fichier ne peut pas se terminer par '.'. PKG_012=Le nom de fichier contient les caractères non-ascii suivants : %1$s. Envisagez de changer le nom de fichier. PKG_013=Le fichier EPUB inclut plusieurs représentations OPS (OPS renditions). PKG_014=L'EPUB contient le répertoire vide '%1$s'. PKG_015=Impossible de lire les contenus EPUB : %1$s. PKG_016=Utilisez seulement des caractères minuscules pour l'extension du fichier EPUB pour une compatibilité maximale. PKG_016_SUG=Pour une compatibilité maximale, utilisez '.epub'. PKG_017=Extension du fichier EPUB inhabituelle. PKG_017_SUG=Pour une compatibilité maximale, utilisez '.epub'. PKG_018=Le fichier EPUB est introuvable. PKG_020=Le fichier OPF '%1$s' est introuvable. PKG_021=Fichier image corrompu rencontré. PKG_022=Extension de fichier incorrecte pour une image. L'image est un fichier '%1$s' mais a l'extension de fichier '%2$s'. PKG_023=Validation de l'EPUB selon la version 2.0, le profil de validation par défaut sera utilisé. #Resources RSC_001=Le fichier '%1$s' est introuvable. RSC_002=La ressource obligatoire META-INF/container.xml est introuvable. RSC_003=Aucun élément 'rootfile' avec le media type 'application/oebps-package+xml' n'est présent dans le container. RSC_004=Le fichier '%1$s' ne peut pas être décrypté. RSC_005=Erreur lors de l'analyse du fichier '%1$s'. RSC_006=Référence à une ressource externe non-autorisée ; La ressource doit être placée dans l'OCF. RSC_006_SUG=Seules les ressources externes audio et vidéo sont autorisées. RSC_007=La ressource référencée n'est pas présente dans l'EPUB. RSC_007w=La ressource référencée n'est pas présente dans l'EPUB. RSC_008=La ressource référencée n'est pas déclarée dans le manifest de l'OPF. RSC_009=Un identificateur de fragment ne devrait pas être utilisé avec un attribut 'src' de 'img'. RSC_010=Référence à une ressource non-standard présente. RSC_011=Une référence à une ressource qui n'est pas un élément du spine a été trouvée. RSC_012=L'identificateur de fragment n'est pas défini. RSC_013=L'identificateur de fragment est utilisé en référence à une feuille de style. RSC_014=L'identificateur de fragment définit un type de ressource incompatible. RSC_015=Un identificateur de fragment est obligatoire pour les références aux éléments utilisés dans svg. RSC_016=Erreur Fatale lors de l'analyse du fichier '%1$s'. RSC_017=Avertissement lors de l'analyse du fichier '%1$s'. RSC_018=Le fichier image alternatif '%1$s' est introuvable. RSC_019=Les EPUB avec de Multiple Représentations (Multiple Renditions) devrait contenir un fichier META-INF/metadata.xml. RSC_020='%1$s' n'est pas une URI valide RSC_021=Un index de clés de recherche (Search Key Map) doit référencer des documents de contenus uniquement ('%1$s' n'a pas été trouvé dans le bloc "spine"). RSC_022=Impossible de contrôler les détails de l'image (nécessite Java version 7 ou plus). #Scripting SCP_001=L'utilisation de la fonction JavaScript eval() dans les scripts EPUB présente un risque de sécurité. SCP_002=L'utilisation de XMLHttpRequest dans les scripts EPUB présente un risque de sécurité. SCP_003=Local et Session Storage ne sont actuellement pas supportés. SCP_004=Le fichier de contenu contient un script ce qui n'est pas supporté dans EPUB v2. SCP_005=Le fichier contient un script mais il n'est pas marqué comme 'scripted'. SCP_006=Scripts en ligne (inline scripts) présents. SCP_007=Le script référence 'innerHtml'. SCP_007_SUG=Utilisez un DOM à la place. SCP_008=Le script référence 'innerText'. SCP_008_SUG=Utilisez 'textContent' à la place. SCP_009=Le fichier de contenu utilise des handlers d'événement souris. SCP_009_SUG=Assurez-vous que toute fonctionnalité avec la souris sont accessibles à partir de clavier et d'appareils tactiles. SCP_010=Le fichier de contenu ePub 3 contient du script. epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/0000755000175000017500000000000013017276730023524 5ustar eugeneeugeneepubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/0000755000175000017500000000000013017276730023746 5ustar eugeneeugeneepubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/package-30.nvdl0000644000175000017500000000102313017276730026442 0ustar eugeneeugene epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/package-30.rnc0000644000175000017500000001531613017276730026273 0ustar eugeneeugene default namespace = "http://www.idpf.org/2007/opf" namespace opf = "http://www.idpf.org/2007/opf" namespace dc = "http://purl.org/dc/elements/1.1/" include "./mod/datatypes.rnc" include "./mod/epub-prefix-attr.rnc" start = element package { opf.package.attlist & opf.package.content } opf.package.attlist &= opf.version.attr & opf.unique.identifier.attr & opf.id.attr? & epub.prefix.attr? & opf.i18n.attrs opf.version.attr = attribute version { '3.0' } opf.unique.identifier.attr = attribute unique-identifier { datatype.IDREF } opf.package.content = opf.metadata, opf.manifest, opf.spine, opf.guide?, opf.bindings?, opf.collection* opf.metadata = element metadata { opf.id.attr? & opf.i18n.attrs & opf.metadata.content } opf.metadata.content = opf.dc.elems & opf.meta* & opf.link* opf.meta = element meta { opf.epub3.meta.content | opf.epub2.meta.content } opf.epub3.meta.content = (opf.property.attr & opf.refines.attr? & opf.id.attr? & opf.scheme.attr? & opf.i18n.attrs & datatype.string.nonempty) opf.epub2.meta.content = (attribute name { text } & attribute content { text }) #legacy opf.link = element link { opf.href.attr & opf.rel.attr & opf.id.attr? & opf.refines.attr? & opf.media-type.attr? } opf.property.attr = attribute property { datatype.property } opf.rel.attr = attribute rel { datatype.properties } opf.scheme.attr = attribute scheme { datatype.property } opf.refines.attr = attribute refines { datatype.URI } opf.dc.identifier = element dc:identifier { opf.id.attr? & datatype.string.nonempty } opf.dc.title = element dc:title { opf.dc.attlist & datatype.string.nonempty } opf.dc.language = element dc:language { opf.id.attr? & datatype.languagecode } opf.dc.date = element dc:date { opf.id.attr? & datatype.string.nonempty } opf.dc.source = element dc:source { opf.dc.attlist & datatype.string.nonempty } opf.dc.type = element dc:type { opf.id.attr? & datatype.string.nonempty } opf.dc.format = element dc:format { opf.id.attr? & datatype.string.nonempty } opf.dc.creator = element dc:creator { opf.dc.attlist & datatype.string.nonempty } opf.dc.subject = element dc:subject { opf.dc.attlist & datatype.string.nonempty } opf.dc.description = element dc:description { opf.dc.attlist & datatype.string.nonempty } opf.dc.publisher = element dc:publisher { opf.dc.attlist & datatype.string.nonempty } opf.dc.contributor = element dc:contributor { opf.dc.attlist & datatype.string.nonempty } opf.dc.relation = element dc:relation { opf.dc.attlist & datatype.string.nonempty } opf.dc.coverage = element dc:coverage { opf.dc.attlist & datatype.string.nonempty } opf.dc.rights = element dc:rights { opf.dc.attlist & datatype.string.nonempty } opf.dc.elems = opf.dc.identifier+ & opf.dc.title+ & opf.dc.language+ & opf.dc.date? & opf.dc.source* & opf.dc.type* & opf.dc.format* & opf.dc.creator* & opf.dc.subject* & opf.dc.description* & opf.dc.publisher* & opf.dc.contributor* & opf.dc.relation* & opf.dc.coverage* & opf.dc.rights* opf.dc.attlist = opf.id.attr? & opf.i18n.attrs opf.manifest = element manifest { opf.manifest.attlist & opf.manifest.content } opf.manifest.attlist &= opf.id.attr? opf.manifest.content = opf.item+ opf.item = element item { opf.item.attlist } opf.item.attlist &= opf.id.attr & opf.href.attr & opf.media-type.attr & opf.fallback.attr? & opf.media-overlay.attr? & opf.properties.attr? opf.fallback.attr = attribute fallback { datatype.IDREF } opf.media-overlay.attr = attribute media-overlay { datatype.IDREF } opf.properties.attr = attribute properties { datatype.properties } opf.spine = element spine { opf.spine.attlist & opf.spine.content } opf.spine.attlist &= opf.id.attr? & opf.spine.toc.attr? & opf.ppd.attr? opf.spine.toc.attr = attribute toc { datatype.IDREF } opf.ppd.attr = attribute page-progression-direction { 'ltr' | 'rtl' | 'default'} opf.spine.content = opf.itemref+ opf.itemref = element itemref { opf.itemref.attlist } opf.itemref.attlist &= opf.itemref.idref.attr & opf.itemref.linear.attr? & opf.id.attr? & opf.properties.attr? opf.itemref.idref.attr = attribute idref { datatype.IDREF } opf.itemref.linear.attr = attribute linear { 'yes' | 'no' } opf.guide = element guide { opf.reference+ } opf.reference = element reference { opf.href.attr & attribute type { datatype.text } & attribute title { datatype.text }?} opf.bindings = element bindings { opf.bindings.mediaType+ } opf.bindings.mediaType = element mediaType { opf.bindings.mediaType.attlist } opf.bindings.mediaType.attlist &= opf.media-type.attr & attribute handler { datatype.IDREF } opf.collection = element collection { opf.collection.attlist, opf.collection.content } opf.collection.attlist &= opf.id.attr? & opf.dir.attr? & opf.xml.lang.attr? & opf.collection.role.attr opf.collection.role.attr = attribute role { datatype.space.separated.tokens } opf.collection.content = opf.collection.metadata?, (opf.collection+ | (opf.collection*, opf.collection.link+)) opf.collection.metadata = element metadata { opf.id.attr? & opf.i18n.attrs & opf.collection.metadata.content } opf.collection.metadata.content = opf.collection.dc.elems & opf.collection.meta* & opf.link* opf.collection.dc.elems = opf.dc.identifier* & opf.dc.title* & opf.dc.language* & opf.dc.date* & opf.dc.source* & opf.dc.type* & opf.dc.format* & opf.dc.creator* & opf.dc.subject* & opf.dc.description* & opf.dc.publisher* & opf.dc.contributor* & opf.dc.relation* & opf.dc.coverage* & opf.dc.rights* opf.collection.meta = element meta { opf.epub3.meta.content } opf.collection.link = element link { opf.href.attr & opf.rel.attr? & opf.id.attr? & opf.media-type.attr? } opf.media-type.attr = attribute media-type { datatype.mimetype } opf.href.attr = attribute href { datatype.URI } opf.id.attr = attribute id { datatype.ID } opf.i18n.attrs = opf.xml.lang.attr? & opf.dir.attr? opf.xml.lang.attr = attribute xml:lang { datatype.languagecode } opf.dir.attr = attribute dir { 'ltr' | 'rtl' }epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/epub-xhtml-30.sch0000644000175000017500000004324613017276730026763 0ustar eugeneeugene The meta element in encoding declaration state (http-equiv='content-type') must have the value 'text/html; charset=utf-8' A document must not contain both a meta element in encoding declaration state (http-equiv='content-type') and a meta element with the charset attribute present. WARNING: the 'aria-describedat' attribute is deprecated. The aria-activedescendant attribute must refer to a descendant element. The for attribute does not refer to an allowed target element (expecting: button|keygen|meter|output|progress|select|textarea|input[not(@type='hidden')]). The headers attribute must refer to th elements in the same table. Duplicate map name '' The id attribute on the map element must have the same value as the name attribute. The lang and xml:lang attributes must have the same value. Duplicate ID '' A select element whose multiple attribute is not specified must not have more than one descendant option element with its selected attribute set. The track element label attribute value must not be the empty string. There must not be more than one track child of a media element element with the default attribute specified. The ssml:ph attribute must not be specified on a descendant of an element that also carries this attribute. The scoped style element must occur before any other flow content other than other style elements and inter-element whitespace. The sizes attribute must not be specified on link elements that do not have a rel attribute that specifies the icon keyword. There must not be more than one meta element with a charset attribute per document. For each article element, there must be no more than one time element child with a pubdate attribute For each Document, there must be no more than one time element with a pubdate attribute that does not have an ancestor article element. If the itemprop is specified on an a element, then the href attribute must also be specified. If the itemprop is specified on an iframe, embed or object element, then the data attribute must also be specified. If the itemprop is specified on an video or audio element, then the src attribute must also be specified. The attribute must refer to an element in the same document (the ID '' does not exist). The attribute must refer to elements in the same document (target ID missing) The attribute does not refer to an allowed target element (expecting: ). The element must have a attribute. The element must not appear inside elements. The element must have an ancestor element. The element must not appear inside elements. epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/dict/0000755000175000017500000000000013017276730024671 5ustar eugeneeugeneepubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/dict/dict-collection.sch0000644000175000017500000000256613017276730030455 0ustar eugeneeugene An EPUB Dictionary collection must not have sub-collections. An EPUB Dictionary must declare its source language using a 'source-language' metadata. An EPUB Dictionary must declare its source language using a 'target-language' metadata. An EPUB Dictionary must not declare more than one source language. epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/dict/dict-xhtml.sch0000644000175000017500000000766013017276730027456 0ustar eugeneeugene The 'dictionary' type is only allowed on 'body' or 'section' elements. A 'dictionary' must have at least one article child. The 'dictentry' type is only allowed on 'article' elements. A dictionary entry must have at least one 'dfn' descendant (outside of the optional condensed entry 'aside'). The 'condensed-entry' type is only allowed on 'aside' elements. The 'condensed-entry' type is only allowed on a child element of an 'article' dictionary entry. A 'condensed-entry' must have a 'hidden' attribute with its value set to 'hidden' or the empty string. The 'part-of-speech-list' type is only allowed on 'ol' elements. A 'part-of-speech-group' must contain an element of type 'part-of-speech'. The 'sense-list' type is only allowed on 'ol' elements. An element of type 'tran-info' must have a sibling element of type 'tran'. The 'idiom' type is only allowed on 'dfn' elements. The 'phrase-list' type is only allowed on 'ol' or 'ul' elements. A 'phrase-group' must contain an element of type 'idiom' or 'example'. epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/dict/dict-opf.sch0000644000175000017500000000617013017276730027101 0ustar eugeneeugene The dc:type identifier 'dictionary' is required. An EPUB Publication consisting of a single EPUB Dictionary must contain exactly one Search Key Map document for this dictionary (i.e. exactly one item with properties 'search-key-map' and 'dictionary'). An EPUB Dictionary must declare its source language using a 'source-language' metadata. An EPUB Dictionary must declare its source language using a 'target-language' metadata. An EPUB Dictionary must not declare more than one source language. Search Key Map Document '' is referenced in more than one dictionary collection. EPUB Dictionaries 'source-language' and 'target-language' must also be declared as 'dc:language' in package-level metadata. EPUB Dictionaries 'dictionary-type' metadata must be one of 'monolingual', 'bilingual', 'multilingual', 'thesaurus', 'encyclopedia', 'spelling', 'pronouncing', or 'etymological'. epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/dict/search-key-map.rnc0000644000175000017500000000223213017276730030202 0ustar eugeneeugenedefault namespace = "http://www.idpf.org/2007/ops" start = element search-key-map {skm.search-key-map.attlist & skm.search-key-map.content } skm.search-key-map.attlist &= skm.xml-lang.attr & skm.id.attr? & skm.dir.attr? skm.search-key-map.content = skm.search-key-group+ skm.search-key-group = element search-key-group {skm.search-key-group.attlist & skm.search-key-group.content} skm.search-key-group.attlist &= skm.href.attr & skm.id.attr? skm.search-key-group.content = skm.match+ skm.match = element match {skm.match.attlist & skm.match.content} skm.match.attlist &= skm.href.attr? & skm.value.attr? & skm.title.attr? & skm.phonogram.attr? & skm.id.attr? & skm.xml-lang.attr? skm.match.content = skm.value* skm.value = element value {skm.value.attlist} skm.value.attlist &= skm.value.attr # Attributes skm.dir.attr = attribute dir {"ltr"|"rtl"} skm.id.attr = attribute id {xsd:ID} skm.href.attr = attribute href { xsd:anyURI } skm.phonogram.attr = attribute phonogram { text } skm.title.attr = attribute title { text } skm.value.attr = attribute value { text } skm.xml-lang.attr = attribute xml:lang { xsd:language { pattern = "[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*" } }epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/epub-svg-30.sch0000644000175000017500000000042013017276730026411 0ustar eugeneeugene epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/epub-svg-30.rnc0000644000175000017500000000075613017276730026432 0ustar eugeneeugene namespace x = "http://www.w3.org/1999/xhtml" include "./mod/html5/html5-grouping-30.rnc" inherit = x include "./mod/html5/html5-phrasing-30.rnc" inherit = x include "./mod/html5/html5-sections-30.rnc" inherit = x include "./mod/html5/html5-style-30.rnc" inherit = x include "./mod/epub-ssml-attrs.rnc" include "./mod/html5/html5-attrib-30.rnc" include "./mod/datatypes.rnc" include "./mod/html5/html5-models-30.rnc" start = external "mod/epub-svg11-30.rnc" epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/epub-nav-30.rnc0000644000175000017500000000047213017276730026412 0ustar eugeneeugene default namespace = "http://www.w3.org/1999/xhtml" namespace epub = "http://www.idpf.org/2007/ops" include "epub-xhtml-30.rnc" { html5.nav.content = html5.headings.class?, html5.ol html5.oli.content = html5.a.phrasing | ((html5.a.phrasing | html5.span), html5.ol) } epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/epub-nav-30.nvdl0000644000175000017500000000105213017276730026566 0ustar eugeneeugene epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/collection-manifest-30.sch0000644000175000017500000000134213017276730030624 0ustar eugeneeugene A manifest collection must only contain child link elements. A manifest collection must include at least one child link element. A manifest collection must be the child of another collection. epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/previews/0000755000175000017500000000000013017276730025612 5ustar eugeneeugeneepubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/previews/preview-collection.sch0000644000175000017500000000126413017276730032126 0ustar eugeneeugene A 'preview' collection must include exactly one child 'manifest' collection A 'preview' collection must include at least one child link element, pointing to an EPUB Content Document. epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/previews/preview-pub-opf.sch0000644000175000017500000000202713017276730031341 0ustar eugeneeugene An EPUB Preview publication must have a 'preview' dc:type. WARNING: An EPUB Preview publication should link back to its source Publication using a dc:source element. A Preview Publication must not use the same package identifier as its source Publication. epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/collection-do-30.sch0000644000175000017500000000250013017276730027415 0ustar eugeneeugene A distributable-object collection must include a child metadata element. A distributable-object collection must not contain more than one child manifest collection. A distributable-object collection must include at least one child link element. The distributable-object metadata must include exactly one identifier (dc:identifier). The distributable-object metadata must include at least one title (dc:title). The distributable-object metadata must include at least one language declaration (dc:language). epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/ocf-container-30.nvdl0000644000175000017500000000077713017276730027615 0ustar eugeneeugene epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/datanav/0000755000175000017500000000000013017276730025364 5ustar eugeneeugeneepubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/datanav/datanav-xhtml.sch0000644000175000017500000000356613017276730030645 0ustar eugeneeugene A 'nav' element in a Data Navigation Document must have an 'epub:type' attribute (to identify the nature of the navigation component it contains). A region-based nav element must contain exactly one child ol element. The first child of a region-based nav list item must be either an 'a' or 'span' element. The first child of a region-based nav list item can only be followed by a single 'ol' element. WARNING: 'a' elements in region-based navs should not contain text labels. 'span'elements in region-base navs must contain exactly two 'a' elements. epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/idx/0000755000175000017500000000000013017276730024532 5ustar eugeneeugeneepubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/idx/idx-xhtml-index.sch0000644000175000017500000000171613017276730030261 0ustar eugeneeugene At least one 'index' element must be present in a document declared as an index in the OPF. The document containins only index content, its 'body' element must have the epub:type 'index' epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/idx/idx-collection.sch0000644000175000017500000000160113017276730030144 0ustar eugeneeugene An 'index' collection must not have sub-collections other than 'index-group' collections. An 'index-group' collection must be a child of an 'index' collection. An 'index-group' collection must not have child collections. epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/idx/idx-xhtml.sch0000644000175000017500000003154113017276730027153 0ustar eugeneeugene The 'index' type is only allowed on 'body' or sectioning elements. At most one heading element child must be present. At most one 'index-headnotes' child must be present. An 'index' must contain one and only one 'index-entry-list' (possibly implied) OR one or more 'index-group's. The 'index-headnotes' type is only allowed on 'header' or sectioning elements. The 'index-headnotes' type is only allowed as a child of 'index'. The 'index-legend' type is only allowed on 'dl' or sectioning elements. The 'index-legend' type is only allowed as a child of 'index-headnotes'. The 'index-group' type is only allowed on sectioning elements. The 'index-group' type is only allowed on children of 'index'. 'index-group' must not have more than one heading child. 'index-group' must have exactly one 'index-entry-list' child. The 'index-entry-list' type is only allowed on 'ul' elements. The 'index-entry-list' type is only allowed on children of 'index', 'index-group' or 'index-entry'. At least one 'index-entry' child. The 'index-entry' type is only allowed on 'li' elements. The 'index-entry' type is only allowed on children of (possibly-implied) 'index-entry-list'. An 'index-entry' must have one and only one 'index-term' child. An 'index-entry' must have at least one child with the type 'index-entry-list' or 'index-locator-list' or 'index-locator', 'index-locator-range' or 'index-editor-note' or 'index-xref-preferred' or 'index-xref-related'. An 'index-entry' must have at most one child with the (possibly implied) type 'index-entry-list'. An 'index-entry' must not have both 'index-locator-list' and 'index-locator' or 'index-locator-range' children. An 'index-entry' must have at most one child with the type 'index-locator-list'. An 'index-entry' must have at most one child with the type 'index-editor-note'. An 'index-entry' must not have both 'index-xref-preferred' and 'index-xref-related' children. The '' type is only allowed on children of elements with the (possibly implied) type 'index-entry'. The 'index-term' type is only allowed on phrasing content elements. The 'index-term' type is only allowed on children of elements with the type 'index-entry' (possibly implied), 'index-xref-preferred' or 'index-xref-related'. The 'index-locator-list' type is only allowed on 'ul' elements. An 'index-entry-list' must have at least one descendant with the (possibly implied) 'index-locator' type. The 'index-locator' type is only allowed on 'a' elements. The 'index-locator' type is only allowed on children of elements with the (possibly implied) type 'index-entry' or descendants of 'index-locator-list' or 'index-range'. The 'index-locator-range' type is only allowed on children of elements with the (possibly implied) type 'index-entry' or descendants of 'index-locator-list'. Must contain one or two 'index-locator' child. An 'index-xref-preferred' or 'index-xref-related' must have at least one child with the type 'index-term' or 'index-term-category'. The 'index-term-category' type is only allowed on 'a' elements. The 'index-term-category' type is only allowed on elements (or descendants of elements) with the type 'index-xref-preferred' or 'index-xref-related'. epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/0000755000175000017500000000000013017276730024525 5ustar eugeneeugeneepubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/epub-svg11-re.sch0000644000175000017500000000053713017276730027527 0ustar eugeneeugene Invalid value (expecting: 'http://www.idpf.org/2007/ops') epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/epub-prefix-attr.rnc0000644000175000017500000000037213017276730030431 0ustar eugeneeugene namespace epub = "http://www.idpf.org/2007/ops" html5.html.attlist &= epub.prefix.attr.ns? epub.prefix.attr = attribute prefix { datatype.prefixdecl } epub.prefix.attr.ns = attribute epub:prefix { datatype.prefixdecl }epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/id-unique.sch0000644000175000017500000000072113017276730027124 0ustar eugeneeugene Duplicate '' epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/mathml/0000755000175000017500000000000013017276730026007 5ustar eugeneeugeneepubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/mathml/mathml3-presentation.rnc0000644000175000017500000004601013017276730032572 0ustar eugeneeugene # This is the Mathematical Markup Language (MathML) 3.0, an XML # application for describing mathematical notation and capturing # both its structure and content. # # Copyright 1998-2014 W3C (MIT, ERCIM, Keio, Beihang) # # Use and distribution of this code are permitted under the terms # W3C Software Notice and License # http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231 default namespace m = "http://www.w3.org/1998/Math/MathML" MathExpression |= PresentationExpression ImpliedMrow = MathExpression* TableRowExpression = mtr|mlabeledtr TableCellExpression = mtd MstackExpression = MathExpression|mscarries|msline|msrow|msgroup MsrowExpression = MathExpression|none MultiScriptExpression = (MathExpression|none),(MathExpression|none) mpadded-length = xsd:string { pattern = '\s*([\+\-]?[0-9]*([0-9]\.?|\.[0-9])[0-9]*\s*((%?\s*(height|depth|width)?)|e[mx]|in|cm|mm|p[xtc]|((negative)?((very){0,2}thi(n|ck)|medium)mathspace))?)\s*' } linestyle = "none" | "solid" | "dashed" verticalalign = "top" | "bottom" | "center" | "baseline" | "axis" columnalignstyle = "left" | "center" | "right" notationstyle = "longdiv" | "actuarial" | "radical" | "box" | "roundedbox" | "circle" | "left" | "right" | "top" | "bottom" | "updiagonalstrike" | "downdiagonalstrike" | "verticalstrike" | "horizontalstrike" | "madruwb" idref = text unsigned-integer = xsd:unsignedLong integer = xsd:integer number = xsd:decimal character = xsd:string { pattern = '\s*\S\s*'} color = xsd:string { pattern = '\s*((#[0-9a-fA-F]{3}([0-9a-fA-F]{3})?)|[aA][qQ][uU][aA]|[bB][lL][aA][cC][kK]|[bB][lL][uU][eE]|[fF][uU][cC][hH][sS][iI][aA]|[gG][rR][aA][yY]|[gG][rR][eE][eE][nN]|[lL][iI][mM][eE]|[mM][aA][rR][oO][oO][nN]|[nN][aA][vV][yY]|[oO][lL][iI][vV][eE]|[pP][uU][rR][pP][lL][eE]|[rR][eE][dD]|[sS][iI][lL][vV][eE][rR]|[tT][eE][aA][lL]|[wW][hH][iI][tT][eE]|[yY][eE][lL][lL][oO][wW])\s*'} group-alignment = "left" | "center" | "right" | "decimalpoint" group-alignment-list = list {group-alignment+} group-alignment-list-list = xsd:string { pattern = '(\s*\{\s*(left|center|right|decimalpoint)(\s+(left|center|right|decimalpoint))*\})*\s*' } positive-integer = xsd:positiveInteger TokenExpression = mi|mn|mo|mtext|mspace|ms token.content = mglyph|malignmark|text mi = element mi {mi.attributes, token.content*} mi.attributes = CommonAtt, CommonPresAtt, TokenAtt mn = element mn {mn.attributes, token.content*} mn.attributes = CommonAtt, CommonPresAtt, TokenAtt mo = element mo {mo.attributes, token.content*} mo.attributes = CommonAtt, CommonPresAtt, TokenAtt, attribute form {"prefix" | "infix" | "postfix"}?, attribute fence {"true" | "false"}?, attribute separator {"true" | "false"}?, attribute lspace {length}?, attribute rspace {length}?, attribute stretchy {"true" | "false"}?, attribute symmetric {"true" | "false"}?, attribute maxsize {length | "infinity"}?, attribute minsize {length}?, attribute largeop {"true" | "false"}?, attribute movablelimits {"true" | "false"}?, attribute accent {"true" | "false"}?, attribute linebreak {"auto" | "newline" | "nobreak" | "goodbreak" | "badbreak"}?, attribute lineleading {length}?, attribute linebreakstyle {"before" | "after" | "duplicate" | "infixlinebreakstyle"}?, attribute linebreakmultchar {text}?, attribute indentalign {"left" | "center" | "right" | "auto" | "id"}?, attribute indentshift {length}?, attribute indenttarget {idref}?, attribute indentalignfirst {"left" | "center" | "right" | "auto" | "id" | "indentalign"}?, attribute indentshiftfirst {length | "indentshift"}?, attribute indentalignlast {"left" | "center" | "right" | "auto" | "id" | "indentalign"}?, attribute indentshiftlast {length | "indentshift"}? mtext = element mtext {mtext.attributes, token.content*} mtext.attributes = CommonAtt, CommonPresAtt, TokenAtt mspace = element mspace {mspace.attributes, empty} mspace.attributes = CommonAtt, CommonPresAtt, TokenAtt, attribute width {length}?, attribute height {length}?, attribute depth {length}?, attribute linebreak {"auto" | "newline" | "nobreak" | "goodbreak" | "badbreak" | "indentingnewline"}?, attribute indentalign {"left" | "center" | "right" | "auto" | "id"}?, attribute indentshift {length}?, attribute indenttarget {idref}?, attribute indentalignfirst {"left" | "center" | "right" | "auto" | "id" | "indentalign"}?, attribute indentshiftfirst {length | "indentshift"}?, attribute indentalignlast {"left" | "center" | "right" | "auto" | "id" | "indentalign"}?, attribute indentshiftlast {length | "indentshift"}? ms = element ms {ms.attributes, token.content*} ms.attributes = CommonAtt, CommonPresAtt, TokenAtt, attribute lquote {text}?, attribute rquote {text}? mglyph = element mglyph {mglyph.attributes,mglyph.deprecatedattributes,empty} mglyph.attributes = CommonAtt, CommonPresAtt, attribute src {xsd:anyURI}?, attribute width {length}?, attribute height {length}?, attribute valign {length}?, attribute alt {text}? mglyph.deprecatedattributes = attribute index {integer}?, attribute mathvariant {"normal" | "bold" | "italic" | "bold-italic" | "double-struck" | "bold-fraktur" | "script" | "bold-script" | "fraktur" | "sans-serif" | "bold-sans-serif" | "sans-serif-italic" | "sans-serif-bold-italic" | "monospace" | "initial" | "tailed" | "looped" | "stretched"}?, attribute mathsize {"small" | "normal" | "big" | length}?, DeprecatedTokenAtt msline = element msline {msline.attributes,empty} msline.attributes = CommonAtt, CommonPresAtt, attribute position {integer}?, attribute length {unsigned-integer}?, attribute leftoverhang {length}?, attribute rightoverhang {length}?, attribute mslinethickness {length | "thin" | "medium" | "thick"}? none = element none {none.attributes,empty} none.attributes = CommonAtt, CommonPresAtt mprescripts = element mprescripts {mprescripts.attributes,empty} mprescripts.attributes = CommonAtt, CommonPresAtt CommonPresAtt = attribute mathcolor {color}?, attribute mathbackground {color | "transparent"}? TokenAtt = attribute mathvariant {"normal" | "bold" | "italic" | "bold-italic" | "double-struck" | "bold-fraktur" | "script" | "bold-script" | "fraktur" | "sans-serif" | "bold-sans-serif" | "sans-serif-italic" | "sans-serif-bold-italic" | "monospace" | "initial" | "tailed" | "looped" | "stretched"}?, attribute mathsize {"small" | "normal" | "big" | length}?, attribute dir {"ltr" | "rtl"}?, DeprecatedTokenAtt DeprecatedTokenAtt = attribute fontfamily {text}?, attribute fontweight {"normal" | "bold"}?, attribute fontstyle {"normal" | "italic"}?, attribute fontsize {length}?, attribute color {color}?, attribute background {color | "transparent"}? MalignExpression = maligngroup|malignmark malignmark = element malignmark {malignmark.attributes, empty} malignmark.attributes = CommonAtt, CommonPresAtt, attribute edge {"left" | "right"}? maligngroup = element maligngroup {maligngroup.attributes, empty} maligngroup.attributes = CommonAtt, CommonPresAtt, attribute groupalign {"left" | "center" | "right" | "decimalpoint"}? PresentationExpression = TokenExpression|MalignExpression| mrow|mfrac|msqrt|mroot|mstyle|merror|mpadded|mphantom| mfenced|menclose|msub|msup|msubsup|munder|mover|munderover| mmultiscripts|mtable|mstack|mlongdiv|maction mrow = element mrow {mrow.attributes, MathExpression*} mrow.attributes = CommonAtt, CommonPresAtt, attribute dir {"ltr" | "rtl"}? mfrac = element mfrac {mfrac.attributes, MathExpression, MathExpression} mfrac.attributes = CommonAtt, CommonPresAtt, attribute linethickness {length | "thin" | "medium" | "thick"}?, attribute numalign {"left" | "center" | "right"}?, attribute denomalign {"left" | "center" | "right"}?, attribute bevelled {"true" | "false"}? msqrt = element msqrt {msqrt.attributes, ImpliedMrow} msqrt.attributes = CommonAtt, CommonPresAtt mroot = element mroot {mroot.attributes, MathExpression, MathExpression} mroot.attributes = CommonAtt, CommonPresAtt mstyle = element mstyle {mstyle.attributes, ImpliedMrow} mstyle.attributes = CommonAtt, CommonPresAtt, mstyle.specificattributes, mstyle.generalattributes, mstyle.deprecatedattributes mstyle.specificattributes = attribute scriptlevel {integer}?, attribute displaystyle {"true" | "false"}?, attribute scriptsizemultiplier {number}?, attribute scriptminsize {length}?, attribute infixlinebreakstyle {"before" | "after" | "duplicate"}?, attribute decimalpoint {character}? mstyle.generalattributes = attribute accent {"true" | "false"}?, attribute accentunder {"true" | "false"}?, attribute align {"left" | "right" | "center"}?, attribute alignmentscope {list {("true" | "false") +}}?, attribute bevelled {"true" | "false"}?, attribute charalign {"left" | "center" | "right"}?, attribute charspacing {length | "loose" | "medium" | "tight"}?, attribute close {text}?, attribute columnalign {list {columnalignstyle+} }?, attribute columnlines {list {linestyle +}}?, attribute columnspacing {list {(length) +}}?, attribute columnspan {positive-integer}?, attribute columnwidth {list {("auto" | length | "fit") +}}?, attribute crossout {list {("none" | "updiagonalstrike" | "downdiagonalstrike" | "verticalstrike" | "horizontalstrike")*}}?, attribute denomalign {"left" | "center" | "right"}?, attribute depth {length}?, attribute dir {"ltr" | "rtl"}?, attribute edge {"left" | "right"}?, attribute equalcolumns {"true" | "false"}?, attribute equalrows {"true" | "false"}?, attribute fence {"true" | "false"}?, attribute form {"prefix" | "infix" | "postfix"}?, attribute frame {linestyle}?, attribute framespacing {list {length, length}}?, attribute groupalign {group-alignment-list-list}?, attribute height {length}?, attribute indentalign {"left" | "center" | "right" | "auto" | "id"}?, attribute indentalignfirst {"left" | "center" | "right" | "auto" | "id" | "indentalign"}?, attribute indentalignlast {"left" | "center" | "right" | "auto" | "id" | "indentalign"}?, attribute indentshift {length}?, attribute indentshiftfirst {length | "indentshift"}?, attribute indentshiftlast {length | "indentshift"}?, attribute indenttarget {idref}?, attribute largeop {"true" | "false"}?, attribute leftoverhang {length}?, attribute length {unsigned-integer}?, attribute linebreak {"auto" | "newline" | "nobreak" | "goodbreak" | "badbreak"}?, attribute linebreakmultchar {text}?, attribute linebreakstyle {"before" | "after" | "duplicate" | "infixlinebreakstyle"}?, attribute lineleading {length}?, attribute linethickness {length | "thin" | "medium" | "thick"}?, attribute location {"w" | "nw" | "n" | "ne" | "e" | "se" | "s" | "sw"}?, attribute longdivstyle {"lefttop" | "stackedrightright" | "mediumstackedrightright" | "shortstackedrightright" | "righttop" | "left/\right" | "left)(right" | ":right=right" | "stackedleftleft" | "stackedleftlinetop"}?, attribute lquote {text}?, attribute lspace {length}?, attribute mathsize {"small" | "normal" | "big" | length}?, attribute mathvariant {"normal" | "bold" | "italic" | "bold-italic" | "double-struck" | "bold-fraktur" | "script" | "bold-script" | "fraktur" | "sans-serif" | "bold-sans-serif" | "sans-serif-italic" | "sans-serif-bold-italic" | "monospace" | "initial" | "tailed" | "looped" | "stretched"}?, attribute maxsize {length | "infinity"}?, attribute minlabelspacing {length}?, attribute minsize {length}?, attribute movablelimits {"true" | "false"}?, attribute mslinethickness {length | "thin" | "medium" | "thick"}?, attribute notation {text}?, attribute numalign {"left" | "center" | "right"}?, attribute open {text}?, attribute position {integer}?, attribute rightoverhang {length}?, attribute rowalign {list {verticalalign+} }?, attribute rowlines {list {linestyle +}}?, attribute rowspacing {list {(length) +}}?, attribute rowspan {positive-integer}?, attribute rquote {text}?, attribute rspace {length}?, attribute selection {positive-integer}?, attribute separator {"true" | "false"}?, attribute separators {text}?, attribute shift {integer}?, attribute side {"left" | "right" | "leftoverlap" | "rightoverlap"}?, attribute stackalign {"left" | "center" | "right" | "decimalpoint"}?, attribute stretchy {"true" | "false"}?, attribute subscriptshift {length}?, attribute superscriptshift {length}?, attribute symmetric {"true" | "false"}?, attribute valign {length}?, attribute width {length}? mstyle.deprecatedattributes = DeprecatedTokenAtt, attribute veryverythinmathspace {length}?, attribute verythinmathspace {length}?, attribute thinmathspace {length}?, attribute mediummathspace {length}?, attribute thickmathspace {length}?, attribute verythickmathspace {length}?, attribute veryverythickmathspace {length}? math.attributes &= CommonPresAtt math.attributes &= mstyle.specificattributes math.attributes &= mstyle.generalattributes merror = element merror {merror.attributes, ImpliedMrow} merror.attributes = CommonAtt, CommonPresAtt mpadded = element mpadded {mpadded.attributes, ImpliedMrow} mpadded.attributes = CommonAtt, CommonPresAtt, attribute height {mpadded-length}?, attribute depth {mpadded-length}?, attribute width {mpadded-length}?, attribute lspace {mpadded-length}?, attribute voffset {mpadded-length}? mphantom = element mphantom {mphantom.attributes, ImpliedMrow} mphantom.attributes = CommonAtt, CommonPresAtt mfenced = element mfenced {mfenced.attributes, MathExpression*} mfenced.attributes = CommonAtt, CommonPresAtt, attribute open {text}?, attribute close {text}?, attribute separators {text}? menclose = element menclose {menclose.attributes, ImpliedMrow} menclose.attributes = CommonAtt, CommonPresAtt, attribute notation {text}? msub = element msub {msub.attributes, MathExpression, MathExpression} msub.attributes = CommonAtt, CommonPresAtt, attribute subscriptshift {length}? msup = element msup {msup.attributes, MathExpression, MathExpression} msup.attributes = CommonAtt, CommonPresAtt, attribute superscriptshift {length}? msubsup = element msubsup {msubsup.attributes, MathExpression, MathExpression, MathExpression} msubsup.attributes = CommonAtt, CommonPresAtt, attribute subscriptshift {length}?, attribute superscriptshift {length}? munder = element munder {munder.attributes, MathExpression, MathExpression} munder.attributes = CommonAtt, CommonPresAtt, attribute accentunder {"true" | "false"}?, attribute align {"left" | "right" | "center"}? mover = element mover {mover.attributes, MathExpression, MathExpression} mover.attributes = CommonAtt, CommonPresAtt, attribute accent {"true" | "false"}?, attribute align {"left" | "right" | "center"}? munderover = element munderover {munderover.attributes, MathExpression, MathExpression, MathExpression} munderover.attributes = CommonAtt, CommonPresAtt, attribute accent {"true" | "false"}?, attribute accentunder {"true" | "false"}?, attribute align {"left" | "right" | "center"}? mmultiscripts = element mmultiscripts {mmultiscripts.attributes, MathExpression,MultiScriptExpression*,(mprescripts,MultiScriptExpression*)?} mmultiscripts.attributes = msubsup.attributes mtable = element mtable {mtable.attributes, TableRowExpression*} mtable.attributes = CommonAtt, CommonPresAtt, attribute align {xsd:string { pattern ='\s*(top|bottom|center|baseline|axis)(\s+-?[0-9]+)?\s*'}}?, attribute rowalign {list {verticalalign+} }?, attribute columnalign {list {columnalignstyle+} }?, attribute groupalign {group-alignment-list-list}?, attribute alignmentscope {list {("true" | "false") +}}?, attribute columnwidth {list {("auto" | length | "fit") +}}?, attribute width {"auto" | length}?, attribute rowspacing {list {(length) +}}?, attribute columnspacing {list {(length) +}}?, attribute rowlines {list {linestyle +}}?, attribute columnlines {list {linestyle +}}?, attribute frame {linestyle}?, attribute framespacing {list {length, length}}?, attribute equalrows {"true" | "false"}?, attribute equalcolumns {"true" | "false"}?, attribute displaystyle {"true" | "false"}?, attribute side {"left" | "right" | "leftoverlap" | "rightoverlap"}?, attribute minlabelspacing {length}? mlabeledtr = element mlabeledtr {mlabeledtr.attributes, TableCellExpression+} mlabeledtr.attributes = mtr.attributes mtr = element mtr {mtr.attributes, TableCellExpression*} mtr.attributes = CommonAtt, CommonPresAtt, attribute rowalign {"top" | "bottom" | "center" | "baseline" | "axis"}?, attribute columnalign {list {columnalignstyle+} }?, attribute groupalign {group-alignment-list-list}? mtd = element mtd {mtd.attributes, ImpliedMrow} mtd.attributes = CommonAtt, CommonPresAtt, attribute rowspan {positive-integer}?, attribute columnspan {positive-integer}?, attribute rowalign {"top" | "bottom" | "center" | "baseline" | "axis"}?, attribute columnalign {columnalignstyle}?, attribute groupalign {group-alignment-list}? mstack = element mstack {mstack.attributes, MstackExpression*} mstack.attributes = CommonAtt, CommonPresAtt, attribute align {xsd:string { pattern ='\s*(top|bottom|center|baseline|axis)(\s+-?[0-9]+)?\s*'}}?, attribute stackalign {"left" | "center" | "right" | "decimalpoint"}?, attribute charalign {"left" | "center" | "right"}?, attribute charspacing {length | "loose" | "medium" | "tight"}? mlongdiv = element mlongdiv {mlongdiv.attributes, MstackExpression,MstackExpression,MstackExpression+} mlongdiv.attributes = msgroup.attributes, attribute longdivstyle {"lefttop" | "stackedrightright" | "mediumstackedrightright" | "shortstackedrightright" | "righttop" | "left/\right" | "left)(right" | ":right=right" | "stackedleftleft" | "stackedleftlinetop"}? msgroup = element msgroup {msgroup.attributes, MstackExpression*} msgroup.attributes = CommonAtt, CommonPresAtt, attribute position {integer}?, attribute shift {integer}? msrow = element msrow {msrow.attributes, MsrowExpression*} msrow.attributes = CommonAtt, CommonPresAtt, attribute position {integer}? mscarries = element mscarries {mscarries.attributes, (MsrowExpression|mscarry)*} mscarries.attributes = CommonAtt, CommonPresAtt, attribute position {integer}?, attribute location {"w" | "nw" | "n" | "ne" | "e" | "se" | "s" | "sw"}?, attribute crossout {list {("none" | "updiagonalstrike" | "downdiagonalstrike" | "verticalstrike" | "horizontalstrike")*}}?, attribute scriptsizemultiplier {number}? mscarry = element mscarry {mscarry.attributes, MsrowExpression*} mscarry.attributes = CommonAtt, CommonPresAtt, attribute location {"w" | "nw" | "n" | "ne" | "e" | "se" | "s" | "sw"}?, attribute crossout {list {("none" | "updiagonalstrike" | "downdiagonalstrike" | "verticalstrike" | "horizontalstrike")*}}? maction = element maction {maction.attributes, MathExpression+} maction.attributes = CommonAtt, CommonPresAtt, attribute actiontype {text}, attribute selection {positive-integer}? epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/mathml/mathml3-common.rnc0000644000175000017500000000543713017276730031357 0ustar eugeneeugene# This is the Mathematical Markup Language (MathML) 3.0, an XML # application for describing mathematical notation and capturing # both its structure and content. # # Copyright 1998-2014 W3C (MIT, ERCIM, Keio, Beihang) # # Use and distribution of this code are permitted under the terms # W3C Software Notice and License # http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231 default namespace m = "http://www.w3.org/1998/Math/MathML" namespace local = "" start = math math = element math {math.attributes,MathExpression*} MathExpression = semantics NonMathMLAtt = attribute (* - (local:*|m:*)) {xsd:string} CommonDeprecatedAtt = attribute other {text}? CommonAtt = attribute id {xsd:ID}?, attribute xref {text}?, attribute class {xsd:NMTOKENS}?, attribute style {xsd:string}?, attribute href {xsd:anyURI}?, CommonDeprecatedAtt, NonMathMLAtt* math.attributes = CommonAtt, attribute display {"block" | "inline"}?, attribute maxwidth {length}?, attribute overflow {"linebreak" | "scroll" | "elide" | "truncate" | "scale"}?, attribute altimg {xsd:anyURI}?, attribute altimg-width {length}?, attribute altimg-height {length}?, attribute altimg-valign {length | "top" | "middle" | "bottom"}?, attribute alttext {text}?, attribute cdgroup {xsd:anyURI}?, math.deprecatedattributes # the mathml3-presentation schema adds additional attributes # to the math element, all those valid on mstyle math.deprecatedattributes = attribute mode {xsd:string}?, attribute macros {xsd:string}? name = attribute name {xsd:NCName} cd = attribute cd {xsd:NCName} src = attribute src {xsd:anyURI}? annotation = element annotation {annotation.attributes,text} annotation-xml.model = (MathExpression|anyElement)* anyElement = element (* - m:*) {(attribute * {text}|text| anyElement)*} annotation-xml = element annotation-xml {annotation.attributes, annotation-xml.model} annotation.attributes = CommonAtt, cd?, name?, DefEncAtt, src? DefEncAtt = attribute encoding {xsd:string}?, attribute definitionURL {xsd:anyURI}? semantics = element semantics {semantics.attributes, MathExpression, (annotation|annotation-xml)*} semantics.attributes = CommonAtt,DefEncAtt,cd?,name? length = xsd:string { pattern = '\s*((-?[0-9]*([0-9]\.?|\.[0-9])[0-9]*(e[mx]|in|cm|mm|p[xtc]|%)?)|(negative)?((very){0,2}thi(n|ck)|medium)mathspace)\s*' } epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/mathml/mathml3-content.rnc0000644000175000017500000003007113017276730031531 0ustar eugeneeugene # This is the Mathematical Markup Language (MathML) 3.0, an XML # application for describing mathematical notation and capturing # both its structure and content. # # Copyright 1998-2014 W3C (MIT, ERCIM, Keio, Beihang) # # Use and distribution of this code are permitted under the terms # W3C Software Notice and License # http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231 include "mathml3-strict-content.rnc"{ cn.content = (text | mglyph | sep | PresentationExpression)* cn.attributes = CommonAtt, DefEncAtt, attribute type {text}?, base? ci.attributes = CommonAtt, DefEncAtt, ci.type? ci.type = attribute type {text} ci.content = (text | mglyph | PresentationExpression)* csymbol.attributes = CommonAtt, DefEncAtt, attribute type {text}?,cd? csymbol.content = (text | mglyph | PresentationExpression)* bvar = element bvar {CommonAtt, ((ci | semantics-ci) & degree?)} cbytes.attributes = CommonAtt, DefEncAtt cs.attributes = CommonAtt, DefEncAtt apply.content = ContExp+ | (ContExp, BvarQ, Qualifier*, ContExp*) bind.content = apply.content } base = attribute base {text} sep = element sep {empty} PresentationExpression |= notAllowed DomainQ = (domainofapplication|condition|interval|(lowlimit,uplimit?))* domainofapplication = element domainofapplication {ContExp} condition = element condition {ContExp} uplimit = element uplimit {ContExp} lowlimit = element lowlimit {ContExp} Qualifier = DomainQ|degree|momentabout|logbase degree = element degree {ContExp} momentabout = element momentabout {ContExp} logbase = element logbase {ContExp} type = attribute type {text} order = attribute order {"numeric" | "lexicographic"} closure = attribute closure {text} ContExp |= piecewise piecewise = element piecewise {CommonAtt, DefEncAtt,(piece* & otherwise?)} piece = element piece {CommonAtt, DefEncAtt, ContExp, ContExp} otherwise = element otherwise {CommonAtt, DefEncAtt, ContExp} DeprecatedContExp = reln | fn | declare ContExp |= DeprecatedContExp reln = element reln {ContExp*} fn = element fn {ContExp} declare = element declare {attribute type {xsd:string}?, attribute scope {xsd:string}?, attribute nargs {xsd:nonNegativeInteger}?, attribute occurrence {"prefix"|"infix"|"function-model"}?, DefEncAtt, ContExp+} interval.class = interval ContExp |= interval.class interval = element interval { CommonAtt, DefEncAtt,closure?, ContExp,ContExp} unary-functional.class = inverse | ident | domain | codomain | image | ln | log | moment ContExp |= unary-functional.class inverse = element inverse { CommonAtt, DefEncAtt, empty} ident = element ident { CommonAtt, DefEncAtt, empty} domain = element domain { CommonAtt, DefEncAtt, empty} codomain = element codomain { CommonAtt, DefEncAtt, empty} image = element image { CommonAtt, DefEncAtt, empty} ln = element ln { CommonAtt, DefEncAtt, empty} log = element log { CommonAtt, DefEncAtt, empty} moment = element moment { CommonAtt, DefEncAtt, empty} lambda.class = lambda ContExp |= lambda.class lambda = element lambda { CommonAtt, DefEncAtt, BvarQ, DomainQ, ContExp} nary-functional.class = compose ContExp |= nary-functional.class compose = element compose { CommonAtt, DefEncAtt, empty} binary-arith.class = quotient | divide | minus | power | rem | root ContExp |= binary-arith.class quotient = element quotient { CommonAtt, DefEncAtt, empty} divide = element divide { CommonAtt, DefEncAtt, empty} minus = element minus { CommonAtt, DefEncAtt, empty} power = element power { CommonAtt, DefEncAtt, empty} rem = element rem { CommonAtt, DefEncAtt, empty} root = element root { CommonAtt, DefEncAtt, empty} unary-arith.class = factorial | minus | root | abs | conjugate | arg | real | imaginary | floor | ceiling | exp ContExp |= unary-arith.class factorial = element factorial { CommonAtt, DefEncAtt, empty} abs = element abs { CommonAtt, DefEncAtt, empty} conjugate = element conjugate { CommonAtt, DefEncAtt, empty} arg = element arg { CommonAtt, DefEncAtt, empty} real = element real { CommonAtt, DefEncAtt, empty} imaginary = element imaginary { CommonAtt, DefEncAtt, empty} floor = element floor { CommonAtt, DefEncAtt, empty} ceiling = element ceiling { CommonAtt, DefEncAtt, empty} exp = element exp { CommonAtt, DefEncAtt, empty} nary-minmax.class = max | min ContExp |= nary-minmax.class max = element max { CommonAtt, DefEncAtt, empty} min = element min { CommonAtt, DefEncAtt, empty} nary-arith.class = plus | times | gcd | lcm ContExp |= nary-arith.class plus = element plus { CommonAtt, DefEncAtt, empty} times = element times { CommonAtt, DefEncAtt, empty} gcd = element gcd { CommonAtt, DefEncAtt, empty} lcm = element lcm { CommonAtt, DefEncAtt, empty} nary-logical.class = and | or | xor ContExp |= nary-logical.class and = element and { CommonAtt, DefEncAtt, empty} or = element or { CommonAtt, DefEncAtt, empty} xor = element xor { CommonAtt, DefEncAtt, empty} unary-logical.class = not ContExp |= unary-logical.class not = element not { CommonAtt, DefEncAtt, empty} binary-logical.class = implies | equivalent ContExp |= binary-logical.class implies = element implies { CommonAtt, DefEncAtt, empty} equivalent = element equivalent { CommonAtt, DefEncAtt, empty} quantifier.class = forall | exists ContExp |= quantifier.class forall = element forall { CommonAtt, DefEncAtt, empty} exists = element exists { CommonAtt, DefEncAtt, empty} nary-reln.class = eq | gt | lt | geq | leq ContExp |= nary-reln.class eq = element eq { CommonAtt, DefEncAtt, empty} gt = element gt { CommonAtt, DefEncAtt, empty} lt = element lt { CommonAtt, DefEncAtt, empty} geq = element geq { CommonAtt, DefEncAtt, empty} leq = element leq { CommonAtt, DefEncAtt, empty} binary-reln.class = neq | approx | factorof | tendsto ContExp |= binary-reln.class neq = element neq { CommonAtt, DefEncAtt, empty} approx = element approx { CommonAtt, DefEncAtt, empty} factorof = element factorof { CommonAtt, DefEncAtt, empty} tendsto = element tendsto { CommonAtt, DefEncAtt, type?, empty} int.class = int ContExp |= int.class int = element int { CommonAtt, DefEncAtt, empty} Differential-Operator.class = diff ContExp |= Differential-Operator.class diff = element diff { CommonAtt, DefEncAtt, empty} partialdiff.class = partialdiff ContExp |= partialdiff.class partialdiff = element partialdiff { CommonAtt, DefEncAtt, empty} unary-veccalc.class = divergence | grad | curl | laplacian ContExp |= unary-veccalc.class divergence = element divergence { CommonAtt, DefEncAtt, empty} grad = element grad { CommonAtt, DefEncAtt, empty} curl = element curl { CommonAtt, DefEncAtt, empty} laplacian = element laplacian { CommonAtt, DefEncAtt, empty} nary-setlist-constructor.class = set | \list ContExp |= nary-setlist-constructor.class set = element set { CommonAtt, DefEncAtt, type?, BvarQ*, DomainQ*, ContExp*} \list = element \list { CommonAtt, DefEncAtt, order?, BvarQ*, DomainQ*, ContExp*} nary-set.class = union | intersect | cartesianproduct ContExp |= nary-set.class union = element union { CommonAtt, DefEncAtt, empty} intersect = element intersect { CommonAtt, DefEncAtt, empty} cartesianproduct = element cartesianproduct { CommonAtt, DefEncAtt, empty} binary-set.class = in | notin | notsubset | notprsubset | setdiff ContExp |= binary-set.class in = element in { CommonAtt, DefEncAtt, empty} notin = element notin { CommonAtt, DefEncAtt, empty} notsubset = element notsubset { CommonAtt, DefEncAtt, empty} notprsubset = element notprsubset { CommonAtt, DefEncAtt, empty} setdiff = element setdiff { CommonAtt, DefEncAtt, empty} nary-set-reln.class = subset | prsubset ContExp |= nary-set-reln.class subset = element subset { CommonAtt, DefEncAtt, empty} prsubset = element prsubset { CommonAtt, DefEncAtt, empty} unary-set.class = card ContExp |= unary-set.class card = element card { CommonAtt, DefEncAtt, empty} sum.class = sum ContExp |= sum.class sum = element sum { CommonAtt, DefEncAtt, empty} product.class = product ContExp |= product.class product = element product { CommonAtt, DefEncAtt, empty} limit.class = limit ContExp |= limit.class limit = element limit { CommonAtt, DefEncAtt, empty} unary-elementary.class = sin | cos | tan | sec | csc | cot | sinh | cosh | tanh | sech | csch | coth | arcsin | arccos | arctan | arccosh | arccot | arccoth | arccsc | arccsch | arcsec | arcsech | arcsinh | arctanh ContExp |= unary-elementary.class sin = element sin { CommonAtt, DefEncAtt, empty} cos = element cos { CommonAtt, DefEncAtt, empty} tan = element tan { CommonAtt, DefEncAtt, empty} sec = element sec { CommonAtt, DefEncAtt, empty} csc = element csc { CommonAtt, DefEncAtt, empty} cot = element cot { CommonAtt, DefEncAtt, empty} sinh = element sinh { CommonAtt, DefEncAtt, empty} cosh = element cosh { CommonAtt, DefEncAtt, empty} tanh = element tanh { CommonAtt, DefEncAtt, empty} sech = element sech { CommonAtt, DefEncAtt, empty} csch = element csch { CommonAtt, DefEncAtt, empty} coth = element coth { CommonAtt, DefEncAtt, empty} arcsin = element arcsin { CommonAtt, DefEncAtt, empty} arccos = element arccos { CommonAtt, DefEncAtt, empty} arctan = element arctan { CommonAtt, DefEncAtt, empty} arccosh = element arccosh { CommonAtt, DefEncAtt, empty} arccot = element arccot { CommonAtt, DefEncAtt, empty} arccoth = element arccoth { CommonAtt, DefEncAtt, empty} arccsc = element arccsc { CommonAtt, DefEncAtt, empty} arccsch = element arccsch { CommonAtt, DefEncAtt, empty} arcsec = element arcsec { CommonAtt, DefEncAtt, empty} arcsech = element arcsech { CommonAtt, DefEncAtt, empty} arcsinh = element arcsinh { CommonAtt, DefEncAtt, empty} arctanh = element arctanh { CommonAtt, DefEncAtt, empty} nary-stats.class = mean | sdev | variance | median | mode ContExp |= nary-stats.class mean = element mean { CommonAtt, DefEncAtt, empty} sdev = element sdev { CommonAtt, DefEncAtt, empty} variance = element variance { CommonAtt, DefEncAtt, empty} median = element median { CommonAtt, DefEncAtt, empty} mode = element mode { CommonAtt, DefEncAtt, empty} nary-constructor.class = vector | matrix | matrixrow ContExp |= nary-constructor.class vector = element vector { CommonAtt, DefEncAtt, BvarQ, DomainQ, ContExp*} matrix = element matrix { CommonAtt, DefEncAtt, BvarQ, DomainQ, ContExp*} matrixrow = element matrixrow { CommonAtt, DefEncAtt, BvarQ, DomainQ, ContExp*} unary-linalg.class = determinant | transpose ContExp |= unary-linalg.class determinant = element determinant { CommonAtt, DefEncAtt, empty} transpose = element transpose { CommonAtt, DefEncAtt, empty} nary-linalg.class = selector ContExp |= nary-linalg.class selector = element selector { CommonAtt, DefEncAtt, empty} binary-linalg.class = vectorproduct | scalarproduct | outerproduct ContExp |= binary-linalg.class vectorproduct = element vectorproduct { CommonAtt, DefEncAtt, empty} scalarproduct = element scalarproduct { CommonAtt, DefEncAtt, empty} outerproduct = element outerproduct { CommonAtt, DefEncAtt, empty} constant-set.class = integers | reals | rationals | naturalnumbers | complexes | primes | emptyset ContExp |= constant-set.class integers = element integers { CommonAtt, DefEncAtt, empty} reals = element reals { CommonAtt, DefEncAtt, empty} rationals = element rationals { CommonAtt, DefEncAtt, empty} naturalnumbers = element naturalnumbers { CommonAtt, DefEncAtt, empty} complexes = element complexes { CommonAtt, DefEncAtt, empty} primes = element primes { CommonAtt, DefEncAtt, empty} emptyset = element emptyset { CommonAtt, DefEncAtt, empty} constant-arith.class = exponentiale | imaginaryi | notanumber | true | false | pi | eulergamma | infinity ContExp |= constant-arith.class exponentiale = element exponentiale { CommonAtt, DefEncAtt, empty} imaginaryi = element imaginaryi { CommonAtt, DefEncAtt, empty} notanumber = element notanumber { CommonAtt, DefEncAtt, empty} true = element true { CommonAtt, DefEncAtt, empty} false = element false { CommonAtt, DefEncAtt, empty} pi = element pi { CommonAtt, DefEncAtt, empty} eulergamma = element eulergamma { CommonAtt, DefEncAtt, empty} infinity = element infinity { CommonAtt, DefEncAtt, empty}epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/mathml/LICENSE0000644000175000017500000000027013017276730027013 0ustar eugeneeugeneUse and distribution of all schemas in this directory are permitted under the terms W3C Software Notice and License http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231 ././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootepubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/mathml/mathml3-strict-content.rncepubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/mathml/mathml3-strict-content.r0000644000175000017500000000361613017276730032523 0ustar eugeneeugene# This is the Mathematical Markup Language (MathML) 3.0, an XML # application for describing mathematical notation and capturing # both its structure and content. # # Copyright 1998-2014 W3C (MIT, ERCIM, Keio, Beihang) # # Use and distribution of this code are permitted under the terms # W3C Software Notice and License # http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231 default namespace m = "http://www.w3.org/1998/Math/MathML" ContExp = semantics-contexp | cn | ci | csymbol | apply | bind | share | cerror | cbytes | cs cn = element cn {cn.attributes,cn.content} cn.content = text cn.attributes = CommonAtt, attribute type {"integer" | "real" | "double" | "hexdouble"} semantics-ci = element semantics {semantics.attributes,(ci|semantics-ci), (annotation|annotation-xml)*} semantics-contexp = element semantics {semantics.attributes,ContExp, (annotation|annotation-xml)*} ci = element ci {ci.attributes, ci.content} ci.attributes = CommonAtt, ci.type? ci.type = attribute type {"integer" | "rational" | "real" | "complex" | "complex-polar" | "complex-cartesian" | "constant" | "function" | "vector" | "list" | "set" | "matrix"} ci.content = text csymbol = element csymbol {csymbol.attributes,csymbol.content} SymbolName = xsd:NCName csymbol.attributes = CommonAtt, cd csymbol.content = SymbolName BvarQ = bvar* bvar = element bvar {CommonAtt, (ci | semantics-ci)} apply = element apply {CommonAtt,apply.content} apply.content = ContExp+ bind = element bind {CommonAtt,bind.content} bind.content = ContExp,bvar*,ContExp share = element share {CommonAtt, src, empty} cerror = element cerror {cerror.attributes, csymbol, ContExp*} cerror.attributes = CommonAtt cbytes = element cbytes {cbytes.attributes, base64} cbytes.attributes = CommonAtt base64 = xsd:base64Binary cs = element cs {cs.attributes, text} cs.attributes = CommonAtt MathExpression |= ContExp epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/epub-trigger.rnc0000644000175000017500000000210713017276730027625 0ustar eugeneeugene namespace epub = "http://www.idpf.org/2007/ops" namespace ev = "http://www.w3.org/2001/xml-events" html5.metadata.class |= epub.trigger html5.flow.class |= epub.trigger epub.trigger = element epub:trigger { epub.trigger.attlist & epub.trigger.content } epub.trigger.attlist = html5.id.attr? & epub.trigger.action.attr & epub.trigger.ref.attr & xml.events.event.attr & xml.events.observer.attr & xml.events.defaultAction.attr? & xml.events.phase.attr? & xml.events.propagate.attr? epub.trigger.action.attr = attribute action { 'show'|'hide'|'play'|'pause'|'resume'|'mute'|'unmute' } epub.trigger.ref.attr = attribute ref { datatype.IDREF } xml.events.event.attr = attribute ev:event { datatype.NMTOKEN } xml.events.observer.attr = attribute ev:observer { datatype.IDREF } xml.events.defaultAction.attr = attribute ev:defaultAction { 'cancel' | 'perform' } xml.events.phase.attr = attribute ev:phase { 'capture' | 'default' } xml.events.propagate.attr = attribute ev:propagate { 'stop' | 'continue' } epub.trigger.content = emptyepubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/datatypes.rnc0000644000175000017500000001644313017276730027237 0ustar eugeneeugene[ xml:id = "datatypes-common" ] div { datatype.ID = datatype.ID.lexical datatype.IDREF = datatype.IDREF.lexical datatype.IDREFS = datatype.IDREFS.lexical datatype.languagecode = datatype.BCP47 # http://www.w3.org/TR/xmlschema11-2/#language datatype.BCP47 = xsd:language { pattern = "[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*" } # http://www.w3.org/TR/xmlschema11-2/#ID datatype.ID.xsd = xsd:ID # http://www.w3.org/TR/xmlschema11-2/#NCName datatype.IDREF.lexical = xsd:NCName datatype.IDREFS.lexical = list { datatype.IDREF.lexical+ } datatype.ID.lexical = xsd:NCName # http://www.w3.org/TR/xmlschema11-2/#IDREF datatype.IDREF.xsd = xsd:IDREF # http://www.w3.org/TR/xmlschema11-2/#IDREFS datatype.IDREFS.xsd = xsd:IDREFS # http://www.w3.org/TR/xmlschema11-2/#NMTOKEN datatype.NMTOKEN = xsd:NMTOKEN # http://www.w3.org/TR/xmlschema11-2/#NMTOKENS datatype.NMTOKENS = xsd:NMTOKENS # http://www.w3.org/TR/xmlschema11-2/#string datatype.string = xsd:string datatype.string.nonempty = xsd:token { minLength='1' } datatype.text = text # http://www.w3.org/TR/xmlschema11-2/#nt-dateRep datatype.date = xsd:date # http://www.w3.org/TR/xmlschema11-2/#nt-dateTimeRep datatype.dateTime = xsd:dateTime # http://www.w3.org/TR/xmlschema11-2/#nt-timeRep datatype.date.or.dateTime = datatype.date | datatype.dateTime datatype.LEIRI = xsd:anyURI # http://www.w3.org/TR/xmlschema11-2/#anyURI # http://tools.ietf.org/html/rfc3986#appendix-B # http://www.w3.org/TR/html5/urls.html#valid-url-potentially-surrounded-by-spaces datatype.URI = xsd:anyURI datatype.URI.absolute = xsd:anyURI datatype.IRI = datatype.URI datatype.character.encoding = datatype.iana.charset datatype.iana.charset = xsd:NMTOKEN # http://www.w3.org/TR/html5/infrastructure.html#valid-mime-type # http://tools.ietf.org/html/rfc4288#section-4.2 # http://tools.ietf.org/html/rfc2616#section-3.7 datatype.mimetype = xsd:string { pattern='[a-zA-Z0-9!#$&+\-\^_]+/[a-zA-Z0-9!#$&+\-\^_]+.*' } datatype.mimetype.nocharset = datatype.mimetype # http://www.w3.org/TR/xmlschema11-2/#nonNegativeInteger # http://www.w3.org/TR/html5/common-microsyntaxes.html#non-negative-integers datatype.non-negative.integer = xsd:nonNegativeInteger # http://www.w3.org/TR/xmlschema11-2/#positiveInteger datatype.positive.integer = xsd:positiveInteger # http://www.w3.org/TR/xmlschema11-2/#integer datatype.integer = xsd:integer # http://www.w3.org/TR/xmlschema11-2/#nt-floatRep # http://www.w3.org/TR/html5/common-microsyntaxes.html#real-numbers datatype.float = xsd:float datatype.float.positive = xsd:float { minExclusive = '0'} datatype.float.non-negative = xsd:float { minInclusive = '0' } datatype.token = xsd:string { pattern = '[^\s]+' } datatype.space.separated.tokens = list { datatype.token* } } [ xml:id = "datatypes-smil" ] div { # http://www.w3.org/TR/smil/smil-timing.html#TimingSyntax-Full-clock-value # http://www.w3.org/TR/smil/smil-timing.html#TimingSyntax-Partial-clock-value # http://www.w3.org/TR/smil/smil-timing.html#TimingSyntax-Timecount-value datatype.smil.npt = xsd:string { pattern = "(\s*)[0-9]+:[0-5][0-9]:[0-5][0-9](\.[0-9]+)?(\s*)" } | xsd:string { pattern = "(\s*)[0-5][0-9]:[0-5][0-9](\.[0-9]+)?(\s*)" } | xsd:string { pattern = "(\s*)[0-9]+(\.[0-9]+)?(h|min|s|ms)?(\s*)" } } [ xml:id = "datatypes-vocab" ] div { datatype.property = xsd:NMTOKEN datatype.properties = xsd:NMTOKENS datatype.prefixdecl = text #\s*([\i-[:]][\c-[:]]*: +[^ ]+)(\s+[\i-[:]][\c-[:]]*: +[^ ]+)*\s* } [ xml:id = "datatypes-ssml" ] div { # http://www.w3.org/TR/speech-synthesis11/#edef_phoneme datatype.ssml.PhoneticExpression = xsd:string datatype.ssml.PhoneticAlphabet = xsd:string { pattern = "(ipa|x-.+)" } } [ xml:id = "datatypes-html5" ] div { datatype.html5.browsing.context.name.or.keyword = xsd:string { pattern = "()|([^_].*)|(_[bB][lL][aA][nN][kK])|(_[sS][eE][lL][fF])|(_[pP][aA][rR][eE][nN][tT])|(_[tT][oO][pP])" } datatype.html5.browsing.context.name = xsd:string { pattern = "()|([^_].*)" } datatype.html5.token = xsd:string { pattern = '[^\s]+' } # http://www.w3.org/TR/html5/common-microsyntaxes.html#space-separated-tokens datatype.html5.space.separated.tokens = list { datatype.html5.token* } datatype.html5.ordered.set.unique.tokens = datatype.html5.space.separated.tokens datatype.html5.URL.spaces = datatype.URI # http://dev.w3.org/csswg/css3-mediaqueries/#syntax # http://www.w3.org/TR/html5/common-microsyntaxes.html#mq datatype.html5.media.query = xsd:string datatype.html5.name = xsd:string datatype.html5.name.reference = xsd:string { pattern = "#.+" } # http://www.w3.org/TR/html5/common-microsyntaxes.html#months datatype.html5.month = xsd:token { pattern ='([0-9]{4,})-([0-9]{2})' } # http://www.w3.org/TR/html5/common-microsyntaxes.html#dates datatype.html5.date = xsd:token { pattern ='([0-9]{4,})-([0-9]{2})-([0-9]{2})'} # http://www.w3.org/TR/html5/common-microsyntaxes.html#times datatype.html5.time = xsd:token { pattern ='([0-9]{2}):([0-9]{2})(:[0-9]{2}(\.[0-9]+)?)?'} # http://www.w3.org/TR/html5/common-microsyntaxes.html#local-dates-and-times datatype.html5.datetime.local = xsd:token { pattern = '([0-9]{4,})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2})(:[0-9]{2}(\.[0-9]+)?)?' } # http://www.w3.org/TR/html5/common-microsyntaxes.html#global-dates-and-times datatype.html5.datetime.global = xsd:token { pattern = '([0-9]{4,})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2})(:[0-9]{2}(\.[0-9]+)?)?(Z|((\+|-)([0-9]{2}):([0-9]{2})))' } datatype.html5.datetime = datatype.html5.datetime.global # http://www.w3.org/TR/html5/common-microsyntaxes.html#vaguer-moments-in-time datatype.html5.date.or.time = datatype.html5.date | datatype.html5.month | datatype.html5.time | datatype.html5.datetime.global # http://www.w3.org/TR/html5/common-microsyntaxes.html#vaguer-moments-in-time datatype.html5.date.optional.time = datatype.html5.date | datatype.html5.datetime.global datatype.html5.week = xsd:token { pattern ='([0-9]{4,})-W([0-9]{2})' } datatype.html5.accesskey = datatype.html5.ordered.set.unique.tokens datatype.html5.coords.rectangle = xsd:token { pattern = "-?[0-9]+,-?[0-9]+,-?[0-9]+,-?[0-9]+" } datatype.html5.coords.circle = xsd:token { pattern = "-?[0-9]+,-?[0-9]+,[0-9]+" } datatype.html5.coords.poly = xsd:token { pattern = "-?[0-9]+,-?[0-9]+,-?[0-9]+,-?[0-9]+,-?[0-9]+,-?[0-9]+(,-?[0-9]+,-?[0-9]+)*" } datatype.html5.js = xsd:string datatype.html5.script = xsd:string datatype.html5.script.documentation = xsd:string datatype.html5.iframe.srcdoc.xml = xsd:string datatype.style = xsd:string datatype.html5.sizes = list { xsd:string { pattern = "[1-9][0-9]*x[1-9][0-9]*" }+ } datatype.html5.emailaddress = xsd:string { pattern = "[^@]+@[^@]+" } datatype.html5.emailaddresslist = xsd:string { pattern = "([^@]+@[^@]+,)*([^@]+@[^@]+)" } # http://www.w3.org/TR/html5/common-microsyntaxes.html#colors datatype.html5.color = xsd:string { pattern = '#([A-Fa-f0-9]{6})' } } [ xml:id = "datatypes-html5forms" ] div { datatype.html5.forms.mimetypelist = xsd:string # http://www.w3.org/TR/html5/forms.html#attr-form-accept-charset datatype.html5.forms.charsetlist = list { datatype.character.encoding+ } datatype.html5.forms.pattern = xsd:string datatype.html5.forms.string.nolinebreaks = xsd:string } epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/epub-switch.rnc0000644000175000017500000000253713017276730027472 0ustar eugeneeugene namespace epub = "http://www.idpf.org/2007/ops" html5.flow.class |= epub.switch.flow html5.phrasing.class |= epub.switch.phrasing epub.switch.flow = element epub:switch { epub.switch.attlist, epub.switch.case.flow+, epub.switch.default.flow } epub.switch.phrasing = element epub:switch { epub.switch.attlist, epub.switch.case.phrasing+, epub.switch.default.phrasing } epub.switch.case.flow = element epub:case { epub.case.attlist & epub.case.flow.content } epub.switch.case.phrasing = element epub:case { epub.case.attlist & epub.case.phrasing.content } epub.switch.default.flow = element epub:default { epub.default.attlist & epub.default.flow.content } epub.switch.default.phrasing = element epub:default { epub.default.attlist & epub.default.phrasing.content } epub.case.flow.content = epub.switch.any epub.case.phrasing.content = epub.switch.any epub.switch.any = (anyElement | text)* epub.default.flow.content = html5.flow.model epub.default.phrasing.content = html5.phrasing.model epub.switch.attlist &= html5.id.attr? epub.case.attlist &= html5.id.attr? & epub.case.rn.attr epub.default.attlist &= html5.id.attr? epub.case.rn.attr = attribute required-namespace { datatype.URI } anyElement = element * { (attribute * { text } | text | anyElement)* } epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/html5/0000755000175000017500000000000013017276730025556 5ustar eugeneeugeneepubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/html5/html5-sections-30.rnc0000644000175000017500000000472613017276730031371 0ustar eugeneeugene html5.flow.class |= html5.sections.class | html5.headings.class html5.sections.class |= html5.section | html5.article | html5.nav | html5.aside | html5.header | html5.footer | html5.address | html5.main html5.headings.class |= html5.hgroup | html5.h1 | html5.h2 | html5.h3 | html5.h4 | html5.h5 | html5.h6 html5.headings.attrs &= html5.global.attrs html5.sections.attrs &= html5.global.attrs html5.hgroup = element hgroup {html5.hgroup.attlist & html5.hgroup.content} html5.hgroup.attlist &= html5.headings.attrs html5.hgroup.content = (html5.h1 | html5.h2 | html5.h3 | html5.h4 | html5.h5 | html5.h6)+ html5.h1 = element h1 {html5.h.attlist, html5.h.content} html5.h2 = element h2 {html5.h.attlist, html5.h.content} html5.h3 = element h3 {html5.h.attlist, html5.h.content} html5.h4 = element h4 {html5.h.attlist, html5.h.content} html5.h5 = element h5 {html5.h.attlist, html5.h.content} html5.h6 = element h6 {html5.h.attlist, html5.h.content} html5.h.attlist &= html5.headings.attrs html5.h.content = html5.phrasing.model html5.section = element section {html5.section.attlist & html5.section.content} html5.section.attlist &= html5.sections.attrs html5.section.content = html5.section.model html5.article = element article {html5.article.attlist & html5.article.content} html5.article.attlist &= html5.sections.attrs html5.article.content = html5.section.model html5.nav = element nav { html5.nav.attlist & html5.nav.content } html5.nav.attlist &= html5.sections.attrs html5.nav.content = html5.flow.model html5.aside = element aside { html5.aside.attlist & html5.aside.content } html5.aside.attlist &= html5.sections.attrs html5.aside.content = html5.flow.model html5.header = element header { html5.header.attlist & html5.header.content } html5.header.attlist &= html5.sections.attrs html5.header.content = html5.flow.model html5.footer = element footer { html5.footer.attlist & html5.footer.content } html5.footer.attlist &= html5.sections.attrs html5.footer.content = html5.flow.model html5.address = element address { html5.address.attlist & html5.address.content } html5.address.attlist &= html5.sections.attrs html5.address.content = html5.flow.model html5.main = element main { html5.main.attlist & html5.main.content } html5.main.attlist &= html5.sections.attrs html5.main.content = html5.flow.modelepubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/html5/html5-md.rnc0000644000175000017500000000301113017276730027704 0ustar eugeneeugenehtml5.global.attrs &= html5.attrs.md html5.link.attlist &= html5.attrs.md html5.meta.attlist &= html5.attrs.md html5.a.attrs &= html5.attrs.md html5.area.attlist &= html5.attrs.md html5.attrs.md = ( html5.md.attr.itemref? & html5.md.attr.itemprop? & html5.md.attr.itemscope? & html5.md.attr.itemtype? & html5.md.attr.itemid? ) html5.attrs.md.no-itemprop = ( html5.md.attr.itemref? & html5.md.attr.itemscope? & html5.md.attr.itemtype? & html5.md.attr.itemid? ) html5.md.attr.itemref = attribute itemref { datatype.IDREFS.lexical } html5.md.attr.itemprop = attribute itemprop { datatype.string } html5.md.attr.itemscope = attribute itemscope { "itemscope" | "" } html5.md.attr.itemtype = attribute itemtype { list { datatype.URI.absolute+ } } html5.md.attr.itemid = attribute itemid { datatype.URI } ### elements ###### html5.phrasing.class |= html5.md.link.elem | html5.md.meta.elem html5.metadata.class |= html5.md.meta.elem | html5.md.link.elem html5.md.link.elem = element link { html5.md.link.attlist } html5.md.link.attlist = html5.md.attr.itemprop & html5.attrs.md.no-itemprop & html5.global.common.attrs & html5.global.xml.attrs & html5.media.attr? & html5.hreflang.attr? & html5.rel.attr? & html5.type.mime.attr? & html5.link.sizes.attr? & html5.href.attr? html5.md.meta.elem = element meta { html5.md.meta.attlist } html5.md.meta.attlist = html5.md.attr.itemprop & html5.meta.content.attr & html5.attrs.md.no-itemprop & html5.global.common.attrs & html5.global.xml.attrs epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/html5/html5-embed-30.rnc0000644000175000017500000002171413017276730030612 0ustar eugeneeugene html5.flow.class |= html5.embed.flow.class html5.phrasing.class |= html5.embed.phrasing.class html5.embed.flow.class |= html5.audio.flow | html5.video.flow | html5.object.flow | html5.canvas.flow | html5.map.flow | html5.area | html5.iframe | html5.img | html5.embed html5.embed.phrasing.class |= html5.audio.phrasing | html5.video.phrasing | html5.object.phrasing | html5.canvas.phrasing | html5.map.phrasing | html5.area | html5.iframe | html5.img | html5.embed html5.video.flow = element video { html5.video.attlist & html5.video.flow.content } html5.video.phrasing = element video { html5.video.attlist & html5.video.phrasing.content } html5.video.attlist &= html5.global.attrs & html5.av.common.attrs & html5.video.poster.attr? & html5.dimension.attrs html5.video.poster.attr = attribute poster { datatype.html5.URL.spaces } html5.video.flow.content = html5.av.source, html5.track*, html5.flow.model html5.video.phrasing.content = html5.av.source, html5.track*, html5.phrasing.model html5.audio.flow = element audio { html5.audio.attlist & html5.audio.flow.content } html5.audio.phrasing = element audio { html5.audio.attlist & html5.audio.phrasing.content } html5.audio.attlist &= html5.global.attrs & html5.av.common.attrs html5.audio.flow.content = html5.av.source, html5.track*, html5.flow.model html5.audio.phrasing.content = html5.av.source, html5.track*, html5.phrasing.model html5.av.source = html5.src.attr | html5.source* html5.av.common.attrs = html5.av.autoplay.attr? & html5.av.preload.attr? & html5.av.controls.attr? & html5.av.loop.attr? & html5.av.mediagroup.attr? & html5.av.muted.attr? html5.track = element track { html5.track.attlist } html5.track.attlist &= html5.global.attrs & html5.track.kind.attr? & html5.src.attr & html5.track.default.attr? & html5.track.srclang.attr? & html5.track.label.attr? html5.track.kind.attr = attribute kind { 'subtitles' | 'captions' | 'descriptions' | 'chapters' | 'metadata' } html5.track.srclang.attr = attribute srclang { datatype.languagecode } html5.track.label.attr = attribute label { datatype.string } html5.track.default.attr = attribute default { 'default' | '' } html5.av.autoplay.attr = attribute autoplay { 'autoplay' | '' } html5.av.preload.attr = attribute preload { 'none' | 'metadata' | 'auto' | '' } html5.av.controls.attr = attribute controls { 'controls' | '' } html5.av.loop.attr = attribute loop { 'loop' | '' } html5.av.mediagroup.attr = attribute mediagroup { datatype.string } html5.av.muted.attr = attribute muted { 'muted' | '' } html5.source = element source { html5.source.attlist } html5.source.attlist &= html5.global.attrs & html5.src.attr & html5.type.mime.attr? & html5.media.attr? html5.img = element img { html5.img.attlist } html5.img.attlist &= html5.global.attrs & html5.dimension.attrs & html5.src.attr & html5.alt.attr? & html5.usemap.attr? & html5.img.ismap.attr? html5.img.ismap.attr = attribute ismap { 'ismap' | '' } html5.embed = element embed { html5.embed.attlist } html5.embed.attlist &= html5.global.attrs & html5.src.attr? & html5.type.mime.attr? & html5.dimension.attrs & html5.embed.attrs.other* html5.embed.attrs.other = empty #TODO html5.object.flow = element object { html5.object.flow.content & html5.object.attlist } html5.object.phrasing = element object { html5.object.phrasing.content & html5.object.attlist } html5.object.attlist &= html5.global.attrs & (( html5.object.data.attr & html5.type.mime.attr? & html5.object.typemustmatch.attr?) | html5.type.mime.attr ) & html5.dimension.attrs & html5.usemap.attr? & html5.name.context.attr? & html5.forms.form.attr? html5.object.data.attr = attribute data { datatype.html5.URL.spaces } html5.object.typemustmatch.attr = attribute typemustmatch { 'typemustmatch' | '' } html5.object.flow.content = html5.param*, html5.flow.model html5.object.phrasing.content = html5.param*, html5.phrasing.model html5.param = element param { html5.param.attlist } html5.param.attlist &= html5.global.attrs & html5.param.name.attr & html5.param.value.attr html5.param.name.attr = attribute name { string } html5.param.value.attr = attribute value { string } html5.canvas.flow = element canvas { html5.canvas.attlist & html5.canvas.flow.content } html5.canvas.phrasing = element canvas { html5.canvas.attlist & html5.canvas.phrasing.content } html5.canvas.attlist = html5.global.attrs & html5.dimension.attrs html5.canvas.flow.content = html5.flow.model html5.canvas.phrasing.content = html5.phrasing.model html5.map.flow = element map { html5.map.flow.content & html5.map.attlist } html5.map.phrasing = element map { html5.map.phrasing.content & html5.map.attlist } html5.map.attlist &= html5.global.attrs & html5.name.id.attr html5.map.flow.content = html5.flow.model html5.map.phrasing.content = html5.phrasing.model html5.area = element area { html5.area.attlist } html5.area.attlist &= html5.global.common.attrs & html5.global.xml.attrs & (html5.alt.attr & html5.href.attr)? & html5.target.attr? & html5.rel.attr? & html5.media.attr? & html5.hreflang.attr? & html5.type.mime.attr? & html5.area.shape.attrs? html5.area.shape.attrs = ( html5.area.shape.rect.attr? & html5.area.coords.rect.attr ) |( html5.area.shape.circle.attr & html5.area.coords.circle.attr ) |( html5.area.shape.poly.attr & html5.area.coords.poly.attr ) |( html5.area.shape.default.attr ) html5.area.shape.rect.attr = attribute shape { 'rect' } html5.area.coords.rect.attr = attribute coords { datatype.html5.coords.rectangle } html5.area.shape.circle.attr = attribute shape { 'circle' } html5.area.coords.circle.attr = attribute coords { datatype.html5.coords.circle } html5.area.shape.poly.attr = attribute shape { 'poly' } html5.area.coords.poly.attr = attribute coords {datatype.html5.coords.poly} html5.area.shape.default.attr = attribute shape { 'default' } html5.iframe = element iframe { html5.iframe.attlist & html5.iframe.content} html5.iframe.attlist &= html5.global.attrs & html5.src.attr? & html5.name.context.attr? & html5.dimension.attrs & html5.iframe.sandbox.attr? & html5.iframe.seamless.attr? & html5.iframe.srcdoc.attr? html5.iframe.seamless.attr = attribute seamless { 'seamless' | '' } html5.iframe.sandbox.attr = attribute sandbox { list { 'allow-top-navigation'?, 'allow-same-origin'?, 'allow-forms'?, 'allow-scripts'? } | list { 'allow-top-navigation'?, 'allow-same-origin'?, 'allow-scripts'?, 'allow-forms'? } | list { 'allow-top-navigation'?, 'allow-forms'?, 'allow-same-origin'?, 'allow-scripts'? } | list { 'allow-top-navigation'?, 'allow-forms'?, 'allow-scripts'?, 'allow-same-origin'? } | list { 'allow-top-navigation'?, 'allow-scripts'?, 'allow-same-origin'?, 'allow-forms'? } | list { 'allow-top-navigation'?, 'allow-scripts'?, 'allow-forms'?, 'allow-same-origin'? } | list { 'allow-same-origin'?, 'allow-top-navigation'?, 'allow-forms'?, 'allow-scripts'? } | list { 'allow-same-origin'?, 'allow-top-navigation'?, 'allow-scripts'?, 'allow-forms'? } | list { 'allow-forms'?, 'allow-top-navigation'?, 'allow-same-origin'?, 'allow-scripts'? } | list { 'allow-forms'?, 'allow-top-navigation'?, 'allow-scripts'?, 'allow-same-origin'? } | list { 'allow-scripts'?, 'allow-top-navigation'?, 'allow-same-origin'?, 'allow-forms'? } | list { 'allow-scripts'?, 'allow-top-navigation'?, 'allow-forms'?, 'allow-same-origin'? } | list { 'allow-same-origin'?, 'allow-forms'?, 'allow-top-navigation'?, 'allow-scripts'? } | list { 'allow-same-origin'?, 'allow-scripts'?, 'allow-top-navigation'?, 'allow-forms'? } | list { 'allow-forms'?, 'allow-same-origin'?, 'allow-top-navigation'?, 'allow-scripts'? } | list { 'allow-forms'?, 'allow-scripts'?, 'allow-top-navigation'?, 'allow-same-origin'? } | list { 'allow-scripts'?, 'allow-same-origin'?, 'allow-top-navigation'?, 'allow-forms'? } | list { 'allow-scripts'?, 'allow-forms'?, 'allow-top-navigation'?, 'allow-same-origin'? } | list { 'allow-same-origin'?, 'allow-forms'?, 'allow-scripts'?, 'allow-top-navigation'? } | list { 'allow-same-origin'?, 'allow-scripts'?, 'allow-forms'?, 'allow-top-navigation'? } | list { 'allow-forms'?, 'allow-same-origin'?, 'allow-scripts'?, 'allow-top-navigation'? } | list { 'allow-forms'?, 'allow-scripts'?, 'allow-same-origin'?, 'allow-top-navigation'? } | list { 'allow-scripts'?, 'allow-same-origin'?, 'allow-forms'?, 'allow-top-navigation'? } | list { 'allow-scripts'?, 'allow-forms'?, 'allow-same-origin'?, 'allow-top-navigation'? } } html5.iframe.srcdoc.attr = attribute srcdoc { datatype.html5.iframe.srcdoc.xml } html5.iframe.content = html5.iframe.content.xml html5.iframe.content.html = datatype.text html5.iframe.content.xml = empty epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/html5/html5-phrasing-30.rnc0000644000175000017500000001325513017276730031352 0ustar eugeneeugene html5.flow.class |= html5.phrasing.class | html5.a.flow html5.phrasing.class |= datatype.text | html5.a.phrasing | html5.em | html5.strong | html5.small | html5.cite | html5.q | html5.dfn | html5.abbr | html5.time | html5.code | html5.var | html5.samp | html5.kbd | html5.sup | html5.sub | html5.i | html5.b | html5.mark | html5.bdo | html5.bdi | html5.span | html5.br | html5.wbr | html5.s | html5.u | html5.ruby html5.phrasing.attrs &= html5.global.attrs html5.a.flow = element a { html5.a.flow.attlist & html5.a.flow.content } html5.a.flow.attlist &= html5.global.common.attrs & html5.global.xml.attrs & html5.a.attrs html5.a.flow.content = html5.flow.model html5.a.phrasing = element a { html5.a.phrasing.attlist & html5.a.phrasing.content } html5.a.phrasing.attlist &= html5.global.common.attrs & html5.global.xml.attrs & html5.a.attrs html5.a.phrasing.content = html5.phrasing.model html5.a.attrs &= ( html5.href.attr & ( html5.hreflang.attr? & html5.target.attr? & html5.rel.attr? & html5.media.attr? & html5.type.mime.attr? ))? html5.abbr = element abbr { html5.abbr.attlist & html5.abbr.content } html5.abbr.attlist &= html5.phrasing.attrs html5.abbr.content = html5.phrasing.model html5.b = element b { html5.b.attlist & html5.b.content } html5.b.attlist &= html5.phrasing.attrs html5.b.content = html5.phrasing.model html5.bdo = element bdo { html5.bdo.attlist & html5.bdo.content } html5.bdo.attlist &= html5.phrasing.attrs html5.bdo.content = html5.phrasing.model html5.bdi = element bdi { html5.bdi.attlist & html5.bdi.content } html5.bdi.attlist &= html5.phrasing.attrs html5.bdi.content = html5.phrasing.model html5.br = element br { html5.br.attlist } html5.br.attlist &= html5.phrasing.attrs html5.cite = element cite { html5.cite.attlist & html5.cite.content } html5.cite.attlist &= html5.phrasing.attrs html5.cite.content = html5.phrasing.model html5.code = element code { html5.code.attlist & html5.code.content } html5.code.attlist &= html5.phrasing.attrs html5.code.content = html5.phrasing.model html5.dfn = element dfn { html5.dfn.attlist & html5.dfn.content } html5.dfn.attlist &= html5.phrasing.attrs html5.dfn.content = html5.phrasing.model html5.em = element em { html5.em.attlist & html5.em.content } html5.em.attlist &= html5.phrasing.attrs html5.em.content = html5.phrasing.model html5.i = element i { html5.i.attlist & html5.i.content } html5.i.attlist &= html5.phrasing.attrs html5.i.content = html5.phrasing.model html5.kbd = element kbd { html5.kbd.attlist & html5.kbd.content } html5.kbd.attlist &= html5.phrasing.attrs html5.kbd.content = html5.phrasing.model html5.mark = element mark { html5.mark.attlist & html5.mark.content } html5.mark.attlist &= html5.phrasing.attrs html5.mark.content = html5.phrasing.model html5.strong = element strong { html5.strong.attlist & html5.strong.content } html5.strong.attlist &= html5.phrasing.attrs html5.strong.content = html5.phrasing.model html5.small = element small { html5.small.attlist & html5.small.content } html5.small.attlist &= html5.phrasing.attrs html5.small.content = html5.phrasing.model html5.q = element q { html5.q.attlist & html5.q.content } html5.q.attlist &= html5.phrasing.attrs & html5.cite.attr? html5.q.content = html5.phrasing.model html5.s = element s { html5.s.attlist & html5.s.content } html5.s.attlist &= html5.phrasing.attrs html5.s.content = html5.phrasing.model html5.samp = element samp { html5.samp.attlist & html5.samp.content } html5.samp.attlist &= html5.phrasing.attrs html5.samp.content = html5.phrasing.model html5.sub = element sub { html5.sub.attlist & html5.sub.content } html5.sub.attlist &= html5.phrasing.attrs html5.sub.content = html5.phrasing.model html5.sup = element sup { html5.sup.attlist & html5.sup.content } html5.sup.attlist &= html5.phrasing.attrs html5.sup.content = html5.phrasing.model html5.span = element span { html5.span.attlist & html5.span.content } html5.span.attlist &= html5.phrasing.attrs html5.span.content = html5.phrasing.model html5.time = element time { html5.time.attlist & html5.time.content } html5.time.attlist &= html5.phrasing.attrs & ((html5.time.pubdate.attr & html5.time.datetime.attr.date-optional-time?) | (html5.time.datetime.attr.date-or-time?)) html5.time.pubdate.attr = attribute pubdate { 'pubdate' | '' } html5.time.datetime.attr.date-optional-time = attribute datetime { datatype.html5.date.optional.time } html5.time.datetime.attr.date-or-time = attribute datetime { datatype.html5.date.or.time } html5.time.content = html5.phrasing.model html5.var = element var { html5.var.attlist & html5.var.content } html5.var.attlist &= html5.phrasing.attrs html5.var.content = html5.phrasing.model html5.wbr = element wbr { html5.wbr.attlist } html5.wbr.attlist &= html5.phrasing.attrs html5.u = element u { html5.u.attlist & html5.u.content } html5.u.attlist = html5.phrasing.attrs html5.u.content = html5.phrasing.model html5.ruby = element ruby { html5.ruby.attlist & html5.ruby.content } html5.ruby.attlist = html5.phrasing.attrs html5.ruby.content = ((html5.phrasing.model, (html5.rt | (html5.rp, html5.rt, html5.rp)))+) html5.rt = element rt { html5.rt.attlist & html5.rt.content } html5.rt.attlist &= html5.phrasing.attrs html5.rt.content = html5.phrasing.model html5.rp = element rp { html5.rp.attlist & html5.rp.content } html5.rp.attlist &= html5.phrasing.attrs html5.rp.content = html5.phrasing.model epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/html5/html5-script-30.rnc0000644000175000017500000002173313017276730031043 0ustar eugeneeugene html5.metadata.class |= html5.script html5.flow.class |= html5.script html5.phrasing.class |= html5.script html5.global.common.attrs &= html5.global.scripting.attrs html5.body.attlist &= html5.scripting.body.attrs html5.script = html5.script.internal | html5.script.external html5.script.internal = element script { html5.script.internal.attlist & html5.script.internal.content } html5.script.external = element script { html5.script.external.attlist & html5.script.external.content } html5.script.internal.attlist &= html5.global.attrs & html5.type.mime.nocharset.attr? html5.script.external.attlist &= html5.global.attrs & html5.src.attr & html5.script.defer.attr? & html5.script.async.attr? & html5.type.mime.nocharset.attr? & html5.charset.attr? html5.script.defer.attr = attribute defer { 'defer' | '' } html5.script.async.attr = attribute async { 'async' | '' } html5.script.internal.content = datatype.html5.script html5.script.external.content = datatype.html5.script.documentation html5.global.scripting.attrs &= html5.scripting.onabort.attr? & html5.scripting.onblur.attr? & html5.scripting.oncanplay.attr? & html5.scripting.oncanplaythrough.attr? & html5.scripting.onchange.attr? & html5.scripting.onclick.attr? & html5.scripting.oncontextmenu.attr? & html5.scripting.ondblclick.attr? & html5.scripting.ondrag.attr? & html5.scripting.ondragend.attr? & html5.scripting.ondragenter.attr? & html5.scripting.ondragleave.attr? & html5.scripting.ondragover.attr? & html5.scripting.ondragstart.attr? & html5.scripting.ondrop.attr? & html5.scripting.ondurationchange.attr? & html5.scripting.onemptied.attr? & html5.scripting.onended.attr? & html5.scripting.onerror.attr? & html5.scripting.onfocus.attr? & html5.scripting.oninput.attr? & html5.scripting.oninvalid.attr? & html5.scripting.onkeydown.attr? & html5.scripting.onkeypress.attr? & html5.scripting.onkeyup.attr? & html5.scripting.onload.attr? & html5.scripting.onloadeddata.attr? & html5.scripting.onloadedmetadata.attr? & html5.scripting.onloadstart.attr? & html5.scripting.onmousedown.attr? & html5.scripting.onmousemove.attr? & html5.scripting.onmouseout.attr? & html5.scripting.onmouseover.attr? & html5.scripting.onmouseup.attr? & html5.scripting.onmousewheel.attr? & html5.scripting.onpause.attr? & html5.scripting.onplay.attr? & html5.scripting.onplaying.attr? & html5.scripting.onprogress.attr? & html5.scripting.onratechange.attr? & html5.scripting.onreadystatechange.attr? & html5.scripting.onreset.attr? & html5.scripting.onscroll.attr? & html5.scripting.onseeked.attr? & html5.scripting.onseeking.attr? & html5.scripting.onselect.attr? & html5.scripting.onshow.attr? & html5.scripting.onstalled.attr? & html5.scripting.onsubmit.attr? & html5.scripting.onsuspend.attr? & html5.scripting.ontimeupdate.attr? & html5.scripting.onvolumechange.attr? & html5.scripting.onwaiting.attr? html5.scripting.onabort.attr = attribute onabort { datatype.html5.js } html5.scripting.onblur.attr = attribute onblur { datatype.html5.js } html5.scripting.oncanplay.attr = attribute oncanplay { datatype.html5.js } html5.scripting.oncanplaythrough.attr = attribute oncanplaythrough { datatype.html5.js } html5.scripting.onchange.attr = attribute onchange { datatype.html5.js } html5.scripting.onclick.attr = attribute onclick { datatype.html5.js } html5.scripting.oncontextmenu.attr = attribute oncontextmenu { datatype.html5.js } html5.scripting.ondblclick.attr = attribute ondblclick { datatype.html5.js } html5.scripting.ondrag.attr = attribute ondrag { datatype.html5.js } html5.scripting.ondragend.attr = attribute ondragend { datatype.html5.js } html5.scripting.ondragenter.attr = attribute ondragenter { datatype.html5.js } html5.scripting.ondragleave.attr = attribute ondragleave { datatype.html5.js } html5.scripting.ondragover.attr = attribute ondragover { datatype.html5.js } html5.scripting.ondragstart.attr = attribute ondragstart { datatype.html5.js } html5.scripting.ondrop.attr = attribute ondrop { datatype.html5.js } html5.scripting.ondurationchange.attr = attribute ondurationchange { datatype.html5.js } html5.scripting.onemptied.attr = attribute onemptied { datatype.html5.js } html5.scripting.onended.attr = attribute onended { datatype.html5.js } html5.scripting.onerror.attr = attribute onerror { datatype.html5.js } html5.scripting.onfocus.attr = attribute onfocus { datatype.html5.js } html5.scripting.oninput.attr = attribute oninput { datatype.html5.js } html5.scripting.oninvalid.attr = attribute oninvalid { datatype.html5.js } html5.scripting.onkeydown.attr = attribute onkeydown { datatype.html5.js } html5.scripting.onkeypress.attr = attribute onkeypress { datatype.html5.js } html5.scripting.onkeyup.attr = attribute onkeyup { datatype.html5.js } html5.scripting.onload.attr = attribute onload { datatype.html5.js } html5.scripting.onloadeddata.attr = attribute onloadeddata { datatype.html5.js } html5.scripting.onloadedmetadata.attr = attribute onloadedmetadata { datatype.html5.js } html5.scripting.onloadstart.attr = attribute onloadstart { datatype.html5.js } html5.scripting.onmousedown.attr = attribute onmousedown { datatype.html5.js } html5.scripting.onmousemove.attr = attribute onmousemove { datatype.html5.js } html5.scripting.onmouseout.attr = attribute onmouseout { datatype.html5.js } html5.scripting.onmouseover.attr = attribute onmouseover { datatype.html5.js } html5.scripting.onmouseup.attr = attribute onmouseup { datatype.html5.js } html5.scripting.onmousewheel.attr = attribute onmousewheel { datatype.html5.js } html5.scripting.onpause.attr = attribute onpause { datatype.html5.js } html5.scripting.onplay.attr = attribute onplay { datatype.html5.js } html5.scripting.onplaying.attr = attribute onplaying { datatype.html5.js } html5.scripting.onprogress.attr = attribute onprogress { datatype.html5.js } html5.scripting.onratechange.attr = attribute onratechange { datatype.html5.js } html5.scripting.onreadystatechange.attr = attribute onreadystatechange { datatype.html5.js } html5.scripting.onreset.attr = attribute onreset { datatype.html5.js } html5.scripting.onscroll.attr = attribute onscroll { datatype.html5.js } html5.scripting.onseeked.attr = attribute onseeked { datatype.html5.js } html5.scripting.onseeking.attr = attribute onseeking { datatype.html5.js } html5.scripting.onselect.attr = attribute onselect { datatype.html5.js } html5.scripting.onshow.attr = attribute onshow { datatype.html5.js } html5.scripting.onstalled.attr = attribute onstalled { datatype.html5.js } html5.scripting.onsubmit.attr = attribute onsubmit { datatype.html5.js } html5.scripting.onsuspend.attr = attribute onsuspend { datatype.html5.js } html5.scripting.ontimeupdate.attr = attribute ontimeupdate { datatype.html5.js } html5.scripting.onvolumechange.attr = attribute onvolumechange { datatype.html5.js } html5.scripting.onwaiting.attr = attribute onwaiting { datatype.html5.js } html5.scripting.body.attrs = html5.scripting.body.onafterprint.attr? & html5.scripting.body.onbeforeprint.attr? & html5.scripting.body.onbeforeunload.attr? & html5.scripting.body.onhashchange.attr? & html5.scripting.body.onmessage.attr? & html5.scripting.body.onoffline.attr? & html5.scripting.body.ononline.attr? & html5.scripting.body.onpopstate.attr? & html5.scripting.body.onredo.attr? & html5.scripting.body.onresize.attr? & html5.scripting.body.onstorage.attr? & html5.scripting.body.onundo.attr? & html5.scripting.body.onunload.attr? html5.scripting.body.onafterprint.attr = attribute onafterprint { datatype.html5.js } html5.scripting.body.onbeforeprint.attr = attribute onbeforeprint { datatype.html5.js } html5.scripting.body.onbeforeunload.attr = attribute onbeforeunload { datatype.html5.js } html5.scripting.body.onhashchange.attr = attribute onhashchange { datatype.html5.js } html5.scripting.body.onmessage.attr = attribute onmessage { datatype.html5.js } html5.scripting.body.onoffline.attr = attribute onoffline { datatype.html5.js } html5.scripting.body.ononline.attr = attribute ononline { datatype.html5.js } html5.scripting.body.onpopstate.attr = attribute onpopstate { datatype.html5.js } html5.scripting.body.onredo.attr = attribute onredo { datatype.html5.js } html5.scripting.body.onresize.attr = attribute onresize { datatype.html5.js } html5.scripting.body.onstorage.attr = attribute onstorage { datatype.html5.js } html5.scripting.body.onundo.attr = attribute onundo { datatype.html5.js } html5.scripting.body.onunload.attr = attribute onunload { datatype.html5.js }epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/html5/html5-interactive-30.rnc0000644000175000017500000001107113017276730032046 0ustar eugeneeugene html5.flow.class |= html5.interactive.flow.class html5.phrasing.class |= html5.interactive.phrasing.class html5.metadata.class |= html5.interactive.metadata.class html5.interactive.phrasing.class |= html5.command.class | html5.progress html5.interactive.flow.class |= html5.menu | html5.details html5.interactive.metadata.class |= html5.command.class html5.command.class |= html5.command.command | html5.command.radio | html5.command.checkbox html5.html.attlist &= html5.interactive.manifest.attr? html5.global.common.attrs &= html5.interactive.global.attrs html5.interactive.global.attrs &= html5.interactive.contextmenu.attr? & html5.interactive.contenteditable.attr? & html5.interactive.draggable.attr? & html5.interactive.hidden.attr? & html5.interactive.spellcheck.attr? & html5.interactive.accesskey.attr? & html5.interactive.tabindex.attr? & html5.interactive.dropzone.attr? html5.progress = element progress { html5.progress.attlist & html5.progress.content } html5.progress.attlist &= html5.phrasing.attrs & html5.progress.value.attr? & html5.progress.max.attr? html5.progress.value.attr = attribute value { datatype.float.non-negative } html5.progress.max.attr = attribute max { datatype.float.positive } html5.progress.content = html5.phrasing.model html5.command.command = element command { html5.command.command.attlist } html5.command.command.attlist &= html5.phrasing.attrs & html5.command.command.type.attr? & html5.common-command.attrs html5.command.command.type.attr = attribute type { 'command' } html5.command.checked.attr = attribute checked { 'checked' | '' } html5.command.radio = element command { html5.command.radio.attlist } html5.command.radio.attlist &= html5.phrasing.attrs & ( html5.command.radio.type.attr & html5.command.radio.radiogroup.attr & html5.command.checked.attr? ) & html5.common-command.attrs html5.command.radio.type.attr = attribute type { 'radio' } html5.command.radio.radiogroup.attr = attribute radiogroup { datatype.string } html5.command.checkbox = element command { html5.command.checkbox.attlist } html5.command.checkbox.attlist = html5.phrasing.attrs & ( html5.command.checkbox.type.attr & html5.command.checked.attr? ) & html5.common-command.attrs html5.command.checkbox.type.attr = attribute type { 'checkbox' } html5.common-command.attrs &= html5.command.label.attr? & html5.command.icon.attr? & html5.command.disabled.attr? html5.command.label.attr = attribute label { string } html5.command.icon.attr = attribute icon { datatype.html5.URL.spaces } html5.command.disabled.attr = attribute disabled { 'disabled' |'' } html5.menu = element menu { html5.menu.attlist & html5.menu.content } html5.menu.attlist &= html5.global.attrs & html5.menu.type.attr? & html5.menu.label.attr? html5.menu.type.attr = attribute type { 'toolbar' | 'context' } html5.menu.label.attr = attribute label { string } html5.menu.content = ( html5.mli* | html5.flow.model ) html5.mli = element li { html5.mli.attlist & html5.mli.content } html5.mli.attlist &= html5.global.attrs html5.mli.content = html5.flow.model html5.details = element details { html5.details.attlist & html5.details.content } html5.details.attlist &= html5.global.attrs & html5.details.open.attr? html5.details.open.attr = attribute open { 'open' | '' } html5.details.content = html5.summary?, html5.flow.model html5.summary = element summary { html5.summary.attlist & html5.summary.content } html5.summary.attlist &= html5.global.attrs html5.summary.content = html5.phrasing.model html5.interactive.manifest.attr = attribute manifest { datatype.html5.URL.spaces } html5.interactive.contextmenu.attr = attribute contextmenu { datatype.IDREF } html5.interactive.contenteditable.attr = attribute contenteditable { 'true' | 'false' | '' } html5.interactive.draggable.attr = attribute draggable { 'true' | 'false' } html5.interactive.hidden.attr = attribute hidden { 'hidden' | '' } html5.interactive.spellcheck.attr = attribute spellcheck { 'true' | 'false' | '' } html5.interactive.accesskey.attr = attribute accesskey { datatype.html5.accesskey } html5.interactive.tabindex.attr = attribute tabindex { datatype.integer } html5.interactive.dropzone.attr = attribute dropzone { list { ( xsd:string { pattern = "[sS]:.+" } | xsd:string { pattern = "[fF]:.+" })*, ( 'copy' | 'move' | 'link' )?, ( xsd:string { pattern = "[sS]:.+" } | xsd:string { pattern = "[fF]:.+" })* } } epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/html5/html5-style-30.rnc0000644000175000017500000000136213017276730030673 0ustar eugeneeugene html5.metadata.class |= html5.style.unscoped html5.global.common.attrs &= html5.style.attr? html5.flow.class |= html5.style.scoped html5.style.unscoped = element style { html5.style.unscoped.attlist, html5.style.content } html5.style.unscoped.attlist &= html5.global.attrs, html5.media.attr?, html5.type.mime.nocharset.attr? html5.style.scoped = element style { html5.style.scoped.attlist, html5.style.content } html5.style.scoped.attlist &= html5.global.attrs, html5.media.attr?, html5.type.mime.nocharset.attr?, html5.style.scoped.attr html5.style.scoped.attr = attribute scoped {'scoped' | ''} html5.style.content = datatype.style html5.style.attr = attribute style { datatype.style }epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/html5/README0000644000175000017500000000155213017276730026441 0ustar eugeneeugene The modules in this directory are part of the schema that defines a vocabulary and grammar for EPUB3 XHTML Content Documents [1], based on W3C XHTML5 [2], with IDPF/EPUB extensions. The modules are derived from the schemas used in the validator.nu service [3]. The schema for for EPUB3 XHTML Content Documents is not continuously updated to reflect the latest version of the W3C HTML5 specification; it is a static representation of the EPUB3 XHTML Content Document definition, and changes to it occur only in conjunction with new releases of the EPUB3 specification. Note - as the W3C HTML5 specification becomes a Final Recommendation, it is anticipated that IDPF will no longer maintain its own complete schema. [1] http://idpf.org/epub/30/spec/epub30-contentdocs.html#sec-xhtml [2] http://www.w3.org/TR/html5/ [3] https://bitbucket.org/validator/syntax/ epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/html5/html5-document-30.rnc0000644000175000017500000000407113017276730031351 0ustar eugeneeugene html5.html = element html { html5.html.attlist, html5.head, html5.body } html5.html.attlist &= html5.global.attrs html5.head = element head { html5.head.attlist & html5.head.content } html5.head.attlist &= html5.global.attrs html5.head.content = html5.title? & html5.base? & html5.metadata.class* html5.metadata.class |= html5.link | html5.meta html5.body = element body { html5.body.attlist & html5.body.content } html5.body.attlist &= html5.global.attrs html5.body.content = html5.section.model html5.base = element base { html5.base.attlist } html5.base.attlist &= html5.global.attrs & ((html5.href.attr & html5.target.attr?) | html5.target.attr) html5.link = element link { html5.link.attlist } html5.link.attlist &= html5.global.common.attrs & html5.global.xml.attrs & html5.media.attr? & html5.hreflang.attr? & html5.type.mime.attr? & html5.link.sizes.attr? & html5.link.choice html5.link.choice = html5.rel.attr & html5.href.attr html5.link.sizes.attr = attribute sizes { 'any' | datatype.html5.sizes } html5.meta = element meta { html5.meta.attlist } html5.meta.attlist &= html5.global.common.attrs & html5.global.xml.attrs & html5.meta.attrs.choice html5.meta.attrs.choice = (html5.meta.name.attr & html5.meta.content.attr) | (html5.meta.http-equiv.attr & html5.meta.content.attr) | html5.charset.attr html5.meta.name.attr = attribute name { datatype.string } html5.meta.http-equiv.attr = attribute http-equiv { html5.meta.http-equiv.attr.content } html5.meta.http-equiv.attr.content = xsd:string { pattern = "([Dd][Ee][Ff][Aa][Uu][Ll][Tt]\-[Ss][Tt][Yy][Ll][Ee])|([Rr][Ee][Ff][Rr][Ee][Ss][Hh])|([Cc][Oo][Nn][Tt][Ee][Nn][Tt]\-[Tt][Yy][Pp][Ee])" } html5.meta.content.attr = attribute content { datatype.string } html5.title = element title { html5.title.attlist & html5.title.content } html5.title.attlist &= html5.global.attrs html5.title.content = datatype.text epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/html5/html5-grouping-30.rnc0000644000175000017500000001261413017276730031367 0ustar eugeneeugene html5.flow.class |= html5.grouping.class html5.grouping.class |= html5.p | html5.hr | html5.pre | html5.blockquote | html5.ul | html5.ol | html5.dl | html5.div | html5.figure | html5.table html5.grouping.attrs &= html5.global.attrs html5.p = element p { html5.p.attlist & html5.p.content } html5.p.attlist &= html5.grouping.attrs html5.p.content = html5.phrasing.model html5.hr = element hr { html5.hr.attlist } html5.hr.attlist = html5.grouping.attrs html5.pre = element pre { html5.pre.attlist & html5.pre.content } html5.pre.attlist = html5.grouping.attrs html5.pre.content = html5.phrasing.model html5.blockquote = element blockquote { html5.blockquote.attlist & html5.blockquote.content } html5.blockquote.attlist = html5.grouping.attrs & html5.cite.attr? html5.blockquote.content = html5.flow.model html5.ul = element ul { html5.ul.attlist & html5.ul.content } html5.ul.attlist = html5.grouping.attrs html5.ul.content = html5.li* html5.li = element li { html5.li.attlist & html5.li.content } html5.li.attlist = html5.global.attrs html5.li.content = html5.flow.model html5.ol = element ol { html5.ol.attlist & html5.ol.content } html5.ol.attlist = html5.grouping.attrs & html5.ol.start.attr? & html5.ol.reversed.attr? & ol.type.attr? html5.ol.start.attr = attribute start { datatype.integer } html5.ol.reversed.attr = attribute reversed { 'reversed' | '' } ol.type.attr = attribute type {'1' | 'a' | 'A' | 'i' | 'I' } html5.ol.content = html5.oli* html5.oli = element li { html5.oli.attlist & html5.oli.content } html5.oli.attlist = html5.global.attrs & html5.oli.attrs.value? html5.oli.attrs.value = attribute value { datatype.integer } html5.oli.content = html5.flow.model html5.dl = element dl { html5.dl.attlist & html5.dl.content } html5.dl.attlist = html5.grouping.attrs html5.dl.content = (html5.dt+ , html5.dd+)* html5.dt = element dt { html5.dt.attlist & html5.dt.content } html5.dt.attlist = html5.global.attrs html5.dt.content = html5.phrasing.model html5.dd = element dd { html5.dd.attlist & html5.dd.content } html5.dd.phrasing = element dd { html5.dd.phrasing.content & html5.dd.attlist } html5.dd.attlist = html5.global.attrs html5.dd.content = html5.flow.model html5.dd.phrasing.content = html5.phrasing.model html5.div = element div { html5.div.attlist & html5.div.content } html5.div.attlist = html5.grouping.attrs html5.div.content = html5.flow.model html5.figure = element figure { html5.figure.attlist & html5.figure.content } html5.figure.attlist = html5.grouping.attrs html5.figure.content = ( html5.figcaption, html5.flow.model ) | ( html5.flow.model, html5.figcaption? ) html5.figcaption = element figcaption { html5.figcaption.attlist & html5.figcaption.content } html5.figcaption.attlist = html5.global.attrs html5.figcaption.content = html5.flow.model html5.table = element table { table.attlist & table.content } table.attlist &= html5.grouping.attrs & html5.table.border.attr? html5.table.border.attr = attribute border { '1' | '' } table.content = (html5.caption?, html5.colgroup*, html5.thead?, ((html5.tfoot, ( html5.tbody* | html5.tr+ ))|(( html5.tbody* | html5.tr+ ), html5.tfoot?))) html5.caption = element caption { html5.caption.attlist & html5.caption.content } html5.caption.attlist &= html5.global.attrs html5.caption.content = html5.flow.model html5.colgroup = element colgroup { html5.colgroup.attlist & html5.colgroup.content } html5.colgroup.attlist &= html5.global.attrs html5.colgroup.content = html5.col* | html5.colspan.col.span.attr? html5.col = element col { html5.col.attlist } html5.col.attlist &= html5.global.attrs & html5.colspan.col.span.attr? html5.thead = element thead { html5.thead.attlist & html5.thead.content } html5.thead.attlist &= html5.grouping.attrs html5.thead.content = html5.tr* html5.tfoot = element tfoot { html5.tfoot.attlist & html5.tfoot.content } html5.tfoot.attlist &= ( html5.grouping.attrs ) html5.tfoot.content = ( html5.tr* ) html5.tbody = element tbody { html5.tbody.attlist & html5.tbody.content } html5.tbody.attlist &= ( html5.grouping.attrs ) html5.tbody.content = ( html5.tr* ) html5.tr = element tr { html5.tr.attlist & html5.tr.content } html5.tr.attlist &= html5.grouping.attrs html5.tr.content = ( html5.td | html5.th )* html5.td = element td { html5.td.attlist & html5.td.content } html5.td.attlist &= html5.global.attrs & html5.table.colspan.attr? & html5.table.rowspan.attr? & html5.table.headers.attr? html5.td.content = ( html5.flow.model ) html5.th = element th { html5.th.content & html5.th.attlist } html5.th.attlist &= html5.global.attrs & html5.table.colspan.attr? & html5.table.rowspan.attr? & html5.table.scope.attr? & html5.table.headers.attr? html5.th.content = ( html5.flow.model ) html5.colspan.col.span.attr = attribute span { datatype.positive.integer } html5.table.colspan.attr = attribute colspan { datatype.positive.integer } html5.table.rowspan.attr = attribute rowspan { datatype.non-negative.integer } html5.table.headers.attr = attribute headers { datatype.IDREFS } html5.table.scope.attr = attribute scope { 'row' | 'col' | 'rowgroup' | 'colgroup' } html5.table.abbr.attr = attribute abbr { string } epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/html5/html5-edit-30.rnc0000644000175000017500000000203213017276730030453 0ustar eugeneeugene html5.flow.class |= html5.edit.flow.class html5.phrasing.class |= html5.edit.phrasing.class html5.edit.flow.class |= html5.ins.flow | html5.del.flow html5.edit.phrasing.class |= html5.ins.phrasing | html5.del.phrasing html5.ins.flow = element ins { html5.ins.attlist & html5.ins.flow.content } html5.ins.phrasing = element ins { html5.ins.attlist & html5.ins.phrasing.content } html5.ins.flow.content = html5.flow.model html5.ins.phrasing.content = html5.phrasing.model html5.ins.attlist &= html5.global.attrs & html5.cite.attr? & html5.edit.datetime.attr? html5.del.flow = element del { html5.del.attlist & html5.del.flow.content } html5.del.phrasing = element del { html5.del.attlist & html5.del.phrasing.content } html5.del.flow.content = html5.flow.model html5.del.phrasing.content = html5.phrasing.model html5.del.attlist &= html5.global.attrs & html5.cite.attr? & html5.edit.datetime.attr? html5.edit.datetime.attr = attribute datetime { datatype.html5.date.optional.time } epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/html5/LICENSE0000644000175000017500000000240013017276730026557 0ustar eugeneeugeneThe license statement herein applies to all files in this directory. Copyright (c) 2005-2007 Elika J. Etemad (fantasai) and Henri Sivonen (hsivonen) Copyright (c) 2007-2008 Mozilla Foundation Copyright (c) 2010-2011 International Digital Publishing Forum Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/html5/html5-models-30.rnc0000644000175000017500000000047213017276730031017 0ustar eugeneeugene html5.flow.model = html5.flow.model.html5 html5.flow.model.html5 = html5.flow.class* html5.grouping.model = html5.grouping.class+ html5.phrasing.model = html5.phrasing.class+ html5.section.model = html5.section.model.html5 html5.section.model.html5 = html5.flow.modelepubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/html5/html5-rdfa.rnc0000644000175000017500000001043413017276730030227 0ustar eugeneeugene html5.global.attrs &= html5.rdfa.attrs html5.link.choice |= (html5.rdfa.attrs & html5.href.attr?) html5.meta.attlist &= html5.rdfa.attrs.no-content-property html5.meta.attrs.choice |= html5.rdfa.property.attr & html5.meta.content.attr html5.a.phrasing.attlist &= html5.rdfa.attrs.no-rel html5.area.attlist &= html5.rdfa.attrs.no-rel ### elements ###### html5.flow.class |= html5.rdfa.link.elem | html5.rdfa.meta.elem html5.rdfa.link.elem = element link { html5.rdfa.link.attlist } html5.rdfa.link.attlist = html5.rdfa.property.attr & html5.rdfa.attrs.no-property & html5.global.common.attrs & html5.global.xml.attrs & html5.media.attr? & html5.hreflang.attr? & html5.type.mime.attr? & html5.link.sizes.attr? & html5.href.attr? html5.rdfa.meta.elem = element meta { html5.rdfa.meta.attlist } html5.rdfa.meta.attlist = html5.rdfa.property.attr & html5.rdfa.attrs.no-property & html5.global.common.attrs & html5.global.xml.attrs ### attributes ##### html5.rdfa.attrs &= ( html5.rdfa.about.attr? & html5.rdfa.prefix.attr? & html5.rdfa.property.attr? & html5.rdfa.typeof.attr? & html5.rdfa.vocab.attr? & html5.rdfa.content.attr? & html5.rdfa.datatype.attr? & html5.rdfa.rel.attr? & html5.rdfa.resource.attr? & html5.rdfa.rev.attr? & html5.rdfa.inlist.attr? ) html5.rdfa.attrs.no-property &= ( html5.rdfa.about.attr? & html5.rdfa.prefix.attr? & html5.rdfa.typeof.attr? & html5.rdfa.vocab.attr? & html5.rdfa.content.attr? & html5.rdfa.datatype.attr? & html5.rdfa.rel.attr? & html5.rdfa.resource.attr? & html5.rdfa.rev.attr? & html5.rdfa.inlist.attr? ) html5.rdfa.attrs.no-rel &= ( html5.rdfa.about.attr? & html5.rdfa.prefix.attr? & html5.rdfa.property.attr? & html5.rdfa.typeof.attr? & html5.rdfa.vocab.attr? & html5.rdfa.content.attr? & html5.rdfa.datatype.attr? & html5.rdfa.resource.attr? & html5.rdfa.rev.attr? & html5.rdfa.inlist.attr? ) html5.rdfa.attrs.no-rel-property-resource &= ( html5.rdfa.about.attr? & html5.rdfa.prefix.attr? & html5.rdfa.typeof.attr? & html5.rdfa.vocab.attr? & html5.rdfa.content.attr? & html5.rdfa.datatype.attr? & html5.rdfa.rev.attr? & html5.rdfa.inlist.attr? ) html5.rdfa.attrs.no-content-property &= ( html5.rdfa.about.attr? & html5.rdfa.prefix.attr? & html5.rdfa.typeof.attr? & html5.rdfa.vocab.attr? & html5.rdfa.datatype.attr? & html5.rdfa.rel.attr? & html5.rdfa.resource.attr? & html5.rdfa.rev.attr? & html5.rdfa.inlist.attr? ) ### atomic attributes ############# html5.rdfa.prefix.attr = attribute prefix { ( xsd:string { pattern = "\s*([\i-[:]][\c-[:]]*: [^ ]+)(\s+[\i-[:]][\c-[:]]*: [^ ]+)*\s*" } | string "" ) } html5.rdfa.property.attr = attribute property { ( list { ( datatypes.rdfa.term | datatypes.rdfa.curie | datatype.URI.absolute )+ } | string "" ) } html5.rdfa.resource.attr = attribute resource { ( datatypes.rdfa.safecurie | datatypes.rdfa.curie | datatype.URI ) } html5.rdfa.typeof.attr = attribute typeof { ( list { ( datatypes.rdfa.term | datatypes.rdfa.curie | datatype.URI.absolute )+ } | string "" ) } html5.rdfa.vocab.attr = attribute vocab { ( datatype.URI.absolute | string "" ) } html5.rdfa.about.attr = attribute about { ( datatypes.rdfa.safecurie | datatypes.rdfa.curie | datatype.URI ) } html5.rdfa.content.attr = attribute content { string } html5.rdfa.datatype.attr = attribute datatype { ( datatypes.rdfa.term | datatypes.rdfa.curie | datatype.URI.absolute | string "" ) } html5.rdfa.rel.attr = attribute rel { ( list { ( datatypes.rdfa.term | datatypes.rdfa.curie | datatype.URI.absolute )+ } | string "" ) } html5.rdfa.rev.attr = attribute rev { ( list { ( datatypes.rdfa.term | datatypes.rdfa.curie | datatype.URI.absolute )+ } | string "" ) } html5.rdfa.inlist.attr = attribute inlist { string } ### datatypes ########### datatypes.rdfa.safecurie = xsd:string { pattern = "\[(([\i-[:]][\c-[:]]*)?:?)[^\s]*\]" minLength = "2" } datatypes.rdfa.curie = xsd:string { pattern = "(([\i-[:]][\c-[:]]*)?:)[^\s]*" minLength = "1" } datatypes.rdfa.term = xsd:string { pattern = "[\i-[:]][/\c-[:]]*" } epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/html5/html5-attrib-30.rnc0000644000175000017500000000424113017276730031017 0ustar eugeneeugene html5.global.attrs &= html5.global.common.attrs & html5.global.xml.attrs html5.i18n.attrs = html5.xml.lang.attr? & html5.lang.attr? & html5.dir.attr? html5.global.xml.attrs &= html5.xml.lang.attr? & html5.xml.base.attr? & html5.xml.space.attr? html5.global.common.attrs &= html5.lang.attr? & html5.id.attr? & html5.title.attr? & html5.dir.attr? & html5.class.attr? html5.lang.attr = attribute lang { datatype.languagecode } html5.xml.lang.attr = attribute xml:lang { datatype.languagecode } html5.dir.attr = attribute dir { 'ltr' | 'rtl' | 'auto' } html5.id.attr = attribute id { datatype.html5.token } html5.title.attr = attribute title { string } html5.class.attr = attribute class { datatype.html5.space.separated.tokens } html5.xml.base.attr = attribute xml:base { datatype.LEIRI } html5.xml.space.attr = attribute xml:space { 'preserve' | 'default' } html5.href.attr = attribute href { datatype.html5.URL.spaces } html5.hreflang.attr = attribute hreflang { datatype.languagecode } html5.target.attr = attribute target { datatype.html5.browsing.context.name.or.keyword } html5.rel.attr = attribute rel { datatype.html5.space.separated.tokens } html5.media.attr = attribute media { datatype.html5.media.query } html5.type.mime.attr = attribute type { datatype.mimetype } html5.type.mime.nocharset.attr = attribute type { datatype.mimetype.nocharset } html5.charset.attr = attribute charset { datatype.character.encoding } html5.src.attr = attribute src { datatype.html5.URL.spaces } html5.usemap.attr = attribute usemap {datatype.html5.name.reference} html5.cite.attr = attribute cite { datatype.html5.URL.spaces } html5.alt.attr = attribute alt { datatype.string } html5.name.context.attr = attribute name { datatype.html5.browsing.context.name } html5.name.id.attr = attribute name { datatype.html5.name } html5.dimension.attrs &= html5.width.attr? & html5.height.attr? html5.width.attr = attribute width { datatype.non-negative.integer } html5.height.attr = attribute height { datatype.non-negative.integer } epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/html5/html5-aria-30.rnc0000644000175000017500000001360613017276730030453 0ustar eugeneeugene html5.global.common.attrs &= aria aria = aria.role.attr? & aria.global & aria.widget.excl & aria.relationship.excl & aria.describedat.attr? aria.role.attr = attribute role { datatype.NMTOKENS } aria.describedat.attr = attribute aria-describedat { datatype.html5.URL.spaces } # Global States and Properties # http://www.w3.org/WAI/PF/aria/states_and_properties#global_states aria.global = aria.prop.atomic? & aria.state.busy? & aria.prop.controls? & aria.prop.describedby? & aria.state.disabled? & aria.prop.dropeffect? & aria.prop.flowto? & aria.state.grabbed? & aria.prop.haspopup? & aria.state.hidden? & aria.state.invalid? & aria.prop.label? & aria.prop.labelledby? & aria.prop.live? & aria.prop.owns? & aria.prop.relevant? # exclusive widget, not in global # http://www.w3.org/WAI/PF/aria/states_and_properties#attrs_widgets aria.widget.excl = aria.prop.autocomplete? & aria.state.checked? & aria.state.expanded? & aria.prop.level? & aria.prop.multiline? & aria.prop.multiselectable? & aria.prop.orientation? & aria.state.pressed? & aria.prop.readonly? & aria.prop.required? & aria.state.selected? & aria.prop.sort? & aria.prop.valuemax? & aria.prop.valuemin? & aria.prop.valuenow? & aria.prop.valuetext? # exclusive relationship, not in global # http://www.w3.org/WAI/PF/aria/states_and_properties#attrs_relationships aria.relationship.excl = aria.prop.activedescendant? & aria.prop.posinset? & aria.prop.setsize? aria.state.busy = attribute aria-busy { 'true' | 'false' } aria.state.checked = attribute aria-checked { 'true' | 'false' | 'mixed' | 'undefined' } aria.state.disabled = attribute aria-disabled { 'true' | 'false' } aria.state.expanded = attribute aria-expanded { 'true' | 'false' | 'undefined' } aria.state.grabbed = attribute aria-grabbed { 'true' | 'false' | 'undefined' } aria.state.hidden = attribute aria-hidden { 'true' | 'false' } aria.state.invalid = attribute aria-invalid { 'true' | 'false' | 'grammar' | 'spelling' } aria.state.pressed = attribute aria-pressed { 'true' | 'false' | 'mixed' | "undefined" } aria.state.selected = attribute aria-selected { 'true' | 'false' | 'undefined' } aria.prop.activedescendant = attribute aria-activedescendant { datatype.IDREF } aria.prop.atomic = attribute aria-atomic { 'true' | 'false' } aria.prop.autocomplete = attribute aria-autocomplete { 'inline' | 'list' | 'both' | 'none' } aria.prop.controls = attribute aria-controls { datatype.IDREFS } aria.prop.describedby = attribute aria-describedby { datatype.IDREFS } aria.prop.dropeffect = attribute aria-dropeffect { token 'none' | token "popup" | token "execute" | list {('copy'), ('execute')? } | list { ('move'), ('execute')?} | list { ('reference'), ('execute')? } | list { ('execute') , ('copy') } | list { ('execute') , ('move')} | list { ('execute' ), ('reference') } } aria.prop.flowto = attribute aria-flowto { datatype.IDREFS } aria.prop.haspopup = attribute aria-haspopup { 'true' | 'false' } aria.prop.label = attribute aria-label { datatype.string } aria.prop.labelledby = attribute aria-labelledby { datatype.IDREFS } aria.prop.level = attribute aria-level { datatype.positive.integer } aria.prop.live = attribute aria-live { 'off' | 'polite' | 'assertive' } aria.prop.multiline = attribute aria-multiline { 'true' | 'false' } aria.prop.multiselectable = attribute aria-multiselectable { 'true' | 'false' } aria.prop.orientation = attribute aria-orientation { 'vertical' | 'horizontal' } aria.prop.owns = attribute aria-owns { datatype.IDREFS } aria.prop.posinset = attribute aria-posinset { datatype.positive.integer } aria.prop.readonly = attribute aria-readonly { 'true' | 'false' } aria.prop.relevant = attribute aria-relevant { token "all" | list { ( 'additions' ), ( 'removals' )? , ( 'text' )? } | list { ( 'additions' ), ( 'text' )?, ( 'removals' )? } | list { ( 'removals' ), ( 'additions' )?, ( 'text' )? } | list { ( 'removals' ), ( 'text' )?, ( 'additions' )? } | list { ( 'text' ), ( 'additions' )?, ( 'removals' )? } | list { ( 'text' ), ( 'removals' )? , ( 'additions' )? } } aria.prop.required = attribute aria-required { 'true' | 'false' } aria.prop.setsize = attribute aria-setsize { datatype.non-negative.integer } aria.prop.sort = attribute aria-sort { 'ascending '| 'descending' | 'none' | 'other' } aria.prop.valuemax = attribute aria-valuemax { datatype.float } aria.prop.valuemin = attribute aria-valuemin { datatype.float } aria.prop.valuenow = attribute aria-valuenow { datatype.float } aria.prop.valuetext = attribute aria-valuetext { datatype.string } aria.roles = aria.widget.roles & aria.structure.roles & aria.landmark.roles aria.widget.roles = 'alert' | 'alertdialog' | 'button' | 'checkbox' | 'dialog' | 'gridcell' | 'link' | 'log' | 'marquee' | 'menuitem' | 'menuitemcheckbox' | 'menuitemradio' | 'option' | 'progressbar' | 'radio' | 'scrollbar' | 'slider' | 'spinbutton' | 'status' | 'tab' | 'tabpanel' | 'textbox' | 'timer' | 'tooltip' | 'treeitem' | 'combobox' | 'grid' | 'listbox' | 'menu' | 'menubar' | 'radiogroup' | 'tablist' | 'tree' | 'treegrid' aria.structure.roles = 'article' | 'columnheader' | 'definition' | 'directory' | 'document' | 'group' | 'heading' | 'img' | 'list' | 'listitem' | 'math' | 'note' | 'presentation' | 'region' | 'row' | 'rowheader' | 'separator' | 'toolbar' aria.landmark.roles = 'application' | 'banner' | 'complementary' | 'contentinfo' | 'form' | 'main' | 'navigation' | 'search' aria.abstract.roles = 'command' | 'composite' | 'input' | 'landmark' | 'range' | 'roletype' | 'section' | 'sectionhead' | 'select' | 'structure' | 'widget' | 'window' epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/html5/html5-forms-30.rnc0000644000175000017500000005624413017276730030672 0ustar eugeneeugene html5.flow.class |= html5.forms.flow.class html5.phrasing.class |= html5.forms.phrasing.class html5.forms.flow.class |= html5.form | html5.fieldset html5.forms.phrasing.class |= html5.meter | html5.input.class | html5.textarea | html5.label | html5.button.class | html5.select | html5.output | html5.datalist | html5.keygen html5.input.class |= html5.input.text | html5.input.password | html5.input.checkbox | html5.input.radio | html5.input.button | html5.input.submit | html5.input.reset | html5.input.file | html5.input.hidden | html5.input.image | html5.input.datetime | html5.input.datetime-local | html5.input.date | html5.input.month | html5.input.time | html5.input.week | html5.input.number | html5.input.range | html5.input.email | html5.input.url | html5.input.search | html5.input.tel | html5.input.color html5.button.class |= html5.button.submit | html5.button.reset | html5.button.button html5.form = element form { html5.form.attlist & html5.form.content } html5.form.attlist &= html5.global.attrs & html5.form.action.attr? & html5.form.method.attr? & html5.form.enctype.attr? & html5.forms.name.attr? & html5.form.accept-charset.attr? & html5.form.novalidate.attr? & html5.form.target.attr? & html5.form.autocomplete.attr? html5.form.action.attr = attribute action { datatype.html5.URL.spaces } html5.form.method.attr = attribute method { html5.form.method.attr.value } html5.form.method.attr.value = ( 'get' | 'post' ) html5.form.enctype.attr = attribute enctype { html5.form.enctype.attr.value } html5.form.enctype.attr.value = ( 'application/x-www-form-urlencoded' | 'multipart/form-data' | 'text/plain' ) html5.form.accept-charset.attr = attribute accept-charset { datatype.html5.forms.charsetlist} html5.form.novalidate.attr = attribute novalidate { 'novalidate' | '' } html5.form.target.attr = attribute target { datatype.html5.browsing.context.name.or.keyword } html5.form.autocomplete.attr = attribute autocomplete { 'on' | 'off' } html5.form.content = html5.flow.model html5.input.text = element input { html5.input.text.attlist } html5.input.text.attlist = html5.global.attrs & html5.forms.common.attrs & attribute type { 'text' }? & html5.forms.maxlength.attr? & html5.forms.readonly.attr? & html5.forms.size.attr? & html5.input.text.value.attr? & html5.input.autocomplete.attr? & html5.forms.autofocus.attr? & html5.input.list.attr? & html5.forms.pattern.attr? & html5.forms.required.attr? & html5.forms.placeholder.attr? & html5.input.common.attrs html5.input.text.value.attr = attribute value { datatype.html5.forms.string.nolinebreaks } html5.input.password = element input { html5.input.password.attlist } html5.input.password.attlist = html5.global.attrs & html5.forms.common.attrs & attribute type { 'password' } & html5.forms.maxlength.attr? & html5.forms.readonly.attr? & html5.forms.size.attr? & html5.input.password.value.attr? & html5.input.autocomplete.attr? & html5.forms.autofocus.attr? & html5.forms.pattern.attr? & html5.forms.required.attr? & html5.forms.placeholder.attr? & html5.input.common.attrs html5.input.password.value.attr = attribute value { datatype.html5.forms.string.nolinebreaks } html5.input.checkbox = element input { html5.input.checkbox.attlist } html5.input.checkbox.attlist = html5.global.attrs & html5.forms.common.attrs & attribute type { 'checkbox' } & html5.input.checked.attr? & html5.input.checkbox.value.attr? & html5.forms.autofocus.attr? & html5.forms.required.attr? & html5.input.common.attrs html5.input.checkbox.value.attr = attribute value { datatype.string } html5.input.radio = element input { html5.input.radio.attlist } html5.input.radio.attlist = html5.global.attrs & html5.forms.common.attrs & attribute type { 'radio' } & html5.input.checked.attr? & html5.input.radio.value.attr? & html5.forms.autofocus.attr? & html5.forms.required.attr? & html5.input.common.attrs html5.input.radio.value.attr = attribute value { datatype.string } html5.input.button = element input { html5.input.button.attlist } html5.input.button.attlist = html5.global.attrs & html5.forms.common.attrs & attribute type { 'button' } & html5.input.button.value.attr? & html5.forms.autofocus.attr? & html5.input.common.attrs html5.input.button.value.attr = attribute value { datatype.string } html5.input.submit = element input { html5.input.submit.attlist } html5.input.submit.attlist = html5.global.attrs & html5.forms.common.attrs & attribute type { 'submit' } & html5.input.submit.value.attr? & html5.forms.formaction.attr? & html5.forms.autofocus.attr? & html5.forms.formenctype.attr? & html5.forms.formmethod.attr? & html5.forms.formtarget.attr? & html5.forms.formnovalidate.attr? & html5.input.common.attrs html5.input.submit.value.attr = attribute value { datatype.string } html5.input.reset = element input { html5.input.reset.attlist } html5.input.reset.attlist = html5.global.attrs & html5.forms.common.attrs & attribute type { 'reset' } & html5.input.reset.value.attr? & html5.forms.autofocus.attr? & html5.input.common.attrs html5.input.reset.value.attr = attribute value { datatype.string } html5.input.file = element input { html5.input.file.attlist } html5.input.file.attlist = html5.global.attrs & html5.forms.common.attrs & attribute type { 'file'} & html5.input.file.accept.attr? & html5.forms.autofocus.attr? & html5.forms.required.attr? & html5.input.multiple.attr? & html5.input.common.attrs html5.input.file.accept.attr = attribute accept { datatype.html5.forms.mimetypelist } html5.input.hidden = element input { html5.input.hidden.attlist } html5.input.hidden.attlist = html5.global.attrs & html5.forms.common.attrs & attribute type { 'hidden' } & html5.input.hidden.value.attr? & html5.input.common.attrs html5.input.hidden.value.attr = attribute value { datatype.string } html5.input.image = element input { html5.input.image.attlist } html5.input.image.attlist = html5.global.attrs & html5.forms.common.attrs & attribute type { 'image' } & html5.alt.attr & html5.src.attr & html5.forms.formaction.attr? & html5.forms.autofocus.attr? & html5.forms.formenctype.attr? & html5.forms.formmethod.attr? & html5.forms.formtarget.attr? & html5.forms.formnovalidate.attr? & html5.dimension.attrs? & html5.input.common.attrs html5.input.datetime = element input { html5.input.datetime.attlist } html5.input.datetime.attlist = html5.global.attrs & html5.forms.common.attrs & attribute type { 'datetime'} & html5.input.autocomplete.attr? & html5.forms.autofocus.attr? & html5.input.list.attr? & html5.input.datetime.min.attr? & html5.input.datetime.max.attr? & html5.input.step.float.attr? & html5.forms.readonly.attr? & html5.forms.required.attr? & html5.input.datetime.value.attr? & html5.input.common.attrs html5.input.datetime.min.attr = attribute min { datatype.html5.datetime } html5.input.datetime.max.attr = attribute max { datatype.html5.datetime } html5.input.datetime.value.attr = attribute value { datatype.html5.datetime } html5.input.datetime-local = element input { html5.input.datetime-local.attlist } html5.input.datetime-local.attlist = html5.global.attrs & html5.forms.common.attrs & attribute type { 'datetime-local' } & html5.input.autocomplete.attr? & html5.forms.autofocus.attr? & html5.input.list.attr? & html5.input.datetime-local.min.attr? & html5.input.datetime-local.max.attr? & html5.input.step.float.attr? & html5.forms.readonly.attr? & html5.forms.required.attr? & html5.input.datetime-local.value.attr? & html5.input.common.attrs html5.input.datetime-local.min.attr = attribute min { datatype.html5.datetime.local } html5.input.datetime-local.max.attr = attribute max { datatype.html5.datetime.local } html5.input.datetime-local.value.attr = attribute value { datatype.html5.datetime.local } html5.input.date = element input { html5.input.date.attlist } html5.input.date.attlist = html5.global.attrs & html5.forms.common.attrs & attribute type { 'date' } & html5.input.autocomplete.attr? & html5.forms.autofocus.attr? & html5.input.list.attr? & html5.input.date.min.attr? & html5.input.date.max.attr? & html5.input.step.integer.attr? & html5.forms.readonly.attr? & html5.forms.required.attr? & html5.input.date.value.attr? & html5.input.common.attrs html5.input.date.min.attr = attribute min { datatype.html5.date } html5.input.date.max.attr = attribute max { datatype.html5.date } html5.input.date.value.attr = attribute value { datatype.html5.date } html5.input.month = element input { html5.input.month.attlist } html5.input.month.attlist = html5.global.attrs & html5.forms.common.attrs & attribute type { 'month' } & html5.input.autocomplete.attr? & html5.forms.autofocus.attr? & html5.input.list.attr? & html5.input.month.min.attr? & html5.input.month.max.attr? & html5.input.step.integer.attr? & html5.forms.readonly.attr? & html5.forms.required.attr? & html5.input.month.value.attr? & html5.input.common.attrs html5.input.month.min.attr = attribute min { datatype.html5.month } html5.input.month.max.attr = attribute max { datatype.html5.month } html5.input.month.value.attr = attribute value { datatype.html5.month } html5.input.time = element input { html5.input.time.attlist } html5.input.time.attlist = html5.global.attrs & html5.forms.common.attrs & attribute type { 'time' } & html5.input.autocomplete.attr? & html5.forms.autofocus.attr? & html5.input.list.attr? & html5.input.time.min.attr? & html5.input.time.max.attr? & html5.input.step.float.attr? & html5.forms.readonly.attr? & html5.forms.required.attr? & html5.input.time.value.attr? & html5.input.common.attrs html5.input.time.min.attr = attribute min { datatype.html5.time } html5.input.time.max.attr = attribute max { datatype.html5.time } html5.input.time.value.attr = attribute value { datatype.html5.time } html5.input.week = element input { html5.input.week.attlist } html5.input.week.attlist = html5.global.attrs & html5.forms.common.attrs & attribute type { 'week' } & html5.input.autocomplete.attr? & html5.forms.autofocus.attr? & html5.input.list.attr? & html5.input.week.min.attr? & html5.input.week.max.attr? & html5.input.step.integer.attr? & html5.forms.readonly.attr? & html5.forms.required.attr? & html5.input.week.value.attr? & html5.input.common.attrs html5.input.week.min.attr = attribute min { datatype.html5.week } html5.input.week.max.attr = attribute max { datatype.html5.week } html5.input.week.value.attr = attribute value { datatype.html5.week } html5.input.number = element input { input.number.attlist } input.number.attlist = html5.global.attrs & html5.forms.common.attrs & attribute type { 'number' } & html5.input.autocomplete.attr? & html5.forms.autofocus.attr? & html5.input.list.attr? & html5.input.number.min.attr? & html5.input.number.max.attr? & html5.input.step.float.attr? & html5.forms.readonly.attr? & html5.forms.required.attr? & html5.input.number.value.attr? & html5.input.common.attrs html5.input.number.min.attr = attribute min { datatype.float } html5.input.number.max.attr = attribute max { datatype.float } html5.input.number.value.attr = attribute value { datatype.float } html5.input.range = element input { html5.input.range.attlist } html5.input.range.attlist = html5.global.attrs & html5.forms.common.attrs & attribute type { 'range' } & html5.input.autocomplete.attr? & html5.forms.autofocus.attr? & html5.input.list.attr? & html5.input.range.min.attr? & html5.input.range.max.attr? & html5.input.step.float.attr? & html5.input.range.value.attr? & html5.input.common.attrs html5.input.range.min.attr = attribute min { datatype.float } html5.input.range.max.attr = attribute max { datatype.float } html5.input.range.value.attr = attribute value { datatype.float } html5.input.email = element input { html5.input.email.attlist } html5.input.email.attlist = html5.global.attrs & html5.forms.common.attrs & attribute type { 'email' } & html5.input.autocomplete.attr? & html5.forms.autofocus.attr? & html5.input.list.attr? & html5.forms.maxlength.attr? & html5.forms.pattern.attr? & html5.forms.readonly.attr? & html5.forms.required.attr? & html5.forms.size.attr? & html5.forms.placeholder.attr? & ((html5.input.multiple.attr & html5.input.email.value.multiple.attr?) | html5.input.email.value.single.attr? )? & html5.input.common.attrs html5.input.email.value.single.attr = attribute value { datatype.html5.emailaddress } html5.input.email.value.multiple.attr = attribute value { datatype.html5.emailaddresslist } html5.input.url = element input { html5.input.url.attlist } html5.input.url.attlist = html5.global.attrs & html5.forms.common.attrs & attribute type { 'url' } & html5.input.autocomplete.attr? & html5.forms.autofocus.attr? & html5.input.list.attr? & html5.forms.maxlength.attr? & html5.forms.pattern.attr? & html5.forms.readonly.attr? & html5.forms.required.attr? & html5.forms.size.attr? & html5.forms.placeholder.attr? & html5.input.url.value.attr? & html5.input.common.attrs html5.input.url.value.attr = attribute value { '' | datatype.URI.absolute } html5.input.search = element input { html5.input.search.attlist } html5.input.search.attlist = html5.global.attrs & html5.forms.common.attrs & attribute type { 'search' } & html5.input.autocomplete.attr? & html5.forms.autofocus.attr? & html5.input.list.attr? & html5.forms.maxlength.attr? & html5.forms.pattern.attr? & html5.forms.readonly.attr? & html5.forms.required.attr? & html5.forms.size.attr? & html5.forms.placeholder.attr? & html5.input.search.value.attr? & html5.input.common.attrs html5.input.search.value.attr = attribute value { datatype.html5.forms.string.nolinebreaks } html5.input.tel = element input { html5.input.tel.attlist } html5.input.tel.attlist = html5.global.attrs & html5.forms.common.attrs & attribute type { 'tel' } & html5.input.autocomplete.attr? & html5.forms.autofocus.attr? & html5.input.list.attr? & html5.forms.maxlength.attr? & html5.forms.pattern.attr? & html5.forms.readonly.attr? & html5.forms.required.attr? & html5.forms.size.attr? & html5.forms.placeholder.attr? & html5.input.tel.value.attr? & html5.input.common.attrs html5.input.tel.value.attr = attribute value { datatype.string } html5.input.color = element input { html5.input.color.attlist } html5.input.color.attlist = html5.global.attrs & html5.forms.common.attrs & attribute type { 'color' } & html5.input.autocomplete.attr? & html5.forms.autofocus.attr? & html5.input.list.attr? & html5.input.color.value.attr? & html5.input.common.attrs html5.input.color.value.attr = attribute value { datatype.html5.color } html5.textarea = element textarea { html5.textarea.attlist & html5.textarea.content } html5.textarea.attlist = html5.global.attrs & html5.forms.common.attrs & html5.forms.readonly.attr? & html5.forms.maxlength.attr? & html5.forms.autofocus.attr? & html5.forms.required.attr? & html5.forms.placeholder.attr? & html5.textarea.rows.attr? & ((html5.textarea.wrap.hard.attr? & html5.textarea.cols.attr)| (html5.textarea.wrap.soft.attr? & html5.textarea.cols.attr?)) & html5.forms.dirname.attr? html5.textarea.cols.attr = attribute cols { datatype.positive.integer } html5.textarea.rows.attr = attribute rows { datatype.positive.integer } html5.textarea.wrap.hard.attr = attribute wrap { 'hard' } html5.textarea.wrap.soft.attr = attribute wrap { 'soft' } html5.textarea.content = datatype.text html5.option = element option { html5.option.attlist & html5.option.content } html5.option.attlist = html5.global.attrs & html5.forms.disabled.attr? & html5.option.selected.attr? & html5.option.label.attr? & html5.option.value.attr? html5.option.selected.attr = attribute selected { 'selected' | '' } html5.option.label.attr = attribute label { datatype.string } html5.option.value.attr = attribute value { datatype.string } html5.option.content = datatype.text html5.optgroup = element optgroup { html5.optgroup.attlist & html5.optgroup.content } html5.optgroup.attlist = html5.global.attrs & html5.optgroup.label.attr & html5.forms.disabled.attr? html5.optgroup.label.attr = attribute label { datatype.string } html5.optgroup.content = html5.option* html5.select = element select { html5.select.attlist & html5.select.content } html5.select.attlist = html5.global.attrs & html5.forms.common.attrs & html5.select.size.attr? & html5.select.multiple.attr? & html5.forms.autofocus.attr? & html5.forms.required.attr? html5.select.size.attr = attribute size { datatype.positive.integer } html5.select.multiple.attr = attribute multiple { 'multiple' | '' } html5.select.content = html5.optgroup* & html5.option* html5.button.submit = element button { html5.button.submit.attlist & html5.button.content } html5.button.submit.attlist = html5.global.attrs & html5.forms.common.attrs & html5.button.submit.type.attr? & html5.button.value.attr? & html5.forms.formaction.attr? & html5.forms.autofocus.attr? & html5.forms.formenctype.attr? & html5.forms.formmethod.attr? & html5.forms.formtarget.attr? & html5.forms.formnovalidate.attr? html5.button.submit.type.attr = attribute type { 'submit' } html5.button.reset = element button { html5.button.reset.attlist & html5.button.content } html5.button.reset.attlist = html5.global.attrs & html5.forms.common.attrs & html5.button.reset.type.attr & html5.button.value.attr? & html5.forms.autofocus.attr? html5.button.reset.type.attr = attribute type { 'reset' } html5.button.button = element button { html5.button.button.attlist & html5.button.content } html5.button.button.attlist = html5.global.attrs & html5.forms.common.attrs & html5.button.button.type.attr & html5.button.value.attr? & html5.forms.autofocus.attr? html5.button.button.type.attr = attribute type { 'button' } html5.button.value.attr = attribute value { datatype.string } html5.button.content = html5.phrasing.model html5.fieldset = element fieldset { html5.fieldset.attlist & html5.fieldset.content } html5.fieldset.attlist = html5.global.attrs & html5.forms.common.attrs html5.fieldset.content = html5.legend?, html5.flow.model html5.legend = element legend { html5.legend.attlist & html5.legend.content } html5.legend.attlist = html5.global.attrs html5.legend.content = html5.phrasing.model html5.label = element label { html5.label.attlist & html5.label.content } html5.label.attlist = html5.global.attrs & html5.label.for.attr? & html5.forms.form.attr? html5.label.for.attr = attribute for { datatype.IDREF } html5.label.content = html5.phrasing.model html5.meter = element meter { html5.meter.attlist & html5.meter.content } html5.meter.attlist = html5.global.attrs & html5.meter.value.attr & html5.meter.min.attr? & html5.meter.low.attr? & html5.meter.high.attr? & html5.meter.max.attr? & html5.meter.optimum.attr? html5.meter.value.attr = attribute value { datatype.float } html5.meter.min.attr = attribute min { datatype.float } html5.meter.low.attr = attribute low { datatype.float } html5.meter.high.attr = attribute high { datatype.float } html5.meter.max.attr = attribute max { datatype.float } html5.meter.optimum.attr = attribute optimum { datatype.float } html5.meter.content = html5.phrasing.model html5.output = element output { html5.output.attlist & html5.output.content } html5.output.attlist = html5.global.attrs & html5.forms.name.attr? & html5.forms.form.attr? & html5.output.for.attr? html5.output.for.attr = attribute for { datatype.IDREFS } html5.output.content = html5.phrasing.model html5.datalist = element datalist { html5.datalist.attlist & html5.datalist.content } html5.datalist.attlist = html5.global.attrs html5.datalist.content = html5.option* & html5.phrasing.model html5.keygen = element keygen { html5.keygen.attlist } html5.keygen.attlist = html5.global.attrs & html5.keygen.challenge.attr? & html5.keygen.keytype.attr? & html5.forms.autofocus.attr? & html5.forms.common.attrs? html5.keygen.challenge.attr = attribute challenge { datatype.string } html5.keygen.keytype.attr = attribute keytype { 'rsa' } html5.input.common.attrs = html5.forms.dirname.attr? html5.input.checked.attr = attribute checked { 'checked' | '' } html5.input.autocomplete.attr = attribute autocomplete { 'on' | 'off'} html5.input.list.attr = attribute list { datatype.IDREF } html5.input.step.float.attr = attribute step { 'any' | datatype.float.positive } html5.input.step.integer.attr = attribute step { 'any' | datatype.positive.integer } html5.input.multiple.attr = attribute multiple { 'multiple' | '' } html5.forms.common.attrs = html5.forms.name.attr? & html5.forms.disabled.attr? & html5.forms.form.attr? html5.forms.name.attr = attribute name { datatype.string } html5.forms.disabled.attr = attribute disabled { 'disabled' | '' } html5.forms.form.attr = attribute form { datatype.IDREF } html5.forms.readonly.attr = attribute readonly { 'readonly' | '' } html5.forms.maxlength.attr = attribute maxlength { datatype.non-negative.integer } html5.forms.size.attr = attribute size { datatype.positive.integer } html5.forms.formaction.attr = attribute formaction { datatype.html5.URL.spaces } html5.forms.formenctype.attr = attribute formenctype { html5.forms.formenctype.attr.value } html5.forms.formenctype.attr.value = ( 'application/x-www-form-urlencoded' | 'multipart/form-data'| 'text/plain' ) html5.forms.formmethod.attr = attribute formmethod { html5.forms.formmethod.attr.value } html5.forms.formmethod.attr.value = ( 'get'| 'post') html5.forms.formtarget.attr = attribute formtarget { datatype.html5.browsing.context.name.or.keyword } html5.forms.formnovalidate.attr = attribute formnovalidate { 'formnovalidate' | '' } html5.forms.autofocus.attr = attribute autofocus { 'autofocus' | '' } html5.forms.pattern.attr = attribute pattern { datatype.html5.forms.pattern } html5.forms.template.attr = attribute template { datatype.IDREF } html5.forms.required.attr = attribute required { 'required' | '' } html5.forms.placeholder.attr = attribute placeholder { datatype.html5.forms.string.nolinebreaks } html5.forms.dirname.attr = attribute dirname { datatype.string } epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/epub-ssml-attrs.rnc0000644000175000017500000000055113017276730030274 0ustar eugeneeugene namespace ssml = "http://www.w3.org/2001/10/synthesis" html5.global.common.attrs &= epub.ssml.ph.attr? & epub.ssml.alphabet.attr? #TODO determine injection in SVG epub.ssml.ph.attr = attribute ssml:ph { datatype.ssml.PhoneticExpression } epub.ssml.alphabet.attr = attribute ssml:alphabet { datatype.ssml.PhoneticAlphabet }epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/epub-type-attr.rnc0000644000175000017500000000024613017276730030115 0ustar eugeneeugene namespace epub = "http://www.idpf.org/2007/ops" html5.global.xml.attrs &= epub.type.attr? epub.type.attr = attribute epub:type { datatype.properties }epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/epub-xhtml-svg11-30.rnc0000644000175000017500000000032513017276730030475 0ustar eugeneeugene# $Id: epub-xhtml-svg11-30.rnc 3024 2011-07-10 08:29:17Z eb2mmrt $ # Contributors: MURATA Makoto and Markus Gylling html5.phrasing.class |= svg html5.flow.class |= svg svg = external "epub-svg11-30.rnc" epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/security/0000755000175000017500000000000013017276730026374 5ustar eugeneeugene././@LongLink0000644000000000000000000000015400000000000011603 Lustar rootrootepubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/security/xmldsig-properties-schema.rncepubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/security/xmldsig-properties-sch0000644000175000017500000000255313017276730032740 0ustar eugeneeugene# xmldsig-properties-schema.rnc (derived from xmldsig-properties-schema.xsd) # # Copyright 2011 W3C (Massachusetts Institute of Technology, # Institut National de Recherche en Informatique et en Automatique, # Keio University). All Rights Reserved. http://www.w3.org/Consortium/Legal/ # # Use and distribution of all schemas in this directory are permitted under the terms # W3C Software Notice and License # http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231 # # This schema allows Profile, Role, Identifier, Created, Expires, # and ReplayProject elements as children of SignatureProperty # elements. default namespace = "http://www.w3.org/2009/xmldsig-properties" ds_SignaturePropertyChild |= dsp_Profile | dsp_Role | dsp_Identifier | dsp_Created | dsp_Expires | dsp_ReplayProtect dsp_Profile = element Profile { dsp_ProfileType } dsp_ProfileType = attribute URI { xsd:anyURI }? dsp_Role = element Role { dsp_RoleType } dsp_RoleType = attribute URI { xsd:anyURI }? dsp_Identifier = element Identifier { xsd:string } dsp_Created = element Created { xsd:dateTime } dsp_Expires = element Expires { xsd:dateTime } dsp_ReplayProtect = element ReplayProtect { dsp_ReplayProtectType } dsp_ReplayProtectType = element timestamp { xsd:dateTime }, element nonce { dsp_NonceValueType } dsp_NonceValueType = attribute EncodingType { xsd:anyURI }?, xsd:string epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/security/exc-c14n.rnc0000644000175000017500000000271613017276730030430 0ustar eugeneeugene# exc-c14n.rnc (derived from exc-c14n.xsd) # # Copyright 2011 W3C (Massachusetts Institute of Technology, # Institut National de Recherche en Informatique et en Automatique, # Keio University). All Rights Reserved. http://www.w3.org/Consortium/Legal/ # # Use and distribution of all schemas in this directory are permitted under the terms # W3C Software Notice and License # http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231 # # This RELAX NG schema allows the use of two algorithms, namely # # http://www.w3.org/2001/10/xml-exc-c14n# and # http://www.w3.org/2001/10/xml-exc-c14n#WithComments, # # in ds_CanonicalizationMethodType, which specifies permissible # contents of Transform or CanonicalizationMethod elements. # # The definition of ds_CanonicalizationMethodType in this schema is # combined with the other definitions of ds_CanonicalizationMethodType # by the choice operator. default namespace = "http://www.w3.org/2001/10/xml-exc-c14n#" ds_CanonicalizationMethodType |= attribute Algorithm { xsd:anyURI "http://www.w3.org/2001/10/xml-exc-c14n#" | xsd:anyURI "http://www.w3.org/2001/10/xml-exc-c14n#WithComments" }, ec_InclusiveNamespaces? ec_InclusiveNamespaces = element InclusiveNamespaces { attribute PrefixList { xsd:NMTOKENS } } # List of known algorithms ds_CanonicalizationAlgorithms |= xsd:anyURI "http://www.w3.org/2001/10/xml-exc-c14n#" | xsd:anyURI "http://www.w3.org/2001/10/xml-exc-c14n#WithComments" ././@LongLink0000644000000000000000000000015500000000000011604 Lustar rootrootepubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/security/xmlsec-ghc-allowAnyForeign.rncepubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/security/xmlsec-ghc-allowAnyFor0000644000175000017500000000154313017276730032607 0ustar eugeneeugene# xmlsec-ghc-allowAnyForeign.rnc # # Copyright 2011 W3C (Massachusetts Institute of Technology, # Institut National de Recherche en Informatique et en Automatique, # Keio University). All Rights Reserved. http://www.w3.org/Consortium/Legal/ # # Use and distribution of all schemas in this directory are permitted under the terms # W3C Software Notice and License # http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231 # # This schema mimicks in # xmlsec-ghc-schema.xsd, thus allowing any parameter # and any value for the attribute "Algorithm". # # Schema authors might want to create a dedicated schema # for a collection of particular algorithms rather than # using this schema. gh_KeyEncapsulationMethodParams |= attribute Algorithm {xsd:anyURI - gh_KeyEncapsulationAlgorithms }, security_anyElement* epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/security/xenc-schema-11.rnc0000644000175000017500000000761713017276730031525 0ustar eugeneeugene# xenc-schema-11.rnc (derived from xenc-schema.xsd) # # Copyright 2011 W3C (Massachusetts Institute of Technology, # Institut National de Recherche en Informatique et en Automatique, # Keio University). All Rights Reserved. http://www.w3.org/Consortium/Legal/ # # Use and distribution of all schemas in this directory are permitted under the terms # W3C Software Notice and License # http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231 # # This schema complements "xenc-schema.rnc" by introducing # elements specific to 1.1. Note that the definitions of # xenc_EncryptionMethodOtherParams and # xenc_AgreementMethodParams have been extended so that # elements specific to 1.1 are allowed. default namespace = "http://www.w3.org/2009/xmlenc11#" namespace ds = "http://www.w3.org/2000/09/xmldsig#" namespace xenc = "http://www.w3.org/2001/04/xmlenc#" namespace xenc11 = "http://www.w3.org/2009/xmlenc11#" xenc11_ConcatKDFParams = element ConcatKDFParams { xenc11_ConcatKDFParamsType } xenc11_ConcatKDFParamsType = attribute AlgorithmID { xsd:hexBinary }?, attribute PartyUInfo { xsd:hexBinary }?, attribute PartyVInfo { xsd:hexBinary }?, attribute SuppPubInfo { xsd:hexBinary }?, attribute SuppPrivInfo { xsd:hexBinary }?, ds_DigestMethod xenc11_DerivedKey = element DerivedKey { xenc11_DerivedKeyType } xenc11_DerivedKeyType = attribute Recipient { xsd:string }?, attribute Id { xenc11_IdType }?, attribute Type { xsd:anyURI }?, xenc11_KeyDerivationMethod?, xenc_ReferenceList?, element DerivedKeyName { xsd:string }?, element MasterKeyName { xsd:string }? xenc11_KeyDerivationMethod = element KeyDerivationMethod { xenc11_KeyDerivationMethodType } xenc11_KeyDerivationMethodType = (attribute Algorithm { xsd:anyURI "http://www.w3.org/2009/xmlenc11#ConcatKDF" }, xenc11_ConcatKDFParams) | (attribute Algorithm { xsd:anyURI "http://www.w3.org/2009/xmlenc11#pbkdf2" }, xenc11_PBKDF2-params) xenc11_PBKDF2-params = element PBKDF2-params { xenc11_PBKDF2ParameterType } xenc11_AlgorithmIdentifierType = attribute Algorithm { xsd:anyURI }, element Parameters { security_anyAttribute*, mixed { security_anyElement* } }? xenc11_PRFAlgorithmIdentifierType = # Restricts xenc11:AlgorithmIdentifierType attribute Algorithm { xsd:anyURI } xenc11_PBKDF2ParameterType = element Salt { element Specified { xsd:base64Binary } | element OtherSource { xenc11_AlgorithmIdentifierType } }, element IterationCount { xsd:positiveInteger }, element KeyLength { xsd:positiveInteger }, element PRF { xenc11_PRFAlgorithmIdentifierType } xenc11_IdType = xsd:NCName # xsd:ID does not work xenc_EncryptionMethodOtherParams |= attribute Algorithm { # Block Encryption xsd:anyURI "http://www.w3.org/2009/xmlenc11#aes128-gcm" | xsd:anyURI "http://www.w3.org/2009/xmlenc11#aes256-gcm" # Symmetric Key Wrap | xsd:anyURI "http://www.w3.org/2009/xmlenc11#kw-aes-128-pad" | xsd:anyURI "http://www.w3.org/2009/xmlenc11#kw-aes-192-pad" | xsd:anyURI "http://www.w3.org/2009/xmlenc11#kw-aes-256-pad" } xenc_AgreementMethodParams |= attribute Algorithm { xsd:anyURI "http://www.w3.org/2009/xmlenc11#dh-es" } | attribute Algorithm { xsd:anyURI "http://www.w3.org/2009/xmlenc11#ECDH-ES" } # List of known algorithms xenc_EncryptionAlgorithms |= # Block Encryption xsd:anyURI "http://www.w3.org/2009/xmlenc11#aes128-gcm" | xsd:anyURI "http://www.w3.org/2009/xmlenc11#aes256-gcm" # Symmetric Key Wrap | xsd:anyURI "http://www.w3.org/2009/xmlenc11#kw-aes-128-pad" | xsd:anyURI "http://www.w3.org/2009/xmlenc11#kw-aes-192-pad" | xsd:anyURI "http://www.w3.org/2009/xmlenc11#kw-aes-256-pad" xenc_KeyAgreementAlgorithms |= xsd:anyURI "http://www.w3.org/2009/xmlenc11#dh-es" | xsd:anyURI "http://www.w3.org/2009/xmlenc11#ECDH-ES" xenc11_KeyDerivationAlgorithms = xsd:anyURI "http://www.w3.org/2009/xmlenc11#ConcatKDF" | xsd:anyURI "http://www.w3.org/2009/xmlenc11#pbkdf2" epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/security/Strict-Encryption.rnc0000644000175000017500000000203113017276730032474 0ustar eugeneeugene# Strict-Encryption.rnc # # Copyright 2011 W3C (Massachusetts Institute of Technology, # Institut National de Recherche en Informatique et en Automatique, # Keio University). All Rights Reserved. http://www.w3.org/Consortium/Legal/ # # Use and distribution of all schemas in this directory are permitted under the terms # W3C Software Notice and License # http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231 namespace ds = "http://www.w3.org/2000/09/xmldsig#" namespace xenc = "http://www.w3.org/2001/04/xmlenc#" start = anyForeignElementOrEncrypted anyForeignElementOrEncrypted = element * - xenc:* { mixed { security_anyAttribute*, anyForeignElementOrEncrypted* } } | xenc_EncryptedData | xenc_EncryptedKey ds_anyForeignElement = element * - (ds:* | xenc:*) { mixed { security_anyAttribute*, security_anyElement* } } xenc_anyForeignElement = element * - xenc:* { mixed { security_anyAttribute*, security_anyElement* } } include "security_any.rnc" include "xmldsig-core-schema.rnc" include "xenc-schema.rnc" epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/security/security_any.rnc0000644000175000017500000000127013017276730031616 0ustar eugeneeugene# security_any.rnc # # Copyright 2011 W3C (Massachusetts Institute of Technology, # Institut National de Recherche en Informatique et en Automatique, # Keio University). All Rights Reserved. http://www.w3.org/Consortium/Legal/ # # Use and distribution of all schemas in this directory are permitted under the terms # W3C Software Notice and License # http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231 # # This RELAX NG schema defines security_anyElement, which allows any element, # and security_anyAttribute, which allows any attribute. security_anyElement = element * { mixed { security_anyAttribute*, security_anyElement* } } security_anyAttribute = attribute * { text }epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/security/Strict-Signature.rnc0000644000175000017500000000146713017276730032317 0ustar eugeneeugene# Strict-Signature.rnc # # Copyright 2011 W3C (Massachusetts Institute of Technology, # Institut National de Recherche en Informatique et en Automatique, # Keio University). All Rights Reserved. http://www.w3.org/Consortium/Legal/ # # Use and distribution of all schemas in this directory are permitted under the terms # W3C Software Notice and License # http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231 namespace ds = "http://www.w3.org/2000/09/xmldsig#" start = anyForeignElementOrSignature anyForeignElementOrSignature = element * - ds:* { mixed { security_anyAttribute*, anyForeignElementOrSignature* } } | ds_Signature ds_anyForeignElement = element * - ds:* { mixed { security_anyAttribute*, security_anyElement* } } include "security_any.rnc" include "xmldsig-core-schema.rnc" ././@LongLink0000644000000000000000000000017700000000000011610 Lustar rootrootepubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/security/Lenient-Signature11-properties-exclusiveC14N.rncepubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/security/Lenient-Signature11-pr0000644000175000017500000000245513017276730032443 0ustar eugeneeugene# Lenient-Signature11-properties-exclusiveC14N.rnc # # Copyright 2011 W3C (Massachusetts Institute of Technology, # Institut National de Recherche en Informatique et en Automatique, # Keio University). All Rights Reserved. http://www.w3.org/Consortium/Legal/ # # Use and distribution of all schemas in this directory are permitted under the terms # W3C Software Notice and License # http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231 namespace ds = "http://www.w3.org/2000/09/xmldsig#" namespace ds11 = "http://www.w3.org/2009/xmldsig11#" namespace dsp = "http://www.w3.org/2009/xmldsig-properties" namespace ec = "http://www.w3.org/2001/10/xml-exc-c14n#" start = anyForeignElementOrSignature anyForeignElementOrSignature = element * - (ds:* | ds11:* | dsp:* | ec:*) { mixed { security_anyAttribute*, anyForeignElementOrSignature* } } | ds_Signature ds_anyForeignElement = element * - ds:* { mixed { security_anyAttribute*, security_anyElement* } } dsig11_anyForeignElement = element * - ds11:* { mixed { security_anyAttribute*, security_anyElement* } } include "security_any.rnc" include "xmldsig-core-schema.rnc" include "xmldsig11-schema.rnc" include "xmldsig-allowAnyForeign.rnc" include "xmldsig11-allowAnyForeign.rnc" include "xmldsig-properties-schema.rnc" include "exc-c14n.rnc"././@LongLink0000644000000000000000000000015400000000000011603 Lustar rootrootepubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/security/xmldsig11-allowAnyForeign.rncepubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/security/xmldsig11-allowAnyFore0000644000175000017500000000132713017276730032533 0ustar eugeneeugene# xmldsig11-allowAnyForeign.rnc # # Copyright 2011 W3C (Massachusetts Institute of Technology, # Institut National de Recherche en Informatique et en Automatique, # Keio University). All Rights Reserved. http://www.w3.org/Consortium/Legal/ # # Use and distribution of all schemas in this directory are permitted under the terms # W3C Software Notice and License # http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231 # # This schema mimicks # in xmldsig11-schema.xsd. # # Schema authors might want to create a dedicated schema # for a collection of particular algorithms rather than # using this schema. dsig11_OtherFieldIDType |= dsig11_anyForeignElement././@LongLink0000644000000000000000000000015100000000000011600 Lustar rootrootepubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/security/xenc11-allowAnyForeign.rncepubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/security/xenc11-allowAnyForeign0000644000175000017500000000137513017276730032522 0ustar eugeneeugene# xenc11-allowAnyForeign.rnc # # Copyright 2011 W3C (Massachusetts Institute of Technology, # Institut National de Recherche en Informatique et en Automatique, # Keio University). All Rights Reserved. http://www.w3.org/Consortium/Legal/ # # Use and distribution of all schemas in this directory are permitted under the terms # W3C Software Notice and License # http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231 # # This schema mimicks in xenc-schema-11.xsd. # # Schema authors might want to create a dedicated schema # for a collection of particular algorithms rather than # using this schema. xenc11_KeyDerivationMethodType |= attribute Algorithm { xsd:anyURI - xenc11_KeyDerivationAlgorithms }, xenc11_anyForeignElement* epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/security/xmldsig11-schema.rnc0000644000175000017500000001347513017276730032161 0ustar eugeneeugene# xmldsig11-schema.rnc # # Copyright 2011 W3C (Massachusetts Institute of Technology, # Institut National de Recherche en Informatique et en Automatique, # Keio University). All Rights Reserved. http://www.w3.org/Consortium/Legal/ # # Use and distribution of all schemas in this directory are permitted under the terms # W3C Software Notice and License # http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231 # # This schema complements "xmldsig-core-schema.rnc" by # introducing elements specific to 1.1. Note that the definition # of ds_KeyValueType, ds_KeyInfoChild, and ds_X509DataChild # in "xmldsig-core-schema.rnc" has been extended so that # elements specific to 1.1 are allowed. default namespace = "http://www.w3.org/2009/xmldsig11#" ds_KeyValueType |= dsig11_ECKeyValue ds_KeyInfoChild |= dsig11_DEREncodedKeyValue | dsig11_KeyInfoReference ds_X509DataChild |= dsig11_OCSPResponse | dsig11_X509Digest ds_CanonicalizationMethodType |= attribute Algorithm { xsd:anyURI "http://www.w3.org/2006/12/xml-c14n11" | xsd:anyURI "http://www.w3.org/2006/12/xml-c14n11#WithComments" } ds_TransformType |= attribute Algorithm { xsd:anyURI "http://www.w3.org/2002/06/xmldsig-filter2" }, external "xmldsig-filter2.rnc" + ds_DigestMethodType |= attribute Algorithm { xsd:anyURI "http://www.w3.org/2001/04/xmlenc#sha256" } | attribute Algorithm { xsd:anyURI "http://www.w3.org/2001/04/xmldsig-more#sha384" } | attribute Algorithm { xsd:anyURI "http://www.w3.org/2001/04/xmlenc#sha512" } ds_SignatureMethodType |= (attribute Algorithm { xsd:anyURI "http://www.w3.org/2001/04/xmldsig-more#hmac-sha256" | xsd:anyURI "http://www.w3.org/2001/04/xmldsig-more#hmac-sha384" | xsd:anyURI "http://www.w3.org/2001/04/xmldsig-more#hmac-sha512" }, element HMACOutputLength { ds_HMACOutputLengthType }?) | attribute Algorithm { xsd:anyURI "http://www.w3.org/2009/xmldsig11#dsa-sha256" } | attribute Algorithm { xsd:anyURI "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" | xsd:anyURI "http://www.w3.org/2001/04/xmldsig-more#rsa-sha384" | xsd:anyURI "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512" } | attribute Algorithm { xsd:anyURI "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha1" | xsd:anyURI "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256" | xsd:anyURI "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha384" | xsd:anyURI "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha512" } dsig11_ECKeyValue = element ECKeyValue { dsig11_ECKeyValueType } dsig11_ECKeyValueType = attribute Id { ds_IdType }?, (element ECParameters { dsig11_ECParametersType } | element NamedCurve { dsig11_NamedCurveType }), element PublicKey { dsig11_ECPointType } dsig11_NamedCurveType = attribute URI { xsd:anyURI } dsig11_ECPointType = ds_CryptoBinary dsig11_ECParametersType = element FieldID { dsig11_FieldIDType }, element Curve { dsig11_CurveType }, element Base { dsig11_ECPointType }, element Order { ds_CryptoBinary }, element CoFactor { xsd:integer }?, element ValidationData { dsig11_ECValidationDataType }? dsig11_FieldIDType = dsig11_Prime | dsig11_TnB | dsig11_PnB | dsig11_GnB | dsig11_OtherFieldIDType dsig11_OtherFieldIDType = notAllowed dsig11_CurveType = element A { ds_CryptoBinary }, element B { ds_CryptoBinary } dsig11_ECValidationDataType = attribute hashAlgorithm { xsd:anyURI }, element seed { ds_CryptoBinary } dsig11_Prime = element Prime { dsig11_PrimeFieldParamsType } dsig11_PrimeFieldParamsType = element P { ds_CryptoBinary } dsig11_GnB = element GnB { dsig11_CharTwoFieldParamsType } dsig11_CharTwoFieldParamsType = element M { xsd:positiveInteger } dsig11_TnB = element TnB { dsig11_TnBFieldParamsType } dsig11_TnBFieldParamsType = dsig11_CharTwoFieldParamsType, element K { xsd:positiveInteger } dsig11_PnB = element PnB { dsig11_PnBFieldParamsType } dsig11_PnBFieldParamsType = dsig11_CharTwoFieldParamsType, element K1 { xsd:positiveInteger }, element K2 { xsd:positiveInteger }, element K3 { xsd:positiveInteger } dsig11_OCSPResponse = element OCSPResponse { xsd:base64Binary } dsig11_DEREncodedKeyValue = element DEREncodedKeyValue { dsig11_DEREncodedKeyValueType } dsig11_DEREncodedKeyValueType = attribute Id { ds_IdType }?, xsd:base64Binary dsig11_KeyInfoReference = element KeyInfoReference { dsig11_KeyInfoReferenceType} dsig11_KeyInfoReferenceType = attribute URI { xsd:anyURI }, attribute Id { ds_IdType }? dsig11_X509Digest = element X509Digest { dsig11_X509DigestType } dsig11_X509DigestType = attribute Algorithm {xsd:anyURI}, xsd:base64Binary # List of known algorithms ds_CanonicalizationAlgorithms |= xsd:anyURI "http://www.w3.org/2006/12/xml-c14n11" | xsd:anyURI "http://www.w3.org/2006/12/xml-c14n11#WithComments" ds_SignatureAlgorithms |= xsd:anyURI "http://www.w3.org/2001/04/xmldsig-more#hmac-sha256" | xsd:anyURI "http://www.w3.org/2001/04/xmldsig-more#hmac-sha384" | xsd:anyURI "http://www.w3.org/2001/04/xmldsig-more#hmac-sha512" | xsd:anyURI "http://www.w3.org/2009/xmldsig11#dsa-sha256" | xsd:anyURI "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" | xsd:anyURI "http://www.w3.org/2001/04/xmldsig-more#rsa-sha384" | xsd:anyURI "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512" | xsd:anyURI "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha1" | xsd:anyURI "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256" | xsd:anyURI "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha384" | xsd:anyURI "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha512" ds_DigestAlgorithms |= xsd:anyURI "http://www.w3.org/2001/04/xmlenc#sha256" | xsd:anyURI "http://www.w3.org/2001/04/xmldsig-more#sha384" | xsd:anyURI "http://www.w3.org/2001/04/xmlenc#sha512" ds_TransformAlgorithms |= xsd:anyURI "http://www.w3.org/2002/06/xmldsig-filter2"././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootepubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/security/xenc-allowAnyForeign.rncepubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/security/xenc-allowAnyForeign.r0000644000175000017500000000161313017276730032613 0ustar eugeneeugene# xenc-allowAnyForeign.rnc # # Copyright 2011 W3C (Massachusetts Institute of Technology, # Institut National de Recherche en Informatique et en Automatique, # Keio University). All Rights Reserved. http://www.w3.org/Consortium/Legal/ # # Use and distribution of all schemas in this directory are permitted under the terms # W3C Software Notice and License # http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231 # # This schema mimicks # in xenc-schema.xsd. # # Schema authors might want to create a dedicated schema # for a collection of particular algorithms rather than # using this schema. xenc_EncryptionMethodOtherParams |= attribute Algorithm { xsd:anyURI - xenc_EncryptionAlgorithms }, xenc_anyForeignElement* xenc_AgreementMethodParams |= attribute Algorithm { xsd:anyURI - xenc_KeyAgreementAlgorithms }, xenc_anyForeignElement* ././@LongLink0000644000000000000000000000014600000000000011604 Lustar rootrootepubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/security/xmldsig-core-schema.rncepubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/security/xmldsig-core-schema.rn0000644000175000017500000002332313017276730032573 0ustar eugeneeugene# xmldsig-core-schema.rnc (derived from xmldsig-core-schema.xsd) # # Copyright 2011 W3C (Massachusetts Institute of Technology, # Institut National de Recherche en Informatique et en Automatique, # Keio University). All Rights Reserved. http://www.w3.org/Consortium/Legal/ # # Use and distribution of all schemas in this directory are permitted under the terms # W3C Software Notice and License # http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231 # # 1. Differences from dsig-core-schema.xsd. # # 1.1 Attribute-value dependent content models # # The content models of CanonicalizationMethod, SignatureMethod, # Transform, and DigestMethod elemenst are dependent on the value # of the attribute Algorithm. # # 1.2 Customization # # The original XSD schema uses xsd:any several times, and it is # not intended to be customized. However, this RELAX NG schema # is intended to be customized always, and provides customization # points rather than wildcards. # # This schema also defines lists of known algorithms. These definitions # are expected to be customized when algorithms are added. # # A customization example is xmldsig-allowAnyForeign.rnc, which # allows anything at any cutomization point. # # 2. Customization points # # 2.1 Union-combination (i.e., |= ) is intended # # (1) Algorithm identifiers and parameters # # Allow the combination of a particular value of @Algorithm # and the parameter elements. See 6.1 in the xmldsig-core recommendation. # # ds_CanonicalizationMethodType # ds_SignatureMethodType # ds_TransformType # ds_DigestMethodType # # Example: # namespace foo = "http://www.example.com/someNewAlgorithm" # ds_CanonicalizationMethodType |= # attribute Algorithm { # xsd:anyURI "http://www.example.com/someNewAlgorithm" }, # element foo:Param1 { text }, # element foo:Param2 { text } # # (2) Other contents # # Allow one element rather than a sequence of elements or empty sequence. # # ds_KeyInfoChild # ds_KeyValueType # ds_X509DataForeignChild # ds_SPKIDataForeignChild # ds_ObjectChild # ds_SignaturePropertyChild # ds_PGPDataForeignChild # # (3) Known algorithms # # ds_CanonicalizationAlgorithms # ds_SignatureAlgorithms # ds_TransformAlgorithms # ds_DigestAlgorithms = # # 2.2 Overriding # # (1) ds_IdType # # This is defined as xsd:NCName. One might want to use xsd:ID # instead, but jing is likely to report an error. This is because # of the compatibility requirement for the ID/IDREF/IDREFS feature, # which is specified in the OASIS committee specification # "RELAX NG DTD Compatibility" (December 2001). # # (2) ds_xslt # # This is defined as any element, but one might want to use the # schema created by James Clark. default namespace = "http://www.w3.org/2000/09/xmldsig#" namespace xsi = "http://www.w3.org/2001/XMLSchema-instance" ds_CryptoBinary = xsd:base64Binary ds_Signature = element Signature { ds_SignatureType & attribute xsi:schemaLocation { text }? } ds_SignatureType = attribute Id { ds_IdType }?, ds_SignedInfo, ds_SignatureValue, ds_KeyInfo?, ds_Object* ds_SignatureValue = element SignatureValue { ds_SignatureValueType } ds_SignatureValueType = xsd:base64Binary, attribute Id { ds_IdType }? ds_SignedInfo = element SignedInfo { ds_SignedInfoType } ds_SignedInfoType = attribute Id { ds_IdType }?, ds_CanonicalizationMethod, ds_SignatureMethod, ds_Reference+ ds_CanonicalizationMethod = element CanonicalizationMethod { mixed { ds_CanonicalizationMethodType } } ds_CanonicalizationMethodType = attribute Algorithm { xsd:anyURI "http://www.w3.org/TR/2001/REC-xml-c14n-20010315" | xsd:anyURI "http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments" } | attribute Algorithm { xsd:anyURI "http://www.w3.org/2006/12/xml-c14n11" | xsd:anyURI "http://www.w3.org/2006/12/xml-c14n11#WithComments" } ds_SignatureMethod = element SignatureMethod { mixed { ds_SignatureMethodType } } ds_SignatureMethodType = (attribute Algorithm { xsd:anyURI "http://www.w3.org/2000/09/xmldsig#hmac-sha1" }, element HMACOutputLength { ds_HMACOutputLengthType }?) | attribute Algorithm { xsd:anyURI "http://www.w3.org/2000/09/xmldsig#dsa-sha1" } | attribute Algorithm { xsd:anyURI "http://www.w3.org/2000/09/xmldsig#rsa-sha1" } ds_Reference = element Reference { ds_ReferenceType } ds_ReferenceType = attribute Id { ds_IdType }?, attribute URI { xsd:anyURI }?, attribute Type { xsd:anyURI }?, ds_Transforms?, ds_DigestMethod, ds_DigestValue ds_Transforms = element Transforms { ds_TransformsType } ds_TransformsType = ds_Transform+ ds_Transform = element Transform { mixed { ds_TransformType } } ds_TransformType = ds_CanonicalizationMethodType | attribute Algorithm { xsd:anyURI "http://www.w3.org/2000/09/xmldsig#base64" } | (attribute Algorithm { xsd:anyURI "http://www.w3.org/TR/1999/REC-xpath-19991116"}, element XPath { xsd:string }) | attribute Algorithm { xsd:anyURI "http://www.w3.org/2000/09/xmldsig#enveloped-signature"} | (attribute Algorithm { xsd:anyURI "http://www.w3.org/TR/1999/REC-xslt-19991116"}, ds_Xslt) ds_Xslt = security_anyElement ds_DigestMethod = element DigestMethod { mixed { ds_DigestMethodType } } ds_DigestMethodType = attribute Algorithm { xsd:anyURI "http://www.w3.org/2000/09/xmldsig#sha1" } ds_DigestValue = element DigestValue { ds_DigestValueType } ds_DigestValueType = xsd:base64Binary ds_KeyInfo = element KeyInfo { mixed { ds_KeyInfoType } } ds_KeyInfoType = attribute Id { ds_IdType }?, ds_KeyInfoChild+ ds_KeyInfoChild = ds_KeyName | ds_KeyValue | ds_RetrievalMethod | ds_X509Data | ds_PGPData | ds_SPKIData | ds_MgmtData ds_KeyName = element KeyName { xsd:string } ds_MgmtData = element MgmtData { xsd:string } ds_KeyValue = element KeyValue { mixed { ds_KeyValueType } } ds_KeyValueType = ds_DSAKeyValue | ds_RSAKeyValue ds_RetrievalMethod = element RetrievalMethod { ds_RetrievalMethodType } ds_RetrievalMethodType = attribute URI { xsd:anyURI }?, attribute Type { xsd:anyURI }?, ds_Transforms? ds_X509Data = element X509Data { (ds_X509DataChild | ds_X509DataForeignChild?)+ } ds_X509DataChild = element X509IssuerSerial { ds_X509IssuerSerialType } | element X509SKI { xsd:base64Binary } | element X509SubjectName { xsd:string } | element X509Certificate { xsd:base64Binary } | element X509CRL { xsd:base64Binary } ds_X509DataForeignChild = notAllowed ds_X509IssuerSerialType = element X509IssuerName { xsd:string }, element X509SerialNumber { xsd:integer } ds_PGPData = element PGPData { ds_PGPDataType } ds_PGPDataType = (element PGPKeyID { xsd:base64Binary }, element PGPKeyPacket { xsd:base64Binary }?, ds_PGPDataForeignChild*) | (element PGPKeyPacket { xsd:base64Binary }, ds_PGPDataForeignChild*) ds_PGPDataForeignChild = notAllowed ds_SPKIData = element SPKIData { SPKIDataType } SPKIDataType = (element SPKISexp { xsd:base64Binary } | ds_SPKIDataForeignChild?)+ ds_SPKIDataForeignChild = notAllowed ds_Object = element Object { mixed { ds_ObjectType } } ds_ObjectType = attribute Id { ds_IdType }?, attribute MimeType { xsd:string }?, attribute Encoding { xsd:anyURI }?, ds_ObjectChild* ds_ObjectChild = ds_anyDsElement ds_Manifest = element Manifest { ds_ManifestType } ds_ManifestType = attribute Id { ds_IdType }?, ds_Reference+ ds_SignatureProperties = element SignatureProperties { ds_SignaturePropertiesType } ds_SignaturePropertiesType = attribute Id { ds_IdType }?, ds_SignatureProperty+ ds_SignatureProperty = element SignatureProperty { mixed { ds_SignaturePropertyType } } ds_SignaturePropertyType = attribute Target { xsd:anyURI }, attribute Id { ds_IdType }?, ds_SignaturePropertyChild* ds_SignaturePropertyChild = notAllowed ds_HMACOutputLengthType = xsd:integer ds_DSAKeyValue = element DSAKeyValue { ds_DSAKeyValueType } ds_DSAKeyValueType = (element P { ds_CryptoBinary }, element Q { ds_CryptoBinary })?, element G { ds_CryptoBinary }?, element Y { ds_CryptoBinary }, element J { ds_CryptoBinary }?, (element Seed { ds_CryptoBinary }, element PgenCounter { ds_CryptoBinary })? ds_RSAKeyValue = element RSAKeyValue { ds_RSAKeyValueType } ds_RSAKeyValueType = element Modulus { ds_CryptoBinary }, element Exponent { ds_CryptoBinary } ds_IdType = xsd:NCName # xsd:ID does not work #Definitions for mimicking xsd:any ds_anyDsElement = ds_Signature | ds_SignatureValue | ds_SignedInfo | ds_CanonicalizationMethod | ds_SignatureMethod | ds_Reference | ds_Transforms | ds_Transform | ds_DigestMethod | ds_DigestValue | ds_KeyInfo | ds_KeyName | ds_MgmtData | ds_KeyValue | ds_RetrievalMethod | ds_X509Data | ds_PGPData | ds_SPKIData | ds_Object | ds_Manifest | ds_SignatureProperties | ds_SignatureProperty | ds_DSAKeyValue | ds_RSAKeyValue # List of known canonicalization algorithms ds_CanonicalizationAlgorithms = xsd:anyURI "http://www.w3.org/TR/2001/REC-xml-c14n-20010315" | xsd:anyURI "http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments" | xsd:anyURI "http://www.w3.org/2006/12/xml-c14n11" | xsd:anyURI "http://www.w3.org/2006/12/xml-c14n11#WithComments" # List of known signature algorithms ds_SignatureAlgorithms = xsd:anyURI "http://www.w3.org/2000/09/xmldsig#hmac-sha1" | xsd:anyURI "http://www.w3.org/2000/09/xmldsig#dsa-sha1" | xsd:anyURI "http://www.w3.org/2000/09/xmldsig#rsa-sha1" # List of known transformation-but-non-canonicalization algorithms ds_TransformAlgorithms = xsd:anyURI "http://www.w3.org/2000/09/xmldsig#base64" | xsd:anyURI "http://www.w3.org/TR/1999/REC-xpath-19991116" | xsd:anyURI "http://www.w3.org/2000/09/xmldsig#enveloped-signature" | xsd:anyURI "http://www.w3.org/TR/1999/REC-xslt-19991116" # List of known digest algorithms ds_DigestAlgorithms = xsd:anyURI "http://www.w3.org/2000/09/xmldsig#sha1" ././@LongLink0000644000000000000000000000014600000000000011604 Lustar rootrootepubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/security/Lenient-Signature11.rncepubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/security/Lenient-Signature11.rn0000644000175000017500000000212113017276730032430 0ustar eugeneeugene# Lenient-Signature11.rnc # # Copyright 2011 W3C (Massachusetts Institute of Technology, # Institut National de Recherche en Informatique et en Automatique, # Keio University). All Rights Reserved. http://www.w3.org/Consortium/Legal/ # # Use and distribution of all schemas in this directory are permitted under the terms # W3C Software Notice and License # http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231 namespace ds = "http://www.w3.org/2000/09/xmldsig#" namespace ds11 = "http://www.w3.org/2009/xmldsig11#" start = anyForeignElementOrSignature anyForeignElementOrSignature = element * - (ds:* | ds11:*) { mixed { security_anyAttribute*, anyForeignElementOrSignature* } } | ds_Signature ds_anyForeignElement = element * - ds:* { mixed { security_anyAttribute*, security_anyElement* } } dsig11_anyForeignElement = element * - ds11:* { mixed { security_anyAttribute*, security_anyElement* } } include "security_any.rnc" include "xmldsig-core-schema.rnc" include "xmldsig11-schema.rnc" include "xmldsig-allowAnyForeign.rnc" include "xmldsig11-allowAnyForeign.rnc"././@LongLink0000644000000000000000000000015300000000000011602 Lustar rootrootepubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/security/Lenient-Encryption11-ghc.rncepubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/security/Lenient-Encryption11-g0000644000175000017500000000317513017276730032441 0ustar eugeneeugene# Lenient-Encryption11-ghc.rnc # # Copyright 2011 W3C (Massachusetts Institute of Technology, # Institut National de Recherche en Informatique et en Automatique, # Keio University). All Rights Reserved. http://www.w3.org/Consortium/Legal/ # # Use and distribution of all schemas in this directory are permitted under the terms # W3C Software Notice and License # http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231 namespace ds = "http://www.w3.org/2000/09/xmldsig#" namespace ds11 = "http://www.w3.org/2009/xmldsig11#" namespace xenc = "http://www.w3.org/2001/04/xmlenc#" namespace xenc11 = "http://www.w3.org/2009/xmlenc11#" start = anyForeignElementOrEncrypted anyForeignElementOrEncrypted = element * - xenc:* { mixed { security_anyAttribute*, anyForeignElementOrEncrypted* } } | xenc_EncryptedData | xenc_EncryptedKey ds_anyForeignElement = element * - (ds:* | xenc:*) { mixed { security_anyAttribute*, security_anyElement* } } dsig11_anyForeignElement = element * - ds11:* { mixed { security_anyAttribute*, security_anyElement* } } xenc_anyForeignElement = element * - xenc:* { mixed { security_anyAttribute*, security_anyElement* } } xenc11_anyForeignElement = element * - xenc11:* { mixed { security_anyAttribute*, security_anyElement* } } include "security_any.rnc" include "xmldsig-core-schema.rnc" include "xmldsig-allowAnyForeign.rnc" include "xmldsig11-schema.rnc" include "xmldsig11-allowAnyForeign.rnc" include "xenc-schema.rnc" include "xenc-allowAnyForeign.rnc" include "xenc-schema-11.rnc" include "xenc11-allowAnyForeign.rnc" include "xmlsec-ghc-schema.rnc" include "xmlsec-ghc-allowAnyForeign.rnc"././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootepubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/security/Lenient-Encryption11.rncepubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/security/Lenient-Encryption11.r0000644000175000017500000000306013017276730032446 0ustar eugeneeugene# Lenient-Encryption11.rnc # # Copyright 2011 W3C (Massachusetts Institute of Technology, # Institut National de Recherche en Informatique et en Automatique, # Keio University). All Rights Reserved. http://www.w3.org/Consortium/Legal/ # # Use and distribution of all schemas in this directory are permitted under the terms # W3C Software Notice and License # http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231 namespace ds = "http://www.w3.org/2000/09/xmldsig#" namespace ds11 = "http://www.w3.org/2009/xmldsig11#" namespace xenc = "http://www.w3.org/2001/04/xmlenc#" namespace xenc11 = "http://www.w3.org/2009/xmlenc11#" start = anyForeignElementOrEncrypted anyForeignElementOrEncrypted = element * - xenc:* { mixed { security_anyAttribute*, anyForeignElementOrEncrypted* } } | xenc_EncryptedData | xenc_EncryptedKey ds_anyForeignElement = element * - (ds:* | xenc:*) { mixed { security_anyAttribute*, security_anyElement* } } dsig11_anyForeignElement = element * - ds11:* { mixed { security_anyAttribute*, security_anyElement* } } xenc_anyForeignElement = element * - xenc:* { mixed { security_anyAttribute*, security_anyElement* } } xenc11_anyForeignElement = element * - xenc11:* { mixed { security_anyAttribute*, security_anyElement* } } include "security_any.rnc" include "xmldsig-core-schema.rnc" include "xmldsig-allowAnyForeign.rnc" include "xmldsig11-schema.rnc" include "xmldsig11-allowAnyForeign.rnc" include "xenc-schema.rnc" include "xenc-allowAnyForeign.rnc" include "xenc-schema-11.rnc" include "xenc11-allowAnyForeign.rnc"epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/security/xmlsec-ghc-schema.rnc0000644000175000017500000000307113017276730032371 0ustar eugeneeugene# xmlsec-ghc-schema.rnc (derived from xmlsec-ghc-schema.xsd) # # Copyright 2011 W3C (Massachusetts Institute of Technology, # Institut National de Recherche en Informatique et en Automatique, # Keio University). All Rights Reserved. http://www.w3.org/Consortium/Legal/ # # Use and distribution of all schemas in this directory are permitted under the terms # W3C Software Notice and License # http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231 # default namespace gh = "http://www.w3.org/2009/xmlsec-gh#" gh_GenericHybridCipherMethod = element GenericHybridCipherMethod { gh_GenericHybridCipherMethodType } gh_GenericHybridCipherMethodType = element KeyEncapsulationMethod { gh_KeyEncapsulationMethodType }, element DataEncapsulationMethod { xenc_EncryptionMethodType } gh_KeyEncapsulationMethodType = xenc11_KeyDerivationMethod, element KeyLen { xsd:positiveInteger } , gh_KeyEncapsulationMethodParams gh_KeyEncapsulationMethodParams = attribute Algorithm {xsd:anyURI "http://www.w3.org/2009/xmlsec-gh#rsaes-kem"} | attribute Algorithm {xsd:anyURI "http://www.w3.org/2009/xmlsec-gh#ecies-kem" } xenc_EncryptionMethodOtherParams |= attribute Algorithm { xsd:anyURI "http://www.w3.org/2009/xmlsec-gh#generic-hybrid" }, gh_GenericHybridCipherMethod # List of known algorithms xenc_EncryptionAlgorithms |= xsd:anyURI "http://www.w3.org/2009/xmlsec-gh#generic-hybrid" gh_KeyEncapsulationAlgorithms = xsd:anyURI "http://www.w3.org/2009/xmlsec-gh#rsaes-kem" | xsd:anyURI "http://www.w3.org/2009/xmlsec-gh#ecies-kem" epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/security/LICENSE0000644000175000017500000000027113017276730027401 0ustar eugeneeugeneUse and distribution of all schemas in this directory are permitted under the terms W3C Software Notice and License http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231 ././@LongLink0000644000000000000000000000015200000000000011601 Lustar rootrootepubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/security/xmldsig-allowAnyForeign.rncepubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/security/xmldsig-allowAnyForeig0000644000175000017500000000377613017276730032723 0ustar eugeneeugene# xmldsig-allowAnyForeign.rnc # # Copyright 2011 W3C (Massachusetts Institute of Technology, # Institut National de Recherche en Informatique et en Automatique, # Keio University). All Rights Reserved. http://www.w3.org/Consortium/Legal/ # # Use and distribution of all schemas in this directory are permitted under the terms # W3C Software Notice and License # http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231 # # This schema mimicks in xmldsig-core-schema.xsd. # When namespace="##other", any foreign element is allowed. # When namespace="##any", any foreign element as well as # any element valid against xmldsig-core-schema.xsd is allowed. # # Schema authors might want to create a dedicated schema # for a collection of particular algorithms rather than # using this schema. default namespace ds = "http://www.w3.org/2000/09/xmldsig#" ds_CanonicalizationMethodType |= attribute Algorithm { xsd:anyURI - ds_CanonicalizationAlgorithms }, (ds_anyForeignElement | ds_anyDsElement)* ds_SignatureMethodType |= attribute Algorithm { xsd:anyURI - ds_SignatureAlgorithms }, # It is allowed to use an HMACOutputLength element even when # the agorithm is not "http://www.w3.org/2000/09/xmldsig#hmac-sha1" element HMACOutputLength { ds_HMACOutputLengthType }?, ds_anyForeignElement* ds_TransformType |= attribute Algorithm { xsd:anyURI - (ds_CanonicalizationAlgorithms | ds_TransformAlgorithms) }, # It is allowed to use XPath elements even when # the algorithm is not "http://www.w3.org/TR/1999/REC-xpath-19991116" (ds_anyForeignElement | element XPath { xsd:string })* ds_DigestMethodType |= attribute Algorithm { xsd:anyURI - ds_DigestAlgorithms }, ds_anyForeignElement* ds_KeyInfoChild |= ds_anyForeignElement ds_KeyValueType |= ds_anyForeignElement ds_X509DataForeignChild |= ds_anyForeignElement ds_SPKIDataForeignChild |= ds_anyForeignElement ds_ObjectChild |= ds_anyForeignElement ds_SignaturePropertyChild |= ds_anyForeignElement ds_PGPDataForeignChild |= ds_anyForeignElement epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/security/xenc-schema.rnc0000644000175000017500000001323313017276730031275 0ustar eugeneeugene# xenc-schema.rnc (derived from xenc-schema.xsd) # # Copyright 2011 W3C (Massachusetts Institute of Technology, # Institut National de Recherche en Informatique et en Automatique, # Keio University). All Rights Reserved. http://www.w3.org/Consortium/Legal/ # # Use and distribution of all schemas in this directory are permitted under the terms # W3C Software Notice and License # http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231 # #It is assumed that the driver schema imports xmldsig-core-schema.rnc. default namespace = "http://www.w3.org/2001/04/xmlenc#" namespace xenc = "http://www.w3.org/2001/04/xmlenc#" ds_KeyValueType |= xenc_DHKeyValue ds_DigestMethodType |= attribute Algorithm { xsd:anyURI "http://www.w3.org/2001/04/xmlenc#sha256" | xsd:anyURI "http://www.w3.org/2001/04/xmlenc#sha512" | xsd:anyURI "http://www.w3.org/2001/04/xmlenc#ripemd160" } xenc_EncryptedType = attribute Id { xenc_IdType }?, attribute Type { xsd:anyURI }?, attribute MimeType { xsd:string }?, attribute Encoding { xsd:anyURI }?, element EncryptionMethod { xenc_EncryptionMethodType }?, ds_KeyInfo?, xenc_CipherData, xenc_EncryptionProperties? xenc_EncryptionMethodType = mixed { element KeySize { xenc_KeySizeType }?, xenc_EncryptionMethodOtherParams } ds_KeyInfoChild |= xenc_EncryptedKey | xenc_AgreementMethod xenc_EncryptionMethodOtherParams = attribute Algorithm { xsd:anyURI "http://www.w3.org/2001/04/xmlenc#tripledes-cbc" } | attribute Algorithm { xsd:anyURI "http://www.w3.org/2001/04/xmlenc#aes128-cbc" } | attribute Algorithm { xsd:anyURI "http://www.w3.org/2001/04/xmlenc#aes256-cbc" } | attribute Algorithm { xsd:anyURI "http://www.w3.org/2001/04/xmlenc#aes192-cbc" } | attribute Algorithm { xsd:anyURI "http://www.w3.org/2001/04/xmlenc#rsa-1_5" } | (attribute Algorithm { xsd:anyURI "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p" }, element OAEPparams { xsd:base64Binary }?, ds_DigestMethod?) | attribute Algorithm { xsd:anyURI "http://www.w3.org/2001/04/xmlenc#kw-tripledes" } | attribute Algorithm { xsd:anyURI "http://www.w3.org/2001/04/xmlenc#kw-aes128" | xsd:anyURI "http://www.w3.org/2001/04/xmlenc#kw-aes192" | xsd:anyURI "http://www.w3.org/2001/04/xmlenc#kw-aes256" } xenc_KeySizeType = xsd:integer xenc_CipherData = element CipherData { xenc_CipherDataType } xenc_CipherDataType = element CipherValue { xsd:base64Binary } | xenc_CipherReference xenc_CipherReference = element CipherReference { xenc_CipherReferenceType } xenc_CipherReferenceType = attribute URI { xsd:anyURI }, element Transforms { xenc_TransformsType }? xenc_TransformsType = ds_Transform+ xenc_EncryptedData = element EncryptedData { xenc_EncryptedDataType } xenc_EncryptedDataType = xenc_EncryptedType xenc_EncryptedKey = element EncryptedKey { xenc_EncryptedKeyType } xenc_EncryptedKeyType = xenc_EncryptedType, xenc_ReferenceList?, element CarriedKeyName { xsd:string }?, attribute Recipient { xsd:string }? xenc_AgreementMethod = element AgreementMethod { xenc_AgreementMethodType } xenc_AgreementMethodType = mixed { element KA-Nonce { xsd:base64Binary }?, xenc_AgreementMethodParams, element OriginatorKeyInfo { ds_KeyInfoType }?, element RecipientKeyInfo { ds_KeyInfoType }? } xenc_AgreementMethodParams = attribute Algorithm { xsd:anyURI "http://www.w3.org/2001/04/xmlenc#dh" }, ds_DigestMethod xenc_ReferenceList = element ReferenceList { (element DataReference { xenc_ReferenceType } | element KeyReference { xenc_ReferenceType })+ } xenc_ReferenceType = attribute URI { xsd:anyURI }, xenc_anyForeignElement* #For both types of references one may optionally specify child elements to aid the recipient in retrieving the EncryptedKey and/or EncryptedData elements. These could include information such as XPath transforms, decompression transforms, or information on how to retrieve the elements from a document storage facility. For example: #ds_Transforms xenc_EncryptionProperties = element EncryptionProperties { xenc_EncryptionPropertiesType } xenc_EncryptionPropertiesType = attribute Id { xenc_IdType }?, xenc_EncryptionProperty+ xenc_EncryptionProperty = element EncryptionProperty { xenc_EncryptionPropertyType } xenc_EncryptionPropertyType = mixed { attribute Target { xsd:anyURI }?, attribute Id { xenc_IdType }?, attribute xml:* { text }*, xenc_anyForeignElement+ } xenc_DHKeyValue = element DHKeyValue { xenc_DHKeyValueType } xenc_DHKeyValueType = (element P { ds_CryptoBinary }, element Q { ds_CryptoBinary }, element Generator { ds_CryptoBinary })?, element Public { ds_CryptoBinary }, (element seed { ds_CryptoBinary }, element pgenCounter { ds_CryptoBinary })? xenc_IdType = xsd:NCName # xsd:ID does not work ds_DigestAlgorithms |= xsd:anyURI "http://www.w3.org/2001/04/xmlenc#sha256" | xsd:anyURI "http://www.w3.org/2001/04/xmlenc#sha512" | xsd:anyURI "http://www.w3.org/2001/04/xmlenc#ripemd160" xenc_EncryptionAlgorithms = xsd:anyURI "http://www.w3.org/2001/04/xmlenc#tripledes-cbc" | xsd:anyURI "http://www.w3.org/2001/04/xmlenc#aes128-cbc" | xsd:anyURI "http://www.w3.org/2001/04/xmlenc#aes256-cbc" | xsd:anyURI "http://www.w3.org/2001/04/xmlenc#aes192-cbc" | xsd:anyURI "http://www.w3.org/2001/04/xmlenc#rsa-1_5" | xsd:anyURI "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p" | xsd:anyURI "http://www.w3.org/2001/04/xmlenc#kw-tripledes" | xsd:anyURI "http://www.w3.org/2001/04/xmlenc#kw-aes128" | xsd:anyURI "http://www.w3.org/2001/04/xmlenc#kw-aes256" | xsd:anyURI "http://www.w3.org/2001/04/xmlenc#kw-aes192" xenc_KeyAgreementAlgorithms = xsd:anyURI "http://www.w3.org/2001/04/xmlenc#dh"././@LongLink0000644000000000000000000000016200000000000011602 Lustar rootrootepubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/security/Lenient-Signature-exclusiveC14N.rncepubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/security/Lenient-Signature-excl0000644000175000017500000000167313017276730032614 0ustar eugeneeugene# Lenient-Signature-exclusiveC14N.rnc # # Copyright 2011 W3C (Massachusetts Institute of Technology, # Institut National de Recherche en Informatique et en Automatique, # Keio University). All Rights Reserved. http://www.w3.org/Consortium/Legal/ # # Use and distribution of all schemas in this directory are permitted under the terms # W3C Software Notice and License # http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231 namespace ds = "http://www.w3.org/2000/09/xmldsig#" namespace ec = "http://www.w3.org/2001/10/xml-exc-c14n#" start = anyForeignElementOrSignature anyForeignElementOrSignature = element * - ds:* { mixed { security_anyAttribute*, anyForeignElementOrSignature* } } | ds_Signature ds_anyForeignElement = element * - ds:* { mixed { security_anyAttribute*, security_anyElement* } } include "security_any.rnc" include "xmldsig-core-schema.rnc" include "xmldsig-allowAnyForeign.rnc" include "exc-c14n.rnc"epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/security/xmldsig-filter2.rnc0000644000175000017500000000120713017276730032114 0ustar eugeneeugene# xmldsig-filter2.rnc (derived from xmldsig-filter2.xsd) # # Copyright 2011 W3C (Massachusetts Institute of Technology, # Institut National de Recherche en Informatique et en Automatique, # Keio University). All Rights Reserved. http://www.w3.org/Consortium/Legal/ # # Use and distribution of all schemas in this directory are permitted under the terms # W3C Software Notice and License # http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231 default namespace = "http://www.w3.org/2002/06/xmldsig-filter2" start = element XPath { attribute Filter { string "intersect" | string "substract" | string "union" }, text }././@LongLink0000644000000000000000000000016100000000000011601 Lustar rootrootepubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/security/Lenient-Signature11-properties.rncepubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/security/Lenient-Signature11-pr0000644000175000017500000000231113017276730032432 0ustar eugeneeugene# Lenient-Signature11-properties.rnc # # Copyright 2011 W3C (Massachusetts Institute of Technology, # Institut National de Recherche en Informatique et en Automatique, # Keio University). All Rights Reserved. http://www.w3.org/Consortium/Legal/ # # Use and distribution of all schemas in this directory are permitted under the terms # W3C Software Notice and License # http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231 namespace ds = "http://www.w3.org/2000/09/xmldsig#" namespace ds11 = "http://www.w3.org/2009/xmldsig11#" namespace dsp = "http://www.w3.org/2009/xmldsig-properties" start = anyForeignElementOrSignature anyForeignElementOrSignature = element * - (ds:* | ds11:* | dsp:*) { mixed { security_anyAttribute*, anyForeignElementOrSignature* } } | ds_Signature ds_anyForeignElement = element * - ds:* { mixed { security_anyAttribute*, security_anyElement* } } dsig11_anyForeignElement = element * - ds11:* { mixed { security_anyAttribute*, security_anyElement* } } include "security_any.rnc" include "xmldsig-core-schema.rnc" include "xmldsig11-schema.rnc" include "xmldsig-allowAnyForeign.rnc" include "xmldsig11-allowAnyForeign.rnc" include "xmldsig-properties-schema.rnc" epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/epub-mathml3-30.rnc0000644000175000017500000000517013017276730027752 0ustar eugeneeugene default namespace m = "http://www.w3.org/1998/Math/MathML" namespace local = "" namespace x = "http://www.w3.org/1999/xhtml" namespace ev = "http://www.w3.org/2001/xml-events" namespace ssml = "http://www.w3.org/2001/10/synthesis" include "mathml/mathml3-common.rnc" { start = element math { math.attributes & MathExpression+ } # redefine annotation-xml to point to ops specialization and allow validation of content mathml annotation-xml = element annotation-xml { html5.annotation.xml.attlist & html5.annotation.xml.content } # redefine to refer to datatype proxy and remove deprecated attributes CommonAtt = attribute id { parent datatype.ID }?, attribute xref { parent datatype.IDREF }?, attribute class { parent datatype.NMTOKENS }?, attribute style { parent datatype.string }?, attribute href { parent datatype.URI }?, NonMathMLAtt* CommonAtt &= parent epub.ssml.ph.attr? # remove deprecated attributes math.deprecatedattributes = empty semantics.attributes = CommonAtt # extend to circumvent datatype collisions NonMathMLAtt = attribute * - (local:* | m:* | xml:* | x:* | ev:* | ssml:*) { parent datatype.string } } html5.annotation.xml.attlist = CommonAtt & attribute cd { "mathmlkeys" }? & attribute name { "contentequiv" | "alternate-representation" }? & attribute definitionURL { parent datatype.URI }? # The choice pattern for combinations of values of @encoding and actual xml annotation content. html5.annotation.xml.content |= (attribute encoding { "application/mathml-content+xml" | "MathML-Content" }, (src | ContExp+)) | (attribute encoding { "application/mathml-presentation+xml" | "MathML-Presentation" }, (src | MathExpression+)) | (attribute encoding { "application/xhtml+xml" }, parent html5.flow.model) # add xml:base CommonAtt &= parent html5.xml.base.attr? include "mathml/mathml3-presentation.rnc" { # redefine to refer to datatype proxy idref = parent datatype.IDREF # remove deprecated mglyph.deprecatedattributes = empty DeprecatedTokenAtt = empty mstyle.deprecatedattributes = empty } include "mathml/mathml3-content.rnc" { # as ops allows presentation mathml only at top level, kill the contribution to MathExpression MathExpression |= notAllowed # remove deprecated DeprecatedContExp = empty } epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/epub-svg11-30.rnc0000644000175000017500000000113113017276730027337 0ustar eugeneeugene# $Id: epub-svg11-30.rnc 3093 2011-08-22 18:33:36Z markus.gylling@gmail.com $ # Contributors: MURATA Makoto and Markus Gylling namespace epub = "http://www.idpf.org/2007/ops" include "svg11/svg11-flat.rnc" { start = svg SVG.id.attrib = attribute id { parent datatype.ID }? SVG.AnimationEvents.attrib = notAllowed SVG.Animation.class = notAllowed SVG.foreignObject.extra.content = parent html5.flow.class SVG.title.extra.content = parent html5.phrasing.class SVG.Core.extra.attrib &= attribute epub:type { parent datatype.properties }? } epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/epub-xhtml-mathml3-30.rnc0000644000175000017500000000014713017276730031103 0ustar eugeneeugene html5.phrasing.class |= math html5.flow.class |= math math = external "epub-mathml3-30.rnc" epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/svg11/0000755000175000017500000000000013017276730025466 5ustar eugeneeugeneepubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/svg11/svg11-flat.rnc0000644000175000017500000035542713017276730030077 0ustar eugeneeugene# ....................................................................... # SVG 1.1 DTD ........................................................... # file: svg11.dtd # SVG 1.1 DTD # # This is SVG, a language for describing two-dimensional graphics in XML. # # The Scalable Vector Graphics (SVG) # Copyright 2001, 2002 World Wide Web Consortium # (Massachusetts Institute of Technology, Institut National de # Recherche en Informatique et en Automatique, Keio University). # All Rights Reserved. # # Permission to use, copy, modify and distribute the SVG DTD and its # accompanying documentation for any purpose and without fee is hereby # granted in perpetuity, provided that the above copyright notice and # this paragraph appear in all copies. The copyright holders make no # representation about the suitability of the DTD for any purpose. # # It is provided "as is" without expressed or implied warranty. # # Author: Jun Fujisawa # Revision: $Id: svg11-flat.rnc 3024 2011-07-10 08:29:17Z eb2mmrt $ # # This is the driver file for version 1.1 of the SVG DTD. # # This DTD is identified by the PUBLIC and SYSTEM identifiers: # # PUBLIC "-//W3C//DTD SVG 1.1//EN" # SYSTEM "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" # Use this URI to identify the default namespace: # # "http://www.w3.org/2000/svg" # # See the Qualified Names module for information # on the use of namespace prefixes in the DTD. # reserved for future use with document profiles # ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: # Pre-Framework Redeclaration Placeholder ..................... # Document Model Module ....................................... # Attribute Collection Module ................................. # Modular Framework Module .................................... # ....................................................................... # SVG 1.1 Modular Framework Module ...................................... # file: svg-framework.mod # # This is SVG, a language for describing two-dimensional graphics in XML. # Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. # Revision: $Id: svg11-flat.rnc 3024 2011-07-10 08:29:17Z eb2mmrt $ # # This DTD module is identified by the PUBLIC and SYSTEM identifiers: # # PUBLIC "-//W3C//ENTITIES SVG 1.1 Modular Framework//EN" # SYSTEM "http://www.w3.org/Graphics/SVG/1.1/DTD/svg-framework.mod" # # ....................................................................... # Modular Framework # # This module instantiates the modules needed to support the SVG # modularization model, including: # # + Datatypes # + Qualified Name # + Document Model # + Attribute Collection # ....................................................................... # SVG 1.1 Datatypes Module .............................................. # file: svg-datatypes.mod # # This is SVG, a language for describing two-dimensional graphics in XML. # Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. # Revision: $Id: svg11-flat.rnc 3024 2011-07-10 08:29:17Z eb2mmrt $ # # This DTD module is identified by the PUBLIC and SYSTEM identifiers: # # PUBLIC "-//W3C//ENTITIES SVG 1.1 Datatypes//EN" # SYSTEM "http://www.w3.org/Graphics/SVG/1.1/DTD/svg-datatypes.mod" # # ....................................................................... # Datatypes # # This module declares common data types for properties and attributes. # feature specification default namespace = "http://www.w3.org/2000/svg" namespace a = "http://relaxng.org/ns/compatibility/annotations/1.0" namespace xlink = "http://www.w3.org/1999/xlink" Boolean.datatype = "false" | "true" # 'clip-rule' or 'fill-rule' property/attribute value ClipFillRule.datatype = "nonzero" | "evenodd" | "inherit" # media type, as per [RFC2045] ContentType.datatype = string # a Coordinate.datatype = string # a list of s Coordinates.datatype = string # a value Color.datatype = string # a Integer.datatype = string # a language code, as per [BCP47] LanguageCode.datatype = xsd:NMTOKEN # comma-separated list of language codes, as per [BCP47] LanguageCodes.datatype = string # a Length.datatype = string # a list of s Lengths.datatype = string # a Number.datatype = string # a list of s Numbers.datatype = string # opacity value (e.g., ) OpacityValue.datatype = string # a path data specification PathData.datatype = string # 'preserveAspectRatio' attribute specification PreserveAspectRatioSpec.datatype = string # script expression Script.datatype = string # An SVG color value (RGB plus optional ICC) SVGColor.datatype = string # arbitrary text string Text.datatype = string # list of transforms TransformList.datatype = string # a Uniform Resource Identifier, see [URI] URI.datatype = string # 'viewBox' attribute specification ViewBoxSpec.datatype = string # end of svg-datatypes.mod # ....................................................................... # SVG 1.1 Qualified Name Module ......................................... # file: svg-qname.mod # # This is SVG, a language for describing two-dimensional graphics in XML. # Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. # Revision: $Id: svg11-flat.rnc 3024 2011-07-10 08:29:17Z eb2mmrt $ # # This DTD module is identified by the PUBLIC and SYSTEM identifiers: # # PUBLIC "-//W3C//ENTITIES SVG 1.1 Qualified Name//EN" # SYSTEM "http://www.w3.org/Graphics/SVG/1.1/DTD/svg-qname.mod" # # ....................................................................... # Qualified Name # # This module is contained in two parts, labeled Section 'A' and 'B': # # Section A declares parameter entities to support namespace- # qualified names, namespace declarations, and name prefixing # for SVG and extensions. # # Section B declares parameter entities used to provide # namespace-qualified names for all SVG element types: # Section A: SVG XML Namespace Framework :::::::::::::::::::::: # 1. Declare a %SVG.prefixed; conditional section keyword, used # to activate namespace prefixing. The default value should # inherit '%NS.prefixed;' from the DTD driver, so that unless # overridden, the default behaviour follows the overall DTD # prefixing scheme. # 2. Declare a parameter entity (eg., %SVG.xmlns;) containing # the URI reference used to identify the SVG namespace: # 3. Declare parameter entities (eg., %SVG.prefix;) containing # the default namespace prefix string(s) to use when prefixing # is enabled. This may be overridden in the DTD driver or the # internal subset of an document instance. If no default prefix # is desired, this may be declared as an empty string. # 4. Declare parameter entities (eg., %SVG.pfx;) containing the # colonized prefix(es) (eg., '%SVG.prefix;:') used when # prefixing is active, an empty string when it is not. # 5. The parameter entity %SVG.xmlns.extra.attrib; may be # redeclared to contain any non-SVG namespace declaration # attributes for namespaces embedded in SVG. The default # is an empty string. # Declare a parameter entity XLINK.xmlns.attrib containing # the XML Namespace declarations for XLink. XLINK.xmlns.attrib = empty # Declare a parameter entity %NS.decl.attrib; containing # all XML Namespace declarations used in the DTD, plus the # xmlns declaration for SVG, its form dependent on whether # prefixing is active. # Declare a parameter entity %SVG.xmlns.attrib; containing # all XML namespace declaration attributes used by SVG, # including a default xmlns attribute when prefixing is # inactive. SVG.xmlns.attrib = XLINK.xmlns.attrib # Section B: SVG Qualified Names :::::::::::::::::::::::::::::: # 6. This section declares parameter entities used to provide # namespace-qualified names for all SVG element types. # module: svg-structure.mod ......................... # module: svg-conditional.mod ....................... # module: svg-image.mod ............................. # module: svg-style.mod ............................. # module: svg-shape.mod ............................. # module: svg-text.mod .............................. # module: svg-marker.mod ............................ # module: svg-profile.mod ........................... # module: svg-gradient.mod .......................... # module: svg-pattern.mod ........................... # module: svg-clip.mod .............................. # module: svg-mask.mod .............................. # module: svg-filter.mod ............................ # module: svg-cursor.mod ............................ # module: svg-hyperlink.mod ......................... # module: svg-view.mod .............................. # module: svg-script.mod ............................ # module: svg-animation.mod ......................... # module: svg-font.mod .............................. # module: svg-extensibility.mod ..................... # end of svg-qname.mod # instantiate the Document Model declared in the DTD driver # ....................................................................... # SVG 1.1 Document Model Module ......................................... # file: svg11-model.mod # # This is SVG, a language for describing two-dimensional graphics in XML. # Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. # Revision: $Id: svg11-flat.rnc 3024 2011-07-10 08:29:17Z eb2mmrt $ # # This DTD module is identified by the PUBLIC and SYSTEM identifiers: # # PUBLIC "-//W3C//ENTITIES SVG 1.1 Document Model//EN" # SYSTEM "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-model.mod" # # ....................................................................... # SVG 1.1 Document Model # # This module describes the groupings of elements that make up # common content models for SVG elements. # module: svg-structure.mod ......................... SVG.Description.extra.class = notAllowed SVG.Description.class = desc | title | metadata | SVG.Description.extra.class SVG.Use.extra.class = notAllowed SVG.Use.class = use | SVG.Use.extra.class SVG.Structure.extra.class = notAllowed SVG.Structure.class = svg | g | defs | symbol | SVG.Use.class | SVG.Structure.extra.class # module: svg-conditional.mod ....................... SVG.Conditional.extra.class = notAllowed SVG.Conditional.class = switch | SVG.Conditional.extra.class # module: svg-image.mod ............................. SVG.Image.extra.class = notAllowed SVG.Image.class = image | SVG.Image.extra.class # module: svg-style.mod ............................. SVG.Style.extra.class = notAllowed SVG.Style.class = style | SVG.Style.extra.class # module: svg-shape.mod ............................. SVG.Shape.extra.class = notAllowed SVG.Shape.class = path | rect | circle | line | ellipse | polyline | polygon | SVG.Shape.extra.class # module: svg-text.mod .............................. SVG.Text.extra.class = notAllowed SVG.Text.class = \text | altGlyphDef | SVG.Text.extra.class SVG.TextContent.extra.class = notAllowed SVG.TextContent.class = tspan | tref | textPath | altGlyph | SVG.TextContent.extra.class # module: svg-marker.mod ............................ SVG.Marker.extra.class = notAllowed SVG.Marker.class = marker | SVG.Marker.extra.class # module: svg-profile.mod ........................... SVG.ColorProfile.extra.class = notAllowed SVG.ColorProfile.class = color-profile | SVG.ColorProfile.extra.class # module: svg-gradient.mod .......................... SVG.Gradient.extra.class = notAllowed SVG.Gradient.class = linearGradient | radialGradient | SVG.Gradient.extra.class # module: svg-pattern.mod ........................... SVG.Pattern.extra.class = notAllowed SVG.Pattern.class = pattern | SVG.Pattern.extra.class # module: svg-clip.mod .............................. SVG.Clip.extra.class = notAllowed SVG.Clip.class = clipPath | SVG.Clip.extra.class # module: svg-mask.mod .............................. SVG.Mask.extra.class = notAllowed SVG.Mask.class = mask | SVG.Mask.extra.class # module: svg-filter.mod ............................ SVG.Filter.extra.class = notAllowed SVG.Filter.class = filter | SVG.Filter.extra.class SVG.FilterPrimitive.extra.class = notAllowed SVG.FilterPrimitive.class = feBlend | feColorMatrix | feComponentTransfer | feComposite | feConvolveMatrix | feDiffuseLighting | feDisplacementMap | feFlood | feGaussianBlur | feImage | feMerge | feMorphology | feOffset | feSpecularLighting | feTile | feTurbulence | SVG.FilterPrimitive.extra.class # module: svg-cursor.mod ............................ SVG.Cursor.extra.class = notAllowed SVG.Cursor.class = cursor | SVG.Cursor.extra.class # module: svg-hyperlink.mod ......................... SVG.Hyperlink.extra.class = notAllowed SVG.Hyperlink.class = a | SVG.Hyperlink.extra.class # module: svg-view.mod .............................. SVG.View.extra.class = notAllowed SVG.View.class = view | SVG.View.extra.class # module: svg-script.mod ............................ SVG.Script.extra.class = notAllowed SVG.Script.class = script | SVG.Script.extra.class # module: svg-animation.mod ......................... SVG.Animation.extra.class = notAllowed SVG.Animation.class = animate | set | animateMotion | animateColor | animateTransform | SVG.Animation.extra.class # module: svg-font.mod .............................. SVG.Font.extra.class = notAllowed SVG.Font.class = font | font-face | SVG.Font.extra.class # module: svg-extensibility.mod ..................... SVG.Extensibility.extra.class = notAllowed SVG.Extensibility.class = foreignObject | SVG.Extensibility.extra.class # end of svg11-model.mod # instantiate the Attribute Collection declared in the DTD driver # ....................................................................... # SVG 1.1 Attribute Collection Module ................................... # file: svg11-attribs.mod # # This is SVG, a language for describing two-dimensional graphics in XML. # Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. # Revision: $Id: svg11-flat.rnc 3024 2011-07-10 08:29:17Z eb2mmrt $ # # This DTD module is identified by the PUBLIC and SYSTEM identifiers: # # PUBLIC "-//W3C//ENTITIES SVG 1.1 Attribute Collection//EN" # SYSTEM "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-attribs.mod" # # ....................................................................... # SVG 1.1 Attribute Collection # # This module defines the set of common attributes that can be present # on many SVG elements. # module: svg-conditional.mod ....................... ExtensionList.datatype = string FeatureList.datatype = string SVG.Conditional.extra.attrib = empty SVG.Conditional.attrib = attribute requiredFeatures { FeatureList.datatype }?, attribute requiredExtensions { ExtensionList.datatype }?, attribute systemLanguage { LanguageCodes.datatype }?, SVG.Conditional.extra.attrib # module: svg-style.mod ............................. ClassList.datatype = string StyleSheet.datatype = string SVG.Style.extra.attrib = empty SVG.Style.attrib = attribute style { StyleSheet.datatype }?, attribute class { ClassList.datatype }?, SVG.Style.extra.attrib # module: svg-text.mod .............................. BaselineShiftValue.datatype = string FontFamilyValue.datatype = string FontSizeValue.datatype = string FontSizeAdjustValue.datatype = string GlyphOrientationHorizontalValue.datatype = string GlyphOrientationVerticalValue.datatype = string KerningValue.datatype = string SpacingValue.datatype = string TextDecorationValue.datatype = string SVG.Text.extra.attrib = empty SVG.Text.attrib = attribute writing-mode { "lr-tb" | "rl-tb" | "tb-rl" | "lr" | "rl" | "tb" | "inherit" }?, SVG.Text.extra.attrib SVG.TextContent.extra.attrib = empty SVG.TextContent.attrib = attribute alignment-baseline { "auto" | "baseline" | "before-edge" | "text-before-edge" | "middle" | "central" | "after-edge" | "text-after-edge" | "ideographic" | "alphabetic" | "hanging" | "mathematical" | "inherit" }?, attribute baseline-shift { BaselineShiftValue.datatype }?, attribute direction { "ltr" | "rtl" | "inherit" }?, attribute dominant-baseline { "auto" | "use-script" | "no-change" | "reset-size" | "ideographic" | "alphabetic" | "hanging" | "mathematical" | "central" | "middle" | "text-after-edge" | "text-before-edge" | "inherit" }?, attribute glyph-orientation-horizontal { GlyphOrientationHorizontalValue.datatype }?, attribute glyph-orientation-vertical { GlyphOrientationVerticalValue.datatype }?, attribute kerning { KerningValue.datatype }?, attribute letter-spacing { SpacingValue.datatype }?, attribute text-anchor { "start" | "middle" | "end" | "inherit" }?, attribute text-decoration { TextDecorationValue.datatype }?, attribute unicode-bidi { "normal" | "embed" | "bidi-override" | "inherit" }?, attribute word-spacing { SpacingValue.datatype }?, SVG.TextContent.extra.attrib SVG.Font.extra.attrib = empty SVG.Font.attrib = attribute font-family { FontFamilyValue.datatype }?, attribute font-size { FontSizeValue.datatype }?, attribute font-size-adjust { FontSizeAdjustValue.datatype }?, attribute font-stretch { "normal" | "wider" | "narrower" | "ultra-condensed" | "extra-condensed" | "condensed" | "semi-condensed" | "semi-expanded" | "expanded" | "extra-expanded" | "ultra-expanded" | "inherit" }?, attribute font-style { "normal" | "italic" | "oblique" | "inherit" }?, attribute font-variant { "normal" | "small-caps" | "inherit" }?, attribute font-weight { "normal" | "bold" | "bolder" | "lighter" | "100" | "200" | "300" | "400" | "500" | "600" | "700" | "800" | "900" | "inherit" }?, SVG.Font.extra.attrib # module: svg-marker.mod ............................ MarkerValue.datatype = string SVG.Marker.extra.attrib = empty SVG.Marker.attrib = attribute marker-start { MarkerValue.datatype }?, attribute marker-mid { MarkerValue.datatype }?, attribute marker-end { MarkerValue.datatype }?, SVG.Marker.extra.attrib # module: svg-profile.mod ........................... SVG.ColorProfile.extra.attrib = empty SVG.ColorProfile.attrib = attribute color-profile { text }?, SVG.ColorProfile.extra.attrib # module: svg-gradient.mod .......................... NumberOrPercentage.datatype = string SVG.Gradient.extra.attrib = empty SVG.Gradient.attrib = attribute stop-color { SVGColor.datatype }?, attribute stop-opacity { OpacityValue.datatype }?, SVG.Gradient.extra.attrib # module: svg-clip.mod .............................. ClipPathValue.datatype = string SVG.Clip.extra.attrib = empty SVG.Clip.attrib = attribute clip-path { ClipPathValue.datatype }?, attribute clip-rule { ClipFillRule.datatype }?, SVG.Clip.extra.attrib # module: svg-mask.mod .............................. MaskValue.datatype = string SVG.Mask.extra.attrib = empty SVG.Mask.attrib = attribute mask { MaskValue.datatype }?, SVG.Mask.extra.attrib # module: svg-filter.mod ............................ FilterValue.datatype = string NumberOptionalNumber.datatype = string SVG.Filter.extra.attrib = empty SVG.Filter.attrib = attribute filter { FilterValue.datatype }?, SVG.Filter.extra.attrib SVG.FilterColor.extra.attrib = empty SVG.FilterColor.attrib = attribute color-interpolation-filters { "auto" | "sRGB" | "linearRGB" | "inherit" }?, SVG.FilterColor.extra.attrib # module: svg-cursor.mod ............................ CursorValue.datatype = string SVG.Cursor.extra.attrib = empty SVG.Cursor.attrib = attribute cursor { CursorValue.datatype }?, SVG.Cursor.extra.attrib # end of svg11-attribs.mod # end of svg-framework.mod # Post-Framework Redeclaration Placeholder .................... # ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: # Core Attribute Module ....................................... # ....................................................................... # SVG 1.1 Core Attribute Module ......................................... # file: svg-core-attrib.mod # # This is SVG, a language for describing two-dimensional graphics in XML. # Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. # Revision: $Id: svg11-flat.rnc 3024 2011-07-10 08:29:17Z eb2mmrt $ # # This DTD module is identified by the PUBLIC and SYSTEM identifiers: # # PUBLIC "-//W3C//ENTITIES SVG 1.1 Core Attribute//EN" # SYSTEM "http://www.w3.org/Graphics/SVG/1.1/DTD/svg-core-attrib.mod" # # ....................................................................... # Core Attribute # # id, xml:base, xml:lang, xml:space # # This module defines the core set of attributes that can be present on # any element. SVG.id.attrib = attribute id { xsd:ID }? SVG.base.attrib = attribute xml:base { URI.datatype }? SVG.lang.attrib = attribute xml:lang { LanguageCode.datatype }? SVG.space.attrib = attribute xml:space { "default" | "preserve" }? SVG.Core.extra.attrib = empty SVG.Core.attrib = SVG.id.attrib, SVG.base.attrib, SVG.lang.attrib, SVG.space.attrib, SVG.Core.extra.attrib # end of svg-core-attrib.mod # Container Attribute Module .................................. # ....................................................................... # SVG 1.1 Container Attribute Module .................................... # file: svg-container-attrib.mod # # This is SVG, a language for describing two-dimensional graphics in XML. # Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. # Revision: $Id: svg11-flat.rnc 3024 2011-07-10 08:29:17Z eb2mmrt $ # # This DTD module is identified by the PUBLIC and SYSTEM identifiers: # # PUBLIC "-//W3C//ENTITIES SVG 1.1 Container Attribute//EN" # SYSTEM "http://www.w3.org/Graphics/SVG/1.1/DTD/svg-container-attrib.mod" # # ....................................................................... # Container Attribute # # enable-background # # This module defines the Container attribute set. # 'enable-background' property/attribute value (e.g., 'new', 'accumulate') EnableBackgroundValue.datatype = string SVG.enable-background.attrib = attribute enable-background { EnableBackgroundValue.datatype }? SVG.Container.extra.attrib = empty SVG.Container.attrib = SVG.enable-background.attrib, SVG.Container.extra.attrib # end of svg-container-attrib.mod # Viewport Attribute Module ................................... # ....................................................................... # SVG 1.1 Viewport Attribute Module ..................................... # file: svg-viewport-attrib.mod # # This is SVG, a language for describing two-dimensional graphics in XML. # Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. # Revision: $Id: svg11-flat.rnc 3024 2011-07-10 08:29:17Z eb2mmrt $ # # This DTD module is identified by the PUBLIC and SYSTEM identifiers: # # PUBLIC "-//W3C//ENTITIES SVG 1.1 Viewport Attribute//EN" # SYSTEM "http://www.w3.org/Graphics/SVG/1.1/DTD/svg-viewport-attrib.mod" # # ....................................................................... # Viewport Attribute # # clip, overflow # # This module defines the Viewport attribute set. # 'clip' property/attribute value (e.g., 'auto', rect(...)) ClipValue.datatype = string SVG.clip.attrib = attribute clip { ClipValue.datatype }? SVG.overflow.attrib = attribute overflow { "visible" | "hidden" | "scroll" | "auto" | "inherit" }? SVG.Viewport.extra.attrib = empty SVG.Viewport.attrib = SVG.clip.attrib, SVG.overflow.attrib, SVG.Viewport.extra.attrib # end of svg-viewport-attrib.mod # Paint Attribute Module ...................................... # ....................................................................... # SVG 1.1 Paint Attribute Module ........................................ # file: svg-paint-attrib.mod # # This is SVG, a language for describing two-dimensional graphics in XML. # Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. # Revision: $Id: svg11-flat.rnc 3024 2011-07-10 08:29:17Z eb2mmrt $ # # This DTD module is identified by the PUBLIC and SYSTEM identifiers: # # PUBLIC "-//W3C//ENTITIES SVG 1.1 Paint Attribute//EN" # SYSTEM "http://www.w3.org/Graphics/SVG/1.1/DTD/svg-paint-attrib.mod" # # ....................................................................... # Paint Attribute # # fill, fill-rule, stroke, stroke-dasharray, stroke-dashoffset, # stroke-linecap, stroke-linejoin, stroke-miterlimit, stroke-width, color, # color-interpolation, color-rendering # # This module defines the Paint and Color attribute sets. # a 'fill' or 'stroke' property/attribute value: Paint.datatype = string # 'stroke-dasharray' property/attribute value (e.g., 'none', list of s) StrokeDashArrayValue.datatype = string # 'stroke-dashoffset' property/attribute value (e.g., 'none', ) StrokeDashOffsetValue.datatype = string # 'stroke-miterlimit' property/attribute value (e.g., ) StrokeMiterLimitValue.datatype = string # 'stroke-width' property/attribute value (e.g., ) StrokeWidthValue.datatype = string SVG.fill.attrib = attribute fill { Paint.datatype }? SVG.fill-rule.attrib = attribute fill-rule { ClipFillRule.datatype }? SVG.stroke.attrib = attribute stroke { Paint.datatype }? SVG.stroke-dasharray.attrib = attribute stroke-dasharray { StrokeDashArrayValue.datatype }? SVG.stroke-dashoffset.attrib = attribute stroke-dashoffset { StrokeDashOffsetValue.datatype }? SVG.stroke-linecap.attrib = attribute stroke-linecap { "butt" | "round" | "square" | "inherit" }? SVG.stroke-linejoin.attrib = attribute stroke-linejoin { "miter" | "round" | "bevel" | "inherit" }? SVG.stroke-miterlimit.attrib = attribute stroke-miterlimit { StrokeMiterLimitValue.datatype }? SVG.stroke-width.attrib = attribute stroke-width { StrokeWidthValue.datatype }? SVG.Paint.extra.attrib = empty SVG.Paint.attrib = SVG.fill.attrib, SVG.fill-rule.attrib, SVG.stroke.attrib, SVG.stroke-dasharray.attrib, SVG.stroke-dashoffset.attrib, SVG.stroke-linecap.attrib, SVG.stroke-linejoin.attrib, SVG.stroke-miterlimit.attrib, SVG.stroke-width.attrib, SVG.Paint.extra.attrib SVG.color.attrib = attribute color { Color.datatype }? SVG.color-interpolation.attrib = attribute color-interpolation { "auto" | "sRGB" | "linearRGB" | "inherit" }? SVG.color-rendering.attrib = attribute color-rendering { "auto" | "optimizeSpeed" | "optimizeQuality" | "inherit" }? SVG.Color.extra.attrib = empty SVG.Color.attrib = SVG.color.attrib, SVG.color-interpolation.attrib, SVG.color-rendering.attrib, SVG.Color.extra.attrib # end of svg-paint-attrib.mod # Paint Opacity Attribute Module .............................. # ....................................................................... # SVG 1.1 Paint Opacity Attribute Module ................................ # file: svg-opacity-attrib.mod # # This is SVG, a language for describing two-dimensional graphics in XML. # Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. # Revision: $Id: svg11-flat.rnc 3024 2011-07-10 08:29:17Z eb2mmrt $ # # This DTD module is identified by the PUBLIC and SYSTEM identifiers: # # PUBLIC "-//W3C//ENTITIES SVG 1.1 Paint Opacity Attribute//EN" # SYSTEM "http://www.w3.org/Graphics/SVG/1.1/DTD/svg-opacity-attrib.mod" # # ....................................................................... # Paint Opacity Attribute # # opacity, fill-opacity, stroke-opacity # # This module defines the Opacity attribute set. SVG.opacity.attrib = attribute opacity { OpacityValue.datatype }? SVG.fill-opacity.attrib = attribute fill-opacity { OpacityValue.datatype }? SVG.stroke-opacity.attrib = attribute stroke-opacity { OpacityValue.datatype }? SVG.Opacity.extra.attrib = empty SVG.Opacity.attrib = SVG.opacity.attrib, SVG.fill-opacity.attrib, SVG.stroke-opacity.attrib, SVG.Opacity.extra.attrib # end of svg-opacity-attrib.mod # Graphics Attribute Module ................................... # ....................................................................... # SVG 1.1 Graphics Attribute Module ..................................... # file: svg-graphics-attrib.mod # # This is SVG, a language for describing two-dimensional graphics in XML. # Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. # Revision: $Id: svg11-flat.rnc 3024 2011-07-10 08:29:17Z eb2mmrt $ # # This DTD module is identified by the PUBLIC and SYSTEM identifiers: # # PUBLIC "-//W3C//ENTITIES SVG 1.1 Graphics Attribute//EN" # SYSTEM "http://www.w3.org/Graphics/SVG/1.1/DTD/svg-graphics-attrib.mod" # # ....................................................................... # Graphics Attribute # # display, image-rendering, pointer-events, shape-rendering, # text-rendering, visibility # # This module defines the Graphics attribute set. SVG.display.attrib = attribute display { "inline" | "block" | "list-item" | "run-in" | "compact" | "marker" | "table" | "inline-table" | "table-row-group" | "table-header-group" | "table-footer-group" | "table-row" | "table-column-group" | "table-column" | "table-cell" | "table-caption" | "none" | "inherit" }? SVG.image-rendering.attrib = attribute image-rendering { "auto" | "optimizeSpeed" | "optimizeQuality" | "inherit" }? SVG.pointer-events.attrib = attribute pointer-events { "visiblePainted" | "visibleFill" | "visibleStroke" | "visible" | "painted" | "fill" | "stroke" | "all" | "none" | "inherit" }? SVG.shape-rendering.attrib = attribute shape-rendering { "auto" | "optimizeSpeed" | "crispEdges" | "geometricPrecision" | "inherit" }? SVG.text-rendering.attrib = attribute text-rendering { "auto" | "optimizeSpeed" | "optimizeLegibility" | "geometricPrecision" | "inherit" }? SVG.visibility.attrib = attribute visibility { "visible" | "hidden" | "inherit" }? SVG.Graphics.extra.attrib = empty SVG.Graphics.attrib = SVG.display.attrib, SVG.image-rendering.attrib, SVG.pointer-events.attrib, SVG.shape-rendering.attrib, SVG.text-rendering.attrib, SVG.visibility.attrib, SVG.Graphics.extra.attrib # end of svg-graphics-attrib.mod # Document Events Attribute Module ............................ # ....................................................................... # SVG 1.1 Document Events Attribute Module .............................. # file: svg-docevents-attrib.mod # # This is SVG, a language for describing two-dimensional graphics in XML. # Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. # Revision: $Id: svg11-flat.rnc 3024 2011-07-10 08:29:17Z eb2mmrt $ # # This DTD module is identified by the PUBLIC and SYSTEM identifiers: # # PUBLIC "-//W3C//ENTITIES SVG 1.1 Document Events Attribute//EN" # SYSTEM "http://www.w3.org/Graphics/SVG/1.1/DTD/svg-docevents-attrib.mod" # # ....................................................................... # Document Events Attribute # # onunload, onabort, onerror, onresize, onscroll, onzoom # # This module defines the DocumentEvents attribute set. SVG.onunload.attrib = attribute onunload { Script.datatype }? SVG.onabort.attrib = attribute onabort { Script.datatype }? SVG.onerror.attrib = attribute onerror { Script.datatype }? SVG.onresize.attrib = attribute onresize { Script.datatype }? SVG.onscroll.attrib = attribute onscroll { Script.datatype }? SVG.onzoom.attrib = attribute onzoom { Script.datatype }? SVG.DocumentEvents.extra.attrib = empty SVG.DocumentEvents.attrib = SVG.onunload.attrib, SVG.onabort.attrib, SVG.onerror.attrib, SVG.onresize.attrib, SVG.onscroll.attrib, SVG.onzoom.attrib, SVG.DocumentEvents.extra.attrib # end of svg-docevents-attrib.mod # Graphical Element Events Attribute Module ................... # ....................................................................... # SVG 1.1 Graphical Element Events Attribute Module ..................... # file: svg-graphevents-attrib.mod # # This is SVG, a language for describing two-dimensional graphics in XML. # Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. # Revision: $Id: svg11-flat.rnc 3024 2011-07-10 08:29:17Z eb2mmrt $ # # This DTD module is identified by the PUBLIC and SYSTEM identifiers: # # PUBLIC "-//W3C//ENTITIES SVG 1.1 Graphical Element Events Attribute//EN" # SYSTEM "http://www.w3.org/Graphics/SVG/1.1/DTD/svg-graphevents-attrib.mod" # # ....................................................................... # Graphical Element Events Attribute # # onfocusin, onfocusout, onactivate, onclick, onmousedown, onmouseup, # onmouseover, onmousemove, onmouseout, onload # # This module defines the GraphicalEvents attribute set. SVG.onfocusin.attrib = attribute onfocusin { Script.datatype }? SVG.onfocusout.attrib = attribute onfocusout { Script.datatype }? SVG.onactivate.attrib = attribute onactivate { Script.datatype }? SVG.onclick.attrib = attribute onclick { Script.datatype }? SVG.onmousedown.attrib = attribute onmousedown { Script.datatype }? SVG.onmouseup.attrib = attribute onmouseup { Script.datatype }? SVG.onmouseover.attrib = attribute onmouseover { Script.datatype }? SVG.onmousemove.attrib = attribute onmousemove { Script.datatype }? SVG.onmouseout.attrib = attribute onmouseout { Script.datatype }? SVG.onload.attrib = attribute onload { Script.datatype }? SVG.GraphicalEvents.extra.attrib = empty SVG.GraphicalEvents.attrib = SVG.onfocusin.attrib, SVG.onfocusout.attrib, SVG.onactivate.attrib, SVG.onclick.attrib, SVG.onmousedown.attrib, SVG.onmouseup.attrib, SVG.onmouseover.attrib, SVG.onmousemove.attrib, SVG.onmouseout.attrib, SVG.onload.attrib, SVG.GraphicalEvents.extra.attrib # end of svg-graphevents-attrib.mod # Animation Events Attribute Module ........................... # ....................................................................... # SVG 1.1 Animation Events Attribute Module ............................. # file: svg-animevents-attrib.mod # # This is SVG, a language for describing two-dimensional graphics in XML. # Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. # Revision: $Id: svg11-flat.rnc 3024 2011-07-10 08:29:17Z eb2mmrt $ # # This DTD module is identified by the PUBLIC and SYSTEM identifiers: # # PUBLIC "-//W3C//ENTITIES SVG 1.1 Animation Events Attribute//EN" # SYSTEM "http://www.w3.org/Graphics/SVG/1.1/DTD/svg-animevents-attrib.mod" # # ....................................................................... # Animation Events Attribute # # onbegin, onend, onrepeat, onload # # This module defines the AnimationEvents attribute set. SVG.onbegin.attrib = attribute onbegin { Script.datatype }? SVG.onend.attrib = attribute onend { Script.datatype }? SVG.onrepeat.attrib = attribute onrepeat { Script.datatype }? SVG.AnimationEvents.extra.attrib = empty SVG.AnimationEvents.attrib = SVG.onbegin.attrib, SVG.onend.attrib, SVG.onrepeat.attrib, SVG.onload.attrib, SVG.AnimationEvents.extra.attrib # end of svg-animevents-attrib.mod # XLink Attribute Module ...................................... # ....................................................................... # SVG 1.1 XLink Attribute Module ........................................ # file: svg-xlink-attrib.mod # # This is SVG, a language for describing two-dimensional graphics in XML. # Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. # Revision: $Id: svg11-flat.rnc 3024 2011-07-10 08:29:17Z eb2mmrt $ # # This DTD module is identified by the PUBLIC and SYSTEM identifiers: # # PUBLIC "-//W3C//ENTITIES SVG 1.1 XLink Attribute//EN" # SYSTEM "http://www.w3.org/Graphics/SVG/1.1/DTD/svg-xlink-attrib.mod" # # ....................................................................... # XLink Attribute # # type, href, role, arcrole, title, show, actuate # # This module defines the XLink, XLinkRequired, XLinkEmbed, and # XLinkReplace attribute set. SVG.XLink.extra.attrib = empty SVG.XLink.attrib = XLINK.xmlns.attrib, [ a:defaultValue = "simple" ] attribute xlink:type { "simple" }?, attribute xlink:href { URI.datatype }?, attribute xlink:role { URI.datatype }?, attribute xlink:arcrole { URI.datatype }?, attribute xlink:title { text }?, [ a:defaultValue = "other" ] attribute xlink:show { "other" }?, [ a:defaultValue = "onLoad" ] attribute xlink:actuate { "onLoad" }?, SVG.XLink.extra.attrib SVG.XLinkRequired.extra.attrib = empty SVG.XLinkRequired.attrib = XLINK.xmlns.attrib, [ a:defaultValue = "simple" ] attribute xlink:type { "simple" }?, attribute xlink:href { URI.datatype }, attribute xlink:role { URI.datatype }?, attribute xlink:arcrole { URI.datatype }?, attribute xlink:title { text }?, [ a:defaultValue = "other" ] attribute xlink:show { "other" }?, [ a:defaultValue = "onLoad" ] attribute xlink:actuate { "onLoad" }?, SVG.XLinkRequired.extra.attrib SVG.XLinkEmbed.extra.attrib = empty SVG.XLinkEmbed.attrib = XLINK.xmlns.attrib, [ a:defaultValue = "simple" ] attribute xlink:type { "simple" }?, attribute xlink:href { URI.datatype }, attribute xlink:role { URI.datatype }?, attribute xlink:arcrole { URI.datatype }?, attribute xlink:title { text }?, [ a:defaultValue = "embed" ] attribute xlink:show { "embed" }?, [ a:defaultValue = "onLoad" ] attribute xlink:actuate { "onLoad" }?, SVG.XLinkEmbed.extra.attrib SVG.XLinkReplace.extra.attrib = empty SVG.XLinkReplace.attrib = XLINK.xmlns.attrib, [ a:defaultValue = "simple" ] attribute xlink:type { "simple" }?, attribute xlink:href { URI.datatype }, attribute xlink:role { URI.datatype }?, attribute xlink:arcrole { URI.datatype }?, attribute xlink:title { text }?, [ a:defaultValue = "replace" ] attribute xlink:show { "new" | "replace" }?, [ a:defaultValue = "onRequest" ] attribute xlink:actuate { "onRequest" }?, SVG.XLinkReplace.extra.attrib # end of svg-xlink-attrib.mod # External Resources Attribute Module ......................... # ....................................................................... # SVG 1.1 External Resources Attribute Module ........................... # file: svg-extresources-attrib.mod # # This is SVG, a language for describing two-dimensional graphics in XML. # Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. # Revision: $Id: svg11-flat.rnc 3024 2011-07-10 08:29:17Z eb2mmrt $ # # This DTD module is identified by the PUBLIC and SYSTEM identifiers: # # PUBLIC "-//W3C//ENTITIES SVG 1.1 External Resources Attribute//EN" # SYSTEM "http://www.w3.org/Graphics/SVG/1.1/DTD/svg-extresources-attrib.mod" # # ....................................................................... # External Resources Attribute # # externalResourcesRequired # # This module defines the External attribute set. SVG.externalResourcesRequired.attrib = attribute externalResourcesRequired { Boolean.datatype }? SVG.External.extra.attrib = empty SVG.External.attrib = SVG.externalResourcesRequired.attrib, SVG.External.extra.attrib # end of svg-extresources-attrib.mod # ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: # Structure Module ............................................ # ....................................................................... # SVG 1.1 Structure Module .............................................. # file: svg-structure.mod # # This is SVG, a language for describing two-dimensional graphics in XML. # Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. # Revision: $Id: svg11-flat.rnc 3024 2011-07-10 08:29:17Z eb2mmrt $ # # This DTD module is identified by the PUBLIC and SYSTEM identifiers: # # PUBLIC "-//W3C//ELEMENTS SVG 1.1 Structure//EN" # SYSTEM "http://www.w3.org/Graphics/SVG/1.1/DTD/svg-structure.mod" # # ....................................................................... # Structure # # svg, g, defs, desc, title, metadata, symbol, use # # This module declares the major structural elements and their attributes. # Qualified Names (Default) ......................... # Attribute Collections (Default) ................... # SVG.Description.class ............................. # SVG.Use.class ..................................... # SVG.Structure.class ............................... # SVG.Presentation.attrib ........................... SVG.Presentation.extra.attrib = empty SVG.Presentation.attrib = SVG.Container.attrib, SVG.Viewport.attrib, SVG.Text.attrib, SVG.TextContent.attrib, SVG.Font.attrib, SVG.Paint.attrib, SVG.Color.attrib, SVG.Opacity.attrib, SVG.Graphics.attrib, SVG.Marker.attrib, SVG.ColorProfile.attrib, SVG.Gradient.attrib, SVG.Clip.attrib, SVG.Mask.attrib, SVG.Filter.attrib, SVG.FilterColor.attrib, SVG.Cursor.attrib, attribute flood-color { SVGColor.datatype }?, attribute flood-opacity { OpacityValue.datatype }?, attribute lighting-color { SVGColor.datatype }?, SVG.Presentation.extra.attrib # svg: SVG Document Element ......................... SVG.svg.extra.content = notAllowed SVG.svg.content = (SVG.Description.class | SVG.Animation.class | SVG.Structure.class | SVG.Conditional.class | SVG.Image.class | SVG.Style.class | SVG.Shape.class | SVG.Text.class | SVG.Marker.class | SVG.ColorProfile.class | SVG.Gradient.class | SVG.Pattern.class | SVG.Clip.class | SVG.Mask.class | SVG.Filter.class | SVG.Cursor.class | SVG.Hyperlink.class | SVG.View.class | SVG.Script.class | SVG.Font.class | SVG.Extensibility.class | SVG.svg.extra.content)* svg = element svg { SVG.xmlns.attrib, SVG.Core.attrib, SVG.Conditional.attrib, SVG.Style.attrib, SVG.Presentation.attrib, SVG.DocumentEvents.attrib, SVG.GraphicalEvents.attrib, SVG.External.attrib, attribute x { Coordinate.datatype }?, attribute y { Coordinate.datatype }?, attribute width { Length.datatype }?, attribute height { Length.datatype }?, attribute viewBox { ViewBoxSpec.datatype }?, [ a:defaultValue = "xMidYMid meet" ] attribute preserveAspectRatio { PreserveAspectRatioSpec.datatype }?, [ a:defaultValue = "magnify" ] attribute zoomAndPan { "disable" | "magnify" }?, [ a:defaultValue = "1.1" ] attribute version { string "1.1" }?, attribute baseProfile { Text.datatype }?, [ a:defaultValue = "application/ecmascript" ] attribute contentScriptType { ContentType.datatype }?, [ a:defaultValue = "text/css" ] attribute contentStyleType { ContentType.datatype }?, SVG.svg.content } # end of SVG.svg.element # end of SVG.svg.attlist # g: Group Element .................................. SVG.g.extra.content = notAllowed SVG.g.content = (SVG.Description.class | SVG.Animation.class | SVG.Structure.class | SVG.Conditional.class | SVG.Image.class | SVG.Style.class | SVG.Shape.class | SVG.Text.class | SVG.Marker.class | SVG.ColorProfile.class | SVG.Gradient.class | SVG.Pattern.class | SVG.Clip.class | SVG.Mask.class | SVG.Filter.class | SVG.Cursor.class | SVG.Hyperlink.class | SVG.View.class | SVG.Script.class | SVG.Font.class | SVG.Extensibility.class | SVG.g.extra.content)* g = element g { SVG.Core.attrib, SVG.Conditional.attrib, SVG.Style.attrib, SVG.Presentation.attrib, SVG.GraphicalEvents.attrib, SVG.External.attrib, attribute transform { TransformList.datatype }?, SVG.g.content } # end of SVG.g.element # end of SVG.g.attlist # defs: Definisions Element ......................... SVG.defs.extra.content = notAllowed SVG.defs.content = (SVG.Description.class | SVG.Animation.class | SVG.Structure.class | SVG.Conditional.class | SVG.Image.class | SVG.Style.class | SVG.Shape.class | SVG.Text.class | SVG.Marker.class | SVG.ColorProfile.class | SVG.Gradient.class | SVG.Pattern.class | SVG.Clip.class | SVG.Mask.class | SVG.Filter.class | SVG.Cursor.class | SVG.Hyperlink.class | SVG.View.class | SVG.Script.class | SVG.Font.class | SVG.Extensibility.class | SVG.defs.extra.content)* defs = element defs { SVG.Core.attrib, SVG.Conditional.attrib, SVG.Style.attrib, SVG.Presentation.attrib, SVG.GraphicalEvents.attrib, SVG.External.attrib, attribute transform { TransformList.datatype }?, SVG.defs.content } # end of SVG.defs.element # end of SVG.defs.attlist # desc: Description Element ......................... SVG.desc.extra.content = notAllowed SVG.desc.content = (text | SVG.desc.extra.content)* desc = element desc { SVG.Core.attrib, SVG.Style.attrib, SVG.desc.content } # end of SVG.desc.element # end of SVG.desc.attlist # title: Title Element .............................. SVG.title.extra.content = notAllowed SVG.title.content = (text | SVG.title.extra.content)* title = element title { SVG.Core.attrib, SVG.Style.attrib, SVG.title.content } # end of SVG.title.element # end of SVG.title.attlist # metadata: Metadata Element ........................ SVG.metadata.extra.content = notAllowed SVG.metadata.content = (text | SVG.metadata.extra.content)* metadata = element metadata { SVG.Core.attrib, SVG.metadata.content } # end of SVG.metadata.element # end of SVG.metadata.attlist # symbol: Symbol Element ............................ SVG.symbol.extra.content = notAllowed SVG.symbol.content = (SVG.Description.class | SVG.Animation.class | SVG.Structure.class | SVG.Conditional.class | SVG.Image.class | SVG.Style.class | SVG.Shape.class | SVG.Text.class | SVG.Marker.class | SVG.ColorProfile.class | SVG.Gradient.class | SVG.Pattern.class | SVG.Clip.class | SVG.Mask.class | SVG.Filter.class | SVG.Cursor.class | SVG.Hyperlink.class | SVG.View.class | SVG.Script.class | SVG.Font.class | SVG.Extensibility.class | SVG.symbol.extra.content)* symbol = element symbol { SVG.Core.attrib, SVG.Style.attrib, SVG.Presentation.attrib, SVG.GraphicalEvents.attrib, SVG.External.attrib, attribute viewBox { ViewBoxSpec.datatype }?, [ a:defaultValue = "xMidYMid meet" ] attribute preserveAspectRatio { PreserveAspectRatioSpec.datatype }?, SVG.symbol.content } # end of SVG.symbol.element # end of SVG.symbol.attlist # use: Use Element .................................. SVG.use.extra.content = notAllowed SVG.use.content = (SVG.Description.class | SVG.Animation.class | SVG.use.extra.content)* use = element use { SVG.Core.attrib, SVG.Conditional.attrib, SVG.Style.attrib, SVG.Presentation.attrib, SVG.GraphicalEvents.attrib, SVG.XLinkEmbed.attrib, SVG.External.attrib, attribute x { Coordinate.datatype }?, attribute y { Coordinate.datatype }?, attribute width { Length.datatype }?, attribute height { Length.datatype }?, attribute transform { TransformList.datatype }?, SVG.use.content } # end of SVG.use.element # end of SVG.use.attlist # end of svg-structure.mod # Conditional Processing Module ............................... # ....................................................................... # SVG 1.1 Conditional Processing Module ................................. # file: svg-conditional.mod # # This is SVG, a language for describing two-dimensional graphics in XML. # Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. # Revision: $Id: svg11-flat.rnc 3024 2011-07-10 08:29:17Z eb2mmrt $ # # This DTD module is identified by the PUBLIC and SYSTEM identifiers: # # PUBLIC "-//W3C//ELEMENTS SVG 1.1 Conditional Processing//EN" # SYSTEM "http://www.w3.org/Graphics/SVG/1.1/DTD/svg-conditional.mod" # # ....................................................................... # Conditional Processing # # switch # # This module declares markup to provide support for conditional processing. # extension list specification # feature list specification # Qualified Names (Default) ......................... # Attribute Collections (Default) ................... # SVG.Conditional.class ............................. # SVG.Conditional.attrib ............................ # SVG.Presentation.attrib ........................... # switch: Switch Element ............................ SVG.switch.extra.content = notAllowed SVG.switch.content = (SVG.Description.class | svg | g | use | \text | SVG.Animation.class | SVG.Conditional.class | SVG.Image.class | SVG.Shape.class | SVG.Hyperlink.class | SVG.Extensibility.class | SVG.switch.extra.content)* switch = element switch { SVG.Core.attrib, SVG.Conditional.attrib, SVG.Style.attrib, SVG.Presentation.attrib, SVG.GraphicalEvents.attrib, SVG.External.attrib, attribute transform { TransformList.datatype }?, SVG.switch.content } # end of SVG.switch.element # end of SVG.switch.attlist # end of svg-conditional.mod # Image Module ................................................ # ....................................................................... # SVG 1.1 Image Module .................................................. # file: svg-image.mod # # This is SVG, a language for describing two-dimensional graphics in XML. # Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. # Revision: $Id: svg11-flat.rnc 3024 2011-07-10 08:29:17Z eb2mmrt $ # # This DTD module is identified by the PUBLIC and SYSTEM identifiers: # # PUBLIC "-//W3C//ELEMENTS SVG 1.1 Image//EN" # SYSTEM "http://www.w3.org/Graphics/SVG/1.1/DTD/svg-image.mod" # # ....................................................................... # Image # # image # # This module declares markup to provide support for image. # Qualified Names (Default) ......................... # Attribute Collections (Default) ................... # SVG.Image.class ................................... # image: Image Element .............................. SVG.image.extra.content = notAllowed SVG.image.content = (SVG.Description.class | SVG.Animation.class | SVG.image.extra.content)* image = element image { SVG.Core.attrib, SVG.Conditional.attrib, SVG.Style.attrib, SVG.Presentation.attrib, SVG.GraphicalEvents.attrib, SVG.XLinkEmbed.attrib, SVG.External.attrib, attribute x { Coordinate.datatype }?, attribute y { Coordinate.datatype }?, attribute width { Length.datatype }, attribute height { Length.datatype }, [ a:defaultValue = "xMidYMid meet" ] attribute preserveAspectRatio { PreserveAspectRatioSpec.datatype }?, attribute transform { TransformList.datatype }?, SVG.image.content } # end of SVG.image.element # end of SVG.image.attlist # end of svg-image.mod # Style Module ................................................ # ....................................................................... # SVG 1.1 Style Module .................................................. # file: svg-style.mod # # This is SVG, a language for describing two-dimensional graphics in XML. # Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. # Revision: $Id: svg11-flat.rnc 3024 2011-07-10 08:29:17Z eb2mmrt $ # # This DTD module is identified by the PUBLIC and SYSTEM identifiers: # # PUBLIC "-//W3C//ELEMENTS SVG 1.1 Style//EN" # SYSTEM "http://www.w3.org/Graphics/SVG/1.1/DTD/svg-style.mod" # # ....................................................................... # Style # # style # # This module declares markup to provide support for stylesheet. # list of classes # comma-separated list of media descriptors. MediaDesc.datatype = string # style sheet data # Qualified Names (Default) ......................... # Attribute Collections (Default) ................... # SVG.Style.class ................................... # SVG.Style.attrib .................................. # style: Style Element .............................. SVG.style.extra.content = notAllowed SVG.style.content = (text | SVG.style.extra.content)* style = element style { [ a:defaultValue = "preserve" ] attribute xml:space { "preserve" }?, SVG.id.attrib, SVG.base.attrib, SVG.lang.attrib, SVG.Core.extra.attrib, attribute type { ContentType.datatype }, attribute media { MediaDesc.datatype }?, attribute title { Text.datatype }?, SVG.style.content } # end of SVG.style.element # end of SVG.style.attlist # end of svg-style.mod # Shape Module ................................................ # ....................................................................... # SVG 1.1 Shape Module .................................................. # file: svg-shape.mod # # This is SVG, a language for describing two-dimensional graphics in XML. # Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. # Revision: $Id: svg11-flat.rnc 3024 2011-07-10 08:29:17Z eb2mmrt $ # # This DTD module is identified by the PUBLIC and SYSTEM identifiers: # # PUBLIC "-//W3C//ELEMENTS SVG 1.1 Shape//EN" # SYSTEM "http://www.w3.org/Graphics/SVG/1.1/DTD/svg-shape.mod" # # ....................................................................... # Shape # # path, rect, circle, line, ellipse, polyline, polygon # # This module declares markup to provide support for graphical shapes. # a list of points Points.datatype = string # Qualified Names (Default) ......................... # Attribute Collections (Default) ................... # SVG.Shape.class ................................... # path: Path Element ................................ SVG.path.extra.content = notAllowed SVG.path.content = (SVG.Description.class | SVG.Animation.class | SVG.path.extra.content)* path = element path { SVG.Core.attrib, SVG.Conditional.attrib, SVG.Style.attrib, SVG.Presentation.attrib, SVG.GraphicalEvents.attrib, SVG.External.attrib, attribute d { PathData.datatype }, attribute pathLength { Number.datatype }?, attribute transform { TransformList.datatype }?, SVG.path.content } # end of SVG.path.element # end of SVG.path.attlist # rect: Rectangle Element ........................... SVG.rect.extra.content = notAllowed SVG.rect.content = (SVG.Description.class | SVG.Animation.class | SVG.rect.extra.content)* rect = element rect { SVG.Core.attrib, SVG.Conditional.attrib, SVG.Style.attrib, SVG.Presentation.attrib, SVG.GraphicalEvents.attrib, SVG.External.attrib, attribute x { Coordinate.datatype }?, attribute y { Coordinate.datatype }?, attribute width { Length.datatype }, attribute height { Length.datatype }, attribute rx { Length.datatype }?, attribute ry { Length.datatype }?, attribute transform { TransformList.datatype }?, SVG.rect.content } # end of SVG.rect.element # end of SVG.rect.attlist # circle: Circle Element ............................ SVG.circle.extra.content = notAllowed SVG.circle.content = (SVG.Description.class | SVG.Animation.class | SVG.circle.extra.content)* circle = element circle { SVG.Core.attrib, SVG.Conditional.attrib, SVG.Style.attrib, SVG.Presentation.attrib, SVG.GraphicalEvents.attrib, SVG.External.attrib, attribute cx { Coordinate.datatype }?, attribute cy { Coordinate.datatype }?, attribute r { Length.datatype }, attribute transform { TransformList.datatype }?, SVG.circle.content } # end of SVG.circle.element # end of SVG.circle.attlist # line: Line Element ................................ SVG.line.extra.content = notAllowed SVG.line.content = (SVG.Description.class | SVG.Animation.class | SVG.line.extra.content)* line = element line { SVG.Core.attrib, SVG.Conditional.attrib, SVG.Style.attrib, SVG.Presentation.attrib, SVG.GraphicalEvents.attrib, SVG.External.attrib, attribute x1 { Coordinate.datatype }?, attribute y1 { Coordinate.datatype }?, attribute x2 { Coordinate.datatype }?, attribute y2 { Coordinate.datatype }?, attribute transform { TransformList.datatype }?, SVG.line.content } # end of SVG.line.element # end of SVG.line.attlist # ellipse: Ellipse Element .......................... SVG.ellipse.extra.content = notAllowed SVG.ellipse.content = (SVG.Description.class | SVG.Animation.class | SVG.ellipse.extra.content)* ellipse = element ellipse { SVG.Core.attrib, SVG.Conditional.attrib, SVG.Style.attrib, SVG.Presentation.attrib, SVG.GraphicalEvents.attrib, SVG.External.attrib, attribute cx { Coordinate.datatype }?, attribute cy { Coordinate.datatype }?, attribute rx { Length.datatype }, attribute ry { Length.datatype }, attribute transform { TransformList.datatype }?, SVG.ellipse.content } # end of SVG.ellipse.element # end of SVG.ellipse.attlist # polyline: Polyline Element ........................ SVG.polyline.extra.content = notAllowed SVG.polyline.content = (SVG.Description.class | SVG.Animation.class | SVG.polyline.extra.content)* polyline = element polyline { SVG.Core.attrib, SVG.Conditional.attrib, SVG.Style.attrib, SVG.Presentation.attrib, SVG.GraphicalEvents.attrib, SVG.External.attrib, attribute points { Points.datatype }, attribute transform { TransformList.datatype }?, SVG.polyline.content } # end of SVG.polyline.element # end of SVG.polyline.attlist # polygon: Polygon Element .......................... SVG.polygon.extra.content = notAllowed SVG.polygon.content = (SVG.Description.class | SVG.Animation.class | SVG.polygon.extra.content)* polygon = element polygon { SVG.Core.attrib, SVG.Conditional.attrib, SVG.Style.attrib, SVG.Presentation.attrib, SVG.GraphicalEvents.attrib, SVG.External.attrib, attribute points { Points.datatype }, attribute transform { TransformList.datatype }?, SVG.polygon.content } # end of SVG.polygon.element # end of SVG.polygon.attlist # end of svg-shape.mod # Text Module ................................................. # ....................................................................... # SVG 1.1 Text Module ................................................... # file: svg-text.mod # # This is SVG, a language for describing two-dimensional graphics in XML. # Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. # Revision: $Id: svg11-flat.rnc 3024 2011-07-10 08:29:17Z eb2mmrt $ # # This DTD module is identified by the PUBLIC and SYSTEM identifiers: # # PUBLIC "-//W3C//ELEMENTS SVG 1.1 Text//EN" # SYSTEM "http://www.w3.org/Graphics/SVG/1.1/DTD/svg-text.mod" # # ....................................................................... # Text # # text, tspan, tref, textPath, altGlyph, altGlyphDef, altGlyphItem, # glyphRef # # This module declares markup to provide support for alternate glyph. # 'baseline-shift' property/attribute value (e.g., 'baseline', 'sub', etc.) # 'font-family' property/attribute value (i.e., list of fonts) # 'font-size' property/attribute value # 'font-size-adjust' property/attribute value # 'glyph-orientation-horizontal' property/attribute value (e.g., ) # 'glyph-orientation-vertical' property/attribute value (e.g., 'auto', ) # 'kerning' property/attribute value (e.g., 'auto', ) # 'letter-spacing' or 'word-spacing' property/attribute value (e.g., 'normal', ) # 'text-decoration' property/attribute value (e.g., 'none', 'underline') # Qualified Names (Default) ......................... # Attribute Collections (Default) ................... # SVG.Text.class .................................... # SVG.TextContent.class ............................. # SVG.Text.attrib ................................... # SVG.TextContent.attrib ............................ # SVG.Font.attrib ................................... # text: Text Element ................................ SVG.text.extra.content = notAllowed SVG.text.content = (text | SVG.Description.class | SVG.Animation.class | SVG.TextContent.class | SVG.Hyperlink.class | SVG.text.extra.content)* \text = element text { SVG.Core.attrib, SVG.Conditional.attrib, SVG.Style.attrib, SVG.Presentation.attrib, SVG.GraphicalEvents.attrib, SVG.External.attrib, attribute x { Coordinates.datatype }?, attribute y { Coordinates.datatype }?, attribute dx { Lengths.datatype }?, attribute dy { Lengths.datatype }?, attribute rotate { Numbers.datatype }?, attribute textLength { Length.datatype }?, attribute lengthAdjust { "spacing" | "spacingAndGlyphs" }?, attribute transform { TransformList.datatype }?, SVG.text.content } # end of SVG.text.element # end of SVG.text.attlist # tspan: Text Span Element .......................... SVG.tspan.extra.content = notAllowed SVG.tspan.content = (text | tspan | tref | altGlyph | animate | set | animateColor | SVG.Description.class | SVG.Hyperlink.class | SVG.tspan.extra.content)* tspan = element tspan { SVG.Core.attrib, SVG.Conditional.attrib, SVG.Style.attrib, SVG.Presentation.attrib, SVG.GraphicalEvents.attrib, SVG.External.attrib, attribute x { Coordinates.datatype }?, attribute y { Coordinates.datatype }?, attribute dx { Lengths.datatype }?, attribute dy { Lengths.datatype }?, attribute rotate { Numbers.datatype }?, attribute textLength { Length.datatype }?, attribute lengthAdjust { "spacing" | "spacingAndGlyphs" }?, SVG.tspan.content } # end of SVG.tspan.element # end of SVG.tspan.attlist # tref: Text Reference Element ...................... SVG.tref.extra.content = notAllowed SVG.tref.content = (animate | set | animateColor | SVG.Description.class | SVG.tref.extra.content)* tref = element tref { SVG.Core.attrib, SVG.Conditional.attrib, SVG.Style.attrib, SVG.Presentation.attrib, SVG.GraphicalEvents.attrib, SVG.XLinkRequired.attrib, SVG.External.attrib, attribute x { Coordinates.datatype }?, attribute y { Coordinates.datatype }?, attribute dx { Lengths.datatype }?, attribute dy { Lengths.datatype }?, attribute rotate { Numbers.datatype }?, attribute textLength { Length.datatype }?, attribute lengthAdjust { "spacing" | "spacingAndGlyphs" }?, SVG.tref.content } # end of SVG.tref.element # end of SVG.tref.attlist # textPath: Text Path Element ....................... SVG.textPath.extra.content = notAllowed SVG.textPath.content = (text | tspan | tref | altGlyph | animate | set | animateColor | SVG.Description.class | SVG.Hyperlink.class | SVG.textPath.extra.content)* textPath = element textPath { SVG.Core.attrib, SVG.Conditional.attrib, SVG.Style.attrib, SVG.Presentation.attrib, SVG.GraphicalEvents.attrib, SVG.XLinkRequired.attrib, SVG.External.attrib, attribute startOffset { Length.datatype }?, attribute textLength { Length.datatype }?, attribute lengthAdjust { "spacing" | "spacingAndGlyphs" }?, attribute method { "align" | "stretch" }?, attribute spacing { "auto" | "exact" }?, SVG.textPath.content } # end of SVG.textPath.element # end of SVG.textPath.attlist # altGlyph: Alternate Glyph Element ................. SVG.altGlyph.extra.content = notAllowed SVG.altGlyph.content = (text | SVG.altGlyph.extra.content)* altGlyph = element altGlyph { SVG.Core.attrib, SVG.Conditional.attrib, SVG.Style.attrib, SVG.Presentation.attrib, SVG.GraphicalEvents.attrib, SVG.XLink.attrib, SVG.External.attrib, attribute x { Coordinates.datatype }?, attribute y { Coordinates.datatype }?, attribute dx { Lengths.datatype }?, attribute dy { Lengths.datatype }?, attribute glyphRef { text }?, attribute format { text }?, attribute rotate { Numbers.datatype }?, SVG.altGlyph.content } # end of SVG.altGlyph.element # end of SVG.altGlyph.attlist # altGlyphDef: Alternate Glyph Definition Element ... SVG.altGlyphDef.extra.content = notAllowed SVG.altGlyphDef.content = (glyphRef+ | altGlyphItem+) | SVG.altGlyphDef.extra.content altGlyphDef = element altGlyphDef { SVG.Core.attrib, SVG.altGlyphDef.content } # end of SVG.altGlyphDef.element # end of SVG.altGlyphDef.attlist # altGlyphItem: Alternate Glyph Item Element ........ SVG.altGlyphItem.extra.content = notAllowed SVG.altGlyphItem.content = glyphRef+ | SVG.altGlyphItem.extra.content altGlyphItem = element altGlyphItem { SVG.Core.attrib, SVG.altGlyphItem.content } # end of SVG.altGlyphItem.element # end of SVG.altGlyphItem.attlist # glyphRef: Glyph Reference Element ................. SVG.glyphRef.content = empty glyphRef = element glyphRef { SVG.Core.attrib, SVG.Style.attrib, SVG.Presentation.attrib, SVG.XLink.attrib, attribute x { Number.datatype }?, attribute y { Number.datatype }?, attribute dx { Number.datatype }?, attribute dy { Number.datatype }?, attribute glyphRef { text }?, attribute format { text }?, SVG.glyphRef.content } # end of SVG.glyphRef.element # end of SVG.glyphRef.attlist # end of svg-text.mod # Marker Module ............................................... # ....................................................................... # SVG 1.1 Marker Module ................................................. # file: svg-marker.mod # # This is SVG, a language for describing two-dimensional graphics in XML. # Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. # Revision: $Id: svg11-flat.rnc 3024 2011-07-10 08:29:17Z eb2mmrt $ # # This DTD module is identified by the PUBLIC and SYSTEM identifiers: # # PUBLIC "-//W3C//ELEMENTS SVG 1.1 Marker//EN" # SYSTEM "http://www.w3.org/Graphics/SVG/1.1/DTD/svg-marker.mod" # # ....................................................................... # Marker # # marker # # This module declares markup to provide support for marker. # 'marker' property/attribute value (e.g., 'none', ) # Qualified Names (Default) ......................... # Attribute Collections (Default) ................... # SVG.Marker.class .................................. # SVG.Marker.attrib ................................. # SVG.Presentation.attrib ........................... # marker: Marker Element ............................ SVG.marker.extra.content = notAllowed SVG.marker.content = (SVG.Description.class | SVG.Animation.class | SVG.Structure.class | SVG.Conditional.class | SVG.Image.class | SVG.Style.class | SVG.Shape.class | SVG.Text.class | SVG.Marker.class | SVG.ColorProfile.class | SVG.Gradient.class | SVG.Pattern.class | SVG.Clip.class | SVG.Mask.class | SVG.Filter.class | SVG.Cursor.class | SVG.Hyperlink.class | SVG.View.class | SVG.Script.class | SVG.Font.class | SVG.Extensibility.class | SVG.marker.extra.content)* marker = element marker { SVG.Core.attrib, SVG.Style.attrib, SVG.Presentation.attrib, SVG.External.attrib, attribute refX { Coordinate.datatype }?, attribute refY { Coordinate.datatype }?, attribute markerUnits { "strokeWidth" | "userSpaceOnUse" }?, attribute markerWidth { Length.datatype }?, attribute markerHeight { Length.datatype }?, attribute orient { text }?, attribute viewBox { ViewBoxSpec.datatype }?, [ a:defaultValue = "xMidYMid meet" ] attribute preserveAspectRatio { PreserveAspectRatioSpec.datatype }?, SVG.marker.content } # end of SVG.marker.element # end of SVG.marker.attlist # end of svg-marker.mod # Color Profile Module ........................................ # ....................................................................... # SVG 1.1 Color Profile Module .......................................... # file: svg-profile.mod # # This is SVG, a language for describing two-dimensional graphics in XML. # Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. # Revision: $Id: svg11-flat.rnc 3024 2011-07-10 08:29:17Z eb2mmrt $ # # This DTD module is identified by the PUBLIC and SYSTEM identifiers: # # PUBLIC "-//W3C//ELEMENTS SVG 1.1 Color Profile//EN" # SYSTEM "http://www.w3.org/Graphics/SVG/1.1/DTD/svg-profile.mod" # # ....................................................................... # Color Profile # # color-profile # # This module declares markup to provide support for color profile. # Qualified Names (Default) ......................... # Attribute Collections (Default) ................... # SVG.ColorProfile.class ............................ # SVG.ColorProfile.attrib ........................... # color-profile: Color Profile Element .............. SVG.color-profile.extra.content = notAllowed SVG.color-profile.content = (SVG.Description.class | SVG.color-profile.extra.content)* color-profile = element color-profile { SVG.Core.attrib, SVG.XLink.attrib, attribute local { text }?, attribute name { text }, [ a:defaultValue = "auto" ] attribute rendering-intent { "auto" | "perceptual" | "relative-colorimetric" | "saturation" | "absolute-colorimetric" }?, SVG.color-profile.content } # end of SVG.color-profile.element # end of SVG.color-profile.attlist # end of svg-profile.mod # Gradient Module ............................................. # ....................................................................... # SVG 1.1 Gradient Module ............................................... # file: svg-gradient.mod # # This is SVG, a language for describing two-dimensional graphics in XML. # Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. # Revision: $Id: svg11-flat.rnc 3024 2011-07-10 08:29:17Z eb2mmrt $ # # This DTD module is identified by the PUBLIC and SYSTEM identifiers: # # PUBLIC "-//W3C//ELEMENTS SVG 1.1 Gradient//EN" # SYSTEM "http://www.w3.org/Graphics/SVG/1.1/DTD/svg-gradient.mod" # # ....................................................................... # Gradient # # linearGradient, radialGradient, stop # # This module declares markup to provide support for gradient fill. # a or a # Qualified Names (Default) ......................... # Attribute Collections (Default) ................... # SVG.Gradient.class ................................ # SVG.Gradient.attrib ............................... # linearGradient: Linear Gradient Element ........... SVG.linearGradient.extra.content = notAllowed SVG.linearGradient.content = (SVG.Description.class | stop | animate | set | animateTransform | SVG.linearGradient.extra.content)* linearGradient = element linearGradient { SVG.Core.attrib, SVG.Style.attrib, SVG.Presentation.attrib, SVG.XLink.attrib, SVG.External.attrib, attribute x1 { Coordinate.datatype }?, attribute y1 { Coordinate.datatype }?, attribute x2 { Coordinate.datatype }?, attribute y2 { Coordinate.datatype }?, attribute gradientUnits { "userSpaceOnUse" | "objectBoundingBox" }?, attribute gradientTransform { TransformList.datatype }?, attribute spreadMethod { "pad" | "reflect" | "repeat" }?, SVG.linearGradient.content } # end of SVG.linearGradient.element # end of SVG.linearGradient.attlist # radialGradient: Radial Gradient Element ........... SVG.radialGradient.extra.content = notAllowed SVG.radialGradient.content = (SVG.Description.class | stop | animate | set | animateTransform | SVG.radialGradient.extra.content)* radialGradient = element radialGradient { SVG.Core.attrib, SVG.Style.attrib, SVG.Presentation.attrib, SVG.XLink.attrib, SVG.External.attrib, attribute cx { Coordinate.datatype }?, attribute cy { Coordinate.datatype }?, attribute r { Length.datatype }?, attribute fx { Coordinate.datatype }?, attribute fy { Coordinate.datatype }?, attribute gradientUnits { "userSpaceOnUse" | "objectBoundingBox" }?, attribute gradientTransform { TransformList.datatype }?, attribute spreadMethod { "pad" | "reflect" | "repeat" }?, SVG.radialGradient.content } # end of SVG.radialGradient.element # end of SVG.radialGradient.attlist # stop: Stop Element ................................ SVG.stop.extra.content = notAllowed SVG.stop.content = (animate | set | animateColor | SVG.stop.extra.content)* stop = element stop { SVG.Core.attrib, SVG.Style.attrib, SVG.Presentation.attrib, attribute offset { NumberOrPercentage.datatype }, SVG.stop.content } # end of SVG.stop.element # end of SVG.stop.attlist # end of svg-gradient.mod # Pattern Module .............................................. # ....................................................................... # SVG 1.1 Pattern Module ................................................ # file: svg-pattern.mod # # This is SVG, a language for describing two-dimensional graphics in XML. # Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. # Revision: $Id: svg11-flat.rnc 3024 2011-07-10 08:29:17Z eb2mmrt $ # # This DTD module is identified by the PUBLIC and SYSTEM identifiers: # # PUBLIC "-//W3C//ELEMENTS SVG 1.1 Pattern//EN" # SYSTEM "http://www.w3.org/Graphics/SVG/1.1/DTD/svg-pattern.mod" # # ....................................................................... # Pattern # # pattern # # This module declares markup to provide support for pattern fill. # Qualified Names (Default) ......................... # Attribute Collections (Default) ................... # SVG.Pattern.class ................................. # SVG.Presentation.attrib ........................... # pattern: Pattern Element .......................... SVG.pattern.extra.content = notAllowed SVG.pattern.content = (SVG.Description.class | SVG.Animation.class | SVG.Structure.class | SVG.Conditional.class | SVG.Image.class | SVG.Style.class | SVG.Shape.class | SVG.Text.class | SVG.Marker.class | SVG.ColorProfile.class | SVG.Gradient.class | SVG.Pattern.class | SVG.Clip.class | SVG.Mask.class | SVG.Filter.class | SVG.Cursor.class | SVG.Hyperlink.class | SVG.View.class | SVG.Script.class | SVG.Font.class | SVG.Extensibility.class | SVG.pattern.extra.content)* pattern = element pattern { SVG.Core.attrib, SVG.Conditional.attrib, SVG.Style.attrib, SVG.Presentation.attrib, SVG.XLink.attrib, SVG.External.attrib, attribute x { Coordinate.datatype }?, attribute y { Coordinate.datatype }?, attribute width { Length.datatype }?, attribute height { Length.datatype }?, attribute patternUnits { "userSpaceOnUse" | "objectBoundingBox" }?, attribute patternContentUnits { "userSpaceOnUse" | "objectBoundingBox" }?, attribute patternTransform { TransformList.datatype }?, attribute viewBox { ViewBoxSpec.datatype }?, [ a:defaultValue = "xMidYMid meet" ] attribute preserveAspectRatio { PreserveAspectRatioSpec.datatype }?, SVG.pattern.content } # end of SVG.pattern.element # end of SVG.pattern.attlist # end of svg-pattern.mod # Clip Module ................................................. # ....................................................................... # SVG 1.1 Clip Module ................................................... # file: svg-clip.mod # # This is SVG, a language for describing two-dimensional graphics in XML. # Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. # Revision: $Id: svg11-flat.rnc 3024 2011-07-10 08:29:17Z eb2mmrt $ # # This DTD module is identified by the PUBLIC and SYSTEM identifiers: # # PUBLIC "-//W3C//ELEMENTS SVG 1.1 Clip//EN" # SYSTEM "http://www.w3.org/Graphics/SVG/1.1/DTD/svg-clip.mod" # # ....................................................................... # Clip # # clipPath # # This module declares markup to provide support for clipping. # 'clip-path' property/attribute value (e.g., 'none', ) # Qualified Names (Default) ......................... # Attribute Collections (Default) ................... # SVG.Clip.class .................................... # SVG.Clip.attrib ................................... # clipPath: Clip Path Element ....................... SVG.clipPath.extra.content = notAllowed SVG.clipPath.content = (SVG.Description.class | SVG.Animation.class | SVG.Use.class | SVG.Shape.class | \text | SVG.clipPath.extra.content)* clipPath = element clipPath { SVG.Core.attrib, SVG.Conditional.attrib, SVG.Style.attrib, SVG.Presentation.attrib, SVG.External.attrib, attribute transform { TransformList.datatype }?, attribute clipPathUnits { "userSpaceOnUse" | "objectBoundingBox" }?, SVG.clipPath.content } # end of SVG.clipPath.element # end of SVG.clipPath.attlist # end of svg-clip.mod # Mask Module ................................................. # ....................................................................... # SVG 1.1 Mask Module ................................................... # file: svg-mask.mod # # This is SVG, a language for describing two-dimensional graphics in XML. # Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. # Revision: $Id: svg11-flat.rnc 3024 2011-07-10 08:29:17Z eb2mmrt $ # # This DTD module is identified by the PUBLIC and SYSTEM identifiers: # # PUBLIC "-//W3C//ELEMENTS SVG 1.1 Mask//EN" # SYSTEM "http://www.w3.org/Graphics/SVG/1.1/DTD/svg-mask.mod" # # ....................................................................... # Mask # # mask # # This module declares markup to provide support for masking. # 'mask' property/attribute value (e.g., 'none', ) # Qualified Names (Default) ......................... # Attribute Collections (Default) ................... # SVG.Mask.class .................................... # SVG.Mask.attrib ................................... # SVG.Presentation.attrib ........................... # mask: Mask Element ................................ SVG.mask.extra.content = notAllowed SVG.mask.content = (SVG.Description.class | SVG.Animation.class | SVG.Structure.class | SVG.Conditional.class | SVG.Image.class | SVG.Style.class | SVG.Shape.class | SVG.Text.class | SVG.Marker.class | SVG.ColorProfile.class | SVG.Gradient.class | SVG.Pattern.class | SVG.Clip.class | SVG.Mask.class | SVG.Filter.class | SVG.Cursor.class | SVG.Hyperlink.class | SVG.View.class | SVG.Script.class | SVG.Font.class | SVG.Extensibility.class | SVG.mask.extra.content)* mask = element mask { SVG.Core.attrib, SVG.Conditional.attrib, SVG.Style.attrib, SVG.Presentation.attrib, SVG.External.attrib, attribute x { Coordinate.datatype }?, attribute y { Coordinate.datatype }?, attribute width { Length.datatype }?, attribute height { Length.datatype }?, attribute maskUnits { "userSpaceOnUse" | "objectBoundingBox" }?, attribute maskContentUnits { "userSpaceOnUse" | "objectBoundingBox" }?, SVG.mask.content } # end of SVG.mask.element # end of SVG.mask.attlist # end of svg-mask.mod # Filter Module ............................................... # ....................................................................... # SVG 1.1 Filter Module ................................................. # file: svg-filter.mod # # This is SVG, a language for describing two-dimensional graphics in XML. # Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. # Revision: $Id: svg11-flat.rnc 3024 2011-07-10 08:29:17Z eb2mmrt $ # # This DTD module is identified by the PUBLIC and SYSTEM identifiers: # # PUBLIC "-//W3C//ELEMENTS SVG 1.1 Filter//EN" # SYSTEM "http://www.w3.org/Graphics/SVG/1.1/DTD/svg-filter.mod" # # ....................................................................... # Filter # # filter, feBlend, feColorMatrix, feComponentTransfer, feComposite, # feConvolveMatrix, feDiffuseLighting, feDisplacementMap, feFlood, # feGaussianBlur, feImage, feMerge, feMergeNode, feMorphology, feOffset, # feSpecularLighting, feTile, feTurbulence, feDistantLight, fePointLight, # feSpotLight, feFuncR, feFuncG, feFuncB, feFuncA # # This module declares markup to provide support for filter effect. # 'filter' property/attribute value (e.g., 'none', ) # list of s, but at least one and at most two # Qualified Names (Default) ......................... # Attribute Collections (Default) ................... # SVG.Filter.class .................................. # SVG.FilterPrimitive.class ......................... # SVG.Filter.attrib ................................. # SVG.FilterColor.attrib ............................ # SVG.FilterPrimitive.attrib ........................ SVG.FilterPrimitive.extra.attrib = empty SVG.FilterPrimitive.attrib = attribute x { Coordinate.datatype }?, attribute y { Coordinate.datatype }?, attribute width { Length.datatype }?, attribute height { Length.datatype }?, attribute result { text }?, SVG.FilterPrimitive.extra.attrib # SVG.FilterPrimitiveWithIn.attrib .................. SVG.FilterPrimitiveWithIn.extra.attrib = empty SVG.FilterPrimitiveWithIn.attrib = SVG.FilterPrimitive.attrib, attribute in { text }?, SVG.FilterPrimitiveWithIn.extra.attrib # SVG.Presentation.attrib ........................... # filter: Filter Element ............................ SVG.filter.extra.content = notAllowed SVG.filter.content = (SVG.Description.class | animate | set | SVG.FilterPrimitive.class | SVG.filter.extra.content)* filter = element filter { SVG.Core.attrib, SVG.Style.attrib, SVG.Presentation.attrib, SVG.XLink.attrib, SVG.External.attrib, attribute x { Coordinate.datatype }?, attribute y { Coordinate.datatype }?, attribute width { Length.datatype }?, attribute height { Length.datatype }?, attribute filterRes { NumberOptionalNumber.datatype }?, attribute filterUnits { "userSpaceOnUse" | "objectBoundingBox" }?, attribute primitiveUnits { "userSpaceOnUse" | "objectBoundingBox" }?, SVG.filter.content } # end of SVG.filter.element # end of SVG.filter.attlist # feBlend: Filter Effect Blend Element .............. SVG.feBlend.extra.content = notAllowed SVG.feBlend.content = (animate | set | SVG.feBlend.extra.content)* feBlend = element feBlend { SVG.Core.attrib, SVG.Style.attrib, SVG.Presentation.attrib, SVG.FilterPrimitiveWithIn.attrib, attribute in2 { text }, [ a:defaultValue = "normal" ] attribute mode { "normal" | "multiply" | "screen" | "darken" | "lighten" }?, SVG.feBlend.content } # end of SVG.feBlend.element # end of SVG.feBlend.attlist # feColorMatrix: Filter Effect Color Matrix Element . SVG.feColorMatrix.extra.content = notAllowed SVG.feColorMatrix.content = (animate | set | SVG.feColorMatrix.extra.content)* feColorMatrix = element feColorMatrix { SVG.Core.attrib, SVG.Style.attrib, SVG.Presentation.attrib, SVG.FilterPrimitiveWithIn.attrib, [ a:defaultValue = "matrix" ] attribute type { "matrix" | "saturate" | "hueRotate" | "luminanceToAlpha" }?, attribute values { text }?, SVG.feColorMatrix.content } # end of SVG.feColorMatrix.element # end of SVG.feColorMatrix.attlist # feComponentTransfer: Filter Effect Component Transfer Element SVG.feComponentTransfer.extra.content = empty SVG.feComponentTransfer.content = feFuncR?, feFuncG?, feFuncB?, feFuncA?, SVG.feComponentTransfer.extra.content feComponentTransfer = element feComponentTransfer { SVG.Core.attrib, SVG.Style.attrib, SVG.Presentation.attrib, SVG.FilterPrimitiveWithIn.attrib, SVG.feComponentTransfer.content } # end of SVG.feComponentTransfer.element # end of SVG.feComponentTransfer.attlist # feComposite: Filter Effect Composite Element ...... SVG.feComposite.extra.content = notAllowed SVG.feComposite.content = (animate | set | SVG.feComposite.extra.content)* feComposite = element feComposite { SVG.Core.attrib, SVG.Style.attrib, SVG.Presentation.attrib, SVG.FilterPrimitiveWithIn.attrib, attribute in2 { text }, [ a:defaultValue = "over" ] attribute operator { "over" | "in" | "out" | "atop" | "xor" | "arithmetic" }?, attribute k1 { Number.datatype }?, attribute k2 { Number.datatype }?, attribute k3 { Number.datatype }?, attribute k4 { Number.datatype }?, SVG.feComposite.content } # end of SVG.feComposite.element # end of SVG.feComposite.attlist # feConvolveMatrix: Filter Effect Convolve Matrix Element SVG.feConvolveMatrix.extra.content = notAllowed SVG.feConvolveMatrix.content = (animate | set | SVG.feConvolveMatrix.extra.content)* feConvolveMatrix = element feConvolveMatrix { SVG.Core.attrib, SVG.Style.attrib, SVG.Presentation.attrib, SVG.FilterPrimitiveWithIn.attrib, attribute order { NumberOptionalNumber.datatype }?, attribute kernelMatrix { text }, attribute divisor { Number.datatype }?, attribute bias { Number.datatype }?, attribute targetX { Integer.datatype }?, attribute targetY { Integer.datatype }?, [ a:defaultValue = "duplicate" ] attribute edgeMode { "duplicate" | "wrap" | "none" }?, attribute kernelUnitLength { NumberOptionalNumber.datatype }?, attribute preserveAlpha { Boolean.datatype }?, SVG.feConvolveMatrix.content } # end of SVG.feConvolveMatrix.element # end of SVG.feConvolveMatrix.attlist # feDiffuseLighting: Filter Effect Diffuse Lighting Element SVG.feDiffuseLighting.extra.content = notAllowed SVG.feDiffuseLighting.content = (feDistantLight | fePointLight | feSpotLight), (animate | set | animateColor | SVG.feDiffuseLighting.extra.content)* feDiffuseLighting = element feDiffuseLighting { SVG.Core.attrib, SVG.Style.attrib, SVG.Presentation.attrib, SVG.FilterPrimitiveWithIn.attrib, attribute surfaceScale { Number.datatype }?, attribute diffuseConstant { Number.datatype }?, attribute kernelUnitLength { NumberOptionalNumber.datatype }?, SVG.feDiffuseLighting.content } # end of SVG.feDiffuseLighting.element # end of SVG.feDiffuseLighting.attlist # feDisplacementMap: Filter Effect Displacement Map Element SVG.feDisplacementMap.extra.content = notAllowed SVG.feDisplacementMap.content = (animate | set | SVG.feDisplacementMap.extra.content)* feDisplacementMap = element feDisplacementMap { SVG.Core.attrib, SVG.Style.attrib, SVG.Presentation.attrib, SVG.FilterPrimitiveWithIn.attrib, attribute in2 { text }, attribute scale { Number.datatype }?, [ a:defaultValue = "A" ] attribute xChannelSelector { "R" | "G" | "B" | "A" }?, [ a:defaultValue = "A" ] attribute yChannelSelector { "R" | "G" | "B" | "A" }?, SVG.feDisplacementMap.content } # end of SVG.feDisplacementMap.element # end of SVG.feDisplacementMap.attlist # feFlood: Filter Effect Flood Element .............. SVG.feFlood.extra.content = notAllowed SVG.feFlood.content = (animate | set | animateColor | SVG.feFlood.extra.content)* feFlood = element feFlood { SVG.Core.attrib, SVG.Style.attrib, SVG.Presentation.attrib, SVG.FilterPrimitive.attrib, SVG.feFlood.content } # end of SVG.feFlood.element # end of SVG.feFlood.attlist # feGaussianBlur: Filter Effect Gaussian Blur Element SVG.feGaussianBlur.extra.content = notAllowed SVG.feGaussianBlur.content = (animate | set | SVG.feGaussianBlur.extra.content)* feGaussianBlur = element feGaussianBlur { SVG.Core.attrib, SVG.Style.attrib, SVG.Presentation.attrib, SVG.FilterPrimitiveWithIn.attrib, attribute stdDeviation { NumberOptionalNumber.datatype }?, SVG.feGaussianBlur.content } # end of SVG.feGaussianBlur.element # end of SVG.feGaussianBlur.attlist # feImage: Filter Effect Image Element .............. SVG.feImage.extra.content = notAllowed SVG.feImage.content = (animate | set | animateTransform | SVG.feImage.extra.content)* feImage = element feImage { SVG.Core.attrib, SVG.Style.attrib, SVG.Presentation.attrib, SVG.FilterPrimitive.attrib, SVG.XLinkEmbed.attrib, SVG.External.attrib, [ a:defaultValue = "xMidYMid meet" ] attribute preserveAspectRatio { PreserveAspectRatioSpec.datatype }?, SVG.feImage.content } # end of SVG.feImage.element # end of SVG.feImage.attlist # feMerge: Filter Effect Merge Element .............. SVG.feMerge.extra.content = notAllowed SVG.feMerge.content = (feMergeNode | SVG.feMerge.extra.content)* feMerge = element feMerge { SVG.Core.attrib, SVG.Style.attrib, SVG.Presentation.attrib, SVG.FilterPrimitive.attrib, SVG.feMerge.content } # end of SVG.feMerge.element # end of SVG.feMerge.attlist # feMergeNode: Filter Effect Merge Node Element ..... SVG.feMergeNode.extra.content = notAllowed SVG.feMergeNode.content = (animate | set | SVG.feMergeNode.extra.content)* feMergeNode = element feMergeNode { SVG.Core.attrib, attribute in { text }?, SVG.feMergeNode.content } # end of SVG.feMergeNode.element # end of SVG.feMergeNode.attlist # feMorphology: Filter Effect Morphology Element .... SVG.feMorphology.extra.content = notAllowed SVG.feMorphology.content = (animate | set | SVG.feMorphology.extra.content)* feMorphology = element feMorphology { SVG.Core.attrib, SVG.Style.attrib, SVG.Presentation.attrib, SVG.FilterPrimitiveWithIn.attrib, [ a:defaultValue = "erode" ] attribute operator { "erode" | "dilate" }?, attribute radius { NumberOptionalNumber.datatype }?, SVG.feMorphology.content } # end of SVG.feMorphology.element # end of SVG.feMorphology.attlist # feOffset: Filter Effect Offset Element ............ SVG.feOffset.extra.content = notAllowed SVG.feOffset.content = (animate | set | SVG.feOffset.extra.content)* feOffset = element feOffset { SVG.Core.attrib, SVG.Style.attrib, SVG.Presentation.attrib, SVG.FilterPrimitiveWithIn.attrib, attribute dx { Number.datatype }?, attribute dy { Number.datatype }?, SVG.feOffset.content } # end of SVG.feOffset.element # end of SVG.feOffset.attlist # feSpecularLighting: Filter Effect Specular Lighting Element SVG.feSpecularLighting.extra.content = notAllowed SVG.feSpecularLighting.content = (feDistantLight | fePointLight | feSpotLight), (animate | set | animateColor | SVG.feSpecularLighting.extra.content)* feSpecularLighting = element feSpecularLighting { SVG.Core.attrib, SVG.Style.attrib, SVG.Presentation.attrib, SVG.FilterPrimitiveWithIn.attrib, attribute surfaceScale { Number.datatype }?, attribute specularConstant { Number.datatype }?, attribute specularExponent { Number.datatype }?, attribute kernelUnitLength { NumberOptionalNumber.datatype }?, SVG.feSpecularLighting.content } # end of SVG.feSpecularLighting.element # end of SVG.feSpecularLighting.attlist # feTile: Filter Effect Tile Element ................ SVG.feTile.extra.content = notAllowed SVG.feTile.content = (animate | set | SVG.feTile.extra.content)* feTile = element feTile { SVG.Core.attrib, SVG.Style.attrib, SVG.Presentation.attrib, SVG.FilterPrimitiveWithIn.attrib, SVG.feTile.content } # end of SVG.feTile.element # end of SVG.feTile.attlist # feTurbulence: Filter Effect Turbulence Element .... SVG.feTurbulence.extra.content = notAllowed SVG.feTurbulence.content = (animate | set | SVG.feTurbulence.extra.content)* feTurbulence = element feTurbulence { SVG.Core.attrib, SVG.Style.attrib, SVG.Presentation.attrib, SVG.FilterPrimitive.attrib, attribute baseFrequency { NumberOptionalNumber.datatype }?, attribute numOctaves { Integer.datatype }?, attribute seed { Number.datatype }?, [ a:defaultValue = "noStitch" ] attribute stitchTiles { "stitch" | "noStitch" }?, [ a:defaultValue = "turbulence" ] attribute type { "fractalNoise" | "turbulence" }?, SVG.feTurbulence.content } # end of SVG.feTurbulence.element # end of SVG.feTurbulence.attlist # feDistantLight: Filter Effect Distant Light Element SVG.feDistantLight.extra.content = notAllowed SVG.feDistantLight.content = (animate | set | SVG.feDistantLight.extra.content)* feDistantLight = element feDistantLight { SVG.Core.attrib, attribute azimuth { Number.datatype }?, attribute elevation { Number.datatype }?, SVG.feDistantLight.content } # end of SVG.feDistantLight.element # end of SVG.feDistantLight.attlist # fePointLight: Filter Effect Point Light Element ... SVG.fePointLight.extra.content = notAllowed SVG.fePointLight.content = (animate | set | SVG.fePointLight.extra.content)* fePointLight = element fePointLight { SVG.Core.attrib, attribute x { Number.datatype }?, attribute y { Number.datatype }?, attribute z { Number.datatype }?, SVG.fePointLight.content } # end of SVG.fePointLight.element # end of SVG.fePointLight.attlist # feSpotLight: Filter Effect Spot Light Element ..... SVG.feSpotLight.extra.content = notAllowed SVG.feSpotLight.content = (animate | set | SVG.feSpotLight.extra.content)* feSpotLight = element feSpotLight { SVG.Core.attrib, attribute x { Number.datatype }?, attribute y { Number.datatype }?, attribute z { Number.datatype }?, attribute pointsAtX { Number.datatype }?, attribute pointsAtY { Number.datatype }?, attribute pointsAtZ { Number.datatype }?, attribute specularExponent { Number.datatype }?, attribute limitingConeAngle { Number.datatype }?, SVG.feSpotLight.content } # end of SVG.feSpotLight.element # end of SVG.feSpotLight.attlist # feFuncR: Filter Effect Function Red Element ....... SVG.feFuncR.extra.content = notAllowed SVG.feFuncR.content = (animate | set | SVG.feFuncR.extra.content)* feFuncR = element feFuncR { SVG.Core.attrib, attribute type { "identity" | "table" | "discrete" | "linear" | "gamma" }, attribute tableValues { text }?, attribute slope { Number.datatype }?, attribute intercept { Number.datatype }?, attribute amplitude { Number.datatype }?, attribute exponent { Number.datatype }?, attribute offset { Number.datatype }?, SVG.feFuncR.content } # end of SVG.feFuncR.element # end of SVG.feFuncR.attlist # feFuncG: Filter Effect Function Green Element ..... SVG.feFuncG.extra.content = notAllowed SVG.feFuncG.content = (animate | set | SVG.feFuncG.extra.content)* feFuncG = element feFuncG { SVG.Core.attrib, attribute type { "identity" | "table" | "discrete" | "linear" | "gamma" }, attribute tableValues { text }?, attribute slope { Number.datatype }?, attribute intercept { Number.datatype }?, attribute amplitude { Number.datatype }?, attribute exponent { Number.datatype }?, attribute offset { Number.datatype }?, SVG.feFuncG.content } # end of SVG.feFuncG.element # end of SVG.feFuncG.attlist # feFuncB: Filter Effect Function Blue Element ...... SVG.feFuncB.extra.content = notAllowed SVG.feFuncB.content = (animate | set | SVG.feFuncB.extra.content)* feFuncB = element feFuncB { SVG.Core.attrib, attribute type { "identity" | "table" | "discrete" | "linear" | "gamma" }, attribute tableValues { text }?, attribute slope { Number.datatype }?, attribute intercept { Number.datatype }?, attribute amplitude { Number.datatype }?, attribute exponent { Number.datatype }?, attribute offset { Number.datatype }?, SVG.feFuncB.content } # end of SVG.feFuncB.element # end of SVG.feFuncB.attlist # feFuncA: Filter Effect Function Alpha Element ..... SVG.feFuncA.extra.content = notAllowed SVG.feFuncA.content = (animate | set | SVG.feFuncA.extra.content)* feFuncA = element feFuncA { SVG.Core.attrib, attribute type { "identity" | "table" | "discrete" | "linear" | "gamma" }, attribute tableValues { text }?, attribute slope { Number.datatype }?, attribute intercept { Number.datatype }?, attribute amplitude { Number.datatype }?, attribute exponent { Number.datatype }?, attribute offset { Number.datatype }?, SVG.feFuncA.content } # end of SVG.feFuncA.element # end of SVG.feFuncA.attlist # end of svg-filter.mod # Cursor Module ............................................... # ....................................................................... # SVG 1.1 Cursor Module ................................................. # file: svg-cursor.mod # # This is SVG, a language for describing two-dimensional graphics in XML. # Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. # Revision: $Id: svg11-flat.rnc 3024 2011-07-10 08:29:17Z eb2mmrt $ # # This DTD module is identified by the PUBLIC and SYSTEM identifiers: # # PUBLIC "-//W3C//ELEMENTS SVG 1.1 Cursor//EN" # SYSTEM "http://www.w3.org/Graphics/SVG/1.1/DTD/svg-cursor.mod" # # ....................................................................... # Cursor # # cursor # # This module declares markup to provide support for cursor. # 'cursor' property/attribute value (e.g., 'crosshair', ) # Qualified Names (Default) ......................... # Attribute Collections (Default) ................... # SVG.Cursor.class .................................. # SVG.Cursor.attrib ................................. # cursor: Cursor Element ............................ SVG.cursor.extra.content = notAllowed SVG.cursor.content = (SVG.Description.class | SVG.cursor.extra.content)* cursor = element cursor { SVG.Core.attrib, SVG.Conditional.attrib, SVG.XLinkRequired.attrib, SVG.External.attrib, attribute x { Coordinate.datatype }?, attribute y { Coordinate.datatype }?, SVG.cursor.content } # end of SVG.cursor.element # end of SVG.cursor.attlist # end of svg-cursor.mod # Hyperlinking Module ......................................... # ....................................................................... # SVG 1.1 Hyperlinking Module ........................................... # file: svg-hyperlink.mod # # This is SVG, a language for describing two-dimensional graphics in XML. # Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. # Revision: $Id: svg11-flat.rnc 3024 2011-07-10 08:29:17Z eb2mmrt $ # # This DTD module is identified by the PUBLIC and SYSTEM identifiers: # # PUBLIC "-//W3C//ELEMENTS SVG 1.1 Hyperlinking//EN" # SYSTEM "http://www.w3.org/Graphics/SVG/1.1/DTD/svg-hyperlink.mod" # # ....................................................................... # Hyperlinking # # a # # This module declares markup to provide support for hyper linking. # link to this target LinkTarget.datatype = xsd:NMTOKEN # Qualified Names (Default) ......................... # Attribute Collections (Default) ................... # SVG.Hyperlink.class ............................... # SVG.Presentation.attrib ........................... # a: Anchor Element ................................. SVG.a.extra.content = notAllowed SVG.a.content = (text | SVG.Description.class | SVG.Animation.class | SVG.Structure.class | SVG.Conditional.class | SVG.Image.class | SVG.Style.class | SVG.Shape.class | SVG.Text.class | SVG.Marker.class | SVG.ColorProfile.class | SVG.Gradient.class | SVG.Pattern.class | SVG.Clip.class | SVG.Mask.class | SVG.Filter.class | SVG.Cursor.class | SVG.Hyperlink.class | SVG.View.class | SVG.Script.class | SVG.Font.class | SVG.Extensibility.class | SVG.a.extra.content)* a = element a { SVG.Core.attrib, SVG.Conditional.attrib, SVG.Style.attrib, SVG.Presentation.attrib, SVG.GraphicalEvents.attrib, SVG.XLinkReplace.attrib, SVG.External.attrib, attribute transform { TransformList.datatype }?, attribute target { LinkTarget.datatype }?, SVG.a.content } # end of SVG.a.element # end of SVG.a.attlist # end of svg-hyperlink.mod # View Module ................................................. # ....................................................................... # SVG 1.1 View Module ................................................... # file: svg-view.mod # # This is SVG, a language for describing two-dimensional graphics in XML. # Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. # Revision: $Id: svg11-flat.rnc 3024 2011-07-10 08:29:17Z eb2mmrt $ # # This DTD module is identified by the PUBLIC and SYSTEM identifiers: # # PUBLIC "-//W3C//ELEMENTS SVG 1.1 View//EN" # SYSTEM "http://www.w3.org/Graphics/SVG/1.1/DTD/svg-view.mod" # # ....................................................................... # View # # view # # This module declares markup to provide support for view. # Qualified Names (Default) ......................... # Attribute Collections (Default) ................... # SVG.View.class .................................... # view: View Element ................................ SVG.view.extra.content = notAllowed SVG.view.content = (SVG.Description.class | SVG.view.extra.content)* view = element view { SVG.Core.attrib, SVG.External.attrib, attribute viewBox { ViewBoxSpec.datatype }?, [ a:defaultValue = "xMidYMid meet" ] attribute preserveAspectRatio { PreserveAspectRatioSpec.datatype }?, [ a:defaultValue = "magnify" ] attribute zoomAndPan { "disable" | "magnify" }?, attribute viewTarget { text }?, SVG.view.content } # end of SVG.view.element # end of SVG.view.attlist # end of svg-view.mod # Scripting Module ............................................ # ....................................................................... # SVG 1.1 Scripting Module .............................................. # file: svg-script.mod # # This is SVG, a language for describing two-dimensional graphics in XML. # Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. # Revision: $Id: svg11-flat.rnc 3024 2011-07-10 08:29:17Z eb2mmrt $ # # This DTD module is identified by the PUBLIC and SYSTEM identifiers: # # PUBLIC "-//W3C//ELEMENTS SVG 1.1 Scripting//EN" # SYSTEM "http://www.w3.org/Graphics/SVG/1.1/DTD/svg-script.mod" # # ....................................................................... # Scripting # # script # # This module declares markup to provide support for scripting. # Qualified Names (Default) ......................... # Attribute Collections (Default) ................... # SVG.Script.class .................................. # script: Script Element ............................ SVG.script.extra.content = notAllowed SVG.script.content = (text | SVG.script.extra.content)* script = element script { SVG.Core.attrib, SVG.XLink.attrib, SVG.External.attrib, attribute type { ContentType.datatype }, SVG.script.content } # end of SVG.script.element # end of SVG.script.attlist # end of svg-script.mod # Animation Module ............................................ # ....................................................................... # SVG 1.1 Animation Module .............................................. # file: svg-animation.mod # # This is SVG, a language for describing two-dimensional graphics in XML. # Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. # Revision: $Id: svg11-flat.rnc 3024 2011-07-10 08:29:17Z eb2mmrt $ # # This DTD module is identified by the PUBLIC and SYSTEM identifiers: # # PUBLIC "-//W3C//ELEMENTS SVG 1.1 Animation//EN" # SYSTEM "http://www.w3.org/Graphics/SVG/1.1/DTD/svg-animation.mod" # # ....................................................................... # Animation # # animate, set, animateMotion, animateColor, animateTransform, mpath # # This module declares markup to provide support for animation. # Qualified Names (Default) ......................... # Attribute Collections (Default) ................... # SVG.Animation.class ............................... # SVG.Animation.attrib .............................. SVG.Animation.extra.attrib = empty SVG.Animation.attrib = SVG.XLink.attrib, SVG.Animation.extra.attrib # SVG.AnimationAttribute.attrib ..................... SVG.AnimationAttribute.extra.attrib = empty SVG.AnimationAttribute.attrib = attribute attributeName { text }, attribute attributeType { text }?, SVG.AnimationAttribute.extra.attrib # SVG.AnimationTiming.attrib ........................ SVG.AnimationTiming.extra.attrib = empty SVG.AnimationTiming.attrib = attribute begin { text }?, attribute dur { text }?, attribute end { text }?, attribute min { text }?, attribute max { text }?, [ a:defaultValue = "always" ] attribute restart { "always" | "never" | "whenNotActive" }?, attribute repeatCount { text }?, attribute repeatDur { text }?, [ a:defaultValue = "remove" ] attribute fill { "remove" | "freeze" }?, SVG.AnimationTiming.extra.attrib # SVG.AnimationValue.attrib ......................... SVG.AnimationValue.extra.attrib = empty SVG.AnimationValue.attrib = [ a:defaultValue = "linear" ] attribute calcMode { "discrete" | "linear" | "paced" | "spline" }?, attribute values { text }?, attribute keyTimes { text }?, attribute keySplines { text }?, attribute from { text }?, attribute to { text }?, attribute by { text }?, SVG.AnimationValue.extra.attrib # SVG.AnimationAddtion.attrib ....................... SVG.AnimationAddtion.extra.attrib = empty SVG.AnimationAddtion.attrib = [ a:defaultValue = "replace" ] attribute additive { "replace" | "sum" }?, [ a:defaultValue = "none" ] attribute accumulate { "none" | "sum" }?, SVG.AnimationAddtion.extra.attrib # animate: Animate Element .......................... SVG.animate.extra.content = notAllowed SVG.animate.content = (SVG.Description.class | SVG.animate.extra.content)* animate = element animate { SVG.Core.attrib, SVG.Conditional.attrib, SVG.AnimationEvents.attrib, SVG.External.attrib, SVG.Animation.attrib, SVG.AnimationAttribute.attrib, SVG.AnimationTiming.attrib, SVG.AnimationValue.attrib, SVG.AnimationAddtion.attrib, SVG.animate.content } # end of SVG.animate.element # end of SVG.animate.attlist # set: Set Element .................................. SVG.set.extra.content = notAllowed SVG.set.content = (SVG.Description.class | SVG.set.extra.content)* set = element set { SVG.Core.attrib, SVG.Conditional.attrib, SVG.AnimationEvents.attrib, SVG.External.attrib, SVG.Animation.attrib, SVG.AnimationAttribute.attrib, SVG.AnimationTiming.attrib, attribute to { text }?, SVG.set.content } # end of SVG.set.element # end of SVG.set.attlist # animateMotion: Animate Motion Element ............. SVG.animateMotion.extra.content = notAllowed SVG.animateMotion.content = (mpath, (SVG.Description.class | SVG.animateMotion.extra.content)*) | ((SVG.Description.class | SVG.animateMotion.extra.content)+, mpath, ((SVG.Description.class | SVG.animateMotion.extra.content)*)?) animateMotion = element animateMotion { SVG.Core.attrib, SVG.Conditional.attrib, SVG.AnimationEvents.attrib, SVG.External.attrib, SVG.Animation.attrib, SVG.AnimationTiming.attrib, SVG.AnimationAddtion.attrib, [ a:defaultValue = "paced" ] attribute calcMode { "discrete" | "linear" | "paced" | "spline" }?, attribute values { text }?, attribute keyTimes { text }?, attribute keySplines { text }?, attribute from { text }?, attribute to { text }?, attribute by { text }?, attribute path { text }?, attribute keyPoints { text }?, attribute rotate { text }?, attribute origin { text }?, SVG.animateMotion.content } # end of SVG.animateMotion.element # end of SVG.animateMotion.attlist # animateColor: Animate Color Element ............... SVG.animateColor.extra.content = notAllowed SVG.animateColor.content = (SVG.Description.class | SVG.animateColor.extra.content)* animateColor = element animateColor { SVG.Core.attrib, SVG.Conditional.attrib, SVG.AnimationEvents.attrib, SVG.External.attrib, SVG.Animation.attrib, SVG.AnimationAttribute.attrib, SVG.AnimationTiming.attrib, SVG.AnimationValue.attrib, SVG.AnimationAddtion.attrib, SVG.animateColor.content } # end of SVG.animateColor.element # end of SVG.animateColor.attlist # animateTransform: Animate Transform Element ....... SVG.animateTransform.extra.content = notAllowed SVG.animateTransform.content = (SVG.Description.class | SVG.animateTransform.extra.content)* animateTransform = element animateTransform { SVG.Core.attrib, SVG.Conditional.attrib, SVG.AnimationEvents.attrib, SVG.External.attrib, SVG.Animation.attrib, SVG.AnimationAttribute.attrib, SVG.AnimationTiming.attrib, SVG.AnimationValue.attrib, SVG.AnimationAddtion.attrib, [ a:defaultValue = "translate" ] attribute type { "translate" | "scale" | "rotate" | "skewX" | "skewY" }?, SVG.animateTransform.content } # end of SVG.animateTransform.element # end of SVG.animateTransform.attlist # mpath: Motion Path Element ........................ SVG.mpath.extra.content = notAllowed SVG.mpath.content = (SVG.Description.class | SVG.mpath.extra.content)* mpath = element mpath { SVG.Core.attrib, SVG.XLinkRequired.attrib, SVG.External.attrib, SVG.mpath.content } # end of SVG.mpath.element # end of SVG.mpath.attlist # end of svg-animation.mod # Font Module ................................................. # ....................................................................... # SVG 1.1 Font Module ................................................... # file: svg-font.mod # # This is SVG, a language for describing two-dimensional graphics in XML. # Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. # Revision: $Id: svg11-flat.rnc 3024 2011-07-10 08:29:17Z eb2mmrt $ # # This DTD module is identified by the PUBLIC and SYSTEM identifiers: # # PUBLIC "-//W3C//ELEMENTS SVG 1.1 Font//EN" # SYSTEM "http://www.w3.org/Graphics/SVG/1.1/DTD/svg-font.mod" # # ....................................................................... # Font # # font, font-face, glyph, missing-glyph, hkern, vkern, font-face-src, # font-face-uri, font-face-format, font-face-name # # This module declares markup to provide support for template. # Qualified Names (Default) ......................... # Attribute Collections (Default) ................... # SVG.Font.class .................................... # SVG.Presentation.attrib ........................... # font: Font Element ................................ SVG.font.extra.content = notAllowed SVG.font.content = (SVG.Description.class | font-face | missing-glyph | glyph | hkern | vkern | SVG.font.extra.content)* font = element font { SVG.Core.attrib, SVG.Style.attrib, SVG.Presentation.attrib, SVG.External.attrib, attribute horiz-origin-x { Number.datatype }?, attribute horiz-origin-y { Number.datatype }?, attribute horiz-adv-x { Number.datatype }, attribute vert-origin-x { Number.datatype }?, attribute vert-origin-y { Number.datatype }?, attribute vert-adv-y { Number.datatype }?, SVG.font.content } # end of SVG.font.element # end of SVG.font.attlist # font-face: Font Face Element ...................... SVG.font-face.extra.content = notAllowed SVG.font-face.content = empty | (font-face-src, (SVG.Description.class | SVG.font-face.extra.content)*) | ((SVG.Description.class | SVG.font-face.extra.content)+, font-face-src, ((SVG.Description.class | SVG.font-face.extra.content)*)?) font-face = element font-face { SVG.Core.attrib, attribute font-family { text }?, attribute font-style { text }?, attribute font-variant { text }?, attribute font-weight { text }?, attribute font-stretch { text }?, attribute font-size { text }?, attribute unicode-range { text }?, attribute units-per-em { Number.datatype }?, attribute panose-1 { text }?, attribute stemv { Number.datatype }?, attribute stemh { Number.datatype }?, attribute slope { Number.datatype }?, attribute cap-height { Number.datatype }?, attribute x-height { Number.datatype }?, attribute accent-height { Number.datatype }?, attribute ascent { Number.datatype }?, attribute descent { Number.datatype }?, attribute widths { text }?, attribute bbox { text }?, attribute ideographic { Number.datatype }?, attribute alphabetic { Number.datatype }?, attribute mathematical { Number.datatype }?, attribute hanging { Number.datatype }?, attribute v-ideographic { Number.datatype }?, attribute v-alphabetic { Number.datatype }?, attribute v-mathematical { Number.datatype }?, attribute v-hanging { Number.datatype }?, attribute underline-position { Number.datatype }?, attribute underline-thickness { Number.datatype }?, attribute strikethrough-position { Number.datatype }?, attribute strikethrough-thickness { Number.datatype }?, attribute overline-position { Number.datatype }?, attribute overline-thickness { Number.datatype }?, SVG.font-face.content } # end of SVG.font-face.element # end of SVG.font-face.attlist # glyph: Glyph Element .............................. SVG.glyph.extra.content = notAllowed SVG.glyph.content = (SVG.Description.class | SVG.Animation.class | SVG.Structure.class | SVG.Conditional.class | SVG.Image.class | SVG.Style.class | SVG.Shape.class | SVG.Text.class | SVG.Marker.class | SVG.ColorProfile.class | SVG.Gradient.class | SVG.Pattern.class | SVG.Clip.class | SVG.Mask.class | SVG.Filter.class | SVG.Cursor.class | SVG.Hyperlink.class | SVG.View.class | SVG.Script.class | SVG.Font.class | SVG.Extensibility.class | SVG.glyph.extra.content)* glyph = element glyph { SVG.Core.attrib, SVG.Style.attrib, SVG.Presentation.attrib, attribute unicode { text }?, attribute glyph-name { text }?, attribute d { PathData.datatype }?, attribute orientation { text }?, attribute arabic-form { text }?, attribute lang { LanguageCodes.datatype }?, attribute horiz-adv-x { Number.datatype }?, attribute vert-origin-x { Number.datatype }?, attribute vert-origin-y { Number.datatype }?, attribute vert-adv-y { Number.datatype }?, SVG.glyph.content } # end of SVG.glyph.element # end of SVG.glyph.attlist # missing-glyph: Missing Glyph Element .............. SVG.missing-glyph.extra.content = notAllowed SVG.missing-glyph.content = (SVG.Description.class | SVG.Animation.class | SVG.Structure.class | SVG.Conditional.class | SVG.Image.class | SVG.Style.class | SVG.Shape.class | SVG.Text.class | SVG.Marker.class | SVG.ColorProfile.class | SVG.Gradient.class | SVG.Pattern.class | SVG.Clip.class | SVG.Mask.class | SVG.Filter.class | SVG.Cursor.class | SVG.Hyperlink.class | SVG.View.class | SVG.Script.class | SVG.Font.class | SVG.Extensibility.class | SVG.missing-glyph.extra.content)* missing-glyph = element missing-glyph { SVG.Core.attrib, SVG.Style.attrib, SVG.Presentation.attrib, attribute d { PathData.datatype }?, attribute horiz-adv-x { Number.datatype }?, attribute vert-origin-x { Number.datatype }?, attribute vert-origin-y { Number.datatype }?, attribute vert-adv-y { Number.datatype }?, SVG.missing-glyph.content } # end of SVG.missing-glyph.element # end of SVG.missing-glyph.attlist # hkern: Horizontal Kerning Element ................. SVG.hkern.content = empty hkern = element hkern { SVG.Core.attrib, attribute u1 { text }?, attribute g1 { text }?, attribute u2 { text }?, attribute g2 { text }?, attribute k { Number.datatype }, SVG.hkern.content } # end of SVG.hkern.element # end of SVG.hkern.attlist # vkern: Vertical Kerning Element ................... SVG.vkern.content = empty vkern = element vkern { SVG.Core.attrib, attribute u1 { text }?, attribute g1 { text }?, attribute u2 { text }?, attribute g2 { text }?, attribute k { Number.datatype }, SVG.vkern.content } # end of SVG.vkern.element # end of SVG.vkern.attlist # font-face-src: Font Face Source Element ........... SVG.font-face-src.extra.content = notAllowed SVG.font-face-src.content = (font-face-uri | font-face-name | SVG.font-face-src.extra.content)+ font-face-src = element font-face-src { SVG.Core.attrib, SVG.font-face-src.content } # end of SVG.font-face-src.element # end of SVG.font-face-src.attlist # font-face-uri: Font Face URI Element .............. SVG.font-face-uri.extra.content = notAllowed SVG.font-face-uri.content = (font-face-format | SVG.font-face-uri.extra.content)* font-face-uri = element font-face-uri { SVG.Core.attrib, SVG.XLinkRequired.attrib, SVG.font-face-uri.content } # end of SVG.font-face-uri.element # end of SVG.font-face-uri.attlist # font-face-format: Font Face Format Element ........ SVG.font-face-format.content = empty font-face-format = element font-face-format { SVG.Core.attrib, attribute string { text }?, SVG.font-face-format.content } # end of SVG.font-face-format.element # end of SVG.font-face-format.attlist # font-face-name: Font Face Name Element ............ SVG.font-face-name.content = empty font-face-name = element font-face-name { SVG.Core.attrib, attribute name { text }?, SVG.font-face-name.content } # end of SVG.font-face-name.element # end of SVG.font-face-name.attlist # end of svg-font.mod # Extensibility Module ........................................ # ....................................................................... # SVG 1.1 Extensibility Module .......................................... # file: svg-extensibility.mod # # This is SVG, a language for describing two-dimensional graphics in XML. # Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. # Revision: $Id: svg11-flat.rnc 3024 2011-07-10 08:29:17Z eb2mmrt $ # # This DTD module is identified by the PUBLIC and SYSTEM identifiers: # # PUBLIC "-//W3C//ELEMENTS SVG 1.1 Extensibility//EN" # SYSTEM "http://www.w3.org/Graphics/SVG/1.1/DTD/svg-extensibility.mod" # # ....................................................................... # Extensibility # # foreignObject # # This module declares markup to provide support for extensibility. # Qualified Names (Default) ......................... # Attribute Collections (Default) ................... # SVG.Extensibility.class ........................... # SVG.Presentation.attrib ........................... # foreignObject: Foreign Object Element ............. SVG.foreignObject.extra.content = notAllowed SVG.foreignObject.content = (text | SVG.foreignObject.extra.content)* foreignObject = element foreignObject { SVG.Core.attrib, SVG.Conditional.attrib, SVG.Style.attrib, SVG.Presentation.attrib, SVG.GraphicalEvents.attrib, SVG.External.attrib, attribute x { Coordinate.datatype }?, attribute y { Coordinate.datatype }?, attribute width { Length.datatype }, attribute height { Length.datatype }, attribute transform { TransformList.datatype }?, SVG.foreignObject.content } start = feComposite | animate | cursor | feTile | font-face-src | feFlood | mask | feTurbulence | feFuncA | polygon | feFuncB | clipPath | animateTransform | feMorphology | tref | missing-glyph | feBlend | metadata | feColorMatrix | font-face-uri | \text | ellipse | symbol | linearGradient | foreignObject | font | radialGradient | glyph | feDisplacementMap | image | script | rect | hkern | feSpotLight | animateMotion | feComponentTransfer | altGlyphDef | animateColor | marker | font-face | vkern | view | filter | feMergeNode | stop | desc | feOffset | set | feMerge | line | use | switch | fePointLight | circle | color-profile | feSpecularLighting | title | polyline | style | path | altGlyph | feDiffuseLighting | font-face-format | g | defs | feFuncG | svg | a | feImage | textPath | feConvolveMatrix | altGlyphItem | mpath | feFuncR | font-face-name | tspan | feGaussianBlur | pattern | feDistantLight | glyphRef # end of SVG.foreignObject.element # end of SVG.foreignObject.attlist # end of svg-extensibility.mod # end of SVG 1.1 DTD .................................................... # ....................................................................... epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/svg11/LICENSE0000644000175000017500000000006213017276730026471 0ustar eugeneeugeneLicense is shown in the header of svg11-flat.rnc. epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/mod/svg11/README.txt0000644000175000017500000000046413017276730027170 0ustar eugeneeugene$Id: README.txt 3106 2011-08-24 07:56:19Z eb2mmrt $ $Author: eb2mmrt $ This directory contains a RELAX NG schema, namely svg11-flat.rnc, for SVG 1.1 (2nd Edition). It is automatically created by trang from svg11-flat.dtd, available at http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-flat.dtd (08-July-2011). epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/media-overlay-30.sch0000644000175000017500000000045013017276730027422 0ustar eugeneeugene epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/media-overlay-30.nvdl0000644000175000017500000000102513017276730027607 0ustar eugeneeugene epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/epub30-catalog.xml0000644000175000017500000004651113017276730027205 0ustar eugeneeugene epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/epub-xhtml-30.nvdl0000644000175000017500000000076013017276730027143 0ustar eugeneeugene epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/edupub/0000755000175000017500000000000013017276730025232 5ustar eugeneeugeneepubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/edupub/edu-structure.sch0000644000175000017500000001424613017276730030553 0ustar eugeneeugene Empty aria-label attribute found. The body element requires a heading when it is used as an implied section. More than one ranked heading found as direct descendant of body. Empty ranked heading detected. The value of the 'aria-label' attribute must not be the same as the content of the heading. Empty aria-label attribute found. does not have a heading. More than one ranked heading found as direct descendant of . Empty ranked heading detected. The value of the 'aria-label' attribute must not be the same as the content of the heading. Ranked headings are not valid in figure or blockquote The heading rank h does not match the current nesting level (). The current heading rank should be h6. Non-section elements not allowed between or after section elements. Section subtitles must be wrapped in a header element. epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/edupub/edu-ocf-metadata.sch0000644000175000017500000000067213017276730031036 0ustar eugeneeugene A dc:type element with the value 'edupub' is required. epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/edupub/edu-semantics.sch0000644000175000017500000001553513017276730030503 0ustar eugeneeugene An element that carries the answers term requires at least one descendant element that carries the answer term. An element that carries the assessments term requires at least one descendant element that carries the assessment term. An element that carries the bibliography term requires at least one descendant element that carries the biblioentry term. An element that carries the the credits term requires at least one descendant element that carries the credit term. An element that carries the fill-in-the-blank-problem term requires at least one descendant element that carries the question term. An element that carries the fill-in-the-blank-problem term must not contain more than one descendant element that carries the answer term. An element that carries the footnotes term requires at least one descendant element that carries the footnote term. An element that carries the general-problem term requires at least one descendant element that carries the question term. An element that carries the general-problem term must not contain more than one descendant element that carries the answer term. An element that carries the keywords term requires at least one descendant element that carries the keyword term. An element that carries the learning-objectives term requires at least one descendant element that carries the learning-objective term. An element that carries the learning-outcomes term requires at least one descendant element that carries the learning-outcome term. An element that carries the learning-resources term requires at least one descendant element that carries the learning-resource term. An element that carries the learning-standards term requires at least one descendant element that carries the learning-standard term. An element that carries the match-problem term requires at least one descendant element that carries the question term. An element that carries the match-problem term must not contain more than one descendant element that carries the answer term. An element that carries the multiple-choice-problem term requires at least one descendant element that carries the question term. An element that carries the multiple-choice-problem term must not contain more than one descendant element that carries the answer term. An element that carries the ordinal term must not have descendants that also carry the ordinal term. An element that carries the practies term requires at least one descendant element that carries the practice term. An element that carries the rearnotes term requires at least one descendant element that carries the rearnote term. An element that carries the true-false-problem term requires at least one descendant element that carries the question term. An element that carries the true-false-problem term must not contain more than one descendant element that carries the answer term. epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/edupub/edu-opf.sch0000644000175000017500000001302413017276730027270 0ustar eugeneeugene The dc:type identifier 'edupub' is required. At least one schema:accessibilityFeature declaration is required. The schema:accessibilityFeature property value 'none' is not valid in edupub. Use 'tableOfContents' if no other values are applicable. WARNING: A teacher's edition should identify the corresponding student edition in a dc:source element. WARNING: When targeting , including a schema:educationalAlignment property is recommended. WARNING: When targeting , including a schema:educationalRole property is strongly recommended. WARNING: When targeting , including a schema:educationalUse property is strongly recommended. WARNING: When targeting , including a schema:interactivityType property is strongly recommended. WARNING: When targeting , including a schema:isBasedOnUrlUse property is recommended. WARNING: When targeting , including a schema:learningResourceType property is recommended. WARNING: When targeting , including a schema:typicalAgeRange property is recommended. WARNING: When targeting , including a schema:educationalAlignment property is recommended. WARNING: When targeting , including a schema:educationalRole property is strongly recommended. WARNING: When targeting , including a schema:educationalUse property is strongly recommended. WARNING: When targeting , including a schema:interactivityType property is strongly recommended. WARNING: When targeting , including a schema:isBasedOnUrlUse property is recommended. WARNING: When targeting , including a schema:learningResourceType property is recommended. WARNING: When targeting , including a schema:typicalAgeRange property is recommended. WARNING: When targeting , including a schema:educationalRole property is strongly recommended. WARNING: When targeting , including a schema:interactivityType property is recommended. WARNING: When targeting , including a schema:isBasedOnUrlUse property is recommended. epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/multiple-renditions/0000755000175000017500000000000013017276730027755 5ustar eugeneeugeneepubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/multiple-renditions/mapping.sch0000644000175000017500000000212213017276730032104 0ustar eugeneeugene A meta tag with the name 'epub.multiple.renditions.version' and value '1.0' is required. A Rendition Mapping Document must contain exactly one 'resource-map' nav element. A nav element of a Rendition Mapping Document must identify its nature in an epub:type attribute. epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/multiple-renditions/container.rnc0000644000175000017500000000135513017276730032447 0ustar eugeneeugenenamespace rendition = "http://www.idpf.org/2013/rendition" ocf.rootfile.attlist &= mr.rendition.attr? & mr.layout.attr? & mr.language.attr? & mr.accessMode.attr? & mr.label.attr? mr.rendition.attr = attribute rendition:media { xsd:string { pattern='\s*(((only|not)\s+)?all|\([^>)]+\))(\s+and\s+\([^>)]+\))*\s*(,\s*(((only|not)\s+)?all|\([^>)]+\))(\s+and\s+\([^>)]+\))*\s*)*' } } mr.layout.attr = attribute rendition:layout { "reflowable" | "pre-paginated" } mr.language.attr = attribute rendition:language { datatype.languagecode } mr.accessMode.attr = attribute rendition:accessMode { list { ("auditory" | "tactile" | "textual" | "visual")+ } } mr.label.attr = attribute rendition:label { text } epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/multiple-renditions/container.sch0000644000175000017500000000265013017276730032441 0ustar eugeneeugene The accessMode attribute contains a duplicate value. WARNING: At least one rendition selection attribute should be specified for each non-first rootfile element, which represents a non-default rendition." The Container Document must not reference more than one mapping document. The media type of Rendition Mapping Documents must be "application/xhtml+xml". epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/multiple-renditions/mapping.rnc0000644000175000017500000000146313017276730032120 0ustar eugeneeugenedefault namespace = "http://www.w3.org/1999/xhtml" namespace epub = "http://www.idpf.org/2007/ops" include "../mod/datatypes.rnc" start = html html = element html { attribute epub:prefix { datatype.prefixdecl }?, head, body } head = element head { meta* } body = element body { nav+ } meta = element meta { (attribute name { xsd:string } & attribute content { xsd:string }) | attribute charset { xsd:NMTOKEN } } nav = element nav { # presence of epub:type is checked with Schematron for better error message (attribute epub:type { xsd:NMTOKENS })? & ul+ } ul = element ul { li, li+ } li = element li { a } a = element a { attribute href { xsd:anyURI } & attribute epub:rendition { xsd:anyURI }? } epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/LICENSE0000644000175000017500000000240013017276730024747 0ustar eugeneeugeneUnless explicitly overridden by other license statements in child directories of this directory, the following license statement holds for all files in this directory and its subdirectories. Copyright (c) 2010-2011 International Digital Publishing Forum Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/epub-svg-30.nvdl0000644000175000017500000000075013017276730026605 0ustar eugeneeugene epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/package-30.sch0000644000175000017500000003731513017276730026271 0ustar eugeneeugene package element unique-identifier attribute does not resolve to a dc:identifier element (given reference was '') package dcterms:modified meta element must occur exactly once dcterms:modified illegal syntax (expecting: 'CCYY-MM-DDThh:mm:ssZ') @refines missing target id: '' The 'source-of' property must have the value 'pagination' The 'source-of' property must refine a 'dc:source' element. The type of 'record' references must be identifiable from the link element's 'media-type' attribute. 'record' links only applies to the Publication (must not have a 'refines' attribute). Property 'belongs-to-collection' can only refine other 'belongs-to-collection' properties. Property 'collection-type' must refine a 'belongs-to-collection' property. itemref element idref attribute does not resolve to a manifest item element manifest item element fallback attribute must resolve to another manifest item (given reference was '') media overlay items must be of the 'application/smil+xml' type (given type was '') global media:duration meta element not set item media:duration meta element not set (expecting: meta property='media:duration' refines='') manifest items referenced from the handler attribute of a bindings mediaType element must be of the 'application/xhtml+xml' type (given type was '') spine element toc attribute must reference the NCX manifest item (referenced media type was '') spine element toc attribute must be set when an NCX is included in the publication Exactly one manifest item must declare the 'nav' property (number of 'nav' items: ). The manifest item representing the Navigation Document must be of the 'application/xhtml+xml' type (given type was '') Found 'data-nav' items. The manifest must not include more than one Data Navigation Document. Multiple occurrences of the 'cover-image' property (number of 'cover-image' items: ). The 'rendition:flow' property must not occur more than one time in the package metadata. The 'rendition:layout' property must not occur more than one time in the package metadata. The 'rendition:orientation' property must not occur more than one time in the package metadata. The 'rendition:spread' property must not occur more than one time in the package metadata. The 'rendition:viewport' property must not occur more than one time as a global value in the package metadata. The 'rendition:flow' property must not be set on elements with a 'refines' attribute The value of the 'rendition:flow' property must be either 'paginated', 'scrolled-continuous', 'scrolled-doc', or 'auto' The 'rendition:layout' property must not be set on elements with a 'refines' attribute The value of the 'rendition:layout' property must be either 'reflowable' or 'pre-paginated' The 'rendition:orientation' property must not be set on elements with a 'refines' attribute The value of the 'rendition:orientation' property must be either 'landscape', 'portrait' or 'auto' The 'rendition:spread' property must not be set on elements with a 'refines' attribute The value of the 'rendition:spread' property must be either 'none', 'landscape', 'portrait', 'both' or 'auto' The 'rendition:spread' property must not be set on elements with a 'refines' attribute The value of the 'rendition:spread' property must be either 'none', 'landscape', 'portrait', 'both' or 'auto' The value of the 'rendition:viewport' property must be of the form 'width=x, height=y' Properties 'rendition:flow-paginated', 'rendition:flow-scrolled-continuous', 'rendition:flow-scrolled-doc' and 'rendition:flow-auto' are mutually exclusive Properties 'rendition:layout-reflowable' and 'rendition:layout-pre-paginated' are mutually exclusive Properties 'rendition:orientation-landscape', 'rendition:orientation-portrait' and 'rendition:orientation-auto' are mutually exclusive Properties 'page-spread-right', 'page-spread-left' and 'rendition:page-spread-center' are mutually exclusive Properties 'rendition:spread-portrait', 'rendition:spread-landscape', 'rendition:spread-both', 'rendition:spread-none' and 'rendition:spread-auto' are mutually exclusive @refines must point to an element within the current collection epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/epub-nav-30.sch0000644000175000017500000000611213017276730026402 0ustar eugeneeugene Exactly one 'toc' nav element must be present Multiple occurrences of the 'page-list' nav element Multiple occurrences of the 'landmarks' nav element The span element must only be used as heading for flat sublists (not hierarchical navigation structures) Missing epub:type attribute on anchor inside 'landmarks' nav element Anchors within nav elements must contain text Spans within nav elements must contain text nav elements other than 'toc', 'page-list' and 'landmarks' must contain a heading as the first child Heading elements must contain text epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/ocf-encryption-30.rnc0000644000175000017500000000072713017276730027637 0ustar eugeneeugene default namespace = "urn:oasis:names:tc:opendocument:xmlns:container" start = element encryption { grammar { include "mod/security/Lenient-Encryption11-ghc.rnc" { start = xenc_EncryptedData | xenc_EncryptedKey } xenc_EncryptionMethodOtherParams |= attribute Algorithm { xsd:anyURI "http://www.idpf.org/2008/embedding" } xenc_EncryptionAlgorithms |= xsd:anyURI "http://www.idpf.org/2008/embedding" }+ } epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/ocf-metadata-30.nvdl0000644000175000017500000000074213017276730027403 0ustar eugeneeugene epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/media-overlay-30.rnc0000644000175000017500000000371513017276730027436 0ustar eugeneeugene default namespace = "http://www.w3.org/ns/SMIL" namespace epub = "http://www.idpf.org/2007/ops" include "./mod/epub-type-attr.rnc" include "./mod/epub-prefix-attr.rnc" include "./mod/datatypes.rnc" start = element smil { smil.attlist & smil.content } smil.attlist = smil.version.attr & smil.id.attr? & epub.prefix.attr.ns? smil.content = smil.head?, smil.body smil.head = element head { smil.metadata? } smil.metadata = element metadata { smil.metadata.content } smil.metadata.content = anyElement* smil.body = element body { smil.body.attlist & smil.body.content } smil.body.attlist = smil.tc.attrs & epub.textref.attr? smil.body.content = (smil.seq | smil.par)+ smil.seq = element seq { smil.seq.attlist & smil.seq.content } smil.seq.attlist = smil.tc.attrs & epub.textref.attr smil.seq.content = (smil.seq | smil.par)+ smil.par = element par {smil.par.attlist & smil.par.content } smil.par.attlist = smil.tc.attrs smil.par.content = smil.text, smil.audio? smil.text = element \text { smil.text.attlist } smil.text.attlist = smil.id.attr? & smil.src.attr smil.audio = element audio { smil.audio.attlist } smil.audio.attlist = smil.id.attr? & attribute clipBegin { datatype.smil.npt }? & attribute clipEnd { datatype.smil.npt }? & smil.src.attr smil.tc.attrs = epub.type.attr? & smil.id.attr? smil.src.attr = attribute src { datatype.URI } smil.id.attr = attribute id { datatype.ID } smil.i18n.attrs = smil.xml.lang.attr? & smil.dir.attr? smil.xml.lang.attr = attribute xml:lang { datatype.languagecode } smil.dir.attr = attribute dir { 'ltr' | 'rtl' } smil.version.attr = attribute version { '3.0' } epub.textref.attr = attribute epub:textref { datatype.URI } smil.name.attr = attribute name { datatype.string } smil.content.attr = attribute content {datatype.string } anyElement = element * { (attribute * { text } | text | anyElement)* }epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/epub-xhtml-30.rnc0000644000175000017500000000216313017276730026761 0ustar eugeneeugene default namespace = "http://www.w3.org/1999/xhtml" include "./mod/html5/html5-document-30.rnc" include "./mod/html5/html5-sections-30.rnc" include "./mod/html5/html5-grouping-30.rnc" include "./mod/html5/html5-phrasing-30.rnc" include "./mod/html5/html5-embed-30.rnc" include "./mod/html5/html5-edit-30.rnc" include "./mod/html5/html5-style-30.rnc" include "./mod/html5/html5-script-30.rnc" include "./mod/html5/html5-interactive-30.rnc" include "./mod/html5/html5-forms-30.rnc" include "./mod/html5/html5-attrib-30.rnc" include "./mod/html5/html5-aria-30.rnc" include "./mod/html5/html5-rdfa.rnc" include "./mod/html5/html5-md.rnc" include "./mod/datatypes.rnc" include "./mod/html5/html5-models-30.rnc" include "./mod/epub-xhtml-mathml3-30.rnc" include "./mod/epub-xhtml-svg11-30.rnc" include "./mod/epub-trigger.rnc" include "./mod/epub-switch.rnc" include "./mod/epub-type-attr.rnc" include "./mod/epub-prefix-attr.rnc" include "./mod/epub-ssml-attrs.rnc" start = html5.html epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/ocf-metadata-30.rnc0000644000175000017500000000231513017276730027220 0ustar eugeneeugenedefault namespace = "http://www.idpf.org/2013/metadata" include "./package-30.rnc" { start = element metadata {mr.metadata.attlist & mr.metadata.content } opf.meta = element meta { opf.epub3.meta.content #Obsolete OPF2 meta content disallowed } opf.link = element link { opf.href.attr & opf.rel.attr & opf.id.attr? & opf.refines.attr? & opf.media-type.attr? } #Duplicated only for changing the namespace. opf.dc.elems = opf.dc.identifier+ & opf.dc.title* #made optional & opf.dc.language* #made optional & opf.dc.date? & opf.dc.source* & opf.dc.type* & opf.dc.format* & opf.dc.creator* & opf.dc.subject* & opf.dc.description* & opf.dc.publisher* & opf.dc.contributor* & opf.dc.relation* & opf.dc.coverage* & opf.dc.rights* } mr.metadata.attlist = opf.unique.identifier.attr & epub.prefix.attr? & opf.id.attr? & opf.i18n.attrs & opf.version.attr? mr.metadata.content = opf.metadata.content epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/ocf-signatures-30.rnc0000644000175000017500000000037713017276730027632 0ustar eugeneeugene default namespace = "urn:oasis:names:tc:opendocument:xmlns:container" start = element signatures { grammar { include "mod/security/Lenient-Signature11-properties-exclusiveC14N.rnc" { start = ds_Signature } }+ } epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/ocf-container-30.rnc0000644000175000017500000000234413017276730027424 0ustar eugeneeugene default namespace = "urn:oasis:names:tc:opendocument:xmlns:container" include "./mod/datatypes.rnc" include "./multiple-renditions/container.rnc" start = ocf.container ocf.container = element container { ocf.container.attlist & ocf.container.content } ocf.container.attlist = attribute version { '1.0' } ocf.container.content = ocf.rootfiles, ocf.links? ocf.rootfiles = element rootfiles { ocf.rootfiles.attlist & ocf.rootfiles.content } ocf.rootfiles.attlist = empty ocf.rootfiles.content = ocf.rootfile+ ocf.rootfile = element rootfile {ocf.rootfile.attlist & ocf.rootfile.content } ocf.rootfile.attlist = attribute full-path { datatype.URI } & attribute media-type { 'application/oebps-package+xml' } ocf.rootfile.content = empty ocf.links = element links { ocf.links.attlist & ocf.links.content } ocf.links.attlist = empty ocf.links.content = ocf.link+ ocf.link = element link { ocf.link.attlist & ocf.link.content } ocf.link.attlist = attribute href { datatype.URI } & attribute rel { datatype.space.separated.tokens } & attribute media-type { datatype.mimetype }? ocf.link.content = empty epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/30/ocf-metadata-30.sch0000644000175000017500000001376713017276730027230 0ustar eugeneeugene unique-identifier attribute does not resolve to a dc:identifier element (given reference was '') dcterms:modified meta element must occur exactly once dcterms:modified illegal syntax (expecting: 'CCYY-MM-DDThh:mm:ssZ') @refines missing target id: '' The 'source-of' property must have the value 'pagination' The 'source-of' property must refine a 'dc:source' element. The type of 'record' references must be identifiable from the link element's 'media-type' attribute. 'record' links only applies to the Publication (must not have a 'refines' attribute). Property 'belongs-to-collection' can only refine other 'belongs-to-collection' properties. Property 'collection-type' must refine a 'belongs-to-collection' property. The 'rendition:flow' property must not occur more than one time in the metadata. The 'rendition:layout' property must not occur more than one time in the metadata. The 'rendition:orientation' property must not occur more than one time in the metadata. The 'rendition:spread' property must not occur more than one time in the metadata. The 'rendition:viewport' property must not occur more than one time as a global value in the metadata. The 'rendition:flow' property must not be set on elements with a 'refines' attribute The value of the 'rendition:flow' property must be either 'paginated', 'scrolled-continuous', 'scrolled-doc', or 'auto' The 'rendition:layout' property must not be set on elements with a 'refines' attribute The value of the 'rendition:layout' property must be either 'reflowable' or 'pre-paginated' The 'rendition:orientation' property must not be set on elements with a 'refines' attribute The value of the 'rendition:orientation' property must be either 'landscape', 'portrait' or 'auto' The 'rendition:spread' property must not be set on elements with a 'refines' attribute The value of the 'rendition:spread' property must be either 'none', 'landscape', 'portrait', 'both' or 'auto' The 'rendition:spread' property must not be set on elements with a 'refines' attribute The value of the 'rendition:spread' property must be either 'none', 'landscape', 'portrait', 'both' or 'auto' The value of the 'rendition:viewport' property must be of the form 'width=x, height=y' epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/0000755000175000017500000000000013017276730023745 5ustar eugeneeugeneepubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/sch/0000755000175000017500000000000013017276730024522 5ustar eugeneeugeneepubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/sch/id-unique.sch0000644000175000017500000000101013017276730027111 0ustar eugeneeugene Duplicate '' epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/sch/opf.sch0000644000175000017500000000107413017276730026007 0ustar eugeneeugene The "id" attribute does not have a unique value epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/sch/xhtml.sch0000644000175000017500000000054013017276730026354 0ustar eugeneeugene The a element cannot contain any nested a elements. epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/sch/ncx.sch0000644000175000017500000001007413017276730026013 0ustar eugeneeugene pageTarget combination of value and type is not unique the first playOrder value is not 1 Multiple navLabels with same xml:lang attribute within an NCX node Multiple navInfos with same xml:lang attribute within an NCX node playOrder sequence has gaps identical playOrder values for navPoint/navTarget/pageTarget that do not refer to same target different playOrder values for navPoint/navTarget/pageTarget that refer to same target The "id" attribute does not have a unique value epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/dtd/0000755000175000017500000000000013017276730024520 5ustar eugeneeugeneepubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/dtd/svg11.dtd0000644000175000017500000055617413017276730026200 0ustar eugeneeugene ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> ]]> epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/dtd/dtbook-2005-2.dtd0000644000175000017500000030471513017276730027234 0ustar eugeneeugene epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/dtd/xhtml1-strict.dtd0000644000175000017500000006160113017276730027744 0ustar eugeneeugene %HTMLlat1; %HTMLsymbol; %HTMLspecial; epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/dtd/ncx-2005-1.dtd0000644000175000017500000002503513017276730026534 0ustar eugeneeugene epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/dtd/xhtml-symbol.dtdinc0000644000175000017500000003303013017276730030345 0ustar eugeneeugene epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/dtd/xhtml-lat1.dtdinc0000644000175000017500000002677713017276730027725 0ustar eugeneeugene epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/dtd/opf20.dtd0000644000175000017500000002047613017276730026154 0ustar eugeneeugene %OEBEntities; epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/dtd/xhtml-special.dtdinc0000644000175000017500000001004313017276730030457 0ustar eugeneeugene epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/dtd/oebpkg12.dtd0000644000175000017500000002472613017276730026642 0ustar eugeneeugene %OEBEntities; epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/dtd/oeb12.dtdinc0000644000175000017500000013532613017276730026631 0ustar eugeneeugene epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/dtd/xhtml1-transitional.dtd0000644000175000017500000007655613017276730031162 0ustar eugeneeugene %HTMLlat1; %HTMLsymbol; %HTMLspecial; epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/dtd/xhtml11-ent.dtd0000644000175000017500000005406013017276730027304 0ustar eugeneeugene epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/dtd/oebdoc12.dtd0000644000175000017500000003760113017276730026622 0ustar eugeneeugene %OEBEntities; epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/0000755000175000017500000000000013017276730024533 5ustar eugeneeugeneepubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/ncx.rng0000644000175000017500000001400713017276730026035 0ustar eugeneeugene 2005-1 ltr rtl epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/signatures.rng0000644000175000017500000000076313017276730027435 0ustar eugeneeugene epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/xenc-schema.rng0000644000175000017500000001756013017276730027447 0ustar eugeneeugene epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/ops20.nvdl0000644000175000017500000000425713017276730026373 0ustar eugeneeugene epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/ops20.rng0000644000175000017500000000070613017276730026211 0ustar eugeneeugene epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/ncx-old.rng0000644000175000017500000001132113017276730026605 0ustar eugeneeugene 2005-1 epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/opf20.rng0000644000175000017500000003066613017276730026204 0ustar eugeneeugene 2.0 1 yes no epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/container.rng0000644000175000017500000000117113017276730027225 0ustar eugeneeugene epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/encryption.rng0000644000175000017500000000120413017276730027432 0ustar eugeneeugene epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/ops/0000755000175000017500000000000013017276730025334 5ustar eugeneeugeneepubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/ops/ops-switch.rng0000644000175000017500000000263313017276730030150 0ustar eugeneeugene OPS conditional processing: switch, case and default elements epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/xmldsig-core-schema.rng0000644000175000017500000002664113017276730031107 0ustar eugeneeugene epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/dtbook-2005-2.rng0000644000175000017500000041264713017276730027266 0ustar eugeneeugene default preserve ltr rtl xxx xxp xlx xlp bxx bxp blx blp default preserve 2005-2 required optional required optional true false default preserve default preserve yes no ltr rtl front normal special ol ul pl 1 a A i I row col rowgroup colgroup void above below hsides lhs rhs vsides box border none groups rows cols all left center right justify char top middle bottom baseline epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/content-svg.rng0000644000175000017500000000056613017276730027521 0ustar eugeneeugene epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/svg/0000755000175000017500000000000013017276730025332 5ustar eugeneeugeneepubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/svg/svg-graphevents-attrib.rng0000644000175000017500000000641013017276730032451 0ustar eugeneeugene SVG 1.1 Graphical Element Events Attribute Module file: svg-graphevents-attrib.rng This is SVG, a language for describing two-dimensional graphics in XML. Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. $Id: svg-graphevents-attrib.rng,v 1.1 2003/07/15 07:11:10 dean Exp $ Graphical Element Events Attribute onfocusin, onfocusout, onactivate, onclick, onmousedown, onmouseup, onmouseover, onmousemove, onmouseout, onload This module defines the GraphicalEvents attribute set. epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/svg/svg-qname.rng0000644000175000017500000001124713017276730027745 0ustar eugeneeugene epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/svg/svg-filter.rng0000644000175000017500000003226213017276730030131 0ustar eugeneeugene SVG 1.1 Filter Module file: svg-filter.rng This is SVG, a language for describing two-dimensional graphics in XML. Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. $Id: svg-filter.rng,v 1.1 2003/07/15 07:11:10 dean Exp $ Filter filter, feBlend, feColorMatrix, feComponentTransfer, feComposite, feConvolveMatrix, feDiffuseLighting, feDisplacementMap, feFlood, feGaussianBlur, feImage, feMerge, feMergeNode, feMorphology, feOffset, feSpecularLighting, feTile, feTurbulence, feDistantLight, fePointLight, feSpotLight, feFuncR, feFuncG, feFuncB, feFuncA This module declares markup to provide support for filter effect. extend SVG.FilterPrimitive.class feConvolveMatrix: Filter Effect Convolve Matrix Element duplicate wrap none feDiffuseLighting: Filter Effect Diffuse Lighting Element feDisplacementMap: Filter Effect Displacement Map Element R G B A R G B A feMorphology: Filter Effect Morphology Element erode dilate feSpecularLighting: Filter Effect Specular Lighting Element feTurbulence: Filter Effect Turbulence Element stitch noStitch fractalNoise turbulence feDistantLight: Filter Effect Distant Light Element fePointLight: Filter Effect Point Light Element feSpotLight: Filter Effect Spot Light Element epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/svg/svg-opacity-attrib.rng0000644000175000017500000000320213017276730031567 0ustar eugeneeugene SVG 1.1 Paint Opacity Attribute Module file: svg-opacity-attrib.rng This is SVG, a language for describing two-dimensional graphics in XML. Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. $Id: svg-opacity-attrib.rng,v 1.1 2003/07/15 07:11:10 dean Exp $ Paint Opacity Attribute opacity, fill-opacity, stroke-opacity This module defines the Opacity attribute set. epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/svg/svg-basic-font.rng0000644000175000017500000003203313017276730030665 0ustar eugeneeugene SVG 1.1 Basic Font Module file: svg-basic-font.rng This is SVG, a language for describing two-dimensional graphics in XML. Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. $Id: svg-basic-font.rng,v 1.1 2003/07/15 07:11:10 dean Exp $ Basic Font font, font-face, glyph, missing-glyph, hkern, vkern, font-face-src, font-face-uri, font-face-name This module declares markup to provide support for template. SVG.Font.class font: Font Element font-face: Font Face Element glyph: Glyph Element missing-glyph: Missing Glyph Element hkern: Horizontal Kerning Element vkern: Vertical Kerning Element font-face-src: Font Face Source Element font-face-uri: Font Face URI Element font-face-name: Font Face Name Element epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/svg/svg-cursor.rng0000644000175000017500000000445413017276730030163 0ustar eugeneeugene SVG 1.1 Cursor Module file: svg-cursor.rng This is SVG, a language for describing two-dimensional graphics in XML. Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. $Id: svg-cursor.rng,v 1.1 2003/07/15 07:11:10 dean Exp $ Cursor cursor This module declares markup to provide support for cursor. Datatypes SVG.Cursor.attrib SVG.Cursor.class cursor: Cursor Element epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/svg/svg-core-attrib.rng0000644000175000017500000000345413017276730031060 0ustar eugeneeugene SVG 1.1 Core Attribute Module file: svg-core-attrib.rng This is SVG, a language for describing two-dimensional graphics in XML. Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. $Id: svg-core-attrib.rng,v 1.1 2003/07/15 07:11:10 dean Exp $ Core Attribute id, xml:base, xml:lang, xml:space This module defines the core set of attributes that can be present on any element. default preserve epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/svg/svg-shape.rng0000644000175000017500000002627013017276730027746 0ustar eugeneeugene SVG 1.1 Shape Module file: svg-shape.rng This is SVG, a language for describing two-dimensional graphics in XML. Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. $Id: svg-shape.rng,v 1.1 2003/07/15 07:11:10 dean Exp $ Shape path, rect, circle, line, ellipse, polyline, polygon This module declares markup to provide support for graphical shapes. a list of points SVG.Shape.class path: Path Element rect: Rectangle Element circle: Circle Element line: Line Element ellipse: Ellipse Element polyline: Polyline Element polygon: Polygon Element epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/svg/svg-marker.rng0000644000175000017500000001017113017276730030120 0ustar eugeneeugene SVG 1.1 Marker Module file: svg-marker.rng This is SVG, a language for describing two-dimensional graphics in XML. Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. $Id: svg-marker.rng,v 1.1 2003/07/15 07:11:10 dean Exp $ Marker marker This module declares markup to provide support for marker. Datatypes SVG.Marker.attrib SVG.Marker.class marker: Marker Element strokeWidth userSpaceOnUse epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/svg/svg-basic-text.rng0000644000175000017500000001512013017276730030701 0ustar eugeneeugene SVG 1.1 Basic Text Module file: svg-basic-text.rng This is SVG, a language for describing two-dimensional graphics in XML. Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. $Id: svg-basic-text.rng,v 1.1 2003/07/15 07:11:10 dean Exp $ Basic Text text, altGlyph, altGlyphDef, glyphRef This module declares markup to provide support for text. Datatypes SVG.Font.attrib normal italic oblique inherit normal bold bolder lighter 100 200 300 400 500 600 700 800 900 inherit SVG.Text.class SVG.TextContent.class text: Text Element altGlyph: Alternate Glyph Element altGlyphDef: Alternate Glyph Definition Element glyphRef: Glyph Reference Element epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/svg/svg-conditional.rng0000644000175000017500000000620013017276730031140 0ustar eugeneeugene SVG 1.1 Conditional Processing Module file: svg-conditional.rng This is SVG, a language for describing two-dimensional graphics in XML. Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. $Id: svg-conditional.rng,v 1.1 2003/07/15 07:11:10 dean Exp $ Conditional Processing switch This module declares markup to provide support for conditional processing. Datatypes SVG.Conditional.attrib SVG.Conditional.class switch: Switch Element epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/svg/svg-animation.rng0000644000175000017500000002433713017276730030627 0ustar eugeneeugene SVG 1.1 Animation Module file: svg-animation.rng This is SVG, a language for describing two-dimensional graphics in XML. Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. $Id: svg-animation.rng,v 1.1 2003/07/15 07:11:10 dean Exp $ Animation animate, set, animateMotion, animateColor, animateTransform, mpath This module declares markup to provide support for animation. SVG.Animation.class SVG.Animation.attrib SVG.AnimationAttribute.attrib SVG.AnimationTiming.attrib always never whenNotActive remove freeze SVG.AnimationValue.attrib discrete linear paced spline SVG.AnimationAddtion.attrib replace sum none sum animate: Animate Element set: Set Element animateMotion: Animate Motion Element discrete linear paced spline animateColor: Animate Color Element animateTransform: Animate Transform Element translate scale rotate skewX skewY mpath: Motion Path Element epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/svg/svg-hyperlink.rng0000644000175000017500000000555613017276730030657 0ustar eugeneeugene SVG 1.1 Hyperlinking Module file: svg-hyperlink.rng This is SVG, a language for describing two-dimensional graphics in XML. Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. $Id: svg-hyperlink.rng,v 1.1 2003/07/15 07:11:10 dean Exp $ Hyperlinking a This module declares markup to provide support for hyper linking. link to this target SVG.Hyperlink.class a: Anchor Element epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/svg/svg-basic-clip.rng0000644000175000017500000000626413017276730030655 0ustar eugeneeugene SVG 1.1 Basic Clip Module file: svg-basic-clip.rng This is SVG, a language for describing two-dimensional graphics in XML. Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. $Id: svg-basic-clip.rng,v 1.1 2003/07/15 07:11:10 dean Exp $ Basic Clip clipPath This module declares markup to provide support for clipping. Datatypes SVG.Clip.attrib SVG.Clip.class clipPath: Clip Path Element userSpaceOnUse objectBoundingBox epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/svg/svg-image.rng0000644000175000017500000000534113017276730027724 0ustar eugeneeugene SVG 1.1 Image Module file: svg-image.rng This is SVG, a language for describing two-dimensional graphics in XML. Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. $Id: svg-image.rng,v 1.1 2003/07/15 07:11:10 dean Exp $ Image image This module declares markup to provide support for image. SVG.Image.class image: Image Element epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/svg/svg-gradient.rng0000644000175000017500000001451113017276730030436 0ustar eugeneeugene SVG 1.1 Gradient Module file: svg-gradient.rng This is SVG, a language for describing two-dimensional graphics in XML. Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. $Id: svg-gradient.rng,v 1.1 2003/07/15 07:11:10 dean Exp $ Gradient linearGradient, radialGradient, stop This module declares markup to provide support for gradient fill. Datatypes SVG.Gradient.attrib SVG.Gradient.class linearGradient: Linear Gradient Element userSpaceOnUse objectBoundingBox pad reflect repeat radialGradient: Radial Gradient Element userSpaceOnUse objectBoundingBox pad reflect repeat stop: Stop Element epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/svg/svg-container-attrib.rng0000644000175000017500000000263513017276730032112 0ustar eugeneeugene SVG 1.1 Container Attribute Module file: svg-container-attrib.rng This is SVG, a language for describing two-dimensional graphics in XML. Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. $Id: svg-container-attrib.rng,v 1.1 2003/07/15 07:11:10 dean Exp $ Container Attribute enable-background This module defines the Container attribute set. 'enable-background' property/attribute value (e.g., 'new', 'accumulate') epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/svg/svg-view.rng0000644000175000017500000000403013017276730027606 0ustar eugeneeugene SVG 1.1 View Module file: svg-view.rng This is SVG, a language for describing two-dimensional graphics in XML. Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. $Id: svg-view.rng,v 1.1 2003/07/15 07:11:10 dean Exp $ View view This module declares markup to provide support for view. SVG.View.class view: View Element disable magnify epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/svg/svg-docevents-attrib.rng0000644000175000017500000000441113017276730032114 0ustar eugeneeugene SVG 1.1 Document Events Attribute Module file: svg-docevents-attrib.rng This is SVG, a language for describing two-dimensional graphics in XML. Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. $Id: svg-docevents-attrib.rng,v 1.1 2003/07/15 07:11:10 dean Exp $ Document Events Attribute onunload, onabort, onerror, onresize, onscroll, onzoom This module defines the DocumentEvents attribute set. epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/svg/svg-script.rng0000644000175000017500000000307713017276730030152 0ustar eugeneeugene SVG 1.1 Scripting Module file: svg-script.rng This is SVG, a language for describing two-dimensional graphics in XML. Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. $Id: svg-script.rng,v 1.1 2003/07/15 07:11:10 dean Exp $ Scripting script This module declares markup to provide support for scripting. SVG.Script.class script: Script Element epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/svg/svg-text.rng0000644000175000017500000003732413017276730027634 0ustar eugeneeugene SVG 1.1 Text Module file: svg-text.rng This is SVG, a language for describing two-dimensional graphics in XML. Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. $Id: svg-text.rng,v 1.1 2003/07/15 07:11:10 dean Exp $ Text text, tspan, tref, textPath, altGlyph, altGlyphDef, altGlyphItem, glyphRef This module declares markup to provide support for alternate glyph. Datatypes SVG.Text.attrib lr-tb rl-tb tb-rl lr rl tb inherit SVG.TextContent.attrib auto baseline before-edge text-before-edge middle central after-edge text-after-edge ideographic alphabetic hanging mathematical inherit ltr rtl inherit auto use-script no-change reset-size ideographic alphabetic hanging mathematical central middle text-after-edge text-before-edge inherit start middle end inherit normal embed bidi-override inherit normal wider narrower ultra-condensed extra-condensed condensed semi-condensed semi-expanded expanded extra-expanded ultra-expanded inherit normal small-caps inherit extend SVG.Text.class extend SVG.TextContent.class text: Text Element spacing spacingAndGlyphs tspan: Text Span Element spacing spacingAndGlyphs tref: Text Reference Element spacing spacingAndGlyphs textPath: Text Path Element spacing spacingAndGlyphs align stretch auto exact altGlyph: Alternate Glyph Element altGlyphDef: Alternate Glyph Definition Element altGlyphItem: Alternate Glyph Item Element glyphRef: Glyph Reference Element epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/svg/svg-clip.rng0000644000175000017500000000177513017276730027600 0ustar eugeneeugene SVG 1.1 Clip Module file: svg-clip.rng This is SVG, a language for describing two-dimensional graphics in XML. Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. $Id: svg-clip.rng,v 1.1 2003/07/15 07:11:10 dean Exp $ Clip clipPath This module declares markup to provide support for clipping. extend content model of clipPath epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/svg/svg-graphics-attrib.rng0000644000175000017500000000526213017276730031727 0ustar eugeneeugene SVG 1.1 Graphics Attribute Module file: svg-graphics-attrib.rng This is SVG, a language for describing two-dimensional graphics in XML. Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. $Id: svg-graphics-attrib.rng,v 1.1 2003/07/15 07:11:10 dean Exp $ Graphics Attribute display, image-rendering, pointer-events, shape-rendering, text-rendering, visibility This module defines the Graphics attribute set. auto optimizeSpeed optimizeQuality inherit visiblePainted visibleFill visibleStroke visible painted fill stroke all none inherit auto optimizeSpeed crispEdges geometricPrecision inherit auto optimizeSpeed optimizeLegibility geometricPrecision inherit epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/svg/svg-datatypes.rng0000644000175000017500000001157713017276730030650 0ustar eugeneeugene SVG 1.1 Datatypes Module file: svg-datatypes.mod This is SVG, a language for describing two-dimensional graphics in XML. Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. $Id: svg-datatypes.rng,v 1.1 2003/07/15 07:11:10 dean Exp $ Datatypes This module declares common data types for properties and attributes. feature specification false true 'clip-rule' or 'fill-rule' property/attribute value nonzero evenodd inherit media type, as per [RFC2045] a <coordinate> a list of <coordinate>s a <color> value a <integer> a language code, as per [RFC3066] comma-separated list of language codes, as per [RFC3066] a <ength> a list of <length>s a <number> a list of <number>s opacity value (e.g., <number>) a path data specification 'preserveAspectRatio' attribute specification \s*(none|xMinYMin|xMidYMin|xMaxYMin|xMinYMid|xMidYMid|xMaxYMid|xMinYMax|xMidYMax|xMaxYMax)(\s+meet|\s+slice)?\s* script expression An SVG color value (RGB plus optional ICC) arbitrary text string list of transforms a Uniform Resource Identifier, see [URI] 'viewBox' attribute specification epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/svg/svg-font.rng0000644000175000017500000001005113017276730027602 0ustar eugeneeugene SVG 1.1 Font Module file: svg-font.rng This is SVG, a language for describing two-dimensional graphics in XML. Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. $Id: svg-font.rng,v 1.1 2003/07/15 07:11:10 dean Exp $ Font font, font-face, glyph, missing-glyph, hkern, vkern, font-face-src, font-face-uri, font-face-format, font-face-name, definition-src This module declares markup to provide support for template. font-face: Font Face Element glyph: Glyph Element missing-glyph: Missing Glyph Element font-face-uri: Font Face URI Element font-face-format: Font Face Format Element definition-src: Definition Source Element epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/svg/svg-basic-filter.rng0000644000175000017500000005147013017276730031212 0ustar eugeneeugene SVG 1.1 Basic Filter Module file: svg-basic-filter.rng This is SVG, a language for describing two-dimensional graphics in XML. Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. $Id: svg-basic-filter.rng,v 1.1 2003/07/15 07:11:10 dean Exp $ Basic Filter filter, feBlend, feColorMatrix, feComponentTransfer, feComposite, feFlood, feGaussianBlur, feImage, feMerge, feMergeNode, feOffset, feTile, feFuncR, feFuncG, feFuncB, feFuncA This module declares markup to provide support for filter effect. Datatypes SVG.Filter.attrib SVG.FilterColor.attrib auto sRGB linearRGB inherit SVG.Filter.class SVG.FilterPrimitive.class SVG.FilterPrimitive.attrib SVG.FilterPrimitiveWithIn.attrib filter: Filter Element userSpaceOnUse objectBoundingBox userSpaceOnUse objectBoundingBox feBlend: Filter Effect Blend Element normal multiply screen darken lighten feColorMatrix: Filter Effect Color Matrix Element matrix saturate hueRotate luminanceToAlpha feComponentTransfer: Filter Effect Component Transfer Element feComposite: Filter Effect Composite Element over in out atop xor arithmetic feFlood: Filter Effect Flood Element feGaussianBlur: Filter Effect Gaussian Blur Element feImage: Filter Effect Image Element feMerge: Filter Effect Merge Element feMergeNode: Filter Effect Merge Node Element feOffset: Filter Effect Offset Element feTile: Filter Effect Tile Element feFuncR: Filter Effect Function Red Element identity table discrete linear gamma feFuncG: Filter Effect Function Green Element identity table discrete linear gamma feFuncB: Filter Effect Function Blue Element identity table discrete linear gamma feFuncA: Filter Effect Function Alpha Element identity table discrete linear gamma epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/svg/svg-pattern.rng0000644000175000017500000000736013017276730030322 0ustar eugeneeugene SVG 1.1 Pattern Module file: svg-pattern.rng This is SVG, a language for describing two-dimensional graphics in XML. Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. $Id: svg-pattern.rng,v 1.1 2003/07/15 07:11:10 dean Exp $ Pattern pattern This module declares markup to provide support for pattern fill. SVG.Pattern.class pattern: Pattern Element userSpaceOnUse objectBoundingBox userSpaceOnUse objectBoundingBox ././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootepubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/svg/svg-basic-graphics-attrib.rngepubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/svg/svg-basic-graphics-attrib.r0000644000175000017500000000415313017276730032457 0ustar eugeneeugene SVG 1.1 Basic Graphics Attribute Module file: svg-basic-graphics-attrib.rng This is SVG, a language for describing two-dimensional graphics in XML. Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. $Id: svg-basic-graphics-attrib.rng,v 1.1 2003/07/15 07:11:10 dean Exp $ Basic Graphics Attribute display, visibility This module defines the Graphics attribute set. inline block list-item run-in compact marker table inline-table table-row-group table-header-group table-footer-group table-row table-column-group table-column table-cell table-caption none inherit visible hidden inherit epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/svg/svg-profile.rng0000644000175000017500000000450513017276730030303 0ustar eugeneeugene SVG 1.1 Color Profile Module file: svg-profile.rng This is SVG, a language for describing two-dimensional graphics in XML. Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. $Id: svg-profile.rng,v 1.1 2003/07/15 07:11:10 dean Exp $ Color Profile color-profile This module declares markup to provide support for color profile. SVG.Profile.attrib SVG.Profile.class color-profile: Color Profile Element auto perceptual relative-colorimetric saturation absolute-colorimetric epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/svg/svg-xlink-attrib.rng0000644000175000017500000001211513017276730031247 0ustar eugeneeugene SVG 1.1 XLink Attribute Module file: svg-xlink-attrib.rng This is SVG, a language for describing two-dimensional graphics in XML. Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. $Id: svg-xlink-attrib.rng,v 1.1 2003/07/15 07:11:10 dean Exp $ XLink Attribute type, href, role, arcrole, title, show, actuate This module defines the XLink, XLinkRequired, XLinkEmbed, and XLinkReplace attribute set. simple other onLoad simple other onLoad simple embed onLoad simple new replace onRequest epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/svg/svg-viewport-attrib.rng0000644000175000017500000000326413017276730032006 0ustar eugeneeugene SVG 1.1 Viewport Attribute Module file: svg-viewport-attrib.rng This is SVG, a language for describing two-dimensional graphics in XML. Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. $Id: svg-viewport-attrib.rng,v 1.1 2003/07/15 07:11:10 dean Exp $ Viewport Attribute clip, overflow This module defines the Viewport attribute set. 'clip' property/attribute value (e.g., 'auto', rect(...)) visible hidden scroll auto inherit epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/svg/svg-extensibility.rng0000644000175000017500000000601013017276730031530 0ustar eugeneeugene SVG 1.1 Extensibility Module file: svg-extensibility.rng This is SVG, a language for describing two-dimensional graphics in XML. Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. $Id: svg-extensibility.rng,v 1.1 2003/07/15 07:11:10 dean Exp $ Extensibility foreignObject This module declares markup to provide support for extensibility. SVG.Extensibility.class foreignObject: Foreign Object Element any element in foreign namespace epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/svg/svg-paint-attrib.rng0000644000175000017500000001270513017276730031242 0ustar eugeneeugene SVG 1.1 Paint Attribute Module file: svg-paint-attrib.rng This is SVG, a language for describing two-dimensional graphics in XML. Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. $Id: svg-paint-attrib.rng,v 1.1 2003/07/15 07:11:10 dean Exp $ Paint Attribute fill, fill-rule, stroke, stroke-dasharray, stroke-dashoffset, stroke-linecap, stroke-linejoin, stroke-miterlimit, stroke-width, color, color-interpolation, color-rendering This module defines the Paint and Color attribute sets. a 'fill' or 'stroke' property/attribute value: <paint> 'stroke-dasharray' property/attribute value (e.g., 'none', list of <number>s) 'stroke-dashoffset' property/attribute value (e.g., 'none', <legnth>) 'stroke-miterlimit' property/attribute value (e.g., <number>) 'stroke-width' property/attribute value (e.g., <length>) butt round square inherit miter round bevel inherit auto sRGB linearRGB inherit auto optimizeSpeed optimizeQuality inherit epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/svg/svg-structure.rng0000644000175000017500000000527313017276730030706 0ustar eugeneeugene SVG 1.1 Structure Module file: svg-structure.rng This is SVG, a language for describing two-dimensional graphics in XML. Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. $Id: svg-structure.rng,v 1.1 2003/07/15 07:11:10 dean Exp $ Structure svg, g, defs, desc, title, metadata, symbol, use This module declares the major structural elements and their attributes. extend SVG.Structure.class symbol: Symbol Element epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/svg/svg-mask.rng0000644000175000017500000000727313017276730027603 0ustar eugeneeugene SVG 1.1 Mask Module file: svg-mask.rng This is SVG, a language for describing two-dimensional graphics in XML. Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. $Id: svg-mask.rng,v 1.1 2003/07/15 07:11:10 dean Exp $ Mask mask This module declares markup to provide support for masking. Datatypes SVG.Mask.attrib SVG.Mask.class mask: Mask Element userSpaceOnUse objectBoundingBox userSpaceOnUse objectBoundingBox epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/svg/svg-animevents-attrib.rng0000644000175000017500000000323513017276730032276 0ustar eugeneeugene SVG 1.1 Animation Events Attribute Module file: svg-animevents-attrib.rng This is SVG, a language for describing two-dimensional graphics in XML. Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. $Id: svg-animevents-attrib.rng,v 1.1 2003/07/15 07:11:10 dean Exp $ Animation Events Attribute onbegin, onend, onrepeat, onload This module defines the AnimationEvents attribute set. epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/svg/svg-basic-structure.rng0000644000175000017500000003637613017276730031775 0ustar eugeneeugene SVG 1.1 Basic Structure Module file: svg-basic-structure.rng This is SVG, a language for describing two-dimensional graphics in XML. Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. $Id: svg-basic-structure.rng,v 1.1 2003/07/15 07:11:10 dean Exp $ Basic Structure svg, g, defs, desc, title, metadata, use This module declares the major structural elements and their attributes.
Include core set of modules Datatypes Module Core Attribute Module
Content Models (Default) Attribute Collections (Default) SVG.Description.class SVG.Use.class SVG.Structure.class SVG.Presentation.attrib svg: SVG Document Element disable magnify 1.1 g: Group Element defs: Definisions Element desc: Description Element title: Title Element metadata: Metadata Element use: Use Element
epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/svg/svg-extresources-attrib.rng0000644000175000017500000000235713017276730032664 0ustar eugeneeugene SVG 1.1 External Resources Attribute Module file: svg-extresources-attrib.rng This is SVG, a language for describing two-dimensional graphics in XML. Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. $Id: svg-extresources-attrib.rng,v 1.1 2003/07/15 07:11:10 dean Exp $ External Resources Attribute externalResourcesRequired This module defines the External attribute set. epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/svg/svg-style.rng0000644000175000017500000000546213017276730030006 0ustar eugeneeugene SVG 1.1 Style Module file: svg-style.rng This is SVG, a language for describing two-dimensional graphics in XML. Copyright 2001, 2002 W3C (MIT, INRIA, Keio), All Rights Reserved. $Id: svg-style.rng,v 1.1 2003/07/15 07:11:10 dean Exp $ Style style This module declares markup to provide support for stylesheet. Datatypes comma-separated list of media descriptors. SVG.Style.attrib SVG.Style.class style: Style Element preserve epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/content.rng0000644000175000017500000000604413017276730026721 0ustar eugeneeugene epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/xhtml/0000755000175000017500000000000013017276730025667 5ustar eugeneeugeneepubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/xhtml/frames.rng0000644000175000017500000000426413017276730027662 0ustar eugeneeugene 1 0 noresize yes no auto epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/xhtml/inlstyle.rng0000644000175000017500000000037713017276730030251 0ustar eugeneeugene epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/xhtml/object.rng0000644000175000017500000000340413017276730027646 0ustar eugeneeugene declare epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/xhtml/pres.rng0000644000175000017500000000363013017276730027352 0ustar eugeneeugene epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/xhtml/applet.rng0000644000175000017500000000202013017276730027656 0ustar eugeneeugene epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/xhtml/image.rng0000644000175000017500000000151513017276730027463 0ustar eugeneeugene epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/xhtml/ruby.rng0000644000175000017500000000353213017276730027363 0ustar eugeneeugene epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/xhtml/text.rng0000644000175000017500000001422013017276730027362 0ustar eugeneeugene preserve epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/xhtml/hypertext.rng0000644000175000017500000000246013017276730030435 0ustar eugeneeugene epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/xhtml/events.rng0000644000175000017500000001100213017276730027675 0ustar eugeneeugene epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/xhtml/ssismap.rng0000644000175000017500000000052513017276730030060 0ustar eugeneeugene ismap epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/xhtml/bdo.rng0000644000175000017500000000134213017276730027143 0ustar eugeneeugene ltr rtl epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/xhtml/base.rng0000644000175000017500000000070513017276730027313 0ustar eugeneeugene epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/xhtml/basic-form.rng0000644000175000017500000000776513017276730030440 0ustar eugeneeugene get post checked text password checkbox radio submit reset hidden multiple selected epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/xhtml/link.rng0000644000175000017500000000225313017276730027336 0ustar eugeneeugene epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/xhtml/form.rng0000644000175000017500000001047113017276730027345 0ustar eugeneeugene disabled readonly image button disabled disabled disabled disabled readonly button submit reset disabled epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/xhtml/edit.rng0000644000175000017500000000213013017276730027320 0ustar eugeneeugene epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/xhtml/struct.rng0000644000175000017500000000261713017276730027731 0ustar eugeneeugene epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/xhtml/attribs.rng0000644000175000017500000000247413017276730030056 0ustar eugeneeugene epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/xhtml/list.rng0000644000175000017500000000311413017276730027351 0ustar eugeneeugene epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/xhtml/table.rng0000644000175000017500000001216413017276730027472 0ustar eugeneeugene left center right justify char top middle bottom baseline row col rowgroup colgroup void above below hsides lhs rhs vsides box border none groups rows cols all epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/xhtml/meta.rng0000644000175000017500000000136213017276730027327 0ustar eugeneeugene epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/xhtml/target.rng0000644000175000017500000000125213017276730027665 0ustar eugeneeugene epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/xhtml/csismap.rng0000644000175000017500000000417113017276730030041 0ustar eugeneeugene nohref rect circle poly default epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/xhtml/datatypes.rng0000644000175000017500000000477413017276730030411 0ustar eugeneeugene epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/xhtml/nameident.rng0000644000175000017500000000154613017276730030351 0ustar eugeneeugene epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/xhtml/param.rng0000644000175000017500000000123613017276730027501 0ustar eugeneeugene data ref object epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/xhtml/basic-table.rng0000644000175000017500000000541113017276730030546 0ustar eugeneeugene left center right top middle bottom row col epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/xhtml/legacy.rng0000644000175000017500000002356513017276730027656 0ustar eugeneeugene compact compact top middle bottom left right left all right none compact left center right noshade top middle bottom left right top bottom left right top middle bottom left right compact nowrap compact left all right none epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/xhtml/script.rng0000644000175000017500000000260613017276730027707 0ustar eugeneeugene defer preserve epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/xhtml/iframe.rng0000644000175000017500000000262513017276730027647 0ustar eugeneeugene 1 0 yes no auto epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/xhtml/style.rng0000644000175000017500000000136713017276730027546 0ustar eugeneeugene preserve epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/opf.rng0000644000175000017500000000053113017276730026026 0ustar eugeneeugene epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/opf12.rng0000644000175000017500000002311213017276730026171 0ustar eugeneeugene yes no epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/svg11.rng0000644000175000017500000001303613017276730026207 0ustar eugeneeugene RELAX NG schema for SVG 1.1 file: svg11.rng This is SVG, a language for describing two-dimensional graphics in XML. The Scalable Vector Graphics (SVG) Copyright 2001, 2002 World Wide Web Consortium (Massachusetts Institute of Technology, Institut National de Recherche en Informatique et en Automatique, Keio University). All Rights Reserved. Permission to use, copy, modify and distribute this RELAX NG schema for SVG and its accompanying documentation for any purpose and without fee is hereby granted in perpetuity, provided that the above copyright notice and this paragraph appear in all copies. The copyright holders nor the author make no representation about the suitability of this RELAX NG schema for any purpose. It is provided "as is" without expressed or implied warranty. Author: Masayasu Ishikawa (mimasa@w3.org) $Id: svg11.rng,v 1.1 2003/07/15 07:11:10 dean Exp $ This is the driver file for version 1.1 of the SVG RELAX NG schema. The DTD version is identified by the PUBLIC and SYSTEM identifiers: PUBLIC "-//W3C//DTD SVG 1.1//EN" SYSTEM "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" Use this URI to identify the default namespace: "http://www.w3.org/2000/svg" Container Attribute Module Viewport Attribute Module Paint Attribute Module Paint Opacity Attribute Module Graphics Attribute Module Document Events Attribute Module Graphical Element Events Attribute Module Animation Events Attribute Module XLink Attribute Module External Resources Attribute Module Structure Module (required) Conditional Processing Module Image Module Style Module Shape Module Text Module Marker Module Color Profile Module Gradient Module Pattern Module Clip Module Mask Module Filter Module Cursor Module Hyperlinking Module View Module Scripting Module Animation Module Font Module Extensibility Module The root element is "svg". epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/schema/20/rng/content-xhtml.rng0000644000175000017500000000056713017276730030057 0ustar eugeneeugene epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/api/0000755000175000017500000000000013017276730023035 5ustar eugeneeugeneepubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/api/project.properties0000644000175000017500000000006313017276730026620 0ustar eugeneeugeneversion=${pom.version} buildDate=${tool.build.date}epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/util/0000755000175000017500000000000013017276730023241 5ustar eugeneeugeneepubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/util/messages_de.properties0000644000175000017500000001414213017276730027640 0ustar eugeneeugenesingle_file=Validierung erfolgt für diese Datei als Einzeldatei vom Typ %1$s, gegen EPUB-Version %2$s und mit dem %3$s-Profil. Nur ein kleiner Teil der verfügbaren Tests wird ausgeführt. opv_version_test=*** Candidate for msg deletion *** Tests are performed only for the OPF version. mode_version_not_supported=EpubCheck validiert Dateien vom Typ %1$s und Version %2$s nicht. no_errors__or_warnings=Das EPUB enthält keine Fehler oder Warnungen.\nEs ist valide. there_were_errors=\nEpubCheck mit Fehlern abgeschlossen.\n there_were_warnings=\nEpubCheck mit Warnungen abgeschlossen.\n error_processing_unexpanded_epub=\nDiese Prüfung kann entpackte EPUB's nicht validieren!\n deleting_archive=\nEPUB-Erstellung abgebrochen, weil Fehler aufgetreten sind.\n display_help=-help zeigt die Hilfe zu EpubCheck an. argument_needed=Es wird mindestens ein Parameter erwartet! version_argument_expected=Dem Versions-Parameter -v fehlt die Versionsnummer! mode_argument_expected=Dem --mode Parameter fehlt der Typ!. profile_argument_expected=Dem --profile Parameter fehlt der Profilname. profile_unknown=Unbekanntes Profil '%1$s'. Es wird das Standard-Validierungsprofil angewendet. no_file_specified=In den Parametern wurde keine Datei spezifiziert. EpubCheck wird beendet! mode_version_ignored=Die Parameter --mode und -v werden für EPUB-Dateien ignoriert. Die Werte werden aus dem EPUB entnommen. mode_required=Parameter --mode ist für Dateien die kein EPUB sind zwingend erforderlich. Die Standard-Version zur Validierung ist 3.0 validating_version_message=Verwendung der EPUB %1$s Prüfungen output_type_conflict=Es kann nur ein Ausgabeformat gleichzeitig angegeben werden! validating_against_epub_version=Validierung gegen den EPUB-Standard Version %1$s file_not_found=Datei wurde nicht gefunden: '%1$s' epubcheck_completed=EpubCheck abgeschlossen error_creating_config_file=Fehler beim Erstellen der Konfigurationsdatei: '%1$s' expected_message_filename=Es wird die benutzerspezifische Datei zum Überschreiben von Warnungen und Fehlermeldungen erwartet, gefunden wurde aber '%1$s' unrecognized_argument=Unbekannter Parameter: '%1$s' help_text = EpubCheck v%1$s\n\n\ Der erste Parameter der an dieses Tool übergeben werden sollte,\n\ sollte der Dateipfad der zu prüfenden Datei sein.\n\n\ Um ein Validierungsprofil anzugeben, verwende den Parameter --profile\n\ Validierungsprofile können verwendet werden, um gegen ein spezielles EPUB 3-Profil\n\ oder eine erweiterte Spezifikation zu validieren.\n\n\ Unterstützte Validierungsprofile:\n\ --profile default // Das Standard-Validierungsprofil\n\ --profile dict // Validiert gegen die 'EPUB Dictionaries and Glossaries'-Spezifikation\n\ --profile edupub // Validiert gegen das 'EDUPUB'-Profil\n\ --profile idx // Validiert gegen die 'EPUB Indexes'-Spezifikation\n\ --profile preview // Validiert gegen die 'EPUB Previews'-Spezifikation\n\n\ Wenn eine Datei geprüft wird die kein gezipptes EPUB ist,\n\ dann muss die EPUB-Versionsnummer gegen die geprüft werden soll\n\ mit dem Parameter -v angegeben werden, sowie der Typ der Datei\n\ mit dem Parameter --mode\n\ Die Standard-Version zur Validierung ist 3.0\n\n\ Unterstützte Werte für die Parameter --mode und -v:\n\ --mode opf -v 2.0 // Für OPF-Dateien der Version 2.0\n\ --mode opf -v 3.0 // Für OPF-Dateien der Version 3.0\n\ --mode xhtml -v 2.0 // Für XHTML-Dateien der Version 2.0\n\ --mode xhtml -v 3.0 // Für XHTML-Dateien der Version 3.0\n\ --mode svg -v 2.0 // Für SVG-Dateien der Version 2.0\n\ --mode svg -v 3.0 // Für SVG-Dateien der Version 3.0\n\ --mode nav -v 3.0 // Für EPUB-Navigationsdokumente der Version 3.0\n\ --mode mo -v 3.0 // Für EPUB-MediaOverlays der Version 3.0\n\ --mode exp // Für entpackte EPUB-Archive\n\n\ EpubCheck akzeptiert diese weiteren Optionen:\n\ --save = generiert ein EPUB aus dem entpackten Ordner\n\ --out = speichert das Ergebnis der Validierung im XML-Format\n\ --xmp = speichert das Ergebnis der Validierung im XMP-Format\n\ --json = speichert das Ergebnis der Validierung im JSON-Format\n\ -m = Synonym zu --mode\n\ -p = Synonym zu --profile\n\ -o = Synonym zu --out\n\ -x = Synonym zu --xmp\n\ -j = Synonym zu --json\n\ --failonwarnings[+|-] = Standardmäßig endet EpubCheck mit ExitCode 1 falls Fehler im EPUB gefunden wurden\n\ \ und mit ExitCode 0, falls keine Fehler gefunden wurden. Bei Nutzung von --failonwarnings\n\ \ wird EpubCheck auch bereits bei Auftreten von Warnungen mit ExitCode 1 beendet.\n\ -q, --quiet = Nur Fehler werden auf der Konsole ausgegeben\n\ -f, --fatal = Nur Fatale Fehler ausgeben\n\ -e, --error = Nur Fatale Fehler und Fehler ausgeben\n\ -w, --warn = Fatale Fehler, Fehler und Warnungen ausgeben\n\ -u, --usage = Informationen zur Nutzung bestimmter EPUB-Features ausgeben (Standardmäßig ausgeschaltet);\n\ \ wenn aktiviert, dann werden Informationen immer auch in die Ausgabedatei aufgenommen.\n\n\ -l, --listChecks [] = Ausgabe aller Message-ID's und Fehler-Level in eine\n\ \ benutzerdefinierte Datei oder auf der Konsole.\n\ -c, --customMessages [] = Überschreibt die Fehler-Level von EpubCheck wie in der\n\ \ benutzerdefinierten Datei angegeben.\n\n\ -h, -? oder --help = Zeigt diese Hilfe an\n\ epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/util/messages_it.properties0000644000175000017500000001244013017276730027663 0ustar eugeneeugenesingle_file=Il file sarà controllato come singolo file di tipo %1$s e versione %2$s. Solo un sottoinsieme dei test disponibili sarà eseguito. opv_version_test=*** Candidato per essere eliminato *** I test sono eseguiti solo per la versione OPF. mode_version_not_supported=Questo programma non supporta il tipo %1$s o la versione %1$s. no_errors__or_warnings=Non sono stati trovati errori o potenziali errori. there_were_errors=\nSono stati rilevati errori.\n there_were_warnings=\nSono stati rilevati potenziali errori.\n error_processing_unexpanded_epub=\nI controlli richiesti non possono essere effettuati su file decompressi.\n deleting_archive=\nCreazione del file EPUB terminata a causa di errori rilevati.\n display_help=-help mosta la guida. argument_needed=È richiesto almeno un argomento. version_argument_expected=Non è stato specificato un valore per l'argomento -v. mode_argument_expected=Non è stato specificato un valore per l'argomento --mode. no_file_specified=Non è stato specificato un file. mode_version_ignored=I valori degli argomenti --mode e -v sono ignorati per i file EPUB compressi, perché letti dal file stesso. mode_required=Il parametro --mode è richiesto se non si indica un file EPUB. Il valore predefinito di -v è 3.0. validating_version_message=Controllo secondo le regole per EPUB versione %1$s. output_type_conflict=Può essere specificato un solo formato di output. validating_against_epub_version=Controllo secondo le regole per EPUB versione %1$s (regole personalizzate). file_not_found=File non trovato: '%1$s'. epubcheck_completed=Controllo completato. error_creating_config_file=Errore durante la creazione del file di regole personalizzate '%1$s'. expected_message_filename=Era atteso un file di regole personalizzate, invece è stato trovato '%1$s'. unrecognized_argument=Argumento non riconosciuto: '%1$s'. help_text = \ EpubCheck v%1$s\n\n\ Il primo argomento è il percorso completo del file da controllare.\n\ \n\ Se non si controlla un file EPUB, la versione EPUB deve essere specificata\n\ usando -v e il tipo di file usando --mode. La versione predefinita è la 3.0.\n\ \n\ Tipi di controlli e corrispondenti versioni EPUB:\n\ --mode exp = controlla file decompressi\n\ --mode mo -v 3.0 = controlla Media Overlays\n\ --mode nav -v 3.0 = controlla Navigation Document\n\ --mode opf -v 2.0 = controlla file OPF\n\ --mode opf -v 3.0 = controlla file OPF\n\ --mode svg -v 2.0 = controlla file SVG\n\ --mode svg -v 3.0 = controlla file SVG\n\ --mode xhtml -v 2.0 = controlla file XHTML\n\ --mode xhtml -v 3.0 = controlla file XHTML\n\ \n\ Argomenti opzionali:\n\ --save = crea un EPUB compresso alla fine del controllo\n\ --out = produci un documento XML coi risultati\n\ \ ('-' per l'output in console)\n\ --xmp = produci un documento XMP coi risultati\n\ \ ('-' per l'output in console)\n\ --json = produci un documento JSON coi risultati\n\ \ ('-' per l'output in console)\n\ -m = sinonimo di --mode\n\ -o = sinonimo di --out\n\ -x = sinonimo di --xmp\n\ -j = sinonimo di --json\n\ --failonwarnings[+|-] = di norma, ritorna 1 se sono rilevati errori,\n\ \ e 0 altrimenti.\n\ \ Specificando --failonwarnings, sarà ritornato\n\ \ 1 in presenza di errori o potenziali errori\n\ \ e 0 altrimenti.\n\ -q, --quiet = non stampa messaggi in console, salvo errori\n\ -f, --fatal = includi solo gli errori fatali nell'output\n\ -e, --error = includi gli errori (fatali e non) nell'output\n\ -w, --warn = includi gli errori (fatali e non) e\n\ \ i potenziali errori nell'output\n\ -u, --usage = includi informazioni sull'uso delle\n\ \ varie specifiche EPUB nell'output;\n\ \ se abilitate, tali informazioni saranno\n\ \ sempre incluse nell'output \n\ \n\ -l, --listChecks [] = salva gli id e i livelli di errore nel\n\ \ file personalizzato o stampali\n\ \ nella console (se è omesso)\n\ -c, --customMessages [] = ridefinisci i livelli di errore come\n\ \ specificato nel file personalizzato \n\ \n\ -h, -? o --help = stampa questa guida\n epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/util/messages_es.properties0000644000175000017500000001245713017276730027666 0ustar eugeneeugenesingle_file=El archivo se valida como archivo único de tipo %1$s y versión %2$s. Solo se ejecuta una parte de los tests disponibles. opv_version_test=*** Candidato para el borrado msg *** Los tests solo se aplican a la versión OPF. mode_version_not_supported=El validador no actúa sobre el tipo %1$s y la versión %2$s. no_errors__or_warnings=No se han detectado errores o advertencias. there_were_errors=\nPrueba finalizada con errores\n there_were_warnings=\nPrueba finalizada con advertencias\n error_processing_unexpanded_epub=\nLa prueba no puede procesar epubs expandidos\n deleting_archive=\nSe ha cancelado la creación del epub porque se han detectado errores.\n display_help=-help muestra la ayuda argument_needed=Se esperaba al menos un argumento version_argument_expected=El número de versión se ha omitido en el argumento -version. mode_argument_expected=El tipo se ha omitido en el argumento -mode. profile_argument_expected=El nombre de perfil se ha omitido después del argumento -profile. profile_unknown=Perfil '%1$s' desconocido; se usará el perfil por defecto. no_file_specified=No se ha especificado un archivo en el argumento. Saliendo. mode_version_ignored=Los argumentos modo y versión se ignoran para epubs. Se extraen de los archivos. mode_required=Mode es obligatorio para archivos que no sean epub. La versión actual es 3.0. validating_version_message=Validación usando la versión de reglas epub %1$s. output_type_conflict=Solo se puede especificar un formato de salida cada vez. validating_against_epub_version=Validación con la versión EPUB %1$s - validación personalizada file_not_found=No se encuentra el archivo: '%1$s' epubcheck_completed=epubcheck completado error_creating_config_file=Error al crear el archivo de configuración '%1$s'. expected_message_filename=Se esperaba nombre de archivo personalizado, pero se ha mostrado '%1$s' unrecognized_argument=Argumento desconocido: '%1$s' help_text = EpubCheck v%1$s\n\n\ Para ejecutar epubcheck el primer argumento debe ser el nombre (y la ruta)\n\ del archivo que se valida.\n\n\ Para especificar un perfil de validación (ejecuta comprobaciones sobre un perfil EPUB 3 específico\n\ o una especificación), use la opción -profile:\n\n\ Perfiles de validación soportados:\n\ --profile default // perfil de validación por defecto\n\ --profile dict // valida sobre la especificación EPUB Diccionarios y Glosarios\n\ --profile edupub // valida sobre el perfil EDUPUB \n\ --profile idx // valida sobre la especificación EPUB Índices\n\ --profile preview // valida sobre la especificación EPUB Vistas Previas\n\n\ Si se valida un archivo que no sea epub, la versión epub del archivo\n\ debe especificarse con -v y el tipo de archivo con -mode.\n\ La versión por defecto es: 3.0.\n\n\ Modos y versiones soportados: \n\ --mode opf -v 2.0\n\ --mode opf -v 3.0\n\ --mode xhtml -v 2.0\n\ --mode xhtml -v 3.0\n\ --mode svg -v 2.0\n\ --mode svg -v 3.0\n\ --mode nav -v 3.0\n\ --mode mo -v 3.0 // Para la validación de Media Overlays\n\ --mode exp // Para archivos EPUB expandidos\n\n\ Esta herramientas permite las siguientes opciones:\n\ --save \t = guarda el epub creado a partir del epub expandido\n\ --out = extrae un fichero XML de validación (utilice - para salida a la consola)\n\ --xmp = extrae un fichero XMP de validación (utilice - para salida a la consola)\n\ --json = extrae un fichero JSON de validación (utilice - para salida a la consola)\n\ -m = igual a --mode\n\ -p = igual a --profile\n\ -o = igual a --out\n\ -x = igual a --xmp\n\ -j = igual a --json\n\ --failonwarnings[+|-] = Por defecto, la herramienta devuelve 1 si se encuentran errores en el archivo o 0 si no hay errores\n\ \ Utilizar --failonwarnings provoca la detención del proceso con un resultado\n\ \ de 1 si hay errores o advertencias y 0 cuando no los hay.\n\ -q, --quiet = no hay mensajes en la consola; excepto errores, solo en la salida\n\ -f, --fatal = incluye solo errores en la salida\n\ -e, --error = incluye solo errores y errores graves en la salida\n\ -w, --warn = incluye solo errores, errores graves y advertencias en la salida\n\ -u, --usage = incluye información sobre el uso de ePub en la salida\n\ \ (por defecto es OFF); si está activada, la información de uso será incluida\n\ \ en el archivo de salida\n\n\ -l, --listChecks [] = enumera los identificadores de mensaje y los niveles de gravedad en el archivo personalizado de mensajes \n\ \ o en la consola\n\ -c, --customMessages [] = sobreescribe los niveles de gravedad del mensaje según los parámetros del archivo personalizado de mensajes \n\n\ -h, -? or --help = muestra este texto de ayuda\n\ epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/util/messages.properties0000644000175000017500000001213313017276730027166 0ustar eugeneeugenesingle_file=File is validated as a single file of type %1$s, for EPUB version %2$s using the %3$s validation profile. Only a subset of the available tests is run. opv_version_test=*** Candidate for msg deletion *** Tests are performed only for the OPF version. mode_version_not_supported=The checker doesn't validate type %1$s and version %2$s. no_errors__or_warnings=No errors or warnings detected. there_were_errors=\nCheck finished with errors\n there_were_warnings=\nCheck finished with warnings\n error_processing_unexpanded_epub=\nThis check cannot process expanded epubs\n deleting_archive=\nEpub creation cancelled due to detected errors.\n display_help=-help displays help argument_needed=At least one argument expected version_argument_expected=Version number omitted from the -version argument. mode_argument_expected=Type omitted from the -mode argument. profile_argument_expected=Profile name omitted after the -profile argument. profile_unknown=Unknown profile '%1$s', using default validation profile. no_file_specified=No file specified in the arguments. Exiting. mode_version_ignored=The mode and version arguments are ignored for epubs. They are retrieved from the files. mode_required=Mode required for non-epub files. Default version is 3.0. validating_version_message=Validating using EPUB version %1$s rules. output_type_conflict=Only one output format can be specified at a time. validating_against_epub_version=Validating against EPUB version %1$s - custom validation file_not_found=File not found: '%1$s' epubcheck_completed=epubcheck completed error_creating_config_file=Error creating config file '%1$s'. expected_message_filename=Expected the Custom message file name, but found '%1$s' unrecognized_argument=Unrecognized argument: '%1$s' help_text = \ EpubCheck v%1$s\n\n\ When running this tool, the first argument should be the name (with the path)\n\ of the file to check.\n\ \n\ To specify a validation profile (to run checks against a specific EPUB 3 profile\n\ or extension specification), use the -profile option:\n\ \n\ Validation profiles supported:\n\ --profile default // the default validation profile\n\ --profile dict // validates against the EPUB Dictionaries and Glossaries specification\n\ --profile edupub // validates against the EDUPUB Profile\n\ --profile idx // validates against the EPUB Indexes specification\n\ --profile preview // validates against the EPUB Previews specification\n\ \n\ If checking a non-epub file, the epub version of the file must\n\ be specified using -v and the type of the file using -mode.\n\ The default version is: 3.0.\n\ \n\ Modes and versions supported: \n\ --mode opf -v 2.0\n\ --mode opf -v 3.0\n\ --mode xhtml -v 2.0\n\ --mode xhtml -v 3.0\n\ --mode svg -v 2.0\n\ --mode svg -v 3.0\n\ --mode nav -v 3.0\n\ --mode mo -v 3.0 // For Media Overlays validation\n\ --mode exp // For expanded EPUB archives\n\ \n\ This tool also accepts the following options:\n\ --save = saves the epub created from the expanded epub\n\ --out = output an assessment XML document file (use - to output to console)\n\ --xmp = output an assessment XMP document file (use - to output to console)\n\ --json = output an assessment JSON document file (use - to output to console)\n\ -m = same as --mode\n\ -p = same as --profile\n\ -o = same as --out\n\ -x = same as --xmp\n\ -j = same as --json\n\ --failonwarnings[+|-] = By default, the tool returns a 1 if errors are found in the file or 0 if no errors\n\ \ are found. Using --failonwarnings will cause the process to exit with a status of\n\ \ 1 if either warnings or errors are present and 0 only when there are no errors or warnings.\n\ -q, --quiet = no message on console, except errors, only in the output\n\ -f, --fatal = include only fatal errors in the output\n\ -e, --error = include only error and fatal severity messages in ouput\n\ -w, --warn = include fatal, error, and warn severity messages in output\n\ -u, --usage = include ePub feature usage information in output\n\ \ (default is OFF); if enabled, usage information will\n\ \ always be included in the output file\n\ \n\ -l, --listChecks [] = list message ids and severity levels to the custom message file named \n\ \ or the console\n\ -c, --customMessages [] = override message severity levels as defined in the custom message file named \n\ \n\ -h, -? or --help = displays this help message\n epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/util/messages_fr.properties0000644000175000017500000001366413017276730027667 0ustar eugeneeugenesingle_file=Le fichier est validé en tant que fichier individuel de type %1$s, pour EPUB version %2$s utilisant le profil de validation %3$s. Seul un sous-ensemble des tests disponibles est lancé. opv_version_test=*** Candidat à la suppression *** Les tests sont passés uniquement sur la version OPF. mode_version_not_supported=Le validateur ne fonctionne que sur le type %1$s et la version %2$s. no_errors__or_warnings=Aucune erreur ou avertissement détecté. there_were_errors=\nVérifications terminés avec des erreurs\n there_were_warnings=\nVérifications terminés avec des avertissements\n error_processing_unexpanded_epub=\nCette vérification ne peut être menée sur des epubs éclatés\n deleting_archive=\nLa création de l'epub a été annulée suite aux erreurs détectées.\n display_help=-help affiche l'aide argument_needed=Un argument au moins est attendu version_argument_expected=Le numéro de version a été omis dans l'argument -version. mode_argument_expected=Le type a été omis dans l'argument -mode. profile_argument_expected=Le nom du profil a été omis après l'argument -profile. profile_unknown=Profile '%1$s' inconnu, utilisation du profil de validation par défaut. no_file_specified=Aucun fichier n'a été précisé dans les arguments. Sortie. mode_version_ignored=Les arguments de mode et de version sont ignorés pour les epubs. Ils sont récupérés dans les fichiers. mode_required=Argument mode obligatoire pour les fichiers non-epubs. La version par défault est 3.0. validating_version_message=Vérifications faites en utilisant les règles de la version epub %1$s. output_type_conflict=Seul un type de format de sortie peut être précisé à la fois. validating_against_epub_version=Vérification par rapport à l'epub version %1$s - vérification personnalisée file_not_found=Fichier introuvable : '%1$s' epubcheck_completed=epubcheck terminé error_creating_config_file=Erreur lors de la création du fichier de configuration '%1$s'. expected_message_filename=Nom du fichier de configuration personnalisée attendu, mais '%1$s' fourni unrecognized_argument=Argument inconnu: '%1$s' help_text = EpubCheck v%1$s\n\n\ Pour utiliser cet outil, le premier argument doit être le nom (ou le chemin) du fichier à valider.\n\n\ Pour spécifier un profil de validation (pour effectuer les vérifications spécifiques à un profil ou une extension EPUB 3), utilisez l'option -profile.\n\n\ Profils de validation acceptés :\n\ --profile default // le profil de validation par défaut\n\ --profile dict // vérifie les règles de la spécification Dictionnaires et Glossaires EPUB\n\ --profile edupub // vérifie les règles du profil EDUPUB\n\ --profile idx // vérifie les règles de la spécification Indexes EPUB\n\ --profile preview // vérifie les règles de la spécification Aperçus EPUB\n\n\ En cas de vérification d'un fichier simple inclus dans un EPUB, la version de la spécification EPUB à vérifier doit être spécifiée avec l'option -v et le type de \n\ fichier avec l'option -mode.\n\ La version par défaut est 3.0.\n\n\ Modes et versions acceptés : \n\ --mode opf -v 2.0\n\ --mode opf -v 3.0\n\ --mode xhtml -v 2.0\n\ --mode xhtml -v 3.0\n\ --mode svg -v 2.0\n\ --mode svg -v 3.0\n\ --mode nav -v 3.0\n\ --mode mo -v 3.0 // Pour une vérification des Media Overlays\n\ --mode exp // Pour une vérification de répertoire EPUB non-compressé\n\n\ Cet outil accepte les options suivantes :\n\ --save \t = sauvegarde un EPUB créé depuis un EPUB non-compressé\n\ --out = produit un rapport de validation XML (utiliser - pour le produire sur la\n\ \ sortie standard)\n\ --xmp = produit un rapport de validation XMP (utiliser - pour le produire sur la\n\ \ sortie standard)\n\ --json = produit un rapport de validation JSON (utiliser - pour le produire sur la\n\ \ sortie standard)\n\ -m = voir --mode\n\ -p = voir --profile\n\ -o = voir --out\n\ -x = voir --xmp\n\ -j = voir --json\n\ --failonwarnings[+|-] = Par défaut, cet outil renvoie 1 si des erreurs sont trouvées ou 0 si le fichier\n\ \ ne contient aucune erreurs. En utilisant --failonwarnings, 1 sera renvoyé également\n\ \ en cas de warnings, et 0 ne sera renvoyés que si le fichier ne contient ni erreurs ni\n\ \ warnings.\n\ -q, --quiet = seuls les messages d'erreurs sont produits sur la sortie standard.\n\ -f, --fatal = inclure uniquement les erreurs fatales dans la sortie.\n\ -e, --error = inclure uniquement les erreurs et erreurs fatales dans la sortie.\n\ -w, --warn = inclure uniquement les erreurs, erreurs fatales, et warnings dans la sortie.\n\ -u, --usage = inclure les informations d'usage dans la sortie (OFF par défaut) ;\n\ \ si cette option est activée, des informations d'usage apparaitront systématiquement\n\ \ dans les rapports de validation.\n\n\ -l, --listChecks [] = liste les identificateurs de message et les niveaux de sévérité dans le fichier\n\ \ de sortie ou sur la sortie standard.\n\ -c, --customMessages [] = remplace les niveaux de sévérité par défaut par ceux contenus\n\ \ dans le fichier \n\n\ -h, -? or --help = affiche cette aide epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/util/messages_nl.properties0000644000175000017500000001333013017276730027657 0ustar eugeneeugenesingle_file=Het bestand is gevalideerd als een los bestand van type %1$s en versie %2$s met gebruik van het %3$s validatieprofiel. Slechts een beperkt aantal van de aanwezige tests is uitgevoerd. opv_version_test=*** Deze boodschap wordt wellicht verwijderd *** De teste worden alleen voor de OPF versie uitgevoerd. mode_version_not_supported=De check kan type %1$s en versie %2$s niet valideren. no_errors__or_warnings=Geen fouten of waarschuwingen gedetecteerd. there_were_errors=\nDe check heeft fouten opgeleverd.\n there_were_warnings=\nDe check heeft waarschuwingen opgeleverd.\n error_processing_unexpanded_epub=\nDeze check kan niet gebruikt worden voor het controleren van uitgepakte epubs.\n deleting_archive=\nHet vervaardigen van uw epub is afgebroken wegens ontdekte fouten.\n display_help=-help geeft de hulpboodschappen weer argument_needed=Er wordt tenminste 1 argument verwacht version_argument_expected=U heeft het versienummer niet ingevuld bij het -version argument. mode_argument_expected=U heeft het type niet ingevuld bij het -mode argument. profile_argument_expected=Geen profielnaam ingevuld na het het -profile argument. profile_unknown=Onbekend profiel '%1$s', het standaard validatieprofiel wordt gebruikt. no_file_specified=Geen bestand opgegeven in de argumenten. Het programma wordt afgesloten. mode_version_ignored=Voor epubs worden de argumenten 'mode' en 'version' genegeerd. Deze worden uit de bestanden zelf afgeleid. mode_required=Het argument 'mode' is verplicht voor niet-epub bestanden. Standaardversie is 3.0. validating_version_message=Validatie geschiedt op basis van de regels van EPUB versie %1$s. output_type_conflict=U kunt slechts 1 uitvoerformaat per keer specificeren. validating_against_epub_version=Validatie geschiedt op basis van de regels van EPUB versie %1$s - aangepaste validatie. file_not_found=Bestand niet gevonden: '%1$s' epubcheck_completed=epubcheck is klaar error_creating_config_file=Foutmelding bij het aanmaken van het configuratiebestand '%1$s'. expected_message_filename=Er werd een bestandsnaam met een aangepaste boodschap verwacht, maar '%1$s' is aangetroffen unrecognized_argument=Dit argument werd niet herkend: '%1$s' help_text = EpubCheck v%1$s \n\n\ Bij het starten van dit programma wordt als eerste argument de bestandsnaam (inclusief directorypad) van het te controleren bestand verwacht. \n\n\ Om een validatieprofiel te specificeren (om te checken tegen een specifiek ePub 3 profiel\n\ of extensiespecificatie), gebruikt u de -profile optie:\n\n\ Ondersteunde validatieprofielen:\n\ --profile default // het standaard validatieprofiel\n\ --profile dict // valideert tegen de ePub Dictionaries & Glossaries specificatie\n\ --profile edupub // valideert tegen de EDUPUB specificatie\n\ --profile idx // valideert tegen de ePub Indexes specificatie\n\ --profile preview // valideert tegen de ePub Previews specificatie\n\n\ Als u een bestand wilt controleren dat geen epub is moet de epub-versie worden gespecificeerd met gebruik van -v \n\ en het type bestand met gebruik van -mode. \n\ De standaardversie is 3.0. \n\n\ De ondersteunde modes en versies: \n\ --mode opf -v 2.0 \n\ --mode opf -v 3.0 \n\ --mode xhtml -v 2.0 \n\ --mode xhtml -v 3.0 \n\ --mode svg -v 2.0 \n\ --mode svg -v 3.0 \n\ --mode nav -v 3.0 \n\ --mode mo -v 3.0 // Voor het valideren van Media Overlays \n\ --mode exp // Voor uitgepakte epub structuren \n\n\ Dit programma accepteert ook de volgende optionele instellingen: \n\ --save ⇥ = slaat een epub op vanuit de uitgepakte epub structuur \n\ --out = geeft een XML bestand met het resultaat van de check (wordt gebruikt om de resultaten in het console weer te geven) \n\ --xmp = geeft een XMP bestand met het resultaat van de check (wordt gebruikt om de resultaten in het console weer te geven) \n\ --json = geeft een JSON bestand met het resultaat van de check (wordt gebruikt om de resultaten in het console weer te geven) \n\ -m = gelijk aan --mode \n\ -p = gelijk aan --profile\n\ -o = gelijk aan --out \n\ -x = gelijk aan --xmp \n\ -j = gelijk aan --json \n\ --failonwarnings[+|-] = standaard geeft het programma een waarde van 1 als er fouten worden gedetecteerd \n\ en een waarde van 0 als alles OK is. \n\ Gebruik --failonwarnings als u wilt dat er een waarde van 1 wordt teruggegeven als er fouten \n\ OF waarschuwingen worden ontdekt. \n\ Een waarde van 0 betekent dat er fouten noch waarschuwingen gedetecteerd zijn. \n\ -q, --quiet = geen berichten in de console, afgezien van eventuele foutmeldingen. In de output vindt u wel alles terug. \n\ -f, --fatal = meldt alleen fatale fouten in de output \n\ -e, --error = meldt alleen foutmeldingen en berichten met fatale afloop in de output \n\ -w, --warn = zowel fatale, foutmeldingen en waarschuwingen in de output \n\ -u, --usage = vermeldt de instellingen van dit programma in de output \n\ (standaard staat dit OFF); wanneer dit op ON staat wordt deze \n\ informatie altijd weergegeven in het outputbestand. \n\ -l, --listChecks [] = geeft bericht IDs en zwaartegraden weer in het berichtenbestand \n\ met de naam of het console. \n\ -c, --customMessages [] = gebruikt de zwaartegraden uit het aparte berichtenbestand \n\ met de naam \n\ -h, -? of --help = geeft dit hulpbestand weer\n\ epubcheck-4.0.2/src/main/resources/com/adobe/epubcheck/util/messages_ja.properties0000644000175000017500000001455113017276730027646 0ustar eugeneeugenesingle_file=ファイルはファイル種別 %1$sで、EPUBのバージョンは %2$s のシングルファイルとして、検証用プロファイル %3$s を使って検証されます. 適用可能なテストのサブセットのみ実行します. opv_version_test=*** Candidate for msg deletion *** テストはOPF versionに対してのみ実行します. mode_version_not_supported=このチェッカーではファイル種別 %1$s、 version %2$s の検証はできません. no_errors__or_warnings=エラーも警告も検出されませんでした. there_were_errors=\nエラーが検出されました\n there_were_warnings=\n警告が検出されました\n error_processing_unexpanded_epub=\nこのチェックは展開されたepubでは実行できません\n deleting_archive=\nエラーの検出のためEPUBの生成を中止しました.\n display_help=-help ヘルプを表示 argument_needed=少なくとも1つの引数が必要です version_argument_expected=オプション -version で与えられるバージョン番号が省略されています mode_argument_expected=オプション --mode で与えられるファイル種別が省略されています profile_argument_expected=オプション --profile で与えられるプロファイル名が省略されています. profile_unknown=不明なプロファイル '%1$s' が指定されたため, デフォルトの検証用プロファイルを使用します. no_file_specified=オプションでファイルが指定されていません. 終了します. mode_version_ignored=mode と version の引数はepubファイル指定時は無視します. ファイルより取り出します. mode_required=非epubファイルには --mode オプションが必要です. デフォルトの version は 3.0 です. validating_version_message=EPUB version %1$s のルールを使って検証します. output_type_conflict=一度に指定できる出力フォーマットは1つのみです. validating_against_epub_version=EPUBバージョン %1$s のファイルに対して検証します - カスタムバリデーション file_not_found=ファイルが見つかりませんでした: '%1$s' epubcheck_completed=epubcheck 完了 error_creating_config_file=Error creating config file '%1$s'. expected_message_filename=カスタムメッセージファイル名として指定されている引数が '%1$s' となっていました unrecognized_argument=認識できない引数です: '%1$s' help_text = EpubCheck v%1$s\n\n\ このツールを実行するには、最初の引数をチェックしたいファイルの(パスを含んだ)\n\ 名前にして下さい.\n\n\ (特定のEPUB 3 プロファイルや拡張仕様に対してチェックするため)検証用プロファイルを\n\ 指定するには, -profile オプションを使用します:\n\n\ サポートしている検証用プロファイル:\n\ --profile default // デフォルトの検証用プロファイルを使用します\n\ --profile dict // EPUB Dictionaries and Glossaries 仕様に対して検証します\n\ --profile edupub // EDUPUB Profile に対して検証します\n\ --profile idx // EPUB Indexes 仕様に対して検証します\n\ --profile preview // EPUB Previews 仕様に対して検証します\n\n\ 非epubファイルを検証する際は、-v オプションでepubのバージョンを、\n\ -modeオプションでファイル種別を指定します.\n\ デフォルトのバージョン: 3.0.\n\n\ サポートしている mode と version: \n\ --mode opf -v 2.0\n\ --mode opf -v 3.0\n\ --mode xhtml -v 2.0\n\ --mode xhtml -v 3.0\n\ --mode svg -v 2.0\n\ --mode svg -v 3.0\n\ --mode nav -v 3.0 // メディアオーバーレイ検証用\n\ --mode mo -v 3.0 // 展開済みEPUBアーカイブ\n\ --mode exp\n\n\ 以下のオプションも受け付けます:\n\ --save \t = 展開されたepubパスから生成されたepubファイルを保存します\n\ --out = 評価結果のXML文書ファイルを出力します (コンソールへの出力には - を使用)\n\ --xmp = 評価結果のXMP文書ファイルを出力します (コンソールへの出力には - を使用)\n\ --json = 評価結果のXJSON文書ファイルを出力します (コンソールへの出力には - を使用)\n\ -m = --mode と同様\n\ -p = --profile と同様\n\ -o = --out と同様\n\ -x = --xmp と同様\n\ -j = --json と同様\n\ --failonwarnings[+|-] = デフォルトでは、終了ステータスコードとして、エラーが検出されれば1を、検出されなければ\n\ \ 0を返します. --failonwarnings オプションを指定すると、警告かエラーがあれば1を、どちらも\n\ \ ない場合のみ0を返すようになります.\n\ -q, --quiet = エラー以外のメッセージをコンソールに出力しないようにします\n\ -f, --fatal = fatal レベルの深刻度のエラーメッセージのみを出力します\n\ -e, --error = fatal レベルと error レベルの深刻度のエラーメッセージのみを出力します\n\ -w, --warn = fatal、error、warn レベルの深刻度のエラーメッセージを出力します\n\ -u, --usage = epubの利用法情報も出力します\n\ \ (デフォルトは OFF です); 指定した場合、利用法情報は\n\ \ 出力ファイルに常に含まれるようになります\n\n\ -l, --listChecks [] = メッセージIDと深刻度レベルをカスタムメッセージファイル または\n\ \ コンソールに出力します\n\ -c, --customMessages [] = カスタムメッセージファイル でメッセージ深刻度レベルを上書きします\n\n\ -h, -? or --help = ヘルプメッセージを表示します\n\ epubcheck-4.0.2/src/main/assembly/0000755000175000017500000000000013017276730016310 5ustar eugeneeugeneepubcheck-4.0.2/src/main/assembly/src.xml0000644000175000017500000000131713017276730017623 0ustar eugeneeugene src zip ${project.basedir} *.txt pom.xml src/**/* docs/**/* epubcheck-4.0.2/src/main/assembly/dist.xml0000644000175000017500000000440513017276730020000 0ustar eugeneeugene dist zip COPYING.txt src/main/assembly/README-dist.txt README.txt ${project.build.directory}/generated-sources/license/THIRD-PARTY.txt ${project.build.directory}/${artifact.artifactId}.jar licenses src/main/licenses *.txt true false com.adobe:epubcheck ${artifact.artifactId}.${artifact.extension} lib false true epubcheck-4.0.2/src/main/assembly/README-dist.txt0000644000175000017500000000306313017276730020751 0ustar eugeneeugeneThis folder contains the distribution of epubcheck project. EpubCheck is a tool to validate IDPF Epub files. It can detect many types of errors in Epub. OCF container structure, OPF and OPS mark-up, and internal reference consistency are checked. EpubCheck can be run as a standalone command-line tool, installed as a web application or used as a library. EpubCheck project home: https://github.com/idpf/epubcheck RUNNING To run the tool you need Java Runtime (1.6 or above). Any OS should do. Run it from the command line: java -jar epubcheck.jar file.epub All detected errors are simply printed to stderr. USING AS A LIBRARY You can also use EpubCheck as a library in your Java application. EpubCheck public interfaces can be found in com.adobe.epubcheck.api package. EpubCheck class can be used to instantiate a validation engine. Use one of its constructors and then call validate() method. Report is an interface that you can implement to get a list of the errors and warnings reported by the validation engine (instead of the error list being printed out). LICENSING See COPYING.txt and THIRD-PARTY.txt AUTHORS / CONTRIBUTORS Peter Sorotokin Garth Conboy Markus Gylling Piotr Kula Paul Norton Jessica Hekman Liza Daly George Bina Bogdan Iordache Ionut-Maxim Margelatu Romain Deltour Thomas Ledoux Tobias Fischer Steve Antoch Arwen Pond Masayoshi Takahashi Satoshi KOJIMA Most of the EpubCheck functionality comes from the schema validation tool Jing and schemas that were developed by IDPF and DAISY. EpubCheck development was largely done at Adobe Systems. epubcheck-4.0.2/src/main/licenses/0000755000175000017500000000000013017276730016276 5ustar eugeneeugeneepubcheck-4.0.2/src/main/licenses/third-party.properties0000644000175000017500000000152713017276730022670 0ustar eugeneeugene# Generated by org.codehaus.mojo.license.AddThirdPartyMojo #------------------------------------------------------------------------------- # Already used licenses in project : # - Mozilla Public License Version 2.0 # - New BSD License # - The Apache Software License, Version 2.0 # - The W3C Software License #------------------------------------------------------------------------------- # Please fill the missing licenses for dependencies : # # #Sat Aug 29 02:32:05 CEST 2015 com.twelvemonkeys.common--common-image--3.1.2=New BSD License com.twelvemonkeys.common--common-io--3.1.2=New BSD License com.twelvemonkeys.common--common-lang--3.1.2=New BSD License com.twelvemonkeys.imageio--imageio-core--3.1.2=New BSD License com.twelvemonkeys.imageio--imageio-jpeg--3.1.2=New BSD License com.twelvemonkeys.imageio--imageio-metadata--3.1.2=New BSD License epubcheck-4.0.2/src/main/licenses/W3C.txt0000644000175000017500000000464413017276730017443 0ustar eugeneeugeneW3C® SOFTWARE NOTICE AND LICENSE Copyright © 1994-2002 World Wide Web Consortium, (Massachusetts Institute of Technology, Institut National de Recherche en Informatique et en Automatique, Keio University). All Rights Reserved. http://www.w3.org/Consortium/Legal/ This W3C work (including software, documents, or other related items) is being provided by the copyright holders under the following license. By obtaining, using and/or copying this work, you (the licensee) agree that you have read, understood, and will comply with the following terms and conditions: Permission to use, copy, modify, and distribute this software and its documentation, with or without modification, for any purpose and without fee or royalty is hereby granted, provided that you include the following on ALL copies of the software and documentation or portions thereof, including modifications, that you make: The full text of this NOTICE in a location viewable to users of the redistributed or derivative work. Any pre-existing intellectual property disclaimers, notices, or terms and conditions. If none exist, a short notice of the following form (hypertext is preferred, text is permitted) should be used within the body of any redistributed or derivative code: "Copyright © [$date-of-software] World Wide Web Consortium, (Massachusetts Institute of Technology, Institut National de Recherche en Informatique et en Automatique, Keio University). All Rights Reserved. http://www.w3.org/Consortium/Legal/" Notice of any changes or modifications to the W3C files, including the date changes were made. (We recommend you provide URIs to the location from which the code is derived.) THIS SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR DOCUMENTATION. The name and trademarks of copyright holders may NOT be used in advertising or publicity pertaining to the software without specific, written prior permission. Title to copyright in this software and any associated documentation will at all times remain with copyright holders.epubcheck-4.0.2/src/main/licenses/BSD-3-Clause.txt0000644000175000017500000000271413017276730021025 0ustar eugeneeugeneCopyright (c) {{YEAR}}, {{OWNER}} 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. 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 {{the ORGANIZATION 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 HOLDER 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.epubcheck-4.0.2/src/main/licenses/third-party.ftl0000644000175000017500000000221313017276730021252 0ustar eugeneeugene<#-- To render the third-party file. Available context : - dependencyMap a collection of Map.Entry with key are dependencies (as a MavenProject) (from the maven project) values are licenses of each dependency (array of string) - licenseMap a collection of Map.Entry with key are licenses of each dependency (array of string) values are all dependencies using this license --> <#function licenseFormat licenses> <#assign result = " "/> <#list licenses as license> <#assign result = result + license/> <#return result> <#function artifactFormat p> <#return " " + p.name + ", v" + p.version + "\n"+ " by "+ p.organization.name +" (" + (p.url!"no url defined") + ")"> Licenses of third-party dependencies ------------------------------------ <#list dependencyMap as e> <#assign project = e.getKey()/> <#assign licenses = e.getValue()/> ${project.name}, ${project.version} <#-- by ${project.organization.name} (${project.url}) --> <#list licenses as license> ${license} Copies of the licenses are provided in the 'licenses' directory.epubcheck-4.0.2/src/main/licenses/Apache-2.0.txt0000644000175000017500000002607613017276730020530 0ustar eugeneeugene Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.epubcheck-4.0.2/src/main/licenses/MPL-1.0.txt0000644000175000017500000004645213017276730017776 0ustar eugeneeugene MOZILLA PUBLIC LICENSE Version 1.0 ---------------- 1. Definitions. 1.1. ``Contributor'' means each entity that creates or contributes to the creation of Modifications. 1.2. ``Contributor Version'' means the combination of the Original Code, prior Modifications used by a Contributor, and the Modifications made by that particular Contributor. 1.3. ``Covered Code'' means the Original Code or Modifications or the combination of the Original Code and Modifications, in each case including portions thereof. 1.4. ``Electronic Distribution Mechanism'' means a mechanism generally accepted in the software development community for the electronic transfer of data. 1.5. ``Executable'' means Covered Code in any form other than Source Code. 1.6. ``Initial Developer'' means the individual or entity identified as the Initial Developer in the Source Code notice required by Exhibit A. 1.7. ``Larger Work'' means a work which combines Covered Code or portions thereof with code not governed by the terms of this License. 1.8. ``License'' means this document. 1.9. ``Modifications'' means any addition to or deletion from the substance or structure of either the Original Code or any previous Modifications. When Covered Code is released as a series of files, a Modification is: A. Any addition to or deletion from the contents of a file containing Original Code or previous Modifications. B. Any new file that contains any part of the Original Code or previous Modifications. 1.10. ``Original Code'' means Source Code of computer software code which is described in the Source Code notice required by Exhibit A as Original Code, and which, at the time of its release under this License is not already Covered Code governed by this License. 1.11. ``Source Code'' means the preferred form of the Covered Code for making modifications to it, including all modules it contains, plus any associated interface definition files, scripts used to control compilation and installation of an Executable, or a list of source code differential comparisons against either the Original Code or another well known, available Covered Code of the Contributor's choice. The Source Code can be in a compressed or archival form, provided the appropriate decompression or de-archiving software is widely available for no charge. 1.12. ``You'' means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License or a future version of this License issued under Section 6.1. For legal entities, ``You'' includes any entity which controls, is controlled by, or is under common control with You. For purposes of this definition, ``control'' means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of fifty percent (50%) or more of the outstanding shares or beneficial ownership of such entity. 2. Source Code License. 2.1. The Initial Developer Grant. The Initial Developer hereby grants You a world-wide, royalty-free, non-exclusive license, subject to third party intellectual property claims: (a) to use, reproduce, modify, display, perform, sublicense and distribute the Original Code (or portions thereof) with or without Modifications, or as part of a Larger Work; and (b) under patents now or hereafter owned or controlled by Initial Developer, to make, have made, use and sell (``Utilize'') the Original Code (or portions thereof), but solely to the extent that any such patent is reasonably necessary to enable You to Utilize the Original Code (or portions thereof) and not to any greater extent that may be necessary to Utilize further Modifications or combinations. 2.2. Contributor Grant. Each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license, subject to third party intellectual property claims: (a) to use, reproduce, modify, display, perform, sublicense and distribute the Modifications created by such Contributor (or portions thereof) either on an unmodified basis, with other Modifications, as Covered Code or as part of a Larger Work; and (b) under patents now or hereafter owned or controlled by Contributor, to Utilize the Contributor Version (or portions thereof), but solely to the extent that any such patent is reasonably necessary to enable You to Utilize the Contributor Version (or portions thereof), and not to any greater extent that may be necessary to Utilize further Modifications or combinations. 3. Distribution Obligations. 3.1. Application of License. The Modifications which You create or to which You contribute are governed by the terms of this License, including without limitation Section 2.2. The Source Code version of Covered Code may be distributed only under the terms of this License or a future version of this License released under Section 6.1, and You must include a copy of this License with every copy of the Source Code You distribute. You may not offer or impose any terms on any Source Code version that alters or restricts the applicable version of this License or the recipients' rights hereunder. However, You may include an additional document offering the additional rights described in Section 3.5. 3.2. Availability of Source Code. Any Modification which You create or to which You contribute must be made available in Source Code form under the terms of this License either on the same media as an Executable version or via an accepted Electronic Distribution Mechanism to anyone to whom you made an Executable version available; and if made available via Electronic Distribution Mechanism, must remain available for at least twelve (12) months after the date it initially became available, or at least six (6) months after a subsequent version of that particular Modification has been made available to such recipients. You are responsible for ensuring that the Source Code version remains available even if the Electronic Distribution Mechanism is maintained by a third party. 3.3. Description of Modifications. You must cause all Covered Code to which you contribute to contain a file documenting the changes You made to create that Covered Code and the date of any change. You must include a prominent statement that the Modification is derived, directly or indirectly, from Original Code provided by the Initial Developer and including the name of the Initial Developer in (a) the Source Code, and (b) in any notice in an Executable version or related documentation in which You describe the origin or ownership of the Covered Code. 3.4. Intellectual Property Matters (a) Third Party Claims. If You have knowledge that a party claims an intellectual property right in particular functionality or code (or its utilization under this License), you must include a text file with the source code distribution titled ``LEGAL'' which describes the claim and the party making the claim in sufficient detail that a recipient will know whom to contact. If you obtain such knowledge after You make Your Modification available as described in Section 3.2, You shall promptly modify the LEGAL file in all copies You make available thereafter and shall take other steps (such as notifying appropriate mailing lists or newsgroups) reasonably calculated to inform those who received the Covered Code that new knowledge has been obtained. (b) Contributor APIs. If Your Modification is an application programming interface and You own or control patents which are reasonably necessary to implement that API, you must also include this information in the LEGAL file. 3.5. Required Notices. You must duplicate the notice in Exhibit A in each file of the Source Code, and this License in any documentation for the Source Code, where You describe recipients' rights relating to Covered Code. If You created one or more Modification(s), You may add your name as a Contributor to the notice described in Exhibit A. If it is not possible to put such notice in a particular Source Code file due to its structure, then you must include such notice in a location (such as a relevant directory file) where a user would be likely to look for such a notice. You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Code. However, You may do so only on Your own behalf, and not on behalf of the Initial Developer or any Contributor. You must make it absolutely clear than any such warranty, support, indemnity or liability obligation is offered by You alone, and You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of warranty, support, indemnity or liability terms You offer. 3.6. Distribution of Executable Versions. You may distribute Covered Code in Executable form only if the requirements of Section 3.1-3.5 have been met for that Covered Code, and if You include a notice stating that the Source Code version of the Covered Code is available under the terms of this License, including a description of how and where You have fulfilled the obligations of Section 3.2. The notice must be conspicuously included in any notice in an Executable version, related documentation or collateral in which You describe recipients' rights relating to the Covered Code. You may distribute the Executable version of Covered Code under a license of Your choice, which may contain terms different from this License, provided that You are in compliance with the terms of this License and that the license for the Executable version does not attempt to limit or alter the recipient's rights in the Source Code version from the rights set forth in this License. If You distribute the Executable version under a different license You must make it absolutely clear that any terms which differ from this License are offered by You alone, not by the Initial Developer or any Contributor. You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of any such terms You offer. 3.7. Larger Works. You may create a Larger Work by combining Covered Code with other code not governed by the terms of this License and distribute the Larger Work as a single product. In such a case, You must make sure the requirements of this License are fulfilled for the Covered Code. 4. Inability to Comply Due to Statute or Regulation. If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Code due to statute or regulation then You must: (a) comply with the terms of this License to the maximum extent possible; and (b) describe the limitations and the code they affect. Such description must be included in the LEGAL file described in Section 3.4 and must be included with all distributions of the Source Code. Except to the extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it. 5. Application of this License. This License applies to code to which the Initial Developer has attached the notice in Exhibit A, and to related Covered Code. 6. Versions of the License. 6.1. New Versions. Netscape Communications Corporation (``Netscape'') may publish revised and/or new versions of the License from time to time. Each version will be given a distinguishing version number. 6.2. Effect of New Versions. Once Covered Code has been published under a particular version of the License, You may always continue to use it under the terms of that version. You may also choose to use such Covered Code under the terms of any subsequent version of the License published by Netscape. No one other than Netscape has the right to modify the terms applicable to Covered Code created under this License. 6.3. Derivative Works. If you create or use a modified version of this License (which you may only do in order to apply it to code which is not already Covered Code governed by this License), you must (a) rename Your license so that the phrases ``Mozilla'', ``MOZILLAPL'', ``MOZPL'', ``Netscape'', ``NPL'' or any confusingly similar phrase do not appear anywhere in your license and (b) otherwise make it clear that your version of the license contains terms which differ from the Mozilla Public License and Netscape Public License. (Filling in the name of the Initial Developer, Original Code or Contributor in the notice described in Exhibit A shall not of themselves be deemed to be modifications of this License.) 7. DISCLAIMER OF WARRANTY. COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN ``AS IS'' BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. 8. TERMINATION. This License and the rights granted hereunder will terminate automatically if You fail to comply with terms herein and fail to cure such breach within 30 days of becoming aware of the breach. All sublicenses to the Covered Code which are properly granted shall survive any termination of this License. Provisions which, by their nature, must remain in effect beyond the termination of this License shall survive. 9. LIMITATION OF LIABILITY. UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL THE INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO YOU OR ANY OTHER PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THAT EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. 10. U.S. GOVERNMENT END USERS. The Covered Code is a ``commercial item,'' as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of ``commercial computer software'' and ``commercial computer software documentation,'' as such terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all U.S. Government End Users acquire Covered Code with only those rights set forth herein. 11. MISCELLANEOUS. This License represents the complete agreement concerning subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. This License shall be governed by California law provisions (except to the extent applicable law, if any, provides otherwise), excluding its conflict-of-law provisions. With respect to disputes in which at least one party is a citizen of, or an entity chartered or registered to do business in, the United States of America: (a) unless otherwise agreed in writing, all disputes relating to this License (excepting any dispute relating to intellectual property rights) shall be subject to final and binding arbitration, with the losing party paying all costs of arbitration; (b) any arbitration relating to this Agreement shall be held in Santa Clara County, California, under the auspices of JAMS/EndDispute; and (c) any litigation relating to this Agreement shall be subject to the jurisdiction of the Federal Courts of the Northern District of California, with venue lying in Santa Clara County, California, with the losing party responsible for costs, including without limitation, court costs and reasonable attorneys fees and expenses. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not apply to this License. 12. RESPONSIBILITY FOR CLAIMS. Except in cases where another Contributor has failed to comply with Section 3.4, You are responsible for damages arising, directly or indirectly, out of Your utilization of rights under this License, based on the number of copies of Covered Code you made available, the revenues you received from utilizing such rights, and other relevant factors. You agree to work with affected parties to distribute responsibility on an equitable basis. EXHIBIT A. ``The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. The Original Code is ______________________________________. The Initial Developer of the Original Code is ________________________. Portions created by ______________________ are Copyright (C) ______ _______________________. All Rights Reserved. Contributor(s): ______________________________________.''epubcheck-4.0.2/src/build/0000755000175000017500000000000013017276730014644 5ustar eugeneeugeneepubcheck-4.0.2/src/build/transifex-pull.sh0000755000175000017500000000511113017276730020156 0ustar eugeneeugene#!/bin/bash # bash script to update and normalize # pulled transifex properties files # # Author: Tobias Fischer (https://github.com/tofi86) # Project: IDPF/EpubCheck (https://github.com/IDPF/epubcheck) # # Date: 2015-10-09 # License: MIT License # param1=$1 function escapeISO88591() { file=$1 echo "- Escaping ISO-8859-1 encodings with Unicode escapes" native2ascii -encoding ISO-8859-1 ${file} ${file} } function removeJavaEscapes() { file=$1 # replace \\ -> \, \` -> `, \= -> =, \: -> :, \! -> ! sed -E -i -- 's/\\([\\`=:!])/\1/g' ${file} # make unicode escapes \u00fc uppercase \u00FC perl -i -pe 's/\\u([0-9a-f]{4})/\\u\U\1/g' ${file} # replace newlines in help_text sed -E -i -- '/^help_text/s/((\\n)+)/\1\\\'$'\n /g' ${file} sed -E -i -- 's/^( )([[:space:]]+)/\1\\\2/g' ${file} # remove temp file rm ${file}-- 2> /dev/null } function processFile() { file=$1 echo "" echo "Processing file '${file}'" file ${file} | grep 'ISO-8859' > /dev/null if [ $? -eq 0 ]; then escapeISO88591 ${file} fi removeJavaEscapes ${file} } # Check if this is running from repo root dir near the .tx/ folder if [ ! -d .tx/ ] ; then echo "FATAL: You need to run this script from the repository's root directory!" echo "e.g. ./src/build/transifex-pull.sh --all" exit 1 fi # Check for Transifex Commandline Client if [ `which tx >/dev/null ; echo $?` -eq 1 ] ; then echo "FATAL: You need to install the Transifex Commandline Client first in order to run this script!" echo "Instructions: http://docs.transifex.com/client/setup/" exit 1 fi # Show help if no language parameter is passed to the script or --help if [[ -z ${param1} || ${param1} == "--help" ]] ; then echo "usage: transifex-pull.sh [--all | <2-digit-country-code>]" echo "examples:" echo " transifex-pull.sh --all" echo " transifex-pull.sh de" # Pull ALL translations elif [ ${param1} == "--all" ] ; then minimum_percent_translated=$(awk -F "=" '/minimum_perc/ {print $2}' .tx/config) echo "Pulling ALL epubcheck translations (>${minimum_percent_translated}% done) from Transifex..." echo "" tx pull -f | tee /dev/stderr | grep "> [a-z][a-z]: " | awk '{print $3}' | while read f; do processFile ${f}; done # Pull translations for a 2-digit-language-code elif [ ${#param1} -eq 2 ] ; then echo "Pulling epubcheck translation '${param1}' from Transifex..." echo "" tx pull -f -l ${param1} | tee /dev/stderr | grep "${param1}: " | awk '{print $3}' | while read f; do processFile ${f}; done else echo "FATAL: Couldn't recognize language code '${param1}'. Exit." exit 1 fi epubcheck-4.0.2/src/tools/0000755000175000017500000000000013017276730014705 5ustar eugeneeugeneepubcheck-4.0.2/src/tools/CompareVersions.py0000644000175000017500000001733713017276730020411 0ustar eugeneeugene#!c:\python27\python import os import sys import datetime import time import webbrowser import urllib import optparse import subprocess import zipfile import tempfile import shutil import glob def parse_args(argv): prog_dir = os.path.dirname(argv[0]) usage = """ Usage: %s [OPTION] Collect ePubStats on the ePub files in the target directory """[1:-1] % os.path.basename(argv[0]) parser = optparse.OptionParser(usage=usage) parser.add_option("-n", "--newerDir", dest="newerDir", type="str", help="Directory holding the latest versions of the ePub versions to compare") parser.add_option("-o", "--olderDir", dest="olderDir", type="str", help="Directory holding the older version of the ePubs being compared") parser.add_option("-p", "--preserveDiffs", action="store_true", dest="saveDiffs", default=False, help=r"Use this flag to save the differences file in the --diffLogDir directory") parser.add_option("--diffLogDir", dest="diffsDir", type="str", default=r"diffLogs", help=r"If --preserveDiffs is specified, the diffs are stored in the directory 'diffLogs' unless overriden by the value of this option.") parser.add_option("--logdir", dest="logdir", type="str", default=r"$EPUBCHECK-LOGS", help=r"Log file location used by this tool, default=%EPUBCHECK-LOGS%\CompareLog.TabDelimitedFile; if EPUBCHECK-LOGS is not defined, the file will be written to the current working directory") parser.add_option("--logfile", dest="logfile", type="str", default=r"CompareEpubsLog.TabDelimitedFile", help=r"Log file name used by this tool, default=CompareEpubsLog.TabDelimitedFile") opts,args = parser.parse_args(argv[1:]) return opts,args def logStats(log_file, elapsedTime, newerFile, olderFile, zipsDiffer, nDiffs): now = datetime.datetime.now() dateTime = str(now.date()) + "\t" + str(now.time()) if not os.path.exists(log_file): print "File " + log_file + " doesn't exist, inititalizing file..." f = open(log_file, 'a') f.write("logDate\t") f.write("logTime\t") f.write("elapsedTime\t") f.write("newerFile\t") f.write("olderFile\t") f.write("zipsDiffer\t") f.write("nDiffs\n") else: f = open(log_file, 'a') f.write(str(now.date()) + "\t" + str(now.time()) + "\t") f.write(elapsedTime + "\t") f.write(newerFile.rstrip("\r") + "\t") f.write(olderFile.rstrip("\r") + "\t") f.write(zipsDiffer + "\t") f.write(nDiffs + "\n") f.close() return "ePubStats Logging complete..." global gopts gopts,args = parse_args(sys.argv) # # verify that the log dir and file are writable # if not os.path.isdir(os.path.expandvars(gopts.logdir)): print ('Activity logging environment variable "' + gopts.logdir + '" is not a valid dir, logging to the current working directory') statsLog = os.path.join(".", gopts.logfile) else: statsLog = os.path.join(os.path.expandvars(gopts.logdir), gopts.logfile) print ("Activity logging is being performed to " + statsLog) olderDir = gopts.olderDir newerDir = gopts.newerDir print("B&N CompareEpubVersions Tool") print(" Compare two directory trees holding differing versions of the same ePubs") print("--\n") print('Comparing the newer ePub versions in "' + newerDir + '" to older versions in "' + olderDir +'"') print("--\n") newerFiles = os.listdir(newerDir) olderFiles = os.listdir(olderDir) newCount = len(newerFiles) if newCount != len(olderFiles): print(' Warning: The number of files in "' + newerDir + '" (' + str(len(newerFiles)) + ') does not match the number in "' + olderDir + '" (' + str(len(olderFiles)) + ')') diffCmd = "diff -q -w -r " nCompared = 0 nChecked = 0 for file in newerFiles: startTime = time.time() nChecked += 1 if os.path.splitext(file)[-1].lower() != ".epub": print (" File #" + str(nChecked) + " (of " + str(newCount) + ") " + str(nChecked) + ": " + file + " is not an ePub, skipped...\n--\n") continue nCompared += 1 ean = file[0:13] olderTarget = glob.glob(os.path.join(olderDir, ean + "*.epub")) if len(olderTarget) == 0: print(" Error: no older version of " + os.path.join(newerDir, file) + " was found in " + olderDir) logStats(statsLog, "NA", os.path.join(newerDir, file), olderDir, str(False), "Older File Not Found") nCompared -= 1 continue if len(olderTarget) > 1: print(" Warning: " + str(len(olderTarget)) + " ePubs found matching the target ean: " + ean) # print("File: " + file + " ean: " + ean + " olderTarget: " + str(olderTarget)) newTmpBookDir = tempfile.mkdtemp(prefix="CePubV-Newer") oldTmpBookDir = tempfile.mkdtemp(prefix="CePubV-Older") newZipFile = os.path.join(newerDir, file) oldZipFile = olderTarget[0] tmpOutputFile = os.path.join(newerDir, ean + ".compare.log") tmpOutput = open(tmpOutputFile, mode="w") cmdStr = diffCmd + '"' + newZipFile + '" "' + oldZipFile + '"' print(" Comparing the zips themselves: " + cmdStr) subprocess.call(cmdStr, stdout=tmpOutput, stderr=tmpOutput, shell=True) tmpOutput.close() tmpOutput = open(tmpOutputFile, mode="r") theDiffs = tmpOutput.readlines() tmpOutput.close() if len(theDiffs) == 0: zipsDiffer = False nDiffs = 0 print(" File #" + str(nChecked) + " (of " + str(newCount) + ") (" + str(nCompared) + " compared) - " + file + ": both ePub container files are identical") else: zipsDiffer = True print(" File #" + str(nChecked) + " (of " + str(newCount) + ") (" + str(nCompared) + " compared) - " + file + ": ePub container files differ") for line in theDiffs: print(" Zip Diff: " + line.rstrip()) # # if they are different, lets see how different # if zipsDiffer: newZip = zipfile.ZipFile(newZipFile, 'r') oldZip = zipfile.ZipFile(oldZipFile, 'r') newZip.extractall(newTmpBookDir) oldZip.extractall(oldTmpBookDir) #print(" New zip: " + file + " extracted to: " + str(newTmpBookDir)) #print(" Old zip: " + olderTarget[0] + " extracted to: " + str(oldTmpBookDir)) tmpOutputFile = os.path.join(newerDir, ean + ".compare.log") tmpOutput = open(tmpOutputFile, mode="w") cmdStr = diffCmd + '"' + newTmpBookDir + '" "' + oldTmpBookDir + '"' subprocess.call(cmdStr, stdout=tmpOutput, stderr=tmpOutput, shell=True) tmpOutput.close() tmpOutput = open(tmpOutputFile, mode="r") theDiffs = tmpOutput.readlines() tmpOutput.close() nDiffs = len(theDiffs) if nDiffs > 0: print(" File #" + str(nChecked) + " (of " + str(newCount) + ") (" + str(nCompared) + " compared) - " + file + " have " + str(len(theDiffs)) + " differences:") for line in theDiffs: print(" Asset Diff: " + line.rstrip()) else: print(" File #" + str(nChecked) + " (of " + str(newCount) + ") (" + str(nCompared) + " compared) - " + file + ": ePub contents in differing containers are identical") shutil.rmtree(newTmpBookDir) shutil.rmtree(oldTmpBookDir) print("--") print("") if gopts.saveDiffs: diffsDir = os.path.join(newerDir, gopts.diffsDir) if not os.path.exists(diffsDir): print ("Dir: " + diffsDir + " does not exist; creating it...") os.mkdir(diffsDir) shutil.move(tmpOutputFile, diffsDir) else: os.remove(tmpOutputFile) elapsedTime = str(time.time() - startTime) logStats(statsLog, elapsedTime, os.path.join(newerDir, file), olderTarget[0], str(zipsDiffer), str(nDiffs))epubcheck-4.0.2/src/tools/BookReporter.py0000644000175000017500000012525713017276730017710 0ustar eugeneeugene#!c:\python27\python import os import sys import datetime import time import webbrowser import urllib import optparse import subprocess import zipfile import shutil import json import Dictionary import CompareResults defaultJarName = os.path.join(os.path.dirname(os.path.realpath(__file__)), r"epubcheck.jar") def parse_args(argv): prog_dir = os.path.dirname(argv[0]) usage = """ Usage: %s [OPTION] BookReporter: ePubCheck all ePub files in the target directory, potentially preserving generated .JSON output files, compare results to prior checks if old results are found. Optional (use --ppDiffs) pretty-prints any jsondiffs.json files found in the json directory. """[1:-1] % os.path.basename(argv[0]) parser = optparse.OptionParser(usage=usage) parser.add_option("-d", "--directory", dest="target", type="str", default=".", help="Directory on which ePubCheck will be run, default is the current working directory") parser.add_option("-f", "--file", dest="targetFile", type="str", default="", help=r'''File or comma separated list of files to run the check on; if -f is omitted, all files in the target directory will be checked. If you include a fully qualified path to a file, you can add additional comma separated file names in the same directory named on the first file (-f /path/a.epub,b.epub). ''') parser.add_option("--NoSaveJson", action="store_false", dest="saveJson", default=True, help=r"Do NOT save ePubcheck .json output files") parser.add_option("--NoCompareJson", action="store_false", dest="compareJson", default=True, help=r"Do NOT compare the json created during this check with the most recently saved .json result, if found.") parser.add_option("--EanOnlyJsonNames", action="store_true", dest="jsonNamedByEAN", default=False, help=r"Use this flag to force .json file names to use EAN-only naming convention, .ePubCheck.json, not .ePubCheck.json names. Files not conforming to EAN-first naming pattern will use the convention") parser.add_option("-j", "--jsonDir", dest="jsonDir", type="str", default=r"", help=r"if the -s switch is used, ePubCheck .json output files will be preserved in either the location specified by the -e switch, or if -e is omitted, stored in \NOOKePubCheckJson") parser.add_option("--ppJson", dest="ppJson", action="store_true", default=False, help=r"Skip checks and 'pretty print' any json files in the target directory's json output directory.") parser.add_option("--ppDiffs", dest="ppDiffs", action="store_true", default=False, help=r"Skip checks and simply 'pretty-print' any jsondiffs.json files found in the target directory's json output directory.") parser.add_option("-v", "--verbose", dest="verbose", action="store_true", default=False, help=r"Show all messages grouped by type") parser.add_option("-q", "--Hide_errors", dest="showErrors", action="store_false", default=True, help=r"'Quiet' output mode; don't list FATAL and ERROR messages; by default these errors are always displayed on the console") parser.add_option("-w", "--warning", dest="showWarning", action="store_true", default=False, help=r"Show WARNING messages; by default, these messages are not shown on the console") parser.add_option("-u", "--usage", dest="showUsage", action="store_true", default=False, help=r"Show USAGE messages, by default, these messages are not shown on the console") parser.add_option("-l", "--logging", dest="loggingFlag", default=False, action="store_true", help=r"Enable logging to a tab-delimited file") parser.add_option("--logdir", dest="logdir", type="str", default=r"$EPUBCHECK-LOGS", help=r'''Log file location used by this tool, defaults to the value of the environment variable "EPUBCHECK-LOGS"; if EPUBCHECK-LOGS is defined and a valid directory, logging is enabled to that directory automatically (-l is not required if EPUBCHECK-LOGS is defined) if EPUBCHECK-LOGS is undefined and logging is enabled, logs are written in the current working directory. if EPUBCHECK-LOGS is defined, automatic logging can be disabled by using the "--logdir none" switch. ''') parser.add_option("--logfile", dest="logfile", type="str", default=r"NookReporter.TabDelimitedFile", help=r"Log file name used by this tool, default=BookReporter.TabDelimitedFile") parser.add_option("--customCheckMessages", dest="overrideFile", type="str", default="$ePubCheckCustomMessageFile", help=r'''Name of a custom ePubCheck message file for use in these checks. If not specified, the value of the environment variable $ePubCheckCustomMessages file will be used, if defined. To override the value of that environment variable, \use "--customCheckMessages= 0: print (" --") def listServerFiles(theDir): theFiles = [] os.chdir(theDir) files = os.listdir(".") for file in files: theFiles.append(string.strip(file)) return(theFiles) def logStats(log_file, checkerVersion, book_dir, book_file, book_path, elapsedTime, checkTime, ePubVersion, comparedTo, checkChanged, pubChanged, spineChanged, manifestChanged, messagesChanged, numFatal, numError, isScripted, hasFixedFormat): now = datetime.datetime.now() dateTime = str(now.date()) + "\t" + str(now.time()) if not os.path.exists(log_file): print ("File " + log_file + " doesn't exist, inititalizing file...") f = open(log_file, 'a') f.write("logDate\t") f.write("logTime\t") f.write("logTool\t") f.write("checkerVersion\t") f.write("PubDir\t") f.write("ePubFile\t") f.write("ePubPath\t") f.write("elpasedTime\t") f.write("checkTime\t") f.write("ePubVersion\t") f.write("comparedTo\t") f.write("checkChanged\t") f.write("pubChanged\t") f.write("spineChanged\t") f.write("manifestChanged\t") f.write("messagesChanged\t") f.write("numFatal\t") f.write("numErrors\t") f.write("isScripted\t") f.write("hasFixedFormat\n") else: f = open(log_file, 'a') f.write(str(now.date()) + "\t" + str(now.time()) + "\t") f.write("BookReporter.py" + "\t") f.write(checkerVersion + "\t") f.write(book_dir + "\t") f.write(book_file.rstrip("\r") + "\t") f.write(book_path + "\t") f.write(elapsedTime + "\t") f.write(checkTime + "\t") f.write(ePubVersion + "\t") f.write(comparedTo + "\t") f.write(checkChanged + "\t") f.write(pubChanged + "\t") f.write(spineChanged + "\t") f.write(manifestChanged + "\t") f.write(messagesChanged + "\t") f.write(numFatal + "\t") f.write(numError + "\t") f.write(isScripted + "\t") f.write(hasFixedFormat + "\n") f.close() return "BookReporter Logging complete..." def ppEpubCheckChanges(jsonDelta): # # print the check metadata plus the publication and manifest item metadata changes # oldCheck = jsonDelta["summary"]["oldCheck"] newCheck = jsonDelta["summary"]["newCheck"] print(" ePubCheck results comparison") print(" --\n\r") print(" New file: " + newCheck["path"] + " checked on: " + newCheck["checkDate"]) # # json schema change: moved file name from publication to checker; if the name isn't found, use one in publication; this hack can be removed soon. # try: print(" Old file: " + oldCheck["path"] + " checked on: " + oldCheck["checkDate"]) except: print(" Old file: path not found due to json output schema change; the old file was checked on: " + oldCheck["checkDate"]) print(" --\n\r") print(" Summary: publication metadata changes: " + str(jsonDelta["summary"]["publicationChanges"])) print(" spine item changes: " + str(jsonDelta["summary"]["spineChanges"])) print(" manifest item changes: " + str(jsonDelta["summary"]["itemChanges"])) print(" --\n\r") if jsonDelta["summary"]["publicationChanges"] > 0: print(" Publication property changes:") pubChanges = jsonDelta["publication"] if len(pubChanges["adds"]) > 0: print(" New properties added: ") for item in pubChanges["adds"]: print(" '" + item + "' (value: " + str(pubChanges["adds"][item]) + ")") if len(pubChanges["cuts"]) > 0: print(" Properties removed: ") for item in pubChanges["cuts"]: print(" '" + item + "' (value was: " + str(pubChanges["cuts"][item]) + ")") if len(pubChanges["changes"]) > 0: print(" Properties changed: ") for item in pubChanges["changes"]: if item == "embeddedFonts": print(" " + item + " changed -- new embedded font list:") for fontString in pubChanges["changes"][item]["newValue"]: print(" " + str(fontString)) print(" " + item + " changed -- old embedded font list:") for fontString in pubChanges["changes"][item]["oldValue"]: print(" " + str(fontString)) else: try: print(" '" + item + "'changed -- new value: '" + str(pubChanges["changes"][item]["newValue"]) + "'; old value: '" + str(pubChanges["changes"][item]["oldValue"]) + "'") except: print(" '" + item + "'changed -- exception occurred trying to render old or new property value") else: print(" Publication property changes: NONE") print(" --\r\n") if jsonDelta["summary"]["spineChanges"] > 0: print(" Spine changes:") spineChanges = jsonDelta["spine"] print(" Unchanged spine items: " + str(spineChanges["unchanged"])) if len(spineChanges["adds"]) > 0: print(" New spine items added: ") for item in spineChanges["adds"]: print(" '" + item + "' order: " + str(spineChanges["adds"][item])) if len(spineChanges["cuts"]) > 0: print(" Spine items removed: ") for item in spineChanges["cuts"]: print(" '" + item + "' order was: " + str(spineChanges["cuts"][item])) if len(spineChanges["orderChanges"]) > 0: print(" Spine items reordered: ") for item in spineChanges["orderChanges"]: print(" '" + item + "' spine order changed -- new order: '" + str(spineChanges["orderChanges"][item]["newSpineIndex"]) + "'; old order: '" + str(spineChanges["orderChanges"][item]["oldSpineIndex"]) + "'") if len(spineChanges["contentChanges"]) > 0: print(" Spine item content changes: ") for item in spineChanges["contentChanges"]: print(" spine ID: '" + item + "' file: '" + str(spineChanges["contentChanges"][item]) + "'") else: print(" Publication spine changes: NONE") print(" --\r\n") if jsonDelta["summary"]["itemChanges"] > 0: print(" Publication manifest item changes:") maniChanges = jsonDelta["manifest"] if len(maniChanges["adds"]) > 0: print(" Manifest items added: ") for item in maniChanges["adds"]: print(" '" + item + "'") if gopts.verbose: for property in maniChanges["adds"][item]: if property == "referencedItems": print(" referenced items: ") for references in maniChanges["adds"][item][property]: print(" " + references) else: try: print(" property: " + property + " -- value: " + str(maniChanges["adds"][item][property])) except: print(" property: " + property + " -- value caused exception during output") if len(maniChanges["cuts"]) > 0: print("\r\n Manifest items removed: ") for item in maniChanges["cuts"]: print(" '" + item + "'") if gopts.verbose: for property in maniChanges["cuts"][item]: if property == "referencedItems": print(" referenced items: ") for references in maniChanges["cuts"][item][property]: print(" " + references) else: try: print(" property: " + property + " -- value: " + str(maniChanges["cuts"][item][property])) except: print(" property: " + property + " -- value caused exception during output") if len(maniChanges["changes"]) > 0: theChanges = maniChanges["changes"] print("\r\n Manifest item property changes: ") for itemId in theChanges: if "adds" in theChanges[itemId]: for theAdd in theChanges[itemId]["adds"]: print(" Manifest item ID: '" + itemId + "' -- property '" + theAdd + "' was added to the manifest item (value: " + str(theChanges[itemId]["adds"][theAdd]) + ")") if "cuts" in theChanges[itemId]: for theCut in theChanges[itemId]["cuts"]: print(" Manifest item ID: '" + itemId + "' -- property '" + theCut + "' was removed from the manifest item (value: " + str(theChanges[itemId]["cuts"][theCut]) +")") if "changes" in theChanges[itemId]: for property in theChanges[itemId]["changes"]: if property == "referencedItems": if "adds" in theChanges[itemId]["changes"][property]: for theAdd in theChanges[itemId]["changes"][property]["adds"]: try: print(" Manifest item ID: '" + itemId + "' -- added reference to: '" + theAdd +"'") except: print(" Manifest item ID: '" + itemId + "' -- added reference to: exception thrown during output of the added reference") if "cuts" in theChanges[itemId]["changes"][property]: for theCut in theChanges[itemId]["changes"][property]["cuts"]: try: print(" Manifest item ID: '" + itemId + "' -- removed reference to: '" + theCut +"'") except: print(" Manifest item ID: '" + itemId + "' -- added reference to: exception thrown during output of the cut reference") elif property == "checkSum": try: print(" Manifest item ID: '" + itemId + "' -- the associated file '" + str(theChanges[itemId]["changes"][property]["newValue"]) +"' contents changed") except: print(" Manifest item ID: '" + itemId + "' -- the associated file (named caused exception on output) contents changed") else: try: print(" Manifest item ID: '" + itemId + "' -- property '" + property + "' changed -- newValue: " + str(theChanges[itemId]["changes"][property]["newValue"]) + "; oldValue: " + str(theChanges[itemId]["changes"][property]["oldValue"])) except: print(" Manifest item ID: '" + itemId + "' -- property '" + property + "' changed -- old or new property value caused exception during output") else: print(" Publication manifest changes: NONE") print(" --\r\n") def compareMessages(newMessages, oldMessages): if newMessages == oldMessages: print (" Message collections are identical you idiot") messDelta = "Mess=!" else: print (" Message collections comparisons:") messDelta = "Mess-" lenNew = len(newMessages) lenOld = len(oldMessages) oldItems = set() oldDict = {} newItems = set() newDict = {} blankIDinNew = 0 blankIDinOld = 0 for item in newMessages: key = item["ID"] if key == "": blankIDinNew += 1 key = "BlankID_" + str(blankIDinNew) if not key in newItems: newItems.add(key) newDict[key] = item ''' else: print (" Message collections comparison: ID Collision in NEW Messages: " + key) ''' for item in oldMessages: key = item["ID"] if key == "": blankIDinOld += 1 key = "BlankID_" + str(blankIDinOld) if not key in oldItems: oldItems.add(key) oldDict[key] = item ''' else: print (" Message collections comparison: ID Collision in OLD Messages: " + key) ''' delta = Dictionary.DictCompare(newDict, oldDict) adds = delta.added() cuts = delta.removed() changes = delta.changed() if len(adds) != 0: messDelta += "A" + str(len(adds)) + "-" for id in adds: print (" Message ID: " + id + " added") else: messDelta += "xA-" print (" No Message items added") if len(cuts) != 0: messDelta += "R" + str(len(cuts)) + "-" for id in cuts: print (" Message ID: " + id + " removed") else: messDelta += "xR-" print (" No Message items removed") if len(changes) != 0: messDelta += "C" + str(len(changes)) for id in changes: newRecord = newDict[id] oldRecord = oldDict[id] recDelta = Dictionary.DictCompare(newRecord, oldRecord) for name in recDelta.added(): print (' Message ID: "' + id + '" -- property value "' + name + '" added; value: "' + str(newRecord[name]) + '"') for name in recDelta.removed(): print (' Message ID: "' + id + '" -- property value "' + name + '" removed; old value was: "' + str(oldRecord[name]) + '"') for name in recDelta.changed(): if name == "locations": print (' Message ID: "' + id + '" -- property value "' + name + '" changed; new occurrence count: ' + str(len(newRecord[name])) + '; old occurrence count: ' + str(len(oldRecord[name]))) newLocs = set() oldLocs = set() oldLocsDict = {} newLocsDict = {} for locs in newRecord[name]: if not locs["fileName"]: locs["fileName"]= id + "HasNullFileNameLoc" locID = locs["fileName"] + "-" + str(locs["line"]) + "-" + str(locs["column"]) if not locID in newLocs: newLocs.add(locID) newLocsDict[locID] = locs else: print (" Messages: duplicate location in NEW message collection for message ID: " + id + " Location: " + locs["fileName"] + "@ " + str(locs["line"]) + ":" + str(locs["column"])) for locs in oldRecord[name]: if not locs["fileName"]: locs["fileName"]= id + "HasNullFileNameLoc" locID = locs["fileName"] + "-" + str(locs["line"]) + "-" + str(locs["column"]) if not locID in oldLocs: oldLocs.add(locID) oldLocsDict[locID] = locs else: print (" Messages: duplicate location in OLD message collection for message ID: " + id + " Location: " + locs["fileName"] + " @ " + str(locs["line"]) + ":" + str(locs["column"])) locsDelta = Dictionary.DictCompare(newLocsDict, oldLocsDict) for locs in locsDelta.added(): try: print (' Message ID: "' + id + '" -- location added; value: "' + newLocsDict[locs]['fileName'] + ' @ ' + str(newLocsDict[locs]['line']) + ':' + str(newLocsDict[locs]['column']) + '"') except: print (' Message ID: "' + id + '" -- location added; value: caused exception on output') for locs in locsDelta.removed(): try: print (' Message ID: "' + id + '" -- location removed; value: ' + oldLocsDict[locs]['fileName'] + ' @ ' + str(oldLocsDict[locs]['line']) + ':' + str(oldLocsDict[locs]['column']) +'"') except: print (' Message ID: "' + id + '" -- location removed; value: caused exception on output') ''' for locs in locsDelta.changed(): print (' Manifest ID: "' + id + '" -- property value "' + name + '" changed; new value: "' + str(newRecord[name]) + '"; old value: "' + str(oldRecord[name]) + '"') ''' else: print (' Message ID: "' + id + '" -- property value "' + name + '" changed; new value: "' + str(newRecord[name]) + '"; old value: "' + str(oldRecord[name]) + '"') else: messDelta += "xC" print (" No Message item properties were changed") if blankIDinNew != 0: print (" " + str(blankIDinNew) + " blank Message item IDs in new Messages found") if blankIDinOld != 0: print (" " + str(blankIDinOld) + " blank Message item IDs in old Messages found") print (" --") return(messDelta) print ("BookReporter Tool: Check ePubs and optionally compare check results to a previous check") global gopts gopts,args = parse_args(sys.argv) # print (str(gopts.target)) # # set up logging of checking activity # logging = gopts.loggingFlag if (logging or os.path.isdir(os.path.expandvars(gopts.logdir)) != "") and os.path.expandvars(gopts.logdir) != "none": logging = True # # verify that the log dir and file are writable # if not os.path.isdir(os.path.expandvars(gopts.logdir)): print ('Activity logging directory "' + os.path.expandvars(gopts.logdir) + '" is not a valid dir, logging to the current working directory') statsLog = os.path.join(".", gopts.logfile) else: statsLog = os.path.join(os.path.expandvars(gopts.logdir), gopts.logfile) print ("Activity logging is being performed to " + statsLog) # # find the epubcheck jar, or give up... # if os.path.exists(gopts.appJar): ePubCheckCmd = "java -jar " + gopts.appJar else: print ("'" + gopts.appJar + "' was not found; BookReporter.py is aborting...") exit(1) #print ("BookReporter is using the java command: " + ePubCheckCmd) # # decide if this is python 2.7 or 3.3 and whether to use the timeout= flag on subprocess.call # useTimeout = False pyVersionString = sys.version pyVersion = float(pyVersionString.split(' ')[0].split(".")[0] + "." + pyVersionString.split(' ')[0].split(".")[1]) if pyVersion >= 3.3: useTimeout = True print("BookReporter is running on Python version: " + str(pyVersion) + " and is using a check time limit of: " + str(gopts.timeoutVal) + "s") else: print("BookReporter is running on Python version: " + str(pyVersion) + "; no check time limit is being enforced. Some books can take > 5 minutes to check...") # # ensure that targetDir is actually a directory... # targetDir = gopts.target if not os.path.isdir(targetDir): print ("-d " + targetDir + " is not a directory, aborting...") sys.exit(1) ppDiffs = gopts.ppDiffs ppJson = gopts.ppJson # # listing will contain the list of files to check, either ePubs in targetDir or .jsondiffs.json or epubcheck.json files in the json output directory of either --ppDiffs or --ppJson are used # if gopts.overrideFile == "" or gopts.overrideFile == "none": print("BookReporter is using NO ePubCheck custom message file... even if one is specified by the environment variable $ePubCheckCustomMessageFile") overrideCmdStr = "" else: overrideFile = os.path.expandvars(gopts.overrideFile) if overrideFile != "" and os.path.exists(overrideFile): print("BookReporter is using the ePubCheck custom message file: " + overrideFile) overrideCmdStr = ' -c "' + overrideFile + '" ' print("BookReporter override command string= '" + overrideCmdStr +"'") else: print("BookReporter could not file the --customMessageFile file: " + overrideFile + "; check continuing without an override file...") overrideCmdStr = "" # # set up the errorLogDirectory name, if necessary; but don't create it until it's needed # if gopts.jsonDir == "": errorsDir = os.path.join(targetDir, "ePubCheckJson") else: errorsDir = gopts.jsonDir if not ppDiffs and not ppJson: targetFileType = ".epub" if gopts.targetFile == "": listing = os.listdir(targetDir) else: # # handle the case where # target file is not specified # where it contains a list of comma separated file names # and where it contains a fq pathname # filePath, fileName = os.path.split(gopts.targetFile) if filePath != "": targetDir = filePath listing = fileName.split(",") else: targetDir = errorsDir if ppJson: targetFileType = ".epubcheck.json" if ppDiffs: targetFileType = ".jsondiffs.json" if gopts.targetFile == "": listing = os.listdir(targetDir) else: filePath, fileName = os.path.split(gopts.targetFile) if filePath != "": targetDir = filePath listing = fileName.split(",") nClean=0 nErrs=0 nChecked = 0 nTotalFiles = len(listing) print ("--\r\n") print ("Target Dir= " + targetDir + " (contains "+ str(nTotalFiles) + " files; looking for files of type '" + targetFileType + "' to examine)") saveJson = gopts.saveJson if saveJson: if not os.path.exists(errorsDir): print ("Dir: " + errorsDir + " does not exist; creating it...") os.mkdir(errorsDir) else: print (".json output files are NOT being saved") print ("--") print ("") for file in listing: if ppJson or ppDiffs: if targetFileType in file.lower(): if ppJson and file.lower().find(targetFileType) == len(file)-len(targetFileType): print(" Pretty print: " + file) jsonFile = os.path.join(targetDir, file) jsonData = open(jsonFile, "r").read() checkResults = json.loads(jsonData) print(" Messages Summary:") logMessages(checkResults["messages"], "FATAL") logMessages(checkResults["messages"], "ERROR") if gopts.verbose or gopts.showWarning: logMessages(checkResults["messages"], "WARNING") if gopts.verbose or gopts.showUsage: logMessages(checkResults["messages"], "USAGE") print ("--") print ("") else: print ("File #" + str(nChecked) + ": " + file + " is not of type '" + targetFileType + "'; skipped...") continue if ppDiffs: print(" Prettyprint: " + file) jsonFile = os.path.join(targetDir, file) jsonData = open(jsonFile, "r").read() jsonDiffs = json.loads(jsonData) ppEpubCheckChanges(jsonDiffs) else: print ("File #" + str(nChecked) + ": " + file + " is not of type '" + targetFileType + "'; skipped...") continue continue startTime = time.time() nChecked += 1 expString = "" if os.path.splitext(file)[-1].lower() != ".epub": if os.path.isdir(os.path.join(targetDir, file)) and os.path.exists(os.path.join(targetDir, file, "mimetype")): print ("File #" + str(nChecked) + ": " + file + " is a directory and mimetype file found; treating it as an expanded ePub...") expString = " --mode exp" if(os.path.exists(os.path.join(targetDir, file + ".epub"))): expString += " --save" print(" ePub: '" + os.path.join(targetDir, file + ".epub") + "' exists; it will be overwritten, or if severe errors exist when checking the expanded ePub directory '" + file + "' it will be deleted.") else: print ("File #" + str(nChecked) + ": " + file + " is not an ePub, skipped...") continue # # Process an ePub # ePub = os.path.join(targetDir, file) print ("File #" + str(nChecked) + " (of " + str(nTotalFiles) + ") : " + ePub +" checking...\r"), tmpOutputFile = os.path.join(targetDir, file + "Check.log") cmdStr = ePubCheckCmd + ' ' + '"' + ePub + '"' + overrideCmdStr #if gopts.jarArgs != "": # # hack to add default json output file name to the -j param until that bug gets fixed in ePubCheck # if not gopts.jsonNamedByEAN: jsonFileName = file + 'Check.json' else: if not file[0:13].isdigit(): jsonFileName = file + 'Check.json' print ('File: "' + file + '" does not conform to the leading-EAN naming scheme; json output file will be named: "' + jsonFileName +'"') else: jsonFileName = file[0:13] + ".ePubCheck.json" jsonFile = os.path.join(targetDir, jsonFileName) cmdStr += ' -u -j "' + jsonFile + '"' + expString # # add the -u flag to epubcheckh if verbose output is on... # if gopts.verbose: cmdStr += " -u" # # add the value of the env var ePubCheckCustomMessageFile if it exists # # # add any more jarArgs to the command line # this is very brittle as the script adds a bunch of things autocratically which could conflict # cmdStr += " " + gopts.jarArgs # print ("ePubCheck cmdstr= " + cmdStr) # # run ePubcheck and present the results stored in the json output file; If the script is running in Python 3.3 or later, use the timeout= # tmpOutput = open(tmpOutputFile, "w") if(useTimeout): try: checkTime = time.time() checkProcess = subprocess.call(cmdStr, stdout=tmpOutput, stderr=tmpOutput, shell=True, timeout=gopts.timeoutVal) checkTime = time.time() - checkTime except subprocess.TimeoutExpired: if logging: elapsedTime = time.time() - startTime checkTime = gopts.timeoutVal logStats(statsLog, targetDir, file, ePub, str(elapsedTime), str(checkTime), "NA", "NA", "NA", "NA", "NA", "NA", "NA", "ePubcheck hang", "NA", "NA", "NA") print ("ePubCheck of " + file + " has hung; skipping this file") continue else: checkTime = time.time() checkProcess = subprocess.call(cmdStr, stdout=tmpOutput, stderr=tmpOutput, shell=True) checkTime = time.time() - checkTime elapsedTime = time.time() - startTime tmpOutput.close() if checkForException(tmpOutputFile, "com.adobe.epubcheck.tool.Checker.main"): print(" Epubcheck threw exception processing file: " + file + "; processing of this file aborting...") logStats(statsLog, "NA", targetDir, file, ePub, str(elapsedTime), str(checkTime), "NA", "NA", "NA", "NA", "NA", "NA", "NA", "ePubcheck exception", "NA", "NA", "NA") continue # # examine the .json output file and check the number of errors reported # if os.path.exists(jsonFile): try: jsonData = open(jsonFile, "r").read() checkResults = json.loads(jsonData) except: if logging: elapsedTime = time.time() - startTime logStats(statsLog, targetDir, file, ePub, str(elapsedTime), str(checkTime), "NA", "NA", "NA", "NA", "NA", "NA", "NA", "exception on .json json.loads", "NA", "NA", "NA") print ("json output file " + jsonFile + " caused exception on load, processing of " + ePub + " abandoned...") continue checkerVersion = checkResults["checker"]["checkerVersion"] nErrs = checkResults["checker"]["nFatal"] + checkResults["checker"]["nError"] if nErrs == 0: print ("File #" + str(nChecked) + " (of " + str(nTotalFiles) + ") : " + ePub + " contained NO severe error messages:") else: print ("File #" + str(nChecked) + " (of " + str(nTotalFiles) + ") : " + ePub + " has " + str(nErrs) + " severe errors (" + str(checkResults["checker"]["nFatal"]) +" FATAL and " + str(checkResults["checker"]["nError"]) + " ERROR messages)") # # custom message file in use? # customMessages = checkResults["customMessageFileName"] if customMessages is not None: print(" Custom message file in use: '" + customMessages +"'") print("") # # failure case, expected .json file not found, keep trying! # else: if logging: elapsedTime = time.time() - startTime logStats(statsLog, "NA", targetDir, file, ePub, str(elapsedTime), str(checkTime), "NA", "NA", "NA", "NA", "na", "NA", "NA", ".json output FNF", "NA", "NA", "NA") print ("json output file " + jsonFile + " NOT found, processing aborting...") continue # # preserve the json if requested; [TODO] only diff them if saving and an older version was foun # # simple case, no prior json file exists, save it away and move on # if not os.path.exists(os.path.join(errorsDir, jsonFileName)): if saveJson: shutil.move(jsonFile, errorsDir) oldPath = "NA" checkChanges = "NA" pubChanged = "NA" spineChanged = "NA" manifestChanged = "NA" messagesChanged = "NA" oldJsonExists = False else: # # existing json file for this epub was found; load the old json to see if its identical; if it is, save the latest copy # oldJsonExists = True if gopts.compareJson: jsonData = open(os.path.join(errorsDir, jsonFileName), "r").read() oldResults = json.loads(jsonData) jsonChanges = CompareResults.compareResults(oldResults, checkResults) changesJsonFile = jsonFileName + "diffs.json" changesJson = os.path.join(errorsDir, changesJsonFile) if os.path.exists(changesJson): oldMTime = os.path.getmtime(changesJson) oldFMTtime = time.strftime("%Y-%m-%d-%H%M.%S", time.gmtime(oldMTime)) newName = jsonFileName + "diffs." + oldFMTtime +".json" print (" Found an older json diff output file for " + ePub + "; saving the older version as: '" + os.path.join(errorsDir, newName) + "'\r\n") os.rename(changesJson, os.path.join(errorsDir, newName)) changesFP = open(changesJson, "w") json.dump(jsonChanges, changesFP, indent=2) changesFP.close() # # json schema change: moved file name from publication to checker; if the name isn't found, use one in publication; this hack can be removed soon. # try: oldPath = oldResults["checker"]["path"] except: oldPath = oldResults["publication"]["path"] #if (oldResults["publication"] == checkResults["publication"]) and (oldResults["items"] == checkResults["items"]) and (oldResults["messages"] == checkResults["messages"]): if jsonChanges["summary"]["publicationChanges"] + jsonChanges["summary"]["itemChanges"] == 0: print (' ePubCheck done on "' + checkResults["checker"]["checkDate"] + '" matched results of check done of "' + str(oldPath) + '" on "' + oldResults["checker"]["checkDate"] + '"; preserving the latest output file...') # # save the latest version # if saveJson: os.remove(os.path.join(errorsDir, jsonFileName)) shutil.move(jsonFile, errorsDir) else: os.remove(jsonFile) pubChanged = False spineChanged = False manifestChanged = False checkChanges = False if oldResults["messages"] == checkResults["messages"]: messagesChanged = False # # the two json files aren't identical; preserve the old one by adding a timestamp to the file name and save the new one as "file".epubCheck.json # else: checkChanges = True if saveJson: oldMTime = os.path.getmtime(os.path.join(errorsDir, jsonFileName)) oldFMTtime = time.strftime("%Y-%m-%d-%H%M.%S", time.gmtime(oldMTime)) newName = jsonFileName + "." + oldFMTtime +".json" print (" Found an older, differing, json output file for " + ePub + "; saving the older version as: '" + os.path.join(errorsDir, newName) + "'\r\n") os.rename(os.path.join(errorsDir, jsonFileName), os.path.join(errorsDir, newName)) shutil.move(jsonFile, errorsDir) else: os.remove(jsonFile) print ("") ppEpubCheckChanges(jsonChanges) pubChanged = jsonChanges["summary"]["encodedPubChanges"] spineChanged = jsonChanges["summary"]["encodedSpineChanges"] manifestChanged = jsonChanges["summary"]["encodedManiChanges"] # # log output to console # if nErrs > 0 and gopts.showErrors: print ("") print (" Messages Summary:") logMessages(checkResults["messages"], "FATAL") logMessages(checkResults["messages"], "ERROR") if gopts.verbose or gopts.showWarning: logMessages(checkResults["messages"], "WARNING") if gopts.verbose or gopts.showUsage: logMessages(checkResults["messages"], "USAGE") if oldJsonExists and gopts.compareJson: if checkResults["messages"] != oldResults["messages"] and (gopts.verbose): messagesChanged = compareMessages(checkResults["messages"], oldResults["messages"]) if checkResults["messages"] != oldResults["messages"] and not gopts.verbose: messagesChanged = "True, comparison disabled" print (" Generated messages from " + file + " changed...") print (" --") if checkResults["messages"] == oldResults["messages"] and gopts.verbose: messagesChanged = "Mess==" print (" Generated messages from " + file + " are unchanged...") print (" --") else: messagesChanged = "NA, comparison disabled" print ("--") print ("") # # save the results and cleanup after each file # elapsedTime = time.time() - startTime if logging: logStats(statsLog, checkerVersion, targetDir, file, ePub, str(elapsedTime), str(checkTime), str(checkResults["publication"]["ePubVersion"]), str(oldPath), str(checkChanges), pubChanged, spineChanged, manifestChanged, str(messagesChanged), str(checkResults["checker"]["nFatal"]), str(checkResults["checker"]["nError"]), str(checkResults["publication"]["isScripted"]), str(checkResults["publication"]["hasFixedFormat"])) os.remove(tmpOutputFile)epubcheck-4.0.2/src/tools/Dictionary.py0000644000175000017500000000225413017276730017367 0ustar eugeneeugene#!c:\python27\python class DictCompare(object): """ Calculate the difference between two dictionaries as: (1) items added (2) items removed (3) keys same in both but changed values (4) keys same in both and unchanged values """ def __init__(self, current_dict, past_dict): self.current_dict, self.past_dict = current_dict, past_dict self.current_keys, self.past_keys = [ set(d.keys()) for d in (current_dict, past_dict) ] self.intersect = self.current_keys.intersection(self.past_keys) def added(self): return self.current_keys - self.intersect def removed(self): return self.past_keys - self.intersect def changed(self): return set(o for o in self.intersect if self.past_dict[o] != self.current_dict[o]) def unchanged(self): return set(o for o in self.intersect if self.past_dict[o] == self.current_dict[o]) def makeDict(inputArray, key): outputDict = {} if len(inputArray) == 0: return outputDict for item in inputArray: itemKey = item[key] outputDict[itemKey] = item return outputDict epubcheck-4.0.2/src/tools/CompareResults.py0000644000175000017500000002232013017276730020226 0ustar eugeneeugene#!c:\python27\python import os import sys import optparse import json import Dictionary def compareResults(oldJson, newJson): # # initialize the differences structure and local copies of the publication metadata and the manifest for comparison # jsonDelta = {} jsonDelta["summary"] = {} jsonDelta["summary"]["newCheck"] = newJson["checker"] jsonDelta["summary"]["oldCheck"] = oldJson["checker"] jsonDelta["publication"] = {} jsonDelta["publication"]["adds"] = {} jsonDelta["publication"]["cuts"] = {} jsonDelta["publication"]["changes"] = {} jsonDelta["manifest"] = {} jsonDelta["manifest"]["adds"] = {} jsonDelta["manifest"]["cuts"] = {} jsonDelta["manifest"]["changes"] = {} jsonDelta["spine"] = {} jsonDelta["spine"]["adds"] = {} jsonDelta["spine"]["cuts"] = {} jsonDelta["spine"]["orderChanges"] = {} jsonDelta["spine"]["contentChanges"] = [] jsonDelta["spine"]["unchanged"] = 0 oldPub = oldJson["publication"] newPub = newJson["publication"] newSpine = {} newSpineContents = {} oldSpineContents = {} oldSpine = {} newMani = newJson["items"] oldMani = oldJson["items"] newManiDict = Dictionary.makeDict(newMani, "id") oldManiDict = Dictionary.makeDict(oldMani, "id") # # compare the publication metadata # deltaPub = Dictionary.DictCompare(newPub, oldPub) for item in deltaPub.added(): jsonDelta["publication"]["adds"][item] = newPub[item] for item in deltaPub.removed(): jsonDelta["publication"]["cuts"][item] = oldPub[item] pubChanges = deltaPub.changed() if len(pubChanges) > 0: for item in pubChanges: jsonDelta["publication"]["changes"][item] = {"newValue" : newPub[item], "oldValue" : oldPub[item]} if len(jsonDelta["publication"]["adds"]) + len(jsonDelta["publication"]["cuts"]) + len(jsonDelta["publication"]["changes"]) == 0: pubChanges = "Pub==" else: pubChanges = "Pub-" if len(jsonDelta["publication"]["adds"]) > 0: pubChanges += "A" + str(len(jsonDelta["publication"]["adds"])) else: pubChanges += "xA" if len(jsonDelta["publication"]["cuts"]) > 0: pubChanges += "-R" + str(len(jsonDelta["publication"]["cuts"])) else: pubChanges += "-xR" if len(jsonDelta["publication"]["changes"]) > 0: pubChanges += "-C" + str(len(jsonDelta["publication"]["changes"])) else: pubChanges += "-xC" jsonDelta["summary"]["publicationChanges"] = len(jsonDelta["publication"]["adds"]) + len(jsonDelta["publication"]["cuts"]) + len(jsonDelta["publication"]["changes"]) jsonDelta["summary"]["encodedPubChanges"] = pubChanges # print(" Calculated publication changes: adds: " + str(len(jsonDelta["publication"]["adds"])) + "; cuts: " + str(len(jsonDelta["publication"]["cuts"])) + "; changes: " + str(len(jsonDelta["publication"]["changes"]))) # # compare the spines # for item in newMani: if item["isSpineItem"]: newSpine[item["id"]] = item["spineIndex"] newSpineContents[item["id"]] = item["checkSum"] for item in oldMani: if item["isSpineItem"]: oldSpine[item["id"]] = item["spineIndex"] oldSpineContents[item["id"]] = item["checkSum"] deltaSpine = Dictionary.DictCompare(newSpine, oldSpine) deltaSpineContents = Dictionary.DictCompare(newSpineContents, oldSpineContents) # # look for adds/cuts/order changes in the spine # if len(deltaSpine.added()) > 0: for item in deltaSpine.added(): jsonDelta["spine"]["adds"][item] = newSpine[item] if len(deltaSpine.removed()) > 0: for item in deltaSpine.removed(): jsonDelta["spine"]["cuts"][item] = oldSpine[item] if len(deltaSpine.changed()) > 0: jsonDelta["spine"]["orderChanges"] = {} for item in deltaSpine.changed(): jsonDelta["spine"]["orderChanges"][item] = {} jsonDelta["spine"]["orderChanges"][item]["newSpineIndex"] = newSpine[item] jsonDelta["spine"]["orderChanges"][item]["oldSpineIndex"] = oldSpine[item] jsonDelta["spine"]["unchanged"] = len(deltaSpine.unchanged()) # # look for content changes only in items common to both spines # if len(deltaSpineContents.changed()) > 0: for item in deltaSpineContents.changed(): jsonDelta["spine"]["contentChanges"] = {} jsonDelta["spine"]["contentChanges"][item] = newManiDict[item]["fileName"] # # summarize the spine changes # if len(jsonDelta["spine"]["adds"]) + len(jsonDelta["spine"]["cuts"]) + len(jsonDelta["spine"]["orderChanges"]) + len(jsonDelta["spine"]["contentChanges"]) == 0: spineChanges = "Spine==-N" + str(newPub["nSpines"]) else: spineChanges = "Spine-N" + str(newPub["nSpines"]) if jsonDelta["spine"]["unchanged"] == 0: spineChanges += "-xU" else: spineChanges += "-U" + str(jsonDelta["spine"]["unchanged"]) if len(jsonDelta["spine"]["adds"]) > 0: spineChanges += "-A" + str(len(jsonDelta["spine"]["adds"])) else: spineChanges += "-xA" if len(jsonDelta["spine"]["cuts"]) > 0: spineChanges += "-R" + str(len(jsonDelta["spine"]["cuts"])) else: spineChanges += "-xR" if len(jsonDelta["spine"]["orderChanges"]) > 0: spineChanges += "-OC" + str(len(jsonDelta["spine"]["orderChanges"])) else: spineChanges += "-xOC" if len(jsonDelta["spine"]["contentChanges"]) > 0: spineChanges += "-CC" + str(len(jsonDelta["spine"]["contentChanges"])) else: spineChanges += "-xCC" jsonDelta["summary"]["spineChanges"] = len(jsonDelta["spine"]["adds"]) + len(jsonDelta["spine"]["cuts"]) + len(jsonDelta["spine"]["orderChanges"]) + len(jsonDelta["spine"]["contentChanges"]) jsonDelta["summary"]["encodedSpineChanges"] = spineChanges # # do the manifest # deltaMani = Dictionary.DictCompare(newManiDict, oldManiDict) for item in deltaMani.added(): jsonDelta["manifest"]["adds"][item] = newManiDict[item] for item in deltaMani.removed(): jsonDelta["manifest"]["cuts"][item] = oldManiDict[item] maniChanges = list(deltaMani.changed()) if (len(maniChanges)) > 0: for item in maniChanges: itemDelta = {} deltaItem = Dictionary.DictCompare(newManiDict[item], oldManiDict[item]) if len(deltaItem.added()) > 0: itemDelta["adds"] = {} for theAdd in deltaItem.added(): #print("property added: " + theAdd + " value: " + str(newManiDict[item][theAdd])) itemDelta["adds"][theAdd] = newManiDict[item][theAdd] if len(deltaItem.removed()) > 0: itemDelta["cuts"] = {} for theCut in deltaItem.removed(): itemDelta["cuts"][theCut] = oldManiDict[item][theCut] if len(deltaItem.changed()) > 0: itemDelta["changes"] = {} for itemProp in deltaItem.changed(): if itemProp == "referencedItems": oldRefs = set(oldManiDict[item][itemProp]) newRefs = set(newManiDict[item][itemProp]) refsCommon = newRefs & oldRefs refsAdded = newRefs - oldRefs refsRemoved = oldRefs - refsCommon itemDelta["changes"][itemProp] = { "adds" : list(refsAdded), "cuts" : list(refsRemoved) } elif itemProp == "checkSum": itemDelta["changes"][itemProp] = {"newValue" : newManiDict[item]["fileName"], "oldValue" : oldManiDict[item]["fileName"]} else: itemDelta["changes"][itemProp] = {"newValue" : newManiDict[item][itemProp], "oldValue" : oldManiDict[item][itemProp]} jsonDelta["manifest"]["changes"][item] = itemDelta #print(" Manifest item id : " + item + " changed...") #print(" Manifest item delta: " + str(itemDelta)) # print(" Calculated manifest changes: adds: " + str(len(jsonDelta["manifest"]["adds"])) + "; cuts: " + str(len(jsonDelta["manifest"]["cuts"])) + "; changes: " + str(len(jsonDelta["manifest"]["changes"]))) jsonDelta["summary"]["itemChanges"] = len(jsonDelta["manifest"]["adds"]) + len(jsonDelta["manifest"]["cuts"]) + len(jsonDelta["manifest"]["changes"]) if jsonDelta["summary"]["itemChanges"] == 0: jsonDelta["summary"]["encodedManiChanges"] = "Mani==" else: maniChanges = "Mani-" if len(jsonDelta["manifest"]["adds"]) > 0: maniChanges += "A" + str(len(jsonDelta["manifest"]["adds"])) else: maniChanges += "xA" if len(jsonDelta["manifest"]["cuts"]) > 0: maniChanges += "-R" + str(len(jsonDelta["manifest"]["cuts"])) else: maniChanges += "-xR" if len(jsonDelta["manifest"]["changes"]) > 0: maniChanges += "-C" + str(len(jsonDelta["manifest"]["changes"])) else: maniChanges += "-xC" jsonDelta["summary"]["encodedManiChanges"] = maniChanges return(jsonDelta)epubcheck-4.0.2/src/tools/CompareResultsUtil.py0000644000175000017500000000317613017276730021074 0ustar eugeneeugene#!c:\python27\python import os import sys import optparse import json import CompareResults def parse_compare_args(argv): prog_dir = os.path.dirname(argv[0]) usage = """ Usage: %s [OPTION] Compare epubcheck json output """[1:-1] % os.path.basename(argv[0]) parser = optparse.OptionParser(usage=usage) parser.add_option("-r", "--resultFile", dest="resultFile", type="str", default="", help="The destination file for the comparison results") opts,args = parser.parse_args(argv[1:]) return opts,args global gopts gopts,args = parse_compare_args(sys.argv) if (len(sys.argv) < 3): print "ERROR: Insufficent args were provided. Specify both the original and new json files" sys.exit(); gopts.oldFile = os.path.join(".", sys.argv[1]) gopts.newFile = os.path.join(".", sys.argv[2]) if (not os.path.isfile(gopts.oldFile)): print "ERROR: Original file " + gopts.oldFile + " could not be found" sys.exit() if (not os.path.isfile(gopts.newFile)): print "ERROR: New file " + gopts.newFile + " could not be found" sys.exit() oldJsonData = open(gopts.oldFile, "r").read() oldResults = json.loads(oldJsonData) newJsonData = open(gopts.newFile, "r").read() newResults = json.loads(newJsonData) jsonChanges = CompareResults.compareResults(oldResults, newResults) if (gopts.resultFile == ""): gopts.resultFile = os.path.basename(gopts.oldFile) + "_" + os.path.basename(gopts.newFile) + ".json" changesFP = open(gopts.resultFile, "w") json.dump(jsonChanges, changesFP, indent=2) changesFP.close() print "Finished! Results can be found in " + gopts.resultFileepubcheck-4.0.2/.gitignore0000644000175000017500000000062613017276730014752 0ustar eugeneeugene######################### #### GENERAL or ROOT #### ######################### # Transifex .transifexrc # Maven target/ # Eclipse /bin/ .classpath .project .settings/ *.iml *.pyc .DS_Store *.orig pre-commit-changes.txt # Emacs temp files ~* *~ #SVN .svn *.svn-base *# .idea .AppleDouble/ # OS Files .DS_Store .DS_Store? ._* .Spotlight-V100 .Trashes Icon? ehthumbs.db Thumbs.db #vim files .*.sw? .*~ epubcheck-4.0.2/.tx/0000755000175000017500000000000013017276730013467 5ustar eugeneeugeneepubcheck-4.0.2/.tx/config0000644000175000017500000000310713017276730014660 0ustar eugeneeugene[main] host = https://www.transifex.com minimum_perc = 50 [epubcheck.ErrorsWarnings] file_filter = src/main/resources/com/adobe/epubcheck/messages/MessageBundle_.properties source_file = src/main/resources/com/adobe/epubcheck/messages/MessageBundle.properties source_lang = en type = UNICODEPROPERTIES [epubcheck.CommandlineMessages] file_filter = src/main/resources/com/adobe/epubcheck/util/messages_.properties source_file = src/main/resources/com/adobe/epubcheck/util/messages.properties source_lang = en type = UNICODEPROPERTIES [epubcheck.CssParser] file_filter = src/main/resources/org/idpf/epubcheck/util/css/messages_.properties source_file = src/main/resources/org/idpf/epubcheck/util/css/messages.properties source_lang = en type = UNICODEPROPERTIES [epubcheck.jing-xsd-validation] file_filter = src/main/resources/com/thaiopensource/datatype/xsd/resources/Messages_.properties source_file = src/main/resources/com/thaiopensource/datatype/xsd/resources/Messages.properties source_lang = en type = PROPERTIES [epubcheck.jing-relaxng-validation] file_filter = src/main/resources/com/thaiopensource/relaxng/pattern/resources/Messages_.properties source_file = src/main/resources/com/thaiopensource/relaxng/pattern/resources/Messages.properties source_lang = en type = PROPERTIES [epubcheck.jing-schematron-validation] file_filter = src/main/resources/com/thaiopensource/validate/schematron/resources/Messages_.properties source_file = src/main/resources/com/thaiopensource/validate/schematron/resources/Messages.properties source_lang = en type = PROPERTIES epubcheck-4.0.2/.gitattributes0000644000175000017500000000041313017276730015647 0ustar eugeneeugene* text=auto *.css text eol=lf *.htm text eol=lf *.html text eol=lf *.js text eol=lf *.json text eol=lf *.ncx text eol=lf *.opf text eol=lf *.svg text eol=lf *.smil text eol=lf *.txt text eol=lf *.xhtml text eol=lf *.xml text eol=lf *.dtd text eol=lf *.ent text eol=lfepubcheck-4.0.2/.travis.yml0000644000175000017500000000110613017276730015065 0ustar eugeneeugenelanguage: java jdk: - oraclejdk8 - oraclejdk7 before_install: .travis/before_install.sh script: mvn verify after_success: .travis/after_success.sh branches: only: - master - contrib/nook env: global: - secure: gcpUIktuajGHvn95bzMg9Nqay+kGAdKXWOosA6sQHvaK+KCsiP4nhAMX5rWUYvk3XnEs2WlfZUBO7/aDcpX4fjZozs8fHbVuSfftYP+4MIIhEI2FNEXp823EShSRB32cGmEkdUh7OQdv5zN8SEQNW9MJguLSvTkp2FGYEsV3x1g= - secure: jMv0M898kWiSKiPaky7CpCcvC3QqzEWwauOsmx9WuRNLFO3e/tuM/bPx+06wWlBgy359uPlSFaOch4QFlDx/CTCLtIudpF7cx4Raej9F3yVdqLnT2/9W88Oi5Vxhak1Szs3MUmVWbIqd5ulf2jsV1hMHJVn2tg3i1KYqmFyQ7+A= epubcheck-4.0.2/.travis/0000755000175000017500000000000013017276730014344 5ustar eugeneeugeneepubcheck-4.0.2/.travis/after_success.sh0000755000175000017500000000022113017276730017527 0ustar eugeneeugene#!/bin/bash if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then mvn deploy -DskipTests -Dinvoker.skip=true else echo "Skipping Maven deploy." fi epubcheck-4.0.2/.travis/settings.xml0000644000175000017500000000763113017276730016735 0ustar eugeneeugene sonatype-nexus-snapshots ${env.CI_DEPLOY_USERNAME} ${env.CI_DEPLOY_PASSWORD} standard-with-extra-repos true sonatype OSS Sonatype repo (releases) true always warn false never fail https://oss.sonatype.org/content/repositories/releases/ sonatype-snapshots OSS Sonatype repo (snapshots) false always warn true never fail https://oss.sonatype.org/content/repositories/snapshots/ sonatype-apache Apache repo (releases) true always warn false never fail https://repository.apache.org/releases/ apache-snapshots ASF repo (snapshots) false never warn true always fail https://repository.apache.org/snapshots/ codehaus-snapshots Codehaus (snapshots) false always warn true never fail https://nexus.codehaus.org/snapshots/ staging-repos sonatype-staging https://oss.sonatype.org/content/groups/staging staging-repos epubcheck-4.0.2/.travis/before_install.sh0000755000175000017500000000021013017276730017664 0ustar eugeneeugene#!/bin/bash echo "Copying Maven settings to '$HOME/.m2/settings.xml'" cp $TRAVIS_BUILD_DIR/.travis/settings.xml $HOME/.m2/settings.xml