From 5f00f5b509327a1b2984c3c56b9207249cfa9798 Mon Sep 17 00:00:00 2001 From: Timothe Litt Date: Sat, 5 Mar 2016 19:02:45 -0500 Subject: [PATCH] Include large file support in SHOW VERSION, work on memory leaks, bufs Show version includes the other configuration info, including READLINE and ASPI. Fix a memory leak in Unix show devices. Start using valgrind. Add VLD support for Windows. Fix memory leaks in main command processing. add command line arguments to history if USEing_READLINE Add atexit() and rundown support to dismount volumes at exit. Update makefiles for READLINE - some versions require you to link with termcap or ncurses as well. Fix memory leak in set default (including implicit set default on mount) Free WCCFILE on search NAM$M_SYNCHK as VMS does. Also release when returning RMS$_NMF. Add nam$l_rlf field to NAM Implement show devices for VMS. When reusing a WCB for large file, ensure that the file header pointer is valid. Add show cwd so it's easy to find out default for local files. Add set cwd Add spawn cmd so it's easy to inspect copied files. Handle condition codes properly. Finish sysmsg. Add standard macros to stsdef.h Deal with strerror on windows. --- extracters/ods2/.valgrindrc | 3 + extracters/ods2/ODS2.exe | Bin 80896 -> 89600 bytes extracters/ods2/ODS2.vcxproj | 10 +- extracters/ods2/access.c | 287 +++++++++- extracters/ods2/access.h | 9 + extracters/ods2/compat.c | 32 +- extracters/ods2/compat.h | 13 + extracters/ods2/makefile.solaris | 2 +- extracters/ods2/makefile.tru64 | 2 +- extracters/ods2/makefile.unix | 2 +- extracters/ods2/ods2.c | 502 +++++++++++++----- extracters/ods2/ods2.h | 9 +- extracters/ods2/phynt.c | 109 ++-- extracters/ods2/phyunix.c | 15 +- extracters/ods2/phyvirt.c | 55 +- extracters/ods2/phyvms.c | 104 +++- extracters/ods2/rms.c | 44 +- extracters/ods2/rms.h | 7 +- extracters/ods2/ssdef.h | 3 + extracters/ods2/stsdef.h | 48 +- extracters/ods2/sysmsg.c | 294 +++++++--- extracters/ods2/sysmsg.h | 16 +- extracters/ods2/valgrind_suppressions_ods2 | 2 + .../ods2/valgrind_suppressions_readline | 46 ++ 24 files changed, 1272 insertions(+), 342 deletions(-) create mode 100644 extracters/ods2/.valgrindrc create mode 100644 extracters/ods2/valgrind_suppressions_ods2 create mode 100644 extracters/ods2/valgrind_suppressions_readline diff --git a/extracters/ods2/.valgrindrc b/extracters/ods2/.valgrindrc new file mode 100644 index 0000000..334700e --- /dev/null +++ b/extracters/ods2/.valgrindrc @@ -0,0 +1,3 @@ +--memcheck:leak-check=yes +--suppressions=valgrind_suppressions_readline +--suppressions=valgrind_suppressions_ods2 diff --git a/extracters/ods2/ODS2.exe b/extracters/ods2/ODS2.exe index 9585a51d68f8546883337858f84c8a8336c01c38..c697cfc252a92be1058f9d2faa548849e875850b 100644 GIT binary patch literal 89600 zcmeFae|!|x)jvL)-6RVv%mM+UMp-p#YNAF13fX|0z;1#P+z^sbH3VB4$5bnZ89*hF zFj>iDn40#%r?d~Y*wU6hrBA5^2@1F&G#d~#D%DtcYOJ)KbWV+;h+UF~twGaCVO49QZd3j%&q}{(S8BU;j9595-pk zE0egry`?SuJ){|ed3YYhadNR_2F-P;|bC8m9KefrEhp1{f1}3{iUAA zpIG^|+a^vNpKgJE<>%!+7mv^Wb?pD#OF#ehCwOo9)|{7y+0*;dKiG5bOMhd}yqC`6 zdBd!;zrKLy#p82+{Q{m@-^zRGGxm)9+Fn zeea2$@>rf8F2OdzHi_fTAZCLZyY#Pkx+#pt6O|~Oz;Q`<&|mDy?Laya6@PZl*T6Ee za`<7-_=Dxy>a%hE6soszv*SQmlKInO8R*SgF{I7jfu2zI|O79Zv~;a-XYz(siI6dw8Wfgrb;*|`4chz}wk z!JIi30pttc_DJ=kD_3)z2g%$jq=Sasg3I#xZmV5g`&A?{nt(Q(6EA@;%J;R$orkTeAF>m=&*?i_Q6+)$leZd{HuGfWEHbG@8ESB* z>PuJ329)9<#or$~CN2oQBl=Kbi9=hKQ{BSvzjs($GTz>XzySLlWWPh~_j7xj9JNWm zQ;UbxvVm%);UZP(@2|1d*p>wK*Ah*1+zg$qKmZlja1mcRLuQRbFa8qZk|I72i?~ZK z{w9?lmXEr84IQbFVYJ$dR&N?_7zUt-OQ;Dyy$QJr-Dm=u?GEZ|uN!%n`ejCI?f_9- zoT}Qq5pkT_DbL}gvr&hdtk^1yX$QG{M)P)?G`+@Is+S!^?-F)9^EtgHmDu4{{e9|C zD9ndSE*i%22dmUSRuWqoKb_^OsqZa(c8I(VpC9p#R}Z5KCXt-{KLT|T0wS2P*1-efIH=* zsbEa#m^2qu273zuK+dB z()sQm4v_xIEOx2B*~qUs?(q6uYm$&9^UZuY<=@0^s+-nmj@iTm! z=9n^}3vbe(>K_^xOpo|dg17lNAWz^KLanPHTP$SKr$ViB@h{(>$nQ^X`^atYl+W8% zJ6T(+D%<6{6e5yS4z+ zMnZU}x;R74Pi^aTD}mYdb8cSaR`VArfxP7=Re)6_kcR@CNhCtER9Iw(a7~07ui?rg z0b)I;F9r(bdh4|$aVcs$YfxNuumI#uEp`$~i9iXf6Sb0*=vAPSH{Z!`z7I@zG)(zo17`Ar`D3We?=QFwJ$bge#9{B`UoK2+>j8(rsUiqaL55Q7 z0;xQzFAZ(;cGgZ8x)XqP#Wbd&THWI~jvA8_4xK_5NaddogE{4flv1)p|HH6h5QS1% zXa7$$PxYs%cLCmnoMUr}J-olzr8ujhtE#=p(yHdb#N5I}NkGK-YHwkJw7fas$}Mz= z4lr;@b5h<-wf^RETkesy^O^$*xm|1T&JEbt-pRiVw2x%sCy?uH+jxDs{s3x%CaCs4 zOUg%b^ZNr1uiq_BeYF*G8Fjt-5Hds)UnS&$nlu$WuK^QkI3ruX21U@>m#gj6uGaO) zisvX6nDj3#ugDpU_?=})&oOdN$!!jPMm=6Qet-V3wlIm`U-G%VA1_1p&+Xmv<4&9O zN6j&#%HFa3!7qT9^A7mqBA_{jd?8`IM=QPf_FoFrBj>ucwE6sg8-tZ#A3{a)Uu@D} zL#H;_`TdhM$K6%S?MFs|H1TUVPviaSar`ffU2VPNqIPs{wJZgF1D$Wpjq;Ff&1Cs= z+nQt_|I0RCWxF^YQRpU!O4Rag=$7Z{71mJ&BDd+{vkBDVLVjE;t5@$!Ht7zVfut4-okWoeARNM0)hCr zii~P`W13A$juf(97b#>K1wvGz&%1%x;bhfU5#>;hddf(H(OyWNv!Ytw02oV*HQD+? z4+ge1S?Z8}4?-wz9}=%J)}&Sl9_n)6n?jMU)}5eG)$+=AQUKzWY9QmBZzfmIapJ^s z{ZEG|kAsqHY~}iXDBlq@F6AF7|InZ~U9NL;qPtxG03DA6P+;V_ zjRrvc@;l|B>uQsX8~ZT|X^whhX2>1P=kRcu52yKX;Gth_0*S#udAZMN^20PC^o27R z@|W5VF3^rFhzDudu`CEDvmo9EMfn+x_(egoBz}RwC6>fiR6AlxIM7WlwkFVzo`QYglF4)S2YB%Lrs6ej0DTXu}q(cFN265 z@nxBhZ1XYGe9YeQtPN>w1gVbrd;}_{k}UaG1KFtSE;W#a$L-Z~0%_9CbNnvpdNq&^ zjXT{~Gt*d;5!8#BY`UxgPVIm!=7dKJB*|l$3quUQKcQN&VSKV?FTAsWaHvTPu!jHsDwJ=*=VbKddZQ9GUAUw9YUADMS(3mpZ}GFN!-Sp8XZV{SJ9 zU>rOEN;CsfPCeUX)_opxWL(ReqhcZ(6x*T+IbpTZt=QEq-)Ta5i~#mGVMHzZ z&TQ46nn}UpGzjcOwJ=+;RjY+FK?8?c>_J?jT9~CkVk`6)*)VM?C)vv#puvJ)&}JcT zF^Kig^)IHw_RRSWj8{kl8d#chN-5r>7N;uyGfHuzQh8dbJP2x~C{k+$DoIeTEV3}p zLSuqZA=CCkq=-mPrLG5bnvRB&R6U69l=FuEgJWn0IyN|`RixyEl`5C~kxi*`E5*AG zAREW~+mtG2&M~FXp%iziN7UjoN|~s)^jSQ^wnQ!rpn}DfW+^LR31Fm8@P(Ge6pLg+_ zHDnp|I}^lfG=Fz+iGEl^5%hT{ATu-J6=aA`UZP7aOox%Z{WO6s>sF7e{vJRze9kyb zweDmECKe@n2WcMC9WgkyR45t5P>RxxyY-)JGSeNg^d&4^UgzQX&=d;$(%Xh0^WmUg z^SNOt{xDP&8+Ic8z0_jGe}d6N+b~oi(BK+W{U>2CoFE-Ey5=DeTlJrSN%Oe8VVDyi zfkqX-g5k-@i4V#fFhrE$C6yBw<8f7DZDGwd75d;g8X27Ew|7c+Rp{Sgua4?D&kh2b zl-_Vy$8&*yen3iXINXQu!bSc&Bv-@XeuVER@OZ=bf9=g{T6yQX-o&)^%BP$Kp=NySMJl>Tzu4?Qc`+REZ?|Fk+2oHj`FE&=4!OsM$)kUJutHz^*~ri; zO^5(5I1)TmJV{ySfgIAH|0U`MWhXIV2>p!7$Z73qn^M-5Gl-tAmYw1E7x^Ootx0gf zRY&~WY#cO&_c$N&0}gD)ww@%235|P-|DfjYDu=e;3W4a+&wpyxp2Dbd5!FD;&5=6! zEgu69wfLY~)~OWlHQN^&$w;lNGc3l?IWtc%e!v&+N#+6xVWh# zs8tzqI9vXBxHPC=gl(sG(LnN!l&DrVMRV1+fPLoche393q1u-DDL8J;kdLSfG5r5!!{5zF@-C5EI!%;# z_6)*a8z0(1anDk>_vSnJ(6`tt^?aJ=g*MS^T@Tn5^~oDkz`b1Jo>_V`sUSWy%!)7w zn<>nP{=#AykjSYis)`$zFVrD*q;n9>6cFd?R}$sI2l;2#|HiH@1SP z%_MIvTEJOj1IM>S{96(LJ6O@-{}!iT{M(4&@s0mUZ~{(w-E7}@&kock1WbtT}|2Qkgo0x7|A{q!pY)~yodMGwXzhj^8mB!`Qj!iWw*VQUgP zwuC+cCP9mss>6rwOS;21#T31U&|l2ZTtUFU zibP985&i0PC_9qg&>w&^bc7Tp^|k~r@;#h1gGPD2@ix4w{ypdbGxz9khX_4q?{tc+ z>>+=T_!NAem^;-%2gRmu&FI7C^sS!F)M)w!`!zOwJ4Fh#P6uvLU(x{SF#{W~$t6ow~B?FLB$4G}hGNnxc<_kPN6`Y)PzNj=6ImmX$a!oiG) zTFd@2*0}X13>atw#Y=ySF3TC5v(~xB2NRs1!Kn%8LDL7@VRFG@*+YC-*vQBc9T(I; zS;tCZ&&ISeYmd?kM>rgRm} zMfvsT6IMIbbsjmA61_$Z!jeDcy%#>N?|^xawlN>qE6ki9A~$*iV#}FfW)4E+7j(cc zI1%287-kW(?SxDUsxdsJeKIat1Mzf}e<{E)kA8ZBE#lqM<#QoWFK8#hn5__`~v^QZM4kk|5@O0llpTa+`Xec2W>KwcN`p!rzyf;)@ya>X0@!(j_MwE`|wM?fnm(w5m; znw`GJW0)Vbd;4qOg^x>Z7s6;sW=BvsN)&LRvD#(_=nxc6Py{JfuxS~;|NhxQ1RkKD z+#vsQTd=LySt6XIOz$C+&_|&YX7&{ree@RUDt@Sj*@HfKIVTGJlmi-=C`O*$@D;3b zdwWpe$hH3*lC(kr<5nO14;anhb%hk5$NL9B{!dV~|1^aq7J zf>6wWr$$p4;F>8ykYev+M5BPF{w6ps z43qXb%GBh5-~!9b1vfGNSCqJnLO(?a3Kpu#RdcKHE+|1Ndq5BJ$G z0W3~I*|>p>sh>^%g-a{Vf^)f*EcU|4d^Y##m_H*~xz7`spN>c_GCzYJ>XWlG&p`?T z-hRHY-_oCIejX&(=^f%_40Ft_PpfDedMx$wiW2>SzXE+=Kr1(VqfCH`hrMsY>%|wo z34f)!Bo9lTlQhR1?~ygh>ha9C5NSw5SO9GMXdI@W{h0Rub`6Trw4VmW0tiKBKlpDS z!qmdv1)RXZD=_l(J`Pc6`_s7c8g7aHoui~+U{kswVO7f`n5+Sa=|2Rc%+Z8g^l&^Y zsc_3N9$mr^*55r?VkDO@7HHsHMR!R7DD{C)vyfF zXp)WfPxNk+W#FD0w*6MwdU7@r6qba%K9GQJfqePcrT&=UkES*>cTuYia_TX zn0_Uz=QA%L65ULVfQXnl_Q5v>Z4P43hKU4H0|eZ2XY3!^K<;x=2ooUSI05aVPIm*T zkTPeafXPOrfXNN~vqu;eVP%9_0Q94^5b$8KH|SZND0do_?G@^}bnp9X6LZ2eh?h9Q z{|V$9f*d`azQ(TPTPqNzePYRTA80$)*7zb}&I!ZS=kHenDII|sc2c&LKv!B533!P8 zY@tM1o~7nHl(J!1p`ZaeXa;&)Q12f^lNi%r3?iCu+zdVeeXZ11trSjbDx8XP{L4l8 z7-^i(`}RzR2uz$P|uDJ$g}=u@{d=9UdC(aQRlU^O&5h&;wBkNzm>gJOtnnqu39 zE=6+yuo|n0HZ7$Pk6g`BfHB6~#mnSA8K2AQ8(EELs zUXZ}Q{6WJ<+&vuE_K|b`giiU0BkCnzwE6)icaDaS4VL6)Nl8%;zyE=RhL0!`nH*SU z&bL#>B!s9i7KexJ?WCPgiFw|DXU*LZ8s(v9XRF=HmhU&A&gQ_(rpBCZgyw@m@`aRI z>b@xEwXK~F4hG;69fB2HIpi(t<2TJA4Sykpm;VhVpnoTE()jv~Q=#!UA;Jh`ff1AV zmlwlt%$VXfnKH#yR?a+6-Ij z8!mc~F(~vUK#RAVE<{s{1ER{zZSZY!3}!xH0$_9sEK1eqkk@5!aL*g>K;M{|p%to? z<#)j|uH_p_ARYN4c9K%BbM2&ZmN8-{%a`n33x~`*d|VFx@56sJ{?Wh4evvn%aNtbmxwt%57cEFisQzv23hnu{tSTtuA({0XISp#Tk8C$#<)Z z-D<$4*rJcCb7E}zpMAU)dE+A_B6_?Jaku* zTEGeeV6w8#T?OBUb}yhPMGR~K`*n8|T+0~~MKmfWY)o8-r;)fGzvZSME)pOm9h+KP z&cCsqzepgJvUCKlf1z$3wqiuDR+qap5cHIIJ4>{&#KaBPY4e?`QyC90NsV%)# zq_RKnU4}=weime4yDuEn7qIPz!&HhS2Cc+$FZK>VZDIwR_HL|35;>R6B&-x;VzH#u z=%PsPw_ zkni&Tqu8{2U8)USoS=>~I}k-sr)2%+|7;iXo)r_+3nSd)pSusbc4T`O`6Jj?2iVza zp|hNSZ7t+boDkG8=#gTw_p61pM}`mTZ(A{@D}enngJMh%1w2|D4V~f}zYi{}^Jz^1 zo*3w60;kR=V0b@izE{i7kU*?P*76FPZ_Cd>EY6Cv{vXAHZ^TYj+BX=}t#4eWTU+3m zkLgxEH1t0cfhS|?lC>PF)eya%UJyh-AN1RU!*<%Pb*LFSw8ej@EYS-W&7A} zu@0U)C=xSe7Sq_XNPio%ND&ybsKXnxNUa#NNYx5mG>s}isTV1dTzL~o!)La66RDgy zsYGy7FQ35xJL8M@kPK_Q7fS6~u8&5an00~iCHls5FV_}fbiBkU0}HMQC8 zKwr#R1!|zsgr*wP`WR5^W>-;)XFM1fPu5+mPqQevirsMKoPs_mb7j7*U=DlO zb{~H@kKC=aWLu&3n*nB^JM)o0vjaZGGK|&IyUpVokBQ^t<3|1YT;6|#3A{D#Q=rINtqfwig9S_v*b3VwogVu3eb@n+ixB8m ztt^;VL=fVGyy-YVeegeGdj>E(Cc0Yc^W3>&qR-n_`}gvkV~4|eK5kC2oA`@w2Kk!W)i8ktg}758iNu}z9e$ABJs7p4_#Ry+PZ)Y41X)@JXPvf>#);g$ooO<4%!;%AqY2vU~R|TsxLz+N{e2Z zd7&XfXjK5tnP0P}0V$wH6(DZleZZ!TT<*a(EM#_Krrq{W{1qUm3mw3a(n@G|SQxSi zFVe?o0ZL<1UkYBAs`qA`%b&@4VEJdM`Lx}%T7C+fcx^=}hXSdv@-QhbU!v!Nne8E`8t(foQPbEof#{=) zb}VrZU^6(gNwHHqw!cDi0fRC_zuPUl~qkGhiV#M{Y#^D20rF_+L5Cm4xDH?1_urxau5bQoPJ8BY8_61?XD2Y#?QLFgoa;{gy| z9(!J+aa#%F5LtC%OmgN$9yKPvRat`(yb3blY!HSJ@f0 z6SHgTPT0-t@1aVW;}_*cC$_-`yd7)54JiPR5heNHOX5woEYV+sRfm!zT>39Wz^{ln zi$^F$Wy^-5N0>W5`YKz~BKK>WUQSD!e&;L1F1Q7tMIjkVWxv^H)po|d<7=IaV{kfo zKjcHZ(4y)&ZvNRHAV7R2g~Y@N9+}IS5=g-2yd*3qPXGg+{4=_Xgy9o?FHQgOmsF_- z)XDr*Lq3R{-QS0On;n#Z!x6>(nSPJlb`ic#Lpp75t5%Zroo1m{5@q>l9ySzW3r4%F zV^5*oTijp!1Qo1IBj1cCI^X-D`nr0KU(lKPsZyNU&_VjA9HVcV{uRJM*Gh#eK@TDf zhBKJeN|N`ilm%QeJ8XWBy_?v@Jk=@s5>k=iA=rgIs5(48(NrR@#Z%(w?UV)SSg-;+ z8NXnvWl`hBKM||24{!kd$UKj(e1GNzZRVA6t!PZ!fv%(a2juWYv?eE9t;|nonvZp+ z45+L0ChUd=CG}nZ#juq-hN2lX0{MXe>e8b>ueMFV(TmKB7Q}K4uLP0CM%AB1M9fC> zh}8Nc=*(uzbZ|po_YUEfW{FIEsAd7CkDPFX(tbIYk+=iBu(VuDOR&tBiW~!$h=PT< z&%E!hzOkh_DUf%Y^ktkMX_JRC_~%sW0TK1hLgd2!?+qe>G7~q}lH2sn%;P!6Ld6OD zS^g<9H&3cRe~a{0EnxGu*9KpsIWVe%gmS%2_{sB%hw^R_Z_2w-ygu(i@%Fq*F%#>B zH=FB)TWIZoo!Xg>BSX<-t0Z7=`YMDkx(S;cQ=!3_{=$BH0$YFnRw+3Ezb))4@7dMY zqXqooZrFw`abU-^yw|jix|a8hS8~<3L>+A5* zpz)46#2@xgz~UiLgL{IUq)w{{j_bI@iS>08Zj`PAXj-xh%=dm;`)g8KA6BtFo6Gt6 z=AeqI^!j?l*p354%UdZwqYCQ2308zvSyHSnROB7nKsgC%mNV`H4`5$`{5M1s z$j|u0N!W->D+nBO@dd!DTLJZZU=c{nV6#?&QC`1OoQ!^2+dCEoUVaqpf_TjL_OA}0 z@FOvDJlH%Tw~g4{W?7^bNldGhuw;ZtVuZNO@TUY!D7CKu%3`%Rg$}w?tQdEdJl_0t7lMq2CWP?A_M4nby)66Snjh3z<{xEjO8Z3;S$3d6~CW5 z42zLgOjLh*1^@C>iRv=!CgQwU*-PQ?AJX!ZDuSi@Nh~Qd+sEa7bNx7N=F9d$@0)e! zAU5_7y+d_(b=bZ03oZX4-fwDsq`JDg@Z2ZxdVijve%AKM4Etx_J$KQOtsZZ(&qp!r zgx~m{>W6YotAVSEgj5bg6=R^(zs@?ls~-DDrE$>y&A$95?4hcI^LENP>i9;evXg#AX4tYT1!cnY* zL_}0z?;nbB>M}RBc`4dsh*O?lLBIP}(r@KXEc5_szq)a8y~sZv?5KSIk- zbsjp?1T$zC7B~{;)NK)+2dHl&LY1~hLhAs8gfL3yUDPjIMYBeVO53f{m>Jh?L94MP za1GpjPsQPwKnP1VnqQ5bRn7LiTlmIG0M5ISZ!E)8E!&ClLhX+D8>u>+Z>e>7yVf{i zFTDL1rEDj(9{=pkNW!Tm11Fl4&?;aSv)7D7vL7*f)BM}e)~&%M#y+B#el|jsPF4K7 zXbt3t*e#{{w;fe-VQ7hMLi;af!7dLX;+9y>%O8F9fFar7g3uY&IJL-}d*yzI>s#L}%w9XrJi;u9q zn~nAhZ~x8vxtI|Xh^>0w2__I0nim|v=6#E^X#1SX#?|vw*5KYLXw@sEW}*(*FfVEa z*au0(SqsyqQG3A9@~()!sDgQAJELxM9Sfl(B5(1o93#S@pt#A4=TH;*ue@bx{N|;2 z$vHKra;ub;6Q1Mu(7CbFO9}eJj?n}yAxz7*sTwguDFYn}aB5OarrotI(HlVP5?HLk z63xFmsNan(+-lhlnxMOho&NJmT?@ZI7rEp}g8g$gb5rUXX_a^t*uuYjZ=zO^1T#0n z%TPI9u?=@hoYHe2AnKZrv~mREYY5R<;F3sU^qM>?LZELn~{7 z`hcOT6xZty4*`Ux`0PfPE=BfklBqucwbh>a`BuadNS`=vy-)6!}$w(FT~E#3k< zdQ@9W)Kw0xnA%zrELT7-iOt1f?y%m_09cmn2913tNt?>`mKZ^ZNz$^=;JN^C^L9(g z7GgQ4s5zTvgS@H<>Dzz=Qb}0A^T;|FFb_1yZ08%3@QnC(2~a4}nGt^rS8o`s4bk7Q z?J&{9Abs?pe8G;hZgn2)O`MMs#7w44#5oXZHV>+vle~7O`aX%+7YfX#x3FCzI+vLx zXkK&Jwyvf3``GFMdl|3{ zX&W3eJFstMtEHf(Fb^EF8rg}F$FY%)3?M_=Liw2zH};W2H})}wKeqV0V3vF|okkK? z{5Gq&rFJTJ%3((k8%{`1NbYXj_PM)GM1574PkG4Vh)9&p+f51ZQ$AGUzR ztb&mz#!KdEL-%~{X85Nuk>isw&t?;kv>t_O| zMHGF6MVlTjxU}WDl#W#c*qMhZD5jDAHSVHKsPDlG2ipri%4_A0)Hz9#j#y#mmjLD& z6AV@^$T5!ovi@qV(1~f`MeLqleh-si#xjOmab}iN1W0ewB?rAq)9M_Fw<>( zM>>-ejwZsS>%{sIANn2fgYB;B=mv3iQhf(0)I*_{D3o?HLc0*cIFr~}iIuqL!sER{bQHhH*ousiP&!@=RHr>@Q?&JzGC8ypkF)%S#7^X>=HCnL#k;j< z6rI_f`KHjh6rOEVLv`yXzzUjuhYsRR9x|k9RqTZCa#PE6LgAB=&{$)zt2%8BBCsg! zXr*nW2ew|3PX{&l#!gr&T8Q=oM?x6@MQACZ*$A0MgAs-qVr_coItvCXN#|G8Yn+&& zSvhsOumv?>Yt;2M&Y->!YZF1il?K)<$3$GnMu;{Mru6=WYzKGZN;LJwMj~BkAYLIz zaS|^I`_De``9wl@FZ=~E+z*9{Y?Hk70RL-eLs1s?xnp0lrLP%Zb zY~~xWb@K&8QGce%_u@hr-05m)DKZoV)zC6Ledw)O*iB=`V$>;eH(l&w5ou; z<5Id6DFl&0{{;Rqlit&aK|rwgFi4dGV_b+a%L8%!p`l69o#JTZp2;=|^C zN;RY-2WB8sVknL4XiOwP<9+3HgoOdcTvcH8G4nA5|32y@PMC}g>c9O4NDIHCL(zzN zGf^CH*b*Es-vWvQAChCF5$L&3 zZ?bXHQdOhsUm@5SC z(D6}E3CZ}^))KXxL7|6AtYrXPvHswEgpo4#sz|__x*&C*P}?x^n)uOh;W$ubN{jVN zenB_G6WPS9kg;JN=4&{G8mtf;*PxOqW+iaeW9@*M6sNH3gE~8%JUNMe9u%@DV=tQl zV{w;<+jZzim+Qvj6xK=6`<9N-LU(~PiY>+HANp?R|%a#nlbG$w3pNg+xHYf zzJ`m0y?AviJ#g~CEMf1Ujdls&CE13kQ@zT*KKust_n|xD65iN&c~xU7k$wh&UOj8b$`HN&f~aGWJn!m?1d6;iSHD1p!-nDKP0kj4B_1 zD(HPC!Ej#rtLzoWbu7ID80IBLEvu;yttWB#@mr*2%synAyx#x?sk4okx-5kL)4IMM z`tz$0kjwi}nJdL<5L`q;I8%*^ltH(|jXy0dITpHoC_gHB)K)MCwWN z&FV2{@J5{>g~_d@Ar3T~NULu~LMM;`oWTLVeOnM@2hMRG#gsRJdWuo&#O7^{Fw$rC zSban})P;BSl-tUM?L?YpxX3Q)DKtrlDW!l_r50*LIanYMJT_W5zQ#nCk}%Ta7s?&K zL4E00M(4_AxrUH}5emOFLP69Kisf$B#0iE^XAFrvmCZxz|xUSxxXJNp5VZl{*}WSp7Ho z{IGayb3$&CR4$+Yhj@K+fh{*+lNQS7FN)Ke3leez2~wVX-VmM51$NxJBi(MD4Ko-M zVohknFrhN)Qr{s_=0kH0OqOpFI*HKNy}?GhS4mZ1Ea7@YGU9g}aOYEW-p zafy7h5vJh+jf)s!8oR}tjC~{w!T{CsDsyl-M-3~DO~4D1j)PGmyWDHtD(V+0*CMxO zy2D0|E#+2jy+NU|h5CaC;_Ic5gUkCvalAi}3|gJQ99YzaFb+ueAllpMVRi~A14QgL zBdmUL5O1UV1+`{mBq4#q+o*mK*CteH=J8T!RjNUM?NPKeHZnK<0d&?vCSIdO^FY<; zT>rsx{VUPz9i@fE73J!zl~AzQ=C}%vmch_b)SL{n3J;OlQV5LqSrQup^cq`CV2$_5 zzCwD?crV6n)q+kZDWqRjEsw>YU13Q9H6W-rE@!Wo^4?T*KZP|G6lN1c4;~*;bab$A z^Rp)N^_Mm?Q-S!|w+Z}|!RHZvVnYF&I9XITm7IHG6EqVHg=x%C;N91dbx^^(ZzR5H zhf?YcgH5ZzyIX0#gN+wBp$JWe1m*b?__g>3!N3b+y|#)HwN6T${CquoywJiPKi+`{ z=1jlX!(KyY@UU1-i*D-kR7m|yOPic?Ol?2a zPGM6Lb)+>m?}ggl7?KwHDl2Za$pmdRlsDVmoM5()(WNQ$F5t7q!a6_@e5K}U)JStY zEl@&Pc;P3r7HT1)j$)#`&;jGZDr7Y}67nE|!0?k<^WkPk1S1ingQBg&dyE=!iKk4F z(0craG5^av9tkxfOxU0k5He~ryYKW-@W~_*#+)8LBLK>?Rvj!qO zVr}{_V3UJnBZc!=VX8H#uc&5;m=|76HuD`A2!g^=lDa@Ale*qdnVzTI7!6nj^c&Oz z*fkHZgw4;9#b6{vS6~^tM>1km!wYi2)*|k+narbKv2Y?56Npk|h^^K^($b87CpxU%Km*Xqxs3~ff`55FTHL7CURZ}XwAP#GppKCA)1VK82s zh*@f2KXS;2sBJX6AzV4}9yOGWfHm=X9yx^dpe4_ZK;_63FP6-FG>A=;s(2%;bS$k>l}ecRPUX!wkV@CKie__%r>m@1{BiM@COt5SI^aLqbB`4MLEpwBjiBa@-1M-a%*5>85&J!-yg+EMA={<^z_PRb&&EDrP9 zGbRu7Hk$3E$@$$3RzGE2WWr(wlsU1OW@XfUpp3ac4tIeKVOtRP6?w?@XUyuZM$v{^ zK*S-de&b0;xsZk={o)a7hX)&YV^b5zo7`6v7coedzZGvZAj2(*yK@lHX$cY=JpA33 z{2)OeB|82gc3v?ykoa38{vjvmSxN#>+^NeeMlk?)8X>*QgY=;OGsYUk;C`7hk~}hP zO~d0hFf%C3B-H0K)ZMT~0Bj=B$=3Sh&5ST>ZTYctTR$R{KU_(?I7vwE50e-%UNG6+6w8*Nub)d(DE)aqVmi{lIPMo0e8T8 z9egbue#prpxDn8+7+h4!QuuIxas!u5(|6h?ebJBWjIza7iahSNZu?f$m<97TdNrPHiFXNc?Mp~SUo(djZC z^I;exIIim%9Ga@q-gYxG+l)lqsK`ZTq*Y_j19Z$URzMh&R`lgjY0e}Iih1j2%dgO; z4*Z|O|2h0m1uFE9_K}B@wgN$4Sh#;D#lk(2-`ov2K)vX3ANGsjcDX6SD%7g)Jw&qL zU}qzZHKZdZ=$hl=ZWTxJawgS!F$6FreeR(4eXI%HOT9!!*Q*b-9Yn{+4l-3j_k1#68R~23I|#WL(dX9S^y0SVSdgOCHzl-vm{uIg zexXf0IF(_JSW2i1378t-7m58ygqFmM7CKE)ragp>Xp=)6-Z9f;mJlpy1KRFLKo*mwGRzJ%le} zsVo);S;lnyYM}*4An+~7iE)-z_O?bH50#)P&R%o{HU113TvS*v##9? zqo9>1654^#CeA^vS&AHy(5_f?O|b}6c!^{m~d1=oh(dP0z+y8CTVz~21Y{l zc&A__bQ&R&W-t^XMbq&MxwYgG`ykvjS?xpYPORau{$|Xg?xkoX2a(VKeiH#eKj4Oj zB!Q)6f)sc};_C#jU??End9Ix~wC(ciGtRYpAdKRKhS#Yt4Yu=9`(XPFF{$D8dcacK zZ*-URqCaT_+=n4gdj^CI~$ zZMg~3o$^KUVdmR%3vAMj@b(MFQ(2pESM{Ty zEZ)V3WtPZoz{Jl9El}OcGzGR&v6U@r`3-9?!fr5AFGMo-H33zFk)TxH2R#tq1|Woy z$()>;4Z}Vfvz;bM?dNb=Vu;$Nu=WP^S}+guSS(xs8(#hqNYl|ci*kU)K3u%Ta^ngm zs{Po0Le8m%h%q*%9n=s}-yR}<7$IT~Iw5}55b?tvVjN;&+)sftlckJ%W*Te08fpO- zEPHGQa8UQP5?l7|VZXcZ3k!`nLt;hy=HwwC?kWUl8&B~{?RfI@Zdj(>pTc&)p6hM< z+^!yJ(`VR^XnFN*e@?*lK){naCsB5KE{@i_(#mPax}Bt61OG&N{muhjiAHP{s| zr7{uKOjJg^0QQTf;Pv*7V?6;hMeii(79Ri=r8pJW5fxui6S}EH35#(=anBUJ7MK}g-6?0OCE2F4$ngLTDMOU;N|w>xy98*(a{qWC%T4#R zJz(|ji9%W`a!2f;Kq6od@lV+I8?z3%!n6&tniKPPs5Yg!M!fCumT|yT<5{099m>Gk53Cn{?J1aN9%FRWbNk=Q%btSdv zCKk=1UMo6{Me{7$ITD@4qKAMv{03kK_S*r=oVnyj6tm<*L1g6)tfO45kKvbWdkf-v zR`d{Sv^)BxSY9%yTZ_hKUCOe4n`L#$hq4JM=_J;Utt?SuiB9=Y)|kYdEOA*ZF=I^P zL6+!^B{E#&V7pl2wPvDK6)B6LJ|1ya#2J?9d>S=B4X`nW7QwdXH#b0-U?dN0@PWE6 zq*w)w_$7jQM6ue2B9U+s)wJZo-ofr4pf}E3L$%EOCknp|=GXHHRq2 z0b&;Bi5~0hiEW zb;yHS%uzG@SLis|h}UmINDbuyNAw%Hhd{MY9<#4bZ6o(lK@S7?GDf+K_ zs9-GGf#{_a{oa^pCyuHwqv+QVjpD*X^zstRW7g?t(;Z(}tu_WwyxKKmqT|(8jfsv| zTZCw;R-kIVEKj`JFK+GhF@WOL8o&I)*6L%T6XsTAEYLBu!@oHUP*xDbA0Ti#c zX-ssywNH+Tj#v8tqN!Sv*<(iNx2x-rpldOSQPI!=#!5l!@Hp*rWXJaIOBakZ&q0L81djfsv|`^MC)&%|2PYimKJ3W zKu~A^G)+PnsurB5O*oKSWDtw~nay8{Y^Kex9wNgT--HTJ_+q0U=048Fuw2-jiM;j> zg*^w`J>rv?im`2dOndYG-q~J1VF$JTcRwczkqKvK7Cbh5 zGGjl2lWFt*2?l1hum;$dFJ2(qj(RP92nZhk69iTUSdeIx$A1yL{50DnkH7zZGGF^C z;{z_rqrA`#3#THdx!()7 zIQw0~ifNRLMTY_0nwp7JKnaDP!ZGIInCIHD+}vht!5qfW}03hDCPT`Tg@$k6xjLSMOiGDYqv(iYor3YBfT!P#iKdxKq+0qh;v zXp|~EHl1cQv=2|EOBfwLqV9?7Zq5-LDb75CFOblw`C(jJ66U`-3*!f_uE4oQMbdF1UA>0L zkYm)$HSVJ8AZfp>;s^I6H@?Jh*T}n=)B&l%d1UzWx^UKg&TPK%D2dFq>UgF2OtT$V z?cswlSg6JkTpP$s`ytqEC=|d&+uDP+d;(s4#@iuXP5GsF)iT_SK^HBC=*yPs=fHpt zv{9rg>GBcWw$U%=a?;aHS=^mimS0)LdPpXZUr;ZPR^#B()SSX*I&U~Y#N9oRq}U^h(h--Hd133kH9 zr!~JD&R}D$yHwXO`DVT%)D3qL-}o{z0UCBv|CpF8=|1f8!hu$h*X!@$wFuIC|D8%< zJFPzjU%r6M;pU;BNhLa{3_b@12hCKU_$iYXoVBJk9;gEAcENvLvAxvB&nBe*w?9jVpvCWh}hy?p2mYR)~v)R{**Qs-f z=jMJowmIhgrX=iYKs#q&D}6!|1Wf}PY4_v4>f}P!kI%C+Gjpz?lQVqd-#|5MKi+h> zneiDx|B(4^`S&u5hrH+4UWXG7!}?Rnq;Y6^I2o5(;oSf~5m= z{})ps&ya?=c~skfAN?3WgoAVvzVRwT$NZLuft7I zkmqnJ+9Nr=pRT{k``O0nrf(nTfXj{d(d#WJ-cMg~-GW)26F+?M5$uFRK$kD6i;(Cc zBx){6AgwU+hyGq-UNx9=3SR-hLHlI%Yx7#&F7!W(TElTV;i}y=Q?ZF@F}@(Q027m# z-h>JO`Z#c|x^XXKCxH=t)h%=lo|p}90v1^6pGqu}JBNMqp$@FU`i-4LA%}5yxsU-x zr5|GNE;*7)Um-YR&O>&YnXKlI;7%dt&v&CMkNETH+_N+19l9yu`62X_In!uCFv7N? z&ti8*J)@z&(R?(Sk1gh-#e8fvAKT2wcJr~reC#wIyUfRK^RdT#>@^?ER~zvkG~dGJ zvMm_mrH(Be(B zo{*I15y$7Yi%EdQN&O7c#5|A0Mhc4Bioxldlc{ockRRUwGB;6G=sllPXJKl9EsKA> z5&b$uvWAI{N`ORH5xXmOZ00SY%TTku9t48zvp`CM)fVM z1I70DXOdD3(w%MA9VUT7!UbE935d%2k;=dlfa%m?!kllsA5F~j@Qnp{3Oh*=eZGTr zX;bMjJlh{K@e~$N`tL4F|4}Smr1V!VOP8&5T5<+mu(g{OogcSiFVhEf-gB_s%{OjC zUYrRsZ{o)#V;B-GFaBAKMGb#q4pcYPtFVPe%Y0U`Q+*vb7uUlYQ|oXgkyE@L8#X2i zEtF%1iCTr3e=^?K#YfJDkGXX?rf`9Nr3~D(hmUVExy6YYF|m~n{RD+=1mVAbK*Yh& zht){H#o1+-O{5R5{SH~B-?Bnh)|WCalD0 z9^YwVniIf2vBNQMJWjDmHxju=-!hjn%6KM4&n~G)ZruI)&-6L*ue^d;fOn!bnXlt3 zw#*E4TzRP-2vWihgaJ6U8Ha~)XSVd-$gxX^N!VQU9U-5!p9v$LHF3!~rGF`pgV#;E zmiAa&Q$VKn36jG*zt4IbHK+$R?Ex;B&&|1pe#K;bWns>h()os7dbJiuYEom%BR=~P zAR7PPA4oZUEEQrf57S&}&NcKa&b925qyxdJ|Kl^Xzy!yCua%DB_S?gw5WH8r-$~zq z^U)W=@`p?e{}!=va6>XIl`q4khIO2_9;cE&jCCs3tVq6#w4dCOBDbaDyDfnHTEizJ zZTuwGLi>@Q!FtCPmzF_^u^)F0J%aVbDqJJ9;UT(eZszx4BhdXsWRK;9Ge3o1dp_*5 zci1D?PKcQt6Ge93rg#`K^aRcnK#t~k3UL=v5LTTra~m%459&8!H{5)5So=k9rE~pG zlKc35*DdkSV9eURBA>H=T9Xc`B@3Kca8h7)l9YwoUL--LyQ>`*-=j;%igJu4>YF1Q z3^R}0CKA-BM|~64J}sNa^yP~bpLyJ8Z~GC2Fl`8hplz&6yA81bC$Ex9*?l}X@Sz8W zO*5aq=RIlUqz@LzZm{<2h=rv>KZ)I||G_jw^zIP|!Vo3=kR{-A>)3!7`?g3>rv+)6 zK(HHW|41mDWkZZ3Z=7TgM9+?GkBJ}Ocmzrv*{;JUz!1vw@{N1w>65++CQK2yOp<@I zzFzt&3pm0~(jahZAS3{=h+fN+=~#v}6xd~g(mnpCP@!#IrjrUO$x_F|n;u})RV zbE%tgtjj@5n%xZi{GT0G$E6dd<=+wI@yRCk4HE0p9%2V62vfV2bAC$VK({cbaEJ|^s#MXaK1=`6}+|Ing?0(;-c7EV)|lcmw1M%D<1%{kYK z^Q`+z0OD@_W@fn1CZ=mlebsB+Eu^NS=o{M@QDQ~uE7wkFo$0akUyMyRZy~5CDPKZ; z8DD|J=bn<#&Y1+Of#t>aUURB@m+%n9e%*wCyLjn~LMth1nVFG3Wk-uk+d*(FE^Ya? z58o|I5mr%_S;!Ktrq?a>dK0}?sDTvbr?ToSPfGaTR)&7o3Vl-B

yPt)s1^g2c8q3~}JrcZy>ea6~P)5$}S>r!*AdOuQ4D`8~P4&Hw9E%@T_p94%? z_%FbJ3I0b7Z#2G@fHme-mTriZn=X*R)uFSeiz{OGXG}SeRamGM+HfJ59hVNa^(5dr zB&L^{_7qnrGqi=uae#u;g@<6139HC3TY!3* zLo<4REA0WRR{W>2GZVWy@zq)^%+q$)>_zCT(6#KS6Z6b{GKb8CECOI>h`Ujy!+!yh zODXb`=S}twij&Gs)}A(F$eYs6%-Ell04TbR#YEuW(ANb7Mw&qO5L`y(K!L944bhBI z=tP#FzWf$V#oGE_|CGV zarGN)9?33uB#a%3T50{sHi300tU)tW=`^%ZPhj>jFtj*L31U(NoeS{p!Pyo*G#hbM zpdh1Pb?{R9;XYudf#Cqa9&swiz86NZb}9D1j<52@zD#lp6zhDq%;R17(_!ePiTA#e*r(cODBs=>Eb z<)J(I&4&O%zUbuTegrU!IE)29F0&u&B5>(@;$OL=uXOeI9;51xiI2tb{g}#Jj;|V7 zVj=5esBWXmfAMXiPm27^Pyz;p)#m&U=YOCpL6Y9h0EJjJa;`h5+pNf1M4}}rOVA8V z)d);A1LKZ9U^W06c_l^P&!Qa+`)CFlv>F$YjcH8FrL9q+u?Q?16nR$OWyi;XhvoKE z`I$c46%T3XrGqV|X)M<{F<*Ufz2)!v?{5*}j*$+J{*Eb_F>Mzt2vV0}F~d9yK(X2S zKYqya2Zi0&0pB06(k`~G*1C8pt~f^Yhv__(oa&oEYs8wREANIfk7LE98ZxQ>ItN^U zGGlx9-OD41v@k+lo{gU6v}oj>#T=nQVI5U|y;(Wb7RzDPcjGud>sN9d8iLv{Xu(%e}eFT!}??ofZPo8@c&b#pa=RShh;W z*ge~rmIpGbowz^z#^6Yn6728rC5+9$H@1)%;(M^a#J2)}i7z}QW6`AwpOkMy`scdW;&+EP7yA ztKq~9!hs0Dh>*&S_o08A#0BP84x*eimAPU}O8wzp6I*%<=e(i6W4*`t z`9H%y?Q;AT3(%$bkHVETA&x7x#ljzGe;sH?{AbX{e}#SeCD^BoV9(@{E!WV{i!Q16 ztwzrt^AX3fJ&?(7_K5t#&^O)d%(zes7kE1*7{YvL6-Yl=n4VxRMOtj-LmEkCJI*c< z(l9~>z&5qer}zi)2|Rqkn18JhcMGGL-98Lp#7``{b(2iifOjV$rirU9-X$4p!MoGI z7vmr!0!Tt&vDOr4=D5bnKEClJVqxGI-^Wb(T)n+^HhmJU44=Hqf-uvfVm4-grd;0yIQvK7tfQ&qpSO?}b7N+{2$^0Tpr+HN z6Y9rZ0GDm7^#Q0cErY?pSHi_aZ(+9R!;E1%96IzlZ>v+TEiy$7wUmt1vWIGE_`+Ha zP>Xp#KHzZw0?23VgSEF?aQ-#Fh(RdFhiF+Y&Lc*a|6M#%D)r0x6GioCan%cP{;bPF zi=R_R(-njw%36e4Txj*l{}=o_w>@5ui|V=gf3f%W@l{n-T zNCW~F2xxASn-|F&d4&qbklc`9NYeYli!~Cwq;fq?>r9=go#}M6>Svta_?w66I2vEZ zCg6~0sbaNCN2bNr+KXY@sEkBp$n#x$pL=ry*k|VV$L}+LJb``BIeV|Y_S@QPuf6u# zdrwIx)_&{GYrjRB29o8TciQhO7kLcYD728 zEe^&t$I!8>8AMM47%pBeyrvK!3=dbwL2=UR7Du=^9k@11*$eRK6*^og%+&a}hn!5z zm9zxWuH_TKWzgqL)K&1jnzjcCj;!8$4t2`iBX*BEQ=qA{A+mW~Q61cAbyeh5v>yt= zfFL+?e>{SQNEwnKMH^U`EbA6FrXSgu`nNBt?=N0}aY)iB0ppBC!MG!e@qNMg|D1#I z^cjt@ih{;4-f3gBrVT|d3KuUueoBQ76w*R=qN}4ImFd=1s>WYQw1&c!>06AUW7mXU zIg3zcqz=7zb(N}jV{QG!n|6(7=o-IT*J!E^R~1dg*HiBrk}BO|1eZq!9@gwbQCM5r zO%&p{--xdkIF%gHV`uDfbnaTuv7EM1O)Xqb8qRp_AXK;vH zU2@sJsy`=#d$KxEGiRyJ?Im$|&YJ#y@rlJ#)AoomM*FG8v#QC=Vk4q; zK`BZA5f&8o9I_5hBt3nn+c?Ehxg+7amz9JuAcv2aAC@luCdIJVBepM95i>vL8eDZz zFEUIxI1&|OHUs%b#F#-EMZ}mRQ8DIU5mFF9V`9wvh%s;3Vksi%pb}$51U*NLiNLH7 zW5xuZZE41hp7CPLIEP3QNS9uYDn^MhhqV~rJhB~IdAacy;axnk-BxWVL9K=ZOd;y6R z2Bf?$kLPf>xKKnU&P{%q%sV^-+&2+C6uC&|D4x`upIPOHxk4j&2nL*j!4>UDvx=OV z3*~XLE|yk7nd&hyQgged*V}WuJn5cAq_4I2t5i^L9L$#|{dhM!)>r9(l}v?wj(sGD17mXTnTP6C94gzSV3qjDww|OAWmEFtaKP{M@7^b+b#J@R=jQ50Nrh3nRL2| zWio`fJuV?Z0E0r=-7r*SFT!Lv+a^#LrsApL%5?abf&`%rs-9?U` z@rKA?DI62s20+J80>o7Uz=`2x;94%S&3r8(n3gYgHC#U;H&HRg{;nL@taPFC<%+eM zwl*Q9&wHb!^bv2Mm}=&w%2P7QpIRT?un60($3`g7BX{sx6Z*--4`1agXON?+q?*H? zfmWE&9*Dv)obEOO{h|CsTuvcklqSK;ly9U{t5@K;UlMTyMT=*Exzj*s{EB=2rSIJx zSN9%p@4ZUmj_&MTEzg3UZeY;AmmC@Wxpmd|p|yq|vk3xX?UnSnDtEYK%N11qorB8Lh_pHEYz7>~ zqkk`&%K?E_>dU{$)x9h7GghJLV$#3l{xp=nax>g3fn2s9XTHhJaGD<@jg@jg+!dU8 zf!0XmuGkfE#y9)%CmRX)!Z@1tth_#5bp8kc-7ZL_9Gck zC35efYtJ_PxPUMsLxHL=yZ?f?9%&>UKBgD1u(=e|RBlTPCx9K~8hZ@Ya z{k5D8&4u4%9G)VY=P`8EP}+S5m&)WHT~ zoU5c5xgEzDE_P0;9JN&ux&j-b(y1WOmIs!R>%}mj*-3m&fa@m742v&ub!w%1^0k`(9nf12V5x6|tsv zsheM-SME~(nwP**`&>}IuGSZ(QN#WIvy@cq*SHGmK?aMB$A5Y^OyoAFI{dR2km!E< z%-3^&;wt_H$MF$l^Azi1d|zWk1IbSY@&FEROwJu^dm2ox;<3nXaJ7x_(RP@hnzkeS zMmi*c)psfpB8?@Ulr33eOY01cCInBS+?RLQQkwNk&0nVk&zN|}QZ+9?a5*6!p{#~v zYrk42N`5f5P?Vf|aGNvpZO7s2daA9aEh4G^ekZBl${>gh&?}Ui)p40<+Xb?jSm3rP z3=EF1(xfF9w>~Ji>LVX~CPOJA5SK3B3NEg10+)0Gj{P5(l=hI4>I~;tJjrQRXKvjBj>UPhiOg)ATC;wViT*U_2jbgMt_z!t()JPSf0XrYehEuE9-Y5B=N79#Z z_`Ow<9-h%^9S_`?yfggJ!;My$A8yN$|vMcrY@qz6(enHU9#1kLUo3@ z7Nq>i@W!XZ!F}PLK{>3-UTowQHSGIRc>z&gw)7=LXS&bJnhPACR`_ygSD6vKs^4>H z*mFo=*-tD3tLG_bZMYb*p8irESv%3qE`jedS*CI2l!cZgA;G60Syn&ZVxcUpKC)vn z*h6qz9zSBw^t2%|D)YS;5m+QEdYDry12@@O3D4`Vy3}r44&ISuhx1a@qt~>_f~EJX z*2(D{|Nd1y;-kLKBXjx%5p1pnSr?6UV0!{J`1-wVFA?!4JKsvjdm+o@U+iUrBD| z{y@sA>_GCWjjp~|CHZ9%z0&fGRD?Yvp^3zMJiW`af_ZtB@_9D#p61Zm>A@>^=ia_( z(W2nI*4;zg|E7B9DY#vH@puP?Pe4;SaLgGN49$p`f| z&UDo3c`@^y{`?QEH$fN9PaDp!1s}?Q6lY+%e9(}&`6;e%%V~pE{l%AZ-RD;14m?` zGAOnGq2<|E(@@pFlr_Z{1;YoYg}Z?vu-^(koqN{RKSC*#eP-RhoOd1XSg*(MCH7Y* z#NnIfF5s5BNPod1S&f_Q(@IYx8}R$PQH|}Z!K$)8a$05+<=EY%Jo-(D)v7xbF1-A@ z)<+-YgMDU~-}uO%^0v3|a?HS{wT9jE!e5&oUhA|Hx!5z2+&RJ`RziO-=F!|UxGKKb z@wxR4sf)1NY_-0ziZ@C?)O1Sm&0CoF(tdS^at4R<71w}ar}f_^$~uQ<%z>)+Swa+B zA!J_ow)xKsT~xK^?)P2N_9U5!yy}y>VKOrYyJ9Y8)kPqP(Edvu!`RWTja(;XQZ!?2 ze3B77F`P?I3x$9fD$Ab=?MyQ`G-k&-Be+nMFp-PYU@2yS*KofzeP!y&X3MfQ(S&!D z#bk5E66f0i15P+LlQg{&JI(gB2MHx#*2aww<=84C3x#$vIAA$)INbAA|Fbf{qVx)I z8H%ufTZi{TmQMN8qGV>%wtj6Ig<-d#_ys;5Fv%?HvOyL&!=9IGkoSv{(RI%X-J4>d zK$2^ZM%zLo3E`sT0jbE=%%W7_N35dM&>%G?y1gPZ?D?S8DoQ8dL%Cn=7%!}f+Pbr& zQX$;u!)`r#9ZL}XMQONsDA@j;y7t&8E7*KmZ?*>io6vG7Yxz z_|N&+{kdG0%;o4*scX+dSjVS%$&}z)VKOPZKbOjL^?gqEL#@eYa|WsM#Ni^FYKzhW z9&0uhn6Ct;NkVQX8RNr=on?Y`v+7ROk`+fqYPfJkYOGJKNQ=%7oyRN51^ka)><>`K zD~g=1zTLcRSrqNLaz9`)WV7dm9&h+R*v_Uw*^=#6^yij}2NB)ABy>7~oYJD8ePd)wu3lP@LGB5r; z@$3?);+#{A<9{NM8;{U$wo8k^ATW>MR@@m934HzAFLey{mp>&}#1+hsBuWuPTuHHN z%y2<^xMo3rN+PT%T(B^_W)bb>c{*IMG`wcHybgp5R&l0r0fWbj;etY|V19T_UT#6^ zuA8d36FmPbO2Cn1i&G`p+gUx*SBFN=@xS**-Fa?r9C+v(u`bm%=_|sG-O;LTUnHa# zWUF{p4q0=kb zc*FhhBbl$WWpQTiLH`Zsz`6t$$!TM%W?iAvw+Cj2POl1FG+Y2zfs|XZ^vxa8f)ofY zpNaq}=5%(@36|gWS0(~?-zP*0o!%I@D0KQ3SKn{>vXfr}lq=MS$5a$5w&ZuKU4TG~ z#OU9_y}@g^@O9fAlEiw_p38jrf+f8)8gtfU%#_hA`3SE`$vrq+zzPk@lq&}_GKE3r z$<#D+!u=I z9X~r!^9N}ttJ0~=(Qetk(Q@`DH!)wV?_a83*m)jlT~Aj)|0&m-1eRK}huvxjvu1zl zPDu@1S|54hV*sWD5Jxk^#j1T+lj2YIwlXnN>_2{jB=aND@5#z4W9oeRtQmHv4WyYg z%SEA`OELZ1AD3k{-mHonZ#>EMNOUhr^kL6i{2FRrl057=A|K)MLxHsTL8k~szY<4R zr%*~GFgJ8IujiLVp;iARrDg}3e7{yBs>T`C&a!aN5$2cm{pClv8vGAZ%AO-pjj?Ob zFG)cJJW`en1g5`Gcz=R1x{%`l4oBV-g&>udY|u!!>SZ#*lTDftNypeS-iKEIsu zk*ZQvySF6DQg8qLi)ac4H12Q)Wcec&B{x* z)-7;7g>RxOl!*bYr;Kw2H1~!PhFf zHe5`~MQP#U!Lvg-lqS7IfzE ztBON1Q;J@!3tKFOO;<@4kh_J)MJa(7@sh2ARivnH=4IP{g5_W8>U)Ax9r?N_fub zKP!)+50hd(e`otlkNJGh_L&v)x!?A2MSYGV=1Qt0%5qf7@n(^IxSKtAMl?FEzGh^H zm^{jyhIg$w;2pmA?}K^9_lNR~8*qP*YbK{gf;0M;s9zipeoUByu(`PFaVu~YI3p=3 zDIqB_Dan!Kj3?Oh_)EDy?6?6@Hp*W_v|VBI7n`}rA_j(j$FHTD$zaH4E|)&Y34%TU zmKR#p7v(N||FotajmI2ods#Sm1kJ^CwTLxZD!puNpVn`F)oRNs=6v>0)C#n5K+?I)N;%w^T$mqrX zR# zv_ER}8rQRTn7e<2fkyAnC#OS``aig)C1WvE1{A zMpAPRyYBBHC9ZLM)@|kNO%?wC)r>tgVnRM1x4 zxS$%{@?&X-cs$V%l%`|WN8B7Ug4#RObHWj19-M3?SUb{l-|;WZJe_-X+f`iS26~jR zXB-DmML6eFMUG~Yp}KJh$MKHiR}?+-l+|;TMCp?^_B$`l^^9#xv4UfnA7e%;ZCj5< z2s497R*j>}vPe{>hk=>s$Y_BHM=+rvdf)N;k?*oA+^Rc9g@3xAD+3S9 zueP_QpC7w+gFQa#dC6_R3kelbn|i)57|N(Nw$p4l60QolC;)v_xz#XGiC0+x;4DcyuH!d zub`P#NNn}~VA{XHXK^Vw2kxVn^NiCt;hSw$hw_Zb$!n$mIZquye*H4dlouQERsTyR zv3grX8>bOz#WV8Ik{Wiqff=@l7RNiU(C2|5js4~v>FiAGka_b+YUB(rtS`ib*DP3_K^_OH?nsmOE$Iayz zp|RuE;9__i64a-qs{2^99(Lm}j=&9!u2#tcsZ}jOAv^VoCdPTtotA_?AA>epmr4rt zuyN*U+8C+oOjYEr-$}sORH>>FX<601TK{HAfQ85D14j|xWx=2-(u(;HJRe4<>URMw z60OS&>+UqGIwjn50u~ppdq2wMx{Kl?|VC#v}MPGM?(ukDLvQzI?1(5g$dX2}A9W0ow1xSma9 zSg0IX+Zvudu}oHNCVbAwuQRB76g4b*p?taos^^=*I%^u0eUTn(^Dp-!tO zSgvRRTLa!BXc+tdSs?L$5`QZn5n_-lRR}!7<^X-pebpyVgvy`d0yWmc`r3frL2bvK zY3~^y?hD|3XDjm2ciyLQqdaT9<$1*6dD!7WeoVY~`U|q0GFo`bvyUlXjEOC^%6l!( z-mog|V^Y}uu%H@Fl48o6W2E)bmz5$c;gN$%50)6}8G!p9A|pJWmIrp>o&llmIphGQ z65~B;MAuv>+FIv7ReNzh73+aHpK?Ccr$esbw9qRqmK7n49BvYx?%H#lT!&VVQBjH8 zbGBSEvFrq|_JIc+c6NqTr5)sMGGU-|C3rYV;4dMAD1Vd>h5-i?Gn5p74F(4VoTNy` z3uF8S<}x?Tm~f$FbfDKckR19t2S|Nl)v({zwdWs5o)t?jH4aq8-zN#5@4q{tfel#G zUNrdH4z+tRAtdmv!2Q0?9VSN43NyHL(^Du_MAEBT%J{|kR}H5wj?%04v={p zML^PHm{qwB9h*+ZALxBJ2R)>7rHQ+;J94+5#~TV^)p|D9f3=JnzAEUEl-g4BO z2%*Gx?eP(p((Rm5I$BK^?YvS2t5Ca6Q>~cvLNYahWz0+8qzcF7*JWv7Qt4pq|_9W*yJSn3 z8hg-CE9tOh2U|TJ6C4UGyiAHUx%)%$=e05>ok4C^8^&J9leUrTf378WZ6|Z#o_Py) zmn=1U*^cqk2I`43=l-Km@gixysXRx?JCqWB!)b%ok%pns6s+zJB<}v5bpPnCqA<4I$7k$O?0nsH|y;2H`&ti0Kl#l+rGg3_$-EcIBw2)QR1jm zvV!sE#xo*Mq_X6GGGZ|F>ZZ8Fu`!iNAC`0*<>=79cSHc1vadDT3ab9oMV@4`f<-1w zpIb@j17gc?U#C)u|+I>?Cazxt=h*FeFs~@5`3$a`WL(Js8qNmp+2&}BQ-gnqFp7#Kn0&< z2#7p-CQ1&|B(DEuF`TYnP~&>$4mUiF1=I%YiD+uqGq=rhJ$rXD%GgTBXQ9s%{mE9n z8QPyVdWBVC=C0?~HwP`$eqbKsO#h#pfi*i0%Rnqvv94!X4IhRGq)Pgod;81B^44P6 zL+RN`iEMUvu4-qhL^|YtqR8}KI%Mc~*Ra$9eMoyt&QG}haXid35?KaUfmCu{X$_+m z@+9vqfk*I*SdDbL_pA_1#R5th8k#LFagw!Z)`6KPq3U`+GL1G7RxfD=svjtSf6pty zq`e#8A9c8%`Gu_I8raCNmK(TPs8d*nu2K0qhPKO$ELGHLW03O}j=xRo4ctTa!P+Qy zV_vz%s2?s$$A|M&Pw zTd_N&`tD7H6HPyRVDBByQRl%Tbfd6!*@h(bjPR1Ww8=Gy zsjC=}UUkhuCz)#UH+ctF=4)%K8%9l6Y9gTwClI{#DoTBj#jvbJGuKB#q{8yB(o3|4 z8?i}yE1A@%g^RBiZDaAZ@_L?h7elAerlV_YO}2IK z0+fnE3*nye2a4RQCfV6lurt>)gSl=v+D~YO_Q80LW=nQIA|P}(!|dg*XNnVC&r~L6 zj_|fJH0Wf+`=&_BqVAUIxEj=oXH#{>&OD`1QoCb>f5>GVs!?2fTBSRB#Jt)Ci=%na z_dpdwxaCI~@!-HL&NF1eG9PfKd_jJ%{G$9O5>TUu*s-eWNT#e(_C%1RFgR~JD(zWP zA*qQr-?itT$UZt3*L{B@FI>on1QBpq1u3roHJs~7aozWA{28w})y?%xKE=OnCFTt( zxIgVSYvY*f+1G1I-~zLZL0MNwggdyN%_I7d>)D^QmSDjV=fxM+FJ~+XM^Hd7nLiD2 ztT%6^Tpnz>CDnwY5TN4B zTJarEu1fz<$9}GK;lSK4EyI-_n)R5aMyzoev5rB}Jl@x%*2_zE_tCYc#K<6GB;+Xr z*L%BAfermWDf1)b2T(91*!;(0^U%rAX*yYG*gXDSDl_L(C9qhpA-(JmZik&~;eqwQ z{N-dP+cAs)=NMVbU>Pny8o4blWo&lJ&#)Lw6Jvel`nxe~bv$X7(Ha^ME@A{zTSGgT zIbL)sPs!WCEih1fRbWwMY`I;9R^7>>;?P;sbsyGDGD4vQhn$f-$v7o&^&vsve}drz z<`Izt@@T>w0YOaZ%yGJ*yX9B;@` zDqJ^2EIu2e5e;3pFW~=d)SP4ald#6Ij6N3M` zC1I_cr5`!?6^b8~;am>%be?4Hq`y!2+#+izt_b8`O|MGWtW|mHGpKtN3CJs*%B1Z-u#MZ_6BknlfLr$lms|N z`XRK)KPnZCl2^JQ1)111xcX#$ANh=PhT3yK@vm?_+cRb#?m2Wi(Ry|0_%)7KgGmRc znWM=M?B2`JzIR#?fT{h?uwyWD{DJ#zKkM@WyY zfA7?1*69a&bw=#7Q{(XTy>jm~P`oqhC8;J-k^HZh!%Ta@fH+;& z^RXQ(%={)+>iFWam=(6lBb0a~<}KFd7lUf{1NZNtn8m7MeEY2O_ZyjYqQ*bgn%Rwb zw^(x{`*bm(*eR28+Ed1Ic7WER6R77|#q-mm>AivEfuo_hq70~SD`8u}F2HrtVrL3l8g^!mLu^Z@=f1Z6GT-dm zLJ`z{yZ*gVT^8HOJdhOWKt!36v_h=t(VSvWgpjDIj~Rk}LX2#I3f>}fC|yo@<5d;a z^La0GOeyN<#p16DTNQEW!iu=^0V$7uh2e2}|J~Cwdii4L2;88K+3N2(*zNr? zIiGr?e-|U@D;18Ry~Ptl#9}HZd(a&L5Zya~fCsJqr;?!@LRB_nt z(1(}J+z;ONp*we;op6k`?>BC|XTpK?--!~$3wY1phk7Egi7^Nx;5v0g1{9IFT&Lb0 zy(s#T7@nv36a2MNOo85`vUS^O`jA5x(-1IH>LV6o0-Z_fMO3XU%HLXpxzFCkd@xzr zdjrqiL!kLkRiT-Jf%2uXXcO7hT9BDsT%UA}yf8W+i1?lwY&5cV#?SpHuM_s)DUFE^#{1h2bL z-7x#f!TvO{H8Z6zg5T&&{Bj0Q{o>TG!VZPBHN3`o>JO5nt_q5tIX)2HyLa!Y-?xUp zo}ykIZwtWbp+8*XIDP65%&gyYI^M~A9nYcn5;H%txn^tFKf@XV;k2P+&deds!UPj} zM27o%GRlXI2XbenH@c0FgNYv>`1tq<GCSrMXTR0P@Vl+#S5MUF0+dC*}rtrNead z*mwZA-6zti)Ge1q3{KgAoRYRAuK(!`kBv8DzB}ur{LUSd->Xi@@3M&eu7022)^E;D zZIQ<;r+QpXG#pkMDmwDH#yUV?1_-Ps`(c%;1|@@M9_BudXN_PAVZR zfq#!m;A2j{hLgrOxedwpaMBsxq|n1j$qJ4?Bj0Tg!TTcbK{L`Jq>7Rw63?!N`MMfDn;Dzq{r_DJ@58A6dxe*Y=w2zmE?bga zHpNfZ_LrqQGe@o*JazcXBi73q21bLqBOm)_T0`p}LQ&{U|M)Nx@zZa&b@O*RBZH-tP2&qj^6~8x*zwz!HAHH#9CgvfhKC#A5 zwWQAjqA)$})CZ0?e6w?b+n(&3o(t@@gbEIVIC#hH`&0G3+R61+$tuSPb~S1JYv(x* z^D^zOu?3EgbKho8Se}x5TZ(T6>(Gw;l-vmf|n6V{;cO2N4aEG+GoOu|WelTe%un7^_ z3lVW)@xl^^I~+V+@pk6`rtypgbdZ z=cB85>>iMhDi8CG%I9X%eOg!SohQL=M7`%EEOUru+;-?@z2yDIQ+erBW^eFIEaBrh zu`glt8b%Xll)C};3FX_EVO z1@^9%I_JF9UNqyui$#_3XNbM>?B}_Dy$xB41MxElG{~3A!U&@rXRf4+Wjs_WnlzZkEuF>y23lXL%=vIL~uqCZ+hcxR^0?2<6 zI->Ou=yYPH5p&7AdpG`0nmcj|cCpuU^wBhGD(4k=v0!Oj(B;u##I&2 z6ghlVO?(BI&wc=J9;5Re0Sciratj5f?9=KaKf`CwyTPQ$?|5OJoDlgNLB8HDl67!& zwbJy<3dk{Rj}8L1e!UQ?nx%mR<@&M6FYxZ|`JDlx4|t8n_8e2QngfyFlHl>XDX%b# zjOEmY5jwFDxvt=%tCrG7x6Dv^ljUhyTMl_o$U$hcBnT@T4n??1;`H~tRpa`h^~vqw z>EZ3paAk71fw|RNmS`$Y?*6E~(_3nJjxOsAcsphyz8qOr?ClKB969xiEeY$ccx8*x zJCv~gJOlx(QQpcJyLG~~dT?5T5%}`zJEtYG$h5j!9&=Y$v2-4ojVF)kcskfiVy#|9 zc0#Wwgw+e{z}lndB>Vr!3^TiO3IUY17|Bdw%Drw{ji6Cw)t@0H&_+ate! z)hoaMbdUW0^A3Jnzxij6t4IIC>hV_r_2}zXk0(0RQradL+}Fa7fJ z2rt7b2O`>7d1tm%h5H^?=l>mWi4H#J2g>L;vHQd1I`0t`1hqGDWqOB6fv*`Ky~!2443vOk$_Ex zn|)8am#fj?1ABBRnHPLFv?DNk+s{J-5%Qs`w{6>4o-IvERf|Hw*uA{jzx7x!BeWyc z5xj=023MO&-?=<+n)Bh;QL$ulV(te0BI*&2n3n1;A7dt+Q+^@` zYxI%a*Mrlas|5FGYTs*|_&zjiPBEv&9ZQ`#5?12ssW-w(Ow|K?&S2hw0V9u5l>wuz zgtnZ3G~C94Hs)D!q;LWpFmjtJN($|sAfw7SM1JVNKo!sjBFCsD=+)i7HV_aXKBp!z+geow03arJvf{TdL-M21uSrmEi* z^?O)_rm6RN>UX~SHPvsr`dy`d7pmVy>UXL7U7&tP6o!53w?z3w)cgDDw}an(2?vCr z{)hinLjd=cCKzP}3C0FoC$1OwE!+=r1Go{~+qhrjPU4Kh1YTkXDY4; zcPH*X+_!Mw#~s1_2sem(4JUt(^V|cz{kVnTPXou*xa)8&xN6*;gk|%*1$Q&9g6}Oj z`THi{J8<{m4BYSWe;-$9hyS_w^OuGoDSrn?^;6!z%==4m-{NSlGCsm${7prI4qUdvp`YvA-edeg|szpofr^Zvhe3AXF@s->7t8BdMmg(?y zIXZsfGL645$9^u;_zRas!!>^QSG2!-xrTEux4&0teC`$cySi|xcvM#xs)VZ7+4*0m z^Ig#uFxxx%-{Re2wzhY8nUmFZ-qqQ)z0(Zr?Dm=&J7klBF=JbMS99amrp~6#UZ1($ z*B)r^+-z>!)M;k42tW~0O`o^b>+^Otd(GyqU}wN@c6N1U-R<>t0c4sBGFom>xZKUn zUcX-wGyQ?4K+tdF$jGQHtXY!f$;x*ZR=KO)(V`f+D zWQq%+-hg?*Al3dhtxnRB-Ei?Zrj#+;oI+!ZA6@ETqe=03r?9%ApfIC(rJy!4$g+CsUTx4dvgsWe%Yx?Z88>$=#BG#tvScV0 z=grc+7{3{I&H8XNr zOkNH7E^PO!<}+KHsOJ{p@4jGX3oKpwvp{i?p1YvL(^ykd*+64-wg`jP4JL0@LEmOL zKQG>LEqN*Oc_n~$%Ytuqc}=sm3_Q{QGmKKRxvBGdse^zQ(r6N#v__Y2r@7M`_>!v7nqW6_fM0TQUi^G%nYe+y zxoazeLyOVmZ*Fgww(9EMsbmdlM&$|lw|LD3Et)+@g>7o@Z1U|q2UdG3U_gv!@W@l) zYtk57eO+74`tlkftF|tfk%$?XlZWpwfIem*3{9_wcXp2ZN#b&oPn;%6w2DkV=PbxplHT) zM-}`nUOz3?q&n7x67hMvJDQs5iK_5%xiMv&m9#ZKAn8fopld+$7W}Hu`0`8!q1+J}Y zyTHREskEJnPK7@F-A&s&c~*9N<4R`wgPUMoBCZk^pdEM^A{Wauier+Pq*?-P$WmV4 zR$8pXFlvP>KwX+TznI?7gFA=T&!sa-|AMrEe^-k?Ysn;uDLA1U$sJ9bwZtBEvVmoQ zYwGv{SQVx+?%(N$Sqr?Rsc_Mxx^2FY;Br3Z7#572AD!;S4Wp>?6`c$v_OPE8(w#TDTOr8>5}j*7(4@4cC_>HeIEfF!?*XR%Ige$F$ zenW+Pn+xhX+jk(1mDk)r-O=Ca_RSDpp?6bo^Jd9ayf1XvzE#m-t^M5Q^|iMuo~gQ} zu1IflTNimI%+J7V)Z0&;MZfNcunzqVL#A!EDpo_Erp+6rX^0OKhNw2R4O-^f}^ubV{6}vQi5-Z-q_v}8(YZPU8V}uWt*B# zX`$edDQs6~hms>YyP_Bv2k_IQcWjocMpwIQ8?C_(xI1*DwGGH`GL@{ z`fLnN)v@;N?9xw0xB&8$| zW{R*>5Az4%p9r6ddZm*2i`7fi6VX6HF<{0N`TfiD~| zp+)Jw##a5994|;ernhpJ=dZ1EqfW_aMs8PXDW)P#TQ{|D4t53A1S5`NZl&_yGk^XdQRePxkbXVmgM*iftbNhhF`-j zG{FxyyNP%b*;I|J!*0yJG51FNX4Fcj5sJ(}CZ;h6&L(3s3ZnxT3C~~-E3hi@sXus& z&Txg`x69(ms;u%W03s>*v0`e5pdQ^`ZSC|(9ldpyh zL1OD-yL_9QI@|A7!-Ikl8TxBMrm*e8P^!I5Rbllc5AQHB;1I@?G4~wTTwk6qJb-U7oqM9car=~MzmW+UNCPs3#9!BrUs#q*&!HdGzA<7D z5|Q}TYDO$F3lfkjtZtt=>Zg@nE`w-MJ2ho?csn;U%Aq{kw3FGSCR;_z^-aEZr2)_& z3(c)fJKDDfw?<(F=scKKg_Kz%aZ$X;=nCDMTQo;(Nem-v?=({jX71J(+h-gj~POxV&i|UNl6J24F z#jDz^QL~7ZhUBpU=fTM!yijWlm68tH@pT2e?RTW{ju!PE>l?tclwd66DKdhzZ@ZVi zRV)Ln9xm;kALZ;Bh=`Mn0QigyEs~DKy&0h;DtJY@~DV|W|E`=GN#}u+`5aOF8X{_A1L0Fa{lh5s&BoA>oD(g_g7jy+X zS`^>yk~yeOY7)+D)$0n1^JpDR42Rj;+|lLtYUVm6tVZ%tDw<(9HTn|P07Nq60|sT& zZH6Cq62ovTW2UV0BmVi zL6=ejDJ`kp*L68T%M6la7n%)Izu2ysgGCor0@~)=ltYm7TV}aeL zJnL#b6@?dWec{=(hnnNB%#t*>vDheWXsh20>86M-#^RinOK)DebcKYKH~CC+g}G$W z;+v6ug6%A(*ia(NFwgJ?M2%sX1wo(ES8qR0p@F~_?az`DOs?3&5^7O&RS$e%Q95FK zv?g;m+4{RIdm?U{Yo}^2Z00C3ovuGwTY$rA8Bnt(J51)QU9GL?3gh$?YO3F^#R`!r zHJZu3%~IvmJTlFQ&!c8*l5{jq18Xr~5Qi#?gRhl!?(3CWQ|2y8+BI3!Ex%qdKT(53 zr*sPc`Bf@v4w;L0sIDesd{oYf4njLc`DV}aCjDX>2|f8Bp4MB$%HW}QXb~P!DF&^% zRZNkk>$|YDMlbDovTADGwRJUmk=AaP7{8_G3QG`a+uPX{+}tK>pQ75AGU!TQDVJpM zCyQaRczTIZ`khwY+G|T{wr{sp^VSx|W|4MT+~O}rA$$p4tR$nd9;RUMyS=k(qgqGI z(h0|8aY@(4pU6S_Ee}k7=wFJ(^}!RD(r6BnP(aPg*nhRy3eU z0P>$yB1@%EJ1Fuub+JIL^pi2fGN+(fV&8f;W(yGDjio5`EKFBvS_EaF4If+cC2OG6 z4f)YpEQpA>qQg>b+g`i3JBBLrB&9`H_TxjTJO5qYoe*iuLWmBnZ>!Qtw|0rzfoYmF zgCXj05egLT@M~vA(cvG7W|+08x0zdrc00BP~$F?89T92 z5wM)a8U%UiSrHO*d@^W`Yp=LCb%2(kQO`W#3q_agRP1<#(%$O9FHf=-OAQKHj z#9vx+JtHVZrl4e7hEHW6vLFklc7s-od(q8Np6<4tekvzwBO?vtm!;1pv!JlLvYhs% z6ZvE<5e1sk8bT6U?;kUgk@APQz{ zHyLA^$*GNqWiOOgEnPveh51?#jhK?CG_%{@j#jS;CC6r29GYrjq**sYwPFss&UJf5 z+e52;z93>yX-*{DFa`uD>cli#?rK`RXwmAeJN3#;cDuieqQuqJIW0I@VH%0*;_>jd zIt@ygEHPRpRb95V&=e(`YFE{MiZMV!QmLZC6UH%FuOhTXYp_X$NjI`n)5^PrlE}`O zl}@{+87Z(|tbnwN&~7;$k@=d;I7UZ&578;7N>F-W#yz(vxSV%!s|J3A8*Dt9lu>^mykFcFU@; z%m`v-A-*bmk*o|TDNIfIVoN{K`W7stTUD~Yw6d|<<1Soj)_4OVaaU<0kOlBGjiU+a zTiGX=8682p0P*pv(UnWYKOSRhS`sIQ6)mDlX$o#-_xIn*l+KeKuR*K?|IfKPKh78B zDw=;~(^DF4ST*C5@u9_(BI!4kwt7|loN*AXlU_8PTrNRHaLbb7{2P=VLxw-rmYTP1 z(2JTI6mjrlR-HShm}a4G8*-MCtawHND(LkHTv%&Ons80N;jQvS1OzeB$!+c0CgU7w zDBT;+3U5F}a6=7Nd}AppV~0@*D^R+HtQE2OgFU(w3P*I))6{5&{!Z4w=zHBFsKC3M z;>JY10>(JXva(2QDnGTtWmE_vinfy^rs9z2@nVdh82z?lUEo9GikcBQp?wory5Va{4w;HgoA*NwLt#)b{qs-ES!4GAu1Nwlp?D@touD&^Ax z^V$smwPv(WM7y!we>7YfON8}WCb%H9rZo*)>NPW+{|eW~)<~x5m+X6tLw&fFcM@9fy^4We?K2(aicOroc-6lpI1b z=$K_qUdCEAwLpB*y58t__KgbM5Gq`4^THSp%NP6P+LDE4scm%C-4tlkRUU)EgtN-l zyFoFGQzFvH959+EMNCQnccbAfT;pD{Xi;qDm7Pl-w>P&mR#kiI;jGG%4c(2R#cVim zE}DWH?U%Uent`Ic#oruNP)ALsQ6&>okQOSfcT`(J&N6KJ_SDp7i&9Sz+kcO6?q~w< zPx6fady4OJOkzY=-5C^9V>4sX@^uR28yK5EP52=0d%TbFJcGMvIrjNW-G+&)#D6Kz zJlrF^ujAQ*tLA+V&j)c&@cszTr^N9-$ny~H1>Vo_OkU%v_H@l7bxFmAEoM$1rhO zr?K2^T#SDj&ve{u{Fm}9#LeZsiszlU%Xr_xb1&{H;GgC>h)d`FD9;G)Hej49+{QfI z8s1m&EW?SN#0H*iIF^%)dw6~mCmR$V;kgfY9q@;E9>vMu37+G)FX2CLCGl|A@?OZZ z7WZ4;TX+U=iIi~<&xdf_ZfOkiJcN52|D!xl;N&lvL$?GcQH?a-P23vZm-5WReE@td z&o*5AAN!*w9>-74!fmMWlos83>#Zy?qOf5sz|5?ovcg^NQSa%E7(zBJ;Y zjl)x^!ezFIWZVk-5nYl>SK=ugo|+nY$0`K5mtjSVYBKOPF*sp1B`d-`e+A(~7| z<0-132IBIoff#S?xTQs<5*{@bRckmhk5_Q*EeMp#Jjq-D;0;<2Ch#hcRB3!%KK0V8 zObjPKBu9F5Y}aG9j$5wk0Huu5rATu2LW{;-t;-+H7ly(ZiObyGt_a&GK;f#c`D%PV zv^t)NC1wLUyf$CLr!LK@TI^6_jtok$V&C8qcsb(UQCxMO4L+qwh_-uP&fr+(0Mf5YRW9JTNk#vJT zC`RYA&|NE*;sw$#^#T+c{^q;1J~s-ZoyI!?}1p^-7~C z>DX~ZuICSVd=1TPMLW2`75c7*2shHoOo%o&03l z0(uTyT~(}&T7sB5qdT&VlvMv$Y1UPhl@_>bVK>Gkj0#qHLj7M^Bv=TK;{hs6yk+B% z2P)ECP&kmi2?r$~`-ft1HJ-HvB{ag6uBvre2#&I@j|H+l7^@bt>xAj7rwGbMf#Kau zS4TTXziRDh+H7L5M4KZpOF2p_YKl+{Llb^_MSF9*fVJ$TAnnbzhFHVFWoe8ewje3m z7YWy%2a1{;^^?>ilCxetj-nS!&N3 z>P#l6ES+gJV+bE97=1~D_hR?z|L3~R$+A&HFZ^b|COQV z2#{4ksZnAxzi1vCu;nRZWE7mdv&zC+{v=(AzLvOlI7yblJv8qSqMn*AorCy|wUw2P z`K651cG~a)CA-F0cD&A8n-QRY@M2|u^U|zM=2Tk;Od(R6BxmWeo4>N0 z)j&C}Nse)f{{2PQG3j1PRuvhhWi|V2Geo*FjA&R2?`gOZ!bZ*sn}vTHg6>hmj@n_d z2|i)}-9I@4;Lg=rzI!}jGM@^M&Q=WNl^-z<*A&*gvETxt16wcc)wZ=S2e{?!>z+_6?n5%!s$vzdI-Ox;-}ka39m-C zn?2@}emUZ|2fw(sTq=IDr#^3bEUrv{m|(HTorzhtUA8+L6O0E1W|P_i0`dgI1T1@V zYkP}7UFm_1UiRvXpU>}WPS^XZAHnb8q?n(|7a-^T$q5ePdBlFocl(EV#yvRsi-sSH z3!n4vc}51#nV+Cwy+Hg-kfWLUf<5bE`On#Pq>ZeZHw3IzR;&JtC<#%%`k=H@me`x1l2Jtd13$y>ARmn@by zlw-Jlq&7AXqh2?n=TCR^lEHjXs#7w*qVV$b+ zEp3z)987%b3##iX#QJCP(nUI74;$>TMdMD!z}wX93pBQOZE9={b~YP-YIFxN9&7S( z=1wE~qgvX#Y($OQT2Y^O23panog3n}LoPF@Jw!xwQ|#cRLXFE=rPDqQ_PqOEqg7U# z8vUH(1t_-P9Ft-J4hexzy-rY2RiTw8G?49$U6ZVSA&u z6J2vxr>qki==S0vFbiRyXQSGyY@nlS^m#Xn0>Ia3he(^KDb6+IgmywcmJOnp@uhc) z<{OQEZ<{PnODxRCvE;=E$nNgOfNYS=me#_A7|D&k&B_d=xt#c2ovoN``@GR?BH~km z8&%n(d5ng|7lF&2q>LoD)mSn4-sm+lga*l7tNYlZH$rE=&CtcP$uCm7 zlziwox5kw{&?b%5sHPfHB)im&LR*`#uSa7U&A$d!kY2$iCGYfZZ&XQh`>3R>`hnzR z3p+>Eeo(ePU8OLHd3S5KP+wDbd)8Ke7OOg0)N>XMi(y4p$KtHTS$3~E4}z`{4{%O6 zTYtLagU?NYlK>E-IoV(`iE}W}rd~~w@j&O|2?p5h64)6JatHSn`0$QGEz3!gIec_#)wrw#{Rey<@j2sWw{gQ7>bwqttJIboq)np#n;* zLg6T#WHVuUucg-)^Ao(~T`j>5oA+b5o~1{pDz8te-_X2ZyDdxY#*FiGQQBh6j`OWm zG=`_K#t~bj_14HPSede3NbLE)e*Xh%;8+4;33D8gOrtJh`^lV|Amb;vG28D_-W|BV z1bF-$zndf=QR9n`n{4~ZnvCF+gi_D-BVeBGX9ALh`wIBX3-~Rt{Uk4!;3O}LF5tJ^ z_PYj{*|?iXBkvqI$#aSAX96SmB;6|8ZwcSxzm2%-Y(LSLkfc$CyVLe#YNg61er>kj z#k@OlO91Y+{pQ$yo58mu&Mz5%LC_oL$Mj4g*c<03>AV8c2W`I`zGY6h8{miI{G_}e z0{4jRhgwCg%l#!4`=ssX!B2D}>nYGa+fNo!#P3QPaKQHKl1uBmOuqpCVjeT^{HPp#vGaQp^whg-D& zll5+63^#(`QQW?-YJZ6o0e&36ycFQKYX4(jCC!a)V;z1k;_kHl1%4l4BlsP|$sbJ> z`-|Xr5|_6*FXmU(pyAHoKUg{G-$q`Yv)qP>>u#9ze}w!jz^??Cx=Z^HZlH|hrwYFo zoczV7+kxK>+=Go8Uc&FByuJ86g3Ife^nY-@+jtzmk^kM^wZ~;utm{Q$VNp_%o2;E| zV*}=G*34Qn>oRLCGAuPpQc_YYNGMEHl260LBDJ!%wb9Kv(#@#cYDHybWu-+OD=RB1 zPm)@xS*clCvD3(`3 z#HN}7 z3kq-U1dqwI-{(TV3aX4)$OBdpEjNa#eN|L89*Z6C>>w=-eVB)+LcIQ}C>F~bzwf9% z7WnC?K1IL5TdY3u<<>wxR-gDX>wZH|V+U!gfwe^Oc>Oy&kd2kouSbN3*tyy(J)MP) zl_ju#W0e`y1sd`&1#mo-My2-x<$g zB^_*bbf9Y|u;i3qw>K4-ff(-tlu8LK7g0^W@u2`%1!8>NReCkBI>gvmjODot*b>Ae zV?cD@2&@S)JRilStpnDK7@oW0@D^a5h1O_VtgbciCt*L(Nrq1OiTa25Y#G25Z|(U> z1=blqs=e*`$%md0Vtan#%W8jI(?Naa0b7pPzCMk>It%UjX@Gx@`9q~g@m4f3M;iiv z{#(2qP-Wn^|HHxwcrFN0%Q+0yvVlp3ryq{z0xMK_yACc=SSKN*(rOY8ORWZ07sd~R zwFY3T72a-SZwO((5wjnqF{V{r7yVa* zdIs>n6EfNftLwS=&J@H8~r!v65q zM}~fWCwN&0csKa|c1oZ!LH#=}trkb>ezN)xO0lqNZh|%|Za}3aDr+32jnpp1cCa=A zM?GOs#?D%{%V|7VSY}4z7W3LFhQHFT>)(q zaF3)EnkQ?QYg3T7AS^>LCJ26=SNqGb)wDf6HWt@+D1F9s2{W_JRrs_|HaxJs1z7^pdGmyJDTz8e8kK<{OQaY8siQy8b zhwG6JkE!yg^vTiGobb7hyCD<6$RzB?hq+MCMOSDUC@aQgE;LmlRdHO=#)B#|zV#!b ztVG(WxbLXF*|cSTrA^>zhj4b_q>(9a>r{2EKw_G&L^YrtfLe;wa+i5%5x>d9fTfK_FaOs2oEY<@i`6s6N+QukWPp~uj2P`+4d~QbDWMmYFt&I%<(8u z)jGcH+;I9R;8WXLb7;hAupZ?QBCJdX7v~U085-e=92;4+%~#DaN<;OTDZarIlHMf9%l`ue;(i^7s%P6ilx4vhXb+rxK5r zPAabKkB361PN|%7d8j{bayiA7lLk!Jv+%|fUb@D^pwZjjk(nN0_AwryuO!=*0b2->{Hg&_@iMMR~UaYmKke}JaY~Ilz+#6 z=E))?J`yKdCtE|Ue5=S>W_@LyXrE&DvoEm6+OzChyWW1y-em8x_u0vg>x^=)aISX- zx})6jZiPGDt#R*mpL2J(UF5N{r%ab;$n#{OoGKT~M!8+4c>Vn8{?s9dsw%LzCDa7-KFQ&6121qla;!G0nK!s50l6Pn&DZm(BOhPt09rt9b

ZJbR?Q(0U`EWj(PvO_{oB3^g1>etq;U@`STqAB2w~4#O3h}a7FFq092+ca* z8fjHpv#dE*rQHIi%bnTI^UmweyUsS}fODjKlAGaDw+eQ$%zfDXKpyFx=H+?i-W}ds z-X?Fm_nmjFf12Olm;Nw+gTL9I7%UF6`+V?9@D{k)7VHYNBK-UXPL3cm$Zh1`$bIBd z@)UWCj6r+*v$NSaHksYT*0D2;tBre&O~z+Nf_Z}3%givjd5-z2S`EG$b#hvBOhV?w`KJBh|x4C=WpWI{Q=`vgPlSCTQl2V>8 z%VecoE?+cN#6Zu|&SLluNo&y`7d0%+l{DFRsKiI#@ukn}q&Hi@( zguoB34C<9_RN%T9Je)|<$Z6z7{T=;%eXIV9-jyDMp6|1)-iPO)=O^nnzcabglY(PHte_+0E4KZ~wbvXu$HRA5a)|1YrawVt$Iwmz_SS^KR7 z`*hoZ4=J;!*>~8FfyIyQJ@)ZVwi93+j(6rc_c%{EZ#tWtB6yK{_fhv1_d|EL+g)Z# zPZr2xd852ru9R=c7WtD*_4;~)yy0G{_ptY}_qw;iYxREcG(Xet>ofl>|2%k^YJaxB z#DCLo^$++5eJw}~k^&lB7=(fa!8^hJK&!!T?%=K~IfnEgXOI!(VlstXLvA5=k{8LV zWCPiRv74al`px=6y*p*}QM!sY)7|u2dKw$VZe-80CT1D`Zro`sG1eGk%qzj*gYZyq zn_JA!%zfq$<}v&v-U}Qu?(uW@1$-CK{6ECTO;7meZxu>Yc1C*BtCiw|MH zUtkP=ZS{xmn`FOizhS>)e`Y5+Jsii$b%r@poN3N|@OQhMUz`-Thuh0F+(EG03)}_n z9qvEeuJUM^B6~?k4uOSUBrlOAu+oR*WAbykPj>PC1kYFRJ?K5@t@Ac}+q^yCJk9Uz z6MvLH-Y@rW@E5^C|KT4U^bWFv{(%z=3MztG!41J3!GmEB`3AV(6oe-uaGyyAljq?h z_mM7oFMW)D4LsLs{cU}>{*9ghpLGfq^lUnUR?r*hd|FHEXg$4)HlPOt8^Xr3iR@{% zo^50wu}@frVH@Wf*BB2Q9~+rwUvrFEY)&;VOzjg4DW!2nPfg$NRsqS%oS(qrTQBf%e(dO^}f`hv(Wa9bP&6MO=8!u*|55! zjZ=-&4bLbto`!cLW`p?xEbeRbDBgoxyqH(;ZTt&P#RyR?=7@XXpI;L1#97Gq;s}h@ zG>c-i4z-3`7g}Sia;w4$!RJ+D?(AoCd$fHSM(ZSdx_zDfH_ZAEU>23e}y;m zi^W9o2kR7Abx-Hdu<3i8<<4WyM$9gOoQPG%Ua5I~Jjc7;`_%i&yUBk8bIA3~uE444L!HWBKX49~a!`m+%sPC2VFo#>gCg3txcs)IEGDe;D3r4Ltrkd=tja zr+hE}o_B+H>LaKqMK4?>t`@UkU$=+_Sb5zemWqePO0in3#adva*dn%zJ>omj%{tCX zv8DYNdold}8gTcKo#>qGq&u0gq(RR8&IzvplDzkp}&5{O{C;%{H%_pAi?@>Aid>y48(aWIY^TA zeyD?`OZ4CnJzp=-$LU3=Q90^VrPt_lQLkFP9;>z``f`1Rz7qMHP|x+~w-(IiJJ8qr zu!cLRC(j zmafD6wSjKIT3fBOTj>F+u|$^4Qdk;0m1VGOMwr1Q%Yk>zV+E{`6|oXl&MH_Ht7f&V zj@8L}X?PZVot6`6b2+Ji@2Vy0U6zCJ=^9BT*+i0jQbMYb(m+;{bzvW$sHcI8957I( zSEJ2Kz}0%RuvJe&n+RG`NXw%>UX4ao-}P-Zj$9oaKySqAoEolmHu{60FI0^q^{v2a zN7Z*8n;)+8U917CpXF>dJm*^0%r>wVwuS9vd)PkK$}}Us>>6zyT}gVDy+d?g6qDO_9}ZdR@r-SHI|5Lno}{V z3@6_yamt)(r^czn*jnpsby_jHlH6oB#mx?{RSVs6T&>M@=eZ5;N?hSIGR(&`OJCQFKh3;*4k^Yz4qGs1U|c6$P@&@j$bk<2%WgopO;_%`eg{w z)31AFy71!UUtiy8TmI|oS4m&m;9j@>Yk#-?b6;_P;d5X8>epoV=fCJ)uYA@0rLVe| zuB>r?`c1hs(2WHt_!8@<}%j^7|e9{k@+}x%tmL z-7`1;GY>Dh`7ivQd2^iK?ff48(ibFx^+`1k`UGLQElYSma59ogb6Uu-O|?xCgrf*~ z)C}GGJKSCPQ6mW(^qe6GS%QrM#_mE3-U)g5%M`p@c|uA{8TftdMuEbPTWvy+9v-#{ zo2`8GI`+5DCajt!2)jNMg#59O1kPwMoNyV-FAI*t+?-j(ac_4FB6b!0HZs5r81cL(b~+u zH4mB@DKq|feVpPx7oap~GsJztj0P=~(H^w79#y8ZT31`h-tNt6tH`SF755%ZdmGOm za3USEMc8_`r*A{H+Mh(_>ex35Jh4sLYfHND#wr}qE_rfvM0R*K7i`SbLXNea#BEkH zOkh@h0*>~Iin{WQ4G#90TaD$!^VofEac`HW!m(+_m%8#G7WDm&(f>*&qe;}!=Zpzk z0IH;GZGCS9&%}uTD#?28_HHVl=&^q(*z|C&r_6{5#w8zlSzPVD0}KM(#kVqlO95rNHX^k zl!l0s5!SZ`MU1tE<5xYKQxmC^7C6T0b)w{Tq}J+(J-=0EGM{U0OrXlGVZ9Hs{{XUl zPS)h8(w61)RbDqqt8{D23bbW~Y+Y&5dB1wuzA@_{NfLe80xghW)#cIGfz=D5ie?Cn z_}6Pk!+KySq}QGe*9DFHrlNT#)I<3ry*9BmibO0h>UnEp7JEwzj8b9Vau8>_o>S%- z*f^;u#`<}9g4Lc4vW)IOP7X0Z3mOB+OMqMeBzu`}l+_Ox4P_>}Pfxb_5}@r|02};r zGMQw7MECoXBaK4HXgWklb+UkKE!r2e5t7YT)((eF%mD*H$676KO-UDznutH@D{9gv zK6#d^?gImricg=$a}BG{kLa6{-5+FRj%1ERPs#-&Uaw7=vgX0ghrk7(gzmgfk7Rk? z*hpbH$b&FxXoi=t6mW)uYFBY2Xw(%@9rL1HiUTcJ^B@utN55V47E^MxjQiM;?sq5a zt1=d7v!f@Ktg`w%`GJGfkYn$^LX;>vg5JaKE7kKCd49VwtLSY#WMhGR&?Vb*WMc+9 z!kY4;NjXECgP`l8N9B3<1KmGBPC<9xHTA>$mBi$A1u<{VzrKr2KO{{ zP=Adu#nGTP=iBO(2=f;Qjc2X}UREp!v4o-HQ9b0yOvw2xk{7O%M!}iM+|`^voohRH z11;!sBYv+PN+c>JW+uN~bmzPzyTv#L* zhzGlaW;tv+G5|AG`fA(uc9$1|@j_9rC$at*t9P(Bi{5673BOX=IW$LFh->m4{kubG za9CQv-^6_@mWul#esQ0_AcU8j!fYV4^LFP$|fC?yEz@8~O5@eXgyeT@j0^WYwv{25?=Slk!*NZg06 zjF%5WY?|P$5W@PZt)qA!3J0Y#JUiGwK7#{ooGG2Qf-o+uSV5gQ8&zqXVxc22ivGN| z@8y!hQBJ%*{r*# z*|GjOy9@Pn-ZubjR)*n&YR@~;h1!o$~lG}#;X=FtCk8T2{$AjtGrQk+Wxl09G$YBX?doHNf_yUz6|yDy-Tf}liS=`(9b?!;dmwFH zlObgZ7E|(=FQ?=vXy4HjZWJQHnvn7M1se17AWHUN^!yj9jxQgW?vfqn|1d9k!zHb> zfvuo%qru})UxoM%ecR<|RE$&^hsA$0R#uEh*3Zr6-->oagz& zRh1FNsXb1LNG5uP)^ry9sWkBsiWHN_7ihi&^V?Z08&?*aAtel5>*3u6!*<$J*>ZbaJqUSbJJIn1^S+Ay^woDh!fPljJPcBYt9h&_TMPn zD+t}E9Tig(T3|@+v&TP+7(0lYabuFA{^asby$HFc_GQQKh4{@tbha6F+NG~@*f56J zkqY^1k;oCB%ich-A!$z6hnM+9#`r{86f(GA)+w`Byu*aYfvAX zE-2Y8kIfR~FC;4$i2Ew0i+gK;_R3;ByG*jq1X=B@C!Ps9s!eAFPRm&!uGso{8smIt zi4Z|!I|d7ae8@R?Kf-Iq^y;-K#gHjy*B6p#S>h~w1OUJT7PQl~aG`)tWie*zjDmh6CDpw|;2b`Vf6%zQ( z%=Zen;g=fXc>i%i^EBshQp;S7`~xnpp!=LbJun>7YZf#LVd^XO33NVofeqpQBA;t=}a|XLf6uY}I#5nJ=&C zhz5y}j}9=6tti$U4J-nJ1%WI#!m^-AY7Wu>pUXq7Cqaule_~$OTJ>~vjoP(kg0f}G zbExF%S$7RvT^Om0o)lYQDG}J_JXYTHq|7vp`y4+LKZM94uMV1sMTq zmRaK+rWT606$%50T6HA8Lir#*4>^!x4j<2H>M_ZCB<|^3Ka8A+DjL$1)6p)mbqAWc zoz3DVQ<@3F#Taj0muX%>0-R z-D6FMcp$_al*igLm=UqxcfU8e22yV2h zDC)nDi{Sf@osJ%Do}xR2`=@qCk3KQNRur%!QwKapWCtH3q0CSA7xLMHGAZWgDn-oC z=NT9%f)Qi?Y-)moLqlRdN5VbD?$&(6iQ(6UcI40y95J5$vpF_td~8CSs4HToc`vCR zhcM9_2Y~iaV=zy_?5dRcA$OJA8_N9o$}MF+r&7TD1t3-)Td|Nu3PYHTGY-RP)fMyU z`d)59uxbQ&jZ4j8i%+6G-O5x9Ip*xXz86>>a(jh7?{yhkwOgw$&@eDnFVL!swd#d2 zZ|Sb5Y=Tx@-k?=`%{l^Jh$fig-YV!0V)toRX1AKKZJ1)t7HP~>n{sHX>5ylPR6-A* zYE3RFs(q!s<$`UaL)?oQV&2rAh~&NAoLi2DAkp+1XV|!yJE8NZMq*5QwPLl|Ehux^ ztL$z53JA$5>f;XEMth&X!ltcpQ@QdD7J_KTrp%;i!4$v)#ViE1tnk{@<^n|VAqulseEwxYD<-kUehWOd86NO@|`No|Vx z%ZV}5gKDHxW1|ZsE*OYX7%jL(jL(WxpB$2%riwAfJM;kjs%N>pWR+m+4UV8O2$LgZ zGa*yP#2rGCi{n0d>YC0MueYoNz=WW0$g!pl;!|-HSO>YR-UG!ph8Ldw77Y1dpHBsi zGeevu(fO!X??(cR1`lSN3t9C-7A!z5ptWeV(Dr4rqLgAH zQDxUdC9u4WX1MVH#BwrNV1V^#wWne}<5nZN3*ny6=TxB<6d;CfEeyzDpL1 z@!G6HePffTm4iP8fUwd281G&*1|>ieR(p!|(Dc}xPmbY%H4W4?+8}T*q8D?HC2*}b zfcw}SkV9Kiz{HSIu5f5((_6DBRymP`(mhB0hFcJ$q^+eFJf-VTUza?Xjx~`v#+=E6674 zKP0P4O)w&Lp2tMiG9%=8?v^nIoc7!N5?l!Ms8|URTVJ5?H=wRM@$zGW z{*4?weIHK^>gIerev>~wHa|;zQpIEAwRJ|&;57y18_Jg4rF^Z<_$Gw}PNO$9lx@9; zx+tIRq$aRqFH>`h2DYmg?CZbC%3YpP=$(Nf!3BQc$}gNGhM8S3Rn#HYT?)n-nx^?a&w zoMn&-^j#zfN-fBzL#dt?G_EDt0WIX(YIH+Txg;qbT)y~hD0xggxZ|GVXaOL5dK5>M znsjb?FJ8a`r;s(cwU6Q=A*pn%4#}WsGRDpS3o)^Mcbt)+JkBrllihA*;R8ikV zQOtK(^&PjrOrp{j7_bFSW6E;a!HX;o&ftiKDHIzPZs&Nsli_3Y#X_Uz9 zBi=X_mUgBUN2zZks}GjFuB`;XbE17C~?oFL0QQg%TV-4hHMThCKJ&Oz5| z?G;;ZMuwR08B_(68?o&_aA&n$TJ3JN=@k0ePw=i@vdOcU?=;Po>=*w=9JS;3sWwmWutufez0suf;>rfwuewfp?tO8@# z6t$Tvhm|131~;oL&^M6kJa?oLnqdxUhC}F^$OpEFWut7NWf^os@NZNCz?KWNo)$Pk z_O?9K2#@LOX=5fgXUunM3o;MRMka1;qYzq78KfbZ>}^;i{ItGmhRw3CX|?-dVyl1= zhMU+1t~9YBJDH~je+8&CW7jJSgOPB^xc+_Of9Mj&Y2bMdv1~)3UbzsB%3^{2nuB8y za|MU;C|`$b!1EO4;dZ}sk?&71sC6l;xIxWl8r1GF4Qh9jLG6w!3~HZ>7)Rfw;_MBU zLCu9pkzF8j+VPY*?KsI-GN&Ck&1uJNSY50sz;xc|Km&kRs10E85#K4Byo|w&RLxcC zWu+~pH*dV11($0zx-`F*Mxrm~B*G?Fkk*w6%xK{9*lR zs#`F$HAZc#lU^83)e-cua>XBj^ngODSKF*)VZgv(kQwMQ!Gyxzp!9HB*1S~K`9#l` z{+`-aI2IqP0x^gMU99Ou$w^Mk=t-)YuOBq>^lnt3WO&{RKFd(PxB#dje}J|@En8m;^t0FgwS;hXzndy5``&?_5e*-YQn}3Ax1D^S;I0*&j%Bj^Oa=akn(L-hY3m>2|}z~taZsgR)rZ#6%b#i{A+){ZZ_ME5wji*mA4u_V0P<9<-KRVFda#jc5eiA7vm(8c^NhUu9j{s5v} z6c#eW90>E3t#)8s@H%i;5)7#~JN0U(wusH}9Fw!zW|#I256FcwKaBdv$n>mt#N5RCrk$w?D0Vzd_sOlA?Ww=O35Ex;#G?Z7Ij)-)=9^GAq}#2uExuzhRNju^4E z9l>mqT~iWe_h6KmRJPd;~sKT`*)4(28`Hj10a-av@?z&&^=d@t}pSB%|S!O3I&4bsniKVtSalRg0=Gs!1TqtE=c4u(lT5|7jASp2Wh zNi?PO3hGNUST;%5>MN;%elz!PObx3m{lDo|p7Ub#xQTU0i-~e1#fG2=m#~)n!>Uz2 z2EztzMScU66c5x=IhzzPWx8af_ZBuAawj>BdLoxS9B-yN3!4xa`wEY-H247Ayt$hC zKNYcsOLp&%3DRPcl3TJ2nkb@Vg_n$eT6iI?pQ=qxLC$}Uy0?~%vgiQ{(%0?Uo%Bc& zIhRX?h&`6gBYU)B?M@0poa9J{g#gQlhWaJ5Xz<`mMy#YRZi~plz=C4Fgh=4piiABHOBe7SbB05x_fSa} zYL1RviKZm8Xk^v0HNRc+J2bzOOM0T-b9^xF_mWhPjP%u^&Wei8xm?A7_-4D zjqV`K%*G-v#<1?sivWBq?!QJ8ZkQ$S6Ec%^F!y!>1~@l*l+!A&0i3P z15U8df1S-xcY-@;Y2EqqB2=O87Z#&^F7aS_v3M{$2`VIy)oDH_oLmAmR!okz-e}2UfL!gJwOg;6LM2 zFcQ&{ZkI9x7+p+VLYdL&z=Vz34!1$h&|`wYYSMFU$eYqJrRS-~Lz~=&z>u`le9PUA zx3IL0zdg4DFF|RGmGBv!a2uxJiGcKxohQmw#HRV{a9~@AyLD6B{wKvH`EAAXh@YXlvd)7WE(y%YIYz4)=>K zI)a4^m*oc(C<07{;tm~AJ#tt1t@3TQUN7gC zFOp}72fM&6&k&Q5m{4Y66(A2Y8a`^L7J$x)Pp$zk4?d0yyrRo*Q!qVq;3b*)A!y_| zx8X+kZ)J-IPt^F6xjRz8nrE#I+(lK8HNBifW1J60ZygPRaj_ zW^C}$)B5)LZS_-IF5N1B5g0i^-jYOM0wErJ6X+OC!E<rLBYIw!dOE{vVFp=I^c!fC@)lYrs;?p|weX|Cc}PAk zEfzaB!h1HOy`z^A)OH4)ye9T;T?z1>9KTVoJVVKE-n$ z%jP~e62fdUX)*2Ck(Y{lS7xbQ8EUsf{p01#fuioM7ik^viD@G}HmuusHQV=0lJ|oL z$@PG&M>n4)QGs>w&cYPat4(e}o-M7q2mz4N>lU&-@3Kj7$;rkVcQT8M4;Xyx zVR2tgMhH?lJ6I*<0TPsIvmTITkZSO;MiIj#XRfRrH{k``80`}9E{}P+4a-<{luJW+ zE|D?sRp1NK!|O?Gs(>%}h;In%X0!$a87rDt2^ll~z_9|&!VJN3%kN3wz+xd##kr0p zF|lB^lbwHRg~`0O{(VE?d;7g-fEl4z`(Py!3ojsHhh<81P>Z@(M

qh!46E$VxPm{&D2)I)H8nAM7f!Ga{W;%wlfcyG!!5GT_!*vo`%Z$`piS~zRz3|l zMKLS`3~@yj=4h;jhmBAFJE4%=#x&@!0k?*6F#tznxUpi~p+soeWF!Jf_Q3H6i$G~C z2XpH%dSX#OI_Z+4x3+dubwYZ6aRge*PIMG>ToxD(mK<&KXE9%a+I_h}o8F*BGTI{c zAUx?wKoyJroon7^ri(Qv$qEFieP|r4J@#L)xwV2piK>{y%{ye`-eG4K%!F} z!9`y@MRm-#*fLGZaQWh-Q3MWLAnS^(I+iH9p#C|Fi!~b`%+)^;tEoxH##>0T)aL6I zj-r9BJ=7jh-uT*gumLPV2Kk#e~(xWoHo5d zJm`9rfHZiHt>1)|c+YP)JjDA7IfB#;m0`5@Gw#Fjn@pTBoPpz5X9iBXTjtdLKGLu#lWc?$3|UE=p{TQ61{wP4v^h z=WReupnVYPYJ$eC1eLt{s8eGV2i(;?W_~mMfqi+{)&v5=hYYTeLImmrP+uqReJtxB z)GBDmIi5sw220doBU7lxxEIB6kWSBATPEuZ_hycG-fB9Z`3Fx^PSc{kOiyJMmUw=E zoRo|LZ|wZLhK7doA9P>LU>|jVa9!p{to!@tFIQICi`y!bM4ZdECyp`nHif!aBUY<2 zARX<&2Cd9E@djbe+0qQB^vO^#+Cvp>5r^6YKf{^l;R^$5D3fD;(z%6rHYAA#yI6qQ z&&|=d{EqYY$9ad?2>i44EL374-NgdyG??u{Lm_3cMvHFY0t)+d?BKIJY`)OypCS91 z{wN}}4vDTWJwn&$I=VLPhG`VuqchfeP9F7!ncR?u~>97@}oUM+{eBST1?h`+k$%SE-YEL1w%Z0JF+7$Iy`{Dl0pEmIF+z% zbe7fcYD$69o+VJsw}-|92Mo#W+1RdAeyiAeAK;hYD7IGM9*fFWf!N`*-tM`y(E+AC zVrahISlSeyDnOc&qh+;jcw}p}tr!n{t;sA>moZ7(O`CYOhnP}<9xX=6hQoYn4v z*XY&@m!A-XO<$p*zXGGazPv0O*zvs4G>L8o(S102?iTQRDxk|c5e0yvf$EN1nA+~-8Fj3%kj0|Og-Qv?Vc!y1_S1ATM>)pC< zJ20vTp251r?wTOuEJjG!#(5o!a=d0if}(6EvBpf;%1(IP%?av}>~K)`Js&iFKFphf z+QF1izeC&ysj;0k?b4Uto?%Kj&DZMb5!JtgjDSA6*Pn#}GTReq71dP~WYJ&+rvZFJ zxwD!}y@d5C^#Jh@tgVA+Bjeo8DmYixZVPj+tZfU2f+p7j3lJ17#(#bU5KX&G4kz?} zfXss%a3PM0ewRS`c8Yt0SxeM+FY9tfHcTzoKp)FcW{LamsnVKuZA~UYZSh;*Kw6J) zyF7^$f*s`cyaPB?Q1kau823j7+cr%u>GHfS{;(^KwX|$F^CrZdJ*)?0bKZw+aMB*c zC?uFbpKy6D$dv9?v|aEdl&n`#h%nYt@>pe2>ep}-c4Y^{b%yJlg$d$mWqvfd`FhU@1+!$T(^y-cEF)&idzI!L@fk7S4xuHP zae2 zjZ-^=DAatXL0+$YJ`y$-V4V)dLrjy`fwD(^-zLxFM9l?UvGp?Yu)uClAYW8JqUTzx zGlmWAIOkw$CN_%;N#AaAN`8h6U&-eUzYT6woliq1>N>!et8c zwXr}8yrGbFCpmXQ?(tf1K>2BKrhw||p#@`bGAuaY@~qd;6u}fyR|kmMidnUEh@G6z z#v#7YZnh6Xg1AGz)#6?gaBK-52$g9>N6?Vg()j>Wj0cPdXq~wZ_azHVnl{D9L+JY$ z=A5ttV_u$LNBcD4av6mGWQtI7E!pfU3TgME8w=#}XV?Ja8+;nbD^0OgVH7VJAhqo63S;M;#sfKJS=4VvX4+@C!g~Sa$kk{$+Qn(Lp8Qj2eIq0B$>?J12vI6 zXzl8yr2L?IX^ITf$Y{yyWdWzy(XFp4v%yikNbL#+u_px6s5EOEHnHVoRbUde8!!OD z+L+;UwB_FuteOZ~`3XQPmD~=U)n~tFN|o9)ihWizEi?^nWIP!GNax2vBE4x6CB{QN zm0r;Mwee-uG2_4lY+L@hFqXjKYB-oAOXFsY;KThW;rk^$HAOuUn9~rM0OKH1{N~?L zZ@{itWe8hpuwDXx`E0hBysR1*!_sh;(sA=isf&hDcwhONU+)gvgk zfJT_7v79#O`mn6+<}ITISoGwzYhbA}=Yc5YE+`P5)-E~Uv^6{rgu-wElvMfQz&5Kr z8~z|?XnTnm{Wa>K)t^;+^Qep-)^rvQz8zQyB1^1eY85;gpl+giVrwgss!xztAUO%N zloqmUsV&M}Z{sawUQHfD%_-r(BN|mlww6-2GTDnbJjmx87r^A0vaQ7Kt8+nL=0@Eljju3Va0S}|tF(MSg9#JcAC#YCI;8rB>;Rkaz@E8nH_{=Wr8IIw zdV<-%4W1r`(vPJSEZlBRLl%_lF=Ua|{mR5CdyG9OE&YUS>6A#7k(Mq0>e;TwPX*)3 zY)z!|tQ`v}AHISfhsAQ1Z}a3Se)T`?aE(+i+BbY)uD46B>NqK6W zWanX^0t5$~%xMMxGf#mK;B)w*>u~7noCDC<+CdXI-zhC{+VF#{CfwA1b!Ao~9BJ0T z6BV13sU^Pw6?EU3pmZE>eZETwi8D(d9{{}ZCeVZ*M>go#*cR5J#Sr0obRn)%KavHF zZ~Tc#bEPo(l8JyEg*Don+)T10nC_?gVI{=S)fdAX|}nQOzb%0<)D9B z;7w3PJvLisIb0}c7kek|SB5KX!5BbvIhdZDX4)7H6++9sSP>PYccC6wVx@6ujq%Tf zTyr&pFKzvk z(1Ky20P7ReC2v|Jwuw4J6O(U!PuPt4GSzSEC3;i}Vc}P%l=+;zO>$OeIUoe3;xsta zlj?f`J_~7a5Jgh{9nvfRW@6zgNiDwS^Rv_Tbbi3t@bYXFeozQh2>OBGrDXElPhOr$ zAuT+l-wc^bAw&058X0;7(!j@2IGDeTLfkwJoAwaiG<_lB*|dlGb18p*gg?`60{EKn zXD@$V&YxZUImn-L`130MoX4M6^XGg#zx*UhY|!*w6b?47&v_Y5p^zU@Y@7M~Jf2Is zQZc`v7<4d7)k)7*j#uazx&(zEN(=A9GxXzV5O*!QfL{yvwUA$z^XnddeUV?g`1LTq z9_QB+xB~2ec{_@m9zDflB;ZNc3CDU=rVyR5tLub6E$T$bYp|OL=#e~qYYVGFFymB1nT68~!=u}ZXN=VZ57w8)0h+JaVbzXbDAAzwbVU)N|iw+Rzb+)wr zg$aAEu>`aAP*I=csK5e_7CnJfvFLGJpPz!w@X=Fv!h}>Xp605aON%}Vh_pIMyCSF$ zTdLp6t!5AV8QE3j$!h;~X40RzK?_-&MivJ%WRDon*mIpcby^Fr7s1=(l4t%*Xt4>( zRCxT_QVDGoN}UCvP|(cmdX%skG~RzGU0#wxB(^SsUtCF--eKbV6viVoX%!04q7U)w zQht4yUmxMuVt!rCuM%DLbpWp&co^4MG=VE>X)`uQP#Wn|yqq7Rmh4%oIqSV~EgGyv z-R6tgrfR&zr;qL5HB&~n09a;J#*-(LQ6*9OWjO??2_D*N|;dolVJA6B*)DRMYl~j73$LJDkHaJ3x)b2|N#< z?oxi=LZFUI${my{ zmn0=@jOV@Ezf;41s zY+A^0#G)L@C;*z&J4GGzCbgh_Ve^m*VBM*4LX1OToFVjWSyVlE-NF^z^(z*uM!Qg3jy0G!JFYu%zy&3W#wMo5`Q~~HsY_Ch1;Ndtr;*gg zxdiaR*K$}rP>L|{`$F6l+e+I3;tPws@`|x)I8)WAlN{Eg1CbbTY4W49n;#7#`A5`GR3Hju4#34>>7GEU8@Aecu%#+C=FQfoL9noCJo+}zYgy( zV5HchV+-jm`Qs1)bt9KA?r5%78 zHnL&*WYJMj99l7n$34{U1eCgO^9Q%sO17||&Iuy5B2&;fGEB*xgWD0qRdASNJBSz! zTC@wGAhqZQ%kybCmFtJ_Z2S{OAQS=Shdv%O-ufaj|F}LLI34Qqofo)HK6oE`(HLAJ z3gC8{aOswUyPx3JPK3MhufeTIhfBl&+!su^bW6c~k>LK6U`~Ji-0RM7VvB37?1us;{&KDA#o&StveNT1Ri3fZ@1PdW7CMWw8I0TYns8QfWD2 z;BQTKzz*u_APJ{>Il_aceNZ#1R!eL*6dGn6N zWG0o1)B~g?VKX06DOoQI1Uv=Na1g|wato3xUT7ulJcZ!Y6vV32Ap`}DEj*=DJy1v> zhs70FnX;)7Oe z@_4b|Hsj-uu;^Jt!dQ~U*AiFZCWG zJ_v?*p59DmF^YIb$AresL6`-72a*PjYy>b}K;x+Yzph+kRdgF-LxwR#;f_JtBFR-8 ztm4V;papUr(u9peNRxu#?4+sRNOuM$G8?g+7xTlbB(hT?lgmnZY2Ua?B8QxtDz1lqQU%$Vo%| z$pqLPw_7ktVg3IO^UMU8j=u@a6BA%M|0Xc00}LL4P^Z?C-ht_YJPo@zbQ12y+z*mT z1bS0}B$ssM=-W*Pc@4(&jBmJ_AT;oxiPyyh=^aq71@u z>!mlI#C$TfR3(9q6XreV`AmeSMdma~zV8!fLgtJ_e;6RJ9zwIekkJX27+2q=iL)VY zS7049k+F5qv?Vjf4iwX!E2gFf?>5a3@|su3s6}g$S+9@{NIgJP9NWwL@hoS(+=&~! zd-=R46qL4clrWv3T6L*2iaxnA1=JyKQq74}Q?VrR{16xB!9jf0X2;io1a6wFF@`X! z#;I^tD!2q-;lngwe$`6FlJBhb3g_|5dDtsd;8%@b1izG7751mjGb(HbHOP`?lY|d! zEw<*R8=~^JTxp1sd5Er$qJgk=;Ej3hur}d=x-(_a4jjfc7A?e;G;K|%OmI2C6&8-| zmi>^{QNplnxGO8*)1XCL5p8stmQO8u2ybM@$X#omAHxlWhPKW`1q?TchbKtO@-)V3 z-HioDy@R4qL7IGNdO2QV(FM3tRbtWIc*29t@cYwqehN8L`m_l=XdHq~!JJjyOp2xQ zAff*7RGL@w1Mv3qM{^Y>XRt2=XAfXGN;tThTkMXbpmRUbJLs-+44^jjVmJdFt`_ab z8!ZuTL{?_va`qGV{90Fl+;3a+x(N4Yx|HXtSgvqC~pNG&izDs0YW9cH=aN+gv_&t zd9?8W_OEi4`(t*}o2`P`273!O6x{~|yk|onM7~b1lg}{9af4%8Eu7z2g7%*{v;)Tx z56_F@h?Iv|OF+2zqbVTBt(x4SEOTtvmrYD?4`NJYkv$fD5m$7mV$4Yi+zFfp9eshq z&~{Dl!c!au-u<}8qV#4*Vy07*a2B=}-G&FO1f}F_QIFn1*no+32X4l%R;7`XuRZEI zp+%2Ust|0;lq@+* z<$bq%HB5s<=&#+Z2mH;8pyxmce*Vcb5BMxhHJ5>g#k zI8~D@$CF^R{@!W|ZER~tLbQ9rdMN9lES>>n9ZuSOTYrhNVf}c04x0@N|AUs%uPz2fBSf%_J%R(k0h6pmYo?O(UMR!tQlrjYkA6hxiKBtI&7GqF6DO0!^ucZ%C z{Iq8i?|PJ|Nm32BH1>HrExr6%b|+s;UQ7$j@k!SH$&u(GEf#=!X_$%rTRjhN?wT@PL@1WF0-5Bj!@DPh`!IfriM!h$kk7zFz zY(tcTYoFkdQoLv{74lrWa7EcR<7Vt69Ophdb7idkW>H~dH>5q955sdlX;`%ocR^`j zT59;mNI3X=5@-5xUK*8&(&&X2BGRCL2dTL4fi21#8{N+{@N69kJd<*Z8`v0EE(Kxj zO9M~|0ORKgu$K%ZD|(5OPA5`ieyATHIQols(v7{Nz0`@j=QpDI0b1KWsl9{fR<)={ zzE)rTTFa$t#HXJHOsM|i!K2`IINL_IA%LCt=md7dXWFydXZX|8*It=^DFQ0Y)1a6TQiIF?}H(ET^64fk4uFF$sX-%+hbA-Go+JnTv7cpwdvXQf?vW z>&OqDw3g*YqI>W@NzNTlLMP210>@(bHR%yDesyme3ZpTU2l;}0VdDpg0b#dZ%5h_H zX}a`i8cm@c6Cs1fO;D7mV{={#8Rzd#hxXh5N-4{-W9y~AAGdUnaNfdcUB+qM?` zp{I%HXFmss=un0U+#_`)!D&>Cyw3QY#(u01ENi$Z` zK0(ghXr)Y<3rzj{dGvsBSpyflbp1O`=Bz@?p??cL=-+9A=XnIv1}ZGs9*-x3Glrm_1r5t#>lO~Si z{g-wEs|TJzd`6R7YMX8{6O1hBE)okKHW9A#B2fn*7sHH9Wgd70SGZf?ib~lG$6ZL9 z(pSHhD*7li(Xmi}lDBn)x6g(XIP`VMonmMSbr@%JVoR&~zqoT8hVs)m_c6N&NfVU3 zR<&IdY-hw#Fdz|HZ7?9^jkj%Vu&-HbHjHThOAabwb*J<({x&NW(VI;>5r(PjtOMU$ z(R~SsHGriJYum#B1+SkWw!{ucuTCn>noPQ}dp|Wksb{NcOEor^q-z6Bo#%eC7Khb= zc5AFbMh|qtAr!m8`r!|X>5*Wpu+$}P7{5WU?Zp1~0XN0GcpqU#_jLx1pDm@%M;etm za{d-kSnNuxjf+}Oqvhel*4AjLTExn#moBBaVEK0eJ-g}RG6S6a28Rjjq#d&h@cCyU zI4GU}o$xgbHYTMLVDv`8aQqu*W;HQMd^#6h1#39_ANLA1oy0DfsDPEQbVoO=mz~Bf zsOx8NqgBjPxEt@3nPeyJLB>JnIwjIOC`}lALU&-gpNla27-b);AE)fUK_FqX8#TeA z2*&|8A%;@vGK~K@k505QHr>K8$VHK<65eK|Q5P3_D=;8+0TPyvI&lk1yVAg#d!Nlr z3G(s*nx)Y(+#8Q}qdn*MQsazblmK?^Z&eU>0#c~`zY zg_YVfVd)uEsBh`CGh>ZSFXQuLWdx0b=#$v&o>qTXT5U?LlJ(r{X%oa3FuWOaU}@|s*W9DYqoRLtwh1S7}1uG9Vsq4QB!1)WIX%dt8E z1%lX_N3Bkfl)nOZsZF0pFK{$@1ryG4WC9$3fe#qvCg8RJbzBewwA#ixG-V5n+Nvlkn* zT!K7H+KHl5y~u8UZET~%*nmz*r%;$jkc7EUp40`wU`$RyOUjS`n0)p)S0F8R#Y7ry z5>*}udUs$9L943edDXDZ@-NWDvZ%`e&{#e*1OaIw#Gw<@aGp&|W17lQ!{lymY?Ux((TB{+C_u zmhI(}l}vy992wm`zk@=;Vm2 z^f=zXU3}L9&bb%lWA1n4wC+D4C0KNvqHb0eA8)XPa_vR;(~SdcZOhCy$V z+(|Eeqzy-c>)=xBJfF=sNzaTT+&2tEX{Ezhk0|KS(XPjEs_rN(+}4?P52hAb01(EK zZ=OZ5e53Rz?Z^*?>eRRF5o0N*JT`e^d%Ss+wYr#u41A=%PZ_X5;IlbuZ#C;pSI$^M zucG7g(zlyjleXOi*$Ba?ZKuxoWyEy~p0brY*-Ko&Dl4-heOU*gh2(O0dAg(h)TN2{jH%c}Se<;lTZ< zY2XWD#UCHsz?F^+aA5n6r9-6pjwMeZkNGJdY&PFHOP_|p0d%F7{}`Q(oti|)aE_u2 z=M$&d4A}{MM@{X^!&${RVH}?lahS*O;pC*HWS^olX5~AmPW@Z|2+7#;Sk`^&>!TI4 zKLm~x)*>q%yT@jSYos8x1aD4&q?4$+Ob-T%x3+quS02yScoM)l#R&X>7JdD( zNv!+)36w%@bF%sT(;NQ-Jjfu&U=%|IZ%A)i%c9$`F#vlmniGO-^Wsa|H`4jXB?Q(yCkEg7JE}Z{mOUiBfVN0`(n#Y-X(QyokAZnN z;!JD>rJa=S9UMpJCst`GyG@KXp&i&uC_hpyUuTNe!8dr*ZEU>#k=_$O8gbp ze3r#9=p-^X)0U(ckq#7&zP@?7Npef=vtPlppf}E^!3MZ>E|R`Yqd0+N4nrSs z%o^_lWE|w;C%Y}&SV3m2;3k4#-i@jR>gJ6)#kDC6` z+36XGX_LwfX?P|IgA!;iPi(PFI{)2?m$YLJ6(?;rZ{_AqFmK0a z^SE8+ZM%6J!Z>L>3TZE`<^k#<@0jMbm?E)Z>Q%bSt4ZZqXTREpKM_oc4S(Ir0+T1e za%v)T%M#3U)gDI}`{eP-lYJbm&b8*3G)c2FcLHMXsgs55IFFbrkm8=T51LA2WsZpg z5KCm4IDOZur6WF_O~o;rZtERGIC0lh9MNXfqdA;QpovbS;~r{^MP}h_UgwJ!y+Zrc zMGj>yjvkxYzRb3$8YfEQfDs(tf&;zJlyt?jaLmyOELxcdyrpV4-<)Tj6O~9UEV9{t33~I@#UO;;eB>o@b7){In|5{+vx;F(5rJ z&hAc4kjB?PRg(p9{*uW9Uxf*mHiSevXJ8syaNS$hoTT?YNdolX&*0WBG&-f_oQH&TSldvH!ZN!dVQb?o2 z7<{y7f?vr{rbPvqA+@L-SN)-Rw`oxae|Pe$i(hm2HIHBO`PI#@1^imbuM7CKm|qw2 zYbn2$^Q)I%m-1^hzb@z3Aiu8S*VX*`5WhamuaEGn#IKL?>pFgw`E@hDZlSBM1&0Y} zzBbLbP4jKXp%?UF0pCu|w+n}dU~9VOdtURsp!r_J2W2$heweawLN;ty_-X`wN`_8y zhx&Aiz8~W|gAl|ZMi6VmWGftGvRN;ak^Zuuff9C`VoUPY!EOX++i z%YVnoxJOO8Mg4z)H?&&8YuE4HQJ~~)DpL))zlsVU;OA>4DAyb`s@-q%llRh>P?2)C z*h++v_NQ?_v{b8ONZYO+{Loc{VY~%WO%q4@@MG$?w7-^i+>^eeH6<{E!m@31qrTQw zGUDlN{u~Vl_Gcgi#_TCYJteQ>fQF84hQp0UGvC%%-HxM<(kGpdk}iYoo_+RWw;!W} zzS0(A&i@h0?87-@us~J<2bt$R^^Psil_c4<++%>`jrqmOr%+jT=N?R$GKU%qfH=#W z$`e!WCA{Gbq*3hqhCoA=;}1^Upuyg*jj zY+5co(;>UxqFVTd%bF7MO6Ybt_m4`1CXR2d)x2g-G4WlcVd#i6F$cpO(ehvd6615q zxS0&+ic61NlO{lrcu{=HI5_Fyv{*YP;IvW`G|nC5BOBx~eZli2)nw?(`TxWQimk7q z%fLWzz1aE^p2|I9>p#)mt2{tWm?gQ>OB$r_8*@hnf5dp{AFa|7C@s2)V$N_zB8Qwb zg&A6Qn2_KE+6RM3#`=s4GzMcy;x^25qvaHaJ@heo8rWeR9qIHMoWm2LVQDD!;JEb% z`PuPSCYS{v|M~oD`M5DzU2NPBO$FoKMfRcAbXtCtMM~M?d{mRH?*qZcJo?BWsREK9 zOrj$jp-+4YiGo+eF85}bvF4WxS>TNL%fK*xLo^4b4;ro2W~||6NaLO=pdYnqk1S~E zsnC5VaMHr5)r%ey^uVD|TkR>m_B2jtI*u(Sr@#bxs0>cC9l=)#YmbY+#K#LD<7Vjr zd`GIbUz>!K`>m8YNQtouit=gtU_qcCK0i2$WDbhM=OX)1ICt=R4faSX9zB=iBW-`b zg^xzs^@Z=n;5$Clbl&_tVKRN*n^0r6VzUKCd@Zzqj#wF!x(NtgFdC~USfb(MO{ZDRkfIU}HW`_oyhv0l9R(#I&U}2{x9&HVIXOgo;@NnsLnt0+d-?(wHS?TP5-rM=D0Y3`C9i3o`HxBVep-8ZogL{UP=0h<8H8 zi4Zu1BE))em;x4Xj%&5Q6JLugpf3c0y_vrhgbCnNY&bx17+bqSna2=NdxjkeH)aR% zK{m83YXhed29G3^tugvcZmmyB_6ACUEl#0PGuMVTWgFm6_ z`4@`6jIl(wF(=ghr^y((ler6sqavl~Z-IeO9gZ$7M1XmQv1Od;lHDj`yIF*^ok}31 zOFDE~x><_vpQ8QLaSv0=Z~#^^w*bJvOgL`huxCXv2UKMNdh}|5aNsUG*77dC>(xVt zJ>L-1{7XTlwWg^}}Ox^LfTK$05yi|vM6~zle%V56s4Pb@o%U2`b!imJY9q`%--cUq3L&PI^SFQS~3ajeA z0n)elLR^0;466v%nME&IL1Q`$=t)!1v(EHWu_gf})iS&o_!sLTIBQI+O9W=(lobzv zAi##_5?yJIaq1)3eglri%#b1d7-~6A`8Gbos}ApAb{W$Au||g^&BN)n$=t(eCR&1# zB@<`AlWDHs3%YZIV;+)lJ%K<-PV3E~^ApiaDI=XFXWz62=8MAb0j~m*u(x6N$$FVg z6xbLs%u$bWOp~*@250k)-h#ttqASp=Q`3~QNEq+!JVUph&Qo-Isq;A9e$jcDZvQ0h z#4R;>;l?gD?M0|JEcXRmpL-q`I#K(Pv{WwYFMt1CukdU9j^lR{zjyH?qyyiucjCy9 z#RF)HRG3frct<+R@$!ze%eu?vT|MMZKkVJizxAvG^cnAh1P|y{q=g(%o>%? zOLnBx`OGN@bgYA|8=_&E88T5Ht%I=@oSJ4imuEngr%4y=;QGC=b>c)LT6X8W^(X?U zo%{{<2jf92V2rcO2dlkmb7>M=rrt7^<8$f?5_DSV-RCzhd>J?pY}1Hd zbtL)moy~|>tL-G~+6hcvTF)cF*m;`>^e@B_s7;5cgx%E!C3t>Dyg1tSzcnr`Nf&kXR}4#6st!{~br4&B zi-I9C>ULosR>Mao%oa`V#c+W6IrJHlMKRxDK0;AN#b5TO4NqN`pu;eUC7v#vkeog| zfg(2n{`nu8B90GC*2F#~<}A=7zQZ;g4;3i}9ciH3594wvbhEVasdm37Qq1A~g9VR| zPgjSB5AX3$QXMY9K-Ev@+TZY|wqhwLgF~yafB~ZV`n%tqoLSpRrw#vmIf*5gt*O5# z2EMK2XMi0-Yr+3wlJ0`(CqD8=@Ce58elPR?~%Br71CEh@YWLm+)y`zv)A5paZm z1##UaFrDY}Mtmiv`}AZ_0$m0Z2KJ%xZ}_|za?*Uwm%!k0H~72`U-8bYABMf~&mPnZ z`x$C+^tID?AVJmzN;SjQl!LR%iq2z~j{;YD<$G%(YvDr(%MHFcaVPmLL0mpOvB_BA z$T5$vPRW~Hz}t8iH#u}WQaR@v|P$>yOsp0+EDOcT63Y+T&y)OgbtxKd$H`PH&@qLaspr1SYR|_ zm5Td4(HAX0LM^zVU~HO7r=LWBg<$cZ2yQ!p@_;ou6W|2|wlv?jNR0lJN6#^j!Ke9{ zQGqnpRDcRG&sBRa?^NWf34qRpl;p$cCLZu*4Gq5w9|fY6Wlv+ zN#Wqyt_se;7yx_&9ClBnz|Bk5%U|4WOxFAh`Q9s}SqfrVMgDL0-UU3W>f9UO$xI-G zz(frg6lH4@4dmh^bH62-B$Er|GPz3yVn`-rAj!nJ1h52x1In-+%Q@QCp3k-_y?9PN ztvyAF_XI2;S_Pp>D^;vW2SaOA3PCCP|K7FtToSjr`~i%IaLvy5Uk8bAQb#{6o)HJgen)1!xII;x;AtPYa#M7wW=GI#TS+Q&BX z*^H5ouAg}UxV*niNt;skm#N_oreC>Q-bMS7aSS=GmPWz=O>@2l&7mV0wIWc`qYa)W z6)uq*MpNzzjgj#U$Pm#SMsG+zj9W~uaJ>i_3*at>Dc6gP(`65&$NYxtMWg~){wZ`T z#}s*-a9{{6!g*+eW_|d^5fWJq`=+ag*+uHYtZ@wL2AqaXj9u~ys3}B$+toKgfU+mvfOvO2a;R625SgPw3C& z4-$k-(*kn?N_GnlbtxE6Vv12@8Sa{S54{U^aoZZ`Tdg*-ZUlj;(PLkkE9 z&54jUg=-{gFEFWvVYyXe+QT!g_+pLHw#VpOo5RQqj1m~AFHcMhTR zx6OJ1e{r|aPtys1gALX$<~@i0hGxOYj!hT7JD7K<`v;PT7vO@1Lq0lp&_Yp56u}Kh zPd7*p;Na+?693mXZ1{~}8^Q^sGvwAMDbDC}fcrQ``HMFqD$`f1&Ix-fR^I^7LlCyD zQS%Z(3BVcMdTt{`TrX{J%$wM@gA&&iZ9TVXjMZY_AbD^h7Za${(28nl1gQhqo4(kgPM}e6m2CNBB}gHOJAYZd+P_y zH-oyBna14z0IyaeFhYX*8l?C_Id&n1`b9M=I%cL&h?VGRG2a$kRf?-Iy3!*Bv%!WU zBRz!vsl#oK%`JxI$>M$PSh}pXV6hh6|2%zL8Z75V6GIAMC!pUPI)|y2%&z3L+iVXi zN)2HB6{){?<~8eW$eLdyfT4PNSjLql3U6;uFC31MG<5Y!IZ-O#pm@FcvP7cwE~2Do&xqspA?+TXFz;NpbEB zPn)su2ir_6ZL;hO)$1+79@D#?V#O-C|)Q~Z2b$qSn;iLR(|*7l?(FD40Aw}_uT#1|26t5JBm#c|qB9~>^ zF5>bCTjHkUt#?H&?=T)|Djts;z$~A-pOfQX=l&w}977;fyD1q=hpvRG;i8xB%B0P|W%u#PP z6@HgK0^gmFzqo~KUh`UBYB4_BdQ z6a)k-ms$Re$((Qc5S@xX+Uh?Lhg%R|Ad}(FtmYJ~l0bMmjA1J!Q|&3vHgR3}() zhNJR8^_gHz8dN=pu#W%FCmB@929z$n05KP; z&je~9IaF*pg~AL<9QKfUbC|A!B6j)*PRM|DiG9&c1g(}{qc$GtiyI|CKzumA%vnp5_b-Y_Q@H-V-KH7U5N z=xaozON9GjlPHHag0@W{WMApLIm=JKhYt&#((aop%!aIJ%Pm+2oU zCoW+9ow)X>EK&8&{xUYIa05{4Q}Lj^(}cIs57X!hT)P~l;e+lIO%b$I3mI-{nUjpR z2TRjZ0x6xsoD_UOyky5Q?Ggz-U5k30D@n$YMB4#BL$h45bu(U8D@n;)%BElNy^1Z> z0H!b-tK7supL~B2s|O6|QB|0^+Eb|wxF5rct6zECd0D|Lb~mR#PXrDCN()xphDhmw ziuuAEIqDF&MzMQNB3?Rib?^2$NqE~|me;*CV|YsMXV}T4)*$)E42jwnC_#A80W{c7&NGP@WlRDK*umY`UYa z*&cdq5lA;~#j>5CB3lC`DJwbyOH!p-gbf)dqR@PTf%M4zk%80@^^IA`StQ>fI*4dA z%|Z)I+`CvNCzVUakcHzCXycyhb&v#EpteeAIu=+AT$iLwmlldeG5(y$UmV!B=|jgc zenF9ns@T`3$YA+iF#qG?EXimC=#Br(ol)TpWSyU2QG;2Gh(Q1xs` zxPTKyaPijA==H*eXOD^>uZ<=N=4Z!{PO$BYs~*C|N{X$wU~~iqUh+@KFfCZlih;u0 z@B+0uP3n^EShm^Y2QTD$Zydak17ZNoHXioQ9{eiTJ7e&x<%+HEz(>$f+S;NT2&erM z@f%hGTL<+yzHb-RlFz014Ga92ru&qe4R?W9`SJ(X%ay)t*kmhxw+*hJru0D_F!bh@ z2(q2JU2Hijx$zpdzNi^A&(6hsjO(DzqJ)7bkmZi;okhU_@GUg!Zd2l@cwl;N!X()va5N|k=17R+vh*F`^kiZOvI;(|V1 zOQ2~OCa1We<}VOIqwSc3Uc?no!M9LH$Zs%!g{A|+WE>;~0TJ0h=lM@f_ME zbFQT+r19qLV97MdXVVZL7cB#E5(swa03k6jTOfjs>d7#JAqdb7Ji|a+b$uM}hZc6| zDQ+{S^+7X1e8U3V=UtX=8aSYMP($0m!J1et|sa}`a#u;Z5++BdM z&cJuG+2a8v#oVo?57Qnu?tmM%cV(lZVF9dkhlXPJcPXZ90GwZ_E?6~vE);6!bl}JG zr-6NJmU#;Gjt?k-=CXjNip??+;vYv*C2^m`KSC%OA^)_^WUjdW6#2`|XC6o2uq6!> z(qrA41Ah4lqG^iVNwNf@L8cMhM>m4&;if%7G*VbB2YUbFThgS*SOUVs*d4VmlQ18r zj5R$KbK1hdQ(yiJm*4rT#}fnJqX^jQC8_~dbFbW85A)Ccwq5IxQ@}TjLlzK0yzed4 z&V;~;!m(DeWLSYKE@e$8WlhKZU&U{n876XQ^?7U<0rGm`SNZ@EK3dh0tMlwqp^Pu(n_# zJ$UyJ>E6cB9&R)jFT`GrX5a-n4Q_P43_MiR$Q90WQC{-}0 zjLUpVu-}T^@_8@DLL(z8VF&Xm}NVI?K)$lOK>x3)*jOsBwb@zX2^U-EU$z_VST#kJx>z!u#{-76@hn;Pp6o-wBI`V|rBNA_&o$Xj_9qLzlUZNDn1Y~& zghJEtW~8kTU5}J;zT<4B1@JG*KA^EOJGMjON`&fT;hP#a!R#1QCb|GhQN@<~&}QKf zdXiM6>x8|~tH>Z|9%ER9`9FkdD+v;HQ}s!YVHEw_?!AL_wMVhSJ``*^1GG4X+fzgO zyP_!JH4s$Lsqdf8qX`;n1ONhH@FfV!tQxHF*3BRJ42*s%-fr#;+{xqKl|2lJEq!b` z)QX1E2|^GGi|g(o`jXb*I~>nqKQi2MxJI~QxFv95feqtlGZ_mEN+YCxj}5yo@Cdewqy^2|U2 z;5;{)iGW$&Tf?98z!71kRlSoQ|lTReu?aRX;%9|Fw?Gf!X<^11gWx^vhz-ds-^ewU*7&cyl1@LKi( zL=vzv9`WW1O=D2GoBrfUFRAceU*X+Y;kyBe_HnZ!AuCImM-sad6_%mLVLOO@qknKP zN+PorzYyhZ@CX$(qv*zk=rb5A7u)twR~z2KbB0tbH&91M5S zPk@>G;%ALMA`X)3ll}`twJykf7$k3uoSq@Wt-!~Gdoo4*7v38=m=b87FH}NEvlJTf z#LmEa!d*OoxJ&u)rmBf&pD*IBh5HY<3!vb8;f})*P68k6U;+oxXt`WS-pa7C68f!7 z#dEWTmeOEy4O&hM>||h-f4oQ$lo3fSOT(>0BPUWuMpI@U3$&);iojd3g2l4_wm>;< zST6fkpgbL4nOK(Mksc_|hG%L9%_f0zHNE>!C<5hXyv+%e>&cAe$H1)}-~j!@fA^1H zt9Ss*1Zb}ZyIzL6Cw*%p9)dMDP>hS`@&m=toy`ptrwY~^0>x>9^|nCqe8IXXP|OR~ zn*+t^g7wxwF-o?k28t6;8(B^@a{`MKQ655Y0c6c>fyF68&3s{Gq*}F43&zc)EfSfN&IeHtH_a7B5yVz;3a0{5g&!+P9wA|Pn<{*AzNY}*IV#rY>@ zu3fEo?tw={AZ#EYtjCcSheNQ^4NUisB#*w#JVrtZ5uaa5KGP#UKa_lCMSLERd=z1y z({8a;6v`pn)9v^qw15WdTJ+A=c3>*DJ_C~C_-kd-H#QVsei4>nF9EmkycbUuYRSdP z!@qd(MYdxP!j8aw0(Ty62IAdJaT5{};u7K$5@ZQ-;G=|%!HNk8jMpv~QW;h@2h}2W z7UM4E{$?6Suq7c$o=%tzXrW%5Fc<5i6z^P|H#v&hPbUS#FqTV2RV>t&D2cH5llq8T z0qG-aM648&(PxNFFfC#~&#Tm2+UU`A5yZ`4$C>3~3Sw#ubKV5&AEy zgU9zdeg3JT*>n&S-91$}hr;xQVk;Tl(j9d6P}XOt88%fNgW`+^y6Rk6vRpEU@=kw| zc*M~gK`gOi8T%AbrFg_Sj8m=sHOUZ1u%x_DROCM~1D3P$U`=9OusH<+h+nRxM2LY| zRCvSxQ5=NJ-rGoAQkfZ0vpPb`Ft|PyYJq*$)C7Cz0wf)v9sm|;d%ZUU=WoF7c$}w4 z<=a3rW1&c_C{u$o-uyIenF-Hr5N#SZ69!?=Zv(kiqORu$hJyxi?jUB$Gw` z`FiwTEKJ9X20kn@h+Pku;`0!LX%d6!G1C{mN;bQ*^UMX`u`rwzTMhz9B214`?}cHy z0NR$HoQ?tL_4{o{381)*lH#E+6k8s`%kw<`bOx#qzz81e`A*?}ak*q079PsPn8a3> zxnzTPKUl$8ri2VX1#^u>%D+7*Rw9jhpG0V4 zzdft~1dfd+H+0<@y9DzO9Ob+>1gnohZV{sHzSd)5^{@O@+Kkoq%K)3WhbHe4I;fF?Ed3qWIs5iW9q54_E7N|R5!L`J|QSG zWS`VAnOOe=*=5wa7-VOCGxazy#g@mB36tkT_Wl}V`sgR&`>ZEOLVrK?geatsbi$|D zSQdn_0BvRH>H}60&^i83#`X5Vtt17Na**csL$TKYM*_QI;GD*e~3A> zLTioVH4E0>EXYN&SA+qamQ?|>M!h4=h_S>QDXlk;I4=)b^wQW(L>dJCUNLaK9s(mf}HgGWyI z2XL~5e1>dPe*VxcGKTY6d;ELlSOPVrjQk}z>pfxL$fpUI_;LH~OsF))m1SfNDI8q$ z`U%r%|kFC<=dcghz zs!QxOwh^Gwb8mb*4CqwZKuTaBS%uTWp>DDzpQcl}BqlUMlNh|yp`sL0Xvg9E5Z^C9 z6KERqe-)>=uLXpdVSftj1#sZv17*x3S(qU^Y}GrjC{;lqIMjB3IP90gC$duAgfQ3l59L&%*~6Mox8UO2cI3MyFihQd`b zEgy6LT=1c@vE;x-tM#EaEW?Cq3`IKMYmUr!GT{>(pmW*U5F6>KxH>5r(?AL&d7 zAUlq&In%l#ki!TS!{Hz1SMOB~KfqoG%td0@P zX8QN@w2yEnvZB@F7_-kh#^$9Xf89Fn^MbL~D|Ywi60n-+mSh4&Js=7aS%)+A>O;$7 zYT&gZ_ZfOR9Ej`m4_!iaAW323BwtFWe_bNyn?YAr4?>RQA|PEO3Vv|^7F(CWJb>h4 z)ngFFSWzAHmEyiNj1LA8I^(yE%PY|a#a12p*&v`g3!DI|ogmH6o)$I`XcC!W+Nf6C z_Zy&p#S%N(k!)2QA1?-&uXiZ21AvRSfx6H>dk4`pWI+?>DrMQ77GhL*mPs5S-alMy4+#jMi5gZ)#r}Qv;0o<(z9G~?^?+$0X@!F8 z6WE(Sr8|Su=>O7>Mj>=3IYUP2ln=$8&1Zr*# zG(%xP)A)Yte5|c7pOlK5ae&`8JmcR0c-w3Xoj4?=@^?II1@>az{BHMP4*9P#YnJeZh}!H5E!FSzSG zwkX3OQalGW{qC}O#qQaZrt9el@&L7H`M_3<5&pq{2E!m3lm%8Ro@wH?UlLHCD=Uig zB@Hb@r;8GwGCimiEcgb9vXgxUF`6V~VJoZV(1|+g+WCaMOOOaM91Jh)XgvcJZ2?Wx z&|YAo7H8=)UbN5{#i0mNqPdi)dfYH@)>ps1%xaGJ+#;0G*c#0fYBFIL3#IbtsmLp& zbEDV|2qD0*sW@?Ms&kkIT5wCsMF0Wer(M+7 zKv#r{;}DC`n>at8(A##LnqPe^&~z3Ct(e-j7bT-X5J<2Fr6EVEw>75TiP3r|W2H~Z zKvwY}j*tvipF!q@P;LtYC!zXl!R{RNDwyoBvMB8w^a6@4&mk3VU{&1rb9$iz0_nHDvQEyt;2AiO7*$bVu}P`;UQLyR;X`3olAxR&$p+>(NM&mMXgXNaI% zRj+qKqy~U*t4Ic1_gQBFikK=PI_V7TU=#@o9Q$mvz7FeRU?fb+K#XbI$;r?y7_PLY znom<^+jiT@EyKRV?bwfEJ2^THo1`${$QX))yc)((-a-8B4IN25ezV)N!n`I&zGmeiwhO5!fv0?JV;D1WFk{_cn;hYHk%4wq2AiIbP)$PfHUGnQI6 z2K&Hk0G^4oVI1454*xw1HuC{n>S&Ijl%12E^Iwwt{)}*FXqu8`Ntn(8nCk}Ta9Djs z^iej*Cgqp|<}0%HX6@+=#6gw`nO+TyVTD7m!2WAoVTHq5qoVEmldaPa^D(8)3KJjHeyXb7j*9y@^A|{S0=^U5yK| zZ8cQH3QL~UD5UqF;bY__Vh=TA=Osui7B|3L5Ps9!zGA{gu^5~gX%`M)w-zhQ_VplE z4OG@>D#a1@u=4DoL#)QkcIXtLB!u7A>A|JbGY0VmDTO!p70@A=YFt3FuzkaG^UfcE zz#smyz1!kzti>baiKg?L{u*5VwckRSXc-M zl#%z?(0A_?YR{j-%KG5p)3SpQV2}JYapnc*>vyleG%<90MsWQ6UrDifB5~x?>u2t9 zzQZlrfVR>MTCqg-Ih3=u6I+KjJ>wrZ!$CVp6zwFAKa2x800%JV{D-3o=!G!CLARM# zd_d3o6+;2rGk$+p=qo6jCXa;(KGNcw_>q)mYzetH3Z)UyFhL;{!2Xcg@W5Jp+a2)R zJTmHv{PZX1Psb%CAw9r746%&f&&;CMMRr(;@ppc3{Z!OwU}(c)FBvLva56&fz66Qb6EuEOdSLWzS{l(^P5&C ze4Ta4KasF8;Z+)Jirv+JZwaOb&msYCi6dhrOenJR$R2iORLJuo^t$Q7Ko&B)J#ra) zJnI0ICOcS$z#IJ+;x^7Ted+$-^iPoM=7|(os%=Pko*t$z75?q;6!!n{{DrdZgRCB9 z6T(+hGLs#ICHXYu@$Tpfl=W?7P7SEXeS>U&g<^Nrz!x!T#M|Jv?_l}OrKq_nA~#l15Kt zEQ6V@X_g+y=!^ey?`Z=-0pA^<%Wu93d!lrC)`1&`&ma2M0pYa_ZVc+)1MVbYWa%Ri z6v)%}=Fon_t=#BoM&Kc4EKN_FIgC|kReCDkQ?M`jb1d9T)06Q$GHMkL2+I)Cn4Us@ zhfg1V|L~`WkIj7DclP|3!r1wabg1wUl6wA>?67;b3Gvn@x~H2Ew?D2%^$t!5xNA=e z*Y(x$A}%CA0{ny>mO1<7>GL5;ozPU_V<)|KCDWf2`jbc@b55c?Sl{eS!xv_+#MOzR zpP{8o_pVOq(l5f^tZP7dRPP&ZI)f~HGaDLK)8@E!NEKLqvEzv}f>)nBu>9n!ClCP~ z=ER&02sG{W&NJ=92tEhP!jq#ZU4%&!a|RJK`X_ikaU8J`A!+r3kcP?|H8C%67})_0 z1$ONK{JXZ`PiPR>x^yXe4ayHXh;D)%xqtf4C_A7@N5#Xr-PkoqiPljf8%wl5f$}0| z!La;ifToUcDc{GK2<3A4^pJL4ua^fjR&uuW(P zZlUk|mT_M@d3+ddO2uEF4r1rW5nr&K0b7DSkteY5Y^Sy@-77dkn37m*f+dSjH|(5Y zb)hDZlsbejsfABa#-TrnYCBZWP3lJR)#y9q^j2sUn~nmy$^^>{)ww6m1Hx1NBt;YJB1F zb^M(n=Z5zuWV28V85--j!2wC0FtgX=c*Raoz-i|?M8eUlw3%or?IP}gXV)??WH>Gi zuYLwF|v8 zp`lI`G|S*W@h%fiKzKIcgH2>6b;@W5#`pgsob)>`O0ikI2@RnDy`CVA6Um~HO3)CF zOuTCkwIK~A2kai1@SU7^m*L8U?*!f`orJU@=#|hH$3wTGDtl2<29+c>8@YwBGMylk zzw^hIR=}KaqIoD26@P{Pw7|4xpGP4~C&mM3?(UaE`SE${3KmOAvFOiLV@+g?p`sD? z{!J0mkg6*(Q>@SGOI_>G zh_2Hg6mcC-092fv9Wvg+5HHU*uKFDSKi096f&z{Zph|CDG|oed7}rmHUn4LmhmCzP z1dCc)d?3UKL#2_>g7b&4l9IXvV&RSeq=e`PNuSZJ5AzXLLAbvp{!xN)RsV1ZDuKITz6!v|<9v0NX_=e@F=;EyN)<(YlG1 zs|({w>Vz*vMBJ`*?_r?P$PArEVUUb6%t6y-1Q~4JIM*C{pM{VWa#Az>La)JN#a;{% z){*`*DXdO@$2doL-_Y`E&8eanU&MHUV9q;h>t64S^M`iQm>+dOt~`zrOY1PGK~z3$ ztLE^o8UwkLp4-@y-Xv)?vaW4A4S=W?9uXrM5=2$>O zO*sE~A*vt7L!G`1?P<|9c_uWL_NiAlzVf z9QUtqPr~hjI|%my+!!2}6UQaP-3*rtXM`(*YliE9bHm*Sw*&6Sa6@n_k!L+z0UQq} zhZ|GIamV4_gnJI|QMes&_rh&JIQ_bEkssU!xclLDz2B;0?%?Sgv=ZUx*?xDVh? z!TlZX92|%Ba1vZ9+|6)mxMH|^xMgr1aBjGbaNFS?h5HrU9=NyQj=_Bj$DvNCa5uwc z!>Qp4;O>N54cCaWO5wC{*>JbQrNO1ZO@q4#7<>U2f;$0s5PtMqM(~t=na7I4uiV8y z7IBGSv9I(yRsDW5`D5SP{qZE#(h<3Njdq=6Gv(4A-<*5bak;Iic`Z=B# z^RI8N!5i{!H*y(^JX}V;FC$mu$x!=vyc*$nE(rk?iC^n>dL234uJ$z!f-Ne*@fp6{ z48+y=_`5Q+u57sF2;wsG@^ka@k)N29Bfua&pP}mDDV)`h8sc$yc_}i*sd4cgj(%sm z!^3yF+cbYC_3VMd1o*FcR1GZooFI_n|jyuy4Lpc-t~PBK4Tq= zm(=fcwYT=P^|q~YxLHG-y{q{CmA&XXiePO=ksiu`_jud9K9A&|kx^aSRMVJKnZus8 z(&mQja391}eNvq=GHOd3@^fs!rQ*uQYO6h)Z|ZGZiLAXYzKs>civhU}OB;-QhKE&= zi==C*udOL>uC2=Ese1rkS0{hF1f<(}rziT63y6AvjlJGBXK#!@%P^8(Wlc$K4a-l$ zo@iz+0Kh|8w(&iVo|S-2Y+2dBaPO6aP=b_y8QO_@=83h<<9i4nS305~xq3Yag1v3P zg4i}?^DBK`9@TBIH4=a*kZ>VVX=+>~PsFRNwbj>W^ES5|u`mKUsB5F?BLI%1!5C+` zU!h;FkZe*}C4>!E#DK0g;EYd#qDO25zCC@8c4w!P(DgE0isU2pZ5U)c>lLvNJE%iI zURKhuLpQk{e5c#tU{S;|Ho32xE9)CeZOz${ZtZuvy}q_?X;@8yT@=qi5-{c_;gX1Y z5fpT+Lqo(-7j8#OPD_1dqphm8WJ$ON85Y)G8ZBeXs4~Dtg_0Mmsd;_6m%(v zFLiV~02qm2z^}wwQekUtsHklL(e0%GUL?%)X7{;Q0nm7Hw5?%5M9t`>jJlPm5lhdv zdA*LFJ}=RX4pu^R`TYMmToOYMn?d$WhU@086cKO=7_-<#9(~E9ucQ`r- z%fBgoxNUZzF&ZspPXk;kfYmQE!?zIGa1DLkPOk^U7r9pUdK_-?gQqYN=q!+ZH#pkd z?Ol$DM`>lft)x-xgesS7jjt~f#1&I(V~Bi%uMc$3L#5FO0Ct4`qg=kdt@n0npVxt| zY~wqeZb07UUeB+0cyD0Q-I1G{ds#lkP31s}k|lsPLsRq(YwP9yPB#UV zI#Hjt^(e5px`9n>G~&Hom_r=y9%pY`H_VeUzY#3F4v&|f)eMuw6yj*&I5tiYhWyy8 zlwmlS>yZ2@eFLbm-CA$0wl&)7f!IWyD{NIb3<7ku+sO)nAL0?LqZOmzHbB%35KulI z79MQ_!I~=S>2j^5aN9Zn8dGFWKF8hTbF#YEuA~`^?{akaQA68+5IvZ!iOt~1lb&K9 zMAIWV{KWKCs9sFpfM$l_=0O{!E<^khS5F_&&~PXXuPztT($tUe4riyt8-x2wO4y3=w1HRC?PKxO2 zqiKR-<%q9{!ub$R`S!Z{9d2hQt9MSRG!UiEVf_K3&QOXq!2?<(a@djbM1DmiLACWu zV{tixi>=YvR3;efo>pRo@Xla`E|&Vt*^2?z!{#-#gMr1vHKUDa0f(BhC-9nvi-?ep z_AVFl3Adur$+CssN_>_&R{B=0A|TVq#K3X3)3nOPe$|B`DFG~#fCql1x?v&4tOVs& z26b9b5W^nEzX&`cZAIQ4B8)hq6-2Lc;YX<4gQ=5sCcY_*29$>e2pC9ltf5Ubz8Jlb zKmx9}#o67_-sbKQIU>++OhOnIxs-3OtJ_6{D2EXR#$RFtINCt7*m#xl&E+$tp2KWI zDMSiJg^Lu7=pN-4rflK*MPuYnsRtVjs716bM9jbrf&XGHTkkOq3X@lltAkMO z^6)lKyVJ>n`An(P*kp{jl>cSrPJw{ifoZE9$jdq{rZ$Yv&*i+XXhWvfcS=?fU{Y4m zR1!^PJ$ZS1#O6(jbCotRZ>e3ZC&Z5J#{7QOj*a#h;hEPBK9kLQIhDQb-M$V?&ypAK z@nJ*)(g+8n!`=k*a8#m=pl)G)f*~r6VJRhG<)vvJ<#?R;B9BNJtnK8-XNt>$g`60J z;)2!lq6I`8@SB`wa#-wFuL~pV#lfk00l)}TIy)LW*E`t~O zVKPKKF_hzq-A+d*O)reo%3&Dl;nzC7UEo97Fx}q4dJTgoIuce=8st$dF2{TxpgORS zistBp>LG;@{^K$zsodZ*Zhl2{JZ>yhZ(O88SgrASP3cXt~tsN34X#B$O@ z3}bD_0tqNY1&7~QIu?de&eop92ZrCId|7xqlNWWwv`_M(;@OX6HdB8T(8H?Bamaw0 z8C~Pm)Ir>l(VhW58gnItHBOI*rkdLq-cEdNWGz@zTi0xbgo8z8E4>aEC_j@oKtzIt zPa7@hd|;C!X{^=7bxo5Kp@g=cmCjW@mya!OB5^CLs>HZqX%MPI#h?J?FlI167d);^farv`FSPhVSaFT=|Wj~z<`%=3)DbGv9T zXLw55+-@frQ~=NGbN6DMC4CbU$RcHU%D_XTomU7$2^it13tMr~V%hD4*oYQ@Joz_4 zAlM1YOXH%!3oPx)DWQ5x?^R`yckqvGs0fMYx*ff%yj|HCtm`nWr&fp-hI~)kI%kis zha^2K*P}ROb9wqJL@HxhiUoudOK8LLklKMM5u6@_rr3^bzBDpH(2%9_viV|03_L`; zsNxK#N&q%-9DsKM!SK4N&$IccznB(+)C`ZrHj0aP@|UK1UW}80#Wt~(VmR>9NB$&O zmpCTAAMe1GZr4h%HYsN(Hxc$uxwoJRc*b_dl@$*^}h%q0wk>$i9(8)0nq|mcVh@3 z|9&S(HcKH2XvB9B>j|T!F@h9#WaJni<4115T|)<#)PU*N$a9PqKq>{{e>VG%L567J zk5#U+lm?JQUu-$Gc3TZ2FtvS--bthd^8GvmAwyC)eaw@}&Bu~Dxz1!t+h>#HFDKTN9JdqLLDPaW1+9rr% zOI*J04mNMN2%?fOeeFt)BVmJa`7$EA9Mww#15e+PGAN%iYb9o)%Q_?@qq5pwTi=wYk3)ig5Yj<^&G=OxMNF2}nm@FIMP^kL&tyY0%Y&B$o5S?fzGt{h5rmclDB zXF-4pVV5{-iHj%j0c~E$=a_sj689VCw@Go(4OO;kqRXf&pb7~H5hvmmAZO`z^nhZB zS#xYq0ES76zVRo)Int(Yzyj7EwkpWPuHN=iG5kvHkrtcc7?I+YLBm+Zh(M_**^T8e zV#=#z@fvA3i4lPbzyRP-xIWNi*r57Y?}Fli)Gng7fh1EBg{M)|NYeo=?xEEJJBfjq z$;Kf0=Ms%#IA^=F(NwKfumB1#I3In)-A9`H9lClrgoVGtbrs@vQ=ui^8Rd0H+{ zYs}9xstn{GjzOb@zWbpXq~|1=1rt^{!7o$Kf~%9pv8%I_qm>Ns0rGTkL?VACk_#yk z@o-cpo}VJMz*Iv4Ig()K4oNl_8589;s7lJhnj^Gh6=X}qtV**X(njJ!88taBL}{^c zMKVX#fV_ZYQJ7OBGk1jJ6t!K56P|CQanNi@;6qfUk#v{0GjS-%>=-A^L)lV&J0rRz zE($M^SecP}g0E&QGN$=RsZ)d`lz`|^gQ(iHq#BrZ>`Q<5kpc=ZO84;ju7P zxAe)~)$3Xw>%qRK#9?_MC(_#!J{Zx+2sXf965lcSXG18%7FHxq?{tv>6P->eP!Avs ziMnY5V{r1Uajahp;p;afVzL~OI7!+*35}&TlYEkqt}BF!(nrkR;dr(= zm#7!UmWo>FP)SucvSa-AL*s=wV9-{6={Z#t)i(uVwT8J9As;qsAn4% z*{euxa;2nTz!;3hMiR%!;L7sC0A+F~N%9W5+a84g)HKAMxO}uYy2ppb9h55HJkuaxB!}h9QmcvNw~06t?u*HYkqHFyE)->&4#&t}xjJyNIl6ZT!qYa4XAyp+7=P0(va|aa(28l`4q2lxwIUNp1F4jy0 zD=a0~pfvzA^=4B;c>^1h&@NSAWFVy6)#mMXtfxK!GC;ivy%ywB9>9H7FN8}#Tqttg zSV}<_8 zW#b?T0}Zk?Fk(6RqT*MAab`h&dGSJKHxvOi$VV*^G4vU<{X{l7MlA7NYEX@k4O~8L0b&%7q!-yyP>Wm zE{)Y+;wnmM)?ZW@?o+~L$wmzw$#ewNqg71ih_`S&h9}<`QN*Xpn#x8aU+(ahqW{Vr zFoS}`FO$DD!*eS?d7#9`uYwg>Gh=oxj|z588Yg1jwUDP=9*dDpZrQTjW&L2ARanu{ zJN170 zu?rJXHV=aAfX-a2&RGfOuJVpr$~PmDG2vbnS@Vf6)9uCya@8gg2!4JaIo=6*~{ zd}nvtDmKr8L5j`GmeW+z&}0wWS&Ar!VGData6S=A6v?+N2NQ5*W6tyV!?M^z+ZM22gS@6#J&8o^~mmH`lYbTjdIBo8vmZD=Z~K*eZLD>9WL zV;qS?VjPM?pl6yF#(9bpT^Ls3ILy=%D2t*!-(&>upi>4_mcSCB*e|q|a(L_Y?#5pBWcXVbM6EDDc89D@KyOVILV?C{Sf>9X?nbLQ;Uz3G&f6Efj}xK{Oy> zG#;yh7&(k5BuZ=s_?hShahWMjSZ=@;F|3M_HihGp^d}OXx(HlAIC?m5)Pv=X;Z_Tv zOLAvadN(wRidpMBeR37O=vN}_z9`+S>Bkr%bI8`OIb6;e@-}e5(G+iyiwSo z{?bE)@fmS5w3e#PS~=N@EnLi>jNzJJm4hI;}Bng>w|@GEWRKOO(0;2V7(0+ z(a0J=6u(8<+CuRdgA3y>F=|wd$NETIqQ~aV(nR}|vXAs8?^zGCw{?;H%W|y6P&;7x zvy#~mX4F?VfaULMN_}!+A}jS@@8wzA?{5KNxZ{!s-$%#?&^;Mi z?l8C$PrB?U8&A5;D+N!w#c(Xc%5~tm3s1VTYaO0+57?b}K5{?e<4Nc8C*w(1KpaiC za&(#3<9O0}*6Z-hM%j1cnU;t;;7M1@ad@WUaqL@2kIh~`#gmxO4S3RtT%~vdv|K8l zba8j+Rx7vb7LI!f&kgW@5YI07-;L)Z_%`E7cQmBo`4q*!#mWug`4paK5WWu2^f->I zz|#&ME*VcVzEAR~C!R0ixeLz+@ub`BI`G6Nr^b_RAeZAw7oVM2VC5Dm5FgJ}9{J*V z77-iq+;tn8g=aV&qH`B<=rEmPcMMN8j8q5l4F4*akrFK;uqwy)C)gyo`=J3P9y6+s z7P-l$KC*ghmCV?YMB*{UeNWJ+feR+Pbz)wP##~OBm#S`B7EX&HB z-U{E!WsoU?lkWB`1H9aA7=wsR5~XD@NgxT^GFout_H{s^8}mE;LCi~a17XOHVc(E510#GMt^-VRZ9wH{}=R8+NC?UlJ5m?)OV zK^g*WLN!P;45zHvw7aOG52m@c zb)evv`C7R@OY8AUR|z-;GQiqNxi^cJK$L1&7M8@p)>1xM=mo6+`NY(vLIznwTQ`-< zWh6vIY1})kY+7ZLbO_W{E-m|6%zCbb%t0zJVM5MyIvmE#hk(eGwhW9sS>JHmIMHf{ zJcv5elWg4^U1G`7C%2y3AsVMqu+FIE;!WNf*#~Vw<9i~tS z;vAeOLEQcFhXj-e6Ge`@H=%Qt!`sf?hp$;LacyS8t~iwtLh9K)nsP^CZ%u z>xgZ|n1Qqt@EN6;03O-C+u~b0#kZe`Fz#Lgn+wWYeZ44g4R;rE!6=1lnVR}7Su68>UDhi3+(IoR!`4=;&w<=- zwOE&4Zirgb?^@$%UEAjMkhQ~StVJ{kJNpPr&cs*J8isOoblBF>3V)S@`!9Jzx5LrL zosJDH5jQwRB5_CJ!6)=#Y*xnZBl(oGL7CGL7MOFx^2Tt}>>~4rgGp$#mH6DWS1;^& zMBdaZ)}QKu)_`%8I*a=mQGlxl%PK*YXy=K;ZO2jonQ{j~b7E`p3z2@=9d5RQ!pa=h zO4M@hVH(4Y&h|CTgX4Y|Q@2Le?Uh(wj>Py%H74)>mwqpOUc||Zz~{nU`6te?^q1U8 zIpW~}ve@4N_`O8_MX|o%GvW6*`SX+gAB5i)@&_*(`|BgWtNgksY%p$8s2zT#%zu(M zmkB?f{8^2oVad!d`W^cwN7yj3F9c%}_CF-EatGj8sn|tDPbJ{=4E&ygqaO=nZ{nZF z;Sbh!((gg|4NCE+hOL8tkqqa>;4G_fqPyYO2*<zO$Ot*IOO*f;5G=q zb#U}cfq(3;5B^0c^t10o+gkxYGsT}Am75R06!NFvlrYir^1s7~Cr6s8(T~MR`COia z`5cnMW79nizn{Xz`cdR<-;me3D}>qMS1S2W%IgYo!_~V|eU5ThuFo#`U+ovJPi(o5 zBYwC(vFWybQ$AM+TL!->$v-y#>?_0#mqUFs^+)+!?RTa4(AIF{6GbdZEdHL5{H~PO zafHRzk>Wf9zo(=$Q^T&52l-v8K6igZxppZmww|Tm5P#hjVDU}xF<&9CO!)C|Q`?jV zzeKpHwCT*HBJKnn$kU|X0r(BW#nzo748iXixP(cuIqos|JpwmvivNS~+X6RzihmdU zuJ&6dg@x;M%yxAgp**ezhf?Ho864nuH8@ba!exf*cJ`k*J`HXv9KzvOdY(Z1spSsC z?kSMbMSv`n^r_uV-EZt5VVyyR;9ZRQ%dR{XVb^?0k~YPlMGSK@CO z-s$(U{Ig3UHpWXhDLxBXD2;!41Xm?5ZXG7MIOON$+?%+fpe6{1C{* zc$DS9cL$48%ax-194;UJnP^`%z82!WgXOV?#ql9k2hzCV-vWR7a$z4Al~IH8s3h{c zJTxCQrGND6=5CABw~wV*kJN3f?i6mvyAQD_Ps(o%E3u!|gU86GG!)(|g%+`I*!&>I zO5~D@RuU`;y83_6|2&4IUt z$Y&9#ezd%1R&x)+3EuQ;27Gfl(OyW5Oa1F*@u)rBF^~}JlrN>5hkUCLZxxG0z1;`u zMlD%|eunUlVZdZRp8Je@m3tYG6ycu-U7h%z$7xxc?lR|E zN-R%Vp0+$=*=0Fo`Ge)lg6Ty3dFc7@xL;YGw=(ZU-tPRD^BdGlQO5_=yVako6}oa= zweB5Vwmx6qpHke4WaoDp9Rc3928c zex!OzwMX@dYE+e^o~Kr-b!v;cQT=W8ggQYpQ*(!=Lh~!l%bH`F4>g}?g4&0*Kh(ag zeP8>L_B!1>-R-(Hx_fj%-NU*kbpN4yR`-f-zwWT^kGcRQ!NH^#W1qPd; z$1q^{m0`qi+MqDz8w-r(#(rba_yglk<6FiG(=O8srr(+3%!%gN=DFti=5+HSbDmje zE;QTBcbYGnD=iON_FD`E0|oz9@aKY03pNuBieLkaheA0=$txEt?aI598JnR$j=4Vi{g!(zi- z29Mz9%aNyk>dVGQS|VKwnS>sPq=x zU-09C=L(J&d|WUFJfB^7L!qv)vGAV4hk%8@Ej&{A3Bl=Zj?)893CetBv9eOxqI4)X zDR(G;r5sVdqdcWNubi1TKTnxw&8y98&g;wDl=l#D^A~xqL7cjtd6e|!E9^LOUYQ)R2lR86W5l}9z8`Zv|TtAfhBL*MFq{tA45BKEpOc(D1O~M}~hl z{MxX~@Pgrt;hbTn@fu^UQEl986pa6BeAM`oagXs+<8)K1>1LDD)Mt9g^oZ$)rk|Kx z=6RMoEE-Fvm>8Tq>W{`?>1|2qE$;P1n#*VS*SPokAcn)#YcO&jRltD4_w zW@)d}>a-T^YV8BsM?mT3=<+ZML%LadmA(m>^Bw(W{ZI8X3<|@yfI&Hie1id_u>_d3 z8sqT?z@k~k>x^~A7UK$IhjF!WE86xCBWFrCEi#pvs!R>Qs8-WUreR>x0n?kNL#Csq zW2WnYM`}>S9<$qgpZQ1TUzlGqA2c5`pE6%ECt8v%DV9`AnkCm#VQH`|wXC=7uL#U0xk34JznQ7y0ABpM@%=szJ3} z)vmf<^?lWIs#jF6sXkW8)k$iDx=`&`|6Dz+KCJ#&J+8hD^sPn{(0o_(1Tbc|=50{A zkmhSm9PlMutJl_O@6vW_`?Ox|I_(DSp!PBC6WX6^f2sX1?QZQ$+P&I?+QZso+7Gp- zw13l{)qbr_(52~kol$qc?m^v8bidTSs5_&(S)ZZLMvqwZi}iK-yYyXpm%d*=px>f@ zQ2%fGC-lG6{}*PPbC?m*4a*GwW_aB2tl>q&?F`$D#+62=ag+JC=H~(9L*|dne>JyS z9<}_ZWytcL<_6-O1EA2 zm~N-;W!(wgV*LjF5A-kS7Z`RJo(44b7(O}pnygc-Rq(sKFv{(iq+@6YG+KFWs0tyvh@yv1#~c0b$?x&&=pW0Z^wBy{hv&4xc%8THiuieUH4{dDlT=ll75JfFvXxC@;y z4Bvr5>-Bv)p-=18aWM+pZ83HldyN7pe;wRn^EGqQyaIKkl4!ZgX8%fk}C{;6CETp-_vr%S(F$ z-VJY)NQ&cP1bul`)W{R^PTE1Ish^K=uX>PE5;P95Hz=X8S$Try_ z`{WmLiI;f=d5@|R^`QDteXPd(&;6#LIY3Y_v-g_ zUPmUteq6&z<9+Dmn9m@K&DJPV_^Y*O-ED8QH`}Hiw*>{%q4uj!{Aa-fykHvj3J)fY z-Nse(rnwIKK5xAY+Fih=yY7s+wa{s&SMx(n>zq#jm} zD_d#RptgaRJJqYIUA>{+REO0OoZ?AnI)V1x;FqI;AM*|WDLC{M|8>95KMrR80A}7E zJQNgzZ{X0sgL}gJ!vkS=*cYA&|AN*}>OFd&KA;bwcaP~w{k6WN=k$;IivCS6=|5L_ zIgk4y@wE0aeDS}pzO!b|>{71{(<{tMtOUoDW~13^ zrp<$9zd2xzn0c(%Ic(QuGiH@q)s}C?t!66?x3^h2YtR~k-wL39#ICd*TiOXbZD+x( zemjp86p_efEQV623Yl!e#>zN3XV58NGfbmRBW{^n4*n<%FD(i}2`*j8K$HC`RQ}0k>9BEg9rsDf`p_*EUiUdLTuul%_14+YJg1&>++u zp*)?ZB2B@+b2Lv2v2#@GtG4UmySg diff --git a/extracters/ods2/ODS2.vcxproj b/extracters/ods2/ODS2.vcxproj index 090c879..9d826bb 100644 --- a/extracters/ods2/ODS2.vcxproj +++ b/extracters/ods2/ODS2.vcxproj @@ -1,5 +1,5 @@  - + Debug @@ -12,15 +12,18 @@ Win32Proj + {BCCEAED2-1732-D796-1F70-040DE5DA42AD} Application true + v140 Application false + v140 @@ -43,10 +46,10 @@ - DEBUG_BUILD;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + HOME_SKIP=1 ;HOME_LOG;USE_VLD;DEBUG_BUILD;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) MultiThreadedDebugDLL Level3 - ProgramDatabase + EditAndContinue Disabled @@ -98,6 +101,7 @@ copy $(OutDir)$(TargetName)$(TargetExt) $(SolutionDir)$(TargetName)$(TargetExt) $(SolutionDir)$(TargetName)$(TargetExt) Copying $(TargetName)$(TargetExt) + $(OutDir)$(TargetName)$(TargetExt) diff --git a/extracters/ods2/access.c b/extracters/ods2/access.c index 375d2ec..7491681 100644 --- a/extracters/ods2/access.c +++ b/extracters/ods2/access.c @@ -51,6 +51,15 @@ struct WCBKEY { struct WCB *prevwcb; }; +#if 0 +static unsigned int delta_from_name( const char *diskname ); +#endif +static unsigned int delta_from_index( size_t index ); +static unsigned int compute_delta( unsigned long sectorsize, + unsigned long sectors, + unsigned long tracks, + unsigned long cylinders ); + unsigned deallocfile(struct FCB *fcb); /* Update.c */ #define DEBUGx @@ -287,6 +296,7 @@ static void *wcb_create( unsigned hashval, void *keyval, unsigned *retsts ) { curvbn = wcbkey->prevwcb->hd_basevbn; wcb->hd_seg_num = wcbkey->prevwcb->hd_seg_num; memcpy(&wcb->hd_fid,&wcbkey->prevwcb->hd_fid,sizeof(struct fiddef)); + head = wcbkey->fcb->head; } while (TRUE) { register unsigned short *mp; @@ -825,15 +835,28 @@ unsigned dismount(struct VCB * vcb) /******************************************************************** mount() */ #ifdef DEBUG -#define HOME_LIMIT 5 +#ifndef HOME_SKIP +#define HOME_SKIP 1 +#endif +#ifndef HOME_LIMIT +#define HOME_LIMIT 3 +#endif #else -#define HOME_LIMIT 100 +#ifndef HOME_SKIP +#define HOME_SKIP 0 +#endif +#ifndef HOME_LIMIT +#define HOME_LIMIT 1000 +#endif #endif /* mount() make disk volume available for processing... */ -unsigned mount(unsigned flags,unsigned devices,char *devnam[],char *label[], - struct VCB **retvcb) { +unsigned mount( unsigned flags, + unsigned devices, + char *devnam[], + char *label[], + struct VCB **retvcb ) { register unsigned device,sts = 0; struct VCB *vcb; struct VCBDEV *vcbdev; @@ -842,13 +865,21 @@ unsigned mount(unsigned flags,unsigned devices,char *devnam[],char *label[], #ifdef DEBUG if (sizeof(struct HOME) != 512 || sizeof(struct HEAD) != 512) return SS$_NOTINSTALL; #endif - vcb = (struct VCB *) calloc(1, sizeof(struct VCB) + (devices - 1) * sizeof(struct VCBDEV)); - if (vcb == NULL) return SS$_INSFMEM; + if( retvcb ) + *retvcb = NULL; + + vcb = (struct VCB *) calloc( 1, sizeof(struct VCB) + + ((devices - 1) * sizeof(struct VCBDEV)) ); + if( vcb == NULL ) + return SS$_INSFMEM; + vcb->status = 0; - if (flags & MOU_WRITE) vcb->status |= VCB_WRITE; + if( flags & MOU_WRITE ) + vcb->status |= VCB_WRITE; vcb->fcb = NULL; vcb->dircache = NULL; vcb->devices = 0; + vcbdev = vcb->vcbdev; for( device = 0; device < devices; device++, vcbdev++ ) { char *dname; @@ -857,9 +888,12 @@ unsigned mount(unsigned flags,unsigned devices,char *devnam[],char *label[], sts = SS$_NOSUCHVOL; vcbdev->dev = NULL; if (strlen(dname)) { /* Really want to allow skipping volumes? */ - unsigned int hba; + unsigned int hba, delta, homtry; - if( label[device] != NULL && strlen(label[device]) > sizeof( volsetSYS[0].vsr$t_label ) ) { + if( label[device] != NULL && strlen(label[device]) > + sizeof( volsetSYS[0].vsr$t_label ) ) { + printf( "%%ODS2-E-BADPARAM, Label %s is too long\n", + label[device] ); sts = SS$_BADPARAM; break; } @@ -876,35 +910,44 @@ unsigned mount(unsigned flags,unsigned devices,char *devnam[],char *label[], break; } } + vcb->devices++; sts = device_lookup( strlen( dname ), dname, TRUE, &vcbdev->dev ); - if ( !( sts & STS$M_SUCCESS ) ) break; + if( !(sts & STS$M_SUCCESS) ) + break; vcbdev->dev->access = flags; /* Requested mount options */ /* (e.g., /Write) */ sts = phyio_init( vcbdev->dev ); - if ( !( sts & STS$M_SUCCESS ) ) break; - vcb->devices++; + if( !(sts & STS$M_SUCCESS) ) + break; if (vcbdev->dev->vcb != NULL) { sts = SS$_DEVMOUNT; break; } - for (hba = 1; hba <= HOME_LIMIT; hba++) { + delta = delta_from_index( (vcbdev->dev->access & MOU_DEVTYPE) >> MOU_V_DEVTYPE ); + + for( hba = 1, homtry = 0; homtry < HOME_LIMIT; homtry++, hba += delta ) { struct HOME *hom; +#if HOME_SKIP > 100 + if( homtry < HOME_SKIP ) + continue; +#endif sts = phyio_read( vcbdev->dev, hba, sizeof( struct HOME ), (char *) &vcbdev->home ); if (!(sts & STS$M_SUCCESS)) break; hom = &vcbdev->home; -#ifdef DEBUG - printf( "--->mount(): LBA=%u, HM2$L_HOMELBN=%u, " +#if defined( DEBUG ) || defined( HOME_LOG ) + printf( "--->mount(%u): LBA=%u, HM2$L_HOMELBN=%u, " + "HM2$L_ALHOMELBN=%u, " "HM2$T_FORMAT=\"%12.12s\", memcmp()=%u\n", - hba, VMSLONG( hom->hm2$l_homelbn ), + homtry+1,hba, VMSLONG( hom->hm2$l_homelbn ), + VMSLONG( hom->hm2$l_alhomelbn ), hom->hm2$t_format, memcmp( hom->hm2$t_format, "DECFILE11B ", 12 ) ); #endif - if( (hba == VMSLONG(hom->hm2$l_homelbn) || - hba == VMSLONG(hom->hm2$l_alhomelbn)) && + if( (hba == VMSLONG(hom->hm2$l_homelbn)) && (VMSLONG(hom->hm2$l_alhomelbn) != 0) && (VMSLONG(hom->hm2$l_altidxlbn) != 0) && (VMSWORD(hom->hm2$w_homevbn) != 0) && @@ -919,7 +962,7 @@ unsigned mount(unsigned flags,unsigned devices,char *devnam[],char *label[], (memcmp(hom->hm2$t_format,"DECFILE11B ",12) == 0) ) { break; } -#ifdef DEBUG +#if defined( DEBUG ) || defined( HOME_LOG ) printf( "--->mount(): Home block validation failure\n" ); printf( "(VMSLONG(hom->hm2$l_alhomelbn) != 0) %u\n", (VMSLONG(hom->hm2$l_alhomelbn) != 0) ); printf( "(VMSLONG(hom->hm2$l_altidxlbn) != 0) %u\n", (VMSLONG(hom->hm2$l_altidxlbn) != 0) ); @@ -1102,7 +1145,11 @@ unsigned mount(unsigned flags,unsigned devices,char *devnam[],char *label[], if( !(sts & 1) ) { vcbdev = vcb->vcbdev; for( device = 0; device < devices; device++, vcbdev++ ) { - if (vcbdev->dev == NULL) continue; + if (vcbdev->dev == NULL) { + if( flags & MOU_VIRTUAL ) + virt_device( devnam[device], NULL ); + continue; + } if( vcb->status & VCB_WRITE && vcbdev->mapfcb != NULL ) { /* sts = */ @@ -1127,6 +1174,11 @@ unsigned mount(unsigned flags,unsigned devices,char *devnam[],char *label[], } else { /* *** DECREF *** */ vcbdev = vcb->vcbdev; for( device = 0; device < vcb->devices; device++, vcbdev++ ) { + if (vcbdev->dev == NULL) { + if( flags & MOU_VIRTUAL ) + virt_device( devnam[device], NULL ); + continue; + } phyio_done( vcbdev->dev ); } free(vcb); @@ -1314,3 +1366,198 @@ void show_volumes( void ) { return; } + +/*************************************************************** acccess_rundown() */ +void access_rundown( void ) { + struct VCB *vcb, *next; + unsigned sts; + + for( vcb = vcb_list; vcb != NULL; vcb = next ) { + next = vcb->next; + + sts = dismount( vcb ); + if( !(sts & STS$M_SUCCESS) ) { + printf( "Dismount failed in rundown: %s", getmsg(sts, MSG_TEXT) ); + } + } +} + +/*************************************************************** compute_delta() */ +/* + * The search delta is computed from the + * volume geometry, expressed in sectors, tracks (surfaces), and + * cylinders, according to the following rules, to handle the cases where + * one or two dimensions of the volume have a size of 1. + * + * Geometry: Delta + * + * s x 1 x 1: 1 Rule 1 + * 1 x t x 1: 1 Rule 2 + * 1 x 1 x c: 1 Rule 3 + * + * s x t x 1: s+1 Rule 4 + * s x 1 x c: s+1 Rule 5 + * 1 x t x c: t+1 Rule 6 + * + * s x t x c: (t+1)*s+1 Rule 7 + */ + + +#define DISK( name, sectors, tracks, cylinders ) \ + {#name, 512 ## ul, sectors ## ul, tracks ## ul, cylinders ## ul}, +#define DISKS( name, sectorsize, sectors, tracks, cylinders ) \ + {#name, sectorsize ## ul, sectors ## ul, tracks ## ul, cylinders ## ul}, +struct disktype disktype[] = { + DISK(UNKNOWN, 1, 1, 1) /* First = short sequence delta = 1 */ + DISK(RK05, 12, 2, 203) + DISK(RK06, 22, 3, 411) + DISK(RK07, 22, 3, 815) + DISK(RK11, 12, 2, 203) + + DISK(RL01, 40, 2, 256) + DISK(RL02, 40, 2, 512) + + DISK(RM02, 32, 5, 823) + DISK(RM03, 32, 5, 823) + DISK(RP04, 22, 19, 411) + DISK(RP05, 22, 19, 411) + DISK(RM80, 31, 14, 559) + DISK(RP06, 22, 19, 815) + DISK(RM05, 32, 19, 823) + DISK(RP07, 50, 32, 630) + +#if 0 /* Not useful now as RSX20-F used ODS-1 */ + DISKS(RM02-T, 576, 30, 5, 823) + DISKS(RM03-T, 576, 30, 5, 823) + DISKS(RP04-T, 576, 20, 19, 411) + DISKS(RP05-T, 576, 20, 19, 411) + DISKS(RM80-T, 576, 30, 14, 559) + DISKS(RP06-T, 576, 20, 19, 815) + DISKS(RM05-T, 576, 30, 19, 823) + DISKS(RP07-T, 576, 43, 32, 630) +#endif + + DISK(RX50, 10, 1, 80) + DISK(RX33, 15, 2, 80) + +#if 0 + DISK(RD50, 99, 99, 9999) +#endif + DISK(RD51, 18, 4, 306) + DISK(RD31, 17, 4, 615) + DISK(RD52, 17, 8, 512) + DISK(RD53, 17, 7, 1024) + DISK(RD54, 17, 15, 1225) + + DISK(RA72, 51, 20, 1921) + +#if 0 + DISK(RA80, 99, 99, 9999) + +#endif + DISK(RA81, 51, 14, 1258) + DISK(RA82, 57, 15, 1435) + + DISK(RA90, 69, 13, 2649) + DISK(RA92, 73, 13, 3099) + + DISK(RRD40,128, 1, 10400) + DISK(RRD50,128, 1, 10400) + DISKS(RX01, 128, 26, 1, 77) + DISKS(RX02, 256, 26, 1, 77) + +#if 0 + DISK(RX23-SD, 99, 99, 9999) + DISK(RX23-DD, 99, 99, 9999) + + DISK(RX33-SD, 10, 1, 80) + DISK(RX33-DD, 99, 99, 9999) +#endif + + DISK(RX50, 10, 1, 80) +#if 0 + DISK(RC25, 99, 99, 9999 ) + + DISK(RF30, 99, 99, 9999 ) + DISK(RF31, 99, 99, 9999 ) + DISK(RF35, 99, 99, 9999 ) + DISK(RF36, 99, 99, 9999 ) + DISK(RF71, 99, 99, 9999 ) + DISK(RF72, 99, 99, 9999 ) + DISK(RF73, 99, 99, 9999 ) + DISK(RF74, 99, 99, 9999 ) + + DISK(RZ22, 99, 99, 9999 ) + DISK(RZ23, 99, 99, 9999 ) + DISK(RZ24, 99, 99, 9999 ) + DISK(RZ25, 99, 99, 9999 ) + DISK(RZ26, 99, 99, 9999 ) + DISK(RZ27, 99, 99, 9999 ) + DISK(RZ28, 99, 99, 9999 ) + DISK(RZ29, 99, 99, 9999 ) + DISK(RZ31, 99, 99, 9999 ) + DISK(RZ33, 99, 99, 9999 ) + DISK(RZ35, 99, 99, 9999 ) + DISK(RZ55, 99, 99, 9999 ) + DISK(RZ56, 99, 99, 9999 ) + DISK(RZ57, 99, 99, 9999 ) + DISK(RZ58, 99, 99, 9999 ) + DISK(RZ59, 99, 99, 9999 ) + + DISK(RZ72, 99, 99, 9999 ) + DISK(RZ73, 99, 99, 9999 ) + DISK(RZ74, 99, 99, 9999 ) +#endif + + { NULL, 0, 0, 0, 0 } +}; + + +static unsigned int compute_delta( unsigned long sectorsize, + unsigned long sectors, + unsigned long tracks, + unsigned long cylinders ) { + + if( sectorsize < 512 ) + sectors = (sectorsize * sectors) / 512; + + if( sectors > 1 && tracks > 1 && cylinders > 1 ) /* Rule 7 */ + return (tracks + 1) * sectors +1; + + if( (sectors > 1 && tracks > 1 && cylinders == 1 ) || /* Rule 4 */ + (sectors > 1 && tracks == 1 && cylinders > 1 ) ) /* Rule 5 */ + return sectors + 1; + + if( sectors == 1 && tracks > 1 && cylinders > 1 ) /* Rule 6 */ + return tracks + 1; + + return 1; /* Rules 1-3 */ +} + +#if 0 +static unsigned int delta_from_name( const char *diskname ) { + struct disktype *dp; + + for( dp = disktype; dp->name != NULL; dp++ ) { + if( !strcmp( dp->name, diskname ) ) + return compute_delta( dp->sectorsize, dp->sectors, dp->tracks, dp->cylinders ); + } + + return ~0u; +} +#endif +static unsigned int delta_from_index( size_t index ) { + struct disktype *dp; + unsigned int delta; + + if( index >= sizeof(disktype)/sizeof(disktype[0]) ) + abort(); + dp = disktype + index; + delta = compute_delta( dp->sectorsize, dp->sectors, dp->tracks, dp->cylinders ); + +#if defined( DEBUG ) || HOME_SKIP > 0 + printf( "HOM search index for %s is %u\n", dp->name, delta ); +#endif + + return delta; +} diff --git a/extracters/ods2/access.h b/extracters/ods2/access.h index 5aab745..2ef9f46 100644 --- a/extracters/ods2/access.h +++ b/extracters/ods2/access.h @@ -256,6 +256,13 @@ struct VCB { extern struct VCB *vcb_list; void show_volumes( void ); +struct disktype { + const char *name; + unsigned long sectorsize, sectors, tracks, cylinders; +}; + +extern struct disktype disktype[]; + /* RVN_TO_DEV( vcb, rvn ) - returns device from relative volume number */ /* returns NULL if RVN illegal or device not mounted */ @@ -289,4 +296,6 @@ unsigned update_create(struct VCB *vcb,struct fiddef *did,char *filename, unsigned update_extend(struct FCB *fcb,unsigned blocks,unsigned contig); vmsword checksum( vmsword *block ); +void access_rundown( void ); + #endif /* # ifndef _ACCESS_H */ diff --git a/extracters/ods2/compat.c b/extracters/ods2/compat.c index 7282b49..e4bd3ed 100644 --- a/extracters/ods2/compat.c +++ b/extracters/ods2/compat.c @@ -5,7 +5,7 @@ * * Microsoft deprecates sprintf, but doesn't supply standard * replacement until very recent IDEs. - * Microsoft doesn't like fopen. + * Microsoft doesn't like fopen, or strerror, or getcwd. * One needs to use a M$ call to translate system errors. * * Finding out about drive letter assignments is unique to windows. @@ -18,12 +18,14 @@ #ifdef _WIN32 #include +#include #endif #if defined(_MSC_VER) && _MSC_VER < 1900 -int c99_vsnprintf(char *outBuf, size_t size, const char *format, va_list ap) -{ +/******************************************************************* c99_vsnprintf() */ + +int c99_vsnprintf(char *outBuf, size_t size, const char *format, va_list ap) { int count = -1; if (size != 0) @@ -34,8 +36,9 @@ int c99_vsnprintf(char *outBuf, size_t size, const char *format, va_list ap) return count; } -int c99_snprintf(char *outBuf, size_t size, const char *format, ...) -{ +/******************************************************************* c99_snprintf() */ + +int c99_snprintf(char *outBuf, size_t size, const char *format, ...) { int count; va_list ap; @@ -49,6 +52,8 @@ int c99_snprintf(char *outBuf, size_t size, const char *format, ...) #ifdef _MSC_VER +/******************************************************************* openf() */ + FILE *openf( const char *filename, const char *mode ) { errno_t err; FILE *fd = NULL; @@ -63,11 +68,24 @@ FILE *openf( const char *filename, const char *mode ) { #ifdef _WIN32 +/******************************************************************* ods2_strerror() */ + +const char *ods2_strerror( int errn ) { + static char buf[256]; + + if( strerror_s( buf, sizeof( buf ), errn ) != 0 ) + snprintf( buf, sizeof( buf ), "Untranslatable error %u", errn ); + + return buf; +} + +/******************************************************************* w32_errstr() */ + TCHAR *w32_errstr( DWORD eno, ... ) { va_list ap; TCHAR *msg; - if( eno == 0 ) + if( eno == NO_ERROR ) eno = GetLastError(); va_start(ap,eno); @@ -81,6 +99,8 @@ TCHAR *w32_errstr( DWORD eno, ... ) { return msg; } +/******************************************************************* driveFromLetter() */ + char *driveFromLetter( const char *letter ) { DWORD rv = ERROR_INSUFFICIENT_BUFFER; size_t cs = 16; diff --git a/extracters/ods2/compat.h b/extracters/ods2/compat.h index 5a4fa60..ae39b2b 100644 --- a/extracters/ods2/compat.h +++ b/extracters/ods2/compat.h @@ -20,11 +20,24 @@ FILE *openf( const char *filename, const char *mode ); #endif #ifdef _WIN32 +#include #include #include +#include +#undef getcwd +#define getcwd _getcwd +#undef chdir +#define chdir _chdir + +#undef strerror +#define strerror(n) ods2_strerror(n) +const char *ods2_strerror( errno_t errn ); TCHAR *w32_errstr( DWORD eno, ... ); char *driveFromLetter( const char *letter ); + +#else /* Not WIN32 */ +#include #endif #define UNUSED(x) (void)(x) diff --git a/extracters/ods2/makefile.solaris b/extracters/ods2/makefile.solaris index 2af0778..186be7d 100644 --- a/extracters/ods2/makefile.solaris +++ b/extracters/ods2/makefile.solaris @@ -7,7 +7,7 @@ CC=gcc CCFLAGS = -O4 -g DEFS = -DUSE_READLINE -LDFLAGS = -lreadline +LDFLAGS = -lreadline -ltermcap # Object file extension OBJ = .o diff --git a/extracters/ods2/makefile.tru64 b/extracters/ods2/makefile.tru64 index 640e94a..d4b10a3 100644 --- a/extracters/ods2/makefile.tru64 +++ b/extracters/ods2/makefile.tru64 @@ -4,7 +4,7 @@ CCFLAGS = -O4 -g # DEFS = -DUSE_READLINE -# LDFLAGS = -lreadline +# LDFLAGS = -lreadline -ltermcap # Object file extension OBJ = .o diff --git a/extracters/ods2/makefile.unix b/extracters/ods2/makefile.unix index 8f86399..fb334d4 100644 --- a/extracters/ods2/makefile.unix +++ b/extracters/ods2/makefile.unix @@ -9,7 +9,7 @@ CCFLAGS = -O4 -g # Include readline support DEFS = -DUSE_READLINE -LDFLAGS = -lreadline +LDFLAGS = -lreadline -ltermcap # Object file extension OBJ = .o diff --git a/extracters/ods2/ods2.c b/extracters/ods2/ods2.c index 3aefaff..0878537 100644 --- a/extracters/ods2/ods2.c +++ b/extracters/ods2/ods2.c @@ -104,32 +104,38 @@ #define _BSD_SOURCE #include /* isalpha(), isspace(), tolower() */ +#include #include #include #include #include -#include "version.h" -#include "compat.h" -#include "sysmsg.h" -#include "phyio.h" -#include "phyvirt.h" -#ifdef _WIN32 -#include -#endif +#include "version.h" + #include "access.h" +#include "compat.h" #include "descrip.h" #include "device.h" #include "direct.h" #include "ods2.h" #include "phyio.h" +#include "phyvirt.h" #include "rms.h" #include "ssdef.h" #include "stsdef.h" +#include "sysmsg.h" + +#if !defined( _WIN32 ) && !defined( VMS ) +#include +#include +#else +# ifdef _WIN32 +# include +# endif +#endif #ifdef VMS #include - #else #include "vmstime.h" #endif @@ -148,6 +154,14 @@ #define FALSE ( 0 != 0 ) #endif +#if defined( _WIN32 ) && defined(_MSC_VER) && defined( DEBUG_BUILD ) && defined( USE_VLD ) +/* Normally done in the project file, but VLD is optional and I'd rather not provide + * instructions as they vary by IDE version. See http://vld.codeplex.com/ if interested. + */ +#include "C:\\Program Files (x86)\\Visual Leak Detector\\include\\vld.h" +#pragma comment (lib,"C:\\Program Files (x86)\\Visual Leak Detector\\lib\\Win32\\vld.lib") +#endif + #define MAXREC 32767 #define PRINT_ATTR ( FAB$M_CR | FAB$M_PRN | FAB$M_FTN ) @@ -158,6 +172,7 @@ #include #endif +/******************************************************************* fgetline() */ /* Read a line of input - unlimited length * Removes \n, returns NULL at EOF * Caller responsible for free() @@ -170,7 +185,7 @@ static char *fgetline( FILE *stream, int keepnl ) { int c; while( (c = fgetc(stream)) != EOF && c != '\n' ) { - if( idx + (keepnl != 0) +1 > bufsize ) { /* Allow space for char + (optional \n) + \0 */ + if( idx + (keepnl != 0) +2 > bufsize ) { /* In buf + char + (optional \n) + \0 */ char *nbuf; bufsize += xpnsize; nbuf = (char *) realloc( buf, bufsize ); @@ -202,11 +217,12 @@ static char *fgetline( FILE *stream, int keepnl ) { return buf; } +/******************************************************************* keycomp() */ /* keycomp: routine to compare parameter to a keyword - case insensitive! */ static int keycomp(const char *param, const char *keywrd) { while (*param != '\0') { - if (tolower(*param++) != *keywrd++) return 0; + if( tolower(*param++) != tolower(*keywrd++) ) return 0; } return 1; } @@ -217,11 +233,12 @@ static int keycomp(const char *param, const char *keywrd) { */ #define NV NOVAL, NULL #define KV(list) KEYVAL, list +#define CV(list) KEYCOL, list struct qual { const char *name; int set; int clear; - enum qualtype { NOVAL, KEYVAL } qtype; + enum qualtype { NOVAL, KEYVAL, KEYCOL } qtype; void *arg; const char *helpstr; }; @@ -261,6 +278,7 @@ static void qualhelp( int par, struct qual *qtable ); static int vms_qual = 1; static int verify_cmd = 1; +/******************************************************************* checkquals() */ /* checkquals: Given valid qualifier definitions, process qualifer * list from a command left to right. Also handles parameters and * qualifier values (/Qual=value). @@ -322,6 +340,7 @@ static int checkquals(int result, struct qual qualset[],int qualc,char *qualv[]) *nvp++ = '\0'; switch( qp->qtype ) { case KEYVAL: + case KEYCOL: result = checkquals( result, (struct qual *)qp->arg, -1, &qv ); if( result == -1 ) return result; @@ -336,6 +355,9 @@ static int checkquals(int result, struct qual qualset[],int qualc,char *qualv[]) return result; } +/******************************************************************* dodir() */ +/*********************************************************** prvmstime() */ + static int prvmstime(VMSTIME vtime, const char *sfx) { int sts = 0; char tim[24]; @@ -358,6 +380,8 @@ static int prvmstime(VMSTIME vtime, const char *sfx) { return sts; } +/*********************************************************** pwrap() */ + static void pwrap( int *pos, const char *fmt, ... ) { char pbuf[200], *p, *q; va_list ap; @@ -392,6 +416,7 @@ static void pwrap( int *pos, const char *fmt, ... ) { } } +/*********************************************************** dirtotal() */ #define dir_extra (dir_date | dir_fileid | dir_owner | dir_prot | dir_size) #define dir_date (1 << 0) @@ -486,6 +511,8 @@ static void dirtotal( int options, int size, int alloc ) { return; } +/************************************************************ dodir() */ + static unsigned dodir(int argc,char *argv[],int qualc,char *qualv[]) { char res[NAM$C_MAXRSS + 1],rsa[NAM$C_MAXRSS + 1]; int options; @@ -1412,7 +1439,7 @@ static unsigned dostats( void ) { /******************************************************************* doshow() */ -/* show: version */ +/*********************************************************** show_version() */ #define MNAMEX(n) #n #define MNAME(n) MNAMEX(n) @@ -1431,23 +1458,26 @@ static void show_version( void ) { # endif printf( " direct SCSI access support"); #endif - printf( "\n\n" ); + printf( "\n " ); + phyio_show( SHOW_FILE64 ); + putchar( '\n' ); return; } -/* show: the show command */ +/*********************************************************** doshow() */ -static struct qual showkwds[] = { {"default", 0, 0, NV, "Default directory"}, - {"devices", 1, 0, NV, "Devices"}, - {"qualifier_style", 2, 0, NV, "Qualifier style (Unix, VMS)" }, - {"statistics", 3, 0, NV, "Debugging statistics", }, - {"time", 4, 0, NV, "Time"}, - {"verify", 5, 0, NV, "Command file echo" }, - {"version", 6, 0, NV, "Version"}, - {"volumes", 7, 0, NV, "Mounted volume information" }, +static struct qual showkwds[] = { {"cwd", 0, 0, NV, "Working directory on local system"}, + {"default", 1, 0, NV, "Default directory on VMS volume"}, + {"devices", 2, 0, NV, "Devices"}, + {"qualifier_style", 3, 0, NV, "Qualifier style (Unix, VMS)" }, + {"statistics", 4, 0, NV, "Debugging statistics"}, + {"time", 5, 0, NV, "Time"}, + {"verify", 6, 0, NV, "Command file echo" }, + {"version", 7, 0, NV, "Version"}, + {"volumes", 8, 0, NV, "Mounted volume information" }, {NULL, 0, 0, NV, NULL } }; -static struct param showpars[] = { {"item_name", REQ, KEYWD, PA(showkwds), NULL }, +static struct param showpars[] = { {"item_name", REQ, KEYWD, PA(showkwds), "" }, {NULL, 0, 0, NOPA, NULL } }; @@ -1463,6 +1493,29 @@ unsigned doshow(int argc,char *argv[],int qualc,char *qualv[]) { default: return SS$_BADPARAM; case 0: { + size_t size = 32; + char *buf = NULL; + while( 1 ) { + char *nbuf; + nbuf = (char *)realloc( buf, size ); + if( nbuf == NULL ) { + free( buf ); + return SS$_INSFMEM; + } + buf = nbuf; + if( getcwd( buf, size ) != NULL ) + break; + if( errno != ERANGE ) { + perror( "getcwd" ); + return SS$_BADPARAM; + } + size *= 2; + } + printf( " Current working directory is %s\n", buf ); + free( buf ); + return SS$_NORMAL; + } + case 1: { int sts; unsigned short curlen; char curdir[NAM$C_MAXRSS + 1]; @@ -1478,16 +1531,16 @@ unsigned doshow(int argc,char *argv[],int qualc,char *qualv[]) { } return sts; } - case 1: + case 2: phyio_show( SHOW_DEVICES ); virt_show( NULL ); return SS$_NORMAL; - case 2: + case 3: printf ( " Qualifier style: %s\n", vms_qual? "/VMS": "-unix" ); return SS$_NORMAL; - case 3: + case 4: return dostats(); - case 4: { + case 5: { unsigned sts; char timstr[24]; unsigned short timlen; @@ -1504,56 +1557,66 @@ unsigned doshow(int argc,char *argv[],int qualc,char *qualv[]) { } } return SS$_NORMAL; - case 5: + case 6: printf( "Command file verification is %s\n", (verify_cmd? "on": "off") ); return SS$_NORMAL; - case 6: + case 7: show_version(); return SS$_NORMAL; - case 7: + case 8: show_volumes(); return SS$_NORMAL; } return SS$_NORMAL; } -/******************************************************************* setdef() */ +/******************************************************************* doset() */ +/*********************************************************** setdef() */ -static unsigned setdef_count = 0; +static int default_set = FALSE; -static unsigned setdef( char *newdef ) -{ +static unsigned setdef( char *newdef ) { register unsigned sts; struct dsc_descriptor defdsc; defdsc.dsc_a_pointer = (char *) newdef; - defdsc.dsc_w_length = strlen( defdsc.dsc_a_pointer ); + defdsc.dsc_w_length = (unsigned short)strlen( defdsc.dsc_a_pointer ); sts = sys_setddir( &defdsc, NULL, NULL ); if ( sts & STS$M_SUCCESS ) { - setdef_count++; + default_set = TRUE; } else { printf( "%%ODS2-E-SETDEF, Error %s setting default to %s\n", getmsg(sts, MSG_TEXT), newdef ); } return sts; } -/******************************************************************** doset() */ +static unsigned setcwd( char *newdef ) { + if( chdir( newdef ) != 0 ) { + printf( "%%ODS2-W-SETDEF, Error %s setting cwd to %s\n", + strerror( errno ), newdef ); + return SS$_BADPARAM; + } + return SS$_NORMAL; +} + +/************************************************************ sethelp() */ static hlpfunc_t sethelp; -static struct qual setkwds[] = { {"default", 0, 0, NV, "Default directory"}, +static struct qual setkwds[] = { {"cwd", 0, 0, NV, "Working directory on local system"}, {"directory_qualifiers", 1, 0, NV, "Default qualifiers for DIRECTORY command" }, - {"qualifier_style", 2, 0, NV, "Qualifier style (Unix, VMS)" }, - {"verify", 3, 0, NV, "-Display commands in indirect files" }, - {"noverify", 4, 0, NV, NULL }, + {"default", 2, 0, NV, "Default directory on VMS volume"}, + {"qualifier_style", 3, 0, NV, "Qualifier style (Unix, VMS)"}, + {"verify", 4, 0, NV, "-Display commands in indirect files"}, + {"noverify", 5, 0, NV, NULL }, {NULL, 0, 0, NV, NULL } }; static struct qual setqskwds[] = {{"unix", 1, 0, NV, "Unix style options, '-option'"}, {"vms", 2, 0, NV, "VMS style qualifiers, '/qualifier'"}, {NULL, 0, 0, NV, NULL } }; -static struct param setpars[] = { {"item_name", REQ, KEYWD, PA(setkwds), NULL }, - {"value" , CND, KEYWD, sethelp, setqskwds, NULL }, +static struct param setpars[] = { {"item_name", REQ, KEYWD, PA(setkwds), "" }, + {"value" , CND, KEYWD, sethelp, setqskwds, "" }, {NULL, 0, 0, NOPA, NULL }, }; @@ -1575,21 +1638,25 @@ static const char * sethelp( struct CMDSET *cmd, struct param *p, int argc, char return NULL; switch( par ) { case 0: - p->helpstr = "default directory on volume - "; - p->ptype = VMSFS; + p->helpstr = "working directory for local files"; + p->ptype = STRING; break; case 1: + p->helpstr = "default directory on volume"; + p->ptype = VMSFS; + break; + case 2: p->helpstr = "directory qualifier name "; p->ptype = KEYWD; p->arg = dirquals; break; - case 2: + case 3: p->helpstr = "style "; p->ptype = KEYWD; p->arg = setqskwds; break; - case 3: case 4: + case 5: p->ptype = NONE; break; @@ -1599,6 +1666,8 @@ static const char * sethelp( struct CMDSET *cmd, struct param *p, int argc, char return NULL; } +/*********************************************************** doset() */ + static unsigned doset(int argc,char *argv[],int qualc,char *qualv[]) { int parnum; @@ -1611,11 +1680,12 @@ static unsigned doset(int argc,char *argv[],int qualc,char *qualv[]) { default: return SS$_BADPARAM; case 0: /* default */ + case 2: /* current working directory */ if( qualc ) { printf( "%%ODS2-E-NOQUAL, No qualifiers are permitted\n" ); return 0; } - return setdef( argv[2] ); + return (parnum == 0)? setdef( argv[2] ) : setcwd( argv[2] ); case 1:{ /* directory_qualifiers */ int options = checkquals(dir_default,dirquals,qualc,qualv); if( options == -1 ) @@ -1623,7 +1693,7 @@ static unsigned doset(int argc,char *argv[],int qualc,char *qualv[]) { dir_defopt = options; return 1; } - case 2: { /* qualifier_style */ + case 3: { /* qualifier_style */ int par = checkquals (0,setqskwds,1,argv+2); if( par == -1 ) return SS$_BADPARAM; @@ -1639,16 +1709,16 @@ static unsigned doset(int argc,char *argv[],int qualc,char *qualv[]) { } return 1; } - case 3: + case 4: verify_cmd = 1; return 1; - case 4: + case 5: verify_cmd = 0; return 1; } } -/* The bits we need when we don't have real VMS routines underneath... */ +/******************************************************************* dodismount() */ static struct param dmopars[] = { {"drive_letter", REQ, STRING, NOPA, "Drive containing volume to dismount", }, {NULL, 0, 0, NOPA, NULL } @@ -1678,7 +1748,10 @@ unsigned dodismount(int argc,char *argv[],int qualc,char *qualv[]) { #error MOU_WRITE != 1 #endif -static struct qual mouquals[] = { {"image", MOU_VIRTUAL, 0, NV, "Mount a disk image file", }, +#define DT_NAME "drive_type" + +static struct qual mouquals[] = { {DT_NAME, 0, MOU_DEVTYPE, CV(NULL), "Drive type (DEC model name) "}, + {"image", MOU_VIRTUAL, 0, NV, "Mount a disk image file", }, {"readonly", 0, MOU_WRITE, NV, "Only allow reading from volume"}, {"virtual", MOU_VIRTUAL, 0, NV, NULL, }, {"write", MOU_WRITE, 0, NV, "Allow writing to volume", }, @@ -1691,6 +1764,10 @@ static struct param moupars[] = { {"volumes", REQ, LIST, NOPA, { NULL, 0, 0, NOPA, NULL } }; +/******************************************************************* domount() */ + +/*********************************************************** parselist() */ + static int parselist( char ***items, size_t min, char *arg, const char *label ) { size_t n = 0, i; char **list = NULL; @@ -1737,7 +1814,9 @@ static int parselist( char ***items, size_t min, char *arg, const char *label ) return (int)n; } -static unsigned domount(int argc,char *argv[],int qualc,char *qualv[]) { +/*********************************************************** domount() */ + +static unsigned domount( int argc,char *argv[],int qualc,char *qualv[] ) { int sts = 1,devices = 0; char **devs = NULL, **labs = NULL; @@ -1760,7 +1839,7 @@ static unsigned domount(int argc,char *argv[],int qualc,char *qualv[]) { struct VCB *vcb; sts = mount( options | MOU_LOG, devices, devs, labs, &vcb ); if (sts & STS$M_SUCCESS) { - if (setdef_count == 0) { + if( !default_set ) { char *colon, *buf; size_t len; @@ -1770,7 +1849,8 @@ static unsigned domount(int argc,char *argv[],int qualc,char *qualv[]) { perror( "malloc" ); } else { colon = strchr( vcb->vcbdev[0].dev->devnam, ':' ); - if( colon != NULL ) len = (size_t)(colon - vcb->vcbdev[0].dev->devnam); + if( colon != NULL ) + len = (size_t)(colon - vcb->vcbdev[0].dev->devnam); memcpy( buf, vcb->vcbdev[0].dev->devnam, len ); memcpy( buf+len, ":[000000]", sizeof( ":[000000]" ) ); setdef(buf); @@ -1788,8 +1868,68 @@ static unsigned domount(int argc,char *argv[],int qualc,char *qualv[]) { return sts; } +/******************************************************************* dospawn() */ + +static unsigned dospawn( int argc,char *argv[],int qualc,char *qualv[] ) { +#ifdef VMS + unsigned sts; + + UNUSED( argc ); + UNUSED( argv ); + UNUSED( qualc ); + UNUSED( qualv ); + + sts = lib$spawn( 0,0,0,0,0,0,0,0,0,0,0,0,0 ); + return sts; +#else +# ifdef _WIN32 + UNUSED( argc ); + UNUSED( argv ); + UNUSED( qualc ); + UNUSED( qualv ); + + if( system( "cmd" ) == -1 ) { + perror( "cmd" ); + return SS$_NOSUCHFILE; + } + return SS$_NORMAL; +# else + char *shell, *p; + pid_t pid; + + UNUSED( argc ); + UNUSED( argv ); + UNUSED( qualc ); + UNUSED( qualv ); + + if( (shell = getenv( "SHELL" )) == NULL ) + shell = "/bin/sh"; + if( (p = strrchr( shell, '/')) == NULL ) + p = shell; + else + p++; + + if( (pid = fork()) == 0 ) { + execlp( shell, p, (char *)NULL ); + perror( "%s" ); + exit(EXIT_FAILURE); + } + if( pid == -1 ) { + perror( shell ); + return SS$_NOSUCHFILE; + } + waitpid( pid, NULL, 0 ); + + return SS$_NORMAL; +# endif +#endif + +} + /******************************************************************* dohelp() */ +/*********************************************************** cmdhelp() */ + static void cmdhelp( struct CMDSET *cmdset ) { struct CMDSET *cmd; int n = 0; @@ -1809,10 +1949,12 @@ static void cmdhelp( struct CMDSET *cmdset ) { printf( "\n" ); } +/*********************************************************** cmdhelp() */ + static void qualhelp( int par, struct qual *qtable ) { struct qual *q; int n = 0; - size_t max = 0; + size_t max = 0, col = 4; if( par < 0 ) max = -par; @@ -1838,14 +1980,28 @@ static void qualhelp( int par, struct qual *qtable ) { if( *q->helpstr == '-' ) switch( q->qtype ) { case NOVAL: - printf( NOSTR "%-*s - %s\n", - (int) (max-NOSTR_LEN), q->name, q->helpstr+1 ); + if( *q->helpstr ) { + printf( NOSTR "%-*s - %s\n", + (int) (max-NOSTR_LEN), q->name, q->helpstr+1 ); + break; + } + if( col + max > 50 ) { + printf( "\n " ); + col = 8; + } else { + while( col < 8 ) { + putchar( ' ' ); col++; + } + } + printf( "%-*s", (int) max, q->name ); + col += max; break; case KEYVAL: + case KEYCOL: printf( NOSTR "%s=%-*s - %s\n", q->name, (int) (max-(NOSTR_LEN+strlen(q->name)+1)), "", q->helpstr+1 ); - qualhelp( -(int)max, (struct qual *)q->arg ); + qualhelp( q->qtype == KEYCOL? 1 : -(int)max, (struct qual *)q->arg ); break; default: abort(); @@ -1853,12 +2009,26 @@ static void qualhelp( int par, struct qual *qtable ) { else switch( q->qtype ) { case NOVAL: - printf("%-*s - %s\n", (int) max, q->name, q->helpstr ); + if( *q->helpstr ) { + printf("%-*s - %s\n", (int) max, q->name, q->helpstr ); + break; + } + if( col + max > 50 ) { + printf( "\n " ); + col = 8; + } else { + while( col < 8 ) { + putchar( ' ' ); col++; + } + } + printf( "%-*s", (int) max, q->name ); + col += max; break; case KEYVAL: + case KEYCOL: printf( "%s=%-*s - %s\n", q->name, (int)(max-strlen(q->name)+1), "", q->helpstr ); - qualhelp( -(int)max, (struct qual *)q->arg ); + qualhelp( q->qtype == KEYCOL? 1 : -(int)max, (struct qual *)q->arg ); break; default: abort(); @@ -1871,6 +2041,8 @@ static void qualhelp( int par, struct qual *qtable ) { #undef NOSTR #undef NOSTR_LEN +/*********************************************************** parhelp() */ + static void parhelp( struct CMDSET *cmd, int argc, char **argv) { struct param *p; struct param *ptable; @@ -1888,14 +2060,14 @@ static void parhelp( struct CMDSET *cmd, int argc, char **argv) { size_t max = 0; for( p = ptable; p->name != NULL; p++ ) { - if( 1||p->helpstr ) { + if( p->helpstr ) { size_t len = strlen(p->name); if( len > max ) max = len; } } for( p = ptable; p->name != NULL; p++ ) { - if(1|| p->helpstr ) { + if( p->helpstr ) { size_t len = strlen(p->name); if( !col ) { printf( " Parameters:\n " ); @@ -1913,7 +2085,8 @@ static void parhelp( struct CMDSET *cmd, int argc, char **argv) { col += len; } } - printf( "\n\n Type help PARAMETER for more about each parameter.\n" ); + printf( "\n\n Type help %s PARAMETER for more about each parameter.\n", + cmd->name ); return; } @@ -1968,13 +2141,15 @@ static void parhelp( struct CMDSET *cmd, int argc, char **argv) { return; } +/*********************************************************** dohelp() */ /* help: Display help guided by command table. */ -#define NCMD 16 + +#define NCMD 17 static struct CMDSET cmdset[NCMD+1]; -static struct param helppars[] = { {"command", OPT, CMDNAM, PA(cmdset), NULL }, - {"parameter", OPT, STRING, NOPA, NULL }, - {"value", OPT, STRING, NOPA, NULL }, +static struct param helppars[] = { {"command", OPT, CMDNAM, PA(cmdset), "" }, + {"parameter", OPT, STRING, NOPA, "" }, + {"value", OPT, STRING, NOPA, "" }, {NULL, 0, 0, NOPA, NULL }, }; @@ -1983,19 +2158,20 @@ static unsigned dohelp(int argc,char *argv[],int qualc,char *qualv[]); static struct CMDSET cmdset[NCMD+1] = { { "copy", docopy, 0,copyquals,copypars, "Copy a file from VMS to host file", }, - { "import", doimport, 0,NULL, importpars, "Copy a file from host to VMS", }, { "delete", dodelete, 0,delquals, delpars, "Delete a VMS file", }, { "difference",dodiff, 0,NULL, diffpars, "Compare VMS file to host file", }, { "directory", dodir, 0,dirquals,dirpars, "List directory of VMS files", }, + { "dismount", dodismount,0,NULL, dmopars, "Dismount a VMS volume", }, { "exit", NULL, 2,NULL, NULL, "Exit ODS2", }, { "extend", doextend, 0,NULL, extendpars, NULL }, { "help", dohelp, 0,NULL, helppars, "Obtain help on a command", }, - { "quit", NULL, 2,NULL, NULL, "Exit ODS-2", }, - { "show", doshow, 0,NULL, showpars, "Display state", }, - { "search", dosearch, 0,NULL, searchpars, "Search VMS file for a string", }, - { "set", doset, 0,NULL, setpars, "Set PARAMETER - set HELP for list", }, - { "dismount", dodismount,0,NULL, dmopars, "Dismount a VMS volume", }, + { "import", doimport, 0,NULL, importpars, "Copy a file from host to VMS", }, { "mount", domount, 0,mouquals, moupars, "Mount a VMS volume", }, + { "quit", NULL, 2,NULL, NULL, "Exit ODS-2", }, + { "search", dosearch, 0,NULL, searchpars, "Search VMS file for a string", }, + { "set", doset, 0,NULL, setpars, "Set PARAMETER - set HELP for list", }, + { "show", doshow, 0,NULL, showpars, "Display state", }, + { "spawn", dospawn, 0,NULL, NULL, "Open a command subprocess", }, { "test", dotest, 0,NULL, testpars, NULL }, { "type", dotype, 0,NULL, typepars, "Display a VMS file on the terminal", }, { NULL, NULL, 0,NULL, NULL, NULL } /* ** END MARKER ** */ @@ -2064,15 +2240,6 @@ static unsigned dohelp(int argc,char *argv[],int qualc,char *qualv[]) { } printf( "%s: command not found\n", argv[1] ); return 0; - - printf(" set_default type\n"); - printf(" Example:-\n $ mount e:\n"); - printf(" $ search e:[vms_common.decc*...]*.h rms$_wld\n"); - printf(" $ set default e:[sys0.sysmgr]\n"); - printf(" $ copy *.com;-1 c:\\*.*\n"); - printf(" $ directory/file/size/date [-.sys*...].%%\n"); - printf(" $ exit\n"); - return 1; } /*************************************************************** cmdexecute() */ @@ -2142,7 +2309,7 @@ static int cmdexecute( int argc, char *argv[], int qualc, char *qualv[] ) { /* cmdsplit: break a command line into its components */ /* - * New feature for Unix: '//' or '--' stops qualifier parsing. + * Feature for Unix: '//' or '--' stops qualifier parsing. * This enables us to copy to Unix directories with VMS style /qualifiers. * copy /bin // *.com /tmp/ * * is split into argv[0] -> "*.com" argv[1] -> "/tmp/ *" qualv[0]-> "/bin" @@ -2156,60 +2323,71 @@ static int cmdsplit(char *str) { char *sp = str; int i; char q = vms_qual? '/': '-'; - for (i = 0; i < MAXITEMS; i++) argv[i] = qualv[i] = ""; - while (*sp != '\0') { - while (*sp == ' ') sp++; - if (*sp != '\0') { - if (*sp == q) { - *sp++ = '\0'; - if (*sp == q) { - sp++; - q = '\0'; - continue; - } - if( qualc >= MAXITEMS ) { - printf( "%%ODS2-E-CMDERR, Too many qualifiers specified\n" ); - return 0; + + for( i = 0; i < MAXITEMS; i++ ) argv[i] = qualv[i] = ""; + + while( *sp != '\0' ) { + while( *sp == ' ' ) sp++; + if( *sp == '\0' ) + break; + + if( *sp == q ) { /* Start of qualifier */ + *sp++ = '\0'; /* Terminate previous word */ + if (*sp == q) { /* qq = end of qualifiers */ + sp++; + q = '\0'; + continue; + } + if( qualc >= MAXITEMS ) { + printf( "%%ODS2-E-CMDERR, Too many qualifiers specified\n" ); + return 0; + } + qualv[qualc++] = sp; + } else { /* New argument */ + if( argc >= MAXITEMS ) { + printf( "%%ODS2-E-CMDERR, Too many arguments specified\n" ); + return 0; + } + argv[argc++] = sp; + if( *sp == '"' ) { + ++argv[argc-1]; + for( ++sp; *sp && (*sp != '"' || sp[1] == '"'); sp++ ) { + if( *sp == '"' ) /* Interior "" => " */ + memmove( sp, sp+1, strlen(sp+1)+1 ); } - qualv[qualc++] = sp; - } else { - if( argc >= MAXITEMS ) { - printf( "%%ODS2-E-CMDERR, Too many arguments specified\n" ); - return 0; - } - argv[argc++] = sp; - if( *sp == '"' ) { - ++argv[argc-1]; - for( ++sp; *sp && (*sp != '"' || sp[1] == '"'); sp++ ) { - if( *sp == '"' ) - memmove( sp, sp+1, strlen(sp+1)+1 ); - } - if( *sp == '"' ) { - *sp++ = '\0'; - if( *sp && *sp != ' ' ) { - printf( "%%ODS2-E-CMDERR, Unterminated string\n" ); - return 0; - } - } else { + if( *sp == '"' ) { /* Ending " of string */ + *sp++ = '\0'; + if( *sp && *sp != ' ' ) { /* Something following */ printf( "%%ODS2-E-CMDERR, Unterminated string\n" ); return 0; } - continue; + } else { + printf( "%%ODS2-E-CMDERR, Unterminated string\n" ); + return 0; } - } - while (*sp != ' ' && *sp != q && *sp != '\0') sp++; - if (*sp == '\0') { - break; - } else { - if (*sp != q) *sp++ = '\0'; - } + continue; + } /* Quoted string */ } + + /* Find end of atom */ + + while( !(*sp == '\0' || *sp == ' ' || *sp == q) ) sp++; + if (*sp == '\0') + break; + if( *sp == ' ' ) + *sp++ = '\0'; } - if (argc > 0) return cmdexecute(argc,argv,qualc,qualv); + if( argc > 0 ) + return cmdexecute( argc, argv, qualc, qualv ); + return 1; } +/******************************************************************* main() */ + +/*********************************************************** getcmd() */ + #ifdef VMS static char *getcmd( char *inp, size_t max, char *prompt ) { struct dsc_descriptor prompt_d = { strlen(prompt),DSC$K_DTYPE_T, @@ -2242,6 +2420,7 @@ static char *getcmd( char *inp, size_t max, char *prompt ) { } #endif /* VMS */ +/*********************************************************** main() */ /* main: the simple mainline of this puppy... */ /* @@ -2285,10 +2464,43 @@ int main( int argc,char *argv[] ) { history_truncate_file( hfname, 200 ); stifle_history( 200 ); read_history( hfname ); - } else { - hfname = NULL; } #endif + sts = sys_initialize(); + if( !(sts & STS$M_SUCCESS) ) { + printf( "Unable to initialize library: %s\n", getmsg( sts, MSG_TEXT ) ); + exit(EXIT_FAILURE); + } + { /* Build parser keyword list from disk table entries */ + struct qual *qp, *kp = NULL; + struct disktype * dp; + size_t n = 0; + + for( dp = disktype; dp->name != NULL; dp++ ) + ; + n = (size_t) (dp - disktype); + kp = (struct qual *)calloc( n+1, sizeof( struct qual ) ); + if( kp == NULL ) { + perror( "malloc" ); + exit( EXIT_FAILURE ); + } + for( qp = mouquals; qp->name != NULL; qp++ ) + if( !strcmp( qp->name, DT_NAME ) ) + break; + qp->arg = kp; + + for( dp = disktype; dp->name != NULL; dp++ ) { + kp->name = dp->name; + kp->set = (int)((dp-disktype) << MOU_V_DEVTYPE); + kp->clear = MOU_DEVTYPE; + kp->qtype = NOVAL; + if( dp != disktype ) + kp->helpstr = ""; + kp++; + } + if( (((unsigned)(dp-disktype)) << MOU_V_DEVTYPE) & ~MOU_DEVTYPE ) + abort(); /* MOU_DEVTYPE isn't wide enough for the max index */ + } if( argc > 1 ) { int i, l = 0; @@ -2327,6 +2539,10 @@ int main( int argc,char *argv[] ) { *p = '\0'; i += strlen( ptr ) +1; } +#ifdef USE_READLINE + if( ptr != NULL && *ptr ) + add_history( ptr ); +#endif } if( ptr == NULL ) { if (atfile != NULL) { @@ -2404,18 +2620,30 @@ int main( int argc,char *argv[] ) { } } /* while 1 */ + free( command_line ); + if( rl != NULL ) { free( rl ); } #ifdef USE_READLINE if( hfname != NULL ) { write_history( hfname ); + clear_history(); } + wordfree( &wex ); /* hfname points into wex and should not be free()d */ #endif - if (atfile != NULL) fclose(atfile); -#ifdef VMS - return 1; -#else - return 0; -#endif + if (atfile != NULL) + fclose(atfile); + + { + struct qual *qp; + + for( qp = mouquals; qp->name != NULL; qp++ ) + if( !strcmp( qp->name, DT_NAME ) ) { + free( qp-> arg ); + qp->arg = NULL; + break; + } + } + exit( EXIT_SUCCESS ); } diff --git a/extracters/ods2/ods2.h b/extracters/ods2/ods2.h index 1bdbbf7..7b7bcb2 100644 --- a/extracters/ods2/ods2.h +++ b/extracters/ods2/ods2.h @@ -5,10 +5,11 @@ #ifndef _ODS2_H #define _ODS2_H -#define MOU_WRITE 1 -#define MOU_VIRTUAL 2 -#define MOU_LOG 4 +#define MOU_WRITE 1 +#define MOU_VIRTUAL 2 +#define MOU_LOG 4 -#define SUB_DELETE 1 +#define MOU_V_DEVTYPE 8 +#define MOU_DEVTYPE (0xffff << MOU_V_DEVTYPE) #endif /* #ifndef _ODS2_H */ diff --git a/extracters/ods2/phynt.c b/extracters/ods2/phynt.c index bbdd9f7..1f2543a 100644 --- a/extracters/ods2/phynt.c +++ b/extracters/ods2/phynt.c @@ -40,6 +40,7 @@ #include "stsdef.h" #include "compat.h" #include "phyvirt.h" +#include "sysmsg.h" #ifdef USE_ASPI #include "scsidefs.h" @@ -558,9 +559,11 @@ static void getsysversion( void ) { OSVERSIONINFO sysver; memset( &sysver, 0, sizeof( sysver ) ); +#pragma warning (disable : 4996) sysver.dwOSVersionInfoSize = sizeof( sysver ); GetVersionEx( &sysver /* lpVersionInfo */ ); +#pragma warning (default : 4996) is_NT = ( sysver.dwPlatformId == VER_PLATFORM_WIN32_NT ) ? 1 : 0 ; } @@ -580,21 +583,21 @@ static unsigned phy_getsect( struct DEV *dev, unsigned sector ) { sector, dev->bytespersector, dev->IoBuffer ); } else #endif - { + { if ( dev->access & MOU_VIRTUAL || is_NT ) { - DWORD DistanceLow, DistanceHigh, BytesRead; - DistanceLow = ( sector * dev->blockspersector ) << 9; - DistanceHigh = ( sector * dev->blockspersector ) >> 23; - SetLastError( 0 ); - SetFilePointer( dev->API.Win32.handle,/* hFile */ - DistanceLow, /* lDistanceToMove */ - &DistanceHigh, /* lpDistanceToMoveHigh */ - FILE_BEGIN /* dwMoveMethod */ - ); - if ( GetLastError() != NO_ERROR ) { - TCHAR *msg = w32_errstr(0); - printf( "PHYIO_READ: SetFilePointer() failed: %s\n", - msg ); + DWORD BytesRead; + __int64 distance; + LARGE_INTEGER li; + distance = (((__int64)sector) * dev->blockspersector) << 9; + li.QuadPart = distance; + if( SetFilePointer( dev->API.Win32.handle,/* hFile */ + li.LowPart, /* lDistanceToMove */ + &li.HighPart, /* lpDistanceToMoveHigh */ + FILE_BEGIN /* dwMoveMethod */ + ) == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR ) { + TCHAR *msg = w32_errstr(NO_ERROR); + printf( "PHYIO_READ: SetFilePointer() failed at sector %lu: %s\n", + sector, msg ); LocalFree(msg); sts = SS$_PARITY; } @@ -607,9 +610,14 @@ static unsigned phy_getsect( struct DEV *dev, unsigned sector ) { &BytesRead, /* lpNumberOfBytesRead */ NULL /* lpOverlapped */ ) || BytesRead != dev->bytespersector ) { - TCHAR *msg = w32_errstr(0); - printf( "PHYIO_READ: ReadFile() failed: %s\n", - msg ); + TCHAR *msg; + + if( BytesRead == 0 ) + return SS$_ENDOFFILE; + + msg = w32_errstr(NO_ERROR); + printf( "PHYIO_READ: ReadFile() failed at sector %lu: %s\n", + sector, msg ); LocalFree(msg); sts = SS$_PARITY; } @@ -641,7 +649,7 @@ static unsigned phy_getsect( struct DEV *dev, unsigned sector ) { NULL /* lpOverlapped */ ) && !( reg.reg_Flags & 0x0001 ); if ( !result ) { - TCHAR *msg = w32_errstr(0); + TCHAR *msg = w32_errstr(NO_ERROR); printf( "PHYIO_READ: Read sector %d failed: %s\n", sector, msg ); LocalFree(msg); @@ -672,34 +680,33 @@ static unsigned phy_putsect( struct DEV *dev, unsigned sector ) { #endif { if ( dev->access & MOU_VIRTUAL || is_NT ) { - DWORD DistanceLow, DistanceHigh, BytesWritten; - DistanceLow = ( sector * dev->blockspersector ) << 9; - DistanceHigh = ( sector * dev->blockspersector ) >> 23; - SetLastError( 0 ); - SetFilePointer( dev->API.Win32.handle, /* hFile */ - DistanceLow, /* lDistanceToMove */ - &DistanceHigh, /* lpDistanceToMoveHigh */ - FILE_BEGIN /* dwMoveMethod */ - ); - if ( GetLastError() != NO_ERROR ) { - TCHAR *msg = w32_errstr(0); - printf( "PHYIO_WRITE: SetFilePointer() failed: %s\n", - msg ); + DWORD BytesWritten; + __int64 distance; + LARGE_INTEGER li; + distance = (((__int64)sector) * dev->blockspersector) << 9; + li.QuadPart = distance; + if( SetFilePointer( dev->API.Win32.handle,/* hFile */ + li.LowPart, /* lDistanceToMove */ + &li.HighPart, /* lpDistanceToMoveHigh */ + FILE_BEGIN /* dwMoveMethod */ + ) == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR ) { + TCHAR *msg = w32_errstr(NO_ERROR); + printf( "PHYIO_WRITE: SetFilePointer() failed at sector %lu: %s\n", + sector, msg ); LocalFree(msg); sts = SS$_PARITY; } if ( sts & STS$M_SUCCESS ) { - /* hFile */ - if ( !WriteFile( dev->API.Win32.handle, - dev->IoBuffer, /* lpBuffer */ - /* nNumberOfBytesToWrite */ + if ( !WriteFile( dev->API.Win32.handle, /* hFile */ + dev->IoBuffer, /* lpBuffer */ + /* nNumberOfBytesToWrite */ dev->bytespersector, - &BytesWritten, /* lpNumberOfBytesWritten */ - NULL /* lpOverlapped */ + &BytesWritten, /* lpNumberOfBytesWritten */ + NULL /* lpOverlapped */ ) || BytesWritten != dev->bytespersector ) { - TCHAR *msg = w32_errstr(0); - printf( "PHYIO_WRITE: WriteFile() failed: %s\n", - msg ); + TCHAR *msg = w32_errstr(NO_ERROR); + printf( "PHYIO_WRITE: WriteFile() failed at sector %lu: %s\n", + sector, msg ); LocalFree(msg); sts = SS$_PARITY; } @@ -730,7 +737,7 @@ static unsigned phy_putsect( struct DEV *dev, unsigned sector ) { NULL /* lpOverlapped */ ) && !( reg.reg_Flags & 0x0001 ); if ( !result ) { - TCHAR *msg = w32_errstr(0); + TCHAR *msg = w32_errstr(NO_ERROR); printf( "PHYIO_WRITE: Write sector %d failed: %s\n", sector, msg ); LocalFree(msg); @@ -751,7 +758,7 @@ void phyio_show( showtype_t type ) { init_count, read_count, write_count ); return; case SHOW_FILE64: - printf( "\nLarge ODS-2 image files (>2GB) are supported.\n" ); + printf( "Large ODS-2 image files (>2GB) are %ssupported.\n", "" ); return; case SHOW_DEVICES: { TCHAR *namep = NULL, *dname = NULL; @@ -793,8 +800,8 @@ void phyio_show( showtype_t type ) { free(namep); } } - } return; + } default: abort(); } @@ -934,15 +941,15 @@ unsigned phyio_init( struct DEV *dev ) { ); } if ( dev->API.Win32.handle == INVALID_HANDLE_VALUE ) { - TCHAR *msg = w32_errstr(0); + TCHAR *msg = w32_errstr(NO_ERROR); printf( "PHYIO_INIT: Open( \"%s\" ) failed: %s\n", dev->devnam, msg ); LocalFree(msg); return SS$_NOSUCHDEV; } if ( !LockVolume( dev ) ) { - TCHAR *msg = w32_errstr(0); - printf( "PHYIO_INIT: LockVolume( \"%s\" ) failed: %a\n", + TCHAR *msg = w32_errstr(NO_ERROR); + printf( "PHYIO_INIT: LockVolume( \"%s\" ) failed: %s\n", dev->devnam, msg ); LocalFree(msg); phyio_done( dev ); @@ -950,7 +957,7 @@ unsigned phyio_init( struct DEV *dev ) { } } if ( !GetDiskGeometry( dev, &dev->sectors, &dev->bytespersector ) ) { - TCHAR *msg = w32_errstr(0); + TCHAR *msg = w32_errstr(NO_ERROR); printf( "PHYIO_INIT: GetDiskGeometry( \"%s\" ) failed: %s\n", dev->devnam, msg ); LocalFree(msg); @@ -989,6 +996,10 @@ unsigned phyio_init( struct DEV *dev ) { ); } if ( dev->API.Win32.handle == INVALID_HANDLE_VALUE ) { + TCHAR *msg = w32_errstr(NO_ERROR); + printf( "PHYIO_INIT: CreateFile() failed for %s: %s\n", + virtual, msg ); + LocalFree(msg); return SS$_NOSUCHFILE; } SetLastError( 0 ); @@ -1078,8 +1089,8 @@ unsigned phyio_read( struct DEV *dev, unsigned block, unsigned length, offset = 0; } if ( !( sts & STS$M_SUCCESS ) ) { - printf( "PHYIO_READ Error %d Block %d Length %d", - sts, block, length ); + printf( "PHYIO_READ Error %s Block %d Length %d", + getmsg(sts, MSG_TEXT), block, length ); #ifdef USE_ASPI printf( " (ASPI: %x %x %x)", ASPI_status, ASPI_HaStat, ASPI_TargStat ); diff --git a/extracters/ods2/phyunix.c b/extracters/ods2/phyunix.c index d7ed90c..51a911f 100644 --- a/extracters/ods2/phyunix.c +++ b/extracters/ods2/phyunix.c @@ -111,8 +111,10 @@ static void showdevs( void ) { free( fs ); continue; } - if( !S_ISBLK( stb.st_mode ) ) + if( !S_ISBLK( stb.st_mode ) ) { + free( fs ); continue; + } memmove( fs, fs + sizeof( DEV_PREFIX ) -1, len +1 ); unit = ~0; @@ -126,14 +128,17 @@ static void showdevs( void ) { if( unit < (*list)[i].low ) (*list)[i].low = unit; } + free( fs ); break; } } if( i >= n ) { nl = (struct devdat (*)[1]) realloc( list, (n+1) * sizeof( struct devdat ) ); - if( nl == NULL ) + if( nl == NULL ) { + free( fs ); break; + } list = nl; (*list)[n].name = fs; (*list)[n].low = unit; @@ -206,7 +211,8 @@ void phyio_show( showtype_t type ) { init_count, read_count, write_count ); return; case SHOW_FILE64: - printf( "\nLarge ODS-2 image files (>2GB) are supported.\n" ); + printf( "Large ODS-2 image files (>2GB) are %ssupported.\n", + (sizeof( off_t ) < 8)? "NOT ": "" ); return; case SHOW_DEVICES: printf( " Physical devices\n" ); @@ -338,6 +344,9 @@ unsigned phyio_read( struct DEV *dev, unsigned block, unsigned length, return SS$_PARITY; } if ( ( res = read( dev->handle, buffer, length ) ) != length ) { + if( res == 0 ) { + return SS$_ENDOFFILE; + } perror( "read " ); printf("read failed %" PRIuMAX "u\n", (uintmax_t)res); return SS$_PARITY; diff --git a/extracters/ods2/phyvirt.c b/extracters/ods2/phyvirt.c index 0d0274c..ccc1f8a 100644 --- a/extracters/ods2/phyvirt.c +++ b/extracters/ods2/phyvirt.c @@ -52,7 +52,7 @@ void virt_show( const char *devnam ) { unsigned devlen, devsiz; struct VDEV *vp; - if ( devnam == NULL ) { + if( devnam == NULL ) { size_t maxd = sizeof( "Device" ) -1, maxp = sizeof( "File" ) -1, n; @@ -61,7 +61,7 @@ void virt_show( const char *devnam ) { printf( " No virtual devices are assigned\n" ); return; } - for ( vp = virt_device_list; vp != NULL; vp = vp->next ) { + for( vp = virt_device_list; vp != NULL; vp = vp->next ) { n = strlen( vp->devnam ); if( n > maxd ) maxd = n; @@ -79,23 +79,23 @@ void virt_show( const char *devnam ) { for( n = 0; n < maxp; n++ ) putchar( '-' ); putchar( '\n' ); - for ( vp = virt_device_list; vp != NULL; vp = vp->next ) { + for( vp = virt_device_list; vp != NULL; vp = vp->next ) { n = strlen( vp->path ); printf( " %-*s %.*s\n", (int)maxd, vp->devnam, (int)maxp, (n > maxp)? vp->path+(n-maxp): vp->path ); } } else { devlen = strlen( devnam ); - for ( devsiz = 0; devsiz < devlen; devsiz++ ) { - if ( devnam[devsiz] == ':' ) { + for( devsiz = 0; devsiz < devlen; devsiz++ ) { + if( devnam[devsiz] == ':' ) { break; } } - if ( devsiz == 0 ) { + if( devsiz == 0 ) { return; } - for ( vp = virt_device_list; vp != NULL; vp = vp->next ) { - if ( virt_compare( devsiz, (char *) devnam, vp->devnam ) == 0 ) { + for( vp = virt_device_list; vp != NULL; vp = vp->next ) { + if( virt_compare( devsiz, (char *) devnam, vp->devnam ) == 0 ) { printf( " %s => %s\n", vp->devnam, vp->path ); return; } @@ -111,13 +111,13 @@ static int virt_compare( unsigned keylen, const char *keynam, register int cmp; cmp = 0; - while ( keylen-- > 0 ) { + while( keylen-- > 0 ) { cmp = toupper( *keynam++ ) - toupper( *devnam++ ); - if ( cmp != 0 ) { + if( cmp != 0 ) { break; } } - if ( cmp == 0 && *devnam != '\0' && *devnam != ':' ) { + if( cmp == 0 && *devnam != '\0' && *devnam != ':' ) { cmp = -1; } return cmp; @@ -133,16 +133,16 @@ char *virt_lookup( const char *devnam ) { struct VDEV *vp; devlen = strlen( devnam ); - for ( devsiz = 0; devsiz < devlen; devsiz++ ) { - if ( devnam[devsiz] == ':' ) { + for( devsiz = 0; devsiz < devlen; devsiz++ ) { + if( devnam[devsiz] == ':' ) { break; } } - if ( devsiz == 0 ) { + if( devsiz == 0 ) { return NULL; } - for ( vp = virt_device_list; vp != NULL; vp = vp->next ) { - if ( virt_compare( devsiz, (char *) devnam, vp->devnam ) == 0 ) { + for( vp = virt_device_list; vp != NULL; vp = vp->next ) { + if( virt_compare( devsiz, (char *) devnam, vp->devnam ) == 0 ) { return vp->path; } } @@ -176,21 +176,22 @@ unsigned virt_device( char *devnam, char **vname ) { } path = p; - for ( vpp = &virt_device_list; *vpp != NULL; vpp = &(*vpp)->next ) { + for( vpp = &virt_device_list; *vpp != NULL; vpp = &(*vpp)->next ) { if( strcmp( (*vpp)->path, path ) == 0 ) { printf( "%%ODS2-E-MAPPED, %s is in use on virtual drive %s\n", path, (*vpp)->devnam ); + free( path ); return SS$_DEVMOUNT; } } } devlen = strlen( devnam ); - for ( devsiz = 0; devsiz < devlen; devsiz++ ) { - if ( devnam[devsiz] == ':' ) { + for( devsiz = 0; devsiz < devlen; devsiz++ ) { + if( devnam[devsiz] == ':' ) { break; } } - if ( devsiz == 0 ) { + if( devsiz == 0 ) { free( path ); return SS$_BADPARAM; } @@ -216,21 +217,21 @@ static struct VDEV *virt_insert( const char *devnam, unsigned devsiz, struct VDEV *vp, **vpp, **here; here = NULL; - for ( vpp = &virt_device_list; *vpp != NULL; vpp = &(*vpp)->next ) { - if ( virt_compare( devsiz, (char *) devnam, (*vpp)->devnam ) < 0 ) { + for( vpp = &virt_device_list; *vpp != NULL; vpp = &(*vpp)->next ) { + if( virt_compare( devsiz, (char *) devnam, (*vpp)->devnam ) < 0 ) { here = vpp; } } - if ( here == NULL ) { + if( here == NULL ) { here = vpp; } vp = (struct VDEV *) malloc( sizeof( struct VDEV ) ); - if ( vp == NULL ) { + if( vp == NULL ) { return NULL; } vp->devnam = (char *) malloc( devsiz + 1 ); vp->path = (char *) malloc( (pathsiz = strlen( path )) + 1 ); - if ( vp->devnam == NULL || vp->path == NULL ) { + if( vp->devnam == NULL || vp->path == NULL ) { free( vp->devnam ); free( vp->path ); free( vp ); @@ -251,8 +252,8 @@ static void virt_remove( const char *devnam, unsigned devsiz ) { struct VDEV *vp, **vpp; - for ( vpp = &virt_device_list; *vpp != NULL; vpp = &(*vpp)->next ) { - if ( virt_compare( devsiz, (char *) devnam, (*vpp)->devnam ) == 0 ) { + for( vpp = &virt_device_list; *vpp != NULL; vpp = &(*vpp)->next ) { + if( virt_compare( devsiz, (char *) devnam, (*vpp)->devnam ) == 0 ) { vp = *vpp; *vpp = (*vpp)->next; free( vp->devnam ); diff --git a/extracters/ods2/phyvms.c b/extracters/ods2/phyvms.c index 88ac8aa..2d7d963 100644 --- a/extracters/ods2/phyvms.c +++ b/extracters/ods2/phyvms.c @@ -39,6 +39,7 @@ #include #include /* struct FAB */ #include +#include #include #include #include @@ -67,15 +68,23 @@ unsigned sys$dassgn(); #include #endif +#ifndef SS$_NOMOREDEV +#define SS$_NOMOREDEV 2648 +#endif + +#ifndef EFN$C_ENF +#define EFN$C_ENF 0 /* 128 in recent VMS */ +#endif + #include "ods2.h" #include "phyio.h" #include "virtual.h" struct ITMLST { - unsigned short length; - unsigned short itmcod; - void *buffer; - unsigned long *retlen; + unsigned short length; + unsigned short itmcod; + void *buffer; + unsigned short *retlen; }; #define chk( sts ) { register chksts; \ @@ -83,10 +92,86 @@ struct ITMLST { lib$stop( chksts ); \ } +#define MSGID(sts) ((sts) & (STS$M_COND_ID|STS$M_SEVERITY)) + static unsigned init_count = 0; static unsigned read_count = 0; static unsigned write_count = 0; +/*************************************************************** showdevs() */ +static void showdevs( void ) { + unsigned long status; + size_t max = 0; + int pass; + + max = 0 + for( pass = 0; pass < 2; pass++ ) { + unsigned long ctx[2] = { 0, 0 }; + size_t col = 0; + unsigned short retlen, iosb[4]; + char devnam[64+1], + dspnam[64+1]; + struct dsc$descriptor_s retdsc = { sizeof( devnam ) -1, + DSC$K_DTYPE_T, + DSC$K_CLASS_S, devnam }; + $DESCRIPTOR( searchdsc, "*" ); + unsigned long devclass = DC$_DISK; + struct ITMLST scanlist[] = { + { sizeof( devclass ), DC$_DISK, &devclass, NULL }, + { 0, 0, NULL, NULL } + }; + struct ITMLST dvilist[] = { + { sizeof( dspnam ) -1, DVI$_DISPLAY_DEVNAM, dspnam, &retlen }, + { 0, 0, NULL, NULL } + }; + + while( 1 ) { + char *name; + size_t len; + + status = sys$device_scan( &retdsc, &retlen, + &searchdsc, scanlist, &ctx ); + if( MSGID(status) != SS$_NORMAL ) + break; + name = devnam; + name[retlen] = '\0'; + len = retlen; + status = sys$getdviw( EFN$C_ENF, 0, &retdsc, dvilist, iosb, + NULL, 0, NULL ); + if( MSGID(status) == SS$_NORMAL ) { + name = dspnam; + dspnam[retlen] = '\0'; + len = retlen; + } + if( pass == 0 ) { + if( len > max ) + max = len; + continue; + } + if( col + max > 75 ) { + putchar( '\n' ); + col = 0; + } + col += 1+ max; + + printf( " %-*s", (int)max, name ); + } + } + switch( MSGID(status) ) { + case SS$_NOMOREDEV: + break; + case SS$_NOSUCHDEV: + printf( "No devices found\n" ); + case SS$_NORMAL: + break; + default: + printf( "%%ODS2-W-ERRDEV, Error scanning devices: %s\n", + getmsg( status, MSG_TEXT ) ); + break; + } + return; +} + /*************************************************************** phyio_show() */ void phyio_show( showtype_t type ) { @@ -96,13 +181,12 @@ void phyio_show( showtype_t type ) { init_count, read_count, write_count ); return; case SHOW_FILE64: - printf( "\nLarge ODS-2 image files (>2GB) are supported.\n" ); + printf( "Large ODS-2 image files (>2GB) are %ssupported.\n", + (sizeof( off_t ) < 8)? "NOT ": "" ); return; case SHOW_DEVICES: -#if 0 /* VMS doesn't make listing devices easy */ printf( " Physical devices\n" ); showdevs(); -#endif return; default: abort(); @@ -178,6 +262,7 @@ unsigned phyio_init( struct DEV *dev ) { unsigned long devclass, cylinders, tracks, sectors; char devname[65]; unsigned long devchar; + unsigned short iosb[4]; struct ITMLST dvi_itmlst[7] = { { sizeof( devclass ), DVI$_DEVCLASS, &devclass, NULL }, { sizeof( devname ), DVI$_ALLDEVNAM, &devname, NULL }, @@ -191,7 +276,7 @@ unsigned phyio_init( struct DEV *dev ) { /* Get some device information: device name, class, and mount status */ devdsc.dsc$w_length = strlen( dev->devnam ); devdsc.dsc$a_pointer = dev->devnam; - sts = sys$getdviw( 0, 0, &devdsc, &dvi_itmlst, 0, 0, 0, 0 ); + sts = sys$getdviw( EFN$C_ENF, 0, &devdsc, &dvi_itmlst, iosb, 0, 0, 0 ); if ( !( sts & STS$M_SUCCESS ) ) { return sts; } @@ -295,6 +380,9 @@ unsigned phyio_read( struct DEV *dev, unsigned block, unsigned length, return SS$_PARITY; } if ( ( res = read( dev->handle, buffer, length ) ) != length ) { + if( res == 0 ) { + return SS$_ENDOFFILE; + } perror( "read " ); printf( "read failed %d\n", res ); return SS$_PARITY; diff --git a/extracters/ods2/rms.c b/extracters/ods2/rms.c index cab1b48..a9f494f 100644 --- a/extracters/ods2/rms.c +++ b/extracters/ods2/rms.c @@ -37,6 +37,7 @@ #include "ssdef.h" #include "stsdef.h" #include "compat.h" +#include "sysmsg.h" #ifndef TRUE #define TRUE ( 0 == 0 ) @@ -455,6 +456,7 @@ unsigned do_search(struct FAB *fab,struct WCCFILE *wccfile) wcc->wcd_reslen - 6,".DIR;1",6); } else { sts = RMS$_NMF; + cleanup_wcf(&wccfile); break; /* giveup */ } } @@ -753,7 +755,13 @@ unsigned do_parse(struct FAB *fab,struct WCCFILE **wccret) } if (wccret != NULL) *wccret = wccfile; if (nam != NULL) { - nam->nam$l_wcc = wccfile; + if( (nam->nam$b_nop & NAM$M_SYNCHK) && + !fab->fab$b_dns && !nam->nam$l_rlf ) { + cleanup_wcf(&wccfile); + if( wccret ) *wccret = NULL; + } else { + nam->nam$l_wcc = wccfile; + } } return SS$_NORMAL; } @@ -795,14 +803,21 @@ unsigned sys_setddir(struct dsc_descriptor *newdir,unsigned short *oldlen, sts = sys_parse(&fab); if (sts & STS$M_SUCCESS) { if (nam.nam$b_name + nam.nam$b_type + nam.nam$b_ver > 2) { - return RMS$_DIR; + sts = RMS$_DIR; + } else { + if (nam.nam$l_fnb & NAM$M_WILDCARD) + sts = RMS$_WLD; + else { + default_name = default_buffer; + default_size[0] = nam.nam$b_dev; + default_size[1] = nam.nam$b_dir; + memcpy(default_name + nam.nam$b_dev + nam.nam$b_dir,".;",3); + } } - if (nam.nam$l_fnb & NAM$M_WILDCARD) return RMS$_WLD; - default_name = default_buffer; - default_size[0] = nam.nam$b_dev; - default_size[1] = nam.nam$b_dir; - memcpy(default_name + nam.nam$b_dev + nam.nam$b_dir,".;",3); } + fab.fab$b_dns = 0; + nam.nam$l_rlf = 0; + sys$parse( &fab ); } return sts; } @@ -1473,3 +1488,18 @@ unsigned sys_extend(struct FAB *fab) fab->fab$l_alq - ifi_table[ifi_no]->wcf_fcb->hiblock,0); return sts; } + +/*************************************************************** sys_initialize() */ +static void sys_rundown( void ) { + access_rundown(); + + sysmsg_rundown(); +} + +/*************************************************************** sys_initialize() */ +unsigned sys_initialize( void ) { + if( atexit( sys_rundown ) != 0 ) + return SS$_INSFMEM; + + return SS$_NORMAL; +} diff --git a/extracters/ods2/rms.h b/extracters/ods2/rms.h index b009b86..5775a8e 100644 --- a/extracters/ods2/rms.h +++ b/extracters/ods2/rms.h @@ -15,6 +15,8 @@ #include "vmstime.h" +#define RMS$_FACILITY 1 + #define RMS$_RTB 98728 #define RMS$_EOF 98938 #define RMS$_FNF 98962 @@ -170,10 +172,11 @@ struct NAM { void *nam$l_wcc; int nam$b_nop; int nam$l_fnb; + struct NAM *nam$l_rlf; }; #ifdef RMS$INITIALIZE -struct NAM cc$rms_nam = {0,0,0,0,0,0,0,0,0,0,0,NULL,0,NULL,0,NULL,0,NULL,0,NULL,0,NULL,0,NULL,0,0,0}; +struct NAM cc$rms_nam = {0,0,0,0,0,0,0,0,0,0,0,NULL,0,NULL,0,NULL,0,NULL,0,NULL,0,NULL,0,NULL,0,0,0,NULL}; #else extern struct NAM cc$rms_nam; #endif @@ -317,4 +320,6 @@ unsigned sys_extend(struct FAB *fab); unsigned sys_setddir(struct dsc_descriptor *newdir,unsigned short *oldlen, struct dsc_descriptor *olddir); +unsigned sys_initialize(void); + #endif /* #ifndef _RMS_H */ diff --git a/extracters/ods2/ssdef.h b/extracters/ods2/ssdef.h index c74839e..602f7f2 100644 --- a/extracters/ods2/ssdef.h +++ b/extracters/ods2/ssdef.h @@ -13,6 +13,8 @@ #ifndef _SSDEF_H #define _SSDEF_H +#define SYSTEM$_FACILITY 0 + #define SS$_NORMAL 1 #define SS$_WASCLR 1 #define SS$_WASSET 9 @@ -45,6 +47,7 @@ #define SS$_NOSUCHFILE 2320 #define SS$_NOMOREFILES 2352 #define SS$_ITEMNOTFOUND 2640 +#define SS$_NOMOREDEV 2648 #define SS$_NOSUCHVOL 3882 #define SS$_NOTINSTALL 8212 #define SS$_DEVNOTDISM 8628 diff --git a/extracters/ods2/stsdef.h b/extracters/ods2/stsdef.h index 931cf00..247534c 100644 --- a/extracters/ods2/stsdef.h +++ b/extracters/ods2/stsdef.h @@ -5,6 +5,52 @@ #ifndef _STSDEF_H #define _STSDEF_H -#define STS$M_SUCCESS 1 +#define STS$V_SEVERITY 0 +#define STS$M_SEVERITY 0x00000007 +#define STS$S_SEVERITY 3 +#define STS$V_COND_ID 3 +#define STS$M_COND_ID 0x0FFFFFF8 +#define STS$S_COND_ID 25 +#define STS$V_CONTROL 28 +#define STS$M_CONTROL 0xF0000000 +#define STS$S_CONTROL 4 +#define STS$V_SUCCESS 0 +#define STS$M_SUCCESS 0x01 +#define STS$S_SUCCESS 1 +#define STS$V_MSG_NO 3 +#define STS$M_MSG_NO 0x0000FFF8 +#define STS$S_MSG_NO 13 +#define STS$V_CODE 3 +#define STS$M_CODE 0x00007FF8 +#define STS$S_CODE 12 +#define STS$V_FAC_SP 15 +#define STS$M_FAC_SP 0x00008000 +#define STS$S_FAC_SP 1 +#define STS$V_CUST_DEF 27 +#define STS$M_CUST_DEF 0x08000000 +#define STS$S_CUST_DEF 1 +#define STS$V_INHIB_MSG 28 +#define STS$M_INHIB_MSG 0x10000000 +#define STS$S_INHIB_MSG 1 +#define STS$V_FAC_NO 16 +#define STS$M_FAC_NO 0x0FFF0000 +#define STS$S_FAC_NO 12 + +#define STS$K_WARNING 0 +#define STS$K_SUCCESS 1 +#define STS$K_ERROR 2 +#define STS$K_INFO 3 +#define STS$K_SEVERE 4 + +#define $VMS_STATUS_CODE(code) ( ( (code) & STS$M_CODE ) >> STS$V_CODE ) +#define $VMS_STATUS_COND_ID(code) ( ( (code) & STS$M_COND_ID ) >> STS$V_COND_ID ) +#define $VMS_STATUS_CONTROL(code) ( ( (code) & STS$M_CONTROL ) >> STS$V_CONTROL ) +#define $VMS_STATUS_CUST_DEF(code) ( ( (code) & STS$M_CUST_DEF ) >> STS$V_CUST_DEF ) +#define $VMS_STATUS_FAC_NO(code) ( ( (code) & STS$M_FAC_NO ) >> STS$V_FAC_NO ) +#define $VMS_STATUS_FAC_SP(code) ( ( (code) & STS$M_FAC_SP ) >> STS$V_FAC_SP ) +#define $VMS_STATUS_INHIB_MSG(code) ( ( (code) & STS$M_INHIB_MSG ) >> STS$V_INHIB_MSG ) +#define $VMS_STATUS_MSG_NO(code) ( ( (code) & STS$M_MSG_NO ) >> STS$V_MSG_NO ) +#define $VMS_STATUS_SEVERITY(code) ( ( (code) & STS$M_SEVERITY ) >> STS$V_SEVERITY ) +#define $VMS_STATUS_SUCCESS(code) ( ( (code) & STS$M_SUCCESS ) >> STS$V_SUCCESS ) #endif /* #ifndef _STSDEF_H */ diff --git a/extracters/ods2/sysmsg.c b/extracters/ods2/sysmsg.c index 1731299..a4ad9f6 100644 --- a/extracters/ods2/sysmsg.c +++ b/extracters/ods2/sysmsg.c @@ -1,7 +1,18 @@ /* Timothe Litt litt _at_ acm _ddot_ org */ +/* + This is part of ODS2 written by Paul Nankervis, + email address: Paulnank@au1.ibm.com + + ODS2 is distributed freely for all members of the + VMS community to use. However all derived works + must maintain comments in their source to acknowledge + the contibution of the original author. +*/ /* Message code translations for non-VMS systems */ +#include +#include #include #include #include @@ -16,83 +27,226 @@ #include "compat.h" #include "sysmsg.h" +#define MSG(code,text) { $VMS_STATUS_COND_ID(code), #code, text }, + +static +const struct VMSFAC { + unsigned int code; + const char *const text; +} fac2text[] = { + { SYSTEM$_FACILITY, "SYSTEM" }, + { RMS$_FACILITY, "RMS" }, + { 0, NULL }, + { 0, "NONAME" } +}; + +static const char sev2text[(STS$M_SEVERITY>>STS$V_SEVERITY)+1] = + { 'W', 'S', 'E', 'I', 'F', '?', '?', '?', }; + +/* Unknown facility or message code */ + +#ifndef SS$_NOMSG +#define SS$_NOMSG 0xFFFFFFFF +#endif + +static const char nofmt[] = "Message number %08X"; +static char notext[sizeof(nofmt)+8]; + static const struct VMSMSG { - unsigned int code; - const char *const text; -} *mp, vms2text[] = { -{RMS$_BUG, "%RMS-F-BUG, fatal RMS condition detected, process deleted"}, -{RMS$_DIR, "%RMS-F-DIR, error in directory name"}, -{RMS$_DNF, "%RMS-E-DNF, directory not found"}, -{RMS$_EOF, "%RMS-E-EOF, end of file detected"}, -{RMS$_ESS, "%RMS-F-ESS, expanded string area too small"}, -{RMS$_FNF, "%RMS-E-FNF, file not found"}, -{RMS$_FNM, "%RMS-F-FNM, error in file name"}, -{RMS$_IFI, "%RMS-F-IFI, invalid internal file identifier (IFI) value"}, -{RMS$_NAM, "%RMS-F-NAM, invalid NAM block or NAM block not accessible"}, -{RMS$_NMF, "%RMS-E-NMF, no more files found"}, -{RMS$_RSS, "%RMS-F-RSS, invalid resultant string size"}, -{RMS$_RSZ, "%RMS-F-RSZ, invalid record size"}, -{RMS$_RTB, "%RMS-W-RTB, !UL byte record too large for user's buffer"}, -{RMS$_WCC, "%RMS-E-WCC, invalid wild card context (WCC) value"}, -{RMS$_WLD, "%RMS-F-WLD, invalid wildcard operation"}, -{SS$_ABORT, "%SYSTEM-F-ABORT, abort"}, -{SS$_BADFILENAME, "%SYSTEM-W-BADFILENAME, bad file name syntax"}, -{SS$_BADIRECTORY, "%SYSTEM-W-BADIRECTORY, bad directory file format"}, -{SS$_BADPARAM, "%SYSTEM-F-BADPARAM, bad parameter value"}, -{SS$_BUGCHECK, "%SYSTEM-F-BUGCHECK, internal consistency failure"}, -{SS$_DATACHECK, "%SYSTEM-F-DATACHECK, write check error"}, -{SS$_DEVICEFULL, "%SYSTEM-W-DEVICEFULL, device full - allocation failure"}, -{SS$_DEVMOUNT, "%SYSTEM-F-DEVMOUNT, device is already mounted"}, -{SS$_DEVNOTALLOC, "%SYSTEM-W-DEVNOTALLOC, device not allocated"}, -{SS$_DEVNOTDISM, "%SYSTEM-F-DEVNOTDISM, device not dismounted"}, -{SS$_DEVNOTMOUNT, "%SYSTEM-F-DEVNOTMOUNT, device is not mounted"}, -{SS$_DUPFILENAME, "%SYSTEM-W-DUPFILENAME, duplicate file name"}, -{SS$_DUPLICATE, "%SYSTEM-F-DUPLNAM, duplicate name"}, -{SS$_ENDOFFILE, "%SYSTEM-W-ENDOFFILE, end of file"}, -{SS$_FILELOCKED, "%SYSTEM-W-FILELOCKED, file is deaccess locked"}, -{SS$_FILESEQCHK, "%SYSTEM-W-FILESEQCHK, file identification sequence number check"}, -{SS$_ILLEFC, "%SYSTEM-F-ILLEFC, illegal event flag cluster"}, -{SS$_INSFMEM, "%SYSTEM-F-INSFMEM, insufficient dynamic memory"}, -{SS$_ITEMNOTFOUND, "%SYSTEM-W-ITEMNOTFOUND, requested item cannot be returned"}, -{SS$_IVCHAN, "%SYSTEM-F-IVCHAN, invalid I/O channel"}, -{SS$_IVDEVNAM, "%SYSTEM-F-IVDEVNAM, invalid device name"}, -{SS$_NOIOCHAN, "%SYSTEM-F-NOIOCHAN, no I/O channel available"}, -{SS$_NOMOREFILES, "%SYSTEM-W-NOMOREFILES, no more files"}, -{SS$_NORMAL, "%SYSTEM-S-NORMAL, normal successful completion"}, -{SS$_NOSUCHDEV, "%SYSTEM-W-NOSUCHDEV, no such device available"}, -{SS$_NOSUCHFILE, "%SYSTEM-W-NOSUCHFILE, no such file"}, -{SS$_NOSUCHVOL, "%SYSTEM-E-NOSUCHVOL, No such volume"}, -{SS$_NOTINSTALL, "%SYSTEM-F-NOTINSTALL, writable shareable images must be installed"}, -{SS$_PARITY, "%SYSTEM-F-PARITY, parity error"}, -{SS$_UNSUPVOLSET, "%SYSTEM-E-UNSUPVOLSET, Volume set not supported"}, -{SS$_WASCLR, "%SYSTEM-S-NORMAL, normal successful completion"}, -{SS$_WASSET, "%SYSTEM-S-WASSET, Event flag was set"}, -{SS$_WRITLCK, "%SYSTEM-F-WRITLCK, write lock error"}, -{SS$_OFFSET_TOO_BIG, "SYSTEM-F-OFFSET_TOO_BIG, Volume is too large for local file system: needs 64-bit I/O" }, -{0, NULL}, - }; + unsigned int code; + const char *const txtcode; + char *text; +} vms2text[] = { + MSG(RMS$_BUG, "fatal RMS condition detected, process deleted") + MSG(RMS$_DIR, "error in directory name") + MSG(RMS$_DNF, "directory not found") + MSG(RMS$_EOF, "end of file detected") + MSG(RMS$_ESS, "expanded string area too small") + MSG(RMS$_FNF, "file not found") + MSG(RMS$_FNM, "error in file name") + MSG(RMS$_IFI, "invalid internal file identifier (IFI) value") + MSG(RMS$_NAM, "invalid NAM block or NAM block not accessible") + MSG(RMS$_NMF, "no more files found") + MSG(RMS$_RSS, "invalid resultant string size") + MSG(RMS$_RSZ, "invalid record size") + MSG(RMS$_RTB, "%u byte record too large for user's buffer") /* !UL byte */ + MSG(RMS$_WCC, "invalid wild card context (WCC) value") + MSG(RMS$_WLD, "invalid wildcard operation") + MSG(SS$_ABORT, "abort") + MSG(SS$_BADFILENAME, "bad file name syntax") + MSG(SS$_BADIRECTORY, "bad directory file format") + MSG(SS$_BADPARAM, "bad parameter value") + MSG(SS$_BUGCHECK, "internal consistency failure") + MSG(SS$_DATACHECK, "write check error") + MSG(SS$_DEVICEFULL, "device full - allocation failure") + MSG(SS$_DEVMOUNT, "device is already mounted") + MSG(SS$_DEVNOTALLOC, "device not allocated") + MSG(SS$_DEVNOTDISM, "device not dismounted") + MSG(SS$_DEVNOTMOUNT, "device is not mounted") + MSG(SS$_DUPFILENAME, "duplicate file name") + MSG(SS$_DUPLICATE, "duplicate name") + MSG(SS$_ENDOFFILE, "end of file") + MSG(SS$_FILELOCKED, "file is deaccess locked") + MSG(SS$_FILESEQCHK, "file identification sequence number check") + MSG(SS$_ILLEFC, "illegal event flag cluster") + MSG(SS$_INSFMEM, "insufficient dynamic memory") + MSG(SS$_ITEMNOTFOUND, "requested item cannot be returned") + MSG(SS$_NOMOREDEV, "no more devices") + MSG(SS$_IVCHAN, "invalid I/O channel") + MSG(SS$_IVDEVNAM, "invalid device name") + MSG(SS$_NOIOCHAN, "no I/O channel available") + MSG(SS$_NOMOREFILES, "no more files") + MSG(SS$_NORMAL, "normal successful completion") + MSG(SS$_NOSUCHDEV, "no such device available") + MSG(SS$_NOSUCHFILE, "no such file") + MSG(SS$_NOSUCHVOL, "No such volume") + MSG(SS$_NOTINSTALL, "writable shareable images must be installed") + MSG(SS$_PARITY, "parity error") + MSG(SS$_UNSUPVOLSET, "Volume set not supported") + MSG(SS$_WASCLR, "normal successful completion") + MSG(SS$_WASSET, "Event flag was set") + MSG(SS$_WRITLCK, "write lock error") + MSG(SS$_OFFSET_TOO_BIG, "Volume is too large for local file system: needs 64-bit I/O" ) + {0, NULL, NULL}, + { SS$_NOMSG, "SS$_NOMSG", notext } +}; -const char *getmsg( unsigned int vmscode, unsigned int flags ) { - const char fmt[] = "%%SYSTEM-E-NOSUCHMSG, Unknown message code %08X"; - static char buf[sizeof(fmt)+8+1]; - const char *txtp = NULL; +static char *buf = NULL; +static size_t bufsize = 0; - for( mp = vms2text; mp->text; mp++ ) { - if( vmscode == mp-> code ) { - txtp = mp->text; - break; - } +/******************************************************************* xpand() */ + +static int xpand( size_t used, size_t add ) { + char *nbuf; + size_t need; + + need = used + add + 1; /* Always allow for \0 */ + if( need < bufsize ) { + return 1; } - if( txtp == NULL ) { - txtp = buf; + nbuf = realloc( buf, need + 16 + 1); /* 16 minimizes reallocs */ + if( nbuf == NULL ) { + return 0; } - if( flags == MSG_TEXT ) { - txtp = strchr( txtp, ',' ); - if( txtp == NULL ) abort(); - return txtp+2; + buf = nbuf; + bufsize = need + 16 + 1; + return 1; +} + +/******************************************************************* getmsg() */ + +const char *getmsg( unsigned int vmscode, unsigned int flags, ... ) { + const struct VMSMSG *mp = NULL; + const struct VMSFAC *fp = NULL; + + if( !(flags & MSG_FULL) ) + flags = (flags & ~MSG_FULL) | MSG_FULL; + + while( 1 ) { + size_t i = 0, len; + + do { + if( flags & (MSG_FACILITY|MSG_SEVERITY|MSG_NAME) ) { + if( !xpand( i, 1 ) ) + return strerror( errno ); + buf[i++] = '%'; + + if( fp == NULL ) { + for( fp = fac2text; fp->text != NULL; fp++ ) { + if( fp->code == $VMS_STATUS_FAC_NO(vmscode) ) + break; + } + } + if( fp->text == NULL ) + break; + if( flags & MSG_FACILITY ) { + len = strlen( fp->text ); + if( !xpand( i, len +1 ) ) + return strerror( errno ); + + memcpy( buf+i, fp->text, len ); + i += len; + if( flags & (MSG_SEVERITY|MSG_NAME) ) + buf[i++] = '-'; + } + if( flags & MSG_SEVERITY ) { + if( !xpand( i, 2 ) ) + return strerror( errno ); + buf[i++] = sev2text[$VMS_STATUS_SEVERITY(vmscode)]; + if( flags & MSG_NAME ) + buf[i++] = '-'; + } + if( flags & MSG_NAME ) { + char *p; + + if( mp == NULL ) { + for( mp = vms2text; mp->text != NULL; mp++ ) { + if( $VMS_STATUS_COND_ID(vmscode) == mp-> code ) + break; + } + } + if( mp->text == NULL ) + break; + p = strchr( mp->txtcode, '_' ); + if( p == NULL ) + abort(); + len = strlen( ++p ); + if( !xpand( i, len ) ) + return strerror( errno ); + memcpy( buf+i, p, len ); + i += len; + } + if( flags & MSG_TEXT ) { + if( !xpand( i, 2 ) ) + return strerror( errno ); + buf[i++] = ','; + buf[i++] = ' '; + } + } + if( flags & MSG_TEXT ) { + va_list ap; + if( mp == NULL ) { + for( mp = vms2text; mp->text; mp++ ) { + if( $VMS_STATUS_COND_ID(vmscode) == mp-> code ) + break; + } + if( mp->text == NULL ) + break; + } + if( flags & MSG_WITHARGS ) { + va_start( ap, flags ); + len = vsnprintf( buf+i, 1, mp->text, ap ); + va_end( ap ); + } else + len = strlen( mp->text ); + if( !xpand( i, len ) ) + return strerror( errno ); + if( flags & MSG_WITHARGS ) { + va_start( ap, flags ); + (void) vsnprintf( buf+i, len+1, mp->text, ap ); + va_end( ap ); + } else + memcpy( buf+i, mp->text, len ); + i += len; + } + buf[i] = '\0'; + return buf; + } while( 0 ); + + if( fp == NULL || fp->text == NULL ) + fp = fac2text + (sizeof(fac2text)/sizeof(fac2text[0])) -1; + + mp = vms2text + (sizeof(vms2text)/sizeof(vms2text[0])) -1; + snprintf( notext, sizeof(notext), nofmt, vmscode ); } - return txtp; +} + +/******************************************************************* sysmsg_rundown() */ + +void sysmsg_rundown( void ) { + free( buf ); + buf = NULL; } /* diff --git a/extracters/ods2/sysmsg.h b/extracters/ods2/sysmsg.h index cf46ca7..b8f4a04 100644 --- a/extracters/ods2/sysmsg.h +++ b/extracters/ods2/sysmsg.h @@ -1,8 +1,18 @@ #ifndef SYSMSG_H #define SYSMSG_H -#define MSG_TEXT 0 -#define MSG_FULL 1 -const char *getmsg( unsigned int vmscode, unsigned int flags ); +#include + +#define MSG_FACILITY (1 << 0) +#define MSG_SEVERITY (1 << 1) +#define MSG_NAME (1 << 2) +#define MSG_TEXT (1 << 3) +#define MSG_WITHARGS (1 << 4) + +#define MSG_FULL (MSG_FACILITY|MSG_SEVERITY|MSG_NAME|MSG_TEXT) + +const char *getmsg( unsigned int vmscode, unsigned int flags, ... ); + +void sysmsg_rundown( void ); #endif diff --git a/extracters/ods2/valgrind_suppressions_ods2 b/extracters/ods2/valgrind_suppressions_ods2 new file mode 100644 index 0000000..6d39ba5 --- /dev/null +++ b/extracters/ods2/valgrind_suppressions_ods2 @@ -0,0 +1,2 @@ +# suppression rules for ods2 +# The goal is that there aren't any. diff --git a/extracters/ods2/valgrind_suppressions_readline b/extracters/ods2/valgrind_suppressions_readline new file mode 100644 index 0000000..470c88e --- /dev/null +++ b/extracters/ods2/valgrind_suppressions_readline @@ -0,0 +1,46 @@ +# Suppression rules for users of readline +# This attempts to suppress the stuff that +# readline creates from termcap, etc, while +# still tracking the data returned to the caller. +# +# Most history memory can be released with the +# clear_history() call - after write_history +# if desired. However, the master history +# structure remains. Don't know how to +# distinguish the two, so the history calls +# that add lines are suppressed. Note +# that read_history calls add_history internally. + +{ + history + Memcheck:Leak + match-leak-kinds: reachable + ... + fun:add_history +} +{ + readline + Memcheck:Leak + match-leak-kinds: reachable + ... + fun:rl_initialize + ... + fun:readline +} +{ + readline + Memcheck:Leak + match-leak-kinds: reachable + ... + fun:init_line_structures + ... + fun:readline +} +{ + readline + Memcheck:Leak + match-leak-kinds: reachable + ... + fun:rl_set_prompt + fun:readline +}