From c7250fb279af132333266af36e19c156dd84eca1 Mon Sep 17 00:00:00 2001 From: Andre Noll Date: Thu, 10 Feb 2011 23:57:55 +0100 Subject: [PATCH] First draft of a test-suite. Idea and parts of the implementation taken from test-lib.sh of the git project. At the moment there are only three basic tests with more to follow. --- Makefile.in | 11 +- t/.gitignore | 2 + t/audio_files/short-44100-2.ogg | Bin 0 -> 46780 bytes t/makefile.test | 32 ++++ t/t0000-help-output.sh | 20 +++ t/t0001-oggdec-correctness.sh | 36 ++++ t/t0002-oggdec-performance.sh | 39 +++++ t/test-lib.sh | 292 ++++++++++++++++++++++++++++++++ web/manual.m4 | 6 +- 9 files changed, 433 insertions(+), 5 deletions(-) create mode 100644 t/.gitignore create mode 100644 t/audio_files/short-44100-2.ogg create mode 100644 t/makefile.test create mode 100755 t/t0000-help-output.sh create mode 100755 t/t0001-oggdec-correctness.sh create mode 100755 t/t0002-oggdec-performance.sh create mode 100644 t/test-lib.sh diff --git a/Makefile.in b/Makefile.in index 3fbbce21..a246f4c1 100644 --- a/Makefile.in +++ b/Makefile.in @@ -9,6 +9,7 @@ PACKAGE_VERSION := @PACKAGE_VERSION@ PACKAGE_STRING := @PACKAGE_STRING@ install_sh := @install_sh@ cmdline_dir := @cmdline_dir@ +executables := @executables@ build_date := $(shell date) uname_s := $(shell uname -s 2>/dev/null || echo "UNKNOWN_OS") @@ -67,6 +68,7 @@ man_pages_in := $(patsubst %, web/%.man.in.html, @executables@) ggo_dir := ggo object_dir := objects man_dir := man/man1 +test_dir := t m4_ggos := afh audioc audiod client filter gui recv server write all_ggos := $(m4_ggos) dccp_recv alsa_write oss_write fade http_recv \ @@ -93,10 +95,10 @@ endif ifndef BUILD_VERBOSE BUILD_VERBOSE = 0 endif -ifeq ($(BUILD_VERBOSE),1) - Q = -else +ifeq ($(BUILD_VERBOSE),0) Q = @ +else + Q = endif .PHONY: all clean distclean maintainer-clean install man tarball\ @@ -277,7 +279,7 @@ clean2: clean $(Q) rm -rf man $(object_dir) $(Q) rm -f *_command_list.* -distclean: clean2 +distclean: clean2 test-clean @[ -z "$(Q)" ] || echo 'DISTCLEAN' $(Q) rm -f Makefile autoscan.log config.status config.log $(Q) rm -rf autom4te.cache aclocal.m4 @@ -313,3 +315,4 @@ $(tarball): $(cmdline_generated) %.pdf: %.ps ps2pdf - - < $< > $@ +include $(test_dir)/makefile.test diff --git a/t/.gitignore b/t/.gitignore new file mode 100644 index 00000000..e61ae9c6 --- /dev/null +++ b/t/.gitignore @@ -0,0 +1,2 @@ +/trashes +/test-results diff --git a/t/audio_files/short-44100-2.ogg b/t/audio_files/short-44100-2.ogg new file mode 100644 index 0000000000000000000000000000000000000000..91981cd06ffe4d6b0e2474c3abbf0e7ae245943f GIT binary patch literal 46780 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˝Ks>5U}LGLQ{R6qcvjX)?62F4tT+a zViOlMV;3F|bLNi~rmkZD<~#OmFxPOp$-FUX#Hc8%v|LCx?Vwi7fSWF=ctV)T{5|=l z#-YrUpqXrXmEZy$&fCx{8AfflW-{x@qv>W#3zaW2<4C$E_VMaQHS4YuNLv!EYID}Q zZ!Vz$FD{u;II_z=6jg=w2~T&t<)nIl4%fJ=#9h<`+L&;qNcQV0C|d|F0sZ?hGfE($ z0tVc(SX~KgUmP;$=ah{2)X)~MyFtx%nO@To_d{iAw7R7_C4rTt_54$gKGC}G*p`w$ z&pFG~G)J}+A$nSpNJ*^hONEgrlLb`SWaVVAN$$s#d@J#(weh~3U%g$^6;rXx9bJQRg0whl%sflqJI9GDzSZjsO(bDB9)Iif$-mRl$0TW} z!oVhY>bkcDc>{^cBTw_Vrw{2h`&yaXhtX!~4Vk`MM#lKCjKWL$R(X+dfF$<|-k%v8 z?P0?%RX`8%(i;?Jj%iFz17aesn-XtZVi-ooUj91TuXltP6j3hQJD`u7wtCw}1oG7% zjN(khr1`|`#rVeGa96FQ1!$2j804DX?0FGXx*UY8mvG?Dp-9bU0&geLv&MCW!fIvw z>V3j#^3&d=5rN`>H>0C&$n4&$*iaKeUckS=t{nJf1BV}%kqD}2^)y}dvi8|`T4$Qs zX_jA!>#~$11pt`1J|?*iE%iVmsa+xN*Y2D&HfR!p7cw9mYOEw4YZBq&D{0rVrR;Lw6ggd znJgu%Ea#(t#36A<5*6i$;q)BoKuIhMlLQ@3qHy?*lBl=f(-&V)LP^e7 zW!_9J9Ok6~TFlaZ#Mj~m&??OD}CBE>ErZ3<>_;M z)?Dm^YHO-tpDx~bIr=a=bN*@4!!W_?d8y(wjoqF*HXhk)7vubbeNzKlrgI(;8a}d# ztkp@YcJZKPQ6=L=B!bJ8=Ow z?!ppirI+k6fM?2+L-ETrgypIkE-J?p4qn8y-J^@597}_^)b$c5tA+ckoMIAO6+8G zhFW(r0(Q>R<9ReL^`j{`ze9xIsK@jq1d!afdDH3Tr=h87R6y+WaOmFY^EnSnp(yZ^ z!lLAiXg{ZqmLKg+A2u7^h)|nU*)ON? zJ0^1Nr3|9oI)wx-_|D(qR&_W3ymosw%`G~4MBHlY$i1wy)D&K zq?TKb*+LeBa{V_5hkGPacFuav#F~kZ4CYVofmd(L7ITdP(v2p=tBU2{g2tBX2t*9h zo#XaYz;rYpd(1&K18-2^mku(ACNZWuvo8zOGR_NE*pgmUcYERR#qP?78D;A(HIHot zA`63>R zdfBn657%Z##mnv?hUMH;l3T+^dT_d{9 zDEMq*s-S%NrVL)|05;$TdvS#2D7LH7t>7Ni>#WSmCdR2EAA5huDjS`jBXb+ma8vX0 z3{i_)a@B@gJORfQAj$3(mZKej0G zlU?pL6E2#yLMCRq1)kfj8YGhvL0KQc}b_}Y?8wC*e zv(q)3EJhE+5@>Ts1}%joaYXa*gg$jI21@y@BONW+SPOf7m_-sN@0Dq1iewF_o3pYZtSMfY8!^V2%809T&U7_wUQP^!2qs?nu4M~wQ6!97Tieikzr4+A z*jXA9&W?S|V%1xddp^BM_rpb?hmJBUQ)TYy>~f$m-?P=9ribhuI$z(>rnxywN>BiN zb2#l;&IgO~oE&^l^P*E8*2<)n_C=ob@7jnd*pa&r?weCVT_Y4qM9r2T_68VrOov6Q z1akNS%m_vXj7ngB6D8v`qqR|giy(Btj@*%*(p)uk0-)A40X%>OVWw(Z)sR|Tg>c~t zw1^~#SSlJuD#3cbiCdkWEQ8M$NEMkgub@c6o7NWw%%QMh783tgY`f0Lk-YKt>Cuv-53*eY-U3PQZayH=Tb1huRAZl~;yWn@%%VpX7=# zyarEUPED9yiEQ*i; z@Ra6J2pSx<5D_IHEs2mO8m@6qa->pu2~_7GOqx3x0lXx$d8CCz4?sGtqaQ_V3lTiG z0{1K}6)KyF%!*Amnv38WgX&72hjFi^td@Gseq`jK0e^B}%G8OC)zYqsO@pF#w)Kc5 zvaf^#fHNeDcxzzgm>-TXv?zsZIK-LV!B8)&RwtwTBkakIZHWL|&d=so$J$SP@aH)i zPCdT`rhL_<<-66!`{!{qxs?XR9<$nFm= zZq5B9@x%U7X}Ee{p6lr;o4d3+zQEma0Sa`j&<(82zo9kPrXLqd^g%Y7FsX_xIb{aL z2(QG{~H{z=w&tYkXhB{g>UnyiHp3He%0Hs@QW;YbB1J|v>B>(n2`NoW?!zyNJZ3qeNKfjXV9=MQuiw%BdiG;P@i*(aaQQ&=^q zM47Jg9x}Wd(Hn)@|FHl3?K&aB%n-HlTu4!(Ys+RT%6-km_=<9B zMt|VbCgY^9`ERk&yonkb^7OoJlF&*=Guq*mq$cy09bP~ZO(HHS2P_mmi=!li^5U?Sg*!d0 zGDSoZP*GSsyC`=jkV%Q6OVS~K0kxq^LM53GQ!q;A$cfcZ(WUZG)v04htV->ZNp$#l zEI$j2ro5BdNve-twujEMs}ccmGwSorp5O625HWY2#{_c0Yz$63Cq2>^kFj&2P=(T! zguBA=VRU{%luV39f4@(`)%@rE2zUqq(DkkoJnE<3r|zdwrS95);w)`1V z_n33(Bwx!$9w9dk}@1wW#DK(@tyv*Uf!V{VH&LdQax))y0Ll{!;TIyWRsh^xa z$gsUu6?es~v*X9fDdh56-GK>R`Jwi#MT6GifEa%La|i@kAG}f?(;04%aFIv&$!n3! z*4!Z{iv7;mcz-tZ!VnV zuAdIynO-Va3me*`u~yXEVfQ-VbNya&Eh5~Hb#AZmqv!EnY3XTx{>`ez!$1v7*j1i; zC646pzPIKXH7N9|%HfGv>$+qWlbFBJ?>MVof_M*PHGNY~1 zF1M@e-A}SIHJmKui1n)lY7*(%N~ZM}JF?i9Q+O5hVy8|d^lSI1as~fJ(y3iWu+$eeJ zmUDazMGt6E3L{5Est5*)=YdBGcO5D70hl_91z8A{1jVJt5aqjI?6tJBL7YGv*XOyDmHg_@03az3nGY_ z&q221>zq5cBZJbOU7_n-o+;%-g&xAJ>Xq6x>b%mt;|aWq&(6^g!;J4 zR=stqV)Zs{6PksSdCB-xt-az*;7Gi%zwOodxF43QVO1Ai&`Rc$x?9vEtFo*~Rmd?d z8WI58C2juhFor7^9xBW#PY{e!_d=g}%tRDzMfNmG*7-99(D071cOfKr*HUZUHT;`+ zrUsR#Cxs?IlPg)BVkU-FpA~ zzE_Bcmzc0vX=%2Ky^C3g{N%;n(HqTmVJ}iXPF@+bSiW-Yw(othsFfuP)AVo4d*3XC zPK!9Gf86_Vvhi&|2|J#6>8R0Lv@$Q(`_3Kb1;^OZmDIUS?y~a1Oo68~Ldk`RjfcMu zlN2cB9lu+ihiF~-uvv5Dh*5q|PiRYFYHW14{4-w@#u>Aho&8e7liGkU2Wt@$mWTG{ zM2^Rzya{=F^`zUJs!{QF>~R*MdC~Yz@+kFiU%s3H{mXEh8|4|K3(ux2dmmg9oMWa! ziAv{RuNGJVoaO>)>P;k5Z;vLvqU08?=Pm)SP?Y{3qTVy8i9gW(-h==l6axed0W^f( zJ5nqGlTf9G7^(pRLMQ^#Ecgpmy7VR}y@cKo1?gR-S3yM(L@cPFV&TdCKX>MCCX<=G z*cUsy-*Wbx&#_FEp*`|9dEo3l7{jmQVQ-ZK8>E%%@?r01`OASKA5@FDwUxOsBvqNg zJ=gnYlC~V~;(8)@21d)8kj+x8>yG&suU_Vi80`x&-Kj6k)f=kPOD9 zS<~vP-Aknt-_vhBv9QT61W6!RdO=2aUK8!(I z>LU6CVA({PGs0p1-VP)Q1WsKBy3`ZPxzcYFPtNa93df!iNwGnZ8iATY**6?GcF_|8w|kT zg%Wiu$5jRd% zYjNJg$j1ssw;^H%PZv)}jUWfG7SF~bDkr>ZTN;;O5xxzP0;?_~uMQdr-*?;AAAGVb z2(X>l0)1zl5Y~SSgt0i=qPPL=hQ;%>)4W;;x1>9*QZLUrB&A`~a)BB}O;K+Of7hhk zxWe^M`U_wJPW0au;Yrq)zhF(z=@M`;#S@1RoT?t0rt%c<)>mRR`V|XguZMo)mHl>e z>AZ~XtqlFvT^SSoj71EE_c+UQZr$4oK}-2sc~8r!Cq$OCo8X*MM349c9tW;SOjW6g4M^hZ9mRG0 z&ljnEP}9&^&`_aXwsWzO;1+73*@Sg{pjn7c$uI zT7|$Lazg&NMJt9TrbM$Hw9eU*^D=9-#9#@6Y~PFd0z^j_NMA}!-$P!9C2O5~>aO5m zK*prYH{5vO^9$#?84y!vCq2%NZ9Oz%KziP1z6Lp+9=|A;c=0OQ?sp_ zQEisF>*2Aq`wAb%EL%W8yQ;`?qnXB>+~1%)SwS}sHnivF8Q~$6nSJUgY)3ysZXigk zQoTYzicpUc>dW`rt0li`yIk{5PVuCZ5pg!ow#k-N)^H?JP7|{c(d5I4c+F9d-FqZRhZ;7ImXiDaml=qqDzrqV=08iTAL8jDr_aUv|fIh766t{ zT5=mS7%G!t__paP3Ks_9So*`F5yFXtA$xB^X|<=7t*ERuDiJv;6Mh~LUP+0N8DN6lM1L#Hd68M_N8mEcCZMkJu zqxa#Fgw8PuZEo`6S$Oj;kX(jmq}vpWQAh2WnH&lI`QHq)vqG`H9CLqTH?I zN3qVHkwd-H3Fk}?;DcTQiHmZn7vBwPL{1SUdT-iU*|M4xZz({mf_GB(thC(GR_05s zC3Ot2kDQOz8{zu}_5ZA2Hc6%Jv}6a`#iI8jZV)b56&9~5@P_qWk-nkEqZ7bms=rv| z+j(zEx7F-llc<}}gZghqu~qdlpDj%hbzN_Rp4$B~(btlKj9lCJymGTkISBO(ROF`; zJa#hK-<`d$s$fp;A84Tfj(zR%nXdle(bu4-DU&;D8;Q?ZhVZ2;`^B`R%p?M9Qjp_( z{hZwf=tXv!rh}q7is&CY9w-9gBs^aRm1(`<_eu_0v8i|J!aZ1`E}h?O^M0k~4I4yR z@oz#qb-b&qssvl@2kjFh69}br6)jb8^YvZ(t9Y!5gBZDn=v|wFTp*Uq)?WV*C03EX z5BMm(sq`@U*nHdGqEsvA>#`-=Z@v9bl^r$@&z1-ZMpTdKF0!??oJOfG!bm}jJc+@= zlab}S557)i&1Tq&b)G%yK#Y`Fu{II##O3ie2Zn&`kTnMp^`2d(_|o@K)f>3aJ|;%~)?UwT^C_o)Z0iQD2B(3XF1AZo+rnlZaS9Tj&K z$W$8Rmhke6{d=?AB#?!qTiW#DaCnTCXPiWCL~6HW3;Q;ZZRh7VRJh)%wA!|nWH%PI z?XF)OyER*UxlDI20m?8hOtcmNNx%?Lqta@94W>){e=Ql~|0g*x5lO(N=M__VTRU4z zBF@Iv=&}u&L?jU|U$(z&OL8C)9gXmKW0Q*nGU>SBIQg>Ov1^cSnl#JI&x|K*g<}=| zXC&Ny_SL^Qv#ld)@D|O_!p17TXv|hq(OvxDY_^Q6*Srd<6?~%GMZQ`019J7SKb(3f z!YHBbQG7v(RtL_hJIA~H0dPP=DNWkVYJqjO&)KZx#jsSSSCi9^CtPE zNPv(Kh${E&6m}UI%n${rC;PbD_ z6#h0@`w+{?oMj&?4qj@Amwi$zKJXom#C!ANdArGw5Vvqe46;mZKT68&=e_Mydc^qk zWsLXhkd-6z;c066jm>zM)Y2OrhQuKwd?Hzc+}L{Fwb(r0TPnt+LtwhDcQ=$an4m?K z9L+(w0YCs*+Xti;|Liy2eX}};G%`JTT4r)OCk9VHK}C(N19R-} zf2m|$e1wd3|1AE_{aTH%JP$viDEwxUj?mCr1bUgqW#bhwkm0D1P84p8uX~+qXazHC zq?C&Z%)RDjI!X39=KK|yTYrss3!!<2nC15IWY>YZl~CZDB>fM{PIfClQC7C5Ho7V% z{8HHAnHLS|r_suy3V_XtCnQ&MPH^?)JXPO&Q7)nlC7vx*7fs(?42`-u8GOpeZH3B# zMG$Huh}|rJl|bEk|L=Md%#G=-dlS{9ACh5FcrX8Kq;z``P0jyv$LIIk`X2m}1d2sL z|J5OQO&TFPG_KZ{ATaot(a+SPsgys9bNsFMM}of;U%O!!I=$OyDkfBjpH&TrD{Xt(RLm<1k`_ z4Et~W5D|7yQkDW||6kzf%jcNZny9}7|U<}tE8@=;u+BkPv_ zTWQ80uS_3KY|nl2Zc5WR(?pyo@wa8=2dAk{sCGD=ytCxYW+wRSnI+ev%iH|KiyuY8J@uXf2{^0|?s0Xf3 z)?d#Fs7P2>mw3{=%CBv_Y6u1w$j#$3hCi+P+FW3Upfq4!KR&iwUpV?Jm=+Hf(+}?# z@xWC0#$_r6c~VVXo$8#5!(iTDB!q@R?J5E%=3+)Yo$xT)=}~zANUSY~2`(7bFa=xP zw5u;_JztMIjvGp;RZCk~N1e}`4IzmBsc17d#C(lrO$Is&mP$P{O)Y7xwFvbPt;aDz z#g{|xaV2_ee|zH^WI+vDQ`#!fgD~uy`rz!vWCKejoZP;bg-rhgn@UYD>itV5_-7MI z=6?vkcOa41%~e5zzSq1Z6mpj}dt~<BkS&8RE@dC>r`L^0 z&!Q_smyB1~_O2xcEGH&V<=dN5JBaVMMuK9wUtHgwKGoQkq}0=E3(Dq4ciE?vLk%bM%4BhuwM? z=b0fJwF_(hUra6-RZmx66mYY{mo;Cv60EbAQI>n2Ef6hnPN8^#mD9{X#E!_#>2Jx5 zEWUjgp@!0#?k9(BCOSnv3op&thtsb($M8bWQ9Q2XOPl^zKiF_T%H3_fsH@$-+v3Ny ztgTqPzM6YZvw_j}-cJfKrwW7MlXV?}9m7rEBFY7A45Cln;=r??g?*rYlW6?LdU*P7 z_ezAILBi=53LgxahB;*pwa+Hcf_}$qoflsG`-;(V(Q)G$5=x1ibY6)p#yRM6s49a9FvFpaE7Qk5dP~apFk)+=mNnP6yOl#m^QM&Yv|tIz_iC zz)pZfFQ?9R*_G%fw|izW*jA4i7&4+8ig}p7lyB=Lq7fjbFItn7a?u5A*Gmv*2y`bu z3k5{@e!Yvx9L#m-vf}IZlW~mnahX)Qys_hc0fP161%WK}yXgnBa+`{eMT^1V;PhHs zYY}_-6~Mi`3~~43-o3wLO}50#^WY?bLYS`*xit=N0_wFQ6H{3O1Q9&HHg6~^{ZU9#lC}X8Wd;1lDRhE+o*qfJsLEOfR81|SIft% zR3fAPd(?6N)XGX3qIfN5CwuEf?On(6gq@ol4^j2)D*?(c11Oi!Sk^wCs|oo6Zws@e)C&8$t;M?OwA@W{xen zG7Q(n`ow~8Pi5{HePHhwg{hnk8Ia%JHqx?AwnNiy>AsX_Z15#a&+pK_)qO7aJrgjg zr&zghV|@Bp`3CV^|DJjPNwgvV#zSwB4x?mGOldny)6X|Nki&cmg}NQ7;r-2vt7?>8 z#^_$%?zPix@hX|t(b;wjdBMK}z0H}`A?56Y7Y&} z9mKT_fKuP*-}4KxZ=5j?QT?RtRC~F+sWNvEI;vfJ+2dc}*V{WGbDt%X-|5+G%%rBN zE7R)V`CT(JdwSU&l6Wua;ScEK0a_!lDI6nlboD%JrE0Ug_dk#zsSz=GlJf6{=@}{& zw|Ufi*8SXC%zyj#A3_as5LsI~&I3u-3cIwACf>6!30WxSjejumUQClYev~7s33XD-rAlc|sbTv9BS27&LmA$DFvbqEWsqf7IjP|QP!K@lL zcJDwk{X1{i{}YP7%@%XNNc-8w?Oo^Fni)hHOBaf3>G}|Q9Ri(7zMJcmqkXf^T=<{d z;<4^6!s>B=>y4hP2LHLf?>i^)t^CwMwy~ejms9^)Pldm|a%X4!_|L5;__dWEtNVyz zLcsz4_7$g`lbM@YzeYa>ek)wz5)u<^(DTm7uin0XeD>&Xpkl`=!y51LGW4H?`;|hA zh6+P#f6)tnE@su;5v~iYAsANsh!qU~0hzxFzG`t8q51rrkbn!xr@w3{6)5-P2B~LY z)u=cf46nE$HQxMk-x6QWz>@Ekr>DQ6{M{Fw1W{MjWQA^q@$C%j-!IQYq^@OIz&TL49HB;O|bY zoT2|>njSwcxfi9Q_i1te>Ai;I`YHTJts2{|XDL^%Q5Mn@ew+9LPaE^$3&pWSvJ!-yACP^)`+<#}x_dW4Pa$xhsNzM+13+<`Q}W|^E5S>!=6dRmwSf661@FQY>hC6#o2)92RJxmM@v2HvRBm^tJUOdP z*tkfY&^usKH{*SUp;Eq`YC8&!ev!`R9vxROc+RW0o9wk>5~>zq*q-2LnA_awcIuX;yBtOE%}kw zxsOI>{|3sW9N&2`KX1d2Gld(ac{l|z+P$qLjA29lZe4mKBO)umPA6ru|cMM5<1>k%ORm=sH$xmLpOBQA7=7(qu$p1W)R@=TdVZ-3C zewjDTZHiVtPki@zy-6zX>5KS*vxWh4Nf+0;+zYCCkJ3axEU&ei@$IS*&wou7R5!sa@+No{TWbXT&QUYu3>JdX-0o;v0$wLZ7~ z$Da#Z*53vsYh*c^MpxzKvSx-fuOui)PgICs_aNAZZMW1ky!6XF&HqTm<(5KM(0trU zZQ!K=!dTmp+p5))b`m!o-PE-dErZ4zE%O-n#>IMCdB|}1-|=ZGDv?V{9z=2CLFsC~ zsl7-(e~yFbQ@mbtS(n5VKe|4em8@ExE7h)cnPhz*`!q&lM@x*t<~YL$^^#0$wIuMy zJTPhtipPTVB{QwydT%Wem?8KoD*$ETi!rpeY@+=qVYT9oyfeeXmy&*L(|hj$LPPCO zmqJ|=gbP3pbcORx@5?ph4=mEwL0~S}|3*jX-~Ugi_#alLvOho*J9c1x?2g@WOj!bp zC)$`>6Uoeft{i(E-!inbwX*41I{Vdj6ns=-^!e4f@|3)?p!kV%S7L%FClbE?d1ga{ z&2LJlw#9E`rdrjFmmF%RMYPP_ZD00qYAe2@ArKXBlS}36eNk2>1$D{sD*Ziwa6<(Z z=I1?T{^8Pvw{N57T3wn+&`UC=SA{sU8l)!vvvu|s(=C#puo0E+Gr(qz*K1gBN~T}b zv`rcVG_~9SuL!_wMLd9JXMnp$R&unizl;UF{}dc_Aa&pv89eLxtJJH zmd&ML;3x(yMg}$n{;Bx95u^uVY-YsJ|0vAs=9t?iHpu~C?SCv6+&mpbt1p7!FrbGc z9CB$C{7r0m`^=TZ!lBH|%eSNPM(qFbwtc%_xujbD9%Q|0=F{6uQr^{r>J}Q62rSJAhDW+aBKN;wKhw zq^Z|+({#Au$-{vyv0E=pTd&%^EZ};aJyb76U~{wREIU_h(BM+dKE@Jc`Ut#I<2^yJ zqgr({*Q1OTS9M^=61UdqBwclgI?$c*Ptg(zYd99 z7?R?QPF+eMJBQ$`2rJ9IeUA%LT)9(3yP zhaNETnj#>GLqiP6P%@Z&;c}Y$8(V%j5(|33(Jk9D&XNv)eE%0J#6)(t{2L=_oEuzR zSv32?TowNxnwDOm&06`8T>LytN`|io1eo-GajFL!D9ENUPFy#bf$XVe0G63?ACT`Y zG|BuqzIKa+LyneWMdyHrzeT5`>Ty5UPIeBQJ1kb<`e7U-H?Upm_U= zU6Z|sr!7k=0;qCQWtf{->W@PEbU)j-RIza4XUwSZ!7eXXF~wqw>AA2Y=TYva36rNw zt34WOb-0s++o(X7HKZ!^1_T7CR5ZcM>vwx|v975QqQ0lV-5r}$PP+g4Hb7p7N*cDK%j%eZ+hU9-W&R|JDfD72Ysa#lwq^?7(--{LIGGe5O)&At+gDK-ZiNU8v-btNuEkVP;a zgG)}}8b$c|L#hSlG?I&(M%6BrwOV?v&|Pxd2ULDs)tq2h?`M~UQF=LD%4MFr*jaJ* z(R=9>%A??Wcp)r^o)Tioo zIDi1Sm_9(kH;RZfQYRKkh6Cg#~^aK5+viV<4HND}j^SnU)iSx=Dfk%_`nacIUR zA=W@o?|2g}7Yf&VZq~P+oawzLs>js1ns0SK2wl^BS*BerR>aJ8<}4r94?5aU z>SY+Va)NCu-~2(^Nn`Saq|mQlFHLx%^5fS-KB?D2yiF*|7&CU4&e1~kY5d-8zFUsB z`^@#@M1k7#KU(&^)0fv8qbqdWKRw<*m9*z)6Iq>NuDF_q3y23b4(#@%-+s7?t5djp zXv8ybG%S<8+iZeUY!051|!43&BAKziE#HUC*sg-$M2L@~PPm>;Dvbc=)`b z;CzTmp(z&@x~6<{v|Nml2%w@$+PoB4xh9&Ny4K zB$g=Rku|VrwQY%R60hC~=MJ0YlJA_4mlRS$70h3ZNxi`nVtK1RWFIfyFfxsp5wI=3 zWxJuzi$C!Os?vSKJnuy`G*1v{J%3M#^M#T_en*s!Z+!+I?_7Cx+HP)^&7!JZbqO*; zn`iZ)m_wOR@yrv=H5$@SSB=%jN`Mj#WgWFot|^#`X%1+iMfhyK?!oT)CD-&`33}jo z?x4S5_wb*Ye3Xc-KbL)TpN4&S+!lG>&rbgw&7Jl%hk?>>&D9fGw4T?%MA>_Z466$kcgp}I?_Nl#!y_gTsB#7ACxlT@0jbv9ge zP6()9YaVo5W<)L=trXE%Z6sOsY8|@btk_7kuzvUqnNyGzH(f`|)ZUl~`7Y}tcX_fv z!73o9aD+c{3QB%?)%<$!R->(#>X*=)|IUerDtss*X=&u(YDk3WYE!G2X>t@LS@US2 z188@{8Z_1lq_)BAO68P@V_Ag|iNi>?ipYV* zMdA188|QUzA45*X$TwIv;z%Nt#2tif8{{iAqN+Hn6|IYp=&0gli#Eub?kv2K2H=hu zZ0K&Iyq={_P87UM%Xs$WXW19|WKqssZ_G4h-SrJlh>$YjRo z*O!mmmY3^hkEJslQ7a<@nIj1BRMel2fy^jbND=!lcHm1*_hRxl!{@(uI`y`1Lz3R$ ziq^+OWFyUj<5V*yWha@#UHYieqi?Ps;g!dM!tIxxqGq$(Mtby~9-e!3Sf)NKgX$Py z>5otRlruk&a^b+G^1jZ!lx}+)*({TCCq&zhWK3g8+2r_mFH=jRpL9S)$jPKLXAomP zII6cedCs8oqmiscmvh@vwCj}p9Na~CRedmhKLOx0U@;mTri}6Fm!8CG++>Xs0Kjkg z{)ETb3=wJ>f_;{C40~Q)K*VT;P#qb!J7mqnP9j9$kSkFoapi68CTpuadly+h<_0Rw ze*N7s27W@5l#7<^*H3Ts)obsA#&_|R%Cv{!KBBePY}xE3u{b=|aj20(XkTND4U@E>N-KjbnR#gApS5MJ7A3PMW`_IHT;l;ZD1Zt{aVTZI?(0q2h z+?tTc=$7GOD}faQU{*d)#VKvzBKxQj1u{$!f6dDYH=Rm#0Sv6^mbuN)%j1GrC|XKI zUw;SD+;7cMR%&VB4t7%kC=nW_padTfy%D4mF&Wud2a_?F7lc@~#gW;f$PhO%@m7;S zQ`WpWOtNAv!j>8`)^U4_-LgcCXa{bDf&HtB2nMPUeK8*#q!w?f5>1EM^$P**Ov@&C z=($c7n$C}PL5_aKRbcZgbcIR!U`nT2*g-!m8}ix#=aJH-#C`S~I>kFJV*Mwcf^_3-4okk^$hKphQ@#qXv(DEaH{dN1V{WQvO-}Bq%})9&sCB&8C_m@@a;qn}a^n8EkBa9z2Y!8= zxP#GVg;Gs_ z2g_!HH&L=!;rq56xw1(~WkxJscD)gAe#=>#S0b$R`Cgp>C~}_`g&+2K zZ~Y|?FEx-|Z$AooH8EU!x>U=J_-rzFxr{1hjE2Wgo~+JysjxKX9%=hkr@LM`mr}#! zCH>JnEMdCT31&x-KISg43akB*Gx^{Z`o$m134!MiV_&^+XyGM2c~-<@cD*Ys5;?Qy z{BSze>0qPZldnZb${;bPcs@bbAMx;1LinOas5>Ny%Q$*s}}c- zhTd1rOu;iKW9!Scj@u>#g%K4r1k4@70=Iih><|@7bq7R-N~(*mwQqbYkY@3=mG)@) z5>5s+OQ)EO>ZDpIsGe_^6TLK?9iZJI-`m%DAHB?sLQ|Y~Gu*EeB@VZuk7@;MRlOG?CuE!2>m-5tiQl z^ya(yA&0e+$#OW`E7Ey~Bky~Ig^hpD3s!$!h@8!b4S%q`|E8`6e5NZO^=w7+lMFZ2 z&K(jj`0}r=bb#z1OX>E%wP3kKg|*GK#H-GKmJXVr_rYhLvcKB-EPm@?v#O)xZ}^*U z{#J?7Wuojo|2cXZ>p2BGnUU0Kpue?#M*#;=O5O^r&AwS;1CC62tZvYuva@&_Syb_Q$#Q3f3^e6gUQNdqJDuZKi}L# z9$PS_2J*4vvF)+V|NFgseEB%&*#2fGabixXPjI#+7tYX{NrhpidI*p4@xXl_hP&zBD7PF~TA{^cs+5PUA# zNs?CA`_X*iR(%Nj_ge&KXR2t2g9o1-)lBa5d%?3I^H&S~4-|ZT0A)1Tb=s6JR*Kce zr7OUb>AY6B)G`79Hdw8iVF4T5N2iVt%Lx_L!95kqU#|%IS|w~W<|nXHbXJ2pqrXzX z!fuFhay0lPQlJ-=)ej{TtgAr&1TV>x!yCXL()L62aCW@U?a)@G*Gi4<9Fp!uCiDB& z=$g-W@f8unWTIrT^vi1OC_twwja4$g-q^=9y>YtV!k$y;(tl2b zBL}HVD=K>HAki{$W;d$nvss=Z;1iP}!*2P8m6ES?6EG*_OYiim~c7 z&1qDZHRSHDM#Yp|W`82?{ z)aCkk^#U?{8=}IcA#tZk(m3I=|KBra8EL^M8te*lST6=#H7<@KTJl+q<8`_az1CeA zXLypap%E)+H44^DepxfpJZclgy+mixm(t-g0zd|(kraJ|!9p3n5sktjg!G}j@s{sr zr&HM=zP(_pEU2#nTLhp3WS$~N)KLZ*BP@#cy%lScmqoISRTClle5(nC_!48n>H^n5 zyC&}$9B~j}nbJ5B7KWrxCm4#!Yk@uajCcTggj&-@0AE^WP}fGA2iT^;?a`DEK49RK zB_N`5lQLjZ&cRq&U zz;(TXT(5T-#{A!d?ZBdinD<71>SeVu$1k&i^myI)=ta%8A77+rebQKa)*JPBX@@TX*P=k6M*grzpJi3mlP--)Ry@H#WM9ER*=A#am$uvi+895s`daY&%$J z6gS$CvYc2Ykcp>VN~oY!GuVV31~F-(UWBEYLwhE7ma~LDrOiH6(8D9k>&qtun>s1C zlu`9HmKA0l2o>8&Ei5$6M#b67k?KsnLQ)tqOf=*dkyFWaNCYP;G43W*1*^yDg&0fg zS82S2x8*z;V<3heR4q=kVHn}6SScV155RQ-psKJnS;y4s8u`sz2brbM&rMgQ`7(B7 z0&Q8QU<4!NoNQ)4o>c$2?MiUE;*{$fOSY``|H=&B5zJFwg;k%@)aK@Uu#CH7dKmw( zJ4;$RLsR-sp6SfPmKS2%q)$aFPWYZQ-a%Dq3!<4(r%@`cVkO!)sIr9$8aR=j=jFji zMX&zEE9&R9GgM2xoQ^4=eV#)?H{@xDAe6;r!Rn@;BkBjJ`JX~0_~p)%#3*(3H6VJ3}Ujh-Qq_2sJ>kuA9X(% zVe-_p^Hr_%W{G$}fXlNNi{>0K!QONsqRW^qfaqTNX0cHf6VtkQ`j!m8kS}>bW&p5B zU2wql83C+7Ka3lbz^IawNno1-$3&9bEaPA`(a^q#-fw)?;_`j|CH-Zgs1+ zq`k?Tiu8r3{mfq;LA}<#dW!Eo;JhsHccmv~_ZIAo^!AFm(v7Db*TilGYRg7cG1Z#A z64&?mdkD-!tqu#rbf~UtnIvWXp^Jk11j2k!ee8b}Ff@AV!Mt-wV90;Uzvj2G$l(>m zj>+0ZAI*c1>LC?8j;#b-2(iV(sflLRD@)D`I2jisCgs=|Ap>3`J~i`Sp*0~Tf#oNN&KL7%;k^L zeVbwhwaSLPhUCCUlHyM}T((fQcnq?qk}H7*0FL;4 zp2`&44`IRDW*#<|pR9CfUK1W5mR2z>Y0fMMQSWS!8K8&o##=rIowxihRZNT1q;waG zJbkOlEA{<57Zub9Lg%5yZyBq+Rz<;}(8 z7d%<<3xsZuI{PeYk_!j3?TQWp_GJ#TphC}DHGr(^x9C3lNOTRfL=a!yWlo%gSc1yq z-Z@2pfYeNJbQokFV_%a{CxCy9X3%_Svp3k!%h2N_Ipa;Zv!=BGj4NKH#I^fUv_6~9 zAM0S+ctNl{I2!>tkKqF4J^lY3-7;O${wJMR@Mx)@<=_VdcPzZDB!kIoxAqb4*BU{_ zYf3Fg2r|R? zqvU-exZD|E08{&XzZ~%z8arynSqR5_V;_KGl+zP=H@ttQZm5j8S3d|Hk#(}?)X58mx<{RvM_L=00@)m=qR9uYn?mGee{&@Y7(7*;vEe2?e1 z8On-S4myz_+I(1|m}rtZ5RJ2#IirjHfhljAry2A&-tEV3dMa=tz!G3P-xvxV#8yEU zOd}95t^xw#@om^fBS3@iP%-rl?P81y-%p#eg#{6laT&fP{#Z1uh;=$<2~NLwpG{1y zHJAu-<$CSHI>(8WtusH_ph^yDl!LNVDbi2c)~sOK5iq(60Lfh{`mv%m;P8b&_ooPQ zDihQ(G(&zcf|Z4y!}8!V6@JFz>Vy+Vp>_7ZR|%=5v!`8kYRay^mOKdUTmk*i^6t+kJE3x@jpF%IvG+- z{F7P~*!5gggDt`Y;UC&`QcJGOsmAGfb|fB_@01cMyPwXRX457EG4sOm#xtp&;cl|$ zB7JQ|Ti9sEPzhPA3IOe8g8~9zTm<(fIGrOJ>=5lupN_-#m3Ya6oy1-nWzN8G2w(|F zHw~r;0@ypcNEZ&AkBGf?A0_HPN#Bys`#;koHH&b!zq&80o-@g>Lp_{BZx_V4wuK1j z<)Dd&+!AvAzOFCqgunbcT~D0>wTYn);qn{@Zog#xkv7g_ZOXA{}f&OX8eKGTc>_;cSXxEkP<)&ek-n*9LVI?qnQ<^@SC7k&-=F4FcTLye-oZs6)0;8 z7xuzmwaQ;RWLkATUB#uB`NAA~$Fpl{Z?6x43MLg6T5A=l^~ovx#HO?t-})UKs8%X~ z{aP``NS|~8?OJk;))#YJMzDdIXfQ{~bAK})?)5Lf(Gv$dR%nXBB4&=dFSywiHs=2P zw{x+>(8(g?LqX~J$ukO*Wx4$M6=XH_)Vd3#{M+XqH(&SJ_^*MlKHVa_iukUk>rO?%qTBo0tDqJUMq^ zBs7Hzh~9`;SKXUc9+(%6d;jtjZtwRy)9X23C36y=JijVCH$TtPvnKNx`jN_u%hXvc zaxAEAs*z~xv;9yEh{eLiO8%$U`w zlpVCC)j32hr5()+9IQ+s(2b+ww=SL8W9L)ozOM+xsSb|{$XCs@ETZ~gg7l=z^2Sg& zfHQLJCK1tIL`s=PlEk@-Xi0~j;?pO01bR;aJ>-|R(@$9VpRW9y(>l?A#idEMKKy#$ zs`k_3ZsBl`-*v#%`+Ngu+zCDlxf^qi9`BkbBv{y@#}}rjiL0^i#-rzWZY4Jn3;d|~ zIii?;bDfLs$3#noeG4O{Tj{Sjw+o&tmskFKGHJTj;q{ezj-S~L_|y5rTKKzNkHbH@ z-I!d;`dGSUyje46*J*|`*H@y~dKv#&^>XPit=1p>hmeij&e^;TXA{8f&JYyyIYwex zt1?=M28}W-XpY6Bgb!ISu?hr->f+wkX*rV}A}25Cy{Z!~>xPI}D>t&2#-%0{A?$<1 zX17{mJ>AriMqPJJ@z_E8M*DE{j!+pHgB7mRljEpnC?Z;JSE%}kaI)|^S0TiwuHpl-2@U4k=xxVs} zT%X?&|G<{dSXwqM{(hzo<%v)WHiS2*oMxEZKK?t^p?-h#4_0GVv-nv)U76+iS^4lS z>L$pBCBq4#vumekwcE>LXHdSvlFJOI38bC!feRQs=Ei~)Rcis&^xWs`d+sLy*EBG? z7xP$Qww)I4Q&FBiZ(y)FPp7iPew!Tin>iA+(sZRDv};7!tB7rENUA=l_S5<-&IsHg znRp13C(YsAh~*)QjZ6>7Ql#ydHy{6_{v@z9wi*HBy_9=CP<`UjCX_`1AajXk6Hr$o z%T7-*S#)I?V%I)P4~`gl0?Th;%!$Y!=+Q2$Yr3J#?V$Hm=gooPs7r9u@9)l>FK7Nv zbaq3&vH;M`;NEHK*cpK7vRG7&t)uPc(+r;5ZCwSDIf|oXD~e6DtLK-#9Xf2j ze?KWLsuEv3a}z!{bX2`Em@Tz7x8(tNy$aT6>>>{376}m%yg)y<%!(gIK#?uV|Dre) zVJGCnNx2J|ait5gYB#d?qAMlu4pmJbR=X$6qkdb(CF_)1Ld7715uUw_W`x&Igj0Hq zTv-CTIRbB^*C^FkWa-)13+s~=FGt%a3$$1_8WWajOi1Yx<=To^GmxTjI8NYl)mQWS zcwfKDz%E_2RRAkj1S4BLtDwfXHgdiSn&~NGi3pQbv7DgyfiX2trg+4G-cgTmr9Ulg z0kBhc=W5Hl8(2fOd7hWFR?U&uJ~rK`mn5ueT(#rcXI|J6Yt8`TM%In5tA zgV?@-)Bj#$DX;MAsm~3dx9}00@6`XDACUrEExCgK$#hrYTiD}@Tc0p*zp`qpF53i; z6Y!C#^{0B_L#eSBnBz$=vkWSID#Tvu_8?asR`ZExoU}(sUInu*nQEZLS%sx5pn=%p zOv<+SX_Z79-!dh!p0>rCZ5|h# zd(Cl^obAJ2?74UIJBk}!@|u9_G+CZ7Vs%90=&Tgu)bSE1<^L<{JmZ?!!mU3E0YfMT z2r(2ffM5tkx^!s?9TG@FsM3W{RGI};Iw1t4S3!y(Bt$w0%8@Qj0U<~cL`CVAV?Vab z``!=t+kBnb^PAawJ!`H1P>{5b1dsw~t0Te%q;mXlfC&0Dq zG63NO0NepAbSMB1>>fpD5h-w$Eh-|%ppVWIR{V52-OcXMDrQ;kB|dN{|D=6)4=lHi z*22^K2K^7lcu&z0 z-mfvWc`n!D#*roPa@6P}lGr#IlP@d7B1>4a-{f)mMvvv~fQ z|1aqRV=4rix&Fm>B=u`CVq^gRPa+tVQFh_#D|H#5<2NyGBBdpKL07Xg_}jKGsKjO^ zEg^Ukek!$S-je^J1Mi19lx0!<9XqgX&X<;u@fTr!e$_ zZ<3IJ2$(}0!s?*?0FNh0rT~QpZt6c?lG`EEM5omr5fB2@lX&t?062WMXVlk@y*oX% zwwITyLROjocY729tOuw=!hI;A<_PpJL)^*5q>4Ll6aQ{1TW6kO=-?~ zN5HHqa`gN0+v|)vLBxO`7R6)oD7nBiM5bfmC@)*i+brA?{aV3I6VKQ2FYThmaj4Db zA!~`W@{al<%Ma7htC4zlANu=?DFW6q62^rKe_R=y{THMpecmf65!|Qo&jjc69_m;6 zlpL6#_0--H7A!x^vla^V9B;ST#HIz7Wj=v3)wuO6v7q7*h7ADNCLxuAJttwdcO&W^ zt~|=zxVWeLC^p?E^U$q*`*VIVi(|N(W}Gg3AT=XuhDUGJ?^u`|LROPm^45Z{eX9^! zlwN}nG7A)(b=E&7+D<~A+st{WtXwM*>-6A;A)mtHKgl+-Ff{#OgvtvTNV8xyTqv3b zO|bDnmLF&n^$FQRRH7_FhXu>KJRW=kFhx@V^%-@{)0d2xoepDLo}wqb8HtaswYjEO zr&ZUAhz)tos^4(`4KV@|cmZ7pL@l+53}lBfEM1Gt-JN*DjO!8lTia+rJ))8J3(m+h#;qZI@@46xD~gpBoy( z3C@v5NM`bMInaeLKxxZCKU>1GBRE9Z_t$?uO4@Z5L8S8t+kiR$h5|8BpY!QxIyRx9 z_c(2bC@~}s;WY(q029$Yn7K7cJ0WX75xi_P^^{ot02o2<@8_$kPo(puG8&Vv5bKD` z4U=HR=)sTRg+=hX7&xB~j}}YGj8h$f83wRHM@+3Y{0}sYRO-r}l4z$&_1Mz`e$-B6 zb=eq9VQ@QP##bx?DuPtOGZPL9!Tl^%fOTnXqIqjVm6Uh`0*vPCN2{k6K;D=p+=d4< zX9E0i;Y5N`=QEFCTQVe*Oz>)c7I??(42XEjF9BlGA#O88@`vW@IF(;$KDcnu zGq&f^i5j%U(m{Za{oTGpD|_PHqk&<&v8t4iIpHP|wkY3gMuUD;h|e-{mJNjITL_hm zC<@{;i#zvKf&tNK8TM(uNgy)KYrOzBUS*uRl8Z3C|{8( zn*?O7WF5|EDjU({>-RQy8>1%FcXlt$rwD={3=i6_%xLd^J?HkUSOuO7%Hajq=(PYQ z9=4ByPqEhfQ#60&8TKb?0y38$?CAa$BATWCzGM`5?x79P@**c+r;g-8(QF{xcRUK| zZ9KPv?|A7^R6R9ye5SuEv^ax#zvsI9VgEmJnT#(R9MSS&%_(xk+zzgJ^JiH_#LZ6+ zfBGedo)hNy;5UVAncebitrFa4=d10}lnYL-CM1Zx$*sn%Pq8-d>GM& zfD1s!#n)uI?aUNP!b-=?RCQO&WuusprRI@!_kB1Sre2K^DcbHd`#hTBO6Esto=MDB zX++p~_54wOOf~!R8Ta6L1~?Yv)ZM zZ?#zCQa(c&&!hO$|DjB8w_ol&vHd(p51gC~LQ*{)5@n7_Vn$b#bywFrjsa^Yf{)Do zeY-y~e%83J=Sybaw>QtOx1PO!=0^Ru-E$N2%mW1W_XSCjfxFu7np*tP%Kk!|=_@kZ zF2efyLj|u5I1m4x+LTreda-)ap_@z1?3oyOSN&Bh9KLGr@_X-Q1|&YqR3rS2z29O? zJm>WLtCOIAe+Dv}i>;Q>_8o`KU(5QGLK+4KI^x#DwNi5LZKQl%FE*}uTd|oor8jxh z{-7HqgpP?hHAw;mSxOWX-B$+N);<^)b^)i@sH{t0z2l>lj9nM6g6_z8HDE}D{^KR| zYG=p=`39^K6xfmQ&HoF1KF&s-^f`%Kg(mV%k2Nh?b?Nxy=*&L+oiJ_IN6IL=( z2Rj0}mbE_}N72q+?3Z^mZDC1SM<8I!L#BX_75F?&PLOie~G5-j(;8Ng>NdVtu{G+JT^zi6pQTnk=ot60XKi}<*zWgr5 z+G8b+)Mlgl79bxQ-R3-L=NH>lL28Z2L4<}K??7w-pbkuZeBdm}XO>ue*{GQe6hKeD z-~asLoJgyipQiRVDUWVSGnCTV`>grQ8RF4Y@7mcd@qs!Pm&Fpn)y~!t!Db*>68a$C zE}hnOwodTxUoT|phjSiRjCP`t0Z{8pQz2=^g6NmXJM$3Vq@>hwYmwj8zUA}oT!R*z z+3dI+k`P@JbvAIsr|!>fHJv+% z|Bj*Uj}JkOmZ7oV31&gdJRH7}$2YBzpdN%aPT4@oGOV;@?89t~grpJ_@^VY{fK~>O zu&*}~-;@`&4cP~l?W_B>=aybiP)*@Uumg^aika(TAVhbOSpr6~4x8wze34q`$NgHv zrID>t_SGRVxIzSRhp%Pm=V%xmVU6K3VE^k&NC^2q@j&2UvwtV&r-BxVNN{#`aw6Lk zNsdlLlCy<5&eGZSptpfUBsvoa6e5Mz-y(dB*biO5bV zS@J=za&1Gx{Bnk$-7S^2;4cdC_}%Ss(4W_f#j{U8QEvKc9wH-L~8&ouF#$dR)7-8qF=Hi;2Jp~3!L6OdJZ{}f-LZ^Bw{Z0cn&7X;& zB|2t=HFl)sp`FBaQCBZq&KsIV{{-`-Te6DXmokGpmbF%F(GZ=)P`48~C#X~{cvWo~ zevlA(Q*=gVSkeG@Fx6SdX$Rxr7*K%w>f=wsnJ7);K0DgtArc09b8=P0>I(zG<^``U z&lYRTH~P=;W!Ada5S&2MF~7*u>~j^cBa{iFo6{O zv`oRNK8cB!*YP)$s9{fnmAqQ+7uu3E4^Tt0EkD1XR;JE-n>2aJZ{cTu>c2|45ISid z!f<(F%E@IbG6Nqql9Qq>24HnWgzuvb(aNwB1(cOMAaqmeeb5nuERUod-PQIRoLhaZ zqLpYsdAqA!aS`p8<%e}g5S47n4VW~X|7{Y57{@P#;0v!}f6P==?V@AJWSY)?iCgFZ zpzX*taRt#Oid~gBc6Xf8fX$;az+ zLeDUoSe^F;-6YJ`1BJqtz_(Ex>GmhANneKdB%5Jk$Do+f|cpk&dhld+L>$`z|^T ztz!}5_^Nl!TDmTF7pRY&$F;ip2>8W(ev1}4C4-HO&~3QGE>4o}L%c1SUi}=!-og^p z0md_RK9xi9-j7vf$59#Imfq#lzVf$@-n@4#w)?ITGDOS~0-XCBa;1&h!9cqUP^gFz zNewzV%a+Xc>08z;T_~xF-+AVv@oJ`14B0}cA%fy5yHRqm{EB6xAQwrs0aUExz4zY6 zrQPbl$9A&Eq)(h?A)^R5elUBz!DaE0Szv|M+ptmlyiIE>6X{? z`UI3R!iWXzess@H|E|xTt01I3y2ChC@V|nw!4UifsPTFPiywU*qHO zLw>#GuZ2!z^HuZnHD&ilnV+h!L>MHD?YN@?bhA?p81F8e%+nUV{1l;6HL9_k6UME) ziT72N%s=ilq;#p-4)ccd>9}};Fx(4$26K&0ToEH!-wo;-B zp&0*a9_>yB-{+8nDFus42(@8h8H)^O2^@~cUf3*CI8^6q@wfmr(*iKkeN!fo(uT0x zey3O-VN;M(Z{FtX0V{M;9TGR7(qiDZ>2x&BSCYLB}O$ zwH8xfqBK)~rP}zum+-xQob>i%aOBte3^#pc2B_qTT}&26FjGB*3A)3L z{6+ycyFXcnD)eZSmjMCDc9^=c;dy4E#aXaSmxBIid%a>L&M=6I5>32h7`Of#ELBr- zIKP&(CF(L#5iD+T{A+6}57N3fXx6;aWBso|=wIQ%>#$A;6O z)G1QiDGw4v7&OKu?778Agp}?~E18_Ye=(9T?+SV6al`03Rz*owUcD;pdg&F*J7{s7 zc=lv430ng*!&0%}5%LB>`cIn=dzZxCU3Pd^1D#S0 zt)(h;%fal{k*gmc6=Mt_L<0GUOu7(mi}V*PBiD5nMat-V7kI@JHL z9~ZiC7x$sYE2{=0M-6?Au~vc(v#hj5CBR zvXHOBq{w}WuA{I^49?eVIk%nrczMhele4cA9e~IPx+*;hBiuIl`AWifI-9Upt?c!7 zNsJp53&JG5!-tnD9XM!xt*gQ-&BS^D8*oRFT?sl_ST0l+AHTYUyGteC#BqzR{Xn8x3_80$pZ&?W{=fd zFA9!#3WwO?It)7Gy71y~@hnF(^BxH|OZMyzSs^xoKjxN>vKd(g`oQPgj|7yqBG<%> zJx{CT7jiUyIkcHC;avnsd9Lrz~Bb5<#Buaor2LNWbe)Uo8x>7l}afj>=Ejk+cUIiWI|7-#$YcNl}OZ<3wK(aZ#STK#?~HA zZQ>QuC!FfyZW{MwGTkhTZ)}mTpml>g zM?|^|a+@^b&Y@*uY{_9gn$fzU-@@`iPH%B(Yo5LOfK1t7r+2{3INR`2O_G3_CZx=8 z>a*O5+4}^`0(W_?v#Q0TP!Du{MHa2hg(&pK{Gg`DV0nGSaT_tLY^L(9IalU@CI4E| z(y>XGSMR%@#*#_t1z3%uj01@OYHLZ@S+{)60J(}Pk?(G0!XY^YUmUQe#j{%^%VUA! zQ@)?!L4ZwrLntW+S4$S8yR$vrK`p~TV(329z7+T+JF9Rc<&FXRYXnc`*3GfrJNk^m z8~4AML}W3YJ)n}HM_w22*Jw0xd$Yp18oe(p;&r=t_Xk2vzs+Y!O5hN}odV$4=hpNp znk&nJiQre|+xvX*Ehc}GJ{2^6f7epssc~nRYu(GMR}&nlEpTc8IP_dEDm8>xkI9*P z!gantZni)K&CuYMszpsrB+EwekYpFL+cgb;)3)m1yz(#x9^_BgxM}d|ZARri#St+3 z-rFO+(d^BsVRd!6!~JSeFEx@#G3IpSY$F{hLScjlvua($Wi$1} z<-2OQ4M{#1D=r>NpmzGyCSnLdfQsTr1(3eFFt?i7f$+xR^ z0tnK`Qu4|6EqBXQZh6boP}&5;4mqFn;BL{s_K5~DcJFqEwDGY{q?|@7hN>d>pt!oo zPH(NS4y2;#_D!4h=y~ajzVX{Tl?vVOj>V# zxCY{i6rAa`fpyCwwqA%UeF?6DiSAu}Y2UtOec?#V+?^k>NCw60?n_oF&R6&)w=Guf zlFAfJof>NWl56xnJa=&-j*dvrLl|FQ$LxVSykXa4BeUR3gEE<0I)SatS#G8ad zZlh;HEg|vkU(*+P%teIcR1&lZ=<{*B|0__K(*IAOIB53(x)roRN+b^|$<>wY>Ovus zDXz{=F0PIwCue8!-;004{@%dhEv>C^7B1Ak^k@SQI|4M1a$)`Z^YRJLWVqS!k;GTE zPv&-^62wms_3y@evC>j^{R=Z05r~R~OPyNOqqkv_TrvkZFzzC9`3J``%(Di-i=-HA z30pOr`O+C_Df3#iW3tjoK3F-rR^w}xm(wMW){qU8l@s!LVN$b*OZyf(&ei|KLW)i) z&y|#q)GT0OjN0AEc^xZCRon8S4x^iZOU8gPF;K-Mp zl0`J#IxdjBiq5=4trbZV6tt*g(J>fFGX!ti`=31VxNfJ!8NJh zc5u1A5vwjKf@OskKytjc;xm=o9l`@86cru+5~bB^oEZZhHJ%eGnSrWBM3jD;iZU{x zwT3ITc7j&`Jj!n=vox~iINgRQMjpw;-{YGS-^%u^co83@Z<#MHlGrbih8jGkVNmEi z-SjUm{j}!!RA13v=_Y+QwWs8l)N1pQz9;6X1`3Xww3BF^|FA$2rP|x~m!PGA%ZCoK z;mP2~=P!2I202z{aZUI-{1$)y1(TLqP$~}V$CMtjP8KU-K$D#_w$(($xK)@~Z!#7` zG_xY;X-nAnG>ZrisWXqR=pH29JDw5M8rIb(!(8b3Ym@n^5{;BDIQ?hWYi&Ft8q2diJj2Z-18>I`*r$F+iV z9h+SmS)9PHG+)-7j??=}=ZAfPR5k>^{v*`EDu2*TZ9d49QmHBuzSfcsWrRZErO6PEO%XM?>-nl@4bdv8aCJ4{%!pELXK zGoyDGTejx;u&kOL+?}MXU=eYp4hBrvFYhkB1Yxv`0wMCA_ojj=(by_Nm-N#5SUgfi z?xU(Y#iH#&)M2??t(PcC^+(&^k|j03i9^O5q2__0X-1+v);OmIn0TBHvwyw4SG zOzC8W|Mv?>(OiA3H6PV8{zIzMu<+ey!EKv}2cfsPWd*sZLE`QriR}1Oj&_M>uH9j?#O<~#``wdE+9DGBC5_~MAU#-PMdSXAWf&FxEIEUCxl1UVY6W#xQvETn8hQ!5=ZU5w0kFn`^3C+ zld!#u5OjWp&X7y$hl@7L!n6T8v|E6wng2!FEJ!JjlHpj_2@-oQiw&-{0}tR@4dR=wL_RqU;1SjYzCHM}1c3QN~#I+a%{qXyqT_ z6g7ua**iwGd;bZRj z?6lvMOudcC)2H7kv`OjGF8+Sgb(wPtuF)6{u9H?l!;#5S+FJ;D7S~g@j5b(?1z2W8 zZ3e#ap%^33%|rRc+FQ>POigaZ_L56P{k0dRw(%}omEVH)dVBNd-e3*G#ni#!1_O)X zNARxfD|GS6(K_yrPs&le*?E<5hL zjh2Vj;-Dj4v|R82tan(g8X+6@d8>8*_gd)hH{6xhEcpX>zgrV9DQo_DFw#&a|4Zwk zgglY#skdo&2SKnuHWj~A6_UpdKmOJ(vJZ}W2AL3COKh%x@j(bMz4Z9OT6o{zFEN@+ z7H6+gh*Z_VFu{5+8?6KHBkdU=^`(z1cCvh^{C@i6sC=xoW2N(3=dUZsge8J`eDlW_ zYuZvLPpk)>N$WlxNwo+y%cLM?gryxN{D1GX9~3)M)ayE{PY zNICM&lz`fqr=CsSi(mmTS|wo&=xaVH8M2v0F=zp)=;Mvefi`ppbv|u$CPU`+rE2J9 zUSCt^6GR9QyV&#=Q60C}4c-#fPV&r#^lPzk63f@Az)e>gxDFc~rKjV|rKFx%ZLF zDf9PBvsP?geiV^x{j@f>e?HiC+T=y#=%w+XhC$3olV@4PM{}Nx*AR#4vEf>G*+M1J zgf6`%b`vauXDRe?y*-0@UZ|P3VA?MHU7@nh<#P;QAIa7NE>4=t27G&`)a)KlT@fV+ zs{Qy=pF;#wvks`V!?8LaUHXhcC551> zyl8)b1V6%A=wOgD0|INd%p` zDn;IC1IhO5<=Gm|<|oKm99N%NJ$|FB=tBOtv^3TH6ixJHiwB{?4G9jSDqw#;vvYS! zOmETnuu^&F-WB$?wjJh7sRLR+*Dd1RHEGWza=*Pig%6DSby_I?=IMGxqx^sGaWb~C z`l7KW|KW~mObdMe5~f?VXX)JWuyR{6+d4k()8j{%yV_irPzfJCMGid?`z-LWB5`NuFRdDUJ&2tjs)UhH3&DQJBo?eJ5tw0%@2FP{XhL-J(vFx_VA64q3aWEG}+e zdC7v=;choBs4L+8;-C(;ZML6~xcKhPP0fQlE0g~Z(9;`16&O)}{~kEk?AzxAiD5s? zs5tSW{hfAeQ}IcI*PnF@!#|{FG4fCbG?TcRWf$#n(1UGerxgHCGCayIQ{%DkZ+*A& zBXX~hQjg+UGSI8lV(k3PcsTya^DoS5vf#g1Ji&)F2Rh>aQ za$P8U>c6rbMLtiz6o5DO+qAoKeUdw#?!0nB+@x~n41y%8na9RbbL z6I70h($iuKMor@@?hdF^uI||0QlNAik7Do#gCPEmnVX@q52w*`p5fAF!0r7KpJwMD z#!jl**PHg4TN!&FjZf%YU)yf(dr|vhWql9~wLa!~_WKXa$45J}QdijTgLk97Xv{bz ztgplYGiY|F^*%YYAL_KO-fy;>9qIM_)!5j7J3txbbHiYNI{$}dy0EVHrUj_;!Djcx z4v)F3Us%82{59+hJ7|YXcvj4wR#Q9a7DW9=m(9w;582L6s1%k$zFzRmZ|jIkJ(U(e zX6W;J4EFPo%h^6vS=Vn7JALIUy)gl|XZT{`rtkOeOyBtLvBa4l7d!PI=x=yedJLUR zE53fjApisNa@N0O^o4e%Ow&J?Ki856THk!v_C>jtj`rceXVJHkONu7~9cf-scEUe* z_t0+9neqmR)pxhIoTc>)6SKTJAuR{#J2 literal 0 HcmV?d00001 diff --git a/t/makefile.test b/t/makefile.test new file mode 100644 index 00000000..d4aedf80 --- /dev/null +++ b/t/makefile.test @@ -0,0 +1,32 @@ +RM ?= rm -f + +results_dir := $(test_dir)/test-results +trash_dir := $(test_dir)/trashes + +test_options := --executables-dir $(shell pwd) +test_options += --results-dir $(results_dir) +test_options += --trash-dir $(trash_dir) +test_options += --executables "$(executables)" +test_options += --objects "$(basename $(notdir $(all_objs)))" + +ifdef V + ifeq ("$(origin V)", "command line") + test_options += --verbose=$(V) + endif +endif + +tests := $(wildcard $(test_dir)/t[0-9][0-9][0-9][0-9]-*.sh) + +test: $(tests) + +$(tests): all + $(Q) $@ $(test_options) + +test-help: + $(Q) for t in $(tests); do $$t $(test_options) -h; done + +test-clean: + $(RM) -r $(results_dir) + $(RM) -r $(trash_dir) + +.PHONY: $(tests) test-help diff --git a/t/t0000-help-output.sh b/t/t0000-help-output.sh new file mode 100755 index 00000000..fcc2c783 --- /dev/null +++ b/t/t0000-help-output.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +test_description='Parse help output of all executables. + +Each paraslash executable supports the -h switch which instructs +the program to print out all available options and to exit. This test +checks whether this help output looks as expected.' + +. ${0%/*}/test-lib.sh + +grep_output() +{ + local regex='^ -h, --help' + $1 -h | grep "$regex" +} + +for exe in $o_executables; do + test_expect_success "$exe" "grep_output $o_executables_dir/$exe" +done +test_done diff --git a/t/t0001-oggdec-correctness.sh b/t/t0001-oggdec-correctness.sh new file mode 100755 index 00000000..01260e5c --- /dev/null +++ b/t/t0001-oggdec-correctness.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash + +test_description='Check correctness of oggdec output. + +Executes para_filter -f oggdec on the test files provided by the test +suite and compares the output against the output of the reference +implementation.' + +. ${0%/*}/test-lib.sh + +test_require_objects "oggdec_filter" +missing_objects="$result" + +test_require_executables "oggdec" +missing_executables="$result" + +get_audio_file_paths ogg +oggs="$result" + +for ogg in $oggs; do + if [[ -n "$missing_objects" ]]; then + test_skip "${ogg##*/}" "missing object(s): $missing_objects" + continue + fi + if [[ -n "$missing_executables" ]]; then + test_skip "${ogg##*/}" \ + "missing executables(s): $missing_executables" + continue + fi + test_expect_success "${ogg##*/}" " + $PARA_FILTER -f oggdec < $ogg | sha1sum > filter.sha1 && + oggdec --quiet --raw --output - - < $ogg | sha1sum > oggdec.sha1 && + diff -u filter.sha1 oggdec.sha1 + " +done +test_done diff --git a/t/t0002-oggdec-performance.sh b/t/t0002-oggdec-performance.sh new file mode 100755 index 00000000..d496a3ec --- /dev/null +++ b/t/t0002-oggdec-performance.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash + +test_description='Measure time to decode ogg/vorbis files. + +Executes para_filter -f oggdec on the test files provided by the +test suite and fails if it takes much longer than the reference +implementation.' + +. ${0%/*}/test-lib.sh + +test_require_objects "oggdec_filter" +missing_objects="$result" + +get_audio_file_paths ogg +oggs="$result" + +test_require_executables "oggdec" +missing_executables="$result" + +for ogg in $oggs; do + if [[ -n "$missing_objects" ]]; then + test_skip "${ogg##*/}" "missing object(s): $missing_objects" + continue + fi + if [[ -n "$missing_executables" ]]; then + test_skip "${ogg##*/}" \ + "missing executables(s): $missing_executables" + continue + fi + test_expect_success "${ogg##*/}" ' + test_duration oggdec --quiet --raw --output - - < $ogg && + t1=$result && + test_duration $PARA_FILTER -f oggdec < $ogg && + t2=$result && + echo "oggdec: $t1, para_filter: $t2" + (($t2 <= $t1 * 3 / 2 + 100)) + ' +done +test_done diff --git a/t/test-lib.sh b/t/test-lib.sh new file mode 100644 index 00000000..e444e578 --- /dev/null +++ b/t/test-lib.sh @@ -0,0 +1,292 @@ +#!/bin/bash + +# paraslash test suite helper functions +# Licensed under the GPL v2. For licencing details see COPYING. +# uses ideas and code from git's test-lib.sh, Copyright (c) 2005 Junio C Hamano + + +get_audio_file_paths() +{ + local suffix="$1" + + if (($# == 0)); then + result=$(find "$test_audio_file_dir" -type f) + else + result=$(find "$test_audio_file_dir" -type f -name "*.$suffix") + fi +} + +say_color() +{ + if [[ "$o_nocolor" != "true" && -n "$1" ]]; then + export TERM=$ORIGINAL_TERM + case "$1" in + error) tput bold; tput setaf 1;; + skip) tput setaf 5;; + ok) + (($o_verbose == 0)) && return + tput setaf 2;; + pass) tput bold; tput setaf 2;; + info) tput setaf 3;; + run) + (($o_verbose == 0)) && return + tput setaf 6;; + esac + fi + shift + printf "%s\n" "$*" + if [[ "$o_nocolor" != "true" && -n "$1" ]]; then + tput sgr0 + export TERM=dumb + fi +} + +die() +{ + local code=$? + [[ "$exit_ok" == "true" ]] && exit $code + say_color error "FATAL: Unexpected exit with code $code" + exit 1 +} + +error() +{ + say_color error "error: $*" + exit_ok="true" + exit 1 +} + +say() +{ + say_color info "$*" +} + +_test_run() +{ + local f + + let test_count++ + eval >&3 2>&4 "$2" + if (($? == 0)); then + let test_success++ + say_color ok "ok $test_count - $1" + return + fi + let test_failure++ + say_color error "not ok - $test_count $1" + f="$o_results_dir/${0##*/}-$$.out" + if [[ -s "$f" ]]; then + sed -e 's/^/# /' < "$f" + else + sed -e 's/^/# /' <<< "$2" + fi + [[ "$o_immediate" != "true" ]] && return + exit_ok="true" + exit 1 +} + +test_skip() +{ + (($# != 2)) && error "bug: not 2 parameters to test_skip()" + let test_count++ + let test_skipped++ + say_color skip >&3 "skipping test $this_test.$test_count ($1): $2" + say_color skip "ok $test_count - $1 # skipped ($2)" +} + +test_require_objects() +{ + local o1 o2 found + + result= + # if no objects were given, we assume this test is run manually + # rather than via "make test". We won't check anything in this case + [[ -z "$o_objects" ]] && return + + for o1 in $1; do + found= + for o2 in $o_objects; do + [[ "$o1" != "$o2" ]] && continue + found="true" + break + done + [[ "$found" == "true" ]] && continue + [[ -n "$result" ]] && result+=" " + result+="$o1" + done + [[ -z "$result" ]] +} + +test_require_executables() +{ + local i + + result= + for i in "$@"; do + [[ -n "$(builtin type -t "$i")" ]] && continue + [[ -n "$result" ]] && result+=" " + result+="$i" + done + [[ -z "$result" ]] +} + +test_duration() +{ + local t=$(exec 2>&1 1>/dev/null; time -p "$@") + result=$(awk '{print $2 * 1000}' <<< $t) +} + +test_expect_success() +{ + (($# != 2)) && error "bug: not 2 parameters to test_expect_success()" + say >&3 "expecting success: $2" + _test_run "$1" "$2" + echo >&3 "" +} + +test_done() +{ + test_results_path="$o_results_dir/${0##*/}-$$.counts" + { + echo "total $test_count" + echo "success $test_success" + echo "failed $test_failure" + echo "skipped $test_skipped" + echo + } > $test_results_path + + exit_ok="true" + msg="$test_count test(s) ($test_skipped test(s) skipped)" + if (($test_failure == 0)); then + say_color pass "# ${0##*/}: passed all $msg" + exit 0 + else + say_color error "# ${0##*/}: failed $test_failure among $msg" + exit 1 + fi +} + +sanitize_environment() +{ + export LANG=C + export LC_ALL=C + export PAGER=cat + export TZ=UTC + export TERM=dumb + export EDITOR=: + export HOME=$(pwd) + + unset VISUAL + unset EMAIL + unset CDPATH + unset GREP_OPTIONS +} + +can_use_colors() +{ + result="false" + [[ "$TERM" == "dumb" ]] && return + [[ -t 1 ]] || return + tput bold >/dev/null 2>&1 || return + tput setaf 1 >/dev/null 2>&1 || return + tput sgr0 >/dev/null 2>&1 || return + result="true" +} + +parse_options() +{ + while (($# > 0)); do + case "$1" in + -i|--immediate) o_immediate="true"; shift;; + -l|--long) export o_long="true"; shift;; + -h|--help) o_help="true"; shift;; + -v=0|--verbose=0) o_verbose="0"; shift;; + -v=1|--verbose=1) o_verbose="1"; shift;; + -v|--verbose|-v=2|--verbose=2) o_verbose="2"; shift;; + --no-color) o_nocolor="true"; shift;; + --results-dir) o_results_dir="$2"; shift; shift;; + --trash-dir) o_trash_dir="$2"; shift; shift;; + --executables-dir) export o_executables_dir="$2"; shift; shift;; + --executables) export o_executables="$2"; shift; shift;; + --objects) export o_objects="$2"; shift; shift;; + *) echo "error: unknown test option '$1'" >&2; exit 1;; + esac + done + [[ -z "$o_verbose" ]] && o_verbose=1 +} + +create_trash_dir_and_cd() +{ + local trash="$o_trash_dir/trash-dir.${0##*/}" + + rm -rf "$trash" || error "could not remove trash dir" + mkdir -p "$trash" || error "could not make trash dir" + cd "$trash" || error "could not change to trash dir" +} + +fixup_dirs() +{ + local wd=$(pwd) + + test_dir="$wd/${0%/*}" + test_audio_file_dir="$test_dir/audio_files" + + [[ -z "$o_results_dir" ]] && o_results_dir="$test_dir/test-results" + [[ -z "$o_executables_dir" ]] && o_executables_dir="$test_dir/.." + [[ -z "$o_trash_dir" ]] && o_trash_dir="$test_dir/trashes" + + # we want alsolute paths because relative paths become invalid + # after changing to the trash dir + [[ -n "${o_results_dir##/*}" ]] && o_results_dir="$wd/$o_results_dir" + [[ -n "${o_executables_dir##/*}" ]] && o_executables_dir="$wd/$o_results_dir" + [[ -n "${o_trash_dir##/*}" ]] && o_trash_dir="$wd/$o_trash_dir" + + mkdir -p "$o_results_dir" +} + +parse_options "$@" +if [[ "$o_nocolor" != "true" ]]; then + can_use_colors + [[ "$result" != "true" ]] && o_nocolor="true" +fi + +# Each test must set test_description +[[ -z "${test_description}" ]] && error "${0##*/} did not set test_description" +if [[ "$o_help" == "true" ]]; then + printf "${0##*/}: " + sed -e '1!d' <<< "$test_description" + if (($o_verbose >= 2)); then + echo + sed -e '1,2d' -e 's/^/ /g' <<<"$test_description" + echo + fi + exit 0 +fi +fixup_dirs + +[[ -z "$o_executables" ]] && o_executables="para_afh para_audioc para_audiod + para_client para_fade para_filter para_gui para_recv para_server + para_write" +for exe in $o_executables; do + export $(tr 'a-z' 'A-Z' <<< $exe)="$o_executables_dir/$exe" +done + +test_failure=0 +test_count=0 +test_success=0 +test_skipped=0 + +ORIGINAL_TERM=$TERM +sanitize_environment +create_trash_dir_and_cd + +if (($o_verbose >= 2)); then + exec 4>&2 3>&1 +else + exec 4>$o_results_dir/${0##*/}-$$.out 3>&4 +fi + +exit_ok= +trap 'die' EXIT + +say_color run "# running ${0##*/}" diff --git a/web/manual.m4 b/web/manual.m4 index 946b9d09..5926b555 100644 --- a/web/manual.m4 +++ b/web/manual.m4 @@ -280,7 +280,11 @@ might need to tell the configure script where to find them. Try ./configure --help to see a list of options. If the paraslash package was compiled -successfully, execute as root, +successfully, execute (optionally) + + make test + +to run the paraslash test suite. If all tests pass, execute as root make install -- 2.39.5