diff --git a/.gitmodules b/.gitmodules
index 33629ff4e086fcdec5aebc53e1921d7ec6f43fba..00c9ab7233aec51314acd18e80da4bb7fe4ede6c 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,3 @@
 [submodule "library/storm"]
 	path = library/storm
-	url = http://git.afi-sa.fr/afi/storm.git
+	url = git@git.afi-sa.fr:afi/storm.git
diff --git a/.htaccess b/.htaccess
index 4cdb15b94936a33baf7b577982c65074b21b78d2..08872ab2457f411ae808abcf7e342be25651e77d 100644
--- a/.htaccess
+++ b/.htaccess
@@ -1,7 +1,6 @@
 RewriteEngine on
 RewriteCond %{REQUEST_URI} !/(xhprof_html|ckeditor)
-RewriteRule !(userfiles|public|tmp|temp)/.*\.(js|ico|txt|gif|jpg|jpeg|png|css|xml|swf|mov|pdf|doc|docx|woff|eot|svg|ttf|xls|wsdl|mp3|m4v|ogg|ogv|epub|html|xhtml|asmx)$ index.php [NC,NE]
-
+RewriteRule !(userfiles|public|tmp|temp|skins)/.*\.(js|ico|txt|gif|jpg|jpeg|png|css|xml|swf|mov|pdf|doc|docx|woff|eot|svg|ttf|xls|wsdl|mp3|m4v|ogg|ogv|epub|html|xhtml|asmx)$ index.php [NC,NE]
 
 
 AddType application/x-javascript .js
diff --git a/application/modules/admin/controllers/IndexController.php b/application/modules/admin/controllers/IndexController.php
index ccc4443205b779045ac9716867b75735ec5f1720..a8716ec14a2c609e283ec45302986470c6e2ae15 100644
--- a/application/modules/admin/controllers/IndexController.php
+++ b/application/modules/admin/controllers/IndexController.php
@@ -33,7 +33,6 @@ class Admin_IndexController extends Zend_Controller_Action {
 			$this->view->etat_site="Le site est en ligne";
 			$this->view->lien_site="Rendre le site indisponible";
 			$this->view->href_site="false";
-
 		} else {
 			$this->view->etat_site="Le site est indisponible";
 			$this->view->lien_site="Remettre le site en ligne";
@@ -49,30 +48,29 @@ class Admin_IndexController extends Zend_Controller_Action {
 		$this->view->user = Class_Users::getLoader()->getIdentity();
 	}
 
+
 	public function adminvarAction()	{
-		$existing_variables = Class_AdminVar::getLoader()->findAllBy(['order' => 'CLEF']);
-		$existing_clefs = array();
+		$existing_variables = Class_AdminVar::findAllBy(['order' => 'CLEF']);
+		$existing_clefs = [];
 		foreach ($existing_variables as $var)
 			$existing_clefs[] = $var->getId();
 
 		// creer les variables manquantes
-		foreach (Class_AdminVar::getKnownVars() as $name) {
-			if (!in_array($name, $existing_clefs)) {
+		foreach (Class_AdminVar::getKnownVarsKeys() as $name)
+			if (!in_array($name, $existing_clefs))
 				$existing_variables[] = Class_AdminVar::set($name, '');
-			}
-		}
-		
+
+		xdebug_break();
 		$this->view->titre = 'Gestion des variables';
 		$this->view->vars = $existing_variables;
-
 	}
 
 
 
 	public function shouldEncodeVar($cle) {
 		return in_array($cle->getId(), 
-										array("REGISTER_OK", "RESA_CONDITION","TEXTE_MAIL_RESA",
-													"USER_VALIDATED", "USER_NON_VALIDATED"));
+										['REGISTER_OK', 'RESA_CONDITION', 'TEXTE_MAIL_RESA',
+										 'USER_VALIDATED', 'USER_NON_VALIDATED']);
 	}
 
 
@@ -98,14 +96,13 @@ class Admin_IndexController extends Zend_Controller_Action {
 			$this->_redirect('admin/index/adminvar');
 		}
 
-		if ($this->shouldEncodeVar($cle))
-			$this->view->var_valeur	= urldecode($cle->getValeur());
-		else
-			$this->view->var_valeur	= $cle->getValeur();
+		$this->view->var_valeur	= $this->shouldEncodeVar($cle) 
+			? urldecode($cle->getValeur())
+			: $cle->getValeur();
 
 		$this->view->var_cle		= $cle->getId();
-		$this->view->tuto				= $this->_getAdminVarHelpFor($cle->getId());
-		$this->view->titre			= 'Modifier la variable: '.$cle->getId();
+		$this->view->tuto				= Class_AdminVar::helpFor($cle->getId());
+		$this->view->titre			= 'Modifier la variable: ' . $cle->getId();
 	}
 
 
@@ -119,86 +116,14 @@ class Admin_IndexController extends Zend_Controller_Action {
 		$this->_redirect('admin');
 	}
 
+
 	public function clearcacheAction() {
 		Zend_Registry::get('cache')->clean(Zend_Cache::CLEANING_MODE_ALL);
 		$this->_redirect('admin/index/adminvar');
 	}
 
-	/**
-	 * @param string $name
-	 * @return string
-	 */
-	private function _getAdminVarHelpFor($name) {
-		$help = array(
-			'AVIS_MAX_SAISIE'           => 'Nombre de caractères maximum autorisé à saisir dans les avis.',
-			'AVIS_MIN_SAISIE'           => 'Nombre de caractères minimum autorisé à saisir dans les avis.',
-			'BLOG_MAX_NB_CARAC'         => "Nombre de caractères maximum à afficher dans le bloc critiques.",
-			'FACETTE_PCDM4_LIBELLE'			=> "Libellé affichage pour la PCDM4",
-			'FACETTE_DEWEY_LIBELLE'			=> "Libellé affichage pour la Dewey",
-			'NB_AFFICH_AVIS_PAR_AUTEUR' => "Nombre d'avis maximum à afficher par utilisateur.",
-			'CLEF_GOOGLE_MAP'           => 'Clef d\'activation pour le plan d\'accès google map. <a target="_blank" href="http://code.google.com/apis/maps/signup.html">Obtenir la clé google map</a>',
-			'MODO_AVIS'                 => 'Modération des avis des lecteurs.<br /> 0 = Affichage sans attente de validation<br /> 1 = Affichage seulement après validation.',
-			'MODO_AVIS_BIBLIO'          => 'Modération des avis des bibliothèquaires.<br />  0 = Affichage sans attente de validation<br /> 1 = Affichage seulement après validation.',
-			'AVIS_BIB_SEULEMENT'        => '0 = Les lecteurs peuvent donner leur avis. <br /> 1 = Seuls les bibliothèquaires peuvent donner leur avis',
-			'MODO_BLOG'                 => '0 = Ne requiert pas d\'identification pour saisir des  commentaires. <br /> 1 = Requiert l\'identification pour saisir des commentaires.',
-			'REGISTER_OK'               => 'Texte visible par l\'internaute après son inscription.',
-			'RESA_CONDITION'            => 'Texte visible après l\'envoi d\'e-mail de demande de réservation.',
-			'SITE_OK'                   => '0 = Site en maintenance. <br /> 1 = Site ouvert.',
-			'ID_BIBLIOSURF'             => 'Nom de la bibliothèque chez bibliosurf (en minuscules)',
-			'GOOGLE_ANALYTICS'          => 'Code Google Analytics',
-			'ID_READ_SPEAKER'           => 'Numéro de client Read Speaker <a target="_blank" href="http://webreader.readspeaker.com">http://webreader.readspeaker.com</a>',
-			'BLUGA_API_KEY'             => 'Clé API Bluga Webthumb <a target="_blank" href="http://webthumb.bluga.net/home">http://webthumb.bluga.net/home</a>',
-			'AIDE_FICHE_ABONNE'         => "Texte d'aide affiché dans la fiche abonné",
-			'INTERDIRE_ENREG_UTIL'      => "Supprime l'affichage du lien d'enregistrement dans les différents formulaires de connexion et interdit l'enregistrement d'utilisateurs",
-			'LANGUES'                   => "Liste des codes langue utilisées en plus du français séparées par des ;. Exemple: en;ro;es",
-			'WORKFLOW'									=> 'Activer ou désactiver la gestion des validations des articles<br />1 = Activé, Autre valeur = désactivé',
-			'BIBNUM'									  => 'Activer ou désactiver la bibliothèque numérique<br />1 = Activé, Autre valeur = désactivé',
-			'FORMATIONS'							  => 'Activer ou désactiver le module formation<br />1 = Activé, Autre valeur = désactivé',
-			'CACHE_ACTIF'               => implode(
-																			'<br/>',
-																			array(
-																				'Activer le cache des boîtes (meilleure performance mais mise à jour toutes les ' . ((int)Zend_Registry::get('cache')->getOption('lifetime')) / 60 . 'mn)',
-																				'0 = inactif',
-																				'1 = actif',
-																				sprintf(
-																					'<a href="%s" >Vider le cache</a>',
-																					$this->view->url(array('action' => 'clearcache'))
-																				)
-																			)
-																	 ),
-			'VODECLIC_KEY'              => 'Clé de sécurité Vodeclic',
-			'VODECLIC_ID'               => 'Identifiant partenaire Vodeclic',
-			'VODECLIC_BIB_ID'           => 'Identifiant code bibliothèque Vodeclic',
-			'OAI_SERVER'                => 'Activation du serveur OAI. 0 = inactif, 1 = actif',
-			'PACK_MOBILE'               => 'Activation des fonctions avancées du téléphone.  0 = inactif, 1 = actif',
-			'ARTE_VOD_LOGIN'            => 'Login ARTE VOD',
-			'ARTE_VOD_KEY'              => 'Clé ARTE VOD',
-			'ARTE_VOD_SSO_KEY'          => 'Clé ARTE VOD Single Sign-On',
-			'BABELTHEQUE_JS'            => 'URL du javascript Babelthèque à insérer dans l\'OPAC',
-			'MULTIMEDIA_KEY'            => 'Clé AFI-multimédia',
-			'CMS_FORMULAIRES'           => 'Activation des formulaires.  0 = inactif, 1 = actif',
-			'MENU_BOITE'                => 'Activation des boîtes dans les menus.  0 = inactif, 1 = actif',
-			'INTERDIRE_MODIF_FICHE_ABONNE'						=> 'Interdire la modification de la fiche abonne 0 = inactif, 1 = actif',
-			'CHAMPS_FICHE_UTILISATEUR'								=> 'Liste des champs que l\'utilisateur peux modifier. <br/>Ex: nom;prenom;pseudo;adresse;<br/>code_postal;ville;mail;is_contact_mail;<br/>telephone;is_contact_telephone;',
-			'URL_TYPO3'																=> 'Url d\'import d\un agenda TYPO3',
-			'AFFICHER_DISPONIBILITE_SUR_RECHERCHE'		=> 'Activation de la disponibilite dans le resultat de recherche.  0 = inactif, 1 = actif',
-			'NOM_DOMAINE'															=> 'Nom de domaine principal de l\'OPAC, ex: monopac.macommune.fr',
-			'WEBKIOSK_KEY'                            => 'Clé publique pour le cryptage des données Aesis Webkiosk',
-			'WEBKIOSK_RESERVATION_URL'                => 'URL d\'accès à l\'interface de réservation des postes Aesis Webkiosk',
-			'BOITE_PANIER_AUTO' => 'Ajouter automatiquement une boîte panier dans la division flottante.  0 = inactif, 1 = actif'
-			
-		);
-
-		if (!array_key_exists($name, $help)) {
-			return '';
-		}
-
-		return $help[$name];
-	}
-
 
 	public function heartbeatAction() {
 		$this->getHelper('ViewRenderer')->setNoRender();
 	}
-
 }
\ No newline at end of file
diff --git a/application/modules/opac/views/scripts/head.phtml b/application/modules/opac/views/scripts/head.phtml
index 9b1e83794d61c10c49039003904c34d1598c2414..d74d001a8e291ed1624108e08069af5bfcc167e4 100644
--- a/application/modules/opac/views/scripts/head.phtml
+++ b/application/modules/opac/views/scripts/head.phtml
@@ -1,133 +1,107 @@
-<!DOCTYPE html>
-<html lang="<?php echo $this->_translate()->getLocale() ?>">
-<head>
-	<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
-	<title><?php echo $this->titre ?></title>
-	<?php $current_profil = Class_Profil::getCurrentProfil(); ?>
-
-	<meta name="description" content="<?php echo $current_profil->getCommentaire();?>" />
-	<meta name="keywords" content="<?php echo $current_profil->getRefTags();?>" />
-	<meta content="all" name="robots" />
-	<meta content="10 days" name="revisit-after" />
-	<?php 
-	echo $current_profil->getStyleCss();
-  if ($current_profil->hasFavicon())
-		echo sprintf('<link rel="shortcut icon" href="%s"/>', $current_profil->getFavicon());
-
-$head_scripts = Class_ScriptLoader::newInstance()
-	->addOPACStyleSheet('global')
-	->addSkinStyleSheets(array('global', 'erreur', 'dialog', 'popup', 'nuage_tags'))
-	->addAdminStyleSheet('subModal')
-	->addOPACStyleSheet('print', array('media' => 'print'))
-	->addInlineScript(sprintf('var baseUrl="%s"; var imagesUrl="%s"; var cssUrl="%s"; var userFilesUrl="%s"',
-														BASE_URL, URL_IMG, URL_CSS, USERFILESURL))
-	->loadJQuery()
-	->loadJQueryUI()
-	->addAdminScripts(['onload_utils',
-										 'global', 
-										 'toolbar', 
-										 'common',
-										 'subModal'])			 
-	->addOPACScripts(['abonne', 
-										'menu', 
-										'bib', 
-										'avis', 
-										'recherche', 
-										'jquery.placeholder.min', 
-										'accessibility',
-										'subModal',
-										'division-five',
-										'reload_module'])
-	->addJQueryReady('
-       $("input").placeholder();
-       setupAnchorsTarget();
-       autoHideShowConfigurationModule();
-       initializeNoticeMurAnimation();
-       initializeImgHover();
-       initializePopups();
-       initializeDivisionFive();
-       initializeReseauxSociaux();')
-	->addJQueryBackEnd(sprintf('$("#select_clef_profil").parent().prepend(\'%s\')',
-													 $this->tagImg(URL_ADMIN_IMG.'ico/lock.png',
-																				 ['alt' => $this->_("Afficher les outils d\'administration"),
-																					'title' => $this->_("Afficher les outils d\'administration"),
-																					'onclick' => 'toggleMenuAdmin($(this));',
-																					'style'=>'vertical-align:middle;padding-left:10px;'])))
-->showNotifications();
-
-if (file_exists(PATH_SKIN.'/css/bib.css'))
-	$head_scripts->addSkinStyleSheet('bib');
-
-if ($this->header_js)
-	$head_scripts->addJQueryReady('$.getScript("'.$this->header_js.'")');
-
-if (Class_Users::isCurrentUserAdmin()) {
-	$head_scripts
-		->loadAmber(true)
-		->addAmberPackage('AFI-OPAC');
-
-	if ($this->header_css)
-		$this->header_css .= '?cache='.md5(time());
-}
-
-
-if ($this->header_css && $current_profil->getUseParentCss() && !$current_profil->hasPageCss()) 
-	$head_scripts->addStyleSheet($this->header_css, ['id' => 'profil_css']);
-
-if ($this->header_css && $current_profil->getUseParentCss() && $current_profil->hasPageCss()) 
-	$head_scripts->addStyleSheet($this->header_css);
-
-if($current_profil->hasPageCss())
-	$head_scripts->addStyleSheet($current_profil->getPageCss(), ['id' => 'profil_css']);
-
-if ($this->accessibilite_on) {  //Feuilles de styles pour les déficiences visuelles
-	$head_scripts
-		->addOPACStyleSheet('blanc_sur_noir', ['rel' => 'alternate stylesheet',
-																					 'title' => $this->_('Blanc sur noir'),
-                                           'data-name' => 'style_blanc_sur_noir'])
-
-		->addOPACStyleSheet('noir_sur_blanc', ['rel' => 'alternate stylesheet',	
-																				   'title' => $this->_('Noir sur blanc'),
-                                           'data-name' => 'style_noir_sur_blanc'])
- 
-		->addOPACStyleSheet('bleu_sur_jaune', ['rel' => 'alternate stylesheet',
-																					 'title' => $this->_('Bleu sur jaune'),
-                                           'data-name' => 'style_bleu_sur_jaune'])
-
-		->cssAddLine($this->_('<link rel="alternate stylesheet" type="text/css" href="#" title="%s" data-name="style_defaut">', 
-													'Style par défaut'))
-
-		->cssAddLine('<link id="accessibility_stylesheet" rel="stylesheet" type="text/css" href="#" title="CSS accessibilité">')
-		->addAdminScript('jquery.cookie')
-		->addJQueryReady('initAccessibilityOptions();');
-}
-
-if ($read_speaker = Class_AdminVar::get('ID_READ_SPEAKER'))
-	$head_scripts
-		->addJQueryReady(sprintf('$.getScript("http://wr.readspeaker.com/webreader/webreader.js.php?cid=%s")',
-														 $read_speaker));
-
-$script_loader = Class_ScriptLoader::getInstance();
-
-echo $this->partial('skin_head.phtml', ['profil' => $this->profil]);
-
-$head_scripts->renderStyleSheets();
-$script_loader->renderStyleSheets();
-
-foreach(array(7,8) as $ie) {
-	if (file_exists(PATH_SKIN.'/css/ie'.$ie.'.css')) {
-		echo sprintf('<!--[if IE %d]><link rel="stylesheet" type="text/css" href="%sie%d.css" title="Feuille de style IE7"/><![endif]-->',
-								 $ie, URL_CSS, $ie);
-	}
-
-	$ie_css = $current_profil->getHeaderCssIE($ie);
-	if (file_exists(USERFILESPATH.'/css/'.$ie_css ))
-		echo sprintf('<!--[if IE %d]><link rel="stylesheet" type="text/css" href="%s/css/%s" title="Feuille de style IE8"/><![endif]-->',
-								 $ie, USERFILESURL, $ie_css);
-}
-
-
-$head_scripts->renderJavaScripts();
-$script_loader->renderJavaScripts();
-?>
-</head>
+<!DOCTYPE html>
+<html lang="<?php echo $this->_translate()->getLocale() ?>">
+<head>
+	<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
+	<title><?php echo $this->titre ?></title>
+	<?php $current_profil = Class_Profil::getCurrentProfil(); ?>
+
+	<meta name="description" content="<?php echo $current_profil->getCommentaire();?>" />
+	<meta name="keywords" content="<?php echo $current_profil->getRefTags();?>" />
+	<meta content="all" name="robots" />
+	<meta content="10 days" name="revisit-after" />
+	<?php
+	echo $current_profil->getStyleCss();
+  if ($current_profil->hasFavicon())
+		echo sprintf('<link rel="shortcut icon" href="%s"/>', $current_profil->getFavicon());
+
+	$head_scripts = Class_ScriptLoader::newInstance()
+		->addOPACStyleSheet('global')
+		->addSkinStyleSheets(['global', 'erreur', 'dialog', 'popup', 'nuage_tags', 'bib'])
+		->addAdminStyleSheet('subModal')
+		->addOPACStyleSheet('print', ['media' => 'print'])
+		->addInlineScript(sprintf('var baseUrl="%s"; var imagesUrl="%s"; var cssUrl="%s"; var userFilesUrl="%s"',
+															BASE_URL, URL_IMG, URL_CSS, USERFILESURL))
+		->loadJQuery()
+		->loadJQueryUI()
+		->addAdminScripts(['onload_utils', 'global', 'toolbar', 'common', 'subModal'])
+		->addOPACScripts(['abonne', 'menu', 'bib', 'avis', 'recherche',
+											'jquery.placeholder.min', 'accessibility', 'subModal',
+											'division-five', 'reload_module'])
+		->addJQueryReady('
+       $("input").placeholder();
+       setupAnchorsTarget();
+       autoHideShowConfigurationModule();
+       initializeNoticeMurAnimation();
+       initializeImgHover();
+       initializePopups();
+       initializeDivisionFive();
+       initializeReseauxSociaux();')
+		->addJQueryBackEnd(sprintf('$("#select_clef_profil").parent().prepend(\'%s\')',
+															 $this->tagImg(URL_ADMIN_IMG.'ico/lock.png',
+																						 ['alt' => $this->_("Afficher les outils d\'administration"),
+																							'title' => $this->_("Afficher les outils d\'administration"),
+																							'onclick' => 'toggleMenuAdmin($(this));',
+																							'style' => 'vertical-align:middle;padding-left:10px;'])))
+		->showNotifications();
+
+	if ($this->header_js)
+		$head_scripts->addJQueryReady('$.getScript("' . $this->header_js . '")');
+
+	if (Class_Users::isCurrentUserAdmin()) {
+		$head_scripts->loadAmber(true)
+								 ->addAmberPackage('AFI-OPAC');
+
+		if ($this->header_css)
+			$this->header_css .= '?cache='.md5(time());
+	}
+
+
+	if ($this->header_css && $current_profil->getUseParentCss() && !$current_profil->hasPageCss()) 
+		$head_scripts->addStyleSheet($this->header_css, ['id' => 'profil_css']);
+
+	if ($this->header_css && $current_profil->getUseParentCss() && $current_profil->hasPageCss()) 
+		$head_scripts->addStyleSheet($this->header_css);
+
+	if($current_profil->hasPageCss())
+		$head_scripts->addStyleSheet($current_profil->getPageCss(), ['id' => 'profil_css']);
+
+	if ($this->accessibilite_on) {
+		//Feuilles de styles pour les déficiences visuelles
+		$head_scripts
+			->addOPACStyleSheet('blanc_sur_noir', ['rel' => 'alternate stylesheet',
+																						 'title' => $this->_('Blanc sur noir'),
+																						 'data-name' => 'style_blanc_sur_noir'])
+			->addOPACStyleSheet('noir_sur_blanc', ['rel' => 'alternate stylesheet',
+																						 'title' => $this->_('Noir sur blanc'),
+																						 'data-name' => 'style_noir_sur_blanc'])
+			->addOPACStyleSheet('bleu_sur_jaune', ['rel' => 'alternate stylesheet',
+																						 'title' => $this->_('Bleu sur jaune'),
+																						 'data-name' => 'style_bleu_sur_jaune'])
+			->cssAddLine($this->_('<link rel="alternate stylesheet" type="text/css" href="#" title="%s" data-name="style_defaut">', 
+														'Style par défaut'))
+
+			->cssAddLine('<link id="accessibility_stylesheet" rel="stylesheet" type="text/css" href="#" title="CSS accessibilité">')
+			->addAdminScript('jquery.cookie')
+			->addJQueryReady('initAccessibilityOptions();');
+	}
+
+	if ($read_speaker = Class_AdminVar::get('ID_READ_SPEAKER'))
+		$head_scripts
+			->addJQueryReady(sprintf('$.getScript("http://wr.readspeaker.com/webreader/webreader.js.php?cid=%s")',
+															 $read_speaker));
+
+	echo $this->partial('skin_head.phtml', ['profil' => $this->profil]);
+
+	$script_loader = Class_ScriptLoader::getInstance();
+	foreach([7,8] as $ie)
+		$script_loader->addSkinStyleSheet('ie' . $ie, ['ie_version' => $ie])
+									->addUserFilesStylSheet($current_profil->getHeaderCssIE($ie), 
+																					['ie_version' => $ie]);
+
+	$head_scripts->renderStyleSheets();
+	$script_loader->renderStyleSheets();
+	
+	$head_scripts->renderJavaScripts();
+	$script_loader->renderJavaScripts();
+?>
+</head>
diff --git a/application/modules/opac/views/scripts/iframe.phtml b/application/modules/opac/views/scripts/iframe.phtml
index a81c10b6c4e8d8e6faf4c7f621cff8e74de19642..45f5fc6b3ca74b765c4591591dc1d22cc2103b3a 100644
--- a/application/modules/opac/views/scripts/iframe.phtml
+++ b/application/modules/opac/views/scripts/iframe.phtml
@@ -1,28 +1,25 @@
-<?php 
-$script_loader = Class_ScriptLoader::getInstance()
-	->addAdminScript('onload_utils')
-	->addInlineScript(sprintf('var imagesUrl = "%s";', URL_IMG));
-
-if (file_exists(PATH_SKIN.'/css/iframe.css'))
-	$script_loader->addSkinStyleSheet('iframe');
-
-ob_start(); 
-echo $this->render($this->actionScript);
-$html_contents = ob_get_contents();
-ob_end_clean();
-?>
-
-<!DOCTYPE html>
-<html lang="<?php echo $this->_translate()->getLocale() ?>">
-<head>
-	<title></title>
-	<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
-	<?php echo $script_loader->html();	?>
-	<style>#ZFDebug {display:none}</style>
-</head>
-
-<body style="margin:0px;padding:0px;background-color:transparent;background-image:none" class="auto_resize iframe">
-	<?php echo $html_contents; ?>
-</body>
-
-</html>
+<?php
+$script_loader = Class_ScriptLoader::getInstance()
+	->addAdminScript('onload_utils')
+	->addInlineScript(sprintf('var imagesUrl = "%s";', URL_IMG))
+	->addSkinStyleSheet('iframe');
+
+ob_start();
+echo $this->render($this->actionScript);
+$html_contents = ob_get_contents();
+ob_end_clean();
+?>
+
+<!DOCTYPE html>
+<html lang="<?php echo $this->_translate()->getLocale() ?>">
+<head>
+	<title></title>
+	<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
+	<?php echo $script_loader->html();	?>
+	<style>#ZFDebug {display:none}</style>
+</head>
+
+<body style="margin:0px;padding:0px;background-color:transparent;background-image:none" class="auto_resize iframe">
+	<?php echo $html_contents; ?>
+</body>
+</html>
diff --git a/library/Class/AdminVar.php b/library/Class/AdminVar.php
index fb8c180f0032e7fae7a6409246c4011cfac3c987..bf976f6455c353ed7ff2734315d09c4483128b4c 100644
--- a/library/Class/AdminVar.php
+++ b/library/Class/AdminVar.php
@@ -18,91 +18,13 @@
  * 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 
  */
-//////////////////////////////////////////////////////////////////////////////////////////
-// OPAC3 - Variables globales admin
-//////////////////////////////////////////////////////////////////////////////////////////
 
 class Class_AdminVar extends Storm_Model_Abstract {
 	protected $_table_name = 'bib_admin_var';
 	protected $_table_primary = 'CLEF';
 
 	/** @var array */
-	protected static $_knownVars = array(
-		'AVIS_MAX_SAISIE',
-		'AVIS_MIN_SAISIE',
-		'BLOG_MAX_NB_CARAC',
-		'NB_AFFICH_AVIS_PAR_AUTEUR',
-		'CLEF_GOOGLE_MAP',
-		'MODO_AVIS',
-		'MODO_AVIS_BIBLIO',
-		'AVIS_BIB_SEULEMENT',
-		'MODO_BLOG',
-		'REGISTER_OK',
-		'RESA_CONDITION',
-		'SITE_OK',
-		'ID_BIBLIOSURF',
-		'GOOGLE_ANALYTICS',
-		'ID_READ_SPEAKER',
-		'BLUGA_API_KEY',
-		'AIDE_FICHE_ABONNE',
-		'INTERDIRE_ENREG_UTIL',
-		'LANGUES',
-		'CACHE_ACTIF',
-		'WORKFLOW',
-		'WORKFLOW_TEXT_MAIL_ARTICLE_PENDING',
-		'WORKFLOW_TEXT_MAIL_ARTICLE_REFUSED',
-		'BIBNUM',
-		'FORMATIONS',
-		'VODECLIC_KEY',
-		'VODECLIC_ID',
-		'VODECLIC_BIB_ID',
-		'CVS_BMKEY',
-		'CVS_BMID',
-		'CVS_SOURCENAME',
-		'CVS_SOURCEID',
-		'CVS_SOURCEKEY',
-		'CVS_SOURCEPASSWORD',
-		'CVS_LOGINTEST',
-		'NUMILOG_URL',
-		'NUMILOG_OAI_URL',
-		'NUMILOG_OAI_IDBIB',
-		'OAI_SERVER',
-		'PACK_MOBILE',
-		'ARTE_VOD_LOGIN',
-		'ARTE_VOD_KEY',
-		'ARTE_VOD_SSO_KEY',
-		'BABELTHEQUE_JS',
-		'MULTIMEDIA_KEY',
-		'WEBKIOSK_KEY',
-		'WEBKIOSK_RESERVATION_URL',
-		'CSS_EDITOR',
-		'CMS_FORMULAIRES',
-		'MENU_BOITE',
-		'INTERDIRE_MODIF_FICHE_ABONNE',
-		'ROOT_URL_ECOUTE',
-		'URL_TYPO3',
-		'CHAMPS_FICHE_UTILISATEUR',
-		'FACETTE_PCDM4_LIBELLE',
-		'FACETTE_DEWEY_LIBELLE',
-		'FACETTE_TYPE_DOC_LIBELLE',
-		'FACETTE_LANGUE_LIBELLE',
-		'FACETTE_GENRE_LIBELLE',
-		'FACETTE_SITE_LIBELLE',
-		'FACETTE_SECTION_LIBELLE',
-		'FACETTE_BIBLIOTHEQUE_LIBELLE',
-		'FACETTE_AUTEUR_LIBELLE',
-		'FACETTE_INTERET_LIBELLE',
-		'FACETTE_MATIERE_LIBELLE',
-		'FACETTE_TAG_LIBELLE',
-		'AFFICHER_DISPONIBILITE_SUR_RECHERCHE',
-		'NOM_DOMAINE',
-		'TOUTAPPRENDRE_BIB_ID',
-		'TOUTAPPRENDRE_KEY',
-		'MUSICME_URL',
-		'MUSICME_BIB_ID',
-		'DATE_LAST_FULL_INTEGRATION_USERS',
-		'BOITE_PANIER_AUTO'
-	);
+	protected static $_knownVars;
 
 
 	/**
@@ -110,7 +32,6 @@ class Class_AdminVar extends Storm_Model_Abstract {
 	 * @return mixed
 	 */
 	public static function get($name) {
-
 		$var = static::getLoader()->find($name);
 		if ($var == null)
 			return null;
@@ -139,10 +60,12 @@ class Class_AdminVar extends Storm_Model_Abstract {
 		return $instance;
 	}
 
+
 	public static function getDefaultLanguage() {
 		return 'fr';
 	}
 
+
 	public static function getLangues() {
 		if (!$langues_value = self::get('LANGUES'))
 			return array();
@@ -159,6 +82,7 @@ class Class_AdminVar extends Storm_Model_Abstract {
 		return array_diff(self::getLangues(), array(self::getDefaultLanguage()));
 	}
 
+
 	/**
 	 * @return bool
 	 */
@@ -216,7 +140,6 @@ class Class_AdminVar extends Storm_Model_Abstract {
 	}
 
 
-
 	/**
 	 * @return bool
 	 */
@@ -312,14 +235,115 @@ class Class_AdminVar extends Storm_Model_Abstract {
 	}
 
 
+	public static function getKnownVarsKeys() {
+		return array_keys(static::getKnownVars());
+	}
+
+
 	/**
 	 * @return array
 	 */
 	public static function getKnownVars() {
+		if (null === self::$_knownVars)
+			self::$_knownVars = [
+				'AVIS_MAX_SAISIE' => 'Nombre de caractères maximum autorisé à saisir dans les avis.',
+				'AVIS_MIN_SAISIE' => 'Nombre de caractères minimum autorisé à saisir dans les avis.',
+				'BLOG_MAX_NB_CARAC' => 'Nombre de caractères maximum à afficher dans le bloc critiques.',
+				'NB_AFFICH_AVIS_PAR_AUTEUR'  => 'Nombre d\'avis maximum à afficher par utilisateur.',
+				'CLEF_GOOGLE_MAP' => 'Clef d\'activation pour le plan d\'accès google map. <a target="_blank" href="http://code.google.com/apis/maps/signup.html">Obtenir la clé google map</a>',
+				'MODO_AVIS' => 'Modération des avis des lecteurs.<br /> 0 = Affichage sans attente de validation<br /> 1 = Affichage seulement après validation.',
+				'MODO_AVIS_BIBLIO' => 'Modération des avis des bibliothèquaires.<br />  0 = Affichage sans attente de validation<br /> 1 = Affichage seulement après validation.',
+				'AVIS_BIB_SEULEMENT' => '0 = Les lecteurs peuvent donner leur avis. <br /> 1 = Seuls les bibliothèquaires peuvent donner leur avis',
+				'MODO_BLOG' => '0 = Ne requiert pas d\'identification pour saisir des  commentaires. <br /> 1 = Requiert l\'identification pour saisir des commentaires.',
+				'REGISTER_OK' => 'Texte visible par l\'internaute après son inscription.',
+				'RESA_CONDITION' => 'Texte visible après l\'envoi d\'e-mail de demande de réservation.',
+				'SITE_OK' => '0 = Site en maintenance. <br /> 1 = Site ouvert.',
+				'ID_BIBLIOSURF' => 'Nom de la bibliothèque chez bibliosurf (en minuscules)',
+				'GOOGLE_ANALYTICS' => 'Code Google Analytics',
+				'ID_READ_SPEAKER' => 'Numéro de client Read Speaker <a target="_blank" href="http://webreader.readspeaker.com">http://webreader.readspeaker.com</a>',
+				'BLUGA_API_KEY' => 'Clé API Bluga Webthumb <a target="_blank" href="http://webthumb.bluga.net/home">http://webthumb.bluga.net/home</a>',
+				'AIDE_FICHE_ABONNE' => 'Texte d\'aide affiché dans la fiche abonné',
+				'INTERDIRE_ENREG_UTIL' => 'Supprime l\'affichage du lien d\'enregistrement dans les différents formulaires de connexion et interdit l\'enregistrement d\'utilisateurs',
+				'LANGUES' => 'Liste des codes langue utilisées en plus du français séparées par des ;. Exemple: en;ro;es',
+				'CACHE_ACTIF' => implode('<br/>',
+																 ['Activer le cache des boîtes (meilleure performance mais mise à jour toutes les ' . ((int)Zend_Registry::get('cache')->getOption('lifetime')) / 60 . 'mn)',
+																	'0 = inactif',
+																	'1 = actif',
+																	sprintf('<a href="%s" >Vider le cache</a>',
+																					Class_Url::assemble(['module' => 'admin',
+																															 'action' => 'clearcache']))]),
+				'WORKFLOW' => 'Activer ou désactiver la gestion des validations des articles<br />1 = Activé, Autre valeur = désactivé',
+				'WORKFLOW_TEXT_MAIL_ARTICLE_PENDING' => '',
+				'WORKFLOW_TEXT_MAIL_ARTICLE_REFUSED' => '',
+				'BIBNUM' => 'Activer ou désactiver la bibliothèque numérique<br />1 = Activé, Autre valeur = désactivé',
+				'FORMATIONS' => 'Activer ou désactiver le module formation<br />1 = Activé, Autre valeur = désactivé',
+				'VODECLIC_KEY' => 'Clé de sécurité Vodeclic',
+				'VODECLIC_ID' => 'Identifiant partenaire Vodeclic',
+				'VODECLIC_BIB_ID' => 'Identifiant code bibliothèque Vodeclic',
+				'CVS_BMKEY' => '',
+				'CVS_BMID' => '',
+				'CVS_SOURCENAME' => '',
+				'CVS_SOURCEID' => '',
+				'CVS_SOURCEKEY' => '',
+				'CVS_SOURCEPASSWORD' => '',
+				'CVS_LOGINTEST' => '',
+				'NUMILOG_URL' => '',
+				'NUMILOG_OAI_URL' => '',
+				'NUMILOG_OAI_IDBIB' => '',
+				'OAI_SERVER' => 'Activation du serveur OAI. 0 = inactif, 1 = actif',
+				'PACK_MOBILE' => 'Activation des fonctions avancées du téléphone.  0 = inactif, 1 = actif',
+				'ARTE_VOD_LOGIN' => 'Login ARTE VOD',
+				'ARTE_VOD_KEY' => 'Clé ARTE VOD',
+				'ARTE_VOD_SSO_KEY' => 'Clé ARTE VOD Single Sign-On',
+				'BABELTHEQUE_JS' => 'URL du javascript Babelthèque à insérer dans l\'OPAC',
+				'MULTIMEDIA_KEY' => 'Clé AFI-multimédia',
+				'WEBKIOSK_KEY' => 'Clé publique pour le cryptage des données Aesis Webkiosk',
+				'WEBKIOSK_RESERVATION_URL' => 'URL d\'accès à l\'interface de réservation des postes Aesis Webkiosk',
+				'CSS_EDITOR' => '',
+				'CMS_FORMULAIRES' => 'Activation des formulaires.  0 = inactif, 1 = actif',
+				'MENU_BOITE' => 'Activation des boîtes dans les menus.  0 = inactif, 1 = actif',
+				'INTERDIRE_MODIF_FICHE_ABONNE' => 'Interdire la modification de la fiche abonne 0 = inactif, 1 = actif',
+				'ROOT_URL_ECOUTE' => '',
+				'URL_TYPO3' => 'Url d\'import d\un agenda TYPO3',
+				'CHAMPS_FICHE_UTILISATEUR' => 'Liste des champs que l\'utilisateur peux modifier. <br/>Ex: nom;prenom;pseudo;adresse;<br/>code_postal;ville;mail;is_contact_mail;<br/>telephone;is_contact_telephone;',
+				'FACETTE_PCDM4_LIBELLE' => 'Libellé affichage pour la PCDM4',
+				'FACETTE_DEWEY_LIBELLE' => 'Libellé affichage pour la Dewey',
+				'FACETTE_TYPE_DOC_LIBELLE' => '',
+				'FACETTE_LANGUE_LIBELLE' => '',
+				'FACETTE_GENRE_LIBELLE' => '',
+				'FACETTE_SITE_LIBELLE' => '',
+				'FACETTE_SECTION_LIBELLE' => '',
+				'FACETTE_BIBLIOTHEQUE_LIBELLE' => '',
+				'FACETTE_AUTEUR_LIBELLE' => '',
+				'FACETTE_INTERET_LIBELLE' => '',
+				'FACETTE_MATIERE_LIBELLE' => '',
+				'FACETTE_TAG_LIBELLE' => '',
+				'AFFICHER_DISPONIBILITE_SUR_RECHERCHE' => 'Activation de la disponibilite dans le resultat de recherche.  0 = inactif, 1 = actif',
+				'NOM_DOMAINE' => 'Nom de domaine principal de l\'OPAC, ex: monopac.macommune.fr',
+				'TOUTAPPRENDRE_BIB_ID' => '',
+				'TOUTAPPRENDRE_KEY' => '',
+				'MUSICME_URL' => '',
+				'MUSICME_BIB_ID' => '',
+				'DATE_LAST_FULL_INTEGRATION_USERS' => '',
+				'BOITE_PANIER_AUTO' => 'Ajouter automatiquement une boîte panier dans la division flottante.  0 = inactif, 1 = actif',
+				'EXTRA_SKIN_PATH' => 'Chemin vers les skins personnalisées, relatif à ' . Class_Profil_Skin::EXTRA_PATH,
+				];
 		return self::$_knownVars;
 	}
 
 
+	/**
+	 * @param $name string
+	 * @return string
+	 */
+	public static function helpFor($name) {
+		if (!array_key_exists($name, static::getKnownVars()))
+			return '';
+		return static::getKnownVars()[$name];
+	}
+
+
+
 	/** @return bool */
 	public static function isCacheEnabled() {
 		return self::isModuleEnabled('CACHE_ACTIF');
@@ -380,13 +404,11 @@ class Class_AdminVar extends Storm_Model_Abstract {
 	}
 
 
-
 	public static function getChampsFicheUtilisateur() {
 		return array_filter(explode(';', trim(self::get('CHAMPS_FICHE_UTILISATEUR'))));
 	}
 
 
-
 	public static function getWorkflowTextMailArticlePending() {
 		if(!static::get('WORKFLOW_TEXT_MAIL_ARTICLE_PENDING'))
 			static::set('WORKFLOW_TEXT_MAIL_ARTICLE_PENDING',
diff --git a/library/Class/Notice.php b/library/Class/Notice.php
index ec70b173e67b18e9231154f6c7a04da01fbad5f8..5624737e8e331df50441689766d844cd4addcae2 100644
--- a/library/Class/Notice.php
+++ b/library/Class/Notice.php
@@ -1591,30 +1591,34 @@ class Class_Notice extends Storm_Model_Abstract {
 		if (isset($result[0]))	{
 			// black list
 			$trav = Class_CosmoVar::get('black_list_856');
-			if (trim($trav)) $black_list = explode(";", $trav);
+			$black_list = (trim($trav)) ? explode(';', $trav) : [];
 
 			// controle url pour target
 			$target = Class_CosmoVar::get('url_site');
 			$trav = explode('/', $target);
 			$ctrl_target = array_pop($trav);
-			if (!trim($ctrl_target)) $ctrl_target = array_pop($trav);
+			if (!trim($ctrl_target)) 
+				$ctrl_target = array_pop($trav);
 
 			// tableau des liens
-			foreach ($result as $item)
-			{
+			foreach ($result as $item) {
 				$controle = true;
-				if ($black_list)
-				{
-					foreach ($black_list as $mot)
-					{
-						if (stripos($item, $mot) !== false)
-						{ $controle = false; break; }
+				if ($black_list) {
+					foreach ($black_list as $mot) {
+						if (stripos($item, $mot) !== false) {
+							$controle = false; 
+							break; 
+						}
 					}
 				}
-				if ($controle == true)
-				{
-					if (substr(strtoupper($item), 0, 4) != "HTTP") $item = "http://" . $item;
-					if (strpos($item, $ctrl_target) === false) $target = 'target="_blank"'; else $target="";
+
+				if ($controle == true) {
+					if (substr(strtoupper($item), 0, 4) != 'HTTP') 
+						$item = 'http://' . $item;
+
+					$target = (strpos($item, $ctrl_target) === false) 
+						? 'target="_blank"' : ''; 
+
 					$lien[] = '<a href="' . trim($item) . '" ' . $target . ">" . trim($item) . '</a>';
 				}
 			}
diff --git a/library/Class/Profil.php b/library/Class/Profil.php
index 617c870627b4c65049cd20fd10bdb8ce455365f3..42556351ff58a02ad816816638840f49e5a5c439 100644
--- a/library/Class/Profil.php
+++ b/library/Class/Profil.php
@@ -89,6 +89,7 @@ class Class_Profil extends Storm_Model_Abstract {
 	protected $_has_parent_profil = null;
 	protected $_cfg_site_array;
 	protected $_should_forward_attributes = [];
+	protected $_skin;
 
 	/**
 	 * liste des bannieres
@@ -347,10 +348,19 @@ class Class_Profil extends Storm_Model_Abstract {
 	 * @return string
 	 */
 	public function getPathTheme()	{
-		$path='/public/opac/skins/'.$this->getSkin().'/';
-		if(!file_exists('.'.$path))
-			$path='/public/opac/skins/original/';
-		return $path;
+		return $this->_getSkin()->getPath();
+	}
+
+
+	protected function _getSkin() {
+		if (null === $this->_skin)
+			$this->_skin = Class_Profil_Skin::newFor($this);
+		return $this->_skin;
+	}
+
+
+	public function skinHasImage($img) {
+		return $this->_getSkin()->imageExists($img);
 	}
 
 
@@ -358,27 +368,25 @@ class Class_Profil extends Storm_Model_Abstract {
 	 * @return string
 	 */
 	public function getSkinImagePath($img) {
-		return '.'.$this->getPathTheme().'images/'.$img;
+		return $this->_getSkin()->getImagePath($img);
 	}
 
 
+	/** @return string */
 	public function getUrlSkinCss($file) {
-		
-		$url =  $this->getPathTheme().'css/'.$file.'.css';
-		if(!$this->getFileWriter()->fileExists('.'.$url)){
-			return null;
-		}
-		return BASE_URL.$url;
+		return $this->_getSkin()->getCssUrl($file);
 	}
 
 
 	/** @return string */
 	public function getUrlImage($img) {
-		$path_img = $this->getSkinImagePath($img);
-		$url_img = file_exists($path_img)
-			? URL_IMG.$img
-			: URL_SHARED_IMG.$img;
-		return $url_img;
+		return $this->_getSkin()->getImageUrl($img);
+	}
+
+
+	/** @return string */
+	public function getUrlAdminImage($img) {
+		return $this->_getSkin()->getAdminImageUrl($img);
 	}
 
 
@@ -386,9 +394,7 @@ class Class_Profil extends Storm_Model_Abstract {
 	 * @return string
 	 */
 	public function getPathTemplates() {
-		if($this->isTelephone())
-			return './public/opac/mobile/templates/';
-		return '.'.$this->getPathTheme().'templates/';
+		return $this->_getSkin()->getTemplatesPath();
 	}
 
 
@@ -427,12 +433,11 @@ class Class_Profil extends Storm_Model_Abstract {
 	 * @param int $id_module
 	 * @return string css path
 	 */
-	public function getHeaderCssIE($ieversion) {
+	public function getHeaderCssIE($version) {
 		$parts = pathinfo($this->getHeaderCss());
 		if (!isset($parts['dirname']))
 			return '';
-
-		return 'ie'.$ieversion.'_'.$parts['basename'];
+		return 'ie' . $version . '_' . $parts['basename'];
 	}
 
 
@@ -563,14 +568,21 @@ class Class_Profil extends Storm_Model_Abstract {
 	 * @return string
 	 */
 	public function getHeaderImg() {
-		$path = $this->_get('header_img');
-		if (!$path) {
-			if (file_exists(PATH_SKIN.'/images/site/banniere.png'))
-				$path = URL_IMG.'site/banniere.png';
-			else
-				$path = URL_IMG.'site/banniere.jpg';
-		}
-		return $path;
+		if ($path = $this->_get('header_img'))
+			return $path;
+		return $this->getSkinHeaderImg();
+	}
+
+
+	public function getSkinHeaderImg() {
+		$skin = $this->_getSkin();
+		if ($skin->imageExists('site/banniere.png'))
+			return $skin->getImageUrl('site/banniere.png');
+
+		if ($skin->imageExists('site/banniere.jpg'))
+			return $skin->getImageUrl('site/banniere.jpg');
+
+		return '';
 	}
 
 
@@ -929,17 +941,8 @@ class Class_Profil extends Storm_Model_Abstract {
 	/**
 	 * @return array
 	 */
-	function getAvailableSkins()	{
-		// Parcourir le dossier des skins opac
-		$scanlisting = scandir('./public/opac/skins');
-		$availableSkins = array();
-
-		foreach($scanlisting as $key => $value)
-			if (is_dir("./public/opac/skins/$value") and $value[0] != '.')
-				$availableSkins[$value] = $value;
-
-		return $availableSkins;
-
+	public function getAvailableSkins()	{
+		return $this->_getSkin()->getAvailables();
 	}
 
 
@@ -1571,7 +1574,8 @@ class Class_Profil extends Storm_Model_Abstract {
 
 
 	public function writeHeaderCss($data) {
-		if ((!$header_css = $this->getHeaderCssPath()) || !$this->getFileWriter()->fileExists($header_css)) 
+		if ((!$header_css = $this->getHeaderCssPath()) 
+				|| !$this->getFileWriter()->fileExists($header_css)) 
 			$header_css = USERFILESPATH.'/css/profil_'.$this->getId().'.css';
 
 		$this->writeCssPath($header_css, $data);		
@@ -1581,7 +1585,8 @@ class Class_Profil extends Storm_Model_Abstract {
 	
 	public function writePageCss($data) {
 		$page_css='';
-		if((!$page_css = $this->getPageCssPath()) || !$this->getFileWriter()->fileExists($page_css))
+		if((!$page_css = $this->getPageCssPath()) 
+			 || !$this->getFileWriter()->fileExists($page_css))
 			$page_css = USERFILESPATH.'/css/page_'.$this->getId().'.css';
 		
 		$this->writeCssPath($page_css, $data);		
@@ -1619,9 +1624,9 @@ class Class_Profil extends Storm_Model_Abstract {
 	}
 
 
-	public function getCssPath($css) {
+	protected function getCssPath($css) {
 		if ($this->_get($css))
-			return USERFILESPATH.str_replace(USERFILESURL, '/', $this->_get($css));
+			return USERFILESPATH . str_replace(USERFILESURL, '/', $this->_get($css));
 		return '';
 	}
 
@@ -1636,9 +1641,12 @@ class Class_Profil extends Storm_Model_Abstract {
 	}
 
 
-	public function getCss($css_filename) {
-		if ($this->getFileWriter()->fileExists($this->getCssPath($css_filename)))
-			return $this->_get($css_filename);
+	public function getCss($name) {
+		if (!$this->_get($name)) 
+			return '';
+
+		if ($this->getFileWriter()->fileExists($this->getCssPath($name)))
+			return $this->_get($name);
 		return '';
 	}
 
diff --git a/library/Class/Profil/Skin.php b/library/Class/Profil/Skin.php
new file mode 100644
index 0000000000000000000000000000000000000000..fc17237793e6e24f839c89495ef1407651595d4b
--- /dev/null
+++ b/library/Class/Profil/Skin.php
@@ -0,0 +1,140 @@
+<?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 Class_Profil_Skin {
+	const DEFAULT_SKIN = 'original';
+	const DEFAULT_PATH = '/public/opac/skins/';
+	const EXTRA_PATH = '/skins/';
+	const PHONE_PATH = '/public/opac/mobile/';
+	const IMAGE_DIR = 'images';
+	const CSS_DIR = 'css';
+
+	protected static $_file_system;
+
+	protected $_name;
+	protected $_is_telephone;
+
+	public static function newFor($profil) {
+		return new self($profil);
+	}
+
+
+	public function __construct($profil) {
+		$this->_name = ($profil->getSkin()) ? $profil->getSkin() : self::DEFAULT_SKIN;
+		$this->_is_telephone = $profil->isTelephone();
+	}
+
+
+	public function getPath() {
+		$path = $this->getExtraPath() . $this->_name . '/';
+		if ($this->fileExists('.' . $path))
+			return $path;
+
+		$path = self::DEFAULT_PATH . $this->_name . '/';
+		if ($this->fileExists('.' . $path))
+			return $path;
+			
+		return self::DEFAULT_PATH . self::DEFAULT_SKIN . '/';
+	}
+
+
+	protected function getExtraPath() {
+		if (!$admin_var = Class_AdminVar::get('EXTRA_SKIN_PATH'))
+			return self::EXTRA_PATH;
+		return self::EXTRA_PATH . $admin_var . ('/' !== substr($admin_var, -1) ? '/' : '');
+	}
+
+
+	public function getUrl() {
+		return BASE_URL . $this->getPath();
+	}
+
+
+	public function getImagePath($img) {
+		return '.' . $this->getPath() . self::IMAGE_DIR . '/' .$img;
+	}
+
+
+	public function imageExists($img) {
+		return $this->fileExists($this->getImagePath($img));
+	}
+
+
+	public function getImageUrl($img) {
+		return ($this->imageExists($img) 
+						? $this->getUrl() . self::IMAGE_DIR : URL_SHARED_IMG)  . '/' . $img;
+	}
+
+
+	public function getAdminImageUrl($img) {
+		if ($this->imageExists($img))
+			return $this->getUrl() . self::IMAGE_DIR . '/' . $img;
+		$img = str_replace('.png', '.gif', $img);
+		return URL_ADMIN_IMG  . '/' . $img;
+	}
+
+
+	public function getCssUrl($name) {
+		$path = $this->getPath() . self::CSS_DIR . '/' . $name . '.css';
+		if ($this->fileExists('.' . $path))
+			return BASE_URL . $path;
+	}
+
+
+	public function getTemplatesPath() {
+		return '.' 
+			. (($this->_is_telephone) ? self::PHONE_PATH : $this->getPath()) 
+			. 'templates/';
+	}
+
+
+	public function getAvailables() {
+		$skins = [];
+		foreach ([self::DEFAULT_PATH, $this->getExtraPath()] as $path)
+			$skins = array_merge($skins, $this->getAvailablesIn('.' . $path));
+		return $skins;
+	}
+
+
+	protected function getAvailablesIn($path) {
+		return $this->getFileSystem()->directoryNamesAt($path);
+	}
+
+
+	protected function fileExists($path) {
+		return $this->getFileSystem()->fileExists($path);
+	}
+
+
+	/** @category testing */
+	public static function setFileSystem($file_system) {
+		self::$_file_system = $file_system;
+	}
+
+
+	protected function getFileSystem() {
+		if (null !== self::$_file_system)
+			return self::$_file_system;
+		return new Storm_FileSystem_Disk();
+	}
+}
+?>
\ No newline at end of file
diff --git a/library/Class/ScriptLoader.php b/library/Class/ScriptLoader.php
index f890b661c00c3dd3e1aea9dfbe3422f79201368c..f2708d6209525439e9051196b03298cae7ee4ec6 100644
--- a/library/Class/ScriptLoader.php
+++ b/library/Class/ScriptLoader.php
@@ -331,25 +331,35 @@ class Class_ScriptLoader {
 	/**
 	 * @return ScriptLoader
 	 */
-	public function addStyleSheet($file, $additional_attributes=null) {
-		if (!is_array($additional_attributes))
-			$additional_attributes = array();
+	public function addStyleSheet($file, $attributes=null) {
+		if (!is_array($attributes))
+			$attributes = [];
 
 		if (false === strpos($file, '.css'))
 				$file .= '.css';
 		$file = $this->_addVersionParam($file);
 
-		$attributes = array_merge(array('type' => 'text/css', 
-																		'rel' => 'stylesheet', 
-																		'href' => $file,
-																		'media' => 'screen'),
-															$additional_attributes);
+		$ie_version = 0;
+		if (isset($attributes['ie_version'])) {
+			$ie_version = $attributes['ie_version'];
+			unset($attributes['ie_version']);
+		}
+
+		$attributes = array_merge(['type' => 'text/css', 
+															 'rel' => 'stylesheet', 
+															 'href' => $file,
+															 'media' => 'screen'],
+															$attributes);
 		
 		$html_attributes = '';
 		foreach($attributes as $name => $value)
 			$html_attributes .= sprintf(' %s="%s" ', $name, $value);
 
-		return $this->cssAddLine(sprintf('<link %s>', $html_attributes));
+		$link = sprintf('<link %s>', $html_attributes);
+		if ($ie_version)
+			$link = '<!--[if IE ' . $ie_version . ']>' . $link . '<![endif]-->';
+
+		return $this->cssAddLine($link);
 	}
 
 
@@ -389,10 +399,17 @@ class Class_ScriptLoader {
 	 * @return ScriptLoader
 	 */
 	public function addSkinStyleSheet($file, $additional_attributes=null) {
-		$url = Class_Profil::getCurrentProfil()->getUrlSkinCss($file);
-		if(!$url)
+		if(!$url = Class_Profil::getCurrentProfil()->getUrlSkinCss($file))
+			return $this;
+		return $this->addStyleSheet($url, $additional_attributes);
+	}
+
+
+	/** @return ScriptLoader */
+	public function addUserFilesStylSheet($file, $additional_attributes=null) {
+		if (!$file || !file_exists(USERFILESPATH.'/css/' . $file))
 			return $this;
-		return $this->addStyleSheet($url,$additional_attributes);
+		return $this->addStyleSheet(USERFILESURL . '/css/' . $file, $additional_attributes);
 	}
 
 
diff --git a/library/Class/Testing/FileSystem.php b/library/Class/Testing/FileSystem.php
index b4213ba25ab2132db111d6921a5c8ed5b69bfdd1..87d5b019c0b0535be15460eb662775005228a774 100644
--- a/library/Class/Testing/FileSystem.php
+++ b/library/Class/Testing/FileSystem.php
@@ -22,7 +22,7 @@
 class Class_Testing_FileSystem {
 	protected $_known_functions = ['rmdir', 'unlink', 'fopen', 'fseek', 'fgets',
 																 'filesize', 'fclose', 'ftell', 'fread', 'feof',
-																 'getcwd'];
+																 'getcwd', 'file_exists', 'scandir', 'is_dir'];
 
 	public function __call($name, $args) {
 		if (!in_array($name, $this->_known_functions))
diff --git a/library/ZendAfi/View/Helper/Permalink.php b/library/ZendAfi/View/Helper/Permalink.php
index 5f709cc8e057c03983ad697bef9af48d74ea4264..687d81e097dd268b25f93a8d518651b7cf15ff59 100644
--- a/library/ZendAfi/View/Helper/Permalink.php
+++ b/library/ZendAfi/View/Helper/Permalink.php
@@ -20,14 +20,14 @@
  */
 class ZendAfi_View_Helper_Permalink extends ZendAfi_View_Helper_BaseHelper {
 	public function permalink($url) {
-		$icone_permalink = 'reseaux/permalink.png';
-		$path_icone_permalink = PATH_SKIN . 'images/' . $icone_permalink;
-		$url_icone_permalink = file_exists($path_icone_permalink)
-			? URL_IMG . $icone_permalink
+		$profil = Class_Profil::getCurrentProfil();
+		$icon = 'reseaux/permalink.png';
+		$icon_url = $profil->skinHasImage($icon)
+			? $profil->getUrlImage($icon)
 			: URL_ADMIN_IMG . 'reseaux/permalink.gif';
 
 		$lien_permanent = $this->translate()->_('Lien permanent');
-		$html = $this->view->tagImgHover($url_icone_permalink,
+		$html = $this->view->tagImgHover($icon_url,
 																		 ['class' => 'permalien-img',
 																			'title' => $lien_permanent,
 																			'alt' => $lien_permanent,
diff --git a/library/ZendAfi/View/Helper/ReseauxSociaux.php b/library/ZendAfi/View/Helper/ReseauxSociaux.php
index 97eb22d18d20a0401abb5d6e4e793bb173191dcb..59687ab810bbb94dd6348b81c327cb2830bcd298 100644
--- a/library/ZendAfi/View/Helper/ReseauxSociaux.php
+++ b/library/ZendAfi/View/Helper/ReseauxSociaux.php
@@ -18,9 +18,6 @@
  * 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 
  */
-//////////////////////////////////////////////////////////////////////////////////////////
-// OPAC3 : Reseaux sociaux (facebook, twitter,etc...)
-//////////////////////////////////////////////////////////////////////////////////////////
 
 class ZendAfi_View_Helper_ReseauxSociaux extends ZendAfi_View_Helper_BaseHelper {
 	protected $reseaux;
@@ -62,7 +59,6 @@ class ZendAfi_View_Helper_ReseauxSociaux extends ZendAfi_View_Helper_BaseHelper
 
 	
 	public function renderProfil($profil) {
-
 		return $this->headerLinks(['url_to_share'=>Zend_Controller_Front::getInstance()->getBaseUrl(),
 															 'titre' => $profil->getTitreSite(),
 															 'message' => $profil->getCommentaire(),
@@ -71,7 +67,6 @@ class ZendAfi_View_Helper_ReseauxSociaux extends ZendAfi_View_Helper_BaseHelper
 
 
 	public function links($info_to_share) {
-
 		// Get reseaux
 
 		// Html
@@ -93,27 +88,31 @@ class ZendAfi_View_Helper_ReseauxSociaux extends ZendAfi_View_Helper_BaseHelper
 
 	
 	public function shareLinkHtml($info) {
-		$html='';
+		$html = '';
 		foreach($this->reseaux as $clef => $reseau) {
-			$html.= $this->shareLinkImgHtml($clef,array_merge($this->shareLinkUrlTable($clef,$info),$this->getShareIco($clef)));
+			$html.= $this->shareLinkImgHtml($clef, 
+																			array_merge($this->shareLinkUrlTable($clef,$info),
+																									$this->getShareIco($clef)));
 		}
 		return $html;
 	}
 
 
-		public function shareLinkHtmlHeader($info) {
-		$html='';
+	public function shareLinkHtmlHeader($info) {
+		$html = '';
 		foreach($this->reseaux as $clef => $reseau) {
 			if($clef=='mail')
 				continue;
-			$html.= $this->shareLinkImgHtml($clef,array_merge($this->shareLinkUrlTable($clef,$info),$this->getHeaderShareIco($clef)));
+
+			$html.= $this->shareLinkImgHtml($clef,
+																			array_merge($this->shareLinkUrlTable($clef,$info),
+																									$this->getHeaderShareIco($clef)));
 		}
 		return $html;
 	}
 
 
 	public function shareLinkImgHtml($clef,$url_table) {
-					
 		$html = $this->view->tagImgHover($url_table['url_ico_reseau'],
 																		 ['class' => 'reseau-social-img',
 																			'alt' => sprintf("%s ".$clef, $this->translate()->_('icone')),
@@ -146,21 +145,34 @@ class ZendAfi_View_Helper_ReseauxSociaux extends ZendAfi_View_Helper_BaseHelper
 
 
 	public function getHeaderShareIco($action) {
-		$ico_action = $action.'.png';
-
-		return ['url_ico_reseau' => 
-						file_exists(Class_Profil::getCurrentProfil()->getSkinImagePath('/reseaux/'.$ico_action)) 
-						? URL_IMG.'reseaux/'.$ico_action 
-						: URL_SHARED_IMG.'reseaux/'.$ico_action];
+		$image = $this->imageForAction($action);
+		return $this->getIco(
+			function($profil) use ($image) {
+				return $profil->getUrlImage($image);
+			});
 	}
 
 
 	public function getShareIco($action) {
-		$ico_action = 'reseaux/'.$action.'.png';
+		$image = $this->imageForAction($action);
+		return $this->getIco(
+			function($profil) use ($image) {
+				return $profil->getUrlAdminImage($image);
+			});
+	}
+
+
+	protected function getIco($closure) {
+		return ['url_ico_reseau' => $this->withProfilDo($closure)];
+	}
+
+
+	protected function withProfilDo($closure) {
+		return $closure(Class_Profil::getCurrentProfil());
+	}
+
 
-		return ['url_ico_reseau' => 
-						file_exists(Class_Profil::getCurrentProfil()->getSkinImagePath($ico_action)) 
-						? URL_IMG.$ico_action 
-						: URL_ADMIN_IMG.'reseaux/'.$action.'.gif'];
+	protected function imageForAction($action) {
+		return 'reseaux/'. $action . '.png';
 	}
 }
\ No newline at end of file
diff --git a/library/ZendAfi/View/Helper/TagBanniere.php b/library/ZendAfi/View/Helper/TagBanniere.php
index 9cc8dd0542d93068ddc24dd8a823ca627337e225..5cb5ca06ca732a6f18ae4d175ec5b3aeee1cce33 100644
--- a/library/ZendAfi/View/Helper/TagBanniere.php
+++ b/library/ZendAfi/View/Helper/TagBanniere.php
@@ -25,30 +25,31 @@ class ZendAfi_View_Helper_TagBanniere extends Zend_View_Helper_HtmlElement {
 			Class_ScriptLoader::getInstance()
 				->addScript(URL_JAVA . 'diaporama/jquery.cycle.all.min')
 				->addJQueryReady(sprintf('$("#banniere a.home").cycle(%s)', 
-																 json_encode(array('fx' => 'fade',
-																									 'width' => $this->_profil->getLargeurSite(),
-																									 'height' => $this->_profil->getHauteurBanniere()))));
+																 json_encode(['fx' => 'fade',
+																							'width' => $this->_profil->getLargeurSite(),
+																							'height' => $this->_profil->getHauteurBanniere()])));
 		}
 
 		return sprintf('<div id="banniere">%s<a class="home" href="%s" style="display:block">%s</a></div>',
 									 $this->_getLogos(),
-									 BASE_URL,
+									 $this->view->url([], null, true),
 									 $this->_getImages());
 	}
 
 
 
 	protected function _getLogos() {
-		return $this->_getLogo('gauche').$this->_getLogo('droite');
+		return $this->_getLogo('gauche') . $this->_getLogo('droite');
 	}
 
 	
 	protected function _getLogo($position) {
 		if ($this->_profil->_has('logo_'.$position.'_img'))
-			return sprintf("<div class='logo_%s'><a href='%s'><img src='%s' alt=''/></a></div>",
-										 $position,
-										 $this->_profil->_get('logo_'.$position.'_link'),
-										 $this->_profil->_get('logo_'.$position.'_img'));
+			return sprintf(
+				'<div class="logo_%s"><a href="%s"><img src="%s" alt=""/></a></div>',
+				$position,
+				$this->_profil->_get('logo_'.$position.'_link'),
+				$this->_profil->_get('logo_'.$position.'_img'));
 		return '';
 	}
 
@@ -57,11 +58,13 @@ class ZendAfi_View_Helper_TagBanniere extends Zend_View_Helper_HtmlElement {
 		$images = '';
 		$largeur_site = $this->_profil->getLargeurSite();
 
-		foreach ($this->_profil->getAllHeaderImg() as $img)
-			$images .= sprintf('<img alt="%s" src="%s" style="width:%dpx" />',
-												 $this->view->_("banniere du site"),
-												 $img,
-												 $largeur_site);
+		foreach ($this->_profil->getAllHeaderImg() as $img) {
+			if (!$img)
+				continue;
+
+			$images .= sprintf('<img alt="" src="%s" style="width:%dpx" />',
+												 $img, $largeur_site);
+		}
 
 		return $images;
 	}
diff --git a/library/storm b/library/storm
index e8c97bd32462ece3fa87dc6d828bd77875fc5187..ce4ba4ba1adcae6c4c8c647a7cc6ff4991f5d86d 160000
--- a/library/storm
+++ b/library/storm
@@ -1 +1 @@
-Subproject commit e8c97bd32462ece3fa87dc6d828bd77875fc5187
+Subproject commit ce4ba4ba1adcae6c4c8c647a7cc6ff4991f5d86d
diff --git a/skins/.gitignore b/skins/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..8d1c8b69c3fce7bea45c73efd06983e3c419a92f
--- /dev/null
+++ b/skins/.gitignore
@@ -0,0 +1 @@
+ 
diff --git a/tests/application/modules/admin/controllers/ProfilControllerTest.php b/tests/application/modules/admin/controllers/ProfilControllerTest.php
index 57a4582937b9213a05a2d592818fa4a2acef8b4b..c1ec531c4082f6a127ca1bfaec04ab2974a3ef71 100644
--- a/tests/application/modules/admin/controllers/ProfilControllerTest.php
+++ b/tests/application/modules/admin/controllers/ProfilControllerTest.php
@@ -24,34 +24,34 @@ require_once 'AdminAbstractControllerTestCase.php';
 abstract class Admin_ProfilControllerProfilJeunesseTestCase extends Admin_AbstractControllerTestCase {
 	public function setUp() {
 		parent::setUp();
-		$cfg_site = array('header_img' => "/public/jeunesse.png",
-											'header_img_cycle' => true,
-											'liens_sortants_off' => true,
-											'accessibilite_on' => 0,
-											'couleur_texte_bandeau' => '#222',
-											'couleur_lien_bandeau' => '#55F',
-											'access_level' => 3,
-											'favicon' => '/userfiles/favicon.ico',
-											'logo_gauche_img' => '/userfiles/mabib.png',
-											'logo_gauche_link' => 'http://mabib.fr',
-											'logo_droite_img' => '/userfiles/macommune.png',
-											'logo_droite_link' => 'http://macommune.fr',
-											'header_social_network' => true,
-											'division_three_always_visible' => true,
-											'header_css' => '/userfiles/css/my.css',
-											'header_js' => '/userfiles/js/my.js',
-											'ordre_divisions' => 1);
-
-		$cfg_notice = array('exemplaires' => array('grouper' => 1,
-																							 'section' => 1,
-																							 'emplacement' => 0,
-																							 'bib' => 1,
-																							 'annexe' => 0,
-																							 'dispo' => 1,
-																							 'date_retour' => 0,
-																							 'localisation' => 0,
-																							 'plan' => 0,
-																							 'resa' => 2));
+		$cfg_site = ['header_img' => "/public/jeunesse.png",
+								 'header_img_cycle' => true,
+								 'liens_sortants_off' => true,
+								 'accessibilite_on' => 0,
+								 'couleur_texte_bandeau' => '#222',
+								 'couleur_lien_bandeau' => '#55F',
+								 'access_level' => 3,
+								 'favicon' => '/userfiles/favicon.ico',
+								 'logo_gauche_img' => '/userfiles/mabib.png',
+								 'logo_gauche_link' => 'http://mabib.fr',
+								 'logo_droite_img' => '/userfiles/macommune.png',
+								 'logo_droite_link' => 'http://macommune.fr',
+								 'header_social_network' => true,
+								 'division_three_always_visible' => true,
+								 'header_css' => '/userfiles/css/my.css',
+								 'header_js' => '/userfiles/js/my.js',
+								 'ordre_divisions' => 1];
+
+		$cfg_notice = ['exemplaires' => ['grouper' => 1,
+																		 'section' => 1,
+																		 'emplacement' => 0,
+																		 'bib' => 1,
+																		 'annexe' => 0,
+																		 'dispo' => 1,
+																		 'date_retour' => 0,
+																		 'localisation' => 0,
+																		 'plan' => 0,
+																		 'resa' => 2]];
 
 
 		$this->profil_jeunesse = Class_Profil::getLoader()
@@ -74,6 +74,9 @@ abstract class Admin_ProfilControllerProfilJeunesseTestCase extends Admin_Abstra
 			->whenCalled('save')->answers(true)->getWrapper();
 
 		ZendAfi_Auth::getInstance()->getIdentity()->ROLE_LEVEL = 7;
+
+		$this->fixture('Class_AdminVar', ['id' => 'EXTRA_SKIN_PATH',
+																			'valeur' => '']);
 	}
 }
 
@@ -83,11 +86,25 @@ class Admin_ProfilControllerEditProfilJeunesseTest extends Admin_ProfilControlle
 	public function setUp() {
 		parent::setUp();
 
-		Class_Profil::setFileWriter(Storm_Test_ObjectWrapper::mock()->whenCalled('fileExists')->answers(true));
+		Class_Profil::setFileWriter(Storm_Test_ObjectWrapper::mock()
+																->whenCalled('fileExists')->answers(true));
+
+		Class_Profil_Skin::setFileSystem(
+			(new Storm_FileSystem_Volatile())
+			->mkdir(Class_Profil_Skin::DEFAULT_PATH . 'original')
+			->mkdir(Class_Profil_Skin::DEFAULT_PATH . 'modele')
+			->mkdir(Class_Profil_Skin::EXTRA_PATH));
+
 		$this->dispatch('/admin/profil/edit/id_profil/5');
 	}
 
 
+	public function tearDown() {
+		Class_Profil_Skin::setFileSystem(null);
+		parent::tearDown();
+	}
+
+
 	/**
 	 * @test
 	 */
diff --git a/tests/application/modules/opac/controllers/NoticeAjaxControllerTest.php b/tests/application/modules/opac/controllers/NoticeAjaxControllerTest.php
index 2dd2533aaf06edd1ebaf6f4bf20085dfa89f02bf..d851e82af21202e208264d67c41396bfea7e092f 100644
--- a/tests/application/modules/opac/controllers/NoticeAjaxControllerTest.php
+++ b/tests/application/modules/opac/controllers/NoticeAjaxControllerTest.php
@@ -58,7 +58,7 @@ class NoticeAjaxControllerNonRegressionTest extends AbstractControllerTestCase {
 
 
 
- class NoticeAjaxControllerNoticeWithGamUrlTestCase extends AbstractControllerTestCase {
+class NoticeAjaxControllerNoticeWithGamUrlTestCase extends AbstractControllerTestCase {
 	protected $_wesley;
 
 	public function setUp() {
@@ -67,18 +67,20 @@ class NoticeAjaxControllerNonRegressionTest extends AbstractControllerTestCase {
 		Class_Profil::getCurrentProfil()
 			->setCfgModules(['recherche' => ['resultatsimple' => ['liste_codes' => "TANECRG"]]]);
 
+		$this->_wesley = $this->fixture(
+			'Class_Notice',
+			['id' => 1,
+			 'facettes' => 'A1',
+			 'isbn' => '',
+			 'ean' => '',
+			 'type_doc' => 1,
+			 'tome_alpha' => '',
+			 'clef_alpha' => 'Wesley',
+			 'unimarc' => "02502njm0 22007331  450 00100060000007100370000610000410004310100080008412700100009220000450010220000030014721000390015021500090018932700030019834500420020146400030024346400030024646400030024946400030025246400030025546400030025846400030026146400030026446400030026746400030027046400030027346400030027646400030027946400190028246400210030146400160032246400100033846400240034846400250037246400110039746400250040846400290043346400280046246400180049046400150050846400170052368600290054070000320056970000030060170100320060470200400063670200340067670200330071070200380074370200440078170200350082570200360086070200310089671100030092780100220093085601320095293301470108498401320123198500820136398500840144598500790152998500730160898500870168134793100a2784087bHIP-OSelect.com/Polydor  a20130311d2011    u  y0frey0103    ba0 aeng  a53:221 aThe Lost album featuring Watermelon man 1   cUniversal RecordsdRÂeedition 2011  a1 cd1   b0602527840871cdisque compactd7,48 E 1 1 1 1 1 1 1 1 1 1 1 1 1  tWatermelon man  tSweet loneliness  tSecret love  tSeulb  tYou've got a friend  tTransmograpification  tUse me  tGet on the good foot  tEverybody plays the fool  tAlone again (Naturally)  tBack stabbers  tJ.B. shout  tFunky & some  a1.382tJazz funky2PCDM4 1aWesleybFred40006trombone 1 1aThe JB's 40006ens. instr. 1aFarrellbJoe40006saxophone tÂenor 1aStammbMarvin4btr6trompette 1aBrownbCharlie40006guitare 1aCranshawbBob4MBS6basse guitare 1aBreckerbMichael40006saxophone tÂenor 1aBreckerbRandy4btr6trompette 1aCarterbRon4MBS6basse guitare 1aGaddbSteve4PDS6batterie02 0aFRbGAMc201303114 uhttp://www.gamannecy.com//upload/albums/201202/0602527840871_thumb.jpgzFred Wesley / Lost album featuring Watermelon man (The)  3http://www.gamannecy.com//upload/albums/201202/0602527840871_thumb.jpgahttp://www.gamannecy.com//upload/albums/201202/0602527840871_thumb.jpg  ahttp://www.gamannecy.com//upload/albums/201202/0602527840871_thumb.jpgbFred Wesley / Lost album featuring Watermelon man (The)  ahttp://www.gamannecy.com/polysson/201205/01-0602527840871.mp3bWatermelon man  ahttp://www.gamannecy.com/polysson/201205/02-0602527840871.mp3bSweet loneliness  ahttp://www.gamannecy.com/polysson/201205/03-0602527840871.mp3bSecret love  ahttp://www.gamannecy.com/polysson/201205/04-0602527840871.mp3bSeulb  ahttp://www.gamannecy.com/polysson/201205/05-0602527840871.mp3bYou've got a friend",
+			 'annee' => '2000',
+			 'url_vignette' => 'wesley_small.png',
+			 'url_image' => 'wesley.png']);
 
-		$this->_wesley = Class_Notice::newInstanceWithId(1, 
-																												 ['facettes' => 'A1',
-																													'isbn' => '',
-																													'ean' => '',
-																													'type_doc' => 1,
-																													'tome_alpha' => '',
-																													'clef_alpha' => 'Wesley',
-																													'unimarc' => "02502njm0 22007331  450 00100060000007100370000610000410004310100080008412700100009220000450010220000030014721000390015021500090018932700030019834500420020146400030024346400030024646400030024946400030025246400030025546400030025846400030026146400030026446400030026746400030027046400030027346400030027646400030027946400190028246400210030146400160032246400100033846400240034846400250037246400110039746400250040846400290043346400280046246400180049046400150050846400170052368600290054070000320056970000030060170100320060470200400063670200340067670200330071070200380074370200440078170200350082570200360086070200310089671100030092780100220093085601320095293301470108498401320123198500820136398500840144598500790152998500730160898500870168134793100a2784087bHIP-OSelect.com/Polydor  a20130311d2011    u  y0frey0103    ba0 aeng  a53:221 aThe Lost album featuring Watermelon man 1   cUniversal RecordsdRÂeedition 2011  a1 cd1   b0602527840871cdisque compactd7,48 E 1 1 1 1 1 1 1 1 1 1 1 1 1  tWatermelon man  tSweet loneliness  tSecret love  tSeulb  tYou've got a friend  tTransmograpification  tUse me  tGet on the good foot  tEverybody plays the fool  tAlone again (Naturally)  tBack stabbers  tJ.B. shout  tFunky & some  a1.382tJazz funky2PCDM4 1aWesleybFred40006trombone 1 1aThe JB's 40006ens. instr. 1aFarrellbJoe40006saxophone tÂenor 1aStammbMarvin4btr6trompette 1aBrownbCharlie40006guitare 1aCranshawbBob4MBS6basse guitare 1aBreckerbMichael40006saxophone tÂenor 1aBreckerbRandy4btr6trompette 1aCarterbRon4MBS6basse guitare 1aGaddbSteve4PDS6batterie02 0aFRbGAMc201303114 uhttp://www.gamannecy.com//upload/albums/201202/0602527840871_thumb.jpgzFred Wesley / Lost album featuring Watermelon man (The)  3http://www.gamannecy.com//upload/albums/201202/0602527840871_thumb.jpgahttp://www.gamannecy.com//upload/albums/201202/0602527840871_thumb.jpg  ahttp://www.gamannecy.com//upload/albums/201202/0602527840871_thumb.jpgbFred Wesley / Lost album featuring Watermelon man (The)  ahttp://www.gamannecy.com/polysson/201205/01-0602527840871.mp3bWatermelon man  ahttp://www.gamannecy.com/polysson/201205/02-0602527840871.mp3bSweet loneliness  ahttp://www.gamannecy.com/polysson/201205/03-0602527840871.mp3bSecret love  ahttp://www.gamannecy.com/polysson/201205/04-0602527840871.mp3bSeulb  ahttp://www.gamannecy.com/polysson/201205/05-0602527840871.mp3bYou've got a friend",
-																													'annee' => '2000',
-																													'url_vignette' => 'wesley_small.png',
-																													'url_image' => 'wesley.png']);
 		$mock_sql = Storm_Test_ObjectWrapper::on(Zend_Registry::get('sql'));
 		Zend_Registry::set('sql', $mock_sql);
 
@@ -86,16 +88,21 @@ class NoticeAjaxControllerNonRegressionTest extends AbstractControllerTestCase {
 			->whenCalled('fetchOne')
 			->with("select valeur from variables where clef='black_list_856'")
 			->answers('electre');
+
+		$this->fixture('Class_CosmoVar', ['id' => 'types_docs',
+																			'liste' => "1:cd\r\n200:non identifié\r\n201:livres\r\n202:bd"]);
 	}
 
+
 	/** @test */
 	public function withNoticeFoundResponseShouldContainsLienInternet() {
 		$this->dispatch('/opac/noticeajax/detail/id_notice/1', true);
 		$this->assertXPathContentContains('//a', 'http://www.gamannecy.com//upload/albums/201202/0602527840871_thumb.jpg', $this->_response->getBody());
-	}
-
-	
+	}	
 }
+
+
+
 abstract class NoticeAjaxControllerNoticeSouleymaneTestCase extends AbstractControllerTestCase {
 	protected $_souleymane;
 
diff --git a/tests/application/modules/opac/controllers/ProfilOptionsControllerTest.php b/tests/application/modules/opac/controllers/ProfilOptionsControllerTest.php
index ac5bd15e49f183a9b0a23747fd602d88cdafdda1..8f5fe415fb222341a1d715d2fd59354397dc239a 100644
--- a/tests/application/modules/opac/controllers/ProfilOptionsControllerTest.php
+++ b/tests/application/modules/opac/controllers/ProfilOptionsControllerTest.php
@@ -80,7 +80,9 @@ abstract class ProfilOptionsControllerWithProfilAdulteTestCase extends AbstractC
 																											 ['type_menu' => Class_Systeme_ModulesMenu::MODULE_ACCUEIL_PREFIX.'NEWS',
 																												'libelle' => 'Nouvelles',
 																												'picto' => 'vide.gif',
-																												'preferences' => ['titre' => 'Nouvelles']],
+																												'preferences' => [
+																													'titre' => 'Nouvelles',
+																													'nb_aff' => 0]],
 
 																				 ]],
 
@@ -212,7 +214,7 @@ abstract class ProfilOptionsControllerWithProfilAdulteTestCase extends AbstractC
 			->setCommentaire('Super bib')
 			->setRefTags('bib,Adulte');
 		$this->profil_adulte->assertSave();
-		Class_Profil::setCurrentProfil($this->profil_adulte);
+		$this->profil_adulte->beCurrentProfil();
 	}
 }
 
@@ -618,6 +620,22 @@ class ProfilOptionsControllerViewProfilAdulteTest extends ProfilOptionsControlle
 		$this->assertXPath('//link[contains(@href, "nuage_tags.css")]');
 	}
 
+}
+
+
+class ProfilOptionsControllerViewProfilAdulteHtml5Test extends ProfilOptionsControllerWithProfilAdulteTestCase {
+	public function setUp() {
+		parent::setUp();
+		Class_Profil::getCurrentProfil()
+			->setCfgMenus(array('H' => ['libelle' => 'Menu horizontal',
+																	'picto' => 'vide.gif',
+																	'menus' => []],
+													'V' => ['libelle' => 'Menu vertical', 
+																	'picto' => 'vide.gif',
+																	'menus' => []]))
+			->assertSave();
+		$this->dispatch('/opac/');		
+	}
 
 	/** 
 	 * @group integration
diff --git a/tests/application/modules/telephone/controllers/IndexControllerTest.php b/tests/application/modules/telephone/controllers/IndexControllerTest.php
index 792dcb259544f85096cce89ec20adc5c1afa0e7d..744205c169059a307e66fa02f07ed4ac0a859c6e 100644
--- a/tests/application/modules/telephone/controllers/IndexControllerTest.php
+++ b/tests/application/modules/telephone/controllers/IndexControllerTest.php
@@ -33,7 +33,6 @@ abstract class AbstractIndexControllerTelephoneWithModulesTest extends Telephone
 	public function setUp() {
 		parent::setUp();
 
-
 		Storm_Test_ObjectWrapper::onLoaderOfModel('Class_Article')
 			->whenCalled('getArticlesByPreferences')
 			->answers([
@@ -43,35 +42,35 @@ abstract class AbstractIndexControllerTelephoneWithModulesTest extends Telephone
 									]);
 
 		$cfg_accueil =
-			array('modules' => array('1' => array('division' => '1',
-																						'type_module' => 'RECH_SIMPLE',
-																						'preferences' => array()),
-
-															 '2' => array('division' => '1',
-																						'type_module' => 'NEWS',
-																						'preferences' => array('titre' => 'Concerts',
-																																	 'rss_avis' => 0)),
-
-															 '3' => array('division' => '1',
-																						'type_module' => 'LOGIN',
-																						'preferences' => array('titre' => 'Se connecter',
-																																	 'identifiant' => 'identifiant',
-																																	 'identifiant_exemple' => 'numero carte',
-																																	 'mot_de_passe' => 'mot de passe',
-																																	 'mot_de_passe_exemple' => 'zork',
-																																	 'lien_connexion' => 'go')),
-															 '4' => array('division' => '1',
-																						'type_module' => 'BIB_NUMERIQUE',
-																						'preferences' => array('titre' => 'Mes albums')),
-
-															 '5' => array('division' => '1',
-																						'type_module' => 'CALENDAR',
-																						'preferences' => array('titre' => 'Agenda')),
-
-															 '6' => array('division' => '1',
-																						'type_module' => 'CRITIQUES',
-																						'preferences' => array('titre' => 'Critiques'))
-															 )); 
+			['modules' => ['1' => ['division' => '1',
+														 'type_module' => 'RECH_SIMPLE',
+														 'preferences' => []],
+										 
+										 '2' => ['division' => '1',
+														 'type_module' => 'NEWS',
+														 'preferences' => ['titre' => 'Concerts',
+																							 'rss_avis' => 0]],
+
+										 '3' => ['division' => '1',
+														 'type_module' => 'LOGIN',
+														 'preferences' => ['titre' => 'Se connecter',
+																							 'identifiant' => 'identifiant',
+																							 'identifiant_exemple' => 'numero carte',
+																							 'mot_de_passe' => 'mot de passe',
+																							 'mot_de_passe_exemple' => 'zork',
+																							 'lien_connexion' => 'go']],
+										 '4' => ['division' => '1',
+														 'type_module' => 'BIB_NUMERIQUE',
+														 'preferences' => ['titre' => 'Mes albums']],
+										 
+										 '5' => ['division' => '1',
+														 'type_module' => 'CALENDAR',
+														 'preferences' => ['titre' => 'Agenda']],
+										 
+										 '6' => ['division' => '1',
+														 'type_module' => 'CRITIQUES',
+														 'preferences' => ['titre' => 'Critiques']]
+					]]; 
 
 		$this->profil_adulte = Class_Profil::getCurrentProfil()
 			->setTitreSite('Smartphone')
@@ -83,11 +82,21 @@ abstract class AbstractIndexControllerTelephoneWithModulesTest extends Telephone
 
 		Storm_Test_ObjectWrapper::onLoaderOfModel("Class_Profil")
 			->whenCalled('findFirstBy')
-			->with(array('BROWSER' => 'telephone'))
+			->with(['BROWSER' => 'telephone'])
 			->answers($this->profil_adulte);
 
+		Class_Profil_Skin::setFileSystem((new Storm_FileSystem_Volatile())
+																		 ->mkdir('/public/opac/skins/vide/css/')
+																		 ->touch('/public/opac/skins/vide/css/mobile.css'));
+
 		Class_Profil::setFileWriter(Storm_Test_ObjectWrapper::mock()->whenCalled('fileExists')->answers(true));
 	}
+
+
+	public function tearDown() {
+		Class_Profil_Skin::setFileSystem(null);
+		parent::tearDown();
+	}
 }
 
 
@@ -202,24 +211,23 @@ class IndexControllerTelephoneSimulationWithModulesTest extends AbstractIndexCon
 	public function setUp() {
 		parent::setUp();
 
-		$avis = array(Class_AvisNotice::getLoader()
-									->newInstanceWithId(34)
-									->setDateAvis('2012-01-01')
-									->setClefOeuvre('HARRYPOT')
-									->beWrittenByBibliothecaire()
-									->setNote(3)
-									->setEntete('bien')
-									->setAvis('bla bla')
-									->setNotice(Class_Notice::getLoader()
-															->newInstanceWithId(3)
-															->setUrlVignette('http://opac.com/potter.jpg'))
-									->setUser(Class_Users::getLoader()->newInstanceWithId(2)));
+		$avis = [Class_AvisNotice::getLoader()
+						 ->newInstanceWithId(34)
+						 ->setDateAvis('2012-01-01')
+						 ->setClefOeuvre('HARRYPOT')
+						 ->beWrittenByBibliothecaire()
+						 ->setNote(3)
+						 ->setEntete('bien')
+						 ->setAvis('bla bla')
+						 ->setNotice(Class_Notice::getLoader()
+												 ->newInstanceWithId(3)
+												 ->setUrlVignette('http://opac.com/potter.jpg'))
+						 ->setUser(Class_Users::getLoader()->newInstanceWithId(2))];
+
 		Storm_Test_ObjectWrapper::onLoaderOfModel('Class_AvisNotice')
 			->whenCalled('getAvisFromPreferences')
 			->answers($avis);
 
-
-
 		unset($_SERVER['HTTP_USER_AGENT']);
 		$this->dispatch('/', true);
 	}
@@ -239,7 +247,6 @@ class IndexControllerTelephoneSimulationWithModulesTest extends AbstractIndexCon
 
 	/** @test */
 	public function pageShouldContainsSkinVideMobileCss() {
-		
 		$this->assertXPath('//link[contains(@href, "skins/vide/css/mobile.css")]',$this->_response->getBody());
 	}
 
diff --git a/tests/application/modules/telephone/controllers/TelephoneAbstractControllerTestCase.php b/tests/application/modules/telephone/controllers/TelephoneAbstractControllerTestCase.php
index 6a2a2281b078de33b767a86ead6952c75d161883..854b6384f700410b5b60b18da6e594ae3d3c8498 100644
--- a/tests/application/modules/telephone/controllers/TelephoneAbstractControllerTestCase.php
+++ b/tests/application/modules/telephone/controllers/TelephoneAbstractControllerTestCase.php
@@ -25,11 +25,14 @@ abstract class TelephoneAbstractControllerTestCase extends AbstractControllerTes
 	public function setUp() {
 		parent::setUp();
 		$_SERVER['HTTP_USER_AGENT'] = 'iPhone';
-
 		Storm_Test_ObjectWrapper::onLoaderOfModel('Class_Profil')
 			->whenCalled('findFirstBy')
 			->with(['BROWSER' => 'telephone'])
 			->answers(Class_Profil::getCurrentProfil()->beTelephone());
+
+/*		$this->fixture('Class_Profil', ['id' => 2, 
+																		'browser' => 'telephone'])
+																		->beCurrentProfil();*/
 	}
 
 	public function tearDown() {
diff --git a/tests/library/Class/Profil/SkinTest.php b/tests/library/Class/Profil/SkinTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..31784f153805d8993efddfe4d7f2c5b99ded8b38
--- /dev/null
+++ b/tests/library/Class/Profil/SkinTest.php
@@ -0,0 +1,182 @@
+<?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 
+ */
+
+abstract class Class_Profil_SkinTestCase extends Storm_Test_ModelTestCase {
+	protected $_skin;
+	protected $_file_system;
+	protected $_skin_name = 'testing';
+
+	public function setUp() {
+		parent::setUp();
+		$this->_file_system = (new Storm_FileSystem_Volatile())
+			->mkdir(Class_Profil_Skin::DEFAULT_PATH)
+			->cd(Class_Profil_Skin::DEFAULT_PATH)
+			->mkdir('afi')
+			->mkdir('original')
+			->mkdir('testing/images')
+			->touch('testing/images/test.png')
+			->mkdir('testing/css')
+			->touch('testing/css/testing.css')
+
+			->mkdir('/public/opac/images')
+			->touch('/public/opac/images/test.png')
+
+			->mkdir(Class_Profil_Skin::EXTRA_PATH . 'my-skin')
+			->cd('/');
+
+		Class_Profil_Skin::setFileSystem($this->_file_system);
+
+		$this->_skin = Class_Profil_Skin::newFor(
+			$this->fixture('Class_Profil', ['id' => 3, 'skin' => $this->_skin_name]));
+
+		Class_AdminVar::beVolatile();
+	}
+
+
+	public function tearDown() {
+		Class_Profil_Skin::setFileSystem(null);
+		parent::tearDown();
+	}
+}
+
+
+class Class_Profil_SkinExtraTest extends Class_Profil_SkinTestCase {
+	protected $_skin_name = 'my-skin';
+
+	/** @test */
+	public function pathShouldContainsMySkin() {
+		$this->assertContains($this->_skin_name, $this->_skin->getPath());
+	}
+
+
+	/** @test */
+	public function withExtraSkinPathShouldContainsIt() {
+		$this->fixture('Class_AdminVar', ['id' => 'EXTRA_SKIN_PATH',
+																			'valeur' => 'sub-skins']);
+		$this->_file_system
+			->mkdir(Class_Profil_Skin::EXTRA_PATH . 'sub-skins/my-skin');
+
+		$this->assertContains('sub-skins/' . $this->_skin_name, 
+													$this->_skin->getPath());
+	}
+}
+
+
+
+class Class_Profil_SkinExistTest extends Class_Profil_SkinTestCase {
+	/** @test */
+	public function pathShouldContainsTesting() {
+		$this->assertContains('testing/', $this->_skin->getPath());
+	}
+
+
+	/** @test */
+	public function imagePathShouldContainsTesting() {
+		$this->assertContains('testing/images/test.png', 
+													$this->_skin->getImagePath('test.png'));
+	}
+
+
+	/** @test */
+	public function cssUrlShouldContainsTesting() {
+		$this->assertContains('testing/css/testing.css', 
+													$this->_skin->getCssUrl('testing'));
+	}
+
+
+	/** @test */
+	public function imageUrlShouldContainsTesting() {
+		$this->assertContains('testing/images/test.png', 
+													$this->_skin->getImageUrl('test.png'));
+	}
+
+
+	/** @test */
+	public function imageUrlNotExistingShouldContainsShared() {
+		$this->_file_system->rm(Class_Profil_Skin::DEFAULT_PATH.'testing/images/test.png');
+		$this->assertContains('public/opac/images/test.png', 
+													$this->_skin->getImageUrl('test.png'));
+	}
+
+
+	/** @test */
+	public function templatesPathShouldContainsTesting() {
+		$this->assertContains('testing/templates', $this->_skin->getTemplatesPath());
+	}
+
+
+	/** @test */
+	public function availableShouldBeAsExpected() {
+		$this->assertEquals(['afi' => 'afi',
+												 'my-skin' => 'my-skin',
+												 'original' => 'original',
+												 'testing' => 'testing'], 
+												$this->_skin->getAvailables());
+	}
+
+	
+	/** @test */
+	public function availableWithExtraPathVarShouldBeAsExpected() {
+		$extra_var = 'sub-skins';
+		$this->fixture('Class_AdminVar', ['id' => 'EXTRA_SKIN_PATH',
+																			'valeur' => $extra_var]);
+
+		$this->_file_system
+			->mkdir(Class_Profil_Skin::EXTRA_PATH . $extra_var . '/very-dark')
+			->mkdir(Class_Profil_Skin::EXTRA_PATH . $extra_var . '/very-light');
+
+		$this->assertEquals(['afi' => 'afi',
+												 'very-dark' => 'very-dark',
+												 'very-light' => 'very-light',
+												 'original' => 'original',
+												 'testing' => 'testing'], 
+												$this->_skin->getAvailables());
+	}
+}
+
+
+class Class_Profil_SkinTelephoneTest extends Class_Profil_SkinTestCase {
+	public function setUp() {
+		parent::setUp();
+		$this->_skin = Class_Profil_Skin::newFor(Class_Profil::find(3)->beTelephone());
+	}
+
+
+	/** @test */
+	public function templatesPathShouldContainsTelephone() {
+		$this->assertContains('opac/mobile/templates', $this->_skin->getTemplatesPath());
+	}
+}
+
+
+
+class Class_Profil_SkinNotExistsTest extends Class_Profil_SkinTestCase {
+	protected $_skin_name = 'unknown';
+
+
+	/** @test */
+	public function pathShouldBeDefault() {
+		$this->assertEquals(
+			Class_Profil_Skin::DEFAULT_PATH . Class_Profil_Skin::DEFAULT_SKIN . '/',
+			$this->_skin->getPath());
+	}
+}
+?>
\ No newline at end of file
diff --git a/tests/library/ZendAfi/View/Helper/ReseauxSociauxTest.php b/tests/library/ZendAfi/View/Helper/ReseauxSociauxTest.php
index 3203fce16557359a535c2084502f4f682aa1ba92..c027627096f0ed1125fdb2ae714c7717e81ae8d8 100644
--- a/tests/library/ZendAfi/View/Helper/ReseauxSociauxTest.php
+++ b/tests/library/ZendAfi/View/Helper/ReseauxSociauxTest.php
@@ -18,9 +18,9 @@
  * 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 
  */
+require_once realpath(dirname(__FILE__)) . '/ViewHelperTestCase.php';
 
-
-class ZendAfi_View_Helper_ReseauxSociauxTest extends ViewHelperTestCase {
+abstract class ZendAfi_View_Helper_ReseauxSociauxTestCase extends ViewHelperTestCase {
 	/** @var ZendAfi_View_Helper_ReseauxSociaux */
 	protected $_helper;
 
@@ -29,69 +29,85 @@ class ZendAfi_View_Helper_ReseauxSociauxTest extends ViewHelperTestCase {
 
 	public function setUp() {
 		parent::setUp();
-		$_SERVER["HTTP_HOST"] = 'localhost';
-		defineConstant('PATH_SKIN', '');
+		$_SERVER['HTTP_HOST'] = 'localhost';
 		$this->_helper = new ZendAfi_View_Helper_ReseauxSociaux();
 		$this->_helper->setView(new ZendAfi_Controller_Action_Helper_View());
 	}
 
 
 	/** @test */
-	public function withArticleLinksShouldContainsArticleUrl() {
-		$this->_html = $this->_helper->reseauxSociaux(Class_Article::newInstanceWithId(123456789));
-		$this->assertContains('cms/articleview/id/123456789', $this->_html);
+	public function withoutObjectLinksShouldBeEmpty() {
+		$this->assertEmpty($this->_helper->reseauxSociaux(null));
 	}
+}
 
 
-	/** @test */
-	public function withoutObjectLinksShouldBeEmpty() {
-		$this->_html = $this->_helper->reseauxSociaux(null);
-		$this->assertEmpty($this->_html);
+class ZendAfi_View_Helper_ReseauxSociauxArticleTest extends ZendAfi_View_Helper_ReseauxSociauxTestCase {
+	public function setUp() {
+		parent::setUp();
+		$this->_html = $this->_helper
+			->reseauxSociaux($this->fixture('Class_Article', ['id' => 123456789,
+																												'titre' => 'an article',
+																												'contenu' => 'a content']));
 	}
 
+
 	/** @test */
-	public function withNoticeLinksShouldContainsNoticeUrl() {
-		$this->_html = $this->_helper->reseauxSociaux(Class_Notice::newInstanceWithId(777, ['titre_principal' => 'Tarzan',
-																																												'clef_alpha' => 'tarzan']));
-		$this->assertContains('recherche/viewnotice/clef/tarzan/id/777', $this->_html);
+	public function linksShouldContainsArticleUrl() {
+		$this->assertContains('cms/articleview/id/123456789', $this->_html);
 	}
+}
 
-	/** @test **/
-	public function withNoticeLinkFacebookShouldBeAOnclickShareFacebookTarzan() {
-		$this->_html = $this->_helper->reseauxSociaux(
-			Class_Notice::newInstanceWithId(777, 
-																			['titre_principal' => 'Tarzan',
+
+class ZendAfi_View_Helper_ReseauxSociauxNoticeTest extends ZendAfi_View_Helper_ReseauxSociauxTestCase {
+	public function setUp() {
+		parent::setUp();
+		$this->_html = $this->_helper
+			->reseauxSociaux($this->fixture('Class_Notice', 
+																			['id' => 777, 
+																			 'titre_principal' => 'Tarzan',
 																			 'clef_alpha' => 'tarzan',
-																			 'resume' => 'Le livre de la jungle.',
+																			 'resume' => 'Le livre de la jungle',
 																			 'url_vignette'=>'desphotos.com/tarzan.png']));
+	}
+
+
+	/** @test */
+	public function linksShouldContainsNoticeUrl() {
 		$this->assertContains('recherche/viewnotice/clef/tarzan/id/777', $this->_html);
 	}
+}
+
 	
+class ZendAfi_View_Helper_ReseauxSociauxProfileTest extends ZendAfi_View_Helper_ReseauxSociauxTestCase {
+	protected $_profile;
+
+	public function setUp() {
+		parent::setUp();
+		$this->_profile = $this->fixture('Class_Profil', 
+																		 ['id' => 77, 'libelle' => 'musique']);
+		$this->_html = $this->_helper->reseauxSociaux($this->_profile);
+	}
 
 	/** @test **/
 	public function withProfilLinkMailShouldBeOnClickShareByEMailProfilMusique(){
-		$this->_html = $this->_helper->reseauxSociaux(
-			Class_Profil::newInstanceWithId(77,['libelle'=>'musique']),['mail'=>'mail']);
-
-		$this->assertContains('/index/formulairecontact',$this->_html);
+		$this->assertContains('/index/formulairecontact',
+													$this->_helper->reseauxSociaux($this->_profile, 
+																												 ['mail' => 'mail']));
 	}
 
 	
 	/** @test **/
 	public function withProfilLinkFacebookShouldBeOnClickShareFacebookProfilMusique(){
-		$this->_html = $this->_helper->reseauxSociaux(
-			Class_Profil::newInstanceWithId(77,['libelle'=>'musique']));
-
-		$this->assertContains("$.getScript('/social-network/share/on/facebook/url",$this->_html);
+		$this->assertContains("/social-network/share/on/facebook/url",
+													$this->_html);
 	}
 
 
 	/** @test **/
 	public function withProfilLinkTwitterShouldBeOnClickShareTwitterProfilMusique(){
-		$this->_html = $this->_helper->reseauxSociaux(
-			Class_Profil::newInstanceWithId(77,['libelle'=>'musique']));
-
-		$this->assertContains("$.getScript('/social-network/share/on/twitter/url",$this->_html);
+		$this->assertContains("/social-network/share/on/twitter/url",
+													$this->_html);
 	}
 }