diff --git a/VERSIONS b/VERSIONS
index 4777d647872d6603ec2717c0105b6b7c4236e2e4..0a35dfca75ef48219dda9d8795179e08c1c7d4e6 100644
--- a/VERSIONS
+++ b/VERSIONS
@@ -1,3 +1,15 @@
+19/01/2015 - v6.59.3
+
+- ticket #16601: Génération des facettes emplacement lors de l'import/mise à
+  jour d'une notice.
+
+- ticket #18512: Corrige l'ajout d'avis sur les articles
+
+- ticket #19216: Supprime la limite "bokeh" pour l'upload de fichier multiple.
+  La seul restriction se situe au niveau de la configuration PHP.
+
+
+
 13/01/2015 - v6.59.2
 
 - ticket #19208: Change la configuration du helper ckeditor pour permettre l'utilisation d'ids sur tous les elements.
diff --git a/application/modules/admin/controllers/ModoController.php b/application/modules/admin/controllers/ModoController.php
index cdcc14fa778691fa094d159e1af0dddbd8b73143..67f2cac2d50e68c127976d7c2c1c435bea788746 100644
--- a/application/modules/admin/controllers/ModoController.php
+++ b/application/modules/admin/controllers/ModoController.php
@@ -99,7 +99,7 @@ class Admin_ModoController extends ZendAfi_Controller_Action {
 	public function deleteCmsAvisAction() {
 		$avis = Class_Avis::find($this->_getParam('id'));
 		$avis->delete();
-		$avis->maj_note_cms($avis->getIdCms(), $avis->getAbonOuBib());
+		$avis->majNoteCms($avis->getIdCms(), $avis->getAbonOuBib());
 		$this->_redirect('opac/cms/articleview/id/'.$avis->getIdCms());
 
 		$this->_helper->notify($this->view->_('Avis %s supprimé', $avis->getEntete()));
@@ -163,7 +163,7 @@ class Admin_ModoController extends ZendAfi_Controller_Action {
 	public function delAviscmsAction() {
 		$avis = Class_Avis::find($this->_getParam('id'));
 		$avis->delete();
-		$avis->maj_note_cms($avis->getIdCms(), $avis->getAbonOuBib());
+		$avis->majNoteCms($avis->getIdCms(), $avis->getAbonOuBib());
 		$this->_helper->notify($this->view->_('Avis %s supprimé', $avis->getEntete()));
 		$this->_redirect('/admin/modo/aviscms');
 
@@ -173,7 +173,7 @@ class Admin_ModoController extends ZendAfi_Controller_Action {
 	public function validateAviscmsAction() {
 		$avis = Class_Avis::find($this->_getParam('id'));
 		$avis->beValid()->save();
-		$avis->maj_note_cms($avis->getIdCms(), $avis->getAbonOuBib());
+		$avis->majNoteCms($avis->getIdCms(), $avis->getAbonOuBib());
 		$this->_helper->notify($this->view->_('Avis %s validé', $avis->getEntete()));
 		$this->_redirect('/admin/modo/aviscms');
 	}
diff --git a/application/modules/opac/controllers/AbonneController.php b/application/modules/opac/controllers/AbonneController.php
index d3ab612feeffc6fbd5c62383d48de161e1507c71..1860dfdd57f9e27b3522571ed1da2a7115d010c5 100644
--- a/application/modules/opac/controllers/AbonneController.php
+++ b/application/modules/opac/controllers/AbonneController.php
@@ -132,83 +132,6 @@ class AbonneController extends ZendAfi_Controller_Action {
 	}
 
 
-	private function handleAvis($readSourceMethod, $writeAvisMethod) {
-		$cls_user= new Class_Users();
-
-		$avis = new Class_Avis();
-
-		// Validation du formulaire
-		if ($this->_request->isPost()) {
-			// Bornage du texte
-			$longueur_min = Class_AdminVar::get("AVIS_MIN_SAISIE");
-			$longueur_max = Class_AdminVar::get("AVIS_MAX_SAISIE");
-			if(!$longueur_min) $longueur_min=10;
-			if(!$longueur_max) $longueur_max=250;
-
-
-			$filter = new Zend_Filter_StripTags();
-			$avisSignature = trim($filter->filter($this->_request->getPost('avisSignature')));
-			$avisEntete = trim($filter->filter($this->_request->getPost('avisEntete')));
-			$avisTexte = trim($filter->filter($this->_request->getPost('avisTexte')));
-			$avisNote = trim($filter->filter($this->_request->getPost('avisNote')));
-			$id = trim($filter->filter($this->_request->getPost('id')));
-
-			if ($avisEntete != '' and (strlen($avisTexte)>= $longueur_min and strlen($avisTexte)<= $longueur_max ) and $avisSignature != '')
-			{
-				$avis->$writeAvisMethod($this->_user->ID_USER,$this->_user->ROLE_LEVEL,$id,$avisNote,$avisEntete,$avisTexte);
-				$cls_user->updatePseudo($this->_user, $avisSignature);
-
-				$this->_renderRefreshOnglet();
-			}
-			else
-			{
-				if(strlen($avisTexte)< $longueur_min or strlen($avisTexte) > $longueur_max)
-					$this->view->message = $this->_("L'avis doit avoir une longueur comprise entre %d et %d caractères", $longueur_min, $longueur_max);
-				else
-					$this->view->message = $this->_('Il faut compléter tous les champs.');
-				$this->view->avisSignature = $avisSignature;
-				$this->view->avisEntete = $avisEntete;
-				$this->view->avisTexte = $avisTexte;
-				$this->view->avisNote = $avisNote;
-				$this->view->id = $id;
-
-				$viewRenderer = $this->getHelper('ViewRenderer');
-				$viewRenderer->setLayoutScript('subModal.phtml');
-			}
-		}
-		// Saisie du formulaire
-		else
-		{
-			$id = $this->_request->getParam('id', 0);
-			$this->view->message = '';
-			$this->view->id = $id;
-			$this->view->avisSignature = $cls_user->getNomAff($this->_user->ID_USER);
-			$data = $avis->$readSourceMethod($this->_user->ID_USER, $id);
-
-			$this->view->avisEntete = $data[0]["ENTETE"];
-			$this->view->avisTexte = $data[0]["AVIS"];
-			if(!$data[0]["NOTE"]) $data[0]["NOTE"]="0";
-			$this->view->avisNote = $data[0]["NOTE"];
-			if($this->view->avisEntete) $this->view->mode_modif=true;
-			else $this->view->mode_modif=false;
-
-			$viewRenderer = $this->getHelper('ViewRenderer');
-			$viewRenderer->setLayoutScript('subModal.phtml');
-		}
-	}
-
-
-	protected function _renderRefreshOnglet() {
-		$this->getResponse()->setHeader('Content-Type', 'text/html;charset=utf-8');
-		$js = 'location.reload()';
-		if (array_key_exists('onglets', $_SESSION))
-			$js = "refreshOnglet('" . $_SESSION["onglets"]["avis"] . "')";
-		$this->getResponse()->setBody("<script>window.top.hidePopWin(false);window.top." . $js. ";</script>");
-		$viewRenderer = $this->getHelper('ViewRenderer');
-		$viewRenderer->setNoRender();
-	}
-
-
 	public function avisAction()	{
 		$id_notice = $this->_request->getParam('id_notice', 0);
 
@@ -317,7 +240,68 @@ class AbonneController extends ZendAfi_Controller_Action {
 
 
 	public function cmsavisAction()	{
-		$this->handleAvis('getCmsAvisById', 'ecrireCmsAvis');
+		$this->view->titre = $this->_('Votre avis');
+
+		// Validation du formulaire
+		if ($this->_request->isPost()) {
+			// Bornage du texte
+			$longueur_min = Class_AdminVar::get("AVIS_MIN_SAISIE");
+			$longueur_max = Class_AdminVar::get("AVIS_MAX_SAISIE");
+			if(!$longueur_min) $longueur_min=10;
+			if(!$longueur_max) $longueur_max=250;
+
+
+			$filter = new Zend_Filter_StripTags();
+			$avisSignature = trim($filter->filter($this->_request->getPost('avisSignature')));
+			$avisEntete = trim($filter->filter($this->_request->getPost('avisEntete')));
+			$avisTexte = trim($filter->filter($this->_request->getPost('avisTexte')));
+			$avisNote = trim($filter->filter($this->_request->getPost('avisNote')));
+			$id = trim($filter->filter($this->_request->getParam('id')));
+
+			if ($avisEntete != '' and (strlen($avisTexte)>= $longueur_min and strlen($avisTexte)<= $longueur_max ) and $avisSignature != '')	{
+				Class_Avis::ecrireCmsAvis($this->_user->ID_USER,
+																	$this->_user->ROLE_LEVEL,
+																	$id,
+																	$avisNote,
+																	$avisEntete,
+																	$avisTexte);
+				$this->_user
+					->setPseudo($avisSignature)
+					->save();
+
+				$this->_redirect('/opac/cms/articleview/id/'.$id);
+				return;
+			}
+			else
+			{
+				if(strlen($avisTexte)< $longueur_min or strlen($avisTexte) > $longueur_max)
+					$this->view->message = $this->_("L'avis doit avoir une longueur comprise entre %d et %d caractères", $longueur_min, $longueur_max);
+				else
+					$this->view->message = $this->_('Il faut compléter tous les champs.');
+				$this->view->avisSignature = $avisSignature;
+				$this->view->avisEntete = $avisEntete;
+				$this->view->avisTexte = $avisTexte;
+				$this->view->avisNote = $avisNote;
+				$this->view->id = $id;
+			}
+		}
+		// Saisie du formulaire
+		else
+		{
+			$id = $this->_request->getParam('id', 0);
+			$this->view->message = '';
+			$this->view->id = $id;
+			$this->view->avisSignature = $this->_user->getNomAff();
+
+			if (!$avis = Class_Avis::findFirstBy(['id_user' => $this->_user->getId(),
+																						'id_cms' => $id]))
+				$avis = Class_Avis::newInstance(['id_user' => $this->_user->getId(),
+																				 'id_cms' => $id]);
+
+			$this->view->avisEntete = $avis->getEntete();
+			$this->view->avisTexte = $avis->getAvis();
+			$this->view->avisNote = $avis->getNote();
+		}
 	}
 
 
diff --git a/application/modules/opac/controllers/BlogController.php b/application/modules/opac/controllers/BlogController.php
index 33338e491ca39faa521f38c821e32dc66fa1acfc..5788de638ef22b102ac4d1630ec58307808e9748 100644
--- a/application/modules/opac/controllers/BlogController.php
+++ b/application/modules/opac/controllers/BlogController.php
@@ -16,7 +16,7 @@
  *
  * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
  * along with BOKEH; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA 
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
  */
 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 //  OPAC3: Blog
@@ -28,7 +28,7 @@ class BlogController extends ZendAfi_Controller_Action {
 	private $_user = null;								// Le user connecté
 	var $modo_blog;
 	var $_today;
-    
+
 	function init()
 	{
 		//Verify that the user has successfully authenticated.  If not, we redirect to the login.
@@ -39,15 +39,15 @@ class BlogController extends ZendAfi_Controller_Action {
 		$class_date = new Class_Date();
 		$this->_today = $class_date->DateTimeDuJour();
 	}
-    
+
 	function indexAction()
 	{
 		$this->_redirect('opac/blog/lastcritique/nb/10');
 	}
-	
-	//------------------------------------------------------------------------------------------------------  
+
+	//------------------------------------------------------------------------------------------------------
 	// Donner son avis
-	//------------------------------------------------------------------------------------------------------  
+	//------------------------------------------------------------------------------------------------------
 	function viewauteurAction()	{
 		$id_user = (int)$this->_request->getParam('id', $this->_user->ID_USER);
 		if ($auteur = Class_Users::getLoader()->find($id_user)) {
@@ -57,7 +57,7 @@ class BlogController extends ZendAfi_Controller_Action {
 			$this->view->liste_avis = '';
 			$this->view->name = 'Auteur introuvable';
 		}
-		
+
 		$this->view->title = "Avis";
 		$this->view->id_user = $id_user;
 
@@ -84,12 +84,12 @@ class BlogController extends ZendAfi_Controller_Action {
 		$this->_javascriptRedirectToReferrer();
 	}
 
-    
+
 	function lastcritiqueAction()	{
 		$nb_avis = (int)$this->_request->getParam('nb', 20);
 		$liste_avis = Class_AvisNotice::getLoader()->findAllBy(array('order' => 'date_avis desc',
 																																 'limit' => $nb_avis));
-		
+
 		$this->view->nb_aff = $nb_avis;
 		$this->view->liste_avis = Class_AvisNotice::filterVisibleForUser($this->_user, $liste_avis);
 		$this->view->title = $this->view->_("Dernières critiques");
@@ -102,7 +102,7 @@ class BlogController extends ZendAfi_Controller_Action {
 		$preferences = Class_Profil::getCurrentProfil()
 			->getModuleAccueilPreferences($id_module, 'CRITIQUES');
 		$avis = Class_AvisNotice::getAvisFromPreferences($preferences);
-		
+
 		$this->view->nb_aff = 50;
 		$this->view->liste_avis = $avis;
 		$this->view->title = 'Dernières critiques';
@@ -119,13 +119,13 @@ class BlogController extends ZendAfi_Controller_Action {
 			->getHelper('ViewRenderer')
 			->setLayoutScript('readspeaker.phtml');
 
-		$id_avis = $this->_request->getParam('id'); 
+		$id_avis = $this->_request->getParam('id');
 		$this->view->avis = Class_AvisNotice::getLoader()->find($id_avis);
 	}
 
-    
+
 	function viewavisAction()	{
-		$id_avis = $this->_request->getParam('id'); 
+		$id_avis = $this->_request->getParam('id');
 		$avis = Class_AvisNotice::getLoader()->find($id_avis);
 
 		$this->view->avis = $avis;
@@ -134,52 +134,9 @@ class BlogController extends ZendAfi_Controller_Action {
 		$this->view->user_co = ($this->_user->ID_USER != '');
 		$this->view->user = $this->_user;
 	}
-    
-
-	function addcmtAction()	{
-		$filter = new Zend_Filter_StripTags();
-		$contenu = $filter->filter($this->_request->getPost('cmt'));
-		$id_avi = $this->_request->getPost('id_avis'); $id_avis = explode('-',$id_avi);
-		$pseudo = $this->_request->getPost('pseudo');
-		$type = $this->_request->getPost('type');
-
-		if(trim($pseudo)=="") {$this->_redirect('blog/viewavis/id/'.$id_avi);}
-        
-        
-		if($type == "notice") $id_notice = $id_avis[0]; else $id_notice = 0;
-		if($type == "cms") $id_cms = $id_avis[0]; else $id_cms = 0;
-		if($this->modo_blog == 1) $statut =0; else $statut=1;
-
-		if($this->_user->LOGIN)	{
-				if($this->_user->ROLE_LEVEL >=3) $abon_ou_bib = 1;
-				else $abon_ou_bib = 0;
-
-				$cls_user= new Class_Users();
-				$cls_user->updatePseudo($this->_user, $pseudo);
-		}	else 	{
-			$abon_ou_bib = 0;
-		}
-        
-		$data = array(
-									'ID_CMT' => '',
-									'ID_USER' => $this->_user->ID_USER,
-									'ID_NOTICE' => $id_notice,
-									'ID_CMS' => $id_cms,
-									'DATE_CMT' => $this->_today,
-									'DATE_MOD' => null,
-									'CMT' => $contenu,
-									'STATUT' => $statut,
-									'ABON_OU_BIB' => $abon_ou_bib,
-									'SIGNATURE' => $pseudo,
-									);
-        
-		$class_blog = new Class_Blog();
-		$class_blog->addCmt($data);
-		$this->_redirect('blog/viewavis/id/'.$id_avi);
-	}
-    
-	function alertAction()
-	{
+
+
+	function alertAction()	{
 		$class_blog = new Class_Blog();
 		$type = $this->_request->getParam('type');
 		$id = $this->_request->getParam('id_avis');
diff --git a/application/modules/opac/views/scripts/abonne/avis.phtml b/application/modules/opac/views/scripts/abonne/avis.phtml
index 205501b56bc9825953a303d1295ac5f4c38c6f57..6ca3fc9bd736d670eed1d613e177592af94dfafc 100644
--- a/application/modules/opac/views/scripts/abonne/avis.phtml
+++ b/application/modules/opac/views/scripts/abonne/avis.phtml
@@ -1,9 +1,9 @@
 <?php
-echo $this->partial("abonne/avis_partial.phtml", 
+echo $this->partial("abonne/avis_partial.phtml",
 										array(
 													'message' => $this->message,
-													'action' => $this->url(array('controller' => 'abonne', 
-																											 'action' => 'avis', 
+													'action' => $this->url(array('controller' => 'abonne',
+																											 'action' => 'avis',
 																											 'id_notice' => $this->id_notice,
 																											 'id' => $this->id)),
 													'id' => $this->id,
@@ -11,19 +11,5 @@ echo $this->partial("abonne/avis_partial.phtml",
 													'avisEntete' => $this->avisEntete,
 													'avisTexte' => $this->avisTexte,
 													'avisNote' => $this->avisNote,
-													));  
+													));
 ?>
-
-<script> 
-$('#opac-dialog form').submit(function(event) {
-  event.preventDefault();
-  var form = $(this);
-  $.post(form.attr('action'),
-         form.serialize(),
-         function(data) { opacDialogClose(); 
-                          opacDialogFromData(data); 
-                         }
-         );
-}
-);
-</script>
\ No newline at end of file
diff --git a/application/modules/opac/views/scripts/abonne/avis_partial.phtml b/application/modules/opac/views/scripts/abonne/avis_partial.phtml
index 7f00091c6a9f74622b197f3f7edf2068044292af..f86c9fa10a269238713933d8ebcb58908d2d7d00 100644
--- a/application/modules/opac/views/scripts/abonne/avis_partial.phtml
+++ b/application/modules/opac/views/scripts/abonne/avis_partial.phtml
@@ -37,4 +37,20 @@
 		</form>
 		<br>
 	</div>
-</center>
\ No newline at end of file
+</center>
+
+
+
+<script>
+$('#opac-dialog form').submit(function(event) {
+  event.preventDefault();
+  var form = $(this);
+  $.post(form.attr('action'),
+         form.serialize(),
+         function(data) { opacDialogClose();
+                          opacDialogFromData(data);
+                         }
+         );
+}
+);
+</script>
diff --git a/ckeditor/core_five_filemanager/scripts/filemanager.js b/ckeditor/core_five_filemanager/scripts/filemanager.js
index 984590c6727fda31ef3056afcd36873ac6f43b25..7e2ec29e587c2e25ee94bc2d6f59c2c790ab4518 100644
--- a/ckeditor/core_five_filemanager/scripts/filemanager.js
+++ b/ckeditor/core_five_filemanager/scripts/filemanager.js
@@ -952,10 +952,10 @@ $(function(){
 
 			if (is_image) {
 				$.prompt(
-								 [{title: 'Redimmensionner automatiquement l\'image si la résolution est supérieure à:',
+								 [{title: 'Redimensionner automatiquement l\'image si la résolution est supérieure à:',
 									buttons: {
 										'OK': true,
-										'Ne pas redimmensionner': false},
+										'Ne pas redimensionner': false},
 									html: '<label><input type="radio" name="geometry" value="800">800x600</label>'
 									 +'<label><input type="radio" name="geometry" value="1024" checked="checked">1024x768</label>'
 									 +'<label><input type="radio" name="geometry" value="1280">1280x1024</label>',
diff --git a/ckeditor/core_five_filemanager/scripts/languages/fr.js b/ckeditor/core_five_filemanager/scripts/languages/fr.js
index 983ad12276de0e38660b3859fbb1ea6e48997d8c..b1d5a942a687cd4984c07b6f6b988d333d220094 100644
--- a/ckeditor/core_five_filemanager/scripts/languages/fr.js
+++ b/ckeditor/core_five_filemanager/scripts/languages/fr.js
@@ -53,5 +53,5 @@
 	"kb": "ko",
 	"mb": "mo",
 	"gb": "go",
-	"resize" : "redimmensionner automatiquement les images"
+	"resize" : "redimensionner automatiquement les images"
 }
diff --git a/cosmogramme/php/classes/classe_notice_integration.php b/cosmogramme/php/classes/classe_notice_integration.php
index a97af8eac3df586076fa8b4b39e27a55773271bc..462578625f42e40c47a018d02d120eb24d888568 100644
--- a/cosmogramme/php/classes/classe_notice_integration.php
+++ b/cosmogramme/php/classes/classe_notice_integration.php
@@ -878,6 +878,10 @@ class notice_integration {
 			}
 		}
 
+		// emplacements
+		if (count($this->notice['emplacements']))
+				$facettes = array_merge($facettes, array_map(function($e) { return "E$e";}, $this->notice['emplacements']));
+
 		// Maj enreg facette
 		$this->notice["facettes"] = trim(implode(' ', array_unique($facettes)));
 	}
diff --git a/cosmogramme/tests/php/classes/NoticeIntegrationTest.php b/cosmogramme/tests/php/classes/NoticeIntegrationTest.php
index 6374b2bb219203e9a88462252a42a870806917dd..b06e28b6fe2f9ed48bec4b51c6eae28a9dfc9780 100644
--- a/cosmogramme/tests/php/classes/NoticeIntegrationTest.php
+++ b/cosmogramme/tests/php/classes/NoticeIntegrationTest.php
@@ -2209,4 +2209,55 @@ class NoticeIntegrationOblivionTest extends NoticeIntegrationTestCase {
 	}
 }
 
+
+
+
+class NoticeIntegrationPommeDeReinetteTest extends NoticeIntegrationTestCase {
+	protected $_profil_donnees = ['id_profil' => 111,
+																'id' => 111,
+																'libelle' => 'Unimarc Casqy',
+																'accents' => '1',
+																'rejet_periodiques' =>  '0',
+																'id_article_periodique' => '2',
+																'type_fichier' => '0',
+																'format' => '0',
+																'attributs' => 'a:6:{i:0;a:8:{s:8:"type_doc";a:26:{i:0;a:3:{s:4:"code";s:1:"0";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:1;a:3:{s:4:"code";s:1:"1";s:5:"label";s:5:"am;na";s:8:"zone_995";s:6:"LIV;MS";}i:2;a:3:{s:4:"code";s:1:"2";s:5:"label";s:2:"as";s:8:"zone_995";s:3:"PER";}i:3;a:3:{s:4:"code";s:1:"3";s:5:"label";s:3:"i;j";s:8:"zone_995";s:17:"CD;LIVCD;LIVK7;K7";}i:4;a:3:{s:4:"code";s:1:"4";s:5:"label";s:1:"g";s:8:"zone_995";s:3:"DVD";}i:5;a:3:{s:4:"code";s:1:"5";s:5:"label";s:3:"l;m";s:8:"zone_995";s:3:"CDR";}i:6;a:3:{s:4:"code";s:1:"6";s:5:"label";s:2:"cm";s:8:"zone_995";s:3:"PAR";}i:7;a:3:{s:4:"code";s:1:"7";s:5:"label";s:0:"";s:8:"zone_995";s:3:"BRO";}i:8;a:3:{s:4:"code";s:1:"8";s:5:"label";s:0:"";s:8:"zone_995";s:3:"DOS";}i:9;a:3:{s:4:"code";s:1:"9";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:10;a:3:{s:4:"code";s:2:"10";s:5:"label";s:0:"";s:8:"zone_995";s:6:"WEB;MF";}i:11;a:3:{s:4:"code";s:2:"11";s:5:"label";s:0:"";s:8:"zone_995";s:3:"MET";}i:12;a:3:{s:4:"code";s:2:"12";s:5:"label";s:0:"";s:8:"zone_995";s:3:"JEU";}i:13;a:3:{s:4:"code";s:2:"13";s:5:"label";s:0:"";s:8:"zone_995";s:3:"CAR";}i:14;a:3:{s:4:"code";s:2:"14";s:5:"label";s:0:"";s:8:"zone_995";s:3:"DDD";}i:15;a:3:{s:4:"code";s:2:"15";s:5:"label";s:0:"";s:8:"zone_995";s:3:"DIA";}i:16;a:3:{s:4:"code";s:2:"16";s:5:"label";s:0:"";s:8:"zone_995";s:3:"DIS";}i:17;a:3:{s:4:"code";s:2:"17";s:5:"label";s:0:"";s:8:"zone_995";s:3:"CDJ";}i:18;a:3:{s:4:"code";s:2:"18";s:5:"label";s:0:"";s:8:"zone_995";s:4:"LDVD";}i:19;a:3:{s:4:"code";s:2:"19";s:5:"label";s:0:"";s:8:"zone_995";s:3:"LIA";}i:20;a:3:{s:4:"code";s:2:"20";s:5:"label";s:0:"";s:8:"zone_995";s:3:"LIS";}i:21;a:3:{s:4:"code";s:2:"21";s:5:"label";s:0:"";s:8:"zone_995";s:3:"TXT";}i:22;a:3:{s:4:"code";s:2:"22";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:23;a:3:{s:4:"code";s:2:"23";s:5:"label";s:0:"";s:8:"zone_995";s:14:"VDD;VID;UMATIC";}i:24;a:3:{s:4:"code";s:2:"24";s:5:"label";s:0:"";s:8:"zone_995";s:4:"METI";}i:25;a:3:{s:4:"code";s:3:"100";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}}s:17:"champ_code_barres";s:1:"f";s:10:"champ_cote";s:1:"k";s:14:"champ_type_doc";s:0:"";s:11:"champ_genre";s:0:"";s:13:"champ_section";s:1:"q";s:17:"champ_emplacement";s:1:"u";s:12:"champ_annexe";s:1:"b";}i:1;a:1:{s:6:"champs";s:0:"";}i:2;a:1:{s:6:"champs";s:0:"";}i:3;a:1:{s:6:"champs";s:0:"";}i:5;a:3:{s:6:"champs";s:0:"";s:17:"xml_balise_abonne";s:0:"";s:17:"xml_champs_abonne";a:11:{s:6:"IDABON";s:0:"";s:9:"ORDREABON";s:0:"";s:3:"NOM";s:0:"";s:6:"PRENOM";s:0:"";s:9:"NAISSANCE";s:0:"";s:8:"PASSWORD";s:0:"";s:4:"MAIL";s:0:"";s:10:"DATE_DEBUT";s:0:"";s:8:"DATE_FIN";s:0:"";s:7:"ID_SIGB";s:0:"";s:9:"NUM_CARTE";s:0:"";}}i:4;a:5:{s:4:"zone";s:3:"995";s:5:"champ";s:1:"v";s:6:"format";s:1:"3";s:5:"jours";s:0:"";s:7:"valeurs";s:1:"n";}}'
+	];
+
+
+	public function setUp() {
+		parent::setUp();
+
+		VariableCache::getInstance()
+			->setListeCache([
+											 'nature_docs'=> "1:Collection\r\n2:Dataset\r\n3:Event\r\n4:Image",
+											 'types_docs' => "0:non identifié\r\n1:livres\r\n2:périodiques\r\n3:disques\r\n4:DVD\r\n5:cédéroms\r\n8:articles cms\r\n9:fils rss\r\n10:sites internet\r\n15:Liseuse\r\n21:Texte audio\r\n100:Livre Numérique\r\n101:Diaporamas\r\n102:Type doc\r\n103:OAI\r\n104:Type doc\r\n105:Formation Vodéclic\r\n106:Livres Numériques\r\n107:Vidéos à la demande\r\n108:Tout apprendre\r\n109:Enregistrement audio\r\n110:Numérique Premium"
+											 ]);
+
+		$this->fixture('Class_CodifEmplacement',
+									 ['id' => 46,
+										'libelle' => 'Espace Bébé',
+										'regles' => '995$u=59;Espace bébé']);
+
+		$this->loadNotice('unimarc_pomme_de_reinette');
+
+		$this->_notice = Class_Notice::find(1);
+		$this->_exemplaire = Class_Exemplaire::findFirstBy(['id_notice' => 1,
+																												'code_barres' => '1203195946']);
+	}
+
+
+	/** @test */
+	public function exemplaireShouldHaveEmplacementE46() {
+		$this->assertEquals(46, $this->_exemplaire->getEmplacement());
+	}
+
+
+	/** @test */
+	public function facettesShouldContainsE46() {
+		$this->assertContains(' E46', $this->_notice->getFacettes());
+	}
+}
+
+
 ?>
\ No newline at end of file
diff --git a/cosmogramme/tests/php/classes/unimarc_pomme_de_reinette.txt b/cosmogramme/tests/php/classes/unimarc_pomme_de_reinette.txt
new file mode 100644
index 0000000000000000000000000000000000000000..9506e2bdc68aff4d92a17e7fb31019233a029f8e
--- /dev/null
+++ b/cosmogramme/tests/php/classes/unimarc_pomme_de_reinette.txt
@@ -0,0 +1 @@
+01368nam0 2200325   450 0010008000000100035000080730018000431000041000611010008001021020007001101050018001171060006001352000098001412100058002392150063002973300227003606060014005876860027006016860026006286860026006547000038006808010033007188010021007518010033007728010021008059020011008269950078008379950052009159950075009672209406  a2-7470-1757-5brel.d14,90 EUR 0a9782747017572  a20051003d2005    m  y0frey0103    ba| afre  aFR  ay   z   000a|  ar1 aPomme de reinette et pomme d'apieles comptines des petitsfIllustrations de Antonin Louchard  a[Paris]cBayard jeunessedDL 2005eimpr. Áa Singapour  a1 vol. (227 p.)cill. en coul., couv. ill. en coul.d17 cm  a23 comptines connues des tout-petits, dÂeclinÂees chacune en 4 sÂequences. DiffÂerentes techniques graphiques (la photo, le dessin, la gravure, la peinture, les collages, etc.) sont employÂees pour illustrer ces comptines.| aComptines  aJ0001002thÁemeelectre  aGJEU0022genreelectre  aPJ02012publicelectre |aLouchardbAntoninf1954-....4070 3aFRbElectrec20050930gAFNOR |aFRbROU Juliette 3aFRbElectrec20050930gAFNOR |aFRbROU Juliette  aHumour  32209418aJean RousselotbROUf1208051453k804 LOU oEXCLU DU PRETq8rLIV  32239820aCRPEbCRPEf1204069881kA LOU q5rLIV  32986171aAnatole FrancebTRAf1203195946kBB C q8rLIVuEspace bÂebÂe
\ No newline at end of file
diff --git a/library/Class/Article.php b/library/Class/Article.php
index 7282dc8c7ef77f15e52032da85e0bc624d28773b..b3fae930ac120e0de2392be6cdc6e9ea01a8a92c 100644
--- a/library/Class/Article.php
+++ b/library/Class/Article.php
@@ -1065,7 +1065,9 @@ class Class_Article extends Storm_Model_Abstract {
 
 
 	public function getRank() {
-		return Class_CmsRank::getLoader()->findFirstBy(array('id_cms' => $this->getId()));
+		if (!$rank = Class_CmsRank::findFirstBy(['id_cms' => $this->getId()]))
+			$rank = Class_CmsRank::newInstance(['id_cms' => $this->getId()]);
+		return $rank;
 	}
 
 
@@ -1175,4 +1177,4 @@ class Class_Article extends Storm_Model_Abstract {
 
 }
 
-?>
+?>
\ No newline at end of file
diff --git a/library/Class/Avis.php b/library/Class/Avis.php
index f878a6cb81cf6aadfaeceaa967f61297ff6bc31f..9181071006baa41775c32bba0f207e5011db1499 100644
--- a/library/Class/Avis.php
+++ b/library/Class/Avis.php
@@ -23,7 +23,7 @@
  * Gestion des Avis sur les articles
  */
 class Class_Avis extends Storm_Model_Abstract {
-	use Trait_Avis;
+	use Trait_Avis, Trait_TimeSource, Trait_Translator;
 
 	protected $_table_name = 'cms_avis';
 	protected $_belongs_to = ['auteur' => ['model' => 'Class_Users',
@@ -35,37 +35,15 @@ class Class_Avis extends Storm_Model_Abstract {
 														'user' => ['model' => 'Class_Users',
 																			 'referenced_in' => 'id_user']];
 
-	var $sql;	// Curseur sql
-	var $_today;
+	protected $_default_attribute_values = ['entete' => '',
+																					'avis' => '',
+																					'note' => 0	];
 
 
-	public function __construct() {
-		$this->sql = Zend_Registry::get('sql');
-		$class_date = new Class_Date();
-		$this->_today = $class_date->DateTimeDuJour();
-	}
-
-
-	public function getNomAff() {
-		if (!$auteur = $this->getAuteur())
-			return 'Anonyme';
-		return $auteur->getNomAff();
-	}
-
-
-	public function beValid() {
-		return $this->setStatut(1);
-	}
-
-
-	public function getCmsAvisById($id_user,$id_news) {
-		$req_news = "Select * from cms_avis Where ID_CMS=$id_news AND ID_USER=$id_user";
-		return $this->sql->fetchAll($req_news);
-	}
 
 
 	/** Ecrire 1 avis (update si existe déjà) */
-	public function ecrireCmsAvis($id_user, $role_level, $id_news, $note, $entete, $avis) {
+	public static function ecrireCmsAvis($id_user, $role_level, $id_news, $note, $entete, $content) {
 		$modo_avis_abo = getVar('MODO_AVIS'); // 0 apres / 1 avant de publier sur le site
 		$modo_avis_bib = getVar('MODO_AVIS_BIBLIO'); // 0 apres / 1 avant de publier sur le site
 
@@ -79,85 +57,69 @@ class Class_Avis extends Storm_Model_Abstract {
 			if($modo_avis_bib == 0) $statut = 1;
 		}
 
-		try {
-			$avis = Class_Avis::getLoader()->findFirstBy(['id_user' => $id_user,
-																										'id_cms' => $id_news]);
-
-			if (!$avis)
-				$avis = Class_Avis::newInstance(['id_user' => $id_user,
-																				 'id_notice' => '',
-																				 'id_cms' => $id_news,
-																				 'date_avis' => $this->_today,
-																				 'date_mod' => '']);
-
-			$avis
-				->setEntete(strLeft($entete, 100))
-				->setAvis($avis)
-				->setNote($note)
-				->setStatut($statut)
-				->setAbonOuBib($abon_ou_bib)
-				->save();
-
-			if (($modo_avis_abo == 0 && $role_level < 3)
-					|| ($modo_avis_bib == 0 && $role_level >= 3))
-				$this->maj_note_cms($id_news, $abon_ou_bib);
-
-		} catch (Exception $e) {
-			logErrorMessage('Class: Class_Avis; Function: ecrireCmsAvis' . NL . $req . NL . $e->getMessage());
-			return false;
-		}
+		$avis = Class_Avis::getLoader()->findFirstBy(['id_user' => $id_user,
+																									'id_cms' => $id_news]);
+
+		if (!$avis)
+			$avis = Class_Avis::getLoader()->newInstance(['id_user' => $id_user,
+																										'id_notice' => '',
+																										'id_cms' => $id_news,
+																										'date_avis' => date('Y-m-d H:i:s', self::getTimeSource()->time()),
+																										'date_mod' => '']);
+		$avis
+			->setEntete(strLeft($entete, 100))
+			->setAvis($content)
+			->setNote($note)
+			->setStatut($statut)
+			->setAbonOuBib($abon_ou_bib)
+			->save();
+
+		if (($modo_avis_abo == 0 && $role_level < 3)
+				|| ($modo_avis_bib == 0 && $role_level >= 3))
+			$avis->majNoteCms($id_news, $abon_ou_bib);
+
+		return $avis;
 	}
 
 
-	public function maj_note_cms($id_news, $abon_ou_bib)	{
-		$sqlStmt = "Select count(*), avg(NOTE) From cms_avis Where ID_CMS=$id_news and ABON_OU_BIB='$abon_ou_bib' AND STATUT=1";
-		$data = $this->sql->fetchAll($sqlStmt);
-		$note=round($data[0]["avg(NOTE)"],1);
-		if (strlen($note)==1)
-			$note.=".0";
-		else	{
-			$dec=strRight($note,1);
-			if($dec<3) $dec="0"; elseif($dec<"8")$dec="5";else {$note+=1; $dec=0;}
-			$note=strLeft($note,1).".".$dec;
-		}
 
-		$nombre=$data[0]["count(*)"];
-				// Lire enreg rank
-		$enreg=fetchEnreg("select * from cms_rank where ID_CMS=$id_news");
-		$sqlStmt = "Delete from cms_rank Where ID_CMS=$id_news";
-		$stmt = $this->sql->query($sqlStmt);
-		if($abon_ou_bib==1) {
-			$abon_nombre_avis=$enreg["ABON_NOMBRE_AVIS"];
-			$abon_note=$enreg["ABON_NOTE"];
-			$bib_nombre_avis=$nombre;
-			$bib_note=$note;
-		} else {
-			$abon_nombre_avis=$nombre;
-			$abon_note=$note;
-			$bib_nombre_avis=$enreg["BIB_NOMBRE_AVIS"];
-			$bib_note=$enreg["BIB_NOTE"];
-		}
+	public function getNomAff() {
+		if (!$auteur = $this->getAuteur())
+			return $this->_('Anonyme');
+		return $auteur->getNomAff();
+	}
 
-		if(!$abon_nombre_avis) $abon_nombre_avis=0;
-		if(!$bib_nombre_avis) $bib_nombre_avis=0;
 
-		$sqlStmt = "Insert Into cms_rank(ID_CMS,ABON_NOMBRE_AVIS,ABON_NOTE,BIB_NOMBRE_AVIS,BIB_NOTE) Values($id_news,$abon_nombre_avis,'$abon_note',$bib_nombre_avis,'$bib_note')";
-		$stmt = $this->sql->query($sqlStmt);
+	public function beValid() {
+		return $this->setStatut(1);
 	}
 
 
-	public function HtmlCmsAvecAvis($id_news) {
-		$req_news = "Select * from cms_article Where ID_ARTICLE=$id_news";
-		$news = $this->sql->fetchAll($req_news);
+	public function majNoteCms($id_news, $abon_ou_bib)	{
+		$note = 0;
+		if ( $all_avis = Class_Avis::getLoader()->findAllBy(['id_cms' => $id_news,
+																												 'abon_ou_bib' => $abon_ou_bib,
+																												 'statut' => 1])) {
+			$note = array_sum(array_map(function($a){return $a->getNote();}, $all_avis)) / count($all_avis);
+		}
 
-		if ($news[0]["AVIS"] != 1)
-			return ' ';
+		$note = sprintf("%01.1f", floor($note * 2)/2);
+		$nombre = count($all_avis);
 
-		$sqlStmt = "Select * from cms_rank Where ID_CMS=$id_news";
-		$ret = $this->sql->fetchAll($sqlStmt);
+		$rank = Class_Article::find($id_news)->getRank();
 
-		$nb_avis = (int)$ret[0]["BIB_NOMBRE_AVIS"] + (int)$ret[0]["ABON_NOMBRE_AVIS"];
-		$label = ($nb_avis == 0) ? 'aucun avis' : ' avis ('.$nb_avis.')';
-		return '<div align="right"><a href="'.BASE_URL.'/cms/articleview/id/'.$id_news.'">&raquo;' . $label . '</a></div>';
+		if ($abon_ou_bib == static::$AVIS_BIBLIO) {
+			$rank
+				->setBibNombreAvis($nombre)
+				->setBibNote($note);
+		} else {
+			$rank
+				->setAbonNombreAvis($nombre)
+				->setAbonNote($note);
+		}
+
+		$rank->save();
 	}
-}
\ No newline at end of file
+}
+
+?>
\ No newline at end of file
diff --git a/library/Class/CmsRank.php b/library/Class/CmsRank.php
index d1f8467ac54e28b30222540816bcac564f0d696d..72a6cb0d88097d784e4a9113ea80c7d03cba114e 100644
--- a/library/Class/CmsRank.php
+++ b/library/Class/CmsRank.php
@@ -16,29 +16,27 @@
  *
  * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
  * along with BOKEH; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA 
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
  */
 
 
 class Class_CmsRank extends Storm_Model_Abstract {
 	protected $_table_name = 'cms_rank';
-	protected $_belongs_to = array('article' => array('model' => 'Class_Article',
-			                                              'referenced_in' => 'id_cms'));
-	protected $_default_attribute_values = array(
+	protected $_table_primary = 'id_cms';
+
+	protected $_belongs_to = ['article' => ['model' => 'Class_Article',
+																					'referenced_in' => 'id_cms']];
+
+	protected $_default_attribute_values = [
 																					'abon_nombre_avis' => 0,
 																					'bib_nombre_avis' => 0,
 																					'abon_note' => 0,
-	                                        'bib_note' => 0);
+																					'bib_note' => 0];
 
-	public static function getLoader() {
-		return self::getLoaderFor(__CLASS__);
-	}
-
-	
 	public function getNbAvisTotal() {
 		return $this->getBibNombreAvis() + $this->getAbonNombreAvis();
 	}
 }
 
-		
+
 ?>
\ No newline at end of file
diff --git a/library/Class/MultiUpload.php b/library/Class/MultiUpload.php
index 873935f039858e6411941edd14ef5277bfa05711..2d9f3d22520a56fa95b706ad9bd0fa44728e079c 100644
--- a/library/Class/MultiUpload.php
+++ b/library/Class/MultiUpload.php
@@ -22,9 +22,6 @@ class Class_MultiUpload {
 	/** @var Zend_Controller_Request_Http */
 	protected $_request;
 
-	/** @var int */
-	protected $_sizeLimit = 10485760;
-
 	/** @var Class_MultiUpload_HandlerFactory */
 	protected $_handlerFactory;
 
@@ -165,9 +162,6 @@ class Class_MultiUpload {
 	 * @return bool
 	 */
 	public function handleUpload($uploadDirectory, $filename_prefix) {
-		if (!$this->_isPhpSettingsCompatible())
-			return false;
-
 		if (!$this->_setHandler())
 			return false;
 
@@ -176,10 +170,8 @@ class Class_MultiUpload {
 			return false;
 		}
 
-		if ($size > $this->_sizeLimit) {
-			$this->_error = 'Fichier trop volumineux';
+		if (!$this->_isPhpSettingsCompatible($size))
 			return false;
-		}
 
 		$filename = $filename_prefix . '_' . $this->_handler->getName();
 
@@ -227,17 +219,16 @@ class Class_MultiUpload {
 	/**
 	 * @return bool
 	 */
-	protected function _isPhpSettingsCompatible() {
+	protected function _isPhpSettingsCompatible($size) {
 		$settingsReader = $this->getSettingsReader();
 		$postSize		= $this->_toBytes($settingsReader->get('post_max_size'));
 		$uploadSize	= $this->_toBytes($settingsReader->get('upload_max_filesize'));
 
 		if (
-			($postSize < $this->_sizeLimit )
-			|| ($uploadSize < $this->_sizeLimit)
+			($postSize < $size )
+			|| ($uploadSize < $size)
 		) {
-			$size = max(array(1, $this->_sizeLimit / 1024 / 1024)) . 'M';
-			$this->_error = 'Paramétrage du serveur : monter le post_max_size et le upload_max_filesize à ' . $size;
+			$this->_error = 'Fichier trop volumineux. Paramétrage du serveur : monter le post_max_size et le upload_max_filesize à ' . $size;
 			return false;
 		}
 
diff --git a/library/Class/Users.php b/library/Class/Users.php
index e41ab42e8bb4d9c9e1539383e18bb2b85149df56..aee7ad6551a61019badd525f6da9e0ab71cb4425 100644
--- a/library/Class/Users.php
+++ b/library/Class/Users.php
@@ -789,18 +789,6 @@ class Class_Users extends Storm_Model_Abstract {
 	}
 
 
-	//------------------------------------------------------------------------------------------------------
-	// Ecriture user
-	//------------------------------------------------------------------------------------------------------
-	public function updatePseudo($data_user, $pseudo) {
-		$user = $this->getLoader()->find($data_user->ID_USER);
-		if ($user == null) return false;
-
-		return $user
-			->setPseudo($pseudo)
-			->save();
-	}
-
 	//------------------------------------------------------------------------------------------------------
 	// Vérification pour eviter les doublons de login
 	//------------------------------------------------------------------------------------------------------
diff --git a/library/ZendAfi/Controller/Plugin/AdminAuth.php b/library/ZendAfi/Controller/Plugin/AdminAuth.php
index 19753e8d23cc6000467fc957b93236dcf0cf79e3..23b522f18961a664ea2f831ffd0be4418b921cc6 100644
--- a/library/ZendAfi/Controller/Plugin/AdminAuth.php
+++ b/library/ZendAfi/Controller/Plugin/AdminAuth.php
@@ -66,7 +66,7 @@ class ZendAfi_Controller_Plugin_AdminAuth extends Zend_Controller_Plugin_Abstrac
 			if ((!$user = Class_Users::getIdentity()) && ($controller == "abonne" && $action !== "authenticate")) {
 				$request->setParam('redirect', Class_Url::absolute());
 				$controller = 'auth';
-				$action = 'login';
+				$action = ($request->getParam('render') == 'popup') ? 'popup-login' : 'login';
 			}
 		}
 
diff --git a/library/ZendAfi/View/Helper/AvisCms.php b/library/ZendAfi/View/Helper/AvisCms.php
index 92123b55a149a1dd1ed606f9ebdb061b7d2183f9..3bb676fa561aa838b79e9bdba3a5cc3066377396 100644
--- a/library/ZendAfi/View/Helper/AvisCms.php
+++ b/library/ZendAfi/View/Helper/AvisCms.php
@@ -16,39 +16,40 @@
  *
  * 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_AvisCms extends Zend_View_Helper_HtmlElement {
 	public function avisCms($article) {
 		return $this->rendHtmlBlockAvis($article);
 	}
 
-	
-	function rendHtmlBlockAvis($article)	{
-		$info_bib = $this->rendInfoCmsAvis($article, 1);
-		$info_abo = $this->rendInfoCmsAvis($article, 0);
 
+	function rendHtmlBlockAvis($article)	{
 		$nb_avis = 0;
-		if ($rank = $article->getRank())
-			$nb_avis = $rank->getNbAvisTotal();
+		$rank = $article->getRank();
+		$nb_avis = $rank->getNbAvisTotal();
 
 		$txt_nb_avis = ($nb_avis == 0) ?"&nbsp;Aucun avis" : "&nbsp;Avis (".$nb_avis.")";
 		$id_news = $article->getId();
 		$html = '<div class="avis_show_avis" onclick="showCmsAvis('.$id_news.', this)"><img src="'.URL_IMG.'bouton/plus_carre.gif" style="float:left" border="0" alt="Voir les avis" title="Voir les avis" id="plus"/> '.$txt_nb_avis.' </div>';
 		$html.='<div id="avis_'.$id_news.'" style="display:none;padding-left:5px;">';
 		$html.='<br />';
-		$html.='<a href="#" onclick="javascript:fonction_abonne(\''.Class_Users::currentUserId().'\',\'/opac/abonne/cmsavis?id='.$id_news.'\')">&raquo; Donner ou modifier votre avis</a>';
+		$html.= $this->view->tagAnchor(['controller' => 'abonne', 'action' => 'cmsavis', 'id' => $id_news],
+																	 '&raquo; '.$this->view->_('Donner ou modifier votre avis'),
+																	 ['data-popup' => 'true']);
 		$html.='<ul class="notice_info">';
-		$html.='<li>'.$info_bib["NOTE"].' <a href="#" onclick="showAvis('.$id_news.',\'bib\');return false;">Avis de bibliothécaires</a> '.$info_bib["AVIS"].'</li>';
-		$html.='<li>'.$info_abo["NOTE"].' <a href="#" onclick="showAvis('.$id_news.',\'abo\');return false;">Avis de lecteurs du portail</a> '.$info_abo["AVIS"].'</li>';
+		if ($rank->getBibNombreAvis())
+				$html.='<li>'.$this->view->noteImg($rank->getBibNote()).' <a href="#" onclick="showAvis('.$id_news.',\'bib\');return false;">Avis de bibliothécaires</a> '.$this->formatNoteLabel($rank->getBibNombreAvis()).'</li>';
+		if ($rank->getAbonNombreAvis())
+				$html.='<li>'.$this->view->noteImg($rank->getAbonNote()).' <a href="#" onclick="showAvis('.$id_news.',\'abo\');return false;">Avis de lecteurs du portail</a> '.$this->formatNoteLabel($rank->getAbonNombreAvis()).'</li>';
 		$html.='</ul>';
-        
+
 		$view = (getVar('MODO_AVIS_BIBLIO') == 1) ? 1 : "";
-        
+
 		$liste_avis = $this->getCmsAvisBiblio($article, $view);
 
 		$style = (count($liste_avis) == 0) ? "none" : "block";
-		
+
 		// Tableau bib
 		$html.='<div id="bib_'.$id_news.'" style="display:'.$style.'"><table cellpadding="0" cellspacing="0" border="0" style="width:100%">';
 		$html.='<tr><td class="avis_from">Avis des bibliothécaires</td></tr>';
@@ -56,7 +57,7 @@ class ZendAfi_View_Helper_AvisCms extends Zend_View_Helper_HtmlElement {
 		$html.='</table></div>';
 
 		$view = (getVar('MODO_AVIS') == 1) ? 1 : "";
-        
+
 		// Tableau Abonne
 		$liste_avis_abo = $this->getCmsAvisAbo($article, $view);
 
@@ -65,46 +66,22 @@ class ZendAfi_View_Helper_AvisCms extends Zend_View_Helper_HtmlElement {
 		$html.='<div id="abo_'.$id_news.'" style="display:'.$style.'"><table cellpadding="0" cellspacing="0" border="0" style="width:100%">';
 		$html.='<tr><td class="avis_from">Avis des lecteurs du portail</td></tr>';
 		$html.='<tr><td>'.$this->rendHTMLCmsAvis($liste_avis_abo,0).'</td></tr>';
-        
+
 		$html.='</table></div>';
 		$html.='</div>';
 		$html.='<div style="width:100%;background:transparent url('.URL_IMG.'box/menu/separ.gif) repeat-x scroll center bottom">&nbsp;</div>';
-        
+
 		return($html);
 	}
 
-
-	public function rendInfoCmsAvis($article, $abon_ou_bib) {
-		if (!$rank = $article->getRank())
-			return array('NOTE' => 0, 'AVIS' => 0, 'ABON_NOMBRE_AVIS' => 0, 'BIB_NOMBRE_AVIS' => 0);
-
-		$abon_nb_avis = $rank->getAbonNombreAvis();
-		$bib_nb_avis = $rank->getBibNombreAvis();
-		
-		if($abon_ou_bib == 0)	{
-				if ($abon_nb_avis == 0 || $abon_nb_avis == null) $nb_eva = "(aucune évaluation)";
-				elseif($abon_nb_avis == 1) $nb_eva = "(1 évaluation)";
-				elseif($abon_nb_avis > 1) $nb_eva = "(".$abon_nb_avis." évaluations)";
-            
-			$note = $rank->getAbonNote();
-		}	else {
-				if ($bib_nb_avis == 0 || $bib_nb_avis == null) $nb_eva = "(aucune évaluation)";
-				elseif($bib_nb_avis == 1) $nb_eva = "(1 évaluation)";
-				elseif($bib_nb_avis > 1) $nb_eva = "(".$bib_nb_avis." évaluations)";
-
-			$note = $rank->getBibNote();
-		}
-
-		$note_r = str_replace('.','-',$note);
-		$note_r = str_replace('-0','',$note_r);
-		if ($note_r == '') $note_r = "0";
-		$img = '<img src="'.URL_ADMIN_IMG.'stars/stars-'.$note_r.'.gif"  alt="note:'.$note.'" border="0"/>';
-		$info["NOTE"] = $img;
-
-		$info["AVIS"] = $nb_eva;
-		return($info);
+	public function formatNoteLabel($note) {
+		return $this->view->_plural($note,
+																'(aucune évaluation)',
+																'(%d évaluation)',
+																'(%d évaluations)',
+																$note);
 	}
-    
+
 
 	function getCmsAvisBiblio($article, $statut = "")	{
 		return $this->getCmsAvis($article, Trait_Avis::$AVIS_BIBLIO, $statut);
@@ -126,11 +103,11 @@ class ZendAfi_View_Helper_AvisCms extends Zend_View_Helper_HtmlElement {
 		return Class_Avis::getLoader()->findAllBy($params);
 	}
 
-    
+
 	// type =0 -> rend bulle blanche pour abonne
 	// type =1 -> rend bulle bleue pour bibliothecaire
 	function rendHTMLCmsAvis($avis_array, $type=0)	{
-		if(!is_array($avis_array))	
+		if(!is_array($avis_array))
 			return '';
 
 		$html = array();
@@ -190,7 +167,7 @@ class ZendAfi_View_Helper_AvisCms extends Zend_View_Helper_HtmlElement {
 			$html[]='</table>';
 		}
 
-		if(is_array($html)) 
+		if(is_array($html))
 			return(implode("", $html));
 
 		return('<div style="padding-left:7px">&nbsp;Aucun avis pour le moment.</div>');
diff --git a/library/startup.php b/library/startup.php
index c1c9e37c64992e256f25bad4d2b8f3585169dff9..0f37f838fd342301c8ebc14f74ba3ea925083df6 100644
--- a/library/startup.php
+++ b/library/startup.php
@@ -58,7 +58,7 @@ function defineConstant($name, $value) {
 
 function setupConstants() {
 	defineConstant('BOKEH_MAJOR_VERSION','6.59');
-	defineConstant('BOKEH_RELEASE_NUMBER', BOKEH_MAJOR_VERSION . '.2');
+	defineConstant('BOKEH_RELEASE_NUMBER', BOKEH_MAJOR_VERSION . '.3');
 
 	defineConstant('ROOT_PATH',  realpath(dirname(__FILE__).'/..').'/');
 
@@ -355,4 +355,4 @@ function setupRestful() {
 	Restful_Bootstrap::asPlugin(Zend_Controller_Front::getInstance(),
 															'rest',
 															Zend_Controller_Action_HelperBroker::getExistingHelper('ViewRenderer'));
-}
\ No newline at end of file
+}
diff --git a/tests/application/modules/admin/controllers/ModoControllerTest.php b/tests/application/modules/admin/controllers/ModoControllerTest.php
index 13110c12a1a3134169dd725f0594daaca271e7f1..03e5c3bc71cbc27be9c9de22f21cd175617daf61 100644
--- a/tests/application/modules/admin/controllers/ModoControllerTest.php
+++ b/tests/application/modules/admin/controllers/ModoControllerTest.php
@@ -463,18 +463,24 @@ class ModoControllerDeleteAvisCmsTest extends Admin_AbstractControllerTestCase {
 	public function setUp() {
 		parent::setUp();
 
-		Class_Avis::getLoader()
-			->newInstanceWithId(34)
-			->setAuteur(Class_Users::getLoader()
-				          ->newInstanceWithId(98)
-				          ->setPseudo('Mimi'))
-			->setDateAvis('2012-02-05')
-			->setNote(4)
-			->setEntete('Hmmm')
-			->setAvis('ça a l\'air bon')
-			->beWrittenByAbonne()
-      ->setIdCms(28);
+		$this->fixture('Class_Article', ['id' => 28,
+																		 'titre' => 'test',
+																		 'contenu' => 'test']);
 
+		$this->fixture('Class_Avis',
+									 ['id' => 34,
+										'auteur' => $this->fixture('Class_Users',
+																							 ['id' => 98,
+																								'login' => 'mimi',
+																								'password' => 'secret',
+																								'pseudo' => 'mimi']),
+										'date_avis' => '2012-02-05',
+										'note' => 4,
+										'entete' => 'Hmmmm',
+										'avis' => 'ça a l\'air bon',
+										'id_cms' => 28])
+				 ->beWrittenByAbonne()
+				 ->assertSave();
 
 	  Storm_Test_ObjectWrapper::onLoaderOfModel('Class_Avis')
 			->whenCalled('delete')
diff --git a/tests/application/modules/opac/controllers/AbonneControllerCmsAvisTest.php b/tests/application/modules/opac/controllers/AbonneControllerCmsAvisTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..40647670994b4d6fce3435a0d326fb3c75fa8684
--- /dev/null
+++ b/tests/application/modules/opac/controllers/AbonneControllerCmsAvisTest.php
@@ -0,0 +1,266 @@
+<?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
+ */
+
+abstract class AbonneControllerCmsAvisTestCase extends AbstractControllerTestCase {
+	public function setUp() {
+		parent::setUp();
+
+		Storm_Model_Loader::defaultToVolatile();
+		$this->fixture('Class_Article', ['id' => 1,
+																		 'titre' => 'Je suis Charlie',
+																		 'contenu' => 'C\'est de la balle d\'être Charlie',
+																		 'avis' => 1]);
+
+	}
+
+
+	public function tearDown() {
+		Storm_Model_Loader::defaultToDb();
+		parent::tearDown();
+	}
+}
+
+
+
+
+class AbonneControllerCmsAvisViewArticleWithoutCommentTest extends AbonneControllerCmsAvisTestCase {
+	public function setUp() {
+		parent::setUp();
+
+		$this->dispatch('/cms/articleview/id/1', true);
+	}
+
+
+	/** @test */
+	public function articleJeSuisCharlieShouldHaveLinkToAddComment() {
+		$this->assertXPathContentContains('//a[@href = "/abonne/cmsavis/id/1"][@data-popup="true"]',
+																			'Donner ou modifier votre avis');
+	}
+
+
+	/** @test */
+	public function articleWithoutCommentShouldNotHaveLinkToAccessLibrariansComments() {
+		$this->assertNotXPathContentContains('//a[contains(@onclick, "showAvis(1")]',
+																				 'Avis de bibliothécaires');
+	}
+
+
+	/** @test */
+	public function articleWithoutCommentShouldNotHaveLinkToAccessBorrowersComments() {
+		$this->assertNotXPathContentContains('//a[contains(@onclick, "showAvis(1")]',
+																				 'Avis de lecteurs du portail');
+	}
+}
+
+
+
+class AbonneControllerCmsAvisPostActionTest extends AbonneControllerCmsAvisTestCase {
+	public function setUp() {
+		parent::setUp();
+
+		Class_AdminVar::newInstanceWithId('MODO_AVIS_BIBLIO', ['valeur' => 0]);
+		Class_AdminVar::newInstanceWithId('MODO_AVIS', ['valeur' => 0]);
+
+		Class_Avis::setTimeSource(new TimeSourceForTest('2015-01-15 17:18:35'));
+
+		$this->postDispatch('/abonne/cmsavis/id/1',
+												['avisSignature' => 'toto',
+												 'avisEntete' => 'Vive les dessins',
+												 'avisTexte' => 'A vos jolis crayons !',
+												 'avisNote' => 3]);
+	}
+
+
+	/** @test */
+	public function responseShouldRedirectToArticle() {
+		$this->assertRedirectTo('/opac/cms/articleview/id/1', $this->getResponseLocation());
+	}
+
+
+	/** @test */
+	public function createdAvisEnTeteShouldBeViveLesDessins() {
+		$this->assertEquals('Vive les dessins', Class_Avis::find(1)->getEntete());
+
+	}
+
+
+	/** @test */
+	public function createdAvisContentShouldBeAVosCrayons() {
+		$this->assertEquals('A vos jolis crayons !', Class_Avis::find(1)->getAvis());
+	}
+
+
+	/** @test */
+	public function createdAvisNoteShouldBeThree() {
+		$this->assertEquals(3, Class_Avis::find(1)->getNote());
+	}
+
+	/** @test */
+	public function currentUsedPseudoShouldBeToto() {
+		$this->assertEquals('toto', Class_Users::getIdentity()->getPseudo());
+	}
+
+	/** @test */
+	public function dateAvisShouldBeNow() {
+		$this->assertEquals('2015-01-15 17:18:35', Class_Avis::find(1)->getDateAvis());
+	}
+
+
+	/** @test */
+	public function createdAvisModerationShouldBeOK() {
+		$this->assertTrue(Class_Avis::find(1)->isModerationOK());
+	}
+
+
+	/** @test */
+	public function rankNoteShouldBeThree() {
+		$this->assertEquals(3, Class_Avis::find(1)->getArticle()->getRank()->getBibNote());
+	}
+
+
+	/** @test */
+	public function userIdShouldBe666() {
+		$this->assertEquals(666, Class_Avis::find(1)->getIdUser());
+	}
+}
+
+
+
+
+
+class AbonneControllerCmsAvisPostWithErrorsActionTest extends AbonneControllerCmsAvisTestCase {
+	public function setUp() {
+		parent::setUp();
+
+		$this->postDispatch('/abonne/cmsavis/id/1',
+												['avisSignature' => 'toto',
+												 'avisEntete' => 'Vive les dessins',
+												 'avisTexte' => '',
+												 'avisNote' => 3]);
+	}
+
+
+	/** @test */
+	public function pageShouldContainsContentTooShort() {
+		$this->assertXPathContentContains('//p[@class="error"]',
+																			'doit avoir une longueur comprise entre');
+	}
+}
+
+
+
+
+abstract class AbonneControllerCmsAvisViewArticleWithCommentTestCase extends AbonneControllerCmsAvisTestCase {
+	public function setUp() {
+		parent::setUp();
+
+		ZendAfi_Auth::getInstance()
+			->logUser(
+								$this->fixture('Class_Users' ,
+															 ['id' => 112,
+																'login' => 'max',
+																'password' => 'maxLaMenace']));
+
+		$this->fixture('Class_CmsRank', ['id' => 1,
+																		 'abon_nombre_avis' => 1,
+																		 'abon_note' => '4.0',
+																		 'bib_nombre_avis' => 0,
+																		 'bib_note' => '0.0']);
+
+		$this->fixture('Class_Avis' , ['id' => 7,
+																	 'id_user' => 112,
+																	 'id_cms' => '1',
+																	 'entete' => 'Pas mal !',
+																	 'avis' => 'J\'aime cet article',
+																	 'note' => 4,
+																	 'status' => 1]);
+	}
+}
+
+
+
+
+class AbonneControllerCmsAvisEditExistingTest extends AbonneControllerCmsAvisViewArticleWithCommentTestCase {
+	public function setUp() {
+		parent::setUp();
+
+		Class_AdminVar::newInstanceWithId('MODO_AVIS_BIBLIO', ['valeur' => 0]);
+		Class_AdminVar::newInstanceWithId('MODO_AVIS', ['valeur' => 0]);
+
+		$this->dispatch('/abonne/cmsavis/id/1', true);
+	}
+
+	/** @test */
+	public function inputAvisEnteteShouldContainsPasMal() {
+		$this->assertXPath('//input[@name="avisEntete"][@value="Pas mal !"]');
+	}
+
+
+	/** @test */
+	public function avisContentShouldBeJaimeCetArticle() {
+		$this->assertXPathContentContains('//textarea[@name="avisTexte"]',
+																			'J\'aime cet article');
+	}
+
+
+	/** @test */
+	public function avisSignatureShouldBeMax() {
+		$this->assertXPath('//input[@name="avisSignature"][@value="max"]');
+	}
+
+
+	/** @test */
+	public function selectedNoteShouldBeFour() {
+		$this->assertXPath('//select[@name="avisNote"]/option[@selected="1"][@value="4"]');
+	}
+}
+
+
+
+
+class AbonneControllerCmsAvisViewArticleWithCommentTest extends AbonneControllerCmsAvisViewArticleWithCommentTestCase {
+	public function setUp() {
+		parent::setUp();
+		$this->dispatch('/cms/articleview/id/1', true);
+	}
+
+
+	/** @test */
+	public function articleJeSuisCharlieShouldHaveLinkToAccessBorrowersComments() {
+		$this->assertXPathContentContains('//a[contains(@onclick, "showAvis(1")]', 'Avis de lecteurs du portail', $this->_response->getBody());
+	}
+
+
+	/** @test */
+	public function articleJeSuisCharlieShouldHaveOneBorrowersComments() {
+		$this->assertXPathContentContains('//div[@id="avis_1"]/ul[@class="notice_info"]/li[1]', "(1 évaluation)");
+	}
+
+
+	/** @test */
+	public function articleJeSuisCharlieShouldHaveFourStarsImage() {
+		$this->assertXPath('//div[@id="avis_1"]/ul[@class="notice_info"]/li[1]/img[contains(@src, "stars-4.gif")]');
+	}
+}
+
+
+
+?>
\ 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 e600010a60b9ca52f16f1e9cbc251745fb8c8c73..18de3486c7a4cde599d619365436c8e9df43557a 100644
--- a/tests/application/modules/opac/controllers/NoticeAjaxControllerTest.php
+++ b/tests/application/modules/opac/controllers/NoticeAjaxControllerTest.php
@@ -1574,6 +1574,8 @@ abstract class NoticeAjaxControllerLocalisationTestCase extends AbstractControll
 
 		Class_Exemplaire::beVolatile();
 		$file_system = Storm_Test_ObjectWrapper::mock()
+			->whenCalled('unlink')
+			->answers(true)
 			->whenCalled('file_exists')
 			->answers(true)
 			->whenCalled('getimagesize')
@@ -1630,6 +1632,9 @@ class NoticeAjaxControllerNoLocalisationTest extends NoticeAjaxControllerLocalis
 class NoticeAjaxControllerNoLocaltionForExemplaireTest extends NoticeAjaxControllerLocalisationTestCase {
 	public function setUp() {
 		parent::setUp();
+
+		Class_Localisation::deleteBy([]);
+
 		$this->fixture('Class_Exemplaire',
 									 ['id' => 1,
 										'id_bib' => 1,
diff --git a/tests/library/Class/MultiUploadTest.php b/tests/library/Class/MultiUploadTest.php
index 0262fe00f8e2afa1271b5abc98254d3f1be16b24..c3eb1ca8050ee0abcbba81dcd49f251943f13826 100644
--- a/tests/library/Class/MultiUploadTest.php
+++ b/tests/library/Class/MultiUploadTest.php
@@ -28,6 +28,7 @@ abstract class MultiUploadTestCase extends PHPUnit_Framework_TestCase {
 	protected function setUp() {
 		parent::setUp();
 		$this->_request = new Zend_Controller_Request_Http();
+		$this->_request->setParam('qqfile', 'foo');
 		$this->_tmpBasePath = realpath(sys_get_temp_dir()) . '/testAlbum';
 	}
 
@@ -36,25 +37,6 @@ abstract class MultiUploadTestCase extends PHPUnit_Framework_TestCase {
 
 
 
-class MultiUploadInitializationTest extends MultiUploadTestCase {
-	/** @test */
-	public function withIncompatibleSettingsShouldHaveError() {
-		$upload = Class_MultiUpload::newInstanceWith($this->_request)
-								->setSettingsReader(
-									Storm_Test_ObjectWrapper::on(new MultiUploadSettingReader())
-										->whenCalled('get')->with('post_max_size')
-										->answers('1K')->getWrapper()
-										->whenCalled('get')->with('upload_max_filesize')
-										->answers('1K')->getWrapper()
-								);
-
-		$this->assertFalse($upload->handleUpload('', ''));
-		$this->assertRegExp('/monter le post/', $upload->getError());
-	}
-}
-
-
-
 class MultiUploadXHRTest extends MultiUploadTestCase {
 	/** @var Class_MultiUpload */
 	protected $_upload;
@@ -122,7 +104,7 @@ class MultiUploadXHRTest extends MultiUploadTestCase {
 												->whenCalled('getHandlerFor')
 												->answers(
 													Storm_Test_ObjectWrapper::on(new Class_MultiUpload_Handler(null))
-														->whenCalled('getSize')->answers(100 * 1024 * 1024)
+														->whenCalled('getSize')->answers(600 * 1024 * 1024)
 														->getWrapper()
 												)
 												->getWrapper();
@@ -130,7 +112,7 @@ class MultiUploadXHRTest extends MultiUploadTestCase {
 		$this->_upload->setHandlerFactory($factoryWrapper);
 
 		$this->assertFalse($this->_upload->handleUpload('', ''));
-		$this->assertEquals('Fichier trop volumineux', $this->_upload->getError());
+		$this->assertContains('Fichier trop volumineux. Paramétrage du serveur : monter le post_max_size et le upload_max_filesize', $this->_upload->getError());
 	}
 
 
diff --git a/tests/library/ZendAfi/View/Helper/CkEditorTest.php b/tests/library/ZendAfi/View/Helper/CkEditorTest.php
index e63507be0e2354e959197f84e87c3f6aa14267ff..7f445b08b6aa0ab3c2bd3c51475decffc45e9a98 100644
--- a/tests/library/ZendAfi/View/Helper/CkEditorTest.php
+++ b/tests/library/ZendAfi/View/Helper/CkEditorTest.php
@@ -16,19 +16,19 @@
  *
  * 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 'ViewHelperTestCase.php';
 require_once 'ZendAfi/View/Helper/CkEditor.php';
 
 
 class CkEditorWithFormulaireEnabledTest extends ViewHelperTestCase {
-	
+
 		public function setUp() {
 			parent::setUp();
 			$this->_helper = new ZendAfi_View_Helper_CkEditor();
 			$this->_helper->setView(new ZendAfi_Controller_Action_Helper_View());
-			if (!defined('URL_CSS')) 
+			if (!defined('URL_CSS'))
 				define('URL_CSS','');
 			Class_AdminVar::newInstanceWithId('CMS_FORMULAIRES')->setValeur(1);
 			$this->_html=$this->_helper->ckeditor('','','');
@@ -45,12 +45,12 @@ class CkEditorWithFormulaireEnabledTest extends ViewHelperTestCase {
 
 
 class CkEditorWithFormulaireDisabledTest extends ViewHelperTestCase {
-	
+
 		public function setUp() {
 			parent::setUp();
 			$this->_helper = new ZendAfi_View_Helper_CkEditor();
 			$this->_helper->setView(new ZendAfi_Controller_Action_Helper_View());
-			if (!defined('URL_CSS')) 
+			if (!defined('URL_CSS'))
 				define('URL_CSS','');
 
 			Class_AdminVar::newInstanceWithId('CMS_FORMULAIRES')->setValeur(0);