From e2f1d5e0e331d3aa2ffe5a807c646bc15b4bac0b Mon Sep 17 00:00:00 2001 From: fredtempez Date: Mon, 5 Apr 2021 08:55:50 +0200 Subject: [PATCH 01/14] gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 3da2b58a..060401b3 100755 --- a/.gitignore +++ b/.gitignore @@ -47,3 +47,4 @@ site/data/en/page.json site/data/de/locale.json site/data/de/module.json site/data/de/page.json +site/data/modules/* \ No newline at end of file From fd8a15812b15e0fe70d76e58a8fd85122307a977 Mon Sep 17 00:00:00 2001 From: fredtempez Date: Mon, 5 Apr 2021 08:57:16 +0200 Subject: [PATCH 02/14] Style perso --- core/core.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/core/core.php b/core/core.php index 3ae75036..7a4a6e42 100755 --- a/core/core.php +++ b/core/core.php @@ -44,7 +44,7 @@ class common { const ACCESS_TIMER = 1800; // Numéro de version - const ZWII_VERSION = '10.5.02'; + const ZWII_VERSION = '10.6.00'; const ZWII_UPDATE_CHANNEL = "v10"; public static $actions = []; @@ -2134,6 +2134,11 @@ class core extends common { 'style' => file_get_contents($stylePath) ]); } + if ($output['style']) { + $this->addOutput([ + 'style' => $this->output['style'] . file_get_contents($output['style']) + ]); + } // JS $scriptPath = $modulePath . 'module/' . $moduleId . '/view/' . $output['view'] . '/' . $output['view'] . '.js.php'; if(file_exists($scriptPath)) { From c2c67b55ffb037096977ea01f3fdc39d6e5f4cf2 Mon Sep 17 00:00:00 2001 From: fredtempez Date: Mon, 5 Apr 2021 08:59:24 +0200 Subject: [PATCH 03/14] Modules de v11 --- module/blog/blog.php | 47 +- module/blog/view/config/config.php | 8 + module/download/download.php | 978 ++++++++++++++++ module/download/ressource/feed-icon-16.gif | Bin 0 -> 652 bytes module/download/vendor/FeedWriter/ATOM.php | 38 + module/download/vendor/FeedWriter/Feed.php | 1017 +++++++++++++++++ .../FeedWriter/InvalidOperationException.php | 33 + module/download/vendor/FeedWriter/Item.php | 413 +++++++ module/download/vendor/FeedWriter/README.md | 42 + module/download/vendor/FeedWriter/RSS1.php | 37 + module/download/vendor/FeedWriter/RSS2.php | 37 + module/download/view/add/add.css | 18 + module/download/view/add/add.js.php | 54 + module/download/view/add/add.php | 139 +++ module/download/view/comment/comment.css | 18 + module/download/view/comment/comment.js.php | 62 + module/download/view/comment/comment.php | 22 + module/download/view/config/config.css | 18 + module/download/view/config/config.js.php | 21 + module/download/view/config/config.php | 60 + module/download/view/edit/edit.css | 18 + module/download/view/edit/edit.js.php | 66 ++ module/download/view/edit/edit.php | 159 +++ module/download/view/index/index.css | 69 ++ module/download/view/item/item.css | 63 + module/download/view/item/item.js.php | 43 + module/download/view/list/list.php | 1 + module/download/view/rss/rss.php | 1 + module/download/view/stats/stats.css | 18 + module/download/view/stats/stats.js.php | 22 + module/download/view/stats/stats.php | 36 + module/gallery/gallery.php | 162 ++- module/gallery/ressource/defaultdata.php | 3 +- module/gallery/view/edit/edit.php | 8 +- module/gallery/view/theme/theme.php | 28 +- module/news/news.php | 151 ++- module/news/view/article/article.css | 20 + module/news/view/config/config.php | 54 +- module/news/view/index/index.css | 42 +- module/news/view/index/index.php | 35 +- module/search/ressource/defaultdata.php | 3 +- module/search/search.php | 150 ++- module/search/view/config/config.php | 10 +- module/search/view/index/index.php | 2 +- 44 files changed, 4061 insertions(+), 165 deletions(-) create mode 100644 module/download/download.php create mode 100644 module/download/ressource/feed-icon-16.gif create mode 100644 module/download/vendor/FeedWriter/ATOM.php create mode 100644 module/download/vendor/FeedWriter/Feed.php create mode 100644 module/download/vendor/FeedWriter/InvalidOperationException.php create mode 100644 module/download/vendor/FeedWriter/Item.php create mode 100644 module/download/vendor/FeedWriter/README.md create mode 100644 module/download/vendor/FeedWriter/RSS1.php create mode 100644 module/download/vendor/FeedWriter/RSS2.php create mode 100644 module/download/view/add/add.css create mode 100644 module/download/view/add/add.js.php create mode 100644 module/download/view/add/add.php create mode 100644 module/download/view/comment/comment.css create mode 100644 module/download/view/comment/comment.js.php create mode 100644 module/download/view/comment/comment.php create mode 100644 module/download/view/config/config.css create mode 100644 module/download/view/config/config.js.php create mode 100644 module/download/view/config/config.php create mode 100644 module/download/view/edit/edit.css create mode 100644 module/download/view/edit/edit.js.php create mode 100644 module/download/view/edit/edit.php create mode 100644 module/download/view/index/index.css create mode 100644 module/download/view/item/item.css create mode 100644 module/download/view/item/item.js.php create mode 100644 module/download/view/list/list.php create mode 100644 module/download/view/rss/rss.php create mode 100644 module/download/view/stats/stats.css create mode 100644 module/download/view/stats/stats.js.php create mode 100644 module/download/view/stats/stats.php create mode 100644 module/news/view/article/article.css diff --git a/module/blog/blog.php b/module/blog/blog.php index 7e2b2b30..a4d68c3d 100755 --- a/module/blog/blog.php +++ b/module/blog/blog.php @@ -15,7 +15,7 @@ class blog extends common { - const VERSION = '4.5'; + const VERSION = '5.0'; const REALNAME = 'Blog'; const DELETE = true; const UPDATE = '0.0'; @@ -75,6 +75,15 @@ class blog extends common { 'right' => 'À droite ', ]; + // Nombre d'objets par page + public static $ItemsList = [ + 4 => '4 articles', + 8 => '8 articles', + 12 => '12 articles', + 16 => '16 articles', + 22 => '22 articles' + ]; + //Paramètre longueur maximale des commentaires en nb de caractères public static $commentLength = [ '500' => '500', @@ -94,7 +103,23 @@ class blog extends common { public static $users = []; - /** + + + /** + * Mise à jour du module + * Appelée par les fonctions index et config + */ + private function update() { + // Version 5.0 + if (version_compare($this->getData(['module', $this->getUrl(0), 'config', 'versionData']), '5.0', '<') ) { + $this->setData(['module', $this->getUrl(0), 'config', 'itemsperPage', 6]); + $this->setData(['module', $this->getUrl(0), 'config', 'versionData','5.0']); + } + } + + + + /** * Flux RSS */ public function rss() { @@ -192,7 +217,7 @@ class blog extends common { 'commentApproved' => $this->getInput('blogAddCommentApproved', helper::FILTER_BOOLEAN), 'commentClose' => $this->getInput('blogAddCommentClose', helper::FILTER_BOOLEAN), 'commentNotification' => $this->getInput('blogAddCommentNotification', helper::FILTER_BOOLEAN), - 'commentGroupNotification' => $this->getInput('blogAddCommentGroupNotification', helper::FILTER_INT) + 'commentGroupNotification' => $this->getInput('blogAddCommentGroupNotification', helper::FILTER_INT), ] ]); // Valeurs en sortie @@ -234,7 +259,7 @@ class blog extends common { // Ids des commentaires par ordre de création $commentIds = array_keys(helper::arrayCollumn($comments, 'createdOn', 'SORT_DESC')); // Pagination - $pagination = helper::pagination($commentIds, $this->getUrl(),$this->getData(['config','itemsperPage'])); + $pagination = helper::pagination($commentIds, $this->getUrl(),$this->getData(['module', $this->getUrl(0), 'config', 'itemsperPage']) ); // Liste des pages self::$pages = $pagination['pages']; // Commentaires en fonction de la pagination @@ -371,11 +396,15 @@ class blog extends common { * Configuration */ public function config() { + // Mise à jour des données de module + $this->update(); // Soumission du formulaire if($this->isPost()) { $this->setData(['module', $this->getUrl(0), 'config',[ 'feeds' => $this->getInput('blogConfigShowFeeds',helper::FILTER_BOOLEAN), - 'feedsLabel' => $this->getInput('blogConfigFeedslabel',helper::FILTER_STRING_SHORT) + 'feedsLabel' => $this->getInput('blogConfigFeedslabel',helper::FILTER_STRING_SHORT), + 'itemsperPage' => $this->getInput('blogConfigItemsperPage', helper::FILTER_INT,true), + 'versionData' => $this->getData(['module', $this->getUrl(0), 'config', 'versionData']) ]]); // Valeurs en sortie $this->addOutput([ @@ -411,7 +440,7 @@ class blog extends common { } $articleIds = $filterData; // Pagination - $pagination = helper::pagination($articleIds, $this->getUrl(),$this->getData(['config','itemsperPage'])); + $pagination = helper::pagination($articleIds, $this->getUrl(),$this->getData(['module', $this->getUrl(0),'config', 'itemsperPage'])); // Liste des pages self::$pages = $pagination['pages']; // Articles en fonction de la pagination @@ -590,6 +619,8 @@ class blog extends common { * Accueil (deux affichages en un pour éviter une url à rallonge) */ public function index() { + // Mise à jour des données de module + $this->update(); // Affichage d'un article if( $this->getUrl(1) @@ -678,7 +709,7 @@ class blog extends common { } $commentIds = array_keys(helper::arrayCollumn($commentsApproved, 'createdOn', 'SORT_DESC')); // Pagination - $pagination = helper::pagination($commentIds, $this->getUrl(),$this->getData(['config','itemsperPage']),'#comment'); + $pagination = helper::pagination($commentIds, $this->getUrl(), $this->getData(['module', $this->getUrl(0),'config', 'itemsperPage']),'#comment'); // Liste des pages self::$pages = $pagination['pages']; // Signature de l'article @@ -725,7 +756,7 @@ class blog extends common { } } // Pagination - $pagination = helper::pagination($articleIds, $this->getUrl(),$this->getData(['config','itemsperPage'])); + $pagination = helper::pagination($articleIds, $this->getUrl(), $this->getData(['module', $this->getUrl(0),'config', 'itemsperPage'])); // Liste des pages self::$pages = $pagination['pages']; // Articles en fonction de la pagination diff --git a/module/blog/view/config/config.php b/module/blog/view/config/config.php index fee5671a..736151c9 100755 --- a/module/blog/view/config/config.php +++ b/module/blog/view/config/config.php @@ -36,6 +36,14 @@ ]); ?> +
+
+ 'Articles par page', + 'selected' => $this->getData(['module', $this->getUrl(0),'config', 'itemsperPage']) + ]); ?> +
+
diff --git a/module/download/download.php b/module/download/download.php new file mode 100644 index 00000000..7dd08a7c --- /dev/null +++ b/module/download/download.php @@ -0,0 +1,978 @@ + + * @copyright Copyright (C) 2008-2018, Rémi Jean + * @license GNU General Public License, version 3 + * @link http://zwiicms.fr/ + */ + +class download extends common { + + const VERSION = '1.2'; + const REALNAME = 'Téléchargement'; + const DELETE = true; + const UPDATE = '0.0'; + const DATADIRECTORY = []; // Contenu localisé inclus par défaut (page.json et module.json) + + // Constantes du module + const EDIT_OWNER = 'owner'; + const EDIT_GROUP = 'group'; + const EDIT_ALL = 'all'; + + public static $actions = [ + 'add' => self::GROUP_MODERATOR, + 'comment' => self::GROUP_MODERATOR, + 'commentApprove' => self::GROUP_MODERATOR, + 'commentDelete' => self::GROUP_MODERATOR, + 'commentDeleteAll' => self::GROUP_MODERATOR, + 'config' => self::GROUP_MODERATOR, + 'delete' => self::GROUP_MODERATOR, + 'edit' => self::GROUP_MODERATOR, + 'stats' => self::GROUP_MODERATOR, + 'statsDeleteAll' => self::GROUP_MODERATOR, + 'index' => self::GROUP_VISITOR, + 'rss' => self::GROUP_VISITOR, + 'downloadFile' => self::GROUP_VISITOR, + 'list' =>self::GROUP_VISITOR + ]; + + public static $items = []; + + // Signature de l'item + public static $itemSignature = ''; + + // Signature du commentaire + public static $editCommentSignature = ''; + + public static $comments = []; + + public static $nbCommentsApproved = 0; + + public static $commentsDelete; + + // Signatures des commentaires déjà saisis + public static $commentsSignature = []; + + public static $pages; + + // Nombre de téléchargements + public static $statSum = 0; + + public static $states = [ + false => 'Brouillon', + true => 'Publié' + ]; + + public static $pictureSizes = [ + '20' => 'Très petite', + '30' => 'Petite', + '40' => 'Grande', + '50' => 'Très Grande', + '100' => 'Pleine largeur', + ]; + + public static $picturePositions = [ + 'left' => 'À gauche', + 'right' => 'À droite ', + ]; + + //Paramètre longueur maximale des commentaires en nb de caractères + public static $commentLength = [ + '500' => '500', + '1000' => '1000', + '2000' => '2000', + '5000' => '5000', + '10000' => '10000' + ]; + + // Nombre d'objets par page + public static $ItemsList = [ + 4 => '4 articles', + 8 => '8 articles', + 12 => '12 articles', + 16 => '16 articles', + 22 => '22 articles' + ]; + + // Permissions d'un item + public static $itemConsent = [ + self::EDIT_ALL => 'Tous les groupes', + self::EDIT_GROUP => 'Groupe du propriétaire', + self::EDIT_OWNER => 'Propriétaire' + ]; + + + public static $itemLicense = [ + 'none'=> 'Non définie', + 'cc' => 'Licence libre Creative Common, partage autorisé', + 'gnu' => 'Licence libre GNU, partage autorisé', + 'mit' => 'Licence libre MIT, partage autorisé', + 'owner' => 'Licence Propriétaire' + ]; + + public static $users = []; + + /** + * Mise à jour du module + * Appelée par les fonctions index et config + */ + private function update() { + // Version 5.0 + if (version_compare($this->getData(['module', $this->getUrl(0), 'config', 'versionData']), '1.1', '<') ) { + $this->setData(['module', $this->getUrl(0), 'config', 'itemsperPage', 6]); + $this->setData(['module', $this->getUrl(0), 'config', 'versionData','1.2']); + } + } + + /** + * Flux RSS + */ + public function rss() { + // Inclure les classes + include_once 'module/news/vendor/FeedWriter/Item.php'; + include_once 'module/news/vendor/FeedWriter/Feed.php'; + include_once 'module/news/vendor/FeedWriter/RSS2.php'; + include_once 'module/news/vendor/FeedWriter/InvalidOperationException.php'; + + date_default_timezone_set('UTC'); + $feeds = new \FeedWriter\RSS2(); + + // En-tête + $feeds->setTitle($this->getData (['page', $this->getUrl(0), 'title'])); + $feeds->setLink(helper::baseUrl() . $this->getUrl(0)); + $feeds->setDescription($this->getData (['page', $this->getUrl(0), 'metaDescription'])); + $feeds->setChannelElement('language', 'fr-FR'); + $feeds->setDate(date('r',time())); + $feeds->addGenerator(); + // Corps des items + $itemIdsPublishedOns = helper::arrayCollumn($this->getData(['module', $this->getUrl(0), 'items']), 'publishedOn', 'SORT_DESC'); + $itemIdsStates = helper::arrayCollumn($this->getData(['module', $this->getUrl(0),'items']), 'state', 'SORT_DESC'); + foreach($itemIdsPublishedOns as $itemId => $itemPublishedOn) { + if($itemPublishedOn <= time() AND $itemIdsStates[$itemId]) { + // Miniature + $parts = explode('/',$this->getData(['module', $this->getUrl(0), 'items', $itemId, 'picture'])); + $thumb = str_replace ($parts[(count($parts)-1)],'mini_' . $parts[(count($parts)-1)], $this->getData(['module', $this->getUrl(0), 'items', $itemId, 'picture'])); + // Créer les items du flux + $newsitem = $feeds->createNewItem(); + // Signature de l'item + $author = $this->signature($this->getData(['module', $this->getUrl(0), 'items', $itemId, 'userId'])); + $newsitem->addElementArray([ + 'title' => $this->getData(['module', $this->getUrl(0), 'items', $itemId, 'title']), + 'link' => helper::baseUrl() .$this->getUrl(0) . '/' . $itemId, + 'description' => '' . $this->getData(['module', $this->getUrl(0), 'items', $itemId, 'title'])
+									 . '' . + $this->getData(['module', $this->getUrl(0), 'items', $itemId, 'content']), + ]); + $newsitem->setAuthor($author,'no@mail.com'); + $newsitem->setId(helper::baseUrl() .$this->getUrl(0) . '/' . $itemId); + $newsitem->setDate(date('r', $this->getData(['module', $this->getUrl(0), 'items', $itemId, 'publishedOn']))); + $imageData = getimagesize(helper::baseUrl(false) . self::FILE_DIR . 'thumb/' . $thumb); + $newsitem->addEnclosure( helper::baseUrl(false) . self::FILE_DIR . 'thumb/' . $thumb, + $imageData[0] * $imageData[1], + $imageData['mime'] + ); + $feeds->addItem($newsitem); + } + } + + // Valeurs en sortie + $this->addOutput([ + 'display' => self::DISPLAY_RSS, + 'content' => $feeds->generateFeed(), + 'view' => 'rss' + ]); + } + + /** + * Édition + */ + public function add() { + // Soumission du formulaire + if($this->isPost()) { + // Modification de l'userId + if($this->getUser('group') === self::GROUP_ADMIN){ + $newuserid = $this->getInput('downloadAddUserId', helper::FILTER_STRING_SHORT, true); + } + else{ + $newuserid = $this->getUser('id'); + } + // Incrémente l'id de l'item + $itemId = helper::increment($this->getInput('downloadAddTitle', helper::FILTER_ID), $this->getData(['page'])); + $itemId = helper::increment($itemId, (array) $this->getData(['module', $this->getUrl(0)])); + $itemId = helper::increment($itemId, array_keys(self::$actions)); + // Crée l'item + $this->setData(['module', + $this->getUrl(0), + 'items', + $itemId, [ + 'comment' => $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'comment']), + 'content' => $this->getInput('downloadAddContent', null), + 'picture' => $this->getInput('downloadAddPicture', helper::FILTER_STRING_SHORT, true), + 'file' => $this->getInput('downloadAddFile', helper::FILTER_STRING_SHORT, true), + 'fileVersion' => $this->getInput('downloadAddFileVersion', helper::FILTER_STRING_SHORT, true), + 'fileDate' => $this->getInput('downloadAddFileDate', helper::FILTER_DATETIME, true), + 'fileLicense' => $this->getInput('downloadAddFileLicense', helper::FILTER_STRING_SHORT, true), + 'fileAuthor' => $this->getInput('downloadAddFileAuthor', helper::FILTER_STRING_SHORT, true), + 'fileStats' => [], + 'publishedOn' => $this->getInput('downloadAddPublishedOn', helper::FILTER_DATETIME, true), + 'state' => $this->getInput('downloadAddState', helper::FILTER_BOOLEAN), + 'title' => $this->getInput('downloadAddTitle', helper::FILTER_STRING_SHORT, true), + 'userId' => $newuserid, + 'editConsent' => $this->getInput('downloadAddConsent') === self::EDIT_GROUP ? $this->getUser('group') : $this->getInput('downloadAddConsent'), + 'commentMaxlength' => $this->getInput('downloadAddCommentMaxlength'), + 'commentApproved' => $this->getInput('downloadAddCommentApproved', helper::FILTER_BOOLEAN), + 'commentClose' => $this->getInput('downloadAddCommentClose', helper::FILTER_BOOLEAN), + 'commentNotification' => $this->getInput('downloadAddCommentNotification', helper::FILTER_BOOLEAN), + 'commentGroupNotification' => $this->getInput('downloadAddCommentGroupNotification', helper::FILTER_INT) + ] + ]); + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/config', + 'notification' => 'Nouvel item créé', + 'state' => true + ]); + } + // Liste des utilisateurs + self::$users = helper::arrayCollumn($this->getData(['user']), 'firstname'); + ksort(self::$users); + foreach(self::$users as $userId => &$userFirstname) { + $userFirstname = $userFirstname . ' ' . $this->getData(['user', $userId, 'lastname']); + } + unset($userFirstname); + // Valeurs en sortie + $this->addOutput([ + 'title' => 'Nouvel item', + 'vendor' => [ + 'flatpickr', + 'tinymce' + ], + 'view' => 'add' + ]); + } + + /** + * Liste des commentaires + */ + public function comment() { + $comments = $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2),'comment']); + self::$commentsDelete = template::button('downloadCommentDeleteAll', [ + 'class' => 'downloadCommentDeleteAll buttonRed', + 'href' => helper::baseUrl() . $this->getUrl(0) . '/commentDeleteAll/' . $this->getUrl(2).'/' . $_SESSION['csrf'] , + 'ico' => 'cancel', + 'value' => 'Tout effacer' + ]); + // Ids des commentaires par ordre de création + $commentIds = array_keys(helper::arrayCollumn($comments, 'createdOn', 'SORT_DESC')); + // Pagination + $pagination = helper::pagination($commentIds, $this->getUrl(), $this->getData(['module', $this->getUrl(0),'config', 'itemsperPage'])); + // Liste des pages + self::$pages = $pagination['pages']; + // Commentaires en fonction de la pagination + for($i = $pagination['first']; $i < $pagination['last']; $i++) { + // Met en forme le tableau + $comment = $comments[$commentIds[$i]]; + // Bouton d'approbation + $buttonApproval = ''; + // Compatibilité avec les commentaires des versions précédentes, les valider + $comment['approval'] = array_key_exists('approval', $comment) === false ? true : $comment['approval'] ; + if ( $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2),'commentApproved']) === true) { + $buttonApproval = template::button('downloadCommentApproved' . $commentIds[$i], [ + 'class' => $comment['approval'] === true ? 'downloadCommentRejected buttonGreen' : 'downloadCommentApproved buttonRed' , + 'href' => helper::baseUrl() . $this->getUrl(0) . '/commentApprove/' . $this->getUrl(2) . '/' . $commentIds[$i] . '/' . $_SESSION['csrf'] , + 'value' => $comment['approval'] === true ? 'A' : 'R' + ]); + } + self::$comments[] = [ + mb_detect_encoding(strftime('%d %B %Y - %H:%M', $comment['createdOn']), 'UTF-8', true) + ? strftime('%d %B %Y - %H:%M', $comment['createdOn']) + : utf8_encode(strftime('%d %B %Y - %H:%M', $comment['createdOn'])), + $comment['content'], + $comment['userId'] ? $this->getData(['user', $comment['userId'], 'firstname']) . ' ' . $this->getData(['user', $comment['userId'], 'lastname']) : $comment['author'], + $buttonApproval, + template::button('downloadCommentDelete' . $commentIds[$i], [ + 'class' => 'downloadCommentDelete buttonRed', + 'href' => helper::baseUrl() . $this->getUrl(0) . '/commentDelete/' . $this->getUrl(2) . '/' . $commentIds[$i] . '/' . $_SESSION['csrf'] , + 'value' => template::ico('cancel') + ]) + ]; + } + // Valeurs en sortie + $this->addOutput([ + 'title' => 'Gestion des commentaires : '. $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'title']), + 'view' => 'comment' + ]); + } + + /** + * Suppression de commentaire + */ + public function commentDelete() { + // Le commentaire n'existe pas + if($this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'comment', $this->getUrl(3)]) === null) { + // Valeurs en sortie + $this->addOutput([ + 'access' => false + ]); + } + // Jeton incorrect + elseif ($this->getUrl(4) !== $_SESSION['csrf']) { + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/config', + 'notification' => 'Action non autorisée' + ]); + } + // Suppression + else { + $this->deleteData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'comment', $this->getUrl(3)]); + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/comment/'.$this->getUrl(2), + 'notification' => 'Commentaire supprimé', + 'state' => true + ]); + } + } + + /** + * Suppression de tous les commentaires de l'item $this->getUrl(2) + */ + public function commentDeleteAll() { + // Jeton incorrect + if ($this->getUrl(3) !== $_SESSION['csrf']) { + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/config', + 'notification' => 'Action non autorisée' + ]); + } + // Suppression + else { + $this->setData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'comment',[] ]); + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/comment', + 'notification' => 'Commentaires supprimés', + 'state' => true + ]); + } + } + + /** + * Approbation oou désapprobation de commentaire + */ + public function commentApprove() { + // Le commentaire n'existe pas + if($this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'comment', $this->getUrl(3)]) === null) { + // Valeurs en sortie + $this->addOutput([ + 'access' => false + ]); + } + // Jeton incorrect + elseif ($this->getUrl(4) !== $_SESSION['csrf']) { + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/config', + 'notification' => 'Action non autorisée' + ]); + } + // Inversion du statut + else { + $approved = !$this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'comment', $this->getUrl(3), 'approval']) ; + $this->setData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'comment', $this->getUrl(3), [ + 'author' => $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'comment', $this->getUrl(3), 'author']), + 'content' => $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'comment', $this->getUrl(3), 'content']), + 'createdOn' => $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'comment', $this->getUrl(3), 'createdOn']), + 'userId' => $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'comment', $this->getUrl(3), 'userId']), + 'approval' => $approved + ]]); + + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/comment/'.$this->getUrl(2), + 'notification' => $approved ? 'Commentaire approuvé' : 'Commentaire rejeté', + 'state' => $approved + ]); + } + } + + /** + * Configuration + */ + public function config() { + // Mise à jour des données de module + $this->update(); + // Soumission du formulaire + if($this->isPost()) { + $this->setData(['module', $this->getUrl(0), 'config',[ + 'feeds' => $this->getInput('downloadConfigShowFeeds',helper::FILTER_BOOLEAN), + 'feedsLabel' => $this->getInput('downloadConfigFeedslabel',helper::FILTER_STRING_SHORT), + 'itemsperPage' => $this->getInput('blogConfigItemsperPage', helper::FILTER_INT,true), + 'versionData' => $this->getData(['module', $this->getUrl(0), 'config', 'versionData']) + ]]); + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/config', + 'notification' => 'Modifications enregistrées', + 'state' => true + ]); + } else { + // Ids des items par ordre de publication + $itemIds = array_keys(helper::arrayCollumn($this->getData(['module', $this->getUrl(0), 'items']), 'publishedOn', 'SORT_DESC')); + // Gestion des droits d'accès + $filterData=[]; + foreach ($itemIds as $key => $value) { + if ( + ( // Propriétaire + $this->getData(['module', $this->getUrl(0), 'items', $value,'editConsent']) === self::EDIT_OWNER + AND ( $this->getData(['module', $this->getUrl(0), 'items', $value,'userId']) === $this->getUser('id') + OR $this->getUser('group') === self::GROUP_ADMIN ) + ) + + OR ( + // Groupe + $this->getData(['module', $this->getUrl(0), 'items', $value,'editConsent']) !== self::EDIT_OWNER + AND $this->getUser('group') >= $this->getData(['module',$this->getUrl(0), 'items', $value,'editConsent']) + ) + OR ( + // Tout le monde + $this->getData(['module', $this->getUrl(0), 'items', $value,'editConsent']) === self::EDIT_ALL + ) + ) { + $filterData[] = $value; + } + } + $itemIds = $filterData; + // Pagination + $pagination = helper::pagination($itemIds, $this->getUrl(), $this->getData(['module', $this->getUrl(0),'config', 'itemsperPage'])); + // Liste des pages + self::$pages = $pagination['pages']; + // items en fonction de la pagination + for($i = $pagination['first']; $i < $pagination['last']; $i++) { + // Nombre de commentaires à approuver et approuvés + $approvals = helper::arrayCollumn($this->getData(['module', $this->getUrl(0), 'items', $itemIds[$i], 'comment' ]),'approval', 'SORT_DESC'); + if ( is_array($approvals) ) { + $a = array_values($approvals); + $toApprove = count(array_keys($a,false)); + $approved = count(array_keys($a,true)); + } else { + $toApprove = 0; + $approved = count($this->getData(['module', $this->getUrl(0), 'items', $itemIds[$i],'comment'])); + } + // Met en forme le tableau + $date = mb_detect_encoding(strftime('%d %B %Y', $this->getData(['module', $this->getUrl(0), 'items', $itemIds[$i], 'fileDate'])), 'UTF-8', true) + ? strftime('%d %B %Y', $this->getData(['module', $this->getUrl(0), 'items', $itemIds[$i], 'fileDate'])) + : utf8_encode(strftime('%d %B %Y', $this->getData(['module', $this->getUrl(0), 'items', $itemIds[$i], 'fileDate']))); + $heure = mb_detect_encoding(strftime('%H:%M', $this->getData(['module', $this->getUrl(0), 'items', $itemIds[$i], 'fileDate'])), 'UTF-8', true) + ? strftime('%H:%M', $this->getData(['module', $this->getUrl(0), 'items', $itemIds[$i], 'fileDate'])) + : utf8_encode(strftime('%H:%M', $this->getData(['module', $this->getUrl(0), 'items', $itemIds[$i], 'fileDate']))); + $stat = count(helper::arrayCollumn($this->getData(['module', $this->getUrl(0), 'items', $itemIds[$i],'fileStats']), 'time') ) === 0 + ? '0' + : '' . + count(helper::arrayCollumn($this->getData(['module', $this->getUrl(0), 'items', $itemIds[$i],'fileStats']), 'time') ) . + ''; + self::$items[] = [ + '' . + $this->getData(['module', $this->getUrl(0), 'items', $itemIds[$i], 'title']) . + '', + $this->getData(['module', $this->getUrl(0), 'items', $itemIds[$i], 'fileVersion']), + $date .' à '. $heure, + $stat, + self::$states[$this->getData(['module', $this->getUrl(0), 'items', $itemIds[$i], 'state'])], + // Bouton pour afficher les commentaires de l'item + template::button('downloadConfigComment' . $itemIds[$i], [ + 'class' => ($toApprove || $approved ) > 0 ? 'buttonBlue' : 'buttonGrey' , + 'href' => ($toApprove || $approved ) > 0 ? helper::baseUrl() . $this->getUrl(0) . '/comment/' . $itemIds[$i] : '', + 'value' => $toApprove > 0 ? $toApprove . '/' . $approved : $approved + ]), + template::button('downloadConfigEdit' . $itemIds[$i], [ + 'href' => helper::baseUrl() . $this->getUrl(0) . '/edit/' . $itemIds[$i] . '/' . $_SESSION['csrf'], + 'value' => template::ico('pencil') + ]), + template::button('downloadConfigDelete' . $itemIds[$i], [ + 'class' => 'downloadConfigDelete buttonRed', + 'href' => helper::baseUrl() . $this->getUrl(0) . '/delete/' . $itemIds[$i] . '/' . $_SESSION['csrf'], + 'value' => template::ico('cancel') + ]) + ]; + } + // Valeurs en sortie + $this->addOutput([ + 'title' => 'Configuration du module', + 'view' => 'config' + ]); + } + } + + /** + * Suppression + */ + public function delete() { + if($this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2)]) === null) { + // Valeurs en sortie + $this->addOutput([ + 'access' => false + ]); + } + // Jeton incorrect + elseif ($this->getUrl(3) !== $_SESSION['csrf']) { + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/config', + 'notification' => 'Action non autorisée' + ]); + } + // Suppression + else { + $this->deleteData(['module', $this->getUrl(0), 'items', $this->getUrl(2)]); + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/config', + 'notification' => 'Item supprimé', + 'state' => true + ]); + } + } + + /** + * Édition + */ + public function edit() { + // Jeton incorrect + if ($this->getUrl(3) !== $_SESSION['csrf']) { + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/config', + 'notification' => 'Action non autorisée' + ]); + } + // L'item n'existe pas + if($this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2)]) === null) { + // Valeurs en sortie + $this->addOutput([ + 'access' => false + ]); + } + // L'item existe + else { + // Soumission du formulaire + if($this->isPost()) { + if($this->getUser('group') === self::GROUP_ADMIN){ + $newuserid = $this->getInput('downloadEditUserId', helper::FILTER_STRING_SHORT, true); + } + else{ + $newuserid = $this->getUser('id'); + } + $itemId = $this->getInput('downloadEditTitle', helper::FILTER_ID, true); + // Incrémente le nouvel id de l'item + if($itemId !== $this->getUrl(2)) { + $itemId = helper::increment($itemId, $this->getData(['page'])); + $itemId = helper::increment($itemId, $this->getData(['module', $this->getUrl(0),'items'])); + $itemId = helper::increment($itemId, array_keys(self::$actions)); + } + $this->setData(['module', + $this->getUrl(0), + 'items', + $itemId, [ + 'comment' => $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'comment']), + 'content' => $this->getInput('downloadEditContent', null), + 'picture' => $this->getInput('downloadEditPicture', helper::FILTER_STRING_SHORT, true), + 'file' => $this->getInput('downloadEditFile', helper::FILTER_STRING_SHORT, true), + 'fileVersion' => $this->getInput('downloadEditFileVersion', helper::FILTER_STRING_SHORT, true), + 'fileDate' => $this->getInput('downloadEditFileDate', helper::FILTER_DATETIME, true), + 'fileStats' => $this->getData(['module',$this->getUrl(0), 'items', $this->getUrl(2), 'fileStats']), + 'fileLicense' => $this->getInput('downloadEditFileLicense', helper::FILTER_STRING_SHORT, true), + 'fileAuthor' => $this->getInput('downloadEditFileAuthor', helper::FILTER_STRING_SHORT, true), + 'publishedOn' => $this->getInput('downloadEditPublishedOn', helper::FILTER_DATETIME, true), + 'state' => $this->getInput('downloadEditState', helper::FILTER_BOOLEAN), + 'title' => $this->getInput('downloadEditTitle', helper::FILTER_STRING_SHORT, true), + 'userId' => $newuserid, + 'editConsent' => $this->getInput('downloadEditConsent') === self::EDIT_GROUP ? $this->getUser('group') : $this->getInput('downloadEditConsent'), + 'commentMaxlength' => $this->getInput('downloadEditCommentMaxlength'), + 'commentApproved' => $this->getInput('downloadEditCommentApproved', helper::FILTER_BOOLEAN), + 'commentClose' => $this->getInput('downloadEditCommentClose', helper::FILTER_BOOLEAN), + 'commentNotification' => $this->getInput('downloadEditCommentNotification', helper::FILTER_BOOLEAN), + 'commentGroupNotification' => $this->getInput('downloadEditCommentGroupNotification', helper::FILTER_INT) + ] + ]); + // Supprime l'ancien item + if($itemId !== $this->getUrl(2)) { + $this->deleteData(['module', $this->getUrl(0), 'items', $this->getUrl(2)]); + } + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/config', + 'notification' => 'Modifications enregistrées', + 'state' => true + ]); + } + // Liste des utilisateurs + self::$users = helper::arrayCollumn($this->getData(['user']), 'firstname'); + ksort(self::$users); + foreach(self::$users as $userId => &$userFirstname) { + // Les membres ne sont pas éditeurs, les exclure de la liste + if ( $this->getData(['user', $userId, 'group']) < self::GROUP_MODERATOR) { + unset(self::$users[$userId]); + } + $userFirstname = $userFirstname . ' ' . $this->getData(['user', $userId, 'lastname']) . ' (' . self::$groupEdits[$this->getData(['user', $userId, 'group'])] . ')'; + } + unset($userFirstname); + // Valeurs en sortie + $this->addOutput([ + 'title' => $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'title']), + 'vendor' => [ + 'flatpickr', + 'tinymce' + ], + 'view' => 'edit' + ]); + } + } + + /** + * Accueil (deux affichages en un pour éviter une url à rallonge) + */ + public function index() { + // Mise à jour des données de module + $this->update(); + // Affichage d'un item + if( + $this->getUrl(1) + // Protection pour la pagination, un ID ne peut pas être un entier, une page oui + AND intval($this->getUrl(1)) === 0 + ) { + // L'item n'existe pas + if($this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(1)]) === null) { + // Valeurs en sortie + $this->addOutput([ + 'access' => false + ]); + } + // L'item existe + else { + // Soumission du formulaire + if($this->isPost()) { + // Check la captcha + if( + $this->getUser('password') !== $this->getInput('ZWII_USER_PASSWORD') + //AND $this->getInput('downloaditemcaptcha', helper::FILTER_INT) !== $this->getInput('downloaditemcaptchaFirstNumber', helper::FILTER_INT) + $this->getInput('downloaditemcaptchaSecondNumber', helper::FILTER_INT)) + AND password_verify($this->getInput('downloadItemCaptcha', helper::FILTER_INT), $this->getInput('downloadItemCaptchaResult') ) === false ) + { + self::$inputNotices['downloadItemCaptcha'] = 'Incorrect'; + } + // Crée le commentaire + $commentId = helper::increment(uniqid(), $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(1), 'comment'])); + $content = $this->getInput('downloadItemContent', false); + $this->setData(['module', $this->getUrl(0), 'items', $this->getUrl(1), 'comment', $commentId, [ + 'author' => $this->getInput('downloadItemAuthor', helper::FILTER_STRING_SHORT, empty($this->getInput('downloadItemUserId')) ? TRUE : FALSE), + 'content' => $content, + 'createdOn' => time(), + 'userId' => $this->getInput('downloadItemUserId'), + 'approval' => !$this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(1), 'commentApproved']) // true commentaire publié false en attente de publication + ]]); + // Envoi d'une notification aux administrateurs + // Init tableau + $to = []; + // Liste des destinataires + foreach($this->getData(['user']) as $userId => $user) { + if ($user['group'] >= $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(1), 'commentGroupNotification']) ) { + $to[] = $user['mail']; + $firstname[] = $user['firstname']; + $lastname[] = $user['lastname']; + } + } + // Envoi du mail $sent code d'erreur ou de réussite + $notification = $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(1), 'commentApproved']) === true ? 'Commentaire déposé en attente d\'approbation': 'Commentaire déposé'; + if ($this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(1), 'commentNotification']) === true) { + $error = 0; + foreach($to as $key => $adress){ + $sent = $this->sendMail( + $adress, + 'Nouveau commentaire déposé', + 'Bonjour' . ' ' . $firstname[$key] . ' ' . $lastname[$key] . ',

' . + 'L\'item ' . $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(1), 'title']) . ' a reçu un nouveau commentaire.

', + '' + ); + if( $sent === false) $error++; + } + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl() . '#comment', + 'notification' => ($error === 0 ? $notification . '
Une notification a été envoyée.' : $notification . '
Erreur de notification : ' . $sent), + 'state' => ($sent === true ? true : null) + ]); + + } else { + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl() . '#comment', + 'notification' => $notification, + 'state' => true + ]); + } + + } + // Ids des commentaires approuvés par ordre de publication + $commentsApproved = $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(1), 'comment']); + if ($commentsApproved) { + foreach( $commentsApproved as $key => $value){ + if($value['approval']===false) unset($commentsApproved[$key]); + } + // Ligne suivante si affichage du nombre total de commentaires approuvés sous l'item + self::$nbCommentsApproved = count($commentsApproved); + } + $commentIds = array_keys(helper::arrayCollumn($commentsApproved, 'createdOn', 'SORT_DESC')); + // Pagination + $pagination = helper::pagination($commentIds, $this->getUrl(), $this->getData(['module', $this->getUrl(0),'config', 'itemsperPage']),'#comment'); + // Nombre de téléchargements + self::$statSum = count(helper::arrayCollumn($this->getData(['module', $this->getUrl(0), 'items',$this->getUrl(1),'fileStats']), 'time') ) === 0 + ? '0' + : count(helper::arrayCollumn($this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(1),'fileStats']), 'time') ) ; + // Liste des pages + self::$pages = $pagination['pages']; + // Signature de l'item + self::$itemSignature = $this->signature($this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(1), 'userId'])); + // Signature du commentaire édité + if($this->getUser('password') === $this->getInput('ZWII_USER_PASSWORD')) { + self::$editCommentSignature = $this->signature($this->getUser('id')); + } + // Commentaires en fonction de la pagination + for($i = $pagination['first']; $i < $pagination['last']; $i++) { + // Signatures des commentaires + $e = $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(1), 'comment', $commentIds[$i],'userId']); + if ($e) { + self::$commentsSignature[$commentIds[$i]] = $this->signature($e); + } else { + self::$commentsSignature[$commentIds[$i]] = $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(1), 'comment', $commentIds[$i],'author']); + } + // Données du commentaire si approuvé + if ($this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(1), 'comment', $commentIds[$i],'approval']) === true ) { + self::$comments[$commentIds[$i]] = $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(1), 'comment', $commentIds[$i]]); + } + } + // Valeurs en sortie + $this->addOutput([ + 'showBarEditButton' => true, + 'title' => $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(1), 'title']), + 'vendor' => [ + 'tinymce' + ], + 'view' => 'item' + ]); + } + + } + // Liste des items + else { + // Ids des items par ordre de publication + $itemIdsPublishedOns = helper::arrayCollumn($this->getData(['module', $this->getUrl(0),'items']), 'publishedOn', 'SORT_DESC'); + $itemIdsStates = helper::arrayCollumn($this->getData(['module', $this->getUrl(0), 'items']), 'state', 'SORT_DESC'); + $itemIds = []; + foreach($itemIdsPublishedOns as $itemId => $itemPublishedOn) { + if($itemPublishedOn <= time() AND $itemIdsStates[$itemId]) { + $itemIds[] = $itemId; + } + } + // Pagination + $pagination = helper::pagination($itemIds, $this->getUrl(), $this->getData(['module', $this->getUrl(0),'config', 'itemsperPage'])); + // Liste des pages + self::$pages = $pagination['pages']; + // Items en fonction de la pagination + for($i = $pagination['first']; $i < $pagination['last']; $i++) { + self::$items[$itemIds[$i]] = $this->getData(['module', $this->getUrl(0), 'items', $itemIds[$i]]); + } + // Valeurs en sortie + $this->addOutput([ + 'showBarEditButton' => true, + 'showPageContent' => true, + 'view' => 'index' + ]); + } + } + + /** + * Retourne la signature d'un utilisateur + */ + private function signature($userId) { + switch ($this->getData(['user', $userId, 'signature'])){ + case 1: + return $userId; + break; + case 2: + return $this->getData(['user', $userId, 'pseudo']); + break; + case 3: + return $this->getData(['user', $userId, 'firstname']) . ' ' . $this->getData(['user', $userId, 'lastname']); + break; + case 4: + return $this->getData(['user', $userId, 'lastname']) . ' ' . $this->getData(['user', $userId, 'firstname']); + break; + default: + return $this->getData(['user', $userId, 'firstname']); + } + } + + /** + * Initie un téléchargement protégé + */ + public function downloadFile() { + + if($this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2)]) === null) { + // Valeurs en sortie + $this->addOutput([ + 'access' => false + ]); + } + // Jeton incorrect + elseif ($this->getUrl(3) !== $_SESSION['csrf']) { + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0), + 'notification' => 'Action non autorisée' + ]); + } + // Téléchargement + else { + $filePath = self::FILE_DIR . 'source/' . $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'file']); + $fileName = $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'file']); + if (file_exists($filePath)) { + // Statistiques de téléchargement + $statId = helper::increment(uniqid(), $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'fileStats'])); + $this->setData(['module', + $this->getUrl(0), + 'items', + $this->getUrl(2), + 'fileStats', + $statId, [ + 'time' => time(), + 'ip' => helper::getIp() + ]]); + // Formatage http + header('Content-Type: application/octet-stream'); + header('Content-Disposition: attachment; filename="' . $fileName . '"'); + header('Content-Length: ' . filesize($filePath)); + readfile( $filePath); + // Valeurs en sortie + $this->addOutput([ + 'display' => self::DISPLAY_RAW + ]); + // Valeurs en sortie + $this->addOutput([ + 'title' => 'Configuration', + 'view' => 'index' + ]); + } else { + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0), + 'notification' => 'Le fichier n\'existe pas', + 'state' => false + ]); + } + } + } + + /** + * Ecran de consultation des données statistiques + */ + + public function stats() { + + // Construction de la page des statistiques + $itemIds = array_keys($this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'fileStats'])); + // Total des téléchargements + self::$statSum = count ($itemIds); + // Pagination + $pagination = helper::pagination($itemIds, $this->getUrl(), $this->getData(['module', $this->getUrl(0),'config', 'itemsperPage'])); + + // Liste des pages + self::$pages = $pagination['pages']; + + for($i = $pagination['first']; $i < $pagination['last']; $i++) { + + // Format des variables + $date = mb_detect_encoding(strftime('%d %B %Y - %H:%M', $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'fileStats', $itemIds[$i], 'time'])), 'UTF-8', true) + ? strftime('%d %B %Y - %H:%M',$this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'fileStats', $itemIds[$i], 'time'])) + : utf8_encode(strftime('%d %B %Y - %H:%M', $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'fileStats', $itemIds[$i], 'time']))); + + // Met en forme le tableau + self::$items[] = [ + $date, + $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'fileStats', $itemIds[$i], 'ip']) + ]; + + } + $this->addOutput([ + 'title' => 'Statistiques de téléchargement', + 'view' => 'stats' + ]); + } + + public function statsDeleteAll() { + // Validité de la page demandée + if($this->getData(['module', $this->getUrl(0), 'items']) === null) { + // Valeurs en sortie + $this->addOutput([ + 'access' => false + ]); + } + // Jeton incorrect + elseif ($this->getUrl(3) !== $_SESSION['csrf']) { + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0), + 'notification' => 'Action non autorisée' + ]); + } + // Téléchargement + else { + $this->setData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'fileStats', [] ]); + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/stats/' . $this->getUrl(2), + 'notification' => 'Purge des statistiques', + 'state' => true + ]); + } + } + + /*** + * Retourne une chaîne json contenant la liste des téléchargements disponibles + */ + public function list() { + $itemIdsPublishedOns = helper::arrayCollumn($this->getData(['module', $this->getUrl(0),'items']), 'publishedOn', 'SORT_DESC'); + $itemIdsStates = helper::arrayCollumn($this->getData(['module', $this->getUrl(0), 'items']), 'state', 'SORT_DESC'); + $itemIds = []; + foreach($itemIdsPublishedOns as $itemId => $itemPublishedOn) { + if($itemPublishedOn <= time() AND $itemIdsStates[$itemId]) { + $itemIds[] = $itemId; + } + } + foreach ($itemIds as $key) { + self::$items[$key] = [ + 'title' => $this->getData(['module', $this->getUrl(0), 'items', $key, 'title']), + 'content' => $this->getData(['module', $this->getUrl(0), 'items', $key, 'content']), + 'picture' => $this->getData(['module', $this->getUrl(0), 'items', $key, 'picture']), + 'file' =>$this->getData(['module', $this->getUrl(0), 'items', $key, 'file']), + 'fileVersion' => $this->getData(['module', $this->getUrl(0), 'items', $key, 'fileVersion']), + 'fileDate' =>$this->getData(['module', $this->getUrl(0), 'items', $key, 'fileDate']), + 'fileAuthor' =>$this->getData(['module', $this->getUrl(0), 'items', $key, 'fileAuthor']), + 'fileLicense' =>$this->getData(['module', $this->getUrl(0), 'items', $key, 'fileLicense']), + ]; + } + $this->addOutput([ + 'display' => self::DISPLAY_JSON, + 'content' => self::$items + ]); + } +} \ No newline at end of file diff --git a/module/download/ressource/feed-icon-16.gif b/module/download/ressource/feed-icon-16.gif new file mode 100644 index 0000000000000000000000000000000000000000..26fa274454d016fdafa1b371e6d172030b61ac7d GIT binary patch literal 652 zcmZ?wbhEHb6krfwI9AB;Wun>ZdZS-+EPv0n`Z3e;&({zCe|~<~YVxAe@L9d_w<+eI zdQG2|=)Y_={m^OhuGRS8k57;D^!|N%b}LTnd4>L)F0+RfhHn~;9%Sjhsx^FEY4o_# z@aJ5|7tJR3Qg!}*e0DEi|9+vtokZ=wx3)ekF?ii+`l8kJ-}g^XOY|O<89r|`zE@!I zw8rQ~lgXb$Ew9>5@8;=0sWy6AYxJ_i?AMyOU+0$pSfBZBqR*FQ>F;Kx{5&!HWu4`h zy)%Byb9vwE_-=LQzc;sjE)9COY3j%A(|_+Qe^BcBc}e>FxhY@P6#u!o_50e)zxNOR z`}pkB;X?tj(k`Srkzulr~IeR}rieAnO4Zv4Ey|51V2uYJwG*T+4nasRbB>(}MY z-=|yroMriSlKIDO(^nhX|C0g~f3h%gG1N2YFaQB4P8irutD!|K07BTzlA_-oNcc1hVb)@I$C@&8w%Mnm^}*x>=-$uWM@XE3q3K( z+n30}qshBGH{_PjB8AT4CPx+_eKXyakCM*VXfpa8x!9!W!fBS3&{_Cd#ZQtY`q7^c z42zs*YqCAMQjx5}C&}jgh(nMu*=?1A*RH1rgcN%xD+z}kc=+HAgLSinO~;G`HX#{d V-YAuXg^H}50tyKne}y?1tN}38S(N|) literal 0 HcmV?d00001 diff --git a/module/download/vendor/FeedWriter/ATOM.php b/module/download/vendor/FeedWriter/ATOM.php new file mode 100644 index 00000000..28494501 --- /dev/null +++ b/module/download/vendor/FeedWriter/ATOM.php @@ -0,0 +1,38 @@ + + * + * This file is part of the "Universal Feed Writer" project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * Wrapper for creating ATOM feeds + * + * @package UniversalFeedWriter + */ +class ATOM extends Feed +{ + /** + * {@inheritdoc} + */ + public function __construct() + { + parent::__construct(Feed::ATOM); + } + +} diff --git a/module/download/vendor/FeedWriter/Feed.php b/module/download/vendor/FeedWriter/Feed.php new file mode 100644 index 00000000..d33a2059 --- /dev/null +++ b/module/download/vendor/FeedWriter/Feed.php @@ -0,0 +1,1017 @@ + + * Copyright (C) 2010-2016 Michael Bemmerl + * + * This file is part of the "Universal Feed Writer" project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * Universal Feed Writer class + * + * Generate RSS 1.0, RSS2.0 and ATOM Feeds + * + * @package UniversalFeedWriter + * @author Anis uddin Ahmad + * @link http://www.ajaxray.com/projects/rss + */ +abstract class Feed +{ + // RSS 0.90 Officially obsoleted by 1.0 + // RSS 0.91, 0.92, 0.93 and 0.94 Officially obsoleted by 2.0 + // So, define constants for RSS 1.0, RSS 2.0 and ATOM + + const RSS1 = 'RSS 1.0'; + const RSS2 = 'RSS 2.0'; + const ATOM = 'ATOM'; + + const VERSION = '1.1.0'; + + /** + * Collection of all channel elements + */ + private $channels = array(); + + /** + * Collection of items as object of \FeedWriter\Item class. + */ + private $items = array(); + + /** + * Collection of other version wise data. + * + * Currently used to store the 'rdf:about' attribute and image element of the channel (both RSS1 only). + */ + private $data = array(); + + /** + * The tag names which have to encoded as CDATA + */ + private $CDATAEncoding = array(); + + /** + * Collection of XML namespaces + */ + private $namespaces = array(); + + /** + * Contains the format of this feed. + */ + private $version = null; + + /** + * Constructor + * + * If no version is given, a feed in RSS 2.0 format will be generated. + * + * @param string $version the version constant (RSS1/RSS2/ATOM). + */ + protected function __construct($version = Feed::RSS2) + { + $this->version = $version; + + // Setting default encoding + $this->encoding = 'utf-8'; + + // Setting default value for essential channel element + $this->setTitle($version . ' Feed'); + + // Add some default XML namespaces + $this->namespaces['content'] = 'http://purl.org/rss/1.0/modules/content/'; + $this->namespaces['wfw'] = 'http://wellformedweb.org/CommentAPI/'; + $this->namespaces['atom'] = 'http://www.w3.org/2005/Atom'; + $this->namespaces['rdf'] = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'; + $this->namespaces['rss1'] = 'http://purl.org/rss/1.0/'; + $this->namespaces['dc'] = 'http://purl.org/dc/elements/1.1/'; + $this->namespaces['sy'] = 'http://purl.org/rss/1.0/modules/syndication/'; + + // Tag names to encode in CDATA + $this->addCDATAEncoding(array('description', 'content:encoded', 'summary')); + } + + // Start # public functions --------------------------------------------- + + /** + * Set the URLs for feed pagination. + * + * See RFC 5005, chapter 3. At least one page URL must be specified. + * + * @param string $nextURL The URL to the next page of this feed. Optional. + * @param string $previousURL The URL to the previous page of this feed. Optional. + * @param string $firstURL The URL to the first page of this feed. Optional. + * @param string $lastURL The URL to the last page of this feed. Optional. + * @link http://tools.ietf.org/html/rfc5005#section-3 + * @return self + * @throws \LogicException if none of the parameters are set. + */ + public function setPagination($nextURL = null, $previousURL = null, $firstURL = null, $lastURL = null) + { + if (empty($nextURL) && empty($previousURL) && empty($firstURL) && empty($lastURL)) + throw new \LogicException('At least one URL must be specified for pagination to work.'); + + if (!empty($nextURL)) + $this->setAtomLink($nextURL, 'next'); + + if (!empty($previousURL)) + $this->setAtomLink($previousURL, 'previous'); + + if (!empty($firstURL)) + $this->setAtomLink($firstURL, 'first'); + + if (!empty($lastURL)) + $this->setAtomLink($lastURL, 'last'); + + return $this; + } + + /** + * Add a channel element indicating the program used to generate the feed. + * + * @return self + * @throws InvalidOperationException if this method is called on an RSS1 feed. + */ + public function addGenerator() + { + if ($this->version == Feed::ATOM) + $this->setChannelElement('atom:generator', 'FeedWriter', array('uri' => 'https://github.com/mibe/FeedWriter')); + else if ($this->version == Feed::RSS2) + $this->setChannelElement('generator', 'FeedWriter'); + else + throw new InvalidOperationException('The generator element is not supported in RSS1 feeds.'); + + return $this; + } + + /** + * Add a XML namespace to the internal list of namespaces. After that, + * custom channel elements can be used properly to generate a valid feed. + * + * @access public + * @param string $prefix namespace prefix + * @param string $uri namespace name (URI) + * @return self + * @link http://www.w3.org/TR/REC-xml-names/ + * @throws \InvalidArgumentException if the prefix or uri is empty or NULL. + */ + public function addNamespace($prefix, $uri) + { + if (empty($prefix)) + throw new \InvalidArgumentException('The prefix may not be emtpy or NULL.'); + if (empty($uri)) + throw new \InvalidArgumentException('The uri may not be empty or NULL.'); + + $this->namespaces[$prefix] = $uri; + + return $this; + } + + /** + * Add a channel element to the feed. + * + * @access public + * @param string $elementName name of the channel tag + * @param string $content content of the channel tag + * @param array array of element attributes with attribute name as array key + * @param bool TRUE if this element can appear multiple times + * @return self + * @throws \InvalidArgumentException if the element name is not a string, empty or NULL. + */ + public function setChannelElement($elementName, $content, array $attributes = null, $multiple = false) + { + if (empty($elementName)) + throw new \InvalidArgumentException('The element name may not be empty or NULL.'); + if (!is_string($elementName)) + throw new \InvalidArgumentException('The element name must be a string.'); + + $entity['content'] = $content; + $entity['attributes'] = $attributes; + + if ($multiple === TRUE) + $this->channels[$elementName][] = $entity; + else + $this->channels[$elementName] = $entity; + + return $this; + } + + /** + * Set multiple channel elements from an array. Array elements + * should be 'channelName' => 'channelContent' format. + * + * @access public + * @param array array of channels + * @return self + */ + public function setChannelElementsFromArray(array $elementArray) + { + foreach ($elementArray as $elementName => $content) { + $this->setChannelElement($elementName, $content); + } + + return $this; + } + + /** + * Get the appropriate MIME type string for the current feed. + * + * @access public + * @return string The MIME type string. + */ + public function getMIMEType() + { + switch ($this->version) { + case Feed::RSS2 : $mimeType = "application/rss+xml"; + break; + case Feed::RSS1 : $mimeType = "application/rdf+xml"; + break; + case Feed::ATOM : $mimeType = "application/atom+xml"; + break; + default : $mimeType = "text/xml"; + } + + return $mimeType; + } + + /** + * Print the actual RSS/ATOM file + * + * Sets a Content-Type header and echoes the contents of the feed. + * Should only be used in situations where direct output is desired; + * if you need to pass a string around, use generateFeed() instead. + * + * @access public + * @param bool FALSE if the specific feed media type should be sent. + * @return void + * @throws \InvalidArgumentException if the useGenericContentType parameter is not boolean. + */ + public function printFeed($useGenericContentType = false) + { + if (!is_bool($useGenericContentType)) + throw new \InvalidArgumentException('The useGenericContentType parameter must be boolean.'); + + $contentType = "text/xml"; + + if (!$useGenericContentType) { + $contentType = $this->getMIMEType(); + } + + // Generate the feed before setting the header, so Exceptions will be nicely visible. + $feed = $this->generateFeed(); + header("Content-Type: " . $contentType . "; charset=" . $this->encoding); + echo $feed; + } + + /** + * Generate the feed. + * + * @access public + * @return string The complete feed XML. + * @throws InvalidOperationException if the link element of the feed is not set. + */ + public function generateFeed() + { + if ($this->version != Feed::ATOM && !array_key_exists('link', $this->channels)) + throw new InvalidOperationException('RSS1 & RSS2 feeds need a link element. Call the setLink method before this method.'); + + return $this->makeHeader() + . $this->makeChannels() + . $this->makeItems() + . $this->makeFooter(); + } + + /** + * Create a new Item. + * + * @access public + * @return Item instance of Item class + */ + public function createNewItem() + { + $Item = new Item($this->version); + + return $Item; + } + + /** + * Add one or more tags to the list of CDATA encoded tags + * + * @access public + * @param array $tags An array of tag names that are merged into the list of tags which should be encoded as CDATA + * @return self + */ + public function addCDATAEncoding(array $tags) + { + $this->CDATAEncoding = array_merge($this->CDATAEncoding, $tags); + + return $this; + } + + /** + * Get list of CDATA encoded properties + * + * @access public + * @return array Return an array of CDATA properties that are to be encoded as CDATA + */ + public function getCDATAEncoding() + { + return $this->CDATAEncoding; + } + + /** + * Remove tags from the list of CDATA encoded tags + * + * @access public + * @param array $tags An array of tag names that should be removed. + * @return void + */ + public function removeCDATAEncoding(array $tags) + { + // Call array_values to re-index the array. + $this->CDATAEncoding = array_values(array_diff($this->CDATAEncoding, $tags)); + } + + /** + * Add a FeedItem to the main class + * + * @access public + * @param Item $feedItem instance of Item class + * @return self + * @throws \InvalidArgumentException if the given item version mismatches. + */ + public function addItem(Item $feedItem) + { + if ($feedItem->getVersion() != $this->version) + { + $msg = sprintf('Feed type mismatch: This instance can handle %s feeds only, but item for %s feeds given.', $this->version, $feedItem->getVersion()); + throw new \InvalidArgumentException($msg); + } + + $this->items[] = $feedItem; + + return $this; + } + + // Wrapper functions ------------------------------------------------------------------- + + /** + * Set the 'encoding' attribute in the XML prolog. + * + * @access public + * @param string $encoding value of 'encoding' attribute + * @return self + * @throws \InvalidArgumentException if the encoding is not a string, empty or NULL. + */ + public function setEncoding($encoding) + { + if (empty($encoding)) + throw new \InvalidArgumentException('The encoding may not be empty or NULL.'); + if (!is_string($encoding)) + throw new \InvalidArgumentException('The encoding must be a string.'); + + $this->encoding = $encoding; + + return $this; + } + + /** + * Set the 'title' channel element + * + * @access public + * @param string $title value of 'title' channel tag + * @return self + */ + public function setTitle($title) + { + return $this->setChannelElement('title', $title); + } + + /** + * Set the date when the feed was lastly updated. + * + * This adds the 'updated' element to the feed. The value of the date parameter + * can be either an instance of the DateTime class, an integer containing a UNIX + * timestamp or a string which is parseable by PHP's 'strtotime' function. + * + * Not supported in RSS1 feeds. + * + * @access public + * @param DateTime|int|string Date which should be used. + * @return self + * @throws \InvalidArgumentException if the given date is not an instance of DateTime, a UNIX timestamp or a date string. + * @throws InvalidOperationException if this method is called on an RSS1 feed. + */ + public function setDate($date) + { + if ($this->version == Feed::RSS1) + throw new InvalidOperationException('The publication date is not supported in RSS1 feeds.'); + + // The feeds have different date formats. + $format = $this->version == Feed::ATOM ? \DATE_ATOM : \DATE_RSS; + + if ($date instanceof DateTime) + $date = $date->format($format); + else if(is_numeric($date) && $date >= 0) + $date = date($format, $date); + else if (is_string($date)) + { + $timestamp = strtotime($date); + if ($timestamp === FALSE) + throw new \InvalidArgumentException('The given date was not parseable.'); + + $date = date($format, $timestamp); + } + else + throw new \InvalidArgumentException('The given date is not an instance of DateTime, a UNIX timestamp or a date string.'); + + if ($this->version == Feed::ATOM) + $this->setChannelElement('updated', $date); + else + $this->setChannelElement('lastBuildDate', $date); + + return $this; + } + + /** + * Set a phrase or sentence describing the feed. + * + * @access public + * @param string $description Description of the feed. + * @return self + */ + public function setDescription($description) + { + if ($this->version != Feed::ATOM) + $this->setChannelElement('description', $description); + else + $this->setChannelElement('subtitle', $description); + + return $this; + } + + /** + * Set the 'link' channel element + * + * @access public + * @param string $link value of 'link' channel tag + * @return self + */ + public function setLink($link) + { + if ($this->version == Feed::ATOM) + $this->setAtomLink($link); + else + $this->setChannelElement('link', $link); + + return $this; + } + + /** + * Set custom 'link' channel elements. + * + * In ATOM feeds, only one link with alternate relation and the same combination of + * type and hreflang values. + * + * @access public + * @param string $href URI of this link + * @param string $rel relation type of the resource + * @param string $type MIME type of the target resource + * @param string $hreflang language of the resource + * @param string $title human-readable information about the resource + * @param int $length length of the resource in bytes + * @link https://www.iana.org/assignments/link-relations/link-relations.xml + * @link https://tools.ietf.org/html/rfc4287#section-4.2.7 + * @return self + * @throws \InvalidArgumentException on multiple occasions. + * @throws InvalidOperationException if the same link with the same attributes was already added to the feed. + */ + public function setAtomLink($href, $rel = null, $type = null, $hreflang = null, $title = null, $length = null) + { + $data = array('href' => $href); + + if ($rel != null) { + if (!is_string($rel) || empty($rel)) + throw new \InvalidArgumentException('rel parameter must be a string and a valid relation identifier.'); + + $data['rel'] = $rel; + } + if ($type != null) { + // Regex used from RFC 4287, page 41 + if (!is_string($type) || preg_match('/.+\/.+/', $type) != 1) + throw new \InvalidArgumentException('type parameter must be a string and a MIME type.'); + + $data['type'] = $type; + } + if ($hreflang != null) { + // Regex used from RFC 4287, page 41 + if (!is_string($hreflang) || preg_match('/[A-Za-z]{1,8}(-[A-Za-z0-9]{1,8})*/', $hreflang) != 1) + throw new \InvalidArgumentException('hreflang parameter must be a string and a valid language code.'); + + $data['hreflang'] = $hreflang; + } + if ($title != null) { + if (!is_string($title) || empty($title)) + throw new \InvalidArgumentException('title parameter must be a string and not empty.'); + + $data['title'] = $title; + } + if ($length != null) { + if (!is_int($length) || $length < 0) + throw new \InvalidArgumentException('length parameter must be a positive integer.'); + + $data['length'] = (string) $length; + } + + // ATOM spec. has some restrictions on atom:link usage + // See RFC 4287, page 12 (4.1.1) + if ($this->version == Feed::ATOM) { + foreach ($this->channels as $key => $value) { + if ($key != 'atom:link') + continue; + + // $value is an array , so check every element + foreach ($value as $linkItem) { + $attrib = $linkItem['attributes']; + // Only one link with relation alternate and same hreflang & type is allowed. + if (@$attrib['rel'] == 'alternate' && @$attrib['hreflang'] == $hreflang && @$attrib['type'] == $type) + throw new InvalidOperationException('The feed must not contain more than one link element with a' + . ' relation of "alternate" that has the same combination of type and hreflang attribute values.'); + } + } + } + + return $this->setChannelElement('atom:link', '', $data, true); + } + + /** + * Set an 'atom:link' channel element with relation=self attribute. + * Needs the full URL to this feed. + * + * @link http://www.rssboard.org/rss-profile#namespace-elements-atom-link + * @access public + * @param string $url URL to this feed + * @return self + */ + public function setSelfLink($url) + { + return $this->setAtomLink($url, 'self', $this->getMIMEType()); + } + + /** + * Set the 'image' channel element + * + * @access public + * @param string $url URL of the image + * @param string $title Title of the image. RSS only. + * @param string $link Link target URL of the image. RSS only. + * @return self + * @throws \InvalidArgumentException if the url is invalid. + * @throws \InvalidArgumentException if the title and link parameter are not a string or empty. + */ + public function setImage($url, $title = null, $link = null) + { + if (!is_string($url) || empty($url)) + throw new \InvalidArgumentException('url parameter must be a string and may not be empty or NULL.'); + + // RSS feeds have support for a title & link element. + if ($this->version != Feed::ATOM) + { + if (!is_string($title) || empty($title)) + throw new \InvalidArgumentException('title parameter must be a string and may not be empty or NULL.'); + if (!is_string($link) || empty($link)) + throw new \InvalidArgumentException('link parameter must be a string and may not be empty or NULL.'); + + $data = array('title'=>$title, 'link'=>$link, 'url'=>$url); + $name = 'image'; + } + else + { + $name = 'logo'; + $data = $url; + } + + // Special handling for RSS1 again (since RSS1 is a bit strange...) + if ($this->version == Feed::RSS1) + { + $this->data['Image'] = $data; + return $this->setChannelElement($name, '', array('rdf:resource' => $url), false); + } + else + return $this->setChannelElement($name, $data); + } + + /** + * Set the channel 'rdf:about' attribute, which is used in RSS1 feeds only. + * + * @access public + * @param string $url value of 'rdf:about' attribute of the channel element + * @return self + * @throws InvalidOperationException if this method is called and the feed is not of type RSS1. + * @throws \InvalidArgumentException if the given URL is invalid. + */ + public function setChannelAbout($url) + { + if ($this->version != Feed::RSS1) + throw new InvalidOperationException("This method is only supported in RSS1 feeds."); + if (empty($url)) + throw new \InvalidArgumentException('The about URL may not be empty or NULL.'); + if (!is_string($url)) + throw new \InvalidArgumentException('The about URL must be a string.'); + + $this->data['ChannelAbout'] = $url; + + return $this; + } + + /** + * Generate an UUID. + * + * The UUID is based on an MD5 hash. If no key is given, a unique ID as the input + * for the MD5 hash is generated. + * + * @author Anis uddin Ahmad + * @access public + * @param string $key optional key on which the UUID is generated + * @param string $prefix an optional prefix + * @return string the formatted UUID + */ + public static function uuid($key = null, $prefix = '') + { + $key = ($key == null) ? uniqid(rand()) : $key; + $chars = md5($key); + $uuid = substr($chars,0,8) . '-'; + $uuid .= substr($chars,8,4) . '-'; + $uuid .= substr($chars,12,4) . '-'; + $uuid .= substr($chars,16,4) . '-'; + $uuid .= substr($chars,20,12); + + return $prefix . $uuid; + } + + /** + * Replace invalid XML characters. + * + * @link http://www.phpwact.org/php/i18n/charsets#xml See utf8_for_xml() function + * @link http://www.w3.org/TR/REC-xml/#charsets + * @link https://github.com/mibe/FeedWriter/issues/30 + * + * @access public + * @param string $string string which should be filtered + * @param string $replacement replace invalid characters with this string + * @return string the filtered string + */ + public static function filterInvalidXMLChars($string, $replacement = '_') // default to '\x{FFFD}' ??? + { + $result = preg_replace('/[^\x{0009}\x{000a}\x{000d}\x{0020}-\x{D7FF}\x{E000}-\x{FFFD}\x{10000}-\x{10FFFF}]+/u', $replacement, $string); + + // Did the PCRE replace failed because of bad UTF-8 data? + // If yes, try a non-multibyte regex and without the UTF-8 mode enabled. + if ($result == NULL && preg_last_error() == PREG_BAD_UTF8_ERROR) + $result = preg_replace('/[^\x09\x0a\x0d\x20-\xFF]+/', $replacement, $string); + + // In case the regex replacing failed completely, return the whole unfiltered string. + if ($result == NULL) + $result = $string; + + return $result; + } + // End # public functions ---------------------------------------------- + + // Start # private functions ---------------------------------------------- + + /** + * Returns all used XML namespace prefixes in this instance. + * This includes all channel elements and feed items. + * Unfortunately some namespace prefixes are not included, + * because they are hardcoded, e.g. rdf. + * + * @access private + * @return array Array with namespace prefix as value. + */ + private function getNamespacePrefixes() + { + $prefixes = array(); + + // Get all tag names from channel elements... + $tags = array_keys($this->channels); + + // ... and now all names from feed items + foreach ($this->items as $item) { + foreach (array_keys($item->getElements()) as $key) { + if (!in_array($key, $tags)) { + $tags[] = $key; + } + } + } + + // Look for prefixes in those tag names + foreach ($tags as $tag) { + $elements = explode(':', $tag); + + if (count($elements) != 2) + continue; + + $prefixes[] = $elements[0]; + } + + return array_unique($prefixes); + } + + /** + * Returns the XML header and root element, depending on the feed type. + * + * @access private + * @return string The XML header of the feed. + * @throws InvalidOperationException if an unknown XML namespace prefix is encountered. + */ + private function makeHeader() + { + $out = 'encoding.'" ?>' . PHP_EOL; + + $prefixes = $this->getNamespacePrefixes(); + $attributes = array(); + $tagName = ''; + $defaultNamespace = ''; + + if ($this->version == Feed::RSS2) { + $tagName = 'rss'; + $attributes['version'] = '2.0'; + } elseif ($this->version == Feed::RSS1) { + $tagName = 'rdf:RDF'; + $prefixes[] = 'rdf'; + $defaultNamespace = $this->namespaces['rss1']; + } elseif ($this->version == Feed::ATOM) { + $tagName = 'feed'; + $defaultNamespace = $this->namespaces['atom']; + + // Ugly hack to remove the 'atom' value from the prefixes array. + $prefixes = array_flip($prefixes); + unset($prefixes['atom']); + $prefixes = array_flip($prefixes); + } + + // Iterate through every namespace prefix and add it to the element attributes. + foreach ($prefixes as $prefix) { + if (!isset($this->namespaces[$prefix])) + throw new InvalidOperationException('Unknown XML namespace prefix: \'' . $prefix . '\'.' + . ' Use the addNamespace method to add support for this prefix.'); + else + $attributes['xmlns:' . $prefix] = $this->namespaces[$prefix]; + } + + // Include default namepsace, if required + if (!empty($defaultNamespace)) + $attributes['xmlns'] = $defaultNamespace; + + $out .= $this->makeNode($tagName, '', $attributes, true); + + return $out; + } + + /** + * Closes the open tags at the end of file + * + * @access private + * @return string The XML footer of the feed. + */ + private function makeFooter() + { + if ($this->version == Feed::RSS2) { + return '' . PHP_EOL . ''; + } elseif ($this->version == Feed::RSS1) { + return ''; + } elseif ($this->version == Feed::ATOM) { + return ''; + } + } + + /** + * Creates a single node in XML format + * + * @access private + * @param string $tagName name of the tag + * @param mixed $tagContent tag value as string or array of nested tags in 'tagName' => 'tagValue' format + * @param array $attributes Attributes (if any) in 'attrName' => 'attrValue' format + * @param bool $omitEndTag True if the end tag should be omitted. Defaults to false. + * @return string formatted xml tag + * @throws \InvalidArgumentException if the tagContent is not an array and not a string. + */ + private function makeNode($tagName, $tagContent, array $attributes = null, $omitEndTag = false) + { + $nodeText = ''; + $attrText = ''; + + if ($attributes != null) { + foreach ($attributes as $key => $value) { + $value = self::filterInvalidXMLChars($value); + $value = htmlspecialchars($value); + $attrText .= " $key=\"$value\""; + } + } + + $attrText .= (in_array($tagName, $this->CDATAEncoding) && $this->version == Feed::ATOM) ? ' type="html"' : ''; + $nodeText .= "<{$tagName}{$attrText}>"; + $nodeText .= (in_array($tagName, $this->CDATAEncoding)) ? ' $value) { + if (is_array($value)) { + $nodeText .= PHP_EOL; + foreach ($value as $subValue) { + $nodeText .= $this->makeNode($key, $subValue); + } + } else if (is_string($value)) { + $nodeText .= $this->makeNode($key, $value); + } else { + throw new \InvalidArgumentException("Unknown node-value type for $key"); + } + } + } else { + $tagContent = self::filterInvalidXMLChars($tagContent); + $nodeText .= (in_array($tagName, $this->CDATAEncoding)) ? $this->sanitizeCDATA($tagContent) : htmlspecialchars($tagContent); + } + + $nodeText .= (in_array($tagName, $this->CDATAEncoding)) ? ']]>' : ''; + + if (!$omitEndTag) + $nodeText .= ""; + + $nodeText .= PHP_EOL; + + return $nodeText; + } + + /** + * Make the channels. + * + * @access private + * @return string The feed header as XML containing all the feed metadata. + */ + private function makeChannels() + { + $out = ''; + + //Start channel tag + switch ($this->version) { + case Feed::RSS2: + $out .= '' . PHP_EOL; + break; + case Feed::RSS1: + $out .= (isset($this->data['ChannelAbout']))? "data['ChannelAbout']}\">" : "channels['link']['content']}\">"; + break; + } + + //Print Items of channel + foreach ($this->channels as $key => $value) { + // In ATOM feeds, strip all ATOM namespace prefixes from the tag name. They are not needed here, + // because the ATOM namespace name is set as default namespace. + if ($this->version == Feed::ATOM && strncmp($key, 'atom', 4) == 0) { + $key = substr($key, 5); + } + + // The channel element can occur multiple times, when the key 'content' is not in the array. + if (!array_key_exists('content', $value)) { + // If this is the case, iterate through the array with the multiple elements. + foreach ($value as $singleElement) { + $out .= $this->makeNode($key, $singleElement['content'], $singleElement['attributes']); + } + } else { + $out .= $this->makeNode($key, $value['content'], $value['attributes']); + } + } + + if ($this->version == Feed::RSS1) { + //RSS 1.0 have special tag with channel + $out .= "" . PHP_EOL . "" . PHP_EOL; + foreach ($this->items as $item) { + $thisItems = $item->getElements(); + $out .= "" . PHP_EOL; + } + $out .= "" . PHP_EOL . "" . PHP_EOL . "" . PHP_EOL; + + // An image has its own element after the channel elements. + if (array_key_exists('image', $this->data)) + $out .= $this->makeNode('image', $this->data['Image'], array('rdf:about' => $this->data['Image']['url'])); + } else if ($this->version == Feed::ATOM) { + // ATOM feeds have a unique feed ID. Use the title channel element as key. + $out .= $this->makeNode('id', Feed::uuid($this->channels['title']['content'], 'urn:uuid:')); + } + + return $out; + } + + /** + * Prints formatted feed items + * + * @access private + * @return string The XML of every feed item. + */ + private function makeItems() + { + $out = ''; + + foreach ($this->items as $item) { + $thisItems = $item->getElements(); + + // The argument is printed as rdf:about attribute of item in RSS 1.0 + // We're using the link set in the item (which is mandatory) as the about attribute. + if ($this->version == Feed::RSS1) + $out .= $this->startItem($thisItems['link']['content']); + else + $out .= $this->startItem(); + + foreach ($thisItems as $feedItem) { + $name = $feedItem['name']; + + // Strip all ATOM namespace prefixes from tags when feed is an ATOM feed. + // Not needed here, because the ATOM namespace name is used as default namespace. + if ($this->version == Feed::ATOM && strncmp($name, 'atom', 4) == 0) + $name = substr($name, 5); + + $out .= $this->makeNode($name, $feedItem['content'], $feedItem['attributes']); + } + $out .= $this->endItem(); + } + + return $out; + } + + /** + * Make the starting tag of channels + * + * @access private + * @param string $about The value of about attribute which is used for RSS 1.0 only. + * @return string The starting XML tag of an feed item. + * @throws InvalidOperationException if this object misses the data for the about attribute. + */ + private function startItem($about = false) + { + $out = ''; + + if ($this->version == Feed::RSS2) { + $out .= '
' . PHP_EOL; + } elseif ($this->version == Feed::RSS1) { + if ($about) { + $out .= "" . PHP_EOL; + } else { + throw new InvalidOperationException("Missing data for about attribute. Call setChannelAbout method."); + } + } elseif ($this->version == Feed::ATOM) { + $out .= "" . PHP_EOL; + } + + return $out; + } + + /** + * Closes feed item tag + * + * @access private + * @return string The ending XML tag of an feed item. + */ + private function endItem() + { + if ($this->version == Feed::RSS2 || $this->version == Feed::RSS1) { + return '
' . PHP_EOL; + } elseif ($this->version == Feed::ATOM) { + return '' . PHP_EOL; + } + } + + /** + * Sanitizes data which will be later on returned as CDATA in the feed. + * + * A "]]>" respectively "", "]]>", $text); + $text = str_replace(" + * + * This file is part of the "Universal Feed Writer" project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * The exception that is thrown when an invalid operation is performed on + * the object. + * + * @package UniversalFeedWriter + */ +class InvalidOperationException extends LogicException +{ +} diff --git a/module/download/vendor/FeedWriter/Item.php b/module/download/vendor/FeedWriter/Item.php new file mode 100644 index 00000000..c4f21a93 --- /dev/null +++ b/module/download/vendor/FeedWriter/Item.php @@ -0,0 +1,413 @@ + + * Copyright (C) 2010-2013, 2015-2016 Michael Bemmerl + * + * This file is part of the "Universal Feed Writer" project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * Universal Feed Writer + * + * Item class - Used as feed element in Feed class + * + * @package UniversalFeedWriter + * @author Anis uddin Ahmad + * @link http://www.ajaxray.com/projects/rss + */ +class Item +{ + /** + * Collection of feed item elements + */ + private $elements = array(); + + /** + * Contains the format of this feed. + */ + private $version; + + /** + * Is used as a suffix when multiple elements have the same name. + **/ + private $_cpt = 0; + + /** + * Constructor + * + * @param string $version constant (RSS1/RSS2/ATOM) RSS2 is default. + */ + public function __construct($version = Feed::RSS2) + { + $this->version = $version; + } + + /** + * Return an unique number + * + * @access private + * @return int + **/ + private function cpt() + { + return $this->_cpt++; + } + + /** + * Add an element to elements array + * + * @access public + * @param string $elementName The tag name of an element + * @param string $content The content of tag + * @param array $attributes Attributes (if any) in 'attrName' => 'attrValue' format + * @param boolean $overwrite Specifies if an already existing element is overwritten. + * @param boolean $allowMultiple Specifies if multiple elements of the same name are allowed. + * @return self + * @throws \InvalidArgumentException if the element name is not a string, empty or NULL. + */ + public function addElement($elementName, $content, array $attributes = null, $overwrite = FALSE, $allowMultiple = FALSE) + { + if (empty($elementName)) + throw new \InvalidArgumentException('The element name may not be empty or NULL.'); + if (!is_string($elementName)) + throw new \InvalidArgumentException('The element name must be a string.'); + + $key = $elementName; + + // return if element already exists & if overwriting is disabled + // & if multiple elements are not allowed. + if (isset($this->elements[$elementName]) && !$overwrite) { + if (!$allowMultiple) + return $this; + + $key .= '-' . $this->cpt(); + } + + $this->elements[$key]['name'] = $elementName; + $this->elements[$key]['content'] = $content; + $this->elements[$key]['attributes'] = $attributes; + + return $this; + } + + /** + * Set multiple feed elements from an array. + * Elements which have attributes cannot be added by this method + * + * @access public + * @param array array of elements in 'tagName' => 'tagContent' format. + * @return self + */ + public function addElementArray(array $elementArray) + { + foreach ($elementArray as $elementName => $content) { + $this->addElement($elementName, $content); + } + + return $this; + } + + /** + * Return the collection of elements in this feed item + * + * @access public + * @return array All elements of this item. + * @throws InvalidOperationException on ATOM feeds if either a content or link element is missing. + * @throws InvalidOperationException on RSS1 feeds if a title or link element is missing. + */ + public function getElements() + { + // ATOM feeds have some specific requirements... + if ($this->version == Feed::ATOM) + { + // Add an 'id' element, if it was not added by calling the setLink method. + // Use the value of the title element as key, since no link element was specified. + if (!array_key_exists('id', $this->elements)) + $this->setId(Feed::uuid($this->elements['title']['content'], 'urn:uuid:')); + + // Either a 'link' or 'content' element is needed. + if (!array_key_exists('content', $this->elements) && !array_key_exists('link', $this->elements)) + throw new InvalidOperationException('ATOM feed entries need a link or a content element. Call the setLink or setContent method.'); + } + // ...same with RSS1 feeds. + else if ($this->version == Feed::RSS1) + { + if (!array_key_exists('title', $this->elements)) + throw new InvalidOperationException('RSS1 feed entries need a title element. Call the setTitle method.'); + if (!array_key_exists('link', $this->elements)) + throw new InvalidOperationException('RSS1 feed entries need a link element. Call the setLink method.'); + } + + return $this->elements; + } + + /** + * Return the type of this feed item + * + * @access public + * @return string The feed type, as defined in Feed.php + */ + public function getVersion() + { + return $this->version; + } + + // Wrapper functions ------------------------------------------------------ + + /** + * Set the 'description' element of feed item + * + * @access public + * @param string $description The content of the 'description' or 'summary' element + * @return self + */ + public function setDescription($description) + { + $tag = ($this->version == Feed::ATOM) ? 'summary' : 'description'; + + return $this->addElement($tag, $description); + } + + /** + * Set the 'content' element of the feed item + * For ATOM feeds only + * + * @access public + * @param string $content Content for the item (i.e., the body of a download post). + * @return self + * @throws InvalidOperationException if this method is called on non-ATOM feeds. + */ + public function setContent($content) + { + if ($this->version != Feed::ATOM) + throw new InvalidOperationException('The content element is supported in ATOM feeds only.'); + + return $this->addElement('content', $content, array('type' => 'html')); + } + + /** + * Set the 'title' element of feed item + * + * @access public + * @param string $title The content of 'title' element + * @return self + */ + public function setTitle($title) + { + return $this->addElement('title', $title); + } + + /** + * Set the 'date' element of the feed item. + * + * The value of the date parameter can be either an instance of the + * DateTime class, an integer containing a UNIX timestamp or a string + * which is parseable by PHP's 'strtotime' function. + * + * @access public + * @param DateTime|int|string $date Date which should be used. + * @return self + * @throws \InvalidArgumentException if the given date was not parseable. + */ + public function setDate($date) + { + if (!is_numeric($date)) { + if ($date instanceof DateTime) + $date = $date->getTimestamp(); + else { + $date = strtotime($date); + + if ($date === FALSE) + throw new \InvalidArgumentException('The given date string was not parseable.'); + } + } elseif ($date < 0) + throw new \InvalidArgumentException('The given date is not an UNIX timestamp.'); + + if ($this->version == Feed::ATOM) { + $tag = 'updated'; + $value = date(\DATE_ATOM, $date); + } elseif ($this->version == Feed::RSS2) { + $tag = 'pubDate'; + $value = date(\DATE_RSS, $date); + } else { + $tag = 'dc:date'; + $value = date("Y-m-d", $date); + } + + return $this->addElement($tag, $value); + } + + /** + * Set the 'link' element of feed item + * + * @access public + * @param string $link The content of 'link' element + * @return self + */ + public function setLink($link) + { + if ($this->version == Feed::RSS2 || $this->version == Feed::RSS1) { + $this->addElement('link', $link); + } else { + $this->addElement('link','',array('href'=>$link)); + $this->setId(Feed::uuid($link,'urn:uuid:')); + } + + return $this; + } + + /** + * Attach a external media to the feed item. + * Not supported in RSS 1.0 feeds. + * + * See RFC 4288 for syntactical correct MIME types. + * + * Note that you should avoid the use of more than one enclosure in one item, + * since some RSS aggregators don't support it. + * + * @access public + * @param string $url The URL of the media. + * @param integer $length The length of the media. + * @param string $type The MIME type attribute of the media. + * @param boolean $multiple Specifies if multiple enclosures are allowed + * @return self + * @link https://tools.ietf.org/html/rfc4288 + * @throws \InvalidArgumentException if the length or type parameter is invalid. + * @throws InvalidOperationException if this method is called on RSS1 feeds. + */ + public function addEnclosure($url, $length, $type, $multiple = TRUE) + { + if ($this->version == Feed::RSS1) + throw new InvalidOperationException('Media attachment is not supported in RSS1 feeds.'); + + // the length parameter should be set to 0 if it can't be determined + // see http://www.rssboard.org/rss-profile#element-channel-item-enclosure + if (!is_numeric($length) || $length < 0) + throw new \InvalidArgumentException('The length parameter must be an integer and greater or equals to zero.'); + + // Regex used from RFC 4287, page 41 + if (!is_string($type) || preg_match('/.+\/.+/', $type) != 1) + throw new \InvalidArgumentException('type parameter must be a string and a MIME type.'); + + $attributes = array('length' => $length, 'type' => $type); + + if ($this->version == Feed::RSS2) { + $attributes['url'] = $url; + $this->addElement('enclosure', '', $attributes, FALSE, $multiple); + } else { + $attributes['href'] = $url; + $attributes['rel'] = 'enclosure'; + $this->addElement('atom:link', '', $attributes, FALSE, $multiple); + } + + return $this; + } + + /** + * Set the 'author' element of feed item. + * Not supported in RSS 1.0 feeds. + * + * @access public + * @param string $author The author of this item + * @param string|null $email Optional email address of the author + * @param string|null $uri Optional URI related to the author + * @return self + * @throws \InvalidArgumentException if the provided email address is syntactically incorrect. + * @throws InvalidOperationException if this method is called on RSS1 feeds. + */ + public function setAuthor($author, $email = null, $uri = null) + { + if ($this->version == Feed::RSS1) + throw new InvalidOperationException('The author element is not supported in RSS1 feeds.'); + + // Regex from RFC 4287 page 41 + if ($email != null && preg_match('/.+@.+/', $email) != 1) + throw new \InvalidArgumentException('The email address is syntactically incorrect.'); + + if ($this->version == Feed::RSS2) + { + if ($email != null) + $author = $email . ' (' . $author . ')'; + + $this->addElement('author', $author); + } + else + { + $elements = array('name' => $author); + + if ($email != null) + $elements['email'] = $email; + + if ($uri != null) + $elements['uri'] = $uri; + + $this->addElement('author', $elements); + } + + return $this; + } + + /** + * Set the unique identifier of the feed item + * + * On ATOM feeds, the identifier must begin with an valid URI scheme. + * + * @access public + * @param string $id The unique identifier of this item + * @param boolean $permaLink The value of the 'isPermaLink' attribute in RSS 2 feeds. + * @return self + * @throws \InvalidArgumentException if the permaLink parameter is not boolean. + * @throws InvalidOperationException if this method is called on RSS1 feeds. + */ + public function setId($id, $permaLink = false) + { + if ($this->version == Feed::RSS2) { + if (!is_bool($permaLink)) + throw new \InvalidArgumentException('The permaLink parameter must be boolean.'); + + $permaLink = $permaLink ? 'true' : 'false'; + + $this->addElement('guid', $id, array('isPermaLink' => $permaLink)); + } elseif ($this->version == Feed::ATOM) { + // Check if the given ID is an valid URI scheme (see RFC 4287 4.2.6) + // The list of valid schemes was generated from http://www.iana.org/assignments/uri-schemes + // by using only permanent or historical schemes. + $validSchemes = array('aaa', 'aaas', 'about', 'acap', 'acct', 'cap', 'cid', 'coap', 'coaps', 'crid', 'data', 'dav', 'dict', 'dns', 'example', 'fax', 'file', 'filesystem', 'ftp', 'geo', 'go', 'gopher', 'h323', 'http', 'https', 'iax', 'icap', 'im', 'imap', 'info', 'ipp', 'ipps', 'iris', 'iris.beep', 'iris.lwz', 'iris.xpc', 'iris.xpcs', 'jabber', 'ldap', 'mailserver', 'mailto', 'mid', 'modem', 'msrp', 'msrps', 'mtqp', 'mupdate', 'news', 'nfs', 'ni', 'nih', 'nntp', 'opaquelocktoken', 'pack', 'pkcs11', 'pop', 'pres', 'prospero', 'reload', 'rtsp', 'rtsps', 'rtspu', 'service', 'session', 'shttp', 'sieve', 'sip', 'sips', 'sms', 'snews', 'snmp', 'soap.beep', 'soap.beeps', 'stun', 'stuns', 'tag', 'tel', 'telnet', 'tftp', 'thismessage', 'tip', 'tn3270', 'turn', 'turns', 'tv', 'urn', 'vemmi', 'videotex', 'vnc', 'wais', 'ws', 'wss', 'xcon', 'xcon-userid', 'xmlrpc.beep', 'xmlrpc.beeps', 'xmpp', 'z39.50', 'z39.50r', 'z39.50s'); + $found = FALSE; + $checkId = strtolower($id); + + foreach($validSchemes as $scheme) + if (strrpos($checkId, $scheme . ':', -strlen($checkId)) !== FALSE) + { + $found = TRUE; + break; + } + + if (!$found) + throw new \InvalidArgumentException("The ID must begin with an IANA-registered URI scheme."); + + $this->addElement('id', $id, NULL, TRUE); + } else + throw new InvalidOperationException('A unique ID is not supported in RSS1 feeds.'); + + return $this; + } + + } // end of class Item diff --git a/module/download/vendor/FeedWriter/README.md b/module/download/vendor/FeedWriter/README.md new file mode 100644 index 00000000..f630af99 --- /dev/null +++ b/module/download/vendor/FeedWriter/README.md @@ -0,0 +1,42 @@ +# Generate **RSS 1.0**, **RSS 2.0** or **ATOM** Formatted Feeds + +This package can be used to generate feeds in either **RSS 1.0**, **RSS 2.0** or **ATOM** format. + +Applications can create a feed object, several feed item objects, set several types of properties of either feed and feed items, and add items to the feed. + +Once a feed is fully composed with its items, the feed class can generate the necessary XML structure to describe the feed in **RSS** or **ATOM** format. This structure can be directly sent to the browser, or just returned as string. + +## Requirements + +- PHP 5.3 or higher + +If you don't have **PHP 5.3** available on your system there is a version supporting **PHP 5.0** and above. See the `legacy-php-5.0` branch. + +## Documentation + +The documentation can be found in the `gh-pages` branch, or on [GitHub Pages](https://mibe.github.io/FeedWriter/). + +See the `/examples` directory for usage examples. + +See the `CHANGELOG.md` file for changes between the different versions. + +## Authors + +In chronological order: + +- [Anis uddin Ahmad](https://github.com/ajaxray) +- [Michael Bemmerl](https://github.com/mibe) +- Phil Freo +- Paul Ferrett +- Brennen Bearnes +- Michael Robinson +- Baptiste Fontaine +- Kristián Valentín +- Brandtley McMinn +- Julian Bogdani +- Cedric Gampert +- Yamek +- Thielj +- Pavel Khakhlou +- Daniel +- Tino Goratsch diff --git a/module/download/vendor/FeedWriter/RSS1.php b/module/download/vendor/FeedWriter/RSS1.php new file mode 100644 index 00000000..a0465cf5 --- /dev/null +++ b/module/download/vendor/FeedWriter/RSS1.php @@ -0,0 +1,37 @@ + + * + * This file is part of the "Universal Feed Writer" project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * Wrapper for creating RSS1 feeds + * + * @package UniversalFeedWriter + */ +class RSS1 extends Feed +{ + /** + * {@inheritdoc} + */ + public function __construct() + { + parent::__construct(Feed::RSS1); + } +} diff --git a/module/download/vendor/FeedWriter/RSS2.php b/module/download/vendor/FeedWriter/RSS2.php new file mode 100644 index 00000000..9e36a728 --- /dev/null +++ b/module/download/vendor/FeedWriter/RSS2.php @@ -0,0 +1,37 @@ + + * + * This file is part of the "Universal Feed Writer" project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * Wrapper for creating RSS2 feeds + * + * @package UniversalFeedWriter + */ +class RSS2 extends Feed +{ + /** + * {@inheritdoc} + */ + public function __construct() + { + parent::__construct(Feed::RSS2); + } +} diff --git a/module/download/view/add/add.css b/module/download/view/add/add.css new file mode 100644 index 00000000..805e9150 --- /dev/null +++ b/module/download/view/add/add.css @@ -0,0 +1,18 @@ +/** + * This file is part of Zwii. + * + * For full copyright and license information, please see the LICENSE + * file that was distributed with this source code. + * + * @author Rémi Jean + * @copyright Copyright (C) 2008-2018, Rémi Jean + * @author Frédéric Tempez + * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @license GNU General Public License, version 3 + * @link http://zwiicms.fr/ + */ + + +/** NE PAS EFFACER +* admin.css +*/ \ No newline at end of file diff --git a/module/download/view/add/add.js.php b/module/download/view/add/add.js.php new file mode 100644 index 00000000..d88ff563 --- /dev/null +++ b/module/download/view/add/add.js.php @@ -0,0 +1,54 @@ +/** + * This file is part of Zwii. + * + * For full copyright and license information, please see the LICENSE + * file that was distributed with this source code. + * + * @author Rémi Jean + * @copyright Copyright (C) 2008-2018, Rémi Jean + * @license GNU General Public License, version 3 + * @link http://zwiicms.fr/ + */ + +/** + * Soumission du formulaire pour enregistrer en brouillon + */ +$("#downloadAddDraft").on("click", function() { + $("#downloadAddState").val(0); + $("#downloadAddForm").trigger("submit"); +}); + +/** + * Options de commentaires + */ +$("#downloadAddCommentClose").on("change", function() { + if ($(this).is(':checked') ) { + $(".commentOptionsWrapper").slideUp(); + } else { + $(".commentOptionsWrapper").slideDown(); + } +}); + +$("#downloadAddCommentNotification").on("change", function() { + if ($(this).is(':checked') ) { + $("#downloadAddCommentGroupNotification").slideDown(); + } else { + $("#downloadAddCommentGroupNotification").slideUp(); + } +}); + + +$( document).ready(function() { + + if ($("#downloadAddCloseComment").is(':checked') ) { + $(".commentOptionsWrapper").slideUp(); + } else { + $(".commentOptionsWrapper").slideDown(); + } + + if ($("#downloadAddCommentNotification").is(':checked') ) { + $("#downloadAddCommentGroupNotification").slideDown(); + } else { + $("#downloadAddCommentGroupNotification").slideUp(); + } +}); \ No newline at end of file diff --git a/module/download/view/add/add.php b/module/download/view/add/add.php new file mode 100644 index 00000000..e33f4df8 --- /dev/null +++ b/module/download/view/add/add.php @@ -0,0 +1,139 @@ + +
+
+ 'buttonGrey', + 'href' => helper::baseUrl() . $this->getUrl(0) . '/config', + 'ico' => 'left', + 'value' => 'Retour' + ]); ?> +
+
+ true, + 'value' => 'Enregistrer en brouillon' + ]); ?> + true + ]); ?> +
+
+ 'Publier' + ]); ?> +
+
+
+
+
+

Informations générales

+
+
+ 'Titre' + ]); ?> +
+
+ 'Version' + ]); ?> +
+
+ 'Date' + ]); ?> +
+
+
+
+ 'Archive du fichier' + ]); ?> +
+
+ 'Capture d\'écran', + 'type' => 1 + ]); ?> +
+
+
+
+ 'Auteur', + 'value' => $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'fileAuthor']) + ]); ?> +
+
+ 'Licence', + 'selected' => $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'fileLicense']) + ]); ?> +
+
+
+
+
+ 'editorWysiwyg' + ]); ?> +
+
+
+

Options de publication

+
+
+ 'Auteur', + 'selected' => $this->getUser('id'), + 'disabled' => $this->getUser('group') !== self::GROUP_ADMIN ? true : false + ]); ?> +
+
+ 'L\'item n\'est visible qu\'après la date de publication prévue.', + 'label' => 'Date de publication', + 'value' => time() + ]); ?> +
+
+ 'Edition / Suppression', + 'selected' => $module::EDIT_ALL, + 'help' => 'Les utilisateurs des groupes supérieurs accèdent à l\'item sans restriction' + ]); ?> +
+
+
+
+
+
+
+
+

Commentaires

+
+
+ +
+
+ +
+
+ 'Choix du nombre maximum de caractères pour chaque commentaire de l\'item, mise en forme html comprise.', + 'label' => 'Caractères par commentaire' + ]); ?> +
+
+
+
+ +
+
+ +
+
+
+
+
+ diff --git a/module/download/view/comment/comment.css b/module/download/view/comment/comment.css new file mode 100644 index 00000000..805e9150 --- /dev/null +++ b/module/download/view/comment/comment.css @@ -0,0 +1,18 @@ +/** + * This file is part of Zwii. + * + * For full copyright and license information, please see the LICENSE + * file that was distributed with this source code. + * + * @author Rémi Jean + * @copyright Copyright (C) 2008-2018, Rémi Jean + * @author Frédéric Tempez + * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @license GNU General Public License, version 3 + * @link http://zwiicms.fr/ + */ + + +/** NE PAS EFFACER +* admin.css +*/ \ No newline at end of file diff --git a/module/download/view/comment/comment.js.php b/module/download/view/comment/comment.js.php new file mode 100644 index 00000000..fe2f99d5 --- /dev/null +++ b/module/download/view/comment/comment.js.php @@ -0,0 +1,62 @@ +/** + * This file is part of Zwii. + * + * For full copyright and license information, please see the LICENSE + * file that was distributed with this source code. + * + * @author Rémi Jean + * @copyright Copyright (C) 2008-2018, Rémi Jean + * @license GNU General Public License, version 3 + * @link http://zwiicms.fr/ + */ + + +/** + * Confirmation de suppression + */ +$(".downloadCommentDelete").on("click", function() { + var _this = $(this); + var nom = "getData(['module', $this->getUrl(0), $this->getUrl(2), 'title' ]); ?>"; + return core.confirm("Supprimer le commentaire de l'item " + nom + " ?", function() { + $(location).attr("href", _this.attr("href")); + }); +}); + +/** + * Confirmation d'approbation + */ +$(".downloadCommentApproved").on("click", function() { + var _this = $(this); + var nom = "getData(['module', $this->getUrl(0), $this->getUrl(2), 'title' ]); ?>"; + return core.confirm("Approuver le commentaire de l'item " + nom + " ?", function() { + $(location).attr("href", _this.attr("href")); + }); +}); + +/** + * Confirmation de rejet + */ +$(".downloadCommentRejected").on("click", function() { + var _this = $(this); + var nom = "getData(['module', $this->getUrl(0), $this->getUrl(2), 'title' ]); ?>"; + return core.confirm("Rejeter le commentaire de l'item " + nom + " ?", function() { + $(location).attr("href", _this.attr("href")); + }); +}); + +/** + * Confirmation de suppression en masse + */ +$(".downloadCommentDeleteAll").on("click", function() { + var _this = $(this); + var nombre = "getData(['module', $this->getUrl(0), $this->getUrl(2), 'comment' ])); ?>"; + var nom = "getData(['module', $this->getUrl(0), $this->getUrl(2), 'title' ]); ?>"; + if( nombre === "1"){ + var message = "Supprimer le commentaire de l'item " + nom + " ?"; + } else{ + var message = "Supprimer les " + nombre + " commentaires de l'item " + nom + " ?"; + } + return core.confirm(message, function() { + $(location).attr("href", _this.attr("href")); + }); +}); diff --git a/module/download/view/comment/comment.php b/module/download/view/comment/comment.php new file mode 100644 index 00000000..76c50a61 --- /dev/null +++ b/module/download/view/comment/comment.php @@ -0,0 +1,22 @@ +
+
+ 'buttonGrey', + 'href' => helper::baseUrl() . $this->getUrl(0) . '/config', + 'ico' => 'left', + 'value' => 'Retour' + ]); ?> +
+ + +
+ +
+ +
+ + '; ?> + + + + diff --git a/module/download/view/config/config.css b/module/download/view/config/config.css new file mode 100644 index 00000000..805e9150 --- /dev/null +++ b/module/download/view/config/config.css @@ -0,0 +1,18 @@ +/** + * This file is part of Zwii. + * + * For full copyright and license information, please see the LICENSE + * file that was distributed with this source code. + * + * @author Rémi Jean + * @copyright Copyright (C) 2008-2018, Rémi Jean + * @author Frédéric Tempez + * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @license GNU General Public License, version 3 + * @link http://zwiicms.fr/ + */ + + +/** NE PAS EFFACER +* admin.css +*/ \ No newline at end of file diff --git a/module/download/view/config/config.js.php b/module/download/view/config/config.js.php new file mode 100644 index 00000000..bc462697 --- /dev/null +++ b/module/download/view/config/config.js.php @@ -0,0 +1,21 @@ +/** + * This file is part of Zwii. + * + * For full copyright and license information, please see the LICENSE + * file that was distributed with this source code. + * + * @author Rémi Jean + * @copyright Copyright (C) 2008-2018, Rémi Jean + * @license GNU General Public License, version 3 + * @link http://zwiicms.fr/ + */ + +/** + * Confirmation de suppression + */ +$(".downloadConfigDelete").on("click", function() { + var _this = $(this); + return core.confirm("Êtes-vous sûr de vouloir supprimer cet item ?", function() { + $(location).attr("href", _this.attr("href")); + }); +}); \ No newline at end of file diff --git a/module/download/view/config/config.php b/module/download/view/config/config.php new file mode 100644 index 00000000..8ac3cd4d --- /dev/null +++ b/module/download/view/config/config.php @@ -0,0 +1,60 @@ + +
+
+ 'buttonGrey', + 'href' => helper::baseUrl() . 'page/edit/' . $this->getUrl(0), 'items', + 'ico' => 'left', + 'value' => 'Retour' + ]); ?> +
+
+ helper::baseUrl() . $this->getUrl(0) . '/add', + 'ico' => 'plus', + 'value' => 'Fichier' + ]); ?> +
+
+ +
+
+
+
+
+

Paramètres du module

+
+
+ $this->getData(['module', $this->getUrl(0), 'config', 'feeds']), + ]); ?> +
+
+ 'Etiquette du flux', + 'value' => $this->getData(['module', $this->getUrl(0), 'config', 'feedsLabel']) + ]); ?> +
+
+
+
+ 'Articles par page', + 'selected' => $this->getData(['module', $this->getUrl(0),'config', 'itemsperPage']) + ]); ?> +
+
+
+
+
+ + + + + + + +
Version n° + +
+ diff --git a/module/download/view/edit/edit.css b/module/download/view/edit/edit.css new file mode 100644 index 00000000..805e9150 --- /dev/null +++ b/module/download/view/edit/edit.css @@ -0,0 +1,18 @@ +/** + * This file is part of Zwii. + * + * For full copyright and license information, please see the LICENSE + * file that was distributed with this source code. + * + * @author Rémi Jean + * @copyright Copyright (C) 2008-2018, Rémi Jean + * @author Frédéric Tempez + * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @license GNU General Public License, version 3 + * @link http://zwiicms.fr/ + */ + + +/** NE PAS EFFACER +* admin.css +*/ \ No newline at end of file diff --git a/module/download/view/edit/edit.js.php b/module/download/view/edit/edit.js.php new file mode 100644 index 00000000..148e937a --- /dev/null +++ b/module/download/view/edit/edit.js.php @@ -0,0 +1,66 @@ +/** + * This file is part of Zwii. + * + * For full copyright and license information, please see the LICENSE + * file that was distributed with this source code. + * + * @author Rémi Jean + * @copyright Copyright (C) 2008-2018, Rémi Jean + * @license GNU General Public License, version 3 + * @link http://zwiicms.fr/ + */ + + +// Lien de connexion +$("#downloadEditMailNotification").on("change", function() { + if($(this).is(":checked")) { + $("#formConfigGroup").show(); + } + else { + $("#formConfigGroup").hide(); + } +}).trigger("change"); + + +/** + * Soumission du formulaire pour enregistrer en brouillon + */ +$("#downloadEditDraft").on("click", function() { + $("#downloadEditState").val(0); + $("#downloadEditForm").trigger("submit"); +}); + +/** + * Options de commentaires + */ +$("#downloadEditCommentClose").on("change", function() { + if ($(this).is(':checked') ) { + $(".commentOptionsWrapper").slideUp(); + } else { + $(".commentOptionsWrapper").slideDown(); + } +}); + +$("#downloadEditCommentNotification").on("change", function() { + if ($(this).is(':checked') ) { + $("#downloadEditCommentGroupNotification").slideDown(); + } else { + $("#downloadEditCommentGroupNotification").slideUp(); + } +}); + + +$( document).ready(function() { + + if ($("#downloadEditCloseComment").is(':checked') ) { + $(".commentOptionsWrapper").slideUp(); + } else { + $(".commentOptionsWrapper").slideDown(); + } + + if ($("#downloadEditCommentNotification").is(':checked') ) { + $("#downloadEditCommentGroupNotification").slideDown(); + } else { + $("#downloadEditCommentGroupNotification").slideUp(); + } +}); \ No newline at end of file diff --git a/module/download/view/edit/edit.php b/module/download/view/edit/edit.php new file mode 100644 index 00000000..db0b5477 --- /dev/null +++ b/module/download/view/edit/edit.php @@ -0,0 +1,159 @@ + +
+
+ 'buttonGrey', + 'href' => helper::baseUrl() . $this->getUrl(0) . '/config', + 'ico' => 'left', + 'value' => 'Retour' + ]); ?> +
+
+ true, + 'value' => 'Enregistrer en brouillon' + ]); ?> + true + ]); ?> +
+
+ 'Publier' + ]); ?> + +
+
+
+
+
+

Informations générales

+ +
+
+ 'Titre', + 'value' => $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'title']) + ]); ?> +
+
+ 'Version', + 'value' => $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'fileVersion']) + ]); ?> +
+
+ 'Date', + 'value' => $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'fileDate']) + ]); ?> +
+
+
+
+ 'Archive du fichier', + 'value' => $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'file']) + ]); ?> +
+
+ 'Capture d\'écran', + 'type' => 1, + 'value' => $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'picture']) + ]); ?> +
+
+
+
+ 'Auteur', + 'value' => $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'fileAuthor']) + ]); ?> +
+
+ 'Licence', + 'selected' => $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'fileLicense']) + ]); ?> +
+
+
+
+
+ 'editorWysiwyg', + 'value' => $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'content']) + ]); ?> +
+
+
+

Options de publication

+
+
+ 'Auteur', + 'selected' => $this->getUser('id'), + 'disabled' => $this->getUser('group') !== self::GROUP_ADMIN ? true : false + ]); ?> +
+
+ 'L\'item n\'est visible qu\'après la date de publication prévue.', + 'label' => 'Date de publication', + 'value' => time() + ]); ?> +
+
+ 'Edition / Suppression', + 'selected' => is_numeric($this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'editConsent'])) ? $module::EDIT_GROUP : $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'editConsent']), + 'help' => 'Les utilisateurs des groupes supérieurs accèdent à l\'item sans restriction' + ]); ?> +
+
+
+
+
+
+
+
+

Commentaires

+
+
+ $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'commentClose']) + ]); ?> +
+
+ $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'commentApproved']), + '' + ]); ?> +
+
+ 'Choix du nombre maximum de caractères pour chaque commentaire de l\'item, mise en forme html comprise.', + 'label' => 'Caractères par commentaire', + 'selected' => $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'commentMaxlength']) + ]); ?> +
+ +
+
+
+ $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'commentNotification']), + ]); ?> +
+
+ $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'commentGroupNotification']), + 'help' => 'Editeurs = éditeurs + administrateurs
Membres = membres + éditeurs + administrateurs' + ]); ?> +
+
+
+
+
+ diff --git a/module/download/view/index/index.css b/module/download/view/index/index.css new file mode 100644 index 00000000..b958b637 --- /dev/null +++ b/module/download/view/index/index.css @@ -0,0 +1,69 @@ +.rowitem { + margin-bottom: 10px !important; +} +.downloadPicture { + float: none; + border: 1px; +} +.downloadPicture img { + width: 100%; + height: auto; + /* + border:1px solid lightgray; + box-shadow: 1px 1px 5px darkgray; + */ +} + +.downloadPicture:hover { + opacity: .7; +} +.row:after { + content: " "; + display: table; + clear: both; +} +.downloadComment { + padding-right: 10px; + float: right; +} +h2{ + margin-bottom: 5px; + margin-top: 0px; + padding: 0px; + +} +.downloadContent { + float: left; + margin-top: 5px; +} +.downloadDate { + font-size:0.8em; + font-style: italic; + /* + color: grey; + */ +} +@media (max-width: 768px) { + .downloadContent { + display: none; + } + + .downloadPicture img { + width: 50% ; + display: block; + margin-left: auto; + margin-right: auto; + } +} + +/* +* Flux RSS +*/ +#rssFeed { + text-align: right; + float: right; +} +#rssFeed p { + display: inline; + vertical-align: top; +} \ No newline at end of file diff --git a/module/download/view/item/item.css b/module/download/view/item/item.css new file mode 100644 index 00000000..445f719d --- /dev/null +++ b/module/download/view/item/item.css @@ -0,0 +1,63 @@ + +#sectionTitle { + margin-top: 0; + margin-bottom: 5px; +} +.downloaditemPicture { + height: auto; + border:1px solid lightgray; + box-shadow: 1px 1px 5px; +} +.downloaditemPictureleft { + float: left; + margin: 15px 10px 5px 0 ; +} +.downloaditemPictureright { + float: right; + margin: 15px 0 5px 10px ; +} + + +.pict20{ + width: 20%; +} +.pict30{ + width: 30%; +} +.pict40{ + width: 40%; +} +.pict50{ + width: 50%; +} +.pict100{ + width: 100%; + margin: 15px 0 20px 0 ; +} + +#downloaditemCommentShow { + cursor: text; +} +#downloaditemOr { + padding: 10px; +} +.downloadDate { + font-size:0.8em; + font-style: italic; + color: grey; +} +@media (max-width: 767px) { + .downloaditemPicture { + height:auto; + max-width: 100%;} + } + + +#rssFeed { + text-align: right; + float: right; +} +#rssFeed p { + display: inline; + vertical-align: top; +} diff --git a/module/download/view/item/item.js.php b/module/download/view/item/item.js.php new file mode 100644 index 00000000..cb07dcd2 --- /dev/null +++ b/module/download/view/item/item.js.php @@ -0,0 +1,43 @@ +/** + * This file is part of Zwii. + * + * For full copyright and license information, please see the LICENSE + * file that was distributed with this source code. + * + * @author Rémi Jean + * @copyright Copyright (C) 2008-2018, Rémi Jean + * @license GNU General Public License, version 3 + * @link http://zwiicms.fr/ + */ + +/** + * Affiche le bloc pour rédiger un commentaire + */ +var commentShowDOM = $("#downloadItemCommentShow"); +commentShowDOM.on("click focus", function() { + $("#downloadItemCommentShowWrapper").fadeOut(function() { + $("#downloadItemCommentWrapper").fadeIn(); + $("#downloadItemCommentContent").trigger("focus"); + }); +}); +if($("#downloadItemCommentWrapper").find("textarea.notice,input.notice").length) { + commentShowDOM.trigger("click"); +} + +/** + * Cache le bloc pour rédiger un commentaire + */ +$("#downloadItemCommentHide").on("click focus", function() { + $("#downloadItemCommentWrapper").fadeOut(function() { + $("#downloadItemCommentShowWrapper").fadeIn(); + $("#downloadItemCommentContent").val(""); + $("#downloadItemCommentAuthor").val(""); + }); +}); + +/** + * Force le scroll vers les commentaires en cas d'erreur + */ +$("#downloadItemCommentForm").on("submit", function() { + $(location).attr("href", "#comment"); +}); \ No newline at end of file diff --git a/module/download/view/list/list.php b/module/download/view/list/list.php new file mode 100644 index 00000000..4b8f6d3c --- /dev/null +++ b/module/download/view/list/list.php @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/module/download/view/rss/rss.php b/module/download/view/rss/rss.php new file mode 100644 index 00000000..4b8f6d3c --- /dev/null +++ b/module/download/view/rss/rss.php @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/module/download/view/stats/stats.css b/module/download/view/stats/stats.css new file mode 100644 index 00000000..805e9150 --- /dev/null +++ b/module/download/view/stats/stats.css @@ -0,0 +1,18 @@ +/** + * This file is part of Zwii. + * + * For full copyright and license information, please see the LICENSE + * file that was distributed with this source code. + * + * @author Rémi Jean + * @copyright Copyright (C) 2008-2018, Rémi Jean + * @author Frédéric Tempez + * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @license GNU General Public License, version 3 + * @link http://zwiicms.fr/ + */ + + +/** NE PAS EFFACER +* admin.css +*/ \ No newline at end of file diff --git a/module/download/view/stats/stats.js.php b/module/download/view/stats/stats.js.php new file mode 100644 index 00000000..fbeffea1 --- /dev/null +++ b/module/download/view/stats/stats.js.php @@ -0,0 +1,22 @@ +/** + * This file is part of Zwii. + * + * For full copyright and license information, please see the LICENSE + * file that was distributed with this source code. + * + * @author Rémi Jean + * @copyright Copyright (C) 2008-2018, Rémi Jean + * @license GNU General Public License, version 3 + * @link http://zwiicms.fr/ + */ + + +/** + * Confirmation de suppression + */ +$(".statsDeleteAll").on("click", function() { + var _this = $(this); + return core.confirm("Êtes-vous sûr de vouloir purger les statistiques ?", function() { + $(location).attr("href", _this.attr("href")); + }); +}); \ No newline at end of file diff --git a/module/download/view/stats/stats.php b/module/download/view/stats/stats.php new file mode 100644 index 00000000..5b778f3b --- /dev/null +++ b/module/download/view/stats/stats.php @@ -0,0 +1,36 @@ + +
+
+ 'buttonGrey', + 'href' => helper::baseUrl() . $this->getUrl(0) . '/config', + 'ico' => 'left', + 'value' => 'Retour' + ]); ?> +
+
+ 'statsDeleteAll buttonRed', + 'href' => helper::baseUrl() . $this->getUrl(0) . '/statsDeleteAll' . '/' . $this->getUrl(2) . '/'. $_SESSION['csrf'] , + 'ico' => 'cancel', + 'value' => 'Purger' + ]); ?> +
+
+ +
+
+

Nombre de téléchargements : + +

+
+
+ + + + + + +
Version n° + +
\ No newline at end of file diff --git a/module/gallery/gallery.php b/module/gallery/gallery.php index 9434387f..1da334b0 100755 --- a/module/gallery/gallery.php +++ b/module/gallery/gallery.php @@ -17,7 +17,7 @@ class gallery extends common { - const VERSION = '2.6'; + const VERSION = '3.0'; const REALNAME = 'Galerie'; const DELETE = true; const UPDATE = '0.0'; @@ -143,6 +143,75 @@ class gallery extends common { '1px 1px 50px' => 'Très importante' ]; + /** + * Mise à jour du module + * Appelée par les fonctions index et config + */ + private function update() { + + // Installation des données par défaut + $class = get_called_class(); + $moduleId = $this->getUrl(0); + if ( $this->getData(['module', $this->getUrl(0), 'config',]) === null ) { + require_once('module/gallery/ressource/defaultdata.php'); + $this->setData(['module', $this->getUrl(0), 'config', theme::$defaultData]); + + // Dossier de l'instance + if (!is_dir(self::DATA_DIR . 'modules/' . $class)) { + mkdir (self::DATA_DIR . 'modules/' . $class, 0777, true); + } + + // Nom de la feuille de style + $fileCSS = self::DATA_DIR . 'modules/' . $class . '/' . $moduleId . '.css' ; + $this->setData(['module', $this->getUrl(0), 'config', 'style', $fileCSS]); + } + + // Générer la feuille de CSS + if (!file_exists(self::DATA_DIR . 'modules/' . $class . '/' . $moduleId . '.css' )) { + $content = file_get_contents('module/gallery/ressource/vartheme.css'); + $themeCss = file_get_contents('module/gallery/ressource/theme.css'); + // Injection des variables + $content = str_replace('#thumbAlign#',$this->getData(['module', $this->getUrl(0), 'config', 'thumbAlign']),$content ); + $content = str_replace('#thumbWidth#',$this->getData(['module', $this->getUrl(0), 'config', 'thumbWidth']),$content ); + $content = str_replace('#thumbHeight#',$this->getData(['module', $this->getUrl(0), 'config', 'thumbHeight']),$content ); + $content = str_replace('#thumbMargin#',$this->getData(['module', $this->getUrl(0), 'config', 'thumbMargin']),$content ); + $content = str_replace('#thumbBorder#',$this->getData(['module', $this->getUrl(0), 'config', 'thumbBorder']),$content ); + $content = str_replace('#thumbBorderColor#',$this->getData(['module', $this->getUrl(0), 'config', 'thumbBorderColor']),$content ); + $content = str_replace('#thumbOpacity#',$this->getData(['module', $this->getUrl(0), 'config', 'thumbOpacity']),$content ); + $content = str_replace('#thumbShadows#',$this->getData(['module', $this->getUrl(0), 'config', 'thumbShadows']),$content ); + $content = str_replace('#thumbShadowsColor#',$this->getData(['module', $this->getUrl(0), 'config', 'thumbShadowsColor']),$content ); + $content = str_replace('#thumbRadius#',$this->getData(['module', $this->getUrl(0), 'config', 'thumbRadius']),$content ); + $content = str_replace('#legendAlign#',$this->getData(['module', $this->getUrl(0), 'config', 'legendAlign']),$content ); + $content = str_replace('#legendHeight#',$this->getData(['module', $this->getUrl(0), 'config', 'legendHeight']),$content ); + $content = str_replace('#legendTextColor#',$this->getData(['module', $this->getUrl(0), 'config', 'legendTextColor']),$content ); + $content = str_replace('#legendBgColor#',$this->getData(['module', $this->getUrl(0), 'config', 'legendBgColor']),$content ); + // Ecriture de la feuille de style + $success = file_put_contents(self::DATA_DIR . 'modules/' . $class . '/' . $moduleId . '.css' , $content . $themeCss); + } + + // Mise à jour d'une version inférieure + if (version_compare($this->getData(['module', $this->getUrl(0), 'config', 'versionData']), '3.0', '<') ) { + // Changement de l'arborescence dans module.json + $data = $this->getData(['module', $this->getUrl(0)]); + $this->deleteData(['module', $this->getUrl(0)]); + $this->setData(['module', $this->getUrl(0), 'content', $data]); + // Effacer les fichiers CSS de l'ancienne version + if (file_exists('module/gallery/view/index/index.css')) { + unlink('module/gallery/view/index/index.css'); + } + if (file_exists('module/gallery/view/gallery/gallery.css')) { + unlink('module/gallery/view/gallery/gallery.css'); + } + // Stockage des données du thème de la gallery + $data = $this->getData(['theme','gallery']); + $this->deleteData(['theme','gallery']); + $this->setData(['module', $this->getUrl(0), 'config', $data]); + // Nouvelle version + $this->setData(['module', $this->getUrl(0), 'config', 'versionData', '3.0']); + } + } + + /** * Tri de la liste des galeries * @@ -152,7 +221,7 @@ class gallery extends common { $data = explode('&',$_POST['response']); $data = str_replace('galleryTable%5B%5D=','',$data); for($i=0;$isetData(['module', $this->getUrl(0), $data[$i], [ + $this->setData(['module', $this->getUrl(0), 'content', $data[$i], [ 'config' => [ 'name' => $this->getData(['module',$this->getUrl(0),$data[$i],'config','name']), 'directory' => $this->getData(['module',$this->getUrl(0),$data[$i],'config','directory']), @@ -179,7 +248,7 @@ class gallery extends common { $data = explode('&',$_POST['response']); $data = str_replace('galleryTable%5B%5D=','',$data); // Sauvegarder - $this->setData(['module', $this->getUrl(0), $galleryName, [ + $this->setData(['module', $this->getUrl(0), 'content', $galleryName, [ 'config' => [ 'name' => $this->getData(['module',$this->getUrl(0),$galleryName,'config','name']), 'directory' => $this->getData(['module',$this->getUrl(0),$galleryName,'config','directory']), @@ -200,8 +269,11 @@ class gallery extends common { * Configuration */ public function config() { + // Mise à jour des données de module + $this->update(); + //Affichage de la galerie triée - $g = $this->getData(['module', $this->getUrl(0)]); + $g = $this->getData(['module', $this->getUrl(0), 'content']); $p = helper::arrayCollumn(helper::arrayCollumn($g,'config'),'position'); asort($p,SORT_NUMERIC); $galleries = []; @@ -243,7 +315,7 @@ class gallery extends common { // Soumission du formulaire d'ajout d'une galerie if($this->isPost()) { if (!$this->getInput('galleryConfigFilterResponse')) { - $galleryId = helper::increment($this->getInput('galleryConfigName', helper::FILTER_ID, true), (array) $this->getData(['module', $this->getUrl(0)])); + $galleryId = helper::increment($this->getInput('galleryConfigName', helper::FILTER_ID, true), (array) $this->getData(['module', $this->getUrl(0), 'content'])); // définir une vignette par défaut $directory = $this->getInput('galleryConfigDirectory', helper::FILTER_STRING_SHORT, true); $iterator = new DirectoryIterator($directory); @@ -260,13 +332,13 @@ class gallery extends common { break; } } - $this->setData(['module', $this->getUrl(0), $galleryId, [ + $this->setData(['module', $this->getUrl(0), 'content', $galleryId, [ 'config' => [ 'name' => $this->getInput('galleryConfigName'), 'directory' => $this->getInput('galleryConfigDirectory', helper::FILTER_STRING_SHORT, true), 'homePicture' => $homePicture, 'sort' => self::SORT_ASC, - 'position' => $this->getData(['module', $this->getUrl(0), $galleryId,'config','position']), + 'position' => $this->getData(['module', $this->getUrl(0), 'content', $galleryId,'config','position']), 'fullScreen' => false ], 'legend' => [], @@ -296,7 +368,7 @@ class gallery extends common { public function delete() { // $url prend l'adresse sans le token // La galerie n'existe pas - if($this->getData(['module', $this->getUrl(0), $this->getUrl(2)]) === null) { + if($this->getData(['module', $this->getUrl(0), 'content', $this->getUrl(2)]) === null) { // Valeurs en sortie $this->addOutput([ 'access' => false @@ -312,7 +384,7 @@ class gallery extends common { } // Suppression else { - $this->deleteData(['module', $this->getUrl(0), $this->getUrl(2)]); + $this->deleteData(['module', $this->getUrl(0), 'content', $this->getUrl(2)]); // Valeurs en sortie $this->addOutput([ 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/config', @@ -346,7 +418,7 @@ class gallery extends common { ]); } // La galerie n'existe pas - if($this->getData(['module', $this->getUrl(0), $this->getUrl(2)]) === null) { + if($this->getData(['module', $this->getUrl(0), 'content', $this->getUrl(2)]) === null) { // Valeurs en sortie $this->addOutput([ 'access' => false @@ -360,11 +432,11 @@ class gallery extends common { $galleryId = !empty($this->getInput('galleryEditName')) ? $this->getInput('galleryEditName', helper::FILTER_ID, true) : $this->getUrl(2); if($galleryId !== $this->getUrl(2)) { // Incrémente le nouvel id de la galerie - $galleryId = helper::increment($galleryId, $this->getData(['module', $this->getUrl(0)])); + $galleryId = helper::increment($galleryId, $this->getData(['module', $this->getUrl(0), 'content'])); // Transférer la position des images $oldPositions = $this->getData(['module',$this->getUrl(0), $this->getUrl(2),'positions']); // Supprime l'ancienne galerie - $this->deleteData(['module', $this->getUrl(0), $this->getUrl(2)]); + $this->deleteData(['module', $this->getUrl(0), 'content', $this->getUrl(2)]); } // légendes $legends = []; @@ -382,19 +454,19 @@ class gallery extends common { } // Sauvegarder if ($this->getInput('galleryEditName')) { - $this->setData(['module', $this->getUrl(0), $galleryId, [ + $this->setData(['module', $this->getUrl(0), 'content', $galleryId, [ 'config' => [ 'name' => $this->getInput('galleryEditName', helper::FILTER_STRING_SHORT, true), 'directory' => $this->getInput('galleryEditDirectory', helper::FILTER_STRING_SHORT, true), 'homePicture' => $homePicture, // pas de positions, on active le tri alpha 'sort' => $this->getInput('galleryEditSort'), - 'position' => $this->getData(['module', $this->getUrl(0), $galleryId,'config','position']), + 'position' => $this->getData(['module', $this->getUrl(0), 'content', $galleryId,'config','position']), 'fullScreen' => $this->getInput('galleryEditFullscreen', helper::FILTER_BOOLEAN) ], 'legend' => $legends, - 'positions' => empty($oldPositions) ? $this->getdata(['module', $this->getUrl(0), $galleryId, 'positions']) : $oldPositions + 'positions' => empty($oldPositions) ? $this->getdata(['module', $this->getUrl(0), 'content', $galleryId, 'positions']) : $oldPositions ]]); } // Valeurs en sortie @@ -405,7 +477,7 @@ class gallery extends common { ]); } // Met en forme le tableau - $directory = $this->getData(['module', $this->getUrl(0), $this->getUrl(2), 'config', 'directory']); + $directory = $this->getData(['module', $this->getUrl(0), 'content', $this->getUrl(2), 'config', 'directory']); if(is_dir($directory)) { $iterator = new DirectoryIterator($directory); @@ -421,11 +493,11 @@ class gallery extends common { template::ico('sort'), $fileInfos->getFilename(), template::checkbox( 'homePicture[' . $fileInfos->getFilename() . ']', true, '', [ - 'checked' => $this->getData(['module', $this->getUrl(0), $this->getUrl(2),'config', 'homePicture']) === $fileInfos->getFilename() ? true : false, + 'checked' => $this->getData(['module', $this->getUrl(0), 'content', $this->getUrl(2),'config', 'homePicture']) === $fileInfos->getFilename() ? true : false, 'class' => 'homePicture' ]), template::text('legend[' . $fileInfos->getFilename() . ']', [ - 'value' => $this->getData(['module', $this->getUrl(0), $this->getUrl(2), 'legend', str_replace('.','',$fileInfos->getFilename())]) + 'value' => $this->getData(['module', $this->getUrl(0), 'content', $this->getUrl(2), 'legend', str_replace('.','',$fileInfos->getFilename())]) ]), '' ]; @@ -433,7 +505,7 @@ class gallery extends common { } } // Tri des images - switch ($this->getData(['module', $this->getUrl(0), $this->getUrl(2), 'config', 'sort'])) { + switch ($this->getData(['module', $this->getUrl(0), 'content', $this->getUrl(2), 'config', 'sort'])) { case self::SORT_HAND: $positions = $this->getdata(['module',$this->getUrl(0), $this->getUrl(2),'positions']); if ($positions) { @@ -466,7 +538,7 @@ class gallery extends common { } // Valeurs en sortie $this->addOutput([ - 'title' => $this->getData(['module', $this->getUrl(0), $this->getUrl(2), 'config', 'name']), + 'title' => $this->getData(['module', $this->getUrl(0), 'content', $this->getUrl(2), 'config', 'name']), 'view' => 'edit', 'vendor' => [ 'tablednd' @@ -479,10 +551,12 @@ class gallery extends common { * Accueil (deux affichages en un pour éviter une url à rallonge) */ public function index() { + // Mise à jour des données de module + $this->update(); // Images d'une galerie if($this->getUrl(1)) { // La galerie n'existe pas - if($this->getData(['module', $this->getUrl(0), $this->getUrl(1)]) === null) { + if($this->getData(['module', $this->getUrl(0), 'content', $this->getUrl(1)]) === null) { // Valeurs en sortie $this->addOutput([ 'access' => false @@ -491,13 +565,13 @@ class gallery extends common { // La galerie existe else { // Images de la galerie - $directory = $this->getData(['module', $this->getUrl(0), $this->getUrl(1), 'config', 'directory']); + $directory = $this->getData(['module', $this->getUrl(0), 'content', $this->getUrl(1), 'config', 'directory']); if(is_dir($directory)) { $iterator = new DirectoryIterator($directory); foreach($iterator as $fileInfos) { if($fileInfos->isDot() === false AND $fileInfos->isFile() AND @getimagesize($fileInfos->getPathname())) { - self::$pictures[$directory . '/' . $fileInfos->getFilename()] = $this->getData(['module', $this->getUrl(0), $this->getUrl(1), 'legend', str_replace('.','',$fileInfos->getFilename())]); - $picturesSort[$directory . '/' . $fileInfos->getFilename()] = $this->getData(['module', $this->getUrl(0), $this->getUrl(1), 'positions', str_replace('.','',$fileInfos->getFilename())]); + self::$pictures[$directory . '/' . $fileInfos->getFilename()] = $this->getData(['module', $this->getUrl(0), 'content', $this->getUrl(1), 'legend', str_replace('.','',$fileInfos->getFilename())]); + $picturesSort[$directory . '/' . $fileInfos->getFilename()] = $this->getData(['module', $this->getUrl(0), 'content', $this->getUrl(1), 'positions', str_replace('.','',$fileInfos->getFilename())]); // Créer la miniature si manquante if (!file_exists( str_replace('source','thumb',$fileInfos->getPath()) . '/' . self::THUMBS_SEPARATOR . strtolower($fileInfos->getFilename()))) { $this->makeThumb($fileInfos->getPathname(), @@ -511,7 +585,7 @@ class gallery extends common { } } // Tri des images par ordre alphabétique - switch ($this->getData(['module', $this->getUrl(0), $this->getUrl(1), 'config', 'sort'])) { + switch ($this->getData(['module', $this->getUrl(0), 'content', $this->getUrl(1), 'config', 'sort'])) { case self::SORT_HAND: asort($picturesSort); if ($picturesSort) { @@ -535,8 +609,9 @@ class gallery extends common { // Valeurs en sortie $this->addOutput([ 'showBarEditButton' => true, - 'title' => $this->getData(['module', $this->getUrl(0), $this->getUrl(1), 'config', 'name']), - 'view' => 'gallery' + 'title' => $this->getData(['module', $this->getUrl(0), 'content', $this->getUrl(1), 'config', 'name']), + 'view' => 'gallery', + 'style' => $this->getData(['module', $this->getUrl(0), 'config', 'style']) ]); } // Pas d'image dans la galerie @@ -552,7 +627,7 @@ class gallery extends common { // Liste des galeries else { // Tri des galeries suivant l'ordre défini - $g = $this->getData(['module', $this->getUrl(0)]); + $g = $this->getData(['module', $this->getUrl(0), 'content']); $p = helper::arrayCollumn(helper::arrayCollumn($g,'config'),'position'); asort($p,SORT_NUMERIC); $galleries = []; @@ -598,7 +673,8 @@ class gallery extends common { $this->addOutput([ 'showBarEditButton' => true, 'showPageContent' => true, - 'view' => 'index' + 'view' => 'index', + 'style' => $this->getData(['module', $this->getUrl(0), 'config', 'style']) ]); } } @@ -615,16 +691,19 @@ class gallery extends common { 'notification' => 'Action non autorisée' ]); } - // Initialisation des données de thème de la galerie dasn theme.json - // Création des valeur par défaut absentes - if ( $this->getData(['theme', 'gallery']) === null ) { - require_once('module/gallery/ressource/defaultdata.php'); - $this->setData(['theme', 'gallery', theme::$defaultData]); - } // Soumission du formulaire - if($this->isPost()) { - $this->setData(['theme', 'gallery', [ + + // Générer la feuille de CSS + $class = get_called_class(); + $moduleId = $this->getUrl(0); + // Dossier de l'instance + if (!is_dir(self::DATA_DIR . 'modules/' . $class)) { + mkdir (self::DATA_DIR . 'modules/' . $class, 0777, true); + } + $fileCSS = self::DATA_DIR . 'modules/' . $class . '/' . $moduleId . '.css' ; + // Fin feuille de style + $this->getData(['module', $this->getUrl(0), 'config', [ 'thumbAlign' => $this->getinput('galleryThemeThumbAlign'), 'thumbWidth' => $this->getinput('galleryThemeThumbWidth'), 'thumbHeight' => $this->getinput('galleryThemeThumbHeight'), @@ -638,7 +717,9 @@ class gallery extends common { 'legendHeight' => $this->getinput('galleryThemeLegendHeight'), 'legendAlign' => $this->getinput('galleryThemeLegendAlign'), 'legendTextColor' => $this->getinput('galleryThemeLegendTextColor'), - 'legendBgColor' => $this->getinput('galleryThemeLegendBgColor') + 'legendBgColor' => $this->getinput('galleryThemeLegendBgColor'), + 'style' => $fileCSS, + 'version' => $this->getData(['module', $this->getUrl(0), 'config', 'version']) ] ]); // Création des fichiers CSS @@ -659,12 +740,11 @@ class gallery extends common { $content = str_replace('#legendHeight#',$this->getinput('galleryThemeLegendHeight'),$content ); $content = str_replace('#legendTextColor#',$this->getinput('galleryThemeLegendTextColor'),$content ); $content = str_replace('#legendBgColor#',$this->getinput('galleryThemeLegendBgColor'),$content ); - $success = file_put_contents('module/gallery/view/index/index.css',$content . $themeCss); - $success = $success && file_put_contents('module/gallery/view/gallery/gallery.css',$content . $themeCss); + $success = file_put_contents($fileCSS, $content . $themeCss); // Valeurs en sortie $this->addOutput([ 'redirect' => helper::baseUrl() . $this->getUrl() . '/theme', - 'notification' => $success !== FALSE ? 'Modifications enregistrées' : 'Modifications non enregistées !', + 'notification' => $success !== FALSE ? 'Modifications enregistrées' : 'Modifications non enregistrées !', 'state' => $success !== FALSE ]); } diff --git a/module/gallery/ressource/defaultdata.php b/module/gallery/ressource/defaultdata.php index ff71bbc3..22777389 100755 --- a/module/gallery/ressource/defaultdata.php +++ b/module/gallery/ressource/defaultdata.php @@ -14,6 +14,7 @@ class theme extends gallery { 'legendHeight' => '.375em', 'legendAlign' => 'center', 'legendTextColor' => 'rgba(255, 255, 255, 1)', - 'legendBgColor' => 'rgba(0, 0, 0, .6)' + 'legendBgColor' => 'rgba(0, 0, 0, .6)', + 'versionData' => '3.0' ]; } diff --git a/module/gallery/view/edit/edit.php b/module/gallery/view/edit/edit.php index c745d1e5..c8f74f42 100755 --- a/module/gallery/view/edit/edit.php +++ b/module/gallery/view/edit/edit.php @@ -20,12 +20,12 @@
'Nom', - 'value' => $this->getData(['module', $this->getUrl(0), $this->getUrl(2), 'config', 'name']) + 'value' => $this->getData(['module', $this->getUrl(0), 'content', $this->getUrl(2), 'config', 'name']) ]); ?>
$this->getData(['module', $this->getUrl(0), $this->getUrl(2), 'config', 'directory']), + 'value' => $this->getData(['module', $this->getUrl(0), 'content', $this->getUrl(2), 'config', 'directory']), 'noDirty' => true // Désactivé à cause des modifications en ajax ]); ?>
$this->getData(['module', $this->getUrl(0), $this->getUrl(2), 'config', 'sort']), + 'selected' => $this->getData(['module', $this->getUrl(0), 'content', $this->getUrl(2), 'config', 'sort']), 'label' => 'Tri des images', 'help' => 'Tri manuel : déplacez le images dans le tableau ci-dessous. L\'ordre est sauvegardé automatiquement.' ]); ?> @@ -43,7 +43,7 @@
$this->getData(['module', $this->getUrl(0), $this->getUrl(2), 'config', 'fullScreen']), + 'checked' => $this->getData(['module', $this->getUrl(0), 'content', $this->getUrl(2), 'config', 'fullScreen']), 'help' => 'A l\'ouverture de la galerie, la première image est affichée en plein écran.' ]); ?>
diff --git a/module/gallery/view/theme/theme.php b/module/gallery/view/theme/theme.php index 694ecaf9..5110b148 100755 --- a/module/gallery/view/theme/theme.php +++ b/module/gallery/view/theme/theme.php @@ -25,25 +25,25 @@
'Largeur', - 'selected' => $this->getData(['theme', 'gallery','thumbWidth']) + 'selected' => $this->getData(['module', $this->getUrl(0), 'config','thumbWidth']) ]); ?>
'Hauteur', - 'selected' => $this->getData(['theme', 'gallery','thumbHeight']) + 'selected' => $this->getData(['module', $this->getUrl(0), 'config','thumbHeight']) ]); ?>
'Alignement', - 'selected' => $this->getData(['theme', 'gallery','thumbAlign']) + 'selected' => $this->getData(['module', $this->getUrl(0), 'config','thumbAlign']) ]); ?>
'Marge', - 'selected' => $this->getData(['theme', 'gallery','thumbMargin']) + 'selected' => $this->getData(['module', $this->getUrl(0), 'config','thumbMargin']) ]); ?>
@@ -51,7 +51,7 @@
'Bordure', - 'selected' => $this->getData(['theme', 'gallery','thumbBorder']) + 'selected' => $this->getData(['module', $this->getUrl(0), 'config','thumbBorder']) ]); ?>
@@ -59,13 +59,13 @@ 'class' => 'colorPicker', 'help' => 'Le curseur horizontal règle le niveau de transparence.', 'label' => 'Couleur de la bordure', - 'value' => $this->getData(['theme', 'gallery','thumbBorderColor']) + 'value' => $this->getData(['module', $this->getUrl(0), 'config','thumbBorderColor']) ]); ?>
'Arrondi des angles', - 'selected' => $this->getData(['theme', 'gallery','thumbRadius']) + 'selected' => $this->getData(['module', $this->getUrl(0), 'config','thumbRadius']) ]); ?>
@@ -73,7 +73,7 @@
'Ombre', - 'selected' => $this->getData(['theme', 'gallery','thumbShadows']) + 'selected' => $this->getData(['module', $this->getUrl(0), 'config','thumbShadows']) ]); ?>
@@ -81,13 +81,13 @@ 'class' => 'colorPicker', 'help' => 'Le curseur horizontal règle le niveau de transparence.', 'label' => 'Couleur de l\'ombre', - 'value' => $this->getData(['theme', 'gallery','thumbShadowsColor']) + 'value' => $this->getData(['module', $this->getUrl(0), 'config','thumbShadowsColor']) ]); ?>
'Opacité au survol', - 'selected' => $this->getData(['theme', 'gallery','thumbOpacity']) + 'selected' => $this->getData(['module', $this->getUrl(0), 'config','thumbOpacity']) ]); ?>
@@ -108,7 +108,7 @@ 'class' => 'colorPicker', 'help' => 'Le curseur horizontal règle le niveau de transparence.', 'label' => 'Texte', - 'value' => $this->getData(['theme', 'gallery','legendTextColor']) + 'value' => $this->getData(['module', $this->getUrl(0), 'config','legendTextColor']) ]); ?>
@@ -116,19 +116,19 @@ 'class' => 'colorPicker', 'help' => 'Le curseur horizontal règle le niveau de transparence.', 'label' => 'Fond', - 'value' => $this->getData(['theme', 'gallery','legendBgColor']) + 'value' => $this->getData(['module', $this->getUrl(0), 'config','legendBgColor']) ]); ?>
'Hauteur', - 'selected' => $this->getData(['theme', 'gallery','legendHeight']) + 'selected' => $this->getData(['module', $this->getUrl(0), 'config','legendHeight']) ]); ?>
'Alignement', - 'selected' => $this->getData(['theme', 'gallery','legendAlign']) + 'selected' => $this->getData(['module', $this->getUrl(0), 'config','legendAlign']) ]); ?>
diff --git a/module/news/news.php b/module/news/news.php index b3896b31..888571f8 100755 --- a/module/news/news.php +++ b/module/news/news.php @@ -15,7 +15,7 @@ class news extends common { - const VERSION = '2.3'; + const VERSION = '3.0'; const REALNAME = 'Actualités'; const DELETE = true; const UPDATE = '0.0'; @@ -43,11 +43,51 @@ class news extends common { public static $users = []; + // Nombre d'objets par page + public static $ItemsList = [ + 4 => '4 articles', + 8 => '8 articles', + 12 => '12 articles', + 16 => '16 articles', + 22 => '22 articles' + ]; + // Nombre de colone par page + public static $Columns = [ + 12 => '1 Colonne', + 6 => '2 Colonnes', + 4 => '3 Colonnes', + 2 => '4 Colonnes' + ]; + public static $nbrCol = 1; + + public static $ItemsHeight = [ + '200px' => 'Petit', + '300px' => 'Moyen', + '400px' => 'Grand' + ]; + + // Signature de l'article + public static $articleSignature = ''; + + + /** + * Mise à jour du module + * Appelée par les fonctions index et config + */ + private function update() { + // Version 3.0 + if (version_compare($this->getData(['module', $this->getUrl(0), 'config', 'versionData']), '3.0', '<') ) { + $this->setData(['module', $this->getUrl(0), 'config', 'itemsperPage', 16]); + $this->setData(['module', $this->getUrl(0), 'config', 'itemsperCol', 6]); + $this->setData(['module', $this->getUrl(0), 'config', 'versionData','3.0']); + } + } + + /** * Flux RSS */ public function rss() { - // Inclure les classes include_once 'module/news/vendor/FeedWriter/Item.php'; include_once 'module/news/vendor/FeedWriter/Feed.php'; @@ -68,7 +108,7 @@ class news extends common { // Corps des articles $newsIdsPublishedOns = helper::arrayCollumn($this->getData(['module', $this->getUrl(0), 'posts']), 'publishedOn', 'SORT_DESC'); // Articles de la première page uniquement - $newsIdsPublishedOns = array_slice($newsIdsPublishedOns, 0, $this->getData(['config', 'itemsperPage']) ); + $newsIdsPublishedOns = array_slice($newsIdsPublishedOns, 0, $this->getData(['module', $this->getUrl(0), 'config', 'itemsperPage']) ); $newsIdsStates = helper::arrayCollumn($this->getData(['module', $this->getUrl(0), 'posts']), 'state', 'SORT_DESC'); foreach($newsIdsPublishedOns as $newsId => $newsPublishedOn) { if($newsPublishedOn <= time() AND $newsIdsStates[$newsId]) { @@ -95,7 +135,7 @@ class news extends common { } /** - * Édition + * Ajout d'un article */ public function add() { // Soumission du formulaire @@ -138,11 +178,32 @@ class news extends common { * Configuration */ public function config() { + // Mise à jour des données de module + $this->update(); + // Soumission du formulaire if($this->isPost()) { + + // Générer la feuille de CSS + $class = get_called_class(); + $moduleId = $this->getUrl(0); + $style = '.newsContent {height:' . $this->getInput('newsConfigItemsHeight',helper::FILTER_STRING_SHORT) . ';}'; + // Dossier de l'instance + if (!is_dir(self::DATA_DIR . 'modules/' . $class)) { + mkdir (self::DATA_DIR . 'modules/' . $class, 0777, true); + } + + $success = file_put_contents(self::DATA_DIR . 'modules/' . $class . '/' . $moduleId . '.css' , $style ); + // Fin feuille de style + $this->setData(['module', $this->getUrl(0), 'config',[ 'feeds' => $this->getInput('newsConfigShowFeeds',helper::FILTER_BOOLEAN), - 'feedsLabel' => $this->getInput('newsConfigFeedslabel',helper::FILTER_STRING_SHORT) + 'feedsLabel' => $this->getInput('newsConfigFeedslabel',helper::FILTER_STRING_SHORT), + 'itemsperPage' => $this->getInput('newsConfigItemsperPage', helper::FILTER_INT,true), + 'itemsperCol' => $this->getInput('newsConfigItemsperCol', helper::FILTER_INT,true), + 'itemsHeight' => $this->getInput('newsConfigItemsHeight',helper::FILTER_STRING_SHORT), + 'versionData' => $this->getData(['module', $this->getUrl(0), 'config', 'versionData']), + 'style' => $success ? self::DATA_DIR . 'modules/' . $class . '/' . $moduleId . '.css' : '' ]]); // Valeurs en sortie $this->addOutput([ @@ -154,7 +215,7 @@ class news extends common { // Ids des news par ordre de publication $newsIds = array_keys(helper::arrayCollumn($this->getData(['module', $this->getUrl(0), 'posts']), 'publishedOn', 'SORT_DESC')); // Pagination - $pagination = helper::pagination($newsIds, $this->getUrl(),$this->getData(['config','itemsperPage'])); + $pagination = helper::pagination($newsIds, $this->getUrl(),$this->getData(['module', $this->getUrl(0), 'config', 'itemsperPage']) ); // Liste des pages self::$pages = $pagination['pages']; // News en fonction de la pagination @@ -288,30 +349,64 @@ class news extends common { * Accueil */ public function index() { - // Ids des news par ordre de publication - $newsIdsPublishedOns = helper::arrayCollumn($this->getData(['module', $this->getUrl(0), 'posts']), 'publishedOn', 'SORT_DESC'); - $newsIdsStates = helper::arrayCollumn($this->getData(['module', $this->getUrl(0), 'posts']), 'state', 'SORT_DESC'); - $newsIds = []; - foreach($newsIdsPublishedOns as $newsId => $newsPublishedOn) { - if($newsPublishedOn <= time() AND $newsIdsStates[$newsId]) { - $newsIds[] = $newsId; + // Mise à jour des données de module + $this->update(); + // Affichage d'un article + if( + $this->getUrl(1) + // Protection pour la pagination, un ID ne peut pas être un entier, une page oui + AND intval($this->getUrl(1)) === 0 + ) { + // L'article n'existe pas + if($this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1)]) === null) { + // Valeurs en sortie + $this->addOutput([ + 'access' => false + ]); } + // L'article existe + else { + self::$articleSignature = $this->signature($this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'userId'])); + // Valeurs en sortie + $this->addOutput([ + 'showBarEditButton' => true, + 'title' => $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'title']), + 'view' => 'article' + ]); + + } + } else { + // Affichage index + // Ids des news par ordre de publication + $newsIdsPublishedOns = helper::arrayCollumn($this->getData(['module', $this->getUrl(0), 'posts']), 'publishedOn', 'SORT_DESC'); + $newsIdsStates = helper::arrayCollumn($this->getData(['module', $this->getUrl(0), 'posts']), 'state', 'SORT_DESC'); + $newsIds = []; + foreach($newsIdsPublishedOns as $newsId => $newsPublishedOn) { + if($newsPublishedOn <= time() AND $newsIdsStates[$newsId]) { + $newsIds[] = $newsId; + } + } + // Pagination + //$pagination = helper::pagination($newsIds, $this->getUrl(),$this->getData(['config','itemsperPage'])); + $pagination = helper::pagination($newsIds, $this->getUrl(),$this->getData(['module', $this->getUrl(0),'config', 'itemsperPage'])); + // Nombre de colonnes + self::$nbrCol = $this->getData(['module', $this->getUrl(0),'config', 'itemsperCol']); + // Liste des pages + self::$pages = $pagination['pages']; + // News en fonction de la pagination + for($i = $pagination['first']; $i < $pagination['last']; $i++) { + self::$news[$newsIds[$i]] = $this->getData(['module', $this->getUrl(0),'posts', $newsIds[$i]]); + self::$news[$newsIds[$i]]['userId'] = $this->signature($this->getData(['module', $this->getUrl(0), 'posts', $newsIds[$i], 'userId'])); + } + // Valeurs en sortie + $this->addOutput([ + 'showBarEditButton' => true, + 'showPageContent' => true, + 'view' => 'index', + 'style' => $this->getData(['module', $this->getUrl(0),'config', 'style']) + ]); + } - // Pagination - $pagination = helper::pagination($newsIds, $this->getUrl(),$this->getData(['config','itemsperPage'])); - // Liste des pages - self::$pages = $pagination['pages']; - // News en fonction de la pagination - for($i = $pagination['first']; $i < $pagination['last']; $i++) { - self::$news[$newsIds[$i]] = $this->getData(['module', $this->getUrl(0),'posts', $newsIds[$i]]); - self::$news[$newsIds[$i]]['userId'] = $this->signature($this->getData(['module', $this->getUrl(0), 'posts', $newsIds[$i], 'userId'])); - } - // Valeurs en sortie - $this->addOutput([ - 'showBarEditButton' => true, - 'showPageContent' => true, - 'view' => 'index' - ]); } /** diff --git a/module/news/view/article/article.css b/module/news/view/article/article.css new file mode 100644 index 00000000..604e6d6f --- /dev/null +++ b/module/news/view/article/article.css @@ -0,0 +1,20 @@ + +/** +* @author Frédéric Tempez +* @copyright Copyright (C) 2018-2021, Frédéric Tempez +* @license GNU General Public License, version 3 +* @link http://zwiicms.fr/ +*/ + +/* +* Module news +*/ + +#rssFeed { + text-align: right; + float: right; +} +#rssFeed p { + display: inline; + vertical-align: top; +} diff --git a/module/news/view/config/config.php b/module/news/view/config/config.php index 73929b9d..b9cee0bd 100755 --- a/module/news/view/config/config.php +++ b/module/news/view/config/config.php @@ -20,26 +20,48 @@
-
-
-

Paramètres du module

-
-
- $this->getData(['module', $this->getUrl(0), 'config', 'feeds']), - 'help' => 'Flux limité aux articles de la première page.' - ]); ?> -
-
- 'Texte de l\'étiquette', - 'value' => $this->getData(['module', $this->getUrl(0), 'config', 'feedsLabel']) - ]); ?> -
+
+
+

Paramètres du module

+
+
+ $this->getData(['module', $this->getUrl(0), 'config', 'feeds']), + 'help' => 'Flux limité aux articles de la première page.' + ]); ?> +
+
+ 'Etiquette RSS', + 'value' => $this->getData(['module', $this->getUrl(0), 'config', 'feedsLabel']) + ]); ?> +
+
+ +
+
+ 'Pagination', + 'selected' => $this->getData(['module', $this->getUrl(0),'config', 'itemsperCol']), + 'help' => 'Nombre de colonnes par page' + ]); ?> +
+
+ 'Articles par page', + 'selected' => $this->getData(['module', $this->getUrl(0),'config', 'itemsperPage']) + ]); ?> +
+
+ 'Hauteur', + 'selected' => $this->getData(['module', $this->getUrl(0),'config', 'itemsHeight']) + ]); ?>
+
diff --git a/module/news/view/index/index.css b/module/news/view/index/index.css index 48553448..c462ebbd 100755 --- a/module/news/view/index/index.css +++ b/module/news/view/index/index.css @@ -12,7 +12,7 @@ * @link http://zwiicms.fr/ */ -/* + /* * Module news */ @@ -21,10 +21,26 @@ background-color: #ECEFF1; padding:5px; }*/ +.newsContent { + overflow: hidden; /* les dépassements seront masqués */ + position: relative; +} + +.newsBlur { + position: absolute; + bottom: -5%; + margin: -10px; + height: 20%; + width: 110%; + backdrop-filter: blur(1px); + -webkit-backdrop-filter: blur(1px); +} + .newsContent { clear: left; margin-left: 10px; + margin-bottom: 5px; } .newsSignature { @@ -44,4 +60,26 @@ #rssFeed p { display: inline; vertical-align: top; -} \ No newline at end of file +} +@media (min-width: 769px) +{ + .col2 {width: 20%;} + .col3 {width: 24%;} + .col4 {width: 32%;} + .col6 {width: 49%;} + .col12 {width: 100%;} +} + +@media (max-width: 768px) +{ + .col2 {width: 49%;} + .col3 {width: 49%;} + .col4 {width: 49%;} +} +@media (max-width: 480px) +{ + .col2 {width: 100%;} + .col3 {width: 100%;} + .col4 {width: 100%;} +} + diff --git a/module/news/view/index/index.php b/module/news/view/index/index.php index 11c6150d..d71aba33 100755 --- a/module/news/view/index/index.php +++ b/module/news/view/index/index.php @@ -1,20 +1,19 @@
-
- $news): ?> -
-
-

- -

-
- -
-
- - + $news): ?> +
+

+ getUrl(0) . '/' . $newsId . '">' . $news['title'] . ''; ?> +

+
+ +
+
+
+ + - Editer -
-
-
+
getData(['module',$this->getUrl(0), 'config', 'feeds'])): ?>
- ' . $this->getData(['module',$this->getUrl(0), 'config', 'feedsLabel']) . '

' ; ?>
diff --git a/module/search/ressource/defaultdata.php b/module/search/ressource/defaultdata.php index d9d5a2a2..378c347c 100755 --- a/module/search/ressource/defaultdata.php +++ b/module/search/ressource/defaultdata.php @@ -5,6 +5,7 @@ class init extends search { 'resultHideContent' => false, 'placeHolder' => 'Un ou plusieurs mots-clés séparés par un espace ou par +', 'submitText' => 'Rechercher', - 'keywordColor' => 'rgba(229, 229, 1, 1)' + 'keywordColor' => 'rgba(229, 229, 1, 1)', + 'versionData' => '2.0' ]; } \ No newline at end of file diff --git a/module/search/search.php b/module/search/search.php index ed9a5815..9050a8a9 100755 --- a/module/search/search.php +++ b/module/search/search.php @@ -10,7 +10,8 @@ * @copyright Copyright (C) 2008-2018, Rémi Jean * @author Frédéric Tempez * @copyright Copyright (C) 2018-2021, Frédéric Tempez - * @copyright Sylvain Lelièvre + * @author Sylvain Lelièvre + * @copyright Copyright (C) 2020-2021, Sylvain Lelièvre * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ * @@ -18,7 +19,7 @@ class search extends common { - const VERSION = '1.3'; + const VERSION = '2.0'; const REALNAME = 'Recherche'; const DELETE = true; const UPDATE = '0.0'; @@ -45,22 +46,66 @@ class search extends common { ]; + /** + * Mise à jour du module + * Appelée par les fonctions index et config + */ + private function update() { + // Création des valeurs de réglage par défaut + if ( !is_array($this->getData(['module', $this->getUrl(0), 'config']) ) ) { + require_once('module/search/ressource/defaultdata.php'); + $this->setData(['module', $this->getUrl(0), 'config', init::$defaultData]); + } + // Version 2.0 + if (version_compare($this->getData(['module', $this->getUrl(0), 'config', 'versionData']), '2.0', '<') ) { + + // Distinguer la config des autres données + $data = $this->getData(['module', $this->getUrl(0)]); + $this->setData(['module', $this->getUrl(0), 'config', [ + 'submitText' => $this->getData(['module', $this->getUrl(0), 'submitText']), + 'placeHolder' => $this->getData(['module', $this->getUrl(0), 'placeHolder']), + 'resultHideContent' => $this->getData(['module', $this->getUrl(0), 'resultHideContent']), + 'previewLength' => $this->getData(['module', $this->getUrl(0), 'previewLength']), + 'keywordColor' => $this->getData(['module', $this->getUrl(0), 'keywordColor']) + ]]); + $this->deleteData(['module', $this->getUrl(0), 'submitText']); + $this->deleteData(['module', $this->getUrl(0), 'placeHolder']); + $this->deleteData(['module', $this->getUrl(0), 'resultHideContent']); + $this->deleteData(['module', $this->getUrl(0), 'previewLength']); + $this->deleteData(['module', $this->getUrl(0), 'keywordColor']); + $this->setData(['module', $this->getUrl(0), 'config', 'versionData','2.0']); + } + } + // Configuration vide public function config() { - // Création des valeurs de réglage par défaut - if ( $this->getData(['module', $this->getUrl(0)]) === null ) { - require_once('module/search/ressource/defaultdata.php'); - $this->setData(['module', $this->getUrl(0), init::$defaultData]); - } + + // Mise à jour des données de module + $this->update(); if($this->isPost()) { + + // Générer la feuille de CSS + $class = get_called_class(); + $moduleId = $this->getUrl(0); + $style = '.searchItem {background:' . $this->getInput('searchKeywordColor') . ';}'; + // Dossier de l'instance + if (!is_dir(self::DATA_DIR . 'modules/' . $class)) { + mkdir (self::DATA_DIR . 'modules/' . $class, 0777, true); + } + + $success = file_put_contents(self::DATA_DIR . 'modules/' . $class . '/' . $moduleId . '.css' , $style ); + // Fin feuille de style + // Soumission du formulaire - $this->setData(['module', $this->getUrl(0), [ + $this->setData(['module', $this->getUrl(0), 'config',[ 'submitText' => $this->getInput('searchSubmitText'), 'placeHolder' => $this->getInput('searchPlaceHolder'), 'resultHideContent' => $this->getInput('searchResultHideContent',helper::FILTER_BOOLEAN), 'previewLength' => $this->getInput('searchPreviewLength',helper::FILTER_INT), - 'keywordColor' => $this->getInput('searchKeywordColor') + 'keywordColor' => $this->getInput('searchKeywordColor'), + 'style' => $success ? self::DATA_DIR . 'modules/' . $class . '/' . $moduleId . '.css' : '', + 'versionData' => $this->getData(['module', $this->getUrl(0), 'config', 'versionData']) ]]); @@ -83,12 +128,8 @@ class search extends common { } public function index() { - - // Création des valeurs de réglage par défaut - if ( $this->getData(['module', $this->getUrl(0)]) === null ) { - require_once('module/search/ressource/defaultdata.php'); - $this->setData(['module', $this->getUrl(0), init::$defaultData]); - } + // Mise à jour des données de module + $this->update(); if($this->isPost()) { //Initialisations variables @@ -99,11 +140,59 @@ class search extends common { // Récupération du mot clef passé par le formulaire de ...view/index.php, avec caractères accentués self::$motclef=$this->getInput('searchMotphraseclef'); + // Variable de travail, on conserve la variable globale pour l'affichage du résultat + $motclef = self::$motclef; + + // Traduction du mot clé si le script Google Trad est actif + // Le multi langue est sélectionné + if ( $this->getData(['config','translate','scriptGoogle']) === true + AND + // et la traduction de la langue courante est automatique + ( isset($_COOKIE['googtrans']) + AND ( $this->getData(['config','translate', substr($_COOKIE['googtrans'],4,2)]) === 'script' + // Ou traduction automatique + OR $this->getData(['config','translate','autoDetect']) === true ) + ) + // Cas des pages d'administration + // Pas connecté + AND ( $this->getUser('password') !== $this->getInput('ZWII_USER_PASSWORD') + // Ou connecté avec option active + OR ($this->getUser('password') === $this->getInput('ZWII_USER_PASSWORD') + AND $this->getData(['config','translate','admin']) === true + ) + ) + AND !isset($_COOKIE['ZWII_I18N_SITE']) + ) + { + // Découper la chaîne + $f = str_getcsv($motclef, ' '); + // Supprimer les espaces et les guillemets + $f = str_replace(' ','',$f); + $f = str_replace('"','',$f); + // Lire le cookie GoogTrans et déterminer les langues cibles + $language['origin'] = substr($_COOKIE['googtrans'],4,2); + $language['target'] = substr($_COOKIE['googtrans'],1,2); + if ($language['target'] !== $language['origin']) { + foreach ($f as $key => $value) { + $e = $this->translate($language['origin'],$language['target'],$value); + $motclef = str_replace($value,$e,$motclef); + } + } + } + + // Suppression des mots < 3 caractères et des articles > 2 caractères de la chaîne $motclef + $arraymotclef = explode(' ', $motclef); + $motclef = ''; + foreach($arraymotclef as $key=>$value){ + if( strlen($value)>2 && $value!=='les' && $value!=='des' && $value!=='une' && $value!=='aux') $motclef.=$value.' '; + } + // Suppression du dernier ' ' + if($motclef !== '') $motclef = substr($motclef,0, strlen($motclef)-1); // Récupération de l'état de l'option mot entier passé par le même formulaire self::$motentier=$this->getInput('searchMotentier', helper::FILTER_BOOLEAN); - if (self::$motclef !== '' ) { + if ($motclef !== '' ) { foreach($this->getHierarchy(null,false,null) as $parentId => $childIds) { if ($this->getData(['page', $parentId, 'disable']) === false && $this->getUser('group') >= $this->getData(['page', $parentId, 'group']) && @@ -112,7 +201,7 @@ class search extends common { $titre = $this->getData(['page', $parentId, 'title']); $contenu = ' ' . $titre . ' ' . $this->getData(['page', $parentId, 'content']); // Pages sauf pages filles et articles de blog - $tempData = $this->occurrence($url, $titre, $contenu, self::$motclef, self::$motentier); + $tempData = $this->occurrence($url, $titre, $contenu, $motclef, self::$motentier); if (is_array($tempData) ) { $result [] = $tempData; } @@ -127,14 +216,15 @@ class search extends common { $titre = $this->getData(['page', $childId, 'title']); $contenu = ' ' . $titre . ' ' . $this->getData(['page', $childId, 'content']); //Pages filles - $tempData = $this->occurrence($url, $titre, $contenu, self::$motclef, self::$motentier); + $tempData = $this->occurrence($url, $titre, $contenu, $motclef, self::$motentier); if (is_array($tempData) ) { $result [] = $tempData; } } // Articles d'une sous-page blog - if ($this->getData(['page', $childId, 'moduleId']) === 'blog') + if ($this->getData(['page', $childId, 'moduleId']) === 'blog' && + $this->getData(['module',$parentId,'posts']) ) { foreach($this->getData(['module',$childId,'posts']) as $articleId => $article) { if($this->getData(['module',$childId,'posts',$articleId,'state']) === true) { @@ -142,7 +232,7 @@ class search extends common { $titre = $article['title']; $contenu = ' ' . $titre . ' ' . $article['content']; // Articles de sous-page de type blog - $tempData = $this->occurrence($url, $titre, $contenu, self::$motclef, self::$motentier); + $tempData = $this->occurrence($url, $titre, $contenu, $motclef, self::$motentier); if (is_array($tempData) ) { $result [] = $tempData; } @@ -152,7 +242,8 @@ class search extends common { } // Articles d'un blog - if ($this->getData(['page', $parentId, 'moduleId']) === 'blog' ) { + if ($this->getData(['page', $parentId, 'moduleId']) === 'blog' && + $this->getData(['module',$parentId,'posts']) ) { foreach($this->getData(['module',$parentId,'posts']) as $articleId => $article) { if($this->getData(['module',$parentId,'posts',$articleId,'state']) === true) { @@ -160,7 +251,7 @@ class search extends common { $titre = $article['title']; $contenu = ' ' . $titre . ' ' . $article['content']; // Articles de Blog - $tempData = $this->occurrence($url, $titre, $contenu, self::$motclef, self::$motentier); + $tempData = $this->occurrence($url, $titre, $contenu, $motclef, self::$motentier); if (is_array($tempData) ) { $result [] = $tempData; } @@ -189,7 +280,8 @@ class search extends common { $this->addOutput([ 'view' => 'index', 'showBarEditButton' => true, - 'showPageContent' => !$this->getData(['module', $this->getUrl(0),'resultHideContent']) + 'showPageContent' => !$this->getData(['module', $this->getUrl(0), 'config', 'resultHideContent']), + 'style' => $this->getData(['module', $this->getUrl(0), 'config', 'style']) ]); } else { // Valeurs en sortie, affichage du formulaire @@ -216,7 +308,9 @@ class search extends common { // Construire la clé de recherche selon options de recherche $keywords = '/('; + foreach ($a as $key => $value) { + $keywords .= $motentier === true ? $value . '|' : '\b' . $value . '\b|' ; } $keywords = substr($keywords,0,strlen($keywords) - 1); @@ -234,9 +328,9 @@ class search extends common { // Rechercher l'espace le plus proche $d = $d >= 1 ? strpos($contenu,' ',$d) : $d; // Découper l'aperçu - $t = substr($contenu, $d ,$this->getData(['module',$this->getUrl(0),'previewLength'])); + $t = substr($contenu, $d ,$this->getData(['module',$this->getUrl(0), 'config', 'previewLength'])); // Applique une mise en évidence - $t = preg_replace($keywords, '\1',$t); + $t = preg_replace($keywords, '\1',$t); // Sauver résultat $resultat .= '

'.$t.'...

'; $resultat .= '

' . count($matches[0]) . (count($matches[0]) === 1 ? ' correspondance

' : ' correspondances

'); @@ -248,4 +342,10 @@ class search extends common { } } } + + // Requête de traduction avec le script Google + private function translate($from_lan, $to_lan, $text) { + $arrayjson = json_decode(file_get_contents('https://translate.googleapis.com/translate_a/single?client=gtx&sl='.$from_lan.'&tl=fr&dt=t&q='.$text),true); + return $arrayjson[0][0][0]; + } } diff --git a/module/search/view/config/config.php b/module/search/view/config/config.php index f54674d7..06d22285 100755 --- a/module/search/view/config/config.php +++ b/module/search/view/config/config.php @@ -20,13 +20,13 @@

'Texte du bouton', - 'value' => $this->getData(['module', $this->getUrl(0), 'submitText']) + 'value' => $this->getData(['module', $this->getUrl(0), 'config', 'submitText']) ]); ?>
'Dimension de l\'aperçu', - 'selected' => $this->getData(['module', $this->getUrl(0),'previewLength']) + 'selected' => $this->getData(['module', $this->getUrl(0), 'config', 'previewLength']) ]); ?>
@@ -34,12 +34,12 @@
'Aide dans la zone de saisie', - 'value' => $this->getData(['module', $this->getUrl(0), 'placeHolder']) + 'value' => $this->getData(['module', $this->getUrl(0), 'config', 'placeHolder']) ]); ?>
$this->getData(['module', $this->getUrl(0), 'resultHideContent']), + 'checked' => $this->getData(['module', $this->getUrl(0), 'config', 'resultHideContent']), ]); ?>
@@ -59,7 +59,7 @@ 'class' => 'colorPicker', 'help' => 'Le curseur horizontal règle le niveau de transparence, le placer tout à la gauche pour un surlignement invisible.', 'label' => 'Surlignement', - 'value' => $this->getData(['module', $this->getUrl(0), 'keywordColor']) + 'value' => $this->getData(['module', $this->getUrl(0), 'config', 'keywordColor']) ]); ?>
diff --git a/module/search/view/index/index.php b/module/search/view/index/index.php index 5fa91623..06434a7e 100755 --- a/module/search/view/index/index.php +++ b/module/search/view/index/index.php @@ -4,7 +4,7 @@
$this->getData(['module', $this->getUrl(0), 'placeHolder']), + 'placeholder' => isset($_COOKIE['ZWII_I18N_SITE'] ) ? $this->getData(['module', $this->getUrl(0), 'placeHolder']):'Un ou plusieurs mots clef séparés par un espace', 'value' => $module::$motclef ]); ?>
From 9630f093cd803c33e1012adeaa43ec647cd9a45b Mon Sep 17 00:00:00 2001 From: fredtempez Date: Mon, 5 Apr 2021 09:00:29 +0200 Subject: [PATCH 04/14] defaultdata de la v11 --- core/module/install/ressource/defaultdata.php | 120 ++++++++++++------ 1 file changed, 83 insertions(+), 37 deletions(-) diff --git a/core/module/install/ressource/defaultdata.php b/core/module/install/ressource/defaultdata.php index e6e89524..272e536b 100755 --- a/core/module/install/ressource/defaultdata.php +++ b/core/module/install/ressource/defaultdata.php @@ -21,7 +21,6 @@ class init extends common { 'githubId' => '' ], 'timezone' => 'Europe/Paris', - 'itemsperPage' => 10, 'proxyUrl' => '', 'proxyPort' => '', 'proxyType' => 'tcp://', @@ -34,9 +33,23 @@ class init extends common { 'log' => false, 'captcha' => true ], + 'translate' => [ + 'scriptGoogle' => false, + 'showCredits' => false, + 'autoDetect' => false, + 'admin' => false, + 'fr' => true, + 'de' => true, + 'en' => true, + 'es' => false, + 'it' => false, + 'nl' => false, + 'pt' => false + + ], ], 'core' => [ - 'dataVersion' => 10400, + 'dataVersion' => 11000, 'lastBackup' => 0, 'lastClearTmp' => 0, 'lastAutoUpdate' => 0, @@ -84,6 +97,19 @@ class init extends common { ], 'module' => [], 'user' => [], + 'translate' => [ + 'scriptGoogle' => false, + 'showCredits' => false, + 'autoDetect' => false, + 'admin' => false, + 'fr' => 'none', + 'de' => 'none', + 'en' => 'none', + 'es' => 'none', + 'it' => 'none', + 'nl' => 'none', + 'pt' => 'none' + ], 'theme' => [ 'body' => [ 'backgroundColor' => 'rgba(236, 239, 241, 1)', @@ -724,44 +750,64 @@ class init extends common { ], ], 'galeries' => [ - 'beaux-paysages' => [ - 'config' => [ - 'name' => 'Beaux paysages', - 'directory' => self::FILE_DIR.'source/galerie/landscape', - 'homePicture' => 'iceberg.jpg', - 'sort' => 'SORT_ASC', - 'position' => 1 + 'content' => [ + 'beaux-paysages' => [ + 'config' => [ + 'name' => 'Beaux paysages', + 'directory' => self::FILE_DIR.'source/galerie/landscape', + 'homePicture' => 'iceberg.jpg', + 'sort' => 'SORT_ASC', + 'position' => 1 + ], + 'legend' => [ + 'desertjpg' => 'Un désert', + 'icebergjpg' => 'Un iceberg', + 'meadowjpg' => 'Une prairie' + ], + 'positions' => [ + 'desertjpg' => 3, + 'icebergjpg' => 1, + 'meadowjpg' => 2 + ] ], - 'legend' => [ - 'desertjpg' => 'Un désert', - 'icebergjpg' => 'Un iceberg', - 'meadowjpg' => 'Une prairie' + 'espace' => [ + 'config' => [ + 'name' => 'Espace', + 'directory' => self::FILE_DIR.'source/galerie/space', + 'homePicture' => 'nebula.jpg', + 'sort' => 'SORT_ASC', + 'position' => 2 + ], + 'legend' => [ + 'earthjpg' => 'La Terre et la Lune', + 'cosmosjpg' => 'Le cosmos', + 'nebulajpg' => 'Une nébuleuse' + ], + 'positions' => [ + 'earthjpg' => 1, + 'cosmosjpg' => 3, + 'nebulajpg' => 2 + ] ], - 'positions' => [ - 'desertjpg' => 3, - 'icebergjpg' => 1, - 'meadowjpg' => 2 - ] ], - 'espace' => [ - 'config' => [ - 'name' => 'Espace', - 'directory' => self::FILE_DIR.'source/galerie/space', - 'homePicture' => 'nebula.jpg', - 'sort' => 'SORT_ASC', - 'position' => 2 - ], - 'legend' => [ - 'earthjpg' => 'La Terre et la Lune', - 'cosmosjpg' => 'Le cosmos', - 'nebulajpg' => 'Une nébuleuse' - ], - 'positions' => [ - 'earthjpg' => 1, - 'cosmosjpg' => 3, - 'nebulajpg' => 2 - ] - ] + 'config' => [ + 'thumbAlign' => 'center', + 'thumbWidth' => '18em', + 'thumbHeight' => '15em', + 'thumbMargin' => '.5em', + 'thumbBorder' => '.1em', + 'thumbOpacity' => '.7', + 'thumbBorderColor' => 'rgba(221, 221, 221, 1)', + 'thumbRadius' => '.3em', + 'thumbShadows' => '1px 1px 10px', + 'thumbShadowsColor'=> 'rgba(125, 125, 125, 1)', + 'legendHeight' => '.375em', + 'legendAlign' => 'center', + 'legendTextColor' => 'rgba(255, 255, 255, 1)', + 'legendBgColor' => 'rgba(0, 0, 0, .6)', + 'versionData' => '3.0', + 'style' => 'site/data/modules/gallery/galeries.css' + ], ], 'site-de-zwii' => [ 'url' => 'https://zwiicms.fr/', From df778fbee1fa2789682f83bfaf8e5e29f26858f8 Mon Sep 17 00:00:00 2001 From: fredtempez Date: Mon, 5 Apr 2021 09:05:33 +0200 Subject: [PATCH 05/14] config objets par page --- core/module/config/config.php | 8 -------- core/module/config/view/advanced/advanced.php | 15 ++++----------- 2 files changed, 4 insertions(+), 19 deletions(-) diff --git a/core/module/config/config.php b/core/module/config/config.php index a2244036..6e88920e 100755 --- a/core/module/config/config.php +++ b/core/module/config/config.php @@ -146,13 +146,6 @@ class config extends common { 'Pacific/Fiji' => '(GMT+12:00) Fiji', 'Asia/Kamchatka' => '(GMT+12:00) Kamchatka' ]; - // Nombre d'objets par page - public static $ItemsList = [ - 5 => '5 articles', - 10 => '10 articles', - 15 => '15 articles', - 20 => '20 articles' - ]; // Type de proxy public static $proxyType = [ 'tcp://' => 'TCP', @@ -457,7 +450,6 @@ class config extends common { 'githubId' => $this->getInput('configAdvancedSocialGithubId') ], 'timezone' => $this->getInput('configAdvancedTimezone', helper::FILTER_STRING_SHORT, true), - 'itemsperPage' => $this->getInput('configAdvancedItemsperPage', helper::FILTER_INT,true), 'autoUpdate' => $this->getInput('configAdvancedAutoUpdate', helper::FILTER_BOOLEAN), 'autoUpdateHtaccess' => $this->getInput('configAdvancedAutoUpdateHtaccess', helper::FILTER_BOOLEAN), 'proxyType' => $this->getInput('configAdvancedProxyType'), diff --git a/core/module/config/view/advanced/advanced.php b/core/module/config/view/advanced/advanced.php index 0d11fe06..bc9effc8 100644 --- a/core/module/config/view/advanced/advanced.php +++ b/core/module/config/view/advanced/advanced.php @@ -60,15 +60,6 @@ 'value' => $this->getData(['config', 'faviconDark']) ]); ?>
-
- 'Articles par page', - 'selected' => $this->getData(['config', 'itemsperPage']), - 'help' => 'Modules Blog et News' - ]); ?> -
-
-
'Fuseau horaire', @@ -76,12 +67,14 @@ 'help' => 'Le fuseau horaire est utile au bon référencement' ]); ?>
-
+
+
+
$this->getData(['config', 'cookieConsent']) ]); ?>
-
+
$this->getData(['config','captchaStrong']), 'help' => 'Option recommandée pour sécuriser la connexion. S\'applique à tous les captchas du site. Le captcha simple se limite à une addition de nombres de 0 à 10. Le captcha renforcé utilise quatre opérations de nombres de 0 à 20.' From c45fdc489579c03be6a25fa49df0227c90488909 Mon Sep 17 00:00:00 2001 From: fredtempez Date: Mon, 5 Apr 2021 09:09:51 +0200 Subject: [PATCH 06/14] =?UTF-8?q?config=20advanced=20emplacements=20des=20?= =?UTF-8?q?s=C3=A9lecteurs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/module/config/view/advanced/advanced.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/core/module/config/view/advanced/advanced.php b/core/module/config/view/advanced/advanced.php index bc9effc8..e6f02601 100644 --- a/core/module/config/view/advanced/advanced.php +++ b/core/module/config/view/advanced/advanced.php @@ -69,25 +69,26 @@
-
+
$this->getData(['config', 'cookieConsent']) ]); ?>
-
+
$this->getData(['config','captchaStrong']), 'help' => 'Option recommandée pour sécuriser la connexion. S\'applique à tous les captchas du site. Le captcha simple se limite à une addition de nombres de 0 à 10. Le captcha renforcé utilise quatre opérations de nombres de 0 à 20.' ]); ?>
-
-
+
helper::checkRewrite(), 'help' => 'Vérifiez d\'abord que votre serveur l\'autorise : ce n\'est pas le cas chez Free.' ]); ?>
+
+
$this->getData(['config', 'autoBackup']), From 89a5828d995a7b8fd0c416608371ec1808d11930 Mon Sep 17 00:00:00 2001 From: fredtempez Date: Mon, 5 Apr 2021 14:38:15 +0200 Subject: [PATCH 07/14] =?UTF-8?q?suprresion=20des=20options=20de=20langues?= =?UTF-8?q?=20comment=C3=A9es?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/core.php | 11 ----------- core/module/install/ressource/defaultdata.php | 16 +--------------- 2 files changed, 1 insertion(+), 26 deletions(-) diff --git a/core/core.php b/core/core.php index 7a4a6e42..9efcb80d 100755 --- a/core/core.php +++ b/core/core.php @@ -143,16 +143,6 @@ class common { self::GROUP_MODERATOR => 'Éditeur', self::GROUP_ADMIN => 'Administrateur' ]; - // Langues proposées - public static $i18nList = [ - 'fr' => 'Français (fr)', - 'de' => 'Allemand (de)', - 'en' => 'Anglais (en)', - 'es' => 'Espagnol (es)', - 'it' => 'Italien (it)', - 'nl' => 'Néerlandais (nl)', - 'pt' => 'Portugais (pt)', - ]; // Langue courante public static $i18nCurrent = 'fr'; public static $timezone; @@ -2933,7 +2923,6 @@ class layout extends common { if($this->getUser('group') >= self::GROUP_ADMIN) { $rightItems .= '
  • ' . template::ico('users') . '
  • '; $rightItems .= '
  • ' . template::ico('brush') . '
  • '; - //$rightItems .= '
  • ' . template::ico('flag') . '
  • '; $rightItems .= '
  • ' . template::ico('puzzle') . '
  • '; $rightItems .= '
  • ' . template::ico('cog-alt') . '
  • '; // Mise à jour automatique diff --git a/core/module/install/ressource/defaultdata.php b/core/module/install/ressource/defaultdata.php index 272e536b..67b1b38b 100755 --- a/core/module/install/ressource/defaultdata.php +++ b/core/module/install/ressource/defaultdata.php @@ -32,21 +32,7 @@ class init extends common { 'attempt' => 3, 'log' => false, 'captcha' => true - ], - 'translate' => [ - 'scriptGoogle' => false, - 'showCredits' => false, - 'autoDetect' => false, - 'admin' => false, - 'fr' => true, - 'de' => true, - 'en' => true, - 'es' => false, - 'it' => false, - 'nl' => false, - 'pt' => false - - ], + ] ], 'core' => [ 'dataVersion' => 11000, From 374439755c47ff6cdd567411b57783883b1a768f Mon Sep 17 00:00:00 2001 From: fredtempez Date: Mon, 5 Apr 2021 14:38:31 +0200 Subject: [PATCH 08/14] Gallery correction init --- module/gallery/gallery.php | 15 +++-- module/gallery/view/gallery/gallery.css | 79 ------------------------- module/gallery/view/index/index.css | 79 ------------------------- 3 files changed, 10 insertions(+), 163 deletions(-) delete mode 100755 module/gallery/view/gallery/gallery.css delete mode 100755 module/gallery/view/index/index.css diff --git a/module/gallery/gallery.php b/module/gallery/gallery.php index 1da334b0..7ecdb7d2 100755 --- a/module/gallery/gallery.php +++ b/module/gallery/gallery.php @@ -149,10 +149,12 @@ class gallery extends common { */ private function update() { - // Installation des données par défaut + // Variables génériques $class = get_called_class(); $moduleId = $this->getUrl(0); - if ( $this->getData(['module', $this->getUrl(0), 'config',]) === null ) { + + // Installation des données de thème par défaut + if ( $this->getData(['module', $this->getUrl(0), 'config']) === null ) { require_once('module/gallery/ressource/defaultdata.php'); $this->setData(['module', $this->getUrl(0), 'config', theme::$defaultData]); @@ -164,10 +166,13 @@ class gallery extends common { // Nom de la feuille de style $fileCSS = self::DATA_DIR . 'modules/' . $class . '/' . $moduleId . '.css' ; $this->setData(['module', $this->getUrl(0), 'config', 'style', $fileCSS]); - } - // Générer la feuille de CSS - if (!file_exists(self::DATA_DIR . 'modules/' . $class . '/' . $moduleId . '.css' )) { + // Créer le dossier du module + if (!is_dir(self::DATA_DIR . 'modules/' . $class)) { + mkdir (self::DATA_DIR . 'modules/' . $class, 0777, true); + } + + // Générer la feuille de CSS $content = file_get_contents('module/gallery/ressource/vartheme.css'); $themeCss = file_get_contents('module/gallery/ressource/theme.css'); // Injection des variables diff --git a/module/gallery/view/gallery/gallery.css b/module/gallery/view/gallery/gallery.css deleted file mode 100755 index a9da4105..00000000 --- a/module/gallery/view/gallery/gallery.css +++ /dev/null @@ -1,79 +0,0 @@ -.galleryRow { - --thumbAlign: center; -} -.colPicture { - --thumbWidth: 18em; - --thumbMargin: .5em; -} -.galleryPicture, -.galleryGalleryPicture { - --thumbHeight: 15em; - --thumbBorder: .1em; - --thumbBorderColor: rgba(221, 221, 221, 1); - --thumbRadius: .3em; - --thumbShadows: 1px 1px 10px; - --thumbShadowsColor: rgba(125, 125, 125, 1); -} -.galleryName, -.galleryGalleryName { - --legendHeight: .375em; - --legendAlign: center; - --legendTextColor: rgba(255, 255, 255, 1); - --legendBgColor: rgba(0, 0, 0, .6); -} -.galleryPicture:hover, -.galleryGalleryPicture:hover { - --thumbOpacity: .7; -} -.galleryPicture, -.galleryGalleryPicture { - display: block; - border: var(--thumbBorder) solid var(--thumbBorderColor); - height: var(--thumbHeight); - background-size: cover; - background-repeat: no-repeat; - background-position: center; - position: relative; - -webkit-transition: opacity .3s ease-out; - transition: opacity .3s ease-out; - border-radius: var(--thumbRadius); - box-shadow: var(--thumbShadows) var(--thumbShadowsColor); - -webkit-box-shadow: var(--thumbShadows) var(--thumbShadowsColor); - -moz-box-shadow: var(--thumbShadows) var(--thumbShadowsColor); -} -.galleryPicture:hover, -.galleryGalleryPicture:hover { - opacity: var(--thumbOpacity); -} -.galleryName, -.galleryGalleryName { - position: absolute; - left: 0; - right: 0; - bottom: 0; - border-radius: 0 0 calc(var(--thumbRadius)/2) calc(var(--thumbRadius)/2); - padding: var(--legendHeight); - background: var(--legendBgColor); - color: var(--legendTextColor); - text-align: var(--legendAlign); -} - -.galleryRow { - display: flex; - flex-wrap: wrap; - justify-content: var(--thumbAlign); -} - -.colPicture { - width : var(--thumbWidth); - max-width: 50%; - padding: var(--thumbMargin); - } - - @media (max-width: 432px) { - .colPicture { - width: 90%; - max-width: 90%; - margin: 0.5em; - } - } \ No newline at end of file diff --git a/module/gallery/view/index/index.css b/module/gallery/view/index/index.css deleted file mode 100755 index a9da4105..00000000 --- a/module/gallery/view/index/index.css +++ /dev/null @@ -1,79 +0,0 @@ -.galleryRow { - --thumbAlign: center; -} -.colPicture { - --thumbWidth: 18em; - --thumbMargin: .5em; -} -.galleryPicture, -.galleryGalleryPicture { - --thumbHeight: 15em; - --thumbBorder: .1em; - --thumbBorderColor: rgba(221, 221, 221, 1); - --thumbRadius: .3em; - --thumbShadows: 1px 1px 10px; - --thumbShadowsColor: rgba(125, 125, 125, 1); -} -.galleryName, -.galleryGalleryName { - --legendHeight: .375em; - --legendAlign: center; - --legendTextColor: rgba(255, 255, 255, 1); - --legendBgColor: rgba(0, 0, 0, .6); -} -.galleryPicture:hover, -.galleryGalleryPicture:hover { - --thumbOpacity: .7; -} -.galleryPicture, -.galleryGalleryPicture { - display: block; - border: var(--thumbBorder) solid var(--thumbBorderColor); - height: var(--thumbHeight); - background-size: cover; - background-repeat: no-repeat; - background-position: center; - position: relative; - -webkit-transition: opacity .3s ease-out; - transition: opacity .3s ease-out; - border-radius: var(--thumbRadius); - box-shadow: var(--thumbShadows) var(--thumbShadowsColor); - -webkit-box-shadow: var(--thumbShadows) var(--thumbShadowsColor); - -moz-box-shadow: var(--thumbShadows) var(--thumbShadowsColor); -} -.galleryPicture:hover, -.galleryGalleryPicture:hover { - opacity: var(--thumbOpacity); -} -.galleryName, -.galleryGalleryName { - position: absolute; - left: 0; - right: 0; - bottom: 0; - border-radius: 0 0 calc(var(--thumbRadius)/2) calc(var(--thumbRadius)/2); - padding: var(--legendHeight); - background: var(--legendBgColor); - color: var(--legendTextColor); - text-align: var(--legendAlign); -} - -.galleryRow { - display: flex; - flex-wrap: wrap; - justify-content: var(--thumbAlign); -} - -.colPicture { - width : var(--thumbWidth); - max-width: 50%; - padding: var(--thumbMargin); - } - - @media (max-width: 432px) { - .colPicture { - width: 90%; - max-width: 90%; - margin: 0.5em; - } - } \ No newline at end of file From cba87d3295ba54a5cafbe12de3fdb25c4f46e692 Mon Sep 17 00:00:00 2001 From: fredtempez Date: Mon, 5 Apr 2021 15:01:42 +0200 Subject: [PATCH 09/14] news Effet blur --- module/news/view/index/index.css | 11 ++++------- module/news/view/index/index.php | 3 +-- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/module/news/view/index/index.css b/module/news/view/index/index.css index c462ebbd..01708395 100755 --- a/module/news/view/index/index.css +++ b/module/news/view/index/index.css @@ -27,13 +27,10 @@ } .newsBlur { - position: absolute; - bottom: -5%; - margin: -10px; - height: 20%; - width: 110%; - backdrop-filter: blur(1px); - -webkit-backdrop-filter: blur(1px); + background: linear-gradient(#333 70%,#FFF ); + background-clip: text; + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; } diff --git a/module/news/view/index/index.php b/module/news/view/index/index.php index d71aba33..62d28a53 100755 --- a/module/news/view/index/index.php +++ b/module/news/view/index/index.php @@ -5,9 +5,8 @@

    getUrl(0) . '/' . $newsId . '">' . $news['title'] . ''; ?>

    -
    +
    -
    From 9a8592cb6829933f78b50509ea644039eac48211 Mon Sep 17 00:00:00 2001 From: fredtempez Date: Mon, 5 Apr 2021 15:32:04 +0200 Subject: [PATCH 10/14] Search fonction initialisation --- module/search/ressource/defaultdata.php | 3 +- module/search/search.php | 52 ++++++++++++++++++++----- module/search/view/index/index.php | 4 +- 3 files changed, 47 insertions(+), 12 deletions(-) diff --git a/module/search/ressource/defaultdata.php b/module/search/ressource/defaultdata.php index 378c347c..bd10fb70 100755 --- a/module/search/ressource/defaultdata.php +++ b/module/search/ressource/defaultdata.php @@ -6,6 +6,7 @@ class init extends search { 'placeHolder' => 'Un ou plusieurs mots-clés séparés par un espace ou par +', 'submitText' => 'Rechercher', 'keywordColor' => 'rgba(229, 229, 1, 1)', - 'versionData' => '2.0' + 'versionData' => '2.0', + 'style' => '' ]; } \ No newline at end of file diff --git a/module/search/search.php b/module/search/search.php index 9050a8a9..17602377 100755 --- a/module/search/search.php +++ b/module/search/search.php @@ -51,35 +51,65 @@ class search extends common { * Appelée par les fonctions index et config */ private function update() { - // Création des valeurs de réglage par défaut - if ( !is_array($this->getData(['module', $this->getUrl(0), 'config']) ) ) { - require_once('module/search/ressource/defaultdata.php'); - $this->setData(['module', $this->getUrl(0), 'config', init::$defaultData]); - } - // Version 2.0 + + // Version 2.0 if (version_compare($this->getData(['module', $this->getUrl(0), 'config', 'versionData']), '2.0', '<') ) { - // Distinguer la config des autres données + $class = get_called_class(); + $moduleId = $this->getUrl(0); + // Données de l'instance $data = $this->getData(['module', $this->getUrl(0)]); $this->setData(['module', $this->getUrl(0), 'config', [ 'submitText' => $this->getData(['module', $this->getUrl(0), 'submitText']), 'placeHolder' => $this->getData(['module', $this->getUrl(0), 'placeHolder']), 'resultHideContent' => $this->getData(['module', $this->getUrl(0), 'resultHideContent']), 'previewLength' => $this->getData(['module', $this->getUrl(0), 'previewLength']), - 'keywordColor' => $this->getData(['module', $this->getUrl(0), 'keywordColor']) + 'keywordColor' => $this->getData(['module', $this->getUrl(0), 'keywordColor']), + 'style' => self::DATA_DIR . 'modules/' . $class . '/' . $moduleId . '.css', + 'versionData' => '2.0' ]]); $this->deleteData(['module', $this->getUrl(0), 'submitText']); $this->deleteData(['module', $this->getUrl(0), 'placeHolder']); $this->deleteData(['module', $this->getUrl(0), 'resultHideContent']); $this->deleteData(['module', $this->getUrl(0), 'previewLength']); $this->deleteData(['module', $this->getUrl(0), 'keywordColor']); - $this->setData(['module', $this->getUrl(0), 'config', 'versionData','2.0']); } } + /** + * Initialisation du module + * Appelée par les fonctions index et config + */ + private function init(){ + // Création des valeurs de réglage par défaut + if ( !is_array($this->getData(['module', $this->getUrl(0), 'config']) ) ) { + require_once('module/search/ressource/defaultdata.php'); + + $class = get_called_class(); + $moduleId = $this->getUrl(0); + // Sauver les données par défaut + init::$defaultData['style'] = self::DATA_DIR . 'modules/' . $class . '/' . $moduleId . '.css'; + $this->setData(['module', $this->getUrl(0), 'config', init::$defaultData]); + + $style = '.searchItem {background:' . $this->getData(['module', $this->getUrl(0), 'config', 'keywordColor']). ';}'; + + // Dossier de l'instance + if (!is_dir(self::DATA_DIR . 'modules/' . $class)) { + mkdir (self::DATA_DIR . 'modules/' . $class, 0777, true); + } + $success = file_put_contents(self::DATA_DIR . 'modules/' . $class . '/' . $moduleId . '.css' , $style ); + + + } + } + + // Configuration vide public function config() { + // Initialisation d'un nouveau module + $this->init(); + // Mise à jour des données de module $this->update(); @@ -128,6 +158,10 @@ class search extends common { } public function index() { + + // Initialisation d'un nouveau module + $this->init(); + // Mise à jour des données de module $this->update(); diff --git a/module/search/view/index/index.php b/module/search/view/index/index.php index 06434a7e..1b809245 100755 --- a/module/search/view/index/index.php +++ b/module/search/view/index/index.php @@ -4,13 +4,13 @@
    isset($_COOKIE['ZWII_I18N_SITE'] ) ? $this->getData(['module', $this->getUrl(0), 'placeHolder']):'Un ou plusieurs mots clef séparés par un espace', + 'placeholder' => isset($_COOKIE['ZWII_I18N_SITE'] ) ? $this->getData(['module', $this->getUrl(0), 'config', 'placeHolder']):'Un ou plusieurs mots clef séparés par un espace', 'value' => $module::$motclef ]); ?>
    $this->getData(['module', $this->getUrl(0), 'submitText']) + 'value' => $this->getData(['module', $this->getUrl(0), 'config', 'submitText']) ]); ?>
    From a1d934ad7b999aa48800974eeea28b10eaffc492 Mon Sep 17 00:00:00 2001 From: fredtempez Date: Mon, 5 Apr 2021 15:33:38 +0200 Subject: [PATCH 11/14] search initCSS --- module/search/search.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/module/search/search.php b/module/search/search.php index 17602377..102d7986 100755 --- a/module/search/search.php +++ b/module/search/search.php @@ -77,10 +77,10 @@ class search extends common { } /** - * Initialisation du module + * Initialisation du thème du module * Appelée par les fonctions index et config */ - private function init(){ + private function initCss(){ // Création des valeurs de réglage par défaut if ( !is_array($this->getData(['module', $this->getUrl(0), 'config']) ) ) { require_once('module/search/ressource/defaultdata.php'); @@ -108,7 +108,7 @@ class search extends common { public function config() { // Initialisation d'un nouveau module - $this->init(); + $this->initCss(); // Mise à jour des données de module $this->update(); @@ -160,7 +160,7 @@ class search extends common { public function index() { // Initialisation d'un nouveau module - $this->init(); + $this->initCss(); // Mise à jour des données de module $this->update(); From 77fc370e283e4ce3dcb8338d169232d1e52a1331 Mon Sep 17 00:00:00 2001 From: fredtempez Date: Mon, 5 Apr 2021 15:38:07 +0200 Subject: [PATCH 12/14] Fonction initCss --- module/gallery/gallery.php | 91 +++++++++++++++++++++----------------- 1 file changed, 51 insertions(+), 40 deletions(-) diff --git a/module/gallery/gallery.php b/module/gallery/gallery.php index 7ecdb7d2..e454dc7a 100755 --- a/module/gallery/gallery.php +++ b/module/gallery/gallery.php @@ -153,46 +153,6 @@ class gallery extends common { $class = get_called_class(); $moduleId = $this->getUrl(0); - // Installation des données de thème par défaut - if ( $this->getData(['module', $this->getUrl(0), 'config']) === null ) { - require_once('module/gallery/ressource/defaultdata.php'); - $this->setData(['module', $this->getUrl(0), 'config', theme::$defaultData]); - - // Dossier de l'instance - if (!is_dir(self::DATA_DIR . 'modules/' . $class)) { - mkdir (self::DATA_DIR . 'modules/' . $class, 0777, true); - } - - // Nom de la feuille de style - $fileCSS = self::DATA_DIR . 'modules/' . $class . '/' . $moduleId . '.css' ; - $this->setData(['module', $this->getUrl(0), 'config', 'style', $fileCSS]); - - // Créer le dossier du module - if (!is_dir(self::DATA_DIR . 'modules/' . $class)) { - mkdir (self::DATA_DIR . 'modules/' . $class, 0777, true); - } - - // Générer la feuille de CSS - $content = file_get_contents('module/gallery/ressource/vartheme.css'); - $themeCss = file_get_contents('module/gallery/ressource/theme.css'); - // Injection des variables - $content = str_replace('#thumbAlign#',$this->getData(['module', $this->getUrl(0), 'config', 'thumbAlign']),$content ); - $content = str_replace('#thumbWidth#',$this->getData(['module', $this->getUrl(0), 'config', 'thumbWidth']),$content ); - $content = str_replace('#thumbHeight#',$this->getData(['module', $this->getUrl(0), 'config', 'thumbHeight']),$content ); - $content = str_replace('#thumbMargin#',$this->getData(['module', $this->getUrl(0), 'config', 'thumbMargin']),$content ); - $content = str_replace('#thumbBorder#',$this->getData(['module', $this->getUrl(0), 'config', 'thumbBorder']),$content ); - $content = str_replace('#thumbBorderColor#',$this->getData(['module', $this->getUrl(0), 'config', 'thumbBorderColor']),$content ); - $content = str_replace('#thumbOpacity#',$this->getData(['module', $this->getUrl(0), 'config', 'thumbOpacity']),$content ); - $content = str_replace('#thumbShadows#',$this->getData(['module', $this->getUrl(0), 'config', 'thumbShadows']),$content ); - $content = str_replace('#thumbShadowsColor#',$this->getData(['module', $this->getUrl(0), 'config', 'thumbShadowsColor']),$content ); - $content = str_replace('#thumbRadius#',$this->getData(['module', $this->getUrl(0), 'config', 'thumbRadius']),$content ); - $content = str_replace('#legendAlign#',$this->getData(['module', $this->getUrl(0), 'config', 'legendAlign']),$content ); - $content = str_replace('#legendHeight#',$this->getData(['module', $this->getUrl(0), 'config', 'legendHeight']),$content ); - $content = str_replace('#legendTextColor#',$this->getData(['module', $this->getUrl(0), 'config', 'legendTextColor']),$content ); - $content = str_replace('#legendBgColor#',$this->getData(['module', $this->getUrl(0), 'config', 'legendBgColor']),$content ); - // Ecriture de la feuille de style - $success = file_put_contents(self::DATA_DIR . 'modules/' . $class . '/' . $moduleId . '.css' , $content . $themeCss); - } // Mise à jour d'une version inférieure if (version_compare($this->getData(['module', $this->getUrl(0), 'config', 'versionData']), '3.0', '<') ) { @@ -216,6 +176,51 @@ class gallery extends common { } } + /** + * Initialisation du thème d'un nouveau module + */ + private function initCSS() { + if ( $this->getData(['module', $this->getUrl(0), 'config']) === null ) { + require_once('module/gallery/ressource/defaultdata.php'); + $this->setData(['module', $this->getUrl(0), 'config', theme::$defaultData]); + + // Variables génériques + $class = get_called_class(); + $moduleId = $this->getUrl(0); + + // Dossier de l'instance + if (!is_dir(self::DATA_DIR . 'modules/' . $class)) { + mkdir (self::DATA_DIR . 'modules/' . $class, 0777, true); + } + + // Nom de la feuille de style + $fileCSS = self::DATA_DIR . 'modules/' . $class . '/' . $moduleId . '.css' ; + $this->setData(['module', $this->getUrl(0), 'config', 'style', $fileCSS]); + + // Générer la feuille de CSS + $content = file_get_contents('module/gallery/ressource/vartheme.css'); + $themeCss = file_get_contents('module/gallery/ressource/theme.css'); + + // Injection des variables + $content = str_replace('#thumbAlign#',$this->getData(['module', $this->getUrl(0), 'config', 'thumbAlign']),$content ); + $content = str_replace('#thumbWidth#',$this->getData(['module', $this->getUrl(0), 'config', 'thumbWidth']),$content ); + $content = str_replace('#thumbHeight#',$this->getData(['module', $this->getUrl(0), 'config', 'thumbHeight']),$content ); + $content = str_replace('#thumbMargin#',$this->getData(['module', $this->getUrl(0), 'config', 'thumbMargin']),$content ); + $content = str_replace('#thumbBorder#',$this->getData(['module', $this->getUrl(0), 'config', 'thumbBorder']),$content ); + $content = str_replace('#thumbBorderColor#',$this->getData(['module', $this->getUrl(0), 'config', 'thumbBorderColor']),$content ); + $content = str_replace('#thumbOpacity#',$this->getData(['module', $this->getUrl(0), 'config', 'thumbOpacity']),$content ); + $content = str_replace('#thumbShadows#',$this->getData(['module', $this->getUrl(0), 'config', 'thumbShadows']),$content ); + $content = str_replace('#thumbShadowsColor#',$this->getData(['module', $this->getUrl(0), 'config', 'thumbShadowsColor']),$content ); + $content = str_replace('#thumbRadius#',$this->getData(['module', $this->getUrl(0), 'config', 'thumbRadius']),$content ); + $content = str_replace('#legendAlign#',$this->getData(['module', $this->getUrl(0), 'config', 'legendAlign']),$content ); + $content = str_replace('#legendHeight#',$this->getData(['module', $this->getUrl(0), 'config', 'legendHeight']),$content ); + $content = str_replace('#legendTextColor#',$this->getData(['module', $this->getUrl(0), 'config', 'legendTextColor']),$content ); + $content = str_replace('#legendBgColor#',$this->getData(['module', $this->getUrl(0), 'config', 'legendBgColor']),$content ); + // Ecriture de la feuille de style + $success = file_put_contents(self::DATA_DIR . 'modules/' . $class . '/' . $moduleId . '.css' , $content . $themeCss); + } + } + /** * Tri de la liste des galeries @@ -274,6 +279,10 @@ class gallery extends common { * Configuration */ public function config() { + + // Initialisation du thème d'un nouveau module + $this->initCss(); + // Mise à jour des données de module $this->update(); @@ -556,6 +565,8 @@ class gallery extends common { * Accueil (deux affichages en un pour éviter une url à rallonge) */ public function index() { + // Initialisation du thème du nouveau module + $this->initCss(); // Mise à jour des données de module $this->update(); // Images d'une galerie From 687a98df15deac9820bf9dc353a7ccf6481f26c5 Mon Sep 17 00:00:00 2001 From: fredtempez Date: Mon, 5 Apr 2021 15:41:42 +0200 Subject: [PATCH 13/14] =?UTF-8?q?Ic=C3=B4ne=20search?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/vendor/zwiico/css/zwiico-codes.css | 1 + core/vendor/zwiico/css/zwiico-embedded.css | 13 +++++++------ core/vendor/zwiico/css/zwiico-ie7-codes.css | 1 + core/vendor/zwiico/css/zwiico-ie7.css | 1 + core/vendor/zwiico/css/zwiico.css | 15 ++++++++------- core/vendor/zwiico/font/zwiico.eot | Bin 21304 -> 21492 bytes core/vendor/zwiico/font/zwiico.svg | 2 ++ core/vendor/zwiico/font/zwiico.ttf | Bin 21144 -> 21332 bytes core/vendor/zwiico/font/zwiico.woff | Bin 13360 -> 13512 bytes core/vendor/zwiico/font/zwiico.woff2 | Bin 11444 -> 11480 bytes 10 files changed, 20 insertions(+), 13 deletions(-) diff --git a/core/vendor/zwiico/css/zwiico-codes.css b/core/vendor/zwiico/css/zwiico-codes.css index 9c7b0e02..eda6869e 100755 --- a/core/vendor/zwiico/css/zwiico-codes.css +++ b/core/vendor/zwiico/css/zwiico-codes.css @@ -38,6 +38,7 @@ .zwiico-mimi:before { content: '\e823'; } /* '' */ .zwiico-divide:before { content: '\e824'; } /* '' */ .zwiico-flag:before { content: '\e825'; } /* '' */ +.zwiico-search:before { content: '\e826'; } /* '' */ .zwiico-spin:before { content: '\e831'; } /* '' */ .zwiico-twitter:before { content: '\f099'; } /* '' */ .zwiico-facebook:before { content: '\f09a'; } /* '' */ diff --git a/core/vendor/zwiico/css/zwiico-embedded.css b/core/vendor/zwiico/css/zwiico-embedded.css index 36707b09..ad17bb2e 100755 --- a/core/vendor/zwiico/css/zwiico-embedded.css +++ b/core/vendor/zwiico/css/zwiico-embedded.css @@ -1,15 +1,15 @@ @font-face { font-family: 'zwiico'; - src: url('../font/zwiico.eot?55150548'); - src: url('../font/zwiico.eot?55150548#iefix') format('embedded-opentype'), - url('../font/zwiico.svg?55150548#zwiico') format('svg'); + src: url('../font/zwiico.eot?65225042'); + src: url('../font/zwiico.eot?65225042#iefix') format('embedded-opentype'), + url('../font/zwiico.svg?65225042#zwiico') format('svg'); font-weight: normal; font-style: normal; } @font-face { font-family: 'zwiico'; - src: url('data:application/octet-stream;base64,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') format('woff'), - url('data:application/octet-stream;base64,AAEAAAAPAIAAAwBwR1NVQiCLJXoAAAD8AAAAVE9TLzJ3sVO/AAABUAAAAFZjbWFwhV6NdwAAAagAAAS+Y3Z0IAAAAAAAAEPgAAAADmZwZ21iLvl6AABD8AAADgxnYXNwAAAAEAAAQ9gAAAAIZ2x5ZtNa3IIAAAZoAAA23GhlYWQb7SZTAAA9RAAAADZoaGVhB38DywAAPXwAAAAkaG10eL79/+4AAD2gAAAA3GxvY2FKy1cIAAA+fAAAAHBtYXhwAhUPhwAAPuwAAAAgbmFtZV7wsFsAAD8MAAACtXBvc3Ti4d+2AABBxAAAAhNwcmVwfrY7tgAAUfwAAACcAAEAAAAKADAAPgACREZMVAAObGF0bgAaAAQAAAAAAAAAAQAAAAQAAAAAAAAAAQAAAAFsaWdhAAgAAAABAAAAAQAEAAQAAAABAAgAAQAGAAAAAQAAAAEDeQGQAAUAAAJ6ArwAAACMAnoCvAAAAeAAMQECAAACAAUDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFBmRWQAwCGR8jEDUv9qAFoDWACWAAAAAQAAAAAAAAAAAAUAAAADAAAALAAAAAQAAAImAAEAAAAAASAAAwABAAAALAADAAoAAAImAAQA9AAAAB4AEAADAA4hkegl6DHwmvDJ8Nzw4fDu8SHxLvFn8W3x/PIx//8AACGR6ADoMfCZ8Mnw3PDg8O3xIfEu8WfxbfH88jH//wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAeAB4AaABoAGoAagBqAGwAbgBuAG4AbgBuAG4AAAABAAIAAwAEAAUABgAHAAgACQAKAAsADAANAA4ADwAQABEAEgATABQAFQAWABcAGAAZABoAGwAcAB0AHgAfACAAIQAiACMAJAAlACYAJwAoACkAKgArACwALQAuAC8AMAAxADIAMwA0ADUANgAAAQYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAACmAAAAAAAAAA2AAAhkQAAIZEAAAABAADoAAAA6AAAAAACAADoAQAA6AEAAAADAADoAgAA6AIAAAAEAADoAwAA6AMAAAAFAADoBAAA6AQAAAAGAADoBQAA6AUAAAAHAADoBgAA6AYAAAAIAADoBwAA6AcAAAAJAADoCAAA6AgAAAAKAADoCQAA6AkAAAALAADoCgAA6AoAAAAMAADoCwAA6AsAAAANAADoDAAA6AwAAAAOAADoDQAA6A0AAAAPAADoDgAA6A4AAAAQAADoDwAA6A8AAAARAADoEAAA6BAAAAASAADoEQAA6BEAAAATAADoEgAA6BIAAAAUAADoEwAA6BMAAAAVAADoFAAA6BQAAAAWAADoFQAA6BUAAAAXAADoFgAA6BYAAAAYAADoFwAA6BcAAAAZAADoGAAA6BgAAAAaAADoGQAA6BkAAAAbAADoGgAA6BoAAAAcAADoGwAA6BsAAAAdAADoHAAA6BwAAAAeAADoHQAA6B0AAAAfAADoHgAA6B4AAAAgAADoHwAA6B8AAAAhAADoIAAA6CAAAAAiAADoIQAA6CEAAAAjAADoIgAA6CIAAAAkAADoIwAA6CMAAAAlAADoJAAA6CQAAAAmAADoJQAA6CUAAAAnAADoMQAA6DEAAAAoAADwmQAA8JkAAAApAADwmgAA8JoAAAAqAADwyQAA8MkAAAArAADw3AAA8NwAAAAsAADw4AAA8OAAAAAtAADw4QAA8OEAAAAuAADw7QAA8O0AAAAvAADw7gAA8O4AAAAwAADxIQAA8SEAAAAxAADxLgAA8S4AAAAyAADxZwAA8WcAAAAzAADxbQAA8W0AAAA0AADx/AAA8fwAAAA1AADyMQAA8jEAAAA2AAAAAgAA/7oDSAMCAAgAFABEQEEFAQMEAgQDAoAGAQIHBAIHfggBAAAEAwAEZwAHAQEHVwAHBwFhAAEHAVEBABQTEhEQDw4NDAsKCQUEAAgBCAkGFisBMhYQBiAmEDYTMzUjNSMVIxUzFTMBpK729v6k9vbiyMhmyspmAwL2/qT29gFc9v4qZsrKZsoAAAACAAD/+QNrAsMAJwBAAEJAPxQBAgEBTAAGAgUCBgWAAAUDAgUDfgAEAwADBACAAAEAAgYBAmcAAwQAA1cAAwMAXwAAAwBPFiMZJSolJwcGHSslFBYPAQ4BByMiJjURNDY7ATIWFRcWDwEOAScjIgYHERQWFzMyHgIBFAcBBiImPQEjIiY9ATQ2NzM1NDYWFwEWAWUCAQIBCAiyQ15eQ7IICgEBAQIBCAiyJTQBNiS0BgIGAgIGC/7RCxwW+g4WFg76FhwLAS8LLgISBQ4JBAFeQwGIQ14KCAsJBg0HCAE0Jv54JTQBBAIIASwOC/7QChQPoRYO1g8UAaEOFgIJ/tAKAAAAAAEAAP/5AxIDCwAjAClAJgAEAwSFAAEAAYYFAQMAAANXBQEDAwBfAgEAAwBPIzMlIzMjBgYcKwEVFAYnIxUUBgcjIiY3NSMiJic1NDY3MzU0NjsBMhYXFTMyFgMSIBboIBZrFiAB6BceASAW6B4XaxceAegXHgG3axYgAekWHgEgFekeF2sXHgHoFiAgFuggAAEAAP/vAtQChgAkAB5AGyIZEAcEAAIBTAMBAgAChQEBAAB2FBwUFAQGGislFA8BBiIvAQcGIi8BJjQ/AScmND8BNjIfATc2Mh8BFhQPARcWAtQPTBAsEKSkECwQTBAQpKQQEEwQLBCkpBAsEEwPD6SkD3AWEEwPD6WlDw9MECwQpKQQLBBMEBCkpBAQTA8uD6SkDwAD//3/sQNfAwsADwA3AEQASEBFKQEFAwkBAgEAAkwABAIDAgQDgAADBQIDBX4ABwACBAcCaQAFAAABBQBnAAEGBgFXAAEBBmEABgEGURUeKxMWJiYjCAYeKyU1NCYrASIGHQEUFjsBMjYTNC4BIyIHBh8BFjMyNz4BMhYVFAYHDgEXFRQWOwEyNjQ2PwE+AxcUDgEiLgI+ATIeAQH0CghrCAoKCGsICo8+XDGIRwkNSgQGCQUeJTgqFhsjPAEKCGsIChgSHAoeFAzXcsboyG4Gerz0un5SawgKCghrCAoKAX8xVC53DQs3BAcmGx4SFRoMD0IlFAgKChIiCxAGGhwoUnXEdHTE6sR0dMQAAQAAAAADEgHtAA8AGEAVAAEAAAFXAAEBAF8AAAEATzUzAgYYKwEVFAYnISImJzU0NjchMhYDEiAW/VoXHgEgFgKmFx4Bt2sWIAEeF2sXHgEgAAAAAgAA/7EDWgMLAAgAagBFQEJlWUxBBAAEOwoCAQA0KBsQBAMBA0wABQQFhQYBBAAEhQAAAQCFAAEDAYUAAwIDhQACAnZcW1NRSUgrKiIgExIHBhgrATQmIg4BFjI2JRUUBg8BBgcWFxYUBw4BJyIvAQYHBgcGKwEiJjUnJicHBiInJicmNDc+ATcmLwEuASc1NDY/ATY3JicmNDc+ATMyHwE2NzY3NjsBMhYfARYXNzYyFxYXFhQHDgEHFh8BHgECO1J4UgJWdFYBHAgHaAoLEygGBQ9QDQcHTRkaCQcEEHwIDBAbF08GEAZGFgQFCCgKDwhmBwgBCgVoCA4XJQYFD1ANBwhNGBoJCAMRfAcMAQ8cF08FDwdIFAQECSgKDwhmBwoBXjtUVHZUVHh8BwwBEB4VGzIGDgYVUAEFPA0ITBwQCgdnCQw8BQZAHgUOBgwyDxwbDwEMB3wHDAEQGRogLQcMBxRQBTwNCEwcEAoHZwkLOwUFQxwFDgYMMg8cGhABDAAAAAQAAP+xA00C/wAGABQAGQAkAIZAFx4BAgUdFg4HBAMCGQMCAwADAQEBAARMS7ASUFhAJwAFAgWFAAIDAoUAAwADhQAAAQEAcAYBAQQEAVcGAQEBBGAABAEEUBtAJgAFAgWFAAIDAoUAAwADhQAAAQCFBgEBBAQBVwYBAQEEYAAEAQRQWUASAAAhIBgXEA8JCAAGAAYUBwYXKxc3JwcVMxUBNCMiBwEGFRQzMjcBNicXASM1ARQPASc3NjIfARbLMoMzSAFfDAUE/tEEDQUEAS8DHuj+MOgDTRRd6F0UOxaDFAczgzM8RwIGDAT+0gQGDAQBLgRx6P4v6QGaHRVd6VwVFYMWAAAAAAEAAAAAA7YCRgAUABlAFgUBAAIBTAACAAKFAQEAAHYXFBIDBhkrJQcGIicJAQYiLwEmNDcBNjIXARYUA6tcCx4K/tj+2AscC10LCwGeCxwLAZ4La1wKCgEp/tcKClwLHgoBngoK/mILHAAAAAMAAP/5A+gCfQARACIAMwBGQEMLAgIEAg0BAAMCTAAEAgMCBAOAAAMAAgMAfgAAAQIAAX4ABgACBAYCaQABBQUBWQABAQVhAAUBBVEXFiQUFRgWBwYdKwEmJxYVFAYuATU0NwYHHgEgNgE0JgciBhUUFjI2NTQ2MzI2BRQHBgQgJCcmNDc2LAEEFxYDoVWAIpLQkiKAVUvgAQTi/rcQC0ZkEBYQRDALEAHZC07++P7a/vhOCwtOAQgBJgEITgsBOoRBOkNnlAKQaUM6QYRyiIgBSQsQAWRFCxAQCzBEEMwTE4GamoETJhSAmgKefhQAAAQAAP/5A6EDUgAIABEAJwA/AElARjwBBwgJAAICAAJMAAgHCIUJAQcDB4UABgMEAwYEgAAEAAIEWQUBAwEBAAIDAGkABAQCXwACBAJPPz0kJRYiEiU5GBIKBh8rJTQuAQ4BFj4BNzQuAQ4BFj4BNxUUBgchIiYnNTQ2MyEXFjI/ASEyFgMWDwEGIi8BJjc2OwE1NDY3MzIWBxUzMgLKFB4UAhgaGI0UIBICFhwYRiAW/MsXHgEgFgEDSyFWIUwBAxYgtgoS+goeCvoRCQoXjxYOjw4WAY8YZA8UAhgaGAIUDw8UAhgaGAIUjLMWHgEgFbMWIEwgIEwgASgXEPoLC/oQFxX6DxQBFg76AAAC////+QQZAwsAEgApACxAKQADBAOFAAECAAIBAIAAAACEAAQCAgRXAAQEAl8AAgQCTyM6IzY1BQYbKwEUDwEOASMhIi4BPwE+ATMhMhYnFSEiBg8CJyY3ETQ2OwEyFh0BITIWBBkSuxhWJv2hExwBEbwYViUCXxMewP4wNXIjvAIBAQFKM7MzSgEvNEgBPxEU3RwoDiIU3RwoDq9aNCndAwcFAgIYM0pKMxJKAAAAAAb///9qBC8DUgARADIAOwBEAFYAXwBvQGxPDgIDAgFMEQEJCwmFAAsIC4UQAQgCCIUPAQIDAoUHAQUAAQAFAYAMCgIBBgABBn4ABgQABgR+AAQEhA4BAwAAA1kOAQMDAGENAQADAFFeXVpZVlRSUEtKSUdDQj8+OjkZFRQZNyMTIRASBh8rAQYHIyImNzQzMh4BNzI3BhUUARQGIyEiJic0PgUzMh4CPgE/ATY3Mh4EFwEUBiImNDYyFgEUBi4BPgIWBRQGJyMmJzY1NCcWMzI+ARcyJxQGIiY0NjIWAUtaOkstQAFFBCpCISYlAwKDUkP+GERQAQQMECAmOiEGJC5IUEYZKRAIIjgmIBAOAf3GVHZUVHZUAYl+sIACfLR6AUM+Lks5Wi0DJSUhRCgERUdUdlRUdlQBXgNELCzFFhoBDRUQTv5bQk5OQh44Qjg0JhYYHBoCFhAaCgIWJjQ4QhwCjztUVHZUVP7vWX4CerZ4BoTTKy4BRANBThAVDRgYAY87VFR2VFQAAQAAAAABZwJ8AA0AF0AUAAEAAQFMAAEAAYUAAAB2FxMCBhgrAREUBiIvASY0PwE2MhYBZRQgCfoKCvoLHBgCWP4MDhYL+gscC/oLFgAAAAAD////sQPoAsMAGQA5AEkAQEA9GxIBAwMCEwACAQACTAADAgACAwCAAAABAgABfgAFAAIDBQJnAAEEBAFXAAEBBF8ABAEETzU9LRkqKQYGHCslEQYHBgcOAicjIi4BJyYnJicRFBY3ITI2EzUvASYGJyEiBgcUFxYXHgQ3MzI+Azc2Nz4BNxEUBgchIiY3ETQ2MyEyFgOhEhWVWRwkPBsCGj4iHViWFRIMBgM2BwoBAgMDBAb8ygcKAVNrdAQgEiAYDAILGh4UHgV0bB40RzQl/MokNgE0JQM2JTQLAawUEHNKGBoeAhoeFkpzEBT+VAcMAQoCUg4OBQUCAwwGXkFUXAMcDhQMAQoWDB4CXFQYUjX9oSU0ATYkAl8lNDQAAAACAAD/sQLKAwwAFQAeACVAIgAFAQWFAwEBBAGFAAQCBIUAAgAChQAAAHYTFxERFzIGBhwrJRQGIyEiJjU0PgMXFjI3Mh4DAxQGIi4BNh4BAspGMf4kMUYKGCo+LUnKSipCJhwIj3y0egSCrIRFPFhYPDBUVjwoAUhIJj5UVgHAWH5+sIACfAAAAgAA/7EDWwMLACQARwBdQFpDJQIGCS8BBQYXAQMCCAEBAwRMAAkIBggJBoAHAQUGAgYFAoAEAQIDBgIDfgABAwADAQCAAAgABgUIBmkAAwEAA1kAAwMAYQAAAwBRRkUmJSU2JSY1FCQKBh8rARQVDgEjIiYnBwYiJj0BNDY7ATIWBg8BHgE3MjY3Njc2OwEyFhMVFAYrASImNj8BJiMiBgcGBwYrASImNzU+ATMyFhc3NjIWA0sk5JlRmDxICxwWFg76DhYCCU0oZDdKgicGGAQMawgKDhQQ+g4WAglNUnBLgicGFwUMbwcMASTmmVGaPEgLHBgBBQMBlro+OUgLFg76DhYWHAtNJCoBSj4KOA0MAbj6DhYWHAtNTUo+CjgNDAYElro+OUgLFgAAAgAA//kDkgLFABAAMQAuQCsuJiUYFQ8ODQgBAwwBAAECTAQBAwEDhQABAAGFAgEAAHYqKCMiIREUBQYZKwERFAYHIzUjFSMiJicRCQEWNwcGByMiJwkBBiYvASY2NwE2Mh8BNTQ2OwEyFh0BFxYUAxIWDtaP1g8UAQFBAUEBfCIFBwIHBf5+/n4HDQUjBAIFAZESMBOICghrCAp6BgEo/vUPFAHW1hYOAQ8BCP74ASQpBQEDAUL+vgQCBSkGDgUBTg8PcWwICgoI42YEEAAAAAMAAP+AAvgDQAALAB8AKwB7tQMBAAIBTEuwE1BYQC0ABwUEBAdyAAACAQIAAYAAAQGEAAMABQcDBWcGAQQCAgRXBgEEBAJiAAIEAlIbQC4ABwUEBQcEgAAAAgECAAGAAAEBhAADAAUHAwVnBgEEAgIEVwYBBAQCYgACBAJSWUALERIyEjgaFREIBh4rExYgNwMOAiIuAScBHgEdARQGICY9ATQ2PwE2OwEyFwczLgErASIPATM3MzJ6AaB6NgJChpSERAIBsl6A4P7I4IBeKhYwXDQSDFRcGhJmFgpqVEBSAcpGRv4aDiwqKiwOAxISSiIKOlJSOgoiShIwGhqgbiAQfkIAAQAAAAACPAHtAA4AF0AUAAEAAQFMAAEAAYUAAAB2NRQCBhgrARQPAQYiLwEmNDYzITIWAjsK+gscC/oLFg4B9A4WAckOC/oLC/oLHBYWAAABAAD/kwPoAykABgAdQBoFAQFJAAABAIUDAgIBAXYAAAAGAAYREQQGGCs1ESERIQU1A+j+J/7AYALJ/TfNzQAAAgAA/7AD6ALDACUASwA/QDxJHAIAAT8BAwApAQIDA0wKAQMBSzIBAkkAAQABhQAAAwCFAAMCAgNZAAMDAmEAAgMCUUJAPjwjIiMEBhcrARQOASMiJwYHBgcjIiY1JjQ2NT8CNgc3PgI3LgEnND4BMh4BFxQGBx4BHwEWHwMUBw4BJyYnJicGIyInFjMyNjc+ASc0Jx4BAxJqtGswMkZVFRsCBgwBAgEEAwMBHAUODgRFTgFqtNa0atZQRAUMCBsJBAUEAwECCgccFFZGMjCXcCARWqRCRUwBDUhUAaVNhEwJMRcFBAoHAQQEAQMGAwMBHgUYEhAodENOhExMhNxDdicOFgohCwMFBgoBAggKAQQFFzEJSgMyLzSGSisqJ3gABQAA/8MD6AKxAAkAGgA+AEQAVwBXQFQ0GwIABFMGAgIAUkMCAQJQQiknCAEGBgEETAAFBAWFAAIAAQACAYAAAQYAAQZ+AAYDAAYDfgADA4QABAAABFkABAQAYQAABABRTEsTLhkkFB0HBhwrJTcuATc0NwYHFgE0JgciBhUUFjI2NTQ2MzI2NxQVBgIPAQYjIicmNTQ3LgEnJjQ3PgEzMhc3NjMyFh8BFgcWExQGBxMWFxQHBgcOASM3PgE3Jic3HgEXFgE2KzA4ASKAVV4BahALRmQQFhBEMAsQyjvqOxwFCgdECRlQhjILC1b8lzIyHwUKAw4LJAsBCRVYSZ0E+gsWJ1TcfCl3yEVBXSM1YiALaU8jaj1DOkGEkAFnCxABZEULEBALMEQQdQQBaf5aaTIJJwYKByokeE0RKhKDmAo2CQYGFAYBBf79ToAbARgZXhMTJC1gakoKhGlkQD8kYjYTAAABAAD/5wO2AikAFAAZQBYNAQABAUwCAQEAAYUAAAB2FBcSAwYZKwkBBiInASY0PwE2MhcJATYyHwEWFAOr/mIKHgr+YgsLXQoeCgEoASgLHAxcCwGP/mMLCwGdCx4KXAsL/tgBKAsLXAscAAAEAAD/sQOhAy4ACAARACkAQABGQEM1AQcGCQACAgACTAAJBgmFCAEGBwaFAAcDB4UABAACBFcFAQMBAQACAwBpAAQEAl8AAgQCTz08IzMjIjIlORgSCgYfKyU0Jg4CHgE2NzQmDgIeATY3FRQGIyEiJic1NDYXMx4BOwEyNjczMhYDBisBFRQGByMiJic1IyImPwE2Mh8BFgLKFB4UAhgaGI0UIBICFhwYRiAW/MsXHgEgFu4MNiOPIjYN7hYgtgkYjxQPjw8UAY8XExH6Ch4K+hIdDhYCEiASBBoMDhYCEiASBBqJsxYgIBazFiABHygoHx4BUhb6DxQBFg76LBH6Cgr6EQAAAAAGAAD/tgPoAwYAJwAwAFgAgACLAJYAuEC1RQ8OBwYFBQBWVVNRTEpJERAFBAsDBWhlZGNfXlRQT0sVFAEADgIDaWddJRgFCAKBbSQiGxkGBwZ+fXt5dHEjGggBBwZMYAECagEIAktCQUA/PTw7ODc2NQsJSnx4d3NyBQFJAAkACYUABQADAAUDgAAIAgYCCAaAAAYHAgYHfgAHAQIHAX4EAQAAAwIAA2kAAggBAlkAAgIBXwABAgFPlZOKiG9uW1pHRjMyLy4rKh8eGgoGFys9ATc2Nyc3FzY/ATMXFhc3FwcWHwEVBwYHFwcnBg8BIycmJwcnNyYnNxQWPgIuAQYlNxc2Nyc3FzY/ARcHFhc3FwcWHwEHIwYHFwcnBg8BJzUmJwcnNyYnAzczNjcnNxc2PwEXFRYXNxcHFh8BByMGBxcHJwYPASc1JicHJzcmJzcGHgE+ASYnIyIGEwYeAT4BJicjIgZeCA88REoaHQhhCh0aSkQ8EAdeXgcQPERKGh0KYQgdGkpEPA8IfzRMMgI2SDgBQAhGCAwlNjEUFQ5IAhYROS0xCgJECEQIDic4LxYVDkYUETstMQgEJQYxBggaJSQNEAowEAwpHyMGBC8GMQQKHCgjDRAKMQ0OKR8jBgJFBBgoHAYaEgYRHBIEJDYqBCAcBxok9WEIHhlKRT0QB15eBxA9RUoZHghhCh0aSEY8DwheXggPPEZIGh07JTYCMk4wBDjLSAIWETktMQoEQghECA4nNjEUFw5GFBE7LTEIBEIGRggMJTYxFBX+UTIQDCshJQgCMAUxBgobKSMNEAwzDwwrISUIAjEGMwQKHCkkDRAZFR4EFi4YBhgBsBsqCCY0LAIiAAABAAD/wAKYA0QAFAAXQBQBAQABAUwAAQABhQAAAHYXFwIGGCsJAhYUDwEGIicBJjQ3ATYyHwEWFAKO/tcBKQoKXQscC/5iCwsBngoeCl0KAqr+2P7XCh4KXQoKAZ8KHgoBngsLXQoeAAEAAP/PA4MDCwAeACBAHRgPAgABAUwAAgEChQMBAQABhQAAAHYVNRcUBAYaKwEUBwEGIicBJjQ/ATYyHwERNDY3MzIWFRE3NjIfARYDgxX+lRY6Ff6VFRUpFjoVpCoeRx0qpRQ7FikVAYIeFP6UFRUBbBQ7FikVFaQBiR0qASwc/nekFRUpFgAGAAD/cgQvA0kACAASABsAegC2APEAnECZ7tkCBA5qXQIFCNC8cAMABb6soHVSTEUjHQkBALOeQAMCATotAgYClYACCwMHTOfbAg5KggELSQoBCAkFCQgFgAAGAgcCBgeAAA4ABAkOBGkACQgACVcABQ0BAAEFAGkAAgYBAlkMAQEABwMBB2cAAwsLA1kAAwMLYQALAwtR5ePHxqqoi4ptbGRiWlk0MisqExQUFBMSDwYcKwE0JiIGFBYyNgU0Jg4BFxQWMjYDNCYiBh4BMjYHFRQGDwEGBxYXFhQHDgEiLwEGBwYHBisBIiY1JyYnBwYiJyY1NDc+ATcmLwEuAT0BNDY/ATY3JicmNDc+ATMyHwE2NzY3NjsBMhYfARYXNzYyFxYVFA8BBgcWHwEeAQEVFAcGBxYVFAcGIyIvAQYiJw4BByInJjU0NyYnJj0BNDc2NyY1ND8BNjMyFhc3FzY/ATIXFhUUBxYXFhEVFAcGBxYVFAcGIyImJwYiJw4BIicmNTQ3JicmPQE0NzY3JjU0PwE2MzIWFzcXNj8BMhcWFRQHFhcWAfRUdlRUdlQBrSw4LAEqOiwBLDgsASo6LNgIBFcGDBMfBAQMRBAFQBUWBgcEDWgGCg0TF0IEDQZQBAUkCA0HVQUICAVWBwsTHwQEDEQKBgZAExgGBwMNaAYKAQ0TF0EFDQVRBBgRCA0GVQYGAWZTBgocAkQBBRUdCwwLBywDAUQDHQoHU1MHCh0DNBABBCoIEREcFwQCQwIcCQdTUwYKHAJEAQUqCAsMCwcsBEQDHQoHU1MHCh0DNBABBCoIEREcFwQCQwIcCQdTAV47VFR2VFTjHSwCKB8dKioCWR0qKjsqKs1nBgoBDhMXGyUGDAQRQgQyCwY8Gw0IBlUGDDIEBEsPBQUILAwYFg0BCAdoBQoBDhMXGyUGDAUQQgQyCgg8Gg0IBlUGCzEEBEsPBAYeFQ0bEwwCCP7PTgkIDw4/DgICKBslAQELNAEoAgIOPw4PCAlOCQkQDT8OAgIeCTQMAQEoFwEnAgIOPw0QCQIzTgkJDw4/DgICJzQMAQEMNCcCAg4/Dg8JCU4JCBANPw4CAh4JNAsBAScXAScCAg4/DRAIAAABAAD/sQODAucAHgAgQB0QBwIAAwFMAAMAA4UCAQABAIUAAQF2FxU1FAQGGisBFA8BBiIvAREUBgcjIiY1EQcGIi8BJjQ3ATYyFwEWA4MVKRY7FKUoH0ceKqQUPBQqFRUBaxQ8FQFrFQE0HBYqFRWk/ncdJAEmHAGJpBUVKhU7FQFrFRX+lRYAA////2oD6ANSAA8AHwA7AIpADyMBBAUrAQIGAAkBAQcDTEuwDFBYQC8ABAUDBQRyAAgABQQIBWcAAwAABgMAZwAGAAcBBgdnAAECAgFXAAEBAl8AAgECTxtAMAAEBQMFBAOAAAgABQQIBWcAAwAABgMAZwAGAAcBBgdnAAECAgFXAAEBAl8AAgECT1lADDUhJhQTNTYXIwkGHysFETQmIyEiBhURFBYXITI2ExEUBiMhIiYnETQ2FyEyFicVIzU0JichIgYHERQWOwEVIyImNxE0NjMhMhYDoQwG/aEICgoIAl8HCkg0Jf2hJTQBNiQCXyU01kgKCP2hBwoBDAZaWiQ2ATQlAl8lNj0CXwgKCgj9oQcKAQwCZf2hJTQ0JQJfJTYBNLFaWgcKAQwG/aEICkg2JAJfJTQ0AAAAAAIAAP+6A0gDAgAIAAwAJkAjBAEAAgCFAAIDAoUAAwEDhQABAXYBAAwLCgkFBAAIAQgFBhYrATIWEAYgJhA2ASEVIQGkrvb2/qT29gGq/ggB+AMC9v6k9vYBXPb+kGYAAAEAAAAAA6UCmAAVAB1AGg8BAAEBTAACAQKFAAEAAYUAAAB2FBcUAwYZKwEUBwEGIicBJjQ/ATYyHwEBNjIfARYDpRD+IBAsEP7qDw9MECwQpAFuECwQTBACFhYQ/iAPDwEWECwQTBAQpQFvEBBMDwAEAAD/sQOhAsMADAAZADMAWgBLQEhZUk5HBAIIDQACAAMCTAkBBwgHhQAIAgiFBAECAwKFAAMAA4UBAQAFAIUABQYGBVcABQUGYQAGBQZRVVQjHUs3IhIrHBMKBh8rJRQOAS4DPgIeAQUUDgEuAz4CHgEXNCYjIgcGIicmIyIGBxQeAzczMj4DNxQHDgQHIi4EJyY1NDcmNTQ3MhYXNjMyFz4BNxYVFAcWAWUOIi4kDAIQIDIeEgFjDiIuJAwCECAyHhJYTkEXVihgJ1UYQkwBJDZSSi5eLkpSOCJ+IhZKVGpWMitIXE5MOhMjTA8cPVo9UlpTSjpcOx0PTKsWLigCJDIoNCIEKiwYFi4oAiQyKDQiBCosGENeDAYGDF5DMUgsFgwCCBooTJJ0RSs+IhQEAQQKGCI4JEV0hFktMkA5LC8UEi4qATlAMS1ZAAIAAP/5A1kCxAAYAEAAUEBNDAEBAgFMIQEAAUsAAwcGBwMGgAACBgEGAgGAAAEFBgEFfgAABQQFAASAAAcABgIHBmcABQAEBVcABQUEXwAEBQRPLCUqJxMWIxQIBh4rARQHAQYiJj0BIyImJzU0NjczNTQ2FhcBFjcRFAYrASImNycmPwE+ARczMjYnETQmByMiNCY2LwEmPwE+ARczMhYClQv+0QseFPoPFAEWDvoUHgsBLwvEXkOyBwwBAQEBAgEICLIlNgE0JrQGCgICAQEBAgEICLJDXgFeDgv+0AoUD6EWDtYPFAGhDhYCCf7QCrX+eENeCggLCQYNBwgBNiQBiCU2AQQCCAQLCQYNBwgBXgAAAAIAAP/5AoMDCwAHAB8AKkAnBQMCAAECAQACgAACAoQABAEBBFkABAQBYQABBAFRIxMlNhMQBgYcKxMhNTQmDgEXBREUBgchIiYnETQ2FzM1NDYyFgcVMzIWswEdVHZUAQHQIBb96RceASAWEZTMlgISFx4BpWw7VAJQPaH+vhYeASAVAUIWIAFsZpSUZmweAAMAAP9qA40DUgAXACQALQA5QDYAAwQABAMAgAAAAIQAAQYBAgUBAmkABQQEBVkABQUEYQAEBQRRGRgsKygnHx4YJBkkGxUHBhgrARQHBgcGIicmJyY1NDY3Njc2MhcWFx4BASIOARQeATI+ATQuARcUBiImNDYyFgONPjxnavZrZj0+Rz5BUFe0V09BPkf+OkV1RUV1inVERHUWNUw1NUw1AR53ZWM6Ozs6Y2V3WsdTWDI2NjJYU8cBMkR1inVFRXWKdUT+JjU1TDQ0AAMAAP+wA0MDDAAFAAsAGAAsQCkAAAABBAABaQAEAAUCBAVnAAIDAwJZAAICA2EAAwIDUTMzIRIhEQYGHCsBNDIUByIRNDIUByIBNDY3ITIeAQYjISImASzqdnTqdnT+1DwsAnEsPAJAKv2PLDwCl3XqAf4FdeoBAa4rPAE+VD4+AAAAAAIAAP+xA+gDCwARADcAPEA5CwICBgUDAQAEAkwAAQUBhQcBBQYFhQAGAwaFAAMCA4UAAgQChQAEAASFAAAAdiQTKCIjJxgWCAYeKxMUBxEUBgcjIiYnESY1NDYyFgURFAYHBiMiLgIjIgcGIyImNxE0NzY3NjMyFhcWMjY/ATYzMhazJAoIJAcKASMqOiwDNA4PeFYiRjJQJ2uYCgkOFgERDCCEZzxoRhU6RhsxFggPFALDKBX9PQcKAQwGAsMVKB4qKkL+Vw4QB0EYHhhRBRQPAZ8RDQgQQyAhCxgOGgwUAAAAAAX/+v9qA+kDWAAfADwAWgB4AJgAR0BEagEFA5MBBAICTCsBAEoAAAEAhQABAwGFAAMFA4UAAgUEBQIEgAAFAgQFWQAFBQRhAAQFBFGRj399dXNnZUpIMC4GBhYrNzEjLgEnJjY3PgEXMhUXHgEHDgEHBhYXFg8BBiYnIjUTMTU2NzY3PgEXFhUHDgEnIwYHDgEHBiIvAS4BNyUxMxYXFhceARcWBgcnIiYnJi8BJicmJyY/AT4BFxMxMDEGBwYHDgEHBiYvAiY2Nz4BNzY3NjMXMhYVATEwMQYjIicuAScmND8BNhYXFhcWFxY3Mh8BFgYHBiMuAQsTBg4RIAIJBAJQBAICBwsDCAwTAwdQBAkDAXgVGR0WQ5hOCiABCAQoGg4zXygDCANPBAEDAk4BGBoQHjhMEAIGBWYEBgECBwUJBjBZBwIfAQkF9gYJDAohaUMECgIBHgEDBBAhDUsaAwhiBQb+Sh4eIhlNjToEBFIECQMUDBYMXmoJAx0CBAUBApAYPB1LmEcEAwIBOwIIBBApFDJnMAgFOAMCBAICPgETEhQLJh8JAgtgBAQBAgIIKyECAjoCCgRCDhIMGjSGTAUHAQEFBAoTDhUKXjgECVwEBQL96B4bIBdGcSYCAgQCXgQIAgobDUlnCAEGBf5yAwQJPzUDCQQ7AgEDEAcOBi8GCFwECAIBAAABAAD/9wOIAsMALwBNQEouLCogAgUFBhkBBAUWEgIDBAsBAQIETAAGBQaFAAUEBYUABAMEhQADAgOFAAIBAoUAAQAAAVkAAQEAYQAAAQBRJBYWIxEiKAcGHSsBBgcVFA4DJyInFjMyNy4BJxYzMjcuAT0BFhcuATQ3HgEXJjU0NjcyFzY3Bgc2A4glNSpWeKhhl30TGH5iO1wSEw8YGD9SJiwlLBlEwHAFakpPNT02FTs0Am42JxdJkIZkQAJRAk0BRjYDBg1iQgIVAhlOYCpTZAUVFEtoATkMIEAkBgAAAAEAAP+xAhcDUgAUADNAMAABAAYBTAADAgOGAAYAAAEGAGcFAQECAgFXBQEBAQJfBAECAQJPIxERERETIQcGHSsBFSMiBh0BMwcjESMRIzUzNTQ2MzICF1cwIqQWjquOjnRhUgNLkygoaqX+WAGopXpocgAAAwAA//kDWgLEAA8AHwAvADdANCgBBAUIAAIAAQJMAAUABAMFBGcAAwACAQMCZwABAAABVwABAQBfAAABAE8mNSY1JjMGBhwrJRUUBgchIiYnNTQ2NyEyFgMVFAYnISImJzU0NhchMhYDFRQGIyEiJic1NDYXITIWA1kUEPzvDxQBFg4DEQ8WARQQ/O8PFAEWDgMRDxYBFBD87w8UARYOAxEPFmRHDxQBFg5HDxQBFgEQSA4WARQPSA4WARQBDkcOFhYORw8WARQAAAAAAv///9UCPALnAA4AHQAjQCAAAQABAUwAAwIDhQACAQKFAAEAAYUAAAB2FTQmFAQGGislFA8BBiIvASY0NjchMhYnFAYjISIuAT8BNjIfARYCOwr6CxwL+gsWDgH0DhYBFA/+DA8UAgz6Ch4K+grzDwr6Cwv6Ch4UARbIDhYWHAv6Cwv6CgAAAAL///+xA+kCwwAZADgALUAqCQACAgMBTAADAgOFAAIBAoUAAQAAAVkAAQEAXwAAAQBPNzQmJDozBAYYKwERFAYHISImNxEWFxYXHgI3MzI+ATc2NzY3FAYHBg8BDgInIyImLwEuAS8BJicuASc0NjMhMhYD6DQl/MokNgEZH8pMICZEGwIcQigfX7cgGDYp0jQ1DCIeDQIMHhEeDSIGk2ASIzwBLisDNiQ2Acb+RSU0ATYkAbsbFok3GBocARocF0R8Fr8sUB2SIycJEgwBCgoSCBwDZUIOF1IkKzo0AAAAAwAA/8wDWQL/AAMADgAqAEpARyIBBQEBTAcJAgEIBQgBBYAGBAIABQCGAAMAAggDAmkACAEFCFkACAgFYQAFCAVRAAApJyEgHBsWFBEQDQwJBgADAAMRCgYXKxMRIxE3FAYrASImNDYyFgERIxE0JiMiBgcGFREjNj0BJzMVIz4DNzIWw7jEOi4BLjg6XDgCi7cuMCMuDQa4AQG4AQsYJjwiX3QB9f3XAimrKTY2UjY2/kD+wwEoO0ImHREc/svfiqUbUBIaIBABfgAAAv////kEMAMLABgAMwBCQD8qAQEGMSMFAwABAkwABgUBBQYBgAIBAAEDAQADgAAFAAEABQFnAAMEBANZAAMDBF8ABAMETyMoNhYUIyIHBh0rATQmKwE1NCYrASIGHQEjIgYUHwEWMj8BNgUUBgchIiY3NDY3JzQ2MzIWFzYzMhYVFAceAQLKCgh9CgdsBwp9CAoFxAUQBcQFAWV8Wv2hZ5QBTkIBqHZXkCEoNTtUF0heAUwICsQICgoIxAoQBcQFBcQGdll8AZJoSHweGHaoYlAjVDsrIhF2AAAAAAL////5BDADCwAYADMARUBCKgEABjEjAgEADQECAQNMAAYFAAUGAIADAQEAAgABAoAABQAAAQUAaQACBAQCVwACAgRfAAQCBE8jKDUUIyUUBwYdKwE0LwEmIg8BBhQWOwEVFBY7ATI2PQEzMjYFFAYHISImNzQ2Nyc0NjMyFhc2MzIWFRQHHgECygXEBRAFxAUKCH0KB2wHCn0ICgFlfFr9oWeUAU5CAah2V5AhKDU7VBdIXgFwCAXEBQXEBg8KxAgKCgjECplZfAGSaEh8Hhh2qGJQI1Q7KyIRdgADAAD/uQQWAroAFAAkADkAHkAbLhECAAEBTAMBAQABhQIBAAB2NTQoJxcSBAYYKyUHBiInASY0NwE2Mh8BFhQPARcWFAEDDgEvAS4BNxM+AR8BHgEJAQYiLwEmND8BJyY0PwE2MhcBFhQBWBwFDgb+/AYGAQQFEAQcBgbb2wYBRNACDgYiCAYB0QIMByMHCAFs/vwGDgYcBQXb2wUFHAYOBgEEBUUcBQUBBQUOBgEEBgYcBRAE3NsGDgJO/S8HCAMJAwwIAtAIBgEKAg7+j/77BQUcBg4G29wFDgYcBgb+/AUQAAABAAD/5QOhA1MAZAGIS7AKUFhAFk5DAgkHGwEAATEnDQMCAANMNAEJAUsbS7ALUFhAEk5DNAMFBxsBAAExJw0DAgADTBtAFk5DAgkHGwEAATEnDQMCAANMNAEJAUtZWUuwCVBYQEEABwkHhQAJBQmFAAUGBYUIAQYLBoUAAwoBCgMBgAACAAQAAgSAAAQEhAALCgALWQAKAAEACgFpAAsLAGEAAAsAURtLsApQWEBFAAcJB4UACQUJhQAFCAWFAAgGCIUABgsGhQADCgEKAwGAAAIABAACBIAABASEAAsKAAtZAAoAAQAKAWkACwsAYQAACwBRG0uwC1BYQD0ABwUHhQkBBQYFhQgBBgsGhQADCgEKAwGAAAIABAACBIAABASEAAsKAAtZAAoAAQAKAWkACwsAYQAACwBRG0BBAAcJB4UACQUJhQAFBgWFCAEGCwaFAAMKAQoDAYAAAgAEAAIEgAAEBIQACwoAC1kACgABAAoBaQALCwBhAAALAFFZWVlAEmNhXlxTUhkqIhorKTgjIgwGHyslFAYjIi4CIyIVFBYHFSMOAgciJjU0PgI3NCYjIgYVFBYfARYHFAcGIyInLgEvASI1ERcWMhcWMzI3NjU0LgInNDYXMhYXFA4CFxQWPgE3FQYPAQYVFBcWMzI+AjMyFgOhMiwXKBomFD4SARITRjwYIy4SGhACPiwvQhIJEwoCGRUsNlMFFgQJAQoJFAJTNiwVGRAWDgJCMCw8ARQWFgIuRoIaAQEFDRMZGQwgHCwYLjLtLTwUFhRFFlYVAwIKBAEeIBQmGigXLDI0LRgsDh4QDBkZEw0BAgIBAQI7AgICDhQYGQ0gGi4YLTQBMiwXKBokFiAeARABAQEIH1Q1LRQaEBYQQgAAAAsAAP9qA0oDUgAJAA8AFwAqADsAVwBfAHgAhACUAKYCzUAkpaGEfnsFFhWYARsWMQEBCQYBAgFWPjwgHAUGABI2KgIHAAZMS7AJUFhAcRwBGh4ahR8BGxYdFhsdgAYBBAUJBQQJgBMNCwMJAQUJcA8IAgcADAwHciQjIQMeABUWHhVpIgEWIAEdGRYdaQAZDgEFBBkFZwMBAQACEgECZwASEQoCAAcSAGkUEAIMABcYDBdqFBACDAwYYgAYDBhSG0uwClBYQH0cARoeGoUkIwIhHhUeIRWAHwEbFh0WGx2ABgEEBQ0FBA2AEwENCQUNcAsBCQEFCXAPCAIHAAwMB3IAHgAVFh4VaSIBFiABHRkWHWkAGQ4BBQQZBWcDAQEAAhIBAmcAEhEKAgAHEgBpFBACDAAXGAwXahQQAgwMGGIAGAwYUhtLsAtQWEBnHAEaHhqFBgEEBQkFBAmAEw0LAwkBBQlwJCMhAx4AFRYeFWkiARYgHx0DGxkWG2kAGQ4BBQQZBWcDAQEAAhIBAmcAEhEKAgAHEgBpFBAPDAgFBwAXGAcXaRQQDwwIBQcHGGEAGAcYURtLsA5QWEBxHAEaHhqFHwEbFh0WGx2ABgEEBQkFBAmAEw0LAwkBBQlwDwgCBwAMDAdyJCMhAx4AFRYeFWkiARYgAR0ZFh1pABkOAQUEGQVnAwEBAAISAQJnABIRCgIABxIAaRQQAgwAFxgMF2oUEAIMDBhiABgMGFIbQHIcARoeGoUfARsWHRYbHYAGAQQFCQUECYATDQsDCQEFCQF+DwgCBwAMDAdyJCMhAx4AFRYeFWkiARYgAR0ZFh1pABkOAQUEGQVnAwEBAAISAQJnABIRCgIABxIAaRQQAgwAFxgMF2oUEAIMDBhiABgMGFJZWVlZQEaVlZWmlaakoqCfm5mXlpKRiomDgn18enlzcmdmZWRfXltaU1JLSkZFQ0E5NzU0MzIwLykoJCMfHRsaERERERESEiMiJQYfKyUVFCMiJzU2MzIXFSM1NDIlMzUjFTMROwIRIxUGIyInJj0BIxUUFxYyPwE1NCcmIgc1IxEzNRYzMjc2NzUjFAcGIyI9ATM1NCcmIgcGHQEUFxYyNzY3NgE1NCIdARQyARQHDgEHBiAnLgEnJhA3PgE3NiAXHgEXFgEzBxUjNSYnJiczHwEVFAcGIicmPQE0NzYyFxY3ESM1BiMiJyY9ATMVFjMyNzUCHhYNDAwNFr0zMv3lPK47N6EyMhEPCgEBMgUHNB7wBQo6GDIyGRseCgW8MwEEEhpkDxZLFg8QFk4UCgIB/q0wMAGRDggyIGb+YmcgMgcPDwcyIGcBnmYhMgcO/dM5QzgIGhUQPCf1EBVLFg8PFksVELszHhwZCAQzAgoPEZx2JQyoDCYZGSZUNDT+wgEU0xcLAhLL2hwNFSI1bikOHx55/o4bHx8PLwcdBRQmMTksFRwcFSxgLBUdHg8PBQIZdScndSf+hINAIS4CDAwDLCI+AQhAIS4DCwsELCI+AkPfl5cqTTkvkydhLhQdHRUtYS0VHBwVLv7pHyMVDR3c4QwY1QAAAAUAAP+xA1kDCwAIABEAGgBUAG0AY0BgEgEDBQFMAAoCBwcKcgANCw4CBgUNBmkABQAEAAUEaQADAAABAwBpAAEAAgoBAmkJCAIHDAwHWQkIAgcHDGAADAcMUCAbamVeWVJRPTw6OTg3NjUbVCBTExQTFBMSDwYcKwE0JiIOARYyNjcUBi4BPgIWNxQGIi4BNjIWJSIrASIOAQcOAQcOAhYGFgYWFB8BHgEXHgEyFjYWNhY+ATc+ATc+AiY2JjYmNC8BLgEnLgEiJgYBFAcOAQcGIicuAScmEDc+ATc2IBceARcWAjtSeFICVnRWS4C2ggJ+unw/HiwcAiAoIv7mBCc7FEQuERwqDAYIBAICAgICBgoMKhwQMEIqTApKLEA0DRwsCgYIBAICAgICBgoLKh0QLkYmUAGqAwWAczL+MnSABQMDBYB0MQEAMXR+BgMBXjtUVHZUVDtbggJ+un4CgooVHh4qHh5mBAYICyocEDBEJlAGUCZEGCgcKgsGCgQEBAQECAIKCyocEDBEJlAGUCZEGCgcKgsGCgQE/qKAMXSABQMDBn51MQEAMXSABQMDBn51MQAC////agPoA1IADwAoAC1AKhwTAgMBAUwEAQABAIUAAQMBhQADAgOFAAICdgEAIiAYFgoIAA8BDwUGFisBMhYHFAcCBwYjIi4BNwE2AR4BHwEWBiMiLgI3Fx4CMzI3PgQDhSc8ARm5SzZDR2QBNAFkIf4sFkovAQKUeURqQCIBFxMgIAoXCA4kKjg6A1I0JyMx/qFFM2iOLwFDHv2/Kj4LKHaWNFpyQhEOFhIUJTQgFgYAAAABAAD/sQLKA1MASgBFQEIjAQUCEwEBAwJMHAEBSQACBAUEAgWAAAUDBAUDfgAAAAQCAARpAAMBAQNZAAMDAWEAAQMBUUVEOzkxLyknKCUGBhgrETQ+AxcyHgEVFA4DJyImJwcOBQ8BJyY1NDY/ASY1NDY3MhYVFA4BFjMyPgQ3NCYjIgYVFB4CFRQGIycuAypKYG46WJheFDBAYDomShEPCggOEBIiEgcFCRgZHRI6LSImMAEyJB80JBoQBgF6Y2+WDhAOEA0JHSwYDAIFPGpQOh4BSo5ZNmZgRi4CJB8/KRg4FjAoHAMGWBEzgGFxJDovUAEuIiWKRy4cMDpAPBpgbJBvGS4aGgQPMgEJLD46AAEAAAABAAA2kjnsXw889QAPA+gAAAAA3E/xVgAAAADcT/FW//r/agQwA1gAAAAIAAIAAAAAAAAAAQAAA1L/agAABC//+v/6BDAAAQAAAAAAAAAAAAAAAAAAADcD6AAAA0gAAAOgAAADEQAAAxEAAANZ//0DEQAAA1kAAANZAAAD6AAAA+gAAAOgAAAEL///BC///wFlAAAD6P//AsoAAANZAAADoAAAAvgAAAI7AAAD6AAAA+gAAAPoAAAD6AAAA6AAAAPoAAACygAAA6AAAAQvAAADoAAAA+j//wNIAAAD6AAAA6AAAANZAAACggAAA40AAANCAAAD6AAAA+j/+gOgAAACOwAAA1kAAAI7//8D6P//A1kAAAQv//8EL///BC8AAAOgAAADWQAAA1kAAAPo//8CygAAAAAAAABGAMgBEAFaAeACCgLMA1ADhgP+BIQE3AWgBcgGWAacBzIHmggcCEQIZAj0CaYJ3ApgC6QL2AwcDcAOBA6iDtIPCg+wEDoQghDoESoRnBKgExATShOwE/QUZBTKFTgVphYYF2YZshqMGuYbbgABAAAANwDyAAsAAAAAAAIASgCHAI0AAAD7DgwAAAAAAAAAEgDeAAEAAAAAAAAANQAAAAEAAAAAAAEABgA1AAEAAAAAAAIABwA7AAEAAAAAAAMABgBCAAEAAAAAAAQABgBIAAEAAAAAAAUACwBOAAEAAAAAAAYABgBZAAEAAAAAAAoAKwBfAAEAAAAAAAsAEwCKAAMAAQQJAAAAagCdAAMAAQQJAAEADAEHAAMAAQQJAAIADgETAAMAAQQJAAMADAEhAAMAAQQJAAQADAEtAAMAAQQJAAUAFgE5AAMAAQQJAAYADAFPAAMAAQQJAAoAVgFbAAMAAQQJAAsAJgGxQ29weXJpZ2h0IChDKSAyMDIxIGJ5IG9yaWdpbmFsIGF1dGhvcnMgQCBmb250ZWxsby5jb216d2lpY29SZWd1bGFyendpaWNvendpaWNvVmVyc2lvbiAxLjB6d2lpY29HZW5lcmF0ZWQgYnkgc3ZnMnR0ZiBmcm9tIEZvbnRlbGxvIHByb2plY3QuaHR0cDovL2ZvbnRlbGxvLmNvbQBDAG8AcAB5AHIAaQBnAGgAdAAgACgAQwApACAAMgAwADIAMQAgAGIAeQAgAG8AcgBpAGcAaQBuAGEAbAAgAGEAdQB0AGgAbwByAHMAIABAACAAZgBvAG4AdABlAGwAbABvAC4AYwBvAG0AegB3AGkAaQBjAG8AUgBlAGcAdQBsAGEAcgB6AHcAaQBpAGMAbwB6AHcAaQBpAGMAbwBWAGUAcgBzAGkAbwBuACAAMQAuADAAegB3AGkAaQBjAG8ARwBlAG4AZQByAGEAdABlAGQAIABiAHkAIABzAHYAZwAyAHQAdABmACAAZgByAG8AbQAgAEYAbwBuAHQAZQBsAGwAbwAgAHAAcgBvAGoAZQBjAHQALgBoAHQAdABwADoALwAvAGYAbwBuAHQAZQBsAGwAbwAuAGMAbwBtAAAAAAIAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANwECAQMBBAEFAQYBBwEIAQkBCgELAQwBDQEOAQ8BEAERARIBEwEUARUBFgEXARgBGQEaARsBHAEdAR4BHwEgASEBIgEjASQBJQEmAScBKAEpASoBKwEsAS0BLgEvATABMQEyATMBNAE1ATYBNwE4AAxwbHVzLWNpcmNsZWQGbG9nb3V0BHBsdXMGY2FuY2VsBGhlbHAFbWludXMEZ2VhcgZwZW5jaWwCdXADZXllCGRvd25sb2FkBmZvbGRlcgV1c2VycwRsZWZ0BG1haWwEdXNlcgZ1cGRhdGUEaG9tZQV0cmFzaARkb3duB2NvbW1lbnQEY2hhdAdleWUtb2ZmCWRvd24tb3BlbgZ1cGxvYWQEY29ncwlsZWZ0LW9wZW4IZG93bi1iaWcHY29nLWFsdAZ1cC1iaWcFY2xvbmUNbWludXMtY2lyY2xlZAVjaGVjawZnaXRodWIFbG9naW4EbG9jawRtaW1pBmRpdmlkZQRmbGFnBHNwaW4HdHdpdHRlcghmYWNlYm9vawRtZW51BHNvcnQIbWFpbC1hbHQIbGlua2VkaW4OZG93bmxvYWQtY2xvdWQMdXBsb2FkLWNsb3VkBGNvZGUGcHV6emxlB3lvdXR1YmUJaW5zdGFncmFtBWJydXNoCXBpbnRlcmVzdAAAAAABAAH//wAPAAAAAAAAAAAAAAAAAAAAALAALCCwAFVYRVkgIEu4AA5RS7AGU1pYsDQbsChZYGYgilVYsAIlYbkIAAgAY2MjYhshIbAAWbAAQyNEsgABAENgQi2wASywIGBmLbACLCMhIyEtsAMsIGSzAxQVAEJDsBNDIGBgQrECFENCsSUDQ7ACQ1R4ILAMI7ACQ0NhZLAEUHiyAgICQ2BCsCFlHCGwAkNDsg4VAUIcILACQyNCshMBE0NgQiOwAFBYZVmyFgECQ2BCLbAELLADK7AVQ1gjISMhsBZDQyOwAFBYZVkbIGQgsMBQsAQmWrIoAQ1DRWNFsAZFWCGwAyVZUltYISMhG4pYILBQUFghsEBZGyCwOFBYIbA4WVkgsQENQ0VjRWFksChQWCGxAQ1DRWNFILAwUFghsDBZGyCwwFBYIGYgiophILAKUFhgGyCwIFBYIbAKYBsgsDZQWCGwNmAbYFlZWRuwAiWwDENjsABSWLAAS7AKUFghsAxDG0uwHlBYIbAeS2G4EABjsAxDY7gFAGJZWWRhWbABK1lZI7AAUFhlWVkgZLAWQyNCWS2wBSwgRSCwBCVhZCCwB0NQWLAHI0KwCCNCGyEhWbABYC2wBiwjISMhsAMrIGSxB2JCILAII0KwBkVYG7EBDUNFY7EBDUOwAGBFY7AFKiEgsAhDIIogirABK7EwBSWwBCZRWGBQG2FSWVgjWSFZILBAU1iwASsbIbBAWSOwAFBYZVktsAcssAlDK7IAAgBDYEItsAgssAkjQiMgsAAjQmGwAmJmsAFjsAFgsAcqLbAJLCAgRSCwDkNjuAQAYiCwAFBYsEBgWWawAWNgRLABYC2wCiyyCQ4AQ0VCKiGyAAEAQ2BCLbALLLAAQyNEsgABAENgQi2wDCwgIEUgsAErI7AAQ7AEJWAgRYojYSBkILAgUFghsAAbsDBQWLAgG7BAWVkjsABQWGVZsAMlI2FERLABYC2wDSwgIEUgsAErI7AAQ7AEJWAgRYojYSBksCRQWLAAG7BAWSOwAFBYZVmwAyUjYUREsAFgLbAOLCCwACNCsw0MAANFUFghGyMhWSohLbAPLLECAkWwZGFELbAQLLABYCAgsA9DSrAAUFggsA8jQlmwEENKsABSWCCwECNCWS2wESwgsBBiZrABYyC4BABjiiNhsBFDYCCKYCCwESNCIy2wEixLVFixBGREWSSwDWUjeC2wEyxLUVhLU1ixBGREWRshWSSwE2UjeC2wFCyxABJDVVixEhJDsAFhQrARK1mwAEOwAiVCsQ8CJUKxEAIlQrABFiMgsAMlUFixAQBDYLAEJUKKiiCKI2GwECohI7ABYSCKI2GwECohG7EBAENgsAIlQrACJWGwECohWbAPQ0ewEENHYLACYiCwAFBYsEBgWWawAWMgsA5DY7gEAGIgsABQWLBAYFlmsAFjYLEAABMjRLABQ7AAPrIBAQFDYEItsBUsALEAAkVUWLASI0IgRbAOI0KwDSOwAGBCIGC3GBgBABEAEwBCQkKKYCCwFCNCsAFhsRQIK7CLKxsiWS2wFiyxABUrLbAXLLEBFSstsBgssQIVKy2wGSyxAxUrLbAaLLEEFSstsBsssQUVKy2wHCyxBhUrLbAdLLEHFSstsB4ssQgVKy2wHyyxCRUrLbArLCMgsBBiZrABY7AGYEtUWCMgLrABXRshIVktsCwsIyCwEGJmsAFjsBZgS1RYIyAusAFxGyEhWS2wLSwjILAQYmawAWOwJmBLVFgjIC6wAXIbISFZLbAgLACwDyuxAAJFVFiwEiNCIEWwDiNCsA0jsABgQiBgsAFhtRgYAQARAEJCimCxFAgrsIsrGyJZLbAhLLEAICstsCIssQEgKy2wIyyxAiArLbAkLLEDICstsCUssQQgKy2wJiyxBSArLbAnLLEGICstsCgssQcgKy2wKSyxCCArLbAqLLEJICstsC4sIDywAWAtsC8sIGCwGGAgQyOwAWBDsAIlYbABYLAuKiEtsDAssC8rsC8qLbAxLCAgRyAgsA5DY7gEAGIgsABQWLBAYFlmsAFjYCNhOCMgilVYIEcgILAOQ2O4BABiILAAUFiwQGBZZrABY2AjYTgbIVktsDIsALEAAkVUWLEOBkVCsAEWsDEqsQUBFUVYMFkbIlktsDMsALAPK7EAAkVUWLEOBkVCsAEWsDEqsQUBFUVYMFkbIlktsDQsIDWwAWAtsDUsALEOBkVCsAFFY7gEAGIgsABQWLBAYFlmsAFjsAErsA5DY7gEAGIgsABQWLBAYFlmsAFjsAErsAAWtAAAAAAARD4jOLE0ARUqIS2wNiwgPCBHILAOQ2O4BABiILAAUFiwQGBZZrABY2CwAENhOC2wNywuFzwtsDgsIDwgRyCwDkNjuAQAYiCwAFBYsEBgWWawAWNgsABDYbABQ2M4LbA5LLECABYlIC4gR7AAI0KwAiVJiopHI0cjYSBYYhshWbABI0KyOAEBFRQqLbA6LLAAFrAXI0KwBCWwBCVHI0cjYbEMAEKwC0MrZYouIyAgPIo4LbA7LLAAFrAXI0KwBCWwBCUgLkcjRyNhILAGI0KxDABCsAtDKyCwYFBYILBAUVizBCAFIBuzBCYFGllCQiMgsApDIIojRyNHI2EjRmCwBkOwAmIgsABQWLBAYFlmsAFjYCCwASsgiophILAEQ2BkI7AFQ2FkUFiwBENhG7AFQ2BZsAMlsAJiILAAUFiwQGBZZrABY2EjICCwBCYjRmE4GyOwCkNGsAIlsApDRyNHI2FgILAGQ7ACYiCwAFBYsEBgWWawAWNgIyCwASsjsAZDYLABK7AFJWGwBSWwAmIgsABQWLBAYFlmsAFjsAQmYSCwBCVgZCOwAyVgZFBYIRsjIVkjICCwBCYjRmE4WS2wPCywABawFyNCICAgsAUmIC5HI0cjYSM8OC2wPSywABawFyNCILAKI0IgICBGI0ewASsjYTgtsD4ssAAWsBcjQrADJbACJUcjRyNhsABUWC4gPCMhG7ACJbACJUcjRyNhILAFJbAEJUcjRyNhsAYlsAUlSbACJWG5CAAIAGNjIyBYYhshWWO4BABiILAAUFiwQGBZZrABY2AjLiMgIDyKOCMhWS2wPyywABawFyNCILAKQyAuRyNHI2EgYLAgYGawAmIgsABQWLBAYFlmsAFjIyAgPIo4LbBALCMgLkawAiVGsBdDWFAbUllYIDxZLrEwARQrLbBBLCMgLkawAiVGsBdDWFIbUFlYIDxZLrEwARQrLbBCLCMgLkawAiVGsBdDWFAbUllYIDxZIyAuRrACJUawF0NYUhtQWVggPFkusTABFCstsEMssDorIyAuRrACJUawF0NYUBtSWVggPFkusTABFCstsEQssDsriiAgPLAGI0KKOCMgLkawAiVGsBdDWFAbUllYIDxZLrEwARQrsAZDLrAwKy2wRSywABawBCWwBCYgICBGI0dhsAwjQi5HI0cjYbALQysjIDwgLiM4sTABFCstsEYssQoEJUKwABawBCWwBCUgLkcjRyNhILAGI0KxDABCsAtDKyCwYFBYILBAUVizBCAFIBuzBCYFGllCQiMgR7AGQ7ACYiCwAFBYsEBgWWawAWNgILABKyCKimEgsARDYGQjsAVDYWRQWLAEQ2EbsAVDYFmwAyWwAmIgsABQWLBAYFlmsAFjYbACJUZhOCMgPCM4GyEgIEYjR7ABKyNhOCFZsTABFCstsEcssQA6Ky6xMAEUKy2wSCyxADsrISMgIDywBiNCIzixMAEUK7AGQy6wMCstsEkssAAVIEewACNCsgABARUUEy6wNiotsEossAAVIEewACNCsgABARUUEy6wNiotsEsssQABFBOwNyotsEwssDkqLbBNLLAAFkUjIC4gRoojYTixMAEUKy2wTiywCiNCsE0rLbBPLLIAAEYrLbBQLLIAAUYrLbBRLLIBAEYrLbBSLLIBAUYrLbBTLLIAAEcrLbBULLIAAUcrLbBVLLIBAEcrLbBWLLIBAUcrLbBXLLMAAABDKy2wWCyzAAEAQystsFksswEAAEMrLbBaLLMBAQBDKy2wWyyzAAABQystsFwsswABAUMrLbBdLLMBAAFDKy2wXiyzAQEBQystsF8ssgAARSstsGAssgABRSstsGEssgEARSstsGIssgEBRSstsGMssgAASCstsGQssgABSCstsGUssgEASCstsGYssgEBSCstsGcsswAAAEQrLbBoLLMAAQBEKy2waSyzAQAARCstsGosswEBAEQrLbBrLLMAAAFEKy2wbCyzAAEBRCstsG0sswEAAUQrLbBuLLMBAQFEKy2wbyyxADwrLrEwARQrLbBwLLEAPCuwQCstsHEssQA8K7BBKy2wciywABaxADwrsEIrLbBzLLEBPCuwQCstsHQssQE8K7BBKy2wdSywABaxATwrsEIrLbB2LLEAPSsusTABFCstsHcssQA9K7BAKy2weCyxAD0rsEErLbB5LLEAPSuwQistsHossQE9K7BAKy2weyyxAT0rsEErLbB8LLEBPSuwQistsH0ssQA+Ky6xMAEUKy2wfiyxAD4rsEArLbB/LLEAPiuwQSstsIAssQA+K7BCKy2wgSyxAT4rsEArLbCCLLEBPiuwQSstsIMssQE+K7BCKy2whCyxAD8rLrEwARQrLbCFLLEAPyuwQCstsIYssQA/K7BBKy2whyyxAD8rsEIrLbCILLEBPyuwQCstsIkssQE/K7BBKy2wiiyxAT8rsEIrLbCLLLILAANFUFiwBhuyBAIDRVgjIRshWVlCK7AIZbADJFB4sQUBFUVYMFktAEu4AMhSWLEBAY5ZsAG5CAAIAGNwsQAHQrEAACqxAAdCsQAKKrEAB0KxAAoqsQAHQrkAAAALKrEAB0K5AAAACyq5AAMAAESxJAGIUViwQIhYuQADAGREsSgBiFFYuAgAiFi5AAMAAERZG7EnAYhRWLoIgAABBECIY1RYuQADAABEWVlZWVmxAA4quAH/hbAEjbECAESzBWQGAERE') format('truetype'); + src: url('data:application/octet-stream;base64,d09GRgABAAAAADTIAA8AAAAAU1QAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABHU1VCAAABWAAAADsAAABUIIslek9TLzIAAAGUAAAAQwAAAFZ3sVO/Y21hcAAAAdgAAAHJAAAEzCXyvi5jdnQgAAADpAAAAAsAAAAOAAAAAGZwZ20AAAOwAAAG7QAADgxiLvl6Z2FzcAAACqAAAAAIAAAACAAAABBnbHlmAAAKqAAAJVgAADd8Ksg08mhlYWQAADAAAAAAMwAAADYcbssxaGhlYQAAMDQAAAAgAAAAJAd/A8xobXR4AAAwVAAAAGwAAADgwp7/7WxvY2EAADDAAAAAcgAAAHJj7VSCbWF4cAAAMTQAAAAgAAAAIAIWD4duYW1lAAAxVAAAAYEAAAK1XvCwW3Bvc3QAADLYAAABdAAAAhxHTtqicHJlcAAANEwAAAB6AAAAnH62O7Z4nGNgZGBg4GIwYLBjYHJx8wlh4MtJLMljkGJgYYAAkDwymzEnMz2RgQPGA8qxgGkOIGaDiAIAJjsFSAB4nGNgZK5knMDAysDAVMW0h4GBoQdCMz5gMGRkAooysDIzYAUBaa4pDAcUJ34yZA76n8UQxRzBMA0ozAiSAwDxWQwxAHic5dRJTltBFIXh/9nGdMb0PRhswEAaJ07nJSFFIcpWMoQxm2EPDGB2J6AqBhkhkVM+GUQZsIH46bP8qiS/su45BiaAuryRBtROqPSJqqfVarxeZ2a83uCX7jssaKXd/Rn9GKbLdJ1u0l16yN08yGf5PD89Dp+fQfto/2K8f5vu/91/4VXpGR2+6vo2vr7z46+r7Nd0goZO3mSSKaZ1vllazNFmXqdbZIllVlhljXU22GSLbXbY1bfusU+XHgccckSfY0445RWv9TvfMuAd7xnygY984jNfGOlxzRdP+3+8WuWtdvXnblTmayUjgWkuRGUlU1GzkquoW8lbNEzzIyZMkySappkSk6bpElNWchjTpokTM1ZOF7OmFBAtUx6IOVMyiLYpI8S8KS3Egik3xKIpQcSSKUvEsilVxIopX8SqKWnEmilzxLopfcSGKYfEpimRxJYpm8S2KaXEjimvxK4puUTHlGFiz5RmYt+Ua6JrSjjRM2WdODClnjg05Z84MjWB6Js6oe6a2kG6MPWEdGlqDOnayn9HujG1iHRr6hPpztQs0r2pY6QHU9vIXVPvyANTA8lnpi6Sz02tJD+Z+snj0Bj9Bq3mu1cAAAB4nGNgQAYAAA4AAQB4nK1Xa1sbxxWe1Q2MAQNC2M267ihjUZcdySRxHGIrDtllURwlqcC43XVuu0i4TZNekt7oNb1flD9zVrRPnW/5aXnPzEoBB9ynz1M+6Lwz886c65xZSGhJ4n4UxlJ2H4n5nS5V7j2I6IZL1+LkoRzej6jQSD+bFtOi31f7br1OIiYRqK2RcESQ+E1yNMnkYZMKWtVVvUlFLQdHxeWa8AOqBjJJ/KywHPhZoxhQIdg7lDSrAIJ0QKXe4ahQKOAYqh9crvPsaL7m+JcloPJHVaeKNUWiFx3EoxWnYBSWNBU9qgUR66OVIMgJrhxI+rxHpdUHo2vOXBD2Q6qEUZ2KjXj3rQhkdxhJ6vUwtQk2bTDaiGOZWTYsuoapfCRpndfXmfl5L5KIxjCVNNOLEsxIXpthdJPRzcRN4jh2ES2aDfokdiMSXSbXMXa7dIXRlW76aEH0mfGoLPbjeJDG5HhxnHsQywH8UX7cpLKWsKDUSOHTVNCLaEr5NK18ZABbkiZVTLgRCTnIpvZ9yYvsrmvN518SSdin8lodi4EcyiF0ZevlBiK0EyU9N92NIxXXY0mb9yKsuRyX3JQmTWk6F3gjUbBpnsZQ+QrlovyUCvsPyenDEJpaa9I5LdnaebhVEvuST6DNJGZKsmWsndGjc/MiCP21+qRwzuuThTRrT3E8mBDA9USGQ5VyUk2whcsJIenCyLGVSK1Kt6yKuTO201XsEu6Xrh3fNK+NQ0dzs6IYQour6vEaiviCzgqFkAbpVpMWNKhS0oXgNT4AABmiBR7tYrRg8rWIgxZMUCRi0IdmWgwSOUwkLSJsTVrS3b0oKw224qs0d6AOm1TV3Z2oe89OunXMV838ss7EUnA/ypaWAnJSnxY9vnIoLT+7wD8L+CFnBbkoNnpRxuGDv/4QGYbahbW6wrYxdu06b8FN5pkYnnRgfwezJ5N1RgozIaoK8UJB3Rk5jmOyVdMiE4VwL6Il5cuQ5lF+c4hw4svkP5cuOWJRVIXv+xyBZaw5abY87dGnnvs0wrUCH2teky7qzGF5CfFm+TWdFVk+pbMSS1dnZZaXdVZh+XWdTbG8orNplt/Q2TmWnlbj+FMlQaSVbJHzDt+WJuljiyuTxY/sYvPY4upk8WO7KLWgC96ZfsKpf1tX2c/j/tXhn4RdT8M/lgr+sbwK/1g24B/LVfjH8pvwj+U1+MfyW/CP5Rr8Y9nSsm0K9rqG2kuJRNNzksCkFJewxTW7rum6R9dxH5/BVejIM7Kp0g3Fjf2JDJe9f3ac4my+EnLF0TNrWdmphRGaInv53LHwnMW5oeXzxvLncZrlhF/ViWt7qi08L1b+Jfhv647ayG44Nfb1JuIBB063H5cl3WjSC7p1sd2kjf9GRWH3QX8RKRIrDdmSHW4JCO3d4bCjOughER4+dF28SBuOU1tGhG+hd63QRdBKaKcNQ8tmhU/nA+9g2FJStoc48/ZJmmzZ86ii/DFbUsI9ZXMnOirJsnSPSqvlp2KfO+0MmrYyO9R2QpXg8euacLezr1IpSAaKynhUsVwKUhc44U73+J4UpqH/q23kWEHDNr9YM4HRgvNOUaJsT62giSAZZRRc+Sun4kQ2osFGFPGbd9IvdaEQ2uNYSMyWV/NYqDbC9NJkiWbM+rbqsFLO4p1JCNkZG2kSe1FLtvGgs/X5pGS78lRQpYHR3ePfLjaJp1V7ni3FJf/yMUuCcboS/sB53OVxijfRP1ocxW26GEQ9F2+qbMetbN1Zxr195cTqrts7seqfuvdJOwJNt7wnKdzSdNsbwjauMTh1JhUJbdE6doTGZa7PVRv5FB9ovnWdC1Th+rRw8+z52zqbwVsz3vI/lnTn/1XF7BP3sbZCqzpWL/U4t7ODBnzLG0flVYxue3WVxyX3ZhKCuwhBzV57fI3ghldbdBO3/LUz5rs4zlmu0gvAr2t6EeINjmKIcMttPLzjaL2puaDpDcBv65EQ2wA9AIfBjh45ZmYXwMzcY04HYI85DO4zh8F3mMPgu/oIvTAAioAcg2J95Ni5B0B27i3mOYzeZp5B7zDPoHeZZ9B7rDMESFgng5R1MthnnQz6zHkVYMAcBgfMYfCQOQy+Z+zaAvq+sYvR+8YuRj8wdjH6wNjF6ENjF6MfGrsY/cjYxejHiHF7ksCfmBFtAn5k4SuAH3PQzcjH6Kd4a3POzyxkzs8Nx8k5v8Dmlyan/tKMzI5DC3nHryxk+q9xTk74jYVM+K2FTPgduHcm5/3ejAz9EwuZ/gcLmf5H7MwJf7KQCX+2kAl/AfflyXl/NSND/5uFTP+7hUz/B3bmhH9ayIShhUz4VI/Omy9bqrijUqEY4p8mtMHY92j6gIpXe4fjx7r5BSXaAUEAAAAAAQAB//8AD3icxXsLcFxXmeb5z3327e7br3tvP9TdavVbrXZL6qesl9t6WZZkWZIV21Js+RHbshWTh2M7JjhCxHYqCUMc8iY7EzBlUylg2ISEwABLqE0GMgZqwsAEZsLUsMMyOFQN7NZClsnGnf3P7ZbtkEyG2aJq3fLte889597z+P/v//7/P00oIW9/lRvlKJGJRoaq6wXgeMpzdEUEKvFUWpaBEJ4j/CKRAKRtRJJgDwEJpoFoHrfL6VDtNqtiEXgig2wRjTbIG04xknSWPYVSrBTTY3pBL8D5L7zxRu38G2/808svH7h48QBHzSvY8UYtw64vEkJYX/6Vu5G+SFKkSgaq6zSgABNEpAIVhRUicFTglllnOJ6sECAU+7jILrhthOPILkI4stmI+ROZREoSQ20JzXCAClIsmiy5iuUe7JnuNYtSsagouTTDW8iHKWgSiNFkH8TYoViuFErFsuEFA/ZT7IEsf3FwYWHwi7ICUL9MFKEcf06kIqWitfZ9a9B4UzUM9U0jaIV2a466BdXCw8Ig3DO4oMhWi2iXZCgmayewIU9lyKrW2iuK5jhnqK86NDinGtSCBTgFOCg2B27OSmKktZrEwfJnsBDuxnXB4W3DLxwoBTbSWCERK8REMdgGuiamYnhgQ62U8JAqNcbBBu3VC3mDc0eMSxHjRiMCl7xhwIuw90Y8YRdfZqWvG1iqv94oNSKsutmfX9Mf0rtJnISrTVG/U+IJhQkOKKFnAG8f14KaxosBnG0HTmM7SOyQLK6DFDuU881QYQcDb3sN+kPHhDPrPH8eDxNO9u28eu1wnD/vuMVgJxcuON5d0ZFjFQj39uW3n+F24Rw5SIUMkdHqcCsInAUXh9AJwlMOBXiFcALlhGUiEcpL9BARcHIFskhAFGEbARD3EBHEaT3c5jGSyZgshtsSpWKyDaJiCDQD563sKeZQJiQRO1/IV/qZ+OAUq+DV6/eL5XXQz3k1FaI5irfDAL9R5BtlxTyc7d/Rec8Gi32MFy1CONGVMZpivWDe8rmDSliz/ejIty69fJN4x9d/89XlmdVmCny4czZ3u91a4aVkU9itB2yOgYSGN9xRq1MMBNMzx146evSlX7IDWx8UCzf8C86Fr6qza3N0TBmAbC4VqOiri0dLQyha6qJwed4UAvqZ1eWvr3ukoYfPcPM4vzJZIsPVgf1zE+t5wvcoOMHFdJOT54CbIAIvnBEBy8+wV6GUcnCGcJQ7Qyg9vuP6LdMbR9sy0YjHLbEuFJNRFYx8OYF9QTmRDK+h4VSmUFZECT8478lSKol6G8VjsojTXUm2Qw5Yp1GMKo3CAopSuYIfJti4MF4ULm/jYRIWhIH2zJyYoVuPboWgLB1UrJ60KDim7JK0yR+wSLzzpGxzNnk3i05xxOAFOa045AOon4pwUFa9iXpdeZMvYJE510nJBo6gd7PgkEY1nrfUKyuw0DM7e3x29gS77wzrTXlRFfUpEHrt8kTQqUiLFluvIFbDgira8o5gkwNsklnXH4iskWySNnVNVWuPIAwGG1UDTrDhGvDmGmyibxMRcdmP2nd3FZeHCiFDlRCe/TjRhENAIvzE+NPuqe3VFBGogHPPUVwFwrFFAXKLCMDzsA2/gN9NeOCnmhBV3lWTnHl3xbmqm5CWiM/rdFhk7IaoSaK3zVtJSQjoUETFAFHXUDGgnPJCrASo4Km6qn8nf6owCrtsAl/7Pm8XeGjnwpdqHZe4TdrOSzu1HuOUJhVOFXo3UNHG1/6GxyPk+Fsv1dpfhydC+s7Xd+j6KaOBhyjfz9MRNgtVQwAGPuQK9ng1Nyf62xJMaixQBx7sTx7BW+M+t8MaVmo/rv3YGrTutFrhSfzGw407UMdaaz9SFHYfnlSU2l5rkL3GxN5L9E7iIlFSICPVQSulPLUj2l6LKzhzZBm7Rgks47xQXkR4AUGAOZxyYQ8RQJj2GnFN9xnMCkEyxXAjB6ViRZRQxcqoDFIU5w7VAYW7kC8LOLV8JM4kvJwF3mtw565biT74yoPRlevGfwr8P9W+7LSO7HMazqEOqxP+zjpZ+13t72u/m7RaJ0GGJMiTVug+vb57cPFh+sChwe71p4/ccw9sxLr7hq1Op7VjyPldj+cjTzzxEU9SW3mCPrms1WXsX7lz3AzquQtt7jqysTrSC5JsQQ1mSCpL8hkLSJx0hogcz4n8Crah/BwaIZx9nIVDhOfpLiyim9f1xRNG1J1Y63MrYnNbAqET9R2V+MoJw84GCBVavEZ+HTAoMupGI8kU2rRZeQPlK08vamGN+gK+j2kRNzWCvpGI8dZ3TMgCbrxla8sEcEbkecX9phJW3nRZFO9ZQz2rGnDWt89hNqSaY/XkT541TduzRmQign+Q9jrftFrfdHr1N9H8ouFGzHv77bf/lfcj5rlJK8lWW5FWoGYwKwfINQg5jetP+W1XBxzrjpVLgtjUxuRehVhLNAdoDqCAo0rpLVHRQVPJSoN2hNhYeb/7a76tycvnPEFwfd23NUF3ecLfrHWUjsS+jkQHxgrPFsagvTgK61zaPwTTatQ8/uf5Yus/cJJAqa8wNlZwjzGVELG/S3w7rp2L5EkPWsGtCPk3Vw9vVlFMYcIFFqvlDLHK1jNOkKl8xgFM3yU0gYACumJDLBfRFqIA8/iHrIo/rZoUY05lFGMPE3oyvbBzfm7r7MzU+NjGDYMD6/q71/p1zV+JeVqcblxlqBOOIrIoqOQrKNKgiTG2yMV+gVGrfmDQnQ/zXrwRTRbLeQOYKvRTQ2CUJZlCDUihde0Hbz51pcr4fPf4mioM85mBlmSCo6dmBmu+oSngbc5IsrtFjOdGp0b8rU452pWMOFW4/C2Gxsdn4d7lp1foyefugMH+3Pja+TVcItEylOaHNzTuL3BD2exfGgGw687J2vUDk5MD4a6BrmLS8AUD1HAGFGoki10DQXq2jvC1X88t0zuePyGe/kFbDoa49ZNO3e7zQeN2HZ9gkZ4kduKtaoyqIT7hEVEV4cljml+XtkqJ2OD2axHLm4rypjXoo9trNtWw4in+N/GOw3V9BjHoRcT8tWQjqVb7mty4INRD6uwGmToq3soq/Ah4JSAJNsEb383vYti9udS3xp9pZdQw4WLmVaXIeNGWohFNIe1FElD2lLBLjBaIkoYGNMyj6vVzaFlRVV11VWXSy8SZO+fWH5kLxnubaKA/Gtr+qO62iVwZ7SDlOF586yKebbnxKB9xR3w2ag2EtbBw9HC4uKGYeOtiHOEuwZUTRSt8XnPeNuYLhGkgbIzd5tRqs2gSFTqjqgJyNZu4sH52BxdUNSw0bGG6Y9Y3U7p8zmTbdFeiWFzlJvQiZyM6CZNENcrQ9gzCEY8zjo7LGdM2sLn3eF0ub96cgrpMlorI1Yw8SiPH4YLkoIz29OJIZy3eOaL4Mv1rNl4cywwkg/JZFCD+rs+fHu7dvr23Y3ZrbxpGR5P9s1vhm9uXTQFb5UjXI17EyQayszo/mKCipR0E0QscUnz0oiaIRRbRI1pBpUNfQaArPM6XSNGFAWa7cRHRrAqyeIhdcHPMhdnDrND0yHAykSgnkiUtzrAUNF1lvgnjRqaDwhAFSRTTuStUyIPwyjgUcqUkc24alKpSYpTJZEkGNx7/75+Yfrx3FB0WBD3mdWxK76uM3ZUSfbwNqaeqOeulM7eMY6FXsN2MCxT/509MP8Ea+ZBkw6Nf7V87ajWbo7uzKZ6BsX6ly26DrzRKNtWvRb5Rc9Wve5D+JXGSTpKrtuWSCZ+OfqMMnA1VhU7waFA40885Q5lZz6Rj0RaXJqBpZ8ojmW4kToDLAkZFYqDDrD3Sw2S5YnoYpVWYRSLIudGtOsscK1iPn5NRQaKSUFuuLUt2IcZTAT7u7vDcY5LtO0RI136LVV991VDBAXLtdxBvZfZtoPYNrNoqqgJMOhy3Hmbs/GcHeGeDJ6zQ33FVYiXNpI186EucSUvGn/YgD1tDJIHnpSM4bqai6KfCaWwiSJywiHSZGRH84uleZkVmmqo5Vl+Q0Lb+QQ3mqlaXO+/uCugu5rJ4jEiFUynTbZQHdFzQ82YiglCDE+KVCjlAMXBAAbX7DvjUHWU6cPfDp4cofHFh5ae1l3+6spAxOnYU3bbZHQH3AUNZmq3OwMWRkVpAzWYyWZVzu8eiSvfMTLcSHXN3BAKfuiniXB6o4x7tRb9DfQ/cK2km7jUcwmQdRWiP0gA6FX6DlvqvVCuzwkwY637vQ9wlrhUJVagaEAA2mrSUo2gZjzODR0SXi8enllwtrhahxF2qpWrf3E3/6nLle9+ry9jTJm4myDhZV+3dGMS5XIeK1spAakLBJR3PA93Y6CNHmK9CTa2jexgXnh6o9vfGojEeSS5oTOFSoilqyRIOoLSOlqVKP63gRBdNV8+rMTKHZLeZMx0ZBq0iNkJjxjA0VUyFgXMvPXdjR37kOr0JmS76pzzHATJ9lR+ehKXnXn1u6dWpIcEmN1l4AZ0qqkhBbetIvuOxWyKu+fMDwxNgH52FC5tOT1g6vQKvSAzmOREfEhZ8bmf66ODk6YmJ0z8ZPJ5SDaXFygkiYrKsAC94Oy1jXL69ePdYWyZ1gnm/b7+I8/MMsZAA6Ue+sI1sq84Wmyjht4hI92YGUfqmBlpTMnOQ+bp7h9PKJBtFssEVOPxbxik7zcgjP4esgUEWT6Ynxj05f1wLSQxvcZIqjOsa7yK6FU0XKUoFzhPiMZvMhlOHAFUw/TnJ8ODEegyvxswWxEw/MFXB+Tag3NbRBUiJF2DpGjp8seeXPUFBkYYs/qm781br1rcey+ebBYVTrXErWPTtG/+MR6FLzf7kZOvtLw+v3xkr7Y1YD22OLfUxovwALF5Lk4/xcKg2fyhvSYmKlImf2OTKuE89rpQtoqiJINQuT640gc+/4PHE1+xeGlNOH9pXXRffW/bUZfgX6Ku01n0Vu6kTKL4NpdC8pq/C3JRUgwx4LVAPjXCfq+1FIouOiHUnfkMa0tagbYcVztZuQM/lz9BR2WG11n6MxdYdzFmp+4fnuJzJ3VtJlXkrJZDEVe5uES1nZOZanyEmgWfEfdt7Efe+3lghFs1fJe5JlYaRtK1+6w1GhwvoLYSBxT0YSedEM6wgmbEmPNQjPcb78PZf2cqxs9Gy/VfI2y2+s5rjLOLuWa/HZVJ4dwgtjzvi5gO21ZN7n2VBKDxAczrdHIYZo0HXsy7Gn1wmD8Z5eB5xQ0T/pYNsR5v6UfIo+Ur1S8MOVRIFgWy9bsv0xNhGl1PgUT0O7t93w66F2anN40hVCVLlQ4s7Ez5Bph/5QDza5MfpWr7zQx88emssIONcTuwGuoTseXxgfXVdX29PV6VcslrGTp64/bYjAgKUhSDFFhhWo1soU5HK4goRJSpKy0QCKsEyjzKBjI07RJAT0DlcG9iFBg82P/LQfffcfNP18xtGCvn2XFumORxQEHj6AO15quJF/C4gKat4WUhDR03wSim0+DEWIEkxfdCMfpoDMYFVG/WxaqO+FFutnyo16nOVwpV6+vvUq4hhdGGSLDzquXq6IDt6h8YCIXmPEgqMDfU6pYUFyWkWKXtks8ghf7g4kafl0S6oyiOyLVHuRNYySg3X2jWdCh2Sh2Q11dVu6OqI5upZ0ynzCbFTlAOJuN2pdDhtrc0xkW8XO3klmI5hUaddZUV0mPelg2LALbqCbj5ezvCRoBSI/3aPHPaPDffVO9I3POYPm30bHcGOLLDujowGQj2JMs1PdvBd31ntBz9g9gP75r3SjwFxtbu16bzT1taSkGmH0CkqTa3YEVvBUS/qFAvYt1bsrl8P80bOJ/rg6aaMnCxmabSu+9+kj3NDqPtoD+H3/AAvs4cWapgWMdUIUjDFp/fXfgStirITLSPTfngSlWGnQj9b+3HtR+apAp9kiPCkiQzme/6aO4W8M0wi1ZDPQc0XIXYzEtx4nV7ymhHZemB7FWyawVX3r3VXPUrDndJrjxjdeND1Vvw+nwlvCGUuaD1Gqw53hbXaw7oOh81L/TzcG8pANli7/TyrbOrdEfQ/NyL+uEkTuYM8T/4n+dPqJ371d5RXl3ZSQX7l67egZnzj8586NjMxHAtZgDz7ZBV90+41qCmPrFArJ0384jWqjt0F1o0KyBbBIguoP5Qp0AryCt6i8oeQRBPLNiIwNBUQt1jMf86GQ5U4kBYJZ7WaNty6h1g56/TPf/btb332qY/e94HD+/bOzxXzbRmPpmket4MFyYvJqMhMkYDQhuYbzzhWFEZEk94ZlXzPoGTpakyywbDePyapa+YTWUgSkRIfZ7BjjD07mlJBqj8SH4FPw8Z4gY80uTpTU/MBrD+ua9sixWBt/8Cm8JuG2/vn2a4sZLqz0Pj+sYyc0uZp5nnbkFOo6oYo8faDomL3eAd4uzjFC3HZLl0nyLKwVbLW6ymiWPX4RIljFQFrrhfswjTvc8l28TqkDAe2iEqQDoGgh6w2q5Tl0FsOKdKWLZIS4opO4DOyyxX08nSQBi1Y3Kidkc3a/PtWXo23/iyUpenmUCZD5/DQk8l8bxH7onq8TQnRxrsG+LxV7G2yy9ghW57nxx2CIGdtPjTFsnRQuFJTcGJNRe4NmDWtnawmL4Z1e5PHRuXaX09aZIe6TqU03ZQAsBYhTSleO2TLpMXitLM7YUsRhTDthRS7ZXdaaAHv1Vul2C1bMVVvZMFG8pVGVoDUlUZyHTee4U7RX9T12SmhsUB9ZmFZ9ITMsDoc9+qlhj7XCbWrbndLLukdEU/U51ajR7uQbt4QzpzXerUM6u+NWi8edCgGDbw8X7s9FIdkEO5FNc7oPewWAwEz7rCEdnSGONCn6SH3VR0xZJFtQEViAZA49G5s6N20E17gBP4Iqr3Ay8Iic4aQFS4iICDWoEICmjgWiGDsAujmpmpHvQWzkH9Yk7mqrdSS1DylsjdmQUYiuIpJZCCizvJ1LHDhajAShDOvGWyLlYpJM5DhYnkZ5ilejVzYxMvnmO9Gd0nKaDFxTTjh1VFFvnxOUsAmzs+bUQosLffRXax6/Qbdz+rXb0Dxmfl5szZ74OjVkAS5NodqI8lqDK0+JasBdtOxheNArmZJhWuzpNCit1zJjsJnazL87prk6AMHVmPgF+jjRGe+kQOuQD65yi01xi1/H/DrRoa74KxFnFln7ZeNnBrcZCbVqGHgDYcDjHqO7QLczJJsq9wSfSkb8ZMCmSfj1dG5mckNPJXtODKOTlhAkpFUssAiD1cSCYjKAo5bEEUBEVtgGTZBnL5uNhYar0TdbUGPSTDRt8px/cgthStnXlzhqAmyLHShhbl6LAqhmJeiOb6OdvgfEQ5hzoswbCIc7FejubiNOiP5sBtuuOZi++R679b07tR1voEJiJdnxnILubGZruhy1BibXdqabxvdMTnR7YlNOIJ9830z81vGunf0hBwTnzNyaRrPp4tRPpP1veNicMEmiraFwc7RrIEoEUhPPHh0uK0/qvHAK75oV3z46Om5Nfnq2my75s5lYG21c81cI/YxR18iPuToU9VNNpZDnmjBhRsnHAI7h5QRbZpoelkCehjLhLlehF8hErOF4iLOKW/OJ4vtCfzmbCKT8hgxjbn/16aur6R8WeqahfDM+E8qyYLSXvS9UF+SCBvFZBkxo1Fo0EdYAjusNZi1FmYZ7JcWBr8oYUdX090sYfGcqDBXfDUfDgvvncP+Uu3ENTnvchzuwdYoN3yjZGE1z08Zh5EQazLVlICqYyZvcSooupYApmvJ9hnwMB3zJMoeJwvkeVpKpukWGvFJEwHYiOs5A+NZCDFrB69EjMuvmz6H6+HvPkrdeHrhcM8sneo7V/uGmQqAAfQqDh94+OEDh8NmPGeJ+xhin5fEyRqytlpmmwp4rhH4B6QcArAUMs8Lc2wh9rCFmPb7sm3pVHPYF/fHm3Qzy8lMdT2ByRajXM9Nov2PqqAhz+iHYo4FDuphbu5j/b2LS2/ceKCvf0P/+qltz23bvL5/Q617+Njw8LH7jg0NHTNKEyX8g/Dt+2/o7unpvmH/7fPf3rI9Xy7nt2/5NuSHsFq9bi2JFRGOODMOMsjZUGqsKHMsk4EIwhNAl48IlEf8pRxnuiLcHpaunS4UWtwtLnMbQTGvSVGXeQQzVRwGE2oh+8vjR/Gv9sPeLL0120urmctn8euxY7+EmoAH+EJbL/TP9vev4uEzaEus6JlWSG91rZVSUeCA8OiXggAsCyEKLKckriaMeco8VN7EsrgnHY2lfIYZ3tKkhrFLuZLmQptrj0woRxli1KGeTTRjP8jo6jzo2bgixxGrY8h1uKLqOLE1OpKfSt34uGJRDXDZIqcXew+O6N0jTZ2G7NDoi2n9cp+J7fRFPR3OZAZq21SntN4X9k0LaHQ/6bLLzsFIi9WnBmyaOUbTXp7j7Ij5LSRfbUewJSq61zhExMO7GYjirB8iwHFmXpBNNnDT3hiyUTNrhJKAbLQfwEwOmCPq58PUq0leg5568JUH8Q/C2W7thX0fmnrwYJX2Hr7//P2He2H4BWTniw/SRy8+Lv5J7YlQRn9huH/pgU/ff1M3P3Dg0U0f2veCToS338T+vc5tRw3rRQQ/QR4nG6pDSyBwD7GY4kQbkLFr8/YCWwYEHorAw8TkGjn/+NkP33nstsX9Y6MdORFNV6UzxgI3LMrlzeso3iz1LhpsZ42YTEVLns5S2cwjIA9lkbGYaFaIMuZcSXQWDFMnvEg6U7iuLIrLFMZEJE9nR6eZr8D6yXZqvsNcXS+6LcBuxqKpXGNnCXsOfirMxjGZyIHVI6quCLXwdArHKFk52ebhpCnewsEJ3R8yBh+fVCIg8+mAWtiV5mRuMw8cnQRfwBnuQoMoCgd4tu9JsIgdcxJtBovwhmixKS2HBnmFIpHneGeLfTzAyXsFsTYWDkf9mz7WzfMz+AbNZtgWlixcCCcP6AO+3tD44xt49Hd6EP2crVp+sUMWujgUddoPHrdmTTZbqHU3whylclsLpd0U/VPVbQsU754QJACBVzyqrix08ZYduC6XL4WbIt6RW5MsJb3Ay1Rpsm9clEEUakc43rKuxFn4HgqcU1LFdlHegTWgzi//N3cP2vJ2sqk6lstmIhQtsx+5neGmHI98lPITzE6fqUf8zA1HdaWsEwxiii8L8wGZjhtGzBVNm2ltEZ0mlUuZEU8Wyat/9aH7k0OvBBfYxMC8t1wRpTJ3T6KU2XriqT2P3enxLe/t2eH2OHy+dTPJbCLrH/rmLcLS2OZSX1nvKdKbyinvxgfu3lel03QTjJQ50b53gOrUP7k7s2WfoGvjB2GtLVKNi439Us9QL2K3RgrINYGIjD5T7m7mooJIFgUw+aXAbNcunGxkmDEX/vO0mKNAtiiGoCDFXPgpFcwwJfVu64ieN+7/3P33H90zw40/lE4vXahth6cu3HHwyOo+gXm06Ywrt5NKtZjG+ZRZtBTVH8018l1Gc3E1WGrunVtykiX8FMy81DUZcXNbzjXbdLyN69i113Oa861fm4aaczkMeJ+rfRvMU/MIzlEEPc1hHkHdwLaqbWANVnHsb2kv+h8qCZFYNdKI5F8rAY2gQjH5jm1eyXqnU2YfWeq7Hv/7vSC/5qjZEGBtZoxP+V8OhYX8lTB262UzXWReNvrxDPe6mffsImuqGRbH5H6vIw1RrM9jpZiMdxf4Rn61nq40kYUy8miiRoWZCgeYyU/Tb2dQwwL4dd/gUiM96W++OBFJDjXR4EC6edeXI75y698US7Zo2E5tYVfYHhUf2u2O9UKujStj9W/Vhk0fAr7WZNxb8QWCEAh6h04aL2SnQg/GUha3DRTFLQe5/QOqdybe1l1s5Iy+izzwbTxTSYaMVTdE0RTChGRBRiXIIKyIPEXZuZvJjcwh28AyeY6gC76HCLIwTUhrqiUSbDI0l9Nus4iMcbtYzNCDklupsz0zeY6XxXoKUHfFyn2QKugxJNN548WvvNSdg1xX944u+tEv5zpiObv4FYCvgNWX7I3uOgq/vfwj2vq51nJ5plyuVWsvQrpnIBlyBWvf+cf7LjRNuQMRJyyv7pXo4Bi/KLB9mhkAsTMmcKb4iwKjsSvMe2VpTbQm5o4Dtk+TN0M1jMZy/OZYumxozIaHWGSmDa7svcOuayhJeZQoobGwKGps0er0n1F/lrlV5DsV6bCk3CkrwkuCE//D/pPzl88tPgyTA/DU8W0PtKRLPbPe0QWYkJWXmFf3ksKqCS+Jx+dOwoMHR0+Gfcef2jsVm+1pi7qOr+rD1bENVwcyiCidMRyNHaGDY8ND/4asmHF0HO9KY1/hIeQwPN2GQsuGR9nwSlosodWHh3IXdTBzj95pfetgH5jbft5neI0xXTPKf3N4t8j1UTlWR/mJ9xwek8G/4A36VcTKOFnL9nPmXGb8sB46NFOvpWI65XUztTI3VV0TqmTbNzXgVDDtuKcfWGRrddPVld2ebOcVbGe72WpvsUSS4OSDovjaayIMvUJVMSqL8H1qk2LoCxzGGqoYFITXXhOEIJ5i7WG8BEFg5wiR2Pgnr4kqnbzcLsmchbPJ9BV8gELV2tna/6k3eu0nWBtfUXtLcNbtwc+Rl20h++Ce8aeVqe1VY3KQWqQmHGFnys6C8RNF7PZ40/jTVrzrnhwscsI7bjf9W03m5saftmCb9USyoPdrEVj4H5ksGmEro7IKKBy6cdRMtqywLTXEqhDrHFGwXwoycKuV2VErmW6qd2342gfJaH1lUUZe/B9/GBtJH5EE6YwF/h979EcY1dzcXNV9w56FHVtm/JlooK21Kxa1mS5/g7Cj8Et6TKWSuRuDVkycwkKW9zPjmymG0dGSC6m8l/GJcqmYo6gbSP+8mork2NxIxkK1usYq9FOWijqXz3rTgaTW7wa3Z6TXF8u5A07an20fcFs8CvXr2fIWweAtoFg0uqWc1f1OQ6UDHdle0AyD5kbuCiDdsnv8flskmPXl8v+yplcztGFjq84hKYNwREsG0t5svrjGl1XDTpvf77EzVgG0h1Kqaj6/PRLI+dYUwexJ3IiEwYmEQ26eLa3RAk7DOUDYDDE/cwy5igWZgxetQA/ZhtbsBPqYD5PP0O9V4xfOnV7+kGDoj0OT0QlgQTIKW/t7I0HEHHc5QyUiTtRl8FY0O+HAmWasGDKaQitMeSwCb1nx2K0cCoHlFoeM1W026Ug81sKFiW6E9UNRQL835DdCh4hfRYbpFxZNJHOzjfRul0KJ5CaHNCe1Ea/P5l1iZzbfXuKz+WYaMntn/cXxGG0J6+EWfeUdXbALvH3FA3aLYL/FCu/sB/njdILJ+mK9E+8e9O+NtTnENfmNpn/nRQ6bLEj4Lsm7eiH59hCf5GOqpf7/mezqkX/vnbD8x37pHFPgkUceeeQzj3zm/Kc/9cn/9InHHn3w4/fde+quO0/e8cHbjiwe2L9v18L181tmxsdGhgfXr62UioV8R3trOh5rDjUFGK12ud2xaIIpvY7WPVVi8ToWoM0nCqWYXnD1UFdMN/P/fRBjSox2vlRMJaNSKeYqlEylr5RiJhqgkazfYjvy2dYt5HRYOYpXeTA3fIsR0xt0mm5ixPQqkcvj+5hLWWg28y7RRpoEEaWCFL/x7oLOXlWiYcNus9mN/1LIX/557xd6KufyeZdDAcgLUjH8PwSl25fP+5vCivD1AvDuwD6HMW44nMakhv5g7c87OuDjqpyPHKjtXYzkJYdDykcW4ckDLXlJvfyDtYNdckB39qZ+69SxFTbVnV8rhIN+mS9QxeH60+MJ21O2pN+fnC0Wa/8VtB94rdT9nb8P2vVo6aZWtTn8wdr9Tc3NjnYpJGjJzrVZPRjUs7uzeijscAjUfyyVOpaqnT5VbcnhKnLZaD/IeM5ZrTye08F/fOyxzKa17Q+l9uS0UEhfs2cNe0Cu9npzTLeHfvLfbL6/RVwSzHjNnLnf30UCZJZ8gNxQ3e0GTkACrlBJUo4Qu1VF99gush9S8OgqHmJ0AthOAhQuBeghCwojyuIc+5Zsu4lNsk1Fmpb2L8zNTPf1dq9lyfOm2cgWj+a5JiFn/iag0tgSWqlvy8sbiWgbC5mxFVapIeJHY2QD1zdvlPGDq83+aLKMn6L5K4Ec0l+xIRTRdwnFld8EjK88fxdd/urJdeFskEbS0do/86kebSjnCmZsooy+Of4TFVsm6OwYyEwoY9lq0R7MKldvWTMhZ24kOQWf5YSV2/K1/NEVgcPTo51AOo8ui9xqrqrnevaiZXrXfXo4nAmHD/CibGXPHUpOiVPJIV86mLGKCs/+oTP/nrdqn17pNJ8vLh8zn7963og/1fM1aeYvBT3oLsEED+/+LQaQaMRnKDJxgKORekBrS80oGiC7A3Mbk2miK+g+sZ+68NyZVC/4/2K8PLhhHxRhX0sta4y1A334g0NL1Sh4PZGI4pXVeKarm5sppmKdtXPDhYP3t8Ng+PILmX5r+vijxfkjAy7VcGuJYsS46qtfRG42xph1DATqAXSRJ4JstxflBZ6av/Li2a+8CLJowqQMazCvgQWDOZgeHupZ29nemkonRKSoLralMx+GeiAimZJUwQFm7HUd1KMPyKZV9uudfn6VbIQpc6tTOS4ztvum7u2PL2gd1d3dyTHUell1uqNuSbD4/CF395posgPy8eZiPOAU4Y4bbn5UdapOuyWU9dmo0Ls01R2Gsfvnygd2j+RovHldq6/L6EgHOXG7q7Cy59Z4d/sU5KKJ+zbkgh3d1d7A7sMP3OzPBQK8Iw+WbH/3/wV8V8/ieJxjYGRgYABiZ81nc+P5bb4y8DO/AIow3Jlw+CiM/v/rfxaLAXMEkMvBwAQSBQCJGg5uAHicY2BkYGAO+p/FwMCi///X/18sBgxAERRgAQCWawZSeJxjfsHAwOwBxAuAWBCKI///hdBQ/AKKgWpY9P//B2HGVJDY//9Mp6BqgHJMP4DYGkk9kj4QDVYLNgMm9v8/2G6YGqA5TE1AuheInWDiQDUv/v8Cm28NVWMNFvsPYsPcAzcT7maI2wDv0TcZAAAAAABGAMgBEAFaAeACCgLMA1ADhgP+BIQE3AWgBcgGWAacBzIHmggcCEQIZAj0CaYJ3ApgC6QL2AwcDcAOBA6iDtIPCg+wEDoQghDoESoRnBHsEvATYBOaFAAURBS0FRoViBX2FmgXthoCGtwbNhu+AAAAAQAAADgA8gALAAAAAAACAEoAhwCNAAAA+w4MAAAAAHicdZDNSgMxFIVP7B9acaHgOm6kIk7bARfWjVhoXSl0URAXMo7TmZTppGTSlvoIvoMP4Qv5LJ7OBKmCE5L57rknNzcBcIgvCJTfJWfJAnVGJe+ggWvHFeq3jqvkO8c1NHHvuM7x6HgP53h23MQR3llBVHcZTfHhWGBfNBzv4EAcOa5QP3FcJV84ruFYXDmuU39wvIexeHLcxKn47Ov52qg4sbLVP5N+x+/Kl7XUlFQWpDJY2ESbXN7Iic5slKbaC/XsbaVUqEdRvEgDUwblOo5MrnQmu16nFIZRFpnARq+bqvky9q2dyInRMzlw9eTc6GkUWi+xdt5rt7fPQR8ac6xhoBAjgYVEi+oZ/z46nF3SCx2SztKlkCFASiXAgjuSIpMzvuGcMMqoRnSkZA8h1xnesOJOVUQjZmPuTVnB/Mps85iuTV1VVJTsxGNH244hHVnhCooTX396zbHkCT5Vy442XZmiC4nBn/4k77/JTamE1L3iFSzVHtoc/9znG7SWfQsAAAB4nG1Q11LcMBT1WWTZJgvpvZBGIMXphXyOLF3bmpUljwoMfH3k3eEt9+1c3dNUrIrd7Bf/nzOssAeGEhwVajTYxw2scYBD3MQt3MYd3MU93McDPMQjPMYTPMUzPMcLHOElXuE13uAtjvEOJzjFe3zAR3xCi8/4gq/4hu/4gZ/4hd/4gzP8LdazSaGV2ktDihs3uBTZsuNSWEmGjWTmctI2BTaQ8HwmK7VZpXmPLqlW7sIaJxTvnVHkyxTIB2aoj2wS2rAF8zQrEYmNbqIyehFGttAq6aaJbGRyFLHKYq3r+2Z5aV02yaxFmEk3hGYR3G63hm2nh8weWmFiPltgKY2zdLDNed2mlCPJDR90HFNX5mraMuPkhk160lzpc62I9UYMPORicmRh1raKFzpG8nUvJHXO5WuyiQXnY700Wjxro+2GlLaH1/XbbJ/Uehd5B3JwRXxOV1eGqsv8q6mjRtsQxeDFVHY+hbHJhtmLQiyKf6CZkqR4nGPw3sFwIihiIyNjX+QGxp0cDBwMyQUbGdidNjIwaEFoLhR6JwMDAzcSaycDMwODy0YVxo7AiA0OHREgforLRg0QfwcHA0SAwSVSeqM6SGgXRwMDI4tDR3IITAIENjLwae1g/N+6gaV3IxODy2bWFDYGFxcAlBwqBwAA') format('woff'), + url('data:application/octet-stream;base64,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') format('truetype'); } /* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */ /* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */ @@ -17,7 +17,7 @@ @media screen and (-webkit-min-device-pixel-ratio:0) { @font-face { font-family: 'zwiico'; - src: url('../font/zwiico.svg?55150548#zwiico') format('svg'); + src: url('../font/zwiico.svg?65225042#zwiico') format('svg'); } } */ @@ -95,6 +95,7 @@ .zwiico-mimi:before { content: '\e823'; } /* '' */ .zwiico-divide:before { content: '\e824'; } /* '' */ .zwiico-flag:before { content: '\e825'; } /* '' */ +.zwiico-search:before { content: '\e826'; } /* '' */ .zwiico-spin:before { content: '\e831'; } /* '' */ .zwiico-twitter:before { content: '\f099'; } /* '' */ .zwiico-facebook:before { content: '\f09a'; } /* '' */ diff --git a/core/vendor/zwiico/css/zwiico-ie7-codes.css b/core/vendor/zwiico/css/zwiico-ie7-codes.css index 6e732fc0..2f820279 100755 --- a/core/vendor/zwiico/css/zwiico-ie7-codes.css +++ b/core/vendor/zwiico/css/zwiico-ie7-codes.css @@ -38,6 +38,7 @@ .zwiico-mimi { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .zwiico-divide { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .zwiico-flag { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.zwiico-search { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .zwiico-spin { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .zwiico-twitter { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .zwiico-facebook { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } diff --git a/core/vendor/zwiico/css/zwiico-ie7.css b/core/vendor/zwiico/css/zwiico-ie7.css index f7920c99..9d7aa389 100755 --- a/core/vendor/zwiico/css/zwiico-ie7.css +++ b/core/vendor/zwiico/css/zwiico-ie7.css @@ -49,6 +49,7 @@ .zwiico-mimi { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .zwiico-divide { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .zwiico-flag { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.zwiico-search { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .zwiico-spin { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .zwiico-twitter { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .zwiico-facebook { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } diff --git a/core/vendor/zwiico/css/zwiico.css b/core/vendor/zwiico/css/zwiico.css index c2b405f7..ea9a526d 100755 --- a/core/vendor/zwiico/css/zwiico.css +++ b/core/vendor/zwiico/css/zwiico.css @@ -1,11 +1,11 @@ @font-face { font-family: 'zwiico'; - src: url('../font/zwiico.eot?44489499'); - src: url('../font/zwiico.eot?44489499#iefix') format('embedded-opentype'), - url('../font/zwiico.woff2?44489499') format('woff2'), - url('../font/zwiico.woff?44489499') format('woff'), - url('../font/zwiico.ttf?44489499') format('truetype'), - url('../font/zwiico.svg?44489499#zwiico') format('svg'); + src: url('../font/zwiico.eot?32340763'); + src: url('../font/zwiico.eot?32340763#iefix') format('embedded-opentype'), + url('../font/zwiico.woff2?32340763') format('woff2'), + url('../font/zwiico.woff?32340763') format('woff'), + url('../font/zwiico.ttf?32340763') format('truetype'), + url('../font/zwiico.svg?32340763#zwiico') format('svg'); font-weight: normal; font-style: normal; } @@ -15,7 +15,7 @@ @media screen and (-webkit-min-device-pixel-ratio:0) { @font-face { font-family: 'zwiico'; - src: url('../font/zwiico.svg?44489499#zwiico') format('svg'); + src: url('../font/zwiico.svg?32340763#zwiico') format('svg'); } } */ @@ -94,6 +94,7 @@ .zwiico-mimi:before { content: '\e823'; } /* '' */ .zwiico-divide:before { content: '\e824'; } /* '' */ .zwiico-flag:before { content: '\e825'; } /* '' */ +.zwiico-search:before { content: '\e826'; } /* '' */ .zwiico-spin:before { content: '\e831'; } /* '' */ .zwiico-twitter:before { content: '\f099'; } /* '' */ .zwiico-facebook:before { content: '\f09a'; } /* '' */ diff --git a/core/vendor/zwiico/font/zwiico.eot b/core/vendor/zwiico/font/zwiico.eot index 66efe7e20071a21e00bd114e4e6a4e35ba9edb1d..0623aecc28f256b6ec3ac89d893da18ec1debad7 100755 GIT binary patch delta 825 zcmYL{Ur19?9LK-s-0O8k&2o1esF{CCbefi#Q?u)sN(2^_zC`qA&AB+OvLWkEE$^rHQ5SN^{dh@W;njVwrJA!WijqUs9uk%SrI`F7kH5F??UUph z`4;l4zAon(hjXoM2xusyK)2t~7v!dld*q*z&kH#GuB(Zcm&v~Y`0HR-Pw(k-U#0+i zANibMw<|a}cXAH6IIoVg#nNIh$^$Eaurn$n-A!*6L&PRcac~_d1){)ek!nV51)6_0e+BKb8o0>H`D1K(4A|OtHYKv3NDNq6=9%;Zr zI-!A5(hnM-QWGm0I6}Ir0lJ68R}EB<(mAETQPS@kpl|%h*HBPN14>GP_B_W7`0hu4LOY^ zGo9Bm>VF|ah|}J&GP3yYpQ<{=%4$@bGATSwCe>9XT)h8VX2NjYFd;*3l3y9KjQ5S3 zCXab8i)XE5S7$F!YU($siAEZJa>^aH2RN&ZZrIaUy42%xbUQujR%0mI-xSmT1zKp_ A9smFU delta 632 zcmYL_O=uHA7>3{7P17PZDQ;r56-luMZEO9joBEelQU!Y{DkvycVw+@<{H!);6)_^H z7Yn9)iJmG#6}=Q!gQp_sq1vMdJuKLIkQ^FGG#-?SzR4iY@a!}1eDm!rTX`hCoR*xu z$AH|?tW$H$VN%QX-_6_{p11@^j{(Q*$i=h|wGmpNTu~#IINSa63J@wWHpaqZ2KSqo zKhh1c_~q#PllBe3sRNp=N5Z46ML+M@Kft=CbE7_^%rjqQZr2m(@!8*hzA{fS+ws)M z;qc)6i3T88Jzyllp!qrymmgAo-xwR$cT8p7g_k3JdG`@d{jR*}_KimVCNdhmLc#8AtN}G=Iq{ zzQFnLydq_X>Q=H-&hb$lnswdrLCS0g3Iv;g(meq-)At4Fpx+A6N!tQ+(F+1>p%(?{ zri%h>rTLSpU>i_w6M*-Xd9F$ic5o3BU?-gru!8ck0K0&1Y^nkcusrp%>Urnw^-ix|(;Qv< ltmRJ2m)2zMHwUak{oiHw> + + diff --git a/core/vendor/zwiico/font/zwiico.ttf b/core/vendor/zwiico/font/zwiico.ttf index 1cd9d571690fc563ecafed29f49d1c7698fad0b9..f04c925200d219abc30098d2805283c651b8e5b1 100755 GIT binary patch delta 808 zcmYL{ZAep57{~wT-0f;nv)tVVYUWGHd}*4QQ`2R>5P?O7Uo3iAbM88}Idp_&G%%<> z#L(RklZYu6L4F8U(kB;5(2Gz(5QT(&k$uQmi=-f2&%8wE+#mn*f6jf*J;vR6)9tUNl34Rhr1By$jG4j>b!rWp>Ksh8v#s?t}k-S5ELgt(Ddh zm3Mqisp4AYjUaBAPOnYP8vQJMV8Id~PJl{_Q^{#i3M6i+pp0}v1?8kKRX~*{7FDo| zbV&tt4T&!*s3fIhN`orWZz`Z~d@oe7p_&Gilm>f9T`H&{^{QYm=^qu;0!dmR4b>ov z^~FJ+N~PSwq_7#8C`5I0<#xuPV*=wH-~zu&=LV)hFPI>(E-)t8Au!>XsaVoyYsK7h zR%2nJWVA6RiA9x6EH1Ken5!+9wZ{ys zVAvJrW3R@=8*3BW$_%k~n|ov`W&$rkXb;+q!3A^lxADVy!C5#LVs32Awg=B9vN~B*A1&i*)*HOa~5-JbLS{E n{hQQ9leQn6a+eSIIIE9#wrE*~IN-GRJ7lG+H5mQa8q@s+ofp_h delta 617 zcmYL_Pe>F|9LK*iW1EQVinFVw5i8kZYG(gti)y8IFG&#*Bp4Z!?(PsfyF)Hz5iJDK zB_W#*=E;bbpo=u*QGz;Do}!=*1Faoo4;i~zcud^#x^-`5JSlVdf_me*gK(Jj?86a-&D}!Ns9^Am%NwOnt(V zLxEe&Uzo#L-As;D=FR{Ejez{j%8lngFMXN^4!>kpt&2(P`uqXrlWS8yU-U#EaT}yC zl-j75Zs5WQ>afbfX8yYZf5%jLtGz6pZ8c!vLak?z{on0jImZKh58ujCGq>?>9y0BH z*)*r5e2@w|figiCP`NL_HhM;YZu+$VJ+v!8FI^H~JG~@8AH5>L4w|pzfqtOcApq~I za-GK>?BXCTz;4$U+gBQX#fBK diff --git a/core/vendor/zwiico/font/zwiico.woff b/core/vendor/zwiico/font/zwiico.woff index 272be499556e044ac711d4d1182165f0d1e3a721..51ae44d0bb96f828abbcf1ab94315f834e5dd9c6 100755 GIT binary patch delta 10955 zcmXw{`p=A0T%{2?;Q8u+PCZ42JUGS@nB7NER3Y1A`hTzwTl%adROC1A{F5%piP% z{0W%3gN5ye42LNdW9br)L_Q&#&%g`R*57d6z7~(UWZV7K^BP{~8@71j6XZwE%@uyJ{4nkS zGS5HO0bpD02#28S_?e@t>t?5>;&jm^AVguqG=aLX}d=8=>iB^a>db*A>Y{-d>Y9OS>Q=EoNk+y~N#@3zN!Iz+GF&sPX4za!MLAq-d%0XJ z?6UrcnLNMFGggG#nC^mHepn$Mt&9SaZOn~fF4o5wN0W1Oe>=-e3Sm`OhxJr1h9OlU zM=XjN5~k#Nk@6#trn7lX-6mD+GAD5wWawp1R5 z1;(nc2gpRlvf=J59Q1;u@S;|?QT*z|1)%x|B_Z0uZ#?9l$#mD=Hpga|c zJpd%*?NP;tON5l4KyP`BI=hHN(OiAkPVq<0A$ui_2P?D{OE5$Mhb#8CBy1i#Qaa

    EyD~gwn00? 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 literal 11444 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 Date: Mon, 5 Apr 2021 15:54:19 +0200 Subject: [PATCH 14/14] Search bouton loupe si pas de texte --- module/search/view/index/index.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/module/search/view/index/index.php b/module/search/view/index/index.php index 1b809245..d308b95c 100755 --- a/module/search/view/index/index.php +++ b/module/search/view/index/index.php @@ -8,9 +8,11 @@ 'value' => $module::$motclef ]); ?>

    -
    + getData(['module', $this->getUrl(0), 'config', 'submitText'])) ? 'col1' : 'col3';?> +
    $this->getData(['module', $this->getUrl(0), 'config', 'submitText']) + 'value' => $this->getData(['module', $this->getUrl(0), 'config', 'submitText']), + 'ico' => 'search' ]); ?>