diff --git a/VERSIONS_WIP/dev_#15527 b/VERSIONS_WIP/dev_#15527
new file mode 100644
index 0000000000000000000000000000000000000000..bcee4593623643de058d4f05e8cbd66a9ecbb9b1
--- /dev/null
+++ b/VERSIONS_WIP/dev_#15527
@@ -0,0 +1,3 @@
+- ticket: #15527
+  - localisation dans la bibliothèque:
+    - ajout du critère "genre"
\ No newline at end of file
diff --git a/application/modules/admin/controllers/BibController.php b/application/modules/admin/controllers/BibController.php
index 1f9f36ea69ef4a5c9866bb8012d6dfcf77b8201a..86a374df58c232cb04e45a944be9f2201b08950a 100644
--- a/application/modules/admin/controllers/BibController.php
+++ b/application/modules/admin/controllers/BibController.php
@@ -16,7 +16,7 @@
  *
  * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
  * along with AFI-OPAC 2.0; 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_BibController extends Zend_Controller_Action {
@@ -27,7 +27,7 @@ class Admin_BibController extends Zend_Controller_Action {
 		// filters are initialized in DefineUrls plugin
 		$this->id_zone = $_SESSION['admin']['filtre_localisation']['id_zone'];
 		$this->id_bib = $_SESSION['admin']['filtre_localisation']['id_bib'];
-		
+
 		$this->view->id_zone = $this->id_zone;
 		$this->view->id_bib = $this->id_bib;
 	}
@@ -51,13 +51,13 @@ class Admin_BibController extends Zend_Controller_Action {
 		$this->view->bib_array = Class_Bib::findAllByIdZone($this->id_zone);
 	}
 
-	
+
 	public function addAction() {
 		$this->view->titre = $this->view->_('Ajouter une bibliothèque');
- 
+
 		if ($this->_request->isPost()) {
 			$filter = new Zend_Filter_StripTags();
- 
+
 			$libelle = trim($filter->filter($this->_request->getPost('libelle')));
 			$responsable = trim($filter->filter($this->_request->getPost('responsable')));
 			$adresse = trim($filter->filter($this->_request->getPost('adresse')));
@@ -77,7 +77,7 @@ class Admin_BibController extends Zend_Controller_Action {
 			$url = trim($filter->filter($this->_request->getPost('url')));
 			$horaire = trim($filter->filter($this->_request->getPost('horaire')));
 			$photo = trim($filter->filter($this->_request->getPost('photo')));
- 
+
 			$data = ['ID_SITE' => '',
 							 'LIBELLE' => $libelle,
 							 'RESPONSABLE' => $responsable,
@@ -100,7 +100,7 @@ class Admin_BibController extends Zend_Controller_Action {
 							 'HORAIRE' => $horaire,
 							 'GOOGLE_MAP' => '',
 							 'INTERDIRE_RESA' => $this->_request->getPost('interdire_resa')];
- 
+
 			$bibClass = new Class_Bib();
 			$errorMessage = $bibClass->addBib($data);
 			if ($errorMessage == '') {
@@ -142,7 +142,7 @@ class Admin_BibController extends Zend_Controller_Action {
 		} else {
 			$this->view->ID_ZONE = $this->id_zone;
 			$adresse_img = getcwd()."/userfiles/photobib/photoBib0.jpg";
-			if(file_exists($adresse_img)) 
+			if(file_exists($adresse_img))
 				unlink($adresse_img);
 		}
 
@@ -150,7 +150,7 @@ class Admin_BibController extends Zend_Controller_Action {
 		$this->view->combo_zone=$cls_zone->getComboZone($zone);
 		$this->view->action = 'add';
 	}
- 
+
 
 	public function editAction() {
 		$user = ZendAfi_Auth::getInstance()->getIdentity();
@@ -164,7 +164,7 @@ class Admin_BibController extends Zend_Controller_Action {
 			$this->_request->getPost('id_bib') :
 			$this->_request->getParam('id', 0);
 
-		if ($user->ROLE_LEVEL == ZendAfi_Acl_AdminControllerRoles::ADMIN_BIB 
+		if ($user->ROLE_LEVEL == ZendAfi_Acl_AdminControllerRoles::ADMIN_BIB
 				and $user->ID_SITE != $id) {
 			$this->_redirect('admin/index');
 			return;
@@ -174,7 +174,7 @@ class Admin_BibController extends Zend_Controller_Action {
 		$bibClass = new Class_Bib();
 		if ($this->_request->isPost()) {
 			$filter = new Zend_Filter_StripTags();
-			
+
 			$libelle = trim($filter->filter($this->_request->getPost('libelle')));
 			$responsable = trim($filter->filter($this->_request->getPost('responsable')));
 			$adresse = trim($filter->filter($this->_request->getPost('adresse')));
@@ -192,9 +192,9 @@ class Admin_BibController extends Zend_Controller_Action {
 			$annexe = trim(urlencode($this->_request->getPost('annexe')));
 			$statut = trim($filter->filter($this->_request->getPost('statut')));
 			$url = trim($filter->filter($this->_request->getPost('url')));
-			$horaire = trim(urlencode($this->_request->getPost('horaire')));			
+			$horaire = trim(urlencode($this->_request->getPost('horaire')));
 			$photo = trim($filter->filter($this->_request->getPost('photo')));
-			
+
 			if ($id !== false ) {
 				$data = ['ID_SITE' => $id,
 								 'LIBELLE' => $libelle,
@@ -217,14 +217,14 @@ class Admin_BibController extends Zend_Controller_Action {
 								 'PHOTO' => $photo,
 								 'HORAIRE' => $horaire,
 								 'INTERDIRE_RESA' => $this->_request->getPost('interdire_resa')];
-				
+
 				$errorMessage = $bibClass->editBib($data, $id);
-				
+
 				$redirect = 'admin';
 				$user = ZendAfi_Auth::getInstance()->getIdentity();
-				if ($user->ROLE_LEVEL > ZendAfi_Acl_AdminControllerRoles::MODO_PORTAIL) 
+				if ($user->ROLE_LEVEL > ZendAfi_Acl_AdminControllerRoles::MODO_PORTAIL)
 					$redirect .= "/bib?z=" . $this->id_zone;
-				
+
 				if ($errorMessage == '') {
 					$this->_redirect($redirect);
 					return;
@@ -258,7 +258,7 @@ class Admin_BibController extends Zend_Controller_Action {
 
 	public function deleteAction() {
 		$bib = Class_Bib::find((int)$this->_request->getParam('id'));
-		$this->view->titre = $this->view->_('Supprimer la bibliothèque: %s', $bib->getLibelle()); 
+		$this->view->titre = $this->view->_('Supprimer la bibliothèque: %s', $bib->getLibelle());
 		$this->view->bib = $bib;
 	}
 
@@ -269,12 +269,12 @@ class Admin_BibController extends Zend_Controller_Action {
 		$this->_helper->notify('La bibliothèque "'.$bib->getLibelle().'" a été supprimée');
 		$this->_redirect('admin/bib/index');
 	}
- 
+
 
 	public function photoAction()	{
 		$viewRenderer = $this->getHelper('ViewRenderer');
 		$viewRenderer->setNoRender();
-		
+
 		// Parametres et adresse du fichier
 		$id_bib = (int)$this->_request->getParam('id');
 		$img = "/userfiles/photobib/photoBib".$id_bib.".jpg";
@@ -283,13 +283,13 @@ class Admin_BibController extends Zend_Controller_Action {
 																 'action'=>'getimage',
 																 'id'=>$id_bib]);
 		$adresse_img = getcwd().$img;
-		if (!file_exists($adresse_img)) 
-			$url_img = BASE_URL."/userfiles/photobib/photoVide.jpg"; 
+		if (!file_exists($adresse_img))
+			$url_img = BASE_URL."/userfiles/photobib/photoVide.jpg";
 
 		$html = '<body style="background-color:#f0f0f0;overflow:hidden">';
 		$html .= '<link rel="stylesheet" type="text/css" media="screen" href="'.URL_ADMIN_CSS.'global.css" />';
 		$html .= '<div>';
-		
+
 
 		if ($_FILES["photo"]) {
 			$fic = $_FILES["photo"];
@@ -311,7 +311,7 @@ class Admin_BibController extends Zend_Controller_Action {
 				} elseif($taille > 100 ) {
 						$erreur = $this->view->_("La photo que vous avez sélectionnée est trop volumiseuse : %d ko", $taille);
 				} else {
-					if(move_uploaded_file($fic['tmp_name'], $adresse_img)) { 
+					if(move_uploaded_file($fic['tmp_name'], $adresse_img)) {
 						$html .= "<script>document.location.replace('".BASE_URL."/admin/bib/photo?id=".$id_bib."&upload=1')</script>";
 					} else {
 						$erreur = $this->view->_("Erreur au transfert du fichier vers userfiles");
@@ -332,12 +332,12 @@ class Admin_BibController extends Zend_Controller_Action {
 			$html .= '<form name="form" action="'.BASE_URL.'/admin/bib/photo?id='.$id_bib.'" enctype="multipart/form-data" method="post">';
 			$html .= '<table><tr>';
 			$html .= '<td width="190px"><img src="'.$url_img.'" width="180px" height="140px"></td>';
-			$html .= '<td style=padding-left:10px"><span style="font-size:12px">'.$this->view->_('NB : l\'image doit être de type ".jpg", avoir une taille inférieure à 100 ko et des dimensions se rapprochant de 180 / 140 pixels').'</span><br/><br/>'; 
+			$html .= '<td style=padding-left:10px"><span style="font-size:12px">'.$this->view->_('NB : l\'image doit être de type ".jpg", avoir une taille inférieure à 100 ko et des dimensions se rapprochant de 180 / 140 pixels').'</span><br/><br/>';
 			$html .= '<center><input type="file" name="photo" size="40" enctype="multipart/form-data">';
 			$html .= '<br/><br/><input type="submit" class="bouton" value="'.$this->view->_('Envoyer la photo sur le serveur').'"></td>';
 			$html .= '</tr></table></form>';
 		}
-		
+
 		$html .= '</div>';
 		$html .= '<script>document.body.setAttribute("bgColor ","#f0f0f0"))</script>';
 
@@ -345,7 +345,7 @@ class Admin_BibController extends Zend_Controller_Action {
 		$this->getResponse()->setHeader('pragma', 'no-cache');
 		$this->getResponse()->setBody($html);
 	}
-	
+
 
 	public function getimageAction() {
 		$id_bib = (int)$this->_request->getParam('id');
@@ -353,11 +353,11 @@ class Admin_BibController extends Zend_Controller_Action {
 		$adresse_img=getcwd().$img;
 		if (!file_exists($adresse_img))
 			$adresse_img = getcwd()."/userfiles/photobib/photoVide.jpg";
-		
+
 		$handle = fopen($adresse_img,"rb");
 		$data = fread($handle, filesize($adresse_img));
 		fclose($handle);
-		
+
 		header("Content-type: image/jpg");
 		header("pragma: no-cache");
 		print($data);
@@ -369,73 +369,108 @@ class Admin_BibController extends Zend_Controller_Action {
 		$cls_loc = new Class_Localisation();
 		$id_bib = (int)$this->_request->getParam('id_bib');
 		$this->view->id_bib = $id_bib;
-		$this->view->nom_bib = fetchOne("select LIBELLE from bib_c_site where ID_SITE=$id_bib");
-		$this->view->localisations = $cls_loc->getLocalisations($id_bib);
-		$this->view->titre = $this->view->_("Localisations de la bibliothèque: %s", 
+		if (!$bib=Class_Bib::find($id_bib))
+			return $this->_redirect('admin/bib/index');
+		$this->view->nom_bib = $bib->getLibelle();
+		$this->view->localisations = $bib->getLocalisations();
+		$this->view->titre = $this->view->_("Localisations de la bibliothèque: %s",
 																				$this->view->nom_bib);
 	}
 
-	
-	public function localisationsmajAction() {
-		$cls_loc = new Class_Localisation();
-		$id_localisation=(int)$this->_request->getParam('id_localisation');
-		$id_bib = (int)$this->_request->getParam('id_bib');
-
-		if ($this->_request->isPost()) 	{
-			$data = ZendAfi_Filters_Post::filterStatic($this->_request->getPost());
-			if(!$data["LIBELLE"])
+	protected function _checkPost($localisation) {
+		$this->view->localisation = $localisation;
+		if (!$this->_request->isPost())
+			return false;
+		$erreurs=[];
+		$data = $this->_request->getPost();
+		if ($data)
+			$localisation->updateAttributes($data);
+		if(!$this->_getParam("libelle"))
 				$erreurs[] = $this->view->_("le libellé est obligatoire.");
 
-			if($erreurs) {
-				$this->view->erreurs=$erreurs;
-				$id_localisation=0;
-				$enreg=$data;
-			} else {
-				$data["ID_BIB"]=$id_bib;
-				if(!$data["ANIMATION"]) 
-					$data["ANIMATION"]="etoile.gif";
-				Class_AdminVar::set("animation", $data["ANIMATION"]);
-				$cls_loc->ecrireLocalisation($id_localisation,$data);
-				$this->_redirect('admin/bib/localisations?id_bib='.$id_bib);
-				return;
-			}
+		if($erreurs) {
+			$this->view->erreurs=$erreurs;
+			$id_localisation=0;
+			return false;
+		}
+		$id_bib=$this->_getParam("id_bib");
+		$localisation->setIdBib($id_bib);
+		Class_AdminVar::set("animation", $localisation->getAnimation());
+		if (!$localisation->save())
+			return false;
+
+		$this->_redirect('admin/bib/localisations/id_bib/'.$id_bib);
+		return true;
+	}
 
-		} else {
-			if($this->_request->getParam('creation')==1) {
-				$id_localisation=0;
-				$enreg["LIBELLE"]=$this->view->_("** nouvelle localisation **");
-				$enreg["ANIMATION"]=getVar("animation");
-			} else {
-				$id_localisation = (int)$this->_request->getParam('id_localisation');
-				$enreg=$cls_loc->getLocalisations($id_bib,$id_localisation);
-			}
+	public function addlocalisationAction() {
+		if (!$bib = $this->getBib())
+			return $this->_redirect('admin/bib');
+
+		$localisation = new Class_Localisation();
+		$localisation->setLibelle($this->view->_("** nouvelle localisation **"));
+		if ($default_animation = Class_AdminVar::get("animation"))
+			$localisation->setAnimation($default_animation);
+
+		if ($this->_checkPost($localisation))
+			return $this->_redirect('admin/bib/plans/id_bib/'.$bib->getId());
+
+		$this->view->titre = $this->view->_("Nouvelle localisation");
+		$this->view->localisation = $localisation;
+		$this->view->plans=$this->getTablePlans($bib);
+		$this->view->id_bib=$bib->getId();
+		$this->view->nom_bib=$bib->getLibelle();
+
+	}
+
+
+	protected function getTablePlans($bib) {
+		// Plans
+		$table_plans[0]="aucun";
+
+		if ($plans = $bib->getPlans()) {
+			foreach($plans as $plan)
+				$table_plans[$plan->getId()] = $plan->getLibelle();
 		}
-		
+		return $table_plans;
+
+	}
+
+	public function localisationsmajAction() {
+
+		if ((!$bib = $this->getBib())
+				|| (!$localisation = $this->getLocalisation()))
+ 			return $this->_redirect('admin/bib');
+
+			$this->_checkPost($localisation);
+
+
 		// Plans
 		$table_plans[0]="aucun";
-		$plans=$cls_loc->getPlans($id_bib);
-		if ($plans) {
-			foreach($plans as $plan) 
-				$table_plans[$plan["ID_PLAN"]] = $plan["LIBELLE"];
+
+		if ($plans = $bib->getPlans()) {
+			foreach($plans as $plan)
+				$table_plans[$plan->getId()] = $plan->getLibelle();
 		}
 
 		// Variables de vue
-		if(!$enreg["ANIMATION"]) 
-			$enreg["ANIMATION"]="etoile.gif";
+
+		$this->view->localisation = $localisation;
 		$this->view->plans=$table_plans;
-		$this->view->id_bib=$id_bib;
-		$this->view->nom_bib=fetchOne("select LIBELLE from bib_c_site where ID_SITE=$id_bib");
-		$this->view->id_localisation=$id_localisation;
-		$this->view->localisation=$enreg;
+		$this->view->id_bib=$bib->getId();
+		$this->view->nom_bib=$bib->getLibelle();
+		$this->view->id_localisation=$localisation->getId();;
 		$this->view->titre = $this->view->_("Mise à jour de la localisation");
 	}
 
 
 	public function localisationsdeleteAction() {
-		$cls_loc = new Class_Localisation();
-		$id_localisation=(int)$this->_request->getParam('id_localisation');
 		$id_bib = (int)$this->_request->getParam('id_bib');
-		$cls_loc->deleteLocalisation($id_localisation);
+		$id_localisation=(int)$this->_request->getParam('id_localisation');
+		if (!$id_localisation)
+			return $this->_redirect('admin/bib/localisations?id_bib='.$id_bib);
+		$cls_loc = Class_Localisation::find($id_localisation);
+		$cls_loc->delete();
 		$this->_redirect('admin/bib/localisations?id_bib='.$id_bib);
 	}
 
@@ -444,83 +479,119 @@ class Admin_BibController extends Zend_Controller_Action {
 		$viewRenderer = $this->getHelper('ViewRenderer');
 		$viewRenderer->setNoRender();
 
-		$cls_loc = new Class_Localisation();
-		$id_plan = $this->_request->getParam('id_plan');
-		$image = $cls_loc->getImagePlan($id_plan);
+		if (!$plan=$this->getPlan()) {
+			print('ERROR - No plan specified');
+			return;
+		}
+
+
+		$image = $plan->getImagePath();
 		if (!$image) {
-			print('ERREUR');
-			exit;
+			print('ERRORR - No image found');
+			return;
 		}
 
-		print('<a id="ref_plan" href="'.$image["url"].'" rel="lightbox" title="">'
-					. '<img id="img_plan" src="'.$image["url"].'">'
+		print('<a id="ref_plan" href="'.$image.'" rel="lightbox" title="">'
+					. '<img id="img_plan" src="'.$image.'">'
 					. '</a>');
-		exit;
+		return;
 	}
-	
+
 
 	public function plansAction() {
 		$cls_loc = new Class_Localisation();
 		$id_bib = (int)$this->_request->getParam('id_bib');
+		if (!$bib= Class_Bib::find($id_bib))
+			return $this->_redirect('admin/');
+
 		$this->view->id_bib = $id_bib;
-		$this->view->nom_bib = fetchOne("select LIBELLE from bib_c_site where ID_SITE=$id_bib");
-		$this->view->plans = $cls_loc->getPlans($id_bib);
+		$this->view->nom_bib = $bib->getLibelle();
+		$this->view->plans = $bib->getPlans();
 		$this->view->titre = $this->view->_('Plans de la bibliothèque: %s', $this->view->nom_bib);
 	}
 
 
+	public function addplanAction() {
+		if (!$bib = $this->getBib())
+			return;
+		$this->view->_('Ajouter un plan de la bibliothèque: %s', $bib->getLibelle());
+		$plan = new Class_Plan();
+		$plan->setLibelle($this->view->_("** nouveau plan **"));
+		$plan->setBib($bib);
+		if ($this->_request->isPost()) {
+			$plan->updateAttributes($this->_request->getPost());
+			if ($this->checkForm()) {
+				$plan->save();
+				return $this->_redirect('admin/bib/plans/id_bib/'.$bib->getId());
+			}
+		}
+
+		$this->view->id_bib = $bib->getId();
+		$this->view->plan = $plan;
+
+	}
+
+
+	protected function getBib() {
+		$id_bib = (int)$this->_getParam('id_bib',0);
+		return  Class_Bib::find($id_bib);
+	}
+
+
+	protected function getPlan() {
+		$id_plan=(int)$this->_getParam('id_plan',0);
+		return Class_Plan::find($id_plan);
+	}
+
+
+	protected function getLocalisation() {
+		$id_location=(int)$this->_getParam('id_localisation',0);
+		return Class_Localisation::find($id_location);
+	}
+
+	protected function checkForm() {
+		$this->view->erreurs=[];
+		if(!$this->_getParam("libelle"))
+			$this->view->erreurs[] = $this->view->_("le libellé est obligatoire.");
+		if(!$this->_getParam("image"))
+			$this->view->erreurs[]=$this->view->_("L'image du plan est obligatoire.");
+
+		return (!$this->view->erreurs);
+
+	}
+
 	public function plansmajAction() {
 		$cls_loc = new Class_Localisation();
-		$id_plan=(int)$this->_request->getParam('id_plan');
-		$id_bib = (int)$this->_request->getParam('id_bib');
+		if ((!$bib = $this->getBib())
+				|| (!$plan = $this->getPlan()))
+ 			return $this->_redirect('admin/bib');
+
 
 		if ($this->_request->isPost()) {
-			$data = ZendAfi_Filters_Post::filterStatic($this->_request->getPost());
-			if(!$data["LIBELLE"])
-				$erreurs[] = $this->view->_("le libellé est obligatoire.");
-			if(!$data["IMAGE"]) 
-				$erreurs[]=$this->view->_("L'image du plan est obligatoire.");
+			$plan->updateAttributes($this->_request->getPost());
+			if ($this->checkForm()) {
 
-			if($erreurs) {
-				$this->view->erreurs=$erreurs;
-				$id_plan=0;
-				$enreg=$data;
-			} else {
-				$data["ID_BIB"]=$id_bib;
-				$cls_loc->ecrirePlan($id_plan,$data);
-				$this->_redirect('admin/bib/plans?id_bib='.$id_bib);
+				$plan->save();
+				return $this->_redirect('admin/bib/plans/id_bib/'.$bib->getId());
 			}
+		}
 
-		} else {
-			$add_action = ($this->_request->getParam('creation')==1);
-			if($add_action)	{
-				$id_plan=0;
-				$enreg["LIBELLE"]=$this->view->_("** nouveau plan **");
-
-			} else	{
-				$id_plan = (int)$this->_request->getParam('id_plan');
-				$enreg=$cls_loc->getPlans($id_bib,$id_plan);
-			}
 
-		}
+		$this->view->_('Modifier un plan de la bibliothèque: %s', $bib->getLibelle());
 
-		$nom_bib=fetchOne("select LIBELLE from bib_c_site where ID_SITE=$id_bib");
-		$this->view->titre = ($add_action) ?
-			$this->view->_('Ajouter un plan de la bibliothèque: %s', $nom_bib) :
-			$this->view->_('Modifier un plan de la bibliothèque: %s', $nom_bib);
-		
-		$this->view->id_bib = $id_bib;
-		$this->view->id_plan = $id_plan;
-		$this->view->plan = $enreg;
+		$this->view->id_bib = $bib->getId();
+		$this->view->id_plan = $plan->getId();
+		$this->view->plan = $plan;
 	}
- 
+
 
 	public function plansdeleteAction() {
-		$cls_loc = new Class_Localisation();
-		$id_plan = (int)$this->_request->getParam('id_plan');
-		$id_bib = (int)$this->_request->getParam('id_bib');
-		$cls_loc->deletePlan($id_plan);
-		$this->_redirect('admin/bib/plans?id_bib=' . $id_bib);
+		if (!$bib = $this->getBib())
+			return $this->_redirect('admin/bib/');
+		if (!$plan =  $this->getPlan())
+			return $this->_redirect('admin/bib/plans/id_bib/' . $bib->getId());
+		$plan->delete();
+		$this->_redirect('admin/bib/plans/id_bib/' . $bib->getId());
 	}
 
 
@@ -529,8 +600,8 @@ class Admin_BibController extends Zend_Controller_Action {
 		$include_items = ! (bool)$this->_getParam('categories_only', false);
 		$id_bib = (int)$this->_getParam('id_bib', 0);
 
-		$bibs = ($id_bib) ? 
-			[Class_Bib::find($id_bib)] : 
+		$bibs = ($id_bib) ?
+			[Class_Bib::find($id_bib)] :
 			Class_Bib::findAllByWithPortail(['order' => 'libelle']);
 
 		$jsons = [];
@@ -557,7 +628,7 @@ class Admin_BibController extends Zend_Controller_Action {
 
 		$class_bib = new Class_Bib();
 		$cats_by_bib = $class_bib->buildBibTree($id_bib, $type, $do_load_items);
-		
+
 		$jsons = [];
 		foreach($cats_by_bib as $bib)
 			$jsons[] = $bib->toJSON();
diff --git a/application/modules/admin/views/scripts/bib/addlocalisation.phtml b/application/modules/admin/views/scripts/bib/addlocalisation.phtml
new file mode 100644
index 0000000000000000000000000000000000000000..7bb4f0d4608227610431c7af1118da13c43e7a13
--- /dev/null
+++ b/application/modules/admin/views/scripts/bib/addlocalisation.phtml
@@ -0,0 +1 @@
+<?php echo $this->render('bib/localisationsmaj.phtml'); ?>
diff --git a/application/modules/admin/views/scripts/bib/addplan.phtml b/application/modules/admin/views/scripts/bib/addplan.phtml
new file mode 100644
index 0000000000000000000000000000000000000000..00a94eb0a2f894dad2920a432d2c4112fa83e4cc
--- /dev/null
+++ b/application/modules/admin/views/scripts/bib/addplan.phtml
@@ -0,0 +1 @@
+<?php echo $this->render('bib/plansmaj.phtml'); ?>
diff --git a/application/modules/admin/views/scripts/bib/localisations.phtml b/application/modules/admin/views/scripts/bib/localisations.phtml
index 4494eb5ae4c6254491b0c5fd201c4f830dddbcc3..624c07cb27aabf3ba02544db92eb2efa82e9ce64 100644
--- a/application/modules/admin/views/scripts/bib/localisations.phtml
+++ b/application/modules/admin/views/scripts/bib/localisations.phtml
@@ -3,7 +3,7 @@
 <script type="text/javascript" src="<?php echo URL_ADMIN_JS?>slimbox/autoload_image_simple.js"> </script>
 
 <?php
-echo ('<center><div align="center"><br>'.$this->bouton('id=c_19','picto=add.gif','texte='.$this->traduire('Ajouter une localisation').'','url='.BASE_URL.'/admin/bib/localisationsmaj?id_bib='.$this->id_bib.'&creation=1','largeur=230px').'</div></center>');  ?>
+echo ('<center><div align="center"><br>'.$this->bouton('id=c_19','picto=add.gif','texte='.$this->traduire('Ajouter une localisation').'','url='.BASE_URL.'/admin/bib/addlocalisation/id_bib/'.$this->id_bib,'largeur=230px').'</div></center>');  ?>
 <br />
 
 <?php
@@ -21,27 +21,44 @@ if($this->localisations)
 		<td colspan="6"  class="separ"> </td>
 	</tr>
 	<?php
+	$ligne = 0;
 	foreach ($this->localisations as $localisation)
 	{
-		if($localisation["IMAGE"]) $image=BASE_URL.'/userfiles/photobib/localisations/'.$localisation["IMAGE"]; else $image="";
-		$ico_del = '<a href="'.BASE_URL.'/admin/bib/localisationsdelete/id_localisation/'.$localisation["ID_LOCALISATION"].'?id_bib='.$this->id_bib.'">'.$this->boutonIco("type=del").'</a>';
+		$ico_del = $this->tagAnchor(['controller' => 'bib',
+																 'action' => 'localisationsdelete',
+																 'id_localisation' => $localisation->getId(),
+																 'id_bib' => $this->id_bib],
+																$this->boutonIco("type=del")
+																);
 		$ligne ++ ; if ($ligne & 1) $class="first"; else $class="second";
 		echo '<tr class="'.$class.'">
-			<td>'.$localisation["LIBELLE"]. '</td>
-			<td>'.$localisation["DESCRIPTION"].'</td>
+			<td>'.$localisation->getLibelle(). '</td>
+			<td>'.$localisation->getDescription().'</td>
 			<td>';
-			if($image)
+			if($localisation->getImage())
 			{
+			$img_url=BASE_URL.'/userfiles/photobib/localisations/'.$localisation->getImage().'?'.time();
+
 				//Le time c'est pour contourner le cache du navigateur: scr toujours différent
-				echo'
-				<a href="'.$image.'" rel="lightbox" title="'.$localisation["LIBELLE"].'">
-				<img src="'.$image.'?'.time().'" width="100" border="0">
-				</a>';
-			}
+			echo $this->tagImg($img_url,
+ 										[ 'title' => $localisation->getLibelle(),
+											'rel' => 'lightbox',
+											'width' => 100,
+											'border' => 0 ]);
+
+		}
+
 			else echo "&nbsp;";
+		$ico_edit = $this->tagAnchor(['controller' => 'bib',
+																	'action' => 'localisationsmaj',
+																	'id_localisation' => $localisation->getId(),
+																	'id_bib' => $this->id_bib],
+																 $this->boutonIco("type=edit")
+																);
+
 			echo'
 			</td>
-			<td align="center"><a href="'.BASE_URL.'/admin/bib/localisationsmaj/id_localisation/'.$localisation["ID_LOCALISATION"].'?id_bib='.$this->id_bib.'?id_bib='.$this->id_bib.'">'.$this->boutonIco("type=edit").'</a></td>
+			<td align="center">'.$ico_edit.'</td>
 			<td align="center">'.$ico_del.'</td>
 		</tr>';
 	}
@@ -54,4 +71,3 @@ if($this->localisations)
 }
 else echo '<p class="error" align="center">Il n\'y a aucune localisation associée à cette bibliothèque.</p>';
 ?>
-
diff --git a/application/modules/admin/views/scripts/bib/localisationsmaj.phtml b/application/modules/admin/views/scripts/bib/localisationsmaj.phtml
index 126e7222de6a9e9a2b5401d9bc18a33f46d863ae..20d5df14f5521f4f1a90b4bd96c85f9fd471d8e2 100644
--- a/application/modules/admin/views/scripts/bib/localisationsmaj.phtml
+++ b/application/modules/admin/views/scripts/bib/localisationsmaj.phtml
@@ -20,7 +20,7 @@
 				$('#POS_X').attr('value',ui.position.left-container.left);
 			}
 		})
-		$('#ID_PLAN').change(function()
+		$('#id_plan').change(function()
 		{
 			$('#POS_X').attr('value','0');
 			$('#POS_Y').attr('value','0');
@@ -29,13 +29,13 @@
 
 
 	// Init function de fin du load ajax
-	jQuery(function($) 
+	jQuery(function($)
 	{
 		$('#plan').ajaxStop(function()
 		{
 			$('#patience').css('display','none');
 			if($(this).html()=="ERREUR") {alert("Impossible de trouver l'image de ce plan."); return;}
-			$('#ref_plan').attr('title',$('#LIBELLE').val());
+			$('#ref_plan').attr('title',$('#libelle').val());
 			jQuery(function($) {
 				$("a[rel^='lightbox']").slimbox({onClose:function(){$('#point_localisation').css('display','none')}},null,null);
 			});
@@ -44,7 +44,7 @@
 			imageLoaded();
 		});
 	});
-	
+
 	// Verif si le slimbox est affiché
 	function imageLoaded()
 	{
@@ -65,7 +65,7 @@
 	// Affichage du plan
 	function afficherPlan()
 	{
-		var id_plan=$("#ID_PLAN").val();
+		var id_plan=$("#id_plan").val();
 		if(id_plan=="0") {alert("Sélectionnez le plan a associer à cette localisation."); return; }
 		$('#patience').css('display','block');
 		$('#plan').load('<?php echo BASE_URL ?>/admin/bib/ajaximageplan/id_plan/'+id_plan);
@@ -79,7 +79,7 @@
 
 <center>
 <div class="form" align="center" >
-	<form name="form" action="<?php print(BASE_URL.'/admin/bib/localisationsmaj/id_localisation/'.$this->id_localisation.'?id_bib='.$this->id_bib) ?>" method="post">
+	<form name="form" action="<?php echo $this->url() ?>" method="post">
 
 		<fieldset>
 			<legend><?php echo $this->traduire('Localisation'); ?> </legend>
@@ -94,20 +94,21 @@
 			<table border="0" cellpadding="5" cellspacing="0">
 				<tr>
 					<td class="droite" style="width:150px;">Libellé</td>
-					<td class="gauche"><input type="text" id="LIBELLE" name="LIBELLE"style="width:100%" value="<?php echo $this->escape(trim($this->localisation["LIBELLE"]));?>" maxlength="100"/></td>
+					<td class="gauche"><input type="text" id="libelle" name="libelle" style="width:100%" value="<?php echo $this->escape(trim($this->localisation->getLibelle()));?>" maxlength="100"/></td>
 				</tr>
 
 				<tr>
 					<td class="droite" valign="top"><?php echo $this->traduire('Description'); ?></td>
-					<td class="gauche"><TEXTAREA name="DESCRIPTION" rows="4" cols="42"><?php echo $this->escape(trim($this->localisation["DESCRIPTION"]));?></TEXTAREA></td>
+					<td class="gauche"><TEXTAREA name="description" rows="4" cols="42"><?php echo $this->escape(trim($this->localisation->getDescription()));?></TEXTAREA></td>
 				</tr>
 
 				<tr>
 					<td class="droite"><?php echo $this->traduire('Plan associé'); ?></td>
 					<td class="gauche">
-						<input type="hidden" name="POS_X" id="POS_X" value="<?php echo $this->localisation["POS_X"] ?>">
-						<input type="hidden" name="POS_Y" id="POS_Y" value="<?php echo $this->localisation["POS_Y"] ?>">
-						<?php echo $this->formSelect("ID_PLAN", $this->localisation["ID_PLAN"],"",$this->plans) ?>&nbsp;&nbsp;
+						<input type="hidden" name="POS_X" id="POS_X" value="<?php echo $this->localisation->getPosX() ?>">
+						<input type="hidden" name="POS_Y" id="POS_Y" value="<?php echo $this->localisation->getPosY() ?>">
+
+						<?php echo $this->formSelect("id_plan", $this->localisation->getPlan() ? $this->localisation->getPlan()->getId(): 0,"",$this->plans) ?>&nbsp;&nbsp;
 						<a href="#" onclick="afficherPlan()">&raquo;&nbsp;Placer sur le plan</a>
 					</td>
 				</tr>
@@ -121,7 +122,7 @@
 				<tr>
 					<td class="droite"><?php echo $this->traduire('Animation'); ?></td>
 					<td class="gauche">
-						<?php echo $this->ChoixPictogramme("plan_animation","ANIMATION",0,$this->localisation["ANIMATION"]); ?>
+						<?php echo $this->ChoixPictogramme("plan_animation","ANIMATION",0,$this->localisation->getAnimation()); ?>
 					</td>
 				</tr>
 
@@ -134,32 +135,37 @@
 
 				<tr>
 					<td class="droite" valign="top"><?php echo $this->traduire('Types de documents'); ?></td>
-					<td class="gauche"><?php echo $this->TagListeCoches("type_doc","TYPE_DOC",$this->localisation["TYPE_DOC"]); ?></td>
+					<td class="gauche"><?php echo $this->TagListeCoches("type_doc","TYPE_DOC",$this->localisation->getTypeDoc()); ?></td>
 				</tr>
-				
+
 				<tr>
 					<td class="droite" valign="top"><?php echo $this->traduire('Annexe'); ?></td>
-					<td class="gauche"><?php echo $this->TagListeCoches("annexe","ANNEXE",$this->localisation["ANNEXE"],$this->id_bib); ?></td>
+					<td class="gauche"><?php echo $this->TagListeCoches("annexe","ANNEXE",$this->localisation->getAnnexe()); ?></td>
 				</tr>
 
 				<tr>
 					<td class="droite" valign="top"><?php echo $this->traduire('Sections'); ?></td>
-					<td class="gauche"><?php echo $this->TagListeCoches("section","SECTION",$this->localisation["SECTION"]); ?></td>
+					<td class="gauche"><?php echo $this->TagListeCoches("section","SECTION",$this->localisation->getSection()); ?></td>
 				</tr>
-
 				<tr>
 					<td class="droite" valign="top"><?php echo $this->traduire('Emplacements'); ?></td>
-					<td class="gauche"><?php echo $this->TagListeCoches("emplacement","EMPLACEMENT",$this->localisation["EMPLACEMENT"]); ?></td>
+					<td class="gauche"><?php echo $this->TagListeCoches("emplacement","EMPLACEMENT",$this->localisation->getEmplacement()); ?></td>
 				</tr>
 
+				<tr>
+					<td class="droite" valign="top"><?php echo $this->traduire('Genres'); ?></td>
+					<td class="gauche"><?php echo $this->TagListeCoches("genre","GENRE",$this->localisation->getGenre()); ?></td>
+				</tr>
+
+
 				<tr>
 					<td class="droite" valign="top"><?php echo $this->traduire('Cotes - depuis'); ?></td>
-					<td class="gauche"><input type="text" name="COTE_DEBUT" size="10" value="<?php echo $this->localisation["COTE_DEBUT"];?>" maxlength="10"/></td>
+					<td class="gauche"><input type="text" name="COTE_DEBUT" size="10" value="<?php echo $this->localisation->getCoteDebut();?>" maxlength="10"/></td>
 				</tr>
 
 				<tr>
 					<td class="droite" valign="top"><?php echo $this->traduire('jusqu\'à'); ?></td>
-					<td class="gauche"><input type="text" name="COTE_FIN" size="10" value="<?php echo $this->localisation["COTE_FIN"];?>" maxlength="10"/></td>
+					<td class="gauche"><input type="text" name="COTE_FIN" size="10" value="<?php echo $this->localisation->getCoteFin();?>" maxlength="10"/></td>
 				</tr>
 
 			</table>
@@ -169,7 +175,7 @@
 			<legend><?php echo $this->traduire('Photo'); ?></legend>
 			<table>
 				<tr>
-					<td class="droite"><?php echo $this->tagUpload("IMAGE","localisation_bib",$this->localisation["IMAGE"]) ?></td>
+					<td class="droite"><?php echo $this->tagUpload("IMAGE","localisation_bib",$this->localisation->getImage()) ?></td>
 				</tr>
 			</table>
 		</fieldset>
@@ -177,9 +183,9 @@
 		<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/bib/localisations?id_bib='.$this->id_bib,'largeur=120px'); ?></td>
+				<td align="left" style="padding-left:5px;"> <?php echo $this->bouton('id=29','picto=del.gif','texte=Annuler','url='.BASE_URL.'/admin/bib/localisations/id_bib/'.$this->id_bib,'largeur=120px'); ?></td>
 			</tr>
 		</table>
 	</form>
 </div>
-</center>
\ No newline at end of file
+</center>
diff --git a/application/modules/admin/views/scripts/bib/plans.phtml b/application/modules/admin/views/scripts/bib/plans.phtml
index 01023e79223a28b8c3a2f147e5785785f0f41508..782d6816e6fcd2c1152b5641bab2454beac0f96f 100644
--- a/application/modules/admin/views/scripts/bib/plans.phtml
+++ b/application/modules/admin/views/scripts/bib/plans.phtml
@@ -3,7 +3,7 @@
 <script type="text/javascript" src="<?php echo URL_ADMIN_JS?>slimbox/autoload_image_simple.js"> </script>
 
 <?php
-echo ('<center><div align="center"><br>'.$this->bouton('id=c_19','picto=add.gif','texte='.$this->traduire('Ajouter un plan').'','url='.BASE_URL.'/admin/bib/plansmaj?id_bib='.$this->id_bib.'&creation=1','largeur=170px').'</div></center>');  ?>
+echo ('<center><div align="center"><br>'.$this->bouton('id=c_19','picto=add.gif','texte='.$this->traduire('Ajouter un plan').'','url='.BASE_URL.'/admin/bib/addplan/id_bib/'.$this->id_bib,'largeur=170px').'</div></center>');  ?>
 <br />
 
 <?php
@@ -21,22 +21,23 @@ if($this->plans)
 		<td colspan="6"  class="separ"> </td>
 	</tr>
 	<?php
+	$ligne = 0;
 	foreach ($this->plans as $plan)
 	{
-		$image=BASE_URL.'/userfiles/photobib/plans/'.$plan["IMAGE"];
-		$test=fetchOne("select count(*) from bib_localisations where ID_PLAN=".$plan["ID_PLAN"]);
-		if($test == 0) $ico_del = '<a href="'.BASE_URL.'/admin/bib/plansdelete/id_plan/'.$plan["ID_PLAN"].'?id_bib='.$this->id_bib.'">'.$this->boutonIco("type=del").'</a>';
+		$image=BASE_URL.'/userfiles/photobib/plans/'.$plan->getImage();
+		$test=fetchOne("select count(*) from bib_localisations where ID_PLAN=".$plan->getId());
+		if($test == 0) $ico_del = '<a href="'.BASE_URL.'/admin/bib/plansdelete/id_plan/'.$plan->getId().'?id_bib='.$this->id_bib.'">'.$this->boutonIco("type=del").'</a>';
 		else $ico_del ='<a href="#" onclick="alert(\'Ce plan a encore des localisations associées. \'); return false;"><img src="'.URL_ADMIN_IMG.'ico/del.gif" class="ico" alt="Supprimer" title="Supprimer"/></a>';
 		$ligne ++ ; if ($ligne & 1) $class="first"; else $class="second";
 		echo('<tr class="'.$class.'">
-			<td>'.$plan["LIBELLE"]. '</td>
-			<td>'.$plan["DESCRIPTION"].'</td>
+			<td>'.$plan->getLibelle(). '</td>
+			<td>'.$plan->getDescription().'</td>
 			<td>
-				<a href="'.$image.'" rel="lightbox" title="'.$plan["LIBELLE"].'">
+				<a href="'.$image.'" rel="lightbox" title="'.$plan->getLibelle().'">
 				<img src="'.$image.'" width="100" border="0">
 				</a>
 			</td>
-			<td align="center"><a href="'.BASE_URL.'/admin/bib/plansmaj/id_plan/'.$plan["ID_PLAN"].'?id_bib='.$this->id_bib.'?id_bib='.$this->id_bib.'">'.$this->boutonIco("type=edit").'</a></td>
+			<td align="center"><a href="'.BASE_URL.'/admin/bib/plansmaj/id_plan/'.$plan->getId().'/id_bib/'.$this->id_bib.'">'.$this->boutonIco("type=edit").'</a></td>
 			<td align="center">'.$ico_del.'</td>
 		</tr>');
 	}
@@ -49,4 +50,3 @@ if($this->plans)
 }
 else echo '<p class="error" align="center">Il n\'y a aucun plan associé à cette bibliothèque.</p>';
 ?>
-
diff --git a/application/modules/admin/views/scripts/bib/plansmaj.phtml b/application/modules/admin/views/scripts/bib/plansmaj.phtml
index ca8a735b68f4bfaecba1bb4902eb1421e5690683..bc13131c50f9726b05e414bd3641f94733007c03 100644
--- a/application/modules/admin/views/scripts/bib/plansmaj.phtml
+++ b/application/modules/admin/views/scripts/bib/plansmaj.phtml
@@ -1,6 +1,6 @@
 <center>
 <div class="form" align="center" >
-	<form name="form" action="<?php print(BASE_URL.'/admin/bib/plansmaj/id_plan/'.$this->id_plan.'?id_bib='.$this->id_bib) ?>" method="post">
+	<form name="form" action="<?php echo $this->url() ?>" method="post">
 
 		<fieldset>
 			<legend><?php echo $this->traduire('Plan'); ?> </legend>
@@ -15,11 +15,11 @@
 			<table border="0" cellpadding="5" cellspacing="0">
 				<tr>
 					<td class="droite" style="width:150px;">Libellé</td>
-					<td class="gauche"><input type="text" name="LIBELLE"style="width:100%" value="<?php echo $this->escape(trim($this->plan["LIBELLE"]));?>" maxlength="100"/></td>
+					<td class="gauche"><input type="text" name="libelle"style="width:100%" value="<?php echo $this->escape(trim($this->plan->getLibelle()));?>" maxlength="100"/></td>
 				</tr>
 				<tr>
 					<td class="droite" valign="top"><?php echo $this->traduire('Description'); ?></td>
-					<td class="gauche"><TEXTAREA name="DESCRIPTION" rows="4" cols="42"><?php echo $this->escape(trim($this->plan["DESCRIPTION"]));?></TEXTAREA></td>
+					<td class="gauche"><TEXTAREA name="description" rows="4" cols="42"><?php echo $this->escape(trim($this->plan->getDescription()));?></TEXTAREA></td>
 				</tr>
 				</table>
 		</fieldset>
@@ -28,7 +28,7 @@
 				<legend><?php echo $this->traduire('Image'); ?></legend>
 				<table>
 					<tr>
-						<td class="droite"><?php echo $this->tagUpload("IMAGE","plan_bib",$this->plan["IMAGE"]) ?></td>
+						<td class="droite"><?php echo $this->tagUpload("image","plan_bib",$this->plan->getImage()) ?></td>
 					</tr>
 				</table>
 			</fieldset>
diff --git a/application/modules/opac/controllers/NoticeajaxController.php b/application/modules/opac/controllers/NoticeajaxController.php
index 58400410752c71c6d9102981e01dd55f60e29689..f6a27ac515adfade9bbde16a40570225b4d3f025 100644
--- a/application/modules/opac/controllers/NoticeajaxController.php
+++ b/application/modules/opac/controllers/NoticeajaxController.php
@@ -158,7 +158,9 @@ class NoticeAjaxController extends Zend_Controller_Action {
 
 		// Recup des donnees
 		$cls_loc=new Class_Localisation();
-		$data=$cls_loc->getLocFromExemplaire($id_bib,$cote,$code_barres);
+		$data = [];
+		if ($bib=Class_Bib::find($id_bib))
+			$data=$cls_loc->getLocFromExemplaire($bib,$cote,$code_barres);
 
 		// Retour
 		$ret =json_encode($data);
diff --git a/application/modules/opac/controllers/UploadController.php b/application/modules/opac/controllers/UploadController.php
index 46161290a8da3905c120f2ddc876b20de7d6390d..5f18c9a8043637a48dfdcf8f1570eeb222911b3b 100644
--- a/application/modules/opac/controllers/UploadController.php
+++ b/application/modules/opac/controllers/UploadController.php
@@ -16,7 +16,7 @@
  *
  * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
  * along with AFI-OPAC 2.0; 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 UploadController extends Zend_Controller_Action
 {
@@ -35,13 +35,13 @@ class UploadController extends Zend_Controller_Action
 		$this->view->input_name=$this->_getParam("input_name");
 
 		// Message sur l'image
-		$msg = $this->view->_("*NB : l'image doit être de type \"%s\", avoir une taille inférieure à %s ko", 
-													urldecode($this->_getParam("extensions")), 
+		$msg = $this->view->_("*NB : l'image doit être de type \"%s\", avoir une taille inférieure à %s ko",
+													urldecode($this->_getParam("extensions")),
 													$this->_getParam("poids"));
 
-		if ($this->_getParam("largeur_conseil")) 
-			$msg.= $this->view->_(" et des dimensions se rapprochant de %s x %s pixels", 
-														$this->_getParam("largeur_conseil"), 
+		if ($this->_getParam("largeur_conseil"))
+			$msg.= $this->view->_(" et des dimensions se rapprochant de %s x %s pixels",
+														$this->_getParam("largeur_conseil"),
 														$this->_getParam("hauteur_conseil"));
 		$msg.=".";
 		$this->view->conseil=$msg;
@@ -51,12 +51,12 @@ class UploadController extends Zend_Controller_Action
 	//---------------------------------------------------------------------
 	function formAction()
 	{
-		$path = "/userfiles/".$this->_getParam("path").'/'.urldecode($this->_getParam("filename"));
+		$path = "/userfiles/".urldecode($this->_getParam("path")).'/'.urldecode($this->_getParam("filename"));
 
 		// Controle image
 		$adresse_img=getcwd().$path;
 
-		if($this->_getParam("filename") and file_exists($adresse_img)) 
+		if($this->_getParam("filename") and file_exists($adresse_img))
 			$this->view->image=BASE_URL.$path;
 		else $this->view->image = URL_ADMIN_IMG."blank.gif";
 		$this->view->filename=$this->_getParam("filename");
@@ -71,6 +71,7 @@ class UploadController extends Zend_Controller_Action
 	function uploadAction()
 	{
 		$fic = $_FILES["photo"];
+		$erreur='';
 		if($fic["error"] > 0)
 		{
 			if(!$fic["name"]) $erreur=$this->view->_("Vous devez sélectionner une image en cliquant sur le bouton : parcourir");
@@ -84,9 +85,9 @@ class UploadController extends Zend_Controller_Action
 			$ext=".".strtolower($ext);
 
 			$taille=(int)($fic["size"]/1024);
-			if(strpos($this->_getParam("extensions"),$ext) === false) 
+			if(strpos($this->_getParam("extensions"),$ext) === false)
 				$erreur=$this->view->_("L'image que vous avez sélectionnée doit être de type : '$s' et pas de type : %s", $this->_getParam("extensions"), $ext);
-			elseif($taille > $this->_getParam("poids") ) 
+			elseif($taille > $this->_getParam("poids") )
 				$erreur=$this->view->_("L'image que vous avez sélectionnée est trop volumiseuse. Taille maximum : %d ko", $this->_getParam("poids"));
 			else	{
 				$path_img = "/userfiles/".urldecode($this->_getParam("path")).'/'.$fic["name"];
@@ -94,13 +95,13 @@ class UploadController extends Zend_Controller_Action
 				$adresse_img=getcwd().$path_img;
 
 				if(move_uploaded_file($fic['tmp_name'],$adresse_img))
-				{ 
+				{
 					$this->view->filename=$fic["name"];
 					$this->view->image=BASE_URL.$path_img;
 					$viewRenderer = $this->getHelper('ViewRenderer');
 					$viewRenderer->renderScript('upload/form.phtml');
 				}
-				else 
+				else
 					$erreur=$this->view->_("Erreur au transfert du fichier vers userfiles");
 			}
 		}
@@ -130,7 +131,7 @@ class UploadController extends Zend_Controller_Action
 		// parametres
 		$type=$this->_getParam("type");
 		$id_dossier=$this->_getParam("id_dossier");
-		
+
 		// classe de traitemnt de l'image
 		switch($type)
 		{
@@ -138,7 +139,7 @@ class UploadController extends Zend_Controller_Action
 				$cls=new Class_Album(); break;
 			default : $ret=array("succes"=>false,"erreur"=>"type incorrect");
 		}
-		
+
 		// traiter l'enregistement et l'image
 		if($cls)
 		{
diff --git a/cosmogramme/php/_init.php b/cosmogramme/php/_init.php
index 4ebce3f17dc19ad12155924a2c5ea9efc11da7ba..bbe91bda598ff32cf4456915654ba984ef583df6 100644
--- a/cosmogramme/php/_init.php
+++ b/cosmogramme/php/_init.php
@@ -1,8 +1,8 @@
 <?php
 // Constantes
 error_reporting(E_ERROR | E_PARSE);
-define("VERSION_COSMOGRAMME","6.57");
-define("PATCH_LEVEL","219");
+define("VERSION_COSMOGRAMME","6.58");
+define("PATCH_LEVEL","221");
 
 define("APPLI","cosmogramme");
 define("COSMOPATH", "/var/www/html/vhosts/opac2/www/htdocs");
diff --git a/cosmogramme/sql/patch/patch_221.sql b/cosmogramme/sql/patch/patch_221.sql
new file mode 100644
index 0000000000000000000000000000000000000000..d2a20fc3249725716c5822e75ed8b31c15678801
--- /dev/null
+++ b/cosmogramme/sql/patch/patch_221.sql
@@ -0,0 +1 @@
+ALTER TABLE `bib_localisations` ADD `GENRE` VARCHAR( 10 ) NOT NULL AFTER `EMPLACEMENT` ;
diff --git a/library/Class/Bib.php b/library/Class/Bib.php
index e8f64e21dfe28c617a736a47c7b366fd9af6bc6c..3d8cd261e096aee4b432a21aa822ad6dad6dc329 100644
--- a/library/Class/Bib.php
+++ b/library/Class/Bib.php
@@ -143,7 +143,13 @@ class Class_Bib extends Storm_Model_Abstract {
 
 													'exemplaires' => ['model' => 'Class_Exemplaire',
 																						'role' => 'bib',
-																						'dependents' => 'delete']  ];
+																						'dependents' => 'delete'],
+													'localisations' => ['model' => 'Class_Localisation',
+																							 'role' => 'bib',
+																							 'order' => 'libelle'],
+													'plans' => ['model' => 'Class_Plan',
+																			'role' => 'bib',
+																			'order' => 'libelle']];
 
 	protected $_belongs_to = ['zone' => ['model' => 'Class_Zone',
 																			 'role' => 'bib',
@@ -560,6 +566,7 @@ class Class_Bib extends Storm_Model_Abstract {
 	// Modifier une bibliotheque
 	public function editBib($data, $id_bib)
 	{
+		$errorMessage = $this->verifData($data);
 		if ($errorMessage == '')
 		{
 			try
diff --git a/library/Class/Localisation.php b/library/Class/Localisation.php
index 4bd8c6f6e044242ee591dfbc54f071c1a4175ee6..b50984e1492a04b1d33839d30ea32bcaab120287 100644
--- a/library/Class/Localisation.php
+++ b/library/Class/Localisation.php
@@ -16,155 +16,226 @@
  *
  * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
  * along with AFI-OPAC 2.0; 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 : Plans et localisations des bibliotheques
-//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-class Class_Localisation
-{
+class LocalisationLoader extends Storm_Model_Loader {
 
-	// ----------------------------------------------------------------
-	// Localisations
-	// ----------------------------------------------------------------
-	public function getLocalisations($id_bib,$id_localisation=0)
-	{
-		if(!$id_localisation) $ret=fetchAll("select * from bib_localisations where ID_BIB=$id_bib order by LIBELLE");
-		else $ret=fetchEnreg("select * from bib_localisations where ID_LOCALISATION=$id_localisation");
-		return $ret;
+	public function findAvailableLocalisation($localisations, $exemplaire) {
+		$available_localisations = [];
+		foreach($localisations as $loc) {
+			if($localisation_with_quality = $loc->isForExemplaire($exemplaire)) {
+				$available_localisations[array_keys($localisation_with_quality)[0]] = array_shift($localisation_with_quality);
+			}
+		}
+
+		if(!array_filter($available_localisations))
+			 return '';
+
+		krsort($available_localisations);
+		return array_shift($available_localisations);
 	}
+}
+
+
+
+class Class_Localisation extends Storm_Model_Abstract {
+	use Trait_Translator;
+	use Trait_StaticFileSystem;
+
+
+  protected $_table_name = 'bib_localisations';
+  protected $_table_primary = 'id_localisation';
+  protected $_loader_class = 'LocalisationLoader';
+
+	protected $_default_attribute_values = ['libelle' => '',
+																					'animation' => 'etoile.gif',
+																					'description' => '',
+																					'type_doc' => '',
+																					'annexe' => '',
+																					'section' => '',
+																					'emplacement' => '',
+																					'genre' => '',
+																					'cote_debut' => '',
+																					'cote_fin' => '',
+																					'image' => '',
+																					'pos_x' => 0,
+																					'pos_y' => 0];
+
+	protected $_belongs_to = ['plan' => ['model' => 'Class_Plan',
+																			 'referenced_in' => 'id_plan'],
+														'bib' => ['model' => 'Class_Bib',
+																				'referenced_in' => 'id_bib']];
+
 
 	// ----------------------------------------------------------------
 	// Ecrire localisation
 	// ----------------------------------------------------------------
-	public function ecrireLocalisation($id_localisation,$enreg)
+	public function afterSave()
 	{
-		if(!$id_localisation) $id_localisation=sqlInsert("bib_localisations",$enreg);
-		else sqlUpdate("update bib_localisations set @SET@ where ID_LOCALISATION=$id_localisation",$enreg);
+		parent::afterSave();
 
 		// Renommer l'image s'il y a lieu
-		if(!$enreg["IMAGE"]) return true;
-		$extension=explode(".",$enreg["IMAGE"]);
-		$extension=$extension[count($extension)-1];
-		$image="bib_".$enreg["ID_BIB"]."_localisation_".$id_localisation.".".$extension;
-		if($image == $enreg["IMAGE"]) return true;
-		$root=getcwd()."/userfiles/photobib/localisations/";
-		rename($root.$enreg["IMAGE"], $root.$image);
-		sqlExecute("update bib_localisations set IMAGE='$image' where ID_LOCALISATION=$id_localisation");
+		if($image=$this->getImage()) {
+			$extension=explode(".",$image);
+			$extension=$extension[count($extension)-1];
+			$new_image="bib_".$this->getBib()->getId()."_localisation_".$this->getId().".".$extension;
+			if ($image == $new_image)
+				return true;
+			$root=$this->getImageLocalisationsPath();
+			self::getFileSystem()->rename($root.$this->getImage(), $root.$new_image);
+			$this->setImage($new_image);
+			Class_Localisation::getLoader()->save($this);
+		}
+
 	}
 
 	// ----------------------------------------------------------------
 	// Supprimer localisations
 	// ----------------------------------------------------------------
-	public function deleteLocalisation($id_localisation)
+	public function beforeDelete()
 	{
+		parent::beforeDelete();
 		// Supprimer l'image
-		$image=fetchOne("select IMAGE from bib_localisations where ID_LOCALISATION=$id_localisation");
-		$image=getcwd()."/userfiles/photobib/localisations/".$image;
-		if(file_exists($image)) unlink($image);
-
-		// Supprimer l'enreg
-		sqlExecute("delete from bib_localisations where ID_LOCALISATION=$id_localisation");
+		$image=$this->getImage();
+		$image=$this->getImageLocalisationsPath().$image;
+		if(self::getFileSystem()->file_exists($image))
+			self::getFileSystem()->unlink($image);
 	}
 
+
+	protected function getImageLocalisationsPath()
+	{
+		return self::getFileSystem()->getcwd()."/userfiles/photobib/localisations/";
+	}
 	// ----------------------------------------------------------------
-	// Plans
+	// Rend les caracteristiques de l'image pour un plan
 	// ----------------------------------------------------------------
-	public function getPlans($id_bib,$id_plan=0)
+	public function getImagePlan()
 	{
-		if(!$id_plan) $ret=fetchAll("select * from bib_plans where ID_BIB=$id_bib order by LIBELLE");
-		else $ret=fetchEnreg("select * from bib_plans where ID_PLAN=$id_plan");
+		if (!$plan=$this->getPlan())
+			return [];
+
+		$image=$plan->getImage();
+		$img = "/userfiles/photobib/plans/".$image;
+    if ($image == "" or (self::getFileSystem()->file_exists(self::getFileSystem()->getcwd().$img)==false))
+			return false;
+
+		$ret=self::getFileSystem()->getimagesize(getcwd().$img);
+		$ret["url"]=BASE_URL.$img;
 		return $ret;
 	}
 
+
 	// ----------------------------------------------------------------
-	// Ecrire plan
+	// Rend les données de localisation pour 1 exemplaire
 	// ----------------------------------------------------------------
-	public function ecrirePlan($id_plan,$enreg)
-	{
-		if(!$id_plan) $id_plan=sqlInsert("bib_plans",$enreg);
-		else sqlUpdate("update bib_plans set @SET@ where ID_PLAN=$id_plan",$enreg);
+	public function getLocFromExemplaire($bib, $cote, $code_barres) {
 
-		// Renommer l'image s'il y a lieu
-		$extension=explode(".",$enreg["IMAGE"]);
-		$extension=$extension[count($extension)-1];
-		$image="bib_".$enreg["ID_BIB"]."_plan_".$id_plan.".".$extension;
-		if($image == $enreg["IMAGE"]) return true;
-		$root=getcwd()."/userfiles/photobib/plans/";
-		rename($root.$enreg["IMAGE"], $root.$image);
-		sqlExecute("update bib_plans set IMAGE='$image' where ID_PLAN=$id_plan");
+		if(!$localisations = $bib->getLocalisations())
+			return $this->localisationErrorAsArray();
+
+		$exemplaire = (!$code_barres)
+			? Class_Exemplaire::findFirstBy(['cote' => $cote,
+																			 'id_bib' => $bib->getId()])
+			: Class_Exemplaire::findFirstBy(['code_barres' => $code_barres,
+																			 'id_bib' => $bib->getId()]);
+
+		if(!$exemplaire)
+			return $this->localisationErrorAsArray();
+
+		$localisation = Class_Localisation::getLoader()->findAvailableLocalisation($localisations, $exemplaire);
+
+		if(!$localisation)
+			return $this->localisationErrorAsArray();
+
+		return $localisation->asArrayForJson();
 	}
 
-	// ----------------------------------------------------------------
-	// Supprimer plan
-	// ----------------------------------------------------------------
-	public function deletePlan($id_plan)
-	{
-		// Supprimer l'image
-		$image=fetchOne("select IMAGE from bib_plans where ID_PLAN=$id_plan");
-		$image=getcwd()."/userfiles/photobib/plans/".$image;
-		if(file_exists($image)) unlink($image);
 
-		// Supprimer l'enreg
-		sqlExecute("delete from bib_plans where ID_PLAN=$id_plan");
+	protected function localisationErrorAsArray() {
+		return ['erreur'=> $this->_('Aucune donnée de localisation trouvée pour cet exemplaire')];
 	}
 
-	// ----------------------------------------------------------------
-	// Rend les caracteristiques de l'image pour un plan
-	// ----------------------------------------------------------------
-	public function getImagePlan($id_plan)
-	{
-		$image=fetchOne("select IMAGE from bib_plans where ID_PLAN=$id_plan");
-		$img = "/userfiles/photobib/plans/".$image;
-    if ($image == "" or file_exists(getcwd().$img)==false) return false;
-		$ret=getimagesize(getcwd().$img);
-		$ret["url"]=BASE_URL.$img;
-		return $ret;
+
+	protected function getImageLocalisation() {
+		if(!$this->hasImage())
+			return '';
+
+		return USERFILESURL . 'photobib/localisations/' . $this->getImage();
 	}
 
-	// ----------------------------------------------------------------
-	// Rend les données de localisation pour 1 exemplaire
-	// ----------------------------------------------------------------
-	public function getLocFromExemplaire($id_bib,$cote,$code_barres)
-	{
-		$erreur_not_found = Zend_Registry::get('translate')->_("Aucune donnée de localisation trouvée pour cet exemplaire");
-
-		// Lire les localisations
-		$localisations=$this->getLocalisations($id_bib);
-		if(!$localisations) return array("erreur"=> $erreur_not_found);
-
-		// Lire les données de l'exemplaire
-		if($code_barres > '') $ex=fetchEnreg("select id_notice,cote,annexe,section,emplacement from exemplaires where code_barres='$code_barres' and id_bib=$id_bib");
-		else $ex=fetchEnreg("select id_notice,cote,annexe,section,emplacement from exemplaires where cote='$cote' and id_bib=$id_bib");
-		$ex["type_doc"]=fetchOne("select type_doc from notices where id_notice=".$ex["id_notice"]);
-
-		// Analyse des regles
-		foreach($localisations as $localisation)
-		{
-			if($localisation["TYPE_DOC"] and strpos(";".$localisation["TYPE_DOC"].";",";".$ex["type_doc"].";") === false) continue;
-			if($localisation["ANNEXE"] and strpos(";".$localisation["ANNEXE"].";",";".$ex["annexe"].";") === false) continue;
-			if($localisation["SECTION"] and strpos(";".$localisation["SECTION"].";",";".$ex["section"].";") === false) continue;
-			if($localisation["EMPLACEMENT"] and strpos(";".$localisation["EMPLACEMENT"].";",";".$ex["emplacement"].";") === false) continue;
-			if($localisation["COTE_DEBUT"] and substr($ex["cote"],0,strlen($localisation["COTE_DEBUT"])) < $localisation["COTE_DEBUT"]) continue;
-			if($localisation["COTE_FIN"] and substr($ex["cote"],0,strlen($localisation["COTE_FIN"])) > $localisation["COTE_FIN"]) continue;
-			$ok=true;
-			break;
+
+	protected function asArrayForJson() {
+
+		if (!$url=$this->getImagePlan()["url"])
+			$url ='';
+
+		return [
+						'url' =>  $url,
+						'posX' => $this->getPosX(),
+						'posY' => $this->getPosY(),
+						'description' => (trim($this->getDescription())
+															? $this->getDescription()
+															: $this->getLibelle()),
+						'libelle' => $this->getLibelle(),
+						'photo' => $this->getImageLocalisation($this->getId()),
+						'animation' => $this->getAnimationImage()];
+	}
+
+
+	protected function getAnimationImage() {
+		return URL_ADMIN_IMG . 	'animation_plan/' . ($this->hasAnimation()
+																								 ? $this->getAnimation()
+																								 : 'genie.gif');
+	}
+
+
+	public function isForExemplaire($exemplaire) {
+		if(! $location_with_quality = $this->findLocationWithParamsFor($exemplaire))
+			return $this->findLocalisationByCote($exemplaire);
+
+		return $location_with_quality;
+	}
+
+
+	protected function findLocationWithParamsFor($exemplaire) {
+		$exemplaire_datas = ['type_doc' => $exemplaire->getNotice()->getTypeDoc(),
+												 'genre' => $exemplaire->getGenre(),
+												 'annexe' => $exemplaire->getAnnexe(),
+												 'section' => $exemplaire->getSection(),
+												 'emplacement' => $exemplaire->getEmplacement()];
+
+		$matching_datas = ['type_doc' => $this->getTypeDoc(),
+											 'genre' => $this->getGenre(),
+											 'annexe' => $this->getAnnexe(),
+											 'section' => $this->getSection(),
+											 'emplacement' => $this->getEmplacement()];
+
+		if(!$matching_datas = array_filter($matching_datas)) {
+			return '';
 		}
-		// Lecture des infos
-		if(!$ok) return array("erreur"=>$erreur_not_found);
-		$image=$this->getImagePlan($localisation["ID_PLAN"]);
-		$ret["url"]=$image["url"];
-		$ret["posX"]=$localisation["POS_X"];
-		$ret["posY"]=$localisation["POS_Y"];
-		if(trim($localisation["DESCRIPTION"])) $ret["description"]=$localisation["DESCRIPTION"];
-		else $ret["description"]=$localisation["LIBELLE"];
-		$ret["titre"]=$localisation["LIBELLE"];
-		if($localisation["IMAGE"]) $localisation["IMAGE"]=BASE_URL."/userfiles/photobib/localisations/".$localisation["IMAGE"];
-		$ret["photo"]=$localisation["IMAGE"];
-		if(!$localisation["ANIMATION"]) $localisation["ANIMATION"]="genie.gif";
-		$ret["animation"]=URL_ADMIN_IMG.'animation_plan/'.$localisation["ANIMATION"];
-		return $ret;
+
+		$quality = count($matching_datas);
+
+		if(!array_filter(array_diff_assoc($matching_datas, $exemplaire_datas)))
+			return [$quality => $this];
+		return '';
+	}
+
+
+	protected function findLocalisationByCote($exemplaire) {
+		$start_cote_exemplaire = substr($exemplaire->getCote() ,0,strlen($this->getCoteDebut()));
+		$end_cote_exemplaire =substr($exemplaire->getCote() ,0,strlen($this->getCoteFin()));
+
+		if(!$this->hasCoteDebut() && !$this->hasCoteFin())
+			 return '';
+
+		if((!$this->hasCoteDebut() || ($this->hasCoteDebut() and $start_cote_exemplaire >= $this->getCoteDebut())) &&
+			 (!$this->hasCoteFin() || ($this->hasCoteFin() and $end_cote_exemplaire <= $this->getCoteFin())))
+			return ['1' => $this];
+
+		return '';
 	}
 }
 ?>
\ No newline at end of file
diff --git a/library/Class/Plan.php b/library/Class/Plan.php
new file mode 100644
index 0000000000000000000000000000000000000000..d033922ee2c81027f0cb2919e0b7f2f77780b393
--- /dev/null
+++ b/library/Class/Plan.php
@@ -0,0 +1,84 @@
+<?php
+/**
+ * Copyright (c) 2012-2014, Agence Française Informatique (AFI). All rights reserved.
+ *
+ * AFI-OPAC 2.0 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).
+ *
+ * AFI-OPAC 2.0 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 AFI-OPAC 2.0; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
+ */
+
+class PlanLoader extends Storm_Model_Loader {
+
+
+}
+
+class Class_Plan extends Storm_Model_Abstract {
+	use Trait_StaticFileSystem;
+  protected $_table_name = 'bib_plans';
+  protected $_table_primary = 'id_plan';
+	protected $_loader_class = 'PlanLoader';
+	protected $_belongs_to = ['bib' => ['model' => 'Class_Bib',
+																			 'referenced_in' => 'id_bib']];
+
+
+	protected $_default_attribute_values = ['libelle' =>'',
+																					'description' =>'',
+																					'image' => ''];
+	public function afterSave() {
+		parent::afterSave();
+		// Renommer l'image s'il y a lieu
+		$extension=explode(".",$this->getImage());
+		$extension=$extension[count($extension)-1];
+		$image="bib_".$this->getBibId()."_plan_".$this->getId().".".$extension;
+		if($image == $this->getImage()) return true;
+		$root = $this->getImageServerPath();
+
+		self::getFileSystem()->rename($root.$this->getImage(), $root.$image);
+		$this->setImage($image);
+		Class_Plan::getLoader()->save($this);
+	}
+
+
+	public function beforeDelete() {
+		parent::beforeDelete();
+		$image=$this->getImageServerPath().$this->getImage();
+		if(self::getFileSystem()->file_exists($image)) unlink($image);
+	}
+
+	protected function getImageServerPath() {
+		return getcwd()."/userfiles/photobib/plans/";
+	}
+
+
+	public function getImagePath() {
+		if(!$this->hasImage())
+			return '';
+
+		$img = "photobib/plans/".$this->getImage();
+
+		if(!self::getFileSystem()->file_exists( $this->getImageServerPath().$this->getImage()))
+			return '';
+
+		return USERFILESURL . $img;
+
+	}
+
+	public function getBibId() {
+		if ($bib = $this->getBib())
+			return $bib->getId();
+		return 0;
+	}
+}
+?>
\ No newline at end of file
diff --git a/library/Class/Testing/FileSystem.php b/library/Class/Testing/FileSystem.php
index 9953938096c977290df3f63a7b230a0374cf6a05..a1e10b950b59274e7fb382ddcb8919dd311086b9 100644
--- a/library/Class/Testing/FileSystem.php
+++ b/library/Class/Testing/FileSystem.php
@@ -16,17 +16,20 @@
  *
  * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
  * along with AFI-OPAC 2.0; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA 
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
  */
 
 class Class_Testing_FileSystem {
-	protected $_known_functions = [
-		'rmdir', 'unlink', 'fopen', 'fseek', 'fgets',
-		'filesize', 'fclose', 'ftell', 'fread', 'feof',
-		'getcwd', 'file_exists', 'scandir', 'is_dir',
-		'opendir', 'readdir', 'closedir', 'mkdir','glob','file', 'fwrite'];
+	protected $_known_functions =
+		[
+		 'rmdir', 'unlink', 'fopen', 'fseek', 'fgets',
+		 'filesize', 'fclose', 'ftell', 'fread', 'feof',
+		 'getcwd', 'file_exists', 'scandir', 'is_dir',
+		 'opendir', 'readdir', 'closedir', 'mkdir','glob','file', 'fwrite','rename',
+		 'getimagesize'
+		];
+
 
-	
 	public function __call($name, $args) {
 		if (!in_array($name, $this->_known_functions))
 			throw new RuntimeException('Call to unknown fileSystem method ' . $name);
diff --git a/library/ZendAfi/View/Helper/IframeContainer.php b/library/ZendAfi/View/Helper/IframeContainer.php
index aa0c93e0999371a048a7a0233df3225e174e7c68..c9fb293f3895214cf5f19398a61af12fe57ec667 100644
--- a/library/ZendAfi/View/Helper/IframeContainer.php
+++ b/library/ZendAfi/View/Helper/IframeContainer.php
@@ -16,7 +16,7 @@
  *
  * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
  * along with AFI-OPAC 2.0; 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 - Containeur Iframe pour objets flash et javascript
diff --git a/library/ZendAfi/View/Helper/TagUpload.php b/library/ZendAfi/View/Helper/TagUpload.php
index 584335dc8578b3c92db4fb2b7e18796e64c3a5b5..181447586e685ddb8549d5a4233c762bc621ff3a 100644
--- a/library/ZendAfi/View/Helper/TagUpload.php
+++ b/library/ZendAfi/View/Helper/TagUpload.php
@@ -16,7 +16,7 @@
  *
  * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
  * along with AFI-OPAC 2.0; 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 :	Tag pour upload d'images
diff --git a/tests/application/modules/admin/controllers/BibControllerTest.php b/tests/application/modules/admin/controllers/BibControllerTest.php
index 7d19ce781e7a14c353eb587f135f324fcdcf8d26..c1fe53091dc4f5a959b95244766cea92e7c4c5a8 100644
--- a/tests/application/modules/admin/controllers/BibControllerTest.php
+++ b/tests/application/modules/admin/controllers/BibControllerTest.php
@@ -16,15 +16,15 @@
  *
  * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
  * along with AFI-OPAC 2.0; 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 BibControllerTestCase extends AbstractControllerTestCase {
 	public function setUp() {
 		parent::setUp();
-
-		$this->bib_annecy = $this->fixture('Class_Bib', 
+		Class_TypeDoc::beVolatile();
+		$this->bib_annecy = $this->fixture('Class_Bib',
 																			 ['id' => 2,
 																				'libelle' => 'Annecy',
 																				'responsable' => 'Ludivine',
@@ -232,7 +232,7 @@ class BibControllerWithAdminBibEditAnnecyTest extends BibControllerWithAdminBibT
 
 	/** @test */
 	function nomResponsableShouldBeLudivine() {
-			$this->assertXPath('//input[@name="responsable"][@value="Ludivine"]');
+		$this->assertXPath('//input[@name="responsable"][@value="Ludivine"]');
 	}
 }
 
@@ -255,9 +255,9 @@ class BibControllerJSONTest extends BibControllerTestCase {
 												]}],
 				"items": []}]
 JSON;
-			$this->assertJsonStringEqualsJsonString($expectedJSON,
-																							$this->_response->getBody(),
-																							$this->_response->getBody());
+		$this->assertJsonStringEqualsJsonString($expectedJSON,
+																						$this->_response->getBody(),
+																						$this->_response->getBody());
 	}
 
 	/** @test */
@@ -291,8 +291,8 @@ JSON;
 												]}],
 				"items": []}]
 JSON;
-			$this->assertJsonStringEqualsJsonString($expectedJSON,
-																							$this->_response->getBody());
+		$this->assertJsonStringEqualsJsonString($expectedJSON,
+																						$this->_response->getBody());
 	}
 
 
@@ -321,8 +321,8 @@ JSON;
 												"items": []}],
 				"items": []}]
 JSON;
-			$this->assertJsonStringEqualsJsonString($expectedJSON,
-																							$this->_response->getBody());
+		$this->assertJsonStringEqualsJsonString($expectedJSON,
+																						$this->_response->getBody());
 	}
 }
 
@@ -349,7 +349,7 @@ abstract class BibControllerDeleteCranActionTestCase extends BibControllerTestCa
 		$this->fixture('Class_Profil', ['id' => 25, 'id_site' =>  3]);
 
 		$this->fixture('Class_SitothequeCategorie', ['id' => 23, 'id_site' => 3,  'libelle' => 'linux']);
-		$this->fixture('Class_Sitotheque', ['id' => 10, 'titre' => 'linux.fr', 'id_cat' =>  23, 'url' => 'http://www.linux.fr']);		
+		$this->fixture('Class_Sitotheque', ['id' => 10, 'titre' => 'linux.fr', 'id_cat' =>  23, 'url' => 'http://www.linux.fr']);
 	}
 }
 
@@ -504,4 +504,353 @@ class BibControllerForceDeleteCranActionTest extends BibControllerDeleteCranActi
 
 }
 
+
+class BibControllerLocalisationNewTest extends BibControllerTestCase {
+	public function setUp() {
+		parent::setUp();
+		$this->dispatch('admin/bib/addlocalisation/id_bib/2');
+	}
+
+
+	/** @test */
+	public function libelleShouldBeNouvelleLocalisation(){
+		$this->assertXPath('//input[@id="libelle"][@value="** nouvelle localisation **"]');
+	}
+
+
+}
+
+class BibControllerLocalisationNewPostTest extends BibControllerTestCase {
+	public function setUp() {
+		parent::setUp();
+		$file_system = Storm_Test_ObjectWrapper::mock()
+			->whenCalled('file_exists')
+//			->with(ROOT_PATH . '/userfiles/photobib/localisations/bib_2_localisation_9.jpg')
+			->answers(true)
+			->whenCalled('rename')
+			->answers(true)
+			->whenCalled('getcwd')
+			->answers('path');
+		Class_Localisation::beVolatile();
+		Class_Localisation::setFileSystem($file_system);
+
+		$this->postDispatch('admin/bib/addlocalisation/id_bib/2',
+												['libelle' => '5eme Etage',
+												 'description' => 'en haut',
+												 'id_plan' => 3,
+												 'image' => 'mezzanine.png']);
+	}
+
+
+	/** @test */
+	public function libelleShouldBeNouvelleLocalisation(){
+		$this->assertNotNull(Class_Localisation::findFirstBy(['libelle' => '5eme Etage']));
+	}
+
+	/** @test */
+	public function imageShouldExists(){
+		$localisation = Class_Localisation::findFirstBy(['libelle' => '5eme Etage']);
+		$this->assertEquals('bib_2_localisation_1.png',$localisation->getImage());
+	}
+
+
+}
+
+
+class BibControllerLocalisatonDeleteTest extends BibControllerTestCase {
+	public function setUp() {
+		parent::setUp();
+		$file_system = Storm_Test_ObjectWrapper::mock()
+			->whenCalled('file_exists')
+//			->with(ROOT_PATH . '/userfiles/photobib/localisations/bib_2_localisation_9.jpg')
+			->answers(true)
+			->whenCalled('unlink')
+			->answers(true)
+			->whenCalled('getcwd')
+			->answers('path');
+;
+
+		Class_Localisation::setFileSystem($file_system);
+		$location = $this->fixture('Class_Localisation',
+									 ['id' => 9,
+										'libelle' => 'Arts',
+										'description' => 'Coin des arts.',
+										'bib' => $this->bib_annecy,
+										'image' => 'bib_2_localisation_9.jpg']);
+
+
+
+		$this->dispatch('admin/bib/localisationsdelete/id_localisation/9/id_bib/2');
+
+	}
+
+  /** @test */
+	public function deleteShouldDeleteLocalisation() {
+		$this->assertNull(Class_Localisation::find(9));
+	}
+
+}
+
+
+class BibControllerPlanTest extends BibControllerTestCase {
+	public function setUp() {
+		parent::setUp();
+		$this->fixture('Class_Localisation',
+									 ['id' => 9,
+										'libelle' => 'Arts',
+										'description' => 'Coin des arts.',
+										'bib' => $this->bib_annecy,
+										'image' => 'bib_2_localisation_9.jpg']);
+		$file_system = Storm_Test_ObjectWrapper::mock()
+			->whenCalled('file_exists')
+			->with(ROOT_PATH . '/userfiles/photobib/plans/bib_3_plan_3.png')
+			->answers(true)
+			->whenCalled('rename')
+			->answers(true);
+
+
+		Class_Plan::setFileSystem($file_system);
+
+		$plan=$this->fixture('Class_Plan',
+												 ['id'=> 3,
+													'bib' => $this->bib_cran,
+													'libelle' => 'Mezzanine',
+													'description' => '',
+													'image' => 'mezzanine.png']);
+
+
+	}
+
+  /** @test */
+	public function errorShouldDisplayNoPlan() {
+		$this->dispatch('admin/bib/plans/id_bib/2');
+		$this->assertXPathContentContains('//p[@class="error"]',"Il n'y a aucun plan associé à cette bibliothèque.",$this->_response->getBody());
+	}
+
+
+  /** @test */
+	public function forCranShouldDisplayPlan() {
+		$this->dispatch('admin/bib/plans/id_bib/3');
+		$this->assertXPath('//img[contains(@src,"plans/bib_3_plan_3.png")]',$this->_response->getBody());
+	}
+
+}
+
+
+class BibControllerPlanMajTest extends BibControllerTestCase {
+	public function setUp() {
+		parent::setUp();
+		$this->fixture('Class_Localisation',
+									 ['id' => 9,
+										'libelle' => 'Arts',
+										'description' => 'Coin des arts.',
+										'bib' => $this->bib_annecy,
+										'image' => 'bib_2_localisation_9.jpg']);
+
+		$file_system = Storm_Test_ObjectWrapper::mock()
+			->whenCalled('file_exists')
+			->with(ROOT_PATH . '/userfiles/photobib/plans/bib_3_plan_3.png')
+			->answers(true)
+			->whenCalled('rename')
+			->answers(true);
+
+
+		Class_Plan::setFileSystem($file_system);
+
+		$plan=$this->fixture('Class_Plan',
+												 ['id'=> 3,
+													'bib' => $this->bib_cran,
+													'libelle' => 'Mezzanine',
+													'description' => '',
+													'image' => 'mezzanine.png']);
+
+
+
+	}
+
+  /** @test */
+	public function errorShouldRedirect() {
+		$this->dispatch('admin/bib/plansmaj/id_bib/2');
+		$this->assertRedirectTo('/admin/bib');
+	}
+
+
+  /** @test */
+	public function forCranShouldDisplayMezzanineImage() {
+		$this->dispatch('admin/bib/plans/id_bib/3');
+		$this->assertXPath('//img[contains(@src,"plans/bib_3_plan_3.png")]',$this->_response->getBody());
+	}
+
+}
+
+
+
+class BibControllerPostMajPlanTest extends BibControllerTestCase {
+	public function setUp() {
+		parent::setUp();
+		$this->fixture('Class_Localisation',
+									 ['id' => 9,
+										'libelle' => 'Arts',
+										'description' => 'Coin des arts.',
+										'bib' => $this->bib_annecy,
+										'image' => 'bib_2_localisation_9.jpg']);
+
+		$file_system = Storm_Test_ObjectWrapper::mock()
+			->whenCalled('file_exists')
+			->with(ROOT_PATH . '/userfiles/photobib/plans/bib_3_plan_3.png')
+			->answers(true)
+			->whenCalled('rename')
+			->answers(true);
+
+
+		Class_Plan::setFileSystem($file_system);
+
+		$plan=$this->fixture('Class_Plan',
+												 ['id'=> 3,
+													'bib' => $this->bib_cran,
+													'libelle' => 'Mezzanine',
+													'description' => '',
+													'image' => 'mezzanine.png']);
+
+		$this->postDispatch('admin/bib/plansmaj/id_bib/3/id_plan/3',
+												[
+												 'libelle' => 'Mezzanine',
+												 'description' =>'en haut',
+												 'image' => 'mezza.png']);
+
+
+	}
+
+  /** @test */
+	public function postDispatchShouldSave() {
+		$this->assertEquals('en haut',Class_Plan::find(3)->getDescription());
+
+	}
+
+
+  /** @test */
+	public function forCranShouldDisplayMezzanineImage() {
+		$this->assertEquals('bib_3_plan_3.png',Class_Plan::find(3)->getImage());
+	}
+
+}
+
+
+class BibControllerLocalisationMajTest extends BibControllerTestCase {
+	public function setUp() {
+		parent::setUp();
+
+		$this->fixture('Class_TypeDoc',
+									 ['id'=> 8,
+										'label'=> 'Articles']);
+
+		$plan=$this->fixture('Class_Plan',
+												 ['id'=> 3,
+													'id_bib' => 2,
+													'libelle' => 'Mezzanine',
+													'description' => '',
+													'image' => 'bib_2_plan_3.png']);
+
+		$plan2=$this->fixture('Class_Plan',
+													['id'=> 2,
+													 'id_bib' => 2,
+													 'libelle' => 'Niveau 1',
+													 'description' => '',
+													 'image' => 'bib_2_plan_2.png']);
+
+
+		$this->fixture('Class_Localisation',
+									 ['id' => 9,
+										'bib' => $this->bib_annecy,
+										'libelle' => 'Arts',
+										'description' => 'Coin des arts.',
+										'plan' =>$plan,
+										'image' => 'bib_2_localisation_9.jpg']);
+		$this->dispatch('admin/bib/localisationsmaj/id_localisation/9/id_bib/2');
+	}
+
+
+	/** @disable-test */
+	public function pageShouldBeHtml5Valid() {
+		$this->assertHtml5();
+	}
+
+
+	/** @test */
+	public function libelleShouldBeArts(){
+		$this->assertXPath('//input[@name="libelle"][@value="Arts"]');
+	}
+
+
+	/** @test */
+	public function descriptionShouldBeCoindesarts() {
+		$this->assertXPathContentContains('//textarea[@name="description"]','Coin des arts.');
+	}
+
+
+	/** @test */
+	public function planAssocieShouldBeMezzanine() {
+		$this->assertXPathContentContains('//option[@selected="selected"][@value="3"]','Mezzanine');
+	}
+
+
+  /** @test */
+	public function documentTypesShouldBeDisplayed() {
+		$this->assertTrue(0 < strpos($this->_response->getBody(), '<input type="checkbox" style="width: inherit;" value="1" clef="8" onclick="getCoches(\'TYPE_DOC\',true)">Articles<br />'));
+	}
+
+
+	/** @test */
+ 	public function annexeShouldBeDisplayed() {
+		$this->assertXPath('//input[@id="ANNEXE"]');
+	}
+
+
+	/** @test */
+	public function genreShouldBeDisplayed() {
+		$this->assertXPath('//input[@id="GENRE"]');
+	}
+
+
+	/** @test */
+	public function imagePlanShouldBeDisplayed() {
+		$this->assertXPath('//iframe[contains(@src,"filename=bib_2_localisation_9.jpg")]');
+	}
+
+}
+
+
+
+
+class BibControllerAjaxImagePlanTest extends BibControllerTestCase {
+	public function setUp() {
+		parent::setUp();
+		$file_system = Storm_Test_ObjectWrapper::mock()
+			->whenCalled('file_exists')
+			->with(ROOT_PATH . '/userfiles/photobib/plans/bib_3_plan_3.png')
+			->answers(true)
+			->whenCalled('rename')
+			->answers(true);
+
+
+		Class_Plan::setFileSystem($file_system);
+
+		$plan=$this->fixture('Class_Plan',
+												 ['id'=> 3,
+													'bib' => $this->bib_cran,
+													'libelle' => 'Mezzanine',
+													'description' => '',
+													'image' => 'mezzanine.png']);
+
+		$this->dispatch('/admin/bib/ajaximageplan/id_plan/3');
+
+	}
+
+
+	/** @test */
+	public function ajaxShouldReturnURLImage() {
+		$this->assertContains("photobib/plans/bib_3_plan_3.png",$this->_response->getBody());
+	}
+
+}
 ?>
\ No newline at end of file
diff --git a/tests/application/modules/opac/controllers/NoticeAjaxControllerTest.php b/tests/application/modules/opac/controllers/NoticeAjaxControllerTest.php
index 53dd4d9b9be17982ee62ab2c850c69ac9677b057..dce7fa6a3461a13fb6cf65d88983ca3a57c8b7aa 100644
--- a/tests/application/modules/opac/controllers/NoticeAjaxControllerTest.php
+++ b/tests/application/modules/opac/controllers/NoticeAjaxControllerTest.php
@@ -1373,4 +1373,265 @@ class NoticeAjaxControllerBiographieNonTrouveeTest extends NoticeAjaxControllerB
 	}
 }
 
+
+
+
+abstract class NoticeAjaxControllerLocalisationTestCase extends AbstractControllerTestCase {
+	protected $_json;
+
+
+	public function setUp() {
+		parent::setUp();
+
+		Class_Exemplaire::beVolatile();
+		$file_system = Storm_Test_ObjectWrapper::mock()
+			->whenCalled('file_exists')
+			->answers(true)
+			->whenCalled('getimagesize')
+			->answers(['480','360',2,'width="480" height="600"'])
+			->whenCalled('rename')
+			->answers(true)
+			->whenCalled('getcwd')
+			->answers('path');
+		Class_Localisation::beVolatile();
+		Class_Plan::beVolatile();
+		Class_Localisation::setFileSystem($file_system);
+		Class_Plan::setFileSystem($file_system);
+		$this->fixture('Class_Notice',
+									 ['id' => 1,
+										'titre' => 'An Error occurd',
+										'type_doc' => '1']);
+
+		$this->fixture('Class_Localisation',
+									 ['id' => '1',
+										'id_bib' => '1',
+										'libelle' => 'First Floor',
+										'id_plan' => 1,
+										'genre' => 'Doc']);
+
+		$this->fixture('Class_bib',
+									 ['id' => 1,
+									 ]);
+
+		$this->fixture('Class_Plan',
+									 ['id' => 1,
+										'image' => 'plan_bib_level_1.png']);
+
+
+	}
+
+}
+
+
+
+class NoticeAjaxControllerNoLocalisationTest extends NoticeAjaxControllerLocalisationTestCase {
+	public function setUp() {
+		parent::setUp();
+		$this->dispatch('noticeajax/localisation/id_bib/1', true);
+	}
+
+	/** @test */
+	public function errorMessageShouldBeAsExpected() {
+		$this->assertEquals('{"erreur":"Aucune donn\u00e9e de localisation trouv\u00e9e pour cet exemplaire"}', $this->_response->getBody());
+	}
+}
+
+
+
+class NoticeAjaxControllerNoLocaltionForExemplaireTest extends NoticeAjaxControllerLocalisationTestCase {
+	public function setUp() {
+		parent::setUp();
+		$this->fixture('Class_Exemplaire',
+									 ['id' => 1,
+										'id_bib' => 1,
+										'code_barres' => 123456,
+										'cote' => 123,
+										'genre' => '',
+										'id_notice' => '1',
+										'section' => '',
+										'emplacement' => '']);
+		$this->dispatch('noticeajax/localisation/id_bib/1/cote/123', true);
+	}
+
+
+	/** @test */
+	public function noLocalisationDataShouldBeReturn() {
+		$this->assertEquals('{"erreur":"Aucune donn\u00e9e de localisation trouv\u00e9e pour cet exemplaire"}', $this->_response->getBody());
+	}
+}
+
+
+
+
+class NoticeAjaxControllerWithLocalisationTest extends NoticeAjaxControllerLocalisationTestCase {
+	public function setUp() {
+		parent::setUp();
+
+		$this->fixture('Class_Exemplaire',
+									 ['id' => 1,
+										'id_bib' => 1,
+										'code_barres' => 123456,
+										'cote' => 123,
+										'genre' => 'Doc',
+										'id_notice' => '1',
+										'section' => '',
+										'emplacement' => '']);
+
+
+		$this->dispatch('noticeajax/localisation/id_bib/1/cote/123', true);
+		$this->_json = json_decode($this->_response->getBody());
+	}
+
+
+	/** @test */
+	public function urlShoudlBeAsExpected() {
+
+		$this->assertContains('/userfiles/photobib/plans/bib_0_plan_1.png', $this->_json->url);
+	}
+
+
+	/** @test */
+	public function locationTitleShouldBeFirstFloor() {
+		$this->assertEquals('First Floor', $this->_json->libelle);
+	}
+}
+
+
+
+
+class NoticeAjaxControllerWithMultipleSelectorLocalisationTest extends NoticeAjaxControllerLocalisationTestCase {
+	public function setUp() {
+		parent::setUp();
+
+		$this->fixture('Class_Exemplaire',
+									 ['id' => 5,
+										'id_bib' => 1,
+										'code_barres' => '',
+										'cote' => 123789,
+										'genre' => 'Doc',
+										'emplacement' => '7',
+										'id_notice' => 1,
+										'section' => '']);
+
+		$this->fixture('Class_Localisation',
+									 ['id' => 2,
+										'id_bib' => 1,
+										'libelle' => 'Second floor',
+										'id_plan' => '1',
+										'genre' => 'Doc',
+										'emplacement' => '7']);
+
+
+
+		$this->dispatch('noticeajax/localisation/id_bib/1/cote/123789', true);
+		$this->_json = json_decode($this->_response->getBody());
+	}
+
+
+	/** @test */
+	public function locationTitleShouldBeSecondFloor() {
+		$this->assertEquals('Second floor', $this->_json->libelle);
+	}
+}
+
+
+
+class NoticeAjaxControllerLocalisationWithCoteTest extends  NoticeAjaxControllerLocalisationTestCase {
+	public function setUp() {
+		parent::setUp();
+		$this->fixture('Class_Exemplaire',
+									 ['id' => 5,
+										'id_bib' => 1,
+										'code_barres' => '123456',
+										'cote' => '995 E',
+										'genre' => 'Doc',
+										'emplacement' => '7',
+										'id_notice' => 1,
+										'section' => '']);
+
+		Class_Localisation::find(1)
+			->setLibelle('Last floor')
+			->setGenre('')
+			->setCoteDebut('995 A')
+			->setCoteFin('999 Z')
+			->save();
+
+		$this->dispatch('noticeajax/localisation/id_bib/1/code_barres/123456', true);
+		$this->_json = json_decode($this->_response->getBody());
+	}
+
+
+	/** @test */
+	public function locationTitleWithStartCoteShouldBeLastFloor() {
+		$this->assertEquals('Last floor', $this->_json->libelle);
+	}
+}
+
+
+
+
+
+class NoticeAjaxControllerLocalisationWithStartedCoteTest extends  NoticeAjaxControllerLocalisationTestCase {
+	public function setUp() {
+		parent::setUp();
+		$this->fixture('Class_Exemplaire',
+									 ['id' => 5,
+										'id_bib' => 1,
+										'code_barres' => '123456',
+										'cote' => '995 E',
+										'genre' => 'Doc',
+										'emplacement' => '7',
+										'id_notice' => 1,
+										'section' => '']);
+
+		Class_Localisation::find(1)
+			->setLibelle('Last floor')
+			->setGenre('')
+			->setCoteDebut('995 A')
+			->setCoteFin('999 Z')
+			->save();
+
+		$this->dispatch('noticeajax/localisation/id_bib/1/code_barres/123456', true);
+		$this->_json = json_decode($this->_response->getBody());
+	}
+
+
+	/** @test */
+	public function locationTitleShouldBeLastFloor() {
+		$this->assertEquals('Last floor', $this->_json->libelle);
+	}
+}
+
+
+
+
+class NoticeAjaxControllerLocalisationWithEndCoteTest extends  NoticeAjaxControllerLocalisationTestCase {
+	public function setUp() {
+		parent::setUp();
+		$this->fixture('Class_Exemplaire',
+									 ['id' => 5,
+										'id_bib' => 1,
+										'code_barres' => '123456',
+										'cote' => '995 E',
+										'genre' => 'Doc',
+										'emplacement' => '7',
+										'id_notice' => 1,
+										'section' => '']);
+
+		Class_Localisation::find(1)
+			->setLibelle('Last floor')
+			->setGenre('')
+			->setCoteFin('999 Z')
+			->save();
+
+		$this->dispatch('noticeajax/localisation/id_bib/1/code_barres/123456', true);
+		$this->_json = json_decode($this->_response->getBody());
+	}
+
+
+	/** @test */
+	public function locationTitleWithEndCoteShouldBeLastFloor() {
+		$this->assertEquals('Last floor', $this->_json->libelle);
+	}
+}
 ?>
\ No newline at end of file