From b0d1a39e995871ef81cb58e8f1587a771fdd2deb Mon Sep 17 00:00:00 2001 From: Miklos Vajna Date: Wed, 2 Nov 2016 11:10:35 +0100 Subject: [PATCH] xmlsecurity PDF verify: add support for object streams Adobe Acrobat uses object streams (PDF 1.6) when it signs a PDF exported from LO (PDF 1.4), with this we can verify that signature. If the PDF had at least one signature in LO, then the doc is not upgraded from PDF 1.4, so that was working already. Change-Id: I54b4447ca965a8ba1ffc69bde228ab6f0bda59ee --- xmlsecurity/inc/pdfio/pdfdocument.hxx | 50 +- .../qa/unit/pdfsigning/data/pdf16adobe.pdf | Bin 0 -> 81882 bytes xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx | 14 + xmlsecurity/source/pdfio/pdfdocument.cxx | 439 +++++++++++++----- 4 files changed, 382 insertions(+), 121 deletions(-) create mode 100644 xmlsecurity/qa/unit/pdfsigning/data/pdf16adobe.pdf diff --git a/xmlsecurity/inc/pdfio/pdfdocument.hxx b/xmlsecurity/inc/pdfio/pdfdocument.hxx index 95663e6c190b..37457c024d42 100644 --- a/xmlsecurity/inc/pdfio/pdfdocument.hxx +++ b/xmlsecurity/inc/pdfio/pdfdocument.hxx @@ -45,7 +45,40 @@ enum class TokenizeMode /// Till the first %%EOF token. EOF_TOKEN, /// Till the end of the current object. - END_OF_OBJECT + END_OF_OBJECT, + /// Same as END_OF_OBJECT, but for object streams (no endobj keyword). + STORED_OBJECT +}; + +/// The type column of an entry in a cross-reference stream. +enum class XRefEntryType +{ + /// xref "n" or xref stream "1". + NOT_COMPRESSED, + /// xref stream "2. + COMPRESSED +}; + +/// An entry in a cross-reference stream. +struct XRefEntry +{ + XRefEntryType m_eType; + /** + * Non-compressed: The byte offset of the object, starting from the + * beginning of the file. + * Compressed: The object number of the object stream in which this object is + * stored. + */ + sal_uInt64 m_nOffset; + /** + * Non-compressed: The generation number of the object. + * Compressed: The index of this object within the object stream. + */ + sal_uInt64 m_nGenerationNumber; + /// Are changed as part of an incremental update?. + bool m_bDirty; + + XRefEntry(); }; /** @@ -60,9 +93,7 @@ class XMLSECURITY_DLLPUBLIC PDFDocument /// This vector owns all elements. std::vector< std::unique_ptr > m_aElements; /// Object ID <-> object offset map. - std::map m_aXRef; - /// Object ID <-> "are changed as part of an incremental update?" map. - std::map m_aXRefDirty; + std::map m_aXRef; /// Object offset <-> Object pointer map. std::map m_aOffsetObjects; /// Object ID <-> Object pointer map. @@ -80,8 +111,6 @@ class XMLSECURITY_DLLPUBLIC PDFDocument static int AsHex(char ch); /// Decode a hex dump. static std::vector DecodeHexString(PDFHexStringElement* pElement); - /// Tokenize elements from current offset. - bool Tokenize(SvStream& rStream, TokenizeMode eMode); public: PDFDocument(); @@ -99,7 +128,14 @@ public: std::vector GetPages(); /// Remember the end location of an EOF token. void PushBackEOF(size_t nOffset); - const std::map& GetIDObjects() const; + /// Look up object based on object number, possibly by parsing object streams. + PDFObjectElement* LookupObject(size_t nObjectNumber); + /// Access to the input document, even after the inpust ream is gone. + SvMemoryStream& GetEditBuffer(); + /// Tokenize elements from current offset. + bool Tokenize(SvStream& rStream, TokenizeMode eMode, std::vector< std::unique_ptr >& rElements, PDFObjectElement* pObject); + /// Register an object (owned directly or indirectly by m_aElements) as a provder for a given ID. + void SetIDObject(size_t nID, PDFObjectElement* pObject); /// Read elements from the start of the stream till its end. bool Read(SvStream& rStream); diff --git a/xmlsecurity/qa/unit/pdfsigning/data/pdf16adobe.pdf b/xmlsecurity/qa/unit/pdfsigning/data/pdf16adobe.pdf new file mode 100644 index 0000000000000000000000000000000000000000..ac1c5f37b97235e9865ad535bb68604f6874baca GIT binary patch literal 81882 zcma&N19)WJwl3UJ$F@2Z+p5^MZQJVDcG4Z&M#r{ob!^+o-`}_QIcM+Z?0f&a##5_m zt~uuz?|8=;bD^q8<%LCQ8R^*INq2Uq=HOu%837CcJ3~u&Zf<&M3tJNdM~m+!#sEfo zX#kKB2xOv{128hvivZZ!8JXDVW&d<2|LI_5XQdYhXaQK**#V3|W*uH$coSRWztjN! z*9H&6#PUBjgiVa>j7{VX9BrKbSQN6ecCoQ_0+W8`4wU|?cnVq_Eq0tH!x1Xvl^S$MgbnV2}3 z7(`jv*jX9afGkV`Y@$FQ15iLf1jqptW)b4mp_i~VHgVVb<2Vz`Uky_`03*X6fQt0e zCbnkI=6~G#3ytgFZnDuU+Sxh(!Swe4r9a#Nm|5wSJ?u^B)fG)l>D9Ct0n7l#KLj{A zJDM2Sz{8mTHZ(NWN7C0f)YrEJiH~9hBp4v3@IXjsfkn>yi(~j8dF&E|8M8x-*?x`B zE8|ayA3+rVFca6;2TkK3sDPyq=YG!izn(|*`vUgGS_%#c9_A0V|J43ZlAW9l9G%@A zO-$io7~o+@Nk!yD;b8#qFwFl#^nYRyz{tq6HL1O!TS%4u*e2udlyls;?hm ztgo*>&t$|8L8Cv;=-<tb#F zj~#;!y}W^$i4%b1@6Nx2CiG{zwVm1j|C9iL;U78omp}i4 z{a?Z@__toVKa>8v*jed-?96NcW)?aYAW-MOLe5VA-|GKBR+lrhG%<4i^GQ@u2Eh0? z-MoJ`dLG)&DW{f70adDZ+ODDVBff`6r+MS4{sQKmS>O%zujRzi9Y3 zoVE-A#(%`dmI=Vf{#TU#Ujd7UQzOu)|GyDQ3J_Kjv^KD{g85I@|8ntPtuy{*^RM`_ z{4>7H|A_DZnM)wszk&J_Q`^5HuFR;%0AK?CgTX(mot=@AiL(~{pK}AfvWdI%pXKcT zB@4vEGgL-mP#KXrUa7r|z7#qnKemAM;R{RQ%^>w6%?peZ)q3&Vm#q`xum}o<@0h)| zoGcg~t}@CLiplZbBx&k|re}IS_WQal(MiYS?q_&+9|GqB*Qw%Zen@5t-L3`p{W5uN zX>shi>}bPy1af5m8MY=(b@ z4_Aq@rs2Tb7P6*X=G0um@>AolgZM&5L6UD!A}{4<$hn+DF8oD?8&n}oJwiYnHI5cf zaln`kGxVNVy3sqx9v0DxO5CNMfT=E+hksV4#Kev~;s7e2Y6=E3u+Iz#LZ+3h`6A8S zJ`~>;R-vy)(-cn{tuaBtMsTL4=Sm~xf*24%?+7JAQ5R5aY0ocQ zL*Sp+8YS+h;w*%od&(Iorn(9TqlMADZLUb%OACVnH35?$@2o0VhN2!6C?l$xGJC&ALM4ktL& zX1<1Lwit)%eMUZ1dbpZOk7W;Jp;A!YzoHfa$W0Z65iZl46Sh+pp-_(3fX+Zz9UxpG zp8x?XmcYdM6_>hVsp>vF=dol1nU)w|{iR05=KFa@nOR736-QHa7CO5%uIV?LbW)Oj zSq2yycfj^9P|QYM+`R-&Dx14UC{;xm;Q{(fti;h-IkZ0op@Ul=?F2zQwVjt$g>{@=livi4nPc!5ThxJgBg?& ziag$v%5E=IXjK)d09cj^b!N)Gk410S>~-9C?Xgo*gQU`-YrPrS59&p=Z`s$KpEBqN zqiaWMDfFgD?vp=$-XQS3P+nd|hGNoRJ z%fo+HwDR#enB`_Gamy|6!M{-iiIJDS(RP1vwa!BQPs_ny_4?1{;Qw6ltgK87?EhW8 zf1UIgh5l#Z77y1}g>^<-z|LA(YS(jf{TW(|W=LsCNW$GPjgo+bA}$EVcmtFnZ%dpA zT1ho_{XtS9Y*naGo1+lK5-ORlsQKe+a1O~!go*n`M9Jj2PE!yVO zN_ThnnZ7`eX;seFV{hXcva>AV)iE!)2t$ytIygWm&R`hIm_#u^T0}BFRh(5ZaGp4N zn5Y2SLe!YV-x*+00C_BuCG-*xKPzy#0U0=$45%n#^$c?YS(1fO4rzD%xB7H)Mvz}sUHj+bQGL4R1(Aqm<$N*m3T>b2$QjN9>$iT1j6R4rHZLGA41Mp=?&Hqfm4-W5C(_R=@ZbJ!+dNN3PgHM* z?tC9#JMlMzFNYAf#ja7G%$~Zg%AeH01;L?0kirT3p>|~R!cqj2kQ@5B4M7Nzp#_Os z!$ZUO`;~+VuB8llYU7`1YXhH%9sGcTc;u5vm|@iYE-0i938civARGyA2pWR2q|_rg zj&vN^QSmm$kSh`&DP9?8#Cl|Uyk8jJLEZ_y z6L>{@1+xq3r`3*p=a!B^zM4>&A~8o{4@8+2G1jLBM~(kt#7Q)4P5E}9V9IezQlH@Q z!z2FKOxM6?puNZ1u#sskbz}USDSdr5$1t9OEYo2s_4pTDLy%W^R~D}D%n>?6ql!`2 znz3b-Gfh|2SFQ&n&j_9=UDN9N&;0Kod;pNulfz*@d zlZ6+l-WdB;7h+e2Z-nm;-*COLuF21k&B@Dy$7{%E;y1B3iw`{C@J~cv zB`Bz*FF}O8?7?=hMnTZMXt~lQ7(Re?dKPF}K}CjO$e?VP@?al>#2S@l!ZVED7!RmiW zVI-wPCqVWbNZz^Kq3?IusUD!+LAaLN@wtw3SAI)>Ds>lVC-R~EpvQw@-nM^gyb8O@ z+^*f0*v8%tvA1ewelvELarb=MxEi_IznXv|pp06_Ee#)z4<(`(W)pi5 z;G_}_6%7>=6N$`2%~#6bpV9bpBFZzDnh$doQxks8t427%{*}jVdX%7%OKQp{HOPI+ zS4n9k6*0CG_p?E`e1KLKtFEFn0Yl9&ZN92lTFA~WS;o!7L&Zf(De``)VEHH8Yo4Hf zaM^65GTR*^rHW*OY5{!5y!@{qG^zBu45s9Q1u_K8BTH@**Ydim5nF551NZs`oIVlS z@2kTgCK7asimi^d?ZS)NB-G)mb0TRw7V~ttj2dI4+rqRF7Vu_MyTT7FsZf(U{q_mc z=2P224`_c{Tm6&ZvT(0l29p3pwnEct(rVVR>ZcYKvGo?3)^CRpAP?Xn^mxcK=9+Xw+s8ajYMXPZyE5#W3D8%_U}! zWOCdnpk;^s^Tt`V&OJDM3b(HbNspUweB|O!3xv!u#1tIiFt&1yr{#pqvBc!8(}8kn zqaa=%h;hU;EjXNQbj393Ka6NOxuqob1ufyDv-++$Q-|Q5bMB8Rh{+9p*Ar<&&b|E5 z3!97kt@pZ5h+m8wxEmhopnZ*mt=BGPZT6=b-BfWpSy|w4DxAPUM%FMk(tO_>6n`M9 z!>A%TcrQC48vZM<%u$iuK!bieX`F%b6uaR2PySw=1nh+f&e?}o$)&pcba+ZKGj_o( z+qxOUl{+%pqar86dceJr29ehRpJ+I zEx%T3E}~}(jNehFCGUe=2+T-N3imEp;s?{)7 zsW*vAO0a5%b_!=@kBx_dpD|V$gRD1oyHx!GMVbA4rh8nbsG^SY)erPY(Z6NEx@u+v zk0NNRueYK{3NUlUfMZ);KG=thavN$hs&-rV?q`kHB$_8HO`@t4&MT5of{|F*i&d6L z%Y>+3Htjehy1Fy{<-dgbdjkDODR{ik6xrZ}!u6~Il zg;L#&l^SbBQ1nL>4eVI!X$Ja&OjtYWa}es>DL3H{7bZR?jhe~ML_s&E$8ww^sDhzP zx`Bj!zpxq}j#~$OMyc%-g<=()-U*QPHf-qi?mOooJ{i=^`OIkZ90-@zN1BCu^~%#0 zh&I*vGtSEJ>*m}vY@?=aXUZN}su%ZF$>k9vS@kI_o=MEGnFGLM3(v0&EZhhj{FV0= z;zfVPF%f4?$X(YabX?}|QP%VgnGRBsTA3D71=jE|vV%GsrF(bGQ7tP@lg@=oDemAJSCPD%T3_Hd*ikDzYb9D{omyo`UZ86d{{0n8^9;v6YvK9KL^11paoRX z?qpdvM&>KNQG-7BU=u^`OnS60bu3?yp6cegG97%_v7lg+H>la&PY<)e$oLfn7bT14 z&jc%!D*cZCWdsE)5S+r;7sxf)Qo z)r?)9cqIg=(R9yJ}{OZ?D9KhSdsRyoMemSD=)WRKf-6E|Yv+7EHE^&{W%GxzvbJBCl3mQ3SX zKoiOS(`fm$-!+kECz{-IfNPQw#6i*)&oyQ^fUdn%d#>|LAyBD^aaS6MEW@Q&NhVaO zRAet)KSZviN|P1e-jkz!sf+GlQ}xq0c8IttVjiaD-nUp9J;lGsQT zw{THd5QTC!!O5OM39+RIfxH|!x#E|x<|H-^DfXoPI7bFBG_oW~g2SwVk(iZg)EyxngB>=d)LW6HtZIKDN=@ZdV3~v} zJdlj~1l2XkyW;MfP;7?ZfKd>LJwvK52AaqjJag0VMeI-Mi{Ps+t2=z7zR)-MLcLaV zL!?UEU*@fT|5bHK{~k;A69)ZOekMGkI&X(hy&lqP(r{u;oy)I*vZ5n!6p2bM_lCA& zE!YK2{gG->P5+&~R-h+DX!#19?d>bBZJs4^*{Z@lymE(MSr`9F01L>mXPgh>F-Dn{ zyiLvvw(=)#_A8jBruynJnNGDE#kat4x67QY{RC&xyrmxMD)b6I~;D}@{^b~ zjNu#wn|IjjT=OU7vKMH2{jwK=R$1*n=n2dGfc&G#{6_C0RAXoK3*CIS;5#}CT;4Vw z4qe_hDoYlBB7qF*RZ_1K#FU47RWEMHBaAWj4g0p%*G-@ofdB`*FZ3JLo1Xt?HB^NV zAc!BsKbz1VY@&GD3zpW~+yk?RA>h(*O~INg)P}&|^-E({*m+ZJJ^@$O5Lkoz7VFvB z(B$Lw7V7dsuuhlgsp>BuSWDLVp`1?8`>AO*fm1(M{9J&boPZvbH_{6qGOz#DRIMkm zYxcl}T&)?J=SOg(>aUKNj^t(BzTeEtf9^^%2Rk39J5kS3%|CHD(VV%XW2}}p{oj8& zY_V`+=GNn9R_ERtIrBtSx!K#pL0;y)B0GPAZY<5r`DGnWJAri|<~^<*d83AMIvklw zxnZpb^weXuNAJe&K7|4ew)!EkP7UsQo=~D9u`GMzqI0Ff&iIXy;vbREh37@@;KrXB zUJYXUyf6;z7`YMqv>3P}w#UL$h}dG5Rr)Ug9}GL}2FcxJf%l*lZCDxs@c>aGERM){ zDXh%c88}hj2w@JCSmJA@!8C>knn9m{+Q+!{*gX#tdVmMMEB2Y|GV!O8;d-B?>=nbu z^B~6n5+?$2h9s3}+ivQJ$q!bzwq2&A5&cl?D8`oZq+Jxjgg7Ziih>~RJf(Q6U`f(s zVMRs9)IA&@a&qg2&ojQw!&~0V*Y_F##+0kOY#%dpHJv;BAT|1>t~=t8C&uq4jpf+j zeDxAD0}@`;tJJ_L7_WqDkLYUV&Z?*HySQPO)ELJzft}PZAV-I}n}HupFK#p!lRNn| zK0OH%G~q_2U{dV$^WC$DG){&q%0KpZ%py0PeteGKxT`ML8xm1Z*3J4SYpGlG`?7sN zKT%h_gs9xAyTmUDsb}`4a&56L%H{BQZKgFxI$amA(arz%juK&Cs&+~w=z~x zlbd4+d|h0tBPQHB_ZZ6c1{@`A>6yNcD#*9=-I-4vmM+CdPnf@+t<}0pjl_!eakX8bo*G0}5 z0cMFXe$Xvr_!Xr-G^H5tZg&eG!Fw#%2yf957_t1&Z%gz*D@Nu(5}NPLfz!+A6jOQF zj6d{yyA`7?IFCpuCP{2oCA9gA3#qre%&J`=fC?${(N9b$FA<1(56)iNXgt|np zDoUL=8j4sPmZ+js!kI*xwBi>DF^SfZ($0(*f2DE`m$bRb4Beh%;*1aRx)@`*gxL6u zkyP0X=$&z$$%nl&gvmw6D$GMudt0zW7!JO;Tga9x2+SD!Ybm;-L_?`jUBwA;9dS!S zi$BbgGmP%RwVZhJ4HRpg0gB3YOo zr^92!1UEkuKO+JN(asJ+;MoVAjQD~pDYRt_fb83*h_)e0Bxuq3N1RQoPF74!FwOT_ zYevmHv1^oQO?k`VJNIZ^dz11PPfmy2Zr_w%@gdr`5=YYYTBa0B}Te=6VSS#qn0 zmAnl1QF3#S5W{|(*j0dt<#B(DBR_X%N+vIMze(!q+^GhX(U$0n-s@!f49t;a@fH@b zvVP{6aQP{(g%24NB!)&txHj>YNtAMVQ8Q&f!~Y9wsXC4 z1=>|#SHWL$ySu>-K%0<`!bbUENtM(WPG+{U{6^gOhAHYv87)EF4a6syymFw)=G|2a z-y+`&Zw?EJOifLxOg3$twJvAzq?s6!ywz5C7n?uGd%W-=Z?oPm~{;L^+u7s zFHRl!D~q(!E^;5u!idZ!pwPz3!c%!w=BF#G;euMlVz^47`CufO*eYVegGOE^{VLTl zgBE9dQVjCVGyRQ6gR^6@tcT$_)uPAjidyU454w@rd)VVNiq>r5CMjpPfdi}B6?(Qp z!*b*`N<&Wx>#>2V{AGA#u8w7V)HcM~bGKs*s*S1$Z_nDL$amM;DU?^u<4#$;)yO`A z9eG*=f&qno1>%^F0f%JGQ|&giMe&yDp6J~3Qcb+?7Fn#KDnRbaKJ~kg-#px; zV4q`~8Ck%v#i)Ri?4o`?6c^;I473ui+AH}{$>8ULm(+0zv)EgrYCVK&7f6rG<1wMR zb!4z0SQj-@=B{=`1eU3GEbrwot)vJxFplCoqPZn& z2_06|+3nQIoSmu8-2GmwtT>*!(QCVn@>!~kpqj1UsIOA7{7o_RYHl^5C#FqBRa=!7 zH_Ib&=(rP`f_56zXBOdv;;klng0NS{!g@>W1M9Y7tiZfF^CrdDMDU{3X8d_$*;-|u zWv~c5B_Mxi8~5)0ZH~CnyG=Eb4!j&EJ?_DXIruRe<)<7gA}MX@T*kz{K-I{Pt)8R4 zNBudzbatzzefr(<74CI%zDG21$L^%LR^Qm-@TQl$uw2GyZLuMziO#(J!E!##KRS?C zH-9K5J>ASY^Wt$Tv!O&b*}|p3YeJ_`uhz8c+9UM1*mTgdUvC(w z-Fa9!@Z~Bu1RKo?9%)P!IhnBdW$LNm~>Ir{t1M{a4OjtKts$S(FwQZQ=YGmyC5f{8EDD&LZI z&GjYd%oWB65lsYBO|rZJ-6hJn*ZA#LT>yjzBPM!HaTFf;$BeGarskejszP(dgxx59Osj2Y=*fkCY47*m->=}`0Ca$5bb=>=PgU<_q87Gio!>26Y*>Av~;%M>s z>Hha|d_vIi6oYb1(BzEjCO5Z*6s4ORptoTp3dEB(RGOe4tpbexR59S<2pKQbuOwy++2}u=1qAE3_&Et>vZ=$5#c&5Kehi?XePBncQ!JjR*l4i9=buS&2k;E^XV`AEXcsi9NAFaqg&ggFoHK@Y2(xUf1iM^>bb z_f_|Q7wa8(G}n}goLWzRQ?qq!yh6Q|aO-(ig*s&l?lJhO;CQCWi=McISD0@gvUyaU zUlomTY@Lwe^0lJ7QzpE(%0Tzla^H z4j3XP$2q5}^^8m!N#znW7|M%m$$L|-Wp1?Yr<%CLXl69FNLPK>crTfBMd?6~%;M;@ zhTlhKr~AI7??|ZU(*3{9qt5dTexDxlKU|i;&etuuLg>KdA^N7KJR!2d;z7wr!X*cW zsH*2;qQM1(bgg|~kKp`P84;_0zQcBQear6ZwAP3;QP6CP7VQVoidY1qC;vJ`@q4Ry zxg}Ntsjy?Fz=dRD^A1jNBZL)jZnYxSVpN*(`WgA%Dv z3F^GlSkOIp!u|BXSdM*OIu^PBGP^Vj))#iCrZnkDF>QjrZStzVJ%$V=#j9;89;6O| z`v(u}x|Fl$=Y#v#hFRW6T^5n}25bLI_)S}gd|AM-0i;MxQ>L>;7mwFC39C}00DR@h zS>PufpmWz3sOM*rdma$)js5=>vMbZg|K)bg*!f|{AhS87UZAlr``dhWgDtTYK~ z6LB&i#Pk;lID-zq5@OU1l$BU>*i7#f80=imeQrJ!oU|bEwj%#V{kSW>sfMTd$iDfU z2$p-XyH5K2KptvB6DXHmh9ReLb6nbHV@3X|hn(Jz*Vkr|=ibY3Mcr2fZo(}|*SVJDE5VG} z!F(f+)4^P)iW42jV~^xTsp8tZad&fbvXXqyUcOrR;zx(}`ijTb9@=ssYiydVO_i6f z>=D6#{4iW|{vjQAs8DV9mOw-^Tx+<_E3urNX$A9*roJNRu{_|i=NZSny7yPbhX%F# z?_h}gJyg=B;7`7*#ukm^&lYxkluWgcy3^~pgSMw2*fTzIQzZqice$r&^WcC_Kd_)H zn-EZ3bzbvuUxR0RmIntIWoFNLa+tY0h%G}0N}@L}is&;Uk}IJ=0GtHdAQ&>;jg=R9jX#pjpMMkDg-(9!#5Z-| zOW?^M9xk;_LVYVfTYj=M?1YN#)RBn_;}noJ{-soj#2;r=T8Jq{pM*soP8X!JoQyFW z@qv+$S-iIGNR4O9ynrZp7k8_aFh{O%y&CZ(n)bOWJ*P+6Hi5BcHHuqMy|~a^$n3Sd z+gdkvqE*1kNP1&kq#tUR#(KW(@nQ_*Iuaq(TO|28EfoEVr}N%OXNE6AH`gYzXE){9 z_mjSEWkeb)=jLdF5Bd&ZcTyfE_bqDY+y;Rs zc-Nes?`Pwo!1A|HL>l(JsW7qZP_=Zx=oopwlkjz&j(*Wpin{@WzaWNnNRAL$3jT4F zyId|CZc0Kuc>?IfMdSQ1By0+)&tZT^iz`oO_}-TG>c@^57RnND46PR#VjGsmUCd4p z^cA=ieF%X0#py+!z>;|q5}0{aX`2l~YsSRix##20jwU*)k6?@X{_}(?I$~$E_kl$v znoP;bF!O>%M?wYML;|g^s>e0f9DpSfn}ebeO+*#R0?#%L1hFtyAgdcLBia>x^aD_o zAhRQIL7C$~i4()*IdJS&W-Vng$EG+j-9D;xJa&3+x?R3^?k&f48DVgYdqa=$e>|Ym zoK(nhm+T((91j=6Ja}M^U>ESy)CqhXXB19u#~_|A@Zvp3VEek4<)r1eG6YmX=0p!b z@!KKsGPFi)w!{cx9x43nIXVgYC61_B(NjE%Cc5hyG)*-E{uh| zOb#~5!CCE7O7l^(cqGfyKx#o865`>Zuk|k9kqGOXQ#)Mz3d5Xe4`S?Or;)ad7}hxn zu`!^C0VP45;t2Xh&r>H~t=}`HIR1JA^5tRo8uUBmhoqSG5ZWjD*yE}ZeJp4^hjqNf zk7hNXUW#1|M8KDOVz6YnPYy51*hACSHAZ1P9evq*0+3nVo~F)$`&)e|ve2XR zEed}eWPAkEw4QlnHtKvwllR&3Fm>XP^H68a_L&;|Wm9V`x0ikkW;*%LI1aynIzZXXx!D-7bC*WNDVO&6WeS5($ zWhvS>J{Q7Kco*_RIfiRkyQTvXgW+es*L53)OW%rxrO@cBbvBWblw5JPf#}N^Znb^# z>Q0F1N=M3ICZ@Vhjan(}?R`-a0a%Lyy~9Izy@two{f{qVo^pC)-ZQCU$?Ko_ER&IF zcHEtH_BQbzjZoudkXP~=gn>3#S)@0@n*d5z>1}g*(_Ee=M$9L4u20x}@v&?2>d)rP z<+ySdUum)oj%5sHhZ?SS11Ux}FrH$&4gACndEFK7m`WIJJ>#j0M@gPvfw=b=W|$dc zRVG;lO+lPvKYR|YrZ^Llgl@b$w|%f&e|%l$66Nc+q}5!?w>IiN-ri-WXJa9(i>Y6N z$h3>snPKCxsEU>0{Bwg??BK#fvwEu593nu#HAZ{rW*gKMWWU?y%;!GB-DvHm-Bo+% z48>(b{Y+U=4O-&|ABXis33bAZuM6T&vJf%%oUJa<1@Z#d>!Ynu#6g7iVhUZO4r6@U2^&vhJF7g2>oe!FRK}3zuPb+$wz`Srx-E={o^6NaevRjVN0fz!l9Ig=PD zSt+p`@ol>|8{k6>*`w;&B&?lfUTZM^iJhBC4K(v@4~BZj(_2Rf#O=X!cBcgqggy+~$C;zF>W4joh1f*4#0h zYfNTHC1aXkS}*`{083@XR%3+@;S83K8t<18H`a#8Binnff_ZG6whud5!G+#TS_^Oo4$w+)FA? zUkNZHGi$OnDOC#z;s%$Z8N}O42J9_{{+a%KZLuWmn<7iQ3|-r~LNwW-cinncB^SZc z%lBmhxMeDR1Gz4y%1EpD^E!`JUYfb>58^l)-oimt#!vC#!j?dv=7VU zZI!;OG2tL%TNNcJ?a0oTuO%OR9yC#-j*tH1XvnL!40c@iH!i3_pNNYhw%V%1p2+K= zok83#cSXi|+<5`5dXoEfwfZi%Ae2XRAB+ilO@4;r3C`;D76D+=Sn6DFc zwIX!bcy%7uu*~;vR<^1&saTecxVhwWbVcmCKdyy{$dwv_gglhA;f1(M`0IE#_{_d* zTenT@kb`TuZ{9a8G%g{MwD}n1ZoLT@HI~TA@In`1afqP7z}@2U0K*k^fU0qfc?>KH zp_MU@DWof+FC7hVs!TI1s7Ag4bN5#TGVioKHto(q#z`*Y!GMKXwsVZ2OLK0sbGI5# z03o;iKFV(hQ`ekSGhuJi^Y{IMQp#s*UGjKTf_T(P@N@BX)Io^glFs`${44b}3rA#y z8H!)9G+f=wg&#c7`}uc(%Wmp{yZP0tLi>YiKkQ^%^>60gPzcLcISI^?E_O3 zh0{i^ibra?4Q3l~;&Lt23xA_s)|6dZHs%zg56lGFDC&&FC;++7KJs zqF(F7+jrN@4534K_wInUg+jaD-b9sn>mVvJGQv@9Fd12O{Px~r3L`!LtuAFXPkALZ z96Pq(xXzp!p>4Tm9c!LL_X0NF=YFv;E|qdcT}q}#}O)HmW` z+$dmSNWW`n{9z)Ypl(i7EhCAlX3@2ZVzQ=%+#ZAQKbJX}569QJHZQpjUnd{Ax~3ey z)UZvWIO(?~(yq8rrV7#gqP^I=9>{Bca-5lHbu@Beb5b&VOE~D|K#R~H*@-u48!_Q> zV2Rpsfjh>i8i0!rMLG$|g*F?m5R{gd_Y(SUHg z%k6%@Un_{))h4X?LTKz_GuLAIyx!a22dMj*uX4bjqE?rUMw^70`Je;c<@|I5A=U0- zLMZ&YvOr$_B2Q!O3q$S3!_B|i>~bxz9Qa!aviJ`TlmEFYY0qm1O-mu5JGMD5K4^9I zhFbaX{k?-f?Wi_sjBbpM5wCq*SI)R*H<)AxZTR~jz-walBjQVC3vHU|cTCyw^7G_b zLYRt8smf65jcw$k8!zJSB3t&i^RI#G8Er%|v`UmmyR$i1dMABxV)S3i4}0pjV~{>g zT*XxYoMU2yzu792R99m~)-#27ioS?6t1F2kVm7+K$p=5LXgtFyuuKqMSkh^a%M{Ck z2NCcLmDuM=zSDbF2|5LOAt%Va@OZ{`eFq;NIva$^`qjvMP7Pxp@=72V)Noc|&>jsP zLN=?Yvaz8{uBKf)7Ru1UPyr0nJUzc3F`MX-+ez^xN_>LDMxJ`)#5bgn5XO9Vd;$ML zT+xF4kYSSriU08Z1MG*r*KMD4_^*;PRZV6UtIoHdD59)UrO8YUDKH5O56n4Oz!-k9 zZu@4hedFd147?#zfl-ZE^~?o^GeFNiBk~kQW}V2kEI* zRf8~Ghh%yW-9`2;Layn_dsS1Z_u3&;b-^gTL_uKfKND)jfL9HqMq1Ys(?P#t-<&Oj zm_Q}o?}~nrd90D?J01i~aKv_J5=`$}soxQwz`M@D58n~;LKv5@(;P2qz`n-aQQpxa z&|QDxjAjz-=;I2y^dSl)ud|=e2LniylQK(n4qqPvqz~mB5L1XhwLe;BKY04mOl3OG zA?h+)t~T~(&2$=`Ywlh7+VnZsVV!C`yx?l!R7lzHRK%x}NREP+Aa>*S-%t@A{kZ4r ziVV`P`cC)4Z%8~qdy~?Yqz@-TbqR;jUAw)s7`QeO+}%eo=crgQnMb7WMO41h!biuV zlagmiiSxMCz9}6#+LTu{k#&Xy-^7Uk3fi<1M?=@m<4X7hZV zJR~%0!|qTAUQOoe5>1{S1Ajo&m;L!?UtFe!30oq2bwkYDIuR11BHP)r$53PICl86= zCZ4Oth_8fO9d7MFz;x65whLD?C~F@!b)aSI8nt&^3mj7M{q8~pGlDz zJonYe_$wEF3o#w~$z#61uT?sQqVl-V`=x40iMCT)lfsZ=x#Ab2BqXC^7-3Fn&<{8x zpG4vMc%F>G+p!Iz$3d?}4!524PB*J-`zBlU3UCE$_mw~kjU{8Q;gf_n4iSGuUZ0Qqk!g#Je}M#Fu_c#<0#~L zN2=?60e<(Ju+6s5X%PBdo+`jH4SqGV+oxs%rb%Ymj2z*+!gpj!z&j>cq)em~W=@)- zGWGb)Y6D>XH-bmEE*vLBK;`SUDofux@NsMMb!!4}g=^x!JY+pT&b!MqG{AtQRgIL* zEh;g2sFTd-Xh)M@aI-@TQ(>J2!Odd?ZpLucCh$b(Q;7TeVtL>3s%#N{k`Ob4Sg4Dx z6F&9MQy?oe2?=wc2z8>=tUL6Aq4tn#dpqeqjs|?O877&5%IK!nb*U{a3aFB}NMJ1l zuA|~UD;R610gkz87e$U_vGKUef)+4PSORUoF}m}xH800%KGt?oC*qdJ(k62uC4$t> zPE$C(KCNUM9dY=m%wihz+XpO#1B}AMFrEzqLOy48&J|=bG`KA?!pl8pZ3hJ=%!}wY zzFV$rtYTnlo#zc=eg(0}rx1^88dib=)kO6uL6aA-igyFVUlkGE#1;ENL4o>PE)BgL zEp}?it#RG;CBCEVoMv1QI5BO$dv|dqzHYQUy0szRF(G!@J+;WHAZJe~dLNETTCS1k zjaYu##&P~|-)oY_OUcpP6tFbo+WYi%a}F znn^4V=%p4zo=8<(y;Q09n6|#;y%uu2xoLicYb2sXbNE%FS^hD_{nWmST8mt5M%e&C zl8AFyTfA3D6|V^b2d-Gk$`OV{n7YwYIA3O)M7dXbypk zh=AAmmy#l@M2QdP>hktKMsMXUHD_l1!u7CrGf|}EM&AFKt1sWo_0nf$j?n(=Sc(l* zXCR;rj3Aw_3kMXu2I|KwPjocTMpm?~EmyntocdBx=7!?i9x0U%VLRayDD+W%^nI7* zWqV<2alFWKnYM%NK%PciSg-O9sCi-10grNS=XGzjh}#d#gHn_DM#d^;fz;C4EMgd z@KAa|Q9;;*&lrvVm2w9>2ct9yLIzydUBBK}OPr>dlQeT3{psJsU#wWRt0rI#e7==1 z+HID@GHHQ192$tM+beqJz&M`|oYxfVSYw5t_c7e!RJ1RebQZ#VOn@}`HU6v=bs9y{9e6cOAZGr>KRFs|mAljW|>4RX7F%(5M z73OG5!#!7Hl+piQ6QPgV7dv zv6r;GZa=O0YiyXbFS|eUlQL9;OerhvkyKU>-py|i1Qu>KL`}_VD$Ualu!z+uE>SFE zYAto8Ky_f}_PANAdo$&V9e1wNvMPD}+lPp4Rt>-3dR1v22wn3qnz zlh*x158P2;W=|AHc=$)NU?*&2KMMoMB&dDgFc;QQpV6RF0eB3wKAY%AL_A2{s}@n_ zStD`CFgvZ5XzK>q9*?0n^D?Uf!mc)-HyaN%dnm`d1=Gd*Je!NbN3LLzgce82==X$q zvmP7VlbF0MXdA`u9) z6os}oV5=>w&mT_%KNycy6R6g`Nyw%XbCcTg;Ihe$9=3=-0<*!dsMy7SVxXN$sjObr zq#V_R^>%z^e$n$ekaP1zbLI<GITN^_ys%F9SHC=DNkAbSk$$E0K z;IrXLM`m=XC1astdcG+KICmvX@0}z_rc6eP@HDi!fDElfu;Goks)t1)(b3cI>R0o_ zhRdSp1_TQ?O*p|K-yAzY_&VtE6$br`-Il{4ABj0fd0d^AB2`J{fS3h?7ar{i>T{4z zp{mX(OloMjH@hjEGb;_22C?2rJF>f4u_4hpzp6NXp~djpB)rvF)q;7pi*;Y6^PFaV71T~H&A|^f_NwAw^ zcixla#JfEz=PLl?`?2SiLlI~3gY)y7k@5E{=>6I_qJr*GJ+PGthH{@fqOKh(nj=hp z_Px2#$XLVe*K&InL-X3%!yGEYCK(Ge1!WiqDlwyt z7R(!1f^L*Te+$y_1f5t$g>>+#5S-!YysHP!UfjsQ<7DYcWYaip zED`b8Uh*>V3?s~L`w%|hHs{Nt)1!swkW8Z;oZWZ(cU4@dxn(;xJuM=h69K&iE{}@a zTgCqmMnJj0cqp5%cAUM^&x&A+dcbK2WPOVNkzM9NQCxW(cO1LhEmOpzZ35F()5c^s zmSWTrjkpGth$k|GC*W`>ryLFn%y8;x06At5K`s#(5#?q;Zh{QbgVQ<^1tqN)o7tBaz6#-JcO`|Sn$LEiIU>93TYr5t zPh+NA@5>lIkWzV{L zm$dy1MD9^wHY72YAPH*0bk(7NF^jF z1^4i}wHW~QeGf5AZFV4_W)*rvZIu#RsKJ{As-sMfs0Og#Y#%VKc?|kVx(Q17Zy99% zsU=#?(c$Zhcec2T4@n5RsXC~khX}1|R5h_!?~fnAma${EWKCRsuh&()q0rYO%bi8k z)JIIBnmAsiYOEJMY4`uZMmeqcLpWnQ|*(I=w%h!}sL6B2g$)^3=c#Gz1dV}7Z(T+Y#LNVt2$ny(}i zZ^ZP8M>TKWiXjwnOiya{xRL!^q18SdetxP!nW9|re&LYm$P+L%X8z!8q-~}pmQk>% zq4QpEz2}z5GcoZe#dO|od4RiRBXn^jgN0>N5?rNhC?n&)}Vi6iqo{ zn$LL&FWS{>`fixkf*mhmXb)cGKrM66JaDIy(4Yy@BpaR^1iY$WSj&Hgn_4Gyv>(bS zlOSZL0LkF?Vg9d5(-9-Y80l92i!o+bdR0gRn{!T`lEKjvY5jzsMy2f#!EaXRIz_ie zB}B!a5PL-(I^@XO1oVz^aLsB;P1&5?oDn2`K%S~idfFi}P(Iqas7CfqOLI*DXQJbm z48Y1JU!5uZsS}76`d%q+dEJai*$GNx69vDbB1Qp4#Mh(@iQ<%Tp|Qs;lE~QN_<}gC z3@psokxEoVw3BpG23Qg5BK4IbQ3`o3Bt0Ni(TbLvcag2IG`%RjJngbY3aLJtd`zv# zKvw1^PhxT21H&+!95$UW^7DSATNA;+JR<36WWcwHZ){8KW5MiAWnUlH*H`%zgd!07 zJ&@?ddg;m%G@spKA9s2`hZ@#W@Y)P*0|l8{Sa}wEx&5=nXf^g7hc7-yQvU#TN|+d8 zVH++qo0Ii!3V7WGvYupRkLzWd2cW>X&kBK_HyDgpF!b5|_S~ns)zcjCkZND7g?c^a_ zyOFb(5+>Qn2FNf7ARkwre13>Q2arMn3MA{t?*fGZDc}Hw8m7);FUZCf@qktVONSwQ z2<9sVcPAmFKGNh~c!p!N_*ZS7I5WAj2TabqE1V;*+KBuPtXE_JW(~y(! zQC40?URI%nhD=f>D#Ao2**XwDGdu&K021E{p^g89sVKNyR-q^i3VbTG99CJy{%&oYfW1I4hhsgFt`fzgBViFtMJCx39F7TM|E^n_3nNi{hXCk_= z;Y2I@O0Vzb=n!d}cg?$82BxJTmgrkG3P0od2AW4yo-o`yId8 zwD0D~ozCtN4kzhT20<;KEv$v>AHwsHYJevUpi&BO>8pMwgaSRYPCEW-y!PF1Z53h1 zFL6bI=RNI3X!f43SBcS5-id)l1DJ$I$w7<61VZQSn}%B<3e8@D%i+?OOW_lk3-j)S zLlQR{-5=Z~K5B69+}rf_y1AkeEpYHCb1pu3$-;YYbwstYG|U3c-HTI-R`H)>@d^g~ zksRUC=nnoMpZ;oWL;-k)hkGNMv4Z^H#Fu?kjd>oxCwZRAoXu{}JdJvG?t@4XmQ1tl z%G~ujMw89XLZjnUL4-)Bdt& zzxUos*J?%wXHI`~&hP$y-?!)UeZv6f2w#?gs3b%R)?kB)HwZ@X_>yK5*Dp(+&sk2GMrh0G zzk*>=N&LRUd_(~i9_%Ia;Knbi{MQd9=UWv=!Zs!G#@Sd@y|2Kv8!^%|U}SPYxWL>J zCWALyOT4KTnyl@xqlVMuJ6tAyqOXBBwdV?Z8Rk<=Tar9MzU!!A9KFkPmq)VeW!xy7 zh2!ivVno%_z|Fqz2^`d%6d*<)2KHH0Dy%nDY!?*P>8lwjv5kquv zJQ(V@Reawz+!yl9?Zt&27b@h1Cq+#2Nw1?$qUe?A zagZPW;ujj^=NFoJ0Ds9&&CC(?wxYU1T44fTDPX+fEzBTOg;{LYwjHS{Tyj$6hP^!V zgDhju#&k}Rk%!yj5_)x1DA*x>mUqaNwQ`Q?EK(`oiJF5yWti{rpaI-UMC-VJ*9u; z=`vwEI|5;^r7P92U+RIqM~0%^r2fvr`>Oj)OW$&s=OkIM?#9{QKO{H+aX!=wXFq?5 z<}ACHXGg&BSIj$yo&kfb*3#qDtdh2L3636Tv>~a-aruSaoen#LEijfHj}fS$;Ujef zdhXG>_Z(n!@7zXrm0EYZ9#prRgxrt06N}Eie8fB@oZ^>!^Y`oVtxL{Xt!FP~kiVma z8c({it}X`XaT4Lu^Df@&8%`ncB}EO4ix?)Fg4}>vA%=lbx4v%_ZHvvDT0BJ|HpAv} zk5YBm*^|RGlPDe@XCFU76cxSts%Oo@n`Y!&Xr*jk*wHY%!!pLiQ#hi?FAPn}HPaJ@S5nxpdX4o_sp%7Lh zriNNfF$CR;=y$Ei8&usw0*PHdkphhdd<*pj7=4Phh-KcYTtV`F!Ux2G2Q4$v4!`6fiwZe&7AL%Xp=x0>m+r(5A z<+4HfHKA1;*xvZ*$ph!pgg(xX%XiPIG%q=Py7@w}G$KR9DOU)b`CQjUQZ_D1Y`+%jo={?KC$hzFd)`*W{;Zi#U&Uc5-beB^_B9{ zEs5^8q#?Qm=;d&s6^ZqyPL+ON)t0Ja9>1|v=D*jlKBXaSl8k_^`h=r|lj;9K*`-EZ zp89EdT6g{Gs>E)ZI#-5*K%&xzYEw9B021M2%8DLMoB|gFyN0@&MbQ$4R32Dn15QJ% zXjs)bgd&9otsNJ2>VQ_%c^s)kZIP;7ZA?qQ#4%4jJC^mDq`KYjJxOWY$Nck+Q3?k% zZSjyG(?4V?$dsMG+eQn9LJ?Koxp*qv+iK7`sPi}l$2&%`kMYAyqaA0eDY{BcrJtxN zvXoW%NFe3{7+0MJ3zNetaBF1N3-+d)bED)%<}ll!ZDl*La&lf9=pjmTrZVyryNkI8 z3DZ3I4F+Uxti>E+WX_b$I63qF)l+!|S)y$;vwnvYwH`iWnX<^J4O=5c?&~}}9Jys) zS!Y{8FZJgr-bI+l+7b(@k_Kb2_>GLfIb$9>7Ol8USKLE*D{QE0ddw^4)ICCL);#?2 z!PkvUxU9bxmCAHX3YT@;R4VJkDCWcmWERvT{`<4CCHSp_gZ%^2gEaNG=PU%z((vpz zirYGj8yI8YF4B`;30Kh(&@VtcQp(y(BhVCazikog8YAwpM%-7#PRVTH7<=|uVR^Zy ze6FLXo67>Z$9X>b2uX~ww%pUf58`OKpgaV5#=31-Ij8?M0QO0cLz%=8LwLqemz;0_Wtc4yq~ zJ?2erz>|q&*r&vRSQ5)7Yp}jip0Ybf6kbWK^YM~7a<-qB!iQ0OY$bbPM`1$~_hA2| ze?;@23syR1;QeSJR;b42b$Q;S53{`B_BPCN-$thO9jL_pVL9ZzVG_S5ucOdwO_o;D zwrXd|qjZT7D*X|aD6zwRYAS@bj;TI27O#h!fWbUS=AH6E7}-#-GBDTB=BLh zD*6F-yY4s4)5Svd8wQ~dwU($B25U-<#tDDC^%tc~3Inv+t5j{q>{a}a^(qZ&D$Bw} z;mbp(DoybWVluurwvO7>E^Q;&iqL4;f{G9qaA-%_L}fPw0)#CfA|MKbsK~yFh!BTG zKpSbuh>QqfX%GRqzOaoYQWJu8w@F z$r22~b9zs<$lmv40`pf6)g|+Yk9yyeO_tMo(nHq9&S}#Y@Cn=)(uETC7!UCmE=Q(l z#mg^Y9?S;)`(OpjR=h+E6Tg-Bx@yrnq+_#Tt%>b}e~;8Yf6bIa=Cn$DikO}_=8R>V z2(Iz{lO*i>pp&z_{7Hev4f#VQ?0Qg39V58U#SLH4pyed~NL&#-_kGtCD}U z`0|gn^3cd^I`1x#an$+3_ku+>+s$`Y?NfO(t>VG}7rvX1*LJ7NCf=_V&ME;KfRJ{aoiDioOc-5FsZ z*BD(Tk;Sk}-{boFihTMM-b#`;5cfH8nGmLD4z zb0V4!I^g3W4i*Lah6l#vZ8XYDs!p#iZ~n1*um#rR3)Tyxm7Fip-y@Gi9g6nFcZOrd zk>#>03!%aYtigTy?4G5SQ0Fxk@Dt~{`FO@Iznrc8cGUO%AYXN|6P|aqVa8eP0^KY_ zc0nh)dWw@*m{X8b1l~|)l&B!aiOrB6&j}O-1xQ5550x9iarVT_23N;)x=5h86Cyhe z22|`HhN-%EXy!e_!lP!As*A0uk8crx;lIjST9}rWvL~R+2i+t6b_!Y{TwRRx1zT*6 zM>{a6`Wq5{HAL1R;UwpmCDjVRW@s5Q!DprI(#1&V>6LgokcJqrCb_+6iv&C+MH2Sz zo0CBXeGlQ6hm;(?HiRmY>V;YH1F?hj>BO>4wH7xl=YubL8ME2V-7Iu|mK6bWvs-&% z5r0g79g>rupIUcjH65Se)p4-Pv41}DhG)cb4kdqUN^*O0C7|ei)wC1#8r)YwznU5y z(`UuJrd=d801J#sY7{L%{o0o`+Lv8BZ;gvppn!g)P_tsv_|H7l{|fp!ToW9ty9xYz zbii4y%f_;!yq@tB8^HznBmJGAkGj>+4f;(;AN)z~;uVrH-%bO#sXjbH4YnYXM|FU- z2$o?Zt>nKkZ(DMfK21`C?Int)UcPE$Gt#lzd^E_5&Jq%7g-!X5g4XMY_iQk>MTCes zzk@heR*{k`pgNu7DH4~E-**uOiCIW0>JlkvHJ#u6}`SRC-i z05Yue|5_G;$(3$@*$_%+en-4Xf7F4+0O<$I!@!i?VR9jvpf?eEfDO^O1k4syZu9hx z3KP*s!vX`t{q^EuG1zmcQ3bNc71a|h_Ukb^!)X5mt)BvOhy_uZys zplEm0;_ChfTguBgUw>7}mxmNd&(hnaL}vJfzyQ8`kiRsTrdk!_cX%JYLX}Qc0VPNM z1h$PpDs`Sd)`ce4gr`IXz>p>Z1k$s#?nR`vy>dCZE7iGBM2mAvBdP>tMae0d%!xK4 zP9}{D5PUB!Yi34XG=2djX8jcsO2$6xFo5hq*CDE-2D$SfJR3g4hqxhMZF76oggsjd ztLxhMKU+60*=Fl6K165jB+?4%3hM=TE4}t^GI#rvKa*xdoGB_zxrEL6q{2~%R-q^# z_c(@oQP$%k88gMbt%7P5Rogda%A=yUBv zid2;1C2(_!@bY9_4~Fir;s+q7Tx@~9?AskV*~gEk(OIp;nJ`hRpTOQt>gUI}yN3#` z_@P$T?c*jY9MoytgycflM9$S6c3s{%nyk)huvb&CjFn!`0REq+Q5dXaNnu6s~va51W*SR z)ef)5ta;Q(N|@(4FTtJzAwJ$XZTJowe&mN~2_@oaM7Up~9G2(B9?PKL&Q*RzTh>YJFN=9ubyH7b=M?e}@YPuymGM>9lZ2uI*IW*K1veX+%s0!pczfNH1za z8xNVQR-4w0it_i`d{mlApyutJivj_o7?;q{Gy@14w$_FtAjlFB z2+AUgC|k4Tz(E=j5OK)~Cwjcac{pbt^JC7*uQ~Oje!N#-z5DL{?)Tk<(r|X_-$MG& zsol9^AfQ@P{}iK;N>Ky*<@!Eige(u~nS@3cRh?oN`3@TC8l$x+nnMwp&(Ip6 z82Cbk)iD;1+F*aTVHJH8#CLnzz;#%AaMog;;`#WO^qG@~5`7u!olii?&&Ro#%EYGg z-9o6nOHw>)B6BkSl`Z;7S|Gj3LSq}MBJ(=sEtM6*+FQ*f_n4O3XHJ)K@&TgY+e1ZO zjD>5IuRnM6NR;@jqtGSbA({St`stKQ8J8}J4g@|XFWZ-i>w|^jw$aEbW}xHRwVRw~ z1$F_UN*JEVNUX1$t}TA14Y94Wt&}Pi`f;h>tF3Ns4zKYRhn)xtstLQ#rPtB1$;H)l2c+hYCN?I;_1&#i3t+^@r>~PkVKE7P-2lp$;)Ph9*MsDU`9MAhar?G zR?-9DN8q98YGZz5UV|``%nQjoT5xy(`RZ!InN&ISl)yu|dJSygqhYtdSw|M4o`(a0J$ZTF0c4{fcxFn+6#%+b!xJ9pEly|Cp020ylvyQz~Qm zuu?irB1vOcLdY~pri{a$?Q&Lbb~fA7{iOamGxy}UxSPwqn04U?k*06zATJzLZ3?mL=;WI?SRnoNd z!hWoNRdb%tsiYz!nrb|!=s4HG00Vy+2f>Wf9qW9IO|>ZHZEZ@?Q~UN!F7ELOk^l8) zrFX8kGyM%QJ|2!IwqD?pB$;l6^om@nV5r6yJt6LPjtBLFgL5v&ahjIK31Be@cP3Zk z>s3(`d}13tXu^N8MS!YSJ|hl53$jpwg}`EvMu$m>jGz|55CTgoN~#O1)@7v=X^|OG z;n)G_A))f?1Q_TC!%=M*n5U9z4X}ouD{DF5%z(ikQ}Ah1N@G+7=i6>}Ww)df40R!j z%pWCC1L=nv;G^8hvpJRsk?fq4tfqVFAe8sQm;LIkbC5f$!8`DO z(CES$vygsaZ`*spUu*Pg`(>}lBC*s&NQUT=4SKyp4L^dnm(U!hLQ`Nbp zWtd#Wb&3{d?5@AX7LTvJR>u|N1YR+wUc~Ea@CMjmt?1f8yM**b8}TEvKxd zSLMmaU@pY0@8!?;XgAKe%|MjO`8hQYuVIX)CPr@6GG7{F__%MBQz5k63E{ z;>vm2=3r}oSIaL0*SUrG_F#7r-sgZX1PS{=?=jp^syEF+&a8$C32C@^84R$$j23~h z@htY=np?J^zoNCz9F~+_x2omXJIA0;Hk%{c3qo*!AllWt>BY;wmPf-6y|%|)JoUpF zE;Q+2ls}^hXD@UfPk_iyRVVD|)V?tc*2ADb1U5rdM=H4Uztg4;c1VXqf0qusPBBkM zm9PP{_79tI5?}h!br);XI1ewM$Uc>nQ&skNvDDer$(4sRyj@l!z9P}P4{8MO#Ou?h z_I4P8!=OlK#C2+V6=!ubXn75ruxS`e;bOhIY#Qq!_KE17maeXNqu92C!K zK*6%X|LxY7oalu{J+up12I+0L@_P+7;CTP#1TKI)%~Q_$y=TFo@}GrZa|`GX?E;2pqZY>>F4sTJ(C2Htuoz_Sj*z+=D2q zyi?i3yt(P=Vqj~IEYS{bpEKcu$-ORh1TGIi$cQ#{%)2a5i#gSFLRH_%F$T7&7Tzwn z_E;5inF4BQvZC?9plDJ&j_7^PadBa6sT(0LZ^Ip9s``-MKP|)ExIh;yDT_0z5ECiq zBRye{K4v_`WrgvarWMuz#~~P;>v>ZYxV17q$DgoEKG!=@L4~_XRTL)Ii4q{=QVi4WtK*LWH9O{WTh2Zbqwg- z-)}DEb~*U$_VSe%#;~WHiNu>di6abrzVr$xRnYx_3a<2MKz;xd|Gh+Vnkxe<0;Hs- zQ>qfW2f$=py>=E97~5=FpH4ZI{$ng>an3&6$5-g)c4#yDOoVI}kQ#8nOuQb>!_g=ou4IlV1#^1XyB%(|ML$F`Q??$ zS+>Pl{&h@U%5T+>;!x~hL?S@9Rz|UoK`lQ|bPI4%_3^iRwd~BpG4Y-+~xR%_f7B7FjksIQ1ez{fnp2M7L_HeXEXcg z-2vSLGVXC>+xT^MF0SjCwaD2&&>GWT%HO8{LwmgkHFc!{04JN?o3vfoDc7`cZ|B}W z>Z?|K>=s9;gO6QxLFG*h@0Wm59svmf0unT^5E5(=LLiWY_ZxhG29gK{1VJ7?@X?Cc zqE=^hrhA39&i-@fW^!+G&iTG`e&6?XtN$La@F?GOxa|Ww$MM0F z#%a>lE%zF5nFOXuR`(pJxXXT+%hSu76m4HzI(o6iY~o%RHGU61!hwr3uwfh+hu<wcmla$NL*jcag6-UCD)wV>9o5_j-n%U67l9nA)2f zlITTj3LKibKQM9a|6L~iZ~XFM+}2*T?#>RlJLzBjtncTmE8T&|ZK&^B)RzAbeDA~E z842-q<0Qw+3sQc8?=lzneZp9>4&vKku02DH8J^?2as?H*fG__QdvDA^ds9aj?5!Di zZZG%E_AYbV`NCckwD&^yg1wGE+pE?oYF@XO|FXR|toG*pclPpMp%*}UzxvnoIu|y- zOs@da%X&_)E?xC1z5EyS4&JpwL+`fId-x!;>`nA8+a`#KO@5u;J&@j#1$wnzwY|g@ zE4?1Uo(uE0$~#Gaz@`JO@_w)tnE#Eu{O9r-t@6gtF33Covb>uonYZ37@3-3l_6B*+ zEXd3MkLBh6Q(p6&wHCQ+l~+~@gYrV&cbP@6$(zKyv-~A_eW1MKFXYX&${TEzm+u0W z?7RSe8r=<++C9Ew8WIc*+`~G6(S>)5^RQyz{1`qSa%y=S>C~KB-Gv|PsXJ>lNV03m zx)B8XJf$L3X!Za=cH>E(dOJCwFx8cb~VFn)J?aOie-yG*L1G$Tl#7CkY9nNNEUnXV4H@cu<~`i{~k13MuIuIEI!6*F>}= zaD$BFq6y;sKy_s;%s1xkN$|}%5O|RVGN0M_Np09*G3eyoN5#z6oFxbRJ>(8)ij3mS zqmo_rhcr#Hb^^R3@4j0Jcs0P?9xOh`EJ90$k*h~r#-|9qCO^NDs=9!bWTzZWAQ)T` z%5Za58Y|E8aliG1aEs7}*AQ+D8MusCkl6EAGa`J=ZKSGPM6j@m~KQhEE zi41`8D*_t=O(P~dka7zaFhlQSLcjs5P0Z>M>lNdGPeDGi7G1}zk|bpbr6~>tXl~uX zI!ViVu-e`cg-uvK!YmF1j-HGoyrS4Kh68`LIt{oEgQdf)v-CzbhyZCkEm(@oqZ!On zgdvy=xGJv5U(r;?6&Zn>-WB=tuoGGhANg+B8Px-4#0wQM&d5h-&5Qe0Uf-hW@b$G` zx8P@2#Fix4wn;sYt3#fR7 zFxG>J-m58-P#FP8R?X=gBk{waWt76Y&Cw_PN=R7g8H`oU?I&?lY_C&bcxDznbQvk# zV+L-+ED$lt25|7a9|q07K(>*?Y-5y2B=BC!0ju6(-bLk#Ik2d_x~!_a&Os?hzeAj|oMS89zi>sa4hzGi`ApLE%ZE(fi9wGpXzVM5^n~ zIYm4e8@gdi>4>kQG|6#a#t{c|i{ytX^=$;Kfs1&=8YUNGgcvLtu&bQ_tEMm$&^`T% zmzyn@ODNyGkc|ENxslOA&n@`JmhBI2o*TVRVl&qR%)ciwQ$(CtlupUfvJpf7O%+#J zQ7KmuD;X1ypJX^oVKb%5lHxDPdUd0&mFR1Z3#2epP-1KZT#TNlS_?}HG;A%Lh9B^g zbC^xc9C8^2o51(TDOjf-rQQ30vluw_+0{+*$H04I{3+}a`0VM|ysf_ByY}nideW&v z4mKYwPK*n}{f&Zqv%|ep#<=#-Dr*ED8Fba19k?mV=uBes1s zyt=5W_{@>Ms`ggy$z#nUv-rb+OY1gx@7%o29B}zWOJ$v&RLEsf841ZEht%{0X?%gC zFsn$a;LZaRZ=fc`=a4+FAfHM*m?DWI!i4QTrk1X5%JwG#?S7A?zr!Af|I%2cZD`2U zCMTz-Cnr~@H(0-Z#u7)7c_%g^6X`SlHHOpt}UabKLjk$ z_{6SzyvYz@Xq&*M!4CRE-g(Z1s?%V^E%B{?tcSDq)r-}Qcui$pZ+BC+OigM`8D&Xj zF$#ylP%n<>q1Y$^?tel!kwW%m>N6AZ1YuePiA~4GsbD9PDX7glEq`l z@BbsKYjUWU4I=3sykSn0qP|pJBJH!!%Sw~Q69JJOqk~=DgDqN_OiiiHNQor1o1wRYwhy+)P|x>RFwByQps=~fnL^IT=hp?%CUN-bsH;Cw4~$KM!<(FiJWOC3lL~oYslLThy*4V<>*fVmDifBf^Um$+ zPAt{RQK^tSmg$UDD&%f2RV|ikh?5Gro1wmomkO8INp-Q?e1+-^KaHhIipNr|6BU(J zmvT}?TcldR$ox2|kViYb(F`J+Q@5L79!cE8PL)`kQZpfAPTj^%tr>Nyq`>CXF5W3q zM1y><Om-GLO{yR?evX51qWZ?^MVXAT$X%Q&8*gE*V;mYx7Vt4(;>eMZUJTRb*l6|E zn7?r_mDN(!R+!M+9XBydZ8n(D+dND;rhhoV)X%}RkcX+5gGr2Giiu0GxTHvQ< zsSUdn60ke-@7SfpQI}e(>n$!J58fqwGV})yR_eExVwbilRi%j*mr#ryN+^m$>HL24 zLJfzKEIE`z2?c>*OHV1p@55gtg% zF-&Uu)VA{E%~qK56;XvHYKC}kd!UF|xl`AW(jX=B{WzYGC+2C@C{M_f<0+?duOmp_a5jOH@n1YnTrFo4+CbK|Vw;>Pa2~U1-Zbiu*d~9@CMb5W35uV~ zCieR?_&+G7DHOb+jO1V<${lHfvN4))$qUc~#T-ppiQs0#X`qSyh7VEW;56`boN$P; z_{4{($9-Z&;{kP<(p?mxk-JN9PXf3jJ3o@N%5IGP0| zuh1+g=FP$$s{ zkAB|D3*E|Mrj_&P%QmQG8Ep= zn^u(Yy2nRJ^LU72ng3&m(mHyieT5upc#SmUVzk)KBA@Xn+WVM9fv*sv-SC@06PC!8 zlZa@7u-zn)WV6VbXi7aL`js3JNe&)KLV9|et4`O_d1BnKEWKXYDE;C3O?V4FLKDCREkY_Z9W6#-NDd5| z1hX%86;zoS7xq19?-f-4yg*nDh+O{jf?kQsY|9WUE_t zAk~TJhuP`m4mM7-M7(n(PDI>j9bQC6s^UJ2tWeh0>GZYr@rNVv*_;j2+20DPSfLPh zuzN`_F`9~GfFJm9A_`<8FoA5GVOyt;>wE{kA(0!t_@x-!K!)%`(eW>`2611R-{+xDDy$%X}Z*$Abx-OMo(p4Y+fwah@X^{A}zuzleS;Q zgG;OWQwE7!un+!=f6u(K(;Dh1eV!rDfal|$^wjsu8sDcA<)z}DjPlKLDqgEjSJT8j zty-&6Qoe@hlc{uuWPM8PCSNKpPnD;_jk)SPbvzZI-m)Tt-Yzc}51p(3QLi;<^$hOA zFAh`2{4Xx^3mN{{EEvMSBBhH+Gm;E{3=%W){iQ*|U-a%20Cfqc(oN(_ko@9}By#W_ zKE_@BaJWm*_fH|L9#)aE4}1`ri2|L`>Pu+yx!H8T*y~3*5U`knPdk7dxJz3*;LiiX zn;(*W*Du0k2&5p;2T0!`dWrZe_fAA09}4-%5$QD(D=`TS;3_x?zZ2dE16fz0uVd;n z@%LXEsZuH!MP{Y4R_aoe)#G|$Xbu}rl(YJ~J|txI(1ZipNI1wvpWt%jDaw$HxT0Ai9|;>a(^h@AH^2ANnfzW? z9os@AvDNImWSnYU^jhhfsPdxC3=voqrO^3FW&Yt2(M;_IkwM>dq*>Zlvo)ofA=sV9 zhWH-o*`9_*BNL6@A-Aa3Z4QwJZ8}uQwH8My4*5x!`b9*BjfTv+N(4usw)eJ>AcriW3`dzL((sK4@F#}6&EJ0Gio$Oa1;hm2{?!o z6%bTh5TOZ+?E9u2KxC6$kR3r0R0#WSBTZ0r5M)4{Q34aqd7TSYa~qAyRK~Gtoa!H4 z)%Tq9eSPlv?l~t8v>SnKRJ+8-3HWNzrW;YZa1dAm3>%Ry*$X0K8@U0A2-Iu>>EtTJ z5@?$VEFjn6-`dC?d@cfAP;Z3IjcNrge0Ga~F9vmbuvOkWVA?GCgZa)~ySU2TW({93 zdWHt;K5P8b{d?85H*RpdD{D-`~Ipz8?L1I>a{xNTH%3RR<`^9%ps&{X;*Zk zqPX;WeW`_A31?%w$8rZFGIqGhD>~H5`ON~}5$@1v8vtQIqOAyEE8+<``3!!d(HxWz z>>uPC?Ehg186pde4wj+0kgSDkBQfesRCL6*c$SLvi}H;Mz)kc#`lLzO-kX zu%J?mwz5p-5b0^CyOI&*^4$ux@jeLd6Y%4F zH?5c$*)%e_yid6tf~UTOB9~>uD}Me|BbUEI?d5xvH|eb;m4b{XWr5Ctj=^p?i$Tf$ z>3%6_7K~~kc6+kb_qm`qv5{ycMH^Ns_=jB@(R{>&H@r{v^RX*2#7B`rI0cmiPTC2$ zN<_hU*Tgbl4u1VPYAU{APST7Ww$hPK!yT_p%l*O4B@w~NV7&rDb`-shnb)u z2CZJ03-duofjBe^F$UUe&G6J`250a!Mq$H_+V)Xk#bAJ&?mT3Iwjc(7%#dc=q7E}Q z2v3+u*MJlqOL5`#hEkWnHbsZvtY5=u2SnpHnfO7 zD$UALo#iBDUCcdy!a;R*M0(;dOF3)9)`{=vfV_~>GBIowKDHY}i;cItIa;&lw-c%P z73a#C(bzAoIUgZ13D+^ilND8_t$*F%iM%SmIE#%WaR`|)aSB$`_`o;BC)k(W?`dsq z#QeoJtL_n~CH^CX6J_Ip-u@k(*LN%qP(|lM-Tx z>;!uv=_cI{76kP;t~9nZ=8}2@8DkS;9shMZGS@=Rd_HX&QE1iA3=~&1gmb${$3WMU zmW-uaW?H~Btlpac70Z!7jn@yq8lfl~?W>1%FGFkae{7{515!%pY0n?4#hXDvn5R!wikW zhg1`vIZV6Rf8}k?pf$^$!S6x;=@_i4t?+Ws$AAxF@` z1Lcmtwk9Ox;#PnbDJ$vaXohNg?p`i1!#y)ECgnUzXLLWXxdq^LtjUQeCS1uTX4Y2;FaaeP+{FHkk zNA;;HXY|}rmk&!?)AUm2l`sWif3MQMl*VZX=L; zokHJ~JpLaX;xGr5TyBxAFXW;ibyRYB4PB)d*Umfd9{dVAO*ch#^4s# z(KGSnNwM_-S6lySmoPM?TB9eA`l+F}W6`Z*@xxoNkSY!63+J(nrRm3>SD{n(wCoSp zOY2qW>J_lOBDSA;u<`8}+}fz3@NnZ>aJYf@(X2>WVgeH%=j)TqQGc)YPEGPlVJcGd zTS7T2@^FZ+zdPgM9v$t@;gGQ|Zqd%nUdR2$;had0`=PuC3Z%7DvW4D3K@aX)ladD@ zhh8KfR7&(v0qTVUAs!h&p>99_r-~K@k??AZAe7((t7vuUzL~?cb8Zq57@u7_zp`@gJ^TC4 zK4iL>8P@pvqP!@0OzLd2|mY{?wvM^VZQiejBRi_^__$^BjBCHNOzz zZbOnj0phMci}&IOkD00vkO%`u%emHeGMmiL=w>6O?mbZ(?Lx#JHl^`k+(e-g-wy(3 zuAM84rq^nM8vHI}0W?{Vw@B$kR^t59r{>rk7%N02V1gT{3p5OZ zO9j_+TlX{(qY*oK8>Y676XHBB%P1%M)k|X>&{lG;@g51XK(D{GIKjR>7Y8d5MZbo(n&u3YR&g z*-7whEWuK|dUU?^=><}|i4;)q0TUZb`JPmK*C>V&4e%Ejed17vtbkQ7VYbkPi+0*C z5~Ex^b{b~zh{f)y`@LA0rSs|2*H(~eSaJc9stZ8Kx0lFveSa-!p_`&rt1_(8Cnr1X zPztZmVcDTo!JVNRpJPkYgj)o)drzP35T8^YU7g1kxhzPvk}R;@9I;Z`ZqFp{%1b;X zxfXlg!$v%P;TKk{HR;2gH-QxzN>$hgmVSk>!vOj@DP!^W;1lo%n#xy#e!N@rRJ}G~ zV;y&_&P&k@Li5vF@a;fVhw_;~Rjsm00uz6{a<9wb6sC_ztyHf2&x?;1p1M|1qS%nh zqWrx?C{?BUI;PB#;J0k1y*>8gA{gKjWo3KLsJ(MMlB78$6uh2M-gHH5*bdu&JH7Hizp^~Muk+~VbB%rVAvi(4 zttst5&CdsYoQH0HHZ;6}o1Z$|C+(JVHyd~d3C>zma29E~o8a2e9W@hN=$~LfKM!lX zzJ^uiWXa-M)YflR;D63DsKyAY;6YIvxqGOFS3U&TQ|V5CD@oJ)x1ze-q)`hETGK`% z`MO64u*bcRfQ32iA-SZ-z$65}_4!jU3BF|PJX{^6==Ws@-M&AgEO1C8bhG0oQG-StV5k~s2Gg*u>YEZAF&p<#8m1%-|Ujwh4sZdg{VN-2^5#V{dkjVvnC+aFBn%?m+&0U5G`T zqS;ml-u1TU2?6t1T?{(hAwrGt8bnawM(1Jj(^!w=Xmr>YA}QEZhZE@l@TTBkefNhn zt{}&TszCu2OglIxt5S+~9_SAZq%%CF?F&m>JSl2K&H(SXHkDT&OFiHI-Mv6VTxs094 zPTP3=L<75&M#sFOgFT%j=!ol@yy8e{Z(di+jilDUD5k%8zXwSV1)jk4N?99fxx%r`W5IYR7G2h(Nw?5R4pfMr?{Y`+=S99{Ir&Mcd)Tm} zROI@wD5b{YKAfiC<+SY zfb2BgfDJSng=Scy5Vn?G*#u;V0^Ar-WEa|9Kxo_(A!hVz>M~Pv8=i(%V`?nsXII^K z&bjwH-|6pD7V*@{;_Ql)bdEZ4gxr5jQC9QZr62)S(p2wnNHs)ZkX#2ds(R}63fo~$ zt3EVA8Xcak$jM=zhpPs@GX zLhRTjUv$Crk#oJEUsos(&EV5Ji9|n#q;FXC;X*VGEk>sIO<_^nNo8Udj|@gv(B{aP zXd%H6jESiMou$d6?_o4+a+4XJt2W&y){+m%uS9)ZUE@aDC%6=!mA6)9=#3gQ|WQ5acY#b|m(=3}vRaAasi zC`TQ)-m}?x6Kl5R#!pYqT)*93=U|(}$H=2(at2mGD4mjcs^k(=7?>BBz^%vojV#&M zm)Rlp+!MeVt_2rWX3h8Dx( zE2ovo1)Qvf2zGOkuV>9asfRx(_^1}T`A}K!5c@EDxosqmVl{Jh65xrD01t%(c*fkI zEu@xLe+p>LAbH$1HsnTK*F2-Uge%+MJA8Rc=+K{_=xL$7JpFN@GyL)=-R*Yc)Ljkj zgC|0Ktwc^|VUECo86J1_VG0_}!IN@8crYuGCgoK$)R!IR<6|-pr5uvAyrY8*cgdG& zSvX`0CO^deBPyPY6zvx8*ly3*9rrwwpBJahAN}q zwS-SuYj6|W+?iZm%hy(Bc7i?wMI!3*+32$9V(xuZK+6K zKiA#gTIKYul8X(E3Xw6`cJJ!g?tx&tJA&;diyndng5t8D>#>6t-YOKI7kh{?NK{=L&O@-zcTLW-svG+OA-;75|oj}l$WGc9K>5k z6WT;m!&7pd{#RXR_=W4}s@8jiRgVmJ4^q7oPyExAXzKmnG@+SL_>wl&QTj&HS0n4s zVzv2ou%tG8kh(Z;Lh-G6QzH4|yjN+yHSYz{lsW@_4LNjfbR1s%5)<}^rsH#;%G1;K zW@Z$NJ z|Maspqi+i_hkiybXWd|LNoIVr!?PVH0#XA7K^9~WU$x8&x@0Y|1RGdVE}VRJB0a!avx6x zN{n-%gESkTQOF6|ky1U?;H7STSdIsX<^Q%H1RJvE1Xv;&@q|RKPzoDi3o)NW?;*?J zpdd+T5Z;asj|I@@V>|LMGRFdPrAeH1Fp(Op6pNXiyQI$hIYTszmn?f}J>E}nHM_7| zM(wcyMsC0&dKumQOZ>fj(*1IIv=*u9aYRFi#ZP6~BbN?6`25}opW5?7sE zUfsZU6xpukQPlvP5-DSpv58z&N?FMXw!6r78IN)Xpi~4_W|iw4c8B_Va#C4LClQBD^cGxk{4tHNZVoo%rAZffOZ)kh6TB|2EfvZoc zsc6DIX@h(6m>McY@Ue0ET1(q)4t|`1r0Ne`CssY>P+*S9llK%thk@P8=kF=x`0V$d zNJ}uIyH-u9UYEjj>;ip0rlUZ`6h3p5OzH239TlK;l&id5Go!ub>G)E6i@E^?nte24 z=9{6vprs>A;B9ylW?h9fV7hb!@w~#C{-wfrCDL1OwZdY<^~ZN=9{j>1BRHrNc0USX zcS8uf37%${t2fS~|2iZtaG172bBP8L-hjD8(`?~~KK>yPXa~;M#z!Q$3DJwuoFp3S zc08OLmEMGg0jeJIw21FuL<^phS>>*)-Of2}B&hllkE&)uTwE=$VS#`@UV|?$`Lu1V z;VaKO=imcbyBrg@vq&^HlU76#zQywDN=98Z4AY8p<$;-8zB3(79(9S^>c$|w4OV~l z@QO#q#~ZD4)=+u zw&;D|MTN1OzTRQu&xey#VZ?oHYi^6O{~H6wFh(!O;OGAz;Pb)bxyD%|EUv$@U<#*h zs`)obk}yg0b0m3_NJ7R=(NyCrV|-&+8}@^CxjNks%uW5WELvJrA99)nQTw@@J&u(t zj`8cWJyXm7%X_s4HFaij({L}ivm0l*d)b(*xoh1z?YKU6W!N2yD{fo0LdDXpxtpPmoBeQRzeGfEo!xOq z`{zB$J-_oi-*d0(SUJsEG;GQlPE^%^P`(d5y_QzimO_U_z+aYj2E;0+U)b=$R}uB7XDK;LAg^#96)trEqaP@Rr!iT8My-xyaK znJBZ8E2D!#R4Hj{QJ6b%AhRf@K-hjdud~`)zc+;`ZXl?K-{?+#IVdpKFM78ASI2rD zX8l~HnnuLb&klZiotk_}fM1~tGY;`Acf!)WngH82>r2uMph1+zCxLnE~)N?GLby@L`0piyeQ>JCKK07Xf>f) zg-{$?-o-#VSYO1N#^6bvV#cwa981KLdXl~Ue_fXcg_6x5>oR=NLa-N6Sm|A6sLBH*byyWs3kQ`;VmH@4iL*+1kjVT`0 z9MK&9r6a`ip&g`il=!Db55eej6>)kynJMGP`_>S2ckBnM>Df9)Ut%5hV{}PQK~ae^ z&);96@DIq9moo5y%}gu^$8vD&CvFdo+XFna$FMce2@8B*F)}BWb>*g-fHzLL5QjBM zF|mSJZA@I0NVVH{pFCI=w$T-e+P?{;tN1eB8SB=UNZB1IT8CeM4Yu=`q~#V68Iy+?%3m|mMxRNp9UT{bTVyNNGDyxYHg{#l1qaq~VA&vd5(U!J&SUnh zo^c*VG0f*Y1XnJIjeYbAG@lqEfr9x2&**)YqlZMU-e{nmlPY&z7migmb|x`9NLg&K zLM#-A=<{P4Qv#B66pFdvWE9g6fF#}_oi<>v?ATANCm$jb*CJ{9XB!9X&*R-Dncitj zG{%-`0tCw7C`C|k%4cDs@ZH!R7RTs?tu6T-b>2nNBh2wO;&JL@P{ai*;|2P6IMpE8 z(~rN3o(+V7Tmt0tXr53N&7~Ra8G~s`?{QLZPu$^l7^QScc7AcO3d@O75#XP#FiTA7 zbj;5b%Tbgt=2!0hz=dV_jpE!wyB(^6+awAxHRSl|bqQFew?2GQIyV+s8?h(3cqh&`QKL2BLI zL%G9(!!(sEmwn=Dp5^U@6-P31%(FaF9Ty_>Q)V4!DEI2>dY#E8I~uoCJ*?u~YyG~J z3%mctp+E4H{9Rn@d9I_by17MKyM;NlmoCkg`}qYceEow9^(C2wr6ztIst#*?Bdk0{ z1sIHObdh;jrl&_8$Y!W2OQvL94ES8B#&gn5CfS1L zWJ#_Py!v3^a)QdbkUd9TX6?a?9ztHkB#A3VCEl{DT|-FCwdt?uG3HHF>P= z^SZQJEYE44X&ySaUbKzRlN{`W^j?r(v>qOZpovX4DRwxCjw?A8*CoV@$ZNwn^^HvV ziTsltg1ZiFjv1mPONt%T*Pp#0Xj9gD=|$yxKGN9=w>Te+mNMg8>E!hM@IjQRE|nm@J@SG5f2`#;o?V@`cIdQTJTu%$=}k%977p zm0*ClA=qcm$*yJjG}6I7C^byYdt}EhFrWsA10Bip#Q=o{PARM5mfEly!_+U5N!E(} zf@qs^{VUwkT2B3J>LkJI#~tn;h6)u<2UjPaR0;iX74=UT?N*}-bQLNrc|U3f;qVZs z2RW5DN1ed3(KX@$ zi85F|XrYEc^GGB?pN0m7$U|fcwQ$9jGs0x(13T46)0Rs|QN zeGRvA0rzDqshWn)Ow+N3@Bg`f^ zivENlgLLQO6r&GDtuPt%S-}J{^s-^fbMU2MC7LpXrW|0X&db&$ zRpm{hNqdl~AzDo%Kafrb-QCRc9tBI9h+2Vg`~onZB{r%%E3h@ZqhwLum%GM#2^ z63Ym7YqWEWJFLxBh*2>73W3ncGbGHA`IdmF^^vP_7TsPFd1lK6b1>JLN`Mb~fVK3P z_nhbiqvD@)OLEU)CLdk%LvZoZ2gq1QFoeMiYT~33T0i!JT^G!Kpglrih%J#DflO^Z z&1DRyZ=;fuh8a#*L6?R=D-=p1N0_(}#4-j2bwdyd#+kzpVF4`wfxL-3-y%E-`%wHZ zP!0;|L#iK2#n(xy&Gxbrj0YhNI`>EYL)wN|GyzGRr`UQjREH-hnvh{SUf6h};a6a2 za7G_thPopcB*8yVB(67X^kfo9svj9R6M`bmFxd-cb{)b(JWU2T`~P8@bo`fTLJgot z93$F`%y?IcVld+gw!O7wFu<&jRr~TmjW26qU!JJ(<%5K32mD(U_ii7s8Uv=lOuZBC zVHz5Yx}Oqz@V&Pld=Gmt3Kze(6CKCQ{a&-}?H=ryAFR@tYW0vX>{&{m{24Xy&ReP9 zkZviS-ucH1Bl7;Z0G(jLZS+!9h_fqBF`GhjN3*K|c8XPC=H4P~f5bUHqAEEZja%sa z?iLfVTe!UE7NhfkP5g^nFz>mA0ZVnL1hs!^$OO%?6cIvBtB-1eNmzPHEWL6pz04rR zJLzSrrAL)&#CNxFM~lv?55yNey!xH^uovjYzyBqTyh~pQ;frT+eVKz)-Tz1BI8C@5 z68#bSa9cH@PuKwGGHE?RqhZ<;AYaoR|5~ooW zoE}xdRIGwi?^N(H?!4PyRnUT_Iujlk{r7qh64T6SH^oE<&-O!ZHwM)LU&*MBgsq8N zlh)#c)ou1Fagw01Qaxmj47*K$?6`5Erie`==4TXds*vnIn3ASo_ub^JOWBoQO;eR1 z%7ob&R~YmLrQ#RCm>Zp4w=Q`s&Sui1NU)~ELu}~d0V68)leJIpuOOh{r4zK7)2fHDLRt1tyX)f6zOc$}IJh>Ye^tzEu=5$5CR5W)o)SI6x{2X1^df3ZY z>UDCwEID4{PG)7LBxkY8#M?e5wCz$4TW6n&(lDHT$KkR@?6CjayzKAQh98iR=(hZB zVl|T`->1lA2H>-MU;z{9?BwjEEM^uFo3dvojm9}4>8jaG0^#aK0<9DM zb7j#o7aEOOyx5MRRQB`gfj8V--(H3@sWhe$>~6wm^}=(HT$I=bjRr(f8{H$kB-9H> z_fyq1_4$2l-OYax)PTLm(MuO93mdDhMnxZCb8C3{-}rpDM1n-F3td+ht-iI3#r3^# zjPdbyr;*mHwS%`?bB~qc<~fW^uJ?=(p6dsXUYvj)BdO?k@#(G_T9J?;OJRI7eE0bs z;yV?`8tOrh9dry`pRZ3bC@O06efvgcrqe(4` zlpC3{=!)24S<>bxw_Ra;!6r3_HidJu+c25iln{e^3YKEHK<1?8q#t0aaw^MfB;6+# z&t=h1q-)x&>kW)5-S+cX~^8V!>I zpO|_mYJmOqT4(#q?xb$rh;s^%F6q(FIU!VXaSE5fr$|8NvR0Mzj2|no` ztVATzOJNp`Mb`d^Ki$&(1vuj#J&$P$2v1bned6ve`v4LsHm-S*G8V+%ZAq?P^uTZ|xA}PfF*kT=tP`KrF~Ah)$VLc& zadzuA74Ha-i;0v(+6xj=Q{z*_b*C0t9G9f*NZb`g?}^FMf;o=UuSLb)jA=(6HA=&&6MNbqOCuO52Pj}rAx@xw0ePWVnlWg z4KK`5H5NKyF=2bQGhSgH9xKJRo3AuWpu~J2L1>#iKYa^x7ndsTK@ELb=#yOrd963Jr}97n4o1k{nB} z(-+HX+RBP|L}W3UKM4*=J(NyjGHAk3L4vi6iV*qXnK1Mk56|I>hkQ8B zMpB3#V~Q-$l)lM$^y|UrcQCz9n9_%rrr5>Qi&Ep6i03fNa>lZjKOU7oeIXGkG`Kgh zI%-~HClui}vBV>5_nA1{;&+mSZuzycpT$7DdVt^BxEXy&Ja_eGPalc5=jPRD1dW1( zc8T-%ZDDS)b10zIKQ=wAwlPJ#wKh{7oyuy%m>6Z;{{6JbALpspz~xzr_s_phsD1lkNMhY}`!rnS+fDE}?D2 zbzqx#V1^&nFPEvfsNM0A;w`d6*Ce2VNkV0l02LCmHiqvAmF!<9NY2hnJ}<681;n_M zu6HuCl2Xzc(TWH)Ypvilbi%FV~zMB?pT#3XGBoFhN!Kaa zwEX327#_)pfUm{(bO$WG3l1H8)(}|AibzC`g5|#7x~*ST1>)yLZRM3rlC{v?!{ckj zqme_;{IGYVS-HFWlG~ZO$3|;d)m-A2P-o}m>r&Wli=C?X z#ZK#g7durNv4em0HS0_{A!9)uaUYBYgXp*tr>0@#mxCCYeV>tE{!fg|e!$4cs(%c% z7Dv6TjXIbwIY_jW+549%^Zo~v2_gM+2SlI2h{&}8pv4XN9%tJgh&WxXw(yZkDi>ak{;4q=UpQl z)A>jztYvRgq)aCmnF%Th(od%f%mn1d2($o=qEv@-@>GhfK&f0VlN}Dum%tu_{7h^M z$&$+6*j@wP47x}chyL;j27Y-DOziRLAg@Mz3iRp-^d0z81@7UBPW1}Pxsl>^BK9Y~={juxCg6PWMqEer6J zc*m*yi^U>T#B#3!*MJYB`j@=-pm(y>nnIYuDE(v(4l)C#^nXiff!3gG^%i6ax$X_l z3~9x|%Dje}J9&-vn-eZ&y>3gCW@4kAyAf zj4g#RyjW=F$M$2Lq>IJ~E)v!-MsV3c^HEFK;14e3A(+MkJ{C29>$jjH(KNvYq6nsO zNByp#H~N|WrpK`8F)7XH_ofOC-=(f~!URLa#9R0bc|a5ABa6oqwfXBAOnrhUlB%r>^MJzt!pTtm_%x7iY7E z6gmiga7;a*^QQ$nT#d>h8V(ZVD|C>Zh_92Y!7%`18<6#O=5jWFu29%kAQ9cmma~6X z!(=rNmUY5`ZhjmFYA!4vc-9Hs!klAgzCSBIe=683Pm;S)iP_9<+e&|L#^1|B?zQuf zz2Vuknw+u<-MZ?NUC-&p@J62t%mp9k!Z~8+b#ldKNerxk7&U>VJr46seF`J>AJWS_ zs;N7R<4}Ar@w5|1-h_s{nY@a1Yf%(2I-{Ja3o435QNRLrSS2#D2q9qNXb==pf}jHx z1BAteVG9LiKcG03MRtfdRMr%T3hIouH_VTo&Mzv~Q_pzLoH_X`dB6Pb`~B|cd%ySg zj+pe~5I+h>^plX&!$P0JQtmQ*QQag^hMS6!_rRG>INJT^2vhY#>Yn}@Hcd+RRhYX< zNTXoHLo1OJ3c}497j}PpJ55=@$l3_0uUnKWjg~FJwEZ@gfyqwvm;|#_-7{E9*Hs^r z6)>C?QQi9L?tlo>TUrSGj=FcffE%Xnifo}_<-O5ok9XB0vYc6__ReeOR~FTeH&#R( z%Mwr(Ib8&GFD>v3rsVqmwGf7t3V=&vL?uH%>Su zWX=5A_S7_d^2|s)&fL!rspp8UdRL+hMgLWz&;hwd4-v)?fN2f@DHrkfiEM)oC7nAg zIJ${Ao>dZ)PXk+94_g?$s|||-wI|x4x*ay*)Xp6QuMtQXGl97{I4Wi#qm$@EXIFtt z7Ay-sdBKjSzNS>>Fb`VJfe;q*!4tfuAF*O{D`FdIoi_94EvB$2tGbyFOVFa<2P_ZZ#>VFZXiGDPgQD4s#6=qen@WBGjZa_Sd|BEO}8y2NTSx5z0_z&;{8sI82 zauj*AZoqHx{MBDt28G9;jbJ$Am@%pg7UA=5*Fv2370M3NlUmTRvh(XyW%Soqj)iA3 z*`a?GeZfc3S~$yUliu(z7UTx`r0u4ic8SG)OdL4FF$}GDrUaT=p)R7iDy9~8LA^fppJy)u$XIw3GX7| zHwMCY$Tc34skIUHm8M|c2AnpkMuGPR@wD4{nIbCYh`Gewd#l}P_K~P~MGQk7IlhUY zYGPBAaanXj&DHvHrmFe+zluj;9z5n*krt>}>VDMsn8-Yil$FX#q@{=trM!HY&$Ul1 z@#?3CO0TsgGF!=jSb5Ms+9N72FP7odo$1j}8esj&C`@kjlaZs`2-q{^f;;OR+JGf_ z9ySo*J|(o7oUy7(5I`82T;gY@)%X1yJ&Tb?kbR?2a2?>1g!#@g%QL+<6 zM0z{76J_PO|{R^-Ct?0?NC#v^g;WoR3WLnVf8d@S=O#-S(^ zL)Ry|v9~~w=i!jLoeuZGOfX;%<+yZ|BMsMppNg)ohzcuW3dC6=SH9O@0>ohgQNSLl zGaV>?frd8@mD&nnZ3YsD$Gg4t2`#nUAZm$OS~$$N!B916Y$8hbzTZYLo;syiF{w`K#1xNk;o6~ z2+neO7o@a;w96ER{#F%6}AS5>E4Cgs0aU8syS`j5-Sip(g~D=C;;r z!vVXvcwW+|Li+MrioRkZaTmzD(FlPwD4CCLNH~qi`yPfPvuq@kO; zwbWp0aOf<|UL?^Ej+lNkwTTLuT4FXtdSUe=6B2!Z`Ut8xP#Csex`lm;ly-_W!2@_) z=;Pt1REP(z4g+L5Tu*wM2!vwLTtQ~6y<(GZ$)<|I7-@)B65fYz3w2iqv-`{w$kVHn z5Rtf)&FR2b(9sJ;hN1<1+8Iqj2lSy1{8}qf5$b~?7Uz3;m%g^kSgq4<95;b~;uaBY zMds)u6o5QoE)u|I_zc(1IdB9#(EBhCIWV!CxUirTFX5x5wunLk^gCPN!pE?<8_eNj zhI4C1%Fz0znp<(7WVn#M_}$VvA-BV@;sjn{HUin?Nmb72%kPU z`||~A9|zSc+HTK@7%yhTfqV91Zo=2}qh?R*W!v{!1cfOQBN@)As2+V~Pay7r#;Fed zL8{YivL$1;($d6%+-rw zjC;X0WoBqUJO(eg zPb?y>kaei1^kAfq`6=?SItoE-6niqI7h)IqJXh$1TpDk7H^!(9PcBnbf|T;&#^iV!XetShTr zRI+jrDX6GmKn0|ZRy2^H;wr9PyM2%Q(Xn5`YIoZH(Z4chCi9;6{l4dYp5MV@tPZXT zJ?k}wmI!zQd4n#7lr*HqO}*?MDVx4|E_smIYc%5lg1lg~<2Ium+Zk5`-DD=YyfQ3_ z?7Q%@lr^M-(|Y!hVbi2svpq>t(ahuu{1an%4K#je@|QoqdpBtabT@?wne@J2`CCV#Xu98aW4|57 zelb}k{YSk^I4U~^!1*o<*6ASY8UDm_;5) zewD62TXpfK5SF4(dJ!ET^6#?Bl2Zls)RQM-17%u8;j#%dW5>MVlZXE4VDzMr>BjS< z{|hH3K2$d{EUy=d4vK%(G=_*8>cyzoV!=xPrBTy7nS?(?@&_ULE{k!SU}L+`@Zk=D z=4RR=6SRc#^;R7ZrezyB@t1lJ-KM}57J(VW!Y*V2)+l_-wgibEUA>8OqNTn33I+7Y z0%Tr7quV%f&npH)B%m3Fq(Oz@JSN8&dYp`TZ)loHF4>BFkH8Ex3mhr12XpuY4uQV~ z_9|!m`7;9%$TNYqB*=5n%4L2xh4{$qa}dBhnrwwd{V)fFFk6ExkWhrt+1dqtiar(b z#8{DSx8TTaR;S)zQea|!?08Yxk;;>OCth8|%yvi?X@WOleAD;`Z$c*3oOz@`}vb(=g^EUMbZscCF4 zYolJ3IE(32F7n8qzXi<{k{vF8-Z(kX)!0-kDj>+DBU?F#z>!aOq~)Y$r-}9^i^c9# zU`Xw?=fJ9bkwf#gD{e6+{g5hUeK!Hs<7~#`Z3sUy#Vig}e*aCTKCTCsqZvZ9 zq8mBFTA24}5^TZ7eiVJY(KXm*zbKn1>^$CI*Lwc)wNnpD>x){Cep753GG)WJ4YOWq z6%5>m>Z4~XPK(r4=WDyDH+2i0Xx_@q9z1B=b+GI;8+r_WI@c$pe8`+^&pFk7_zLws z*jE5K==0s@MqKH*T6*z(j}T0dP_^32Ju5Rpq}{<+Rv%ZMru5AR{k%5G-000j?lyiO z-dOEml8cL7vS&;}e!*9mD|cf%Up|C=g+0W`_){_+vm8Q)xV)Wtx8cXzX2*t`AAsFh z>^qaq*aH}BzA~&2u4|f`%tNFIPmGl8-&MbXwmo*SaSbzMOmFFNyABw3{kjKcI!Ie;~Y9)!|y$!el$+KI%)5nOY^i? zn~^sl3`1y}maW1a!*+CFL;9XQQEO()0~2>igH1-4hIQ=WY1u(UCHGNV*qR2qTwEEVl9)at;??r@L-ip# z|E@JhF$>2C<`T#ag>obiO7PZ|O3p|ay8*Kw9>Z!KDf_`7Odl@UhVj!iFjAC~D$9^( z7jG1_)s~z%Noy{sp28d z#WLi8tY2Hf?_nm)dVn)wvGr?2(>a^@Z!XMVg;?%Rjw`l4{OMWSi#Iec2#;brXn0S& z{=+8QLj07i-Y{u0a*=??0K+zf#IO#|>B*PFXg6O66-vVIbazZ21;kHdumLRXUZI&z zUg4f$bPhp|9DdAkB9sA2-!Fu^0DftKs-Q$fzPwf0-O@u%bgo>A*gMwQxbJN4O{8;5 za!OS~9->kQ8IwUg44bjk@)ci29`dEEoCn~e*FBGbeW^i_QcYLg;grS&sC+17yU>t; zXz}-paoBWLlzxpp>5tRHfP;=*f=6)yt0`NT;)T|fO6tv4Pk}Or-Y}5rbXlX zN_q^P$5wSafsa6}=J8VQpt#fERzq=U~M!e=_N3mV_<=A$SsnxmNOi0p-=7Fqp^ z^>Pnt>dxXgDVtnoyPKVIH?EtzbFYf6QnqU`3Mj&=Z54%Gv|4R_R31|05kep&Ag`bf zAPS8rh=3soD4;w9gop^fDuy@6`lz5le85y?t-9xCestX5y`b)H{cEQ)nSr_a-Sa!= z_xql2KIcanOxsDLRksQJ{b~ZJgJ5+RWKwW={~ns2NrRkl{b`oO;gI*OG3k@bZ zZ%=s?cjd3Mq_bDKei%=S(Qj~-xRe8|w{{$%1np+<8Mbcc zn#+wq)}5Oko@vf0IEis{9WUT0ktS?wTma>+I(?M^{3^`Z%WW;_9RfG}c_n&w6tBkN z-B{WDi9dMh!k^_k`I2%X<=9s#?_fJ#rQE=$+_+&f<=Fp;nVe(--`4xx0&q0LH)iX@ zIKncp8+RmFD~pe+=c2wlqs}f^u_rl- zh6M!D{3`uOL0S>j(G%gec&Wl8JSr`12Ln%8SB#rnlj81l;*$m$?-L=D{rf6*?@-oc z#^bo>(ev{$Be$EQofkSqt_bC$i_yE<9&l^{hb{r!yKg-LAreRy zIqX{b_YbMh{cKD^DZjxqXp6@Es2xh5{cm(hPNJXBnr z(?o$)({h&s3`)VYDdrI@uoLV%wA^*|--S#wshGH@Aqec}Xp_zyoDVh>h<_LZN3fqi zhHR0I^E~wXSjL6JOdkTyj4zcq`8*iKjQQC3aB!&hqmMCN&hfXOON-}W@oi~=MOOs% z4><9$?yO3p^IfA`O?j>9{W);W^h7>Lj{X8LLjDW+K)IwOzwlUzxhdxV)8)r&3ahD_6OqCBOzBq#yuGC}B9?6T zr^Do-2?4wEmQ6jQt2b1X+L)TF#(- z>>tFF<|91xOrl^1*!_$K(XSyuB13jUlL*f)b{Khnr|pKhyueP~w`MMsxW+_L#do)SCkQ{G{pg22`U0(&#&viVckC>iG{|E#w- zOM+DqA@YKVvWkMj(p08QT^RKGr58_am1C*q)F=P>(({dM=UcC`RL?&P3w?c+Xaogx zZ&X`W@Z0zC+pD&r07*kzZgn+NSD$lrRLXkF#_b8R7TN3!h)~dK)po6aiVYbBOD&fq zK{&ZkL-@%GLs1EzTre$$wMnKeYB*|o&~5vC0G!MaWG0)QPohu!^qrq>4yLs`HE+o0 zC?=mH_b155i6EPJBWy@%pnA+%#%87zTUI0f4iQzzDm;*%Vi#a1jKWT6NIy=Q?r2T8;zrQ38=t*?|4FXW-!EHrTy> zi-_vkiV5>_!>X%99=JQay>(m_QP?gj3P_2P5=w`Xy8}s)mhNUJNDD}Vgdhk=N{4g` zD2;@qC`gNRgLH!m3U~CJ@B7ZZ=ezfJ{<<6XZ)VS0^R9P2@AE!u_RQ>Al6&4oO5nI7 z-z(O@SVBF+tmyqouZ~iz&DWKN9Pwv_`@r>nX>bB#tw4Ecdtt_b3{pcAM6jyWbWwfC49mA){aUEZx3wMHX5MKfQqLD12Dyzbfek4Um znM`Y@7~8bt zOH(|>BP&^DxwbTN((4b?iteHJaw1(WhCSrydHn;Gxc)S(SxkMVJBfcTEtN;dQKNig zI~45OEln=1+)U2c6fGlV!xonlJ$)nGCUh$p*30v$Z7s5g;*rgLd#%0h#l9PCbB&Ps z0GW^{=SoeI6s3Qp9&|vAXhz<~c0-oGe3$!Ui5$Vt)yxRmiL3T{FbOgbE^4QDy&|?f zf&T6=`%3sSTZdPHy?JJSkchc_vx;^${?>GCc6fr& z(qaO)i=QH?;lpGd!NOTc>b%5ct~mL(d5Q9Z^rEJKI+2I4!9^>FtgO^yl-(3A)aY|JaW&S^mh;(T|3^6}K;LBd-49RYp;;66FFrSEkwT=bJUAXYKis+SvN_L{+?qk4V` z8Vs@8jSB6iISIPO$K$GEbjD{OazufCCQ4AM_6(RS+eb_9J8O5+Jh}&8J@Ute5&gu2 zw5B#FRpsl@28;UJ$CZ5|gg7qD(j$)C*~dvE8NHN9?kfflhak;?J6 zsp(bcT%Ke;5d7CfB$H zsXhPIVX-l=S2VQvV~em6eanR$W{J^eS&OZDnOW5rSQVByS&Ncv^lY5>L@5DJd^owtMqt=G=gK&H z*!{VHnSnxs&Ntrs_h~Ieoww8ENw8s?3Q}A2dpVP6@tm~fpsUO`5PUa}Y)SShT6vqo zBAH8AeQq8X>hbCGW!~bH7dV$1lKNVca+dZrQVv<7m6DXj855z~BbFkv8NsvOnIkgu zOO!(0;Ux2cv#z0RFH2N9Ysi$J7 zJvb)hk;0>fIir}ay}kfHRArZ?xz*4Fp$A!?k;d4lR#U zmm3@EKWLiv>ky-@D(!OKEesRKw&qa@Y4VR5W$lSEOF)edG_#>0**DngXCihVzQ?P3 zwa^tEea1a2Sppv02u6*4*b*9bG?{Z}-JW9FG8TfL>}dthdREEt{vwZ3yTJxCo_T%F z(NDEb;-uR8!o;HGg?7jLx<5@Ui$1Y)(M}dmYeP-g&0E%`{VtMAz$T4>3ER|19@!be z2d*s%wao@BthoV?F>8hKMG`i~Fyet-WkE2H)R7WLs>lgkg0cT`d!X+Rr z6(#M$$0Mox!U8hE8f)yP@4mhgyy3)D^PHAaWxn<62%i_lxnB9ZH+I;gWvlyiSsrsP z!B4hi9vTTYUg-@X4DVk$ZVhREe#Ybzei=F&m^JS=Bx7&6)?MG$aI@s6_eW$))R=;N z>C>1DA}6C>#_-man;6c$ay1QI;?QT_M!(k;g7(2Lulkf?YN`Chy(3B(3^HEoPkrkB z&DWfhk++s_W3wno8G0Isc?W5)dIb2FA3V<2Lgl~sJd}#zBL5D-&^gHL-v03!(_vE; z0T~_ec4|%byZ5{0E7UN#!X-Hy1}uCaGmwnANT!nJ=2m3w<3F`N-CGKoDz#R$|4Dz5TNCxh4l2AG+T~aI^DX+fj};m|tV@D$ z+3kQi*0^18-s$*w75U_@7U(vyrh_qA%uio>=ZoFJKx$(xF39|CW)7u5sV)jv9ZQ+q0bYTH%`y5C-Dpd&@qI^{BrW)ryM4LvvK>{5U1~UFY4YS(j z{u)E>P$aC7#7(rKe077d&L^qHa-4(HGU<2cHoaaP*A(-vMzkBlUE7Tx4b2S}K@wBB zszPjKYP^RXRs3cr*S4;znc4ijBtm)HP&)FW)#X~_^y~R6j*{eQ)JxCnpM~>{Y4Fh) z3PYlH5V%_v21jBo_js<&n|Hr<(JvPm0B1I(N8eeQX-4G~wJd!)WEtrhcxs<68SQoR zmzScv|1mCjQe#$;sk3{5G$ECT@3n5Ez~z-aI_2?lZSJE?EAGp$z#BBxgu<9WnAoCI z9+a*nvg(n?KEj{ryT?qYl4~sR^Wni$@3(Yz=GqMBH>}*NsQb=7H1+-#m@N+;5vg~$ zFuzQnOiBFl!Mt7LkImp%&{@<{iRIIu>rBa_7za@+=~kaP$+(3926ySFMY^sdHvMMi z2$y92g0=Q729aSSOWMSy&Zu&n=;~H(AfFI;tx|H(gqe9&)EHu;#+LqPi2c%_LoA!R zStQ!T1ZU3jO7Q3rf96S|rx?lN?eau4`O-%NqL#rUE2El+HMMxhFEu!i+)1WWZnZmW zT0LwQS__Yyt4cM<4olvFt~7Q;ehG1qfx8X4wkb@IU#HySIhJ3fb&uU!>ky}GipVVT zsn#yK2He??GfY3L_@+&kO3R@d?bz5v`A+&wZ1kF;V4DhcOjUfi@v>6`{N3?+d0@FN zW1bn47I$e?Fx;R@d5@!-r=9^7Z{SiI`LkVJoI1G4&IyWD@^F0G`++>ZFWaE;^Ha6t zVxe`R()L(;n2t1XjqhW3Vc~G`hP5T925m=6;?9Ie8mHI!WHdb9^|z*7eDp0^ziSL> zodk2yf#?}|wF!mzlUH|yG>kihA~*(aPM5*6$a<&wKM#a$>3oe<0wOuJ=kcv3r-#33Hj8E5lonvI8%S!eA%g~HE3ice$BJ3FQ8U#6(~Wk{-ytf|(0 zcbHe|rk;L$S!N#6^?ADezE?kOU;CQuyax&4IGNl&_4>5D3$a?Vko5`|I+tJKOJu;a z{xAbs^ebI2#CG~IYc%%e_w6aEVE!VDXWP%8_9?5XeUHZ$P2*f`l1oV(u8ccg66W}} z%|XQ~YF9&I8Q~URv3+4>vOH- z@pu0W<<&Y5`I6g6c0(yLumt^HL4FX7&tUduu~Mr^b^6H9D8MF)ZSDyGKg<;xdG~l6bo!8HWz;)mIy2H{8$BXyHqf zq(&-aqSD^q)zisM<6)j-TsLCfSe}sksL`grFfhyL`zT;xZ8ZDwq?_-DLR@a<%j;i; zVpFci8t9b<~X8cy-q+WANJFW^W`Td7X^r(!c(8zF<`&!%- z6r}rvOusNyxagFDDB7IXr=l{@%aqmsBAPsPtS5Jw44hn$RIQ}uMpN)eQ4w`6t2Xi> zxLhTU^!gp$@Ls*g!ir|pNnnsuQCoE5n%)Qv*Fy&r#m~FiP4uN!*=%L1(cgftUR9Z6w+4bb?E%6v|hHz z3OJGF#=8(zH3GkU@aMxAKqJP$RVn#>!+|R{zh+jOZiP4iv#$=Hi6>NfekmY7(um`0 z2)0+NIQQYzc*%_8;$jD+skJMeH1DWdu<+jemLb|2@*~Pq z(W~uqNJK6VbgvhroI#7d-7*&_lgA=EYC^T9Z@{_lA|O$dU_m_Ms_43Y0J3wma9rv8 zvIjyS3m(%9TzVOG1U>+#eP*3XO6opQ_%d-*p2Et)i1hswvEZg~ly@6HfA`R>E%lPO zq~7Y>fuUl|OBOTBJzjsiGCZzpQ-@RMcLST31qG_m5;j8Lh0E>y6a+VgebrB?R*NN{(NZg9 zVO7?4uIn>+3^iH~W9+)yi3~HyHR|qa|G-Bx4iD^B?~cM=1WPF-8f^Ete4|3dn=KQjIoNT$Gaat*38KyrL(9(nNr&y z*GQlO5XBYO>95c7`JNQXJvGDIKRpjVJN!^2W2SLC_Nvwl7x+lvF5%8xb#7~PnXGJR z^<|eVrkE5})#(bwj?f?dH*l?izi(JgGZuR)O+HX9V@54GO@_Zkep-K2K4_?GCMNl0 zP;N-I;{%y*bx$_gXxc(J+%JSiH@+fG5&!xQSgv%1)5S{BkLnq$f1$9O=Z+meBK4d7~}m~bSP&1dzKJG+6T%r zmqVM<0fK2xo#;MRAwpfn>~ZyU;=TfD139QRV$ioqScdWim|Zq-^(|yIC#`vU=??{k2I*D#^dKS5MJ1Ea_S;@sFlC@d?;XCvNB|BdKZDS0a_+@LD&^#I@ zabpoFR%Og&$#kARk*$CJQ4sr)cRQM2xh1qX`HTH;$BPW5s3?7F2i*q`a3%4TN(n`h zj}-_VzHOeVuT!sg5$0#d%l)gB{mQfMWLa>e$Z_NZO{j=x8l^UiO?OOp?nDlCbgax7 zRFKEXorImoY2?Jd%=78dRT`0Rx4)djBNeE~*({boaplh1|SdU}D`P@5fSM=-IN%WO1*^BB%S=PKfIJ6iqCG__VFl9-1X{R}k5(@jKX$H+bm^FMKiJ7uugVX7$n8M*AZ_eJAB^>Js! zi|?-8oO5)n&k%V`=fzL%xkI;mC|ddg85SFjV|>d!XnG@;42yclZLrBZ{ivPJj5|n1 zyj`q%-nf}*a$MtQ_HnA$YSePdt&CW+Oesnx?N19lzmFc9O3PD!Hl5)xepNJh_M~%` z;|ncBkY7stX4dne!Lkl*>w2R3#-Pdla(&jplIF=J(AsOeIKH+k@9sXXRV=^E!};#E z3mt>cj31MItwjHz<$bpMFK5Sm?I#7_^IoRC{7Y$CZoZ#`lpzbzG3Q}>K%?HA{&?I9 z!gywE-OS%OD+Wq)qB5jaEp!4N`Nw)NOkTP4K$O&sfG?A|g!?1huOBS(xcqd7v7pgl zv-ppZ<~0c`w4{*i$;(rv)`#UjM{qTx7Dqk#D`Ri3?(n@h#=K~_iT}QFr#3pDr8$3y zUf~JVAkmw;_(qMPL5UGM&OY~nwms(Ss&yQXcfXaa z!YY;g-(uR{ca?L0f3d``eB|VEh#j|pZH8!Fd{vQKFSU%ZVLtCzz1glW9Le*He0NCk z11Gl+OW*DkX^)DovPIDwX|gMOIv+0iN?|TxJTH-XUiyf+G_=4$|Js9&!~n@9@p@LvQ)`HDAbe z)cOtm(~BHuT%}#7(}C@qeR2+b#row(5-os zpe)~B7R=>*YUALTv1~scE^8TKtC=GFCP33|h&x1*$M?reEC1-%3(eT5%c@azhBg~7 z54W8u-{0T2c>9(rMB#0fb`M#yzA1J5hlzXB}6y&cOJ3w7~dfPpJ2<20# zVrg+4x{$rKYbw+s#V(5yP4vvChh*(LLiaf?=99ODbraelqH$j~HmYBpc2}dSvCkpTrzi(N^1;0(W{52EOxPM>8RsWfg zNSahZS5IKM?@YyQdigzZT0z!<;k9;X+~=hY?>EHfixj-6cC<02kv{IaG;Mxqrk|2t z|4H^C=SHd*t6_52S>>d~J_O$i)k+e$mTjThKHJI9}+aAl0C~WB%9b3`S(PO|;ii!I0B7IQA3yWmyr_)iHw#?tl^z(F(k# zHD6Kfpy?vEePS>29m_RQmxqsn!yV?`)U_tAHOv@fOfw2u>b{y%l!5%@P5UFV@o~h1 z;G4wv_FjZE$-U%pYShEvVt4UD>xeM{ekJhW%NNBJKc0yuD?H`+Hf2+ua=}#zS|R^7 zClIhO1KJ5?`su8?p`dX5D9Sc%Q{-aeB`wX?ecj^9dRa>kZ}qTM1&K7Jy{G}@D>To+ zae^%l)Z1n=vA2U?grSThB^ApLI4z4r^f=Ib4+kEq#gDI!HntS_OqDkFSMjWUc}7=- zpVzfCr)Ix!sraJFIJZTrZXHjO$fEox8vGfRn!36530W9qSIRNFSr!a-GN>D{g8nWV z)A0~bqOi;g7;M}WT{$H(cc~N*)7d5mKdq6kiQHGA*9zyKcOZpPH}V&tL^^ zjFN&uG>Rw$2aX<2wEmnI5#Ys5eH9HIyvH!eQy=cPpV%f7Q}t%m$?GkRzvJbmlfc;u zgXunWPR-0RRICk^0YNV=2l!mwf6YB99Ic?!vhH=+W%^09;SDy$r&UxJxYKKA{VDB* z^&OjD73n)2<5zwhqbr_)%9ttlnk9@Cj$ATW6>pxJ>y|ntS=i{BS7zMo$+*DX&#Z zm&Iy$ThOnb=wycQUpM>&!ENm`P&X2lY4XH1aw8&>qow&*6>$C!1|Ewz5Apx?Fq#X*^>;;5Qe5$oy&J(rT+trmMtDHLIpGPwCKp#XE(AjS zA;Hnw&4vq%grUVXxX|KyUd{w@O{}f1n}f9U|1?QuGrMd!<1#8q?{|4tE=kLD@H~FI zIHxEz=2P6CfaP9b(yIEw@l;mPb5{I4yyvNusFwgOzV5_P9KjT|Wl(qOwplHrphL=| zs*sH5`TXEcewYhgt^$<8IxuWseB?nV_vr);jz^=zsPpH*!Gk7Wm5+yoM~a4Z$s4vI zSv8)DA8)c4!4ynWiBTU9m*SUd$EhFC)%I+7;vckB$eUdUc0;i7z1^ZaP^b{*KS%m zp(v92a5GF}_Ge=URFL^PTfMM6$$2bA_SHqn%hs*yj`$m47lep*3QCft#fN-V50&|( z(iC{EwEZXL#^J)(tv0P8#!09A4sb;<=+xjva92PJpK|@ zg#q=)ghHVRKR#rHzS zgtvvHYaoZ0wDGI!@Zp7T-LNH#(Cciv?b>40t&PCluS|{WT@MwHOdRHHs%DSEM7U>_ z#hzRwSXliKI^MXbzBs@u%os4G9+_(wr?y;osOTjqe9;oG*{+<@oiJ#6;#9MOk1N?9 zEiO3veA|6jb;Q7UM$h}}nP6{JGa@X?AYT8#{%x8TVZF%rDjaPhM>xj&!FI zClz%sa`XLhH3jlrPGZ_h``4iuwtpJCQ4kxz6 z=fCu3TTApGyuH0vm}VZ$@#blo=Z3nztqHAuNc28dcC7pRS-#QYl3Hm=O#!;BAb!0B zGS%;aE;W}N!pGMz4avJ zB~upSMO#o_*Gu<1BoC~noEjINd7zlU*0c;v+wMs3sue0<*CQO)t8&wUs1ozE`})4L zY!eR0la)|&oi|jW1{?5^RB95}*KD%Kj?Vg4QY+V;N?5$rk3YQ1`;fOyEMtDz_QiOO z{+ubPuZ?QY))`;KG0&cjG-FFFy&TQ1|E5Vz@b>{}nUr3H+Sv4=$4+dY;8yb4s}#-y zXkGfiuON$EInk#5c6M=r?ug*8#oy4!5`_#IBf%6|>&Q?m4qBsjij|PqQ)qgwf18?}c`B zI^Vel{V=ih+j)1ma!NBqE#_oy=zDDE`n07ckH@^Ugzc_l=5vTE4yCg|8(Oh#i1f^{ z)!oiKH4XRxpHI1&ruq>@{$5v#dbZR=#>H?xyLWb@bIW!kz4-t=gIszz1-6%&I>-x=}!UAe~I<5%vXQF%!i75xaIG9KlMaW{&J~r z9gS3?oPH^w6mHC+5ywz~bBR-N&q4D)#!3+SzlKK7bm$;d@6LB2 zJd z|4&?oLm}w@In;x>&=45xf9=2u%0Y|$d&)qSaG-2JH7O$reFkCei zy|l-BN#xe8fgaPw2q%G`w*vMmH=(!H}Z%n&kG#~lb?=CyI--Z+(ktJCg z5)Z#zUMQqYTH3J5D>Gi>O7}JS7$5E?KvTLJ4sZYYNsn*hxbwp%sXwc%H1zd~!-LOR;Ek`Ly3%a1~D3|=+xGM9rHL^WNJh~0) ze3`awVBS4=;fhSBRpcGDiro*bH(r_hk6#&R8&yh{B8PTym2K2QBGUl}eyaP5wCOo>{Y?wO(p|dkM7tDvsx@$DTQ>hFbT7~OhC9V~O0V?C z&%E1cE86I$l@g%|-?O_SkrydL;_ctpCa!3+2qs&uigLD4q7Qd<4YGo7?|F@r^Qyrt z+6p_(HY~*@72tnp3%`nks_u2(dv=p-;lPmc7ZuIO8=e)hTl95)4?@lt)wY6t%jkvY zQ}3x6QP(zHf7bm=ZBeKvq~%uxb@i|QUq2L{h&gT`-+-LJe}I`4@qS$})k)ArX~RHY z$d`Lx2DIuj$@Z#uXBcRXj!(8`S9WK;)C|AB+`hdn?PO}#i_knA6HRlPt$y60zWMFV zqoRt^H^zQALYEMM&@g4pH{n3`Yi#PPQ{?5dN6fF~+w=;*1_elp<~-Jo|-K8#r&)Q{sZAFjF+?(PM(CyFr|`{b&} zT00MvUut_knee*Ie11>#7DC^JFDvH2Wq4lutqq}Kl|5R+OP-Ne!_?LE)tIuQ!?lOs zO(?7B^WGT5jnsP!yT}@C&%i_j__G@FA2!<>9qv+jPMNK&v`waNn*5ra zfl|jGmaVOYHh&u_b=eq>U$O;fwEv46neJyEiPqY}3WKpAj@9))Yx^G{z zxgVnWvgAQ_D>2_UxYW!fVgD&3JMbm*R*AD0TDYT)^*YUs9Q7TlwR)N>7pSix;ozJGcZCY|@Ugbd@vxp4BgZ$fSDE zeae;e>Tb#QLULJ(aItb;jb7ktXz{}dw9cN7U&B1l)mJ*%P1@YhzL$pkp^>foMe#H} zdTTFj{cd<)NiB@J6m9F)cW*{Zlg&1ajoEJL%jm|dJcGPy5%;8!m8fIV`WM*+Of|N^ zO+3}r-r{qH?>vM?3!ZV+LpG2$2O%s=<*P2UwU!7&ns5``Qa~v zmuwTMB5vI6kz#v8al@6BIqo8rYsoyJA*)q2!SP0-8TM-{0rc8I zs(NFR=a+h;UOhLQxI~nhr@T%dr=}1tSS@uI6)hj@-&d$!5;{2{tCb{Z zOZXHdKkfoiF#dACHcsJ#P!{uNuDteUa6)+Mk=o%kDfsq&<(FGCosoB@I&@Vvt)NK- zhs&ln(mNkG`+@p0)tl_Z`6Ho4GK;u% zwP0N`MZ$y79vV!dI|Fv%pgc+PQhd7IBI(QP{anteguqY`igyk6ey1qz-a&xut@!?Z z5#_Wn;?Se`^zMpBR{V#{sZz|EF9kJwZkmnsD2v}%A$UiBkwaxZ|FxDX@Mb1mGB|z& z&57C4N}Y>@dRJ)-V2|wCwB5LhHFb9Xu)U)kXTMV@dUtN` z%D03+mpAodXkXnutFSG`9^GsAjhU4*-)j=g+;mn(^YaJsC6xC(4h^bJUrpb+H6*mU z95CTn6GnV1lkCK-b}R1E{il@_RNoR8OLRnp6m;)8dcR@p$RDo_uoUV#y!ADt|5c82 z31f63_8sG&e9wF4f9mGC${F9EfG@+425N(&qs#V=!z9Jdxm7Js=eEDc3#yOf9TBM7EeK5o;jpkk)dapqdm zQ{nOP(?XJOjZefdGb@~pW7_e*4|l_)_n&x+TarAN^ijRxfHZpH(3MZ%pT9n-I?aDS z(?}-{VDH{l>TR!8^ESzk_N=x9&uW_MNeg&ZfnJba=sDyWWLh<%kcR!UmYBQ`tHrVl zU$w~8)Nw*-+r-25wu1*zl5gvaXwule&FPs1eEzKZX!}&aSg8Azao38S@KE(i=ECuH zB<%N}H`e|?2L!>0A2zVS>ocJ;!s*`AmNql<&9+`P5v(4{*%X#Bq5yYojBGL|B-^x7OUuc@{V}xg|yCRu749o~!Ji@7E_51Wm zD0>C&M_n;Ye+-U{9*@09Wr}tgbyTQaRCpOTtpny=f6sh2+girbbZgYZ;>L7+LH7M! zp(iX1mRZ7RZ$`hCxXDTSs`;|~mhHTjW?8>pva3y74TccYHkxnuM9I!ycZo6n3J#KY z=RxhKGyKu8cg~p!zlrw#9A2d{n(jFo{yYP<-kHZBuW^LZHf;EHSL47{=Stxu8drR- zU0z%|G@{&RbD&?m{-{tV;x>{zHPv3+(zxNJ$<$hpg=w*tYs9Tl*Zq)&mm@NN)=g!+ z4m&Mn_Cnr<`|PH5LS2Waoi5HgWSTBUc3XURww+qLEk4sd`{mJBF)aR($8%0M(XN&$ zCE~^HAbw=4e9wURyOq?c;s%}CHy>;>QZ918Q+HOrpb${1xH5IC{&S%F)zn*_p8^GM zd5#8NzqcoSm58bfq?Y^=j=35~g|eZ!<(bLLag~aX$CbS^#m%ZG(7%6hz3`T2oGHJ- zaNwVG&o3&VjVIsULGD8{uDIQTiKbJk_n#KzuRw(j^kT9ui`l!Z$9$?eM7B%leRQ6ANHW&+-5T5r^bDY&v?+#rKf45CzKX-ho8uclO7JZUg~9%X>6^dKaU#{!zo4jCVqDl_m3OudmlH1sMp^~8hr_$?S9(WMw@zQ zIg;5-tBM&OF~`5VuM$3k7k9O^{&BTJxK>*h(POc2oj9eYELZP;GfKMt?aZ!XG&}qB zo%gYO#z+m97qrh%Gj|%mmEJ;ev3&>HD=XzaI`~Hp7~Q4gSEfd9j179oPXvl}Vnd$3 z-yCZ2nU$1^>p5ksC9IyKzGpV=mP@sbPCsvv`q?YPWnt-m!Ee2NRs7ZHB724ZrsBdk z`hoqv-%~%y{cak!g-&ET-S_u5u*fw3eA9s}S&%u51N{9{^Wqbk*gYTmQ$92Cg$R0S zUQGToTFNI9+L?)a7)lv&ZUKH8m9?Zw_4XS2^0+}UZsq#@oM+$pB}Es?o(VF;1o-8% zJ>=T>xK%Ra_Y$5}h$@FR1SsWXCuyw;Xg-!_Lt;kXU6hw<29@>)pXUn(`3p?XS6_sY z7pCa@WREHse{TQ8g$So=SulS;wrOX3@aKD)>5rM(f?S+>{DAf8^XvDHTm!z+2@$hS z?OPoVcS-BcWimPaYO0q$i~syp_oX6r;;FPq1mAG4Sk_^CVWLi=d4n z?{>u^2+0O5Z>;N&{Psvf_arlKa@^1u`LW?d6Vag6y||=3nayESAM%v3 z^(xQzM2zpy?wbfOm&&Z|hs*em7?Oyieu(V{fjG3)2jZQ8k2EN1`@KjK>yDYdYgcMz z>BiWdX&J3bNxoxmd9YS88Bhq`yl^!ZOb5^V8VRnlIFn3sITD7_#-EzK3@5pw7^5z5 zh57Y|>dyfRMozXcD~3-Gu8q?OKfDUq{rpgq-5Fs9@%t7aS~>YUhvfSQs>6Y6C_~TQ z-+?5inBWyb^7N~9D~v48($lf7&q;26m`opWc)MUE;O@aE^89P0&~<^hGu^ifHi{Nf zM*K)b*`t^#hVX^hu<2A~eulen2DQ#j7t;!6y9AH;a9X%7uT%8(u_s;RJdI`33@Tlr z?nS9=D^WtG+kNnI4oH$Y%e!GAI zUp?vVeS%*sNl=r_WD$&Cie-D@bB9Sq3Ac|yf6+lyuRPTIQkkd3o1$m0b(?iUQ;J=x+|rP;$t-J1jEA7&*PpIWyzl6xaSN5)VplJqUy|&eJhBp^508h!%V;|l zv8?Zy^>sJ6^dmnrvp+n1p~bzN$5wItGN1kvg~Dm^Nx5(k<7->wXI_f>PsE6UYHT1!_+%iqQ)xP`A8&*Pc zP0L}a+`_r*jWz=D(|VRNV6b)}+Z)!r{?XW#)959_i6F0{j85O@HRYQ%GW{mV?z7&w zwTW4N55Zz-X(|l_sqJ#ekQs34*IAAb$q!v`bhFPBi)Aa{J$WL>-f5M*Lo?$cPuk8k z@`k>g9!5c_-0rXZxcH7X!AN~n$b>zcWNc7W{+_RId^ zG0o~RB;* zuAlRYw-&$eK>SWv4rZD~^` zru<8Rh@%bd;PfZXO(lezey;fA9o%$S-1;cXF~{Nn><7CbCnQ>P_rPTiQW5{TwA{lx zp`KOjp7Igh=@#;2;*P$;54hD<9%YMou3~rYbUDqvM;Y_FvGaZrNfpadEjmnoj-in% zuNoZV=1B*z*)MCFkRtIE(Ft-wb7xob!0mpUZxw#I6*bk-<$hz$Y`fpwu2>+l!B;pM zlr%s#wNIB@kd+gkvzf|#OeL0~J{C{M;p82@jfzGzCFfc=2*9zP!%&U|!QqUEKdg&~ z1%|M`H(&i9e0lEa015p@8hz&>XYW+JWm`Tqor7 z52XZ6D|*DxdxDh0N9iZNv`IUua=3v}R`9orien=)6^pj~Gu|4O-aB36gst@CyTV-*X$OO4)I2$@%EMLHYLWzTk`d>)WpE)2-t!wY%RtIn(9t!t`QtL~gM^Gi&h7<<)X5a@eoAKR1ZtuEu<<nvhf-FQ#St;a+K%%lVb8^ee@_NU6yB4{~u4El(QivN4G4W zN(cON!sAiql_9qEhxMpke}7Z(?EOa*YwHE?GXX#t++>uIe|ESZBWI4sS0=blE<{Z@ zU8MB>3|ezY{ER{W`mlWEIp+<*T^Zljz284SJ?7r7a1mVmy5o6f*`Su1?l+;1wPbGK z-p$;;!c^*)?H~O<>)FZ9Bj?>m6)u+F^v10Vo~iTMFw9`9#zh4>uXe>_YYBC&ea#U& zuICZ{ZA$~64ksFCW{zhT`+lP}^QzLzwv~61r@0+}=r`P(MAkcO@0^^TaMoSq{Fyl^ zJ9qbeaqc^Crg8cpx}s$E`~Is}X9jNdr?=F*{OBi7x72H;Ns5Qm2MwLl>L?MWt=k-F zHo?Rj0=I3tStTWBrgY6`(D72O?{%ww{;>6wEnUNC4wOrojFDVBJpmpy&3mrCcP{_@ zb$+$3-4>-y_OMkUv%rUr0F}#I`6IM8lm#Oxw*HtW@HX7hvyHd5JUeQedPd9gPuND> z6!RPC4WJ~qmAnn09CXPXaVIUX%BwhoP1T3@9Fmtlp9Wv)_q({Fwn3Nj-<>3d{GXg8 zg&_WKr$x^7HOT zt6vOFyUflh8$8iGkm3_o2w)ggo1z}5EKXjLPIbpV75mTf`|m+fpgg8=>A2LwjIK~NCvUpX8Etb(xrtwr!Ziy#ol|`TGY3 z{j>3}h5v_FV8HUf7T`$04=m6U8fXa$hXbu6z<>=n9EOF0!GC=q{AURYgaaXAa0CH? zMBor$UK13C(Y0j_}wU;tSt7zzj85a5l1f}lv?6AD;I!!iG} z6!EVV0+jsUN}(V)u;2erJqFMN{}+0HdyM?wk%54KUZVgs@kkJWD$rvX7+9haPz3y6 zT>l~WKX~%LMe*;o7a+(03jj9#jrPAa3<&aX34{etK;Y3RC>#$b63}=Y9)?9jz-R;( zioha4C@2nvCqe-Jp$SAhl!%AGhyY$V3Py4opO02~ao+M}T6WPz(lv2SFfM z3>pWAV_+cYUkad51SARu!(qV)6dp_K`EunY&d0)-GT0Lu^%2!;TIU@&kTmI%keP((Bqf&hUb z7yxM`1`Q$rZoyGV91%jq;Bhc05e6gRz+fT*i^hOKKxHBk=puvwgM*L=I2I@eB8U2m z9uf|;hb6+m=)XLMqOmXn8j69TU_>yS2*RRaFhBs{FdPm60EL;&ju z0+v9)AdpA|3WvcF&~PFWuu8xIfTGYu9E5-eVGtlVfIScn2oe2H4gRGk2)LsI1;+hl z6c`6&;(z2j7!RZrpg6#mzib5q`243D0UCw^(hkrnpau}_zv+wt7EtJaTMG{Y90VhP z3w40>0Xa;714#+P0el890EqH8xBuld;$JTR<2bPWe`NOGQXt>a2*f|;|EmZ1^H;k7 zRRWfTzi9!y0YHctKsm7x0tk#n6Cgw=iauEC>%`069K>oct8OGb^;0lc#eakk$|fHhxP&O6aV5sB>oo? zgui(Gr+*MYIl+J11oRU~!oRxxH#dR!|HJKn-v-3_|0SpYDf7Ra{);^bpbrd4V<1^k z1Uwc7NaFciQU7zB<6;39zGcz`Q-9KdT77>tD?0kp700tkbL{0#>I1;>LC zfE0jGFo2;%A{L590%;Bg(vkosVsWs)x(z`Cv_b)3K=E)48Ze55qJZ!bKoBAx=oS)# zf`hP5OfgC~NF@WIUF;EC#3&>CuP=JF1fx{C)P@tOtQ6MM` z6i__`97tUl28bgJhXj(2NWj8?v_cbr=8z~NAl7Is8VisQ*ba1>fW*P@zzYa17AOJ( za9{v|!~%+k`lXxY5e$Q2ktjSA3CBPPSS*$Zv_b%63yB3- z03o1(5TXzWCu0*uxK;8H#YfE6GU zU=PSVH1e-VBY?vdIF3LB0!;+ra99Ki3v>nuHiihW8X!Chg2w_WiU8Cc55NmRhXli* z2mo=w5iAyf4*E~@0S_TKfGGqR3=jY)8t?)*8bJc`3}iJxZ318b4j>2vTttA7IG|_9 z|Es-o0j{gM&aeTGpb9kQVV5w0UW))WM!M(yxRC|2W!DA^3rj^L#x>{cy^npdq^n#> zSQwZV=V2bH2`>+%23i6(4YWK;Xn4mYKqxO0lVA_D(72&MXpDgjq(h&v-jG2{p>Kto;)m3T& z1j_>y90$;kVOb%l;;A@xv%o-{Qcp+5GXQV~g2d#nMG;8D5Z1z#vm^?E%9PTZ#-s}6 zJWyVeaTWz|B1J(B-2heunXy&OTtO_Q4alk~NU)QP!)C`+n>5gwR)*7U$6Uk9D8rCH zo6A9Igv-Z?69EK1{6-3E7y``{AU6zMmuk<+7h(eUgzx#v$wH8cZvvl!Wn2%a<49L9 zD<)hXGj;7mXe6nXx>~`vV02^?mjOwE5n*7yg3qRW3mr^>JX^}3?LshRCd|nSjTfcF zCxuaHFL7Mo^C(lcqf!=-L2x5d-v*%sd%etuT`DLHunyCP7X|=xYJ))*oR{?Vh@Z9< zRKiMu5(qZ6E@ovu0B(X98W|>tD`t|yJBS0YLSa%4;Oo1tF`-3>0i7hK?j;sfDg?L5 zSiX$B)OUOpSrjN}9(f-DXGuc&hSnLO3BJq6fgIygqcTqmhY;ouZ?aMqLph<+DdZNK zWK#-EniyCSo50ZtO&ZuKvCGmR;Dp2|S#%^4&*6fh18oJ&(E(IH)_{03Zl+w$f$u~R zY04H{7KKLLXCFBSKpH2-hwL$HICe_J*>~z|-~=h>Hj4pUA%;q5O@eZir4f3z%Hb+t zo(ma(0dT4fln<($rog%%vfqA233e5v41yAP79@fIr3ptQ6y2ISFcRvvf)9}(#6E*S zaMGxnSwKnCe3&ALYz!HZbE1GxIp7)%Y3n$Slt%VY+*GPSHSQ&<{b4Qk2iN*k&X`%<15%m-j z%%_wGAwzCLs)%|l@+iaYfa0M%BhDx%76A!ifKmDoEI1PoigfhhOktc^Xb(6N^236)UsT03zgtod@#dFyXu4Z8$Iv%LOcq2xVZ(uo!U41C2E4 zYKJmO4NXFU13+oY5}|&C7%CNI3GB#IE+Nn?!GhKTd9ngjG|a{*5*u;?$h$1uhjYa# zsOeBDKx}LPKsxk66eA)l3|PvBC!${QQXn6cW6ToJ zihaRBfIS-@XG6frFb?2^|KesQiFJy8bNq-Hawgp6$Awb6Q%G4NMI>; zk}D8sE*YBy^@Cv-Q#e?@&J1kUgscD%)`%2D3>E}jorj>Wlp$-P&^HA>Ki3}lE6OJra1k%D7 zC=sL#w5G%Yr{YCIN$`lNS4}7KcU&FsCdoT zJfg~}5HRBaTm)P(<(y0*&#{M5BGfc;TO;sU1l|uO1+D@XNF3tb#u>Dd0Ar`n2f*FH zVW7e!acBn^fW(T;0zzQf1RWm0K0-5XjU~;rKt@%Qa0i#4e z#TiH)WI~KO5R^=8Tr3C%bD_LZ&cJ_#jKUwtEC3b*8kyq*&>_7J#eoQ@8w5Q?A>mx2 z77T0Fo)n>sLmtsYa)}c%51Wkx5+F}}j9l^j40aigX_!zGFxh;}N={Y~5-G?%>j!(W zSiy71kIfY=5S*+*W>DVwg$$;`ggqF(OU1)0$7`>DjEq%52k3zzW}c6rPWv!Vzco>ul3FCJzInUM|<=PFJkyj;tO9Y~g- z0dZFOsMzFiQV1eFQ^aBxIJ^)1VOq=|1DXrcsv^}`65@#BMowd9P~kX;$YSsUV*$m4 zx`(Yoen1{@Eu!6mQ3-E{6K5XoB}W$Bj2K6@Vl5-D#D`8$*z80Mp1Ig_kTjGVMF1IZ zF*Ny&k>Qj1vUHUabyk2V${^HIq_YG?Vct0Rd7LWsVZ!2%{^+$On(HZ#3(Kx5L1FjT1x{QBg8& zX;)D~@o%wtkyV)b9Ag||WD#x(+?R97B$+t27?m5G!{%oBQrbd0W^r`YgofboIMP5g z4*v;+W91-oDNArDY^Mq@=A{a{06fw?{H*ao=FagFVn5&sjDLRwl~(Z%@f}9pb>UPx zby!0v0$vsSVZ8e?NC@%4cmFI`lRGwu8l&tsYULH#1+t2kn?-w-gAF7>4WKyUv4LLj z7b;g|5*q28Jenc&gA$59NI;5JN-s7UuGY}XKGxA6a64d@%*2uwinQr4Dk$)vCQ_O? z;8_u$PzA(^TQ)d3(h6L24+p7%xD2eLmCskY)mbUkt$TH)@_! zr^Om0m2k!khZP=3C*Gl*W06TDE_MUmZj2Vnj_?y|4Q7N(o+K~@t}HY~cnUj6#|a0C zrO{@`KEo@;>Evf3q~#_Qv0qbYx#VVGH0^fE3=JlFd*WKNr5+9loW&JK8uP8v>lda^ z@0`0!usN7^Ko^AyNCvTMm`nn-oCr68uE0VPSUN0|7=*}Nj7VWxEY%ku0%XHqrcZ;h z%xA!ETtT)?_?5ha);YzPZfZvHWyUF{E7m-z9#L-?2~XZZLO{M?dE)%hx#R>){F#Wr zLd^cK*P|3pc;8Xl&NcJIb~t7*W{b0Hx*z=l?ER+3B`7%%q z%B3{v<*UVzc~j<#raAdVtxNLl#jd6K#W@;%u$cVfx&70bfL}+4v5wnXeRoE_t=!ks zYjiWus>=12`%J^owAHBpW|UIb+qCYvhLMJwA)e_J^Lug|gyNT<)G8#dZEwPj|g&9r*aNM;BQ^@$!u) z9h_S->x3U|nY6NJ#o8lRTztP`@bya z`d@v#=ES5a{L6E%Z~x*O`){22?Z$2G=il<-lMUD0ckH4EZ+xrg-2JZJbo7O@cdl-E z?AGUhzW&2MKj+}9YwDic_)y~wg-d6wS$XE7(ku6VsY&@$URd?k^=IDnqqfP(#ct1IJ>)i(zwr-lV-|x2Fci0^-{H$uz?fub}mp^yuG|m4((OrJ(4ZB`Dt#$2( z2c7-n3pT%Z*5kkb-ZAx0-14V)|I4&>%loJ7|M{mDA5eAM{39E`^V63Vq9sZEx?GvSHg9yQcgwd}HRj9eC61%KCt&Cm8cxO7e5LAS5__od%h z^ud<4uWx#6a>Iee*IIt{ty^|AS=$cNr|rdQH_zX4b9(1P-+FWF zj-UTq$0c{)IrYMw7yPW}#3QS&?&w!J{g94L-z&Ydrt_5d%QKc$pILq8Gq03yJm<#k7iZztH;--p!jk^0%I96a zbM8YoJn`Q0%}sqz%yYLL`sT07pI>v-}^W->!3y~)T!XX;Pv?@rW8)0<1p@?zJlnw|GQT$3y6SvBo` zv(?-^$E+yMUtKn>t50oHt5-trYffyauJ14OcXoF&TCTsdqpPRTKdUAYEGzJ}{5W5e ztGuOm<*b?t3gymdZpqCll}*mC3u?K+!Oulro$aHD{1YnRk++<@?bccj_)&1;pL#Fd(x_kOL;&irry zSYN$Xg{)NWOnMuV?rthbB9X{*k^20|OC!OM_p7o=dQ0WXUJQq*vMH_RYrFqct{_qE zC^j?~S9X+oa;GO}cO~`t!5@wcEbpxRboVhTv-tQ0>se`Gj?BYI-D!}5Q)^qbw%uk2 z1uG~x0p+q_S@rob?;N?}$QY$^TdCC1&|aqSmPdVJ@aJPbLiHV4+kvEL`VC9q) zno6oq&h3JxhQ7X{E^s3%N?#?l^tY2*nksH>L}$L18}GH;z9u)KRbtcJJo>XA8+Soh zPjAwt%+R>pY%J|)Rf`j?Yd!k!wRGLGT3mS=IowgoeO^Q3j{5B2xC3WmRFV!LK;@(W z0iaKQ7=Au>^o9@Tr}@Rmf`kud?;`?nL}+IxJ)ygCuCF#*~8w-e#odwj;c zIuWih0onVv6XDu>e8#-Gw{TUD2pFEXJ*#FF@?;!=H0l?n_o(~5A=zJf0Jps-)qhu; z)pEz3&#ihU|Mbk$tmof*X5ox=fmc;s_2?UG+os<1#{OU0xM}K(+xJ1Oz2blF_HicT zji|LfPG;DHplO5$vB%l8J$YyKBi0{G+Oq74UrgTo(#_tDSIxG+H}|;f)OnAtczyG= z|M8!Ni(dKgs5Sfk$qV-^efuxwu6o_x)q35I3)VgMn{TG4)~~&0!P@Kgd-s5gUfcZT zhxcutbl9@r-us6OuKmfjb!$Jm8rbbK7Mm>JzQoSCIeY1dNM7;J zX*y}2W9Q9V8de=!RrTtxb62z<+~mBwX8vRMpS1m>wKbb-4*d23SG@j57im4|0Bh3b h$yG;=6B59{{=8 > m_aStoredElements; + /// Elements of an object in an object stream. + std::vector< std::unique_ptr > m_aElements; public: PDFObjectElement(PDFDocument& rDoc, double fObjectValue, double fGenerationValue); @@ -107,7 +114,11 @@ public: PDFDictionaryElement* GetDictionary() const; void SetDictionary(PDFDictionaryElement* pDictionaryElement); void SetArray(PDFArrayElement* pArrayElement); + void SetStream(PDFStreamElement* pStreamElement); PDFArrayElement* GetArray() const; + /// Parse objects stored in this object stream. + void ParseStoredObjects(); + std::vector< std::unique_ptr >& GetStoredElements(); }; /// Dictionary object: a set key-value pairs. @@ -175,7 +186,7 @@ public: /// Assuming the reference points to a number object, return its value. double LookupNumber(SvStream& rStream) const; /// Lookup referenced object, without assuming anything about its contents. - PDFObjectElement* LookupObject() const; + PDFObjectElement* LookupObject(); int GetObjectValue() const; int GetGenerationValue() const; }; @@ -275,6 +286,14 @@ public: PDFElement* Lookup(const OString& rDictionaryKey); }; +XRefEntry::XRefEntry() + : m_eType(XRefEntryType::NOT_COMPRESSED), + m_nOffset(0), + m_nGenerationNumber(0), + m_bDirty(false) +{ +} + PDFDocument::PDFDocument() : m_pTrailer(nullptr), m_pXRefStream(nullptr) @@ -315,14 +334,15 @@ bool PDFDocument::Sign(const uno::Reference& xCertificat // Write signature object. sal_Int32 nSignatureId = m_aXRef.size(); - sal_uInt64 nSignatureOffset = m_aEditBuffer.Tell(); - m_aXRef[nSignatureId] = nSignatureOffset; - m_aXRefDirty[nSignatureId] = true; + XRefEntry aSignatureEntry; + aSignatureEntry.m_nOffset = m_aEditBuffer.Tell(); + aSignatureEntry.m_bDirty = true; + m_aXRef[nSignatureId] = aSignatureEntry; OStringBuffer aSigBuffer; aSigBuffer.append(nSignatureId); aSigBuffer.append(" 0 obj\n"); aSigBuffer.append("<& xCertificat aSigBuffer.append(" "); aSigBuffer.append(nSignatureContentOffset + MAX_SIGNATURE_CONTENT_LENGTH + 1); aSigBuffer.append(" "); - sal_uInt64 nSignatureLastByteRangeOffset = nSignatureOffset + aSigBuffer.getLength(); + sal_uInt64 nSignatureLastByteRangeOffset = aSignatureEntry.m_nOffset + aSigBuffer.getLength(); // We don't know how many bytes we need for the last ByteRange value, this // should be enough. OStringBuffer aByteRangeFiller; @@ -358,8 +378,10 @@ bool PDFDocument::Sign(const uno::Reference& xCertificat // Write appearance object. sal_Int32 nAppearanceId = m_aXRef.size(); - m_aXRef[nAppearanceId] = m_aEditBuffer.Tell(); - m_aXRefDirty[nAppearanceId] = true; + XRefEntry aAppearanceEntry; + aAppearanceEntry.m_nOffset = m_aEditBuffer.Tell(); + aAppearanceEntry.m_bDirty = true; + m_aXRef[nAppearanceId] = aAppearanceEntry; m_aEditBuffer.WriteUInt32AsString(nAppearanceId); m_aEditBuffer.WriteCharPtr(" 0 obj\n"); m_aEditBuffer.WriteCharPtr("<& xCertificat // Write the Annot object, references nSignatureId and nAppearanceId. sal_Int32 nAnnotId = m_aXRef.size(); - m_aXRef[nAnnotId] = m_aEditBuffer.Tell(); - m_aXRefDirty[nAnnotId] = true; + XRefEntry aAnnotEntry; + aAnnotEntry.m_nOffset = m_aEditBuffer.Tell(); + aAnnotEntry.m_bDirty = true; + m_aXRef[nAnnotId] = aAnnotEntry; m_aEditBuffer.WriteUInt32AsString(nAnnotId); m_aEditBuffer.WriteCharPtr(" 0 obj\n"); m_aEditBuffer.WriteCharPtr("<& xCertificat SAL_WARN("xmlsecurity.pdfio", "PDFDocument::Sign: invalid first page obj id"); return false; } - m_aXRef[nFirstPageId] = m_aEditBuffer.Tell(); - m_aXRefDirty[nFirstPageId] = true; + m_aXRef[nFirstPageId].m_nOffset = m_aEditBuffer.Tell(); + m_aXRef[nFirstPageId].m_bDirty = true; m_aEditBuffer.WriteUInt32AsString(nFirstPageId); m_aEditBuffer.WriteCharPtr(" 0 obj\n"); m_aEditBuffer.WriteCharPtr("<<"); @@ -459,8 +483,8 @@ bool PDFDocument::Sign(const uno::Reference& xCertificat SAL_WARN("xmlsecurity.pdfio", "PDFDocument::Sign: invalid catalog obj id"); return false; } - m_aXRef[nCatalogId] = m_aEditBuffer.Tell(); - m_aXRefDirty[nCatalogId] = true; + m_aXRef[nCatalogId].m_nOffset = m_aEditBuffer.Tell(); + m_aXRef[nCatalogId].m_bDirty = true; m_aEditBuffer.WriteUInt32AsString(nCatalogId); m_aEditBuffer.WriteCharPtr(" 0 obj\n"); m_aEditBuffer.WriteCharPtr("<<"); @@ -510,8 +534,8 @@ bool PDFDocument::Sign(const uno::Reference& xCertificat for (const auto& rXRef : m_aXRef) { size_t nObject = rXRef.first; - size_t nOffset = rXRef.second; - if (!m_aXRefDirty[nObject]) + size_t nOffset = rXRef.second.m_nOffset; + if (!rXRef.second.m_bDirty) continue; m_aEditBuffer.WriteUInt32AsString(nObject); @@ -632,13 +656,13 @@ bool PDFDocument::Write(SvStream& rStream) return rStream.good(); } -bool PDFDocument::Tokenize(SvStream& rStream, TokenizeMode eMode) +bool PDFDocument::Tokenize(SvStream& rStream, TokenizeMode eMode, std::vector< std::unique_ptr >& rElements, PDFObjectElement* pObjectElement) { + // Last seen object token. + PDFObjectElement* pObject = pObjectElement; bool bInXRef = false; // The next number will be an xref offset. bool bInStartXRef = false; - // Last seen object token. - PDFObjectElement* pObject = nullptr; // Dictionary depth, so we know when we're outside any dictionaries. int nDictionaryDepth = 0; // Last seen array token that's outside any dictionaries. @@ -655,9 +679,9 @@ bool PDFDocument::Tokenize(SvStream& rStream, TokenizeMode eMode) case '%': { auto pComment = new PDFCommentElement(*this); - m_aElements.push_back(std::unique_ptr(pComment)); + rElements.push_back(std::unique_ptr(pComment)); rStream.SeekRel(-1); - if (!m_aElements.back()->Read(rStream)) + if (!rElements.back()->Read(rStream)) return false; if (eMode == TokenizeMode::EOF_TOKEN && !m_aEOFs.empty() && m_aEOFs.back() == rStream.Tell()) { @@ -673,28 +697,28 @@ bool PDFDocument::Tokenize(SvStream& rStream, TokenizeMode eMode) rStream.SeekRel(-2); if (ch == '<') { - m_aElements.push_back(std::unique_ptr(new PDFDictionaryElement())); + rElements.push_back(std::unique_ptr(new PDFDictionaryElement())); ++nDictionaryDepth; } else - m_aElements.push_back(std::unique_ptr(new PDFHexStringElement())); - if (!m_aElements.back()->Read(rStream)) + rElements.push_back(std::unique_ptr(new PDFHexStringElement())); + if (!rElements.back()->Read(rStream)) return false; break; } case '>': { - m_aElements.push_back(std::unique_ptr(new PDFEndDictionaryElement())); + rElements.push_back(std::unique_ptr(new PDFEndDictionaryElement())); --nDictionaryDepth; rStream.SeekRel(-1); - if (!m_aElements.back()->Read(rStream)) + if (!rElements.back()->Read(rStream)) return false; break; } case '[': { auto pArr = new PDFArrayElement(); - m_aElements.push_back(std::unique_ptr(pArr)); + rElements.push_back(std::unique_ptr(pArr)); if (nDictionaryDepth == 0) { // The array is attached directly, inform the object. @@ -703,32 +727,32 @@ bool PDFDocument::Tokenize(SvStream& rStream, TokenizeMode eMode) pObject->SetArray(pArray); } rStream.SeekRel(-1); - if (!m_aElements.back()->Read(rStream)) + if (!rElements.back()->Read(rStream)) return false; break; } case ']': { - m_aElements.push_back(std::unique_ptr(new PDFEndArrayElement())); + rElements.push_back(std::unique_ptr(new PDFEndArrayElement())); pArray = nullptr; rStream.SeekRel(-1); - if (!m_aElements.back()->Read(rStream)) + if (!rElements.back()->Read(rStream)) return false; break; } case '/': { - m_aElements.push_back(std::unique_ptr(new PDFNameElement())); + rElements.push_back(std::unique_ptr(new PDFNameElement())); rStream.SeekRel(-1); - if (!m_aElements.back()->Read(rStream)) + if (!rElements.back()->Read(rStream)) return false; break; } case '(': { - m_aElements.push_back(std::unique_ptr(new PDFLiteralStringElement())); + rElements.push_back(std::unique_ptr(new PDFLiteralStringElement())); rStream.SeekRel(-1); - if (!m_aElements.back()->Read(rStream)) + if (!rElements.back()->Read(rStream)) return false; break; } @@ -738,7 +762,7 @@ bool PDFDocument::Tokenize(SvStream& rStream, TokenizeMode eMode) { // Numbering object: an integer or a real. PDFNumberElement* pNumberElement = new PDFNumberElement(); - m_aElements.push_back(std::unique_ptr(pNumberElement)); + rElements.push_back(std::unique_ptr(pNumberElement)); rStream.SeekRel(-1); if (!pNumberElement->Read(rStream)) return false; @@ -761,15 +785,15 @@ bool PDFDocument::Tokenize(SvStream& rStream, TokenizeMode eMode) bool bObj = aKeyword == "obj"; if (bObj || aKeyword == "R") { - size_t nElements = m_aElements.size(); + size_t nElements = rElements.size(); if (nElements < 2) { SAL_WARN("xmlsecurity.pdfio", "PDFDocument::Tokenize: expected at least two tokens before 'obj' or 'R' keyword"); return false; } - auto pObjectNumber = dynamic_cast(m_aElements[nElements - 2].get()); - auto pGenerationNumber = dynamic_cast(m_aElements[nElements - 1].get()); + auto pObjectNumber = dynamic_cast(rElements[nElements - 2].get()); + auto pGenerationNumber = dynamic_cast(rElements[nElements - 1].get()); if (!pObjectNumber || !pGenerationNumber) { SAL_WARN("xmlsecurity.pdfio", "PDFDocument::Tokenize: missing object or generation number before 'obj' or 'R' keyword"); @@ -779,34 +803,34 @@ bool PDFDocument::Tokenize(SvStream& rStream, TokenizeMode eMode) if (bObj) { pObject = new PDFObjectElement(*this, pObjectNumber->GetValue(), pGenerationNumber->GetValue()); - m_aElements.push_back(std::unique_ptr(pObject)); + rElements.push_back(std::unique_ptr(pObject)); m_aOffsetObjects[pObjectNumber->GetLocation()] = pObject; m_aIDObjects[pObjectNumber->GetValue()] = pObject; } else { - m_aElements.push_back(std::unique_ptr(new PDFReferenceElement(*this, pObjectNumber->GetValue(), pGenerationNumber->GetValue()))); + rElements.push_back(std::unique_ptr(new PDFReferenceElement(*this, pObjectNumber->GetValue(), pGenerationNumber->GetValue()))); if (pArray) // Reference is part of a direct (non-dictionary) array, inform the array. - pArray->PushBack(m_aElements.back().get()); + pArray->PushBack(rElements.back().get()); } - if (!m_aElements.back()->Read(rStream)) + if (!rElements.back()->Read(rStream)) return false; } else if (aKeyword == "stream") { // Look up the length of the stream from the parent object's dictionary. size_t nLength = 0; - for (size_t nElement = 0; nElement < m_aElements.size(); ++nElement) + for (size_t nElement = 0; nElement < rElements.size(); ++nElement) { // Iterate in reverse order. - size_t nIndex = m_aElements.size() - nElement - 1; - PDFElement* pElement = m_aElements[nIndex].get(); - auto pObjectElement = dynamic_cast(pElement); - if (!pObjectElement) + size_t nIndex = rElements.size() - nElement - 1; + PDFElement* pElement = rElements[nIndex].get(); + auto pObj = dynamic_cast(pElement); + if (!pObj) continue; - PDFElement* pLookup = pObjectElement->Lookup("Length"); + PDFElement* pLookup = pObj->Lookup("Length"); auto pReference = dynamic_cast(pLookup); if (pReference) { @@ -828,20 +852,23 @@ bool PDFDocument::Tokenize(SvStream& rStream, TokenizeMode eMode) } PDFDocument::SkipLineBreaks(rStream); - m_aElements.push_back(std::unique_ptr(new PDFStreamElement(nLength))); - if (!m_aElements.back()->Read(rStream)) + auto pStreamElement = new PDFStreamElement(nLength); + if (pObject) + pObject->SetStream(pStreamElement); + rElements.push_back(std::unique_ptr(pStreamElement)); + if (!rElements.back()->Read(rStream)) return false; } else if (aKeyword == "endstream") { - m_aElements.push_back(std::unique_ptr(new PDFEndStreamElement())); - if (!m_aElements.back()->Read(rStream)) + rElements.push_back(std::unique_ptr(new PDFEndStreamElement())); + if (!rElements.back()->Read(rStream)) return false; } else if (aKeyword == "endobj") { - m_aElements.push_back(std::unique_ptr(new PDFEndObjectElement())); - if (!m_aElements.back()->Read(rStream)) + rElements.push_back(std::unique_ptr(new PDFEndObjectElement())); + if (!rElements.back()->Read(rStream)) return false; if (eMode == TokenizeMode::END_OF_OBJECT) { @@ -850,9 +877,9 @@ bool PDFDocument::Tokenize(SvStream& rStream, TokenizeMode eMode) } } else if (aKeyword == "true" || aKeyword == "false") - m_aElements.push_back(std::unique_ptr(new PDFBooleanElement(aKeyword.toBoolean()))); + rElements.push_back(std::unique_ptr(new PDFBooleanElement(aKeyword.toBoolean()))); else if (aKeyword == "null") - m_aElements.push_back(std::unique_ptr(new PDFNullElement())); + rElements.push_back(std::unique_ptr(new PDFNullElement())); else if (aKeyword == "xref") // Allow 'f' and 'n' keywords. bInXRef = true; @@ -862,7 +889,7 @@ bool PDFDocument::Tokenize(SvStream& rStream, TokenizeMode eMode) else if (aKeyword == "trailer") { m_pTrailer = new PDFTrailerElement(*this); - m_aElements.push_back(std::unique_ptr(m_pTrailer)); + rElements.push_back(std::unique_ptr(m_pTrailer)); } else if (aKeyword == "startxref") { @@ -890,6 +917,11 @@ bool PDFDocument::Tokenize(SvStream& rStream, TokenizeMode eMode) return true; } +void PDFDocument::SetIDObject(size_t nID, PDFObjectElement* pObject) +{ + m_aIDObjects[nID] = pObject; +} + bool PDFDocument::Read(SvStream& rStream) { // Check file magic. @@ -917,16 +949,30 @@ bool PDFDocument::Read(SvStream& rStream) while (true) { rStream.Seek(nStartXRef); - ReadXRef(rStream); - if (!Tokenize(rStream, TokenizeMode::EOF_TOKEN)) + OString aKeyword = ReadKeyword(rStream); + if (aKeyword.isEmpty()) + ReadXRefStream(rStream); + + else { - SAL_WARN("xmlsecurity.pdfio", "PDFDocument::Read: failed to tokenizer trailer after xref"); - return false; + if (aKeyword != "xref") + { + SAL_WARN("xmlsecurity.pdfio", "PDFDocument::Read: xref is not the first keyword"); + return false; + } + ReadXRef(rStream); + if (!Tokenize(rStream, TokenizeMode::EOF_TOKEN, m_aElements, nullptr)) + { + SAL_WARN("xmlsecurity.pdfio", "PDFDocument::Read: failed to tokenizer trailer after xref"); + return false; + } } PDFNumberElement* pPrev = nullptr; if (m_pTrailer) pPrev = dynamic_cast(m_pTrailer->Lookup("Prev")); + else if (m_pXRefStream) + pPrev = dynamic_cast(m_pXRefStream->Lookup("Prev")); if (pPrev) nStartXRef = pPrev->GetValue(); @@ -942,7 +988,7 @@ bool PDFDocument::Read(SvStream& rStream) // Then we can tokenize the stream. rStream.Seek(0); - return Tokenize(rStream, TokenizeMode::END_OF_STREAM); + return Tokenize(rStream, TokenizeMode::END_OF_STREAM, m_aElements, nullptr); } OString PDFDocument::ReadKeyword(SvStream& rStream) @@ -997,7 +1043,7 @@ size_t PDFDocument::FindStartXRef(SvStream& rStream) void PDFDocument::ReadXRefStream(SvStream& rStream) { // Look up the stream length in the object dictionary. - if (!Tokenize(rStream, TokenizeMode::END_OF_OBJECT)) + if (!Tokenize(rStream, TokenizeMode::END_OF_OBJECT, m_aElements, nullptr)) { SAL_WARN("xmlsecurity.pdfio", "PDFDocument::ReadXRefStream: failed to read object"); return; @@ -1024,6 +1070,9 @@ void PDFDocument::ReadXRefStream(SvStream& rStream) return; } + // So that the Prev key can be looked up later. + m_pXRefStream = pObject; + PDFElement* pLookup = pObject->Lookup("Length"); auto pNumber = dynamic_cast(pLookup); if (!pNumber) @@ -1095,25 +1144,37 @@ void PDFDocument::ReadXRefStream(SvStream& rStream) // Look up the first and the last entry we need to read. auto pIndex = dynamic_cast(pObject->Lookup("Index")); + size_t nFirstObject = 0; + size_t nNumberOfObjects = 0; if (!pIndex || pIndex->GetElements().size() < 2) { - SAL_WARN("xmlsecurity.pdfio", "PDFDocument::ReadXRefStream: Index not found or has < 2 elements"); - return; + auto pSize = dynamic_cast(pObject->Lookup("Size")); + if (pSize) + nNumberOfObjects = pSize->GetValue(); + else + { + SAL_WARN("xmlsecurity.pdfio", "PDFDocument::ReadXRefStream: Index not found or has < 2 elements"); + return; + } } - - const std::vector& rIndexElements = pIndex->GetElements(); - auto pFirstObject = dynamic_cast(rIndexElements[0]); - if (!pFirstObject) + else { - SAL_WARN("xmlsecurity.pdfio", "PDFDocument::ReadXRefStream: Index has no first object"); - return; - } + const std::vector& rIndexElements = pIndex->GetElements(); + auto pFirstObject = dynamic_cast(rIndexElements[0]); + if (!pFirstObject) + { + SAL_WARN("xmlsecurity.pdfio", "PDFDocument::ReadXRefStream: Index has no first object"); + return; + } + nFirstObject = pFirstObject->GetValue(); - auto pNumberOfObjects = dynamic_cast(rIndexElements[1]); - if (!pNumberOfObjects) - { - SAL_WARN("xmlsecurity.pdfio", "PDFDocument::ReadXRefStream: Index has no number of objects"); - return; + auto pNumberOfObjects = dynamic_cast(rIndexElements[1]); + if (!pNumberOfObjects) + { + SAL_WARN("xmlsecurity.pdfio", "PDFDocument::ReadXRefStream: Index has no number of objects"); + return; + } + nNumberOfObjects = pNumberOfObjects->GetValue(); } // Look up the format of a single entry. @@ -1145,15 +1206,14 @@ void PDFDocument::ReadXRefStream(SvStream& rStream) return; } - size_t nSize = pNumberOfObjects->GetValue(); aStream.Seek(0); // This is the line as read from the stream. std::vector aOrigLine(nLineLength); // This is the line as it appears after tweaking according to nPredictor. std::vector aFilteredLine(nLineLength); - for (size_t nEntry = 0; nEntry < nSize; ++nEntry) + for (size_t nEntry = 0; nEntry < nNumberOfObjects; ++nEntry) { - size_t nIndex = pFirstObject->GetValue() + nEntry; + size_t nIndex = nFirstObject + nEntry; aStream.ReadBytes(aOrigLine.data(), aOrigLine.size()); if (aOrigLine[0] + 10 != nPredictor) @@ -1210,12 +1270,15 @@ void PDFDocument::ReadXRefStream(SvStream& rStream) } // "n" entry of the xref table - if (nType == 1) + if (nType == 1 || nType == 2) { if (m_aXRef.find(nIndex) == m_aXRef.end()) { - m_aXRef[nIndex] = nStreamOffset; - m_aXRefDirty[nIndex] = false; + XRefEntry aEntry; + aEntry.m_eType = nType == 1 ? XRefEntryType::NOT_COMPRESSED : XRefEntryType::COMPRESSED; + aEntry.m_nOffset = nStreamOffset; + aEntry.m_nGenerationNumber = nGenerationNumber; + m_aXRef[nIndex] = aEntry; } } } @@ -1223,19 +1286,6 @@ void PDFDocument::ReadXRefStream(SvStream& rStream) void PDFDocument::ReadXRef(SvStream& rStream) { - OString aKeyword = ReadKeyword(rStream); - if (aKeyword.isEmpty()) - { - ReadXRefStream(rStream); - return; - } - - if (aKeyword != "xref") - { - SAL_WARN("xmlsecurity.pdfio", "PDFDocument::ReadXRef: xref is not the first keyword"); - return; - } - PDFDocument::SkipWhitespace(rStream); while (true) @@ -1288,7 +1338,7 @@ void PDFDocument::ReadXRef(SvStream& rStream) } PDFDocument::SkipWhitespace(rStream); - aKeyword = ReadKeyword(rStream); + OString aKeyword = ReadKeyword(rStream); if (aKeyword != "f" && aKeyword != "n") { SAL_WARN("xmlsecurity.pdfio", "PDFDocument::ReadXRef: unexpected keyword"); @@ -1298,9 +1348,13 @@ void PDFDocument::ReadXRef(SvStream& rStream) // offset with an older one. if (m_aXRef.find(nIndex) == m_aXRef.end()) { - m_aXRef[nIndex] = aOffset.GetValue(); + XRefEntry aEntry; + aEntry.m_nOffset = aOffset.GetValue(); + aEntry.m_nGenerationNumber = aGenerationNumber.GetValue(); // Initially only the first entry is dirty. - m_aXRefDirty[nIndex] = nIndex == 0; + if (nIndex == 0) + aEntry.m_bDirty = true; + m_aXRef[nIndex] = aEntry; } PDFDocument::SkipWhitespace(rStream); } @@ -1346,13 +1400,13 @@ void PDFDocument::SkipLineBreaks(SvStream& rStream) size_t PDFDocument::GetObjectOffset(size_t nIndex) const { auto it = m_aXRef.find(nIndex); - if (it == m_aXRef.end()) + if (it == m_aXRef.end() || it->second.m_eType == XRefEntryType::COMPRESSED) { SAL_WARN("xmlsecurity.pdfio", "PDFDocument::GetObjectOffset: wanted to look up index #" << nIndex << ", but failed"); return 0; } - return it->second; + return it->second.m_nOffset; } const std::vector< std::unique_ptr >& PDFDocument::GetElements() @@ -1360,11 +1414,6 @@ const std::vector< std::unique_ptr >& PDFDocument::GetElements() return m_aElements; } -const std::map& PDFDocument::GetIDObjects() const -{ - return m_aIDObjects; -} - std::vector PDFDocument::GetPages() { std::vector aRet; @@ -2011,7 +2060,8 @@ PDFObjectElement::PDFObjectElement(PDFDocument& rDoc, double fObjectValue, doubl m_nDictionaryOffset(0), m_nDictionaryLength(0), m_pDictionaryElement(nullptr), - m_pArrayElement(nullptr) + m_pArrayElement(nullptr), + m_pStreamElement(nullptr) { } @@ -2236,7 +2286,14 @@ PDFElement* PDFDictionaryElement::Lookup(const std::map& r PDFElement* PDFObjectElement::Lookup(const OString& rDictionaryKey) { if (m_aDictionary.empty()) - PDFDictionaryElement::Parse(m_rDoc.GetElements(), this, m_aDictionary); + { + if (!m_aElements.empty()) + // This is a stored object in an object stream. + PDFDictionaryElement::Parse(m_aElements, this, m_aDictionary); + else + // Normal object: elements are stored as members of the document itself. + PDFDictionaryElement::Parse(m_rDoc.GetElements(), this, m_aDictionary); + } return PDFDictionaryElement::Lookup(m_aDictionary, rDictionaryKey); } @@ -2332,11 +2389,139 @@ void PDFObjectElement::SetArray(PDFArrayElement* pArrayElement) m_pArrayElement = pArrayElement; } +void PDFObjectElement::SetStream(PDFStreamElement* pStreamElement) +{ + m_pStreamElement = pStreamElement; +} + PDFArrayElement* PDFObjectElement::GetArray() const { return m_pArrayElement; } +void PDFObjectElement::ParseStoredObjects() +{ + if (!m_pStreamElement) + { + SAL_WARN("xmlsecurity.pdfio", "PDFObjectElement::ParseStoredObjects: no stream"); + return; + } + + auto pType = dynamic_cast(Lookup("Type")); + if (!pType || pType->GetValue() != "ObjStm") + { + SAL_WARN("xmlsecurity.pdfio", "PDFDocument::ReadXRefStream: missing or unexpected type: " << pType->GetValue()); + return; + } + + auto pFilter = dynamic_cast(Lookup("Filter")); + if (!pFilter || pFilter->GetValue() != "FlateDecode") + { + SAL_WARN("xmlsecurity.pdfio", "PDFDocument::ReadXRefStream: missing or unexpected filter"); + return; + } + + auto pFirst = dynamic_cast(Lookup("First")); + if (!pFirst) + { + SAL_WARN("xmlsecurity.pdfio", "PDFObjectElement::ParseStoredObjects: no First"); + return; + } + + auto pN = dynamic_cast(Lookup("N")); + if (!pN) + { + SAL_WARN("xmlsecurity.pdfio", "PDFObjectElement::ParseStoredObjects: no N"); + return; + } + size_t nN = pN->GetValue(); + + auto pLength = dynamic_cast(Lookup("Length")); + if (!pLength) + { + SAL_WARN("xmlsecurity.pdfio", "PDFObjectElement::ParseStoredObjects: no length"); + return; + } + size_t nLength = pLength->GetValue(); + + // Read and decompress it. + SvMemoryStream& rEditBuffer = m_rDoc.GetEditBuffer(); + rEditBuffer.Seek(m_pStreamElement->GetOffset()); + std::vector aBuf(nLength); + rEditBuffer.ReadBytes(aBuf.data(), aBuf.size()); + SvMemoryStream aSource(aBuf.data(), aBuf.size(), StreamMode::READ); + SvMemoryStream aStream; + ZCodec aZCodec; + aZCodec.BeginCompression(); + aZCodec.Decompress(aSource, aStream); + if (!aZCodec.EndCompression()) + { + SAL_WARN("xmlsecurity.pdfio", "PDFObjectElement::ParseStoredObjects: decompression failed"); + return; + } + + aStream.Seek(STREAM_SEEK_TO_END); + nLength = aStream.Tell(); + aStream.Seek(0); + std::vector aObjNums; + std::vector aOffsets; + std::vector aLengths; + // First iterate over and find out the lengths. + for (size_t nObject = 0; nObject < nN; ++nObject) + { + PDFNumberElement aObjNum; + if (!aObjNum.Read(aStream)) + { + SAL_WARN("xmlsecurity.pdfio", "PDFObjectElement::ParseStoredObjects: failed to read object number"); + return; + } + aObjNums.push_back(aObjNum.GetValue()); + + PDFDocument::SkipWhitespace(aStream); + + PDFNumberElement aByteOffset; + if (!aByteOffset.Read(aStream)) + { + SAL_WARN("xmlsecurity.pdfio", "PDFObjectElement::ParseStoredObjects: failed to read byte offset"); + return; + } + aOffsets.push_back(pFirst->GetValue() + aByteOffset.GetValue()); + + if (aOffsets.size() > 1) + aLengths.push_back(aOffsets.back() - aOffsets[aOffsets.size() - 2]); + if (nObject + 1 == nN) + aLengths.push_back(nLength - aOffsets.back()); + + PDFDocument::SkipWhitespace(aStream); + } + + // Now create streams with the proper length and tokenize the data. + for (size_t nObject = 0; nObject < nN; ++nObject) + { + size_t nObjNum = aObjNums[nObject]; + size_t nOffset = aOffsets[nObject]; + size_t nLen = aLengths[nObject]; + + aStream.Seek(nOffset); + m_aStoredElements.push_back(std::unique_ptr(new PDFObjectElement(m_rDoc, nObjNum, 0))); + PDFObjectElement* pStored = m_aStoredElements.back().get(); + + aBuf.clear(); + aBuf.resize(nLen); + aStream.ReadBytes(aBuf.data(), aBuf.size()); + SvMemoryStream aStoredStream(aBuf.data(), aBuf.size(), StreamMode::READ); + + m_rDoc.Tokenize(aStoredStream, TokenizeMode::STORED_OBJECT, pStored->GetStoredElements(), pStored); + // This is how references know the object is stored inside this object stream. + m_rDoc.SetIDObject(nObjNum, pStored); + } +} + +std::vector< std::unique_ptr >& PDFObjectElement::GetStoredElements() +{ + return m_aElements; +} + PDFReferenceElement::PDFReferenceElement(PDFDocument& rDoc, int fObjectValue, int fGenerationValue) : m_rDoc(rDoc), m_fObjectValue(fObjectValue), @@ -2409,17 +2594,43 @@ double PDFReferenceElement::LookupNumber(SvStream& rStream) const return aNumber.GetValue(); } -PDFObjectElement* PDFReferenceElement::LookupObject() const +PDFObjectElement* PDFReferenceElement::LookupObject() { - const std::map& rIDObjects = m_rDoc.GetIDObjects(); - auto it = rIDObjects.find(m_fObjectValue); - if (it != rIDObjects.end()) - return it->second; + return m_rDoc.LookupObject(m_fObjectValue); +} - SAL_WARN("xmlsecurity.pdfio", "PDFReferenceElement::LookupObject: can't find obj " << m_fObjectValue); +PDFObjectElement* PDFDocument::LookupObject(size_t nObjectNumber) +{ + auto itIDObjects = m_aIDObjects.find(nObjectNumber); + auto itXRef = m_aXRef.find(nObjectNumber); + if (itIDObjects == m_aIDObjects.end() && itXRef != m_aXRef.end()) + { + // We don't have an object for this number yet, but there is an xref + // entry for it. + const XRefEntry& rEntry = itXRef->second; + if (rEntry.m_eType == XRefEntryType::COMPRESSED) + { + // It's a compressed entry, try parsing the stored objects. + if (PDFObjectElement* pObjectStream = LookupObject(rEntry.m_nOffset)) + // This registers new IDs. + pObjectStream->ParseStoredObjects(); + } + // Find again, now that the new objects are registered. + itIDObjects = m_aIDObjects.find(nObjectNumber); + } + + if (itIDObjects != m_aIDObjects.end()) + return itIDObjects->second; + + SAL_WARN("xmlsecurity.pdfio", "PDFDocument::LookupObject: can't find obj " << nObjectNumber); return nullptr; } +SvMemoryStream& PDFDocument::GetEditBuffer() +{ + return m_aEditBuffer; +} + int PDFReferenceElement::GetObjectValue() const { return m_fObjectValue;