From a094a8fb732ee5b4e785b02ebed7ee185b1c37e7 Mon Sep 17 00:00:00 2001 From: Cameron Date: Tue, 8 Dec 2020 09:10:26 -0800 Subject: [PATCH] Thumbnailer: Added option for on-the-fly conversion to WebP format. Example: toImage($src, ['w'=>'type'=>'webp']); --- e107_handlers/e_parse_class.php | 57 ++++++++++++------ e107_handlers/e_thumbnail_class.php | 19 +++++- .../tests/_data/thumbnailTest/image_16.webp | Bin 0 -> 39642 bytes .../tests/_data/thumbnailTest/image_17.jpg | Bin 0 -> 6088 bytes e107_tests/tests/unit/e_parseTest.php | 52 ++++++++++++++-- e107_tests/tests/unit/e_thumbnailTest.php | 10 ++- 6 files changed, 110 insertions(+), 28 deletions(-) create mode 100644 e107_tests/tests/_data/thumbnailTest/image_16.webp create mode 100644 e107_tests/tests/_data/thumbnailTest/image_17.jpg diff --git a/e107_handlers/e_parse_class.php b/e107_handlers/e_parse_class.php index 0d2a5cbb7..1d6e611b7 100644 --- a/e107_handlers/e_parse_class.php +++ b/e107_handlers/e_parse_class.php @@ -36,17 +36,17 @@ class e_parse extends e_parser protected $e_bb; // Profanity filter - protected $e_pf; + public $e_pf; // Emote filter - protected $e_emote; + public $e_emote; // 'Hooked' parsers (array) protected $e_hook; - protected $search = array('&#039;', ''', ''', '"', 'onerror', '>', '&quot;', ' & '); + public $search = array('&#039;', ''', ''', '"', 'onerror', '>', '&quot;', ' & '); - protected $replace = array("'", "'", "'", '"', 'onerror', '>', '"', ' & '); + public $replace = array("'", "'", "'", '"', 'onerror', '>', '"', ' & '); // Set to TRUE or FALSE once it has been calculated protected $e_highlighting; @@ -2609,6 +2609,7 @@ class e_parse extends e_parser * Generated a Thumb Cache File Name from path and options. * @param string $path * @param array $options + * @param string $log (optional) - log file name * @return null|string */ public function thumbCacheFile($path, $options=null, $log=null) @@ -2630,8 +2631,7 @@ class e_parse extends e_parser $tmp = explode('.',$filename); $ext = end($tmp); $len = strlen($ext) + 1; - $start = substr($filename,0,- $len); - + $start = substr($filename,0, - $len); // cleanup. $newOpts = array( @@ -2639,16 +2639,12 @@ class e_parse extends e_parser 'h' => (string) intval($options['h']), 'aw' => (string) intval($options['aw']), 'ah' => (string) intval($options['ah']), - 'c' => strtoupper(vartrue($options['c'],'0')) + 'c' => strtoupper(vartrue($options['c'],'0')), ); - if($log !== null) + if(!empty($options['type'])) { - file_put_contents(e_LOG.$log, "\n++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n\n", FILE_APPEND); - $message = $path."\n".print_r($newOpts,true)."\n\n\n"; - file_put_contents(e_LOG.$log, $message, FILE_APPEND); - - // file_put_contents(e_LOG.$log, "\t\tFOUND!!\n\n\n", FILE_APPEND); + $ext = $newOpts['type'] = $options['type']; } @@ -2682,6 +2678,19 @@ class e_parse extends e_parser $fname = $pre.strtolower($start.'_'.$cache_str.'_'.$size.'.'.$ext).$post; + + if($log !== null) + { + file_put_contents(e_LOG.$log, "\n++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n\n", FILE_APPEND); + $message = "Name: ".$fname."\n"; + $message .= $path."\n".var_export($newOpts,true)."\n\n\n"; + file_put_contents(e_LOG.$log, $message, FILE_APPEND); + + // file_put_contents(e_LOG.$log, "\t\tFOUND!!\n\n\n", FILE_APPEND); + } + + + return $fname; } @@ -2797,12 +2806,12 @@ class e_parse extends e_parser * Generate an auto-sized Image URL. * @param $url - path to image or leave blank for a placeholder. eg. {e_MEDIA}folder/my-image.jpg * @param array $options - width and height, but leaving this empty and using $this->thumbWidth() and $this->thumbHeight() is preferred. ie. {SETWIDTH: w=x&y=x} - * @param int $options ['w'] width (optional) - * @param int $options ['h'] height (optional) + * @param int $options['w'] width (optional) + * @param int $options['h'] height (optional) * @param bool|string $options ['crop'] true/false or A(auto) or T(op) or B(ottom) or C(enter) or L(eft) or R(right) - * @param string $options ['scale'] '2x' (optional) - * @param bool $options ['x'] encode/mask the url parms (optional) - * @param bool $options ['nosef'] when set to true disabled SEF Url being returned (optional) + * @param string $options['scale'] '2x' (optional) + * @param bool $options['x'] encode/mask the url parms (optional) + * @param bool $options['nosef'] when set to true disabled SEF Url being returned (optional) * @param bool $raw set to true when the $url does not being with an e107 variable ie. "{e_XXXX}" eg. {e_MEDIA} (optional) * @param bool $full when true returns full http:// url. (optional) * @return string @@ -2839,8 +2848,6 @@ class e_parse extends e_parser } - - if(strstr($url,e_MEDIA) || strstr($url,e_SYSTEM)) // prevent disclosure of 'hashed' path. { @@ -2905,6 +2912,11 @@ class e_parse extends e_parser } + if(!empty($options['type']) && ($options['type'] === 'webp')) + { + $thurl .= '&type=webp'; + } + if(defined('e_MEDIA_STATIC')) // experimental - subject to change. { @@ -3092,6 +3104,10 @@ class e_parse extends e_parser $parms = array('w'=>$width,'h'=>$height,'crop'=> $parm['crop'],'x'=>$parm['x'], 'aw'=>$parm['aw'],'ah'=>$parm['ah']); + if(!empty($parm['type'])) + { + $parms['type'] = $parm['type']; + } // $parms = !empty($this->thumbCrop) ? array('aw' => $width, 'ah' => $height, 'x'=>$encode) : array('w' => $width, 'h' => $height, 'x'=>$encode ); // $parms['x'] = $encode; @@ -4606,6 +4622,7 @@ class e_parser * @param string $file * @param array $parm keys: legacy|w|h|alt|class|id|crop|loading * @param array $parm['legacy'] Usually a legacy path like {e_FILE} + * @param array $parm['type'] Force the returned image to be a jpg, webp etc. * @return string * @example $tp->toImage('welcome.png', array('legacy'=>{e_IMAGE}newspost_images/','w'=>200)); */ diff --git a/e107_handlers/e_thumbnail_class.php b/e107_handlers/e_thumbnail_class.php index d761ae499..cd1ac1bc6 100644 --- a/e107_handlers/e_thumbnail_class.php +++ b/e107_handlers/e_thumbnail_class.php @@ -154,6 +154,18 @@ class e_thumbnail $this->_request = (array) $array; } + private function getImageInfo() + { + $thumbnfo = pathinfo($this->_src_path); + + if(!empty($this->_request['type']) && $this->_request['type'] == 'webp') + { + $thumbnfo['extension'] = 'webp'; + } + + return $thumbnfo; + } + /** * Validate and Sanitize the Request. * @return bool true when request is okay. @@ -223,7 +235,7 @@ class e_thumbnail return $this; } - $thumbnfo = pathinfo($this->_src_path); + $thumbnfo = $this->getImageInfo(); $options = $this->getRequestOptions(); $fname = e107::getParser()->thumbCacheFile($this->_src_path, $options); $cache_filename = e_CACHE_IMAGE . $fname; @@ -479,6 +491,11 @@ class e_thumbnail $ret['c'] = 'T'; // default is 'Top'; } + if(!empty($this->_request['type'])) + { + $ret['type'] = $this->_request['type']; + } + return $ret; } diff --git a/e107_tests/tests/_data/thumbnailTest/image_16.webp b/e107_tests/tests/_data/thumbnailTest/image_16.webp new file mode 100644 index 0000000000000000000000000000000000000000..c3906cb07b15e7aa4b52023b11acc549f3e3e7f7 GIT binary patch literal 39642 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≫PN_?(cbsoc3;&cLQU!#nBOE;nY{eHaO*Ms1boiY0eB0*RovbDgenWp1B=Q$)5H1<_j zVYuSTC6VFLWUc(_=-bi|rf0})%Prxro+o+eT)L1x(Zob;akQ3}V zLh5dqs68dL$(RAi`1yq{2Lt*%jW6E@WEzAftvq+%Qnu| zZAJNJ_@aY-?I%1gObQjrEe-~SMLrB1ohT~z8C^HkYiZ4931yw&?!bbt^k9hc5U6HL zlJJ$o@{6sP?&j>C8W9%BMr&x3QQRUj8RM)f98PnP+dm%Nvp1#`ac~tl_*xa2LX+o8 zB!u=F7xg!Z;1NNdRT_H3)q{?sd16lYg8BG8I{WsKRJ7FN$Oc`FL{z`15d?I8&?I~l z^h$%Ua(zht_kEwiNXGVASCzqkx(oQ>XFY_NzPk0cocxGhD2dPGqf*BuWxFwIsRFGX zUy((f=b#elvkw2JY$UN@hx30`Ls_VG{&aHqtQnpV))2D7T*GrAtA?coHy)PT** zES;wfNskfU7$fm%Gg}1YcA0FP>qk^lC@YPlp_{1Hevf~OGu$Zx`-*b6m#t`5Yt_0e z3P9jP5C99(z%r=3*cr2Iv((&isemiKkHMOwjRg<+O_al`+d_qU?jUOI0fq7G?K#Cl z+IRRu!6IOCqi>R;ZM18hgWuYUk~-(e1vhVBEnqsV@7{vX%ex|9#A>*#n~~qf)EbI8 zkKECfqOq!rs;mp{Qqn}uEHlMiFBXI>6Y_Z-dB>C=z0b{$Npi~yN58yicO00v6vm&AQ7M(;;8%#mG2BaVFV!(z*7N7OJ z=)4{0ZRW|Zy6>U+&AxkDD@968sM!R~L=?#$)ivG7($49NrWW~2q) zQeYwm$TvX+Yd#$hn^l{NfZs}ym4P~6dQ`giwA2G}Xrqp_Pm)Z3eL79(;$Hm2&dHGc z##16A2Q-`B*CoDJn#cDuK<35>`QGQ5(?rT@wi#1Er6D+qm?Bik7(OK5c!(%LVsNgt zGPOGXQK3+b1d6k=WSe>Gq+{H11gE$Z12dAb8QN`H*oEV_v-qLm3wG!KG$Jb|5$N#u zKuU8Y5jwBQmx#-Hjxho@QxRtWkXvQ;N$y}lf)M*ze?V$ocsLcSSNR%Q>rG8D{y~qe zM=Bv2Oj@x~_9Y6$JZga=VpoXy{We7Mz<_~6DTyk)lvN*Oa-*of* zTk0mTC0w)fD0I2{ZC`DK-WBGTLL^K8pFEr5F}j-(FD6eKdbS7d77mvUy4pYBC z1nS3zed1S7t|7H)=iMD51Vg)TS5cjwm(ThX*<*k&8@+B7;R(_+oCm}_8Jv7!qtq$C zW{7GSfbwTTR%x>nWljT!)IWF?f!N{HauY!sWMx=;K6+MWW+23(I; z6uuuzkU6lBZ#uO_bEmFIdcp)ft0}Y3<6|W#DhhIBuA&EKK+KmdG%Z-+1mDHyYa}gv zzFF`BYl{*zq zAh_>>#k|8Y8F|4BStcK8)-n&2^-5m-Q;z|T;Uih~jNIHqHvW;u4 ziY9eX*!`*F$TMiFjyNU78E46hEC^+o|`7#UKb!Y*cn(^Mu zg}r^o(n2JV!{gqdolv6=9<25BBah}wGllD2mt7en?ybnyhtRJLv|<^vd7GL zE;B7h))*Z?4sw^|Fx*7LLKIRUI*TxYm)rt%3qVkj*qAvR4^bciEc5q*4$3+f)f;%t z=Z*NdgqBw8g!ycGaTGlwE=D#PH?-!8o#wdz(ciV)_`+!AAyRoih{Oq$#U2OPcc(82 zdJgrU6(iFnld`Vj#!rhG4dh>|?jubCcI{%+H=u~ixk=z&jNN0$6nX~AdC}XydPJxi z@Fp6)#4LmGf#!%Lk6ajvnbV%j>aPrNq4SnGxi@AouYwN)qD~Fn;vXjht7xRkh{S&s z{527FbB{+z2R~rUcp#(nn>p8N@_O=U-3Gx^%2c;4VMG_UyvV z{jx$kztHx#tmjF9Anr`%-va+-w{_2dpb#aYF)NI6s?`fV2?HL9SX@qjfsS`yT~?)n zJ9kMh4;_OYsDwfzo8C_HUq28rQ?jDH>88cnU>=BVpZDjj-7Zot+%{veKtT>MhOcz=}k@Nekm^JN|+-j!WpkOqx2-V}uVn6f9tZz>5U81Md4^A8{CP!=fzv^VaYCa6X^3z^|b^6$Si z#5cw08h0_)du^`VC)Yfte1^l{XX<|`EZ0)NGdBAIs6oj?F04f_eQ(2^z&&NiDoPj{ z|Bba454W)+DoO1%AiE_$j47C`;@xe)5QB)eC^b`Ktf>2>2sLMDICksk#Z5wq7TXVt}if)z~Ui>5Y&`bLd*!ceHV}-__5wNNIxa0CiJku@tT$c@_FW=k(o}aS#;~$w=GScH_fq45BhKK~G6ngr)X)2YnnIMol{hP&!z7Sw`-6 z`#_M=?A>ccgmL?0ZdU-~n{p$KW64Xg#>6x4b&N`u;@%UjXbSa zYpgs6HWa(g#(&E)sPdoMh6{{!XdVGy+dai~?p<6sn=Oj34e7j^JS6gFq_h7f{&+!J zGNM0{fGxM|H=eLwNi3cZt6d#nMi7W!Y5nNcf~K$2yq~juj|FM4cuYKcw6VYl(?~nr zHEKfy2-&jdvJ0BqDYdg=`r1OL6y%>V069R$zgcc2>5i1jmuS0=K@;Q>b+8n;k{2Cl zPeh@}tSP<c)e*1hh&4jhco5t{7pI{%8HmDP-mLfD_j5mSQxXaOAp#l zOI9kQo7(#dHCRm!sRk4sjNj%@B5YMf76=R znz7JgPQ`tHCrKmSZX3O})%5eNObrbr1$+PPN3o~^v#jN-I$hhj%-EOl_ykb;`gIn& zEP?y5SmA%k=8=R2FJoy!3PrJFiSN%*ILru;O89~rfrZ=$))*YuYRJhwUtgCeu_lQ($?-Mck`H0$a>ofs>{@s!wdx@!u+V;U;H83BZq!@?rME3NSoiW{@-ZIfF|<(m#OdOy$r2mI<8o9I|gfaS^gYe375mBodZXJ(x8B>_X0tpB=aFVw8-lS*N4P8SBwolWrz!q!~3k zFDB|Mcs{6$s%7e2DKIGc$`Ev%^( zY?po3qTUf^wu}EF;<>^mWQ)a;aIiy|9Cw?FA@c(r$&NhHtPC^4mwP;zq-bY4aAbfI zRW=$_5WB{2=nfGQSv0fIrG5Kr#NQ>XBcw#q#;Q*|Vs+scf`eetUbb zBp(M+qI(m;;s3q(B7lu+QwVtH17}0~@e)C{t!!J3_fn*3>76z9LMC@j z)X^odYqGus{n?vt9>nFZt%f()Scdx)F*m~h3D-uE=&pJiHb^Pg2}!=2*S7*&vL;1q zd+*KEk4<%0YY7`}CU#0%>lJ|R#NtYr92D5lHhRPx#!OXTEbZMt4k@f#B>wD^b_=`G<3YUSTy4SS$>nY++%k4i7=xn z5#tV>>vauRh-Gw*UzEAT39wn4x+bXZrIS$BLnA zS1mm?apsKXzmtTOD~1QzKJV=hL}Z(}{9JAIt1Iad3aX>wXJ*wt?#9H6Rk4Wi2FgGr z<5Q+qW9FH*r{l-2e3qJtqj3%Pw~)^-F?cebG}B!p*PZU%Zo#kT-5q_`Su!O01T&lJGUcZ3@4exT2X2S#A;7fI zRjc0<>i*Vif%C$(mp>|CQM?`0h7=dw@F-MMatJKy0np>&Kl0Jv3WC)<8$=^Y$f4(= zDj`bM2M|zKl36@}<}}`>^6XDjfi=7VdW;$N7TK@G^H}=+rDy`!1y;MT@u)vQv!7#& zz=eh(h5orvRwKN%f{VuWWbluf5(LH38j4}PD1?w5T+ij3nz!T!3?79^YLNj#>T;8PyX z$>HiduqYeE@Y7^8DlM~j@Dv;((nFCsrMLOxnqNx+bs!}BJZdN&_9F(VghXkNE&h{O z5u7`T&)*t!0UZ@0D3i6|q`}4+sH&Kw3?wbG(H;I^p}vr=CA;~=$P(vM}9X7ndybbmI$*1>9Hb9)<<+CpRn28jQ#;Ay#h9Ue95mnQT;8z_Yk@D(4kX z%gIe!`Y>eeAgVrdZ!n`Ms8h2&MvnbluIjFPJH>z9YK06~MSv(Q2v}6Ey^Oe73Yg;w zZ{YWx0;k^DkL#)2M2Gxj|wq4AQ-EaMzu-X~c8eBE7!ebtB2!_s zblv}@QI4f?E_^+|3sa|Tb1f)PHpaLM$Q#VV-Z zqgJp&mJsZ)g_3X!fheV|)fD=NfievULbC?#6uHnRy{UuT^#X&5dIaC>#ZBB`yIcSR z>1fRT9a1DeZ#D>Vtlge7jCU$ERJTpvtV)ovw@&0&kjFm#*-EHBXOu)%pj!R!vgJ1T zs=9Y0(Ho&9m=Fw_ru?VBPoT^xyM@wDJXVI^LBu}A#`kIz+At^muTT)G2sR+nHU+QF zRg&BK;uQ+V>e#=jL67T6r-%DFBi(9_`^H6LfKh^93;4buQTsO9sRCb{APQKf8noCv z%7Rk*`~47@o$%zj>0&o1B_W4+5}oZ@A9K3b|8j@N)mcBp&m=;jY@n#d23dFaczf5jL9^E67O1~w6vG9JFj;7eWLG=a5$Yi4!*9$cZu=jPo zG1(rXCuDuV@}F@vZ4p{*FY6+NW}igH3*HuaK_8`;cDwAh&_?^bph35^Wv)iua1 zQjbgDgUBmQ!7kpY9T@9c-JN{?^+)E{qfk)BtWhxQxS|*%jTmk*vZq1_r=Wj21;-AK_8J#Y^H-jJV7fu0ZyB^)v~S9sRsbOJSufB1CDqa zFrm3Br=~vMYzqI5;s07s=|>A)^ty5U&8`wGVMzE8n0j}GH0oH`?W;J*t_?a z`>Kf7G#U$9NYEr)q4)j2a%cKv=ZwD+jI^1&{cpr%1x6B*oU-olr6iSiNB3Emht8;o)#l&P)88D0*{8q_4vQLE|9*CQONN+#|DF+lGEO zspO&e6kNofGbCm(1Nj3q!%PP`J(QEtN5#O=1T*zrGK9xe_lQfGOkpgvl{k@YF{y`f za!DO$v#8@Bc#g1a?&XaEg%l(QN$HRFOPK2*Zo?5#s11FJD%36%S zjN;Vg`Q;lngjZvP6*IlVRj+}@u2sA7+`A?PUkl#*Kx+zHMt2lblVREaxpD*pF!vZ3 z8c=(_daWoHhDYazBw%B4R7;H&E`FbAhO<>zQdj~ct54himn5o17?ktj7joIv>6NT; zS2d@gK6aqvrH3FA-Cl^+Y}&}{J1GRW_0xT)s{?2Mk=nTP6Z(S4-;CX_0_1;EgEuJFBK$Sz?e=c1;eRzrEVj2MSbKnH>LK zD9@@OVm@q76aUq6I_^&U&BO_yXFvENNhIA+#86uMU09zmucRPt`p5> z3?c+uYVoE8w032M^GEQq@}7}2KeV57Yj7XbrHaJ zu6?=}5wCAAksjS@v>g=!XVKX~+L^B=@vD_Oq~{QV*M^%MJtQD`Nj^Sl@^bSIq z-9uTOUm0S>A%dy2PqL<%Me94T!nLo1-5yO*yw~k9AJ=VmNveCGGb6&?k9>Y2@6BZ( z!y3txEf1ftS7NX9{yBDt2ILOZqF)2}d9Pv-QkU{bG5a5~ITwFXu~3hYfTSi>nZB`2 zBWVQ*-bS2vDAF)H{U|w6@#}Y$KO;A_gU0+IJ%mo+0-4XixHB`ypF~m5<{gr;;IzJc zCX+o5K-GIR`^@{J9tl9}m=c=%JaKEAgUznZP``QySS+cqL^p^F`kd5~i?uiw)y6Di zz7w*s%HOAQMhox{ym&&``D(7Czc%FV5eZk1=?Nb?6Z4pY*E}^ z<*gHZ_r;zRO-3%7+8#1NV&Kj%3@;dK#v$@2J)3}b6{*6(EY`Vz*-{%Ml2VjV)N8|h zEm~RV@JfBc;3Le!ocwAWUhu+z-({~``1!;9JM;XSC#`Q!c_fcA{-Bg(ttjfN?uBQ+ z(ZE3{HB<$BmkG(}EIB*TlLhA$VoqyD5a72 zE{dh)B5`eNJ1up%c8eG8_hTA^LdWg0+f!PWw1GZ%*{sAaL@sflP?9_1fD{ajzCn33 zZ{ME^md00#`d=tiuLA8idknBSvn@$us0*I$(DD-k!8y3vh6v^cK1{ev85aB zXuc?&>Lsr8p2ls?q5Y_;>K@ynRuKOZRs-{nmV&wOSHvq+)HnYsz$AP|@3>zyzJ=1c z>4Q>k=0hxI2nl}!5HU5LIdeg2u*wo6GA0rNy+Gagnc=Sc?@m;f3xa2bk^CX%?VEas zRcu8F|Mi$>WH5LdvVm`4J&kNLJGZhJLK#L@$=;$8?)28;(?ybB+B%*H=!4lXzU9!K zwtdTUGOuu2^Y0T?dO#tBGSAf(`3>(U#z#HeVX)l%d9`$tR*iW8FD*&X4~A5IEUsc} zGx|Tdf%-tHn3~vv*@^w_%<}|M`*&*Ca6|7S`mbqUe0I%{?`;cG-qX`mLQ|jf$DLSQ z$TmbS#}wj*!nL(x8GI4Qd+3HrH!Hm2;m$g>`lhBhbE8Z;+H>jV#H{$qXlt zZu~`}&UukhGi|~=t1bPqi5D$I8u2r4j<;$|>HtiI6L}cLQ0Y?^+CY|n0q(9lj0H^F z!mHsNjxhQM77RBUUTV`6F3nvj|4Pa7xS0jd*#vCU1+Rv8f@${Ew>Fk_IWV#1+P_wL z*N#cWGdKG&_z1o*l=QIFJJ^K-%C8u$H zlf9{6LVG;h%UnC8YRhIYQ|r$VaT(X<1FtVln(JP{JsG$pTm!e{a|HxFbfe=r5+*%YOlmNnRN`EiWcre1*O8xL_Zz{WKE-8b2ZqRPQ8@f56?V6! zh2$YcnK%~6sD1dNQdhcqiiabayKyf0m%Q)91SGCr5FUE25qGv1-ycE1lPt|FYBkVU zgtI2{3ZVPCSPHv;1L;VV4{V<>{zY$PLQBPzWp~dbm}~L1m9k%M!zZ_PnBLClz+!Ij z*LyQ@%{Fb<4@V`^YJ7$GeWp7?5wP<~W#<81(@{hnT9!7IjWiPOe>ani9OL?v$(|>y zO=}zB=19>i0!g17>sn(5=y+y|YGoVd2L7tPNLMjm0x~wUyoYTti~q{l*B1788eqw* z?V*`ju1T0buN6A9oK=(oLbSdLw?giRk`MRlnm0Kg@W_0rz8z$`J6x7^n^V_x9%!T_ z#CRi@k?KjtVl~p_j1ebf9>kmXq*EqBjcbFtV={*-KEW`%>frn`gHcF>#hy6FC|N_g z12Ok;gHYeP=FiTGi)>98YZ^;z+*cs9b$}__{zo0Oo-MJ zx6EC~@Y%bvL{^pUi_hnx-#E{YF$3VmtNje_qv-r~p(N}^_fMtNrE(qBke3OXF{mS@f zVcjX8!qVD zW)hH3U)XF-PB@N))<%*PJWI0mm#t`0xoaVnX~IN5dB#t@%wLMfmAoT;whzq4v4L$V z4v1u=m+(!{?t>6}4t-mE2p$sz9@8LJvNh~O%MOgo$h#VXKXc+b4@@+Cn31McD<-*L zJhpFO`>VC4syo@C6K&Kgnl3~JpNO3niSTD&Zketlg6ybn-PAIa8mn`|9rt>Qz_pgi zv%cNtLcH}{{f$h;iADUQfjjG^7F>m*2Pmj2HH$z-FE;)^JQ6x$WbhvDi&*oYcUc<} z|C9>P_Yp4$n8Gdr#E&mZ4L1NUUl(S_R6hM}x1k5^Q%dH@i74{`?EVQkZX~<$YuBg_BQu1{x&J&Q1xCQ5vClaktc%arA4rKspz?H z+ga2?G1xbq57X=f6GHx}IhtzYuR=VDoGYcXyQ#UpZ2`p9_ozhLXu%-`U$09DOm-ugAJ?TLB3ig$v-mm@QSP+d1Vnz0Ue- zHUL>X)#(;nYfE}c@B&9c3y*?evlj9rHwuA6s@8EuUrEp4SMmG(bN4}uYZLs5qBlBb z?+lc!Q+c1fQQ#?dNkUeaA(8+K1^6PjAr<{;JWR0D+^#*8G>W4_m;Q$4i}}vIJOG&1RoHIRVe#4AwynKHHP#wEUKMIzm zx4*L%WcUyd_+WVB$q&TpKyzQbzqaC=27Ew;zkO!=Jdy3Z4{}p{Cz#F_#PbJQc|)6* z7pB^!jTdIKbPv8T^?%DBeMjs4-nw12;ZI5IE{-ajg^p~`wUN9 z)q*{+jC`Qu&GzG6k^Z?G{gCE>ZN0S;9tydu;?41wUxb$(f$?;Anm=aF$k1;ysTbq2 z*3)r~#yh5FN@vaR3qwY%!66oD_MP%kICeyupzlQ+o0S%kE$_f9H1)iOaqL6K-X%d=Tbdg+kBVB>i_w zI*jmNc~zi>s0bG#15LC+2b?RhS}@vmW`@W0Wref)Hi#V-G0H7z6v}K8LWIs&{U?rg z4*cv6%}t?0GRyr8yF>p%*y1~Xy-5WA>9I=nr2|~TtvE)%Z5E7kYg|pGx~14 zWYcRuu#sYZ^FA)Z?2TogtRM^*E0sZFKV|^mOm|G2f6v!c66e|=gG!7!gpN7_mXZ6u zn?=LnSzJ1RA$n8s0_! zu4T(c z4H(evLz2o29jStlst+RfZOM*sQ_TmE+>Fe>_oo=3HoJA~U5Qt5nn%Ef9a^{XP8ygo zd=O16w{xC9cYqq~W+G#$#y?X?YyhieqXYl*^7{J^$HDMI4!f7cHFd<6PHO@N-S3gb zIHB0PosTOeUM?ocrK^YiOFVYtrrKzf8?xNT>aN2@NDHoWOP)hxScnQOE zH7wq!c)P8s0$QLi%W;A{9p;6~HwSQ3m%MW%St=@fQp7xe=rK{vF2?76a;gc|GzZ1e zl5X9guLst2iw=#qga425RxcB_02|SEZa(wnwaZ5J`HMUW+Ch%Z702=iJL%#2J|x|! z+#PPBk^v8b&Up_}UE*mNEjV`G+{pLc>{`v}S?))UV2T;;B3pq;Lv#2Lgf{odI)src z5Fp~2zd^OWAC8~4v^uy=ltfuxFAhR884OEey7=H8+fd?#oTpU^+T}W^16&{4 zlJB?Jzx8lHeJXQ%=?b%z8m2ImpVOSoE69wprF#FqN$o~1#`2IP>3dwlV?C!Fr)DI- z1OLai13q<2Owl2y8^l`d8v|;*UBgdDDW%2^f0sPAlF6lEkVW|vd~mD1jPRC7;m<_1 z0HgUSq(^k>zto*M_0`#HLD@L`OB4R^gzdxR2y;CH`~@YdN+T4Lm=&YG=+|W`_dh8H z2lVSFEf6&G<8zlUiMofT24*Wt~x&WS9bT6x! zMWYGKCE%6$)Wm|aWYbk~asHIPyXPL1sBiOjGJs7Lj2LxJ{wu5Nr`r=n$&aiN)>$co zgG7JW^?+s9uNn`EA5arnNln8&0P%4sT8;h@=qBAd*$oiKLltk{SWx7WV4Cqeu{}*? z2LsAnJNIxm{;fShkLy$~yzaljA65Dc~3Ag^*N+>hvGQv9y*ykK_DnteB4VPR9+GG@g6cu z#Ne27Zr#3(#w}3awW5up7GCKlxcsRLmx%iyL={K)ux^a1aWS81QjGewy|7IPKBfcE zEUK40bZn5Y$G^@2EAubxrGSaw1?r$5)q-g66U5$rZ)ZzTae!pi)u9xMyMKzxbo9Ct z0HJEo%69E`8^(C{`B{TuvU`I!rU8qauDp`efZ{J|U?Wlt$dsNF_?mY{z5Sd@Bj9a| zJ)}Mz(z|}L?xZ1wiQ=JTJ$f8_yB*A>FimllBF%+i^*@C>2$`{u+y z)BAnzNYio4h?<&LCDN^IXEP$kEvH$8Ys_0=`q#5O4SgH-_E{`taVC4XrzZcxG0Ij? zQ|m)+xRmJhJc-dQAw#ES=AaR2wDEDm2p>86u9O;*gVE$d2_p!$Jw<92t_m}ZA zc)VZ?K)j~hBa!iohKS?>?5Kg8Q%b`Ca2spCI-MuCpFPYZ6Xx;!hXBtPaAf0O5-sBg1=M!{&mmmBKuK%Lxb9B_W~+7RI+S`uDcBoixjvV*AIxsNmV zFh(jaIa|nr6!o`=_N=$Sv8m$s;yBw~haJ%g8bm$Z8*rTZE=yz-(j=%0N36z_8eUnR zz_ckyB~FpwMF3#OK;?bc+R!Twq|XoC7hZP~NX#C=_tJuLP35>l>S4!#`Ht5?Spe4z zHRCTws4yCoPXIvCkhdgLzBx#-*;BI&MHKD4iJ!WmB(0tm@GcUQVB1-^~Zu6GsdN^ zTvLi^&RtE6KjDH_?CBg$4ECJMH+8#Y-IM96ebW`kqsM$?HThH2l6r1_{vh~H8XoiB zuLje`gMtET78X5X))q+clZfiKLP5bbzV@8p98a{YgReJ_9N_hOiiV242~#B?uw=|F zV;zcMV~{MlxJ0rN=^vA2QQFFIA^z zTOPb!gmyh9eo{kvcp3}*T*>Tt#Y=_7Iwg0ydON@Wq4!wKTcK3TH`K^( zo0&?WC%Z|n-z=O|4=wZo3Eff;AgbuvDj>VYj#ET@7}0O`Uj?IG*UOjB&%UgM0nkc# zDlkB#J=g@U-${@)U;s_(veBKuptg6YbrXvTsR|WR2*5)P=0QalginxgG4JHW1#6<+ z57P!wiT<6?Xd9m=L;u!M=-pX`;pXj_3z<{m(-ty3*^K5TJHYH(H+v_ht`_Fx9AOfS zIaI!sAJPs3fFem*JWC0)tHyE8)$33g5ayN049WIW{shm%G=_BZ>qum1l1Xq-1^bWM zK_-)t{Kg2o%C$bE%4C%6x%w()f=W9~0{8UQ(|dmVDl}W+v^fQFyzDFEAPRc*mxckO ztQz~RwfTMx4+r| ze_J2Ys^0h)ytC17Dy{A!ESM$-dKcBk-%~FJ%hcrShmGW0m$7ICFN7kodEbb^cr{+D zI7{B)ayX(uA3Pm;%($wlrl#b5j$9fR`R7 zLW-JM10u7ei+(?So}ALv+hY?B%7lee0dmPVEL+`nc7QOqy^QVgoSR+Tq0KXIo)$yd z;8;{ha>|KjZN0TdmwDH1tLexg+~ho?ll3B`k8X0Pf1vqJArx~EHh{t*_GGC0P3D-% z0xir!2aIIgIi}?mSgx9zBLTpbmIUytcrWeZ09Z10T8bf=XM#TyWCg*0T17p-xr#-E zbt9%d`MpvG^z;T!8$;!_9W?K`)ZI7;nZ6{YQr)SYRQ@pw+j3cZ2iY_=UK2jqoxtB5 zfi3Q1tK8Ukc85WG`coVoS6ifr3(0 zon+4xMNpg4{D~%2IUjaqH~6NrWS%n+PQw%@RQa}XWs!Hf0b#1EVhwO?x~<5rQ@q@W z;u`k&0C`=HKDt&aHibW5=H zIb8tm38x%^HRUDj&f)C1CT~v?eBQFHtl6FO0&cZ&t?7>egq2z1HdILZD%S_NqNui~ zW-1P?{dd@dN$Eg|(D81yT6q?N62=N+!s>pkG{Ekj5`ERqliNf?Nj-_dD$QDA+H}`9TT+bf?5xbC|&w;fdm_ad?Zh$MW+&q#)wV{vG`NQD*Ktt3zGV-<` z`*^+lQ&T7pwqF@4C!R^IdpR#h(|k_`*`l3%Oi-y{c*>?OAjf~p^2CC6OirjeG;D5D znA#jo$}@z~mM?4QTjzdX#zK$|OU0d#kc5x6!x`3ko<$%Bu_9yEx+i&4m%k)7uo=48 zY2v21Rm%5QQegsQ73g`vu#azd_?<{sG;lf90j@du34}xe{p(XQ=bF^KEn3^f%8g*k^s~i6Q^gJ@El#0`oQLW=Pe}+hyeu{u@ccnFp-k+o1h5VF`=T;XlUU#zHkV) zM9yKou~AR4?5I-P@s|~yTHhynYmTOw%A9^S3KSHevaz9896Gw+K`2}c3M!VBr=fZv z@~H`WIFsW4KGqGPj(VZtD2w;*<5FEw@D$PVZenD(gHz^Uaa`s3pzc^9#7VU%y`rM9 zMWXRVU%EeUncu3pY3Q(9D?&~u%Gy)^IkBQj#@1PAfbOINKZXW^K)*&(UzWjhGt@s^ z1<4H|C#r2>R->|33Z1fIr{-GL5ub+^X_CgUtc!Gp_A1App1ZeG57|-|Su!<$FL0tg z8uxpZTI8^Q^<_g^{cCkY8}ms||Inv$W*$&|B$$gk4+xUz4#+Jr~e_PI7~B*%f- zb1?665651NIlX#Gg~gpKt>y@o2q?`l(1F#YKgZAH5yTIPS^o8Ze5qYOrB<~gW=!Zn zId%1g;i`8HW>VW>7x1DRg?oDqb_JMjQ$W?_JP}tF6gN>@=l>$niFQB^C_y_NvJYY_ z-fbMzXdRTYHy^?sNf$a=i^U_8y81`vU5lZC!e2}+5tu2t9n$YJ59bKk4RgSZm9{U} zjgt;FiZ^ddY>gdILUaY{bf`?tn7h74#ZXZd81-uqPz031*)Pa#RM%(^6KA?CXl>Bx zt!)>opZWC!slWNdFP_l`jvIaNm|8&&aL5vB-I2`=OD^Q?SO4ZHxDg&^WJ#FZM=q^}o z9JuLLZHgq8=)_bG`Z{K=NZRQ?uM6To37AaR8`*TaNV#@)9u~rd|Lf=|B4im*ZWznE za2Hu`X`fMOY^dE8&=eN3fkRtT+Z>UGea_y%{J#3@AtyCdpC)V$z@wO>%T<-(3~jse zBp(|_)TKa^Qc-g(*XuEgz_Q?aOCv1f$nZGC)IlzqjvCl9Tt)usJsJNZ?%N3{0C3!t z*Si{YW)V{^{B{9a%fXq*Z`rAn6UPMXd|YXZFNOZ)0Km1%dka$@?7DKe_yZ9C{57## z&>w74z;Ee1U#l*a?nTGq(KbUoyWT(N;vSx&T% z+=}UVpUipy#u{>-j?zTH9(PGp1T(a6aR|)AXo%(dqZ_5m&RfXLwR5{Fq#oQzz^Aub zRIf~R^p4JY7kDW1uHp8Eu(fWGXrn!KlQvKxt)#U93M@AGjS`+p+rTzHblqwqmE$0- zV}Ba4$0BDZLGNRoG{aXu9Fb2K8%Z^jQ7I#L;T6>@%R@MiD6VJmy^audps|t<&%=SE z4Ghu`sIaoQC6BbkU@pG4%_Pu5n?;(i3Bwy7A){0VVtGzsP`g3bW9ZK#U95nuHCMyn z1qGK2r%bed40%fV6E*#YrQSR?!5mwpD&TU^)mvRsavL`$c`&SFAyJp)Hay)iqS{6h z<OGcZh9MX+cBbF!q_UlBmko&4I{+R1L3&Wk`tVIlq$mTN=Ut zYT9$6TNX{I^oY)NOYn)f5?4`CcJ}oWPrs;ZEK`F4^vQ#rG#^Ft0g)K(Y^H>@hlej1 zwiSxwd{d`ASS;5Bl-_7}@lq1li)Uzg?UhAM0iGe6nR%$f)L(CX#y}Z@8AcJ4b#*VU z`W_Q(`PCKu1xdaskT2be1$Ud*U3-{M6b20sL}^H~r)=WSFow$5*4BOX_h{ZV6fZFC z`sEjqYt;cHTu#fNva2&uxZ%=>{kZ#L?yU`vEZO7o%+Bhy#s?^sTGfBf76W$x=c#}2 z9sqE*nvOx?fb%r_Bot~E1I;sZAxvHmm(JZ?NFYIw!>*53i#lT{UfQspm*?{nRA`pZ zFACV?GApsAWG`Ku#dpt!pQy6AMzxy>x+|Kj2Qrj@}EGI zof4_Iz=n!-g?J?#y)FJnZ`KVIkzd@wc$Hs+sy4TnOt5XBj(#6h*k(KW2%4F^V0U*n z(AJ5{f3DdSqcUqQHXlXE?>L9-AJkwAlv3YSMsC?~|$&DOIwn_302V2hGI zkS^vaT-Hvs6#lr{FJt~W=4#+Ud%8AbwOAsjq>o!>OCu4|kZ@A2fJ00Ub+rd6_R?o! zv0eKk!%K?l&(ta+xsCx@3TfcV)BwAT+I7A2n-TzRGw~0p51KZZmH>i2A5KG6_a$qR z2fVx8U&GMzxVt;2Fmr2PUGR&DKwgd)aXQ(4h)cw=pB-6D8m2jknjGysP%c&t{{~D~ zM!>@Ym;EtW?&+%R!&;U@uZbN`jV({?@^0gZ$=igsx$j%kR%PV*Q^SQnAWK*zrwUIh zrqF4R0%^Ma;G#T+uV7M9Hm@}ZxnrZOn-;RcG6 zzGLE<`$H~$CAHw);Cdh)g@O}^E_fBd^PrLVybEcj(xs;Nj6Dv6GpQ!bPfM&49Znq( zfcE%7&bD7{IJBOCa3rlTKvv#(y<-zuI`8}_v_l!8<^yhshvI7-eF+$2g{^zqRb*UE30q4kUn(7jZg;XNfj#z0M-t$?D*Ps+6*OLh z;I@MI&`#}mHP5p8tw5A;>FE?&{z>LzcS;!siJ_n^!&NwxPm?WSSS+FZZu8{%VsaM| z3Sn^UX9lUYln$H`dLd*bu#WH)1Yyg8Cnaf#Iy#A7U+Q&>GGOOT>l6-&nI5HlXa3zR z6Yg-Skf?e%&!RkII`Ner9-^}kOK4RqsfBQqR5&5c=J#V0ADHS%w0FT;0r|*1z5|xq zRhae@*#qMttwNyckYYyQS;p(VcMG;fs6dP0>*ciAvZM03oRRn@1BnF%NcXW5Nd1MO z-=2nbQ4>M?5(`(}ra;RelQ!1Ol1p^d1p0P^v5!Zwb$o$D$w z3_&T;g)g(YkiuMA$O$AmnBWed8h( z%6>3l%WMRYo&8;!p0b}vM2`cMe>!_m?svmGq=91FV;H)Xri0c-z?GNfoxAM~rcg|iXL3FwHfP=XX7=}<3%9}W(xur7b?-;od%J$+CBg6{% z_C5bOF2wp4u(0`cXBBD*FeVGb>3ObedcD$G=G2qyxPa2~Z0h^eE>Kh~xn9I7;sLcd zsX!t<{96FuX6UhUy1UGHc`AeH!$zPg$rQ<|8&zf?kBx+;#S6%C%*h1G@0eyr9woJA z*h%w;0&4DCw21b-pDX%Wg2-rThiL;JMCALi)v2vdNYpV=^IHWnZ(FfNmZ%+Op<+mL z3o^ACbw7FpQ5njPbRp0;P&FCScXu^M2Y;YYQ0Y6R)pt$t2@EwI6WOT}>;Z2+=^&B% znJkZ-Kf!r_&UH4p@PINa>jneqepWUC$R)j#btk_7HI9E+32Jovh6^VVtG(14i-jLA z|JF$UCuiAC=rz;;;LiFvsRDg&?R`jPFs3ioYxeVA%A z*Zks9EpZybXr0GLXvWr+q-z3Any%-K9^<^u!p?AQABl#@7#Z6I4UUnR%xr3o$oYum z(#K}f?^`qEI`%4ftOO6k6Gji^fIfz>5SBMcrvYH}-5=Si0Fl{3fmp0x1f|MDMhVDdFQ?w-SrI{Bq9%#k1y#+6Umuiq}cB`4-5 zL=lX|sT#=^;s=k6>a^uWl2k)DD-L0ja7>gv9t;WZK>JrF8T zIwRY5!}T7VfIThU=Op6NObah20)3Yfoa%F{?7u)2O#6A?=(Xg&*F?k}V+XmSfeUz_ zF4ekF*nqQO$4+7M@5`q>({(HLSFXSLk%0K-0{@-&c&`e`aA*hoO#^AoBfAkwbPEYE z!AS|xTGs<g95srzV=wH;Ay+SPWp(`ma@`{9#l+rVs+_4{PYQrZey700eCNS9a< zjce)LZ4rep#^?}{FNpK=Ixw*mWlJW&L-`spAhW^?SV!Hts6$vg1v&V07Qc%s>1xZ2<`r+@g;W0kyXlE!c6YID34w)%+?AHv8UR}1wMZ1= z{S(p^lZMVro{eO*3=mDm&NpC+4Kba;EwH@ZJRm+kknh!p3AZlLNYyzTzPHijXPzt^ z9GE_;WOM0EOnlB6_W0L^DSp|nwg&4-XT(yrbZF|@mB+=W{^8(aztM*qO_AN<6B z*_yLq+H}-a!tyMzE3`EH!7z0g33xx?H1n&vu{RLiW9!w=tr-Vt9VB?N*SQFQJll>-b2ee+~X~_};HA z6lnajV&uaS-}#u_vAIn21{_g(-4+x$2v^w74227P@-la`yjuwfG;l&3xFv71N1rL5YhuGzpwBPV#D;(1D3`fdxh@*c3 zW(AKf3*e6gFf-YzG>R6&TAF_ShL5M9;&}RJmik+eK({onVQ+LEVQ}_F~fuGIUi~FvQWqIy!X@U^_ zcwT4$Q?MQpms+(o8*5YkoTST1Vcpb~@$VAb(PnRLuSr&mUeNBcomB8F5dl3XAG@ON zz!T{!kGaiuAez#)NKd62B+= zh`5x?un8N0@~Ts_)v?d}#xs3bM^LywqDWs(g!H!x?N_P8+x#=!Oug5`avAmn=5L+5I44u+8YJ4dqXN7tGtOiQB zrV%BQ#T z&5Q%CA-*<(#}EKYrTT}##NeHO?a(m zPm9BW!5ZrZ3cPXKLiSD8{+%`j*J6equ1*Y*eRav*VeoXWqX!OzTgxWca{pA~EuQ0s zG#2o{qhmLF@u)ndFuiv}t1J*_g$32RuDbYO?LQ_-qc*5Ng8jE2K$W@wIx{{zTvHyV zZ}V%#J#4ota`kA3bir7IIJ9>>atchA4PQw+A=7-gF1eF^a z6k@n(IoA7!Xn3xvA@2S>t#_w8JA2tg=Hs+g`ZWVGCJQfe^$Y+}e~McPMEfY!9j<$;bg|!)SOVia3obCU=iJdplpkW)Xupb1afkr~lh;6AEvs<%Q^fk6j z+P5oRwj_dPn7awG-u9M%+ehKH4YVtLlL>W~Tg1y_Zwy|)vx5GJ-LF7g^ecYa8QPv4 z>v!7@HB`N1jx*4ZtUSag*VBVmpM|bR+G8cjcSzSu-DQ|>F0Gu|_`%tZSOiSKEUbx$p;>F+A8tAzN5_`~+3>JYrM=FFL?NDuJkQkCo` zwv^cANXJzw4g5F*g`rWF>Go++Vj_QFL4mTX=hC%o(qq5RV3q1@DgQsm%mx2v)1$>P z%WNyM;+znGo69hZ3yO|$!GWKpcH?eP&K7f;6DLWwu;=LXY&CLBqJE7_zr2Y(b0B&udCzIX zgPpoiR~vJ4Q~ePz`r#);pG|ptV>R45GiMYecd`iwvK-&*BmCeoZdU7#pgW!iz%sC; zXJc%?1`ypi*!5h&le2#45gk$q2$RK{s^Y-ZmJpV#fvd0-)OoeT``ywyYVxM#9JCrm zL^&pOn=t59xD#o^%!dJZqLN*pzVTRF%_5!d_}K%Ka12`;ZgVGt>+F{vJInp;17Wxu zJ0#VbjCxYYCXP(g6Rh|;;RiCf7m3?0CY>S4VZwY^)TXT4Y zU{j!>PvW>0Sp+hNtYAp{&7(ep&(`!bA|vj(%d>o94aPCFe;8wII+TaS?>=F*C@bCn<>qH}ZHHc4uvE5v<_a5&8u{gz#e>2~b1y z&38&fdqw*5DdCxkyCAQWeBo4j6C2U%f3d8=`yAWQuFu?C0q({i!m9^cOW2%=u$|IU z?@|R>439tp6IxeI9vzJj2J&nrBu^9w`8i$(TcdfrKD4D*ABqd#J33}b3x~kq**zA# z+fW^oX}hwPhga1L9yaPg`W}4V3oBP|iK$Lxaf|62E{j_Ixtcy80qKzl5JOqvW^6D= zr&25HW1Q=1!epphkAp+^_Dqx^1$AW)Zg51I@St3RzCPOaDH|UWX~z2fRymj%XQEP> znWNoM-pjlGHp0~DStB^8>0I%w2MUjnX3M1#_Gn6@eY$E3KxP$70Gud$yD)AW$nI4_ zAs+MqoCGQ!&Rw71`X)}euH*)Zo>oEWzBFOEBJJ3*qgW>sx3EyzTx(ehKq4l;i2AnO z`!{e6GK_=n_->h+#pR zB|hC)4R$|F{kApft0rj0`&UjU8%HV2s8(M$2CkdrteyspgbZ^YMfwBxtd)?ZhX4N2 z!uU7tW3RfbR7Cj-9?{#W64qDJ4^%jt!Zh&)EHjN=l_XMi*7>UV_kY-`dlxvfmxR+2 z!?a%iE~eSUTf-pq@!@6D$Fg3Ke#fK9uq4bq;68qHi)TApr2kqg(Pzh%ZgtLFgqw25 zic!lyuGWzm4kGM_a_Zk~l z&UF!KRMZ>>zw6v|(eE{>*@d~s=mrwxUbYOLNAL-q)rZtbL9*mWCM9IK%Z@tC4)xSD zX5Ch8oMMw_P;o7LbO3Pn&R)yAP1XP0@N2QrRIRpxDpW<;_v*UyD@$nFj@`zl*-JDf zHl~hZLe^n$XwK&xN0-=Ji7*v1G3=E)1}iecv?c+W+F}+#Tv$I?(Jm;Sn;WcK>o`)N z-W#sWnXQs4a}%m0bG`U8;A}nO2G2EKQ_1sYKFj9Qt`YJPStzKX8}kMgaR zn?X&}8%*w>f3`J>G+@Djz>%EibZ0Nvc;e8H;Ijzt?}1!=;U90HV4XP^NwYw8t`uni zqJw5)J}uQqhN8JdqFtKJF@Kn>J)#q5EyNd}$~0$h9Xjo#jx*ex%`46`! zCv6qj1k2tOot`+a7Zw7LjmlN$0<&Oy0Xr{QDs~*V&(+yTHZHfwI|$dt`}O)F70YeN zmP&W2sd{0d^|TeKq_G&%u^0Wq8Z}Q~>o!ZW|DJ}50QvzZ6&ma_^pu}b6{`o|a={uK1g0>8J=VYDZU*t`7@m9oNHjZa zor{O+JN$F|GB=rQN)CyBxmki1)du}Sfyxl#rzI6USq!mk-%?9JT~Y`CJaq@4O%g^7KCN~pWooO{$T>_S!+5*JOid^>%a#L3H*&UBUZtvsDSylMvT4f^(~iQC=NP1cBmEX~iTRDjFfN%Yd{+);re zZLZi8)lkaG$JN+LF(-(*$%tVxJpcp=`Ne-jp0nUbs;dBgGHs3!uaxqi_%lb}(li2= zm8bOpXlSy{UM~*Lq1T}jFuib~CRtoHQr2&evWa27&rjF8Q4=~@NLM^mlO1E<)1eho zwoxjAH{y>{;=ldjSCRrplS$MQi-q`YAl3PJFOlL36Qaxq-3uQ7ll0Y{mpwXVo1sxf z)q*Fqp*5}Z-AQyFD>ciEdmsIkw6_)-vu>;IFkuog^MuU3xZcR z-^}Y#1rlE7cQrjq#6GJ`8FooCY-zL;hy6)t8DTJ_p)u$g)D5dHTAXI z?#*Vs-s>caq4BJ^@v9WStP;slynl-OX0M|K407=xMo<@1c2gsuJ>w+^0l|%_1h797 z(MNbka{1Wj>(w_`nytF5;#79an*~v806!Px*Z?$fDTCg`;J657s=SX3o@Wf{k;J5c z9}SV;FH1tK_1WSZmAfvljNLk)nMUM2vo%mocHG4dDn@y|mPYQCy$Y*L20_}-q9(~h z0D$4&kbcFNAl-%H7gec_^_R_$B~4wQQL%|_H8rouju@jhrCj*CyJu-}BGUgwm^$Fewh_CcT>{(0Wc-Q#vg-F3Y=~M}YA!`^ z!8@aOR|0(Ho>@k|HWvn5Al(;E@~53k41ez``od;jAugj3zCAFK<_dVjYK;4Qa56YbcXI1ozD&{loX4I+ zNfMW=V##)SALznq*J*l8U>Z5!W|q1(W(&n)k&857crDk&Z|DA1ZV+(MfSpa_pbto* zNjwxKsgH_HixK}x{! zjSlR)>Gmar<;e!?>LN4$c;MF@99NpNmzcds(+yKACPXL{uBauF`IZyfw9LR9ccM3TW|Gd?8^1405fOF8$kEB96ui|p)1|1M`1byf@a6% zm&c*&r%bzAB1PY_>;}qx1H3KBefDrj)%s(T2Wr+)uhdaFdOF$xgdiXjN)fMWCk^nQ zp>DldRroNki15*vtfz=Bh7S@3FLR{nNJMqY>ah3Ix0ZfLie2-(LP!&3#}1K4mHRjC zyTfkrP@f6vl0FVAhyln$Js-NjoSgJsBk4I6RT{^V=QG<7{T@J{7(|WS7;w|aQBW2Q zg!%N5lPFR&CafRb8*FN#0P^4yWQAeyur`WE>Q+=svIc6pNylA9PYdZ0;EEzD*Q9LW zR!j%B_63Z$CgawFV=s7t=5|j|!A6=q-0dR+ziB{JA?^NNy$FE;1-Zqu%;7Rdc2r0S z_Nz7?ZnUi$ZFH!v9duJ`rP)aS?Xa+rfMv2<5U5yKq%Yd;Zh8lg{E-MjS>eHrTP8NT zZR;De^sxa6Pg;1(4wni+H!EGBaRW^@+NiD@@sNo-&gh^>X%0k=9cZbSx!W6Zc@W_` z80g~4D-uK>%O`6aM(_s6VlKu}8^~MCx~e)=M`TzrMFKcJ|6(#nylvc4?@YfJgIxOw zNhCBa0u{Sdr?DR;_0R%D#>C_g`*t5RMVt&s)bggJMhF83|8Th8%j<97>cVJA#Fqvz z?wk^H2@mE)RcC;{lFD*hr*M$7m{QDAJTM~b9RJNQzpm?b)ZUzHrc?uX@I^(^gA8m6IlSS7B*6j#;a!kiTOfe*ixe73YRiE zgq6FM;o5m6`>VOuJ%5hPb-7*9uuRc%lZW|-zmS_ju{be>?;~VwvGcGjU))@9C@hTR z9VcxN(i0QBPomxR+aB!=H|g#V5zG00Z*()au?N{JAHhcW;D^W9_)BOxQ9pKvV;AY@ z$97C>$xDm}6ph*gjK(krPGNVhd5zYLE-)Y6GPTyOI9O(2gdztnB2?)bQG0+=2pwl4 z3%3uja-la-5T_xJ$9Fc6!R@driQuS>KdR?UKHX>$<$%1h4lnX_^O%gVY&p}>Oxcpv*aOU~>A>(LDEPD0P=`d==@@(yXB7Rwf+!Tn}Cy;kou zz(cfDG$xJq0tagc)Z?3`f((1gcDn%ot&hl;M|)p9{M!5RVW6hA;S-eHp} z3AY%ga1s$}+kpD{aI_nzbTKYfXV3w{@KJRcBsO~`uqePEw{~*Yhvs}rUchzW6p2f} zKgWD;+d|Mw@wD(X6o8w3>zzD6+BnXpo#DY?tb@<*xk!mlulXjb@&1B{1E6k)VLH>h zgjpDb1F01E+ac4<7yKXtfFvchYW$4+{0TC==)T|ipjblDA7bl*00oFn<7fp3V6k~N zFzBY^bc2DhWRmR+-5AV-0B(CO#@&%0liD)bUY)?br7+OT)&rS@g;)gU7+eC8TP!2( z;N=XIX3$wEVJC?b<&KC4>!36&x^M!kNecHhZgsd|x~o?-sDDYR%*=mfv&?yL_A=Bw z0I@3b`hGJKe+0*vxOrO{H|Fb4X2Q|!p zW$h~YHdJheiX++?o&f!~4l(tCAy|V0taTm0#SM~BK8J094YD;8f}vuSvoiC5 z9(enQE)p;8!8PZpYJ(tF5`;%{MM1Ly2F^gqL$F5+O;r2_sX}VxLf@*p)@9bWaJyX7b9Wfu`?Sb1DtRJ=Gxf0I# z;SYdy$~-oJF729Xv<&fz(RbKf6HxpNe{eG4*=uEdH8~ESATvxj+EZlJ$+Ufmk*eY^ zVBrcQ_zrkLLL+ZEa0D0c;XrN(Wp}fFfqvQDJ&o>JUdWcMf&7ucm{;u+s^4iwjursO z&6&$D)?B_cppTA1FVe!e6-(ldgNX90^$edjGorsB;#Wfxvv1L`YSzT4>&S$NM;&H@-T4?xGJ-ncE^#H3*VT_zs2ed-JF zz%|!Qb&>;tV99;BJ1p3xYvjhJ`40?9vrbF#qD$-Em1###OR76K!EfdWb@YY%E9KAzMXx(j`29*+%IFs`7xYw{vRXv`;>HdkK$QLP138GVWoy*31r$I0H#U zuyT4+cpbG-+z%Xq<(tSf{6Tl6pE1dyr)_x|q=OYnA+>gbDvV+yXLYv~q@?0IdRMyO zy1NvRzsZ(0^Wvma{&TIdzqt76k7>IVK3{l#7ot@Z;@wRCydL6#xQyRRxQ(kEEXWbR zv^(E$ik_G4!*1qo^zUdUA4uLc?vz#%cdxX$1YV4IJ<*zV>c>z(dziNeI)N&|8zUx_ zCQ&Nhovlei+5{Q>{P1hzz1ovutH|EkT-f)z+>|R2%%{6V9tjW$fDl?40Be8{iwICxR7f3oZ)2YQhWQ6O&JFP+_oeKqzqz$GKn!`VpF5(rh+1I$ z;s`M|;^?31s%e9r0j!BF6aZL6Ai*JQ#>Qo$>HuHM&hiG8KuAg{_k=L zblSi>_u11s`r(*-#sAu}fA%wf`!|2P=TCV;Ew`+A87eDSwQ#@EN>Mv}_D)ur$ViDq zr4Ybu(Qc$2p3NeGkxe1icIKCO^dr#5yJfqYZMPM%`@&g2wxmGEuXv|*KZ6>-r*?k$ zah@?+guIxQCe54=OMv>om7Xe#RW_W4MgR z8TYGmww|f;EpD+*+%^#HDIYo$UAWaRV9uX0Tntcb^}znuA|W> z4xhX(TD54?wq%UNSLQ#Wy&~lNgN_L{q)=@4lgkGvn|ziQAJ(T;ln|CXM#uNr9X%<_ zDOQzB_d_6X=YAW8`yJb0Qd&9QAKn&y!FaR!T>i(|K-)UFD>hbso^_qoRL?+_7h_DV z&zVKzSuAmz8ns7i6~pm=I3G|>n|3aPmPR1;1&Lul(p9y6%{U$dg*ABxO&Wx^%*KRy zpoIl+TXscnK^8xeV8c)THWD8Vb60n4fG}aGV7jWlVVIUOdjuF<&C#L3PtM6V9o82v zwSnliRSFD(u(szULii1NseftPYqAbN$@oc};j^logqPO0skkjjRcvmHDx^vTEThm( z*HeI|s+xMEe-g3{h{X9hY`<)dl&s1LVW%vTVjV#NR}qs_fTEn!AkzkWO` zo0Aj=a>&xOFALw^XK?HlDsyRt>*LZW$5Hz`SYW&JS4zFYt{YxDpu2W<04jom(OC)l zhua3b3}MM7bbMw;?$PFbl!lqj!PpX5FH+m=(*LQsa=0`~&i*vBwz4X0jCa8-A;`Yes$iC8B6{Mplts0;7syzNw$kTiqWDBF130Dqk`%?6N)= zKMfENq_O~Q%X@qjtjF*I&9{$CxY5}f3uOTe>!UKsT$5jFFQSO zTsBkFBB@(L8`uD1*p-Q;omnIDM=HIvx^vz9xG7Fd(>(TaLE<0~u80wSn_c0X!#8|_ z`qVovJnLBzFU7g$!X}#2TH1jnO!QEc1Oh@+f5{r{wgz7|&?YqFaLSH}c5aM|8H&Z| z-_Wpqb+U#a1w}Nu9tjTwY;0+Q?+;zMp#7-oKP7HRp%dvOK7V`11=N?D|Em-@cNk7` zm=zu?q!Xf3@fHBwZ?cF(H(l!cZ2BZUD3|^lf(>} z$B`5%t=4x&O_1z=(dTnz3M!nxfSd1&6IWNtf=uE6=m_csmpyR>`e}(GUotDw<8#8A ztu%mz$cUM}uq5iz>eOgGdmWEEag;Ds6KEvGs+&?^laP2Ba_Ms}K~FT?xeodH%?av+Ukn&BRw=A}bhjZIc=&6`MM!wB6Qf+Jyq8wRKjlsS>pHHJ z3n18#G->i&c}JDT9aUpkY4rr+0geSj761ArAlGx%2=Hab24p|DAA-&3kJ)lfYSeZ_Q6h zLXP{#MrLxkwc)y%m~c{T0D^en=6)y@e|=#$QMvG|1Z)EOH!3-^?)!$ynf}bmI(ING z-B4j`zN?1XH^U9!po3)6fL5&BwtRF(q-4bVZ$VRF|0W!v0GAVdyV~R95vwJEgf7ma zJtgn^6tFzdp-@goCs$&<1w0d8_&bQU*X@KOnmnmli? zT;~aDOR9g`b~Xv+CWMlmxW$U-*;9D4+`4%vW$x7+E0Eni-M|3VLOQlVt*pe#$gVM) zo)pje&0n@I5KA#P9+tnwU_WZ0Ks$SIf@K4uoN7|=g^-wDI%xA)s-DI-@Dxt9)9e{W zmPSI`3{A^vw~9wT%sS$)?w+>&vm(rdjOtKZ3cg%y@p<&RS1krGu;cN4gi~F0w~?UF z7p&r9YBd3r+#&hJ*vt;Am+nIKJ&u8FKg;xDQ11T~5wnuzuyZ?4l<93gl{xpB_Po26 z&B_!HHiA=ZObY`*D=bD2dZKD7$jV`8K{J3#o0#BK=En^wQwZuvkF~ zmLG2YIz(q<`OJYRBoYx=X(#c*6Q0ADz}b9$&>c+C50YE*z#~4FZx*|h%Ze%}L!Ko_7QF8R$ z&i!7j!FKSK#`so|46j=PzvU2lg`|Vp)h0ut4gx5Bqyj>ea!TGl`5?gsgjybR)M$^X zB3~?})shXRmM3yuqTH2h(=9j6?9~-n2rmF)QKe=99B?fBy$51eOf(0$K7fm9Kzx)G z+of0E9Jf#|8-NzW`0_`YtCQ+(Yw0#B`LcE*2Sg}27NP_O$l({d5W7XkYisvF13_@~ zEr*RrnYP0ifky~DG5-%+>(WCHA71nEEkJIFb?K z@*{tE8bV1TtGD}8BOU=Z4jzU~AT5Chlc*sLZh}bIh4N1Y>;v%gOF}lcv+cwg;P+yAW{Ize+Soih zq^ss)o3@Za9?AB}>xd8A2wpK09=??oR?Yf*O1IJ+c>%=%z5~nrI*@%w#!i%aOXo2` z0C@}Jl$8RWG(MCL+vY`ud5^nz{%tMjzU^UWX-y?Tw^8&H%J27C zg5+6aMZfvMvGm%;OMS~p#Q6Cf?y!vKctN6ROl#CwV`Yxdgpufh3WVj@h~vd5vf(1{ z>mXeTi;?CDI?p*x&gE*Awz$qkDa zL(rc#s{g9M=Uenf=aLH!qwbD!pkj!Ce7h)I%kWw9g)~>i){!G6ldRZ}(A9BpI@|9&9CdsBHoZc>jfCg!HMmbd1FJ>E zq@+O?Vl?Q_TQjN&Pl1EDOe&11MR?7vubnF{fuM23>#D?3&(T{EQMJ_as^}hX%3w?v zVXlj;!33Sc7|)m9N?)1Kvq7{nEc`R?N;p#)wBajxt5`Qsb>Pd}9;_gp7Wmx1;J6gl z(<3Jl6Ne?!9dzSeOy|&=s^!5n+Gt_NHDtDUc}orv5t!xn{L?p-o6RHU>VxWqUVc_G z*N~1C*NZ2I?Psr`f2rTCS8dQ$bY}7JGajlMCC$EvVP8UC$S#x$i1(d_G=N~Uyw9!q z=UORLHY+rJH5ME1y1MDHs>`rRVkR}Cq?K$(`!N~GXK#xIDx8YYZC1I*`@!?~thS;G7i{=* z=DOo8cKsV&q>LPWr|=0g$9~C^UH{W*`T7J$;oVHIM8txy1Z@@{Sw-Rx9o>~JiIoHRz`FCHaKh^!?UGCEJ;%uk)foh%)BSz9gTDnBE4T3EKqJRt>5G~!wBJ+sq zlw!Kw)l-+^%)+FnnWtLYK*DQ1p?RFGJ3wVS+wyGT$@-lF9iLQ)xX8UHxeDb662&Iq zW0`7NKry2M?|CfSTj?6ps0utSOCH|mI*CTl2wtSJ?0;9QMs$##C@&R!)eD;T{%GQ+ zLUeiaGAv({5tZCyOc&=!bda1M@?#(((YSakE3+LcBwT7CaWxQ-9|<2$rSG{N!B46K z=E&HT@xT>5i~IkQZp*yPVCw=o^!TdAp*rEDBL58$npnx~+ zeWZ_iVzfOe^H-6fvcGijD;~;5fUsaWz9780u|%${vN}UOO0FCpOIjzdkwt{*=P{V8 z8X4Hz2UzPwy=X1yZ&%A<3lm>YjGsdyTdyL}v(3)B9H>zd=W%N?4xrvU(tW$&}#RDL5z^#IJnn2!lHGNXr%gHnGUTmFMZp zoyy754=LalfM6zw%frfIqFKtBH}hK=zy79^Aa(`CK@3p{>Luu#RXI@sHl^so1t561 znP2{tf)&iRL$5qmZyjP=H*tIy2q+$GCHggZY_J>R03S9w@8QPiO=|DUaIlc4nEeYo zDgb1*XU)BO%|!bFiAWEc4R!_1*G>J@V)>E>$Haa&ZOfJ1;lap4b;tD69hP|;js;Yo zoR$WY_Ej(CSc*}`->8^%4~QdUUwfxlTJ+j&)R>~m(P9BL6M~;GhA1Tf*3lwyf;gd2 z=F<(%sKt&<{8~&&e<30P8_zUWYrSX+4=XJ|2OkweCBox3uDtyl%MXG1#;EF5!MZ8t{PmBhUvZ_EZYMig~JtNI6xSFa|*{ zD6kM57$}WcI92%m`+rU>^96i0ke%wGm9nWqr6o0w(B}q%5$}`%w_UD&RFFa4zfs>T zLv7O+Oi6NqM61DQCb22Ovvwc`EUuhMUSNgK<8dZ*;cO1OIW0Ru=BrYA$xuuQ8ZxkK72rUUT>z=VTnX5wxPo(0gpm=Q zkwCGwYV>XZS0-AQh-7_%(|;0RsDzF^tjIirW6T=4~2Ar%cPyv{?P@)_E#2;CyqzP}fe z0T13JNW>Vk$}L62C>IsE=1mpOyCMgq#+oNaeSi{LH;MD@{I`_%=JEd}!4%MkVz|UF zErgFNz`sJ{f&pnbXn`?FQXfy!GECI%^Ip{(n=3IKa)K0|%*^Pi5HdT(Io+{%Q+W|0 O#iLYCt?egXk '{e_PLUGIN}gallery/images/butterfly.jpg', 'expected'=>'/thumb.php?src=e_PLUGIN%2Fgallery%2Fimages%2Fbutterfly.jpg&w=300&h=200'), - array('path' => '{e_PLUGIN}dummy/Freesample.svg', 'expected'=>'/e107_plugins/dummy/Freesample.svg'), + 0 => array( + 'path' => '{e_PLUGIN}gallery/images/butterfly.jpg', + 'options' => array('w'=>300, 'h'=>200), + 'expected' =>'/thumb.php?src=e_PLUGIN%2Fgallery%2Fimages%2Fbutterfly.jpg&w=300&h=200' + ), + 1 => array( + 'path' => '{e_PLUGIN}dummy/Freesample.svg', + 'options' => array('w'=>300, 'h'=>200), + 'expected' =>'/e107_plugins/dummy/Freesample.svg' + ), + 2 => array( + 'path' => '{e_PLUGIN}gallery/images/butterfly.jpg', + 'options' => array('w'=>300, 'h'=>200, 'type'=>'webp'), + 'expected' =>'/thumb.php?src=e_PLUGIN%2Fgallery%2Fimages%2Fbutterfly.jpg&w=300&h=200&type=webp' + ), ); foreach($urls as $val) { - $actual = $this->tp->thumbUrl($val['path'], array('w'=>300, 'h'=>200)); + $actual = $this->tp->thumbUrl($val['path'],$val['options']); $this->assertStringContainsString($val['expected'], $actual); //echo $$actual."\n\n"; @@ -562,12 +575,38 @@ while($row = $sql->fetch()) { } - +*/ public function testThumbCacheFile() { + $tests = array( + 0 => array( + 'file' => 'e107_plugins/gallery/images/butterfly.jpg', + 'options' => array ('w' => 222, 'h' => 272, 'aw' => 0, 'ah' => 0, 'c' => 0,), + 'expected' => array('prefix'=>'thumb_butterfly_', 'suffix'=>'.jpg.cache.bin'), + ), + 1 => array( + 'file' => 'e107_plugins/gallery/images/butterfly.jpg', + 'options' => array ('w' => 222, 'h' => 272, 'aw' => 0, 'ah' => 0, 'c' => 0, 'type'=>'webp'), + 'expected' => array('prefix'=>'thumb_butterfly_', 'suffix'=>'.webp.cache.bin'), + ), + + ); + + foreach($tests as $var) + { + + $result = $this->tp->thumbCacheFile($var['file'], $var['options']); + + $this->assertStringStartsWith($var['expected']['prefix'], $result); + $this->assertStringEndsWith($var['expected']['suffix'], $result); + + } + + + } - +/* public function testText_truncate() { @@ -944,6 +983,9 @@ while($row = $sql->fetch()) $result4 = $this->tp->toImage($src, ['loading'=>'lazy']); $this->assertStringContainsString('loading="lazy"', $result4); // src + $result5 = $this->tp->toImage($src, ['type'=>'webp']); + $this->assertStringContainsString('&type=webp', $result5); // src + } public function testThumbSrcSet() diff --git a/e107_tests/tests/unit/e_thumbnailTest.php b/e107_tests/tests/unit/e_thumbnailTest.php index b4fc59c11..264801584 100644 --- a/e107_tests/tests/unit/e_thumbnailTest.php +++ b/e107_tests/tests/unit/e_thumbnailTest.php @@ -27,7 +27,7 @@ } catch(Exception $e) { - $this->assertTrue(false, "Couldn't load e_thumbnail object"); + $this->assertTrue(false, $e->getMessage()); } $this->thm->setCache(false); @@ -157,7 +157,13 @@ ), - + // Test Converting JPEG to WebP and resize. (Stored index file is saved with a .jpg extension but encoded as WebP) + 17 => array ( + 'src' => 'e_PLUGIN/gallery/images/butterfly.jpg', + 'w' => 222, + 'h' => 272, + 'type'=>'webp' + ), );