diff --git a/VERSIONS b/VERSIONS
index c93a7ed3081a0fdf9df0167aa86132a6f03307fb..7fc263f7b940386355c26020e3b3c83e58999e75 100644
--- a/VERSIONS
+++ b/VERSIONS
@@ -1,9 +1,46 @@
+23/04/2015 - v7.1.27
+
+ - ticket #23391 : Correction d'une régression dans le mode de dédoublonnage par identifiant.
+ - ticket #19079 : Correction de la modification des vignettes pour les périodiques.
+ - hotline#22305 : Respect des sauts de ligne dans les avis notice des bibliothécaires. 
+
+
+
+17/04/2015 - v7.0.15 - v7.1.25 v7.1.26
+ - ticket #18020 : Mise à jour de la gestion des réservations des postes multimédia.
+
+ - ticket #24018 : Correction d'un bug qui ajoutait des boîtes avec le même identifiant entre les profils partagés.
+
+
+
+14/04/2015 - v7.1.23 - v7.1.24
+
+ - ticket #23322 : Correction d'un bug qui empéchait la création de sous-catégories d'articles dans la nouvelle interface de gestion
+
+
+
+
+14/04/2015 - v7.0.14
+
+ - ticket #23080 : Correction d'un bug qui duplicait le résumé d'un album en note de la notice à l'indexation.
+
+ - ticket #23465 : Correction du lien pour accéder aux bibliothèques depuis le mode territoire
+
+
+
 30/032015 - v 7.1.22
+
  - ticket #18283 : RGAA
+
    - Amélioration de la conformité RGAA dans la banniere, les images, les permaliens, la boite de recherche, la boite de connexion, 
      la boite calendrier avec le tableau des jours, la boite kiosque de notice.
+
    - Pour faciliter la mise en place de charte graphique, les tailles du site paramétrées dans les profils peuvent être exprimées en pourcentage.
 
+
+
+30/03/2015 - v7.0.13
+
  - ticket #21695: Bibliothèque numérique : ajout d'un mode de visualisation en listes paginées.
                   Ceci permet d'améliorer grandement la vitesse d'affichage 
                   et de navigation dans les albums pour les grands volumes d'albums.
diff --git a/application/modules/admin/controllers/AlbumController.php b/application/modules/admin/controllers/AlbumController.php
index df8c8e5a33e0ee2637e7cf361e9c307c8a084144..d0ae3ef64c61f6ead94a7264126cdfdcced9c20b 100644
--- a/application/modules/admin/controllers/AlbumController.php
+++ b/application/modules/admin/controllers/AlbumController.php
@@ -128,7 +128,6 @@ class Admin_AlbumController extends ZendAfi_Controller_Action {
 	}
 
 
-
 	protected function _formImportDilicom() {
 		return $this->view
 			->newForm(['id' => 'import_dilicom', 'class' => 'form'])
@@ -140,7 +139,6 @@ class Admin_AlbumController extends ZendAfi_Controller_Action {
 	}
 
 
-
 	protected function _formImportEAD() {
 		return $this->view
 			->newForm(['id' => 'import_ead', 'class' => 'form'])
diff --git a/application/modules/admin/controllers/CmsController.php b/application/modules/admin/controllers/CmsController.php
index fc7f5f725c897270197383866d0a51bf4df90e79..bc29712ad96bd854c0cf3aaece6f7255469f4619 100644
--- a/application/modules/admin/controllers/CmsController.php
+++ b/application/modules/admin/controllers/CmsController.php
@@ -538,7 +538,9 @@ class Admin_CmsController extends ZendAfi_Controller_Action {
 		if (!Class_AdminVar::isArticlesListMode())
 			return 'admin/cms/index' . (!$model->isNew() ? '/id/' . $model->getId() : '');
 
-		return $this->view->url(['action' => 'index']);
+		return $this->view->absoluteUrl(['module' => 'admin',
+														 'controller' => 'cms',
+														 'action' => 'index']);
 	}
 
 
diff --git a/application/modules/admin/controllers/MultimediaController.php b/application/modules/admin/controllers/MultimediaController.php
index 3767d71b141a2ab5293d1ac21bd5885983c3a0c2..9f1760669a09edf952bd3efda8bfa3aa7c31d13e 100644
--- a/application/modules/admin/controllers/MultimediaController.php
+++ b/application/modules/admin/controllers/MultimediaController.php
@@ -39,10 +39,7 @@ class Admin_MultimediaController extends ZendAfi_Controller_Action {
 																					'elements' => $this->getConfigFields()],
 
 														 'config_auto' => ['legend' => 'Réservation automatique',
-																							 'elements' => $this->getConfigAutoFields()],
-
-														 'config_auto_closing_days' => ['legend' => 'Réservation les jours de fermetures',
-																							 'elements' => $this->getConfigClosingDaysFields()]
+																							 'elements' => $this->getConfigAutoFields()]
 														 ]
 						];
 	}
@@ -131,29 +128,6 @@ disponible',
 	}
 
 
-	public function getConfigClosingDaysFields() {
-		$hours_select = Class_Multimedia_Location::getPossibleHours(30);
-
-
-		$fields['autohold_for_closing_days'] = ['element' => 'checkbox',
-													 'options' => ['label' => 'Autoriser les réservations automatique pour les jours de fermeture
-disponible',
-																				 'title' => 'Permet de définir des jours d\'utilisation des postes sans possibilités de réservation de bokeh',
-																				 'required' => true,
-																				 'allowEmpty' => false]];
-
-
-		$field_labels = ['open_hour' => $this->view->_('Heure d\'ouverture'),
-										 'close_hour' => $this->view->_('Heure de fermeture')];
-
-		foreach ($field_labels as $field => $label)
-			$fields[$field] = ['element' => 'select', 'options' => ['label' => $label,
-																															'multiOptions' => $hours_select]];
-
-		return $fields;
-						}
-
-
 	public function browseAction() {
 		if (!$location = Class_Multimedia_Location::find((int)$this->_getParam('id'))) {
 			$this->_redirect('/admin/multimedia');
diff --git a/application/modules/admin/controllers/OuverturesController.php b/application/modules/admin/controllers/OuverturesController.php
index 4f222939aadda5ecbbbc8abbe4dd8e081041a31d..304f30ae668f0b78fe9b3f774856203c92b35638 100644
--- a/application/modules/admin/controllers/OuverturesController.php
+++ b/application/modules/admin/controllers/OuverturesController.php
@@ -81,7 +81,7 @@ class Admin_OuverturesController extends ZendAfi_Controller_Action {
 		}
 
 		parent::indexAction();
-		$this->formatTitreWithLibelleBib('%s: plages d\'ouverture');
+		$this->formatTitreWithLibelleBib('%s: plages ouvertes à la réservation des postes multimédia');
 	}
 
 
diff --git a/application/modules/admin/controllers/ZoneController.php b/application/modules/admin/controllers/ZoneController.php
index cba055c472eac28e2ca15897a9fd2f2b52d4dc0d..d2c88d13a6dbbbbf7050cdb9576cbfe4c3000c10 100644
--- a/application/modules/admin/controllers/ZoneController.php
+++ b/application/modules/admin/controllers/ZoneController.php
@@ -16,9 +16,9 @@
  *
  * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
  * along with BOKEH; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA 
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
  */
-class Admin_ZoneController extends Zend_Controller_Action
+class Admin_ZoneController extends ZendAfi_Controller_Action
 {
 
 	//---------------------------------------------------------------------
@@ -33,11 +33,11 @@ class Admin_ZoneController extends Zend_Controller_Action
 	protected function _checkPost($zone) {
 		$this->view->zone = $zone;
 
-		if (!$this->_request->isPost()) 
+		if (!$this->_request->isPost())
 			return;
 
 		if ($zone->updateAttributes($_POST)->save())
-				$this->_redirect('admin/zone/index');
+			$this->_redirect('admin/zone/index');
 	}
 
 	//---------------------------------------------------------------------
@@ -78,47 +78,35 @@ class Admin_ZoneController extends Zend_Controller_Action
 	//---------------------------------------------------------------------
 	// placer les bibliotheques sur la carte
 	//---------------------------------------------------------------------
-	function placerbibsAction()
-	{
-		$this->view->titre = 'Placement des bibliothèques sur la carte';
-		$id_zone=$this->_request->getParam("id_zone");
+	function placerbibsAction()	{
+		$this->view->titre = $this->view->_('Placement des bibliothèques sur la carte');
+
+		if(!$zone = Class_Zone::find($this->_request->getParam('id_zone')))
+			return $this->_redirect('admin/zone/index');
+
+		if(!$bibs = $zone->getVisibleBibs())
+			return $this->_redirect('admin/zone/index');
 
-		$bibs = fetchAll("select * from bib_c_site where ID_ZONE=$id_zone and VISIBILITE > 0");
-		// Validation
-		if ($this->_request->isPost())
-		{
-			$i = 0;
-			foreach($bibs as $bib)
-			{
-				// Positions des bibs
-				$id_bib=$bib['ID_SITE'];
-				$data = array();
-				$data["libelle"]=$_POST["libelle_".$i];
-				$data["posX"]=$_POST["posX_".$i];
-				$data["posY"]=$_POST["posY_".$i];
-				$data["posPoint"]=$_POST["posPoint_".$i];
-				$data["profilID"]=$_POST["profilID_".$i];
-				$props=addslashes(ZendAfi_Filters_Serialize::serialize($data));
-				sqlExecute("update bib_c_site set AFF_ZONE='$props' where ID_SITE=$id_bib");
-
-				// Proprietes du label
-				$couleur_texte=$_POST["couleur_texte"];
-				$couleur_ombre=$_POST["couleur_ombre"];
-				$taille_fonte=$_POST["taille_fonte"];
-				sqlExecute("update bib_c_zone set COULEUR_TEXTE='$couleur_texte', COULEUR_OMBRE='$couleur_ombre', TAILLE_FONTE='$taille_fonte' where ID_ZONE=$id_zone");
-				$i++;
+		if ($this->_request->isPost()) {
+			foreach($bibs as $bib) {
+				$bib_id = $bib->getId();
+				$data = ['posX' => $this->_request->getParam('posX_' . $bib_id, 0),
+								 'posY' => $this->_request->getParam('posY_' . $bib_id, 0),
+								 'posPoint' => $this->_request->getParam('posPoint_' . $bib_id),
+								 'profilID' => $this->_request->getParam('profilID_' . $bib_id, 0)];
+
+				$aff_zone = ZendAfi_Filters_Serialize::serialize($data);
+				$bib->setAffZone($aff_zone)->save();
 			}
-			$this->_redirect('admin/zone/index');
+
+			$zone->setCouleurTexte($this->_request->getParam('couleur_texte'))
+					 ->setCouleurOmbre($this->_request->getParam('couleur_ombre'))
+					 ->setTailleFonte($this->_request->getParam('taille_fonte'))
+					 ->save();
 		}
 
-		// Entree formulaire
-		$this->view->zone= Class_Zone::getLoader()->find($id_zone);
-		if(!$this->view->zone->COULEUR_TEXTE) $this->view->zone->COULEUR_TEXTE="#ffffff";
-		if(!$this->view->zone->COULEUR_OMBRE) $this->view->zone->COULEUR_OMBRE="#000000";
-		if(!$this->view->zone->TAILLE_FONTE) $this->view->zone->TAILLE_FONTE="12";
-		
-		// Caracteristiques de l'image
-		$this->view->image=$this->view->zone->getImageZone($this->view->zone->IMAGE,true);
-		$this->view->bibs=$bibs;
+		$this->view->zone = $zone;
+		$this->view->image= $this->view->zone->getImageZone($zone->getImage(), true);
+		$this->view->bibs = $bibs;
 	}
 }
\ No newline at end of file
diff --git a/application/modules/admin/views/scripts/zone/placerbibs.phtml b/application/modules/admin/views/scripts/zone/placerbibs.phtml
index d2b9ff513bbce6b60b192e660d40fb6b57db39ae..d9cd208a6da3ea52379a92f4ffd2e32948188a4f 100644
--- a/application/modules/admin/views/scripts/zone/placerbibs.phtml
+++ b/application/modules/admin/views/scripts/zone/placerbibs.phtml
@@ -4,114 +4,124 @@
 <script type="text/javascript" src="<?php echo URL_ADMIN_JS?>color_picker/jquery.vreboton.ColorPicker.js"> </script>
 
 <script type="text/javascript">
-var current_index=0;
-// Color picker
-	jQuery(function($)
-	{
-		$("#couleur_texte").attachColorPicker();
-		$("#couleur_texte").change(function()	{	$('span').css('color',$('#couleur_texte').val()) });
-		$("#couleur_ombre").attachColorPicker();
-		$("#couleur_ombre").change(function()	{	$('span').css('text-shadow','1px 0px 5px ' + $('#couleur_ombre').val()) });
-	});
-
-// Change valeur proprietes
-	$(function()
-	{
-		$('#posPoint_aff').change(function()
-		{
-			$('#posPoint_'+current_index).attr('value',$(this).val());
-			memoPos(current_index,parseInt($('#bib'+current_index).css('left')),parseInt($('#bib'+current_index).css('top')));
-		});
-
-		$('#select_clef_profil').change(function()
-		{
-			$('#profilID_'+current_index).attr('value',$(this).val());
-		});
-
-		$('#libelle_aff').keyup(function()
-		{
-			$('#libelle_'+current_index).attr('value',$(this).val());
-			$('#bib'+current_index).text($(this).val());
-			memoPos(current_index,parseInt($('#bib'+current_index).css('left')),parseInt($('#bib'+current_index).css('top')));
-		});
-	});
-
-// Memo coordonnees
-	function memoPos(index,nX,nY)
-	{
-		// Memo des coordonnées
-		var posContainer=$('#image_container').offset();
-		$('#posX_'+index).attr('value',parseInt(nX-posContainer.left));
-		$('#posY_'+index).attr('value',parseInt(nY-posContainer.top));
-
-		// Positionnement du point
-		var oPoint=$('#point_'+index);
-		var hauteur_point=oPoint.outerHeight(true);
-		var largeur_point=oPoint.outerWidth(true);
-		var hauteur=$('#bib'+index).outerHeight(true);
-		var largeur=$('#bib'+index).outerWidth(true);
-		var position=$('#posPoint_'+index).val();
-
-		//		if(position=="dessus") par défaut
-		pointY=nY-hauteur_point;
-		pointX=nX+(largeur/2)-(largeur_point/2);
-
-		if(position=="dessous")
-		{
-			pointY=nY+hauteur;
-			pointX=nX+(largeur/2)-(largeur_point/2);
-		}
-		if(position=="droite")
-		{
-			pointY=nY+(hauteur/2)-(hauteur_point/2);
-			pointX=nX+largeur+2;
-		}
-		if(position=="gauche")
-		{
-			pointY=nY+(hauteur/2)-(hauteur_point/2);
-			pointX=nX-largeur_point-2;
-		}
-		oPoint.css('left',parseInt(pointX)+'px');
-		oPoint.css('top',parseInt(pointY)+'px');
-	}
-
-	// Changement de la fonte
-	function changeFonte()
-	{
-		$('span').css('font-size',$('#taille_fonte').val()+'px');
-		$('span').each(function (i)
-		{
-			memoPos(i,parseInt(this.style.left),parseInt(this.style.top));
-		});
-	}
+ var current_index=0;
+ // Color picker
+ jQuery(function($)
+				{
+	 $("#couleur_texte").attachColorPicker();
+	 $("#couleur_texte").change(function()	{	$('span').css('color',$('#couleur_texte').val()) });
+	 $("#couleur_ombre").attachColorPicker();
+	 $("#couleur_ombre").change(function()	{	$('span').css('text-shadow','1px 0px 5px ' + $('#couleur_ombre').val()) });
+ });
+
+ // Change valeur proprietes
+ $(function()
+	 {
+	 $('#posPoint_aff').change(function()
+														 {
+		 $('#posPoint_'+current_index).attr('value',$(this).val());
+		 memoPos(current_index,parseInt($('#bib'+current_index).css('left')),parseInt($('#bib'+current_index).css('top')));
+	 });
+
+	 $('#select_clef_profil').change(function()
+																	 {
+		 $('#profilID_'+current_index).attr('value',$(this).val());
+	 });
+
+	 $('#libelle_aff').keyup(function()
+													 {
+		 $('#libelle_'+current_index).attr('value',$(this).val());
+		 $('#bib'+current_index).text($(this).val());
+		 memoPos(current_index,parseInt($('#bib'+current_index).css('left')),parseInt($('#bib'+current_index).css('top')));
+	 });
+ });
+
+ // Memo coordonnees
+ function memoPos(index,nX,nY)
+ {
+	 // Memo des coordonnées
+	 var posContainer=$('#image_container').offset();
+	 $('#posX_'+index).attr('value',parseInt(nX-posContainer.left));
+	 $('#posY_'+index).attr('value',parseInt(nY-posContainer.top));
+
+	 // Positionnement du point
+	 var oPoint=$('#point_'+index);
+	 var hauteur_point=oPoint.outerHeight(true);
+	 var largeur_point=oPoint.outerWidth(true);
+	 var hauteur=$('#bib'+index).outerHeight(true);
+	 var largeur=$('#bib'+index).outerWidth(true);
+	 var position=$('#posPoint_'+index).val();
+
+	 //		if(position=="dessus") par défaut
+	 pointY=nY-hauteur_point;
+	 pointX=nX+(largeur/2)-(largeur_point/2);
+
+	 if(position=="dessous")
+	 {
+		 pointY=nY+hauteur;
+		 pointX=nX+(largeur/2)-(largeur_point/2);
+	 }
+	 if(position=="droite")
+	 {
+		 pointY=nY+(hauteur/2)-(hauteur_point/2);
+		 pointX=nX+largeur+2;
+	 }
+	 if(position=="gauche")
+	 {
+		 pointY=nY+(hauteur/2)-(hauteur_point/2);
+		 pointX=nX-largeur_point-2;
+	 }
+	 oPoint.css('left',parseInt(pointX)+'px');
+	 oPoint.css('top',parseInt(pointY)+'px');
+ }
+
+ // Changement de la fonte
+ function changeFonte()
+ {
+	 $('span').css('font-size',$('#taille_fonte').val()+'px');
+	 $('span').each(function (i)
+									{
+		 memoPos(i,parseInt(this.style.left),parseInt(this.style.top));
+	 });
+ }
 </script>
 
-<?php 
-echo '<h3>Territoire : '.$this->zone->LIBELLE.'</h3>';
+<?php
+echo '<h3>Territoire : '.$this->zone->getLibelle.'</h3>';
 
 echo '<div class="form" align="center">';
 echo '<div id="image_container" style="width:'.$this->image[0].'px;height:'.$this->image[1].'px;background-image:url(\''.$this->image["url"].'\');" align="left">';
-if($this->bibs)
-{
-	$index=0;
+if($this->bibs) {
 	$hidden='';
-	foreach($this->bibs as $bib)
-	{
-		// Proprietes
-		$props=ZendAfi_Filters_Serialize::unserialize($bib["AFF_ZONE"]);
-		if (!$libelle = $props["libelle"]) $libelle=$bib["VILLE"];
-		if (!$posX = $props["posX"]) $posX=0;
-		if (!$posY = $props["posY"]) $posY=12*$index;
-		if (!$posPoint = $props["posPoint"]) $posPoint="gauche";
-		if (!$profilID = $props["profilID"]) $profilID = 1;
-		if($index==0){$libelle_aff=$libelle; $posPoint_aff=$posPoint;$nomBib_aff=$bib["LIBELLE"];}
+	$default_position = 0;
+	foreach($this->bibs as $bib) {
+		$index = $bib->getId();
+
+		$props = ['libelle' => $bib->getVille(),
+							'posX' => 0,
+							'posY' => 0,
+							'posPoint' => 'gauche',
+							'profilID' => 0];
+
+		$unserialize = ($unserialize = ZendAfi_Filters_Serialize::unserialize($bib->getAffZone())) ? $unserialize : [];
+
+		$props = array_merge($props, $unserialize);
+
+		if (0 == $props["posY"])
+			$posY = $default_position = 12 + $default_position;
+
+		$libelle = $props['libelle'];
+		$posX = $props['posX'];
+		$posY = $props['posY'];
+		$posPoint = $props['posPoint'];
+		$profilID = $props['profilID'];
 
 		// Champ draggable
-		echo'<span id="bib'.$index.'" style="position:absolute;cursor:pointer;font-family:Verdana;font-size:'.$this->zone->TAILLE_FONTE.'px;font-weight:bold;color:'.$this->zone->COULEUR_TEXTE.';white-space:nowrap;text-shadow: 1px 0px 5px '.$this->zone->COULEUR_OMBRE.'">'.$libelle.'</span>';
+		echo'<span id="bib'.$index.'" style="position:absolute;cursor:pointer;font-family:Verdana;font-size:'.$this->zone->getTailleFonte().'px;font-weight:bold;color:'.$this->zone->getCouleurTexte().';white-space:nowrap;text-shadow: 1px 0px 5px '.$this->zone->getCouleurOmbre().'">'.$libelle.'</span>';
 
 		// Champs du post
-		$hidden.='<input id="idbib_'.$index.'" name="idbib_'.$index.'" type="hidden" value="'.$bib["ID_SITE"].'">';
-		$hidden.='<input id="nomBib_'.$index.'" type="hidden" value="'.$bib["LIBELLE"].'">';
+		$hidden.='<input id="idbib_'.$index.'" name="idbib_'.$index.'" type="hidden" value="'.$bib->getId().'">';
+		$hidden.='<input id="nomBib_'.$index.'" type="hidden" value="'.$bib->getLibelle().'">';
 		$hidden.='<input id="posX_'.$index.'" name="posX_'.$index.'" type="hidden" value="'.$posX.'">';
 		$hidden.='<input id="posY_'.$index.'" name="posY_'.$index.'" type="hidden" value="'.$posY.'">';
 		$hidden.='<input id="libelle_'.$index.'" name="libelle_'.$index.'" type="hidden" value="'.$libelle.'">';
@@ -120,108 +130,112 @@ if($this->bibs)
 		$hidden.='<img id="point_'.$index.'" src="'.URL_ADMIN_IMG.'picto/point_map.png" style="position:absolute;">';
 
 		// Javascript d'initialisation
-		?>
-			<script>
-			$(function()
-			{
-				posContainer=$('#image_container').offset();
-				posX=parseInt(<?php echo $posX ?>+posContainer.left);
-				posY=parseInt(<?php echo $posY ?>+posContainer.top);
-				memoPos(<?php echo $index ?>,posX,posY)
-				oObj=$('#bib<?php echo $index ?>');
-				oObj.draggable
-				({
-					containment: 'parent',
-					drag: function(event, ui)
-					{	memoPos(<?php echo $index ?>,ui.position.left,ui.position.top)}
-				})
-				.css('left',posX+'px')
-				.css('top',posY+'px')
-				.mousedown(function()
-				{
-					$('#nomBib_aff').attr('value',$('#nomBib_<?php echo $index ?>').val());
-					$('#libelle_aff').attr('value',$('#libelle_<?php echo $index ?>').val());
-
-					var valeur=$('#posPoint_<?php echo $index ?>').val();
-					$('#posPoint_aff > option').attr('selected','');
-					$('#posPoint_aff option[value='+valeur+']').attr('selected','selected');
-
-					var profil_id=$('#profilID_<?php echo $index ?>').val();
-					$('#select_clef_profil option').attr('selected', '');
-					$('#select_clef_profil option[value='+profil_id+']').attr('selected','selected');
-
-					current_index=<?php echo $index ?>;
-				});
-			});
-
-			</script>
-		<?php
-		$index++;
+?>
+	<script>
+	 $(function()
+		 {
+		 posContainer=$('#image_container').offset();
+		 posX=parseInt(<?php echo $posX ?>+posContainer.left);
+		 posY=parseInt(<?php echo $posY ?>+posContainer.top);
+		 memoPos(<?php echo $index ?>,posX,posY)
+		 oObj=$('#bib<?php echo $index ?>');
+		 oObj.draggable
+		 ({
+			 containment: 'parent',
+			 drag: function(event, ui)
+			 {	memoPos(<?php echo $index ?>,ui.position.left,ui.position.top)}
+		 })
+				 .css('left',posX+'px')
+				 .css('top',posY+'px')
+				 .mousedown(function()
+										{
+			 $('#nomBib_aff').attr('value',$('#nomBib_<?php echo $index ?>').val());
+			 $('#libelle_aff').attr('value',$('#libelle_<?php echo $index ?>').val());
+
+			 var valeur=$('#posPoint_<?php echo $index ?>').val();
+			 $('#posPoint_aff > option').attr('selected','');
+			 $('#posPoint_aff option[value='+valeur+']').attr('selected','selected');
+
+			 var profil_id=$('#profilID_<?php echo $index ?>').val();
+			 $('#select_clef_profil option').attr('selected', '');
+			 $('#select_clef_profil option[value='+profil_id+']').attr('selected','selected');
+
+			 current_index=<?php echo $index ?>;
+		 });
+	 });
+
+	</script>
+	<?php
+	$index++;
 	}
 	echo '</div>';
+
+	$nomBib_aff = '';
+	$libelle_aff = '';
+	$posPoint_aff = '';
 	?>
 
-<br />
-<form name="form" action="<?php echo BASE_URL ?>/admin/zone/placerbibs/id_zone/<?php echo $this->zone->ID_ZONE; ?>" method="post">
-<fieldset>
-	<legend>Propriétés</legend>
-	<table>
-		<tr>
-			<td class="droite" style="width:150px">Bibliothèque</td>
-			<td class="gauche"><input type="text" id="nomBib_aff" size="40" value="<?php echo $nomBib_aff ?>" readonly="readonly"></td>
-		</tr>
-		<tr>
-			<td class="droite">Libellé à afficher</td>
-			<td class="gauche"><input type="text" id="libelle_aff" size="40" value="<?php echo $libelle_aff ?>"></td>
-		</tr>
-		<tr>
-			<td class="droite">Position du point</td>
-			<td class="gauche"><?php echo $this->formSelect("posPoint_aff",$posPoint_aff,"",array("dessus" => "au dessus","gauche"=>"à gauche","droite"=>"à droite","dessous"=>"en dessous"))?></td>
-		</tr>
-		<tr>
-			<td class="droite">Lien vers la page</td>
-			<td class="gauche"><?php echo $this->comboProfils(); ?></td>
-		</tr>
-
-		<tr>
-			<td colspan="2"><h3>Etiquettes</h3></td>
-		</tr>
-
-		<tr>
-			<td class="droite">Taille de la police</td>
-			<td class="gauche"><?php echo $this->tagSlider("taille_fonte",$this->zone->TAILLE_FONTE,5,40,1,"changeFonte();") ?></td>
-		</tr>
-		
-		<tr>
-			<td class="droite">Couleur du texte</td>
-			<td class="gauche"><input type="text" id="couleur_texte" name="couleur_texte" size="8" value="<?php echo $this->zone->COULEUR_TEXTE;?>" /></td>
-		</tr>
-
-		<tr>
-			<td class="droite">Couleur de l'ombre</td>
-			<td class="gauche"><input type="text" id="couleur_ombre" name="couleur_ombre" size="8" value="<?php echo $this->zone->COULEUR_OMBRE;?>" /></td>
-		</tr>
-
-	</table>
-</fieldset>
-
-	<?php echo $hidden; ?>
+	<br />
+	<form name="form" action="<?php echo BASE_URL ?>/admin/zone/placerbibs/id_zone/<?php echo $this->zone->getId(); ?>" method="post">
+		<fieldset>
+			<legend>Propriétés</legend>
+			<table>
+				<tr>
+					<td class="droite" style="width:150px">Bibliothèque</td>
+					<td class="gauche"><input type="text" id="nomBib_aff" size="40" value="<?php echo $nomBib_aff ?>" readonly="readonly"></td>
+				</tr>
+				<tr>
+					<td class="droite">Libellé à afficher</td>
+					<td class="gauche"><input type="text" id="libelle_aff" size="40" value="<?php echo $libelle_aff ?>"></td>
+				</tr>
+				<tr>
+					<td class="droite">Position du point</td>
+					<td class="gauche"><?php echo $this->formSelect("posPoint_aff",$posPoint_aff,"",array("dessus" => "au dessus","gauche"=>"à gauche","droite"=>"à droite","dessous"=>"en dessous"))?></td>
+				</tr>
+				<tr>
+					<td class="droite">Lien vers la page</td>
+					<td class="gauche"><?php echo $this->comboProfils('ALL', 'ALL', 0, false, true); ?></td>
+				</tr>
+
+				<tr>
+					<td colspan="2"><h3>Etiquettes</h3></td>
+				</tr>
+
+				<tr>
+					<td class="droite">Taille de la police</td>
+					<td class="gauche"><?php echo $this->tagSlider("taille_fonte",$this->zone->TAILLE_FONTE,5,40,1,"changeFonte();") ?></td>
+				</tr>
+
+				<tr>
+					<td class="droite">Couleur du texte</td>
+					<td class="gauche"><input type="text" id="couleur_texte" name="couleur_texte" size="8" value="<?php echo $this->zone->getCouleurTexte();?>" /></td>
+				</tr>
+
+				<tr>
+					<td class="droite">Couleur de l'ombre</td>
+					<td class="gauche"><input type="text" id="couleur_ombre" name="couleur_ombre" size="8" value="<?php echo $this->zone->getCouleurOmbre();?>" /></td>
+				</tr>
+
+			</table>
+		</fieldset>
+
+		<?php echo $hidden; ?>
 		<table>
 			<tr>
 				<td align="right" style="padding-right:5px;"><?php echo $this->bouton('type=V'); ?> </td>
-				<td align="left" style="padding-left:5px;"> <?php echo $this->bouton('id=29','picto=del.gif','texte=Annuler','url='.BASE_URL.'/admin/zone','largeur=120px'); ?></td>
+				<td align="left" style="padding-left:5px;"> <?php echo $this->bouton('id=29','picto=back.gif','texte=Retour','url='.BASE_URL.'/admin/zone','largeur=120px'); ?></td>
 			</tr>
 		</table>
 	</form>
 	<?php
-}
-else
-{
+	}
+	else
+	{
+		echo '</div>';
+		echo BR.BR.'<p class="error">Il n\'y a aucune bibliothèque visible dans ce territoire.</p>';
+		echo BR.'<div align="center">'.$this->bouton('id=29','picto=retour.gif','texte=Retour','url='.BASE_URL.'/admin/zone','largeur=120px').'</div>'.BR;
+	}
 	echo '</div>';
-	echo BR.BR.'<p class="error">Il n\'y a aucune bibliothèque visible dans ce territoire.</p>';
-	echo BR.'<div align="center">'.$this->bouton('id=29','picto=retour.gif','texte=Retour','url='.BASE_URL.'/admin/zone','largeur=120px').'</div>'.BR;
-}
-echo '</div>';
 
 
-?>
+	?>
diff --git a/application/modules/opac/controllers/AbonneController.php b/application/modules/opac/controllers/AbonneController.php
index 9e53d632dbe698cc1d2c349327e3f0fc4f841b3e..9bb51f1571c8b555fd83f9022aef796e0364fa84 100644
--- a/application/modules/opac/controllers/AbonneController.php
+++ b/application/modules/opac/controllers/AbonneController.php
@@ -573,7 +573,6 @@ class AbonneController extends ZendAfi_Controller_Action {
 
 		$response = new StdClass();
 		$response->auth = 0;
-		$response->until = '';
 
 		$request = Class_Multimedia_AuthenticateRequest::newWithRequest($this->_request);
 		if ($user = $request->getUser()) {
@@ -591,9 +590,13 @@ class AbonneController extends ZendAfi_Controller_Action {
 		}
 
 		$response->auth = 1;
-		$response->until = date('c', $request->getCurrentHoldEnd());
+		$response->holding = $request->canHoldingForToDay();
+		$response->holded = $request->isSuccessHolding();
+		$response->until = '';
+		if($response->holded) $response->until = date('c', $request->getCurrentHoldEnd());
 
 		$this->_response->setBody(json_encode($response));
+
 	}
 
 
@@ -618,6 +621,7 @@ class AbonneController extends ZendAfi_Controller_Action {
 
 		/* Vérification du quota sur le jour choisi */
 		$day = $this->_getParam('day');
+		$this->view->location = $bean->getLocation()->getLibelleBib();
 		$quotaErrorType = null;
 		if (null != $day) {
 			$quotaErrorType = $this->_user->getMultimediaQuotaErrorForDay($day);
@@ -686,6 +690,7 @@ class AbonneController extends ZendAfi_Controller_Action {
 	  return result;';
 
 		$this->view->beforeShowDay = $beforeShowDay;
+		$this->view->location = $bean->getLocation()->getLibelleBib();
 		$this->view->timelineActions = $this->_getTimelineActions('day');
 	}
 
@@ -719,6 +724,7 @@ class AbonneController extends ZendAfi_Controller_Action {
 
 		$this->view->timelineActions = $this->_getTimelineActions('hours');
 		$this->view->form = $this->multimediaHoldHoursForm($bean, $location);
+		$this->view->day = strftime('%d %B %Y', strtotime($bean->day));
 	}
 
 
@@ -741,6 +747,10 @@ class AbonneController extends ZendAfi_Controller_Action {
 
 		$this->view->groups = $bean->getGroups();
 		$this->view->timelineActions = $this->_getTimelineActions('group');
+		$this->view->location = $bean->getLocation()->getLibelleBib();
+		$this->view->day = strftime('%d %B %Y', strtotime($bean->day));
+		$this->view->time = str_replace(':', 'h', $bean->time);
+		$this->view->duration = $bean->duration . 'mn';
 	}
 
 
@@ -752,6 +762,11 @@ class AbonneController extends ZendAfi_Controller_Action {
 		$this->view->devices = $bean->getGroup()->getHoldableDevicesForDateTimeAndDuration($bean->day,
 																																											 $bean->time,
 																																											 $bean->duration);
+		$this->view->location = $bean->getLocation()->getLibelleBib();
+		$this->view->day = strftime('%d %B %Y', strtotime($bean->day));
+		$this->view->time = str_replace(':', 'h', $bean->time);
+		$this->view->duration = $bean->duration . 'mn';
+		$this->view->group = $bean->getGroup()->getLibelle();
 	}
 
 
diff --git a/application/modules/opac/views/scripts/abonne/multimedia-hold-day.phtml b/application/modules/opac/views/scripts/abonne/multimedia-hold-day.phtml
index ce55ca1fcc4277c560a74abb01e4198ae2c230d5..0696b91d9dbdbbf01a913aed588debf7157ab640 100644
--- a/application/modules/opac/views/scripts/abonne/multimedia-hold-day.phtml
+++ b/application/modules/opac/views/scripts/abonne/multimedia-hold-day.phtml
@@ -2,6 +2,11 @@
 <?php echo $this->timeline($this->timelineActions);?>
 
 <div class="workflow_step">
+	<div>
+		<ul>
+			<li><?php echo sprintf('%s : %s', $this->_('Lieu'), $this->escape($this->location));?></li>
+		</ul>
+	</div>
 	<h2><?php echo $this->_('Pour quel jour ?');?></h2>
 	<?php if ($this->quotaError) { ?>
 	<div class="error"><?php echo $this->quotaError;?></div>
@@ -21,4 +26,4 @@
 	<div id="hold-day" class="calendar"></div>
 </div>
 
-<?php $this->closeBoite();?>
\ No newline at end of file
+<?php $this->closeBoite();?>
diff --git a/application/modules/opac/views/scripts/abonne/multimedia-hold-device.phtml b/application/modules/opac/views/scripts/abonne/multimedia-hold-device.phtml
index bc9c175ea357f9a001901c4f1a258d2ff89a3500..33c51db1dc7ab5248fb6c765d446273a664af537 100644
--- a/application/modules/opac/views/scripts/abonne/multimedia-hold-device.phtml
+++ b/application/modules/opac/views/scripts/abonne/multimedia-hold-device.phtml
@@ -3,6 +3,16 @@
 
 
 <div class="workflow_step">
+	<div>
+		<ul>
+			<li><?php echo sprintf('%s : %s', $this->_('Lieu'), $this->escape($this->location));?></li>
+			<li><?php echo sprintf('%s : %s', $this->_('Jour'), $this->escape($this->day));?></li>
+			<li><?php echo sprintf('%s : %s', $this->_('À partir de'), $this->escape($this->time));?></li>
+			<li><?php echo sprintf('%s : %s', $this->_('Durée'), $this->escape($this->duration));?></li>
+			<li><?php echo sprintf('%s : %s', $this->_('Secteur'), $this->escape($this->group));?></li>
+		</ul>
+	</div>
+
 	<h2><?php echo $this->_('Quel poste ?') ?></h2>
 	<ul>
 	<?php
@@ -12,4 +22,4 @@
   </ul>
 </div>
 
-<?php $this->closeBoite();?>
\ No newline at end of file
+<?php $this->closeBoite();?>
diff --git a/application/modules/opac/views/scripts/abonne/multimedia-hold-group.phtml b/application/modules/opac/views/scripts/abonne/multimedia-hold-group.phtml
index 6bde170da33e1a124586956209818f97986ddd4c..60bf6d4f8aa00f4989246667309721a154801f11 100644
--- a/application/modules/opac/views/scripts/abonne/multimedia-hold-group.phtml
+++ b/application/modules/opac/views/scripts/abonne/multimedia-hold-group.phtml
@@ -2,6 +2,15 @@
 <?php echo $this->timeline($this->timelineActions);?>
 
 <div class="workflow_step">
+	<div>
+		<ul>
+			<li><?php echo sprintf('%s : %s', $this->_('Lieu'), $this->escape($this->location));?></li>
+			<li><?php echo sprintf('%s : %s', $this->_('Jour'), $this->escape($this->day));?></li>
+			<li><?php echo sprintf('%s : %s', $this->_('À partir de'), $this->escape($this->time));?></li>
+			<li><?php echo sprintf('%s : %s', $this->_('Durée'), $this->escape($this->duration));?></li>
+		</ul>
+	</div>
+
 	<h2><?php echo $this->_('Quel secteur ?') ?></h2>
 	<ul>
 	<?php
@@ -13,4 +22,4 @@
 	</ul>
 </div>
 
-<?php $this->closeBoite();?>
\ No newline at end of file
+<?php $this->closeBoite();?>
diff --git a/application/modules/opac/views/scripts/abonne/multimedia-hold-hours.phtml b/application/modules/opac/views/scripts/abonne/multimedia-hold-hours.phtml
index c8bf5d8907ddcb06a3559d943f4c6bb14064dbde..faf53fb3e9991def3273ea30c526ff8e6e481ab7 100644
--- a/application/modules/opac/views/scripts/abonne/multimedia-hold-hours.phtml
+++ b/application/modules/opac/views/scripts/abonne/multimedia-hold-hours.phtml
@@ -2,6 +2,13 @@
 <?php echo $this->timeline($this->timelineActions);?>
 
 <div class="workflow_step">
+	<div>
+		<ul>
+			<li><?php echo sprintf('%s : %s', $this->_('Lieu'), $this->escape($this->location));?></li>
+			<li><?php echo sprintf('%s : %s', $this->_('Jour'), $this->escape($this->day));?></li>
+		</ul>
+	</div>
+
 	<h2><?php echo $this->_('Quand ?') ?></h2>
 	<?php if ($this->error) { ?>
 	<div class="error">
@@ -12,4 +19,4 @@
   <?php echo $this->renderForm($this->form) ?>
 </div>
 
-<?php $this->closeBoite();?>
\ No newline at end of file
+<?php $this->closeBoite();?>
diff --git a/application/modules/push/controllers/MultimediaController.php b/application/modules/push/controllers/MultimediaController.php
index f3965d79f17073f4dd03bc49abb0c4fafe7ab752..3b498dddae2efccf8f85aef5776107e038d3d8d6 100644
--- a/application/modules/push/controllers/MultimediaController.php
+++ b/application/modules/push/controllers/MultimediaController.php
@@ -96,31 +96,31 @@ class Push_MultimediaController extends Zend_Controller_Action {
 
 	public function createBorrowerAction() {
 
-		if($infoUser = $this->checkInfoForAbonneAfim())
+		if($infoUser = $this->checkInfoForAbonneAfim('Create borrower multimedia start'))
 			$this->_response->setBody(Class_Multimedia_Users::getInstance()->createUser($infoUser));
 
 	}
 
 	public function modifyBorrowerAction() {
 
-		if($infoUser = $this->checkInfoForAbonneAfim())
+		if($infoUser = $this->checkInfoForAbonneAfim('Modify borrower multimedia start'))
 			$this->_response->setBody(Class_Multimedia_Users::getInstance()->modifyUser($infoUser));
 
 	}
 
 	public function deleteBorrowerAction() {
 
-		if($infoUser = $this->checkInfoForAbonneAfim())
+		if($infoUser = $this->checkInfoForAbonneAfim('Delete borrower multimedia start'))
 			$this->_response->setBody(Class_Multimedia_Users::getInstance()->deleteUser($infoUser));
 	}
 
 
-	private function checkInfoForAbonneAfim(){
+	private function checkInfoForAbonneAfim($info){
 		$this->_helper->getHelper('viewRenderer')->setNoRender();
 
 		$multimedia = Class_Multimedia::getInstance();
 		$log = $multimedia->getLog();
-		$log->info('Create borrower multimedia start');
+		$log->info($info);
 
 
 		if (null == ($json = $this->_getParam('json'))) {
diff --git a/cosmogramme/php/classes/classe_notice_integration.php b/cosmogramme/php/classes/classe_notice_integration.php
index be72a4503f9215213a09969b0290fa8996cfc96b..1d3e20ae11d893d3f05a46abb34cd87d30066000 100644
--- a/cosmogramme/php/classes/classe_notice_integration.php
+++ b/cosmogramme/php/classes/classe_notice_integration.php
@@ -435,14 +435,13 @@ class notice_integration {
 	private function chercheNotice() {
 		$attributes = [];
 		if(!$this->mode_doublon)
-			$attributes = [//'isbn10' => $this->notice['isbn10'],
-										 //'isbn13' => $this->notice['isbn13'],
-										 'isbn' => [$this->notice['isbn13'], $this->notice['isbn10']],
-										 'ean' => $this->notice['ean'],
-										 'id_commerciale' => $this->notice['id_commerciale']];
+			$attributes = [['isbn', $this->notice['isbn13']],
+										 ['isbn', $this->notice['isbn10']],
+										 ['ean', $this->notice['ean']],
+										 ['id_commerciale', $this->notice['id_commerciale']]];
 
 		if ($this->mode_doublon == static::SEARCH_MODE_ALPHAKEY)
-			$attributes = ['clef_alpha' => $this->notice['clef_alpha']];
+			$attributes = [['clef_alpha', $this->notice['clef_alpha']]];
 
 		$this->identification = ['statut' => static::STATUS_NOTFOUND];
 
@@ -453,7 +452,9 @@ class notice_integration {
 			return $id_notice;
 		}
 
-		foreach ($attributes as $key => $value) {
+		foreach ($attributes as $attr) {
+			list($key, $value) = $attr;
+
 			if ($id_notice = $this->searchRecordBy($key, $value)) {
 				$this->identification['statut'] = $key;
 				$this->identification[$key] = $id_notice;
diff --git a/cosmogramme/php/integration/facettes.php b/cosmogramme/php/integration/facettes.php
index 08d5a8ca2a7f040a9d7fe617bc1c2192b08b8c8c..68cd0c1ea245393c54ab9a339d7ec5b976a7d725 100644
--- a/cosmogramme/php/integration/facettes.php
+++ b/cosmogramme/php/integration/facettes.php
@@ -19,73 +19,27 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
  */
 
-/////////////////////////////////////////////////////////////////////////
-// CALCUL DES FACETTES
-/////////////////////////////////////////////////////////////////////////
+// collect state from global scope
+$current_chrono = Class_Cosmogramme_Integration_Chronometre::fromLegacyState($chrono,
+																																						 $chrono_fichier,
+																																						 $chrono100notices);
 
-setVariable("traitement_phase", "Mise à jour des facettes exemplaires");
-if ($phase == 7) {
-	$log->ecrire("<h4>Mise à jour des facettes exemplaires</h4>");
-	unset($phase_data);
-	$phase_data["nombre"] = 0;
-	$phase_data["timeStart"] = time();
-	$phase_data["pointeur_notice"]=0;
-	$phase_data["pointeur"]=getVariable('date_maj_facettes');
-	if(!$phase_data["pointeur"]) $phase_data["pointeur"]='0000-00-00 00:00:00';
-	$chrono100notices->start();
-	$phase = 7.1;
-}
+$current_phase = Class_Cosmogramme_Integration_Phase::fromLegacyState($phase,
+																																			$phase_data,
+																																			$mode_cron,
+																																			$reprise);
 
-// Lancer requete
-if ($phase == 7.1) {
-	if(!$mode_cron and $phase_data["pointeur_notice"] > 0)
-		print("<h4>Mise à jour des facettes exemplaires</h4>");
 
-	while(true) {
-    Storm_Model_Abstract::unsetLoaders();
-		Zend_Db_Table::getDefaultAdapter()->closeConnection();
-		setupDatabase(loadConfig());
-    gc_collect_cycles();
+$phase_facets = new Class_Cosmogramme_Integration_PhaseItemFacets($current_phase,
+																																	$log,
+																																	$current_chrono);
 
-		$notices = Class_Notice::findAllBy([
-																				"where" =>
-																				  "id_notice > ".$phase_data["pointeur_notice"]
-																				  ." and date_maj >='" . $phase_data["pointeur"]."'",
-																				"order" => "id_notice",
-																				"limit" => "1000"]);
-		if (!$notices) break;
+$new_phase = $phase_facets->run();
 
-		foreach ($notices as $notice) {
-			if (!$mode_cron and $chrono->tempsPasse() > $timeout)
-				sauveContexte();
+// reinject state into global scope
+$current_chrono->backToLegacyState($chrono, $chrono_fichier, $chrono100notices);
+$new_phase->backToLegacyState($phase, $phase_data, $mode_cron, $reprise);
 
-			$id_notice = $notice->getId();
-			$last_date_maj = $notice->getDateMaj();
 
-			// si ressource num, les facettes sont déjà calculés dans pseudo notice
-			if (99 < $notice->getTypeDoc()) {
-				$phase_data["pointeur_notice"] = $id_notice;
-				$phase_data["nombre"]++;
-				if ($phase_data["nombre"] % 5000 == 0) {
-					print($phase_data["nombre"] . BR);
-					flush();
-				}
-				continue;
-			}
-
-			$notice
-				->updateFacetsFromExemplaires()
-				->save();
-
-			$phase_data["pointeur_notice"] = $id_notice;
-			$phase_data["nombre"]++;
-			if ($phase_data["nombre"] % 5000 == 0) { print($phase_data["nombre"] . BR); flush(); }
-		}
-	}
-
-	setVariable('date_maj_facettes', $last_date_maj);
-	$log->ecrire('<span class="vert"> '.$phase_data['nombre'].' notices traitées.</span>').BR;
-	$log->ecrire('<span class="vert">Temps de traitement : ' . $chrono100notices->end() . " (" . $chrono100notices->moyenne($phase_data["nombre"], "notices") . ")</span>" . BR);
-	$phase = 8;
-}
-?>
+if (!$mode_cron && $phase_facets->isTimeOut())
+	sauveContexte();
\ No newline at end of file
diff --git a/cosmogramme/php/integre_traite_main.php b/cosmogramme/php/integre_traite_main.php
index 6d1d7ae1ec29472d43d061302f27feeaeafeff86..b8b34769510a823ab1a6a6f66292c98e77ae24d4 100644
--- a/cosmogramme/php/integre_traite_main.php
+++ b/cosmogramme/php/integre_traite_main.php
@@ -404,7 +404,6 @@ if ($phase == 3)
 	if ($homogene_actif == 0)
 	{
 		$log->ecrire('<span class="rouge">Le processus d\'homogénéisation des notices est désactivé</span>' . BR);
-		$phase = 7;
 	} else
 	{
 		if ($ecart < $frequence) $log->ecrire('<span class="vert">Sera fait dans ' . ($frequence - $ecart) . ' jour(s)</span>');
@@ -479,7 +478,6 @@ if ($phase == 4)
 	if ($homogene_actif == 0)
 	{
 		$log->ecrire('<span class="rouge">Le processus d\'homogénéisation des notices est désactivé</span>' . BR);
-		$phase = 7;
 	} else
 	{
 		if ($ecart < $frequence) $log->ecrire('<span class="vert">Sera fait dans ' . ($frequence - $ecart) . ' jour(s)</span>');
@@ -545,7 +543,6 @@ if ($phase == 5)
 	if ($homogene_actif == 0)
 	{
 		$log->ecrire('<span class="rouge">Le processus d\'homogénéisation des notices est désactivé</span>' . BR);
-		$phase = 7;
 	} else
 	{
 		if ($ecart < $frequence) $log->ecrire('<span class="vert">Sera fait dans ' . ($frequence - $ecart) . ' jour(s)</span>');
@@ -593,15 +590,16 @@ if ($phase == 6 and $ecart >= $frequence and $homogene_actif == 1)
 	}
 	afficherRecapHomogene($phase_data, $chrono);
 	setVariable("homogene_date", $date);
-	$phase = 7;
-}
-elseif ($phase == 6) $phase = 7;
+};
 
 // ----------------------------------------------------------------
 // Recalcul des facettes bibliothèque (phases 7 et 7.1)
 // ----------------------------------------------------------------
-if (!$mode_cron and $chrono->tempsPasse() > 5) sauveContexte();
-if ($phase > 6 and $phase < 8) include("integration/facettes.php");
+if (!$mode_cron and $chrono->tempsPasse() > 5)
+	sauveContexte();
+
+include('integration/facettes.php');
+$phase = 8;
 
 // ----------------------------------------------------------------
 // Integration des abonnés
diff --git a/cosmogramme/tests/php/classes/NoticeIntegrationDedupTest.php b/cosmogramme/tests/php/classes/NoticeIntegrationDedupTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..e0274469b744326392ff8c3ff9c61f8378176ef6
--- /dev/null
+++ b/cosmogramme/tests/php/classes/NoticeIntegrationDedupTest.php
@@ -0,0 +1,76 @@
+<?php
+/**
+ * Copyright (c) 2012, Agence Française Informatique (AFI). All rights reserved.
+ *
+ * BOKEH is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by
+ * the Free Software Foundation.
+ *
+ * There are special exceptions to the terms and conditions of the AGPL as it
+ * is applied to this software (see README file).
+ *
+ * BOKEH is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * along with BOKEH; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
+ */
+
+require_once 'NoticeIntegrationTest.php';
+
+/** @see http://forge.afi-sa.fr/issues/17196 */
+class NoticeIntegrationDedupWithoutIsbnTest extends NoticeIntegrationTestCase {
+	public function getProfilDonnees() {
+		return Class_IntProfilDonnees::forALOES()->setIdProfil(113)
+																						->getRawAttributes();
+	}
+	public function setUp() {
+		parent::setUp();
+		$this->fixture('Class_Notice', ['id' => 15824768,
+																		'type_doc' => 2,
+																		'alpha_titre' => 'ANIME LAND 203',
+																		'alpha_auteur' => 'ANIMARTE',
+																		'titres' => 'ANIME ANIM LAND LAN MAGAZINE MAGAZIN FRANCAIS FRANKAI L00  ANIMATION ANIMASION 203',
+																		'auteurs' => 'ANIMARTE ANIMART',
+																		'editeur' => 'Animarte',
+																		'dewey' => 'ARTS AR LOISIRS LOISIR',
+																		'facettes' => 'D7948083 A204019 Lfre G4 G9 G37 G18 G12 G10 G33 G11 G45 G17 G5 G14 G2 G13 G8 G7 G30 G19 G24 G21 G20 G43 G3 G16 G51 G47 G27 G29 G36 G25 G34 G31 G56 G53 G1 G28 G26 G44 G32 G23 G6 G58 G50 T2 B105 S6 YVIGNEULLES B4 S1 S10 B3 YLIGNY S7 B18 YAUBREVILLE B81 YPIERREFITT B40 YDUGNY B53 YLACROIXSME B39 YDOULCON B20 YBELLEVILLE B58 YISLETTES B7 YSTM B94 YSPINCOURT B130 YTRIAUCOURT B26 YBRAS B96 YTREMONT B35 YDAMVILLERS B80 YPAGNY B8 YDIEUE B33 YCOUSANCE B73 YMONTMEDY B126 YCDOS B29 YCLERMONTAR B42 YFRESNES B57 YLEROUVILLE B124 YSOUILLY B41 YETAIN B11 YLAMORVILLE B1 YBDM B101 YVAUBECOURT',
+																		'cote' => '741.5 ANI',
+																		'id_commerciale' => '',
+																		'id_bnf' => '',
+																		'ean' => null,
+																		'clef_alpha' => 'ANIMELAND-LEMAGAZINEFRANCAISDE-ANIMARTE-203-ANIMARTE-1991-2',
+																		'clef_oeuvre' => 'ANIMELAND-LEMAGAZINEFRANCAISDE-ANIMARTE-203',
+																		'clef_chapeau' => 'ANIME LAND',
+																		'tome_alpha' => 203,
+																		'annee' => 1991,
+																		'qualite' => 5,
+																		'exportable' => 1,
+																		'date_creation' => '2015-08-13 00:00:00',
+																		'date_maj' => '2015-04-19 03:56:21',
+																		'unimarc' => "01281cas0 2200373   450 0010007000000110027000070200013000340900011000471000041000581010008000991020007001071060006001141100016001202000114001362070023002502100056002732100045003292100070003742150010004443000072004543120037005263260011005634610015005744610008005894610023005974880055006205170014006755300015006896760018007046860070007227100060007928010048008528020007009001588661 a1148-0807dle n° 20 F  b19104668  a158866  a19910613a1991    m  y0frey50      ba0 afre  aFR  ar  aah z     z 1 aAnime landbTexte impriméele magazine français de l'animationf[Animarte]g[dir. publ. Yvan West Laurence] 0aN° 1 (1991, avr.)  aVanvesb71 rue Jean-Jaurès, 92170cAnimarted1991-0 aParisb7 rue Elie Faure, 75012cAnimarte1 aParisb14 rue Soleillet, 75971 Cedex 20cAnime manga pressd1996-  d30 cm  aCertains numéros sont accompagnés d'un DVD-ROM ou d'un DVD vidéo  aAutre forme de titre : Animeland  aBimest11tAnime land11v20311o- Avril / Mai 2015 1036140168tAnime land. Hors-sériex1283-6338d19971 aAnimeland0 aAnime land  a794.808 3v22  a0002Cadre de classement de la Bibliographie nationale française  312883488aAnimartecVanves, Hauts-de-Seine40709161742 0aFRbFR-751131015c19910613gAFNOR2intermrc  a07",
+		]);
+
+		VariableCache::getInstance()
+		  ->setValeurCache(['filtrer_fulltext' => 1,
+			'mode_doublon'=> 0,
+			'tracer_accents_iso'=>1,
+			'non_exportable'=> 'electre;decitre;gam;zebris',
+			'controle_codes_barres'=> 0,
+			'unimarc_zone_titre' => '200$a;461$t',
+			'unicite_code_barres' => 0,
+			'champs_sup' => '',
+			'ean_345' => '']);
+
+		$this->loadNotice('unimarc_dernier_des_hommes');
+	}
+
+
+	/** @test */
+	public function thereShouldHave2Records() {
+		$this->assertEquals(2, Class_Notice::count());
+	}
+}
diff --git a/cosmogramme/tests/php/classes/unimarc_dernier_des_hommes.txt b/cosmogramme/tests/php/classes/unimarc_dernier_des_hommes.txt
new file mode 100644
index 0000000000000000000000000000000000000000..5ca4e572879b1d2774166daee9a197ef552ca010
--- /dev/null
+++ b/cosmogramme/tests/php/classes/unimarc_dernier_des_hommes.txt
@@ -0,0 +1 @@
+01683ngm0 2200361   450 0010008000000200017000080710022000251000041000471010028000881020007001161150025001232000164001482100050003122150086003623000203004483000131006513040042007823060016008243300071008403450027009116860008009387020046009467020032009927020024010247020025010487020021010738010039010948010025011339010047011589020020012059030008012259950088012330476549  aFRb70502749|1bMK2 Âed.a9714900  a20050119d2005       y0frey0103    ba1 amulcgerjengjfrejspa  aFR  ac   baiz|||||||bz||c1 aDernier des hommes (Le)bImages animÂeesfFriedrich Wilhelm Murnau, rÂeal.gCarl Mayer, scÂenariogEmil Jannings, Maly Delscharft, Max Hiller... [et al.], act.  a[Paris]cMK2 Âed. [Âed., distrib.]d[DL 2005]  a1 DVD vidÂeo monoface double couche zone 2 (2 h 10 min)c4/3, n. et b. (PAL), mu.  aContient aussi : rÂealisation du "Dernier des hommes" par Luciano Berriatua (40 min), crÂeateurs du film, gÂenÂerique, le film est prÂesentÂe avec sa double fin, la deuxiÁeme Âetant la fin originale  aFilm muet avec intertitres en allemand et sous-titrage optionnel en anglais, franÐcais et espagnol avec accompagnement musical  aNotice rÂedigÂee d'aprÁes la jaquette  aCop. : 1924  a"L'histoire de la decheance du portier d'un grand hotel de Berlin"  b3700224303952d56,00 €  a207 |aMurnaubFriedrich Wilhelmf1888-19314300 |aMayerbCarlf1894-19444690 |aJanningsbEmil4005 |aDelschaftbMaly4005 |aHillerbMax4005 0aFRbBNFc20050119gAFNOR2intermrc 0aFRbBM BLDc20070929  aCinÂema -- Allemagne [Europe] -- 1895-1928  aFilm dramatique  aP14  30476707aMÂediathÁeque Jean JEUKENSf10086587kF MUR DVDm20140712n20140823qargd
\ No newline at end of file
diff --git a/library/Class/Bib.php b/library/Class/Bib.php
index 53f37020d44ceac39ad8bf2734c432871f640ed3..1a16adb404b32e7b6919d2eb3bed7cdb4d8bd302 100644
--- a/library/Class/Bib.php
+++ b/library/Class/Bib.php
@@ -252,7 +252,7 @@ class Class_Bib extends Storm_Model_Abstract {
 		if (!$aff_zone = ZendAfi_Filters_Serialize::unserialize($this->getAffZone()))
 			$aff_zone = [];
 
-		return array_merge(['profilID' => null,
+		return array_merge(['profilID' => '',
 												'libelle' => '',
 												'posX' => 0,
 												'posY' => 0,
@@ -263,14 +263,49 @@ class Class_Bib extends Storm_Model_Abstract {
 
 	public function getUrl() {
 		$props = $this->getAffZoneAsArray();
-		$profil = Class_Profil::find($props["profilID"]);
-		$parts = $profil ? $profil->getUrlParts() : ['controller' => 'bib',
-																								 'action' => 'bibview',
-																								 'id' => $this->getId()];
+
+		$parts = ['controller' => 'bib',
+							'action' => 'bibview',
+							'id' => $this->getId()];
+
+		if($profil = Class_Profil::find($props["profilID"]))
+			$parts = $profil->getUrlParts();
+
 		return Class_Url::assemble($parts, null, true);
 	}
 
 
+	public function getPosX() {
+		return $this->getAffZoneKey('posX');
+	}
+
+
+	public function getPosY() {
+		return $this->getAffZoneKey('posY');
+	}
+
+
+	public function getPosPoint() {
+		return $this->getAffZoneKey('posPoint');
+	}
+
+
+	public function getProfilId() {
+		return $this->getAffZoneKey('profilID');
+	}
+
+
+	public function getAffZoneKey($key) {
+		if (!$aff_zone = ZendAfi_Filters_Serialize::unserialize($this->getAffZone()))
+			return 0;
+
+		if(!isset($aff_zone[$key]))
+			return 0;
+
+		return $aff_zone[$key];
+	}
+
+
 	public function getBibsBySite($id_site=0)	{
 		$where = '';
 		if($id_site!=0)
diff --git a/library/Class/Cosmogramme/Integration/Phase.php b/library/Class/Cosmogramme/Integration/Phase.php
index 61d5a9b2af0d8911df914fda0176039694c4904d..c66355dd398db9ec95d3eb1f1b91b948198cb36e 100644
--- a/library/Class/Cosmogramme/Integration/Phase.php
+++ b/library/Class/Cosmogramme/Integration/Phase.php
@@ -68,6 +68,11 @@ class Class_Cosmogramme_Integration_Phase {
 	}
 
 
+	public function isIdIn($ids) {
+		return in_array($this->_id, $ids);
+	}
+
+
 	public function isCron() {
 		return $this->_is_cron;
 	}
diff --git a/library/Class/Cosmogramme/Integration/PhaseAbstract.php b/library/Class/Cosmogramme/Integration/PhaseAbstract.php
new file mode 100644
index 0000000000000000000000000000000000000000..95b27f77c6d803303cc2086e54389d97bea75a0a
--- /dev/null
+++ b/library/Class/Cosmogramme/Integration/PhaseAbstract.php
@@ -0,0 +1,94 @@
+<?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_PhaseAbstract {
+	use Trait_TimeSource;
+
+	protected $_label = '';
+	protected $_phase, $_log, $_printer, $_chrono, $_is_time_out;
+
+
+	public function __construct($phase, $log, $chrono) {
+		$this->_phase = $phase;
+		$this->_log = $log;
+		$this->_chrono = $chrono;
+		$this->_is_time_out = false;
+	}
+
+
+	/** @return Class_Cosmogramme_Integration_Phase */
+	public abstract function run();
+
+
+	protected function _isMyTurn() {
+		return $this->_phase->isId(static::MY_ID);
+	}
+
+
+	protected function _getData($name) {
+		return $this->_phase->getData($name);
+	}
+
+
+	protected function _setData($name, $value) {
+		$this->_phase->setData($name, $value);
+		return $this;
+	}
+
+
+	protected function _incrementData($name) {
+		$this->_phase->incrementData($name);
+		return $this;
+	}
+
+
+	protected function _printLabel() {
+		if (!$this->_phase->isCron() && $this->_wasRunning())
+			$this->_getPrinter()->nextPutAll('<h4>' . $this->_label . '</h4>');
+	}
+
+
+	protected function _wasRunning() {
+		return false;
+	}
+
+
+	/** @category testing */
+	public function setPrinter($printer) {
+		$this->_printer = $printer;
+		return $this;
+	}
+
+
+	protected function _getPrinter() {
+		if (null !== $this->_printer)
+			return $this->_printer;
+		return new Class_Cosmogramme_Integration_PhasePrinter();
+	}
+
+
+	public function isTimeOut() {
+		return $this->_is_time_out = $this->_is_time_out
+			|| (!$this->_phase->isCron()
+					&& $this->_chrono->mainElapsed() > $this->_chrono->timeout());
+	}
+}
\ No newline at end of file
diff --git a/library/Class/Cosmogramme/Integration/PhaseItemFacets.php b/library/Class/Cosmogramme/Integration/PhaseItemFacets.php
new file mode 100644
index 0000000000000000000000000000000000000000..0c9b9c8dae594eb8ed8906bace1fdb81af88a5c9
--- /dev/null
+++ b/library/Class/Cosmogramme/Integration/PhaseItemFacets.php
@@ -0,0 +1,153 @@
+<?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_PhaseItemFacets
+	extends Class_Cosmogramme_Integration_PhaseAbstract {
+	const MY_ID = 7;
+	const MAX_ITEMS = 1000;
+
+	protected $_previous_records, $_last_update_date;
+	protected $_db_reset = true;
+	protected $_label = 'Mise à jour des facettes exemplaires';
+
+
+	public function __construct($phase, $log, $chrono) {
+		parent::__construct($phase, $log, $chrono);
+		$this->_previous_records = [];
+	}
+
+
+	public function run() {
+		Class_CosmoVar::setValueOf('traitement_phase', $this->_label);
+		$this->_init();
+
+		if (!$this->_isMyTurn())
+			return $this->_phase;
+
+		$this->_printLabel();
+
+		while ($records = Class_Notice::findAllAfter($this->_getData('pointeur_notice'),
+																								 $this->_getData('pointeur'))) {
+
+			if (0 == ($this->_getData('nombre') % 100))
+				$this->_log->ecrire('<span class="vert"> ' . $this->_getData('nombre') . ' records updated </span>');
+
+			/* @see #23391 : whenever we fetched ths same record page, end loop */
+			if ($this->_previous_records && (0 == count(array_filter(array_diff($this->_previous_records,	$records)))))
+				break;
+
+			$this->_previous_records = $records;
+
+			$this->runUpdateForRecords($records);
+
+			$this->_resetDbConnection();
+		}
+
+		Class_CosmoVar::setValueOf('date_maj_facettes', $this->_last_update_date);
+
+		$this->_log->ecrire('<span class="vert">'.
+												'Toutes les exemplaires ont été mis à jour :' .
+												' pointeur notice : ' . $this->_getData('pointeur_notice') .
+												' pointeur : ' . $this->_getData('pointeur') .
+												'<br>' . $this->_getData('nombre') . ' notices traitées.</span>');
+
+		$msg = '<span class="vert">Temps de traitement : '
+			. $this->_chrono->endFile()
+			. ' (' . $this->_chrono->meanOnFile($this->_getData('nombre'),
+																					'notices') . ')</span>';
+
+		$this->_log->ecrire($msg);
+
+		return $this->_phase;
+	}
+
+
+	protected function runUpdateForRecords($records) {
+		foreach ($records as $record) {
+			if ($this->isTimeOut())
+				return $this->_resetDbConnection()
+										->_phase;
+
+			if (static::MAX_ITEMS < Class_Exemplaire::countBy(['id_notice' => $record->getId()]))
+				return;
+
+			$this->_runOne($record);
+		}
+	}
+
+
+	protected function _runOne($record) {
+		// types starting with 100 are indexed at another phase
+		if (100 > $record->getTypeDoc())
+			$record->updateFacetsFromExemplaires()
+						 ->save();
+
+		$this->_setData('pointeur_notice', $record->getId());
+		$this->_incrementData('nombre');
+		$this->_last_update_date = $record->getDateMaj();
+	}
+
+
+	protected function _init() {
+		if (!$this->_phase->isIdIn([4, 5, 6]))
+			return;
+
+		$last_update_date = Class_CosmoVar::getValueOf('date_maj_facettes');
+		$this->_phase = (new Class_Cosmogramme_Integration_Phase(self::MY_ID))
+			->beSameCronAs($this->_phase)
+			->resetDatas()
+			->setData('nombre', 0)
+			->setData('pointeur_notice', 0)
+			->setData('pointeur',
+								$last_update_date ? $last_update_date : '0000-00-00 00:00:00');
+
+		$this->_chrono
+			->startOnFile()
+			->startOnRecords();
+
+		$this->_log->ecrire('<h4>' . $this->_label . '</h4>');
+	}
+
+
+	protected function _wasRunning() {
+		return $this->_getData('pointeur_notice') > 0;
+	}
+
+
+	/** @category testing */
+	public function noDbReset() {
+		$this->_db_reset = false;
+		return $this;
+	}
+
+
+	protected function _resetDbConnection() {
+		if (!$this->_db_reset)
+			return $this;
+
+		Storm_Model_Abstract::unsetLoaders();
+		Zend_Db_Table::getDefaultAdapter()->closeConnection();
+		setupDatabase(loadConfig());
+		gc_collect_cycles();
+		return $this;
+	}
+}
\ No newline at end of file
diff --git a/library/Class/Cosmogramme/Integration/PhasePrinter.php b/library/Class/Cosmogramme/Integration/PhasePrinter.php
new file mode 100644
index 0000000000000000000000000000000000000000..38c974d3ccc7014b80a71b03122654a970f5edab
--- /dev/null
+++ b/library/Class/Cosmogramme/Integration/PhasePrinter.php
@@ -0,0 +1,27 @@
+<?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_PhasePrinter {
+	public function nextPutAll($value) {
+		print($value);flush();
+	}
+}
diff --git a/library/Class/Cosmogramme/Integration/PhaseReservation.php b/library/Class/Cosmogramme/Integration/PhaseReservation.php
index f9c452dd52531b72cb3b157fd95ea44a76816496..82b4f56b725ebc94c7ec9708933c07ee85c11309 100644
--- a/library/Class/Cosmogramme/Integration/PhaseReservation.php
+++ b/library/Class/Cosmogramme/Integration/PhaseReservation.php
@@ -20,23 +20,14 @@
  */
 
 
-class Class_Cosmogramme_Integration_PhaseReservation {
-	use Trait_TimeSource;
-
+class Class_Cosmogramme_Integration_PhaseReservation
+	extends Class_Cosmogramme_Integration_PhaseAbstract{
 	const MY_ID = 13;
 
 	protected $_phase, $_log, $_printer, $_chrono, $_is_time_out;
 	protected $_label = 'Intégration des fichiers de réservations';
 
 
-	public function __construct($phase, $log, $chrono) {
-		$this->_phase = $phase;
-		$this->_log = $log;
-		$this->_chrono = $chrono;
-		$this->_is_time_out = false;
-	}
-
-
 	public function run() {
 		Class_CosmoVar::setValueOf('traitement_phase', $this->_label);
 		$this->_init();
@@ -55,8 +46,8 @@ class Class_Cosmogramme_Integration_PhaseReservation {
 			$this->_runOne($integration);
 		}
 
-		$this->_phase->setData('pointeur', 0);
-		$processed = $this->_phase->getData('nb_fic');
+		$this->_setData('pointeur', 0);
+		$processed = $this->_getData('nb_fic');
 		$msg = ($processed > 0) ?
 			$processed . ' fichier(s) traité(s).' :
 			'aucun fichier traité';
@@ -66,17 +57,6 @@ class Class_Cosmogramme_Integration_PhaseReservation {
 	}
 
 
-	protected function _isMyTurn() {
-		return $this->_phase->isId(self::MY_ID);
-	}
-
-
-	protected function _printLabel() {
-		if (!$this->_phase->isCron() && $this->_phase->getData('nombre') > 0)
-			$this->_getPrinter()->nextPutAll('<h4>' . $this->_label . '</h4>');
-	}
-
-
 	protected function _runOne($integration) {
 		if (!($profil = $integration->getProfilDonnees()) || !$profil->isHolds())
 			return;
@@ -102,7 +82,7 @@ class Class_Cosmogramme_Integration_PhaseReservation {
 
 		if (!$this->isTimeOut()) {
 			$integration->setTraite($this->getTimeSource()->dateYmd())
-									->setPointeurReprise($this->_phase->getData('nombre'))
+									->setPointeurReprise($this->_getData('nombre'))
 									->save();
 			$this->_phase->incrementData('nb_fic');
 		}
@@ -127,6 +107,12 @@ class Class_Cosmogramme_Integration_PhaseReservation {
 	}
 
 
+
+	protected function _wasRunning() {
+		return $this->_getData('nombre') > 0;
+	}
+
+
 	protected function _runFile($parser, $integration) {
 		while(true) {
 			if ($this->isTimeOut())
@@ -150,7 +136,7 @@ class Class_Cosmogramme_Integration_PhaseReservation {
 														$this->_log->ecrire('<span class="rouge">' . $error . '</span><br>');
 											 });
 
-		$processed = $this->_phase->getData('nombre');
+		$processed = $this->_getData('nombre');
 		$msg = ($processed > 0) ?
 			$processed . ' fiches ont pu être traitées.' :
 			'aucune fiche n\'a pu être traitée.';
@@ -164,7 +150,7 @@ class Class_Cosmogramme_Integration_PhaseReservation {
 		if (!$line->isEnd())
 			return false;
 
-		$processed = $this->_phase->getData('nombre');
+		$processed = $this->_getData('nombre');
 		if ($processed == 0) {
 			$this->_log->ecrire('<br><span class="vert">Le fichier ne contenait aucune fiche</span><br>');
 			return true;
@@ -196,9 +182,9 @@ class Class_Cosmogramme_Integration_PhaseReservation {
 												$transaction->importHold($data);
 											});
 
-		$this->_phase->incrementData('nombre');
+		$this->_incrementData('nombre');
 
-		$processed = $this->_phase->getData('nombre');
+		$processed = $this->_getData('nombre');
 		if (0 == $processed % 1000) {
 			$this->_log->ecrire('fiche ' . $processed
 													. ' (' . $this->_chrono->elapsedOnRecords()
@@ -208,8 +194,7 @@ class Class_Cosmogramme_Integration_PhaseReservation {
 
 		$line->withNextPositionDo(
 															function($next) use ($integration) {
-																$this->_phase
-																	->setData('pointeur', $next);
+																$this->_setData('pointeur', $next);
 
 																$integration
 																	->setPointeurReprise($next)
@@ -218,13 +203,6 @@ class Class_Cosmogramme_Integration_PhaseReservation {
 	}
 
 
-	public function isTimeOut() {
-		return $this->_is_time_out = $this->_is_time_out
-			|| (!$this->_phase->isCron()
-					&& $this->_chrono->mainElapsed() > $this->_chrono->timeout());
-	}
-
-
 	protected function _clean($integration) {
 		if ($integration->shouldClean())
 			Class_Reservation::deleteBy(['id_site' => $integration->getBib()->getId()]);
@@ -257,26 +235,4 @@ class Class_Cosmogramme_Integration_PhaseReservation {
 
 		$this->_log->ecrire('<h4>' . $this->_label . '</h4>');
 	}
-
-
-	/** @category testing */
-	public function setPrinter($printer) {
-		$this->_printer = $printer;
-		return $this;
-	}
-
-
-	protected function _getPrinter() {
-		if (null !== $this->_printer)
-			return $this->_printer;
-		return new Class_Cosmogramme_Integration_PhasePrinter();
-	}
-}
-
-
-
-class Class_Cosmogramme_Integration_PhasePrinter {
-	public function nextPutAll($value) {
-		print($value);
-	}
 }
diff --git a/library/Class/Indexation/PseudoNotice.php b/library/Class/Indexation/PseudoNotice.php
index e3966d286152dce012ab914a6b67ea317ab20b48..d0006f7482855092fc66c23f7687ad7fd3391395 100644
--- a/library/Class/Indexation/PseudoNotice.php
+++ b/library/Class/Indexation/PseudoNotice.php
@@ -152,6 +152,7 @@ class Class_Indexation_PseudoNotice {
 		$authors = $this->getAuthorsNames();
 
 		$indexation = Class_Indexation::getInstance();
+
 		$this->_notice
 			->setMatieres($this->extractFullTextFromCodif($data,
 																										'matiere',
@@ -159,9 +160,9 @@ class Class_Indexation_PseudoNotice {
 			->setAlphaTitre($indexation->codeAlphaTitre($this->_datas["titre"]))
 			->setClefAlpha($this->_model->getAlphaKey())
 			->setClefOeuvre($indexation->getClefOeuvre($this->_datas["titre"],
-																												'',
-																												$this->_datas["auteur"],
-																												''))
+																								 '',
+																								 $this->_datas["auteur"],
+																								 ''))
 			->setTitres($indexation->getfullText($this->extractTitles()))
 			->setAuteurs($indexation->getfullText($authors))
 			->setAlphaAuteur($indexation->alphaMaj(implode(' ', $this->extractAuthors())))
@@ -195,6 +196,7 @@ class Class_Indexation_PseudoNotice {
 		}
 
 		$cote = '';
+
 		if ($this->dataExist('cote', $this->_datas))
 			$cote = $this->_datas['cote'];
 
@@ -328,6 +330,7 @@ class Class_Indexation_PseudoNotice {
 		return $visitor->getUnimarc();
 	}
 
+
 	protected function _getCodeBarres() {
 		return str_repeat('0', (4 - strlen($this->_datas['id_bib'])))
 			. $this->_datas['id_bib'] . '-' . $this->_notice->getId();
@@ -391,6 +394,7 @@ class Class_Indexation_PseudoNotice_Album extends Class_Indexation_PseudoNotice{
 	}
 
 
+
 	public function extractEditors() {
 		$editors = parent::extractEditors();
 		if(empty($editors))
@@ -435,11 +439,19 @@ class Class_Indexation_PseudoNotice_Album extends Class_Indexation_PseudoNotice{
 			$visitor->visitRessource($ressource);
 	}
 
+
 	public function isValid() {
 		return null != $this->_model
 			&& $this->_model->isVisible()
 			&& $this->_model->isValidated();
 	}
+
+
+	protected function _getUnimarc() {
+		$visitor = new Class_Indexation_PseudoNotice_AlbumVisitor();
+		$this->acceptVisitor($visitor);
+		return $visitor->getUnimarc();
+	}
 }
 
 
diff --git a/library/Class/Indexation/PseudoNotice/AlbumVisitor.php b/library/Class/Indexation/PseudoNotice/AlbumVisitor.php
new file mode 100644
index 0000000000000000000000000000000000000000..ef1c6d96a70baabfc520d686590d546ff53f1282
--- /dev/null
+++ b/library/Class/Indexation/PseudoNotice/AlbumVisitor.php
@@ -0,0 +1,30 @@
+<?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_Indexation_PseudoNotice_AlbumVisitor extends Class_Indexation_PseudoNotice_UnimarcVisitor {
+
+
+	public function visitDescription($description) {
+		return $this;
+	}
+}
+?>
\ No newline at end of file
diff --git a/library/Class/Multimedia/AuthenticateRequest.php b/library/Class/Multimedia/AuthenticateRequest.php
index 13f6591e93691af93077f011724c971863d1d123..6913997ce3d2869ace586c88a5f2bcfd6ae7e81c 100644
--- a/library/Class/Multimedia/AuthenticateRequest.php
+++ b/library/Class/Multimedia/AuthenticateRequest.php
@@ -32,6 +32,11 @@ class Class_Multimedia_AuthenticateRequest {
 	/** @var Class_Multimedia_Device */
 	protected $_device;
 
+	/** @var boolean */
+	protected $_holdableDay = false;
+
+	/** @var boolean */
+	protected $_successHolding = false;
 
 	/**
 	 * @param Zend_Controller_Request_Abstract
@@ -79,19 +84,46 @@ class Class_Multimedia_AuthenticateRequest {
 		if (!$this->_device)
 			return $this->_error('DeviceNotFound');
 
-		if (!$this->getCurrentHold())
-			return $this->_error('DeviceNotHeldByUser');
+		$mode = $request->getParam('mode');
+		if(isset($mode) && $mode === 'holdable-day'){
+			$this->_holdableDay = $this->_device->isHoldableDayToDay();
+		}
+
+		if (isset($mode) && $mode === 'hold'){
+			$temps = $request->getParam('temps');
+			if(!$this->getCurrentHold($temps))
+				return $this->_error('DeviceNotHeldByUser');
+
+			$this->_successHolding = true;
+		}
+
+		if(isset($mode) && $mode === 'modified-hold'){
+			if(!$hold = $this->getCurrentHold())
+				return $this->_error('DeviceNotHeldByUser');
+			$start = $hold->getStart();
+			$duration = floor(($location->getTimeSource()->time() - $start) / 60);
+			$hold->delete();
+			$this->_device->createHoldWithStartTimeAndDuration($user, $start, $duration);
+		}
 
 		return $this->beValid();
 	}
 
 
+	public function canHoldingForToDay(){
+		return $this->_holdableDay;
+	}
+
+	public function isSuccessHolding(){
+		return $this->_successHolding;
+	}
+
 	/**
 	 * @return Class_Multimedia_DeviceHold
 	 */
-	public function getCurrentHold() {
+	public function getCurrentHold($temps=null) {
 		if (!isset($this->_current_hold) && isset($this->_device) && isset($this->_user))
-			$this->_current_hold = $this->_device->getCurrentHoldForUser($this->_user);
+			$this->_current_hold = $this->_device->getCurrentHoldForUser($this->_user, $temps);
 		return $this->_current_hold;
 	}
 
diff --git a/library/Class/Multimedia/Device.php b/library/Class/Multimedia/Device.php
index fbf6f267900cf10113fe447024f42066dd23c407..45cc607ffb1d0ecb2452620415322aa564947f2c 100644
--- a/library/Class/Multimedia/Device.php
+++ b/library/Class/Multimedia/Device.php
@@ -109,12 +109,12 @@ class Class_Multimedia_Device extends Storm_Model_Abstract {
 	 * @param $user Class_Users
 	 * @return Class_Multimedia_DeviceHold
 	 */
-	public function getCurrentHoldForUser($user) {
+	public function getCurrentHoldForUser($user, $temps=null) {
 		if (null !== ($hold = $this->getCurrentHold())
 			and $user->getId() == $hold->getIdUser())
 			return $hold;
 
-		return $this->autoHoldByUser($user, $hold);
+		return $this->autoHoldByUser($user, $hold, $temps);
 	}
 
 
@@ -123,7 +123,7 @@ class Class_Multimedia_Device extends Storm_Model_Abstract {
 	 * @param $current_hold Class_Multimedia_DeviceHold
 	 * @return Class_Multimedia_DeviceHold
 	 */
-	public function autoHoldByUser($user, $current_hold) {
+	public function autoHoldByUser($user, $current_hold, $temps=null) {
 		if (!$this->canCreateHoldGivenCurrentHoldAndUser($current_hold, $user))
 			return null;
 
@@ -131,11 +131,15 @@ class Class_Multimedia_Device extends Storm_Model_Abstract {
 		if (null == ($start = $this->getPreviousStartTime()))
 			return null;
 
-		$end = $this->findHoldEndForTodayFrom($start, 1);
+		return $this->createHoldWithStartTimeAndDuration($user, $start, $temps);
+	}
 
+	public function createHoldWithStartTimeAndDuration($user, $start, $duration){
+		$end = $this->findHoldEndForTodayFrom($start, $duration );
 		if ($end <= $start)
 			return null;
 
+
 		$hold = Class_Multimedia_DeviceHold::getLoader()
 				->newInstance()
 				->setDevice($this)
@@ -143,10 +147,15 @@ class Class_Multimedia_Device extends Storm_Model_Abstract {
 				->setStart($start)
 				->setEnd($end);
 		$hold->save();
+
 		return $hold;
 	}
 
 
+	public function isHoldableDayToDay(){
+		return $this->getGroup()->isHoldableDayToDay();
+	}
+
 	/**
 	 * @param Class_Multimedia_DeviceHold $current_hold
 	 * @return boolean
@@ -196,12 +205,16 @@ class Class_Multimedia_Device extends Storm_Model_Abstract {
 	 * @param timestamp $starrt
 	 * @return timestamp
 	 */
-	public function findHoldEndForTodayFrom($start, $autohold=null) {
-		// fin de créneau par défaut selon config
-		$end = $start + (60 * $this->getAutoholdSlotsMax() * $this->getSlotSize());
+	public function findHoldEndForTodayFrom($start, $temps=null) {
+
+		$nbSlotMax = (!isset($temps)) ? $this->getAutoholdSlotsMax()
+			: ceil($temps / $this->getSlotSize());
+
+    // fin de créneau par défaut selon config
+		$end = $start + (60 * $nbSlotMax * $this->getSlotSize());
 
 		// si on dépasse la fin de journée on se limite à la fin de journée
-		if ($end > ($next_closing = $this->getMaxTimeForToday($autohold)))
+		if ($end > ($next_closing = $this->getMaxTimeForToday()))
 			$end = $next_closing;
 
 		// si on dépasse la prochaine résa on se limite au début de la prochaine résa
@@ -279,8 +292,8 @@ class Class_Multimedia_Device extends Storm_Model_Abstract {
 
 
 	/** @return int */
-	public function getMaxTimeForToday($autohold=null) {
-		return $this->getGroup()->getMaxTimeForToday($autohold);
+	public function getMaxTimeForToday() {
+		return $this->getGroup()->getMaxTimeForToday();
 	}
 
 
diff --git a/library/Class/Multimedia/DeviceGroup.php b/library/Class/Multimedia/DeviceGroup.php
index dfe9913fffbe55ec6f81cb3855644767eb53efae..e73612337dffb8b8181ec53a6a6e4dedffb7008a 100644
--- a/library/Class/Multimedia/DeviceGroup.php
+++ b/library/Class/Multimedia/DeviceGroup.php
@@ -91,8 +91,8 @@ class Class_Multimedia_DeviceGroup extends Storm_Model_Abstract {
 
 
 	/** @return int */
-	public function getMaxTimeForToday($autohold=null) {
-		return $this->getLocation()->getMaxTimeForToday($autohold);
+	public function getMaxTimeForToday() {
+		return $this->getLocation()->getMaxTimeForToday();
 	}
 
 
@@ -120,4 +120,9 @@ class Class_Multimedia_DeviceGroup extends Storm_Model_Abstract {
 	public function getLibelleBib() {
 		return $this->getLocation()->getLibelleBib();
 	}
+
+	/** @return bool */
+	public function isHoldableDayToDay(){
+		return $this->getLocation()->isHoldableDayToDay();
+	}
 }
\ No newline at end of file
diff --git a/library/Class/Multimedia/Location.php b/library/Class/Multimedia/Location.php
index 4be161568644097ce9e738388d7220d0f66ecb00..3168cc3f43bd71cb59ab3940a7e28ff94eead9ce 100644
--- a/library/Class/Multimedia/Location.php
+++ b/library/Class/Multimedia/Location.php
@@ -192,6 +192,7 @@ class Class_Multimedia_Location extends Storm_Model_Abstract {
 																									$time_source->date(),
 																									$time_source->nextDate());
 
+
 		if (0 == count($times))
 			return null;
 
@@ -201,13 +202,10 @@ class Class_Multimedia_Location extends Storm_Model_Abstract {
 				return $previous;
 			$previous = $time;
 		}
-
 		return null;
 	}
 
-
-
-	public function getOuvertureForDate($date, $autohold=null) {
+	public function getOuvertureForDate($date) {
 		if (is_string($date))
 			$date = strtotime($date);
 
@@ -223,8 +221,6 @@ class Class_Multimedia_Location extends Storm_Model_Abstract {
 				return $ouverture;
 		}
 
-		return ($this->getAutoholdForClosingDays() && $autohold === 1) ?
-			$this->_autoOpening() : null;
 	}
 
 
@@ -262,8 +258,8 @@ class Class_Multimedia_Location extends Storm_Model_Abstract {
 
 
 	/** @return int */
-	public function getMaxTimeForToday($autohold = null) {
-		if (!$ouverture = $this->getOuvertureForDate(self::getTimeSource()->date(), $autohold))
+	public function getMaxTimeForToday() {
+		if (!$ouverture = $this->getOuvertureForDate(self::getTimeSource()->date()))
 			return 0;
 		return $ouverture->getNextCloseFrom($this->getCurrentTime());
 	}
@@ -352,6 +348,9 @@ class Class_Multimedia_Location extends Storm_Model_Abstract {
 																		 }));
 	}
 
+	public function isHoldableDayToDay(){
+		return (!$ouverture = $this->getOuvertureForDate(self::getTimeSource()->date())) ? false : true;
+	}
 
 	public function beforeSave() {
 		if (is_array($days = $this->getDays()))
diff --git a/library/Class/Multimedia/Users.php b/library/Class/Multimedia/Users.php
index a77b8cb72664e76bf9513f90a33895e144bb4c6b..0a560ef8b8092fbd349a695253aa95409d2feb14 100644
--- a/library/Class/Multimedia/Users.php
+++ b/library/Class/Multimedia/Users.php
@@ -78,8 +78,7 @@ class Class_Multimedia_Users {
 				return $this->createUser(array($infoUser));
 
 			if($user->isAbonneInviteInGroupMultimedia()){
-			$user->setPassword($infoUser->pwd)
-					 ->setNom($infoUser->nom)
+					 $user->setNom($infoUser->nom)
 					 ->setPrenom($infoUser->prenom)
 					 ->setNaissance($infoUser->naissance)
 					 ->setPseudo('')
@@ -90,8 +89,10 @@ class Class_Multimedia_Users {
 					 ->setOrdreabon(1)
 					 ->setDateDebut('')
 					 ->setDateFin($infoUser->datefin)
-					 ->setIdSite($infoUser->site->id)
-					 ->save();
+					 ->setIdSite($infoUser->site->id);
+					 if($infoUser->pwd !== md5($user->getPassword()))
+						 $user->setPassword($infoUser->pwd);
+					 $user->save();
 			}
 		return 'MODIFICATION_USER_OK';
 
diff --git a/library/Class/Notice.php b/library/Class/Notice.php
index 444634bc0a518393dace6250a61073afc248e81c..d882587eaf80f36af7cee599f47445fa1979d705 100644
--- a/library/Class/Notice.php
+++ b/library/Class/Notice.php
@@ -120,6 +120,14 @@ class NoticeLoader extends Storm_Model_Loader {
 
 		return $result[0];
 	}
+
+
+	public function findAllAfter($record_id, $update_date) {
+		$where = "id_notice > " . $record_id . " and date_maj >='" . $update_date . "'";
+		return Class_Notice::findAllBy(['where' => $where,
+																		'order' => 'id_notice',
+																		'limit' => '100']);
+	}
 }
 
 
diff --git a/library/Class/Profil.php b/library/Class/Profil.php
index acfe2b1d37feb39dea9e54e697037b331869d74e..d7b01d0793698dc8d5ab155701b16f30cae9fde0 100644
--- a/library/Class/Profil.php
+++ b/library/Class/Profil.php
@@ -1601,10 +1601,61 @@ class Class_Profil extends Storm_Model_Abstract {
 	public function afterSave() {
 		$this->_has_parent_profil = null;
 		$this->_should_forward_attributes = [];
+		$this->syncModulesIds();
 	}
 
 
 
+	protected function syncModulesIds() {
+		$this->syncModulesIdsWithParentProfil();
+	}
+
+
+	protected function syncModulesIdsWithParentProfil() {
+		if(!$this->hasParentProfil())
+			return;
+
+		if(!$parent_banner_modules = $this->getParentProfil()->getBoitesDivision(self::DIV_BANNIERE))
+			return;
+
+		if(!$ids_used_by_parent_profil = array_keys($parent_banner_modules))
+			return;
+
+		return $this->doNotUseIds($ids_used_by_parent_profil);
+	}
+
+
+	protected function doNotUseIds($ids) {
+		$my_cfg = $this->getCfgAccueilAsArray();
+
+		if(!isset($my_cfg['modules']))
+			return;
+
+		if(!$my_modules_ids = array_keys($my_cfg['modules']))
+			return;
+
+		if(!$duplicate_ids = array_intersect($ids, $my_modules_ids))
+			return;
+
+		$last_used_id = max(array_unique(array_merge($ids, $my_modules_ids)));
+
+		foreach($duplicate_ids as $id) {
+			$last_used_id++;
+			$this->changeIdModuleTo($id, $last_used_id);
+		}
+	}
+
+
+	protected function changeIdModuleTo($id, $new_id) {
+		$cfg_accueil = $this->getCfgAccueilAsArray();
+		$module_cfg = $cfg_accueil['modules'][$id];
+		unset($cfg_accueil['modules'][$id]);
+		$cfg_accueil['modules'][$new_id] = $module_cfg;
+		$this->setCfgAccueil($cfg_accueil)->save();
+		return $this;
+	}
+
+
 	public function setCfgMenuHorizontal($cfg_menu_horizontal) {
 		$menus = $this->getCfgMenusAsArray();
 		$menus ['H']= $cfg_menu_horizontal;
diff --git a/library/Class/Zone.php b/library/Class/Zone.php
index 8e11ae508b359ee8a4071b82e8740b4053265035..f8d05c5ba57a4b4716c622e5483a87791be18bd4 100644
--- a/library/Class/Zone.php
+++ b/library/Class/Zone.php
@@ -16,10 +16,10 @@
  *
  * 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
  */
 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-//  OPAC 3 -                                                    Table Name 
+//  OPAC 3 -                                                    Table Name
 //
 // @TODO@ : A nettoyer
 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -28,24 +28,29 @@ class BibCZone extends Zend_Db_Table_Abstract
 	protected $_name = 'bib_c_zone';
 }
 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-//  OPAC 3 -                                             Class_Zone -> gestion des territoires 
+//  OPAC 3 -                                             Class_Zone -> gestion des territoires
 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 class Class_Zone extends Storm_Model_Abstract {
 	private $sql;
 	private $_dataBaseError = "Problème d'accès à  la base de données";
-	private $statut_bib = array('Invisible','N\'envoie pas de données','Envoie des données');
+	private $statut_bib = ['Invisible',
+												 'N\'envoie pas de données',
+												 'Envoie des données'];
 
 	protected $_table_name = 'bib_c_zone';
 	protected $_table_primary = 'id_zone';
-	protected $_has_many = array('bibs' => array( 'model' => 'Class_Bib',
-																								 'role' => 'zone',
-																								 'referenced_in' => 'ID_ZONE',
-																								 'order' => 'libelle'));
+	protected $_has_many = ['bibs' => ['model' => 'Class_Bib',
+																		 'role' => 'zone',
+																		 'referenced_in' => 'ID_ZONE',
+																		 'order' => 'libelle']];
 
-	protected $_default_attribute_values = array('libelle' => '',
-																							  'couleur' => '',
-																							  'map_coords' => '',
-																							  'image' => '');
+	protected $_default_attribute_values = ['libelle' => '',
+																					'couleur' => '#fff',
+																					'map_coords' => '',
+																					'couleur_texte' => '#fff',
+																					'couleur_ombre' => '#000',
+																					'taille_fonte' => '12',
+																					'image' => ''];
 
 
 
@@ -53,7 +58,7 @@ class Class_Zone extends Storm_Model_Abstract {
 		return self::getLoaderFor(__CLASS__);
 	}
 
-	
+
 	public function __construct()	{
 		$this->sql = Zend_Registry::get('sql');
 	}
@@ -71,7 +76,7 @@ class Class_Zone extends Storm_Model_Abstract {
 
 
 	public function setCouleur($couleur) {
-		if (substr($couleur,0,1)!="#") 
+		if (substr($couleur,0,1)!="#")
 			$couleur="#".$couleur;
 		parent::_set('couleur', $couleur);
 		return $this;
@@ -88,7 +93,7 @@ class Class_Zone extends Storm_Model_Abstract {
 		$data=fetchAll("select * from bib_c_zone ".$where. " order by LIBELLE");
 		return $data;
 	}
-	
+
 	// Lire tous les territoires  == OLD FUNCTION =======
 	public function getAllZone()
 	{
@@ -100,7 +105,7 @@ class Class_Zone extends Storm_Model_Abstract {
 			return $this->_dataBaseError;
 		}
 	}
-	
+
 	public function getZoneById($id_zone)
 	{
 		try{
@@ -124,7 +129,7 @@ class Class_Zone extends Storm_Model_Abstract {
 		return $img_infos;
 	}
 
-	
+
 	public function getImageWithInfos($image = null) {
 		if (!$image)	$image = $this->getImage();
 		$img = "/userfiles/photobib/".$image;
@@ -139,8 +144,8 @@ class Class_Zone extends Storm_Model_Abstract {
 		$ret["url"]=BASE_URL.$img;
 		return $ret;
 	}
-	
-	
+
+
 	// Rend un select avec la liste des zones pour la page d'accueil
 	public function getComboZoneAvecUrl($id_selected =0)
 	{
@@ -159,7 +164,7 @@ class Class_Zone extends Storm_Model_Abstract {
 	}
 
 	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-	//                                                      méthode ADMIN 
+	//                                                      méthode ADMIN
 	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
   //---------------------------------------------------------------------
 	// Insert zone
@@ -168,7 +173,7 @@ class Class_Zone extends Storm_Model_Abstract {
 	{
 		$id_zone=sqlInsert("bib_c_zone",$data);
 	}
-	
+
   //---------------------------------------------------------------------
 	// Update zone
 	//---------------------------------------------------------------------
@@ -181,12 +186,12 @@ class Class_Zone extends Storm_Model_Abstract {
 				$adresse_img=getcwd()."/userfiles/photobib/".$old_img;
 				if(file_exists($adresse_img)) unlink($adresse_img);
 			}
-		
+
 		// Ecriture
 		sqlUpdate("update bib_c_zone set @SET@ where ID_ZONE=$id_zone",$data);
 	}
 
-	
+
   //---------------------------------------------------------------------
 	// supprimer zone
 	//---------------------------------------------------------------------
@@ -217,7 +222,7 @@ class Class_Zone extends Storm_Model_Abstract {
 		$html[]='</select>';
 		return implode('',$html);
 	}
-	
+
   //---------------------------------------------------------------------
 	// Vérification de saisie
 	//---------------------------------------------------------------------
diff --git a/library/ZendAfi/Filters/Serialize.php b/library/ZendAfi/Filters/Serialize.php
index 6ef9f02a4530b0853ce98840ebea8b713b00ef5b..1b82eb9b7f70eca3578e4ad0581b5bd4e1eb5323 100644
--- a/library/ZendAfi/Filters/Serialize.php
+++ b/library/ZendAfi/Filters/Serialize.php
@@ -16,46 +16,32 @@
  *
  * 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 :	FILTRE POUR LES SERIALIZE ET UNSERIALIZE
-//////////////////////////////////////////////////////////////////////////////////////////////////////////
 
-class ZendAfi_Filters_Serialize
-{	
-	
-//----------------------------------------------------------------
-// Encodage
-//----------------------------------------------------------------
-	static function serialize($valeurs)
-	{
-		if(!$valeurs) return false;
-		$cls=new ZendAfi_Filters_Serialize();
-		array_walk_recursive($valeurs, array(&$cls,'encodeItem'));
-		$chaine=serialize($valeurs);
+class ZendAfi_Filters_Serialize {
 
-		$chaine=utf8_encode($chaine);
+	public static function serialize($valeurs)	{
+		if(!$valeurs)
+			return false;
+
+		$cls = new ZendAfi_Filters_Serialize();
+		array_walk_recursive($valeurs, [&$cls,'encodeItem']);
+		$chaine = serialize($valeurs);
+		$chaine = utf8_encode($chaine);
 		return $chaine;
 	}
-	
-//----------------------------------------------------------------
-// Decodage
-//----------------------------------------------------------------
-	static function unserialize($valeur)
-	{
-		$valeur=utf8_decode($valeur);
-		$valeurs=unserialize($valeur);
+
+
+	public static function unserialize($valeur)	{
+		$valeur = utf8_decode($valeur);
+		$valeurs = unserialize($valeur);
 		return $valeurs;
 	}
 
-//----------------------------------------------------------------
-// Fonction callback pour l'encodage 
-//----------------------------------------------------------------
-	private function encodeItem(&$valeur,$key)
-	{
-		$valeur=stripslashes($valeur);
+
+	protected function encodeItem(&$valeur, $key)	{
+		$valeur = stripslashes($valeur);
 		return $valeur;
 	}
-
 }
\ No newline at end of file
diff --git a/library/ZendAfi/Form/Album.php b/library/ZendAfi/Form/Album.php
index 88441a90fb149f436dda0e746f55445e97d46c77..ca227deb5cb36a7c247a48ae762105a74176c45f 100644
--- a/library/ZendAfi/Form/Album.php
+++ b/library/ZendAfi/Form/Album.php
@@ -24,6 +24,7 @@ class ZendAfi_Form_Album extends ZendAfi_Form {
 	const RIGHT_OTHER_KEY = 2;
 	const RIGHT_PUBLIC_DOMAIN = 'Domaine public';
 
+
 	protected $_simple_elements = ['titre',
 																 'cat_id',
 																 'type_doc_id',
@@ -31,7 +32,6 @@ class ZendAfi_Form_Album extends ZendAfi_Form {
 																 'status',
 																 'frbr_multi'];
 
-
 	public static function newWithAlbum($album) {
 		$form = new self();
 
diff --git a/library/ZendAfi/View/Helper/Abonne/Multimedia.php b/library/ZendAfi/View/Helper/Abonne/Multimedia.php
index 9088e65cb5cc0ff5d86c9927100f76e1a8f997b7..5e7d2dfe230aab6d13214bc4dbe8bdf2f26e8285 100644
--- a/library/ZendAfi/View/Helper/Abonne/Multimedia.php
+++ b/library/ZendAfi/View/Helper/Abonne/Multimedia.php
@@ -16,11 +16,12 @@
  *
  * 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_View_Helper_Abonne_Multimedia extends ZendAfi_View_Helper_Abonne_Abstract {
 	public function abonne_multimedia($user) {
-		if (Class_AdminVar::isMultimediaEnabled()) {
+		$ouvertures = Class_Ouverture::findAll();
+		if (Class_AdminVar::isMultimediaEnabled() && !empty($ouvertures)) {
 
 			$action_url = $this->getActionUrl('multimedia-hold-location');
 
@@ -28,7 +29,7 @@ class ZendAfi_View_Helper_Abonne_Multimedia extends ZendAfi_View_Helper_Abonne_A
 																			$this->view->_("Réserver un poste multimédia"));
 			$html .= '<ul>';
 			foreach ($user->getFutureMultimediaHolds() as $hold) {
-				$html .= sprintf('<li><a href="%s">%s, %s %s, %s</li>', 
+				$html .= sprintf('<li><a href="%s">%s, %s %s, %s</li>',
 												 $this->view->url(['controller' => 'abonne',
 																					 'action' => 'multimedia-hold-view',
 																					 'id' => $hold->getId()],
@@ -38,8 +39,8 @@ class ZendAfi_View_Helper_Abonne_Multimedia extends ZendAfi_View_Helper_Abonne_A
 												 sprintf('pour %smn', (($hold->getEnd() - $hold->getStart()) / 60)),
 												 $hold->getLibelleBib());
 			}
-			
-			
+
+
 		$html .= '</ul>';
 
 		return $this->tagFicheAbonne($html, 'multimedia', $action_url);
@@ -52,7 +53,7 @@ class ZendAfi_View_Helper_Abonne_Multimedia extends ZendAfi_View_Helper_Abonne_A
 
 			$html =  $this->view->tagAnchor($action_url,
 																			$this->view->_("Réserver un poste Webkiosk"));
-		
+
 		return $this->tagFicheAbonne($html, 'multimedia', $action_url);
 
 		}
@@ -63,7 +64,7 @@ class ZendAfi_View_Helper_Abonne_Multimedia extends ZendAfi_View_Helper_Abonne_A
 
 	protected function getActionUrl($action){
 		return  $this->view->url(['controller' => 'abonne',
-																			'action' => $action], 
+																			'action' => $action],
 																		 null, true);
 	}
 }
diff --git a/library/ZendAfi/View/Helper/Avis.php b/library/ZendAfi/View/Helper/Avis.php
index 5c13d06fe3e7c6eb4c2438ba2200feaa353949ad..afcbfedd4b9572a0208a0dbe5df67a0b2bb48a91 100644
--- a/library/ZendAfi/View/Helper/Avis.php
+++ b/library/ZendAfi/View/Helper/Avis.php
@@ -124,7 +124,7 @@ class ZendAfi_View_Helper_Avis extends ZendAfi_View_Helper_BaseHelper {
 
 		$url_avis = $this->_getUrlAvis($avis);
 		$format_text_avis = $avis->getAbonOuBib() ?
-			['text_avis' => $avis->getAvis(), 'lire_la_suite' => false] :
+			['text_avis' => nl2br($avis->getAvis()), 'lire_la_suite' => false] :
 			$this->_formatTextAvis($this->view->escape($avis->getAvis()));
 
 		$text_avis = $format_text_avis['text_avis'];
diff --git a/library/ZendAfi/View/Helper/ModelActionsTable.php b/library/ZendAfi/View/Helper/ModelActionsTable.php
index 4e1fe91fff311647eef73ce2a671f7587f7ac8ce..c4f6a835bccb0296cbe2300b07c7be51aa052c9c 100644
--- a/library/ZendAfi/View/Helper/ModelActionsTable.php
+++ b/library/ZendAfi/View/Helper/ModelActionsTable.php
@@ -40,16 +40,16 @@ class ZendAfi_View_Helper_ModelActionsTable {
 	}
 
 
-	protected function _getUrlForAction($action) {
-		return $this->_getUrlFor('', $action);
+	protected function _getUrlForAction($action, $reset = false) {
+		return $this->_getUrlFor('', $action, 'id', $reset);
 	}
 
 
-	protected function _getUrlFor($controller = '', $action = '', $id_key = 'id') {
+	protected function _getUrlFor($controller = '', $action = '', $id_key = 'id', $reset = false) {
 		return $this->view->url(array_merge($this->getBaseUrl(),
 																				array_filter(['controller'=> $controller,
 																											'action'		=> $action,
-																											$id_key => ''])))
+																											$id_key => ''])), null, $reset)
 			. '/' . $id_key . '/%s';
 	}
 
diff --git a/library/ZendAfi/View/Helper/ModelActionsTable/ArticlesCategories.php b/library/ZendAfi/View/Helper/ModelActionsTable/ArticlesCategories.php
index a79da383283e2ae80c6abd6dcdae8cab8166c09c..c3ce7cc3320d238a5c98b5960034f92f599e5f9d 100644
--- a/library/ZendAfi/View/Helper/ModelActionsTable/ArticlesCategories.php
+++ b/library/ZendAfi/View/Helper/ModelActionsTable/ArticlesCategories.php
@@ -54,7 +54,7 @@ class ZendAfi_View_Helper_ModelActionsTable_ArticlesCategories extends ZendAfi_V
 
 
 		$actions[] = [
-									'url' => $this->_getUrlFor('cms', 'add', 'id_cat'),
+									'url' => $this->_getUrlFor('cms', 'add', 'id_cat', true),
 									'icon' => 'ico/add_news.gif',
 									'label' => 'Ajouter un article',
 									'condition' => function($model) {
@@ -65,7 +65,7 @@ class ZendAfi_View_Helper_ModelActionsTable_ArticlesCategories extends ZendAfi_V
 									}];
 
 		$actions[] = [
-									'url' => $this->_getUrlForAction('add'),
+									'url' => $this->_getUrlForAction('add', true),
 									'icon'	=> 'ico/add_cat.gif',
 									'label' => 'Ajouter une sous-catégorie',
 									'condition' => function($model) {
diff --git a/library/ZendAfi/View/Helper/ModelActionsTable/Bib.php b/library/ZendAfi/View/Helper/ModelActionsTable/Bib.php
index 26e8ef0ed556a109cb4db9dd9ea31c9694449978..7b66ad4afe80bc08c0dd1c76a1937e9861c6d44c 100644
--- a/library/ZendAfi/View/Helper/ModelActionsTable/Bib.php
+++ b/library/ZendAfi/View/Helper/ModelActionsTable/Bib.php
@@ -52,7 +52,7 @@ class ZendAfi_View_Helper_ModelActionsTable_Bib extends ZendAfi_View_Helper_Mode
 	}
 
 
-	protected function _getUrlForAction($actions) {
+	protected function _getUrlForAction($actions, $reset = false) {
 		return $actions;
 	}
 }
diff --git a/library/ZendAfi/View/Helper/Notice/Entete.php b/library/ZendAfi/View/Helper/Notice/Entete.php
index f5950cec9c240db40004e284ca0b5c96085d2fdd..f330ad01a731a5bea08add35fd7c6822ccd4761a 100644
--- a/library/ZendAfi/View/Helper/Notice/Entete.php
+++ b/library/ZendAfi/View/Helper/Notice/Entete.php
@@ -20,6 +20,9 @@
  */
 class ZendAfi_View_Helper_Notice_Entete extends Zend_View_Helper_HtmlElement {
 	public function notice_Entete($notice, $preferences) {
+		if(!$notice)
+			return '';
+
 		if (!array_isset('entete', $preferences))
 			return '';
 
diff --git a/library/startup.php b/library/startup.php
index 1a8ecdba30e3cfb5e009ad1b04bf65dbe51541b8..b6b42231c0732e5adf1e7d9e2c12c3b4f0a47b0f 100644
--- a/library/startup.php
+++ b/library/startup.php
@@ -64,7 +64,7 @@ function defineConstant($name, $value) {
 
 function setupConstants() {
 	defineConstant('BOKEH_MAJOR_VERSION','7.1');
-	defineConstant('BOKEH_RELEASE_NUMBER', BOKEH_MAJOR_VERSION . '.22');
+	defineConstant('BOKEH_RELEASE_NUMBER', BOKEH_MAJOR_VERSION . '.27');
 
 	defineConstant('ROOT_PATH',  realpath(dirname(__FILE__).'/..').'/');
 
diff --git a/tests/application/modules/admin/controllers/AlbumControllerTest.php b/tests/application/modules/admin/controllers/AlbumControllerTest.php
index 9fc6355afc54b20dfedf74fc0aae9d776324ac0e..ef4c6afaf52ccf23066455ab71bc60394bc9bbd3 100644
--- a/tests/application/modules/admin/controllers/AlbumControllerTest.php
+++ b/tests/application/modules/admin/controllers/AlbumControllerTest.php
@@ -1201,7 +1201,6 @@ abstract class Admin_AlbumControllerEditAlbumMesBDTestCase extends Admin_AlbumCo
 			->addCollection('Ratm')
 			->setDistributor('Geffen Records')
 			->save();
-
 	}
 }
 
diff --git a/tests/application/modules/admin/controllers/CmsControllerListModeTest.php b/tests/application/modules/admin/controllers/CmsControllerListModeTest.php
index 4a42e63484b33fd073bad08977b0962ec8e097ea..61b4e46ad664b808a5921db173ae2e81f7e1b6ff 100644
--- a/tests/application/modules/admin/controllers/CmsControllerListModeTest.php
+++ b/tests/application/modules/admin/controllers/CmsControllerListModeTest.php
@@ -53,6 +53,7 @@ class CmsControllerListModeAdminRootTest extends CmsControllerListModeTestCase {
 	}
 
 
+
 	/** @test */
 	public function portalShouldHaveDefaultPermissionsAction() {
 		$this->assertXPath('//td//a[contains(@href, "bib/permissions/id/0")]',
@@ -144,6 +145,14 @@ class CmsControllerListModeAdminBibSubCategoryTest
 		$this->assertXPathContentContains('//td/a[contains(@href, "cms/index/id_cat/23")]',
 																			'A la Une');
 	}
+
+
+	/** @test */
+	public function shouldDisplayAddArticleAction() {
+		$this->assertXPath('//td//a[contains(@href, "cms/add/id_cat/23")]',
+											 $this->_response->getBody());
+	}
+
 }
 
 
diff --git a/tests/application/modules/admin/controllers/OuverturesControllerTest.php b/tests/application/modules/admin/controllers/OuverturesControllerTest.php
index c597c11dfd81fabed4ce8a71804c630b47da3efa..8b9ff6e185539e9c31854c0dcdbe2b2f98a2fe13 100644
--- a/tests/application/modules/admin/controllers/OuverturesControllerTest.php
+++ b/tests/application/modules/admin/controllers/OuverturesControllerTest.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
  */
 require_once 'AdminAbstractControllerTestCase.php';
 
@@ -30,7 +30,7 @@ abstract class OuverturesControllerTestCase extends Admin_AbstractControllerTest
 
 		Class_Bib::newInstanceWithId(1)->setLibelle('Cran-Gévrier');
 		Class_Bib::newInstanceWithId(3)->setLibelle('Annecy');
-		
+
 
 		Storm_Test_ObjectWrapper::onLoaderOfModel('Class_Ouverture')
 			->whenCalled('save')
@@ -105,7 +105,7 @@ class OuverturesControllerIndexActionSiteCranTest extends OuverturesControllerTe
 
 	/** @test */
 	public function titleShouldBePlagesDouvertureDeLaBibliothequeCranGevrier() {
-		$this->assertXPathContentContains('//h1', 'Cran-Gévrier: plages d\'ouverture');
+		$this->assertXPathContentContains('//h1', 'Cran-Gévrier: plages ouvertes à la réservation des postes multimédia');
 	}
 }
 
@@ -164,7 +164,7 @@ class OuverturesControllerEditOuvertureMardiTest extends OuverturesControllerTes
 	public function formShouldContainsSelectForJour() {
 		$this->assertXPath('//form//input[@name="jour"][@value="23/07/2012"]');
 	}
-	
+
 
 	/** @test */
 	public function formShouldContainsSelectForDebutMatinWithHours() {
@@ -237,7 +237,7 @@ class OuverturesControllerAddOuvertureCranTest extends OuverturesControllerTestC
 		$this->dispatch('/admin/ouvertures/add/id_site/1', true);
 	}
 
-	
+
 	/** @test */
 	public function formShouldContainsSelectForDebutMatin() {
 		$this->assertXPath('//form//select[@name="debut_matin"]');
@@ -273,8 +273,8 @@ class OuverturesControllerPostAddOuvertureCranTest extends OuverturesControllerT
 	public function setUp() {
 		parent::setUp();
 
-		Class_Ouverture::whenCalled('save')->willDo(function($model) { 
-																									$model->setId(99); 
+		Class_Ouverture::whenCalled('save')->willDo(function($model) {
+																									$model->setId(99);
 																									return true;
 																								});
 
diff --git a/tests/application/modules/admin/controllers/ZoneControllerTest.php b/tests/application/modules/admin/controllers/ZoneControllerTest.php
index 21e019877aa5890a6de8947feb5ddb780c6ad0a7..54647bbd57396ee20f651bea1866eb9eb0d7c0d2 100644
--- a/tests/application/modules/admin/controllers/ZoneControllerTest.php
+++ b/tests/application/modules/admin/controllers/ZoneControllerTest.php
@@ -16,35 +16,37 @@
  *
  * 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
  */
 require_once 'AbstractControllerTestCase.php';
 
 abstract class ZoneControllerTestCase extends AbstractControllerTestCase {
 	public function setUp() {
 		parent::setUp();
-		$this->zone_annecy = Class_Zone::getLoader()
-			->newInstanceWithId(2)
-			->setLibelle('Annecy')
-			->setCouleur('#123')
-			->setMapCoords('93,14,87,20')
-			->setImage('bassin annecy.jpg');
-
-		$this->zone_pringy = Class_Zone::getLoader()
-			->newInstanceWithId(4)
-			->setLibelle('Pringy')
-			->setCouleur('#456')
-			->setImage('pringy.jpg');
-
-
-		$this->loader_wrapper = Storm_Test_ObjectWrapper::onLoaderOfModel('Class_Zone')
-			->whenCalled('findAll')
-			->answers(array($this->zone_annecy, $this->zone_pringy))
-			->getWrapper();
-	}	
+		Storm_Model_Loader::defaultToVolatile();
+		$this->zone_annecy = $this->fixture('Class_Zone',
+																				['id' => 2,
+																				 'libelle' => 'Annecy',
+																				 'couleur' => '#123',
+																				 'map_coords' => '93,14,87,20',
+																				 'image' => 'bassin annecy.jpg']);
+
+		$this->zone_pringy = $this->fixture('Class_Zone',
+																				['id' => 4,
+																				 'libelle' => 'Pringy',
+																				 'couleur' => '#456',
+																				 'image' => 'pringy.jpg']);
+	}
+
+
+	public function tearDown() {
+		Storm_Model_Loader::defaultToDb();
+		parent::tearDown();
+	}
 }
 
 
+
 class ZoneControllerIndexActionTest extends ZoneControllerTestCase {
 	public function setUp(){
 		parent::setUp();
@@ -69,7 +71,14 @@ class ZoneControllerIndexActionTest extends ZoneControllerTestCase {
 class ZoneControllerPlacerBibsActionTest extends ZoneControllerTestCase {
 	public function setUp() {
 		parent::setUp();
-		$this->dispatch('admin/zone/placerbibs/id_zone/2');
+
+		$this->fixture('Class_Bib',
+									 ['id' => 1,
+										'libelle' => 'Annecy',
+										'id_zone' => 2,
+										'visibilite' => 1]);
+
+		$this->dispatch('admin/zone/placerbibs/id_zone/2', true);
 	}
 
 
@@ -81,6 +90,105 @@ class ZoneControllerPlacerBibsActionTest extends ZoneControllerTestCase {
 
 
 
+abstract class ZoneControllerPlacerBibsPostActionTestCase extends ZoneControllerTestCase {
+	public function setUp() {
+		parent::setUp();
+
+		$this->fixture('Class_Profil',
+									 ['id' => 1,
+										'libelle' => 'Home']);
+
+		$this->fixture('Class_Profil',
+									 ['id' => 2,
+										'libelle' => 'Bib d\'Annecy']);
+
+		$this->fixture('Class_Bib',
+									 ['id' => 1,
+										'libelle' => 'Annecy',
+										'id_zone' => 2,
+										'visibilite' => 1]);
+	}
+}
+
+
+
+class ZoneControllerPlacerBibsPostActionWithProfilTest extends ZoneControllerPlacerBibsPostActionTestCase {
+
+	public function setUp() {
+		parent::setUp();
+
+		$aff_zone = ZendAfi_Filters_Serialize::serialize(['posX' => '25',
+																											'posY' => '65',
+																											'posPoint' => 'above',
+																											'profilID' => '1']);
+
+		Class_Bib::find(1)->setAffZone($aff_zone)->save();
+
+		$this->postDispatch('admin/zone/placerbibs/id_zone/2', ['posX_1' => '50',
+																														'posY_1' => '150',
+																														'posPoint_1' => 'left',
+																														'profilID_1' => '2']);
+	}
+
+
+  /** @test */
+	public function urlForAnnecyShouldBeProfil() {
+		$this->assertEquals('/index/index/id_profil/2', Class_Bib::find(1)->getUrl());
+	}
+
+
+	/** @test */
+	public function annecyPosXShouldBe50() {
+		$this->assertEquals('50', Class_Bib::find(1)->getPosX());
+	}
+
+}
+
+
+
+class ZoneControllerPlacerBibsPostActionWithOutTest extends ZoneControllerPlacerBibsPostActionTestCase {
+
+	public function setUp() {
+		parent::setUp();
+		$this->postDispatch('admin/zone/placerbibs/id_zone/2', ['posX_1' => '50',
+																														'posY_1' => '150',
+																														'posPoint_1' => 'left']);
+	}
+
+
+  /** @test */
+	public function urlForAnnecyShouldBeBeBibView() {
+		$this->assertEquals('/bib/bibview/id/1', Class_Bib::find(1)->getUrl());
+	}
+
+
+	/** @test */
+	public function annecyPosXShouldBe50() {
+		$this->assertEquals('50', Class_Bib::find(1)->getPosX());
+	}
+
+
+	/** @test */
+	public function annecyPosYShouldBe150() {
+		$this->assertEquals('150', Class_Bib::find(1)->getPosY());
+	}
+
+
+	/** @test */
+	public function posPointForAnnecyShouldBeLeft() {
+		$this->assertEquals('left', Class_Bib::find('1')->getPosPoint());
+	}
+
+
+	/** @test */
+	public function profilForAnnecyShouldBeEmpty() {
+		$this->assertEquals('0', Class_Bib::find('1')->getProfilId());
+	}
+}
+
+
+
+
 class ZoneControllerEditAnnecyTest extends ZoneControllerTestCase {
 	public function setUp() {
 		parent::setUp();
@@ -137,21 +245,10 @@ class ZoneControllerPostValidDataForAnnecyTest extends ZoneControllerTestCase {
 	public function setUp() {
 		parent::setUp();
 
-		$data = array('libelle' => 'Bassin annécien',
-									'couleur' => '123456',
-									'map_coords' => '34,45',
-									'image' => 'paquier.jpg');
-
-		$this->loader_wrapper
-			->whenCalled('save')
-			->answers(true);
-
-		$this
-			->getRequest()
-			->setMethod('POST')
-			->setPost($data);
-
-		$this->dispatch('admin/zone/edit/id/2');
+		$this->postDispatch('admin/zone/edit/id/2', ['libelle' => 'Bassin annécien',
+																								 'couleur' => '123456',
+																								 'map_coords' => '34,45',
+																								 'image' => 'paquier.jpg']);
 	}
 
 
@@ -163,7 +260,7 @@ class ZoneControllerPostValidDataForAnnecyTest extends ZoneControllerTestCase {
 
 	/** @test */
 	function shouldRedirectToIndexPage() {
-		$this->assertRedirect('admin/zone/index');	
+		$this->assertRedirect('admin/zone/index');
 	}
 
 
@@ -174,28 +271,18 @@ class ZoneControllerPostValidDataForAnnecyTest extends ZoneControllerTestCase {
 }
 
 
+
 class ZoneControllerPostEmptyLabelForAnnecyTest extends ZoneControllerTestCase {
 	public function setUp() {
 		parent::setUp();
 
-		$data = array('libelle' => '');
-
-		$this->loader_wrapper
-			->whenCalled('save')
-			->answers(true);
-
-		$this
-			->getRequest()
-			->setMethod('POST')
-			->setPost($data);
-
-		$this->dispatch('admin/zone/edit/id/2');
+		$this->postDispatch('admin/zone/edit/id/2', ['libelle' => '']);
 	}
 
 
 	/** @test */
 	function shouldNotRedirectToIndexPage() {
-		$this->assertNotRedirect('admin/zone/index');	
+		$this->assertNotRedirect('admin/zone/index');
 	}
 
 	/** @test */
@@ -223,24 +310,12 @@ class ZoneControllerAddActionTest extends ZoneControllerTestCase {
 
 	/** @test */
 	function postShouldSaveNewObject() {
-		$data = array('libelle' => 'Cran',
-									'couleur' => '#456',
-									'map_coords' => '34,45',
-									'image' => 'paquier.jpg');
-
-		$this->loader_wrapper
-			->whenCalled('save')
-			->answers(true);
-
-		$this
-			->getRequest()
-			->setMethod('POST')
-			->setPost($data);
-
-		$this->dispatch('admin/zone/add');
+		$this->postDispatch('admin/zone/add', ['libelle' => 'Cran',
+																					 'couleur' => '#456',
+																					 'map_coords' => '34,45',
+																					 'image' => 'paquier.jpg']);
 
-		$new_zone = $this->loader_wrapper->getFirstAttributeForLastCallOn('save');
-		$this->assertEquals('Cran', $new_zone->getLibelle());
+		$this->assertEquals('Cran', Class_Zone::find(5)->getLibelle());
 	}
 }
 
diff --git a/tests/application/modules/opac/controllers/AbonneControllerMultimediaTest.php b/tests/application/modules/opac/controllers/AbonneControllerMultimediaTest.php
index bcb33bef6ca9a0dbaf055004dfaf210856402846..b80041d229fec075a64442d52a826dcd94ce1c71 100644
--- a/tests/application/modules/opac/controllers/AbonneControllerMultimediaTest.php
+++ b/tests/application/modules/opac/controllers/AbonneControllerMultimediaTest.php
@@ -24,14 +24,30 @@ require_once 'application/modules/opac/controllers/AbonneController.php';
 
 trait TAbonneControllerMultimediaFixtureHoldSuccessOnSept12 {
 	protected function _launch() {
-		$this->onLoaderOfModel('Class_Multimedia_Location')
+/*		$this->onLoaderOfModel('Class_Multimedia_Location')
 			->whenCalled('findByIdOrigine')
 			->answers(Class_Multimedia_Location::newInstanceWithId(1));
 
 
 		$this->onLoaderOfModel('Class_Multimedia_Device')
 			->whenCalled('findByIdOrigineAndLocation')
-			->answers(Class_Multimedia_Device::newInstanceWithId(1));
+			->answers(Class_Multimedia_Device::newInstanceWithId(1));*/
+		$this->fixture('Class_Multimedia_Device',
+									 ['id' => 1,
+										'id_origine' => '1-1',
+										'group' => $this->fixture('Class_Multimedia_DeviceGroup',
+																								 ['id' => 1,
+																									'location' => $this->fixture('Class_Multimedia_Location',
+																																							 ['id' => 1, 'id_origine' => 1,
+																																								'ouvertures' => $this->fixture('Class_Ouverture',
+																																																											['id' => 1,
+																																																											 'Jour' => '2012-09-12',
+																																																											 'horaires' => ['08:00', '12:00', '12:00', '18:00']])
+																																							 ])
+																								 ])
+													]);
+
+
 
 		$this->onLoaderOfModel('Class_Multimedia_DeviceHold')
 			->whenCalled('getHoldOnDeviceAtTime')
@@ -246,13 +262,12 @@ class AbonneControllerMultimediaAuthenticateInviteAfiMultimediaTest extends Abon
 }
 
 
-
-
 abstract class AbonneControllerMultimediaAuthenticateValidTestCase extends AbonneControllerMultimediaAuthenticateTestCase {
 	protected $_user;
 	protected $_group;
 
 	public function setUp() {
+		Class_Multimedia_Location::setTimeSource(new TimeSourceForTest('2012-09-12 09:00:00'));
 		parent::setUp();
 
 		$this->_initUser();
@@ -261,21 +276,47 @@ abstract class AbonneControllerMultimediaAuthenticateValidTestCase extends Abonn
 		$this->_launch();
 	}
 
+	protected function _initUser() {}
+}
 
+abstract class AbonneControllerMultimediaCheckedHoldableDayTestCase extends AbonneControllerMultimediaAuthenticateValidTestCase {
 	protected function _launch() {
-		$this->_json = $this->getJson(sprintf('/abonne/authenticate/login/%s/password/%s/poste/1/site/1',
+		$this->_json = $this->getJson(sprintf('/abonne/authenticate/login/%s/password/%s/poste/1/site/1/mode/holdable-day',
 																					$this->_user->getLogin(),
 																					$this->_user->getPassword()));
 	}
 
+}
+
+
+class AbonneControllerMultimediaHoldableDay extends AbonneControllerMultimediaCheckedHoldableDayTestCase {
+		use
+		TAbonneControllerMultimediaFixtureHoldSuccessOnSept12,
+		TAbonneControllerMultimediaFixtureWithUserLaurentInDevsAgiles;
+
+		/** @test */
+		public function shouldHaveAuth() {
+			$this->assertEquals(1, $this->_json->auth);
+		}
+
+		/** @test */
+		public function shouldHaveHoldedDay() {
+			$this->assertEquals(1, $this->_json->holding);
+		}
 
-	protected function _initUser() {}
 }
 
 
+abstract class AbonneControllerMultimediaHoldedTestCase extends AbonneControllerMultimediaAuthenticateValidTestCase {
+	protected function _launch() {
+		$this->_json = $this->getJson(sprintf('/abonne/authenticate/login/%s/password/%s/poste/1/site/1/mode/hold',
+																					$this->_user->getLogin(),
+																					$this->_user->getPassword()));
+	}
+}
 
 
-class AbonneControllerMultimediaAuthenticateLaurentTest extends AbonneControllerMultimediaAuthenticateValidTestCase {
+class AbonneControllerMultimediaAuthenticateLaurentTest extends AbonneControllerMultimediaHoldedTestCase {
 	use
 		TAbonneControllerMultimediaFixtureHoldSuccessOnSept12,
 		TAbonneControllerMultimediaFixtureWithUserLaurentInDevsAgiles;
@@ -330,107 +371,24 @@ class AbonneControllerMultimediaAuthenticateLaurentTest extends AbonneController
 
 
 	/** @test */
-	public function shouldHaveHold() {
+	public function shouldHaveAuth() {
 		$this->assertEquals(1, $this->_json->auth);
 	}
 
-
-	/** @test */
-	public function holdShouldLastUntil16h40() {
-		$this->assertEquals('2012-09-12T16:40:00+02:00', $this->_json->until);
-	}
-}
-
-
-class AbonneControllerMultimediaAuthenticateLaurentAtClosingDaysDeviceHoldByUserTest extends AbonneControllerMultimediaAuthenticateValidTestCase {
-	use TAbonneControllerMultimediaFixtureWithUserLaurentInDevsAgiles;
-
-	protected function _launch() {
-
-		Class_Multimedia_Location::setTimeSource(new TimeSourceForTest('2012-09-12 09:30:00'));
-
-		$this->onLoaderOfModel('Class_Multimedia_Location')
-			->whenCalled('findByIdOrigine')
-			->answers($location = Class_Multimedia_Location::newInstanceWithId(1)
-								->setSlotSize(30)
-								->setAutoholdSlotsMax(1)
-								->setAuthDelay(1)
-								->setAutohold(1)
-								->setOuvertures([])
-								->setAutoholdForClosingDays(1)
-								->setOpenHour('09:00')
-								->setCloseHour('17:00'));
-
-		$this->onLoaderOfModel('Class_Multimedia_Device')
-			->whenCalled('findByIdOrigineAndLocation')
-			->answers(Class_Multimedia_Device::newInstanceWithId(1)
-								->setGroup(Class_Multimedia_DeviceGroup::newInstanceWithId(34)->setLocation($location)));
-
-
-		$this->onLoaderOfModel('Class_Multimedia_DeviceHold')
-			->whenCalled('getHoldOnDeviceAtTime')
-			->answers(null);
-
-		parent::_launch();
-	}
-
-
 	/** @test */
 	public function shouldHaveHold() {
-		$this->assertEquals(1, $this->_json->auth);
-	}
-
-	/** @test */
-	public function holdShouldLastUntil16h40() {
-		$this->assertEquals('2012-09-12T10:00:00+02:00', $this->_json->until);
-	}
-
-
-}
-
-
-class AbonneControllerMultimediaAuthenticateLaurentAtClosingDaysDeviceNotHeldByUserTest extends AbonneControllerMultimediaAuthenticateValidTestCase {
-	use TAbonneControllerMultimediaFixtureWithUserLaurentInDevsAgiles;
-
-	protected function _launch() {
-
-		Class_Multimedia_Location::setTimeSource(new TimeSourceForTest('2012-09-12 09:30:00'));
-
-		$this->onLoaderOfModel('Class_Multimedia_Location')
-			->whenCalled('findByIdOrigine')
-			->answers($location = Class_Multimedia_Location::newInstanceWithId(1)
-								->setAuthDelay(1)
-								->setAutohold(1)
-								->setOuvertures([])
-								->setAutoholdForClosingDays(0)
-								->setOpenHour('09:00')
-								->setCloseHour('17:00'));
-
-		$this->onLoaderOfModel('Class_Multimedia_Device')
-			->whenCalled('findByIdOrigineAndLocation')
-			->answers(Class_Multimedia_Device::newInstanceWithId(1)
-								->setGroup(Class_Multimedia_DeviceGroup::newInstanceWithId(34)->setLocation($location)));
-
-
-		$this->onLoaderOfModel('Class_Multimedia_DeviceHold')
-			->whenCalled('getHoldOnDeviceAtTime')
-			->answers(null);
-
-		parent::_launch();
+		$this->assertEquals(1, $this->_json->holded);
 	}
 
 
 	/** @test */
-	public function shouldHaveNotHeld() {
-		$this->assertEquals(0, $this->_json->auth);
+	public function holdShouldLastUntil16h40() {
+		$this->assertEquals('2012-09-12T16:40:00+02:00', $this->_json->until);
 	}
-
-
 }
 
 
-
-class AbonneControllerMultimediaAuthenticateLaurentDeviceNotHeldByUserTest extends AbonneControllerMultimediaAuthenticateValidTestCase {
+class AbonneControllerMultimediaAuthenticateLaurentDeviceNotHeldByUserTest extends AbonneControllerMultimediaHoldedTestCase {
 	use TAbonneControllerMultimediaFixtureWithUserLaurentInDevsAgiles;
 
 	protected function _launch() {
@@ -438,7 +396,6 @@ class AbonneControllerMultimediaAuthenticateLaurentDeviceNotHeldByUserTest exten
 			->whenCalled('findByIdOrigine')
 			->answers($location = Class_Multimedia_Location::newInstanceWithId(1)
 								->setAuthDelay(1)
-								->setAutoholdForClosingDays(0)
 								->setAutohold(1));
 
 		$this->onLoaderOfModel('Class_Multimedia_Device')
@@ -478,7 +435,7 @@ class AbonneControllerMultimediaAuthenticateLaurentDeviceNotHeldByUserTest exten
 
 
 
-class AbonneControllerMultimediaAuthenticateLaurentDeviceNotFoundTest extends AbonneControllerMultimediaAuthenticateValidTestCase {
+class AbonneControllerMultimediaAuthenticateLaurentDeviceNotFoundTest extends AbonneControllerMultimediaHoldedTestCase {
 	use TAbonneControllerMultimediaFixtureWithUserLaurentInDevsAgiles;
 	protected function _launch() {
 		$this->onLoaderOfModel('Class_Multimedia_Location')
@@ -507,7 +464,7 @@ class AbonneControllerMultimediaAuthenticateLaurentDeviceNotFoundTest extends Ab
 
 
 
-class AbonneControllerMultimediaAuthenticateArnaudTest extends AbonneControllerMultimediaAuthenticateValidTestCase {
+class AbonneControllerMultimediaAuthenticateArnaudTest extends AbonneControllerMultimediaHoldedTestCase {
 	use TAbonneControllerMultimediaFixtureHoldSuccessOnSept12;
 
 	protected function _initUser() {
@@ -531,7 +488,7 @@ class AbonneControllerMultimediaAuthenticateArnaudTest extends AbonneControllerM
 
 
 
-class AbonneControllerMultimediaAuthenticateBaptisteTest extends AbonneControllerMultimediaAuthenticateValidTestCase {
+class AbonneControllerMultimediaAuthenticateBaptisteTest extends AbonneControllerMultimediaHoldedTestCase {
 	use TAbonneControllerMultimediaFixtureHoldSuccessOnSept12;
 
 	protected function _initUser() {
@@ -560,8 +517,6 @@ class AbonneControllerMultimediaAuthenticateBaptisteTest extends AbonneControlle
 }
 
 
-
-
 /* Début test du workflow de réservation */
 abstract class AbonneControllerMultimediaHoldTestCase extends AbstractControllerTestCase {
 	protected $_session;
@@ -597,7 +552,6 @@ abstract class AbonneControllerMultimediaHoldTestCase extends AbstractController
 			->setLibelle('Antibes')
 			->setSlotSize(30)
 			->setMaxSlots(4)
-			->setAutoholdForClosingDays(0)
 			->setHoldDelayMin(0)
 			->setHoldDelayMax(60)
 			->setOuvertures([Class_Ouverture::chaqueLundi('08:30', '12:00', '12:00', '17:45')->setId(1)->cache(),
@@ -1345,6 +1299,8 @@ class AbonneControllerMultimediaHoldFicheAbonneTest extends AbstractControllerTe
 																											->setBib(Class_Bib::newInstanceWithId(5)
 																															 ->setLibelle('Médiathèque d\'Antibes')))))
 								 ]);
+		 $this->fixture('Class_Ouverture', ['id' => 1]);
+
 		$this->dispatch('/abonne/fiche', true);
 	}
 
diff --git a/tests/application/modules/opac/controllers/BibControllerTest.php b/tests/application/modules/opac/controllers/BibControllerTest.php
index cc9814c65bca68b5ec3a51095b11ec9b98927e7d..632c528ae7432e1cf4ecd397f0639941ee65a629 100644
--- a/tests/application/modules/opac/controllers/BibControllerTest.php
+++ b/tests/application/modules/opac/controllers/BibControllerTest.php
@@ -197,19 +197,30 @@ class BibControllerIndexWithShowNewsTest extends BibControllerWithZoneTestCase {
 }
 
 
-class BibControllerMapViewTest extends BibControllerWithZoneTestCase {
+
+abstract class BibControllerMapViewTest extends BibControllerWithZoneTestCase {
 	public function setUp() {
 		parent::setUp();
 
 		$this->fixture('Class_Profil',
 									 ['id' => 3,
 										'libelle' => 'Annecy']);
+	}
+}
+
+
+
+class BibControllerMapViewWithProfilTest extends BibControllerMapViewTest {
+
+	public function setUp() {
+		parent::setUp();
 
 		$aff_zone = ['profilID' => '3',
 								 'libelle' => 'Annecy',
 								 'posX' => 2,
 								 'posY' => 5,
 								 'posPoint' => 'droite'];
+
 		$this->bib_annecy->setAffZone(ZendAfi_Filters_Serialize::serialize($aff_zone));
 
 		$this->dispatch('bib/mapzoneview/id/1');
@@ -236,7 +247,32 @@ class BibControllerMapViewTest extends BibControllerWithZoneTestCase {
 
 	/** @test */
 	public function bibAnnecyShouldBeVisibleOnMap() {
-		$this->assertXPathContentContains("//span[contains(@onclick, '/id_profil/3')]", "Annecy");
+		$this->assertXPathContentContains("//span[contains(@onclick, 'index/index/id_profil/3')]", "Annecy", $this->_response->getBody());
+	}
+}
+
+
+
+class BibControllerMapViewWithoutProfilTest extends BibControllerMapViewTest {
+
+	public function setUp() {
+		parent::setUp();
+
+		$aff_zone = ['profilID' => '',
+								 'libelle' => 'Annecy',
+								 'posX' => 2,
+								 'posY' => 5,
+								 'posPoint' => 'droite'];
+
+		$this->bib_annecy->setAffZone(ZendAfi_Filters_Serialize::serialize($aff_zone));
+
+		$this->dispatch('bib/mapzoneview/id/1');
+	}
+
+
+	/** @test */
+	public function bibAnnecyShouldBeVisibleOnMap() {
+		$this->assertXPathContentContains("//span[contains(@onclick, 'bibview/id/4')]", "Annecy", $this->_response->getBody());
 	}
 }
 
diff --git a/tests/application/modules/opac/controllers/ProfilOptionsControllerTest.php b/tests/application/modules/opac/controllers/ProfilOptionsControllerTest.php
index 43ff03c6673a86f7c74e34892d185134fd9cfa10..2d11113d0e217d5908b8427df3b7f32883e70d6c 100644
--- a/tests/application/modules/opac/controllers/ProfilOptionsControllerTest.php
+++ b/tests/application/modules/opac/controllers/ProfilOptionsControllerTest.php
@@ -2414,4 +2414,98 @@ class ProfilOptionsControllerSelectedActionInMenuVerticalWidgetInHomeTest extend
 		$this->assertXPathContentContains('//ul/li//ul/li[@class="menuGauche"]', 'Bokeh FAQ');
 	}
 }
-?>
\ No newline at end of file
+
+
+
+abstract class ProfilOptionControllerHeritedModulesTestCase extends AbstractControllerTestCase {
+	protected $_profil_portal, $_profil_gnu;
+
+	public function setUp() {
+		parent::setUp();
+
+		$this->fixture('Class_AdminVar',['id'=>'MENU_BOITE', 'valeur' => 0]);
+
+		$this->_profil_portal = $this->fixture('Class_Profil',
+																					 ['id' => 1,
+																						'browser' => 'opac',
+																						'libelle' => 'Bokeh Portal'])
+																 ->setCfgAccueil(['modules' => ['1' => ['division' => '4',
+																																				'type_module' => 'RECH_SIMPLE',
+																																				'preferences' => []],
+																																'4' => ['division' => '4',
+																																				'type_module' => 'NEWS']]]);
+
+		$this->_profil_gnu = $this->fixture('Class_profil',
+																				['id' => 2,
+																				 'parent_profil' => $this->_profil_portal,
+																				 'browser' => 'opac',
+																				 'libelle' => 'A GNU Portal'])
+															->setCfgAccueil(['modules' => ['4' => ['division' => '1',
+																																		 'type_module' => 'NEWS'],
+																														 '10' => ['division' => '1',
+																																			'type_module' => 'NEWS']]]);
+	}
+}
+
+
+
+class ProfilOptionControllerWithHeritedBannerTest extends ProfilOptionControllerHeritedModulesTestCase {
+
+	public function setUp() {
+		parent::setUp();
+		$this->_profil_gnu->beCurrentProfil()->save();
+		$this->dispatch('/opac', true);
+	}
+
+
+	/** @test */
+	public function htmlShouldContainsOnlyOneIdBoite4() {
+		$this->assertXPathCount('//div[@id="boite_4"]', 1);
+	}
+
+
+	/** @test */
+	public function htmlShouldContainsIdBoite11() {
+		$this->assertXPathCount('//div[@id="boite_11"]', 1);
+	}
+
+
+	/** @test */
+	public function profilShouldIncrementCfgIdsAndDeleteOldId() {
+		$this->assertEquals([10,11], array_keys(Class_Profil::find(2)->getCfgAccueilAsArray()['modules']));
+	}
+}
+
+
+
+class ProfilOptionControllerWithHeritedPagesTest extends ProfilOptionControllerHeritedModulesTestCase {
+
+	public function setUp() {
+		parent::setUp();
+
+		$this->_profil_portal
+			->setSubProfils([$this->_profil_gnu])
+			->beCurrentProfil()
+			->save();
+
+		$this->dispatch('/opac', true);
+	}
+
+
+	/** @test */
+	public function htmlShouldContainsIdBoite1() {
+		$this->assertXPathCount('//div[@id="boite_1"]', 1);
+	}
+
+
+	/** @test */
+	public function htmlShouldContainsIdBoite4() {
+		$this->assertXPathCount('//div[@id="boite_4"]', 1);
+	}
+
+
+	/** @test */
+	public function profilShouldIncrementCfgIdsAndDeleteOldId() {
+		$this->assertEquals([10,11], array_keys(Class_Profil::find(2)->getCfgAccueilAsArray()['modules']));
+	}
+}
\ No newline at end of file
diff --git a/tests/application/modules/telephone/controllers/IndexControllerTest.php b/tests/application/modules/telephone/controllers/IndexControllerTest.php
index 2b0c1b0a8b98ac7c308f43ebd605db46f72d0a57..5a90b38124f69309b87ceaff3a767f8e7dab6d03 100644
--- a/tests/application/modules/telephone/controllers/IndexControllerTest.php
+++ b/tests/application/modules/telephone/controllers/IndexControllerTest.php
@@ -80,9 +80,11 @@ abstract class AbstractIndexControllerTelephoneWithModulesTest extends Telephone
 																->setHeaderCss('mon_style.css')
 																->setHauteurBanniere(150)
 																->setBrowser('telephone')
-																->setSubProfils([$this->fixture('Class_Profil', ['id' => 34])])
 																->beCurrentProfil();
 
+		$this->fixture('Class_Profil', ['id' => 34,
+																		'parent_profil' => $this->profil_adulte]);
+
 		Class_Profil_Skin::setFileSystem((new Storm_FileSystem_Volatile())
 																		 ->mkdir('/public/opac/skins/vide/css/')
 																		 ->touch('/public/opac/skins/vide/css/mobile.css'));
@@ -98,6 +100,7 @@ abstract class AbstractIndexControllerTelephoneWithModulesTest extends Telephone
 }
 
 
+
 class IndexControllerTelephoneOnSubpageTest extends AbstractIndexControllerTelephoneWithModulesTest {
 	public function setUp() {
 		parent::setUp();
diff --git a/tests/library/Class/Cosmogramme/Integration/PhaseItemFacetsTest.php b/tests/library/Class/Cosmogramme/Integration/PhaseItemFacetsTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..cc3fa3e164d9812185ff9bd1cfd5e92c355180ff
--- /dev/null
+++ b/tests/library/Class/Cosmogramme/Integration/PhaseItemFacetsTest.php
@@ -0,0 +1,150 @@
+<?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 PhaseItemFacetsTestCase extends Storm_Test_ModelTestCase {
+	protected $_log_content, $_printer_content;
+
+	public function setUp() {
+		parent::setUp();
+		Storm_Model_Loader::defaultToVolatile();
+
+		$this->_log = $this->mock()
+											 ->whenCalled('ecrire')
+											 ->willDo(function($content) { $this->_log_content .= $content; });
+
+		$this->_chrono = new Class_Cosmogramme_Integration_Chronometre();
+		$this->_printer = $this->mock()
+													 ->whenCalled('nextPutAll')
+													 ->willDo(function($content) { $this->_printer_content .= $content; });
+
+		$this->_prepareFixtures();
+
+		$items_facets = (new Class_Cosmogramme_Integration_PhaseItemFacets($this->_previousPhase(), $this->_log, $this->_chrono))
+			->noDbReset()
+			->setPrinter($this->_printer);
+
+		$this->_phase = $items_facets->run();
+	}
+
+
+	public function tearDown() {
+		Storm_Model_Loader::defaultToDb();
+		parent::tearDown();
+	}
+
+
+	protected function assertLogContains($value) {
+		$this->assertContains($value, $this->_log_content);
+	}
+
+
+	protected function _previousPhase() {
+		return null;
+	}
+
+
+	protected function _prepareFixtures() {
+	}
+}
+
+
+
+class PhaseItemFacetsBadPreviousPhaseTest extends PhaseItemFacetsTestCase {
+	protected function _previousPhase() {
+		return new Class_Cosmogramme_Integration_Phase(2);
+	}
+
+
+	/** @test */
+	public function shouldNotChangePhase() {
+		$this->assertTrue($this->_phase->isId(2));
+	}
+}
+
+
+
+class PhaseItemFacetsExpectedPreviousPhaseTest extends PhaseItemFacetsTestCase {
+	protected function _previousPhase() {
+		return (new Class_Cosmogramme_Integration_Phase(4))
+			->beCron();
+	}
+
+
+	protected function _prepareFixtures() {
+		$this->fixture('Class_CosmoVar',
+									 ['id' => 'date_maj_facettes',
+										'valeur' => '']);
+
+		$this
+			->onLoaderOfModel('Class_Notice')
+			->whenCalled('findAllAfter')
+			->answers([$this->fixture('Class_Notice',
+																['id' => 1,
+																 'date_maj' => '2015-04-05 15:08:34'])]);
+	}
+
+
+	/** @test */
+	public function shouldChangePhase() {
+		$this->assertTrue($this->_phase->isId(7));
+	}
+
+
+	/** @test */
+	public function logShouldContainsPhaseLabel() {
+		$this->assertLogContains('Mise à jour des facettes exemplaires');
+	}
+
+
+	/** @test */
+	public function logShouldContainsProcessedRecordCount() {
+		$this->assertLogContains('1 notices traitées');
+	}
+
+
+	/** @test */
+	public function lastFacetsUpdateDateShouldBeSet() {
+		$this->assertNotEquals('', Class_CosmoVar::getValueOf('date_maj_facettes'));
+	}
+}
+
+
+
+abstract class PhaseItemFacetsCallbackTest extends PhaseItemFacetsTestCase {
+	protected function _previousPhase() {
+		return (new Class_Cosmogramme_Integration_Phase(4));
+	}
+
+
+	protected function _prepareFixtures() {
+		$this->fixture('Class_CosmoVar',
+									 ['id' => 'date_maj_facettes',
+										'valeur' => '']);
+
+		$this
+			->onLoaderOfModel('Class_Notice')
+			->whenCalled('findAllAfter')
+			->answers([$this->fixture('Class_Notice',
+																['id' => 1,
+																 'date_maj' => '2015-04-05 15:08:34'])]);
+	}
+}
\ No newline at end of file
diff --git a/tests/library/Class/Multimedia/DeviceTest.php b/tests/library/Class/Multimedia/DeviceTest.php
index 9f15bd401c740ee6da04da8d8dfbc883a6180ec4..499fc6a3b339e52f9974d2e4273e174ca0c182b6 100644
--- a/tests/library/Class/Multimedia/DeviceTest.php
+++ b/tests/library/Class/Multimedia/DeviceTest.php
@@ -179,7 +179,6 @@ class Multimedia_DeviceCurrentHoldForUserWithoutHoldAndAnotherValidHoldTest exte
 			->setAuthDelay(10)
 			->setAutohold(1)
 			->setSlotSize(15)
-			->setAutoholdForClosingDays(1)
 			->save();
 	}
 
diff --git a/tests/library/Class/Multimedia/LocationTest.php b/tests/library/Class/Multimedia/LocationTest.php
index 4ecc4ef33575d78f2acf4b4624aeec78b88049df..287bb49adf968295b78ecb96b22fed5f4c8976b3 100644
--- a/tests/library/Class/Multimedia/LocationTest.php
+++ b/tests/library/Class/Multimedia/LocationTest.php
@@ -181,8 +181,7 @@ class Multimedia_LocationWithBibTest extends Multimedia_LocationWithBibTestCase
 	/** @test */
 	public function getDatesOuvertureShouldAnswersAllMercrediJeudiForNextTwoMonthsWith9and19Sept() {
 		$this->_time_source->setTime(strtotime('2012-08-05'));
-		$this->_location->setHoldDelayMax(60)
-										->setAutoholdForClosingDays(false);
+		$this->_location->setHoldDelayMax(60);
 		$this->assertEquals(['2012-08-08', '2012-08-09',
 												 '2012-08-15', '2012-08-16',
 												 '2012-08-22', '2012-08-23',
@@ -195,28 +194,6 @@ class Multimedia_LocationWithBibTest extends Multimedia_LocationWithBibTestCase
 												 '2012-10-03', '2012-10-04'],
 												$this->_location->getHoldableDays());
 	}
-
-	/** @test */
-	public function getDatesOuvertureMardiClosingDayShouldAnswersOpenHour0800() {
-		$this->_time_source->setTime(strtotime('2012-12-04'));
-		$this->_location->setAutoholdForClosingDays(true)
-										->setOpenHour('08:00')
-										->setCloseHour('17:00');
-		$this->_autohold = 1;
-		$this->assertEquals('08:00', $this->_location->getOuvertureForDate($this->_time_source->time(), $this->_autohold)->getDebutMatin());
-
-	}
-
-	/** @test */
-	public function getDatesOuvertureMardiClosingDayShouldAnswersCloseHour1700() {
-		$this->_time_source->setTime(strtotime('2012-12-04'));
-		$this->_location->setAutoholdForClosingDays(true)
-										->setOpenHour('08:00')
-										->setCloseHour('17:00');
-		$this->_autohold = 1;
-		$this->assertEquals('17:00', $this->_location->getOuvertureForDate($this->_time_source->time(),$this->_autohold)->getFinApresMidi());
-
-	}
 }
 
 
diff --git a/tests/library/ZendAfi/View/Helper/AvisTest.php b/tests/library/ZendAfi/View/Helper/AvisTest.php
index d85bfe77ca4300dd8ee27e8cf0cd622e3f1d0e89..37cad32e3a5e6eb95c7e6968ab684bb37fca0e3f 100644
--- a/tests/library/ZendAfi/View/Helper/AvisTest.php
+++ b/tests/library/ZendAfi/View/Helper/AvisTest.php
@@ -134,6 +134,41 @@ class ViewHelperAvisTestWithAvisNotice extends ViewHelperTestCase {
 }
 
 
+class ViewHelperAvisTestAsBib extends ViewHelperTestCase {
+	public function setUp() {
+		parent::setUp();
+
+		Class_Profil::getCurrentProfil()->setSkin('original');
+
+		$tintin = new Class_Users();
+		$tintin
+			->setId(26)
+			->setPseudo('Tintin');
+
+		$orphan_avis = new Class_AvisNotice();
+		$orphan_avis
+			->setId(67)
+			->setEntete("Bof")
+			->setAvis("Pas\nterrible")
+			->setNote(2.5)
+			->setDateAvis('2010-01-02 10:00:00')
+			->setUser($tintin)
+			->setStatut(0)
+			->setAbonOuBib(1)
+			->setNotices(array());
+
+		$helper = new ZendAfi_View_Helper_Avis();
+		$helper->setView(new ZendAfi_Controller_Action_Helper_View());
+		$this->html = $helper->avis($orphan_avis);
+	}
+
+	public function testBrInAvis() {
+		$this->assertTrue(strpos($this->html, "Pas<br />\nterrible") !== false, $this->html);
+	}
+
+
+}
+
 class ViewHelperAvisTestWithoutAvisNoticeAndModeration extends ViewHelperTestCase {
 	public function setUp() {
 		parent::setUp();
diff --git a/tests/library/ZendAfi/View/Helper/Notice/EnteteTest.php b/tests/library/ZendAfi/View/Helper/Notice/EnteteTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..b12d8da768c94abd0c9a4cbd52279e5432151c8d
--- /dev/null
+++ b/tests/library/ZendAfi/View/Helper/Notice/EnteteTest.php
@@ -0,0 +1,102 @@
+<?php
+/**
+ * Copyright (c) 2012, Agence Française Informatique (AFI). All rights reserved.
+ *
+ * BOKEH is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by
+ * the Free Software Foundation.
+ *
+ * There are special exceptions to the terms and conditions of the AGPL as it
+ * is applied to this software (see README file).
+ *
+ * BOKEH is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * along with BOKEH; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
+ */
+
+
+class ZendAfi_View_Helper_Notice_EnteteTest extends ViewHelperTestCase {
+	protected $_html;
+
+	public function setUp() {
+		parent::setUp();
+		Storm_Model_Loader::defaultToVolatile();
+		$this->_helper = new ZendAfi_View_Helper_Notice_Entete();
+		$this->_helper->setView(new ZendAfi_Controller_Action_Helper_View());
+		$this->_view = new ZendAfi_Controller_Action_Helper_View();
+
+		$this->fixture('Class_IntBib',
+									 ['id' => 1]);
+
+		$album = $this->fixture('Class_Album',
+														['id' => 99,
+														 'titre' => 'Plein de medias',
+														 'visible' => 1,
+														 'status' => Class_Album::STATUS_VALIDATED])
+			->beDiaporama()
+			->setNoticeId(500)
+			->setIdOrigine("A888")
+			->setCote('50')
+			->setDateMaj('2012-02-17 10:00:00')
+			->setDescription('<p>pour passer la soirée</p>')
+			->setNotes(['305$a' => 'XXe siècle',
+									'200$b' => 'Parchemin',
+									'316$a' => 'Reliure restaurée en 1980 par la BN.'])
+			->setIdLang('lat')
+
+			->setRessources([Class_AlbumRessource::newInstanceWithId(2)
+											 ->setFichier('mimi_jolie.mp3')
+											 ->setTitre('Emilie jolie')
+											 ->setOrdre(1)
+											 ->setPoster('mimi_jolie.png'),
+
+											 Class_AlbumRessource::newInstanceWithId(4)
+											 ->setFichier('dark_night.mp4')
+											 ->setTitre('Batman Dark Knight')
+											 ->setPoster('batman.jpg')
+											 ->setOrdre(2)
+											 ->setDuration('00:02:30')
+											 ->setDescription('Une nouvelle aventure du justicier noir'),
+
+											 Class_AlbumRessource::newInstanceWithId(5)
+											 ->setUrl('http://progressive.totaleclips.com.edgesuite.net/107/e107950_227.mp4')
+											 ->setTitre('Hunger Games')
+											 ->setOrdre(3)
+											 ->setPoster('hunger.jpg'),
+
+											 Class_AlbumRessource::newInstanceWithId(6)
+											 ->setFichier('Monsieur l\'escargot.mp3')
+											 ->setTitre('Monsieur l\'escargot')
+											 ->setOrdre(4)
+											 ->setPoster('l\'escargot.jpg')]);
+
+		$album->index();
+
+		$notice = $album->getNotice();
+
+		$this->_html = $this->_helper->Notice_Entete($notice, ['entete' => Class_Codification::CHAMPS]);
+	}
+
+
+	public function tearDown() {
+		Storm_Model_Loader::defaultToDb();
+		parent::tearDown();
+	}
+
+
+	/** @test */
+	public function notesShouldContainsRestoredByBNF() {
+		$this->assertXPathContentContains($this->_html, '//dl//dd', utf8_encode('<div>XXe siècle</div><div>Reliure restaurée en 1980 par la BN.</div>'), $this->_html);
+	}
+
+
+	/** @test */
+	public function resumeShouldCOntainsForTheEvening() {
+		$this->assertXPathContentContains($this->_html, '//dl//dd', utf8_encode('<p>pour passer la soirée</p>'), $this->_html);
+	}
+}
\ No newline at end of file