web/lib/Zend/Cache/Backend/File.php
author Yves-Marie Haussonne <1218002+ymph@users.noreply.github.com>
Thu, 14 Jun 2018 18:13:05 +0200
changeset 1423 a6ed32f6dbcf
parent 1230 68c69c656a2c
permissions -rw-r--r--
add 2018 preparatoire

<?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_Cache
 * @subpackage Zend_Cache_Backend
 * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 * @version    $Id$
 */

/**
 * @see Zend_Cache_Backend_Interface
 */
require_once 'Zend/Cache/Backend/ExtendedInterface.php';

/**
 * @see Zend_Cache_Backend
 */
require_once 'Zend/Cache/Backend.php';


/**
 * @package    Zend_Cache
 * @subpackage Zend_Cache_Backend
 * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 */
class Zend_Cache_Backend_File extends Zend_Cache_Backend implements Zend_Cache_Backend_ExtendedInterface
{
    /**
     * Available options
     *
     * =====> (string) cache_dir :
     * - Directory where to put the cache files
     *
     * =====> (boolean) file_locking :
     * - Enable / disable file_locking
     * - Can avoid cache corruption under bad circumstances but it doesn't work on multithread
     * webservers and on NFS filesystems for example
     *
     * =====> (boolean) read_control :
     * - Enable / disable read control
     * - If enabled, a control key is embeded in cache file and this key is compared with the one
     * calculated after the reading.
     *
     * =====> (string) read_control_type :
     * - Type of read control (only if read control is enabled). Available values are :
     *   'md5' for a md5 hash control (best but slowest)
     *   'crc32' for a crc32 hash control (lightly less safe but faster, better choice)
     *   'adler32' for an adler32 hash control (excellent choice too, faster than crc32)
     *   'strlen' for a length only test (fastest)
     *
     * =====> (int) hashed_directory_level :
     * - Hashed directory level
     * - Set the hashed directory structure level. 0 means "no hashed directory
     * structure", 1 means "one level of directory", 2 means "two levels"...
     * This option can speed up the cache only when you have many thousands of
     * cache file. Only specific benchs can help you to choose the perfect value
     * for you. Maybe, 1 or 2 is a good start.
     *
     * =====> (int) hashed_directory_umask :
     * - deprecated
     * - Permissions for hashed directory structure
     *
     * =====> (int) hashed_directory_perm :
     * - Permissions for hashed directory structure
     *
     * =====> (string) file_name_prefix :
     * - prefix for cache files
     * - be really carefull with this option because a too generic value in a system cache dir
     *   (like /tmp) can cause disasters when cleaning the cache
     *
     * =====> (int) cache_file_umask :
     * - deprecated
     * - Permissions for cache files
     *
     * =====> (int) cache_file_perm :
     * - Permissions for cache files
     *
     * =====> (int) metatadatas_array_max_size :
     * - max size for the metadatas array (don't change this value unless you
     *   know what you are doing)
     *
     * @var array available options
     */
    protected $_options = array(
        'cache_dir' => null,
        'file_locking' => true,
        'read_control' => true,
        'read_control_type' => 'crc32',
        'hashed_directory_level' => 0,
        'hashed_directory_perm' => 0700,
        'file_name_prefix' => 'zend_cache',
        'cache_file_perm' => 0600,
        'metadatas_array_max_size' => 100
    );

    /**
     * Array of metadatas (each item is an associative array)
     *
     * @var array
     */
    protected $_metadatasArray = array();


    /**
     * Constructor
     *
     * @param  array $options associative array of options
     * @throws Zend_Cache_Exception
     */
    public function __construct(array $options = array())
    {
        parent::__construct($options);
        if ($this->_options['cache_dir'] !== null) { // particular case for this option
            $this->setCacheDir($this->_options['cache_dir']);
        } else {
            $this->setCacheDir(self::getTmpDir() . DIRECTORY_SEPARATOR, false);
        }
        if (isset($this->_options['file_name_prefix'])) { // particular case for this option
            if (!preg_match('~^[a-zA-Z0-9_]+$~D', $this->_options['file_name_prefix'])) {
                Zend_Cache::throwException('Invalid file_name_prefix : must use only [a-zA-Z0-9_]');
            }
        }
        if ($this->_options['metadatas_array_max_size'] < 10) {
            Zend_Cache::throwException('Invalid metadatas_array_max_size, must be > 10');
        }

        if (isset($options['hashed_directory_umask'])) {
            // See #ZF-12047
            trigger_error("'hashed_directory_umask' is deprecated -> please use 'hashed_directory_perm' instead", E_USER_NOTICE);
            if (!isset($options['hashed_directory_perm'])) {
                $options['hashed_directory_perm'] = $options['hashed_directory_umask'];
            }
        }
        if (isset($options['hashed_directory_perm']) && is_string($options['hashed_directory_perm'])) {
            // See #ZF-4422
            $this->_options['hashed_directory_perm'] = octdec($this->_options['hashed_directory_perm']);
        }

        if (isset($options['cache_file_umask'])) {
            // See #ZF-12047
            trigger_error("'cache_file_umask' is deprecated -> please use 'cache_file_perm' instead", E_USER_NOTICE);
            if (!isset($options['cache_file_perm'])) {
                $options['cache_file_perm'] = $options['cache_file_umask'];
            }
        }
        if (isset($options['cache_file_perm']) && is_string($options['cache_file_perm'])) {
            // See #ZF-4422
            $this->_options['cache_file_perm'] = octdec($this->_options['cache_file_perm']);
        }
    }

    /**
     * Set the cache_dir (particular case of setOption() method)
     *
     * @param  string  $value
     * @param  boolean $trailingSeparator If true, add a trailing separator is necessary
     * @throws Zend_Cache_Exception
     * @return void
     */
    public function setCacheDir($value, $trailingSeparator = true)
    {
        if (!is_dir($value)) {
            Zend_Cache::throwException(sprintf('cache_dir "%s" must be a directory', $value));
        }
        if (!is_writable($value)) {
            Zend_Cache::throwException(sprintf('cache_dir "%s" is not writable', $value));
        }
        if ($trailingSeparator) {
            // add a trailing DIRECTORY_SEPARATOR if necessary
            $value = rtrim(realpath($value), '\\/') . DIRECTORY_SEPARATOR;
        }
        $this->_options['cache_dir'] = $value;
    }

    /**
     * Test if a cache is available for the given id and (if yes) return it (false else)
     *
     * @param string $id cache id
     * @param boolean $doNotTestCacheValidity if set to true, the cache validity won't be tested
     * @return string|false cached datas
     */
    public function load($id, $doNotTestCacheValidity = false)
    {
        if (!($this->_test($id, $doNotTestCacheValidity))) {
            // The cache is not hit !
            return false;
        }
        $metadatas = $this->_getMetadatas($id);
        $file = $this->_file($id);
        $data = $this->_fileGetContents($file);
        if ($this->_options['read_control']) {
            $hashData = $this->_hash($data, $this->_options['read_control_type']);
            $hashControl = $metadatas['hash'];
            if ($hashData != $hashControl) {
                // Problem detected by the read control !
                $this->_log('Zend_Cache_Backend_File::load() / read_control : stored hash and computed hash do not match');
                $this->remove($id);
                return false;
            }
        }
        return $data;
    }

    /**
     * Test if a cache is available or not (for the given id)
     *
     * @param string $id cache id
     * @return mixed false (a cache is not available) or "last modified" timestamp (int) of the available cache record
     */
    public function test($id)
    {
        clearstatcache();
        return $this->_test($id, false);
    }

    /**
     * Save some string datas into a cache record
     *
     * Note : $data is always "string" (serialization is done by the
     * core not by the backend)
     *
     * @param  string      $data             Datas to cache
     * @param  string      $id               Cache id
     * @param  array       $tags             Array of strings, the cache record will be tagged by each string entry
     * @param  boolean|int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime)
     * @return boolean true if no problem
     */
    public function save($data, $id, $tags = array(), $specificLifetime = false)
    {
        clearstatcache();
        $file = $this->_file($id);
        $path = $this->_path($id);
        if ($this->_options['hashed_directory_level'] > 0) {
            if (!is_writable($path)) {
                // maybe, we just have to build the directory structure
                $this->_recursiveMkdirAndChmod($id);
            }
            if (!is_writable($path)) {
                return false;
            }
        }
        if ($this->_options['read_control']) {
            $hash = $this->_hash($data, $this->_options['read_control_type']);
        } else {
            $hash = '';
        }
        $metadatas = array(
            'hash' => $hash,
            'mtime' => time(),
            'expire' => $this->_expireTime($this->getLifetime($specificLifetime)),
            'tags' => $tags
        );
        $res = $this->_setMetadatas($id, $metadatas);
        if (!$res) {
            $this->_log('Zend_Cache_Backend_File::save() / error on saving metadata');
            return false;
        }
        $res = $this->_filePutContents($file, $data);
        return $res;
    }

    /**
     * Remove a cache record
     *
     * @param  string $id cache id
     * @return boolean true if no problem
     */
    public function remove($id)
    {
        $file = $this->_file($id);
        $boolRemove   = $this->_remove($file);
        $boolMetadata = $this->_delMetadatas($id);
        return $boolMetadata && $boolRemove;
    }

    /**
     * Clean some cache records
     *
     * Available modes are :
     *
     * Zend_Cache::CLEANING_MODE_ALL (default)    => remove all cache entries ($tags is not used)
     * Zend_Cache::CLEANING_MODE_OLD              => remove too old cache entries ($tags is not used)
     * Zend_Cache::CLEANING_MODE_MATCHING_TAG     => remove cache entries matching all given tags
     *                                               ($tags can be an array of strings or a single string)
     * Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG => remove cache entries not {matching one of the given tags}
     *                                               ($tags can be an array of strings or a single string)
     * Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG => remove cache entries matching any given tags
     *                                               ($tags can be an array of strings or a single string)
     *
     * @param string $mode clean mode
     * @param array $tags array of tags
     * @return boolean true if no problem
     */
    public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array())
    {
        // We use this protected method to hide the recursive stuff
        clearstatcache();
        return $this->_clean($this->_options['cache_dir'], $mode, $tags);
    }

    /**
     * Return an array of stored cache ids
     *
     * @return array array of stored cache ids (string)
     */
    public function getIds()
    {
        return $this->_get($this->_options['cache_dir'], 'ids', array());
    }

    /**
     * Return an array of stored tags
     *
     * @return array array of stored tags (string)
     */
    public function getTags()
    {
        return $this->_get($this->_options['cache_dir'], 'tags', array());
    }

    /**
     * Return an array of stored cache ids which match given tags
     *
     * In case of multiple tags, a logical AND is made between tags
     *
     * @param array $tags array of tags
     * @return array array of matching cache ids (string)
     */
    public function getIdsMatchingTags($tags = array())
    {
        return $this->_get($this->_options['cache_dir'], 'matching', $tags);
    }

    /**
     * Return an array of stored cache ids which don't match given tags
     *
     * In case of multiple tags, a logical OR is made between tags
     *
     * @param array $tags array of tags
     * @return array array of not matching cache ids (string)
     */
    public function getIdsNotMatchingTags($tags = array())
    {
        return $this->_get($this->_options['cache_dir'], 'notMatching', $tags);
    }

    /**
     * Return an array of stored cache ids which match any given tags
     *
     * In case of multiple tags, a logical AND is made between tags
     *
     * @param array $tags array of tags
     * @return array array of any matching cache ids (string)
     */
    public function getIdsMatchingAnyTags($tags = array())
    {
        return $this->_get($this->_options['cache_dir'], 'matchingAny', $tags);
    }

    /**
     * Return the filling percentage of the backend storage
     *
     * @throws Zend_Cache_Exception
     * @return int integer between 0 and 100
     */
    public function getFillingPercentage()
    {
        $free = disk_free_space($this->_options['cache_dir']);
        $total = disk_total_space($this->_options['cache_dir']);
        if ($total == 0) {
            Zend_Cache::throwException('can\'t get disk_total_space');
        } else {
            if ($free >= $total) {
                return 100;
            }
            return ((int) (100. * ($total - $free) / $total));
        }
    }

    /**
     * Return an array of metadatas for the given cache id
     *
     * The array must include these keys :
     * - expire : the expire timestamp
     * - tags : a string array of tags
     * - mtime : timestamp of last modification time
     *
     * @param string $id cache id
     * @return array array of metadatas (false if the cache id is not found)
     */
    public function getMetadatas($id)
    {
        $metadatas = $this->_getMetadatas($id);
        if (!$metadatas) {
            return false;
        }
        if (time() > $metadatas['expire']) {
            return false;
        }
        return array(
            'expire' => $metadatas['expire'],
            'tags' => $metadatas['tags'],
            'mtime' => $metadatas['mtime']
        );
    }

    /**
     * Give (if possible) an extra lifetime to the given cache id
     *
     * @param string $id cache id
     * @param int $extraLifetime
     * @return boolean true if ok
     */
    public function touch($id, $extraLifetime)
    {
        $metadatas = $this->_getMetadatas($id);
        if (!$metadatas) {
            return false;
        }
        if (time() > $metadatas['expire']) {
            return false;
        }
        $newMetadatas = array(
            'hash' => $metadatas['hash'],
            'mtime' => time(),
            'expire' => $metadatas['expire'] + $extraLifetime,
            'tags' => $metadatas['tags']
        );
        $res = $this->_setMetadatas($id, $newMetadatas);
        if (!$res) {
            return false;
        }
        return true;
    }

    /**
     * Return an associative array of capabilities (booleans) of the backend
     *
     * The array must include these keys :
     * - automatic_cleaning (is automating cleaning necessary)
     * - tags (are tags supported)
     * - expired_read (is it possible to read expired cache records
     *                 (for doNotTestCacheValidity option for example))
     * - priority does the backend deal with priority when saving
     * - infinite_lifetime (is infinite lifetime can work with this backend)
     * - get_list (is it possible to get the list of cache ids and the complete list of tags)
     *
     * @return array associative of with capabilities
     */
    public function getCapabilities()
    {
        return array(
            'automatic_cleaning' => true,
            'tags' => true,
            'expired_read' => true,
            'priority' => false,
            'infinite_lifetime' => true,
            'get_list' => true
        );
    }

    /**
     * PUBLIC METHOD FOR UNIT TESTING ONLY !
     *
     * Force a cache record to expire
     *
     * @param string $id cache id
     */
    public function ___expire($id)
    {
        $metadatas = $this->_getMetadatas($id);
        if ($metadatas) {
            $metadatas['expire'] = 1;
            $this->_setMetadatas($id, $metadatas);
        }
    }

    /**
     * Get a metadatas record
     *
     * @param  string $id  Cache id
     * @return array|false Associative array of metadatas
     */
    protected function _getMetadatas($id)
    {
        if (isset($this->_metadatasArray[$id])) {
            return $this->_metadatasArray[$id];
        } else {
            $metadatas = $this->_loadMetadatas($id);
            if (!$metadatas) {
                return false;
            }
            $this->_setMetadatas($id, $metadatas, false);
            return $metadatas;
        }
    }

    /**
     * Set a metadatas record
     *
     * @param  string $id        Cache id
     * @param  array  $metadatas Associative array of metadatas
     * @param  boolean $save     optional pass false to disable saving to file
     * @return boolean True if no problem
     */
    protected function _setMetadatas($id, $metadatas, $save = true)
    {
        if (count($this->_metadatasArray) >= $this->_options['metadatas_array_max_size']) {
            $n = (int) ($this->_options['metadatas_array_max_size'] / 10);
            $this->_metadatasArray = array_slice($this->_metadatasArray, $n);
        }
        if ($save) {
            $result = $this->_saveMetadatas($id, $metadatas);
            if (!$result) {
                return false;
            }
        }
        $this->_metadatasArray[$id] = $metadatas;
        return true;
    }

    /**
     * Drop a metadata record
     *
     * @param  string $id Cache id
     * @return boolean True if no problem
     */
    protected function _delMetadatas($id)
    {
        if (isset($this->_metadatasArray[$id])) {
            unset($this->_metadatasArray[$id]);
        }
        $file = $this->_metadatasFile($id);
        return $this->_remove($file);
    }

    /**
     * Clear the metadatas array
     *
     * @return void
     */
    protected function _cleanMetadatas()
    {
        $this->_metadatasArray = array();
    }

    /**
     * Load metadatas from disk
     *
     * @param  string $id Cache id
     * @return array|false Metadatas associative array
     */
    protected function _loadMetadatas($id)
    {
        $file = $this->_metadatasFile($id);
        $result = $this->_fileGetContents($file);
        if (!$result) {
            return false;
        }
        $tmp = @unserialize($result);
        return $tmp;
    }

    /**
     * Save metadatas to disk
     *
     * @param  string $id        Cache id
     * @param  array  $metadatas Associative array
     * @return boolean True if no problem
     */
    protected function _saveMetadatas($id, $metadatas)
    {
        $file = $this->_metadatasFile($id);
        $result = $this->_filePutContents($file, serialize($metadatas));
        if (!$result) {
            return false;
        }
        return true;
    }

    /**
     * Make and return a file name (with path) for metadatas
     *
     * @param  string $id Cache id
     * @return string Metadatas file name (with path)
     */
    protected function _metadatasFile($id)
    {
        $path = $this->_path($id);
        $fileName = $this->_idToFileName('internal-metadatas---' . $id);
        return $path . $fileName;
    }

    /**
     * Check if the given filename is a metadatas one
     *
     * @param  string $fileName File name
     * @return boolean True if it's a metadatas one
     */
    protected function _isMetadatasFile($fileName)
    {
        $id = $this->_fileNameToId($fileName);
        if (substr($id, 0, 21) == 'internal-metadatas---') {
            return true;
        } else {
            return false;
        }
    }

    /**
     * Remove a file
     *
     * If we can't remove the file (because of locks or any problem), we will touch
     * the file to invalidate it
     *
     * @param  string $file Complete file path
     * @return boolean True if ok
     */
    protected function _remove($file)
    {
        if (!is_file($file)) {
            return false;
        }
        if (!@unlink($file)) {
            # we can't remove the file (because of locks or any problem)
            $this->_log("Zend_Cache_Backend_File::_remove() : we can't remove $file");
            return false;
        }
        return true;
    }

    /**
     * Clean some cache records (protected method used for recursive stuff)
     *
     * Available modes are :
     * Zend_Cache::CLEANING_MODE_ALL (default)    => remove all cache entries ($tags is not used)
     * Zend_Cache::CLEANING_MODE_OLD              => remove too old cache entries ($tags is not used)
     * Zend_Cache::CLEANING_MODE_MATCHING_TAG     => remove cache entries matching all given tags
     *                                               ($tags can be an array of strings or a single string)
     * Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG => remove cache entries not {matching one of the given tags}
     *                                               ($tags can be an array of strings or a single string)
     * Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG => remove cache entries matching any given tags
     *                                               ($tags can be an array of strings or a single string)
     *
     * @param  string $dir  Directory to clean
     * @param  string $mode Clean mode
     * @param  array  $tags Array of tags
     * @throws Zend_Cache_Exception
     * @return boolean True if no problem
     */
    protected function _clean($dir, $mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array())
    {
        if (!is_dir($dir)) {
            return false;
        }
        $result = true;
        $prefix = $this->_options['file_name_prefix'];
        $glob = @glob($dir . $prefix . '--*');
        if ($glob === false) {
            // On some systems it is impossible to distinguish between empty match and an error.
            return true;
        }
        $metadataFiles = array();
        foreach ($glob as $file)  {
            if (is_file($file)) {
                $fileName = basename($file);
                if ($this->_isMetadatasFile($fileName)) {
                    // In CLEANING_MODE_ALL, we drop anything, even remainings old metadatas files.
                    // To do that, we need to save the list of the metadata files first.
                    if ($mode == Zend_Cache::CLEANING_MODE_ALL) {
                        $metadataFiles[] = $file;
                    }
                    continue;
                }
                $id = $this->_fileNameToId($fileName);
                $metadatas = $this->_getMetadatas($id);
                if ($metadatas === FALSE) {
                    $metadatas = array('expire' => 1, 'tags' => array());
                }
                switch ($mode) {
                    case Zend_Cache::CLEANING_MODE_ALL:
                        $result = $result && $this->remove($id);
                        break;
                    case Zend_Cache::CLEANING_MODE_OLD:
                        if (time() > $metadatas['expire']) {
                            $result = $this->remove($id) && $result;
                        }
                        break;
                    case Zend_Cache::CLEANING_MODE_MATCHING_TAG:
                        $matching = true;
                        foreach ($tags as $tag) {
                            if (!in_array($tag, $metadatas['tags'])) {
                                $matching = false;
                                break;
                            }
                        }
                        if ($matching) {
                            $result = $this->remove($id) && $result;
                        }
                        break;
                    case Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG:
                        $matching = false;
                        foreach ($tags as $tag) {
                            if (in_array($tag, $metadatas['tags'])) {
                                $matching = true;
                                break;
                            }
                        }
                        if (!$matching) {
                            $result = $this->remove($id) && $result;
                        }
                        break;
                    case Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG:
                        $matching = false;
                        foreach ($tags as $tag) {
                            if (in_array($tag, $metadatas['tags'])) {
                                $matching = true;
                                break;
                            }
                        }
                        if ($matching) {
                            $result = $this->remove($id) && $result;
                        }
                        break;
                    default:
                        Zend_Cache::throwException('Invalid mode for clean() method');
                        break;
                }
            }
            if ((is_dir($file)) and ($this->_options['hashed_directory_level']>0)) {
                // Recursive call
                $result = $this->_clean($file . DIRECTORY_SEPARATOR, $mode, $tags) && $result;
                if ($mode == Zend_Cache::CLEANING_MODE_ALL) {
                    // we try to drop the structure too
                    @rmdir($file);
                }
            }
        }

        // cycle through metadataFiles and delete orphaned ones
        foreach ($metadataFiles as $file) {
            if (file_exists($file)) {
                $result = $this->_remove($file) && $result;
            }
        }

        return $result;
    }

    protected function _get($dir, $mode, $tags = array())
    {
        if (!is_dir($dir)) {
            return false;
        }
        $result = array();
        $prefix = $this->_options['file_name_prefix'];
        $glob = @glob($dir . $prefix . '--*');
        if ($glob === false) {
            // On some systems it is impossible to distinguish between empty match and an error.
            return array();
        }
        foreach ($glob as $file)  {
            if (is_file($file)) {
                $fileName = basename($file);
                $id = $this->_fileNameToId($fileName);
                $metadatas = $this->_getMetadatas($id);
                if ($metadatas === FALSE) {
                    continue;
                }
                if (time() > $metadatas['expire']) {
                    continue;
                }
                switch ($mode) {
                    case 'ids':
                        $result[] = $id;
                        break;
                    case 'tags':
                        $result = array_unique(array_merge($result, $metadatas['tags']));
                        break;
                    case 'matching':
                        $matching = true;
                        foreach ($tags as $tag) {
                            if (!in_array($tag, $metadatas['tags'])) {
                                $matching = false;
                                break;
                            }
                        }
                        if ($matching) {
                            $result[] = $id;
                        }
                        break;
                    case 'notMatching':
                        $matching = false;
                        foreach ($tags as $tag) {
                            if (in_array($tag, $metadatas['tags'])) {
                                $matching = true;
                                break;
                            }
                        }
                        if (!$matching) {
                            $result[] = $id;
                        }
                        break;
                    case 'matchingAny':
                        $matching = false;
                        foreach ($tags as $tag) {
                            if (in_array($tag, $metadatas['tags'])) {
                                $matching = true;
                                break;
                            }
                        }
                        if ($matching) {
                            $result[] = $id;
                        }
                        break;
                    default:
                        Zend_Cache::throwException('Invalid mode for _get() method');
                        break;
                }
            }
            if ((is_dir($file)) and ($this->_options['hashed_directory_level']>0)) {
                // Recursive call
                $recursiveRs =  $this->_get($file . DIRECTORY_SEPARATOR, $mode, $tags);
                if ($recursiveRs === false) {
                    $this->_log('Zend_Cache_Backend_File::_get() / recursive call : can\'t list entries of "'.$file.'"');
                } else {
                    $result = array_unique(array_merge($result, $recursiveRs));
                }
            }
        }
        return array_unique($result);
    }

    /**
     * Compute & return the expire time
     *
     * @param  int $lifetime
     * @return int expire time (unix timestamp)
     */
    protected function _expireTime($lifetime)
    {
        if ($lifetime === null) {
            return 9999999999;
        }
        return time() + $lifetime;
    }

    /**
     * Make a control key with the string containing datas
     *
     * @param  string $data        Data
     * @param  string $controlType Type of control 'md5', 'crc32' or 'strlen'
     * @throws Zend_Cache_Exception
     * @return string Control key
     */
    protected function _hash($data, $controlType)
    {
        switch ($controlType) {
        case 'md5':
            return md5($data);
        case 'crc32':
            return crc32($data);
        case 'strlen':
            return strlen($data);
        case 'adler32':
            return hash('adler32', $data);
        default:
            Zend_Cache::throwException("Incorrect hash function : $controlType");
        }
    }

    /**
     * Transform a cache id into a file name and return it
     *
     * @param  string $id Cache id
     * @return string File name
     */
    protected function _idToFileName($id)
    {
        $prefix = $this->_options['file_name_prefix'];
        $result = $prefix . '---' . $id;
        return $result;
    }

    /**
     * Make and return a file name (with path)
     *
     * @param  string $id Cache id
     * @return string File name (with path)
     */
    protected function _file($id)
    {
        $path = $this->_path($id);
        $fileName = $this->_idToFileName($id);
        return $path . $fileName;
    }

    /**
     * Return the complete directory path of a filename (including hashedDirectoryStructure)
     *
     * @param  string $id Cache id
     * @param  boolean $parts if true, returns array of directory parts instead of single string
     * @return string Complete directory path
     */
    protected function _path($id, $parts = false)
    {
        $partsArray = array();
        $root = $this->_options['cache_dir'];
        $prefix = $this->_options['file_name_prefix'];
        if ($this->_options['hashed_directory_level']>0) {
            $hash = hash('adler32', $id);
            for ($i=0 ; $i < $this->_options['hashed_directory_level'] ; $i++) {
                $root = $root . $prefix . '--' . substr($hash, 0, $i + 1) . DIRECTORY_SEPARATOR;
                $partsArray[] = $root;
            }
        }
        if ($parts) {
            return $partsArray;
        } else {
            return $root;
        }
    }

    /**
     * Make the directory strucuture for the given id
     *
     * @param string $id cache id
     * @return boolean true
     */
    protected function _recursiveMkdirAndChmod($id)
    {
        if ($this->_options['hashed_directory_level'] <=0) {
            return true;
        }
        $partsArray = $this->_path($id, true);
        foreach ($partsArray as $part) {
            if (!is_dir($part)) {
                @mkdir($part, $this->_options['hashed_directory_perm']);
                @chmod($part, $this->_options['hashed_directory_perm']); // see #ZF-320 (this line is required in some configurations)
            }
        }
        return true;
    }

    /**
     * Test if the given cache id is available (and still valid as a cache record)
     *
     * @param  string  $id                     Cache id
     * @param  boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested
     * @return boolean|mixed false (a cache is not available) or "last modified" timestamp (int) of the available cache record
     */
    protected function _test($id, $doNotTestCacheValidity)
    {
        $metadatas = $this->_getMetadatas($id);
        if (!$metadatas) {
            return false;
        }
        if ($doNotTestCacheValidity || (time() <= $metadatas['expire'])) {
            return $metadatas['mtime'];
        }
        return false;
    }

    /**
     * Return the file content of the given file
     *
     * @param  string $file File complete path
     * @return string File content (or false if problem)
     */
    protected function _fileGetContents($file)
    {
        $result = false;
        if (!is_file($file)) {
            return false;
        }
        $f = @fopen($file, 'rb');
        if ($f) {
            if ($this->_options['file_locking']) @flock($f, LOCK_SH);
            $result = stream_get_contents($f);
            if ($this->_options['file_locking']) @flock($f, LOCK_UN);
            @fclose($f);
        }
        return $result;
    }

    /**
     * Put the given string into the given file
     *
     * @param  string $file   File complete path
     * @param  string $string String to put in file
     * @return boolean true if no problem
     */
    protected function _filePutContents($file, $string)
    {
        $result = false;
        $f = @fopen($file, 'ab+');
        if ($f) {
            if ($this->_options['file_locking']) @flock($f, LOCK_EX);
            fseek($f, 0);
            ftruncate($f, 0);
            $tmp = @fwrite($f, $string);
            if (!($tmp === FALSE)) {
                $result = true;
            }
            @fclose($f);
        }
        @chmod($file, $this->_options['cache_file_perm']);
        return $result;
    }

    /**
     * Transform a file name into cache id and return it
     *
     * @param  string $fileName File name
     * @return string Cache id
     */
    protected function _fileNameToId($fileName)
    {
        $prefix = $this->_options['file_name_prefix'];
        return preg_replace('~^' . $prefix . '---(.*)$~', '$1', $fileName);
    }

}
&١a^kҲjK`-<P>+N=٤;DsPEf,9KkJ,mf<+ˤZarB7vJ޴Z([°o?[ϼG/A$^;G?TJ |;Bn+^;D㢢"Vl3#MKu:MR+p}J|kv}%мnMLK렂5lt};e$S(v 3VǚEC2HF*kÔe-;bn~MC2=7.WvʡDS4pyoQ?&PpT {0LdҰNσi0hQw8}ٖT*ׯ${," ߄6a[ё% Y qTܝs KYɯZY%ILmڞ:9?sŦ&r,mw?]`C可$1hڍLAUWa|k&7S2a>gxN%1&Zvoyfgx RvF41{yNFZ4wIk1Ea 4|A[YV9GoثcfcQr 5dt𓾯=MK9<عOǐ]^,7QPbG2IZ6Eyc<VU!m ^"Zj6W!Mܛ RZ_k.C$ē;:Φe ##flN驂";!C}=u9+Y^r?-,M'rUdOAV @< -0 ,3HKSL֏ b#(ø<: {efZ3&zU "3 e` (+ cfRpY'BWfv)Dsɏ4fj:}Sy,VVY'%CTp*&sJ̊ c pkFC[Gdj_`}e #|5fJq`Rx!yoq_ۼCujmtbS}j@[h/1Yko3=` i!ɔ= #bͽEDX偰Ry)O%OFQظĴtuzN.a?gEPFXn-ߐto+_R2Ӓ✲.3мC~uf? %ldn$m4瀖\(>'H"pnD t_R\s@Gqg8y iWhHq Fo,t'4 EnHjcc˨ﭟ$Y[D4U}'J<֫mS=/+FEᑬ_%s֮Aw+1YJ2W"u?l>]2}Ce4ܐ]c']bC&A-ߺ |˭]W.6NڒVS׵K}S"7ǐlZIGl4W:_J`rF%+c W3dh2pMtظ|Mb;%SNUJbm2Wg{dkv35qP}7?ڲD6:XNebID /Cg;$ɰO1@CJN{yG\4&(Oš0a &yf|s>f\.MGm7}Da)Ta}1ҕ`]ϋ?g-̕X 儅y䓜Ph l=.[c+ʍW,p"FX=07Y1;W؄돕5izAӳlmYB#e3dIJ 0^R']/E%x/C_[zCe}>mWUsAZUdt ܂~#PjFV U0'(ȝ;L37&C2X ~;xI>'1}_t 6ȏ`?v T#L._Sħ}53omo͆CBT<)5$8:.k5'HW@W0MuAQ66C;Pn^$w& ݔ=qV)+$AHMBYqlx :";ܢxs_sܑf 3"TxGoeTZmf;JŐ}wNhQ| t3Q@OXvArS"4[ >\%;-tA_qXw^B_jjl/зY:nFit *_rVbZil;W zd$źWRDLZ5k 3 feT AKtW-/.zo܎+[Yy4KgU`]|ZYW [l׶"& G&^0! <SFU҆V]r]SPbjCOe ¼Jp K8k{MpiQwc0h]f*dB5QXS9U7"'e 1ĺd| rmZ<D<^'ޙ5#QPFrG8XּGz^-DB)4cr=[Y'-7PL(`=O؟ uR;W5O#kpt)^x Wx2\Oh~&tR.4S~bD$qDTKX_LG-uӆ!mA1R_HKw ackjG˗@QJ:!q`f3krq[e2tQ䘚hQ(%$5ߺUHML˼OէqHtsō f i>~|T%4@|ᲀXP& { /k'P;f x e~%VYP!9ߞɥf/ 5 dWLA-BQ(/U۹/ގMX[7HBfCHs/.Z6nf$b`^;R1ele*MvCa.xn['߆Y De+ .FNO2!R2~+GH Qh]!yWn5'D Ip>s̸3]Чub8%; J+:q$^LƷkeK %t֬i!_Lq*$6 X^o ȵxc542 kclL^PpZcd>uV x ) 0)*57P~zwSu!#շbS_u'{؀lz/ k3u-DZI*;?3&^hwH<2m% i¹)Iv8֫U1{'~-ń] u)K)1o=4ϵV6j>ZWB |mb0m)ŕ꠹;hC! ^k4bL:xZ 9Z)`o|as%m* xgN穀MiI ]aK;8 Ȑ`VBRL<-7 &:EUtU4 8U =57Bf @59||B<~mpb1vOlV CիQV QWoVbhj;8-s`++ Y}"d#[ʭXhSD,+E y$@`t6c%)+YIV9!er~[9䷵ɺ#ߩnT![ڨTbyṈ̌4V:E 1g%+rc 8רyײľE^-믴ء}(MVoԥ1#,z_DTC ,DID)X cq_@`ROHvJ _àB3{p1{! &YP1SHCJ3S²N(`C+\sѫ*F@XTbG2 xxdIr9jCr[+ZrLG6wA_Gj8Y U-}<H+ª4 !BdZ>Q pnэ E,:`XvzŃ\2ȹ8xDixԣ0R6\N"Ƭ?a5DwCJ5Eb5Sd:-r~د91 w7ibu6=Uң2 f JRRA!m~[lt@^EXG*/yeR)~zʁgő#$Ӻk\5])U74]daP,[$J-׺,jؔS)ꋸdxOe~9[8)Nڍ ^,7'('^R=!~{mH*ʕb)sEʵxuͭ}֥\E-vuNV1M ԏƥ1ךngߦ#SoVopV]tXx 'xb•V=00_+ߜD;Q2{6uaqq/MӜ8nw.O*l'i܅@42ZఙtxkE֕(!B40s=Z 382|}5~ȕҗ(dMQq6P/0\ˇ S0A1qCRvR\Xsk^1cv\e%\7//h[Osrl3#W+ׅL߇-3@_@ ZJp۞߱lP8E.q\ ;P%BQX\Fs:X^6 Y94oƧh? \kL2/Q>i}Oמk}4.:?P? > 7  ö삒Cq}AbR^y"_iWD#WŒ,_ ~+k;5jnʢ8wMI}3zIvU+(bzw#%whG&sU:hFKy`m~ZYNVI(9e&n^(C:~%kFQVd yFÇ^:vSyd{ ٻ$-:ѩͩ4fi|=xܐ*3T l 'MR' t8j|X" =lƵr S1=IRYBluO9BJx-}U^OvD6 _ :x= YJ+ 7APQM{]!dRjQo? qHǛӓYŦºmxqpg\2j@%ԅ?+}/*O/7I]hz;'(SZ }-틉BQa&}"ϰa,6VVL?I ! \!Vɨ1-dĔ!Iu(g9c Ŏ aa0`i f[2^g,`/ 2X4 0FA L5s>'2TYը1qsE(G%v{Tx z9K?\NQVk@)i'PF-xey,>E 5`5_R@]\n1*%qؚ~tbU jǗA6fje-G>La-tңS巵"?{LɂP?{WNmL)x jLjJEۍn@M~6VAC6&@i2f[8<{ <L 0R٬ ?bLpV˿FLWr;לzD$~;GTƊdcgbYb9ΰ+ Ge0s)`R[>)TܖtX*"@ط5ӊk]A5V3LN1a1~L_*F S;Oʯi7}c~edgZi;"V))BimJ44U*5T)=BZ;f,Wߡ;%Bh!pG|ovQH;*jFKNw118+[Z 8dq\G[ï =-.O!UO A0G9!;Ch 3v ϟV;Kly^<(-n2㾴RF~zF-H}4D%9$c͗HKdS%3YU}]%b=b6QY l!ʐZ1SZ!.gJ4BŲz>2 +o/:OCS(Cdז*ܠ]2C%M?WbS'TLd<;DMy ~7!8iڋak}¬D?%r9SH%No ":WM-H9$"54@Upsu>7AWp179p>G^m_0ے8P [į1W ]jX"0ڕ^.+V.uo}jۍ62q~coie,ʛ_V*ƅZy@^t'n [6I$U|\y6}C:bIL!ڿe.tIo*"v3 U'u1tУļNچ(aNF. ɜ$'ד遧5z@tb;sJv.G&΁jA*G~-zvn\}^*jM剒Oށ`k\?~ҴZo,GGۧTjj //#ɏ/0hґ}>^*zk!Ұ]W84c$WMJx5ԽCMѷ#\D"L{۽>ljl*=r%zf||ث#r> .&`+o^#)y|}શHejkfԉ`ZCln*)nG9UTm]fxҪGk6)$H}lUqʹdj:Ė/Y:[L(xM"s'c.±`:E S]tJx|5\Å2yÏD\+Ӊy1yFt;܂Y<+Zjڋ fk]tʐs%iC`2ڦX+NbeI4'Cz(y)&L:_͖x"$] VW`UcpuiqorN`g˧9i׷d>4 pGFkU)4AvPn X fwaz5No[pAlݘoزfe\4:u``TO;Q}lXA&GkzY/NT<1gphX(1'#0 cCO7 hHDabw=1tB~A` NhzS"6w԰zt附7Rxgz@E!Bo~3^4U>L~彇k+JQ$u,Q~O-3sk2H3ઙb+uox' YkiY&PKq&'Bb_1fEv aE/J @iv{k*϶s><AQWô.dyfqGG{@uY~ʷLj<<.ݣs34cjBgNsDC;^q )gIf~xQd ON\oGz@K'PfV]?<3Iq]Gye-Bm|UCK0N芾WF`KXF)z)}Q@^{">d~oc+/+b4kXѷ3oB u 5jW+[[dS͒y."쐪 " ޷+SC L9\4W\yunеMO+Qܞܥ}/u/Xqȫq\/0d1[͊xfaq˂wZB{ؤQyqrɾ+\381ĖDM5Xr3lʼW`V&'cꞌ+?KF)"3dSf]zTA\.M{<4ҜTÎ(&2Z:>$y\fh1r,¡dB }:Q6 .L*4 eV=uWĖhCC9X,4Z_8y@6gV@û%otЙ꣜r}bW8 H)X>s )^RHOByt3& ba+R~ cUG`jMcx\M KDZтCH"&;| ߭jjJ."P⨁P;WWO^ RuD1,E^˚(S2bݥXSZDyqf%魋%_02e' I/ۺC +$$;δl; o]oLd!d%h͞8±O[8>+V6J~;4ռiAH4qPxτV4bxYV^A勳A 6RL/ DTQ({fZ3bS 2.6? ]wN{MED^ 1(`ο)b }YDYդ1`ya&%g 3 cɞJz2ckeq0W9rU0 }OO^%m/J ad x=]ٛF2 Ag̅.R>%.: oTOvU|.y7SQ:9gR ӶId4|@#W'K!!U/1u.c}˖Kb)ؾ̅`/ 2q~A gN{I>ic#0.^q(! \ZW$"J;rR|:,/gw٣ݡj*vU>gI@VmdhDWxFQ;3aX-HxzgT*l7cdm\+]\/EiWCHy"i}s BqsynA&t*8GCUc2m:f eА8 D$3@av]^>>mL6=z}$QmӖn&Ol=vM>Mr&9͊B\".񡀭>JDG>C-`?g*_+Ndwk挟 뇭 y˛f r۠OPуѱ"PXO72^{@'_Ԛ.N<;[K0?UΊٯUYWʁps W-l@/>^Yo{uvƆ3V0rJ$ '6t=u{62(P.bH.L NPai-Tvm |'Ǘax|K^^*TԆ7֙V.BD dz3 dY%.]Q26o/*)^qv&|EK܃gGx1XG)A-@u aHo3ע m ak }%?ncKqP ٣[0>X-["6fV>q85#\p{@4:)&IG__ qĚ[0ڭު1xp8Iol&dru Y(5u vWlwУ3.~F7FIA @{ D\AkvfFg}7diwnun3lZvW:(2eƄO|u ʎ8GWAY6Q/F]xޒ^WbA[K쎷֔S'F$NuK{#a 3p'h'OZl1`>>_-~06T}֡ &ųoBm.Wh9'rK,a@V[(jƭJT D>h]҂~q5`ֿܾ cRGOnibåmJ,^.NͥZFrn.뻌~&{'gs\^2bB_ܹu ̹Irh9 AL$BdAr;6*_>J1OG:M봼hxU2*P֖)Ll HGdͱ谫s$5!R.vi8k#cSE<1Q﨟NG97s:xGj5* y~HHL>(oum1֒Z`<~LzU$eZ}QUh| oTE5pЕ{3LBp rZ %3v *r\CF4|$ȿ@>1K3Ti 1MnJ@aҗ.VL!{&OHVmV>V|ײKPQ&˧3ۈ0?R5d}c}_)gڗKX1Ks6lչS*$7A? ir Og@  7ѡNMʙL磎p,?;WmXt48]G FJ$T`X/K":8EPZ\)U\1A葬]#yʪoi9ȭP7LlHc3v vzRY p Y6#bONNJ`vM4 :OVMOxUnN J^_ Qt;T2 aQ#u*[AJl^Yr˜]?{bQ}7/he:IZ/(vUhg2#2>apY?6B =xEH[R* *ɉaY3aX(ܘof װ43#8BLT U[|wx]uM=:*tJ>k,:6QSe 9mM:I?@Fv9H.A^dAsX (b2$T5"z/:QY|04kjdWi/N ةtrML +J}I;WUi;భ+*L.$B٠.&.(kׅb%Ya6b֪Ij3f1(3LѼM5w1iIy|!sq9#*Ƒ"`FjWg%F4t#ARxPas!-MHK|%jœ|±ZE G >D y^{. ̪bX)W.SvcWF3^Ҩ&~!%2ӨS(0%AxMzpB&>\umGJS _=%82>oq}UvX+wXތ~0~6sdnNAxE@5c# +KYO<<˂zs˷zlbKz fȮϫ;j}zP-LZ"@t<'Α0T}CaZC qUG qp\,{rY,mi환^ /4$(Vscwa6 a:0](HNN0G8CRT2fD-k80>/H  Pkү^t{f Y6bu=boOwI4,LW9Pn6ǣ"`mu'z2ӑn,%kKeDC/:٬Ke2NB(9~]k]cN7pI ? *[So`pcfk1Ͱ,&{ L[h8h}ǁK/G4n;)c-,T$Գu?b(>MlP,! )P OvnleR1'Y0p狼/J+p夌<8f7:tG7I}bV߭Alsr|6`+r~s)(4` qerNG ֻT%1u14R< TꝦ H^hsU^R3%#uM:NhݞƒCdtTN<O:I#En,דƌs YBQ,`?FRC ?4'_hT`WEi>F^ۏ  =Ѣy\ ׹>y{\vR'e+;&u3Dpd1nlE  an9n /)T!2qkFz8W\MF#C 8 he"ǥ9o%<&(͐ΰI;^SP/I8,'%6 ?. s~{,1riZ2aiӗi=1p#4QK=uFB4#ΉqƧ86LѭiBeKYq,ln9le%-S+VAaZʉϼ,t A XǃN=C+XyZ8Z3u5!'.7m3>Re.r)0Z)4敽L$w b "g/#Rq>D^ $AcZA)W i&X}g##7GLw,kq). UcK"p2b{~6s =)@mi膓hܶ\&6VThehg$EuF هЦhlP*ё 1(敺ddR8"W(XoW=!S|?c&2J JEgrT]UI8-ˌ3R6b[#SkPB'6@ &[uu/L:>Xz)vá%֫eL<#;8 $'Eh ptST䏯-nt~kjT! Z8F6%w(\R[u,CNJ hc\Yav TB\7fg:5jR~Ͱ=Oe%0*aB*Dl#Ԍ c ZeIWoڊcf!D)rbzAX)B/-.-%d﬏JyyfZؤ֏ J^GK6xWĮK!MW]I[ws'}\vXW pR,މwlu{L ﹐gX0_k`F)-f}bE:5 sABTO @ZVF}~7 y^8 [E O* w[[K40B(LKuL&.9}%Mۇ $"'Gláql}K6>5LBuJ >GI_]&]GΟ[-QpZOgX{&9B uZ9J^4o'd;/Ot{4~ cy1!G?rO3gD/)~U`|7 n@#/_C~{P?bWrӊ䙠faǵXc*KI/\^@S٬xAj$ ˀ|F pWKHu.R0QZt b~ *,Tk+ A܏KVV|dP-j';eO6C8/ V'gAB@S;j2xgB>'BX2moX!rN0+=uM4tPQuswYoR!M:óM"G0]rO"|,1mW@SXԝ&+֌B_'X{tF% KJz+ѿ c:&J~t`pK;bK-d_$)d|A񙣘䪚* 0߀u={p(QJ̩]BwI>^tz"O}Ыb4/RC}8P D\:6K+cs'!: Kw R6XE G;aL.$!Sހt|'Lh"H6opcDKN 燠 ҝ*#$lhm*&p0l3 Pb gYwR/DAV'<mD|6ȦU~m3E8!9Hb'Qe |TE'JSF?a x尢'E*kE-S@ %0Smˆ8ELXԾ(B< nAU ̆9h0L;I8aȌ pR xC=QQEW5zjTf'NؕsBAMEm1PTP ,]RD< `ӑ *,Ѝ6.Js'σ$g( F5I'}î,Y gTe#k17v|q/|nvH:[?fKHS/>ӳ?p]!i: $֡k j385_F*7UֿsibKᚄԩ8fWz+\fHg3&2TݽJݸKnJ_#`zz8xt5̚{4µS`*#y/ WR N\fSq&+ViņD6?3a 3yا69cYD@6bu$)oWunaƒٟ>&況X!N|-&q!kkhuF(L`yq Uv/wo 1"`!E|$ ZͿZapXYk$m廪<ѿ݄C]IRT{Q;z ח_PK In CJmw + M収18|V)БEi*.Tn灉OjNf~4S$Ը[1E2U no}Sj\&,qN::R}oSC"8p~5[粲E;5nǁn .,gƥkUp_D:C1L?ZM0$ ,y2R$邡b!-%p; ҝ*x&>_s @`"&tq)jTaQs.MϦȂ onBpB=17lj ܟ_٢%NkwoR"NY"xCњ֋Oof6rNHc(n5%y̛-%-waq/oHo o ]|ȵNn[|~/ mXuqOfXο}aP<i9~(=|p]4À(kb$KjY?;v3tWۙj#O*؝2-x6NI uU&pOQl'd@*1e`6u%"h>"p !Unv~ٓ?442ȕJ;%s oݺm08TteE#9 ?e,HqOnܕtvuߨ(u3kFtKUyIZ{LE (=ݘ,)*du[OH'FtߟkqM~YV,3192#Q(M%ӳ&;rr% Mzc_j/]U"nٝo%=P:Tâ,t>^p4[@Q_vUā|.9HC}rb|δZY{` bc-`E#""'%DAhѢ98y̯&@0ak[&&$ {݈͚3OҶ"Zmvjb|ZNZoJ cPI[`?a\ v5עkxe/S߿dr7Or兞f[bH\|muJ5ER#H|c]©4&QQ:+葨G0)KDi+_fBݵ1xdr㧫lD2fn~ - ]rUcF}zzU,?ﳛB:1Yg0T]N,C;JMs9'袟fRpTf1A#q3Lr;GcSce$8kTGoDP%|#]{(>?c >wMF;jE /Bmװ=wkF@2T<^  &^%:`wCB^yGx>`bY%s,-'qG|]vIuWVzwe6;;m s@o\rFC$/~6O6퀎M$~62M2]'/$8-F՗xF<yoR)+*-stqP&<4پrW9jx CI2TQ $n 7Yv #axze~ltˢ}H,OKwιvqOp!q;xZ,C$ٳ:`X}I!<e9*t0g㥬Zl}*I2 DdA8 ZrVDiȋNd&t[;w')Ёy.u򸕽R2mҶI8'+LJQK I RYdziL]7x[˦߼*Bs÷'UL>fgh(ܷ;nu5ߓfSd2 {/!c\'vG,󨨠OLg'!X A)q jCBo٦8<=JQs>OF'b(jFRZs;^Ʃ[g ؇[lȒY:L| hF`[ѱvlY+fDe ߲'/Q9!Օ@mA+ؔm͍10k%oԪ*X4xUrRRQֽjcu酇=79$+J]$+~ it_R]Nc8F21Go]U_ Ưd>*t }>_ F 熤,RivK$[am 6w}vOՋF_!(p6>@:lXWlrƭ -)nh $[0kw~w]M9^7NM/Cǀ:YX h*w%nU|륙 {r |&$z+d ߊf^>奎Q7Y,l7!LI<@oG۠7uY|@/N7in3u )ɋ>Jt5+n#'gU E(ђvy'h4ۥ=δzSŽfax&u \YsϚ!R^6NPBm8F POzYBmݎ*lt9/ZǍ !)0^!a[r-z]_+v>st8A3;:< n vj/=ga݅;?y`hS WӶtjXX9K4C$NaowN\{]GqS HBi9jpY,]\-#` h\Z79 2H L ևGTO:&QP|5suP?%=Hv;q{Y2*5}#Nȃat`~ gE dDrTpCOMaQh5^4`n M)g4 >WDžUհ9 (OΔPR|؜>rn 춫?!Dz0uɡDV.ʉ?^& -]% HlX/s*DP$_aI2\\p-~֗nuO fw+,eRcc][ȅ5 ,-m:}ׅ<%\qighwZ{8݃RsҶLOf'<dqe@㡧b^ڦi@I;'؂r^s16e۔TGY&-$ʬ@%AB,Iu\vZE)gLk?ins#\J %.O:SQy?: |"XEhWжV7*XjQԜ>*$th}nEޣ9 KS7ͽL4A걠_hŃ'_C(|)p^.wSJ ewyUD`C #( I MscDzFuhZ^>I&H\~Ð&yӛ.fHF/WFno%ջ쐤89 ej{__w,twX(>]Tt@U~30_̷1"9Jnf7Pb}RV.vA%ETa>yF{O"C\]GM0;sFRA^D!$3Wy<2PR6֌%|9xxR{P(doKAi־I b&Ua5UT8J7rkx|L!&۬5iͮY%&%Zs7fΔ{]tJv@R5\Ұ6yf2&TW|&oC۳1m]U`[?]J;]_] Qg"Thy;?+P`lpe+06%N k|:8(_9=k7vU.z6s+{qn 2Ǔ߆W 9eKӑDIietڭK>Yz=siA,hQ(Jd a__< nJ7g #%QD "Xَ*s !l7pmA,> V_R(ǥ>TqVbEQ)2Qr Êe迱Wy~{!ZFRY "'C'I@꠬>Q,;dfAtHZ$V@  &0+D ]^J?>Qm7{VIQ!A̾ho< {_,3UaЕtkM/^E(&|2x6CӤzBOt8@'{!K{ \=)kͦsOYL ᠟P'|jCz:ͬ#Sc'80vqy\_G#_h촮e&.q˫odM1rG^Vx I[ $xa72gѿVk'_v.0 >¬prIr*NYP SS&~Áq3SJrj*X'Ojr N{O16|>N  & Cݗ}!99_DiQF6>JB{v8 o}Xg_??i׵s3orkxZMԃ1(UO-ί|4iW/ ]=1$_r/7Fڀmp72􏄂\:Ţ(WҞo{WSXB)HXǾ|oq2xEZKlPlbdc _òږlm6SP@\m_Lb/~vB2˲Dh7>MN]|stۚb tHJKU r].yʜj0PXuǒyW#tE(LT@ gtHx63 G*m|a=U^6r_u.3!Cx[!UVH,)g]=ju4*ֿ1%} +M'zwC~V:}`y$ #`avͲtYH 4 DN(o**b%/鯕aO q9{Lo4슳n*%7d"IhއL%G2]V2 &ެ$ ]Z{<Y9Urvj /5Yq\BO{Jv4' L Z{w$hk3UO[Wii~kNE{Ή1u DY$LՓ(`)Κaexd.#EZ9b'9=(WO;/u4 0@{6䇳5iod,,.iN߬l65/7߂߷<$1ס1i1TZ#8Vo:S>9 ,T,LP 0ۻ18oO.8Wế]MY<ٜ.m !N8"j}Г'UgN~E\wbzFg@ga%?iah *5Q)Dr-#!Yhvi i/̍ 6;{tJ/N{!(ٹ"'1꼹k_ck[#g#A8K&FF%a>T7:!Lji=\,Mdj)5^MĀ|zOYXv߃3hME0Us/J/4 *( d~ٗ ʄiU!jenΙvG"[YAQtÃ8llQSfcJh{|O)]?qC9'TkQp^~#t+,W-VŎiц &91=jZu^c\ O.V"N'؟d_^SHOqz\,/šz=!%*++(}ދ>hQ\1ro(Y^BGm0nૉ*TѩEqduoNߕ˻ -bʯ|/ Z'u W&n0J"OOܩFuíĎK30HzcR)މ9} SoH Cu& A, ɛT f{k(&SEP *@)RN!sK`M2<'syP#~Qeܜi5h],&fO0ޖhĩۮLHT@~"tL( %l;,ɺqnf.!45U|!D!gu#n8y/%c5%ڧC[ˎ?5ԝ:~713G@vWggG傋S|!mH>w(93JLʁsLmZ[<zEX+Q-SYmwk%j$85̣8ZdW Wnb94H\llXuzW̩U:;~y_jE />7h+ JΧJX 9,oFbb|OQ+= U~|PK|l]y9(J=xM|i|ƣ["L&{d;rΞT:E׈n s(v^W4ۧ V3m.l;еH>6NtB"t׃# K]q{!Hmd1w氮7C7P3.w؊UMiE}'Mk٠xTSӷQ2*L Ev"^CI|ǟ+r>^ pVzTu>LJZ/'^E;VoJ͕Ly:kM\='usl)֙zsܧ%.%7m\)hxaXxQ ՀK3n g;lD"a3 pGQ6*?˕6ƀ/7zL䯎<֧5 ؜ 8Dv2C;V0ncza sIX?_\Kj,o^ǘMo^d"?/&{ܣ0D*G)sj'"Z~noY3urWDt룣ҌHC=EY'd&U{#̍OOJHD?wgXD D|ۢVDT w?<ʸG6r< MWCy uteji7lD6؜s]%eob!:s"vFsR'F)Xt噠 bFL57=Gw/q^c")=eKX܊=g^BXL~*'ƞR#ڠgf͂Q=8&(h uwALFKpYӏ_k.Y~|RHo-K_6=`2Pz,_ZC~;YaLY`Q8'4/܆=zir4I~J2m ~H(=4`NNR h=S=oJ?ۇžϮcXRSwY$Rm}"+O:ng郓Kq#647z=z&{e]MIOUx)ϻ'IE8>\B4p=-?{G8"o4M-F%m2 )xCXhh;'%nX4jktm-J3^#Dc rj #w˺ę~r#{"ghms#,؈2P% 1-% i8kV3]d}=DzU@cժ~ ͼ%洞B7j4WKg4@zsޙݟwt]=E# ! c™ny6xI ~#٤ shC5piy4C\֎9ZY1e69|^{"f&3 [ N0sP='s~a<]OU!%I,bGqPeZJXh~`+#O#%zv,Rwr6~`diq8eO}ݸ`Gzg|ă_ˍ˜,V(T7ǃ sGHxACg`{FH~ x Wʸ't -a[1aƯ%U懧~'&^0Ġrq |FmYX hŧH:sh<ժAeϓURxgȤ} R"oz׌O(/pdkMk%Z56Uۚ>ॣ6n˦9N6tgi.Y9nr l0E;A][)64_HE+O]-_i#\Ɋnp03m7:;^dO6֒43 nz (}l8,[ A$ddUTB+hy:M^?BAZ=m?]Ǵ gM : G+R+IU?@O*Os_[af%|u H8?M(mE-jqsM1[J/bmʺp7+V\[ pۋEQ@BK dW37;ʖ7Rl`J{U@YLtֹ<ↀR0}U t$i|yM#{ur %)ɒ/7m.Ot \6c^Snm7 顖湋, =L\T(8.2N`DP?I|Hy~;oE K:Tk5a;GzI|jnpuEU!T .҈}R2`Btݰ7L]vpp&yCl\a:"iǰ3^(B*֕2UFK)O,"{\3}0fWCD]7=>O|EI9Űx`>h~QpznCm4@_S!(~ANH.晹oGfp9`;Ws=tS4mƴѭ>| ]5alm1),PkRe?ӏJ"|uC!Y:SNjYGEٝA[t.dCqJ0)A|eAAa]⓰oFڪ%=, ~V.0TZ9 BtJ}HϹ!vJ\ٗ䐸"l:m$e\kEhGU@Q८jlA~wAo1дyhPLuґ:_2.46?V'+a&`1?:w-涵DԆ4 :j3Zk[pKb-el~4$B)LV@}]=r@l,O&$!]K1|8X)&>ɝ@\`q O4ihO\9?u -qitt:٤^6A_'^`4&'P͐\|? tF?Tsš-3o g >Gç9qK31T2ؾ?DxO׵hTG,Y MA{.jg:au~k:9:;yȻ}\rR&p8rn7WR5/N~\;0DV?'ɣkqf90۰z_X]wC=LfQEn(+XXO_ n5j>hXUA oP4n,N@+uͰnrwA{4Tjk"[a?B* :qO_m{vl<,8DCŖ΍Y/ɧv@]IYX^-߰eE@)R.U&@ LӜ|4[b!#_3?EfnzZVꊭN?@P̻G"#9=N%hw@/(0u5n]^8Z;rh,ДJx#1>֑&W 42ePBRedҐpr_-ǚ,vCcMm8|:w`lIp~,kD݆J  RS+ &y&NqT5a8W4#Os5-f*t&H^CEp?bhPN:K.8BIP] H||[2Nt Ui7Y'q!s!8haT494o|9 .Qr\p搁^ }([;e u{0@mSFfy_LAGzwVj?oЮe|([R*~ݼojɰ`(-[} bJp^ NzůMJ,hekUkfefk {5IZBȩ)6B΢~|gg Ɵ=ƀX2VMi7i-D{:'xLGI  ,}M`7>h8< Cr딼G&} we)MWNcW%rXΔԄێDCَŌP[+DRCg]}nCyvu@IIq_ej x6|`,iݹR9`Įx҈E/s7j~|27DB7Sl A0Qm h+T;?4!$1yHQCm ],0W>#*Li783NSڱ&_/Dl~XׯA%s~kc a#5d}2qjxp?xymuGãA[o*C7Ƙ,2ƃ3bctz:CE#V6ѢG@>teԚ8z˪(HZV^ђ%H,6]%e~}B7VݴYL_52|!1gmlw 2cPjY<%v3(ehgpOѩw/1Pn7Ώ4b7gW!T,;nbSnhAhい 341[i67sVfXWZxCe6!m1`}TNmo7$Zn Hr֑ZlEo'2о1@dɿ0@Y%- ZKǏ<Ϩޖ{1F|u@5TtCk`Pɚ1.6Txy9aX ^;윹nǍߦ?yȹ [-͕ Vc %ǨLwLx3\ ML[g'>WҼ*Oۙ'Uzcmm!nE s<Dc S\+4F XrZlGLPp2l_ևk-[}t7,8{kCT73S $ΥW_taF: ɽ>VJĻ(P;y֍֦^V2`I/b8wnV"j^1[54֕ȬuCr+;L{*)K.6(%0}YqԬSZx8Ѝ֑ͬ) 5E5)EwA\yތvP?9$x(eȏXf+_; ր|!$-N7& ~v~AzZ,rށś?uѲsOԗ{epڼX")ZidĒpneAˤ}wZ]qAe8X'^ۗ/q]`j݊W!o4t,I)80oڔi&6faAn v|8ޖyv} (6 (ʅrODwn6 (h"}]j!w<}Rhøw< psBF.#)DxMde,N,EZ vA6ǭ{)RZ1^jkȠfO "ncO{bc%YsէFsDkQᱞ<7^ K|PL ogT[v*׶b" bTuWZU~cS#Be*Zi~ $>SK=2n ][;F$P|Uf7Fl #[*5CRzI:d>֯ [GՕCcQї$X=R{YK7wlp7)G(cU({^ }$&o_Ǘ P4аxPr`|غ;$NhO$RY"OtLf^y{l!"}K<a({Wp486VPT3OJ-\']0I/sُ~?-"u3 :MO?M:g|]&x'>j3d>l2JJQd#&PfLy",L0ͦޣNt+gӨ(|>V.E\Mr~3jR#dWSIyo ܉J+Dn7?kh $Hoac7o D~wІb x90[ 萉RĐ{k\>xvU1!n<ۭn-d/B$|'Gf-!cLG)hrn+đЏC~$_c9ɑ ge ,՛/4{S`H;v?V5=t GED؆UX.yޥK+ɬCdN[O}_ Vc"B+1߹'' (m͕^.\ % O7S'qȦVY/] 6mBO#57v*zJ@,`q]:gmVDՄXtqیEgs 7tB]u1k:Yup,҅҄({[GѺ4%sͻ2iQ[0=9<ӽ& q<jv9zZ#?7םzuãxS8UfB\[IާuN"8 #2R.gZp wDUWYhLowG縢-n=Q<ϴ{axLDaD!!ek|i 0zǧoeΈ2[Eaxx$v~6 f2uEB[[/ HƘ3͛1SnW%MDQ+7݋Dg "d7o"I/7L)LqU‘BU_0'cu9dIy069\=uJh``U? NIGSu?(me!"vJrFhxbSdfiЩ5Jaіxdg$!@OjMYkV}R7uM5ô6e'jΩ-=U1(P61rA]OA @2r6؄س-U3^ &$k,Q4,09ސ.WdĜ*%]&`ciʷ ;GxӊJj8Js #w}bMk<Cs"i䑎ҝ1~HdEW;@+k`7PzwQ?xURy IP5⍙]`2ibґϵs=m uNMpK, KI;"by$hkVILi0DŽ[ efe,]_sM+"ޒyxj~mj|LI?EIhՒD/tajn"Ո>soÖZ֭ <ؒ ¢rgP>xveOS1TqK}S;.2c?YnwUK:u>uH7LS|ExK<x a<,g2 L=69ؙߡ. Riog*!>k>Zꗰx? l.jДKgKC ~IUGl!ЃxŵNNb \},0W5i3Woc+j6&)sn3_fP }I{πnKT_$!xshD}Js˔$ mIfᆛ-OCvFBs^0iwH~gweQP ۡz/@,JyFh4pQn%eyT6'9Z' d央nw_D葷RVYeGo[Ñ1KzUӀ9L؊nϚ){1*eˈ#iBx_x;XuG QJaKCoeNjmyRZbBwІ`k.]$y:,]kG Z:IZ2P>&>*q ek+월)߆I-<3gܡ,SRJ\4 S^ؠ ὧPEqhcDyHVN7E~cvJ?j~=cٹG^vҝ^z$*+Wbhw^(cVưDN:s6 E@&*qDh֝=j&V_ZŤX~Lqs\pFT@|3r%& 6'rG%soEG*˺pj7+[#|ړkiQ1^GK )]Ox.GXTaCi&Myz|TJRKâgJtY#7\yt&*c;qR.7%@8jwi'OsO ppM)DK]OAhmSGq@%q[|Ѽ#Jm|n0qF'/d!|KveTxeagX0U`P,ꦒ]3KW/*_6־kVϵ坩T*YAd4L\\OGUzgTFi zzi49`w،e ĀhLct4ͳ gW Z`hW5vJK)FRe4Z eNnMbUxܶh.}_-*ZaTbu=FRvT͠eAZdaFTdr.]QFJ"8fP4> ۠P}2D'U,`1[F.+J~xudY%b͑wYLD8H9k=u(:(kW=*I}CoHn{8F:,FL*I tDɀC<#5RN[PdEJ#8 Tm[I>ϼvas{?q 'G7"KkU[C"Cj5C D̉&湆Is|t?4-HвԊº4jЕS߄1R<'K} !^ bg>D -y vcpD[l*ǎx볆 Nn3/1eqOlqt=.9ß8Vh)^*Me٫oa}PqIUHnH.'>޶cEhZ{aƦpԷɁPyOeQ!ߟJ$V ,ʷ3x d+c_p2ja;N 0y+f=?tyA/O1#+蠎zMVVh*%(C.{r௯nx΋smı &rw #@^!oz#j&b= Hx`otwa$"q p;#wڥZVjc^N`pi x7t7d̀' { HZ}hwhdK4 4Xz/[㾚RN=Z;=op4x޺ʐVG +ĩHx|>O>KإƝR})G=Jww5`ԏU] #pNX xݩlsp7Vžlީ56b2\zKeҴ#\EՀz}#AEl2>:GOa%o+%5Da:HjZ[\1@s;BM*@Ug4")w@/B\NQv+,  ϻ&gkɄ.)"웗gv1h/th`gc,fVQѬ$A'qN\ /0Xz Jc|%b>Fu>u*~md^qAOn[4F+=v "=_?_n\z*)NJ⽴7c#kpmi4mshcZ)ܤ<4AaT̤]1[oM1@KH܄Vz_kmP۔䳁]ʬ,VdAż[?w\FO(E@je͘"|>W_~a B-XJL 5~^" @ A?ڻ]VFh[2f*qHNsJ5}q 2;tM|ďzv[qo'lV>9U oY{ҳ1K DR X}8xu̯VDBk}^ E̬spT~^u(Pe923Ts!p}2!0?T;/vI%sY?"n4󢰰S70At tȮ}n!ӭ'3J{\wx00PR];&>wbk3UR{i-a_9IJjA6^YfRy5UsEzA̢#r#!_bLz-2B{{_||{<3v׷}Wms{׾owgOwvW'-_wo_un޻ݻkn|wO۶ݒmF4L0ɚ&CLL)a444SL0m C&D&COM44MSzmM4ИI`L$64C) La?CA44&L0Melz\vB/j__c'm[GOU3fTF~vJ?vvQ.CJTmS 1'nd\"I& ˂QQ܊m(m>o9B_Oss咨k)`Ku`rP-t<澄]+[Ic{n46G?+qWFojL*?=c6`};8¶&<[(DnemcRLo`,$|WrŎ;_?ʇ 3B_t7n2oW8*DUs}W{b]D2'Si\MN(T WYa ܸc]$>C Oxyܧgя>]isyk,LfU|9ꩫ@װ7Nէ/3;eY=,^] ?/W}D4v~,,UH*>Vm}8ȮoGI"2>>T<[ Slii/m^|sPϿ|P *;Ԝd]` Wa,P!"xYx.1ebq OrOC B.=o* Z| ɑ袹H{wԾ&e`C'2Ӯ˪U !bЮ|O?H^"N婌o b}y#(]51SO&OH²*7P~zvgwڵGe &{}GZ/] VC@3Ps*3]I7I@\ Z9WqI/VKGBDЏ.Mswr5B˓5;AbU_[2̳`Zn yCE3C3 DxT-]+nIa2PCVs3'f8N qe!rצqA$NyGq;W'Ow@gݑE–1n94$:?\}$"zmzڕSa kLV_a]mRt$!f IuKV.)! $YH :L{l_B+x_8qk`KJ͉_Wa&;%쫏9)>y`S6dDIY4_Zn$ۦrfYTWw?Nq^IIQ ONZKT0%E/3٪wPʰjJ6|Cv^OeK^qP QPghżAR4n+D;B`cO^B _%ɠ3e?Ϝ8ɵp`K<vr+˺m{Ž6LXT[$C1/'r&T5g~/xWΏX9zu AW){~RWuO.L&fWdj?lxĔ bb`M,Q.^OAmV~ՕsWHJ"i}]>rcuȭU|8lm^2eڧ?`B.a/t!6dG:< $øٜ&ÿB!R5%kt &^ȜE31pIB2I `LHk^FZ [Ӳ _蕈pTc6Ckӕt-#v(#5[I*=g-Z9iD(D6YeV=H{!}f$y| dZra5>[mswZd?QOtƾZrs>B9}Ϫ+#+4^ycOc-a{r+p>76EwQCa4Qo3|01 v)s#gpOelI UOdFeŷ`Md%׌ ?q.iy&jŎS#qE )"`&Va>" dj{ L7Ƣ[H |Xkј q[lexm1aeGʓP^j3GaP~gG'٬A=mPMi0qre]9W64d%Z{ N?RMW!/lajf1 ze_?7w r&cEL,*ҡ[. l i%w^Քmt#c]}>T;?w\9UׯZ떟`6Y9&m;P!I"h?-tTs]&]iaϔ8 S7K u88(g :X ^JsGq< *V1ux_u*)Av"gЬDHi4 "b!Jsmf-B!O :["䶩&+[٨ߧb )5-y2~PUHÕ&{!! PS'ǛML-:XVûZ9}Hr fOb48\f޳577XXܩk$׳'cxE:4_j޽0p>?vV "'t'a;Ylx;%@Zy[~˚MajEM[8`MuI"Fٺ\r up _:ɼJebNnRsr+ElfPhnrѩ3K;աW? untyr~&`"T8 (})7-foG^]27 ZEeVqLr+ImKNx[ڔ\RުՑ{W,nVHaY R\$'Ln`E9Q`JpGlv '5n̈ՕgTIo㍅2%W"ߊ午7m0i=Ecr7 eUK99 _WC R ի 04Ь4fc^d> !{e aa蛗ʙRFVhSLtK+%GR R]fߔ}ɵ̝e >tXlv\x$O LFLnN4wg,V;閥WsE,$w*=xz61ثT' Y&W7yuޙ;n]}~mRc#WP>O@O(k ֛(֎v;?ےd݃/wmOA;jʩ nI _p`VyA ok\rfjy}7%nnt, QZClۏRE`@P鼓F5Z!<"o$:XC\r+N7ZobB.@u\Y3bV!s2͓{Ů) XG' ZK'Ƈhq!ܪ'E!s|~*"V@} mk:F9YBߴR;O-^yZx`P/.O @'T?7!^&ܬ%ۙ=v };)zm{h'1 =mHWQ+|̄o΁ 4nN(=D"zȱn]c ^Avws_a t@I6I%Rb/4B 9a` \d"^Nk6/M3>xÜgj|г% 5Uj+~{Ji-rgCIk?`b2Aa'03+8zؘ#S\?rWov+jUxU;J0}y20I^-ȗ4T=1jvj"qQ}7?쫭JNœ&Lr`Erf@7nRҬB5R|A_ѺSs{<9S[)q/ߴZ1IeG1kSy${ְv۹no=tK^vj(Mpa+?ױ>.$5G>p?g$]6vo2sbڕYjDT2'oC)>+k^|EA,xʬQ#Sl_0ϑlHrvV,Uě"8"S~ ~=Ӗ6ܑu+w=pAk fs$ȃl$IDH9 FģD^:<͝6)0lc(Wm,do&1[&?FhAօ& Ɵ@֩7=69d"@jEԕG_Q v2}c+?Y#pMItx>AH/ &,k2+OvSePEGX>GҭY`F{ L'aF1^] rdso8>#Z/٦^ꦋ]Y]C;^8)eZj[}jG)z3Q+QFoސ;3IL-s̺N.: > O]IGH'3Dgx73Ӄt!,KVl |d\#z׼ ah}|S`E( 1cZ5 n P5u3)xI]gsJn@zyQ,lё9!jOaN;(zFNA[H-!ӓؘS, dn DQ%f{9jTDAA-tFQiܠG]W_P;I. w`, 0-HNQP*sq`j ;뇘KLF*8BU$l":>TMU%ߖ,,n7΂Gs"297,+OXۅ.Lsl = tcZarI2꾭$<&:s`鲐M6yi}J^.ʹJ D͍Xus@q節G.BX VcJL>jԝxU9@wĀGGM§kAҵI@1+uKT.V#9} M{J.x[mLW;Q8ǔ# +Ǟ7JWr[ kbCDU>I֯{5 2Kī]8ʫQ_'b ̿ A&ˁ{Ԣђ Ds]˚\,Y59>$URv>캌+W{ߑ [:{;5"ў4KoA*`Ϝ3C@/@#<\K(x'u$;͸ڡߞNjj7$PJGSDBZ""8`V(7otbx*(4N껽0M)|N=5O4GN}մ-ۦLrXRl"f}BQ̞#Y?na%ŏy"An-Q.dJtƫ~UZw6m:gvr%8VkCॾ0K"QT -AGh|VS]E"g_˦/;,~yB?ePh?pT,ԌD`5w ~7W퓫_=y$'d:wRط䉚]1xp57GAؑ@ 7QJ.'<`(,‡pXv*U鈔 T=Rȩv|26P P@ww-V?RZ x\;m8'F+֜!)+ ?|ޓj̭!;:ج95:MHb~NHƍtg9}]2`Uj5@ 㤡cR`7o͘O鹧Y7=Nja5!9lxǴM(`t6SQ~ @\5_{WBO yJeZG;ܢh^OP%p}y#*BGs.H"IBb:cmF5^ sF3 gXҍ#̓,lTRaFg-h˫W2n%f(tREiDǟ4S-}^@V| zZ:\.i.%M.UK)Խ!i3RAC_SHW0kmkjlPN2_&gGyTt'7d?`Yµ}xRi9nytY[ɞi(!tָGϳO\l\4AZlgatys5KyUL1l"uf-Vr'ԧ`t3[>EY"@K3s y6ZiKxNAB%-$qn`tLvRqvFvI%Rχ 殰;}w/Ge{/՜M|ބǐe&9enFߪLWE=ZjuHwHPr :}ֹ.7Zۑ-tS7oHͼ,D{F'0^{{aBlX^?>Z=:V|W9?}^axMT'~\.( z늺lu <x8U3L- 5P2m94&^EmJbt4rV{=p[ [ Y8JIpLb2NI|3+ټumVW>Kצ,NA2Er?Lߧj5Q2zM 76_@P ""ahoR|/0HE2}τft _Ӷ8t`y1\l4Sڛ1#Zi~ݗ0! d\޳y9>+ |տi1] H4z,YB7GbC6s.o!6$ ~}LSqUgvQƿ@?=Vft_R|ݖ 8{7 mFk6 8\4 JQ3 C$,[˅\uR}@4f{rK<9MU[JяF SA7k(3zDhB穝ؖZ JAVS?8KζL585m #bx;0_z2Ugty)d'".'8[ne4[ý1|%Ys v?Ao)ho tWe)g?*X/q:C]Xx_Nj-]ٿT\2t+vHzemm}0$B pb]yrk Qp JWT=O߂ k'&z$CJ9B7)p'ǖ>waEɉ%ׯJ/g{`?PBEwK Xs N<Fkx=&(I`j&rY\9 8b,G܃椗\bvq}bk"'&]f_1;v qxlFY1ZxƕS$qvA g\%A@*V!!`ۛHxx xng_;نֳp# @$l`IzSkb`0(N/%:{Ū5mڃԢwSzauV+ Z^լeh`M2Y_wp$= #{q3K$e.TB}zïSj$Qqwgէ49Iq4q̉cdKx;P.H3+&,`YmX>oefr CCRRqK 2¢Xjn[mކ4Bm?ʛкl64 yP&uN^%1Nv`Z[C1}Nϫ%ogF;~erŸԡ1˟!#k]1ˣR)oGMJ, |#g}bP AYuaZ3-[7t~$]F\ :v٤əa3oXѩıBLD;q` YgR&U?\1)Ye|B;ͷ m\TWa`6pU X di@H4$[jI/~j0k"q4^a A?VxYR_՛6ϠJsfjmDc!.rnL${Y\#O*e&ŵJ@!X4nl@-3BY?N%esmFG$w2!Jԃ"k':MP`ګM|IZ5*~>p[R FPRg׌!P8iǫ=Aiۈ*=)D?K,<&W #Xv&vk@ؓ0_~س$>.O͏$~M=c9}l,`AuP)) )_/z&PeH5wrkJ!V(kZc?rTV^G/[WEr,OLֺXx_!<4>C4R5 ǡ/y#LJ m좰U'O?\wKdKg8*Ff s9x+hkQysEv@Y zHO3̨Ajify;+?\Ҥil5E2W)'o\LKRӿ3ߎRXn?=d {d"J8RAGw^ړV;=,.GNRsȸQ}ix0̣|+%&dIqʖ6G*LZ7Z5 ]ompE+-8;0SqL*L )sjZڱUXnH{rjoaM*؇_|f)c3Z i d^s,dzCdðCU#ar@Gi}:DEhubA!Ø70挴 O#JJT6VhĊ嵤bXD f#^oP3֡ ]gsYhİ& j!ۘz["U˪vSUVZRHtnM{+ə3 {m~y>o+uɈF%- @E?~^綥eYAaew[|b0NU-<<;CȕJ]_ӓ a;=y$;6*ΥDg oPbU0x?%I\H5yj5.1!/M0öߍFZyjhJfBT1b] y-|7g@$j `4}(yK*If>{d.߶ ־UTB?Krv,ONy0wOkb7og&g"(HhC뒀