web/lib/Zend/Gdata/HttpClient.php
author Thibaut Cavalié <thibaut.cavalie@iri.centrepompidou.fr>
Fri, 20 Jun 2014 10:54:14 +0200
changeset 1133 7af603663d1e
parent 807 877f952ae2bd
child 1230 68c69c656a2c
permissions -rw-r--r--
correct folder

<?php
/**
 * Zend Framework
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://framework.zend.com/license/new-bsd
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@zend.com so we can send you a copy immediately.
 *
 * @category   Zend
 * @package    Zend_Gdata
 * @subpackage Gdata
 * @copyright  Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 * @version    $Id: HttpClient.php 24593 2012-01-05 20:35:02Z matthew $
 */

/**
 * Zend_Http_Client
 */
require_once 'Zend/Http/Client.php';

/**
 * Gdata Http Client object.
 *
 * Class to extend the generic Zend Http Client with the ability to perform
 * secure AuthSub requests
 *
 * @category   Zend
 * @package    Zend_Gdata
 * @subpackage Gdata
 * @copyright  Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 */
class Zend_Gdata_HttpClient extends Zend_Http_Client
{

    /**
     * OpenSSL private key resource id
     * This key is used for AuthSub authentication.  If this value is set,
     * it is assuemd that secure AuthSub is desired.
     *
     * @var resource
     */
    private $_authSubPrivateKeyId = null;

    /**
     * Token for AuthSub authentication.
     * If this token is set, AuthSub authentication is used.
     *
     * @var string
     */
    private $_authSubToken = null;

    /**
     * Token for ClientLogin authentication.
     * If only this token is set, ClientLogin authentication is used.
     *
     * @var string
     */
    private $_clientLoginToken = null;

    /**
     * Token for ClientLogin authentication.
     * If this token is set, and the AuthSub key is not set,
     * ClientLogin authentication is used
     *
     * @var string
     */
    private $_clientLoginKey = null;

    /**
     * True if this request is being made with data supplied by
     * a stream object instead of a raw encoded string.
     *
     * @var bool
     */
    protected $_streamingRequest = null;

    /**
     * Sets the PEM formatted private key, as read from a file.
     *
     * This method reads the file and then calls setAuthSubPrivateKey()
     * with the file contents.
     *
     * @param string $file The location of the file containing the PEM key
     * @param string $passphrase The optional private key passphrase
     * @param bool $useIncludePath Whether to search the include_path
     *                             for the file
     * @return void
     */
    public function setAuthSubPrivateKeyFile($file, $passphrase = null,
                                             $useIncludePath = false) {
        $fp = @fopen($file, "r", $useIncludePath);
        if (!$fp) {
            require_once 'Zend/Gdata/App/InvalidArgumentException.php';
            throw new Zend_Gdata_App_InvalidArgumentException('Failed to open private key file for AuthSub.');
        }

        $key = '';
        while (!feof($fp)) {
            $key .= fread($fp, 8192);
        }
        $this->setAuthSubPrivateKey($key, $passphrase);
        fclose($fp);
    }

    /**
     * Sets the PEM formatted private key to be used for secure AuthSub auth.
     *
     * In order to call this method, openssl must be enabled in your PHP
     * installation.  Otherwise, a Zend_Gdata_App_InvalidArgumentException
     * will be thrown.
     *
     * @param string $key The private key
     * @param string $passphrase The optional private key passphrase
     * @throws Zend_Gdata_App_InvalidArgumentException
     * @return Zend_Gdata_HttpClient Provides a fluent interface
     */
    public function setAuthSubPrivateKey($key, $passphrase = null) {
        if ($key != null && !function_exists('openssl_pkey_get_private')) {
            require_once 'Zend/Gdata/App/InvalidArgumentException.php';
            throw new Zend_Gdata_App_InvalidArgumentException(
                    'You cannot enable secure AuthSub if the openssl module ' .
                    'is not enabled in your PHP installation.');
        }
        $this->_authSubPrivateKeyId = openssl_pkey_get_private(
                $key, $passphrase);
        return $this;
    }

    /**
     * Gets the openssl private key id
     *
     * @return string The private key
     */
    public function getAuthSubPrivateKeyId() {
        return $this->_authSubPrivateKeyId;
    }

    /**
     * Gets the AuthSub token used for authentication
     *
     * @return string The token
     */
    public function getAuthSubToken() {
        return $this->_authSubToken;
    }

    /**
     * Sets the AuthSub token used for authentication
     *
     * @param string $token The token
     * @return Zend_Gdata_HttpClient Provides a fluent interface
     */
    public function setAuthSubToken($token) {
        $this->_authSubToken = $token;
        return $this;
    }

    /**
     * Gets the ClientLogin token used for authentication
     *
     * @return string The token
     */
    public function getClientLoginToken() {
        return $this->_clientLoginToken;
    }

    /**
     * Sets the ClientLogin token used for authentication
     *
     * @param string $token The token
     * @return Zend_Gdata_HttpClient Provides a fluent interface
     */
    public function setClientLoginToken($token) {
        $this->_clientLoginToken = $token;
        return $this;
    }

    /**
     * Filters the HTTP requests being sent to add the Authorization header.
     *
     * If both AuthSub and ClientLogin tokens are set,
     * AuthSub takes precedence.  If an AuthSub key is set, then
     * secure AuthSub authentication is used, and the request is signed.
     * Requests must be signed only with the private key corresponding to the
     * public key registered with Google.  If an AuthSub key is set, but
     * openssl support is not enabled in the PHP installation, an exception is
     * thrown.
     *
     * @param string $method The HTTP method
     * @param string $url The URL
     * @param array $headers An associate array of headers to be
     *                       sent with the request or null
     * @param string $body The body of the request or null
     * @param string $contentType The MIME content type of the body or null
     * @throws Zend_Gdata_App_Exception if there was a signing failure
     * @return array The processed values in an associative array,
     *               using the same names as the params
     */
    public function filterHttpRequest($method, $url, $headers = array(), $body = null, $contentType = null) {
        if ($this->getAuthSubToken() != null) {
            // AuthSub authentication
            if ($this->getAuthSubPrivateKeyId() != null) {
                // secure AuthSub
                $time = time();
                $nonce = mt_rand(0, 999999999);
                $dataToSign = $method . ' ' . $url . ' ' . $time . ' ' . $nonce;

                // compute signature
                $pKeyId = $this->getAuthSubPrivateKeyId();
                $signSuccess = openssl_sign($dataToSign, $signature, $pKeyId,
                                            OPENSSL_ALGO_SHA1);
                if (!$signSuccess) {
                    require_once 'Zend/Gdata/App/Exception.php';
                    throw new Zend_Gdata_App_Exception(
                            'openssl_signing failure - returned false');
                }
                // encode signature
                $encodedSignature = base64_encode($signature);

                // final header
                $headers['authorization'] = 'AuthSub token="' . $this->getAuthSubToken() . '" ' .
                                            'data="' . $dataToSign . '" ' .
                                            'sig="' . $encodedSignature . '" ' .
                                            'sigalg="rsa-sha1"';
            } else {
                // AuthSub without secure tokens
                $headers['authorization'] = 'AuthSub token="' . $this->getAuthSubToken() . '"';
            }
        } elseif ($this->getClientLoginToken() != null) {
            $headers['authorization'] = 'GoogleLogin auth=' . $this->getClientLoginToken();
        }
        return array('method' => $method, 'url' => $url, 'body' => $body, 'headers' => $headers, 'contentType' => $contentType);
    }

    /**
     * Method for filtering the HTTP response, though no filtering is
     * currently done.
     *
     * @param Zend_Http_Response $response The response object to filter
     * @return Zend_Http_Response The filterd response object
     */
    public function filterHttpResponse($response) {
        return $response;
    }

    /**
     * Return the current connection adapter
     *
     * @return Zend_Http_Client_Adapter_Interface|string $adapter
     */
    public function getAdapter()
    {
        return $this->adapter;
    }

   /**
     * Load the connection adapter
     *
     * @param Zend_Http_Client_Adapter_Interface $adapter
     * @return void
     */
    public function setAdapter($adapter)
    {
        if ($adapter == null) {
            $this->adapter = $adapter;
        } else {
              parent::setAdapter($adapter);
        }
    }

    /**
     * Set the streamingRequest variable which controls whether we are
     * sending the raw (already encoded) POST data from a stream source.
     *
     * @param boolean $value The value to set.
     * @return void
     */
    public function setStreamingRequest($value)
    {
        $this->_streamingRequest = $value;
    }

    /**
     * Check whether the client is set to perform streaming requests.
     *
     * @return boolean True if yes, false otherwise.
     */
    public function getStreamingRequest()
    {
        if ($this->_streamingRequest()) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * Prepare the request body (for POST and PUT requests)
     *
     * @return string
     * @throws Zend_Http_Client_Exception
     */
    protected function _prepareBody()
    {
        if($this->_streamingRequest) {
            $this->setHeaders(self::CONTENT_LENGTH,
                $this->raw_post_data->getTotalSize());
            return $this->raw_post_data;
        }
        else {
            return parent::_prepareBody();
        }
    }

    /**
     * Clear all custom parameters we set.
     *
     * @return Zend_Http_Client
     */
    public function resetParameters($clearAll = false)
    {
        $this->_streamingRequest = false;

        return parent::resetParameters($clearAll);
    }

    /**
     * Set the raw (already encoded) POST data from a stream source.
     *
     * This is used to support POSTing from open file handles without
     * caching the entire body into memory. It is a wrapper around
     * Zend_Http_Client::setRawData().
     *
     * @param string $data The request data
     * @param string $enctype The encoding type
     * @return Zend_Http_Client
     */
    public function setRawDataStream($data, $enctype = null)
    {
        $this->_streamingRequest = true;
        return $this->setRawData($data, $enctype);
    }

}
2Uhd40qU*Tn=dLU<^FAAhGj/ٸjPd2Fj2#cn o -pxQUX0< 2 X`6 WuX?T=zpz20`ʉAUe1V U~EJCچ0`lA&CAgRd0`"KG0C}\]xxCY W!V>$޷ Wd X+*lcb%8*ħ pV*UܫX0002U~rv:`KYVU``U.gWE0`^c`"p="WL%e %j_8h`V`ʭ Ui x`*tR# KQyĭ 60` :UheVHCc$],U-j(n %nFՔ3W+ccPz2!S *CEHu*^`C 40eg0vdBλ닮oV5g?H'HdnԋnQuzÀ7 *顱J9Cjʲjޫp4  "V Dr0` C UenJ{P 0` 0` 0` 0` 0` 0` 0` 0` 0` 0j 0` 0` 0wʭ$Z:L Ch22 "d0dY jJ]n)2  !j*!ѕJÕ~8u#kTQ$tD*$g0t` h~yP{֗x{U9QxCڻg-gkV.>ϓc~8y0zZ]9n5V|;G;`W5qT8rQ7 ⭃`ڭx1ZqT2jtUd9se'5Un C!̭*[r9 Fʹ [mW5\ PqCT;%t?L8 ^WCUOyU_90jEqߋJC!ٌd0vChe 1W7 n̲*CCCCCCAի#yp<0r0rcc5 ;0wcvGCc!`=GQ6668Ɔ #cxF"zVvڮ8@4pv ;@00'`nAVp=4: Ay62PyA6;luE` "åWq- 64;Cz Lj:a:F es\eqƻUr:-p8=G71GCE8az!0vP:140`#cwQoVU]CƮj7 `l 40нj8cyv 1=QvcCp5h`0v#ld60xC66=clfjՖCE48 2̲ c px :CPC0l`Z49#CCCP0m  T4: ;C:!y )445"xyZEC )^>V}VP0`"$0`2*d42UP/ D UEJRbRjPt0` 0` {"RP3JL"_C0`({"Gw}mI~CHI_X̆*aX0`&CQb/8~uy|dX0`{~ad0CHqq~?1 ZH`V0hjVH 49P|5w7|CM U(qU3=c;yG#6>p5Ur; s !0z!9qwCy (ljv0lwCC` Ad8vUxbQЂa)SVs`VC {Pz>/Zs{Ϟ3pYUwd2̲| *KTV Ed1eV"#I5T9.F;+Jȵ"d2E>#H}HƃCCq+=ȵ"0a+!ePd`44460`ʫpʪ JAA|ۼcIO'I%<y~0` h` 5 0` 0hh` ; !%/zPu= Uf CZZUd>ꍏ?D=%5KCu0V vz 5 $̂9 5C1*#.zC-/ [}*C%~R!0hli hhl`E#!d21C!Vtw|U p47 ixxH*z"aar+(x =a{Ľ5Uh`!X2E`i0`#j҆UbU D|ڟ!ecEq!: _\bW6ROC"|PXv/ \C5U67 CU[(]Q^xvU<]||FǕU 0` S֬0d`YAҤ>H=WΌXB Nʻ/dd_x0bR Ca$2ﻍZ!uE/pԋ*? =/  CT?MC$X6c0~CC ETi`JHn z rܫSnϥ^;>5CcᱪJj P7X|ArCpu Q4Gqtwcd9E`V; Q4Gb !چZ~:_eᓤ0,"YUd2I!%!tRb,"?}^h~H}/u``01VJeX UhA+žclj4F+nEO8p5CF*Uhb/ Pjjahp0p2V"8;Cc;5w~Hn!:!Py ^2hw2ΫdT2 beRⲭPA>^eT$5 >#!!>q'x`+wX0d r aC 40bCj^ JMP՜Re {~80`/I.*UV"XbnVKʇ} 0` 0`CCPU UZ1V)6D] X3 YUeU 5Hު+{*C {T<견U]4U֊o\'\XUSGchr60uYPүC!LCUUJu;UR^(d?B_pVU`ʬdXfJ`2Sc򡒓R-ȸ0`ʹ `(}#}UqU|{`0d>E"(|aVM?b(d>`XJ45 +PEhd1Vjd UTx}kSZ+­uZ*МVd02 62`ʬ 1Pjߥ)C*ʰ02CP򹇄2 BeVC(eT0j Bgz"V 2E*eV ZC!`_Nz/ PP7;!{!B1VUʫyPaH}(U}.b|`bVT*ڬ 7Up69 9:ad0`7UÁ8_sC܋5"Ҵ%<{A\E 0`CVd1VCYyr!]Cx0`u$㲥GJ|Lz) UY^w AVCCC 0u_uUċVCo)ʹCjcpݐʬr+P; 0`vp8g\beL5V4M1ʭCPVeCVH"V* 0jHC  b, 0`ʬV `1IԋXhhh`Hd0d0`*UZ0`j [8 CCC*!dPhh` Te !\?@cVeX0b XSW㲩*p$JyR=*`*P/fY CC! 0`U ,ʬUK1j$KAd:Hx׈0` op̋xe|=!H\!_\Jg90` 0` 0` 0` 0` 0` 0` >q+A٪/ J$Ed8xJ\Uj'Uy<9s"#D¯!]SC*2 UxUvE!< 4P7xU v*UX=F7u[}ȱ-aJjU)R6C / *d0b- ʫUY CCC`U*40hi)xIS 8**UW"5#EE?X"Äʭpp0`u<_g:G_Zʇ+d[_n0`Uvr8YCt*2VPj H d*"xP*ZIKde[F Á?5Gqv anq!cC*90싑thuƆFà8Ax Cu!tc; r*0:[յ]r6;60lr44; c%d9U^7UvU]hd22 * hn8݃)T{C\33,`(e, 0hp8  l`|G~گ!XLP^(kXV$Nl lKxh5Vh *Ud5UY a`hnVԞ񱪬pV궤liP2p<{8PBC =!u%^^#jc48`iW* h`jY0UZU}70hj5C}܋mJC[5CJ(b,Zzmy_&3, ا\"Y E e;=xA|yC/\(%/JAچA.i%EC!ʇxh`Z40d*sz S*Gniټ7j ܪnntƕ`ZU׮o|*ֶ8˅\q\*㍎2Wln{Ɛ¡ 0EJ^ڡp48F#{Ž[ғ⫀O +\2 C:e* tH .8d2bCRad*iDK_UW}O:!E|`HHn CRL$>`~Oɴ6 mVe)2C2:Wva.a|]/A!/ +ơ]-"u `b9UҢlBʬeVI/`$5oyPH  UiW/2E!X1)`ot10`y({C2"WJX`b(bS!{j;0` 0` 0` 0` =¡s%eV;Z̋c! CaCuUԌ `bHBneX ]lUM=~mջV|AҪU_u 5[W#8#`vƬsAҫuZr;a98aQ:R, Ê".* P[_sJO0`Ҫ`"WK!c 2ȷX {w(?E `@C}.!jTt  P ""UU EP PUH URDQP@!%BJR@*)BR P )@PJPPP!# &Sd@h a08ѣA@hhѠѠhdh " "dț L*~R&GOPژzJDAdi2dɢzOHh4??7癙eT%<5??H;E|FnwݷABFJO5UnECU( hk2K0 j(`fY5T~/_]F!P*%KU40b(կՒ0 0+(^8Z5B%,R0!^}{|JWrkz 6HKaŊň"N{ ס3, jQN)t]R#%J{`dFuvynYJ~a\$^#ޟ< bJ2Y6|b+1~@pcM ըJ5oX{%_  #޹em]v%t3kվK,aHedc!%ZaqDYUƬ k*4pLQ%kUjI-VJ ԬS?YJ& 2צv70rytc@KC>8t8#l|I`C:GFQ9)C漱O{x$2S@Cf?N">@G$hʯ\&#,6闆Ԯ')jqxC#P qNb%XUpnʱ}eYV{a{|G5YU!ppt zWZ99Ǡ]5YS= @V*UuCuGV`1V`8jUb eXz``GA*ʻ*] Y9 U^CqIw*h000@`l>ah4S:WeXAM6anw?iVA]¯^j*A­*! x\d§ V[06U2qVUZWBXUzz U]J)WjYNC櫐uP8*F0UUc# sUe ¤P2*2=*A**AWqVJeX*X 5(jlz]AU`e(j6<ar7 JUƫX=:`<mWr ^IM\C2CZUZ@ n/Q?/Ϛj?Ʒ[[rTUptxB e6Q=?.5*~*np666662HP8n8eCP- 0`7 Pj!q hdJ2qCU 8H9.aY j82CSђvvTZAH( PqnC!C"49#=aFƇwcQ?6<ǀp8Q=FGaG#H<`2G=a`9 allu#GAt>cuq?{r=FCyhp>yall|Fa;LjvP?q/ 2X4:8#P,d;G 4=GAp:t70v8CC{/QvQl{x 4<`b.F hp0t A:P 櫥V9Cl?]C]x`8p`:v 44 h h8 `yx:`uu !60À?0>4 axl=}a[Ch6A6uyp8h::x!!=tA 0P+UyA<ǠAylr>ccCÑ9#C}c1G ; qp0`8 6880u#C0p!xQ<A01!8Eyc4IKNTU_PUN(; dUtELUV XZXDʧ2`0f 3`0f Q*e"a WQx jR`U2Ub//!#C9RACC\B͘Vl+dVnVKGtVn6҇hv#ƫs&f^;;zzlu}㧠Uy 2ybψ~we=Gw(}+WǧQ*<*ON;ՕZƱ!ZӞzxZ-c靲[uDk#RX5FkQ fkt^ÎAo<ǀ?xcGȟK/:Ch~w; ![Ph`<ƇA9?`CCh}CcC0wLjcC42Ƈ#G#Ǹ;h`0{ CAl|698ah`yG>th|0x="r28ǰ># !p860`:xbCQ#Cz qp4;hz <4^Á#xl|=ǘ0r20`p0hv C0r1!;E7WzU0606a6Xu :|ÀtPh` 4Ar {=ACu x l;}|A@@{`} 6x``>!<l8 h=ʾcU]Gcp9FƇh`5Ca8`qad4=X{! 8!n !hjC`8#^0<.vDŽ:>#`w8N_Oc?q4?톡\?|q8j`U]\|1I=URzeES0f 3`22pĪV&p6=itE=!`lr60hlqÒWJ)b摼a, 5ʰkC)(d0BQ/>#%hd20e,J EF#p+49E~1+Ǒ`hhd0~:hhlnhb-44JwEua:``}-IdKj Zh;h~vq̋K*4J%Ĥ%J:H&aV1I f U:P,v"Mk3PhfC5kY ֆfk42hfP̔} mV *(x*` 0`40h`b- (hh|lllljF 0` 0` 0mWap8Gr8:45 7<Q0yC#r?r?}Cd8Cp4<09p:CccCIWG#: 0n0` 0` 0`0`> <A 0`  !.FyJ< A`:FWJE 0`#440` 0` :CC 0` 0` 0` 0`?(`CCC 0` ;={ccتvG0J; ðllp69膆}FƆƇƆ F=Wc.(!p?e~q"o,PՒ-C!= Uxa0hh`xĮWt:ΡC{çkC4;  0`p664PÁiP'CaT:E{{FGG#0` 0` 0` 0` 0` 0` 0` 0` 0` 0`jCxYUe|AU@CCZ# 0`ac{t90lp0p2 *CP: 0` 0` ?dJ;= ø5PC8?8"0lr9 r8H F᱐; Ahs) H 0`Q/!#CccHr90` 0` 0` 0h:cc Ccc ?D>H_99A|$\U]!U2?22# 0eVtY > 0`(<* 0` 0`PXVYVGꇰ;0` 0` 8{X2R~JEjCa|Q^\U`gq` DC G.+\ZH vCU_U>?j#0y^U"Zy0`..z_E D^?6EU42ECp95]*l6)UX**Y :!5jtApiW!W"WXd j(etrB{Ah00000000000000000000000000000000000000000000004W``````````````````````jU׾˶P "`bCH2AQ%T,\r2H d1U`d0:~8jR!UGM?2D)uF{UOh}#s CDjR@^䄧p^Uvf>}>G:wNrԱx{~w?wjwʫpcW!9jC:UZ?8cul6 ⑰ʰ-hhU> 4  Ҭ ]*ʲ;Cn0lv 8qV A!UyÊxCPꫀxWYVU[VPd:Z Į "wH|n*[ykX3\UU3!cH`V *X0hhj|-xU[!*U].4x[`/Uʫ!C(\hr9pCW5]Uޫ`34;<#cPU;ørCuwuj*<!d! ! ]"WJU]R.yEֆ>D]FH`PhJu] & =T{eC=F atQ:FUBb1`UL“csV歪C:="C!,GVUҭڑԫeX>LVF b!e 0`UȪeV5 U^U| tKE=${ Ah4 AZ A!OvUuh|||X02y14U*fjث*/AeWWQ RCj4hbT{C UWUu'*W!):~ׄ8Z})eU`eUjCC`,EeV*Er0d2!d2UUm*UǀxIi@UpYVÀJWJb V)J]P:‘^AU.Uh`uZ ?2,#qUUXb:*eYVeX#rYSHT}A^* Az3!,f`eX(ʱ!C2xĮQ+T`d>ue'E,b+EUCC0zҟ9v {>WFԉSiO3Cj}ȿ,0d0e P5<dW 4 UX  E Pʊ8`"sE5O$2\UIWUp*حU[ 6:FCZ UxvUh04y:sNxat;ÑCU^]*CtTU` ;P܋UCCr!~I\}OƫL%*LU<~8y1!!ܫ5V=nxV0 @`1TUPAʆCUYTMWX;Cc:ePv UVUMP;qa;!O:U`UZ$CV ;VYf`Y`f`fe`X6JCuP|DDkd_5|`=U*U`eD_J0eU!1 j5 Ueπ= MGƆC"ddU󆡒ZDJnyA04h4 AԣY"凕>VC*(x=X(jSR¬,htEXAiVh1)ʦ_pWV*>sUj5OZj>*sBBګޫ=pCAҭU0`ZNX.mVyLDMDMTLdo*2dd8օeUҨq ڭ`j`p6=G#UґeCU_ eU`X2U#ήO ~EX~,jK`~HRMAn Id?Cx~eW%\C>`>P`>!*ԤU_Idy08UԣTXUSJ 5 BVCCT1#Ù7V* U V*ʰ4,c!j  (*ZUZA|r ``!02YU(g* C(YzCCuX2~AyAyʫ'8xP†,Rli"ʬxp68"Zʬ UyCUzVPW aLU0eV C!d2C!2@? U*U*HRUe*hsCb,}p"CCҪUA`'eX+)Cƪ8`*8`|}}}R{ʔ*X *W CccCuWW[櫁t 9u]*~{{ UM ^تP|*bSXVUd!~1Ăÿzt]Us"ߒWX U􊹫^W+0!(0BȪ||VCƪ֪l7 CCCCCR-PU PʫT2cp67T|FƆC0d4667Tp64pԋ(j PjU`0`R툼ahp48 ,= 0}PʭU`42U]d^` ZU֪U5!x4K~m=AUX*/{2WECe HzQ24!d1C§5u|/q}ڇYƪ) w dkQI@^eX U;YV%5V*ʠ^R<*`{ 5C 0`"0a' _QAU^ s"e\պqW=Į6^%}Ub\v`2l=tʕ3<.Q{H^p~WHtUx2 "bBt?PY d.OԼa`֣Q*zl*i߫*ŒJyNA~_VC_UҝI0eU~/\ 0>{T*!eW_V*@fAU8JpeWJ] CD(~E_e#0ʲ/)dU02VR':*``j_ڻ}C\ 5Y ~}}PUSQ``b,ȕ0`*d/0eW<Ƥ:P?nU;C<8v/bBe `©WUs^Gjʳ, 1h2 FXVc* FU`eYƪf2*ʬ0` 2Wzx5VCe$Z᪚ZU:hz*P|iVR2Tnbb0dC`gυeT~XuU Xr:FƇ5\vʫ\ðˮ2!uFƇ5\u⫵W5]8as!>CL2"EaeU5Hq!>c0`9%p80``OHun(~\P)z,,*((_; J0iM004( ~JzEHS#M4bd@!h&&i.$r?W.H !#$zGk1b 22%䲹Â|%Z\U2@i<ˎdvVV!h8# vҩKy1kro]C}Ϩ!hbcWˆ^(ՒY