diff --git a/VERSIONS b/VERSIONS
index 07e6b877d0a2b6cb6945c9313716d9b0308bb2ed..62349358b06ba59e08051218ce1bb87729eff0df 100644
--- a/VERSIONS
+++ b/VERSIONS
@@ -1,3 +1,14 @@
+25/10/2018 - v7.12.41
+
+ - ticket #80536 : Recherche avancée : prise en compte du mix des axes de recherches avec des facettes dynamiques
+ 
+ - ticket #80939 : Recherche : la sélection multiple de notices par page prend correctement en compte la taille de page par défaut définie dans les options du résultat de recherche
+
+ - ticket #80953 : SIGB Nanook > 4.1 : prend en charge les étalons au format UTF-8
+ 
+ - ticket #81002 : SIGB Dynix / Plaine Centrale: mise à jour des adresses mails pour la réception de demandes de réservations
+
+
 23/10/2018 - v7.12.40
 
  - ticket #80530 : Recherche : Possibilité d'indexer tout champ unimarc pour la recherche simple
diff --git a/VERSIONS_HOTLINE/80536 b/VERSIONS_HOTLINE/80536
new file mode 100644
index 0000000000000000000000000000000000000000..c9b680cad7012f81c4691b97d6041e446951b00d
--- /dev/null
+++ b/VERSIONS_HOTLINE/80536
@@ -0,0 +1 @@
+ - ticket #80536 : Affine le resultat de recherche multicritères: différencie les thésauri
\ No newline at end of file
diff --git a/VERSIONS_HOTLINE/81053 b/VERSIONS_HOTLINE/81053
new file mode 100644
index 0000000000000000000000000000000000000000..ce205cdec695d14ee5ed63d42818a9e9f9579a03
--- /dev/null
+++ b/VERSIONS_HOTLINE/81053
@@ -0,0 +1 @@
+ - ticket #81053 : Connecteur Skilleos : suppression automatique des albmus n'étant plus fournis
\ No newline at end of file
diff --git a/VERSIONS_HOTLINE/81124 b/VERSIONS_HOTLINE/81124
new file mode 100644
index 0000000000000000000000000000000000000000..45f3dba511fc5f910b9fcb615724886fbaf64b02
--- /dev/null
+++ b/VERSIONS_HOTLINE/81124
@@ -0,0 +1 @@
+ - ticket #81124 : Cosmogramme : correction de la précision du calcul des tailles minimum des fichiers à intégrer
\ No newline at end of file
diff --git a/VERSIONS_HOTLINE/81317 b/VERSIONS_HOTLINE/81317
new file mode 100644
index 0000000000000000000000000000000000000000..28c9c28e2cdb1b513ea66e1299e1fc0e8d820a07
--- /dev/null
+++ b/VERSIONS_HOTLINE/81317
@@ -0,0 +1 @@
+ - ticket #81317 : Page notice : prise en compte de la feuille de style XSLT pour les périodiques
\ No newline at end of file
diff --git a/application/modules/opac/controllers/NoticeajaxController.php b/application/modules/opac/controllers/NoticeajaxController.php
index 6563d0e58837c893bb29cec19b0ec8e6c57a4f60..748afc908e7ca8a7f034a5047843d41c98c7127e 100644
--- a/application/modules/opac/controllers/NoticeajaxController.php
+++ b/application/modules/opac/controllers/NoticeajaxController.php
@@ -154,17 +154,17 @@ class NoticeAjaxController extends Zend_Controller_Action {
       return;
     }
 
+    $xsl = (new Class_Notice_Xsl($notice, Class_Profil::getCurrentProfil()));
+    if ($xsl->isEnabled())
+      return $this->_sendResponseWithScripts($this->view->Notice_Xsl($xsl));
+
     if ($notice->isPeriodique()) {
       $periodiques = $this->notice->getArticlesPeriodique($this->id_notice);
-      $this->_sendResponseWithScripts($this->notice_html->getArticlesPeriodique($periodiques));
-      return;
+      return $this->_sendResponseWithScripts($this->notice_html->getArticlesPeriodique($periodiques));
     }
 
-    $xsl = (new Class_Notice_Xsl($notice, Class_Profil::getCurrentProfil()));
-    $html = $xsl->isEnabled()
-      ? $this->view->Notice_Xsl($xsl)
-      : $this->view->notice_Entete($notice, ['entete' => Class_Codification::CHAMPS]);
 
+    $html = $this->view->notice_Entete($notice, ['entete' => Class_Codification::CHAMPS]);
     $this->_sendResponseWithScripts($html);
   }
 
diff --git a/application/modules/opac/controllers/RechercheController.php b/application/modules/opac/controllers/RechercheController.php
index 86188d06a74153d603f06d076e68f1de217d9d61..03b098d8deded4330a6c7e948e1d0f272ced217b 100644
--- a/application/modules/opac/controllers/RechercheController.php
+++ b/application/modules/opac/controllers/RechercheController.php
@@ -87,16 +87,8 @@ class RechercheController extends ZendAfi_Controller_Action {
       unset($params['q']);
     }
 
-    if($dynamic_facets = $this->_extractDynamicFacets($params) ) {
-      $url = $this->newCriteresRecherches($params)
-                  ->getUrlWithMultifacetsUpdate($dynamic_facets);
-      return $this->_redirect($this->view->url($url,
-                                               null,
-                                               true),
-                              ['prependBase' => false]);
-    }
-
-    if ($multifacets = $this->_extractMultifacetsPost()) {
+    if ($multifacets = array_merge($this->_extractDynamicFacets($params),
+                                   $this->_extractMultifacetsPost())) {
       $url = $this->newCriteresRecherches($params)
                   ->getUrlWithMultifacetsUpdate($multifacets);
       $this->_redirect($this->view->url($url, null, true),
@@ -193,7 +185,7 @@ class RechercheController extends ZendAfi_Controller_Action {
   protected function _extractMultifacetsPost() {
     return $this->_request->isPost()
       ? ZendAfi_View_Helper_Facettes::extractMultiFacets($this->_request->getPost())
-      : null;
+      : [];
   }
 
 
diff --git a/cosmogramme/php/fonctions/fonctions_base.php b/cosmogramme/php/fonctions/fonctions_base.php
index 3105d7ae374ea396c1ff245fcfde29825900e727..b70ea8ed994477b64bca266e20fbca521d7bb999 100644
--- a/cosmogramme/php/fonctions/fonctions_base.php
+++ b/cosmogramme/php/fonctions/fonctions_base.php
@@ -16,7 +16,7 @@
  *
  * 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
  */
 //////////////////////////////////////////////////////////////////////////////
 //   FONCTIONS DE BASE
@@ -43,9 +43,9 @@ function lireConfig($fic)
 	}
 	return $cfg;
 }
-// ---------------------------------------------------	
+// ---------------------------------------------------
 // Clef se securite
-// ---------------------------------------------------	
+// ---------------------------------------------------
 function getClefSecurite()
 {
 	$clef="IMG".date("DxzxYxM")."VIG";
@@ -83,52 +83,4 @@ function rendBouton($libelle,$script,$arguments,$confirmation="")
 	return $url;
 }
 
-///////////////////////////////////////////////////////////////////////////////////////
-// DEBUG
-///////////////////////////////////////////////////////////////////////////////////////
-
-// Affiche le contenu d'un tableau
-function dump_array( $tableau)
-{
-	print( "<br><br><big><b>Tableau</b></big>");
-	print("<br><br><pre>");
-	print_r($tableau);
-	print("</pre><br><br>");
-}
-function dump_var($texte)
-{
-	print(htmlspecialchars($texte));
-}
-function dump_ascii($chaine)
-{
-	for($i=0;$i<strlen($chaine);$i++)
-	{
-		$car=strmid($chaine,$i,1);
-		print("CHAR=".$car."=".ord($car).BR);
-	}
-}
-function traceDebug($trace=false,$exit=false)
-{
-	// Script et fonction
-	$stack=debug_backtrace();
-	$lig=$stack[1];
-	print('<div class="trace_debug">');
-	if($niveau==100) dump_array($stack);
-	else
-	{
-		print("<b>Script : </b>". $lig["file"]);
-		print(" - <b>Ligne : </b>". $lig["line"]);
-		if($lig["class"]) print(" - <b>Classe : </b>". $lig["class"]);
-		print(" - <b>Fonction : </b>". $lig["function"].BR);
-		// Données
-		if($trace)
-		{
-			if(gettype($trace) == "array") dump_array($trace);
-			else print('<b>Message : </b>'.$trace.BR);
-		}
-	}
-	print('</div>');
-	flush();
-	if($exit == true) exit;
-}
 ?>
\ No newline at end of file
diff --git a/cosmogramme/php/fonctions/sql.php b/cosmogramme/php/fonctions/sql.php
index 1d8c0618bf5540e96ebb0aa96be4c9b06be8817b..479ca335dd324115850ca31d3c6498e72c44ca90 100644
--- a/cosmogramme/php/fonctions/sql.php
+++ b/cosmogramme/php/fonctions/sql.php
@@ -16,7 +16,7 @@
  *
  * 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
  */
 //////////////////////////////////////////////////////////////////////////////////////////
 // OPAC3 - Fonctions sql simplifi�es
@@ -58,23 +58,6 @@ function fetchAll($req,$num=false)
 	return $sql->fetchAll($req,$num);
 }
 
-// ---------------------------------------------------
-// Renvoie un where a partir d'un array de conditions
-// ---------------------------------------------------
-function getWhereSql($conditions)
-{
-	if(!$conditions) return "";
-	if(gettype($conditions)=="string") $conditions[0]=$conditions;
-	foreach($conditions as $condition)
-	{
-		if(!trim($condition)) continue;
-		if($where) $where.=" and ";
-		$where.=$condition;
-	}
-	if(!$where) return "";
-	$where=" where ".$where;
-	return $where;
-}
 
 // ---------------------------------------------------
 // Requete update
@@ -93,13 +76,3 @@ function sqlInsert($table,$data)
 	global $sql;
 	return $sql->insert($table,$data);
 }
-// ---------------------------------------------------
-// Renvoie une clause limt sql
-// ---------------------------------------------------
-function getLimitSql($nb_par_page,$page)
-{
-	if(!$page) $page=1;
-	$limit = ($page-1) * $nb_par_page;
-	$limit = " LIMIT ".$limit.",". $nb_par_page;
-	return $limit;
-}
\ No newline at end of file
diff --git a/cosmogramme/php/fonctions/string.php b/cosmogramme/php/fonctions/string.php
index d7df060caeb0c0760ccce6b07ee21783a0c60286..15bd25cce9cb1abdc4698530e7c04bd8d318a269 100644
--- a/cosmogramme/php/fonctions/string.php
+++ b/cosmogramme/php/fonctions/string.php
@@ -16,7 +16,7 @@
  *
  * 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
  */
 //////////////////////////////////////////////////////////////////////////////////////
 //                  FONCTIONS CHAINES DE CARACTERES
@@ -51,15 +51,5 @@ function strScan( $chaine, $cherche, $posDeb=0)
 	return -1;
 }
 
-function strScanReverse( $chaine, $cherche, $pos )
-{
-	$len = strLen($cherche);
-	if( $pos == -1 ) $pos = strLen($chaine);
-	for( $i=$pos; $i>=0; $i-- )
-	{
-		if( substr( $chaine, $i, $len ) == $cherche ) return $i;
-	}
-	return -1;
-}
 
 ?>
\ No newline at end of file
diff --git a/library/Class/Cosmogramme/Generator.php b/library/Class/Cosmogramme/Generator.php
index d66e45e75a00d42ffe82b8cdb8ba2bc0b1052c34..39e8774e8eafe695c1428c6e838758db61a92a26 100644
--- a/library/Class/Cosmogramme/Generator.php
+++ b/library/Class/Cosmogramme/Generator.php
@@ -97,110 +97,16 @@ class Class_Cosmogramme_Generator {
 
 
   protected function _generateLibraries() {
-    if (!$libraries = $this->getLandingDirectory()->getLibrariesOf($this->_params['path_ftp'])) {
-      $this->logError($this->_('Étalon des bibliothèques vide'));
-      return false;
-    }
+    $libraries = $this->getLandingDirectory()->getLibrariesOf($this->_params['path_ftp']);
 
-    $this->_disableDeletedLibraries($libraries);
-    $this->_generateLibrariesEntities($libraries);
+    (new Class_Cosmogramme_Generator_LibrariesTask($this, $this->_params))->run($libraries);
     $this->_generateLibrariesBranches($libraries);
-    $this->_generatePlannedIntegrations($libraries);
+    (new Class_Cosmogramme_Generator_PlannedIntegrationsTask($this, $this->_params))->run($libraries);
 
     return true;
   }
 
 
-  protected function _disableDeletedLibraries($libraries) {
-    if ((!$ids = $this->_librariesIdsFrom($libraries))
-        || !$libs = Class_IntBib::findAllBy(['id_bib not' => $ids]))
-      return;
-
-    foreach($libs as $lib)
-      $this->_disableDeletedLibrary($lib);
-  }
-
-
-  protected function _disableDeletedLibrary($library) {
-    $library->beDisconnected()->save();
-    Class_IntMajAuto::deleteBy(['id_bib' => $library->getId()]);
-  }
-
-
-  protected function _librariesIdsFrom($datas) {
-    if (!$datas)
-      return [];
-
-    $ids = [];
-    foreach($datas as $data)
-      if ($elem = $this->_extractLibraryData($data))
-        $ids[] = $elem[0];
-
-    return $ids;
-  }
-
-
-  protected function _generateLibrariesEntities($libraries) {
-    $this->logTitle($this->_('1 - Création des bibliothèques'));
-
-    $html = '';
-    foreach ($libraries as $data)
-      $html .= $this->_generateLibrary($data);
-
-    $this->log('<div class="liste"><table class="blank">' . $html . '</table></div>');
-  }
-
-
-  protected function _generateLibrary($data) {
-    if (!$elem = $this->_extractLibraryData($data))
-      return '';
-
-    if (!$bib = Class_Cosmogramme_Generator_FixedIdBib::findFirstBy(['id_site' => $elem[0]]))
-      $bib = Class_Cosmogramme_Generator_FixedIdBib::newInstance(['ville' => $this->_params['path_ftp']]);
-
-    $bib->updateAttributes(['id_site' => $elem[0],
-                            'libelle' => trim($elem[1]),
-                            'id_zone' => 1,
-                            'visibilite' => Class_Bib::V_DATA]);
-
-    if (!$int_bib = Class_IntBib::findFirstBy(['id_bib' => $bib->getIdSite()]))
-      $int_bib = Class_IntBib::newInstance(['id_bib' => $bib->getIdSite(),
-                                            'qualite' => 5,
-                                            'sigb' => $this->_params['type_sigb'],
-                                            'planif_mode' => 'r',
-                                            'planif_jours' => '1111111']);
-
-    $int_bib->updateAttributes(['nom' => $bib->getLibelle(),
-                                'nom_court' => $bib->getLibelle()]);
-
-    $this->_generateNewLibrary($int_bib);
-
-    $int_bib->save();
-    // bib after save auto create int_bib and we need Storm::isNew
-    $bib->save();
-
-    return '<tr><td class="blank">Site n° '. $bib->getIdSite() . '</td><td class="blank">'. $bib->getLibelle() . '</td></tr>';
-  }
-
-
-  protected function _generateNewLibrary($int_bib)
-  {
-    if (!$int_bib->isNew())
-      return $int_bib;
-
-    if ($int_bib->isNanook())
-      return $int_bib
-        ->setCommSigb(Class_IntBib::COM_NANOOK)
-        ->setCommParams(serialize(['url_serveur' => $this->_params['service_nanook']]));
-
-    return $int_bib
-      ->setCommSigb(Class_IntBib::COM_PERGAME)
-      ->setCommParams(serialize(['Autoriser_docs_disponibles' => '0',
-                                 'Max_par_carte' => '3',
-                                 'Max_par_document' => '3']));
-  }
-
-
   protected function _generateLibrariesBranches($libraries) {
     if ('1' != $this->_params['creer_annexes']) {
       $this->logTitle($this->_('2 - Création des annexes'));
@@ -208,53 +114,25 @@ class Class_Cosmogramme_Generator {
       return;
     }
 
-    return (new Class_Cosmogramme_Generator_BranchesTask($this))->run($libraries);
-  }
-
-
-  protected function _generatePlannedIntegrations($libraries) {
-    $this->logTitle($this->_('3 - Programmation des intégrations'));
-
-    $html = '';
-    foreach ($libraries as $data)
-      $html .= $this->_generatePlannedIntegration($data);
-
-    $this->log('<div class="liste"><table class="blank">' . $html . '</table></div>');
-  }
-
-
-  protected function _generatePlannedIntegration($data) {
-    if (!$elem = $this->_extractLibraryData($data))
-      return '';
-
-    $id_bib = $elem[0];
-    Class_IntMajAuto::deleteBy(['id_bib' => $id_bib]);
-    return $this->getPlannedGenerator()->plan($id_bib, $this->_params['path_ftp']);
-  }
-
-
-  protected function getPlannedGenerator() {
-    return $this->isNanook()
-      ? new Class_Cosmogramme_GeneratorPlannedNanook()
-      : new Class_Cosmogramme_GeneratorPlannedPergame();
+    return (new Class_Cosmogramme_Generator_BranchesTask($this, $this->_params))->run($libraries);
   }
 
 
   protected function _generateSections() {
     $sections = $this->getLandingDirectory()->getSectionsOf($this->_params['path_ftp']);
-    return (new Class_Cosmogramme_Generator_SectionsTask($this))->run($sections);
+    return (new Class_Cosmogramme_Generator_SectionsTask($this, $this->_params))->run($sections);
   }
 
 
   protected function _generateLocations() {
     $locations = $this->getLandingDirectory()->getLocationsOf($this->_params['path_ftp']);
-    return (new Class_Cosmogramme_Generator_LocationsTask($this))->run($locations);
+    return (new Class_Cosmogramme_Generator_LocationsTask($this, $this->_params))->run($locations);
   }
 
 
   protected function _generateKinds() {
     $kinds = $this->getLandingDirectory()->getKindsOf($this->_params['path_ftp']);
-    return (new Class_Cosmogramme_Generator_KindsTask($this))->run($kinds);
+    return (new Class_Cosmogramme_Generator_KindsTask($this, $this->_params))->run($kinds);
   }
 
 
@@ -340,14 +218,6 @@ class Class_Cosmogramme_Generator {
   public function getLastError() {
     return $this->_last_error;
   }
-
-
-  protected function _extractLibraryData($data) {
-    $data = utf8_encode($data);
-		$elem = explode('|', $data);
-
-		return ($elem[0] == 'BIB_SPS_UTT') ? [] : $elem;
-  }
 }
 
 
@@ -404,190 +274,4 @@ class Class_Cosmogramme_GeneratorProfilesPergameValidator
            [102, 'Prêts Pergame', Class_IntProfilDonnees::FT_LOANS],
            [103, 'Réservations Pergame', Class_IntProfilDonnees::FT_HOLDS]];
   }
-}
-
-
-
-class Class_Cosmogramme_GeneratorPlannedAbstract {
-  use Trait_Translator, Trait_Loggable;
-
-  protected
-    $_id_bib,
-    $_id_prog,
-    $_base_path,
-    $_html = '',
-    $_records_profile,
-    $_users_profile,
-    $_loans_profile = 102,
-    $_holds_profile = 103,
-    $_item_delete = false,
-    $_holds = false,
-    $_baskets = false;
-
-  public function plan($id_bib, $base_path) {
-    $this->_id_bib = $id_bib;
-    $this->_id_prog = $id_bib * 100;
-    $this->_base_path = $base_path . DIRECTORY_SEPARATOR . 'site' . $id_bib . DIRECTORY_SEPARATOR;
-
-    $this
-      ->itemDeletion()
-      ->recordsTotal()
-      ->recordsPartial()
-      ->users()
-      ->loans()
-      ->holds()
-      ->basketsTotal()
-      ->basketsPartial();
-
-    return $this->_html;
-  }
-
-
-  protected function itemDeletion() {
-    if (!$this->_item_delete)
-      return $this;
-
-    $profile = $this->_getBarCodeProfile();
-
-    return $this->planWith('Notices - suppression d\'exemplaires',
-                           $profile->getId(),
-                           Class_IntMajAuto::OP_ITEMS_DELETION,
-                           'suppressions.txt');
-  }
-
-
-  protected function recordsTotal() {
-    return $this->planWith('Notices - import total',
-                           $this->_records_profile,
-                           Class_IntMajAuto::OP_FULL_IMPORT,
-                           'notices_total.txt');
-  }
-
-
-  protected function recordsPartial() {
-    return $this->planWith('Notices - import incrémentiel',
-                           $this->_records_profile,
-                           Class_IntMajAuto::OP_PARTIAL_IMPORT,
-                           'notices.txt');
-  }
-
-
-  protected function users() {
-    return $this->planWith('Abonnés',
-                           $this->_users_profile,
-                           Class_IntMajAuto::OP_FULL_IMPORT,
-                           'abonnes.txt');
-  }
-
-
-  protected function loans() {
-    return $this->planWith('Prêts',
-                           $this->_loans_profile,
-                           Class_IntMajAuto::OP_FULL_IMPORT,
-                           'prets.txt');
-  }
-
-
-  protected function holds() {
-    return $this->_holds
-      ? $this->planWith('Réservations', $this->_holds_profile,
-                        Class_IntMajAuto::OP_FULL_IMPORT, 'reservations.txt')
-      : $this;
-  }
-
-
-  protected function basketsTotal() {
-    if (!$this->_baskets)
-      return $this;
-
-    $profile = $this->_getBasketProfile();
-
-    return $this->planWith('Paniers - import total',
-                           $profile->getId(),
-                           Class_IntMajAuto::OP_FULL_IMPORT,
-                           'paniers_total.txt');
-  }
-
-
-  protected function basketsPartial() {
-    if (!$this->_baskets)
-      return $this;
-
-    $profile = $this->_getBasketProfile();
-
-    return $this->planWith('Paniers - import incrémentiel',
-                           $profile->getId(),
-                           Class_IntMajAuto::OP_PARTIAL_IMPORT,
-                           'paniers.txt');
-  }
-
-
-  protected function planWith($name, $profile, $type, $file) {
-    $this->_html .= '<tr><td class="blank">Site n° '. $this->_id_bib . '</td><td class="blank">' . $name . '</td></tr>';
-    $this->_id_prog++;
-    Class_IntMajAuto::newInstance(['id_bib' => $this->_id_bib,
-                                   'libelle' => $name,
-                                   'profil' => $profile,
-                                   'type_operation' => $type,
-                                   'nom_fichier' => $this->_base_path . $file,
-                                   'rang' => $this->_id_prog])
-      ->save();
-
-    return $this;
-  }
-
-
-  protected function _getBarCodeProfile() {
-    $label = 'Liste de codes-barres';
-    if ($profile = Class_IntProfilDonnees::findFirstBy(['libelle' => $label]))
-      return $profile;
-
-
-    $attributs = 'a:6:{i:0;a:7:{s:8:"type_doc";a:11:{i:0;a:3:{s:4:"code";s:1:"0";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:1;a:3:{s:4:"code";s:1:"1";s:5:"label";s:5:"am;na";s:8:"zone_995";s:0:"";}i:2;a:3:{s:4:"code";s:1:"2";s:5:"label";s:2:"as";s:8:"zone_995";s:0:"";}i:3;a:3:{s:4:"code";s:1:"3";s:5:"label";s:3:"i;j";s:8:"zone_995";s:0:"";}i:4;a:3:{s:4:"code";s:1:"4";s:5:"label";s:1:"g";s:8:"zone_995";s:0:"";}i:5;a:3:{s:4:"code";s:1:"5";s:5:"label";s:3:"l;m";s:8:"zone_995";s:0:"";}i:6;a:3:{s:4:"code";s:1:"8";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:7;a:3:{s:4:"code";s:1:"9";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:8;a:3:{s:4:"code";s:2:"10";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:9;a:3:{s:4:"code";s:3:"100";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:10;a:3:{s:4:"code";s:2:"10";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}}s:17:"champ_code_barres";s:1:"f";s:10:"champ_cote";s:1:"k";s:11:"champ_genre";s:0:"";s:13:"champ_section";s:1:"q";s:17:"champ_emplacement";s:1:"u";s:12:"champ_annexe";s:1:"a";}i:1;a:1:{s:6:"champs";s:11:"code_barres";}i:2;a:1:{s:6:"champs";s:11:"code_barres";}i:3;a:1:{s:6:"champs";s:11:"code_barres";}i:5;a:3:{s:6:"champs";s:11:"code_barres";s:17:"xml_balise_abonne";s:0:"";s:17:"xml_champs_abonne";a:10:{s:6:"IDABON";s:0:"";s:9:"ORDREABON";s:0:"";s:3:"NOM";s:0:"";s:6:"PRENOM";s:0:"";s:9:"NAISSANCE";s:0:"";s:8:"PASSWORD";s:0:"";s:4:"MAIL";s:0:"";s:10:"DATE_DEBUT";s:0:"";s:8:"DATE_FIN";s:0:"";s:7:"ID_SIGB";s:0:"";}}i:4;a:5:{s:4:"zone";s:0:"";s:5:"champ";s:0:"";s:6:"format";s:0:"";s:5:"jours";s:0:"";s:7:"valeurs";s:0:"";}}';
-
-    $profile = Class_IntProfilDonnees::newInstance(['libelle' => $label,
-                                                    'accents' => Class_IntProfilDonnees::ENCODING_UTF8,
-                                                    'type_fichier' => Class_IntProfilDonnees::FT_RECORDS,
-                                                    'format' => Class_IntProfilDonnees::FORMAT_TABBED_ASCII,
-                                                    'attributs' => $attributs]);
-    $profile->save();
-    return $profile;
-  }
-
-
-  protected function _getBasketProfile() {
-    if ($profile = Class_IntProfilDonnees::findFirstBy(['accents' => Class_IntProfilDonnees::ENCODING_UTF8,
-                                                        'type_fichier' => Class_IntProfilDonnees::FT_BASKETS,
-                                                        'format' => Class_IntProfilDonnees::FORMAT_PIPED_ASCII]))
-      return $profile;
-
-    $profile = Class_IntProfilDonnees::newInstance(['libelle' => 'Paniers Nanook',
-                                                    'accents' => Class_IntProfilDonnees::ENCODING_UTF8,
-                                                    'rejet_periodiques' => 0,
-                                                    'id_article_periodique' => 4,
-                                                    'type_fichier' => Class_IntProfilDonnees::FT_BASKETS,
-                                                    'format' => Class_IntProfilDonnees::FORMAT_PIPED_ASCII,
-                                                    'attributs' => 'a:7:{i:0;a:9:{s:8:"type_doc";a:35:{i:0;a:3:{s:4:"code";s:1:"0";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:1;a:3:{s:4:"code";s:1:"1";s:5:"label";s:8:"am;na;mn";s:8:"zone_995";s:9:"LIV;MS;uu";}i:2;a:3:{s:4:"code";s:1:"2";s:5:"label";s:2:"as";s:8:"zone_995";s:3:"PER";}i:3;a:3:{s:4:"code";s:1:"3";s:5:"label";s:3:"i;j";s:8:"zone_995";s:17:"CD;LIVCD;LIVK7;K7";}i:4;a:3:{s:4:"code";s:1:"4";s:5:"label";s:1:"g";s:8:"zone_995";s:20:"DIAPO;DVD;VHS;VHD;VD";}i:5;a:3:{s:4:"code";s:1:"5";s:5:"label";s:6:"l;m;mm";s:8:"zone_995";s:3:"CDR";}i:6;a:3:{s:4:"code";s:1:"8";s:5:"label";s:0:"";s:8:"zone_995";s:1:"D";}i:7;a:3:{s:4:"code";s:1:"9";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:8;a:3:{s:4:"code";s:1:"8";s:5:"label";s:0:"";s:8:"zone_995";s:3:"DOS";}i:9;a:3:{s:4:"code";s:1:"9";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:10;a:3:{s:4:"code";s:2:"10";s:5:"label";s:0:"";s:8:"zone_995";s:6:"WEB;MF";}i:11;a:3:{s:4:"code";s:3:"102";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:12;a:3:{s:4:"code";s:3:"103";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:13;a:3:{s:4:"code";s:3:"104";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:14;a:3:{s:4:"code";s:3:"105";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:15;a:3:{s:4:"code";s:3:"106";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:16;a:3:{s:4:"code";s:3:"107";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:17;a:3:{s:4:"code";s:3:"108";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:18;a:3:{s:4:"code";s:3:"100";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:19;a:3:{s:4:"code";s:3:"101";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:20;a:3:{s:4:"code";s:3:"102";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:21;a:3:{s:4:"code";s:3:"103";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:22;a:3:{s:4:"code";s:3:"104";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:23;a:3:{s:4:"code";s:3:"105";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:24;a:3:{s:4:"code";s:3:"106";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:25;a:3:{s:4:"code";s:3:"107";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:26;a:3:{s:4:"code";s:3:"108";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:27;a:3:{s:4:"code";s:3:"109";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:28;a:3:{s:4:"code";s:3:"111";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:29;a:3:{s:4:"code";s:3:"110";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:30;a:3:{s:4:"code";s:3:"112";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:31;a:3:{s:4:"code";s:3:"114";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:32;a:3:{s:4:"code";s:3:"113";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:33;a:3:{s:4:"code";s:3:"115";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:34;a:3:{s:4:"code";s:3:"116";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}}s:17:"champ_code_barres";s:1:"a";s:10:"champ_cote";s:1:"f";s:14:"champ_type_doc";s:0:"";s:11:"champ_genre";s:1:"#";s:13:"champ_section";s:1:"w";s:17:"champ_emplacement";s:1:"x";s:12:"champ_annexe";s:1:"h";s:9:"champ_url";a:2:{s:4:"zone";s:0:"";s:5:"champ";s:0:"";}}i:1;a:1:{s:6:"champs";s:47:"ID_SIGB;LIBELLE;IDABON;MAIL;ROLE;ID_NOTICE_SIGB";}i:2;a:1:{s:6:"champs";s:47:"ID_SIGB;LIBELLE;IDABON;MAIL;ROLE;ID_NOTICE_SIGB";}i:3;a:1:{s:6:"champs";s:47:"ID_SIGB;LIBELLE;IDABON;MAIL;ROLE;ID_NOTICE_SIGB";}i:5;a:3:{s:6:"champs";s:47:"ID_SIGB;LIBELLE;IDABON;MAIL;ROLE;ID_NOTICE_SIGB";s:17:"xml_balise_abonne";s:0:"";s:17:"xml_champs_abonne";a:11:{s:6:"IDABON";s:0:"";s:9:"ORDREABON";s:0:"";s:3:"NOM";s:0:"";s:6:"PRENOM";s:0:"";s:9:"NAISSANCE";s:0:"";s:8:"PASSWORD";s:0:"";s:4:"MAIL";s:0:"";s:10:"DATE_DEBUT";s:0:"";s:8:"DATE_FIN";s:0:"";s:7:"ID_SIGB";s:0:"";s:9:"NUM_CARTE";s:0:"";}}i:4;a:5:{s:4:"zone";s:3:"995";s:5:"champ";s:1:"5";s:6:"format";s:1:"3";s:5:"jours";s:0:"";s:7:"valeurs";s:1:"1";}i:6;a:2:{s:4:"zone";s:0:"";s:5:"champ";s:0:"";}}']);
-    $profile->save();
-    return $profile;
-  }
-}
-
-
-
-class Class_Cosmogramme_GeneratorPlannedNanook extends Class_Cosmogramme_GeneratorPlannedAbstract{
-  protected
-    $_records_profile = 104,
-    $_users_profile = 105,
-    $_item_delete = true,
-    $_baskets = true;
-}
-
-
-
-class Class_Cosmogramme_GeneratorPlannedPergame extends Class_Cosmogramme_GeneratorPlannedAbstract{
-  protected
-    $_records_profile = 100,
-    $_users_profile = 101,
-    $_holds = true;
-}
+}
\ No newline at end of file
diff --git a/library/Class/Cosmogramme/Generator/AbstractTask.php b/library/Class/Cosmogramme/Generator/AbstractTask.php
index 8453a77b453353d0a75d84acd0630d8a04f76dcb..1d7c57a8cfa5db3672cd14240df83e41400ec14d 100644
--- a/library/Class/Cosmogramme/Generator/AbstractTask.php
+++ b/library/Class/Cosmogramme/Generator/AbstractTask.php
@@ -41,8 +41,9 @@ abstract class Class_Cosmogramme_Generator_AbstractTask {
   }
 
 
-  public function __construct($generator) {
+  public function __construct($generator, $params) {
     $this->_generator = $generator;
+    $this->_params = $params;
   }
 
 
@@ -69,17 +70,22 @@ abstract class Class_Cosmogramme_Generator_AbstractTask {
 
 
   protected function _runOne($data) {
-    $data = utf8_encode($data);
-    $elems = explode('|', $data);
-
+    $elems = $this->_extract($data);
     if ($this->_isExcluded($elems))
       return '';
 
     $model = $this->_getOrCreate($elems);
-    $model->setDateMaj($this->_date)
-          ->save();
+    $model->save();
+
+    return $this->renderOne($elems, $model);
+  }
+
 
-    return $this->renderOne($elems);
+  protected function _extract($data) {
+    return explode('|',
+                   mb_detect_encoding($data, 'UTF-8', true)
+                   ? $data
+                   : utf8_encode($data));
   }
 
 
@@ -91,7 +97,9 @@ abstract class Class_Cosmogramme_Generator_AbstractTask {
     if (!$model = $model_class::findFirstBy(['libelle' => $label]))
       $model = $model_class::newInstance(['libelle' => $label]);
 
-    return $model->setRegles($this->_createOrConcatRules($code, $model));
+    return
+      $model->setDateMaj($this->_date)
+            ->setRegles($this->_createOrConcatRules($code, $model));
   }
 
 
@@ -168,7 +176,7 @@ abstract class Class_Cosmogramme_Generator_AbstractTask {
   }
 
 
-  protected function renderOne($elems) {
+  protected function renderOne($elems, $model) {
     return '<tr><td class="blank">' . $this->getCode($elems)
       . '</td><td class="blank">' . $this->getLabel($elems) . '</td></tr>';
   }
diff --git a/library/Class/Cosmogramme/Generator/BranchesTask.php b/library/Class/Cosmogramme/Generator/BranchesTask.php
index 9f7fc36f35110365ed7976496edc88a105109ae2..44863ef2d57f141d540a97976f5ae393c94560ce 100644
--- a/library/Class/Cosmogramme/Generator/BranchesTask.php
+++ b/library/Class/Cosmogramme/Generator/BranchesTask.php
@@ -30,12 +30,12 @@ class Class_Cosmogramme_Generator_BranchesTask
     $_model_class = 'Class_CodifAnnexe';
 
   protected function _getOrCreate($elems) {
-    return ($model = Class_CodifAnnexe::findFirstBy(['id_origine' => $elems[0]]))
-      ? $model
-      : Class_CodifAnnexe::newInstance(['id_bib' => $elems[0],
-                                        'id_origine' => $elems[0],
-                                        'libelle' => trim($elems[1]),
-                                        'invisible' => 0]);
+    if (!$model = Class_CodifAnnexe::findFirstBy(['id_origine' => $elems[0]]))
+      $model = Class_CodifAnnexe::newInstance(['id_bib' => $elems[0],
+                                               'id_origine' => $elems[0],
+                                               'libelle' => trim($elems[1]),
+                                               'invisible' => 0]);
+    return $model->setDateMaj($this->_date);
   }
 
 
diff --git a/library/Class/Cosmogramme/Generator/KindsTask.php b/library/Class/Cosmogramme/Generator/KindsTask.php
index 4c4e40b4ba67fecee3ef55d20047a7c6011e2b4e..416ddd21d3dfaedf8b5bea4cccf3c5f09f161226 100644
--- a/library/Class/Cosmogramme/Generator/KindsTask.php
+++ b/library/Class/Cosmogramme/Generator/KindsTask.php
@@ -67,7 +67,7 @@ class Class_Cosmogramme_Generator_KindsTask extends Class_Cosmogramme_Generator_
       ->setDateMaj($this->_date)
       ->save();
 
-    return $this->renderOne([$codes, $label]);
+    return $this->renderOne([$codes, $label], $model);
   }
 
 
diff --git a/library/Class/Cosmogramme/Generator/LibrariesTask.php b/library/Class/Cosmogramme/Generator/LibrariesTask.php
new file mode 100644
index 0000000000000000000000000000000000000000..bc1f6523f04ae9d045bb0fea5e98a6acacca9715
--- /dev/null
+++ b/library/Class/Cosmogramme/Generator/LibrariesTask.php
@@ -0,0 +1,118 @@
+<?php
+/**
+ * Copyright (c) 2012-2014, 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_Cosmogramme_Generator_LibrariesTask extends Class_Cosmogramme_Generator_AbstractTask {
+  protected
+    $_index = 1,
+    $_name = 'bibliothèques';
+
+
+  protected function _isExcluded($elems) {
+    return 'BIB_SPS_UTT' == $elems[0] || !trim($elems[0]);
+  }
+
+
+  protected function _prepare($libraries) {
+    $this->_disableDeletedLibraries($libraries);
+    return $libraries;
+  }
+
+
+  protected function _disableDeletedLibraries($libraries) {
+    if ((!$ids = $this->_librariesIdsFrom($libraries))
+        || !$libs = Class_IntBib::findAllBy(['id_bib not' => $ids]))
+      return;
+
+    foreach($libs as $lib)
+      $this->_disableDeletedLibrary($lib);
+  }
+
+
+  protected function _getOrCreate($elems) {
+    if (!$bib = Class_Cosmogramme_Generator_FixedIdBib::findFirstBy(['id_site' => $elems[0]]))
+      $bib = Class_Cosmogramme_Generator_FixedIdBib::newInstance(['ville' => $this->_params['path_ftp']]);
+
+    $bib->updateAttributes(['id_site' => $elems[0],
+                            'libelle' => trim($elems[1]),
+                            'id_zone' => 1,
+                            'visibilite' => Class_Bib::V_DATA]);
+
+    if (!$int_bib = Class_IntBib::findFirstBy(['id_bib' => $bib->getIdSite()]))
+      $int_bib = Class_IntBib::newInstance(['id_bib' => $bib->getIdSite(),
+                                            'qualite' => 5,
+                                            'sigb' => $this->_params['type_sigb'],
+                                            'planif_mode' => 'r',
+                                            'planif_jours' => '1111111']);
+
+    $int_bib->updateAttributes(['nom' => $bib->getLibelle(),
+                                'nom_court' => $bib->getLibelle()]);
+
+    $this->_generateNewLibrary($int_bib);
+
+    $int_bib->save();
+    return $bib;
+  }
+
+
+  protected function _generateNewLibrary($int_bib) {
+    if (!$int_bib->isNew())
+      return $int_bib;
+
+    if ($int_bib->isNanook())
+      return $int_bib
+        ->setCommSigb(Class_IntBib::COM_NANOOK)
+        ->setCommParams(serialize(['url_serveur' => $this->_params['service_nanook']]));
+
+    return $int_bib
+      ->setCommSigb(Class_IntBib::COM_PERGAME)
+      ->setCommParams(serialize(['Autoriser_docs_disponibles' => '0',
+                                 'Max_par_carte' => '3',
+                                 'Max_par_document' => '3']));
+  }
+
+
+  protected function renderOne($elems, $bib) {
+    return '<tr><td class="blank">Site n° '. $bib->getIdSite() . '</td><td class="blank">'. $bib->getLibelle() . '</td></tr>';
+  }
+
+
+  protected function _disableDeletedLibrary($library) {
+    $library->beDisconnected()->save();
+    Class_IntMajAuto::deleteBy(['id_bib' => $library->getId()]);
+  }
+
+
+  protected function _librariesIdsFrom($datas) {
+    if (!$datas)
+      return [];
+
+    $ids = [];
+    foreach($datas as $data)
+      if ($elem = $this->_extract($data))
+        $ids[] = $elem[0];
+
+    return $ids;
+  }
+
+
+  protected function _removeDeleted() {
+  }
+}
\ No newline at end of file
diff --git a/library/Class/Cosmogramme/Generator/PlannedIntegrationsTask.php b/library/Class/Cosmogramme/Generator/PlannedIntegrationsTask.php
new file mode 100644
index 0000000000000000000000000000000000000000..e700d9567c7a9ec3f6da3ff562095f819f641b37
--- /dev/null
+++ b/library/Class/Cosmogramme/Generator/PlannedIntegrationsTask.php
@@ -0,0 +1,247 @@
+<?php
+/**
+ * Copyright (c) 2012-2017, 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_Cosmogramme_Generator_PlannedIntegrationsTask
+  extends Class_Cosmogramme_Generator_AbstractTask {
+
+  protected
+    $_index = 3,
+    $_name = 'intégrations programmées',
+    $_html = '';
+
+
+  protected function _isExcluded($elems) {
+    return 'BIB_SPS_UTT' == $elems[0] || !trim($elems[0]);
+  }
+
+
+  protected function _getOrCreate($elems) {
+    $id_bib = $elems[0];
+    Class_IntMajAuto::deleteBy(['id_bib' => $id_bib]);
+
+    $this->_html = $this->getPlannedGenerator()->plan($id_bib, $this->_params['path_ftp']);
+
+    return (new Class_Entity())->whenCalledDo('save', function() { return true; } );
+  }
+
+
+  protected function renderOne($elems, $bib) {
+    return $this->_html;
+  }
+
+
+  protected function getPlannedGenerator() {
+    return $this->_generator->isNanook()
+      ? new Class_Cosmogramme_GeneratorPlannedNanook()
+      : new Class_Cosmogramme_GeneratorPlannedPergame();
+  }
+
+
+  protected function _removeDeleted() {
+  }
+}
+
+
+
+class Class_Cosmogramme_GeneratorPlannedAbstract {
+  use Trait_Translator, Trait_Loggable;
+
+  protected
+    $_id_bib,
+    $_id_prog,
+    $_base_path,
+    $_html = '',
+    $_records_profile,
+    $_users_profile,
+    $_loans_profile = 102,
+    $_holds_profile = 103,
+    $_item_delete = false,
+    $_holds = false,
+    $_baskets = false;
+
+  public function plan($id_bib, $base_path) {
+    $this->_id_bib = $id_bib;
+    $this->_id_prog = $id_bib * 100;
+    $this->_base_path = $base_path . DIRECTORY_SEPARATOR . 'site' . $id_bib . DIRECTORY_SEPARATOR;
+
+    $this
+      ->itemDeletion()
+      ->recordsTotal()
+      ->recordsPartial()
+      ->users()
+      ->loans()
+      ->holds()
+      ->basketsTotal()
+      ->basketsPartial();
+
+    return $this->_html;
+  }
+
+
+  protected function itemDeletion() {
+    if (!$this->_item_delete)
+      return $this;
+
+    $profile = $this->_getBarCodeProfile();
+
+    return $this->planWith('Notices - suppression d\'exemplaires',
+                           $profile->getId(),
+                           Class_IntMajAuto::OP_ITEMS_DELETION,
+                           'suppressions.txt');
+  }
+
+
+  protected function recordsTotal() {
+    return $this->planWith('Notices - import total',
+                           $this->_records_profile,
+                           Class_IntMajAuto::OP_FULL_IMPORT,
+                           'notices_total.txt');
+  }
+
+
+  protected function recordsPartial() {
+    return $this->planWith('Notices - import incrémentiel',
+                           $this->_records_profile,
+                           Class_IntMajAuto::OP_PARTIAL_IMPORT,
+                           'notices.txt');
+  }
+
+
+  protected function users() {
+    return $this->planWith('Abonnés',
+                           $this->_users_profile,
+                           Class_IntMajAuto::OP_FULL_IMPORT,
+                           'abonnes.txt');
+  }
+
+
+  protected function loans() {
+    return $this->planWith('Prêts',
+                           $this->_loans_profile,
+                           Class_IntMajAuto::OP_FULL_IMPORT,
+                           'prets.txt');
+  }
+
+
+  protected function holds() {
+    return $this->_holds
+      ? $this->planWith('Réservations', $this->_holds_profile,
+                        Class_IntMajAuto::OP_FULL_IMPORT, 'reservations.txt')
+      : $this;
+  }
+
+
+  protected function basketsTotal() {
+    if (!$this->_baskets)
+      return $this;
+
+    $profile = $this->_getBasketProfile();
+
+    return $this->planWith('Paniers - import total',
+                           $profile->getId(),
+                           Class_IntMajAuto::OP_FULL_IMPORT,
+                           'paniers_total.txt');
+  }
+
+
+  protected function basketsPartial() {
+    if (!$this->_baskets)
+      return $this;
+
+    $profile = $this->_getBasketProfile();
+
+    return $this->planWith('Paniers - import incrémentiel',
+                           $profile->getId(),
+                           Class_IntMajAuto::OP_PARTIAL_IMPORT,
+                           'paniers.txt');
+  }
+
+
+  protected function planWith($name, $profile, $type, $file) {
+    $this->_html .= '<tr><td class="blank">Site n° '. $this->_id_bib . '</td><td class="blank">' . $name . '</td></tr>';
+    $this->_id_prog++;
+    Class_IntMajAuto::newInstance(['id_bib' => $this->_id_bib,
+                                   'libelle' => $name,
+                                   'profil' => $profile,
+                                   'type_operation' => $type,
+                                   'nom_fichier' => $this->_base_path . $file,
+                                   'rang' => $this->_id_prog])
+      ->save();
+
+    return $this;
+  }
+
+
+  protected function _getBarCodeProfile() {
+    $label = 'Liste de codes-barres';
+    if ($profile = Class_IntProfilDonnees::findFirstBy(['libelle' => $label]))
+      return $profile;
+
+
+    $attributs = 'a:6:{i:0;a:7:{s:8:"type_doc";a:11:{i:0;a:3:{s:4:"code";s:1:"0";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:1;a:3:{s:4:"code";s:1:"1";s:5:"label";s:5:"am;na";s:8:"zone_995";s:0:"";}i:2;a:3:{s:4:"code";s:1:"2";s:5:"label";s:2:"as";s:8:"zone_995";s:0:"";}i:3;a:3:{s:4:"code";s:1:"3";s:5:"label";s:3:"i;j";s:8:"zone_995";s:0:"";}i:4;a:3:{s:4:"code";s:1:"4";s:5:"label";s:1:"g";s:8:"zone_995";s:0:"";}i:5;a:3:{s:4:"code";s:1:"5";s:5:"label";s:3:"l;m";s:8:"zone_995";s:0:"";}i:6;a:3:{s:4:"code";s:1:"8";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:7;a:3:{s:4:"code";s:1:"9";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:8;a:3:{s:4:"code";s:2:"10";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:9;a:3:{s:4:"code";s:3:"100";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:10;a:3:{s:4:"code";s:2:"10";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}}s:17:"champ_code_barres";s:1:"f";s:10:"champ_cote";s:1:"k";s:11:"champ_genre";s:0:"";s:13:"champ_section";s:1:"q";s:17:"champ_emplacement";s:1:"u";s:12:"champ_annexe";s:1:"a";}i:1;a:1:{s:6:"champs";s:11:"code_barres";}i:2;a:1:{s:6:"champs";s:11:"code_barres";}i:3;a:1:{s:6:"champs";s:11:"code_barres";}i:5;a:3:{s:6:"champs";s:11:"code_barres";s:17:"xml_balise_abonne";s:0:"";s:17:"xml_champs_abonne";a:10:{s:6:"IDABON";s:0:"";s:9:"ORDREABON";s:0:"";s:3:"NOM";s:0:"";s:6:"PRENOM";s:0:"";s:9:"NAISSANCE";s:0:"";s:8:"PASSWORD";s:0:"";s:4:"MAIL";s:0:"";s:10:"DATE_DEBUT";s:0:"";s:8:"DATE_FIN";s:0:"";s:7:"ID_SIGB";s:0:"";}}i:4;a:5:{s:4:"zone";s:0:"";s:5:"champ";s:0:"";s:6:"format";s:0:"";s:5:"jours";s:0:"";s:7:"valeurs";s:0:"";}}';
+
+    $profile = Class_IntProfilDonnees::newInstance(['libelle' => $label,
+                                                    'accents' => Class_IntProfilDonnees::ENCODING_UTF8,
+                                                    'type_fichier' => Class_IntProfilDonnees::FT_RECORDS,
+                                                    'format' => Class_IntProfilDonnees::FORMAT_TABBED_ASCII,
+                                                    'attributs' => $attributs]);
+    $profile->save();
+    return $profile;
+  }
+
+
+  protected function _getBasketProfile() {
+    if ($profile = Class_IntProfilDonnees::findFirstBy(['accents' => Class_IntProfilDonnees::ENCODING_UTF8,
+                                                        'type_fichier' => Class_IntProfilDonnees::FT_BASKETS,
+                                                        'format' => Class_IntProfilDonnees::FORMAT_PIPED_ASCII]))
+      return $profile;
+
+    $profile = Class_IntProfilDonnees::newInstance(['libelle' => 'Paniers Nanook',
+                                                    'accents' => Class_IntProfilDonnees::ENCODING_UTF8,
+                                                    'rejet_periodiques' => 0,
+                                                    'id_article_periodique' => 4,
+                                                    'type_fichier' => Class_IntProfilDonnees::FT_BASKETS,
+                                                    'format' => Class_IntProfilDonnees::FORMAT_PIPED_ASCII,
+                                                    'attributs' => 'a:7:{i:0;a:9:{s:8:"type_doc";a:35:{i:0;a:3:{s:4:"code";s:1:"0";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:1;a:3:{s:4:"code";s:1:"1";s:5:"label";s:8:"am;na;mn";s:8:"zone_995";s:9:"LIV;MS;uu";}i:2;a:3:{s:4:"code";s:1:"2";s:5:"label";s:2:"as";s:8:"zone_995";s:3:"PER";}i:3;a:3:{s:4:"code";s:1:"3";s:5:"label";s:3:"i;j";s:8:"zone_995";s:17:"CD;LIVCD;LIVK7;K7";}i:4;a:3:{s:4:"code";s:1:"4";s:5:"label";s:1:"g";s:8:"zone_995";s:20:"DIAPO;DVD;VHS;VHD;VD";}i:5;a:3:{s:4:"code";s:1:"5";s:5:"label";s:6:"l;m;mm";s:8:"zone_995";s:3:"CDR";}i:6;a:3:{s:4:"code";s:1:"8";s:5:"label";s:0:"";s:8:"zone_995";s:1:"D";}i:7;a:3:{s:4:"code";s:1:"9";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:8;a:3:{s:4:"code";s:1:"8";s:5:"label";s:0:"";s:8:"zone_995";s:3:"DOS";}i:9;a:3:{s:4:"code";s:1:"9";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:10;a:3:{s:4:"code";s:2:"10";s:5:"label";s:0:"";s:8:"zone_995";s:6:"WEB;MF";}i:11;a:3:{s:4:"code";s:3:"102";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:12;a:3:{s:4:"code";s:3:"103";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:13;a:3:{s:4:"code";s:3:"104";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:14;a:3:{s:4:"code";s:3:"105";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:15;a:3:{s:4:"code";s:3:"106";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:16;a:3:{s:4:"code";s:3:"107";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:17;a:3:{s:4:"code";s:3:"108";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:18;a:3:{s:4:"code";s:3:"100";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:19;a:3:{s:4:"code";s:3:"101";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:20;a:3:{s:4:"code";s:3:"102";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:21;a:3:{s:4:"code";s:3:"103";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:22;a:3:{s:4:"code";s:3:"104";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:23;a:3:{s:4:"code";s:3:"105";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:24;a:3:{s:4:"code";s:3:"106";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:25;a:3:{s:4:"code";s:3:"107";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:26;a:3:{s:4:"code";s:3:"108";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:27;a:3:{s:4:"code";s:3:"109";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:28;a:3:{s:4:"code";s:3:"111";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:29;a:3:{s:4:"code";s:3:"110";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:30;a:3:{s:4:"code";s:3:"112";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:31;a:3:{s:4:"code";s:3:"114";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:32;a:3:{s:4:"code";s:3:"113";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:33;a:3:{s:4:"code";s:3:"115";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:34;a:3:{s:4:"code";s:3:"116";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}}s:17:"champ_code_barres";s:1:"a";s:10:"champ_cote";s:1:"f";s:14:"champ_type_doc";s:0:"";s:11:"champ_genre";s:1:"#";s:13:"champ_section";s:1:"w";s:17:"champ_emplacement";s:1:"x";s:12:"champ_annexe";s:1:"h";s:9:"champ_url";a:2:{s:4:"zone";s:0:"";s:5:"champ";s:0:"";}}i:1;a:1:{s:6:"champs";s:47:"ID_SIGB;LIBELLE;IDABON;MAIL;ROLE;ID_NOTICE_SIGB";}i:2;a:1:{s:6:"champs";s:47:"ID_SIGB;LIBELLE;IDABON;MAIL;ROLE;ID_NOTICE_SIGB";}i:3;a:1:{s:6:"champs";s:47:"ID_SIGB;LIBELLE;IDABON;MAIL;ROLE;ID_NOTICE_SIGB";}i:5;a:3:{s:6:"champs";s:47:"ID_SIGB;LIBELLE;IDABON;MAIL;ROLE;ID_NOTICE_SIGB";s:17:"xml_balise_abonne";s:0:"";s:17:"xml_champs_abonne";a:11:{s:6:"IDABON";s:0:"";s:9:"ORDREABON";s:0:"";s:3:"NOM";s:0:"";s:6:"PRENOM";s:0:"";s:9:"NAISSANCE";s:0:"";s:8:"PASSWORD";s:0:"";s:4:"MAIL";s:0:"";s:10:"DATE_DEBUT";s:0:"";s:8:"DATE_FIN";s:0:"";s:7:"ID_SIGB";s:0:"";s:9:"NUM_CARTE";s:0:"";}}i:4;a:5:{s:4:"zone";s:3:"995";s:5:"champ";s:1:"5";s:6:"format";s:1:"3";s:5:"jours";s:0:"";s:7:"valeurs";s:1:"1";}i:6;a:2:{s:4:"zone";s:0:"";s:5:"champ";s:0:"";}}']);
+    $profile->save();
+    return $profile;
+  }
+}
+
+
+
+class Class_Cosmogramme_GeneratorPlannedNanook extends Class_Cosmogramme_GeneratorPlannedAbstract{
+  protected
+    $_records_profile = 104,
+    $_users_profile = 105,
+    $_item_delete = true,
+    $_baskets = true;
+}
+
+
+
+class Class_Cosmogramme_GeneratorPlannedPergame extends Class_Cosmogramme_GeneratorPlannedAbstract{
+  protected
+    $_records_profile = 100,
+    $_users_profile = 101,
+    $_holds = true;
+}
\ No newline at end of file
diff --git a/library/Class/Cosmogramme/Integration/PhasePrepareIntegrations.php b/library/Class/Cosmogramme/Integration/PhasePrepareIntegrations.php
index a82d99b7e37acfc32250ce1879f708670a225a15..602a1eef9ba61f9fac8ba6d788362510e298fd9a 100644
--- a/library/Class/Cosmogramme/Integration/PhasePrepareIntegrations.php
+++ b/library/Class/Cosmogramme/Integration/PhasePrepareIntegrations.php
@@ -188,19 +188,17 @@ class Class_Cosmogramme_Integration_PhasePrepareIntegrations extends Class_Cosmo
       return false;
 
     $file_type = $profil->getTypeFichier();
-    $minsize = $majauto->getTailleMinImportTotal();
+    $minsize = $majauto->getTailleMinImportTotal() * 1024 * 1024;
     $type_operation = $majauto->getTypeOperation();
 
     if ($minsize > 0 && $file_type == 0 && $type_operation == 2) {
-      $file_size = filesize($file);
-      if ($file_size > 0)
-        $file_size = (int) (($file_size / 1024) / 1024);
-
+      $file_size = $this->getFileSystem()->filesize($file);
       if ($file_size < $minsize) {
         $this->_log
           ->log(sprintf('<span class="rouge">%s</span></td>',
-                        $this->_('Le fichier est trop petit : %s mo -> taille minimum attendue : %s mo',
-                                 $file_size, $minsize)));
+                        $this->_('Le fichier est trop petit : %s o -> taille minimum attendue : %s o',
+                                 $file_size,
+                                 $minsize)));
         return false;
       }
     }
diff --git a/library/Class/MoteurRecherche.php b/library/Class/MoteurRecherche.php
index b92dd84ecfd2779825ef23256b16d07a64d2007a..50e08a9b8638d04ec397500606c644da3a97193c 100644
--- a/library/Class/MoteurRecherche.php
+++ b/library/Class/MoteurRecherche.php
@@ -230,7 +230,8 @@ class Class_MoteurRecherche {
     if (!$facet)
       return;
 
-    $code = substr($facet, 0, 1);
+    $code = (new Class_Notice_Facette($facet))->getCodeRubrique();
+
     if (!isset($this->multi_facets[$code]))
       $this->multi_facets[$code] = [];
     $this->multi_facets[$code][] = $facet;
diff --git a/library/Class/WebService/SIGB/Dynix/Service.php b/library/Class/WebService/SIGB/Dynix/Service.php
index d6f8b29c7c5981d8576096143d0e3d9cc52a0e8f..a71944ade98d0e4b63d7b48a0ddf643d1e2121e2 100644
--- a/library/Class/WebService/SIGB/Dynix/Service.php
+++ b/library/Class/WebService/SIGB/Dynix/Service.php
@@ -29,7 +29,7 @@ class Class_Webservice_SIGB_Dynix_Service extends Class_WebService_SIGB_Abstract
       'CRETMEC'=>'bibliotheque.creteil.meches@agglo-plainecentrale94.fr',
       'CRETDOY'=>'mediatheque.creteil.abbaye@agglo-plainecentrale94.fr',
       'ENMDAD'=>'',
-      'CRETHAB'=>'bibliotheque.creteil.habette@agglo-plainecentrale94.fr',
+      'CRETHAB'=>'medialudo.creteil@gpsea.fr',
       'CRETMAC'=>'bibliotheque.creteil.mac@agglo-plainecentrale94.fr',
       'CRETMUL'=>'',
       'CRETRES'=>'bibliotheque.creteil.servicesinternes@agglo-plainecentrale94.fr',
diff --git a/library/Class/Xml.php b/library/Class/Xml.php
index 131a1f4b4defbbdbc6d79d31e34fa3e343b1161b..75f509220495a96d3b6209d5c41ffce8eb9167e1 100644
--- a/library/Class/Xml.php
+++ b/library/Class/Xml.php
@@ -40,9 +40,17 @@ class Class_Xml {
   }
 
 
+  public function lire_fichier( $fic) {
+    @$handle = fopen( $fic, "r") or erreur_admin( "Impossible d'ouvrir le fichier : " .$fic );
+    $data=fread ($handle, filesize ($fic));
+    fclose($handle);
+    return $data;
+  }
+
+
   public function open_fichier($fic) {
     include_once 'fonctions/file_system.php';
-    $data = lire_fichier($fic);
+    $data = $this->lire_fichier($fic);
     $parser = xml_parser_create("ISO-8859-1");
     xml_parse_into_struct($parser, $data, $this->valeurs, $this->index);
     xml_parser_free($parser);
@@ -108,22 +116,6 @@ class Class_Xml {
   }
 
 
-  public function dump_node($node)  {
-    if($this->valeurs[$node]["type"]=="complete"){dump_array($this->valeurs[$node]); return true;}
-    for($i=$node; $i< 32000; $i++)
-    {
-      if(!$this->valeurs[$i]) return false;
-      if($this->fin_node($node, $i) == true)
-      {
-        //dump_array($data);
-        return true;
-      }
-      //$data[]= $this->valeurs[$i];
-      dump_array($this->valeurs[$i]);flush();
-    }
-  }
-
-
   public function get_value($node) {
     return $this->valeurs[$node]["value"];
   }
@@ -135,32 +127,6 @@ class Class_Xml {
   }
 
 
-  public function dump_xml($format) {
-    if(strToUpper($format)=="XML") {
-      foreach($this->valeurs as $balise) {
-        $balise["tag"]=strToLower($balise["tag"]);
-        $data.=str_repeat("&nbsp;", 5 * $balise["level"]);
-        if($balise["type"] == "close" ) $data.="@D@/"; else $data.="@D@";
-        $data.= '<font color="#772B1A">'. $balise["tag"] .'</font>';
-        if($balise["attributes"]) {
-          foreach( $balise["attributes"] as $key => $value) $data.=' <font color="#ff0000">'.strToLower($key).'</font><font color="#0000ff">="</font><font color="#ff0000">'.$value.'</font><font color="#0000ff">"</font>';
-        }
-        if($balise["type"]=="complete" and $balise["value"]) $data.= "@F@<b>" .$balise["value"] ."</b>@D@/".'<font color="#772B1A">'.$balise["tag"] .'</font>';
-        $data.= "@F@";
-        $data.= BR;
-      }
-      $data = str_replace("@D@/", '<font color="#0000ff">&lt;/</font>', $data);
-      $data = str_replace("@D@", '<font color="#0000ff">&lt;</font>', $data);
-      $data = str_replace("@F@", '<font color="#0000ff">&gt;</font>', $data);
-      print($data);
-      return;
-    }
-
-    dump_array($this->index);
-    dump_array($this->valeurs);
-  }
-
-
   public function fin_node($node, $test) {
     if($this->valeurs[$node]["type"]=="complete")
       return true;
diff --git a/library/ZendAfi/Controller/Action/Helper/SearchRecords.php b/library/ZendAfi/Controller/Action/Helper/SearchRecords.php
index c23518792803e77b427639a02e683c099ea07886..f50019a65503b78b315198de6c57fbd46d29cbc1 100644
--- a/library/ZendAfi/Controller/Action/Helper/SearchRecords.php
+++ b/library/ZendAfi/Controller/Action/Helper/SearchRecords.php
@@ -22,8 +22,13 @@
 
 class ZendAfi_Controller_Action_Helper_SearchRecords extends Zend_Controller_Action_Helper_Abstract {
   public function searchRecords() {
-    $criteria = (new Class_CriteresRecherche())
-      ->setParams($this->getRequest()->getParams());
+    $criteria = (new Class_CriteresRecherche())->setParams($this->getRequest()->getParams());
+
+    $preferences = Class_Profil::getCurrentProfil()
+        ->getCfgModulesPreferences('recherche', 'resultat', 'simple');
+
+    if (isset($preferences['liste_nb_par_page']))
+      $criteria->setDefaultPageSize($preferences['liste_nb_par_page']);
 
     return Class_MoteurRecherche::getInstance()
       ->lancerRecherche($criteria);
diff --git a/library/digital_resources/Skilleos/Service.php b/library/digital_resources/Skilleos/Service.php
index 35cb54d896602d58580371175566b4177fe5640b..c7f0210596bf3627c7b52ea6493f091bb8eb2ca1 100644
--- a/library/digital_resources/Skilleos/Service.php
+++ b/library/digital_resources/Skilleos/Service.php
@@ -67,6 +67,11 @@ class Skilleos_Service extends Class_DigitalResource_Service {
   }
 
 
+  protected function _deleteNonHarvested() {
+    return $this->_deleteNonHarvestedAlbums();
+  }
+
+
   public function httpGetCatalogue() {
     return $this->httpGet(static::$REST_URL,
                           ['headers' => [ 'Authorization' => 'Bearer ' . $this->getToken()]]);
diff --git a/library/digital_resources/Skilleos/Service/Parser.php b/library/digital_resources/Skilleos/Service/Parser.php
index d787b58dd13e557817b7491ebe2bc53c14caf970..d6c94243d532dd337b9fed0ae8ca37b4e78b2c00 100644
--- a/library/digital_resources/Skilleos/Service/Parser.php
+++ b/library/digital_resources/Skilleos/Service/Parser.php
@@ -28,7 +28,7 @@ class Skilleos_Service_Parser extends Class_WebService_BibNumerique_RessourceNum
          ->setDescription($json->introduction.$json->description.$json->contenu_and_objectif);
 
     $this->_lessons = [];
-    $this->_posters[] = $json->ressource->url;
+    $this->_posters[] = isset($json->picture) ? $json->picture->url : $json->ressource->url;
 
     $this->addAuthor($json->teacher->name);
 
diff --git a/library/digital_resources/Skilleos/tests/SkilleosTest.php b/library/digital_resources/Skilleos/tests/SkilleosTest.php
index f93255d6371fa7041692b17637994880030ffa5a..3c78a91fe0741d388c51053b03ededae47a74807 100644
--- a/library/digital_resources/Skilleos/tests/SkilleosTest.php
+++ b/library/digital_resources/Skilleos/tests/SkilleosTest.php
@@ -179,6 +179,12 @@ abstract class SkilleosServiceTestCase extends AbstractControllerTestCase {
     parent::setUp();
     SkilleosAdminVars::activate();
 
+    $this->fixture('Class_Album',
+                   ['id' => 4,
+                    'titre' => 'I hope to be deleted',
+                    'type_doc_id' => Skilleos_Config::getInstance()->getDocType(),
+                    'id_origine' => 'zork666']);
+
     $token_json = file_get_contents(__DIR__. '/token.json');
     $results_json = file_get_contents(__DIR__. '/results.json');
 
@@ -241,19 +247,19 @@ class SkilleosServiceHarvestTest extends SkilleosServiceTestCase {
 
   /** @test */
   public function urlOriginShouldBeSet() {
-    $this->assertEquals('http://skilleos.com/sigb/sso/',Class_Album::find(1)->getUrlOrigine());
+    $this->assertEquals('http://skilleos.com/sigb/sso/',Class_Album::find(5)->getUrlOrigine());
   }
 
 
   /** @test */
   public function categoryShouldBeSkilleos() {
-    $this->assertEquals('Cours en ligne Skilleos',Class_Album::find(1)->getCategoryLabel());
+    $this->assertEquals('Cours en ligne Skilleos',Class_Album::find(5)->getCategoryLabel());
   }
 
 
   /** @test */
   public function matiereSportEtBienEtreShouldBeCreated() {
-    $id = Class_Album::find(2)->getMatiere();
+    $id = Class_Album::find(6)->getMatiere();
     $labels= Class_CodifMatiere::find($id)->getLibelle();
     $this->assertEquals('Sport & Bien-être', $labels);
   }
@@ -261,24 +267,31 @@ class SkilleosServiceHarvestTest extends SkilleosServiceTestCase {
 
   /** @test */
   public function albumTitleShouldBeMeditationRelaxation() {
-    $this->assertEquals('Hatha Yoga', Class_Album::find(1)->getTitre());
+    $this->assertEquals('Hatha Yoga', Class_Album::find(5)->getTitre());
   }
 
 
   /** @test */
   public function descriptionShouldContains() {
-    $this->assertContains('Des instructions pour rendre',Class_Album::find(2)->getDescription());
+    $this->assertContains('Des instructions pour rendre',Class_Album::find(6)->getDescription());
   }
 
   /** @test */
   public function authorShouldBeYogaChezMoi() {
-    $this->assertEquals('Tatiana Abbey', Class_Album::find(2)->getAuthors()[0]->getName());
+    $this->assertEquals('Tatiana Abbey', Class_Album::find(6)->getAuthors()[0]->getName());
+  }
+
+
+  /** @test */
+  public function thumbnailShouldBeThumbDotpng() {
+    $this->assertEquals('https://moncompte.skilleos.com/uploads/ressources/default/0001/11/thumb_10683_default_big.png', Class_Album::find(6)->getPoster());
   }
 
+
   /** @test */
   public function withoutUserConnectionLinkToModuleSkilleosShouldIndicateToConnect() {
     ZendAfi_Auth::getInstance()->clearIdentity();
-    Class_Album::find(2)->index();
+    Class_Album::find(6)->index();
     $this->dispatch('/noticeajax/resnumeriques/id/1', true);
     $this->assertXPathContentContains('//a[contains(@href, "modules/skilleos")]', 'Vous devez ', $this->_response->getBody());
   }
@@ -287,15 +300,15 @@ class SkilleosServiceHarvestTest extends SkilleosServiceTestCase {
 
   /** @test */
   public function withValidUserConnectionLinkToModuleSkilleosShouldIndicateToConnect() {
-    Class_Album::find(2)->index();
+    Class_Album::find(6)->index();
     $this->dispatch('/noticeajax/resnumeriques/id/1', true);
-    $this->assertXPathContentContains('//a[contains(@href, "/modules/skilleos/album_id/2")]', utf8_encode('Accéder à '), $this->_response->getBody());
+    $this->assertXPathContentContains('//a[contains(@href, "/modules/skilleos/album_id/6")]', utf8_encode('Accéder à '), $this->_response->getBody());
   }
 
 
   /** @test */
   public function withAlbumIdShouldRedirectToSkilleos() {
-    $this->dispatch('/opac/modules/skilleos/album_id/2',true);
+    $this->dispatch('/opac/modules/skilleos/album_id/6',true);
     $ticket = (new Class_CasTicket())->getTicketForCurrentUser();
     $this->assertXPathContentContains('//script','/sigb/sso/602?casid=QUEST&ticket='.$ticket, $this->_response->getBody());
   }
diff --git a/library/digital_resources/Skilleos/tests/results.json b/library/digital_resources/Skilleos/tests/results.json
index b0a6f42ce8282dc8fec3c9a2079344a4d7ebdfa9..a4defa386ec929635b531776cf318c72d6d21804 100644
--- a/library/digital_resources/Skilleos/tests/results.json
+++ b/library/digital_resources/Skilleos/tests/results.json
@@ -105,7 +105,7 @@
       "url": "https:\/\/moncompte.skilleos.com\/uploads\/ressources\/default\/0001\/12\/thumb_11660_default_big.png"
     },
     "id": 677,
-    "ressource": {
+    "picture": {
       "url": "https:\/\/moncompte.skilleos.com\/uploads\/ressources\/default\/0001\/12\/thumb_11659_default_big.png"
     }
   },
diff --git a/library/fonctions/error.php b/library/fonctions/error.php
index 99ad1a39cc5a3522942e6005c4bda1d51063e169..908a07c57c0e06b8824ed65b5cfc02e204ea6ff2 100644
--- a/library/fonctions/error.php
+++ b/library/fonctions/error.php
@@ -16,36 +16,9 @@
  *
  * 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
  */
-function logErrorMessage($message) 
-{ 
-    echo '<b>keskil pass</b><br />'.$message.'<br />'; 
-}
-
-function traceDebug($trace,$exit=false)
-{
-  // Script et fonction
-  $stack=debug_backtrace();
-  $lig=$stack[1];
-  print('<div style="margin-left:10px;margin-bottom:5px;margin-top:5px;border:1px solid;border-color:#E0E0E0;background-color:#CCFF99;padding:5px;text-align:left">');
-  if($niveau==100) dump_array($stack);
-  else
-  {
-    print("<b>Script : </b>". $lig["file"]);
-    print(" - <b>Ligne : </b>". $lig["line"]);
-    if($lig["class"]) print(" - <b>Classe : </b>". $lig["class"]);
-    print(" - <b>Fonction : </b>". $lig["function"].BR);
-    // Données
-    if($trace)
-    {
-      $type=gettype($trace);
-      if( $type == "array" or $type=="object") dump_array($trace);
-      else print('<b>Message : </b>'.$trace.BR);
-    }
-  }
-  print('</div>');
-  flush();
-  if($exit == true) exit;
+function logErrorMessage($message) {
+    echo '<b>Error</b><br />'.$message.'<br />';
 }
 ?>
\ No newline at end of file
diff --git a/library/fonctions/file_system.php b/library/fonctions/file_system.php
deleted file mode 100644
index 25ae3671907bdc13237bffd6078162cb62bf4ee8..0000000000000000000000000000000000000000
--- a/library/fonctions/file_system.php
+++ /dev/null
@@ -1,73 +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 
- */
-/*
- * FONCTIONS DE TRAITEMENTS REPERTOIRES ET FICHIERS
- */
-
-// Lit le contenu entier d'un fichier
-function lire_fichier( $fic)
-{
-  @$handle = fopen( $fic, "r") or erreur_admin( "Impossible d'ouvrir le fichier : " .$fic );
-  $data=fread ($handle, filesize ($fic));
-  fclose($handle);
-  return $data;
-}
-
-// Lit un fichier en éliminant les lignes vides et les commentaires
-function lire_fichier_ressource( $fic )
-{
-  $lig = @file( $fic ) or erreur_admin( "Impossible d'ouvrir le fichier : " . $fic);
-  for( $i = 0; $i < count($lig); $i++)
-  {
-    $lig[$i] = trim($lig[$i]);
-    if( ! $lig[$i] or strLeft( $lig[$i],2 ) == "//") continue;
-    $data .= NL.$lig[$i];
-  }
-  return $data;
-}
-
-// Rend tous les fichiers de tous les dossiers et sous-dossiers d'une racine
-function parse_dossier( $root )
-{
-  if( file_exists($root) == false ) return false;
-  $liste = array();
-  @$dir = opendir( $root) or die("Impossible d'ouvrir le dossier : " .$root);
-  while (($file = readdir($dir)) !== false) 
-  {
-    if( subStr( $file, 0, 1 )!= ".") 
-    {
-      if(filetype($root. "/" .$file) == "dir")
-      {
-        $liste1 = parse_dossier( $root. "/" .$file);
-        $liste = array_merge( $liste, $liste1); 
-      }
-      else
-      {
-        $index = count($liste);
-        $liste[$index][0]= $root;
-        $liste[$index][1]= $file;
-      }
-    }
-  }
-  closedir( $dir);
-  return $liste;
-}
-?>
\ No newline at end of file
diff --git a/library/fonctions/sql.php b/library/fonctions/sql.php
index 8564a2a9c4bd3989b425d628c642eebb28a31bdb..0f36293ac89eaecf33ab1756d7114c171ac8174b 100644
--- a/library/fonctions/sql.php
+++ b/library/fonctions/sql.php
@@ -46,27 +46,6 @@ function fetchAll($req, $num=false) {
 }
 
 
-function getWhereSql($conditions) {
-  if (!$conditions)
-    return '';
-
-  if ('string' == gettype($conditions))
-    $conditions = [$conditions];
-
-  $clauses = [];
-  foreach ($conditions as $condition) {
-    if (!$trimmed = trim($condition))
-      continue;
-    $clauses[] = $trimmed;
-  }
-
-  if (0 == count($clauses))
-    return '';
-
-  return ' where ' . implode(' and ', $clauses);
-}
-
-
 function sqlUpdate($req, $data, $force_quote=false) {
   return Zend_Registry::get('sql')->update($req, $data, $force_quote);
 }
@@ -77,10 +56,4 @@ function sqlInsert($table, $data, $force_quote=false) {
 }
 
 
-function getLimitSql($nb_par_page, $page) {
-  if(!$page) $page = 1;
-  $limit = ($page-1) * $nb_par_page;
-  return ' LIMIT ' . $limit . ',' . $nb_par_page;
-}
-
 ?>
\ No newline at end of file
diff --git a/library/fonctions/string.php b/library/fonctions/string.php
index 9f430f8a42c4cb3b0d0fde5ea385b826f3c909ca..123c87e2d7d61879a99682bc518b7bb31fcd3821 100644
--- a/library/fonctions/string.php
+++ b/library/fonctions/string.php
@@ -23,16 +23,6 @@
 //
 /////////////////////////////////////////////////////////////////////////////////////
 
-//----------------------------------------------------------------------------------
-// Debug dans un fichier log
-//----------------------------------------------------------------------------------
-function debug_log($chaine,$stop=false)
-{
-  $handle=fopen(USERFILESPATH."/debug.log","a");
-  fwrite($handle,$chaine.chr(13).chr(10));
-  fclose($handle);
-  if($stop==true) exit;
-}
 
 //----------------------------------------------------------------------------------
 // Rend une variable admin
@@ -61,16 +51,6 @@ function getVarListeCosmogramme($clef)
   return $liste;
 }
 
-//----------------------------------------------------------------------------------
-// Affichage d'un tableau pour debugging
-//----------------------------------------------------------------------------------
-function dump_array( $tableau)
-{
-  print( "<br><br><big><b>Tableau</b></big>");
-  print("<br><br><pre>");
-  print_r($tableau);
-  print("</pre><br><br>");
-}
 
 //----------------------------------------------------------------------------------
 // Formattage de date
@@ -152,20 +132,6 @@ function strScan( $chaine, $cherche, $posDeb = 0)
   return -1;
 }
 
-function strScanReverse( $chaine, $cherche, $pos ) {
-
-  $chaine = convertFromUtf8($chaine);
-  $cherche = convertFromUtf8($cherche);
-
-  $len = strLen($cherche);
-  if( $pos == -1 )
-    $pos = strLen($chaine);
-  for( $i=$pos; $i>=0; $i-- ) {
-    if( substr( $chaine, $i, $len ) == $cherche )
-      return $i;
-  }
-  return -1;
-}
 
 // Cherche une valeur dans un tableau et renvoie l'indice sinon -1
 function array_find( $tableau, $valeur )
diff --git a/library/startup.php b/library/startup.php
index a120e3d8ebcc5700bdf3a11ecbb8683a028a1e80..30844325374da17057b145164e151cdbcecd283a 100644
--- a/library/startup.php
+++ b/library/startup.php
@@ -81,7 +81,7 @@ class Bokeh_Engine {
 
   function setupConstants() {
     defineConstant('BOKEH_MAJOR_VERSION','7.12');
-    defineConstant('BOKEH_RELEASE_NUMBER', BOKEH_MAJOR_VERSION . '.40');
+    defineConstant('BOKEH_RELEASE_NUMBER', BOKEH_MAJOR_VERSION . '.41');
 
     defineConstant('BOKEH_REMOTE_FILES', 'http://git.afi-sa.fr/afi/opacce/');
 
diff --git a/tests/application/modules/opac/controllers/RechercheControllerTest.php b/tests/application/modules/opac/controllers/RechercheControllerTest.php
index 6c56041a42ccc7ec93188911b27f3bad3cac6135..2eb4e40c5c9a66b066838ce9a5218ac9e04b9d72 100644
--- a/tests/application/modules/opac/controllers/RechercheControllerTest.php
+++ b/tests/application/modules/opac/controllers/RechercheControllerTest.php
@@ -3119,6 +3119,99 @@ class RechercheControllerSimpleActionWithEmptyDomainSettingsAndSiteLinkedTest ex
 
 
 
+class RechercheControlleSimpleActionWithMultifacetsThesauriTest extends RechercheControllerNoticeTestCase {
+  public function setUp() {
+    parent::setUp();
+      $this->fixture('Class_CodifThesaurus',
+                   ['id' => 3,
+                    'libelle' => 'Document',
+                    'libelle_facette' => 'Document',
+                    'id_thesaurus' => 'DOCU',
+                    'id_origine' => null,
+                    'code' => 'DOCU',
+                    'rules' => '{"label":" 99$t "}']);
+
+      $this->fixture('Class_CodifThesaurus',
+                   ['id' => 30,
+                    'libelle' => 'Musique',
+                    'libelle_facette' => 'Musique',
+                    'id_thesaurus' => 'MUSI',
+                    'id_origine' => null,
+                    'code' => 'MUSI',
+                    'rules' => '{"label":" 95$t "}']);
+
+    $this->fixture('Class_CodifThesaurus',
+                   ['id' => 4,
+                    'libelle' => 'SIFI',
+                    'libelle_facette' => 'Science fiction',
+                    'id_thesaurus' => 'DOCU0001',
+                    'code' => 'SIFI',
+                    'rules' => '{"label":" 99$t "}']);
+
+    $this->fixture('Class_CodifThesaurus',
+                   ['id' => 5,
+                    'libelle' => 'BD',
+                    'libelle_facette' => 'Bande dessinee',
+                    'id_thesaurus' => 'DOCU0002',
+                    'code' => 'BD',
+                    'rules' => '{"label":" 99$t "}']);
+
+    $this->fixture('Class_CodifThesaurus',
+                   ['id' => 6,
+                    'libelle' => 'BD',
+                    'libelle_facette' => 'Manga',
+                    'id_thesaurus' => 'DOCU00020001',
+                    'code' => 'Manga',
+                    'rules' => '{"label":" 90$t "}']);
+
+    $this->fixture('Class_CodifThesaurus',
+                   ['id' => 31,
+                    'libelle' => 'Experimentale',
+                    'libelle_facette' => 'Experimentale',
+                    'id_origine' => 30,
+                    'id_thesaurus' => 'MUSI0001',
+                    'code' => 'EXPE',
+                    'rules' => '{"label":" 95$t "}']);
+
+    $this->fixture('Class_Article',
+                   ['id' => 1,
+                    'titre' => 'News of the sprint',
+                    'id_user' => 1,
+                    'indexation' => 1,
+                    'contenu' => 'Articles are going to be auto indexed !',
+                    'domaine_ids' => '3']);
+
+    Class_Article::find(1)->index();
+
+    $this->mock_sql
+      ->whenCalled('fetchAll')
+      ->with("select id_notice, facettes from notices Where MATCH(facettes) AGAINST('+(HDOCU0001 HDOCU0002 HDOCU00020001) +(HMUSI0001)' IN BOOLEAN MODE)", true, false)
+      ->answers([  [1, ''] ])
+
+      ->whenCalled('fetchOne')
+      ->answers(1)
+      ->whenCalled('fetchAll')
+      ->answers([Class_Notice::find(1)->toArray()])
+      ->beStrict();
+
+
+    Class_Profil::getCurrentProfil()
+      ->setCfgModules(['recherche' =>
+                       ['resultatsimple' =>
+                        ['liste_format' =>  Class_Systeme_ModulesAppli::LISTE_FORMAT_MUR]]]);
+
+    $this->dispatch('/recherche/simple/multifacets/HDOCU0001-HDOCU0002-HDOCU00020001-HMUSI0001', true);
+  }
+
+
+  /** @test */
+  public function newsOfTheSPrintShouldExistsAsANotice() {
+    $this->assertNotNull(Class_Notice::find(1));
+  }
+}
+
+
+
 class RechercheControlleSimpleActionWithEmptyDomainSettingsAndArticlesLinkedTest extends RechercheControllerNoticeTestCase {
   public function setUp() {
     parent::setUp();
diff --git a/tests/library/Class/Cosmogramme/Integration/PhasePrepareIntegrationsTest.php b/tests/library/Class/Cosmogramme/Integration/PhasePrepareIntegrationsTest.php
index 77df3e6b1277e16eefcb2b4ff06d76ad61cacb91..c6192da2af56313d99ec40694e3b79711b183eeb 100644
--- a/tests/library/Class/Cosmogramme/Integration/PhasePrepareIntegrationsTest.php
+++ b/tests/library/Class/Cosmogramme/Integration/PhasePrepareIntegrationsTest.php
@@ -32,6 +32,18 @@ abstract class PhasePrepareIntegrationsWithOAITestCase
                         ->with ('ftp/my-library.net/transferts/foo/mylibrarytotal.txt')
                         ->answers(true)
 
+                        ->whenCalled('filesize')
+                        ->with ('ftp/my-library.net/transferts/foo/mylibrarytotal.txt')
+                        ->answers(11000000)
+
+                        ->whenCalled('is_file')
+                        ->with ('ftp/my-library.net/transferts/foo/toosmall.txt')
+                        ->answers(true)
+
+                        ->whenCalled('filesize')
+                        ->with ('ftp/my-library.net/transferts/foo/toosmall.txt')
+                        ->answers(1000000)
+
                         ->whenCalled('is_file')
                         ->with ('ftp/my-library.net/transferts/foo/20180517mylibraryincr.txt')
                         ->answers(true)
@@ -135,7 +147,7 @@ abstract class PhasePrepareIntegrationsWithOAITestCase
                                         'type_doc' => 0,
                                         'nom_fichier' => 'foo/mylibrarytotal.txt',
                                         'rang' => 100,
-                                        'taille_min_import_total' => 0]);
+                                        'taille_min_import_total' => 10]);
 
     $this->fixture('Class_IntMajAuto', ['id' => 101,
                                         'id_prog' => 101,
@@ -159,6 +171,20 @@ abstract class PhasePrepareIntegrationsWithOAITestCase
                                         'rang' => 102,
                                         'taille_min_import_total' => 0]);
 
+
+
+    $this->fixture('Class_IntMajAuto', ['id' => 104,
+                                        'id_prog' => 104,
+                                        'id_bib' => 2,
+                                        'libelle' => 'Notices - too small',
+                                        'profil' => 102,
+                                        'type_operation' => 2,
+                                        'type_doc' => 0,
+                                        'nom_fichier' => 'foo/toosmall.txt',
+                                        'rang' => 100,
+                                        'taille_min_import_total' => 10]);
+
+
     $this->fixture('Class_Cosmogramme_Integration',
                    ['id' => 1,
                     'id_bib' => 2,
@@ -249,6 +275,12 @@ class PhasePrepareIntegrationsWithOAITest extends PhasePrepareIntegrationsWithOA
   }
 
 
+  /** @test */
+  public function logShouldContainsFileTooSmall() {
+    $this->assertLogContains('<td class="blank">foo/toosmall.txt</td><td class="blank"> <span class="rouge">Le fichier est trop petit : 1000000 o -> taille minimum attendue : 10485760 o');
+  }
+
+
   /**
    * @expectedException Class_Cosmogramme_Integration_PhasePrepareIntegrationsException
    * @expectedExceptionMessage La variable ftp_path n'est pas définie
@@ -348,7 +380,9 @@ class PhasePrepareIntegrationsNanookStandardTest
 
       ->whenCalled('getLibrariesOf')->with('foo')
       ->answers(['BIB_SPS_UTT|ID_SITE|LIBELLE',
-                 '2|My library'])
+                 '2|Ma library',
+                 '6|Ma bibliothèque',
+                 '8|' . iconv('UTF-8', 'ISO-8859-1', 'Ma médiathèque')])
 
       ->whenCalled('getSectionsOf')->with('foo')
       ->answers(['BIB_C_SECTION|CODE|LIBELLE',
@@ -624,6 +658,18 @@ class PhasePrepareIntegrationsNanookStandardTest
   }
 
 
+  /** @test */
+  public function libraryIdSixLabelShouldBeMaBibliothèque() {
+    $this->assertEquals('Ma bibliothèque', Class_Cosmogramme_Generator_FixedIdBib::find(6)->getLibelle());
+  }
+
+
+  /** @test */
+  public function libraryIdEigthLabelShouldBeMaMédiathèque() {
+    $this->assertEquals('Ma médiathèque', Class_Cosmogramme_Generator_FixedIdBib::find(8)->getLibelle());
+  }
+
+
   /** @test */
   public function plannedIntegrationsOfRemovedLibraryShouldBeDeleted() {
     $this->assertEmpty(Class_IntMajAuto::findAllBy(['id_bib' => 3]));
diff --git a/tests/scenarios/AdvancedSearch/AdvancedSearchTest.php b/tests/scenarios/AdvancedSearch/AdvancedSearchTest.php
index 6c03141b37aa2e43b5d749655d78e727a5ef096d..1b5082f4820c544e53e38b341e3922018b704074 100644
--- a/tests/scenarios/AdvancedSearch/AdvancedSearchTest.php
+++ b/tests/scenarios/AdvancedSearch/AdvancedSearchTest.php
@@ -659,10 +659,42 @@ class AdvancedSearchMultiFacetsPostDispatchTest extends Admin_AbstractController
       $_storm_default_to_volatile = true;
 
 
+  public function setUp() {
+      parent::setUp();
+      $this->fixture('Class_CodifThesaurus',
+                   ['id' => 3,
+                    'libelle' => 'Document',
+                    'libelle_facette' => 'Document',
+                    'id_thesaurus' => 'DOCU',
+                    'id_origine' => null,
+                    'code' => 'DOCU',
+                    'rules' => '{"label":" 99$t "}']);
+
+    $this->fixture('Class_CodifThesaurus',
+                   ['id' => 4,
+                    'libelle' => 'SIFI',
+                    'libelle_facette' => 'Science fiction',
+                    'id_thesaurus' => 'DOCU0001',
+                    'id_origine' => null,
+                    'code' => 'DOCU',
+                    'rules' => '{"label":" 99$t "}']);
+  }
+
+
   /** @test */
   public function shouldRedirectToRechercheSimpleMultifacetsA12MinusA42MinusM608() {
     $this->postDispatch('/recherche/simple', ['custom_multifacets_author' => ['A12', 'A42'],
                                               'custom_multifacets_subject' => 'M608']);
     $this->assertRedirectTo('/recherche/simple/multifacets/A12-A42-M608');
   }
+
+
+
+  /** @test */
+  public function mixMultifacetsAndDynamicFacetsShouldMergeFacets() {
+    $this->postDispatch('/recherche/simple',   [ 'custom_multifacets_author' => ['A12', 'A42'],
+                                                 'custom_multifacets_subject' => 'M608',
+                                                 'rech_HDOCU' => 'SIFI']);
+    $this->assertRedirectTo('/recherche/simple/multifacets/HDOCU0001-A12-A42-M608');
+  }
 }
\ No newline at end of file
diff --git a/tests/scenarios/SearchSelection/SearchSelectionTest.php b/tests/scenarios/SearchSelection/SearchSelectionTest.php
index cedd474ccd013c1e355f067cc54585899c45dedb..d6300bea092a3ec04989d05366a5f56521fdda3f 100644
--- a/tests/scenarios/SearchSelection/SearchSelectionTest.php
+++ b/tests/scenarios/SearchSelection/SearchSelectionTest.php
@@ -292,18 +292,27 @@ class SearchSelectionSelectClearTest extends SearchSelectionTestCase {
 
 
 class SearchSelectionSelectPageTest extends SearchSelectionTestCase {
-  public function setUp() {
-    parent::setUp();
+  /** @test */
+  public function withTwoRecordsInSessionAndPageSizeTwoSelectShouldAddRecordNine() {
     Zend_Registry::get('session')->search_record_selection = [8, 10];
     $this->dispatch('/records/select-page/expressionRecherche/pomme/facettes/T3/page/1/page_size/2', true);
+    $this->assertEquals([8, 10, 9],
+                        Zend_Registry::get('session')->search_record_selection);
   }
 
 
   /** @test */
-  public function sessionShouldContainsNine() {
-    $this->assertEquals([8, 10, 9],
-                        Zend_Registry::get('session')->search_record_selection);
-    return $this->_response->getBody();
+  public function withEmptySessionAndDefaultPageSizeTwoSelectShouldAddEightAndNine() {
+    Zend_Registry::get('session')->search_record_selection = [];
+    Class_Profil::getCurrentProfil()->setCfgModulesPreferences(['liste_nb_par_page' => 2],
+                                                                'recherche',
+                                                                'resultat',
+                                                                'simple');
+    
+    $this->dispatch('/records/select-page/expressionRecherche/pomme/facettes/T3/page/1', true);
+
+    sort(Zend_Registry::get('session')->search_record_selection);
+    $this->assertEquals([8, 9], Zend_Registry::get('session')->search_record_selection);
   }
 }
 
diff --git a/tests/scenarios/Xsl/XslTest.php b/tests/scenarios/Xsl/XslTest.php
index 20122d6be11d900bd4fdcf0d231a3eb85203a681..1c53428996ea647d04cf1bce52b61ccab8a634ae 100644
--- a/tests/scenarios/Xsl/XslTest.php
+++ b/tests/scenarios/Xsl/XslTest.php
@@ -111,14 +111,12 @@ class XslDocTypeConfigurationPostDispatchTest extends Admin_AbstractControllerTe
 }
 
 
-
-class XslNoticeajaxDetailDispatchTest extends AbstractControllerTestCase {
-
+abstract class XslNoticeajaxDetailTestCase extends AbstractControllerTestCase {
   protected $_storm_default_to_volatile = true;
 
+
   public function setUp() {
     parent::setUp();
-
     Storm_Cache::beVolatile();
 
     $disk = $this->mock()
@@ -173,15 +171,61 @@ class XslNoticeajaxDetailDispatchTest extends AbstractControllerTestCase {
                     'type_doc' => 1,
                     'unimarc' => "01185nam0 2200217   450 0010005000000100031000050350016000360900009000520990038000611000041000991010008001402000036001482100013001842150011001973300660002083330010008686760006008787000028008848010026009129020029009382774  a2-84563-280-0d19,90 Euros  aALOES355754  a2774  c2017-12-11d2018-03-16tLIVREx12  a20171211              frey50          afre  aSeras-tu là ?fGuillaume Musso  cXOd2012  a301 p.  aUn seul geste aurait suffi pour tout changer. Qui n'a jamais rêvé de revenir à cet instant décisif où le bonheur était possible ? San Francisco. Elliott, médecin passionné, ne s'est jamais consolé de la disparition d'Ilena, la femme qu'il aimait, morte il y a trente ans. Un jour, par une circonstance extraordinaire, il est ramené en arrière et rencontre le jeune homme qu'il était, trente ans plus tôt. Il est revenu à l'instant décisif où un geste de lui peut sauver Ilena. Et modifier l'implacable destin qui a figé son sort à jamais. Un stupéfiant face-à-face, Une histoire d'amour bouleversante, Un suspense à couper le souffle.  aAG 14  aR  aMussobGuillaume960415  aFRbCALUIREc20060516  981440aroman francophone"]);
 
-    $this->dispatch('/opac/noticeajax/detail/id_notice/5', true);
   }
 
 
+
+
   public function tearDown() {
     Storm_Cache::setDefaultZendCache(null);
     parent::tearDown();
   }
 
+}
+
+
+
+
+class XslNoticeBookAjaxDetailDispatchTest extends XslNoticeajaxDetailTestCase {
+  public function setUp() {
+    parent::setUp();
+
+    $this->dispatch('/opac/noticeajax/detail/id_notice/5', true);
+  }
+
+
+  /** @test */
+  public function shouldNotRedirect() {
+    $this->assertNotRedirect();
+  }
+
+
+  /** @test */
+  public function shouldDisplayMarcWithXslt() {
+    $this->assertContains('<strong>Numéro de notice Koha : </strong>2774</li><br><li>', $this->_response->getBody());
+  }
+}
+
+
+
+
+class XslNoticeSerialAjaxDetailDispatchTest extends XslNoticeajaxDetailTestCase {
+  public function setUp() {
+    parent::setUp();
+    Class_Notice::find(5)
+      ->setTypeDoc(Class_TypeDoc::PERIODIQUE)
+      ->assertSave();
+
+    $profile = Class_Profil::getCurrentProfil();
+    $profile->setCfgModulesPreferences(['xslt' => '/tests/scenarios/Xsl/record_description.xsl'],
+                                       'recherche',
+                                       'viewnotice',
+                                       Class_TypeDoc::PERIODIQUE);
+    $profile->save();
+
+    $this->dispatch('/opac/noticeajax/detail/id_notice/5', true);
+  }
+
 
   /** @test */
   public function shouldNotRedirect() {