diff --git a/VERSIONS_HOTLINE/88224 b/VERSIONS_HOTLINE/88224
new file mode 100644
index 0000000000000000000000000000000000000000..54b23f4c9568c1bf71d192a9345a3f3d7741831d
--- /dev/null
+++ b/VERSIONS_HOTLINE/88224
@@ -0,0 +1 @@
+ - ticket #88224 : SIGB Nanook : Amélioration de la prise en charge dans Bokeh du dédoublonnage effectué dans le SIGB
\ No newline at end of file
diff --git a/VERSIONS_HOTLINE/90555 b/VERSIONS_HOTLINE/90555
new file mode 100644
index 0000000000000000000000000000000000000000..8909cebb7dff27fa68899f9ed63959f39cb2639d
--- /dev/null
+++ b/VERSIONS_HOTLINE/90555
@@ -0,0 +1 @@
+ - ticket #90555 : SIGB Koha : Bokeh peut maintenant afficher les vignettes de notices stockées dans Koha et précisées dans l'unimarc
\ No newline at end of file
diff --git a/VERSIONS_HOTLINE/90704 b/VERSIONS_HOTLINE/90704
new file mode 100644
index 0000000000000000000000000000000000000000..9b19ce5a3b93b540b95920c3f394747fb4da8c04
--- /dev/null
+++ b/VERSIONS_HOTLINE/90704
@@ -0,0 +1 @@
+ - ticket #90704 : Boite Calendrier : Correction de la prise en compte du paramètre Ordre d'Affichage.
\ No newline at end of file
diff --git a/VERSIONS_HOTLINE/90858 b/VERSIONS_HOTLINE/90858
new file mode 100644
index 0000000000000000000000000000000000000000..d8dd420403bbc137dc93a95896b17c904106ac96
--- /dev/null
+++ b/VERSIONS_HOTLINE/90858
@@ -0,0 +1 @@
+ - ticket #90858 : Administration Activités : Correction d'une erreur survenant lorsqu'un participant a été supprimé de la base de données
\ No newline at end of file
diff --git a/VERSIONS_HOTLINE/93294 b/VERSIONS_HOTLINE/93294
new file mode 100644
index 0000000000000000000000000000000000000000..9457ff03be2b6b81437b2d2df7dc85feb4fccb6c
--- /dev/null
+++ b/VERSIONS_HOTLINE/93294
@@ -0,0 +1 @@
+ - ticket #93294 : Compte lecteur : Correction des paginations multiples sur les prêts
\ No newline at end of file
diff --git a/application/modules/admin/controllers/ActivityController.php b/application/modules/admin/controllers/ActivityController.php
index bc99c9b5379e6cde92761b6de7800d22e0ce0ea7..c1b27cfc8060b9c4050ab74363fd1e2869345dbf 100644
--- a/application/modules/admin/controllers/ActivityController.php
+++ b/application/modules/admin/controllers/ActivityController.php
@@ -118,7 +118,7 @@ class Admin_ActivityController extends ZendAfi_Controller_Action {
 
 
   public function presencesAction() {
-    $session = Class_SessionActivity::getLoader()->find((int)$this->_getParam('id'));
+    $session = Class_SessionActivity::find((int)$this->_getParam('id'));
 
     if ($this->_request->isPost()) {
       $user_ids = $this->_request->getPost('user_ids');
@@ -144,26 +144,29 @@ class Admin_ActivityController extends ZendAfi_Controller_Action {
 
   protected function _presencesForm($session) {
     $user_checkboxes = new Zend_Form_Element_MultiCheckbox('user_ids');
-    $ids = array();
+    $ids = [];
+
     foreach($session->getSessionActivityInscriptions() as $inscription) {
       $user = $inscription->getStagiaire();
       if ($inscription->isPresent())
-        $ids[]=$user->getId();
+        $ids[] = $user->getId();
+
       $user_checkboxes->addMultiOption($user->getId(),
                                        sprintf('%s %s - %s',
                                                $user->getNom(),
                                                $user->getPrenom(),
                                                $user->getLogin()));
     }
+
     $user_checkboxes->setValue($ids);
 
     return $this->view
-      ->newForm(array('id' => 'presencesForm'))
+      ->newForm(['id' => 'presencesForm'])
       ->setMethod('post')
       ->addElement($user_checkboxes)
-      ->addDisplayGroup(array('user_ids'),
+      ->addDisplayGroup(['user_ids'],
                         'presences',
-                        array('legend' => 'Stagiaires présents'));
+                        ['legend' => $this->_('Stagiaires présents')]);
   }
 
 
diff --git a/application/modules/opac/controllers/CmsController.php b/application/modules/opac/controllers/CmsController.php
index 902925d5d8a8c9860782ad5dcf72eaa0298f3a52..5c6105213c272807ab9c39d123cd30d9360ba6be 100644
--- a/application/modules/opac/controllers/CmsController.php
+++ b/application/modules/opac/controllers/CmsController.php
@@ -234,10 +234,10 @@ class CmsController extends ZendAfi_Controller_Action {
 
     $module_calendrier = new Class_Systeme_ModulesAccueil_Calendrier();
     $preferences = array_merge($module_calendrier->getDefaultValues(),
-                               $this->_modulesPreferences($id_module));
+                               Class_Profil::getCurrentProfil()->getModuleAccueilPreferences($id_module, 'CALENDAR'));
     $preferences['ID_MODULE'] = $id_module;
     $preferences['SELECT_ID_CAT'] = $preferences['display_cat_select']
-       ? $this->_getParam('select_id_categorie')
+      ? $this->_getParam('select_id_categorie')
       : 'all';
 
     $this->view->calendar = new Class_Calendar($id_module,
@@ -255,7 +255,7 @@ class CmsController extends ZendAfi_Controller_Action {
    * @param int $id_profil
    * @return array
    */
-  private function _modulesPreferences($id_module, $id_profil = null, $id_menu = null) {
+  protected function _modulesPreferences($id_module, $id_profil = null, $id_menu = null) {
     $profil = ($id_profil)
                 ? Class_Profil::find($id_profil)
                 : Class_Profil::getCurrentProfil();
diff --git a/cosmogramme/cosmozend/VERSIONS_HOTLINE/89832 b/cosmogramme/cosmozend/VERSIONS_HOTLINE/89832
new file mode 100644
index 0000000000000000000000000000000000000000..1bb6b801c6b446b8298157890ef8874d8b991e4c
--- /dev/null
+++ b/cosmogramme/cosmozend/VERSIONS_HOTLINE/89832
@@ -0,0 +1 @@
+ - ticket #89832 : Autorisation d'affichage des vignettes issues de ADAV précisées en unimarc des notices
\ No newline at end of file
diff --git a/library/Class/Calendar.php b/library/Class/Calendar.php
index e2e3a873809d9fd5f20dc74509f3661eed64bcff..44ad270138d544bf8bff964d4dbd36b5dd51ca70 100644
--- a/library/Class/Calendar.php
+++ b/library/Class/Calendar.php
@@ -153,7 +153,7 @@ class Class_Calendar {
 
 
   protected function _loadArticles($extra_prefs) {
-    $prefs = array_merge(['display_order' => 'EventDebut',
+    $prefs = array_merge(['display_order' => $this->preferences['display_order'],
                           'id_categorie' => $this->_getCategoriesIds(),
                           'events_only' => true,
                           'event_date' => $this->date,
diff --git a/library/Class/Entity.php b/library/Class/Entity.php
index 7b3e2df6eaff7306c30f84670d04372569cb9a44..10bab2a777e5dcc2c37cedf96e01097e18898833 100644
--- a/library/Class/Entity.php
+++ b/library/Class/Entity.php
@@ -80,6 +80,11 @@ class Class_Entity {
   }
 
 
+  public function callGetterByAttributeName($attribute) {
+    return call_user_func([$this, 'get' . Storm_Inflector::camelize($attribute)]);
+  }
+
+
   public function __toString() {
     return get_class($this);
   }
diff --git a/library/Class/Notice/BarcodeDoubleFinder.php b/library/Class/Notice/BarcodeDoubleFinder.php
index 552f5d78f26348cf738ea799d74f50ead572b5bc..cb49786552f7e0eb4463e2983167d081d5da070c 100644
--- a/library/Class/Notice/BarcodeDoubleFinder.php
+++ b/library/Class/Notice/BarcodeDoubleFinder.php
@@ -21,27 +21,18 @@
 
 
 class Class_Notice_BarcodeDoubleFinder extends Class_Notice_DoubleFinder {
-  public function find() {
-    $this->_on_barcode = null;
-    $this->_id = null;
-
-    if ($this->_id = $this->findByBarcodes()) {
-      $this->_found_on = 'code_barres';
-      return true;
-    }
-
-    return false;
+  protected function _buildStrategy() {
+    parent::_buildStrategy();
+    $this->_strategy->addItemFilter([$this, 'filterSigbLoanable']);
   }
 
 
-  protected function _getRecordIdByItemFilters() {
-    $filters = parent::_getRecordIdByItemFilters();
-    $filters[] = [$this, '_filterSigbLoanable'];
-    return $filters;
+  protected function _strategyName() {
+    return 'Class_Notice_DoubleFinder_BarcodeStrategy';
   }
 
 
-  protected function _filterSigbLoanable($items) {
+  public function filterSigbLoanable($items) {
     foreach($items as $item)
       if ($item->isSigbLoanable())
         return $item;
diff --git a/library/Class/Notice/DoubleFinder.php b/library/Class/Notice/DoubleFinder.php
index dd6642a4620c0576ba9e86c0a7c3670cb7579d78..a50221ac5825ce44ce9ffc09d20f291acdf24ee5 100644
--- a/library/Class/Notice/DoubleFinder.php
+++ b/library/Class/Notice/DoubleFinder.php
@@ -26,6 +26,7 @@ class Class_Notice_DoubleFinder {
     VAR_DOUBLE_MODE = 'mode_doublon';
 
   protected
+    $_strategy,
     $_barcode_uniq_mode,
     $_double_mode,
     $_data,
@@ -42,28 +43,78 @@ class Class_Notice_DoubleFinder {
 
     if (!$this->_library = Class_IntBib::find($library_id))
       $this->_library = Class_IntBib::newInstance();
+
+    $this->_buildStrategy();
+  }
+
+
+  protected function _buildStrategy() {
+    $strategy_name = $this->_strategyName();
+    $library_limit = ($this->_barcode_uniq_mode == Class_CosmoVar::UNIQ_BARCODE_WITHIN_LIBRARY)
+      ? (int) $this->_library->getId()
+      : null;
+
+    $this->_strategy = new $strategy_name($library_limit);
+  }
+
+
+  protected function _strategyName() {
+    if ($this->_profil
+        && ($this->_profil->isFormatDublinCore() || $this->_profil->isBibliondemand()))
+      return 'Class_Notice_DoubleFinder_BarcodeStrategy';
+
+    if (($this->_double_mode == Class_CosmoVar::DOUBLE_SEARCH_NONE)
+        && $this->_library->isPergame())
+      return 'Class_Notice_DoubleFinder_NoDedupStrategy';
+
+    if ($this->_double_mode == Class_CosmoVar::DOUBLE_SEARCH_ALPHA_KEY)
+      return 'Class_Notice_DoubleFinder_AlphaKeyStrategy';
+
+    return 'Class_Notice_DoubleFinder_IdsStrategy';
   }
 
 
   public function find() {
-    $this->_on_barcode = null;
-    $this->_id = null;
+    return $this->_strategy->find($this->_data);
+  }
 
-    if ($this->_id = $this->findByBarcodes()) {
-      $this->_found_on = 'code_barres';
-      return true;
-    }
 
-    if ($this->_profil && ($this->_profil->isFormatDublinCore() || $this->_profil->isBibliondemand()))
-      return false;
+  public function getMatchedCriteria() {
+    return $this->_strategy->getMatchedCriteria();
+  }
 
-    if ($this->_id = $this->findByIdOrigine()) {
-      $this->_found_on = 'id_origine';
-      return true;
-    }
 
-    return (bool) ($this->_id = $this->findByIds());
+  public function getId() {
+    return $this->_strategy->getId();
   }
+}
+
+
+
+abstract class Class_Notice_DoubleFinder_Strategy {
+  const
+    FOUND_ON_BARCODE = 'code_barres',
+    FOUND_ON_ID_ORIGINE = 'id_origine';
+
+  protected
+    $_data,
+    $_id,
+    $_found_on,
+    $_library_limit,
+    $_item_filters;
+
+
+  public function __construct($library_limit) {
+    $this->_library_limit = $library_limit;
+    $this->_item_filters = [ [$this, '_filterSameDoctype'] ];
+  }
+
+
+  /**
+   * @param Class_Entity $data
+   * @return bool true if double has been found
+   */
+  abstract public function find($data);
 
 
   public function getMatchedCriteria() {
@@ -76,37 +127,34 @@ class Class_Notice_DoubleFinder {
   }
 
 
-  protected function findByBarcodes() {
+  public function addItemFilter($filter) {
+    $this->_item_filters[] = $filter;
+    return $this;
+  }
+
+
+  protected function _findByBarcodes() {
     if (!$this->_hasItems())
       return;
 
     foreach ($this->_data->getexemplaires() as $item)
-      if ($id = $this->findByBarcodeOf($item))
+      if ($id = $this->_findByBarcodeOf($item))
         return $id;
   }
 
 
-  protected function findByBarcodeOf($item) {
+  protected function _findByBarcodeOf($item) {
     if (!$item['code_barres'])
       return;
 
     $conditions = ['code_barres' => $item['code_barres']];
-    if ($this->_barcode_uniq_mode == Class_CosmoVar::UNIQ_BARCODE_WITHIN_LIBRARY)
-      $conditions['id_int_bib'] = (int) $this->_library->getId();
+    if ($this->_library_limit)
+      $conditions['id_int_bib'] = $this->_library_limit;
 
     return $this->_getRecordIdByItem($conditions);
   }
 
 
-  protected function findByIdOrigine() {
-    if (($this->_double_mode != Class_CosmoVar::DOUBLE_SEARCH_NONE)
-        || !$this->_library->isPergame())
-      return;
-
-    return $this->_getRecordIdByItem(['id_origine' => $this->_data->getid_origine()]);
-  }
-
-
   protected function _getRecordIdByItem($conditions) {
     $conditions['type'] = Class_Notice::TYPE_BIBLIOGRAPHIC;
     $founds = Class_Exemplaire::findAllBy($conditions);
@@ -120,7 +168,7 @@ class Class_Notice_DoubleFinder {
 
 
   protected function _getRecordIdByItemFilters() {
-    return [ [$this, '_filterSameDoctype'] ];
+    return $this->_item_filters;
   }
 
 
@@ -131,8 +179,104 @@ class Class_Notice_DoubleFinder {
   }
 
 
+  protected function _hasItems() {
+    return ($statuses = $this->_data->getstatut_exemplaires())
+      || $statuses['nb_ex'] > 0;
+  }
+}
+
+
+
+class Class_Notice_DoubleFinder_BarcodeStrategy extends Class_Notice_DoubleFinder_Strategy {
+  public function find($data) {
+    $this->_id = null;
+    $this->_data = $data;
+
+    if ($this->_id = $this->_findByBarcodes()) {
+      $this->_found_on = static::FOUND_ON_BARCODE;
+      return true;
+    }
+
+    return false;
+  }
+}
+
+
+
+class Class_Notice_DoubleFinder_NoDedupStrategy extends Class_Notice_DoubleFinder_Strategy {
+  public function find($data) {
+    $this->_id = null;
+    $this->_data = $data;
+
+    if ($this->_id = $this->_findByBarcodes()) {
+      $this->_found_on = static::FOUND_ON_BARCODE;
+      return true;
+    }
+
+    if ($this->_id = $this->_findByIdOrigine()) {
+      $this->_found_on = static::FOUND_ON_ID_ORIGINE;
+      return true;
+    }
+
+    return false;
+  }
+
+
+  protected function _findByIdOrigine() {
+    return $this->_getRecordIdByItem(['id_origine' => $this->_data->getid_origine()]);
+  }
+
+
+  protected function _findByBarcodeOf($item) {
+    if (!$item['code_barres'])
+      return;
+
+    $conditions = ['code_barres' => $item['code_barres']];
+    if ($this->_library_limit)
+      $conditions['id_int_bib'] = $this->_library_limit;
+
+    $conditions['type'] = Class_Notice::TYPE_BIBLIOGRAPHIC;
+    $founds = Class_Exemplaire::findAllBy($conditions);
+    if (empty($founds))
+      return;
+
+    foreach($founds as $found)
+      if ($this->_isValidItem($found))
+        return $found->getIdNotice();
+  }
+
+
+  protected function _isValidItem($item) {
+    if ($this->_data->gettype_doc() != $item->getTypeDoc())
+      return false;
+
+    if ($this->_data->getid_origine() != $item->getIdOrigine()) {
+      $item->delete();
+      return false;
+    }
+
+    return true;
+  }
+}
+
+
+
+abstract class Class_Notice_DoubleFinder_KeysStrategy extends Class_Notice_DoubleFinder_Strategy {
+  public function find($data) {
+    $this->_id = null;
+    $this->_data = $data;
+
+    if ($this->_id = $this->_findByBarcodes()) {
+      $this->_found_on = static::FOUND_ON_BARCODE;
+      return true;
+    }
+
+    return (bool) ($this->_id = $this->findByIds());
+  }
+
+
   protected function findByIds() {
-    foreach ($this->recordAttributes() as $attr)
+    foreach ($this->_recordAttributes() as $attr)
       if ($id = $this->findById($attr))
         return $id;
   }
@@ -148,18 +292,7 @@ class Class_Notice_DoubleFinder {
   }
 
 
-  protected function recordAttributes() {
-    if ($this->_double_mode == Class_CosmoVar::DOUBLE_SEARCH_IDS)
-      return [['isbn', $this->_data->getisbn13()],
-              ['isbn', $this->_data->getisbn10()],
-              ['ean', $this->_data->getean()],
-              ['id_commerciale', $this->_data->getid_commerciale()]];
-
-    if ($this->_double_mode == Class_CosmoVar::DOUBLE_SEARCH_ALPHA_KEY)
-      return [ ['clef_alpha', $this->_data->getclef_alpha()] ];
-
-    return [];
-  }
+  abstract protected function _recordAttributes();
 
 
   protected function findRecordBy($key, $value) {
@@ -175,10 +308,23 @@ class Class_Notice_DoubleFinder {
       if($this->_data->gettype_doc() == $found->getTypeDoc())
         return $found->getId();
   }
+}
 
 
-  protected function _hasItems() {
-    return ($statuses = $this->_data->getstatut_exemplaires())
-      || $statuses['nb_ex'] > 0;
+
+class Class_Notice_DoubleFinder_IdsStrategy extends Class_Notice_DoubleFinder_KeysStrategy {
+  protected function _recordAttributes() {
+    return [['isbn', $this->_data->getisbn13()],
+            ['isbn', $this->_data->getisbn10()],
+            ['ean', $this->_data->getean()],
+            ['id_commerciale', $this->_data->getid_commerciale()]];
+  }
+}
+
+
+
+class Class_Notice_DoubleFinder_AlphaKeyStrategy extends Class_Notice_DoubleFinder_KeysStrategy {
+  protected function _recordAttributes() {
+    return [ ['clef_alpha', $this->_data->getclef_alpha()] ];
   }
 }
\ No newline at end of file
diff --git a/library/Class/Profil/Preferences/Loans.php b/library/Class/Profil/Preferences/Loans.php
index b37c8bdce8572e75a2c66e2d2ebcc39360ab91c6..d5b4ee267577cec68285c1b1e4fad80314ca57ad 100644
--- a/library/Class/Profil/Preferences/Loans.php
+++ b/library/Class/Profil/Preferences/Loans.php
@@ -46,7 +46,7 @@ class Class_Profil_Preferences_Loans {
   public function getToolsComposition($value) {
     return (new Class_Entity(['Id' => 'tools_composition',
                               'AvailableHeader' => $this->_('Outils disponibles'),
-                              'SelectedHeader' => $this->_('Outils activées'),
+                              'SelectedHeader' => $this->_('Outils activés'),
                               'Available' => $this->_getAvailablesTools($value),
                               'Selected' => $this->_getSelectedTools($value)]));
   }
diff --git a/library/Class/ScriptLoader.php b/library/Class/ScriptLoader.php
index b9968a0b3da9cd6496c4f069aca0eed7d0d856c7..692bb96391f2406b8f434d715074a1591020ba80 100644
--- a/library/Class/ScriptLoader.php
+++ b/library/Class/ScriptLoader.php
@@ -711,18 +711,20 @@ class Class_ScriptLoader {
   /**
    * @return ScriptLoader
    */
-  public function loadTableSorter($pager = false) {
+  public function loadTableSorter($pager = false,
+                                  $table_selector = '.tablesorter',
+                                  $pager_selector = '.model_table_pager') {
     $this
       ->addOPACScript('tablesorter/js/jquery.tablesorter.min')
       ->addStyleSheet(BASE_URL."/public/opac/js/tablesorter/css/theme.default.css")
-      ->addJQueryReady('$(".tablesorter").tablesorter()');
+      ->addJQueryReady('$("' . $table_selector . '").tablesorter()');
 
 
     if ($pager)
       $this
         ->addOPACScript('tablesorter/addons/pager/jquery.tablesorter.pager.min')
         ->addStyleSheet(BASE_URL."/public/opac/js/tablesorter/addons/pager/jquery.tablesorter.pager.css")
-        ->addJQueryReady('$(".tablesorter").tablesorterPager({container: $(".model_table_pager"),output: "{startRow} - {endRow} / {totalRows} ",fixedHeight: true})');
+        ->addJQueryReady('$("' . $table_selector . '").tablesorterPager({container: $("' . $pager_selector . '"),output: "{startRow} - {endRow} / {totalRows} ",fixedHeight: true})');
     return $this;
   }
 
diff --git a/library/Class/SessionActivityInscription.php b/library/Class/SessionActivityInscription.php
index 622ed3b84be297816cea1f6e44ac2d50f6125d8a..158a45f94b021420e71e810256ef4ad10806cc9b 100644
--- a/library/Class/SessionActivityInscription.php
+++ b/library/Class/SessionActivityInscription.php
@@ -20,6 +20,8 @@
  */
 
 class Class_SessionActivityInscription extends Storm_Model_Abstract {
+  use Trait_Translator;
+
   protected $_table_name = 'session_activity_inscriptions';
   protected $_belongs_to = ['session_activity' => ['model' => 'Class_SessionActivity'],
                             'stagiaire' => ['model' => 'Class_Users'],
@@ -46,4 +48,18 @@ class Class_SessionActivityInscription extends Storm_Model_Abstract {
   public function isPresent() {
     return $this->getPresence();
   }
+
+
+  public function getStagiaire() {
+    if ($user = parent::_get('stagiaire'))
+      return $user;
+
+    $user = (new Class_Entity(['Id' => $this->getStagiaireId(),
+                               'Nom' => $this->_('Anonyme'),
+                               'Prenom' => '',
+                               'Login' => 'n/a']))
+      ->whenCalledDo('hasRightSuivreActivity', function() { return true; });
+
+    return $user;
+  }
 }
\ No newline at end of file
diff --git a/library/ZendAfi/Validate/VignetteUrl.php b/library/ZendAfi/Validate/VignetteUrl.php
index 632e5f32391825fd8da25704efb64c94b129cb2a..c13fcfd7a05bdf5d4440fe7f258da96b39f93fdc 100644
--- a/library/ZendAfi/Validate/VignetteUrl.php
+++ b/library/ZendAfi/Validate/VignetteUrl.php
@@ -16,23 +16,27 @@
  *
  * 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 
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
  */
 class ZendAfi_Validate_VignetteUrl extends Zend_Validate_Abstract {
-  const INVALID_EXTENSION = 'invalidExtension';
-  
-  protected $_messageTemplates = array(self::INVALID_EXTENSION   => "'%value%' n'est pas une extension de type .png, .jpeg, .jpg, .gif.");
-  
+  const INVALID_URL_FORMAT = 'invalidURLFormat';
+
+  protected
+    $_messageTemplates = [self::INVALID_URL_FORMAT   => "'%value%' n'est pas une URL de vignette correspondant aux formats acceptés."],
+    $_valid_url_patterns = ['.+\.(png|jpg|jpeg|gif)$',
+                            '\/cgi-bin\/koha\/opac-image\.pl\?thumbnail=',
+                            'www\.adav-assoc\.com\/.*\/GetImage\/'
+    ];
+
+
   public function isValid($value) {
-    $parts = explode('.', $value);
-    $extension = end($parts);
-    $this->_setValue($extension);
-    
-    if (!in_array(strtolower($extension), ['png', 'jpg', 'jpeg', 'gif'])) {
-      $this->_error(self::INVALID_EXTENSION);
-      return false;
+    foreach($this->_valid_url_patterns as $pattern) {
+      if (preg_match('/' . $pattern . '/i', $value))
+        return true;
     }
-    return true;
+
+    $this->_error(self::INVALID_URL_FORMAT);
+    return false;
   }
 }
 ?>
\ No newline at end of file
diff --git a/library/ZendAfi/View/Helper/RenderTable.php b/library/ZendAfi/View/Helper/RenderTable.php
index 344cf9e13b91c4671786fadbac68f78596a88a28..932d377154330b214c4be02c3fffc81d6e5eb5f9 100644
--- a/library/ZendAfi/View/Helper/RenderTable.php
+++ b/library/ZendAfi/View/Helper/RenderTable.php
@@ -34,7 +34,9 @@ class ZendAfi_View_Helper_RenderTable extends ZendAfi_View_Helper_BaseHelper {
 
     if($description->isSorterClient()) {
       $classes [] = 'tablesorter';
-      Class_ScriptLoader::getInstance()->loadTableSorter($description->getPager());
+      Class_ScriptLoader::getInstance()->loadTableSorter($description->getPager(),
+                                                         '#' . $description->getId(),
+                                                         '.' . $this->_getPagerClass($description));
     }
 
     $classes = array_merge($classes, $description->getClasses());
@@ -53,6 +55,11 @@ class ZendAfi_View_Helper_RenderTable extends ZendAfi_View_Helper_BaseHelper {
   }
 
 
+  protected function _getPagerClass($description){
+    return 'pager_' . $description->getId();
+  }
+
+
   protected function _head($description) {
     return $this->view->renderTable_Header($description);
   }
@@ -98,7 +105,7 @@ class ZendAfi_View_Helper_RenderTable extends ZendAfi_View_Helper_BaseHelper {
 
     $form = $this->_tag('form', $html);
 
-    return $this->_tag('div', $form, ['class' => 'pager model_table_pager']);
+    return $this->_tag('div', $form, ['class' => 'pager model_table_pager '. $this->_getPagerClass($description)]);
   }
 }
 
diff --git a/tests/application/modules/admin/controllers/ActivityControllerTest.php b/tests/application/modules/admin/controllers/ActivityControllerTest.php
index 708050e009e398f5badedb5575dd7f0082b7ce60..21183890842bac131f9b0d11bd15515c21e84e5d 100644
--- a/tests/application/modules/admin/controllers/ActivityControllerTest.php
+++ b/tests/application/modules/admin/controllers/ActivityControllerTest.php
@@ -117,7 +117,7 @@ abstract class Admin_ActivityControllerTestCase extends Admin_AbstractController
                                                 'lieu' => $this->_salle_reunion,
                                                 'date_limite_inscription'=>'2012-03-05',
                                                 'intervenants' => [$this->_prof_laurent],
-                                                'stagiaires' => []]);
+                                                ]);
 
     $this->_session_java_fevrier = $this->fixture('Class_SessionActivity',
                                                   ['id' => 31,
@@ -133,7 +133,6 @@ abstract class Admin_ActivityControllerTestCase extends Admin_AbstractController
       ->setSessions([$this->_session_java_mars, $this->_session_java_fevrier])
       ->assertSave();
 
-
     $this->_patrick_inscription = $this
       ->fixture('Class_SessionActivityInscription',
                 ['id' => 76,
@@ -150,11 +149,14 @@ abstract class Admin_ActivityControllerTestCase extends Admin_AbstractController
 
     $this->_benoit_inscription->beAbsent();
 
-    $this->_session_java_mars->setStagiaires([$this->_patrick,
-                                              $this->_benoit]);
-
-    $this->_session_java_mars->setSessionActivityInscriptions([$this->_patrick_inscription,
-                                                                 $this->_benoit_inscription]);
+    $this->_session_java_mars
+      ->setSessionActivityInscriptions([$this->_patrick_inscription,
+                                        $this->_benoit_inscription,
+                                        // deleted user registration
+                                        $this->fixture('Class_SessionActivityInscription',
+                                                       ['id' => 999,
+                                                        'stagiaire_id' => 999,
+                                                        'session_activity' => $this->_session_java_mars])]);
 
     $this->fixture('Class_Activity',
                    ['id' => 14, 'libelle' => 'Learn emptyness']);
@@ -587,8 +589,8 @@ class Admin_ActivityControllerIndexTest extends Admin_ActivityControllerTestCase
 
 
   /** @test */
-  function session_mars_27_LearnJavaShouldDisplayTwoParticipants() {
-    $this->assertXPathContentContains('//table//tr[2]//td', '2 / 5-25', $this->_response->getBody());
+  function session_mars_27_LearnJavaShouldDisplayThreeParticipants() {
+    $this->assertXPathContentContains('//table//tr[2]//td', '3 / 5-25', $this->_response->getBody());
   }
 
 
@@ -1488,6 +1490,7 @@ class Admin_ActivityControllerExportInscriptionsSessionMarsJavaTest extends  Adm
   /** @test */
   public function contentShouldContainsPatAndBenoit() {
     $this->assertContains("Nom;Prénom;Identifiant\n".
+                          "Anonyme;;n/a\n".
                           "Barroca;Patrick;Pat\n".
                           "Curzillat;Benoit;Benoit\n",
                           $this->_response->getBody());
@@ -1507,7 +1510,9 @@ class Admin_ActivityControllerExportInscriptionsSessionMarsJavaTest extends  Adm
 
 
 
-class Admin_ActivityControllerPresencesSessionJavaMars27Test extends  Admin_ActivityControllerTestCase  {
+class Admin_ActivityControllerPresencesSessionJavaMars27Test
+  extends Admin_ActivityControllerTestCase  {
+
   public function setUp() {
     parent::setUp();
     $this->dispatch('/admin/activity/presences/id/32');
@@ -1536,19 +1541,27 @@ class Admin_ActivityControllerPresencesSessionJavaMars27Test extends  Admin_Acti
   public function formShouldHaveCheckedCheckboxForPatrick() {
     $this->assertXPath('//input[@name="user_ids[]"][@value="5"][@checked="checked"]');
   }
+
+
+  /** @test */
+  public function formShouldHaveCheckedCheckboxForAnonymous() {
+    $this->assertXPath('//input[@name="user_ids[]"][@value="999"][not(@checked)]');
+  }
 }
 
 
 
 
-class Admin_ActivityControllerPostPresencesSessionJavaMars27Test extends  Admin_ActivityControllerTestCase  {
+class Admin_ActivityControllerPostPresencesSessionJavaMars27Test
+  extends Admin_ActivityControllerTestCase  {
+
   protected $_inscription_patrick, $_inscription_benoit;
 
   public function setUp() {
     parent::setUp();
 
-    $this->_inscription_patrick = Class_SessionActivityInscription::getLoader()->find(76);
-    $this->_inscription_benoit = Class_SessionActivityInscription::getLoader()->find(77);
+    $this->_inscription_patrick = Class_SessionActivityInscription::find(76);
+    $this->_inscription_benoit = Class_SessionActivityInscription::find(77);
 
     $this->postDispatch('/admin/activity/presences/id/32',
                         ['user_ids' => [12]]);
diff --git a/tests/application/modules/opac/controllers/AbonneControllerLoansHistoryNanookTest.php b/tests/application/modules/opac/controllers/AbonneControllerLoansHistoryNanookTest.php
index e445867f63aba0b44268ef3669a6cb981a794bdb..7f68542a247dc17d513278bfc3325c2ed66b7c94 100644
--- a/tests/application/modules/opac/controllers/AbonneControllerLoansHistoryNanookTest.php
+++ b/tests/application/modules/opac/controllers/AbonneControllerLoansHistoryNanookTest.php
@@ -137,7 +137,7 @@ class AbonneControllerLoansHistoryNanookIndexTest extends AbonneControllerLoansH
 
   /** @test */
   public function paginatorShouldBePresent() {
-    $this->assertXPath('//div[@class="pager model_table_pager"]');
+    $this->assertXPath('//div[contains(@class,"pager model_table_pager")]');
   }
 }
 
diff --git a/tests/application/modules/opac/controllers/AbonneControllerPretsTest.php b/tests/application/modules/opac/controllers/AbonneControllerPretsTest.php
index dc8b18f4cfa89b8d3fe1d153da00b44c8f025da7..29afa75929066d772190d96017fd4312cc39cb22 100644
--- a/tests/application/modules/opac/controllers/AbonneControllerPretsTest.php
+++ b/tests/application/modules/opac/controllers/AbonneControllerPretsTest.php
@@ -288,7 +288,7 @@ class AbonneControllerPretsListThreePretsTest extends AbonneControllerPretsListT
                       (new Class_Entity())
                       ->setController('abonne')
                       ->setAction('prets'),
-                      ['tools_composition' => 'search_tool;export_barcodes;export_unimarc;extend_all;print']);
+                      ['tools_composition' => 'pager;search_tool;export_barcodes;export_unimarc;extend_all;print']);
 
     $this->dispatch('/opac/abonne/prets', true);
   }
@@ -337,7 +337,7 @@ class AbonneControllerPretsListThreePretsTest extends AbonneControllerPretsListT
 
   /** @test */
   public function tableShouldHaveClassTableSorter() {
-    $this->assertXPath('//table[@class="models tablesorter loans"]', $this->_response->getBody());
+    $this->assertXPath('//table[@class="models tablesorter loans"][@id="borrower_loans"]', $this->_response->getBody());
   }
 
 
@@ -345,7 +345,32 @@ class AbonneControllerPretsListThreePretsTest extends AbonneControllerPretsListT
   public function tableSorterShouldBeLoaded() {
     $this->assertXPath('//script[contains(@src, "tablesorter.min")]');
     $this->assertXPath('//link[contains(@href, "tablesorter/css/theme.default.css")]');
-    $this->assertXPathContentContains('//script', '$(".tablesorter").tablesorter()');
+    $this->assertXPathContentContains('//script', '$("#borrower_loans").tablesorter()');
+  }
+
+
+/** @test */
+  public function pageShouldLoadPagerScriptOnClassPagerBorrowerLoans() {
+    $this->assertXPathContentContains('//script','$("#borrower_loans").tablesorterPager({container: $(".pager_borrower_loans"),output:',$this->_response->getBody());
+  }
+
+
+/** @test */
+  public function pageShouldContainsTwoPagersForBorrowerLoans() {
+    $this->assertXPathCount('//div[@class="pager model_table_pager pager_borrower_loans"]',2, $this->_response->getBody());
+  }
+
+
+/** @test */
+  public function tableSorterForPnbShouldBeLoaded() {
+    $this->assertXPathContentContains('//script', '$("#borrower_loans_pnb").tablesorter()');
+  }
+
+
+
+  /** @test */
+  public function pageShouldContainsTwoPagersForBorrowerLoansPNB() {
+    $this->assertXPathCount('//div[@class="pager model_table_pager pager_borrower_loans_pnb"]',2, $this->_response->getBody());
   }
 
 
@@ -464,13 +489,6 @@ class AbonneControllerPretsListThreePretsTest extends AbonneControllerPretsListT
     $this->assertXPathContentContains('//tbody//td[@class="date_retour"]',
                                       '02/05/2022');
   }
-
-
-  /** @test */
-  public function peterPanPnbLoanReturnDateShouldBe2020() {
-    $this->assertXPathContentContains('//tbody//td[@class="date_retour"]',
-                                      '01/01/2020');
-  }
 }
 
 
@@ -1143,14 +1161,14 @@ class AbonneControllerPrintActionPretsTest extends AbonneControllerPretsListThre
                     'nom' => 'loans',
                     'contenu' => '<div style="page-break-inside:auto">{loans.each[
 <div style="page-break-inside:avoid; page-break-after:auto;overflow:hidden;float:left;clear:both;padding: 0.5em;margin: 0.5em 0;border: 1px solid black;width:190mm;box-shadow: 0px 0px 5px;">
-<h1>Titre : {getTitle}</h1>
+<h1>Titre : {title}</h1>
 <br />
-<span>{getThumbnail}</span><br />
-<span>emprunt&eacute; par : {getLoanedBy}</span><br />
-<span>code barre : {getBarCode}</span><br />
-<span>Auteur : {getAuthor}</span><br />
-<span>date de pr&ecirc;t : {getIssueDate}</span><br />
-<span>dates de retour pr&eacute;vu : {getReturnDate}</span></div>
+<span>{thumbnail}</span><br />
+<span>emprunt&eacute; par : {loaned_by}</span><br />
+<span>code barre : {bar_code}</span><br />
+<span>Auteur : {author}</span><br />
+<span>date de pr&ecirc;t : {issue_date}</span><br />
+<span>dates de retour pr&eacute;vu : {return_date}</span></div>
 ]}</div>']);
     $this->dispatch('abonne/print/ids/reload/strategy/Loans_List/modele_fusion/9', true);
   }
diff --git a/tests/application/modules/opac/controllers/CmsControllerCalendarActionTest.php b/tests/application/modules/opac/controllers/CmsControllerCalendarActionTest.php
index a9a17a86089bcb6e6da84e0dea971aeadb9bc543..eb14bcff09501969ad7c17764e3146fe9dcd57f7 100644
--- a/tests/application/modules/opac/controllers/CmsControllerCalendarActionTest.php
+++ b/tests/application/modules/opac/controllers/CmsControllerCalendarActionTest.php
@@ -593,7 +593,7 @@ class CmsControllerCalendarActionWithDayTest extends AbstractControllerTestCase
 
 
 class CmsControllerCalendarActionHeaderTest extends AbstractControllerTestCase {
-
+  protected $_storm_default_to_volatile = true;
 
   public function setUp() {
     parent::setUp();
@@ -617,6 +617,10 @@ class CmsControllerCalendarActionHeaderTest extends AbstractControllerTestCase {
     ];
 
 
+    $this->onLoaderOfModel('Class_Article')
+         ->whenCalled('getArticlesByPreferences')
+         ->answers([]);
+
     $this->fixture('Class_Profil',
                    ['id' => 4,
                     'browser' => 'opac',
@@ -639,6 +643,7 @@ class CmsControllerCalendarActionHeaderTest extends AbstractControllerTestCase {
 
 
 class CmsControllerCalendarActionAjaxLinkTest extends AbstractControllerTestCase {
+  protected $_storm_default_to_volatile = true;
 
   public function setUp() {
     parent::setUp();
@@ -1056,7 +1061,10 @@ class CmsControllerCalendarActionIcalExportRecurrentAllDayTest
 
 
 
+
 class CmsControllerCalendarActionWithOutDateTest extends AbstractControllerTestCase {
+  protected $_storm_default_to_volatile = true;
+
   public function setUp() {
     parent::setUp();
 
diff --git a/tests/library/Class/Notice/DoubleFinderTest.php b/tests/library/Class/Notice/DoubleFinderTest.php
index a33c63e59d18b1875de341cdbacd814421adc5f6..ffde3b95af5998af371e8676ef9dbc66cb3ec2c6 100644
--- a/tests/library/Class/Notice/DoubleFinderTest.php
+++ b/tests/library/Class/Notice/DoubleFinderTest.php
@@ -22,7 +22,6 @@
 
 abstract class DoubleFinderTestCase extends ModelTestCase {
   protected
-    $_storm_default_to_volatile = true,
     $_data = ['type_doc' => Class_TypeDoc::LIVRE],
     $_library_id = 1,
     $_finder,
@@ -39,45 +38,38 @@ abstract class DoubleFinderTestCase extends ModelTestCase {
 
 
   protected function _prepareFixtures() {
-    $item = $this->fixture('Class_Exemplaire',
-                           ['id' => 1,
-                            'code_barres' => '159',
-                            'id_origine' => '88903',
-                            'id_int_bib' => 1]);
-
     $this->fixture('Class_Notice',
                    ['id' => 1,
                     'type_doc' => Class_TypeDoc::LIVRE,
                     'isbn' => '2-85868-161-9',
                     'clef_alpha' => 'JESUISNEBONHOMME--SARA--EDTHIERRYMAGNIER-2010-1',
-                    'exemplaires' => [$item]]);
-
-    $dilicom_item = $this->fixture('Class_Exemplaire',
-                                   ['id' => 2,
-                                    'code_barres' => '0001-2',
-                                    'id_origine' => '88903',
-                                    'id_int_bib' => 1]);
+                    'exemplaires' => [ $this->fixture('Class_Exemplaire',
+                                                      ['id' => 1,
+                                                       'code_barres' => '159',
+                                                       'id_origine' => '88903',
+                                                       'id_int_bib' => 1])]]);
 
     $this->fixture('Class_Notice',
                    ['id' => 2,
                     'type_doc' => Class_TypeDoc::DILICOM,
                     'isbn' => '2-85868-161-9',
                     'clef_alpha' => 'JESUISNEBONHOMME--SARA--EDTHIERRYMAGNIER-2010-1',
-                    'exemplaires' => [$dilicom_item]]);
-
-    $rss_item = $this->fixture('Class_Exemplaire',
-                               ['id' => 3,
-                                'code_barres' => '159',
-                                'id_origine' => '789',
-                                'id_int_bib' => 1]);
+                    'exemplaires' => [ $this->fixture('Class_Exemplaire',
+                                                      ['id' => 2,
+                                                       'code_barres' => '0001-2',
+                                                       'id_origine' => '88903',
+                                                       'id_int_bib' => 1])]]);
 
     $this->fixture('Class_Notice',
                    ['id' => 3,
                     'type_doc' => Class_TypeDoc::RSS,
                     'isbn' => '2-85868-161-9',
                     'clef_alpha' => 'JESUISNEBONHOMME--SARA--EDTHIERRYMAGNIER-2010-1',
-                    'exemplaires' => [$rss_item]]);
-
+                    'exemplaires' => [ $this->fixture('Class_Exemplaire',
+                                                      ['id' => 3,
+                                                       'code_barres' => '159',
+                                                       'id_origine' => '789',
+                                                       'id_int_bib' => 1])]]);
   }
 
 
@@ -93,8 +85,16 @@ abstract class DoubleFinderTestCase extends ModelTestCase {
 
 
 
-class DoubleFinderWithNoNoticeTest extends DoubleFinderTestCase {
+class DoubleFinderWithoutAnyRecordTest extends DoubleFinderTestCase {
+  /** @test */
+  public function shouldNotFindDouble() {
+    $this->assertNotFound();
+  }
+}
 
+
+
+class DoubleFinderWithNoNoticeTest extends DoubleFinderTestCase {
   protected $_data = ['type_doc' => Class_TypeDoc::DILICOM,
                       'statut_exemplaires' => ['nb_ex' => 1],
                       'exemplaires' => [ ['code_barres' => '302'] ]];
@@ -111,16 +111,7 @@ class DoubleFinderWithNoNoticeTest extends DoubleFinderTestCase {
 
 
   /** @test */
-  public function WithExemplaireWithoutNoticeShouldNotFound() {
-    $this->assertFalse($this->_found);
-  }
-}
-
-
-
-class DoubleFinderWithoutAnyRecordTest extends DoubleFinderTestCase {
-  /** @test */
-  public function shouldNotFindDouble() {
+  public function WithExemplaireWithoutNoticeShouldNotFindDouble() {
     $this->assertNotFound();
   }
 }
@@ -128,7 +119,6 @@ class DoubleFinderWithoutAnyRecordTest extends DoubleFinderTestCase {
 
 
 abstract class DoubleFinderWithRecordMatchingTestCase extends DoubleFinderTestCase {
-
   /** @test */
   public function shouldFindRecord() {
     $this->assertFound();
@@ -200,9 +190,8 @@ class DoubleFinderWithExistingAlphaKeyTest extends DoubleFinderWithRecordMatchin
   protected function _prepareFixtures() {
     parent::_prepareFixtures();
 
-    $this->fixture('Class_CosmoVar',
-                   ['id' => Class_Notice_DoubleFinder::VAR_DOUBLE_MODE,
-                    'valeur' => Class_CosmoVar::DOUBLE_SEARCH_ALPHA_KEY]);
+    Class_CosmoVar::set(Class_Notice_DoubleFinder::VAR_DOUBLE_MODE,
+                        Class_CosmoVar::DOUBLE_SEARCH_ALPHA_KEY);
   }
 
 
@@ -219,15 +208,17 @@ class DoubleFinderWithExistingItemInAnotherLibraryTest extends DoubleFinderTestC
     $_data = ['type_doc' => Class_TypeDoc::LIVRE,
               'statut_exemplaires' => ['nb_ex' => 1],
               'exemplaires' => [ ['code_barres' => '159'] ]],
+
     $_library_id = 42;
 
 
   protected function _prepareFixtures() {
     parent::_prepareFixtures();
 
-    $this->fixture('Class_CosmoVar',
-                   ['id' => Class_Notice_DoubleFinder::VAR_BARCODE_UNIQ_MODE,
-                    'valeur' => '1']);
+    Class_CosmoVar::set(Class_Notice_DoubleFinder::VAR_BARCODE_UNIQ_MODE,
+                        Class_CosmoVar::UNIQ_BARCODE_WITHIN_LIBRARY);
+
+    $this->fixture('Class_IntBib', ['id' => 42]);
   }
 
 
@@ -248,9 +239,8 @@ class DoubleFinderWithExistingItemAndNoDedupModeTest extends DoubleFinderWithRec
   protected function _prepareFixtures() {
     parent::_prepareFixtures();
 
-    $this->fixture('Class_CosmoVar',
-                   ['id' => Class_Notice_DoubleFinder::VAR_DOUBLE_MODE,
-                    'valeur' => Class_CosmoVar::DOUBLE_SEARCH_NONE]);
+    Class_CosmoVar::set(Class_Notice_DoubleFinder::VAR_DOUBLE_MODE,
+                        Class_CosmoVar::DOUBLE_SEARCH_NONE);
   }
 
 
@@ -269,9 +259,8 @@ class DoubleFinderWithExistingIdOrigneNoDedupModeDefaultTest extends DoubleFinde
   protected function _prepareFixtures() {
     parent::_prepareFixtures();
 
-    $this->fixture('Class_CosmoVar',
-                   ['id' => Class_Notice_DoubleFinder::VAR_DOUBLE_MODE,
-                    'valeur' => Class_CosmoVar::DOUBLE_SEARCH_NONE]);
+    Class_CosmoVar::set(Class_Notice_DoubleFinder::VAR_DOUBLE_MODE,
+                        Class_CosmoVar::DOUBLE_SEARCH_NONE);
   }
 
 
@@ -294,9 +283,8 @@ class DoubleFinderWithExistingIdOrigneNoDedupModeForNanookTestTest extends Doubl
                    ['id' => 1,
                     'sigb' => Class_IntBib::SIGB_NANOOK]);
 
-    $this->fixture('Class_CosmoVar',
-                   ['id' => Class_Notice_DoubleFinder::VAR_DOUBLE_MODE,
-                    'valeur' => Class_CosmoVar::DOUBLE_SEARCH_NONE]);
+    Class_CosmoVar::set(Class_Notice_DoubleFinder::VAR_DOUBLE_MODE,
+                        Class_CosmoVar::DOUBLE_SEARCH_NONE);
   }
 
 
@@ -304,4 +292,119 @@ class DoubleFinderWithExistingIdOrigneNoDedupModeForNanookTestTest extends Doubl
   public function shouldHaveMatchedIdOrigine() {
     $this->assertEquals('id_origine', $this->_finder->getMatchedCriteria());
   }
+}
+
+
+
+/** @see #88224 */
+class DoubleFinderWithExistingCodeBarreInRemotelyDeletedRecordNoDedupModeForNanookTest
+  extends DoubleFinderWithRecordMatchingTestCase {
+  protected $_data = ['type_doc' => Class_TypeDoc::LIVRE,
+                      'id_origine' => '88903',
+                      'statut_exemplaires' => ['nb_ex' => 1],
+                      'exemplaires' => [ [ 'code_barres' => 'CLJ0003D82' ] ]];
+
+  protected function _prepareFixtures() {
+    parent::_prepareFixtures();
+
+    $this->fixture('Class_IntBib',
+                   ['id' => 1,
+                    'sigb' => Class_IntBib::SIGB_NANOOK]);
+
+    Class_CosmoVar::set(Class_Notice_DoubleFinder::VAR_DOUBLE_MODE,
+                        Class_CosmoVar::DOUBLE_SEARCH_NONE);
+
+    $this->fixture('Class_Notice',
+                   ['id' => 55,
+                    'type_doc' => Class_TypeDoc::LIVRE,
+                    'isbn' => '2-85868-161-9',
+                    'clef_alpha' => 'JESUISNEBONHOMME--SARA--EDTHIERRYMAGNIER-2010-1',
+                    'exemplaires' => [ $this->fixture('Class_Exemplaire',
+                                                      ['id' => 4,
+                                                       'id_origine' => '99283087',
+                                                       'code_barres' => 'CLJ0003D82',
+                                                       'id_int_bib' => 1,
+                                                      ])]]);
+  }
+
+
+  /** @test */
+  public function shouldHaveMatchedIdOrigine() {
+    $this->assertEquals('id_origine', $this->_finder->getMatchedCriteria());
+  }
+
+
+  /** @test */
+  public function itemInPreviousRecordShouldBeDeleted() {
+    $this->assertNull(Class_Exemplaire::find(4));
+  }
+}
+
+
+
+class DoubleFinderWithDublinCoreProfileTest extends ModelTestCase {
+  public function setUp() {
+    parent::setUp();
+
+    Class_CosmoVar::set(Class_Notice_DoubleFinder::VAR_BARCODE_UNIQ_MODE,
+                        Class_CosmoVar::UNIQ_BARCODE_WITHIN_LIBRARY);
+
+    Class_CosmoVar::set(Class_Notice_DoubleFinder::VAR_DOUBLE_MODE,
+                        Class_CosmoVar::DOUBLE_SEARCH_ALPHA_KEY);
+
+    $this->fixture('Class_IntBib', ['id' => 1]);
+    $this->fixture('Class_IntProfilDonnees',
+                   ['id' => 99,
+                    'format' => Class_IntProfilDonnees::FORMAT_DUBLIN_CORE]);
+  }
+
+
+  /** @test */
+  public function shouldFindExistingBarCodeOfSameDoctypeInSameLibrary() {
+    $id_origine = 'any:oai:server:883987228';
+    $bar_code = md5($id_origine);
+
+    $this->fixture('Class_Notice',
+                   ['id' => 99,
+                    'type_doc' => Class_TypeDoc::LIVRE,
+                    'exemplaires' => [ $this->fixture('Class_Exemplaire',
+                                                      ['id' => 839,
+                                                       'code_barres' => $bar_code,
+                                                       'id_origine' => $id_origine,
+                                                       'id_int_bib' => 1])]]);
+
+    $datas = ['type_doc' => Class_TypeDoc::LIVRE,
+              'id_origine' => $id_origine,
+              'statut_exemplaires' => ['nb_ex' => 1],
+              'exemplaires' => [ [ 'code_barres' => $bar_code ] ]];
+
+    $finder = new Class_Notice_DoubleFinder($datas, 1, 99);
+
+    $this->assertTrue($finder->find());
+    $this->assertEquals(99, $finder->getId());
+    $this->assertEquals(Class_Notice_DoubleFinder_Strategy::FOUND_ON_BARCODE,
+                        $finder->getMatchedCriteria());
+  }
+
+
+  /** @test */
+  public function shouldNotFindExistingAlphaKeyOfSameDoctypeInSameLibrary() {
+    $alpha_key = 'UNEFAMILLEANGLAISE--WALSHH--FLAMMARION-2011-1';
+
+    $this->fixture('Class_Notice',
+                   ['id' => 99,
+                    'type_doc' => Class_TypeDoc::LIVRE,
+                    'clef_alpha' => $alpha_key]);
+
+    $id_origine = 'any:oai:server:883987228';
+    $bar_code = md5($id_origine);
+    $datas = ['type_doc' => Class_TypeDoc::LIVRE,
+              'id_origine' => $id_origine,
+              'statut_exemplaires' => ['nb_ex' => 1],
+              'exemplaires' => [ [ 'code_barres' => $bar_code ] ]];
+
+    $finder = new Class_Notice_DoubleFinder($datas, 1, 99);
+
+    $this->assertFalse($finder->find());
+  }
 }
\ No newline at end of file
diff --git a/tests/library/Class/WebService/LastfmTest.php b/tests/library/Class/WebService/LastfmTest.php
index 32c6f89d6d96d4ffe1f3103fc89e6b7a2e759942..09b96a4afb5c8713c0995c3556b8e281a9a6b235 100644
--- a/tests/library/Class/WebService/LastfmTest.php
+++ b/tests/library/Class/WebService/LastfmTest.php
@@ -117,6 +117,9 @@ class LastFmGetMorceauxUnpluggedClaptonIntegrationTest extends ModelTestCase {
 
 
 class LastfmGetPhotosRageAgainstTheMachineTest extends ModelTestCase {
+  protected $_storm_default_to_volatile = true;
+
+
   public function setUp() {
     parent::setUp();
     $lastfm = new Class_WebService_Lastfm();
diff --git a/tests/library/ZendAfi/View/Helper/Accueil/CalendarTest.php b/tests/library/ZendAfi/View/Helper/Accueil/CalendarTest.php
index 3d721cc059589220f2a8432f214b20dda19f7f02..3a5e2cf2e35245824292ac89439b1fe9811b979b 100644
--- a/tests/library/ZendAfi/View/Helper/Accueil/CalendarTest.php
+++ b/tests/library/ZendAfi/View/Helper/Accueil/CalendarTest.php
@@ -471,38 +471,41 @@ class CalendarWithCategoryLimitAndBibPreferencesTest extends CalendarViewHelperT
 
     $this->params = array('division' => '2',
                           'type_module' => 'CALENDAR',
-                          'preferences' => array('titre' => 'Concerts !',
-                                                 'rss_avis' => '0',
-                                                 'id_categorie' => '12-3',
-                                                 'display_cat_select' => '',
-                                                 'display_event_info' => 'bib',
-                                                 'display_date' => '2011-03-17'));
+                          'preferences' => ['titre' => 'Concerts !',
+                                            'rss_avis' => '0',
+                                            'id_categorie' => '12-3',
+                                            'display_cat_select' => '',
+                                            'display_event_info' => 'bib',
+                                            'display_order' => 'DebutPublicationDesc',
+                                            'display_date' => '2011-03-17']);
     $helper = new ZendAfi_View_Helper_Accueil_Calendar(2, $this->params);
     $helper->setView(new ZendAfi_Controller_Action_Helper_View());
 
     Storm_Test_ObjectWrapper::onLoaderOfModel('Class_Article')
       ->whenCalled('getArticlesByPreferences')
-      ->with(array(
-                   'display_order' => 'EventDebut',
-                   'id_categorie' => '12-3',
-                   'event_date' => '2011-03',
-                   'id_bib' => 5,
-                   'id_lieu' => '',
-                   'custom_fields' => [],
-                   'events_only' => true,
-                   'published' => false))
-      ->answers(array($this->nanook2, $this->opac4, $this->amber))
+      ->with([
+              'display_order' => 'DebutPublicationDesc',
+              'id_categorie' => '12-3',
+              'event_date' => '2011-03',
+              'id_bib' => 5,
+              'id_lieu' => '',
+              'custom_fields' => [],
+              'events_only' => true,
+              'published' => false
+              ])
+      ->answers([$this->nanook2, $this->opac4, $this->amber])
       ->whenCalled('getArticlesByPreferences')
-      ->with(array(
-                   'display_order' => 'EventDebut',
-                   'id_categorie' => '12-3',
-                   'events_only' => true,
-                   'event_date' => '2011-03-17',
-                   'id_bib' => 5,
-                   'id_lieu' => '',
-                   'custom_fields' => [],
-                   'published' => false))
-      ->answers(array($this->nanook2, $this->opac4, $this->amber))
+      ->with([
+              'display_order' => 'DebutPublicationDesc',
+              'id_categorie' => '12-3',
+              'events_only' => true,
+              'event_date' => '2011-03-17',
+              'id_bib' => 5,
+              'id_lieu' => '',
+              'custom_fields' => [],
+              'published' => false
+              ])
+      ->answers([$this->nanook2, $this->opac4, $this->amber])
 
       ->beStrict();
 
diff --git a/tests/library/ZendAfi/View/Helper/Notice/VignetteTest.php b/tests/library/ZendAfi/View/Helper/Notice/VignetteTest.php
index add9ab700f150d6eed65206e706b606fa42b01c7..2ac8be2e7c1bbd8f75b5726bcd9f920674000c8b 100644
--- a/tests/library/ZendAfi/View/Helper/Notice/VignetteTest.php
+++ b/tests/library/ZendAfi/View/Helper/Notice/VignetteTest.php
@@ -50,39 +50,79 @@ class ZendAfi_View_Helper_Notice_VignetteNoThumbnailTest
   }
 
 
+  protected function _setupRecordWithThumbnailUrl($thumbnail_url) {
+    Class_Profil::getCurrentProfil()->setModulePreference('recherche',
+                                                          'viewnotice1',
+                                                          'thumbnail_fields',
+                                                          '859-u');
+
+    return $this
+      ->fixture('Class_Notice',
+                ['id' => 42,
+                 'type_doc' => 1,
+                 'titre_principal' => 'Never Giveup',
+                 'url_vignette' => Class_WebService_Vignette::NO_DATA,
+                 'url_image' => Class_WebService_Vignette::NO_DATA,
+                ])
+      ->set_subfield('859', 'u', $thumbnail_url);
+  }
+
+
   /** @test */
   public function withThumbnailZoneAndUrlInUnimarcViewnoticeShouldContainsThumbnail() {
-    $record = $this->fixture('Class_Notice',
-                             ['id' => 42,
-                              'type_doc' => 1,
-                              'titre_principal' => 'Never Giveup',
-                              'url_vignette' => Class_WebService_Vignette::NO_DATA,
-                              'url_image' => Class_WebService_Vignette::NO_DATA,
-                              ]);
-    $record->set_subfield('859', 'u', 'https://epicpics.org/7bxDlg.png');
-
-    Class_Profil::getCurrentProfil()
-      ->setModulePreference('recherche', 'viewnotice1', 'thumbnail_fields', '859-u');
-
+    $record = $this->_setupRecordWithThumbnailUrl('https://epicpics.org/7bxDlg.png');
     $html = $this->_helper->notice_Vignette($record, [], 'view');
     $this->assertXPath($html, '//img[@src="https://epicpics.org/7bxDlg.png"]', $html);
   }
 
 
+  public function invalidThumbnailUrls() {
+    return [
+            ['https://bloub.org/7364?zork=glub'],
+            ['http://boom.org/index.html'],
+            ['http://image-cache.org/34.jpg.2'],
+    ];
+  }
+
+
+  /**
+   * @dataProvider invalidThumbnailUrls
+   * @test
+   */
+  public function withThumbnailZoneAndInvalidUrlInUnimarcViewnoticeShouldNotContainsThumbnailButBlank($url) {
+    $record = $this->_setupRecordWithThumbnailUrl($url);
+    $html = $this->_helper->notice_Vignette($record, [], 'view');
+    $this->assertXPath($html, '//img[contains(@src, "public/admin/images/blank.gif")]', $html);
+  }
+
+
+  public function validThumbnailUrls() {
+    return [
+            ['https://koha.somewhere.com/cgi-bin/koha/opac-image.pl?thumbnail=1&biblionumber=261990'],
+            ['http://www.adav-assoc.com/4DACTION/GetImage/207155'],
+            ['http://image-cache.org/34.png'],
+            ['http://image-cache.org/34.gif'],
+            ['http://image-cache.org/34.jpeg'],
+            ['http://image-cache.org/34.jPg'],
+            ['http://www.adAv-Assoc.com/4DACTION/GetImage/207155']
+    ];
+  }
+
+
+  /**
+   * @dataProvider validThumbnailUrls
+   * @test
+   */
+  public function withThumbnailZoneAndValidUrlInUnimarcViewnoticeShouldContainsThumbnail($url) {
+    $record = $this->_setupRecordWithThumbnailUrl($url);
+    $html = $this->_helper->notice_Vignette($record, [], 'view');
+    $this->assertXPath($html, '//img[@src="' . $url . '"]', $html);
+  }
+
+
   /** @test */
   public function withThumbnailZoneAndUrlInUnimarcResultAndNoDataShouldTryToRegenerateThumbnailInAjax() {
-    $record = $this->fixture('Class_Notice',
-                             ['id' => 42,
-                              'type_doc' => 1,
-                              'titre_principal' => 'Never Giveup',
-                              'url_vignette' => Class_WebService_Vignette::NO_DATA,
-                              'url_image' => Class_WebService_Vignette::NO_DATA,
-                              ]);
-    $record->set_subfield('859', 'u', 'https://epicpics.org/7bxDlg.png');
-
-    Class_Profil::getCurrentProfil()
-      ->setModulePreference('recherche', 'viewnotice1', 'thumbnail_fields', '859-u');
-
+    $record = $this->_setupRecordWithThumbnailUrl('https://epicpics.org/7bxDlg.png');
     $html = $this->_helper->notice_Vignette($record);
     $this->assertXPath($html, '//img[contains(@src, "/recherche/vignette/clef/")]', $html);
   }
diff --git a/tests/scenarios/HandleOnholdTest/HandleOnholdTest.php b/tests/scenarios/HandleOnholdTest/HandleOnholdTest.php
index 5f7712528f9ae3a9bafb300734a207f90414b3de..fa33a5b0e172e68ca372e7a42e5804d5b93dbd21 100644
--- a/tests/scenarios/HandleOnholdTest/HandleOnholdTest.php
+++ b/tests/scenarios/HandleOnholdTest/HandleOnholdTest.php
@@ -246,7 +246,7 @@ abstract class HandleOnholdDispatchTestCase extends HandleOnholdTestCase {
   /** @test */
   public function pagerShouldBeDisplay() {
     $this->dispatch('/opac/abonne/prets/onhold/yes', true);
-    $this->assertXPath('//div[@class="pager model_table_pager"]');
+    $this->assertXPath('//div[contains(@class,"pager model_table_pager")]');
   }
 }
 
diff --git a/tests/scenarios/PnbDilicom/PnbDilicomTest.php b/tests/scenarios/PnbDilicom/PnbDilicomTest.php
index 3cd2f52aa99fcb829847ac83786bde61836a137d..4750bd9a730699bfe18b4d990143e0f02ee57f7e 100644
--- a/tests/scenarios/PnbDilicom/PnbDilicomTest.php
+++ b/tests/scenarios/PnbDilicom/PnbDilicomTest.php
@@ -3177,8 +3177,8 @@ class PnbDilicomAdminAlbumControllerImportDilicomPaginatorTest extends PnbDilico
 
 
   /** @test */
-  public function contextShouldExpectation() {
-    $this->assertXPathContentContains('//div[@class="pager model_table_pager"]', '1', $this->_response->getBody());
+  public function pageShouldContainsPager() {
+    $this->assertXPathContentContains('//div[contains(@class,"pager model_table_pager")]', '1', $this->_response->getBody());
   }