web/lib/Zend/Cache/Backend/File.php
author Thibaut Cavalié <thibaut.cavalie@iri.centrepompidou.fr>
Wed, 23 Oct 2013 15:31:28 +0200
changeset 963 22a62f408d64
parent 807 877f952ae2bd
child 1230 68c69c656a2c
permissions -rw-r--r--
Added tag V02.37 for changeset 28987652c897

<?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-2012 Zend Technologies USA Inc. (http://www.zend.com)
 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 * @version    $Id: File.php 24844 2012-05-31 19:01:36Z rob $
 */

/**
 * @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-2012 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
     * @return void
     */
    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  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 tags 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;
        }
        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
                    if ($mode != Zend_Cache::CLEANING_MODE_ALL) {
                        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:
                        $res = $this->remove($id);
                        if (!$res) {
                            // in this case only, we accept a problem with the metadatas file drop
                            $res = $this->_remove($file);
                        }
                        $result = $result && $res;
                        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);
                }
            }
        }
        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
     *
     * @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);
    }

}
8}ߍݻrϕΔ~Ǎf;(W }^Ffe6koڦ쵦pjTyJIYhﻳ(U\ݿ2]?|tYn`0;awÓK p=i J#s[&:KfIH|Ʋ_6ߖ7=|yˍ{wn%ҿ(#z?ƊS/:{M^voVzպ(n5&{- [^aLĎ#$db>]ϝL/ЫA,y/)hlJ;yIDȏ?F#X}~쇄j֏MISy|&"!I0]ߝh* RڠZ/uQAMc]w\w%Ŷ֮ TO=Vi{tnepy,{{}HnP" t$`ro".qs1|ztMzO`mmg~ߙ6olLielyG]4%ƙN8py}SuiM#pF8;/a[DIU/َ! H 8$"g.!!}<}99cqXWiIzz[.Mc eb/i=Ƽ-Lz,|*3mv/MvZ:"\br*r#{a=FEt ̡_7hMTnaR~3K`)W^J%ZYmWHn2eOU^[(oIϯ\uaю~e]wbT5z~R>^Hvk^L ][: iLF߇}ę2"=6} 򞢯GgAVJ"I=fd!? ڸ>?hSSD2<ijtξI7zRhME^Vifӿ/AO"R!P $wv~]GH|,dXwpoZj) AxxoY"2xCzηF9%\7Nk Y'S|ez79aCgpkG%H|ꇿ>2g"_) )nO+Y9s:" $0!T8dR9pF+rZsەֽIdJM^om<\FwX*+*BZw:acitA@DDFIl2fֽmw\[kpEUgqlMΝ &ѩ2RXȠ9.NC1|84(()EW( @w'3F AxY'wya~8C&h} 0CLctŗ[Ita 44Ƙɷ?0iT Hxr!iV Z̡פbysSOPtOÊ , MEb) 1،HiLCLldl,ÀиR+:4rlq ph)aPQӪ//"Kou&;>#B΀w~dFNOd0PLP4@ԜTlPǼOn&y8YK=T,I$ D/l*  l$2UR ,agKR&`V$cM 1 :]3pB߻C.:q #VH𸄻uigc,?FF32MdF)b0ȀoG:i. ^qd?yG}V2a5ppHGiz7cZ>f_%20 da$_ \5zve"pӌ7(l:,Th\uo]9ޏ'1$ĴƷ36P' 膔nL;)hƝ.<7nn Pd1E~"Y%3}`ɻ_{+A21K|ɏ7|{@v9N@4O8Q XuH,4U!Co4BoL䆙QԉCixR,:3rbygÅ-sׇg6][)( d"UavܺC[xiO'C`N%,1%FKbz8Ȓj78Nf2Dn6DPԨR'MF߀I#up#*:美4cbeQ"Q̪ T&ݰ&?_F*& ђO -J+)]6 eetiS$%, t]n>TIr7OL|F)r 0c0d1'w$dV!(L5J[fH:^=ˬNOe1Gխ" mmᱻizB^HxF~_x?S=?NYqt@E(ng; J?כn=W?| χPD=s TAP3TR::I~h}gT_&Qsvb%a63DAD% C_rbj-s+x˙FĴlnk\#2Ҳ4ٴ,LA3d @RrNkҥ+@G ねuIF)RھWPb. &>5 JM,q!ql'HRKa)".t3t7 əO{?^u:C |8h$P5MծK/P 4UQ4dl=s2aCްO*=M{D$ h$ZIC)vC{lG 19DRUlGq??u()i4FPP¤CW8G+<7M8ձt6m]1vC!ͣo"¢Vp?mq&0EXVF9bNMŖ[V^g::bG{kw3m"eP̕$!"$gh_Qwhˆjn莹ݙs0V(HF<??*:B SٌS^ovf|qO/>Kml-Xd^PE /C"tqN|;dqxMc^YYxHhD gM)h%=Ph@rW2鎦4U Y c7: !J) 2R $q y-)2S}:6z9 v!J2/yB X[7M]W-zUpwnLS?{HB3Xv i_.yI+&vi+mɑihaV2anjHL(ׯ䊏m!!'K8.o3'KS{͇1OfcޠƛtFw-gaIucJT|q:t;! @0J#3A2lZ6R)Em*ji%PZYtddMxA0K5AMdhYj~zPp8D Qab[ĥkζ^]F@6H F+-s)2’äR! Q?Pv|#WmYn(fSPW!ɐ6u| /pq4ci?^&ih\Xƾ|f OJF6&:oFy}jh Q+*R `yoHh)眻ċ#*(> ?(}nѸCGu7h%DP[SlyuiL d'$QF}Cm%q ?z`qCcF ?ʐ?d&(drw:% !0d!xJl+gϣ5*kV!;箹ӄvd_Cp 0ɁX`&E$C @Ԫ~Uv5!V"N\0.UhAø|x8)/q<~Oi23gN{!bh-I >>){SzީU[Ĵ[:pjUJ{wD1SFdI3 `) =ʜN$ė}|q@}p &6* D|j.j+ͽuۏxi]1r7Ҋj`"%*=3~o[+( *Kl52jdTIceeeK[LVl5&[K*R[)Em,&ZW ]-^O$xUy5U\}$ Q(m0$}cov͙?S)%=1" {CBIU g4`F)~op!q9ıX+CBuGXp匴R`Jc9T#/4?+ g;(?f[u5'SRvqST& d]RH4Wx5 ֑4}*IeZ9LI)I(Uޤb]Cn$Mb7i$L-*Ba89IU)d(|d J2+ MFL6'2$+:Z)a ; UO rMµx!MQQӘ$H?X7e"I2dEFrĘNw~7GUt^ARL,*B@!R!=`)n0yg QBCFuo 30#?H0 /.aٱPM{';I òr2&"9r{;!Jȓviz $qrMRIH:FZ`t Q0,-sY T A5HdTk#bsI;RANRzyrJ.׏NWfCsc'I$Eeua' 1CD bDgoݏ-!w@B ?rC\D֨ňEo\ l`|5h nYzH5zHہBHEwS_|د3ϳ)ANNF0["`$E̛$QiP0ʅȝi*Y* p1 '3-3,2!cXr[fI7'f !4LkW6drٛuxJD?O4J >p?~(-%^c+|x?=5 wCntQOX=nj8 ?;8mϘBЅ 1 Rzq\4qQw ͅbi0T ̓Il?G_w<>qO=8T_.}?:Htʔ'Dd.Қ!?@( I#V"Yn`GCJU875-H)!4T~,pd56mrmT"llm$Tz/< Ad[ȆgNqX6JԾ[Y21j)edLX%h$R6JjiXƙ%E%"`h%BaHj5i"֋2DQ;'B n#gf\nk.E].ݻfU&ۭaB,Ԍ8bC%}7Z![2]aE#^9XP Lfڀ~љZ)ixml3 wT?/~3#ʷ2<\oO8tlêON=Vc#5%)FgQI WmdbXT6`OpGzAS_٣٤l?-}YA D¥$%>ۉ? )$ߟɜβpop$$* ? Psps% eBBBIll[([([([)}>աP IH.WL*oWo OyC @&o6R @fS9߬;:o³Iz]3uNʜ~.:]=rgݷ.͊o)FFCDAo-E*ڒh6pV%=ɝfxIIJTYs b`;n}l=c PaH|>lIdY5/`km=mV^L_vh d%HVpՈ0H8T( ]`fm 6( >6tz&KNڔHxġR47J0Fr1ԩӜ, If 3$tAp훬Jٙ0Q?Jv79<m%рF BF;O8;XFCW+}'"#dz4U9=4\TĥjփHSD0!3 'J{lMfi}gi;;ô?$2t̵%ac$9 b mdځNf0ؔ(HVkeR]%L-1`JZQļESdmM7xY%=K{{&*Az+Jv )?P0;;|Q R'D^K"#ˁE^ovf[y!Tzg)*K1dL&M΄v]b9y ptIךsBjzƼYB@WB-\j-ͱMa#f ̘ʖ8 MH.B4B$LD;`81V3ڨCGM*0/=^TxcLIc{2U|fGE|I1~ߨ͸;ѳ6g1ȫͩJ|#@>wG/䈡 ~?~ri<#4CCj6mVïȝ f[Qd2lM`#~;fWgAS7H  o \8h5ݏz!(&C=zo_rukO@խk0 ;نh3uFs`U"?m}EJ;4drT2Jx|6N >?ØbE k GGs78>ùwiA@fV;`aU4^<,[[zӡ &iCծ)%4f)`y'h1augI55t'NmyA:v4^:̘Xb;u%%I11Xcq3+Ṍ "Nv@NÏ=ھX1`\].)2pJ(!"5L 6%^ZzhOL!=F=/ 9@+Pᰤ̌eQM彁JO1l0¨R'nzΣr!Xa"0w hz{#X('f7:VU=bh1.- FƅFnfe|]ڐ`Әiv˕Q^'F3[X"2AG5C&(534M,pIY0Wxrf{ړC MPi1o3iנAvA'`c*!{îC 2Q ya&2EaQE5g Ιaa!8"{gxŗi!~/X8,(; ?T (!JJ))X<3o5n}j!viFQ" Gh ʰ+Q1fpLMdf".c2 񒑎Q4!v~kBCJ8/TNh](+A7}ĜGyČL\9IIbl^7p%^ 7ѴRHr/c.l!GՈ=Rsj(M|RݨQDV#}6~w}$u1&XD8SG9h{DQ#*x9"i@D3%b_xhV!B"WP,LӐ@jc9#kkYI^MVb[ld)hH 2SZȁ)A) PS$S @Z htB P:7ҡ!J 'I s܇JwlOO-ԉte7)=v,`]S5)%ON- Eq.މͤp Cm[v&~\ɢұA~r) i"m+j"HPnC4I`LgٹOX;p nF| (s"1wDVHHi]l,L[Ƶ9fmfT,CWLʷy)oW+QJҥKjQnu\2Baw2U)sf$<^\ dqa\C٘2Xҹ{:^Z߾c>7݋W,$"X|>PDz!II zhp'ѥ;D; 1slڔد3,R|6HE!E$/g[·7Vy>#Dc60i1Cz7q.>u蓗|T09Υ<6`f#I7ɴ3JPJ(ym5̔"& Ezx?_aɽbc |Ǜo%E#Qk`m͸pp(d\`DgQ߲,cCl H4?5$\[eo( jpEBF4<[ P{=Oﺂ`7.+H w' U=.Տk -bC??v8Sc߉à;2~Hu"cM 1B'!p0M gcqFC> uSDZ"|( &X M;Y6\Tdco.L's=]9gB6 "HFIʢ (`- $ɶm{P>Da!A0A^,qED˯}RzHs]Df;`TJsU\US Ȟ>{<3iʁg@~?nNEz>9 iʌ|PC *Zg((\gg]' Vo[ (=f}jxg:4qjJ%CŔA3ɿZz鞤fQrPQ]p`#+ӊg =D ^;A5^(T<>䵍YW b -L +5=2N(!O'QwO^"|C >3&Q H ^][^d/'"<#p2'Pʇ3MSfJuDWp=B-dH`h]lQ  l$宸V(0pf̂b ׮Fv.`$h4t.6U#ux8B.1l% ^[.2"y\#/}xy񭄢uAȘŹzIV_LjaPYֱ2:j,xQgð曌;D8ݕ \>h%l$)24lhP,C YEn1.<-J _ b< !Ok0 ϊB 3Pxz<RLm ʼnFY!D [."")GI" Z;QƑh@RxGp 﫬}'DQPO_AE(8D-MUxy𢺹R+&$Qa|'NZTt"-aM2`b*QLɛIص!52EI(OG9/NQi*zhȤgDDBj/Pq8G6ai͋ .j]!TqҍDRo;;:{qFDs, A't./KcY>CQk^АC? {(*Ir#E@v3Gnk)\! :wKmI4!oZ ܪIe< xQEA"bzwmQLrڕ*aD6(S_,ȒFp;;"HŦY! "v_gv.gV5cE{ qЄ Ϡм'mN [YiV~{n#QDiDJ,WmGDQ_\02e ŞsQܵ¡wnhӪ&$#t䞺ZI,Pt0$42ҽ8P+)aw^du}d>ᇎf " +Q 5ߢE!sf|Xp"-ܓ gEdAY&(>A=нnz]\SUI*򹣇_J=EЇޯAuFJ@UӀur%ao 7SGDĉj7(#ՙQȈ@nZ8E (#/ő("[zTT( O}׵{{苞Tz=GD%:*6J1yAib.y(aeq$ oQIm5@zB=ˈygnU+ K^LJR6G"D݃wvi @B6%{-Kް;AH> v'"Ea% y"'븳F^:׊-W֍a(سici<ӎ8IC#qAODX1Gm먘DBԒA^57n;qqި P=D:,X}NzPz;EbL-\ !.@t^Z(lr{L"e[G 3G~&)"!B׫VІ!قc' C/>i; s&O>>~sN: +q9Ȇw1ݧS*(9C!DB.oEK} 6(qGs'QQH}TorOˊѬ.\ӒјmzOk>G>D:b}&(lWeahBę5^ȱQhfsvFj;P9Jܡ!$+ZrtQ\"%{ -hk48j(ڇj6ltQE#NtS'Z.%C/{YP^EE.yr%tN=ַ~kW5.>NčPuvPz0 R<}R*joKnrխKʠij9/ hGDDņcFSUgR3 Xw;dm!pjA vE=&^nvWG7<&#SScW/]FZGMI AH pWoWyG^8=.}QӈY<ֳ?DDvdˇ̄8{lV#>"McM}GHo<Șt郰 gFL7V@ L$ 5lb)& NMO- $fs$7eܑh#Iq%wOkûqýλGGTF>$1I87_J~XC! *^&<a9:‹"Ӊݷ %.qF0ׁ7d:uciR j=YVqѵf v5@:!dsL^R-P lW CAڌ$p$A9tX[ƻFQ%!QٰѠ9Q!D pIRj)DZI E)MR0E1KH\[zL8G٬*mT! Q2(‰ +Zwc-C{&$BCv)puXVٙ1NrDrUлֵ%ɝq_k#QSإGJAPGaAփo 0pAe\D4$X"1YvJBJfmPd#y6WW|ycq<#<GT9J;Ø#ezy%Haaen ЫwxС\ףcEq\6*#H/6X\]t:`yІ#AdMӡMG*% Gewlԏ^Q2xCȚ;1GvwxsnJ*,Y-&K;,ssjRMv$)\v5I{Yb&ť$_J ,@̓%  <䧋cD#5ᘠ߬;^:!vil 7PLtpy(e)-Awh%#"IqbJUD竺1ѷIvюDFbSz!IA$$/]~;kNR.,e,7m3¢'~ROѝ/QӨanJԬ԰)k*r6ȒD*GqEiˣ<|]]^XySGvBF{֧8֛_6;R-uFL1a[7P{=* uso%9%u>K.HEކ&kA-z%l0_F'}s/4)8I "&#FLM"¦Gr-h{vg 3'ئI $}7+.XPUQ^GfR&l>19|eՋB62v~O`U7?k?Δް֨P44TP33i114Y2j֫(Z !V* ,JhI~])!U"kkymAU ZqC`GT3 2E$TccS%1؊SRd"M3ӡ$G3Ϸ `y}m@90Iք$.7L$3o%aksy;@’ `1d[S3%ud.r 2P`zpc#L,A4q\=7lu)yJF1y8XDA(Zָ]@vd60tpp Eu=g2Ehp3mzCF|h肔%Vxp'p?_ tYެ : ɾLxt3*@e3ca~63dCCߖ1 v`I)<2T'Hvޅ4hur3,1$ǖ3R鹱OmCa֧I=o)@D1,Rt:HfJrZL\%?GeȫNnp /;D Ź _^(^}F̠,b& z&,啃ALύ}"Q``! =:P+bF(^ Il*%,2>Sm",Kkg@Vԓ{{m|&7O|)X]aZG !XڪH=NM~Yt+*(# rm"2Z19RV)C "R710l #Bc[ioV4L)M.8l%3rHn#" Q!V='u8;D@[A(Pi[~% M㆒&%M$o;ηYf[MYkDmd;%cfP̕ILʨwB?c!3}GD;%GPN'ADT>[H!  ZRM[bxwTJD!Үoތ72O 0Â$+{v29#KR #sF iL}6yNc%iIr8D(Dlԝ6QN<=g<b)C(ۮyrO%;C.>4T$&#!`GVq8gxD7sxXFSu)!)e5tSx\1@  U*;׆tEVɄV_&PݡQC  < {b"2[L}ښ}gqd`g̸ >Hsאҕy"}6{pѭSfbjQKλ:*3Mm#G/8'(('&SZ-Eww>!8S0ny(ڢia3+AL|߹m==K+=2&BŴ2#aHDP84mj-![&.Ox/d>=CC,֔QD,cak(:>݅Pô=ړ&ɳ0FC0(ˈ1w8JL'sۿ1{G^gRƫcZV eWiԓHyLвFD"%9\J> sq 1" I7PJU,aS%ƘTz梠kHɰth%BĦD Q .ϯ4t(l3\`D091mͭ4&o G$U-IU;Ֆ~8$`-!2DY$5z5R}_"73JDC ffaB)erD $V\HO=}.t؉(ʟŸQz>@hħZ(|6v2>ir͆ gwD= H8Q7xO1.3&CWlMJ̰dD p.T#tJs{QL&8.5tq.d!DDn6"Ni <+j>v)ϓMC9NHQ }vyI-ZDQ_+QhRU@PCR!/a$t R2`ϮBu8!'\*<"[{߮쑕[R2 #@8jKqH73Eb$DAZ!Wo;Tջ%dHy~:ZS5I*"aA*9a ,`{-;a}zWOFuHғϝ/"TD-TZ|HJ,d5'CRhf !BғpЍn>$ץJ%lC|( XB`3=QWn;g SM"ʀS/C"iG&}LK\*Dyx帘tY׈x߻"ba:o& C,#>`Qo׏\tarEG~#5m "FtoxDW!'Fԝ>ih ts/戃${1)q7ⵈ#<z"AGHcF}:"NCѱՕvp5ED!y j:O- 95OObFlƊ5Kʭ\F2 +o% O?j(Λh&!68 ίfTM1*"J:kA`h?=#kED\iksm'0o*¬u&wn8d#nW%#Mj~ tz$ #C.bˈP>ܻ-ElW2N *jXCF;lHD#%XfC;6q鱑d'`,Bc> 70&qttNE/mF99=3,,%Pn~0]S{W SYk&O171Ш(q6^Q]okt/TMR+fZ$AA`~6HqܲXKi64 +e ;M8C<]̢BS" `Z6^SEIZ Rlηnl]TpunQ[tmS{OVbb351-[R_%E`5F%,k-XJ !QTh9&s7?h{ Սs]jڢKJ4"FnvvZgnݩiߓ69tg^o7-'wv @v RII26Qֻ)ta] !yA{\޿(/UMp4xX=G3?=G؁z C%a gF&iʚ} }Co,qН1=SϤ"$$29uvmTtIo_Cw^i(rDW_ȒPװ6 Pw;& <tᖑYvmG^ _vBm{ X`H1/{'`8{ ,HF|C?t '.|4d%1ހ!$8\f"\\2re')Ly>s#ڞ10/-U1a>S!d! =L'|JkG>܆2kfi٬k\C˞Ejl^W_<]B$&V@$dhP4" dWxJ>*0S$d|]݈(`ɿQu u4#c^(2OQǓ`h1QE  D_Z^JJ8&4 @&)d=::6pbnS+ DSFɘ@xAi˥;R3t/K0!Py Bws~fO>TKx?N飑JuVZps7C}j؍*ݓfά7plj@ZUJr/&$`9[+,+hLPm !%s O~bv B(w/Q А%_-fc_-J,?܉Iڸ@OgjmN# 8+T`Ov6fYGjaHKk-& 3teusRJܷd--βmgY@$b:L4BKBY-ˆXFdPYG]',8$QӯzܡkSc2ʱ5Re"].h[EIs]m$F]PA 8jz׏5aXw78Р2ZW">| >Oc>{hzmDX<#<ж|p)dk,)LU(LA#H|b0$?݊Tz4>;IԮZ5DV`.!hx@P$*qéLkdKBpW̩;&D_DrC ~vq]:Ai5v4M&7#>rG>M}h+\3<0z bJ!H{dkb%fa ⛢װ1!X5X &GΨwC_XZ"2ջ`Ge? (&xmȏL5:{-omnj*KQȄf]`'>/> 4ԤLD,J d%+7-l4fm2M EP#1Fͩ6EFFMQFXҕ3Y2F-K1m*V(i5+6 -IEYSXImN-Yfd%QE%3d2֦J[RrfM+s62h1ɋhdk3mW*Df#S m5mj(hD2V-6khh6sUͨLeh-*mIXѭmbc&Z[RE +@P"owzs=rPĩPH1PYIVB ! .%=igvQZަloDԁV*R2U%FيM5*Uʤ$Imb(ɆTtjP;hRX,"<Ëm6ש8YMQ|PԪR&.~?o؎H?_*'s{|!鈴=p-x`QUFugR 4_p3ٛ݌z<>O;5Jb|l V,3,b_Di Hjt ]+*}NCb9Kq@O._w ~0# (m4ÑaSzIRSwt9dD#NCCe!lTvacXGJ(:  Ҙc nE<=*)\Ϸyd,=p$5~j>گ;㸟䞕U){{P8>zQ OR? ?Yt9Q:!Q99Z0+S̄8)n8EiHDj[Z< hG^MW@.2,7+zVk$'X<"9Ip(P98jT]s葤D7ă$ĩ;Ę$N,Tw!'-1mM_/)7D7{ȜƉ2dә}>V]<&175c#hR/&{lNx#jR2`j$ a+cuFzczq F,k}aӮ&kZU;6b?F8>|?ͦHiN@O) 2q'.8jәe/}C kR4FiFĘbGY)X>DRNX*hcZ/Av\I424Pfc3QISY K,fhY*Wo}֌iVLcJSH7_1LF61зb41_лK-xH a\tC*XbI,,Զ$ E8,$ 81a,YD9 ByNIP{` CGNF9)AZy:(-%-o3g|ڂfӗ79K{}L/t`ɑBQːZMR-K DOO15S-Z{ɋYZ|kwZDdt9y&fgdѽ%"#\LowPz4TYMjZxX[Ig=#owUnԊ)ڛp$7sIAk˼=x,2M˗tRb2֙jR)nmTelKǝ^4 7_2N^9ΖV2{s[C2U(.bӜyiC9c +E*dRT&?%ii)pP7A9h! sZM )"cbħF/c)EƘM&وJ`"cC"r3F@JDb1JJP (X=li=0^"=mY4W7zƋ˷'7?3WEuF^XC)!:Jﭹ"xDgFRvi^KtԛINHI19T}Sä^<=u)a d-Q"Vi%A9wMQJibHdQ0a.f$Bbp_lEbhh% $W1OQQhFj ?wCJSx?CaJQr ܦoGP訶IlZ]AJ z rJĀ`eC% ?u Βo[qxP{fRɫmb[E51/'C=,d?TF J9l?wퟨMMCyw;?'gaV)K,yk#=$BcD_eEu I'$2u4IÈdy !^NJB(UlJ+y J` {znk7E.MVƔhq1\{b~Bo,cI”T1[i, 1gKzXEcx $gYh4x)Gp{wA"ך$ʏ]䐪7+ȫU]{d4]LYZ7p0QvjcvGY{>e'moExߊNɰ#w[.ͽ[Ro,g~PG"G•n.nux;7㹯Ufj#CAkG ,B8"N s7:֎k:,6J#\n{$֟xQ?ԭQR ŝr(.ù^an6@FNl)C4fDcI ujMS \*8*"I8,0u a,a'Y/R Y|3i0\NHo=+ ^O'mGF@=>pOeS3=nj)Z)ۇө:I4dyW{}OLpSvPF|9Ěr9=8?XVV8݈1S&@k5k%2]bp$Щ.0ݛˮ?ۣ1S,t'n##@S'֓(-Gw{'/B{QqgSٛQr)driiPJE g rVd bZP2m6tZUW m\m'5a % "0B4U9rCGJQUŬmjT)ͮj[*%UlPX#%6-Zlm)$Ia_.ĬN:Xp\3ZA}ׇ3km0J"!}dV30?L BC/䆽C@A:{cqE%>sd>{Ftu^ FM1WC>&C@~`ڧIvZP`u&1bJ ٞ FVsg v~)Ϣ2"%)$;UW"(IC n+aT-*,H  V%d2)(;lPb/+OI/0H'fi Ԉ?$'"5=0ibʕHbx9w_'~HPŦK|VćEHw_r 󂅮>KWϨ7$n'G_Gc?C>D6aIPX1 (ln< . JxLo4L}r$q1IoD ;WA"t\W8ljn' G1Ǫu`d &KXe?W잏ÉYtSF]蘺O-Gƾ=mo/JG0nP")۞#8fFLliH]1簠:h$՟ōomKJ%.X.т5@(:bAm)&-F["hB߁/MˎZԯ-Ƀd Kmx( 5L SY S[κHQBu( \(Ē6%Zk˶#h F2ezj˼]8ʂ;tyF~/gprNGc#mzvSf`}FI߃ N`[`UET- h_as=LLF%rQqs24X%XE2%&S8!|$L CĐީ"lCNX΃_R}^ꯨn$zHS$~.ޞ9&S)|^)s5F++5@dc& J +8 020L2ȜS㏿ݭ$AizvjnظCG^x?La.j|Hmc٤[vhQ8:xT,@~+\33[ s4qNWi (@eUUfuVT L|x0IpvĮA4B@ DF=1dS-k$$ %%& `0"Ms6Qo[`C6JbxpeOvEcEe2Hk3X%d$ReCR7[jBSsu>:iӁ]ߣcal@<422y io W#ȿ8c&Яl~1!@>\$O!&'Ɖ>LBol 9TYT8ō cE CĄ0NH6EJRHC! `H8J2>fSFbk#*p|C[*⠁}@+)#l#u!E.zŁC2GIOBȰBH02HIiŨ8~{}-ĵq&x]]HAQpaJ?I-T仯N΂Hk++WNkKm GWsBC\$@ˤy&˴sÍyt=qY>,¢ `;{Fņ0  3\j}Z81r(x w_tIKP@7yxBrO,_ fƬ<ЭKb#!y `GP7;bcfrk k4'hb7́$3<,SX1Ii$ '@nA <哃bP%ż**ME͂B qbE B0';)BRIöBCr< Y&4L$MhBD&ر *-Bq*d2ƌG$iJ1d,4ȗs p-Ԍ@HQ$!]i_P 5)zPaK*[{R;hk+QCqL:fbG#$`4߿裚bEQKLB(U!>\苧}`iOD?1J|CBR5*xO_/\gz2{9HfQT'߈I؃p^0x>z;N"zOJPX7LOɡC Fvk}z_jr}lNlrbxXAm3K65RiHRa#ܿ IѩօyjBmjI_/vj-l5jjm"P*H@Ġ0BqbĊD")BŒZj[!mTTݒ#KnE+0xjUz?&!pTy24 I@$xwL.*׷֏{p$?Qj!zssu:0":De=[~a*&Ō]R{ 1e,7uu0|.-ᒌh@:oJmniX8DDB\G.qeC0 1Mdh> 7'EFœUtY=zLG쩌7q.$N?̙ 'TrF`,;;fP$^ORumo$KhM?y[`x?\=[+sórĦ"BI$.O;a˴N0KX0'Sp`ޟ:xFpt< Y4`F#Bifhz(xkxJ7@$BǣLm EPMGksM<g{'?%B B6hT33ɮukkqwOaT":"8gBb&݊M&#/&~QVj(\Igf 1ù4!"67%E'ɵ)Ӂux?}rsƦj|!DJaG4?*uÒhc:417vwlFQA$j} ,捍"=33qotA)4 ؙ ppɓ$ 6\? @ڏ3T77+Щʇ:܎|IHn ӔD'{=jCDlkN>5$O*OWr%%Hk&ꄶ `ib ԐRF0¢i dIJJ*吸FTdp.6P4+UMY:`;7jWXRۊq"Eb%bȣ-)ݏ8PX"aýC -m';)vƚ1sXɤ-IRRfuBn Pȝbm9˖_ciͺHFꚙ^+c։iQEYEX;G6Fǃ >yylKk 0)Acb $OJPdZFBTwRD E-"B "o+ȪEۖڼ0𴝩x{UWJ$␁  ߾c?sdf)ZKRajU B6![~.!(:g8;ZO?Q/Ok?w쾘 uRK3~sIBK<)1jhjK'+hޔ!GoLl20M.TE2֛4z_'MEœln&_{*U1j5XFa&M1 ,5v)leHC9Y=0J)=ր1(ZxVsΓkl"xFq=v\Qwj b{eN0D&iR |>{: IA/x{cT9QC8mE%m~H>?\xO);[.Hy ѣ\dfig!p{5o&4g/F3 (rrkKÛ9B_βD:B9s71r3ʚL xsJQ *i{&J[tI4Ms3ـ KM4\¼,MCї1vt DzA"4qc>r+[l% $w^ggH21\\,4rJueI a" Y`@D48< A*كF0-0M1n9c&D'HV8[`&m6ͮ8i1b NVb'f`Զ*PYPJ <^VIm=l?}:"$BC22R}}<[5J[! q:s&d8,&dv+!lK;pw)i ν:Q AHqx %$"6[l%@X'I(#kɋ@HI&vc<#P؟AJe>`a/e=wζ-jvd(xj+S^j09I@Nwa+t6&ಭqDpEsZn&gDS:pQH5Y&*L~qYm]j򪷳byM$w {ɉ:w]Yrn)0듂 QIE:zRh S ,DۨWc~5G䛴c"8ڥԈmdDd-y V<ߩb`y}d :VFKh.ܴ!Dr2BԵ  ="g}Ya > Q+p?qv=E0C`ȓ ]L-P.K̫ 8`}, rݲ,[-9Vu2aveWKأ&S?I ^}zs]=ŧbrmYQ"^8H4-.` @-9>)%/ͬۅ/ ! U@* xC7 ^ri?׆ :OEj$?l9w83po 3j#7i00 U^7E_9 F#JRO̐&DQ )P9G7-](ҴEdr^]nmT̳`j*upav'h_aބI D”,te0d;@hT:!"MH-y"8d'P4IYv:6EHI$0;;fӃDpBp{*$?]F,P!K!6qE0`ci) !*eeV- JSMMQM6 &w`@vmd@%  (&d19nV!.J4Tީu[͉,huƒ*ݫ[U2K]uIIJ:ͮŒڤM UEKC"Y(!dPCS *+f>7>%(w盔a0 dJETD>Jp~2:G9l @6T01!LhZ$yq=pRT+>7@~%AU!(#&.`&fh^a/G玅$Cd7NlmSiMS 3gO˾Pn0(whERȏ{ŏbb"1D=b2c.BbU@)(DE DeR0)h[` "B0!( _ bÀk$AW 0t"b$&EL6Qҫ p GE}EO i6p&^ӗ{:&;쳉!⁓PUMl K / I3A|L"1 2nA69RonNi];H`r iN1QRD?7<ηƾj[J( @J~{7 6ea^2UTfJ%+=rF*STmrE)CM-&'fgA u 0Va(4y#!&#q1vvmIM&Y̘g&MĄv⡬PnJt[ՊuڀQu^ya;mQJ%:L 7CvX9N"%ۅ^W7 A쬢zyg}rSH@_v1dIm_V2ZQy+EF=Id)ʞAHi, $. d=?:)vHvΟwOg4!-t=Y_$?>`rpB@ɦu8¾Fq8NF0"d= ^!wY*jfFFFĦ0oLO8)iTc7р!;M"@,8q m<͒M\ Pp CJ %* HlqhBdShPԆ2pJAu4L DD:e atٍ"*13(j5dkvdRV̶0< \SSS.(8!܁$2C$ɾxL 6p%6IS$LZQCG_aĞ|%1b,6NSRm7Í 03,3:,e+2)jBԫ dR\ԴK),jqeCy~H$ >``j|@bVTpǣ: 9r9m6,?vv١>O$,Gʆn/A|/Q@ Dea}"{f#gIQ9@澚j"4~uZ,U/i5]YTX(45%)JmR24iZ<l_{ ~,,~$݁!ℑ(.t=\j+>Uj=~__C(Y cHeH݁FRNPa7]PP8ICW2\૚kUk]74t`Kω8mḱз:4%@opї>= wˉjSC audQHhH&Bѹ2WP%ġA@zHAe#f-'+ \s\֏+=$W뗋ƯΦ, {:trENHL# "I5ӐF4/h KS7s `$D7͚F-Gu"IF#hߜʒmHqwYΟ0$pfkR֒mpwZ&bn&z&*1EX1!w;z>7=?֚hI]O'aDVvLa ˁҰwñTL,= ɔP rK5OZ H>>ESRE,-JȿW^n1 LBPõ0t%>ቂzCU< I@0x &*SlmW6EM$AU =Wa3{DcV3kK`&B bPeV3RRJTEM@&%&"UT^([/֥ը̛Fښ"b#Bc%I%-*kn/6bSL Lhkg9upl&*()aѾpIМ@$!JHX%0+LڍIY33 CI"Siud2&JW1 G!Ji b i)R b{`тq$q-QJ%5le+RZ4oӞ58` @?ʸp\"C$Lbvvs0v}Xa*fUB@wCVIcƓӣ;,b.{NPLpvBT>N8AZ3:c Sp-!C@ŗLeeaT!NCҪ= ӻ2^̙8$dF!~ ?V;a* /CĘd{sD'o)mx׾Ӥ-&NG$xK)~c?>VYy %Pшb$*S82,T,)*(R3RQIRj[Y5YZk,jIi,fŲRL *[l*H*MMRZԲե+%%d*ʡ+.ߑxmoaRjAsOg플XOSGMl5aע႑' ଫ' AxX?&ܓ~;!:ga\pp:|' 3#1f~lrXO34~XLmØC|wՁR /Z2'm.HXt7 cgjb/璽4lG.Ni$Yd9XK rOcu18$ظ 9f*a2eMnٿ f,LAM%ua1'OaI D&5͗n[&X_ѓH>8NS] 2V#uiAa3ztPAFgۥ Wセd٘>z U}҉*}Y8D~#5)U!@-x{żqGb.'z%1)!?NӘ,N 6qJzĘ"""(&LKd̕(8P 񈆴lixJ1Dc$bK4-(HZI.F%"9B8rQR&.ihjS,Le|1X0YwcZx: aҿYIK sO%dyždz6]?#[ֲe*Y0^ Q NꥴU'gx\%{}a{?a\%vy{_: TV'~/ǧUFrQN\\a2!|Jq0 (zT([$2p'Cb'IvM0H |.biGv *Jn3cJ.33ԡ֝9hã۠D8qם4% BK?MM* Aa )X##q8x"ȔwsAPv) E?)1JH"~S "dGCð$$񠡿Oh)/Prq b J){20Z\;-P?gk Pw*)Ќ߫9YHTD*| m:MZʩ0nՕGc5DUBs㉤\%xp3/0$,l3G`IBbq+61Ruޤ=zrA-cՊ2\2W$*ϰ5O~/7Fբ+/!2Sb(%FS>b ("OLaϹ>ng쇧r00`6Q (P]8[mQ^nefx t0w2>G 80w^⽤!Z?R[m_q99AM$$Ȯ!N ?n~iz TLDDO==U?ʐ$0 ~1Rϯ&?wHN d'ĆDPal(_~?L)ΨӉ4#q(P.yG" WO,,qqN Ğ{xhAZc?9dE1ZBxI"D"Eu"B!DSA mWmӧFܹYP7#^2D}OUύ!tgӚq{aFd'ԑ\=0OO0kܘ?:u'Tl٠ex&0pM!ᨔ1 8q!3霤qJo$ܳiGԶ;͝N܇GV' Pڳ{>C]7`/8x0dRҢNdM,6dW.҉#Cϙ$|NEk e"YT*8Z9wN5le GL$;_?OvfWa"%^'0G9\}5C*S%TNqF8"El&3Ie*<^Wʛ;vn>9DꙆjzzm]:*dL}߫#DB.8DDCөV*7uiOpUY?鑂OH 06Ta2PB)(W,_ j,%4!RQu{s] $D)=dflsK[d!tr121H O*u4LY4v3aQ:JZ_#PQ"-d#Y&ꍊѬjej5#w]r&ellhA.Ї=-9 CaWMwHdu])t  KK&ɤ"a'IjKn$,lLbFӆ4Fb#"3@Sc8<"B&HEFH -Ibl"EP-JZTc6wn.XFQiA6!+$jXRT[](Zj*ib )2껻J'R/D4VK)ImjjVYc FW MI4E,R,$,Z15AfV 2IleJYQU.sXWl;ҙbRB;p,gsYnsk$F]: ?T旔pJb )JR(?;U;qK9)Hh$$-sw 4:B3%L B3p@eS vk6OpȎέAm u2kC@4Sxy,aYvLQ<Ł6n*rQqp<ƀb )iDC$Bt2R |Of;u<^pDm:3ظ3-^N7q·gtƼl8sӼ(hyLKቸ5`vFaiCo ԫp&'qg:JZ!-Oҧ"k|]oS6c H7"Kd$d q7C\1ǣZT᠟9Pl"=)WzQD_ֲO9>z!LyR<{nW2 -RR%(L]i\ifQR%J%6&MJwu'vrp^*iHO2m "S&|{f}zdyo(MMw2EQ<|Rܐc `HR (Gu5ۀI5i#n~S~EE`! ! dbAav‰Q"FYuGqE*+i`Gb"\2G酝s9r+0D꘹‹0=ϻ2l8/&ƂS`yb̀VH79Ñ<Z[%@0 J`I 4G yvpZa R&Ӛߓ=yx C+veU_3l;dw7J-&~ӽ!c)nDM"@* [\Xu3uWcP``IX P0%aD?z<#:sSsr)zCÍ9>YcZ Є~u*#@AzgaJ+KΤae$,MmUR&lFF6j*œQQM?-$9x?8=3 !UL@%t# 6h|&#X{~D7rI8|?'5l@j   ty@߹!#㨒wGsJl$ KX7&щ&udn$UD$&n*:BE p3&GDrXz%ʜιS ct'%YڨIxAN鏽_Ag ]tbe'QR(eiehjd5j0!O*=M,R,S*[bYEBP(L=r?@ ! !IJP n\ΉQ$ &b>Esk<"}>_>KIRguGF4jQI2)(4հIJ)*%)Jl-Nמ[nm25 Q%[ct<ι@D`VBLg1r $wml@VTA&H@֒#B%kaD(A!F`ĜW5^ץRDr+2FDR,RɌc2V1)Yi"!Yt[$  `)"f٪$$̥ݫr\۸NWKQ I 6~҃ [y2U6M:40%e1C$DƑIu7%WB)nuEDD&RpyE4D(@Ok, ;LUfX#:GZ1~1p`N1ml$[!CrBC%3ﹿC!sy,Hiz)"YD%#VeDq T5!HXT'q -;$EwqxqȻir͆X "mڑ#gm#!? g2^g 0V  6Bԩnƻ>8]℄"xDʏz*`܈0!X·&3'L}zKoģ ֕.PRLd+9+Wrv @{>N @NDv/Hi(׋%! 2[#Fn(Z7,dFȘTY - "&&ϳ0F4{‚ EH#}QBFB"Dt ~k׳ Du󾅡(ѿ2b׳7!tVY3ad]8"ڷ&|= Ż}ް@Z" .wB?B3h">Ck긢ba狢KnZG.=gUF%aTʤډDp<!u$n/:5UFDwGFOYX޽R(5\bRࡧd\C:, #ӿsCDANSD#΢\A=&I$!2c4xD4XQ+%"2/v,34Oy.ڙݴΗA B.dX>L=VJo緊4x}kƢ*BMZTdّ:~V;hOjRJ2hH8lT>z^gzdzj>_gwp~M!{?KC7YJ/hQty*pMiZ$˄CP>nb򡞍I3f.(윒bÉG,~.4a.@D2hBJAj! D!T{EQ) @ 1Z |Je]YӖ.X eviL *|I>o͊4\ꮦ " w$tOCPdܯzf"!%[@nPn/*z#QI N /߮֎87rߞ2Nr%.j7_Y&BcwsGG^詡v[%i>wJ29!sS*gyT6dȱNh(g9r8T;,%mdnΜ&briʪř%hm䔽l,(J bPRHa^n.y`{놥݁@0mƓzmMy]cʡԈ F^dJIL &!ZPNF{I _4bU"IBb ѮTF(;$0Ax>콸u'fdPpg[`ЪMI`QԷ~bGwգgCGϜ\l;䟗q;bԮԒA)y%9ă)+CܚS~|3vߋ6;'9ʲb%4/_4@ bJO W\}tѹw*fP*J!WeQ^ɤQYC("ID`c507P(DIbl?PiG/X,=^Gi/858T? ã *E""\4& oA]V]0u­YGt 4N-hagXıJa!|]-f ($ =GAP3e (A ?Z?sjִ.@s^W5]lq Tq!]QrCt{QJ7L EjJF*Qb tb>7t45FSz.>#hY$Gq̄ ؁x ˦B߄Pwo_{bb6S Ģ Pk({ #a@V li|(sjDъ,^$HHQ"->C{NQ")Ӡ](jT{ӵmΑIKY-r2BRh!i18頠s;f8`a#PbZjMDN0['tx,cE@,IOgj_y*Lz<:X!NLc)X²ˠHjl`slCQa h0-OY&U᧢crJ+τ] @Ĺ$DkPgp㼫1Eo9WIN}Md{r*xablU$pqNG@ZV0];m1*c ߍcT\Y _ӻ7HAg,UᩁƴM^D3Mb}bX. 5 16J) ғׇ/: nոu ; 4 UI\D|ؼYQٞe N% iu|,a,Im D!;vx4Qq*m^gk_ӅGJ&4G5 b]Z[K]{_6(G m gHR'v7a&'5c0GI9G!Ɩ|l=IG&݁1;3Y Rz03Af:CQ(b$ē$iirĚ&>H9#%Cki& ,al waMOo"mY]`tY4z6:gH+1!', -3Ljq@6r&KLbz!#.>~ۡi_-xva_C34뱮Ճbp: 6(K$a%"e[CP0}ԨU c (dvLhHOf11UuM0?K 5zz0={lLjlrW](قLJqQOX=? |v3eAsw#pSHl7wx/0J)A:8cRNJyvӵu8loWYS@EX!>@(Jh td?G(9;8=GLj <ß'QQEPėˉlDl⚀z 6] H]Lr-/$jRsrv͍ǽig;)3i'DwlR>B鎞7:,q,d1B뼓gn&`f2LD-d:-P  -k#]}HK? 0֠k!*2DDas n}~O\kwnv1 LvwuajmMXJA Gynuf `(O6rdW=COYg4LhcuwGiWAn|=Tu<ԐT`yN!& 18b^jB|%vL.ɤ97 n;9 aNyCD1|d~`_Æ8!s'=Iz^, Z%#yKt/.L,Zp% HE`wy3XRWF1yOo Ep6N7Pw >-zndT?|x]m{ЧZ]2B^}7WDlqG_QPZ$p>A7|w^5 f`C,KqzPr@ˇwwԈ^$./[GHLJ ZeӲHhO6v̯ӌ>yyo?䶲R5j IJ9ڗum4c"wuK4J0\b)qUM0X#Jəaf&t ,k<4s+aDN,`0R&74=&<`9^wog9[(4-5)Yinxt;'PH=:ڢ;]9i5B@ioGWftgGMsn8PڗS Ğ(ymn dP#PL^5NVgAUbvӶb&de`Q$Sa,LTх61aKJXj02Hndvx,O^~>1~9 vԥWf~~F.\Ed0t!t?rtxjT\)$]h ͰH='s~/D_ [VɁ ~N77胉iM*u=ee;nw@=eOAWؙA10Dr``L&| zWt;;ǹ)m *~1©d9"CKW>~z'~_}}j jT?!6h ?K?Ie"C:^ lU<*0 x;P2U>,U} 9&{ٛٷ;>6 hIm$&I3H@{/wK _t}\e"I鈛W" d+R/(IJOF|&'A35-ɳo5S \*a$m)SI ".EjQ^^ֵwoHE\r#m5snզSܭk}ֻ:ZJ%E)<] ˉ䴽y{wxPU"|ŬǔxFx]>1xQK'7;mun03Az%Q豮 8qi1Sgʻ=sSP.76LO3*LNq|~|^+Cp` $qΤ(Qp  Ёko脻 JUaU~2ɄcA!DmMFLڛaC]2ttJUqG8b\Os_ A>%}7X190VTDOd8ωUT>Q|nk_mL9~7ÊX:$O/%4BDP(&}Z7V)J tqe$Z<"4!DqPI eti p o6_Z #Q24]>paDR 8i }dJ^:f hYL&,ĺyl%7buJne]Q<8oۣZEu(+/&W8ATDYnjX dpG l !3Vrt^;"i)rޟ#$+;X[("thty^\78B/en얅%_|ZZ9c8II: ]YD41#u= CtTBlO~wwgtT(P*ȓ\ge6ujj1QזNͣ1\Ǫ#Y}_/\ t$"Oi:Gn:Q""f&fapޞYDq:0G,Vd4l+bSk'O=nxt.N/K5clgZ-訹eP bn* W,4j,}J^-Xx>ڴ88"sG6ͬR۱OZ1T-`Or1z6tXvh13pz "`+0*2xy] 2*CWw 8jco$8n6+E`2 +XXvΥ!VU wXT{5t!!WG}h6j;Q^*H]5,Z9.Leֳ҉<;S!&`1Niv{w3m0ud VLqJ":QPrmsArWJw{#[՞k*g ڊMdGjՔT]PaVM׍ƕsYKw.2ypw&5`xw'SQ%CO`F=: Τ*&fF PIjR,@ SYkUJ6jK!K,>ߣg'='ͺqǨ@󳼊qF*+$)@ND>x}|$c"ݰb4eF8(+Pʒ@2J (c]qy}L| y=^Na}zއc)PxFe * 0F2 JS;K{؆ҍdk' Xүd(dG㙈吣. PEFv^jm1SMUaH $U4Yk(d(B 4tHIJ(YR\MkSV!bD` 2qѠ`X" iv(- EdHAZS4FFAj!ٍ" dBd`$vsE)AHTTF1('m:{0&޽O}pNK^t-8fsSe#ug'ϭr1-(IvC<| 0D+( ISQ2AK%DlF"=N>觫w}K (a:x[-6$(22RBGJz<<{Sϣ1zqvJI2JY}u"kMhC"Zr sthF6E$ïK#_ǧhDYTUTZަt0Py'S"V@C5 P9w`ֵiwY˖+ 8pGm =]M5%Q\j餈\R&Hg& V@H|b'a3%GJKCX7!1SSݻh]%2U'@w;Q̬G ;lcPq`s]:][oÛsi^/N[M۠_S*TZ,L#Hc""1)!;II^`'!\d2Κ$aI!cB6KK6^'s[ѥ#uܕ:l5W]׊-yi.WM2rMmt+LdM-!vihD"d4!2 lQBWU Be%iD|bAWS@zc|_fgӯDꬔZa P{ H# u=['alB]JLf&XSkIUAQ1?~?Ͱ?t.L-nLꢆk, ȘuɉF>f~8rjBV ̸VGpstOtCCۋiWIbSAhАpؙ43 \ E MB;2 K5%CSխgoMUjrȢ)"]R(*('dR3CCz1줔Ӝgc~gCå\P;%O%̔aQ!:`%(1xb|Kp1/WV6%̠L|m:^QǴoDXC 2 l]F\$e!#›=F0dZ;2ْ*{}뤟fܔٟi~>^S>lL3I"i#E4P7{>cd0! YDx %-I)ZVufR"Nti4bK/=_^6kRm 2+ en!cmș&ˇ  N 2bwG8_9 WQ"Í4  R3Ұ lers\ḧ5 . .QQU<$N)P,gYjHRIPܛ:6mFoelvBv@D+2iuT(/Pb(Iyp01KJN'Zq' k@92"jBPJC0d ὼh4TZ1iP"{ \Fa3\!t,$5$4B!0f rsp%4TWӣ2 lPLj ]4  Ԃ0MJ hPt9J':㸃),x4A Lِ4J_؀:/HAl=nfL = n )i@@|p  H&ؕF$6]"A\JRȉJ* qs:1>r،v!~ЅD;D]/ȋ m9?r#t2(9lQ:wwa|7" wq,@0c*Ɲd/amYGc.<Ϝ(nMQ:|K?4!4Bn4d1@#&BNZXD""mH*HH@25Fb!$,e N:b'E攞xSݞ'wAC:WA;Dbe03462Rhل4)>]1J88NN:?; {le_#H,RAťe=p8|Sd0/3N< T(YZMNLz~q PPz,h7 M:SE̹jD=Rƒ,$ ]Y$J: <"L6UqӤDaqsmB`*oC؄2HHc(i< qy5]x`b*kl1)#YQuv. B1Rl#ZRf[TVF-M$ڊK21IڧBL6t=@5d',,$訠w"t4to&3Cʜ*B$+F{B%f)C"mvkݔ[)D5wuH36L)#!v)`RV(fVbA& *Yda#TmR!$AhҖhR&2*U)LA "@/(u﨓#&JS":_ΒjՄ%"aduIjZTd1V-`IլS6cz N0-N XXi<3DAK!hR  1Fm!T?w蒁9DB:ty94!4'dӽD&p@oW~n| \I ,JbFeKQdg+niP읞ކ`x_!'pb) ?ձ`To#TfVck뗴cz?!(p+ZL!dg'=N_ Ȉ 4Λ S!ץ>0?%SV߷Li )ͤTIb-J*PRNh(*ay7kt'twDyfܮʎ;J1y2bSC b jBXGQ-@A& HIRI1Lmt.lJZlaZ1AF- TI`kfAa$[.kkZ-d1)(N5(c9․XziQDSD!Ć[^G< 1*;D?ıw"O=|=6NGλ^ڊ~`tu u8xPWfk-~9 ?w.Z>げD Fu,K+35^v'Gt*xSH,u|h,^{ycMc''Hv(#H0RHzYgԢTUa(! F Jm{D@RRR-Չ&'tߌGA4 ߈"=DX3̀#ȩbREFj-ɪɌ) p$r8H+lZP6ZGQ㇧aOd_`s|J!yKc2RQOE y2:u[%na>dl{:#Bf sok97h>+@WE>EzCu>e$$aD&N͇D#MU{67{WNR҇sllW[J"Ϻ%WҁZKpoRR<9QBPx㹷_H٠{CLEj:5;T6yCDu8{#An˯z=@frUJK>584a_nLG.>za9MIF%R.n\ztq0kej{G)dj,`8!JҐEo~wyt IlHUUEUURݺ滔mmN; ][ d.؅v]cmͶm;[V[V󗜭[[mm---eŶխ7l"*""#^yp$w  @<󼐄 _<D$Yⶼb̽=3^+~%cS͠qĪaܸ! mݤt,́ʙ(@JS1[~G)/Ծ.(_ jNk!eCo/Pɘd,ʲψ|PK d QN~@0JР&0<b0[X v B#܏ݚ-\4}}:\?{x'2Bm/8a}㑲,Pb DfHEUT%&aTzӘ BƯPB|Җ*XS2D7n5>MjsTd9-w&q2bc}sts{YZ(e^-Ahd9M1IQna '$g/[F|o/M=;>tJW"HNu-A6k1cG3XZQS3OI 'c72 Q0#/`Qad)A?|6)>Qdz,Q'..de.{:DJ;w%6I15̾\kq!R ^D,G>vj9#H/.7 ?욕I-cnh=&Oj }aW|A[B%Ƈ2I V8if@.|O'"xZG^T1$uI]*^-e&0,sFfzݞ|2Qa83XEho2[ H}'r#"xy{#Fm6-13%d԰V%E(PJ)4ŕ$a1%m)jkfVŶ-YJj[)55-$*%!؞hrb*RJnMQ R7kx+x:AtC>OC@[jYilC)D5၊!GPqHEs 1wzh}W]I zQ<.Lm&ԛf@>oDPI)MOx~tm:#K$ ?`V%C$]p̈0$B&d+K*J4ldJDm~7t)MI-%K,Y]uɪR+jK,SISJRE)JKe%6K*}{u  $*lʙ*IeVYұEyK F+ L!L,K)I*1RGQKba`&N^wZ Ͷ_]F ƂLhi2JOzm-řl34DsBL$G-ֲ[eh[e[e-B!m%[BBmE)lmЩcm)J$-lHZ--mKl-[KVJҍ[ mml-mֲm-m-im lm imBZ@`KmZm(֒!mXZBKlհm lKh-m?J/9m?S'z؆[ k ThW_ZiYskG'#0XӈĥMѦS M%YN-m{M#5N)dUtCPD AB3 ".SL o.nhMDS3MY_?k͖'?I)2soקk x07QOy$wz>?&]+B(jhP?~=L9NrBdCN׽ 5|S*^%R@xYWġC_=P: h&$L͖!|8 9M)҅0V(J , `0P+bSjޅ8dWFeK"* +.VS|AR&eYMfAFm ͎m% "Fgװ}IftiDHixp:Ď\e۟q䂔")E(a%fYefI$!>q2ʝҚM&4hѦT#*0H0LǷC7a68T;-burR&e0I8_VyDjDS'OB/1x13C%[M((*/Nd*]q9,A^Lyʑ=&*%ILqv\q2\s+IR j1Iu&eCpѴ1 eku:-N;q:۪qͶyC]P[CP-FOV 鳊:lD+ C4^O=|ijčfbBEg+.D^V);gDwsmikr90社|>-b*N*ҙc{o7*ĵ>}E\ko1^c{"I$;;CR_IQZdtH;?0_Y4\4o:Y=o%2WgE~-oC&QJh ۊSD;%8dN_!Ǩ:sZF2ยH*۩oY}`AB% U Q.kJJRjvc{WC1đHi{?)JZC(=rnk6N7εMNNO9ιXrL:u6enu_T=oxLFJwwnd斯2ֳsPo %*"UorLdz}9zi$دftujjdGKZ=ZW'<5$腮Ziik=ey9kyuf|\&޲sRz箧TM'uQ5]utT!ӷ=}zI JHЇ*5IULj[I3M%WչNd=GkKxvN4gT&ݤRw{rlQI6;,Q-Q*7T^KSS8Ps)"OzYłIkKhK)zsD $}0 1br~n\í8h,;ZN.ZO] G8}/ 1AY&SY]-fTDqު`5]vviT@QOFLh ihɧTM&L#Ԙ4CF8&&&L&!440h $$"i2G68:9UR*y-j`3jjj-bL{njԵN~C&Br@9;uu8vdh)R"ep(!Cl5eNoljh7/ ~EG%ՁhY~w_đx$ H:vplWy(54{ J:vlMHw3ss.zp x.[!ncLꆀWQe4yeH>fM냽QUn\M K}d3KW > IhhLPcrب^!K4 x^u>Z,;e%E&(I!HIS{_x/j@+o愰44[ $SpwnC#]Wӄ:Wބ KB]q<Ԇ7"!66@.#ε3w|+z^Eʰ: d(sUde9 4*"la Y]M9SFBϦ_{ՎS(Rn-tdVwag¬,-SLVIjꎒ@f+$l -뾀uɛs,ێ=Zlڄ|80cƴ4HhzIzQf 98" 5lQΜ ?ܑN$:+Na