diff --git a/VERSIONS b/VERSIONS
index 6da239bb5ea4d888e606a096118f65cc594fc0c1..08825909d1ddf8215689b70b53617dee21b66def 100644
--- a/VERSIONS
+++ b/VERSIONS
@@ -1,3 +1,11 @@
+06/02/2020 - v8.0.41
+
+ - ticket #105040 : Articles / Formulaires : Correction de la détection des robot pour des formulaires ayant des noms d'input contenant des espaces, des tirets bas et des crochets droits
+
+ - ticket #105091 : Performance : Correction de la perte de performance suite à la livraison des nouveaux groupes dynamiques
+
+
+
 03/02/2020 - v8.0.40
 
  - ticket #101015 : Articles / Formulaires : Amélioration de la détection des robots
diff --git a/VERSIONS_WIP/103980 b/VERSIONS_WIP/103980
new file mode 100644
index 0000000000000000000000000000000000000000..9f3e706c69431e7c327cf7c3460748da877c64d7
--- /dev/null
+++ b/VERSIONS_WIP/103980
@@ -0,0 +1 @@
+ - ticket #103980 : Administration / Domaines : l'écran de test/indexation affiche maintenant la liste des notices complète avec pagination et vignettes. Permet de générer les vignettes des notices.
\ No newline at end of file
diff --git a/application/modules/admin/controllers/CatalogueController.php b/application/modules/admin/controllers/CatalogueController.php
index 89d366e7e4bfdff9c93b085d6a73488ab64526dd..2ec4cd43ac98e8412238bfc064c53079ce3e2f7a 100644
--- a/application/modules/admin/controllers/CatalogueController.php
+++ b/application/modules/admin/controllers/CatalogueController.php
@@ -40,12 +40,16 @@ class Admin_CatalogueController extends ZendAfi_Controller_Action {
     if (!$catalogue = Class_Catalogue::find((int)$this->_getParam("id_catalogue", 0)))
       $this->_redirect("admin/catalogue/index");
 
+    $this->view->page = $this->_getParam('page', 1);
+    $this->view->nb_per_page = 20;
     $ret = ['requete' => '',
             'nb_notices' => 0,
             'avec_vignettes' => 0,
             'notices' => ''];
     $this->getRequest()->setParam('render', null);
-    $ret = array_merge($ret, $catalogue->getTestCatalogue());
+    $ret = array_merge($ret,
+                       $catalogue->getTestCatalogue($this->view->nb_per_page,
+                                                    $this->view->page));
 
     if ($catalogue->hasIndexer())
       $catalogue->indexWithBaskets();
diff --git a/application/modules/admin/controllers/ModulesController.php b/application/modules/admin/controllers/ModulesController.php
index 9d48c274efc5737b890f5fb992b18bcc1665cfce..b86bc9f4495c1cb8a09f6ac5d78824d6ef8612f6 100644
--- a/application/modules/admin/controllers/ModulesController.php
+++ b/application/modules/admin/controllers/ModulesController.php
@@ -541,12 +541,10 @@ class Admin_ModulesController extends ZendAfi_Controller_Action {
 
 
   public function applyToAction() {
-    $module = new Class_Profil_ModuleDefinition($this->_getParam('type_module'),
-                                                $this->_getParam('action1'),
-                                                $this->_getParam('action2'));
+    $module = $this->_getProfileModuleDefinition();
 
     $this->view->titre = $this->_('Étendre le paramétrage');
-    $this->view->form = $form = $module->getApplyToForm($this->view->url);
+    $this->view->form = $form = $module->getApplyToForm($this->view->url());
 
     if ($this->_request->isPost()
         && $form->isValid($this->_request->getPost())) {
@@ -556,4 +554,17 @@ class Admin_ModulesController extends ZendAfi_Controller_Action {
       $this->render->renderScript('modules/_retour.phtml');
     }
   }
+
+
+  protected function _getProfileModuleDefinition() {
+    if (!$id = $this->_getParam('id'))
+      return new Class_Profil_ModuleDefinition($this->_getParam('type_module'),
+                                        $this->_getParam('action1'),
+                                        $this->_getParam('action2'));
+
+    $id = explode('_', $id);
+    return new Class_Profil_ModuleDefinition((isset($id[0]) ? $id[0] : ''),
+                                             (isset($id[1]) ? $id[1] : ''),
+                                             (isset($id[2]) ? $id[2] : ''));
+  }
 }
\ No newline at end of file
diff --git a/application/modules/admin/controllers/SystemeController.php b/application/modules/admin/controllers/SystemeController.php
index 6e9da91e37762afdf40c6aaf869ad1ee3a761e8d..b5bf8826b6e5c29b19e7abe68d4467dee0678e3e 100644
--- a/application/modules/admin/controllers/SystemeController.php
+++ b/application/modules/admin/controllers/SystemeController.php
@@ -41,8 +41,7 @@ class Admin_SystemeController extends Zend_Controller_Action {
     if ($this->_getParam('mode') != 'reset_no')
       return $this;
 
-    Zend_Registry::get('sql')
-      ->execute("update notices set url_vignette='',url_image='' where url_vignette='" . Class_WebService_Vignette::NO_DATA . "'");
+    Class_WebService_Vignette::resetNoDataThumbnails();
   }
 
 
@@ -89,16 +88,15 @@ class Admin_SystemeController extends Zend_Controller_Action {
 
 
   public function makecacheimagesAction() {
-    if ($records_count = Class_Notice::countBy(['url_vignette' => ''])) {
-      $record = Class_Notice::findFirstBy(['url_vignette' => '']);
-      $record->fetchUrlLocalVignette();
-    }
-
     $this->getHelper('ViewRenderer')->setNoRender();
 
-    $html = $records_count - 1;
+    $cache = new Class_Notice_Thumbnail_Cache();
+    $cache->build($this->getRequest());
+
 
-    if ($next_record = Class_Notice::findFirstBy(['url_vignette' => ''])) {
+    $html = $cache->getRecordCount();
+
+    if ($next_record = $cache->getNextRecord()) {
       $html .= $this->view->tag('div',
                                 $this->view->tag('a',
                                                  $next_record->getTitrePrincipal() . ' (' . $next_record->getAuteurPrincipal() . ')',
@@ -107,7 +105,12 @@ class Admin_SystemeController extends Zend_Controller_Action {
                                                                                    null,
                                                                                    true),
                                                   'target' => '_blank']));
-      $html .= '<script>makeCacheImages("/admin/systeme/makecacheimages")</script>';
+
+
+      $html .= sprintf('<script>makeCacheImages(\'%s\')</script>',
+                       $this->view->url($cache->getCallbackUrl($this->getRequest()),
+                                        null,
+                                        true));
     }
 
     $this->getResponse()->setBody($html);
diff --git a/application/modules/admin/views/scripts/catalogue/tester.phtml b/application/modules/admin/views/scripts/catalogue/tester.phtml
index 179abfb8eb3fe03a34543f6d4581279dfe8e56a8..a69b81bf66c507842ae290884ac2c2d82764deeb 100644
--- a/application/modules/admin/views/scripts/catalogue/tester.phtml
+++ b/application/modules/admin/views/scripts/catalogue/tester.phtml
@@ -18,7 +18,14 @@
                                                                ['alt' => $this->_('Paniers'),
                                                                 'class' => 'ico',
                                                                 'title' => $this->_('Paniers rattachés au domaine "%s"',
-                                                                                    $this->catalogue->getLibelle())])),
+                                                                                    $this->catalogue->getLibelle())]))
+                    .
+                    $this->tagPreview($this->url(['module' => 'opac',
+                                                  'controller' => 'recherche',
+                                                  'action' => 'simple',
+                                                  'id_catalogue' => $this->catalogue->getId()],
+                                               null, true),
+                                    $this->_('Visualiser le domaine "%s" dans un nouvel onglet', $this->catalogue->getLibelle())),
                   ['class' => 'header_actions']);
 
 
@@ -30,23 +37,44 @@ if (!$this->notices)
 else {
   echo $this->ligneInfos($this->_('Notices trouvées'), $this->nb_notices);
   echo $this->ligneInfos($this->_('Avec vignettes en cache'), $this->avec_vignettes);
+
+  echo $this->Admin_GenerateImageCache(
+    $this->url(['module' => 'admin',
+                'controller' => 'systeme',
+                'action' => 'makecacheimages',
+                'id_catalogue' => $this->catalogue->getId(),
+                'reset_no' => 1],
+               null,
+               true));
+
+  if (!$this->isPopup())
+    echo $this->button((new Class_Entity())
+            ->setText($this->_('Modifier le domaine '))
+            ->setAttribs(['title' => $this->_('Modifier le domaine : %s',
+                                              $this->catalogue->getLibelle())])
+            ->setUrl($this->url(['action' => 'edit',
+                                 'id_catalogue' => $this->catalogue->getId()]))
+            ->setImage($this->tagImg(Class_Admin_Skin::current()
+                                          ->getIconUrl('buttons', 'configuration'))));
 }
 
+echo $this->pager($this->nb_notices,
+                  $this->nb_per_page,
+                  $this->page,
+                  $this->url(['module' => 'admin',
+                              'controller' => 'catalogue',
+                              'action' => 'tester',
+                              'id_catalogue' => $this->catalogue->getId()],
+                             null,
+                             true));
 
 if ($this->notices) {
   echo $this->listeNotices_Tableau($this->notices,
-                                   ['liste_codes' => 'T;J;A;N']);
+                                   ['liste_codes' => implode(';',
+                                                             [Class_Codification::CODE_THUMBNAIL,
+                                                              Class_TypeDoc::CODE_FACETTE,
+                                                              Class_Codification::CODE_TITRE,
+                                                              Class_CodifAuteur::CODE_FACETTE,
+                                                              Class_Codification::CODE_ANNEE ]),
+                                    'open_links_in_new_tab' => '1']);
 }
-
-
-echo $this->tagNotice('Affichage des 20 premières notices uniquement.');
-
-if (!$this->isPopup())
-  echo $this->button((new Class_Entity())
-          ->setText($this->_('Modifier le domaine '))
-          ->setAttribs(['title' => $this->_('Modifier le domaine : %s',
-                                            $this->catalogue->getLibelle())])
-          ->setUrl($this->url(['action' => 'edit',
-                               'id_catalogue' => $this->catalogue->getId()]))
-          ->setImage($this->tagImg(Class_Admin_Skin::current()
-                                        ->getIconUrl('buttons', 'configuration'))));
diff --git a/application/modules/admin/views/scripts/systeme/cacheimages.phtml b/application/modules/admin/views/scripts/systeme/cacheimages.phtml
index b3216845ee91bd01a0fe28fad1408360149eb4d7..ad7e4072951d5ad00a03a52e06fc72894fb765d6 100644
--- a/application/modules/admin/views/scripts/systeme/cacheimages.phtml
+++ b/application/modules/admin/views/scripts/systeme/cacheimages.phtml
@@ -1,6 +1,3 @@
-<script src="<?php echo URL_ADMIN_JS?>jquery-1.6.4.min"> </script>
-<script src="<?php echo URL_ADMIN_JS?>cacheimages.js"> </script>
-
 <?php
 
 echo $this->tag('h2', $this->_('Base de données'));
@@ -20,14 +17,4 @@ echo $this->button(
                       ->setUrl($this->url(['mode' => 'reset_no']))
                       ->setImage($this->tagImg(Class_Admin_Skin::current()->getIconUrl('buttons', 'generate'))));
 
-echo $this->button(
-  (new Class_Entity())->setText($this->_('Constitution du cache'))
-                      ->setAttribs(['onclick' => 'makeCacheImages(); return false;'])
-                      ->setImage($this->tagImg(Class_Admin_Skin::current()->getIconUrl('actions', 'down'),
-                                               ['style' => 'filter: invert();'])));
-
-// Constitution du cache des images
-echo BR.BR.'<div id="bloc_restantes" align="center" style="display:none">';
-echo $this->tag('h2', $this->_('Constitution du cache en cours...'));
-echo $this->tag('h3', $this->_('Notices à traiter: %s', '<span id="restantes"></span>'));
-echo '</div>';
+echo $this->Admin_GenerateImageCache();
diff --git a/application/modules/opac/controllers/FormulaireController.php b/application/modules/opac/controllers/FormulaireController.php
index 145902b4e223f5b07b2f64bb03a4a6ef40f40bc7..a5525e7bd37d5ec18ab4a05c10b5466b19b283a2 100644
--- a/application/modules/opac/controllers/FormulaireController.php
+++ b/application/modules/opac/controllers/FormulaireController.php
@@ -56,7 +56,14 @@ class FormulaireController extends ZendAfi_Controller_Action {
                    $article->getContenu(),
                    $all_inputs);
 
-    if (array_diff(array_keys($post), $all_inputs[1]))
+    $clean_input = array_map(function($input)
+                             {
+                               return str_replace(['.',' ','['],
+                                                  '_',
+                                                  $input);
+                             },
+                             $all_inputs[1]);
+    if (array_diff(array_keys($post), $clean_input))
       return true;
 
     return false;
diff --git a/library/Class/AdminVar.php b/library/Class/AdminVar.php
index 2ebf0a7a9058fd2ccd9429e88e517f8c44c4dc18..2078dc7dabc255cb3c7c0d069093ce0939419bb1 100644
--- a/library/Class/AdminVar.php
+++ b/library/Class/AdminVar.php
@@ -23,10 +23,8 @@
 class Class_AdminVarLoader extends Storm_Model_Loader {
   use Trait_Translator;
 
-  /** @var array */
-  protected
-    $all_vars,
-    $_all_vars_values;
+  protected static $_all_vars_values, $_all_vars;
+
 
   protected $_inited = false;
 
@@ -115,10 +113,10 @@ class Class_AdminVarLoader extends Storm_Model_Loader {
 
 
   public function knownVars() {
-    if (null !== $this->all_vars)
-      return $this->all_vars;
+    if (null !== static::$_all_vars)
+      return static::$_all_vars;
 
-    return $this->all_vars =
+    return static::$_all_vars =
       [
        'avis' => $this->_getCommentVars(),
        'modo' => $this->_getModerationVars(),
@@ -537,15 +535,15 @@ class Class_AdminVarLoader extends Storm_Model_Loader {
 
 
   public function allVarsValues() {
-    if (null !== $this->_all_vars_values)
-      return $this->_all_vars_values;
+    if (null !== static::$_all_vars_values)
+      return static::$_all_vars_values;
 
     $values=[];
     foreach ($this->knownVars() as $key => $value) {
       $values = array_merge($values, $value);
     }
 
-    return $this->_all_vars_values = $values;
+    return static::$_all_vars_values = $values;
   }
 
 
@@ -584,8 +582,9 @@ class Class_AdminVarLoader extends Storm_Model_Loader {
 
   /** @category testing */
   public function resetAllVars() {
-    $this->all_vars = null;
-    $this->_all_vars_values = null;
+    static::$_all_vars = null;
+    static::$_all_vars_values = null;
+    return $this;
   }
 
 
diff --git a/library/Class/Calendar.php b/library/Class/Calendar.php
index cc66a1a5a4be1998fe1172b453be65d0016c6751..37e460e15fcc8003e26af24b453b873c43b16a86 100644
--- a/library/Class/Calendar.php
+++ b/library/Class/Calendar.php
@@ -243,6 +243,12 @@ class Class_Calendar {
   }
 
 
+  public function setSize($size) {
+    $this->preferences['size'] = $size;
+    return $this;
+  }
+
+
   public function getAdminSelectedCategories() {
     if (isset($this->admin_selected_categories))
       return $this->admin_selected_categories;
diff --git a/library/Class/Catalogue.php b/library/Class/Catalogue.php
index 172d2ffc843ba6c8eca3c077d1042a8590ef40cf..c7d95708e6e7323cc146e2f10884d8720d5c4292 100644
--- a/library/Class/Catalogue.php
+++ b/library/Class/Catalogue.php
@@ -345,10 +345,14 @@ class CatalogueLoader extends Storm_Model_Loader {
     if ($catalogue && $catalogue->isEmpty())
       return [];
 
-    if(isset($preferences['only_img']) && ($preferences['only_img'] == 1)
+    if(isset($preferences['only_img']) && ($preferences['only_img'] == Class_Catalogue::ONLY_IMG)
        && (($catalogue && Class_Catalogue::getLoader()->hasFilters($preferences['id_catalogue'])) || !$catalogue))
       $conditions[] = "url_vignette > '' and url_vignette != '" . Class_WebService_Vignette::NO_DATA . "' ";
 
+
+    if (isset($preferences['only_img']) && ($preferences['only_img'] == Class_Catalogue::WITHOUT_IMG))
+      $conditions[] = "url_vignette=''";
+
     $join = (isset($preferences['avec_avis']) && ($preferences['avec_avis'] == 1))
       ? ' INNER JOIN notices_avis ON notices.clef_oeuvre=notices_avis.clef_oeuvre '
       : '';
@@ -645,7 +649,10 @@ class CatalogueLoader extends Storm_Model_Loader {
 class Class_Catalogue extends Storm_Model_Abstract {
   use Trait_TreeNode, Trait_Translator, Trait_CustomFields, Trait_Facetable;
 
-  const CODE_FACETTE = 'Q';
+  const
+    CODE_FACETTE = 'Q',
+    ONLY_IMG = 1,
+    WITHOUT_IMG = 2;
 
   protected
     $_table_name = 'catalogue',
@@ -827,9 +834,8 @@ class Class_Catalogue extends Storm_Model_Abstract {
   }
 
 
-  public function getTestCatalogue() {
+  public function getTestCatalogue($nb_per_page = 20, $page = 1) {
     $preferences = $this->toArray();
-    $preferences['nb_notices'] = 20;
     $requetes = Class_Catalogue::getLoader()->getRequetes($preferences);
 
     if(empty($requetes['req_liste']))
@@ -839,9 +845,10 @@ class Class_Catalogue extends Storm_Model_Abstract {
     $temps = time();
 
     $ret["notices"] = Class_Notice::findAllByRequeteRecherche($requetes['req_ids'],
-                                                              $preferences['nb_notices'],
-                                                              1);
+                                                              $nb_per_page,
+                                                              $page);
     $ret["temps_execution"] = time() - $temps;
+
     $ret["nb_notices"] = fetchOne($requetes["req_comptage"]);
 
     $req = $requetes["req_comptage"];
diff --git a/library/Class/Codification.php b/library/Class/Codification.php
index 443f8817e404d330b9fcb655664c4db7936cb723..c8719d80dbf2109115c86eaec0e70f4a85c9ff0f 100644
--- a/library/Class/Codification.php
+++ b/library/Class/Codification.php
@@ -42,10 +42,10 @@
  * R: résumé
  * S: section
  * T: type de doc
- * U:
+ * U: vignette/image
  * V: disponibilité
  * W: éditeur
- * X:
+ * X: index dewey pcdm4
  * Y: annexe
  * Z: tag
  * 5: données autorités
@@ -68,7 +68,9 @@ class Class_Codification {
     CODE_AVAILABILITY='V',
     CODE_AUTHORITY_DATAS='5',
     CODE_URL = '8',
-    CODE_NOUVEAUTE = '9';
+    CODE_NOUVEAUTE = '9',
+    CODE_INDEX_DEWEY_PCDM4 = 'X',
+    CODE_THUMBNAIL = 'U';
 
 
   protected
@@ -92,7 +94,7 @@ class Class_Codification {
       return '';
 
     switch($type) {
-      case "X":
+      case Class_Codification::CODE_INDEX_DEWEY_PCDM4:
         $lib=[" ", $this->_('Livres et Vidéos'), $this->_('Musique')];
         $l=Class_AdminVar::get("FACETTE_PCDM4_LIBELLE"); if(trim($l)) $lib[2]=$l;
         $l=Class_AdminVar::get("FACETTE_DEWEY_LIBELLE"); if(trim($l)) $lib[1]=$l;
@@ -147,6 +149,7 @@ class Class_Codification {
        Class_Codification::CODE_NOUVEAUTE        => [    $this->_("Nouveauté"),       $this->_("Nouveauté")],
        Class_Codification::CODE_PRIX             => [    $this->_("Prix"),            $this->_("Prix")],
        Class_CodifEmplacement::CODE_FACETTE      => [    $this->_('Emplacement'),     $this->_('Emplacement')],
+       Class_Codification::CODE_THUMBNAIL        => [    $this->_('Vignette'),        $this->_('Vignette')],
        Class_Codification::CODE_AUTHORITY_DATAS  => [    $this->_('Autorité'),        $this->_('Autorité')],];
 
     $this->addThesauriToNomChamps();
diff --git a/library/Class/Journal/Type.php b/library/Class/Journal/Type.php
index 3507dbf567846cc7b138fac0741d97a22c34d3aa..deda6beb83783cef9b30e85b54c7505cd0af582a 100644
--- a/library/Class/Journal/Type.php
+++ b/library/Class/Journal/Type.php
@@ -30,10 +30,33 @@ class Class_Journal_Type {
     PREVIOUS_VALUE = 'previous_value',
     NEW_VALUE = 'new_value';
 
+  protected static $_enabled = true;
+
   protected $_journal;
 
 
+  /** @category testing */
+  public static function disable() {
+    static::$_enabled = false;
+  }
+
+
+  /** @category testing */
+  public static function enable() {
+    static::$_enabled = true;
+  }
+
+
+  /** @category testing */
+  protected static function _isEnabled() {
+    return static::$_enabled;
+  }
+
+
   public static function save($model) {
+    if (!static::_isEnabled())
+      return;
+
     $journal = Class_Journal::newInstance(['type' => static::MY_TYPE]);
     if (!$journal->save())
       return;
diff --git a/library/Class/Notice.php b/library/Class/Notice.php
index e2fcac6860ee2d679f82abf1f8ef6e760e52ee8b..eda5a79fcc45998f4d5821fd184bfd7cc9c54d3f 100644
--- a/library/Class/Notice.php
+++ b/library/Class/Notice.php
@@ -51,18 +51,21 @@ class NoticeLoader extends Storm_Model_Loader {
   }
 
 
-  public function getNoticeIdsByRequeteRecherche($req) {
+  public function getNoticeIdsByRequeteRecherche($req, $clear_cache = false) {
     if (!$req)
       return [];
 
-    $closure = function() use ($req) {
-      return Zend_Registry::get('sql')->fetchAllByColumn($req);
-    };
+    $cache = (new Storm_Cache())->useImplodeExplodeSerialization();
+    $cache_key = [$req, __CLASS__, __FUNCTION__];
 
-    return (new Storm_Cache())
-      ->useImplodeExplodeSerialization()
-      ->memoize([$req, __CLASS__, __FUNCTION__],
-                $closure);
+    if ($clear_cache)
+      $cache->remove($cache_key);
+
+    return $cache->memoize($cache_key,
+                           function() use ($req)
+                           {
+                             return Zend_Registry::get('sql')->fetchAllByColumn($req);
+                           });
   }
 
 
diff --git a/library/Class/Notice/Thumbnail/Cache.php b/library/Class/Notice/Thumbnail/Cache.php
new file mode 100644
index 0000000000000000000000000000000000000000..781b70463569a38cbf1457f248aa84f2e2e2286d
--- /dev/null
+++ b/library/Class/Notice/Thumbnail/Cache.php
@@ -0,0 +1,106 @@
+<?php
+/**
+ * Copyright (c) 2012-2020, Agence Française Informatique (AFI). All rights reserved.
+ *
+ * BOKEH is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by
+ * the Free Software Foundation.
+ *
+ * There are special exceptions to the terms and conditions of the AGPL as it
+ * is applied to this software (see README file).
+ *
+ * BOKEH 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 AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * along with BOKEH; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
+ */
+
+
+class Class_Notice_Thumbnail_Cache {
+  protected
+    $_remaining_records_count,
+    $_next_record;
+
+
+  public function build($request) {
+    $this->_next_record = null;
+    $this->_remaining_records_count = 0;
+
+    if ($request->getParam('reset_no'))
+      Class_WebService_Vignette::resetNoDataThumbnails();
+
+    return ($id_catalogue = $request->getParam('id_catalogue'))
+      ? $this->_updateNextRecordForCatalogue($request)
+      : $this->_updateNextRecordForAll();
+  }
+
+
+  public function getCallbackUrl($request) {
+    return array_filter( ['module' => 'admin',
+                          'controller' => 'systeme',
+                          'action' => 'makecacheimages',
+                          'id_catalogue' => $request->getParam('id_catalogue')] );
+  }
+
+
+  protected function _updateNextRecordForCatalogue($request) {
+    if (!$catalog = Class_Catalogue::find($request->getParam('id_catalogue')))
+      return $this;
+
+    $requetes = Class_Catalogue::getRequetes(['id_catalogue' => $catalog->getId(),
+                                              'only_img' => Class_Catalogue::WITHOUT_IMG]);
+
+    if (!$ids = Class_Notice::getNoticeIdsByRequeteRecherche($requetes['req_ids'], true))
+      return $this;
+
+    $this->_remaining_records_count = count($ids);
+
+    $this->_updateThumbnailForRecord(Class_Notice::find($ids[0]));
+
+    if ($this->_remaining_records_count > 0)
+      $this->_next_record = Class_Notice::find($ids[1]);
+
+    return $this;
+  }
+
+
+  protected function _updateNextRecordForAll() {
+    if (!$this->_remaining_records_count = Class_Notice::countBy(['url_vignette' => '']))
+      return $this;
+
+    $this->_updateThumbnailForRecord($this->_firstRecordWithoutThumbnail());
+    $this->_next_record = $this->_firstRecordWithoutThumbnail();
+    return $this;
+  }
+
+
+  protected function _updateThumbnailForRecord($record) {
+    $record->fetchUrlLocalVignette();
+    $this->_remaining_records_count --;
+    return $this;
+  }
+
+
+  public function getNextRecord() {
+    return $this->_next_record;
+  }
+
+
+  public function getRecordCount() {
+    return $this->_remaining_records_count;
+  }
+
+
+  public function isBuiltDone() {
+    return empty($this->_next_record);
+  }
+
+
+  protected function _firstRecordWithoutThumbnail() {
+    return Class_Notice::findFirstBy(['url_vignette' => '']);
+  }
+}
diff --git a/library/Class/Thumbs.php b/library/Class/Thumbs.php
deleted file mode 100644
index d3a57e0a440bf7200c2bd588d20bb29c32e01de4..0000000000000000000000000000000000000000
--- a/library/Class/Thumbs.php
+++ /dev/null
@@ -1,225 +0,0 @@
-<?php
-/**
- * Copyright (c) 2012, Agence Française Informatique (AFI). All rights reserved.
- *
- * BOKEH is free software; you can redistribute it and/or modify
- * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by
- * the Free Software Foundation.
- *
- * There are special exceptions to the terms and conditions of the AGPL as it
- * is applied to this software (see README file).
- *
- * BOKEH 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 AFFERO GENERAL PUBLIC LICENSE for more details.
- *
- * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
- * along with BOKEH; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA 
- */
-
-class Class_Thumbs
-{
-
-  var $config = array(
-    'album' => array(
-        "max_width" => 9999,
-        "max_height" => 9999,
-        "thumb_max_width" => 160,
-        "thumb_max_height" => 120
-    ) 
-  );
-
-  private $name;
-  private $path_to_save;
-  private $type;
-  private $working_img;
-
-  function __construct($path_to_img="",$type_img='avatar')
-  {
-    $this->type = $type_img;
-    $this->name = str_replace(dirname($path_to_img).'/','',$path_to_img);
-    $this->path_to_save = dirname($path_to_img).'/';
-    $this->working_img = $path_to_img;
-  }
-
-  //---------------------------------------------------------------------
-  // traite une image fabrique le thumb et retaille la grande image
-  //---------------------------------------------------------------------
-  public function traiteImage($adresse_fichier,$creer_thumb,$type)
-  {
-    // parametres du fichier
-    if(file_exists($adresse_fichier)==false) return array("erreur_image"=>"fichier image non trouvé");
-
-    // test si assez de memoire
-    $ret=$this->testConsoMemoire($adresse_fichier);
-
-    // Si pas assez de memoire : on degage
-    if($ret["statut"]==false)
-    {
-      return false;
-    }
-
-    // Grande image
-    $thumb = Thumbs_ThumbLib::create($adresse_fichier);
-    if($this->config[$type]["max_width"] != 9999)
-    {
-      $thumb->resize($this->config[$type]["max_width"], $this->config[$type]["max_height"]);
-      $thumb->save($adresse_fichier);
-    }
-
-    // thumb
-    if($creer_thumb==true)
-    {
-      $fic=pathinfo($adresse_fichier);
-      $path_thumbs=str_replace("/big","/thumbs",$fic["dirname"]);
-      if(file_exists($path_thumbs)==false) mkdir($path_thumbs);
-      $thumb->resize($this->config[$type]["thumb_max_width"], $this->config[$type]["thumb_max_height"]);
-      $thumb->save($path_thumbs.'/'.$fic["basename"]);
-    }
-
-    // retour
-    return $ret;
-  }
-  
-  //---------------------------------------------------------------------
-  // teste la capacité de la memoire pour traiter l'image
-  //---------------------------------------------------------------------
-  function testConsoMemoire($fic)
-{
-  // parametres
-  $facteur_pixels=204;
-  $marge_securite=100;
-  
-  // limite memoire 
-  $mem_limit=ini_get("memory_limit");
-  $mem_max=intval(str_replace("M","",$mem_limit))*1024;
-  $mem_used=intval(memory_get_usage()/1024);
-  $mem_dispo=($mem_max-$mem_used)-$marge_securite;
-  
-  // estimation memoire pour l'image
-  $info=getimagesize ($fic);
-  $pixels=$info[0]*$info[1];
-  $mem_image=intval($pixels/$facteur_pixels);
-  
-  // si pas assez de memoire calcul de la taille pour retrecir
-  if($mem_image<$mem_dispo) $ret["statut"]=true;
-  else 
-  {
-    $ret["statut"]=false;
-    $facteur=1.0;
-    $new_mem=$mem_image;
-    
-    While($new_mem > $mem_dispo)
-    {
-      $facteur-=0.01;
-      $new_witdh=intval($info[0]*$facteur);
-      $new_height=intval($info[1]*$facteur);
-      $new_mem=intval(($new_witdh*$new_height)/204);
-    }
-    $facteur=(1.0-$facteur)*100;
-    $new_dim=intval($new_witdh)." x ".$new_height;
-  }
-  
-  
-  // retour
-  $ret["fichier"]=$fic;
-  $ret["memoire_php_ini"]=$mem_limit."o";
-  $ret["memoire_utilisee"]=$mem_used.' Ko';
-  $ret["memoire_disponible"]=$mem_dispo.' Ko';
-  $ret["memoire_image"]=$mem_image.' Ko';
-  $ret["dimentions_origine"]=$info[0]." x ".$info[1]." pixels";
-  if($ret["statut"]==false)
-  {
-    $ret["dimentions_max"]=$new_dim." pixels";
-    $ret["diminution"]=$facteur."%";
-    $ret["msg"]="l'image est trop grande. Elle doit être réduite de ".$ret["diminution"].". ";
-    $ret["msg"].="Sa taille d'origine est de ".$ret["dimentions_origine"].". ";
-    $ret["msg"].="Sa nouvelle taille doit être au maximum de ".$ret["dimentions_max"];
-  }
-  return $ret;
-}
-
-  //---------------------------------------------------------------------
-  // proportions pour un container sans deformer l'image
-  //---------------------------------------------------------------------
-  static function getProportionsAffichage($hauteur_max,$largeur_max,$adresse_img,$ne_pas_forcer=false)
-  {
-    // dimentions initiales de l'image
-    $info=getimagesize($adresse_img);
-    $largeur=$info[0];
-    $hauteur=$info[1];
-    if(!$largeur or !$hauteur) return "";
-
-    // si option ne_pas_forcer et si l'image est plus petite on n'y touche pas
-    if($ne_pas_forcer and $largeur <= $largeur_max and $hauteur <= $hauteur_max) return;
-
-    // calcul du ratio
-    $ratio_hauteur = $hauteur_max/$hauteur;
-    $ratio_largeur = $largeur_max/$largeur;
-    $ratio = min($ratio_hauteur, $ratio_largeur);
-
-    // nouvelles dimentions
-    $largeur = intval($ratio*$largeur);
-    $hauteur = intval($ratio*$hauteur);
-
-    // retour sous la forme html
-    $html=' height="'.$hauteur.'px" width="'.$largeur.'px" ';
-    return $html;
-  }
-
-  //---------------------------------------------------------------------
-  // fabrique les thumbs pour tout un dossier
-  // attention : les images doivent etre de type .jpg
-  //---------------------------------------------------------------------
-  function saveDossier()
-  {
-    // verifie si le dossier existe et cree le dossier thumbs
-    if(file_exists($this->path_to_save)== false) return false;
-    $controle=file_exists($this->path_to_save.'thumbs');
-    if(file_exists($this->path_to_save.'thumbs')== false) mkdir($this->path_to_save.'thumbs');
-
-    // parcourir le dossier
-    $handle = opendir($this->path_to_save);
-    if(!$handle) return false;
-    while(false !== ($fic = readdir($handle)))
-    {
-      if(substr($fic,-4)!= ".jpg") continue;
-      $this->working_img=$this->path_to_save.$fic;
-      $this->name=$fic;
-      $this->saveImg();
-    }
-    closedir($handle);
-  }
-
-  function saveImg()
-  {
-    // Grande image
-    $thumb = Thumbs_ThumbLib::create($this->working_img);
-    $thumb->resize($this->config[$this->type]["max_width"], $this->config[$this->type]["max_height"]);
-    $thumb->save($this->path_to_save.$this->name);
-
-    // thumb
-    $thumb->resize($this->config[$this->type]["thumb_max_width"], $this->config[$this->type]["thumb_max_height"]);
-    $thumb->save($this->path_to_save.'thumbs/'.$this->name);
-  }
-
-  function createThumb()
-  {
-    $thumb = Thumbs_ThumbLib::create($this->working_img);
-    $thumb->resize($this->config[$this->type]["thumb_max_width"], $this->config[$this->type]["thumb_max_height"]);
-    $thumb->save(getcwd().$this->path_to_save.'thumbs/'.$this->name);
-  }
-
-  function renameImage($new_name)
-  {
-    $this->name=$new_name;
-  }
-
-  function changeSaveDir($path_to_save)
-  {
-    $this->path_to_save = $path_to_save;
-  }
-
-}
\ No newline at end of file
diff --git a/library/Class/UserGroup.php b/library/Class/UserGroup.php
index 5c2ede4bb4552dc79082c8244f644dd87918d580..82eba663a208cd513aa03bd153c5724be8ecc782 100644
--- a/library/Class/UserGroup.php
+++ b/library/Class/UserGroup.php
@@ -22,6 +22,17 @@
 class UserGroupLoader extends Storm_Model_Loader {
   use Trait_MemoryCleaner;
 
+  protected $_dynamics_of_user_cache = [];
+
+
+  public function save($model) {
+    $result = parent::save($model);
+    if ($model->isDynamic())
+      $this->_dynamics_of_user_cache = [];
+
+    return $result;
+  }
+
 
   public function getUsersIdsOf($group) {
     $ids = [];
@@ -99,6 +110,23 @@ class UserGroupLoader extends Storm_Model_Loader {
   public function findAllDynamics() {
     return Class_UserGroup::findAllBy(['group_type' => Class_UserGroup::TYPE_DYNAMIC]);
   }
+
+
+  public function findAllDynamicsOf($user) {
+    if ($user->isNew())
+      return $this->_realFindAllDynamicsOf($user);
+
+    $key = $user->getId();
+    return array_key_exists($key, $this->_dynamics_of_user_cache)
+      ? $this->_dynamics_of_user_cache[$key]
+      : ($this->_dynamics_of_user_cache[$key] = $this->_realFindAllDynamicsOf($user));
+  }
+
+
+  protected function _realFindAllDynamicsOf($user) {
+    return array_filter(Class_UserGroup::findAllDynamics(),
+                        function($group) use($user) { return $group->hasUser($user); });
+  }
 }
 
 
diff --git a/library/Class/Users.php b/library/Class/Users.php
index 705a8e3410c196f1d6f2226086797546d537a7ba..8f6a8558eb019059f35d12843e44484afbfe3c25 100644
--- a/library/Class/Users.php
+++ b/library/Class/Users.php
@@ -827,8 +827,7 @@ class Class_Users extends Storm_Model_Abstract {
 
 
   public function getDynamicUserGroups() {
-    return array_filter(Class_UserGroup::findAllDynamics(),
-                        function($group) { return $group->hasUser($this); });
+    return Class_UserGroup::findAllDynamicsOf($this);
   }
 
 
diff --git a/library/Class/WebService/Vignette.php b/library/Class/WebService/Vignette.php
index b29eedd2185db8ee7e46edf1b2cc533fdda871fb..a601d69bfb48694e5a6daa6579c2ff016ffadd54 100644
--- a/library/Class/WebService/Vignette.php
+++ b/library/Class/WebService/Vignette.php
@@ -30,6 +30,12 @@ class Class_WebService_Vignette extends Class_WebService_Abstract {
   }
 
 
+  public static function resetNoDataThumbnails() {
+    Zend_Registry::get('sql')
+      ->execute("update notices set url_vignette='',url_image='' where url_vignette='" . Class_WebService_Vignette::NO_DATA . "'");
+  }
+
+
   public function isThirdParty($record) {
     return $this->getThumbnailProviderFor($record)
                 ->isThirdParty();
diff --git a/library/Class/Xml.php b/library/Class/Xml.php
index 75f509220495a96d3b6209d5c41ffce8eb9167e1..1e1fb3f592666c39e596400e7a3dfcbfe0989a75 100644
--- a/library/Class/Xml.php
+++ b/library/Class/Xml.php
@@ -105,11 +105,13 @@ class Class_Xml {
 
 
   public function get_child_node($node, $tag) {
-    if($this->valeurs[$node]["type"]=="complete") return false;
+    if (isset($this->valeurs[$node]) && ($this->valeurs[$node]["type"]=="complete"))
+      return false;
+
     $tag=strToUpper($tag);
     for($i=$node; $i<32000; $i++)
     {
-      if(!$this->valeurs[$i]) return false;
+      if (!(isset($this->valeurs[$i]) && $this->valeurs[$i])) return false;
       if($this->valeurs[$i]["tag"]==$tag) return $i;
       if($this->fin_node($node, $i) == true) return false;
     }
@@ -117,7 +119,9 @@ class Class_Xml {
 
 
   public function get_value($node) {
-    return $this->valeurs[$node]["value"];
+    return isset($this->valeurs[$node])
+      ? $this->valeurs[$node]["value"]
+      : null;
   }
 
 
diff --git a/library/ZendAfi/View/Helper/Accueil/MenuVertical.php b/library/ZendAfi/View/Helper/Accueil/MenuVertical.php
index a3d2610a84294dacf462b55dc6b7f39b01895515..d5cfc075312dd8a256e1ba0b295eecc4cf00a222 100644
--- a/library/ZendAfi/View/Helper/Accueil/MenuVertical.php
+++ b/library/ZendAfi/View/Helper/Accueil/MenuVertical.php
@@ -356,7 +356,7 @@ class ZendAfi_View_Helper_Accueil_MenuVertical extends ZendAfi_View_Helper_Accue
 
     $content = $this->_getMenuEntry($url, $a_target, $menuitem, true);
 
-    if ($this->preferences['new_html']=='1')
+    if ( ($this->preferences['new_html']=='1') && (isset($menuitem['sous_menus'])))
       $content .= $this->_getSubItemsHtml($menuitem['sous_menus']);
 
     $profil_key = isset($menuitem["preferences"]["clef_profil"])
diff --git a/library/ZendAfi/View/Helper/Admin/GenerateImageCache.php b/library/ZendAfi/View/Helper/Admin/GenerateImageCache.php
new file mode 100644
index 0000000000000000000000000000000000000000..ad2c03e13ce50a6c29c7811580b189619eebdbd8
--- /dev/null
+++ b/library/ZendAfi/View/Helper/Admin/GenerateImageCache.php
@@ -0,0 +1,49 @@
+<?php
+/**
+ * Copyright (c) 2012-2020, Agence Française Informatique (AFI). All rights reserved.
+ *
+ * BOKEH is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by
+ * the Free Software Foundation.
+ *
+ * There are special exceptions to the terms and conditions of the AGPL as it
+ * is applied to this software (see README file).
+ *
+ * BOKEH 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 AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * along with BOKEH; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
+ */
+
+
+class ZendAfi_View_Helper_Admin_GenerateImageCache extends ZendAfi_View_Helper_BaseHelper {
+  public function Admin_GenerateImageCache($url = '') {
+    Class_ScriptLoader::getInstance()->addAdminScript('cacheimages');
+    $onclick = sprintf('makeCacheImages(%s); return false;',
+                       $url
+                       ? ('\'' . $url . '\'')
+                       : '');
+
+    return
+      $this->view->button(
+                          (new Class_Entity())->setText($this->_('Générer les vignettes'))
+                          ->setAttribs(['onclick' => $onclick])
+                          ->setImage($this->view->tagImg(Class_Admin_Skin::current()->getIconUrl('actions', 'down'),
+                                                         ['style' => 'filter: invert();'])))
+      .
+      $this->_tag('div',
+                  $this->_tag('h2',
+                              $this->_('Constitution du cache en cours...'))
+                  .
+                  $this->_tag('h3',
+                              $this->_('Notices à traiter: %s',
+                                       $this->_tag('span', '', ['id' => 'restantes']))),
+
+                  ['id' => 'bloc_restantes',
+                   'style' => 'text-align: center; display:none']);
+  }
+}
diff --git a/library/ZendAfi/View/Helper/AuthorAnchor.php b/library/ZendAfi/View/Helper/AuthorAnchor.php
index 434cf3c489a486e8a043517998bf75f1cd1f3970..c9dd8c97b64c06221f37597980ced504fc882cd1 100644
--- a/library/ZendAfi/View/Helper/AuthorAnchor.php
+++ b/library/ZendAfi/View/Helper/AuthorAnchor.php
@@ -21,7 +21,6 @@
 
 
 class ZendAfi_View_Helper_AuthorAnchor extends ZendAfi_View_Helper_BaseHelper {
-
   public function authorAnchor($author, $url_params = [], $anchor_params = []) {
     if(!$author)
       return '';
diff --git a/library/ZendAfi/View/Helper/ListeNotices/Mur.php b/library/ZendAfi/View/Helper/ListeNotices/Mur.php
index 7f449efbc625190a51d6bcc2e437c884f5c84b3a..f60d9d4d219410888ac980d6761ae07f7b51a3a7 100644
--- a/library/ZendAfi/View/Helper/ListeNotices/Mur.php
+++ b/library/ZendAfi/View/Helper/ListeNotices/Mur.php
@@ -46,7 +46,7 @@ class ZendAfi_View_Helper_ListeNotices_Mur extends ZendAfi_View_Helper_ListeNoti
                           ['class' => 'notice_titre'])];
 
     $datas[] = $this->_tag('span',
-                            $this->view->notice_LienRebondAuteur($notice),
+                            $this->view->authorAnchor($notice->getAuteurPrincipal()),
                             ['class' => 'notice_auteur']);
 
 
diff --git a/library/ZendAfi/View/Helper/ListeNotices/Tableau.php b/library/ZendAfi/View/Helper/ListeNotices/Tableau.php
index 652e435e8676a1326c71933a678fcbb4366801db..909f32529d51b06ba75ea960c68d8c38bb7aca95 100644
--- a/library/ZendAfi/View/Helper/ListeNotices/Tableau.php
+++ b/library/ZendAfi/View/Helper/ListeNotices/Tableau.php
@@ -20,9 +20,12 @@
  */
 
 class ZendAfi_View_Helper_ListeNotices_Tableau extends ZendAfi_View_Helper_ListeNotices_Abstract {
+  protected
+    $_preferences;
+
   public function listeNotices_Tableau($data, $preferences=[]) {
-    $preferences = $this->_updatePreferences($preferences);
-    $codes = $this->_filterCodes($preferences['liste_codes']);
+    $this->_preferences = $this->_updatePreferences($preferences);
+    $codes = $this->_filterCodes($this->_preferences['liste_codes']);
 
     return $this->_tag('table',
                        $this->_header($codes)
@@ -30,7 +33,8 @@ class ZendAfi_View_Helper_ListeNotices_Tableau extends ZendAfi_View_Helper_Liste
                        ['cellspacing' => '0',
                         'cellpadding' => '3',
                         'border' => '0',
-                        'width' => '100%']);
+                        'width' => '100%',
+                        'class' => 'liste_table']);
   }
 
 
@@ -41,13 +45,13 @@ class ZendAfi_View_Helper_ListeNotices_Tableau extends ZendAfi_View_Helper_Liste
 
 
   protected function _header($codes) {
-    $columns = ['<td class="listeTitre" width="26px">&nbsp;</td>'];
+    $columns = [];
     $codifications = Class_Codification::getInstance();
     foreach($codes as $code)
       $columns[] = $this->_tag('td', $codifications->getNomChamp($code),
                                ['class' => 'listeTitre']);
 
-    return $this->_tag('tr', implode($columns));
+    return $this->_tag('thead', $this->_tag('tr', implode($columns)));
   }
 
 
@@ -55,39 +59,42 @@ class ZendAfi_View_Helper_ListeNotices_Tableau extends ZendAfi_View_Helper_Liste
     $lig=0;
     $rows = [];
     foreach ($data as $notice) {
-      $style = 'liste' . ((0 === $lig % 2) ? 'Impaire' : 'Paire');
-      $rows[] = $this->_record($notice, $codes, $style);
+      $rows[] = $this->_record($notice, $codes);
       $lig++;
     }
 
-    return implode($rows);
+    return $this->_tag('tbody', implode($rows));
   }
 
 
-  protected function _record($notice, $codes, $style) {
-    $columns = [$this->_td($this->view->iconeSupport($notice->getTypeDoc()),
-                           $style,
-                           ['style' => 'text-align:center'])];
+  protected function _record($notice, $codes) {
+    $columns = [];
 
     foreach ($codes as $code)
-      $columns[] = $this->_field($code, $notice, $style);
+      $columns[] = $this->_field($code, $notice);
 
     return $this->_tag('tr', implode($columns));
   }
 
 
-  protected function _field($code, $notice, $style) {
-    if ('J' === $code)
+  protected function _field($code, $notice) {
+    $extra_url_params = (isset($this->_preferences['open_links_in_new_tab']) && ($this->_preferences['open_links_in_new_tab'] === '1'))
+      ? ['target' => '_blank']
+      : [];
+
+    if (Class_Codification::CODE_TITRE === $code)
       return $this->_td($this->_tag('a', $notice->getTitrePrincipal(),
-                                    ['href' => $this->view->urlNotice($notice)]),
-                         $style);
+                                    array_merge(['href' => $this->view->urlNotice($notice)],
+                                                $extra_url_params)));
+
+    if (Class_Codification::CODE_THUMBNAIL === $code)
+      return $this->_td($this->view->Notice_Vignette($notice));
 
-    if ('A' === $code)
-      return $this->_td($this->view->notice_LienRebondAuteur($notice),
-                        $style);
+    if (Class_CodifAuteur::CODE_FACETTE === $code)
+      return $this->_td($this->view->authorAnchor($notice->getAuteurPrincipal(), [], $extra_url_params));
 
     if (!$value = $notice->getChampNotice($code, $notice->getFacettes()))
-      return $this->_td('', $style);
+      return $this->_td('');
 
     if (is_array($value))
       $value = $value[0];
@@ -98,13 +105,16 @@ class ZendAfi_View_Helper_ListeNotices_Tableau extends ZendAfi_View_Helper_Liste
     if (is_object($value))
       $value = $value->renderOn($this->view);
 
-    return $this->_td($value, $style,
-                      ('N' === $code) ? ['style' =>  'text-align:center'] : []);
+    return $this->_td($value,
+                      (Class_Codification::CODE_ANNEE === $code)
+                      ? ['style' =>  'text-align:center']
+                      : []);
   }
 
 
-  protected function _td($content, $style, $attribs=[]) {
-    return $this->_tag('td', $content,
-                       array_merge(['class' => $style], $attribs));
+  protected function _td($content, $attribs=[]) {
+    return $this->_tag('td',
+                       $content,
+                       $attribs);
   }
 }
diff --git a/library/ZendAfi/View/Helper/Notice/LienRebondAuteur.php b/library/ZendAfi/View/Helper/Notice/LienRebondAuteur.php
deleted file mode 100644
index eea3329f53385e32a58c3c4be6a42d32a861d576..0000000000000000000000000000000000000000
--- a/library/ZendAfi/View/Helper/Notice/LienRebondAuteur.php
+++ /dev/null
@@ -1,38 +0,0 @@
-<?php
-/**
- * Copyright (c) 2012, Agence Française Informatique (AFI). All rights reserved.
- *
- * BOKEH is free software; you can redistribute it and/or modify
- * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by
- * the Free Software Foundation.
- *
- * There are special exceptions to the terms and conditions of the AGPL as it
- * is applied to this software (see README file).
- *
- * BOKEH 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 AFFERO GENERAL PUBLIC LICENSE for more details.
- *
- * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
- * along with BOKEH; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
- */
-
-
-class ZendAfi_View_Helper_Notice_LienRebondAuteur extends ZendAfi_View_Helper_BaseHelper {
-  public function notice_LienRebondAuteur($notice) {
-    if (!$author = $notice->getAuteurPrincipal())
-      return '';
-
-    return ($code = $notice->getCodeFacette(Class_CodifAuteur::CODE_FACETTE))
-      ? $this->view->tagAnchor(['module' => 'opac',
-                                'controller' => 'recherche',
-                                'action' => 'simple',
-                                'code_rebond' => $code,
-                                'page' => null],
-                               $author,
-                               ['title' => $this->_('Rechercher tous les documents ayant pour auteur: "%s"', $author)])
-      : $this->_tag('span', $notice->getAuteurPrincipal());
-  }
-}
\ No newline at end of file
diff --git a/library/ZendAfi/View/Helper/Pager.php b/library/ZendAfi/View/Helper/Pager.php
index 8a75ea1eb2714b363109964b6cdfd37d8061ed83..db5f384a4ae7e65adc6f182c90b4e34dc6dcc262 100644
--- a/library/ZendAfi/View/Helper/Pager.php
+++ b/library/ZendAfi/View/Helper/Pager.php
@@ -20,7 +20,7 @@
  */
 
 class ZendAfi_View_Helper_Pager extends ZendAfi_View_Helper_BaseHelper {
-  function Pager($nombre, $nb_par_page, $page,$url) {
+  function Pager($nombre, $nb_par_page, $page, $url) {
     if (!$nombre or !$nb_par_page)
       return '';
 
diff --git a/library/startup.php b/library/startup.php
index f245da0aa17375f493c6eef0208a8f5e35392b83..6742e37b037e102ea56e2ef320fdc5148fa3319e 100644
--- a/library/startup.php
+++ b/library/startup.php
@@ -81,7 +81,7 @@ class Bokeh_Engine {
 
   function setupConstants() {
     defineConstant('BOKEH_MAJOR_VERSION','8.0');
-    defineConstant('BOKEH_RELEASE_NUMBER', BOKEH_MAJOR_VERSION . '.40');
+    defineConstant('BOKEH_RELEASE_NUMBER', BOKEH_MAJOR_VERSION . '.41');
 
     defineConstant('BOKEH_REMOTE_FILES', 'https://git.afi-sa.net/afi/opacce/');
 
diff --git a/library/templates/Intonation/Assets/js/masonry.js b/library/templates/Intonation/Assets/js/masonry.js
index bdca467ceec7aa672e6f103ce56f9b40f6bd5faf..81884b49c33f5425eaebe1288c59e52a3a1a383f 100644
--- a/library/templates/Intonation/Assets/js/masonry.js
+++ b/library/templates/Intonation/Assets/js/masonry.js
@@ -1,37 +1,43 @@
 (function ( $ ) {
   $.fn.masonry = function () {
     var html = $(this);
+    var all_items = initAllItems();
 
-    var allItems = $(html).find('.masonry-brick');
-      for(var i=0; i < allItems.length; i++) {
-	imagesLoaded( allItems[i], function(instance) {
-	  var item = instance.elements[0];
-	  resizeMasonryItem(item);
-	} );
-      }
-
-    var masonryEvents = ['load', 'resize'];
-    masonryEvents.forEach( function(event) {
+    var masonry_events = ['load', 'resize'];
+    masonry_events.forEach( function(event) {
       window.addEventListener(event, resizeAllMasonryItems);
-    } );
-
+    });
 
-    function resizeMasonryItem(item){
-      var grid = html.get(0),
-	  rowGap = parseInt(window.getComputedStyle(grid).getPropertyValue('grid-row-gap')),
+    var resizeMasonryItem = function(item) {
+      var grid = html.find('.masonry')[0];
+      
+      var rowGap = parseInt(window.getComputedStyle(grid).getPropertyValue('grid-row-gap')),
 	  rowHeight = parseInt(window.getComputedStyle(grid).getPropertyValue('grid-auto-rows'));
 
-      var rowSpan = Math.ceil((item.querySelector('.masonry-content').getBoundingClientRect().height+rowGap)/(rowHeight+rowGap));
+      var rowSpan = Math.ceil((item.querySelector('.masonry-content').getBoundingClientRect().height + rowGap)/(rowHeight + rowGap));
 
-      item.style.gridRowEnd = 'span '+rowSpan;
+      item.style.gridRowEnd = 'span ' + rowSpan;
       item.style.visibility = 'visible';
     }
 
 
-    function resizeAllMasonryItems(){
-      for(var i=0;i>allItems.length;i++){
+    var resizeAllMasonryItems = function() {
+      if ( ! allItems.length)
+	allItems = initAllItems();
+      
+      for(var i=0; i > allItems.length; i++){
 	resizeMasonryItem(allItems[i]);
       }
     }
+
+
+    function initAllItems() {
+      var items = $(html).find('.masonry-brick').each(function() {
+	imagesLoaded( $(this), function(instance) {
+	  var item = instance.elements[0];
+	  resizeMasonryItem(item);
+	} );
+      });
+    }
   };
 } (jQuery));
diff --git a/library/templates/Intonation/Library/View/Wrapper/Hold.php b/library/templates/Intonation/Library/View/Wrapper/Hold.php
index 10ef4685fedca087a0f4e4d83823f23d480c0d47..05a0e4301f5ff02c6ef4f5b90b16ba5c63df2276 100644
--- a/library/templates/Intonation/Library/View/Wrapper/Hold.php
+++ b/library/templates/Intonation/Library/View/Wrapper/Hold.php
@@ -170,11 +170,22 @@ class Intonation_Library_View_Wrapper_Hold extends Intonation_Library_View_Wrapp
     if (!$this->_model->getNoticeOPAC())
       return null;
 
+    $badges = [
+               ((new Intonation_Library_Badge)
+                ->setTag('span')
+                ->setClass('secondary')
+                ->setImage(Class_Template::current()->getIco($this->_view,
+                                                             'library',
+                                                             'library'))
+                ->setText($this->_model->getBibliotheque())
+                ->setTitle($this->_('Bibliothèque de l\'emprunt: %s', $this->_model->getBibliotheque())))
+    ];
+
     $wrapper = (new Intonation_Library_View_Wrapper_Record)
       ->setView($this->_view)
       ->setModel($this->_model->getNoticeOPAC());
 
-    return $wrapper->getBadges();
+    return $this->_view->renderBadges($badges) . $wrapper->getBadges();
   }
 
 
diff --git a/library/templates/Intonation/Library/View/Wrapper/Loan.php b/library/templates/Intonation/Library/View/Wrapper/Loan.php
index 29285f18b861648ebde50c9fcad9b7c89c31308c..613240c5af774e5d7f4d0579f023c37c02efcf33 100644
--- a/library/templates/Intonation/Library/View/Wrapper/Loan.php
+++ b/library/templates/Intonation/Library/View/Wrapper/Loan.php
@@ -134,6 +134,15 @@ class Intonation_Library_View_Wrapper_Loan extends Intonation_Library_View_Wrapp
                 ->setText($return_date)
                 ->setTitle($this->_('Date de retour : %s', $return_date))),
 
+               ((new Intonation_Library_Badge)
+                ->setTag('span')
+                ->setClass('secondary')
+                ->setImage(Class_Template::current()->getIco($this->_view,
+                                                             'library',
+                                                             'library'))
+                ->setText($this->_model->getBibliotheque())
+                ->setTitle($this->_('Bibliothèque de l\'emprunt: %s', $this->_model->getBibliotheque()))),
+
                ((new Intonation_Library_Badge)
                 ->setTag('span')
                 ->setClass('info')
diff --git a/library/templates/Intonation/Library/View/Wrapper/Record.php b/library/templates/Intonation/Library/View/Wrapper/Record.php
index 107bdf2ffd285327d50ad44c09532170ad238c9a..ca2be7e213ff112b317c38c724e19ea182a43352 100644
--- a/library/templates/Intonation/Library/View/Wrapper/Record.php
+++ b/library/templates/Intonation/Library/View/Wrapper/Record.php
@@ -259,10 +259,18 @@ class Intonation_Library_View_Wrapper_Record extends Intonation_Library_View_Wra
     if (!$matches = array_filter($matches))
       return $badges;
 
+    $labels = [];
     foreach ($matches as $match) {
       if (!$match)
         continue;
 
+      $label = $match->getLibrary()->getLabel();
+
+      if (in_array($label, $labels))
+        continue;
+
+      $labels [] = $label;
+
       $badges [] = ((new Intonation_Library_Badge)
                     ->setTag('a')
                     ->setUrl($this->_view->url(['controller' => 'recherche',
@@ -273,8 +281,8 @@ class Intonation_Library_View_Wrapper_Record extends Intonation_Library_View_Wra
                     ->setImage(Class_Template::current()->getIco($this->_view,
                                                                  'library',
                                                                  'library'))
-                    ->setText($match->getLibrary()->getLabel())
-                    ->setTitle($this->_('Affiner le résultat avec le site %s', $match->getLibrary()->getLabel())));
+                    ->setText($label)
+                    ->setTitle($this->_('Affiner le résultat avec le site %s', $label)));
     }
 
     return $badges;
diff --git a/library/templates/Intonation/Library/Widget/Carousel/Agenda/View.php b/library/templates/Intonation/Library/Widget/Carousel/Agenda/View.php
index 5cf50c5be06c5b9ce8c75d5c3fde227c849162e2..679abd71f77d1b12bc26de0189ed7e26e175e1a1 100644
--- a/library/templates/Intonation/Library/Widget/Carousel/Agenda/View.php
+++ b/library/templates/Intonation/Library/Widget/Carousel/Agenda/View.php
@@ -49,11 +49,6 @@ class Intonation_Library_Widget_Carousel_Agenda_View extends Intonation_Library_
   }
 
 
-  protected function _getLinkToAllParams() {
-    return [];
-  }
-
-
   protected function _getLinkToAllTitle() {
     return $this->_('Voir tous les événements de la boite %s dans une liste', $this->titre);
   }
@@ -86,8 +81,8 @@ class Intonation_Library_Widget_Carousel_Agenda_View extends Intonation_Library_
 
   public function getLinkToAllContent() {
     $this->view->titre = $this->_settings->getTitre();
-
     $this->_initCalendar();
+    $this->_calendar->setSize(100);
     return $this->view->calendarLinkToAll($this->_calendar, $this->_settings);
   }
 
diff --git a/library/templates/Intonation/Library/Widget/Carousel/Article/View.php b/library/templates/Intonation/Library/Widget/Carousel/Article/View.php
index e25104e4a840af2f722af88c8f85cdfbb84fa771..1937379e3857ef075e08e2515f159ffb0eb156a5 100644
--- a/library/templates/Intonation/Library/Widget/Carousel/Article/View.php
+++ b/library/templates/Intonation/Library/Widget/Carousel/Article/View.php
@@ -22,13 +22,10 @@
 
 class Intonation_Library_Widget_Carousel_Article_View extends Intonation_Library_Widget_Carousel_View {
 
-  protected $_all_articles = [];
-
-
   protected function _findElements() {
     $loader = Class_Article::getLoader();
+    $this->preferences['size'] = 100;
     $articles_to_show = $loader->getArticlesByPreferences($this->preferences);
-    $this->_all_articles = $loader->getAllArticles();
     return $articles_to_show;
   }
 
@@ -38,21 +35,6 @@ class Intonation_Library_Widget_Carousel_Article_View extends Intonation_Library
   }
 
 
-  protected function _getLinkToAllParams() {
-    $articles_ids = implode('-',
-                            array_map(function($article)
-                                      {
-                                        return $article->getId();
-                                      }, $this->_all_articles));
-
-    return ['module' => 'opac',
-            'controller' => 'cms',
-            'action' => 'list',
-            'title' => $this->view->escape($this->titre),
-            'articles' => $articles_ids];
-  }
-
-
   protected function _getLinkToAllTitle() {
     return $this->_('Voir tous les articles de la boite "%s" dans une liste', $this->titre);
   }
diff --git a/library/templates/Intonation/Library/Widget/Carousel/Author/View.php b/library/templates/Intonation/Library/Widget/Carousel/Author/View.php
index 13c17fa955c648286bfaaba9465eb824568e213b..06a09e6d3ba3f3385b9336b4996aa0d3738e0446 100644
--- a/library/templates/Intonation/Library/Widget/Carousel/Author/View.php
+++ b/library/templates/Intonation/Library/Widget/Carousel/Author/View.php
@@ -33,11 +33,6 @@ class Intonation_Library_Widget_Carousel_Author_View extends Intonation_Library_
   }
 
 
-  protected function _getLinkToAllParams() {
-    return '';
-  }
-
-
   protected function _getLinkToAllTitle() {
     return $this->_('Voir tous les auteurs de la boite %s dans une liste', $this->titre);
   }
diff --git a/library/templates/Intonation/Library/Widget/Carousel/Domain/View.php b/library/templates/Intonation/Library/Widget/Carousel/Domain/View.php
index ef9f3b658a8a0242b2a5b3dbe031ce5d2a3b0b2b..ee13e79744f591ad05dfd61ebe674133c7e1d787 100644
--- a/library/templates/Intonation/Library/Widget/Carousel/Domain/View.php
+++ b/library/templates/Intonation/Library/Widget/Carousel/Domain/View.php
@@ -40,11 +40,6 @@ class Intonation_Library_Widget_Carousel_Domain_View extends Intonation_Library_
   }
 
 
-  protected function _getLinkToAllParams() {
-    return [];
-  }
-
-
   protected function _getLinkToAllTitle() {
     return $this->_('Voir tous les domaines de la boite %s dans une liste', $this->titre);
   }
diff --git a/library/templates/Intonation/Library/Widget/Carousel/Library/View.php b/library/templates/Intonation/Library/Widget/Carousel/Library/View.php
index f753cdf686e0021676aeabc7f9789fb256ee8912..d9452cd26024fe710dfc674214e34c7c435d0db3 100644
--- a/library/templates/Intonation/Library/Widget/Carousel/Library/View.php
+++ b/library/templates/Intonation/Library/Widget/Carousel/Library/View.php
@@ -46,11 +46,6 @@ class Intonation_Library_Widget_Carousel_Library_View extends Intonation_Library
   }
 
 
-  protected function _getLinkToAllParams() {
-    return '';
-  }
-
-
   protected function _getLinkToAllTitle() {
     return $this->_('Voir toutes les bibliothèques de la boite %s dans une liste', $this->titre);
   }
diff --git a/library/templates/Intonation/Library/Widget/Carousel/Newsletter/View.php b/library/templates/Intonation/Library/Widget/Carousel/Newsletter/View.php
index 3edfd97f1f7b81345a0c17c16ff89770035715ff..4b5b2b065fac9640f2ab13aec83778e995efba08 100644
--- a/library/templates/Intonation/Library/Widget/Carousel/Newsletter/View.php
+++ b/library/templates/Intonation/Library/Widget/Carousel/Newsletter/View.php
@@ -34,11 +34,6 @@ class Intonation_Library_Widget_Carousel_Newsletter_View extends Intonation_Libr
   }
 
 
-  protected function _getLinkToAllParams() {
-    return '';
-  }
-
-
   protected function _getLinkToAllTitle() {
     return $this->_('Voir toutes les lettres d\'informations de la boite %s dans une liste', $this->titre);
   }
diff --git a/library/templates/Intonation/Library/Widget/Carousel/ReviewsByRecord/View.php b/library/templates/Intonation/Library/Widget/Carousel/ReviewsByRecord/View.php
index 066d08b5a444a6b3747b0b8f6dda2597b4c1e35a..6ac258e1afd981ace243f181c9f2aecf75ed670f 100644
--- a/library/templates/Intonation/Library/Widget/Carousel/ReviewsByRecord/View.php
+++ b/library/templates/Intonation/Library/Widget/Carousel/ReviewsByRecord/View.php
@@ -41,23 +41,6 @@ class Intonation_Library_Widget_Carousel_ReviewsByRecord_View extends Intonation
   }
 
 
-  protected function _getLinkToAllParams() {
-    $reviews_ids = [];
-
-    foreach ($this->_all_reviews as $review)
-      $reviews_ids [] = $review->getId();
-
-    $reviews_ids = implode('-', $reviews_ids);
-
-    return ['module' => 'opac',
-            'controller' => 'blog',
-            'action' => 'list',
-            'title' => $this->view->escape($this->titre),
-            'records_reviews_ids' => $reviews_ids,
-            'order' => $this->_settings->getOrder()];
-  }
-
-
   protected function _getLinkToAllTitle() {
     return $this->_('Voir tous les avis de la boite "%s" dans une liste', $this->titre);
   }
diff --git a/library/templates/Intonation/Library/Widget/Carousel/View.php b/library/templates/Intonation/Library/Widget/Carousel/View.php
index 106ded36de674f0d0b27472d7b215d35f62955c7..d91928692792f9fa9d919b4fc071db6c6d49d2e8 100644
--- a/library/templates/Intonation/Library/Widget/Carousel/View.php
+++ b/library/templates/Intonation/Library/Widget/Carousel/View.php
@@ -22,6 +22,9 @@
 
 abstract class Intonation_Library_Widget_Carousel_View extends Zendafi_View_Helper_Accueil_Base {
 
+  protected $_register_for_head_scripts = [];
+
+
   public function getHtml() {
     $this->titre = $this->_settings->getTitre();
     $this->contenu = $this->_getHTML();
@@ -30,6 +33,14 @@ abstract class Intonation_Library_Widget_Carousel_View extends Zendafi_View_Help
   }
 
 
+  protected function _renderHeadScriptsOn($script_loader) {
+    foreach($this->_register_for_head_scripts as $registered)
+      $registered->renderHeadScriptsOn($script_loader);
+
+    return parent::_renderHeadScriptsOn($script_loader);
+  }
+
+
   public function getFooter() {
     $rss = $this->_settings->getRss()
       ? $this->_getTagRss()
@@ -138,8 +149,11 @@ abstract class Intonation_Library_Widget_Carousel_View extends Zendafi_View_Help
   protected function _renderLayout($layout, $elements, $content_callback) {
     $elements = new Storm_Collection($elements);
 
-    if (Intonation_Library_Widget_Carousel_Definition::WALL == $layout)
-      return $this->view->renderWall($elements, $content_callback);
+    if (Intonation_Library_Widget_Carousel_Definition::WALL == $layout) {
+      $renderer = (new Intonation_View_RenderWall)->setView($this->view);
+      $this->_register_for_head_scripts [] = $renderer;
+      return $renderer->renderWall($elements, $content_callback);
+    }
 
     if (Intonation_Library_Widget_Carousel_Definition::CAROUSEL == $layout)
       return $this->view->renderCarousel($elements, $content_callback);
diff --git a/library/templates/Intonation/View/RenderRecord/RenderItems.php b/library/templates/Intonation/View/RenderRecord/RenderItems.php
index deaf3d8b45af4f071e495d3d7762ac1643d02a9d..6e283015d07cbb4388d729e6f4259c854d96a02d 100644
--- a/library/templates/Intonation/View/RenderRecord/RenderItems.php
+++ b/library/templates/Intonation/View/RenderRecord/RenderItems.php
@@ -37,14 +37,14 @@ class Intonation_View_RenderRecord_RenderItems extends ZendAfi_View_Helper_BaseH
 
     $html = [];
     if ($map = $this->view->osmMap($elements))
-      $html [] = $this->view->div(['class' => 'col-12 mb-3'],
+      $html [] = $this->view->div(['class' => 'col-12 mb-3 items_map'],
                                   $map);
 
-    $html [] = $this->view->div(['class' => 'col-12'],
+    $html [] = $this->view->div(['class' => 'col-12 items_wall'],
                                 $this->_getHtmlItems($items));
 
     if ($same_work) {
-      $html [] = $this->view->div(['class' => 'col-12'],
+      $html [] = $this->view->div(['class' => 'col-12 same_work_items'],
                                   $this->view->tag('h3', $this->_('Exemplaires de la même œuvre')));
       $html [] = $this->view->div(['class' => 'col-12'],
                                   $this->_getHtmlItems($same_work));
diff --git a/library/templates/Intonation/View/RenderWall.php b/library/templates/Intonation/View/RenderWall.php
index d5dcdfabfa8dd2731b8646bef0df118d7d96c2f4..bad8b1d23ee348177963b56758e4cac280285f64 100644
--- a/library/templates/Intonation/View/RenderWall.php
+++ b/library/templates/Intonation/View/RenderWall.php
@@ -21,13 +21,14 @@
 
 
 class Intonation_View_RenderWall extends ZendAfi_View_Helper_BaseHelper {
+
+  protected $_masonry_id;
+
+
   public function renderWall($collection, $callback) {
-    $id = uniqid();
+    $this->_masonry_id = uniqid();
 
-    Class_ScriptLoader::getInstance()
-      ->addScripts([Class_Url::absolute('/library/templates/Intonation/Assets/js/masonry.js')])
-      ->addScripts([Class_Url::absolute('/library/templates/Intonation/Assets/js/imagesloaded4.1.4.min.js')])
-      ->addJQueryReady(sprintf('$("#%s").masonry();', $id));
+    $this->renderHeadScriptsOn(Class_ScriptLoader::getInstance());
 
     $html = array_filter($collection
                          ->injectInto([], function($html, $element) use ($callback)
@@ -38,10 +39,19 @@ class Intonation_View_RenderWall extends ZendAfi_View_Helper_BaseHelper {
                                         return $html;
                                       }));
 
-
     return $this->_tag('div',
                        implode($html),
                        ['class' => 'masonry',
-                        'id' => $id]);
+                        'id' => $this->_masonry_id]);
+  }
+
+
+  public function renderHeadScriptsOn($script_loader) {
+    $script_loader
+      ->addScripts([Class_Url::absolute('/library/templates/Intonation/Assets/js/masonry.js')])
+      ->addScripts([Class_Url::absolute('/library/templates/Intonation/Assets/js/imagesloaded4.1.4.min.js')])
+      ->addJQueryReady(sprintf('$("#%s").parent().masonry();', $this->_masonry_id));
+
+    return $this;
   }
 }
\ No newline at end of file
diff --git a/library/templates/Intonation/View/User/Informations.php b/library/templates/Intonation/View/User/Informations.php
index 552902a36d8b3904406ad2a35cdf63f78d58a729..a06c2a1ec0e7f184bfb4ad0697c9325e23537d04 100644
--- a/library/templates/Intonation/View/User/Informations.php
+++ b/library/templates/Intonation/View/User/Informations.php
@@ -34,7 +34,7 @@ class Intonation_View_User_Informations extends ZendAfi_View_Helper_BaseHelper {
             $this->_('Date de naissance') => (new DateTime($user->getNaissance()))->format($this->_('d / m / Y')),
 
             $this->_('Numéro de carte') => $user->getIdabon(),
-            $this->_('Bibilothèque') => $this->_getLibrary($user),
+            $this->_('Bibliothèque') => $this->_getLibrary($user),
 
             $this->_('Courriel') => $user->getMail(),
             $this->_('Numéro de téléphone') => $user->getTelephone(),
diff --git a/public/opac/js/renderFilters/ajaxifyFilters.js b/public/opac/js/renderFilters/ajaxifyFilters.js
index 3c597d595fd791e282c861fac59b6ceb43d5835e..7b121b9e777903396d7a95f2256019329fdf7e90 100644
--- a/public/opac/js/renderFilters/ajaxifyFilters.js
+++ b/public/opac/js/renderFilters/ajaxifyFilters.js
@@ -47,6 +47,9 @@
       if ('onLoadComplete' in options)
         options.onLoadComplete(widget);
 
+      if (undefined != $.fn.masonry)
+	widget.masonry();
+      
       initializePopups();
       setupAnchorsTarget();
       widget.ajaxifyFilters(options);
diff --git a/tests/application/modules/AbstractControllerTestCase.php b/tests/application/modules/AbstractControllerTestCase.php
index a030c14e620062d712a7b27199b15d7cb535ff9f..de0ea17907acd01e82ff8342e3714425a0ce4cbd 100644
--- a/tests/application/modules/AbstractControllerTestCase.php
+++ b/tests/application/modules/AbstractControllerTestCase.php
@@ -126,6 +126,7 @@ abstract class AbstractControllerTestCase extends Zend_Test_PHPUnit_ControllerTe
     $session = new Zend_Session_Namespace('FlashMessenger');
     $session->unsetAll();
 
+    Class_Journal_Type::disable(); // perf: do not track adminvars by default
     Class_AdminVar::beVolatile();
     Class_TextReplacements::reset();
     Class_AdminVar::set('CACHE_ACTIF', 0);
diff --git a/tests/application/modules/admin/controllers/CatalogueControllerTest.php b/tests/application/modules/admin/controllers/CatalogueControllerTest.php
index 00fe75688314cc555033a89b1cf9a52f0586f9f3..bc5dfac26b7cf66108c11b44ba1b51976e07e92b 100644
--- a/tests/application/modules/admin/controllers/CatalogueControllerTest.php
+++ b/tests/application/modules/admin/controllers/CatalogueControllerTest.php
@@ -1829,4 +1829,219 @@ class Admin_CatalogueControllerActionDomainesTestCase extends AbstractController
     $this->dispatch('/admin/catalogue/domaines', true);
     $this->assertNotRedirect();
   }
+}
+
+
+
+
+abstract class CatalogueControllerActionTesterWithResultsTestCase extends Admin_AbstractControllerTestCase {
+  protected
+    $_storm_default_to_volatile = true,
+    $_mock_sql;
+
+  public function setUp() {
+    parent::setUp();
+    Class_AdminVar::set('FEATURES_TRACKING_ENABLE', 0);
+
+    $this->fixture('Class_Matiere',
+                   ['id' => 78308]);
+
+    $this->fixture('Class_Catalogue',
+                   ['id' => 6,
+                    'libelle' => 'nouveautés',
+                    'type_doc' => '1;3',
+                    'annee_debut' => 2012,
+                    'annee_fin' => 2012,
+                    'annexe' => 0,
+                    'dewey' => 78308,
+                    'bibliotheque' => 1,
+                    'indexer' =>false]);
+
+    Zend_Registry::set('sql',
+                       $this->_mock_sql = $this->mock()->beStrict());
+  }
+}
+
+
+
+
+class CatalogueControllerActionTesterWithResultsPageTwoTest extends CatalogueControllerActionTesterWithResultsTestCase {
+  protected $_storm_default_to_volatile = true;
+
+  public function setUp() {
+    parent::setUp();
+
+    Storm_Cache::beVolatile();
+
+    $clauses = 'from notices Where (MATCH(facettes) AGAINST(\' +(B1) +( D78308*)\' IN BOOLEAN MODE) and notices.type_doc IN (\'1\', \'3\') and annee >= \'2012\' and annee <= \'2012\') and type=1';
+
+    $this->_mock_sql
+      ->whenCalled('fetchAllByColumn')
+      ->with('select notices.id_notice ' . $clauses . ' order by alpha_titre  LIMIT 5000')
+      ->answers(range(1, 22))
+
+      ->whenCalled('fetchOne')
+      ->with('select count(*) ' . $clauses . '')
+      ->answers(22)
+
+      ->whenCalled('fetchOne')
+      ->with('select count(*) ' . $clauses . ' and url_vignette > \'\' and url_vignette != \'NO\' ')
+      ->answers(10);
+
+    $this->fixture('Class_Notice',
+                   ['id' => 21,
+                    'titre_principal' => 'tales',
+                    'auteur_principal' => 'marcus',
+                    'url_vignette' => 'http://image.org/marcus.jpg']);
+
+    $this->fixture('Class_Notice',
+                   ['id' => 22,
+                    'titre_principal' => 'tutu',
+                    'auteur_principal' => 'miles',
+                    'url_vignette' => 'http://image.org/miles.jpg']);
+
+
+    $this->dispatch('admin/catalogue/tester/id_catalogue/6/page/2', true);
+  }
+
+
+  /** @test */
+  public function pageShouldContainsButtonGenerateThumbnails() {
+    $this->assertXPathContentContains('//button[@onclick="makeCacheImages(\'/admin/systeme/makecacheimages/id_catalogue/6/reset_no/1\'); return false;"]',
+                                      'Générer les vignettes');
+  }
+
+
+  /** @test */
+  public function tableShouldHaveTwoRows() {
+    $this->assertXPathCount('//table[@class="liste_table"]//tbody/tr', 2, $this->_response->getBody());
+  }
+
+
+  /** @test */
+  public function rowShouldContainsLinkWithThumbnailForMiles() {
+    $this->assertXPath('//td/a[contains(@href, "/viewnotice/id_catalogue/6")]/img[@src="http://image.org/miles.jpg"]');
+  }
+
+
+  /** @test */
+  public function rowShouldContainsLinkToTutuRecordInNewWindow() {
+    $this->assertXPathContentContains('//td/a[contains(@href, "/viewnotice/id_catalogue/6")][@target="_blank"]', 'tutu');
+  }
+
+
+  /** @test */
+  public function pageShouldContainsLinkToViewDomainInSearchResults() {
+    $this->assertXPath('//div[@class="header_actions"]/a[contains(@href, "/recherche/simple/id_catalogue/6")][@target="_blank"]');
+  }
+
+
+  /** @test */
+  public function pagerCurrentLinkShouldBePageTwo() {
+    $this->assertXPath('//div[@class="pager"]/span[@class="current"]/a[@href="#2"]');
+  }
+
+
+  /** @test */
+  public function scriptsShouldLoadCacheImagesJs() {
+    $this->assertXPath('//script[contains(@src, "public/admin/js/cacheimages.js")]');
+  }
+
+
+  /** @test */
+  public function pageShouldContainsSpanIdRestantesForCacheImagesScript() {
+    $this->assertXPath('//h3/span[@id="restantes"]');
+  }
+}
+
+
+
+
+class CatalogueControllerSystemeControllerMakeCacheActionTesterWithResultsTest extends CatalogueControllerActionTesterWithResultsTestCase {
+  protected
+    $_sql_query;
+
+  public function setUp() {
+    parent::setUp();
+
+    Storm_Cache::beVolatile();
+
+    $this->fixture('Class_Notice',
+                   ['id' => 21,
+                    'titre_principal' => 'tales',
+                    'auteur_principal' => 'marcus',
+                    'url_vignette' => '']);
+
+    $this->fixture('Class_Notice',
+                   ['id' => 22,
+                    'titre_principal' => 'tutu',
+                    'auteur_principal' => 'miles',
+                    'url_vignette' => '']);
+
+
+
+    $this->_sql_query = 'select notices.id_notice from notices Where (MATCH(facettes) AGAINST(\' +(B1) +( D78308*)\' IN BOOLEAN MODE) and notices.type_doc IN (\'1\', \'3\') and annee >= \'2012\' and annee <= \'2012\' and url_vignette=\'\') and type=1 order by alpha_titre  LIMIT 5000';
+
+    $this->_mock_sql
+      ->whenCalled('fetchAllByColumn')
+      ->with($this->_sql_query)
+      ->answers([21, 22])
+
+      ->whenCalled('execute')
+      ->with("update notices set url_vignette='',url_image='' where url_vignette='NO'")
+      ->answers(true)
+      ->beStrict();
+
+    $this->dispatch('/admin/systeme/makecacheimages/id_catalogue/6/reset_no/true', true);
+  }
+
+
+  /** @test */
+  public function responseShouldContainsRecordTutu() {
+     $this
+      ->assertEquals('1'.
+                     '<div>' .
+                       '<a href="/recherche/viewnotice/id/22" target="_blank">' .
+                         'tutu (miles)' .
+                       '</a>' .
+                     '</div>' .
+                     '<script>makeCacheImages(\'/admin/systeme/makecacheimages/id_catalogue/6\')</script>',
+                     $this->_response->getBody());
+  }
+
+
+
+  /** @test */
+  public function thumbnailsShouldBeClearedOnceWithExecuteQueryOnNoticesTable() {
+    $this->assertEquals(1, $this->_mock_sql->methodCallCount('execute'));
+  }
+
+
+
+  /** @test */
+  public function onSecondCallResponseShouldContainsNoRecord() {
+    $this->_mock_sql
+      ->whenCalled('fetchAllByColumn')
+      ->with($this->_sql_query)
+      ->answers([22]);
+
+    $this->_request = null;
+    $this->_response->setBody('');
+    $this->dispatch('/admin/systeme/makecacheimages/id_catalogue/6', true);
+    $this
+      ->assertEquals('0',
+                     $this->_response->getBody());
+
+    return ($this->_mock_sql);
+  }
+
+
+  /**
+   * @depends onSecondCallResponseShouldContainsNoRecord
+   * @test
+   */
+  public function thumbnailsShouldNotBeClearedOnSecondCall($mock_sql) {
+    $this->assertEquals(1, $mock_sql->methodCallCount('execute'));
+  }
+
 }
\ No newline at end of file
diff --git a/tests/application/modules/admin/controllers/SystemeControllerTest.php b/tests/application/modules/admin/controllers/SystemeControllerTest.php
index fa61cd404de9cc5e8889fc75bbd5551782ae54d3..b75b54a12d2eed2bbf8f6b3a85a9bfd7b19e3311 100644
--- a/tests/application/modules/admin/controllers/SystemeControllerTest.php
+++ b/tests/application/modules/admin/controllers/SystemeControllerTest.php
@@ -222,7 +222,7 @@ class SystemeControllerImageCacheTest extends Admin_AbstractControllerTestCase {
                          'Cortomaltese (Hugo Pratt)' .
                        '</a>' .
                      '</div>' .
-                     '<script>makeCacheImages("/admin/systeme/makecacheimages")</script>',
+                     '<script>makeCacheImages(\'/admin/systeme/makecacheimages\')</script>',
                      $this->_response->getBody());
   }
 }
diff --git a/tests/application/modules/opac/controllers/AbonneControllerFicheTest.php b/tests/application/modules/opac/controllers/AbonneControllerFicheTest.php
index 2614eb80d4592e942a57ce76578493d15e3efce8..ae2c3447670fb5387b966304b5a12d853bef07ab 100644
--- a/tests/application/modules/opac/controllers/AbonneControllerFicheTest.php
+++ b/tests/application/modules/opac/controllers/AbonneControllerFicheTest.php
@@ -28,6 +28,8 @@ abstract class AbstractAbonneControllerFicheTest extends AbstractControllerTestC
     $this->fixture('Class_Bib', ['id' => 1]);
     $this->fixture('Class_Bib', ['id' => 2]);
 
+    $this->onLoaderOfModel('Class_UserGroup');
+
     $this->marcus = $this->fixture('Class_Users',
                                    ['id' => 10,
                                     'login' => 'MC',
@@ -121,11 +123,18 @@ class AbonneControllerFicheAsAbonneTest extends AbstractAbonneControllerFicheTes
     $this->assertXPathContentContains('//div[@class="abonneTitre"]//span[@data-name="last-name"]', 'Miller');
   }
 
+
   /** @test */
   public function LoansHistoryShouldNotBeDisplayed() {
     $this->assertNotXPathContentContains('//a', 'Voir mon historique de prêts');
   }
 
+
+  // @see http://forge.afi-sa.fr/issues/105091
+  /** @test */
+  public function callToFindAllDynamicsShouldBeDoneOnlyOnce() {
+    $this->assertEquals(1, Class_UserGroup::methodCallCount('findAllDynamics'));
+  }
 }
 
 
diff --git a/tests/application/modules/opac/controllers/FormulaireControllerTest.php b/tests/application/modules/opac/controllers/FormulaireControllerTest.php
index 9435783773967cd285fbf9908022663e64a172bc..7eea1070debcc8d329c6c82758edb413a4ce06d0 100644
--- a/tests/application/modules/opac/controllers/FormulaireControllerTest.php
+++ b/tests/application/modules/opac/controllers/FormulaireControllerTest.php
@@ -31,6 +31,10 @@ abstract class FormulaireControllerPostActionTestCase extends AbstractController
                                           'contenu' => '<form action="/formulaire/add/id_article/45" method="POST" name="Nous écrire">'
                                           . '<p>Votre nom<input name="nom" type="text" /></p>'
                                           . '<p>Votre prénom<input name="prenom" type="text" /></p>'
+                                          . '<p><input name="Dejeuner" required="required" type="radio" value="libre">Libre</p>'
+                                          . '<p><input name="Dejeuner" required="required" type="radio" value="Restaurant">Restaurant avec le groupe (sur réservation)</p>'
+                                          . '<p><input name="option1" type="checkbox" value="wifi">Wifi</p>'
+                                          . '<p><input name="option2" type="checkbox" value="piscine">Piscine</p>'
                                           . '</form>']);
     $this->fixture('Class_Formulaire',
                    ['id' => 1,
@@ -237,6 +241,107 @@ class FormulaireControllerPostAsBotTest extends FormulaireControllerPostActionTe
 
     $this->assertRedirectTo('/');
   }
+
+
+  /** @test */
+  public function withValidDataShouldCreateANewForm() {
+    $this->postDispatch('/formulaire/add/id_article/45',
+                        ['nom' => 'Tinguette' ,
+                         'prenom' => 'Quentin',
+                         'Dejeuner' => 'libre',
+                         'option1' => 'cafe',
+                         'option2' => 'wifi',
+                         'website' => ''],
+                        true);
+    $this->assertNotRedirectTo('/');
+  }
+
+}
+
+
+
+
+class FormulaireControllerPostActionDebugTestCase extends AbstractControllerTestCase {
+  protected
+    $_storm_default_to_volatile = true;
+
+
+  public function setUp() {
+    parent::setUp();
+
+    Class_Article::newInstanceWithId(45, ['titre' => 'Contactez nous',
+                                          'contenu' => '<form action="/arthur/formulaire/add/id_article/1618" method="POST">
+<p><input name="Inscription Journée Bokeh 2 avril Talence" type="hidden" value="Inscription Journée Bokeh 2 avril Talence" />Nom, Pr&eacute;nom<br />
+<input data-tc-id="w-0.29026469748912975" name="Nom, Prénom" required="required" tc-textcontent="true" type="text" /></p>
+
+<p>Adresse mail<br />
+<input data-tc-id="w-0.07789243529520828" name="Mail" required="required" tc-textcontent="true" type="email" /></p>
+
+<p>Etablissement<br />
+<input data-tc-id="w-0.0005608611335192748" name="Etablissement" required="required" tc-textcontent="true" type="text" /></p>
+
+<p>SIGB (Nanook, Koha, PNB, Orph&eacute;e NX etc....)<br />
+<input data-tc-id="w-0.8095451597979981" name="SIGB" required="required" tc-textcontent="true" type="text" /></p>
+
+<p>Adresse de votre portail Bokeh (url en http/s)<br />
+<input data-tc-id="w-0.20741370069209997" name="Site Web" tc-textcontent="true" type="url" /></p>
+
+<p>D&eacute;jeuner</p>
+
+<p><input data-tc-id="w-0.4082287663760651" name="Dejeuner" required="required" tc-textcontent="true" type="radio" value="libre" />Libre</p>
+
+<p><input data-tc-id="w-0.46758368222915037" name="Dejeuner" required="required" tc-textcontent="true" type="radio" value="Restaurant" />Restaurant avec le groupe (sur r&eacute;servation)</p>
+
+<p>&nbsp;</p>
+
+<p><input data-tc-id="w-0.42382856730050433" tc-textcontent="true" type="submit" value="Envoyer" /></p>
+<input autocomplete="off" data-spambots="true" data-tc-id="w-0.997230006041362" name="website" tc-textcontent="true" type="text" />&nbsp;</form>
+<form action="/arthur/formulaire/add/id_article/1618" method="POST">
+<p><input name="Inscription Journée Bokeh 2 avril Talence" type="hidden" value="Inscription Journée Bokeh 2 avril Talence" />Nom, Pr&eacute;nom<br />
+<input data-tc-id="w-0.29026469748912975" name="Nom, Prénom" required="required" tc-textcontent="true" type="text" /></p>
+
+<p>Adresse mail<br />
+<input data-tc-id="w-0.07789243529520828" name="Mail" required="required" tc-textcontent="true" type="email" /></p>
+
+<p>Etablissement<br />
+<input data-tc-id="w-0.0005608611335192748" name="Etablissement" required="required" tc-textcontent="true" type="text" /></p>
+
+<p>SIGB (Nanook, Koha, PNB, Orph&eacute;e NX etc....)<br />
+<input data-tc-id="w-0.8095451597979981" name="SIGB" required="required" tc-textcontent="true" type="text" /></p>
+
+<p>Adresse de votre portail Bokeh (url en http/s)<br />
+<input data-tc-id="w-0.20741370069209997" name="Site Web" tc-textcontent="true" type="url" /></p>
+
+<p>D&eacute;jeuner</p>
+
+<p><input data-tc-id="w-0.4082287663760651" name="Dejeuner" required="required" tc-textcontent="true" type="radio" value="libre" />Libre</p>
+
+<p><input data-tc-id="w-0.46758368222915037" name="Dejeuner" required="required" tc-textcontent="true" type="radio" value="Restaurant" />Restaurant avec le groupe (sur r&eacute;servation)</p>
+
+<p>&nbsp;</p>
+
+<p><input data-tc-id="w-0.42382856730050433" tc-textcontent="true" type="submit" value="Envoyer" /></p>
+<input autocomplete="off" data-spambots="true" data-tc-id="w-0.997230006041362" name="website" tc-textcontent="true" type="text" />&nbsp;</form>
+']);
+
+    $this->postDispatch('/formulaire/add/id_article/45',
+                        [
+                         'Inscription_Journée_Bokeh_2_avril_Talence' => 'Inscription Journée Bokeh 2 avril Talence',
+                         'Nom,_Prénom' => 'Suzuki',
+                         'Mail' => 'arthur.suzuki@free.fr',
+                         'Etablissement' => 'AFI',
+                         'SIGB' => 'koha',
+                         'Site_Web' => 'http://sandbox.afi-sa.fr/arthur/cms/articleview/id/1618',
+                         'Dejeuner' => 'libre',
+                         'website' => ''
+                        ],
+                        true);
+  }
+
+    /** @test */
+  public function responseShouldNotRedirect() {
+    $this->assertNotRedirectTo('/');
+  }
 }
 
 ?>
\ No newline at end of file
diff --git a/tests/application/modules/opac/controllers/RechercheControllerTest.php b/tests/application/modules/opac/controllers/RechercheControllerTest.php
index ec518498918ab5744779214267f7eda245d7b5a9..982baf0bf752e5f0206b43b35f9a3b7809cbb6ce 100644
--- a/tests/application/modules/opac/controllers/RechercheControllerTest.php
+++ b/tests/application/modules/opac/controllers/RechercheControllerTest.php
@@ -1603,6 +1603,7 @@ class RechercheControllerSimpleActionWithListeFormatMurTest extends RechercheCon
 
   public function setUp() {
     parent::setUp();
+    Class_AdminVar::set('AUTHOR_PAGE', 0);
     $this->dispatch('/recherche/simple/expressionRecherche/potter/facettes/T1/facette/B1/page/2', true);
   }
 
diff --git a/tests/library/Class/CatalogueTest.php b/tests/library/Class/CatalogueTest.php
index d0b8cfb3674f8f5620e3b2b9697f8d6324b1ccfc..03b5e781c3302bf66d32ec16414b08143c17c2e9 100644
--- a/tests/library/Class/CatalogueTest.php
+++ b/tests/library/Class/CatalogueTest.php
@@ -218,6 +218,8 @@ class CatalogueTestOrderByForCatalogueRequestByPreferences extends ModelTestCase
 }
 
 
+
+
 class CatalogueTestGetSelectionFacette extends ModelTestCase {
   protected $_catalogue;
 
@@ -283,6 +285,7 @@ class CatalogueTestGetSelectionFacette extends ModelTestCase {
 }
 
 
+
 class CatalogueTestGetPagedNotices extends ModelTestCase {
   protected $_catalogue;
   protected $_noticeWrapper;
@@ -468,6 +471,8 @@ class CatalogueTestGetPagedNotices extends ModelTestCase {
 }
 
 
+
+
 class CatalogueTestGetRequetesWithFacettesAndNoCatalogue extends ModelTestCase {
   protected $_catalogue;
 
@@ -498,6 +503,7 @@ class CatalogueTestGetRequetesWithFacettesAndNoCatalogue extends ModelTestCase {
 }
 
 
+
 class CatalogueTestOAISpec extends ModelTestCase {
   protected $_catalogue;
 
@@ -1032,6 +1038,8 @@ class CatalogueThesaurusCRUDTest extends CatalogueParentTest {
 }
 
 
+
+
 class CatalogueGetAllNoticesIdsForDomaineTest extends ModelTestCase {
   protected
     $_storm_default_to_volatile = true,
@@ -1040,7 +1048,9 @@ class CatalogueGetAllNoticesIdsForDomaineTest extends ModelTestCase {
   public function setUp() {
     parent::setUp();
     $this->_catalogue = $this->fixture('Class_Catalogue',
-                                       ['id' => 3, 'libelle' => 'Livres', 'facettes' => 'T1']);
+                                       ['id' => 3,
+                                        'libelle' => 'Livres',
+                                        'facettes' => 'T1']);
 
     $this->mock_sql = $this->mock();
     Zend_Registry::set('sql', $this->mock_sql);
diff --git a/tests/library/Class/ModelTestCase.php b/tests/library/Class/ModelTestCase.php
index a356656577e648825aca7f2b9b96f9f484e5de53..079019763dd78d61289f67c5a770797a066b8887 100644
--- a/tests/library/Class/ModelTestCase.php
+++ b/tests/library/Class/ModelTestCase.php
@@ -69,6 +69,7 @@ abstract class ModelTestCase extends Storm_Test_ModelTestCase {
     Class_Url::setBaseUrl('/bokeh');
     Class_Url::setPhpMode('apache');
 
+    Class_Journal_Type::disable(); // perf: do not track adminvars by default
     Class_AdminVar::beVolatile();
     Class_AdminVar::set('CACHE_ACTIF', 0);
     Class_AdminVar::set('BIBNUM', 1);
diff --git a/tests/library/ZendAfi/View/Helper/ListeNotices/MurTest.php b/tests/library/ZendAfi/View/Helper/ListeNotices/MurTest.php
index abed31518e03f501b5fa6bfa6a2bef8deb372010..18ea0416e30fe718e776a163990fdc05404439a8 100644
--- a/tests/library/ZendAfi/View/Helper/ListeNotices/MurTest.php
+++ b/tests/library/ZendAfi/View/Helper/ListeNotices/MurTest.php
@@ -46,6 +46,13 @@ class ZendAfi_View_Helper_ListeNotices_MurForNoticeTest extends ZendAfi_View_Hel
     $time_source = new TimeSourceForTest('2013-12-14 09:00:00');
     Class_Notice::setTimeSource($time_source);
 
+    $this->onLoaderOfModel('Class_CodifAuteur')
+         ->whenCalled('findWithFullName')
+         ->with('Joanne Kathleen Rowling')
+         ->answers($this->fixture('Class_CodifAuteur',
+                                  ['id' => 3,
+                                   'libelle' => 'Joanne Kathleen Rowling']));
+
     $potter = Class_Notice::newInstanceWithId(2,
                                               ['unimarc' => "00627nam0 22002291  450 00100080000001000180000802100070002610000410003310100130007410500390008720000690012621000360019521500290023122500230026067600060028368600100028970000290029983000270032883500060035593000140036193200220037500028922  a2-07-052818-9  aFR  a20010130         d   0frea01      ba1 afreceng  1[2001-01-30-00.00.00.000000][][][]1 aHarry Potter et le prisonnier d'AzkabanfJoanne Kathleen Rowling  aPariscGallimard jeunessed2000  a465 p.3465cill.d18 cm 2aFolio juniorv1006  10  aR ROW1 aRowlingbJoanne Kathleen  1A32A partir de 10 ans  aJ  aRomans4R  aSorcier-Sorcière",
                                                'url_vignette' => 'hp.png',
@@ -80,9 +87,9 @@ class ZendAfi_View_Helper_ListeNotices_MurForNoticeTest extends ZendAfi_View_Hel
 
 
   /** @test */
-  public function divShouldContainsAuteurJKRowlingWithRebond() {
+  public function divShouldContainsAuteurJKRowlingWithLinkToBiography() {
     $this->assertXPathContentContains($this->_html,
-                                      '//div//a[contains(@href, "recherche/simple/code_rebond/A400")]',
+                                      '//div//a[contains(@href, "/author/view/id/3")]',
                                       'Joanne Kathleen Rowling');
   }
 
diff --git a/tests/library/ZendAfi/View/Helper/ListeNotices/TableauTest.php b/tests/library/ZendAfi/View/Helper/ListeNotices/TableauTest.php
index 9bd900deaaeeda0cafab8a8fce9a83b45170350e..66783c93803b885b108af44af9204a8271755587 100644
--- a/tests/library/ZendAfi/View/Helper/ListeNotices/TableauTest.php
+++ b/tests/library/ZendAfi/View/Helper/ListeNotices/TableauTest.php
@@ -34,9 +34,16 @@ class ZendAfi_View_Helper_ListeNotices_TableauTest extends ViewHelperTestCase {
 
     $data = [$this->fixture('Class_Notice',
                             ['id' => 42,
-                             'titre_principal' => 'Le grand livre de Beatrix Potter'])];
+                             'titre_principal' => 'Le grand livre de Beatrix Potter',
+                             'url_vignette' => 'http://image.org/potter'])];
 
-    $this->_html = $this->_helper->listeNotices_Tableau($data, ['liste_codes' => 'J;A;F;C;N']);
+    $this->_html = $this->_helper->listeNotices_Tableau($data, ['liste_codes' => 'U;J;A;F;C;N']);
+  }
+
+
+  /** @test */
+  public function pageShouldContainsThumbnailForPotter() {
+    $this->assertXPath($this->_html, '//td//img[@src="http://image.org/potter"]');
   }
 
 
diff --git a/tests/scenarios/Journal/JournalTest.php b/tests/scenarios/Journal/JournalTest.php
index a694d833078b6d96a57a6fd1957c4eb43f0b23a9..ef2191b55761f217dc91f6e32dbe31b5b4ee75d7 100644
--- a/tests/scenarios/Journal/JournalTest.php
+++ b/tests/scenarios/Journal/JournalTest.php
@@ -20,10 +20,20 @@
  */
 
 
-class JournalAdminVarPostTest extends Admin_AbstractControllerTestCase {
+abstract class JournalAdminVarTestCase extends Admin_AbstractControllerTestCase {
   protected $_storm_default_to_volatile = true;
 
 
+  public function setUp() {
+    parent::setUp();
+    Class_Journal_Type::enable();
+  }
+}
+
+
+
+
+class JournalAdminVarPostTest extends JournalAdminVarTestCase {
   public function setUp() {
     parent::setUp();
     Class_AdminVar::set('FACETTE_GENRE_LIBELLE', '');
@@ -74,10 +84,7 @@ class JournalAdminVarPostTest extends Admin_AbstractControllerTestCase {
 
 
 
-class JournalIndexActionTest extends Admin_AbstractControllerTestCase {
-  protected $_storm_default_to_volatile = true;
-
-
+class JournalIndexActionTest extends JournalAdminVarTestCase {
   public function setUp() {
     parent::setUp();
 
@@ -93,4 +100,4 @@ class JournalIndexActionTest extends Admin_AbstractControllerTestCase {
                                       'La variable "FACETTE_GENRE_LIBELLE" a été modifiée de "" à "test" par "Harlock"',
                                       $this->_response->getBody());
   }
-}
\ No newline at end of file
+}
diff --git a/tests/scenarios/Templates/PolygoneTemplateTest.php b/tests/scenarios/Templates/PolygoneTemplateTest.php
index e82c7a156a65b0e26425bd83adcd8a4e689e077b..4ffedb44cdda12550f3cf3c0718c2086b79cf9b9 100644
--- a/tests/scenarios/Templates/PolygoneTemplateTest.php
+++ b/tests/scenarios/Templates/PolygoneTemplateTest.php
@@ -76,8 +76,7 @@ class PolygoneTemplateProfilePatcherTest extends PolygoneTemplateTestCase {
             ['rech_simple'],
             ['admin_tools'],
             ['scroll'],
-            ['library'],
-            ['critiques'],
+            ['library']
     ];
   }
 
@@ -102,13 +101,14 @@ class PolygoneTemplateProfilePatcherTest extends PolygoneTemplateTestCase {
 class PolygoneTemplateOpacIndexWithUserAgentTest extends PolygoneTemplateTestCase {
   public function setUp() {
     parent::setUp();
+    ZendAfi_Auth::getInstance()->clearIdentity();
     $this->dispatch('/opac/index/index');
   }
 
 
   /** @test */
   public function pageTitleShouldBeTestChartePolygone() {
-    $this->assertXPathContentContains('//head/title', 'Musclé');
+    $this->assertXPathContentContains('//head/title', 'Polygone');
   }
 
 
diff --git a/tests/scenarios/Templates/TemplatesTest.php b/tests/scenarios/Templates/TemplatesTest.php
index f921d8b43ee08ed5961af0dd63721f01c20c917a..f6f1b53492d3fecf4fd65a735722be53d562ac90 100644
--- a/tests/scenarios/Templates/TemplatesTest.php
+++ b/tests/scenarios/Templates/TemplatesTest.php
@@ -2901,7 +2901,13 @@ class TemplatesDispatchIntonationSearchListFormatWallTest extends TemplatesInton
 
   /** @test */
   public function suggestionsShouldBeDisplay() {
-    $this->assertXPathContentContains('//b', 'Suggestions', $this->_response->getBody());
+    $this->assertXPathContentContains('//b', 'Suggestions');
+  }
+
+
+  /** @test */
+  public function masonryShouldBeLoaded() {
+    $this->assertXPath('//head/script[contains(@src, "/masonry.js")]');
   }
 }