diff --git a/INSTALL.en.md b/INSTALL.en.md
index c040accb5ce8c3f219d4bc9fbfab1249295a5d15..edb4925f31ed7598c5f154f8af649df3b7ee7521 100644
--- a/INSTALL.en.md
+++ b/INSTALL.en.md
@@ -66,6 +66,9 @@ Modify /etc/httpd/conf/http.conf and add the line:
 LoadModule php5_module modules/libphp5.so
 ```
 
+Activate mod_mpm_prefork (see https://wiki.archlinux.org/index.php/Apache_HTTP_Server#PHP).
+
+
 Deactivate negotiation module which is in conflict with Zend Framework on index/index urls:
 
 ```  
@@ -86,6 +89,8 @@ Activate the following extensions if they are not already actived (they should b
 php5enmod calendar curl gd gettext iconv mcrypt mysql pdo_mysql openssl soap imagick
 ```
 
+On Archinux uncomment the corresponding lines.
+
 ## Configure Apache
 
 In Apache conf, delete indexes option (file list) and authorise .htaccess: 
@@ -117,7 +122,14 @@ chmod -R 777 opacce/temp
 ```
   
 # MySQL config
-  
+
+## Finalise the installation (ArchLinux)
+
+See https://wiki.archlinux.org/index.php/MySQL#Installation
+
+
+# Configuration
+
 Edit /etc/mysql/my.cnf and add to the [mysqld] section the following line (in order to force fulltext indexation from the first letter) 
 
 ```
diff --git a/INSTALL.fr.md b/INSTALL.fr.md
index 49b163deefc3ccfb7789347bd4f10790f3b7bb26..f53c07dd14a862338067297d1cbb1668b1908e09 100644
--- a/INSTALL.fr.md
+++ b/INSTALL.fr.md
@@ -15,7 +15,7 @@ apt-get install php5 php5-gd php5-imagick php5-xdebug php-pear php5-mysql graphv
 
 ## ArchLinux
 ```
-yaourt -S php php-gd php-imagick xdebug php-pear apache mysql php-apache php-xhprof graphviz git
+yaourt -S php php-gd php-imagick xdebug php-pear apache mariadb php-apache php-xhprof graphviz git php-mcrypt binutils automake autoconf gcc make fakeroot
 ```
 
 ## CentOS
@@ -24,7 +24,7 @@ rpm -Uvh http://repo.webtatic.com/yum/el6/latest.rpm
 yum install php54w php54w-gd php54w-pear php54w-mysql php54w-pecl-xdebug php54w-xml php54w-soap php54w-mbstring
 ```
 
-You need to build Imagick extension from scratch
+Il est nécessaire de compiler Imagick extension à partir des sources.
 
 
 # Installer PHPUnit (en compte root / sudo):
@@ -66,6 +66,9 @@ Modifiez /etc/httpd/conf/http.conf et ajoutez la ligne:
 LoadModule php5_module modules/libphp5.so
 ```
 
+Activer mod_mpm_prefork (voir https://wiki.archlinux.org/index.php/Apache_HTTP_Server#PHP).
+
+
 Désactivez le module negotiation qui pose problème avec Zend Framework sur les urls index/index:
 
 ```  
@@ -86,6 +89,8 @@ Activez les extensions suivantes si elles ne le sont pas déjà (elles devraient
 php5enmod calendar curl gd gettext iconv mcrypt mysql pdo_mysql openssl soap imagick
 ```
 
+Sur ArchLinux décommenter les lignes correspondantes.
+
 ## Configurer Apache
 
 Dans la conf Apache (/etc/apache2/sites-available/votre-site.conf), supprimer l'option Indexes (listing des fichiers) et autoriser les .htaccess: 
@@ -115,9 +120,16 @@ Note: pour apache 2.4
 ```
 chmod -R 777 opacce/temp
 ```
-  
+
 # Configuration MySQL
   
+## Finaliser l'installation (ArchLinux)
+
+Voir https://wiki.archlinux.org/index.php/MySQL#Installation
+
+
+## Configuration
+
 Modifier /etc/mysql/my.cnf pour forcer l'indexation fulltext à partir de 1 lettre : ajouter dans la section [mysqld] :
 
 ```
diff --git a/VERSIONS b/VERSIONS
index 6c6610e1aa7f31d8771e5f37eb825f20cf2c80e9..48399f25da0e301fe09c412d38abf064c283495f 100644
--- a/VERSIONS
+++ b/VERSIONS
@@ -1,3 +1,39 @@
+17/09/2015 - v7.3.11
+
+ - ticket #28958 : Le lien pour ouvrir la ressource 1dtouch devrait ouvrir un nouvel onglet
+
+ - ticket #26993 : PB Affichage incorrect dans Bokeh des notices de dépouillement
+
+ - ticket #29472 : L'Identification des usagers de type abonnés SIGB provenant de la base Koha de la BDM aboutit à une page blanche
+
+ - ticket #29441 : newsletter qui ne part pas
+
+ - ticket #29689 : Correction d'une erreur à l'intégration des articles de dépouillement dans cosmogramme
+
+
+
+15/09/2015 - v7.3.10
+
+ - correction compatibilité PHP 5.4
+
+
+
+14/09/2015 - v7.3.9
+
+ - sandbox : ajout de l'icône type doc sur les vignettes des avis
+
+ - ticket #25302 : Ajout de champs personnalisés pour la sitothèque
+
+ - ticket #21694 : Les pseudo-notices d'article, albums, RSS et sitothèque sont désormais mises à jour au lieu d'être systématiquement supprimées et recréées lors de l'indexation.
+
+ - ticket #27625 : SIBG Nanook: affichage des responsabilités auteur
+
+ - ticket #24864 : PNB Dilicom : Automatisation de l'import des fichiers de métadonnées des acquisitions
+
+ - ticket #25564 : Corrige la manière dont sont calculés les statistiques de modération
+
+
+
 10/09/2015 - v7.3.8
 
  - ticket #28137 : Branchcode non rempli lors de l'envoi d'une suggestion vers Koha 
@@ -10,9 +46,9 @@
 
  - ticket #28967 : Correction de la prise en compte du paramètre qui permet de limiter le nombre d'avis dans l'affichage hiérarchique.
 
-  - ticket #28994 : Prend en compte le changement d'ordre de la balise biblioitemnumber dans la réponse XML de ILSDI (Koha).
+ - ticket #28994 : Prend en compte le changement d'ordre de la balise biblioitemnumber dans la réponse XML de ILSDI (Koha).
 
-  - ticket #29103 : Le terme 'Portail' est maintenant traductible et peut être remplacé via la variable TEXT_REPLACEMENTS
+ - ticket #29103 : Le terme 'Portail' est maintenant traductible et peut être remplacé via la variable TEXT_REPLACEMENTS
 
 
 
diff --git a/VERSIONS_WIP/25584 b/VERSIONS_WIP/25584
new file mode 100644
index 0000000000000000000000000000000000000000..9fb2a817ea427e38f2bd8cfafc7e5c794a0ca4e1
--- /dev/null
+++ b/VERSIONS_WIP/25584
@@ -0,0 +1 @@
+ - ticket #25584 : Ajout de formulaires qui s'envoient par mail
\ No newline at end of file
diff --git a/application/modules/admin/controllers/AlbumController.php b/application/modules/admin/controllers/AlbumController.php
index b615b587ada21abbef3b3c19bd400ca8cf1ea93e..20c0e519ee7e1cfcf15968a4d43cdce14328329e 100644
--- a/application/modules/admin/controllers/AlbumController.php
+++ b/application/modules/admin/controllers/AlbumController.php
@@ -80,20 +80,12 @@ class Admin_AlbumController extends ZendAfi_Controller_Action {
 
     if ($form->isValid($this->_request->getPost()) && $form->offers->receive()) {
       $xml = file_get_contents($form->offers->getFileName());
-      $books = Class_WebService_BibNumerique_Dilicom_PNBOffersFile::booksFromXML($xml);
-      $errors = [];
-      $import_count = 0;
-      foreach($books as $book) {
-        $album = $book->import();
-        if (!$album->hasErrors())
-          $import_count++;
-
-        $errors = $errors + $album->getErrors();
-      }
+      $report = function($import_count, $errors) {
+        $this->_helper->notify($this->view->_('%d livres numériques importés. %s',
+                                              $import_count,
+                                              implode(',', $errors)));
+      };
 
-      $this->_helper->notify($this->view->_('%d livres numériques importés. %s',
-                                            $import_count,
-                                            implode(',', $errors)));
       $this->_redirect('admin/album');
       return;
     }
diff --git a/application/modules/admin/controllers/SitoController.php b/application/modules/admin/controllers/SitoController.php
index e27dfdcbf71fae5ff8cb6c1d99068757e77f801b..12fb20f0ddae22d0f5cef3a1a73b3e92889881e5 100644
--- a/application/modules/admin/controllers/SitoController.php
+++ b/application/modules/admin/controllers/SitoController.php
@@ -16,37 +16,54 @@
  *
  * 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 : Controller SITOTHEQUE
-////////////////////////////////////////////////////////////////////////////////
-
-class Admin_SitoController extends Zend_Controller_Action {
-  use Trait_Translator;
-
-  private $id_zone;
-  private $id_bib;
-  private $_today;
-
-  //-----------------------------------------------------------------------------------------------
-  // Initialisation
-  //-----------------------------------------------------------------------------------------------
-  function init() {
-    // On force une bib s'il ny en a pas
-    if(!intval($this->id_bib))
-    {
-      if(intval($this->id_zone)) $this->id_bib=fetchOne("select ID_SITE from bib_c_site where ID_ZONE=".$this->id_zone." order by LIBELLE");
-      else {$this->id_bib="PORTAIL"; $this->id_zone="PORTAIL";}
+
+class Admin_SitoController extends ZendAfi_Controller_Action {
+
+
+  public function getRessourceDefinitions() {
+    return [
+      'model' => [
+                  'class' => 'Class_Sitotheque',
+                  'name' => 'sitotheque',
+                  'order' => 'id',
+                  'scope' => 'id_cat'],
+
+      'messages' => [
+        'successful_save' => $this->_('Site "%s" sauvegardé'),
+        'successful_add' => $this->_('Le site "%s" a été sauvegardé'),
+        'successful_delete' => $this->_('Site "%s" supprimé')],
+
+      'actions' => [
+                    'add' => ['title' => $this->_("Ajouter un site")],
+                    'edit' => ['title' => $this->_("Modifier le site: %s")],
+                    'delete' => ['title' => $this->_("Supprimer le site: %s")]
+      ],
+
+      'form_class_name' => 'ZendAfi_Form_Admin_Sitotheque'];
+  }
+
+
+  protected function _updateNewModel($sitotheque) {
+    if (!$category = Class_SitothequeCategorie::find($this->_getParam('id_cat'))) {
+      $this->_redirect('admin/sito');
+      return;
     }
 
-    // Objets de vue
-    $this->view->id_zone=$this->id_zone;
-    $this->view->id_bib=$this->id_bib;
-    
-    /// OLD A MODIFIER ///////
-    $class_date = new Class_Date();
-    $this->_today = $class_date->DateTimeDuJour();
+    $sitotheque->setCategorie($category);
+    if ($domaine = Class_Catalogue::findWithSamePathAs($category))
+      $sitotheque->setDomaineIds($domaine->getId());
+
+    return $this;
+  }
+
+
+  public function init() {
+    parent::init();
+    if ($site = Class_Sitotheque::find((int)$this->_getParam('id'))) {
+      $this->_setParam('id_cat',$site->getCategorie()->getId());
+    }
 
     $identity = Class_Users::getLoader()->getIdentity();
 
@@ -57,7 +74,7 @@ class Admin_SitoController extends Zend_Controller_Action {
       $this->_bib = Class_Bib::getLoader()->getPortail();
     }
   }
-  
+
   //----------------------------------------------------------------------------------
   // Liste des sites
   //----------------------------------------------------------------------------------
@@ -86,7 +103,7 @@ class Admin_SitoController extends Zend_Controller_Action {
     foreach ($bibs as $bib) {
       $categories[] = array('bib'=> $bib,
                             'containers' => $bib->getSitothequeCategories(),
-                            'add_link' => $this->view->tagAnchor($this->view->url(array_merge($add_link_options, 
+                            'add_link' => $this->view->tagAnchor($this->view->url(array_merge($add_link_options,
                                                                                               ['id_bib' => $bib->getId()])),
                                                                  $add_link_label));
     }
@@ -96,7 +113,7 @@ class Admin_SitoController extends Zend_Controller_Action {
     $this->view->sitoActions = $this->_getTreeViewItemActions();
 
     $this->view->headScript()->appendScript('var treeViewSelectedCategory = '
-                                      . (int)$this->_getParam('id_cat') . ';');
+                                            . (int)$this->_getParam('id_cat') . ';');
     $this->view->headScript()->appendFile(URL_ADMIN_JS . 'tree-view.js');
   }
 
@@ -107,69 +124,69 @@ class Admin_SitoController extends Zend_Controller_Action {
    */
   private function _getTreeViewContainerActions() {
     return array(
-      array(
-        'url' => $this->_getUrlForActionAndIdName('catedit'),
-        'icon'      => 'ico/edit.gif',
-        'label'     => 'Modifier'
-      ),
-      array(
-        'url' => $this->_getUrlForActionAndIdName('catdel'),
-        'icon'      => 'ico/del.gif',
-        'label'     => 'Supprimer',
-        'condition' => 'hasNoChild',
-        'anchorOptions' => array(
-          'onclick' => "return confirm('Etes-vous sûr de vouloir supprimer cette catégorie ?')"
-        )
-      ),
-      array(
-        'url' => $this->_getUrlForActionAndIdName('sitoadd', 'id_cat'),
-        'icon'      => 'ico/add_news.gif',
-        'label'     => 'Ajouter un site',
-      ),
-      array(
-        'url' => $this->_getUrlForActionAndIdName('catadd'),
-        'icon'      => 'ico/add_cat.gif',
-        'label'     => 'Ajouter une sous-catégorie'
-      ),
+                 array(
+                       'url' => $this->_getUrlForActionAndIdName('catedit'),
+                       'icon'      => 'ico/edit.gif',
+                       'label'     => 'Modifier'
+                 ),
+                 array(
+                       'url' => $this->_getUrlForActionAndIdName('catdel'),
+                       'icon'      => 'ico/del.gif',
+                       'label'     => 'Supprimer',
+                       'condition' => 'hasNoChild',
+                       'anchorOptions' => array(
+                                                'onclick' => "return confirm('Etes-vous sûr de vouloir supprimer cette catégorie ?')"
+                       )
+                 ),
+                 array(
+                       'url' => $this->_getUrlForActionAndIdName('add', 'id_cat'),
+                       'icon'      => 'ico/add_news.gif',
+                       'label'     => 'Ajouter un site',
+                 ),
+                 array(
+                       'url' => $this->_getUrlForActionAndIdName('catadd'),
+                       'icon'      => 'ico/add_cat.gif',
+                       'label'     => 'Ajouter une sous-catégorie'
+                 ),
     );
   }
 
 
   protected function _getUrlForActionAndIdName($action, $idName = 'id') {
     return $this->view->url(array(
-        'module' => 'admin',
-        'controller'=> 'sito',
-        'action'    => $action), null, true) . '/' . $idName . '/%s';
+                                  'module' => 'admin',
+                                  'controller'=> 'sito',
+                                  'action'    => $action), null, true) . '/' . $idName . '/%s';
   }
 
 
   private function _getTreeViewItemActions() {
-    return 
+    return
       [
-        [
-          'url' => $this->_getUrlForActionAndIdName('sitoview').'?&iframe=true&width=80%%&height=80%%',
-          'icon'      => 'ico/show.gif',
-          'label'     => 'Visualiser',
-          'anchorOptions' => [
-            'rel' => 'prettyPhoto'
-            ]
-          ],
-
-        [
-          'url' => $this->_getUrlForActionAndIdName('sitoedit'),
-          'icon'      => 'ico/edit.gif',
-          'label'     => 'Modifier',
-          ],
-
-        [
-          'url' => $this->_getUrlForActionAndIdName('sitodel'),
-          'icon'      => 'ico/del.gif',
-          'label'     => 'Supprimer',
-          'anchorOptions' => [
-            'onclick' => "return confirm('Etes-vous sûr de vouloir supprimer ce site ?')"
-            ],
-          ]
-        ];
+       [
+        'url' => $this->_getUrlForActionAndIdName('sitoview').'?&iframe=true&width=80%%&height=80%%',
+        'icon'      => 'ico/show.gif',
+        'label'     => 'Visualiser',
+        'anchorOptions' => [
+                            'rel' => 'prettyPhoto'
+        ]
+       ],
+
+       [
+        'url' => $this->_getUrlForActionAndIdName('edit'),
+        'icon'      => 'ico/edit.gif',
+        'label'     => 'Modifier',
+       ],
+
+       [
+        'url' => $this->_getUrlForActionAndIdName('delete'),
+        'icon'      => 'ico/del.gif',
+        'label'     => 'Supprimer',
+        'anchorOptions' => [
+                            'onclick' => "return confirm('Etes-vous sûr de vouloir supprimer ce site ?')"
+        ],
+       ]
+      ];
   }
 
 
@@ -183,8 +200,8 @@ class Admin_SitoController extends Zend_Controller_Action {
 
     if ($parent_categorie = Class_SitothequeCategorie::find((int)$this->_getParam('id')))
       $categorie
-      ->setParentCategorie($parent_categorie)
-      ->setIdSite($parent_categorie->getIdSite());
+        ->setParentCategorie($parent_categorie)
+        ->setIdSite($parent_categorie->getIdSite());
 
     if ($this->_isCategorieSaved($categorie)) {
       $this->_helper->notify($this->_('La catégorie "%s" a été ajoutée', $categorie->getLibelle()));
@@ -193,7 +210,7 @@ class Admin_SitoController extends Zend_Controller_Action {
     }
 
     $this->view->categorie = $categorie;
-    $this->view->combo_cat = $this->view->comboParentCategorie($categorie); 
+    $this->view->combo_cat = $this->view->comboParentCategorie($categorie);
   }
 
 
@@ -215,7 +232,7 @@ class Admin_SitoController extends Zend_Controller_Action {
     }
 
     $this->view->categorie = $categorie;
-    $this->view->combo_cat = $this->view->comboParentCategorie($categorie); 
+    $this->view->combo_cat = $this->view->comboParentCategorie($categorie);
   }
 
 
@@ -250,66 +267,22 @@ class Admin_SitoController extends Zend_Controller_Action {
   }
 
 
-  function sitoaddAction()  {
-    if (!$categorie = Class_SitothequeCategorie::find($this->_getParam('id_cat'))) {
-      $this->_redirect('/admin/sito');
-      return;
-    }
-
-    $this->view->site = $site = new Class_Sitotheque();
-    $this->view->titre = "Ajouter un site";
-
-    $site->setIdCat($categorie->getId());
-
-    if ($domaine = Class_Catalogue::findWithSamePathAs($categorie))
-      $site->setDomaineIds($domaine->getId());
-
-    $this->displaySiteForm($site);
+  protected function _canAdd() {
+    $category = Class_SitothequeCategorie::find($this->_getParam('id_cat'));
+    return $category;
   }
 
 
-  function sitoeditAction() {
-    if (!$site = Class_Sitotheque::find((int)$this->_getParam('id'))) {
-      $this->_redirect('/admin/sito');
-      return;
-    }
-
-    $this->view->titre = "Modifier un site";
-    $this->view->site = $site;
-
-    $this->displaySiteForm($site);
+  protected function _getPost() {
+    $post = $this->_request->getPost();
+    unset($post['id_items']);
+    return $post;
   }
 
 
-  public function displaySiteForm($site) {
-    if ($this->_request->isPost()) {
-      $post = $this->_request->getPost();
-      unset($post['id_items']);
-      if ($site
-          ->updateAttributes($post)
-          ->save()) {
-        $site->index();
-        (new Storm_Cache())->clean();
-        $this->_helper->notify($this->_('Le site "%s" a été sauvegardé', $site->getTitre()));
-        $this->_redirect('/admin/sito/sitoedit/id/'.$site->getId());
-        return;
-      }
-    }
-
-    // Action
-    $this->view->combo_cat =$this->view->comboCategories($site->getCategorie());
-  }
-
-
-  function sitodelAction()  {
-    if (!$site = Class_Sitotheque::find((int)$this->_getParam('id'))) {
-      $this->_redirect('/admin/sito');
-      return;
-    }
-
-    $site->delete();
-    $this->_helper->notify($this->_('Le site "%s" a été supprimé', $site->getTitre()));
-    $this->_redirect('/admin/sito/index/id_cat/'.$site->getIdCat());
+  protected function _doAfterSave($model) {
+    $model->index();
+    (new Storm_Cache())->clean();
   }
 
 
diff --git a/application/modules/admin/views/scripts/sito/add.phtml b/application/modules/admin/views/scripts/sito/add.phtml
new file mode 100644
index 0000000000000000000000000000000000000000..c52ca489f905555642d9f8210fc3130ba4abfdcd
--- /dev/null
+++ b/application/modules/admin/views/scripts/sito/add.phtml
@@ -0,0 +1 @@
+<?php echo $this->renderForm($this->form); ?>
diff --git a/application/modules/admin/views/scripts/sito/edit.phtml b/application/modules/admin/views/scripts/sito/edit.phtml
new file mode 100644
index 0000000000000000000000000000000000000000..3ac0df9a91601b0019b8697f2f6a494b1e9a9fd2
--- /dev/null
+++ b/application/modules/admin/views/scripts/sito/edit.phtml
@@ -0,0 +1,5 @@
+<div class="content_edit_head">
+  <?php echo $this->_('Localisation') . ' : ' . $this->sitotheque->getBibLibelle(); ?>
+</div>
+
+<?php echo $this->renderForm($this->form); ?>
diff --git a/application/modules/opac/controllers/FormulaireController.php b/application/modules/opac/controllers/FormulaireController.php
index 1ec97963448bb61a8d2a2b18b73ece46b49c5e91..e6ced064ebbd47db10fa1595e95b3264b12e0f7d 100644
--- a/application/modules/opac/controllers/FormulaireController.php
+++ b/application/modules/opac/controllers/FormulaireController.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
  */
 class FormulaireController extends ZendAfi_Controller_Action {
   public function addAction() {
@@ -30,8 +30,36 @@ class FormulaireController extends ZendAfi_Controller_Action {
 
     $this->view->datas = $formulaire->getDatas();
     $this->view->article = $article;
+
+    if ($address = $article->getDestinationEmail()) {
+      $this->_sendFormEmail($address, $formulaire->dataAsBodyText());
+      $this->view->email_sent = true;
+    }
+  }
+
+  protected function _sendFormEmail($address, $body) {
+    $mail = new ZendAfi_Mail('utf8');
+    $mail->setFrom(Class_Profil::getCurrentProfil()->getMailSiteOrPortail())
+         ->addTo($address)
+         ->setSubject('[Bokeh] ' . $this->_('Envoi d\'un formulaire'))
+         ->setBodyText($body);
+
+    $this->_sendMail($mail);
+    return $this;
   }
 
+  protected function _sendMail($mail) {
+    try {
+      $mail->send();
+      return true;
+
+    } catch (Exception $e) {
+      $this->_helper->notify($this->_('Mail non envoyé: vérifier la configuration du serveur de mail.'));
+      return false;
+    }
+  }
+
+
 }
 
 ?>
\ No newline at end of file
diff --git a/application/modules/opac/controllers/NoticeajaxController.php b/application/modules/opac/controllers/NoticeajaxController.php
index 8b7b20fad1b858fb2d7a0256cd5168bc996f317a..910806f7f3d69a54719255e576b448eca259578c 100644
--- a/application/modules/opac/controllers/NoticeajaxController.php
+++ b/application/modules/opac/controllers/NoticeajaxController.php
@@ -82,8 +82,7 @@ class NoticeAjaxController extends Zend_Controller_Action {
     $tags=$this->notice->getTags($this->id_notice);
     $html=$this->notice_html->getTags($tags, $this->id_notice, $this->view);
 
-    $this->getResponse()->setHeader('Content-Type', 'text/html;charset=utf-8');
-    $this->getResponse()->setBody($html . Class_ScriptLoader::getInstance()->html());
+    $this->_sendResponseWithScripts($html);
   }
 
 
@@ -165,7 +164,7 @@ class NoticeAjaxController extends Zend_Controller_Action {
       $data = Class_Localisation::getLocFromExemplaire($bib,$cote,$code_barres);
 
     // Retour
-    $ret =json_encode($data);
+    $ret = json_encode($data);
     $this->_sendResponse($ret);
   }
 
@@ -177,24 +176,24 @@ class NoticeAjaxController extends Zend_Controller_Action {
     }
 
     if ('' != ($html = $this->view->Notice_Analytics($notice))) {
-      $this->_sendResponse($html);
+      $this->_sendResponseWithScripts($html);
       return;
     }
 
     if ($notice->isPeriodique()) {
       $periodiques = $this->notice->getArticlesPeriodique($this->id_notice);
-      $this->_sendResponse($this->notice_html->getArticlesPeriodique($periodiques));
+      $this->_sendResponseWithScripts($this->notice_html->getArticlesPeriodique($periodiques));
       return;
     }
 
-    $this->_sendResponse($this->view->notice_Entete($notice, ['entete' => Class_Codification::CHAMPS]));
+    $this->_sendResponseWithScripts($this->view->notice_Entete($notice, ['entete' => Class_Codification::CHAMPS]));
   }
 
 
   public function similairesAction()  {
     $notices = $this->notice->getNoticesSimilaires();
     $html = $this->notice_html->getListeNotices($notices, $this->view);
-    $this->_sendResponse($html);
+    $this->_sendResponseWithScripts($html);
   }
 
 
@@ -202,23 +201,15 @@ class NoticeAjaxController extends Zend_Controller_Action {
     $this->notice = Class_Notice::find($this->id_notice);
     $notices=$this->notice->getNoticesMemeSeries();
     $html = $this->notice_html->getListeNotices($notices, $this->view);
-    $this->_sendResponse($html);
+    $this->_sendResponseWithScripts($html);
   }
 
 
-/*  public function auteurAction()  {
-    $this->notice = Class_Notice::find($this->id_notice);
-    $notices = $this->notice->getNoticesMemeAuteur();
-    $html = $this->notice_html->getListeNotices($notices, $this->view);
-    $this->_sendResponse($html);
-    }*/
-
-
   public function resumeAction()  {
     session_write_close();
     $avis = $this->notice->findAllResumes();
     $html=$this->notice_html->getResume($avis);
-    $this->_sendResponse($html);
+    $this->_sendResponseWithScripts($html);
   }
 
 
@@ -226,18 +217,18 @@ class NoticeAjaxController extends Zend_Controller_Action {
     session_write_close();
     if (!$resume = $this->notice->getResume())
       $resume = $this->_('Aucun résumé');
-    $this->_sendResponse($resume);
+    $this->_sendResponseWithScripts($resume);
   }
 
   public function dispoNoticeAction() {
     session_write_close();
-    $this->_sendResponse($this->notice->hasExemplaireDisponible() ? 'true' : 'false');
+    $this->_sendResponseWithScripts($this->notice->hasExemplaireDisponible() ? 'true' : 'false');
   }
 
 
   public function biographieAction() {
     session_write_close();
-    $this->_sendResponse($this->view->biographie($this->notice));
+    $this->_sendResponseWithScripts($this->view->biographie($this->notice));
   }
 
 
@@ -259,7 +250,7 @@ class NoticeAjaxController extends Zend_Controller_Action {
       $html=$this->notice_html->getBandeAnnonce($source,$bo);
     }
     else $html= $html=$this->notice_html->getNonTrouve($this->view->_("Service non disponible"),true);
-    $this->_sendResponse($html);
+    $this->_sendResponseWithScripts($html);
   }
 
 
@@ -272,7 +263,7 @@ class NoticeAjaxController extends Zend_Controller_Action {
       : [];
 
     $html = $this->notice_html->getPhotos($photos);
-    $this->_sendResponse($html);
+    $this->_sendResponseWithScripts($html);
   }
 
 
@@ -285,7 +276,7 @@ class NoticeAjaxController extends Zend_Controller_Action {
       : [];
     $html = $this->notice_html->getBibliographie($biblio, $notice["A"]);
 
-    $this->_sendResponse($html);
+    $this->_sendResponseWithScripts($html);
   }
 
 
@@ -311,7 +302,8 @@ class NoticeAjaxController extends Zend_Controller_Action {
       $html = sprintf('<p>%s</p>', $this->view->_('Aucune ressource correspondante'));
 
     $html = $add_album_tag . $html;
-    $this->_sendResponse($html . Class_ScriptLoader::getInstance()->html());
+
+    $this->_sendResponseWithScripts($html);
   }
 
 
@@ -344,7 +336,7 @@ class NoticeAjaxController extends Zend_Controller_Action {
     if (!$morceaux["nb_resultats"]) $source="";
     $morceaux["auteur"] = $notice->getAuteurPrincipal();
     $html=$this->notice_html->getMorceaux($morceaux,$source);
-    $this->_sendResponse(Class_ScriptLoader::getInstance()->html().$html);
+    $this->_sendResponseWithScripts($html);
   }
 
   public function videomorceauAction() {
@@ -364,14 +356,14 @@ class NoticeAjaxController extends Zend_Controller_Action {
     }
     else
       $html= $html=$this->notice_html->getNonTrouve($this->view->_("Service non disponible"),true);
-    $this->_sendResponse($html);
+    $this->_sendResponseWithScripts($html);
   }
 
 
   public function playerlastfmAction() {
     $lastfm=new Class_WebService_Lastfm();
     $html=$lastfm->getPlayer($_REQUEST["url"]);
-    $this->_sendResponse($html);
+    $this->_sendResponseWithScripts($html);
   }
 
 
@@ -382,7 +374,7 @@ class NoticeAjaxController extends Zend_Controller_Action {
     if ($num_video = $this->_getParam("num_video", 0))  {
       $num_video = $num_video-1;
       $html.=$_SESSION["video_interview"][$num_video]["player"];
-      $this->_sendResponse('<style>*{margin:0;padding:0}</style>'.$html);
+      $this->_sendResponseWithScripts('<style>*{margin:0;padding:0}</style>'.$html);
       return;
     }
 
@@ -390,7 +382,7 @@ class NoticeAjaxController extends Zend_Controller_Action {
     $notice=$this->notice->getNotice("JA");
     if(!trim($notice["A"])) {
       $html=$this->notice_html->getNonTrouve($this->view->_("Cette notice n'a pas d'auteur."),true);
-      $this->_sendResponse($html);
+      $this->_sendResponseWithScripts($html);
       return;
     }
 
@@ -405,26 +397,26 @@ class NoticeAjaxController extends Zend_Controller_Action {
       $videos = $data["videos"];
       $_SESSION["video_interview"]=$videos;
       $html=$this->notice_html->getInterviews($source, $videos, $width, $height);
-      $this->_sendResponse($html);
+      $this->_sendResponseWithScripts($html);
       return;
     }
 
     $html = $this->notice_html->getNonTrouve($this->view->_("Service non disponible"),true);
-    $this->_sendResponse($html);
+    $this->_sendResponseWithScripts($html);
   }
 
 
   public function avisAction() {
     session_write_close();
     // Lire la notice
-    if (!$notice = Class_Notice::getLoader()->find($this->id_notice)) {
+    if (!$notice = Class_Notice::find($this->id_notice)) {
       $this->_sendResponse('');
       return;
     }
 
     $all_avis = $notice->getAllAvisPerSource($this->_getParam("page", 0));
 
-    $this->_sendResponse($this->view->Notice_Avis($notice,$all_avis, $this->_request->getParams()));
+    $this->_sendResponseWithScripts($this->view->Notice_Avis($notice,$all_avis, $this->_request->getParams()));
   }
 
 
@@ -443,11 +435,12 @@ class NoticeAjaxController extends Zend_Controller_Action {
     $notice = Class_Notice::getLoader()->find($this->id_notice);
 
     $html = $this->view->getHelper('Avis')->getAvisPopup($notice, $notice->getAvisAbonne());
-    $this->_sendResponse(Class_ScriptLoader::getInstance()
-                         ->addOPACStyleSheet('global')
-                         ->addSkinStyleSheet('global')
-                         ->html()
-                         .$html);
+
+    Class_ScriptLoader::getInstance()
+      ->addOPACStyleSheet('global')
+      ->addSkinStyleSheet('global');
+
+    $this->_sendResponseWithScripts($html);
   }
 
 
@@ -455,11 +448,11 @@ class NoticeAjaxController extends Zend_Controller_Action {
     session_write_close();
     $notice = Class_Notice::getLoader()->find($this->id_notice);
     $html = $this->view->getHelper('Avis')->getAvisPopup($notice, $notice->getAvisBibliothecaire());
-    $this->_sendResponse(Class_ScriptLoader::getInstance()
-                         ->addOPACStyleSheet('global')
-                         ->addSkinStyleSheet('global')
-                         ->html()
-                         .$html);
+
+    Class_ScriptLoader::getInstance()
+      ->addOPACStyleSheet('global')
+      ->addSkinStyleSheet('global');
+    $this->_sendResponseWithScripts($html);
   }
 
 
@@ -477,7 +470,7 @@ class NoticeAjaxController extends Zend_Controller_Action {
     foreach($blocs as $bloc)
       $html .= sprintf('<div id="BW_%s"></div>', $bloc);
 
-    $this->_sendResponse($html);
+    $this->_sendResponseWithScripts($html);
   }
 
 
@@ -528,7 +521,7 @@ class NoticeAjaxController extends Zend_Controller_Action {
                                 $this->view->url(['controller' => 'noticeajax',
                                                   'action' => 'cvs-search']));
     $html .= '</div>';
-    $this->_sendResponse($html);
+    $this->_sendResponseWithScripts($html);
 
   }
 
@@ -543,12 +536,21 @@ class NoticeAjaxController extends Zend_Controller_Action {
       return;
     }
 
-    $this->_sendResponse($this->view->frbr($model));
+    $this->_sendResponseWithScripts($this->view->frbr($model));
+  }
+
+
+  protected function _sendResponseWithScripts($html) {
+    Class_ScriptLoader::getInstance()
+      ->addAdminScript('onload_utils')
+      ->addJQueryReady('setupAnchorsTarget();');
+
+    $this->_sendResponse(Class_ScriptLoader::getInstance()->html() . $html);
   }
 
 
-  protected function _sendResponse($html) {
+  protected function _sendResponse($data) {
     $this->getResponse()->setHeader('Content-Type', 'text/html;charset=utf-8');
-    $this->getResponse()->setBody($html);
+    $this->getResponse()->setBody($data);
   }
 }
diff --git a/application/modules/opac/views/scripts/formulaire/add.phtml b/application/modules/opac/views/scripts/formulaire/add.phtml
index 0f524caa04bc6470daf775eea2116125a3c87890..92741cd730e721fbeb4204560b58570aed4611f4 100644
--- a/application/modules/opac/views/scripts/formulaire/add.phtml
+++ b/application/modules/opac/views/scripts/formulaire/add.phtml
@@ -10,6 +10,10 @@ foreach ($this->datas as $key => $value)
 
 echo '</ul>';
 
+if ($this->email_sent == true) {
+  echo $this->_('Un courriel a été envoyé.');
+}
+
 echo $this->closeBoite();
 
 ?>
diff --git a/cosmogramme/php/_init.php b/cosmogramme/php/_init.php
index 633bd0493dc62447f2d64905cc6f127767b62ea6..704fff1475ef7f28000babf11950f8c16ce10a18 100644
--- a/cosmogramme/php/_init.php
+++ b/cosmogramme/php/_init.php
@@ -1,7 +1,7 @@
 <?php
 error_reporting(E_ERROR | E_PARSE);
 
-define("PATCH_LEVEL","264");
+define("PATCH_LEVEL","267");
 
 define("APPLI","cosmogramme");
 define("COSMOPATH", "/var/www/html/vhosts/opac2/www/htdocs");
@@ -73,4 +73,4 @@ if (!session_id())
 if (isset($_REQUEST["action"]) && $_REQUEST['action'] == "logout") unset($_SESSION["passe"]);
 if (!isset($_SESSION["passe"])) include("_identification.php");
 
-?>
\ No newline at end of file
+?>
diff --git a/cosmogramme/php/classes/classe_notice_integration.php b/cosmogramme/php/classes/classe_notice_integration.php
index 74f4c5da3ef76d04796890bc994031380523ac43..aed9609ac8f23eca8c6488e3ad81815859f09875 100644
--- a/cosmogramme/php/classes/classe_notice_integration.php
+++ b/cosmogramme/php/classes/classe_notice_integration.php
@@ -38,21 +38,21 @@ class notice_integration {
     RECORD_SUCCINCT = 7,
     STATUS_NOTFOUND = 'non trouvée';
 
-	private $id_profil;									// Id du profil de données initialisé
-	private $format;										// Format de fichier 0=unimarc
-	private $id_article_periodique;			// Mode d'indentification des articles de periodiques
-	private $type_doc_force;						// Type de document forcé dans maj_auto
-	private $analyseur;									// Instance de la classe qui découpe la notice
-	private $indexation;								// Instance de la classe d'indexation
-	private $id_bib;										// Bibliotheque pour qui on integre @deprecated, see below setParamsIntegration
-	private $id_int_bib;								// Intégration programmée pour qui on integre
-	private $type_operation;						// Maj ou suppression
-	private $notice;										// Structure notice en cours de traitement
-	private $qualite_bib;								// Code qualite de la bib
-	private $sigb;											// Sigb de la bib
-	private $statut;										// Statut de la notice traitee
-
-	public  $libStatut = [self::RECORD_REJECT =>  "Rejetées",
+  private $id_profil;                  // Id du profil de données initialisé
+  private $format;                    // Format de fichier 0=unimarc
+  private $id_article_periodique;      // Mode d'indentification des articles de periodiques
+  private $type_doc_force;            // Type de document forcé dans maj_auto
+  private $analyseur;                  // Instance de la classe qui découpe la notice
+  private $indexation;                // Instance de la classe d'indexation
+  private $id_bib;                    // Bibliotheque pour qui on integre @deprecated, see below setParamsIntegration
+  private $id_int_bib;                // Intégration programmée pour qui on integre
+  private $type_operation;            // Maj ou suppression
+  private $notice;                    // Structure notice en cours de traitement
+  private $qualite_bib;                // Code qualite de la bib
+  private $sigb;                      // Sigb de la bib
+  private $statut;                    // Statut de la notice traitee
+
+  public  $libStatut = [self::RECORD_REJECT =>  "Rejetées",
                         self::RECORD_INSERT =>  "Créée",
                         self::RECORD_DELETE =>  "Supprimée",
                         self::RECORD_FULLUPDATE => "Mise à jour notice et exemplaires",
@@ -61,886 +61,865 @@ class notice_integration {
                         self::RECORD_UPGRADE => "Homogénéisées",
                         self::RECORD_SUCCINCT =>"Mises en notices succintes"];
 
-	private $erreur;										// Message d'erreur notice traitee
-	private $filtrer_fulltext;					// Vient de la variable filtrer_fulltext.
-	private $identification;						// Mode d'identification de la notice
-	private $notice_sgbd;								// Instance unimarc pour notices de la base
-	private $mode_doublon;							// Mode de dédoublonnage (tous identifiants ou clef alpha prioritaire)
-	private $url_site;                  // Url d'origine du site opac
-	private $flag_koha=false;						// flag pour réentrance des notices de periodiques koha
-
-	/** @category testing */
-	protected $_service_runner;
-
-	public function __construct() {
-		$this->indexation=new indexation();
-		$this->filtrer_fulltext = Class_CosmoVar::get("filtrer_fulltext");
-		$this->mode_doublon = Class_CosmoVar::get("mode_doublon");
-		$this->notice_sgbd=new notice_unimarc();
-	}
-
-
-	function setParamsIntegration($id_bib,$type_operation,$id_profil,$type_doc_force="")	{
-		/**
-		 * $this->id_bib is deprecated, use $this->id_int_bib instead.
-		 * @see http://forge.afi-sa.fr/issues/14279
-		 */
-		$this->id_bib=$this->id_int_bib=$id_bib;
-		$this->type_operation=$type_operation;
-		$this->type_doc_force=$type_doc_force;
-
-		if (!$bib = Class_IntBib::find($id_bib))
-			$bib = Class_IntBib::newInstance();
-
-		$this->qualite_bib = $bib->getQualite();
-		$this->sigb = $bib->getSigb();
-
-		$this->id_profil=$id_profil;
-		if($id_profil < 0)$format=1; // Paniers d'homogeneisation
-		else
-		{
-			$profil = (new profil_donnees())->getProfil($id_profil);
-			$this->id_article_periodique = $profil['id_article_periodique'];
-
-			$format = $profil['format'];
-			if (!$format) $format=0;
-
-			if ($profil['type_fichier']>9)
-				$format = $profil['type_fichier'];
-		}
-		$this->format=$format;
-		unset($this->analyseur);
-
-		switch($format)
-		{
-			// Unimarc
-			case Class_IntProfilDonnees::FORMAT_UNIMARC:
-			case Class_IntProfilDonnees::FORMAT_UNIMARC_XML:
-				$this->analyseur=new notice_unimarc();
-				break;
-			// archives calice
-			case 10:
-				require_once("classe_notice_archive_calice.php");
-				$this->analyseur=new notice_archive_calice();
-				break;
-			// notices avenio
-			case 12:
-				require_once("classe_notice_avenio.php");
-				$this->analyseur=new notice_avenio($id_bib);
-				break;
-			// marc21
-			case Class_IntProfilDonnees::FORMAT_MARC21:
-				require_once("classe_notice_marc21.php");
-				$this->analyseur=new notice_marc21();
-				break;
-			// Ascii
-			default:
-				require_once("classe_notice_ascii.php");
-				$this->analyseur=new notice_ascii();
-				break;
-		}
-	}
-
-
-	public function traiteNotice($data) {
-		global $sql;
-		$id_bib=$this->id_bib;
-		if(! $this->analyseur ) return false;
-		$this->statut=0;
-		$this->erreur="";
-		unset($this->notice);
-
-		if(!$this->analyseur->ouvrirNotice($data,$this->id_profil,$this->sigb,$this->type_doc_force))
-		{
-			$this->erreur=$this->analyseur->getLastError();
-			return 0;
-		}
-		$this->notice=$this->analyseur->getNoticeIntegration();
-
-		// article de périodique
-		if($this->notice["type_doc"]==100)
-		{
-			$this->ecrireArticlePeriodique();
-			return;
-		}
-
-		// Chercher la notice dans la base
-		$id_notice=$this->chercheNotice();
-		// Traiter le type d'operation : suppressions
-		if($this->type_operation == 1)
-		{
-				$this->statut=2;
-				if($this->format == 0 )$this->supprimerNotice($id_notice,$this->notice["id_origine"]);
-				else $this->supprimerExemplaire($id_notice,$this->notice["exemplaires"][0]);
-				return;
-		}
-		// Notice a supprimer
-		if($this->notice["statut"]==1)
-		{
-			$this->statut=2;
-			$this->supprimerNotice($id_notice,$this->notice["id_origine"]);
-			return;
-		}
-
-		// suppression ou creation des articles si périodique
-		if($this->notice["type_doc"]==2)
-		{
-
-			// Periodiques Koha et orphee (1 exemplaire pour chaque numéro)
-			if(($this->id_article_periodique==3 or $this->id_article_periodique==4) and $this->flag_koha==false)
-			{
-				$this->flag_koha=true;
-				$ret=$this->traitePeriodiquesKoha();
-				$this->flag_koha=false;
-				return $ret;
-			}
-
-			// pergame : on efface tous les articles
-			if($this->id_article_periodique == 1)
-			{
-				$clef_chapeau=$this->notice["clef_chapeau"];
-				$clef_numero=addslashes($this->notice["tome_alpha"]);
-				$date=dateDuJour(0);
-				Class_Notice_SerialArticles::deleteBy(['clef_chapeau' => $clef_chapeau,
-																							 'clef_numero' => $clef_numero,
-																							 'date_maj not' => $date]);
-			}
-
-			// opsys indexpresse : on cree les articles manquants
-			if($this->id_article_periodique == 2 and $this->notice["articles_periodiques"])
-			{
-				$enreg=array("clef_chapeau"=>$this->notice["articles_periodiques"]["clef_chapeau"],
-										"clef_numero"=>$this->notice["articles_periodiques"]["clef_numero"],
-										"date_maj"=>date("Y-m-d"),
-										);
-				foreach($this->notice["articles_periodiques"]["articles"] as $id_unimarc)
-				{
-					$clef_unimarc=intval($id_unimarc);
-					if(!$clef_unimarc) { $this->notice["warnings"][]=array("Identifiant article de périodique incorrect",$id_unimarc); continue; }
-					$existe=$sql->fetchOne("select count(*) from notices_articles where clef_unimarc='$clef_unimarc'");
-					if($existe)
-					{
-						unset($enreg["clef_unimarc"]);
-						$sql->update("update notices_articles set @SET@ where clef_unimarc='$clef_unimarc'",$enreg);
-					}
-					else
-					{
-						$enreg["clef_unimarc"]=$clef_unimarc;
-						$sql->insert("notices_articles",$enreg);
-					}
-				}
-			}
-		}
-		// Mise a jour
-		if(!$id_notice) {
-			$this->notice["qualite"]=$this->qualite_bib;
-			$id_notice=$this->insertNotice();
-			if(!$id_notice) return;
-			else $this->statut=1;
-
-		} else {
-			$this->updateNoticeWithId($id_notice);
-		}
-		$this->ecrireExemplaires($id_notice);
+  private $erreur;                    // Message d'erreur notice traitee
+  private $filtrer_fulltext;          // Vient de la variable filtrer_fulltext.
+  private $identification;            // Mode d'identification de la notice
+  private $notice_sgbd;                // Instance unimarc pour notices de la base
+  private $mode_doublon;              // Mode de dédoublonnage (tous identifiants ou clef alpha prioritaire)
+  private $url_site;                  // Url d'origine du site opac
+  private $flag_koha=false;            // flag pour réentrance des notices de periodiques koha
+
+  /** @category testing */
+  protected $_service_runner;
+
+  public function __construct() {
+    $this->indexation=new indexation();
+    $this->filtrer_fulltext = Class_CosmoVar::get("filtrer_fulltext");
+    $this->mode_doublon = Class_CosmoVar::get("mode_doublon");
+    $this->notice_sgbd=new notice_unimarc();
+  }
+
+
+  function setParamsIntegration($id_bib,$type_operation,$id_profil,$type_doc_force="")  {
+    /**
+     * $this->id_bib is deprecated, use $this->id_int_bib instead.
+     * @see http://forge.afi-sa.fr/issues/14279
+     */
+    $this->id_bib=$this->id_int_bib=$id_bib;
+    $this->type_operation=$type_operation;
+    $this->type_doc_force=$type_doc_force;
+
+    if (!$bib = Class_IntBib::find($id_bib))
+      $bib = Class_IntBib::newInstance();
+
+    $this->qualite_bib = $bib->getQualite();
+    $this->sigb = $bib->getSigb();
+
+    $this->id_profil=$id_profil;
+    if($id_profil < 0)$format=1; // Paniers d'homogeneisation
+    else
+    {
+      $profil = (new profil_donnees())->getProfil($id_profil);
+      $this->id_article_periodique = $profil['id_article_periodique'];
+
+      $format = $profil['format'];
+      if (!$format) $format=0;
+
+      if ($profil['type_fichier']>9)
+        $format = $profil['type_fichier'];
+    }
+    $this->format=$format;
+    unset($this->analyseur);
+
+    switch($format)
+    {
+      // Unimarc
+      case Class_IntProfilDonnees::FORMAT_UNIMARC:
+      case Class_IntProfilDonnees::FORMAT_UNIMARC_XML:
+        $this->analyseur=new notice_unimarc();
+        break;
+      // archives calice
+      case 10:
+        require_once("classe_notice_archive_calice.php");
+        $this->analyseur=new notice_archive_calice();
+        break;
+      // notices avenio
+      case 12:
+        require_once("classe_notice_avenio.php");
+        $this->analyseur=new notice_avenio($id_bib);
+        break;
+      // marc21
+      case Class_IntProfilDonnees::FORMAT_MARC21:
+        require_once("classe_notice_marc21.php");
+        $this->analyseur=new notice_marc21();
+        break;
+      // Ascii
+      default:
+        require_once("classe_notice_ascii.php");
+        $this->analyseur=new notice_ascii();
+        break;
+    }
+  }
+
+
+  public function traiteNotice($data) {
+    global $sql;
+    $id_bib=$this->id_bib;
+    if(! $this->analyseur ) return false;
+    $this->statut=0;
+    $this->erreur="";
+    unset($this->notice);
+
+    if(!$this->analyseur->ouvrirNotice($data,$this->id_profil,$this->sigb,$this->type_doc_force))
+    {
+      $this->erreur=$this->analyseur->getLastError();
+      return 0;
+    }
+    $this->notice=$this->analyseur->getNoticeIntegration();
+
+    // article de périodique
+    if($this->notice["type_doc"]==100)
+    {
+      $this->ecrireArticlePeriodique();
+      return;
+    }
+
+    // Chercher la notice dans la base
+    $id_notice=$this->chercheNotice();
+    // Traiter le type d'operation : suppressions
+    if($this->type_operation == 1)
+    {
+        $this->statut=2;
+        if($this->format == 0 )$this->supprimerNotice($id_notice,$this->notice["id_origine"]);
+        else $this->supprimerExemplaire($id_notice,$this->notice["exemplaires"][0]);
+        return;
+    }
+    // Notice a supprimer
+    if($this->notice["statut"]==1)
+    {
+      $this->statut=2;
+      $this->supprimerNotice($id_notice,$this->notice["id_origine"]);
+      return;
+    }
+
+    // suppression ou creation des articles si périodique
+    if($this->notice["type_doc"]==2)
+    {
+
+      // Periodiques Koha et orphee (1 exemplaire pour chaque numéro)
+      if(($this->id_article_periodique==3 or $this->id_article_periodique==4) and $this->flag_koha==false)
+      {
+        $this->flag_koha=true;
+        $ret=$this->traitePeriodiquesKoha();
+        $this->flag_koha=false;
+        return $ret;
+      }
+
+      // pergame : on efface tous les articles
+      if($this->id_article_periodique == 1)
+      {
+        $clef_chapeau=$this->notice["clef_chapeau"];
+        $clef_numero=addslashes($this->notice["tome_alpha"]);
+        $date=dateDuJour(0);
+        Class_Notice_SerialArticles::deleteBy(['clef_chapeau' => $clef_chapeau,
+                                               'clef_numero' => $clef_numero,
+                                               'date_maj not' => $date]);
+      }
+
+      // opsys indexpresse : on cree les articles manquants
+      if($this->id_article_periodique == 2 and $this->notice["articles_periodiques"])
+      {
+        $enreg=array("clef_chapeau"=>$this->notice["articles_periodiques"]["clef_chapeau"],
+                    "clef_numero"=>$this->notice["articles_periodiques"]["clef_numero"],
+                    "date_maj"=>date("Y-m-d"),
+                    );
+        foreach($this->notice["articles_periodiques"]["articles"] as $id_unimarc)
+        {
+          $clef_unimarc=intval($id_unimarc);
+          if(!$clef_unimarc) { $this->notice["warnings"][]=array("Identifiant article de périodique incorrect",$id_unimarc); continue; }
+          $existe=$sql->fetchOne("select count(*) from notices_articles where clef_unimarc='$clef_unimarc'");
+          if($existe)
+          {
+            unset($enreg["clef_unimarc"]);
+            $sql->update("update notices_articles set @SET@ where clef_unimarc='$clef_unimarc'",$enreg);
+          }
+          else
+          {
+            $enreg["clef_unimarc"]=$clef_unimarc;
+            $sql->insert("notices_articles",$enreg);
+          }
+        }
+      }
+    }
+    // Mise a jour
+    if(!$id_notice) {
+      $this->notice["qualite"]=$this->qualite_bib;
+      $id_notice=$this->insertNotice();
+      if(!$id_notice) return;
+      else $this->statut=1;
+
+    } else {
+      $this->updateNoticeWithId($id_notice);
+    }
+    $this->ecrireExemplaires($id_notice);
     return $this->notice;
-	}
-
-
-	protected function updateNoticeWithId($id_notice) {
-		if(($this->identification["statut"] == "clef_alpha") && $this->flag_koha)
-			return $id_notice;
-
-		return $this->updateNotice($id_notice,$this->qualite_bib);
-	}
-
-
-	public function traiteHomogene($id_notice, $isbn, $ean, $id_commerciale, $no_request) {
-		global $sql;
-
-		// Appel du service
-		$args["isbn"]=$isbn;
-		$args["ean"]= $ean;
-		$args["id_commerciale"]=$id_commerciale;
-		$args["no_request"]=$no_request;
-		$ret=communication::runService(4,$args);
-
-		// Formatter la reponse
-		$ret["timeout"]=10;
-
-		// Statut not found : Mise a jour nombre de retries
-		if ($ret["statut_z3950"] == '1') {
-			$notice = Class_Notice::find($id_notice);
-			$retry = $notice->getZ3950Retry() + 1;
-			$notice->setZ3950Retry($retry)->save();
-		}
-
-		// Statut ok : on remplace la notice
-		if(!$this->analyseur) $this->analyseur=new notice_unimarc();
-		if($ret["statut_z3950"] > "1")
-		{
-			$this->analyseur->ouvrirNotice($ret["unimarc"],
-																		 $args['isbn']
-																		 ? profil_donnees::HOMOGENIZATION_ISBN
-																		 : profil_donnees::HOMOGENIZATION_EAN);
-			$this->notice=$this->analyseur->getNoticeIntegration();
-			$qualite=getVariable("homogene_code_qualite");
-			$this->updateNotice($id_notice,$qualite);
-		}
-		return $ret;
-	}
-
-
-	public function traiteSuccinte($enreg) {
-		global $sql;
-
-		extract($enreg);
-		/**
-		 * $this->id_bib is deprecated, use $this->id_int_bib instead.
-		 * @see http://forge.afi-sa.fr/issues/14279
-		 */
-		$this->id_bib = $this->id_int_bib = $id_bib;
-		$notice = unserialize($data);
-		$this->notice = $notice;
-
-		// On la cherche dans la base
-		if ($id_notice = $this->chercheNotice()) {
-			$this->handleSuccinteLocaly($notice, $id_notice, $sql);
-			$ret["statut"]=4;
-		}
-
-		// On cherche sur les serveurs z3950
-		else {
-			$args["isbn"]=$notice["isbn"];
-			$args["ean"]= $notice["ean"];
-			$args["id_commerciale"]=$notice["id_commerciale"];
-			$args["no_request"]=getVariable("Z3950_cache_only");
-			$ret = $this->getServiceRunner()->run(4, $args);
-
-			// Statut ok : on remplace la notice
-			if (!$this->analyseur)
-				$this->analyseur = new notice_unimarc();
-
-			if ($ret["statut_z3950"] > "1") {
-				$this->analyseur->ouvrirNotice($ret["unimarc"],1);
-				$this->notice=$this->analyseur->getNoticeIntegration();
-				$this->notice["id_origine"]=$notice["id_origine"];
-				$this->notice["statut_exemplaires"] = $notice["statut_exemplaires"];
-				$this->notice["exemplaires"] = $notice["exemplaires"];
-				$this->notice["qualite"]=getVariable("homogene_code_qualite");
-				if ($this->notice["titre_princ"]
-						&& $id_notice = $this->insertNotice()) {
-					$this->ecrireExemplaires($id_notice);
-					$ret["statut"] = 1;
-				}
-				$ret["statut"] = 0;
-			} else {
-				$ret["statut"] = 0;
-			}
-		}
-
-		// Mise a jour
-		$ret["id_notice"]=$id_notice;
-		$ret["id_bib"]=$id_bib;
-		$ret["isbn"]=$notice["isbn"];
-		$ret["ean"]= $notice["ean"];
-		$ret["id_commerciale"] = $notice["id_commerciale"];
-
-		$query = ($id_notice)
-			? "delete from notices_succintes where id=$id"
-			: "Update notices_succintes set z3950_retry = z3950_retry +1 Where id=$id";
-		$sql->execute($query);
-		return $ret;
-	}
-
-
-	protected function handleSuccinteLocaly($succinte, $id_notice, $sql) {
-		$unimarc=$sql->fetchOne("select unimarc from notices where id_notice=$id_notice");
-		$this->notice_sgbd->ouvrirNotice($unimarc,0);
-		$this->notice=$this->notice_sgbd->getNoticeIntegration();
-		$this->notice["id_origine"]=$succinte["id_origine"];
-		$this->notice["statut_exemplaires"] = $succinte["statut_exemplaires"];
-		$this->notice["exemplaires"] = $succinte["exemplaires"];
-		$this->updateNotice($id_notice, $this->notice["qualite"]);
-		$this->ecrireExemplaires($id_notice);
-	}
-
-
-	public function traitePseudoNotice($type_doc, $enreg) {
-		global $sql;
-
-		if (!$enreg['id_bib'])
-			$enreg['id_bib'] = $sql->fetchOne('select min(id_bib) from int_bib');
-
-		$notice = Class_Indexation_PseudoNotice::newWith($type_doc, $enreg);
-
-		if (!$notice->isValid() || !$notice->save())
-			return ['statut' => 0, 'id_notice' => 0];
-
-		return ['statut' => 1,
-						'id_notice' => $notice->getId(),
-						'unimarc' => $notice->getUnimarc(),
-						'code_barres' => $notice->getCodeBarres(),
-						'facettes' => $notice->getFacettes()];
-	}
-
-
-	/**
-	 * 1 item by number
-	 */
-	private function traitePeriodiquesKoha() {
-		if (0 == count($this->notice['exemplaires']))
-			return [];
-
-		$number_map = [3 => 'v', 4 => '6'];
-		if (!array_key_exists($this->id_article_periodique, $number_map))
-			return [];
-
-		$champ_numero = $number_map[$this->id_article_periodique];
-		$unimarc = $this->notice['unimarc'];
-
-		foreach($this->notice['exemplaires'] as $exemplaire) {
-			$this->notice_sgbd->ouvrirNotice($unimarc,
-																			 $this->id_profil,
-																			 $this->sigb,
-																			 $this->type_doc_force);
-
-			$champs = unserialize($exemplaire['zone995']);
-			$table_champs = [];
-			$numero = '';
-			foreach($champs as $champ) {
-				$table_champs[] = [$champ['code'], $champ['valeur']];
-
-				if ($champ['code'] != $champ_numero)
-					continue;
-
-
-				if (preg_match('/(\d+)/', $champ['valeur'], $numbers)) {
-					$numero = $numbers[0];
-					$complement_titre = trim(substr($champ['valeur'], strpos($champ['valeur'], $numero) + strlen($numero)));
-				} else {
-					$numero = $champ['valeur'];
-				}
-
-			}
-
-			$this->notice_sgbd->add_field('461', '11', 't' . $this->notice['titre_princ']);
-			$this->notice_sgbd->add_field('461', '11', 'v' . $numero);
-			if ($complement_titre)
-				$this->notice_sgbd->add_field('461', '11', 'o' . $complement_titre);
-			$this->notice_sgbd->add_field('995', '  ', $table_champs);
-			$this->notice_sgbd->update();
-			$data = $this->notice_sgbd->getFullRecord();
-			$this->traiteNotice($data);
-		}
-	}
+  }
+
+
+  protected function updateNoticeWithId($id_notice) {
+    if(($this->identification["statut"] == "clef_alpha") && $this->flag_koha)
+      return $id_notice;
+
+    return $this->updateNotice($id_notice,$this->qualite_bib);
+  }
+
+
+  public function traiteHomogene($id_notice, $isbn, $ean, $id_commerciale, $no_request) {
+    global $sql;
+
+    // Appel du service
+    $args["isbn"]=$isbn;
+    $args["ean"]= $ean;
+    $args["id_commerciale"]=$id_commerciale;
+    $args["no_request"]=$no_request;
+    $ret=communication::runService(4,$args);
+
+    // Formatter la reponse
+    $ret["timeout"]=10;
+
+    // Statut not found : Mise a jour nombre de retries
+    if ($ret["statut_z3950"] == '1') {
+      $notice = Class_Notice::find($id_notice);
+      $retry = $notice->getZ3950Retry() + 1;
+      $notice->setZ3950Retry($retry)->save();
+    }
+
+    // Statut ok : on remplace la notice
+    if(!$this->analyseur) $this->analyseur=new notice_unimarc();
+    if($ret["statut_z3950"] > "1")
+    {
+      $this->analyseur->ouvrirNotice($ret["unimarc"],
+                                     $args['isbn']
+                                     ? profil_donnees::HOMOGENIZATION_ISBN
+                                     : profil_donnees::HOMOGENIZATION_EAN);
+      $this->notice=$this->analyseur->getNoticeIntegration();
+      $qualite=getVariable("homogene_code_qualite");
+      $this->updateNotice($id_notice,$qualite);
+    }
+    return $ret;
+  }
+
+
+  public function traiteSuccinte($enreg) {
+    global $sql;
+
+    extract($enreg);
+    /**
+     * $this->id_bib is deprecated, use $this->id_int_bib instead.
+     * @see http://forge.afi-sa.fr/issues/14279
+     */
+    $this->id_bib = $this->id_int_bib = $id_bib;
+    $notice = unserialize($data);
+    $this->notice = $notice;
+
+    // On la cherche dans la base
+    if ($id_notice = $this->chercheNotice()) {
+      $this->handleSuccinteLocaly($notice, $id_notice, $sql);
+      $ret["statut"]=4;
+    }
+
+    // On cherche sur les serveurs z3950
+    else {
+      $args["isbn"]=$notice["isbn"];
+      $args["ean"]= $notice["ean"];
+      $args["id_commerciale"]=$notice["id_commerciale"];
+      $args["no_request"]=getVariable("Z3950_cache_only");
+      $ret = $this->getServiceRunner()->run(4, $args);
+
+      // Statut ok : on remplace la notice
+      if (!$this->analyseur)
+        $this->analyseur = new notice_unimarc();
+
+      if ($ret["statut_z3950"] > "1") {
+        $this->analyseur->ouvrirNotice($ret["unimarc"],1);
+        $this->notice=$this->analyseur->getNoticeIntegration();
+        $this->notice["id_origine"]=$notice["id_origine"];
+        $this->notice["statut_exemplaires"] = $notice["statut_exemplaires"];
+        $this->notice["exemplaires"] = $notice["exemplaires"];
+        $this->notice["qualite"]=getVariable("homogene_code_qualite");
+        if ($this->notice["titre_princ"]
+            && $id_notice = $this->insertNotice()) {
+          $this->ecrireExemplaires($id_notice);
+          $ret["statut"] = 1;
+        }
+        $ret["statut"] = 0;
+      } else {
+        $ret["statut"] = 0;
+      }
+    }
+
+    // Mise a jour
+    $ret["id_notice"]=$id_notice;
+    $ret["id_bib"]=$id_bib;
+    $ret["isbn"]=$notice["isbn"];
+    $ret["ean"]= $notice["ean"];
+    $ret["id_commerciale"] = $notice["id_commerciale"];
+
+    $query = ($id_notice)
+      ? "delete from notices_succintes where id=$id"
+      : "Update notices_succintes set z3950_retry = z3950_retry +1 Where id=$id";
+    $sql->execute($query);
+    return $ret;
+  }
+
+
+  protected function handleSuccinteLocaly($succinte, $id_notice, $sql) {
+    $unimarc=$sql->fetchOne("select unimarc from notices where id_notice=$id_notice");
+    $this->notice_sgbd->ouvrirNotice($unimarc,0);
+    $this->notice=$this->notice_sgbd->getNoticeIntegration();
+    $this->notice["id_origine"]=$succinte["id_origine"];
+    $this->notice["statut_exemplaires"] = $succinte["statut_exemplaires"];
+    $this->notice["exemplaires"] = $succinte["exemplaires"];
+    $this->updateNotice($id_notice, $this->notice["qualite"]);
+    $this->ecrireExemplaires($id_notice);
+  }
+
+
+  /**
+   * 1 item by number
+   */
+  private function traitePeriodiquesKoha() {
+    if (0 == count($this->notice['exemplaires']))
+      return [];
+
+    $number_map = [3 => 'v', 4 => '6'];
+    if (!array_key_exists($this->id_article_periodique, $number_map))
+      return [];
+
+    $champ_numero = $number_map[$this->id_article_periodique];
+    $unimarc = $this->notice['unimarc'];
+
+    foreach($this->notice['exemplaires'] as $exemplaire) {
+      $this->notice_sgbd->ouvrirNotice($unimarc,
+                                       $this->id_profil,
+                                       $this->sigb,
+                                       $this->type_doc_force);
+
+      $champs = unserialize($exemplaire['zone995']);
+      $table_champs = [];
+      $numero = '';
+      foreach($champs as $champ) {
+        $table_champs[] = [$champ['code'], $champ['valeur']];
+
+        if ($champ['code'] != $champ_numero)
+          continue;
+
+
+        if (preg_match('/(\d+)/', $champ['valeur'], $numbers)) {
+          $numero = $numbers[0];
+          $complement_titre = trim(substr($champ['valeur'], strpos($champ['valeur'], $numero) + strlen($numero)));
+        } else {
+          $numero = $champ['valeur'];
+        }
+
+      }
+
+      $this->notice_sgbd->add_field('461', '11', 't' . $this->notice['titre_princ']);
+      $this->notice_sgbd->add_field('461', '11', 'v' . $numero);
+      if ($complement_titre)
+        $this->notice_sgbd->add_field('461', '11', 'o' . $complement_titre);
+      $this->notice_sgbd->add_field('995', '  ', $table_champs);
+      $this->notice_sgbd->update();
+      $data = $this->notice_sgbd->getFullRecord();
+      $this->traiteNotice($data);
+    }
+  }
 
 // ----------------------------------------------------------------
 // Retourne l'url d'origine du site (ex: http://opac3.pergame.net/)
 // ----------------------------------------------------------------
-	private function getUrlSite() {
-		if (isset($this->url_site))
-			return $this->url_site;
+  private function getUrlSite() {
+    if (isset($this->url_site))
+      return $this->url_site;
+
+    $adresse=getVariable("url_site");
+    if(strtolower(substr($adresse,0,7)) !="http://") $adresse="http://".$adresse;
+    if(substr($adresse,-1,1)!="/") $adresse.="/";
+    return $this->url_site = $adresse;
+  }
+
+
+  private function chercheNotice() {
+    $attributes = [];
+    if(!$this->mode_doublon)
+      $attributes = [['isbn', $this->notice['isbn13']],
+                     ['isbn', $this->notice['isbn10']],
+                     ['ean', $this->notice['ean']],
+                     ['id_commerciale', $this->notice['id_commerciale']]];
+
+    if ($this->mode_doublon == Class_CosmoVar::DOUBLE_SEARCH_ALPHA_KEY)
+      $attributes = [['clef_alpha', $this->notice['clef_alpha']]];
+
+    $this->identification = ['statut' => static::STATUS_NOTFOUND];
+
+    if ($id_notice = $this->searchRecordByItemsBarcodes()) {
+      $this->identification['statut'] = 'code_barres';
+      $this->identification['code_barres'] = $id_notice;
 
-		$adresse=getVariable("url_site");
-		if(strtolower(substr($adresse,0,7)) !="http://") $adresse="http://".$adresse;
-		if(substr($adresse,-1,1)!="/") $adresse.="/";
-		return $this->url_site = $adresse;
-	}
+      return $id_notice;
+    }
+
+    foreach ($attributes as $attr) {
+      list($key, $value) = $attr;
+
+      if ($id_notice = $this->searchRecordBy($key, $value)) {
+        $this->identification['statut'] = $key;
+        $this->identification[$key] = $id_notice;
+
+        return $id_notice;
+      }
+    }
+
+    return '';
+  }
+
+
+  private function searchRecordByItemsBarcodes() {
+    if ($this->notice['statut_exemplaires']['nb_ex'] <= 0)
+      return '';
 
+    $unicite_codes_barres = getVariable('unicite_code_barres');
+    $condition = [];
 
-	private function chercheNotice() {
-		$attributes = [];
-		if(!$this->mode_doublon)
-			$attributes = [['isbn', $this->notice['isbn13']],
-										 ['isbn', $this->notice['isbn10']],
-										 ['ean', $this->notice['ean']],
-										 ['id_commerciale', $this->notice['id_commerciale']]];
+    if ($unicite_codes_barres == '1')
+      $condition['id_int_bib'] = $this->id_int_bib;
 
-		if ($this->mode_doublon == Class_CosmoVar::DOUBLE_SEARCH_ALPHA_KEY)
-			$attributes = [['clef_alpha', $this->notice['clef_alpha']]];
+    foreach ($this->notice['exemplaires'] as $ex) {
+      if (!$ex['code_barres'] > '')
+        continue;
 
-		$this->identification = ['statut' => static::STATUS_NOTFOUND];
+      $condition['code_barres'] = $ex['code_barres'];
+      if ($exemplaire = Class_Exemplaire::findFirstBy($condition))
+        return $exemplaire->getIdNotice();
+    }
 
-		if ($id_notice = $this->searchRecordByItemsBarcodes()) {
-			$this->identification['statut'] = 'code_barres';
-			$this->identification['code_barres'] = $id_notice;
+    return '';
+  }
 
-			return $id_notice;
-		}
 
-		foreach ($attributes as $attr) {
-			list($key, $value) = $attr;
+  private function searchRecordBy($key, $value) {
+    if (!$value)
+      return '';
 
-			if ($id_notice = $this->searchRecordBy($key, $value)) {
-				$this->identification['statut'] = $key;
-				$this->identification[$key] = $id_notice;
-
-				return $id_notice;
-			}
-		}
-
-		return '';
-	}
-
-
-	private function searchRecordByItemsBarcodes() {
-		if ($this->notice['statut_exemplaires']['nb_ex'] <= 0)
-			return '';
-
-		$unicite_codes_barres = getVariable('unicite_code_barres');
-		$condition = [];
-
-		if ($unicite_codes_barres == '1')
-			$condition['id_int_bib'] = $this->id_int_bib;
-
-		foreach ($this->notice['exemplaires'] as $ex) {
-			if (!$ex['code_barres'] > '')
-				continue;
-
-			$condition['code_barres'] = $ex['code_barres'];
-			if ($exemplaire = Class_Exemplaire::findFirstBy($condition))
-				return $exemplaire->getIdNotice();
-		}
-
-		return '';
-	}
-
-
-	private function searchRecordBy($key, $value) {
-		if (!$value)
-			return '';
-
-		if (!$notice = Class_Notice::findFirstBy([$key => $value]))
-			return '';
-
-		return $notice->getId();
-	}
-
-
-	private function insertNotice() {
-		if(!$this->notice["statut_exemplaires"]["nb_ex"]) {
-			$this->erreur = "notice sans exemplaire";
-			$this->statut = 0;
-			return false;
-		}
-
-		// Test titre principal
-		if( !$this->notice["titre_princ"] ) {
-			if($this->notice["isbn"] or $this->notice["ean"] or $this->notice["id_commerciale"]) {
-				$id_bib=$this->id_bib;
-				$data=serialize($this->notice);
-				Class_NoticeSuccincte::newInstance(['id_bib' => $this->id_bib,
-																						'data' => serialize($this->notice)])
-					->save();
-
-				$this->statut=7;
-				return false;
-			}
-			if($this->format == 0 or $this->format==10) $this->erreur="pas de titre principal";
-			else $this->erreur="Aucun identifiant valide";
-			$this->statut=0;
-			return false;
-		}
-
-		// Traitement des facettes
-		$this->traiteFacettes();
-
-		$notice = Class_Notice::newInstance($this->noticeToDBEnreg());
-		$notice->save();
-		$this->statut=1;
-		return $notice->getId();
-	}
-
-
-	public function noticeToDBEnreg() {
-		return [
-			"type_doc" => $this->notice["type_doc"],
-			"alpha_titre" => $this->notice["alpha_titre"],
-			"alpha_auteur" => $this->notice["alpha_auteur"],
-
-			"titres" => $this->indexation->getfullText(array_merge($this->notice["titres"],
-																														 [$this->notice["clef_chapeau"],
-																															$this->notice["tome_alpha"]])),
-
-			"auteurs" => $this->indexation->getfullText( $this->notice["auteurs"]
-																									 ? array_merge($this->notice["auteurs"],$this->notice["auteurs_renvois"])
-																									 : $this->notice["200_f"]),
-
-			"editeur" => $this->indexation->getfullText($this->notice["editeur"]),
-			"collection" => $this->indexation->getfullText($this->notice["collection"]),
-			"matieres" => $this->indexation->getfullText(array_merge($this->notice["matieres"],$this->notice["matieres_renvois"])),
-			"dewey" => $this->indexation->getfullText($this->notice["full_dewey"]),
-			"facettes" => $this->notice["facettes"],
-			"isbn" => $this->notice["isbn"],
-			"ean" => $this->notice["ean"],
-			"id_commerciale" => $this->notice["id_commerciale"],
-			"clef_alpha" => $this->notice["clef_alpha"],
-			"clef_chapeau" => $this->notice["clef_chapeau"],
-			"clef_oeuvre" => $this->notice["clef_oeuvre"],
-			"tome_alpha" => $this->notice["tome_alpha"],
-			"annee" => $this->notice["annee"],
-			"qualite" => $this->notice["qualite"],
-			"exportable" => $this->notice["exportable"],
-			"cote" => $this->notice["cote"],
-			"unimarc" => $this->notice['unimarc'],
-			"date_maj" => dateDuJour(2) ];
-	}
-
-
-	public function updateNotice($id_notice, $qualite) {
-		if(!$existing_notice = Class_Notice::find($id_notice))
-			return $id_notice;
-		$this->notice["qualite"] = $existing_notice->getQualite();
-		$this->notice["facette"] = $existing_notice->getFacettes();
-
-		// Test qualite
-		if ($qualite >= $this->notice["qualite"]) {
-			$this->notice["qualite"] = $qualite;
-			$this->statut = static::RECORD_RENEW;
-		} else {
-			$this->statut = static::RECORD_UPDATE;
-		}
-
-		// Si la notice n'a pas de titre on substitue par celle de la base en forcant a une qualite inferieure
-		if (!$this->notice['titre_princ'])
-			$this->statut = static::RECORD_UPDATE;
-
-		// Zones forcees
-		$this->notice_sgbd
-			->ouvrirNotice($existing_notice->getUnimarc(),
-										 $this->id_profil,
-										 0,
-										 '',
-										 false);
-
-		$champs_forces = $this->notice_sgbd->getChampsForces();
-
-		$id_origine = $this->notice["id_origine"];
-		$qualite = $this->notice["qualite"];
-		$statut_exemplaires = $this->notice["statut_exemplaires"];
-		$exemplaires = $this->notice["exemplaires"];
-		$warnings = $this->notice["warnings"];
-
-		// Si la notice de la base est de meilleure qualite on la prend
-		if ($this->statut == static::RECORD_RENEW)
-			$this->notice_sgbd->ouvrirNotice($this->notice["unimarc_with_items"], $this->id_profil, 0, '', false);
-
-		$this->updateForcedZones($champs_forces, $this->notice["champs_forces"]);
-		$this->notice = $this->notice_sgbd->getNoticeIntegration();
-		$this->notice["statut_exemplaires"] = $statut_exemplaires;
-		$this->notice["exemplaires"] = $exemplaires;
-		$this->notice["warnings"] = $warnings;
-		$this->notice["qualite"] = $qualite;
-		$this->notice["id_origine"] = $id_origine;
-
-		if ($this->statut == static::RECORD_UPDATE)
-			return $id_notice;
-
-		$this->traiteFacettes();
-
-		$existing_notice
-			->updateAttributes($this->noticeToDBEnreg())
-			->save();
-		return $id_notice;
-	}
-
-
-	protected function updateForcedZones($existing, $current) {
-		if (!$existing || $existing == $current)
-			return;
-
-		$new = ($current) ?
-			array_merge_recursive($existing, $current) :
-			$existing;
-
-		// Fusion des champs forces
-		$champs_forces = [];
-		foreach ($new as $zone => $valeurs) {
-			$zone = substr($zone, 1); // on retire le Z qui sert au array_merge_recursive
-			$this->notice_sgbd->delete_field($zone); // On supprime l'ancienne zone
-			// si champ matiere on dedoublonne directement
-			if ('6' == substr($zone, 0, 1)) {
-				$champs = array_unique($valeurs);
-				$champs_forces[$zone] = $champs;
-				continue;
-			}
-			// sinon on decoupe les elements on les dedoublonne et on les remet dans 1 seule zone
-			$champs=array();
-			foreach($valeurs as $valeur)
-				$champs = array_merge($champs, $this->notice_sgbd->getValeursBloc($valeur));
-			$champs = array_unique($champs);
-			$champs_forces[$zone][] = $this->notice_sgbd->makeZoneByValeurs(substr($valeurs[0],0,2),"a",$champs);
-		}
-
-		// On remet les nouvelles zones
-		foreach($champs_forces as $zone => $valeurs)
-			foreach($valeurs as $valeur)
-			$this->notice_sgbd->add_zone($zone,$valeur);
-
-		$this->statut = 3;
-	}
+    if (!$notice = Class_Notice::findFirstBy([$key => $value]))
+      return '';
+
+    return $notice->getId();
+  }
+
+
+  private function insertNotice() {
+    if(!$this->notice["statut_exemplaires"]["nb_ex"]) {
+      $this->erreur = "notice sans exemplaire";
+      $this->statut = 0;
+      return false;
+    }
+
+    // Test titre principal
+    if( !$this->notice["titre_princ"] ) {
+      if($this->notice["isbn"] or $this->notice["ean"] or $this->notice["id_commerciale"]) {
+        $id_bib=$this->id_bib;
+        $data=serialize($this->notice);
+        Class_NoticeSuccincte::newInstance(['id_bib' => $this->id_bib,
+                                            'data' => serialize($this->notice)])
+          ->save();
+
+        $this->statut=7;
+        return false;
+      }
+      if($this->format == 0 or $this->format==10) $this->erreur="pas de titre principal";
+      else $this->erreur="Aucun identifiant valide";
+      $this->statut=0;
+      return false;
+    }
+
+    // Traitement des facettes
+    $this->traiteFacettes();
+
+    $notice = Class_Notice::newInstance($this->noticeToDBEnreg());
+    $notice->save();
+    $this->statut=1;
+    return $notice->getId();
+  }
+
+
+  public function noticeToDBEnreg() {
+    return [
+      "type_doc" => $this->notice["type_doc"],
+      "alpha_titre" => $this->notice["alpha_titre"],
+      "alpha_auteur" => $this->notice["alpha_auteur"],
+
+      "titres" => $this->indexation->getfullText(array_merge($this->notice["titres"],
+                                                             [$this->notice["clef_chapeau"],
+                                                              $this->notice["tome_alpha"]])),
+
+      "auteurs" => $this->indexation->getfullText( $this->notice["auteurs"]
+                                                   ? array_merge($this->notice["auteurs"],$this->notice["auteurs_renvois"])
+                                                   : $this->notice["200_f"]),
+
+      "editeur" => $this->indexation->getfullText($this->notice["editeur"]),
+      "collection" => $this->indexation->getfullText($this->notice["collection"]),
+      "matieres" => $this->indexation->getfullText(array_merge($this->notice["matieres"],$this->notice["matieres_renvois"])),
+      "dewey" => $this->indexation->getfullText($this->notice["full_dewey"]),
+      "facettes" => $this->notice["facettes"],
+      "isbn" => $this->notice["isbn"],
+      "ean" => $this->notice["ean"],
+      "id_commerciale" => $this->notice["id_commerciale"],
+      "clef_alpha" => $this->notice["clef_alpha"],
+      "clef_chapeau" => $this->notice["clef_chapeau"],
+      "clef_oeuvre" => $this->notice["clef_oeuvre"],
+      "tome_alpha" => $this->notice["tome_alpha"],
+      "annee" => $this->notice["annee"],
+      "qualite" => $this->notice["qualite"],
+      "exportable" => $this->notice["exportable"],
+      "cote" => $this->notice["cote"],
+      "unimarc" => $this->notice['unimarc'],
+      "date_maj" => dateDuJour(2) ];
+  }
+
+
+  public function updateNotice($id_notice, $qualite) {
+    if(!$existing_notice = Class_Notice::find($id_notice))
+      return $id_notice;
+    $this->notice["qualite"] = $existing_notice->getQualite();
+    $this->notice["facette"] = $existing_notice->getFacettes();
+
+    // Test qualite
+    if ($qualite >= $this->notice["qualite"]) {
+      $this->notice["qualite"] = $qualite;
+      $this->statut = static::RECORD_RENEW;
+    } else {
+      $this->statut = static::RECORD_UPDATE;
+    }
+
+    // Si la notice n'a pas de titre on substitue par celle de la base en forcant a une qualite inferieure
+    if (!$this->notice['titre_princ'])
+      $this->statut = static::RECORD_UPDATE;
+
+    // Zones forcees
+    $this->notice_sgbd
+      ->ouvrirNotice($existing_notice->getUnimarc(),
+                     $this->id_profil,
+                     0,
+                     '',
+                     false);
+
+    $champs_forces = $this->notice_sgbd->getChampsForces();
+
+    $id_origine = $this->notice["id_origine"];
+    $qualite = $this->notice["qualite"];
+    $statut_exemplaires = $this->notice["statut_exemplaires"];
+    $exemplaires = $this->notice["exemplaires"];
+    $warnings = $this->notice["warnings"];
+
+    // Si la notice de la base est de meilleure qualite on la prend
+    if ($this->statut == static::RECORD_RENEW)
+      $this->notice_sgbd->ouvrirNotice($this->notice["unimarc_with_items"], $this->id_profil, 0, '', false);
+
+    $this->updateForcedZones($champs_forces, $this->notice["champs_forces"]);
+    $this->notice = $this->notice_sgbd->getNoticeIntegration();
+    $this->notice["statut_exemplaires"] = $statut_exemplaires;
+    $this->notice["exemplaires"] = $exemplaires;
+    $this->notice["warnings"] = $warnings;
+    $this->notice["qualite"] = $qualite;
+    $this->notice["id_origine"] = $id_origine;
+
+    if ($this->statut == static::RECORD_UPDATE)
+      return $id_notice;
+
+    $this->traiteFacettes();
+
+    $existing_notice
+      ->updateAttributes($this->noticeToDBEnreg())
+      ->save();
+    return $id_notice;
+  }
+
+
+  protected function updateForcedZones($existing, $current) {
+    if (!$existing || $existing == $current)
+      return;
+
+    $new = ($current) ?
+      array_merge_recursive($existing, $current) :
+      $existing;
+
+    // Fusion des champs forces
+    $champs_forces = [];
+    foreach ($new as $zone => $valeurs) {
+      $zone = substr($zone, 1); // on retire le Z qui sert au array_merge_recursive
+      $this->notice_sgbd->delete_field($zone); // On supprime l'ancienne zone
+      // si champ matiere on dedoublonne directement
+      if ('6' == substr($zone, 0, 1)) {
+        $champs = array_unique($valeurs);
+        $champs_forces[$zone] = $champs;
+        continue;
+      }
+      // sinon on decoupe les elements on les dedoublonne et on les remet dans 1 seule zone
+      $champs=array();
+      foreach($valeurs as $valeur)
+        $champs = array_merge($champs, $this->notice_sgbd->getValeursBloc($valeur));
+      $champs = array_unique($champs);
+      $champs_forces[$zone][] = $this->notice_sgbd->makeZoneByValeurs(substr($valeurs[0],0,2),"a",$champs);
+    }
+
+    // On remet les nouvelles zones
+    foreach($champs_forces as $zone => $valeurs)
+      foreach($valeurs as $valeur)
+      $this->notice_sgbd->add_zone($zone,$valeur);
+
+    $this->statut = 3;
+  }
 
 
 // --------------------------------------------------------------------------------
 // Suppression de notice (ne supprime pas l'enreg notice)
 // --------------------------------------------------------------------------------
-	private function supprimerNotice($id_notice,$id_origine)
-	{
-		global $sql;
-		$id_bib=$this->id_bib;
-		if(!$id_notice)
-		{
-			// On cherche par id_origine
-			if($id_origine) $id_notice=$sql->fetchOne("select id_notice from exemplaires where id_origine='$id_origine'and id_bib=$id_bib");
-			if(!$id_notice)
-			{
-				$this->statut=0;
-				$this->erreur="notice à supprimer non reconnue";
-				return false;
-			}
-		}
-		$sql->execute( "delete from exemplaires where id_notice=$id_notice and id_bib=$id_bib");
-	}
-
-
-	public function ecrireExemplaires($id_notice) {
-		$code_barres = [];
-		$exemplaires = [];
-		foreach ($this->notice['exemplaires'] as $ex) {
-			$code_barres []= $ex['code_barres'];
-			if ($ex["activite"]=="d")
-				continue;
-
-			$exemplaire = Class_Exemplaire::newInstance($ex)
-				->setIdNotice($id_notice)
-				->setIdOrigine($this->notice['id_origine'])
-				->setIdBib($this->id_bib)
-				->setIdIntBib($this->id_int_bib);
-
-			/**
-			 * @see http://forge.afi-sa.fr/issues/14279
-			 * we can have one file with items for different libraries. We use "annexe" codification to find
-			 * to put each item in the library it belongs to.
-			 **/
-			if ($exemplaire->hasAnnexe() && ($annexe =  CodifAnnexeCache::getInstance()->find($ex['annexe']))) {
-				$exemplaire->setIdBib($annexe->getIdBib());
-			}
-
-			$exemplaires []= $exemplaire;
-		}
-
-		if (!empty($code_barres))  {
-			$unicite_codes_barres = getVariable('unicite_code_barres');
-			$delete_duplicates_args = ($unicite_codes_barres == '1') ? [] : ['id_int_bib' => $this->id_int_bib];
-			$delete_duplicates_args['id_notice'] = $id_notice;
-			$delete_duplicates_args['code_barres'] = $code_barres;
-			Class_Exemplaire::deleteBy($delete_duplicates_args);
-		}
-
-		foreach($exemplaires as $exemplaire)
-			$exemplaire->save();
-
-		if($record = Class_Notice::find($id_notice))
-			$record->setDateMaj(dateDuJour(2))->save();
-
-		Class_Exemplaire::clearCache();
-		Class_Notice::clearCache();
-	}
-
-
-	public function supprimerExemplaire($id_notice,$ex) {
-		if(!$id_notice)	{
-			$this->statut=0;
-			$this->erreur="notice de l'exemplaire à supprimer non trouvée";
-			return false;
-		}
-
-		$exemplaires = Class_Exemplaire::findAllBy(['id_notice' => $id_notice,
-																								'id_int_bib' => $this->id_int_bib,
-																								'code_barres' => $ex['code_barres']]);
-		if(!$exemplaires)	{
-			$this->statut=0;
-			$this->erreur="code-barres à supprimer non trouvé";
-			return false;
-		}
-
-		$notice = Class_Notice::find($id_notice);
-		foreach($exemplaires as $exemplaire) {
-			$notice->removeExemplaire($exemplaire);
-		}
-
-		$notice->setDateMaj(dateDuJour(2))
-					 ->save();
-	}
-
-
-	public function traiteFacettes() {
-		global $sql;
-
-		$facettes = [];
-		$notice_facettes = isset($this->notice["facettes"])
-			? $this->notice["facettes"]
-			: '';
-		// Virer les facettes sauf les tags
-		foreach(explode(' ', $notice_facettes) as $facet) {
-			$tp=substr($facet, 0, 1);
-			if($tp =="Z")
-				$facettes []= $facet;
-		}
-
-		if($type_doc = $this->notice['infos_type_doc']) {
-			if($code_type_doc = $type_doc['code']){
-				$facettes[] = 'T'.$code_type_doc;
-			}
-		}
-
-		// Dewey
-		$this->notice["full_dewey"] = '';
-		if($this->notice["dewey"])
-		{
-			foreach($this->notice["dewey"] as $indice)
-			{
-				if (!$dewey = Class_CodifDewey::find($indice)) {
-					$dewey = Class_CodifDewey::newInstance(['id_dewey' => $indice,
-																									'libelle' => '']);
-					$dewey->save();
-				}
-
-
-				$this->notice["full_dewey"] .= $dewey->getLibelle()." ";
-				$facettes[]="D".$indice;
-			}
-		}
-
-		// Pcdm4
-		if($this->notice["pcdm4"]) {
-			$indice = $this->notice["pcdm4"];
-			if (!$pcdm4 = Class_CodifPcdm4::find($indice)) {
-					$pcdm4 = Class_CodifPcdm4::newInstance(['id_pcdm4' => $indice,
-																									'libelle' => '']);
-					$pcdm4->save();
-			}
-
-			$this->notice["full_dewey"] .= $pcdm4->getLibelle()." ";
-			$facettes[]="P".$indice;
-		}
-
-
-		// Thesaurus
-		if($thesauri=$this->notice["thesauri"])
-			{
-
-				foreach ($thesauri as $thesaurus) {
-					if (empty($thesaurus))
-						continue;
-					if ($thesaurus->getLibelle())
-						$this->notice["full_dewey"] .= $thesaurus->getLibelle().' ';
-					$facettes[]="H".$thesaurus->getIdThesaurus();
-				}
-			}
-
-		// Auteurs
-		if($this->notice["auteurs"])
-		{
-			foreach($this->notice["auteurs"] as $auteur) {
-				if ($facette_auteur= $this->getFacetteAuteur($auteur))
-					$facettes []= $facette_auteur;
-			}
-		}
-
-		// Matieres
-		if($this->notice["matieres"])	{
-			foreach($this->notice["matieres"] as $matiere)	{
-				// limit to the maximum size of code_alpha column in db to avoid duplicates
-				$code_alpha = substr($this->indexation->alphaMaj($matiere), 0, 255);
-				if(!$code_alpha) continue;
-
-				if (!$codif_matiere = Class_CodifMatiere::findFirstBy(['code_alpha' => $code_alpha])) {
-					$codif_matiere = Class_CodifMatiere::newInstance(['libelle' => $matiere,
-																														'code_alpha' => $code_alpha]);
-					$codif_matiere->save();
-				}
-
-				$id_matiere = $codif_matiere->getId();
-				$facettes[]="M".$id_matiere;
-			}
-		}
-
-		// Centres d'interet
-		if ($this->notice["interet"]) {
-			foreach($this->notice["interet"] as $interet) {
-				if (!$code_alpha = $this->indexation->alphaMaj($interet))
-					continue;
-
-				if (!$centre_interet = Class_CodifCentreInteret::findFirstBy(['code_alpha' => $code_alpha])) {
-					$centre_interet = Class_CodifCentreInteret::newInstance(['libelle' => $interet,
-																																	 'code_alpha' => $code_alpha]);
-					$centre_interet->save();
-				}
-
-				$facettes[] = "F" . $centre_interet->getId();
-				$this->notice["full_dewey"] .= $interet." ";
-			}
-		}
-
-		// Langues
-		if($this->notice["langues"])
-		{
-			foreach($this->notice["langues"] as $langue)
-			{
-				if (Class_CodifLangue::find($langue))
-					$facettes[]="L".$langue;
-				else
-					$this->notice["warnings"][]=array("Code langue non reconnu",$langue);
-			}
-		}
-
-		// genres
-		if(isset($this->notice["genres"]) && count($this->notice["genres"]))
-		{
-			foreach(array_filter($this->notice["genres"]) as $genre)
-			{
-				$facettes[]="G".$genre." ";
-				if ($codif_genre = Class_CodifGenre::find($genre))
-					$this->notice["full_dewey"].=$codif_genre->getLibelle();
-			}
-		}
-
-		// emplacements
-		if (isset($this->notice["emplacements"]) && count($this->notice['emplacements']))
-				$facettes = array_merge($facettes, array_map(function($e) { return "E$e";}, $this->notice['emplacements']));
-
-		// Maj enreg facette
-		$this->notice["facettes"] = trim(implode(' ', array_unique($facettes)));
-	}
-
-
-	public function getFacetteAuteur($auteur) {
-		$code_alpha = $this->indexation->alphaMaj($auteur);
-		if (!$code_alpha = str_replace(" ","x",$code_alpha))
-			return;
-
-		if (!$codif_auteur = Class_CodifAuteur::findByCodeAlpha($code_alpha)) {
-			$nom_prenom = (-1 < $pos=strscan($auteur,"|"))
-				? trim(substr($auteur,($pos+1))." ".substr($auteur,0,$pos))
-				: $auteur;
-
-			$codif_auteur = Class_CodifAuteur::newInstance()
-				->setLibelle($nom_prenom)
-				->setFormes($code_alpha);
-			$codif_auteur->save();
-		}
-
-		return 'A'.$codif_auteur->getId();
-	}
+  private function supprimerNotice($id_notice,$id_origine)
+  {
+    global $sql;
+    $id_bib=$this->id_bib;
+    if(!$id_notice)
+    {
+      // On cherche par id_origine
+      if($id_origine) $id_notice=$sql->fetchOne("select id_notice from exemplaires where id_origine='$id_origine'and id_bib=$id_bib");
+      if(!$id_notice)
+      {
+        $this->statut=0;
+        $this->erreur="notice à supprimer non reconnue";
+        return false;
+      }
+    }
+    $sql->execute( "delete from exemplaires where id_notice=$id_notice and id_bib=$id_bib");
+  }
+
+
+  public function ecrireExemplaires($id_notice) {
+    $code_barres = [];
+    $exemplaires = [];
+    foreach ($this->notice['exemplaires'] as $ex) {
+      $code_barres []= $ex['code_barres'];
+      if ($ex["activite"]=="d")
+        continue;
+
+      $exemplaire = Class_Exemplaire::newInstance($ex)
+        ->setIdNotice($id_notice)
+        ->setIdOrigine($this->notice['id_origine'])
+        ->setIdBib($this->id_bib)
+        ->setIdIntBib($this->id_int_bib);
+
+      /**
+       * @see http://forge.afi-sa.fr/issues/14279
+       * we can have one file with items for different libraries. We use "annexe" codification to find
+       * to put each item in the library it belongs to.
+       **/
+      if ($exemplaire->hasAnnexe() && ($annexe =  CodifAnnexeCache::getInstance()->find($ex['annexe']))) {
+        $exemplaire->setIdBib($annexe->getIdBib());
+      }
+
+      $exemplaires []= $exemplaire;
+    }
+
+    if (!empty($code_barres))  {
+      $unicite_codes_barres = getVariable('unicite_code_barres');
+      $delete_duplicates_args = ($unicite_codes_barres == '1') ? [] : ['id_int_bib' => $this->id_int_bib];
+      $delete_duplicates_args['id_notice'] = $id_notice;
+      $delete_duplicates_args['code_barres'] = $code_barres;
+      Class_Exemplaire::deleteBy($delete_duplicates_args);
+    }
+
+    foreach($exemplaires as $exemplaire)
+      $exemplaire->save();
+
+    if($record = Class_Notice::find($id_notice))
+      $record->setDateMaj(dateDuJour(2))->save();
+
+    Class_Exemplaire::clearCache();
+    Class_Notice::clearCache();
+  }
+
+
+  public function supprimerExemplaire($id_notice,$ex) {
+    if(!$id_notice)  {
+      $this->statut=0;
+      $this->erreur="notice de l'exemplaire à supprimer non trouvée";
+      return false;
+    }
+
+    $exemplaires = Class_Exemplaire::findAllBy(['id_notice' => $id_notice,
+                                                'id_int_bib' => $this->id_int_bib,
+                                                'code_barres' => $ex['code_barres']]);
+    if(!$exemplaires)  {
+      $this->statut=0;
+      $this->erreur="code-barres à supprimer non trouvé";
+      return false;
+    }
+
+    $notice = Class_Notice::find($id_notice);
+    foreach($exemplaires as $exemplaire) {
+      $notice->removeExemplaire($exemplaire);
+    }
+
+    $notice->setDateMaj(dateDuJour(2))
+           ->save();
+  }
+
+
+  public function traiteFacettes() {
+    global $sql;
+
+    $facettes = [];
+    $notice_facettes = isset($this->notice["facettes"])
+      ? $this->notice["facettes"]
+      : '';
+    // Virer les facettes sauf les tags
+    foreach(explode(' ', $notice_facettes) as $facet) {
+      $tp=substr($facet, 0, 1);
+      if($tp =="Z")
+        $facettes []= $facet;
+    }
+
+    if($type_doc = $this->notice['infos_type_doc']) {
+      if($code_type_doc = $type_doc['code']){
+        $facettes[] = 'T'.$code_type_doc;
+      }
+    }
+
+    // Dewey
+    $this->notice["full_dewey"] = '';
+    if($this->notice["dewey"])
+    {
+      foreach($this->notice["dewey"] as $indice)
+      {
+        if (!$dewey = Class_CodifDewey::find($indice)) {
+          $dewey = Class_CodifDewey::newInstance(['id_dewey' => $indice,
+                                                  'libelle' => '']);
+          $dewey->save();
+        }
+
+
+        $this->notice["full_dewey"] .= $dewey->getLibelle()." ";
+        $facettes[]="D".$indice;
+      }
+    }
+
+    // Pcdm4
+    if($this->notice["pcdm4"]) {
+      $indice = $this->notice["pcdm4"];
+      if (!$pcdm4 = Class_CodifPcdm4::find($indice)) {
+          $pcdm4 = Class_CodifPcdm4::newInstance(['id_pcdm4' => $indice,
+                                                  'libelle' => '']);
+          $pcdm4->save();
+      }
+
+      $this->notice["full_dewey"] .= $pcdm4->getLibelle()." ";
+      $facettes[]="P".$indice;
+    }
+
+
+    // Thesaurus
+    if($thesauri=$this->notice["thesauri"])
+      {
+
+        foreach ($thesauri as $thesaurus) {
+          if (empty($thesaurus))
+            continue;
+          if ($thesaurus->getLibelle())
+            $this->notice["full_dewey"] .= $thesaurus->getLibelle().' ';
+          $facettes[]="H".$thesaurus->getIdThesaurus();
+        }
+      }
+
+    // Auteurs
+    if($this->notice["auteurs"])
+    {
+      foreach($this->notice["auteurs"] as $auteur) {
+        if ($facette_auteur= $this->getFacetteAuteur($auteur))
+          $facettes []= $facette_auteur;
+      }
+    }
+
+    // Matieres
+    if($this->notice["matieres"])  {
+      foreach($this->notice["matieres"] as $matiere)  {
+        // limit to the maximum size of code_alpha column in db to avoid duplicates
+        $code_alpha = substr($this->indexation->alphaMaj($matiere), 0, 255);
+        if(!$code_alpha) continue;
+
+        if (!$codif_matiere = Class_CodifMatiere::findFirstBy(['code_alpha' => $code_alpha])) {
+          $codif_matiere = Class_CodifMatiere::newInstance(['libelle' => $matiere,
+                                                            'code_alpha' => $code_alpha]);
+          $codif_matiere->save();
+        }
+
+        $id_matiere = $codif_matiere->getId();
+        $facettes[]="M".$id_matiere;
+      }
+    }
+
+    // Centres d'interet
+    if ($this->notice["interet"]) {
+      foreach($this->notice["interet"] as $interet) {
+        if (!$code_alpha = $this->indexation->alphaMaj($interet))
+          continue;
+
+        if (!$centre_interet = Class_CodifCentreInteret::findFirstBy(['code_alpha' => $code_alpha])) {
+          $centre_interet = Class_CodifCentreInteret::newInstance(['libelle' => $interet,
+                                                                   'code_alpha' => $code_alpha]);
+          $centre_interet->save();
+        }
+
+        $facettes[] = "F" . $centre_interet->getId();
+        $this->notice["full_dewey"] .= $interet." ";
+      }
+    }
+
+    // Langues
+    if($this->notice["langues"])
+    {
+      foreach($this->notice["langues"] as $langue)
+      {
+        if (Class_CodifLangue::find($langue))
+          $facettes[]="L".$langue;
+        else
+          $this->notice["warnings"][]=array("Code langue non reconnu",$langue);
+      }
+    }
+
+    // genres
+    if(isset($this->notice["genres"]) && count($this->notice["genres"]))
+    {
+      foreach(array_filter($this->notice["genres"]) as $genre)
+      {
+        $facettes[]="G".$genre." ";
+        if ($codif_genre = Class_CodifGenre::find($genre))
+          $this->notice["full_dewey"].=$codif_genre->getLibelle();
+      }
+    }
+
+    // emplacements
+    if (isset($this->notice["emplacements"]) && count($this->notice['emplacements']))
+        $facettes = array_merge($facettes, array_map(function($e) { return "E$e";}, $this->notice['emplacements']));
+
+    // Maj enreg facette
+    $this->notice["facettes"] = trim(implode(' ', array_unique($facettes)));
+  }
+
+
+  public function getFacetteAuteur($auteur) {
+    $code_alpha = $this->indexation->alphaMaj($auteur);
+    if (!$code_alpha = str_replace(" ","x",$code_alpha))
+      return;
+
+    if (!$codif_auteur = Class_CodifAuteur::findByCodeAlpha($code_alpha)) {
+      $nom_prenom = (-1 < $pos=strscan($auteur,"|"))
+        ? trim(substr($auteur,($pos+1))." ".substr($auteur,0,$pos))
+        : $auteur;
+
+      $codif_auteur = Class_CodifAuteur::newInstance()
+        ->setLibelle($nom_prenom)
+        ->setFormes($code_alpha);
+      $codif_auteur->save();
+    }
+
+    return 'A'.$codif_auteur->getId();
+  }
 
 // --------------------------------------------------------------------------------
 // Ecrit une notice : article de périodique
 // --------------------------------------------------------------------------------
-	private function ecrireArticlePeriodique() {
-		global $sql;
-
-		if( 1 == $this->notice["statut"])
+  private function ecrireArticlePeriodique() {
+    if( 1 == $this->notice["statut"])
       return $this->deleteRecordArticles();
 
     $title_key = hash('crc32b', $this->notice['titre_princ']);
@@ -961,18 +940,18 @@ class notice_integration {
       $common_attribs = ['clef_chapeau' => $this->notice['clef_chapeau'],
                          'clef_numero' => $this->notice['clef_numero']];
 
-			if(!$article = Class_Notice_SerialArticles::findFirstBy(array_merge($common_attribs, ['clef_unimarc' => $title_key])))
+      if(!$article = Class_Notice_SerialArticles::findFirstBy(array_merge($common_attribs, ['clef_unimarc' => $title_key])))
         $article = Class_Notice_SerialArticles::findFirstBy(array_merge($common_attribs, ['clef_article' => $this->notice['clef_article'],
                                                                                           'clef_unimarc' => '']));
       return $this->updateOrInsertArticle($article, $article_from_record);
     }
 
     if ($article = Class_Notice_SerialArticles::findFirstBy(['clef_unimarc' => $this->notice['clef_unimarc']])) {
-				$article_from_record->setClefChapeau($article->getClefChapeau());
-				$article_from_record->setClefNumero($article->getClefNumero());
+        $article_from_record->setClefChapeau($article->getClefChapeau());
+        $article_from_record->setClefNumero($article->getClefNumero());
         return $this->updateOrInsertArticle($article, $article_from_record);
     }
-	}
+  }
 
 
   protected function updateOrInsertArticle($article, $article_from_record) {
@@ -983,7 +962,7 @@ class notice_integration {
 
 
   protected function insertArticleWith($article_from_record) {
-		Class_Notice_SerialArticles::newInstance($article_from_record->toArray())->save();
+    Class_Notice_SerialArticles::newInstance($article_from_record->toArray())->save();
     Class_Notice_SerialArticles::clearCache();
     $this->statut = self::RECORD_INSERT;
     return;
@@ -991,7 +970,7 @@ class notice_integration {
 
 
   protected function updateArticleWith($article, $article_from_record) {
-    if($enreg["qualite"] >= $article->getQualite())	{
+    if($enreg["qualite"] >= $article->getQualite())  {
       $article->updateAttributes($article_from_record->toArray())->save();
       $this->statut = self::RECORD_RENEW;
     }
@@ -999,6 +978,8 @@ class notice_integration {
 
 
   protected function deleteRecordArticles() {
+    global $sql;
+
     $this->statut = self::RECORD_DELETE;
 
     if($this->notice["clef_unimarc"])
@@ -1007,384 +988,384 @@ class notice_integration {
       $controle = $sql->execute("delete from notices_articles where clef_chapeau='$clef_chapeau' and clef_numero='$clef_numero' and clef_article='$clef_article'" );
 
     if(!$controle) {
-				$this->statut = 0;
-				$this->erreur = "notice à supprimer non reconnue";
-			}
+      $this->statut = 0;
+      $this->erreur = "notice à supprimer non reconnue";
+    }
   }
 
 
 // --------------------------------------------------------------------------------
 // Recupere titre, auteurs, matieres pour 1 article de périodique
 // --------------------------------------------------------------------------------
-	public function getDataArticlePeriodique($unimarc)
-	{
-		if(!$unimarc) { $this->erreur="notice sans unimarc"; return false; }
-		if(!$this->analyseur->ouvrirNotice($unimarc,$this->id_profil,0,"")) { $this->erreur=$this->analyseur->getLastError(); return false; }
-
-		$ret["titres"]=$this->analyseur->getTitres();
-		$ret["auteurs"]=$this->analyseur->getAuteurs();
-		$ret["matieres"]=$this->analyseur->getMatieres();
-		return $ret;
-	}
+  public function getDataArticlePeriodique($unimarc)
+  {
+    if(!$unimarc) { $this->erreur="notice sans unimarc"; return false; }
+    if(!$this->analyseur->ouvrirNotice($unimarc,$this->id_profil,0,"")) { $this->erreur=$this->analyseur->getLastError(); return false; }
+
+    $ret["titres"]=$this->analyseur->getTitres();
+    $ret["auteurs"]=$this->analyseur->getAuteurs();
+    $ret["matieres"]=$this->analyseur->getMatieres();
+    return $ret;
+  }
 
 // --------------------------------------------------------------------------------
 // Rend la derniere erreur et les derniers warnings
 // --------------------------------------------------------------------------------
-	public function getLastStatut()
-	{
-		$ret["statut"]=$this->statut;
-		$ret["erreur"]=$this->erreur;
-		$ret["warnings"]=$this->notice["warnings"];
-		$ret["identification"]=$this->identification["statut"];
-		return $ret;
-	}
+  public function getLastStatut()
+  {
+    $ret["statut"]=$this->statut;
+    $ret["erreur"]=$this->erreur;
+    $ret["warnings"]=$this->notice["warnings"];
+    $ret["identification"]=$this->identification["statut"];
+    return $ret;
+  }
 
 // --------------------------------------------------------------------------------
 // Rend tout le contenu de la notice
 // --------------------------------------------------------------------------------
-	public function getNotice()
-	{
-		if(!$this->notice) $this->notice=array();
-		return $this->notice;
-	}
+  public function getNotice()
+  {
+    if(!$this->notice) $this->notice=array();
+    return $this->notice;
+  }
 
 // ----------------------------------------------------------------
 // Test d'une notice unimarc
 // ----------------------------------------------------------------
-	public function testNotice($data,$piege_numero="",$piege_titre="",$piege_code_barres="",$piege_isbn="",$piege_type_doc="")
-	{
-		global $sql;
-
-		// lire la notice
-		$this->analyseur->ouvrirNotice($data,$this->id_profil,$this->sigb);
-		$notice=$this->analyseur->getNoticeIntegration();
-
-	//	tracedebug($notice,true); //++++++++++++++++++++++++++++++++++++++++++++++++++++
-
-		// Titre principal
-		$ret["titre"]=$notice["titre_princ"];
-
-		// Gestion des pieges
-		if($piege_numero){$ret["statut"]=0; return $ret;}
-		if($piege_titre >"" and $this->indexation->codeAlphaTitre($ret["titre"]) == $this->indexation->codeAlphaTitre($piege_titre)) {$ret["statut"]=1; return $ret;}
-		if($piege_code_barres > "" and $notice["statut_exemplaires"]["nb_ex"]>0)
-		{
-			foreach($notice["exemplaires"] as $ex)
-			{
-				if($ex["code_barres"]==$piege_code_barres) {$ret["statut"]=1; return $ret;}
-			}
-		}
-		if($piege_isbn > "" and ($notice["isbn10"] == $piege_isbn or $notice["isbn13"] == $piege_isbn)) {$ret["statut"]=1; return $ret;}
-		if($piege_type_doc >"" and $notice["infos_type_doc"]["code"]==$piege_type_doc) {$ret["statut"]=1; return $ret; }
-		if($piege_titre > "" or $piege_code_barres > "" or $piege_isbn > "" or $piege_type_doc >""){$ret["statut"]=0; return $ret;}
-
-		// Type de document
-		$td=$notice["infos_type_doc"];
-		if(!$td["code"]){	$statut=1; $libelle=" code non reconnu"; $ret["type_doc"]=0; }
-		else {$statut=0; $libelle=$td["code"]." - ".$td["libelle"]; $ret["type_doc"]=$td["code"]; }
-		$ret["lig"][]=array($statut,"Type&nbsp;de&nbsp;document", $libelle,$td["infos"]);
-
-		// Statut : 0=notice vivante 1=à détruire
-		$lig[0]=0;
-		$lig[1]="Statut";
-		$lig[2]="ok";
-		if($notice["statut"]==1)
-		{
-			$lig[0]=3;
-			$lig[2]='<font color="purple">Notice à supprimer</font>';
-		}
-		else if($td["code"]!="100")
-		{
-			if($ret["titre"] == "") {$lig[0]=2; $lig[2]="pas de titre principal";$ret["lig"][]=$lig;}
-			if($notice["statut_exemplaires"]["nb_ex"]==0)
-			{
-				$lig[0]=2;
-				$lig[2]="pas de zone 995";
-			}
-			else
-			{
-				if($notice["statut_exemplaires"]["codes_barres"]==0) {$lig[0]=1; $lig[2]="code-barres non trouvé";}
-				if($notice["statut_exemplaires"]["cotes"]==0) {$lig[0]=1; $lig[2] ="cote non trouvée";}
-				if($notice["exportable"]==false)$lig[3]='<font color="purple">notice non libre de droits</font>'; else $lig[3]="notice libre de droits";
-			}
-		}
-		$ret["lig"][]=$lig;
-
-		// articles de periodiques
-		if($td["code"]== "100")
-		{
-			$lig[0]=0;
-			$lig[1]="titre du numéro";
-			$lig[2]=$notice["titre_numero"];
-			$ret["lig"][]=$lig;
-
-			$lig[0]=0;
-			$lig[1]="identifiant 001";
-			$lig[2]=$notice["info_id"];
-			$ret["lig"][]=$lig;
-		}
-
-		// tout sauf articles de periodiques
-		else
-		{
-			// exemplaires
-			$ret["nb_ex"]=$notice["statut_exemplaires"]["nb_ex"];
-			$lig[0]=0;
-			$lig[1]="Exemplaires";
-			$lig[2]=$notice["statut_exemplaires"]["nb_ex"]." ex. actif(s)";
-			$lig[3]="";
-			if($notice["statut_exemplaires"]["nb_ex_detruits"] > 0 ) $lig[3]=$notice["statut_exemplaires"]["nb_ex_detruits"]." ex. à supprimer";
-			$ret["lig"][]=$lig;
-
-			// Identifiants (isbn / ean)
-			$isbn=$this->analyseur->getIsbn();
-			if(!$isbn) $isbn=$this->analyseur->getEan();
-
-			$lig[0]=0;
-			$lig[1]="Identifiant";
-			$lig[2]="";
-			$lig[3]="";
-			if($isbn["multiple"]==true)
-			{
-				$lig[0]=1;
-				$lig[2]="Isbn multiple";
-				$lig[3]=$isbn["isbn"];
-			}
-			if($isbn["statut"] == 1)
-			{
-				$lig[0]=1;
-				$lig[2]=$isbn["erreur"];
-				$lig[3]=$isbn["code_brut"];
-			}
-			else
-			{
-				if($isbn["isbn"]) {$lig[2]="isbn"; $lig[3]=$isbn["isbn"];}
-				if($isbn["ean"]) {$lig[2]="ean"; $lig[3]=$isbn["ean"];}
-			}
-			$ret["lig"][]=$lig;
-
-			// Identifiants ID_COMMERCIALE
-			$lig[0]=0;
-			$lig[1]="No commercial";
-			$lig[2]=$notice["id_commerciale"];
-			$lig[3]="";
-			$ret["lig"][]=$lig;
-		}
-
-		// Donnes principales
-		$titre=$this->analyseur->getTitres();
-		$auteur=$this->analyseur->getAuteurs();
-		$lig[0]=0;
-		$lig[1]="Données&nbsp;principales";
-		$lig[2]="titre(s) : ".count($titre);
-		$lig[3]="auteur(s) : ".count($auteur);
-		$ret["lig"][]=$lig;
-
-		if($td["code"]!= "100")  // tout sauf articles de periodiques
-		{
-			// section
-			$lig[1]="Section";
-			if(!$notice["sections"]) {$lig[0]=1; $lig[2]="non reconnue";}
-			else
-			{
-				$lig[0]=0;
-				$lig[2]="";
-				foreach($notice["sections"] as $section) $lig[2].=$sql->fetchOne("select libelle from codif_section where id_section=".$section).BR;
-			}
-			$lig[3]="";
-			$ret["lig"][]=$lig;
-
-			// genre
-			$lig[1]="Genre";
-			if(!$notice["genres"]) {$lig[0]=1; $lig[2]="non reconnu";}
-			else
-			{
-				$lig[0]=0;
-				$lig[2]="";
-				foreach($notice["genres"] as $genre) $lig[2].=$sql->fetchOne("select libelle from codif_genre where id_genre=".$genre).BR;
-			}
-			$lig[3]="";
-			$ret["lig"][]=$lig;
-
-			// emplacement
-			$lig[1]="Emplacement";
-			if(!$notice["emplacements"]) {$lig[0]=1; $lig[2]="non reconnu";}
-			else
-			{
-				$lig[0]=0;
-				$lig[2]="";
-				foreach($notice["emplacements"] as $emplacement) $lig[2].=$sql->fetchOne("select libelle from codif_emplacement where id_emplacement=".$emplacement).BR;
-			}
-			$lig[3]="";
-			$ret["lig"][]=$lig;
-
-			// Champs forcés
-			$lig[0]=0;
-			$lig[1]="Champs à conserver";
-			$lig[2]="";
-			$lig[3]="";
-			if(count($notice["champs_forces"]) > 0)
-			{
-				foreach($notice["champs_forces"] as $zone => $champ) $lig[2].= substr($zone,1)." ";
-			}
-			else $lig[2]="aucun";
-			$ret["lig"][]=$lig;
-		}
-
-		// Statut general du retour
-		$ret["statut"]=0;
-		for($i=0; $i < count($ret["lig"]); $i++)
-		{
-			if($ret["lig"][$i][0]==2)
-			{
-				$ret["statut"]=2;
-				break;
-			}
-			if($ret["lig"][$i][0]==1) $ret["statut"]=1;
-			if($ret["lig"][$i][0]==3 and $ret["statut"] <2) $ret["statut"]=3;
-		}
-		return $ret;
-	}
+  public function testNotice($data,$piege_numero="",$piege_titre="",$piege_code_barres="",$piege_isbn="",$piege_type_doc="")
+  {
+    global $sql;
+
+    // lire la notice
+    $this->analyseur->ouvrirNotice($data,$this->id_profil,$this->sigb);
+    $notice=$this->analyseur->getNoticeIntegration();
+
+  //  tracedebug($notice,true); //++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+    // Titre principal
+    $ret["titre"]=$notice["titre_princ"];
+
+    // Gestion des pieges
+    if($piege_numero){$ret["statut"]=0; return $ret;}
+    if($piege_titre >"" and $this->indexation->codeAlphaTitre($ret["titre"]) == $this->indexation->codeAlphaTitre($piege_titre)) {$ret["statut"]=1; return $ret;}
+    if($piege_code_barres > "" and $notice["statut_exemplaires"]["nb_ex"]>0)
+    {
+      foreach($notice["exemplaires"] as $ex)
+      {
+        if($ex["code_barres"]==$piege_code_barres) {$ret["statut"]=1; return $ret;}
+      }
+    }
+    if($piege_isbn > "" and ($notice["isbn10"] == $piege_isbn or $notice["isbn13"] == $piege_isbn)) {$ret["statut"]=1; return $ret;}
+    if($piege_type_doc >"" and $notice["infos_type_doc"]["code"]==$piege_type_doc) {$ret["statut"]=1; return $ret; }
+    if($piege_titre > "" or $piege_code_barres > "" or $piege_isbn > "" or $piege_type_doc >""){$ret["statut"]=0; return $ret;}
+
+    // Type de document
+    $td=$notice["infos_type_doc"];
+    if(!$td["code"]){  $statut=1; $libelle=" code non reconnu"; $ret["type_doc"]=0; }
+    else {$statut=0; $libelle=$td["code"]." - ".$td["libelle"]; $ret["type_doc"]=$td["code"]; }
+    $ret["lig"][]=array($statut,"Type&nbsp;de&nbsp;document", $libelle,$td["infos"]);
+
+    // Statut : 0=notice vivante 1=à détruire
+    $lig[0]=0;
+    $lig[1]="Statut";
+    $lig[2]="ok";
+    if($notice["statut"]==1)
+    {
+      $lig[0]=3;
+      $lig[2]='<font color="purple">Notice à supprimer</font>';
+    }
+    else if($td["code"]!="100")
+    {
+      if($ret["titre"] == "") {$lig[0]=2; $lig[2]="pas de titre principal";$ret["lig"][]=$lig;}
+      if($notice["statut_exemplaires"]["nb_ex"]==0)
+      {
+        $lig[0]=2;
+        $lig[2]="pas de zone 995";
+      }
+      else
+      {
+        if($notice["statut_exemplaires"]["codes_barres"]==0) {$lig[0]=1; $lig[2]="code-barres non trouvé";}
+        if($notice["statut_exemplaires"]["cotes"]==0) {$lig[0]=1; $lig[2] ="cote non trouvée";}
+        if($notice["exportable"]==false)$lig[3]='<font color="purple">notice non libre de droits</font>'; else $lig[3]="notice libre de droits";
+      }
+    }
+    $ret["lig"][]=$lig;
+
+    // articles de periodiques
+    if($td["code"]== "100")
+    {
+      $lig[0]=0;
+      $lig[1]="titre du numéro";
+      $lig[2]=$notice["titre_numero"];
+      $ret["lig"][]=$lig;
+
+      $lig[0]=0;
+      $lig[1]="identifiant 001";
+      $lig[2]=$notice["info_id"];
+      $ret["lig"][]=$lig;
+    }
+
+    // tout sauf articles de periodiques
+    else
+    {
+      // exemplaires
+      $ret["nb_ex"]=$notice["statut_exemplaires"]["nb_ex"];
+      $lig[0]=0;
+      $lig[1]="Exemplaires";
+      $lig[2]=$notice["statut_exemplaires"]["nb_ex"]." ex. actif(s)";
+      $lig[3]="";
+      if($notice["statut_exemplaires"]["nb_ex_detruits"] > 0 ) $lig[3]=$notice["statut_exemplaires"]["nb_ex_detruits"]." ex. à supprimer";
+      $ret["lig"][]=$lig;
+
+      // Identifiants (isbn / ean)
+      $isbn=$this->analyseur->getIsbn();
+      if(!$isbn) $isbn=$this->analyseur->getEan();
+
+      $lig[0]=0;
+      $lig[1]="Identifiant";
+      $lig[2]="";
+      $lig[3]="";
+      if($isbn["multiple"]==true)
+      {
+        $lig[0]=1;
+        $lig[2]="Isbn multiple";
+        $lig[3]=$isbn["isbn"];
+      }
+      if($isbn["statut"] == 1)
+      {
+        $lig[0]=1;
+        $lig[2]=$isbn["erreur"];
+        $lig[3]=$isbn["code_brut"];
+      }
+      else
+      {
+        if($isbn["isbn"]) {$lig[2]="isbn"; $lig[3]=$isbn["isbn"];}
+        if($isbn["ean"]) {$lig[2]="ean"; $lig[3]=$isbn["ean"];}
+      }
+      $ret["lig"][]=$lig;
+
+      // Identifiants ID_COMMERCIALE
+      $lig[0]=0;
+      $lig[1]="No commercial";
+      $lig[2]=$notice["id_commerciale"];
+      $lig[3]="";
+      $ret["lig"][]=$lig;
+    }
+
+    // Donnes principales
+    $titre=$this->analyseur->getTitres();
+    $auteur=$this->analyseur->getAuteurs();
+    $lig[0]=0;
+    $lig[1]="Données&nbsp;principales";
+    $lig[2]="titre(s) : ".count($titre);
+    $lig[3]="auteur(s) : ".count($auteur);
+    $ret["lig"][]=$lig;
+
+    if($td["code"]!= "100")  // tout sauf articles de periodiques
+    {
+      // section
+      $lig[1]="Section";
+      if(!$notice["sections"]) {$lig[0]=1; $lig[2]="non reconnue";}
+      else
+      {
+        $lig[0]=0;
+        $lig[2]="";
+        foreach($notice["sections"] as $section) $lig[2].=$sql->fetchOne("select libelle from codif_section where id_section=".$section).BR;
+      }
+      $lig[3]="";
+      $ret["lig"][]=$lig;
+
+      // genre
+      $lig[1]="Genre";
+      if(!$notice["genres"]) {$lig[0]=1; $lig[2]="non reconnu";}
+      else
+      {
+        $lig[0]=0;
+        $lig[2]="";
+        foreach($notice["genres"] as $genre) $lig[2].=$sql->fetchOne("select libelle from codif_genre where id_genre=".$genre).BR;
+      }
+      $lig[3]="";
+      $ret["lig"][]=$lig;
+
+      // emplacement
+      $lig[1]="Emplacement";
+      if(!$notice["emplacements"]) {$lig[0]=1; $lig[2]="non reconnu";}
+      else
+      {
+        $lig[0]=0;
+        $lig[2]="";
+        foreach($notice["emplacements"] as $emplacement) $lig[2].=$sql->fetchOne("select libelle from codif_emplacement where id_emplacement=".$emplacement).BR;
+      }
+      $lig[3]="";
+      $ret["lig"][]=$lig;
+
+      // Champs forcés
+      $lig[0]=0;
+      $lig[1]="Champs à conserver";
+      $lig[2]="";
+      $lig[3]="";
+      if(count($notice["champs_forces"]) > 0)
+      {
+        foreach($notice["champs_forces"] as $zone => $champ) $lig[2].= substr($zone,1)." ";
+      }
+      else $lig[2]="aucun";
+      $ret["lig"][]=$lig;
+    }
+
+    // Statut general du retour
+    $ret["statut"]=0;
+    for($i=0; $i < count($ret["lig"]); $i++)
+    {
+      if($ret["lig"][$i][0]==2)
+      {
+        $ret["statut"]=2;
+        break;
+      }
+      if($ret["lig"][$i][0]==1) $ret["statut"]=1;
+      if($ret["lig"][$i][0]==3 and $ret["statut"] <2) $ret["statut"]=3;
+    }
+    return $ret;
+  }
 // ----------------------------------------------------------------
 // Analyse de synthese d'une notice unimarc
 // ----------------------------------------------------------------
-	public function syntheseNotice($data)
-	{
-		global $sql;
-
-		$this->analyseur->ouvrirNotice($data,$this->id_profil,$this->sigb);
-		$notice=$this->analyseur->getNoticeIntegration();
-
-		// Notice à supprimer
-		if($notice["statut"]==1) {$ret["statut"]="suppr"; return $ret;}
-
-		// Notice rejetee
-		$ret["statut"]="rejet";
-		if(!$notice["titre_princ"]) {$ret["rejet"]="notice sans titre"; return $ret;}
-		if($notice["type_doc"]!="100" and !$notice["statut_exemplaires"]["nb_ex"]) {$ret["rejet"]="notice sans exemplaire"; return $ret;}
-
-		// Warnings
-		$ret["statut"]="warning";
-		if($notice["type_doc"]!="100")
-		{
-			if(!$notice["statut_exemplaires"]["codes_barres"]) $ret["warnings"][]="code-barres non trouvé";
-			if(!$notice["statut_exemplaires"]["cotes"]) $ret["warnings"][]="cote non trouvée";
-		}
-		if(!$notice["type_doc"])$ret["warnings"][]="Type de document non reconnu";
-
-		// Type de doc
-		if($notice["type_doc"]) $ret["type_doc"]=$notice["infos_type_doc"]["libelle"];
-
-		// Identifiants (isbn / ean)
-		if($notice["type_doc"]!="100")
-		{
-			$isbn=$this->analyseur->getIsbn();
-			if(!$isbn) $isbn=$this->analyseur->getEan();
-			if($isbn["multiple"]==true) $ret["warnings"][]="Isbn multiple";
-			if($isbn["statut"] == 1) $ret["warnings"][]="ISBN ou EAN incorrect";
-			if($isbn["isbn"]) $ret["identifiant"]="ISBN identifié";
-			elseif($isbn["ean"])  $ret["identifiant"]="EAN identifié";
-			else $ret["identifiant"]="Aucun identifiant";
-
-			// Genres
-			if($notice["genres"])
-			{
-				foreach($notice["genres"] as $genre) $ret["genres"][]=$sql->fetchOne("Select libelle from codif_genre where id_genre='$genre'");
-			}
-			else $ret["warnings"][]="Code genre non reconnu";
-
-			// Sections
-			if($notice["sections"])
-			{
-				foreach($notice["sections"] as $section) $ret["sections"][]=$sql->fetchOne("Select libelle from codif_section where id_section='$section'");
-			}
-			else $ret["warnings"][]="Code section non reconnu";
-
-			// Emplacements
-			if($notice["emplacements"])
-			{
-				foreach($notice["emplacements"] as $emplacement) $ret["emplacements"][]=$sql->fetchOne("Select libelle from codif_emplacement where id_emplacement='$emplacement'");
-			}
-			else $ret["warnings"][]="Code emplacement non reconnu";
-
-			// Langues
-			if($notice["langues"])
-			{
-				foreach($notice["langues"] as $langue)
-				{
-					$controle=$sql->fetchOne("Select libelle from codif_langue where id_langue='$langue'");
-					if($controle) $ret["langues"][]=$controle;
-					else $ret["warnings"][]="Code langue non reconnu";
-				}
-			}
-
-			// Champs forcés
-			if(count($notice["champs_forces"]) > 0)
-			{
-				foreach($notice["champs_forces"] as $zone => $champ) $ret["zones_forcees"][]= substr($zone,1);
-			}
-		}
-
-		// Notice sans anomalie
-		if(!$ret["warnings"]) $ret["statut"]="ok";
-
-		// Nombre d'exemplaires
-		$ret["nb_ex"]=$notice["statut_exemplaires"]["nb_ex"];
-		if($ret["nb_ex"] > 100) $ret["warnings"][]="trop d'exemplaires";
-
-		return $ret;
-	}
+  public function syntheseNotice($data)
+  {
+    global $sql;
+
+    $this->analyseur->ouvrirNotice($data,$this->id_profil,$this->sigb);
+    $notice=$this->analyseur->getNoticeIntegration();
+
+    // Notice à supprimer
+    if($notice["statut"]==1) {$ret["statut"]="suppr"; return $ret;}
+
+    // Notice rejetee
+    $ret["statut"]="rejet";
+    if(!$notice["titre_princ"]) {$ret["rejet"]="notice sans titre"; return $ret;}
+    if($notice["type_doc"]!="100" and !$notice["statut_exemplaires"]["nb_ex"]) {$ret["rejet"]="notice sans exemplaire"; return $ret;}
+
+    // Warnings
+    $ret["statut"]="warning";
+    if($notice["type_doc"]!="100")
+    {
+      if(!$notice["statut_exemplaires"]["codes_barres"]) $ret["warnings"][]="code-barres non trouvé";
+      if(!$notice["statut_exemplaires"]["cotes"]) $ret["warnings"][]="cote non trouvée";
+    }
+    if(!$notice["type_doc"])$ret["warnings"][]="Type de document non reconnu";
+
+    // Type de doc
+    if($notice["type_doc"]) $ret["type_doc"]=$notice["infos_type_doc"]["libelle"];
+
+    // Identifiants (isbn / ean)
+    if($notice["type_doc"]!="100")
+    {
+      $isbn=$this->analyseur->getIsbn();
+      if(!$isbn) $isbn=$this->analyseur->getEan();
+      if($isbn["multiple"]==true) $ret["warnings"][]="Isbn multiple";
+      if($isbn["statut"] == 1) $ret["warnings"][]="ISBN ou EAN incorrect";
+      if($isbn["isbn"]) $ret["identifiant"]="ISBN identifié";
+      elseif($isbn["ean"])  $ret["identifiant"]="EAN identifié";
+      else $ret["identifiant"]="Aucun identifiant";
+
+      // Genres
+      if($notice["genres"])
+      {
+        foreach($notice["genres"] as $genre) $ret["genres"][]=$sql->fetchOne("Select libelle from codif_genre where id_genre='$genre'");
+      }
+      else $ret["warnings"][]="Code genre non reconnu";
+
+      // Sections
+      if($notice["sections"])
+      {
+        foreach($notice["sections"] as $section) $ret["sections"][]=$sql->fetchOne("Select libelle from codif_section where id_section='$section'");
+      }
+      else $ret["warnings"][]="Code section non reconnu";
+
+      // Emplacements
+      if($notice["emplacements"])
+      {
+        foreach($notice["emplacements"] as $emplacement) $ret["emplacements"][]=$sql->fetchOne("Select libelle from codif_emplacement where id_emplacement='$emplacement'");
+      }
+      else $ret["warnings"][]="Code emplacement non reconnu";
+
+      // Langues
+      if($notice["langues"])
+      {
+        foreach($notice["langues"] as $langue)
+        {
+          $controle=$sql->fetchOne("Select libelle from codif_langue where id_langue='$langue'");
+          if($controle) $ret["langues"][]=$controle;
+          else $ret["warnings"][]="Code langue non reconnu";
+        }
+      }
+
+      // Champs forcés
+      if(count($notice["champs_forces"]) > 0)
+      {
+        foreach($notice["champs_forces"] as $zone => $champ) $ret["zones_forcees"][]= substr($zone,1);
+      }
+    }
+
+    // Notice sans anomalie
+    if(!$ret["warnings"]) $ret["statut"]="ok";
+
+    // Nombre d'exemplaires
+    $ret["nb_ex"]=$notice["statut_exemplaires"]["nb_ex"];
+    if($ret["nb_ex"] > 100) $ret["warnings"][]="trop d'exemplaires";
+
+    return $ret;
+  }
 
 // ----------------------------------------------------------------
 // Analyse des valeurs distinctes
 // ----------------------------------------------------------------
-	public function valeursDistinctes($champs,$data)
-	{
-		$this->analyseur->ouvrirNotice($data,$this->id_profil,$this->sigb);
-		foreach($champs as $champ)
-		{
-			$zone=substr($champ,0,3);
-			$sous_champ=substr($champ,-1);
-			$valeur=$this->analyseur->get_subfield($zone,$sous_champ);
-			if(!$valeur) $valeur[0] = "non renseigné";
-			foreach($valeur as $code)
-			{
-				$ret[$champ][$code]++;
-			}
-		}
-		return $ret;
-	}
-
-
-	public function analyseurUpdate() {
-		$this->analyseur->update();
-	}
-
-
-	public function get_subfield() {
-		return call_user_func_array([$this->analyseur, 'get_subfield'], func_get_args());
-	}
-
-
-	/** @category testing */
-	public function getServiceRunner() {
-		if (null != $this->_service_runner)
-			return $this->_service_runner;
-		return new Service_Runner();
-	}
-
-
-	public function setServiceRunner($runner) {
-		$this->_service_runner = $runner;
-		return $this;
-	}
+  public function valeursDistinctes($champs,$data)
+  {
+    $this->analyseur->ouvrirNotice($data,$this->id_profil,$this->sigb);
+    foreach($champs as $champ)
+    {
+      $zone=substr($champ,0,3);
+      $sous_champ=substr($champ,-1);
+      $valeur=$this->analyseur->get_subfield($zone,$sous_champ);
+      if(!$valeur) $valeur[0] = "non renseigné";
+      foreach($valeur as $code)
+      {
+        $ret[$champ][$code]++;
+      }
+    }
+    return $ret;
+  }
+
+
+  public function analyseurUpdate() {
+    $this->analyseur->update();
+  }
+
+
+  public function get_subfield() {
+    return call_user_func_array([$this->analyseur, 'get_subfield'], func_get_args());
+  }
+
+
+  /** @category testing */
+  public function getServiceRunner() {
+    if (null != $this->_service_runner)
+      return $this->_service_runner;
+    return new Service_Runner();
+  }
+
+
+  public function setServiceRunner($runner) {
+    $this->_service_runner = $runner;
+    return $this;
+  }
 }
 
 
 class Service_Runner {
-	public function run($type, $args) {
-		return communication::runService($type, $args);
-	}
+  public function run($type, $args) {
+    return communication::runService($type, $args);
+  }
 }
 
 ?>
diff --git a/cosmogramme/php/integration/integration_phase.php b/cosmogramme/php/integration/integration_phase.php
index 0b1f6f6daae68c44d1099ac190cc7c3ace1ce4e2..3927cb0326103cdd5cab7b38eb43ce29f86ef810 100644
--- a/cosmogramme/php/integration/integration_phase.php
+++ b/cosmogramme/php/integration/integration_phase.php
@@ -20,7 +20,7 @@
  */
 
 function startIntegrationPhase($name) {
-	global $chrono, $chrono_fichier, $chrono100notices, $phase, $phase_data, $mode_cron, $reprise, $log;
+	global $chrono, $chrono_fichier, $chrono100notices, $phase, $phase_data, $mode_cron, $reprise, $log, $compteur;
 
 	$integration_class_name = 'Class_Cosmogramme_Integration_Phase'.ucfirst($name);
 
@@ -32,7 +32,8 @@ function startIntegrationPhase($name) {
 	$current_phase = Class_Cosmogramme_Integration_Phase::fromLegacyState($phase,
 																																				$phase_data,
 																																				$mode_cron,
-																																				$reprise);
+																																				$reprise,
+																																				$compteur);
 
 
 	$requested_phase = new $integration_class_name($current_phase,
@@ -43,7 +44,7 @@ function startIntegrationPhase($name) {
 
 // reinject state into global scope
 	$current_chrono->backToLegacyState($chrono, $chrono_fichier, $chrono100notices);
-	$new_phase->backToLegacyState($phase, $phase_data, $mode_cron, $reprise);
+	$new_phase->backToLegacyState($phase, $phase_data, $mode_cron, $reprise, $compteur);
 
 
 	if (!$mode_cron && $requested_phase->isTimeOut())
diff --git a/cosmogramme/php/integration/pseudo_notices.php b/cosmogramme/php/integration/pseudo_notices.php
index e5374f450067e472915666b78e4e1b9142e3f366..93fce93607d2c60d42fbc5ced0906c10528fb950 100644
--- a/cosmogramme/php/integration/pseudo_notices.php
+++ b/cosmogramme/php/integration/pseudo_notices.php
@@ -18,295 +18,10 @@
  * along with BOKEH; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
  */
-// ----------------------------------------------------------------
-// PSEUDO-NOTICES - cms rss sitotheque et albums (phase 0.1 a 0.6)
-// ----------------------------------------------------------------
 
-// ----------------------------------------------------------------
-// Batch
-// ----------------------------------------------------------------
 
-if ($phase >= 0 and $phase < 0.2) {
-	startIntegrationPhase('Batchs');
-	$phase = 0.2;
-}
-
-function deletePseudoNotice($id_notice) {
-	Class_Notice::find($id_notice)->delete();
-}
-// ----------------------------------------------------------------
-// CMS
-// ----------------------------------------------------------------
-if ($phase > 0.1 and $phase < 0.202)
-{
-	// init variables
-	if ($phase == 0.2)
-	{
-		unset($phase_data);
-		$phase_data["nombre"] = 0;
-		$phase_data["timeStart"] = time();
-		$phase_data["pointeur_reprise"] = 0;
-		setVariable("traitement_phase", "Pseudo-notices : CMS");
-		$log->ecrire("<h4>Traitement des pseudo-notices</h4>");
-		$log->ecrire(BR . BR . '<span class="violet">Notices CMS :</span>' . BR);
-	}
-	else print('<span class="violet">Notices CMS :</span>' . BR);
-
-	// suppression des notices et des exemplaires
-	$phase = 0.2001;
-	$items = fetchAll("select id_notice from notices where type_doc=8");
-	if ($items)
-	{
-		foreach ($items as $item)
-		{
-			if (!$mode_cron and $chrono->tempsPasse() > 10) sauveContexte();
-			$id_notice = $item["id_notice"];
-			deletePseudoNotice($id_notice);
-		}
-	}
-	$phase = 0.2002;
-}
-
-
-
-// ----------------------------------------------------------------
-// Articles CMS
-// ----------------------------------------------------------------
-if ($phase == 0.2002)
-{
-	if ($phase_data["nombre"] and !$mode_cron) print('<span class="violet">Notices CMS :</span>' . BR);
-	if (!$mode_cron and $chrono->tempsPasse() > 10) sauveContexte();
-	$chrono->start();
-	$result = $sql->prepareListe("select * from cms_article where ID_ARTICLE >" . $phase_data["pointeur_reprise"] . " and INDEXATION=1 and STATUS NOT IN(1, 2, 4) order by ID_ARTICLE");
-	if ($result)
-	{
-		while ($enreg = $sql->fetchNext($result))
-		{
-			if (!$mode_cron and $chrono->tempsPasse() > 10) sauveContexte();
-			$enreg["id_bib"] = $sql->fetchOne("select ID_SITE from cms_categorie where ID_CAT=" . $enreg["ID_CAT"]);
-			$phase_data["nombre"]++;
-			$ret = $notice->traitePseudoNotice(8, $enreg);
-			tracePseudoNotice($ret, $enreg);
-			$phase_data["pointeur_reprise"] = $enreg["ID_ARTICLE"];
-		}
-	}
-	traceRecapPseudoNotices($phase_data);
-	$phase = 0.201;
-}
-
-
-
-// ----------------------------------------------------------------
-// FILS RSS
-// ----------------------------------------------------------------
-if ($phase < 0.3)
-{
-	// init variables
-	if ($phase == 0.201)
-	{
-		unset($phase_data);
-		$phase_data["nombre"] = 0;
-		$phase_data["timeStart"] = time();
-		$phase_data["pointeur_reprise"] = 0;
-		setVariable("traitement_phase", "Pseudo-notices : FILS RSS :");
-		$log->ecrire('<span class="violet">Notices FILS RSS :</span>' . BR);
-	}
-	else print('<span class="violet">Notices FILS RSS :</span>' . BR);
-
-	// suppression des notices et des exemplaires
-	$phase = 0.21;
-	$items = fetchAll("select id_notice from notices where type_doc=9");
-	if ($items)
-	{
-		foreach ($items as $item)
-		{
-			if (!$mode_cron and $chrono->tempsPasse() > 10) sauveContexte();
-			$id_notice = $item["id_notice"];
-			deletePseudoNotice($id_notice);
-		}
-	}
-	$phase = 0.3;
-}
-
-if ($phase == 0.3)
-	{
-	if ($phase_data["nombre"] and !$mode_cron) print('<span class="violet">Notices FILS RSS :</span>' . BR);
-	if (!$mode_cron and $chrono->tempsPasse() > 10) sauveContexte();
-	$chrono->start();
-	$result = $sql->prepareListe("select * from rss_flux where ID_RSS >" . $phase_data["pointeur_reprise"] . " order by ID_RSS");
-	if ($result)
-	{
-		while ($enreg = $sql->fetchNext($result))
-		{
-			if (!$mode_cron and $chrono->tempsPasse() > 10) sauveContexte();
-			$enreg["id_bib"] = $sql->fetchOne("select ID_SITE from rss_categorie where ID_CAT=" . $enreg["ID_CAT"]);
-			$phase_data["nombre"]++;
-			$ret = $notice->traitePseudoNotice(9, $enreg);
-			tracePseudoNotice($ret, $enreg);
-			$phase_data["pointeur_reprise"] = $enreg["ID_RSS"];
-		}
-	}
-	traceRecapPseudoNotices($phase_data);
-	$phase = 0.4;
-}
-
-// ----------------------------------------------------------------
-// SITHOTHEQUE
-// ----------------------------------------------------------------
-if ($phase < 0.6)
-{
-	// init variables
-	if ($phase == 0.4)
-	{
-		unset($phase_data);
-		$phase_data["nombre"] = 0;
-		$phase_data["timeStart"] = time();
-		$phase_data["pointeur_reprise"] = 0;
-		setVariable("traitement_phase", "Pseudo-notices : SITOTHEQUE :");
-		$log->ecrire('<span class="violet">Notices SITOTHEQUE :</span>' . BR);
-	}
-	else print('<span class="violet">Notices SITOTHEQUE :</span>' . BR);
-
-	// suppression des notices et des exemplaires
-	$phase = 0.41;
-	$items = fetchAll("select id_notice from notices where type_doc=10");
-	if ($items)
-	{
-		foreach ($items as $item)
-		{
-			if (!$mode_cron and $chrono->tempsPasse() > 10) sauveContexte();
-			$id_notice = $item["id_notice"];
-			deletePseudoNotice($id_notice);
-		}
-	}
-	$phase = 0.5;
-}
-
-if ($phase == 0.5)
-{
-	if ($phase_data["nombre"] and !$mode_cron) print('<span class="violet">Notices SITOTHEQUE :</span>' . BR);
-	if (!$mode_cron and $chrono->tempsPasse() > 10) sauveContexte();
-	$chrono->start();
-	$result = $sql->prepareListe("select * from sito_url where ID_SITO >" . $phase_data["pointeur_reprise"] . " order by ID_SITO");
-	if ($result)
-	{
-		while ($enreg = $sql->fetchNext($result))
-		{
-			if (!$mode_cron and $chrono->tempsPasse() > 10) sauveContexte();
-			$enreg["id_bib"] = $sql->fetchOne("select ID_SITE from sito_categorie where ID_CAT=" . $enreg["ID_CAT"]);
-			$phase_data["nombre"]++;
-			$ret = $notice->traitePseudoNotice(10, $enreg);
-			tracePseudoNotice($ret, $enreg);
-			$phase_data["pointeur_reprise"] = $enreg["ID_SITO"];
-		}
-	}
-	traceRecapPseudoNotices($phase_data);
-	$phase = 0.6;
-}
-
-// ----------------------------------------------------------------
-// ALBUMS
-// ----------------------------------------------------------------
-
-
-if ($phase < 0.7)
-{
-	// init variables
-	if ($phase == 0.6)
-	{
-		unset($phase_data);
-		$phase_data["nombre"] = 0;
-		$phase_data["timeStart"] = time();
-		$phase_data["pointeur_reprise"] = 0;
-		setVariable("traitement_phase", "Pseudo-notices : RESSOURCES NUMERIQUES :");
-		$log->ecrire('<span class="violet">Notices RESSOURCES NUMERIQUES :</span>' . BR);
-	}
-	else print('<span class="violet">Notices RESSOURCES NUMERIQUES : suppressions</span>' . BR);
-
-	// suppression des notices et des exemplaires
-	$phase = 0.61;
-	$items = fetchAll("select id_notice from notices where type_doc>99");
-	if ($items)
-	{
-		foreach ($items as $item)
-		{
-			if (!$mode_cron and $chrono->tempsPasse() > 10) sauveContexte();
-			$id_notice = $item["id_notice"];
-			deletePseudoNotice($id_notice);
-		}
-	}
-	$phase = 0.7;
-}
-
-if ($phase == 0.7)
-{
-	if ($phase_data["nombre"] and !$mode_cron)
-		print('<span class="violet">Notices RESSOURCES NUMERIQUES : ajouts</span>' . BR);
-	if (!$mode_cron and $chrono->tempsPasse() > 10)
-		sauveContexte();
-	$chrono->start();
-	$result = $sql->prepareListe("select * from album where id >" . $phase_data["pointeur_reprise"] . " and visible=true order by id");
-	if ($result)
-	{
-		while ($enreg = $sql->fetchNext($result))
-		{
-			if (!$mode_cron and $chrono->tempsPasse() > 10) sauveContexte();
-			$enreg["id_bib"] = $sql->fetchOne("select site_id from album_categorie where id=" . $enreg["cat_id"]);
-			$phase_data["nombre"]++;
-			if(!$enreg["type_doc_id"]) $enreg["type_doc_id"]=100;
-			$ret = $notice->traitePseudoNotice($enreg["type_doc_id"], $enreg);
-			tracePseudoNotice($ret, $enreg);
-			$phase_data["pointeur_reprise"] = $enreg["id"];
-
-      Class_Album::clearCache();
-      Class_AlbumRessource::clearCache();
-      Class_Notice::clearCache();
-      Class_Exemplaire::clearCache();
-		}
-	}
-	traceRecapPseudoNotices($phase_data);
-	$phase = 1;
-}
-
-// ----------------------------------------------------------------
-// Affichage detail pour les pseudo-notices
-// ----------------------------------------------------------------
-function tracePseudoNotice($ret, $enreg)
-{
-	global $debug_level, $phase_data, $log, $compteur;
-
-	// compteurs
-	if ($ret["statut"] > 0) $compteur[$ret["statut"]]++;
-	$phase_data["compteur"][$ret["statut"]]++;
-	if ($debug_level == 0) return;
-
-	// Traces
-	if ($ret["id_notice"]) $log->ecrire('<a class="notice" href="' . URL_BASE . "php/analyse_afficher_notice_full.php?id_notice=" . $ret["id_notice"] . '">Notice n° ' . $ret["id_notice"] . '</a>' . BR);
-	$log->ecrire('<table class="blank" cellspacing="0" cellpadding="5px" style="margin-left:15px;margin-bottom:10px">');
-	$log->ecrire('<tr><td class="blank">Titre</td><td class="blank">' . $enreg["TITRE"] . '</td></tr>');
-	$log->ecrire('<tr><td class="blank">Tags</td><td class="blank">' . $enreg["TAGS"] . '</td></tr>');
-	$log->ecrire('<tr><td class="blank">Code-barres</td><td class="blank">' . $ret["code_barres"] . '</td></tr>');
-	$log->ecrire('<tr><td class="blank">Unimarc</td><td class="blank">' . $ret["unimarc"] . '</td></tr>');
-	$log->ecrire('</table>');
-}
-
-// ----------------------------------------------------------------
-// Recap pour les pseudo-notices
-// ----------------------------------------------------------------
-function traceRecapPseudoNotices($phase_data)
-{
-	global $log, $chrono;
-
-	if ($phase_data["nombre"] == 0)
-	{
-		$log->ecrire('<span class="vert">Aucune notice à traiter</span><br>');
-		return;
-	} else
-	{
-		$log->ecrire('<span class="vert">' . $phase_data["nombre"] . ' notices(s) traitée(s)</span>' . BR);
-		$chrono->timeStart = $phase_data["timeStart"];
-		$log->ecrire('<span class="vert">Temps de traitement : ' . $chrono->end() . " (" . $chrono->moyenne($phase_data["nombre"], "notices") . ")</span>" . BR.BR);
-	}
-}
-
-?>
+startIntegrationPhase('Batchs');
+startIntegrationPhase('PseudoRecordCms');
+startIntegrationPhase('PseudoRecordRss');
+startIntegrationPhase('PseudoRecordSitotheque');
+startIntegrationPhase('PseudoRecordAlbum');
diff --git a/cosmogramme/sql/patch/patch_265.php b/cosmogramme/sql/patch/patch_265.php
new file mode 100644
index 0000000000000000000000000000000000000000..79af65cba287f5bd2463c72980718b705250bb91
--- /dev/null
+++ b/cosmogramme/sql/patch/patch_265.php
@@ -0,0 +1,14 @@
+<?php
+$adapter = Zend_Db_Table::getDefaultAdapter();
+foreach([['table' => 'album', 'id' => 'notice_id'],
+         ['table' => 'cms_article', 'id' => 'id_notice'],
+         ['table' => 'rss_flux', 'id' => 'id_notice'],
+         ['table' => 'sito_url', 'id' => 'id_notice']]
+        as $params) {
+
+  $adapter->query(sprintf('ALTER TABLE `%s` MODIFY `%s` int(11) null default null',
+                          $params['table'], $params['id']));
+
+  $adapter->query(sprintf('UPDATE `%s` SET `%s`=null WHERE `%s`=0',
+                          $params['table'], $params['id'], $params['id']));
+}
\ No newline at end of file
diff --git a/cosmogramme/sql/patch/patch_266.php b/cosmogramme/sql/patch/patch_266.php
new file mode 100644
index 0000000000000000000000000000000000000000..b41562792ca763e6e3ff5aff6724d45ce044ab2d
--- /dev/null
+++ b/cosmogramme/sql/patch/patch_266.php
@@ -0,0 +1,7 @@
+<?php
+$adapter = Zend_Db_Table::getDefaultAdapter();
+try {
+  $adapter->query('SELECT data FROM batchs LIMIT 1');
+} catch(Exception $e) {
+  $adapter->query('ALTER TABLE batchs ADD COLUMN data TEXT NULL');
+}
diff --git a/cosmogramme/sql/patch/patch_267.php b/cosmogramme/sql/patch/patch_267.php
new file mode 100644
index 0000000000000000000000000000000000000000..c03e6db42403815bc0e9a01cb0781721420524f9
--- /dev/null
+++ b/cosmogramme/sql/patch/patch_267.php
@@ -0,0 +1,9 @@
+<?php
+$adapter = Zend_Db_Table::getDefaultAdapter();
+
+try {
+  $adapter->query('select destination_email from cms_article limit 1;');
+} catch (Exception $e) {
+  $adapter->query('alter table cms_article add column destination_email varchar(255);');
+}
+?>
diff --git a/cosmogramme/tests/php/classes/NanookRecordsIntegrationTest.php b/cosmogramme/tests/php/classes/NanookRecordsIntegrationTest.php
index 325a27b8c420da98d5cafdc6f323c5525efaa0e7..e960244e090f0235105c8db837c52c2102239c55 100644
--- a/cosmogramme/tests/php/classes/NanookRecordsIntegrationTest.php
+++ b/cosmogramme/tests/php/classes/NanookRecordsIntegrationTest.php
@@ -482,3 +482,27 @@ class NanookRecordsIntegrationSerialDroitDeVivreEnFamilleTest extends NanookReco
                                                                    'clef_unimarc' => $clef_unimarc]));
   }
 }
+
+
+
+class NanookRecordsIntegrationSerialLiensFamiliauxTest extends NanookRecordsIntegrationTestCase {
+  public function setUp() {
+    parent::setUp();
+
+    $this->fixture('Class_Notice_SerialArticles',
+                   ['id' => 1,
+                    'clef_chapeau' => 'REVUE QUART MONDE',
+                    'clef_numero' => '231',
+                    'clef_article' => 'SORTIR D UNE TRANSMI',
+                    'clef_unimarc' => '']);
+
+    $this->loadRecordsFromFile("unimarc_liens_familiaux");
+    $this->notice = Class_Notice::find(1);
+  }
+
+
+  /** @test */
+  public function firstArticleShouldBeOnEstPasDesChiens() {
+    $this->assertEquals("Revue Quart Monde n° 231<br /> «On n’est pas des chiens !» : Editorial", $this->notice->getArticlesPeriodique()[0]['titre']);
+  }
+}
\ No newline at end of file
diff --git a/cosmogramme/tests/php/classes/NoticeIntegrationTest.php b/cosmogramme/tests/php/classes/NoticeIntegrationTest.php
index 92eb1b8a2ee0117a16bb4d4e43e4e225d49e12c8..718568f4b601b7439d02da9ca39a7fccd3bc8456 100644
--- a/cosmogramme/tests/php/classes/NoticeIntegrationTest.php
+++ b/cosmogramme/tests/php/classes/NoticeIntegrationTest.php
@@ -158,216 +158,6 @@ abstract class NoticeIntegrationTestCase extends ModelTestCase {
 
 
 
-class NoticeIntegrationLivreNumTest extends NoticeIntegrationTestCase {
-	public function setUp() {
-		parent::setUp();
-		$notice_integration = new notice_integration();
-
-		$this->fixture('Class_CodifThesaurus', ['id' =>25,
-																						'id_origine' => 5,
-																						'id_thesaurus' => 25,
-																						'code' => Class_CodifThesaurus::CODE_CATALOGUE,
-																						'libelle' => 'thesaurus']);
-
-		$this->fixture('Class_CodifThesaurus', ['id' =>29,
-																						'id_origine' => 6,
-																						'id_thesaurus' => 29,
-																						'code' => Class_CodifThesaurus::CODE_CATALOGUE,
-																						'libelle' => 'thesaurus']);
-
-
-		$this->fixture('Class_CodifAuteur', ['id' => '234']);
-		$this->fixture('Class_Album', ['id' => 100,
-																	 'status' => Class_Album::STATUS_VALIDATED]);
-
-		$this->ret = $notice_integration
-			->traitePseudoNotice(100,
-			['id' => 100,
-			'id_bib' => 2,
-			'titre'=>'Eloge de la fuite',
-			'tags'=> 'domination,sociologie,biologie',
-			'auteur' => 'Laborit Henri',
-			'id_origine' => '666',
-			'domaine_ids' => '5;6',
-			'nature_doc' => '1;2']);
-
-		$this->notice_sgbd->ouvrirNotice($this->ret['unimarc'], 0);
-	}
-
-
-	/** @test */
-	public function titreShouldBeElogeDeLaFuite() {
-		$this->assertEquals('Eloge de la fuite', $this->notice_sgbd->get_subfield('200', 'a')[0]);
-	}
-
-
-	/** @test */
-	public function facettesShouldContainBeHenriLaborit() {
-		$this->assertContains('A234', $this->ret['facettes']);
-	}
-
-
-	/** @test */
-	public function unimarcAuteurShouldBeA234() {
-		$this->assertEquals('Laborit Henri', $this->notice_sgbd->get_subfield('701', 'a')[0]);
-	}
-
-
-	/** @test */
-	public function subfield200_b_ShouldContainsCollectionAndDataset() {
-		$this->assertEquals(['Collection', 'Dataset'], $this->notice_sgbd->get_subfield('200', 'b'));
-	}
-
-}
-
-
-
-
-abstract class NoticeIntegrationSacramentariumTestCase extends NoticeIntegrationTestCase {
-	public function setUp() {
-		parent::setUp();
-
-		$this->fixture('Class_CodifMatiere', ['id' => 62115,
-		'libelle' => 'Douzième siècle']);
-
-		$this->sacramentarium = $this->fixture(
-			'Class_Album',
-			['id'=>'144',
-			'cat_id'=>'30',
-			'notice_id'=>'99421',
-			'titre'=>'MS 14 - Sacramentarium ad usum Sylviniacensem',
-			'auteur'=>'',
-			'editeur'=>'',
-			'annee'=>'',
-			'description'=>'',
-			'tags'=>'',
-			'date_maj'=>'2012-10-22 16:49:57',
-			'fichier'=>'144_B031906101_MS_014_0033R.jpg',
-			'type_doc_id'=>'100',
-			'id_langue'=>'lat',
-			'genre'=>'7;99',
-			'dewey'=>'',
-			'matiere'=>'62115',
-			'id_origine'=>'D09030160',
-			'cfg_thumbnails'=>'',
-			'a:9:{s:15:"thumbnail_width";s:3:"400";s:28:"thumbnail_left_page_crop_top";s:1:"0";s:30:"thumbnail_left_page_crop_right";s:2:"35";s:31:"thumbnail_left_page_crop_bottom";s:1:"0";s:29:"thumbnail_left_page_crop_left";s:1:"0";s:29:"thumbnail_right_page_crop_top";s:1:"0";s:31:"thumbnail_right_page_crop_right";s:1:"0";s:32:"thumbnail_right_page_crop_bottom";s:1:"0";s:30:"thumbnail_right_page_crop_left";s:2:"35";}',
-			'status' => Class_Album::STATUS_VALIDATED,
-			'pdf'=>'',
-			'sous_titre'=>'Sacramentaire de Souvigny',
-			'cote'=>'MS 14',
-			'provenance'=>'Prieuré de Souvigny',
-			'notes'=>'a:3:{s:5:"305$a";s:12:"XIIe siècle";s:5:"200$b";s:9:"Parchemin";s:5:"316$a";s:12:"Reliure bois";}',
-			'url_origine'=>null,
-			'visible'=> '1',
-			'droits'=> 'Domaine public',
-			'nature_doc'=> '',
-			'id_bib' => 1,
-			'bibliotheques' => '7;87',
-			'annexes' => '6;55',
-			'sections' => '12;23',
-			'status' => Class_Album::STATUS_VALIDATED]);
-
-
-		$this->notice_integration = new notice_integration();
-		$this->pseudo_notice = $this->notice_integration
-			->traitePseudoNotice(100,
-													 $this->sacramentarium->rawToArray());
-		$this->notice_sgbd->ouvrirNotice($this->pseudo_notice['unimarc'], 0);
-	}
-
-
-	protected function assertFacettesContains($value) {
-		$this->assertTrue(false !== strpos($this->pseudo_notice['facettes'], $value),
-											'Failed asserting that facettes CONTAINS [' . $value . ']');
-	}
-}
-
-
-
-
-class NoticeIntegrationSacramentariumParsingTest extends NoticeIntegrationSacramentariumTestCase {
-	/** @test */
-	public function subfield200_bShouldBeParchemin() {
-		$this->assertEquals('Parchemin', $this->notice_sgbd->get_subfield('200', 'b')[0]);
-	}
-
-
-	/** @test */
-	public function matiereShouldBeDouziemeSiecle() {
-		$this->assertEquals('Douzième siècle', $this->notice_sgbd->get_subfield("610", "a")[0]);
-	}
-
-
-	/** @test */
-	public function titreShouldBeSacramentarium() {
-		$this->assertEquals('MS 14 - Sacramentarium ad usum Sylviniacensem',
-												$this->notice_sgbd->get_subfield("200", "a")[0]);
-	}
-
-
-	/** @test */
-	public function bibliotheque7ShouldBeInFacettes() {
-		$this->assertFacettesContains('B7');
-	}
-
-
-	/** @test */
-	public function bibliotheque87ShouldBeInFacettes() {
-		$this->assertFacettesContains('B87');
-	}
-
-
-	/** @test */
-	public function annexe6ShouldBeInFacettes() {
-		$this->assertFacettesContains('Y6');
-	}
-
-
-	/** @test */
-	public function annexe55ShouldBeInFacettes() {
-		$this->assertFacettesContains('Y55');
-	}
-
-
-	/** @test */
-	public function section12ShouldBeInFacettes() {
-		$this->assertFacettesContains('S12');
-	}
-
-
-	/** @test */
-	public function section23ShouldBeInFacettes() {
-		$this->assertFacettesContains('S23');
-	}
-
-	/** @test */
-	public function genre7ShouldBeInFacettes() {
-		$this->assertFacettesContains('G7');
-	}
-
-	/** @test */
-	public function genre99ShouldBeInFacettes() {
-		$this->assertFacettesContains('G99');
-	}
-
-	/** @test */
-	public function typeDocShouldBeInFacettes() {
-		$this->assertFacettesContains('T100');
-	}
-
-
-	/** @test */
-	public function basePathShouldBeUserfilesAlbum() {
-		$my_path = realpath(dirname(__FILE__));
-		$root = substr($my_path, 0, strpos($my_path, '/cosmogramme'));
-		$this->assertEquals($root . '/userfiles/album/144/', $this->sacramentarium->getBasePath());
-	}
-}
-
-
-
-
-
 class NoticeIntegrationLollipopGeneratedNoticeRecordTest extends NoticeIntegrationTestCase {
 	public function setUp() {
 		parent::setUp();
diff --git a/cosmogramme/tests/php/classes/unimarc_liens_familiaux.txt b/cosmogramme/tests/php/classes/unimarc_liens_familiaux.txt
new file mode 100644
index 0000000000000000000000000000000000000000..a3480025c722d4d1d7895bd2937eea7b0b10cf70
--- /dev/null
+++ b/cosmogramme/tests/php/classes/unimarc_liens_familiaux.txt
@@ -0,0 +1 @@
+01172nas2 2200205   450 0010005000001000013000051010008000182000040000262100041000662150017001073300324001244610064004487000020005128010017005329320012005499930014005619950159005759950116007349950116008501165  a20150513  aFRE1 aLiens familiaux : que transmettre ?  a[Paris]cÉditions Quart Monded2014  d24 cma64 p.  aCellule de base qui permet aux petits d’hommes, quand l’environnement est favorable, de s’enraciner dans un monde de pairs et de se créer une identité personnelle, la famille est dans certains contextes oblitérée par des difficultés qui pèsent très lourdement sur la transmission de valeurs et de repères.  c[Paris]nÉditions Quart MondetRevue Quart Mondev2310282 1aATD Quart Monde 2aFrc20150915  aFamille  43aAdulte  aATD MontreuilfATD1-01756kPa 2014 231Cm20150915qurpzppocv12[CSP][A consulter sur place][0][0][A consulter sur place][0][0][1][0]42015-07-018193  aATD MontreuilfATD1-01757kPa 2014 231P1m20150915qurpzppopv12[DIS][Disponible][0][1][][0][0][0][0]8193  aATD MontreuilfATD1-01758kPa 2014 231P2m20150915qurpzppopv12[DIS][Disponible][0][1][][0][0][0][0]819300182naa2 2200073   450 00100050000020000470000546100270005270000290007911711 a«On n’est pas des chiens !»eEditorial  tRevue Quart Mondev231 1aIsabelle Pypaert Perrin00192naa2 2200073   450 00100050000020000540000546100270005970000320008611701 aLiens familiaux : que transmettre ?eIntroduction  tRevue Quart Mondev231 1aMartine Hosselet Herbignat00166naa2 2200073   450 00100050000020000360000546100270004170000240006811731 aUn puits sans fond de questions  tRevue Quart Mondev231 1aMaryvonne Caillaux00153naa2 2200073   450 00100050000020000280000546100270003370000190006011771 aLe bon goût du partage  tRevue Quart Mondev231 1aClaude Farrer00170naa2 2200073   450 00100050000020000440000546100270004970000200007611791 aSortir d’une transmission paralysante  tRevue Quart Mondev231 1aJérémy Ianni00166naa2 2200073   450 00100050000020000410000546100270004670000190007311741 a«Personne n’était avec nous…»  tRevue Quart Mondev231 1aIngrid Hutter00255naa2 2200085   450 00100050000020000830000546100270008870000290011593200250014411671 aEnseigner l’art de la différenciation et de la conformité aux enfants roms  tRevue Quart Mondev231 1aAlice Sophie Sarcinelli  aMigration-Minorités00135naa2 2200073   450 00100050000020000090000546100270001470000200004111681 aErna  tRevue Quart Mondev231 1aMieke Van Dyck00214naa2 2200073   450 00100050000020000890000546100270009470000190012111801 aLégitimité de tous les parents pour contribuer à la réussite de tous les enfants  tRevue Quart Mondev231 1aBruno Masurel00208naa2 2200073   450 00100050000020000600000546100270006570000420009211761 aFamilles pauvres : soutenir le lien dans la séparation  tRevue Quart Mondev231 1aATD Quart Monde, Lst, Pivot Belgique00164naa2 2200073   450 00100050000020000240000546100270002970000340005611721 aAu balcon de la vie  tRevue Quart Mondev231 1aMarie-Hélène Dacos Burgues00171naa2 2200073   450 00100050000020000430000546100270004870000220007511751 aL'exil forcé des enfants réunionnais  tRevue Quart Mondev231 1aColette Duquesne00169naa2 2200073   450 00100050000020000400000546100270004570000230007211781 aLes liens familiaux, une boussole ?  tRevue Quart Mondev231 1aPerrine Levasseur00170naa2 2200073   450 00100050000020000450000546100270005070000190007711661 aLa culture, une arme contre la pauvreté  tRevue Quart Mondev231 1aLaurens Umans00167naa2 2200073   450 00100050000020000450000546100270005070000160007711691 aCe que j’ai appris d’ATD Quart Monde  tRevue Quart Mondev231 1aS M Miller
\ No newline at end of file
diff --git a/library/Class/AdminVar.php b/library/Class/AdminVar.php
index 2e4c58b79a0c11a1ba8ff956d95d3a11aeb16c84..dbfc7f0e30e1e33a1ae2d7c459dfc25d7604a060 100644
--- a/library/Class/AdminVar.php
+++ b/library/Class/AdminVar.php
@@ -236,6 +236,9 @@ class Class_AdminVarLoader extends Storm_Model_Loader {
                    'DILICOM_PNB_SERVER_URL' => Class_AdminVar_Meta::newDefault($this->_('Url du serveur PNB Dilicom'))->bePrivate(),
                    'DILICOM_PNB_IP_ADRESSES' => Class_AdminVar_Meta::newMultiInput($this->_('Liste des adresses IP publiques autorisées pour la consultation des documents'),
                                                                                    ['validate' => 'ZendAfi_Validate_Dilicom_IpAdresses'])->bePrivate(),
+                   'DILICOM_PNB_FTP_SERVER' => Class_AdminVar_Meta::newDefault($this->_('Serveur FTP de diffusion des offres PNB Dilicom'))->bePrivate(),
+                   'DILICOM_PNB_FTP_USER' => Class_AdminVar_Meta::newDefault($this->_('Utilisateur FTP de diffusion des offres PNB Dilicom'))->bePrivate(),
+                   'DILICOM_PNB_FTP_PASS' => Class_AdminVar_Meta::newDefault($this->_('Mot de passe FTP de diffusion des offres PNB Dilicom'))->bePrivate(),
                    'MYCOW_EID' => Class_AdminVar_Meta::newDefault($this->_('Clé d\'identification MyCOW.EU pour le portail. Cette clé doit être fournie par MyCOW.EU. Elle active la ressource numérique dans le portail.'))->bePrivate(),
 
                    'ONEDTOUCH_URL' => Class_AdminVar_Meta::newDefault($this->_('Adresse du serveur OAI 1D touch'))->bePrivate(),
diff --git a/library/Class/Album.php b/library/Class/Album.php
index d8d80d4a6edb29a12d6faed4b734292ce5a29e0d..c019bac7a49143a90fe8bed5a0685ddae3e4b684 100644
--- a/library/Class/Album.php
+++ b/library/Class/Album.php
@@ -98,10 +98,9 @@ class Class_Album extends Storm_Model_Abstract {
   protected $_belongs_to = ['categorie' => ['model' => 'Class_AlbumCategorie',
                                             'referenced_in' => 'cat_id'],
                             'type_doc' => ['model' => 'Class_TypeDoc'],
+
                             'langue' => ['model' => 'Class_CodifLangue',
-                                         'referenced_in' => 'id_langue'],
-                            'notice' => ['model' => 'Class_Notice',
-                                         'referenced_in' => 'notice_id']];
+                                         'referenced_in' => 'id_langue']];
 
   protected $_has_many = ['ressources' => ['model' => 'Class_AlbumRessource',
                                            'role'       => 'album',
@@ -117,7 +116,8 @@ class Class_Album extends Storm_Model_Abstract {
                                       'role' => 'album',
                                       'dependents' => 'delete']];
 
-  protected $_default_attribute_values = ['titre' => '',
+  protected $_default_attribute_values = ['notice_id' => null,
+                                          'titre' => '',
                                           'sous_titre' => '',
                                           'editeur' => '',
                                           'fichier' => '',
@@ -161,7 +161,12 @@ class Class_Album extends Storm_Model_Abstract {
     [self::STATUS_DRAFT => 'Brouillon',
      self::STATUS_VALIDATED => 'Validé'];
 
-  public $arbre_array;
+
+  public function describeAssociationsOn($associations) {
+		$associations
+			->add(new Storm_Model_Association_HasOne('notice', ['model' => 'Class_Notice',
+																													'referenced_in' => 'notice_id']));
+	}
 
 
   /**
@@ -549,6 +554,11 @@ class Class_Album extends Storm_Model_Abstract {
   }
 
 
+  public function getDomaines() {
+		return [];
+	}
+
+
   /**
    * @param Zend_Controller_Request_Http $request
    * @return array
@@ -847,6 +857,11 @@ class Class_Album extends Storm_Model_Abstract {
   }
 
 
+  protected function hasToBeIndexed() {
+		return $this->isVisible() && $this->isValidated();
+	}
+
+
   /**
    * @return Array
    */
@@ -1451,12 +1466,6 @@ class Class_Album extends Storm_Model_Abstract {
       return 'ico/liste.gif';
   }
 
-
-  public function index() {
-    return Class_Indexation_PseudoNotice::index($this);
-  }
-
-
   /**
    * Main author
    * @return string
diff --git a/library/Class/Article.php b/library/Class/Article.php
index e1a689518bc75272162685697647e7ade0b6bfa0..a6ea95d829edc10f1e990c2598927912c4d443c1 100644
--- a/library/Class/Article.php
+++ b/library/Class/Article.php
@@ -494,9 +494,6 @@ class Class_Article extends Storm_Model_Abstract {
                             'article_original' => ['model' => 'Class_Article',
                                                    'referenced_in' => 'parent_id'],
 
-                            'notice' => ['model' => 'Class_Notice',
-                                         'referenced_in' => 'id_notice'],
-
                             'bib' => ['through' => 'categorie'],
 
                             'lieu' => ['model' => 'Class_Lieu',
@@ -517,6 +514,7 @@ class Class_Article extends Storm_Model_Abstract {
                                       'refus_message'];
 
   protected $_default_attribute_values = [
+    'id_notice' => null,
     'titre' => '',
     'description' => '',
     'contenu' => '',
@@ -536,8 +534,17 @@ class Class_Article extends Storm_Model_Abstract {
     'domaine_ids' => '',
     'id_origine' => 0,
     'refus_message' => '',
+    'destination_email' => '',
     'all_day' => FALSE];
 
+
+  public function describeAssociationsOn($associations) {
+		$associations
+			->add(new Storm_Model_Association_HasOne('notice', ['model' => 'Class_Notice',
+																													'referenced_in' => 'id_notice']));
+	}
+
+
   /**
    * Ne retourne que les traductions des articles donnés
    * pour la langue courante.
@@ -631,6 +638,7 @@ class Class_Article extends Storm_Model_Abstract {
 
 
   public function __construct() {
+    parent::__construct();
     $this->_default_attribute_values['langue'] = Class_AdminVar::getDefaultLanguage();
   }
 
@@ -784,8 +792,7 @@ class Class_Article extends Storm_Model_Abstract {
 
 
   protected function hasToBeIndexed() {
-    return ($this->isVisible()
-      && $this->_get('indexation') == 1);
+    return $this->isVisible() && $this->_get('indexation') == 1;
   }
 
 
@@ -985,10 +992,10 @@ class Class_Article extends Storm_Model_Abstract {
    * @return bool
    */
   public function isVisible() {
-    return ($this->isVisibleByDates() && $this->isVisibleByWorkflow());
-
+    return $this->isVisibleByDates() && $this->isVisibleByWorkflow();
   }
 
+
   /**
    * @return bool
    */
@@ -996,13 +1003,15 @@ class Class_Article extends Storm_Model_Abstract {
     return !$this->isVisible();
   }
 
+
   /**
    * @return bool
    */
   public function isVisibleByWorkflow() {
-    return (self::STATUS_VALIDATED == $this->getStatus());
+    return self::STATUS_VALIDATED == $this->getStatus();
   }
 
+
   /**
    * @return bool
    */
@@ -1022,6 +1031,7 @@ class Class_Article extends Storm_Model_Abstract {
     return (($now >= $start) && ($now <= $end));
   }
 
+
   public function beVisible() {
     $date = new DateTime();
 
@@ -1030,6 +1040,7 @@ class Class_Article extends Storm_Model_Abstract {
       ->save();
   }
 
+
   public function beInvisible() {
     $date = new DateTime();
     $date->modify('-1 day');
@@ -1039,6 +1050,7 @@ class Class_Article extends Storm_Model_Abstract {
       ->save();
   }
 
+
   /**
    * @return Class_Article
    */
@@ -1047,6 +1059,7 @@ class Class_Article extends Storm_Model_Abstract {
     return $this;
   }
 
+
   /**
    * @return Class_Article
    */
@@ -1131,6 +1144,7 @@ class Class_Article extends Storm_Model_Abstract {
     return $this->_set('titre', strip_tags($data));
   }
 
+
   public function getNomCompletAuteur() {
     if ($auteur=$this->getAuteur())
       return $auteur->getNomComplet();
@@ -1152,12 +1166,12 @@ class Class_Article extends Storm_Model_Abstract {
     return Class_Profil::getRoot()->findByPath($categorie->getPath());
   }
 
+
   public function renderOn($canvas) {
     return $canvas->renderArticle($this);
   }
 
 
-
   public function getTitleInfo() {
     return '';
   }
@@ -1181,6 +1195,7 @@ class Class_Article extends Storm_Model_Abstract {
     return $this->getTitre();
   }
 
+
   public function copy() {
     $copy = new Class_Article();
     $attributes = $this->_attributes;
@@ -1269,6 +1284,5 @@ class Class_Article extends Storm_Model_Abstract {
       return '';
     return $author->getLoginOrFullName();
   }
-
 }
 ?>
\ No newline at end of file
diff --git a/library/Class/Autocomplete/Index.php b/library/Class/Autocomplete/Index.php
index 37c06bf75510efbec2d4289a5b65727b9ce03d2f..4a5e86c05109b26f36be5ede0b3db03d9313ad51 100644
--- a/library/Class/Autocomplete/Index.php
+++ b/library/Class/Autocomplete/Index.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
  */
 
 
@@ -36,17 +36,17 @@ class Class_Autocomplete_Index {
     return $this->getBasePath() . $this->file_name;
   }
 
-  
+
   public static function getClassFor($name) {
     foreach (['Title' => new Class_Autocomplete_IndexTitle(),
-              'Author' => new Class_Autocomplete_IndexAuthor()] 
+              'Author' => new Class_Autocomplete_IndexAuthor()]
              as $k => $clazz) {
       if ((false !== strpos($name, $k)))
         return $clazz;
     }
     return new Class_Autocomplete_IndexNull();
   }
-  
+
 
   public static function getMethodFor($name) {
     if ('search' == substr($name, 0, 6))
@@ -85,6 +85,7 @@ class Class_Autocomplete_Index {
 
       $current = $response->done;
       Class_Notice::clearCache();
+      Class_CodifAuteur::clearCache();
       Storm_Model_Loader::resetCache();
       gc_collect_cycles();
     } while($response->done < $response->total);
diff --git a/library/Class/Batch.php b/library/Class/Batch.php
index 5425bb8394545364ca18e32a6ee1b81f7ce98c8f..e75a67766964443e3478f7903f3429e51f9fe351 100644
--- a/library/Class/Batch.php
+++ b/library/Class/Batch.php
@@ -19,107 +19,130 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
  */
 
-class Class_BatchLoader extends Storm_Model_Loader{
-
-	public function getKnownTypes() {
-		return array_merge($this->getRessourcesNumeriqueTypes(), [
-						'IMPORT_TYPO3' => new Class_Batch_Typo3(),
-						'CORRECTION_PANIERS' => new Class_Batch_PanierNotice(),
-						'CART_REALLOCATION' => new Class_Batch_PanierUser(),
-						'COMMENT_REALLOCATION'=> new Class_Batch_AvisNotice(),
-						'INDEX_RESSOURCES_NUMERIQUES' => new Class_Batch_IndexRessourcesNumeriques(),
-						'AUTOCOMPLETE_RECORD_TITLE' => new Class_Batch_AutocompleteRecordTitle(),
-						'AUTOCOMPLETE_RECORD_AUTHOR' => new Class_Batch_AutocompleteRecordAuthor(),
-						'BUILD_SITE_MAP' => new Class_Batch_BuildSiteMap(),
-						'UPDATE_PREMIER_CHAPITRE' => new Class_Batch_PremierChapitre(),
-			]);
-	}
-
-	public function getRessourcesNumeriqueTypes() {
-		return ['MOISSONNAGE_VODECLIC' => new Class_Batch_Vodeclic(),
-						'MOISSONNAGE_ARTEVOD' => new Class_Batch_ArteVOD(),
-						'MOISSONNAGE_NUMERIQUEPREMIUM' => new Class_Batch_NumeriquePremium(),
-						'MOISSONNAGE_NUMILOG' => new Class_Batch_Numilog(),
-						'MOISSONNAGE_CYBERLIBRIS' => new Class_Batch_Cyberlibris(),
-						'MOISSONNAGE_TOUTAPPRENDRE' => new Class_Batch_ToutApprendre(),
-						'MOISSONNAGE_1DTOUCH' => new Class_Batch_OneDTouch(),
-						'MOISSONNAGE_ORPHEA' => new Class_Batch_Orphea(),
-						'MOISSONNAGE_JAMENDO' => new Class_Batch_Jamendo(),
-		];
-	}
-
-
-	public function getKnownType($type) {
-		return $this->getKnownTypes()[$type];
-	}
-
-
-	public function getActiveTypes() {
-		$result = [];
-		$batchs_objets = Class_Batch::findAll();
-		foreach($batchs_objets as $batch)
-			$result[] = $batch->getType();
-		return $result;
-	}
-
-
-	public function getAvailableType() {
-		$availables = Class_Batch::getAvailableBatchs();
-		$actives = Class_Batch::getActiveTypes();
-		$result = [];
-		foreach ($availables as $type => $label)
-			if (!in_array($type, $actives))
-				$result[$type] = $label;
-
-		return $result;
-	}
-
-
-	public function getBatchLibelle($type) {
-		return Class_Batch::getKnownType($type)->getLabel();
-	}
-
-
-	public function getAvailableBatchs() {
-		$result = [];
-		$types = Class_Batch::getKnownTypes();
-		foreach($types as $type => $batch)
-			if ($batch->isEnabled())
-				$result[$type] = $batch->getLabel();
-
-		return $result;
-	}
+class Class_BatchLoader extends Storm_Model_Loader {
+
+  public function getKnownTypes() {
+    return array_merge($this->getRessourcesNumeriqueTypes(),
+                       [
+                        Class_Batch_Typo3::TYPE => new Class_Batch_Typo3(),
+                        Class_Batch_PanierNotice::TYPE => new Class_Batch_PanierNotice(),
+                        Class_Batch_PanierUser::TYPE => new Class_Batch_PanierUser(),
+                        Class_Batch_AvisNotice::TYPE => new Class_Batch_AvisNotice(),
+                        Class_Batch_IndexRessourcesNumeriques::TYPE => new Class_Batch_IndexRessourcesNumeriques(),
+                        Class_Batch_AutocompleteRecordTitle::TYPE => new Class_Batch_AutocompleteRecordTitle(),
+                        Class_Batch_AutocompleteRecordAuthor::TYPE => new Class_Batch_AutocompleteRecordAuthor(),
+                        Class_Batch_BuildSiteMap::TYPE => new Class_Batch_BuildSiteMap(),
+                        Class_Batch_PremierChapitre::TYPE => new Class_Batch_PremierChapitre(),
+      ]);
+  }
+
+  public function getRessourcesNumeriqueTypes() {
+    return [Class_Batch_Vodeclic::TYPE => new Class_Batch_Vodeclic(),
+            Class_Batch_ArteVOD::TYPE => new Class_Batch_ArteVOD(),
+            Class_Batch_NumeriquePremium::TYPE => new Class_Batch_NumeriquePremium(),
+            Class_Batch_Numilog::TYPE => new Class_Batch_Numilog(),
+            Class_Batch_Cyberlibris::TYPE => new Class_Batch_Cyberlibris(),
+            Class_Batch_ToutApprendre::TYPE => new Class_Batch_ToutApprendre(),
+            Class_Batch_OneDTouch::TYPE => new Class_Batch_OneDTouch(),
+            Class_Batch_Orphea::TYPE => new Class_Batch_Orphea(),
+            Class_Batch_Jamendo::TYPE => new Class_Batch_Jamendo(),
+            Class_Batch_Dilicom::TYPE => new Class_Batch_Dilicom(),
+    ];
+  }
+
+
+  public function getKnownType($type) {
+    return $this->getKnownTypes()[$type];
+  }
+
+
+  public function getActiveTypes() {
+    $result = [];
+    $batchs_objets = Class_Batch::findAll();
+    foreach($batchs_objets as $batch)
+      $result[] = $batch->getType();
+    return $result;
+  }
+
+
+  public function getAvailableType() {
+    $availables = Class_Batch::getAvailableBatchs();
+    $actives = Class_Batch::getActiveTypes();
+    $result = [];
+    foreach ($availables as $type => $label)
+      if (!in_array($type, $actives))
+        $result[$type] = $label;
+
+    return $result;
+  }
+
+
+  public function getBatchLibelle($type) {
+    return Class_Batch::getKnownType($type)->getLabel();
+  }
+
+
+  public function getAvailableBatchs() {
+    $result = [];
+    $types = Class_Batch::getKnownTypes();
+    foreach($types as $type => $batch)
+      if ($batch->isEnabled())
+        $result[$type] = $batch->getLabel();
+
+    return $result;
+  }
 
 }
 
 
 class Class_Batch extends Storm_Model_Abstract {
-	protected $_table_name = 'batchs';
-	protected $_loader_class = 'Class_BatchLoader';
-	protected $_default_attribute_values = ['type'=> '', 'last_run' => ''];
+  protected $_table_name = 'batchs';
+  protected $_loader_class = 'Class_BatchLoader';
+  protected $_default_attribute_values = ['type'=> '', 'last_run' => ''];
 
 
-	public function getLibelle() {
-		return ($batch = Class_Batch::getLoader()->getKnownType($this->getType())) ?
-			$batch->getLabel() : '';
-	}
+  public function getLibelle() {
+    return $this->withBatchDo(function($batch) { return $batch->getLabel(); },
+                              '');
+  }
 
 
-	public function run() {
-		if (!$batch = Class_Batch::getLoader()->getKnownType($this->getType()))
-			return;
-		$batch->run();
-		$this->setLastRun(date('Y-m-d H:i:s'))->save();
-		return $this;
-	}
+  public function run() {
+    $closure = function ($batch) {
+      $batch->run();
+      $this->setLastRun(date('Y-m-d H:i:s'))->save();
+      return $this;
+    };
 
+    return $this->withBatchDo($closure, $this);
+  }
 
-	public function runStep($params) {
-		if (!$batch = Class_Batch::getLoader()->getKnownType($this->getType()))
-			return;
-		$response = $batch->runStep($params);
-		$this->setLastRun(date('Y-m-d H:i:s'))->save();
-		return $response;
-	}
+
+  public function runStep($params) {
+    $closure = function($batch) use ($params) {
+      $response = $batch->runStep($params);
+      $this->setLastRun(date('Y-m-d H:i:s'))->save();
+      return $response;
+    };
+
+    return $this->withBatchDo($closure, null);
+  }
+
+
+  public function runWithLogger($logger) {
+    $closure = function ($batch) use ($logger) {
+      $batch->setLogger($logger)->run();
+      $this->setLastRun(date('Y-m-d H:i:s'))->save();
+      return $this;
+    };
+
+    return $this->withBatchDo($closure, $this);
+  }
+
+
+  public function withBatchDo($closure, $default) {
+    return ($batch = Class_Batch::getLoader()->getKnownType($this->getType()))
+      ? $closure($batch) : $default;
+  }
 }
 ?>
diff --git a/library/Class/Batch/Abstract.php b/library/Class/Batch/Abstract.php
index 2466efaa839f5a80eef28ae322a3b5d538c33d92..36423a2dc68b6de6e84f6e2972e16c4583039091 100644
--- a/library/Class/Batch/Abstract.php
+++ b/library/Class/Batch/Abstract.php
@@ -16,27 +16,54 @@
  *
  * 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 Class_Batch_Abstract {
   use Trait_Translator;
 
+  protected $_logger;
+
   public function getLabel() {
     return '';
   }
 
+
   public function run() {
     return;
   }
 
+
   public function runStep($params) {
     return;
   }
 
+
   public function isEnabled() {
     return true;
   }
+
+
+  public function getModel() {
+    return Class_Batch::findFirstBy(['type' => static::TYPE]);
+  }
+
+
+  public function setLogger($logger) {
+    $this->_logger = $logger;
+    return $this;
+  }
+
+
+  public function getLogger() {
+    return $this->_logger ? $this->_logger : new Class_Batch_NullLogger();
+  }
 }
+
+
+class Class_Batch_NullLogger {
+  public function log() {}
+}
+
 ?>
\ No newline at end of file
diff --git a/library/Class/Batch/ArteVOD.php b/library/Class/Batch/ArteVOD.php
index ff3d370d8716cabac466b2650e3fa8ca5410931f..a452f1b7e8334819191d729e6dacef047a405bf9 100644
--- a/library/Class/Batch/ArteVOD.php
+++ b/library/Class/Batch/ArteVOD.php
@@ -16,11 +16,13 @@
  *
  * 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 Class_Batch_ArteVOD extends Class_Batch_RessourceNumerique{
+  const TYPE = 'MOISSONNAGE_ARTEVOD';
+
   protected function _getService() {
     return new Class_WebService_BibNumerique_ArteVOD();
   }
diff --git a/library/Class/Batch/AutocompleteRecordAuthor.php b/library/Class/Batch/AutocompleteRecordAuthor.php
index 501215eba12659d0a9103b6bd64f2b6ca63df1a0..1e5ec0647628f31c83cf6f3427a242795f486588 100644
--- a/library/Class/Batch/AutocompleteRecordAuthor.php
+++ b/library/Class/Batch/AutocompleteRecordAuthor.php
@@ -16,11 +16,13 @@
  *
  * 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 Class_Batch_AutocompleteRecordAuthor extends Class_Batch_Abstract {
+  const TYPE = 'AUTOCOMPLETE_RECORD_AUTHOR';
+
   public function getLabel() {
     return $this->_("Indexer les auteurs de notice pour l'autocompletion");
   }
diff --git a/library/Class/Batch/AutocompleteRecordTitle.php b/library/Class/Batch/AutocompleteRecordTitle.php
index f2b5ec53ba127c670b8792912d7c49d6af18a8a6..d98906d5ec8d695d48795816c5af188123c5017e 100644
--- a/library/Class/Batch/AutocompleteRecordTitle.php
+++ b/library/Class/Batch/AutocompleteRecordTitle.php
@@ -16,11 +16,13 @@
  *
  * 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 Class_Batch_AutocompleteRecordTitle extends Class_Batch_Abstract {
+  const TYPE = 'AUTOCOMPLETE_RECORD_TITLE';
+
   public function getLabel() {
     return $this->_("Indexer les titres de notice pour l'autocompletion");
   }
diff --git a/library/Class/Batch/AvisNotice.php b/library/Class/Batch/AvisNotice.php
index 65edb8d220e83f5ea597766ceb6597c2a2a26773..58fb96bbc2b061c73edfebf44d6f20644e73ccf3 100644
--- a/library/Class/Batch/AvisNotice.php
+++ b/library/Class/Batch/AvisNotice.php
@@ -16,11 +16,13 @@
  *
  * 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 Class_Batch_AvisNotice extends Class_Batch_Abstract {
+  const TYPE = 'COMMENT_REALLOCATION';
+
   public function getLabel() {
     return $this->_('Réaffecte les avis perdus des abonnés');
   }
diff --git a/library/Class/Batch/BuildSiteMap.php b/library/Class/Batch/BuildSiteMap.php
index 6427781f46fa3b3a7ebf0761f24b8b000f64040a..ea08c964e84337c2d5529639d7bf27a84825d6d4 100644
--- a/library/Class/Batch/BuildSiteMap.php
+++ b/library/Class/Batch/BuildSiteMap.php
@@ -16,11 +16,13 @@
  *
  * 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 Class_Batch_BuildSiteMap extends Class_Batch_Abstract {
+  const TYPE = 'BUILD_SITE_MAP';
+
   public function getLabel() {
     return $this->_('Régénère le sitemap XML');
   }
@@ -49,7 +51,7 @@ class Class_Batch_BuildSiteMap extends Class_Batch_Abstract {
     foreach ($profiles as $profile) {
       if (!$profile->isPublic())
         continue;
-      
+
       if (0 == (int) $profile->getCfgAccueilParam('sitemap'))
         continue;
 
diff --git a/library/Class/Batch/Cyberlibris.php b/library/Class/Batch/Cyberlibris.php
index 8fd414157259a2987dc7525de4595be6c4a6f716..886d4ac8ff43542945af7395212dd877c467f00c 100644
--- a/library/Class/Batch/Cyberlibris.php
+++ b/library/Class/Batch/Cyberlibris.php
@@ -16,11 +16,13 @@
  *
  * 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 Class_Batch_Cyberlibris extends Class_Batch_RessourceNumerique{
+  const TYPE = 'MOISSONNAGE_CYBERLIBRIS';
+
   protected function _getService() {
     return new Class_WebService_BibNumerique_Cyberlibris();
   }
diff --git a/library/Class/Batch/Dilicom.php b/library/Class/Batch/Dilicom.php
new file mode 100644
index 0000000000000000000000000000000000000000..bf95495f98cbc3e4ba83f38561f724035b944195
--- /dev/null
+++ b/library/Class/Batch/Dilicom.php
@@ -0,0 +1,247 @@
+<?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_Batch_Dilicom extends Class_Batch_Abstract {
+  use Trait_StaticFileSystem;
+  const TYPE = 'MOISSONAGE_DILICOM';
+
+  protected static $_client;
+  protected $_ftp_path = 'HUB/O/';
+  protected $_local_path;
+  protected $_full_prefix = 'full_pnb_';
+  protected $_inc_prefix = 'diffusion_pnb_';
+
+
+  /** @category testing */
+  public static function setFtpClient($client) {
+    static::$_client = $client;
+  }
+
+  protected static function getFtpClient() {
+    return (static::$_client) ? static::$_client : static::$_client = new Class_FTPClient();
+  }
+
+
+  public function __construct() {
+    $this->_local_path = PATH_TEMP . 'dilicom/';
+  }
+
+
+  public function getLabel() {
+    return $this->_('Import Dilicom');
+  }
+
+
+  protected function _log($message) {
+    $this->getLogger()->log($message . "\n");
+    return $this;
+  }
+
+
+  public function run() {
+    $client = static::getFtpClient();
+
+    if (!$client->connect(Class_AdminVar::get('DILICOM_PNB_FTP_SERVER'),
+                          Class_AdminVar::get('DILICOM_PNB_FTP_USER'),
+                          Class_AdminVar::get('DILICOM_PNB_FTP_PASS'))) {
+      $this->_log($this->_('Impossible de se connecter au serveur %s',
+                           Class_AdminVar::get('DILICOM_PNB_FTP_SERVER')));
+      return false;
+    }
+
+    if (false === $list = $client->ls($this->_ftp_path)) {
+      $this->_log($this->_('Impossible de lister le contenu de %s',
+                           $this->_ftp_path));
+      return false;
+    }
+
+    if (!$list) {
+      $this->_log($this->_('Aucun fichier présent dans %s',
+                           $this->_ftp_path));
+      return false;
+    }
+
+    $list = $this->_detectFiles($list);
+
+    if (!$this->downloadAll($list))
+      return false;
+
+    $this->processAll($list);
+
+    return null;
+  }
+
+
+  protected function ensureLocalPathExists() {
+    if ($this->getFileSystem()->file_exists($this->_local_path))
+      return true;
+
+    if (!$this->getFileSystem()->mkdir($this->_local_path)) {
+      $this->_log($this->_('Impossible de créer le répertoire local %s', $this->_local_path));
+      return false;
+    }
+    return true;
+  }
+
+  protected function downloadAll($list) {
+
+    if (!$this->ensureLocalPathExists())
+      return false;
+
+    foreach($list as $file) {
+      if (!$this->downloadOne($file)) {
+        $this->_log($this->_('Impossible de télécharger le fichier %s',
+                             $this->_ftp_path . $file));
+        return false;
+      }
+    }
+    return true;
+  }
+
+  protected function downloadOne($remote_file) {
+    return static::getFtpClient()->get($this->_ftp_path . $remote_file,
+                                       $this->_local_path . $remote_file);
+  }
+
+  protected function processAll($list) {
+    foreach ($list as $file)
+      $this->processOne($file);
+  }
+
+  protected function processOne($local_file) {
+    $this->_log($this->_('Fichier %s', $local_file));
+
+    $xml = $this->getFileSystem()->file_get_contents($this->_local_path . $local_file);
+    $report = function($import_count, $errors) {
+      $this->_log($this->_('%d livre(s) importé(s)', $import_count));
+
+      if ($errors) {
+        $this->_log($this->_('Erreur(s) : %s',
+                             implode("\n  ", $errors)));
+      }
+    };
+
+    (new Class_WebService_BibNumerique_Dilicom())
+      ->importOffersFile($xml, $report);
+
+    $this->setModelData($local_file);
+  }
+
+
+  protected function setModelData($data) {
+    if ($this->getModel())
+      $this->getModel()->setData($data);
+  }
+
+
+  protected function getModelData() {
+    return $this->getModel() ? $this->getModel()->getData() : null;
+  }
+
+
+  protected function _detectFiles($list) {
+
+    $list = array_map(function($element) { return str_replace($this->_ftp_path, '', $element); }, $list);
+
+    if ($data = $this->getModelData())
+      $list = $this->filesAfter($data, $list);
+
+    if (!$list) {
+      $this->_log($this->_('Aucun fichier plus récent que le dernier fichier déjà traité (%s)',
+                           $data));
+      return [];
+    }
+
+    $fulls = $this->filterFiles($list, function($name) { return $this->isFull($name); });
+    $incs = $this->filterFiles($list, function($name) { return $this->isIncremental($name); });
+
+    $this->_log($this->_('%s fichier(s) à traiter dans %s',
+                         count($fulls) + count($incs),
+                         $this->_ftp_path));
+
+    if ($last_full = $this->lastFileIn($fulls))
+      $this->_log($this->_('Fichier total à traiter : %s', $last_full));
+
+    if ($last_incs = ($last_full ? $this->filesAfter($last_full, $incs): $incs))
+      $this->_log($this->_('Fichiers incrémentaux à traiter : %s',
+                           implode(' ', $last_incs)));
+
+    return array_filter(array_merge([$last_full], $last_incs));
+  }
+
+
+  private function filesAfter($previous, $list) {
+    return array_filter(
+                        $list,
+                        function($name) use ($previous) {
+                          return $this->fileDate($name) > $this->fileDate($previous);
+                        });
+  }
+
+
+  private function lastFileIn($list) {
+    $last = null;
+    foreach($list as $name) {
+      if (null == $last) {
+        $last = $name;
+        continue;
+      }
+
+      if ($this->fileDate($name) > $this->fileDate($last))
+        $last = $name;
+    }
+
+    return $last;
+  }
+
+
+  private function fileDate($name) {
+    $parts = explode('_', $name);
+    return substr(end($parts), 0, 8);
+  }
+
+
+  private function filterFiles($list, $closure) {
+    return array_filter($list, $closure);
+  }
+
+
+  private function isFull($name) {
+    return $this->_startsWith($this->_full_prefix, $name);
+  }
+
+
+  private function isIncremental($name) {
+    return $this->_startsWith($this->_inc_prefix, $name);
+  }
+
+
+  private function _startsWith($prefix, $value) {
+    return substr($value, 0, strlen($prefix)) === $prefix;
+  }
+
+
+  public function isEnabled() {
+    return Class_AdminVar::isDilicomPNBEnabled();
+  }
+}
+?>
\ No newline at end of file
diff --git a/library/Class/Batch/IndexRessourcesNumeriques.php b/library/Class/Batch/IndexRessourcesNumeriques.php
index db8a2945d1ec4499f42330db207e0fea52cf4cf3..77a0b1aa4647afa32cf36ab04f2d0aedaf6acc9b 100644
--- a/library/Class/Batch/IndexRessourcesNumeriques.php
+++ b/library/Class/Batch/IndexRessourcesNumeriques.php
@@ -1,6 +1,8 @@
 <?php
 
 class Class_Batch_IndexRessourcesNumeriques extends Class_Batch_Abstract {
+  const TYPE = 'INDEX_RESSOURCES_NUMERIQUES';
+
   public function getLabel() {
     return $this->_("Indexer les ressources numériques");
   }
diff --git a/library/Class/Batch/Jamendo.php b/library/Class/Batch/Jamendo.php
index 11e7bb1b1721900adf352091429001e501c6ca84..68148377f6d6b94a79737c9deba412242cc41b00 100644
--- a/library/Class/Batch/Jamendo.php
+++ b/library/Class/Batch/Jamendo.php
@@ -21,6 +21,8 @@
 
 
 class Class_Batch_Jamendo extends Class_Batch_RessourceNumerique{
+  const TYPE = 'MOISSONAGE_JAMENDO';
+
   protected function _getService() {
     return new Class_WebService_BibNumerique_Jamendo();
   }
diff --git a/library/Class/Batch/NumeriquePremium.php b/library/Class/Batch/NumeriquePremium.php
index 63cfcdc4cec0959f36971c6707d9abea4d9d238b..375eceacfea9d1b8c1eafa5550fef87a26a1dad5 100644
--- a/library/Class/Batch/NumeriquePremium.php
+++ b/library/Class/Batch/NumeriquePremium.php
@@ -16,11 +16,13 @@
  *
  * 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 Class_Batch_NumeriquePremium extends Class_Batch_RessourceNumerique{
+  const TYPE = 'MOISSONNAGE_NUMERIQUEPREMIUM';
+
   protected function _getService() {
     return new Class_WebService_BibNumerique_NumeriquePremium();
   }
diff --git a/library/Class/Batch/Numilog.php b/library/Class/Batch/Numilog.php
index 90ba4fe80b1ba0fbed861f0db5ebd370e3347996..232529d1be2d4ee6e4bc601e7f4e88bc75f74ed9 100644
--- a/library/Class/Batch/Numilog.php
+++ b/library/Class/Batch/Numilog.php
@@ -16,11 +16,13 @@
  *
  * 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 Class_Batch_Numilog extends Class_Batch_RessourceNumerique{
+  const TYPE = 'MOISSONNAGE_NUMILOG';
+
   protected function _getService() {
     return new Class_WebService_BibNumerique_Numilog();
   }
diff --git a/library/Class/Batch/OneDTouch.php b/library/Class/Batch/OneDTouch.php
index 31013f4953d7e76eaa609acaa9580c5ede61bf2a..a80c6aa6fd48f1cc6b319701be98792912e6700d 100644
--- a/library/Class/Batch/OneDTouch.php
+++ b/library/Class/Batch/OneDTouch.php
@@ -16,11 +16,13 @@
  *
  * 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 Class_Batch_OneDTouch extends Class_Batch_RessourceNumerique{
+  const TYPE = 'MOISSONAGE_1DTOUCH';
+
   protected function _getService() {
     return new Class_WebService_BibNumerique_OneDTouch();
   }
diff --git a/library/Class/Batch/Orphea.php b/library/Class/Batch/Orphea.php
index d84538553329de027f7b2957dbd6c0bcb0e71b3b..a63a41bb9e737a4f43b9aea7ad8ee8d439f51626 100644
--- a/library/Class/Batch/Orphea.php
+++ b/library/Class/Batch/Orphea.php
@@ -21,6 +21,8 @@
 
 
 class Class_Batch_Orphea extends Class_Batch_RessourceNumerique{
+  const TYPE = 'MOISSONNAGE_ORPHEA';
+
   protected function _getService() {
     return new Class_WebService_BibNumerique_Orphea();
   }
diff --git a/library/Class/Batch/PanierNotice.php b/library/Class/Batch/PanierNotice.php
index 0355472613784f88bfffe2c6d283c8ba30b0b08a..e5f1edff1016d8bfb86c06b593ed1c3b48610fd6 100644
--- a/library/Class/Batch/PanierNotice.php
+++ b/library/Class/Batch/PanierNotice.php
@@ -16,11 +16,13 @@
  *
  * 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 Class_Batch_PanierNotice extends Class_Batch_Abstract {
+  const TYPE = 'CORRECTION_PANIERS';
+
   public function getLabel() {
     return $this->_('Recherche les notices perdues des paniers');
   }
diff --git a/library/Class/Batch/PanierUser.php b/library/Class/Batch/PanierUser.php
index c9be2737d7869c96e69a354dc35f96958d69ad18..fb801ddbf9e668a3c6fa0c2b791d9bb643a8be19 100644
--- a/library/Class/Batch/PanierUser.php
+++ b/library/Class/Batch/PanierUser.php
@@ -16,11 +16,13 @@
  *
  * 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 Class_Batch_PanierUser extends Class_Batch_Abstract {
+  const TYPE = 'CART_REALLOCATION';
+
   public function getLabel() {
     return $this->_('Réaffecte les paniers perdus des abonnés');
   }
diff --git a/library/Class/Batch/PremierChapitre.php b/library/Class/Batch/PremierChapitre.php
index 4dbfbc9431c0386c6d61dab89155d05e2294d454..f4221dbd903c0928fd46705092e2e28b457b9db5 100644
--- a/library/Class/Batch/PremierChapitre.php
+++ b/library/Class/Batch/PremierChapitre.php
@@ -21,39 +21,50 @@
 
 
 class Class_Batch_PremierChapitre extends Class_Batch_Abstract {
+  const TYPE = 'UPDATE_PREMIER_CHAPITRE';
+
 	public function getLabel() {
 		return $this->_('Mise à jour des données Premier-Chapitre');
 	}
+
+
 	public function run() {
 		$pc_ws = new Class_WebService_PremierChapitre();
-		$contenu = '';
-		$data = $pc_ws->generate();
-		if ($data) {
-			$contenu .= date('H:i:s')." Le référentiel a bien été mise à jour\n";
-			$data = $pc_ws->getDatafile();
-			if ($data){
-				$contenu .= date('H:i:s')." Le référentiel a bien été téléchargé sur le serveur\nIl est possible de procéder à la mise à jour de la base\n";
-				$data = $pc_ws->updateDatabase();
-				if ($data) {
-					$contenu .= date('H:i:s')." La base a bien été mise à jour\n";
-					$contenu .= '* '.$data['total']." oeuvres ont été lues\n";
-					if ($data['new']) $contenu .= '* '.$data['new'].(($data['new']>1)?" ont été ajoutées":" a été ajoutée")."\n";
-					if ($data['maj']) $contenu .= '* '.$data['maj'].(($data['maj']>1)?" ont été mises":" a été mise")." à jour\n";
-					if ($data['err']) $contenu .= '* '.$data['err'].(($data['err']>1)?" erreurs n'ont pas été traitées":" erreur n'a pas été traitée")."\n";
-					$data = $pc_ws->linkToNotices();
-					if ($data) {
-						$contenu .= date('H:i:s')." Les premiers-chapitres ont bien été liés aux notices\n";
-						$contenu .= '* '.$data['total']." oeuvres ont été traités\n";
-						$contenu .= '* '.$data['maj'].(($data['maj']>1)?" ont été mises":" a été mise")." à jour\n";
-					}
-					else $contenu .= "Une erreur est survenue\nLes liaisons n'ont pu être faites\nVeuillez réessayer ultérieurement";
-				}
-				else $contenu .= "Une erreur est survenue\nLa base n'a pu être mise à jour\nVeuillez réessayer ultérieurement";
-			}
-			else $contenu .= "Une erreur est survenue\nle référentiel n'a pas pu être téléchargé\nVeuillez réessayer ultérieurement";
-		}
-		else $contenu .= "Une erreur est survenue\nle référentiel n'a pas pu être mis a jour\nVeuillez réessayer ultérieurement";
-		$this->content = $contenu;
+
+    if (!$data = $pc_ws->generate()) {
+      $this->content = "Une erreur est survenue\nle référentiel n'a pas pu être mis à jour\nVeuillez réessayer ultérieurement";
+      return;
+    }
+
+    $contenu = date('H:i:s') . " Le référentiel a bien été mise à jour\n";
+    if (!$data = $pc_ws->getDatafile()) {
+      $this->content = $contenu . "Une erreur est survenue\nle référentiel n'a pas pu être téléchargé\nVeuillez réessayer ultérieurement";
+      return;
+    }
+
+    $contenu .= date('H:i:s')." Le référentiel a bien été téléchargé sur le serveur\nIl est possible de procéder à la mise à jour de la base\n";
+    if (!$data = $pc_ws->updateDatabase()) {
+      $this->content = $contenu . "Une erreur est survenue\nLa base n'a pu être mise à jour\nVeuillez réessayer ultérieurement";
+      return;
+    }
+
+    $contenu .= date('H:i:s')." La base a bien été mise à jour\n";
+    $contenu .= '* '.$data['total']." oeuvres ont été lues\n";
+    if ($data['new'])
+      $contenu .= '* '.$data['new'].(($data['new']>1)?" ont été ajoutées":" a été ajoutée")."\n";
+    if ($data['maj'])
+      $contenu .= '* '.$data['maj'].(($data['maj']>1)?" ont été mises":" a été mise")." à jour\n";
+    if ($data['err'])
+      $contenu .= '* '.$data['err'].(($data['err']>1)?" erreurs n'ont pas été traitées":" erreur n'a pas été traitée")."\n";
+
+    if (!$data = $pc_ws->linkToNotices()) {
+      $this->content = $contenu . "Une erreur est survenue\nLes liaisons n'ont pu être faites\nVeuillez réessayer ultérieurement";
+      return;
+    }
+
+		$this->content = $contenu
+      . date('H:i:s')." Les premiers-chapitres ont bien été liés aux notices\n"
+      . '* '.$data['total']." oeuvres ont été traités\n"
+      . '* '.$data['maj'].(($data['maj']>1)?" ont été mises":" a été mise")." à jour\n";
 	}
-}
-?>
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/library/Class/Batch/ToutApprendre.php b/library/Class/Batch/ToutApprendre.php
index 5dd3409ae9bd6e77880ae972584661c713ab914a..47bc9e5232b21ea50457779b8a866b552082962d 100644
--- a/library/Class/Batch/ToutApprendre.php
+++ b/library/Class/Batch/ToutApprendre.php
@@ -16,11 +16,13 @@
  *
  * 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 Class_Batch_ToutApprendre extends Class_Batch_RessourceNumerique {
+  const TYPE = 'MOISSONNAGE_TOUTAPPRENDRE';
+
   protected function _getService() {
     return new Class_WebService_BibNumerique_ToutApprendre();
   }
diff --git a/library/Class/Batch/Typo3.php b/library/Class/Batch/Typo3.php
index d1541c0ff548afd59256b9697d3bc41c29e92ad9..3d9ba03157c0bb67ed6460ef9cabeebea28918ad 100644
--- a/library/Class/Batch/Typo3.php
+++ b/library/Class/Batch/Typo3.php
@@ -21,6 +21,8 @@
 
 
 class Class_Batch_Typo3 extends Class_Batch_Abstract {
+  const TYPE = 'IMPORT_TYPO3';
+
   public function getLabel() {
     return $this->_('Import d\'articles TYPO3');
   }
diff --git a/library/Class/Batch/Vodeclic.php b/library/Class/Batch/Vodeclic.php
index 026cbe0f5b2fcbad5baf9f0db80fa8f52b42fbee..bc56e6e8fd87f231d9c2fc1321dcdbeb1746426f 100644
--- a/library/Class/Batch/Vodeclic.php
+++ b/library/Class/Batch/Vodeclic.php
@@ -16,11 +16,13 @@
  *
  * 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 Class_Batch_Vodeclic extends Class_Batch_RessourceNumerique{
+  const TYPE = 'MOISSONNAGE_VODECLIC';
+
   protected function _getService() {
     return new Class_WebService_BibNumerique_Vodeclic();
   }
diff --git a/library/Class/Bib.php b/library/Class/Bib.php
index 807544f2863295426b68d7ad413a841f2b341a1d..d617c65947af4d7d53986fd09cb6e20ad30128fe 100644
--- a/library/Class/Bib.php
+++ b/library/Class/Bib.php
@@ -221,6 +221,7 @@ class Class_Bib extends Storm_Model_Abstract {
   protected $_translate;
 
   public function __construct() {
+    parent::__construct();
     $this->_translate = Zend_Registry::get('translate');
     $this->statut_bib = array($this->_translate->_('Invisible'),
                               $this->_translate->_('N\'envoie pas de données'),
diff --git a/library/Class/Cosmogramme/Chronometre.php b/library/Class/Cosmogramme/Chronometre.php
index e7c08c6ecdd730f924baa7c2ee0a226ef85ac546..99c579fa4f30fb305ff499e24510befece0fd2a9 100644
--- a/library/Class/Cosmogramme/Chronometre.php
+++ b/library/Class/Cosmogramme/Chronometre.php
@@ -92,7 +92,7 @@ class Class_Cosmogramme_Chronometre {
       $elapsed = 1;
     $mean = $total / ($elapsed / 60);
 
-    return number_format($mean, 0, ',', '.')
+    return number_format($mean, 0, ',', ' ')
       . ' ' . $label . ' par minute';
   }
 }
diff --git a/library/Class/Cosmogramme/Integration/Phase.php b/library/Class/Cosmogramme/Integration/Phase.php
index 3e7e9050b2ba2fb30826f2ca7343e1f6900d5aab..a2332c50b446169bb21e968877986ac7ae7ec680 100644
--- a/library/Class/Cosmogramme/Integration/Phase.php
+++ b/library/Class/Cosmogramme/Integration/Phase.php
@@ -22,17 +22,31 @@
 class Class_Cosmogramme_Integration_Phase {
   use Trait_TimeSource;
 
+  const RECORD_REJECT = 0;
+  const RECORD_INSERT = 1;
+  const RECORD_DELETE = 2;
+  const RECORD_FULLUPDATE = 3;
+  const RECORD_UPDATE = 4;
+  const RECORD_RENEW = 5;
+  const RECORD_UPGRADE = 6;
+  const RECORD_SUCCINCT = 7;
+
+
   protected $_id;
   protected $_datas = [];
   protected $_is_callback = false;
   protected $_is_cron = false;
+  protected $_count = [];
 
 
-  public static function fromLegacyState($id, $datas, $is_cron, $is_callback) {
+  public static function fromLegacyState($id, $datas, $is_cron, $is_callback, $compteur) {
     $instance = new Class_Cosmogramme_Integration_Phase($id);
     foreach($datas as $k => $v)
       $instance->setData($k, $v);
 
+    foreach($compteur as $k => $v)
+      $instance->setCount($k, $v);
+
     if ($is_callback)
       $instance->beCallBack();
 
@@ -52,7 +66,7 @@ class Class_Cosmogramme_Integration_Phase {
   }
 
 
-  public function backToLegacyState(&$id, &$datas, &$is_cron, &$is_callback) {
+  public function backToLegacyState(&$id, &$datas, &$is_cron, &$is_callback, &$count) {
     $id = $this->_id;
     $is_cron = $this->isCron();
     $is_callback = $this->isCallBack();
@@ -60,6 +74,10 @@ class Class_Cosmogramme_Integration_Phase {
     $datas = [];
     foreach($this->_datas as $k => $v)
       $datas[$k] = $v;
+
+    $count = [];
+    foreach($this->_count as $k => $v)
+      $count[$k] = $v;
   }
 
 
@@ -90,6 +108,14 @@ class Class_Cosmogramme_Integration_Phase {
   }
 
 
+  public function beSameCountAs($other) {
+    foreach($other->getFullCount() as $k => $v)
+      $this->setCount($k, $v);
+
+    return $this;
+  }
+
+
   public function isCallBack() {
     return $this->_is_callback;
   }
@@ -127,6 +153,31 @@ class Class_Cosmogramme_Integration_Phase {
   }
 
 
+  public function setCount($type, $value) {
+    $this->_count[$type] = $value;
+    return $this;
+  }
+
+
+  public function getCount($type) {
+    return array_key_exists($type, $this->_count) ?
+      $this->_count[$type] : null;
+  }
+
+
+  public function incrementCount($type) {
+    (!array_key_exists($type, $this->_count)) ?
+      $this->_count[$type] = 0 : $this->_count[$type] += 1;
+
+    return $this;
+  }
+
+
+  public function getFullCount() {
+    return $this->_count;
+  }
+
+
   public function resetDatas() {
     $this->_datas = [];
     return $this;
diff --git a/library/Class/Cosmogramme/Integration/PhaseAbstract.php b/library/Class/Cosmogramme/Integration/PhaseAbstract.php
index aea2fb2f2a65b632d4f495d48cd87269936741c2..559cae022514d619a35491e2013198372ecbb4eb 100644
--- a/library/Class/Cosmogramme/Integration/PhaseAbstract.php
+++ b/library/Class/Cosmogramme/Integration/PhaseAbstract.php
@@ -21,8 +21,7 @@
 
 
 abstract class Class_Cosmogramme_Integration_PhaseAbstract {
-  use Trait_TimeSource;
-  use Trait_StaticFileSystem;
+  use Trait_TimeSource, Trait_StaticFileSystem, Trait_Translator;
 
   protected $_label = '';
   protected $_phase, $_log, $_printer, $_chrono, $_is_time_out;
@@ -51,7 +50,8 @@ abstract class Class_Cosmogramme_Integration_PhaseAbstract {
       return $this->_phase;
 
     $new_phase = (new Class_Cosmogramme_Integration_Phase(static::MY_ID))
-      ->beSameCronAs($this->_phase);
+      ->beSameCronAs($this->_phase)
+      ->beSameCountAs($this->_phase);
 
     $this->_log->ecrire('<h4>' . $this->_label . '</h4>');
     $this->_init($new_phase);
@@ -97,6 +97,12 @@ abstract class Class_Cosmogramme_Integration_PhaseAbstract {
   }
 
 
+  protected function _incrementCount($name) {
+    $this->_phase->incrementCount($name);
+    return $this;
+  }
+
+
   protected function _printLabel() {
     if (!$this->_phase->isCron() && $this->_wasRunning())
       $this->_getPrinter()->nextPutAll('<h4>' . $this->_label . '</h4>');
diff --git a/library/Class/Cosmogramme/Integration/PhaseBatchs.php b/library/Class/Cosmogramme/Integration/PhaseBatchs.php
index e2a57fb0d3bdf06895554fd23ebad37f54edcc91..887bd37f63b384eac29d3d8c4b7d6c5652c77372 100644
--- a/library/Class/Cosmogramme/Integration/PhaseBatchs.php
+++ b/library/Class/Cosmogramme/Integration/PhaseBatchs.php
@@ -50,7 +50,7 @@ class Class_Cosmogramme_Integration_PhaseBatchs
   protected function _runOne($batch) {
     $this->_log->ecrire('<span class="vert">' . $batch->getLibelle().':');
     $this->_setData('pointeur_reprise', $batch->getId());
-    $batch->run();
+    $batch->runWithLogger($this);
     $this->_log->ecrire(' OK</span><br/>');
     $this->_log
       ->ecrire(sprintf('<span class="vert">Temps de traitement : %s</span><br/>',
@@ -60,6 +60,11 @@ class Class_Cosmogramme_Integration_PhaseBatchs
   }
 
 
+  public function log($message) {
+    $this->_log->ecrire(nl2br($message) . '<br>');
+  }
+
+
   protected function _init($phase) {
     $phase
       ->resetDatas()
diff --git a/library/Class/Cosmogramme/Integration/PhasePseudoRecord.php b/library/Class/Cosmogramme/Integration/PhasePseudoRecord.php
new file mode 100644
index 0000000000000000000000000000000000000000..22d933b085482b2fa0d6b9e45840420b1a32bcfb
--- /dev/null
+++ b/library/Class/Cosmogramme/Integration/PhasePseudoRecord.php
@@ -0,0 +1,157 @@
+<?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
+ */
+
+
+abstract class Class_Cosmogramme_Integration_PhasePseudoRecord
+  extends Class_Cosmogramme_Integration_PhaseAbstract {
+
+  protected $_model_id_field, $_memory_cleaner;
+
+  /** @var Trait_Indexable */
+  protected $_model_name;
+
+
+  protected function _getModelIdField() {
+    if (!$this->_model_id_field)
+      $this->_model_id_field = call_user_func([$this->_model_name, 'getIdField']);
+
+    return $this->_model_id_field;
+  }
+
+
+  protected function _loadPage() {
+    $this->_cleanMemory();
+    $id_field = $this->_getModelIdField();
+    return call_user_func([$this->_model_name, 'findAllBy'],
+                          ['where' => $id_field . ' > ' . $this->_getData('pointeur_reprise'),
+                           'order' => $id_field,
+                           'limit' => 100]);
+  }
+
+
+  protected function _execute() {
+    while ($models = $this->_loadPage()) {
+      if ($this->isTimeOut())
+        return;
+
+      $this->_runPage($models);
+    }
+
+    $this->_summarize();
+  }
+
+
+  protected function _runPage($models) {
+    $this->_log->ecrire($this->_getData('nombre') . '<br>');
+    foreach($models as $model) {
+      if ($this->isTimeOut())
+        return;
+
+      $this->_runOne($model);
+    }
+  }
+
+
+  protected function _runOne($model) {
+    $old_record = $model->getNotice();
+    $model->index();
+    $new_record = $model->getNotice();
+
+    $this->_incrementData('nombre');
+    $this->_setData('pointeur_reprise', $model->getId());
+
+    if (!$old_record && !$new_record)
+      return;
+
+    if (!$old_record) {
+      $this->_incrementCount(Class_Cosmogramme_Integration_Phase::RECORD_INSERT);
+      return;
+    }
+
+    if (!$new_record) {
+      $this->_incrementCount(Class_Cosmogramme_Integration_Phase::RECORD_DELETE);
+      return;
+    }
+
+    $this->_incrementCount(Class_Cosmogramme_Integration_Phase::RECORD_FULLUPDATE);
+  }
+
+
+  protected function _summarize() {
+    if (!$processed = $this->_getData('nombre')) {
+      $this->_log->ecrire($this->_tagGreen($this->_('Aucune notice à traiter')) . '<br>');
+      return;
+    }
+
+    $trace = [$this->_tagGreen($this->_('%s notice(s) traitée(s)', $processed)),
+              $this->_tagGreen($this->_('Temps de traitement ')
+                               . $this->_chrono->endFile()
+                               . ' (' . $this->_chrono->meanOnFile($processed, 'notices') . ')')];
+
+    $this->_log->ecrire(implode('<br>', $trace));
+  }
+
+
+  protected function _tagGreen($content) {
+    return '<span class="vert">' . $content . '</span>';
+  }
+
+
+  protected function _wasRunning() {
+    return $this->_getData('nombre') > 0;
+  }
+
+
+  protected function _init($phase) {
+    $phase
+      ->resetDatas()
+      ->setData('pointeur_reprise', 0)
+      ->setData('nombre', 0);
+
+    $this->_chrono
+      ->startOnFile()
+      ->startOnRecords();
+  }
+
+
+  protected function _cleanMemory() {
+    call_user_func($this->_getMemoryCleaner());
+  }
+
+
+  /** @category testing */
+  public function setMemoryCleaner($cleaner) {
+    $this->_memory_cleaner = $cleaner;
+    return $this;
+  }
+
+
+  protected function _getMemoryCleaner() {
+    if ($this->_memory_cleaner)
+      return $this->_memory_cleaner;
+
+    return function() {
+      Storm_Model_Abstract::unsetLoaders();
+      Storm_Model_Loader::resetCache();
+      gc_collect_cycles();
+    };
+  }
+}
\ No newline at end of file
diff --git a/library/Class/Cosmogramme/Integration/PhasePseudoRecordAlbum.php b/library/Class/Cosmogramme/Integration/PhasePseudoRecordAlbum.php
new file mode 100644
index 0000000000000000000000000000000000000000..4a798cd03e7c0d376b00a98fbb48d2a68a9566a0
--- /dev/null
+++ b/library/Class/Cosmogramme/Integration/PhasePseudoRecordAlbum.php
@@ -0,0 +1,34 @@
+<?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_Integration_PhasePseudoRecordAlbum extends Class_Cosmogramme_Integration_PhasePseudoRecord {
+  const MY_ID = 0.5;
+
+  protected $_label = 'Pseudo-notices : RESSOURCES NUMERIQUES';
+  protected $_model_name = 'Class_Album';
+
+
+  /** @return array **/
+  protected function _previousPhaseIds() {
+    return [0.4];
+  }
+}
diff --git a/library/Class/Cosmogramme/Integration/PhasePseudoRecordCms.php b/library/Class/Cosmogramme/Integration/PhasePseudoRecordCms.php
new file mode 100644
index 0000000000000000000000000000000000000000..7daa79bdac5b3c0f457ad910783a127b4a4bc5e2
--- /dev/null
+++ b/library/Class/Cosmogramme/Integration/PhasePseudoRecordCms.php
@@ -0,0 +1,34 @@
+<?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_Integration_PhasePseudoRecordCms extends Class_Cosmogramme_Integration_PhasePseudoRecord {
+  const MY_ID = 0.2;
+
+  protected $_label = 'Pseudo-notices : CMS';
+  protected $_model_name = 'Class_Article';
+
+
+  /** @return array **/
+  protected function _previousPhaseIds() {
+    return [0.1];
+  }
+}
\ No newline at end of file
diff --git a/library/Class/Cosmogramme/Integration/PhasePseudoRecordRss.php b/library/Class/Cosmogramme/Integration/PhasePseudoRecordRss.php
new file mode 100644
index 0000000000000000000000000000000000000000..773f9fcb5446515cb91d7be8bbd33b9f9f036d2e
--- /dev/null
+++ b/library/Class/Cosmogramme/Integration/PhasePseudoRecordRss.php
@@ -0,0 +1,34 @@
+<?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_Integration_PhasePseudoRecordRss extends Class_Cosmogramme_Integration_PhasePseudoRecord {
+  const MY_ID = 0.3;
+
+  protected $_label = 'Pseudo-notices : FILS RSS';
+  protected $_model_name = 'Class_Rss';
+
+
+  /** @return array **/
+  protected function _previousPhaseIds() {
+    return [0.2];
+  }
+}
diff --git a/library/Class/Cosmogramme/Integration/PhasePseudoRecordSitotheque.php b/library/Class/Cosmogramme/Integration/PhasePseudoRecordSitotheque.php
new file mode 100644
index 0000000000000000000000000000000000000000..7df83130d2e97310186c14cacd2e421698e84955
--- /dev/null
+++ b/library/Class/Cosmogramme/Integration/PhasePseudoRecordSitotheque.php
@@ -0,0 +1,35 @@
+<?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_Integration_PhasePseudoRecordSitotheque
+  extends Class_Cosmogramme_Integration_PhasePseudoRecord {
+	const MY_ID = 0.4;
+
+  protected $_label = 'Pseudo-notices : SITOTHEQUE';
+  protected $_model_name = 'Class_Sitotheque';
+
+
+  /** @return array **/
+  protected function _previousPhaseIds() {
+    return [0.3];
+  }
+}
diff --git a/library/Class/CustomField/ModelConfiguration/Sitotheque.php b/library/Class/CustomField/ModelConfiguration/Sitotheque.php
index 3462bb1560fcca971c3cbde6d7203b7509848988..b9c1e1bcd0244173ec0bf9cb7fb33fe00562dcba 100644
--- a/library/Class/CustomField/ModelConfiguration/Sitotheque.php
+++ b/library/Class/CustomField/ModelConfiguration/Sitotheque.php
@@ -26,7 +26,7 @@ class Class_CustomField_ModelConfiguration_Sitotheque extends Class_CustomField_
         $this->_label = $this->_('Sitotheque');
         $this->_edit_url = [
             'module' => 'admin',
-            'controller' => 'cms',
+            'controller' => 'sito',
             'action' => 'edit'];
     }
 }
diff --git a/library/Class/FTPClient.php b/library/Class/FTPClient.php
new file mode 100644
index 0000000000000000000000000000000000000000..67c88460d96426481462e2811cc05f9e473d6246
--- /dev/null
+++ b/library/Class/FTPClient.php
@@ -0,0 +1,46 @@
+<?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_FTPClient {
+
+  private $_resource;
+
+  public function connect($host, $user, $pass, $port = 21) {
+    $resource = ftp_connect($host, $port);
+    if (!$resource) return false;
+    if (!ftp_login($resource, $user, $pass)) return false;
+    ftp_pasv($resource, true);
+    $this->_resource = $resource;
+    return true;
+  }
+
+
+  public function ls($directory) {
+    return $this->_resource ? ftp_nlist($this->_resource, $directory) : false;
+  }
+
+
+  public function get($remote, $local, $mode=FTP_ASCII) {
+    return $this->_resource ? ftp_get($this->_resource, $local, $remote, $mode) : false;
+  }
+}
+?>
\ No newline at end of file
diff --git a/library/Class/Formulaire.php b/library/Class/Formulaire.php
index e0b5256485f9436d80adf50285ad6fe8f35745b9..e8dcffa769e0d05c6fee1cc78cf25de729184d40 100644
--- a/library/Class/Formulaire.php
+++ b/library/Class/Formulaire.php
@@ -111,6 +111,15 @@ class Class_Formulaire extends Storm_Model_Abstract {
   }
 
 
+  public function dataAsBodyText() {
+    $body = '';
+    foreach ($this->getDatas() as $name => $value)
+      $body .= "$name: $value\n";
+
+    return $body;
+  }
+
+
   public function _get($attribute) {
     try {
       return parent::_get($attribute);
diff --git a/library/Class/Indexation/PseudoNotice.php b/library/Class/Indexation/PseudoNotice.php
index 3ba44558beef25a5b2283b5ee572a96bf82c3278..d53710d75793e55dbd04acf39978131dfcb7fdcf 100644
--- a/library/Class/Indexation/PseudoNotice.php
+++ b/library/Class/Indexation/PseudoNotice.php
@@ -20,6 +20,8 @@
  */
 
 class Class_Indexation_PseudoNotice {
+  use Trait_Translator;
+
   protected $_model;
   protected $_datas = [];
   protected $_table;
@@ -32,14 +34,22 @@ class Class_Indexation_PseudoNotice {
 
 
   public static function index($model) {
-    if (null !== ($notice = $model->getNotice()))
-      $notice->delete();
-    $instance = self::newWith($model->getTypeDocId(), $model->toArray());
+    $instance = self::newWith($model);
     return ($instance->isValid()) ? $instance->save() : false;
   }
 
 
-  public static function newWith($type_doc, $datas) {
+  public static function unindex($model) {
+		if($notice = $model->getNotice())
+			$notice->delete();
+
+		return $model;
+	}
+
+
+  public static function newWith($model) {
+		$type_doc = $model->getTypeDocId();
+
     // types simples
     $mapping = [Class_TypeDoc::ARTICLE => 'Cms',
                 Class_TypeDoc::RSS => 'Rss',
@@ -47,22 +57,21 @@ class Class_Indexation_PseudoNotice {
 
     if (array_key_exists($type_doc, $mapping)) {
       $class_name = 'Class_Indexation_PseudoNotice_' . $mapping[$type_doc];
-      return new $class_name($type_doc, $datas);
+      return new $class_name($model);
     }
 
     // bibnum
     if (99 < $type_doc)
-      return new Class_Indexation_PseudoNotice_Album($type_doc, $datas);
+      return new Class_Indexation_PseudoNotice_Album($model);
     return new Class_Indexation_PseudoNotice_Null();
   }
 
 
-  public function __construct($type_doc, $datas) {
-    $this->_type_doc = (int)$type_doc;
-    $this->_datas = array_change_key_case($datas, CASE_LOWER);
-    $this->_model = call_user_func_array([$this->_model_name, 'find'],
-                                         [$this->_datas[$this->_id]]);
-  }
+	public function __construct($model) {
+		$this->_model = $model;
+		$this->_type_doc = $model->getTypeDocId();
+		$this->_datas = array_change_key_case($model->toArray(), CASE_LOWER);
+	}
 
   public function getId() {
     return $this->_notice->getId();
@@ -82,15 +91,21 @@ class Class_Indexation_PseudoNotice {
 
   public function save() {
     $this->_prepare();
-    $notice = Class_Notice::newInstance(['type_doc' => $this->_type_doc]);
+
+    if (!$notice = $this->_model->getNotice()) {
+      $notice = Class_Notice::newInstance(['type_doc' => $this->_type_doc]);
+    }
+
     if (!$notice->save())
       return false;
     $this->_notice = $notice;
+    $exemplaire = $notice->hasExemplaires()
+      ? $notice->getExemplaires()[0]
+      : Class_Exemplaire::newInstance(['id_bib' => $this->_datas['id_bib'],
+                                       'id_notice' => $this->_notice->getId(),
+                                       'id_origine' => $this->_model->getId(),
+                                       'activite' => $this->_('A consulter sur le portail')]);
 
-    $exemplaire = Class_Exemplaire::newInstance(['id_bib' => $this->_datas['id_bib'],
-                                                 'id_notice' => $this->_notice->getId(),
-                                                 'id_origine' => $this->_model->getId(),
-                                                 'activite' => 'A consulter sur le portail']);
     if (!$exemplaire->save())
       return false;
     $this->_exemplaire = $exemplaire;
diff --git a/library/Class/Moderer.php b/library/Class/Moderer.php
index 1cae5fa44026e63fa189ce248a5d7c1aa2d89014..a64efd0cebde54675cd23648d747279ac1186898 100644
--- a/library/Class/Moderer.php
+++ b/library/Class/Moderer.php
@@ -85,16 +85,16 @@ class Class_Moderer {
     if (!isset($this->_moderation_stats)) {
       $moderations = ['avis_notices' => ['label' => $translate->_('Avis sur les notices'),
                                          'url' => BASE_URL . '/admin/modo/avisnotice',
-                                         'count' => fetchOne('select count(*) from notices_avis where STATUT = 0')],
+                                         'count' => Class_AvisNotice::countBy(['statut' => 0])],
                       'avis_articles' => ['label' => $translate->_('Avis sur les articles'),
                                           'url' => BASE_URL . '/admin/modo/aviscms',
-                                          'count' => fetchOne('select count(*) from cms_avis where STATUT = 0')],
+                                          'count' => Class_Avis::countBy(['statut' => 0])],
                       'tags_notices' => ['label' => $translate->_('Tags sur les notices'),
                                          'url' => BASE_URL . '/admin/modo/tagnotice',
-                                         'count' => fetchOne('select count(*) from codif_tags where a_moderer > \'\'')],
+                                         'count' => count((new Class_Moderer())->getAllTagsAModerer())],
                       'demandes_inscription' => ['label' => $translate->_('Demandes d\'inscription'),
                                                  'url' => BASE_URL . '/admin/modo/membreview',
-                                                 'count' => fetchOne('select count(*) from bib_admin_users_non_valid')],
+                                                 'count' => Class_UsersNonValid::count()],
                       'suggestions_achat' => ['label' => $translate->_('Suggestions d\'achat'),
                                               'url' => BASE_URL . '/admin/modo/suggestion-achat',
                                               'count' => Class_SuggestionAchat::count()],
diff --git a/library/Class/Newsletter.php b/library/Class/Newsletter.php
index 93dc1eb538b891eb150370ef3123fc85809c00c3..a991af74386d4637f4361547be93c8ab592f7a1a 100644
--- a/library/Class/Newsletter.php
+++ b/library/Class/Newsletter.php
@@ -187,26 +187,36 @@ class Class_Newsletter extends Storm_Model_Abstract {
   }
 
 
-  protected function _getBodyText($notices) {
-    $lines = array($this->_htmlToText($this->getContenu()));
+  protected function _getBodyText($records) {
+    $lines = [$this->_htmlToText($this->getContenu())];
 
-    foreach($notices as $notice) {
-      $url_notice = sprintf('http://%s/recherche/viewnotice/id/%d',
-                            $_SERVER['SERVER_NAME'].BASE_URL,
-                            $notice->getId());
-
-      $lines []= '- '.$this->_getTitleForNotice($notice);
-      $lines []= $notice->getResume();
-      $lines []= "Lien: $url_notice";
-      $lines []= "\n";
-
-    }
+    foreach($records as $record)
+      $this->_addBodyTextRecordInto($record, $lines);
 
     $lines[] = $this->_getUnsubscribeText();
+
     return implode("\n", $lines);
   }
 
 
+  protected function _addBodyTextRecordInto($record, &$data) {
+    if (!$record)
+      return;
+
+    $data[] = '- ' . $this->_getTitleForNotice($record);
+    $data[] = $record->getResume();
+    $data[] = 'Lien: ' . $this->_getRecordUrlWithoutRouter($record);
+    $data[] = "\n";
+  }
+
+
+  protected function _getRecordUrlWithoutRouter($record) {
+    return sprintf('http://%s/recherche/viewnotice/id/%d',
+                   $_SERVER['SERVER_NAME'].BASE_URL,
+                   $record->getId());
+  }
+
+
   /**
    * @return string
    */
@@ -216,42 +226,42 @@ class Class_Newsletter extends Storm_Model_Abstract {
 
 
   /**
-   * @param array $notices
+   * /!\ maybe in cli context : cannot rely on view helpers
+   * @see scripts/sendNewsletter.php
+   *
+   * @param array $records
    * @return string
    */
-  protected function _getBodyHTML($notices) {
-    $view = new ZendAfi_Controller_Action_Helper_View();
-
+  protected function _getBodyHTML($records) {
     $html = $this->getContenu();
 
-    foreach($notices as $notice) {
-      $title = $this->_getTitleForNotice($notice);
-      $vignette = $notice->fetchUrlVignette();
-      $resume = $notice->getResume();
-
-
-			$anchor_notice = $view
-				->tagAnchor($view->absoluteUrl(
-															 [ 'controller' => 'recherche',
-																'action' => 'viewnotice',
-																'id' => $notice->getId()],
-                                null, true
-                                       ),
-										$view->tagImg($vignette,
-																	['style' => 'float:left;width:50px;vertical-align:top;padding:5px',
-																	 'alt' => 'vignette']
-										) . $title);
-
-      $html.=
-        '<div style="padding:5px">' .
-        $anchor_notice .
-        '<div>' . $resume . '</div>' .
-        '<div style="clear:both"></div>'.
-        '</div>';
-    }
-    $html.=$this->_getUnsubscribeHTML();
+    foreach($records as $record)
+      $html .= $this->_getBodyHTMLRecord($record);
+
+    $html .= $this->_getUnsubscribeHTML();
+
     return $html;
+  }
+
+
+  protected function _getBodyHTMLRecord($record) {
+    $title = $this->_getTitleForNotice($record);
+
+    $anchor = '<a href="' . $this->_getRecordUrlWithoutRouter($record) . '">'
+      . $this->_getRecordThumbWithoutRouter($record) . $title . '</a>';
+
+    return '<div style="padding:5px">' .
+      $anchor .
+      '<div>' . $record->getResume() . '</div>' .
+      '<div style="clear:both"></div>'.
+      '</div>';
+  }
+
 
+  protected function _getRecordThumbWithoutRouter($record) {
+    return $record->hasVignette() ?
+      '<img src="' . $record->getUrlVignette() . '" style="float:left;width:50px;vertical-align:top;padding:5px" alt="" />'
+      : '';
   }
 
 
diff --git a/library/Class/Notice.php b/library/Class/Notice.php
index 117ff12aa19fc51aff5205927c380e3c10cf8492..a5e435b7284be5f5895e871b469b49d2773587c2 100644
--- a/library/Class/Notice.php
+++ b/library/Class/Notice.php
@@ -179,6 +179,7 @@ class Class_Notice extends Storm_Model_Abstract {
 
 
   public function __construct() {
+    parent::__construct();
     $this->_notice_unimarc = new Class_NoticeUnimarc();
   }
 
@@ -333,38 +334,41 @@ class Class_Notice extends Storm_Model_Abstract {
   }
 
 
-  public function getAvisBibliothecaires()  {
+  public function getAvisBibliothecaires() {
     return Class_AvisNotice::filterByBibliothecaire($this->getAvis());
   }
 
+
   public function numberOfAvisBibliothecaire() {
     return Class_AvisNotice::countBy(['abon_ou_bib' => 1, 'clef_oeuvre' => $this->getClefOeuvre()]);
   }
 
-  public function getAvisAbonnes()
-  {
+
+  public function getAvisAbonnes() {
     return Class_AvisNotice::filterByAbonne($this->getAvis());
   }
 
+
   public function numberOfAvisAbonne() {
     return Class_AvisNotice::countBy(['abon_ou_bib' => 0, 'clef_oeuvre' => $this->getClefOeuvre()]);
   }
 
-  public function getNoteMoyenneAvisBibliothecaires()
-  {
+
+  public function getNoteMoyenneAvisBibliothecaires() {
     return Class_AvisNotice::getNoteAverage($this->getAvisBibliothecaires());
   }
 
-  public function getNoteMoyenneAvisAbonnes()
-  {
+
+  public function getNoteMoyenneAvisAbonnes() {
     return Class_AvisNotice::getNoteAverage($this->getAvisAbonnes());
   }
 
-  public function setAvis($list_avis)
-  {
+
+  public function setAvis($list_avis) {
     $this->_avis = $list_avis;
   }
 
+
   public function setUnimarc($unimarc) {
     $this->getNoticeUnimarc()->setNotice($unimarc);
     return parent::setUnimarc($unimarc);
@@ -453,18 +457,22 @@ class Class_Notice extends Storm_Model_Abstract {
     return ($this->getTypeDoc() == Class_TypeDoc::ARTICLE);
   }
 
+
   public function isRSS() {
     return ($this->getTypeDoc() == Class_TypeDoc::RSS);
   }
 
+
   public function isAudioRecord() {
     return ($this->getTypeDoc() == Class_TypeDoc::AUDIO_RECORD);
   }
 
+
   public function isSite() {
     return ($this->getTypeDoc() == Class_TypeDoc::SITE);
   }
 
+
   public function getArticleCms() {
     if (!$this->isArticleCms())
       return null;
@@ -473,6 +481,7 @@ class Class_Notice extends Storm_Model_Abstract {
     return Class_Article::find($id);
   }
 
+
   public function getSite() {
     if (!$this->isSite())
       return null;
@@ -587,7 +596,8 @@ class Class_Notice extends Storm_Model_Abstract {
   public function getArticlesPeriodique() {
     // lire dans la base
     $datas = Class_Notice_SerialArticles::findAllBy(['clef_chapeau' => $this->getClefChapeau(),
-                                                     'clef_numero' => $this->getTomeAlpha()]);
+                                                     'clef_numero' => $this->getTomeAlpha(),
+                                                     'order' => 'id_article asc']);
 
     $articles = [];
 
@@ -1134,14 +1144,28 @@ class Class_Notice extends Storm_Model_Abstract {
     $auteur = new stdClass();
     $auteur->nom = $auteur->prenom = $auteur->fonction = $auteur->fonction_pergame = '';
     foreach ($data as $item) {
-      if ($item['code'] == 'a')
+      if ($item['code'] == 'a') {
         $auteur->nom = trim($item['valeur']);
-      elseif ($item['code'] == 'b')
+        continue;
+      }
+      if ($item['code'] == 'b') {
         $auteur->prenom = trim($item['valeur']);
-      elseif ($item['code'] == '4')
+        continue;
+      }
+
+      if ($item['code'] == '4') {
         $auteur->fonction = trim($item['valeur']);
-      elseif ($item['code'] == 'g')
+        continue;
+      }
+
+      if  ($item['code'] == 'g' && !$auteur->fonction_pergame) {
         $auteur->fonction_pergame = trim($item['valeur']);
+        continue;
+      }
+      if ($item['code'] == '6') {
+        $auteur->fonction_pergame = trim($item['valeur']);
+      }
+
     }
     return $auteur;
   }
diff --git a/library/Class/Reservation.php b/library/Class/Reservation.php
index b666326a398687034d6286409f1509c4a0e95c2c..be5ae832a4508e9a774b0cde28bf014afcc7891d 100644
--- a/library/Class/Reservation.php
+++ b/library/Class/Reservation.php
@@ -50,6 +50,7 @@ class Class_Reservation extends Storm_Model_Abstract {
 
 
   public function __construct() {
+    parent::__construct();
     $this->setDateResa(date('Y-m-d H:i:s', $this->getCurrentTime()));
   }
 
diff --git a/library/Class/Rss.php b/library/Class/Rss.php
index 769f500d172c66d63ed0e8d378c3970e994501e0..87c3275bf365087e2fe82908785d21d23c3d1ff7 100644
--- a/library/Class/Rss.php
+++ b/library/Class/Rss.php
@@ -108,15 +108,16 @@ class RssLoader extends Storm_Model_Loader {
 class Class_Rss extends Storm_Model_Abstract {
   use Trait_Indexable, Trait_Translator;
 
-  protected $_loader_class = 'RssLoader';
-  protected $_table_name = 'rss_flux';
-  protected $_table_primary = 'ID_RSS';
-  protected $_belongs_to = array('categorie' => array('model' => 'Class_RssCategorie',
-                                                      'referenced_in' => 'id_cat'),
-                                  'notice' => array('model' => 'Class_Notice',
-                                                    'referenced_in' => 'ID_NOTICE'));
+  protected
+    $_loader_class = 'RssLoader',
+    $_table_name = 'rss_flux',
+    $_table_primary = 'ID_RSS',
+    $_belongs_to = ['categorie' => ['model' => 'Class_RssCategorie',
+                                    'referenced_in' => 'id_cat']],
 
-  protected $_feed_items;
+    $_default_attribute_values = [ 'id_notice' => null],
+
+    $_feed_items;
 
   private $_dataBaseError = "Problème d'accès à la base de données";
   private $_rssCategorie ;
@@ -124,11 +125,16 @@ class Class_Rss extends Storm_Model_Abstract {
   public $arbre_array;
   private $sql;
 
-  public static function getLoader() {
-    return self::getLoaderFor(__CLASS__);
-  }
+
+  public function describeAssociationsOn($associations) {
+		$associations
+			->add(new Storm_Model_Association_HasOne('notice', ['model' => 'Class_Notice',
+																													'referenced_in' => 'id_notice']));
+	}
+
 
   public function __construct() {
+    parent::__construct();
     $this->_rssCategorie = new bibRssCategorie();
     $this->_rssFlux = new bibRssFlux();
     $this->sql = Zend_Registry::get('sql');
@@ -437,6 +443,16 @@ class Class_Rss extends Storm_Model_Abstract {
   }
 
 
+  public function getTypeDocId() {
+    return Class_TypeDoc::RSS;
+  }
+
+
+  public function getDomaines() {
+    return [];
+  }
+
+
   ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
   //                    ARBRE pour lister les cat+ subcat sur lindex admin
   ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/library/Class/Sitotheque.php b/library/Class/Sitotheque.php
index 85e5b1787c779d230c9b62b3806ce90edad663fa..357b97b6943636b10742e89c02ef23ef69e67b88 100644
--- a/library/Class/Sitotheque.php
+++ b/library/Class/Sitotheque.php
@@ -110,12 +110,11 @@ class Class_Sitotheque extends Storm_Model_Abstract {
   protected $_table_primary = 'ID_SITO';
   protected $_belongs_to = ['categorie' => ['model' => 'Class_SitothequeCategorie',
                                             'referenced_in' => 'id_cat'],
-                            'notice' => ['model' => 'Class_Notice',
-                                         'referenced_in' => 'id_notice'],
                             'bib' => ['through' => 'categorie'],
                             'zone' => ['through' => 'bib']];
 
   protected $_default_attribute_values = ['id_cat' => 0,
+                                          'id_notice' => null,
                                           'titre' => '',
                                           'url' => '',
                                           'description' => '',
@@ -123,8 +122,11 @@ class Class_Sitotheque extends Storm_Model_Abstract {
                                           'domaine_ids' => ''];
 
 
-  private $_dataBaseError = "Problème d'accès à la base de données";
-
+  public function describeAssociationsOn($associations) {
+		$associations
+			->add(new Storm_Model_Association_HasOne('notice', ['model' => 'Class_Notice',
+																													'referenced_in' => 'id_notice']));
+	}
 
   public function beforeSave() {
     $this->setDateMaj($this->getCurrentDateTime());
@@ -169,6 +171,11 @@ class Class_Sitotheque extends Storm_Model_Abstract {
   }
 
 
+  public function getLibelle() {
+    return $this->getTitre();
+  }
+
+
   public function getCategorieLibelle() {
     if ($categorie = parent::_get('categorie'))
       return $categorie->getLibelle();
@@ -193,20 +200,12 @@ class Class_Sitotheque extends Storm_Model_Abstract {
 
 
   public function validate()  {
-    $this->check($this->getTitre(), $this->_("Vous devez compléter le champ 'Titre'"));
-
-    $this->check(mb_strlen($this->getTitre(),'UTF-8') <= 255,
-                 $this->_("Le champ 'Titre' doit être inférieur à 255 caractères"));
-
-    $this->check($this->getUrl(),
-                 $this->_("Vous devez compléter le champ 'Url'"));
-
-    $this->check(mb_strlen($this->getUrl(),'UTF-8') <= 250,
-                 $this->_("Le champ 'Url' doit être inférieur à 250 caractères"));
 
-    //  $this->check(strlen_utf8($this->getDescription()) <= 250,
-    //             $this->_("Le champ 'Commentaire' doit être inférieur à 250 caractères"));
+    $this->checkAttribute('titre', $this->getTitre() && mb_strlen($this->getTitre(),'UTF-8') <= 255,
+                 $this->_("Le champ 'Titre' doit être renseigné et inférieur à 255 caractères"));
 
+    $this->checkAttribute('url',$this->getUrl() && mb_strlen($this->getUrl(),'UTF-8') <= 250,
+                 $this->_("Vous devez compléter le champ 'Url' et il doit être inférieur à 250 caractères"));
     $url_validator = new ZendAfi_Validate_Url();
     if (!$url_validator->isValid($this->getUrl())) {
       $messages = $url_validator->getMessages();
diff --git a/library/Class/WebService/BibNumerique/Dilicom.php b/library/Class/WebService/BibNumerique/Dilicom.php
new file mode 100644
index 0000000000000000000000000000000000000000..c7aa172e27127aac7845eca715f42e6143ad7b53
--- /dev/null
+++ b/library/Class/WebService/BibNumerique/Dilicom.php
@@ -0,0 +1,48 @@
+<?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_WebService_BibNumerique_Dilicom {
+  use Trait_Translator;
+
+  public function importOffersFile($xml, $report_closure) {
+    $books = Class_WebService_BibNumerique_Dilicom_PNBOffersFile::booksFromXML($xml);
+
+    if (!$books) {
+      $report_closure(0, $this->_('Impossible de traiter le fichier'));
+      return;
+    }
+
+    $errors = [];
+    $import_count = 0;
+
+    foreach($books as $book) {
+      $album = $book->import();
+      if (!$album->hasErrors())
+        $import_count++;
+
+      $errors = $errors + $album->getErrors();
+    }
+
+    $report_closure($import_count, $errors);
+  }
+}
+?>
\ No newline at end of file
diff --git a/library/Class/WebService/SIGB/Koha/PatronInfoReader.php b/library/Class/WebService/SIGB/Koha/PatronInfoReader.php
index 6e2f1ff11f4f0417035138420b436344de67278c..5bd30a214123c16f0e1d9b9aca706d1dffcb4d10 100644
--- a/library/Class/WebService/SIGB/Koha/PatronInfoReader.php
+++ b/library/Class/WebService/SIGB/Koha/PatronInfoReader.php
@@ -77,7 +77,8 @@ class Class_WebService_SIGB_Koha_PatronInfoReader extends Class_WebService_SIGB_
 
 
   public function updateBibliothequeWith($data) {
-    $site = $this->findSite($data);
+    if(!$site = $this->findSite($data))
+      return;
 
     $this->_current_operation->getExemplaire()->setBibliotheque($site->getLibelle());
 
diff --git a/library/Class/Zone.php b/library/Class/Zone.php
index 8a431099a38a7a7a5984582b687191631d6d5563..2ac4b597ef166e06c9158ae0eace9f782e803a02 100644
--- a/library/Class/Zone.php
+++ b/library/Class/Zone.php
@@ -60,6 +60,7 @@ class Class_Zone extends Storm_Model_Abstract {
 
 
   public function __construct() {
+    parent::__construct();
     $this->sql = Zend_Registry::get('sql');
   }
 
diff --git a/library/Trait/Indexable.php b/library/Trait/Indexable.php
index 9c82a8644040bfd8a03829e4e48e0be6c19aa9af..79898db10e4bb8bfb31d3ad6a2cbcfde9c870e9c 100644
--- a/library/Trait/Indexable.php
+++ b/library/Trait/Indexable.php
@@ -22,10 +22,12 @@
 
 trait Trait_Indexable {
   public function index() {
-    if (!$this->hasToBeIndexed())
+    if (!$this->hasToBeIndexed()) {
+      Class_Indexation_PseudoNotice::unindex($this);
       return $this;
+    }
     Class_Indexation_PseudoNotice::index($this);
-    $this->indexIntoDomain();
+    return $this->indexIntoDomain();
   }
 
 
diff --git a/library/ZendAfi/Controller/Action/Helper/AlbumListViewMode.php b/library/ZendAfi/Controller/Action/Helper/AlbumListViewMode.php
index b05fa25ec89902255ac6923b1110421f7addcc55..1dc401f2746fe251faaa939c3fcd68c9f2714a97 100644
--- a/library/ZendAfi/Controller/Action/Helper/AlbumListViewMode.php
+++ b/library/ZendAfi/Controller/Action/Helper/AlbumListViewMode.php
@@ -48,7 +48,7 @@ class ZendAfi_Controller_Action_Helper_AlbumListViewMode extends ZendAfi_Control
   public function getCategories() {
     $categories = [];
 
-    if ($this->getModel() != Class_AlbumCategorie::defaultCategory())
+    if (!$this->getModel() || ($this->getModel()->getId() !== Class_AlbumCategorie::defaultCategory()->getId()))
       $categories = Class_AlbumCategorie::findAllBy(['parent_id' => $this->getModelId(),
                                                      'order' => 'libelle']);
 
diff --git a/library/ZendAfi/Controller/Plugin/CustomFields.php b/library/ZendAfi/Controller/Plugin/CustomFields.php
index 804210438e4519634e7e58b41d1be67ae14241b5..5441918225aa497638ddb62acaf30e6d286c6463 100644
--- a/library/ZendAfi/Controller/Plugin/CustomFields.php
+++ b/library/ZendAfi/Controller/Plugin/CustomFields.php
@@ -16,23 +16,24 @@
  *
  * 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_Controller_Plugin_CustomFields extends Zend_Controller_Plugin_Abstract {
   use Trait_Translator;
 
-  
+
   public function preDispatch(Zend_Controller_Request_Abstract $request) {
     Class_CustomField_Model::registerAll([
             new Class_CustomField_ModelConfiguration_Article(),
             new Class_CustomField_ModelConfiguration_Formation(),
             new Class_CustomField_ModelConfiguration_UserGroup(),
+            new Class_CustomField_ModelConfiguration_Sitotheque(),
             new Class_CustomField_ModelConfiguration('SessionFormation',
                                                      $this->_('Session'),
                                                      ['module' => 'admin',
-                                                      'controller' => 'formation', 
+                                                      'controller' => 'formation',
                                                       'action' => 'session_edit'])
                                            ]);
   }
diff --git a/library/ZendAfi/Form.php b/library/ZendAfi/Form.php
index f7027df4a6df2a8d99a15ee80ae945b320fc39d5..d09a50fbec25ccea383387bccccce762e794174b 100644
--- a/library/ZendAfi/Form.php
+++ b/library/ZendAfi/Form.php
@@ -106,12 +106,15 @@ class ZendAfi_Form extends Zend_Form {
    * @return boolean
    */
   public function isValid($array_or_model) {
+
     if (is_array($array_or_model))
       return parent::isValid($array_or_model);
 
     $valid = parent::isValid($array_or_model->toArray()) & $array_or_model->isValid();
     $this->addModelErrors($array_or_model);
 
+
+
     $this->_errorsExist = !$valid;
     return $valid;
   }
@@ -119,7 +122,6 @@ class ZendAfi_Form extends Zend_Form {
   public function isValidModelAndArray($model, $array) {
     $valid = parent::isValid($array) && $model->isValid();
     $this->addModelErrors($model);
-
     $this->_errorsExist = !$valid;
     return $valid;
   }
diff --git a/library/ZendAfi/Form/Admin/CustomFields/ModelValues.php b/library/ZendAfi/Form/Admin/CustomFields/ModelValues.php
index 215ea9f80e33191a10a94939f621f6ab6dfc46a9..fae57e785afcb07c93f76ced82beadc46ef40c23 100644
--- a/library/ZendAfi/Form/Admin/CustomFields/ModelValues.php
+++ b/library/ZendAfi/Form/Admin/CustomFields/ModelValues.php
@@ -117,11 +117,11 @@ class ZendAfi_Form_Admin_CustomFields_ModelValues_Field_Strategy_ckeditor extend
 class ZendAfi_Form_Admin_CustomFields_ModelValues_Field_Strategy_select extends ZendAfi_Form_Admin_CustomFields_ModelValues_Field_Strategy {
   protected function getOptions() {
     $options = $this->_field->getOptionsListAsArray();
-    array_unshift($options, '');
     $multioptions=[];
     foreach($options as $option) {
       $multioptions[$option]=$option;
     }
+    $multioptions['']= _('*Vide*');
     return ['multioptions' => $multioptions];
   }
 }
diff --git a/library/ZendAfi/Form/Admin/News.php b/library/ZendAfi/Form/Admin/News.php
index 3874c5ee8828104f2670158591fe596860e112ff..4ebe5318d05398b699057faec87e0b775c5471de 100644
--- a/library/ZendAfi/Form/Admin/News.php
+++ b/library/ZendAfi/Form/Admin/News.php
@@ -28,7 +28,8 @@ class ZendAfi_Form_Admin_News extends ZendAfi_Form {
       ->addWorkflow(isset($datas['status']) ? $datas['status'] : '',
                     isset($datas['id_cat']) ? $datas['id_cat'] : '')
       ->addPublication($datas['debut'], $datas['fin'])
-      ->addAgenda($datas['all_day'], $datas['events_debut'], $datas['events_fin']);
+      ->addAgenda($datas['all_day'], $datas['events_debut'], $datas['events_fin'])
+      ->addEmail($datas['contenu'], $datas['destination_email']);
 
     return $form;
   }
@@ -96,7 +97,6 @@ class ZendAfi_Form_Admin_News extends ZendAfi_Form {
                    ['label' => $this->_('Autoriser les commentaires d\'internautes (Mode blog) ?')])
       ->addElement('checkbox', 'indexation',
                    ['label' => $this->_('Indexer l\'article dans le catalogue ?')])
-
       ->addDisplayGroup([
                          'titre',
                          'cacher_titre',
@@ -147,6 +147,19 @@ class ZendAfi_Form_Admin_News extends ZendAfi_Form {
   }
 
 
+  protected function addEmail($contenu, $email) {
+    if (Class_AdminVar::isCmsFormulairesEnabled() &&
+        preg_match('/<form/', $contenu)) {
+      $this->addElement('email', 'destination_email',
+                        ['label' => $this->_('Email du modérateur'),
+                         'value' => $email,
+                         'order' => 4]);
+      $this->updateDisplayGroup('publication', ['destination_email']);
+    }
+    return $this;
+  }
+
+
   protected function addWorkflow($status, $id_cat) {
     if(!Class_AdminVar::isWorkFlowEnabled())
       return $this;
@@ -201,7 +214,6 @@ class ZendAfi_Form_Admin_News extends ZendAfi_Form {
     $current_elements = array_map(function($element) {return $element->getName();},
                                   $display_group->getElements());
     $current_elements = array_merge($current_elements, $elements);
-
     return $this->addDisplayGroup($current_elements, $display_group_name, ['legend' => $display_group->getLegend(),
                                                                            'order' => $display_group->getOrder()]);
   }
diff --git a/library/ZendAfi/Form/Admin/Sitotheque.php b/library/ZendAfi/Form/Admin/Sitotheque.php
new file mode 100644
index 0000000000000000000000000000000000000000..3eee25227012fd8b11f0e7deff92096ed8e79885
--- /dev/null
+++ b/library/ZendAfi/Form/Admin/Sitotheque.php
@@ -0,0 +1,77 @@
+<?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 ZendAfi_Form_Admin_Sitotheque extends ZendAfi_Form {
+  public function init() {
+    parent::init();
+
+    $this
+      ->setAttrib('id', 'sitothequeform')
+
+      ->addElement('comboCategories', 'id_cat',
+                   ['label' => $this->_('Catégorie'),
+                    'category_type' => 'Sitotheque'])
+
+      ->addElement('text',
+                   'titre',
+                   ['label' => $this->_('Titre'), 'size' => 50])
+
+      ->addElement('text',
+                   'url',
+                   ['label' => $this->_('Url'), 'size' => 50])
+
+      ->addElement('textarea',
+                   'description',
+                   ['label' => $this->_('Commentaire'),
+                    'cols' => 50,
+                    'rows' => 5
+                   ])
+
+      ->addElement('textarea',
+                   'tags',
+                   ['label' => $this->_('Tags'),
+                    'cols' => 50,
+                    'rows' => 5
+                   ])
+
+
+      ->addDisplayGroup(['id_cat', 'titre', 'url', 'description'],
+                        'sitotheque',
+                        ['legend' => $this->_('Sitothèque')])
+
+      ->addDisplayGroup(['tags'], 'tagsgroup',
+                        ['legend' => $this->_('Entrez la liste des mots-clefs  et expressions qui caractérisent ce site séparés  avec des ;')])
+
+      ->addDomainIndexation();
+
+
+  }
+
+  protected function addDomainIndexation() {
+    if (defined('DEVELOPMENT'))
+      return $this->addElement('domainSelect', 'domaine_ids')
+                  ->addDisplayGroup(['domaine_ids'], 'domains_set', ['legend' => $this->_('Indexation')]);
+
+    return $this;
+  }
+}
+?>
diff --git a/library/ZendAfi/Form/Element/ComboCategories.php b/library/ZendAfi/Form/Element/ComboCategories.php
index a6616d49992962af901f8b12f70f317acd762028..408b7a59da73167c764fe8d2d2bedc579f3b8835 100644
--- a/library/ZendAfi/Form/Element/ComboCategories.php
+++ b/library/ZendAfi/Form/Element/ComboCategories.php
@@ -21,6 +21,8 @@
 
 
 class ZendAfi_Form_Element_ComboCategories extends Zend_Form_Element {
+  protected $category_type = 'Article';
+
   public function __construct($spec, $options = null) {
     parent::__construct($spec, $options);
     $decorators = $this->_decorators;
@@ -33,9 +35,10 @@ class ZendAfi_Form_Element_ComboCategories extends Zend_Form_Element {
     $this->removeDecorator('ViewHelper');
   }
 
-
   public function getCategory() {
-    return Class_ArticleCategorie::find($this->getValue());
+    $class_name='Class_'.$this->category_type.'Categorie';
+    return $class_name::find($this->getValue());
   }
 }
+
 ?>
\ No newline at end of file
diff --git a/library/ZendAfi/View/Helper/Avis.php b/library/ZendAfi/View/Helper/Avis.php
index 654ad437334c983bc22312237ec73a3aacc8cc57..73f097c7bb1ad7ee259b1952b5bfcb388e780322 100644
--- a/library/ZendAfi/View/Helper/Avis.php
+++ b/library/ZendAfi/View/Helper/Avis.php
@@ -89,8 +89,14 @@ class ZendAfi_View_Helper_Avis extends ZendAfi_View_Helper_BaseHelper {
   protected function avisNotice($avis, $vignette_link_to_avis) {
     $url_vignette = URL_ADMIN_IMG . 'supports/vignette_vide.gif';
     $title = $this->_('Oeuvre non trouvée');
+    $type_doc_id = 0;
+    $type_doc_label = $this->_('Inconnu');
+
     if (null !== $notice = $avis->getFirstNotice()) {
       $title = $notice->getTitrePrincipal();
+      $type_doc_id = $notice->getTypeDoc();
+      $type_doc = Class_TypeDoc::find($type_doc_id);
+      $type_doc_label = $type_doc ? $type_doc->getLabel() : $type_doc_label;
 
       if (strlen($auteur_principal = $notice->getAuteurPrincipal()) > 0)
         $title .= ' (' . $auteur_principal . ')';
@@ -104,7 +110,11 @@ class ZendAfi_View_Helper_Avis extends ZendAfi_View_Helper_BaseHelper {
       _tag('div',
            $this->_tag('h2', $title)
            . $this->_tag('div',
-                         $this->_tag('a', $this->view->tagImg($url_vignette, ['alt' => 'vignette de \''.$title.'\'']),
+                         $this->view->iconeSupport($type_doc_id)
+                         . $this->_tag('a',
+                                       $this->view->tagImg($url_vignette,
+                                                           ['alt' => $this->_('vignette de \'%s\'', $title),
+                                                            'title' => $type_doc_label . ' : ' . $title]),
                                      ['href' => $this->_getUrlClickVignette($avis)])
                          . $this->_tag('a', $this->_('Voir la notice'),
                                        ['href' => $this->_getUrlNotice($avis)]),
diff --git a/library/ZendAfi/View/Helper/ModelActionsTable/AlbumCategories.php b/library/ZendAfi/View/Helper/ModelActionsTable/AlbumCategories.php
index 79191779010448d153b896d9bd30cdce9d059c07..dbe9e24c65b617b0a198f6c6cc7d2d05254cf0e6 100644
--- a/library/ZendAfi/View/Helper/ModelActionsTable/AlbumCategories.php
+++ b/library/ZendAfi/View/Helper/ModelActionsTable/AlbumCategories.php
@@ -28,10 +28,11 @@ class ZendAfi_View_Helper_ModelActionsTable_AlbumCategories extends ZendAfi_View
 
 
   public function getActions() {
-    if(!$this->_model || $this->_model == Class_AlbumCategorie::defaultCategory())
+    if (!$this->_model) {
       return $this->setActions([ ['url' => $this->_getUrlForAction('add_categorie'),
                                   'icon' => 'ico/add_cat.gif',
                                   'label' => 'Ajouter une sous-catégorie']]);
+    }
 
     $actions = Class_AdminVar::isBibNumEnabled()
       ? [['url' => $this->_getUrlForAction('add_categorie_to'),
diff --git a/library/ZendAfi/View/Helper/RenderForm.php b/library/ZendAfi/View/Helper/RenderForm.php
index e0e333e060ccd2ed3d440e6e3d1a9933adca0265..d7847952eec5473f009cc6522732b1503dac1c4f 100644
--- a/library/ZendAfi/View/Helper/RenderForm.php
+++ b/library/ZendAfi/View/Helper/RenderForm.php
@@ -80,7 +80,6 @@ class ZendAfi_View_Helper_RenderForm extends ZendAfi_View_Helper_BaseHelper {
   protected function _decoratorsForTableRendering($element) {
     $newDecorators = array();
     $decorators = $element->getDecorators();
-
     foreach ($decorators as $name => $decorator) {
       $name = explode('_', $name);
       $name = end($name);
diff --git a/library/ZendAfi/View/Helper/TagOneDTouch.php b/library/ZendAfi/View/Helper/TagOneDTouch.php
index 6e0fcdde074b9594d5dd100edb54a05be8b23c58..195ee426e26e22d8d3960baa660e60b5e36e7858 100644
--- a/library/ZendAfi/View/Helper/TagOneDTouch.php
+++ b/library/ZendAfi/View/Helper/TagOneDTouch.php
@@ -24,7 +24,7 @@ class ZendAfi_View_Helper_TagOneDTouch extends ZendAfi_View_Helper_BaseHelper {
   public function tagOneDTouch($album) {
     return $this->_tag('a',
                        $this->_('Écouter l\'album sur 1DTouch'),
-                       [ 'href' => Class_OneDTouchLink::urlFor($album) ]);
+                       ['href' => Class_OneDTouchLink::urlFor($album)]);
   }
 }
 ?>
\ No newline at end of file
diff --git a/library/startup.php b/library/startup.php
index 219997368e777ef1026c31c9b65a7987ce4afdfa..3aca1b80135aef395b38f70a46ff06ee022b5753 100644
--- a/library/startup.php
+++ b/library/startup.php
@@ -21,336 +21,336 @@
 
 
 if (!function_exists('xdebug_break')) {
-	function xdebug_break(){};
+  function xdebug_break(){};
 }
 
 
 function setupOpac() {
-	require_once('Class/Url.php');
+  require_once('Class/Url.php');
 
-	defineConstant('ROOT_URL', Class_Url::rootUrl());
-	defineConstant('BASE_URL',  Class_Url::baseUrl());
+  defineConstant('ROOT_URL', Class_Url::rootUrl());
+  defineConstant('BASE_URL',  Class_Url::baseUrl());
 
-	require_once "Zend/Loader.php";
-	Zend_Loader::registerAutoload();
+  require_once "Zend/Loader.php";
+  Zend_Loader::registerAutoload();
 
-	setupConstants();
-	require_once('requires.php');
+  setupConstants();
+  require_once('requires.php');
 
-	$cfg = loadConfig();
-	setupSession($cfg);
-	setupDatabase($cfg);
-	Class_AdminVar::findAll();
-	setupLanguage();
-	setupDevOptions($cfg);
-	setupControllerActionHelper();
-	setupHTTPClient($cfg);
-	setupCache($cfg);
-	setupMail($cfg);
+  $cfg = loadConfig();
+  setupSession($cfg);
+  setupDatabase($cfg);
+  Class_AdminVar::findAll();
+  setupLanguage();
+  setupDevOptions($cfg);
+  setupControllerActionHelper();
+  setupHTTPClient($cfg);
+  setupCache($cfg);
+  setupMail($cfg);
 
-	$front_controller = setupFrontController($cfg);
-	setupPagination();
-	setupRestful();
+  $front_controller = setupFrontController($cfg);
+  setupPagination();
+  setupRestful();
 
-	return $front_controller;
+  return $front_controller;
 }
 
 
 function defineConstant($name, $value) {
-	if (!defined($name))
-		define($name, $value);
+  if (!defined($name))
+    define($name, $value);
 }
 
 
 function setupConstants() {
-	defineConstant('BOKEH_MAJOR_VERSION','7.3');
-	defineConstant('BOKEH_RELEASE_NUMBER', BOKEH_MAJOR_VERSION . '.8');
+  defineConstant('BOKEH_MAJOR_VERSION','7.3');
+  defineConstant('BOKEH_RELEASE_NUMBER', BOKEH_MAJOR_VERSION . '.11');
 
-	defineConstant('ROOT_PATH',  realpath(dirname(__FILE__).'/..').'/');
+  defineConstant('ROOT_PATH',  realpath(dirname(__FILE__).'/..').'/');
 
-	defineConstant('ZEND_FRAMEWORK_PATH',  ROOT_PATH . 'library/storm/zf/library/');
+  defineConstant('ZEND_FRAMEWORK_PATH',  ROOT_PATH . 'library/storm/zf/library/');
 
-	defineConstant('MODULEDIRECTORY', ROOT_PATH . 'application/modules');
-	defineConstant('LANG_DIR', ROOT_PATH . 'library/translation/');
+  defineConstant('MODULEDIRECTORY', ROOT_PATH . 'application/modules');
+  defineConstant('LANG_DIR', ROOT_PATH . 'library/translation/');
 
-	defineConstant('USERFILESPATH', './userfiles');
-	defineConstant('USERFILESURL', BASE_URL . '/userfiles/');
-	defineConstant('PATH_TEMP',  ROOT_PATH . 'temp/');
+  defineConstant('USERFILESPATH', './userfiles');
+  defineConstant('USERFILESURL', BASE_URL . '/userfiles/');
+  defineConstant('PATH_TEMP',  ROOT_PATH . 'temp/');
 
-	defineConstant('CKBASEPATH',  'ckeditor/');
-	defineConstant('CKBASEURL',  BASE_URL . '/ckeditor/');
+  defineConstant('CKBASEPATH',  'ckeditor/');
+  defineConstant('CKBASEURL',  BASE_URL . '/ckeditor/');
 
-	defineConstant('AMBERURL',  BASE_URL . '/amber/');
+  defineConstant('AMBERURL',  BASE_URL . '/amber/');
 
-	defineConstant('URL_ADMIN_CSS', BASE_URL . '/public/admin/css/');
-	defineConstant('URL_ADMIN_IMG', BASE_URL . '/public/admin/images/');
-	defineConstant('URL_ADMIN_JS', BASE_URL . '/public/admin/js/');
+  defineConstant('URL_ADMIN_CSS', BASE_URL . '/public/admin/css/');
+  defineConstant('URL_ADMIN_IMG', BASE_URL . '/public/admin/images/');
+  defineConstant('URL_ADMIN_JS', BASE_URL . '/public/admin/js/');
 
-	defineConstant('JQUERY', URL_ADMIN_JS . 'jquery-1.8.3.js');
-	defineConstant('JQUERYMOBILE_VERSION',  '1.4.5');
-	defineConstant('JQUERYUI', URL_ADMIN_JS . 'jquery_ui/jquery-ui-1.10.3.full.js');
-	defineConstant("URL_JS", BASE_URL . "/public/opac/js/");
-	defineConstant("URL_EPUB", BASE_URL . "/temp/epub/");
-	defineConstant("URL_SHARED_IMG", BASE_URL . "/public/opac/images/");
+  defineConstant('JQUERY', URL_ADMIN_JS . 'jquery-1.8.3.js');
+  defineConstant('JQUERYMOBILE_VERSION',  '1.4.5');
+  defineConstant('JQUERYUI', URL_ADMIN_JS . 'jquery_ui/jquery-ui-1.10.3.full.js');
+  defineConstant("URL_JS", BASE_URL . "/public/opac/js/");
+  defineConstant("URL_EPUB", BASE_URL . "/temp/epub/");
+  defineConstant("URL_SHARED_IMG", BASE_URL . "/public/opac/images/");
 
-	// il y a des autre define URL dans ZendAfi_Controller_Plugin_DefineURLs
-	// par exemple URL_IMG, URL_CSS, URL_HTML et URL_JS va chercher dans 'URL_SKIN . 'nom de le module' . /html' etc.
-	defineConstant('BR','<br />');
-	defineConstant('NL',"\n");
-	defineConstant('CRLF', chr(13).chr(10));
+  // il y a des autre define URL dans ZendAfi_Controller_Plugin_DefineURLs
+  // par exemple URL_IMG, URL_CSS, URL_HTML et URL_JS va chercher dans 'URL_SKIN . 'nom de le module' . /html' etc.
+  defineConstant('BR','<br />');
+  defineConstant('NL',"\n");
+  defineConstant('CRLF', chr(13).chr(10));
 
-	defineConstant('URL_FLASH', BASE_URL . '/public/opac/flash/');
-	defineConstant('PATH_FLASH', ROOT_PATH . 'public/opac/flash/');
-	defineConstant('URL_JAVA', BASE_URL . '/public/opac/java/');
-	defineConstant('PATH_JAVA', ROOT_PATH . 'public/opac/java/');
-	defineConstant('PATH_ADMIN_SUPPORTS', ROOT_PATH . 'public/admin/images/supports/');
+  defineConstant('URL_FLASH', BASE_URL . '/public/opac/flash/');
+  defineConstant('PATH_FLASH', ROOT_PATH . 'public/opac/flash/');
+  defineConstant('URL_JAVA', BASE_URL . '/public/opac/java/');
+  defineConstant('PATH_JAVA', ROOT_PATH . 'public/opac/java/');
+  defineConstant('PATH_ADMIN_SUPPORTS', ROOT_PATH . 'public/admin/images/supports/');
 
-	defineConstant('PATH_FONTS', ROOT_PATH . 'public/opac/fonts/');
-	defineConstant('URL_CAPTCHA', BASE_URL . '/public/captcha/');
-	defineConstant('PATH_CAPTCHA', ROOT_PATH . 'public/captcha/');
-	defineConstant('CACHE_LIFETIME', 3600);
-	defineConstant('MEMCACHED_ENABLE', false);
-	defineConstant('MEMCACHED_HOST', 'localhost');
-	defineConstant('MEMCACHED_PORT', '11211');
+  defineConstant('PATH_FONTS', ROOT_PATH . 'public/opac/fonts/');
+  defineConstant('URL_CAPTCHA', BASE_URL . '/public/captcha/');
+  defineConstant('PATH_CAPTCHA', ROOT_PATH . 'public/captcha/');
+  defineConstant('CACHE_LIFETIME', 3600);
+  defineConstant('MEMCACHED_ENABLE', false);
+  defineConstant('MEMCACHED_HOST', 'localhost');
+  defineConstant('MEMCACHED_PORT', '11211');
 
-	defineConstant('IMAGE_MAGICK_PATH', 'convert');
+  defineConstant('IMAGE_MAGICK_PATH', 'convert');
 
-	defineConstant('PATCH_PATH', ROOT_PATH . '/cosmogramme/sql/patch/');
+  defineConstant('PATCH_PATH', ROOT_PATH . '/cosmogramme/sql/patch/');
 }
 
 
 function loadConfig($config_init_file_path = './config.ini') {
-	// load configuration (local ou production)
-	if(array_isset('REMOTE_ADDR', $_SERVER) and $_SERVER['REMOTE_ADDR'] == '127.0.0.1')
-		$serveur='local';
-	else
-		$serveur='production';
-	$cfg = new Zend_Config_Ini($config_init_file_path, $serveur);
-	Zend_Registry::set('cfg', $cfg);
+  // load configuration (local ou production)
+  if(array_isset('REMOTE_ADDR', $_SERVER) and $_SERVER['REMOTE_ADDR'] == '127.0.0.1')
+    $serveur='local';
+  else
+    $serveur='production';
+  $cfg = new Zend_Config_Ini($config_init_file_path, $serveur);
+  Zend_Registry::set('cfg', $cfg);
 
 
-	setlocale(LC_TIME, 'fr_FR.UTF-8');
-	date_default_timezone_set($cfg->timeZone);
+  setlocale(LC_TIME, 'fr_FR.UTF-8');
+  date_default_timezone_set($cfg->timeZone);
 
-	return $cfg;
+  return $cfg;
 }
 
 
 function setupCache($cfg) {
-	if (Class_Users::isCurrentUserCanAccesBackend())
-		return;
-
-	$frontendOptions = ['lifetime' => CACHE_LIFETIME, // durée du cache: 1h
-											'automatic_serialization' => false,
-											'caching' => true];
-
-	$use_memcached = (MEMCACHED_ENABLE === true);
-	$backendOptions = $use_memcached
-		? ['servers' => [ ['host' => MEMCACHED_HOST,
-											 'port' => MEMCACHED_PORT] ]]
-		: ['cache_dir' => PATH_TEMP ];
-
-	// getting a Zend_Cache_Core object
-	$cache = Zend_Cache::factory('Core',
-															 $use_memcached ? 'Memcached' : 'File',
-															 $frontendOptions,
-															 $backendOptions);
-	//	$cache->clean(Zend_Cache::CLEANING_MODE_ALL);
-
-	Storm_Cache::setDefaultZendCache($cache);
-	Storm_Cache::setSeed($cfg->sgbd->config->dbname);
+  if (Class_Users::isCurrentUserCanAccesBackend())
+    return;
+
+  $frontendOptions = ['lifetime' => CACHE_LIFETIME, // durée du cache: 1h
+                      'automatic_serialization' => false,
+                      'caching' => true];
+
+  $use_memcached = (MEMCACHED_ENABLE === true);
+  $backendOptions = $use_memcached
+    ? ['servers' => [ ['host' => MEMCACHED_HOST,
+                       'port' => MEMCACHED_PORT] ]]
+    : ['cache_dir' => PATH_TEMP ];
+
+  // getting a Zend_Cache_Core object
+  $cache = Zend_Cache::factory('Core',
+                               $use_memcached ? 'Memcached' : 'File',
+                               $frontendOptions,
+                               $backendOptions);
+  //  $cache->clean(Zend_Cache::CLEANING_MODE_ALL);
+
+  Storm_Cache::setDefaultZendCache($cache);
+  Storm_Cache::setSeed($cfg->sgbd->config->dbname);
 }
 
 
 function setupSession($cfg) {
-	// Start Session
-	$session = new Zend_Session_Namespace(md5(BASE_URL));
-	if (!isset($session->initialized))
-		{
-			Zend_Session::regenerateId();
-			$session->initialized = true;
-		}
-	if (!isset($session->baseUrl)) $session->baseUrl = BASE_URL;
-	Zend_Registry::set('session', $session);
+  // Start Session
+  $session = new Zend_Session_Namespace(md5(BASE_URL));
+  if (!isset($session->initialized))
+    {
+      Zend_Session::regenerateId();
+      $session->initialized = true;
+    }
+  if (!isset($session->baseUrl)) $session->baseUrl = BASE_URL;
+  Zend_Registry::set('session', $session);
 }
 
 
 function setupLanguage() {
-	Zend_Locale::setDefault(Class_AdminVar::getDefaultLanguage());
-	Zend_Registry::set('locale', new Zend_Locale());
-
-	$translate = new ZendAfi_Translate('gettext', LANG_DIR.'fr.mo', 'fr');
-	foreach (Class_AdminVar::getLanguesWithoutDefault() as $language) {
-		$filename = LANG_DIR.$language.'.mo';
-		if (file_exists($filename))
-			$translate->addTranslation($filename, $language);
-	}
-	Zend_Registry::set('translate', $translate);
-
-	Zend_Validate_Abstract::setDefaultTranslator($translate);
+  Zend_Locale::setDefault(Class_AdminVar::getDefaultLanguage());
+  Zend_Registry::set('locale', new Zend_Locale());
+
+  $translate = new ZendAfi_Translate('gettext', LANG_DIR.'fr.mo', 'fr');
+  foreach (Class_AdminVar::getLanguesWithoutDefault() as $language) {
+    $filename = LANG_DIR.$language.'.mo';
+    if (file_exists($filename))
+      $translate->addTranslation($filename, $language);
+  }
+  Zend_Registry::set('translate', $translate);
+
+  Zend_Validate_Abstract::setDefaultTranslator($translate);
 }
 
 
 function setupDatabase($cfg) {
-	// setup database
-	$sql = Zend_Db::factory($cfg->sgbd->adapter, $cfg->sgbd->config->toArray());
-	$sql->usePrepared(false);
-	Zend_Db_Table::setDefaultAdapter($sql);
+  // setup database
+  $sql = Zend_Db::factory($cfg->sgbd->adapter, $cfg->sgbd->config->toArray());
+  $sql->usePrepared(false);
+  Zend_Db_Table::setDefaultAdapter($sql);
 
-	$afi_sql = new Class_Systeme_Sql();
-	Zend_Registry::set('sql', $afi_sql);
+  $afi_sql = new Class_Systeme_Sql();
+  Zend_Registry::set('sql', $afi_sql);
 
-	Zend_Db_Table::getDefaultAdapter()->query('set names "UTF8"');
+  Zend_Db_Table::getDefaultAdapter()->query('set names "UTF8"');
 }
 
 
 function setupDevOptions($cfg) {
-	//permet d'activer les fonctions en développement
-	if (null !== $experimental_dev = $cfg->get('experimental_dev'))
-		defineConstant('DEVELOPMENT', $experimental_dev);
+  //permet d'activer les fonctions en développement
+  if (null !== $experimental_dev = $cfg->get('experimental_dev'))
+    defineConstant('DEVELOPMENT', $experimental_dev);
 }
 
 
 function setupControllerActionHelper() {
-	Zend_Controller_Action_HelperBroker::resetHelpers();
-	Zend_Controller_Action_HelperBroker::addHelper(new ZendAfi_Controller_Action_Helper_ViewRenderer());
-	Zend_Controller_Action_HelperBroker::addPrefix('ZendAfi_Controller_Action_Helper');
+  Zend_Controller_Action_HelperBroker::resetHelpers();
+  Zend_Controller_Action_HelperBroker::addHelper(new ZendAfi_Controller_Action_Helper_ViewRenderer());
+  Zend_Controller_Action_HelperBroker::addPrefix('ZendAfi_Controller_Action_Helper');
 }
 
 
 function setupHTTPClient($cfg) {
-	//set up HTTP Client to use proxy settings
-	$httpClient = new Zend_Http_Client();
-	if ( (isset ($cfg->proxy->host) ) || ($cfg->proxy->host != '') ){
-		$proxyConfig = array(
-												 'adapter'    => 'Zend_Http_Client_Adapter_Proxy',
-												 'proxy_host' => $cfg->proxy->host,
-												 'proxy_port' => $cfg->proxy->port,
-												 'proxy_user' => $cfg->proxy->user,
-												 'proxy_pass' => $cfg->proxy->pass
-		);
-		Zend_Registry::set('http_proxy',$proxyConfig);
-
-		$proxy_adapter = new Zend_Http_Client_Adapter_Proxy();
-		$proxy_adapter->setConfig($proxyConfig);
-		$httpClient->setAdapter($proxy_adapter);
-	}else{
-		$proxyConfig = null;
-	}
-
-	$httpClient->setConfig(array('timeout' => 2));
-	Zend_Registry::set('httpClient',$httpClient);
+  //set up HTTP Client to use proxy settings
+  $httpClient = new Zend_Http_Client();
+  if ( (isset ($cfg->proxy->host) ) || ($cfg->proxy->host != '') ){
+    $proxyConfig = array(
+                         'adapter'    => 'Zend_Http_Client_Adapter_Proxy',
+                         'proxy_host' => $cfg->proxy->host,
+                         'proxy_port' => $cfg->proxy->port,
+                         'proxy_user' => $cfg->proxy->user,
+                         'proxy_pass' => $cfg->proxy->pass
+    );
+    Zend_Registry::set('http_proxy',$proxyConfig);
+
+    $proxy_adapter = new Zend_Http_Client_Adapter_Proxy();
+    $proxy_adapter->setConfig($proxyConfig);
+    $httpClient->setAdapter($proxy_adapter);
+  }else{
+    $proxyConfig = null;
+  }
+
+  $httpClient->setConfig(array('timeout' => 2));
+  Zend_Registry::set('httpClient',$httpClient);
 }
 
 
 function setupMail($cfg) {
-	if (isset($cfg->mail->transport->smtp)) {
-		ZendAfi_Mail::setDefaultTransport(new Zend_Mail_Transport_Smtp($cfg->mail->transport->smtp->host,
-																																	 $cfg->mail->transport->smtp->toArray()));
-		return;
-	}
-
-	if (defined('SMTP_HOST'))
-		ZendAfi_Mail::setDefaultTransport(new Zend_Mail_Transport_Smtp(SMTP_HOST));
+  if (isset($cfg->mail->transport->smtp)) {
+    ZendAfi_Mail::setDefaultTransport(new Zend_Mail_Transport_Smtp($cfg->mail->transport->smtp->host,
+                                                                   $cfg->mail->transport->smtp->toArray()));
+    return;
+  }
+
+  if (defined('SMTP_HOST'))
+    ZendAfi_Mail::setDefaultTransport(new Zend_Mail_Transport_Smtp(SMTP_HOST));
 }
 
 
 function newFrontController() {
-	return Zend_Controller_Front::getInstance()
-		->setDispatcher(new ZendAfi_Controller_Dispatcher_Standard())
-		->addModuleDirectory(MODULEDIRECTORY)
-		->setDefaultModule('opac')
-		->registerPlugin(new ZendAfi_Controller_Plugin_SetupDomain())
-		->registerPlugin(new ZendAfi_Controller_Plugin_AdminAuth())
-		->registerPlugin(new ZendAfi_Controller_Plugin_SetupLocale())
-		->registerPlugin(new ZendAfi_Controller_Plugin_DefineURLs())
-		->registerPlugin(new ZendAfi_Controller_Plugin_InitModule())
-		->registerPlugin(new ZendAfi_Controller_Plugin_SelectionBib())
-		->registerPlugin(new ZendAfi_Controller_Plugin_System())
-		->registerPlugin(new ZendAfi_Controller_Plugin_Popup())
-		->registerPlugin(new ZendAfi_Controller_Plugin_TogetherJS())
-		->registerPlugin(new ZendAfi_Controller_Plugin_CustomFields())
-		->registerPlugin(new ZendAfi_Controller_Plugin_Lectura())
-		->registerPlugin(new ZendAfi_Controller_Plugin_InspectorGadget())
-		->setParam('useDefaultControllerAlways', false);
+  return Zend_Controller_Front::getInstance()
+    ->setDispatcher(new ZendAfi_Controller_Dispatcher_Standard())
+    ->addModuleDirectory(MODULEDIRECTORY)
+    ->setDefaultModule('opac')
+    ->registerPlugin(new ZendAfi_Controller_Plugin_SetupDomain())
+    ->registerPlugin(new ZendAfi_Controller_Plugin_AdminAuth())
+    ->registerPlugin(new ZendAfi_Controller_Plugin_SetupLocale())
+    ->registerPlugin(new ZendAfi_Controller_Plugin_DefineURLs())
+    ->registerPlugin(new ZendAfi_Controller_Plugin_InitModule())
+    ->registerPlugin(new ZendAfi_Controller_Plugin_SelectionBib())
+    ->registerPlugin(new ZendAfi_Controller_Plugin_System())
+    ->registerPlugin(new ZendAfi_Controller_Plugin_Popup())
+    ->registerPlugin(new ZendAfi_Controller_Plugin_TogetherJS())
+    ->registerPlugin(new ZendAfi_Controller_Plugin_CustomFields())
+    ->registerPlugin(new ZendAfi_Controller_Plugin_Lectura())
+    ->registerPlugin(new ZendAfi_Controller_Plugin_InspectorGadget())
+    ->setParam('useDefaultControllerAlways', false);
 }
 
 
 function setupFrontController($cfg) {
-	$front_controller = newFrontController()
-		->addControllerDirectory(ROOT_PATH.'afi/application/modules/opacpriv/controllers','opacpriv')
-		->setBaseURL(BASE_URL);
-
-	setupRoutes($front_controller, $cfg);
-
-	if (!Class_Users::isCurrentUserSuperAdmin())
-		return $front_controller;
-
-	$front_controller->registerPlugin(new ZendAfi_Controller_Plugin_XHProfile());
-	return $front_controller;
-	set_include_path(get_include_path() . PATH_SEPARATOR . ROOT_PATH.'library/ZFDebug/library');
-	return $front_controller
-		->registerPlugin(new ZFDebug_Controller_Plugin_Debug(['plugins' =>
-																													[
-																													 'Variables',
-																													 'Constants',
-																													 'Html',
-																													 'Database',
-																													 'Memory',
-																													 'Time',
-																													 'Exception']
-																													]
-																												 ));
+  $front_controller = newFrontController()
+    ->addControllerDirectory(ROOT_PATH.'afi/application/modules/opacpriv/controllers','opacpriv')
+    ->setBaseURL(BASE_URL);
+
+  setupRoutes($front_controller, $cfg);
+
+  if (!Class_Users::isCurrentUserSuperAdmin())
+    return $front_controller;
+
+  $front_controller->registerPlugin(new ZendAfi_Controller_Plugin_XHProfile());
+  return $front_controller;
+  set_include_path(get_include_path() . PATH_SEPARATOR . ROOT_PATH.'library/ZFDebug/library');
+  return $front_controller
+    ->registerPlugin(new ZFDebug_Controller_Plugin_Debug(['plugins' =>
+                                                          [
+                                                           'Variables',
+                                                           'Constants',
+                                                           'Html',
+                                                           'Database',
+                                                           'Memory',
+                                                           'Time',
+                                                           'Exception']
+                                                          ]
+                                                         ));
 }
 
 
 function setupRoutes($front_controller, $cfg) {
-	if ('1' == $cfg->get('enable_rewriting')) {
-		$front_controller
-			->setBaseUrl('')
-			->setRouter(new ZendAfi_Controller_Router_RewriteWithoutBaseUrl());
-
-		Class_Url::doNotAddBaseUrl();
-	}
-
-	$front_controller
-		->getRouter()
-		->addRoute('embed',
-							 new Zend_Controller_Router_Route(
-																								'embed/:controller/:action/*',
-																								['module' => 'telephone',
-																								 'controller' => 'index',
-																								 'action' => 'index']))
-		->addRoute('flash',
-							 new Zend_Controller_Router_Route('flash/:action/*',
-																								['module' => 'opacpriv',
-																								 'controller' => 'flash',
-																								 'action' => 'index']))
-		->addRoute('sitemap',
-							 new Zend_Controller_Router_Route_Static('sitemap.xml',
-																											 ['module' => 'opac',
-																												'controller' => 'index',
-																												'action' => 'sitemap']));
-	return $front_controller;
+  if ('1' == $cfg->get('enable_rewriting')) {
+    $front_controller
+      ->setBaseUrl('')
+      ->setRouter(new ZendAfi_Controller_Router_RewriteWithoutBaseUrl());
+
+    Class_Url::doNotAddBaseUrl();
+  }
+
+  $front_controller
+    ->getRouter()
+    ->addRoute('embed',
+               new Zend_Controller_Router_Route(
+                                                'embed/:controller/:action/*',
+                                                ['module' => 'telephone',
+                                                 'controller' => 'index',
+                                                 'action' => 'index']))
+    ->addRoute('flash',
+               new Zend_Controller_Router_Route('flash/:action/*',
+                                                ['module' => 'opacpriv',
+                                                 'controller' => 'flash',
+                                                 'action' => 'index']))
+    ->addRoute('sitemap',
+               new Zend_Controller_Router_Route_Static('sitemap.xml',
+                                                       ['module' => 'opac',
+                                                        'controller' => 'index',
+                                                        'action' => 'sitemap']));
+  return $front_controller;
 }
 
 
 function setupPagination() {
-	Zend_Paginator::setDefaultScrollingStyle('Sliding');
-	Zend_View_Helper_PaginationControl::setDefaultViewPartial('pagination.phtml');
+  Zend_Paginator::setDefaultScrollingStyle('Sliding');
+  Zend_View_Helper_PaginationControl::setDefaultViewPartial('pagination.phtml');
 }
 
 
 function setupRestful() {
-	if (!(new Class_Testing_FileSystem())->file_exists(ROOT_PATH . 'restful.php'))
-		return;
+  if (!(new Class_Testing_FileSystem())->file_exists(ROOT_PATH . 'restful.php'))
+    return;
 
-	set_include_path(ROOT_PATH . '/restful/library' . PATH_SEPARATOR .
-									 get_include_path());
+  set_include_path(ROOT_PATH . '/restful/library' . PATH_SEPARATOR .
+                   get_include_path());
 
-	$config = new Zend_Config(include ROOT_PATH . 'restful.php');
-	Restful_Model_Configuration::setConfig($config);
-	Restful_Bootstrap::asPlugin(Zend_Controller_Front::getInstance(),
-															'rest',
-															Zend_Controller_Action_HelperBroker::getExistingHelper('ViewRenderer'));
+  $config = new Zend_Config(include ROOT_PATH . 'restful.php');
+  Restful_Model_Configuration::setConfig($config);
+  Restful_Bootstrap::asPlugin(Zend_Controller_Front::getInstance(),
+                              'rest',
+                              Zend_Controller_Action_HelperBroker::getExistingHelper('ViewRenderer'));
 }
diff --git a/library/storm b/library/storm
index e8b3587ac7dd17e67ce4d968cc7d3e1c1b9a1d5d..6a2a4b4d149401ecef5f8a51963cecfc6cc91fa8 160000
--- a/library/storm
+++ b/library/storm
@@ -1 +1 @@
-Subproject commit e8b3587ac7dd17e67ce4d968cc7d3e1c1b9a1d5d
+Subproject commit 6a2a4b4d149401ecef5f8a51963cecfc6cc91fa8
diff --git a/public/opac/css/global.css b/public/opac/css/global.css
index b5c0290b04ecf9e15057f4dd18379232a6ba29fa..071df1ab31c9baf11c8e1ed1aae2c3376d7365f4 100644
--- a/public/opac/css/global.css
+++ b/public/opac/css/global.css
@@ -235,11 +235,23 @@ table.calendar_main {margin-left: auto; margin-right: auto}
     background-color: #eee;
 }
 
-.vignette_notice img {
+.vignette_notice a img {
     width: 100px;
     margin: 2px;
 }
 
+
+.critique .vignette_notice {
+    position: relative;
+}
+
+
+.critique .vignette_notice .icone_support {
+    position: absolute;
+    right: 0;
+    margin: 2px;
+}
+
 .vignette_notice a + a {
     display:block;
 }
diff --git a/scripts/sendNewsletter.php b/scripts/sendNewsletter.php
index 7356481814db85af13d2022fffe397b2cea1e8ed..070baeb2dd7aa82092cc78abd02cac1956c12dde 100644
--- a/scripts/sendNewsletter.php
+++ b/scripts/sendNewsletter.php
@@ -18,7 +18,8 @@
  * along with BOKEH; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
  */
-define("BASE_URL", $argv[3]);
+
+define('BASE_URL', $argv[3]);
 $_SERVER['SERVER_NAME'] = $argv[2];
 $_SERVER['HTTP_HOST'] = $argv[1];
 
diff --git a/tests/application/modules/admin/controllers/AlbumControllerTest.php b/tests/application/modules/admin/controllers/AlbumControllerTest.php
index e6affec4a020ba1dee8e6872d51f01f653ff9661..f83269f2b6562a2fd2399ca61bc2189e340ffb61 100644
--- a/tests/application/modules/admin/controllers/AlbumControllerTest.php
+++ b/tests/application/modules/admin/controllers/AlbumControllerTest.php
@@ -1665,9 +1665,11 @@ class Admin_AlbumControllerPostEditAlbumMesBDTest extends Admin_AlbumControllerT
     $this->bd->setNotice(
       $this->fixture('Class_Notice',
                      ['id' => 72,
+                      'titre_principal' => 'Mes Romans',
                       'exemplaires' => [
                         $this->fixture('Class_Exemplaire',
-                                       ['id' => 2])]]))
+                                       ['id' => 2])]
+                     ]))
       ->save();
 
     $this->cache_mock = $this->mock()
@@ -1765,14 +1767,14 @@ class Admin_AlbumControllerPostEditAlbumMesBDTest extends Admin_AlbumControllerT
 
 
   /** @test */
-  public function oldExemplaireShouldHaveBeenDeleted() {
-    $this->assertNull(Class_Exemplaire::find(2));
+  public function oldExemplaireShouldHaveBeenUpdated() {
+    $this->assertNotNull(Class_Exemplaire::find(2));
   }
 
 
   /** @test */
-  public function oldNoticeShouldHaveBeenDeleted() {
-    $this->assertNull(Class_Notice::find(72));
+  public function oldNoticeShouldHaveBeenUpdated() {
+    $this->assertEquals('Mes BD', Class_Notice::find(72)->getTitrePrincipal());
   }
 
 
diff --git a/tests/application/modules/admin/controllers/CmsControllerTest.php b/tests/application/modules/admin/controllers/CmsControllerTest.php
index 30811d21ce7d3cb6c74f4282a22a6f2f3a1fbe1c..ced6bb48b6c7d187449acb3efcd47c09c7250301 100644
--- a/tests/application/modules/admin/controllers/CmsControllerTest.php
+++ b/tests/application/modules/admin/controllers/CmsControllerTest.php
@@ -709,6 +709,11 @@ class CmsControllerArticleConcertEditActionTest extends CmsControllerWithPermiss
   public function checkBoxShouldCheckedDomaineArtEtHistoire() {
     $this->assertXPath("//input[@name='domaine_ids'][@value='11-12']");
   }
+
+  /** @test */
+  public function emailShouldNotBePresent() {
+    $this->assertNotXPath("//input[@name='destination_email']");
+  }
 }
 
 
@@ -1858,6 +1863,96 @@ class CmsControllerNewsAddActionWithSimpleWorkflowTest extends CmsControllerWith
 }
 
 
+class CmsControllerArticleEditActionWithFormTest extends CmsControllerWithPermissionTestCase {
+  public function setUp() {
+    parent::setUp();
+
+    $this->articleWithForm = $this->fixture('Class_Article',
+                                    ['id' => 5,
+                                     'categorie' => $this->cat_evenements,
+                                     'titre' => 'Mon article avec formulaire',
+                                     'auteur' => $this->fixture('Class_Users',
+                                                                ['id' => 2,
+                                                                 'Nom' => 'Tom et Jerry',
+                                                                 'password'=>'toto',
+                                                                 'login'=>'tom']),
+                                     'description' => 'Mon article avec formulaire',
+                                     'contenu' => '<form action="/formulaire/add/id_article/5" method="POST" name="mon form">',
+                                     'debut' => '2011-03-20',
+                                     'fin' => '2011-03-28',
+                                     'events_debut' =>  '2011-03-27 21:00',
+                                     'events_fin' => '2011-03-28 22:30',
+                                     'cacher_titre' => 1,
+                                     'langue' => 'fr',
+                                     'tags' => 'concert;jazz',
+                                     'avis' => true,
+                                     'indexation' => false,
+                                     'date_creation' => '2010-12-25 10:23:23',
+                                     'date_maj' => '2010-12-26  11:12:34',
+                                     'domaine_ids' => [11,12],
+                                     'avis_users' => []]);
+
+
+    Class_AdminVar::getLoader()->newInstanceWithId('CMS_FORMULAIRES')->setValeur('1');
+    $this->dispatch('/admin/cms/edit/id/5');
+  }
+
+
+  /** @test */
+  public function emailShouldBePresentOnFourthPosition() {
+    $this->assertXPath("//table//tr[4]//input[@name='destination_email'][@type='email']",
+                       $this->_response->getBody());
+  }
+}
+
+
+
+
+class CmsControllerArticleEditActionWithFormAndEmailFilledTest extends CmsControllerWithPermissionTestCase {
+  public function setUp() {
+    parent::setUp();
+
+    $this->articleWithForm = $this->fixture('Class_Article',
+                                    ['id' => 5,
+                                     'categorie' => $this->cat_evenements,
+                                     'titre' => 'Mon article avec formulaire',
+                                     'auteur' => $this->fixture('Class_Users',
+                                                                ['id' => 2,
+                                                                 'Nom' => 'Tom et Jerry',
+                                                                 'password'=>'toto',
+                                                                 'login'=>'tom']),
+                                     'description' => 'Mon article avec formulaire',
+                                     'contenu' => '<form action="/formulaire/add/id_article/5" method="POST" name="mon form">',
+                                     'debut' => '2011-03-20',
+                                     'fin' => '2011-03-28',
+                                     'events_debut' =>  '2011-03-27 21:00',
+                                     'events_fin' => '2011-03-28 22:30',
+                                     'cacher_titre' => 1,
+                                     'langue' => 'fr',
+                                     'tags' => 'concert;jazz',
+                                     'avis' => true,
+                                     'indexation' => false,
+                                     'date_creation' => '2010-12-25 10:23:23',
+                                     'date_maj' => '2010-12-26  11:12:34',
+                                     'domaine_ids' => [11,12],
+                                     'avis_users' => [],
+                                     'destination_email' => 'william@dlaton.com']);
+
+
+    Class_AdminVar::getLoader()->newInstanceWithId('CMS_FORMULAIRES')->setValeur('1');
+    $this->dispatch('/admin/cms/edit/id/5');
+  }
+
+
+  /** @test */
+  public function emailFieldShouldBeFilled() {
+    Class_Article::find(5)->setDestinationEmail('william@dalton.com')->save();
+    $this->dispatch('/admin/cms/edit/id/5');
+    $this->assertXpath('//input[@name="destination_email"][@value="william@dalton.com"]');
+  }
+}
+
+
 
 class CmsControllerArticleConcertEditActionWithoutWorkflowTest extends CmsControllerWithPermissionTestCase {
   public function setUp() {
diff --git a/tests/application/modules/admin/controllers/CustomFieldsControllerTest.php b/tests/application/modules/admin/controllers/CustomFieldsControllerTest.php
index 3e29f2be181439df86d23a4648b4777b4e752f03..fac69bfe980c204a0ac672c7a03b7dee3d931825 100644
--- a/tests/application/modules/admin/controllers/CustomFieldsControllerTest.php
+++ b/tests/application/modules/admin/controllers/CustomFieldsControllerTest.php
@@ -493,7 +493,7 @@ class CustomFieldsControllerValuesForUserGroupTeachersTest extends CustomFieldCo
 
    /** @test */
    public function statusSelectOptionsShouldBePresent() {
-     $this->assertXPath('//form//fieldset//select//option[@value=""][not(text())]');
+     $this->assertXPath('//form//fieldset//select//option[@value=""]');
      $this->assertXPathContentContains('//form//fieldset//select//option[@value="enabled"]', 'enabled');
      $this->assertXPathContentContains('//form//fieldset//select//option[@value="disabled"]', 'disabled');
    }
diff --git a/tests/application/modules/admin/controllers/ModoControllerTest.php b/tests/application/modules/admin/controllers/ModoControllerTest.php
index 7953e6dc0b8d0721e9cc2842d378d5db85283b3b..4b042f15cc6a998d7c0ba9db5f9709e7f6499cfb 100644
--- a/tests/application/modules/admin/controllers/ModoControllerTest.php
+++ b/tests/application/modules/admin/controllers/ModoControllerTest.php
@@ -22,8 +22,59 @@ require_once realpath(dirname(__FILE__)) . '/AdminAbstractControllerTestCase.php
 
 
 class ModoControllerIndexActionTest extends Admin_AbstractControllerTestCase {
+  protected $_storm_default_to_volatile = true;
+
   public function setUp() {
     parent::setUp();
+
+    Class_AdminVar::set('AVIS_MIN_SAISIE', 2);
+    Class_AdminVar::set('AVIS_MAX_SAISIE', 2000);
+
+    $this->fixture('Class_Notice', ['id' => 1002,
+                                    'titre_principal' => 'Para Ana']);
+
+    $this->fixture('Class_Notice', ['id' => 1003,
+                                    'titre_principal' => 'Maison de la Nuit (La)']);
+
+    $this->fixture('Class_CodifTags', ['id' => 1,
+                                       'a_moderer' => '1002',
+                                       'libelle' => 'litteratures espagnol',
+                                       'code_alpha' => 'LITTERATURES ESPAGNOL']);
+
+    $this->fixture('Class_CodifTags', ['id' => 2,
+                                       'a_moderer' => '1002;1003',
+                                       'libelle' => 'muerto',
+                                       'code_alpha' => 'LITTERATURES ESPAGNOL']);
+
+    $this->fixture('Class_Avis', ['id' => 1,
+                                  'id_notice' => 1002,
+                                  'statut' => 0]);
+
+    $this->fixture('Class_AvisNotice', ['id' => 1,
+                                        'id_notice' => 1002,
+                                        'entete' => 'Mon avis',
+                                        'avis' => 'Ce livre est vraiment bien !',
+                                        'statut' => 0]);
+
+    $this->fixture('Class_SuggestionAchat', ['id' => 92,
+                                            'titre' => 'Kikolol',
+                                            'auteur' => 'Moi',
+                                            'isbn' => '',
+                                            'description_url' => 'http://livre.com/1',
+                                            'type_doc_id' => 1]);
+
+    $this->fixture('Class_UsersNonValid', ['id_user' => 8,
+                                          'id' => 8,
+                                          'login' => 'moo',
+                                          'password' => 'moo',
+                                          'mail' => 'moo@moo.com',]);
+
+    $this->fixture('Class_UsersNonValid', ['id_user' => 9,
+                                          'id' => 9,
+                                          'login' => 'Simon',
+                                          'password' => 'LeHerisson',
+                                          'mail' => 'simon-le-herisson@gmail.com',]);
+
     $this->dispatch('admin/modo/', true);
   }
 
@@ -40,28 +91,64 @@ class ModoControllerIndexActionTest extends Admin_AbstractControllerTestCase {
   }
 
 
+  /** @test */
+  public function linkToModerateMembershipShouldBePresent() {
+    $this->assertXPath('//a[contains(@href, "/modo/membreview")]');
+  }
+
+
+  /** @test */
+  public function numberOfModerateMembreshipShouldBeTwo() {
+    $this->assertXPathContentContains('//span[@class="menu_info"][preceding::a[contains(@href, "/modo/membreview")]]', '2');
+  }
+
+
   /** @test */
   public function linkToModerateAvisCmsShouldBePresent() {
     $this->assertXPath('//a[contains(@href, "/modo/aviscms")]');
   }
 
 
+  /** @test */
+  public function numberOfAvisCmsShouldBeOne() {
+    $this->assertXPathContentContains('//span[@class="menu_info"][preceding::a[contains(@href, "/modo/aviscms")]]', '1');
+  }
+
+
   /** @test */
   public function linkToModerateAvisNoticeShouldBePresent() {
     $this->assertXPath('//a[contains(@href, "/modo/avisnotice")]');
   }
 
 
+  /** @test */
+  public function numberOfAvisNoticeShouldBeOne() {
+    $this->assertXPathContentContains('//span[@class="menu_info"][preceding::a[contains(@href, "/modo/avisnotice")]]', '1');
+  }
+
+
   /** @test */
   public function linkToModerateTagsShouldBePresent() {
     $this->assertXPath('//a[contains(@href, "/modo/tagnotice")]');
   }
 
 
+  /** @test */
+  public function numberOfModerateTagsShouldBeThree() {
+    $this->assertXPathContentContains('//span[@class="menu_info"][preceding::a[contains(@href, "/modo/tagnotice")]]', '3');
+  }
+
+
   /** @test */
   public function linkToModerateSuggestionAchatShouldBePresent() {
     $this->assertXPath('//a[contains(@href, "/admin/modo/suggestion-achat")]');
   }
+
+
+  /** @test */
+  public function numberOfModerateSuggestionAchatShouldBeOne() {
+    $this->assertXPathContentContains('//span[@class="menu_info"][preceding::a[contains(@href, "/modo/suggestion-achat")]]', '1');
+  }
 }
 
 
diff --git a/tests/application/modules/admin/controllers/SitothequeControllerTest.php b/tests/application/modules/admin/controllers/SitothequeControllerTest.php
index 558054198770bbbb542eca976c96fa288bd46888..83b1ea18c4b0eaa6cda52291b7dc38f03cedc382 100644
--- a/tests/application/modules/admin/controllers/SitothequeControllerTest.php
+++ b/tests/application/modules/admin/controllers/SitothequeControllerTest.php
@@ -25,7 +25,7 @@ abstract class SitothequeControllerTestCase extends Admin_AbstractControllerTest
 
   public function setUp() {
     parent::setUp();
-
+    $this->setupCustomFields();
     $this->setupDomaines();
     Class_Exemplaire::beVolatile();
     Class_Notice::beVolatile();
@@ -59,6 +59,20 @@ abstract class SitothequeControllerTestCase extends Admin_AbstractControllerTest
     Class_Bib::getPortail()->setSitothequeCategories([]);
   }
 
+
+  public function setupCustomFields() {
+    Class_CustomField_Meta::beVolatile();
+    $theme = $this->fixture('Class_CustomField',
+                            ['id' => 2,
+                             'priority' => 3,
+                             'label' => 'Theme',
+                             'field_type' => Class_CustomField_Meta::SELECT,
+                             'options_list' => 'web links;livres',
+                             'model' => 'Sitotheque']);
+
+  }
+
+
   public function tearDown() {
     Storm_Model_Loader::defaultToDb();
     parent::tearDown();
@@ -122,13 +136,13 @@ class SitothequeControllerIndexTest extends SitothequeControllerTestCase {
 
   /** @test */
   public function siteLeCanardShouldHaveLinkForEdit() {
-    $this->assertXPath('//ul/li[1]//a[contains(@href, "sito/sitoedit/id/22")]');
+    $this->assertXPath('//ul/li[1]//a[contains(@href, "sito/edit/id/22")]');
   }
 
 
   /** @test */
   public function siteLeCanardShouldHaveLinkForDelete() {
-    $this->assertXPath('//ul/li[1]//a[contains(@href, "sito/sitodel/id/22")]');
+    $this->assertXPath('//ul/li[1]//a[contains(@href, "sito/delete/id/22")]');
   }
 
 
@@ -156,7 +170,7 @@ class SitothequeControllerIndexTest extends SitothequeControllerTestCase {
 class SitothequeControllerSitoEditTest extends SitothequeControllerTestCase {
   public function setUp() {
     parent::setUp();
-    $this->dispatch('/admin/sito/sitoedit/id/22', true);
+    $this->dispatch('/admin/sito/edit/id/22', true);
   }
 
 
@@ -177,7 +191,7 @@ class SitothequeControllerSitoEditTest extends SitothequeControllerTestCase {
 
   /** @test */
   public function formShouldActionShouldBeSitoEditId22() {
-    $this->assertXPath('//form[contains(@action, "admin/sito/sitoedit/id/22")]',
+    $this->assertXPath('//form[contains(@action, "admin/sito/edit/id/22")]',
                        $this->_response->getBody());
   }
 
@@ -193,6 +207,13 @@ class SitothequeControllerSitoEditTest extends SitothequeControllerTestCase {
   public function checkBoxShouldCheckedDomaineArt() {
     $this->assertXPath("//input[@name='domaine_ids'][@value='10']");
   }
+
+
+  /** @test */
+  public function customFieldShouldBeDisplayed() {
+    $this->assertXPathContentContains('//select[@id="field_2"]//option', 'web links', $this->_response->getBody());
+  }
+
 }
 
 
@@ -217,9 +238,14 @@ class SitothequeControllerSitoViewTest extends SitothequeControllerTestCase {
 class SitothequeControllerAddActionTest extends SitothequeControllerTestCase {
   public function setUp() {
     parent::setUp();
-    $this->dispatch('/admin/sito/sitoadd/id_cat/2', true);
+    $this->dispatch('/admin/sito/add/id_cat/2', true);
   }
 
+  /** @test */
+  public function comboShouldBeValid() {
+    $this->assertXPath("//select[@name='id_cat']//option");
+
+  }
 
   /** @test */
   public function titreShouldBeAjouterUnSite() {
@@ -228,8 +254,15 @@ class SitothequeControllerAddActionTest extends SitothequeControllerTestCase {
 
   /** @test */
   public function checkBoxShouldCheckedDomaineInformations() {
-    $this->assertXPath("//input[@name='domaine_ids'][@value='66']");
+    $this->assertXPath("//input[@name='domaine_ids'][@value='66']",$this->_response->getBody());
   }
+
+
+  /** @test */
+  public function customFieldShouldBeDisplayed() {
+    $this->assertXPathContentContains('//select[@id="field_2"]//option', 'web links', $this->_response->getBody());
+  }
+
 }
 
 
@@ -247,7 +280,7 @@ class SitothequeControllerPostAddActionTest extends SitothequeControllerTestCase
       ->answers(true);
     Storm_Cache::setDefaultZendCache($this->cache);
 
-    $this->postDispatch('/admin/sito/sitoadd/id_cat/2',
+    $this->postDispatch('/admin/sito/add/id_cat/2',
                         ['titre' => 'google',
                          'url' => 'http://www.google.fr',
                          'id_items' => '23-23',
@@ -258,7 +291,7 @@ class SitothequeControllerPostAddActionTest extends SitothequeControllerTestCase
 
   /** @test */
   public function anwersShouldRedirectToSitoEdit24() {
-    $this->assertRedirectTo('/admin/sito/sitoedit/id/24');
+    $this->assertRedirectTo('/admin/sito/edit/id/24');
   }
 
 
@@ -290,6 +323,7 @@ class SitothequeControllerPostAddActionTest extends SitothequeControllerTestCase
   public function cacheShouldHaveBeenCleaned() {
     $this->assertTrue($this->cache->methodHasBeenCalled('clean'));
   }
+
 }
 
 
@@ -298,12 +332,12 @@ class SitothequeControllerPostAddActionTest extends SitothequeControllerTestCase
 class SitothequeControllerInvalidPostActionTest extends SitothequeControllerTestCase {
   public function setUp() {
     parent::setUp();
-    $this->postDispatch('/admin/sito/sitoadd/id_cat/2', [], true);
+    $this->postDispatch('/admin/sito/add/id_cat/2', [], true);
   }
 
   /** @test */
   public function pageShouldContainsErrorValeurRequise() {
-    $this->assertXPathContentContains('//span[@class="error"]', "Vous devez compléter le champ 'Titre'");
+    $this->assertXPathContentContains('//ul[@class="errors"]/li', "Le champ 'Titre' doit être renseigné et inférieur à 255 caractères",$this->_response->getBody());
   }
 }
 
@@ -313,7 +347,7 @@ class SitothequeControllerInvalidPostActionTest extends SitothequeControllerTest
 class SitothequeControllerSitoPostEditLeMondeTest extends SitothequeControllerTestCase {
   public function setUp() {
     parent::setUp();
-    $this->postDispatch('/admin/sito/sitoedit/id/23',
+    $this->postDispatch('/admin/sito/edit/id/23',
                         ['titre' => 'Times'],
                         true);
     Class_Sitotheque::clearCache();
@@ -329,8 +363,10 @@ class SitothequeControllerSitoPostEditLeMondeTest extends SitothequeControllerTe
 
   /** @test */
   public function anwersShouldRedirectToSitoEdit23() {
-    $this->assertRedirectTo('/admin/sito/sitoedit/id/23');
+    $this->assertRedirectTo('/admin/sito/edit/id/23');
   }
+
+
 }
 
 
@@ -339,7 +375,7 @@ class SitothequeControllerSitoPostEditLeMondeTest extends SitothequeControllerTe
 class SitothequeControllerSitoDeleteLeMondeTest extends SitothequeControllerTestCase {
   public function setUp() {
     parent::setUp();
-    $this->dispatch('/admin/sito/sitodel/id/23', true);
+    $this->dispatch('/admin/sito/delete/id/23', true);
   }
 
 
@@ -360,10 +396,7 @@ class SitothequeControllerSitoDeleteLeMondeTest extends SitothequeControllerTest
 
 class SitothequeControllerActionErrorsTest extends SitothequeControllerTestCase {
   public function errorUrls() {
-    return [['/admin/sito/sitoadd/id_cat/-1'],
-            ['/admin/sito/sitoedit/id/-1'],
-            ['/admin/sito/sitodel/id/-1'],
-            ['/admin/sito/catdel/id_cat/-1'],
+    return [['/admin/sito/catdel/id_cat/-1'],
             ['/admin/sito/catedit/id_cat/-1']
     ];
   }
diff --git a/tests/application/modules/opac/controllers/FormulaireControllerTest.php b/tests/application/modules/opac/controllers/FormulaireControllerTest.php
index 90677cb49ee0cb845deeec78f97a5f5ea0a20a83..b65b5f84ee547b5a62707d79c8248688d22a2500 100644
--- a/tests/application/modules/opac/controllers/FormulaireControllerTest.php
+++ b/tests/application/modules/opac/controllers/FormulaireControllerTest.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
  */
 
 abstract class FormulaireControllerPostActionTestCase extends AbstractControllerTestCase {
@@ -39,8 +39,63 @@ abstract class FormulaireControllerPostActionTestCase extends AbstractController
   }
 }
 
+class FormulaireControllerWithEmailPostActionTest extends FormulaireControllerPostActionTestCase {
+  protected $_user;
+
+  public function setUp() {
+    parent::setUp();
+
+    Class_Article::find(45)->setDestinationEmail('recipient@example.com');
+
+    Class_Profil::getCurrentProfil()->setMailSite('sender@example.com');
+
+    $user = Class_Users::newInstanceWithId(23, ['nom' => 'Mas',
+                                                'prenom' => 'Fanto',
+                                                'login' => 'fantomas']);
+    ZendAfi_Auth::getInstance()->logUser($user);
+
+    $this->mock_transport = new MockMailTransport();
+    Zend_Mail::setDefaultTransport($this->mock_transport);
 
 
+    $this->postDispatch('/formulaire/add/id_article/45',
+                        ['nom' => 'Tinguette' ,
+                         'prenom' => 'Quentin' ]
+                        ,true);
+
+    $this->new_formulaire = Class_Formulaire::find(2);
+  }
+
+  /** @test */
+  public function postFormulaireShouldReturnEmail() {
+    $this->assertXpathContentContains('//div','courriel',true );
+  }
+
+
+  /** @test */
+  public function mailContentShouldContainData() {
+    $this->assertContains('nom: Tinguette', quoted_printable_decode($this->mock_transport->getSentMails()[0]->getBodyText()->getContent()));
+  }
+
+
+  /** @test */
+  public function emailFromShouldBeSender() {
+    $this->assertEquals('sender@example.com', $this->mock_transport->getSentMails()[0]->getFrom());
+  }
+
+  /** @test */
+  public function emailToShouldBeRecipient() {
+    $this->assertEquals('recipient@example.com', $this->mock_transport->getSentMails()[0]->getRecipients()[0]);
+  }
+
+  /** @test */
+  public function emailSubjectShouldBeFormSent() {
+    $this->assertEquals('[Bokeh] Envoi d\'un formulaire', $this->mock_transport->getSentMails()[0]->getSubject());
+  }
+
+
+}
+
 
 class FormulaireControllerPostActionTest extends FormulaireControllerPostActionTestCase {
   protected $_user;
@@ -48,13 +103,13 @@ class FormulaireControllerPostActionTest extends FormulaireControllerPostActionT
   public function setUp() {
     parent::setUp();
 
-    $user = Class_Users::newInstanceWithId(23, ['nom' => 'Mas', 
-                                                'prenom' => 'Fanto', 
+    $user = Class_Users::newInstanceWithId(23, ['nom' => 'Mas',
+                                                'prenom' => 'Fanto',
                                                 'login' => 'fantomas']);
     ZendAfi_Auth::getInstance()->logUser($user);
 
 
-    $this->postDispatch('/formulaire/add/id_article/45', 
+    $this->postDispatch('/formulaire/add/id_article/45',
                         ['nom' => 'Tinguette' ,
                          'prenom' => 'Quentin' ]
                         ,true);
@@ -62,13 +117,12 @@ class FormulaireControllerPostActionTest extends FormulaireControllerPostActionT
     $this->new_formulaire = Class_Formulaire::find(2);
   }
 
-  
   /** @test */
   public function saveFormulaireShouldHaveNomTinguette() {
     $this->assertEquals('Tinguette', $this->new_formulaire->getNom());
   }
 
-  
+
   /** @test */
   public function dateCreationShouldBeNow() {
     $this->assertEquals('2012-10-23 12:32:00', $this->new_formulaire->getDateCreation());
@@ -123,7 +177,7 @@ class FormulaireControllerWithoutConnectedUserPostActionTest extends FormulaireC
 
     ZendAfi_Auth::getInstance()->clearIdentity();
 
-    $this->postDispatch('/formulaire/add/id_article/45', 
+    $this->postDispatch('/formulaire/add/id_article/45',
                         ['nom' => 'Tinguette' ,
                          'prenom' => 'Quentin' ]
                         ,true);
@@ -135,7 +189,7 @@ class FormulaireControllerWithoutConnectedUserPostActionTest extends FormulaireC
   /** @test */
   public function saveFormulaireShouldNotHaveAnyUsers() {
     $this->assertEmpty($this->new_formulaire->getUser());
-    
+
   }
 
 }
diff --git a/tests/application/modules/opac/controllers/NoticeAjaxControllerTest.php b/tests/application/modules/opac/controllers/NoticeAjaxControllerTest.php
index 8abcfa74c5769cdccb914b95598d66d99f9fe6e3..d9bacbdebb48590f993af01c7e79eed544173f79 100644
--- a/tests/application/modules/opac/controllers/NoticeAjaxControllerTest.php
+++ b/tests/application/modules/opac/controllers/NoticeAjaxControllerTest.php
@@ -291,7 +291,7 @@ class NoticeAjaxController1DTouchTest extends AbstractControllerTestCase {
                              'type_doc_id' => Class_TypeDoc::ONEDTOUCH]);
 
     $album->index();
-    $this->dispatch('noticeajax/resnumeriques?id_notice=' . $album->getNoticeId(), true);
+    $this->dispatch('noticeajax/ resnumeriques?id_notice=' . $album->getNoticeId(), true);
   }
 
 
@@ -300,6 +300,12 @@ class NoticeAjaxController1DTouchTest extends AbstractControllerTestCase {
     $this->assertXPathContentContains('//a[@href="http://music.1dtouch.com/users/auth/my_bib?dest=albums/9"]',
                                       'l\'album sur 1DTouch', $this->_response->getBody());
   }
+
+
+  /** @test */
+  public function onloadUtilShouldBeLoaded() {
+    $this->assertXPath('//script[contains(@src, "onload_util")]');
+  }
 }
 
 
@@ -1520,6 +1526,12 @@ class NoticeAjaxControllerNoticeWithAvisAvisAbonneTest extends NoticeAjaxControl
   }
 
 
+  /** @test */
+  public function globalCsssShouldBePresent() {
+    $this->assertXPath('//link[contains(@href, "global.css")]', $this->_response->getBody());
+  }
+
+
   /** @test */
   public function answerShouldContainsAvisDePaul() {
     $this->assertXPathContentContains('//body', 'Tres Bien');
@@ -1780,6 +1792,12 @@ class NoticeAjaxControllerBiographieTest extends NoticeAjaxControllerBiographieT
     $this->dispatch('/opac/noticeajax/biographie/id_notice/23', true);
     $this->assertNotXPathContentContains('//a', 'Modifier la biographie');
   }
+
+
+  /** @test */
+  public function onloadUtilShouldBeLoaded() {
+    $this->assertXPath('//script[contains(@src, "onload_util")]', $this->_response->getBody());
+  }
 }
 
 
@@ -1930,7 +1948,6 @@ class NoticeAjaxControllerWithLocalisationTest extends NoticeAjaxControllerLocal
 
   /** @test */
   public function urlShoudlBeAsExpected() {
-
     $this->assertContains('/userfiles/photobib/plans/bib_0_plan_1.png', $this->_json->url);
   }
 
diff --git a/tests/application/modules/opac/controllers/RechercheControllerAlbumAudioRecordTest.php b/tests/application/modules/opac/controllers/RechercheControllerAlbumAudioRecordTest.php
index 99ed6df476a8c4a535c6db344eabd1dc151e840f..8652397268ecbdcee10ce43d6918653987d1fadf 100644
--- a/tests/application/modules/opac/controllers/RechercheControllerAlbumAudioRecordTest.php
+++ b/tests/application/modules/opac/controllers/RechercheControllerAlbumAudioRecordTest.php
@@ -442,9 +442,9 @@ class RechercheControllerAlbumAudioRecordAsTelephoneViewRessourcesNumeriquesTest
 class RechercheControllerAlbumAudioRecordNotVisibleTest extends RechercheControllerAlbumAudioRecordTestCase {
   /** @test */
   public function noNoticeShouldBeCreated() {
-    Class_Album::find(4)
-      ->setVisible(false)
-      ->index();
+    $album = Class_Album::find(4);
+    $album->setVisible(false);
+    $album->index();
     $this->assertEmpty(Class_Notice::findAll());
   }
 }
diff --git a/tests/bootstrap.php b/tests/bootstrap.php
index e35202db3fcf20d1f28d8ff15449a34c09032b29..ba842159d211a2970845302981e76143cc240479 100644
--- a/tests/bootstrap.php
+++ b/tests/bootstrap.php
@@ -82,9 +82,6 @@ $translate->addTranslation(LANG_DIR.'ro.mo', 'ro');
 $translate->addTranslation(LANG_DIR.'en.mo', 'en');
 $translate->setLocale('fr');
 
-//Initialize the router for tests that do not rely on dispatch
-Zend_Controller_Front::getInstance()->getRouter()->route(new Zend_Controller_Request_Http('http://localhost/'));
-
 require_once 'tests/library/ZendAfi/View/Helper/ViewHelperTestCase.php';
 require_once 'tests/application/modules/admin/controllers/AdminAbstractControllerTestCase.php';
 require_once 'tests/fixtures/RessourcesNumeriquesFixtures.php';
diff --git a/tests/fixtures/RessourcesNumeriquesFixtures.php b/tests/fixtures/RessourcesNumeriquesFixtures.php
index 29310bee65243030816a2dacac4839cd8a6b4374..e704ccbf19d0ed7e165d53f34b5abd9b85bd0e5b 100644
--- a/tests/fixtures/RessourcesNumeriquesFixtures.php
+++ b/tests/fixtures/RessourcesNumeriquesFixtures.php
@@ -36,6 +36,7 @@ class RessourcesNumeriquesFixtures {
     self::deactivatePlanetNemo();
     self::deactivateKidilangues();
     self::deactivateJamendo();
+    self::deactivateDilicom();
   }
 
 
@@ -56,6 +57,7 @@ class RessourcesNumeriquesFixtures {
     self::activatePlanetNemo();
     self::activateKidilangues();
     self::activateJamendo();
+    self::activateDilicom();
   }
 
 
diff --git a/tests/fixtures/audiard_herosdiscret.uni b/tests/fixtures/audiard_herosdiscret.uni
new file mode 100644
index 0000000000000000000000000000000000000000..602bdcce7151f8d2b11b93c83f4bdcd181f26234
--- /dev/null
+++ b/tests/fixtures/audiard_herosdiscret.uni
@@ -0,0 +1 @@
+01518ngm0 2200349   450 001000700000071002700007073001800034100001300052200004500065210001900110215001600129300013500145345001800280606002200298686001300320686004100333686003500374700007300409702005300482702005200535702004800587702004500635702004900680702005300729702003400782702003300816702003800849801001700887932001000904992012500914995012901039694479  a826030-9bStudio Canal  a5050582603095  a201411061 aUn héros très discretfJacques Audiard  cAliceleod1996  a1 DVD, 1h41  aD'après le roman de Jean-François Deniau. - Bonus : interview du réalisateur et Alain Le Henry. Scènes commentées. Making of.  b826030-9cDVD  acinéma français  aF2PCDM4  aFictiontFiction2Code_Statistique_1  aFilmtFilm2Code_Statistique_2 1aAudiardbJacques31000251106g3006Metteur en scène ou réalisateur 1aDesplatbAlexandre3100025081142306Compositeur 1aDeniaubJean-François3100013496740706Auteur 1aKassovitzbMathieu3100021986940056Acteur 1aGrinbergbAnouk3130350006040056Acteur 1aKiberlainbSandrine310003627044005gActeur 1aTrintignantbJean-Louis3100022982340056Acteur 1aDupontelbAlbert40056Acteur 1aBarentinbNadia40056Acteur 1aLe HenrybAlain40006Intervenant 2aFrc20150829  aDrame  uhttp://ecx.images-amazon.com/images/I/51%2BE27GCzjL._SL160_.jpgvhttp://ecx.images-amazon.com/images/I/51%2BE27GCzjL.jpg  aMédiathèquef31879003220456kF AUDm20150829qdrgfopv12[DISPO][Disponible][0][1][][0][0][0][0]42015-02-1367778197
\ No newline at end of file
diff --git a/tests/library/Class/Batch/DilicomTest.php b/tests/library/Class/Batch/DilicomTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..dc953b1ee62b1e9b8ace125a4ee02f69b731a3ab
--- /dev/null
+++ b/tests/library/Class/Batch/DilicomTest.php
@@ -0,0 +1,310 @@
+<?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
+ */
+
+abstract class Class_Batch_DilicomTestCase extends ModelTestCase {
+
+  protected $_storm_default_to_volatile = true;
+  protected $_log = '';
+
+  public function setUp() {
+    parent::setUp();
+
+    $this->fixture('Class_AdminVar',
+                   ['id' => 'DILICOM_PNB_FTP_SERVER',
+                    'clef' => 'DILICOM_PNB_FTP_SERVER',
+                    'valeur' => 'pftp.centprod.com']);
+
+    $this->fixture('Class_AdminVar',
+                   ['id' => 'DILICOM_PNB_FTP_USER',
+                    'clef' => 'DILICOM_PNB_FTP_USER',
+                    'valeur' => '007']);
+
+    $this->fixture('Class_AdminVar',
+                   ['id' => 'DILICOM_PNB_FTP_PASS',
+                    'clef' => 'DILICOM_PNB_FTP_PASS',
+                    'valeur' => 'IGotZeLicense']);
+
+    Class_Batch_Dilicom::setFtpClient($this->getFtpClient());
+    Class_Batch_Dilicom::setFileSystem($this->mock()
+                                       ->whenCalled('file_get_contents')
+                                       ->with(PATH_TEMP . 'dilicom/full_pnb_3056309900005_20150726T050431Z.xml')
+                                       ->answers(file_get_contents(__DIR__ . '/full_pnb_3056309900005_20150726T050431Z.xml'))
+
+                                       ->whenCalled('file_get_contents')
+                                       ->answers(file_get_contents(__DIR__ . '/diffusion_pnb_3056309900005_20150728T050431Z.xml'))
+                                       ->whenCalled('file_exists')
+                                       ->with(PATH_TEMP . 'dilicom/')
+                                       ->answers(true)
+    );
+
+    $this->_prepareFixtures();
+
+    $batch = new Class_Batch_Dilicom();
+    $batch
+      ->setLogger($this->getLogger())
+      ->run();
+  }
+
+
+  protected function _prepareFixtures() {
+
+  }
+
+  public function getFtpClient() {
+    return $this->mock();
+  }
+
+
+  public function getLogger() {
+    return $this->logger = $this->mock()
+                                ->whenCalled('log')
+                                ->willDo(
+                                         function($message) {
+                                           $this->_log .= $message;
+                                         });
+  }
+}
+
+
+
+
+class Class_Batch_DilicomNoConnectionTest extends Class_Batch_DilicomTestCase {
+  protected $_log = '';
+
+  public function getFtpClient() {
+    return parent::getFtpClient()
+      ->whenCalled('connect')
+      ->with('pftp.centprod.com', '007', 'IGotZeLicense')
+      ->answers(false)
+
+      ->beStrict();
+  }
+
+
+  /** @test */
+  public function noConnectionErrorShouldBeLogged() {
+    $this->assertContains('Impossible de se connecter au serveur pftp.centprod.com',
+                          $this->_log);
+  }
+}
+
+
+
+
+class Class_Batch_DilicomNoLsTest extends Class_Batch_DilicomTestCase {
+
+  public function getFtpClient() {
+    return parent::getFtpClient()
+      ->whenCalled('connect')
+      ->with('pftp.centprod.com', '007', 'IGotZeLicense')
+      ->answers(true)
+      ->whenCalled('ls')
+      ->with('HUB/O/')
+      ->answers(false)
+
+      ->beStrict();
+  }
+
+
+  /** @test */
+  public function noLsErrorShouldBeLogged() {
+    $this->assertContains('Impossible de lister le contenu de HUB/O/',
+                          $this->_log);
+  }
+}
+
+class Class_Batch_DilicomNoGetTest extends Class_Batch_DilicomTestCase {
+
+  public function getFtpClient() {
+    return parent::getFtpClient()
+      ->whenCalled('connect')
+      ->with('pftp.centprod.com', '007', 'IGotZeLicense')
+      ->answers(true)
+      ->whenCalled('ls')
+      ->with('HUB/O/')
+      ->answers(['full_pnb_3056309900005_20150726T050431Z.xml',
+                 'full_pnb_3056309900005_20150719T050431Z.xml',
+                 'diffusion_pnb_3056309900005_20150720T050431Z.xml',
+                 'diffusion_pnb_3056309900005_20150728T050431Z.xml',
+                 '007.xml'])
+
+      ->whenCalled('get')
+      ->with('HUB/O/full_pnb_3056309900005_20150726T050431Z.xml',
+             PATH_TEMP . 'dilicom/full_pnb_3056309900005_20150726T050431Z.xml')
+      ->answers(false)
+      ->beStrict();
+  }
+
+
+  /** @test */
+  public function noGetErrorShouldBeLogged() {
+    $this->assertContains('Impossible de télécharger le fichier HUB/O/full_pnb_3056309900005_20150726T050431Z.xml',
+                          $this->_log);
+  }
+}
+
+
+
+class Class_Batch_DilicomWithFullTest extends Class_Batch_DilicomTestCase {
+  public function getFtpClient() {
+    return parent::getFtpClient()
+      ->whenCalled('connect')
+      ->with('pftp.centprod.com', '007', 'IGotZeLicense')
+      ->answers(true)
+
+      ->whenCalled('ls')
+      ->with('HUB/O/')
+      ->answers(['full_pnb_3056309900005_20150726T050431Z.xml',
+                 'full_pnb_3056309900005_20150719T050431Z.xml',
+                 'diffusion_pnb_3056309900005_20150720T050431Z.xml',
+                 'diffusion_pnb_3056309900005_20150728T050431Z.xml',
+                 '007.xml'])
+
+      ->whenCalled('get')
+      ->with('HUB/O/full_pnb_3056309900005_20150726T050431Z.xml',
+             PATH_TEMP . 'dilicom/full_pnb_3056309900005_20150726T050431Z.xml')
+      ->answers(true)
+
+      ->whenCalled('get')
+      ->with('HUB/O/diffusion_pnb_3056309900005_20150728T050431Z.xml',
+             PATH_TEMP . 'dilicom/diffusion_pnb_3056309900005_20150728T050431Z.xml')
+      ->answers(true)
+
+      ->beStrict();
+  }
+
+
+  /** @test */
+  public function shouldLog4FilesInDirectory() {
+    $this->assertContains('4 fichier(s) à traiter dans HUB/O/', $this->_log);
+  }
+
+
+  /** @test */
+  public function shouldLogFullFileToProcess() {
+    $this->assertContains('Fichier total à traiter : full_pnb_3056309900005_20150726T050431Z.xml',
+                          $this->_log);
+  }
+
+
+  /** @test */
+  public function shouldLogIncrementalFileToProcess() {
+    $this->assertContains('Fichiers incrémentaux à traiter : diffusion_pnb_3056309900005_20150728T050431Z.xml',
+                          $this->_log);
+  }
+
+
+  /** @test */
+  public function shouldHaveAdded3Albums() {
+    $this->assertEquals(3, Class_Album::countBy(['type_doc_id' => Class_TypeDoc::DILICOM]));
+  }
+}
+
+
+class Class_Batch_DilicomWithDataTest extends Class_Batch_DilicomTestCase {
+  public function getFtpClient() {
+    return parent::getFtpClient()
+      ->whenCalled('connect')
+      ->with('pftp.centprod.com', '007', 'IGotZeLicense')
+      ->answers(true)
+
+      ->whenCalled('ls')
+      ->with('HUB/O/')
+      ->answers(['full_pnb_3056309900005_20150726T050431Z.xml',
+                 'full_pnb_3056309900005_20150719T050431Z.xml',
+                 'diffusion_pnb_3056309900005_20150720T050431Z.xml',
+                 'diffusion_pnb_3056309900005_20150728T050431Z.xml',
+                 '007.xml'])
+
+      ->whenCalled('get')
+      ->with('HUB/O/full_pnb_3056309900005_20150726T050431Z.xml',
+             PATH_TEMP . 'dilicom/full_pnb_3056309900005_20150726T050431Z.xml')
+      ->answers(true)
+
+      ->whenCalled('get')
+      ->with('HUB/O/diffusion_pnb_3056309900005_20150728T050431Z.xml',
+             PATH_TEMP . 'dilicom/diffusion_pnb_3056309900005_20150728T050431Z.xml')
+      ->answers(true)
+
+      ->beStrict();
+  }
+
+  protected function _prepareFixtures() {
+    $this->fixture('Class_Batch',
+                   [ 'id' => 12,
+                    'type' => Class_Batch_Dilicom::TYPE,
+                    'data' => 'full_pnb_3056309900005_20150822T050431Z.xml']);
+  }
+
+  /** @test */
+  public function shouldLogFullFileToProcess() {
+    $this->assertContains('Aucun fichier plus récent que le dernier fichier déjà traité (full_pnb_3056309900005_20150822T050431Z.xml)',
+                          $this->_log);
+  }
+}
+
+
+
+class Class_Batch_DilicomWithoutFullTest extends Class_Batch_DilicomTestCase {
+  public function getFtpClient() {
+    return parent::getFtpClient()
+      ->whenCalled('connect')
+      ->with('pftp.centprod.com', '007', 'IGotZeLicense')
+      ->answers(true)
+
+      ->whenCalled('ls')
+      ->with('HUB/O/')
+      ->answers(['diffusion_pnb_3056309900005_20150720T050431Z.xml',
+                 'diffusion_pnb_3056309900005_20150728T050431Z.xml',
+                 '007.xml'])
+
+      ->whenCalled('get')
+      ->with('HUB/O/diffusion_pnb_3056309900005_20150720T050431Z.xml',
+             PATH_TEMP . 'dilicom/diffusion_pnb_3056309900005_20150720T050431Z.xml')
+      ->answers(true)
+
+      ->whenCalled('get')
+      ->with('HUB/O/diffusion_pnb_3056309900005_20150728T050431Z.xml',
+             PATH_TEMP . 'dilicom/diffusion_pnb_3056309900005_20150728T050431Z.xml')
+      ->answers(true)
+
+      ->beStrict();
+  }
+
+
+  /** @test */
+  public function shouldLog2FilesInDirectory() {
+    $this->assertContains('2 fichier(s) à traiter dans HUB/O/', $this->_log);
+  }
+
+
+  /** @test */
+  public function shouldNotLogFullFileToProcess() {
+    $this->assertNotContains('Fichier total', $this->_log);
+  }
+
+
+  /** @test */
+  public function shouldLogIncrementalFileToProcess() {
+    $this->assertContains('Fichiers incrémentaux à traiter : diffusion_pnb_3056309900005_20150720T050431Z.xml diffusion_pnb_3056309900005_20150728T050431Z.xml',
+                          $this->_log);
+  }
+}
diff --git a/tests/library/Class/Batch/diffusion_pnb_3056309900005_20150728T050431Z.xml b/tests/library/Class/Batch/diffusion_pnb_3056309900005_20150728T050431Z.xml
new file mode 100644
index 0000000000000000000000000000000000000000..9be39bc875d8cdde913d90e27514769792c0ef1c
--- /dev/null
+++ b/tests/library/Class/Batch/diffusion_pnb_3056309900005_20150728T050431Z.xml
@@ -0,0 +1,451 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<pnbOffers
+xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+xsi:schemaLocation="
+http://www.editeur.org/onix/3.0/reference 
+http://pnb-recette.dilicom.net/notices_onix/schema_onix/ONIX_BookProduct_3.0_reference.xsd
+http://pnb.dilicom.net/definitions
+http://pnb-recette.dilicom.net/notices_onix/schema/pnb_diffusion_offre_collectivite.xsd">
+<offer>
+    <notice>&lt;?xml version="1.0" encoding="UTF-8"?&gt;&lt;ONIXMessage release="3.0" xmlns="http://www.editeur.org/onix/3.0/reference"&gt;
+&lt;Header&gt;
+&lt;Sender&gt;
+&lt;SenderIdentifier&gt;&lt;SenderIDType&gt;06&lt;/SenderIDType&gt;&lt;IDValue&gt;3025599000108&lt;/IDValue&gt;&lt;/SenderIdentifier&gt;
+&lt;SenderName&gt;SERVEUR DILICOM - PNB NUMERIQUE&lt;/SenderName&gt;&lt;/Sender&gt;
+&lt;Addressee&gt;&lt;AddresseeIdentifier&gt;&lt;AddresseeIDType&gt;06&lt;/AddresseeIDType&gt;&lt;IDValue&gt;3056309900005&lt;/IDValue&gt;&lt;/AddresseeIdentifier&gt;&lt;/Addressee&gt;
+&lt;SentDateTime&gt;20150721T0703Z&lt;/SentDateTime&gt;
+&lt;/Header&gt;
+&lt;Product&gt;
+&lt;RecordReference&gt;EDEN-30724-51042-LIBRARIES&lt;/RecordReference&gt;
+&lt;NotificationType&gt;04&lt;/NotificationType&gt;
+&lt;ProductIdentifier&gt;
+&lt;ProductIDType&gt;15&lt;/ProductIDType&gt;
+&lt;IDValue&gt;9791021012431&lt;/IDValue&gt;
+&lt;/ProductIdentifier&gt;
+&lt;ProductIdentifier&gt;
+&lt;ProductIDType&gt;01&lt;/ProductIDType&gt;
+&lt;IDTypeName&gt;internal_key&lt;/IDTypeName&gt;
+&lt;IDValue&gt;eden-30724-51042-libraries&lt;/IDValue&gt;
+&lt;/ProductIdentifier&gt;
+&lt;DescriptiveDetail&gt;
+&lt;ProductComposition&gt;00&lt;/ProductComposition&gt;
+&lt;ProductForm&gt;EB&lt;/ProductForm&gt;
+&lt;ProductFormDetail&gt;E101&lt;/ProductFormDetail&gt;
+&lt;ProductFormDetail&gt;E200&lt;/ProductFormDetail&gt;
+&lt;ProductFormFeature&gt;
+&lt;ProductFormFeatureType&gt;07&lt;/ProductFormFeatureType&gt;
+&lt;ProductFormFeatureValue&gt;on-site&lt;/ProductFormFeatureValue&gt;
+&lt;ProductFormFeatureDescription&gt;PNBONLINE04&lt;/ProductFormFeatureDescription&gt;
+&lt;/ProductFormFeature&gt;
+&lt;EpubTechnicalProtection&gt;03&lt;/EpubTechnicalProtection&gt;
+&lt;EpubUsageConstraint&gt;
+&lt;EpubUsageType&gt;02&lt;/EpubUsageType&gt;
+&lt;EpubUsageStatus&gt;03&lt;/EpubUsageStatus&gt;
+&lt;/EpubUsageConstraint&gt;
+&lt;EpubUsageConstraint&gt;
+&lt;EpubUsageType&gt;03&lt;/EpubUsageType&gt;
+&lt;EpubUsageStatus&gt;03&lt;/EpubUsageStatus&gt;
+&lt;/EpubUsageConstraint&gt;
+&lt;EpubUsageConstraint&gt;
+&lt;EpubUsageType&gt;04&lt;/EpubUsageType&gt;
+&lt;EpubUsageStatus&gt;02&lt;/EpubUsageStatus&gt;
+&lt;EpubUsageLimit&gt;
+&lt;Quantity&gt;6&lt;/Quantity&gt;
+&lt;EpubUsageUnit&gt;06&lt;/EpubUsageUnit&gt;
+&lt;/EpubUsageLimit&gt;
+&lt;/EpubUsageConstraint&gt;
+&lt;EpubUsageConstraint&gt;
+&lt;EpubUsageType&gt;06&lt;/EpubUsageType&gt;
+&lt;EpubUsageStatus&gt;02&lt;/EpubUsageStatus&gt;
+&lt;EpubUsageLimit&gt;
+&lt;Quantity&gt;59&lt;/Quantity&gt;
+&lt;EpubUsageUnit&gt;09&lt;/EpubUsageUnit&gt;
+&lt;/EpubUsageLimit&gt;
+&lt;EpubUsageLimit&gt;
+&lt;Quantity&gt;40&lt;/Quantity&gt;
+&lt;EpubUsageUnit&gt;10&lt;/EpubUsageUnit&gt;
+&lt;/EpubUsageLimit&gt;
+&lt;EpubUsageLimit&gt;
+&lt;Quantity&gt;15&lt;/Quantity&gt;
+&lt;EpubUsageUnit&gt;07&lt;/EpubUsageUnit&gt;
+&lt;/EpubUsageLimit&gt;
+&lt;/EpubUsageConstraint&gt;
+&lt;EpubUsageConstraint&gt;
+&lt;EpubUsageType&gt;07&lt;/EpubUsageType&gt;
+&lt;EpubUsageStatus&gt;02&lt;/EpubUsageStatus&gt;
+&lt;EpubUsageLimit&gt;
+&lt;Quantity&gt;1825&lt;/Quantity&gt;
+&lt;EpubUsageUnit&gt;09&lt;/EpubUsageUnit&gt;
+&lt;/EpubUsageLimit&gt;
+&lt;/EpubUsageConstraint&gt;
+&lt;EpubUsageConstraint&gt;
+&lt;EpubUsageType&gt;04&lt;/EpubUsageType&gt;
+&lt;EpubUsageStatus&gt;02&lt;/EpubUsageStatus&gt;
+&lt;EpubUsageLimit&gt;
+&lt;Quantity&gt;9999&lt;/Quantity&gt;
+&lt;EpubUsageUnit&gt;07&lt;/EpubUsageUnit&gt;
+&lt;/EpubUsageLimit&gt;
+&lt;/EpubUsageConstraint&gt;
+&lt;TitleDetail&gt;
+&lt;TitleType&gt;01&lt;/TitleType&gt;
+&lt;TitleElement&gt;
+&lt;TitleElementLevel&gt;01&lt;/TitleElementLevel&gt;
+&lt;TitleText&gt;La Guerre germano-soviétique&lt;/TitleText&gt;
+&lt;Subtitle&gt;1941-1945&lt;/Subtitle&gt;
+&lt;/TitleElement&gt;
+&lt;/TitleDetail&gt;
+&lt;Contributor&gt;
+&lt;SequenceNumber&gt;1&lt;/SequenceNumber&gt;
+&lt;ContributorRole&gt;A01&lt;/ContributorRole&gt;
+&lt;PersonName&gt;Nicolas Bernard&lt;/PersonName&gt;
+&lt;PersonNameInverted&gt;Bernard, Nicolas&lt;/PersonNameInverted&gt;
+&lt;NamesBeforeKey&gt;Nicolas&lt;/NamesBeforeKey&gt;
+&lt;KeyNames&gt;Bernard&lt;/KeyNames&gt;
+&lt;BiographicalNote&gt;Nicolas BERNARD, avocat, est spécialiste de la Deuxième Guerre mondiale et contribue à plusieurs revues d’histoire militaire. Il se consacre également à l’étude et à la réfutation du négationnisme.&lt;/BiographicalNote&gt;
+&lt;ContributorPlace&gt;
+&lt;ContributorPlaceRelator&gt;08&lt;/ContributorPlaceRelator&gt;
+&lt;CountryCode&gt;FR&lt;/CountryCode&gt;
+&lt;/ContributorPlace&gt;
+&lt;/Contributor&gt;
+&lt;NoEdition/&gt;
+&lt;Language&gt;
+&lt;LanguageRole&gt;01&lt;/LanguageRole&gt;
+&lt;LanguageCode&gt;fre&lt;/LanguageCode&gt;
+&lt;/Language&gt;
+&lt;Extent&gt;
+&lt;ExtentType&gt;22&lt;/ExtentType&gt;
+&lt;ExtentValue&gt;7.94&lt;/ExtentValue&gt;
+&lt;ExtentUnit&gt;19&lt;/ExtentUnit&gt;
+&lt;/Extent&gt;
+&lt;Extent&gt;
+&lt;ExtentType&gt;00&lt;/ExtentType&gt;
+&lt;ExtentValue&gt;800&lt;/ExtentValue&gt;
+&lt;ExtentUnit&gt;03&lt;/ExtentUnit&gt;
+&lt;/Extent&gt;
+&lt;Subject&gt;
+&lt;SubjectSchemeIdentifier&gt;29&lt;/SubjectSchemeIdentifier&gt;
+&lt;SubjectSchemeVersion&gt;DILICOM20&lt;/SubjectSchemeVersion&gt;
+&lt;SubjectCode&gt;2340&lt;/SubjectCode&gt;
+&lt;SubjectHeadingText&gt;Reportages, actualités, documents&lt;/SubjectHeadingText&gt;
+&lt;/Subject&gt;
+&lt;Subject&gt;
+&lt;SubjectSchemeIdentifier&gt;29&lt;/SubjectSchemeIdentifier&gt;
+&lt;SubjectSchemeVersion&gt;DILICOM20&lt;/SubjectSchemeVersion&gt;
+&lt;SubjectCode&gt;2110&lt;/SubjectCode&gt;
+&lt;SubjectHeadingText&gt;Histoire&lt;/SubjectHeadingText&gt;
+&lt;/Subject&gt;
+&lt;Subject&gt;
+&lt;SubjectSchemeIdentifier&gt;10&lt;/SubjectSchemeIdentifier&gt;
+&lt;SubjectCode&gt;HIS000000&lt;/SubjectCode&gt;
+&lt;/Subject&gt;
+&lt;Subject&gt;
+&lt;MainSubject/&gt;
+&lt;SubjectSchemeIdentifier&gt;10&lt;/SubjectSchemeIdentifier&gt;
+&lt;SubjectCode&gt;SOC041000&lt;/SubjectCode&gt;
+&lt;/Subject&gt;
+&lt;Subject&gt;
+&lt;MainSubject/&gt;
+&lt;SubjectSchemeIdentifier&gt;29&lt;/SubjectSchemeIdentifier&gt;
+&lt;SubjectCode&gt;3377&lt;/SubjectCode&gt;
+&lt;SubjectHeadingText&gt;HISTOIRE&lt;/SubjectHeadingText&gt;
+&lt;/Subject&gt;
+&lt;Subject&gt;
+&lt;SubjectSchemeIdentifier&gt;29&lt;/SubjectSchemeIdentifier&gt;
+&lt;SubjectCode&gt;3644&lt;/SubjectCode&gt;
+&lt;SubjectHeadingText&gt;Actualités, Reportages&lt;/SubjectHeadingText&gt;
+&lt;/Subject&gt;
+&lt;Subject&gt;
+&lt;SubjectSchemeIdentifier&gt;20&lt;/SubjectSchemeIdentifier&gt;
+&lt;SubjectHeadingText&gt;Tallandier; Epub; numérique; guerre; Russie; Allemagne; nazi; URSS; Barbarossa; Moscou; Hitler; Staline; juif; Kersaudy; Stalingrad&lt;/SubjectHeadingText&gt;
+&lt;/Subject&gt;
+&lt;/DescriptiveDetail&gt;
+&lt;CollateralDetail&gt;
+&lt;TextContent&gt;
+&lt;TextType&gt;03&lt;/TextType&gt;
+&lt;ContentAudience&gt;00&lt;/ContentAudience&gt;
+&lt;Text&gt;22 juin 1941. Violant le pacte de non-agression conclu le 23 août 1939, l’Allemagne nazie envahit l’URSS. S’ouvre alors une guerre aussi colossale qu’inexpiable, qui fauchera plus de trente millions de personnes, soit la moitié des pertes causées par la Deuxième Guerre mondiale. 
+
+S’appuyant sur une ample documentation russe, allemande, anglo-saxonne, et s’affranchissant de plusieurs idées reçues, cette vaste fresque nous entraîne de « Barbarossa » à Moscou, de Stalingrad à Koursk, de la reconquête soviétique à la chute de Budapest et de Berlin, nous plongeant au cœur des opérations et des doctrines militaires dont elles procèdent. 
+L’auteur déchiffre les calculs de Hitler et de Staline, mais fait aussi une large part aux péripéties diplomatiques, à la dimension économique de l’affrontement, au déchaînement de violence qu’il génère, notamment la « Shoah par balles » qui se traduira par l’assassinat de plus d’un million trois cent mille juifs soviétiques par les nazis. Sans oublier le vécu des obscurs et des sans-grades, « matériel humain » d’une guerre totale et absolue. 
+
+« Ce que le lecteur retiendra, c’est la remarquable objectivité avec laquelle Nicolas Bernard traite les questions les plus délicates posées par cet affrontement titanesque entre deux tyrans, deux idéologies mortifères et deux peuples engagés malgré eux dans une guerre d’extermination. Même si certaines archives restent fermées à la recherche, il faudra sans doute bien des années avant qu’une œuvre aussi magistrale puisse être considérée comme dépassée. »
+
+François Kersaudy&lt;/Text&gt;
+&lt;/TextContent&gt;
+&lt;TextContent&gt;
+&lt;TextType&gt;02&lt;/TextType&gt;
+&lt;ContentAudience&gt;00&lt;/ContentAudience&gt;
+&lt;Text&gt;22 juin 1941. Violant le pacte de non-agression conclu le 23 août 1939, l’Allemagne nazie envahit l’URSS. S’ouvre alors une guerre aussi colossale qu’inexpiable, qui fauchera plus de trente millions de personnes, soit la moitié des pertes causées par la Deuxième Guerre mondiale. 
+
+S’appuyant sur une ample documentation russe, allemande, anglo-saxonne, et s’affranchissant de plusieurs idées reçues, cette vaste fresque nous entraîne de « Barbarossa » à Moscou, de Stalingrad à Koursk, de la reconquête soviétique à la chute de Budapest et de Berlin, nous plongeant au cœur des opérations et des doctrines militaires dont elles procèdent. 
+L’auteur déchiffre les calculs de Hitler et de Staline, mais fait aussi une large part aux péripéties diplomatiques, à la dimension économique de l’affrontement, au déchaînement de violence qu’il génère, notamment la « Shoah par balles » qui se traduira par l’assassinat de plus d’un million trois cent mille juifs soviétiques par les nazis. Sans oublier le vécu des obscurs et des sans-grades, « matériel humain » d’une guerre totale et absolue. 
+
+« Ce que le lecteur retiendra, c’est la remarquable objectivité avec laquelle Nicolas Bernard traite les questions les plus délicates posées par cet affrontement titanesque entre deux tyrans, deux idéologies mortifères et deux peuples engagés malgré eux dans une guerre d’extermination. Même si certaines archives restent fermées à la recherche, il faudra sans doute bien des années avant qu’une œuvre aussi magistrale puisse être considérée comme dépassée. » 
+François Kersaudy&lt;/Text&gt;
+&lt;/TextContent&gt;
+&lt;SupportingResource&gt;
+&lt;ResourceContentType&gt;01&lt;/ResourceContentType&gt;
+&lt;ContentAudience&gt;00&lt;/ContentAudience&gt;
+&lt;ResourceMode&gt;03&lt;/ResourceMode&gt;
+&lt;ResourceFeature&gt;
+&lt;ResourceFeatureType&gt;02&lt;/ResourceFeatureType&gt;
+&lt;FeatureValue&gt;couverture principale&lt;/FeatureValue&gt;
+&lt;/ResourceFeature&gt;
+&lt;ResourceVersion&gt;
+&lt;ResourceForm&gt;02&lt;/ResourceForm&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;04&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;front_cover.jpg&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;01&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;D502&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;03&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;1000&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;02&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;1394&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceLink&gt;https://assets.edenlivres.fr/assets/publications/30724/medias/front_cover.jpg&lt;/ResourceLink&gt;
+&lt;ContentDate&gt;
+&lt;ContentDateRole&gt;17&lt;/ContentDateRole&gt;
+&lt;DateFormat&gt;14&lt;/DateFormat&gt;
+&lt;Date&gt;20131015T153823+0200&lt;/Date&gt;
+&lt;/ContentDate&gt;
+&lt;/ResourceVersion&gt;
+&lt;/SupportingResource&gt;
+&lt;SupportingResource&gt;
+&lt;ResourceContentType&gt;15&lt;/ResourceContentType&gt;
+&lt;ContentAudience&gt;00&lt;/ContentAudience&gt;
+&lt;ResourceMode&gt;04&lt;/ResourceMode&gt;
+&lt;ResourceFeature&gt;
+&lt;ResourceFeatureType&gt;02&lt;/ResourceFeatureType&gt;
+&lt;FeatureValue&gt;Extrait&lt;/FeatureValue&gt;
+&lt;/ResourceFeature&gt;
+&lt;ResourceVersion&gt;
+&lt;ResourceForm&gt;02&lt;/ResourceForm&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;04&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;extrait.epub&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;01&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;E101&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceLink&gt;https://assets.edenlivres.fr/assets/publications/30724/medias/extrait.epub&lt;/ResourceLink&gt;
+&lt;ContentDate&gt;
+&lt;ContentDateRole&gt;17&lt;/ContentDateRole&gt;
+&lt;DateFormat&gt;14&lt;/DateFormat&gt;
+&lt;Date&gt;20131015T153824+0200&lt;/Date&gt;
+&lt;/ContentDate&gt;
+&lt;/ResourceVersion&gt;
+&lt;/SupportingResource&gt;
+&lt;SupportingResource&gt;
+&lt;ResourceContentType&gt;01&lt;/ResourceContentType&gt;
+&lt;ContentAudience&gt;00&lt;/ContentAudience&gt;
+&lt;ResourceMode&gt;03&lt;/ResourceMode&gt;
+&lt;ResourceFeature&gt;
+&lt;ResourceFeatureType&gt;02&lt;/ResourceFeatureType&gt;
+&lt;FeatureValue&gt;front_cover_small&lt;/FeatureValue&gt;
+&lt;/ResourceFeature&gt;
+&lt;ResourceVersion&gt;
+&lt;ResourceForm&gt;02&lt;/ResourceForm&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;04&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;http://assets.edenlivres.fr/assets/publications/30724/cover/small.jpg&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;01&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;D502&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;03&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;65&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceLink&gt;http://assets.edenlivres.fr/assets/publications/30724/cover/small.jpg&lt;/ResourceLink&gt;
+&lt;ContentDate&gt;
+&lt;ContentDateRole&gt;17&lt;/ContentDateRole&gt;
+&lt;DateFormat&gt;14&lt;/DateFormat&gt;
+&lt;Date&gt;20150113T190647+0100&lt;/Date&gt;
+&lt;/ContentDate&gt;
+&lt;/ResourceVersion&gt;
+&lt;/SupportingResource&gt;
+&lt;SupportingResource&gt;
+&lt;ResourceContentType&gt;01&lt;/ResourceContentType&gt;
+&lt;ContentAudience&gt;00&lt;/ContentAudience&gt;
+&lt;ResourceMode&gt;03&lt;/ResourceMode&gt;
+&lt;ResourceFeature&gt;
+&lt;ResourceFeatureType&gt;02&lt;/ResourceFeatureType&gt;
+&lt;FeatureValue&gt;front_cover_medium&lt;/FeatureValue&gt;
+&lt;/ResourceFeature&gt;
+&lt;ResourceVersion&gt;
+&lt;ResourceForm&gt;02&lt;/ResourceForm&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;04&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;http://assets.edenlivres.fr/assets/publications/30724/cover/medium.jpg&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;01&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;D502&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;03&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;200&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceLink&gt;http://assets.edenlivres.fr/assets/publications/30724/cover/medium.jpg&lt;/ResourceLink&gt;
+&lt;ContentDate&gt;
+&lt;ContentDateRole&gt;17&lt;/ContentDateRole&gt;
+&lt;DateFormat&gt;14&lt;/DateFormat&gt;
+&lt;Date&gt;20150113T190646+0100&lt;/Date&gt;
+&lt;/ContentDate&gt;
+&lt;/ResourceVersion&gt;
+&lt;/SupportingResource&gt;
+&lt;SupportingResource&gt;
+&lt;ResourceContentType&gt;01&lt;/ResourceContentType&gt;
+&lt;ContentAudience&gt;00&lt;/ContentAudience&gt;
+&lt;ResourceMode&gt;03&lt;/ResourceMode&gt;
+&lt;ResourceFeature&gt;
+&lt;ResourceFeatureType&gt;02&lt;/ResourceFeatureType&gt;
+&lt;FeatureValue&gt;front_cover_large&lt;/FeatureValue&gt;
+&lt;/ResourceFeature&gt;
+&lt;ResourceVersion&gt;
+&lt;ResourceForm&gt;02&lt;/ResourceForm&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;04&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;http://assets.edenlivres.fr/assets/publications/30724/cover/large.jpg&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;01&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;D502&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;03&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;1000&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceLink&gt;http://assets.edenlivres.fr/assets/publications/30724/cover/large.jpg&lt;/ResourceLink&gt;
+&lt;ContentDate&gt;
+&lt;ContentDateRole&gt;17&lt;/ContentDateRole&gt;
+&lt;DateFormat&gt;14&lt;/DateFormat&gt;
+&lt;Date&gt;20150113T190646+0100&lt;/Date&gt;
+&lt;/ContentDate&gt;
+&lt;/ResourceVersion&gt;
+&lt;/SupportingResource&gt;
+&lt;SupportingResource&gt;
+&lt;ResourceContentType&gt;16&lt;/ResourceContentType&gt;
+&lt;ContentAudience&gt;00&lt;/ContentAudience&gt;
+&lt;ResourceMode&gt;06&lt;/ResourceMode&gt;
+&lt;ResourceVersion&gt;
+&lt;ResourceForm&gt;01&lt;/ResourceForm&gt;
+&lt;ResourceLink&gt;http://www.edenlivres.fr/p/30724&lt;/ResourceLink&gt;
+&lt;/ResourceVersion&gt;
+&lt;/SupportingResource&gt;
+&lt;/CollateralDetail&gt;
+&lt;PublishingDetail&gt;
+&lt;Imprint&gt;
+&lt;ImprintName&gt;Tallandier&lt;/ImprintName&gt;
+&lt;/Imprint&gt;
+&lt;Publisher&gt;
+&lt;PublishingRole&gt;01&lt;/PublishingRole&gt;
+&lt;PublisherIdentifier&gt;
+&lt;PublisherIDType&gt;06&lt;/PublisherIDType&gt;
+&lt;IDValue&gt;3052235000017&lt;/IDValue&gt;
+&lt;/PublisherIdentifier&gt;
+&lt;PublisherIdentifier&gt;
+&lt;PublisherIDType&gt;01&lt;/PublisherIDType&gt;
+&lt;IDTypeName&gt;DM_GLOBAL_ID&lt;/IDTypeName&gt;
+&lt;IDValue&gt;EDEN165&lt;/IDValue&gt;
+&lt;/PublisherIdentifier&gt;
+&lt;PublisherName&gt;Tallandier&lt;/PublisherName&gt;
+&lt;Website&gt;
+&lt;WebsiteRole&gt;01&lt;/WebsiteRole&gt;
+&lt;WebsiteLink&gt;http://www.tallandier.com/&lt;/WebsiteLink&gt;
+&lt;/Website&gt;
+&lt;/Publisher&gt;
+&lt;PublishingStatus&gt;04&lt;/PublishingStatus&gt;
+&lt;PublishingDate&gt;
+&lt;PublishingDateRole&gt;01&lt;/PublishingDateRole&gt;
+&lt;DateFormat&gt;14&lt;/DateFormat&gt;
+&lt;Date&gt;20130905T000000+0200&lt;/Date&gt;
+&lt;/PublishingDate&gt;
+&lt;PublishingDate&gt;
+&lt;PublishingDateRole&gt;19&lt;/PublishingDateRole&gt;
+&lt;DateFormat&gt;14&lt;/DateFormat&gt;
+&lt;Date&gt;20130905T000000+0200&lt;/Date&gt;
+&lt;/PublishingDate&gt;
+&lt;SalesRights&gt;
+&lt;SalesRightsType&gt;01&lt;/SalesRightsType&gt;
+&lt;Territory&gt;
+&lt;CountriesIncluded&gt;DE AD AT BE CY ES EE FI FR GR GP GF IE IT LU MT MQ YT MC NL PT RE SK SI&lt;/CountriesIncluded&gt;
+&lt;/Territory&gt;
+&lt;/SalesRights&gt;
+&lt;SalesRestriction&gt;
+&lt;SalesRestrictionType&gt;06&lt;/SalesRestrictionType&gt;
+&lt;/SalesRestriction&gt;
+&lt;/PublishingDetail&gt;
+&lt;RelatedMaterial&gt;
+&lt;RelatedProduct&gt;
+&lt;ProductRelationCode&gt;13&lt;/ProductRelationCode&gt;
+&lt;ProductIdentifier&gt;
+&lt;ProductIDType&gt;03&lt;/ProductIDType&gt;
+&lt;IDValue&gt;9791021002746&lt;/IDValue&gt;
+&lt;/ProductIdentifier&gt;
+&lt;ProductForm&gt;BA&lt;/ProductForm&gt;
+&lt;/RelatedProduct&gt;
+&lt;RelatedProduct&gt;
+&lt;ProductRelationCode&gt;31&lt;/ProductRelationCode&gt;
+&lt;ProductIdentifier&gt;
+&lt;ProductIDType&gt;15&lt;/ProductIDType&gt;
+&lt;IDValue&gt;9791021003002&lt;/IDValue&gt;
+&lt;/ProductIdentifier&gt;
+&lt;ProductForm&gt;EA&lt;/ProductForm&gt;
+&lt;ProductFormDetail&gt;E101&lt;/ProductFormDetail&gt;
+&lt;ProductFormDetail&gt;E200&lt;/ProductFormDetail&gt;
+&lt;/RelatedProduct&gt;
+&lt;RelatedProduct&gt;
+&lt;ProductRelationCode&gt;06&lt;/ProductRelationCode&gt;
+&lt;ProductIdentifier&gt;
+&lt;ProductIDType&gt;01&lt;/ProductIDType&gt;
+&lt;IDValue&gt;eden-30724-15766-libraries&lt;/IDValue&gt;
+&lt;/ProductIdentifier&gt;
+&lt;ProductForm&gt;EA&lt;/ProductForm&gt;
+&lt;/RelatedProduct&gt;
+&lt;/RelatedMaterial&gt;
+&lt;/Product&gt;
+&lt;/ONIXMessage&gt;</notice>
+    <orderLine>
+        <orderId>FBKS1974</orderId>
+        <orderIdColl>LIBFBKS1974</orderIdColl>
+        <orderLineId>55a1145c975a0323f994c608</orderLineId>
+        <orderDate>2015-07-11T15:04:29.582+02:00</orderDate>
+        <ean13>9791021012431</ean13>
+        <quantity>1</quantity>
+        <usage>
+            <loanTerms>
+                <loanMaxDuration>
+                    <value>59</value>
+                    <unit>DAY</unit>
+                </loanMaxDuration>
+                <nbLoans>40</nbLoans>
+                <loanNbSimultaneousUsers>15</loanNbSimultaneousUsers>
+                <consultNbSimultaneousUsersInSitu>9999</consultNbSimultaneousUsersInSitu>
+                <consultNbSimultaneousUsersExSitu>0</consultNbSimultaneousUsersExSitu>
+            </loanTerms>
+            <userRights>
+                <printing>PROHIBITED</printing>
+                <copyAndPaste>PROHIBITED</copyAndPaste>
+                <nbAllowedDevices>6</nbAllowedDevices>
+            </userRights>
+            <collRights>
+                <offerValidity>
+                    <value>1825</value>
+                    <unit>DAY</unit>
+                </offerValidity>
+            </collRights>
+        </usage>
+        <returnStatus>OK</returnStatus>
+    </orderLine>
+</offer>
+</pnbOffers>
\ No newline at end of file
diff --git a/tests/library/Class/Batch/full_pnb_3056309900005_20150726T050431Z.xml b/tests/library/Class/Batch/full_pnb_3056309900005_20150726T050431Z.xml
new file mode 100644
index 0000000000000000000000000000000000000000..625df36d6b5d4bcb9759becaf0657eb725c06794
--- /dev/null
+++ b/tests/library/Class/Batch/full_pnb_3056309900005_20150726T050431Z.xml
@@ -0,0 +1,1375 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<pnbOffers
+xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+xsi:schemaLocation="
+http://www.editeur.org/onix/3.0/reference 
+http://pnb-recette.dilicom.net/notices_onix/schema_onix/ONIX_BookProduct_3.0_reference.xsd
+http://pnb.dilicom.net/definitions
+http://pnb-recette.dilicom.net/notices_onix/schema/pnb_diffusion_offre_collectivite.xsd">
+<offer>
+    <notice>&lt;?xml version="1.0" encoding="UTF-8"?&gt;&lt;ONIXMessage release="3.0" xmlns="http://www.editeur.org/onix/3.0/reference"&gt;
+&lt;Header&gt;
+&lt;Sender&gt;
+&lt;SenderIdentifier&gt;&lt;SenderIDType&gt;06&lt;/SenderIDType&gt;&lt;IDValue&gt;3025599000108&lt;/IDValue&gt;&lt;/SenderIdentifier&gt;
+&lt;SenderName&gt;SERVEUR DILICOM - PNB NUMERIQUE&lt;/SenderName&gt;&lt;/Sender&gt;
+&lt;Addressee&gt;&lt;AddresseeIdentifier&gt;&lt;AddresseeIDType&gt;06&lt;/AddresseeIDType&gt;&lt;IDValue&gt;3056309900005&lt;/IDValue&gt;&lt;/AddresseeIdentifier&gt;&lt;/Addressee&gt;
+&lt;SentDateTime&gt;20150726T0704Z&lt;/SentDateTime&gt;
+&lt;/Header&gt;
+&lt;Product&gt;
+&lt;RecordReference&gt;EDEN-100287-73941-LIBRARIES&lt;/RecordReference&gt;
+&lt;NotificationType&gt;03&lt;/NotificationType&gt;
+&lt;ProductIdentifier&gt;
+&lt;ProductIDType&gt;03&lt;/ProductIDType&gt;
+&lt;IDValue&gt;9782290123409&lt;/IDValue&gt;
+&lt;/ProductIdentifier&gt;
+&lt;ProductIdentifier&gt;
+&lt;ProductIDType&gt;01&lt;/ProductIDType&gt;
+&lt;IDTypeName&gt;internal_key&lt;/IDTypeName&gt;
+&lt;IDValue&gt;eden-100287-73941-libraries&lt;/IDValue&gt;
+&lt;/ProductIdentifier&gt;
+&lt;DescriptiveDetail&gt;
+&lt;ProductComposition&gt;00&lt;/ProductComposition&gt;
+&lt;ProductForm&gt;EB&lt;/ProductForm&gt;
+&lt;ProductFormDetail&gt;E101&lt;/ProductFormDetail&gt;
+&lt;ProductFormDetail&gt;E200&lt;/ProductFormDetail&gt;
+&lt;ProductFormFeature&gt;
+&lt;ProductFormFeatureType&gt;07&lt;/ProductFormFeatureType&gt;
+&lt;ProductFormFeatureValue&gt;on-site&lt;/ProductFormFeatureValue&gt;
+&lt;ProductFormFeatureDescription&gt;PNBONLINE04&lt;/ProductFormFeatureDescription&gt;
+&lt;/ProductFormFeature&gt;
+&lt;EpubTechnicalProtection&gt;03&lt;/EpubTechnicalProtection&gt;
+&lt;EpubUsageConstraint&gt;
+&lt;EpubUsageType&gt;02&lt;/EpubUsageType&gt;
+&lt;EpubUsageStatus&gt;03&lt;/EpubUsageStatus&gt;
+&lt;/EpubUsageConstraint&gt;
+&lt;EpubUsageConstraint&gt;
+&lt;EpubUsageType&gt;03&lt;/EpubUsageType&gt;
+&lt;EpubUsageStatus&gt;03&lt;/EpubUsageStatus&gt;
+&lt;/EpubUsageConstraint&gt;
+&lt;EpubUsageConstraint&gt;
+&lt;EpubUsageType&gt;04&lt;/EpubUsageType&gt;
+&lt;EpubUsageStatus&gt;02&lt;/EpubUsageStatus&gt;
+&lt;EpubUsageLimit&gt;
+&lt;Quantity&gt;6&lt;/Quantity&gt;
+&lt;EpubUsageUnit&gt;06&lt;/EpubUsageUnit&gt;
+&lt;/EpubUsageLimit&gt;
+&lt;/EpubUsageConstraint&gt;
+&lt;EpubUsageConstraint&gt;
+&lt;EpubUsageType&gt;06&lt;/EpubUsageType&gt;
+&lt;EpubUsageStatus&gt;02&lt;/EpubUsageStatus&gt;
+&lt;EpubUsageLimit&gt;
+&lt;Quantity&gt;59&lt;/Quantity&gt;
+&lt;EpubUsageUnit&gt;09&lt;/EpubUsageUnit&gt;
+&lt;/EpubUsageLimit&gt;
+&lt;EpubUsageLimit&gt;
+&lt;Quantity&gt;30&lt;/Quantity&gt;
+&lt;EpubUsageUnit&gt;10&lt;/EpubUsageUnit&gt;
+&lt;/EpubUsageLimit&gt;
+&lt;EpubUsageLimit&gt;
+&lt;Quantity&gt;10&lt;/Quantity&gt;
+&lt;EpubUsageUnit&gt;07&lt;/EpubUsageUnit&gt;
+&lt;/EpubUsageLimit&gt;
+&lt;/EpubUsageConstraint&gt;
+&lt;EpubUsageConstraint&gt;
+&lt;EpubUsageType&gt;07&lt;/EpubUsageType&gt;
+&lt;EpubUsageStatus&gt;02&lt;/EpubUsageStatus&gt;
+&lt;EpubUsageLimit&gt;
+&lt;Quantity&gt;2190&lt;/Quantity&gt;
+&lt;EpubUsageUnit&gt;09&lt;/EpubUsageUnit&gt;
+&lt;/EpubUsageLimit&gt;
+&lt;/EpubUsageConstraint&gt;
+&lt;EpubUsageConstraint&gt;
+&lt;EpubUsageType&gt;04&lt;/EpubUsageType&gt;
+&lt;EpubUsageStatus&gt;02&lt;/EpubUsageStatus&gt;
+&lt;EpubUsageLimit&gt;
+&lt;Quantity&gt;10&lt;/Quantity&gt;
+&lt;EpubUsageUnit&gt;07&lt;/EpubUsageUnit&gt;
+&lt;/EpubUsageLimit&gt;
+&lt;/EpubUsageConstraint&gt;
+&lt;Collection&gt;
+&lt;CollectionType&gt;10&lt;/CollectionType&gt;
+&lt;TitleDetail&gt;
+&lt;TitleType&gt;01&lt;/TitleType&gt;
+&lt;TitleElement&gt;
+&lt;TitleElementLevel&gt;02&lt;/TitleElementLevel&gt;
+&lt;TitleText&gt;Librio&lt;/TitleText&gt;
+&lt;/TitleElement&gt;
+&lt;/TitleDetail&gt;
+&lt;/Collection&gt;
+&lt;TitleDetail&gt;
+&lt;TitleType&gt;01&lt;/TitleType&gt;
+&lt;TitleElement&gt;
+&lt;TitleElementLevel&gt;01&lt;/TitleElementLevel&gt;
+&lt;TitleText&gt;La Reine des Neiges&lt;/TitleText&gt;
+&lt;/TitleElement&gt;
+&lt;/TitleDetail&gt;
+&lt;Contributor&gt;
+&lt;SequenceNumber&gt;1&lt;/SequenceNumber&gt;
+&lt;ContributorRole&gt;A01&lt;/ContributorRole&gt;
+&lt;PersonName&gt;Hans Christian Andersen&lt;/PersonName&gt;
+&lt;PersonNameInverted&gt;Andersen, Hans Christian&lt;/PersonNameInverted&gt;
+&lt;NamesBeforeKey&gt;Hans Christian&lt;/NamesBeforeKey&gt;
+&lt;KeyNames&gt;Andersen&lt;/KeyNames&gt;
+&lt;BiographicalNote/&gt;
+&lt;ContributorPlace&gt;
+&lt;ContributorPlaceRelator&gt;08&lt;/ContributorPlaceRelator&gt;
+&lt;CountryCode&gt;DK&lt;/CountryCode&gt;
+&lt;/ContributorPlace&gt;
+&lt;/Contributor&gt;
+&lt;Contributor&gt;
+&lt;SequenceNumber&gt;2&lt;/SequenceNumber&gt;
+&lt;ContributorRole&gt;B06&lt;/ContributorRole&gt;
+&lt;PersonName&gt;David Soldi&lt;/PersonName&gt;
+&lt;PersonNameInverted&gt;Soldi, David&lt;/PersonNameInverted&gt;
+&lt;NamesBeforeKey&gt;David&lt;/NamesBeforeKey&gt;
+&lt;KeyNames&gt;Soldi&lt;/KeyNames&gt;
+&lt;BiographicalNote/&gt;
+&lt;ContributorPlace&gt;
+&lt;ContributorPlaceRelator&gt;08&lt;/ContributorPlaceRelator&gt;
+&lt;CountryCode&gt;FR&lt;/CountryCode&gt;
+&lt;/ContributorPlace&gt;
+&lt;/Contributor&gt;
+&lt;Contributor&gt;
+&lt;SequenceNumber&gt;3&lt;/SequenceNumber&gt;
+&lt;ContributorRole&gt;B06&lt;/ContributorRole&gt;
+&lt;PersonName&gt;Ernest Grégoire&lt;/PersonName&gt;
+&lt;PersonNameInverted&gt;Grégoire, Ernest&lt;/PersonNameInverted&gt;
+&lt;NamesBeforeKey&gt;Ernest&lt;/NamesBeforeKey&gt;
+&lt;KeyNames&gt;Grégoire&lt;/KeyNames&gt;
+&lt;BiographicalNote/&gt;
+&lt;ContributorPlace&gt;
+&lt;ContributorPlaceRelator&gt;08&lt;/ContributorPlaceRelator&gt;
+&lt;CountryCode&gt;FR&lt;/CountryCode&gt;
+&lt;/ContributorPlace&gt;
+&lt;/Contributor&gt;
+&lt;Contributor&gt;
+&lt;SequenceNumber&gt;4&lt;/SequenceNumber&gt;
+&lt;ContributorRole&gt;B06&lt;/ContributorRole&gt;
+&lt;PersonName&gt;Louis Moland&lt;/PersonName&gt;
+&lt;PersonNameInverted&gt;Moland, Louis&lt;/PersonNameInverted&gt;
+&lt;NamesBeforeKey&gt;Louis&lt;/NamesBeforeKey&gt;
+&lt;KeyNames&gt;Moland&lt;/KeyNames&gt;
+&lt;BiographicalNote/&gt;
+&lt;ContributorPlace&gt;
+&lt;ContributorPlaceRelator&gt;08&lt;/ContributorPlaceRelator&gt;
+&lt;CountryCode&gt;FR&lt;/CountryCode&gt;
+&lt;/ContributorPlace&gt;
+&lt;/Contributor&gt;
+&lt;NoEdition/&gt;
+&lt;Language&gt;
+&lt;LanguageRole&gt;01&lt;/LanguageRole&gt;
+&lt;LanguageCode&gt;fre&lt;/LanguageCode&gt;
+&lt;/Language&gt;
+&lt;Language&gt;
+&lt;LanguageRole&gt;02&lt;/LanguageRole&gt;
+&lt;LanguageCode&gt;dan&lt;/LanguageCode&gt;
+&lt;/Language&gt;
+&lt;Extent&gt;
+&lt;ExtentType&gt;22&lt;/ExtentType&gt;
+&lt;ExtentValue&gt;1.13&lt;/ExtentValue&gt;
+&lt;ExtentUnit&gt;19&lt;/ExtentUnit&gt;
+&lt;/Extent&gt;
+&lt;Extent&gt;
+&lt;ExtentType&gt;00&lt;/ExtentType&gt;
+&lt;ExtentValue&gt;93&lt;/ExtentValue&gt;
+&lt;ExtentUnit&gt;03&lt;/ExtentUnit&gt;
+&lt;/Extent&gt;
+&lt;Subject&gt;
+&lt;SubjectSchemeIdentifier&gt;29&lt;/SubjectSchemeIdentifier&gt;
+&lt;SubjectSchemeVersion&gt;DILICOM20&lt;/SubjectSchemeVersion&gt;
+&lt;SubjectCode&gt;2315&lt;/SubjectCode&gt;
+&lt;SubjectHeadingText&gt;Romans de science-fiction, terreur, épouvante&lt;/SubjectHeadingText&gt;
+&lt;/Subject&gt;
+&lt;Subject&gt;
+&lt;SubjectSchemeIdentifier&gt;29&lt;/SubjectSchemeIdentifier&gt;
+&lt;SubjectSchemeVersion&gt;DILICOM20&lt;/SubjectSchemeVersion&gt;
+&lt;SubjectCode&gt;2311&lt;/SubjectCode&gt;
+&lt;SubjectHeadingText&gt;Romans classiques&lt;/SubjectHeadingText&gt;
+&lt;/Subject&gt;
+&lt;Subject&gt;
+&lt;SubjectSchemeIdentifier&gt;10&lt;/SubjectSchemeIdentifier&gt;
+&lt;SubjectCode&gt;FIC000000&lt;/SubjectCode&gt;
+&lt;/Subject&gt;
+&lt;Subject&gt;
+&lt;MainSubject/&gt;
+&lt;SubjectSchemeIdentifier&gt;10&lt;/SubjectSchemeIdentifier&gt;
+&lt;SubjectCode&gt;FIC004000&lt;/SubjectCode&gt;
+&lt;/Subject&gt;
+&lt;Subject&gt;
+&lt;SubjectSchemeIdentifier&gt;29&lt;/SubjectSchemeIdentifier&gt;
+&lt;SubjectCode&gt;3436&lt;/SubjectCode&gt;
+&lt;SubjectHeadingText&gt;Oeuvres classiques&lt;/SubjectHeadingText&gt;
+&lt;/Subject&gt;
+&lt;Subject&gt;
+&lt;MainSubject/&gt;
+&lt;SubjectSchemeIdentifier&gt;29&lt;/SubjectSchemeIdentifier&gt;
+&lt;SubjectCode&gt;3478&lt;/SubjectCode&gt;
+&lt;SubjectHeadingText&gt;Fantasy, Merveilleux&lt;/SubjectHeadingText&gt;
+&lt;/Subject&gt;
+&lt;Subject&gt;
+&lt;SubjectSchemeIdentifier&gt;20&lt;/SubjectSchemeIdentifier&gt;
+&lt;SubjectHeadingText&gt;miroir déformant; conte fantastique; Kay; Andersen; La Petite Poucette; Les Fleurs de la petite Ida; Les Cygnes sauvages&lt;/SubjectHeadingText&gt;
+&lt;/Subject&gt;
+&lt;Subject&gt;
+&lt;SubjectSchemeIdentifier&gt;29&lt;/SubjectSchemeIdentifier&gt;
+&lt;SubjectSchemeVersion&gt;DILICOM10&lt;/SubjectSchemeVersion&gt;
+&lt;SubjectCode&gt;3435&lt;/SubjectCode&gt;
+&lt;SubjectHeadingText&gt;LITTÉRATURE GÉNÉRALE&lt;/SubjectHeadingText&gt;
+&lt;/Subject&gt;
+&lt;/DescriptiveDetail&gt;
+&lt;CollateralDetail&gt;
+&lt;TextContent&gt;
+&lt;TextType&gt;03&lt;/TextType&gt;
+&lt;ContentAudience&gt;00&lt;/ContentAudience&gt;
+&lt;Text&gt;Lorsque le miroir déformant du diable se brise, des milliers d’éclats se répandent sur la Terre. Quiconque en reçoit un dans l’oeil se met à voir tout en noir, et s’il se fiche dans le coeur, celui-ci se change en bloc de glace, attirant la Reine des Neiges. C’est ce qui arrive au petit Kay, enlevé par la froide souveraine et retenu prisonnier dans son palais. Mais son amie Gerda part à sa recherche, rencontrant en chemin magiciens, brigands et princesses.
+Ce recueil rassemble cinq contes parmi les plus célèbres d’Andersen : La Reine des Neiges, La Petite Poucette, La Cloche, Les Fleurs de la petite Ida et Les Cygnes sauvages, qui entraînent le lecteur dans un univers enchanté qui n’a pas pris une ride.&lt;/Text&gt;
+&lt;/TextContent&gt;
+&lt;SupportingResource&gt;
+&lt;ResourceContentType&gt;01&lt;/ResourceContentType&gt;
+&lt;ContentAudience&gt;00&lt;/ContentAudience&gt;
+&lt;ResourceMode&gt;03&lt;/ResourceMode&gt;
+&lt;ResourceFeature&gt;
+&lt;ResourceFeatureType&gt;02&lt;/ResourceFeatureType&gt;
+&lt;FeatureValue&gt;Couverture principale&lt;/FeatureValue&gt;
+&lt;/ResourceFeature&gt;
+&lt;ResourceVersion&gt;
+&lt;ResourceForm&gt;02&lt;/ResourceForm&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;04&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;front_cover.jpg&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;01&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;D502&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;03&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;600&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;02&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;946&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceLink&gt;https://assets.edenlivres.fr/assets/publications/100287/medias/front_cover.jpg&lt;/ResourceLink&gt;
+&lt;ContentDate&gt;
+&lt;ContentDateRole&gt;17&lt;/ContentDateRole&gt;
+&lt;DateFormat&gt;14&lt;/DateFormat&gt;
+&lt;Date&gt;20150630T151540+0200&lt;/Date&gt;
+&lt;/ContentDate&gt;
+&lt;/ResourceVersion&gt;
+&lt;/SupportingResource&gt;
+&lt;SupportingResource&gt;
+&lt;ResourceContentType&gt;15&lt;/ResourceContentType&gt;
+&lt;ContentAudience&gt;00&lt;/ContentAudience&gt;
+&lt;ResourceMode&gt;04&lt;/ResourceMode&gt;
+&lt;ResourceVersion&gt;
+&lt;ResourceForm&gt;02&lt;/ResourceForm&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;04&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;excerpt.pdf&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;01&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;D401&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceLink&gt;https://assets.edenlivres.fr/assets/publications/100287/medias/excerpt.pdf&lt;/ResourceLink&gt;
+&lt;ContentDate&gt;
+&lt;ContentDateRole&gt;17&lt;/ContentDateRole&gt;
+&lt;DateFormat&gt;14&lt;/DateFormat&gt;
+&lt;Date&gt;20150630T151746+0200&lt;/Date&gt;
+&lt;/ContentDate&gt;
+&lt;/ResourceVersion&gt;
+&lt;/SupportingResource&gt;
+&lt;SupportingResource&gt;
+&lt;ResourceContentType&gt;15&lt;/ResourceContentType&gt;
+&lt;ContentAudience&gt;00&lt;/ContentAudience&gt;
+&lt;ResourceMode&gt;04&lt;/ResourceMode&gt;
+&lt;ResourceVersion&gt;
+&lt;ResourceForm&gt;02&lt;/ResourceForm&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;04&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;excerpt.epub&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;01&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;E101&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceLink&gt;https://assets.edenlivres.fr/assets/publications/100287/medias/excerpt.epub&lt;/ResourceLink&gt;
+&lt;ContentDate&gt;
+&lt;ContentDateRole&gt;17&lt;/ContentDateRole&gt;
+&lt;DateFormat&gt;14&lt;/DateFormat&gt;
+&lt;Date&gt;20150630T151747+0200&lt;/Date&gt;
+&lt;/ContentDate&gt;
+&lt;/ResourceVersion&gt;
+&lt;/SupportingResource&gt;
+&lt;SupportingResource&gt;
+&lt;ResourceContentType&gt;01&lt;/ResourceContentType&gt;
+&lt;ContentAudience&gt;00&lt;/ContentAudience&gt;
+&lt;ResourceMode&gt;03&lt;/ResourceMode&gt;
+&lt;ResourceFeature&gt;
+&lt;ResourceFeatureType&gt;02&lt;/ResourceFeatureType&gt;
+&lt;FeatureValue&gt;front_cover_small&lt;/FeatureValue&gt;
+&lt;/ResourceFeature&gt;
+&lt;ResourceVersion&gt;
+&lt;ResourceForm&gt;02&lt;/ResourceForm&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;04&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;http://assets.edenlivres.fr/assets/publications/100287/cover/small.jpg&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;01&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;D502&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;03&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;65&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceLink&gt;http://assets.edenlivres.fr/assets/publications/100287/cover/small.jpg&lt;/ResourceLink&gt;
+&lt;ContentDate&gt;
+&lt;ContentDateRole&gt;17&lt;/ContentDateRole&gt;
+&lt;DateFormat&gt;14&lt;/DateFormat&gt;
+&lt;Date&gt;20150630T151541+0200&lt;/Date&gt;
+&lt;/ContentDate&gt;
+&lt;/ResourceVersion&gt;
+&lt;/SupportingResource&gt;
+&lt;SupportingResource&gt;
+&lt;ResourceContentType&gt;01&lt;/ResourceContentType&gt;
+&lt;ContentAudience&gt;00&lt;/ContentAudience&gt;
+&lt;ResourceMode&gt;03&lt;/ResourceMode&gt;
+&lt;ResourceFeature&gt;
+&lt;ResourceFeatureType&gt;02&lt;/ResourceFeatureType&gt;
+&lt;FeatureValue&gt;front_cover_medium&lt;/FeatureValue&gt;
+&lt;/ResourceFeature&gt;
+&lt;ResourceVersion&gt;
+&lt;ResourceForm&gt;02&lt;/ResourceForm&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;04&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;http://assets.edenlivres.fr/assets/publications/100287/cover/medium.jpg&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;01&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;D502&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;03&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;200&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceLink&gt;http://assets.edenlivres.fr/assets/publications/100287/cover/medium.jpg&lt;/ResourceLink&gt;
+&lt;ContentDate&gt;
+&lt;ContentDateRole&gt;17&lt;/ContentDateRole&gt;
+&lt;DateFormat&gt;14&lt;/DateFormat&gt;
+&lt;Date&gt;20150630T151541+0200&lt;/Date&gt;
+&lt;/ContentDate&gt;
+&lt;/ResourceVersion&gt;
+&lt;/SupportingResource&gt;
+&lt;SupportingResource&gt;
+&lt;ResourceContentType&gt;01&lt;/ResourceContentType&gt;
+&lt;ContentAudience&gt;00&lt;/ContentAudience&gt;
+&lt;ResourceMode&gt;03&lt;/ResourceMode&gt;
+&lt;ResourceFeature&gt;
+&lt;ResourceFeatureType&gt;02&lt;/ResourceFeatureType&gt;
+&lt;FeatureValue&gt;front_cover_large&lt;/FeatureValue&gt;
+&lt;/ResourceFeature&gt;
+&lt;ResourceVersion&gt;
+&lt;ResourceForm&gt;02&lt;/ResourceForm&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;04&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;http://assets.edenlivres.fr/assets/publications/100287/cover/large.jpg&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;01&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;D502&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;03&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;1000&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceLink&gt;http://assets.edenlivres.fr/assets/publications/100287/cover/large.jpg&lt;/ResourceLink&gt;
+&lt;ContentDate&gt;
+&lt;ContentDateRole&gt;17&lt;/ContentDateRole&gt;
+&lt;DateFormat&gt;14&lt;/DateFormat&gt;
+&lt;Date&gt;20150630T151541+0200&lt;/Date&gt;
+&lt;/ContentDate&gt;
+&lt;/ResourceVersion&gt;
+&lt;/SupportingResource&gt;
+&lt;SupportingResource&gt;
+&lt;ResourceContentType&gt;16&lt;/ResourceContentType&gt;
+&lt;ContentAudience&gt;00&lt;/ContentAudience&gt;
+&lt;ResourceMode&gt;06&lt;/ResourceMode&gt;
+&lt;ResourceVersion&gt;
+&lt;ResourceForm&gt;01&lt;/ResourceForm&gt;
+&lt;ResourceLink&gt;http://www.edenlivres.fr/p/100287&lt;/ResourceLink&gt;
+&lt;/ResourceVersion&gt;
+&lt;/SupportingResource&gt;
+&lt;/CollateralDetail&gt;
+&lt;PublishingDetail&gt;
+&lt;Imprint&gt;
+&lt;ImprintName&gt;J'ai Lu&lt;/ImprintName&gt;
+&lt;/Imprint&gt;
+&lt;Publisher&gt;
+&lt;PublishingRole&gt;01&lt;/PublishingRole&gt;
+&lt;PublisherIdentifier&gt;
+&lt;PublisherIDType&gt;01&lt;/PublisherIDType&gt;
+&lt;IDTypeName&gt;DEMARQUE_ID&lt;/IDTypeName&gt;
+&lt;IDValue&gt;111&lt;/IDValue&gt;
+&lt;/PublisherIdentifier&gt;
+&lt;PublisherIdentifier&gt;
+&lt;PublisherIDType&gt;01&lt;/PublisherIDType&gt;
+&lt;IDTypeName&gt;DM_GLOBAL_ID&lt;/IDTypeName&gt;
+&lt;IDValue&gt;EDEN111&lt;/IDValue&gt;
+&lt;/PublisherIdentifier&gt;
+&lt;PublisherName&gt;J'ai Lu&lt;/PublisherName&gt;
+&lt;Website&gt;
+&lt;WebsiteRole&gt;01&lt;/WebsiteRole&gt;
+&lt;WebsiteLink&gt;http://www.jailu.com/&lt;/WebsiteLink&gt;
+&lt;/Website&gt;
+&lt;/Publisher&gt;
+&lt;PublishingStatus&gt;04&lt;/PublishingStatus&gt;
+&lt;PublishingDate&gt;
+&lt;PublishingDateRole&gt;01&lt;/PublishingDateRole&gt;
+&lt;DateFormat&gt;14&lt;/DateFormat&gt;
+&lt;Date&gt;20150701T000000+0200&lt;/Date&gt;
+&lt;/PublishingDate&gt;
+&lt;PublishingDate&gt;
+&lt;PublishingDateRole&gt;19&lt;/PublishingDateRole&gt;
+&lt;DateFormat&gt;14&lt;/DateFormat&gt;
+&lt;Date&gt;20131120T000000+0100&lt;/Date&gt;
+&lt;/PublishingDate&gt;
+&lt;SalesRights&gt;
+&lt;SalesRightsType&gt;01&lt;/SalesRightsType&gt;
+&lt;Territory&gt;
+&lt;CountriesIncluded&gt;DE AD AT BE BG CY HR ES EE FI FR GR GP GF HU IE IT LV LT LU MT MQ YT MC NL PL PT RE RO SK SI CZ&lt;/CountriesIncluded&gt;
+&lt;/Territory&gt;
+&lt;/SalesRights&gt;
+&lt;SalesRestriction&gt;
+&lt;SalesRestrictionType&gt;06&lt;/SalesRestrictionType&gt;
+&lt;/SalesRestriction&gt;
+&lt;/PublishingDetail&gt;
+&lt;RelatedMaterial&gt;
+&lt;RelatedProduct&gt;
+&lt;ProductRelationCode&gt;13&lt;/ProductRelationCode&gt;
+&lt;ProductIdentifier&gt;
+&lt;ProductIDType&gt;03&lt;/ProductIDType&gt;
+&lt;IDValue&gt;9782290080467&lt;/IDValue&gt;
+&lt;/ProductIdentifier&gt;
+&lt;ProductForm&gt;BA&lt;/ProductForm&gt;
+&lt;/RelatedProduct&gt;
+&lt;RelatedProduct&gt;
+&lt;ProductRelationCode&gt;31&lt;/ProductRelationCode&gt;
+&lt;ProductIdentifier&gt;
+&lt;ProductIDType&gt;03&lt;/ProductIDType&gt;
+&lt;IDValue&gt;9782290121504&lt;/IDValue&gt;
+&lt;/ProductIdentifier&gt;
+&lt;ProductForm&gt;EA&lt;/ProductForm&gt;
+&lt;ProductFormDetail&gt;E101&lt;/ProductFormDetail&gt;
+&lt;ProductFormDetail&gt;E200&lt;/ProductFormDetail&gt;
+&lt;/RelatedProduct&gt;
+&lt;RelatedProduct&gt;
+&lt;ProductRelationCode&gt;06&lt;/ProductRelationCode&gt;
+&lt;ProductIdentifier&gt;
+&lt;ProductIDType&gt;01&lt;/ProductIDType&gt;
+&lt;IDValue&gt;eden-100287-73935-libraries&lt;/IDValue&gt;
+&lt;/ProductIdentifier&gt;
+&lt;ProductForm&gt;EA&lt;/ProductForm&gt;
+&lt;/RelatedProduct&gt;
+&lt;RelatedProduct&gt;
+&lt;ProductRelationCode&gt;06&lt;/ProductRelationCode&gt;
+&lt;ProductIdentifier&gt;
+&lt;ProductIDType&gt;01&lt;/ProductIDType&gt;
+&lt;IDValue&gt;eden-100287-73938-libraries&lt;/IDValue&gt;
+&lt;/ProductIdentifier&gt;
+&lt;ProductForm&gt;EA&lt;/ProductForm&gt;
+&lt;/RelatedProduct&gt;
+&lt;/RelatedMaterial&gt;
+&lt;/Product&gt;
+&lt;/ONIXMessage&gt;</notice>
+    <orderLine>
+        <orderId>FBKS1971</orderId>
+        <orderIdColl>LIBFBKS1971</orderIdColl>
+        <orderLineId>559fa8aa975a0323f994c5f8</orderLineId>
+        <orderDate>2015-07-10T13:12:43.792+02:00</orderDate>
+        <ean13>9782290123409</ean13>
+        <quantity>1</quantity>
+        <usage>
+            <loanTerms>
+                <loanMaxDuration>
+                    <value>59</value>
+                    <unit>DAY</unit>
+                </loanMaxDuration>
+                <nbLoans>30</nbLoans>
+                <loanNbSimultaneousUsers>10</loanNbSimultaneousUsers>
+                <consultNbSimultaneousUsersInSitu>10</consultNbSimultaneousUsersInSitu>
+                <consultNbSimultaneousUsersExSitu>0</consultNbSimultaneousUsersExSitu>
+            </loanTerms>
+            <userRights>
+                <printing>PROHIBITED</printing>
+                <copyAndPaste>PROHIBITED</copyAndPaste>
+                <nbAllowedDevices>6</nbAllowedDevices>
+            </userRights>
+            <collRights>
+                <offerValidity>
+                    <value>2190</value>
+                    <unit>DAY</unit>
+                </offerValidity>
+            </collRights>
+        </usage>
+        <returnStatus>OK</returnStatus>
+    </orderLine>
+</offer>
+<offer>
+    <notice>&lt;?xml version="1.0" encoding="UTF-8"?&gt;&lt;ONIXMessage release="3.0" xmlns="http://www.editeur.org/onix/3.0/reference"&gt;
+&lt;Header&gt;
+&lt;Sender&gt;
+&lt;SenderIdentifier&gt;&lt;SenderIDType&gt;06&lt;/SenderIDType&gt;&lt;IDValue&gt;3025599000108&lt;/IDValue&gt;&lt;/SenderIdentifier&gt;
+&lt;SenderName&gt;SERVEUR DILICOM - PNB NUMERIQUE&lt;/SenderName&gt;&lt;/Sender&gt;
+&lt;Addressee&gt;&lt;AddresseeIdentifier&gt;&lt;AddresseeIDType&gt;06&lt;/AddresseeIDType&gt;&lt;IDValue&gt;3056309900005&lt;/IDValue&gt;&lt;/AddresseeIdentifier&gt;&lt;/Addressee&gt;
+&lt;SentDateTime&gt;20150726T0704Z&lt;/SentDateTime&gt;
+&lt;/Header&gt;
+&lt;Product&gt;
+&lt;RecordReference&gt;EDEN-37170-11182-LIBRARIES&lt;/RecordReference&gt;
+&lt;NotificationType&gt;04&lt;/NotificationType&gt;
+&lt;ProductIdentifier&gt;
+&lt;ProductIDType&gt;03&lt;/ProductIDType&gt;
+&lt;IDValue&gt;9782841117420&lt;/IDValue&gt;
+&lt;/ProductIdentifier&gt;
+&lt;ProductIdentifier&gt;
+&lt;ProductIDType&gt;01&lt;/ProductIDType&gt;
+&lt;IDTypeName&gt;internal_key&lt;/IDTypeName&gt;
+&lt;IDValue&gt;eden-37170-11182-libraries&lt;/IDValue&gt;
+&lt;/ProductIdentifier&gt;
+&lt;DescriptiveDetail&gt;
+&lt;ProductComposition&gt;00&lt;/ProductComposition&gt;
+&lt;ProductForm&gt;EB&lt;/ProductForm&gt;
+&lt;ProductFormDetail&gt;E101&lt;/ProductFormDetail&gt;
+&lt;ProductFormDetail&gt;E200&lt;/ProductFormDetail&gt;
+&lt;ProductFormFeature&gt;
+&lt;ProductFormFeatureType&gt;07&lt;/ProductFormFeatureType&gt;
+&lt;ProductFormFeatureValue&gt;on-site&lt;/ProductFormFeatureValue&gt;
+&lt;ProductFormFeatureDescription&gt;PNBONLINE04&lt;/ProductFormFeatureDescription&gt;
+&lt;/ProductFormFeature&gt;
+&lt;EpubTechnicalProtection&gt;03&lt;/EpubTechnicalProtection&gt;
+&lt;EpubUsageConstraint&gt;
+&lt;EpubUsageType&gt;02&lt;/EpubUsageType&gt;
+&lt;EpubUsageStatus&gt;03&lt;/EpubUsageStatus&gt;
+&lt;/EpubUsageConstraint&gt;
+&lt;EpubUsageConstraint&gt;
+&lt;EpubUsageType&gt;03&lt;/EpubUsageType&gt;
+&lt;EpubUsageStatus&gt;03&lt;/EpubUsageStatus&gt;
+&lt;/EpubUsageConstraint&gt;
+&lt;EpubUsageConstraint&gt;
+&lt;EpubUsageType&gt;04&lt;/EpubUsageType&gt;
+&lt;EpubUsageStatus&gt;02&lt;/EpubUsageStatus&gt;
+&lt;EpubUsageLimit&gt;
+&lt;Quantity&gt;6&lt;/Quantity&gt;
+&lt;EpubUsageUnit&gt;06&lt;/EpubUsageUnit&gt;
+&lt;/EpubUsageLimit&gt;
+&lt;/EpubUsageConstraint&gt;
+&lt;EpubUsageConstraint&gt;
+&lt;EpubUsageType&gt;06&lt;/EpubUsageType&gt;
+&lt;EpubUsageStatus&gt;02&lt;/EpubUsageStatus&gt;
+&lt;EpubUsageLimit&gt;
+&lt;Quantity&gt;59&lt;/Quantity&gt;
+&lt;EpubUsageUnit&gt;09&lt;/EpubUsageUnit&gt;
+&lt;/EpubUsageLimit&gt;
+&lt;EpubUsageLimit&gt;
+&lt;Quantity&gt;30&lt;/Quantity&gt;
+&lt;EpubUsageUnit&gt;10&lt;/EpubUsageUnit&gt;
+&lt;/EpubUsageLimit&gt;
+&lt;EpubUsageLimit&gt;
+&lt;Quantity&gt;30&lt;/Quantity&gt;
+&lt;EpubUsageUnit&gt;07&lt;/EpubUsageUnit&gt;
+&lt;/EpubUsageLimit&gt;
+&lt;/EpubUsageConstraint&gt;
+&lt;EpubUsageConstraint&gt;
+&lt;EpubUsageType&gt;07&lt;/EpubUsageType&gt;
+&lt;EpubUsageStatus&gt;02&lt;/EpubUsageStatus&gt;
+&lt;EpubUsageLimit&gt;
+&lt;Quantity&gt;1095&lt;/Quantity&gt;
+&lt;EpubUsageUnit&gt;09&lt;/EpubUsageUnit&gt;
+&lt;/EpubUsageLimit&gt;
+&lt;/EpubUsageConstraint&gt;
+&lt;EpubUsageConstraint&gt;
+&lt;EpubUsageType&gt;04&lt;/EpubUsageType&gt;
+&lt;EpubUsageStatus&gt;02&lt;/EpubUsageStatus&gt;
+&lt;EpubUsageLimit&gt;
+&lt;Quantity&gt;30&lt;/Quantity&gt;
+&lt;EpubUsageUnit&gt;07&lt;/EpubUsageUnit&gt;
+&lt;/EpubUsageLimit&gt;
+&lt;/EpubUsageConstraint&gt;
+&lt;TitleDetail&gt;
+&lt;TitleType&gt;01&lt;/TitleType&gt;
+&lt;TitleElement&gt;
+&lt;TitleElementLevel&gt;01&lt;/TitleElementLevel&gt;
+&lt;TitleText&gt;Le Cercle littéraire des amateurs d'épluchures de patates&lt;/TitleText&gt;
+&lt;/TitleElement&gt;
+&lt;/TitleDetail&gt;
+&lt;Contributor&gt;
+&lt;SequenceNumber&gt;1&lt;/SequenceNumber&gt;
+&lt;ContributorRole&gt;A01&lt;/ContributorRole&gt;
+&lt;PersonName&gt;Annie BARROWS&lt;/PersonName&gt;
+&lt;PersonNameInverted&gt;BARROWS, Annie&lt;/PersonNameInverted&gt;
+&lt;NamesBeforeKey&gt;Annie&lt;/NamesBeforeKey&gt;
+&lt;KeyNames&gt;BARROWS&lt;/KeyNames&gt;
+&lt;BiographicalNote&gt; Annie Barrows est née en 1962 à San Diego. Elle est la co-auteur du roman Le Cercle littéraire des amateurs d'épluchures de patates. Nièce de l'auteur principal, Mary Ann Shaffer, elle a assuré le retravail du manuscrit à la place de sa tante lorsque la santé de celle-ci ne lui permit plus de travailler son texte. &lt;/BiographicalNote&gt;
+&lt;/Contributor&gt;
+&lt;Contributor&gt;
+&lt;SequenceNumber&gt;2&lt;/SequenceNumber&gt;
+&lt;ContributorRole&gt;A01&lt;/ContributorRole&gt;
+&lt;PersonName&gt;Mary Ann SHAFFER&lt;/PersonName&gt;
+&lt;PersonNameInverted&gt;SHAFFER, Mary Ann&lt;/PersonNameInverted&gt;
+&lt;NamesBeforeKey&gt;Mary Ann&lt;/NamesBeforeKey&gt;
+&lt;KeyNames&gt;SHAFFER&lt;/KeyNames&gt;
+&lt;BiographicalNote&gt;Mary Ann Shaffer est née en 1934 en Virginie-Occidentale. C'est lors d'un séjour à Londres, en 1976, qu'elle commence à s'intéresser à Guernesey. Sur un coup de tête, elle prend l'avion pour gagner cette petite île oubliée où elle reste coincée à cause d'un épais brouillard. Elle se plonge alors dans un ouvrage sur Jersey qu'elle dévore : ainsi naît fascination pour les îles anglo-normandes. Des années plus tard, encouragée à écrire un livre par son propre cercle littéraire, Mary Ann Shaffer pense naturellement à Guernesey. Le Cercle littéraire des amateurs d'épluchures de patates est son premier roman, écrit avec sa nièce, Annie Barrows, elle-même auteur de livres pour enfants. Mary Ann Shaffer est malheureusement décédée en février 2008 – peu de temps après avoir su que son livre allait être publié et traduit en plusieurs langues.&lt;/BiographicalNote&gt;
+&lt;/Contributor&gt;
+&lt;Contributor&gt;
+&lt;SequenceNumber&gt;3&lt;/SequenceNumber&gt;
+&lt;ContributorRole&gt;B06&lt;/ContributorRole&gt;
+&lt;PersonName&gt;Aline AZOULAY-PAVCON&lt;/PersonName&gt;
+&lt;PersonNameInverted&gt;AZOULAY-PAVCON, Aline&lt;/PersonNameInverted&gt;
+&lt;NamesBeforeKey&gt;Aline&lt;/NamesBeforeKey&gt;
+&lt;KeyNames&gt;AZOULAY-PAVCON&lt;/KeyNames&gt;
+&lt;BiographicalNote/&gt;
+&lt;/Contributor&gt;
+&lt;Language&gt;
+&lt;LanguageRole&gt;01&lt;/LanguageRole&gt;
+&lt;LanguageCode&gt;fre&lt;/LanguageCode&gt;
+&lt;/Language&gt;
+&lt;Extent&gt;
+&lt;ExtentType&gt;22&lt;/ExtentType&gt;
+&lt;ExtentValue&gt;3.86&lt;/ExtentValue&gt;
+&lt;ExtentUnit&gt;19&lt;/ExtentUnit&gt;
+&lt;/Extent&gt;
+&lt;Subject&gt;
+&lt;SubjectSchemeIdentifier&gt;29&lt;/SubjectSchemeIdentifier&gt;
+&lt;SubjectSchemeVersion&gt;DILICOM20&lt;/SubjectSchemeVersion&gt;
+&lt;SubjectCode&gt;2312&lt;/SubjectCode&gt;
+&lt;SubjectHeadingText&gt;Romans contemporains&lt;/SubjectHeadingText&gt;
+&lt;/Subject&gt;
+&lt;Subject&gt;
+&lt;MainSubject/&gt;
+&lt;SubjectSchemeIdentifier&gt;29&lt;/SubjectSchemeIdentifier&gt;
+&lt;SubjectCode&gt;3444&lt;/SubjectCode&gt;
+&lt;SubjectHeadingText&gt;Romans étrangers&lt;/SubjectHeadingText&gt;
+&lt;/Subject&gt;
+&lt;Subject&gt;
+&lt;SubjectSchemeIdentifier&gt;20&lt;/SubjectSchemeIdentifier&gt;
+&lt;SubjectHeadingText&gt;Roman anglo-américain&lt;/SubjectHeadingText&gt;
+&lt;/Subject&gt;
+&lt;Audience&gt;
+&lt;AudienceCodeType&gt;01&lt;/AudienceCodeType&gt;
+&lt;AudienceCodeValue&gt;01&lt;/AudienceCodeValue&gt;
+&lt;/Audience&gt;
+&lt;/DescriptiveDetail&gt;
+&lt;CollateralDetail&gt;
+&lt;TextContent&gt;
+&lt;TextType&gt;03&lt;/TextType&gt;
+&lt;ContentAudience&gt;00&lt;/ContentAudience&gt;
+&lt;Text&gt;&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;" Je me demande comment cet ouvrage est arrivé à Guernesey. Peut-être les livres possèdent-ils un instinct de préservation secret qui les guide jusqu'à leur lecteur idéal... " &amp;lt;/em&amp;gt;&amp;lt;br/&amp;gt; Janvier 1946. Tandis que Londres se relève douloureusement de la guerre, Juliet, jeune écrivain, cherche un sujet pour son prochain roman. Comment pourrait-elle imaginer que la lettre d'un inconnu, natif de l'île de Guernesey, va le lui fournir ? Au fil de ses échanges avec son nouveau correspondant, Juliet pénètre un monde insoupçonné, délicieusement excentrique ; celui d'un club de lecture au nom étrange inventé pour tromper l'occupant allemand : le " Cercle littéraire des amateurs d'épluchures de patates ". De lettre en lettre, Juliet découvre l'histoire d'une petite communauté débordante de charme, d'humour, d'humanité. Et puis vient le jour où, à son tour, elle se rend à Guernesey...&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;Fantasque, drôle, tendre et incroyablement attachant...&amp;lt;br/&amp;gt; Bienvenue dans &amp;lt;em&amp;gt;Le Cercle littéraire des amateurs d'épluchures de patates&amp;lt;/em&amp;gt; !&amp;lt;/b&amp;gt;&amp;lt;/p&amp;gt;&lt;/Text&gt;
+&lt;/TextContent&gt;
+&lt;TextContent&gt;
+&lt;TextType&gt;12&lt;/TextType&gt;
+&lt;ContentAudience&gt;00&lt;/ContentAudience&gt;
+&lt;Text&gt;&amp;lt;p&amp;gt;Mary Ann Shaffer est née en 1934 en Virginie-Occidentale. C'est lors d'un séjour à Londres, en 1976, qu'elle commence à s'intéresser à Guernesey. Sur un coup de tête, elle prend l'avion pour gagner cette petite île oubliée où elle reste coincée à cause d'un épais brouillard. Elle se plonge alors dans un ouvrage sur Jersey qu'elle dévore : ainsi naît fascination pour les îles anglo-normandes. Des années plus tard, encouragée à écrire un livre par son propre cercle littéraire, Mary Ann Shaffer pense naturellement à Guernesey. &amp;lt;em&amp;gt;Le Cercle littéraire des amateurs d'épluchures de patates&amp;lt;/em&amp;gt; est son premier roman, écrit avec sa nièce, Annie Barrows, elle-même auteur de livres pour enfants. Mary Ann Shaffer est malheureusement décédée en février 2008 – peu de temps après avoir su que son livre allait être publié et traduit en plusieurs langues.&amp;lt;/p&amp;gt;
+&amp;lt;p&amp;gt;&amp;lt;/p&amp;gt;&lt;/Text&gt;
+&lt;/TextContent&gt;
+&lt;TextContent&gt;
+&lt;TextType&gt;04&lt;/TextType&gt;
+&lt;ContentAudience&gt;00&lt;/ContentAudience&gt;
+&lt;Text&gt;&amp;lt;p&amp;gt;&amp;lt;b&amp;gt;RÉSUMÉ&amp;lt;/b&amp;gt;&amp;lt;/p&amp;gt;
+&amp;lt;p&amp;gt;&amp;lt;/p&amp;gt;
+&amp;lt;p&amp;gt;Londres, 1946. Juliet Ashton est une auteure célibataire de trente-trois ans qui s'est fait connaître grâce à sa rubrique humoristique dans un journal. Ses chroniques de guerre ont connu un tel succès qu'elles ont été rassemblées en un recueil, &amp;lt;i&amp;gt;Izzy s'en va-t'en guerre&amp;lt;/i&amp;gt;, publié par la maison d'édition dont son ami Sydney est le directeur. Sa vie s'écoule au rythme de sa correspondance avec son amie de toujours, Sophie, sœur de Sydney, expatriée en Écosse, et de ses rendez-vous avec Sydney, qu'elle aime comme un frère. Mais en dépit de son indéniable réussite, Juliet vit des jours moroses : l'état de Londres qui a subi les bombardements allemands, la destruction de son propre appartement et sa difficulté à trouver un sujet pour son prochain livre sont autant de préoccupations qui reviennent dans ses lettres. Brièvement fiancée à un officier mort depuis au combat, elle se sent seule. &amp;lt;br/&amp;gt;Elle reçoit alors la lettre d'un inconnu, Dawsey Adams, qui vit sur l'île de Guernesey : il lui explique qu'il a découvert son nom et son adresse griffonnés sur un livre de Charles Lamb, acheté d'occasion, et qu'il aimerait avoir de plus amples informations sur cet auteur. Il lui parle également d'une société littéraire au nom étrange née sur l'île pendant l'occupation nazie, le " Cercle littéraire des amateurs d'épluchures de patates ", dont il fait partie... C'est le début d'une correspondance abondante entre Juliet et Dawsey, qui s'étend peu à peu à tous les membres du " club ". Dans le même temps, Juliet fait la connaissance d'un riche Américain, Markham V. Reynolds Junior, qui lui fait la cour avec acharnement. Mais l'esprit et le cœur de Juliet sont ailleurs : dévorée par l'envie de rencontrer les personnages haut en couleur de ce mystérieux club qu'elle a appris à connaître, elle décide de partir à Guernesey. Une idée a en effet germé dans son esprit d'écrivain : et si elle consacrait son prochain livre à cette île et à cette surprenante société littéraire ? &amp;lt;br/&amp;gt;Sur place, Juliet rencontre enfin Dawsey, fermier taciturne et calme, mais aussi le vieil Eben et son petit-fils Eli, Amelia, la directrice du cercle, et Kit, fillette de quatre ans dont la mère, Elizabeth, a été déportée par les nazis et dont on demeure sans nouvelles. Kit est élevée tour à tour par les membres du Cercle, qui forment comme une grande famille. Installée chez Elizabeth, Juliet trouve rapidement sa place parmi eux. Elle comprend bientôt que c'est cette absente, dont la mort est hélas confirmée, qui se trouve au cœur de leur histoire à tous, et décide de faire d'Elizabeth le personnage principal de son livre. &amp;lt;br/&amp;gt;Après plusieurs malentendus, Juliet et Dawsey se révèlent enfin leur amour et Juliet, après avoir refusé à Markham sa proposition de mariage, demande à Dawsey de l'épouser. Elle s'installe alors définitivement à Guernesey, avec son mari et Kit, qu'ils élèvent comme leur fille. &amp;lt;/p&amp;gt;
+&amp;lt;p&amp;gt;&amp;lt;/p&amp;gt;&lt;/Text&gt;
+&lt;/TextContent&gt;
+&lt;TextContent&gt;
+&lt;TextType&gt;05&lt;/TextType&gt;
+&lt;ContentAudience&gt;00&lt;/ContentAudience&gt;
+&lt;Text&gt;&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;" Je me demande comment cet ouvrage est arrivé à Guernesey. Peut-être les livres possèdent-ils un instinct de préservation secret qui les guide jusqu'à leur lecteur idéal... " &amp;lt;/em&amp;gt;&amp;lt;br/&amp;gt; Janvier 1946. Tandis que Londres se relève douloureusement de la guerre, Juliet, jeune écrivain, cherche un sujet pour son prochain roman. Comment pourrait-elle imaginer que la lettre d'un inconnu, natif de l'île de Guernesey, va le lui fournir ? Au fil de ses échanges avec son nouveau correspondant, Juliet pénètre un monde insoupçonné, délicieusement excentrique ; celui d'un club de lecture au nom étrange inventé pour tromper l'occupant allemand : le " Cercle littéraire des amateurs d'épluchures de patates ". De lettre en lettre, Juliet découvre l'histoire d'une petite communauté débordante de charme, d'humour, d'humanité. Et puis vient le jour où, à son tour, elle se rend à Guernesey...&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;Fantasque, drôle, tendre et incroyablement attachant...&amp;lt;br/&amp;gt; Bienvenue dans &amp;lt;em&amp;gt;Le Cercle littéraire des amateurs d'épluchures de patates&amp;lt;/em&amp;gt; !&amp;lt;/b&amp;gt;&amp;lt;/p&amp;gt;&lt;/Text&gt;
+&lt;/TextContent&gt;
+&lt;SupportingResource&gt;
+&lt;ResourceContentType&gt;15&lt;/ResourceContentType&gt;
+&lt;ContentAudience&gt;00&lt;/ContentAudience&gt;
+&lt;ResourceMode&gt;04&lt;/ResourceMode&gt;
+&lt;ResourceVersion&gt;
+&lt;ResourceForm&gt;02&lt;/ResourceForm&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;04&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;excerpt.epub&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;01&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;E101&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceLink&gt;https://assets.edenlivres.fr/assets/publications/37170/medias/excerpt.epub&lt;/ResourceLink&gt;
+&lt;ContentDate&gt;
+&lt;ContentDateRole&gt;17&lt;/ContentDateRole&gt;
+&lt;DateFormat&gt;14&lt;/DateFormat&gt;
+&lt;Date&gt;20140224T125846+0100&lt;/Date&gt;
+&lt;/ContentDate&gt;
+&lt;/ResourceVersion&gt;
+&lt;/SupportingResource&gt;
+&lt;SupportingResource&gt;
+&lt;ResourceContentType&gt;01&lt;/ResourceContentType&gt;
+&lt;ContentAudience&gt;00&lt;/ContentAudience&gt;
+&lt;ResourceMode&gt;03&lt;/ResourceMode&gt;
+&lt;ResourceFeature&gt;
+&lt;ResourceFeatureType&gt;02&lt;/ResourceFeatureType&gt;
+&lt;FeatureValue&gt;Couverture principale&lt;/FeatureValue&gt;
+&lt;/ResourceFeature&gt;
+&lt;ResourceVersion&gt;
+&lt;ResourceForm&gt;02&lt;/ResourceForm&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;04&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;front_cover.jpg&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;01&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;D502&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;03&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;1018&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;02&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;1600&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceLink&gt;https://assets.edenlivres.fr/assets/publications/37170/medias/front_cover.jpg&lt;/ResourceLink&gt;
+&lt;ContentDate&gt;
+&lt;ContentDateRole&gt;17&lt;/ContentDateRole&gt;
+&lt;DateFormat&gt;14&lt;/DateFormat&gt;
+&lt;Date&gt;20140224T130018+0100&lt;/Date&gt;
+&lt;/ContentDate&gt;
+&lt;/ResourceVersion&gt;
+&lt;/SupportingResource&gt;
+&lt;SupportingResource&gt;
+&lt;ResourceContentType&gt;01&lt;/ResourceContentType&gt;
+&lt;ContentAudience&gt;00&lt;/ContentAudience&gt;
+&lt;ResourceMode&gt;03&lt;/ResourceMode&gt;
+&lt;ResourceFeature&gt;
+&lt;ResourceFeatureType&gt;02&lt;/ResourceFeatureType&gt;
+&lt;FeatureValue&gt;front_cover_small&lt;/FeatureValue&gt;
+&lt;/ResourceFeature&gt;
+&lt;ResourceVersion&gt;
+&lt;ResourceForm&gt;02&lt;/ResourceForm&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;04&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;http://assets.edenlivres.fr/assets/publications/37170/cover/small.jpg&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;01&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;D502&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;03&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;65&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceLink&gt;http://assets.edenlivres.fr/assets/publications/37170/cover/small.jpg&lt;/ResourceLink&gt;
+&lt;ContentDate&gt;
+&lt;ContentDateRole&gt;17&lt;/ContentDateRole&gt;
+&lt;DateFormat&gt;14&lt;/DateFormat&gt;
+&lt;Date&gt;20150401T085104+0200&lt;/Date&gt;
+&lt;/ContentDate&gt;
+&lt;/ResourceVersion&gt;
+&lt;/SupportingResource&gt;
+&lt;SupportingResource&gt;
+&lt;ResourceContentType&gt;01&lt;/ResourceContentType&gt;
+&lt;ContentAudience&gt;00&lt;/ContentAudience&gt;
+&lt;ResourceMode&gt;03&lt;/ResourceMode&gt;
+&lt;ResourceFeature&gt;
+&lt;ResourceFeatureType&gt;02&lt;/ResourceFeatureType&gt;
+&lt;FeatureValue&gt;front_cover_medium&lt;/FeatureValue&gt;
+&lt;/ResourceFeature&gt;
+&lt;ResourceVersion&gt;
+&lt;ResourceForm&gt;02&lt;/ResourceForm&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;04&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;http://assets.edenlivres.fr/assets/publications/37170/cover/medium.jpg&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;01&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;D502&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;03&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;200&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceLink&gt;http://assets.edenlivres.fr/assets/publications/37170/cover/medium.jpg&lt;/ResourceLink&gt;
+&lt;ContentDate&gt;
+&lt;ContentDateRole&gt;17&lt;/ContentDateRole&gt;
+&lt;DateFormat&gt;14&lt;/DateFormat&gt;
+&lt;Date&gt;20150401T085104+0200&lt;/Date&gt;
+&lt;/ContentDate&gt;
+&lt;/ResourceVersion&gt;
+&lt;/SupportingResource&gt;
+&lt;SupportingResource&gt;
+&lt;ResourceContentType&gt;01&lt;/ResourceContentType&gt;
+&lt;ContentAudience&gt;00&lt;/ContentAudience&gt;
+&lt;ResourceMode&gt;03&lt;/ResourceMode&gt;
+&lt;ResourceFeature&gt;
+&lt;ResourceFeatureType&gt;02&lt;/ResourceFeatureType&gt;
+&lt;FeatureValue&gt;front_cover_large&lt;/FeatureValue&gt;
+&lt;/ResourceFeature&gt;
+&lt;ResourceVersion&gt;
+&lt;ResourceForm&gt;02&lt;/ResourceForm&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;04&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;http://assets.edenlivres.fr/assets/publications/37170/cover/large.jpg&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;01&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;D502&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;03&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;1000&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceLink&gt;http://assets.edenlivres.fr/assets/publications/37170/cover/large.jpg&lt;/ResourceLink&gt;
+&lt;ContentDate&gt;
+&lt;ContentDateRole&gt;17&lt;/ContentDateRole&gt;
+&lt;DateFormat&gt;14&lt;/DateFormat&gt;
+&lt;Date&gt;20150401T085104+0200&lt;/Date&gt;
+&lt;/ContentDate&gt;
+&lt;/ResourceVersion&gt;
+&lt;/SupportingResource&gt;
+&lt;SupportingResource&gt;
+&lt;ResourceContentType&gt;16&lt;/ResourceContentType&gt;
+&lt;ContentAudience&gt;00&lt;/ContentAudience&gt;
+&lt;ResourceMode&gt;06&lt;/ResourceMode&gt;
+&lt;ResourceVersion&gt;
+&lt;ResourceForm&gt;01&lt;/ResourceForm&gt;
+&lt;ResourceLink&gt;http://www.edenlivres.fr/p/37170&lt;/ResourceLink&gt;
+&lt;/ResourceVersion&gt;
+&lt;/SupportingResource&gt;
+&lt;/CollateralDetail&gt;
+&lt;PublishingDetail&gt;
+&lt;Imprint&gt;
+&lt;ImprintName&gt;Nil&lt;/ImprintName&gt;
+&lt;/Imprint&gt;
+&lt;Publisher&gt;
+&lt;PublishingRole&gt;01&lt;/PublishingRole&gt;
+&lt;PublisherIdentifier&gt;
+&lt;PublisherIDType&gt;01&lt;/PublisherIDType&gt;
+&lt;IDTypeName&gt;DEMARQUE_ID&lt;/IDTypeName&gt;
+&lt;IDValue&gt;789&lt;/IDValue&gt;
+&lt;/PublisherIdentifier&gt;
+&lt;PublisherIdentifier&gt;
+&lt;PublisherIDType&gt;01&lt;/PublisherIDType&gt;
+&lt;IDTypeName&gt;DM_GLOBAL_ID&lt;/IDTypeName&gt;
+&lt;IDValue&gt;EDEN789&lt;/IDValue&gt;
+&lt;/PublisherIdentifier&gt;
+&lt;PublisherName&gt;ROBERT LAFFONT/BOUQUINS/SEGHER&lt;/PublisherName&gt;
+&lt;/Publisher&gt;
+&lt;PublishingStatus&gt;04&lt;/PublishingStatus&gt;
+&lt;PublishingDate&gt;
+&lt;PublishingDateRole&gt;01&lt;/PublishingDateRole&gt;
+&lt;DateFormat&gt;14&lt;/DateFormat&gt;
+&lt;Date&gt;20120705T000000+0200&lt;/Date&gt;
+&lt;/PublishingDate&gt;
+&lt;SalesRights&gt;
+&lt;SalesRightsType&gt;01&lt;/SalesRightsType&gt;
+&lt;Territory&gt;
+&lt;CountriesIncluded&gt;FR CH BE&lt;/CountriesIncluded&gt;
+&lt;/Territory&gt;
+&lt;/SalesRights&gt;
+&lt;SalesRestriction&gt;
+&lt;SalesRestrictionType&gt;06&lt;/SalesRestrictionType&gt;
+&lt;/SalesRestriction&gt;
+&lt;/PublishingDetail&gt;
+&lt;RelatedMaterial&gt;
+&lt;RelatedProduct&gt;
+&lt;ProductRelationCode&gt;31&lt;/ProductRelationCode&gt;
+&lt;ProductIdentifier&gt;
+&lt;ProductIDType&gt;03&lt;/ProductIDType&gt;
+&lt;IDValue&gt;9782841115921&lt;/IDValue&gt;
+&lt;/ProductIdentifier&gt;
+&lt;ProductForm&gt;EA&lt;/ProductForm&gt;
+&lt;ProductFormDetail&gt;E101&lt;/ProductFormDetail&gt;
+&lt;ProductFormDetail&gt;E200&lt;/ProductFormDetail&gt;
+&lt;/RelatedProduct&gt;
+&lt;RelatedProduct&gt;
+&lt;ProductRelationCode&gt;06&lt;/ProductRelationCode&gt;
+&lt;ProductIdentifier&gt;
+&lt;ProductIDType&gt;01&lt;/ProductIDType&gt;
+&lt;IDValue&gt;eden-37170-89899-libraries&lt;/IDValue&gt;
+&lt;/ProductIdentifier&gt;
+&lt;ProductForm&gt;EA&lt;/ProductForm&gt;
+&lt;/RelatedProduct&gt;
+&lt;/RelatedMaterial&gt;
+&lt;/Product&gt;
+&lt;/ONIXMessage&gt;</notice>
+    <orderLine>
+        <orderId>FBKS1973</orderId>
+        <orderIdColl>LIBFBKS1973</orderIdColl>
+        <orderLineId>55a11444975a0323f994c601</orderLineId>
+        <orderDate>2015-07-11T15:04:05.142+02:00</orderDate>
+        <ean13>9782841117420</ean13>
+        <quantity>1</quantity>
+        <usage>
+            <loanTerms>
+                <loanMaxDuration>
+                    <value>59</value>
+                    <unit>DAY</unit>
+                </loanMaxDuration>
+                <nbLoans>30</nbLoans>
+                <loanNbSimultaneousUsers>30</loanNbSimultaneousUsers>
+                <consultNbSimultaneousUsersInSitu>30</consultNbSimultaneousUsersInSitu>
+                <consultNbSimultaneousUsersExSitu>0</consultNbSimultaneousUsersExSitu>
+            </loanTerms>
+            <userRights>
+                <printing>PROHIBITED</printing>
+                <copyAndPaste>PROHIBITED</copyAndPaste>
+                <nbAllowedDevices>6</nbAllowedDevices>
+            </userRights>
+            <collRights>
+                <offerValidity>
+                    <value>1095</value>
+                    <unit>DAY</unit>
+                </offerValidity>
+            </collRights>
+        </usage>
+        <returnStatus>OK</returnStatus>
+    </orderLine>
+</offer>
+<offer>
+    <notice>&lt;?xml version="1.0" encoding="UTF-8"?&gt;&lt;ONIXMessage release="3.0" xmlns="http://www.editeur.org/onix/3.0/reference"&gt;
+&lt;Header&gt;
+&lt;Sender&gt;
+&lt;SenderIdentifier&gt;&lt;SenderIDType&gt;06&lt;/SenderIDType&gt;&lt;IDValue&gt;3025599000108&lt;/IDValue&gt;&lt;/SenderIdentifier&gt;
+&lt;SenderName&gt;SERVEUR DILICOM - PNB NUMERIQUE&lt;/SenderName&gt;&lt;/Sender&gt;
+&lt;Addressee&gt;&lt;AddresseeIdentifier&gt;&lt;AddresseeIDType&gt;06&lt;/AddresseeIDType&gt;&lt;IDValue&gt;3056309900005&lt;/IDValue&gt;&lt;/AddresseeIdentifier&gt;&lt;/Addressee&gt;
+&lt;SentDateTime&gt;20150726T0704Z&lt;/SentDateTime&gt;
+&lt;/Header&gt;
+&lt;Product&gt;
+&lt;RecordReference&gt;EDEN-30724-51042-LIBRARIES&lt;/RecordReference&gt;
+&lt;NotificationType&gt;04&lt;/NotificationType&gt;
+&lt;ProductIdentifier&gt;
+&lt;ProductIDType&gt;15&lt;/ProductIDType&gt;
+&lt;IDValue&gt;9791021012431&lt;/IDValue&gt;
+&lt;/ProductIdentifier&gt;
+&lt;ProductIdentifier&gt;
+&lt;ProductIDType&gt;01&lt;/ProductIDType&gt;
+&lt;IDTypeName&gt;internal_key&lt;/IDTypeName&gt;
+&lt;IDValue&gt;eden-30724-51042-libraries&lt;/IDValue&gt;
+&lt;/ProductIdentifier&gt;
+&lt;DescriptiveDetail&gt;
+&lt;ProductComposition&gt;00&lt;/ProductComposition&gt;
+&lt;ProductForm&gt;EB&lt;/ProductForm&gt;
+&lt;ProductFormDetail&gt;E101&lt;/ProductFormDetail&gt;
+&lt;ProductFormDetail&gt;E200&lt;/ProductFormDetail&gt;
+&lt;ProductFormFeature&gt;
+&lt;ProductFormFeatureType&gt;07&lt;/ProductFormFeatureType&gt;
+&lt;ProductFormFeatureValue&gt;on-site&lt;/ProductFormFeatureValue&gt;
+&lt;ProductFormFeatureDescription&gt;PNBONLINE04&lt;/ProductFormFeatureDescription&gt;
+&lt;/ProductFormFeature&gt;
+&lt;EpubTechnicalProtection&gt;03&lt;/EpubTechnicalProtection&gt;
+&lt;EpubUsageConstraint&gt;
+&lt;EpubUsageType&gt;02&lt;/EpubUsageType&gt;
+&lt;EpubUsageStatus&gt;03&lt;/EpubUsageStatus&gt;
+&lt;/EpubUsageConstraint&gt;
+&lt;EpubUsageConstraint&gt;
+&lt;EpubUsageType&gt;03&lt;/EpubUsageType&gt;
+&lt;EpubUsageStatus&gt;03&lt;/EpubUsageStatus&gt;
+&lt;/EpubUsageConstraint&gt;
+&lt;EpubUsageConstraint&gt;
+&lt;EpubUsageType&gt;04&lt;/EpubUsageType&gt;
+&lt;EpubUsageStatus&gt;02&lt;/EpubUsageStatus&gt;
+&lt;EpubUsageLimit&gt;
+&lt;Quantity&gt;6&lt;/Quantity&gt;
+&lt;EpubUsageUnit&gt;06&lt;/EpubUsageUnit&gt;
+&lt;/EpubUsageLimit&gt;
+&lt;/EpubUsageConstraint&gt;
+&lt;EpubUsageConstraint&gt;
+&lt;EpubUsageType&gt;06&lt;/EpubUsageType&gt;
+&lt;EpubUsageStatus&gt;02&lt;/EpubUsageStatus&gt;
+&lt;EpubUsageLimit&gt;
+&lt;Quantity&gt;59&lt;/Quantity&gt;
+&lt;EpubUsageUnit&gt;09&lt;/EpubUsageUnit&gt;
+&lt;/EpubUsageLimit&gt;
+&lt;EpubUsageLimit&gt;
+&lt;Quantity&gt;40&lt;/Quantity&gt;
+&lt;EpubUsageUnit&gt;10&lt;/EpubUsageUnit&gt;
+&lt;/EpubUsageLimit&gt;
+&lt;EpubUsageLimit&gt;
+&lt;Quantity&gt;15&lt;/Quantity&gt;
+&lt;EpubUsageUnit&gt;07&lt;/EpubUsageUnit&gt;
+&lt;/EpubUsageLimit&gt;
+&lt;/EpubUsageConstraint&gt;
+&lt;EpubUsageConstraint&gt;
+&lt;EpubUsageType&gt;07&lt;/EpubUsageType&gt;
+&lt;EpubUsageStatus&gt;02&lt;/EpubUsageStatus&gt;
+&lt;EpubUsageLimit&gt;
+&lt;Quantity&gt;1825&lt;/Quantity&gt;
+&lt;EpubUsageUnit&gt;09&lt;/EpubUsageUnit&gt;
+&lt;/EpubUsageLimit&gt;
+&lt;/EpubUsageConstraint&gt;
+&lt;EpubUsageConstraint&gt;
+&lt;EpubUsageType&gt;04&lt;/EpubUsageType&gt;
+&lt;EpubUsageStatus&gt;02&lt;/EpubUsageStatus&gt;
+&lt;EpubUsageLimit&gt;
+&lt;Quantity&gt;9999&lt;/Quantity&gt;
+&lt;EpubUsageUnit&gt;07&lt;/EpubUsageUnit&gt;
+&lt;/EpubUsageLimit&gt;
+&lt;/EpubUsageConstraint&gt;
+&lt;TitleDetail&gt;
+&lt;TitleType&gt;01&lt;/TitleType&gt;
+&lt;TitleElement&gt;
+&lt;TitleElementLevel&gt;01&lt;/TitleElementLevel&gt;
+&lt;TitleText&gt;La Guerre germano-soviétique&lt;/TitleText&gt;
+&lt;Subtitle&gt;1941-1945&lt;/Subtitle&gt;
+&lt;/TitleElement&gt;
+&lt;/TitleDetail&gt;
+&lt;Contributor&gt;
+&lt;SequenceNumber&gt;1&lt;/SequenceNumber&gt;
+&lt;ContributorRole&gt;A01&lt;/ContributorRole&gt;
+&lt;PersonName&gt;Nicolas Bernard&lt;/PersonName&gt;
+&lt;PersonNameInverted&gt;Bernard, Nicolas&lt;/PersonNameInverted&gt;
+&lt;NamesBeforeKey&gt;Nicolas&lt;/NamesBeforeKey&gt;
+&lt;KeyNames&gt;Bernard&lt;/KeyNames&gt;
+&lt;BiographicalNote&gt;Nicolas BERNARD, avocat, est spécialiste de la Deuxième Guerre mondiale et contribue à plusieurs revues d’histoire militaire. Il se consacre également à l’étude et à la réfutation du négationnisme.&lt;/BiographicalNote&gt;
+&lt;ContributorPlace&gt;
+&lt;ContributorPlaceRelator&gt;08&lt;/ContributorPlaceRelator&gt;
+&lt;CountryCode&gt;FR&lt;/CountryCode&gt;
+&lt;/ContributorPlace&gt;
+&lt;/Contributor&gt;
+&lt;NoEdition/&gt;
+&lt;Language&gt;
+&lt;LanguageRole&gt;01&lt;/LanguageRole&gt;
+&lt;LanguageCode&gt;fre&lt;/LanguageCode&gt;
+&lt;/Language&gt;
+&lt;Extent&gt;
+&lt;ExtentType&gt;22&lt;/ExtentType&gt;
+&lt;ExtentValue&gt;7.94&lt;/ExtentValue&gt;
+&lt;ExtentUnit&gt;19&lt;/ExtentUnit&gt;
+&lt;/Extent&gt;
+&lt;Extent&gt;
+&lt;ExtentType&gt;00&lt;/ExtentType&gt;
+&lt;ExtentValue&gt;800&lt;/ExtentValue&gt;
+&lt;ExtentUnit&gt;03&lt;/ExtentUnit&gt;
+&lt;/Extent&gt;
+&lt;Subject&gt;
+&lt;SubjectSchemeIdentifier&gt;29&lt;/SubjectSchemeIdentifier&gt;
+&lt;SubjectSchemeVersion&gt;DILICOM20&lt;/SubjectSchemeVersion&gt;
+&lt;SubjectCode&gt;2340&lt;/SubjectCode&gt;
+&lt;SubjectHeadingText&gt;Reportages, actualités, documents&lt;/SubjectHeadingText&gt;
+&lt;/Subject&gt;
+&lt;Subject&gt;
+&lt;SubjectSchemeIdentifier&gt;29&lt;/SubjectSchemeIdentifier&gt;
+&lt;SubjectSchemeVersion&gt;DILICOM20&lt;/SubjectSchemeVersion&gt;
+&lt;SubjectCode&gt;2110&lt;/SubjectCode&gt;
+&lt;SubjectHeadingText&gt;Histoire&lt;/SubjectHeadingText&gt;
+&lt;/Subject&gt;
+&lt;Subject&gt;
+&lt;SubjectSchemeIdentifier&gt;10&lt;/SubjectSchemeIdentifier&gt;
+&lt;SubjectCode&gt;HIS000000&lt;/SubjectCode&gt;
+&lt;/Subject&gt;
+&lt;Subject&gt;
+&lt;MainSubject/&gt;
+&lt;SubjectSchemeIdentifier&gt;10&lt;/SubjectSchemeIdentifier&gt;
+&lt;SubjectCode&gt;SOC041000&lt;/SubjectCode&gt;
+&lt;/Subject&gt;
+&lt;Subject&gt;
+&lt;MainSubject/&gt;
+&lt;SubjectSchemeIdentifier&gt;29&lt;/SubjectSchemeIdentifier&gt;
+&lt;SubjectCode&gt;3377&lt;/SubjectCode&gt;
+&lt;SubjectHeadingText&gt;HISTOIRE&lt;/SubjectHeadingText&gt;
+&lt;/Subject&gt;
+&lt;Subject&gt;
+&lt;SubjectSchemeIdentifier&gt;29&lt;/SubjectSchemeIdentifier&gt;
+&lt;SubjectCode&gt;3644&lt;/SubjectCode&gt;
+&lt;SubjectHeadingText&gt;Actualités, Reportages&lt;/SubjectHeadingText&gt;
+&lt;/Subject&gt;
+&lt;Subject&gt;
+&lt;SubjectSchemeIdentifier&gt;20&lt;/SubjectSchemeIdentifier&gt;
+&lt;SubjectHeadingText&gt;Tallandier; Epub; numérique; guerre; Russie; Allemagne; nazi; URSS; Barbarossa; Moscou; Hitler; Staline; juif; Kersaudy; Stalingrad&lt;/SubjectHeadingText&gt;
+&lt;/Subject&gt;
+&lt;/DescriptiveDetail&gt;
+&lt;CollateralDetail&gt;
+&lt;TextContent&gt;
+&lt;TextType&gt;03&lt;/TextType&gt;
+&lt;ContentAudience&gt;00&lt;/ContentAudience&gt;
+&lt;Text&gt;22 juin 1941. Violant le pacte de non-agression conclu le 23 août 1939, l’Allemagne nazie envahit l’URSS. S’ouvre alors une guerre aussi colossale qu’inexpiable, qui fauchera plus de trente millions de personnes, soit la moitié des pertes causées par la Deuxième Guerre mondiale. 
+
+S’appuyant sur une ample documentation russe, allemande, anglo-saxonne, et s’affranchissant de plusieurs idées reçues, cette vaste fresque nous entraîne de « Barbarossa » à Moscou, de Stalingrad à Koursk, de la reconquête soviétique à la chute de Budapest et de Berlin, nous plongeant au cœur des opérations et des doctrines militaires dont elles procèdent. 
+L’auteur déchiffre les calculs de Hitler et de Staline, mais fait aussi une large part aux péripéties diplomatiques, à la dimension économique de l’affrontement, au déchaînement de violence qu’il génère, notamment la « Shoah par balles » qui se traduira par l’assassinat de plus d’un million trois cent mille juifs soviétiques par les nazis. Sans oublier le vécu des obscurs et des sans-grades, « matériel humain » d’une guerre totale et absolue. 
+
+« Ce que le lecteur retiendra, c’est la remarquable objectivité avec laquelle Nicolas Bernard traite les questions les plus délicates posées par cet affrontement titanesque entre deux tyrans, deux idéologies mortifères et deux peuples engagés malgré eux dans une guerre d’extermination. Même si certaines archives restent fermées à la recherche, il faudra sans doute bien des années avant qu’une œuvre aussi magistrale puisse être considérée comme dépassée. »
+
+François Kersaudy&lt;/Text&gt;
+&lt;/TextContent&gt;
+&lt;TextContent&gt;
+&lt;TextType&gt;02&lt;/TextType&gt;
+&lt;ContentAudience&gt;00&lt;/ContentAudience&gt;
+&lt;Text&gt;22 juin 1941. Violant le pacte de non-agression conclu le 23 août 1939, l’Allemagne nazie envahit l’URSS. S’ouvre alors une guerre aussi colossale qu’inexpiable, qui fauchera plus de trente millions de personnes, soit la moitié des pertes causées par la Deuxième Guerre mondiale. 
+
+S’appuyant sur une ample documentation russe, allemande, anglo-saxonne, et s’affranchissant de plusieurs idées reçues, cette vaste fresque nous entraîne de « Barbarossa » à Moscou, de Stalingrad à Koursk, de la reconquête soviétique à la chute de Budapest et de Berlin, nous plongeant au cœur des opérations et des doctrines militaires dont elles procèdent. 
+L’auteur déchiffre les calculs de Hitler et de Staline, mais fait aussi une large part aux péripéties diplomatiques, à la dimension économique de l’affrontement, au déchaînement de violence qu’il génère, notamment la « Shoah par balles » qui se traduira par l’assassinat de plus d’un million trois cent mille juifs soviétiques par les nazis. Sans oublier le vécu des obscurs et des sans-grades, « matériel humain » d’une guerre totale et absolue. 
+
+« Ce que le lecteur retiendra, c’est la remarquable objectivité avec laquelle Nicolas Bernard traite les questions les plus délicates posées par cet affrontement titanesque entre deux tyrans, deux idéologies mortifères et deux peuples engagés malgré eux dans une guerre d’extermination. Même si certaines archives restent fermées à la recherche, il faudra sans doute bien des années avant qu’une œuvre aussi magistrale puisse être considérée comme dépassée. » 
+François Kersaudy&lt;/Text&gt;
+&lt;/TextContent&gt;
+&lt;SupportingResource&gt;
+&lt;ResourceContentType&gt;01&lt;/ResourceContentType&gt;
+&lt;ContentAudience&gt;00&lt;/ContentAudience&gt;
+&lt;ResourceMode&gt;03&lt;/ResourceMode&gt;
+&lt;ResourceFeature&gt;
+&lt;ResourceFeatureType&gt;02&lt;/ResourceFeatureType&gt;
+&lt;FeatureValue&gt;couverture principale&lt;/FeatureValue&gt;
+&lt;/ResourceFeature&gt;
+&lt;ResourceVersion&gt;
+&lt;ResourceForm&gt;02&lt;/ResourceForm&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;04&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;front_cover.jpg&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;01&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;D502&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;03&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;1000&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;02&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;1394&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceLink&gt;https://assets.edenlivres.fr/assets/publications/30724/medias/front_cover.jpg&lt;/ResourceLink&gt;
+&lt;ContentDate&gt;
+&lt;ContentDateRole&gt;17&lt;/ContentDateRole&gt;
+&lt;DateFormat&gt;14&lt;/DateFormat&gt;
+&lt;Date&gt;20131015T153823+0200&lt;/Date&gt;
+&lt;/ContentDate&gt;
+&lt;/ResourceVersion&gt;
+&lt;/SupportingResource&gt;
+&lt;SupportingResource&gt;
+&lt;ResourceContentType&gt;15&lt;/ResourceContentType&gt;
+&lt;ContentAudience&gt;00&lt;/ContentAudience&gt;
+&lt;ResourceMode&gt;04&lt;/ResourceMode&gt;
+&lt;ResourceFeature&gt;
+&lt;ResourceFeatureType&gt;02&lt;/ResourceFeatureType&gt;
+&lt;FeatureValue&gt;Extrait&lt;/FeatureValue&gt;
+&lt;/ResourceFeature&gt;
+&lt;ResourceVersion&gt;
+&lt;ResourceForm&gt;02&lt;/ResourceForm&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;04&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;extrait.epub&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;01&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;E101&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceLink&gt;https://assets.edenlivres.fr/assets/publications/30724/medias/extrait.epub&lt;/ResourceLink&gt;
+&lt;ContentDate&gt;
+&lt;ContentDateRole&gt;17&lt;/ContentDateRole&gt;
+&lt;DateFormat&gt;14&lt;/DateFormat&gt;
+&lt;Date&gt;20131015T153824+0200&lt;/Date&gt;
+&lt;/ContentDate&gt;
+&lt;/ResourceVersion&gt;
+&lt;/SupportingResource&gt;
+&lt;SupportingResource&gt;
+&lt;ResourceContentType&gt;01&lt;/ResourceContentType&gt;
+&lt;ContentAudience&gt;00&lt;/ContentAudience&gt;
+&lt;ResourceMode&gt;03&lt;/ResourceMode&gt;
+&lt;ResourceFeature&gt;
+&lt;ResourceFeatureType&gt;02&lt;/ResourceFeatureType&gt;
+&lt;FeatureValue&gt;front_cover_small&lt;/FeatureValue&gt;
+&lt;/ResourceFeature&gt;
+&lt;ResourceVersion&gt;
+&lt;ResourceForm&gt;02&lt;/ResourceForm&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;04&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;http://assets.edenlivres.fr/assets/publications/30724/cover/small.jpg&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;01&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;D502&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;03&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;65&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceLink&gt;http://assets.edenlivres.fr/assets/publications/30724/cover/small.jpg&lt;/ResourceLink&gt;
+&lt;ContentDate&gt;
+&lt;ContentDateRole&gt;17&lt;/ContentDateRole&gt;
+&lt;DateFormat&gt;14&lt;/DateFormat&gt;
+&lt;Date&gt;20150113T190647+0100&lt;/Date&gt;
+&lt;/ContentDate&gt;
+&lt;/ResourceVersion&gt;
+&lt;/SupportingResource&gt;
+&lt;SupportingResource&gt;
+&lt;ResourceContentType&gt;01&lt;/ResourceContentType&gt;
+&lt;ContentAudience&gt;00&lt;/ContentAudience&gt;
+&lt;ResourceMode&gt;03&lt;/ResourceMode&gt;
+&lt;ResourceFeature&gt;
+&lt;ResourceFeatureType&gt;02&lt;/ResourceFeatureType&gt;
+&lt;FeatureValue&gt;front_cover_medium&lt;/FeatureValue&gt;
+&lt;/ResourceFeature&gt;
+&lt;ResourceVersion&gt;
+&lt;ResourceForm&gt;02&lt;/ResourceForm&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;04&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;http://assets.edenlivres.fr/assets/publications/30724/cover/medium.jpg&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;01&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;D502&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;03&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;200&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceLink&gt;http://assets.edenlivres.fr/assets/publications/30724/cover/medium.jpg&lt;/ResourceLink&gt;
+&lt;ContentDate&gt;
+&lt;ContentDateRole&gt;17&lt;/ContentDateRole&gt;
+&lt;DateFormat&gt;14&lt;/DateFormat&gt;
+&lt;Date&gt;20150113T190646+0100&lt;/Date&gt;
+&lt;/ContentDate&gt;
+&lt;/ResourceVersion&gt;
+&lt;/SupportingResource&gt;
+&lt;SupportingResource&gt;
+&lt;ResourceContentType&gt;01&lt;/ResourceContentType&gt;
+&lt;ContentAudience&gt;00&lt;/ContentAudience&gt;
+&lt;ResourceMode&gt;03&lt;/ResourceMode&gt;
+&lt;ResourceFeature&gt;
+&lt;ResourceFeatureType&gt;02&lt;/ResourceFeatureType&gt;
+&lt;FeatureValue&gt;front_cover_large&lt;/FeatureValue&gt;
+&lt;/ResourceFeature&gt;
+&lt;ResourceVersion&gt;
+&lt;ResourceForm&gt;02&lt;/ResourceForm&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;04&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;http://assets.edenlivres.fr/assets/publications/30724/cover/large.jpg&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;01&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;D502&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceVersionFeature&gt;
+&lt;ResourceVersionFeatureType&gt;03&lt;/ResourceVersionFeatureType&gt;
+&lt;FeatureValue&gt;1000&lt;/FeatureValue&gt;
+&lt;/ResourceVersionFeature&gt;
+&lt;ResourceLink&gt;http://assets.edenlivres.fr/assets/publications/30724/cover/large.jpg&lt;/ResourceLink&gt;
+&lt;ContentDate&gt;
+&lt;ContentDateRole&gt;17&lt;/ContentDateRole&gt;
+&lt;DateFormat&gt;14&lt;/DateFormat&gt;
+&lt;Date&gt;20150113T190646+0100&lt;/Date&gt;
+&lt;/ContentDate&gt;
+&lt;/ResourceVersion&gt;
+&lt;/SupportingResource&gt;
+&lt;SupportingResource&gt;
+&lt;ResourceContentType&gt;16&lt;/ResourceContentType&gt;
+&lt;ContentAudience&gt;00&lt;/ContentAudience&gt;
+&lt;ResourceMode&gt;06&lt;/ResourceMode&gt;
+&lt;ResourceVersion&gt;
+&lt;ResourceForm&gt;01&lt;/ResourceForm&gt;
+&lt;ResourceLink&gt;http://www.edenlivres.fr/p/30724&lt;/ResourceLink&gt;
+&lt;/ResourceVersion&gt;
+&lt;/SupportingResource&gt;
+&lt;/CollateralDetail&gt;
+&lt;PublishingDetail&gt;
+&lt;Imprint&gt;
+&lt;ImprintName&gt;Tallandier&lt;/ImprintName&gt;
+&lt;/Imprint&gt;
+&lt;Publisher&gt;
+&lt;PublishingRole&gt;01&lt;/PublishingRole&gt;
+&lt;PublisherIdentifier&gt;
+&lt;PublisherIDType&gt;06&lt;/PublisherIDType&gt;
+&lt;IDValue&gt;3052235000017&lt;/IDValue&gt;
+&lt;/PublisherIdentifier&gt;
+&lt;PublisherIdentifier&gt;
+&lt;PublisherIDType&gt;01&lt;/PublisherIDType&gt;
+&lt;IDTypeName&gt;DM_GLOBAL_ID&lt;/IDTypeName&gt;
+&lt;IDValue&gt;EDEN165&lt;/IDValue&gt;
+&lt;/PublisherIdentifier&gt;
+&lt;PublisherName&gt;Tallandier&lt;/PublisherName&gt;
+&lt;Website&gt;
+&lt;WebsiteRole&gt;01&lt;/WebsiteRole&gt;
+&lt;WebsiteLink&gt;http://www.tallandier.com/&lt;/WebsiteLink&gt;
+&lt;/Website&gt;
+&lt;/Publisher&gt;
+&lt;PublishingStatus&gt;04&lt;/PublishingStatus&gt;
+&lt;PublishingDate&gt;
+&lt;PublishingDateRole&gt;01&lt;/PublishingDateRole&gt;
+&lt;DateFormat&gt;14&lt;/DateFormat&gt;
+&lt;Date&gt;20130905T000000+0200&lt;/Date&gt;
+&lt;/PublishingDate&gt;
+&lt;PublishingDate&gt;
+&lt;PublishingDateRole&gt;19&lt;/PublishingDateRole&gt;
+&lt;DateFormat&gt;14&lt;/DateFormat&gt;
+&lt;Date&gt;20130905T000000+0200&lt;/Date&gt;
+&lt;/PublishingDate&gt;
+&lt;SalesRights&gt;
+&lt;SalesRightsType&gt;01&lt;/SalesRightsType&gt;
+&lt;Territory&gt;
+&lt;CountriesIncluded&gt;DE AD AT BE CY ES EE FI FR GR GP GF IE IT LU MT MQ YT MC NL PT RE SK SI&lt;/CountriesIncluded&gt;
+&lt;/Territory&gt;
+&lt;/SalesRights&gt;
+&lt;SalesRestriction&gt;
+&lt;SalesRestrictionType&gt;06&lt;/SalesRestrictionType&gt;
+&lt;/SalesRestriction&gt;
+&lt;/PublishingDetail&gt;
+&lt;RelatedMaterial&gt;
+&lt;RelatedProduct&gt;
+&lt;ProductRelationCode&gt;13&lt;/ProductRelationCode&gt;
+&lt;ProductIdentifier&gt;
+&lt;ProductIDType&gt;03&lt;/ProductIDType&gt;
+&lt;IDValue&gt;9791021002746&lt;/IDValue&gt;
+&lt;/ProductIdentifier&gt;
+&lt;ProductForm&gt;BA&lt;/ProductForm&gt;
+&lt;/RelatedProduct&gt;
+&lt;RelatedProduct&gt;
+&lt;ProductRelationCode&gt;31&lt;/ProductRelationCode&gt;
+&lt;ProductIdentifier&gt;
+&lt;ProductIDType&gt;15&lt;/ProductIDType&gt;
+&lt;IDValue&gt;9791021003002&lt;/IDValue&gt;
+&lt;/ProductIdentifier&gt;
+&lt;ProductForm&gt;EA&lt;/ProductForm&gt;
+&lt;ProductFormDetail&gt;E101&lt;/ProductFormDetail&gt;
+&lt;ProductFormDetail&gt;E200&lt;/ProductFormDetail&gt;
+&lt;/RelatedProduct&gt;
+&lt;RelatedProduct&gt;
+&lt;ProductRelationCode&gt;06&lt;/ProductRelationCode&gt;
+&lt;ProductIdentifier&gt;
+&lt;ProductIDType&gt;01&lt;/ProductIDType&gt;
+&lt;IDValue&gt;eden-30724-15766-libraries&lt;/IDValue&gt;
+&lt;/ProductIdentifier&gt;
+&lt;ProductForm&gt;EA&lt;/ProductForm&gt;
+&lt;/RelatedProduct&gt;
+&lt;/RelatedMaterial&gt;
+&lt;/Product&gt;
+&lt;/ONIXMessage&gt;</notice>
+    <orderLine>
+        <orderId>FBKS1974</orderId>
+        <orderIdColl>LIBFBKS1974</orderIdColl>
+        <orderLineId>55a1145c975a0323f994c608</orderLineId>
+        <orderDate>2015-07-11T15:04:29.582+02:00</orderDate>
+        <ean13>9791021012431</ean13>
+        <quantity>1</quantity>
+        <usage>
+            <loanTerms>
+                <loanMaxDuration>
+                    <value>59</value>
+                    <unit>DAY</unit>
+                </loanMaxDuration>
+                <nbLoans>40</nbLoans>
+                <loanNbSimultaneousUsers>15</loanNbSimultaneousUsers>
+                <consultNbSimultaneousUsersInSitu>9999</consultNbSimultaneousUsersInSitu>
+                <consultNbSimultaneousUsersExSitu>0</consultNbSimultaneousUsersExSitu>
+            </loanTerms>
+            <userRights>
+                <printing>PROHIBITED</printing>
+                <copyAndPaste>PROHIBITED</copyAndPaste>
+                <nbAllowedDevices>6</nbAllowedDevices>
+            </userRights>
+            <collRights>
+                <offerValidity>
+                    <value>1825</value>
+                    <unit>DAY</unit>
+                </offerValidity>
+            </collRights>
+        </usage>
+        <returnStatus>OK</returnStatus>
+    </orderLine>
+</offer>
+</pnbOffers>
diff --git a/tests/library/Class/Cosmogramme/Integration/PhaseBatchsTest.php b/tests/library/Class/Cosmogramme/Integration/PhaseBatchsTest.php
index 21a23f50ce8abc74ee26d84c89bb008520528ff7..6463d52559add4dea8474ff323d98402a87c235a 100644
--- a/tests/library/Class/Cosmogramme/Integration/PhaseBatchsTest.php
+++ b/tests/library/Class/Cosmogramme/Integration/PhaseBatchsTest.php
@@ -27,9 +27,11 @@ abstract class PhaseBatchsTestCase extends Class_Cosmogramme_Integration_PhaseTe
     $this->fixture('Class_Batch',
                    ['id' => 34, 'type' => 'TestingTest']);
 
-    $this->_batch = $this->mock()
-                         ->whenCalled('getLabel')->answers('Testing Batch')
-                         ->whenCalled('run')->answers(true);
+    $this->_batch = $this->mock();
+    $this->_batch
+      ->whenCalled('getLabel')->answers('Testing Batch')
+      ->whenCalled('run')->answers(true)
+      ->whenCalled('setLogger')->answers($this->_batch);
 
     $this
       ->onLoaderOfModel('Class_Batch')
@@ -100,4 +102,45 @@ class PhaseBatchsCronRunTest extends PhaseBatchsTestCase {
   public function shouldDisplayElapsedTime() {
     $this->assertLogContains('Temps de traitement');
   }
+}
+
+
+
+class PhaseBatchsCronRunWithLoggerTest extends PhaseBatchsTestCase {
+  protected function _getPreviousPhase() {
+    return (new Class_Cosmogramme_Integration_Phase(0))
+      ->beCron();
+  }
+
+
+  protected function _prepareFixtures() {
+    $this->fixture('Class_Batch',
+                   ['id' => 34,
+                    'type' => 'TestingTest']);
+
+    $this->_batch = new Class_Cosmogramme_Integration_PhaseTestingBatch();
+
+    $this
+      ->onLoaderOfModel('Class_Batch')
+      ->whenCalled('getKnownType')->with('TestingTest')->answers($this->_batch);
+  }
+
+
+  /** @test */
+  public function shouldDisplayBatchLog() {
+    $this->assertLogContains('Testing test log');
+  }
+}
+
+
+
+class Class_Cosmogramme_Integration_PhaseTestingBatch extends Class_Batch_Abstract {
+  public function getLabel() {
+    return 'TestingTest batch';
+  }
+
+
+  public function run() {
+    $this->getLogger()->log('Testing test log');
+  }
 }
\ No newline at end of file
diff --git a/tests/library/Class/Cosmogramme/Integration/PhasePseudoRecordTest.php b/tests/library/Class/Cosmogramme/Integration/PhasePseudoRecordTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..a09e4baf1208c19b08ff9e4d90bc69b1ded19690
--- /dev/null
+++ b/tests/library/Class/Cosmogramme/Integration/PhasePseudoRecordTest.php
@@ -0,0 +1,477 @@
+<?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
+ */
+
+
+abstract class PhasePseudoRecordTestCase extends Class_Cosmogramme_Integration_PhaseTestCase {
+  protected
+    $_phase_name,
+    $_phase_label,
+    $_model_name,
+    $_model_id;
+
+  public function setUp() {
+    parent::setUp();
+    $this->_phase = $this->_buildPhase($this->_phase_name)
+                         ->setMemoryCleaner(function() {})
+                         ->run();
+  }
+
+
+  protected function _prepareFixtures() {
+    $loader = $this->onLoaderOfModel($this->_model_name)
+
+         ->whenCalled('findAllBy')
+         ->with(['where' => $this->_model_id . ' > 0',
+                 'order' => $this->_model_id,
+                 'limit' => 100])
+         ->answers([$this->_buildModel(15)])
+
+         ->whenCalled('findAllBy')
+         ->with(['where' => $this->_model_id . ' > 15',
+                 'order' => $this->_model_id,
+                 'limit' => 100])
+         ->answers([$this->_buildModel(16)])
+
+         ->whenCalled('findAllBy')->answers([]);
+  }
+
+
+  protected function _buildModel($id) {
+    return $this->fixture($this->_model_name,
+                          $this->_getModelAttribs($id));
+  }
+
+
+  protected function _getModelAttribs($id) {
+    return ['id' => $id];
+  }
+
+
+  protected function _getModelRecord($id) {
+    return call_user_func([$this->_model_name, 'find'], $id)->getNotice();
+  }
+
+
+  public function assertNullRecordOf($id) {
+    $this->assertNull($this->_getModelRecord($id));
+  }
+
+
+  public function assertNotNullRecordOf($id) {
+    $this->assertNotNull($this->_getModelRecord($id));
+  }
+}
+
+
+
+trait PhasePseudoRecordInvalidPreviousPhase {
+  protected function _getPreviousPhase() {
+    return (new Class_Cosmogramme_Integration_Phase(2))
+      ->beCron();
+  }
+
+
+  /** @test */
+  public function recordShouldNotBeCreated() {
+    $this->assertNullRecordOf(15);
+  }
+
+
+  /** @test */
+  public function logShouldNotContainsPhaseLabel() {
+    $this->assertNotLogContains($this->_phase_label);
+  }
+}
+
+
+trait PhasePseudoRecordValidCron {
+  /** @test */
+  public function shouldHaveCreatedFirstPseudoRecord() {
+    $this->assertNotNullRecordOf(15);
+  }
+
+
+  /** @test */
+  public function shouldHaveCreatedSecondPseudoRecord() {
+    $this->assertNotNullRecordOf(16);
+  }
+
+
+  /** @test */
+  public function traitemenPhaseShouldBePseudoRecord() {
+    $this->assertEquals($this->_phase_label,
+                        Class_CosmoVar::get('traitement_phase'));
+  }
+
+
+  /** @test */
+  public function logShouldContainsPhaseLabel() {
+    $this->assertLogContains($this->_phase_label);
+  }
+
+
+  /** @test */
+  public function dataNombreShouldBe2() {
+    $this->assertEquals(2, $this->_phase->getData('nombre'));
+  }
+
+
+  /** @test */
+  public function insertCountShouldBe7() {
+    $this->assertEquals(7,
+                        $this->_phase
+                        ->getCount(Class_Cosmogramme_Integration_Phase::RECORD_INSERT));
+  }
+
+
+  /** @test */
+  public function shouldDisplayRunSummary() {
+    $this->assertLogContains('2 notice(s) traitée(s)');
+    $this->assertLogContains('Temps de traitement');
+  }
+}
+
+
+
+trait PhasePseudoRecordValidInteractiveTimeout {
+  protected function _prepareFixtures() {
+    parent::_prepareFixtures();
+    $this->_time_source = $this
+      ->mock(new Class_TimeSource())
+      ->whenCalled('time')->answers(mktime(1, 0, 0, 9, 1, 2015))
+      ->whenCalled('dateYmd')->answers('2015-09-01');
+
+    Class_Cosmogramme_Chronometre::setTimeSource($this->_time_source);
+    $this->_chrono->start(mktime(0, 0, 0, 9, 1, 2015));
+  }
+
+
+  /** @test */
+  public function shouldNotHaveCreatedRecord() {
+    $this->assertEquals(0, Class_Notice::count());
+  }
+}
+
+
+
+trait PhasePseudoRecordValidInteractiveCallback {
+  protected function _prepareFixtures() {
+    parent::_prepareFixtures();
+    $this->_time_source = $this
+      ->mock(new Class_TimeSource())
+      ->whenCalled('time')->answers(mktime(0, 0, 0, 9, 1, 2015))
+      ->whenCalled('dateYmd')->answers('2015-09-01');
+
+    Class_Cosmogramme_Chronometre::setTimeSource($this->_time_source);
+    $this->_chrono->start(mktime(0, 0, 0, 9, 1, 2015));
+  }
+
+
+  /** @test */
+  public function shouldNotHaveCreatedArticle15PseudoRecord() {
+    $this->assertNullRecordOf(15);
+  }
+
+
+  /** @test */
+  public function shouldHaveCreatedArticle16PseudoRecord() {
+    $this->assertNotNullRecordOf(16);
+  }
+
+
+  /** @test */
+  public function printerShouldContainsPhaseLabel() {
+    $this->assertPrinterContains($this->_phase_label);
+  }
+
+
+  /** @test */
+  public function dataNombreShouldBe2() {
+    $this->assertEquals(2, $this->_phase->getData('nombre'));
+  }
+
+
+  /** @test */
+  public function insertCountShouldBe7() {
+    $this->assertEquals(7,
+                        $this->_phase
+                        ->getCount(Class_Cosmogramme_Integration_Phase::RECORD_INSERT));
+  }
+}
+
+
+/**
+ * CMS
+ */
+
+abstract class PhasePseudoRecordCmsTestCase extends PhasePseudoRecordTestCase {
+  protected
+    $_phase_name = 'PseudoRecordCms',
+    $_phase_label = 'Pseudo-notices : CMS',
+    $_model_name = 'Class_Article',
+    $_model_id = 'id_article';
+
+
+  protected function _getModelAttribs($id) {
+    return array_merge(parent::_getModelAttribs($id),
+                       ['titre' => 'Article ' . $id,
+                        'contenu' => 'Content ' . $id]);
+  }
+}
+
+
+
+class PhasePseudoRecordCmsInvalidPreviousPhaseTest extends PhasePseudoRecordCmsTestCase {
+  use PhasePseudoRecordInvalidPreviousPhase;
+}
+
+
+
+class PhasePseudoRecordCmsValidCronTest extends PhasePseudoRecordCmsTestCase {
+  use PhasePseudoRecordValidCron;
+
+  protected function _getPreviousPhase() {
+    return (new Class_Cosmogramme_Integration_Phase(0.1))
+      ->setData('pointeur_reprise', 45)
+      ->setCount(Class_Cosmogramme_Integration_Phase::RECORD_INSERT, 5)
+      ->beCron();
+  }
+}
+
+
+
+class PhasePseudoRecordCmsValidInteractiveTimeoutTest
+  extends PhasePseudoRecordCmsTestCase {
+  use PhasePseudoRecordValidInteractiveTimeout;
+
+  protected function _getPreviousPhase() {
+    return (new Class_Cosmogramme_Integration_Phase(0.1));
+  }
+}
+
+
+
+class PhasePseudoRecordCmsValidInteractiveCallbackTest
+  extends PhasePseudoRecordCmsTestCase {
+  use PhasePseudoRecordValidInteractiveCallback;
+
+  protected function _getPreviousPhase() {
+    return (new Class_Cosmogramme_Integration_Phase(0.2))
+      ->beCallBack()
+      ->setData('nombre', 1)
+      ->setData('pointeur_reprise', 15)
+      ->setCount(Class_Cosmogramme_Integration_Phase::RECORD_INSERT, 6);
+  }
+}
+
+
+/**
+ * RSS
+ */
+
+abstract class PhasePseudoRecordRssTestCase extends PhasePseudoRecordTestCase {
+  protected
+    $_phase_name = 'PseudoRecordRss',
+    $_phase_label = 'Pseudo-notices : FILS RSS',
+    $_model_name = 'Class_Rss',
+    $_model_id = 'id_rss';
+
+  protected function _getModelAttribs($id) {
+    return array_merge(parent::_getModelAttribs($id),
+                       ['titre' => 'RSS ' . $id]);
+  }
+}
+
+
+
+class PhasePseudoRecordRssInvalidPreviousPhaseTest extends PhasePseudoRecordRssTestCase {
+  use PhasePseudoRecordInvalidPreviousPhase;
+}
+
+
+
+class PhasePseudoRecordRssValidCronTest extends PhasePseudoRecordRssTestCase {
+  use PhasePseudoRecordValidCron;
+
+  protected function _getPreviousPhase() {
+    return (new Class_Cosmogramme_Integration_Phase(0.2))
+      ->setData('pointeur_reprise', 45)
+      ->setCount(Class_Cosmogramme_Integration_Phase::RECORD_INSERT, 5)
+      ->beCron();
+  }
+}
+
+
+
+class PhasePseudoRecordRssValidInteractiveTimeoutTest
+  extends PhasePseudoRecordRssTestCase {
+  use PhasePseudoRecordValidInteractiveTimeout;
+
+  protected function _getPreviousPhase() {
+    return (new Class_Cosmogramme_Integration_Phase(0.2));
+  }
+}
+
+
+
+class PhasePseudoRecordRssValidInteractiveCallbackTest
+  extends PhasePseudoRecordRssTestCase {
+  use PhasePseudoRecordValidInteractiveCallback;
+
+  protected function _getPreviousPhase() {
+    return (new Class_Cosmogramme_Integration_Phase(0.3))
+      ->beCallBack()
+      ->setData('nombre', 1)
+      ->setData('pointeur_reprise', 15)
+      ->setCount(Class_Cosmogramme_Integration_Phase::RECORD_INSERT, 6);
+  }
+}
+
+
+
+/**
+ * SITO
+ */
+
+abstract class PhasePseudoRecordSitoTestCase extends PhasePseudoRecordTestCase {
+  protected
+    $_phase_name = 'PseudoRecordSitotheque',
+    $_phase_label = 'Pseudo-notices : SITOTHEQUE',
+    $_model_name = 'Class_Sitotheque',
+    $_model_id = 'id_sito';
+
+  protected function _getModelAttribs($id) {
+    return array_merge(parent::_getModelAttribs($id),
+                       ['titre' => 'Sito ' . $id,
+                        'url' => 'http://server.com/' . $id]);
+  }
+}
+
+
+
+class PhasePseudoRecordSitoInvalidPreviousPhaseTest extends PhasePseudoRecordSitoTestCase {
+  use PhasePseudoRecordInvalidPreviousPhase;
+}
+
+
+
+class PhasePseudoRecordSitoValidCronTest extends PhasePseudoRecordSitoTestCase {
+  use PhasePseudoRecordValidCron;
+
+  protected function _getPreviousPhase() {
+    return (new Class_Cosmogramme_Integration_Phase(0.3))
+      ->setData('pointeur_reprise', 45)
+      ->setCount(Class_Cosmogramme_Integration_Phase::RECORD_INSERT, 5)
+      ->beCron();
+  }
+}
+
+
+
+class PhasePseudoRecordSitoValidInteractiveTimeoutTest
+  extends PhasePseudoRecordSitoTestCase {
+  use PhasePseudoRecordValidInteractiveTimeout;
+
+  protected function _getPreviousPhase() {
+    return (new Class_Cosmogramme_Integration_Phase(0.3));
+  }
+}
+
+
+
+class PhasePseudoRecordSitoValidInteractiveCallbackTest
+  extends PhasePseudoRecordSitoTestCase {
+  use PhasePseudoRecordValidInteractiveCallback;
+
+  protected function _getPreviousPhase() {
+    return (new Class_Cosmogramme_Integration_Phase(0.4))
+      ->beCallBack()
+      ->setData('nombre', 1)
+      ->setData('pointeur_reprise', 15)
+      ->setCount(Class_Cosmogramme_Integration_Phase::RECORD_INSERT, 6);
+  }
+}
+
+
+
+/**
+ * Albums
+ */
+
+abstract class PhasePseudoRecordAlbumTestCase extends PhasePseudoRecordTestCase {
+  protected
+    $_phase_name = 'PseudoRecordAlbum',
+    $_phase_label = 'Pseudo-notices : RESSOURCES NUMERIQUES',
+    $_model_name = 'Class_Album',
+    $_model_id = 'id';
+
+  protected function _getModelAttribs($id) {
+    return array_merge(parent::_getModelAttribs($id),
+                       ['titre' => 'Album ' . $id,
+                        'visible' => 1,
+                        'status' => Class_Album::STATUS_VALIDATED]);
+  }
+}
+
+
+
+class PhasePseudoRecordAlbumInvalidPreviousPhaseTest extends PhasePseudoRecordAlbumTestCase {
+  use PhasePseudoRecordInvalidPreviousPhase;
+}
+
+
+
+class PhasePseudoRecordAlbumValidCronTest extends PhasePseudoRecordAlbumTestCase {
+  use PhasePseudoRecordValidCron;
+
+  protected function _getPreviousPhase() {
+    return (new Class_Cosmogramme_Integration_Phase(0.4))
+      ->setData('pointeur_reprise', 45)
+      ->setCount(Class_Cosmogramme_Integration_Phase::RECORD_INSERT, 5)
+      ->beCron();
+  }
+}
+
+
+
+class PhasePseudoRecordAlbumValidInteractiveTimeoutTest
+  extends PhasePseudoRecordAlbumTestCase {
+  use PhasePseudoRecordValidInteractiveTimeout;
+
+  protected function _getPreviousPhase() {
+    return (new Class_Cosmogramme_Integration_Phase(0.4));
+  }
+}
+
+
+
+class PhasePseudoRecordAlbumValidInteractiveCallbackTest
+  extends PhasePseudoRecordAlbumTestCase {
+  use PhasePseudoRecordValidInteractiveCallback;
+
+  protected function _getPreviousPhase() {
+    return (new Class_Cosmogramme_Integration_Phase(0.5))
+      ->beCallBack()
+      ->setData('nombre', 1)
+      ->setData('pointeur_reprise', 15)
+      ->setCount(Class_Cosmogramme_Integration_Phase::RECORD_INSERT, 6);
+  }
+}
\ No newline at end of file
diff --git a/tests/library/Class/Cosmogramme/Integration/PhaseTestCase.php b/tests/library/Class/Cosmogramme/Integration/PhaseTestCase.php
index 213994ea97737bffc17cd889d2555f422678141b..1ec618f382e2039dc585bceeec1493938b93036f 100644
--- a/tests/library/Class/Cosmogramme/Integration/PhaseTestCase.php
+++ b/tests/library/Class/Cosmogramme/Integration/PhaseTestCase.php
@@ -25,9 +25,9 @@ require_once('cosmogramme/php/classes/classe_profil_donnees.php');
 abstract class Class_Cosmogramme_Integration_PhaseTestCase extends ModelTestCase {
   protected
     $_storm_default_to_volatile = true,
-    $_log_content,
+    $_log_content = '',
     $_log,
-    $_printer_content,
+    $_printer_content = '',
     $_printer,
     $_phase;
 
@@ -83,6 +83,11 @@ abstract class Class_Cosmogramme_Integration_PhaseTestCase extends ModelTestCase
   }
 
 
+  protected function assertPrinterContains($value) {
+    $this->assertContains($value, $this->_printer_content);
+  }
+
+
   protected function assertNotLogContains($value) {
     $this->assertNotContains($value, $this->_log_content);
   }
diff --git a/tests/library/Class/DecodageUnimarcTest.php b/tests/library/Class/DecodageUnimarcTest.php
index 5eb8c008dd78f8c330b570d50beb71d8496f98bd..80abacd0f745dad8360cc30b79b3b8c3c255e469 100644
--- a/tests/library/Class/DecodageUnimarcTest.php
+++ b/tests/library/Class/DecodageUnimarcTest.php
@@ -310,4 +310,80 @@ class DecodageUnimarcConcertoAuteursTest extends PHPUnit_Framework_TestCase {
 
 }
 
+
+class DecodageUnimarcDVDUnHerosTresDiscretTest extends Storm_Test_ModelTestCase {
+  public function setUp() {
+    parent::setUp();
+    Class_CodifAuteurFonction::beVolatile();
+    Class_CodifAuteur::beVolatile();
+
+    $this->fixture('Class_CodifLangue',
+                   ['id' => 23,
+                    'libelle' => '']);
+    foreach ($this->createAuthors() as $author) {
+      $author_db=$this->fixture('Class_CodifAuteur',
+                                ['id' => $author[0],
+                                 'libelle' => $author[1]
+                                ]);
+      Storm_Test_ObjectWrapper::onLoaderOfModel('Class_CodifAuteur')
+        ->whenCalled('findFirstBy')
+        ->with(['where' => "MATCH(formes) AGAINST('".$author[2]."' IN BOOLEAN MODE)"])
+        ->answers($author_db);
+
+
+    }
+    $this->fixture('Class_CodifAuteurFonction', ['id' => '005',
+                                                 'libelle' => 'Charpentier']);
+    $unimarc=file_get_contents(realpath(dirname(__FILE__)).'../../../fixtures/audiard_herosdiscret.uni');
+    $this->audiard = $this->fixture('Class_Notice',
+                                    ['id' => 10,
+                                     'unimarc' => $unimarc,
+                                     'exemplaires' => []]);
+    $this->_authors = $this->audiard->getAuteursUnimarc(false, true);
+  }
+
+  protected function createAuthors() {
+    return [[1,'Jacques Audiard','AUDIARDxJACQUES'],
+            [2,'Alexandre Desplat', 'DESPLATxALEXANDRE'],
+            [3, 'Jean-François Deniau', 'DENIAUxJEANxFRANCOIS'],
+            [4, 'Mathieu Kassovitz', 'KASSOVITZxMATHIEU'],
+            [5, 'Anouk Grinberg', 'GRINBERGxANOUK'],
+            [6,'Sandrine Kiberlain' , 'KIBERLAINxSANDRINE'],
+            [8,'Albert Dupontel' , 'DUPONTELxALBERT'],
+            [7,'Alain Le Henry' , 'LExHENRYxALAIN']];
+  }
+  /**
+   * @dataProvider expectedAuthors
+   * @test
+   */
+  public function getAuthorUnimarcShouldReturnExpectedAuthors($id, $label, $rebound_code, $author_index) {
+    $author = $this->_authors[$author_index];
+
+
+    $this->assertEquals($id, $author->getId());
+    $this->assertEquals($label, $author->getLabel());
+    $this->assertEquals(['controller' => 'recherche',
+                         'action' => 'simple',
+                         'code_rebond' => $rebound_code,
+                         'facettes' => null,
+                         'facette' => null,
+                         'serie' => null,
+                         'page' => null],
+                        $author->getUrlParams());
+  }
+
+
+  public function expectedAuthors() {
+    return [
+            [1, 'Jacques Audiard (Metteur en scène ou réalisateur)', 'A1', 0],
+            [2, 'Alexandre Desplat (Compositeur)', 'A2', 1],
+            [3, 'Jean-François Deniau (Auteur)', 'A3', 2],
+            [4, 'Mathieu Kassovitz (Acteur)', 'A4', 3],
+            [5, 'Anouk Grinberg (Acteur)','A5', 4],
+            [6, 'Sandrine Kiberlain (Acteur)' , 'A6', 5],
+            [8, 'Albert Dupontel (Acteur)' , 'A8', 7],
+            [7, 'Alain Le Henry (Intervenant)' , 'A7', 9]];
+  }
+
+}
 ?>
\ No newline at end of file
diff --git a/tests/library/Class/Indexation/PseudoNoticeTest.php b/tests/library/Class/Indexation/PseudoNoticeTest.php
index c8d534450844c0dab0c3345faf69f9f0f03b771a..56232eb5f5cc4e1d2775272bb0c353c50731801a 100644
--- a/tests/library/Class/Indexation/PseudoNoticeTest.php
+++ b/tests/library/Class/Indexation/PseudoNoticeTest.php
@@ -31,18 +31,41 @@ abstract class Class_Indexation_PseudoNoticeTestCase extends Storm_Test_ModelTes
 class Class_Indexation_PseudoNoticeAlbumTest extends Class_Indexation_PseudoNoticeTestCase {
   public function setUp() {
     parent::setUp();
+
+    $this->fixture('Class_CodifAuteur', ['id' => '234']);
+
     $this->fixture('Class_Album',
                    ['id' => 896,
-                   'fichier' => '123_file.png',
-                   'notes' => 'a:3:{i:1;a:2:{s:5:"field";s:3:"856";s:4:"data";a:2:{s:1:"x";s:12:"external_uri";s:1:"a";N;}}s:5:"215$a";s:0:"";i:2;a:2:{s:5:"field";s:3:"701";s:4:"data";a:2:{s:1:"a";s:16:"Gustave Flaubert";i:4;s:0:"";}}}',
-                   'id_origine' => '778997987',
-                   'annee' => 2012,
-                   'status' => Class_Album::STATUS_VALIDATED])
-      ->index();
+                    'titre' => 'Trois contes',
+                    'fichier' => '123_file.png',
+                    'notes' => 'a:3:{i:1;a:2:{s:5:"field";s:3:"856";s:4:"data";a:2:{s:1:"x";s:12:"external_uri";s:1:"a";N;}}s:5:"215$a";s:0:"";i:2;a:2:{s:5:"field";s:3:"701";s:4:"data";a:2:{s:1:"a";s:16:"Gustave Flaubert";i:4;s:0:"";}}}',
+                    'id_origine' => '778997987',
+                    'annee' => 2012,
+                    'status' => Class_Album::STATUS_VALIDATED])
+         ->index();
+
     $this->_notice = Class_Notice::find(1);
   }
 
 
+  /** @test */
+  public function titleShouldBeTroisContes() {
+    $this->assertEquals('Trois contes', $this->_notice->getTitrePrincipal());
+  }
+
+
+  /** @test */
+  public function facetsShouldContainAuthor() {
+    $this->assertContains('A234', $this->_notice->getFacettes());
+  }
+
+
+  /** @test */
+  public function unimarcShouldContainAuthor() {
+    $this->assertEquals('Gustave Flaubert', $this->_notice->get_subfield('701', 'a')[0]);
+  }
+
+
   /** @test */
   public function vignetteURLShouldBeUserfile123file() {
     $this->assertEquals(BASE_URL.'/userfiles/album/896/thumb_123_file.png', $this->_notice->getUrlVignette());
@@ -85,19 +108,14 @@ class Class_Indexation_PseudoNoticeSitothequeFromRawSQLTest extends Class_Indexa
 
   public function setUp() {
     parent::setUp();
-    $this->fixture('Class_Sitotheque', ['id' => 12,
-                                        'titre' => 'Thot cursus',
-                                        'url' => 'http://cursus.edu/',
-                                        'description' => 'Top notch site',
-                                        'tags' => 'VOD']);
+    $sito = $this->fixture('Class_Sitotheque', ['id' => 12,
+                                                'titre' => 'Thot cursus',
+                                                'url' => 'http://cursus.edu/',
+                                                'description' => 'Top notch site',
+                                                'tags' => 'VOD']);
 
     /** as done in Cosmogramme */
-    Class_Indexation_PseudoNotice::newWith(Class_TypeDoc::SITE,
-                                           ['ID_SITO' => 12,
-                                            'TITRE' => 'Thot cursus',
-                                            'URL' => 'http://cursus.edu/',
-                                            'DESCRIPTION' => 'Top notch site',
-                                            'TAGS' => 'VOD'])->save();
+    Class_Indexation_PseudoNotice::newWith($sito)->save();
 
     $this->_notice = Class_Notice::find(1);
   }
@@ -129,8 +147,7 @@ class Class_Indexation_PseudoNoticeCmsTest extends Class_Indexation_PseudoNotice
                               ['id' => 43,
                                'titre' => 'Festival Animation',
                                'contenu' => 'à Annecy']);
-    Class_Indexation_PseudoNotice::newWith(Class_TypeDoc::ARTICLE,
-                                           $article->getRawAttributes())->save();
+    Class_Indexation_PseudoNotice::newWith($article)->save();
     $this->_notice = Class_Notice::find(1);
   }
 
@@ -162,9 +179,7 @@ class Class_Indexation_PseudoNoticeSitothequeTest extends Class_Indexation_Pseud
                                                        'description' => 'Top notch site',
                                                        'tags' => 'VOD']);
 
-    Class_Indexation_PseudoNotice::newWith(Class_TypeDoc::SITE,
-                                           $this->_sito->toArray() + ['ID_SITO' => $this->_sito->getId()])
-      ->save();
+    Class_Indexation_PseudoNotice::newWith($this->_sito)->save();
 
     $this->_notice = $this->_sito->getNotice();
   }
@@ -232,3 +247,345 @@ class Class_Indexation_PseudoNoticeArticleTest extends Storm_Test_ModelTestCase
     $this->assertCount(1, Class_NoticeDomain::findAll());
   }
 }
+
+
+
+class Class_Indexation_PseudoNoticeArticleUpdateTest extends Storm_Test_ModelTestCase {
+  public function setUp() {
+    parent::setUp();
+    $record = $this->fixture('Class_Notice',
+                             ['id' => 15,
+                              'titres' => 'Should not be deleted']);
+
+    $article = $this->fixture('Class_Article',
+                              ['id' => 1,
+                               'titre' => 'Should update record with id 15',
+                               'contenu' => 'Index me should update my record',
+                               'indexation' => 1,
+                               'status' => Class_Article::STATUS_VALIDATED,
+                               'notice' => $record]);
+    $article->index();
+  }
+
+
+  /** @test */
+  public function recordShouldNotBeDeleted() {
+    $this->assertNotNull(Class_Notice::find(15));
+  }
+
+
+  /** @test */
+  public function onlyOneRecordShouldBePresent() {
+    $this->assertCount(1, Class_Notice::findAll());
+  }
+
+
+  /** @test */
+  public function recordShouldHaveBeenUpdated() {
+    $this->assertEquals('SHOULD CHOUL UPDATE UPDAT RECORD REKOR WITH OUI 15',
+                        Class_Notice::find(15)->getTitres());
+  }
+
+
+  /** @test */
+  public function deleteArticleShouldDeleteRecord() {
+    Class_Article::find(1)->delete();
+    $this->assertNull(Class_Notice::find(15));
+  }
+}
+
+
+
+class Class_Indexation_PseudoNoticeRssUpdateTest extends Storm_Test_ModelTestCase {
+  public function setUp() {
+    parent::setUp();
+    $record = $this->fixture('Class_Notice',
+                   ['id' => 15,
+                    'titres' => 'Should not be deleted']);
+
+    $rss = $this->fixture('Class_Rss',
+                   ['id' => 1,
+                    'titre' => 'Should update record with id 15',
+                    'contenu' => 'Index me should update my record',
+                    'notice' => $record]);
+
+    $rss->index();
+  }
+
+
+  /** @test */
+  public function recordShouldNotBeDeleted() {
+    $this->assertNotNull(Class_Notice::find(15));
+  }
+
+
+  /** @test */
+  public function onlyOneRecordShouldBePresent() {
+    $this->assertCount(1, Class_Notice::findAll());
+  }
+
+
+  /** @test */
+  public function recordShouldHaveBeenUpdated() {
+    $this->assertEquals('SHOULD CHOUL UPDATE UPDAT RECORD REKOR WITH OUI 15',
+                        Class_Notice::find(15)->getTitres());
+  }
+
+
+  /** @test */
+  public function deleteArticleShouldDeleteRecord() {
+    Class_Rss::find(1)->delete();
+    $this->assertNull(Class_Notice::find(15));
+  }
+}
+
+
+
+class Class_Indexation_PseudoNoticeSitothequeUpdateTest extends Storm_Test_ModelTestCase {
+  public function setUp() {
+    parent::setUp();
+    Class_Notice::beVolatile();
+    Class_Exemplaire::beVolatile();
+    $sitotheque = $this->fixture('Class_Sitotheque',
+                   ['id' => 1,
+                    'url' => 'http://www.bokeh-library-portal.org',
+                    'titre' => 'Should update record with id 15',
+                    'contenu' => 'Index me should update my record']);
+    $sitotheque->index();
+    $sitotheque->index();
+  }
+
+
+  /** @test */
+  public function sitoGetNoticeShouldNotBeNull() {
+    $record = Class_Sitotheque::find(1)->getNotice();
+    $this->assertEquals('SHOULD CHOUL UPDATE UPDAT RECORD REKOR WITH OUI 15', $record->getTitres());
+  }
+
+
+  /** @test */
+  public function sitoHasNoticeShouldBeTrue() {
+    $this->assertTrue(Class_Sitotheque::find(1)->hasNotice());
+  }
+
+
+  /** @test */
+  public function sitoSetdNoticeShouldSetIt() {
+    $record = $this->fixture('Class_Notice',
+                             ['id' => 15,
+                              'titres' => 'Should not be deleted']);
+    Class_Sitotheque::find(1)->setNotice($record);
+    $this->assertEquals(15, Class_Sitotheque::find(1)->getIdNotice());
+  }
+
+
+  /** @test */
+  public function recordShouldNotBeDeleted() {
+    $this->assertNotNull(Class_Notice::find(1));
+  }
+
+
+  /** @test */
+  public function onlyOneRecordShouldBePresent() {
+    $this->assertCount(1, Class_Notice::findAll());
+  }
+
+
+  /** @test */
+  public function onlyOneItemShouldBePresent() {
+    $this->assertCount(1, Class_Exemplaire::findAll());
+  }
+
+
+  /** @test */
+  public function deleteArticleShouldDeleteRecord() {
+    Class_Sitotheque::find(1)->delete();
+    $this->assertNull(Class_Notice::find(15));
+  }
+}
+
+
+
+
+class Class_Indexation_PseudoNoticeAlbumUpdateTest extends Storm_Test_ModelTestCase {
+  public function setUp() {
+    parent::setUp();
+    $record = $this->fixture('Class_Notice',
+                   ['id' => 15,
+                    'titres' => 'Should not be deleted']);
+
+    $album = $this->fixture('Class_Album',
+                   ['id' => 1,
+                    'type_doc_id' => Class_TypeDoc::AUDIO_RECORD,
+                    'titre' => 'Should update record with this new title.',
+                    'status' => Class_Album::STATUS_VALIDATED,
+                    'notice' => $record]);
+
+    $album->index();
+  }
+
+
+  /** @test */
+  public function recordShouldNotBeDeleted() {
+    $this->assertNotNull(Class_Notice::find(15));
+  }
+
+
+  /** @test */
+  public function onlyOneRecordShouldBePresent() {
+    $this->assertCount(1, Class_Notice::findAll());
+  }
+
+
+  /** @test */
+  public function recordShouldHaveBeenUpdated() {
+    $this->assertEquals('SHOULD CHOUL UPDATE UPDAT RECORD REKOR WITH OUI THIS TI NEW  TITLE TITL',
+                        Class_Notice::find(15)->getTitres());
+  }
+
+
+  /** @test */
+  public function deleteArticleShouldDeleteRecord() {
+    Class_Album::find(1)->delete();
+    $this->assertNull(Class_Notice::find(15));
+  }
+}
+
+
+
+class Class_Indexation_PseudoNoticeSacramentariumTest
+  extends Class_Indexation_PseudoNoticeTestCase {
+
+  public function setUp() {
+    parent::setUp();
+
+    $this->fixture('Class_CodifMatiere', ['id' => 62115,
+                                          'libelle' => 'Douzième siècle']);
+
+    $this->sacramentarium = $this
+      ->fixture('Class_Album',
+                ['id'=>'144',
+                 'cat_id'=>'30',
+                 'notice_id'=>'99421',
+                 'titre'=>'MS 14 - Sacramentarium ad usum Sylviniacensem',
+                 'auteur'=>'',
+                 'editeur'=>'',
+                 'annee'=>'',
+                 'description'=>'',
+                 'tags'=>'',
+                 'date_maj'=>'2012-10-22 16:49:57',
+                 'fichier'=>'144_B031906101_MS_014_0033R.jpg',
+                 'type_doc_id'=>'100',
+                 'id_langue'=>'lat',
+                 'genre'=>'7;99',
+                 'dewey'=>'',
+                 'matiere'=>'62115',
+                 'id_origine'=>'D09030160',
+                 'cfg_thumbnails'=>'',
+                 'a:9:{s:15:"thumbnail_width";s:3:"400";s:28:"thumbnail_left_page_crop_top";s:1:"0";s:30:"thumbnail_left_page_crop_right";s:2:"35";s:31:"thumbnail_left_page_crop_bottom";s:1:"0";s:29:"thumbnail_left_page_crop_left";s:1:"0";s:29:"thumbnail_right_page_crop_top";s:1:"0";s:31:"thumbnail_right_page_crop_right";s:1:"0";s:32:"thumbnail_right_page_crop_bottom";s:1:"0";s:30:"thumbnail_right_page_crop_left";s:2:"35";}',
+                 'pdf'=>'',
+                 'sous_titre'=>'Sacramentaire de Souvigny',
+                 'cote'=>'MS 14',
+                 'provenance'=>'Prieuré de Souvigny',
+                 'notes'=>'a:3:{s:5:"305$a";s:12:"XIIe siècle";s:5:"200$b";s:9:"Parchemin";s:5:"316$a";s:12:"Reliure bois";}',
+                 'url_origine'=>null,
+                 'visible'=> '1',
+                 'droits'=> 'Domaine public',
+                 'nature_doc'=> '',
+                 'id_bib' => 1,
+                 'bibliotheques' => '7;87',
+                 'annexes' => '6;55',
+                 'sections' => '12;23',
+                 'status' => Class_Album::STATUS_VALIDATED])
+      ->index();
+
+    $this->_notice = Class_Notice::find(1);
+  }
+
+
+  protected function assertFacettesContains($value) {
+    $this->assertTrue(false !== strpos($this->_notice->getFacettes(), $value),
+                      'Failed asserting that facettes CONTAINS [' . $value . ']');
+  }
+
+
+  /** @test */
+  public function subfield200_bShouldBeParchemin() {
+    $this->assertEquals('Parchemin', $this->_notice->get_subfield('200', 'b')[0]);
+  }
+
+
+  /** @test */
+  public function matiereShouldBeDouziemeSiecle() {
+    $this->assertEquals('Douzième siècle', $this->_notice->get_subfield("610", "a")[0]);
+  }
+
+
+  /** @test */
+  public function titreShouldBeSacramentarium() {
+    $this->assertEquals('MS 14 - Sacramentarium ad usum Sylviniacensem',
+                        $this->_notice->get_subfield("200", "a")[0]);
+  }
+
+
+  /** @test */
+  public function bibliotheque7ShouldBeInFacettes() {
+    $this->assertFacettesContains('B7');
+  }
+
+
+  /** @test */
+  public function bibliotheque87ShouldBeInFacettes() {
+    $this->assertFacettesContains('B87');
+  }
+
+
+  /** @test */
+  public function annexe6ShouldBeInFacettes() {
+    $this->assertFacettesContains('Y6');
+  }
+
+
+  /** @test */
+  public function annexe55ShouldBeInFacettes() {
+    $this->assertFacettesContains('Y55');
+  }
+
+
+  /** @test */
+  public function section12ShouldBeInFacettes() {
+    $this->assertFacettesContains('S12');
+  }
+
+
+  /** @test */
+  public function section23ShouldBeInFacettes() {
+    $this->assertFacettesContains('S23');
+  }
+
+  /** @test */
+  public function genre7ShouldBeInFacettes() {
+    $this->assertFacettesContains('G7');
+  }
+
+
+  /** @test */
+  public function genre99ShouldBeInFacettes() {
+    $this->assertFacettesContains('G99');
+  }
+
+
+  /** @test */
+  public function typeDocShouldBeInFacettes() {
+    $this->assertFacettesContains('T100');
+  }
+
+
+  /** @test */
+  public function basePathShouldBeUserfilesAlbum() {
+    $my_path = realpath(dirname(__FILE__));
+    $root = substr($my_path, 0, strpos($my_path, '/cosmogramme'));
+    $this->assertContains('/userfiles/album/144/',
+                          $this->sacramentarium->getBasePath());
+  }
+}
\ No newline at end of file
diff --git a/tests/library/Class/NewsletterMailingTest.php b/tests/library/Class/NewsletterMailingTest.php
index 52b49cee6d3abfa2c06c93b43ae8a4fde3e0554f..2940ca12f59aa8c7bfcd043fdd39e0030d9ac4e8 100644
--- a/tests/library/Class/NewsletterMailingTest.php
+++ b/tests/library/Class/NewsletterMailingTest.php
@@ -444,12 +444,12 @@ class NewsletterMailingConcertsPanierHtmlTest extends NewsletterMailingTestCase
 /** @see http://forge.afi-sa.fr/issues/18661 */
 class NewsletterMailingDedupTest extends ModelTestCase {
   protected
+    $_storm_default_to_volatile = true,
     $_fetch_users_calls = 0,
     $_letter;
 
   public function setUp() {
     parent::setUp();
-    Storm_Model_Loader::defaultToVolatile();
 
     $this->mock_transport = new MockMailTransport();
     Zend_Mail::setDefaultTransport($this->mock_transport);
@@ -495,12 +495,6 @@ class NewsletterMailingDedupTest extends ModelTestCase {
   }
 
 
-  public function tearDown() {
-    Storm_Model_Loader::defaultToDb();
-    parent::tearDown();
-  }
-
-
   /** @test */
   public function procyonInOnePageShouldNotReceiveTwoMails() {
     $this->expectUserFetchAndDo(
@@ -554,4 +548,109 @@ class NewsletterMailingDedupTest extends ModelTestCase {
       ->with('select bib_admin_users.* from bib_admin_users join newsletters_users on bib_admin_users.id_user = newsletters_users.user_id where newsletter_id = 23 and newsletters_users.send is false order by bib_admin_users.mail limit 20')
       ->willDo($closure);
   }
-}
\ No newline at end of file
+}
+
+
+
+/** @see http://forge.afi-sa.fr/issues/29441 */
+class NewsletterMailingRecordAbsoluteUrlTest extends ModelTestCase {
+  protected
+    $_text_content = '',
+    $_html_content = '',
+    $_xpath,
+    $_base_url = '';
+
+
+  public function setUp() {
+    parent::setUp();
+
+    $this->_xpath = new Storm_Test_XPath();
+    $this->_base_url = 'http://' . $_SERVER['HTTP_HOST'] . BASE_URL;
+
+    $time_source = new TimeSourceForTest('2014-05-23 14:30:00');
+    Class_Newsletter::setTimeSource($time_source);
+
+    $this->alcor = $this->fixture('Class_Users',
+                                  ['id' => 120,
+                                   'login' => 'alc',
+                                   'password' => 'or',
+                                   'mail' => 'procyon@centre-de-recherche.fr']);
+
+    $this->_letter = $this->fixture('Class_Newsletter',
+                                    ['id' => 23,
+                                     'titre' => 'Alerte vega',
+                                     'id_panier' => 1,
+                                     'nb_notices' => 50,
+                                     'id_catalogue' => 0,
+                                     'expediteur' => 'professeur@centre-de-recherche.fr',
+                                     'contenu' => 'Golgoth aperçu azimut 234.53',
+                                     'last_distribution_date' => '',
+                                     'users' => [$this->alcor]]);
+
+    $this->onLoaderOfModel('Class_Notice')
+         ->whenCalled('getNoticesFromPreferences')
+         ->answers([$this->fixture('Class_Notice',
+                                   ['id' => 12,
+                                    'titre_principal' => 'UFO robot']),
+
+                    $this->fixture('Class_Notice',
+                                   ['id' => 14,
+                                    'titre_principal' => 'To test is to doubt',
+                                    'url_vignette' => 'http://server.com/test.png'])]);
+
+    $mail = $this->_letter
+      ->newMailFromTemplate($this->_letter->newTemplate(), $this->alcor);
+
+    $this->_text_content = $mail->getBodyText(true);
+    $this->_html_content = quoted_printable_decode($mail->getBodyHtml(true));
+  }
+
+
+  public function recordIds() {
+    return [[12], [14]];
+  }
+
+
+  /**
+   * @test
+   * @dataProvider recordIds
+   */
+  public function textShouldContainRecordUrl($record_id) {
+    $this->assertContains($this->_recordUrlOf($record_id), $this->_text_content);
+  }
+
+
+  /**
+   * @test
+   * @dataProvider recordIds
+   */
+  public function htmlShouldContainRecordLink($record_id) {
+    $this->_xpath->assertXPath($this->_html_content,
+                               '//a[@href="' . $this->_recordUrlOf($record_id) . '"]');
+  }
+
+
+  /** @test */
+  public function htmlShouldNotContainUfoRobotThumb() {
+    $this->_xpath->assertNotXPath($this->_html_content,
+                                  '//a[@href="' . $this->_recordUrlOf(12) . '"]//img');
+  }
+
+
+  /** @test */
+  public function htmlShouldContainsDoubtThumb() {
+    $this->_xpath->assertXPath($this->_html_content,
+                               '//a[@href="' . $this->_recordUrlOf(14) . '"]//img[@src="http://server.com/test.png"]',
+                               $this->_html_content);
+  }
+
+
+  protected function _recordUrlOf($id) {
+    return $this->_basedUrl('/recherche/viewnotice/id/' . $id);
+  }
+
+
+  protected function _basedUrl($url) {
+    return $this->_base_url . $url;
+  }
+}
diff --git a/tests/library/Class/WebService/SIGB/KohaTest.php b/tests/library/Class/WebService/SIGB/KohaTest.php
index a390e25ec8809b4ad9403b1aaf536358597e6f49..589fb5ca08e3a8fa8c6e1c33480e44b8855712d6 100644
--- a/tests/library/Class/WebService/SIGB/KohaTest.php
+++ b/tests/library/Class/WebService/SIGB/KohaTest.php
@@ -740,7 +740,7 @@ class KohaOperationsTest extends KohaTestCase {
   }
 
 
-    /** @test */
+  /** @test */
   function prolongerPretWithKohaCG55VersionShouldReturnErrorIfTooMany() {
     $this->mock_web_client
       ->whenCalled('open_url')
@@ -945,7 +945,7 @@ class KohaServiceGetNoticeHarryPotterWithRestrictionTest
     $this->mock_web_client = $this->mock();
 
     $this->service = Class_WebService_SIGB_Koha::getService(['url_serveur' => 'http://cat-aficg55.biblibre.com/cgi-bin/koha/ilsdi.pl',
-                                                       'Interdire_reservation_doc_dispo' => '1']);
+                                                             'Interdire_reservation_doc_dispo' => '1']);
 
     $this->mock_web_client
       ->whenCalled('open_url')
@@ -976,6 +976,7 @@ class KohaServiceGetNoticeHarryPotterWithRestrictionTest
 }
 
 
+
 class KohaServiceGetNoticeJardinEnfantWithItemOnTopTest extends KohaTestCase {
   public function setUp() {
     parent::setUp();
@@ -994,3 +995,32 @@ class KohaServiceGetNoticeJardinEnfantWithItemOnTopTest extends KohaTestCase {
     $this->assertEquals(1, count($this->jardins_enfant->getExemplaires()));
   }
 }
+
+
+
+class KohaServicePatroninfoReaderWithNoLibTest extends KohaTestCase {
+  public function setUp() {
+    parent::setUp();
+    $this->mock_web_client
+      ->whenCalled('open_url')
+      ->with('http://cat-aficg55.biblibre.com/cgi-bin/koha/ilsdi.pl?service=LookupPatron&id=012345&id_type=cardnumber')
+      ->answers(KohaFixtures::xmlLookupPatronLaure());
+
+    $this->mock_web_client
+      ->whenCalled('open_url')
+      ->with('http://cat-aficg55.biblibre.com/cgi-bin/koha/ilsdi.pl?service=GetPatronInfo&patron_id=572&show_contact=0&show_loans=1&show_holds=1')
+      ->answers(KohaFixtures::xmlGetPatronInfoLaure());
+
+    $this->laurent = $this->service
+      ->getEmprunteur(Class_Users::newInstance()
+                      ->setLogin('lafond')
+                      ->setPassword('afi')
+                      ->setIdabon('012345'));
+ }
+
+
+  /** @test */
+  public function laurendShouldNotHaveLibrary() {
+    $this->assertEmpty($this->laurent->getLibraryLabel());
+  }
+}
\ No newline at end of file
diff --git a/tests/library/ZendAfi/View/Helper/AvisTest.php b/tests/library/ZendAfi/View/Helper/AvisTest.php
index cae5c62c2e5e08a0da32f14f4c05060de8fcdec9..78ea8dbc0fa7bd28650c374bdaeaf291648cb4c7 100644
--- a/tests/library/ZendAfi/View/Helper/AvisTest.php
+++ b/tests/library/ZendAfi/View/Helper/AvisTest.php
@@ -36,12 +36,14 @@ class ViewHelperAvisTestWithAvisNotice extends ViewHelperTestCase {
     $millenium = new Class_Notice();
     $millenium
       ->setId(1128)
+      ->setTypeDoc(Class_TypeDoc::DVD)
       ->setTitrePrincipal('Millenium (Stieg Larsson)')
       ->setUrlVignette('');
 
     $millenium_with_vignette = new Class_Notice();
     $millenium_with_vignette
       ->setId(9867)
+      ->setTypeDoc(Class_TypeDoc::DVD)
       ->setTitrePrincipal('Millenium (Stieg Larsson)')
       ->setUrlVignette('http://amazon.com/vignette.png');
 
@@ -82,58 +84,85 @@ class ViewHelperAvisTestWithAvisNotice extends ViewHelperTestCase {
                        "//div[@class='contenu_critique']//img[@class='note_critique note-5'][@alt='note: 5']");
   }
 
+
   public function testNoteImgIsStarsFive() {
     $this->assertXPath($this->html,
                        "//img[@class='note_critique note-5'][contains(@src, 'stars-5.gif')]");
   }
 
+
   public function testAvisIsSuspenseIntense() {
     $this->assertQueryContentContains($this->html, 'p', "Suspense intense");
   }
 
+
   public function testDateIs18June() {
     $this->assertQueryContentContains($this->html, 'span.auteur_critique', '- 18 mars 2010');
   }
 
+
   public function testAuteurIsLolo() {
     $this->assertXPathContentContains($this->html,
                                       "//span[@class='auteur_critique']//a[contains(@href, '/blog/viewauteur/id/91')]",
                                       'Lolo');
   }
 
+
   public function testTitreNoticeIsMilleniumStiegLarsson() {
-    $this->assertQueryContentContains($this->html, 'div.critique h2', 'Millenium (Stieg Larsson)');
+    $this->assertXPath($this->html,
+                       '//div[@class="critique"]//h2[text()="Millenium (Stieg Larsson)"]');
   }
 
+
   public function testVignetteNotice() {
     $this->assertXPath($this->html,
                        "//div[@class='vignette_notice']//img[@src='http://amazon.com/vignette.png']");
   }
 
+
   public function testVignetteLinkToNotice() {
     $this->assertXPath($this->html,
                        "//div[@class='vignette_notice']/a[contains(@href,'/recherche/viewnotice/id/9867')]");
 
   }
 
+
   public function testVignetteLinkVoirLaNotice() {
     $this->assertXPathContentContains($this->html,
                                       "//div[@class='vignette_notice']/a[contains(@href,'/recherche/viewnotice/id/9867')]",
                                       'Voir la notice');
   }
 
+
   public function testReadSpeakerLink() {
     $this->assertXPath($this->html,
                        "//a[contains(@href, 'webreader.php')][contains(@onclick, 'blog/readavis?id=23')]".
                        "/img[contains(@src, 'read_speaker_listen.gif')]");
   }
 
+
   public function testNoModerationTag() {
     $this->assertNotXPath($this->html, "//div[@class='moderation']");
   }
+
+
+  /** @test */
+  public function recordThumbnailTitleAttributeShouldContainsTypeDoc() {
+    $this->assertXPath($this->html,
+                       '//div[@class="vignette_notice"]/a/img[@title="DVD : Millenium (Stieg Larsson)"]');
+  }
+
+
+  /** @test */
+  public function avisShouldContainsDVDIcon() {
+    $this->assertXPath($this->html,
+                       '//div[@class="vignette_notice"]/img[@class="icone_support"][contains(@src, "images/supports/famille_video_small.png")]');
+  }
 }
 
 
+
+
 class ViewHelperAvisTestAsBib extends ViewHelperTestCase {
   public function setUp() {
     parent::setUp();
diff --git a/tests/library/ZendAfi/View/Helper/ViewHelperTestCase.php b/tests/library/ZendAfi/View/Helper/ViewHelperTestCase.php
index 9cf02564de7db62faa6a893c31fd3a05c148919b..4d442180ee6ff253f62dfa62b75a6049bea90dc0 100644
--- a/tests/library/ZendAfi/View/Helper/ViewHelperTestCase.php
+++ b/tests/library/ZendAfi/View/Helper/ViewHelperTestCase.php
@@ -96,8 +96,8 @@ abstract class ViewHelperTestCase extends PHPUnit_Framework_TestCase {
 
     $this->view = new ZendAfi_Controller_Action_Helper_View();
 
-    if (!defined("URL_IMG"))
-      define("URL_IMG", 'public/opac/skins/original/images');
+    defineConstant("URL_IMG", 'public/opac/skins/original/images');
+    defineConstant("PATH_SKIN", "./public/opac/skins/original/");
 
     Class_AdminVar::newInstanceWithId('CACHE_ACTIF')->setValeur(false);