Controller/WikiTagController.php
author cavaliet
Fri, 02 Dec 2011 11:31:51 +0100
changeset 52 e804ae133f27
parent 50 e967654e90cb
child 53 22377c9e2eae
permissions -rwxr-xr-x
icon images in css, little debug, update document profile configuration

<?php
/*
* This file is part of the WikiTagBundle package.
*
* (c) IRI <http://www.iri.centrepompidou.fr/>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace IRI\Bundle\WikiTagBundle\Controller;

use Doctrine\ORM\Query\ResultSetMapping;
use Doctrine\DBAL\DriverManager;

use IRI\Bundle\WikiTagBundle\Entity\DocumentTag;
use IRI\Bundle\WikiTagBundle\Entity\Tag;
use IRI\Bundle\WikiTagBundle\Utils\WikiTagUtils;
use Pagerfanta\Pagerfanta;
use Pagerfanta\Adapter\ArrayAdapter;
use Pagerfanta\Adapter\DoctrineORMAdapter;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Response;


class WikiTagController extends Controller
{
    private static $SEARCH_STAR_CHARACTER = "*";
    
    /**
     * Fake index action
     */
    public function indexAction()
    {
        return new Response('<html><body>Nothing to see here.</body></html>');
    }

    /**
     * Renders the little html to add the css
     */
    public function addCssAction()
    {
        return $this->render('WikiTagBundle:WikiTag:css.html.twig');
    }

    /**
     * Renders the little html to add the javascript
     *
     * @param unknown_type $tags_list
     * @return \Symfony\Bundle\FrameworkBundle\Controller\Response
     */
    public function addJavascriptAction($tags_list=false)
    {
        $cats = $this->getDoctrine()->getRepository('WikiTagBundle:Category')->findOrderedCategories();
        // $cats is {"Label":"Créateur"},{"Label":"Datation"},...
        $nbCats = count($cats);
        $ar = array('' => '');
        for($i=0;$i<$nbCats;$i++) {
            $temp = array($cats[$i]["label"] => $cats[$i]["label"]);
            $ar = array_merge($ar, $temp);
        }
        // ... so we create is json like {"":""},{"Créateur":"Créateur"},{"Datation":"Datation"},...
        $categories = json_encode($ar);
        return $this->render('WikiTagBundle:WikiTag:javascript.html.twig', array('categories' => $categories, 'tags_list' => $tags_list));
    }

    /**
     * Renders the little html to add the javascript for context search
     */
    public function addJavascriptForContextSearchAction($context_name)
    {
        // WARNING : PREREQUISITE : the request to add a tag needs the external document id,
        // which is gotten by the jQuery call $('#wikitag_document_id').val() in the page.
        // So the page holding this context search MUST have a input value with this id.
        // We add the reactive selectors
        $reac_sel_array = $this->container->getParameter("wiki_tag.reactive_selectors");
        $reactive_selectors = null;
        if(array_key_exists($context_name, $reac_sel_array)){
            if($reac_sel_array[$context_name][0]=='document'){
                $reactive_selectors = 'document';
            }
            else{
                $reactive_selectors = '"'.join('","',$reac_sel_array[$context_name]).'"';
            }
        }
        return $this->render('WikiTagBundle:WikiTag:javascriptForContextSearch.html.twig', array('reactive_selectors' => $reactive_selectors));
    }

    /**
     * Display a list of ordered tag for a document
     * @param integer $id_doc
     */
    public function documentTagsAction($id_doc, $profile_name="")
    {
        // Management of profiles for the list of displayed columns and reorder tag button
        $profile_array = $this->container->getParameter("wiki_tag.document_list_profile");
        $columns_array = null;
        if($profile_array!=null && $profile_name!=null && $profile_name!=""){
            $columns_array = $profile_array[$profile_name];
        }
        
        $ordered_tags = $this->getDoctrine()->getRepository('WikiTagBundle:DocumentTag')->findOrderedTagsForDoc($id_doc);
        return $this->render('WikiTagBundle:WikiTag:documentTags.html.twig', array('ordered_tags' => $ordered_tags, 'doc_id' => $id_doc, 'profile_name' => $profile_name, 'columns' => $columns_array));
    }

    /**
     *
     * The action called when a tag is moved in a document tag list.
     *
     * @return \Symfony\Bundle\FrameworkBundle\Controller\Response
     */
    public function tagUpDownAction()
    {

        $req = $this->getRequest()->request;
        $id_doc = $req->get('wikitag_document_id');
        // post vars new_order and old_order indicate the position (from 1) of the tag in the list.
        // NB : it is different from the DocumentTag.order in the database.
        $new_order = intval($req->get('new_order')) - 1;
        $old_order = intval($req->get('old_order')) - 1;
        // First we get the DocumentTags
        $em = $this->getDoctrine()->getEntityManager();
        $ordered_tags = $this->getDoctrine()->getRepository('WikiTagBundle:DocumentTag')->findOrderedTagsForDoc($id_doc);
        // We change the moved DocumentTag's order
        $new_dt_order = $ordered_tags[$new_order]->getTagOrder();
        $moved_dt = $ordered_tags[$old_order];
        $moved_dt->setTagOrder($new_dt_order);
        // We move the TaggedSheets's order
        if($new_order > $old_order){
            // And we decrease the other ones
            for ($i=($old_order+1); $i <= ($new_order); $i++){
                $dt = $ordered_tags[$i];
                $dt->setTagOrder($dt->getTagOrder() - 1);
            }
        }
        else{
            // And we increase the other ones
            for ($i=$new_order; $i <= ($old_order-1); $i++){
                $dt = $ordered_tags[$i];
                $dt->setTagOrder($dt->getTagOrder() + 1);
            }
        }
        // Save datas.
        $em->flush();

        return $this->renderDocTags($id_doc, $req->get('wikitag_document_profile'));
    }

    /**
     * Action to remove a tag from a document tag list
     * @return \Symfony\Bundle\FrameworkBundle\Controller\Response
     */
    public function removeTagFromListAction()
    {
        $id_doc = $this->getRequest()->request->get('wikitag_document_id');
        $id_tag = $this->getRequest()->request->get('tag_id');
        // We get the DocumentTag meant to be deleted, and remove it.
        $em = $this->getDoctrine()->getEntityManager();
        
        $dt = $this->getDoctrine()->getRepository('WikiTagBundle:DocumentTag')->findOneByDocumentExternalId($id_doc, array('tag' => $id_tag));
        $em->remove($dt);
        $em->flush();

        return $this->renderDocTags($id_doc, $this->getRequest()->request->get('wikitag_document_profile'));
    }

    /**
     * Modify the tag in the context of a tag list for one document
     *
     */
    public function modifyDocumentTagAction()
    {
        $id_doc = $this->getRequest()->request->get('wikitag_document_id');
        $tag_label = $this->getRequest()->request->get('value');
        $id_moved_tag = $this->getRequest()->request->get('id');
        $moved_tag = $this->getDoctrine()->getRepository('WikiTagBundle:Tag')->findOneBy(array('id' => $id_moved_tag));
        if($tag_label!=$moved_tag->getLabel()){
            // We get the DocumentTags
            $em = $this->getDoctrine()->getEntityManager();
            
            $tags = $this->getDoctrine()->getRepository('WikiTagBundle:DocumentTag')->findByDocumentExternalId($id_doc);
            $found = false;
            foreach ($tags as $dt)
            {
                if($dt->getTag()->getLabel()===$tag_label)
                {
                    $found = true;
                    break;
                }
            }
            // If the label was found, we sent a bad request
            if($found==true){
                return new Response(json_encode(array('error' => 'duplicate_tag', 'message' => sprintf("Le tag %s existe déjà pour cette fiche.", $tag_label))),400);
            }
            // We create the new tag or get the already existing tag. $tag, $revision_id, $created
            try {
                $ar = $this->getDoctrine()->getRepository('WikiTagBundle:Tag')->getOrCreateTag($tag_label);
            }
            catch (\Exception $e){
                return new Response(json_encode(array('error' => 'wikipedia_request_failed', 'message' => $e->getMessage())),400);
            }
            $tag = $ar[0];
            $revision_id = $ar[1];
            $created = $ar[2];
            
            // We get the DocumentTag and change its tag
            
            $dt = $this->getDoctrine()->getRepository('WikiTagBundle:DocumentTag')->findOneByDocumentExternalId($id_doc, array('tag' => $id_moved_tag));
            $dt->setTag($tag);
            $dt->setWikipediaRevisionId($revision_id);
            
            $score_res = $this->container->get('wiki_tag.search')->search($tag_label, array("externalId"=>$id_doc));
            
            if(count($score_res)>0)
            {
                $score = floatval($score_res[0]['score']);
            }
            else
            {
                $score = 0.0;
            }
            $dt->setIndexNote($score);
            
            // We set ManualOrder = true for the current document
            $doc = $this->getDoctrine()->getRepository('WikiTagBundle:Document')->findOneBy(array('externalId' => $id_doc));
            $doc->setManualOrder(true);
            // We save the datas
            $em->flush();
        }
        // We render the document's tags
        return $this->renderDocTags($id_doc, $this->getRequest()->request->get('wikitag_document_profile'));

    }

    /**
     * The action called to reorder the the tags of a document. The tags are reordered according to the indexation score of the tag label on the document.
     * The fields taken into account for calculating the score are defined in the wikitag configuration.
     */
    public function reorderTagDocumentAction()
    {
        $id_doc = $this->getRequest()->request->get('wikitag_document_id');
        $res = $this->getDoctrine()->getRepository('WikiTagBundle:Document');
        
        $doc = $res->findOneByExternalId($id_doc);
        $doc->setManualOrder(false);
        $this->getDoctrine()->getEntityManager()->persist($doc);
        
        $search_service = $this->get('wiki_tag.search');
        
        $search_service->reorderTagsForDocument($doc);
        
        $this->getDoctrine()->getEntityManager()->flush();

        return $this->renderDocTags($id_doc, $this->getRequest()->request->get('wikitag_document_profile'));
    }

    /**
     * The action called to add a new tag (especially from the completion box)
     */
    public function addTagAction()
    {
        $id_doc = $this->getRequest()->request->get('wikitag_document_id');
        $tag_label = $this->getRequest()->request->get('value');
        // We get the DocumentTags
        $em = $this->getDoctrine()->getEntityManager();
        $tags = $this->getDoctrine()->getRepository('WikiTagBundle:DocumentTag')->findByDocumentExternalId($id_doc);
        $nb_tags = count($tags);
        $found = false;
        $i = 0;
        while($i<$nb_tags && $found==false){
            $dt = $tags[$i];
            if(strtolower($dt->getTag()->getLabel())==strtolower($tag_label)){
                $found = true;
            }
            $i++;
        }
        // If the label was found, we sent a bad request
        if($found==true){
            //TODO : translation
            return new Response(json_encode(array('error' => 'duplicate_tag', 'message' => sprintf("Le tag %s existe déjà pour cette fiche.", $tag_label))),400);
        }
        // returns array($tag, $revision_id, $created)
        try {
            $ar = $this->getDoctrine()->getRepository('WikiTagBundle:Tag')->getOrCreateTag($tag_label);
        }
        catch (\Exception $e){
            return new Response(json_encode(array('error' => 'wikipedia_request_failed', 'message' => $e->getMessage())),400);
        }
        
        $tag = $ar[0];
        $revision_id = $ar[1];
        $created = $ar[2];
        
        $tags = $this->getDoctrine()->getRepository('WikiTagBundle:DocumentTag')->findByDocumentExternalId($id_doc, array('tag'=>$tag->getId()));
        $nb_tags = count($tags);

        if($created==true || $nb_tags==0){
            $new_order_ar = $this->getDoctrine()->getRepository('WikiTagBundle:DocumentTag')->getMaxOrder($id_doc);
            // The result is a double array. And reset(reset($newOrderAr)) is not allowed. And a string is returned.
            $a1 = reset($new_order_ar);
            $new_order = intval(reset($a1)) + 1;
            $new_DT = new DocumentTag();
            $new_DT->setDocument($this->getDoctrine()->getRepository('WikiTagBundle:Document')->findOneByExternalId($id_doc));
            $new_DT->setTag($tag);
            $new_DT->setOriginalOrder($new_order);
            $new_DT->setTagOrder($new_order);
            $new_DT->setWikipediaRevisionId($revision_id);
            $em->persist($new_DT);
            $em->flush();
        }

        return $this->renderDocTags($id_doc, $this->getRequest()->request->get('wikitag_document_profile'));
    }


    /**
     * Action to remove the wikipedia link form a tag. This action create a copy of the original tag with all the link to wikipedia set to null.
     *
     * @return \Symfony\Bundle\FrameworkBundle\Controller\Response
     */
    public function removeWpLinkAction()
    {
        $id_doc = $this->getRequest()->request->get('wikitag_document_id');
        $id_tag = $this->getRequest()->request->get('tag_id');
        $tag = $this->getDoctrine()->getRepository('WikiTagBundle:Tag')->find($id_tag);
        //return new Response(var_dump(array($tag)));
        // We search if the unsemantized version of the tag already exist.
        $un_tag = $this->getDoctrine()->getRepository('WikiTagBundle:Tag')->findOneBy(array('label'=>$tag->getLabel(), 'urlStatus'=>Tag::$TAG_URL_STATUS_DICT['null_result']));
        $em = $this->getDoctrine()->getEntityManager();
        $un_tag_created = FALSE;
        if(!$un_tag){
            // Create another tag almost identical, without the W info
            $un_tag = new Tag();
            $un_tag->setLabel($tag->getLabel());
            $un_tag->setOriginalLabel($tag->getOriginalLabel());
            $un_tag->setUrlStatus(Tag::$TAG_URL_STATUS_DICT['null_result']);
            $un_tag->setWikipediaUrl(null);
            $un_tag->setWikipediaPageId(null);
            $un_tag->setAlternativeWikipediaUrl(null);
            $un_tag->setAlternativeWikipediaPageId(null);
            $un_tag->setAlternativeLabel(null);
            $un_tag->setDbpediaUri(null);
            $un_tag->setCategory($tag->getCategory());
            $un_tag->setAlias($tag->getAlias());
            $un_tag->setPopularity($tag->getPopularity());
            $em->persist($un_tag);
            $un_tag_created = true;
        }
        
        if($id_doc && $id_doc!=""){
            // We associate the unsemantized tag to the DocumentTag and save datas
            $dt = $this->getDoctrine()->getRepository('WikiTagBundle:DocumentTag')->findOneByDocumentExternalId($id_doc, array('tag' => $id_tag));
            $dt->setTag($un_tag);
            $em->flush();
            return $this->renderDocTags($id_doc, $this->getRequest()->request->get('wikitag_document_profile'));
        }
        else{
            // Here we are in the context of tag list.
            if($un_tag_created==TRUE){
                $em->flush();
                $num_page = $this->getRequest()->request->get('num_page');
                $nb_by_page = $this->getRequest()->request->get('nb_by_page');
                $sort = $this->getRequest()->request->get('sort');
                $searched = $this->getRequest()->request->get('searched');
                return $this->renderAllTags($num_page, $nb_by_page, $sort, $searched);
            }
            else{
                // The unsemantized version of the tag already exist, so we send an error.
                return new Response(json_encode(array('error' => 'duplicate_tag', 'message' => sprintf("La version désémantisée du tag %s (%s) existe déjà.", $un_tag->getLabel(), $un_tag->getOriginalLabel()))),400);
            }
        }
    }


    /**
     * Action to update a tag category.
     * @return \Symfony\Bundle\FrameworkBundle\Controller\Response
     */
    public function updateTagCategoryAction()
    {
        $id_doc = $this->getRequest()->request->get('wikitag_document_id');
        $id_tag = $this->getRequest()->request->get('id');
        $cat_label = $this->getRequest()->request->get('value');
        // We get the Tag and update its category.
        $em = $this->getDoctrine()->getEntityManager();
        $tag = $this->getDoctrine()->getRepository('WikiTagBundle:Tag')->find($id_tag);
        if($cat_label==''){
            $cat = null;
            $tag->nullCategory();
        }
        else{
            $cat = $this->getDoctrine()->getRepository('WikiTagBundle:Category')->findOneBy(array('label' => $cat_label));
            $tag->setCategory($cat);
        }
        $em->flush();

        if($id_doc && $id_doc!=""){
            return $this->renderDocTags($id_doc, $this->getRequest()->request->get('wikitag_document_profile'));
        }
        else{
            $num_page = $this->getRequest()->request->get('num_page');
            $nb_by_page = $this->getRequest()->request->get('nb_by_page');
            $sort = $this->getRequest()->request->get('sort');
            $searched = $this->getRequest()->request->get('searched');
            return $this->renderAllTags($num_page, $nb_by_page, $sort, $searched);
        }
    }


    /**
     *
     * Generic render partial template
     * @param unknown_type $id_doc
     */
    public function renderDocTags($id_doc, $profile_name)
    {
        // Management of profiles for the list of displayed columns and reorder tag button
        $profile_array = $this->container->getParameter("wiki_tag.document_list_profile");
        $columns_array = null;
        if($profile_array!=null && $profile_name!=null && $profile_name!=""){
            $columns_array = $profile_array[$profile_name];
        }
        // Get tags and render the table
        $ordered_tags = $this->getDoctrine()->getRepository('WikiTagBundle:DocumentTag')->findOrderedTagsForDoc($id_doc);
        return $this->render('WikiTagBundle:WikiTag:tagTable.html.twig', array('ordered_tags' => $ordered_tags, 'doc_id' => $id_doc, 'columns' => $columns_array));
    }


    /**
     * Action to update the tag alias.
	 *
     * @return \Symfony\Bundle\FrameworkBundle\Controller\Response
     */
    public function updateTagAliasAction()
    {
        $id_tag = $this->getRequest()->request->get('id');
        $alias = $this->getRequest()->request->get('value');
        // We get the Tag and update its category.
        $em = $this->getDoctrine()->getEntityManager();
        $tag = $this->getDoctrine()->getRepository('WikiTagBundle:Tag')->find($id_tag);
        $tag->setAlias($alias);
        $em->flush();
        
        $id_doc = $this->getRequest()->request->get('wikitag_document_id');
        if($id_doc && $id_doc!=""){
            // In case we changed the alias from the document view
            return $this->renderDocTags($id_doc, $this->getRequest()->request->get('wikitag_document_profile'));
        }
        else{
            // In case we changed the alias from the tag list.
            $num_page = $this->getRequest()->request->get('num_page');
            $nb_by_page = $this->getRequest()->request->get('nb_by_page');
            $sort = $this->getRequest()->request->get('sort');
            $searched = $this->getRequest()->request->get('searched');
            return $this->renderAllTags($num_page, $nb_by_page, $sort, $searched);
        }
    }
    
    /**
     * List all tags, with pagination and search.
     *
     * @return \Symfony\Bundle\FrameworkBundle\Controller\Response
     */
    public function allTagsAction()
    {
        // $this->getRequest()->query->get('foo') does not work "because" we are a second controller. So we have to use $_GET.
        // Searched string
        $searched = NULL;
        if(array_key_exists('searched', $_GET)){
            $searched = $_GET['searched'];
        }
        // Number of tags per page
        $nb_by_page = 50;
        if(array_key_exists('nb_by_page', $_GET)){
            $nb_by_page = intval($_GET['nb_by_page']);
        }
        // Current page number
        $num_page = 1;
        if(array_key_exists('num_page', $_GET)){
            $num_page = intval($_GET['num_page']);
        }
        // Sorting criteria
        $sort = NULL;
        if(array_key_exists('sort', $_GET)){
            $sort = $_GET['sort'];
        }
        
        // We get the needed datas in an array($tags, $num_page, $nb_by_page, $searched, $sort, $reverse_sort, $pagerfanta);
        $ar = $this->getAllTags($num_page, $nb_by_page, $sort, $searched);
        //return new Response($ar);
        $tags = $ar[0];
        $num_page = $ar[1];
        $nb_by_page = $ar[2];
        $searched = $ar[3];
        $sort = $ar[4];
        $reverse_sort = $ar[5];
        $pagerfanta = $ar[6];
        
        // We get the needed vars : number totals of tags, previous and next page number
        $last_page = $pagerfanta->getNbPages();
        $nb_total = $pagerfanta->getNbResults();
        $prev_page = 1;
        if($pagerfanta->hasPreviousPage()){
            $prev_page = $pagerfanta->getPreviousPage();
        }
        $next_page = $last_page;
        if($pagerfanta->hasNextPage()){
            $next_page = $pagerfanta->getNextPage();
        }
        // We calculate start_index and end_index (number of tags in the whole list)
        $start_index = 1 + (($num_page - 1) * $nb_by_page);
        $end_index = min($nb_total, $start_index + $nb_by_page - 1);
        
        // We build the list of tags's first letters to make quick search.
        $conn = $this->getDoctrine()->getEntityManager()->getConnection();
        $sql = "SELECT UPPER(SUBSTRING(normalized_label,1,1)) as fl FROM wikitag_tag GROUP BY fl ORDER BY fl";
        $letters = $conn->query($sql)->fetchAll();
        $search_def = array();
        foreach ($letters as $l){
            $search_def[$l[0]] = $l[0].WikiTagController::$SEARCH_STAR_CHARACTER;
        }
        
        return $this->render('WikiTagBundle:WikiTag:TagList.html.twig',
            array('tags' => $tags, 'searched' => $searched, 'search_def' => $search_def, 'nb_by_page' => $nb_by_page, 'sort' => $sort,
            'start_index' => $start_index, 'end_index' => $end_index, 'nb_total' => $nb_total, 'num_page' => $num_page, 'last_page' => $last_page,
        	'prev_page' => $prev_page, 'next_page' => $next_page, 'reverse_sort' => $reverse_sort, 'route_for_documents_by_tag' => $this->container->getParameter("wiki_tag.route_for_documents_by_tag")));
    }

    /**
     * Modify the tag in the context of all tags list.
     */
    public function modifyTagAction()
    {
        $tag_label = $this->getRequest()->request->get('value');
        $id_moved_tag = $this->getRequest()->request->get('id');
        $moved_tag = $this->getDoctrine()->getRepository('WikiTagBundle:Tag')->findOneBy(array('id' => $id_moved_tag));
        // We update the tag label and its wikipedia info with the new label.
        try {
            $this->updateTagWithNewLabel($moved_tag, $tag_label);
        }
        catch (\Exception $e){
            return new Response(json_encode(array('error' => 'wikipedia_request_failed', 'message' => $e->getMessage())),400);
        }
        // We render the tag list.
        $num_page = $this->getRequest()->request->get('num_page');
        $nb_by_page = $this->getRequest()->request->get('nb_by_page');
        $sort = $this->getRequest()->request->get('sort');
        $searched = $this->getRequest()->request->get('searched');
        return $this->renderAllTags($num_page, $nb_by_page, $sort, $searched);
    }
    
    /**
     *
     * Resemantize the tag with its original label. Kind of undo if we changed the tag's label.
     *
     */
    public function resetWpInfoAction()
    {
        $id_moved_tag = $this->getRequest()->request->get('tag_id');
        $moved_tag = $this->getDoctrine()->getRepository('WikiTagBundle:Tag')->findOneBy(array('id' => $id_moved_tag));
        // We update the tag label and its wikipedia info with the original label.
        try {
            $this->updateTagWithNewLabel($moved_tag, $moved_tag->getOriginalLabel());
        }
        catch (\Exception $e){
            return new Response(json_encode(array('error' => 'wikipedia_request_failed', 'message' => $e->getMessage())),400);
        }
        
        // We render the tag list.
        $num_page = $this->getRequest()->request->get('num_page');
        $nb_by_page = $this->getRequest()->request->get('nb_by_page');
        $sort = $this->getRequest()->request->get('sort');
        $searched = $this->getRequest()->request->get('searched');
        return $this->renderAllTags($num_page, $nb_by_page, $sort, $searched);
    }


    /**
     * Generic render partial template for tag list
     */
    private function updateTagWithNewLabel($tag, $label)
    {
        if($tag!=null && $label!=null){
            if($label!=$tag->getLabel()){
                // We get the Wikipedia informations for the sent label
                $tag_label_normalized = WikiTagUtils::normalizeTag($label);
                try {
                    $wp_response = WikiTagUtils::getWikipediaInfo($tag_label_normalized);
                }
                catch (\Exception $e){
                    throw new \Exception($e->getMessage());
                }
                $tag->setWikipediaInfo($wp_response);
                // Save datas.
                $em = $this->getDoctrine()->getEntityManager();
                $em->persist($tag);
                $em->flush();
            }
        }
    }


    /**
     * Generic render partial template for tag list
     */
    public function renderAllTags($num_page=NULL, $nb_by_page=NULL, $sort=NULL, $searched=NULL)
    {
        
        //We get the needed datas in an array($tags, $num_page, $nb_by_page, $searched, $sort, $reverse_sort, $pagerfanta);
        $ar = $this->getAllTags($num_page, $nb_by_page, $sort, $searched);
        $tags = $ar[0];
        $num_page = $ar[1];
        $nb_by_page = $ar[2];
        $searched = $ar[3];
        $sort = $ar[4];
        $reverse_sort = $ar[5];
        
        return $this->render('WikiTagBundle:WikiTag:TagListTable.html.twig',
            array('tags' => $tags, 'searched' => $searched, 'nb_by_page' => $nb_by_page, 'sort' => $sort, 'num_page' => $num_page,
        	'reverse_sort' => $reverse_sort, 'route_for_documents_by_tag' => $this->container->getParameter("wiki_tag.route_for_documents_by_tag")));
        
        return $this->getAllTags();
    }


    /**
     * Generic to get all tags with the context (pagination number, nb by page, searched string, sort)
     */
    private function getAllTags($num_page=NULL, $nb_by_page=NULL, $sort=NULL, $searched=NULL)
    {
        // We get/set all the parameters for the search and pagination.
        // Searched string
        if($searched==NULL){
            $searched = "";
        }
        // Number of tags per page
        if($nb_by_page==NULL){
            $nb_by_page = 50;
        }
        // Current page number
        if($num_page==NULL){
            $num_page = 1;
        }
        
        // We build the query.
        $qb = $this->getDoctrine()->getEntityManager()->createQueryBuilder();
        $qb->select('t', 'COUNT( dt.id ) AS nb_docs');
        $qb->from('WikiTagBundle:Tag','t');
        $qb->leftJoin('t.documents', 'dt', 'WITH', 't = dt.tag');
        $qb->addGroupBy('t.id');
        
        // We add the search string if necessary
        if($searched!=""){
            // We replace "*" by "%", and doctrine wants ' to be ''.
            $qb->where($qb->expr()->orx($qb->expr()->like('t.normalizedLabel', "'".str_replace("'", "''", str_replace("*", "%", str_replace("+", " ", $searched)))."'")));
        }
        //return $qb->getDql();
        
        // We add the sorting criteria
        if($sort==NULL){
            $sort = "popd"; // sort by descendent popularity by default.
            $reverse_sort = "popa";
        }
        //$sort_query = "nb_docs DESC t.popularity DESC t.normalizedLabel ASC t.label ASC";
        switch($sort){
            case "popd":
                $qb->addOrderBy('t.popularity','DESC');
                $qb->addOrderBy('nb_docs','DESC');
                $qb->addOrderBy('t.normalizedLabel','ASC');
                $qb->addOrderBy('t.label','ASC');
                $reverse_sort = "popa";
                break;
            case "popa":
                $qb->addOrderBy('t.popularity','ASC');
                $qb->addOrderBy('nb_docs','DESC');
                $qb->addOrderBy('t.normalizedLabel','ASC');
                $qb->addOrderBy('t.label','ASC');
                $reverse_sort = "popd";
                break;
            case "labd":
                $qb->addOrderBy('t.normalizedLabel','DESC');
                $qb->addOrderBy('t.label','DESC');
                $reverse_sort = "laba";
                break;
            case "laba":
                $qb->addOrderBy('t.normalizedLabel','ASC');
                $qb->addOrderBy('t.label','ASC');
                $reverse_sort = "labd";
                break;
            case "nbd":
                $qb->addOrderBy('nb_docs','DESC');
                $qb->addOrderBy('t.popularity','DESC');
                $qb->addOrderBy('t.normalizedLabel','ASC');
                $qb->addOrderBy('t.label','ASC');
                $reverse_sort = "nba";
                break;
            case "nba":
                $qb->addOrderBy('nb_docs','ASC');
                $qb->addOrderBy('t.popularity','DESC');
                $qb->addOrderBy('t.normalizedLabel','ASC');
                $qb->addOrderBy('t.label','ASC');
                $reverse_sort = "nbd";
                break;
        }
        
        // We paginate
        $adapter = new DoctrineORMAdapter($qb);
        $pagerfanta = new Pagerfanta($adapter);
        $pagerfanta->setMaxPerPage($nb_by_page); // 10 by default
        $pagerfanta->setCurrentPage($num_page); // 1 by default
        $nb_total = $pagerfanta->getNbResults();
        $tags = $pagerfanta->getCurrentPageResults();
        $pagerfanta->haveToPaginate(); // whether the number of results if higher than the max per page
        
        return array($tags, $num_page, $nb_by_page, $searched, $sort, $reverse_sort, $pagerfanta);
    }


}
x0p.C}ݮ}fYShh"ϼwcnE\﷏}DecJCu3MtL95{FmZ]Vvs8wZo|U*Fi둁ơHrH xJc6^o?-WE6%v⵫hYf >='8JTn]ҏǥ s.e^y 8\'!RFJnpJX(2F]ޥu. =_Cr?5̹0m1x,++m-|VՃ}/j77yl:gK}adP4 CfUShcTjWD0Z<_NI F{#rGrP^!< 7_նC(=iKd]\ -kІݸX[[#vz ef* {ѸYvz]seK2Z&<;]:C4&ynP$iFx^ݛ?hS(z>]Lz9y)ֺ1ċ{$ZϤVlb=Lx:6mwCyXma`Q89,V&)dgk |:zUd:hk﷎ᆩmr97:E+UZ3Ժ;NzNnimR!U.7燱ʹܩw|i䣌n#6/2X\:L>piO< ;US~5i.'9~9FtmU;ZoFs}cr cdM9'ϳ/n+C3"є|\d,3eh/,9>h+lV7n3L[ٸ[ tZ ?:kyW{bK__~s|V bk}A~'571u`cOd^s(Zݣ=vQ|j'ޠQxCb ~t g6)_er4 ypEɿwH͵ԍ7A3{<8fg4rusZ,^':3ktc2>4]ütIFcڦKb]C"9$|mU{A%sTtY=PY ա˳z3zz:l>zeftTunfu>/E(`?NdUmo-d8q~r/B 2OLi>4*3JvQl՘d`7sDž[n075ݍJHB8AY3x%sSmsʛMe5K۽ݛMAwdm{T-z~Ѭ7/:8 B#*_4<[h؝f0q[VVD=-Ku"2˥iߕ#儷3rMl]۽w;Rؚht?odTFKHp;<,mmi݃Ϋ$xݿ'wh/ئEh=~'i?{a0g}1.tgZlB|bˊ9,JYߖ[Wxΐƽ5إC{F##4fY?=:ev@[5.WmuLݍt0{]*}70Bg (1P<\-uDd󩵗/!S {A_iQt)5xr>:NVO֚l%8 'AZo {+Xu&}xw~[?yM~I,uA}k}awfT1k5-͢Vbs1|GEàκpqS?/ n_sC]YltdWݲ=e;l- 0SՏ#гYWnO?~}gVUY̌F*əGݥU]هNb܀n_#s4FmD'eE-gl yy?fi*9ˍ*dnեj{o1i3韻cp{3ěΚ9΋t%|:qꕴ[@R A$ Si=^ z|'J_B=Q=a8۝K!E#{)ms2~j5sޑf+[vp땷0Kk8iو57T1Ĕ*?*@D^Źc: :G\TJ?\'"yhÚs* 'qhѪ4~4/I 뜿Gq%_GQO~VBmeϲs1Zޡ`8 ޢ̜pqapW4:\75c۬e룮ofkzpҾ9I5/LmV[Chڹ`D\\_z8s%ۘu]LţEnqZ["ۦg4󬱮G/z2\sZn]9/=FіoxNG nLWq~H)}00-ol蹍¦ %ev܇zncI33S%к@pU|2{O._:e-jr gKޟKp{Ҳ?kCkMo %;>ї ;M.+$/*ycdC1]`07K/b|/trMABj_yMr6'OfouY^v΅֏Stn='Vc^QHM<[A=yB~8pe|(A\iY\gD߹ΩO^7Ind9N~'۟uަCbiPXxÚg̲'|K@~ ~m^(ꭱ-wpbhR^+FF՞rse$&UanQ$÷AQ^{p;͙;ʟ;e|]m`|dU;+얈m"ډ  XKh#1|sȰ]f œ_ 6goįst`Gzن_נ;t'C~-ξ_FU.!"0y|kҨO5p%JvkTgW-ew&Fj|rKmAikǾ7+IiƸa I>CˈlIRv5^5$Gt›nO)8v?0 ''0M>muVQ6p۵1eykCl]npF۽|v48|7^kkFu;6w`C}wB5ZjnvKm“>ޛϞ&\eT{e5Ӯm; u CjzﳟR|ڹ]γy{{뽻v]@vڦ56q Jwy"Q&Z靥Da>]}.jIu}Y vl LSʽ9b:uǭ3={}=޸ P:gws1l9Wtl>̕霥ff%Tmٞx{__m` <SX8ٸKm7N`vצ;bvHH:Fa}T z$oOl̋>-g]/MJl&c*w;'yC޻'OzOk7u.nֆٛt-7&A^u@mv[Jm鷻mE{:ܶjART kY lZ>{Y8l{5Zn8įoy{^AҎ+2x@T4Yo%W`Тǹϱ['ճTCc{[V7^}7 ֫;}KΟxI@@FMM =#hB7ji13HF  A412e=&J~S5z!44hhd)4#T6jGiFPi3P@4dЀҧL'h̦z MM24@" M4SSѓ&*~OFTJɕ'j$ 0 j`ɍ lMF=GOȚjOP0[JGǟo~=>ϒgCx/vL_.k@1ۧ:/>w[# iO * $B*G(""QQDS}Ux@ xMW\QN%ʽWWw!WYkLxl:s^Gp54@N$ !"pd2-US dE8 @1ABs_@*Hj+UVjN1wzimbTEl^ojubxǘ j 6]%ga.*"!qAhZj);OlcI펄wó }pM ␃tX@s f@HxnULD Лcn-!}O O1>MHD#ďMY(ωX[SQEQdPAg_o⍳զ ޔ0h7~n+3vyPΝ~#5g$=оN]w^f<^IY_t5=t{ꡥb_:a0ʧy隠 Hl WSẙvE[lmw`pm1D^Q{P,H=vx匙m3^bCޒ }_mR mq U)^)OC9k'(q?fN}WRZM2{uXr8/hҞgG>Z𷶙<ʜW4_D [U[-6 ʁP:*o&:_h [gL!z#.94H>xI|*pl ]#X5QADnvT/7>z(ǮwpSArV51 \dK06h6J2on<{2Pב_-ͯ9nCD>EYH#[y><1 y99;#=u y"TLHKH7X1嶰`ٙhP^l4 \Xg^9Nsk͟]3wyDL'qՂ'NjkD%)'N8˪nShMI\FlEchbaQ[c֞Hb;H ˈ@' KJ0j瞉gv2*DPDA;HeexE7iH؇Edy +]t]H5VACĕZY3_]5Fr|%E0%̊~qYmHVao|zK'F4SicĶ[KN1Q~KTW(r6"\W6(Zb$MU0c_jTR&S$bI?57'ğ"f(_B3_7)){4(6.^fUڪFlln5G#Qj(Hn;Ӫ/-^VObmfcFe^|۷Drpt s}" Jc`5-0(رga.m.+ Oei=ٲQ{:4׍n  ,'@e4|؜ahMf7q & Uw'4i rRfaW{PzSGo|]S*F`CD8* kaZtj^m e)qCl!d2rpsew\mn,J33fEǾ:7h]I;C-&gFJYIlEfgVY9نsH'^|e'Hd^>5kRvO<B.EE'ty~yvM\@ 1 gt1}υIAP}:uOdޥiRIK3 R* qk: *6f{ )!GvRuMuV6 q-DPrB+a TD>xȅԡy&XbleW84)!!$x irGPU"Y5}9aS q8*$c4 0<4jZ:+,a#4LfaU\JS@bn=WMlcYTt+A.ZNģģVmN;љzK a X(a̢ tD^1>|9ނ?^?sqE4/uAJ i%XPޡp@PZia`{iX֊0:ZCH0N} c--|D >2ѓl1 WBTDB>}G a ]2< 0y\iw4О;0"फP''8IIb((Q%6A9֠24álq1!'XuKaL>~~]ax߃pkzPXˁra""@Ҋ<3}!,TGڄ$>ل9D`({qv 2s7ե<%m>Z|SKyT_)#C tpDX[]100!FX:l(J`~2:LCY@:`㶃o x3M3Pe0['>\ 00٤xMfȜ ̪$1',_N-'|0|q=r(+>8`G ]JirЫ$a! Iz|~C2 `h2 ^z6&eMhɳ8]1miJ!0I%޵Lz.S!;}22z%o }R_"\P&G:50܊5a1HI$/=*Q.BCF8Vځ<%L\HXLLv }h2ɀ6NS q; 8^0pLb0,H~%aƒ4$$TO>rXHraQH۳~=ϋs}G2N$m?3͡#̤%viA@ (V~T ah]'QwKqבl P"Cu)qF@4sj&=\#UfsD|]{jvQ#'*,y(EmC2:2ty鮭zܡD p_JvڶP#TI!ys),bcHcz'|ʪD,PHB袈/[h|Zo^lA_ zM{̕{ )K()J()!\HBD}'hj Ny6bIE X0DCR4 A2 - 41JPDADLi\A70OKrA~~.5H0a:tTA^24{9䠭Ѝ=$H *#*}719S†)=dxG=j˙˳pdOppZH4F6PBPRRb@b %Ba@Rf&T ?ZT whN[b J#'(V1'%[mypVn֝_\<:x]yeqGv4|7:]>C>J'#O?yi@? nύuJ"-e"/Ob@h+H BH$!$f(`"*D:` ;Hd QO^LJ?Ls=c'SZ^LL(z/>CSH"С(LH(|*;r;(]H4@%BT 9* Q$Lo0ijCOD+hHlF $UUR~,UTB%2P*2Q@6_cwjP- 䂈+$Q C%QL'q2>ādaqG>q(LۘiiZ(h"B/6IJ}e5d (hkZaXMtmhOCp3B1QxL%H}t rb3_CQF rqU(QVDr 58K 3$̬J1k5bfS.AӍb.Ex0QV LDiWD` JdB+N@Ų](R+=W`LHJ B. B  2~J"ۂ31:T@,Ai!݂D+^o?SN:q<@NϢLpE1bx9NLU8H`Gvp}lG0qo׹B(\DzwƵ9gti(Cؑ4p,&=^GUl.qسOiV<fZQZk=oh{WyM)I( }$߳8yd&bZ  |}oc{[ewQOXi)":аI=%)e4b\σGtEHDDv/хr&~!8JjT{̒B h&&Kxa.9=ju93bt:B U lmwy66եen#DD 6ɉl .V#~W)6$G]-36/4bڳD nun̷[I-#Ui1@~Tr[gu-+LzØ.`HMC~;6R*ad]<&!KwU˃mQ퓮hiy8]e:i):U ҆+!hџVf Ϛ%sp?9R H9KщrRwrbb4s)~X̾.Q@MWK 0uiwơY8Y饷()c6TR\ZDAU_xE ffD&vO| |dJٳiS?{ǩraۍLDDXs .*' WS(evB<aФ~.1פ2[pqbs0k.z7[Hةֹ\h(`G&~ˈ L)HF) $kdnIVe+k/6~gc+%U\\;zLS]E9lIiq0x^RCE*}&""' rq4&fDHqGKg 53VPBA^$V7pzLk}y7HV*SMF,r;u9ɟ>8{ 5NReVψa[G54F@a3I,%VUr Ņ]Mΰ-yp/#`!{F%{8ױUn_VPƭ&baY;: Owq BG>a8]e1xozN>у8I73 Mg*^e,+qYY@FZ f&u`)9hȄF߮)dYsc΀$o\PЭY6fh)Ԋe,/R55٥ӭ2 /6RV9887t.x!ؚHI Abfg  rӫs>Y`$>> rW׊A}36 2}Lޅ]ebGw[x5 k~?$`9Pj,E^Df j\s\1BoW^B!x}9 IĘL/)}Ǽsн/{hlڒ~γymIKcP}̙8 ˁ5jr /,"̾~ʩ7) r9% jĎж5|γO `{a5% 6%9H0doR_7w'Ɓj@D*zʈ>w k,#AxRTDFb]i E(N^j[w5!+;?/a^1O|2d{+9>7fcRFD]F`_Ry>Qhſ&0 d K4+E Q+#j )eB+BS\3~=P'>8("ڰd sK ji1=Y4#T1B#>A(?=A@I:*?\}siэAgGk6cbM㖊x' ?/~/MIh> J 4 b;TK=s 5Mg 5^)hi<o篝6"׋G@\Zgb-S\&[RW[ؘX!uW ǝ$O@cxG*VԌrV:U8CZ ~iSv5 gRB Mc. >hW^'lI=6**=t:9CNL^վRGRӤD珫/gYj$Z-.-E0*"8PA,+OvN{[y<:L[}fj/3mbYfpWd_{`%L6o _+%8ϟ >W Caіj=zhuc%^eR,H+v|9ޚUQ\͂wksQx|-K.*DwŌs1ahGC(dːo{;SeF%8j."q5"2^7jZUvK2vxY;s"Jox1lM-_|3k}zcE,`ab[*d@U2łrwNk]#\lM9!nwbxrڎq)BzgU0$| M*=}ۂxdYqV-V\}M3a~]!g': w\ :-5>vձQ/(B_T"V; 0(! hyEv`# /8[A䔫LZ >1+ cȃ8|uԹenDKĦw9 N{\rI$xGBmR?e ]̧Uv([>JBXAl)a %(Uq&iB܆\޸p]GL1^9ZRHy\5qRn;GR㑪VTe7y&eދ_g.A,=xEa oEʴ|雎7Ftfz{;! y,RպleAYV#'dpQriD4DK^$(Mk*XH2O23֡$L 1b7@2sN e'I>he/1Mٺ@7^ZDvK'qln,4l⭹X1BEN &PGu j'( z6JVZ8^μFG6:bpAGr}}cs:>Y2\Qίrn2W  G<+v P%aAZ R< 1 6}c#İZ[EP>\2L0H2(ý[0N\܌ C 9Z]䗘BAО~/ix޸BO>xλ>׃p.A”{ϛńH iJ6W:wsQ50i+ DؑEOj7KI+zmG>O>I:X!lxǬA`&֞kb1y7e<޲z*ﳕ&~up4<#pPTC6!Jn1p&@INo J3$Sy׆suݽ3ЄĂV4J@u ".(0 O[X'oNDܨ q j-Z!APϰ<ƹ8y=>jgc PLd(v HdZVݍTFo-Vdb5D: ?Any;@%4{~ ZETý/EΩ@yQTu>"c ~?uu7r/dƙ`#l,ma:?OP9X"w֕1TEh6<S@"ڀ b@U5-B}]G:948J\Q FTs1@8C7L%0Da$#NK^sP7W !08@䵒NSCᩞ{>hhgAHcB~ԍQ讶mXr ). h"BdXhi lU48C6^o_y rnczZ̿{ 8^%E[ A`i9Bhp"A.# ۋߵ4wPuWUrNzo3b`45^Wzgʢ٢}W+7&Xv]H.,U䖵l@jEv^>cZN5Ԥ8$o?t[Sjz 0˗нEOfx^boujH.qg almϾ͟psx^D˜W;#84Ku1jH~=0꣍1(1W$7Oz1JS g[g ˃:/F4)l0ftF$cBs2"ˆk㶹zof;-*bc;AVVm3,_K) wAQxQN|6>xېRX1a5cAQm;ƪi,H=s  锿mM # 7 7=X%EGU4dL%ABz$$(oGIĞZko7S=:#YkOฬ_f6),,wYQJ!ٍp}DK T[l.Ŵy>s{dzPcD~s@/8_%-ٌmW yR,{#ȦtRM*`{ %4TsTm*j^ʔX4de~{'cqlX>nX(6\1=Wd>3Mg@'q/MIU2P =*OūuX^wZ1]b.Us}?mI rcjJۚa$[~NR~f jn[Z.)sU IdTdw S/.SZfñɌoE#mƑqW5 s(םtaM7xU2%˘*pd-$B`E eOLjQ#+:NHqCD! kysD}y,}AJ+kM"ї";Ebd >uRZgf$x1żLGs/7>Wgc[2CzEнE};Ew%|!]u1AVse,g뭮js69SkI%3GZ#g}dLgWJY(F_狓9GxpfǒO|vЉ+vU|<3$^7Lϒ#Y]ڮڼ3kH_LsxN F߮3߿}+B]980bXjNکWq>pZ{{sCcGM(NP[+:P$ YZNF]p6AVAnƌcMoj|\uΝc X@/S%vTLPkDeWu^)SaNWs-xQ4y>a~ʡ]PuVS\ uBbǔ+r|]ٓXCs,c89.`Gw^E hԭWvL8~~\9bY1|x6qkg\,!zozKqW@˾&0 YALw| y Eʢ S{ ͥzMMwMVtAi߈ #4 SN  SI!Sm* `ΟO3dnls PHҲ/, h rUmQc6xÀ@c;8Uz!TقxBwšUq}=` H_אX --MuhS}٦& p %.ݲ|(h1^޷Tok"gx3)\eu`oWd&?)$_G&oen3.+v`'᧖[mcɶ,HB;pB.zҐ $igexTD4]ױɭ <&1IUEO x"ۧǩ"%Q\au}S׺,餅%+9|7:4G6@EG8-z IXo8q>cDK"1nF)1 ;/ܠ׀P࣎w:]$zc3.;,LtpZ@TQ܀s , -F;FLIUMbZ1011hM5.ԝtTD AWc gL:Ī.˻4hVj[Na&S@5ءZ22%Qń0|?| 8'|3ᔚz/Ÿ!$$hE^w>i6XSs௦ 2 @F@cӮnc(el0j)m-~ R$Pn=8?D);5};nN. |txly/W n; Hc{%K^4/}4zSǔ91L?UqD(yOI {Ƽ=&"& ..%*QkAJZZo1.]"RuWB R4$oa0ׅV$j.L4 ù_]2>Ġ) (IuqVC0]+LxWf=o3 ď٭Zв;DޟDlXI0_߂\_:x5H Z4%Bʙ~wM}$U.$Y$!/}5B #) 0aHaT5TL.62$W'Y n^闃O=a5{Bgcs.U,ﴈ_i,IȄH)F߲2nr 1i:zۿDQ5:ib!hsr7 D;ptI\WW9Ș7hZFQ/7\bʢ7N?Js ,;Py|<<# Wڸb!~zv(vN`>Q *;KUy~i[xJG?ˎ %@6K)HwX) 3Kͭ" gz '.zC:ByriY Q?6]ɧ]T/ZUˡ1K ;Cl$tDI{ǥ }|PrZ.Ȱx#a02)rr<3 'llSn'e]K" 充V|ҵ?^ܙͧ AD hfRf, %`BI]`־}h@>#GVv zh-ɒHQtzm'(*09Uʉ|}43PY&h"$QD]‘iN7]=:Cda#C4E %|gn٫x@w%' jAޗ~(|$ a=Fb5q..k7j|w=T(T,~oujX;:0a#Y(`NId $GJu *G|D??  *)鄉AV& ),$"> dQWm&4g팉8\y%z_o0 P|fi<ߝ4 8FnE)$<0xT c%}TlR,/~Q,3eIkPNqۃil>89B(p&cnͫRg@Q |Iq~P&%Cd44TPxl Y?YΔ@50!*Wʏ^zVVot2z#q!}0}iO<OfRCQ{AeDE94ª<_z0l:XJye`L4:cphb| A`a328p8A`0a?~EcF\ѥVv[ ={ TK cutx oq㠅-BA1Nr~.0AĄT %~4 `ɉJ?\IDΘZY;9!x0 !Y ÜC9`'0:s!WR2ʙ齲*qk1CBÌ0f49k SeI X$bV  p1@DD1mkYCޭq1<~$ h\iE0́cKq5ĆNjT 2b-\!Ѩv1`0\#hd8r|#Kq?t/q<}i|pW{4~p&Qjԓe.**aX"ј,A#'[&4 t#qBD4`HO 6)SP @1d  ``萉]'"CHeTA *;챱Il>u*i^:a]&Y4jh4 .I8)(+ZR^t4ݚhQBӑpޗqR! %Jb$T=,g GɜK:8aMp!c AAh!d45fPl31WJK  RJ{!, iޓT$(&pC^a8sK  2ፅ"`Tw"h8yQv Rn*ƨt XYt\,*V* Gz n",[780ƂbBƨ ) [Zl@(g-`|x~c]]}:1}©* #Hi궑}~/gkA; Ґ+R!<w:Éq8 OqbE `oӈ?k E|˸>@̧+i?nk3g=0J$O{>:u:4L*}Xa:hs uZF*: X"Gb/?!X?|%hu}E,eNV!qbfg<Ǵ̑Ċ{OO\4z}ӷF>nOY(Z% ?;~%T aO{>4/?8!5v#HDc$oq`N>(N7؁ߎ>0Op'7o>?ª%y6x>yt~-W-U-aب"R %RGxaZh'%zk9cڡ\C`,OG8àu+Ed󔶍 i=yo'"I UUD ,jL##$! LD6"lѼσ8x$'Cv %U]B+NCYX{|*JuvZ=IGVv_});DtFW 4Eeg< 0QMU߱B^Erܖf"01U!j񇯗ǟcgA7Lrْ{pj$uyOrԬzfS\p ;ɸII Ѓk(H܉f͍ή/b)#*'8$Pt?t4nǂa2E `j:i ,!:J7T5UZN{q3v1cLʱ҃1xXH4[tbr6i|v#j U%a1Ѷ>ųF=_zs{]PIC&c:=_3׺/,QԮjsj;Ѽ|mX̨ٖi_Ch MKngٶSA|huϻ}e(~}0yUTu|lx&=9, 啲. viAS ԟxkgg7ya2 (O'᳗NR(q)px*6~1{vM1m2pȓ>DԵdC; rY2J$J-fLNcM'jj/WC1?O]-9~F`tلtnNGI4xWdunRkY%h(h܀`x;.ɏՃ_Vdl/ϣ1ojm'Z:_WxA hnO!z˿Pu-5*JJl!> ?W,J MЈ'겘e BRXV( t9 t @vj)b…<Dv1"(MRm" :0r꫎8F8Kf l0<d/MLayl.bszANb*%!QE"A#iX"uI SQ!0E@*(3 (%eP dƿxHI&H'EX :()H IRQ`bՍ}2\4Jys?}t&NL\A=N ^MM`aJ*T e<$M N൜10` PLR.rd``)B &Qݗ!MڂfVi A,摁Aq=#*nE! !S$J,[fzf8\r$]s bB͊d[rm\NJJr`U " c2$e1A=R/JH+\aQe:08nVr^IvJ9kv11L?*w`cn#a~&Q!ҹq0yPI0i1b 0f8i&ڜN.P Mu )D1$@L&s] Q7Wtp.9!RIf% QͨyÍ4ֹ2nEY@6o:KƴPDU\(ōfa z62]45⴯K\0 b".]@ڈ"/yJY#z!Yp@(u0OO< 9zBP#!0`u2 `14"@ RBA1L F2,ם 009oU,^VjЗNG1Lj CRwLm.;P9!,ISMN MDƅH8#uŗh_")[$s%BS^ɀo":y4l!pr^v`cGL3D<7!w 0# HN#q!KPRF I+ 6o0 ;pik"h)B~9r! xUǃ, "9!A1:SDQ[G x!R0?23 I #:Bp!VBr$}%"p$Ȉ)\ y^bmˣ9wA=&(@Si $)W?ϽˌN LHTi,-0&9Ģ2r]\Ǚ-8]G@Y` %3z" ?.0\yC U(Jxm #cХ8!Cg9e &( F* ,)D!ar 4A Vds߉0RI$jɉ2 7Zaq\\OmӠ9ʡry2DHP ,:u*=pBme*䢊'B6A 4{"B%GT{t f i-Cm&MNMx7$K.:m(Ӑ[+lg(*2Xi#0=,w| %Ġ,8D1%4*[YL (t\aR %H^aӨ@FՃ9#bpDT_g?\<VgȥoB4I+oO?Lq9BN$Gn@lPV? @1[$m;!Cppɬ>Yd"#M9 +☯mmϘ1 t=÷k/_GQ{*v8OAZCXhi2JᙄPƎl,KuEͣ+F'SM̈!:b^J%8{㬣"тj^w$`iH%4%Eak׎l1wdșA|fX38?*G^|{?$P4Yerh羋F޻:9R݁14%!!$4ik#D%%hrez+Y^x^q69s~Tz',xixI&3RHyЗl0-b_g~/iQ됨+jiSH S\@.!PuaܺPԁ2v1:V 9t^P'lWdmaq~mU8tqK tRx<^8"BCmM0j |͇w{ad?Y7haidSwVH(*5Bl;'a"H C]n ZQwH* :Mc FGәk/_S#sc#$ ]+ޣeCӌOh7wٸ OT8M"r{ 3ݨH|o*q"/0>7 kpuc4ֶx]6d4Pp i{6%{B+#$FstxD`Er2`-[ubO1q2Ix'Ϩ]$i#Q&8<4G8^Ё 9qɀa(pېM˳5UJv:h?hb ?X> qL̖b $(6B -EVlh#(-1%ڍ#gBÖ U7W(?*-F,4#"@h2.o9~b }x%@ywB7Nm$"0B H" yC ؂ hImnD% }s(ĹMc+z R<:&EP #ARIA |"̇ Q>qC b [㌡\>-2ݥs`oVH*V%IX*ʅ7Jflb !-n`$"N*Rbe)&[moJgvk~:­]dDwbEtA4Ѷwv~v7׊1PbGs$txchO^*eQv;/C'&@PGyPE"S2H.|\r*zes٩(p>%\h" ơ @GR,6 d;`HQQ,Nda(*{i 켳ufwDǶ K2&be&A`14|tw0p2Pu/xG= RC@܌!{fv@n4-tPߤő,@.|_;"PW<`rGI>z 0VwqӘ9(.j]ꊘ{׋xIyT >V8!U3 "+X l :] Xv]V;SM"H $5B-/20h71n;*9ãsra j/3ݙ_5^xƣ&s[;w2=8L/5շ @ƹ z3>i_4&N9f1):vgk Lbh'T6%ulX I a"(Wh e[y0MJ)q 9A{BČdJ+j%FUtVEqcmM<R$ AȺis0M{&nuF 7gx!|73naڇ)2PF*=dl/W#eM\%";!ݨ Wi}v6UQ E,5ά % 4B KqA5E3L[L]@%~p^_]pڥ} m Nraq!_,>,DuZV_`zӳZWY}A7ތ6 WeD j`^2Q>CX@$LAtWynA8o͇?Ҧ)8tuHۢ~o"|a]H+5f]S@bԠC^NxTۋLA! %ı@$.7p.<&_}y, jm(F@\HEd*C/m8_WU{|5@ =0+1nyD&6_NE8Iqۓ 䪊@D绀Ab1C&BPpK';ܚZ5VNb+@Δ/hc#_ޓ>6 聖+5~YiuBmy9btoζ6w(n4vhŬXc |!)$Npo1Q34hzY$PS'䅴3r 4AW \eV<#lM7*"o˙)ґW$.F2JJi.%6pR[|-{xHc)El,"Ûo}U$K}x( Km12YX_bk6,l$@嘱5cVS0j*#><yrsQo JZ- lad&!Bն+lVmq,iEaLIYeR{iM_1زF!,uqa5C 6SA>]{٢` JP>LcIaVبKw"@vt?bSe9OPyfM9h˘+.(؂} }s#}Fme""m걫uEf| Ԕw^9ץ{uzvqS;-gww8cua{~F;/^<[9⼥˭ɼҶM^5bj;kי[nZIxlG!cS<~) T§U?X; $pTF= >= ?BJR)(1N =E 6@6!lfŽYٝPEtACU"1?̄4 p(Ɍ = bdLrM*Em(W\ӌ>0P ,C{pW(AS.6 02[װSȿ<?ը BR@z'PZmX >ps=uu ,1"LfgOK.6%sնaZx펓imBRUU 7D!p K:ea*Z4jOj?JBT% ԲJU!@;5:ntg*s'x:l!+[+! P Bi㴸Xt1 &%:=bJ|S>qSn;15D/!F dϦY/ 4 }­ɼ $  Kqp*Hubs^n" `6/J`Az$MmHM_\;ˈ d~pJahL ux;jѶw%B|iFJ|2 —Rt2JU 8 yp^cm׶8 x%X% ȟ$ <|S 3*%j IW|rNcT}} T@FJ$%`QjPv9;IZV#Nx]`„T-06֠8+ohqDR{@ڹ:X+ jɉkC WF\cN[1E<@:MbvH МdtNAJM/964<9MU89.7 !OTHOR80"| '}+ ҿV>pwX|4>OOlqn%Y;K?Q# '2 DrgWv>lxjpwQCEPһȒWkBBIP_# p0Rbj]32ֻHZ)vި4,dR d1['uAb`1v5rdwb6mh#.q8vuQ.i 1R}>%B pop1~`@*bH&2!C)Qؿ ~G*ۜZD범R;".:f@``p 0 ̬@C8zyn Ƞ>y]k.nU3,2A:o@% ?%@AF?..u.牷PEɈr$bICE'7lSd݉ڈ]uІ".030v + 8"d4 0m)!8WnD#8p3"0iDxb" /OJ;tH wޖU`tNC"T^36:j0#c=cCW"пh "ɗB_17|d8Ө*nwWQPPAiq,,Yn"R؊'O r_ QUn!x !p{r\: r!;F뗵YqUȪ^Q簚ܒ)TNIjp6l%@C(>CuV(b#r:3idw!m()t0qO H`Lj|^IM(!bL}/tD" b"""!INo u&IK`~Uzk$"J NA&E^N _@[Ā^~H'I<X('OoGwW/UgJ=!C3q)4; ٕ´+ "qTJ+!D ,,(g /];o&-߉I6?ޭ;Թ!8l iu`dX(VjV4@ #r -[2(?p<8@6r,ɓc^K&騋1CR-tb Inzg_hL|1W_NFC7NpM{6'yXC'&%]P_a}Vp&; $|i@W5`[+# uuvFi`0 1rv?a =#бR%t?~{"g&ƶ-Vı|seZ0V}gDչ:GBY`;D:u98PUC~[\i=] I1 ={M೤Zdhbu*]JMHUUUUT{Q2Bf/=18)Jt/Р)J͵#R&ߑt؎rWE.@h >k<Xl'H74X= #c 2oS T~v 0-b2qVEɅ>q) (P҃)ʈAђ*`=i%~Q>gBCvH q QdiN' G#fӣr^Z=ݖ::ό(%ޮ5y#$>wM')*b|}oքLHH iD@ݟ( +1 eć<緀תRzs2@/9inڊqX*goF+Khqv59Qlԟ\,bA gH_pGvaӣ(|vx] 5Z^; pW*.- AǵXI`E xH?f+@װ<GAE/69%g\:h̜] @ R:3`SSLJ><*ݞH)*`DDC/[ d)VFË!9NFaE^6T,9Cy',O\"|"s XkZ@϶_ soVp0fRXcw2fQVd~E D87B@(Ki![A\Z-ˮ VH4́cD<<_ITO46i334coޯWQW?qB1PldSz L|b^O+HE M*zBã㤯G< snQ:U[QGVȚD:;L-h S!CLjsҠ:p#ܚ'bhȏj(b,^-a uzwAvߔԤ>`|!?;?MP\5ӫX X/ͮ0?/>%>`7kn qya_#>.`/#Fӫ1[4h6R p0!|Ld"# yH~ϳn%ˑdk^f^ j(v30 zArHIa B˞j8!>=B gO ~|}tUA+ys@‡||Q)Ia%C 0_xM=t'p`4-7w qqOV<ׂ 1()w ܋_5~)xe=zs2˓fEߤ$ *r،kq h$*~u!q$x`|&(vSFe%#9H&|9R"NKĄ}.&wN q$F"!,%(^&И=l4@ Y $( 8:maƓkzB%A.k,4b6g͏vbÎ&; NlA7u 1'2PpΚQ)<QݓNɉ;MSRDL((> \Jta}~]~p3OO>yIR4szAަ @#LjY ,qAz 4/vMT$tB  +@*@:Rj%Dj|r:qU PFZEFP&* ǨL4d(BS螇[5S5M{2XZ;AD;"+ :`B| A;'0M*[G:OO{\.W5ՉrbB걝E$\C ~;͘!W\G.aɡ4%_RI5{aClv0u鉜T IxeI.ॗ+s>_4b;EAdnd7M ]h~ : C @Qx*lݻ>A1P!S$E`c4G8iGh@T+'?R=b M R5@ 8rA P(Yu)jk:L x26N(a $"!(]]`Es Sq4Z?R?Oz8fep1 2BW!90brWu~5M.d=nk( E00uxlu;`u646:$Ob@,,(<҇棪!=` A.jxvޒE[wboXGvbS_'DZlS-P&QtPPPLٶD _hl5x|I?%%<0`ܖK-ϖT[$1O#k~3;? ,?ϟ<υ`k45)%, ;g9|^O#(&͂>~F[`Ry-~-CI|I'CfzEB z8npaaaFa$_@AB"H 7,H $8!%C!ͲqxmғlbIlPw$0e & &`;AB4i&}~vf(*?).==oH*{xqO 8w"9L) t *OLͦ{\;3B1`ap@,ZUYE)?uG( vDl"0Fo J CG߂_ԃPQǍAY69c+tt_CJ0|< 숅O@tճ<9?7q=ƅR!eB )/(l "r0CR2QTS{^CoG{ { ]BD$I٤|xV 6 &+$ӆ 9bí'SiLuT8͓tAӉ- P2 j""XlXj t/H p:Anr2_fPXWlnjcdAu~$M#A"^smyv$ʊd9OOd՝h#Dh=ji5Jٻ/.mm,{y& $B,ֆ.mȊAƕq?)o7m!(pp, 2jF!:@Gt9.* )`HzWV $|G^(* 2&$REX8c=J"]iUMbܦ ͯb8*{=<0;Pc)M,љ))&mHN'&11 f07 ĝL 4. M܆(i4wb% j ZPعFiĨ[AQ-5k p$F LL h44 (P4 ]) 8l]$9 KoM]gaUv"VW5@ƷfAԩ"|K@zB` 53bAQZ7! at> ))S=J"X& 2!@؛S GŏW@ry|(ț廠7i?ې⫴x0 RJ<BR .`U-|/wݨ2dAw~diAHDxpL C? xuHs0|0>ԝ}<>(8RPߴ iTW쟊u^GG9P,u`oH?XLrUqsx|{QGHRBI4STAP%,A,HO\6ML0H`!0ދE$ gC_D$K05툞ދ~QJ xtRjO >2C!-$XD|Oh!cd_%p7~5&Ibj{ wŲrf3Whv:E3_K0&|LC9?A a8E$Šs̈́#U8=h)R|H00DT.$(PФBI"DII0d 5j1у `܎ZST!8 Wn%TV`!85Kؔ.R ĬBBD2 *@V\0}nڿېT Z,Z$TZ/C<]8^.9-';KwhFyb;hpI{/ cZg`xܹE7nQ<=(e5}r9}U8VKO ;ME/=8HTO4eT|.%,&0!^),Ȉ^xO` (<[}ذ͸|.OjU]ʚ_$ZAxLX2q#zO=?zUh@ I=ux@tz/fQ mo4Xzϔ>{z : h 1H28 PJRʪ=7>sRQ&94DuK"@Q0JxJ(Fvm.ClJce~`ryvj% Jֻod! 0P &COknُ*U|fl=uUFQU Pr~)pؚAlj"8V.cX=}!1KrB~|Wb];ѧOH"8iQyx!@֎yz.\_r;BH|7? Bw}Yb>vv*+(I ?:Vγc~!݆-y=Ti p %߁;u{}Hӗm}B"#Im2< ;M?F8!S!LN"Q@%M]p@M?# \v5?u`ZR ;2/ӤQkH~ ܕqqmߌ/;#pg!aL 0r~p( kWl0D_Oؿ,,0K$\ )7قiv`o/R AC!pWى A! pxv\o3":OĈvh1aa,1<)aN5’ gہ FN=g[6dvP텛~PZ% xckB1GEb>=Fd> }`@G<(VKۓuTT_!ZHA*dHޫ4kQ mk9PjJ&sH Mg )`ѶMJ_GÖݭM[4%4 ѮU^.%*+uD"~(x8Ĩ $(A+R"C½AaѾ@~C?~^aӋpW򯳽 D}ūQi@ ^nsI NCrJP#EJGU:Š=2Ut:FEx}S3N "0# %'朗$춿G@t\}iqL18 7n&(*?XӎWCj*oAǰ,3Db?tP$] Z @)إwq/n @!ÈK`[صmc 4c jSL# tx9~Yj-eZTE & qԄ7 񟯶'_ϴs>X6DֶM. 06?}}QIZ@D 08p$0L ;Q~S{_/ܑxO7T@[% hz )9NV4<=,:pWVV wu$n1Ɯ a!PS qxc97 r@pקrT"$G D1 cfaH<QB ux| %SdND !dYo'a cӤ=jVRw%aN~ QZzT++ʟ>K]M1lwk< "gԐ !)LnT$XUaؔqX 7;GX74Glb..ĵvrU6?(`M1 0h:g!cCy1϶w6i #I`d M^}qKT5CTK8焺KfrGkC0@@,N RH"byFjn,F,+ҁI&p!Ǭ@D<)7 qnC.#D$?!4x٠kI}"̠F=n"|bD:TB{jlв@#/I =!h0sڹp|Z8=0bKO'*b${jT},~oUP {2^ H+ѐ PD"#p @z:mhFVZ>a! v Tw4Y s "|G52 9{>*oAx1FJ7\S ;] GŸi)RO/p)lwP:O"dA(#zN9!jhr0(`bH3OZ3 X )UxtXEla`~՗<&_ws7-vIG2Lrgد#''S{ %y9'=ANH* Zp{7ՒyA:U;1DMPJ}: yS>&PD{ lF! 4R)%j sŪĵ`? v r*5"Ġ~k%PJn"jk2};´ R h`! 4}[^Q-w%HaМNS8.2Py=z4; 9}Ȑwrmmī^AYԺl _Kwj13&*''9+2kVզvdmmg]mٞ?%<y "{ ;Tǎ̩)?-~-W(7}P S( JɴD!wyѣ7U0KKU$-U-PUUUUUUUUQX%B6 h~/Qubu!?H#ao1H}^h֟>kz[HO|$ _Y4 w\I%OED jN!18]E" lApR"p J z­"E#Q)$=ߡD5@kI @s|> H-H^hG>1^pD$p& A}@ UP]KWV D-!4KWMhP`%R :]X'^ZED#}鑡CK1}TfqһU: w8-Q^HlG%'H2u0QChH4ԅ,eI=p!Jue"mvGyqf6/P( $STO˜}3vov&_2|B*?`OQyRqXW}b{o2^ϋW1ǘFE=O5,_?),ELSTXX`/ U4-ge C ap.W-*TU1Di5@D6XD`JlyA9=uxUQ"t׊%6 PYkyi 3,G?x>y5f3\ѐANp$/h%n#q=yh *8<)ONL{yyd*rjx=B=uEݒTH'~t'pX` vQ( 3)҈41wRWӫmj.!>;Ȍ5ֶ6*2Klzklg N.kAq||obL.X|ؐ(``pp?JbX2 C.[30C!qixK}y./[fߓoɺ~Y.ێ#c;,ܩPqsZ>z=Jߩq>1_o^jVg?WkΞ Л]fDH@u|ra%dΓŦ70a\c$!w-~p6wWŇ.c0ZYVje4А}13?tz>s xL=?+PĒd]Qe'o/#ŒLYcP #@=&`K>|.]sڌ6岲0B`J/B߻_~s wtC'"m/l  bB`9!HZ )a h&e"0% ZrtS_P)(@!(h Y*f!C9}oA * T ͻvVA0/"-0p/ =' T1֔0{ Q!aanJ0ײ2GnjReH K \@ H$J6kV2JRp>'D(IbB9,'SAz?NQ ]Z g,"$w HR"Dd !14fB,y>{=ԏQ ?MP,Bby5.BvYO*QȔz`M?"W øk:BUaB|=8!3_ieώ5DU5 ֍/!swG Hn9~GVݟ@x ֵ 0%6J&BpD8 ?ϡ?Wk䐌mOTnz`Ӌhi9(6-$2`B-Vu7X+9Yi $ENs1Ns}{áS*dS$Sҵ&V@"H MmI0^n\b0{/FmP#CL㳬@d9 hG6_{"zO`EBE JǷO'&ˆ_foa޼8-?8]i<ӱd_QJaIR'~ױ@_y۠9XY^l`.#zE`Q<{Ɨd"DPB PB"D%.?:k( l(*鲤Q=WRxAÌH8s2 @c(L J2*aA H Ha(ᄩK! @P"jF YEC0d  !UeӠrSB-/;vt~إC=- g+P u9MȂ8Ɩl4ocl6N|qޠqvAp!@!I5C012?!d$|i$VdYWwI$dGK {_)F@)y9GLC0""AD4b @p 3$HKDUZ؆Y{_i( AB?ཋv`q"QckK"ɵł]۠ҥJWzRl/YrWHpdLVi)Tt8S9M&.+&`$6aE.|_FDUUUUUUUUUWnAOtqaG>|CASl7&!zEsJEgB0Ў#S=87oSB{OC s 7`" \7]ifoMaNR҉JP tZC OŲE2o *-p`Ar>pxā?)9p)awX= E$UaDA44Hz(W4>B.HA?{g@%tX  KD~iDA}}kuz(Pg=FhHc $ W S "@ q'iF8q[Ӡ(Ux[IAoA<) I| ڂ*҉Ċt4ϖw"b &fKbܝ ]>A?NJ$H`DaAD~ 'F@A Q# "@B[q@~C@G-q |^qL~oݘy1DAr$e8㻡ԙM݈U";+jƻ9E\WFJ"ya?MDb';B02w^wQjAb4#`sN?B66#;-ݬW^+)A7`r82O*>"n`P#;wCo~LC1ҩI6ypş ?j@fH `LLF<^!W'ƕ79|ap:%KVLbmaAV,ТqV%8m)C1( `Jރ1+$Q@;(DLz_==~&*U(q1뻮RQ2!`02JJ,ho!;/>@dcٺI>MHP^p.B1N@<\C A0$֐@.,B]4q, I!hHȂ1 P"@Y $&ք\B!aRрU4Pb/x 鑠=nkTl;{p}9q@RɣJ#jDÚ z!DGyAQ=}?4h )n$(E='p<y#b6(1DA5@)3o:N r?(P6˝tadtydBa.bs賱h0);"Hd8!8x IIw$1.q{Ywg J9"9jz,aλWTtÀ.;6&uvtFQZP/T6$ $CX-8K 98d.w"{hKIJ!b8PcXO ^ a2uR)IEi3B(hOTCUA%H/:ANGgKBHb(u@Rqm>nKg R)Ljy KEhĠՀAǖ:Og##8+{ P_WxG o2&E VM3'!pX4d7DNTb*8?,)Te`slՁ;aJ"wxdbF#ОދU-eBOxV!/jVX8 x`uȪ) FJs0D?&RAys0SAeAa*xIt]8ifb =@B!tS󌋐! IQxԖÛnHDA4H  6e K&PO< vINJ.6 w!RW\z WtIoXq%N`lĶJWi&6^>040;pdR4^v">S?|D Ɍ=$M)n&M8 ݇Շ2 2YWh! N_ ׳>LJ @3)U[4Ba0KhYVA6_P vv$桿HCխ`Ƚdx&mP-c$ ~n 9{cB .Щހw(-`wcț]Vr0&26W  ,Bk'8&@(C% (YM:ۤ@b0Scu̾AoPU`QG!x'g˨>`*»?+wn׼NsXaM m5K%P6g)6"lOٶ>dD^9ΘÍ)@%g PǸ{PVD|ipN~-B !֠W0ơj\siqGZudlX+Q8Y1 ̄d]4%N&ݑZq-X`ܤU\vDxRD~(Y7P8.A_( 9&rKPp@cVAD{0 D@:m5QʆAh|F%Bs"Ru7>QtQLis8%S jD2|]!-6W8MUn?tlmQڤ(g{K}C99ku3wh;ML @ _2w8غEdiT #Yr39s+y[`n P 4gĕ*q́P :0 w_]KBػNZЎHQ@AP `2Nt!a eRRudt b7.C"vMҹH{4v,]*1_BLrgc(A-b 3ŪfD,`r(4N/J "t-~:R pA2M]̓ ؕn}:tvF'BH2bx+Ozbq[V<.]S5=hBpn˟F!~uc&qdYpcz=#j>)AfK7Xi1*1 XVU!,/nX0viC@w"pQ\Zl9:R'Qn3]l X. f#M}ٶ43 ,lH\>wtLQP"i27ͼ㜯O>W`_n/!.!;Uk9AgyawF{'S[緧J1b` ғJE-0^=&X-rF*;NfY.0zs,y}9F8|wE# SAvZc yi!'5rZvhf#q ׈tF0X஄),1HZ2H,A%|qrL}儍^/Ld^9fqp޲[Ђb \׶F0@K:7*h***JI*h`p00(V_$T4Ȏh$ꢦh&`e@*F#f05Uu+EvhSXQ7lU,HvP=U za"oTUjBaЗգb#}.vm11$hs½nq°v;֚2@T(irA7rSEZˁ@1 ej X50DK1 L4χ̘ /5h c5$^ pTpbJ1EؘIp\ܓ4.SQ/>TqF&Xڝ\\,(gZ,5,"X*NCTvc%+(轰bEPx(H҄Fbkkey2S}ť±H0BýTh'" ͓`AX h]4y ;=Xdur'qm8|hݣ", 3z-)A9Xv*kv -e`¦UrV/줈߬9"8"Y/dDJH۰H2'bPx\ dU^AUUlx2!RXVAv,p ]a_HXpψ cS sIi Ѩ8.vE.l3H•1UUR}Yn{5Ѵgx6OCb߬F2@ATSAޣȜ# )'Q8n7h";3K}-곯EW>hu,"Ys9_L37PbA=_I|ȮD.DOWݔU|./(?76M8V(*/!l@Ոmr'BPzAy aDz0jdWȼk#cpa66_ęd]MxЎJ7Ȇl C\ 4%+ 0iÚ#껂Haf8` P+b,sUH %O+*7ú\k:!)MH:E}G9ڳ]Vx °+ txZ#oaz] $IR uqTe#2 Ԝ8>Ię%x@xB(3!yܹ8/}:Du azX{/ AYI0;:R,<`1#9d0@ (s Qa*iD:o4U7 6(C Ht9݅gQӼk1gs!rt!zNLv:ꙀoM(OoEF3׹d8:t YG-wyd\&?[ ϙlUzzx}" ,Jнݮ fQ'\s=PaqFb+~U wO]fsy5䣷\Gd^ކmơ(IG6#5ba~ / ,'`~#4 %ݠ;.JD,aGjm"Ь ^<R[j5Ƕ(jGj.uQ0݅uרQ6wXPelmyE@@-3"XLHMݩ:lq}Tu`>E"CBI^YWp!I(Ĝl;&4AΞX{, (0.,(f% "#håSXFplFAl5O2ʅ \pѱ r8w@# oBY8lX $!Hnǽތ-4 4>D]HBBzELhB_`"|S2I$$n~aPa( {pO7<= w]7@ x@E qjش~- N%H*h _Hd0BLj " $ #"*|[aٽz , PELs(&~$G+D(A$0$4BR'1 8炟0 np!)D|PBa-H{@r3 "HxghH<G q 9(iuWv.=\Є5V|T1D%3ԟzIh ln0Q%L(*?iSaq# 8CR߶KBuJLik2nY5Q*]A"swY)̒hS`X\ywL ڎђ11-q| 4;THIaf^.SX=|Z0\3!RDDd7l֥.B,.]ip@, 9-k g1 J7rPUq jPIۥ 0qC#Y) CB -bpf0`u6 &A8\J[5{&ĠG*xo/9i!î3cfaHW|'đRD,iC4]m=s.q̦P̼Cab>v=!b/'|4OQ.!B ~K] Ϻl{؁8W)]׾{H_xYE,qjST|-nALv6a #,9uZ5q5mfi5 3HQ}Dyޒ%7<HٜDlҼF6nbțk^|:q |=nO$\ >39Qh]6Q&ŜVǭ뗴~$iV%т4I6߀Ѳ$~5(p."{1dM3 32Jf̼L D T4\fJ] `qTw0\ N.+$BU\X002N mu#M0ObJY#D1b*b A)@` Y nPY ?˖[ypqh 6 סOх%m,Ƚ"T4\!(=pҭunUEyPЮbP EEZ G (qګ.( %aAs.2{ÑW9Pbz0!3,~XUoC<\T`A蠢2櫒BX;T?+ >̢,YZO-;~һ .^Y7}cGi=Zd¡e7$10 ́,!JTM<'4l71q g'#]}#'p|j~Q1DlDLH<CvPB?qiJUvNy$scH6Mʾ@8O4'6T̲y 4Gc C#J R('2Q &B0(R ? AR@@+¸qZs,P32C[BG @)g[IF٧ԛ6Aȩ j7E"a lU qDr7(o 7Ga,Z_-tp(/B椢t@HX!ZI m dDi$ @&E[F1z!%L/y?νt™WFOBCA@PpT94S0X 1{K.QSw p_ۑ,4SJH^`4$.vN\`u$jjJ!tX UӠ5XҒ0!́4kh[EBPSb0-%0aI#T($!<|gpg̒eA']R98 C f!qrJ]t푘=88e)mXn-.77l5I4 AV24kzɥȴaskP^Fh a֦)ѸHC JD $iB"@J"1c*ӯB-/K\wͯZ*;7FTP)`BP~ ;CS1T  kZqo$ DL%9Bb9+@?%6B>Z  eemy$$9[n$`A `1(JQD ~8V*N\@jdY G}ǁGzqa)$2u0 @d^^176W> c(#&01X)HV&((,DHBa  U1!P Ж.Po 'rǑH PEy Az .>2GHA-=g8`<U$TJUl4oiX3. p9z3 (JTITBPHaʄ"Y&\^R5zf_ `>J4E?@q J0h|xt|ӳ-fea@7i&C .D5/@>ɎՒ$2Oh(*  Q*A+o)AP4'7G##e "ÁHM !5'"v[vۤ9`zӒ~MFi>oFM-ZL8$%s(+^6Rh!s .-?tOo폔s,ޝs u7>_(/8MBBIPib{DXyH`3wWȬdY$$h < 69ȏlrW'=q?$vG 7{_F".oSAq9 d4| ! E}"*hڠ@ӴoPm9 ˠlHD ftEl& S{PUVQ ,$ҫ*V#X4MqO50&PRkMF*BHZbrQ$tp]ĸVE ՂZR@W扒l@zf#d1BUIhJBkA:C𿠟RR*DQM# L "m"D$l@6y׊WNC*Q\CcP YZ \NϞCjH}PD@zN|Z3@i_wZ4`i@ܠhuϺME86$zXotG<1\Sχ`B뽂\ 4d"q v;  0b:,P")2}!2dpo]'83<00s Mχ aدZNִT<{OY߰bFh$.@Ѡ>#m1$s UGtK1~SzH2Rhe$*;]f>bl%Վ*iq]٩faE2nMU|`@;\ ͵ny͹B?K6E$rRW1|ęյTuxoJY$<`0ix]ncAx%UBW@xVhKuhQ @ J3BPBp ]]@"3f$7(8'>n3x(nr 1%)(KafǬ+;!=D|:L!gNP+^_ }ĝ hlܒJPGʙᙥ!W !&rE y1nM=`B@#N0RP*1'"hJPD%"CD  RH.Bf&TP!>ߌ[Bu;]`> `<1@q"?1=03Dx$e=Hc^yZ@(d`ORpyx BZ l66`8,g̭>hHb#@(2[SBP5&D$8Z W${GÐj   }p.ٚC(%zZ" hq K> `l wzm֠I4it0b."ze3Ay4J h"(Q8Y802 R2*'!=h`H0AU|X )bVA"!)L!:>.1U5UA</AMc2!2 Br2eX@Nb ?iFO?.\<0:p.m X[wRxAFDw!äZtJRRHJLFVP By:'0TUAyDjAa}U7Vy1(^̒:fHT@bfQ9`(5ⷊqg8BD 47@آ†L Xx.ݕwy aۃHdD2MADTA$(D-JjjAp (IYf,"@3`Eȴ <6(烻)!KR6 )LX2n*2`b0Ld.*1՚N nZ:Grrl5#C $T5jB7Bn$ D7"C#/F-&C@pr-g$s uw@<c!N{ޒ%b{|9O YWO HzvK5&ba9FtQ-Je]𢡄-U{a]P9+7E  AX@%E}ݻCj]#ְH:J-{ ^s)Bm~<ӄx|N]B1TJg~ %H bET&D`mJrmCE&TWUQ!``Ā 9&M{ɛZYtr&'Ցe{,^,J0bƧ f11kR2oN00YyptpUY0 @ކ0 F CFW)NXkUsTDV0i9!pX;SJ65jUN6YmH"R2"iE<=b! @%䐆ik@.4|XBh@>h'CYKš m3h׏ycI:PNð/R0 @$(C$w*'Nh{JF"@fRC0 -"ŠpUS]ZZ֕T֚a[ 32雪6HdSf$i"CTu`;6όAE$!Qzԁ`r* R&(QtEHBJ^ĎLNC\H\q:`%Dw r2IHr67 >zR6a< Jӂ_MJTBGŏ;.Wx|Ch1 (qfn3 p-$>.|%$LI 5< )%7=p,V1. Dx7kӀObM֡x^."y60R[݈;K `jB4@1-,'ŷ!CPFbP/@APHq&$R.y yT W][ 3ʓ,Ptt !@Ji#Dˁ< n\˩?'u \@ĩ" @G_Hc1aCdE`E;CK'@2Aʊ{Cu'W/wK}d6fou=PPsD+zrtPv0 B"B~_Q% ! _*p%ش+bH*&0=` [@ h!(F e'w6F f(_5>o.Tqdg b=2Jsrg.%pnLM]J0È|YWTIKL84 \nny7n4) Ea.0Xp60.RR 10͙j mǘY $sLJ7]CGdRmUZyƅUL=^ Pmt߱eOȏ;3@0$ 8%r.i^Rs @ ,=b E_gGdRӆt (C(WXu^ X+)r$vD. L QU⬸ 6 LB{NlCIɭ@4ϖv:~5@$Dlq\3ٞ {|S$=QЁӀ/Dǘ D[ Ljܠ6.b!$pw +}|1H+ʐߧ3GroNp;GTĪ tTd$"lUAcTT+bb4PƖٚ i,"@ԭX@O/MϨ9rdZYzhDXB%B`</5Cb0Nun *Y-%=|9Qm l(rr'pµ،M4]f i%|E ]B )h>փR+,*C(%誔gj1acz6R|o .4]A Nx.M.jZ;N6p2Z"*#ʲ F.pfa\C@lƐX[4h4m I(7'+V7F|!9vm0$"rQ?lN 0BH-:WJQ*n k0ڴE//."19! !ZFXZ*e*TeБc0}Hu\i"DQSipɒΆހ:D֖ $=ˀJ!`ď9 ]lJe0n!X@6 P:mCSf%ذv%|)J }v钴b: D\`+C(p& >@# )VQJUIFE%FTHP^M+iXiC>& J3P(E@LMOti OٜG缪Hj%q'!d)Vu" #ZqR&#?1)VGEOǂPM@X9'  A `ߏ I|%ݹ)=ǥ!b71)C?';-y$C%,_ |̬($9"%"!Q1z ~8 Xq $ É[>) WDJR.k >(hxˢ5g\Xie>l>\^CpF`LCtrs A@^&*GjR~cB*b Â^pPlĐ!TN^w:; V; > \Zzsm\`&D& ʨ:Fc B]wS`}Q{=8byUvQ 4PX5I>brxHR7ȌzQG:31&d1o-h7.s>4F1zYI!'8@P,&)0!I]H$1$&$bØbaßyu&$)#81L$ [1Wa*:6JQ*d$-"HAaTI2HRJbJAcYL!A,]!"$@% )6IhMVE< زdckIހ`@Q4)؊ Nƪm{h! A#P*H RoS/UCOJRi" } 5!FǏw~v(j ۡpH bf-H:~c,EYô 'k,(2`a06 +1 _ol vNvBζd(!j0s޷1jˌ 썴#0M$y] h26B[| ՘;ǎS*ރj`<BD6X1r4J 9BCȂAYǂ ZxWX_Vcmz@p DAS Vs1`5ۤVh?Hp'I"S oy,P &T/.dY"LEƒl(84vc>n4fCxH ed#qIinV'Q(8^nC7s=0w?'(2$Hbs(.)GR>j,Ӗj7 @Bbc"B "@ ne'8ODz2EQ-* ?1F`VGNxJBYR [x "D")mXvoeZ]&b$L@PQ‘ !RXde00hTL w: "AW"%I-(DP1E2iWPjiЁ9"QsB$]l@\XUܘA$I|.6.n-vDT¨ ,~^)zrt׈iE|F\K$c%ttODwN_]^(d :+痽VDQ"Lʅ)ݙJ fWO UIEGq@j=t+$ );`0ڏ,EN`H,^+TY"'IkvCT 6r"1/Mb*\9GM&ހ3MPru ŋHX [=c#GYyՈm:P@IEC 4J1ṔBI *@cQ$)+` B .C bHJCcZe6,"#N@&&If"ZWPU{" !` Z(A$VTI I@Af#'ƿ2}@:8"HIxH`؈ԠtKI/v PR;t/AP: C$wT-@9L&t\"3DCb0"$ B8~e%THWPb_<gN q;Sq 5kd[ Oq47NC~ o#' K/+=J&F0E{:ɴ%(-:Du<L>pďoЇbd5v~Bx&0wIqPtB 2kǫ Ϧ)0Ϗ,ȳ+`cK#tP1M6`vH]M;):vi\%pI{V ?\-sđ0nF;*dhA<ꐭegڂu6E\J:1?5N%_5GF ?*"֡e$B@Xp"_M'hLi#v(%,o98z \S'u5!bt GԯztƮZE1S@/z B7"~**'/h-|!{ hŃ! GIϲc| מtU^:dp<\I(g/H&#yJmBbw oK')^b]AC ȥIz=gajr FF C  ( EU;V.]de?yUU%x8y!|ָ 1 sJ)șLzzǰ"?dAp( ems0jy<NVUD|;6|P9O p;v!64EaA @8O;쎰5x{xE7L0}g>r!Ӣ]2Hk#FStWq: M؎&ͱ d7ξCAbԆE[93!R䔥)ȑ Ixʙ dW`iېZ@_PP F  j >k;`7m!DMNDǼe|38 qzX>^*GN.?eۅHC~#_yCPg\PL }o!؊Z&NzsD 6h1iQSP)@K$!"SߦC4`0&'.-ĺ]5;*K!O/N>>v)!ܚ>L Z  㟡(1/yUx!Q /..8 ]m=b~SGp}{~)1T\@M.1W? ѩ>`l2'{>gS]&!b$),)RscYae.$$s"S;/ r1WNWjU.K<.RNL[rMзw N#ahENyAK8 ij T,$ C1T #$АJ:qE4Ž' lO8qϢw<$b MZO@<4oDC zVAEG 83=Uq,UI!q4?z^^r]`pEv#/0m 1cvm~<8 >ƄOn(٥iI@N<PYr89B!|p*>:ތW @ R{D_4O!P ĨkBDTF D/0@ũ.#<ݹڠ>߸|JG# @ Cyvr1l]&ye L'Δ)pyX("&"8TJ|k#R* fiTě1 ESw !)Pi@58v,ufqɖi.!Jw8y”J}d<<"PhaϋDIE@(tO#t`!6 8C0>]ʩ#I`?P4#:@ A HLM&$}yC |ckK,/ !=8ĈɊA_ca;:Ch|1_}q`}=čR X0Q)<"~񣜌xAJp?:LSM ia%4l%f~%!BA!Ҩ$E$I !@;#-dbA.)#ڲ!BP) E07L,bad4a!8d9Lf!ba0 ZժXJ`APJ)'RAun)y z(C֟)bld}z|00G:6R ȺkI  a#,kX* BP˱ 8294V.`QhYllmfšD7.!ݚɸ]*Kv~zLA#=]H#iͬ$J, AREՇ`V’{Ȓ$"+ q%9lD&.q;dR:  ~E}) g4\؈i*AjI" /Sޭ!?k*q,UYg~|w]b "ל;5ffɗ"ۛi0 a. vؑijLq2AD&=' {;v UWNYՍ X J@DbYڊ)-sD֗gxShҾbtX!T<'d]9<gQEޑ{wj]8@Xtx^@BJPoI`DXv}Q)Q٤jT5REh LP(4h(d͇u+4 |ה*%ﲸ.Xs7g!MVn-Jp10`lq(GÖd[3 4ASʬbhIoNNI8Q!AF96GR<;LJAa$劺 raT瀧#x0"Pmɕ7&ER> .0 |IʡDANT $"I~85Gi#ڨsX!wj?)Z@eT4<4\@B‰R;*ID%hh,^~53y c0 0ܦ-(7AYHJPKӧ"vLm ,`{Cn5hHBpSLd%Z #GY`h4.ٜ1G !N8 9%Lshw8$I=*|X7Nt$-jn^zZ[PH̒&L^0`x-TY(y/яds00%H(h0M.ʠ, TuF$=$'&X{vښqHD,C^Nf5y5< ң_$N܊^g$!l!rPߛyblQc(iR`8P6&]S.8 {lnhXݬu@)zES,aG/]^8j603> R=O5r /઼.$0#2.;jDd4Bb&jC'oF](]rpʀaG` Ug F$ zY ,u( );@b07``im5 'J3uMVI39'qB )O}9Ct煃-!'EE "" @A Cm*fz^k{ !vWRCv}OHȨ*PDFލ@]Cry M+wnD ?xC0}ōR1&5 J1] CKU$#AT])9.*tZR*n8.(c(.V!<Ȅo!5[,tRmg 9|#0*̩lZ10mu(: bҀ:IDYڨ cq0'" +֔Yq^!.;,~ ,'9բLèUr~㎕G2jk^uMj;fkx[Y%&N* !Fip E +-$XXR2CJs"5!!6=Ak~9  $r8o `Ff8DqxE&Ʀ 4ECbDљe1ccn-qebaԸIYU 6ɡEpyaekAJH@9@U6;]h4 @.`S 9L$}M)Bhg0Ĕ:G3pH͞(5JIْ>;;A#H& !}M(R:ȕr2; Mb^L && 0Jc@Sbk¼NTJ7=d;gb[eʢQ0oW;L<\K* f3T".̂@v4t5eB;'Q1 0Ht1%B!bE`QV5-lPc!Tb6HB<74.mL'W Fs|8h0;mq24hhhᠴ 8Ld`#n2A}0m%CA. i,at  CAA^|("@2Ai9XN`<;L_=VxKn =t HDxEB%6Hq7`WJ!yo'󧗌nI8A@(w 'PDX&M@6QD"CnRa[fz4- N DGqqYf,:a(&^%!ڧl:ؓ71rr&~YfϣZb0uVy1kJ90Cʛ%;׷J5;uq` (3:ˆ$'rLtzqFJ* !6f,i]!4U _UUIUUUUT)otmVLRh0 1!mZi %'cjRy.mnmmytë!ClNhҠNͶiC)+Ll*Xmbpx&TO tw) [ !@!g20'aKt~L"2ķۮv@;|g6gBq)%=uszŤܩZb9@&HU ]J„HtWaVn\OBt(}P}YACP @2@ԫ'  x1LD`ЇxcTiø`|iJ@lCu"\^UDE" We?D|/ՒF)8Ύ́@/~tHvD[' "@Y @ -ƤF+ѰQ؏"N2G;0J穃'*dP%J@z{u}"pd0L1P:'ܐGBbHF}]G]~oaYS@6>h4ÒK YA}`;9$V[ YyM|060w]j{R4rk4#c1Nf1M6f@rIJˑH[%W!&!T)d%t8rwut9lΎj`'MEFBHm3޲ʝi¶ t2.f╝9%\AH| uDX }-ʪ{A E$x05ǂj a H6E( A1p`Gp p ?/҈QJ TD!'%??xQT#043."u!iL"ga˩.S60n*J0x* hTOxMˠz60=즦˨y#2l6@]Ĝ$# B a@HjT]P)%fZzMD2D}8QM/IB'| !Ў YjQ?W5 TH$"@U!7O3#P?p$ֲG6`9in%`n=F]m$x\+y/|T9IS  SE[S!'9XĤ(RNY!ΝNpd"2DH#2 NRE h@d㲪vӌTؙp4lPI׿A,rR\%Q" DȨE?&"""%* j⊹C`v@@( `Dאz4䑠jT2ݚog h4)R{+?ۃ8GR$&̊B\` RA"a|JRIC0;S{Ztbi6O&MF)^U"Ъ?K 9!49AABi \^Fx t§EGQX"z~οl@. D *}aEprBQWʊJX;Rde|Oț%0 QGhqmtA F @[J U"b K02QCĂ0/#Q.$tHcTc*2 `$$% JA ""b)vh0I-0k"6)!4+ail&@$M)zQ]$PEJ;SzhSlc%BQdHA5߰D $i?MKADž$~F %{(tMDPTLʒ!LvA\CY 0@c0rOa~${b? ]HC}٠`!Y("B Ta >W̆K1RD`T 𰱺e(`?@5DpOc鐂%dY@)BeIN(JόJtl꼆 k>P,! o"܂Wp|JP#T%,X @`$Ј6({=>iN:~}p􁿎{N"  (H;@DD~IGU:>;u]u !dH/49ѧoȜL T G@N4)`QAXSR0KIB ؝ )/0.YQ1.IKh5 H4dO Gimr'%_a"@BX8p0 c2E.vY"A6&( 20A=Q-4 , >$,韲7++jag ?td7Cӎ5Ҡ8M4pMR,@΀92NAIz5!>#:|B<]fFC),1EdSD #dYKd(X`$LC~`HrF@bkx L*hՂ#"!N*GgMwPh ?V )V!Cp|uФb Hv!&?Ƅ Fd)/.l,@*:-[qI1ZX9% bG:("!@@~oI@R;E8a TթHǤx%C4D=/q6b?S2"&b YEdH'|3~舀X`7M,P%`M-4HU"$/X "F*yhdiG\~7ucNNJpѮ!d:ܣYF(\m8CM\YU60(>>7K3V1} Xaa?fӀ803Q PBف,"J&Hq$~` E3 B RДU@- BAJHBJ B"J0Al tFN7ɼKm%&|'Q @y9 ZCI{G{OwM=36/,"٣b~ғ)Ĵ WqV$HVtc@DLW pd0 jf%(0V#',G?FU.`A&ԔR~"CXgC(bq\KGSF1~vPakqNPy/"`7O:@_w4R@Kܝݽ8#j$K/)H=z+.i] `?\{2fϲWCJ@X b$`ǁf$' SLdHhu*ArL[M>S9(A>" ~>QXm* * I< _\*0>Y`{pp۹f&OPth׈492ۑfaUO`[iRDE(@VЁ {BEz!nd0pbS:0E=,$QB"HcB ߠvGӡ%OOC ZHdT_=_Xq$QRm "I"뿿MUo; g@B(""G R ! bUbHYa)I!?=]ݪ~i_Le' ~6ĉ%j1r 4!IR) qMfJC`E v 3_N9Wsż}.*7Em,>.AehvɄ#?#9 ;/|"Uo%|;zo.`| ;%D_0>1⯷e]Zr#V)bϚzS1ᖑC#/U0yob6g<ulnfjcQb;@:/߱ m&3b0WdF^;L4b; .$EKآ,4]\e=l5b*x,z"LbjV 9LgZ@K22(c&D%#6aaxq{ld,{pzΓV%tMy.y1t$(e: Ξ0vu҈_Ļ' y̏a> .LĜBД L!P"%$$aiBPGX2K$ _\E,@9J*4,T$A3 BT D%"% 1H WP~&@$b Jd)Gl8@ d E=m@2eQWqP&0~<^SHP2.0{sk( D"d_A@Bh HG, П$ 뜢tc.X&tĮ h%mhe@P_w?Jl#tԘpPЯ8R`mbM)?^,B>FDfdAxXL*C5 j1b&grBuq[5 k ` 9AV ]݀6Eq HB^ǀ ۢ<lgD(.JBs5(bIWxZ8|@:|QrT|#y=1"kq5RF5-Bbs BX?P*/e5 UC%y;6a$ 0Jz4#HzP=M d j0Li4Objh2Lhe 1B(HB@HP$)^J2_h*@R1 ^►$ aP=hӕ {wasF!c{c€Dr\vY-Mi\q*k80*~ Utj{#]PC7< *P%Y?T6Lj($IFXTQAb ´[Q= VB[H'2%H+2{rPPސO)mC;"8{}<1.~ %@/4 p=qёt1EK7 XyqMCak0@RhmB)}o,PP&n"wz)\Q./,U!ς |x`.t\e@{gnJ&Ӡ;B b>R[Ц_$-V'$"'W(d ?o?sz F /Ҫ<ߒ`uH /r XJNL)zh_XQ .jn ESBCDk7i[V\#pAs'4o Dav8;9$(P)B $v!6%9wi5&.4(P!GKP0