diff --git a/CONTRIB.fr.md b/CONTRIB.fr.md
new file mode 100644
index 0000000000000000000000000000000000000000..b5f68b8d798484d9121303ab4a7bc7d0fdabbb85
--- /dev/null
+++ b/CONTRIB.fr.md
@@ -0,0 +1,163 @@
+# Contribuer au code source
+
+## Contenu
+* [Prérequis](#pr-requis)
+* [Créer sa copie du projet](#cr-er-sa-copie-du-projet)
+* [Contribuer au code](#contribuer-au-code)
+* [Créer un nouveau skin](#cr-er-un-nouveau-skin)
+
+## Prérequis
+
+Les équipes de développement AFI et Biblibre utilisent le [sytème de gestion de développement](https://fr.wikipedia.org/wiki/Forge_%28informatique%29) libre [GitLab](https://www.gitlab.com) et le [système de gestion de version](https://fr.wikipedia.org/wiki/Gestion_de_versions) [Git](http://www.git-scm.com). Ce document décrit l'utilisation minimale nécessaire de ces deux outils pour pouvoir contribuer au code des projets maintenus par AFI et Biblibre. Néanmoins nous vous invitons à lire le livre [Pro Git](http://git-scm.com/book/fr).
+
+Nous hébergeons les codes sources des projets sur une instance de GitLab accessible à l'URL https://git.afi-sa.fr. Les projets publics sont accessibles sans compte à l'URL https://git.afi-sa.fr/public.
+
+
+## Créer sa copie du projet
+
+### Créer un compte gitlab
+
+Depuis la page [Sign Up](http://git.afi-sa.fr/users/sign_up) vous pouvez créer votre compte. Un mail sera automatiqument envoyé pour vous confirmer l'accès. 
+
+
+### Cloner le projet
+
+Une fois connecté, depuis la [page du project OPACCE](http://git.afi-sa.fr/afi/opacce), cliquez sur le bouton **Fork repository**. Vous pouvez aussi cloner le projet via [ce lien](http://git.afi-sa.fr/afi/opacce/fork).
+
+Cela vous créera une copie intégrale du projet, accessible publiquement à l'adresse http://git.afi-sa.fr/mon_compte/opacce.
+
+
+L'accès SSH au dépôt git est donné sur la page d'accueil de votre projet. Par exemple git@git.afi-sa.fr:mon_compte/opacce.git
+
+
+### Installer l'accès SSH
+
+Le poussage de modifications sur gitlab requiert un accès ssh.  Sur [la page de modification de votre profil](http://git.afi-sa.fr/profile), à l'onglet [SSH Keys](http://git.afi-sa.fr/profile/keys), le lien [Add SSH Key](http://git.afi-sa.fr/profile/keys/new) permet d'ajouter une clé.
+
+Si vous posséder déjà une clé sur votre poste de travail dans **~/.ssh/id_rsa.pub**, copiez le contenu.
+
+Sinon pour [générer une clé SSH sur votre poste de travail](http://git.afi-sa.fr/help/ssh), utilisez la commande suivante:
+```bash
+ssh-keygen -t rsa -C "addresse_email@domaine.ext"
+```
+
+et pour afficher le contenu:
+```bash
+cat ~/.ssh/id_rsa.pub
+```
+
+
+## Contribuer au code
+
+### Installer sa copie de l'OPAC
+
+L'installation se déroule comme décrit [dans la procédure d'installation](INSTALL.md), excepté que la commande pour cloner le projet décrite dans la section [Récupération des sources](INSTALL.md#Récupération-des-sources) utilise votre propre dépôt:
+```bash
+cd /var/www
+git clone git@git.afi-sa.fr:mon_compte/opacce.git
+```
+
+### Faire des modifications et les pousser vers gitlab
+
+Une fois quelques modifications effectuées, l'envoi des données se fait en deux temps.
+
+1. Commit des modifications sur votre machine en local
+```bash
+git commit -a -m "Commentaires des modifications"
+```
+
+2. Pousser les modifications de votre branche master vers gitlab (origin):
+```bash
+git push origin master
+```
+
+Pour plus de détails, consultez [Pro Git](http://git-scm.com/book/fr)
+
+
+### Proposer les modifications aux mainteneurs de la version officielle
+
+Sur la page de votre projet GitLab, onglet **Merge Requests**, cliquez sur le lien **+ New Merge Request** et remplissez les différents champs pour décrire vos modifications. 
+
+
+### Récupérer les dernières modifications de la version officielle
+
+Tout d'abord, il faut déclarer le dépôt de la version officielle (upstream) dans votre projet local:
+```bash
+git remote add upstream git@git.afi-sa.fr:afi/opacce.git
+```
+
+Ceci fait, vous pouvez fusionner les modifications dans votre branche:
+
+```bash
+# Télécharge toutes les nouvelles modifications du dépôt distant
+git fetch upstream master
+# Fusionne les nouvelles modifications dans votre répertoire
+git merge upstream/master
+# Pousse la fusion sur gitlab
+git push origin master
+```
+
+
+
+## Créer un nouveau skin
+
+### Création
+
+Se placer dans le répertoire skins à la racine de l'OPAC et recopier le skin modele
+
+```bash
+cd skins
+cp -a ../public/opac/skins/modele mon_skin
+```
+
+Aller dans la configuration d'un profil de l'OPAC, le nouveau skin devrait être disponible dans le sélecteur de thème.
+
+
+
+### Sauvegarde sur GitLab
+
+Créer le projet sur [GitLab](https://git.afi-sa.fr) pour stocker les sources. Par exemple https://git.afi-sa.fr/mon_compte/mon_skin.
+
+Aller dans le répertoire mon_skin et initialiser le dépôt:
+
+```bash
+cd mon_skin
+git init
+git remote add origin -t master git@git.afi-sa.fr:mon_compte/mon_skin.git
+git add *
+git commit -m "Premier commit"
+git push origin master
+```
+
+Ceci fait, les nouveaux fichiers devraient être accessibles sur https://git.afi-sa.fr/mon_compte/mon_skin/files
+
+
+### Description des répertoires
+
+* **css/** contient le fichier global.css sur lequel travailler. Les autres fichiers sont destinés à devenir obsolètes.
+* **images/** les icônes, dont **images/support/** pour les types de support. Les fichiers doivent être nommés comme suit: **support_id_.png**, par exemple **support_1.png** pour les livres.
+* **templates/** les modèles de rendu boite de la page d'accueil. Les fichiers doivent êtres nommés en séparant les mots par des tirets bas **_**, qui seront dans la configuration des boîtes **Style de boîte**. Chaque modèle de boîte peut inclure les tags **{TITRE}**, **{RSS}**, **{CONTENU}**. Pour avoir un rendu conditionnel, le fichier peut inclure les conditions **{IF-TITRE}**, **{IF-RSS}**, **{IF-CONTENU}** suivi de la balise **{ENDIF}**
+
+```html
+<div class="right-box">
+	<div class="right-box-inner">
+		{IF-TITRE}
+		<div class="header">
+			<div><h1>{TITRE}</h1></div>
+			<div class="rss">{RSS}</div>
+		</div>
+		{ENDIF}
+		<div class="content">
+			{CONTENU}
+		</div>
+	</div>
+</div>
+```
+
+
+Tous les fichiers de vue du répertoire **application/modules/opac/views/scripts** peuvent être redéfinis dans un répertoire html. Les principaux sont:
+* **footer.phtml** pour le pied de page
+* **banniere.phtml** pour l'en-tête
+* **skin_head.phtml** pour rajouter des éléments dans la balise **head** du site
+* **accueil.phtml** pour la page d'accueil
+* **contenu.phtml** pour les autres pages
\ No newline at end of file
diff --git a/VERSIONS b/VERSIONS
index 757ba065de739e2d0cc953fb6aed6ee21bfd6685..4cbf92418ea1739da1d7fa0d57aea0a40994e9d8 100644
--- a/VERSIONS
+++ b/VERSIONS
@@ -1,12 +1,45 @@
-09/06/2014 - v6.45
-- (alpha) ticket #13014: navigation dans les notices
+16/06/2014 - v6.45.3
+- ticket #13866 : Correction de l'indexation des facettes de domaines pour les sitothèques
+- ajout de l'indexation temps réel des sitothèques lors de leur enregistrement.
+
+
+12/06/2014 - v6.45.2
+- ticket #14170 : Ajout d'un bouton de suppression des avis en visualisation des notices lorsqu'on est connecté bibliothécaire
+- ticket #13906 : Correction de l'application de premier emplacement d'exemplaire trouvé à tous les exemplaires de la notice qui pouvait survenir dans certaines configurations de cosmogramme et d'export SIGB
+- ticket #14209 : Correction de la régression de l'import des périodiques Koha et Orphée, nécessite un réimport total des notices
+
+
+10/06/2014 - v6.45.1
+- Correction régression dans le chargement des préférences par défaut des modules pouvant entraîner un écran blanc.
+
+
+10/06/2014 - v6.45
+- ticket #13014: navigation dans les notices
   - les liens document précédent / suivant sont identifiés par les id #previousrecord et #nextrecord
   - le lien document précédent n'est pas affiché sur la première notice d'un résultat de recherche
   - le lien document suivant n'est pas affiché sur la dernière notice d'un résultat de recherche
 
-- (beta) connecteur afi-multimedia 
-  - ajout d'un service d'export des abonnés
- 
+- ticket #13931: connecteur afi-multimedia
+	- ajout d'un service d'export des abonnés
+	- support du cryptage SSL pour tous les services
+
+- ticket #13582 : Possibilité de définir dans la configuration de la boite login un profil auquel se rendre lors de la déconnexion
+
+- ticket #13060 : Amélioration du paramétrage de l'écran d'inscription
+	- ajout d'un deuxième champ pour confirmer l'email
+	- uniformisation du captcha avec le formulaire de contact
+	- les messages affichés sur la page de création et de confirmation sont configurables via la clé à molette de la page
+	- les messages d'erreur de saisie du formulaire sont reliés au champs concernés
+	- le mail de confirmation est aussi envoyé 
+
+- ticket #13776 : SIGB Aloès, web services: amélioration de la fermeture des sessions qui pouvait perturber le fonctionnement d'Aloès
+
+- ticket #12422 : Connecteurs bibliothèque numérique: amélioration de la conformité au protocole CAS
+	- les "service tickets" CAS sont préfixés par "ST-"
+	- l'authentification et la validation ont la même URL de base
+
+- ticket #14199 : Filtrage des bots SISTRIX et VOILABOT pour qu'ils ne moissonnent que dans les plages horaires autorisées
+
 
 04/06/2014 - v6.44.7
 - ticket #14019 : Correction de l'export unimarc des listes de prêts
@@ -22,6 +55,7 @@
 - ticket #13776 : mise à jour de la fermeture de session avec le web service ALOES
 
 
+
 28/05/2014 - v6.44.4
 - ticket #13574 : Correction intégration des notices provenant de GAM lorsqu'elles contiennent le caractère 0x92
 
diff --git a/application/modules/admin/controllers/AccueilController.php b/application/modules/admin/controllers/AccueilController.php
index 27792abc7b324e8eb8a7f306a006e71eba2646c6..47c99d2c9bb5c7c29fdfa2eab969c35b9510e734 100644
--- a/application/modules/admin/controllers/AccueilController.php
+++ b/application/modules/admin/controllers/AccueilController.php
@@ -152,11 +152,6 @@ class Admin_AccueilController extends Zend_Controller_Action {
 
 
 	public function loginAction() {
-		$this->view->getHelper('ComboProfils')
-			->setTagId('profil_redirect')
-			->setTagName('profil_redirect')
-			->addEmptyOption();
-
 		$this->_simpleAction();
 	}
 
diff --git a/application/modules/admin/controllers/SitoController.php b/application/modules/admin/controllers/SitoController.php
index d06e0cd4afddb3136f85338243d25f1dfb9d4576..0cd675a52c8cf6ae7205ecad1d6b8df75a03f209 100644
--- a/application/modules/admin/controllers/SitoController.php
+++ b/application/modules/admin/controllers/SitoController.php
@@ -288,6 +288,8 @@ class Admin_SitoController extends Zend_Controller_Action {
 			if ($site
 					->updateAttributes($post)
 					->save()) {
+				$site->index();
+				(new Storm_Cache())->clean();
 				$this->_helper->notify($this->_('Le site "%s" a été sauvegardé', $site->getTitre()));
 				$this->_redirect('/admin/sito/sitoedit/id/'.$site->getId());
 				return;
diff --git a/application/modules/admin/views/scripts/modules/auth_form.phtml b/application/modules/admin/views/scripts/modules/auth_form.phtml
index 4b8f12f734ffab60176177fd84a3fda077958262..409e5a6fcdf99b59af1104c0304c14633149de5d 100644
--- a/application/modules/admin/views/scripts/modules/auth_form.phtml
+++ b/application/modules/admin/views/scripts/modules/auth_form.phtml
@@ -66,7 +66,6 @@
   <td class="gauche"><input type="text" name="lien_compte" size="50" value="<?php print($this->preferences["lien_compte"]); ?>"></td>
 </tr>
 
-
 <tr>
   <td class="droite">Libelle lien nouveau compte &nbsp;</td>
   <td class="gauche"><input type="text" name="lien_creer_compte" size="50" value="<?php print($this->preferences["lien_creer_compte"]); ?>"></td>
@@ -75,7 +74,24 @@
 <tr>
 	<td class="droite">Basculer automatiquement sur le profil:&nbsp;</td>
 	<td class="gauche">
-    <?php echo $this->ComboProfils('ALL', 'ALL', $this->preferences['profil_redirect']);
+    <?php 
+		$this->getHelper('ComboProfils')
+				 ->setTagId('profil_redirect')
+				 ->setTagName('profil_redirect')
+				 ->addEmptyOption();
+		echo $this->comboProfils('ALL', 'ALL', $this->preferences['profil_redirect']);
+    ?>
+	</td>
+</tr>
+
+<tr>
+	<td class="droite">Déconnexion : basculer sur le profil:&nbsp;</td>
+	<td class="gauche">
+    <?php $this->getHelper('ComboProfils')
+							 ->setTagId('profil_logout_redirect')
+							 ->setTagName('profil_logout_redirect')
+							 ->addEmptyOption();
+		echo $this->comboProfils('ALL', 'ALL', $this->preferences['profil_logout_redirect']);
     ?>
 	</td>
 </tr>
diff --git a/application/modules/admin/views/scripts/modules/auth_register.phtml b/application/modules/admin/views/scripts/modules/auth_register.phtml
index 4067b5c6de403748b4b36d39d9246f2e5c9f1fda..0dc806e6ca297c22ea3e005a0527177937e5a220 100644
--- a/application/modules/admin/views/scripts/modules/auth_register.phtml
+++ b/application/modules/admin/views/scripts/modules/auth_register.phtml
@@ -9,6 +9,14 @@
 			<td class="droite">Titre &nbsp;</td>
 			<td class="gauche"><input type="text" name="titre" size="40" value="<?php print($this->preferences["titre"]); ?>"></td>
 		</tr>
+		<tr>
+			<td class="droite">Texte d'aide &nbsp;</td>
+			<td class="gauche"><textarea cols="70" rows="5" name="register_help"><?php print($this->preferences["register_help"]); ?></textarea></td>
+		</tr>
+		<tr>
+			<td class="droite">Texte de confirmation &nbsp;</td>
+			<td class="gauche"><textarea cols="70" rows="5" name="register_confirm"><?php print($this->preferences["register_confirm"]); ?></textarea></td>
+		</tr>
 		
 
 	</table>
diff --git a/application/modules/opac/controllers/AbonneController.php b/application/modules/opac/controllers/AbonneController.php
index aaf71ff92b898faad34ff183ccff877217431524..a4c1c6b765049a7810416cb7dbde7a3335779634 100644
--- a/application/modules/opac/controllers/AbonneController.php
+++ b/application/modules/opac/controllers/AbonneController.php
@@ -143,9 +143,10 @@ class AbonneController extends ZendAfi_Controller_Action {
 
 	public function delavisnoticeAction(){
 		$this->_forward('delavisnotice', 'blog', 'opac', ['id' => $this->_getParam('id'),
-																											'redirect' => 'abonne/viewavis/id/'.$this->_user->getId()]);
+																											'redirect' =>'abonne/viewavis/id/'.$this->_user->getId(),
+																											'js_redirect' => $this->_getParam('expressionRecherche')? true: false]);
 	}
-
+		
 
 	private function handleAvis($readSourceMethod, $writeAvisMethod) {
 		$cls_user= new Class_Users();
diff --git a/application/modules/opac/controllers/AuthController.php b/application/modules/opac/controllers/AuthController.php
index 70e6c899a493628f74d3d6a3f6048756d9cc1429..e233ecef37f0a530598de46bc8efce18d2e8da50 100644
--- a/application/modules/opac/controllers/AuthController.php
+++ b/application/modules/opac/controllers/AuthController.php
@@ -18,18 +18,14 @@
  * 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: AUTHENTIFICATION ABONNE
-//
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
 class AuthController extends ZendAfi_Controller_Action {
-	function init()	{
+	public function init()	{
 		$this->view->locale = Zend_Registry::get('locale');
 	}
 
 
-	function indexAction()	{
+	public function indexAction()	{
 		$this->_redirect('/opac');
 	}
 
@@ -43,10 +39,12 @@ class AuthController extends ZendAfi_Controller_Action {
 		return $this->_request->getParam('service');
 	}
 
+
 	public function notify($message) {
 		$this->_helper->notify($message);
 	}
 
+
 	public function getRedirectDefaultUrl() {
 		return $this->_request->getParam('redirect','/opac');
 	}
@@ -57,7 +55,6 @@ class AuthController extends ZendAfi_Controller_Action {
 	}
 
 
-
 	public function _authenticate() {
 		$f = new Zend_Filter_StripTags();
 		$username = $f->filter($this->_request->getPost('username'));
@@ -77,6 +74,12 @@ class AuthController extends ZendAfi_Controller_Action {
 	}
 
 
+	//see http://www.jasig.org/cas/protocol#cas-uris
+	function validateAction() {
+		$this->_forward('validate', 'cas-server');
+	}
+
+
 	function loginAction() {
 		$this->view->preferences = Class_Profil::getCurrentProfil()->getCfgModulesPreferences('auth','login');		
 		$redirect = $this->_getParam('redirect', '/opac');
@@ -92,7 +95,7 @@ class AuthController extends ZendAfi_Controller_Action {
 	}
 
 
-	function ajaxLoginAction(){
+	public function ajaxLoginAction(){
 		$this->view->preferences = Class_Profil::getCurrentProfil()->getCfgModulesPreferences('auth','login');	
 		$strategy = Auth_Strategy_Abstract::strategyForController($this);
 		$strategy->disableRedirect();
@@ -109,7 +112,7 @@ class AuthController extends ZendAfi_Controller_Action {
 	}
 
 
-	function popupLoginAction() {
+	public function popupLoginAction() {
 		$page_settings = Class_Profil::getCurrentProfil()->getCfgModulesPreferences('auth','login');
 		$widget_settings = Class_Profil::getCurrentProfil()->getModuleAccueilPreferencesByType('LOGIN');
 		$this->view->preferences = 
@@ -118,7 +121,7 @@ class AuthController extends ZendAfi_Controller_Action {
 			:( $page_settings 
 				 ? $page_settings 
 				 : []);
-		//$this->view->preferences = 
+
 		$this->view->redirect = $this->_getParam('redirect');
 
 		$this->renderPopupResult($this->view->_('Authentification'),
@@ -126,23 +129,21 @@ class AuthController extends ZendAfi_Controller_Action {
 	}
 
 
-	function boiteLoginAction() {
+	public function boiteLoginAction() {
 		$this->view->preferences = Class_Profil::getCurrentProfil()->getModuleAccueilPreferencesByType('LOGIN');	
 		$strategy = Auth_Strategy_Abstract::strategyForController($this);
 		$strategy->setDefaultUrl($this->_request->getServer('HTTP_REFERER'));
 		$strategy->processLogin();
-		
 	}
 	
 
-	function ajaxlostpassAction()	{
-		if($_POST)
-		{
-			$user=ZendAfi_Filters_Post::filterStatic($this->_request->getPost('username'));
+	public function ajaxlostpassAction()	{
+		if ($this->_request->isPost()) {
+			$user = ZendAfi_Filters_Post::filterStatic($this->_request->getPost('username'));
 			$classe_user = new Class_Users();
-			$ret=$classe_user->lostpass($user);
-			$this->view->message=$this->messages[$ret["error"]];
-			$this->view->message_mail=$ret["message_mail"];
+			$ret = $classe_user->lostpass($user);
+			$this->view->message = $this->messages[$ret["error"]];
+			$this->view->message_mail = $ret["message_mail"];
 		}
 		$this->view->username=$user;
 		$viewRenderer = $this->getHelper('ViewRenderer');
@@ -150,14 +151,15 @@ class AuthController extends ZendAfi_Controller_Action {
 	}
 
 
-	function logoutAction()	{
+	public function logoutAction()	{
 		ZendAfi_Auth::getInstance()->clearIdentity();
-		$this->_redirectToParentProfil();
+		$profil = Class_Profil::getCurrentProfil();
+		$this->_redirectToLogoutProfil($profil->getModuleAccueilPreferencesByType('LOGIN')); 
 	}
 
 
-	function lostpassAction() {
-		if($_POST) {
+	public function lostpassAction() {
+		if($this->_request->isPost()) {
 			$user = ZendAfi_Filters_Post::filterStatic($this->_request->getPost('username'));
 			$classe_user = new Class_Users();
 			$ret=$classe_user->lostpass($user);
@@ -168,46 +170,82 @@ class AuthController extends ZendAfi_Controller_Action {
 	}
 
 
-	function registerAction()	{
+	public function registerAction()	{
+		$this->view->preferences = Class_Profil::getCurrentProfil()->getCfgModulesPreferences('auth', 'register');
 		if (Class_AdminVar::get('INTERDIRE_ENREG_UTIL'))
 			$this->_redirect('/');
 
-		if ($this->_request->isPost())
-		{
+		$this->view->form = ZendAfi_Form::newWithOptions(['action' => $this->view->url(['module'=>'opac',
+																																	'controller'=>'auth',
+																																	'action'=>'register'])])
+
+			->addElement('text', 'login', ['label' => $this->view->_('Identifiant'),
+																		 'maxlength' => 20,
+																		 'required' => true,
+																		 'validators' => ['LoginExists']])
+
+			->addElement('password', 'mdp', ['label' => $this->view->_('Mot de passe'),
+																			 'maxlength' => 15,
+																			 'required' => true])
+
+			->addElement('password', 'mdp2', ['label' => $this->view->_('Confirmez votre mot de passe'),
+																				'maxlength' => 15,
+																				'required' => true,
+																				'validators' => [new ZendAfi_Validate_PasswordEquals('mdp')]])
+
+			->addElement('email', 'mail', ['label' => $this->view->_('E-mail'),
+																		 'maxlength' => 50,
+																		 'required' => true,
+																		 'validators' => ['MailExists']])
+
+			->addElement('email', 'mail2', ['label' => $this->view->_('Confirmez votre e-mail'),
+																			'maxlength' => 50,
+																			'required' => true,
+																			'validators' => [new ZendAfi_Validate_MailEquals('mail')]])
+
+			->addDisplayGroup(['login', 'mdp', 'mdp2', 'mail', 'mail2'], 
+												'fields',
+												['legend' => ''])
+
+			->addElement('captcha', 'captcha', array('captcha' => 'Image',
+																							 'label' => $this->view->_('Recopiez le code'),
+																							 'captchaOptions' => array('font' => PATH_FONTS.'/Vera.ttf',
+																																				 'imgDir' => PATH_CAPTCHA,
+																																				 'imgUrl' => URL_CAPTCHA)))
+			->addDisplayGroup(['captcha'], 
+												'security',
+												['legend' => $this->view->_('Sécurité'),
+												 'required' => true])
+			->addElement('submit','submit', ['label' => $this->view->_('Valider')]);
+
+
+		if ($this->_request->isPost() && $this->view->form->isValid($this->_request->getPost()))	{
 			// recup _post
-			$data=ZendAfi_Filters_Post::filterStatic($this->_request->getPost());
+			$data = ZendAfi_Filters_Post::filterStatic($this->_request->getPost());
 			$class_user = new Class_Users();
+			$data['cle'] = md5($data['mail']);
 			$ret=$class_user->registerUser($data);
 
 			// Affichage des erreurs
-			if($ret["error"])
-			{
-				$this->view->cle = $this->getCleActivation();
+			if(isset($ret["error"])) {
 				$this->view->login = $data["login"];
 				$this->view->email = $data["mail"];
-				$this->view->error = '<div align="center" class="error">'.$ret["error"].'</div>';
+				$this->view->email2 = $data["mail2"];
+				$this->view->error = '<div align="center" class="error">' . $ret["error"] . '</div>';
 			}
-			$this->view->message_mail=$ret["message_mail"];
+			$this->view->message_mail=$ret["message_confirm"];
 		}
 
 		// Opération terminée
-		if($this->view->message_mail)
-		{
-			$this->view->titre=$this->view->_("Votre demande d'inscription");
+		if($this->view->message_mail) {
+			$this->view->titre = $this->view->_("Votre demande d'inscription");
 			$viewRenderer = $this->getHelper('ViewRenderer');
 			$viewRenderer->renderScript('auth/message.phtml');
 		}
-
-		// Formulaire de saisie
-		$this->view->img_captcha = '<img src="'.BASE_URL.'/auth/generateCaptcha" />';
-		$this->view->cle = $this->getCleActivation();
 	}
 	
-//------------------------------------------------------------------------------------------------------
-// Activation d'une nouvelle inscription
-//------------------------------------------------------------------------------------------------------
-	function activeuserAction()
-	{
+	
+	public function activeuserAction() {
 		if (!$cle = $this->_request->getParam('c'))
 			$this->_redirect('/');
 
@@ -217,11 +255,8 @@ class AuthController extends ZendAfi_Controller_Action {
 		$this->view->info = urldecode(str_replace('%0D%0A',"<br />", $info));
 	}
 
-//------------------------------------------------------------------------------------------------------
-// Captcha
-//------------------------------------------------------------------------------------------------------
-	function generatecaptchaAction()
-	{
+
+	public function generatecaptchaAction() {
 		$md5_hash = md5(rand(0,999));
 		$security_code = substr($md5_hash, 15, 5);
 
@@ -231,32 +266,18 @@ class AuthController extends ZendAfi_Controller_Action {
 		$white = ImageColorAllocate($image, 255, 255, 255);    // bg image
 		ImageString($image, 3, 30, 3, $security_code, $white);
 
-		header("Content-Type: image/jpeg");
+		header('Content-Type: image/jpeg');
 		ImageJpeg($image);
 		$viewRenderer = $this->getHelper('ViewRenderer');
 		$viewRenderer->setNoRender();
 	}
-
-//------------------------------------------------------------------------------------------------------
-// genere une cle aleatoire pour l'activation de compte par URL
-//------------------------------------------------------------------------------------------------------
-	function getCleActivation() {
-		$cle = '';
-		for ($i=0; $i< 10; $i++)
-		{
-			$nb_ascii = rand(1,26) + 64 ;
-			$cle.=chr($nb_ascii).rand(0,9);
-		}
-		return($cle);
-	}
 }
 
 
 
-
 abstract class Auth_Strategy_Abstract {
-	protected $redirect_url='';
-	protected $disable_redirect=false;
+	protected $redirect_url = '';
+	protected $disable_redirect = false;
 	
 	static public function strategyForController($controller) {
 		if ($controller->isCasRequest() && static::isLogged())
@@ -273,7 +294,7 @@ abstract class Auth_Strategy_Abstract {
 	
 
 	static protected function isLogged() {
-		return 	Class_Users::getIdentity();
+		return Class_Users::getIdentity();
 	}
 	
 	public function disableRedirect() {
@@ -281,8 +302,8 @@ abstract class Auth_Strategy_Abstract {
 	}
 
 	public function __construct($controller) {
-		$this->controller=$controller;
-		$this->default_url=$this->controller->getRedirectDefaultUrl();
+		$this->controller = $controller;
+		$this->default_url = $this->controller->getRedirectDefaultUrl();
 	}
 
 	public function getRequest(){
@@ -346,7 +367,6 @@ class Auth_Strategy_Logged extends Auth_Strategy_Abstract{
 
 class Auth_Strategy_Cas_Abstract extends Auth_Strategy_Abstract{
 	public function urlServiceCas(){
-
  		if ($url_musicme=$this->redirectMusicMe())
 			return $url_musicme;
 		$ticket = (new Class_CasTicket())->getTicketForCurrentUser();
diff --git a/application/modules/opac/controllers/BlogController.php b/application/modules/opac/controllers/BlogController.php
index 0e42896f8ad870eb7a47c573d73deeeac4787b26..7861a738c497f841e7fcb9b21626521b5631bb6c 100644
--- a/application/modules/opac/controllers/BlogController.php
+++ b/application/modules/opac/controllers/BlogController.php
@@ -22,7 +22,7 @@
 //  OPAC3: Blog
 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
-class BlogController extends Zend_Controller_Action {
+class BlogController extends ZendAfi_Controller_Action {
 	use Trait_Translator;
 
 	private $_user = null;								// Le user connecté
@@ -75,9 +75,13 @@ class BlogController extends Zend_Controller_Action {
 			$avis->delete();
 			$this->_helper->notify($this->_("Avis supprimé"));
 		}
+		if(!$this->_getParam('js_redirect') === true){
+			$redirect = $this->_getParam('redirect', 'blog/viewauteur/id/'.$avis->getIdUser());
+			$this->_redirect($redirect);
+			return;
+		}
 
-		$redirect = $this->_getParam('redirect', 'blog/viewauteur/id/'.$avis->getIdUser());
-		$this->_redirect($redirect);
+		$this->_javascriptRedirectToReferrer();
 	}
 
     
diff --git a/application/modules/opac/controllers/IndexController.php b/application/modules/opac/controllers/IndexController.php
index caddf41ff1bb995585df204a12450091ffe86042..4eb5668ec0a778e9836149bd82a58bfaa914ce05 100644
--- a/application/modules/opac/controllers/IndexController.php
+++ b/application/modules/opac/controllers/IndexController.php
@@ -78,7 +78,7 @@ class IndexController extends Zend_Controller_Action {
 
 
 	protected function _formulaireContact() {
-		$form = $this->view->newForm(array('id' => 'contact'))
+		return $this->view->newForm(array('id' => 'contact'))
 			->setAttrib('class', 'zend_form')
 			->addElement('text', 'nom', array(
 																				'label' => $this->view->_('Nom').' *',
@@ -126,42 +126,22 @@ class IndexController extends Zend_Controller_Action {
 															'mail'), 
 												'form_coordonnees',
 												array('legend' => $this->view->_('Vos coordonnées')))
+
 			->addDisplayGroup(
 												array('sujet', 
 															'message'),
 												'form_message',
-												array('legend' => $this->view->_('Votre message')));
-
-		if (!defined('NOCAPTCHA')) {//desactive les captchas pour les tests :( 
-			$this->_deleteCaptchaOlderThanOneMinute();
+												array('legend' => $this->view->_('Votre message')))
 
-			$form
-				->addElement('captcha', 'captcha', array('captcha' => 'Image',
-																								 'label' => $this->view->_('Recopiez le code'),
-																								 'captchaOptions' => array('font' => PATH_FONTS.'/Vera.ttf',
-																																					 'imgDir' => PATH_CAPTCHA,
-																																					 'imgUrl' => URL_CAPTCHA)))
+			->addElement('captcha', 'captcha', array('captcha' => 'Image',
+																							 'label' => $this->view->_('Recopiez le code'),
+																							 'captchaOptions' => array('font' => PATH_FONTS.'/Vera.ttf',
+																																				 'imgDir' => PATH_CAPTCHA,
+																																				 'imgUrl' => URL_CAPTCHA)))
 			->addDisplayGroup(
 												array('captcha'),
 												'form_security',
 												array('legend' => $this->view->_('Sécurité')));
-		}
-		return $form;
-	}
-
-	
-	protected function _deleteCaptchaOlderThanOneMinute() {
-		if (!file_exists(PATH_CAPTCHA))
-				mkdir(PATH_CAPTCHA);
-
-		$pngs = glob( PATH_CAPTCHA.'*.png' );
-		if (!is_array($pngs))
-			return;
-
-		foreach ($pngs as $png) {
-			if ((time() - filemtime($png )) > 60 )
-				unlink($png);
-		}
 	}
 
 
diff --git a/application/modules/opac/views/scripts/auth/register.phtml b/application/modules/opac/views/scripts/auth/register.phtml
index de731a24d2280992d482217aad8dd446e6c3cb2e..63214280aae939dc572908b804f6786f8ff2b92c 100644
--- a/application/modules/opac/views/scripts/auth/register.phtml
+++ b/application/modules/opac/views/scripts/auth/register.phtml
@@ -1,41 +1,11 @@
-<form name="form_register" action="<?php 
-                                   echo $this->url(['module'=>'opac',
-                                                    'controller'=>'auth',
-                                                    'action'=>'register']); ?>" method="post">
-    <div class="form" style="margin:0 auto">
-      <?php $this->openBoite($this->current_module["preferences"]["titre"]); ?>
-      <table cellpadding="1" cellspacing="5" width="100%">
-	      <tr>
-	        <td class="masque" width="45%"><?php echo $this->_('Identifiant') ?></td>
-	        <td class="saisie" colspan="2"><input type="text" name="login" maxlength="20" value="<?php echo $this->login; ?>"></td>
-	      </tr>
-	      <tr>
-	        <td class="masque"><?php echo $this->_('Mot de passe') ?></td>
-	        <td class="saisie" colspan="2"><input type="password" name="mdp" maxlength="15"></td>
-	      </tr>
-	      <tr>
-	        <td class="masque"><?php echo $this->_('Confirmer votre mot de passe') ?></td>
-	        <td class="saisie" colspan="2"><input type="password" name="mdp2" maxlength="15"></td>
-	      </tr>
-	      <tr>
-	        <td class="masque"><?php echo $this->_('E-mail') ?></td>
-	        <td class="saisie" colspan="2"><input type="text" name="mail" maxlength="50" value="<?php echo $this->email; ?>"></td>
-	      </tr>
-	      <tr>
-	        <td class="masque" style="padding-bottom:0px"><?php echo $this->_('Copiez le code anti-spam') ?></td>
-	        <td class="saisie" style="padding-bottom:0px"><?php echo $this->img_captcha; ?></td>
-	      </tr>
-	      <tr>
-	        <td class="masque" style="padding-top:0px">ici</td>
-	        <td class="saisie" style="padding-top:0px">
-	          <input type="text" name="captcha" style="height:15px;">
-	          <input type="hidden" value="<?php echo $this->cle; ?>" name="cle">
-	        </td>
-	      </tr>
-      </table>
-      <?php echo $this->bouton('type=V', 'form=form_register'); ?>
-      <?php $this->closeBoite() ?>
-    </div>
+<?php $this->openBoite($this->preferences["titre"]); ?>
+<p><?php echo nl2br($this->preferences["register_help"]); ?></p>
+
+<?php
+
+echo $this->renderForm($this->form);
+
+?>
 
-</form>
 <?php echo $this->error; ?>
+<?php $this->closeBoite() ?>
diff --git a/cosmogramme/cosmozend/application/modules/cosmo/controllers/AuthController.php b/cosmogramme/cosmozend/application/modules/cosmo/controllers/AuthController.php
index e057bb565e9d0ba8d076c533f3795368785e1745..66ae0d552d92d598e5c2180173947d1c08315db9 100644
--- a/cosmogramme/cosmozend/application/modules/cosmo/controllers/AuthController.php
+++ b/cosmogramme/cosmozend/application/modules/cosmo/controllers/AuthController.php
@@ -23,6 +23,9 @@ class Cosmo_AuthController extends Zend_Controller_Action {
 	public function indexAction() {
 
 	}
+
+
+	public function notLoggedAction() {}
 }
 
 ?>
\ No newline at end of file
diff --git a/cosmogramme/cosmozend/application/modules/cosmo/controllers/RunLogController.php b/cosmogramme/cosmozend/application/modules/cosmo/controllers/RunLogController.php
new file mode 100644
index 0000000000000000000000000000000000000000..baa7d90468c65265b8c2553e967c21ab37381ca2
--- /dev/null
+++ b/cosmogramme/cosmozend/application/modules/cosmo/controllers/RunLogController.php
@@ -0,0 +1,62 @@
+<?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 Cosmo_RunLogController extends Zend_Controller_Action {
+	public function preDispatch() {
+		$this->cosmoPath = $this->view->cosmoPath = new CosmoPaths();
+	}
+
+
+	public function byDateAction() {
+		$this->view->date = $this->_getParam('date');
+		$this->view->runs = Class_Cosmogramme_Integration::findAllBy(
+			['traite' => $this->_getParam('date', '0000-00-00'),
+			 'order' => 'id desc']);
+	}
+
+
+	public function syntheseAction() {
+		if (!$run = Class_Cosmogramme_Integration::find((int)$this->_getParam('id')))
+			$this->_redirect($this->cosmoPath->getCosmoBaseUrl() . 'php/integre_log.php', 
+											 ['prependBase' => false]);
+		$this->view->date = $run->getTraite();
+		$this->view->run = $run;
+	}
+
+
+	public function downloadAction() {
+		$this->_helper->getHelper('ViewRenderer')->setNoRender();
+		if ((!$run = Class_Cosmogramme_Integration::find((int)$this->_getParam('id')))
+				 || !$run->fileExists())
+			return;
+
+		$file_path = $run->getFilePath();
+		header('Content-type: application/force-download');
+		header('Content-Disposition: inline; filename="' . basename($file_path) . '"');
+		header('Content-Transfer-Encoding: Binary');
+		header('Content-length: ' . $run->getFileSize());
+		header('Content-Type: application/octet-stream');
+		header('Content-Disposition: attachment; filename="' . basename($file_path) . '"');
+		readfile($file_path);
+	}
+}
+?>
\ No newline at end of file
diff --git a/cosmogramme/cosmozend/application/modules/cosmo/views/scripts/auth/not-logged.phtml b/cosmogramme/cosmozend/application/modules/cosmo/views/scripts/auth/not-logged.phtml
new file mode 100644
index 0000000000000000000000000000000000000000..3821faff8239b37a3850bfbead55939bbbed4051
--- /dev/null
+++ b/cosmogramme/cosmozend/application/modules/cosmo/views/scripts/auth/not-logged.phtml
@@ -0,0 +1,2 @@
+<h1>Erreur</h1>
+Vous n'êtes plus connecté, veuillez vous identifier à nouveau.
diff --git a/cosmogramme/cosmozend/application/modules/cosmo/views/scripts/layout.phtml b/cosmogramme/cosmozend/application/modules/cosmo/views/scripts/layout.phtml
index b2b9a892c8b8fed08ecec63f3a34a5d5a8781b53..22b5dda78d8ccaa8b47993b7d4fe0be2acf68f98 100644
--- a/cosmogramme/cosmozend/application/modules/cosmo/views/scripts/layout.phtml
+++ b/cosmogramme/cosmozend/application/modules/cosmo/views/scripts/layout.phtml
@@ -18,14 +18,21 @@
  * 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 
  */
+
+$paths = new CosmoPaths();
 ?>
 <html>
 	<head>
 		<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
+		<link rel="stylesheet" type="text/css" media="screen" href="<?php echo $paths->getCosmoBaseUrl(); ?>css/main.css"/>
+		<link rel="stylesheet" type="text/css" media="screen" href="<?php echo $paths->getCosmoBaseUrl(); ?>css/menu.css"/>
+		<link rel="stylesheet" type="text/css" media="screen" href="<?php echo $paths->getCosmoBaseUrl(); ?>css/form.css"/>
+		<link rel="stylesheet" type="text/css" media="screen" href="<?php echo $paths->getCosmoBaseUrl(); ?>css/notice.css"/>
+		<link rel="stylesheet" type="text/css" media="screen" href="<?php echo $paths->getCosmoBaseUrl(); ?>css/nuage_tags.css"/>
+		<script type="text/javascript" language="javascript">var sUrlImg="<?php echo $paths->getCosmoBaseUrl(); ?>images/";</script>
+		<script src="<?php echo $paths->getCosmoBaseUrl(); ?>java_script/main.js" type="text/javascript" language="javascript"></script>
 	</head>
-	<body overflow="hidden" style="background-color:#f0f2f0;">
-		<div style="height:88px;border-bottom:2px solid #d5d5d5;padding-left:20px">
+	<body class="droite">
 			<?php echo $this->layout()->content; ?>
-		</div>
 	</body>
 </html>
diff --git a/cosmogramme/cosmozend/application/modules/cosmo/views/scripts/run-log/by-date.phtml b/cosmogramme/cosmozend/application/modules/cosmo/views/scripts/run-log/by-date.phtml
new file mode 100644
index 0000000000000000000000000000000000000000..af66b63f09ac69a0afbb99270566632eed872084
--- /dev/null
+++ b/cosmogramme/cosmozend/application/modules/cosmo/views/scripts/run-log/by-date.phtml
@@ -0,0 +1,60 @@
+<h1>Journal des intégrations du <?php echo $this->getHumanDate($this->date, 'EEEE d MMMM yyyy');?></h1>
+<div align="center">
+<table style="width:800px;margin-left:20px">
+	<tr>
+ 		<th width="15%" colspan="2" align="left">Date</th>
+ 		<th width="30%" align="left">Bibliothèque</th>
+		<th width="20%" align="left">Type de fichier</th>
+ 		<th width="20%" align="left">Type de transaction</th>
+		<th width="20%" align="left">Fichier</th>
+		<th width="9%" align="left">Taille</th>
+ 		<th width="9%" align="left">Fiches traitées</th>
+ 		<th width="9%" align="left">Erreurs</th>
+ 		<th width="9%" align="left">Anomalies</th>
+	</tr>
+	<?php foreach($this->runs as $run) { ?>
+	<tr>
+		<td align="center"><?php 
+		echo $this->tagAnchor(
+			$this->url(['module' => 'cosmo',
+									'controller' => 'run-log',
+									'action' => 'synthese',
+									'id' => $run->getId(),
+									'date' => $this->date], null, true),
+			$this->tagImg($this->cosmoPath->getCosmoBaseUrl() . 'images/loupe.png',
+										['alt' => 'Afficher le détail']));?></td>
+		<td align="center" style="white-space:nowrap">
+			<?php echo $this->getHumanDate($run->getTraite(), 'EEEE d MMMM yyyy');?></td>
+		<td>(<?php echo $run->getBib()->getId();?>)&nbsp;<?php echo $run->getBib()->getNomCourt();?></td>
+		<td><?php 
+				echo Class_CosmoVar::getLabelInList(
+					'type_fichier', 
+					$run->getProfilDonnees()->getTypeFichier())?></td>
+		<td><?php 
+				echo Class_CosmoVar::getLabelInList('import_type_operation', 
+																						$run->getTypeOperation());?></td>
+		<td><?php echo $run->getFichier();?></td>
+		<td align="right" style="white-space:nowrap">
+			<?php echo number_format((int)$run->getFileSize()/1024, 0, '', ' ');?>&nbsp;ko
+			<?php if (0 < $run->getFileSize()) 
+			echo $this->tagAnchor(
+				$this->url(['module' => 'cosmo',
+										'controller' => 'run-log',
+										'action' => 'download',
+										'id' => $run->getId(),
+										'date' => $this->date], null, true),
+				$this->tagImg($this->cosmoPath->getCosmoBaseUrl() . 'images/plus.gif',
+											['alt' => 'Télécharger le fichier']));?>
+		</td>
+		<td align="right"><?php echo number_format($run->getPointeurReprise(), 0, ',', ' ');?></td>
+		<td align="right"><?php echo $run->getNbErreurs();?></td>
+		<td align="right"><?php echo $run->getNbWarnings();?></td>
+	</tr>
+	<?php } ?>
+</table>
+<br>
+<input type="button" class="bouton" value="Retour" 
+			 onclick="document.location.replace('<?php echo $this->cosmoPath->getCosmoBaseUrl(); ?>php/integre_log.php')" style="margin-left:20px">
+<br>
+<br>
+</div>
diff --git a/cosmogramme/cosmozend/application/modules/cosmo/views/scripts/run-log/synthese.phtml b/cosmogramme/cosmozend/application/modules/cosmo/views/scripts/run-log/synthese.phtml
new file mode 100644
index 0000000000000000000000000000000000000000..a0a776390dc53ab951f356fcba51b0a7e1e66c44
--- /dev/null
+++ b/cosmogramme/cosmozend/application/modules/cosmo/views/scripts/run-log/synthese.phtml
@@ -0,0 +1,86 @@
+<h1>Journal des intégrations du <?php echo $this->getHumanDate($this->date, 'EEEE d MMMM yyyy');?></h1>
+<div align="center">
+	<?php echo $this->cosmoIntegration($this->run); ?>
+	<?php if (!$this->run->fileExists()) { ?>
+		<br><br><h3 style="margin-left:30px">Le fichier d'intégration a été effacé</h3>
+</div>
+<?php 
+return;
+} 
+
+$simpleLine = function($label, $count) {
+	$count = (0 < $count) ? number_format($count, 0, ',', ' ') : 'aucune';
+	?>
+  <tr>
+		<td class="blank"><?php echo $label;?></td>
+		<td class="blank" align="right"><?php echo $count;?></td>
+	</tr>
+<?php 
+};
+
+$detailsLine = function($label, $count, $type) { ?>
+	<tr>
+		<td class="blank" align="center">
+			<?php echo $this->tagAnchor(
+				$this->cosmoPath->getCosmoBaseUrl() 
+				. sprintf('php/integre_journal_integrations.php?id_integration=%s&mode=DETAIL&type=%s&rubrique=%s&date=%s',
+									$this->run->getId(), $type, urlencode($label), $this->date),
+				$this->tagImg($this->cosmoPath->getCosmoBaseUrl() . 'images/loupe.png',
+											['alt' => 'Afficher le détail'])); ?>
+		</td>
+		<td class="blank"><?php echo $label; ?></td>
+		<td class="blank" align="right"><?php echo number_format($count, 0, ',', ' ');?></td>
+	</tr>
+<?php 
+}; 
+
+$detailsTable = function($typeLabel, $type, $detectClosure, $listClosure) 
+use ($detailsLine) {
+	if (!$detectClosure()) 
+		return;
+  ?>
+	<br>
+	<div class="analyse"><?php echo $typeLabel; ?></div>
+	<table class="blank" style="margin-left:20px;width:300px" cellspacing="0">
+		<?php 
+		foreach($listClosure() as $label => $list) 
+			$detailsLine($label, count($list), $type);
+		?>
+	</table>
+	<?php
+};
+?>
+
+	<br>
+	<div class="analyse">Notices</div>
+	<table class="blank" style="margin-left:20px;width:300px" cellspacing="0">
+		<?php foreach([['Notices traitées', $this->run->getPointeurReprise()],
+									 ['Erreurs (notices rejetée)', $this->run->getNbErreurs()],
+									 ['Anomalies', $this->run->getNbWarnings()]] 
+									as $line) {
+			call_user_func_array($simpleLine, $line);
+		} ?>
+	</table>
+
+	<?php 
+	foreach([['Erreurs (notices rejetées)', 'Erreurs', 
+						function() {return $this->run->hasError();}, 
+						function() {return $this->run->getErrorsArray();}],
+					 ['Anomalies', 'Anomalies', 
+						function() {return $this->run->hasWarning();}, 
+						function() {return $this->run->getWarningsArray();}]] 
+					as $detail) {
+		call_user_func_array($detailsTable, $detail);
+	}
+	?>
+
+	<br>
+	<input type="button" class="bouton" value="Retour" 
+				 onclick="document.location.replace('<?php 
+	echo $this->url(['module' => 'cosmo',
+									 'controller' => 'run-log',
+									 'action' => 'by-date',
+									 'date' => $this->date], null, true);?>')" style="margin-left:20px">
+	<br>
+	<br>
+</div>
diff --git a/cosmogramme/cosmozend/application/modules/opac/controllers/IndexController.php b/cosmogramme/cosmozend/application/modules/opac/controllers/IndexController.php
new file mode 100644
index 0000000000000000000000000000000000000000..3e5a3e4d61f1ce12f77787fcc38a8e3b99f07c45
--- /dev/null
+++ b/cosmogramme/cosmozend/application/modules/opac/controllers/IndexController.php
@@ -0,0 +1,29 @@
+<?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 IndexController extends Zend_Controller_Action{
+	public function indexAction() {
+		echo 'Access to dummy opac controller';
+		exit;
+	}
+}
+?>
\ No newline at end of file
diff --git a/cosmogramme/cosmozend/index.php b/cosmogramme/cosmozend/index.php
new file mode 100644
index 0000000000000000000000000000000000000000..463da710c5c5eca6667865ac299e6f9ec42673f9
--- /dev/null
+++ b/cosmogramme/cosmozend/index.php
@@ -0,0 +1,49 @@
+<?php
+/**
+ * Copyright (c) 2012, 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 
+ */
+
+date_default_timezone_set('Europe/Paris');
+
+$cosmozendPath = realpath(dirname(__FILE__));
+
+require_once $cosmozendPath . '/../php/classes/classe_cosmopaths.php';
+require_once $cosmozendPath . '/../storm_init.php';
+
+set_include_path( $cosmozendPath
+. PATH_SEPARATOR . $cosmozendPath . '/application'
+. PATH_SEPARATOR . $cosmozendPath . '/library'
+. PATH_SEPARATOR . get_include_path());
+
+Zend_Session::start();
+Zend_Layout::startMvc();
+Zend_Layout::getMvcInstance()
+->getView()
+->addHelperPath('ZendAfi/View/Helper', 'ZendAfi_View_Helper');
+
+Zend_Controller_Action_HelperBroker::addPath('ZendAfi/Controller/Action/Helper',
+                                             'ZendAfi_Controller_Action_Helper');
+
+$front = Zend_Controller_Front::getInstance()
+	->throwExceptions(true)
+	->addModuleDirectory($cosmozendPath . '/application/modules')
+	->setDefaultModule('opac')
+	->registerPlugin(new ZendAfi_Controller_Plugin_CosmoAuth());
+
+$front->dispatch();
\ No newline at end of file
diff --git a/cosmogramme/php/_init.php b/cosmogramme/php/_init.php
index 1529fdbb1e725a91c49e318bfccf4b55b26512f3..1560906cf45327143d7884fff8c4bb12c18e5eda 100644
--- a/cosmogramme/php/_init.php
+++ b/cosmogramme/php/_init.php
@@ -54,7 +54,7 @@ require_once($basePath.'/../storm_init.php');
 
 require_once("classe_sql.php");
 require_once("fonctions/sql.php");
-
+xdebug_break();
 // Lire la config
 chdir($cosmo_path->getBasePath());
 $cfg=lireConfig($cfgfile);
diff --git a/cosmogramme/php/classes/classe_cosmopaths.php b/cosmogramme/php/classes/classe_cosmopaths.php
index d9cc45b2213f7537200ee2d0f75a40fba0213fc7..f4bcacbb6e0d2cdafa08f7cc30d574c5742bb694 100644
--- a/cosmogramme/php/classes/classe_cosmopaths.php
+++ b/cosmogramme/php/classes/classe_cosmopaths.php
@@ -62,7 +62,12 @@ class CosmoPaths {
 
 
 	public function getBaseUrl() {
-		return '/'.$this->getSite().'/';
+		return '/' . $this->getSite() . '/';
+	}
+
+
+	public function getCosmoBaseUrl() {
+		return $this->getBaseUrl() . self::COSMO_DIR_NAME . '/';
 	}
 
 
diff --git a/cosmogramme/php/classes/classe_notice_integration.php b/cosmogramme/php/classes/classe_notice_integration.php
index e4ee1ba6ef69e1f542186d22bf55fea7aa2e2b2a..7fa67371fded7c4d654bc9f0c43722bcfd6de7d4 100644
--- a/cosmogramme/php/classes/classe_notice_integration.php
+++ b/cosmogramme/php/classes/classe_notice_integration.php
@@ -376,47 +376,49 @@ class notice_integration
 						'facettes' => $notice->getFacettes()];
 	}
 
-// ----------------------------------------------------------------
-// Périodiques koha et Orphee (1 exemplaire par numéro de parution)
-// ----------------------------------------------------------------
-	private function traitePeriodiquesKoha()
-	{
-		$exemplaires=$this->notice["statut_exemplaires"]["unimarc"];
-		if(!count($exemplaires)) return array();
-		$unimarc=$this->notice["unimarc"];
-		if($this->id_article_periodique==3) $champ_numero="v";
-		if($this->id_article_periodique==4) $champ_numero="6";
-		if(!$champ_numero) return array();
+
+	/**
+	 * 1 item by number
+	 */
+	private function traitePeriodiquesKoha() {
+		if (0 == count($this->notice['exemplaires'])) 
+			return [];
+
+		$number_map = [3 => 'v', 4 => '6'];
+		if (!array_key_exists($this->id_article_periodique, $number_map))
+			return [];
+
+		$champ_numero = $number_map[$this->id_article_periodique];
+		$unimarc = $this->notice['unimarc'];
 		
-		foreach($exemplaires as $exemplaire)
-		{
-			$this->notice_sgbd->ouvrirNotice($unimarc,$this->id_profil,$this->sigb,$this->type_doc_force);
-			$champs=$this->notice_sgbd->decoupe_bloc_champ($exemplaire);
-			$table_champs=array();
-			$numero="";
-			foreach($champs as $champ)
-			{
-				$table_champs[]=array($champ["code"],$champ["valeur"]);
-				if($champ["code"]==$champ_numero)
-				{
-					for($i=0; $i<strlen($champ['valeur']); $i++)
-					{
-						$car=substr($champ['valeur'],$i,1);
-						if($car>='0' and $car<='9')
-						{
-							$champ['valeur']=substr($champ['valeur'],$i);
-							break;
-						}
+		foreach($this->notice['exemplaires'] as $exemplaire) {
+			$this->notice_sgbd->ouvrirNotice($unimarc, $this->id_profil, 
+																			 $this->sigb, $this->type_doc_force);
+
+			$champs = unserialize($exemplaire['zone995']);
+			$table_champs = [];
+			$numero = '';
+			foreach($champs as $champ) {
+				$table_champs[] = [$champ['code'], $champ['valeur']];
+				if ($champ['code'] != $champ_numero)
+					continue;
+
+				for ($i=0; $i<strlen($champ['valeur']); $i++) {
+					$car = substr($champ['valeur'],$i,1);
+					if ($car >= '0' and $car <= '9') {
+						$champ['valeur'] = substr($champ['valeur'],$i);
+						break;
 					}
-					$trav=explode(' ',$champ['valeur']);
-					$numero=$trav[0];
 				}
+				$trav = explode(' ', $champ['valeur']);
+				$numero = $trav[0];
 			}
-			$this->notice_sgbd->add_field("461","11","t".$this->notice["titre_princ"]);
-			$this->notice_sgbd->add_field("461","11","v".$numero);
-			$this->notice_sgbd->add_field('995',"  ", $table_champs);
+
+			$this->notice_sgbd->add_field('461', '11', 't' . $this->notice['titre_princ']);
+			$this->notice_sgbd->add_field('461', '11', 'v' . $numero);
+			$this->notice_sgbd->add_field('995', '  ', $table_champs);
 			$this->notice_sgbd->update();
-			$data=$this->notice_sgbd->getFullRecord();
+			$data = $this->notice_sgbd->getFullRecord();
 			$this->traiteNotice($data);
 		}
 	}
diff --git a/cosmogramme/php/classes/classe_unimarc.php b/cosmogramme/php/classes/classe_unimarc.php
index 8fd1b5890f8265333a357301bfd8c990f5a55bb3..848307344623ef22b29c07e31ed9ae1f7426633e 100644
--- a/cosmogramme/php/classes/classe_unimarc.php
+++ b/cosmogramme/php/classes/classe_unimarc.php
@@ -1,4 +1,4 @@
-<?PHP
+<?php
 /**
  * Copyright (c) 2012, Agence Française Informatique (AFI). All rights reserved.
  *
@@ -18,19 +18,15 @@
  * 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 
  */
-//////////////////////////////////////////////////////////////////////////////////////
-// CLASSE UNIMARC (Surcharge la classe iso2709)
-//////////////////////////////////////////////////////////////////////////////////////
-
-require_once("classe_profil_donnees.php");
-require_once("classe_iso2709.php");
-require_once("classe_dewey.php");
-require_once("classe_pcdm4.php");
-require_once("classe_indexation.php");
-require_once("classe_isbn.php");
-
-class notice_unimarc extends iso2709_record
-{
+
+require_once 'classe_profil_donnees.php';
+require_once 'classe_iso2709.php';
+require_once 'classe_dewey.php';
+require_once 'classe_pcdm4.php';
+require_once 'classe_indexation.php';
+require_once 'classe_isbn.php';
+
+class notice_unimarc extends iso2709_record {
 	private $id_profil;									// Id du profil de données pour le fichier chargé
 	private $profil_unimarc;						// Instance du profil unimarc pour optimiser
 	private $type_doc_force;						// Type de document forcé dans maj_auto
@@ -44,87 +40,74 @@ class notice_unimarc extends iso2709_record
 	private $id_genre_documentaire;			// Identifiant pour le genre "documentaire"
 	private $controle_codes_barres;     // Exception de filtrage des codes-barres
 
-// ----------------------------------------------------------------
-// Constructeur 
-// ----------------------------------------------------------------
-	function __construct()
-	{
-		$this->profil_unimarc=new profil_donnees();
-		$this->indexation=new indexation();
-		$data=getVariable("non_exportable");
-		$this->copyright=explode(";",$data);
-		$this->controle_codes_barres=getVariable("controle_codes_barres");
-		$data=getVariable("champs_sup");
-		$this->champs_forces=explode(";",$data);
-		$this->ean345=getVariable("ean_345");
+
+	public function __construct() {
+		$this->profil_unimarc = new profil_donnees();
+		$this->indexation = new indexation();
+		$data = getVariable('non_exportable');
+		$this->copyright = explode(';', $data);
+		$this->controle_codes_barres = getVariable('controle_codes_barres');
+		$data = getVariable('champs_sup');
+		$this->champs_forces = explode(';', $data);
+		$this->ean345 = getVariable('ean_345');
 
 		// Règles sections, genres, emplacements
-		$this->regles_sections_genres=$this->extractRegles();
+		$this->regles_sections_genres = $this->extractRegles();
 		parent::__construct();
 	}
 
-// ----------------------------------------------------------------
-// Initialisation nouvelle notice
-// ----------------------------------------------------------------
-	public function ouvrirNotice($data,$id_profil,$sigb=0,$type_doc_force="")
-	{
-		$this->type_doc_force["label"]=$type_doc_force;
-		switch($type_doc_force)
-		{
-			case "a":$this->type_doc_force["code"]="1"; break;
-			case "j":$this->type_doc_force["code"]="3"; break;
-			case "g":$this->type_doc_force["code"]="4"; break;
-			case "l":$this->type_doc_force["code"]="5"; break;
-			case "c":$this->type_doc_force["code"]="6"; break;
-			case "f":$this->type_doc_force["code"]="7"; break;
-		}
-		$this->sigb=$sigb;
-		if($this->id_profil !== $id_profil)
-		{ 
-			$this->id_profil=$id_profil;
-			if($id_profil==0)
-			{
-				$this->profil=$this->profil_unimarc->getProfil(1);
-				$this->profil["accents"]=0;
-			}
-			else $this->profil=$this->profil_unimarc->getProfil($id_profil);
+
+	public function ouvrirNotice($data, $id_profil, $sigb=0, $type_doc_force='') {
+		$this->type_doc_force['label'] = $type_doc_force;
+		$type_doc_map = ['a' => '1', 'j' => '3', 'g' => '4', 
+										 'l' => '5', 'c' => '6', 'f' => '7'];
+		if (array_key_exists($type_doc_force, $type_doc_map))
+			$this->type_doc_force['code'] = $type_doc_map[$type_doc_force];
+
+		$this->sigb = $sigb;
+		$this->id_profil = $id_profil;
+		if($this->id_profil == 0) {
+			$this->profil = $this->profil_unimarc->getProfil(1);
+			$this->profil['accents'] = 0;
 		}
+		else 
+			$this->profil = $this->profil_unimarc->getProfil($this->id_profil);
 
-		$this->setNotice($data,$this->profil["accents"]);
+		$this->setNotice($data, $this->profil['accents']);
 		return true;
 	}
-// ----------------------------------------------------------------
-// Rend la structure complète pour l'integration
-// ----------------------------------------------------------------
-	public function getNoticeIntegration()
-	{
+
+
+	public function getNoticeIntegration() {
 		// type de doc
-		$type_doc=$this->getTypeDoc(true);
-		if($type_doc["code"]==100) return $this->getNoticeIntegrationArticlePeriodique();
-		if($type_doc["code"]==2) $notice["articles_periodiques"]=$this->getIdArticlesPeriodiques();
+		$type_doc = $this->getTypeDoc(true);
+		if($type_doc['code'] == 100) 
+			return $this->getNoticeIntegrationArticlePeriodique();
+
+		if($type_doc['code'] == 2) 
+			$notice["articles_periodiques"] = $this->getIdArticlesPeriodiques();
 
 		// exemplaires
-		$ex=$this->getExemplaires();
-		$warnings=$ex["warnings"];
+		$ex = $this->getExemplaires();
+		$warnings = $ex['warnings'];
 		
 		// Isbn /ean
-		$trav=$this->getIsbn();
-		if($trav["statut"] == 1) $warnings[]=array("isbn incorrect",$trav["code_brut"]);
-		$isbn=$trav["isbn"];
-		$ean=$trav["ean"];
-		if(!$isbn and !$ean)
-		{
-			$trav=$this->getEan();
-			if($trav["statut"] == 1) $warnings[]=array("ean incorrect",$trav["code_brut"]);
-			$isbn=$trav["isbn"];
-			$ean=$trav["ean"];
+		$trav = $this->getIsbn();
+		if($trav['statut'] == 1) 
+			$warnings[] = ['isbn incorrect', $trav['code_brut']];
+		$isbn = $trav['isbn'];
+		$ean = $trav['ean'];
+		if(!$isbn and !$ean) {
+			$trav = $this->getEan();
+			if($trav['statut'] == 1) 
+				$warnings[] = ['ean incorrect', $trav['code_brut']];
+			$isbn = $trav['isbn'];
+			$ean = $trav['ean'];
 		}
+
 		// Virer ISBN si autre que livre
-		if($type_doc["code"] != 1)
-		{
-			$trav["isbn10"]="";
-			$trav["isbn13"]="";
-			$isbn="";
+		if ($type_doc["code"] != 1) {
+			$trav['isbn10'] = $trav['isbn13'] = $isbn = '';
 		}
 				
 		// Structure notice
@@ -133,20 +116,21 @@ class notice_unimarc extends iso2709_record
 		$notice["isbn10"] = $trav["isbn10"];
 		$notice["isbn13"] = $trav["isbn13"];
 		$notice["ean"] = $ean;
-		$notice["id_origine"]=$this->getIdOrigine();
-		$notice["clef_alpha"]=$this->getClefAlpha();
-		$notice["clef_oeuvre"]=$this->getClefAlpha(true);
-		$notice["clef_chapeau"]=$this->getClefChapeau();
+		$notice["id_origine"] = $this->getIdOrigine();
+		$notice["clef_alpha"] = $this->getClefAlpha();
+		$notice["clef_oeuvre"] = $this->getClefAlpha(true);
+		$notice["clef_chapeau"] = $this->getClefChapeau();
 		$notice["titre_princ"] = $this->getTitrePrincipal();
 		$notice["tome_alpha"] = $this->getTome();
-		$notice["alpha_titre"]=$this->indexation->codeAlphaTitre($notice["titre_princ"]." ".$notice["tome_alpha"]);
-		$notice["id_commerciale"]=$this->getIdCommerciale($notice["alpha_titre"]);
+		$notice["alpha_titre"] = $this->indexation->codeAlphaTitre($notice["titre_princ"]." ".$notice["tome_alpha"]);
+		$notice["id_commerciale"] = $this->getIdCommerciale($notice["alpha_titre"]);
 		$notice["titres"] = $this->getTitres();
 		$notice["auteurs"] = $this->getAuteurs();
 		$notice["auteurs_renvois"] = $this->getAuteursRenvois();
 		// si pas d'auteur on prend le 200$f
-		if(!$notice["auteurs"]) $notice["200_f"]=$this->get200f();
-		$notice["alpha_auteur"]=$this->indexation->alphaMaj($notice["auteurs"][0]);
+		if(!$notice["auteurs"]) 
+			$notice["200_f"] = $this->get200f();
+		$notice["alpha_auteur"] = $this->indexation->alphaMaj($notice["auteurs"][0]);
 		$notice["editeur"] = $this->getEditeur();
 		$notice["collection"] = $this->getCollection();
 		$notice["matieres"] = $this->getMatieres();
@@ -156,48 +140,45 @@ class notice_unimarc extends iso2709_record
 		$notice["infos_type_doc"] = $type_doc;
 		$notice["exportable"] = $this->getExportable();
 
-		$notice["dewey"]=$this->getDewey();
+		$notice["dewey"] = $this->getDewey();
 
-		if (defined('DEVELOPMENT')) 
-		{
-			$notice=$this->getThesauriAndPcdm4($notice);
+		if (defined('DEVELOPMENT')) {
+			$notice = $this->getThesauriAndPcdm4($notice);
+		} else {
+			$notice["pcdm4"] = $this->getPcdm4();
 		}
-		else 
-		{
-			$notice["pcdm4"]=$this->getPcdm4();
-		}
-		$notice["cote"]=$this->getCote();
-		$notice["langues"]=$this->getLangues();
+		$notice["cote"] = $this->getCote();
+		$notice["langues"] = $this->getLangues();
 		$notice["champs_forces"] = $this->getChampsForces();
-		$notice["interet"]=$this->getCentreInteret();
+		$notice["interet"] = $this->getCentreInteret();
 		$notice["statut_exemplaires"] = $ex["statut_exemplaires"];
 		$notice["exemplaires"] = $ex["exemplaires"];
 
 		// Analyse sections, genres et emplacements
-		if($notice["dewey"]) 
-			$notice["genre"] = $this->id_genre_documentaire;
+		if ($notice["dewey"]) 
+			$notice['genre'] = $this->id_genre_documentaire;
+
 		$ret = $this->getSectionGenre($notice["genre"]);
 
-		if($ret["genre"]) 
+		if ($ret["genre"]) 
 			$notice["genres"][0] = $ret["genre"];
-		if($notice["statut_exemplaires"]["nb_ex"] > 0) {
+
+		if ($notice["statut_exemplaires"]["nb_ex"] > 0) {
 			for($i=0; $i <count($notice["exemplaires"]); $i++) {
 				$exemplaire = $notice["exemplaires"][$i];
 				if ($exemplaire["section"]) 
 					$notice["sections"][] = $exemplaire["section"];
 
+				if($exemplaire["emplacement"])
+					$notice["emplacements"][] = $exemplaire["emplacement"];
+
 				if($exemplaire["genre"]) 
 					$notice["genres"][] = $exemplaire["genre"];
 				else 
 					$notice["exemplaires"][$i]["genre"] = $ret["genre"];
-
-				if($exemplaire["emplacement"])
-					$notice["emplacements"][]=$exemplaire["emplacement"];
-				else
-					$notice['exemplaires'][$i]['emplacement'] = $ret['emplacement'];
 				
-				if(!$notice["cote"] and $exemplaire["cote"]) 
-					$notice["cote"] = $exemplaire["cote"];
+				if (!$notice['cote'] and $exemplaire['cote']) 
+					$notice['cote'] = $exemplaire['cote'];
 			}
 		}
 
@@ -378,7 +359,7 @@ class notice_unimarc extends iso2709_record
 
 					// Champs parametres
 					if ($champ_genre and $champ['code'] == $champ_genre) 
-						$ex['genre'] = $this->getIdCodeExemplaire('genre', '995', $champ_genre, $champ['valeur'], true);
+						$ex['genre'] = $this->getIdCodeExemplaire('genre', '995', $champ_genre, $champ['valeur']);
 
 					if ($champ_section and $champ['code'] == $champ_section) {
 						$ex['section'] = $this->getIdCodeExemplaire('section', '995', $champ_section, $champ['valeur']);
@@ -420,7 +401,6 @@ class notice_unimarc extends iso2709_record
 				}
 
 				$ret['exemplaires'][] = $ex;
-				$statut['unimarc'][] = $exemplaires[$i];
 			}
 		}
 
@@ -672,68 +652,60 @@ class notice_unimarc extends iso2709_record
 		return $ret;
 	}
 
-// ----------------------------------------------------------------
-// Teste un code barres et le renvoie s'il est valide
-// ----------------------------------------------------------------
-	public function filtreCodeBarres($code_barres)
-	{
-		if($this->controle_codes_barres==1) return utf8_encode(addslashes($code_barres));
-		$cab=trim(strleft($code_barres,20));
-		if(is_numeric($code_barres)) return $cab;
-		$nb_num=0;
-		for($i=0; $i< strlen($cab); $i++)
-		{
-			if($cab[$i] >="0" and $cab[$i] <="9") $nb_num++;
+
+	public function filtreCodeBarres($code_barres) {
+		if ($this->controle_codes_barres == 1) 
+			return utf8_encode(addslashes($code_barres));
+
+		$cab = trim(strleft($code_barres, 20));
+		if (is_numeric($code_barres)) 
+			return $cab;
+
+		$nb_num = 0;
+		for($i=0; $i< strlen($cab); $i++) {
+			if ($cab[$i] >="0" and $cab[$i] <="9") 
+				$nb_num++;
 		}
-		if($nb_num < 4) return false;
-		else return utf8_encode(addslashes($cab));
+
+		return ($nb_num < 4) ? false : utf8_encode(addslashes($cab));
 	}
 	
-// ----------------------------------------------------------------
-// Id bib origine (champ 001)
-// ----------------------------------------------------------------
-	public function getIdOrigine()
-	{
-		$data=$this->get_subfield("001");
-		$id=substr(trim($data[0]),0,20);
-		return $id;
+
+	public function getIdOrigine() {
+		$data = $this->get_subfield('001');
+		return substr(trim($data[0]), 0, 20);
 	}
-// ----------------------------------------------------------------
-// Isbn
-// ----------------------------------------------------------------
-	public function getIsbn()
-	{
-		// Recup du premier
-		$data=$this->get_subfield("010","a");
-		$isbn=trim($data[0]);
-		if($isbn)
-		{
-			$oIsbn=new class_isbn($isbn);
-			$isbn=$oIsbn->getAll();
+
+
+	public function getIsbn() {
+		$data = $this->get_subfield('010', 'a');
+		$isbn = trim($data[0]);
+		if($isbn) {
+			$oIsbn = new class_isbn($isbn);
+			$isbn = $oIsbn->getAll();
 		}
+
 		//controle ISBN doubles
-		$data=$this->get_subfield("010");
-		if(count($data)>1)
-		{ 
-			$warnings[]=array("isbn multiples","");
-			$isbn["multiple"]=true;
-			$this->delete_field("010");
-			$this->add_zone("010",$data[0]);
+		$data = $this->get_subfield('010');
+		if(count($data)>1) { 
+			$warnings[] = ['isbn multiples', ''];
+			$isbn['multiple'] = true;
+			$this->delete_field('010');
+			$this->add_zone('010', $data[0]);
 		}
-		if(!is_array($isbn)) $isbn=array();
+
+		if(!is_array($isbn)) 
+			$isbn = [];
 		return $isbn;
 	}
-// ----------------------------------------------------------------
-// EAN
-// ----------------------------------------------------------------
-	public function getEan()
-	{
-		$data=$this->get_subfield("073","a");
-		$ean=trim($data[0]);
-		if($ean)
-		{
-			$oIsbn=new class_isbn($ean);
-			$ean=$oIsbn->getAll();
+
+
+	public function getEan() {
+		$data = $this->get_subfield('073', 'a');
+		$ean = trim($data[0]);
+		if($ean) {
+			$oIsbn = new class_isbn($ean);
+			$ean = $oIsbn->getAll();
 		}
 		elseif($this->ean345 == 1)
 		{
@@ -745,6 +717,7 @@ class notice_unimarc extends iso2709_record
 				$ean=$oIsbn->getAll();
 			}
 		}
+
 		if(!$ean)
 		{
 			$data=$this->get_subfield("071","a");
@@ -755,164 +728,163 @@ class notice_unimarc extends iso2709_record
 				$ean=$oIsbn->getAll();
 			}
 		}
-		if(!is_array($ean)) $ean=array();
+
+		if(!is_array($ean)) 
+			$ean = [];
 		return $ean;
 	}
 
-// ----------------------------------------------------------------
-// Identifiant no commercial
-// ----------------------------------------------------------------
-	public function getIdCommerciale($clef_alpha)
-	{
-		$data=$this->get_subfield("071","a");
-		$id=trim($data[0]);
-		if(strlen($id) == 13 and is_numeric($id)) return ""; // c'est un ean
-		// On concatene avec le $b
-		$data=$this->get_subfield("071","b");
-		$id=trim($data[0]).$id;
-		$id=$this->indexation->alphaMaj($id);
-		$id=str_replace(" ","",$id);
-		if(!$id) return "";
-		if(substr($id,0,19) == "REFERENCEEDITORIALE") $id=substr($id,19); 
-		if(substr($id,0,18) == "MARQUEINDETERMINEE") $id=substr($id,18);
+
+	public function getIdCommerciale($clef_alpha) {
+		$data = $this->get_subfield('071', 'a');
+		$id = trim($data[0]);
+		if(strlen($id) == 13 and is_numeric($id)) 
+			return ''; // c'est un ean
+
+		$data = $this->get_subfield('071', 'b');
+		$id = trim($data[0]) . $id;
+		$id = $this->indexation->alphaMaj($id);
+		$id = str_replace(' ', '', $id);
+		if(!$id) 
+			return '';
+
+		if(substr($id,0,19) == "REFERENCEEDITORIALE") 
+			$id = substr($id,19); 
+		if(substr($id,0,18) == "MARQUEINDETERMINEE") 
+			$id = substr($id,18);
+
 		// controle s'il y a au moins 2 chiffres
-		$nb_digit=0;
-		for($i=0; $i < strlen($id); $i++) if( $id[$i] >= "0" and $id[$i] <= "9") $nb_digit++;
-		if($nb_digit < 2) return "";
-		$clef_alpha=str_replace(" ","",$clef_alpha);
-		$id=$id.substr($clef_alpha,0,20);
-		return substr($id,0,50);
+		$nb_digit = 0;
+		for($i=0; $i < strlen($id); $i++) 
+			if( $id[$i] >= "0" and $id[$i] <= "9") 
+				$nb_digit++;
+		if($nb_digit < 2) 
+			return '';
+
+		$clef_alpha = str_replace(' ', '', $clef_alpha);
+		$id = $id . substr($clef_alpha, 0, 20);
+		return substr($id, 0, 50);
 	}
 
-// ----------------------------------------------------------------
-// Identifiant BNF
-// ----------------------------------------------------------------
-	public function getIdBnf()
-	{
-		$data=$this->get_subfield("001");
-		$id=strToUpper(trim($data[0]));
-		if(substr($id,0,5) != "FRBNF") $id= '';
-		elseif(is_numeric(substr($id,5,5))== false) $id='';
-		return $id;
+
+	public function getIdBnf() {
+		$data = $this->get_subfield('001');
+		$id = strToUpper(trim($data[0]));
+		return ((substr($id,0,5) != 'FRBNF') || !is_numeric(substr($id, 5, 5))) ?
+			'' : $id;
 	}
 
-// ----------------------------------------------------------------
-// Rend la clef alpha ou la clef oeuvre
-// ----------------------------------------------------------------
-	public function getClefAlpha($oeuvre=false)
-	{
-		$type_doc=$this->getTypeDoc();
-		$titre=$this->getTitrePrincipal();
-		$complement_titre=$this->getComplementTitre();
-		$auteur=$this->getAuteurs(true,true);
-		$editeur=$this->getEditeur();
-		$annee=$this->getAnnee();
-		$tome=$this->getTome();
-		if($oeuvre==true) $clef_alpha=$this->indexation->getClefOeuvre($titre,$complement_titre,$auteur,$tome);
-		else $clef_alpha=$this->indexation->getClefAlpha($type_doc,$titre,$complement_titre,$auteur,$tome,$editeur,$annee);
-		return $clef_alpha;
+
+	public function getClefAlpha($oeuvre=false) {
+		$type_doc = $this->getTypeDoc();
+		$titre = $this->getTitrePrincipal();
+		$complement_titre = $this->getComplementTitre();
+		$auteur = $this->getAuteurs(true,true);
+		$editeur = $this->getEditeur();
+		$annee = $this->getAnnee();
+		$tome = $this->getTome();
+
+		return ($oeuvre) ?
+			$this->indexation->getClefOeuvre($titre, $complement_titre, $auteur, $tome) :
+			$this->indexation->getClefAlpha($type_doc, $titre, $complement_titre, $auteur, $tome, $editeur, $annee);
 	}
 
-// ----------------------------------------------------------------
-// Rend la clef chapeau
-// ----------------------------------------------------------------
-	public function getClefChapeau()
-	{
-		$titre=$this->get_subfield("461","t");
-		$titre=trim($titre[0]);
-		$clef_chapeau=$this->indexation->codeAlphaTitre($titre);
-		return $clef_chapeau;
+
+	public function getClefChapeau() {
+		$titre = $this->get_subfield('461', 't');
+		return $this->indexation->codeAlphaTitre(trim($titre[0]));
 	}
 	
-// ----------------------------------------------------------------
-// TYPE DE DOCUMENT
-// ----------------------------------------------------------------
-	public function getTypeDoc($infos=false)
-	{
-		if($this->type_doc_force["label"] > "") $this->inner_guide["dt"]=$this->type_doc_force["label"];
-		$label=$this->inner_guide["dt"].$this->inner_guide["bl"];
-		if($this->profil['attributs'][0]["champ_type_doc"] > "")
-		{
-			if(strlen($this->profil['attributs'][0]["champ_code_barres"])==3) $zone=$this->profil['attributs'][0]["champ_code_barres"];
-			else $zone="995";
-			$z995r=$this->get_subfield($zone,$this->profil['attributs'][0]["champ_type_doc"]);
-		}
-		else
-		{	
-			if($this->profil['attributs'][0]["champ_code_barres"] == "997") $z995r=$this->get_subfield("997","t");
-			elseif($this->profil['attributs'][0]["champ_code_barres"] == "852") $z995r=$this->get_subfield("852","r");
-			elseif($this->profil['attributs'][0]["champ_code_barres"] == "999") $z995r=$this->get_subfield("996","x");
-			else
-			{
-				$z995r=$this->get_subfield("995","r");
-				$z995p=$this->get_subfield("995","p");
-			}
+
+	public function getTypeDoc($infos=false) {
+		if($this->type_doc_force['label'] > '') 
+			$this->inner_guide['dt'] = $this->type_doc_force['label'];
+		$label = $this->inner_guide['dt'] . $this->inner_guide['bl'];
+
+		$champ_code_barres = $this->profil['attributs'][0]['champ_code_barres'];
+
+		if ($this->profil['attributs'][0]['champ_type_doc'] > '') {
+			$zone = (strlen($champ_code_barres) == 3) ? $champ_code_barres : '995';
+			$z995r = $this->get_subfield($zone, 
+																	 $this->profil['attributs'][0]['champ_type_doc']);
+		} else {
+			$z995r = $this->get_subfield('995', 'r');
+			$z995p = $this->get_subfield('995', 'p');
+			if($champ_code_barres == '997') 
+				$z995r = $this->get_subfield('997', 't');
+			elseif($champ_code_barres == '852') 
+				$z995r = $this->get_subfield('852', 'r');
+			elseif($champ_code_barres == '999') 
+				$z995r = $this->get_subfield('996', 'x');
 		}
-		if($this->type_doc_force["label"] > "") $typeDoc["code"]=$this->type_doc_force["code"];
-		else $typeDoc=$this->profil_unimarc->getTypeDoc($label, $z995r, $z995p);
-		if($infos==true)
-		{
-			$ret["code"]=$typeDoc["code"];
-			$ret["infos"]="Label=".$label." - "."995\$r=".$z995r[0]." - \$p=".$z995p[0];
-			if($this->type_doc_force["label"] > "") $typeDoc["libelle"]=getLibCodifVariable("types_docs",$typeDoc["code"]);
-			$ret["libelle"]=$typeDoc["libelle"];
+
+		if($this->type_doc_force['label'] > '') 
+			$typeDoc['code'] = $this->type_doc_force['code'];
+		else 
+			$typeDoc = $this->profil_unimarc->getTypeDoc($label, $z995r, $z995p);
+
+		if ($infos) {
+			$ret["code"] = $typeDoc["code"];
+			$ret["infos"] = "Label=".$label." - "."995\$r=".$z995r[0]." - \$p=".$z995p[0];
+			if ($this->type_doc_force["label"] > "") 
+				$typeDoc["libelle"] = getLibCodifVariable('types_docs', $typeDoc['code']);
+			$ret["libelle"] = $typeDoc["libelle"];
 			return $ret;
 		}
-		if(!$typeDoc["code"]) $typeDoc["code"]=0;
-		return $typeDoc["code"];
+
+		return ($typeDoc['code']) ? $typeDoc['code'] : 0;
 	}
 
-// ----------------------------------------------------------------
-// Calcul de la date de nouveauté
-// ----------------------------------------------------------------
-	public function calculDateNouveaute($valeur)
-	{
-		// controle
-		$valeur=trim($valeur);
-		if($valeur)
-		{
-			$params=$this->profil['attributs'][4];
-			if($params["format"]=="1") $date=substr($valeur,0,10);
-			if($params["format"]=="2") $date=substr($valeur,0,4)."-".substr($valeur,4,2)."-".substr($valeur,6,2);
-			if($params["format"]=="4") $date=rendDate($valeur,0);
-			if($params["format"]=="5") $date=rendDate($valeur,0);
-			if($params["format"]=="3")
-			{
-				$compare=";".$params["valeurs"].";";
-				if(strpos($compare, ";".$valeur.";") !== false) $date="2030-12-31";
-			}
-		}
-		
-		// ajouter les jours
-		if(!$date) $date="2000-01-01";
-		else $date=ajouterJours($date, $params["jours"]);
 
-		// retour
-		return $date;
+	public function calculDateNouveaute($valeur) {
+		$valeur = trim($valeur);
+		if (!$valeur)
+			return '2000-01-01';
+
+		$params = $this->profil['attributs'][4];
+		if (!$date = $this->_getDateWithFormat($params['format'], $valeur))
+			return '2000-01-01';
+
+		return ajouterJours($date, $params['jours']);
 	}
 
-// ----------------------------------------------------------------
-// TITRES
-// ----------------------------------------------------------------
-	public function getTitres()
-	{
-		// Recup des zones titres dans les variables
-		$zones=getVariable("unimarc_zone_titre");
-		$zones=explode(";",trim($zones));
-		foreach($zones as $elem)
-		{
-			$zone=substr($elem,0,3);
-			$champ=substr($elem,-1,1);
-			$data=$this->get_subfield($zone);
-			foreach($data as $items)
-			{
-				$sous_champs=$this->decoupe_bloc_champ($items);
-				foreach($sous_champs as $item)
-				{
-					if($item["code"]==$champ)
-					{
-						$item = trim($item["valeur"]);
-						if($item) $titre[]=$this->filtreTitre($item);
+
+	protected function _getDateWithFormat($format, $value) {
+		$format = $this->profil['attributs'][4]['format'];
+		$valeurs = $this->profil['attributs'][4]['valeurs'];
+
+		$mappings = [
+			'1' => function($value) {return substr($value, 0, 10);},
+			'2' => function($value) {return substr($value, 0, 4) . '-' 
+															 . substr($value, 4, 2) . '-' 
+															 . substr($value, 6, 2);},
+			'4' => function($value) {return rendDate($value, 0);},
+			'5' => function($value) {return rendDate($value, 0);},
+			'3' => function($value) use ($valeurs) {
+				$compare = ';' . $valeurs . ';';
+				if(strpos($compare, ';' . $value . ';') !== false) 
+					return '2030-12-31';
+			},];
+
+		if (array_key_exists($format, $mappings))
+			return $mappings[$format]($value);
+	}
+
+
+	public function getTitres() {
+		$zones = getVariable('unimarc_zone_titre');
+		$zones = explode(';', trim($zones));
+		foreach($zones as $elem) {
+			$zone = substr($elem, 0, 3);
+			$champ = substr($elem, -1, 1);
+			$data = $this->get_subfield($zone);
+			foreach($data as $items) {
+				$sous_champs = $this->decoupe_bloc_champ($items);
+				foreach($sous_champs as $item) {
+					if($item["code"] == $champ) {
+						$item = trim($item['valeur']);
+						if($item)
+							$titre[] = $this->filtreTitre($item);
 					}
 				}
 			}
@@ -920,412 +892,350 @@ class notice_unimarc extends iso2709_record
 		return($titre);
 	}
 
-// ----------------------------------------------------------------
-// Complément du titre (1er seulement)
-// ----------------------------------------------------------------
-	public function getComplementTitre()
-	{
-		$titre=$this->get_subfield("200","e");
-		$titre=$this->filtreTitre($titre[0]);
-		return trim($titre);
+
+	/** first one only */
+	public function getComplementTitre() {
+		$titre = $this->get_subfield('200', 'e');
+		return $this->filtreTitre($titre[0]);
 	}
 	
-// ----------------------------------------------------------------
-// Nettoyage des titres
-// ----------------------------------------------------------------
-	private function filtreTitre($valeur)
-	{
-		$titre=trim($valeur);
-		$titre=str_replace("[","",$titre);
-		$titre=str_replace("]"," ",$titre);
-		$titre=str_replace("<","",$titre);
-		$titre=str_replace(">"," ",$titre);
-		$titre=str_replace(chr(136),"",$titre);
-		$titre=str_replace(chr(137),"",$titre);
-		if(substr($titre,0,1) == "?")
-		{
-			$deb=substr($titre,0,6);
-			$titre=str_replace("?","",$deb).substr($titre,6);
+
+	private function filtreTitre($valeur) {
+		$titre = trim($valeur);
+		$titre = str_replace(['[', '<', chr(136), chr(137)], '', $titre);
+		$titre = str_replace([']', '>'], ' ', $titre);
+
+		if (substr($titre, 0, 1) == '?') {
+			$deb = substr($titre, 0, 6);
+			$titre = str_replace('?', '', $deb) . substr($titre, 6);
 		}
-		$titre=trim($titre);
-		$car=substr($titre,-1,1);
-		if($car=="/" or $car==";" or $car=="," or $car=="." or $car==":" or $car=="-") $titre=substr($titre,0,strlen($titre)-1);
-		//tracedebug($valeur." = ".$titre);
+
+		$titre = trim($titre);
+		if(in_array(substr($titre, -1, 1), ['/', ';', ',', '.', ':', '-']))
+			$titre = substr($titre, 0, strlen($titre) - 1);
+
 		return trim($titre);
 	}
 	
-// ----------------------------------------------------------------
-// no de partie
-// ----------------------------------------------------------------
-	public function getTome()
-	{
-		$data=$this->get_subfield("200","v");
-		for($i=0; $i< count($data); $i++)
-		{
-			if($data[$i]>"") $tome=$data[$i];
-		}
-		$data=$this->get_subfield("461","v");
-		for($i=0; $i< count($data); $i++)
-		{
-			if($data[$i]>"") $tome=$data[$i];
-		}
-		$data=$this->get_subfield("200","h");
-		for($i=0; $i< count($data); $i++)
-		{
-			if($data[$i]>"") $tome=$data[$i];
+
+	public function getTome() {
+		if ($tome = $this->_getLastNonEmptyValueOf('200', 'v'))
+			return $tome;
+		if ($tome = $this->_getLastNonEmptyValueOf('461', 'v'))
+			return $tome;
+		return $this->_getLastNonEmptyValueOf('200', 'h');
+	}
+
+
+	protected function _getLastNonEmptyValueOf($field, $sub_field) {
+		$value = null;
+		$data = $this->get_subfield($field, $sub_field);
+		for ($i=0; $i< count($data); $i++) {
+			if ($data[$i] > '') 
+				$value = $data[$i];
 		}
-		return $tome;
+		return $value;
 	}
 	
-// ----------------------------------------------------------------
-// AUTEURS
-// ----------------------------------------------------------------
-	public function getAuteurs($auteurPrincipal=false,$clef_alpha=false)
-	{
-		$zones=array("700","710","720","730","701","702","711","712","721","722");
-		foreach($zones as $zone)
-		{
-			$data=$this->get_subfield($zone);
-			foreach($data as $items)
-			{
-				$sous_champs=$this->decoupe_bloc_champ($items);
-				$nom="";
-				$prenom="";
-				foreach($sous_champs as $item)
-				{
-					if($item["code"]=="a") $nom=trim($item["valeur"]);
-					elseif($item["code"]=="b") $prenom=trim($item["valeur"]);
+
+	public function getAuteurs($auteurPrincipal=false, $clef_alpha=false) {
+		$auteur = [];
+		foreach ($this->_getAuthorFields() as $zone) {
+			$data = $this->get_subfield($zone);
+			foreach ($data as $items) {
+				$sous_champs = $this->decoupe_bloc_champ($items);
+				$nom = $prenom = '';
+				$mappings = ['a' => function ($value) use (&$nom) {$nom = $value;},
+										 'b' => function ($value) use (&$prenom) {$prenom = $value;}];
+				foreach ($sous_champs as $item) {
+					if (array_key_exists($item['code'], $mappings))
+						$mappings[$item['code']](trim($item['valeur']));
 				}
-				$nm=$nom . "|" .$prenom;
-				if((strlen($nm) > 2 or $this->indexation->isMotInclu($nom))and striPos($nm,"ANONYME") === false) // On elimine les auteurs avec 1 seule lettre
+
+				$nm = $nom . '|' . $prenom;
+				if ((strlen($nm) > 2 or $this->indexation->isMotInclu($nom)) 
+						and striPos($nm, "ANONYME") === false) // On elimine les auteurs avec 1 seule lettre 
 				{
-					$auteur[]=$nm;
-					if($clef_alpha==true)return trim($nom.substr($prenom,0,1));
-				  if($auteurPrincipal==true) return trim($prenom." ".$nom);
+					if($clef_alpha)
+						return trim($nom . substr($prenom, 0, 1));
+
+				  if($auteurPrincipal) 
+						return trim($prenom . ' ' . $nom);
+
+					$auteur[] = $nm;
 				}
 			}
 		}
 
-		// retour
-		return($auteur);
+		return $auteur;
 	}
 
-// ----------------------------------------------------------------
-// RENVOIS AUTEURS
-// ----------------------------------------------------------------
-	public function getAuteursRenvois()
-	{
+
+	public function getAuteursRenvois() {
 		$auteur = [];
-		$zones=array("700","710","720","730","701","702","711","712","721","722");
-		foreach($zones as $zone)
-		{
-			$data=$this->get_subfield($zone);
-			foreach($data as $items)
-			{
-				$sous_champs=$this->decoupe_bloc_champ($items);
-				foreach($sous_champs as $item)
-				{
-					if($item["code"]=="8")
-					{
-						$nom=trim($item["valeur"]);
-						if(strlen($nom)>1) $auteur[]=$nom;
+		foreach($this->_getAuthorFields() as $zone) {
+			$data = $this->get_subfield($zone);
+			foreach($data as $items) {
+				$sous_champs = $this->decoupe_bloc_champ($items);
+				foreach($sous_champs as $item) {
+					if($item['code'] == '8') {
+						$nom = trim($item["valeur"]);
+						if (strlen($nom)>1) 
+							$auteur[] = $nom;
 					}
 				}
 			}
 		}
+		return $auteur;
+	}
 
-		// retour
-		return($auteur);
+
+	protected function _getAuthorFields() {
+		return ['700','710','720','730','701','702','711','712','721','722'];
 	}
 
-// ----------------------------------------------------------------
-// Auteurs en 200$f
-// ----------------------------------------------------------------
-	public function get200f()
-	{
-		$data=$this->get_subfield("200","f");
-		return($data);
+
+	public function get200f() {
+		return $this->get_subfield('200', 'f');
 	}
 
-// ----------------------------------------------------------------
-// DEWEY
-// ----------------------------------------------------------------
-	public function getDewey()
-	{
-		$data=$this->get_subfield("676");
-		foreach($data as $items)
-		{
-			$sous_champs=$this->decoupe_bloc_champ($items);
-			foreach($sous_champs as $item)
-			{
-				if($item["code"]=="a")
-				{ 
-					$indice=dewey::filtreIndice($item["valeur"]);
-					if($indice) $dewey[]=$indice;
-				}
-			}
+
+	public function getDewey() {
+		$data = $this->get_subfield('676');
+		foreach ($data as $items) {
+			$sous_champs = $this->decoupe_bloc_champ($items);
+			foreach ($sous_champs as $item)
+				if (($item['code'] == 'a')
+						&& ($indice = dewey::filtreIndice($item['valeur'])))
+					$dewey[] = $indice;
 		}
 		return $dewey;
 	}
 
-	public function getThesauriAndPcdm4($notice) {
-
-		$thesaurus=[];
-		$data=$this->get_subfield("686");
-		$pcdm4=null;
-		foreach($data as $items)
-		{
 
-			$sous_champs=$this->decoupe_bloc_champ($items);
-			$code_thesaurus=null;
-			$id_origine=null;
-			foreach($sous_champs as $item)
-			{
-				if($item["code"]=="a") 
-					$id_origine=$item['valeur'];
-				if($item["code"]=="2")
-					$code_thesaurus=trim($item['valeur']);
-				
+	public function getThesauriAndPcdm4($notice) {
+		$thesaurus = [];
+		$data = $this->get_subfield('686');
+		$pcdm4 = null;
+		foreach($data as $items) {
+			$sous_champs = $this->decoupe_bloc_champ($items);
+			$code_thesaurus = null;
+			$id_origine = null;
+			foreach($sous_champs as $item) {
+				if ($item["code"] == "a") 
+					$id_origine = $item['valeur'];
+				if ($item["code"] == "2")
+					$code_thesaurus = trim($item['valeur']);
 				if ($code_thesaurus && $id_origine ) {
 					if ($code_thesaurus == "PCDM") {
-
 						$indice=pcdm4::filtreIndice($id_origine);
 						$pcdm4=$indice;
-
 						continue;
 					}
-						$thesaurus[]=Class_CodifThesaurus::findByIdOrigineAndCode($id_origine,$code_thesaurus);
+					$thesaurus[] = Class_CodifThesaurus::findByIdOrigineAndCode($id_origine,$code_thesaurus);
 				}
 			}
-			
 		}
-		$notice['thesauri']=$thesaurus;
+
+		$notice['thesauri'] = $thesaurus;
 		if ($pcdm4) 
-			$notice['pcdm4']=$pcdm4;
+			$notice['pcdm4'] = $pcdm4;
 		return $notice;
-	
 	}
 
 
-// ----------------------------------------------------------------
-// PCDM4
-// ----------------------------------------------------------------
-	public function getPcdm4()
-	{
-		// specifique pergame
-		$data=$this->get_subfield("934","a");
-		$code=trim($data[0]);
-		if(trim($data[0]) and substr($code,0,1)=="<")
-		{
-			$elems=str_replace("<","",$code);
-			$elems=explode(">",$elems);
-			if($elems[0])$indice=$elems[0].$elems[1].$elems[2];
-			if($indice) return $indice;
-		}
+	public function getPcdm4() {
+		if ($indice = $this->_getPergamePcdm4())
+			return $indice;
 
-		// autres sigb
-		$data=$this->get_subfield("686");
-		$data=$data + $this->get_subfield("676");
-		foreach($data as $items)
-		{
-			$sous_champs=$this->decoupe_bloc_champ($items);
+		$data = $this->get_subfield('686');
+		$data = $data + $this->get_subfield('676');
+		foreach($data as $items) {
+			$sous_champs = $this->decoupe_bloc_champ($items);
 			foreach($sous_champs as $item)
-			{
-				if($item["code"]=="a")
-				{ 
-					$indice=pcdm4::filtreIndice($item["valeur"]);
-					if($indice) return $indice;
-				}
-			}
+				if (($item['code'] == 'a')
+						&& $indice = pcdm4::filtreIndice($item['valeur']))
+					return $indice;
 		}
 	}
-// ----------------------------------------------------------------
-// COTE NIVEAU NOTICE (pergame uniquement)
-// ----------------------------------------------------------------
-public function getCote()
-{
-	if($this->sigb!=1) return false;
-	$data=$this->get_subfield("686","a");
-	return(trim($data[0]));
-}
 
-// ----------------------------------------------------------------
-// EDITEUR
-// ----------------------------------------------------------------
-	public function getEditeur()
-	{
-		$data=$this->get_subfield("210","c");
-		return(trim($data[0]));
+
+	protected function _getPergamePcdm4() {
+		$data = $this->get_subfield('934', 'a');
+		$code = trim($data[0]);
+		if (!trim($data[0]) or substr($code,0,1) != '<')
+			return;
+
+		$elems = str_replace('<', '', $code);
+		$elems = explode('>', $elems);
+		if (!$elems[0])
+			return;
+
+		if ($indice = $elems[0] . $elems[1] . $elems[2])
+			return $indice;
 	}
-// ----------------------------------------------------------------
-// CENTRE D'INTERET
-// ----------------------------------------------------------------
-	public function getCentreInteret()
-	{
-		if($this->sigb==1 or $this->sigb==13)
-		{
-			$zone_interet="932";
-			$champ_interet="a";
-		}
-		else
-		{
-			$zone_interet=$this->profil['attributs'][6]["zone"];
-			$champ_interet=$this->profil['attributs'][6]["champ"];
-		}
-		if(!trim($zone_interet)) return false;
+
+
+	public function getCote() {
+		// pergame uniquement
+		if ($this->sigb!=1) 
+			return false;
+
+		$data = $this->get_subfield('686', 'a');
+		return trim($data[0]);
+	}
+
+
+	public function getEditeur() {
+		$data = $this->get_subfield('210', 'c');
+		return trim($data[0]);
+	}
+
+
+	public function getCentreInteret() {
+		$zone_interet = ($this->sigbIs1Or13()) ? 
+			'932' : $this->profil['attributs'][6]['zone'];
+
+		$champ_interet = ($this->sigbIs1Or13()) ?
+			'a' : $this->profil['attributs'][6]['champ'];
+
+		if(!trim($zone_interet)) 
+			return false;
 		
-		$data=$this->get_subfield($zone_interet);
-		foreach($data as $items)
-		{
-			$sous_champs=$this->decoupe_bloc_champ($items);
+		$data = $this->get_subfield($zone_interet);
+		foreach($data as $items) {
+			$sous_champs = $this->decoupe_bloc_champ($items);
 			foreach($sous_champs as $item)
-			{
-				if($item["code"]==$champ_interet)
-				{
-					if(trim($item["valeur"])) $interet[]=$item["valeur"];
-				}
-			}
+				if (($item['code'] == $champ_interet)
+						&& trim($item['valeur']))
+					$interet[] = $item['valeur'];
 		}
 		return $interet;
 	}
+
+
+	protected function sigbIs1Or13() {
+		return in_array($this->sigb, [1, 13]);
+	}
 	
-// ----------------------------------------------------------------
-// ANNEE
-// ----------------------------------------------------------------
-	public function getAnnee()
-	{
-		$data=$this->get_subfield("210","d");
-		for($i=0; $i < strlen($data[0]); $i++)
-		{
-			$car=strMid($data[0],$i,1);
-			if($car >="0" And $car <= "9") $annee = $annee .$car;
-			if(strLen($annee) == 4 ) break;
+
+	public function getAnnee() {
+		$data = $this->get_subfield('210', 'd');
+		for($i=0; $i < strlen($data[0]); $i++) {
+			$car = strMid($data[0], $i, 1);
+			if($car >= '0' and $car <= '9') 
+				$annee = $annee .$car;
+			if(strLen($annee) == 4) 
+				break;
 		}
-		if($annee < "1000" or $annee > "2020") $annee="";
+
+		if($annee < '1000' or $annee > '2020') 
+			$annee = '';
 		return($annee);
 	}
 
-// ----------------------------------------------------------------
-// Statut de la notice 0=ok 1=detruire la notice
-// ----------------------------------------------------------------
-	public function getStatut()
-	{
-		$statut=0;
-		if($this->inner_guide["rs"] == "d" ) $statut=1; 
-		$ex=$data=$this->get_subfield("995");
-		$nb_ex=count($ex);
+
+	/**
+	 * 0=ok 1=detruire la notice
+	 */
+	public function getStatut() {
+		$statut = 0;
+		if ($this->inner_guide['rs'] == 'd') 
+			$statut = 1; 
+		$ex = $data = $this->get_subfield('995');
+		$nb_ex = count($ex);
 		
 		// Verif du flag delete dans le 995$o	
-		$nb_ex_detruit=0;
-		$ex=$data=$this->get_subfield("995","o");
-		for($i=0; $i<count($ex); $i++) if($ex[$i]=="d") $nb_ex_detruit++;
-		if($nb_ex_detruits >= $nb_ex and $nb_ex > 0) $statut=1;
+		$nb_ex_detruit = 0;
+		$ex = $data = $this->get_subfield('995', 'o');
+		for ($i=0; $i < count($ex); $i++) 
+			if($ex[$i] == 'd') 
+				$nb_ex_detruit++;
+
+		if ($nb_ex_detruits >= $nb_ex and $nb_ex > 0) 
+			$statut = 1;
 
 		return $statut;
 	}
-// ----------------------------------------------------------------
-// Rend si une notice est exportable ou pas 
-// controle par la zone 801$b et la clef variable : non_exportable
-// ----------------------------------------------------------------
-	public function getExportable()
-	{
-		$champs=$this->get_subfield("801","b");
-		for($item=0; $item < count($champs); $item++)
-		{
-			$champ="x".$champs[$item];
-			for($i=0; $i < count($this->copyright); $i++)
-			{ 
-				if( stripos($champ,"x".$this->copyright[$i]) !== false ) return false;
+
+
+	public function getExportable() {
+		$champs = $this->get_subfield('801', 'b');
+		for($item=0; $item < count($champs); $item++) {
+			$champ = 'x' . $champs[$item];
+			for($i=0; $i < count($this->copyright); $i++) { 
+				if(stripos($champ, 'x' . $this->copyright[$i]) !== false ) 
+					return false;
 			}
 		}
 		return true;
 	}
-// ----------------------------------------------------------------
-// Collections
-// ----------------------------------------------------------------
-	public function getCollection()
-	{
-		$data=$this->get_subfield(225,"a");
+
+
+	public function getCollection() {
+		$data = $this->get_subfield(225, 'a');
 		if(!count($data))
-		{
-			$data=$this->get_subfield(410,"t");
-		}
+			$data = $this->get_subfield(410, 't');
 		return $data;
 	}
-// ----------------------------------------------------------------
-// Langues
-// ----------------------------------------------------------------
-	public function getLangues()
-	{
-		$data=$this->get_subfield(101);
-		foreach($data as $items)
-			{
-				$sous_champs=$this->decoupe_bloc_champ($items);
-				foreach($sous_champs as $item)
-				{
-					if($item["code"]=="a") 
-					{
-						$code=strtolower($item["valeur"]);
-						$code=substr($code,0,3);
-						if($code=="fra") $code="fre";
-						if($code != "und") $langues[]=$code;
-					}
+
+
+	public function getLangues() {
+		$data = $this->get_subfield(101);
+		foreach($data as $items) {
+			$sous_champs = $this->decoupe_bloc_champ($items);
+			foreach($sous_champs as $item) {
+				if($item['code'] == 'a') {
+					$code = strtolower($item['valeur']);
+					$code = substr($code, 0, 3);
+					if ($code == 'fra') 
+						$code = 'fre';
+					if($code != 'und') 
+						$langues[] = $code;
 				}
 			}
+		}
 		return $langues;
 	}
-// ----------------------------------------------------------------
-// Matieres
-// ----------------------------------------------------------------
-	public function getMatieres()
-	{
+
+
+	public function getMatieres() {
 		$matiere = [];
-		// Recup des zones matières dans les variables
-		$zones=getVariable("unimarc_zone_matiere");
-		$zones=explode(";",trim($zones));
-		foreach($zones as $elem)
-		{
-			$data=$this->get_subfield(strLeft($elem,3));
-			$champs=strMid($elem,3,10);
-			foreach($data as $items)
-			{
-				$sous_champs=$this->decoupe_bloc_champ($items);
-				$mot="";
-				foreach($sous_champs as $item)
-				{
-					if(strscan($champs,$item["code"]) >=0 )
-					{ 
-						if($mot) $mot.=" : ";
-						$mot.=$item["valeur"];
+		$zones = getVariable('unimarc_zone_matiere');
+		$zones = explode(';',trim($zones));
+		foreach($zones as $elem) {
+			$data = $this->get_subfield(strLeft($elem, 3));
+			$champs = strMid($elem, 3, 10);
+			foreach($data as $items) {
+				$sous_champs = $this->decoupe_bloc_champ($items);
+				$mot = '';
+				foreach($sous_champs as $item) {
+					if(strscan($champs, $item['code']) >=0) { 
+						if($mot) 
+							$mot .= ' : ';
+						$mot .= $item['valeur'];
 					}
 				}
-				$matiere[]=trim($mot);
+				$matiere[] = trim($mot);
 			}
 		}
 		return($matiere);
 	}
 
-// ----------------------------------------------------------------
-// Renvois Matieres
-// ----------------------------------------------------------------
-	public function getMatieresRenvois()
-	{
+
+	public function getMatieresRenvois() {
 		$matiere = [];
-		// Recup des zones matières dans les variables
-		$zones=getVariable("unimarc_zone_matiere");
-		$zones=explode(";",trim($zones));
-		foreach($zones as $elem)
-		{
-			$data=$this->get_subfield(strLeft($elem,3));
-			foreach($data as $items)
-			{
+		$zones = getVariable('unimarc_zone_matiere');
+		$zones = explode(';', trim($zones));
+		foreach($zones as $elem) {
+			$data = $this->get_subfield(strLeft($elem, 3));
+			foreach($data as $items) {
 				$sous_champs=$this->decoupe_bloc_champ($items);
-				foreach($sous_champs as $item)
-				{
-					if($item["code"]==8)
-					{ 
-						$mot=trim($item["valeur"]);
-						if(strlen($mot)>1) $matiere[]=$mot;
+				foreach($sous_champs as $item) {
+					if($item["code"] == 8) { 
+						$mot = trim($item['valeur']);
+						if(strlen($mot) > 1) 
+							$matiere[] = $mot;
 					}
 				}
 			}
@@ -1333,141 +1243,121 @@ public function getCote()
 		return($matiere);
 	}
 
-// ----------------------------------------------------------------
-// Récupere les champs forces
-// ----------------------------------------------------------------	
-	public function getChampsForces()
-	{
-		for($i=0; $i < count($this->champs_forces); $i++)
-		{
-			$champ=$this->get_subfield($this->champs_forces[$i]);
-			for($j=0; $j < count($champ); $j++)
-			{
-				$champ_forces["Z".$this->champs_forces[$i]][]=$champ[$j];
+
+	public function getChampsForces() {
+		for($i=0; $i < count($this->champs_forces); $i++) {
+			$champ = $this->get_subfield($this->champs_forces[$i]);
+			for($j=0; $j < count($champ); $j++) {
+				$champ_forces["Z" . $this->champs_forces[$i]][] = $champ[$j];
 			}
 		}
 		return $champ_forces;
-	} 
-// ----------------------------------------------------------------
-// Rend une notice unimarc complete dans 1 structure
-// ----------------------------------------------------------------
-	public function getAll()
-	{
+	}
+
+
+	public function getAll() {
+		$data = $this->get_subfield(200, 'a');
+		$notice["titre_princ"] = $data[0];
+
+		$label[]=["Longueur de la notice",$this->inner_guide["rl"]];
+		$label[]=["Statut de la notice",$this->inner_guide["rs"]];
+		$label[]=["Type de document",$this->inner_guide["dt"].$this->inner_guide["bl"]];
+		$label[]=["Niveau hiérarchique",$this->inner_guide["hl"]];
+		$label[]=["Adresse des données",$this->inner_guide["ba"]];
+		$label[]=["Niveau de catalogage",$this->inner_guide["el"]];
+		$notice["label"] = $label;
 
-		// Titre principal
-		$data=$this->get_subfield(200,"a");
-		$notice["titre_princ"]=$data[0];
-		// Label
-		$label[]=array("Longueur de la notice",$this->inner_guide["rl"]);
-		$label[]=array("Statut de la notice",$this->inner_guide["rs"]);
-		$label[]=array("Type de document",$this->inner_guide["dt"].$this->inner_guide["bl"]);
-		$label[]=array("Niveau hiérarchique",$this->inner_guide["hl"]);
-		$label[]=array("Adresse des données",$this->inner_guide["ba"]);
-		$label[]=array("Niveau de catalogage",$this->inner_guide["el"]);
-		$notice["label"]=$label;
-
-		// Champs
     foreach ($this->inner_data as $label => $contents) {
       foreach($contents as $content) {
-			  $sc=$this->decoupe_field($label, $content);
-			  $sc["zone"]=$label;
-			  $notice["zones"][]=$sc;
+			  $sc = $this->decoupe_field($label, $content);
+			  $sc["zone"] = $label;
+			  $notice["zones"][] = $sc;
       }
 		}
 		return $notice;
 	}
-// ----------------------------------------------------------------
-// Rend l'unimarc natif découpé par blocs
-// ----------------------------------------------------------------
-	public function getUnimarcNatif()
-	{
-		$ret["label"]=$this->guide;
-		$ret["zones"]=$this->inner_directory;
-		$ret["data"]=$this->inner_data;
-		$ret["bloc"]=$this->full_record;
+
+
+	public function getUnimarcNatif() {
+		$ret["label"] = $this->guide;
+		$ret["zones"] = $this->inner_directory;
+		$ret["data"] = $this->inner_data;
+		$ret["bloc"] = $this->full_record;
 		return $ret;
 	}
-// ----------------------------------------------------------------
-// Decoupage de regles (sections et genres)
-// ----------------------------------------------------------------	
-	private function extractRegles()
-	{
-		$types=array("section","genre","emplacement");
-		foreach($types as $type)
-		{
-			$enregs=fetchAll("select * from codif_".$type);
-			if(!$enregs) continue;
-			foreach($enregs as $enreg)
-			{
-				// Specif genre documentaire
-				//if($type == "genre" and strToUpper(substr($enreg["libelle"],0,5))=="DOCUM")
-				//{
-				//	$this->id_genre_documentaire=$enreg["id_genre"];
-				//	continue;
-				//}
-				if(!$enreg["regles"]) continue;
-				$regles=explode("\n",$enreg["regles"]);
-				foreach($regles as $regle)
-				{
-					$zone=substr($regle,0,5);
-					$signe=substr($regle,5,1);
-					$valeurs=explode(";",strToUpper(substr($regle,6)));
-					foreach($valeurs as $valeur)
-					{ 
-						$valeur=trim($valeur);
-						if($valeur) $ret[$zone][$type][$signe][$valeur]=$enreg["id_".$type];
+
+
+	private function extractRegles() {
+		foreach(['section', 'genre', 'emplacement'] as $type) {
+			$enregs = fetchAll('select * from codif_' . $type);
+			if (!$enregs)
+				continue;
+
+			foreach ($enregs as $enreg) {
+				if (!$enreg['regles'])
+					continue;
+
+				$regles = explode("\n", $enreg['regles']);
+				foreach ($regles as $regle) {
+					$zone = substr($regle, 0, 5);
+					$signe = substr($regle, 5, 1);
+					$valeurs = explode(';', strToUpper(substr($regle, 6)));
+					foreach ($valeurs as $valeur) { 
+						$valeur = trim($valeur);
+						if ($valeur) 
+							$ret[$zone][$type][$signe][$valeur] = $enreg['id_' . $type];
 					}
 				}
 			}
 		}
 		return $ret;
 	}
-// ----------------------------------------------------------------
-// Analyse des règles (sections et genres)
-// ----------------------------------------------------------------	
-	private function getSectionGenre($genre)
-	{
-		$ret["section"]=0;
-		$ret["emplacement"]=0;
-		$ret["genre"]=$genre;
 
-		foreach($this->regles_sections_genres as $zone_champ => $types)
-		{
-			// Champs notice
-			$zone=substr($zone_champ,0,3);
-			$champ=substr($zone_champ,4,1);
-			$data=$this->get_subfield($zone,$champ);
-			if(!count($data)) continue;
-			foreach($data as $valeur_notice)
-			{
-				$valeur_notice=strToUpper($valeur_notice);
-				$valeur_notice=str_replace(" ","",$valeur_notice);
-				if(!$valeur_notice) continue;
-				// Section et genre
-				foreach($types as $type => $signes)
-				{
+
+	private function getSectionGenre($genre) {
+		$ret = ['section' => 0,
+						'emplacement' => 0,
+						'genre' => $genre];
+		
+		foreach ($this->regles_sections_genres as $zone_champ => $types) {
+			$zone = substr($zone_champ, 0, 3);
+			$champ = substr($zone_champ, 4, 1);
+			$data = $this->get_subfield($zone, $champ);
+			if (!count($data))
+				continue;
+
+			foreach($data as $valeur_notice) {
+				$valeur_notice = strToUpper($valeur_notice);
+				$valeur_notice = str_replace(' ', '', $valeur_notice);
+				if (!$valeur_notice)
+					continue;
+
+				foreach($types as $type => $signes) {
 					// Si on l'a deja on continue
-					if($ret[$type]) continue;
-					// Signes de comparaison
-					foreach($signes as $signe => $valeurs)
-					{
-						// Valeurs de controle
-						$retenu="";
-						foreach($valeurs as $valeur => $code)
-						{
-
-							if($signe == "=") {if($valeur == $valeur_notice) $retenu=$code;}
-							elseif($signe == "/") {if($valeur == substr($valeur_notice,0,strlen($valeur))) $retenu=$code;}
-							elseif($signe == "*") {if( strpos($valeur_notice,$valeur) !== false) $retenu=$code;}
-							// Si on a trouvé on break
-
-							if($retenu) break;
+					if ($ret[$type]) continue;
+
+					foreach($signes as $signe => $valeurs) {
+						$retenu = '';
+						foreach($valeurs as $valeur => $code) {
+							if($signe == "=") {
+								if($valeur == $valeur_notice) 
+									$retenu=$code;
+							} elseif($signe == "/") {
+								if($valeur == substr($valeur_notice,0,strlen($valeur))) 
+									$retenu=$code;}
+							elseif($signe == "*") {
+								if( strpos($valeur_notice,$valeur) !== false) 
+									$retenu=$code;
+							}
+
+							if($retenu)
+								break;
 						}
 
-						if($retenu)
-						{ 
-							$ret[$type]=$retenu;
-							if ($ret["section"] and $ret["genre"] and $ret["emplacement"]) return $ret;
+						if($retenu) { 
+							$ret[$type] = $retenu;
+							if ($ret['section'] and $ret['genre'] and $ret['emplacement']) 
+								return $ret;
 							break;
 						}
 					}
@@ -1478,17 +1368,14 @@ public function getCote()
 		return $ret;
 	}
 
-// ----------------------------------------------------------------
-// Rend l'id section genre ou emplacement depuis les regles
-// ----------------------------------------------------------------
-	private function getIdCodeExemplaire($type,$champ,$sous_champ,$valeur,$test0=false)
-	{
-		$valeur=trim(strtoupper($valeur));
-		$champ=$champ."$".$sous_champ;
-		$id=$this->regles_sections_genres[$champ][$type]["="][$valeur];
-		if(!$id) $id=$this->regles_sections_genres["995$0"][$type]["="][$valeur];
-		if(!$id) $id="";
+
+	private function getIdCodeExemplaire($type, $champ, $sous_champ, $valeur) {
+		$valeur = trim(str_replace(' ', '', strtoupper($valeur)));
+		$champ = $champ . '$' . $sous_champ;
+		$id = $this->regles_sections_genres[$champ][$type]['='][$valeur];
+		if(!$id) $id = $this->regles_sections_genres['995$0'][$type]['='][$valeur];
+		if(!$id) $id = '';
 		return $id;
 	}
 }
-?>
+?>
\ No newline at end of file
diff --git a/cosmogramme/php/integre_journal_integrations.php b/cosmogramme/php/integre_journal_integrations.php
index 0c375b560bc11d6427a832dbc3068e9d38728975..4f550e6e4f158d706262a540cb899758c2d49345 100644
--- a/cosmogramme/php/integre_journal_integrations.php
+++ b/cosmogramme/php/integre_journal_integrations.php
@@ -18,21 +18,19 @@
  * 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 
  */
-//////////////////////////////////////////////////
-// JOURNAL DES INTEGRATIONS
-//////////////////////////////////////////////////
-include("_init_frame.php");
+
+include '_init_frame.php';
 
 // Instanciations
-require_once("classe_bib.php");
+require_once 'classe_bib.php';
 $oBib = new bibliotheque();
-require_once("classe_parseur.php");
+require_once 'classe_parseur.php';
 $parseur=new parseur();
-require_once("classe_unimarc.php");
+require_once 'classe_unimarc.php';
 $unimarc=new notice_unimarc();
-require_once("classe_notice_ascii.php");
+require_once 'classe_notice_ascii.php';
 $ascii=new notice_ascii();
-require_once("classe_isbn.php");
+require_once 'classe_isbn.php';
 
 // Titre page
 if($_REQUEST["date"]) $aff_date=" du ".rendDate($_REQUEST["date"],3);
@@ -72,38 +70,36 @@ if( $_REQUEST["id_integration"])
 // ----------------------------------------------------------------
 // Liste des notices
 // ----------------------------------------------------------------
-if( $_REQUEST["mode"] == "DETAIL")
-{
-	$type=$_REQUEST["type"];
-	$rubrique=urldecode($_REQUEST["rubrique"]);
-	print(BR.'<div class="analyse">'.$type);
-	if($rubrique) print(' : '.$rubrique); 
-	print('</div>');
-	
-	// Liste
-	if($type == "Erreurs")
-	{
-		foreach($erreurs as $libelle => $liste)
-		{
-			if($rubrique and $libelle != $rubrique) continue;
-			if($format == 0) printRubriqueUnimarc($fichier,"erreurs", $libelle,$enreg["profil"], $liste);
-			else printRubriqueAscii($fichier,"erreurs", $libelle,$enreg["profil"], $liste);
-		}
-	}
-	if($type == "Anomalies")
-	{
-		foreach($warnings as $libelle => $liste)
-		{
-			if($rubrique and $libelle != $rubrique) continue;
-			if($format == 0) printRubriqueUnimarc($fichier,"warnings", $libelle,$enreg["profil"], $liste);
-			else printRubriqueAscii($fichier,"warnings", $libelle,$enreg["profil"], $liste);
-		}
-	}
-	
-	// Fini
-	$bouton_retour='<input type="button" class="bouton" value="Retour" onclick="document.location.replace(\'integre_journal_integrations.php?mode=SYNTHESE&id_integration='.$_REQUEST["id_integration"]."&date=".$_REQUEST["date"].'\')" style="margin-left:20px">';
-	print(BR.$bouton_retour.BR.BR);
-	quit("");
+if( $_REQUEST["mode"] == "DETAIL") {
+	$type = $_REQUEST["type"];
+	$rubrique = urldecode($_REQUEST["rubrique"]);
+	?>
+	<br>
+	<div class="analyse"><?php echo $type . ($rubrique ? ' : ' . $rubrique : '');?></div>
+	<?php
+	foreach ([['Erreurs', 'erreurs', $erreurs],
+		        ['Anomalies', 'warnings', $warnings]] as $params) {
+	  if (!$type == $params[0])
+			continue;
+		
+		foreach ($params[2] as $libelle => $liste) {
+			if ($rubrique and $libelle != $rubrique)
+				continue;
+
+			($format == 0) ?
+				printRubriqueUnimarc($fichier, $params[1], $libelle, $enreg['profil'], $liste) :
+				printRubriqueAscii($fichier, $params[1], $libelle, $enreg['profil'], $liste);
+    }
+  }
+	?>
+	<br>
+	<input type="button" class="bouton" value="Retour" 
+	       onclick="document.location.replace('../cosmozend/cosmo/run-log/synthese/date/<?php echo $_REQUEST['date'];?>/id/<?php echo $_REQUEST['id_integration'];?>');" 
+				 style="margin-left:20px">
+	<br>
+	<br>
+	<?php 
+	quit('');
 }
 
 // ----------------------------------------------------------------
@@ -144,11 +140,10 @@ if($_REQUEST["mode"] == "SYNTHESE")
 // ----------------------------------------------------------------
 // AFFICHAGE DE LA LISTE 
 // ----------------------------------------------------------------
-else
-{
-  // Entête
-	print('<table style="width:800px;margin-left:20px">');
-	print('<tr>
+// Entête
+?>
+<table style="width:800px;margin-left:20px">
+<tr>
  	<th width="15%" colspan="2" align="left">Date</th>
  	<th width="30%" align="left">Bibliothèque</th>
 	<th width="20%" align="left">Type de fichier</th>
@@ -158,45 +153,51 @@ else
  	<th width="9%" align="left">Fiches traitées</th>
  	<th width="9%" align="left">Erreurs</th>
  	<th width="9%" align="left">Anomalies</th>
-	</tr>');
-  
-  // Lire les integrations
-  if($_REQUEST["date"]) $cond = " and traite='".$_REQUEST["date"]."' ";
-  $req="select * from integrations where traite != 'non' ".$cond."order by id DESC";
-	$liste=$sql->fetchAll($req);
+	</tr>
+<?php 
 
-  foreach ($liste as $ligne) 
-	{ 
-   	$sql_date=rendDate($ligne["traite"],1);
-   	$nb_notices=number_format($ligne["pointeur_reprise"], 0, ',', ' ');
-    $sql_type=getLibCodifVariable("import_type_operation",$ligne["type_operation"]);
-    $nom_bib=$oBib->getNomCourt($ligne["id_bib"]);
-		$type_fichier=getLibCodifVariable("type_fichier",$sql->fetchOne("select type_fichier from profil_donnees where id_profil=".$ligne["profil"]));
-    $loupe=rendUrlImg("loupe.png", "integre_journal_integrations.php","mode=SYNTHESE&id_integration=".$ligne["id"]."&date=".$_REQUEST["date"],"Afficher le détail");
-		$taille_fichier=filesize(getVariable("integration_path").$ligne["fichier"]);
-		if($taille_fichier>0) $taille_fichier=intval($taille_fichier/1024);
-		
-		print ("<tr>");
-		print ('<td align="center">'.$loupe.'</td>');
-		print ('<td align="center">'.$sql_date.'</td>');
-		print ("<td>(".$ligne["id_bib"].")&nbsp;$nom_bib</td>");
-		print ("<td>$type_fichier</td>");
-		print ("<td>$sql_type</td>");
-		print ("<td>".$ligne["fichier"]."</td>");
-		print ('<td align="right">'.$taille_fichier."&nbsp;ko</td>");
-		print ('<td align="right">'.$nb_notices.'</td>');
-		print ('<td align="right">'.$ligne["nb_erreurs"].'</td>');
-		print ('<td align="right">'.$ligne["nb_warnings"].'</td>');
-		print("</tr>");
-	}
+// Lire les integrations
+if ($_REQUEST['date']) 
+	$cond = " and traite='" . $_REQUEST['date'] . "' ";
+$req = "select * from integrations where traite != 'non' " . $cond . " order by id DESC";
+$liste = $sql->fetchAll($req);
 
-	// Fini
-	print('</table></div>');
-	$bouton_retour='<input type="button" class="bouton" value="Retour" onclick="document.location.replace(\'integre_log.php\')" style="margin-left:20px">';
-	print(BR.$bouton_retour.BR.BR);
-	quit("");
-
-}
+foreach ($liste as $ligne) { 
+	$taille_fichier = filesize(getVariable("integration_path") . $ligne["fichier"]);
+	if ($taille_fichier > 0 ) 
+		$taille_fichier = intval($taille_fichier / 1024);
+	?>
+	<tr>
+	<td align="center">
+  <?php echo rendUrlImg("loupe.png", 
+                        "integre_journal_integrations.php",
+												"mode=SYNTHESE&id_integration=" . $ligne["id"] . "&date=" . $_REQUEST["date"],
+												"Afficher le détail");?></td>
+	<td align="center"><?php echo rendDate($ligne["traite"], 1);?></td>
+	<td>(<?php echo $ligne["id_bib"];?>)&nbsp;<?php echo $oBib->getNomCourt($ligne["id_bib"]);?></td>
+	<td><?php echo getLibCodifVariable("type_fichier",
+																		 $sql->fetchOne("select type_fichier from profil_donnees where id_profil=".$ligne["profil"]));?></td>
+	<td><?php echo getLibCodifVariable("import_type_operation",
+																		 $ligne["type_operation"]);?></td>
+	<td><?php echo $ligne["fichier"];?></td>
+	<td align="right" style="white-space:nowrap">
+  <?php echo $taille_fichier;?>&nbsp;ko
+  <?php if (0 < $taille_fichier) 
+	  echo rendUrlImg("plus.gif", 
+		                "integre_journal_integrations.php",
+		                "mode=DOWNLOAD&id_integration=" . $ligne["id"] . "&date=" . $_REQUEST["date"],
+		                "Télécharger le fichier");?>
+	</td>
+	<td align="right"><?php echo number_format($ligne["pointeur_reprise"], 0, ',', ' ');?></td>
+	<td align="right"><?php echo $ligne["nb_erreurs"];?></td>
+	<td align="right"><?php echo $ligne["nb_warnings"];?></td>
+	</tr>
+<?php } ?>
+</table></div>
+<?php
+$bouton_retour='<input type="button" class="bouton" value="Retour" onclick="document.location.replace(\'integre_log.php\')" style="margin-left:20px">';
+print(BR.$bouton_retour.BR.BR);
+quit('');
 
 // ----------------------------------------------------------------
 // FONCTIONS D'AFFICHAGE
diff --git a/cosmogramme/php/integre_log.php b/cosmogramme/php/integre_log.php
index 5ff279079062fce0bdcf9122c55911966aa5f497..088b737c5e03add71cac7973c102c6ed1c45f053 100644
--- a/cosmogramme/php/integre_log.php
+++ b/cosmogramme/php/integre_log.php
@@ -1,4 +1,4 @@
-<?PHP
+<?php
 /**
  * Copyright (c) 2012, Agence Française Informatique (AFI). All rights reserved.
  *
@@ -18,54 +18,37 @@
  * 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 
  */
-////////////////////////////////////////////////////////////////////////////////////////////
-// AFFICHAGE DES LOGS D'INTEGRATION
-////////////////////////////////////////////////////////////////////////////////////////////
-include("_init_frame.php");
 
-require_once("classe_log.php");
-$log=new Class_log("integration");
+include '_init_frame.php';
 
-// ----------------------------------------------------------------
-// AFFICHAGE d'1 LOG COMPLET
-// ----------------------------------------------------------------
-if($_REQUEST["log"])
-{
+require_once 'classe_log.php';
+$log = new Class_log("integration");
+
+if($_REQUEST["log"]) {
 	print('<h1>Log du '.$_REQUEST["date"].'</h1>');
 	print('<div style="margin-left:20px">');
 	$log->afficher($_REQUEST["log"]);
 	print('</div></body></html>');
 	exit;
-}
-
-// ----------------------------------------------------------------
-// LISTE
-// ----------------------------------------------------------------
-print('<h1>Journal des intégrations</h1>');
-print('<div class="liste">');
-print('<table width="600px">');
+} ?>
 
-// ----------------------------------------------------------------
-// Logs d'intégration + Erreurs + warnings
-// ----------------------------------------------------------------
-print('<tr>');
-print('<th colspan="2">Date</th>');
-print('<th colspan="2">Rapport</th>');
-print('<th width="15%">Notices traitées</th>');
-print('<th width="15%">Erreurs</th>');
-print('<th  width="15%">Anomalies</th>');
-print('</tr>');
-
-$liste_integration=$log->rendListe();
-for($i=0; $i < count($liste_integration); $i++)
-{
-	// Date
-	$lig=$liste_integration[$i];
-	print('<tr>');
-	$url_synthese=rendUrlImg("loupe.png", "integre_journal_integrations.php","date=".$lig["date_sql"],"Synthèse par bibliothèques");
-	print('<td>'. $url_synthese .'</td>');
-	print('<td>'.$lig["date"].'</td>');
-	
+<h1>Journal des intégrations</h1>
+<div class="liste">
+	<table width="600px">
+	<tr>
+	<th colspan="2">Date</th>
+	<th colspan="2">Rapport</th>
+	<th width="15%">Notices traitées</th>
+	<th width="15%">Erreurs</th>
+	<th width="15%">Anomalies</th>
+	</tr>
+<?php foreach ($log->rendListe() as $lig) { ?>
+	<tr>
+	<td><?php echo rendUrlImg('loupe.png',
+													 '../cosmozend/cosmo/run-log/by-date/date/' . $lig['date_sql'], 
+													 '', 'Synthèse par bibliothèques');?></td>
+	<td><?php echo $lig["date"];?></td>
+	<?php
 	// Integration
 	$url=rendUrlImg("loupe.png", "integre_log.php","log=".$lig["fic"]."&date=".$lig["date"]."&type=INTEGRATION","Afficher le détail");
 	print('<td>'. $url .'</td>');
diff --git a/cosmogramme/php/integre_traite_main.php b/cosmogramme/php/integre_traite_main.php
index ca77f6d96ef92d6443cee2a0e5ee78b8da04922e..12272f1e7fd71a682ca180125d660ba40822d33c 100644
--- a/cosmogramme/php/integre_traite_main.php
+++ b/cosmogramme/php/integre_traite_main.php
@@ -275,8 +275,7 @@ if ($phase == "0") $phase = "0.1";
 // ----------------------------------------------------------------
 // PSEUDO-NOTICES - cms rss sitotheque et albums (phase 0.1 a 0.6)
 // ----------------------------------------------------------------
-if ($phase > 0 and $phase < 1)
-{
+if ($phase > 0 and $phase < 1) {
 	include("integration/pseudo_notices.php");
 	$phase = 1;
 }
diff --git a/cosmogramme/php/upgrade_db.php b/cosmogramme/php/upgrade_db.php
new file mode 100644
index 0000000000000000000000000000000000000000..b1a00dccf6dc34fe87dd7d8f3bce2fba875ef09b
--- /dev/null
+++ b/cosmogramme/php/upgrade_db.php
@@ -0,0 +1,115 @@
+<?php
+
+$basePath = dirname(realpath(__FILE__));
+require_once 'classes/classe_cosmopaths.php';
+
+
+$cosmo_path = new CosmoPaths();
+define('BASE_URL', $cosmo_path->getBaseUrl());
+
+require_once($basePath.'/../storm_init.php');
+
+$sql = Zend_Registry::get('sql');
+$patch_level = Class_CosmoVar::find("patch_level");
+
+function versionForFile($file) {
+	return (int)substr($file, -7, 3);
+}
+
+function extensionForFile($file) {
+	return substr($file, -4);
+}
+
+// Recup des patches a executer
+$path = realpath(dirname(__FILE__)).'/../sql/patch/';
+$handle = @opendir($path);
+if (!$handle) 
+	echo('Impossible d\'ouvrir le dossier : '.$path);
+
+$scripts = [];
+while (false !== ($fic = readdir($handle))) {
+	if (!in_array(extensionForFile($fic), ['.sql', '.php']))
+		continue;
+	$numero = versionForFile($fic);
+	if ($numero > $patch_level->getValeur()) 
+		$scripts[] = $path . $fic;
+}
+
+sort($scripts);
+closedir($handle);
+
+foreach($scripts as $script) {
+	$num_patch = versionForFile($script);
+	echo('Execution patch n° ' . $num_patch );
+		
+	switch(extensionForFile($script)) {
+	case '.php':
+		runPhpUpgrade($script);break;
+	case '.sql':
+		runSqlUpgrade($script, $sql);break;
+	}
+
+	// Ecrire le patch dans la base
+	$patch_level->setValeur($num_patch)->save();
+}
+echo('Mise à niveau de la base effectuée avec succès');
+exit;
+
+function runSqlUpgrade($script, $sql) {
+	$num_instruction = 0;
+	$data = file($script);
+
+	$instructions = [];
+	$contents = implode(' ', $data);
+	if (false !== strpos($contents, 'CREATE FUNCTION')) 
+		$instructions[] = $contents;
+	else {
+		$instruction = '';
+		foreach($data as $ligne) {
+			$ligne = trim($ligne);
+			if (!$ligne or substr($ligne,0,2)=="--") continue;
+				
+			$instruction.=$ligne.' ';
+			if(substr($ligne,-1)!=";")
+				continue;
+
+			$instructions[] = $instruction;
+			$instruction = '';
+		}
+	}
+
+
+	foreach($instructions as $instruction) {
+		echo($instruction."\n");
+		flush();
+		// Executer
+		$num_instruction++;
+
+		$sql->execute($instruction);
+
+	}
+}
+
+function runPhpUpgrade($script) {
+
+	set_error_handler(
+		function($no, $message, $file, $line, $context) {
+			echo('Erreur :'.$message 
+						. " \nfile : " . $file 
+						. " \nline : " . $line
+						);
+			die(255);
+		});
+
+	try {
+		include $script;
+	} catch (Exception $e) {
+		echo("Code : ".$e->getCode()."\n");
+		echo("Erreur :".$e->getMessage());
+
+		exit;
+	}
+}
+
+
+?>
\ No newline at end of file
diff --git a/cosmogramme/tests/php/classes/NoticeIntegrationTest.php b/cosmogramme/tests/php/classes/NoticeIntegrationTest.php
index e33ebda3878b92e733c221e9f52239f78a2716a1..2cfb08eda9ca37bd34636a166e49fa397ec7b20c 100644
--- a/cosmogramme/tests/php/classes/NoticeIntegrationTest.php
+++ b/cosmogramme/tests/php/classes/NoticeIntegrationTest.php
@@ -27,10 +27,13 @@ require_once 'ModelTestCase.php';
 abstract class NoticeIntegrationTestCase extends ModelTestCase {
 	protected  
 		$notice_sgbd,
-		$_mock_sql;
+		$_mock_sql,
+		$_insert_increment;
 
 
 	public function setupProfilDonnees() {
+		$this->_insert_increment = 12;
+
 		if (!isset($this->_profil_donnees))
 			return;
 
@@ -55,9 +58,19 @@ abstract class NoticeIntegrationTestCase extends ModelTestCase {
 		$this->_mock_sql
 			->whenCalled('execute')->answers(true)
 			->whenCalled('fetchAll')->answers(null)
-			->whenCalled('insert')->answers(12)
+			->whenCalled('insert')->willDo(
+				function() {
+					$args = func_get_args();
+					if ($args[0] == 'notices') {
+						$inc = $this->_insert_increment;
+					  $this->_insert_increment++;
+						return $inc;
+					}
+					return 12;
+				})
 			->whenCalled('update')->answers(null)
-			->whenCalled('fetchEnreg')->answers(null);
+			->whenCalled('fetchEnreg')->answers(null)
+			->whenCalled('fetchOne')->answers(null);
 
 
 		VariableCache::getInstance()
@@ -559,6 +572,48 @@ class NoticeIntegrationMussoWithoutRenvoisTest extends NoticeIntegrationTestCase
 }
 
 
+class NoticeIntegrationBienveillantesTest extends NoticeIntegrationTestCase {
+	protected $_profil_donnees = 
+		['id_profil' => 111,
+		 'libelle' => 'UNIMARC ALOES',
+		 '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:"l";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();
+		$this->_mock_sql
+			->whenCalled('fetchAll')
+			->with('select * from codif_emplacement', false)
+			->answers([
+									['id_emplacement' => 2,
+									 'regles' => '995$l=RES']
+									])
+;
+		$this->loadNotice("unimarc_bienveillantes");
+	}
+
+	/** @test */
+	public function recordShouldContainsSixItems() {
+		$this->assertEquals(6, count($this->notice_data['exemplaires']));
+	}
+
+	/** @test */
+	public function locationForFirstItemShouldNotHaveId2() {
+		$this->assertNotEquals(2,	$this->notice_data['exemplaires'][0]['emplacement']);
+	}
+
+	/** @test */
+	public function thirdItemShouldHaveId2() {
+		$this->assertEquals(2, $this->notice_data['exemplaires'][2]['emplacement']);
+	}
+}
+
+
 
 class NoticeIntegrationZanzibarTest extends NoticeIntegrationTestCase {
 	protected $_profil_donnees = 
@@ -569,7 +624,7 @@ class NoticeIntegrationZanzibarTest extends NoticeIntegrationTestCase {
 		 '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";}}'
+		 '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;LIV7;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() {
@@ -706,7 +761,6 @@ class NoticeIntegrationDimancheALaPiscineTest extends NoticeIntegrationTestCase
 									['id_emplacement' => 54,
 									 'regles' => '995$u=Littératureadulte']])
 
-
 			->whenCalled('fetchAll')
 			->with('select * from codif_section', false)
 			->answers([
@@ -717,7 +771,8 @@ class NoticeIntegrationDimancheALaPiscineTest extends NoticeIntegrationTestCase
 			->with('select * from codif_genre', false)
 			->answers([
 									['id_genre' => 8,
-									 'regles' => '902$a=Roman']]);
+									 'regles' => '902$a=Roman']])
+			;
 
 		$this->loadNotice("unimarc_dimanche_a_la_piscine");
 	}
@@ -899,4 +954,189 @@ class NoticeIntegrationItemsIn852Test extends NoticeIntegrationTestCase {
 		$this->assertEquals($expected, $this->notice_data['exemplaires'][$index][$property]);
 	}
 }
-?>
+
+
+class NoticeIntegrationKohaPeriodiqueTest extends NoticeIntegrationTestCase {
+	protected $_profil_donnees = [
+		'id_profil' => 113,
+		'libelle' => 'Unimarc Koha',
+		'accents' => 0,
+    'rejet_periodiques' => 0,
+		'id_article_periodique' => 3,
+		'type_fichier' => 0,
+		'format' => 0,
+		'attributs' => 'a:7:{i:0;a:8:{s:8:"type_doc";a:25:{i:0;a:3:{s:4:"code";s:1:"0";s:5:"label";s:0:"";s:8:"zone_995";s:3:"IND";}i:1;a:3:{s:4:"code";s:1:"1";s:5:"label";s:5:"am;na";s:8:"zone_995";s:39:"LIV;JLIV;JLCD;LCD;PAR;JPAR;CAR;IMA;JIMA";}i:2;a:3:{s:4:"code";s:1:"2";s:5:"label";s:2:"as";s:8:"zone_995";s:18:"REV;JREV:REVA;REVJ";}i:3;a:3:{s:4:"code";s:1:"3";s:5:"label";s:3:"i;j";s:8:"zone_995";s:25:"CDI;JCDI;LCA;CDI;JCDI;LCA";}i:4;a:3:{s:4:"code";s:1:"4";s:5:"label";s:1:"g";s:8:"zone_995";s:22:"DVD;JDVD;DVDA;DVDJ;VID";}i:5;a:3:{s:4:"code";s:1:"5";s:5:"label";s:3:"l;m";s:8:"zone_995";s:9:"CDROM;CDR";}i:6;a:3:{s:4:"code";s:1:"6";s:5:"label";s:0:"";s:8:"zone_995";s:3:"LCD";}i:7;a:3:{s:4:"code";s:1:"7";s:5:"label";s:0:"";s:8:"zone_995";s:3:"PAR";}i:8;a:3:{s:4:"code";s:1:"8";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}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:0:"";}i:11;a:3:{s:4:"code";s:2:"11";s:5:"label";s:0:"";s:8:"zone_995";s:4:"JVID";}i:12;a:3:{s:4:"code";s:2:"12";s:5:"label";s:0:"";s:8:"zone_995";s:3:"MAT";}i:13;a:3:{s:4:"code";s:2:"13";s:5:"label";s:2:"km";s:8:"zone_995";s:3:"EST";}i:14;a:3:{s:4:"code";s:3:"100";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:15;a:3:{s:4:"code";s:3:"101";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:16;a:3:{s:4:"code";s:3:"102";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:17;a:3:{s:4:"code";s:3:"103";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:18;a:3:{s:4:"code";s:3:"104";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:19;a:3:{s:4:"code";s:3:"105";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:20;a:3:{s:4:"code";s:3:"106";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:21;a:3:{s:4:"code";s:3:"107";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:22;a:3:{s:4:"code";s:3:"108";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:23;a:3:{s:4:"code";s:3:"109";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:24;a:3:{s:4:"code";s:3:"110";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:1:"r";s:11:"champ_genre";s:0:"";s:13:"champ_section";s:1:"q";s:17:"champ_emplacement";s:1:"e";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:22:{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:7:"_IDABON";s:0:"";s:10:"_ORDREABON";s:0:"";s:4:"_NOM";s:0:"";s:7:"_PRENOM";s:0:"";s:10:"_NAISSANCE";s:0:"";s:9:"_PASSWORD";s:0:"";s:5:"_MAIL";s:0:"";s:11:"_DATE_DEBUT";s:0:"";s:9:"_DATE_FIN";s:0:"";s:8:"_ID_SIGB";s:0:"";s:10:"_NUM_CARTE";s:0:"";s:5:"_NULL";s:0:"";}}i:4;a:5:{s:4:"zone";s:3:"801";s:5:"champ";s:1:"c";s:6:"format";s:1:"2";s:5:"jours";s:2:"90";s:7:"valeurs";s:0:"";}i:6;a:2:{s:4:"zone";s:3:"901";s:5:"champ";s:1:"a";}}'
+		];
+
+	protected $_record_inserts;
+	protected $_item_inserts;
+
+	public function setUp() {
+		parent::setUp();
+		$this->_mock_sql
+			->whenCalled('fetchAll')
+			->with('select * from codif_section', false)
+			->answers([
+									['id_section' => 2,
+									 'regles' => '995$q=ADU']])
+
+			->whenCalled('fetchAll')
+			->with('select * from codif_genre', false)
+			->answers([])
+
+			->whenCalled('fetchAll')
+			->with('select * from codif_emplacement', false)
+			->answers([ 
+									['id_emplacement' => 3,
+									 '995$e=A']])
+
+			->whenCalled('fetchEnreg')
+			->with('select * from int_bib where id_bib=1')
+			->answers(['id_bib' => 1])
+
+			->whenCalled('fetchOne')
+			->with('Select liste from variables where clef=\'champs_abonne\'')
+			->answers('')
+
+			->whenCalled('fetchOne')
+			->with('Select valeur from variables where clef=\'unimarc_zone_matiere\'')
+			->answers('')
+
+			->whenCalled('fetchEnreg')
+			->with('select * from codif_section where id_section=2', false)
+			->answers(['id_section' => 2])
+
+			->whenCalled('fetchEnreg')
+			->with('select * from codif_annexe where code=\'POL\'', false)
+			->answers(['code' => 'POL'])
+
+			->whenCalled('fetchEnreg')
+			->with('select * from codif_annexe where code=\'CHAB\'', false)
+			->answers(['code' => 'CHAB'])
+
+			->whenCalled('fetchEnreg')
+			->with('select * from codif_annexe where code=\'PLV\'', false)
+			->answers(['code' => 'PLV'])
+
+			->whenCalled('fetchEnreg')
+			->with('select * from codif_annexe where code=\'BLV\'', false)
+			->answers(['code' => 'BLV']);
+
+		$this->loadNotice('unimarc_kohaperiodique');
+
+		$this->_record_inserts = [];
+		foreach (range(0, $this->_mock_sql->methodCallCount('insert')) as $index) {
+			$params = $this->_mock_sql->getAttributesForMethodCallAt('insert', $index);
+			if ($params[0] == 'notices')
+				$this->_record_inserts[] = $params[1];
+		}
+
+		$this->_item_inserts = [];
+		foreach (range(0, $this->_mock_sql->methodCallCount('insert')) as $index) {
+			$params = $this->_mock_sql->getAttributesForMethodCallAt('insert', $index);
+			if ($params[0] == 'exemplaires')
+				$this->_item_inserts[] = $params[1];
+		}
+	}
+
+
+	/** @test */
+	public function shouldHaveInsertedRecordFor51Items() {
+		$this->assertEquals(51, count($this->_record_inserts));
+	}
+
+
+	/** @test */
+	public function shouldHaveInserted51Items() {
+		$this->assertEquals(51, count($this->_item_inserts));
+	}
+
+
+	/** @test */
+	public function recordsTitleShouldBeOriginTitle() {
+		foreach ($this->recordTitles() as $title)
+			$this->assertContains('MARIE CLAIRE', $title);
+	}
+
+
+	/** @test */
+	public function firstTitleShouldContainsNumber725() {
+		$this->assertEquals('MARIE CLAIRE 725', 
+												$this->_record_inserts[0]['alpha_titre']);
+	}
+
+
+	/** @test */
+	public function firstNumberShouldBe725() {
+		$this->assertEquals(
+			'725', 
+			$this->getSubfieldAt('461', 'v', 1, $this->marcDumpFor($this->unimarcAt(0))));
+	}
+
+
+	/** @test */
+	public function firstSetNameShouldBeMarieClaire() {
+		$this->assertEquals(
+			'MARIE CLAIRE', 
+			$this->getSubfieldAt('461', 't', 0, $this->marcDumpFor($this->unimarcAt(0))));
+	}
+
+
+	/** @test */
+	public function firstItemBarcodeShouldBe62432666() {
+		$this->assertEquals('62432666', $this->_item_inserts[0]['code_barres']);
+	}
+
+
+	/** @test */
+	public function firstItemZone995ShouldNotBeEmpty() {
+		$f995 = unserialize($this->_item_inserts[0]);
+		$this->assertTrue(0 < count($f995));
+	}
+
+
+	protected function unimarcAt($index) {
+		return $this->_record_inserts[$index]['unimarc'];
+	}
+
+
+	protected function marcDumpFor($unimarc) {
+		$temp_file = tempnam('/tmp', 'UNIMARC');
+		file_put_contents($temp_file, $unimarc);
+		exec('yaz-marcdump ' . $temp_file, $output);
+		return $output;
+	}
+
+
+	protected function recordTitles() {
+		return array_map(function ($value) {return $value['alpha_titre'];},
+										 $this->_record_inserts);
+	}
+
+
+	protected function getFieldsFromMarcDump($field_name, $dump) {
+		$values = [];
+		foreach ($dump as $field)
+			if ($field_name == substr($field, 0, strlen($field_name)))
+				$values[] = substr($field, strlen($field_name));
+		return $values;
+	}
+
+
+	protected function getSubfieldFromLine($field_name, $line) {
+		$parts = explode('$', $line);
+		foreach($parts as $part) {
+			$part = trim($part);
+			if ($field_name == substr($part, 0, strlen($field_name)))
+				return substr($part, strlen($field_name) + 1);
+		}
+	}
+
+
+	protected function getSubfieldAt($field, $sub_field, $index=0, $dump) {
+		return $this->getSubfieldFromLine(
+			$sub_field, 
+			$this->getFieldsFromMarcDump($field, $dump)[$index]);
+	}
+}
+?>
\ No newline at end of file
diff --git a/cosmogramme/tests/php/classes/unimarc_bienveillantes.txt b/cosmogramme/tests/php/classes/unimarc_bienveillantes.txt
new file mode 100644
index 0000000000000000000000000000000000000000..b3ae9b4c43e6a92b3717fe4955f4f3de0ab4df7d
--- /dev/null
+++ b/cosmogramme/tests/php/classes/unimarc_bienveillantes.txt
@@ -0,0 +1 @@
+01659nam0 2200313   450 0010008000000100031000080200017000390210027000560730018000831000041001011010008001421020007001501050018001571060006001752000041001812100080002222110013003022150032003153000014003473300416003617000038007778010039008159950099008549950079009539950086010329950067011189950072011859950088012571374068  a2-07-078097-Xbbr.d25 EUR  aFRb00639584  aFRbDLE-20060811-39736  a9782070780976  a20060811d2006    m  y0frey0103    ba| afre  aFR  ay   z   000a|  ar1 abienveillantes (Les)bTexte imprimÂe  a[Paris]cGallimarddimpr. 2006e27-Mesnil-sur-l'EstrÂeegImpr. Firmin-Didot  a20060821  a1 vol. (903 p.)d23 x 16 cm  aGlossaire  a1980, un Franco-Allemand achÁeve sa carriÁere de directeur d'une usine de dentelle du nord de la France. Quarante ans plus tÃot, il Âetait un fonctionnaire SS chargÂe de surveiller le bon dÂeroulement des opÂerations d'Âelimination sur le front de l'Est. A travers une sorte d'enquÃete autobiographique, il se lance sur ses propres traces. Prix Goncourt 2006. Grand prix du roman de l'AcadÂemie franÐcaise 2006. |aLittellbJonathanf1967-....4070 0aFRbBNFc20060811gAFNOR2intermrc  31374070aMÂediathÁeque Valbonne Sophia AntipolisbVf87316k LIT m20140517n20140614qFArLIV  31542841aMÂediathÁeque Roquefort les PinsbRLPf804508373kR LIT qFArLIV  31707638aMÂediathÁeque de Villeneuve-LoubetbVLfC0801018656k LIT qFArLIVlRES  31773929aMÂediathÁeque Albert CamusbMf318368k LIT qFArLIV  31779968aMÂediathÁeque Albert CamusbMf320619k LIT qFArLIVlRES  31914814aMÂediathÁeque Albert CamusbMf00001k  qFArNUMuConsultation uniquement
\ No newline at end of file
diff --git a/cosmogramme/tests/php/classes/unimarc_kohaperiodique.txt b/cosmogramme/tests/php/classes/unimarc_kohaperiodique.txt
new file mode 100644
index 0000000000000000000000000000000000000000..f118e04fb9612fbc8d49ce9c530ba5d8a325b9fc
--- /dev/null
+++ b/cosmogramme/tests/php/classes/unimarc_kohaperiodique.txt
@@ -0,0 +1 @@
+05918nas0a2200769   4500001000700000009011600007011001000123035001600133090001100149100004100160200001700201207000700218210003000225700005700255801002600312995009900338995010000437995009600537995009700633995009500730995009600825995009900921995009701020995010101117995009901218995010001317995010101417995009901518995010001617995009601717995012101813995010101934995009402035995007602129995008602205995009502291995008302386995007102469995007202540995007102612995007102683995007102754995008302825995009502908995011503003995012003118995009103238995007903329995007903408995007903487995007903566995010303645995007903748995012703827995007903954995007904033995007904112995010304191995007904294995012804373995012804501995011204629995010504741995010604846995010804952995008805060139179|cOPSYS|mSOCIETE1|p342;40;22;30;28;19;14;41;34;26;22;10|s1|fOPSYS810.BIB|nBM0104200|tUNI:23|004/11/2004|107/01/2014  d14,00  aval-0443310  a139179  a19960413m1955         frey50      ba1 aMARIE CLAIRE  a1-  aPariscMarie Claired1955 130121322aProuvost-BerrybEvelyne4dir. publ.9240635 0aFRbVALENCEc19960413  f62432666w2014-04-14609157604cPOL2052014-04-14qADUo0v725 Janvier 2013eArREVA40bPOL  f62432699w2014-04-14609160766cPOL2052014-04-14qADUo0v726 Février 2013eArREVA40bPOL  f62432735w2014-04-14609162980cPOL2052014-04-14qADUo0v727 Mars 2013eArREVA40bPOL  f62433010w2014-04-14609165713cPOL2052014-04-14qADUo0v728 Avril 2013eArREVA40bPOL  f62433137w2014-04-14609168535cPOL2052014-04-14qADUo0v729 Mai 2013eArREVA40bPOL  f62433191w2014-04-14609171463cPOL2052014-04-14qADUo0v730 Juin 2013eArREVA40bPOL  f62433364w2014-04-14609175540cPOL2052014-04-14qADUo0v731 Juillet 2013eArREVA40bPOL  f62433452w2014-04-14609180964cPOL2052014-04-14qADUo0v732 Août 2013eArREVA40bPOL  f62433547w2014-04-14609184367cPOL2052014-04-14qADUo0v733 Septembre 2013eArREVA40bPOL  f62433632w2014-04-14609186808cPOL2052014-04-14qADUo0v734 Octobre 2013eArREVA40bPOL  f62433658w2014-04-14609189687cPOL2052014-04-14qADUo0v735 Novembre 2013eArREVA40bPOL  f62433802w2014-04-14609195738cPOL2052014-04-14qADUo0v736 Décembre 2013eArREVA40bPOL  f62433951w2014-04-14609200229cPOL2052014-04-14qADUo0v737 Janvier 2014eArREVA40bPOL  f62433994w2014-04-24609205289cPOL2052014-04-14qADUo0v738 Février 2014eArREVA40bPOL  f62434088w2014-05-02609208167cPOL2052014-04-14qADUo0v739 Mars 2014eArREVA40bPOL  f62434197w2014-05-02609212885cPOL2052014-04-14n2014-06-27qADUo0v740 Avril 2014eArREVAm2014-05-0240bPOL  f62434358w2014-04-14609218563cPOL2052014-04-148REVUqADUo0v741 Mai 2014eArREVA40bPOL  f10042089w2014-06-06609582005cCHAB2052014-04-15qADUo0eRrREVm2014-05-1640bCHAB  f10024686-1o0w2014-04-15609582008cCHABrREV2052014-04-15bCHAB40  f10011741w2014-06-07609582009cCHAB2052014-04-15o0rREVm2014-05-1440bCHAB  f3388320w2014-05-23609582010cPLV2052014-04-15n2014-06-13o0rREVm2014-05-2340bPLV  f3387461w2014-05-10609582011cPLV2052014-04-15o0rREVm2014-05-0340bPLV  f3387204o0w2014-04-15609582012cPLVrREV2052014-04-15bPLV40  f20035483o0w2014-04-15609582013cPLVrREV2052014-04-15bPLV40  f3388203o0w2014-04-15609582014cPLVrREV2052014-04-15bPLV40  f3387317o0w2014-04-15609582015cPLVrREV2052014-04-15bPLV40  f3387257o0w2014-04-15609582016cPLVrREV2052014-04-15bPLV40  f3388286w2014-06-03609582017cPLV2052014-04-15o0rREVm2014-05-2140bPLV  f3387627w2014-06-07609582018cPLV2052014-04-15n2014-06-28o0rREVm2014-06-0740bPLV  f058030027w2014-06-07609582019cBLV2052014-04-15qADUo0vN°741 de mai 2014eKIOrREVm2014-05-2240bBLV  f058031406w2014-05-30609582020cBLV2052014-04-15qADUo0vN°738 de février 2014eKIOrREVm2014-05-0740bBLV  f20668w2014-05-28609582021cBLV2052014-04-15qADUo0eKIOrREVm2014-04-2640bBLV  f20364w2014-04-15609582022cBLV2052014-04-15qADUo0eKIOrREV40bBLV  f20123w2014-04-15609582023cBLV2052014-04-15qADUo0eKIOrREV40bBLV  f19881w2014-04-15609582024cBLV2052014-04-15qADUo0eKIOrREV40bBLV  f19596w2014-04-15609582025cBLV2052014-04-15qADUo0eKIOrREV40bBLV  f18833w2014-05-21609582026cBLV2052014-04-15n2014-06-18qADUo0eKIOrREVm2014-05-2140bBLV  f20892w2014-04-15609582027cBLV2052014-04-15qADUo0eKIOrREV40bBLV  f21416w2014-05-21609582028cBLV2052014-04-15n2014-05-13qADUo0vN°737 de janvier 2014eKIOrREVm2014-04-1240bBLV  f19373w2014-04-15609582029cBLV2052014-04-15qADUo0eKIOrREV40bBLV  f18584w2014-04-15609582030cBLV2052014-04-15qADUo0eKIOrREV40bBLV  f19086w2014-04-15609582031cBLV2052014-04-15qADUo0eKIOrREV40bBLV  f21160w2014-05-21609582032cBLV2052014-04-15n2014-06-18qADUo0eKIOrREVm2014-05-2140bBLV  f18315w2014-04-15609582033cBLV2052014-04-15qADUo0eKIOrREV40bBLV  f058031466w2014-05-16609582034cBLV2052014-04-15n2014-07-04qADUo0vN°739 de mars 2014eKIOrREVm2014-05-1640bBLV  f058031750w2014-04-26609582035cBLV2052014-04-15n2014-05-24qADUo0vN°740 d'avril 2014eKIOrREVm2014-04-2640bBLV  f3388393w2014-06-04609584687cPLV2052014-05-06n2014-06-25qADUo0vN° 742e1rREVm2014-06-0440bPLV  f058031786w2014-05-06609584718cBLV2052014-05-06qADUo0vN° 742 de juin 2014eKIOrREV40bBLV  f62445106w2014-05-06609584885cPOL2052014-05-068REVUqADUo1vN° 742 Juin 2014eArREVA40bPOL  f058032022w2014-06-04609588901cBLV2052014-06-04qADUo0vN° 743 de juillet 2014eKIOrREV40bBLV  f3388522w2014-06-04609588954cPLV2052014-06-04qADUo0vN° 743e0rREV40bPLV
diff --git a/library/Class/CasTicket.php b/library/Class/CasTicket.php
index 19e1bf9da615b9e679265890dfa7dc32fbdc7730..cdf8a1f37bb761dc1d1909bbcd1fafe5bb8e5bbf 100644
--- a/library/Class/CasTicket.php
+++ b/library/Class/CasTicket.php
@@ -19,6 +19,9 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA 
  */
 class Class_CasTicket {
+	//see http://www.jasig.org/cas/protocol#service-ticket-properties
+	const PREFIX = 'ST-';
+
 	public function getTicketForCurrentUser() {
 		if ($user = Class_Users::getIdentity())
 			return $this->getTicketForUser($user);
@@ -27,24 +30,29 @@ class Class_CasTicket {
 
 
 	public function getTicketForUser($user) {
-		return md5(Zend_Session::getId() . $user->getId());
+		return self::PREFIX.md5(Zend_Session::getId() . $user->getId());
 	}
 
 
 	public function save() {
 		if ($user = Class_Users::getIdentity())
 			Zend_Registry::get('cache')->save((string)$user->getId(),
-																				$this->getTicketForCurrentUser());
+																				$this->withoutPrefix($this->getTicketForCurrentUser()));
+	}
+
+
+	public function withoutPrefix($ticket) {
+		return str_replace(self::PREFIX, '', $ticket);
 	}
 
 
 	public function clear() {
 		if ($ticket = $this->getTicketForCurrentUser())
-			Zend_Registry::get('cache')->remove($ticket);
+			Zend_Registry::get('cache')->remove($this->withoutPrefix($ticket));
 	}
 
 	public function userForTicket($ticket) {
-		if ($id = (int)Zend_Registry::get('cache')->load($ticket))
+		if ($id = (int)Zend_Registry::get('cache')->load($this->withoutPrefix($ticket)))
 			return Class_Users::find($id);
 		return null;
 	}
diff --git a/library/Class/Catalogue.php b/library/Class/Catalogue.php
index 20adf9e55a393ce1feca7fe96ea3e62aa58ea0f9..afe53bb4d2f1b525637e2e3108f608df84d896b6 100644
--- a/library/Class/Catalogue.php
+++ b/library/Class/Catalogue.php
@@ -382,8 +382,16 @@ class Class_Catalogue extends Storm_Model_Abstract {
 
 
 	public function deleteThesaurusInFacette($id_thesaurus) {
-		$sql = Zend_Registry::get('sql');
-		$sql->query('update  notices set facettes = clean_spaces(replace(facettes,"H'.$id_thesaurus.'",""))  where match(facettes) against("+H'.$id_thesaurus.'"  in boolean mode)');
+		/*
+		 * Sites, articles and RSS records are first destroyed and then get their own selection of domains.
+		 * So therauri facettes must not be deleted. By the way, need to find a nicer implementation ...
+		 */
+		$query = 
+			'update notices set facettes = clean_spaces(replace(facettes,"H'.$id_thesaurus.'","")) '.
+			'where type_doc not in ('.implode(',', [Class_TypeDoc::ARTICLE, Class_TypeDoc::RSS, Class_TypeDoc::SITE]).') '.
+			'and match(facettes) against("+H'.$id_thesaurus.'" in boolean mode)';
+
+		Zend_Registry::get('sql')->query($query);
 	}
 
 
diff --git a/library/Class/CodifThesaurus.php b/library/Class/CodifThesaurus.php
index 8a3e53661e51b9a150197e74cb93f6c368c0de13..09e856c75f42d05e7fe6b347bed61939c8896b23 100644
--- a/library/Class/CodifThesaurus.php
+++ b/library/Class/CodifThesaurus.php
@@ -21,8 +21,8 @@
 
 class Class_CodifThesaurusLoader extends Storm_Model_Loader {
 	public function findThesaurusForCatalogue($catalogue_id) {
-		return Class_CodifThesaurus::findFirstBy(['id_origine'=> $catalogue_id,
-															 'CODE' => 'Catalogue']);
+		return Class_CodifThesaurus::getLoader()->findFirstBy(['id_origine'=> $catalogue_id,
+																													 'code' => Class_CodifThesaurus::CODE_CATALOGUE]);
 	}
 
 
@@ -151,6 +151,7 @@ class Class_CodifThesaurusLoader extends Storm_Model_Loader {
 
 class Class_CodifThesaurus extends Storm_Model_Abstract {
 	const CODE_FACETTE = 'H';
+	const CODE_CATALOGUE = 'Catalogue';
 	const MODE_HIERARCHY_CONTAINS = 1;
 	const MODE_LABEL_STARTS_WITH = 2;
 	const MODE_LABEL_CONTAINS = 3;
@@ -212,4 +213,4 @@ class Class_CodifThesaurus extends Storm_Model_Abstract {
 	}
 }
 
-?>
+?>
\ No newline at end of file
diff --git a/library/Class/CosmoVar.php b/library/Class/CosmoVar.php
index e2666407a7457cf661ea5c18df742849e5800708..9378c7ef39312bfa68ab97376418d797a95c6608 100644
--- a/library/Class/CosmoVar.php
+++ b/library/Class/CosmoVar.php
@@ -19,25 +19,42 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA 
  */
 
+class Class_CosmoVarLoader extends Storm_Model_Loader {
+	public function getValueOf($name) {
+		return ($model = Class_CosmoVar::find($name)) ? $model->getValeur() : null;
+	}
+
+
+	public function isSiteRetraitResaEnabled() {
+		return (1 === (int)Class_CosmoVar::get('site_retrait_resa'));
+	}
+
+
+	public function getLabelInList($name, $value) {
+		if (!$model = Class_CosmoVar::find($name))
+			return '';
+
+		foreach (explode(chr(13).chr(10), $model->getListe()) as $line) {
+			$parts = explode(':', $line);
+			if ($value == $parts[0])
+				return $parts[1];
+		}
+		return '';
+	}
+}
+
+
 class Class_CosmoVar extends Storm_Model_Abstract {
 	protected $_table_name = 'variables';
 	protected $_table_primary = 'clef';
+	protected $_loader_class = 'Class_CosmoVarLoader';
 
 	/**
 	 * @param string $name
-	 * @return mixed
+	 * @return mixed string|null
 	 */
 	public static function get($name) {
-		$var = self::find($name);
-		if ($var == null)
-			return null;
-		return $var->getValeur();
-	}
-
-
-	public static function isSiteRetraitResaEnabled() {
-		return (1 === (int)self::get('site_retrait_resa'));
+		return static::getValueOf($name);
 	}
 }
-
 ?>
\ No newline at end of file
diff --git a/library/Class/Cosmogramme/Integration.php b/library/Class/Cosmogramme/Integration.php
new file mode 100644
index 0000000000000000000000000000000000000000..a492c7f5541b76062451959e8cdde631e41efc6d
--- /dev/null
+++ b/library/Class/Cosmogramme/Integration.php
@@ -0,0 +1,75 @@
+<?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_Cosmogramme_Integration extends Storm_Model_Abstract {
+	protected $_table_name = 'integrations';
+	protected $_belongs_to = [
+		'bib' => ['model' => 'Class_IntBib',
+							'role' => 'int_bib',
+							'referenced_in' => 'id_bib'],
+
+		'profil_donnees' => ['model' => 'Class_Cosmogramme_ProfilDonnees',
+												 'role' => 'integration',
+												 'referenced_in' => 'profil']];
+
+
+	public function getFileSize() {
+		return ($size = filesize($this->getFilePath())) ? intval($size, 1024) : 0;
+	}
+
+
+	public function getFilePath() {
+		return (new CosmoPaths())->getBasePath() 
+			. Class_CosmoVar::getValueOf('integration_path') 
+			. $this->getFichier();
+	}
+
+
+	public function fileExists() {
+		return file_exists($this->getFilePath());
+	}
+
+
+	public function hasError() {
+		return 0 < count($this->getErrorsArray());
+	}
+
+
+	public function getErrorsArray() {
+		if (!$this->getErreurs())
+			return [];
+		return unserialize(stripslashes($this->getErreurs()));
+	}
+
+
+	public function hasWarning() {
+		return 0 < count($this->getWarningsArray());
+	}
+
+
+	public function getWarningsArray() {
+		if (!$this->getWarnings())
+			return [];
+		return unserialize(stripslashes($this->getWarnings()));
+	}
+}
+?>
\ No newline at end of file
diff --git a/library/Class/Cosmogramme/ProfilDonnees.php b/library/Class/Cosmogramme/ProfilDonnees.php
new file mode 100644
index 0000000000000000000000000000000000000000..ea66fc5e6f9d8f14a65e2e1a6e3e42d4434a2b64
--- /dev/null
+++ b/library/Class/Cosmogramme/ProfilDonnees.php
@@ -0,0 +1,27 @@
+<?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_Cosmogramme_ProfilDonnees extends Storm_Model_Abstract {
+	protected $_table_name = 'profil_donnees';
+	protected $_table_primary = 'id_profil';
+}
+?>
\ No newline at end of file
diff --git a/library/Class/Indexation/PseudoNotice.php b/library/Class/Indexation/PseudoNotice.php
index cfe8fef44be3c07ecb1984b2dd2c860a107c5061..280045bf2f580ef4804e6b008ca1c1ea062bdc31 100644
--- a/library/Class/Indexation/PseudoNotice.php
+++ b/library/Class/Indexation/PseudoNotice.php
@@ -63,8 +63,9 @@ class Class_Indexation_PseudoNotice {
 	public function __construct($type_doc, $datas) {
 		$this->_type_doc = (int)$type_doc;
 		$this->_indexation = new Class_Indexation();
-		$this->_datas = $datas;
-		$this->_model = call_user_func_array([$this->_model_name, 'find'], [$datas[$this->_id]]);
+		$this->_datas = array_change_key_case($datas, CASE_LOWER);
+		$this->_model = call_user_func_array([$this->_model_name, 'find'], 
+																				 [$this->_datas[$this->_id]]);
 	}
 
 	public function getId() {
@@ -431,7 +432,7 @@ class Class_Indexation_PseudoNotice_Album extends Class_Indexation_PseudoNotice{
 
 class Class_Indexation_PseudoNotice_Cms extends Class_Indexation_PseudoNotice{
 	protected $_model_name = 'Class_Article';
-	protected $_id = 'ID_ARTICLE';
+	protected $_id = 'id_article';
 	protected $_label='m1';
 
 	protected function _prepare() {
@@ -443,14 +444,14 @@ class Class_Indexation_PseudoNotice_Cms extends Class_Indexation_PseudoNotice{
 
 class Class_Indexation_PseudoNotice_Rss extends Class_Indexation_PseudoNotice{
 	protected $_model_name = 'Class_Rss';
-	protected $_id = 'ID_RSS';
+	protected $_id = 'id_rss';
 	protected $_label='m2';
 }
 
 
 class Class_Indexation_PseudoNotice_Sito extends Class_Indexation_PseudoNotice{
 	protected $_model_name = 'Class_Sitotheque';
-	protected $_id = 'ID_SITO';
+	protected $_id = 'id_sito';
 	protected $_label='m3';
 }
 
diff --git a/library/Class/Indexation/PseudoNotice/FacettesVisitor.php b/library/Class/Indexation/PseudoNotice/FacettesVisitor.php
index 3a9ae1e4282c9c2cfe2d025f0a6ac39ac7ed6614..ab10b77c79b6db3e5242cdf7076e08bdc455222b 100644
--- a/library/Class/Indexation/PseudoNotice/FacettesVisitor.php
+++ b/library/Class/Indexation/PseudoNotice/FacettesVisitor.php
@@ -121,7 +121,6 @@ class Class_Indexation_PseudoNotice_FacettesVisitor extends Class_Indexation_Pse
 	}
 
 	public function visitDomaine($domaine_ids) {
-		 
 		foreach(explode(';', $domaine_ids) as $domaine) {
 			if (!$thesaurus = Class_CodifThesaurus::findThesaurusForCatalogue($domaine))
 				continue;
diff --git a/library/Class/NoticeUnimarc/Writer.php b/library/Class/NoticeUnimarc/Writer.php
index e274db7e2f2d5e95171d327c7b15b24024c9cf88..bd6d15da04809d6eb853605e33af6eaaf983e8cf 100644
--- a/library/Class/NoticeUnimarc/Writer.php
+++ b/library/Class/NoticeUnimarc/Writer.php
@@ -159,7 +159,6 @@ class Class_NoticeUnimarc_Writer extends Class_NoticeUnimarc {
 
 
 	public function add_field($label = '000', $ind = '') {
-
 		// vérification des paramètres : au moins 2
 		if (func_num_args() < 3) {
 			$this->errors[] = '[add_field] impossible d\'ajouter un champ vide';
diff --git a/library/Class/Profil.php b/library/Class/Profil.php
index 4e03eb9aa2ff089b7a7fc768166d7e7c3b6b96c5..8e926f2871aab6f9e3c5be11f8aacb98fe2e21fc 100644
--- a/library/Class/Profil.php
+++ b/library/Class/Profil.php
@@ -413,19 +413,22 @@ class Class_Profil extends Storm_Model_Abstract {
 	 * @return array
 	 */
 	public function getOrCreateConfigAccueil($id_module, $type_module) {
+		if ($this->isTypeBoiteInBanniere($type_module))
+			return $this->getModuleAccueilPreferencesByType($type_module);
+
 		$cfg_accueil = $this->getCfgAccueilAsArray();
 
-		if (array_isset($id_module, $cfg_accueil['modules']))
-			$module = $cfg_accueil['modules'][$id_module];
-		else
-			$module = array('preferences' => array());
+		$module = (array_isset($id_module, $cfg_accueil['modules'])) ?
+			$cfg_accueil['modules'][$id_module] : 
+			['preferences' => []];
 
 		$preferences = [];
 		if (array_isset('preferences', $module))
 			$preferences = $module['preferences'];
 		
 		$preferences = array_merge($preferences, ['id_module' => $id_module]);
-		$default_values = Class_Systeme_ModulesAccueil::getInstance()->getValeursParDefaut($type_module);
+		$default_values = Class_Systeme_ModulesAccueil::getInstance()
+			->getValeursParDefaut($type_module);
 		return array_merge($default_values, $preferences);
 	}
 
@@ -448,8 +451,16 @@ class Class_Profil extends Storm_Model_Abstract {
 	 * @return Class_Profil
 	 */
 	public function updateModuleConfigAccueil($id_module, $module_config) {
+		if (isset($module_config['division']) 
+				&& (self::DIV_BANNIERE == $module_config['division'])
+				&& $this->hasParentProfil()) {
+			$this->getParentProfil()
+				->updateModuleConfigAccueil($id_module, $module_config)
+				->save();
+			return $this;
+		}
 
-		$cfg_accueil=$this->getCfgAccueilAsArray();
+		$cfg_accueil = $this->getCfgAccueilAsArray();
 		$cfg_accueil['modules'][$id_module] = $module_config;
 		$this->setCfgAccueil($cfg_accueil);
 		return $this;
@@ -503,34 +514,40 @@ class Class_Profil extends Storm_Model_Abstract {
 	 * @param int $id_module
 	 * @return array | null
 	 */
-	public function getModuleAccueilConfig($id_module){
-		$cls_module = Class_Systeme_ModulesAccueil::getInstance();
+	public function getModuleAccueilConfig($id_module) {
+		if ($this->hasParentProfil()) {
+			$parent_config = $this->getParentProfil()->getModuleAccueilConfig($id_module);
+			if (isset($parent_config['division'])
+					&& (self::DIV_BANNIERE == $parent_config['division']))
+				return $parent_config;
+		}
 
 		$cfg_accueil = $this->getCfgAccueilAsArray();
 		$modules_config = $cfg_accueil['modules'];
 
 		if (array_key_exists($id_module, $modules_config)) {
 			if (!is_array($modules_config[$id_module]))
-				$modules_config[$id_module] = array();
+				$modules_config[$id_module] = [];
 
-			$module = array_merge(array('type_module' => null,
-																	'preferences' => array()),
+			$module = array_merge(['type_module' => null,
+														 'preferences' => []],
 														$modules_config[$id_module]);
 
-			$default_prefs = $cls_module->getValeursParDefaut($module['type_module']);
+			$default_prefs = Class_Systeme_ModulesAccueil::getInstance()
+				->getValeursParDefaut($module['type_module']);
 			$default_prefs = array_merge($default_prefs,['id_module' => $id_module]);
 
-			if (!array_isset('preferences', $module))
-				$module['preferences'] = $default_prefs;
-			else
-				$module['preferences'] = array_merge($default_prefs, $module['preferences']);
+			$module['preferences'] = (!array_isset('preferences', $module)) ?
+				$default_prefs : array_merge($default_prefs, $module['preferences']);
 		
 			return $module;
 		}
+
 		return [];
 	}
 
-	/*
+
+	/**
 	 * @param string $type_module
 	 * @return array | null
 	 */
@@ -745,14 +762,16 @@ class Class_Profil extends Storm_Model_Abstract {
 	public function getCfgModulesPreferences($controller, $action, $subaction = '') {
 		$cfg_modules = $this->getCfgModulesAsArray();
 		
-		$cls_module = new Class_Systeme_ModulesAppli();
-		$preferences_defaut = $cls_module->getValeursParDefaut($controller,$action);
+		$preferences_defaut = $this->isPortail() 
+			? (new Class_Systeme_ModulesAppli())->getValeursParDefaut($controller,$action)
+			: Class_Profil::getLoader()->getPortail()->getCfgModulesPreferences($controller, $action, $subaction);
+
 		if (!array_key_exists($controller, $cfg_modules) || 
 			  !array_key_exists($action.$subaction, $cfg_modules[$controller]))
 			return $preferences_defaut;
-		else
-			return array_merge($preferences_defaut,
-												 $cfg_modules[$controller][$action.$subaction]);
+
+		return array_merge($preferences_defaut,
+											 $cfg_modules[$controller][$action.$subaction]);
 	}
 
 
@@ -1370,7 +1389,7 @@ class Class_Profil extends Storm_Model_Abstract {
 	 * @return bool
 	 */
 	public function isPortail() {
-		return 1 === $this->getId();
+		return 1 === (int)$this->getId();
 	}
 
 
diff --git a/library/Class/Sitotheque.php b/library/Class/Sitotheque.php
index e8f10d9361957da7c5ae6d738f06242b34b80a55..4aa33592f53c477176041c634b3e920da18da1f0 100644
--- a/library/Class/Sitotheque.php
+++ b/library/Class/Sitotheque.php
@@ -146,6 +146,16 @@ class Class_Sitotheque extends Storm_Model_Abstract {
 	}
 
 
+	public function index() {
+		return Class_Indexation_PseudoNotice::index($this);
+	}
+
+
+	public function getTypeDocId() {
+		return Class_TypeDoc::SITE;
+	}
+
+
 	//------------------------------------------------------------------------------------------------------
 	// Get site
 	//------------------------------------------------------------------------------------------------------
diff --git a/library/Class/Systeme/ModulesAccueil/Login.php b/library/Class/Systeme/ModulesAccueil/Login.php
index 5a91f2973f49eae71f7c60a14d608499f9ba3603..e7a2b0d89bef512de46e5c93e2525cf3c8d08abf 100644
--- a/library/Class/Systeme/ModulesAccueil/Login.php
+++ b/library/Class/Systeme/ModulesAccueil/Login.php
@@ -55,7 +55,8 @@ class Class_Systeme_ModulesAccueil_Login extends Class_Systeme_ModulesAccueil_Nu
 		'lien_compte' => '» Mon compte',
 		'lien_deconnection' => '» Se déconnecter',
 		'autocomplete_off' => 1 ,// si == 1, rajoute autocomplete="off" au formulaire
-		'profil_redirect' => '0'
+		'profil_redirect' => '0',
+		'profil_logout_redirect' => '0'
 		];
 }
 ?>
\ No newline at end of file
diff --git a/library/Class/Systeme/ModulesAppli.php b/library/Class/Systeme/ModulesAppli.php
index fe6f5aed8dae5a07df4aedb87b8126a3cb260ccb..c597a8da1032d49d2784cb1e07fa2720fe76ec16 100644
--- a/library/Class/Systeme/ModulesAppli.php
+++ b/library/Class/Systeme/ModulesAppli.php
@@ -263,6 +263,14 @@ class Class_Systeme_ModulesAppli extends Class_Systeme_ModulesAbstract {
 		case "register":
 			$ret["barre_nav"] = "S'inscrire";						// Barre de nav
 			$ret["titre"] = "Demande d'inscription";				// Titre de la boite
+			$ret["register_help"] = "Remplissez les champs ci-dessous\n"
+				."Un mail de confirmation vous sera envoyé.\n"
+				."Vous devrez cliquer sur le lien pour confirmer la création de votre compte.";				// Texte d'aide
+			$ret["register_confirm"] = "Cher Internaute,<br />"
+				."Merci pour votre inscription.<br />"
+				."Pour vérifier l'adresse e-mail associée à votre compte, nous avons envoyé un courrier "
+				."électronique à l'adresse indiquée. Pour activer votre compte, accédez à votre messagerie "
+				."et cliquez sur le lien fourni dans le courrier de vérification.";
 			break;
 		case "lostpass":
 			$ret["barre_nav"] = "demande de mot de passe";		 // Barre de nav
diff --git a/library/Class/Users.php b/library/Class/Users.php
index 422a430a8533f8afff525b555c2777c7314199ec..d95ea625c6f521f81f0df4777cd3de3718e36b86 100644
--- a/library/Class/Users.php
+++ b/library/Class/Users.php
@@ -826,92 +826,55 @@ class Class_Users extends Storm_Model_Abstract {
 		sqlExecute("delete from bib_admin_users where ID_USER=$id_user");
 	}
 
-	//------------------------------------------------------------------------------------------------------
-	// Vérification d'adresse e-mail
-	//------------------------------------------------------------------------------------------------------
-	function verifMail($adresse) {
-		$syntaxe='#^[\w.-]+@[\w.-]+\.[a-zA-Z]{2,5}$#';
-		if (!preg_match($syntaxe,$adresse))
-			return false;
-
-		$ctrl1 = fetchOne("select count(*) from bib_admin_users_non_valid Where MAIL='$adresse'");
-		$ctrl2 = fetchOne("select count(*) from bib_admin_users Where MAIL='$adresse'");
-		return ($ctrl1 + $ctrl2 === 0);
-	}
-
 	//------------------------------------------------------------------------------------------------------
 	// Enregistrement d'une demande d'inscription
 	//------------------------------------------------------------------------------------------------------
-	public function registerUser($data)
-	{
+	public function registerUser($data)	{
 		// Test champ valid
 		extract($data);
-		$test_login = $this->ifLoginExist($login);
-		$test_mail = $this->verifMail($mail);
-
 		$errors = array();
-		if($test_login == 1)
+		if($this->ifLoginExist($login))
 			$errors []= $this->_("Cet identifiant existe déjà.");
-		elseif(trim($login) =="")
-			$errors []= $this->_("Vous n'avez pas saisi de login.");
 
-		if($mdp != $mdp2)
-			$errors []= $this->_("Vous n'avez pas saisi les mêmes mots de passe.");
-		elseif(trim($mdp) =="")
-			$errors []= $this->_("Le mot de passe est obligatoire.");
+		if ($error = implode('<br/>', $errors)) {
+			$ret["error"]=$error;
+			return $ret;
+		}
+		
+		Class_UsersNonValid::newInstance(['login' => $login,
+																			'password' => $mdp,
+																			'mail' => $mail,
+																			'cle' => $cle])->save();
 
-		if($test_mail == 0)
-			$errors []= $this->_("L'adresse e-mail est invalide ou est déjà utilisée.");
-		elseif(trim($test_mail) =="")
-			$errors []= $this->_("Vous n'avez pas saisi d'E-mail.");
+		$profil = Class_Profil::getCurrentProfil();
 
-		if(trim($captcha) =="")
-			$errors []= $this->_("Vous n'avez pas saisi le code anti-spam.");
-		elseif($_SESSION['captcha_code'] != $captcha)
-			$errors []= $this->_("Le code anti-spam est invalide.");
 
-		$error = implode('<br/>', $errors);
+		// Corps du mail
+		$message_mail=[];
+		$message_mail[]=$this->_("Bonjour,");
+		$message_mail[]=$this->_("Vous avez fait une demande d'inscription sur le portail:").' '.$profil->getLibelle();
+		$message_mail[]=$this->_("Pour activer votre compte, merci de cliquer sur le lien suivant:")." http://".$_SERVER["SERVER_NAME"].BASE_URL.'/opac/auth/activeuser?c='.$cle;
+		$message_mail[]=$this->_("Si vous n'êtes pas à l'origine de cette demande d'inscription, merci de ne pas tenir compte de cet e-mail, et l'inscription ne sera pas activée.");
 
-		// Tout est ok : on ecrit
-		if (!$error)
-		{
-			$enreg = array(
-					'ID_USER' => '',
-					'LOGIN' => $login,
-					'PASSWORD' => $mdp,
-					'MAIL' => $mail,
-					'CLE' => $cle
-				);
-			sqlInsert("bib_admin_users_non_valid",$enreg);
-
-			$profil = Class_Profil::getCurrentProfil();
-
-			// Corps du mail
-			$message_mail=[];
-			$message_mail[]=$this->_("Bonjour,");
-			$message_mail[]=$this->_("Vous avez fait une demande d'inscription sur le portail.");
-			$message_mail[]=$this->_("Pour activer votre compte, merci de cliquer sur le lien suivant :");
-			$message_mail[]=$this->_("Url d'activation : %s",
-																					sprintf('<a href="http://'.$_SERVER["SERVER_NAME"].BASE_URL.'/opac/auth/activeuser?c='.$cle.'">%s</a>',
-																									$this->_('Valider mon inscription')));
-			$message_mail[]=$this->_("Si vous n'êtes pas à l'origine de cette demande d'inscription, merci de ne pas tenir compte de cet e-mail, et l'inscription ne sera pas activée.");
-			$message_mail[]=$profil->getLibelle();
-			$message_mail[]=sprintf("<a href=http://".$_SERVER["SERVER_NAME"].BASE_URL.">%s</a>",
-																$this->_('Aller sur le portail'));
-
-			// envoi du mail de confirmation
-			$cls_mail=new Class_Mail();
-			$erreur=$cls_mail->sendMail($profil->getLibelle(), implode('\n',$message_mail), $mail, "");
-			if($erreur) 
-				$ret["message_mail"]='<p class="error">'.$erreur.'</p>';
-			else {
-				$message_mail = getVar('REGISTER_OK') ? getVar('REGISTER_OK') : $this->_('Un mail viens de vous être envoyé pour confirmer votre inscription');
-				$ret["message_mail"]=urldecode(str_replace('%0D%0A',BR,$message_mail));
-			}
+		// envoi du mail de confirmation
+		$mail_admin = $profil->getMailSiteOrPortail();
+		try {
+			(new ZendAfi_Mail('utf8'))
+				->setSubject($profil->getLibelle())
+				->setBodyText(implode("\n\n",$message_mail))
+				->setFrom($mail_admin)
+				->addTo($mail)
+				->addBcc($mail_admin)
+				->send();
+		} catch (Exception $e) {
+			$ret["message_mail"]='<p class="error">'.$e->getMessage().'</p>';
+			return $ret;
 		}
 
-		// Affichage des erreurs
-		else $ret["error"]=$error;
+
+		$message_confirm = $profil->getCfgModulesPreferences('auth', 'register')['register_confirm'];
+		$ret["message_confirm"]=nl2br($message_confirm);
+
 		return $ret;
 	}
 
@@ -932,27 +895,28 @@ class Class_Users extends Storm_Model_Abstract {
 		if(!trim($user)) 
 			return array('error' => 1);
 
-		$enreg=fetchEnreg("Select * from bib_admin_users where LOGIN='$user'");
-		if (!$enreg) $enreg=fetchEnreg("Select * from bib_admin_users_non_valid where LOGIN='$user'");
-		if (!$enreg["LOGIN"]) 
-			return array('error' => 2);
+		if (!$user = Class_Users::getLoader()->findFirstBy(['login' => $user]))
+			$user = Class_UsersNonValid::getLoader()->findFirstBy(['login' => $user]);
 
-		if (!$enreg["MAIL"]) 
-			return array('error' => 4);
+		if (!$user)
+			return ['error' => 2];
+
+		if (!$user->hasMail()) 
+			return ['error' => 4];
 	
 		// envoi du mail
 		$message_mail = sprintf("%s\n\n",
 														$this->_('Vous avez fait une demande de mot de passe sur le portail.'));
-		$message_mail .= $this->_("Votre identifiant : %s\n", $enreg["LOGIN"]);
-		$message_mail .= $this->_("Votre mot de passe : %s\n", $enreg["PASSWORD"]);
+		$message_mail .= $this->_("Votre identifiant : %s\n", $user->getLogin());
+		$message_mail .= $this->_("Votre mot de passe : %s\n", $user->getPassword());
 		$message_mail .= sprintf("%s\n\n", $this->_('Bonne navigation sur le portail'));
-		$mail = new Class_Mail();
-		$erreur = $mail->sendMail(Class_Profil::getCurrentProfil()->getTitreSite(), $message_mail, $enreg["MAIL"]);
+		$erreur = (new Class_Mail())->sendMail(Class_Profil::getCurrentProfil()->getTitreSite(), 
+																					 $message_mail, 
+																					 $user->getMail());
 
-		if($erreur) 
-			return array('message_mail' => '<p class="error">'.$erreur.'</p>');
-			
-		return array('message_mail' => $this->_("Un mail vient de vous être envoyé avec vos paramètres de connexion."));
+		return $erreur 
+			? ['message_mail' => '<p class="error">'.$erreur.'</p>']
+			: ['message_mail' => $this->_("Un mail vient de vous être envoyé avec vos paramètres de connexion.")];
 	}
 
 	//------------------------------------------------------------------------------------------------------
diff --git a/library/Class/WebService/BibNumerique/Numilog.php b/library/Class/WebService/BibNumerique/Numilog.php
index 5b4e65ef291efd20e71519cd4b34f4ecc7474b3c..7b04715e1d7040dab743c8feee9dcb8f06e2ca20 100644
--- a/library/Class/WebService/BibNumerique/Numilog.php
+++ b/library/Class/WebService/BibNumerique/Numilog.php
@@ -53,7 +53,6 @@ class Class_WebService_BibNumerique_Numilog extends Class_WebService_BibNumeriqu
 
 
 	protected function _deleteNonHarvested() {
-		
 		if (0 < count($this->getHarvestedIds()))
 			Class_Album::getLoader()
 				->deleteBy(['where' => 'url_origine="'.self::BASE_URL.'" and id_origine not in (\'' . implode("', '", $this->getHarvestedIds()) . '\')']);
diff --git a/library/ZendAfi/Controller/Action.php b/library/ZendAfi/Controller/Action.php
index fc0100b4c8a829f022d51890de6a89c508ae6fb1..81832e2c78f9016ac35e272aa500beea3243147c 100644
--- a/library/ZendAfi/Controller/Action.php
+++ b/library/ZendAfi/Controller/Action.php
@@ -142,8 +142,19 @@ class ZendAfi_Controller_Action extends Zend_Controller_Action {
 
 
 	protected function _redirectToParentProfil() {
-		$current_profil = Class_Profil::getCurrentProfil();
-		$this->_redirect($current_profil->hasParentProfil() ? '/opac/index/index/id_profil/'.$current_profil->getParentProfil()->getId() : '/');
+		$profil = Class_Profil::getCurrentProfil();
+		$url = $profil->hasParentProfil() ? 
+			'/opac/index/index/id_profil/' . $profil->getParentProfil()->getId() : 
+			'/';
+		$this->_redirect($url);
+	}
+
+
+	protected function _redirectToLogoutProfil($preferences) {
+		$target = (int)$preferences['profil_logout_redirect'];
+		(0 < $target) ?
+			$this->_redirect('/opac/index/index/id_profil/' . $target) :
+			$this->_redirectToParentProfil();
 	}
 
 
diff --git a/library/ZendAfi/Controller/Plugin/CosmoAuth.php b/library/ZendAfi/Controller/Plugin/CosmoAuth.php
new file mode 100644
index 0000000000000000000000000000000000000000..6763f85861857cf416eaae80dafc635c2c1ead0c
--- /dev/null
+++ b/library/ZendAfi/Controller/Plugin/CosmoAuth.php
@@ -0,0 +1,35 @@
+<?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 ZendAfi_Controller_Plugin_CosmoAuth extends Zend_Controller_Plugin_Abstract {
+	public function preDispatch(Zend_Controller_Request_Abstract $request) {
+		if (('cosmo' != $request->getModuleName())
+				|| 'auth' == $request->getControllerName())
+			return;
+
+		if (!isset($_SESSION['passe'])) {
+			$request->setControllerName('auth');
+			$request->setActionName('not-logged');
+		}
+	}
+}
+?>
\ No newline at end of file
diff --git a/library/ZendAfi/Form/Element/Captcha.php b/library/ZendAfi/Form/Element/Captcha.php
new file mode 100644
index 0000000000000000000000000000000000000000..5d7e4ba0f31d24312f2051b45256dfae2119af43
--- /dev/null
+++ b/library/ZendAfi/Form/Element/Captcha.php
@@ -0,0 +1,38 @@
+<?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 ZendAfi_Form_Element_Captcha extends Zend_Form_Element_Captcha { 
+	protected static $_be_valid = false; //for tests
+
+	public static function beValid() {
+		static::$_be_valid = true;
+	}
+
+	public static function reset() {
+		static::$_be_valid = false;
+	}
+
+	public function isValid($value, $context = null) {
+		return static::$_be_valid ?	true : parent::isValid($value, $context);
+	}
+}
+?>
\ No newline at end of file
diff --git a/library/ZendAfi/Form/Element/Email.php b/library/ZendAfi/Form/Element/Email.php
new file mode 100644
index 0000000000000000000000000000000000000000..71f95e4ec79ceec211cd45d6f9c6dd2d58e5d090
--- /dev/null
+++ b/library/ZendAfi/Form/Element/Email.php
@@ -0,0 +1,35 @@
+<?php
+/**
+ * Copyright (c) 2012, 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 ZendAfi_Form_Element_Email extends Zend_Form_Element_Text {
+	/**
+	 * HTML5 input type = url
+	 * @var string
+	 */
+	public $helper = 'formEmail';
+
+
+	public function init() {
+		$this->addValidator(new ZendAfi_Validate_EmailAddress());
+	}
+}
+
+?>
\ No newline at end of file
diff --git a/library/ZendAfi/Mail.php b/library/ZendAfi/Mail.php
index 75fa147474e4a04cf107b779d7b2b9049a2d2274..ef9a9a66fa48eeafcd70752581f4e082fad1f18a 100644
--- a/library/ZendAfi/Mail.php
+++ b/library/ZendAfi/Mail.php
@@ -50,6 +50,8 @@ class ZendAfi_Mail extends Zend_Mail {
 				parent::addBcc($email);
 		} catch (Zend_Validate_Exception $e) {
 		}
+
+		return $this;
 	}
 
     /**
diff --git a/library/ZendAfi/Validate/Equals.php b/library/ZendAfi/Validate/Equals.php
new file mode 100644
index 0000000000000000000000000000000000000000..9966798cedb78dd00f135d8e2c95ceab6dcb5fba
--- /dev/null
+++ b/library/ZendAfi/Validate/Equals.php
@@ -0,0 +1,47 @@
+<?php
+/**
+ * Copyright (c) 2012, 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 ZendAfi_Validate_Equals extends Zend_Validate_Abstract {
+	const DIFFERENT_VALUES_ERROR = 'differentValuesError';
+	
+	/** @var string */
+	protected $_field_to_compare;
+
+	/**
+	 * @param $field_to_compare string
+	 */
+	public function __construct($field_to_compare) {
+		$this->_field_to_compare = $field_to_compare;
+	}
+
+	
+	/**
+	 * @param $value mixed
+	 * @param $fields array
+	 * @return boolean
+	 */
+	public function isValid($value, array $fields_values = array()) {
+		if (!$valid = ($value == $fields_values[$this->_field_to_compare]))
+			$this->_error(self::DIFFERENT_VALUES_ERROR);
+		return $valid;
+	}
+}
+?>
\ No newline at end of file
diff --git a/library/ZendAfi/Validate/LoginExists.php b/library/ZendAfi/Validate/LoginExists.php
new file mode 100644
index 0000000000000000000000000000000000000000..0c7455020316b53270b1efe0ced4ec39d387c2ea
--- /dev/null
+++ b/library/ZendAfi/Validate/LoginExists.php
@@ -0,0 +1,42 @@
+<?php
+/**
+ * Copyright (c) 2012, 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 ZendAfi_Validate_LoginExists extends Zend_Validate_Abstract {
+	const LOGIN_EXISTS = 'loginExists';
+ 
+	protected $_messageTemplates = [
+		self::LOGIN_EXISTS => "L'identifiant '%value%' existe déjà."
+	];
+	
+	/**
+	 * @param $value mixed
+	 * @param $fields array
+	 * @return boolean
+	 */
+	public function isValid($value, array $fields_values = array()) {
+		$this->_setValue($value);
+		if (!$valid = (0 == (Class_UsersNonValid::getLoader()->countBy(['login' => $value])
+											 + Class_Users::getLoader()->countBy(['login' => $value]))))
+			$this->_error(self::LOGIN_EXISTS);
+		return $valid;
+	}
+}
+?>
\ No newline at end of file
diff --git a/library/ZendAfi/Validate/MailEquals.php b/library/ZendAfi/Validate/MailEquals.php
new file mode 100644
index 0000000000000000000000000000000000000000..4681e2ce0d7de6635761ae0395fd6839ab65472a
--- /dev/null
+++ b/library/ZendAfi/Validate/MailEquals.php
@@ -0,0 +1,28 @@
+<?php
+/**
+ * Copyright (c) 2012, 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 ZendAfi_Validate_MailEquals extends ZendAfi_Validate_Equals {
+	protected $_messageTemplates = [
+		self::DIFFERENT_VALUES_ERROR   => "Les champs 'E-mail' sont différents"
+		];
+
+}
+?>
\ No newline at end of file
diff --git a/library/ZendAfi/Validate/MailExists.php b/library/ZendAfi/Validate/MailExists.php
new file mode 100644
index 0000000000000000000000000000000000000000..85c78cf8f50725bbc8ce023018b5822cf48393bd
--- /dev/null
+++ b/library/ZendAfi/Validate/MailExists.php
@@ -0,0 +1,42 @@
+<?php
+/**
+ * Copyright (c) 2012, 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 ZendAfi_Validate_MailExists extends Zend_Validate_Abstract {
+	const EMAIL_EXISTS = 'mailExists';
+ 
+	protected $_messageTemplates = [
+		self::EMAIL_EXISTS => "L'e-mail '%value%' existe déjà."
+	];
+	
+	/**
+	 * @param $value mixed
+	 * @param $fields array
+	 * @return boolean
+	 */
+	public function isValid($value, array $fields_values = array()) {
+		$this->_setValue($value);
+		if (!$valid = (0 == (Class_UsersNonValid::getLoader()->countBy(['mail' => $value])
+											 + Class_Users::getLoader()->countBy(['mail' => $value]))))
+			$this->_error(self::EMAIL_EXISTS);
+		return $valid;
+	}
+}
+?>
\ No newline at end of file
diff --git a/library/ZendAfi/Validate/PasswordEquals.php b/library/ZendAfi/Validate/PasswordEquals.php
new file mode 100644
index 0000000000000000000000000000000000000000..19d55fb0a04c753cd75acc41ea5c9bfda9f54af9
--- /dev/null
+++ b/library/ZendAfi/Validate/PasswordEquals.php
@@ -0,0 +1,28 @@
+<?php
+/**
+ * Copyright (c) 2012, 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 ZendAfi_Validate_PasswordEquals extends ZendAfi_Validate_Equals {
+	protected $_messageTemplates = [
+		self::DIFFERENT_VALUES_ERROR   => "Les champs 'Mot de passe' sont différents"
+		];
+
+}
+?>
\ No newline at end of file
diff --git a/library/ZendAfi/View/Helper/ComboProfils.php b/library/ZendAfi/View/Helper/ComboProfils.php
index 41119de64b54dfb2b7d60fe9c8dbabf467107528..468cce5465cb1c3d21f95c0e54e67fce9a037f24 100644
--- a/library/ZendAfi/View/Helper/ComboProfils.php
+++ b/library/ZendAfi/View/Helper/ComboProfils.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 - Combo des menu paramétrés
-//////////////////////////////////////////////////////////////////////////////////////////////////////
 
 class ZendAfi_View_Helper_ComboProfils extends ZendAfi_View_Helper_BaseHelper {
 	protected 
@@ -31,15 +28,15 @@ class ZendAfi_View_Helper_ComboProfils extends ZendAfi_View_Helper_BaseHelper {
 		$_id_zone,
 		$_id_bib;
 
-	function comboProfils($id_zone='ALL', $id_bib='ALL', $id_profil=1, $autoload=false, $empty_option = false)	{
+	public function comboProfils($id_zone='ALL', $id_bib='ALL', $id_profil=1, 
+															 $autoload=false, $empty_option=false)	{
 		$this->_select_profil_id = $id_profil;
-		if($empty_option)
+		if ($empty_option)
 			$this->addEmptyOption();
 		$this->_id_zone = 'ALL';
 		$this->_id_bib = 'ALL';
 
-		return $this->renderSelect($autoload,
-															 $this->renderProfilsByBibGroups());
+		return $this->renderSelect($autoload, $this->renderProfilsByBibGroups());
 	}
 
 
@@ -71,35 +68,36 @@ class ZendAfi_View_Helper_ComboProfils extends ZendAfi_View_Helper_BaseHelper {
 
 
 	public function renderSelect($autoload ,$content) {
-		$onchange='';
-		if($autoload==true) 
-			$onchange=' onchange="window.location=\''.BASE_URL.'?id_profil=\' + this.value"'; 
-
 		if ($this->_add_empty_option)
-			$content = '<option value=""></option>'.$content;
+			$content = '<option value=""></option>' . $content;
+
+		$extra = '';
+		if ($autoload) 
+			$extra = ' onchange="window.location=\''.BASE_URL.'?id_profil=\' + this.value"'; 
 
-		return '<select id="'.$this->_select_id.'" name="'.$this->_select_name.'"'.$onchange.'>'.$content.'</select>';
+		return sprintf('<select id="%s" name="%s"%s>%s</select>',
+									 $this->_select_id, $this->_select_name, $extra, $content);
 	}
 
 
 	public function getProfilsByBib() {
-		$profils = Class_Profil::getLoader()->findAllByZoneAndBib($this->_id_zone,
-																															$this->_id_bib);
-		$profils_by_bib = array();
+		$profils = Class_Profil::findAllByZoneAndBib($this->_id_zone,
+																								 $this->_id_bib);
+		$profils_by_bib = [];
 		foreach ($profils as $profil) {
-			if ($profil->hasParentProfil()) continue;
+			if ($profil->hasParentProfil()) 
+				continue;
 
-			if ($profil->isInPortail()) {
-				$libelle = $this->translate()->_('Portail');
-			} else {
-				$libelle = $profil->getBibLibelle();
-			}
+			$libelle = ($profil->isInPortail()) ?
+				$this->translate()->_('Portail') : 
+				$profil->getBibLibelle();
 
 			if (!array_key_exists($libelle, $profils_by_bib))
-				$profils_by_bib[$libelle] = array();
+				$profils_by_bib[$libelle] = [];
 
-			$profils_by_bib[$libelle] []= $profil;
+			$profils_by_bib[$libelle][]= $profil;
 		}
+
 		ksort($profils_by_bib);
 
 		return $profils_by_bib;
@@ -122,7 +120,8 @@ class ZendAfi_View_Helper_ComboProfils extends ZendAfi_View_Helper_BaseHelper {
 
 
 	public function renderProfilOption($profil, $libelle) {
-		$selected = ($this->_select_profil_id == $profil->getId()) ? 'selected="selected"' : '';
+		$selected = ($this->_select_profil_id == $profil->getId()) 
+			? 'selected="selected"' : '';
 		return '<option  value="'.$profil->getId().'" '.$selected.'>'.$libelle.'</option>';
 	}
 }
\ No newline at end of file
diff --git a/library/ZendAfi/View/Helper/CosmoIntegration.php b/library/ZendAfi/View/Helper/CosmoIntegration.php
new file mode 100644
index 0000000000000000000000000000000000000000..528cb426fff8910921841185e78646796b42f74b
--- /dev/null
+++ b/library/ZendAfi/View/Helper/CosmoIntegration.php
@@ -0,0 +1,50 @@
+<?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 ZendAfi_View_Helper_CosmoIntegration extends Zend_View_Helper_Abstract {
+	public function cosmoIntegration($run) {
+		$this->_html = '';
+		$this
+			->labelAndData('Bibliothèque', $run->getBib()->getNomCourt())
+			->labelAndData('Fichier', $run->getFichier())
+			->labelAndData('Intégré le', 
+										 $this->view->getHumanDate($run->getTraite(), 'EEEE d MMMM yyyy'))
+			->labelAndData('Type d\'opération', 
+										 Class_CosmoVar::getLabelInList('import_type_operation', 
+																										$run->getTypeOperation()))
+			->labelAndData('Profil d\'import', $run->getProfilDonnees()->getLibelle())
+			->labelAndData('Format de fichier', 
+										 Class_CosmoVar::getLabelInList('import_format', 
+																										$run->getProfilDonnees()->getFormat()))
+			;
+		
+		return $this->_html;
+	}
+
+
+	protected function labelAndData($label, $data) {
+		$this->_html .= sprintf('<span class="violet">%s : </span><span class="vert">%s</span><br>',
+														$label, $data);
+		return $this;
+	}
+}
+?>
\ No newline at end of file
diff --git a/library/ZendAfi/View/Helper/FormEmail.php b/library/ZendAfi/View/Helper/FormEmail.php
new file mode 100644
index 0000000000000000000000000000000000000000..505a323b84ebb30d7ad722ee720109e95f709968
--- /dev/null
+++ b/library/ZendAfi/View/Helper/FormEmail.php
@@ -0,0 +1,30 @@
+<?php
+/**
+ * Copyright (c) 2012, 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 ZendAfi_View_Helper_FormEmail extends Zend_View_Helper_FormText {
+	public function formEmail($name, $value = null, $attribs = null)	 {
+		return str_replace('type="text"', 
+											 'type="email"',
+											 $this->formText($name, $value, $attribs));
+	}
+}
+
+?>
\ No newline at end of file
diff --git a/library/ZendAfi/View/Helper/Notice/Avis.php b/library/ZendAfi/View/Helper/Notice/Avis.php
index 8b40fb35ebf25f092a78251f506a56515b40ee09..9e284118d4bacfe4b366120078af7f73db39ade9 100644
--- a/library/ZendAfi/View/Helper/Notice/Avis.php
+++ b/library/ZendAfi/View/Helper/Notice/Avis.php
@@ -71,7 +71,7 @@ class ZendAfi_View_Helper_Notice_Avis extends Zend_View_Helper_HtmlElement {
 			$avis_helper = $this->view->getHelper('Avis');
 			if (($user = Class_Users::getIdentity()) 
 					&& $user->isBibliothecaire())
-				$avis_helper->setAdminActions(['edit']);
+				$avis_helper->setAdminActions(['edit', 'del']);
 
 			$html.='<tr><td colspan="3">&nbsp;</td></tr>';
 			$html.='<tr><td class="notice_info_ligne_titre" align="left" colspan="3">' . $avis[$source]["titre"] . '</td></tr>';
diff --git a/library/fonctions/useragent.php b/library/fonctions/useragent.php
index 489eea1f9f0f8df3aa02ba9202817672d8a98744..10d67ce6ff6946fb98088b6e210d276beb384833 100644
--- a/library/fonctions/useragent.php
+++ b/library/fonctions/useragent.php
@@ -35,7 +35,7 @@ function isTelephone() {
 
 
 function isUserAgentBot($useragent) {
-	return false !== strpos(strtoupper($useragent), 'BOT/');
+	return 0 !== preg_match('/(bot\/|sistrix|voilabot)/i', $useragent);
 }
 
 
diff --git a/library/startup.php b/library/startup.php
index fae9c4714a4ae63fc13e3a531dd91bd1c0b0f1c9..554914dbeefa55ff08acaded8d9c0784fe6d3bdb 100644
--- a/library/startup.php
+++ b/library/startup.php
@@ -56,7 +56,7 @@ function defineConstant($name, $value) {
 
 function setupConstants() {
 	defineConstant('VERSION_PERGAME','6.45');
-	defineConstant('RELEASE_NUMBER', VERSION_PERGAME.'.beta');
+	defineConstant('RELEASE_NUMBER', VERSION_PERGAME.'.3');
 
 	defineConstant('ROOT_PATH',  realpath(dirname(__FILE__).'/..').'/');
 
diff --git a/scripts/emacs/magit-1.2.0/.dir-locals.el b/scripts/emacs/magit-1.2.1/.dir-locals.el
similarity index 100%
rename from scripts/emacs/magit-1.2.0/.dir-locals.el
rename to scripts/emacs/magit-1.2.1/.dir-locals.el
diff --git a/scripts/emacs/magit-1.2.0/.gitignore b/scripts/emacs/magit-1.2.1/.gitignore
similarity index 100%
rename from scripts/emacs/magit-1.2.0/.gitignore
rename to scripts/emacs/magit-1.2.1/.gitignore
diff --git a/scripts/emacs/magit-1.2.0/CONTRIBUTING.md b/scripts/emacs/magit-1.2.1/CONTRIBUTING.md
similarity index 100%
rename from scripts/emacs/magit-1.2.0/CONTRIBUTING.md
rename to scripts/emacs/magit-1.2.1/CONTRIBUTING.md
diff --git a/scripts/emacs/magit-1.2.0/COPYING b/scripts/emacs/magit-1.2.1/COPYING
similarity index 100%
rename from scripts/emacs/magit-1.2.0/COPYING
rename to scripts/emacs/magit-1.2.1/COPYING
diff --git a/scripts/emacs/magit-1.2.0/Makefile b/scripts/emacs/magit-1.2.1/Makefile
similarity index 100%
rename from scripts/emacs/magit-1.2.0/Makefile
rename to scripts/emacs/magit-1.2.1/Makefile
diff --git a/scripts/emacs/magit-1.2.0/README.md b/scripts/emacs/magit-1.2.1/README.md
similarity index 100%
rename from scripts/emacs/magit-1.2.0/README.md
rename to scripts/emacs/magit-1.2.1/README.md
diff --git a/scripts/emacs/magit-1.2.0/bin/authors.pl b/scripts/emacs/magit-1.2.1/bin/authors.pl
similarity index 100%
rename from scripts/emacs/magit-1.2.0/bin/authors.pl
rename to scripts/emacs/magit-1.2.1/bin/authors.pl
diff --git a/scripts/emacs/magit-1.2.0/bin/mk_rel.bash b/scripts/emacs/magit-1.2.1/bin/mk_rel.bash
similarity index 100%
rename from scripts/emacs/magit-1.2.0/bin/mk_rel.bash
rename to scripts/emacs/magit-1.2.1/bin/mk_rel.bash
diff --git a/scripts/emacs/magit-1.2.0/contrib/magit b/scripts/emacs/magit-1.2.1/contrib/magit
similarity index 100%
rename from scripts/emacs/magit-1.2.0/contrib/magit
rename to scripts/emacs/magit-1.2.1/contrib/magit
diff --git a/scripts/emacs/magit-1.2.0/contrib/magit-classic-theme.el b/scripts/emacs/magit-1.2.1/contrib/magit-classic-theme.el
similarity index 100%
rename from scripts/emacs/magit-1.2.0/contrib/magit-classic-theme.el
rename to scripts/emacs/magit-1.2.1/contrib/magit-classic-theme.el
diff --git a/scripts/emacs/magit-1.2.0/contrib/magit-simple-keys.el b/scripts/emacs/magit-1.2.1/contrib/magit-simple-keys.el
similarity index 100%
rename from scripts/emacs/magit-1.2.0/contrib/magit-simple-keys.el
rename to scripts/emacs/magit-1.2.1/contrib/magit-simple-keys.el
diff --git a/scripts/emacs/magit-1.2.0/fdl.texi b/scripts/emacs/magit-1.2.1/fdl.texi
similarity index 100%
rename from scripts/emacs/magit-1.2.0/fdl.texi
rename to scripts/emacs/magit-1.2.1/fdl.texi
diff --git a/scripts/emacs/magit-1.2.0/magit-bisect.el b/scripts/emacs/magit-1.2.1/magit-bisect.el
similarity index 100%
rename from scripts/emacs/magit-1.2.0/magit-bisect.el
rename to scripts/emacs/magit-1.2.1/magit-bisect.el
diff --git a/scripts/emacs/magit-1.2.0/magit-blame.el b/scripts/emacs/magit-1.2.1/magit-blame.el
similarity index 100%
rename from scripts/emacs/magit-1.2.0/magit-blame.el
rename to scripts/emacs/magit-1.2.1/magit-blame.el
diff --git a/scripts/emacs/magit-1.2.0/magit-key-mode.el b/scripts/emacs/magit-1.2.1/magit-key-mode.el
similarity index 100%
rename from scripts/emacs/magit-1.2.0/magit-key-mode.el
rename to scripts/emacs/magit-1.2.1/magit-key-mode.el
diff --git a/scripts/emacs/magit-1.2.0/magit-pkg.el.in b/scripts/emacs/magit-1.2.1/magit-pkg.el.in
similarity index 100%
rename from scripts/emacs/magit-1.2.0/magit-pkg.el.in
rename to scripts/emacs/magit-1.2.1/magit-pkg.el.in
diff --git a/scripts/emacs/magit-1.2.0/magit-stgit.el b/scripts/emacs/magit-1.2.1/magit-stgit.el
similarity index 100%
rename from scripts/emacs/magit-1.2.0/magit-stgit.el
rename to scripts/emacs/magit-1.2.1/magit-stgit.el
diff --git a/scripts/emacs/magit-1.2.0/magit-svn.el b/scripts/emacs/magit-1.2.1/magit-svn.el
similarity index 100%
rename from scripts/emacs/magit-1.2.0/magit-svn.el
rename to scripts/emacs/magit-1.2.1/magit-svn.el
diff --git a/scripts/emacs/magit-1.2.0/magit-topgit.el b/scripts/emacs/magit-1.2.1/magit-topgit.el
similarity index 100%
rename from scripts/emacs/magit-1.2.0/magit-topgit.el
rename to scripts/emacs/magit-1.2.1/magit-topgit.el
diff --git a/scripts/emacs/magit-1.2.0/magit-wip.el b/scripts/emacs/magit-1.2.1/magit-wip.el
similarity index 100%
rename from scripts/emacs/magit-1.2.0/magit-wip.el
rename to scripts/emacs/magit-1.2.1/magit-wip.el
diff --git a/scripts/emacs/magit-1.2.0/magit.el b/scripts/emacs/magit-1.2.1/magit.el
similarity index 99%
rename from scripts/emacs/magit-1.2.0/magit.el
rename to scripts/emacs/magit-1.2.1/magit.el
index 5923afc1a42ed5b3224ab0d20876edfe575d795d..3364e1cfa8c9e625b8e19c554e91a17c0bbb4b7b 100644
--- a/scripts/emacs/magit-1.2.0/magit.el
+++ b/scripts/emacs/magit-1.2.1/magit.el
@@ -734,24 +734,6 @@ operation after commit).")
 ;;; Compatibilities
 
 (eval-and-compile
-  (defun magit-max-args-internal (function)
-    "Returns the maximum number of arguments accepted by FUNCTION."
-    (if (symbolp function)
-        (setq function (symbol-function function)))
-    (if (subrp function)
-        (let ((max (cdr (subr-arity function))))
-          (if (eq 'many max)
-              most-positive-fixnum
-            max))
-      (if (eq 'macro (car-safe function))
-          (setq function (cdr function)))
-      (let ((arglist (if (byte-code-function-p function)
-                         (aref function 0)
-                       (second function))))
-        (if (memq '&rest arglist)
-            most-positive-fixnum
-          (length (remq '&optional arglist))))))
-
   (if (functionp 'start-file-process)
       (defalias 'magit-start-process 'start-file-process)
     (defalias 'magit-start-process 'start-process))
@@ -774,22 +756,28 @@ record undo information."
                 before-change-functions
                 after-change-functions)
             ,@body)))))
-
-  (if (>= (magit-max-args-internal 'delete-directory) 2)
-      (defalias 'magit-delete-directory 'delete-directory)
-    (defun magit-delete-directory (directory &optional recursive)
-      "Deletes a directory named DIRECTORY.  If RECURSIVE is non-nil,
-recursively delete all of DIRECTORY's contents as well.
-
-Does not follow symlinks."
-      (if (or (file-symlink-p directory)
-              (not (file-directory-p directory)))
-          (delete-file directory)
-        (if recursive
-            ;; `directory-files-no-dot-files-regex' borrowed from Emacs 23
-            (dolist (file (directory-files directory 'full "\\([^.]\\|\\.\\([^.]\\|\\..\\)\\).*"))
-              (magit-delete-directory file recursive)))
-        (delete-directory directory)))))
+  )
+
+;; RECURSIVE has been introduced with Emacs 23.2, XEmacs still lacks it.
+;; This is copied and adapted from `tramp-compat-delete-directory'
+(defun magit-delete-directory (directory &optional recursive)
+  "Compatibility function for `delete-directory'."
+  (if (null recursive)
+      (delete-directory directory)
+    (condition-case nil
+        (funcall 'delete-directory directory recursive)
+      (wrong-number-of-arguments
+       ;; This Emacs version does not support the RECURSIVE flag.
+       ;; We use the implementation from Emacs 23.2.
+       (setq directory (directory-file-name (expand-file-name directory)))
+       (if (not (file-symlink-p directory))
+           (mapc (lambda (file)
+                   (if (eq t (car (file-attributes file)))
+                       (org-delete-directory file recursive)
+                     (delete-file file)))
+                 (directory-files
+                  directory 'full "^\\([^.]\\|\\.\\([^.]\\|\\..\\)\\).*")))
+       (delete-directory directory)))))
 
 ;;; Utilities
 
diff --git a/scripts/emacs/magit-1.2.0/magit.spec.in b/scripts/emacs/magit-1.2.1/magit.spec.in
similarity index 100%
rename from scripts/emacs/magit-1.2.0/magit.spec.in
rename to scripts/emacs/magit-1.2.1/magit.spec.in
diff --git a/scripts/emacs/magit-1.2.0/magit.texi b/scripts/emacs/magit-1.2.1/magit.texi
similarity index 100%
rename from scripts/emacs/magit-1.2.0/magit.texi
rename to scripts/emacs/magit-1.2.1/magit.texi
diff --git a/scripts/emacs/magit-1.2.0/rebase-mode.el b/scripts/emacs/magit-1.2.1/rebase-mode.el
similarity index 100%
rename from scripts/emacs/magit-1.2.0/rebase-mode.el
rename to scripts/emacs/magit-1.2.1/rebase-mode.el
diff --git a/scripts/emacs/magit-1.2.0/tests/magit-tests.el b/scripts/emacs/magit-1.2.1/tests/magit-tests.el
similarity index 100%
rename from scripts/emacs/magit-1.2.0/tests/magit-tests.el
rename to scripts/emacs/magit-1.2.1/tests/magit-tests.el
diff --git a/scripts/emacs/phafi-autoload.el b/scripts/emacs/phafi-autoload.el
index a1ea597ca7e8f32cd19356585a6cc2bf206f5c78..e60ddd57ee4819c0376b87a8d7e60c829fee0ec0 100644
--- a/scripts/emacs/phafi-autoload.el
+++ b/scripts/emacs/phafi-autoload.el
@@ -29,8 +29,8 @@
     )
 )
 
-(phafi-autoload-load "php-mode-1.10")
-(phafi-autoload-load "magit-1.2.0")
+(phafi-autoload-load "php-mode-1.13.2")
+(phafi-autoload-load "magit-1.2.1")
 (phafi-autoload-load "geben-0.26")
 (phafi-autoload-load "nxhtml-2.08-100425")
 (phafi-autoload-load "popup-0.5")
diff --git a/scripts/emacs/php-mode-1.10/README.md b/scripts/emacs/php-mode-1.10/README.md
deleted file mode 100644
index fd9d94de4f547c75aa3923cd78646bc597dbaa79..0000000000000000000000000000000000000000
--- a/scripts/emacs/php-mode-1.10/README.md
+++ /dev/null
@@ -1,201 +0,0 @@
-# php-mode
-
-This updates php-mode with features to make it more friendly to use with PHP 5.4 and 5.5.  It is based on the work of:
-
-1. Turadg Aleahmad: The original author.
-
-2. Aaron S. Hawley
-
-3. Lennart Borgman
-
-And all those mentioned in the ‘Contributors’ section below.
-
-Please email any bugs or feature requests to `lobbyjones at gmail dot com` or submit them as Issues on the [Github page](https://github.com/ejmr/php-mode).  Also please include the output of `php-mode-version` in bug reports.
-
-**Note:** [You can see all of the previous changes for each version here.](https://github.com/ejmr/php-mode/blob/master/Changelog.md)
-
-# Status
-
-[The php-mode wiki](https://github.com/ejmr/php-mode/wiki) describes the plan for the next release and I update it to mark off issues when they are complete.  However, there is no hard date set for each release.  Serious bugs I try to resolve as soon as possibe.  But lately I have been lax when it comes to finishing feature requests, so my apologies.  That said, php-mode is in no way a dead project by any means, even if updates are sometimes sparse.
-
-# Features
-
-## New Keywords
-
-Now php-mode supports syntax highlighting for new keywords which were added as part of PHP 5.4, e.g. those related to traits, such as `insteadof`.  Also supported are the older keywords `clone` and `default`.
-
-## Constants
-
-Syntax highlighting includes every magic constant and predefined constant listed on the official PHP site.  However, some constants from specific extensions are not currently included.
-
-## Traits, Interfaces, and Namespaces
-
-Traits, interfaces, and namespaces now appear under Imenu listings. Fontification works properly for namespaces as well, so that code like `namespace Foo\Bar\Baz` no longer looks like a warning.  This is also true for namespace aliases, e.g. `use <namespace> as <alias>`; currently the aliased name is not listed in Imenu, but that will be addressed in the future.
-
-## Treatment of Underscores
-
-Underscores are treated as ‘symbol constituents’ (in Emacs terminology) so that you can use keys like M-f and M-b to move through the individual parts of a variable name like `$foo_bar_baz`.
-
-## Chained Method Calls
-
-A series of method calls over multiple lines will now be aligned with the `->` operator, e.g.:
-
-    $object->foo()
-           ->bar()
-           ->baz();
-
-## Nested Array Formatting
-
-Nested function calls and `array()` structures now look better by default (or at least in my opinion).  Here is an example of the style:
-
-    $results = Post::model()->find(
-        array(
-            'select' => 'title',
-            'condition' => 'postID=:postID',
-            'params' => array(':postID' => 10),
-        )
-    );
-
-## Anonymous Functions
-
-Anonymous functions such as
-
-    $greet = function($name) { … };
-
-will now appear on Imenu; in this case the name will be `$greet`.
-
-## Flymake Support
-
-By customizing the variable `php-executable` you can enable Flymake mode in order to see warnings and errors in real-time as you write code.
-
-## Search Local Documentation
-
-The key command `C-c C-f` will search the PHP website for documentation on the word under the cursor.  However, if you have a [local copy of the PHP documentation](http://us2.php.net/download-docs.php) then php-mode will try searching that documentation first.  All you need to do is customize the variable `php-manual-path` and give it the path to your copy of the documentation.  If php-mode cannot find something locally then it will still fallback on searching the PHP website.
-
-## Executing Regions of PHP
-
-The command `php-send-region`, which is bound to `C-c C-r` by default, will execute the selected region of PHP code.  In conjunction with the Emacs command `C-x h` you can use this to execute an entire file.  Any output will appear in a buffer called `*PHP*`.
-
-## Annotation Highlighting
-
-Projects like [Symfony](http://symfony.com/) use annotations in comments.  For example, here is code from their website:
-
-    /**
-     * @ORM\Entity
-     * @ORM\Table(name="product")
-     */
-    class Product
-    {
-        /**
-         * @ORM\Id
-         * @ORM\Column(type="integer")
-         * @ORM\GeneratedValue(strategy="AUTO")
-         */
-        protected $id;
-
-        /**
-         * @ORM\Column(type="string", length=100)
-         */
-        protected $name;
-
-        /**
-         * @ORM\Column(type="decimal", scale=2)
-         */
-        protected $price;
-
-        /**
-         * @ORM\Column(type="text")
-         */
-        protected $description;
-    }
-
-The annotations are the lines that begin with the `@` character, and php-mode will give these special highlighting to help them stand out.
-
-## Coding Styles
-
-By default php-mode tries to provide a reasonable style for indentation and formatting.  However, it provides other options suited for particular projects which you may find useful.  These coding styles are available through three functions:
-
-1. `php-enable-pear-coding-style`
-2. `php-enable-drupal-coding-style`
-3. `php-enable-wordpress-coding-style`
-
-They will help format your code for PEAR projects, or work on the Drupal and WordPress software, respectively.  You may enable any of them by default by running `M-x customize-group <RET> php` and looking for the ‘PHP Mode Coding Style’ option.
-
-# How to Contribute
-
-All contributions to php-mode are welcome.  But please try to do the following when sending improvements or bug fixes:
-
-1. Add your name to the list of ‘Contributors’ in this `README.md` file if it is not there already.  If you have a Github page then please link your name to it, so people can see your other work.
-
-2. If your contribution addresses an issue on the Github project page then include a single line like `Github-issue: 16` with the appropriate issue number.
-
-3. Make sure to update the constant `php-mode-modified`.
-
-4. However, please do not modify `php-mode-version-number`.  I will decide what constitutes a bump in the version number.
-
-5. Open the `php-mode-test.el` file and [run all of the tests](http://www.gnu.org/software/emacs/manual/html_node/ert/Running-Tests-Interactively.html#Running-Tests-Interactively) to ensure they still pass as expected.  Sometimes we expect for a test to fail, and those unit tests have the appropriate configuration so their failure will not raise any warnings.  You can use the `run-tests.sh` script to run all tests from a terminal, which is also useful in conjunction with [`git bisect run`](http://git-scm.com/book/en/Git-Tools-Debugging-with-Git).
-
-6. Send me a pull request here on Github.  Or if you do not have a Github account then email the patches to me at `lobbyjones at gmail dot com`.  Please try to make sure the patches are acceptable input to the comand `git am`.  Please note that even if you send a pull request it is very likely that I will *not* simply merge your branch through Github; I prefer to go through commits and cherry-pick them so I can review the commit messages and sign-off on them.  You can see which commits I did or did not merge by using the [`git-cherry`](http://www.kernel.org/pub/software/scm/git/docs/git-cherry.html) command.
-
-If you are fixing a bug related to a Github issue, then first of all, thank you for the help improving php-mode.  Second, there is a `tests/` directory which contains PHP scripts for issues (although not all of them).  Please consider adding a test script to that directory that documents the expected behavior and provides code that allows others to see if said behavior works properly.  Then create a unit test within `php-mode-test.el` using [ERT](http://www.gnu.org/software/emacs/manual/html_node/ert/index.html). Please try to follow the format of the existing tests.
-
-# The Wiki
-
-The Github project page [has a wiki](https://github.com/ejmr/php-mode/wiki) that you should feel free to edit.  The wiki lists the features and bugs that are on plan to include in upcoming versions of php-mode.  It is also a place to add any tips to make the mode more useful.
-
-# License
-
-The code for php-mode is covered by the [GNU General Public License 3](http://www.gnu.org/copyleft/gpl.html).
-
-# Contributors
-
-In chronological order:
-
-1. Juanjo
-2. Torsten Martinsen
-3. Vinai Kopp
-4. Sean Champ
-5. Doug Marcey
-6. Kevin Blake
-7. Rex McMaster
-8. Mathias Meyer
-9. Boris Folgmann
-10. Roland
-11. Rosenfeld
-12. Fred Yankowski
-13. Craig Andrews
-14. John Keller
-15. Ryan
-16. Sammartino
-17. ppercot
-18. Valentin Funk
-19. Stig Bakken
-20. Gregory Stark
-21. Chris Morris
-22. Nils Rennebarth
-23. Gerrit Riessen
-24. Eric Mc Sween
-25. Ville Skytta
-26. Giacomo Tesio
-27. Lennart Borgman
-28. Stefan Monnier
-29. Aaron S. Hawley
-30. [Ian Eure](https://github.com/ieure)
-31. [Bill Lovett](https://github.com/lovett)
-32. Dias Badekas
-33. David House
-34. [Tom Willemsen](https://github.com/ryuslash)
-35. [Olaf the Viking](https://github.com/olavTHEviking)
-36. [Maël Nison](https://github.com/arcanis)
-37. [flack](https://github.com/flack)
-38. [Michele Bini](https://github.com/rev22)
-39. Emanuele Tomasi
-40. [David Maus](https://github.com/dmj)
-41. [Jakub Jankiewicz](https://github.com/jcubic)
-42. [Marcin Antczak](https://github.com/marcinant)
-43. [顾伟刚](https://github.com/cnwggu)
-44. [zapad](https://github.com/zargener)
-45. [Carl Groner](https://github.com/cgroner)
-46. [Michael Dwyer](https://github.com/kalifg)
-47. [Daniel Hackney](https://github.com/haxney)
-48. [Nate Eagleson](https://github.com/NateEag)
diff --git a/scripts/emacs/php-mode-1.10/php-mode-test.el b/scripts/emacs/php-mode-1.10/php-mode-test.el
deleted file mode 100644
index 0e982b7e9bbe597d8d56d0a56ca0ef682355327a..0000000000000000000000000000000000000000
--- a/scripts/emacs/php-mode-1.10/php-mode-test.el
+++ /dev/null
@@ -1,176 +0,0 @@
-;;; php-mode-test.el --- Tests for php-mode
-
-;; Copyright (C) 2013 Daniel Hackney
-
-;; Author: Daniel Hackney <dan@haxney.org>
-;; URL: https://github.com/ejmr/php-mode
-
-;;; License
-
-;; This file is free software; you can redistribute it and/or
-;; modify it under the terms of the GNU General Public License
-;; as published by the Free Software Foundation; either version 3
-;; of the License, or (at your option) any later version.
-
-;; This file 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 General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with this file; if not, write to the Free Software
-;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-;; 02110-1301, USA.
-
-;;; Commentary:
-
-;; Automate tests from the "tests" directory using `ert', which comes bundled
-;; with Emacs >= 24.1.
-
-;;; Code:
-
-(require 'php-mode)
-(require 'ert)
-(eval-when-compile
-  (require 'cl))
-
-(defvar php-mode-test-dir (expand-file-name "tests" (file-name-directory load-file-name))
-  "Directory containing the `php-mode' test files.")
-
-(defmacro* with-php-mode-test ((file &optional &key style) &rest body)
-  "Set up environment for testing `php-mode'.
-Execute BODY in a temporary buffer containing the contents of
-FILE, in `php-mode'. Optional keyword `:style' can be used to set
-the coding style to one of `pear', `drupal', or `wordpress'."
-  (declare (indent 1))
-  `(with-temp-buffer
-     (insert-file-contents (expand-file-name ,file php-mode-test-dir))
-     ,(case style
-        (pear '(php-enable-pear-coding-style))
-        (drupal '(php-enable-drupal-coding-style))
-        (wordpress '(php-enable-wordpress-coding-style)))
-     (php-mode)
-     (font-lock-fontify-buffer)
-     (goto-char (point-min))
-     ,@body))
-
-(ert-deftest php-mode-test-issue-8 ()
-  "Annotation highlighting."
-  (with-php-mode-test ("issue-8.php")
-  (search-forward "@ORM")
-  (should (eq
-           (get-text-property (match-beginning 0) 'face)
-           'php-annotations-annotation-face))))
-
-(ert-deftest php-mode-test-issue-9 ()
-  "Single quote in text in HTML misinterpreted.
-The next character after \">We\" is a single quote. It should not
-have a string face."
-  :expected-result :failed
-  (with-php-mode-test ("issue-9.php")
-    (should-not (eq
-                 (get-text-property (search-forward ">We") 'face)
-                 'font-lock-string-face))))
-
-(ert-deftest php-mode-test-issue-14 ()
-  "Array indentation."
-  :expected-result :failed
-  (with-php-mode-test ("issue-14.php")
-    (let ((expected (concat "$post = Post::model()->find(array(\n"
-                            "    'select' => 'title',\n"
-                            "    'condition' => 'postID=:postID',\n"
-                            "    'params' => array(':postID'=>10),\n"
-                            "));")))
-      (indent-region (point-min) (point-max))
-      (goto-char (point-min))
-      (re-search-forward "^\\$post")
-      (should (string= (buffer-substring-no-properties (match-beginning 0) (point-max))
-                       expected)))))
-
-(ert-deftest php-mode-test-issue-16 ()
-  "Comma separated \"use\" (namespaces).
-Gets the face of the text after the comma."
-  (with-php-mode-test ("issue-16.php")
-    (re-search-forward "^use " nil nil 3)
-    (should (eq
-             (get-text-property (search-forward ", ") 'face)
-             'font-lock-type-face))))
-
-(ert-deftest php-mode-test-issue-18 ()
-  "Indentation of strings which include \"//\"."
-  (with-php-mode-test ("issue-18.php")
-    (let ((expected (concat "if ($a === 'github') {\n"
-                            "    header('Location: http://github.com');\n"
-                            "}")))
-      (indent-region (point-min) (point-max))
-      (goto-char (point-min))
-      (re-search-forward "^if ")
-      (should (string= (buffer-substring-no-properties (match-beginning 0) (point-max))
-                       expected)))))
-
-(ert-deftest php-mode-test-issue-19 ()
-  "Alignment of arrow operators."
-  :expected-result :failed
-  (with-php-mode-test ("issue-19.php")
-    (indent-region (point-min) (point-max))
-    (goto-char (point-min))
-    (while (re-search-forward "^\\s-*\\$object->")
-      ;; Point is just after `->'
-      (let ((col (current-column)))
-        (search-forward "->")
-        (should (eq (current-column) col))))))
-
-(ert-deftest php-mode-test-issue-21 ()
-  "Font locking multi-line string."
-  (with-php-mode-test ("issue-21.php")
-    (search-forward "\"")
-    (while (not (looking-at "\""))
-      (should (eq (get-text-property (point) 'face)
-                  'font-lock-string-face))
-      (forward-char))))
-
-(ert-deftest php-mode-test-issue-22 ()
-  "Font lock quotes within comments as regular comments.
-This applies for both single and double quotes."
-  (with-php-mode-test ("issue-21.php")
-    (while (search-forward "#" nil t)
-     (while (not (looking-at "\n"))
-       (should (eq (get-text-property (point) 'face)
-                   'font-lock-comment-face))
-       (forward-char)))))
-
-(ert-deftest php-mode-test-issue-27 ()
-  "Indentation in a file with a shebang."
-  (with-php-mode-test ("issue-27.php")
-    (re-search-forward "^\\s-*// Tab")
-    (indent-for-tab-command)
-    (back-to-indentation)
-    (should (eq (current-column) tab-width))))
-
-(ert-deftest php-mode-test-issue-28 ()
-  "Slowdown when scrolling.
-No obvious way to test this. One possibility is to record time it
-takes to scroll down the whole buffer using `next-line'. This may
-not cause the desired fontification, and it could take different
-amounts of time on different machines, so an absolute time would
-not be very useful.
-
-This doesn't test anything, for now."
-  (should t))
-
-(ert-deftest php-mode-test-issue-29 ()
-  "Indentation of anonymous functions as arguments.
-The closing brace and parenthesis should be at column 0."
-  (with-php-mode-test ("issue-29.php")
-    (indent-region (point-min) (point-max))
-    (goto-char (point-min))
-    (re-search-forward "^\\s-*});")
-    (back-to-indentation)
-    (should (eq (current-column) 0))))
-
-(ert-deftest php-mode-test-issue-42 ()
-  "Error while indenting closures.
-If the bug has been fixed, indenting the buffer should not cause
-an error."
-  (with-php-mode-test ("issue-42.php")
-    (indent-region (point-min) (point-max))))
diff --git a/scripts/emacs/php-mode-1.10/run-tests.sh b/scripts/emacs/php-mode-1.10/run-tests.sh
deleted file mode 100755
index 947e90ffe7a0062c545bbbfca2874c96ecab4ce1..0000000000000000000000000000000000000000
--- a/scripts/emacs/php-mode-1.10/run-tests.sh
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/bin/sh
-#
-# This shell script runs all of unit tests from the php-mode-test.el
-# file and shows the results.  The script will exit with the status
-# code zero if all tests pass.  If any test fails the script exits
-# with a non-zero status and shows diagnostics on standard output.
-#
-# You can use this script with git-bisect.  See the documentation at
-#
-#     http://git-scm.com/book/en/Git-Tools-Debugging-with-Git
-#
-# for an example of using a script like this with the 'git bisect run'
-# command.
-
-emacs -Q -batch -l cl -l ert \
-    -l php-mode.el \
-    -l php-mode-test.el \
-    -f ert-run-tests-batch-and-exit
diff --git a/scripts/emacs/php-mode-1.13.2/.gitignore b/scripts/emacs/php-mode-1.13.2/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..6302bc32b67a9b1c2a4705630fd2fcf569e99dc3
--- /dev/null
+++ b/scripts/emacs/php-mode-1.13.2/.gitignore
@@ -0,0 +1,2 @@
+*~
+*.elc
diff --git a/scripts/emacs/php-mode-1.10/Changelog.md b/scripts/emacs/php-mode-1.13.2/Changelog.md
similarity index 53%
rename from scripts/emacs/php-mode-1.10/Changelog.md
rename to scripts/emacs/php-mode-1.13.2/Changelog.md
index dadc5cb691caf40700d559444c90b8bb07a3d965..ab5cdf8c347a22cef7097c7a688ce9164968bff4 100644
--- a/scripts/emacs/php-mode-1.10/Changelog.md
+++ b/scripts/emacs/php-mode-1.13.2/Changelog.md
@@ -5,6 +5,130 @@ Changes for PHP Mode by Version
 because when I (Eric James Michael Ritz) took over the project I did
 not have a record of all changes available.
 
+1.13
+----
+
+* Update version to 1.13
+* Merge branch 'ejmr/highlight-variables-in-strings'
+* Merge commit '38e1940e950d47737fed30a5bd5d4e75e0faf103'
+* Append file patterns to auto-mode-alist
+* Guard propertize functions for Emacs that don't support it.
+* Add more tests for highlighting variable interpolation
+* Create a unit test for highlighting interpolated variables
+* Avoid calling syntax-propertize-rules as may be unavailable.
+* README: Explicitly mention the oldest supported Emacs
+* Merge branch 'heredoc-support'
+* README: Replace mention of ‘run-tests.sh’ with ‘make tests’
+* Explain the expected behavior of the test for GitHub issue 124
+* Added unit test for GitHub issue 124
+* Replaced run-tests.sh with a Makefile
+* Replaced `put-text-property' with macro `c-put-char-property'
+* Added initial support for propertizing a heredoc as a string
+* Merge branch 'fix-highlighting-final-keyword'
+* Update php-mode-modified
+* Add a simple script to test syntax highlighting for ‘final’
+* Add a template script for creating test cases
+* Fix ‘final’ not highlighted as a keyword in some methods
+* Merge branch 'github/pr/127'
+* Update php-mode-modified
+* Removed unused defconst.
+* Added PREG constants to the list of predefined constants.
+* Fix byte compile error again; resurfaced in after a merge.
+* Add Andrei Chițu to the list of contributors
+* fix inclusion of `web-mode-extra-php-keywords` in `php-keywords`
+* Update Changelog for version 1.12
+
+1.12
+----
+
+* Automatically enable PHP Mode for Amaka scripts
+* Also enable PHP Mode for Amaka scripts using the ‘*.amk’ extension
+* Use mode-specific functions for defun movement
+* Treat `const` as a keyword instead of a type-hint
+* Add `enddeclare` to the list of keywords
+* Treat `eval` as a built-in keyword
+* Show links to the official site and wiki when customizing PHP Mode
+* Update php-mode-modified for changes made today
+* Add FILTER_SANITIZE_FULL_SPECIAL_CHARS to the list of constants
+* Fix an error about php-extra-constants being void
+* Use extra constants and keywords from Web Mode if available
+* README: Replace ‘php-mode’ with ‘PHP Mode’ for consistency
+* README: Update the ‘Status’ section
+* README: Use the spelling ‘GitHub’ consistently
+* README: Add installation instructions
+* Address the compiler warning regarding `c-syntactic-context`
+* GitHub-Issue: 102 (Unit Test)
+* Fix indentation error involving magic constants
+* Merge branch 'ejmr/issue-102'
+* Stop marching indentation for try-catch blocks
+* GitHub-Issue: 100 (Unit Test)
+* Fix two errors with the regex for matching namespace imports
+* GitHub-Issue: 115 (Unit Test)
+* Use the PEAR indentation style by default for unit tests
+* Align chained method calls inside of arrays
+* Update php-mode-modified
+* Merge branch 'ejmr/align-method-calls-in-arrays'
+* Update php-mode-modified for byte-compiler fixes
+* Merge branch 'github/pr/123'
+* README: Document use of Web Mode constants and keywords
+* Merge branch 'ejmr/web-mode-constants'
+* Change the test for Issue 100 to require correct indentation
+* Line-up multiple namespaces in a multi-line ‘use’ statement
+* Merge branch 'ejmr/multiline-use-statements'
+* Increase the version number to 1.12
+* Fix the compiler warning about `add-log-current-defun-header-regexp`
+* Add (require 'speedbar) as functions are used.
+* Remove eval-when-compile.
+* Add (require 'etags) as etag functions are used.
+* Added newline at end of file restriction to Symfony2 style.
+* Fix regex for namespaces in function calls
+
+
+1.11
+----
+
+* Add STDOUT, STDIN, and STDERR to the php-constants list
+* Add Symfony2 coding style.
+* Add a full copy of the license
+* Add proper statement-case-intro indent for symfony2
+* Added "function" as a PHP keyword.
+* Added function php-lineup-arglist
+* Added gitignore with *.elc
+* Associate file extensions when installing from an Elisp repository
+* Be nice to PSR standards (there should be 4 spaces)
+* Correct indentation for array arguments (tests/issues-14.php)
+* Correct syntax highlighting for ‘parent’ and ‘self’
+* Describe php-extra-constants in the README
+* Describe php-template-compatibility in the README
+* Do not expect failure for test issue-19
+* Do not trigger search error in php-mode-test-issue-19
+* Document Subword Mode in the README
+* Document support for the Symfony2 style in the README
+* Fix chained method alignment
+* Fix indentation of statements after ‘foreach’ without braces
+* Highlight ‘static’ as a constant when it appears in a class context
+* Improve the docstring for php-create-regexp-for-method
+* Improve the plain-text formatting of the README
+* Introduce php-extra-constants
+* Introduce php-template-compatility
+* Introduce ‘C-c C-w’ to toggle Subword Mode
+* Issue #73, correct behavior of `delete-indentation`.
+* List all methods via Imenu regardless of their visibility
+* Make `with-php-mode-test` aware of the Symfony2 coding style
+* README: Change the absolute link to the Changelog to a relative link
+* README: Correct the documentation for chained-method call alignment
+* README: Document how chained method alignment may fail
+* README: Reword the mention of Web Mode for clarity
+* README: Use syntax highlighting for the method alignment example
+* Re-define C-M-h to mark-defun instead of c-mark-function
+* Remove the unnecessary &optional from the with-php-mode-test macro
+* Set brace-list-entry to offset of four
+* Tests: Remove executable permissions from the issue 27 test
+* Treat ‘abstract’ as a keyword
+* Use "magic" comments in PHP files to simplify indentation testing
+* Use magic for tests of issues #14, #19, #27, #29, #42
+* Workaround "bug" in `load-theme`
+
 
 1.10
 ----
diff --git a/scripts/emacs/php-mode-1.13.2/LICENSE b/scripts/emacs/php-mode-1.13.2/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..94a9ed024d3859793618152ea559a168bbcbb5e2
--- /dev/null
+++ b/scripts/emacs/php-mode-1.13.2/LICENSE
@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program 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 General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/scripts/emacs/php-mode-1.13.2/Makefile b/scripts/emacs/php-mode-1.13.2/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..e8878049d024e2144a1aaaba882e62fc686c4570
--- /dev/null
+++ b/scripts/emacs/php-mode-1.13.2/Makefile
@@ -0,0 +1,27 @@
+EMACS = emacs -Q -batch -L .
+ELS = php-mode.el php-mode-test.el
+ELCS = $(ELS:.el=.elc)
+
+%.elc: %.el
+	$(EMACS) -f batch-byte-compile $<
+
+all: $(ELCS)
+
+clean:
+	rm -f $(ELCS)
+
+# Runs all unit tests from php-mode-test.el and shows the results. The
+# script will exit with the status code zero if all tests pass. If any
+# test fails the script exits with a non-zero status and shows
+# diagnostics on standard output.
+#
+# You can use this script with git-bisect. See the documentation at
+#
+#     http://git-scm.com/book/en/Git-Tools-Debugging-with-Git
+#
+# for an example of using a script like this with the 'git bisect run'
+# command.
+test: $(ELCS)
+	$(EMACS) -l php-mode-test.el -f ert-run-tests-batch-and-exit
+
+.PHONY: all clean test
diff --git a/scripts/emacs/php-mode-1.13.2/README.md b/scripts/emacs/php-mode-1.13.2/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..6df52880f1aa59c01006e87c629efbbc073e124a
--- /dev/null
+++ b/scripts/emacs/php-mode-1.13.2/README.md
@@ -0,0 +1,298 @@
+PHP Mode for GNU Emacs
+======================
+
+This updates PHP Mode with features to make it more friendly to use with PHP 5.4 and later.  This fork builds on the work of:
+
+1. Turadg Aleahmad (Original Author)
+
+2. Aaron S. Hawley
+
+3. Lennart Borgman
+
+All contributors listed below improved PHP Mode as well.
+
+Please email any bugs or feature requests to `ejmr at plutono dot com` or submit them as Issues on the [GitHub page](https://github.com/ejmr/php-mode).  Also please include the output of `php-mode-version` in bug reports.  [There is a changelog for previous versions.](./Changelog.md)
+
+
+Installation
+------------
+
+If you are using GNU Emacs 24 or later then you can use its [package][] feature to install PHP Mode from [MELPA][].  *The [Marmalade][] package repository only has the original PHP Mode from 2004.*
+
+If you are using an older version of Emacs, or if you simply do not wish to use the package manager, then all you need to do is download the `php-mode.el` file, place it inside your `load-path`, and optionally add `(require 'php-mode)` to your Emacs configuration to automatically enable PHP Mode whenever you open a PHP file.
+
+**Note:** PHP Mode requires Emacs 23.1 or later.
+
+
+Status
+------
+
+I am currently looking for someone willing to take over as the maintainer of PHP Mode, ideally before the end of 2014.  Please see [this discussion](https://github.com/ejmr/php-mode/issues/109) for details.
+
+
+Features
+--------
+
+### New Keywords ###
+
+Now PHP Mode supports syntax highlighting for new keywords which PHP 5.4 introduced, e.g. those related to traits, such as `insteadof`.  Also supported are the older keywords `clone` and `default`.
+
+### Constants ###
+
+Syntax highlighting includes every magic constant and predefined constant listed on the official PHP site.  However, some constants from specific extensions are not currently included.
+
+### Traits, Interfaces, and Namespaces ###
+
+Traits, interfaces, and namespaces now appear under Imenu listings. Fontification behaves properly for namespaces as well, so that code like `namespace Foo\Bar\Baz` no longer looks like a warning.  This is also true for namespace aliases, e.g. `use <namespace> as <alias>`; currently the aliased name is not listed in Imenu, but future versions will address this.
+
+### Treatment of Underscores ###
+
+PHP Mode treats underscores as ‘symbol constituents’ (in Emacs terminology) so that you can use keys like `M-f` and `M-b` to move through the individual parts of a variable name like `$foo_bar_baz`.
+
+### Chained Method Calls ###
+
+PHP Mode will align method calls over multiple lines anchored around the `->` operator, e.g.:
+
+```php
+$object->foo()
+       ->bar()
+       ->baz();
+```
+
+**Note:** Alignment will only work if you use one of the coding styles described below.  PHP Mode uses [CC mode][] for indentation.  If you use any indentation style other than those described under the *Coding Styles* section then the method alignment above is not guaranteed to work.
+
+### Nested Array Formatting ###
+
+Nested function calls and `array()` structures now look better by default (or at least in my opinion).  Here is an example of the style:
+
+```php
+$results = Post::model()->find(
+    array(
+        'select' => 'title',
+        'condition' => 'postID=:postID',
+        'params' => array(':postID' => 10),
+    )
+);
+```
+
+### Anonymous Functions ###
+
+Anonymous functions such as
+
+```php
+$greet = function($name) { ... };
+```
+
+will now appear on Imenu; in this case the name will be `$greet`.
+
+### Flymake Support ###
+
+By customizing the variable `php-executable` you can enable Flymake mode in order to see warnings and errors in real-time as you write code.
+
+### Search Local Documentation ###
+
+The key command `C-c C-f` will search the PHP website for documentation on the word under the cursor.  However, if you have a [local copy of the PHP documentation](http://us2.php.net/download-docs.php) then PHP Mode will try searching that documentation first.  All you need to do is customize the variable `php-manual-path` and give it the path to your copy of the documentation.  If PHP Mode cannot find something locally then it will still fallback on searching the PHP website.
+
+### Executing Regions of PHP ###
+
+The command `php-send-region`, which is bound to `C-c C-r` by default, will execute the selected region of PHP code.  In conjunction with the Emacs command `C-x h` you can use this to execute an entire file.  Any output will appear in a buffer called `*PHP*`.
+
+### Annotation Highlighting ###
+
+Projects like [Symfony](http://symfony.com/) use annotations in comments.  For example, here is code from their website:
+
+```php
+/**
+ * @ORM\Entity
+ * @ORM\Table(name="product")
+ */
+class Product
+{
+    /**
+     * @ORM\Id
+     * @ORM\Column(type="integer")
+     * @ORM\GeneratedValue(strategy="AUTO")
+     */
+    protected $id;
+
+    /**
+     * @ORM\Column(type="string", length=100)
+     */
+    protected $name;
+
+    /**
+     * @ORM\Column(type="decimal", scale=2)
+     */
+    protected $price;
+
+    /**
+     * @ORM\Column(type="text")
+     */
+    protected $description;
+}
+```
+
+The annotations are the lines that begin with the `@` character, and PHP Mode will give these special highlighting to help them stand out.
+
+### Coding Styles ###
+
+By default PHP Mode tries to provide a reasonable style for indentation and formatting.  However, it provides other options suited for particular projects which you may find useful.  These coding styles are available through these functions:
+
+1. `php-enable-pear-coding-style`
+2. `php-enable-drupal-coding-style`
+3. `php-enable-wordpress-coding-style`
+4. `php-enable-symfony2-coding-style`
+
+They will help format your code for PEAR projects, or work on Drupal, WordPress, and Symfony2 software, respectively.  You may enable any of them by default by running `M-x customize-group <RET> php` and looking for the ‘PHP Mode Coding Style’ option.
+
+#### Symfony2 Style ####
+
+With this style method call chains can be formatted with indented continuation and a hanging semi-colon:
+
+```php
+    $user1
+        ->setCreateDate(new \DateTime('2007-05-07 01:34:45'))
+        ->setLastDate(new \DateTime('2012-08-18 19:03:02'))
+        ->setUsername('jay')
+    ;
+```
+
+This style is used widely throughout Symfony2 source code even if it is not explicitly mentioned in their conventions documents.
+
+### Extra Constants ###
+
+If you commonly use a framework or library that defines a set of constants then you may wish to customize the value of `php-extra-constants`.  It is a list of strings that PHP Mode will treat as additional constants, i.e. providing them the same level syntax highlighting that PHP Mode uses for built-in constants.
+
+### Web Mode Constants and Keywords ###
+
+If you use [Web Mode][] then PHP Mode will attempt to use any additional PHP constants and keywords that Web Mode allows you to define.
+
+### Avoid HTML Template Compatibility ###
+
+Many developers use PHP Mode to edit pure PHP scripts (e.g. files with only PHP and no HTML). A basic compatibility layer with HTML has historically been part of PHP Mode but it does not work perfectly and can cause some bad side effects such as slowness and incorrect font locking.  Configuring the `php-template-compatibility` property with a `nil` will cancel any attempt of HTML compatibility.  [Web Mode](http://web-mode.org/) is a great alternative to PHP Mode if you need to work with PHP scripts that do contain HTML and other markup.
+
+### Subword Mode ###
+
+GNU Emacs comes with [Subword Mode][], a minor mode that allows you to navigate the parts of a [camelCase][] as if they were separate words.  For example, PHP Mode treats the variable `$fooBarBaz` as a whole name by default.  But if you enable Subword Mode then Emacs will treat the variable name as three separate words, and therefore word-related commands (e.g. `M-f`, `M-b`, `M-d`) will only affect the camelCase part of the name under the cursor.
+
+If you want to always use Subword Mode for PHP files then you can add this to your Emacs configuration:
+
+```lisp
+(add-hook 'php-mode-hook (lambda () (subword-mode 1)))
+```
+
+The key-binding `C-c C-w` will also toggle Subword Mode on and off.
+
+### Amaka Support ###
+
+Viewing and editing build scripts for [Amaka](http://trashofmasters.github.io/amaka/) will automatically enable PHP Mode.
+
+
+How to Contribute
+-----------------
+
+All contributions to PHP Mode are welcome.  But please try to do the following when sending improvements or bug fixes:
+
+1. Add your name to the list of ‘Contributors’ in this `README.md` file if it is not there already.  If you have a GitHub page then please link your name to it, so people can see your other work.
+
+2. If your contribution addresses an issue on the GitHub project page then include a single line like `GitHub-Issue: 16` with the appropriate issue number.
+
+3. Make sure to update the constant `php-mode-modified`.
+
+4. However, please do not modify `php-mode-version-number`.  I will decide what constitutes a bump in the version number.
+
+5. Open the `php-mode-test.el` file and [run all of the tests](http://www.gnu.org/software/emacs/manual/html_node/ert/Running-Tests-Interactively.html#Running-Tests-Interactively) to ensure they still pass as expected.  Sometimes we expect for a test to fail, and those unit tests have the appropriate configuration so their failure will not raise any warnings.  You can use `make test` script to run all tests from a terminal, which is also useful in conjunction with [`git bisect run`](http://git-scm.com/book/en/Git-Tools-Debugging-with-Git).
+
+6. Send me a pull request here on GitHub.  Or if you do not have a GitHub account then email the patches to me at `lobbyjones at gmail dot com`.  Please try to make sure the patches are acceptable input to the comand `git am`.  Please note that even if you send a pull request it is very likely that I will *not* simply merge your branch through GitHub; I prefer to go through commits and cherry-pick them so I can review the commit messages and sign-off on them.  You can see which commits I did or did not merge by using the [`git-cherry`](http://www.kernel.org/pub/software/scm/git/docs/git-cherry.html) command.
+
+If you are fixing a bug related to a GitHub issue, then first of all, thank you for the help improving PHP Mode.  Second, there is a `tests/` directory which contains PHP scripts for issues (although not all of them).  Please consider adding a test script to that directory that documents the expected behavior and provides code that allows others to see if said behavior works properly.  Then create a unit test within `php-mode-test.el` using [ERT][]. Please try to follow the format of the existing tests.
+
+
+The Wiki
+--------
+
+The GitHub project page has a [wiki][] that you should feel free to edit.  The wiki lists the features and bugs that are on plan to include in upcoming versions of PHP Mode.  It is also a place to add any tips to make the mode more useful.
+
+
+License
+-------
+
+PHP Mode uses the [GNU General Public License 3](http://www.gnu.org/copyleft/gpl.html).
+
+
+Contributors
+------------
+
+In chronological order:
+
+1. Juanjo
+2. Torsten Martinsen
+3. Vinai Kopp
+4. Sean Champ
+5. Doug Marcey
+6. Kevin Blake
+7. Rex McMaster
+8. Mathias Meyer
+9. Boris Folgmann
+10. Roland
+11. Rosenfeld
+12. Fred Yankowski
+13. Craig Andrews
+14. John Keller
+15. Ryan
+16. Sammartino
+17. ppercot
+18. Valentin Funk
+19. Stig Bakken
+20. Gregory Stark
+21. Chris Morris
+22. Nils Rennebarth
+23. Gerrit Riessen
+24. Eric Mc Sween
+25. Ville Skytta
+26. Giacomo Tesio
+27. Urban Müller
+28. [Engelke Eschner](https://github.com/tekai)
+29. Lennart Borgman
+30. Stefan Monnier
+31. Aaron S. Hawley
+32. [Ian Eure](https://github.com/ieure)
+33. [Bill Lovett](https://github.com/lovett)
+34. Dias Badekas
+35. David House
+36. [Tom Willemse](https://github.com/ryuslash)
+37. [Olaf the Viking](https://github.com/olavTHEviking)
+38. [Maël Nison](https://github.com/arcanis)
+39. [flack](https://github.com/flack)
+40. [Michele Bini](https://github.com/rev22)
+41. Emanuele Tomasi
+42. [David Maus](https://github.com/dmj)
+43. [Jakub Jankiewicz](https://github.com/jcubic)
+44. [Marcin Antczak](https://github.com/marcinant)
+45. [顾伟刚](https://github.com/cnwggu)
+46. [zapad](https://github.com/zargener)
+47. [Carl Groner](https://github.com/cgroner)
+48. [Michael Dwyer](https://github.com/kalifg)
+49. [Daniel Hackney](https://github.com/haxney)
+50. [Nate Eagleson](https://github.com/NateEag)
+51. [Steve Purcell](https://github.com/purcell)
+52. TatriX
+53. [François-Xavier Bois](https://github.com/fxbois)
+54. [James Laver](https://github.com/jjl)
+55. [Jacek Wysocki](https://github.com/exu)
+56. [Jon Dufrense](https://github.com/jdufresne)
+57. [Andrei Chițu](https://github.com/achitu)
+58. [phil-s](https://github.com/phil-s)
+59. [Bence Kalmar](https://github.com/brkalmar)
+
+
+
+[wiki]: https://github.com/ejmr/php-mode/wiki
+[ert]: http://www.gnu.org/software/emacs/manual/html_node/ert/index.html
+[cc mode]: https://www.gnu.org/software/emacs/manual/html_mono/ccmode.html
+[Subword Mode]: https://www.gnu.org/software/emacs/manual/html_node/ccmode/Subword-Movement.html
+[camelCase]: http://en.wikipedia.org/wiki/Camel_case
+[package]: https://www.gnu.org/software/emacs/manual/html_node/emacs/Packages.html
+[MELPA]: http://melpa.milkbox.net/
+[Marmalade]: http://marmalade-repo.org/
+[Web Mode]: http://web-mode.org/
diff --git a/scripts/emacs/php-mode-1.13.2/php-mode-test.el b/scripts/emacs/php-mode-1.13.2/php-mode-test.el
new file mode 100644
index 0000000000000000000000000000000000000000..0d5fc46b31b6600bbc62a17b869fc3d6eb8075f8
--- /dev/null
+++ b/scripts/emacs/php-mode-1.13.2/php-mode-test.el
@@ -0,0 +1,276 @@
+;;; php-mode-test.el --- Tests for php-mode
+
+;; Copyright (C) 2013 Daniel Hackney
+;;               2014 Eric James Michael Ritz
+
+;; Author: Daniel Hackney <dan@haxney.org>
+;; URL: https://github.com/ejmr/php-mode
+
+;;; License
+
+;; This file is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License
+;; as published by the Free Software Foundation; either version 3
+;; of the License, or (at your option) any later version.
+
+;; This file 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 General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this file; if not, write to the Free Software
+;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+;; 02110-1301, USA.
+
+;;; Commentary:
+
+;; Automate tests from the "tests" directory using `ert', which comes bundled
+;; with Emacs >= 24.1.
+
+;;; Code:
+
+(require 'php-mode)
+(require 'ert)
+(eval-when-compile
+  (require 'cl))
+
+;; Work around bug #14325
+;; <http://debbugs.gnu.org/cgi/bugreport.cgi?bug=14325>.
+(c-after-font-lock-init)
+
+(defvar php-mode-test-dir (expand-file-name "tests" (file-name-directory load-file-name))
+  "Directory containing the `php-mode' test files.")
+
+(defvar php-mode-test-valid-magics '(indent)
+  "List of allowed \"magic\" directives which can appear in test cases.")
+
+(defvar php-mode-test-magic-regexp "###php-mode-test### \\((.+)\\)"
+  "Regexp which identifies a magic comment.")
+
+(defun php-mode-test-process-magics ()
+  "Process the test directives in the current buffer.
+These are the ###php-mode-test### comments. Valid magics are
+listed in `php-mode-test-valid-magics'; no other directives will
+be processed."
+  (flet ((indent (offset) (equal (current-indentation) offset)))
+    (let (directives answers)
+     (save-excursion
+       (goto-char (point-min))
+       (while (re-search-forward php-mode-test-magic-regexp nil t)
+         (setq directives (read (buffer-substring (match-beginning 1)
+                                                  (match-end 1))))
+         (setq answers
+               (append (mapcar (lambda (curr)
+                                 (let ((fn (car curr))
+                                       (args (mapcar 'eval (cdr-safe curr))))
+                                   (if (memq fn php-mode-test-valid-magics)
+                                       (apply fn args))))
+                               directives)
+                       answers))))
+     answers)))
+
+(defmacro* with-php-mode-test ((file &key style indent magic) &rest body)
+  "Set up environment for testing `php-mode'.
+Execute BODY in a temporary buffer containing the contents of
+FILE, in `php-mode'. Optional keyword `:style' can be used to set
+the coding style to one of the following:
+
+1. `pear'
+2. `drupal'
+3. `wordpress'
+4. `symfony2'
+
+Using any other symbol for STYLE results in undefined behavior.
+The test will use the PEAR style by default."
+  (declare (indent 1))
+  `(with-temp-buffer
+     (insert-file-contents (expand-file-name ,file php-mode-test-dir))
+     (php-mode)
+     (font-lock-fontify-buffer)
+     ,(case style
+        (pear '(php-enable-pear-coding-style))
+        (drupal '(php-enable-drupal-coding-style))
+        (wordpress '(php-enable-wordpress-coding-style))
+        (symfony2 '(php-enable-symfony2-coding-style))
+        (t '(php-enable-pear-coding-style)))
+     ,(if indent
+          '(indent-region (point-min) (point-max)))
+     ,(if magic
+          '(should (reduce (lambda (l r) (and l r))
+                           (php-mode-test-process-magics))))
+     (goto-char (point-min))
+     ,@body))
+
+(ert-deftest php-mode-test-issue-8 ()
+  "Annotation highlighting."
+  (with-php-mode-test ("issue-8.php")
+  (search-forward "@ORM")
+  (should (eq
+           (get-text-property (match-beginning 0) 'face)
+           'php-annotations-annotation-face))))
+
+(ert-deftest php-mode-test-issue-9 ()
+  "Single quote in text in HTML misinterpreted.
+The next character after \">We\" is a single quote. It should not
+have a string face."
+  :expected-result :failed
+  (with-php-mode-test ("issue-9.php")
+    (should-not (eq
+                 (get-text-property (search-forward ">We") 'face)
+                 'font-lock-string-face))))
+
+(ert-deftest php-mode-test-issue-14 ()
+  "Array indentation."
+  (with-php-mode-test ("issue-14.php" :indent t :magic t)))
+
+(ert-deftest php-mode-test-issue-16 ()
+  "Comma separated \"use\" (namespaces).
+Gets the face of the text after the comma."
+  (with-php-mode-test ("issue-16.php")
+    (re-search-forward "^use " nil nil 3)
+    (should (eq
+             (get-text-property (search-forward ", ") 'face)
+             'font-lock-type-face))))
+
+(ert-deftest php-mode-test-issue-18 ()
+  "Indentation of strings which include \"//\"."
+  (with-php-mode-test ("issue-18.php" :indent t :magic t)))
+
+(ert-deftest php-mode-test-issue-19 ()
+  "Alignment of arrow operators."
+  (with-php-mode-test ("issue-19.php" :indent t)
+    (while (search-forward "$object->" (point-max) t)
+      ;; Point is just after `->'
+      (let ((col (current-column)))
+        (search-forward "->")
+        (should (= (current-column) col))))))
+
+(ert-deftest php-mode-test-issue-21 ()
+  "Font locking multi-line string."
+  (with-php-mode-test ("issue-21.php")
+    (search-forward "\"")
+    (while (not (looking-at "\""))
+      (should (eq (get-text-property (point) 'face)
+                  'font-lock-string-face))
+      (forward-char))))
+
+(ert-deftest php-mode-test-issue-22 ()
+  "Font lock quotes within comments as regular comments.
+This applies for both single and double quotes."
+  (with-php-mode-test ("issue-21.php")
+    (while (search-forward "#" nil t)
+     (while (not (looking-at "\n"))
+       (should (eq (get-text-property (point) 'face)
+                   'font-lock-comment-face))
+       (forward-char)))))
+
+(ert-deftest php-mode-test-issue-27 ()
+  "Indentation in a file with a shebang."
+  (with-php-mode-test ("issue-27.php" :indent t :magic t)))
+
+(ert-deftest php-mode-test-issue-28 ()
+  "Slowdown when scrolling.
+No obvious way to test this. One possibility is to record time it
+takes to scroll down the whole buffer using `next-line'. This may
+not cause the desired fontification, and it could take different
+amounts of time on different machines, so an absolute time would
+not be very useful.
+
+This doesn't test anything, for now."
+  (should t))
+
+(ert-deftest php-mode-test-issue-29 ()
+  "Indentation of anonymous functions as arguments.
+The closing brace and parenthesis should be at column 0."
+  (with-php-mode-test ("issue-29.php" :indent t :magic t)))
+
+(ert-deftest php-mode-test-issue-42 ()
+  "Error while indenting closures.
+If the bug has been fixed, indenting the buffer should not cause
+an error."
+  (with-php-mode-test ("issue-42.php" :indent t)))
+
+(ert-deftest php-mode-test-issue-53 ()
+  "Check if whitespace effects are undone when changing coding
+style from Drupal."
+  (with-php-mode-test
+   ("issue-53.php")
+   (search-forward "return $this->bar;")
+   ;; the file written to has no significance, only the buffer
+   (let ((tmp-filename (make-temp-name temporary-file-directory)))
+     (dolist (mode '(pear wordpress symfony2))
+       (php-mode-custom-coding-style-set 'php-mode-coding-style 'drupal)
+       (php-mode-custom-coding-style-set 'php-mode-coding-style mode)
+       (should-not show-trailing-whitespace)
+       (write-file tmp-filename)
+       (should (char-equal (char-after) ?\s))))))
+
+(ert-deftest php-mode-test-issue-73 ()
+  "The `delete-indentation' function should work properly for PHP.
+ This means modifying the logic of `fixup-whitespace' so that it
+ eliminates spaces before ',', ';', '->' amd '::' and after '->' and
+ '::'."
+  (with-php-mode-test ("issue-73.php")
+    (when (search-forward "# Correct" nil t)
+      (forward-line 1)
+      (let ((correct-line (thing-at-point 'line)))
+        (while (search-forward "# Test" nil t)
+          (forward-line 1)
+          (let ((current-line (line-number-at-pos)))
+            (catch 'eob
+              (while (not (looking-at-p "$"))
+                (unless (zerop (forward-line 1))
+                  (throw 'eob t))))
+            (forward-line -1)
+            (while (not (eq (line-number-at-pos) current-line))
+              (delete-indentation))
+            (beginning-of-line)
+            (should (string= (thing-at-point 'line) correct-line))))))))
+
+(ert-deftest php-mode-test-issue-99 ()
+  "Proper indentation for 'foreach' statements without braces."
+  (with-php-mode-test ("issue-99.php" :indent t :magic t)))
+
+(ert-deftest php-mode-test-issue-115 ()
+  "Proper alignment for chained method calls inside arrays."
+  :expected-result :failed
+  (with-php-mode-test ("issue-115.php" :indent t :magic t)))
+
+(ert-deftest php-mode-test-issue-124 ()
+  "Proper syntax propertizing when a quote appears in a heredoc."
+  (with-php-mode-test ("issue-124.php" :indent t)
+     (search-forward "Heredoc")
+     ;; The heredoc should be recognized as a string.
+     (dolist (syntax (c-guess-basic-syntax))
+       (should (eq (car syntax) 'string)))
+     (search-forward "function bar")
+     ;; After the heredoc should *not* be recognized as a string.
+     (dolist (syntax (c-guess-basic-syntax))
+       (should (not (eq (car syntax) 'string))))))
+
+(ert-deftest php-mode-test-issue-136 ()
+  "Proper highlighting for variable interpolation."
+  (with-php-mode-test ("issue-136.php")
+    (let ((variables '("$name"
+                       "${name}"
+                       "{$name}"
+                       "{$user->name}"
+                       "{$user->getName()}"
+                       "{$users[0]->name}"
+                       "{$users[$index]->name}"
+                       "{$users[$user->id]->name}"
+                       "{$users[$user->getID()]->name}")))
+      ;; All of the strings we want to test come after the call to
+      ;; ob_start(), so we jump to there first.
+      (search-forward "ob_start()")
+      (dolist (variable variables)
+        (search-forward variable)
+        (should (eq 'font-lock-variable-name-face
+                    (get-text-property (point) 'face)))))))
+
+(ert-deftest php-mode-test-issue-145 ()
+  "Closure indentation."
+  (with-php-mode-test ("issue-145.php" :indent t)))
+
+;;; php-mode-test.el ends here
diff --git a/scripts/emacs/php-mode-1.10/php-mode.el b/scripts/emacs/php-mode-1.13.2/php-mode.el
similarity index 52%
rename from scripts/emacs/php-mode-1.10/php-mode.el
rename to scripts/emacs/php-mode-1.13.2/php-mode.el
index 5227e4bd6d4ceec37a0f90facdedd739ecc74651..58fdb02d7a5eb5562d19661db7fbb909bbed0580 100644
--- a/scripts/emacs/php-mode-1.10/php-mode.el
+++ b/scripts/emacs/php-mode-1.13.2/php-mode.el
@@ -2,16 +2,16 @@
 
 ;; Copyright (C) 1999, 2000, 2001, 2003, 2004 Turadg Aleahmad
 ;;               2008 Aaron S. Hawley
-;;               2011, 2012, 2013 Eric James Michael Ritz
+;;               2011, 2012, 2013, 2014 Eric James Michael Ritz
 
 ;;; Author: Eric James Michael Ritz
 ;;; URL: https://github.com/ejmr/php-mode
-;;; Version: 1.10
+;;; Version: 1.13.2
 
-(defconst php-mode-version-number "1.10"
+(defconst php-mode-version-number "1.13.2"
   "PHP Mode version number.")
 
-(defconst php-mode-modified "2013-02-06"
+(defconst php-mode-modified "2014-05-19"
   "PHP Mode build date.")
 
 ;;; License
@@ -61,11 +61,14 @@
 
 ;;; Code:
 
+(require 'add-log)
 (require 'font-lock)
 (require 'cc-mode)
 (require 'cc-langs)
 (require 'custom)
 (require 'flymake)
+(require 'etags)
+(require 'speedbar)
 (eval-when-compile
   (unless (require 'cl-lib nil t)
     (require 'cl))
@@ -83,7 +86,9 @@
 (defgroup php nil
   "Major mode `php-mode' for editing PHP code."
   :prefix "php-"
-  :group 'languages)
+  :group 'languages
+  :link '(url-link :tag "Official Site" "https://github.com/ejmr/php-mode")
+  :link '(url-link :tag "PHP Mode Wiki" "https://github.com/ejmr/php-mode/wiki"))
 
 (defcustom php-executable "/usr/bin/php"
   "The location of the PHP executable."
@@ -106,7 +111,7 @@ Ignores php-file patterns option; fixed to expression \"\\.\\(inc\\|php[s345]?\\
   :type 'boolean
   :set (lambda (sym val)
          (set-default sym val)
-         (if (and val (boundp 'speedbar))
+         (when val
              (speedbar-add-supported-extension
               "\\.\\(inc\\|php[s345]?\\|phtml\\)")))
   :group 'php)
@@ -121,14 +126,33 @@ Turning this on will open it whenever `php-mode' is loaded."
              (speedbar 1)))
   :group 'php)
 
-(defun php-create-regexp-for-method (type)
-  "Accepts a `type' of function as a string, e.g. 'public' or 'private',
-and returns a regexp that will match that type of function."
+(defcustom php-template-compatibility t
+  "Should detect presence of html tags."
+  :type 'boolean
+  :group 'php)
+
+;;;###autoload
+(defcustom php-extra-constants '()
+  "A list of additional strings to treat as PHP constants."
+  :type 'list
+  :group 'php)
+
+(defun php-create-regexp-for-method (visibility)
+  "Make a regular expression for methods with the given VISIBILITY.
+
+VISIBILITY must be a string that names the visibility for a PHP
+method, e.g. 'public'.  The parameter VISIBILITY can itself also
+be a regular expression.
+
+The regular expression this function returns will check for other
+keywords that can appear in method signatures, e.g. 'final' and
+'static'.  The regular expression will have one capture group
+which will be the name of the method."
   (concat
    ;; Initial space with possible 'abstract' or 'final' keywords
    "^\\s-*\\(?:\\(?:abstract\\|final\\)\\s-+\\)?"
-   ;; The function type
-   type
+   ;; The function visilibity
+   visibility
    ;; Is it static?
    "\\s-+\\(?:static\\s-+\\)?"
    ;; Make sure 'function' comes next with some space after
@@ -162,6 +186,8 @@ can be used to match against definitions for that classlike."
     ,(php-create-regexp-for-classlike "interface") 1)
    ("Traits"
     ,(php-create-regexp-for-classlike "trait") 1)
+   ("All Methods"
+    ,(php-create-regexp-for-method "\\(?:\\sw\\|\\s_\\)+") 1)
    ("Private Methods"
     ,(php-create-regexp-for-method "private") 1)
    ("Protected Methods"
@@ -198,16 +224,6 @@ You can replace \"en\" with your ISO language code."
 ;;;###autoload
 (add-to-list 'interpreter-mode-alist (cons "php" 'php-mode))
 
-;;;###autoload
-(defcustom php-file-patterns '("\\.php[s345t]?\\'" "\\.phtml\\'" "\\.inc\\'")
-  "List of file patterns for which to automatically invoke `php-mode'."
-  :type '(repeat (regexp :tag "Pattern"))
-  :set (lambda (sym val)
-         (set-default sym val)
-         (mapc (lambda (i) (add-to-list 'auto-mode-alist (cons i 'php-mode)))
-               val))
-  :group 'php)
-
 (defcustom php-mode-hook nil
   "List of functions to be executed on entry to `php-mode'."
   :type 'hook
@@ -228,6 +244,11 @@ You can replace \"en\" with your ISO language code."
   :type 'hook
   :group 'php)
 
+(defcustom php-mode-symfony2-hook nil
+  "Hook called when a Symfony2 file is opened with `php-mode'."
+  :type 'hook
+  :group 'php)
+
 (defcustom php-mode-force-pear nil
   "Normally PEAR coding rules are enforced only when the filename contains \"PEAR.\"
 Turning this on will force PEAR rules on all PHP files."
@@ -250,23 +271,29 @@ This variable can take one of the following symbol values:
 
 `Drupal' - use coding styles preferred for working with Drupal projects.
 
-`WordPress' - use coding styles preferred for working with WordPress projects."
+`WordPress' - use coding styles preferred for working with WordPress projects.
+
+`Symfony2' - use coding styles preferred for working with Symfony2 projects."
   :type '(choice (const :tag "PEAR" pear)
-                                 (const :tag "Drupal" drupal)
-                                 (const :tag "WordPress" wordpress))
+                 (const :tag "Drupal" drupal)
+                 (const :tag "WordPress" wordpress)
+                 (const :tag "Symfony2" symfony2))
   :group 'php
   :set 'php-mode-custom-coding-style-set
   :initialize 'custom-initialize-default)
 
 (defun php-mode-custom-coding-style-set (sym value)
-  (set         sym value)
-  (set-default sym value)
-  (cond ((eq value 'pear)
-                 (php-enable-pear-coding-style))
-                ((eq value 'drupal)
-                 (php-enable-drupal-coding-style))
-                ((eq value 'wordpress)
-                 (php-enable-wordpress-coding-style))))
+  (when (eq major-mode 'php-mode)
+    (set         sym value)
+    (set-default sym value)
+    (cond ((eq value 'pear)
+           (php-enable-pear-coding-style))
+          ((eq value 'drupal)
+           (php-enable-drupal-coding-style))
+          ((eq value 'wordpress)
+           (php-enable-wordpress-coding-style))
+          ((eq value 'symfony2)
+           (php-enable-symfony2-coding-style)))))
 
 
 
@@ -275,7 +302,15 @@ This variable can take one of the following symbol values:
  '((c-basic-offset . 4)
    (c-offsets-alist . ((block-open . -)
                        (block-close . 0)
-                       (statement-cont . +)))))
+                       (topmost-intro-cont . (first c-lineup-cascaded-calls
+                                                    php-lineup-arglist-intro))
+                       (brace-list-intro . +)
+                       (brace-list-entry . c-lineup-cascaded-calls)
+                       (arglist-close . php-lineup-arglist-close)
+                       (arglist-intro . php-lineup-arglist-intro)
+                       (knr-argdecl . [0])
+                       (arglist-cont-nonempty . c-lineup-cascaded-calls)
+                       (statement-cont . (first c-lineup-cascaded-calls +))))))
 
 (defun php-enable-pear-coding-style ()
   "Sets up php-mode to use the coding styles preferred for PEAR
@@ -283,16 +318,25 @@ code and modules."
   (interactive)
   (setq tab-width 4
         indent-tabs-mode nil)
-  (c-set-style "pear"))
+  (c-set-style "pear")
+  ;; Undo drupal coding style whitespace effects
+  (setq show-trailing-whitespace nil)
+  (remove-hook 'before-save-hook 'delete-trailing-whitespace t))
+
 
 (c-add-style
  "drupal"
  '((c-basic-offset . 2)
    (c-offsets-alist . ((case-label . +)
-                       (arglist-close . 0)
-                       (arglist-intro . +)
-                       (arglist-cont-nonempty . c-lineup-math)
-                       (statement-cont . +)))))
+                       (topmost-intro-cont . (first c-lineup-cascaded-calls
+                                                    php-lineup-arglist-intro))
+                       (brace-list-intro . +)
+                       (brace-list-entry . c-lineup-cascaded-calls)
+                       (arglist-close . php-lineup-arglist-close)
+                       (arglist-intro . php-lineup-arglist-intro)
+                       (arglist-cont-nonempty . (first c-lineup-math c-lineup-cascaded-calls))
+                       (knr-argdecl . [0])
+                       (statement-cont . (first c-lineup-cascaded-calls +))))))
 
 (defun php-enable-drupal-coding-style ()
   "Makes php-mode use coding styles that are preferable for
@@ -302,19 +346,26 @@ working with Drupal."
         indent-tabs-mode nil
         fill-column 78
         show-trailing-whitespace t)
-  (add-hook 'before-save-hook 'delete-trailing-whitespace)
+  (add-hook 'before-save-hook 'delete-trailing-whitespace nil t)
   (c-set-style "drupal"))
 
 (c-add-style
  "wordpress"
  '((c-basic-offset . 4)
    (c-offsets-alist . ((arglist-cont . 0)
-                       (arglist-intro . +)
+                       (arglist-intro . php-lineup-arglist-intro)
+                       (arglist-close . php-lineup-arglist-close)
+                       (topmost-intro-cont . (first c-lineup-cascaded-calls
+                                                    php-lineup-arglist-intro))
+                       (brace-list-intro . +)
+                       (brace-list-entry . c-lineup-cascaded-calls)
                        (case-label . 2)
                        (arglist-close . 0)
                        (defun-close . 0)
                        (defun-block-intro . +)
-                       (statement-cont . +)))))
+                       (knr-argdecl . [0])
+                       (arglist-cont-nonempty . c-lineup-cascaded-calls)
+                       (statement-cont . (first c-lineup-cascaded-calls +))))))
 
 (defun php-enable-wordpress-coding-style ()
   "Makes php-mode use coding styles that are preferable for
@@ -324,7 +375,42 @@ working with Wordpress."
         fill-column 78
         tab-width 4
         c-indent-comments-syntactically-p t)
-  (c-set-style "wordpress"))
+  (c-set-style "wordpress")
+  ;; Undo drupal coding style whitespace effects
+  (setq show-trailing-whitespace nil)
+  (remove-hook 'before-save-hook 'delete-trailing-whitespace t))
+
+(c-add-style
+ "symfony2"
+ '((c-basic-offset . 4)
+   (c-offsets-alist . ((arglist-cont . php-lineup-arglist)
+                       (arglist-intro . php-lineup-arglist-intro)
+                       (arglist-close . php-lineup-arglist-close)
+                       (topmost-intro-cont . (first c-lineup-cascaded-calls
+                                                    php-lineup-arglist-intro))
+                       (brace-list-intro . +)
+                       (brace-list-entry . c-lineup-cascaded-calls)
+                       (case-label . 4)
+                       (statement-case-intro . 4)
+                       (defun-close . 0)
+                       (defun-block-intro . +)
+                       (knr-argdecl . [0])
+                       (arglist-cont-nonempty . c-lineup-cascaded-calls)
+                       (statement-cont . php-lineup-hanging-semicolon)))))
+
+(defun php-enable-symfony2-coding-style ()
+  "Makes php-mode use coding styles that are preferable for
+working with Symfony2."
+  (interactive)
+  (setq indent-tabs-mode nil
+        fill-column 78
+        tab-width 4
+        c-indent-comments-syntactically-p t
+        require-final-newline t)
+  (c-set-style "symfony2")
+  ;; Undo drupal coding style whitespace effects
+  (setq show-trailing-whitespace nil)
+  (remove-hook 'before-save-hook 'delete-trailing-whitespace t))
 
 
 (defun php-mode-version ()
@@ -465,7 +551,7 @@ example `html-mode'.  Known such libraries are:\n\t"
 
 (defconst php-block-stmt-1-kwds '("do" "else" "finally" "try"))
 (defconst php-block-stmt-2-kwds
-  '("for" "if" "while" "switch" "foreach" "elseif"  "catch all"))
+  '("for" "if" "while" "switch" "foreach" "elseif" "catch" "catch all"))
 
 (defconst php-block-stmt-1-key
   (regexp-opt php-block-stmt-1-kwds))
@@ -489,27 +575,29 @@ POS is a position on the line in question.
 This is was done due to the problem reported here:
 
   URL `https://answers.launchpad.net/nxhtml/+question/43320'"
-  (setq pos (or pos (point)))
-  (let ((here (point))
-        ret)
-  (save-match-data
-    (goto-char pos)
-    (beginning-of-line)
-    (setq ret (looking-at
-               (rx
-                (or (seq
-                     bol
-                     (0+ space)
-                     "<"
-                     (in "a-z\\?"))
-                    (seq
-                     (0+ not-newline)
-                     (in "a-z\\?")
-                     ">"
-                     (0+ space)
-                     eol))))))
-  (goto-char here)
-  ret))
+  (if (not php-template-compatibility)
+      nil
+    (setq pos (or pos (point)))
+    (let ((here (point))
+          ret)
+      (save-match-data
+        (goto-char pos)
+        (beginning-of-line)
+        (setq ret (looking-at
+                   (rx
+                    (or (seq
+                         bol
+                         (0+ space)
+                         "<"
+                         (in "a-z\\?"))
+                        (seq
+                         (0+ not-newline)
+                         (in "a-z\\?")
+                         ">"
+                         (0+ space)
+                         eol))))))
+      (goto-char here)
+      ret)))
 
 (defun php-c-vsemi-status-unknown-p ()
   "See `php-c-at-vsemi-p'."
@@ -528,19 +616,15 @@ This is was done due to the problem reported here:
 (c-set-offset 'arglist-intro 'php-lineup-arglist-intro)
 (c-set-offset 'arglist-close 'php-lineup-arglist-close)
 
-(defun php-unindent-closure ()
-  (let ((syntax (mapcar 'car c-syntactic-context)))
-    (if (and (member 'arglist-cont-nonempty syntax)
-             (or
-              (member 'statement-block-intro syntax)
-              (member 'brace-list-intro syntax)
-              (member 'brace-list-close syntax)
-              (member 'block-close syntax)))
-        (save-excursion
-          (let ((count-func (if (fboundp 'cl-count) #'cl-count #'count)))
-            (beginning-of-line)
-            (delete-char (* (funcall count-func 'arglist-cont-nonempty syntax)
-                            c-basic-offset)))))))
+(defun php-lineup-arglist (langelem)
+  (save-excursion
+    (beginning-of-line)
+    (if (looking-at-p "\\s-*->") '+ 0)))
+
+(defun php-lineup-hanging-semicolon (langelem)
+  (save-excursion
+    (beginning-of-line)
+    (if (looking-at-p "\\s-*;\\s-*$") 0 '+)))
 
 (defvar php-mode-map
   (let ((map (make-sparse-keymap)))
@@ -554,6 +638,37 @@ This is was done due to the problem reported here:
     (define-key map [menu-bar php search-documentation]
       '("Search documentation" . php-search-documentation))
 
+    ;; By default PHP mode binds C-M-h to c-mark-function, which it
+    ;; inherits from cc-mode.  But there are situations where
+    ;; c-mark-function fails to properly mark a function.  For
+    ;; example, if we use c-mark-function within a method definition
+    ;; then the region will expand beyond the method and into the
+    ;; class definition itself.
+    ;;
+    ;; Changing the default to mark-defun provides behavior that users
+    ;; are more likely to expect.
+    (define-key map (kbd "C-M-h") 'mark-defun)
+
+    ;; Many packages based on cc-mode provide the 'C-c C-w' binding
+    ;; to toggle Subword Mode.  See the page
+    ;;
+    ;;     https://www.gnu.org/software/emacs/manual/html_node/ccmode/Subword-Movement.html
+    ;;
+    ;; for more information about Submode Word.
+    (if (boundp 'subword-mode)
+        (if subword-mode
+            (subword-mode nil)
+          (subword-mode t)))
+
+    ;; We inherit c-beginning-of-defun and c-end-of-defun from CC Mode
+    ;; but we have two replacement functions specifically for PHP.  We
+    ;; remap the commands themselves and not their default
+    ;; key-bindings so that our PHP-specific versions will work even
+    ;; if the user has reconfigured their keys, e.g. if they rebind
+    ;; c-end-of-defun to something other than C-M-e.
+    (define-key map [remap c-beginning-of-defun] 'php-beginning-of-defun)
+    (define-key map [remap c-end-of-defun] 'php-end-of-defun)
+
     (define-key map [(control c) (control f)] 'php-search-documentation)
     (define-key map [(meta tab)] 'php-complete-function)
     (define-key map [(control c) (control m)] 'php-browse-manual)
@@ -566,6 +681,46 @@ This is was done due to the problem reported here:
     map)
   "Keymap for `php-mode'")
 
+(defconst php-heredoc-start-re
+  "<<<\\(?:\\w+\\|'\\w+'\\)$"
+  "Regular expression for the start of a PHP heredoc.")
+
+(defun php-heredoc-end-re (heredoc-start)
+  "Build a regular expression for the end of a heredoc started by
+the string HEREDOC-START."
+  ;; Extract just the identifier without <<< and quotes.
+  (string-match "\\w+" heredoc-start)
+  (concat "^\\(" (match-string 0 heredoc-start) "\\)\\W"))
+
+(defun php-syntax-propertize-function (start end)
+  "Apply propertize rules from START to END."
+  ;; (defconst php-syntax-propertize-function
+  ;;   (syntax-propertize-rules
+  ;;    (php-heredoc-start-re (0 (ignore (php-heredoc-syntax))))))
+  (goto-char start)
+  (while (and (< (point) end)
+              (re-search-forward php-heredoc-start-re end t))
+    (php-heredoc-syntax)))
+
+(defun php-heredoc-syntax ()
+  "Mark the boundaries of searched heredoc."
+  (goto-char (match-beginning 0))
+  (c-put-char-property (point) 'syntax-table (string-to-syntax "|"))
+  (if (re-search-forward (php-heredoc-end-re (match-string 0)) nil t)
+      (goto-char (match-end 1))
+    ;; Did not find the delimiter so go to the end of the buffer.
+    (goto-char (point-max)))
+  (c-put-char-property (1- (point)) 'syntax-table (string-to-syntax "|")))
+
+(defun php-syntax-propertize-extend-region (start end)
+  "Extend the propertize region of START falls inside a heredoc."
+  (when (re-search-backward php-heredoc-start-re nil t)
+    (let ((new-start (point)))
+      (when (and (re-search-forward
+                  (php-heredoc-end-re (match-string 0)) nil t)
+                 (> (point) start))
+        (cons new-start end)))))
+
 ;;;###autoload
 (define-derived-mode php-mode c-mode "PHP"
   "Major mode for editing PHP code.\n\n\\{php-mode-map}"
@@ -576,11 +731,6 @@ This is was done due to the problem reported here:
   (set (make-local-variable 'c-opt-cpp-start) php-tags-key)
   (set (make-local-variable 'c-opt-cpp-prefix) php-tags-key)
 
-  ;; These settings ensure that chained method calls line up correctly
-  ;; over multiple lines.
-  (c-set-offset 'topmost-intro-cont 'c-lineup-cascaded-calls)
-  (c-set-offset 'brace-list-entry 'c-lineup-cascaded-calls)
-
   (set (make-local-variable 'c-block-stmt-1-key) php-block-stmt-1-key)
   (set (make-local-variable 'c-block-stmt-2-key) php-block-stmt-2-key)
 
@@ -612,6 +762,12 @@ This is was done due to the problem reported here:
        '(("\\(\"\\)\\(\\\\.\\|[^\"\n\\]\\)*\\(\"\\)" (1 "\"") (3 "\""))
          ("\\(\'\\)\\(\\\\.\\|[^\'\n\\]\\)*\\(\'\\)" (1 "\"") (3 "\""))))
 
+  (when (boundp 'syntax-propertize-function)
+    (add-to-list (make-local-variable 'syntax-propertize-extend-region-functions)
+                 #'php-syntax-propertize-extend-region)
+    (set (make-local-variable 'syntax-propertize-function)
+         #'php-syntax-propertize-function))
+
   (setq font-lock-maximum-decoration t
         imenu-generic-expression php-imenu-generic-expression)
 
@@ -636,12 +792,22 @@ This is was done due to the problem reported here:
   (add-hook 'php-mode-wordpress-hook 'php-enable-wordpress-coding-style
              nil t)
 
+  ;; ;; Symfony2 coding standards
+  (add-hook 'php-mode-symfony2-hook 'php-enable-symfony2-coding-style
+             nil t)
+
   (cond ((eq php-mode-coding-style 'pear)
-                 (run-hooks 'php-mode-pear-hook))
-                ((eq php-mode-coding-style 'drupal)
-                 (run-hooks 'php-mode-drupal-hook))
-                ((eq php-mode-coding-style 'wordpress)
-                 (run-hooks 'php-mode-wordpress-hook)))
+         (php-enable-pear-coding-style)
+         (run-hooks 'php-mode-pear-hook))
+        ((eq php-mode-coding-style 'drupal)
+         (php-enable-drupal-coding-style)
+         (run-hooks 'php-mode-drupal-hook))
+        ((eq php-mode-coding-style 'wordpress)
+         (php-enable-wordpress-coding-style)
+         (run-hooks 'php-mode-wordpress-hook))
+        ((eq php-mode-coding-style 'symfony2)
+         (php-enable-symfony2-coding-style)
+         (run-hooks 'php-mode-symfony2-hook)))
 
   (if (or php-mode-force-pear
           (and (stringp buffer-file-name)
@@ -652,16 +818,23 @@ This is was done due to the problem reported here:
 
   (setq indent-line-function 'php-cautious-indent-line)
   (setq indent-region-function 'php-cautious-indent-region)
-  (add-hook 'c-special-indent-hook 'php-unindent-closure)
   (setq c-at-vsemi-p-fn 'php-c-at-vsemi-p)
   (setq c-vsemi-status-unknown-p 'php-c-vsemi-status-unknown-p)
 
   (set (make-local-variable 'syntax-begin-function)
        'c-beginning-of-syntax)
+
+  ;; We map the php-{beginning,end}-of-defun functions so that they
+  ;; replace the similar commands that we inherit from CC Mode.
+  ;; Because of our remapping we may not actually need to keep the
+  ;; following two local variables, but we keep them for now until we
+  ;; are completely sure their removal will not break any current
+  ;; behavior or backwards compatibility.
   (set (make-local-variable 'beginning-of-defun-function)
        'php-beginning-of-defun)
   (set (make-local-variable 'end-of-defun-function)
        'php-end-of-defun)
+
   (set (make-local-variable 'open-paren-in-column-0-is-defun-start)
        nil)
   (set (make-local-variable 'defun-prompt-regexp)
@@ -712,11 +885,9 @@ current `tags-file-name'."
            (save-excursion (tags-verify-table tags-file-name))
            php-completion-table)
       (let ((tags-table
-             (if (and tags-file-name
-                      (functionp 'etags-tags-completion-table))
-                 (with-current-buffer (get-file-buffer tags-file-name)
-                   (etags-tags-completion-table))
-               nil))
+             (when tags-file-name
+               (with-current-buffer (get-file-buffer tags-file-name)
+                 (etags-tags-completion-table))))
             (php-table
              (cond ((and (not (string= "" php-completion-file))
                          (file-readable-p php-completion-file))
@@ -811,7 +982,12 @@ documentation exists, and nil otherwise."
                                  php-manual-path)))
     (let ((doc-file (php-function-file-for (current-word))))
       (and (file-exists-p doc-file)
-           (browse-url doc-file)
+           ;; Some browsers require the file:// prefix.  Others do not
+           ;; seem to care.  But it should never be incorrect to use
+           ;; the prefix.
+           (browse-url (if (string-prefix-p "file://" doc-file)
+                           doc-file
+                         (concat "file://" doc-file)))
            t))))
 
 ;; Define function documentation function
@@ -838,606 +1014,635 @@ searching the PHP website."
 
 
 (defconst php-constants
-  (eval-when-compile
-    (regexp-opt
-     '(;; core constants
-       "__LINE__" "__FILE__" "__DIR__"
-       "__FUNCTION__" "__CLASS__" "__TRAIT__" "__METHOD__"
-       "__NAMESPACE__"
-       "__COMPILER_HALT_OFFSET__"
-       "PHP_OS" "PHP_VERSION"
-       "PHP_MINOR_VERSION" "PHP_MAJOR_VERSION" "PHP_RELEASE_VERSION"
-       "PHP_VERSION_ID" "PHP_EXTRA_VERSION"
-       "TRUE" "FALSE" "NULL"
-       "E_ERROR" "E_NOTICE" "E_PARSE" "E_WARNING" "E_ALL" "E_STRICT"
-       "E_USER_ERROR" "E_USER_WARNING" "E_USER_NOTICE"
-       "E_CORE_ERROR" "E_CORE_WARNING"
-       "E_COMPILE_ERROR" "E_COMPILE_WARNING"
-       "E_DEPRECATED" "E_USER_DEPRECATED"
-       "DEFAULT_INCLUDE_PATH" "PEAR_INSTALL_DIR" "PEAR_EXTENSION_DIR"
-       "PHP_BINDIR" "PHP_LIBDIR" "PHP_DATADIR" "PHP_SYSCONFDIR"
-       "PHP_LOCALSTATEDIR" "PHP_CONFIG_FILE_PATH"
-       "PHP_EOL"
-       "PHP_ZTS"
-       "PHP_DEBUG"
-       "PHP_MAXPATHLEN"
-       "PHP_SAPI"
-       "PHP_INT_MAX" "PHP_INT_SIZE"
-       "PHP_EXTENSION_DIR"
-       "PHP_PREFIX"
-       "PHP_MANDIR"
-       "PHP_CONFIG_FILE_SCAN_DIR"
-
-       "PHP_WINDOWS_VERSION_MAJOR"
-       "PHP_WINDOWS_VERSION_MINOR"
-       "PHP_WINDOWS_VERSION_BUILD"
-       "PHP_WINDOWS_VERSION_PLATFORM"
-       "PHP_WINDOWS_VERSION_SP_MAJOR"
-       "PHP_WINDOWS_VERSION_SP_MINOR"
-       "PHP_WINDOWS_VERSION_SUITEMASK"
-       "PHP_WINDOWS_VERSION_PRODUCTTYPE"
-       "PHP_WINDOWS_NT_DOMAIN_CONTROLLER"
-       "PHP_WINDOWS_NT_SERVER"
-       "PHP_WINDOWS_NT_WORKSTATION"
-
-       ;; date and time constants
-       "DATE_ATOM" "DATE_COOKIE" "DATE_ISO8601"
-       "DATE_RFC822" "DATE_RFC850" "DATE_RFC1036" "DATE_RFC1123"
-       "DATE_RFC2822" "DATE_RFC3339"
-       "DATE_RSS" "DATE_W3C"
-
-       ;; upload error message constants
-       "UPLOAD_ERR_CANT_WRITE" "UPLOAD_ERR_EXTENSION"
-       "UPLOAD_ERR_FORM_SIZE" "UPLOAD_ERR_INI_SIZE"
-       "UPLOAD_ERR_NO_FILE" "UPLOAD_ERR_NO_TMP_DIR"
-       "UPLOAD_ERR_OK" "UPLOAD_ERR_PARTIAL"
-
-       ;; from ext/standard:
-       "EXTR_OVERWRITE"
-       "EXTR_PREFIX_SAME"
-       "EXTR_PREFIX_INVALID"
-       "EXTR_IF_EXISTS"
-       "SORT_DESC"
-       "SORT_NUMERIC"
-       "CASE_LOWER"
-       "COUNT_NORMAL"
-       "ASSERT_ACTIVE"
-       "ASSERT_BAIL"
-       "ASSERT_QUIET_EVAL"
-       "CONNECTION_NORMAL"
-       "INI_USER"
-       "INI_SYSTEM"
-       "M_E"
-       "M_LOG10E"
-       "M_LN10"
-       "M_PI_2"
-       "M_1_PI"
-       "M_2_SQRTPI"
-       "M_SQRT1_2"
-       "CRYPT_STD_DES"
-       "CRYPT_MD5"
-       "DIRECTORY_SEPARATOR"
-       "SEEK_CUR"
-       "LOCK_SH"
-       "LOCK_UN"
-       "HTML_SPECIALCHARS"
-       "ENT_COMPAT"
-       "ENT_QUOTES"
-       "ENT_NOQUOTES"
-       "ENT_IGNORE"
-       "ENT_SUBSTITUTE"
-       "ENT_DISALLOWED"
-       "ENT_HTML401"
-       "ENT_XML1"
-       "ENT_XHTML"
-       "ENT_HTML5"
-       "INFO_CREDITS"
-       "INFO_MODULES"
-       "INFO_VARIABLES"
-       "INFO_ALL"
-       "CREDITS_GENERAL"
-       "CREDITS_MODULES"
-       "CREDITS_FULLPAGE"
-       "CREDITS_ALL"
-       "STR_PAD_RIGHT"
-       "PATHINFO_DIRNAME"
-       "PATHINFO_EXTENSION"
-       "CHAR_MAX"
-       "LC_NUMERIC"
-       "LC_COLLATE"
-       "LC_ALL"
-       "ABDAY_1"
-       "ABDAY_3"
-       "ABDAY_5"
-       "ABDAY_7"
-       "DAY_2"
-       "DAY_4"
-       "DAY_6"
-       "ABMON_1"
-       "ABMON_3"
-       "ABMON_5"
-       "ABMON_7"
-       "ABMON_9"
-       "ABMON_11"
-       "MON_1"
-       "MON_3"
-       "MON_5"
-       "MON_7"
-       "MON_9"
-       "MON_11"
-       "AM_STR"
-       "D_T_FMT"
-       "T_FMT"
-       "ERA"
-       "ERA_D_T_FMT"
-       "ERA_T_FMT"
-       "INT_CURR_SYMBOL"
-       "CRNCYSTR"
-       "MON_THOUSANDS_SEP"
-       "POSITIVE_SIGN"
-       "INT_FRAC_DIGITS"
-       "P_CS_PRECEDES"
-       "N_CS_PRECEDES"
-       "P_SIGN_POSN"
-       "DECIMAL_POINT"
-       "THOUSANDS_SEP"
-       "GROUPING"
-       "NOEXPR"
-       "NOSTR"
-       "LOG_EMERG"
-       "LOG_CRIT"
-       "LOG_WARNING"
-       "LOG_INFO"
-       "LOG_KERN"
-       "LOG_MAIL"
-       "LOG_AUTH"
-       "LOG_LPR"
-       "LOG_UUCP"
-       "LOG_AUTHPRIV"
-       "LOG_LOCAL1"
-       "LOG_LOCAL3"
-       "LOG_LOCAL5"
-       "LOG_LOCAL7"
-       "LOG_CONS"
-       "LOG_NDELAY"
-       "LOG_PERROR"
-
-       ; Filter constants
-       "INPUT_POST"
-       "INPUT_GET"
-       "INPUT_COOKIE"
-       "INPUT_ENV"
-       "INPUT_SERVER"
-       "INPUT_SESSION"
-       "INPUT_REQUEST"
-       "FILTER_FLAG_NONE"
-       "FILTER_REQUIRE_SCALAR"
-       "FILTER_REQUIRE_ARRAY"
-       "FILTER_FORCE_ARRAY"
-       "FILTER_NULL_ON_FAILURE"
-       "FILTER_VALIDATE_INT"
-       "FILTER_VALIDATE_BOOLEAN"
-       "FILTER_VALIDATE_FLOAT"
-       "FILTER_VALIDATE_REGEXP"
-       "FILTER_VALIDATE_URL"
-       "FILTER_VALIDATE_EMAIL"
-       "FILTER_VALIDATE_IP"
-       "FILTER_DEFAULT"
-       "FILTER_UNSAFE_RAW"
-       "FILTER_SANITIZE_STRING"
-       "FILTER_SANITIZE_STRIPPED"
-       "FILTER_SANITIZE_ENCODED"
-       "FILTER_SANITIZE_SPECIAL_CHARS"
-       "FILTER_SANITIZE_EMAIL"
-       "FILTER_SANITIZE_URL"
-       "FILTER_SANITIZE_NUMBER_INT"
-       "FILTER_SANITIZE_NUMBER_FLOAT"
-       "FILTER_SANITIZE_MAGIC_QUOTES"
-       "FILTER_CALLBACK"
-       "FILTER_FLAG_ALLOW_OCTAL"
-       "FILTER_FLAG_ALLOW_HEX"
-       "FILTER_FLAG_STRIP_LOW"
-       "FILTER_FLAG_STRIP_HIGH"
-       "FILTER_FLAG_ENCODE_LOW"
-       "FILTER_FLAG_ENCODE_HIGH"
-       "FILTER_FLAG_ENCODE_AMP"
-       "FILTER_FLAG_NO_ENCODE_QUOTES"
-       "FILTER_FLAG_EMPTY_STRING_NULL"
-       "FILTER_FLAG_ALLOW_FRACTION"
-       "FILTER_FLAG_ALLOW_THOUSAND"
-       "FILTER_FLAG_ALLOW_SCIENTIFIC"
-       "FILTER_FLAG_PATH_REQUIRED"
-       "FILTER_FLAG_QUERY_REQUIRED"
-       "FILTER_FLAG_IPV4"
-       "FILTER_FLAG_IPV6"
-       "FILTER_FLAG_NO_RES_RANGE"
-       "FILTER_FLAG_NO_PRIV_RANGE"
-
-       ;; Password constants
-       "PASSWORD_DEFAULT"
-       "PASSWORD_BCRYPT"
-
-       ;; cURL constants
-       "CURLOPT_AUTOREFERER"
-       "CURLOPT_COOKIESESSION"
-       "CURLOPT_DNS_USE_GLOBAL_CACHE"
-       "CURLOPT_DNS_CACHE_TIMEOUT"
-       "CURLOPT_FTP_SSL"
-       "CURLFTPSSL_TRY"
-       "CURLFTPSSL_ALL"
-       "CURLFTPSSL_CONTROL"
-       "CURLFTPSSL_NONE"
-       "CURLOPT_PRIVATE"
-       "CURLOPT_FTPSSLAUTH"
-       "CURLOPT_PORT"
-       "CURLOPT_FILE"
-       "CURLOPT_INFILE"
-       "CURLOPT_INFILESIZE"
-       "CURLOPT_URL"
-       "CURLOPT_PROXY"
-       "CURLOPT_VERBOSE"
-       "CURLOPT_HEADER"
-       "CURLOPT_HTTPHEADER"
-       "CURLOPT_NOPROGRESS"
-       "CURLOPT_NOBODY"
-       "CURLOPT_FAILONERROR"
-       "CURLOPT_UPLOAD"
-       "CURLOPT_POST"
-       "CURLOPT_FTPLISTONLY"
-       "CURLOPT_FTPAPPEND"
-       "CURLOPT_FTP_CREATE_MISSING_DIRS"
-       "CURLOPT_NETRC"
-       "CURLOPT_FOLLOWLOCATION"
-       "CURLOPT_FTPASCII"
-       "CURLOPT_PUT"
-       "CURLOPT_MUTE"
-       "CURLOPT_USERPWD"
-       "CURLOPT_PROXYUSERPWD"
-       "CURLOPT_RANGE"
-       "CURLOPT_TIMEOUT"
-       "CURLOPT_TIMEOUT_MS"
-       "CURLOPT_TCP_NODELAY"
-       "CURLOPT_POSTFIELDS"
-       "CURLOPT_PROGRESSFUNCTION"
-       "CURLOPT_REFERER"
-       "CURLOPT_USERAGENT"
-       "CURLOPT_FTPPORT"
-       "CURLOPT_FTP_USE_EPSV"
-       "CURLOPT_LOW_SPEED_LIMIT"
-       "CURLOPT_LOW_SPEED_TIME"
-       "CURLOPT_RESUME_FROM"
-       "CURLOPT_COOKIE"
-       "CURLOPT_SSLCERT"
-       "CURLOPT_SSLCERTPASSWD"
-       "CURLOPT_WRITEHEADER"
-       "CURLOPT_SSL_VERIFYHOST"
-       "CURLOPT_COOKIEFILE"
-       "CURLOPT_SSLVERSION"
-       "CURLOPT_TIMECONDITION"
-       "CURLOPT_TIMEVALUE"
-       "CURLOPT_CUSTOMREQUEST"
-       "CURLOPT_STDERR"
-       "CURLOPT_TRANSFERTEXT"
-       "CURLOPT_RETURNTRANSFER"
-       "CURLOPT_QUOTE"
-       "CURLOPT_POSTQUOTE"
-       "CURLOPT_INTERFACE"
-       "CURLOPT_KRB4LEVEL"
-       "CURLOPT_HTTPPROXYTUNNEL"
-       "CURLOPT_FILETIME"
-       "CURLOPT_WRITEFUNCTION"
-       "CURLOPT_READFUNCTION"
-       "CURLOPT_PASSWDFUNCTION"
-       "CURLOPT_HEADERFUNCTION"
-       "CURLOPT_MAXREDIRS"
-       "CURLOPT_MAXCONNECTS"
-       "CURLOPT_CLOSEPOLICY"
-       "CURLOPT_FRESH_CONNECT"
-       "CURLOPT_FORBID_REUSE"
-       "CURLOPT_RANDOM_FILE"
-       "CURLOPT_EGDSOCKET"
-       "CURLOPT_CONNECTTIMEOUT"
-       "CURLOPT_CONNECTTIMEOUT_MS"
-       "CURLOPT_SSL_VERIFYPEER"
-       "CURLOPT_CAINFO"
-       "CURLOPT_CAPATH"
-       "CURLOPT_COOKIEJAR"
-       "CURLOPT_SSL_CIPHER_LIST"
-       "CURLOPT_BINARYTRANSFER"
-       "CURLOPT_NOSIGNAL"
-       "CURLOPT_PROXYTYPE"
-       "CURLOPT_BUFFERSIZE"
-       "CURLOPT_HTTPGET"
-       "CURLOPT_HTTP_VERSION"
-       "CURLOPT_SSLKEY"
-       "CURLOPT_SSLKEYTYPE"
-       "CURLOPT_SSLKEYPASSWD"
-       "CURLOPT_SSLENGINE"
-       "CURLOPT_SSLENGINE_DEFAULT"
-       "CURLOPT_SSLCERTTYPE"
-       "CURLOPT_CRLF"
-       "CURLOPT_ENCODING"
-       "CURLOPT_PROXYPORT"
-       "CURLOPT_UNRESTRICTED_AUTH"
-       "CURLOPT_FTP_USE_EPRT"
-       "CURLOPT_HTTP200ALIASES"
-       "CURLOPT_HTTPAUTH"
-       "CURLAUTH_BASIC"
-       "CURLAUTH_DIGEST"
-       "CURLAUTH_GSSNEGOTIATE"
-       "CURLAUTH_NTLM"
-       "CURLAUTH_ANY"
-       "CURLAUTH_ANYSAFE"
-       "CURLOPT_PROXYAUTH"
-       "CURLOPT_MAX_RECV_SPEED_LARGE"
-       "CURLOPT_MAX_SEND_SPEED_LARGE"
-       "CURLCLOSEPOLICY_LEAST_RECENTLY_USED"
-       "CURLCLOSEPOLICY_LEAST_TRAFFIC"
-       "CURLCLOSEPOLICY_SLOWEST"
-       "CURLCLOSEPOLICY_CALLBACK"
-       "CURLCLOSEPOLICY_OLDEST"
-       "CURLINFO_PRIVATE"
-       "CURLINFO_EFFECTIVE_URL"
-       "CURLINFO_HTTP_CODE"
-       "CURLINFO_HEADER_OUT"
-       "CURLINFO_HEADER_SIZE"
-       "CURLINFO_REQUEST_SIZE"
-       "CURLINFO_TOTAL_TIME"
-       "CURLINFO_NAMELOOKUP_TIME"
-       "CURLINFO_CONNECT_TIME"
-       "CURLINFO_PRETRANSFER_TIME"
-       "CURLINFO_SIZE_UPLOAD"
-       "CURLINFO_SIZE_DOWNLOAD"
-       "CURLINFO_SPEED_DOWNLOAD"
-       "CURLINFO_SPEED_UPLOAD"
-       "CURLINFO_FILETIME"
-       "CURLINFO_SSL_VERIFYRESULT"
-       "CURLINFO_CONTENT_LENGTH_DOWNLOAD"
-       "CURLINFO_CONTENT_LENGTH_UPLOAD"
-       "CURLINFO_STARTTRANSFER_TIME"
-       "CURLINFO_CONTENT_TYPE"
-       "CURLINFO_REDIRECT_TIME"
-       "CURLINFO_REDIRECT_COUNT"
-       "CURL_TIMECOND_IFMODSINCE"
-       "CURL_TIMECOND_IFUNMODSINCE"
-       "CURL_TIMECOND_LASTMOD"
-       "CURL_VERSION_IPV6"
-       "CURL_VERSION_KERBEROS4"
-       "CURL_VERSION_SSL"
-       "CURL_VERSION_LIBZ"
-       "CURLVERSION_NOW"
-       "CURLE_OK"
-       "CURLE_UNSUPPORTED_PROTOCOL"
-       "CURLE_FAILED_INIT"
-       "CURLE_URL_MALFORMAT"
-       "CURLE_URL_MALFORMAT_USER"
-       "CURLE_COULDNT_RESOLVE_PROXY"
-       "CURLE_COULDNT_RESOLVE_HOST"
-       "CURLE_COULDNT_CONNECT"
-       "CURLE_FTP_WEIRD_SERVER_REPLY"
-       "CURLE_FTP_ACCESS_DENIED"
-       "CURLE_FTP_USER_PASSWORD_INCORRECT"
-       "CURLE_FTP_WEIRD_PASS_REPLY"
-       "CURLE_FTP_WEIRD_USER_REPLY"
-       "CURLE_FTP_WEIRD_PASV_REPLY"
-       "CURLE_FTP_WEIRD_227_FORMAT"
-       "CURLE_FTP_CANT_GET_HOST"
-       "CURLE_FTP_CANT_RECONNECT"
-       "CURLE_FTP_COULDNT_SET_BINARY"
-       "CURLE_PARTIAL_FILE"
-       "CURLE_FTP_COULDNT_RETR_FILE"
-       "CURLE_FTP_WRITE_ERROR"
-       "CURLE_FTP_QUOTE_ERROR"
-       "CURLE_HTTP_NOT_FOUND"
-       "CURLE_WRITE_ERROR"
-       "CURLE_MALFORMAT_USER"
-       "CURLE_FTP_COULDNT_STOR_FILE"
-       "CURLE_READ_ERROR"
-       "CURLE_OUT_OF_MEMORY"
-       "CURLE_OPERATION_TIMEOUTED"
-       "CURLE_FTP_COULDNT_SET_ASCII"
-       "CURLE_FTP_PORT_FAILED"
-       "CURLE_FTP_COULDNT_USE_REST"
-       "CURLE_FTP_COULDNT_GET_SIZE"
-       "CURLE_HTTP_RANGE_ERROR"
-       "CURLE_HTTP_POST_ERROR"
-       "CURLE_SSL_CONNECT_ERROR"
-       "CURLE_FTP_BAD_DOWNLOAD_RESUME"
-       "CURLE_FILE_COULDNT_READ_FILE"
-       "CURLE_LDAP_CANNOT_BIND"
-       "CURLE_LDAP_SEARCH_FAILED"
-       "CURLE_LIBRARY_NOT_FOUND"
-       "CURLE_FUNCTION_NOT_FOUND"
-       "CURLE_ABORTED_BY_CALLBACK"
-       "CURLE_BAD_FUNCTION_ARGUMENT"
-       "CURLE_BAD_CALLING_ORDER"
-       "CURLE_HTTP_PORT_FAILED"
-       "CURLE_BAD_PASSWORD_ENTERED"
-       "CURLE_TOO_MANY_REDIRECTS"
-       "CURLE_UNKNOWN_TELNET_OPTION"
-       "CURLE_TELNET_OPTION_SYNTAX"
-       "CURLE_OBSOLETE"
-       "CURLE_SSL_PEER_CERTIFICATE"
-       "CURLE_GOT_NOTHING"
-       "CURLE_SSL_ENGINE_NOTFOUND"
-       "CURLE_SSL_ENGINE_SETFAILED"
-       "CURLE_SEND_ERROR"
-       "CURLE_RECV_ERROR"
-       "CURLE_SHARE_IN_USE"
-       "CURLE_SSL_CERTPROBLEM"
-       "CURLE_SSL_CIPHER"
-       "CURLE_SSL_CACERT"
-       "CURLE_BAD_CONTENT_ENCODING"
-       "CURLE_LDAP_INVALID_URL"
-       "CURLE_FILESIZE_EXCEEDED"
-       "CURLE_FTP_SSL_FAILED"
-       "CURLFTPAUTH_DEFAULT"
-       "CURLFTPAUTH_SSL"
-       "CURLFTPAUTH_TLS"
-       "CURLPROXY_HTTP"
-       "CURLPROXY_SOCKS5"
-       "CURL_NETRC_OPTIONAL"
-       "CURL_NETRC_IGNORED"
-       "CURL_NETRC_REQUIRED"
-       "CURL_HTTP_VERSION_NONE"
-       "CURL_HTTP_VERSION_1_0"
-       "CURL_HTTP_VERSION_1_1"
-       "CURLM_CALL_MULTI_PERFORM"
-       "CURLM_OK"
-       "CURLM_BAD_HANDLE"
-       "CURLM_BAD_EASY_HANDLE"
-       "CURLM_OUT_OF_MEMORY"
-       "CURLM_INTERNAL_ERROR"
-       "CURLMSG_DONE"
-       "CURLOPT_KEYPASSWD"
-       "CURLOPT_SSH_AUTH_TYPES"
-       "CURLOPT_SSH_HOST_PUBLIC_KEY_MD5"
-       "CURLOPT_SSH_PRIVATE_KEYFILE"
-       "CURLOPT_SSH_PUBLIC_KEYFILE"
-       "CURLSSH_AUTH_ANY"
-       "CURLSSH_AUTH_DEFAULT"
-       "CURLSSH_AUTH_HOST"
-       "CURLSSH_AUTH_KEYBOARD"
-       "CURLSSH_AUTH_NONE"
-       "CURLSSH_AUTH_PASSWORD"
-       "CURLSSH_AUTH_PUBLICKEY"
-
-       ;; IMAP constants
-       "NIL"
-       "OP_DEBUG"
-       "OP_READONLY"
-       "OP_ANONYMOUS"
-       "OP_SHORTCACHE"
-       "OP_SILENT"
-       "OP_PROTOTYPE"
-       "OP_HALFOPEN"
-       "OP_EXPUNGE"
-       "OP_SECURE"
-       "CL_EXPUNGE"
-       "FT_UID"
-       "FT_PEEK"
-       "FT_NOT"
-       "FT_INTERNAL"
-       "FT_PREFETCHTEXT"
-       "ST_UID"
-       "ST_SILENT"
-       "ST_SET"
-       "CP_UID"
-       "CP_MOVE"
-       "SE_UID"
-       "SE_FREE"
-       "SE_NOPREFETCH"
-       "SO_FREE"
-       "SO_NOSERVER"
-       "SA_MESSAGES"
-       "SA_RECENT"
-       "SA_UNSEEN"
-       "SA_UIDNEXT"
-       "SA_UIDVALIDITY"
-       "SA_ALL"
-       "LATT_NOINFERIORS"
-       "LATT_NOSELECT"
-       "LATT_MARKED"
-       "LATT_UNMARKED"
-       "SORTDATE"
-       "SORTARRIVAL"
-       "SORTFROM"
-       "SORTSUBJECT"
-       "SORTTO"
-       "SORTCC"
-       "SORTSIZE"
-       "TYPETEXT"
-       "TYPEMULTIPART"
-       "TYPEMESSAGE"
-       "TYPEAPPLCATION"
-       "TYPEAUDIO"
-       "TYPEIMAGE"
-       "TYPEVIDEO"
-       "TYPEOTHER"
-       "ENC7BIT"
-       "ENC8BIT"
-       "ENCBINARY"
-       "ENCBASE64"
-       "ENCQUOTEDPRINTABLE"
-       "ENCOTHER"
-       "IMAP_OPENTIMEOUT"
-       "IMAP_READTIMEOUT"
-       "IMAP_WRITETIMEOUT"
-       "IMAP_CLOSETIMEOUT"
-       "LATT_REFERRAL"
-       "LATT_HASCHILDREN"
-       "LATT_HASNOCHILDREN"
-       "TYPEMODEL"
-       "IMAP_GC_ELT"
-       "IMAP_GC_ENV"
-       "IMAP_GC_TEXTS")))
+  (regexp-opt
+   (append
+    php-extra-constants
+    (when (boundp 'web-mode-extra-php-constants) web-mode-extra-php-constants)
+    '( ;; core constants
+      "__LINE__" "__FILE__" "__DIR__"
+      "__FUNCTION__" "__CLASS__" "__TRAIT__" "__METHOD__"
+      "__NAMESPACE__"
+      "__COMPILER_HALT_OFFSET__"
+      "PHP_OS" "PHP_VERSION"
+      "PHP_MINOR_VERSION" "PHP_MAJOR_VERSION" "PHP_RELEASE_VERSION"
+      "PHP_VERSION_ID" "PHP_EXTRA_VERSION"
+      "TRUE" "FALSE" "NULL"
+      "E_ERROR" "E_NOTICE" "E_PARSE" "E_WARNING" "E_ALL" "E_STRICT"
+      "E_USER_ERROR" "E_USER_WARNING" "E_USER_NOTICE"
+      "E_CORE_ERROR" "E_CORE_WARNING"
+      "E_COMPILE_ERROR" "E_COMPILE_WARNING"
+      "E_DEPRECATED" "E_USER_DEPRECATED"
+      "DEFAULT_INCLUDE_PATH" "PEAR_INSTALL_DIR" "PEAR_EXTENSION_DIR"
+      "PHP_BINDIR" "PHP_LIBDIR" "PHP_DATADIR" "PHP_SYSCONFDIR"
+      "PHP_LOCALSTATEDIR" "PHP_CONFIG_FILE_PATH"
+      "PHP_EOL"
+      "PHP_ZTS"
+      "PHP_DEBUG"
+      "PHP_MAXPATHLEN"
+      "PHP_SAPI"
+      "PHP_INT_MAX" "PHP_INT_SIZE"
+      "PHP_EXTENSION_DIR"
+      "PHP_PREFIX"
+      "PHP_MANDIR"
+      "PHP_CONFIG_FILE_SCAN_DIR"
+
+      "PHP_WINDOWS_VERSION_MAJOR"
+      "PHP_WINDOWS_VERSION_MINOR"
+      "PHP_WINDOWS_VERSION_BUILD"
+      "PHP_WINDOWS_VERSION_PLATFORM"
+      "PHP_WINDOWS_VERSION_SP_MAJOR"
+      "PHP_WINDOWS_VERSION_SP_MINOR"
+      "PHP_WINDOWS_VERSION_SUITEMASK"
+      "PHP_WINDOWS_VERSION_PRODUCTTYPE"
+      "PHP_WINDOWS_NT_DOMAIN_CONTROLLER"
+      "PHP_WINDOWS_NT_SERVER"
+      "PHP_WINDOWS_NT_WORKSTATION"
+
+      ;; CLI SAPI
+      "STDIN"
+      "STDOUT"
+      "STDERR"
+
+      ;; date and time constants
+      "DATE_ATOM" "DATE_COOKIE" "DATE_ISO8601"
+      "DATE_RFC822" "DATE_RFC850" "DATE_RFC1036" "DATE_RFC1123"
+      "DATE_RFC2822" "DATE_RFC3339"
+      "DATE_RSS" "DATE_W3C"
+
+      ;; upload error message constants
+      "UPLOAD_ERR_CANT_WRITE" "UPLOAD_ERR_EXTENSION"
+      "UPLOAD_ERR_FORM_SIZE" "UPLOAD_ERR_INI_SIZE"
+      "UPLOAD_ERR_NO_FILE" "UPLOAD_ERR_NO_TMP_DIR"
+      "UPLOAD_ERR_OK" "UPLOAD_ERR_PARTIAL"
+
+      ;; from ext/standard:
+      "EXTR_OVERWRITE"
+      "EXTR_PREFIX_SAME"
+      "EXTR_PREFIX_INVALID"
+      "EXTR_IF_EXISTS"
+      "SORT_DESC"
+      "SORT_NUMERIC"
+      "CASE_LOWER"
+      "COUNT_NORMAL"
+      "ASSERT_ACTIVE"
+      "ASSERT_BAIL"
+      "ASSERT_QUIET_EVAL"
+      "CONNECTION_NORMAL"
+      "INI_USER"
+      "INI_SYSTEM"
+      "M_E"
+      "M_LOG10E"
+      "M_LN10"
+      "M_PI_2"
+      "M_1_PI"
+      "M_2_SQRTPI"
+      "M_SQRT1_2"
+      "CRYPT_STD_DES"
+      "CRYPT_MD5"
+      "DIRECTORY_SEPARATOR"
+      "SEEK_CUR"
+      "LOCK_SH"
+      "LOCK_UN"
+      "HTML_SPECIALCHARS"
+      "ENT_COMPAT"
+      "ENT_QUOTES"
+      "ENT_NOQUOTES"
+      "ENT_IGNORE"
+      "ENT_SUBSTITUTE"
+      "ENT_DISALLOWED"
+      "ENT_HTML401"
+      "ENT_XML1"
+      "ENT_XHTML"
+      "ENT_HTML5"
+      "INFO_CREDITS"
+      "INFO_MODULES"
+      "INFO_VARIABLES"
+      "INFO_ALL"
+      "CREDITS_GENERAL"
+      "CREDITS_MODULES"
+      "CREDITS_FULLPAGE"
+      "CREDITS_ALL"
+      "STR_PAD_RIGHT"
+      "PATHINFO_DIRNAME"
+      "PATHINFO_EXTENSION"
+      "CHAR_MAX"
+      "LC_NUMERIC"
+      "LC_COLLATE"
+      "LC_ALL"
+      "ABDAY_1"
+      "ABDAY_3"
+      "ABDAY_5"
+      "ABDAY_7"
+      "DAY_2"
+      "DAY_4"
+      "DAY_6"
+      "ABMON_1"
+      "ABMON_3"
+      "ABMON_5"
+      "ABMON_7"
+      "ABMON_9"
+      "ABMON_11"
+      "MON_1"
+      "MON_3"
+      "MON_5"
+      "MON_7"
+      "MON_9"
+      "MON_11"
+      "AM_STR"
+      "D_T_FMT"
+      "T_FMT"
+      "ERA"
+      "ERA_D_T_FMT"
+      "ERA_T_FMT"
+      "INT_CURR_SYMBOL"
+      "CRNCYSTR"
+      "MON_THOUSANDS_SEP"
+      "POSITIVE_SIGN"
+      "INT_FRAC_DIGITS"
+      "P_CS_PRECEDES"
+      "N_CS_PRECEDES"
+      "P_SIGN_POSN"
+      "DECIMAL_POINT"
+      "THOUSANDS_SEP"
+      "GROUPING"
+      "NOEXPR"
+      "NOSTR"
+      "LOG_EMERG"
+      "LOG_CRIT"
+      "LOG_WARNING"
+      "LOG_INFO"
+      "LOG_KERN"
+      "LOG_MAIL"
+      "LOG_AUTH"
+      "LOG_LPR"
+      "LOG_UUCP"
+      "LOG_AUTHPRIV"
+      "LOG_LOCAL1"
+      "LOG_LOCAL3"
+      "LOG_LOCAL5"
+      "LOG_LOCAL7"
+      "LOG_CONS"
+      "LOG_NDELAY"
+      "LOG_PERROR"
+
+      ;; Filter constants
+      "INPUT_POST"
+      "INPUT_GET"
+      "INPUT_COOKIE"
+      "INPUT_ENV"
+      "INPUT_SERVER"
+      "INPUT_SESSION"
+      "INPUT_REQUEST"
+      "FILTER_FLAG_NONE"
+      "FILTER_REQUIRE_SCALAR"
+      "FILTER_REQUIRE_ARRAY"
+      "FILTER_FORCE_ARRAY"
+      "FILTER_NULL_ON_FAILURE"
+      "FILTER_VALIDATE_INT"
+      "FILTER_VALIDATE_BOOLEAN"
+      "FILTER_VALIDATE_FLOAT"
+      "FILTER_VALIDATE_REGEXP"
+      "FILTER_VALIDATE_URL"
+      "FILTER_VALIDATE_EMAIL"
+      "FILTER_VALIDATE_IP"
+      "FILTER_DEFAULT"
+      "FILTER_UNSAFE_RAW"
+      "FILTER_SANITIZE_STRING"
+      "FILTER_SANITIZE_STRIPPED"
+      "FILTER_SANITIZE_ENCODED"
+      "FILTER_SANITIZE_SPECIAL_CHARS"
+      "FILTER_SANITIZE_FULL_SPECIAL_CHARS"
+      "FILTER_SANITIZE_EMAIL"
+      "FILTER_SANITIZE_URL"
+      "FILTER_SANITIZE_NUMBER_INT"
+      "FILTER_SANITIZE_NUMBER_FLOAT"
+      "FILTER_SANITIZE_MAGIC_QUOTES"
+      "FILTER_CALLBACK"
+      "FILTER_FLAG_ALLOW_OCTAL"
+      "FILTER_FLAG_ALLOW_HEX"
+      "FILTER_FLAG_STRIP_LOW"
+      "FILTER_FLAG_STRIP_HIGH"
+      "FILTER_FLAG_ENCODE_LOW"
+      "FILTER_FLAG_ENCODE_HIGH"
+      "FILTER_FLAG_ENCODE_AMP"
+      "FILTER_FLAG_NO_ENCODE_QUOTES"
+      "FILTER_FLAG_EMPTY_STRING_NULL"
+      "FILTER_FLAG_ALLOW_FRACTION"
+      "FILTER_FLAG_ALLOW_THOUSAND"
+      "FILTER_FLAG_ALLOW_SCIENTIFIC"
+      "FILTER_FLAG_PATH_REQUIRED"
+      "FILTER_FLAG_QUERY_REQUIRED"
+      "FILTER_FLAG_IPV4"
+      "FILTER_FLAG_IPV6"
+      "FILTER_FLAG_NO_RES_RANGE"
+      "FILTER_FLAG_NO_PRIV_RANGE"
+
+      ;; Password constants
+      "PASSWORD_DEFAULT"
+      "PASSWORD_BCRYPT"
+
+      ;; PREG constants
+      "PREG_PATTERN_ORDER"
+      "PREG_SET_ORDER"
+      "PREG_OFFSET_CAPTURE"
+      "PREG_SPLIT_NO_EMPTY"
+      "PREG_SPLIT_DELIM_CAPTURE"
+      "PREG_SPLIT_OFFSET_CAPTURE"
+      "PREG_NO_ERROR"
+      "PREG_INTERNAL_ERROR"
+      "PREG_BACKTRACK_LIMIT_ERROR"
+      "PREG_RECURSION_LIMIT_ERROR"
+      "PREG_BAD_UTF8_ERROR"
+      "PREG_BAD_UTF8_OFFSET_ERROR"
+      "PCRE_VERSION"
+
+      ;; cURL constants
+      "CURLOPT_AUTOREFERER"
+      "CURLOPT_COOKIESESSION"
+      "CURLOPT_DNS_USE_GLOBAL_CACHE"
+      "CURLOPT_DNS_CACHE_TIMEOUT"
+      "CURLOPT_FTP_SSL"
+      "CURLFTPSSL_TRY"
+      "CURLFTPSSL_ALL"
+      "CURLFTPSSL_CONTROL"
+      "CURLFTPSSL_NONE"
+      "CURLOPT_PRIVATE"
+      "CURLOPT_FTPSSLAUTH"
+      "CURLOPT_PORT"
+      "CURLOPT_FILE"
+      "CURLOPT_INFILE"
+      "CURLOPT_INFILESIZE"
+      "CURLOPT_URL"
+      "CURLOPT_PROXY"
+      "CURLOPT_VERBOSE"
+      "CURLOPT_HEADER"
+      "CURLOPT_HTTPHEADER"
+      "CURLOPT_NOPROGRESS"
+      "CURLOPT_NOBODY"
+      "CURLOPT_FAILONERROR"
+      "CURLOPT_UPLOAD"
+      "CURLOPT_POST"
+      "CURLOPT_FTPLISTONLY"
+      "CURLOPT_FTPAPPEND"
+      "CURLOPT_FTP_CREATE_MISSING_DIRS"
+      "CURLOPT_NETRC"
+      "CURLOPT_FOLLOWLOCATION"
+      "CURLOPT_FTPASCII"
+      "CURLOPT_PUT"
+      "CURLOPT_MUTE"
+      "CURLOPT_USERPWD"
+      "CURLOPT_PROXYUSERPWD"
+      "CURLOPT_RANGE"
+      "CURLOPT_TIMEOUT"
+      "CURLOPT_TIMEOUT_MS"
+      "CURLOPT_TCP_NODELAY"
+      "CURLOPT_POSTFIELDS"
+      "CURLOPT_PROGRESSFUNCTION"
+      "CURLOPT_REFERER"
+      "CURLOPT_USERAGENT"
+      "CURLOPT_FTPPORT"
+      "CURLOPT_FTP_USE_EPSV"
+      "CURLOPT_LOW_SPEED_LIMIT"
+      "CURLOPT_LOW_SPEED_TIME"
+      "CURLOPT_RESUME_FROM"
+      "CURLOPT_COOKIE"
+      "CURLOPT_SSLCERT"
+      "CURLOPT_SSLCERTPASSWD"
+      "CURLOPT_WRITEHEADER"
+      "CURLOPT_SSL_VERIFYHOST"
+      "CURLOPT_COOKIEFILE"
+      "CURLOPT_SSLVERSION"
+      "CURLOPT_TIMECONDITION"
+      "CURLOPT_TIMEVALUE"
+      "CURLOPT_CUSTOMREQUEST"
+      "CURLOPT_STDERR"
+      "CURLOPT_TRANSFERTEXT"
+      "CURLOPT_RETURNTRANSFER"
+      "CURLOPT_QUOTE"
+      "CURLOPT_POSTQUOTE"
+      "CURLOPT_INTERFACE"
+      "CURLOPT_KRB4LEVEL"
+      "CURLOPT_HTTPPROXYTUNNEL"
+      "CURLOPT_FILETIME"
+      "CURLOPT_WRITEFUNCTION"
+      "CURLOPT_READFUNCTION"
+      "CURLOPT_PASSWDFUNCTION"
+      "CURLOPT_HEADERFUNCTION"
+      "CURLOPT_MAXREDIRS"
+      "CURLOPT_MAXCONNECTS"
+      "CURLOPT_CLOSEPOLICY"
+      "CURLOPT_FRESH_CONNECT"
+      "CURLOPT_FORBID_REUSE"
+      "CURLOPT_RANDOM_FILE"
+      "CURLOPT_EGDSOCKET"
+      "CURLOPT_CONNECTTIMEOUT"
+      "CURLOPT_CONNECTTIMEOUT_MS"
+      "CURLOPT_SSL_VERIFYPEER"
+      "CURLOPT_CAINFO"
+      "CURLOPT_CAPATH"
+      "CURLOPT_COOKIEJAR"
+      "CURLOPT_SSL_CIPHER_LIST"
+      "CURLOPT_BINARYTRANSFER"
+      "CURLOPT_NOSIGNAL"
+      "CURLOPT_PROXYTYPE"
+      "CURLOPT_BUFFERSIZE"
+      "CURLOPT_HTTPGET"
+      "CURLOPT_HTTP_VERSION"
+      "CURLOPT_SSLKEY"
+      "CURLOPT_SSLKEYTYPE"
+      "CURLOPT_SSLKEYPASSWD"
+      "CURLOPT_SSLENGINE"
+      "CURLOPT_SSLENGINE_DEFAULT"
+      "CURLOPT_SSLCERTTYPE"
+      "CURLOPT_CRLF"
+      "CURLOPT_ENCODING"
+      "CURLOPT_PROXYPORT"
+      "CURLOPT_UNRESTRICTED_AUTH"
+      "CURLOPT_FTP_USE_EPRT"
+      "CURLOPT_HTTP200ALIASES"
+      "CURLOPT_HTTPAUTH"
+      "CURLAUTH_BASIC"
+      "CURLAUTH_DIGEST"
+      "CURLAUTH_GSSNEGOTIATE"
+      "CURLAUTH_NTLM"
+      "CURLAUTH_ANY"
+      "CURLAUTH_ANYSAFE"
+      "CURLOPT_PROXYAUTH"
+      "CURLOPT_MAX_RECV_SPEED_LARGE"
+      "CURLOPT_MAX_SEND_SPEED_LARGE"
+      "CURLCLOSEPOLICY_LEAST_RECENTLY_USED"
+      "CURLCLOSEPOLICY_LEAST_TRAFFIC"
+      "CURLCLOSEPOLICY_SLOWEST"
+      "CURLCLOSEPOLICY_CALLBACK"
+      "CURLCLOSEPOLICY_OLDEST"
+      "CURLINFO_PRIVATE"
+      "CURLINFO_EFFECTIVE_URL"
+      "CURLINFO_HTTP_CODE"
+      "CURLINFO_HEADER_OUT"
+      "CURLINFO_HEADER_SIZE"
+      "CURLINFO_REQUEST_SIZE"
+      "CURLINFO_TOTAL_TIME"
+      "CURLINFO_NAMELOOKUP_TIME"
+      "CURLINFO_CONNECT_TIME"
+      "CURLINFO_PRETRANSFER_TIME"
+      "CURLINFO_SIZE_UPLOAD"
+      "CURLINFO_SIZE_DOWNLOAD"
+      "CURLINFO_SPEED_DOWNLOAD"
+      "CURLINFO_SPEED_UPLOAD"
+      "CURLINFO_FILETIME"
+      "CURLINFO_SSL_VERIFYRESULT"
+      "CURLINFO_CONTENT_LENGTH_DOWNLOAD"
+      "CURLINFO_CONTENT_LENGTH_UPLOAD"
+      "CURLINFO_STARTTRANSFER_TIME"
+      "CURLINFO_CONTENT_TYPE"
+      "CURLINFO_REDIRECT_TIME"
+      "CURLINFO_REDIRECT_COUNT"
+      "CURL_TIMECOND_IFMODSINCE"
+      "CURL_TIMECOND_IFUNMODSINCE"
+      "CURL_TIMECOND_LASTMOD"
+      "CURL_VERSION_IPV6"
+      "CURL_VERSION_KERBEROS4"
+      "CURL_VERSION_SSL"
+      "CURL_VERSION_LIBZ"
+      "CURLVERSION_NOW"
+      "CURLE_OK"
+      "CURLE_UNSUPPORTED_PROTOCOL"
+      "CURLE_FAILED_INIT"
+      "CURLE_URL_MALFORMAT"
+      "CURLE_URL_MALFORMAT_USER"
+      "CURLE_COULDNT_RESOLVE_PROXY"
+      "CURLE_COULDNT_RESOLVE_HOST"
+      "CURLE_COULDNT_CONNECT"
+      "CURLE_FTP_WEIRD_SERVER_REPLY"
+      "CURLE_FTP_ACCESS_DENIED"
+      "CURLE_FTP_USER_PASSWORD_INCORRECT"
+      "CURLE_FTP_WEIRD_PASS_REPLY"
+      "CURLE_FTP_WEIRD_USER_REPLY"
+      "CURLE_FTP_WEIRD_PASV_REPLY"
+      "CURLE_FTP_WEIRD_227_FORMAT"
+      "CURLE_FTP_CANT_GET_HOST"
+      "CURLE_FTP_CANT_RECONNECT"
+      "CURLE_FTP_COULDNT_SET_BINARY"
+      "CURLE_PARTIAL_FILE"
+      "CURLE_FTP_COULDNT_RETR_FILE"
+      "CURLE_FTP_WRITE_ERROR"
+      "CURLE_FTP_QUOTE_ERROR"
+      "CURLE_HTTP_NOT_FOUND"
+      "CURLE_WRITE_ERROR"
+      "CURLE_MALFORMAT_USER"
+      "CURLE_FTP_COULDNT_STOR_FILE"
+      "CURLE_READ_ERROR"
+      "CURLE_OUT_OF_MEMORY"
+      "CURLE_OPERATION_TIMEOUTED"
+      "CURLE_FTP_COULDNT_SET_ASCII"
+      "CURLE_FTP_PORT_FAILED"
+      "CURLE_FTP_COULDNT_USE_REST"
+      "CURLE_FTP_COULDNT_GET_SIZE"
+      "CURLE_HTTP_RANGE_ERROR"
+      "CURLE_HTTP_POST_ERROR"
+      "CURLE_SSL_CONNECT_ERROR"
+      "CURLE_FTP_BAD_DOWNLOAD_RESUME"
+      "CURLE_FILE_COULDNT_READ_FILE"
+      "CURLE_LDAP_CANNOT_BIND"
+      "CURLE_LDAP_SEARCH_FAILED"
+      "CURLE_LIBRARY_NOT_FOUND"
+      "CURLE_FUNCTION_NOT_FOUND"
+      "CURLE_ABORTED_BY_CALLBACK"
+      "CURLE_BAD_FUNCTION_ARGUMENT"
+      "CURLE_BAD_CALLING_ORDER"
+      "CURLE_HTTP_PORT_FAILED"
+      "CURLE_BAD_PASSWORD_ENTERED"
+      "CURLE_TOO_MANY_REDIRECTS"
+      "CURLE_UNKNOWN_TELNET_OPTION"
+      "CURLE_TELNET_OPTION_SYNTAX"
+      "CURLE_OBSOLETE"
+      "CURLE_SSL_PEER_CERTIFICATE"
+      "CURLE_GOT_NOTHING"
+      "CURLE_SSL_ENGINE_NOTFOUND"
+      "CURLE_SSL_ENGINE_SETFAILED"
+      "CURLE_SEND_ERROR"
+      "CURLE_RECV_ERROR"
+      "CURLE_SHARE_IN_USE"
+      "CURLE_SSL_CERTPROBLEM"
+      "CURLE_SSL_CIPHER"
+      "CURLE_SSL_CACERT"
+      "CURLE_BAD_CONTENT_ENCODING"
+      "CURLE_LDAP_INVALID_URL"
+      "CURLE_FILESIZE_EXCEEDED"
+      "CURLE_FTP_SSL_FAILED"
+      "CURLFTPAUTH_DEFAULT"
+      "CURLFTPAUTH_SSL"
+      "CURLFTPAUTH_TLS"
+      "CURLPROXY_HTTP"
+      "CURLPROXY_SOCKS5"
+      "CURL_NETRC_OPTIONAL"
+      "CURL_NETRC_IGNORED"
+      "CURL_NETRC_REQUIRED"
+      "CURL_HTTP_VERSION_NONE"
+      "CURL_HTTP_VERSION_1_0"
+      "CURL_HTTP_VERSION_1_1"
+      "CURLM_CALL_MULTI_PERFORM"
+      "CURLM_OK"
+      "CURLM_BAD_HANDLE"
+      "CURLM_BAD_EASY_HANDLE"
+      "CURLM_OUT_OF_MEMORY"
+      "CURLM_INTERNAL_ERROR"
+      "CURLMSG_DONE"
+      "CURLOPT_KEYPASSWD"
+      "CURLOPT_SSH_AUTH_TYPES"
+      "CURLOPT_SSH_HOST_PUBLIC_KEY_MD5"
+      "CURLOPT_SSH_PRIVATE_KEYFILE"
+      "CURLOPT_SSH_PUBLIC_KEYFILE"
+      "CURLSSH_AUTH_ANY"
+      "CURLSSH_AUTH_DEFAULT"
+      "CURLSSH_AUTH_HOST"
+      "CURLSSH_AUTH_KEYBOARD"
+      "CURLSSH_AUTH_NONE"
+      "CURLSSH_AUTH_PASSWORD"
+      "CURLSSH_AUTH_PUBLICKEY"
+
+      ;; IMAP constants
+      "NIL"
+      "OP_DEBUG"
+      "OP_READONLY"
+      "OP_ANONYMOUS"
+      "OP_SHORTCACHE"
+      "OP_SILENT"
+      "OP_PROTOTYPE"
+      "OP_HALFOPEN"
+      "OP_EXPUNGE"
+      "OP_SECURE"
+      "CL_EXPUNGE"
+      "FT_UID"
+      "FT_PEEK"
+      "FT_NOT"
+      "FT_INTERNAL"
+      "FT_PREFETCHTEXT"
+      "ST_UID"
+      "ST_SILENT"
+      "ST_SET"
+      "CP_UID"
+      "CP_MOVE"
+      "SE_UID"
+      "SE_FREE"
+      "SE_NOPREFETCH"
+      "SO_FREE"
+      "SO_NOSERVER"
+      "SA_MESSAGES"
+      "SA_RECENT"
+      "SA_UNSEEN"
+      "SA_UIDNEXT"
+      "SA_UIDVALIDITY"
+      "SA_ALL"
+      "LATT_NOINFERIORS"
+      "LATT_NOSELECT"
+      "LATT_MARKED"
+      "LATT_UNMARKED"
+      "SORTDATE"
+      "SORTARRIVAL"
+      "SORTFROM"
+      "SORTSUBJECT"
+      "SORTTO"
+      "SORTCC"
+      "SORTSIZE"
+      "TYPETEXT"
+      "TYPEMULTIPART"
+      "TYPEMESSAGE"
+      "TYPEAPPLCATION"
+      "TYPEAUDIO"
+      "TYPEIMAGE"
+      "TYPEVIDEO"
+      "TYPEOTHER"
+      "ENC7BIT"
+      "ENC8BIT"
+      "ENCBINARY"
+      "ENCBASE64"
+      "ENCQUOTEDPRINTABLE"
+      "ENCOTHER"
+      "IMAP_OPENTIMEOUT"
+      "IMAP_READTIMEOUT"
+      "IMAP_WRITETIMEOUT"
+      "IMAP_CLOSETIMEOUT"
+      "LATT_REFERRAL"
+      "LATT_HASCHILDREN"
+      "LATT_HASNOCHILDREN"
+      "TYPEMODEL"
+      "IMAP_GC_ELT"
+      "IMAP_GC_ENV"
+      "IMAP_GC_TEXTS")))
   "PHP constants.")
 
 (defconst php-keywords
   (eval-when-compile
     (regexp-opt
-     ;; "class", "new" and "extends" get special treatment
-     ;; "case" gets special treatment elsewhere
-     '("and"
-       "array"
-       "as"
-       "break"
-       "catch all"
-       "catch"
-       "clone"
-       "continue"
-       "declare"
-       "default"
-       "die"
-       "do"
-       "echo"
-       "else"
-       "elseif"
-       "empty"
-       "encoding"
-       "endfor"
-       "endforeach"
-       "endif"
-       "endswitch"
-       "endwhile"
-       "exit"
-       "extends"
-       "finally"
-       "for"
-       "foreach"
-       "global"
-       "if"
-       "include"
-       "include_once"
-       "instanceof"
-       "insteadof"
-       "isset"
-       "list"
-       "or"
-       "require"
-       "require_once"
-       "return"
-       "static"
-       "switch"
-       "ticks"
-       "throw"
-       "try"
-       "unset"
-       "use"
-       "var"
-       "while"
-       "xor"
-       "yield")))
+     (append
+      (when (boundp 'web-mode-extra-php-keywords) web-mode-extra-php-keywords)
+      ;; "class", "new" and "extends" get special treatment
+      ;; "case" gets special treatment elsewhere
+      '("abstract"
+        "and"
+        "array"
+        "as"
+        "break"
+        "catch all"
+        "catch"
+        "clone"
+        "const"
+        "continue"
+        "declare"
+        "default"
+        "die"
+        "do"
+        "echo"
+        "else"
+        "elseif"
+        "empty"
+        "encoding"
+        "enddeclare"
+        "endfor"
+        "endforeach"
+        "endif"
+        "endswitch"
+        "endwhile"
+        "eval"
+        "exit"
+        "extends"
+        "final"
+        "finally"
+        "for"
+        "foreach"
+        "function"
+        "global"
+        "if"
+        "include"
+        "include_once"
+        "instanceof"
+        "insteadof"
+        "isset"
+        "list"
+        "or"
+        "private"
+        "protected"
+        "public"
+        "require"
+        "require_once"
+        "return"
+        "static"
+        "switch"
+        "throw"
+        "ticks"
+        "try"
+        "unset"
+        "use"
+        "var"
+        "while"
+        "xor"
+        "yield"))))
   "PHP keywords.")
 
-(defconst php-identifier
-  (eval-when-compile
-    '"[a-zA-Z\_\x7f-\xff][a-zA-Z0-9\_\x7f-\xff]*")
-  "Characters in a PHP identifier.")
-
 (defconst php-types
   (eval-when-compile
-    (regexp-opt '("array" "bool" "boolean" "callable" "char" "const" "double" "float"
+    (regexp-opt '("array" "bool" "boolean" "callable" "char" "double" "float"
                   "int" "integer" "long" "mixed" "object" "real"
                   "string")))
   "PHP types.")
@@ -1450,36 +1655,42 @@ searching the PHP website."
 
 ;; Set up font locking
 (defconst php-font-lock-keywords-1
-  (list
+  (append
+   (list
 
-   ;; Fontify constants
-   (cons
-    (concat "[^_$]?\\<\\(" php-constants "\\)\\>[^_]?")
-    '(1 font-lock-constant-face))
+    ;; Fontify constants
+    (cons
+     (concat "[^_$]?\\<\\(" php-constants "\\)\\>[^_]?")
+     '(1 font-lock-constant-face))
 
-   ;; Fontify keywords
-   (cons
-    (concat "[^_$]?\\<\\(" php-keywords "\\)\\>[^_]?")
-    '(1 font-lock-keyword-face))
+    ;; Fontify keywords
+    (cons
+     (concat "[^_$]?\\<\\(" php-keywords "\\)\\>[^_]?")
+     '(1 font-lock-keyword-face))
 
-   ;; Fontify keywords and targets, and case default tags.
-   (list "\\<\\(break\\|case\\|continue\\)\\>\\s-+\\(-?\\sw+\\)?"
-         '(1 font-lock-keyword-face) '(2 font-lock-constant-face keep t))
-   ;; This must come after the one for keywords and targets.
-   '(":" ("^\\s-+\\(\\sw+\\)\\s-+\\s-+$"
-          (beginning-of-line) (end-of-line)
-          (1 font-lock-constant-face)))
+    ;; Fontify keywords and targets, and case default tags.
+    (list "\\<\\(break\\|case\\|continue\\)\\>\\s-+\\(-?\\sw+\\)?"
+          '(1 font-lock-keyword-face) '(2 font-lock-constant-face keep t))
+    ;; This must come after the one for keywords and targets.
+    '(":" ("^\\s-+\\(\\sw+\\)\\s-+\\s-+$"
+           (beginning-of-line) (end-of-line)
+           (1 font-lock-constant-face)))
 
-   ;; treat 'print' as keyword only when not used like a function name
-   '("\\<print\\s-*(" . php-function-call-face)
-   '("\\<print\\>" . font-lock-keyword-face)
+    ;; treat 'print' as keyword only when not used like a function name
+    '("\\<print\\s-*(" . php-function-call-face)
+    '("\\<print\\>" . font-lock-keyword-face)
 
-   ;; Fontify PHP tag
-   (cons php-tags-key font-lock-preprocessor-face)
+    ;; Fontify PHP tag
+    (cons php-tags-key font-lock-preprocessor-face)
 
-   ;; Fontify ASP-style tag
-   '("<\\%\\(=\\)?" . font-lock-preprocessor-face)
-   '("\\%>" . font-lock-preprocessor-face)
+    )
+
+   (if php-template-compatibility
+       (list
+        ;; Fontify ASP-style tag
+        '("<\\%\\(=\\)?" . font-lock-preprocessor-face)
+        '("\\%>" . font-lock-preprocessor-face))
+     ())
 
    )
   "Subdued level highlighting for PHP mode.")
@@ -1491,71 +1702,61 @@ searching the PHP website."
 
     ;; namespace, class, interface, and trait declarations
     '("\\<\\(namespace\\|class\\|interface\\|trait\\)\\s-+\\(\\(?:\\sw\\|\\\\\\)+\\)?"
-      (1 font-lock-keyword-face) (2 font-lock-type-face nil t))
+      (1 font-lock-keyword-face)
+      (2 font-lock-type-face nil t))
 
     ;; handle several words specially, to include following word,
     ;; thereby excluding it from unknown-symbol checks later
     ;; FIX to handle implementing multiple
     ;; currently breaks on "class Foo implements Bar, Baz"
     '("\\<\\(new\\|extends\\|implements\\)\\s-+\\$?\\(\\(:?\\sw\\|\\\\\\)+\\)"
-      (1 font-lock-keyword-face) (2 font-lock-type-face nil t))
+      (1 font-lock-keyword-face)
+      (2 font-lock-type-face nil t))
 
     ;; instanceof operator
     '("\\<instanceof\\s-+\\([^$]\\(:?\\sw\\|\\\\\\)+\\)"
       (1 font-lock-type-face nil t))
 
     ;; namespace imports
-    '("\\<\\(use\\)\\s-+\\(\\(?:\\sw\\|\\(?:,\s-?\\)\\|\\\\\\)+\\)"
-      (1 font-lock-keyword-face)
-      (2 font-lock-type-face))
+    '("\\<use\\s-+\\(\\(?:\\sw\\|\\(?:,\\s-*\\)\\|\\\\\\)+\\)"
+      (1 font-lock-type-face))
 
     ;; namespace imports with aliases
-    '("\\<\\(use\\)\\s-+\\(\\(?:\\sw\\|\\\\\\)+\\)\\s-+\\(as\\)\\s-+\\(\\(?:\\sw\\|\\\\\\)+\\)"
-      (1 font-lock-keyword-face)
-      (2 font-lock-type-face)
-      (3 font-lock-keyword-face)
-      (4 font-lock-type-face))
+    '("\\<use\\s-+\\(\\(?:\\sw\\|\\\\\\)+\\)\\s-+as\\s-+\\(\\(?:\\sw\\|\\\\\\)+\\)"
+      (1 font-lock-type-face)
+      (2 font-lock-type-face))
 
     ;; constants
-    '("\\<\\(const\\)\\s-+\\(\\sw+\\)"
-      (1 font-lock-keyword-face)
-      (2 font-lock-type-face))
+    '("\\<const\\s-+\\(\\sw+\\)"
+      (1 font-lock-type-face))
 
     ;; function declaration
-    '("\\<\\(function\\)\\s-+&?\\(\\sw+\\)\\s-*("
-      (1 font-lock-keyword-face)
-      (2 font-lock-function-name-face nil t))
-
-    ;; class hierarchy
-    '("\\<\\(self\\|parent\\)\\>" (1 font-lock-constant-face nil nil))
+    '("\\<function\\s-+&?\\(\\sw+\\)\\s-*("
+      (1 font-lock-function-name-face nil t))
 
-    ;; method and variable features
-    '("\\<\\(private\\|protected\\|public\\)\\s-+\\$?\\sw+"
-      (1 font-lock-keyword-face))
-
-    ;; method features
-    '("^\\s-*\\(abstract\\|static\\|final\\)\\s-+\\$?\\sw+"
-      (1 font-lock-keyword-face))
-
-    ;; variable features
-    '("^\\s-*\\(static\\|const\\)\\s-+\\$?\\sw+"
-      (1 font-lock-keyword-face))
+    ;; self, parent, and static in class contexts
+    '("\\<\\(self\\)\\(?:::\\)" (1 font-lock-constant-face nil nil))
+    '("\\<\\(parent\\)\\(?:::\\|\\s-*(\\)" (1 font-lock-constant-face nil nil))
+    '("\\<\\(static\\)\\(?:::\\)" (1 font-lock-constant-face t nil))
     ))
   "Medium level highlighting for PHP mode.")
 
 (defconst php-font-lock-keywords-3
   (append
    php-font-lock-keywords-2
+   (if php-template-compatibility
+       (list
+        '("</?[a-z!:]+" . font-lock-constant-face)
+        ;; HTML >
+        '("<[^>]*\\(>\\)" (1 font-lock-constant-face))
+        ;; HTML tags
+        '("\\(<[a-z]+\\)[[:space:]]+\\([a-z:]+=\\)[^>]*?"
+          (1 font-lock-constant-face)
+          (2 font-lock-constant-face))
+        '("\"[[:space:]]+\\([a-z:]+=\\)" (1 font-lock-constant-face))
+        )
+     ())
    (list
-    '("</?[a-z!:]+" . font-lock-constant-face)
-
-    ;; HTML >
-    '("<[^>]*\\(>\\)" (1 font-lock-constant-face))
-
-    ;; HTML tags
-    '("\\(<[a-z]+\\)[[:space:]]+\\([a-z:]+=\\)[^>]*?" (1 font-lock-constant-face) (2 font-lock-constant-face) )
-    '("\"[[:space:]]+\\([a-z:]+=\\)" (1 font-lock-constant-face))
-
     ;; warn about $word.word -- it could be a valid concatenation,
     ;; but without any spaces we'll assume $word->word was meant.
     '("\\$\\sw+\\(\\.\\)\\sw"
@@ -1573,7 +1774,7 @@ searching the PHP website."
       1 font-lock-type-face)
 
     ;; Function calls qualified by namespaces
-    '("\\(?:\\(\\sw+\\)\\\\\\)+\\sw+("
+    '("\\(\\\\?\\(?:\\sw+\\\\\\)+\\)\\sw+("
       (1 font-lock-type-face))
 
     ;; Fontify variables and function calls
@@ -1681,6 +1882,26 @@ The output will appear in the buffer *PHP*."
 
 
 
+;;; Correct the behavior of `delete-indentation' by modifying the
+;;; logic of `fixup-whitespace'.
+(defadvice fixup-whitespace (after php-mode-fixup-whitespace)
+  "Remove whitespace before certain characters in PHP mode."
+  (let* ((no-behind-space ";\\|,\\|->\\|::")
+         (no-front-space "->\\|::"))
+    (when (and (eq major-mode 'php-mode)
+               (or (looking-at-p (concat " \\(" no-behind-space "\\)"))
+                   (save-excursion
+                     (forward-char -2)
+                     (looking-at-p no-front-space))))
+      (delete-char 1))))
+
+(ad-activate 'fixup-whitespace)
+
+
+;;;###autoload
+(dolist (pattern '("\\.php[s345t]?\\'" "\\.phtml\\'" "Amkfile" "\\.amk$"))
+  (add-to-list 'auto-mode-alist `(,pattern . php-mode) t))
+
 (provide 'php-mode)
 
 ;;; php-mode.el ends here
diff --git a/scripts/emacs/php-mode-1.10/tests/README.md b/scripts/emacs/php-mode-1.13.2/tests/README.md
similarity index 70%
rename from scripts/emacs/php-mode-1.10/tests/README.md
rename to scripts/emacs/php-mode-1.13.2/tests/README.md
index 9c290ff9bc777b03b3a1f437fde593e0a7200d14..9eea1e386b5c2431cc3c2211423c318d527483c0 100644
--- a/scripts/emacs/php-mode-1.10/tests/README.md
+++ b/scripts/emacs/php-mode-1.13.2/tests/README.md
@@ -1,14 +1,17 @@
 Tests
 =====
 
-This directory contains tests for php-mode.  Each test begins with a
+This directory contains tests for PHP Mode.  Each test begins with a
 comment header explaining the purpose of the test and a link to the
 relative [Github issue][github].  The main purpose of these tests are
 to demonstrate whether or not features like syntax highlighting and
 indentation work properly.  Because of that, executing most of the
 tests is not important, since we do not care about how PHP itself
 interprets the test scripts.  We only care about how Emacs and
-php-mode formats the code within each test.
+PHP Mode formats the code within each test.
+
+Please use the file `tests/template.php` as a start when creating new
+tests cases.
 
 
 
diff --git a/scripts/emacs/php-mode-1.13.2/tests/issue-100.php b/scripts/emacs/php-mode-1.13.2/tests/issue-100.php
new file mode 100644
index 0000000000000000000000000000000000000000..d1053ccca7369b0b7b1341268595f15c67612496
--- /dev/null
+++ b/scripts/emacs/php-mode-1.13.2/tests/issue-100.php
@@ -0,0 +1,26 @@
+<?php
+
+/**
+ * GitHub Issue:    https://github.com/ejmr/php-mode/issues/100
+ *
+ * The code below should appear like so:
+ *
+ *     use ReflectionMethod,
+ *         ReflectionObject,
+ *         ReflectionProperty;
+ *
+ * Each namespace must have the correct font-face.  Aligning the
+ * namespaces is also required to satisfy the test.
+ * 
+ */
+
+use ReflectionMethod,
+    ReflectionObject,
+    ReflectionProperty;
+
+class Foo
+{
+    use ReflectionMethod,
+        ReflectionObject,
+        ReflectionProperty;
+}
\ No newline at end of file
diff --git a/scripts/emacs/php-mode-1.13.2/tests/issue-102.php b/scripts/emacs/php-mode-1.13.2/tests/issue-102.php
new file mode 100644
index 0000000000000000000000000000000000000000..95d7adbd024bcd2efe314bdb548f56988cc8f012
--- /dev/null
+++ b/scripts/emacs/php-mode-1.13.2/tests/issue-102.php
@@ -0,0 +1,23 @@
+<?php
+
+/**
+ * Github Issue:    https://github.com/ejmr/php-mode/issues/102
+ *
+ * Every line of code in the form of
+ *
+ *     $broken = true;
+ *
+ * in the code below should have no indentation.  This test makes sure
+ * that files containing magic constants, e.g. __FILE__, do not
+ * incorrectly affect the indentation of following lines.
+ *
+ */
+
+$x = some_function(__FILE__) . '';
+$broken = true;
+
+some_function(__FILE__) . '';
+$broken = true;
+
+some_function(__FILE__) + 1;
+$broken = true;
diff --git a/scripts/emacs/php-mode-1.13.2/tests/issue-115.php b/scripts/emacs/php-mode-1.13.2/tests/issue-115.php
new file mode 100644
index 0000000000000000000000000000000000000000..096389b0a981cd8d9bde46ef4f39d3c9ef672363
--- /dev/null
+++ b/scripts/emacs/php-mode-1.13.2/tests/issue-115.php
@@ -0,0 +1,18 @@
+<?php
+
+/**
+ * Github Issue:    https://github.com/ejmr/php-mode/issues/115
+ *
+ * This tests for aligning method calls within arrays, similar to what
+ * we do in the test for issue 19.  The method calls below should all
+ * align vertically along the '->' characters.
+ *
+ */
+
+$x = ["x" => $this->foo()
+                  ->bar()   // ###php-mode-test### ((indent c-lineup-cascaded-calls))
+                  ->baz()]; // ###php-mode-test### ((indent c-lineup-cascaded-calls))
+
+$y = array("y" => $this->foo()
+                       ->bar()   // ###php-mode-test### ((indent c-lineup-cascaded-calls))
+                       ->baz()); // ###php-mode-test### ((indent c-lineup-cascaded-calls))
diff --git a/scripts/emacs/php-mode-1.13.2/tests/issue-124.php b/scripts/emacs/php-mode-1.13.2/tests/issue-124.php
new file mode 100644
index 0000000000000000000000000000000000000000..d220c07f0bcec07c4a9df868ecd4c8001a81884a
--- /dev/null
+++ b/scripts/emacs/php-mode-1.13.2/tests/issue-124.php
@@ -0,0 +1,20 @@
+<?php
+
+/**
+ * GitHub Issue:    https://github.com/ejmr/php-mode/issues/124
+ *
+ * PHP Mode must highlight the heredoc string below using
+ * font-lock-string-face.  The presence of the apostrophe or anything
+ * else within the string should not stop the highlighting from
+ * leaking out beyond the ending 'EOT' marker.
+ * 
+ */
+
+$foo = <<<EOT
+Heredoc with a ' inside.
+EOT;
+
+function bar()
+{
+    return true;
+}
diff --git a/scripts/emacs/php-mode-1.13.2/tests/issue-129.php b/scripts/emacs/php-mode-1.13.2/tests/issue-129.php
new file mode 100644
index 0000000000000000000000000000000000000000..2767615fdee25b1b69eff3415bfc7f8cac792fb1
--- /dev/null
+++ b/scripts/emacs/php-mode-1.13.2/tests/issue-129.php
@@ -0,0 +1,17 @@
+<?php
+
+/**
+ * GitHub Issue:    https://github.com/ejmr/php-mode/issues/129
+ *
+ * PHP Mode should use 'font-lock-keyword-face' to highlight 'final'
+ * in the method below.
+ * 
+ */
+
+class MyClass
+{
+        public final function foo() 
+        {
+                return null;
+        }
+}
diff --git a/scripts/emacs/php-mode-1.13.2/tests/issue-136.php b/scripts/emacs/php-mode-1.13.2/tests/issue-136.php
new file mode 100644
index 0000000000000000000000000000000000000000..97de245f8c5263b1613c9e5e0e01946e729dea27
--- /dev/null
+++ b/scripts/emacs/php-mode-1.13.2/tests/issue-136.php
@@ -0,0 +1,53 @@
+<?php
+
+/**
+ * GitHub Issue:    https://github.com/ejmr/php-mode/issues/136
+ *
+ * The code below contains strings with interpolated variables.  PHP
+ * Mode must use font-lock-variable-name-face to highlight all of
+ * those variables.  The page
+ *
+ *     http://www.php.net/manual/en/language.types.string.php#language.types.string.parsing
+ *
+ * describes all of the variable syntaxes which PHP Mode must
+ * recognize and highlight appropriately.
+ * 
+ */
+
+$name = "Eric";
+
+class User
+{
+        public $name;
+        public $id = 0;
+
+        public function getName()
+        {
+                return $this->name;
+        }
+
+        public function getID()
+        {
+                return $this->id;
+        }
+}
+
+$user = new User();
+$user->name = "Eric";
+
+$users = array($user);
+$index = 0;
+
+ob_start();
+
+echo "My name is $name";
+echo "My name is ${name}";
+echo "My name is {$name}";
+echo "My name is {$user->name}";
+echo "My name is {$user->getName()}";
+echo "My name is {$users[0]->name}";
+echo "My name is {$users[$index]->name}";
+echo "My name is {$users[$user->id]->name}";
+echo "My name is {$users[$user->getID()]->name}";
+
+ob_end_clean();
diff --git a/scripts/emacs/php-mode-1.10/tests/issue-14.php b/scripts/emacs/php-mode-1.13.2/tests/issue-14.php
similarity index 51%
rename from scripts/emacs/php-mode-1.10/tests/issue-14.php
rename to scripts/emacs/php-mode-1.13.2/tests/issue-14.php
index 18652c7e531ec6a5a2064b422378535b2bf28f9a..96f49fdab2403f93303ad28c87d8e7403f8851de 100644
--- a/scripts/emacs/php-mode-1.10/tests/issue-14.php
+++ b/scripts/emacs/php-mode-1.13.2/tests/issue-14.php
@@ -15,7 +15,7 @@
  */
 
 $post = Post::model()->find(array(
-    'select' => 'title',
-    'condition' => 'postID=:postID',
-    'params' => array(':postID'=>10),
-));
\ No newline at end of file
+    'select' => 'title',              // ###php-mode-test### ((indent c-basic-offset))
+    'condition' => 'postID=:postID',  // ###php-mode-test### ((indent c-basic-offset))
+    'params' => array(':postID'=>10), // ###php-mode-test### ((indent c-basic-offset))
+));                                   // ###php-mode-test### ((indent 0))
\ No newline at end of file
diff --git a/scripts/emacs/php-mode-1.13.2/tests/issue-145.php b/scripts/emacs/php-mode-1.13.2/tests/issue-145.php
new file mode 100644
index 0000000000000000000000000000000000000000..affb0a0d21ed985191df81098ef20d9eb674c1b3
--- /dev/null
+++ b/scripts/emacs/php-mode-1.13.2/tests/issue-145.php
@@ -0,0 +1,18 @@
+<?php
+
+/**
+ * GitHub Issue:    https://github.com/ejmr/php-mode/issues/145
+ *
+ * This tests closure indentation.
+ *
+ */
+
+function bar() {
+    return function() {
+        array_filter(function($foo) {
+            return array_map(function() use ($foo) {
+                return "xxx";
+            }, "foo");
+        });
+    };
+}
\ No newline at end of file
diff --git a/scripts/emacs/php-mode-1.10/tests/issue-16.php b/scripts/emacs/php-mode-1.13.2/tests/issue-16.php
similarity index 100%
rename from scripts/emacs/php-mode-1.10/tests/issue-16.php
rename to scripts/emacs/php-mode-1.13.2/tests/issue-16.php
diff --git a/scripts/emacs/php-mode-1.10/tests/issue-18.php b/scripts/emacs/php-mode-1.13.2/tests/issue-18.php
similarity index 81%
rename from scripts/emacs/php-mode-1.10/tests/issue-18.php
rename to scripts/emacs/php-mode-1.13.2/tests/issue-18.php
index ec89cdd52e40031b0098a8622bcb557409e32022..d59e8455ce38ecff4533441e65d09e9370a5c87c 100644
--- a/scripts/emacs/php-mode-1.10/tests/issue-18.php
+++ b/scripts/emacs/php-mode-1.13.2/tests/issue-18.php
@@ -19,5 +19,5 @@
 $a = 'github';
 
 if ($a === 'github') {
-    header('Location: http://github.com');
+    header('Location: http://github.com'); // ###php-mode-test### ((indent c-basic-offset))
 }
\ No newline at end of file
diff --git a/scripts/emacs/php-mode-1.10/tests/issue-19.php b/scripts/emacs/php-mode-1.13.2/tests/issue-19.php
similarity index 100%
rename from scripts/emacs/php-mode-1.10/tests/issue-19.php
rename to scripts/emacs/php-mode-1.13.2/tests/issue-19.php
diff --git a/scripts/emacs/php-mode-1.10/tests/issue-21.php b/scripts/emacs/php-mode-1.13.2/tests/issue-21.php
similarity index 100%
rename from scripts/emacs/php-mode-1.10/tests/issue-21.php
rename to scripts/emacs/php-mode-1.13.2/tests/issue-21.php
diff --git a/scripts/emacs/php-mode-1.10/tests/issue-22.php b/scripts/emacs/php-mode-1.13.2/tests/issue-22.php
similarity index 100%
rename from scripts/emacs/php-mode-1.10/tests/issue-22.php
rename to scripts/emacs/php-mode-1.13.2/tests/issue-22.php
diff --git a/scripts/emacs/php-mode-1.10/tests/issue-27.php b/scripts/emacs/php-mode-1.13.2/tests/issue-27.php
similarity index 88%
rename from scripts/emacs/php-mode-1.10/tests/issue-27.php
rename to scripts/emacs/php-mode-1.13.2/tests/issue-27.php
index 9b917f4ed999692cc14e68213da0f76d89537985..25082e244ab53a36b8d54686261d001c580058aa 100644
--- a/scripts/emacs/php-mode-1.10/tests/issue-27.php
+++ b/scripts/emacs/php-mode-1.13.2/tests/issue-27.php
@@ -12,5 +12,5 @@
  */
 
 if (1 == 1) {
-    // Tab
+    // Tab ###php-mode-test### ((indent c-basic-offset))
 }
diff --git a/scripts/emacs/php-mode-1.10/tests/issue-28.php b/scripts/emacs/php-mode-1.13.2/tests/issue-28.php
similarity index 100%
rename from scripts/emacs/php-mode-1.10/tests/issue-28.php
rename to scripts/emacs/php-mode-1.13.2/tests/issue-28.php
diff --git a/scripts/emacs/php-mode-1.10/tests/issue-29.php b/scripts/emacs/php-mode-1.13.2/tests/issue-29.php
similarity index 63%
rename from scripts/emacs/php-mode-1.10/tests/issue-29.php
rename to scripts/emacs/php-mode-1.13.2/tests/issue-29.php
index 81db3837aa7836ab7bb44eb09a619923ca8e0e2d..9b9174eff317ebb9dc791352e646a3bf0e7f56dc 100644
--- a/scripts/emacs/php-mode-1.10/tests/issue-29.php
+++ b/scripts/emacs/php-mode-1.13.2/tests/issue-29.php
@@ -12,5 +12,5 @@
  */
 
 $app->get("/index", function() {
-    $app->redirect("foo");
-});
+    $app->redirect("foo"); // ###php-mode-test### ((indent c-basic-offset))
+});                        // ###php-mode-test### ((indent 0))
diff --git a/scripts/emacs/php-mode-1.10/tests/issue-42.php b/scripts/emacs/php-mode-1.13.2/tests/issue-42.php
similarity index 100%
rename from scripts/emacs/php-mode-1.10/tests/issue-42.php
rename to scripts/emacs/php-mode-1.13.2/tests/issue-42.php
diff --git a/scripts/emacs/php-mode-1.13.2/tests/issue-53.php b/scripts/emacs/php-mode-1.13.2/tests/issue-53.php
new file mode 100644
index 0000000000000000000000000000000000000000..d5ff295691c3aad75efc09d9b139fffc6b7da7ca
--- /dev/null
+++ b/scripts/emacs/php-mode-1.13.2/tests/issue-53.php
@@ -0,0 +1,30 @@
+<?php
+
+/**
+ * GitHub Issue:    https://github.com/ejmr/php-mode/issues/53
+ *
+ * Test if switching from Drupal coding style to other coding styles updates
+ * the whitespace effects.
+ *
+ * This file contains arbitrary PHP code with some whitespace added to the end
+ * of some lines.
+ *
+ */
+
+class Foo {
+
+    private $bar;
+
+    public function __construct($bar) {
+        $this->bar = $bar;
+    }
+
+    public function getBar() {
+        // here is the whitespace
+        return $this->bar;    
+    }
+
+}
+
+$foo = new Foo('bar');
+$bar = $foo->getBar();
diff --git a/scripts/emacs/php-mode-1.13.2/tests/issue-68.php b/scripts/emacs/php-mode-1.13.2/tests/issue-68.php
new file mode 100644
index 0000000000000000000000000000000000000000..a152ab31771321d410c89358be0642abb2239585
--- /dev/null
+++ b/scripts/emacs/php-mode-1.13.2/tests/issue-68.php
@@ -0,0 +1,57 @@
+<?php
+
+/**
+ * GitHub Issue:    https://github.com/ejmr/php-mode/issues/68
+ *
+ * The 'catch' keywords should align with 'try' and not march
+ * off to the right side of the screen like they do in the bug
+ * report at the URL above.
+ *
+ */
+
+/* CC Mode uses the indentation for 'block-close' for these 'catch'
+ * statements.  However, that is assuming that the closing braces for
+ * 'try' and each 'catch' align with the keywords themselves.  If they
+ * do not then CC Mode gets confused and starts trying to indent
+ * 'catch' blocks as if they were function definitions and other
+ * strange things.
+ *
+ * The easiest way to deal with this is to make sure that the
+ * `c-block-stmt-2-key' list contains the string "catch", which we
+ * take care of in the definition of `php-block-stmt-2-key'.
+ */
+
+try {
+        $mongo = new \Mongo($dsn, array("replicaSet" => 'mat_replica'));
+} catch (\MongoConnectionException $e) {
+        throw $e;
+} catch (\Exception $e) {
+        throw $e;
+}
+
+/* CC Mode uses the indentation syntax for 'topmost-intro' for the
+ * 'catch' keywords in the remaining tests.
+ */
+
+try {
+        $mongo = new \Mongo($dsn, array("replicaSet" => 'mat_replica'));
+}
+catch (\MongoConnectionException $e) {
+        throw $e;
+}
+catch (\Exception $e) {
+        throw $e;
+}
+
+try
+{
+        $mongo = new \Mongo($dsn, array("replicaSet" => 'mat_replica'));
+}
+catch (\MongoConnectionException $e)
+{
+        throw $e;
+}
+catch (\Exception $e)
+{
+        throw $e;
+}
diff --git a/scripts/emacs/php-mode-1.13.2/tests/issue-73.php b/scripts/emacs/php-mode-1.13.2/tests/issue-73.php
new file mode 100644
index 0000000000000000000000000000000000000000..87476ef58e327bb696e742d751fd10b392280e43
--- /dev/null
+++ b/scripts/emacs/php-mode-1.13.2/tests/issue-73.php
@@ -0,0 +1,31 @@
+<?php
+
+/**
+ * Github Issue:    https://github.com/ejmr/php-mode/issues/73
+ *
+ * The `delete-indentation' function should work properly for PHP.
+ * This means modifying the logic of `fixup-whitespace' so that it
+ * eliminates spaces before ',', ';', '->' amd '::' and after '->' and
+ * '::'.
+ */
+
+# Correct
+TEST::di->set('config', function () use ($config);
+
+# Test
+TEST
+::
+di->set('config', function () use ($config);
+
+# Test
+TEST::di
+->
+set('config', function () use ($config);
+
+# Test
+TEST::di->set('config'
+, function () use ($config);
+
+# Test
+TEST::di->set('config', function () use ($config)
+;
diff --git a/scripts/emacs/php-mode-1.10/tests/issue-8.php b/scripts/emacs/php-mode-1.13.2/tests/issue-8.php
similarity index 100%
rename from scripts/emacs/php-mode-1.10/tests/issue-8.php
rename to scripts/emacs/php-mode-1.13.2/tests/issue-8.php
diff --git a/scripts/emacs/php-mode-1.10/tests/issue-9.php b/scripts/emacs/php-mode-1.13.2/tests/issue-9.php
similarity index 100%
rename from scripts/emacs/php-mode-1.10/tests/issue-9.php
rename to scripts/emacs/php-mode-1.13.2/tests/issue-9.php
diff --git a/scripts/emacs/php-mode-1.13.2/tests/issue-99.php b/scripts/emacs/php-mode-1.13.2/tests/issue-99.php
new file mode 100644
index 0000000000000000000000000000000000000000..8492759006a7b52a5f477b7a7f30609fb9d748ea
--- /dev/null
+++ b/scripts/emacs/php-mode-1.13.2/tests/issue-99.php
@@ -0,0 +1,15 @@
+<?php
+
+/**
+ * Github Issue:    https://github.com/ejmr/php-mode/issues/99
+ *
+ * The code below contains a 'foreach' without any braces.  We use CC
+ * Mode to customize indentation and it treats continued differently
+ * depending on whether or not they end with a brace.  This test is to
+ * ensure that PHP Mode properly indents 'foreach' statements without
+ * any braces.
+ *
+ */
+
+foreach ($x as $s)
+        echo $s; // ###php-mode-test### ((indent c-basic-offset))
\ No newline at end of file
diff --git a/scripts/emacs/php-mode-1.13.2/tests/template.php b/scripts/emacs/php-mode-1.13.2/tests/template.php
new file mode 100644
index 0000000000000000000000000000000000000000..cc454d2a346c144970e4908924d947620ee03b73
--- /dev/null
+++ b/scripts/emacs/php-mode-1.13.2/tests/template.php
@@ -0,0 +1,12 @@
+<?php
+
+/**
+ * GitHub Issue:    https://github.com/ejmr/php-mode/issues/NNN
+ *
+ * ---------------------------------------------------------------------- 
+ * Add the correct issue number to the URL above, replacing the 'NNN',
+ * and then replace this with a description of the test and its
+ * purpose, using the existing tests as examples.
+ * ----------------------------------------------------------------------
+ * 
+ */
diff --git a/scripts/emacs/web-mode-master/.gitignore b/scripts/emacs/web-mode-master/.gitignore
index 658d5173d19839d3c8b3850f466d53c5bf1a7a7f..9f8e806caf52eb3d7bf7c0051d90f80773de50ca 100644
--- a/scripts/emacs/web-mode-master/.gitignore
+++ b/scripts/emacs/web-mode-master/.gitignore
@@ -1,3 +1,4 @@
 *~
 \#*\#
-*.elc
\ No newline at end of file
+*.elc
+/.cask
diff --git a/scripts/emacs/web-mode-master/README.md b/scripts/emacs/web-mode-master/README.md
index 96993216fed20bb4a21b11dc892ad965d7845c07..9e592da4e1514f40ec25551980c09a8a9b865776 100644
--- a/scripts/emacs/web-mode-master/README.md
+++ b/scripts/emacs/web-mode-master/README.md
@@ -1,18 +1,10 @@
 web-mode.el  [![Flattr this git repo](http://api.flattr.com/button/flattr-badge-large.png)](https://flattr.com/thing/1849746/web-mode-el)
 =========
 
-web-mode.el is an emacs major mode for editing **web templates** aka HTML files embedding client parts (CSS/JavaScript) and server blocks.
+web-mode.el is an emacs major mode for editing **web templates** aka HTML files embedding parts (CSS/JavaScript) and blocks (pre rendered by client/server side engines).
 
-web-mode.el is compatible with many template engines: PHP, JSP, ASP, Django, Twig, Jinja(2), ERB, FreeMarker, Velocity, Cheetah, Smarty, CTemplate, Mustache, Blade, ErlyDTL, Go Template, Dust.js, Google Closure (soy),  etc.
+web-mode.el is compatible with many template engines: PHP, JSP, ASP, Django, Twig, Jinja(2), ERB, FreeMarker, Velocity, Cheetah, Smarty, CTemplate, Mustache, Blade, ErlyDTL, Go Template, Dust.js, Google Closure (soy), JSX, etc.
 
 More infos on http://web-mode.org/
 
 ![ScreenShot](http://web-mode.org/web-mode.png?v=2)
-
-=========
-
- [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/fxbois/web-mode/trend.png)](https://bitdeli.com/free "Bitdeli Badge")
-
-
-
-
diff --git a/scripts/emacs/web-mode-master/test/.travis.yml b/scripts/emacs/web-mode-master/test/.travis.yml
new file mode 100644
index 0000000000000000000000000000000000000000..ded215aaf6c271875576227117064e629a407a29
--- /dev/null
+++ b/scripts/emacs/web-mode-master/test/.travis.yml
@@ -0,0 +1,15 @@
+language: emacs-lisp
+before_install:
+  - curl -fsSkL https://gist.github.com/rejeep/7736123/raw | sh
+  - export PATH="/home/travis/.cask/bin:$PATH"
+  - export PATH="/home/travis/.evm/bin:$PATH"
+  - evm install $EVM_EMACS --use
+  - cask
+env:
+  - EVM_EMACS=emacs-23.4-bin
+  - EVM_EMACS=emacs-24.1-bin
+  - EVM_EMACS=emacs-24.2-bin
+  - EVM_EMACS=emacs-24.3-bin
+script:
+  - emacs --version
+  - make test
diff --git a/scripts/emacs/web-mode-master/test/Cask b/scripts/emacs/web-mode-master/test/Cask
new file mode 100644
index 0000000000000000000000000000000000000000..5c87431a81d17f495cbe3baa5c222c2593d8f07a
--- /dev/null
+++ b/scripts/emacs/web-mode-master/test/Cask
@@ -0,0 +1,10 @@
+(source gnu)
+(source melpa)
+
+(package-file "web-mode.el")
+
+(development
+ (depends-on "f")
+ (depends-on "ecukes")
+ (depends-on "ert-runner")
+ (depends-on "el-mock"))
diff --git a/scripts/emacs/web-mode-master/test/Makefile b/scripts/emacs/web-mode-master/test/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..9fe1144c5303804266e2a4ef4dbbb97f7fe58c20
--- /dev/null
+++ b/scripts/emacs/web-mode-master/test/Makefile
@@ -0,0 +1,21 @@
+CASK ?= cask
+EMACS ?= emacs
+
+all: test
+
+test: clean-elc
+	${MAKE} unit
+	${MAKE} compile
+	${MAKE} unit
+	${MAKE} clean-elc
+
+unit:
+	${CASK} exec ert-runner
+
+compile:
+	${CASK} exec ${EMACS} -Q -batch -f batch-byte-compile web-mode.el
+
+clean-elc:
+	rm -f web-mode.elc
+
+.PHONY:	all test unit
diff --git a/scripts/emacs/web-mode-master/test/README.md b/scripts/emacs/web-mode-master/test/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..069a319e8afa521306499074c351e8c9cb977b28
--- /dev/null
+++ b/scripts/emacs/web-mode-master/test/README.md
@@ -0,0 +1,19 @@
+## Contribution
+
+Install [Cask](https://github.com/cask/cask) if you haven't already,
+then:
+
+    $ cd /path/to/web-mode.el
+    $ cask
+
+Run the unit tests with:
+
+    $ make unit
+
+The integration tests with:
+
+    $ make ecukes
+
+And all tests with:
+
+    $ make
diff --git a/scripts/emacs/web-mode-master/test/features/step-definitions/web-mode-steps.el b/scripts/emacs/web-mode-master/test/features/step-definitions/web-mode-steps.el
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/scripts/emacs/web-mode-master/test/features/support/env.el b/scripts/emacs/web-mode-master/test/features/support/env.el
new file mode 100644
index 0000000000000000000000000000000000000000..e03e4fff14f446ecd4c1c043534fd0a5821e1418
--- /dev/null
+++ b/scripts/emacs/web-mode-master/test/features/support/env.el
@@ -0,0 +1,27 @@
+(require 'f)
+
+(defconst web-mode-test/support-path
+  (f-dirname load-file-name))
+
+(defconst web-mode-test/features-path
+  (f-parent web-mode-test/support-path))
+
+(defconst web-mode-test/root-path
+  (f-parent web-mode-test/features-path))
+
+(defconst web-mode-test/buffer "*web-mode*")
+
+(add-to-list 'load-path web-mode-test/root-path)
+
+(require 'web-mode)
+(require 'espuds)
+(require 'ert)
+
+(Setup
+ (setq-default indent-tabs-mode nil))
+
+(Before
+ (when (buffer-live-p web-mode-test/buffer)
+   (kill-buffer web-mode-test/buffer))
+ (switch-to-buffer
+  (get-buffer-create web-mode-test/buffer)))
diff --git a/scripts/emacs/web-mode-master/test/features/tags.feature b/scripts/emacs/web-mode-master/test/features/tags.feature
new file mode 100644
index 0000000000000000000000000000000000000000..8eeb7570477c8e306fa5cdd972ec7331bd014ebf
--- /dev/null
+++ b/scripts/emacs/web-mode-master/test/features/tags.feature
@@ -0,0 +1,12 @@
+Feature: Tags
+
+  Background:
+    Given I turn on web-mode
+
+  Scenario: Automatically close tag
+    Given I type "<script>"
+    When I press "<"
+    And I press "/"
+    When I debug
+    Then I should see "<script></script>"
+    And the cursor should be between "<script>" and "</script>"
diff --git a/scripts/emacs/web-mode-master/test/features/web-mode.feature b/scripts/emacs/web-mode-master/test/features/web-mode.feature
new file mode 100644
index 0000000000000000000000000000000000000000..cf0718cc1ba80a3552f0ec3c967fbc279f1cd0d7
--- /dev/null
+++ b/scripts/emacs/web-mode-master/test/features/web-mode.feature
@@ -0,0 +1 @@
+Feature: Web mode
diff --git a/scripts/emacs/web-mode-master/test/test-helper.el b/scripts/emacs/web-mode-master/test/test-helper.el
new file mode 100644
index 0000000000000000000000000000000000000000..0b187074df5785c0a40073e2f9b209069ed2cf84
--- /dev/null
+++ b/scripts/emacs/web-mode-master/test/test-helper.el
@@ -0,0 +1,9 @@
+(require 'f)
+
+(defconst web-mode-test/test-path
+  (f-parent (f-this-file)))
+
+(defconst web-mode-test/root-path
+  (f-parent web-mode-test/test-path))
+
+(require 'web-mode (f-expand "web-mode" web-mode-test/root-path))
diff --git a/scripts/emacs/web-mode-master/test/web-mode-test.el b/scripts/emacs/web-mode-master/test/web-mode-test.el
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/scripts/emacs/web-mode-master/web-mode.el b/scripts/emacs/web-mode-master/web-mode.el
index d02eba60ec3fd6920e87b8c80305ece0fda87903..03081b3937e723e10f13171d96c23717f4273ea2 100644
--- a/scripts/emacs/web-mode-master/web-mode.el
+++ b/scripts/emacs/web-mode-master/web-mode.el
@@ -1,9 +1,9 @@
 ;;; web-mode.el --- major mode for editing html templates
 ;;; -*- coding: utf-8 -*-
 
-;; Copyright 2011-2013 François-Xavier Bois
+;; Copyright 2011-2014 François-Xavier Bois
 
-;; Version: 7.0.74
+;; Version: 9.0.28
 ;; Author: François-Xavier Bois <fxbois AT Google Mail Service>
 ;; Maintainer: François-Xavier Bois
 ;; Created: July 2011
@@ -36,20 +36,28 @@
 
 ;; Code goes here
 
+;;todo :
+;;       web-mode-part|block-extra-keywords
+;;       web-mode-surround : chaque ligne est entourée par un open et un close tag
+;;       tester web-mode avec un fond blanc
+;;       web-mode-extra-constants
+;;       web-mode-extra-keywords + engines + javascript + comment
+;;       phphint
+
+;;todo : Stickiness of Text Properties
+;;todo : web-mode-engine-real-name (canonical name)
+;;todo : finir filling
 ;;todo : screenshot : http://www.cockos.com/licecap/
-;;todo : better default colors for tags & attrs
 ;;todo : passer les content-types en symboles
 ;;todo : tester shortcut A -> pour pomme
-;;todo : commentaire d'une ligne ruby ou d'une ligne asp
-;;todo : créer tag-token pour différentier de part-token : tag-token=attr,comment ???
 
-(defconst web-mode-version "7.0.74"
+(defconst web-mode-version "9.0.28"
   "Web Mode version.")
 
 (defgroup web-mode nil
   "Major mode for editing web templates:
-   HTML files embedding parts (CSS/JavaScript)
-   and blocks (PHP, Erb, Django/Twig, Smarty, JSP, ASP, etc.)"
+   html files embedding parts (css/javascript)
+   and blocks (php, erb, django/twig, smarty, jsp, asp, etc.)"
   :group 'languages
   :prefix "web-"
   :link '(url-link :tag "Site" "http://web-mode.org")
@@ -90,23 +98,43 @@
   :type 'integer
   :group 'web-mode)
 
-(defcustom web-mode-disable-css-colorization (not (display-graphic-p))
-  "In a CSS block, do not set background according to the color: #xxx, rgb(x,x,x)."
+(defcustom web-mode-enable-css-colorization (display-graphic-p)
+  "In a CSS part, set background according to the color: #xxx, rgb(x,x,x)."
   :type 'boolean
   :group 'web-mode)
 
-(defcustom web-mode-disable-auto-indentation (not (display-graphic-p))
-  "Disable auto-indentation."
+(defcustom web-mode-enable-auto-indentation (display-graphic-p)
+  "Auto-indentation."
   :type 'boolean
   :group 'web-mode)
 
-(defcustom web-mode-disable-auto-pairing (not (display-graphic-p))
-  "Disable auto-pairing."
+(defcustom web-mode-enable-auto-pairing (display-graphic-p)
+  "Auto-pairing."
   :type 'boolean
   :group 'web-mode)
 
-(defcustom web-mode-disable-auto-opening (not (display-graphic-p))
-  "Disable html element auto-opening."
+(defcustom web-mode-enable-auto-opening (display-graphic-p)
+  "Html element auto-opening."
+  :type 'boolean
+  :group 'web-mode)
+
+(defcustom web-mode-enable-indent-cycle nil
+  "Disable cycle indent."
+  :type 'boolean
+  :group 'web-mode)
+
+(defcustom web-mode-enable-block-partial-invalidation t
+  "Partial invalidation in blocks (php and asp at the moment)."
+  :type 'boolean
+  :group 'web-mode)
+
+(defcustom web-mode-enable-part-partial-invalidation t
+  "Partial invalidation in js/css parts."
+  :type 'boolean
+  :group 'web-mode)
+
+(defcustom web-mode-indent-cycle-left-first nil
+  "Indent from left to right instead of starting at rightmost match."
   :type 'boolean
   :group 'web-mode)
 
@@ -132,7 +160,17 @@ See web-mode-part-face."
   :type 'boolean
   :group 'web-mode)
 
-(defcustom web-mode-enable-heredoc-fontification nil
+(defcustom web-mode-enable-inlays nil
+  "Enable inlays (e.g. LaTeX) highlighting."
+  :type 'boolean
+  :group 'web-mode)
+
+(defcustom web-mode-enable-string-interpolation t
+  "Enable string interpolation fontification (php and erb)."
+  :type 'boolean
+  :group 'web-mode)
+
+(defcustom web-mode-enable-heredoc-fontification t
   "Enable heredoc fontification. The identifier should contain JS, JAVASCRIPT or HTML."
   :type 'boolean
   :group 'web-mode)
@@ -144,16 +182,17 @@ See web-mode-part-face."
 
 (defcustom web-mode-comment-style 1
   "Comment style : 1 = default, 2 = force server comments outside a block."
-  :type 'integer
-  :group 'web-mode)
+  :group 'web-mode
+  :type '(choice (const :tag "default" 1)
+                 (const :tag "force engine comments" 2)))
 
 (defcustom web-mode-indent-style 2
-  "Indentation style.
-with value 2, HTML lines beginning text are also indented (do not forget side effects, e.g. content of a textarea)."
-  :type 'integer
-  :group 'web-mode)
+  "Indentation style."
+  :group 'web-mode
+  :type '(choice (const :tag "default (all lines are indented)" 2)
+                 (const :tag "text at the beginning of line is not indented" 1)))
 
-(defcustom web-mode-tag-auto-close-style 1
+(defcustom web-mode-tag-auto-close-style (if (display-graphic-p) 1 0)
   "Tag auto-close style:
 0=no auto-closing
 1=auto-close with </
@@ -161,15 +200,20 @@ with value 2, HTML lines beginning text are also indented (do not forget side ef
   :type 'integer
   :group 'web-mode)
 
-;; (defcustom web-mode-extra-snippets '()
-;;   "A list of snippets."
-;;   :type 'list
-;;   :group 'web-mode)
+(defcustom web-mode-extra-auto-pairs '()
+  "A list of additional snippets."
+  :type 'list
+  :group 'web-mode)
+
+(defcustom web-mode-extra-snippets '()
+  "A list of additional snippets."
+  :type 'list
+  :group 'web-mode)
 
-;; (defcustom web-mode-extra-auto-pairs '()
-;;   "A list of auto-pairs."
-;;   :type 'list
-;;   :group 'web-mode)
+(defcustom web-mode-extra-python-constants '()
+  "A list of additional strings to treat as Python constants."
+  :type 'list
+  :group 'web-mode)
 
 (defcustom web-mode-extra-php-constants '()
   "A list of additional strings to treat as PHP constants."
@@ -196,6 +240,11 @@ with value 2, HTML lines beginning text are also indented (do not forget side ef
   :type 'list
   :group 'web-mode)
 
+(defcustom web-mode-extra-mason-keywords '()
+  "A list of additional strings to treat as Mason keywords."
+  :type 'list
+  :group 'web-mode)
+
 (defcustom web-mode-extra-asp-constants '()
   "A list of additional strings to treat as ASP constants."
   :type 'list
@@ -231,6 +280,11 @@ with value 2, HTML lines beginning text are also indented (do not forget side ef
   :type 'list
   :group 'web-mode)
 
+(defface web-mode-error-face
+  '((t :background "red"))
+  "Face for warning."
+  :group 'web-mode-faces)
+
 (defface web-mode-warning-face
   '((t :inherit font-lock-warning-face))
   "Face for warning."
@@ -241,6 +295,11 @@ with value 2, HTML lines beginning text are also indented (do not forget side ef
   "Face for preprocessor."
   :group 'web-mode-faces)
 
+(defface web-mode-block-delimiter-face
+  '((t :inherit font-lock-preprocessor-face))
+  "Face for block delimiters."
+  :group 'web-mode-faces)
+
 (defface web-mode-block-control-face
   '((t :inherit font-lock-preprocessor-face))
   "Face for preprocessor."
@@ -262,20 +321,13 @@ with value 2, HTML lines beginning text are also indented (do not forget side ef
   :group 'web-mode-faces)
 
 (defface web-mode-html-tag-face
-  '((((class color) (min-colors 88) (background dark))
-     :foreground "Snow4")
-    (((class color) (min-colors 88) (background light))
-     :foreground "grey15")
-    (((class color) (min-colors 16) (background dark))
-     :foreground "Snow4")
-    (((class color) (min-colors 16) (background light))
-     :foreground "grey15")
-    (((class color) (min-colors 8))
-     :foreground "Snow4")
-    (((type tty) (class mono))
-     :inverse-video t)
-    (t
-     :foreground "Snow4"))
+  '((((class color) (min-colors 88) (background dark)) :foreground "Snow4")
+    (((class color) (min-colors 88) (background light)) :foreground "grey15")
+    (((class color) (min-colors 16) (background dark)) :foreground "Snow4")
+    (((class color) (min-colors 16) (background light)) :foreground "grey15")
+    (((class color) (min-colors 8)) :foreground "Snow4")
+    (((type tty) (class mono)) :inverse-video t)
+    (t :foreground "Snow4"))
   "Face for HTML tags."
   :group 'web-mode-faces)
 
@@ -285,25 +337,25 @@ with value 2, HTML lines beginning text are also indented (do not forget side ef
   :group 'web-mode-faces)
 
 (defface web-mode-html-tag-bracket-face
-  '((t :inherit web-mode-html-tag-face))
+;;  '((t :inherit web-mode-html-tag-face))
+  '((((class color) (min-colors 88) (background dark)) :foreground "Snow3")
+    (((class color) (min-colors 88) (background light)) :foreground "grey14")
+    (((class color) (min-colors 16) (background dark)) :foreground "Snow3")
+    (((class color) (min-colors 16) (background light)) :foreground "grey14")
+    (((class color) (min-colors 8)) :foreground "Snow3")
+    (((type tty) (class mono)) :inverse-video t)
+    (t :foreground "Snow3"))
   "Face for HTML tags angle brackets (< and >)."
   :group 'web-mode-faces)
 
 (defface web-mode-html-attr-name-face
-  '((((class color) (min-colors 88) (background dark))
-     :foreground "Snow3")
-    (((class color) (min-colors 88) (background light))
-     :foreground "grey13")
-    (((class color) (min-colors 16) (background dark))
-     :foreground "Snow3")
-    (((class color) (min-colors 16) (background light))
-     :foreground "grey13")
-    (((class color) (min-colors 8))
-     :foreground "Snow3")
-    (((type tty) (class mono))
-     :inverse-video t)
-    (t
-     :foreground "Snow4"))
+  '((((class color) (min-colors 88) (background dark)) :foreground "Snow3")
+    (((class color) (min-colors 88) (background light)) :foreground "grey13")
+    (((class color) (min-colors 16) (background dark)) :foreground "Snow3")
+    (((class color) (min-colors 16) (background light)) :foreground "grey13")
+    (((class color) (min-colors 8)) :foreground "Snow3")
+    (((type tty) (class mono)) :inverse-video t)
+    (t :foreground "Snow4"))
   "Face for HTML attribute names."
   :group 'web-mode-faces)
 
@@ -312,6 +364,11 @@ with value 2, HTML lines beginning text are also indented (do not forget side ef
   "Face for custom attribute names (e.g. data-*)."
   :group 'web-mode-faces)
 
+(defface web-mode-html-attr-engine-face
+  '((t :inherit web-mode-html-attr-custom-face))
+  "Face for custom engine attribute names (e.g. ng-*)."
+  :group 'web-mode-faces)
+
 (defface web-mode-html-attr-equal-face
   '((t :inherit web-mode-html-attr-name-face))
   "Face for the = character between name and value."
@@ -323,7 +380,7 @@ with value 2, HTML lines beginning text are also indented (do not forget side ef
   :group 'web-mode-faces)
 
 (defface web-mode-block-attr-name-face
-  '((t :inherit web-mode-html-attr-name-face))
+  '((t :foreground "#8fbc8f")) ;; inherit web-mode-html-attr-name-face))
   "Face for block attribute names."
   :group 'web-mode-faces)
 
@@ -332,6 +389,11 @@ with value 2, HTML lines beginning text are also indented (do not forget side ef
   "Face for block attribute values."
   :group 'web-mode-faces)
 
+(defface web-mode-variable-name-face
+  '((t :inherit font-lock-variable-name-face))
+  "Face for variable names."
+  :group 'web-mode-faces)
+
 (defface web-mode-css-selector-face
   '((t :inherit font-lock-keyword-face))
   "Face for CSS rules."
@@ -367,9 +429,9 @@ with value 2, HTML lines beginning text are also indented (do not forget side ef
   "Face for CSS functions."
   :group 'web-mode-faces)
 
-(defface web-mode-variable-name-face
-  '((t :inherit font-lock-variable-name-face))
-  "Face for variable names."
+(defface web-mode-css-variable-face
+  '((t :inherit web-mode-variable-name-face :slant italic))
+  "Face for CSS vars."
   :group 'web-mode-faces)
 
 (defface web-mode-function-name-face
@@ -437,6 +499,21 @@ with value 2, HTML lines beginning text are also indented (do not forget side ef
   "Face for part comments."
   :group 'web-mode-faces)
 
+(defface web-mode-json-comment-face
+  '((t :inherit web-mode-comment-face))
+  "Face for json comments."
+  :group 'web-mode-faces)
+
+(defface web-mode-javascript-comment-face
+  '((t :inherit web-mode-comment-face))
+  "Face for javascript comments."
+  :group 'web-mode-faces)
+
+(defface web-mode-css-comment-face
+  '((t :inherit web-mode-comment-face))
+  "Face for css comments."
+  :group 'web-mode-faces)
+
 (defface web-mode-constant-face
   '((t :inherit font-lock-constant-face))
   "Face for language constants."
@@ -462,9 +539,26 @@ with value 2, HTML lines beginning text are also indented (do not forget side ef
   "Face for whitespaces."
   :group 'web-mode-faces)
 
+(defface web-mode-inlay-face
+  '((((class color) (min-colors 88) (background dark))
+     :background "black")
+    (((class color) (min-colors 88) (background light))
+     :background "LightYellow1")
+    (((class color) (min-colors 16) (background dark))
+     :background "grey18")
+    (((class color) (min-colors 16) (background light))
+     :background "LightYellow1")
+    (((class color) (min-colors 8))
+     :background "Black")
+    (((type tty) (class mono))
+     :inverse-video t)
+    (t :background "grey"))
+  "Face for inlays. Must be used in conjunction with web-mode-enable-inlays."
+  :group 'web-mode-faces)
+
 (defface web-mode-block-face
   '((((class color) (min-colors 88) (background dark))
-     :background "black") ;;""grey18")
+     :background "black")
     (((class color) (min-colors 88) (background light))
      :background "LightYellow1")
     (((class color) (min-colors 16) (background dark))
@@ -500,27 +594,33 @@ Must be used in conjunction with web-mode-enable-block-face."
   "Comment keywords."
   :group 'web-mode-faces)
 
-(defvar web-mode-void-elements
-  '("area" "base" "br" "col" "command" "embed" "hr" "img" "input" "keygen"
-    "link" "meta" "param" "source" "track" "wbr")
-  "Void (self-closing) tags.")
+(defvar font-lock-beg)
+(defvar font-lock-end)
+
+(defvar web-mode-inlay-regexp nil
+  "")
 
-(defvar web-mode-text-properties
-  '(part-side nil part-token nil part-language nil tag-name nil tag-type nil tag-beg nil tag-end nil block-side nil block-token nil block-beg nil block-end nil face nil)
-  "Text properties used for fontification and indentation.")
+(defvar web-mode-highlight-beg nil
+  "")
 
-(defvar web-mode-text-properties2
-  '(part-side nil part-token nil part-language nil tag-name nil tag-type nil tag-beg nil tag-end nil face nil)
-  "Text properties used for fontification and indentation.")
+(defvar web-mode-highlight-end nil
+  "")
 
-(defvar web-mode-large-embed-threshold 512
-  "Threshold for large part/block.")
+(defvar web-mode-cache '()
+  "Cache computed values.")
 
-(defvar web-mode-has-any-large-part nil
-  "Does the current buffer has large parts ?")
+(defvar web-mode-void-elements
+  '("area" "base" "br" "col" "command" "embed" "hr" "img" "input" "keygen"
+    "link" "meta" "param" "source" "track" "wbr")
+  "Void (self-closing) tags.")
 
-(defvar web-mode-has-any-large-block nil
-  "Does the current buffer has large blocks ?")
+(defvar web-mode-scan-properties
+  (list 'tag-beg nil 'tag-end nil 'tag-name nil 'tag-type nil 'tag-attr nil 'tag-attr-end nil
+        'part-side nil 'part-token nil 'part-expr nil
+        'block-side nil 'block-token nil 'block-controls nil 'block-beg nil 'block-end nil
+        'syntax-table)
+;;        'comment nil
+  "Text properties used for tokens.")
 
 (defvar web-mode-is-scratch nil
   "Is scratch buffer ?")
@@ -548,40 +648,90 @@ Must be used in conjunction with web-mode-enable-block-face."
   "^[ \t]\\{2,\\}$\\| \t\\|\t \\|[ \t]+$\\|^[ \n\t]+\\'\\|^[ \t]?[\n]\\{2,\\}"
   "Regular expression for whitespaces.")
 
+(defvar web-mode-imenu-regexp-list
+  '(("<\\(h[1-9]\\)\\([^>]*\\)>\\([^<]*\\)" 1 3 ">")
+    ("^[ \t]*<\\([@a-z]+\\)[^>]*>? *$" 1 "id=\"\\([a-zA-Z0-9_]+\\)\"" "#" ">")
+    )
+  "List of regular expressions to match imenu items.
+Each element of list could be either of two data types,
+
+1. data type one: (regex index-to-extract-type index-to-extract-content concat-string)
+
+1.1. regex => regular express to match the line contain the full tag from each line
+
+1.2. index-to-extract-type => index to extract the tag type, for example, 1 means thing
+between the *first* '\\(' '\\)' pair in above regex, the extracted string could be 'div' or 'span' ...
+
+1.3. index-to-extract-content => index to extract to tag content, for example, 3 means the
+thing between  *third* '\\(' '\\)' pair in above regex.
+
+1.4. concat-string => the string to concat the type and content
+
+2. data type two: (regex index-to-extract-type another-regex-extract-content concat-string end-tag-regex)
+Please note this one support multi-line tag.
+
+2.1. regex => regular express to match the line contain the beginning of the tag from each line
+
+2.2. index-to-extract-type => index to extract the tag type, for example, 1 means thing
+between the *first* '\\(' '\\)' pair in above regex, the extracted string could be 'div' or 'span' ...
+
+2.3. another-regex-extract-content => regex to extract tag content
+The *first* thing between '\\(' '\\)' will be extracted as tag content
+
+2.4. concat-string => the string to concat the type and content
+
+2.5. end-tag-regex => the regex to match the end of a tag
+")
+
 (defvar web-mode-engine nil
   "Template engine")
 
+(defvar web-mode-engine-font-lock-keywords nil
+  "Font-lock keywords associated with the engine.")
+
 (defvar web-mode-engines
-  '(("angular"    . ("angular.js" "angularjs"))
-    ("asp"        . ())
-    ("aspx"       . ())
-    ("blade"      . ("laravel"))
-    ("closure"    . ("soy"))
-    ("ctemplate"  . ("mustache" "handlebars" "hapax" "ngtemplate" "ember"
-                     "kite" "meteor"))
-    ("django"     . ("dtl" "twig" "swig" "jinja" "jinja2" "erlydtl" "liquid"))
-    ("dust"       . ("dustjs"))
-    ("erb"        . ("eruby" "erubis"))
-    ("go"         . ("gtl"))
-    ("jsp"        . ())
-    ("python"     . ())
-    ("razor"      . ("play" "play2"))
-    ("underscore" . ("underscorejs"))
-    ("velocity"   . ("vtl" "cheetah")))
+  '(("angular"     . ("angular.js" "angularjs"))
+    ("asp"         . ())
+    ("aspx"        . ())
+    ("blade"       . ("laravel"))
+    ("closure"     . ("soy"))
+    ("ctemplate"   . ("mustache" "handlebars" "hapax" "ngtemplate" "ember" "kite" "meteor" "blaze"))
+    ("django"      . ("dtl" "twig" "swig" "jinja" "jinja2" "erlydtl" "liquid"))
+    ("dust"        . ("dustjs"))
+    ("erb"         . ("eruby" "erubis"))
+    ("go"          . ("gtl"))
+    ("jsp"         . ("grails"))
+    ("mason"       . ("poet"))
+    ("lsp"         . ())
+    ("mojolicious" . ())
+    ("python"      . ())
+    ("razor"       . ("play" "play2"))
+    ("underscore"  . ("underscorejs"))
+    ("velocity"    . ("vtl" "cheetah"))
+    ("web2py"      . ()))
   "Engine name aliases")
 
 (defvar web-mode-content-types
-  '(("css"        . "\\.css\\'")
-    ("javascript" . "\\.js\\'")
+  '(("css"        . "\\.css\\'\\|\\.css\\.erb\\'")
+    ("javascript" . "\\.js\\'\\|\\.js\\.erb\\'")
     ("json"       . "\\.\\(json\\|jsonld\\)\\'")
+    ("jsx"        . "\\.jsx\\'")
     ("html"       . "."))
   "content types")
 
+(defvar web-mode-engine-attr-regexp nil
+ "Engine custom attributes")
+
+(defvar web-mode-engine-attr-regexps
+  '(("angular" . "ng-"))
+  "Engine custom attributes")
+
 (defvar web-mode-engine-file-regexps
   '(("asp"              . "\\.asp\\'")
     ("aspx"             . "\\.as[cp]x\\'")
     ("angular"          . "angular")
     ("blade"            . "\\.blade")
+    ("blaze"            . "\\.blaze")
     ("closure"          . "\\.soy\\'")
     ("ctemplate"        . "\\.\\(chtml\\)\\'")
     ("django"           . "\\.\\(djhtml\\|tmpl\\|dtl\\|liquid\\)\\'")
@@ -591,15 +741,20 @@ Must be used in conjunction with web-mode-enable-block-face."
     ("freemarker"       . "\\.ftl\\'")
     ("go"               . "\\.go\\(html\\|tmpl\\)\\'")
     ("handlebars"       . "\\(handlebars\\|.\\hbs\\'\\)")
-    ("jsp"              . "\\.jsp\\'")
+    ("jsp"              . "\\.[gj]sp\\'")
+    ("lsp"              . "\\.lsp\\'")
+    ("mako"             . "\\.mako?\\'")
+    ("mason"            . "\\.mas\\'")
+    ("mojolicious"      . "mojolicious\\|\\.epl\\'")
     ("mustache"         . "\\.mustache\\'")
     ("php"              . "\\.\\(php\\|ctp\\|psp\\|inc\\)\\'")
     ("python"           . "\\.pml\\'")
-    ("razor"            . "play\\|scala\\|\\.razor\\'\\|\\.cshtml\\'\\|\\.vbhtml\\'")
+    ("razor"            . "scala\\|\\.razor\\'\\|\\.cshtml\\'\\|\\.vbhtml\\'")
     ("smarty"           . "\\.tpl\\'")
     ("template-toolkit" . "\\.tt.?\\'")
     ("underscore"       . "\\.underscore\\'")
-    ("velocity"         . "\\.\\(vsl\\|vtl\\|vm\\)\\'"))
+    ("velocity"         . "\\.\\(vsl\\|vtl\\|vm\\)\\'")
+    ("web2py"           . "web2py"))
   "Engine file extensions.")
 
 (defvar web-mode-smart-quotes
@@ -657,6 +812,40 @@ Must be used in conjunction with web-mode-enable-block-face."
     )
   "HTML entities")
 
+(defvar web-mode-engines-alternate-delimiters
+  (if (boundp 'web-mode-engines-alternate-delimiters) web-mode-engines-alternate-delimiters '())
+  "Engine delimiters. Useful for engines that provide alternate delimiters.")
+
+(defun web-mode-highlight-whitespaces (beg end)
+  "Scan whitespaces."
+  (save-excursion
+    (goto-char beg)
+    (while (re-search-forward web-mode-whitespaces-regexp end t)
+      (add-text-properties (match-beginning 0) (match-end 0)
+                           '(face web-mode-whitespace-face))
+      ) ;while
+    ))
+
+(defun web-mode-engine-delimiter-open (engine default)
+  "alternative open delimiter"
+  (let (delim)
+    (setq delim (car (cdr (assoc engine web-mode-engines-alternate-delimiters))))
+    (or delim default)
+  ))
+
+(defun web-mode-engine-delimiter-close (engine default)
+  "alternative close delimiter"
+  (let (delim)
+    (setq delim (cdr (cdr (assoc engine web-mode-engines-alternate-delimiters))))
+    (or delim default)
+    ))
+
+(defvar web-mode-jshint-errors 0
+  "JSHint errors")
+
+(defvar web-mode-change-flags 0
+  "Change flags")
+
 (defvar web-mode-content-type ""
   "Buffer file type.")
 
@@ -684,79 +873,15 @@ Must be used in conjunction with web-mode-enable-block-face."
 (defvar web-mode-hl-line-mode-flag nil
   "Is hl-line-mode enabled ?")
 
-(defvar web-mode-blade-active-blocks
-  '("else" "elseif" "foreach" "forelse" "for" "if" "section" "stop" "unless" "while")
-  "Blade controls.")
-
-(defvar web-mode-closure-active-blocks
-  '("call" "case" "default" "deltemplate" "else" "elseif" "for" "foreach"
-    "if" "ifempty" "let" "literal" "msg" "param" "switch" "template")
-  "Closure controls.")
-
-(defvar web-mode-django-active-blocks
-  '("assets" "autoescape" "block" "blocktrans" "cache" "call" "comment"
-    "elif" "else" "elseif" "elsif" "embed" "empty" "filter" "foreach" "for"
-    "ifchanged" "ifequal" "ifnotequal" "if"
-    "macro" "draw" "random" "sandbox" "spaceless" "verbatim" "with")
+(defvar web-mode-django-control-blocks
+  (regexp-opt
+   '("assets" "autoescape" "block" "blocktrans" "cache" "call" "comment"
+     "elif" "else" "elseif" "elsif" "embed" "empty" "filter" "foreach" "for"
+     "ifchanged" "ifequal" "ifnotequal" "if"
+     "macro" "draw" "random" "sandbox" "spaceless" "verbatim" "with")
+   t)
   "Django controls.")
 
-(defvar web-mode-go-active-blocks
-  '("else" "end" "if" "range" "with")
-  "Go controls.")
-
-(defvar web-mode-php-active-blocks
-  '("declare" "else" "elseif" "for" "foreach" "if" "while")
-  "PHP controls.")
-
-(defvar web-mode-smarty-active-blocks
-  '("block" "else" "elseif" "foreach" "for" "if" "section" "while")
-  "Smarty controls.")
-
-(defvar web-mode-velocity-active-blocks
-  '("define" "else" "elseif" "end" "for" "foreach" "if" "macro")
-  "Velocity controls.")
-
-(defvar web-mode-active-block-regexps
-  (list
-   (cons "asp"        "----")
-   (cons "aspx"       "----")
-   (cons "blade"      (concat "@\\(end\\)?" (regexp-opt web-mode-blade-active-blocks t)))
-   (cons "closure"    (concat "{/?" (regexp-opt web-mode-closure-active-blocks t)))
-   (cons "ctemplate"  "{{[#^/]\\([[:alnum:]_]+\\)")
-   (cons "django"     (concat "{%[-]?[ ]+\\(end\\)?" (regexp-opt web-mode-django-active-blocks t)))
-   (cons "dust"       "{[#/:?@><+^]\\([[:alpha:]_]+\\)")
-   (cons "erb"        "<%[-=]?[ ]+\\(.* do \\|for\\|unless\\|end\\|if\\|else\\)")
-   (cons "freemarker" "</?\\([[:alpha:]]+:[[:alpha:]]+\\)\\|[[<]/?[@#]\\([[:alpha:]]+\\)")
-   (cons "go"         (concat "{{[ ]*" (regexp-opt web-mode-go-active-blocks t)))
-   (cons "jsp"        "</?\\([[:alpha:]]+:[[:alpha:]]+\\)\\|<%[ ]*+\\(if\\|for\\|while\\|} else {\\)")
-   (cons "php"        (concat "<\\?\\(php[ ]+\\|[ ]*\\)?\\(end\\)?" (regexp-opt web-mode-php-active-blocks t)))
-   (cons "razor"      "@\\(main\\|if\\|for\\)")
-   (cons "smarty"     (concat "{/?" (regexp-opt web-mode-smarty-active-blocks t)))
-   (cons "template-toolkit" (concat "\\[% " (regexp-opt '("foreach" "if" "else" "elsif" "filter" "end") t)))
-   (cons "underscore" "<%")
-   (cons "velocity"   (concat "#" (regexp-opt web-mode-velocity-active-blocks t))))
-  "Engine control regexps")
-
-(defvar web-mode-close-block-regexps
-  '(("asp"              . "----")
-    ("aspx"             . "----")
-    ("blade"            . "@\\\(end\\|else\\|stop\\)")
-    ("closure"          . "{\\(/\\|else\\|case\\|default\\|ifempty\\)")
-    ("ctemplate"        . "{{/")
-    ("django"           . "{%[-]?[ ]+\\(end\\|else\\|elseif\\|elsif\\|elif\\|empty\\)")
-    ("dust"             . "{\\(/\\|:else\\)")
-    ("erb"              . "<%[-]?[ ]+\\(end\\|else\\)")
-    ("freemarker"       . "[<[]\\(/#\\|#els\\|#break\\)")
-    ("go"               . "{{[ ]*\\(end\\|else\\)")
-    ("jsp"              . "</\\|<% }")
-    ("php"              . "<\\?\\(php[ ]+\\|[ ]*\\)?\\(end\\|else\\|}\\)")
-    ("razor"            . "}")
-    ("smarty"           . "{\\(/\\|else\\)")
-    ("template-toolkit" . "\\[% \\(end\\|els\\)")
-    ("underscore"       . "<% }")
-    ("velocity"         . "#\\(end\\|else\\)"))
-  "Close control blocks.")
-
 (defvar web-mode-auto-pairs nil
   "Auto-Pairs")
 
@@ -765,51 +890,63 @@ Must be used in conjunction with web-mode-enable-block-face."
 
 (defvar web-mode-engines-closing-blocks
   '(
-
     ("php"       . (("if"      . "<?php endif; ?>")
                     ("for"     . "<?php endfor; ?>")
                     ("foreach" . "<?php endforeach; ?>")
                     ("while"   . "<?php endwhile; ?>")))
-
     )
   "Closing blocks (see web-mode-block-close)"
   )
 
 (defvar web-mode-engines-auto-pairs
   '(
-    ("angular"    . (("{{ " " }}")))
-    ("asp"        . (("<% " " %>")))
-    ("aspx"       . (("<% " " %>")
-                     ("<%=" "%>")
-                     ("<%#" "%>")
-                     ("<%$" "%>")
-                     ("<%@" "%>")
-                     ("<%:" "%>")
-                     ("<%-" "- " " --%>")))
-    ("blade"      . (("{{ " " }}")
-                     ("{{-" "- " " --}}")))
-    ("django"     . (("{{ " " }}")
-                     ("{% " " %}")
-                     ("{# " " #}")))
-    ("erb"        . (("<% " " %>")
-                     ("<%=" "%>")
-                     ("<%#" "%>")))
-    ("freemarker" . (("<% " " %>")
-                     ("${ " " }")
-                     ("[% " " %]")
-                     ("[# " " #]")
-                     ("[#-" "- " " --]")))
-    ("jsp"        . (("<% " " %>")
-                     ("<%-" "- " " %>")
-                     ("<%=" "%>")
-                     ("<%!" "%>")
-                     ("<%@" "%>")
-                     ("${ " " }")))
-    ("php"        . (("<?p" "hp " " ?>")
-                     ("<? " " ?>")
-                     ("<?=" "?>")))
-    ("underscore" . (("<% " " %>")))
-    (nil          . (("<!-" "- " " -->")))
+    ("angular"     . (("{{ " " }}")))
+    ("asp"         . (("<% " " %>")))
+    ("aspx"        . (("<% " " %>")
+                      ("<%=" "%>")
+                      ("<%#" "%>")
+                      ("<%$" "%>")
+                      ("<%@" "%>")
+                      ("<%:" "%>")
+                      ("<%-" "- " " --%>")))
+    ("blade"       . (("{{ " " }}")
+                      ("{{-" "- " " --}}")))
+    ("django"      . (("{{ " " }}")
+                      ("{% " " %}")
+                      ("{# " " #}")))
+    ("erb"         . (("<% " " %>")
+                      ("<%=" "%>")
+                      ("<%#" "%>")))
+    ("freemarker"  . (("<% " " %>")
+                      ("${ " " }")
+                      ("[% " " %]")
+                      ("[# " " #]")
+                      ("[#-" "- " " --]")))
+    ("jsp"         . (("<% " " %>")
+                      ("<%-" "- " " %>")
+                      ("<%=" "%>")
+                      ("<%!" "%>")
+                      ("<%@" "%>")
+                      ("${ " " }")))
+    ("lsp"         . (("<% " " %>")
+                      ("<%%" " " " %>")
+                      ("<%#" " " " %>")))
+    ("mako"        . (("<% " " %>")
+                      ("<%!" " " " %>")
+                      ("${ " " }")))
+    ("mason"       . (("<% " " %>")))
+    ("mojolicious" . (("<% " " %>")
+                      ("<%=" " " " %>")
+                      ("<%%" " " " %>")
+                      ("<%#" " " "%>")))
+    ("php"         . (("<?p" "hp " " ?>")
+                      ("<? " " ?>")
+                      ("<?=" "?>")))
+    ("underscore"  . (("<% " " %>")))
+    ("web2py"      . (("{{ " " }}")
+                      ("{{=" "}}")))
+    (nil           . (("<!-" "- " " -->")))
+
     )
   "Engines auto-pairs")
 
@@ -835,65 +972,65 @@ Must be used in conjunction with web-mode-enable-block-face."
     )
   "Engines snippets")
 
-(defvar web-mode-block-regexps
-  '(("angular"          . "{{")
-    ("asp"              . "<%")
-    ("aspx"             . "<%")
-    ("blade"            . "{{.\\|^[ \t]*@[[:alpha:]]")
-    ("closure"          . "{.\\|/\\*\\| //")
-    ("ctemplate"        . "[$]?{{.")
-    ("django"           . "{[#{%].")
-    ("dust"             . "{.")
-    ("erb"              . "<%\\|^%.")
-    ("freemarker"       . "<%\\|${\\|</?[[:alpha:]]+:[[:alpha:]]\\|</?[@#].\\|\\[/?[@#].")
-    ("go"               . "{{.")
-    ("jsp"              . "<%\\|${\\|</?[[:alpha:]]+:[[:alpha:]]")
-    ("php"              . "<\\?")
-    ("python"           . "<\\?")
-    ("razor"            . "@.")
-    ("smarty"           . "{[[:alpha:]#$/*\"]")
-    ("template-toolkit" . "\\[[%#]")
-    ("underscore"       . "<%")
-    ("velocity"         . "^[ \t]*#[[:alpha:]#*]\\|$[[:alpha:]!{]"))
-  "Engine block regexps.")
+(defvar web-mode-engine-token-regexp nil
+  "web-mode-engine-token-regexp")
+
+(defvar web-mode-engine-token-regexps
+  (list
+   '("asp"         . "//\\|/\\*\\|\"\\|'")
+   '("lsp"         . "\"\\|#|\\|;")
+   '("mako"        . "\"\\|'\\|#")
+   '("mason"       . "\"\\|'\\|#")
+   '("mojolicious" . "\"\\|'")
+   '("php"         . "//\\|/\\*\\|#\\|\"\\|'\\|<<<['\"]?\\([[:alnum:]]+\\)['\"]?")
+   '("python"      . "\"\\|'\\|#")
+   '("web2py"      . "\"\\|'")
+   )
+  "web-mode-engines-token-regexps")
 
-(defvar web-mode-block-electric-chars
+(defvar web-mode-block-regexps
   (list
-   (cons "blade"      '(?\{ ?\@))
-   (cons "closure"    '(?\{ ?\/))
-   (cons "ctemplate"  '(?\{ ?\$))
-   (cons "django"     '(?\{))
-   (cons "dust"       '(?\{))
-   (cons "erb"        '(?\%))
-   (cons "freemarker" '(?\[))
-   (cons "go"         '(?\{))
-   (cons "jsp"        '(?\$))
-   (cons "razor"      '(?\@))
-   (cons "smarty"     '(?\{))
-   (cons "velocity"   '(?\# ?\$)))
-  "Block electric chars.")
+   '("angular"          . "{{")
+   '("asp"              . "<%")
+   '("aspx"             . "<%.")
+   '("blade"            . "{{.\\|^[ \t]*@[[:alpha:]]")
+   '("closure"          . "{.\\|/\\*\\| //")
+   '("ctemplate"        . "[$]?{{.")
+   '("django"           . "{[#{%]")
+   '("dust"             . "{.")
+   '("erb"              . "<%\\|^%.")
+   '("freemarker"       . "<%\\|${\\|</?[[:alpha:]]+:[[:alpha:]]\\|</?[@#].\\|\\[/?[@#].")
+   '("go"               . "{{.")
+   '("jsp"              . "<%\\|${\\|</?[[:alpha:]]+:[[:alpha:]]+")
+   '("lsp"              . "<%")
+   '("mako"             . "</?%\\|${\\|^[ \t]*% \\|^[ \t]*##")
+;;   '("mason"            . "</&>\\|</%def\\|</%method\\|<%[[:alpha:]]+\\|<[%&]\\|^%.")
+   '("mason"            . "</?[&%]\\|^%.")
+   '("mojolicious"      . "<%.\\|^[ \t]*%.")
+   '("php"              . "<\\?")
+   '("python"           . "<\\?")
+   '("razor"            . "@.\\|^[ \t]*}")
+;;   '("react"            . "<script type=.?text/jsx.*>")
+   (cons "smarty"       (concat (web-mode-engine-delimiter-open "smarty" "{") "[[:alpha:]#$/*\"]"))
+
+   '("template-toolkit" . "\\[[%#]")
+   '("underscore"       . "<%")
+   '("velocity"         . "^[ \t]*#[[:alpha:]#*]\\|$[[:alpha:]!{]")
+   '("web2py"           . "{{")
+   )
+  "Engine block regexps.")
 
 (defvar web-mode-block-regexp nil
   "Regular expression for identifying blocks.")
 
-(defvar web-mode-active-block-regexp nil
-  "Engine control regexp")
-
-(defvar web-mode-close-block-regexp nil
-  "Engine end control regexp")
-
-(defvar web-mode-engine-control-matcher nil
-  "Engine control match")
-
-(defvar web-mode-electric-chars nil
-  "electric chars")
-
 (defvar web-mode-normalization-rules
   '(("tag-case"          . "lower-case")
     ("attr-case"         . "lower-case")
-    ("special-chars"     . "unicode") ;; "unicode" "entities"
+    ("special-chars"     . "unicode") ; "unicode" "entities"
+    ("css-indentation"   . t)
     ("smart-apostrophes" . t)
     ("smart-quotes"      . t)
+    ("whitespaces"       . t)
     ("indentation"       . t))
   "Normalization rules")
 
@@ -904,31 +1041,50 @@ Must be used in conjunction with web-mode-enable-block-face."
              "OPTIMIZE" "HACK" "REFACTOR")))
   "Comment keywords.")
 
+(defvar web-mode-python-constants
+  (regexp-opt
+   (append
+    web-mode-extra-python-constants
+    '("True" "False" "None" "__debug__" "NotImplemented" "Ellipsis")))
+  "Python constants.")
+
+(defvar web-mode-lsp-constants
+  (regexp-opt
+   '("nil" "t"))
+  )
+
+(defvar web-mode-lsp-keywords
+  (regexp-opt
+   '("dolist" "let" "while" "cond" "when" "progn" "if"
+     "dotimes" "unless" "lambda"
+     "loop" "for" "and" "or" "in" "do" "defun"))
+  )
+
 (defvar web-mode-php-constants
   (regexp-opt
-   (append web-mode-extra-php-constants
-           '("TRUE" "FALSE" "NULL" "true" "false" "null"
-             "STR_PAD_LEFT" "STR_PAD_RIGHT"
-             "ENT_COMPAT" "ENT_QUOTES" "ENT_NOQUOTES" "ENT_IGNORE"
-             "ENT_SUBSTITUTE" "ENT_DISALLOWED" "ENT_HTML401" "ENT_XML1"
-             "ENT_XHTML" "ENT_HTML5"
-             "LIBXML_NOBLANKS")))
+   (append
+    web-mode-extra-php-constants
+    '("TRUE" "FALSE" "NULL" "true" "false" "null"
+      "STR_PAD_LEFT" "STR_PAD_RIGHT"
+      "ENT_COMPAT" "ENT_QUOTES" "ENT_NOQUOTES" "ENT_IGNORE"
+      "ENT_SUBSTITUTE" "ENT_DISALLOWED" "ENT_HTML401" "ENT_XML1"
+      "ENT_XHTML" "ENT_HTML5"
+      "LIBXML_NOBLANKS")))
   "PHP constants.")
 
 (defvar web-mode-php-keywords
   (regexp-opt
-   (append web-mode-extra-php-keywords
-           '("and" "array" "as" "break"
-             "callable" "case" "catch"  "catch all" "class" "const" "continue"
-             "default" "die" "do"
-             "echo" "else" "elseif" "empty"
-             "endfor" "endforeach" "endif" "endswitch" "endwhile" "exit" "extends"
-             "finally" "for" "foreach" "function" "global" "goto"
-             "if" "include" "include_once" "instanceof" "interface" "isset"
-             "list" "next" "new" "or"
-             "private" "protected" "public"
-             "require" "require_once" "return" "static" "switch" "try" "throw" "unset" "use"
-             "var" "when" "while" "xor" "yield")))
+   (append
+    web-mode-extra-php-keywords
+    '("and" "array" "as" "break"
+      "callable" "case" "catch"  "catch all" "class" "const" "continue"
+      "default" "die" "do" "echo" "else" "elseif" "empty"
+      "endfor" "endforeach" "endif" "endswitch" "endwhile" "exit" "extends"
+      "finally" "for" "foreach" "function" "global" "goto"
+      "if" "include" "include_once" "instanceof" "interface" "isset"
+      "list" "next" "new" "or" "private" "protected" "public"
+      "require" "require_once" "return" "static" "switch" "try" "throw" "unset" "use"
+      "var" "when" "while" "xor" "yield")))
   "PHP keywords.")
 
 (defvar web-mode-php-types
@@ -960,38 +1116,46 @@ Must be used in conjunction with web-mode-enable-block-face."
 
 (defvar web-mode-python-keywords
   (regexp-opt
-   (append web-mode-extra-python-keywords
-           '("False" "class" "finally" "is" "return"
-             "None" "continue" "for" "lambda" "try"
-             "True" "def" "from" "nonlocal" "while"
-             "and" "del" "global" "not" "with"
-             "as" "elif" "if" "or" "yield"
-             "assert" "else" "import" "pass"
-             "break" "except" "in" "raise")))
+   (append
+    web-mode-extra-python-keywords
+    '("and" "as" "assert" "break" "class" "continue" "def" "del"
+      "elif" "else" "except" "finally" "for" "from" "global"
+      "if" "import" "in" "is" "lambda" "nonlocal" "not" "or" "pass"
+      "raise" "return" "try" "while" "with" "yield")))
   "Python keywords.")
 
 (defvar web-mode-jsp-keywords
   (regexp-opt
-   (append web-mode-extra-jsp-keywords
-           '("case" "catch" "do" "else" "end" "false" "for" "function"
-             "if" "in" "include" "new"
-             "package" "page" "private" "protected" "public"
-             "return" "tag" "taglib" "throw" "throws" "true" "try"
-             "void" "while")))
+   (append
+    web-mode-extra-jsp-keywords
+    '("case" "catch" "do" "else" "end" "false" "for" "function" "if" "in" "include"
+      "new" "package" "page" "private" "protected" "public"
+      "return" "tag" "taglib" "throw" "throws" "true" "try" "void" "while")))
   "JSP keywords.")
 
 (defvar web-mode-erb-keywords
   (regexp-opt
-   (append web-mode-extra-erb-keywords
-           '("alias" "and" "begin" "break" "case" "class"
-             "def" "defined?" "do" "elsif" "else" "end" "ensure"
-             "fail" "for" "if" "in" "module" "next" "not"
-             "or" "redo" "rescue" "retry" "return" "then" "super"
-             "unless" "undef" "until" "when" "while" "yield"
-             "__ENCODING__" "__FILE__" "__LINE__"
-             )))
+   (append
+    web-mode-extra-erb-keywords
+    '("alias" "and" "begin" "break" "case" "class" "def" "defined?" "do"
+      "elsif" "else" "end" "ensure" "fail" "for" "if" "in"
+      "module" "next" "not" "or" "redo" "rescue" "retry" "return"
+      "then" "super" "unless" "undef" "until" "when" "while" "yield"
+      "__ENCODING__" "__FILE__" "__LINE__"
+      )))
   "ERB keywords.")
 
+(defvar web-mode-mason-keywords
+  (regexp-opt
+   (append
+    web-mode-extra-mason-keywords
+    '("and" "base" "close" "die" "each" "else" "elsif" "eval" "exists"
+      "foreach" "grep" "if" "length" "local" "my" "next" "open" "or"
+      "package" "pop" "ref" "return" "stat" "sub" "tie"
+      "undef" "unless" "use" "while"
+      )))
+  "Mason keywords.")
+
 (defvar web-mode-erb-builtins
   (regexp-opt
    '("__callee__" "__dir__" "__method__"
@@ -1067,59 +1231,65 @@ Must be used in conjunction with web-mode-enable-block-face."
 
 (defvar web-mode-asp-constants
   (regexp-opt
-   (append web-mode-extra-asp-constants
-           '("adAsyncExecute" "adAsyncFetch" "adAsyncFetchNonBlocking" "adCmdFile" "adCmdStoredProc" "adCmdTable" "adCmdTableDirect" "adCmdText" "adCmdUnknown"
-             "adCmdUnspecified" "adExecuteNoRecords" "adExecuteRecord" "adExecuteStream" "adLockBatchOptimistic" "adLockOptimistic" "adLockPessimistic"
-             "adLockReadOnly" "adLockUnspecified" "adOpenDynamic" "adOpenForwardOnly" "adOpenKeyset" "adOpenStatic" "adOpenUnspecified" "adOptionUnspecified"
-             "Empty" "Nothing" "Null" "True" "False"
-             "vbBack" "vbCr" "vbCrLf" "vbFormFeed" "vbLf" "vbNewLine" "vbNullChar" "vbNullString" "vbObjectError" "vbScript" "vbTab" "vbVerticalTab")))
+   (append
+    web-mode-extra-asp-constants
+    '("adAsyncExecute" "adAsyncFetch" "adAsyncFetchNonBlocking" "adCmdFile"
+      "adCmdStoredProc" "adCmdTable" "adCmdTableDirect" "adCmdText" "adCmdUnknown"
+      "adCmdUnspecified" "adExecuteNoRecords" "adExecuteRecord" "adExecuteStream"
+      "adLockBatchOptimistic" "adLockOptimistic" "adLockPessimistic"
+      "adLockReadOnly" "adLockUnspecified" "adOpenDynamic" "adOpenForwardOnly"
+      "adOpenKeyset" "adOpenStatic" "adOpenUnspecified" "adOptionUnspecified"
+      "Empty" "Nothing" "Null" "True" "False"
+      "vbBack" "vbCr" "vbCrLf" "vbFormFeed" "vbLf" "vbNewLine" "vbNullChar"
+      "vbNullString" "vbObjectError" "vbScript" "vbTab" "vbVerticalTab")))
   "ASP constants.")
 
 (defvar web-mode-asp-keywords
   (regexp-opt
-   (append web-mode-extra-asp-keywords
-           '("Abs" "And" "Array" "Asc" "Atn"
-             "CBool" "CByte" "CCur" "CDate" "CDbl" "CInt" "CLng" "CSng" "CStr"
-             "Call" "Case" "Chr" "Class" "Const" "Cos" "CreateObject"
-             "Date" "DateAdd" "DateDiff" "DatePart" "DateSerial" "DateValue"
-             "Day" "Dim" "Do"
-             "Each" "Else" "ElseIf" "End" "Erase" "Err" "Eval" "Exit" "Exp"
-             "Explicit"
-             "Filter" "Fix" "For" "FormatCurrency" "FormatDateTime"
-             "FormatNumber" "FormatPercent" "Function"
-             "GetLocale" "GetObject" "GetRef" "Hex" "Hour"
-             "If" "In" "InStr" "InStrRev" "InputBox" "Int" "IsArray" "IsDate"
-             "IsEmpty" "IsNull" "IsNumeric" "IsObject" "Join"
-             "LBound" "LCase" "LTrim" "Language" "Left" "Len" "Let"
-             "LoadPicture" "Log" "Loop"
-             "Mid" "Minute" "Month" "MonthName" "MsgBox"
-             "New" "Next" "Not" "Now"
-             "Oct" "On" "Option" "Or" "Preserve" "Private" "Public"
-             "RGB" "RTrim" "Redim" "Rem" "Replace" "Right" "Rnd" "Round"
-             "ScriptEngine" "ScriptEngineBuildVersion"
-             "ScriptEngineMajorVersion" "ScriptEngineMinorVersion"
-             "Second" "Select" "Set" "SetLocale" "Sgn" "Sin" "Space" "Split"
-             "Sqr" "StrComp" "StrReverse" "String" "Sub"
-             "Tan" "Then" "Time" "TimeSerial" "TimeValue" "Timer" "To" "Trim"
-             "TypeName"
-             "UBound" "UCase" "Until" "VarType"
-             "Weekday" "WeekdayName" "Wend" "With" "While" "Year")))
+   (append
+    web-mode-extra-asp-keywords
+    '("Abs" "And" "Array" "Asc" "Atn"
+      "CBool" "CByte" "CCur" "CDate" "CDbl" "CInt" "CLng" "CSng" "CStr"
+      "Call" "Case" "Chr" "Class" "Const" "Cos" "CreateObject"
+      "Date" "DateAdd" "DateDiff" "DatePart" "DateSerial" "DateValue"
+      "Day" "Dim" "Do"
+      "Each" "Else" "ElseIf" "End" "Erase" "Err" "Eval" "Exit" "Exp"
+      "Explicit"
+      "Filter" "Fix" "For" "FormatCurrency" "FormatDateTime"
+      "FormatNumber" "FormatPercent" "Function"
+      "GetLocale" "GetObject" "GetRef" "Hex" "Hour"
+      "If" "In" "InStr" "InStrRev" "InputBox" "Int" "IsArray" "IsDate"
+      "IsEmpty" "IsNull" "IsNumeric" "IsObject" "Join"
+      "LBound" "LCase" "LTrim" "Language" "Left" "Len" "Let"
+      "LoadPicture" "Log" "Loop"
+      "Mid" "Minute" "Month" "MonthName" "MsgBox"
+      "New" "Next" "Not" "Now"
+      "Oct" "On" "Option" "Or" "Preserve" "Private" "Public"
+      "RGB" "RTrim" "Redim" "Rem" "Replace" "Right" "Rnd" "Round"
+      "ScriptEngine" "ScriptEngineBuildVersion"
+      "ScriptEngineMajorVersion" "ScriptEngineMinorVersion"
+      "Second" "Select" "Set" "SetLocale" "Sgn" "Sin" "Space" "Split"
+      "Sqr" "StrComp" "StrReverse" "String" "Sub"
+      "Tan" "Then" "Time" "TimeSerial" "TimeValue" "Timer" "To" "Trim"
+      "TypeName"
+      "UBound" "UCase" "Until" "VarType"
+      "Weekday" "WeekdayName" "Wend" "With" "While" "Year")))
   "ASP keywords.")
 
 (defvar web-mode-asp-types
   (regexp-opt
-   (append web-mode-extra-asp-types
-           '("Application" "ASPError" "Request" "Response" "Server" "Session")))
+   (append
+    web-mode-extra-asp-types
+    '("Application" "ASPError" "Request" "Response" "Server" "Session")))
   "ASP types.")
 
 (defvar web-mode-aspx-keywords
   (regexp-opt
-   (append web-mode-extra-aspx-keywords
-           '("case" "catch" "do" "else" "end"
-             "for" "foreach" "function"
-             "if" "in" "include"
-             "new" "package" "page" "return"
-             "tag" "throw" "throws" "try" "while")))
+   (append
+    web-mode-extra-aspx-keywords
+    '("case" "catch" "do" "else" "end" "for" "foreach" "function"
+      "if" "in" "include" "new" "package" "page" "return"
+      "tag" "throw" "throws" "try" "while")))
   "ASP.Net keywords.")
 
 (defvar web-mode-smarty-keywords
@@ -1162,17 +1332,15 @@ Must be used in conjunction with web-mode-enable-block-face."
     (regexp-opt
      '("and" "as" "autoescape" "block" "blocktrans" "break"
        "cache" "call" "comment" "context" "continue" "csrf_token" "cycle"
-       "debug" "do"
-       "embed" "empty" "else" "elseif" "elsif" "elif"
+       "debug" "do" "embed" "empty" "else" "elseif" "elsif" "elif"
        "endautoescape" "endblock" "endblocktrans" "endcomment"
        "endcache" "endcall" "endembed" "endfilter" "endfor" "endif"
        "endifchanged" "endifequal" "endifnotequal" "endmacro" "endrandom" "endraw"
        "endsandbox" "endset" "endspaceless" "endtrans" "endverbatim" "endwith"
        "extends" "filter" "firstof" "flush" "for" "from"
        "if" "ifchanged" "ifequal" "ifnotequal" "ignore" "import"
-       "in" "include" "is"
-       "load" "macro" "missing" "none" "not" "now" "or" "pluralize"
-       "random" "raw" "regroup" "trans"
+       "in" "include" "is" "load" "macro" "missing" "none" "not" "now" "or"
+       "pluralize" "random" "raw" "regroup" "trans"
        "sandbox" "set" "spaceless" "ssi" "static" "templatetag" "trans"
        "use" "url" "var" "verbatim" "widthratio" "with"
 
@@ -1206,39 +1374,106 @@ Must be used in conjunction with web-mode-enable-block-face."
      "unless" "use" "while" "wrapper"))
   "Template-toolkit keywords")
 
+(defvar web-mode-perl-keywords
+  (regexp-opt
+   '("__DATA__" "__END__" "__FILE__" "__LINE__"
+     "__PACKAGE__"
+     "and" "cmp" "continue" "CORE" "do"
+     "else" "elsif" "eq" "exp" "for" "foreach"
+     "ge" "gt" "if" "le" "lock" "lt" "m" "ne" "no"
+     "or" "package" "q" "qq" "qr" "qw" "qx" "s" "sub"
+     "tr" "unless" "until" "while" "xor" "y"
+     "my"))
+  "Perl keywords")
+
 (defvar web-mode-javascript-keywords
   (regexp-opt
-   (append web-mode-extra-javascript-keywords
-           '("break" "case" "catch" "class" "const" "continue"
-             "debugger" "default" "delete" "do" "else" "enum" "eval"
-             "export" "extends" "finally" "for" "function" "if"
-             "implements" "import" "in" "instanceof" "interface" "let"
-             "new" "package" "private" "protected" "public"
-             "return" "static" "super" "switch" "throw"
-             "try" "typeof" "var" "void" "while" "with" "yield"
-             )))
+   (append
+    web-mode-extra-javascript-keywords
+    '("break" "case" "catch" "class" "const" "continue"
+      "debugger" "default" "delete" "do" "else" "enum" "eval"
+      "export" "extends" "finally" "for" "function" "if"
+      "implements" "import" "in" "instanceof" "interface" "let"
+      "new" "package" "private" "protected" "public"
+      "return" "static" "super" "switch" "throw"
+      "try" "typeof" "var" "void" "while" "with" "yield"
+      )))
   "JavaScript keywords.")
 
 (defvar web-mode-javascript-constants
   (regexp-opt
-   '("false" "null" "undefined"
-     "Infinity" "NaN"
-     "true" "arguments" "this"
-     ))
+   '("false" "null" "undefined" "Infinity" "NaN" "true" "arguments" "this"))
   "JavaScript constants.")
 
 (defvar web-mode-razor-keywords
   (regexp-opt
-   (append web-mode-extra-razor-keywords
-           '("false" "true" "foreach" "if" "else" "in" "var" "for" "display" "main"
-             ;; scala
-             "match" "case"
-             "Html")))
+   (append
+    web-mode-extra-razor-keywords
+    '("false" "true" "foreach" "if" "else" "in" "var" "for" "display"
+      "match" "case"
+      "Html")))
   "Razor keywords.")
 
+(defvar web-mode-selector-font-lock-keywords
+  (list
+
+   (cons (concat "@\\(" web-mode-css-at-rules "\\)\\>")
+         '(1 'web-mode-css-at-rule-face))
+   '("\\<\\(all\|braille\\|embossed\\|handheld\\|print\\|projection\\|screen\\|speech\\|tty\\|tv\\|and\\|or\\)\\>" 1 'web-mode-keyword-face)
+   (cons (concat ":\\(" web-mode-css-pseudo-classes "\\)\\>")
+         '(1 'web-mode-css-pseudo-class-face))
+   '("[[:alnum:]-]+" 0 'web-mode-css-selector-face)
+   '("\\[.*?\\]\\|(.*?)" 0 nil t t)
+   '("url(\\(.+?\\))" 1 'web-mode-string-face)
+   ))
+
+(defvar web-mode-declaration-font-lock-keywords
+  (list
+   '("--[[:alnum:]-]+" 0 'web-mode-css-variable-face)
+   (cons (concat "@\\(" web-mode-css-at-rules "\\)\\>") '(1 'web-mode-css-at-rule-face))
+   '("url(\\([^)]+\\)" 1 'web-mode-string-face)
+   '("\\([[:alpha:]-]+\\)[ ]?:" 1 'web-mode-css-property-name-face)
+   '("\\([[:alpha:]-]+\\)[ ]?(" 1 'web-mode-css-function-face)
+   '("#[[:alnum:]]\\{1,6\\}" 0 'web-mode-css-color-face t t)
+   '("![ ]?important" 0 'web-mode-css-priority-face t t)
+   ))
+
+(defvar web-mode-html-font-lock-keywords
+  (list
+   '("</?[[:alnum:]]+[ >]\\|>" 0 'web-mode-html-tag-face t)
+   '(" \\([[:alnum:]-]+=\\)\\(\"[^\"]+\"\\)"
+     (1 'web-mode-html-attr-name-face)
+     (2 'web-mode-html-attr-value-face))
+   ))
+
+(defvar web-mode-javascript-font-lock-keywords
+  (list
+   (cons (concat "\\<\\(" web-mode-javascript-keywords "\\)\\>")
+         '(0 'web-mode-keyword-face))
+   (cons (concat "\\<\\(" web-mode-javascript-constants "\\)\\>")
+         '(0 'web-mode-constant-face))
+   '("\\<\\(new\\|instanceof\\) \\([[:alnum:]_.]+\\)\\>" 2 'web-mode-type-face)
+   '("\\<\\([[:alnum:]_]+\\):[ ]*function[ ]*(" 1 'web-mode-function-name-face)
+   '("\\<function[ ]+\\([[:alnum:]_]+\\)" 1 'web-mode-function-name-face)
+   '("\\<var[ ]+\\([[:alnum:]_]+\\)" 1 'web-mode-variable-name-face)
+   '("\\<\\(function\\)[ ]*("
+     (1 'web-mode-keyword-face)
+     ("\\([[:alnum:]_]+\\)\\([ ]*=[^,)]*\\)?[,)]" nil nil (1 'web-mode-variable-name-face)))
+   '("\\([[:alnum:]_]+\\):" 1 'web-mode-variable-name-face)
+   ))
+
+(defvar web-mode-html-tag-font-lock-keywords
+  (list
+   '("\\(</?\\)\\([[:alnum:]]+\\)"
+     (1 'web-mode-html-tag-bracket-face)
+     (2 'web-mode-html-tag-face))
+   '("\"[^\"]*\"" 0 'web-mode-html-attr-value-face)
+   '("\\([[:alnum:]]+\\)" 1 'web-mode-html-attr-name-face)
+   '("/?>" 0 'web-mode-html-tag-bracket-face)
+  ))
+
 (defvar web-mode-dust-font-lock-keywords
   (list
-   '("/?}\\|{[#/:?@><+^]?" 0 'web-mode-preprocessor-face)
    '("{[#:/?@><+^]\\([[:alpha:]_]+\\)" 1 'web-mode-block-control-face)
    '(":\\([[:alpha:]]+\\)" 1 'web-mode-keyword-face)
    '("\\<\\([[:alpha:]_]+=\\)\\(\"[^\"]*\"\\|[[:alnum:]_]*\\)"
@@ -1249,7 +1484,6 @@ Must be used in conjunction with web-mode-enable-block-face."
 
 (defvar web-mode-template-toolkit-font-lock-keywords
   (list
-   '("\\[%[-+]?\\|[-+=]?%\\]" 0 'web-mode-preprocessor-face)
    (cons (concat "\\<\\(" web-mode-template-toolkit-keywords "\\)\\>")
          '(1 'web-mode-keyword-face))
    '("\\\([[:alpha:]][[:alnum:]_]+\\)[ ]?(" 1 'web-mode-function-call-face)
@@ -1258,57 +1492,76 @@ Must be used in conjunction with web-mode-enable-block-face."
 
 (defvar web-mode-smarty-font-lock-keywords
   (list
-   '("}\\|{/?" 0 'web-mode-preprocessor-face)
-   (cons (concat "[ ]\\(" web-mode-smarty-keywords "\\)[ ]") '(1 'web-mode-keyword-face))
-   '("{/?\\([[:alpha:]_]+\\)" 1 'web-mode-block-control-face)
+   (cons (concat "[ ]\\(" web-mode-smarty-keywords "\\)[ ]")
+         '(1 'web-mode-keyword-face))
+   (cons (concat (web-mode-engine-delimiter-open "smarty" "{") "/?\\([[:alpha:]_]+\\)")
+         '(1 'web-mode-block-control-face))
+   '("\\([}{]\\)" 0 'web-mode-block-delimiter-face)
    '("\\<\\([$]\\)\\([[:alnum:]_]+\\)" (1 nil) (2 'web-mode-variable-name-face))
    '("\\<\\(\\sw+\\)[ ]?(" 1 'web-mode-function-call-face)
    '(" \\(\\sw+[ ]?=\\)" 1 'web-mode-param-name-face)
    '(" \\(\\sw+\\)[ }]" 1 'web-mode-param-name-face)
    '("|\\([[:alnum:]_]+\\)" 1 'web-mode-function-call-face)
    '("\\(->\\)\\(\\sw+\\)" (1 nil) (2 'web-mode-variable-name-face))
-   '("[.]\\([[:alnum:]_-]+\\)[ ]?(" (1 'web-mode-function-call-face))
-   '("[.]\\([[:alnum:]_]+\\)" (1 'web-mode-variable-name-face))
+   '("[.]\\([[:alnum:]_-]+\\)[ ]?(" 1 'web-mode-function-call-face)
+   '("[.]\\([[:alnum:]_]+\\)" 1 'web-mode-variable-name-face)
    '("#\\([[:alnum:]_]+\\)#" 1 'web-mode-variable-name-face)
    ))
 
 (defvar web-mode-velocity-font-lock-keywords
   (list
-   '("\\([#]\\)\\([[:alpha:]]+\\)\\>"
-     (1 'web-mode-preprocessor-face)
-     (2 'web-mode-block-control-face))
+   '("#\\([[:alpha:]_]+\\)\\>"
+     (1 'web-mode-block-control-face))
    (cons (concat "[ ]\\(" web-mode-velocity-keywords "\\)[ ]") '(1 'web-mode-keyword-face t t))
    '("#macro([ ]*\\([[:alpha:]]+\\)[ ]+" 1 'web-mode-function-name-face)
    '("[.]\\([[:alnum:]_-]+\\)" 1 'web-mode-variable-name-face)
    '("\\<\\($[!]?[{]?\\)\\([[:alnum:]_-]+\\)[}]?" (1 nil) (2 'web-mode-variable-name-face))
    ))
 
+(defvar web-mode-mako-tag-font-lock-keywords
+  (list
+   '("</?%\\([[:alpha:]:]+\\)" 1 'web-mode-block-control-face)
+   '("\\<\\([[:alpha:]]+=\\)\\(\"[^\"]*\"\\)"
+     (1 'web-mode-block-attr-name-face t t)
+     (2 'web-mode-block-attr-value-face t t))
+   ))
+
+(defvar web-mode-mako-block-font-lock-keywords
+  (list
+   '("\\<\\(\\sw+\\)[ ]?(" 1 'web-mode-function-call-face)
+   (cons (concat "\\<\\(" web-mode-python-constants "\\)\\>") '(1 'web-mode-constant-face))
+   (cons (concat "\\<\\(" web-mode-python-keywords "\\)\\>") '(1 'web-mode-keyword-face))
+   (cons (concat "\\<\\(endfor\\|endif\\|endwhile\\)\\>") '(1 'web-mode-keyword-face))
+   ))
+
+(defvar web-mode-web2py-font-lock-keywords
+  (list
+   '("\\<\\(\\sw+\\)[ ]?(" 1 'web-mode-function-call-face)
+   (cons (concat "\\<\\(" web-mode-python-constants "\\)\\>") '(1 'web-mode-constant-face))
+   (cons (concat "\\<\\(" web-mode-python-keywords "\\)\\>") '(1 'web-mode-keyword-face))
+   (cons (concat "\\<\\(block\\|extend\\|super\\|end\\|include\\)\\>") '(1 'web-mode-keyword-face))
+   ))
+
 (defvar web-mode-django-expr-font-lock-keywords
   (list
-   '("\\({{\\)[ ]?" 1 'web-mode-preprocessor-face)
-   '("[ ]?\\(}}\\)" 1 'web-mode-preprocessor-face)
    '("|[ ]?\\([[:alpha:]_]+\\)\\>" 1 'web-mode-function-call-face)
    (cons (concat "\\<\\(" web-mode-django-types "\\)\\>") '(1 'web-mode-type-face))
    '("\\<\\([[:alpha:]_]+\\)[ ]?(" 1 'web-mode-function-call-face)
    '("[[:alnum:]_]+" 0 'web-mode-variable-name-face)
-   )
-  "Font lock keywords for dtl expr")
+   ))
 
 (defvar web-mode-django-code-font-lock-keywords
   (list
-   '("{%\\|%}" 0 'web-mode-preprocessor-face)
    (cons (concat "\\<\\(" web-mode-django-keywords "\\)\\>") '(1 'web-mode-keyword-face))
    (cons (concat "\\<\\(" web-mode-django-types "\\)\\>") '(1 'web-mode-type-face))
    '("|[ ]?\\([[:alpha:]_]+\\)\\>" 1 'web-mode-function-call-face)
-;;   (cons (concat "|[ ]?\\(" web-mode-django-filters "\\)\\>") '(1 'web-mode-function-name-face t t))
    '("\\<\\([[:alpha:]_]+\\)[ ]?(" 1 'web-mode-function-call-face)
    '("[[:alnum:]_]+" 0 'web-mode-variable-name-face)
    ))
 
 (defvar web-mode-ctemplate-font-lock-keywords
   (list
-   '("${{\\|{{[>#/{%^&]?\\|[}]?}}" 0 'web-mode-preprocessor-face)
-   '("{{[#/>][ ]*\\([[:alnum:]_]+\\)" 1 'web-mode-block-control-face)
+   '("{{[#/>][ ]*\\([[:alnum:]_-]+\\)" 1 'web-mode-block-control-face)
    '("[[:alnum:]_]" 0 'web-mode-variable-name-face)
    '("[ ]+\\([[:alnum:]_]+=\\)" 1 'web-mode-param-name-face t t)
    '("[:=]\\([[:alpha:]_]+\\)" 1 'web-mode-function-call-face t t)
@@ -1316,10 +1569,10 @@ Must be used in conjunction with web-mode-enable-block-face."
 
 (defvar web-mode-razor-font-lock-keywords
   (list
-   '("@" 0 'web-mode-preprocessor-face)
-   (cons (concat "\\<\\(" web-mode-razor-keywords "\\)\\>") '(1 'web-mode-keyword-face t t))
+   '("@\\([[:alnum:]_.]+\\)[ ]*[({]" 1 'web-mode-block-control-face)
+   (cons (concat "\\<\\(" web-mode-razor-keywords "\\)\\>") '(1 'web-mode-keyword-face))
 ;;   '("\\([[:alnum:]]+\\):" 1 'web-mode-symbol-face)
-   '("@\\([[:alnum:]_.]+\\)[ ]?(" 1 'web-mode-function-call-face)
+;;   '("@\\([[:alnum:]_.]+\\)[ ]?(" 1 'web-mode-function-call-face)
    '("@\\([[:alnum:]_.]+\\)" 1 'web-mode-variable-name-face)
 ;;   '("<\\([[:alnum:]_]+\\)>" 1 'web-mode-type-face)
 ;;   '("\\<\\([[:alnum:].]+\\)[ ]+[{[:alpha:]]+" 1 'web-mode-type-face)
@@ -1328,11 +1581,11 @@ Must be used in conjunction with web-mode-enable-block-face."
 
 (defvar web-mode-closure-font-lock-keywords
   (list
-   '("{/?\\|/?}" 0 'web-mode-preprocessor-face)
    '("{/?\\([[:alpha:]]+\\)" 1 'web-mode-block-control-face)
    '("{param[ ]+\\([[:alnum:]]+\\)" 1 'web-mode-symbol-face)
    '("\\<\\(true\\|false\\|null\\)\\>" 1 'web-mode-type-face)
-   (cons (concat "\\<\\(" web-mode-closure-keywords "\\)\\>") '(1 'web-mode-keyword-face))
+   (cons (concat "\\<\\(" web-mode-closure-keywords "\\)\\>")
+         '(1 'web-mode-keyword-face))
    '("{\\(alias\\|call\\|delcall\\|delpackage\\|deltemplate\\|namespace\\|template\\)[ ]+\\([[:alnum:].]+\\)" 2 'web-mode-constant-face)
    '("\\(allowemptydefault\\|data\\|desc\\|meaning\\|autoescape\\|private\\|variant\\)=" 0 'web-mode-block-attr-name-face)
    '("|\\([[:alpha:]]+\\)" 1 'web-mode-function-call-face)
@@ -1342,85 +1595,38 @@ Must be used in conjunction with web-mode-enable-block-face."
 
 (defvar web-mode-go-font-lock-keywords
   (list
-   '("{{\\|}}" 0 'web-mode-preprocessor-face)
    '("{{\\([[:alpha:]]+\\)" 1 'web-mode-block-control-face)
-   (cons (concat "\\<\\(" web-mode-go-keywords "\\)\\>") '(1 'web-mode-keyword-face))
-   (cons (concat "\\<\\(" web-mode-go-functions "\\)\\>") '(1 'web-mode-function-call-face))
+   (cons (concat "\\<\\(" web-mode-go-keywords "\\)\\>")
+         '(1 'web-mode-keyword-face))
+   (cons (concat "\\<\\(" web-mode-go-functions "\\)\\>")
+         '(1 'web-mode-function-call-face))
    '("[$.]\\([[:alnum:]_]+\\)" 1 'web-mode-variable-name-face t t)
    ))
 
 (defvar web-mode-expression-font-lock-keywords
   (list
-   '("<%\\$\\|%>" 0 'web-mode-preprocessor-face)
    '("[[:alpha:]_]" 0 'web-mode-variable-name-face)
    ))
 
 (defvar web-mode-angular-font-lock-keywords
   (list
-   '("{{\\|}}" 0 'web-mode-preprocessor-face)
    '("[[:alpha:]_]" 0 'web-mode-variable-name-face)
    ))
 
-(defvar web-mode-selector-font-lock-keywords
-  (list
-   (cons (concat "@\\(" web-mode-css-at-rules "\\)\\>") '(1 'web-mode-css-at-rule-face))
-   '("\\<\\(all\|braille\\|embossed\\|handheld\\|print\\|projection\\|screen\\|speech\\|tty\\|tv\\|and\\|or\\)\\>" 1 'web-mode-keyword-face)
-   (cons (concat ":\\(" web-mode-css-pseudo-classes "\\)\\>") '(1 'web-mode-css-pseudo-class-face))
-   '("[[:alnum:]-]+" 0 'web-mode-css-selector-face)
-   '("\\[.*?\\]\\|(.*?)" 0 nil t t)
-   '("url(\\(.+?\\))" 1 'web-mode-string-face)
-   ))
-
-(defvar web-mode-declaration-font-lock-keywords
+(defvar web-mode-underscore-font-lock-keywords
   (list
-   (cons (concat "@\\(" web-mode-css-at-rules "\\)\\>") '(1 'web-mode-css-at-rule-face))
-   '("url(\\([^)]+\\)" 1 'web-mode-string-face)
-   '("\\([[:alpha:]-]+\\)[ ]?:" 1 'web-mode-css-property-name-face)
-   '("\\([[:alpha:]-]+\\)[ ]?(" 1 'web-mode-css-function-face)
-   '("#[[:alnum:]]\\{1,6\\}" 0 'web-mode-css-color-face t t)
-   '("![ ]?important" 0 'web-mode-css-priority-face t t)
+   (cons (concat "\\<\\(" web-mode-javascript-keywords "\\)\\>")
+         '(0 'web-mode-keyword-face))
+   '("\\<\\(_\.[[:alpha:]]+\\)(" 1 'web-mode-function-call-face)
+   '("\\<new \\([[:alnum:]_.]+\\)\\>" 1 'web-mode-type-face)
+   '("\\<\\([[:alnum:]_]+\\):[ ]*function[ ]*(" 1 'web-mode-function-name-face)
+   '("\\<\\(var\\)\\>[ ]+\\([[:alnum:]_]+\\)"
+     (1 'web-mode-keyword-face)
+     (2 'web-mode-variable-name-face))
    ))
 
-(defvar web-mode-html-font-lock-keywords
+(defvar web-mode-asp-font-lock-keywords
   (list
-   '("</?[[:alnum:]]+\\|>" 0 'web-mode-html-tag-face)
-   '(" \\([[:alnum:]-]+=\\)\\(\"[^\"]+\"\\)"
-     (1 'web-mode-html-attr-name-face)
-     (2 'web-mode-html-attr-value-face))
-   ))
-
-(defvar web-mode-javascript-font-lock-keywords
-  (list
-   (cons (concat "\\<\\(" web-mode-javascript-keywords "\\)\\>") '(0 'web-mode-keyword-face))
-   (cons (concat "\\<\\(" web-mode-javascript-constants "\\)\\>") '(0 'web-mode-constant-face))
-   '("\\<\\(new\\|instanceof\\) \\([[:alnum:]_.]+\\)\\>" 2 'web-mode-type-face)
-   '("\\<\\([[:alnum:]_]+\\):[ ]*function[ ]*(" 1 'web-mode-function-name-face)
-   '("\\<function[ ]+\\([[:alnum:]_]+\\)" 1 'web-mode-function-name-face)
-   '("\\<\\(var\\)\\>[ ]+"
-     (1 'web-mode-keyword-face)
-     ("\\([[:alnum:]_]+\\)\\([ ]*=[^,;]*\\)?[,; ]" nil nil (1 'web-mode-variable-name-face)))
-   '("\\<\\(function\\)[ ]*("
-     (1 'web-mode-keyword-face)
-     ("\\([[:alnum:]_]+\\)\\([ ]*=[^,)]*\\)?[,)]" nil nil (1 'web-mode-variable-name-face)))
-   '("\\([[:alnum:]_]+\\):" 1 'web-mode-variable-name-face)
-;;   '("/[^/]+/" 0 'web-mode-string-face)
-   ))
-
-(defvar web-mode-underscore-font-lock-keywords
-  (list
-   '("<%[-=]?\\|%>" 0 'web-mode-preprocessor-face)
-   (cons (concat "\\<\\(" web-mode-javascript-keywords "\\)\\>") '(0 'web-mode-keyword-face))
-   '("\\<\\(_\.[[:alpha:]]+\\)(" 1 'web-mode-function-call-face)
-   '("\\<new \\([[:alnum:]_.]+\\)\\>" 1 'web-mode-type-face)
-   '("\\<\\([[:alnum:]_]+\\):[ ]*function[ ]*(" 1 'web-mode-function-name-face)
-   '("\\<\\(var\\)\\>[ ]+\\([[:alnum:]_]+\\)"
-     (1 'web-mode-keyword-face)
-     (2 'web-mode-variable-name-face))
-   ))
-
-(defvar web-mode-asp-font-lock-keywords
-  (list
-   '("<%=?\\|%>" 0 'web-mode-preprocessor-face)
    (cons (concat "\\<\\(" web-mode-asp-keywords "\\)\\>")
          '(0 'web-mode-keyword-face))
    (cons (concat "\\<\\(" web-mode-asp-types "\\)\\>")
@@ -1440,16 +1646,15 @@ Must be used in conjunction with web-mode-enable-block-face."
 
 (defvar web-mode-aspx-font-lock-keywords
   (list
-   '("<%[:=#]?\\|%>" 0 'web-mode-preprocessor-face)
    (cons (concat "\\<\\(" web-mode-aspx-keywords "\\)\\>") '(0 'web-mode-keyword-face))
    '("\\<\\([[:alnum:].]+\\)[ ]+[[:alpha:]]+" 1 'web-mode-type-face)
    ))
 
-;;Unified Expression Language
 (defvar web-mode-uel-font-lock-keywords
   (list
    '("[$#{]{\\|}" 0 'web-mode-preprocessor-face)
    '("\\([[:alpha:]_]+\\)[ ]?(" 1 'web-mode-function-call-face)
+   '("|[ ]*\\(trim\\|x\\|u\\)" 1 'web-mode-function-call-face)
    '("[[:alpha:]_]" 0 'web-mode-variable-name-face)
    ))
 
@@ -1461,17 +1666,16 @@ Must be used in conjunction with web-mode-enable-block-face."
 
 (defvar web-mode-freemarker-square-font-lock-keywords
   (list
-   '("\\[/?[#@]\\|/?>\\|/?\\]" 0 'web-mode-preprocessor-face)
    '("\\[/?[#@]\\([[:alpha:]_.]*\\)" 1 'web-mode-block-control-face)
    '("#\\(macro\\|function\\) \\([[:alpha:]]+\\)" 2 'web-mode-function-name-face)
-   (cons (concat "\\<\\(" web-mode-freemarker-keywords "\\)\\>") '(1 'web-mode-keyword-face))
+   (cons (concat "\\<\\(" web-mode-freemarker-keywords "\\)\\>")
+         '(1 'web-mode-keyword-face))
    '("\\<\\([[:alnum:]._]+\\)[ ]?(" 1 'web-mode-function-call-face)
    '("[[:alpha:]]\\([[:alnum:]_]+\\)?" 0 'web-mode-variable-name-face)
    ))
 
 (defvar web-mode-freemarker-font-lock-keywords
   (list
-   '("</?[#@]\\|/?>\\|/?>" 0 'web-mode-preprocessor-face)
    '("</?[#@]\\([[:alpha:]_.]*\\)" 1 'web-mode-block-control-face)
    '("#\\(macro\\|function\\) \\([[:alpha:]]+\\)" 2 'web-mode-function-name-face)
    (cons (concat "\\<\\(" web-mode-freemarker-keywords "\\)\\>") '(1 'web-mode-keyword-face))
@@ -1479,10 +1683,8 @@ Must be used in conjunction with web-mode-enable-block-face."
    '("[[:alpha:]]\\([[:alnum:]_]+\\)?" 0 'web-mode-variable-name-face)
    ))
 
-;;TODO : definir web-mode-block-attr-name-face et web-mode-block-attr-name-face
 (defvar web-mode-jsp-tag-font-lock-keywords
   (list
-   '("</?\\|/?>" 0 'web-mode-preprocessor-face)
    '("</?\\([[:alpha:]]+:[[:alpha:]]+\\)" 1 'web-mode-block-control-face)
    '("\\<\\([[:alpha:]]+=\\)\\(\"[^\"]*\"\\)"
      (1 'web-mode-block-attr-name-face t t)
@@ -1491,7 +1693,6 @@ Must be used in conjunction with web-mode-enable-block-face."
 
 (defvar web-mode-jsp-font-lock-keywords
   (list
-   '("-?%>\\|<%\\(!\\|=\\|#=\\)?" 0 'web-mode-preprocessor-face)
    '("\\(throws\\|new\\|extends\\)[ ]+\\([[:alnum:].]+\\)" 2 'web-mode-type-face)
    (cons (concat "\\<\\(" web-mode-jsp-keywords "\\)\\>") '(0 'web-mode-keyword-face))
    '("\\<\\([[:alnum:]._]+\\)[ ]?(" 1 'web-mode-function-call-face)
@@ -1501,7 +1702,6 @@ Must be used in conjunction with web-mode-enable-block-face."
 
 (defvar web-mode-directive-font-lock-keywords
   (list
-   '("<%@\\|%>" 0 'web-mode-preprocessor-face)
    '("<%@[ ]*\\([[:alpha:]]+\\)[ ]+" 1 'web-mode-block-control-face)
    '("\\<\\([[:alpha:]]+=\\)\\(\"[^\"]*\"\\)"
      (1 'web-mode-block-attr-name-face t t)
@@ -1510,31 +1710,53 @@ Must be used in conjunction with web-mode-enable-block-face."
 
 (defvar web-mode-erb-font-lock-keywords
   (list
-   '("-?%>\\|^%\\|<%[=-]?" 0 'web-mode-preprocessor-face)
    '("[^:]\\(:[[:alnum:]_]+\\)" 1 'web-mode-symbol-face)
    '("\\([[:alnum:]_]+:\\)[ ]+" 1 'web-mode-symbol-face)
-   (cons (concat "\\<\\(" web-mode-erb-builtins "\\)\\>")
-         '(0 'web-mode-builtin-face))
-   (cons (concat "\\<\\(" web-mode-erb-keywords "\\)\\>")
-         '(0 'web-mode-keyword-face))
+   (cons (concat "\\<\\(" web-mode-erb-builtins "\\)\\>") '(0 'web-mode-builtin-face))
+   (cons (concat "\\<\\(" web-mode-erb-keywords "\\)\\>") '(0 'web-mode-keyword-face))
    '("\\<\\(self\\|true\\|false\\|nil\\)\\>" 0 'web-mode-variable-name-face)
    '("[@$]@?\\([[:alnum:]_]+\\)" 0 'web-mode-variable-name-face)
    '("class[ ]+\\([[:alnum:]_]+\\)" 1 'web-mode-type-face)
    '("def[ ]+\\([[:alnum:]_]+\\)" 1 'web-mode-function-name-face)
-   '("\\(?:\\_<\\|::\\)\\([A-Z]+[[:alnum:]_]+\\)"
-     1 (unless (eq ?\( (char-after)) 'web-mode-type-face))
+   '("\\(?:\\_<\\|::\\)\\([A-Z]+[[:alnum:]_]+\\)" 1 (unless (eq (char-after) ?\() 'web-mode-type-face))
    '("/[^/]+/" 0 'web-mode-string-face)
    ))
 
 (defvar web-mode-python-font-lock-keywords
   (list
-   '("<\\?\\|\\?>" 0 'web-mode-preprocessor-face)
    (cons (concat "\\<\\(" web-mode-python-keywords "\\)\\>") '(0 'web-mode-keyword-face))
    ))
 
+(defvar web-mode-mason-font-lock-keywords
+  (list
+   (cons (concat "\\<\\(" web-mode-mason-keywords "\\)\\>")
+         '(0 'web-mode-keyword-face))
+   '("sub[ ]+\\([[:alnum:]_]+\\)" 1 'web-mode-function-name-face)
+   '(" | \\([hun]+\\) " 1 'web-mode-function-name-face)
+   '("\\<\\([[:alnum:]_]+\\)[ ]?::" 1 'web-mode-type-face)
+   '("\\([@]\\)\\([[:alnum:]#_]*\\)" (1 nil) (2 'web-mode-variable-name-face))
+   '("\\<\\([$%]\\)\\([[:alnum:]@#_]*\\)" (1 nil) (2 'web-mode-variable-name-face))
+   '("{\\([[:alnum:]_]+\\)}" 1 'web-mode-variable-name-face)
+   '("\\<\\(\\sw+\\)[ ]?(" 1 'web-mode-function-call-face)
+   '("[[:alnum:]_][ ]?::[ ]?\\([[:alnum:]_]+\\)" 1 'web-mode-variable-name-face)
+   '("->[ ]?\\([[:alnum:]_]+\\)" 1 'web-mode-variable-name-face)
+   ))
+
+(defvar web-mode-mojolicious-font-lock-keywords
+  (list
+   (cons (concat "\\<\\(" web-mode-perl-keywords "\\)\\>") '(0 'web-mode-keyword-face))
+   '("\\<\\([$]\\)\\([[:alnum:]_]*\\)" (1 nil) (2 'web-mode-variable-name-face))
+   ))
+
+(defvar web-mode-lsp-font-lock-keywords
+  (list
+   (cons (concat "\\<\\(" web-mode-lsp-keywords "\\)\\>") '(0 'web-mode-keyword-face))
+   (cons (concat "\\<\\(" web-mode-lsp-constants "\\)\\>") '(1 'web-mode-constant-face))
+   '("[ ]\\(:[[:alnum:]-_]+\\)" 1 'web-mode-symbol-face)
+   ))
+
 (defvar web-mode-php-font-lock-keywords
   (list
-   '("<\\?\\(php\\|=\\)?\\|\\?>" 0 'web-mode-preprocessor-face)
    (cons (concat "\\<\\(" web-mode-php-keywords "\\)\\>") '(0 'web-mode-keyword-face))
    (cons (concat "(\\<\\(" web-mode-php-types "\\)\\>") '(1 'web-mode-type-face))
    (cons (concat "\\<\\(" web-mode-php-constants "\\)\\>") '(0 'web-mode-constant-face))
@@ -1547,15 +1769,48 @@ Must be used in conjunction with web-mode-enable-block-face."
    '("\\<\\([$]\\)\\([[:alnum:]_]*\\)" (1 nil) (2 'web-mode-variable-name-face))
    ))
 
+(defvar web-mode-latex-font-lock-keywords
+  (list
+;;   '("." 0 'web-mode-inlay-face)
+   '("[[:alnum:]_]+" 0 'web-mode-function-name-face t t)
+   )
+  )
+
 (defvar web-mode-blade-font-lock-keywords
   (append
    (list
-    '("{{\\|}}" 0 'web-mode-preprocessor-face)
-    '("\\(@\\)\\([[:alpha:]_]+\\)"
-      (1 'web-mode-preprocessor-face)
-      (2 'web-mode-block-control-face)))
+    '("@\\([[:alpha:]_]+\\)" (1 'web-mode-block-control-face)))
    web-mode-php-font-lock-keywords))
 
+(defvar web-mode-react-font-lock-keywords
+  (append
+   (list
+    '("xxxxxxxxx" 0 'web-mode-block-delimiter-face)
+    )
+   web-mode-javascript-font-lock-keywords))
+
+(defvar web-mode-engines-font-lock-keywords
+  '(("angular"          . web-mode-angular-font-lock-keywords)
+    ("asp"              . web-mode-asp-font-lock-keywords)
+    ("blade"            . web-mode-blade-font-lock-keywords)
+    ("closure"          . web-mode-closure-font-lock-keywords)
+    ("ctemplate"        . web-mode-ctemplate-font-lock-keywords)
+    ("dust"             . web-mode-dust-font-lock-keywords)
+    ("erb"              . web-mode-erb-font-lock-keywords)
+    ("go"               . web-mode-go-font-lock-keywords)
+    ("lsp"              . web-mode-lsp-font-lock-keywords)
+    ("mason"            . web-mode-mason-font-lock-keywords)
+    ("mojolicious"      . web-mode-mojolicious-font-lock-keywords)
+    ("php"              . web-mode-php-font-lock-keywords)
+    ("python"           . web-mode-python-font-lock-keywords)
+    ("razor"            . web-mode-razor-font-lock-keywords)
+    ("smarty"           . web-mode-smarty-font-lock-keywords)
+    ("template-toolkit" . web-mode-template-toolkit-font-lock-keywords)
+    ("underscore"       . web-mode-underscore-font-lock-keywords)
+    ("web2py"           . web-mode-web2py-font-lock-keywords)
+    ("velocity"         . web-mode-velocity-font-lock-keywords))
+  "Engines font-lock keywords")
+
 (defvar web-mode-syntax-table
   (let ((table (make-syntax-table)))
     (modify-syntax-entry ?_ "w" table)
@@ -1572,69 +1827,78 @@ Must be used in conjunction with web-mode-enable-block-face."
 (defvar web-mode-map
   (let ((map (make-sparse-keymap)))
 
-    (define-key map [menu-bar wm] (cons "Web-Mode" (make-sparse-keymap)))
-    (define-key map [menu-bar wm blk] (cons "Block" (make-sparse-keymap)))
-    (define-key map [menu-bar wm tag] (cons "Html Tag" (make-sparse-keymap)))
-    (define-key map [menu-bar wm elt] (cons "Html Element" (make-sparse-keymap)))
+    (define-key map [menu-bar wm]             (cons "Web-Mode" (make-sparse-keymap)))
+    (define-key map [menu-bar wm dom]         (cons "Dom" (make-sparse-keymap)))
+    (define-key map [menu-bar wm blk]         (cons "Block" (make-sparse-keymap)))
+    (define-key map [menu-bar wm attr]        (cons "Html Attr" (make-sparse-keymap)))
+    (define-key map [menu-bar wm tag]         (cons "Html Tag" (make-sparse-keymap)))
+    (define-key map [menu-bar wm elt]         (cons "Html Element" (make-sparse-keymap)))
+
+    (define-key map [menu-bar wm sep-1]       '(menu-item "--"))
+
+    (define-key map [menu-bar wm dom dom-xpa] '(menu-item "XPath" web-mode-dom-xpath))
+    (define-key map [menu-bar wm dom dom-tra] '(menu-item "Traverse" web-mode-dom-traverse))
+    (define-key map [menu-bar wm dom dom-err] '(menu-item "Show error(s)" web-mode-dom-errors-show))
+    (define-key map [menu-bar wm dom dom-ent] '(menu-item "Replace HTML entities" web-mode-dom-entities-replace))
+    (define-key map [menu-bar wm dom dom-quo] '(menu-item "Replace dumb quotes" web-mode-dom-quotes-replace))
+    (define-key map [menu-bar wm dom dom-apo] '(menu-item "Replace apostrophes" web-mode-dom-apostrophes-replace))
+    (define-key map [menu-bar wm dom dom-nor] '(menu-item "Normalise" web-mode-dom-normalize))
 
-    (define-key map [menu-bar wm sep-1] '(menu-item "--"))
     (define-key map [menu-bar wm blk blk-sel] '(menu-item "Select" web-mode-block-select))
-    (define-key map [menu-bar wm blk blk-kill] '(menu-item "Kill" web-mode-block-kill))
-    (define-key map [menu-bar wm blk blk-next] '(menu-item "Next" web-mode-block-next))
-    (define-key map [menu-bar wm blk blk-prev] '(menu-item "Previous" web-mode-block-previous))
-    (define-key map [menu-bar wm blk blk-end] '(menu-item "End" web-mode-block-beginning))
+    (define-key map [menu-bar wm blk blk-pre] '(menu-item "Previous" web-mode-block-previous))
+    (define-key map [menu-bar wm blk blk-nex] '(menu-item "Next" web-mode-block-next))
+    (define-key map [menu-bar wm blk blk-kil] '(menu-item "Kill" web-mode-block-kill))
+    (define-key map [menu-bar wm blk blk-end] '(menu-item "End" web-mode-block-end))
+    (define-key map [menu-bar wm blk blk-clo] '(menu-item "Close" web-mode-block-close))
     (define-key map [menu-bar wm blk blk-beg] '(menu-item "Beginning" web-mode-block-beginning))
-    (define-key map [menu-bar wm blk blk-close] '(menu-item "Close" web-mode-block-close))
 
+    (define-key map [menu-bar wm attr attr-end] '(menu-item "End" web-mode-attribute-end))
+    (define-key map [menu-bar wm attr attr-beg] '(menu-item "Beginning" web-mode-attribute-beginning))
+    (define-key map [menu-bar wm attr attr-sel] '(menu-item "Select" web-mode-attribute-select))
+    (define-key map [menu-bar wm attr attr-nex] '(menu-item "Next" web-mode-attribute-next))
+    (define-key map [menu-bar wm attr attr-tra] '(menu-item "Next" web-mode-attribute-transpose))
+
+    (define-key map [menu-bar wm tag tag-beg] '(menu-item "Sort Attributes" web-mode-tag-attributes-sort))
     (define-key map [menu-bar wm tag tag-sel] '(menu-item "Select" web-mode-tag-select))
-    (define-key map [menu-bar wm tag tag-match] '(menu-item "Match" web-mode-tag-match))
-    (define-key map [menu-bar wm tag tag-next] '(menu-item "Next" web-mode-tag-next))
-    (define-key map [menu-bar wm tag tag-prev] '(menu-item "Previous" web-mode-tag-previous))
-    (define-key map [menu-bar wm tag tag-end] '(menu-item "End" web-mode-tag-beginning))
+    (define-key map [menu-bar wm tag tag-pre] '(menu-item "Previous" web-mode-tag-previous))
+    (define-key map [menu-bar wm tag tag-nex] '(menu-item "Next" web-mode-tag-next))
+    (define-key map [menu-bar wm tag tag-mat] '(menu-item "Match" web-mode-tag-match))
+    (define-key map [menu-bar wm tag tag-end] '(menu-item "End" web-mode-tag-end))
     (define-key map [menu-bar wm tag tag-beg] '(menu-item "Beginning" web-mode-tag-beginning))
 
-    (define-key map [menu-bar wm elt elt-in] '(menu-item "Inner Content" web-mode-element-content-select))
-    (define-key map [menu-bar wm elt elt-parent] '(menu-item "Parent" web-mode-element-parent))
+    (define-key map [menu-bar wm elt elt-wra] '(menu-item "Wrap" web-mode-element-wrap))
+    (define-key map [menu-bar wm elt elt-van] '(menu-item "Vanish" web-mode-element-vanish))
+    (define-key map [menu-bar wm elt elt-exc] '(menu-item "Transpose" web-mode-element-transpose))
     (define-key map [menu-bar wm elt elt-sel] '(menu-item "Select" web-mode-element-select))
     (define-key map [menu-bar wm elt elt-ren] '(menu-item "Rename" web-mode-element-rename))
-    (define-key map [menu-bar wm elt elt-dup] '(menu-item "Clone" web-mode-element-clone))
-    (define-key map [menu-bar wm elt elt-close] '(menu-item "Close" web-mode-element-close))
-    (define-key map [menu-bar wm elt elt-trav] '(menu-item "Traverse DOM" web-mode-element-traverse))
-    (define-key map [menu-bar wm elt elt-child] '(menu-item "Child" web-mode-element-child))
+    (define-key map [menu-bar wm elt elt-pre] '(menu-item "Previous" web-mode-element-previous))
+    (define-key map [menu-bar wm elt elt-par] '(menu-item "Parent" web-mode-element-parent))
+    (define-key map [menu-bar wm elt elt-nex] '(menu-item "Next" web-mode-element-next))
+    (define-key map [menu-bar wm elt elt-mut] '(menu-item "Mute blanks" web-mode-element-mute-blanks))
     (define-key map [menu-bar wm elt elt-del] '(menu-item "Kill" web-mode-element-kill))
-    (define-key map [menu-bar wm elt elt-next] '(menu-item "Next" web-mode-element-next))
-    (define-key map [menu-bar wm elt elt-prev] '(menu-item "Previous" web-mode-element-previous))
     (define-key map [menu-bar wm elt elt-end] '(menu-item "End" web-mode-element-end))
+    (define-key map [menu-bar wm elt elt-inn] '(menu-item "Content (select)" web-mode-element-content-select))
+    (define-key map [menu-bar wm elt elt-clo] '(menu-item "Close" web-mode-element-close))
+    (define-key map [menu-bar wm elt elt-dup] '(menu-item "Clone" web-mode-element-clone))
+    (define-key map [menu-bar wm elt elt-cfo] '(menu-item "Children fold" web-mode-element-children-fold-or-unfold))
+    (define-key map [menu-bar wm elt elt-chi] '(menu-item "Child" web-mode-element-child))
     (define-key map [menu-bar wm elt elt-beg] '(menu-item "Beginning" web-mode-element-beginning))
-    (define-key map [menu-bar wm elt elt-van] '(menu-item "Vanish" web-mode-element-vanish))
 
-    (define-key map [menu-bar wm err] '(menu-item "Show error(s)" web-mode-errors-show))
-    (define-key map [menu-bar wm fold] '(menu-item "Fold/Unfold" web-mode-fold-or-unfold))
-    (define-key map [menu-bar wm indent] '(menu-item "Indent buffer" web-mode-buffer-indent))
-    (define-key map [menu-bar wm nav] '(menu-item "Tag/Block navigation" web-mode-tag-match))
-    (define-key map [menu-bar wm expand] '(menu-item "Mark and Expand" web-mode-mark-and-expand))
-    (define-key map [menu-bar wm space] '(menu-item "Toggle whitespaces" web-mode-whitespaces-show))
-    (define-key map [menu-bar wm xpath] '(menu-item "XPath" web-mode-xpath))
-    (define-key map [menu-bar wm snippet] '(menu-item "Insert snippet" web-mode-snippet-insert))
-    (define-key map [menu-bar wm entities] '(menu-item "Replace HTML entities" web-mode-entities-replace))
-
-    (define-key map (kbd "C-;")       'web-mode-comment-or-uncomment)
-    (define-key map (kbd "M-;")       'web-mode-comment-or-uncomment)
+    (define-key map [menu-bar wm fol]         '(menu-item "Fold/Unfold" web-mode-fold-or-unfold))
+    (define-key map [menu-bar wm ind]         '(menu-item "Indent buffer" web-mode-buffer-indent))
+    (define-key map [menu-bar wm nav]         '(menu-item "Tag/Block navigation" web-mode-navigate))
+    (define-key map [menu-bar wm exp]         '(menu-item "Mark and Expand" web-mode-mark-and-expand))
+    (define-key map [menu-bar wm spa]         '(menu-item "Toggle whitespaces" web-mode-whitespaces-show))
+    (define-key map [menu-bar wm sni]         '(menu-item "Insert snippet" web-mode-snippet-insert))
 
-    (define-key map (kbd "C-c C-c")   'web-mode-block-close)
-    (define-key map (kbd "C-c C-d")   'web-mode-errors-show)
-    (define-key map (kbd "C-c C-f")   'web-mode-fold-or-unfold)
-    (define-key map (kbd "C-c C-i")   'web-mode-buffer-indent)
-    (define-key map (kbd "C-c C-m")   'web-mode-mark-and-expand)
-    (define-key map (kbd "C-c C-n")   'web-mode-buffer-normalize)
-    (define-key map (kbd "C-c C-r")   'web-mode-entities-replace)
-    (define-key map (kbd "C-c C-s")   'web-mode-snippet-insert)
-    (define-key map (kbd "C-c C-x")   'web-mode-xpath)
-    (define-key map (kbd "C-c C-w")   'web-mode-whitespaces-show)
+    ;;--------------------------------------------------------------------------
+    ;; "C-c letter"  are reserved for users
 
-    (define-key map (kbd "C-c /")     'web-mode-element-close)
-    (define-key map (kbd "C-c <")     'web-mode-element-beginning)
-    (define-key map (kbd "C-c >")     'web-mode-element-end)
+    (define-key map (kbd "C-c C-a b") 'web-mode-attribute-beginning)
+    (define-key map (kbd "C-c C-a e") 'web-mode-attribute-end)
+    (define-key map (kbd "C-c C-a s") 'web-mode-attribute-select)
+    (define-key map (kbd "C-c C-a t") 'web-mode-attribute-transpose)
+    (define-key map (kbd "C-c C-a n") 'web-mode-attribute-next)
 
     (define-key map (kbd "C-c C-b c") 'web-mode-block-close)
     (define-key map (kbd "C-c C-b b") 'web-mode-block-beginning)
@@ -1644,20 +1908,32 @@ Must be used in conjunction with web-mode-enable-block-face."
     (define-key map (kbd "C-c C-b p") 'web-mode-block-previous)
     (define-key map (kbd "C-c C-b s") 'web-mode-block-select)
 
+    (define-key map (kbd "C-c C-d a") 'web-mode-dom-apostrophes-replace)
+    (define-key map (kbd "C-c C-d n") 'web-mode-dom-normalize)
+    (define-key map (kbd "C-c C-d d") 'web-mode-dom-errors-show)
+    (define-key map (kbd "C-c C-d e") 'web-mode-dom-entities-replace)
+    (define-key map (kbd "C-c C-d q") 'web-mode-dom-quotes-replace)
+    (define-key map (kbd "C-c C-d t") 'web-mode-dom-traverse)
+    (define-key map (kbd "C-c C-d x") 'web-mode-dom-xpath)
+
     (define-key map (kbd "C-c C-e b") 'web-mode-element-beginning)
     (define-key map (kbd "C-c C-e c") 'web-mode-element-clone)
     (define-key map (kbd "C-c C-e d") 'web-mode-element-child)
     (define-key map (kbd "C-c C-e e") 'web-mode-element-end)
+    (define-key map (kbd "C-c C-e f") 'web-mode-element-children-fold-or-unfold)
     (define-key map (kbd "C-c C-e i") 'web-mode-element-content-select)
     (define-key map (kbd "C-c C-e k") 'web-mode-element-kill)
+    (define-key map (kbd "C-c C-e m") 'web-mode-element-mute-blanks)
     (define-key map (kbd "C-c C-e n") 'web-mode-element-next)
     (define-key map (kbd "C-c C-e p") 'web-mode-element-previous)
     (define-key map (kbd "C-c C-e r") 'web-mode-element-rename)
     (define-key map (kbd "C-c C-e s") 'web-mode-element-select)
-    (define-key map (kbd "C-c C-e t") 'web-mode-element-traverse)
+    (define-key map (kbd "C-c C-e t") 'web-mode-element-transpose)
     (define-key map (kbd "C-c C-e u") 'web-mode-element-parent)
     (define-key map (kbd "C-c C-e v") 'web-mode-element-vanish)
+    (define-key map (kbd "C-c C-e w") 'web-mode-element-wrap)
 
+    (define-key map (kbd "C-c C-t a") 'web-mode-tag-attributes-sort)
     (define-key map (kbd "C-c C-t b") 'web-mode-tag-beginning)
     (define-key map (kbd "C-c C-t e") 'web-mode-tag-end)
     (define-key map (kbd "C-c C-t m") 'web-mode-tag-match)
@@ -1665,11 +1941,22 @@ Must be used in conjunction with web-mode-enable-block-face."
     (define-key map (kbd "C-c C-t p") 'web-mode-tag-previous)
     (define-key map (kbd "C-c C-t s") 'web-mode-tag-select)
 
-    ;; compatibility with nxml
-    (define-key map (kbd "M-C-u")     'web-mode-element-parent)
-    (define-key map (kbd "M-C-d")     'web-mode-element-child)
-    (define-key map (kbd "M-C-n")     'web-mode-element-next)
-    (define-key map (kbd "M-C-p")     'web-mode-element-previous)
+    ;;--------------------------------------------------------------------------
+
+    (define-key map (kbd "M-;")       'web-mode-comment-or-uncomment)
+
+    ;;C-c C-a : attribute
+    ;;C-c C-b : block
+    ;;C-c C-d : dom
+    ;;C-c C-e : element
+    (define-key map (kbd "C-c C-f")   'web-mode-fold-or-unfold)
+    (define-key map (kbd "C-c C-i")   'web-mode-buffer-indent)
+    (define-key map (kbd "C-c C-j")   'web-mode-jshint)
+    (define-key map (kbd "C-c C-m")   'web-mode-mark-and-expand)
+    (define-key map (kbd "C-c C-n")   'web-mode-navigate)
+    (define-key map (kbd "C-c C-s")   'web-mode-snippet-insert)
+    ;;C-c C-t : tag
+    (define-key map (kbd "C-c C-w")   'web-mode-whitespaces-show)
 
     map)
   "Keymap for `web-mode'.")
@@ -1692,62 +1979,132 @@ Must be used in conjunction with web-mode-enable-block-face."
              ,@body
            (set-buffer-modified-p old-modified-p)))))
 
-  );eval-and-compile
+  (defun web-mode-buffer-narrowed-p ()
+    "For compatibility with Emacs 24.3."
+    (if (fboundp 'buffer-narrowed-p)
+        (buffer-narrowed-p)
+      (/= (- (point-max) (point-min)) (buffer-size))))
+
+  ) ;eval-and-compile
+
+;;(defvar web-mode-buffer-highlighted nil)
+
+(defvar web-mode-font-lock-keywords
+  '(web-mode-font-lock-highlight))
+
+(defun web-mode-font-lock-extend-region ()
+  (save-excursion
+    ;;    (message "before : font-lock-beg=%S - font-lock-end=%S" font-lock-beg font-lock-end)
+    (cond
+     ((string= web-mode-engine "razor")
+      (setq font-lock-beg (point-min)
+            font-lock-end (point-max)))
+     ((and web-mode-highlight-beg web-mode-highlight-end)
+      (setq font-lock-beg web-mode-highlight-beg
+            font-lock-end web-mode-highlight-end)
+      (setq web-mode-highlight-beg nil
+            web-mode-highlight-end nil)
+      )
+     (t
+;;      (message "ici")
+      (setq font-lock-beg (or (web-mode-previous-tag-at-bol-pos font-lock-beg)
+                              (point-min))
+            font-lock-end (or (web-mode-next-tag-at-eol-pos font-lock-end)
+                              (point-max)))
+      ) ;t
+     ) ;cond
+    nil))
+
+(defun web-mode-font-lock-highlight (limit)
+  "font-lock matcher"
+;;  (message "highlight : point=%S limit=%S" (point) limit)
+  (let ((inhibit-modification-hooks t)
+        (buffer-undo-list t))
+    (web-mode-highlight-region (point) limit)
+    ) ;let
+  nil)
 
 ;;;###autoload
 (define-derived-mode web-mode web-mode-prog-mode "Web"
   "Major mode for editing web templates (HTML documents with embedded parts and blocks)."
 
-  (make-local-variable 'after-change-functions)
-  (make-local-variable 'fill-paragraph-function)
-  (make-local-variable 'font-lock-fontify-buffer-function)
-  (make-local-variable 'font-lock-keywords)
-  (make-local-variable 'font-lock-multiline)
-  (make-local-variable 'font-lock-unfontify-buffer-function)
-  (make-local-variable 'imenu-case-fold-search)
-  (make-local-variable 'imenu-create-index-function)
-  (make-local-variable 'imenu-generic-expression)
-  (make-local-variable 'indent-line-function)
-
   (make-local-variable 'web-mode-auto-pairs)
   (make-local-variable 'web-mode-buffer-highlighted)
+  (make-local-variable 'web-mode-change-flags)
   (make-local-variable 'web-mode-comment-style)
   (make-local-variable 'web-mode-content-type)
   (make-local-variable 'web-mode-display-table)
   (make-local-variable 'web-mode-engine)
+  (make-local-variable 'web-mode-engine-attr-regexp)
+  (make-local-variable 'web-mode-engine-token-regexp)
   (make-local-variable 'web-mode-block-regexps)
   (make-local-variable 'web-mode-enable-block-face)
+  (make-local-variable 'web-mode-enable-inlays)
   (make-local-variable 'web-mode-enable-part-face)
   (make-local-variable 'web-mode-engine-file-regexps)
   (make-local-variable 'web-mode-expand-initial-pos)
   (make-local-variable 'web-mode-expand-previous-state)
-  (make-local-variable 'web-mode-has-any-large-block)
-  (make-local-variable 'web-mode-has-any-large-part)
+  (make-local-variable 'web-mode-highlight-beg)
+  (make-local-variable 'web-mode-highlight-end)
   (make-local-variable 'web-mode-hl-line-mode-flag)
   (make-local-variable 'web-mode-indent-style)
   (make-local-variable 'web-mode-is-narrowed)
+  (make-local-variable 'web-mode-jshint-errors)
   (make-local-variable 'web-mode-block-regexp)
   (make-local-variable 'web-mode-start-tag-overlay)
   (make-local-variable 'web-mode-end-tag-overlay)
   (make-local-variable 'web-mode-time)
 
-  (if (and (fboundp 'global-hl-line-mode)
-           global-hl-line-mode)
-      (setq web-mode-hl-line-mode-flag t))
+  (make-local-variable 'fill-paragraph-function)
+  (make-local-variable 'font-lock-beg)
+  (make-local-variable 'font-lock-defaults)
+  (make-local-variable 'font-lock-end)
+  (make-local-variable 'font-lock-extend-region-functions)
+  (make-local-variable 'font-lock-maximum-size)
+  (make-local-variable 'font-lock-support-mode)
+  (make-local-variable 'imenu-case-fold-search)
+  (make-local-variable 'imenu-create-index-function)
+  (make-local-variable 'imenu-generic-expression)
+  (make-local-variable 'indent-line-function)
+  (make-local-variable 'parse-sexp-lookup-properties)
+  (make-local-variable 'text-property-default-nonsticky)
+  (make-local-variable 'yank-excluded-properties)
+
+  (add-to-list 'text-property-default-nonsticky '(block-token . t))
+;;  (add-to-list 'text-property-default-nonsticky '((block-token . t)
+;;                                                  (tag-end . t)))
 
   (setq fill-paragraph-function 'web-mode-fill-paragraph
-        font-lock-fontify-buffer-function 'web-mode-scan-buffer
-        font-lock-unfontify-buffer-function 'web-mode-scan-buffer
+        font-lock-defaults '(web-mode-font-lock-keywords t)
+        font-lock-extend-region-functions '(web-mode-font-lock-extend-region)
+        font-lock-support-mode nil
+        font-lock-maximum-size nil
+        ;;        font-lock-fontify-buffer-function 'web-mode-scan-buffer
+        ;;        font-lock-unfontify-buffer-function 'web-mode-scan-buffer
         imenu-case-fold-search t
         imenu-create-index-function 'web-mode-imenu-index
-        indent-line-function 'web-mode-indent-line)
+        indent-line-function 'web-mode-indent-line
+        parse-sexp-lookup-properties t
+        yank-excluded-properties t)
 
-  (remove-hook 'after-change-functions 'font-lock-after-change-function t)
+;;  (remove-hook 'after-change-functions 'font-lock-after-change-function t)
+
+  (if (and (fboundp 'global-hl-line-mode)
+           global-hl-line-mode)
+      (setq web-mode-hl-line-mode-flag t))
 
   (when web-mode-enable-current-element-highlight
-    (add-hook 'post-command-hook 'web-mode-hightlight-current-element nil t))
+    (add-hook 'post-command-hook 'web-mode-highlight-current-element nil t))
 
-  (add-hook 'after-change-functions 'web-mode-on-after-change t t)
+  ;; (add-hook 'post-command-hook
+  ;;           '(lambda()
+  ;;              (message "this command %S" this-command)
+  ;;              )
+  ;;           nil t)
+
+  (add-hook 'after-change-functions  'web-mode-on-after-change nil t)
+  (add-hook 'before-change-functions 'web-mode-on-before-change nil t)
+  (add-hook 'change-major-mode-hook  'web-mode-on-exit nil t)
 
   (add-hook 'after-save-hook
             '(lambda ()
@@ -1758,6 +2115,7 @@ Must be used in conjunction with web-mode-enable-block-face."
                  )
                nil)
             t t)
+
   (cond
    ((boundp 'yas-after-exit-snippet-hook)
     (add-hook 'yas-after-exit-snippet-hook
@@ -1772,39 +2130,16 @@ Must be used in conjunction with web-mode-enable-block-face."
   (when web-mode-enable-whitespaces
     (web-mode-whitespaces-on))
 
-  (when (boundp 'esk-pretty-lambdas) (esk-pretty-lambdas -1))
-  (when (boundp 'esk-add-watchwords) (esk-add-watchwords -1))
-  (when (boundp 'global-whitespace-mode) (global-whitespace-mode -1))
-  (when (boundp 'idle-highlight-mode) (idle-highlight-mode -1))
-  (when (boundp 'rainbow-mode) (rainbow-mode -1))
-  (when (boundp 'whitespace-mode) (whitespace-mode -1))
-
   (web-mode-guess-engine-and-content-type)
-  (web-mode-scan-buffer)
+  (web-mode-scan-region (point-min) (point-max))
 
   )
 
 (defun web-mode-yasnippet-exit-hook ()
   "Yasnippet exit hook"
-  (web-mode-scan-region yas-snippet-beg yas-snippet-end)
-  (indent-region yas-snippet-beg yas-snippet-end))
-
-(defun web-mode-forward-sexp (&optional arg)
-  "Move forward."
-  (interactive "p")
-  (unless arg (setq arg 1))
-  (cond
-   ((> arg 0)
-    (while
-        (progn
-          (web-mode-tag-next)
-          (> (setq arg (1- arg)) 0))))
-   ((< arg 0)
-    (while
-        (progn
-          (web-mode-tag-previous)
-          (< (setq arg (1+ arg)) 0))))
-   ))
+  (when (and (boundp 'yas-snippet-beg) (boundp 'yas-snippet-end))
+;;    (web-mode-highlight-region yas-snippet-beg yas-snippet-end)
+    (indent-region yas-snippet-beg yas-snippet-end)))
 
 (defun web-mode-set-engine (engine)
   "set engine"
@@ -1820,32 +2155,18 @@ Must be used in conjunction with web-mode-enable-block-face."
   (web-mode-on-engine-setted)
   (web-mode-scan-buffer))
 
+(defun web-mode-set-content-type (content-type)
+  "set engine"
+  (setq web-mode-content-type content-type)
+  ;;  (web-mode-on-engine-setted)
+  (web-mode-scan-buffer))
+
 (defun web-mode-on-engine-setted ()
   "engine setted"
-  (let (elt elts)
-;;    (when (string= web-mode-engine "razor") (setq web-mode-enable-block-face t))
-    (cond
-     ((member web-mode-content-type '("css" "javascript" "json"))
-      (setq web-mode-has-any-large-part t))
-     ((member web-mode-content-type '("php"))
-      (setq web-mode-has-any-large-block nil))
-     );cond
-
-    (setq web-mode-electric-chars nil)
-    (when (string= web-mode-content-type "html")
-      (unless (string= web-mode-engine "none")
-        (setq web-mode-active-block-regexp
-              (cdr (assoc web-mode-engine web-mode-active-block-regexps)))
-        (setq web-mode-close-block-regexp
-              (cdr (assoc web-mode-engine web-mode-close-block-regexps)))
-        (setq web-mode-engine-control-matcher
-              (intern-soft (concat "web-mode-match-" web-mode-engine "-block")))
-        )
-      (setq web-mode-electric-chars
-            (append '(?\<)
-                    (cdr (assoc web-mode-engine web-mode-block-electric-chars)))
-            )
-      );when
+  (let (elt elts engines)
+    (when (string= web-mode-engine "razor") (setq web-mode-enable-block-face t))
+    (setq web-mode-engine-attr-regexp (cdr (assoc web-mode-engine web-mode-engine-attr-regexps)))
+    (setq web-mode-engine-token-regexp (cdr (assoc web-mode-engine web-mode-engine-token-regexps)))
 
     (setq elt (assoc web-mode-engine web-mode-block-regexps))
     (if elt
@@ -1881,7 +2202,10 @@ Must be used in conjunction with web-mode-enable-block-face."
 
     (setq web-mode-closing-blocks (cdr (assoc web-mode-engine web-mode-engines-closing-blocks)))
 
-    ;;  (message "%S\n%S\n%S\n%S" web-mode-active-block-regexp web-mode-close-block-regexp web-mode-engine-control-matcher web-mode-electric-chars)
+    (setq web-mode-engine-font-lock-keywords
+          (symbol-value (cdr (assoc web-mode-engine web-mode-engines-font-lock-keywords))))
+
+;;    (message "%S" (symbol-value (cdr (assoc web-mode-engine web-mode-engines-font-lock-keywords))))
 
     ))
 
@@ -1892,6 +2216,7 @@ Must be used in conjunction with web-mode-enable-block-face."
     (unless buff-name (setq buff-name (buffer-name)))
     (setq web-mode-is-scratch (string= buff-name "*scratch*"))
     (setq web-mode-content-type nil)
+
     (when (boundp 'web-mode-content-types-alist)
       (setq found nil)
       (dolist (elt web-mode-content-types-alist)
@@ -1911,16 +2236,21 @@ Must be used in conjunction with web-mode-enable-block-face."
     (when (boundp 'web-mode-engines-alist)
       (setq found nil)
       (dolist (elt web-mode-engines-alist)
-        (when (string-match-p (cdr elt) buff-name)
-          (setq web-mode-engine (car elt)))
-        )
-      )
+        (cond
+         ((stringp (cdr elt))
+          (when (string-match-p (cdr elt) buff-name)
+            (setq web-mode-engine (car elt))))
+         ((functionp (cdr elt))
+          (when (funcall (cdr elt))
+            (setq web-mode-engine (car elt))))
+         ) ;cond
+        ) ;dolist
+      ) ;when
     (unless web-mode-engine
       (setq found nil)
       (dolist (elt web-mode-engine-file-regexps)
 ;;          (message "%S %S" (cdr elt) buff-name)
         (when (and (not found) (string-match-p (cdr elt) buff-name))
-
           (setq web-mode-engine (car elt)
                 found t))
         )
@@ -1941,179 +2271,378 @@ Must be used in conjunction with web-mode-enable-block-face."
             found t)
       )
 
+    (when (and (string= web-mode-content-type "javascript")
+               (string-match-p "@jsx"
+                                (buffer-substring-no-properties
+                                 (point-min)
+                                 (if (< (point-max) 16) (point-max) 16)
+                                 )))
+      (setq web-mode-content-type "jsx"))
+
     (web-mode-on-engine-setted)
     ))
 
 (defun web-mode-imenu-index ()
-  "Return a table of contents."
-  (let (toc-index)
+  (interactive)
+  "return imenu items"
+  (let (toc-index
+        line)
     (save-excursion
       (goto-char (point-min))
-      (while (re-search-forward "<h\\([1-9]\\)\\([^>]*\\)>\\([^<]*\\)" nil t)
-	(setq toc-index
-	      (cons (cons (concat (make-string
-				   (* 2 (1- (string-to-number (match-string 1))))
-				   ?\s)
-				  (match-string 3))
-			  (line-beginning-position))
-		    toc-index))))
+      (while (not (eobp))
+        (setq line (buffer-substring-no-properties
+                    (line-beginning-position)
+                    (line-end-position)))
+
+        (let (found
+              (i 0)
+              item
+              regexp
+              type
+              type-idx
+              content
+              content-idx
+              content-regexp
+              close-tag-regexp
+              concat-str
+              jumpto
+              str)
+          (while (and (not found ) (< i (length web-mode-imenu-regexp-list)))
+            (setq item (nth i web-mode-imenu-regexp-list))
+            (setq regexp (nth 0 item))
+            (setq type-idx (nth 1 item))
+            (setq content-idx (nth 2 item))
+            (setq concat-str (nth 3 item))
+            (when (not (numberp content-idx))
+              (setq content-regexp (nth 2 item)
+                    close-tag-regexp (nth 4 item)
+                    content-idx nil))
+
+            (when (string-match regexp line)
+
+              (cond
+               (content-idx
+                (setq type (match-string type-idx line))
+                (setq content (match-string content-idx line))
+                (setq str (concat type concat-str content))
+                (setq jumpto (line-beginning-position)))
+               (t
+                (let (limit )
+                  (setq type (match-string type-idx line))
+                  (goto-char (line-beginning-position))
+                  (save-excursion
+                    (setq limit (re-search-forward close-tag-regexp (point-max) t)))
+
+                  (when limit
+                    (when (re-search-forward content-regexp limit t)
+                      (setq content (match-string 1))
+                      (setq str (concat type concat-str content))
+                      (setq jumpto (line-beginning-position))
+                      )
+                    )))
+               )
+              (when str (setq toc-index
+                              (cons (cons str jumpto)
+                                    toc-index)
+                              )
+                    (setq found t))
+              )
+            (setq i (1+ i))))
+        (forward-line)
+        (goto-char (line-end-position)) ;; make sure we are at eobp
+        ))
+    ;; (message "toc-index=%s" toc-index)
     (nreverse toc-index)))
 
 (defun web-mode-scan-buffer ()
   "Scan entine buffer."
   (interactive)
-  (web-mode-scan-region (point-min) (point-max)))
+  (web-mode-scan-region (point-min) (point-max))
+  (font-lock-fontify-buffer))
 
 (defun web-mode-scan-region (beg end &optional content-type)
-  "Identify code blocks (client/server) and syntactic symbols (strings/comments)."
+  "Identify nodes/parts/blocks and syntactic symbols (strings/comments)."
   (interactive)
-  (web-mode-trace "scanning region")
-;;  (message "scanning buffer from %d to %d" beg end)
+;;  (message "scan: beg(%d) end(%d) ct(%S)" beg end content-type)
   (web-mode-with-silent-modifications
    (save-excursion
      (save-restriction
        (save-match-data
-         (let ((inhibit-modification-hooks t)
-               (inhibit-point-motion-hooks t)
+         (let ((inhibit-point-motion-hooks t)
                (inhibit-quit t))
            (setq beg (if web-mode-is-narrowed 1 beg))
-
+           (remove-text-properties beg end web-mode-scan-properties)
            (cond
-
-            ((member web-mode-content-type '("javascript" "json" "css"))
-             (remove-text-properties beg end web-mode-text-properties2)
-             (web-mode-scan-part beg end web-mode-content-type))
-
-            ((string= web-mode-engine "none")
-             (remove-text-properties beg end web-mode-text-properties2)
-             (web-mode-scan-parts beg end)
-             (web-mode-trace "parts scanned")
+            ((and content-type (string= content-type "php"))
+;;             (web-mode-scan-block beg end)
              )
-
-            ((and content-type (member content-type '("css")))
-             (remove-text-properties beg end web-mode-text-properties2)
-             (web-mode-mark-blocks beg end)
-             (web-mode-scan-part beg end "css")
+            ((and content-type
+                  (member content-type '("javascript" "json" "jsx" "css")))
+             (put-text-property beg end 'part-side
+                                (cond
+                                 ((string= content-type "javascript") 'javascript)
+                                 ((string= content-type "json") 'json)
+                                 ((string= content-type "jsx") 'jsx)
+                                 ((string= content-type "css") 'css)
+                                 ))
+             (web-mode-scan-part beg end content-type)
+             )
+            ((member web-mode-content-type '("javascript" "json" "jsx" "css"))
              (web-mode-scan-blocks beg end)
+             (web-mode-scan-part beg end)
              )
-
-            ((and content-type (member content-type '("asp")))
-             (remove-text-properties beg end '(block-token nil font nil))
-             (web-mode-scan-block beg end)
+            ((string= web-mode-engine "none")
+             (web-mode-dom-scan beg end)
+             (web-mode-scan-parts beg end)
              )
-
             (t
-             (remove-text-properties beg end web-mode-text-properties)
-             (web-mode-mark-blocks beg end)
-             (web-mode-trace "blocks marked")
-             (web-mode-scan-parts beg end)
-             (web-mode-trace "parts scanned")
              (web-mode-scan-blocks beg end)
-             (web-mode-trace "blocks scanned")
-             (when (string= web-mode-engine "django")
-               (web-mode-scan-django-extra-comments beg end)
-               (web-mode-trace "extra")
-               );when
+             (web-mode-dom-scan beg end)
+             (web-mode-scan-parts beg end)
              )
+            ) ;cond
+           (web-mode-trace "web-mode-scan-region")
+           ))))))
 
-            );cond
-
-           (if web-mode-enable-whitespaces
-               (web-mode-scan-whitespaces beg end))
+(defun web-mode-highlight-region (beg end &optional content-type)
+  "Highlight region (relying on text-properties setted during the scanning phase)."
+  (interactive)
+;;  (message "highlight: beg(%S) end(%S) ct(%S)" beg end content-type)
+  (web-mode-with-silent-modifications
+   (save-excursion
+     (save-restriction
+       (save-match-data
+         (let ((inhibit-modification-hooks t)
+               (inhibit-point-motion-hooks t)
+               (inhibit-quit t))
+           (setq beg (if web-mode-is-narrowed 1 beg))
+           (remove-text-properties beg end '(font-lock-face nil))
+           (cond
+            ((= web-mode-change-flags 1)
+             (web-mode-highlight-block beg end)
+             )
+            ((= web-mode-change-flags 2)
+             (web-mode-highlight-part beg end)
+             )
+            ((or (member web-mode-content-type '("javascript" "json" "jsx" "css"))
+                 (member content-type '("javascript" "css")))
+             (web-mode-highlight-part beg end)
+             (when (member web-mode-content-type '("jsx"))
+               (web-mode-highlight-tags beg end))
+             (web-mode-highlight-blocks beg end))
+            ((string= web-mode-engine "none")
+             (web-mode-highlight-tags beg end)
+             (web-mode-highlight-parts beg end))
+            (t
+             (web-mode-highlight-tags beg end)
+             (web-mode-highlight-parts beg end)
+             (web-mode-highlight-blocks beg end))
+            ) ;cond
+           (when web-mode-enable-whitespaces
+             (web-mode-highlight-whitespaces beg end))
            ))))))
 
-(defun web-mode-mark-blocks (beg end)
+(defun web-mode-scan-blocks (reg-beg reg-end)
   "Identifies blocks (with block-side, block-beg, block-end text properties)."
   (save-excursion
 
-    (let ((i 0)
-          open close closing-string start sub1 sub2 pos tagopen l tmp)
+    (let ((i 0) open close closing-string start sub1 sub2 pos tagopen l tmp delim-open delim-close script-beg)
 
-      (goto-char beg)
+      (goto-char reg-beg)
 
-      ;;      (message "%S: %Sx%S" (point) beg end)
-      ;;      (message "regexp=%S" web-mode-block-regexp)
+      ;;     (message "%S: %Sx%S" (point) reg-beg reg-end)
+      ;;     (message "regexp=%S" web-mode-block-regexp)
       (while (and (< i 1200)
-                  (> end (point))
-                  (re-search-forward web-mode-block-regexp end t))
+                  (> reg-end (point))
+                  web-mode-block-regexp
+                  (re-search-forward web-mode-block-regexp reg-end t)
+                  (not (eobp)))
 
         (setq i (1+ i)
               closing-string nil
               close nil
               tagopen (match-string 0)
               open (match-beginning 0)
+              delim-open nil
+              delim-close nil
               pos nil)
         (setq l (length tagopen))
 
         (when (member (string-to-char tagopen) '(?\s ?\t))
           (setq tagopen (replace-regexp-in-string "\\`[ \t]*" "" tagopen))
+;;          (message "tagopen=%s (%S)" tagopen (point))
           (setq open (+ open (- l (length tagopen))))
           (setq l (length tagopen))
           )
 
+;;        (message "tagopen=%s (%S)" tagopen (point))
+
         (setq sub1 (substring tagopen 0 1)
               sub2 (substring tagopen 0 (if (>= l 2) 2 1)))
 
+
         (cond
 
          ((string= web-mode-engine "php")
-          (unless (looking-at-p "xml ")
-            (setq closing-string '("<\\?". "\\?>"))
-            )
-          );php
+          (unless (member (char-after) '(?x ?X))
+            (setq closing-string '("<\\?". "\\?>")))
+          (cond
+           ((eq (char-after) ?p)
+            (setq delim-open "<?php"))
+           ((eq (char-after) ?\=)
+            (setq delim-open "<?="))
+           (t
+            (setq delim-open "<?"))
+           ) ;cond
+          (setq delim-close "?>")
+          ) ;php
 
          ((string= web-mode-engine "django")
           (cond
            ((string= sub2 "{{")
-            (setq closing-string '("{{" . "}}")))
-;;            (setq closing-string "}}"))
+            (setq closing-string '("{{" . "}}")
+                  delim-open "{{"
+                  delim-close "}}"))
            ((string= sub2 "{%")
-            (setq closing-string "%}"))
+            (setq closing-string "%}"
+                  delim-open "{%[+]?"
+                  delim-close "%}"))
            (t
             (setq closing-string "#}"))
            )
-          );django
+          ) ;django
+
+         ((string= web-mode-engine "erb")
+          (cond
+           ((string= sub2 "<%")
+            (setq closing-string "%>"
+                  delim-open "<%[=-]?"
+                  delim-close "[-]?%>")
+            )
+           (t
+            (setq closing-string "EOL"
+                  delim-open "%"))
+           )
+          ) ;erb
+
+         ((string= web-mode-engine "lsp")
+          (setq closing-string "%>"
+                delim-open "<%[%#]?"
+                delim-close "%>")
+          ) ;lsp
+
+         ((string= web-mode-engine "mako")
+          (cond
+           ((member tagopen '("<% " "<%!"))
+            (setq closing-string "%>"
+                  delim-open "<%[!]?"
+                  delim-close "%>"))
+           ((member sub2 '("<%" "</"))
+            (setq closing-string ">"
+                  delim-open "</?%"
+                  delim-close "/?>"))
+           ((string= sub2 "${")
+            (setq closing-string "}"
+                  delim-open "${"
+                  delim-close "}"))
+           (t
+            (setq closing-string "EOL"
+                  delim-open "%"))
+           )
+          ) ;mako
+
+         ((string= web-mode-engine "mojolicious")
+          (cond
+           ((string= tagopen "<%#")
+            (setq closing-string "%>"))
+           ((string= sub2 "<%")
+            (setq closing-string "%>"
+                  delim-open "<%\\(==\\|[=%]\\)?"
+                  delim-close "%>"))
+           ((string= sub2 "%#")
+            (setq closing-string "EOL"))
+           (t
+            (setq closing-string "EOL"
+                  delim-open "%\\(==\\|[=%]\\)?"))
+           )
+          ) ;mojolicious
 
          ((string= web-mode-engine "ctemplate")
-          (setq closing-string "}}")
-          );ctemplate
+          (cond
+           ((string= tagopen "{{{")
+            (setq closing-string "}}}"
+                  delim-open "{{{"
+                  delim-close "}}}")
+            )
+           ((string= sub2 "{{")
+            (setq closing-string "}}"
+                  delim-open "{{[>#/%^&]?"
+                  delim-close "}}"))
+           (t
+            (setq closing-string "}}"
+                  delim-open "${{"
+                  delim-close "}}"))
+           )
+          ) ;ctemplate
 
          ((or (string= web-mode-engine "asp")
               (string= web-mode-engine "aspx"))
-          (setq closing-string "%>")
-          );asp
+          (setq closing-string "%>"
+                delim-open "<%[:=#@$]?"
+                delim-close "%>")
+          ) ;asp
 
          ((string= web-mode-engine "blade")
           (cond
            ((string= tagopen "{{-")
             (setq closing-string "--}}"))
            ((string= sub2 "{{")
-            (setq closing-string "}}"))
+            (setq closing-string "}}"
+                  delim-open "{{"
+                  delim-close "}}"))
            ((string= sub1 "@")
-            (setq closing-string "EOL"))
+            (setq closing-string "EOL"
+                  delim-open "@"))
            )
-          );blade
+          ) ;blade
 
          ((string= web-mode-engine "smarty")
           (cond
-           ((string= sub2 "{*")
-            (setq closing-string "*}"))
-           ((string= sub2 "{#")
-            (setq closing-string "#}"))
+           ((string= tagopen (concat (web-mode-engine-delimiter-open web-mode-engine "{") "*"))
+            (setq closing-string (concat "*" (web-mode-engine-delimiter-close web-mode-engine "}")))
+            )
+           ((string= tagopen (concat (web-mode-engine-delimiter-open web-mode-engine "{") "#"))
+            (setq closing-string (concat "#" (web-mode-engine-delimiter-close web-mode-engine "}"))
+                  delim-open (concat (web-mode-engine-delimiter-open web-mode-engine "{") "#")
+                  delim-close (concat "#" (web-mode-engine-delimiter-close web-mode-engine "}")))
+            )
            (t
-            (setq closing-string "}"))
-           )
-          );smarty
+            (setq closing-string (cons (web-mode-engine-delimiter-open web-mode-engine "{")
+                                       (web-mode-engine-delimiter-close web-mode-engine "}"))
+                  delim-open (concat (web-mode-engine-delimiter-open web-mode-engine "{") "/?")
+                  delim-close (web-mode-engine-delimiter-close web-mode-engine "}"))
+;;            (message "delim-open=%s delim-close=%s" delim-open delim-close)
+            ) ;t
+           ) ;cond
+          ) ;smarty
+
+         ((string= web-mode-engine "web2py")
+          (setq closing-string "}}"
+                delim-open "{{[=]?"
+                delim-close "}}")
+          ) ;web2py
 
          ((string= web-mode-engine "dust")
           (cond
            ((string= sub2 "{!")
             (setq closing-string "!}"))
            (t
-            (setq closing-string "}")
+            (setq closing-string "}"
+                  delim-open "{[#/:?@><+^]?"
+                  delim-close "/?}")
             )
            )
-          );dust
+          ) ;dust
 
          ((string= web-mode-engine "closure")
           (cond
@@ -2124,10 +2653,12 @@ Must be used in conjunction with web-mode-enable-block-face."
             (setq closing-string "*/")
             )
            (t
-            (setq closing-string "}")
+            (setq closing-string "}"
+                  delim-open "{/?"
+                  delim-close "/?}")
             )
            )
-          );closure
+          ) ;closure
 
          ((string= web-mode-engine "ctemplate")
           (cond
@@ -2136,59 +2667,105 @@ Must be used in conjunction with web-mode-enable-block-face."
            (t
             (setq closing-string "}}"))
            )
-          );ctemplate
+          ) ;ctemplate
 
          ((string= web-mode-engine "go")
-          (setq closing-string "}}")
-          );go
+          (setq closing-string "}}"
+                delim-open "{{"
+                delim-close "}}")
+          ) ;go
 
          ((string= web-mode-engine "angular")
-          (setq closing-string "}}")
-          );angular
+          (setq closing-string "}}"
+                delim-open "{{"
+                delim-close "}}")
+          ) ;angular
 
-         ((string= web-mode-engine "erb")
+         ((string= web-mode-engine "mason")
           (cond
-           ((string= sub2 "<%")
-            (setq closing-string "%>"))
+           ((and (member sub2 '("<%" "</"))
+                 ;;                 (progn (message "%S" (point)) t)
+                 (looking-at "[[:alpha:]]+"))
+            ;;(member tagopen '("<%def" "</%def" "<%method" "</%method"))
+            (if (member (match-string-no-properties 0) '("def" "method"))
+                (setq closing-string ">"
+                      delim-open "<[^>]+>")
+              (setq closing-string (concat "</%" (match-string-no-properties 0) ">")
+                    delim-open "<[^>]+>"
+                    delim-close "<[^>]+>")
+              ) ;if
+;;            (message "closing-string=%S" closing-string)
+            )
+           ((and (string= sub2 "<%")
+                 (eq (char-after) ?\s))
+            (setq closing-string "%>"
+                  delim-open "<%"
+                  delim-close "%>"))
+           ((string= tagopen "</&")
+            (setq closing-string ">"
+                  delim-open "</&"
+                  delim-close ">")
+            )
+           ((string= sub2 "<&")
+            (setq closing-string "&>"
+                  delim-open "<&[|]?"
+                  delim-close "&>"))
            (t
-            (setq closing-string "EOL"))
+            (setq closing-string "EOL"
+                  delim-open "%"))
            )
-          );erb
+          ) ;mason
 
          ((string= web-mode-engine "jsp")
           (cond
            ((string= sub2 "<%")
-            (setq closing-string "%>"))
+            (setq closing-string "%>"
+                  delim-open "<%\\([!=@]\\|#=\\)?"
+                  delim-close "[-]?%>"))
            ((string= sub2 "${")
-            (setq closing-string "}"))
+            (setq closing-string "}"
+                  delim-open "${"
+                  delim-close "}"))
            (t
-            (setq closing-string ">"))
+            (setq closing-string ">"
+                  delim-open "</?"
+                  delim-close "/?>"))
            )
-          );jsp
+          ) ;jsp
 
          ((string= web-mode-engine "underscore")
-          (setq closing-string "%>")
-          );underscore
+          (setq closing-string "%>"
+                delim-open "<%"
+                delim-close "%>")
+          ) ;underscore
 
          ((string= web-mode-engine "template-toolkit")
           (cond
            ((string= sub2 "[#")
             (setq closing-string "#]"))
            (t
-            (setq closing-string "%]"))
+            (setq closing-string "%]"
+                  delim-open "\\[%[-+]?"
+                  delim-close "[-=+]?%\\]"))
            )
-          );underscore
+          ) ;template-toolkit
 
          ((string= web-mode-engine "freemarker")
           (cond
            ((string= sub1 "<")
-            (setq closing-string ">"))
+            (setq closing-string ">"
+                  delim-open "</?[#@]?"
+                  delim-close "/?>"))
            ((string= sub1 "[")
-            (setq closing-string "]"))
+            (setq closing-string "]"
+                  delim-open "\\[/?[#@]"
+                  delim-close "/?\\]"))
            (t
-            (setq closing-string "}"))
+            (setq closing-string "}"
+                  delim-open "${"
+                  delim-close "}"))
            )
-          );freemarker
+          ) ;freemarker
 
          ((string= web-mode-engine "velocity")
           (cond
@@ -2197,11 +2774,13 @@ Must be used in conjunction with web-mode-enable-block-face."
            ((string= sub2 "#*")
             (setq closing-string "*#"))
            (t
-            (setq closing-string "EOV"))
+            (setq closing-string "EOV"
+                  delim-open "#"))
            )
-          );velocity
+          ) ;velocity
 
          ((string= web-mode-engine "razor")
+;;          (message "sub2=%S" sub2)
           (cond
            ((string= sub2 "@@")
             (forward-char 2)
@@ -2209,37 +2788,59 @@ Must be used in conjunction with web-mode-enable-block-face."
            ((string= sub2 "@*")
             (setq closing-string "*@"))
            ((string= sub1 "@")
-            (setq closing-string "EOR"))
+            (setq closing-string "EOR"
+                  delim-open "@"))
            ((string= sub1 "}")
-            (setq closing-string "EOR"))
-           )
-          );razor
-
-         ((string= web-mode-engine "python")
-          (unless (looking-at-p "xml ")
-            (setq closing-string "?>"))
-          );python
-
-         );cond
+            (save-excursion
+              (let (paren-pos)
+                (setq paren-pos (web-mode-opening-paren-position (1- (point))))
+                (if (and paren-pos (get-text-property paren-pos 'block-side))
+                    (setq closing-string "EOR")
+                  (setq closing-string nil)
+                  ) ;if
+                ) ;let
+              ) ;let
+            ) ; case }
+           ) ;cond
+          ) ;razor
+
+         ) ;cond
 
         (when closing-string
 
           (cond
 
            ((listp closing-string)
-            (if (web-mode-rsf-balanced (car closing-string) (cdr closing-string) end t)
-                (progn
-                  (setq close (match-end 0)
-                        pos (point))
-;;                  (message "close=%S pos=%S" close pos)
-                  )
-              (when (string= "<?" sub2)
-                (setq close (point-max)
+;;            (message "point=%S sub2=%S" (point) sub2)
+            (if (web-mode-rsf-balanced (car closing-string) (cdr closing-string) reg-end t)
+                (setq close (match-end 0)
+                      pos (point))
+              (when (and (string= web-mode-engine "php")
+                         (string= "<?" sub2))
+                (setq close (if (looking-at-p "[ \t\n]*<")
+                                (line-end-position)
+                              (point-max))
+                      delim-close nil
                       pos (point-max)))
-              )
+              ) ;if
+            )
+
+           ((and (string= web-mode-engine "smarty")
+                 (string= closing-string (web-mode-engine-delimiter-close web-mode-engine "}")))
+            (goto-char open)
+            (setq tmp (web-mode-closing-delimiter-position
+                       (web-mode-engine-delimiter-close web-mode-engine "}")
+                       (point)
+                       (line-end-position)))
+            (if tmp
+                (setq tmp (1+ tmp))
+              (setq tmp (line-end-position)))
+            (goto-char tmp)
+            (setq close (point)
+                  pos (point))
             )
 
-           ((and (member web-mode-engine '("closure" "dust" "smarty"))
+           ((and (member web-mode-engine '("closure" "dust"))
                  (string= closing-string "}"))
             (goto-char open)
             (setq tmp (web-mode-closing-paren-position (point) (line-end-position)))
@@ -2258,4184 +2859,5308 @@ Must be used in conjunction with web-mode-enable-block-face."
 
            ((string= closing-string "EOR")
             (web-mode-razor-skip-forward open)
-;;            (message "%S > %S" open (point))
-            (setq close (point)
-                  pos (point)))
+            (setq close (if (> (point) reg-end) reg-end (point))
+                  pos (if (> (point) reg-end) reg-end (point)))
+            (goto-char pos)
+;;            (message "pos=%S close=%S" pos close)
+            )
 
            ((string= closing-string "EOV")
             (web-mode-velocity-skip-forward open)
             (setq close (point)
                   pos (point)))
 
-           ((search-forward closing-string end t)
+           ((search-forward closing-string reg-end t)
             (setq close (match-end 0)
-                  pos (point)))
+                  pos (point))
+            )
 
-           );cond
+           ) ;cond
 
-          (when (and close (>= end pos))
+          (when (and close (>= reg-end pos))
             ;;(message "pos(%S) : open(%S) close(%S)" pos open close)
-            (add-text-properties open close '(block-side t))
-            (put-text-property open (1+ open) 'block-beg t)
+            (put-text-property open close 'block-side t)
+            (put-text-property open (1+ open) 'block-beg 0)
+            (put-text-property open (1+ open) 'block-controls 0)
             (put-text-property (1- close) close 'block-end t)
-            (when (string= web-mode-engine "razor")
-              (web-mode-razor-tag-exclude open close)
-              )
+            (when delim-open
+              (web-mode-block-delimiters-set open close delim-open delim-close))
+            (web-mode-scan-block open close)
+            ) ;when close
+
+          (when (string= tagopen "<r:script")
+            (setq script-beg close)
             )
+          (when (and script-beg (string= tagopen "</r:script"))
+            (put-text-property script-beg open 'part-side 'javascript)
+            (setq script-beg nil))
 
           (if pos (goto-char pos))
 
-          );when closing-string
+          ) ;when closing-string
 
-        );while
+        ) ;while
 
-      (when (>= i 1200)
-        (message "** strange loop (web-mode-mark-blocks) **"))
+      (cond
+       ((>= i 1200)
+        (message "** strange loop (web-mode-scan-blocks) **"))
+       ((string= web-mode-engine "razor")
+        (web-mode-process-blocks reg-beg reg-end "scan"))
+       ((string= web-mode-engine "django")
+        (web-mode-scan-django-block-comments reg-beg reg-end))
+       ((string= web-mode-engine "mako")
+        (web-mode-scan-mako-block-comments reg-beg reg-end))
+       ) ;cond
 
       )))
 
-(defun web-mode-scan-django-extra-comments (reg-beg reg-end)
-  "Scan extra"
-  (save-excursion
-    (let (beg end)
+(defun web-mode-block-delimiters-set (reg-beg reg-end delim-open delim-close)
+  "Set text-property 'block-token to 'delimiter on block delimiters (e.g. <?php ?>)"
+;;  (message "reg-beg(%S) reg-end(%S) delim-open(%S) delim-close(%S)" reg-beg reg-end delim-open delim-close)
+  (when (member web-mode-engine '("asp" "aspx" "closure" "ctemplate" "django" "dust"
+                                  "erb" "freemarker" "jsp" "lsp" "mako" "mason" "mojolicious"
+                                  "smarty" "template-toolkit" "web2py"))
+    (save-excursion
       (goto-char reg-beg)
-      (while (and (< (point) reg-end)
-                  (re-search-forward "{% comment %}" reg-end t))
-        ;;        (message "pt=%S" (point))
-        (setq beg (point))
-        (goto-char (1+ (match-beginning 0)))
-        (when (web-mode-match-django-block)
-          (setq end (1- (point)))
-          (remove-text-properties beg end web-mode-text-properties)
-          (add-text-properties beg end '(block-token comment face web-mode-comment-face))
-          )
-        )
-      )))
+      (looking-at delim-open)
+      (setq delim-open (match-string-no-properties 0))
+      (goto-char reg-end)
+      (looking-back delim-close reg-beg t)
+      (setq delim-close (match-string-no-properties 0))
+      ))
+;;  (message "reg-beg(%S) reg-end(%S) delim-open(%S) delim-close(%S)" reg-beg reg-end delim-open delim-close)
+  (put-text-property reg-beg (+ reg-beg (length delim-open)) 'block-token 'delimiter)
+  (when delim-close
+;;    (message "%S > %S" (- reg-end (length delim-close)) reg-end)
+    (put-text-property (- reg-end (length delim-close)) reg-end 'block-token 'delimiter)
+    ))
+
+(defun web-mode-highlight-blocks (reg-beg reg-end)
+  "Highlight blocks."
+  (web-mode-process-blocks reg-beg reg-end "highlight"))
 
-(defun web-mode-scan-blocks (region-beg region-end)
-  "Fontify blocks. The scan relies on the 'block-beg text property."
-  (let ((i 0)
-        (comment nil)
-        (beg region-beg)
-        (end nil)
-        (continue t))
+;;todo : passer en funcall
+(defun web-mode-process-blocks (reg-beg reg-end type)
+  "Process blocks. The scan relies on the 'block-beg and 'block-end text-properties."
+  (let ((i 0) (continue t) (block-beg reg-beg) (block-end nil))
     (while continue
-      (setq end nil
+      (setq block-end nil
             i (1+ i))
-      (unless (get-text-property beg 'block-beg)
-        (setq beg (web-mode-block-next-position beg)))
-      (when (and beg (< beg region-end))
-        (setq end (web-mode-block-end-position beg)))
+      (unless (get-text-property block-beg 'block-beg)
+        (setq block-beg (web-mode-block-next-position block-beg)))
+      (when (and block-beg (< block-beg reg-end))
+        (setq block-end (web-mode-block-end-position block-beg)))
       (cond
-       ((or (null end)
-            (> end region-end)
-            (> i 1200))
+       ((or (null block-end) (> block-end reg-end) (> i 1200))
         (setq continue nil)
-        (if (> i 1200) (message "*** invalid loop (web-mode-scan-blocks) ***")))
+        (if (> i 1200) (message "*** invalid loop (web-mode-process-blocks) ***")))
        (t
-        (setq end (1+ end))
-        ;;(message "beg=%S end=%S" beg end)
-
-        (when (and (not web-mode-has-any-large-block)
-                   (> (- end beg) web-mode-large-embed-threshold))
-;;          (message "** large block detected [ %S - %S ] **" beg end)
-          (setq web-mode-has-any-large-block t))
-
-        (web-mode-scan-block beg end)
-        (when (and (member web-mode-engine '("jsp"))
-                   (> (- end beg) 12)
-                   (eq ?\< (char-after beg)))
-          (web-mode-scan-jsp-tag beg end))
-        (setq beg end)
-        )
-       );cond
-      );while
-
+        (setq block-end (1+ block-end))
+        (cond
+         ((string= type "scan")
+          (web-mode-scan-block block-beg block-end))
+         (t
+          (web-mode-highlight-block block-beg block-end))
+         )
+        (setq block-beg block-end)
+        )
+       ) ;cond
+      ) ;while
     ))
 
-(defun web-mode-scan-block (beg end)
-  "Fontify a block."
-  (let ((sub1 "") (sub2 "") (sub3 "") regexp props start ms continue fc keywords tag token-type hddeb hdend hdflk)
-;;    (message "beg=%S end=%S" beg end)
-;;    (remove-text-properties beg end web-mode-text-properties)
+(defun web-mode-scan-parts (reg-beg reg-end)
+  "Scan parts."
+  (web-mode-process-parts reg-beg reg-end "scan"))
 
-    (goto-char beg)
+(defun web-mode-highlight-parts (reg-beg reg-end)
+  "Highlight parts."
+  (web-mode-process-parts reg-beg reg-end "highlight"))
+
+;;todo : passer en funcall
+(defun web-mode-process-parts (reg-beg reg-end type)
+  "Process parts. The scan relies on the 'part-side text-property."
+  (let ((i 0) (continue t) (part-beg reg-beg) (part-end nil))
+    (while continue
+      (setq part-end nil
+            i (1+ i))
+      (unless (get-text-property part-beg 'part-side)
+        (setq part-beg (web-mode-part-next-position part-beg)))
+      (when (and part-beg (< part-beg reg-end))
+        (setq part-end (web-mode-part-end-position part-beg)))
+      (cond
+       ((or (null part-end) (> part-end reg-end) (> i 1200))
+        (setq continue nil)
+        (if (> i 1200) (message "*** invalid loop (web-mode-process-parts) ***")))
+       (t
+        (setq part-end (1+ part-end))
+        (cond
+         ((string= type "scan")
+          (web-mode-scan-part part-beg part-end))
+         (t
+          (web-mode-highlight-part part-beg part-end))
+         )
+        (setq part-beg part-end)
+        )
+       ) ;cond
+      ) ;while
+    ))
+
+(defun web-mode-scan-block (block-beg block-end)
+  "Scan a block."
+  (let (sub1 sub2 sub3 regexp token-type)
+
+    ;;(message "block-beg=%S block-end=%S" block-beg block-end)
+    ;;(remove-text-properties block-beg block-end web-mode-scan-properties)
+
+    (goto-char block-beg)
 
-    (setq sub1 (buffer-substring-no-properties beg (+ beg 1))
-          sub2 (buffer-substring-no-properties beg (+ beg 2)))
-    (setq sub3 sub2)
-    (if (>= (point-max) (+ beg 3))
-        (setq sub3 (buffer-substring-no-properties beg (+ beg 3))))
+    (cond
+     ((>= (point-max) (+ block-beg 3))
+      (setq sub3 (buffer-substring-no-properties block-beg (+ block-beg 3))
+            sub2 (buffer-substring-no-properties block-beg (+ block-beg 2))
+            sub1 (buffer-substring-no-properties block-beg (+ block-beg 1)))
+      )
+     ((>= (point-max) (+ block-beg 2))
+      (setq sub3 (buffer-substring-no-properties block-beg (+ block-beg 2))
+            sub2 (buffer-substring-no-properties block-beg (+ block-beg 2))
+            sub1 (buffer-substring-no-properties block-beg (+ block-beg 1)))
+      )
+     (t
+      (setq sub1 (buffer-substring-no-properties block-beg (+ block-beg 1)))
+      (setq sub2 sub1
+            sub3 sub1)
+      )
+     )
 
     (cond
 
-     ((string= web-mode-engine "php")
-      (setq regexp "//\\|/\\*\\|\"\\|'\\|<<<['\"]?\\([[:alnum:]]+\\)['\"]?"
-            props '(face nil)
-            keywords web-mode-php-font-lock-keywords)
-      );php
+     ((member web-mode-engine '("php" "asp" "lsp" "mako" "python" "web2py" "mason"))
+      (setq regexp web-mode-engine-token-regexp) ;; "//\\|/\\*\\|#\\|\"\\|'\\|<<<['\"]?\\([[:alnum:]]+\\)['\"]?")
+      ) ;php
 
      ((string= web-mode-engine "django")
       (cond
-       ((string= sub2 "{{")
-        (setq regexp "\"\\|'"
-              props '(face nil)
-              keywords web-mode-django-expr-font-lock-keywords)
-        )
-       ((string= sub2 "{%")
-        (setq regexp "\"\\|'"
-              props '(face nil)
-              keywords web-mode-django-code-font-lock-keywords)
-        )
+       ((member sub2 '("{{" "{%"))
+        (setq regexp "\"\\|'"))
        ((string= sub2 "{#")
-        (setq props '(block-token comment face web-mode-comment-face))
-        )
+        (setq token-type 'comment))
        )
-      );django
+      ) ;django
 
-     ((string= web-mode-engine "ctemplate")
+    ((string= web-mode-engine "ctemplate")
       (cond
-       ((string= sub3 "{{!")
-        (setq props '(block-token comment face web-mode-comment-face)))
        ((string= sub3 "{{%")
-        (setq regexp "\"\\|'"
-              props '(face nil)
-              keywords web-mode-ctemplate-font-lock-keywords))
-       (t
-        (setq props '(face nil)
-              keywords web-mode-ctemplate-font-lock-keywords))
+        (setq regexp "\"\\|'"))
+       ((string= sub3 "{{!")
+        (setq token-type 'comment))
        )
-      );ctemplate
+      ) ;ctemplate
 
      ((string= web-mode-engine "go")
       (cond
        ((string= sub3 "{{/")
-        (setq props '(block-token comment face web-mode-comment-face)))
+        (setq token-type 'comment))
        ((string= sub2 "{{")
-        (setq regexp "\"\\|'"
-              props '(face nil)
-              keywords web-mode-go-font-lock-keywords))
+        (setq regexp "\"\\|'"))
        )
-      );go
+      ) ;go
 
      ((string= web-mode-engine "razor")
       (cond
        ((string= sub2 "@*")
-        (setq props '(block-token comment face web-mode-comment-face)))
+        (setq token-type 'comment))
        (t
-        (setq regexp "//\\|\"\\|'"
-              props '(face nil)
-              keywords web-mode-razor-font-lock-keywords))
+        (setq regexp "//\\|\"\\|'"))
        )
-      );razor
-
-     ((string= web-mode-engine "python")
-      (setq regexp "\"\\|'\\|#"
-            props '(face nil)
-            keywords web-mode-python-font-lock-keywords)
-      );python
+      ) ;razor
 
      ((string= web-mode-engine "blade")
       (cond
        ((string= sub3 "{{-")
-        (setq props '(block-token comment face web-mode-comment-face)))
+        (setq token-type 'comment))
+       (t
+        (setq regexp "\"\\|'"))
+       )
+      ) ;blade
+
+     ((string= web-mode-engine "mojolicious")
+      (cond
+       ((or (string= sub2 "%#") (string= sub3 "<%#"))
+        (setq token-type 'comment))
        (t
-        (setq regexp "\"\\|'"
-              props '(face nil)
-              keywords web-mode-blade-font-lock-keywords))
+        (setq regexp "\"\\|'"))
        )
-      );blade
+      ) ;mojolicious
 
      ((string= web-mode-engine "velocity")
       (cond
        ((member sub2 '("##" "#*"))
-        (setq props '(block-token comment face web-mode-comment-face)))
-       ((string= sub1 "$")
-        (setq regexp "\"\\|'"
-              props '(face nil)
-              keywords web-mode-velocity-font-lock-keywords))
-       ((string= sub1 "#")
-        (setq regexp "\"\\|'"
-              props '(face nil)
-              keywords web-mode-velocity-font-lock-keywords))
+        (setq token-type 'comment))
+       ((member sub1 '("$" "#"))
+        (setq regexp "\"\\|'"))
        )
-      );velocity
+      ) ;velocity
 
      ((string= web-mode-engine "jsp")
       (cond
        ((string= sub3 "<%-")
-        (setq props '(block-token comment face web-mode-comment-face)))
+        (setq token-type 'comment))
        ((string= sub3 "<%@")
-        (setq regexp "/\\*"
-              props '(face nil)
-              keywords web-mode-directive-font-lock-keywords))
+        (setq regexp "/\\*"))
        ((member sub2 '("${" "#{"))
-        (setq regexp "\"\\|'"
-              props '(face nil)
-              keywords web-mode-uel-font-lock-keywords))
+        (setq regexp "\"\\|'"))
        ((string= sub2 "<%")
-        (setq regexp "//\\|/\\*\\|\"\\|'"
-              props '(face nil)
-              keywords web-mode-jsp-font-lock-keywords))
-       (t
-        (setq props '(face nil)
-              keywords web-mode-jsp-tag-font-lock-keywords)
-        )
+        (setq regexp "//\\|/\\*\\|\"\\|'"))
        )
-      );jsp
+      ) ;jsp
 
      ((string= web-mode-engine "freemarker")
       (cond
        ((member sub3 '("<#-" "[#-"))
-        (setq props '(block-token comment face web-mode-comment-face))
-        )
+        (setq token-type 'comment))
        ((member sub2 '("${" "#{"))
-        (setq regexp "\"\\|'"
-              props '(face nil)
-              keywords web-mode-uel-font-lock-keywords))
+        (setq regexp "\"\\|'"))
        ((or (member sub2 '("<@" "[@" "<#" "[#"))
             (member sub3 '("</@" "[/@" "</#" "[/#")))
-        (setq regexp "\""
-              props '(face nil)
-              keywords (if (eq ?\[ (aref sub2 0))
-                           web-mode-freemarker-square-font-lock-keywords
-                         web-mode-freemarker-font-lock-keywords))
-        )
-       (t
-        (setq props '(face nil)
-              keywords web-mode-jsp-tag-font-lock-keywords)
-        )
+        (setq regexp "\""))
        )
-      );freemarker
+      ) ;freemarker
 
      ((string= web-mode-engine "erb")
       (cond
        ((string= sub3 "<%#")
-        (setq props '(block-token comment face web-mode-comment-face)))
+        (setq token-type 'comment))
        (t
-        (setq regexp "\"\\|'\\|#\\|<<[-]?['\"]?\\([[:alnum:]_]+\\)['\"]?"
-              props '(face nil)
-              keywords web-mode-erb-font-lock-keywords)
-        )
+        (setq regexp "\"\\|'\\|#\\|<<[-]?['\"]?\\([[:alnum:]_]+\\)['\"]?"))
        )
-      );erb
-
-     ((string= web-mode-engine "asp")
-      (setq regexp "//\\|/\\*\\|\"\\|'"
-            props '(face nil)
-            keywords web-mode-asp-font-lock-keywords)
-      );asp
+      ) ;erb
 
 
      ((string= web-mode-engine "template-toolkit")
       (cond
        ((string= sub2 "[#")
-        (setq props '(block-token comment face web-mode-comment-face)))
+        (setq token-type 'comment))
        (t
-        (setq regexp "#\\|\"\\|'"
-              props '(face nil)
-              keywords web-mode-template-toolkit-font-lock-keywords)
-        )));template-toolkit
+        (setq regexp "#\\|\"\\|'"))
+       )
+      ) ;template-toolkit
 
      ((string= web-mode-engine "underscore")
-      (setq regexp "/\\*\\|\"\\|'"
-            props '(face nil)
-            keywords web-mode-underscore-font-lock-keywords)
-      );underscore
+      (setq regexp "/\\*\\|\"\\|'")
+      ) ;underscore
 
      ((string= web-mode-engine "angular")
-      (setq props '(face nil)
-            keywords web-mode-angular-font-lock-keywords)
-      );angular
+      ) ;angular
 
      ((string= web-mode-engine "aspx")
       (cond
        ((string= sub3 "<%-")
-        (setq props '(block-token comment face web-mode-comment-face)))
+        (setq token-type 'comment))
        ((string= sub3 "<%@")
-        (setq regexp "/\\*"
-              props '(face nil)
-              keywords web-mode-directive-font-lock-keywords))
+        (setq regexp "/\\*"))
        ((string= sub3 "<%$")
-        (setq regexp "\"\\|'"
-              props '(face nil)
-              keywords web-mode-expression-font-lock-keywords))
+        (setq regexp "\"\\|'"))
        (t
-        (setq regexp "//\\|/\\*\\|\"\\|'"
-              props '(face nil)
-              keywords web-mode-aspx-font-lock-keywords)
-        )
+        (setq regexp "//\\|/\\*\\|\"\\|'"))
        )
-      );aspx
+      ) ;aspx
 
      ((string= web-mode-engine "smarty")
       (cond
-       ((string= sub2 "{*")
-        (setq props '(block-token comment face web-mode-comment-face))
-        )
+       ((string= sub2 (concat (web-mode-engine-delimiter-open web-mode-engine "{") "*"))
+        (setq token-type 'comment))
        (t
-        (setq regexp "\"\\|'"
-              props '(face nil)
-              keywords web-mode-smarty-font-lock-keywords)
-        )
-       )
-      );smarty
+        (setq regexp "\"\\|'")))
+      ) ;smarty
 
      ((string= web-mode-engine "dust")
       (cond
        ((string= sub2 "{!")
-        (setq props '(block-token comment face web-mode-comment-face))
-        )
+        (setq token-type 'comment))
        (t
-        (setq regexp "\"\\|'"
-              props '(face nil)
-              keywords web-mode-dust-font-lock-keywords)
-        )
+        (setq regexp "\"\\|'"))
        )
-      );dust
+      ) ;dust
 
      ((string= web-mode-engine "closure")
       (cond
        ((member sub2 '("/*" "//"))
-        (setq props '(block-token comment face web-mode-comment-face))
-        )
+        (setq token-type 'comment))
        (t
-        (setq regexp "\"\\|'"
-              props '(face nil)
-              keywords web-mode-closure-font-lock-keywords)
-        )
+        (setq regexp "\"\\|'"))
        )
-      );closure
+      ) ;closure
 
-     )
+     ) ;cond
 
-    (add-text-properties beg end props)
+    (cond
+     (token-type
+      (put-text-property block-beg block-end 'block-token token-type)
+      (when (eq token-type 'comment)
+        (web-mode-block-flags-add block-beg 4)))
+     ((and regexp
+           (or (> (- block-end block-beg) 7)
+               (text-property-not-all block-beg block-end 'block-token 'delimiter)))
+      (web-mode-block-tokenize
+       (web-mode-block-code-beginning-position block-beg)
+       (web-mode-block-code-end-position block-beg)
+       regexp)
+      )
+     ) ;cond
 
-    (when keywords (web-mode-fontify-region beg end keywords))
+    ))
+
+(defun web-mode-block-tokenize (reg-beg reg-end &optional regexp)
+  "tokenize zone"
+  (unless regexp (setq regexp web-mode-engine-token-regexp))
+;;  (message "tokenize: reg-beg(%S) reg-end(%S) block-end(%S)" reg-beg reg-end block-end)
+  (save-excursion
+    (let ((pos reg-beg) beg char match continue (flags 0) token-type)
+
+      (remove-text-properties reg-beg reg-end '(block-token nil))
+      (goto-char reg-beg)
+
+      (while (re-search-forward regexp reg-end t)
+
+        (setq beg (match-beginning 0)
+              match (match-string 0)
+              continue t
+              flags (logior flags 1)
+              token-type nil)
+
+        (setq char (aref match 0))
 
-    (when regexp
-      (setq token-type "string")
-      (goto-char beg)
-      (while (re-search-forward regexp end t)
-        (setq start (match-beginning 0)
-              ms (match-string 0)
-              continue t)
-        (setq fc (aref ms 0))
         (cond
 
          ((and (string= web-mode-engine "asp")
-               (eq fc ?\'))
-          (setq props '(block-token comment face web-mode-block-comment-face)
-                token-type "comment")
-          (goto-char (if (< end (line-end-position)) end (line-end-position)))
+               (eq char ?\'))
+          (setq token-type 'comment)
+          (goto-char (if (< reg-end (line-end-position)) reg-end (line-end-position)))
           )
 
-         ((eq fc ?\')
-          (setq props '(block-token string face web-mode-block-string-face))
-          (while (and continue (search-forward "'" end t))
-            (setq continue (eq ?\\ (char-before (1- (point)))))
+         ((eq char ?\')
+          (setq token-type 'string)
+          (while (and continue (search-forward "'" reg-end t))
+            (if (looking-back "\\\\+'" reg-beg t)
+                (setq continue (= (mod (- (point) (match-beginning 0)) 2) 0))
+              (setq continue nil))
             )
           )
 
-         ((eq fc ?\")
-          (setq props '(block-token string face web-mode-block-string-face))
-          (while (and continue (search-forward "\"" end t))
-            (setq continue (eq ?\\ (char-before (1- (point)))))
+         ((eq char ?\")
+          (setq token-type 'string)
+          (while (and continue (search-forward "\"" reg-end t))
+            (if (looking-back "\\\\+\"" reg-beg t)
+                (setq continue (= (mod (- (point) (match-beginning 0)) 2) 0))
+              (setq continue nil))
             )
           )
 
-         ((string= ms "//")
-          (setq props '(block-token comment face web-mode-block-comment-face)
-                token-type "comment")
-          (goto-char (if (< end (line-end-position)) end (line-end-position)))
+         ((string= match "//")
+          (setq token-type 'comment)
+          (goto-char (if (< reg-end (line-end-position)) reg-end (line-end-position)))
+          )
+
+         ((eq char ?\;)
+          (setq token-type 'comment)
+          (goto-char (if (< reg-end (line-end-position)) reg-end (line-end-position)))
           )
 
-         ((eq fc ?\#)
-          (setq props '(block-token comment face web-mode-block-comment-face)
-                token-type "comment")
-          (goto-char (if (< end (line-end-position)) end (line-end-position)))
+         ((string= match "#|")
+          (setq token-type 'comment)
+          (unless (search-forward "|#" reg-end t)
+            (goto-char (if (< reg-end (line-end-position)) reg-end (line-end-position)))
+            )
           )
 
+         ((eq char ?\#)
+          (setq token-type 'comment)
+          (goto-char (if (< reg-end (line-end-position)) reg-end (line-end-position)))
+          )
 
-         ((string= ms "/*")
-          (setq props '(block-token comment face web-mode-block-comment-face)
-                token-type "comment")
-          (search-forward "*/" end t)
+         ((string= match "/*")
+          (setq token-type 'comment)
+          (unless (search-forward "*/" reg-end t)
+            (goto-char (if (< reg-end (line-end-position)) reg-end (line-end-position)))
+            )
           )
 
-         ((eq fc ?\<)
+         ((eq char ?\<)
           (when (and web-mode-enable-heredoc-fontification
                      (string-match-p "JS\\|JAVASCRIPT\\|HTM\\|CSS" (match-string 1)))
-            (setq hddeb (1+ (point))
-                  hdflk (if (string-match-p "HTM" (match-string 1))
-                            web-mode-html-font-lock-keywords
-                          web-mode-javascript-font-lock-keywords))
+            (setq flags (logior flags 2))
             )
-          ;;          (message "tag=%s pos=%S" (match-string 1) (point))
-          (setq props '(block-token string face web-mode-block-string-face))
-          (re-search-forward (concat "^[ ]*" (match-string 1)) end t)
-          (when hddeb (setq hdend (1- (match-beginning 0))))
+          (setq token-type 'string)
+          (re-search-forward (concat "^[ ]*" (match-string 1)) reg-end t)
           )
 
-         ((and (member web-mode-engine '("python" "erb"))
-               (eq fc ?\#))
-          (setq props '(block-token comment face web-mode-block-comment-face))
-          (goto-char (if (< end (line-end-position)) end (line-end-position)))
+         ) ;cond
+
+;;        (message "%S %S %S" beg (point) token-type)
+        (put-text-property beg (point) 'block-token token-type)
+        (when (eq token-type 'comment)
+          (put-text-property beg (1+ beg) 'syntax-table (string-to-syntax "<"))
+          (put-text-property (1- (point)) (point) 'syntax-table (string-to-syntax ">"))
           )
 
-         );;cond
+        ) ;while
 
-        ;;        (message "elt=%S" (buffer-substring start (point)))
-        (add-text-properties start (point) props)
+      (web-mode-block-flags-add pos flags)
+      (web-mode-block-controls-unset pos)
 
-        (when (and (member fc '(?\" ?\<))
-                   (member web-mode-engine '("php" "erb"))
-                   (> (- (point) start) 4))
-          (web-mode-interpolate-string start (point))
-          )
+      )))
+
+;; (1)has token (2)has heredoc (4)comment-block
+(defun web-mode-block-flags-add (pos flags)
+  "Set block flags. Block flags are associated with the 'block-beg text-property."
+  (unless (get-text-property pos 'block-beg)
+    (setq pos (web-mode-block-beginning-position pos)))
+  (setq flags (logior (or (get-text-property pos 'block-beg) 0) flags))
+  (put-text-property pos (1+ pos) 'block-beg flags)
+  )
 
-        (when hddeb
-          (web-mode-fontify-region hddeb hdend hdflk)
-          (setq hddeb nil))
+(defun web-mode-block-flags-detect (pos flags)
+  "Checks if current block has flags."
+  (unless (get-text-property pos 'block-beg)
+    (setq pos (web-mode-block-beginning-position pos)))
+  (= (logand (or (get-text-property pos 'block-beg) 0) flags) flags)
+  )
 
+(defun web-mode-set-php-controls (reg-beg reg-end)
+  "web-mode-set-php-controls"
+  (goto-char reg-beg)
+  (let (match controls
+        (continue t)
+        (regexp "endif\\|endforeach\\|endfor\\|endwhile\\|else\\|elsif\\|if\\|foreach\\|for\\|while"))
+    (while continue
+      (if (not (web-mode-rsf regexp reg-end))
+          (setq continue nil)
+        (setq match (match-string-no-properties 0))
         (cond
-         ((string= token-type "comment")
-          (if web-mode-enable-comment-keywords
-              (web-mode-interpolate-comment start (point) t))
+         ((and (>= (length match) 4)
+               (string= match "else")
+               (looking-at-p "[ ]*:"))
+          (setq controls (append controls (list (cons 'inside "if"))))
           )
-         (t
+         ((and (>= (length match) 3)
+               (string= (substring match 0 3) "end"))
+          (setq controls (append controls (list (cons 'close (substring match 3)))))
           )
-         )
-
-        );while
+         ((and (progn (skip-chars-forward "[ ]") t)
+               (eq (char-after) ?\()
+               (web-mode-closing-paren reg-end)
+               (looking-at-p ")[ ]*:"))
+          (setq controls (append controls (list (cons 'open match))))
+          )
+         ) ; cond
+        ) ;if
+      ) ;while
+;;    (message "ici=%S" controls)
+    (when (and controls (> (length controls) 1))
+      (setq controls (web-mode-block-controls-reduce controls)))
+    controls))
+
+;;todo
+;; nettoyer
+;; <?php if (): echo $x; endif; ?>
+;; ((open . "if") (close . "if"))
+;; -> nil
+(defun web-mode-block-controls-reduce (controls)
+  "clean block controls"
+  (when (and (eq (car (car controls)) 'open)
+             (member (cons 'close (cdr (car controls))) controls))
+    (setq controls nil)
+    )
+  controls)
 
-      );when regexp
+(defun web-mode-block-controls-unset (pos)
+  "Unset block controls"
+  (cond
+   ((null (get-text-property pos 'block-side))
+    (message "** block-controls-unset : invalid (%S) **" pos))
+   ((or (get-text-property pos 'block-beg)
+        (setq pos (web-mode-block-beginning-position pos)))
+    (put-text-property pos (1+ pos) 'block-controls 0))
+   (t
+    (message "** block-controls-unset : failure (%S) **" (point)))
+   ))
 
-    (when web-mode-enable-block-face
-      (font-lock-prepend-text-property beg end
-                                      'face
-                                      'web-mode-block-face))
-    ))
+(defun web-mode-block-controls-get (pos)
+  "Get block controls"
+  (web-mode-with-silent-modifications
+   (let ((controls nil))
+     (cond
+      ((null (get-text-property pos 'block-side))
+       ;;      (backtrace)
+       (message "** block-controls-get : invalid (%S) **" pos))
+      ((or (get-text-property pos 'block-beg)
+           (setq pos (web-mode-block-beginning-position pos)))
+       (setq controls (get-text-property pos 'block-controls))
+       (when (integerp controls)
+         (web-mode-block-controls-set pos (web-mode-block-end-position pos))
+         (setq controls (get-text-property pos 'block-controls))
+         ;;        (message "controls=%S" controls)
+         )
+       )
+      (t
+       (message "** block-controls-get : failure (%S) **" (point)))
+      ) ;cond
+     controls)))
 
-(defun web-mode-scan-jsp-tag (beg end)
-  "Scan a jsp tag to fontify ${ } blocks"
+(defun web-mode-block-controls-set (reg-beg reg-end)
+  "Set block properties"
   (save-excursion
-    (goto-char (+ 4 beg))
-    (setq end (1- end))
-    (while (re-search-forward "${.*}" end t)
-      (web-mode-fontify-region (match-beginning 0) (match-end 0)
-                               web-mode-uel-font-lock-keywords)
-      )
-    ))
+    (goto-char reg-beg)
+    (let (controls pos type control)
 
-;; todo : parsing plus compliqué: {$obj->values[3]->name}
-(defun web-mode-interpolate-string (beg end)
-  "Interpolate php/erb strings."
-  (save-excursion
-    (goto-char (1+ beg))
-    (setq end (1- end))
-    (cond
-     ((string= web-mode-engine "php")
-      (while (re-search-forward "$[[:alnum:]_]+\\(->[[:alnum:]_]+\\)*\\|{[ ]*$.+}" end t)
-        ;;web-mode-php-var-interpolation-font-lock-keywords
+      (cond
 
-        (web-mode-fontify-region (match-beginning 0) (match-end 0)
-                                 web-mode-php-var-interpolation-font-lock-keywords)
+       ((null web-mode-engine)
+        (message "** web-mode-block-controls-set : engine unknown : %S **" web-mode-engine)
+        )
 
-        ;; (put-text-property (match-beginning 0) (match-end 0)
-        ;;                    'face nil)
-        ;; (put-text-property (1+ (match-beginning 0)) (match-end 0)
-        ;;                    'face 'web-mode-variable-name-face)
+       ((string= web-mode-engine "php")
+        (setq controls (web-mode-set-php-controls reg-beg reg-end))
+;;        (message "coucou=%S" controls)
+        (when (web-mode-block-starts-with "}" reg-beg)
+          (setq controls (append controls (list (cons 'close "{")))))
+        (when (web-mode-block-ends-with (cons "{" "}") reg-beg)
+          (setq controls (append controls (list (cons 'open "{")))))
+        ) ; php
 
-        ))
-     ((string= web-mode-engine "erb")
-      (while (re-search-forward "#{.*}" end t)
-        (put-text-property (match-beginning 0) (match-end 0)
-                           'face 'web-mode-variable-name-face)
-        ))
-     );cond
-    ))
+       ((string= web-mode-engine "erb")
+        (cond
+         ((web-mode-block-starts-with "else\\|elsif\\|when" reg-beg)
+          (setq controls (append controls (list (cons 'inside "ctrl")))))
+         ((web-mode-block-starts-with "end" reg-beg)
+          (setq controls (append controls (list (cons 'close "ctrl")))))
+         ((web-mode-block-starts-with ".* do \\|for\\|if\\|unless\\|case" reg-beg)
+          (setq controls (append controls (list (cons 'open "ctrl")))))
+         )
+        ) ; erb
 
+       ((string= web-mode-engine "django")
+        (when (eq (char-after (1+ reg-beg)) ?\%)
+          (cond
+           ((web-mode-block-starts-with "\\(else\\|elsif\\|elif\\)" reg-beg)
+            (setq controls (append controls (list (cons 'inside "if")))))
+           ((web-mode-block-starts-with "\\(empty\\)" reg-beg)
+            (setq controls (append controls (list (cons 'inside "for")))))
+           ((web-mode-block-starts-with "end\\([[:alpha:]]+\\)" reg-beg)
+            (setq controls (append controls (list (cons 'close (match-string-no-properties 1))))))
+           ((web-mode-block-starts-with web-mode-django-control-blocks reg-beg)
+            (setq controls (append controls (list (cons 'open (match-string-no-properties 1))))))
+           )
+          )
+        ) ;django
 
-(defun web-mode-interpolate-comment (beg end block-side)
-  "Interpolate comment"
-  (save-excursion
-    (let (regexp)
-      (goto-char beg)
-      (setq regexp (concat "\\<\\(" web-mode-comment-keywords "\\)\\>"))
-      (while (re-search-forward regexp end t)
-        (font-lock-prepend-text-property (match-beginning 1) (match-end 1)
-                                         'face
-                                         'web-mode-comment-keyword-face)
-        )
-      )))
+       ((string= web-mode-engine "smarty")
+        (cond
+         ((and (eq (char-after (+ (length (web-mode-engine-delimiter-open web-mode-engine "{")) reg-beg)) ?\/)
+               (web-mode-block-starts-with "\\([[:alpha:]]+\\)" reg-beg))
+          (setq controls (append controls (list (cons 'close (match-string-no-properties 1))))))
+         ((web-mode-block-starts-with "\\(else\\|elseif\\)" reg-beg)
+          (setq controls (append controls (list (cons 'inside "if")))))
+         ((web-mode-block-starts-with "\\(block\\|foreach\\|for\\|if\\|section\\|while\\)")
+          (setq controls (append controls (list (cons 'open (match-string-no-properties 1))))))
+         )
+        ) ;smarty
 
-;; start-tag, end-tag, tag-name, element (<a>xsx</a>, an element is delimited by tags), void-element
-;; http://www.w3.org/TR/html-markup/syntax.html#syntax-elements
-(defun web-mode-scan-parts (beg end)
-  "Scan client side blocks (JavaScript / CSS / HTML Comments) and identifies strings and comments."
-  (save-excursion
-    (let (open limit close expr props closing-string tname tbeg tend tstop tface element-content-type attrs-end close-found is-tag slash-beg slash-end)
+       ((string= web-mode-engine "web2py")
+        (cond
+         ((web-mode-block-starts-with "def" reg-beg)
+          (setq controls (append controls (list (cons 'open "def")))))
+         ((web-mode-block-starts-with "return" reg-beg)
+          (setq controls (append controls (list (cons 'close "def")))))
+         ((web-mode-block-starts-with "block" reg-beg)
+          (setq controls (append controls (list (cons 'open "block")))))
+         ((web-mode-block-starts-with "end" reg-beg)
+          (setq controls (append controls (list (cons 'close "block")))))
+         ((web-mode-block-starts-with "pass" reg-beg)
+          (setq controls (append controls (list (cons 'close "ctrl")))))
+         ((web-mode-block-starts-with "\\(except\\|finally\\|els\\)" reg-beg)
+          (setq controls (append controls (list (cons 'inside "ctrl")))))
+         ((web-mode-block-starts-with "\\(if\\|for\\|try\\|while\\)")
+          (setq controls (append controls (list (cons 'open "ctrl")))))
+         )
+        ) ;web2py
 
-      (goto-char beg)
+       ((string= web-mode-engine "dust")
+        (cond
+         ((eq (char-after (1- reg-end)) ?\/)
+          )
+         ((eq (char-after (1+ reg-beg)) ?\:)
+          (setq pos (web-mode-block-control-previous-position 'open reg-beg))
+          (when pos
+            (setq controls (append controls
+                                   (list
+                                    (cons 'inside
+                                          (cdr (car (web-mode-block-controls-get pos))))))))
+          )
+         ((looking-at "{/\\([[:alpha:]]+\\)")
+          (setq controls (append controls (list (cons 'close (match-string-no-properties 1))))))
+         ((looking-at "{[#?@><+^]\\([[:alpha:]]+\\)")
+          (setq controls (append controls (list (cons 'open (match-string-no-properties 1))))))
+         ) ;cond
+        ) ;dust
+
+       ((member web-mode-engine '("asp" "aspx" "underscore" "mojolicious"))
+        (cond
+         ((web-mode-block-starts-with "}" reg-beg)
+          (setq controls (append controls (list (cons 'close "{")))))
+         ((web-mode-block-ends-with "{" reg-beg)
+          (setq controls (append controls (list (cons 'open "{")))))
+         )
+        ) ;asp aspx underscore
 
-      (while (web-mode-rsf-client "<\\(/?[[:alpha:]][[:alnum:]-]*\\|!--\\|!doctype\\|\?xml\\)" end t)
-        (setq tname (downcase (match-string-no-properties 1))
-              tbeg (match-beginning 0)
-              tend nil
-              tstop (point)
-              element-content-type nil
-              open nil
-              limit end
-              close nil
-              props nil
-              expr ">"
-              closing-string nil
-              close-found nil
-              is-tag nil
-              slash-beg nil
-              slash-end nil)
+       ((string= web-mode-engine "mako")
+        (cond
+         ((looking-at "</?%\\([[:alpha:]]+\\(?:[:][[:alpha:]]+\\)?\\)")
+          (setq control (match-string-no-properties 1)
+                type (if (eq (aref (match-string-no-properties 0) 1) ?\/) 'close 'open))
+          (setq controls (append controls (list (cons type control))))
+         )
+         ((web-mode-block-starts-with "\\(else\\|elsif\\)" reg-beg)
+          (setq controls (append controls (list (cons 'inside "if")))))
+         ((web-mode-block-starts-with "end\\(if\\|for\\)" reg-beg)
+          (setq controls (append controls (list (cons 'close (match-string-no-properties 1))))))
+         ((web-mode-block-starts-with "if\\|for" reg-beg)
+          (setq controls (append controls (list (cons 'open (match-string-no-properties 0))))))
+         )
+        ) ;mako
 
+       ((string= web-mode-engine "mason")
         (cond
-         ((string= tname "!--")
-          (setq expr "-->"
-                props '(tag-name "comment" tag-type void part-side t part-token comment face web-mode-comment-face)))
-         ((string= tname "?xml")
-          (setq expr "?>"
-                props '(tag-name "doctype" tag-type void face web-mode-doctype-face)))
-         ((string= tname "!doctype")
-          (setq props '(tag-name "doctype" tag-type void face web-mode-doctype-face))
-;;          (setq expr ">")
+         ((looking-at "</?%\\(def\\|method\\)")
+          (setq control (match-string-no-properties 1)
+                type (if (eq (aref (match-string-no-properties 0) 1) ?\/) 'close 'open))
+          (setq controls (append controls (list (cons type control))))
           )
-         (t
-          (setq is-tag t
-                tface (if (string-match-p "-" tname)
-                             'web-mode-html-tag-custom-face
-                           'web-mode-html-tag-face)
-                )
-          (cond
-           ((eq ?\/ (string-to-char tname))
-            (setq props (list 'face tface 'tag-name (substring tname 1) 'tag-type 'end)
-                  slash-beg t)
-            (setq limit (if (> end (line-end-position)) (line-end-position) end))
-            )
-           ((web-mode-is-void-element tname)
-            (setq props (list 'face tface 'tag-name tname 'tag-type 'void))
-            )
-           (t
-            (setq props (list 'face tface 'tag-name tname 'tag-type 'start))
-            )
-           );cond
-          );t
-         );cond
-
-        (if (web-mode-sf-client expr limit t)
-;;        (if (skip-chars-forward "^>" limit)
-            (progn
-;;              (forward-char)
-;;              (message "OK(%S): %S %S" limit tname (point))
-              (setq attrs-end (- (point) (length expr))
-                    tend (point)
-                    close-found t)
-              (when (eq ?\/ (char-after (- (point) 2)))
-                (setq attrs-end (1- attrs-end)
-                      props (plist-put props 'tag-type 'void)
-                      slash-end t))
-              );progn
-          (setq attrs-end (line-end-position)
-                tend (line-end-position))
-;;          (message "KO(%S): %S %S" limit tname (point))
-          );if
+         ) ;mason
+        )
 
+       ((string= web-mode-engine "ctemplate")
         (cond
-         ((string= tname "script")
-          (let (script)
-            (setq script (buffer-substring-no-properties tbeg tend))
-            (cond
-             ((string-match-p " type[ ]*=[ ]*[\"']text/\\(x-handlebars\\|html\\|ng-template\\)" script)
-              (setq element-content-type "html"))
-             ((string-match-p " type[ ]*=[ ]*[\"']application/\\(ld\\+json\\|json\\)" script)
-              (setq element-content-type "json"))
-             (t
-              (setq element-content-type "javascript"))
-             )
-            ;;          (message "tag=%S : %S" tname element-content-type)
-            )
-          );case script
-         ((string= tname "style")
-          (setq element-content-type "css")
+         ((looking-at-p "{{else")
+          (setq controls (append controls (list (cons 'inside "if")))))
+         ((looking-at "{{[#^/][ ]*\\([[:alpha:]]+\\)")
+          (setq control (match-string-no-properties 1)
+                type (if (eq (aref (match-string-no-properties 0) 2) ?\/) 'close 'open))
+          (setq controls (append controls (list (cons type control))))
           )
          )
+        ) ;ctemplate
 
-        ;;        (message "tag=%S (%S > %S)\n%S" tname tbeg tend props)
-        (add-text-properties tbeg tend props)
-
-        (if is-tag
-            (progn
-              (add-text-properties
-               tbeg (1+ tbeg)
-               '(tag-beg t face web-mode-html-tag-bracket-face))
-              (when slash-beg
-                (add-text-properties
-                 (+ tbeg 1) (+ tbeg 2)
-                 '(face web-mode-html-tag-bracket-face))
-                );when
-              (when close-found
-                (add-text-properties
-                 (1- tend) tend
-                 '(tag-end t face web-mode-html-tag-bracket-face))
-                );when
-              (when slash-end
-                (add-text-properties
-                 (- tend 2) (- tend 1)
-                 '(face web-mode-html-tag-bracket-face))
-                );when
-              );progn
-          (add-text-properties tbeg (1+ tbeg) '(tag-beg t))
-          (add-text-properties (1- tend) tend '(tag-end t))
+       ((string= web-mode-engine "blade")
+        (cond
+         ((not (eq (char-after) ?\@))
+          )
+         ((web-mode-block-starts-with
+           "\\(?:end\\)?\\(foreach\\|forelse\\|for\\|if\\|section\\|unless\\|while\\)"
+           reg-beg)
+          (setq control (match-string-no-properties 1)
+                type (if (eq (aref (match-string-no-properties 0) 0) ?e) 'close 'open))
+          (setq controls (append controls (list (cons type control))))
           )
+         ((web-mode-block-starts-with "stop\\|show" reg-beg)
+          (setq controls (append controls (list (cons 'close "section")))))
+         ((web-mode-block-starts-with "else\\|elseif" reg-beg)
+          (setq controls (append controls (list (cons 'inside "if")))))
+         )
+        ) ;blade
 
-;;        (cond
+       ((string= web-mode-engine "closure")
+        (cond
+         ((eq (char-after (1- reg-end)) ?\/)
+          )
+         ((looking-at "alias\\|namespace")
+          )
+         ((web-mode-block-starts-with "ifempty" reg-beg)
+          (setq controls (append controls (list (cons 'inside "foreach")))))
+         ((web-mode-block-starts-with "else\\|elseif" reg-beg)
+          (setq controls (append controls (list (cons 'inside "if")))))
+         ((web-mode-block-starts-with "case\\|default" reg-beg)
+          (setq controls (append controls (list (cons 'inside "switch")))))
+         ((looking-at
+           "{/?\\(call\\|deltemplate\\|for\\|foreach\\|if\\|let\\|literal\\|msg\\|param\\|switch\\|template\\)")
+          (setq control (match-string-no-properties 1)
+                type (if (eq (aref (match-string-no-properties 0) 1) ?\/) 'close 'open))
+          (setq controls (append controls (list (cons type control))))
+          )
+         )
+        ) ;closure
 
-;;         ((member tname '("!doctype" "?xml"))
-          ;;          (add-text-properties tbeg tend
-          ;;                               '(tag-name "doctype" tag-type void face web-mode-doctype-face))
-;;          )
+       ((string= web-mode-engine "go")
+        (cond
+         ((web-mode-block-starts-with "end" reg-beg)
+          (setq controls (append controls (list (cons 'close "ctrl")))))
+         ((web-mode-block-starts-with "else" reg-beg)
+          (setq controls (append controls (list (cons 'inside "ctrl")))))
+         ((web-mode-block-starts-with "range\\|with" reg-beg)
+          (setq controls (append controls (list (cons 'open "ctrl")))))
+         )
+        ) ;go
 
-;;         ((string= tname "!--")
-;;          (add-text-properties tbeg tend
-          ;;                               '(tag-name "comment" tag-type void part-side t part-token comment face web-mode-comment-face))
-;;          )
+       ((string= web-mode-engine "template-toolkit")
+        (cond
+         ((web-mode-block-starts-with "end" reg-beg)
+          (setq controls (append controls (list (cons 'close "ctrl")))))
+         ((web-mode-block-starts-with "els" reg-beg)
+          (setq controls (append controls (list (cons 'inside "ctrl")))))
+         ((web-mode-block-starts-with "if\\|foreach\\|filter" reg-beg)
+          (setq controls (append controls (list (cons 'open "ctrl")))))
+         )
+        ) ;template-toolkit
 
-        (when (and is-tag close-found)
+       ((string= web-mode-engine "velocity")
+        (cond
+         ((web-mode-block-starts-with "end" reg-beg)
+          (setq controls (append controls (list (cons 'close "ctrl")))))
+         ((web-mode-block-starts-with "els" reg-beg)
+          (setq controls (append controls (list (cons 'inside "ctrl")))))
+         ((web-mode-block-starts-with "define\\|if\\|for\\|foreach\\|macro" reg-beg)
+          (setq controls (append controls (list (cons 'open "ctrl")))))
+         )
+        ) ;velocity
 
-          (when (and (not (eq ?\/ (aref tname 0)))
-                     (> (- attrs-end tstop) 2))
-            ;;            (message "tstop=%S attrs-end=%S" tstop attrs-end)
-            (web-mode-scan-attrs tstop attrs-end)
-            )
+       ((string= web-mode-engine "jsp")
+        (cond
+         ((eq (char-after (1- reg-end)) ?\/)
+          )
+         ((looking-at "</?\\([[:alpha:]]+\\(?:[:][[:alpha:]]+\\)\\)")
+          (setq control (match-string-no-properties 1)
+                type (if (eq (aref (match-string-no-properties 0) 1) ?\/) 'close 'open))
+          (when (not (member control '("h:inputtext" "jsp:usebean" "jsp:forward" "struts:property")))
+            (setq controls (append controls (list (cons type control)))))
+          )
+         (t
+          (when (web-mode-block-starts-with "}" reg-beg)
+            (setq controls (append controls (list (cons 'close "{")))))
+          ;; todo : bug qd <% } else { %>
+          (when (web-mode-block-ends-with "{" reg-beg)
+            (setq controls (append controls (list (cons 'open "{")))))
+          )
+         )
+        ) ;jsp
 
-          (cond
-           ((and (string= tname "script")
-                 (member element-content-type '("javascript" "json")))
-            (setq closing-string "</script>"))
-           ((string= tname "style")
-            (setq closing-string "</style>"))
-           )
+       ((string= web-mode-engine "freemarker")
+        (cond
+         ((eq (char-after (1- reg-end)) ?\/)
+          )
+         ((looking-at "[<[]#\\(break\\|case\\|default\\)")
+          (setq controls (append controls (list (cons 'inside "switch"))))
+          )
+         ((looking-at "[<[]#els")
+          (setq controls (append controls (list (cons 'inside "if"))))
+          )
+         ((looking-at "</?\\([[:alpha:]]+\\(?:[:][[:alpha:]]+\\)?\\)")
+          (setq control (match-string-no-properties 1)
+                type (if (eq (aref (match-string-no-properties 0) 1) ?\/) 'close 'open))
+          (setq controls (append controls (list (cons type control))))
+          )
+         ((looking-at "[<[]/?[#@]\\([[:alpha:]]+\\(?:[:][[:alpha:]]+\\)?\\)")
+          (setq control (match-string-no-properties 1)
+                type (if (eq (aref (match-string-no-properties 0) 1) ?\/) 'close 'open))
+          (setq controls (append controls (list (cons type control))))
+          )
+         (t
+          (when (web-mode-block-starts-with "}" reg-beg)
+            (setq controls (append controls (list (cons 'close "{")))))
+          ;; todo : bug qd <% } else { %>
+          (when (web-mode-block-ends-with "{" reg-beg)
+            (setq controls (append controls (list (cons 'open "{")))))
+          )
+         )
+        ) ;freemarker
 
-          ;; si <script type="document/html"> on ne fait pas la suite
+       ((string= web-mode-engine "razor")
+        (when (web-mode-block-starts-with "}" reg-beg)
+          (setq controls (append controls (list (cons 'close "{")))))
+        (when (web-mode-block-ends-with "{" reg-beg)
+          (setq controls (append controls (list (cons 'open "{")))))
+        ) ;razor
 
-          (when (and closing-string (web-mode-sf-client closing-string end t))
-            (setq open tend
-                  close (match-beginning 0))
-            (if (>= (- close open) 3)
-                (web-mode-scan-part open close element-content-type)
-              (remove-text-properties open close web-mode-text-properties2))
-            (goto-char close)
-            ); when
+       ((string= web-mode-engine "lsp")
+        (when (web-mode-block-starts-with ")" reg-beg)
+          (setq controls (append controls (list (cons 'close "(")))))
+        ;; TODO regarder si la sexp est open e.g. <% (dotimes (i 10) %>
+        (when (web-mode-block-is-opened-sexp reg-beg reg-end)
+          (setq controls (append controls (list (cons 'open "(")))))
+        ) ;lsp
 
-          );when
-        ;;         ); cond tag
+       ) ;cond
 
-        ); while
+      (put-text-property reg-beg (1+ reg-beg) 'block-controls controls)
+      ;;      (message "(%S) controls=%S" reg-beg controls)
 
       )))
 
-;; todo : il serait préférable d'identifier les tokens et ensuite de fontifier
-(defun web-mode-scan-part (part-beg part-end content-type)
-  "Scan client part (e.g. javascript, json, css)."
-  (save-excursion
-    (let (token-re ch-before ch-at ch-next props start continue keywords token-type face)
+(defun web-mode-block-is-opened-sexp (reg-beg reg-end)
+  "web-mode-block-is-opened-sexp"
+  (let ((n 0))
+    (save-excursion
+      (goto-char reg-beg)
+      (while (web-mode-block-rsf "[()]" reg-end)
+        (if (eq (char-before) ?\()
+            (setq n (1+ n))
+          (setq n (1- n))
+          )
+        )
+      )
+    (> n 0)
+    ))
 
-      (remove-text-properties part-beg part-end web-mode-text-properties2)
+(defun web-mode-block-control-previous-position (type &optional pos)
+  "web-mode-block-control-previous-open"
+  (unless pos (setq pos (point)))
+  (let ((continue t) controls)
+    (while continue
+      (setq pos (web-mode-block-previous-position pos))
+;;      (message "pos=%S" pos)
+      (cond
+       ((null pos)
+        (setq continue nil
+              pos nil))
+       ((and (setq controls (web-mode-block-controls-get pos))
+             (eq (car (car controls)) type))
+        (setq continue nil))
+       ) ;cond
+      ) ;while
+    pos))
 
-      (goto-char part-beg)
+(defun web-mode-highlight-block (reg-beg reg-end)
+  "Highlight block."
+  (let (sub2 sub3 continue char keywords token-type face beg end flags (buffer (current-buffer)))
+    ;;(message "reg-beg=%S reg-end=%S" reg-beg reg-end)
+    (remove-text-properties reg-beg reg-end '(font-lock-face nil))
 
-      (when (and (not web-mode-has-any-large-part)
-                 (> (- part-end part-beg) web-mode-large-embed-threshold))
-;;        (message "** large part detected [ %S - %S ] **" part-beg part-end)
-        (setq web-mode-has-any-large-part t))
+    (goto-char reg-beg)
 
-      (cond
-       ((string= content-type "javascript")
-;;        (setq token-re "//\\|/\\*\\|\"\\|'"
-        (setq token-re "/.\\|\"\\|'"
-              keywords web-mode-javascript-font-lock-keywords
-              props '(part-language javascript part-side t)))
-       ((string= content-type "json")
-        (setq token-re "//\\|/\\*\\|\"\\|'"
-              keywords web-mode-javascript-font-lock-keywords
-              props '(part-language json part-side t)))
-       ((string= content-type "css")
-        (setq token-re "/\\*\\|\"\\|'"
-              props '(part-language css part-side t)))
-       )
+    (when (null web-mode-engine-font-lock-keywords)
+      (setq sub2 (buffer-substring-no-properties
+                  reg-beg (+ reg-beg 2))
+            sub3 (buffer-substring-no-properties
+                  reg-beg (+ reg-beg (if (>= (point-max) (+ reg-beg 3)) 3 2))))
+      )
 
-      (add-text-properties part-beg part-end props)
+    (cond
 
-      (when keywords
-        (web-mode-fontify-region part-beg part-end keywords))
+     ((and (get-text-property reg-beg 'block-beg)
+           (eq (get-text-property reg-beg 'block-token) 'comment))
+      (put-text-property reg-beg reg-end 'font-lock-face 'web-mode-comment-face)
+      ) ;comment block
 
-      (when (string= content-type "css")
-        (web-mode-css-scan-rules part-beg part-end))
+     (web-mode-engine-font-lock-keywords
+      (setq keywords web-mode-engine-font-lock-keywords)
+      )
 
-      (when token-re
-        (while (and token-re (web-mode-rsf-client token-re part-end t))
-          (setq start (match-beginning 0)
-                props nil
-                continue t)
-          (setq ch-at (char-after start))
-          (setq ch-next (or (char-after (1+ start)) ?\d))
-          (setq ch-before (or (char-before start) ?\d))
-          (setq token-type "string")
-          ;;        (message "beg=%S :%c%c%c" start ch-before ch-at ch-next)
-          (cond
+     ((string= web-mode-engine "django")
+      (cond
+       ((string= sub2 "{{")
+        (setq keywords web-mode-django-expr-font-lock-keywords))
+       ((string= sub2 "{%")
+        (setq keywords web-mode-django-code-font-lock-keywords))
+       )) ;django
 
-           ((eq ?\' ch-at)
-            (unless (eq ?\\ ch-before)
-              (while (and continue (search-forward "'" part-end t))
-                (setq continue (or (get-text-property (1- (point)) 'block-side)
-                                   (eq ?\\ (char-before (1- (point))))))
-                )
-              (cond
-               ((string= content-type "javascript")
-                (setq props '(part-token string face web-mode-javascript-string-face)))
-               ((string= content-type "css")
-                (setq props '(part-token string face web-mode-css-string-face)))
-               ((string= content-type "json")
-                (setq props '(part-token string face web-mode-json-string-face)))
-               (t
-                (setq props '(part-token string face web-mode-part-string-face)))
-               );cond
-              );unless
-            )
+     ((string= web-mode-engine "mako")
+      (cond
+       ((member sub3 '("<% " "<%\n" "<%!"))
+        (setq keywords web-mode-mako-block-font-lock-keywords))
+       ((string= sub2 "% ")
+        (setq keywords web-mode-mako-block-font-lock-keywords))
+       ((member sub2 '("<%" "</"))
+        (setq keywords web-mode-mako-tag-font-lock-keywords))
+       ((member sub2 '("${"))
+        (setq keywords web-mode-uel-font-lock-keywords))
+       )) ;mako
 
-           ((eq ?\" ch-at)
-            (unless (eq ?\\ ch-before)
-              (while (and continue (search-forward "\"" part-end t))
-                (setq continue (or (get-text-property (1- (point)) 'block-side)
-                                   (eq ?\\ (char-before (1- (point))))))
-                )
-              (cond
-               ((string= content-type "json")
-                (if (looking-at-p "[ ]*:")
-                    (cond
-                     ((eq ?\@ (char-after (1+ start)))
-                      (setq props '(part-token string face web-mode-json-context-face))
-                      )
-                     (t
-                      (setq props '(part-token string face web-mode-json-key-face))
-                      )
-                     )
-                  (setq props '(part-token string face web-mode-json-string-face)))
-                )
-               (t
-                (cond
-                 ((string= content-type "javascript")
-                  (setq props '(part-token string face web-mode-javascript-string-face)))
-                 ((string= content-type "css")
-                  (setq props '(part-token string face web-mode-css-string-face)))
-                 (t
-                  (setq props '(part-token string face web-mode-part-string-face)))
-                 );cond
-                );t
-               );cond
-              );unless
-            )
+     ((string= web-mode-engine "jsp")
+      (cond
+       ((string= sub3 "<%@")
+        (setq keywords web-mode-directive-font-lock-keywords))
+       ((member sub2 '("${" "#{"))
+        (setq keywords web-mode-uel-font-lock-keywords))
+       ((string= sub2 "<%")
+        (setq keywords web-mode-jsp-font-lock-keywords))
+       (t
+        (setq keywords web-mode-jsp-tag-font-lock-keywords))
+       )) ;jsp
 
-           ((eq ?\/ ch-next)
-            (unless (eq ?\\ ch-before)
-              (setq props '(part-token comment face web-mode-part-comment-face)
-                    token-type "comment")
-              (goto-char (if (< part-end (line-end-position)) part-end (line-end-position)))
-              )
-            )
+     ((string= web-mode-engine "aspx")
+      (cond
+       ((string= sub3 "<%@")
+        (setq keywords web-mode-directive-font-lock-keywords))
+       ((string= sub3 "<%$")
+        (setq keywords web-mode-expression-font-lock-keywords))
+       (t
+        (setq keywords web-mode-aspx-font-lock-keywords))
+       )) ;aspx
 
-           ((eq ?\* ch-next)
-            (unless (eq ?\\ ch-before)
-              (setq props '(part-token comment face web-mode-part-comment-face)
-                    token-type "comment")
-              (search-forward "*/" part-end t)
-              )
-            )
+     ((string= web-mode-engine "freemarker")
+      (cond
+       ((member sub2 '("${" "#{"))
+        (setq keywords web-mode-uel-font-lock-keywords))
+       ((or (member sub2 '("<@" "[@" "<#" "[#"))
+            (member sub3 '("</@" "[/@" "</#" "[/#")))
+        (setq keywords (if (eq ?\[ (aref sub2 0))
+                           web-mode-freemarker-square-font-lock-keywords
+                         web-mode-freemarker-font-lock-keywords)))
+       (t
+        (setq keywords web-mode-jsp-tag-font-lock-keywords))
+       )) ;freemarker
 
-           ((and (string= content-type "javascript")
-                 (eq ?\/ ch-at)
-                 (not (eq ?\s ch-next)))
-;;            (backward-char)
-;;            (message "> %S" (point))
-            (while (and continue (search-forward "/" part-end t))
-;;              (message "%S %S %c" (point)
-;;                       (get-text-property (1- (point)) 'part-side)
-;;                       (char-before (1- (point))))
-              (setq continue (or (get-text-property (1- (point)) 'block-side)
-                                 (eq ?\\ (char-before (1- (point))))))
-              )
-            (setq props '(part-token string face web-mode-part-string-face))
-            (skip-chars-forward "gimy")
-;;            (message "#%S" (point))
-            )
+     ) ;cond
 
-           );cond
+    (when keywords
+      (web-mode-fontify-region reg-beg reg-end keywords)
+;;      (message "reg-beg(%S) reg-end(%S)" reg-beg reg-end)
+      (setq flags (get-text-property reg-beg 'block-beg))
+;;      (setq continue (not (null flags))) ;;(> (logand flags 1) 0))
+      (setq continue t)
+      (setq end reg-beg)
+      (while continue
+;;        (message "end=%S %S" end (get-text-property end 'block-token))
 
-          (when (>= part-end (point))
-            (if props (add-text-properties start (point) props))
-            (when (and (string= token-type "comment")
-                       web-mode-enable-comment-keywords)
-              (web-mode-interpolate-comment start (point) t))
-            )
+        ;; (if (and (= reg-beg end)
+        ;;          (eq (get-text-property end 'block-token) 'delimiter))
+        ;;     (setq beg end)
+        ;;   (setq beg (next-single-property-change end 'block-token))
+        ;;   )
 
-          ));while | when token-re
+        (if (get-text-property end 'block-token)
+            (setq beg end)
+          (setq beg (next-single-property-change end 'block-token buffer reg-end)))
 
-      (when web-mode-enable-part-face
-        (font-lock-append-text-property part-beg part-end
-                                        'web-mode-part-face
-                                        face))
+        (setq end nil)
+        (when beg (setq char (char-after beg)))
+        (if (and beg (< beg reg-end))
+            (progn
+              (setq token-type (get-text-property beg 'block-token))
+              (setq face (cond
+                          ((eq token-type 'string)  'web-mode-block-string-face)
+                          ((eq token-type 'comment) 'web-mode-block-comment-face)
+                          (t                        'web-mode-block-delimiter-face)))
+              (setq end (next-single-property-change beg 'block-token buffer reg-end))
+;;              (message "end=%S" end)
+              (if (and end (<= end reg-end))
+                  (progn
+;;                    (message "%S > %S face(%S)" beg end face)
+                    (remove-text-properties beg end '(face nil))
+                    (put-text-property beg end 'font-lock-face face))
+                (setq continue nil
+                      end nil)
+                ) ;if end
+              ) ;progn beg
+          (setq continue nil
+                end nil)
+          ) ;if beg
+        (when (and beg end)
+          (save-match-data
+            (when (and web-mode-enable-heredoc-fontification
+                       (eq char ?\<)
+                       (> (- end beg) 8)
+                       ;;                     (progn (message "ici%S" (buffer-substring-no-properties beg end)) t)
+                     ;;                   (member web-mode-engine '("php"))
+                       (> (logand flags 2) 0)
+                       (string-match-p "JS\\|JAVASCRIPT\\|HTM\\|CSS" (buffer-substring-no-properties beg end)))
+              (setq keywords (if (eq ?H (char-after (+ beg 3)))
+                                 web-mode-html-font-lock-keywords
+                               web-mode-javascript-font-lock-keywords))
+;;              (remove-text-properties beg end '(font-lock-face nil))
+              (web-mode-fontify-region beg end keywords)
+            ))
+;;          (message "%S %c %S beg=%S end=%S" web-mode-enable-string-interpolation char web-mode-engine beg end)
+          (when (and web-mode-enable-string-interpolation
+                     (member char '(?\" ?\<))
+                     (member web-mode-engine '("php" "erb"))
+                     (> (- end beg) 4))
+            (web-mode-interpolate-string beg end))
+          (when (and web-mode-enable-comment-keywords
+                     (eq token-type 'comment)
+                     (> (- end beg) 3))
+            (web-mode-interpolate-comment beg end t)
+            ) ;when
+          ) ;when beg end
+        ) ;while continue
+      ) ;when keywords
+
+    (when (and (member web-mode-engine '("jsp" "mako"))
+               (> (- reg-end reg-beg) 12)
+               (eq ?\< (char-after reg-beg)))
+      (web-mode-interpolate-block-tag reg-beg reg-end))
 
-      )))
+    (when web-mode-enable-block-face
+;;      (message "block-face %S %S" reg-beg reg-end)
+      (font-lock-append-text-property reg-beg reg-end 'face 'web-mode-block-face))
 
-(defun web-mode-css-scan-rules (part-beg part-end)
-  "Scan CSS rules."
-  (save-excursion
-    (goto-char part-beg)
-    (let (rule (continue t) (i 0) at-rule)
-      (while continue
-        (setq i (1+ i))
-        (setq rule (web-mode-css-next-rule part-end))
-        (cond
-         ((> i 1000)
-          (message "*** too much css rules ***")
-          (setq continue nil))
-         ((null rule)
-          (setq continue nil)
-          )
-         ((and (setq at-rule (plist-get rule :at-rule))
-               (not (member at-rule '("charset" "font-face" "import")))
-               (plist-get rule :dec-end))
-          (web-mode-css-fontify-rule (plist-get rule :sel-beg)
-                                     (plist-get rule :sel-end)
-                                     nil nil)
-          (web-mode-css-scan-rules (plist-get rule :dec-beg)
-                                   (plist-get rule :dec-end))
-          )
-         (t
-          (web-mode-css-fontify-rule (plist-get rule :sel-beg)
-                                     (plist-get rule :sel-end)
-                                     (plist-get rule :dec-beg)
-                                     (plist-get rule :dec-end))
-          )
-         );cond
-        )
-      )
     ))
 
-(defun web-mode-css-fontify-rule (sel-beg sel-end dec-beg dec-end)
-  "Fontify css rule."
+(defun web-mode-scan-mako-block-comments (reg-beg reg-end)
+  "Scan extra"
   (save-excursion
-;;    (message "sel-beg=%S sel-end=%S dec-beg=%S dec-end=%S" sel-beg sel-end dec-beg dec-end)
-    (web-mode-fontify-region sel-beg sel-end
-                             web-mode-selector-font-lock-keywords)
-    (when (and dec-beg dec-end)
-      (web-mode-fontify-region dec-beg dec-end
-                               web-mode-declaration-font-lock-keywords)
-      (goto-char dec-beg)
-      (while (and (not web-mode-disable-css-colorization)
-                  (re-search-forward "#[0-9a-fA-F]\\{6\\}\\|#[0-9a-fA-F]\\{3\\}\\|rgb([ ]*\\([[:digit:]]\\{1,3\\}\\)[ ]*,[ ]*\\([[:digit:]]\\{1,3\\}\\)[ ]*,[ ]*\\([[:digit:]]\\{1,3\\}\\)\\(.*?\\))" dec-end t)
-                  (< (point) dec-end))
-        (web-mode-colorize (match-beginning 0) (match-end 0))
-        )
+    (let (beg end (continue t))
+      (goto-char reg-beg)
+      (while (and continue
+                  (< (point) reg-end)
+                  (re-search-forward "<%doc>" reg-end t))
+        (goto-char (match-beginning 0))
+        (setq beg (point))
+        (if (not (re-search-forward "</%doc>" reg-end t))
+            (setq continue nil)
+          (setq end (point))
+          (remove-text-properties beg end web-mode-scan-properties)
+          (add-text-properties beg end '(block-side t block-token comment))
+          (put-text-property beg (1+ beg) 'block-beg t)
+          (put-text-property (1- end) end 'block-end t)
+          ) ;if
+        ) ;while
       )))
 
-;; css rule = selector(s) + declaration (properties)
-(defun web-mode-css-next-rule (limit)
-  "next rule"
-  (let (at-rule sel-beg sel-end dec-beg dec-end chunk)
-    (skip-chars-forward "\n\t ")
-    (setq sel-beg (point))
-    (when (and (< (point) limit)
-               (web-mode-rsf-client "[{;]" limit t))
-      (setq sel-end (1- (point)))
-      (cond
-       ((eq (char-before) ?\{)
-        (setq dec-beg (point))
-        (setq dec-end (web-mode-closing-paren-position (1- dec-beg) limit))
-        (if dec-end
-            (progn
-              (goto-char dec-end)
-              (forward-char))
-          (setq dec-end limit)
-          (goto-char limit))
-        )
-       (t
-        )
-       );cond
-      (setq chunk (buffer-substring-no-properties sel-beg sel-end))
-      (when (string-match "@\\([[:alpha:]-]+\\)" chunk)
-        (setq at-rule (match-string-no-properties 1 chunk))
-;;        (message "%S at-rule=%S" chunk at-rule)
+(defun web-mode-scan-django-block-comments (reg-beg reg-end)
+  "Scan extra"
+  (save-excursion
+    (let (beg end)
+      (goto-char reg-beg)
+      (while (and (< (point) reg-end)
+                  (re-search-forward "{% comment %}" reg-end t))
+        (goto-char (match-beginning 0))
+        (setq beg (point))
+        (goto-char (1+ (match-beginning 0)))
+        (when (re-search-forward "{% endcomment %}" reg-end t)
+;;          (setq end (1- (point)))
+          (setq end (point))
+          (remove-text-properties beg end web-mode-scan-properties)
+          (add-text-properties beg end '(block-side t block-token comment))
+          (put-text-property beg (1+ beg) 'block-beg t)
+          (put-text-property (1- end) end 'block-end t)
+;;          (remove-text-properties beg end web-mode-scan-properties)
+          ;; (add-text-properties
+          ;;  beg end
+          ;;  '(block-token comment font-lock-face web-mode-comment-face))
+          ) ;when
         )
-      );when
-    (if (not sel-end)
-        (progn (goto-char limit) nil)
-      (list :at-rule at-rule
-            :sel-beg sel-beg
-            :sel-end sel-end
-            :dec-beg dec-beg
-            :dec-end dec-end)
-      );if
+      )))
+
+(defun web-mode-interpolate-block-tag (beg end)
+  "Scan a block tag (jsp / mako) to fontify ${ } blocks"
+  (save-excursion
+    (goto-char (+ 4 beg))
+    (setq end (1- end))
+    (while (re-search-forward "${.*}" end t)
+      (remove-text-properties (match-beginning 0) (match-end 0) '(font-lock-face nil))
+      (web-mode-fontify-region (match-beginning 0) (match-end 0)
+                               web-mode-uel-font-lock-keywords)
+      )
     ))
 
-(defun web-mode-css-current-rule (pos min max)
-  "current css rule"
+;; todo : parsing plus compliqué: {$obj->values[3]->name}
+(defun web-mode-interpolate-string (beg end)
+  "Interpolate php/erb strings."
   (save-excursion
-    (let (beg end)
-      (goto-char pos)
-      (if (not (web-mode-sb-client "{" min t))
-          (progn
-            (setq beg min)
-            (if (web-mode-sf-client ";" max t)
-                (setq end (1+ (point)))
-              (setq end max))
-            )
-        (setq beg (point))
-        (setq end (web-mode-closing-paren-position beg max))
-        (if end
-            (setq end (1+ end))
-          (setq end max)
-          )
-;;        (message "%S >>beg%S >>end%S" pos beg end)
-        (if (> pos end)
+    (goto-char (1+ beg))
+    (setq end (1- end))
+    (cond
+     ((string= web-mode-engine "php")
+      (while (re-search-forward "$[[:alnum:]_]+\\(->[[:alnum:]_]+\\)*\\|{[ ]*$.+}" end t)
+        ;;web-mode-php-var-interpolation-font-lock-keywords
+;;        (message "la%S" (point))
+        (remove-text-properties (match-beginning 0) (match-end 0) '(font-lock-face nil))
+        (web-mode-fontify-region (match-beginning 0) (match-end 0)
+                                 web-mode-php-var-interpolation-font-lock-keywords)
 
-            ;;selectors
-            (progn
-              (goto-char pos)
-              (if (web-mode-rsb-client "[};]" min t)
-                  (setq beg (1+ (point)))
-                (setq beg min)
-                )
-              (goto-char pos)
-              (if (web-mode-rsf-client "[{;]" max t)
-                  (cond
-                   ((eq (char-before) ?\;)
-                    (setq end (point))
-                    )
-                   (t
-                    (setq end (web-mode-closing-paren-position (1- (point)) max))
-                    (if end
-                        (setq end (1+ end))
-                      (setq end max))
-                    )
-                   );cond
-                (setq end max)
-                )
-              );progn selectors
+        ;; (put-text-property (match-beginning 0) (match-end 0)
+        ;;                    'font-lock-face nil)
+        ;; (put-text-property (1+ (match-beginning 0)) (match-end 0)
+        ;;                    'font-lock-face 'web-mode-variable-name-face)
 
-          ;; declaration
-          (goto-char beg)
-          (if (web-mode-rsb-client "[}{;]" min t)
-              (setq beg (1+ (point)))
-            (setq beg min)
-            )
-          )
+        ))
+     ((string= web-mode-engine "erb")
+      (while (re-search-forward "#{.*}" end t)
+        (remove-text-properties (match-beginning 0) (match-end 0) '(font-lock-face nil))
+        (put-text-property (match-beginning 0) (match-end 0)
+                           'font-lock-face 'web-mode-variable-name-face)
+        ))
+     ) ;cond
+    ))
+
+(defun web-mode-interpolate-comment (beg end block-side)
+  "Interpolate comment"
+  (save-excursion
+    (let (regexp)
+      (goto-char beg)
+      (setq regexp (concat "\\<\\(" web-mode-comment-keywords "\\)\\>"))
+      (while (re-search-forward regexp end t)
+        (font-lock-prepend-text-property (match-beginning 1) (match-end 1)
+                                         'font-lock-face
+                                         'web-mode-comment-keyword-face)
         )
-;;      (message "beg(%S) end(%S)" beg end)
-      (cons beg end)
       )))
 
-;; http://www.w3.org/TR/html-markup/syntax.html#syntax-attributes
-;; states:
-;; nil(0) space(1) name(2) space-before(3) equal(4) space-after(5) value-uq(6) value-sq(7) value-dq(8)
-(defun web-mode-scan-attrs (beg end)
-  "Scan and fontify html attributes."
+(defun web-mode-dom-scan (reg-beg reg-end)
+  "Scan html nodes (tags/attrs/comments/doctype)."
   (save-excursion
-  ;;    (message "beg(%S) end(%S)" beg end)
-    (let (name-beg name-end val-beg val-end (state 0) char pos escaped spaced)
-      (goto-char (1- beg))
+    (let (part-beg part-end flags limit close-expr props tname tbeg tend tstop element-content-type regexp regexp1 regexp2 part-close-tag)
 
-      (while (< (point) end)
-        (forward-char)
-        (setq pos (point)
-              char (char-after))
-        (setq spaced (eq ?\s char))
-;;        (setq char (buffer-substring-no-properties pos (1+ pos)))
+      (setq regexp1 "<\\(/?[[:alpha:]][[:alnum:]-]*\\|!--\\|!\\[CDATA\\[\\|!doctype\\|\?xml\\)"
+            regexp2 "<\\(/?[[:alpha:]][[:alnum:]-]*\\|!--\\|!\\[CDATA\\[\\)")
 
-        (cond
+      (setq regexp regexp1)
 
-         ((= pos end)
-          (web-mode-propertize-attr state char name-beg name-end val-beg)
-          (setq state 0
-                name-beg nil
-                name-end nil
-                val-beg nil
-                val-end nil)
-          )
+      (goto-char reg-beg)
 
-         ((get-text-property pos 'block-side)
-          )
+      (while (web-mode-dom-rsf regexp reg-end t)
 
-         ((and spaced (= state 0))
-          (setq state 1)
-          )
+        (setq flags 0
+              tname (downcase (match-string-no-properties 1))
+              tbeg (match-beginning 0)
+              tend nil
+              tstop (point)
+              element-content-type nil
+              limit reg-end
+              part-beg nil
+              part-end nil
+              props nil
+              close-expr nil
+              part-close-tag nil)
 
-         ((and spaced (member state '(1 3 5)))
-          )
+        (cond
+         ((string= tname "!--")
+          (setq close-expr "-->"
+                props '(tag-type comment)))
+         ((string= tname "?xml")
+          (setq regexp regexp2
+                close-expr "?>"
+                props '(tag-type declaration)))
+         ((string= tname "![cdata[")
+          (setq close-expr "]]>"
+                props '(tag-type cdata)))
+         ((string= tname "!doctype")
+          (setq regexp regexp2
+                props '(tag-type doctype)))
+         (t
+          (when (string-match-p "-" tname)
+            (setq flags (logior flags 2)))
+          (cond
+           ((eq ?\/ (aref tname 0))
+            (setq props (list 'tag-name (substring tname 1) 'tag-type 'end)
+                  flags (logior flags 4))
+            (setq limit (if (> reg-end (line-end-position)) (line-end-position) reg-end)))
+           ((web-mode-element-is-void tname)
+            (setq props (list 'tag-name tname 'tag-type 'void)))
+           (t
+            (setq props (list 'tag-name tname 'tag-type 'start)))
+           ) ;cond
+          ) ;t
+         ) ;cond
 
-         ((and spaced (= state 2))
-          (setq state 3)
-          )
+        (cond
+         ((and (null close-expr) (eq (char-after) ?\>))
+          (setq flags (logior flags 16))
+          (forward-char)
+          (setq tend (point)))
+         ((and (null close-expr) (looking-at-p "[ ]*/>"))
+          (setq flags (logior flags 24))
+          (search-forward ">")
+          (setq tend (point)))
+         ((null close-expr)
+          (setq flags (logior flags (web-mode-tag-skip reg-end)))
+;;          (message "%S %S" tname (point))
+          (setq tend (point)))
+         ((web-mode-dom-sf close-expr limit t)
+          (setq tend (point)))
+         (t
+          (setq tend (line-end-position)))
+         )
 
-         ((and spaced (= state 4))
-          (setq state 5)
-          )
+        (cond
+         ((string= tname "style")
+          (setq element-content-type "css"
+                part-close-tag "</style>"))
+         ((member tname '("script"))
+          (let (script)
+            (setq script (buffer-substring-no-properties tbeg tend)
+                  part-close-tag "</script>")
+            (cond
+             ((string-match-p " type[ ]*=[ ]*[\"']text/jsx" script)
+              (setq element-content-type "jsx"))
+             ((string-match-p " type[ ]*=[ ]*[\"']text/\\(x-handlebars\\|html\\|ng-template\\)" script)
+              (setq element-content-type "html"
+                    part-close-tag nil))
+             ((string-match-p " type[ ]*=[ ]*[\"']application/\\(ld\\+json\\|json\\)" script)
+              (setq element-content-type "json"))
+             (t
+              (setq element-content-type "javascript"))
+             ) ;cond
+            ) ;let
+          ) ;script
+         )
 
-         ((and (= state 3)
-;;               (progn (message "pt=%S state=%S char=%c" (point) state char) t)
-               (or (and (>= char 65) (<= char 90)) ;; A - Z
-                   (and (>= char 97) (<= char 122)))) ;; a - z
-;;          (message "name-beg=%S name-end=%S char=%c" name-beg (- pos 1) char)
-;;          (message "%S %S - %S %S" ?a ?z ?A ?Z)
-          (web-mode-propertize-attr state char name-beg (- pos 1) val-beg)
-          (setq state 2
-                name-beg pos
-                name-end nil
-                val-beg nil
-                val-end nil)
-          )
+;;        (message "%S %S %S %S" tname (point) part-close-tag reg-end)
 
-         ((and (eq ?\n char) (not (member state '(7 8))))
-          (web-mode-propertize-attr state char name-beg name-end val-beg)
-          (setq state 2
-                name-beg nil
-                name-end nil
-                val-beg nil
-                val-end nil)
+        (add-text-properties tbeg tend props)
+        (put-text-property tbeg (1+ tbeg) 'tag-beg flags)
+        (put-text-property (1- tend) tend 'tag-end t)
+
+        (when (and part-close-tag
+                   (web-mode-dom-sf part-close-tag reg-end t)
+                   (setq part-beg tend)
+                   (setq part-end (match-beginning 0))
+;;                   (progn (message "%S %S" part-beg part-end) t)
+                   (> part-end part-beg))
+          (put-text-property part-beg part-end 'part-side (intern element-content-type))
+;;          (goto-char part-end)
           )
 
-         ((or (and (eq ?\" char) (= state 8) (not escaped))
-              (and (eq ?\' char) (= state 7) (not escaped))
-              (and (member char '(?\s ?\n ?\>)) (= state 6)))
-          (web-mode-propertize-attr state char name-beg name-end val-beg)
-          (setq state (if (= state 6) 1 0)
-                name-beg nil
-                name-end nil
-                val-beg nil
-                val-end nil)
-          )
+        (goto-char tend)
 
-         ((and (not spaced) (= state 1))
-          (setq state 2)
-          (setq name-beg pos)
-          )
+        ) ;while
 
-         ((and (eq ?\= char) (member state '(2 3)))
-          (setq name-end pos)
-          (setq state 4)
-          )
+      )))
 
-         ((and (eq ?\" char) (member state '(4 5)))
-          (setq val-beg pos)
-          (setq state 8)
-          )
+;;todo :
+;; tag-type : start / end / void / comment / cdata / doctype / declaration
+;; tag-name uniquement sur les html tag
 
-         ((and (eq ?\' char) (member state '(4 5)))
-          (setq val-beg pos)
-          (setq state 7)
-          )
+;; piste d'optim : associer tagname à 'tag-end
 
-         ((member state '(4 5))
-          (setq val-beg pos)
-          (setq state 6)
-          )
 
-         ((= state 1)
-          (setq state 2)
-          )
+;; tag flags
+;; (1)attrs (2)custom (4)slash-beg (8)slash-end (16)brackend-end
 
-         );;cond
+;; states:
+;; (0)nil (1)space (2)name (3)space-before (4)equal (5)space-after (6)value-uq (7)value-sq (8)value-dq
 
-        ;;        (message "point(%S) end(%S) state(%S) c(%S) name-beg(%S) name-end(%S) val-beg(%S) val-end(%S)" pos end state char name-beg name-end val-beg val-end)
+;; http://dev.w3.org/html5/html-author/#tags
+;; http://www.w3schools.com/jsref/prop_node_nodetype.asp
+;; start-tag, end-tag, tag-name, element (<a>xsx</a>, an element is delimited by tags), void-element
+;; http://www.w3.org/TR/html-markup/syntax.html#syntax-elements
+;; http://www.w3.org/TR/html-markup/syntax.html#syntax-attributes
+(defun web-mode-tag-skip (limit)
+  "Scan attributes and fetch end of tag."
+  (let ((tag-flags 0) (attr-flags 0) (continue t) (attrs 0) (counter 0)
+        (pos-ori (point)) (state 0) (equal-offset 0) (go-back nil)
+        name-beg name-end val-beg char pos escaped spaced quoted)
 
-        (setq escaped (eq ?\\ char))
+    (while continue
 
-        );;while
+      (setq pos (point)
+            char (char-after)
+            spaced (eq char ?\s))
 
-      )))
+      (when quoted (setq quoted (1+ quoted)))
 
-(defun web-mode-propertize-attr (state char name-beg name-end val-beg &optional val-end)
-  "propertize attr."
-  (unless val-end (setq val-end (point)))
-  ;;  (message "point(%S) state(%S) c(%S) name-beg(%S) name-end(%S) val-beg(%S) val-end(%S)" (point) state char name-beg name-end val-beg val-end)
-  (cond
-   ((and (= state 8) (not (eq ?\" char)))
-    )
-   ((and (= state 7) (not (eq ?\' char)))
-    )
-   ((= state 4)
-    )
-   ((null name-beg)
-    )
-   (t
-    (setq name-end (if name-end name-end (point)))
-    (if (or (= state 3)
-            (and (= state 8) (eq ?\" char))
-            (and (= state 7) (eq ?\' char)))
-        (add-text-properties name-beg name-end
-                             (list 'part-token 'attr 'face
-                                   (if (and (>= (- name-end name-beg) 3)
-                                            (string-match-p "-"
-                                             (buffer-substring-no-properties
-                                              name-beg name-end)))
-                                       'web-mode-html-attr-custom-face
-                                     'web-mode-html-attr-name-face)))
-      (add-text-properties name-beg name-end
-                           '(part-token attr face web-mode-html-attr-name-face)))
-    (when (and val-beg val-end)
-      (setq val-end (if (eq ?\> char) val-end (1+ val-end)))
-      (add-text-properties val-beg val-end '(part-token attr face web-mode-html-attr-value-face))
-      (put-text-property name-end val-beg 'face 'web-mode-html-attr-equal-face))
-    );t
-   );cond
-  )
+      (cond
 
-(defun web-mode-velocity-skip-forward (pos)
-  "find the end of a velocity block."
-  (goto-char pos)
-  (let (continue)
-    (when (eq ?\# (char-after))
-      (forward-char))
-    ;;(message "pt=%S %c" (point) (char-after))
-    (when (member (char-after) '(?\$ ?\@))
-      ;;              (message "pt=%S" (point))
-      (forward-char))
-    (when (member (char-after) '(?\!))
-      ;;              (message "pt=%S" (point))
-      (forward-char))
-    (if (member (char-after) '(?\{))
-        (search-forward "}")
-      (setq continue t)
-      (while continue
-        (skip-chars-forward "a-zA-Z0-9_-")
-        (when (member (char-after) '(?\())
-          (search-forward ")")
-          )
-        (if (member (char-after) '(?\.))
-            (forward-char)
-          (setq continue nil))
-        );while
-      );if
-    ))
+       ((>= pos limit)
+        (setq continue nil)
+        (setq go-back t)
+        (setq attrs (+ attrs (web-mode-scan-attr state char name-beg name-end val-beg attr-flags equal-offset)))
+        )
 
-(defun web-mode-razor-tag-exclude (block-beg block-end)
-  "Exclude HTML"
-  (save-excursion
-    (goto-char block-beg)
-;;    (message "block-beg(%S) block-end(%S)" block-beg block-end)
-    (let ((continue t) beg end tag-beg tag-end)
-      (while (re-search-forward "[ \t]*\\(</?[[:alpha:]].*?>\\)[ \n]*" block-end t)
-        (setq beg (match-beginning 0)
-              end (match-end 0)
-              tag-beg (match-beginning 1)
-              tag-end (match-end 1))
-;;        (message "beg(%S) end(%S)" beg end)
-        (remove-text-properties beg end '(block-side))
-        (put-text-property (1- tag-beg) tag-beg 'block-end t)
-        (put-text-property tag-end (1+ tag-end) 'block-beg t)
-        (when (and (looking-at "\\(.+\\)<")
-                   (not (string-match-p "@" (match-string-no-properties 1))))
-          (remove-text-properties (match-beginning 1) (match-end 1) '(block-side))
+       ((get-text-property pos 'block-side)
+        )
+
+       ((and (not (member state '(7 8)))
+             (eq char ?\<))
+        (setq continue nil)
+        (setq go-back t)
+        (setq attrs (+ attrs (web-mode-scan-attr state char name-beg name-end val-beg attr-flags equal-offset)))
+        )
+
+       ((and (not (member state '(7 8)))
+             (eq char ?\>))
+        (setq tag-flags (logior tag-flags 16))
+        (when (eq (char-before) ?\/)
+          (setq tag-flags (logior tag-flags 8))
           )
+        (setq continue nil)
+        (setq attrs (+ attrs (web-mode-scan-attr state char name-beg name-end val-beg attr-flags equal-offset)))
         )
-      )))
 
-(defun web-mode-razor-skip-forward (pos)
-  "Find the end of a razor block."
-  (goto-char pos)
-  ;;            (message "pt=%S %c" (point) (char-after))
-  (let ((continue t) pt)
-    (while continue
-      (skip-chars-forward " =@a-zA-Z0-9_-")
-      (cond
-       ((looking-at-p "@[({]")
-        (forward-char)
-        (goto-char (web-mode-closing-paren-position (point)))
-        (forward-char)
+       ((and spaced (= state 0))
+        (setq state 1)
         )
-       ((eq ?\( (char-after))
-        (goto-char (web-mode-closing-paren-position))
-        (forward-char)
+
+       ((and spaced (member state '(1 3 5)))
         )
-       ((eq ?\. (char-after))
-        (forward-char))
-       ((looking-at-p "[ \n]*{")
-        (search-forward "{")
-        (backward-char)
-        (goto-char (web-mode-closing-paren-position))
-        (forward-char)
+
+       ((and spaced (= state 2))
+        (setq state 3)
         )
-       (t
-        (setq continue nil))
-       );cond
-      );while
-    ))
 
-(defun web-mode-colorize-foreground (color)
-  "Colorize foreground based on background luminance."
-  (let* ((values (x-color-values color))
-	 (r (car values))
-	 (g (cadr values))
-	 (b (car (cdr (cdr values)))))
-    (if (> 128.0 (floor (+ (* .3 r) (* .59 g) (* .11 b)) 256))
-	"white" "black")))
+       ((and (eq char ?\/) (member state '(4 5)))
+        (setq attrs (+ attrs (web-mode-scan-attr state char name-beg name-end val-beg attr-flags equal-offset)))
+        (setq state 1
+              attr-flags 0
+              equal-offset 0
+              name-beg nil
+              name-end nil
+              val-beg nil)
+        )
 
-(defun web-mode-colorize (beg end)
-  "Colorize CSS colors."
-  (let (str plist len)
-    (setq str (buffer-substring-no-properties beg end))
-    (setq len (length str))
-    (cond
-     ((string= (substring str 0 1) "#")
-      (setq plist (list :background str
-                        :foreground (web-mode-colorize-foreground str)))
-      (put-text-property beg end 'face plist))
-     ((string= (substring str 0 4) "rgb(")
-      (setq str (format "#%02X%02X%02X"
-                        (string-to-number (match-string-no-properties 1))
-                        (string-to-number (match-string-no-properties 2))
-                        (string-to-number (match-string-no-properties 3))))
-      (setq plist (list :background str
-                        :foreground (web-mode-colorize-foreground str)))
-      (put-text-property beg end 'face plist))
-     );cond
-    ))
+       ((and (eq char ?\/) (member state '(0 1)))
+        )
 
-(defun web-mode-fontify-region (beg end keywords)
-  "Highlight block."
-  (save-excursion
-;;    (message "beg=%S end=%S" beg end)
-    (let ((font-lock-keywords keywords)
-          (font-lock-multiline nil)
-          (font-lock-keywords-case-fold-search (member web-mode-engine
-                                                       '("asp"
-                                                         "template-toolkit")))
-          (font-lock-keywords-only t)
-          (font-lock-extend-region-functions nil))
-      (font-lock-fontify-region beg end)
-      ))
-  ;; UGLY HACK / workaround (help needed)
-  (unless web-mode-buffer-highlighted
-    (setq web-mode-buffer-highlighted t)
-    (web-mode-fontify-region beg end keywords))
-  )
+       ((and spaced (= state 4))
+        (setq state 5)
+        )
 
-(defun web-mode-fill-paragraph (&optional justify)
-  "fill paragraph"
-  (save-excursion
-    (let ((pos (point)) fill-coll
-          prop pair beg end delim-beg delim-end chunk fill-col)
-      (cond
-       ((or (eq (get-text-property pos 'part-token) 'comment)
-            (eq (get-text-property pos 'block-token) 'comment))
-        (setq prop
-              (if (get-text-property pos 'part-token) 'part-token 'block-token))
-        (setq pair (web-mode-property-boundaries prop pos))
-        (when (and pair (> (- (cdr pair) (car pair)) 6))
-          (setq fill-coll (if (< fill-column 10) 70 fill-column))
-          (setq beg (car pair)
-                end (cdr pair))
-          (goto-char beg)
-          (setq chunk (buffer-substring-no-properties beg (+ beg 2)))
-          (cond
-           ((string= chunk "//")
-            (setq delim-beg "//"
-                  delim-end "EOL"))
-           ((string= chunk "/*")
-            (setq delim-beg "/*"
-                 delim-end "*/"))
-           ((string= chunk "{#")
-            (setq delim-beg "{#"
-                  delim-end "#}"))
-           ((string= chunk "<!")
-            (setq delim-beg "<!--"
-                  delim-end "-->"))
-           )
-          ;;          (subst-char-in-region beg end ?\n ?\s)
-          ;;          (message "fill-column=%S pt=%S pair=%S chunk=%S"
-          ;;                   fill-column (point) pair chunk)
-          )
-        );comment - case
+       ((and (= state 3)
+             (or (eq char ?\-)
+                 (and (>= char 65) (<= char 90)) ;A - Z
+                 (and (>= char 97) (<= char 122)) ;a - z
+                 ))
+        (setq attrs (+ attrs (web-mode-scan-attr state char name-beg name-end val-beg attr-flags equal-offset)))
+        (setq state 2
+              attr-flags 0
+              equal-offset 0
+              name-beg pos
+              name-end pos
+              val-beg nil)
+        )
 
-       ((web-mode-is-html-text)
-        (setq pair (web-mode-property-boundaries prop pos))
-        (setq beg (previous-property-change pos)
-              end (next-property-change pos))
+       ((and (eq char ?\n) (not (member state '(7 8))))
+        (setq attrs (+ attrs (web-mode-scan-attr state char name-beg name-end val-beg attr-flags equal-offset)))
+        (setq state 1
+              attr-flags 0
+              equal-offset 0
+              name-beg nil
+              name-end nil
+              val-beg nil)
         )
 
-       );cond
-      ;;(message "beg%S end%S" beg end)
-      (when (and beg end)
-        (fill-region beg end))
-      t)))
+       ((and (member char '(?\s ?\n ?\/)) (= state 6))
+        (setq attrs (+ attrs (web-mode-scan-attr state char name-beg name-end val-beg attr-flags equal-offset)))
+        (setq state 1
+              attr-flags 0
+              equal-offset 0
+              name-beg nil
+              name-end nil
+              val-beg nil)
+        )
 
-(defun web-mode-property-boundaries (prop &optional pos)
-  "property boundaries (cdr is 1+)"
-  (unless pos (setq pos (point)))
-  (let (beg end val)
-    (setq val (get-text-property pos prop))
-    (if (null val)
-        val
-      (if (or (bobp)
-              (not (eq (get-text-property (1- pos) prop) val)))
-          (setq beg pos)
-        (setq beg (previous-single-property-change pos prop))
-        (when (null beg) (setq beg (point-min))))
-      (if (or (eobp)
-              (not (eq (get-text-property (1+ pos) prop) val)))
-          (setq end pos)
-        (setq end (next-single-property-change pos prop))
-        (when (null end) (setq end (point-min))))
-      (cons beg end))))
+       ((and quoted (= quoted 2) (member char '(?\s ?\n ?\>)))
+;;        (message "ici %S %S" state val-beg)
+        (when (eq char ?\>)
+          (setq tag-flags (logior tag-flags 16))
+          (setq continue nil))
+        (setq state 6)
+        (setq attrs (+ attrs (web-mode-scan-attr state char name-beg name-end val-beg attr-flags equal-offset)))
+        (setq state 1
+              attr-flags 0
+              equal-offset 0
+              name-beg nil
+              name-end nil
+              val-beg nil)
+        )
 
-(defun web-mode-scan-whitespaces (beg end)
-  "Scan whitespaces."
-  (save-excursion
-    (goto-char beg)
-    (while (re-search-forward web-mode-whitespaces-regexp end t)
-      (add-text-properties (match-beginning 0) (match-end 0)
-                           '(face web-mode-whitespace-face))
-      );while
-    ))
+       ((or (and (eq ?\" char) (= state 8) (not escaped))
+            (and (eq ?\' char) (= state 7) (not escaped)))
+        (setq attrs (+ attrs (web-mode-scan-attr state char name-beg name-end val-beg attr-flags equal-offset)))
+        (setq state 0
+              attr-flags 0
+              equal-offset 0
+              name-beg nil
+              name-end nil
+              val-beg nil)
+        )
 
-(defun web-mode-errors-show ()
-  "Show unclosed tags."
-  (interactive)
-  (let (beg end tag pos l n tags i cont cell overlay overlays first
-            (ori (point))
-            (errors 0)
-            (continue t)
+       ((and (not spaced) (= state 1))
+        (setq state 2)
+        (setq name-beg pos
+              name-end pos)
         )
-    (setq overlays (overlays-in (point-min) (point-max)))
-    (when overlays
-      (dolist (overlay overlays)
-        (when (eq (overlay-get overlay 'face) 'web-mode-warning-face)
-          (delete-overlay overlay)
-          )
+
+       ((and (eq ?\= char) (member state '(2 3)))
+        (setq equal-offset (- pos name-beg))
+        (setq state 4)
         )
-      )
-    (goto-char (point-min))
-    (when (not (or (get-text-property (point) 'tag-beg)
-                   (web-mode-tag-next)))
-      (setq continue nil))
-    (while continue
-      (setq pos (point))
-      (setq tag (get-text-property pos 'tag-name))
-      (cond
-       ((eq (get-text-property (point) 'tag-type) 'start)
-        (setq tags (add-to-list 'tags (list tag pos)))
-;;        (message "(%S) opening %S" pos tag)
+
+       ((and (member char '(?\' ?\")) (member state '(4 5)))
+        (setq val-beg pos)
+        (setq quoted 1)
+        (setq state (if (eq ?\' char) 7 8))
         )
-       ((eq (get-text-property (point) 'tag-type) 'end)
-        (setq i 0
-              l (length tags)
-              cont t)
-        (while (and (< i l) cont)
-          (setq cell (nth i tags))
-;;          (message "cell=%S" cell)
-          (setq i (1+ i))
-          (cond
-           ((string= tag (nth 0 cell))
-            (setq cont nil)
-            )
-           (t
-            (setq errors (1+ errors))
-            (setq beg (nth 1 cell))
-            (setq end (web-mode-tag-end-position beg))
-            (unless first
-              (setq first beg))
-            (setq overlay (make-overlay beg (1+ end)))
-            (overlay-put overlay 'face 'web-mode-warning-face)
-;;            (message "invalid <%S> at %S" (nth 0 cell) (nth 1 cell))
-            )
-           );cond
-          );while
 
-        (dotimes (i i)
-          (setq tags (cdr tags))
-;;          (setq cell (nth i tags))
-;;          (message "removing=%S" cell)
-          )
+       ((member state '(4 5))
+        (setq val-beg pos)
+        (setq state 6)
+        )
 
+       ((= state 1)
+        (setq state 2)
         )
-       );cond
-      (when (not (web-mode-tag-next))
-        (setq continue nil))
-      );while
-    (message "%S error(s) detected" errors)
-    (if (> errors 0)
-        (progn (goto-char first)
-               (recenter))
-      (goto-char ori)
-      );if
-    ;;    (message "%S" tags)
-    ))
 
-(defun web-mode-whitespaces-show ()
-  "Toggle whitespaces."
-  (interactive)
-  (if web-mode-enable-whitespaces
-      (web-mode-whitespaces-off)
-    (web-mode-whitespaces-on))
-  (web-mode-scan-buffer))
+       ((= state 2)
+        (setq name-end pos)
+        (when (and (= attr-flags 0) (eq char ?\-))
+          (setq attr-flags (logior attr-flags 1)))
+        (when (= (logand attr-flags 1) 1)
+          (let (attr)
+            (setq attr (buffer-substring-no-properties name-beg (1+ name-end)))
+            (cond
+             ((member attr '("http-equiv"))
+              (setq attr-flags (1- attr-flags))
+              )
+             ((and web-mode-engine-attr-regexp
+                   (string-match-p web-mode-engine-attr-regexp attr))
+              ;;            (message "%S" web-mode-engine-attr-regexp)
+              (setq attr-flags (logior attr-flags 2))
+              (setq attr-flags (1- attr-flags))
+              )
+             ) ;cond
+            ) ;let
+          ) ;when attr-flags = 1
+        ) ;state=2
 
-(defun web-mode-whitespaces-on ()
-  "Show whitespaces."
-  (interactive)
-  (when web-mode-hl-line-mode-flag
-    (global-hl-line-mode -1))
-  (when web-mode-display-table
-    (setq buffer-display-table web-mode-display-table))
-  (setq web-mode-enable-whitespaces t))
+       ) ;cond
 
-(defun web-mode-whitespaces-off ()
-  "Hide whitespaces."
-  (when web-mode-hl-line-mode-flag
-    (global-hl-line-mode 1))
-  (setq buffer-display-table nil)
-  (setq web-mode-enable-whitespaces nil))
+      ;;(message "point(%S) end(%S) state(%S) c(%S) name-beg(%S) name-end(%S) val-beg(%S) attr-flags(%S) equal-offset(%S)" pos end state char name-beg name-end val-beg attr-flags equal-offset)
 
-(defun web-mode-buffer-indent ()
-  "Indent all buffer."
-  (interactive)
-  (indent-region (point-min) (point-max))
-  (delete-trailing-whitespace))
+      (when (and quoted (>= quoted 2))
+        (setq quoted nil))
 
-(defun web-mode-buffer-refresh ()
-  "Indent and fontify buffer."
-  (interactive)
-  (web-mode-scan-buffer)
-  (web-mode-buffer-indent))
+      (setq escaped (eq ?\\ char))
+      (when (null go-back)
+        (forward-char))
 
-(defun web-mode-buffer-change-tag-case (&optional type)
-  "Change HTML tag case."
-  (interactive)
-  (save-excursion
-    (goto-char (point-min))
-    (let ((continue t) f)
-      (setq f (if (member type '("upper" "uppercase" "upper-case")) 'uppercase 'downcase))
-      (when (and (not (get-text-property (point) 'tag-beg))
-                 (not (web-mode-tag-next)))
+      (when (> (setq counter (1+ counter)) 2000)
+        (message "too much attr (%S) %S" pos-ori limit)
         (setq continue nil))
-      (while continue
-        (skip-chars-forward "<!/")
-        (if (looking-at "\\([[:alnum:]-]+\\)")
-            (replace-match (funcall f (match-string 0)) t))
-;;        (message "tag: %S (%S)"
-;;                 (get-text-property (point) 'tag-name)
-;;                 (point))
-        (unless (web-mode-tag-next)
-          (setq continue nil))
-        );while
-      )))
 
-(defun web-mode-buffer-change-attr-case (&optional type)
-  "alter tag case"
-  (interactive)
-  (save-excursion
-    (goto-char (point-min))
-    (let ((continue t) f)
-      (setq f (if (member type '("upper" "uppercase" "upper-case")) 'uppercase 'downcase))
-      (while continue
-        (if (web-mode-attr-next)
-            (when (looking-at "\\([[:alnum:]-]+\\)")
-              (replace-match (funcall f (match-string 0)) t)
-;;              (message "tag: %S (%S)" (match-string 0) (point))
-              );when
-          (setq continue nil))
-        );while
-      )))
+      ) ;while
 
-;; tag-case=lower|upper-case , attr-case=lower|upper-case
-;; special-chars=unicode|html-entities
-;; smart-apostrophes=bool , smart-quotes=bool , indentation=bool
-(defun web-mode-buffer-normalize ()
-  "Normalize buffer"
-  (interactive)
-  (let ((rules web-mode-normalization-rules) elt)
-    (when (setq elt (cdr (assoc "tag-case" rules)))
-      (web-mode-buffer-change-tag-case elt))
-    (when (setq elt (cdr (assoc "attr-case" rules)))
-      (web-mode-buffer-change-attr-case elt))
-    (when (setq elt (cdr (assoc "smart-apostrophes" rules)))
-      (web-mode-apostrophes-replace))
-    (when (setq elt (cdr (assoc "smart-quotes" rules)))
-      (web-mode-quotes-replace))
-    (when (setq elt (cdr (assoc "special-chars" rules)))
-      (if (string= elt "entities")
-          (web-mode-entities-encode)
-        (web-mode-entities-replace))
-      );when
-    (when (setq elt (cdr (assoc "indentation" rules)))
-      (web-mode-buffer-indent))
-      ))
+    (when (> attrs 0)
+      (setq tag-flags (logior tag-flags 1)))
 
-(defun web-mode-previous-usable-server-line ()
-  "Return previous non blank/comment/string line and return this line (trimmed)."
-  (interactive)
-  (save-excursion
-    (let ((continue t)
-          (line "")
-          (pos (point)))
-      (beginning-of-line)
-      (while (and continue
-                  (not (bobp))
-                  (forward-line -1))
-        (if (not (web-mode-is-comment-or-string-line))
-            (setq line (web-mode-trim (buffer-substring (point) (line-end-position)))))
-        (when (not (string= line "")) (setq continue nil))
-        );while
-      (if (string= line "")
-          (progn (goto-char pos) nil)
-        (cons line (current-indentation)))
-      )))
+    tag-flags))
 
-(defun web-mode-previous-usable-client-line ()
-  "Return previous non blank/comment/string line and return this line (trimmed)."
-  (interactive)
-  (save-excursion
-    (let ((continue t)
-          (line "")
-          (pos (point)))
-      (beginning-of-line)
-      (while (and continue
-                  (not (bobp))
-                  (forward-line -1))
-        (if (not (web-mode-is-part-token-line))
-            (setq line (web-mode-trim (buffer-substring (point) (line-end-position)))))
-        (when (not (string= line "")) (setq continue nil))
-        )
-      (if (string= line "")
-          (progn (goto-char pos) nil)
-        (cons line (current-indentation)))
-      )))
 
-(defun web-mode-in-code-block (open close &optional prop)
-  "Detect if point is in a block delimited by open and close."
-  (save-excursion
-    (let ((pos (point)) pos-open pos-close start end ret)
-      (when prop
-        (setq start pos
-              end pos)
-        (when (eq (get-text-property pos prop) (get-text-property (1- pos) prop))
-          (setq start (or (previous-single-property-change pos prop) (point-min))))
-        (when (eq (get-text-property pos prop) (get-text-property (1+ pos) prop))
-          (setq end (next-single-property-change pos prop)))
-        ;;        (message "start(%S) end(%S)" start end)
-        )
-      (setq ret (and (web-mode-sb open start t)
-                     (setq pos-open (point))
-                     (web-mode-sf close end t)
-                     (setq pos-close (point))
-                     (>= pos-close pos)))
-      (if ret
-          (cons pos-open pos-close)
-        ret)
-      )))
+;; attr flags
+;; (1)custom-attr (2)engine-attr
 
-(defun web-mode-line-number (&optional pos)
-  "Return line number at point."
-  (unless pos (setq pos (point)))
-  (let (ret)
-    (setq ret (+ (count-lines 1 pos)
-                 (if (= (web-mode-column-at-pos pos) 0) 1 0)))
-    ret))
+;; states:
+;; (0)nil (1)space (2)name (3)space-before (4)equal (5)space-after (6)value-uq (7)value-sq (8)value-dq
+(defun web-mode-scan-attr (state char name-beg name-end val-beg flags equal-offset)
+  "propertize attr."
+;;  (when (null char)
+;;    (message "pt=%S" (point)))
 
-(defun web-mode-clean-client-line (input)
-  "Remove comments and server scripts."
-  (let ((out "")
-        (beg 0)
-        (keep t)
-        (n (length input)))
-    (dotimes (i n)
-      (if (or (get-text-property i 'block-side input)
-              (eq (get-text-property i 'part-token input) 'comment))
-          (when keep
-            (setq out (concat out (substring input beg i))
-                  beg 0
-                  keep nil))
-        (when (null keep)
-          (setq beg i
-                keep t))
-        );if
-      ;;      (message "out=%s beg=%d" out beg)
-      );dotimes
-    (if (> beg 0) (setq out (concat out (substring input beg n))))
-    (setq out (if (= (length out) 0) input out))
-    (web-mode-trim out)
-    ;;    (message "%S [%s] > [%s]" beg input out)
-    ))
+;;  (message "point(%S) state(%S) c(%c) name-beg(%S) name-end(%S) val-beg(%S) flags(%S) equal-offset(%S)"
+;;           (point) state char name-beg name-end val-beg flags equal-offset)
+  (if (null flags) (setq flags 0))
+  (cond
+   ((or (null name-beg))
+    0)
+   ((or (and (= state 8) (not (eq ?\" char)))
+        (and (= state 7) (not (eq ?\' char))))
+    (put-text-property name-beg val-beg 'tag-attr flags)
+    (put-text-property (1- val-beg) val-beg 'tag-attr-end equal-offset)
+    1)
+   ((and (member state '(4 5)) (null val-beg))
+    (put-text-property name-beg (+ name-beg equal-offset 1) 'tag-attr flags)
+    (put-text-property (+ name-beg equal-offset) (+ name-beg equal-offset 1) 'tag-attr-end equal-offset)
+    1)
+   (t
+    (let (val-end)
+      (if (null val-beg)
+          (setq val-end name-end)
+        (setq val-end (point))
+        (when (or (null char) (member char '(?\s ?\n ?\> ?\/)))
+          (setq val-end (1- val-end))
+;;          (message "val-end=%S" val-end)
+          )
+        ) ;if
+      (put-text-property name-beg (1+ val-end) 'tag-attr flags)
+      (put-text-property val-end (1+ val-end) 'tag-attr-end equal-offset)
+      ) ;let
+    1) ;t
+   (t
+    0)
+   ) ;cond
+  )
 
-(defun web-mode-clean-server-line (input)
-  "Remove comments from server line."
-  (let ((out "")
-        (beg 0)
-        (keep t)
-        (n (length input)))
-    (dotimes (i n)
-      (if (eq (get-text-property i 'block-token input) 'comment)
-          (when keep
-            (setq out (concat out (substring input beg i))
-                  beg 0
-                  keep nil))
-        (when (null keep)
-          (setq beg i
-                keep t))
-        );if
-      );dotimes
-    (if (> beg 0) (setq out (concat out (substring input beg n))))
-    (setq out (if (= (length out) 0) input out))
-    (web-mode-trim out)
-    ;;    (message "%S [%s] > [%s]" beg input out)
+(defun web-mode-highlight-tags (reg-beg reg-end)
+  "web-mode-highlight-nodes"
+  (let ((continue t))
+    (goto-char reg-beg)
+    (when (and (not (get-text-property (point) 'tag-beg))
+               (not (web-mode-tag-next)))
+      (setq continue nil))
+    (when (and continue (>= (point) reg-end))
+      (setq continue nil))
+    (while continue
+      (web-mode-highlight-tag)
+      (when (or (not (web-mode-tag-next))
+                (>= (point) reg-end))
+        (setq continue nil))
+      ) ;while
+    (when web-mode-enable-inlays
+      (when (null web-mode-inlay-regexp)
+        (setq web-mode-inlay-regexp (regexp-opt '("\\[" "\\(" "\\begin{align}"))))
+      (let (beg end expr)
+        (goto-char reg-beg)
+        (while (web-mode-dom-rsf web-mode-inlay-regexp reg-end)
+          (setq beg (match-beginning 0)
+                end nil
+                expr (substring (match-string-no-properties 0) 0 2))
+          (setq expr (cond
+                      ((string= expr "\\[") "\\]")
+                      ((string= expr "\\(") "\\)")
+                      (t "\\end{align}")))
+          (when (and (web-mode-dom-sf expr reg-end)
+                     (setq end (match-end 0))
+                     (not (text-property-any beg end 'tag-end t)))
+;;            (message "%S %S" beg end)
+;;            (web-mode-fontify-region beg end 'web-mode-latex-font-lock-keywords)
+            (font-lock-append-text-property beg end 'face 'web-mode-inlay-face)
+            ) ;when
+          ) ;while
+        ) ;let
+      ) ;when
     ))
 
-(defun web-mode-column-at-pos (&optional pos)
-  "Column at point"
-  (unless pos (setq pos (point)))
-  (save-excursion
-    (goto-char pos)
-    (current-column)
-    ))
+;; flags
+;; (1)attrs (2)custom (4)slash-beg (8)slash-end (16)brackend-end
+(defun web-mode-highlight-tag ()
+  "web-mode-highlight-nodes"
+  (let ((beg (point)) end name type face flags slash-beg slash-end bracket-end)
 
-;; doit-on considérer que '=' est un bloc ouvrant avec ';' comme char de fin ?
-(defun web-mode-point-context (pos)
-  "POS should be at the beginning of the indentation.
-   Return ctx = plist containing
-    :block-beg, :block-column,
-    :first-char, :line (trimmed)
-    :type (live, comment, string),
-    :language (html, php, jsp, aspx, asp + javascript, css),
-    :indent-offset
-    :prev-line :prev-char :prev-props :prev-indentation"
-  (save-excursion
-    (let (ctx pos-min
-              block-beg block-column first-char line type language indent-offset
-              prev prev-line prev-char prev-props prev-indentation)
+    (setq end (1+ (web-mode-tag-end-position beg))
+          flags (get-text-property beg 'tag-beg)
+          type (get-text-property beg 'tag-type)
+          name (get-text-property beg 'tag-name))
 
-      (setq pos-min (point-min))
-      (setq block-beg pos-min
-            block-column 0
-            type "live"
-            language ""
-            prev-line ""
-            prev-char 0)
-      (cond
+    (cond
 
-       ((bobp)
-        (setq language "html")
+     ((eq type 'comment)
+      (put-text-property beg end 'font-lock-face 'web-mode-comment-face)
+;;      (message "web-mode-enable-comment-keywords=%S beg(%S) end(%S)" web-mode-enable-comment-keywords beg end)
+      (when (and web-mode-enable-comment-keywords (> (- end beg) 5))
+        (web-mode-interpolate-comment beg end nil))
+      )
+
+     ((eq type 'cdata)
+      (put-text-property beg end 'font-lock-face 'web-mode-doctype-face))
+
+     ((eq type 'doctype)
+      (put-text-property beg end 'font-lock-face 'web-mode-doctype-face))
+
+     ((eq type 'declaration)
+      (put-text-property beg end 'font-lock-face 'web-mode-doctype-face))
+
+     (name
+
+      ;; todo : se passer des vars intermédiaires
+      (setq face (if (> (logand flags 2) 0) 'web-mode-html-tag-custom-face 'web-mode-html-tag-face)
+            slash-beg (> (logand flags 4) 0)
+            slash-end (> (logand flags 8) 0)
+            bracket-end (> (logand flags 16) 0))
+
+      (put-text-property beg (+ beg (if slash-beg 2 1)) 'font-lock-face 'web-mode-html-tag-bracket-face)
+      (put-text-property (+ beg (if slash-beg 2 1))
+                         (+ beg (if slash-beg 2 1) (length name))
+                         'font-lock-face face)
+      (when (or slash-end bracket-end)
+        (put-text-property (- end (if slash-end 2 1)) end 'font-lock-face 'web-mode-html-tag-bracket-face)
+        ) ;when
+
+      (when (> (logand flags 1) 0)
+        (web-mode-highlight-attrs beg end)
         )
 
-       ((string= web-mode-content-type "css")
-        (setq language "css"
-              indent-offset web-mode-css-indent-offset))
+      ) ;name
 
-       ((member web-mode-content-type '("javascript" "json"))
-        (setq language "javascript"
-              indent-offset web-mode-code-indent-offset))
+     ) ;cond
 
-       ((string= web-mode-content-type "php")
-        (setq language "php"
-              indent-offset web-mode-code-indent-offset))
+    ))
 
-       ((or (string= web-mode-content-type "xml"))
-        (setq language "xml"
-              indent-offset web-mode-markup-indent-offset))
+;; todo : optimisation des zones reg-beg et reg-end
+(defun web-mode-highlight-attrs (reg-beg reg-end)
+  "Highlight attributes."
+  (let ((continue t) (pos reg-beg) beg end flags offset face)
+    (while continue
+      (setq beg (next-single-property-change pos 'tag-attr))
+      (if (and beg (< beg reg-end))
+          (progn
+            (setq flags (get-text-property beg 'tag-attr))
+;;            (message "beg=%S flags=%S" beg flags)
+            (setq face (cond
+                        ((= (logand flags 1) 1) 'web-mode-html-attr-custom-face)
+                        ((= (logand flags 2) 2) 'web-mode-html-attr-engine-face)
+                        (t 'web-mode-html-attr-name-face)))
+            (if (get-text-property beg 'tag-attr-end)
+                (setq end beg)
+              (setq end (next-single-property-change beg 'tag-attr-end)))
+;;            (message "beg=%S end=%S" beg end)
+            (if (and end (< end reg-end))
+                (progn
+                  (setq offset (get-text-property end 'tag-attr-end))
+;;                  (message "offset=%S" offset)
+                  (if (= offset 0)
+                      (put-text-property beg (1+ end) 'font-lock-face face)
+                    (put-text-property beg (+ beg offset) 'font-lock-face face)
+                    (put-text-property (+ beg offset) (+ beg offset 1) 'font-lock-face 'web-mode-html-attr-equal-face)
+                    (put-text-property (+ beg offset 1) (1+ end) 'font-lock-face 'web-mode-html-attr-value-face)
+                    ) ;if offset
+                  (setq pos (1+ end))
+                  ) ;progn
+              (setq continue nil)
+              ) ;if end
+            ) ;progn beg
+        (setq continue nil)
+        ) ;if beg
+      ) ;while
+    ))
 
-       ((and (get-text-property pos 'tag-beg)
-             (get-text-property pos 'tag-name))
-        (setq language "html"
-              indent-offset web-mode-markup-indent-offset)
+
+(defun web-mode-scan-part (reg-beg reg-end &optional content-type)
+  "Scan client part (e.g. javascript, json, css)."
+  (save-excursion
+    (let (token-re ch-before ch-at ch-next token-type start continue)
+
+      (cond
+       (content-type
         )
+       ((member web-mode-content-type '("javascript" "json" "jsx" "css"))
+        (setq content-type web-mode-content-type))
+       (t
+        (setq content-type (symbol-name (get-text-property reg-beg 'part-side))))
+       )
 
-       ((or (and (eq (get-text-property pos 'part-token) 'comment)
-                 (eq (get-text-property (1- pos) 'part-token) 'comment)
-                 (progn
-                   (setq block-beg (previous-single-property-change pos 'part-token))
-                   t))
-            (and (eq (get-text-property pos 'block-token) 'comment)
-                 (eq (get-text-property (1- pos) 'block-token) 'comment)
-                 (progn
-                   (setq block-beg (previous-single-property-change pos 'block-token))
-                   t)))
-        (setq type "comment"))
+;;      (message "reg-beg(%S) reg-end(%S) content-type(%S)" reg-beg reg-end content-type)
 
-       ((or (and (eq (get-text-property pos 'part-token) 'string)
-                 (eq (get-text-property (1- pos) 'part-token) 'string))
-            (and (eq (get-text-property pos 'block-token) 'string)
-                 (eq (get-text-property (1- pos) 'block-token) 'string)))
-        (setq type "string"))
+;;      (remove-text-properties reg-beg reg-end web-mode-scan-properties2)
 
-       ((and (get-text-property pos 'block-side)
-             (not (get-text-property pos 'block-beg)))
-        (setq block-beg (or (web-mode-block-beginning-position pos) pos-min))
-        (goto-char block-beg)
-        (setq block-column (current-column))
-        (setq language web-mode-engine)
-        (setq indent-offset web-mode-code-indent-offset)
-        (cond
-         ((string= web-mode-engine "blade")
-          (setq block-beg (+ block-beg 2)
-                block-column (+ block-column 2)
-                )
-          )
-         ((string= web-mode-engine "razor")
-          (setq block-beg (+ block-beg 2)
-;;                block-column (+ block-column 2)
-                )
-          )
-         ((string= web-mode-engine "template-toolkit")
-          (setq block-beg (+ block-beg 3)
-                block-column (+ block-column 3))
-          )
-         ((and (string= web-mode-engine "jsp")
-               (web-mode-looking-at-pos "<%@\\|<[[:alpha:]]" block-beg))
-          (save-excursion
-            (goto-char block-beg)
-            (looking-at "<%@[ ]*[[:alpha:]]+[ ]+\\|</?[[:alpha:]]+:[[:alpha:]]+[ ]+")
-            (goto-char (match-end 0))
-            (setq block-column (current-column))
-            )
-          )
-         ((and (string= web-mode-engine "freemarker")
-               (web-mode-looking-at-pos "<@\\|<%@\\|<[[:alpha:]]" block-beg))
-          (save-excursion
-            (goto-char block-beg)
-            (looking-at "<@[[:alpha:].]+[ ]+\\|<%@[ ]*[[:alpha:]]+[ ]+\\|<[[:alpha:]]+:[[:alpha:]]+[ ]+")
-            (goto-char (match-end 0))
-            (setq block-column (current-column))
-            )
-          )
-         );cond
-        )
-
-       ((and (get-text-property pos 'part-side)
-             (get-text-property pos 'part-language))
-        (setq block-beg (or (previous-single-property-change pos 'part-side) pos-min))
-;;        (message "%S" block-beg)
-        (goto-char block-beg)
-        (search-backward "<" nil t)
-        (setq block-column (current-column))
-        (setq language (symbol-name (get-text-property pos 'part-language)))
-        (cond
-         ((string= language "css")
-          (setq indent-offset web-mode-css-indent-offset)
-          )
-         (t
-          (setq language "javascript"
-                indent-offset web-mode-code-indent-offset)
-          )
-         )
-        )
+      (goto-char reg-beg)
 
+      (cond
+       ((string= content-type "javascript")
+        (setq token-re "/.\\|\"\\|'"))
+       ((string= content-type "json")
+        (setq token-re "//\\|/\\*\\|\"\\|'"))
+       ((string= content-type "jsx")
+        (setq token-re "//\\|/\\*\\|\"\\|'"))
+       ((string= content-type "css")
+        (setq token-re "/\\*\\|\"\\|'"))
        (t
-        (setq language "html"
-              indent-offset web-mode-markup-indent-offset)
-        )
-
-       );cond
-
-      (goto-char pos)
-      (setq line (web-mode-trim (buffer-substring-no-properties (line-beginning-position)
-                                                                (line-end-position))))
-      (setq first-char (if (string= line "") 0 (aref line 0)))
-
-      (when (or (member language '("php" "javascript" "razor"))
-                (and (string= language "html") (not (eq ?\< first-char))))
-        (cond
-         ((member language '("html" "javascript"))
-          (setq prev (web-mode-previous-usable-client-line))
-          ;;          (message "prev-line=%S" prev-line)
-          (when prev
-            (setq prev-line (car prev)
-                  prev-indentation (cdr prev))
-            (setq prev-line (web-mode-clean-client-line prev-line))
-            (setq prev-props (text-properties-at (1- (length prev-line)) prev-line)))
-          )
-         (t
-          (setq prev (web-mode-previous-usable-server-line))
-          (when prev
-            (setq prev-line (car prev)
-                  prev-indentation (cdr prev))
-            (setq prev-line (web-mode-clean-server-line prev-line)))
-            ;; (message "pl=%s" prev-line)
-          )
-         );cond
-        (when (>= (length prev-line) 1)
-          (setq prev-char (aref prev-line (1- (length prev-line))))
-          (setq prev-line (substring-no-properties prev-line))
-          )
-        )
-
-;;      (if (string= language "json") (setq language "javascript"))
+        (setq token-re "/\\*\\|\"\\|'"))
+       )
 
-      (when (string= web-mode-content-type "html")
+      (while (and token-re (web-mode-dom-rsf token-re reg-end t))
+        (setq start (match-beginning 0)
+              token-type nil
+              continue t)
+        (setq ch-at (char-after start))
+        (setq ch-next (or (char-after (1+ start)) ?\d))
+        (setq ch-before (or (char-before start) ?\d))
+        ;;(message "beg=%S : before(%c) at(%c) next(%c)" start ch-before ch-at ch-next)
         (cond
-         ((string= language "javascript")
-          (setq block-column (+ block-column web-mode-script-padding)))
-         ((string= language "css")
-          (setq block-column (+ block-column web-mode-style-padding)))
-         ((not (member language '("html" "razor")))
-          (setq block-column (+ block-column web-mode-block-padding)))
-         )
-        )
-
-      (setq ctx (list :block-beg block-beg
-                      :block-column block-column
-                      :first-char first-char
-                      :line line
-                      :type type
-                      :language language
-                      :indent-offset indent-offset
-                      :prev-line prev-line
-                      :prev-char prev-char
-                      :prev-props prev-props
-                      :prev-indentation prev-indentation))
-;;      (message "%S" ctx)
-      ctx
-      )))
-
-(defun web-mode-indent-line ()
-  "Indent current line according to language."
-  (let ((inhibit-modification-hooks t)
-        pos
-        offset
-        ctx
-        block-beg
-        block-column
-        first-char
-        line
-        type
-        language
-        indent-offset
-        prev-line
-        prev-char
-        prev-props
-        prev-indentation)
 
-    (save-excursion
-      (back-to-indentation)
-      (setq pos (point))
-      (setq ctx (web-mode-point-context pos))
-      (setq block-beg (plist-get ctx :block-beg))
-      (setq block-column (plist-get ctx :block-column))
-      (setq first-char (plist-get ctx :first-char))
-      (setq line (plist-get ctx :line))
-      (setq type (plist-get ctx :type))
-      (setq language (plist-get ctx :language))
-      (setq indent-offset (plist-get ctx :indent-offset))
-      (setq prev-line (plist-get ctx :prev-line))
-      (setq prev-char (plist-get ctx :prev-char))
-      (setq prev-props (plist-get ctx :prev-props))
-      (setq prev-indentation (plist-get ctx :prev-indentation))
-
-      (cond
-
-       ((or (bobp)
-            (= (line-number-at-pos pos) 1))
-        (setq offset 0)
-        )
-
-       ((string= type "string")
-        (setq offset nil)
-        )
+         ((eq ?\' ch-at)
+          (while (and continue (search-forward "'" reg-end t))
+            (cond
+             ((get-text-property (1- (point)) 'block-side)
+              (setq continue t))
+             ((looking-back "\\\\+'" reg-beg t)
+              (setq continue (= (mod (- (point) (match-beginning 0)) 2) 0)))
+             (t
+              (setq continue nil))
+             )
+            ) ;while
+          (cond
+           ((string= content-type "javascript")
+            (setq token-type 'string))
+           ((string= content-type "css")
+            (setq token-type 'string))
+           ((string= content-type "json")
+            (setq token-type 'string))
+           (t
+            (setq token-type 'string))
+           ) ;cond
+          ) ;eq '
 
-       ((string= type "comment")
-        (goto-char (car
-                    (web-mode-property-boundaries
-                     (if (eq (get-text-property pos 'part-token) 'comment)
-                         'part-token
-                       'block-token)
-                     pos)))
-        (setq offset (current-column))
-        (cond
-         ((and (string= (buffer-substring-no-properties (point) (+ (point) 2)) "/*")
-                   (eq ?\* first-char))
-          (setq offset (1+ offset)))
-         ((and (string= web-mode-engine "django")
-               (looking-back "{% comment %}"))
-          (setq offset (- offset 12))
+         ((eq ?\" ch-at)
+          (while (and continue (search-forward "\"" reg-end t))
+            (cond
+             ((get-text-property (1- (point)) 'block-side)
+              (setq continue t))
+             ((looking-back "\\\\+\"" reg-beg t)
+              (setq continue (= (mod (- (point) (match-beginning 0)) 2) 0)))
+             (t
+              (setq continue nil))
+             )
+            )
+          (cond
+           ((string= content-type "json")
+            (if (looking-at-p "[ ]*:")
+                (cond
+                 ((eq ?\@ (char-after (1+ start)))
+                  (setq token-type 'context))
+                 (t
+                  (setq token-type 'key))
+                 )
+              (setq token-type 'string))
+            )
+           (t
+            (cond
+             ((string= content-type "javascript")
+              (setq token-type 'string))
+             ((string= content-type "css")
+              (setq token-type 'string))
+             (t
+              (setq token-type 'string))
+             ) ;cond
+            ) ;t
+           ) ;cond
           )
-         );cond
-        );case comment
-
-       ((member language '("php" "jsp" "asp" "aspx" "javascript" "code"
-                           "python" "erb" "freemarker" "blade"
-                           "template-toolkit" "razor"))
-
-        (cond
 
-         ((string-match-p "^[?%]>" line)
-          (if (web-mode-block-beginning pos)
-              (setq offset (current-column)))
+         ((eq ?\/ ch-next)
+          (unless (eq ?\\ ch-before)
+            (setq token-type 'comment)
+            (goto-char (if (< reg-end (line-end-position)) reg-end (line-end-position)))
+            )
           )
 
-         ((and (string= language "razor")
-               (string-match-p "^\\." line)
-               (string-match-p "^\\." prev-line))
-          (setq offset prev-indentation)
+         ((eq ?\* ch-next)
+          (unless (eq ?\\ ch-before)
+            (setq token-type 'comment)
+            (search-forward "*/" reg-end t)
+            )
           )
 
-         ((and (string= language "razor")
-               (string-match-p "^}" line))
-          (goto-char (web-mode-opening-paren-position (point)))
-          (back-to-indentation)
-          (setq offset (current-column))
+         ((and (member content-type '("javascript" "jsx"))
+               (eq ?\/ ch-at)
+               (progn (or (bobp) (backward-char)) t)
+               (looking-back "[(=][ ]*/")
+               (looking-at-p ".+/")
+;;               (not (eq ?\s ch-next))
+               )
+;;          (message "regexp literal at (%S)" (1- (point)))
+          (while (and continue (search-forward "/" reg-end t))
+            (setq continue (or (get-text-property (1- (point)) 'block-side)
+                               (eq ?\\ (char-before (1- (point))))))
+            )
+          (setq token-type 'string)
+          (skip-chars-forward "gimy")
           )
 
-        ((and (string= language "razor")
-              (string-match-p "^case " line)
-              (string-match-p "^case " prev-line))
-         (search-backward "case ")
-         (setq offset (current-column))
-         )
+         ) ;cond
 
-         ((and (string-match-p "^[=]?%]" line)
-               (string= web-mode-engine "template-toolkit"))
-          (if (web-mode-block-beginning pos)
-              (setq offset (current-column)))
+        (when (and (>= reg-end (point)) token-type)
+          (put-text-property start (point) 'part-token token-type)
+          (when (eq token-type 'comment)
+            (put-text-property start (1+ start) 'syntax-table (string-to-syntax "<"))
+            (put-text-property (1- (point)) (point) 'syntax-table (string-to-syntax ">"))
+            )
           )
 
+        ) ;while
 
-         ((and (string= language "php") (string-match-p "^->" line))
-          (when (web-mode-sb "->" block-beg)
-            (setq offset (current-column)))
-          )
+      (when (string= content-type "jsx")
+        (web-mode-scan-literals reg-beg reg-end))
 
-         ((and (string= language "php")
-               (or (string-match-p "^else$" prev-line)
-                   (string-match-p "^\\(if\\|for\\|foreach\\|while\\)[ ]*(.+)$" prev-line))
-               (not (string-match-p "^{" line)))
-          (setq offset (+ prev-indentation web-mode-code-indent-offset))
-          )
+      )))
 
-         ((and (string= language "javascript") (eq ?\. first-char))
-          (when (web-mode-rsb "[[:alnum:][:blank:]]\\.[[:alpha:]]" block-beg)
-            (setq offset (1+ (current-column))))
-          )
+(defun web-mode-highlight-part (reg-beg reg-end)
+  "Highlight part (e.g. javascript, json, css)."
+  (save-excursion
+    (let (char start continue token-type face beg end string-face comment-face content-type)
+;;      (message "highlight-part: reg-beg(%S) reg-end(%S)" reg-beg reg-end)
+      (if (member web-mode-content-type '("javascript" "json" "jsx" "css"))
+          (setq content-type web-mode-content-type)
+        (setq content-type (symbol-name (get-text-property reg-beg 'part-side)))
+        )
 
-         ((and (member first-char '(?\? ?\. ?\:))
-               (not (string= language "erb")))
-          (web-mode-rsb "[^!=][=(]" block-beg)
-          (setq offset (1+ (current-column)))
-          (when (and (string= web-mode-engine "php")
-                     (looking-at-p " =>"))
-            (setq offset (1+ offset))
-            )
-          )
+      (goto-char reg-beg)
 
-         ((and (member prev-char '(?\. ?\+ ?\? ?\:))
-               (not (string-match-p "^\\(case\\|default\\)[ :]" prev-line)))
-          (web-mode-rsb "[=(]" block-beg)
-          (skip-chars-forward "= (")
-          (setq offset (current-column))
-          )
+      (cond
+       ((member content-type '("javascript" "jsx"))
+        (setq string-face 'web-mode-javascript-string-face
+              comment-face 'web-mode-javascript-comment-face)
+        (web-mode-fontify-region reg-beg reg-end web-mode-javascript-font-lock-keywords))
+       ((string= content-type "json")
+        (setq string-face 'web-mode-json-string-face
+              comment-face 'web-mode-json-comment-face)
+        (web-mode-fontify-region reg-beg reg-end web-mode-javascript-font-lock-keywords))
+       ((string= content-type "css")
+        (setq string-face 'web-mode-css-string-face
+              comment-face 'web-mode-css-comment-face)
+        (web-mode-css-rules-highlight reg-beg reg-end)
+        )
+       (t
+        (setq string-face 'web-mode-part-string-face
+              comment-face 'web-mode-part-comment-face)
+        )
+       )
 
-         ((string= language "erb")
-          (setq offset (web-mode-ruby-indentation pos
-                                                  line
-                                                  block-column
-                                                  indent-offset
-                                                  block-beg))
-          )
+      (setq continue t
+            end reg-beg)
+      (while continue
+        (setq char (char-after beg))
+        (if (and (= reg-beg end)
+                 (get-text-property end 'part-token))
+            (setq beg reg-beg)
+          (setq beg (next-single-property-change end 'part-token)))
+        (setq end nil)
+        (if (and beg (< beg reg-end))
+            (progn
+              (setq token-type (get-text-property beg 'part-token))
+              (setq face (cond
+                          ((eq token-type 'string) string-face)
+                          ((eq token-type 'comment) comment-face)
+                          ((eq token-type 'context) 'web-mode-json-context-face)
+                          ((eq token-type 'key) 'web-mode-json-key-face)
+                          ((eq token-type 'html) nil)
+                          ;;                          ((eq token-type 'literal-expr) nil)
+                          (t nil)))
+              (setq end (next-single-property-change beg 'part-token))
+              (if (and end (< end reg-end))
+                  (cond
+                   (face
+                    (remove-text-properties beg end '(face nil))
+                    (put-text-property beg end 'font-lock-face face))
+;;                   ((eq token-type 'tag)
+;;                    (web-mode-fontify-region beg end web-mode-html-tag-font-lock-keywords))
+;;                   ((eq token-type 'literal-expr)
+;;                    (message "ici")
+;;                    (put-text-property beg (1+ beg) 'face 'web-mode-block-delimiter-face))
+                   ) ;cond
+                (setq continue nil
+                      end nil)
+                ) ;if end
+              ) ;progn beg
+          (setq continue nil
+                end nil)
+          ) ;if beg
 
-         ((string= language "asp")
-          (setq offset (web-mode-asp-indentation pos
-                                                 line
-                                                 block-column
-                                                 indent-offset
-                                                 block-beg))
-          )
+        (when (and beg end
+                   web-mode-enable-comment-keywords
+                   (eq token-type 'comment)
+                   (> (- end beg) 3))
+          (web-mode-interpolate-comment beg end t))
 
-         (t
-          (setq offset (web-mode-bracket-indentation pos
-                                                     block-column
-                                                     indent-offset
-                                                     block-beg))
-          );t
+        ) ;while
 
-         ));end case script block
+      (when web-mode-enable-part-face
+        (font-lock-append-text-property reg-beg reg-end 'face 'web-mode-part-face))
 
-       ((string= language "css")
-        (setq offset (web-mode-bracket-indentation pos
-                                                   block-column
-                                                   indent-offset
-                                                   block-beg))
-        );case style
+      (when (string= content-type "jsx")
+        (goto-char reg-beg)
+        (setq continue t
+              end reg-beg)
+        (while continue
+          (setq beg (next-single-property-change end 'part-expr)
+                end nil)
+;;          (message "beg%S reg-end%S" beg reg-end)
+          (if (and beg (< beg reg-end))
+              (progn
+                (setq end (next-single-property-change beg 'part-expr))
+;;                (message "bounds %S %S"  beg end)
+                (if (and end (< end reg-end))
+                    (progn
+                      (remove-text-properties beg end '(face nil))
+                      (put-text-property beg (1+ beg) 'face 'web-mode-block-delimiter-face)
+                      (put-text-property (1- end) end 'face 'web-mode-block-delimiter-face)
+                      (web-mode-fontify-region (1+ beg) (1- end) web-mode-javascript-font-lock-keywords)
+                      ) ;progn
+                  (setq continue nil
+                        end nil))
+                ) ;progn
+            (setq continue nil
+                  end nil))
+          ) ;while
+        ) ;when jsx
 
-       (t ; case html block
+      )))
 
+(defun web-mode-css-rules-highlight (part-beg part-end)
+  "Scan CSS rules."
+  (save-excursion
+    (goto-char part-beg)
+    (let (rule (continue t) (i 0) at-rule)
+      (while continue
+        (setq i (1+ i))
+        (setq rule (web-mode-css-rule-next part-end))
         (cond
-
-         ((and prev-props (eq (plist-get prev-props 'part-token) 'attr))
-          (web-mode-tag-beginning)
-          (let (skip)
-            (setq skip (next-single-property-change (point) 'part-token))
-            (when skip
-              (goto-char skip)
-              (setq offset (current-column))
-              ))
+         ((> i 1000)
+          (message "*** too much css rules ***")
+          (setq continue nil))
+         ((null rule)
+          (setq continue nil)
           )
-
-         ((or (and (eq (get-text-property pos 'tag-type) 'end)
-                   (web-mode-match-html-tag))
-              (and (string= web-mode-engine "razor")
-                   (string-match-p "^[ \t]*}" line)
-                   (funcall web-mode-engine-control-matcher))
-              (and (get-text-property pos 'block-beg)
-                   (looking-at-p web-mode-close-block-regexp)
-                   (funcall web-mode-engine-control-matcher))
-              )
-          (setq offset (current-indentation))
+         ((and (setq at-rule (plist-get rule :at-rule))
+               (not (member at-rule '("charset" "font-face" "import")))
+               (plist-get rule :dec-end))
+          (web-mode-css-rule-highlight (plist-get rule :sel-beg)
+                                       (plist-get rule :sel-end)
+                                       nil nil)
+          (web-mode-css-rules-highlight (plist-get rule :dec-beg)
+                                        (plist-get rule :dec-end))
           )
-
-         ((or (eq (length line) 0)
-              (= web-mode-indent-style 2)
-              (get-text-property pos 'tag-beg)
-              (get-text-property pos 'block-beg))
-          (setq offset (web-mode-markup-indentation pos))
+         (t
+          (web-mode-css-rule-highlight (plist-get rule :sel-beg)
+                                       (plist-get rule :sel-end)
+                                       (plist-get rule :dec-beg)
+                                       (plist-get rule :dec-end))
           )
-
-         );cond
-
-        );end case html block
-
-       );end switch language block
-
-      );save-excursion
-
-    (when offset
-      (let ((diff (- (current-column) (current-indentation))))
-        (setq offset (max 0 offset))
-        (indent-line-to offset)
-        (if (> diff 0) (forward-char diff))
-        );let
-      );when
-
+         ) ;cond
+        )
+      )
     ))
 
-(defun web-mode-is-active-block (pos)
-  "web-mode-is-active-block"
+(defun web-mode-css-rule-highlight (sel-beg sel-end dec-beg dec-end)
+  "Fontify css rule."
   (save-excursion
-    (let (ctrl state)
-      (goto-char pos) ;;(message "pos=%S" pos)
-      (when (looking-at web-mode-active-block-regexp)
-
-        (cond
-
-         ((string= web-mode-engine "php")
-          (setq ctrl (match-string-no-properties 3))
-          (if (member ctrl '("else" "elseif"))
-              (setq ctrl nil)
-            (setq state (not (string= "end" (match-string-no-properties 2))))
-            )
-          )
+;;    (message "sel-beg=%S sel-end=%S dec-beg=%S dec-end=%S" sel-beg sel-end dec-beg dec-end)
+    (web-mode-fontify-region sel-beg sel-end
+                             web-mode-selector-font-lock-keywords)
+    (when (and dec-beg dec-end)
+      (web-mode-fontify-region dec-beg dec-end
+                               web-mode-declaration-font-lock-keywords)
+      (goto-char dec-beg)
+      (while (and web-mode-enable-css-colorization
+                  (re-search-forward "#[0-9a-fA-F]\\{6\\}\\|#[0-9a-fA-F]\\{3\\}\\|rgb([ ]*\\([[:digit:]]\\{1,3\\}\\)[ ]*,[ ]*\\([[:digit:]]\\{1,3\\}\\)[ ]*,[ ]*\\([[:digit:]]\\{1,3\\}\\)\\(.*?\\))" dec-end t)
+                  (< (point) dec-end))
+        (web-mode-colorize (match-beginning 0) (match-end 0))
+        )
+      )))
 
-         ((string= web-mode-engine "django")
-          (setq ctrl (match-string-no-properties 2))
-          (if (member ctrl '("else" "elseif" "elsif" "elif" "empty"))
-              (setq ctrl nil)
-            (setq state (not (string= "end" (match-string-no-properties 1))))
-            )
-          )
+;; css rule = selector(s) + declaration (properties)
+(defun web-mode-css-rule-next (limit)
+  "next rule"
+  (let (at-rule sel-beg sel-end dec-beg dec-end chunk)
+    (skip-chars-forward "\n\t ")
+    (setq sel-beg (point))
+    (when (and (< (point) limit)
+               (web-mode-part-rsf "[{;]" limit t))
+      (setq sel-end (1- (point)))
+      (cond
+       ((eq (char-before) ?\{)
+        (setq dec-beg (point))
+        (setq dec-end (web-mode-closing-paren-position (1- dec-beg) limit))
+        (if dec-end
+            (progn
+              (goto-char dec-end)
+              (forward-char))
+          (setq dec-end limit)
+          (goto-char limit))
+        )
+       (t
+        )
+       ) ;cond
+      (setq chunk (buffer-substring-no-properties sel-beg sel-end))
+      (when (string-match "@\\([[:alpha:]-]+\\)" chunk)
+        (setq at-rule (match-string-no-properties 1 chunk))
+;;        (message "%S at-rule=%S" chunk at-rule)
+        )
+      ) ;when
+    (if (not sel-end)
+        (progn (goto-char limit) nil)
+      (list :at-rule at-rule
+            :sel-beg sel-beg
+            :sel-end sel-end
+            :dec-beg dec-beg
+            :dec-end dec-end)
+      ) ;if
+    ))
 
-         ((string= web-mode-engine "smarty")
-          (setq ctrl (match-string-no-properties 1))
-          (if (member ctrl '("else" "elseif"))
-              (setq ctrl nil)
-            (setq state (not (eq ?\/ (aref (match-string-no-properties 0) 1))))
-            )
-          )
+(defun web-mode-css-rule-current (&optional pos part-beg part-end)
+  "Current CSS rule boundaries."
+  (interactive)
+  (unless pos (setq pos (point)))
+  (unless part-beg (setq part-beg (web-mode-part-beginning-position pos)))
+  (unless part-end (setq part-end (web-mode-part-end-position pos)))
+  (save-excursion
+    (let (beg end)
+      (goto-char pos)
+      (if (not (web-mode-part-sb "{" part-beg t))
+          (progn
+            (setq beg part-beg)
+            (if (web-mode-part-sf ";" part-end t)
+                (setq end (1+ (point)))
+              (setq end part-end))
+            ) ;progn
+        (setq beg (point))
+        (setq end (web-mode-closing-paren-position beg part-end))
+        (if end
+            (setq end (1+ end))
+          (setq end (line-end-position)))
+;;        (message "%S >>beg%S >>end%S" pos beg end)
+        (if (> pos end)
 
-         ((string= web-mode-engine "dust")
-          (setq ctrl (match-string-no-properties 1))
-          (if (or (member ctrl '("else"))
-                  (eq ?\/ (char-after (1- (web-mode-block-end-position)))))
-              (setq ctrl nil)
-            (setq state (not (eq ?\/ (aref (match-string-no-properties 0) 1))))
-            )
-          )
+            ;;selectors
+            (progn
+              (goto-char pos)
+              (if (web-mode-part-rsb "[};]" part-beg t)
+                  (setq beg (1+ (point)))
+                (setq beg part-beg)
+                ) ;if
+              (goto-char pos)
+              (if (web-mode-part-rsf "[{;]" part-end t)
+                  (cond
+                   ((eq (char-before) ?\;)
+                    (setq end (point))
+                    )
+                   (t
+                    (setq end (web-mode-closing-paren-position (1- (point)) part-end))
+                    (if end
+                        (setq end (1+ end))
+                      (setq end part-end))
+                    )
+                   ) ;cond
+                (setq end part-end)
+                )
+              ) ;progn selectors
 
-         ((string= web-mode-engine "closure")
-          (setq ctrl (match-string-no-properties 1))
-          (if (or (member ctrl '("else" "elseif" "case" "default"))
-                  (eq ?\/ (char-after (1- (web-mode-block-end-position)))))
-              (setq ctrl nil)
-            (setq state (not (eq ?\/ (aref (match-string-no-properties 0) 1))))
-            )
-          )
+          ;; declaration
+          (goto-char beg)
+          (if (web-mode-part-rsb "[}{;]" part-beg t)
+              (setq beg (1+ (point)))
+            (setq beg part-beg)
+            ) ;if
+          ) ; if > pos end
+        )
+;;      (message "beg(%S) end(%S)" beg end)
+      (when (eq (char-after beg) ?\n)
+        (setq beg (1+ beg)))
+      (cons beg end)
+      )))
 
-         ((string= web-mode-engine "ctemplate")
-          (setq ctrl (match-string-no-properties 1))
-          (setq state (not (eq ?\/ (aref (match-string-no-properties 0) 2))))
+(defun web-mode-velocity-skip-forward (pos)
+  "find the end of a velocity block."
+  (goto-char pos)
+  (let (continue)
+    (when (eq ?\# (char-after))
+      (forward-char))
+    ;;(message "pt=%S %c" (point) (char-after))
+    (when (member (char-after) '(?\$ ?\@))
+      ;;              (message "pt=%S" (point))
+      (forward-char))
+    (when (member (char-after) '(?\!))
+      ;;              (message "pt=%S" (point))
+      (forward-char))
+    (if (member (char-after) '(?\{))
+        (search-forward "}")
+      (setq continue t)
+      (while continue
+        (skip-chars-forward "a-zA-Z0-9_-")
+        (when (member (char-after) '(?\())
+          (search-forward ")" nil t)
           )
+        (if (member (char-after) '(?\.))
+            (forward-char)
+          (setq continue nil))
+        ) ;while
+      ) ;if
+    ))
 
-         ((string= web-mode-engine "velocity")
-          (setq ctrl (match-string-no-properties 1))
-          (if (member ctrl '("else" "elseif"))
-              (setq ctrl nil)
-            (setq state (not (string= "end" (match-string-no-properties 1))))
-            )
-          )
+;; invalidation lorsqu'on modifie
+;; web-mode-scan-virtual-tags
+;; web-mode-scan-block-literals ?
 
-         ((string= web-mode-engine "blade")
-          (setq ctrl (match-string-no-properties 2))
+(defun web-mode-scan-literals (reg-beg reg-end)
+  "jsx web-mode-scan-literals"
+  (let (continue pair beg end)
+    (save-excursion
+      (goto-char reg-beg)
+;;      (message "reg-beg(%S) reg-end(%S)" reg-beg reg-end)
+      (while (and (< (point) reg-end)
+                  (web-mode-dom-rsf "</?[[:alnum:]]" reg-end))
+;;        (message "%S" (match-string-no-properties 0))
+        (goto-char (match-beginning 0))
+;;        (when (looking-back "^[ ]+")
+;;          (beginning-of-line))
+        (setq beg nil
+              end nil
+              continue t)
+        (while continue
+          (setq pair (web-mode-scan-literal reg-end))
+          (when pair
+            (setq beg (or beg (car pair))
+                  end (cdr pair)))
+;;          (when pair (message "%S : %S" pair (buffer-substring-no-properties (car pair) (cdr pair))))
           (cond
-           ((string= ctrl "stop")
-            (setq ctrl "section"))
-           ((member ctrl '("else" "elseif"))
-            (setq ctrl nil))
+           ((null pair)
+            (setq continue nil))
+           ((eq (char-after (car pair)) ?\<)
+            ;; scan à l'interieur {}
+;;            (put-text-property (car pair) (cdr pair) 'part-token 'tag)
+            )
            (t
-            (setq state (not (string= "end" (match-string-no-properties 1)))))
-           )
-          )
-
-         ((string= web-mode-engine "go")
-          (setq ctrl (match-string-no-properties 1))
-          (if (member ctrl '("else"))
-              (setq ctrl nil)
-            (setq state (not (string= "end" ctrl)))
+;            ;; (put-text-property (car pair) (cdr pair) 'part-expr t)
             )
+           ) ;cond
+;;          (message "pos=%S pair=%S" (point) pair)
+          ) ;while continue
+;;        (message "pos=%S" (point))
+        (when (and beg end)
+;;          (remove-text-properties beg end '(part-token))
+          (put-text-property beg end 'part-token 'html)
+          (web-mode-dom-scan beg end)
+;;          (message "scan-tags %S %S" beg end)
+          (web-mode-scan-expr-literal beg end)
           )
+        ) ;while
+      )))
 
-         ((string= web-mode-engine "erb")
-          (setq ctrl (match-string-no-properties 1))
-          (if (member ctrl '("else"))
-              (setq ctrl nil)
-            (setq state (not (string= "end" ctrl)))
-            )
+(defun web-mode-scan-expr-literal (reg-beg reg-end)
+  "web-mode-scan-expr-literal"
+  (let ((continue t) beg end)
+    (save-excursion
+      (goto-char reg-beg)
+;;      (message "reg-beg=%S reg-end=%S" reg-beg reg-end)
+      (while (and continue (search-forward "{" reg-end t))
+        ;; (message "pt=%S" (point))
+        (backward-char)
+        (setq beg (point)
+              end (web-mode-closing-paren reg-end)
+;;              end (search-forward "}" reg-end t)
+              )
+;;        (message "beg(%S) end(%S)" beg end)
+        (if (not end)
+            (setq continue nil)
+          ;;          (web-mode-scan-part beg end)
+          (setq end (1+ end))
+          ;;(remove-text-properties (1+ beg) (1- end) '(part-token nil))
+          (put-text-property (1+ beg) (1- end) 'part-token nil)
+          (put-text-property beg end 'part-expr t)
+          (web-mode-scan-part beg end "javascript")
+;;          (message "scan part %S %S" beg end)
           )
+        )
+      )))
 
-         ((string= web-mode-engine "template-toolkit")
-          (setq ctrl (match-string-no-properties 1))
-          (if (member ctrl '("else"))
-              (setq ctrl nil)
-            (setq state (not (string= "end" ctrl)))
-            )
-          )
+;; bug du ' : issue210
+(defun web-mode-scan-literal (reg-end)
+  "web-mode-scan-literal"
+  (let (beg end)
+    ;;    (skip-chars-forward " :'\n[:alnum:]")
+    (setq beg (point))
+;;    (message "beg=%S" beg)
+    (cond
+     ((looking-at "</?\\([[:alnum:]]+\\(?:[-][[:alpha:]]+\\)?\\)")
+      (if (web-mode-sf ">") (setq end (point)))
+      )
+     ((eq (char-after) ?\{)
+      (if (web-mode-closing-paren reg-end) (setq end (1+ (point))))
+;;      (message "end=%S" end)
+;;      (if (web-mode-sf "}") (setq end (point)))
+      )
+     ;; ((looking-at "[a-z \n]")
+     ;; (skip-chars-forward "a-z \n")
+     ;; (setq end (point))
+     ;; )
+     ((looking-at "[ \t\n]")
+      (skip-chars-forward " \t\n")
+      ;;      (message "ici%S" (point))
+      (if (looking-at-p "[),;]")
+          (setq end nil)
+        (setq end (point)))
+      )
+     (t
+      (skip-chars-forward "^<),;")
+      (when (> (point) beg)
+        (setq end (point)))
+      )
+     ) ;cond
+    (cond
+     ((null end)
+      nil)
+     ((> (point) reg-end)
+      (goto-char reg-end)
+      nil)
+     (t
+      ;;      (message "literal(%S-%S)=%S" beg end (buffer-substring-no-properties beg end))
+      (cons beg end)
+      )
+     )))
 
-         ((string= web-mode-engine "jsp")
-          (cond
-           ((eq (aref (match-string-no-properties 0) 1) ?\%)
-            (setq ctrl (match-string-no-properties 2)
-                  state t)
-            )
-           (t
-            (setq ctrl (match-string-no-properties 1))
-            (if (or (member ctrl '("h:inputtext" "jsp:usebean" "jsp:forward" "struts:property"))
-                    (eq ?\/ (char-after (1- (web-mode-block-end-position)))))
-                (setq ctrl nil)
-              (setq state (not (eq ?\/ (aref (match-string-no-properties 0) 1))))
-              )
-            )
-           )
+(defun web-mode-exclude-virtual-tags (block-beg block-end)
+  "Exclude HTML"
+  (save-excursion
+    (goto-char block-beg)
+    ;;    (message "block-beg(%S) block-end(%S)" block-beg block-end)
+    (let ((continue t) beg end tag-beg tag-end line line-end line-end-pos pos)
+
+      (setq line (line-number-at-pos block-beg)
+            line-end (line-number-at-pos block-end))
+
+      (while (<= line line-end)
+        (setq pos (point))
+;;        (message "pos=%S line=%S" pos line)
+        (setq line-end-pos (line-end-position))
+        (if (>= line-end-pos block-end)
+            (setq line-end-pos block-end)
+;;          (setq line-end-pos (1+ line-end-pos))
+          )
+        (when (looking-at "[ \n]+")
+;;          (message "ici %S %S" (match-beginning 0) (match-end 0))
+          (remove-text-properties (match-beginning 0) (match-end 0) '(block-side nil block-token nil))
           )
 
-         ((string= web-mode-engine "freemarker")
-          (if (or (member (aref (match-string-no-properties 0) 1) '(?\@ ?\#))
-                  (member (aref (match-string-no-properties 0) 2) '(?\@ ?\#)))
-              (setq ctrl (match-string-no-properties 2))
-            (setq ctrl (match-string-no-properties 1))
+        (while (re-search-forward "\\([ \t]*\\(?:</?[[:alpha:]].*?>\\|<!--.*?-->\\)[ ]*\\)" line-end-pos t)
+          (setq beg (match-beginning 0)
+                end (match-end 0)
+                tag-beg (match-beginning 1)
+                tag-end (match-end 1))
+;;          (message "line-end-pos(%S) beg(%S) end(%S)" line-end-pos beg end)
+          (remove-text-properties beg end '(block-side nil block-token nil))
+
+          (put-text-property (1- tag-beg) tag-beg 'block-end t)
+          (put-text-property tag-end (1+ tag-end) 'block-beg t)
+          (when (and (looking-at "\\(.+\\)<")
+                     (not (string-match-p "@" (match-string-no-properties 1))))
+            (remove-text-properties (match-beginning 1) (match-end 1) '(block-side nil block-token nil))
             )
-;;          (message "ctrl=%S" ctrl)
-          (if (or (member ctrl '("include" "setting" "import" "global" "ftl"
-                                 "nested" "return" "local" "flush" "break" "recover"))
-                  (eq ?\/ (char-after (1- (web-mode-block-end-position)))))
-              (setq ctrl nil)
-            (setq state (not (eq ?\/ (aref (match-string-no-properties 0) 1))))
+          (when (string-match-p "@" (buffer-substring-no-properties beg end))
+;;            (message "@ found(%S %S)" beg end)
+            (remove-text-properties beg end '(block-side nil block-token nil))
+            (web-mode-scan-blocks beg end)
             )
+          ) ;while
+        (goto-char pos)
+        (end-of-line)
+        (when (looking-back "[ ]*")
+          (remove-text-properties (match-beginning 0) (match-end 0) '(block-side nil block-token nil))
           )
-
-         ((string= web-mode-engine "underscore")
-          (cond
-           ((web-mode-block-ends-with "{ %>")
-            (setq ctrl "ctrl"
-                  state t))
-           ((looking-at-p "<% }")
-            (setq ctrl "ctrl"
-                  state nil))
-           )
-          )
-
-         ((string= web-mode-engine "razor")
-          (setq ctrl (match-string-no-properties 1)
-                state t)
+;;        (message "removing %S %S" (point) (1+ (point)))
+        (when (get-text-property (point) 'block-side)
+          (put-text-property (1- (point)) (point) 'block-end t)
+          (remove-text-properties (point) (+ (point) 1) '(block-side nil block-token nil))
           )
-
-         );cond
-
-        );when
-
-;;      (message "engine=%S ctrl=%S state=%S" web-mode-engine ctrl state)
-
-      (if ctrl (cons ctrl state) nil)
+;;        (goto-char pos)
+        (forward-line)
+;;        (message "pos=%S" (point))
+        (setq line (1+ line))
+        )
+;;      (message "%S" (get-text-property 58 'block-token))
       )))
 
-(defun web-mode-markup-indentation-origin ()
-  "web-mode-indentation-origin-pos"
-  (let ((continue t) pos)
+(defun web-mode-razor-skip-forward (pos)
+  "Find the end of a razor block."
+  (goto-char pos)
+  ;;            (message "pt=%S %c" (point) (char-after))
+  (let ((continue t) tmp (i 0))
     (while continue
-      (forward-line -1)
-      (back-to-indentation)
-      (setq continue (not (bobp)))
-      (when (or (get-text-property (point) 'tag-beg)
-                (and (get-text-property (point) 'block-beg)
-                     (web-mode-is-active-block (point))
-                     (not (looking-at-p "{% comment"))))
-        (setq continue nil
-              pos (point))
+      (setq i (1+ i))
+;;      (message "i=%S (%S)" i (point))
+      (skip-chars-forward " =@a-zA-Z0-9_-")
+      (cond
+       ((> i 500)
+        (message "*** invalid razor loop at (%S) ***" pos)
+        (setq continue nil))
+       ((looking-at-p "@[({]")
+        (forward-char)
+        (setq tmp (web-mode-closing-paren-position (point)))
+        (when tmp
+          (goto-char tmp))
+        (forward-char)
         )
-      );while
-;;    (message "indent-origin=%S" pos)
-    pos
+       ((and (not (eobp)) (eq ?\( (char-after)))
+        (if (looking-at-p "[ \n]*<")
+            (setq continue nil)
+          (setq tmp (web-mode-closing-paren-position))
+          (when tmp
+            (goto-char tmp))
+          (forward-char)
+          ) ;if
+        )
+       ((and (not (eobp)) (eq ?\. (char-after)))
+        (forward-char))
+       ((looking-at-p "[ \n]*{")
+        (search-forward "{")
+        (if (looking-at-p "[ \n]*<")
+            (setq continue nil)
+          (backward-char)
+          (setq tmp (web-mode-closing-paren-position))
+          (when tmp
+            (goto-char tmp))
+          (forward-char)
+          ) ;if
+        )
+       ((looking-at-p "}")
+        (forward-char)
+        )
+       (t
+        (setq continue nil))
+       ) ;cond
+      ) ;while
+;;      (message "%S" (get-text-property 58 'block-token))
     ))
 
-(defun web-mode-markup-indentation (pos)
-  "markup indentation"
+(defun web-mode-colorize-foreground (color)
+  "Colorize foreground based on background luminance."
+  (let* ((values (x-color-values color))
+	 (r (car values))
+	 (g (cadr values))
+	 (b (car (cdr (cdr values)))))
+    (if (> 128.0 (floor (+ (* .3 r) (* .59 g) (* .11 b)) 256))
+	"white" "black")))
+
+(defun web-mode-colorize (beg end)
+  "Colorize CSS colors."
+  (let (str plist len)
+    (setq str (buffer-substring-no-properties beg end))
+    (setq len (length str))
+    (cond
+     ((string= (substring str 0 1) "#")
+      (setq plist (list :background str
+                        :foreground (web-mode-colorize-foreground str)))
+      (put-text-property beg end 'face plist))
+     ((string= (substring str 0 4) "rgb(")
+      (setq str (format "#%02X%02X%02X"
+                        (string-to-number (match-string-no-properties 1))
+                        (string-to-number (match-string-no-properties 2))
+                        (string-to-number (match-string-no-properties 3))))
+      (setq plist (list :background str
+                        :foreground (web-mode-colorize-foreground str)))
+      (put-text-property beg end 'face plist))
+     ) ;cond
+    ))
+
+(defun web-mode-fontify-region (beg end keywords)
+  "Font-lock region according to the keywords."
   (save-excursion
-    (goto-char pos)
-    (let ((offset 0) beg ret)
-      (setq beg (web-mode-markup-indentation-origin))
-      (when beg
-        (goto-char beg)
-        (setq ret (web-mode-is-opened-element beg pos))
-        (cond
-         ((null ret)
-          (setq offset (current-indentation)))
-         ((eq ret t)
-          (setq offset (+ (current-indentation) web-mode-markup-indent-offset))
-          )
-         (t
-          (setq offset ret))
-         )
-;;        (setq offset (+ (current-indentation)
-;;                        (if (web-mode-is-opened-element beg pos)
-;;                            web-mode-markup-indent-offset
-;;                          0)))
-        );when
-      offset
+    (let ((font-lock-keywords keywords)
+          (font-lock-multiline nil)
+          (font-lock-keywords-case-fold-search
+           (member web-mode-engine '("asp" "template-toolkit")))
+          (font-lock-keywords-only t)
+          (font-lock-extend-region-functions nil))
+      (when (listp font-lock-keywords)
+        (font-lock-fontify-region beg end))
       )))
 
-;; state(t) <=> start tag
-(defun web-mode-is-opened-element (pos limit)
-  "Is there any HTML element without a closing tag ?"
+(defun web-mode-fill-paragraph (&optional justify)
+  "fill paragraph"
+  (save-excursion
+    (let ((pos (point)) fill-coll
+          prop pair beg end delim-beg delim-end chunk fill-col)
+      (cond
+       ((or (eq (get-text-property pos 'part-token) 'comment)
+            (eq (get-text-property pos 'block-token) 'comment))
+        (setq prop
+              (if (get-text-property pos 'part-token) 'part-token 'block-token))
+        (setq pair (web-mode-property-boundaries prop pos))
+        (when (and pair (> (- (cdr pair) (car pair)) 6))
+          (setq fill-coll (if (< fill-column 10) 70 fill-column))
+          (setq beg (car pair)
+                end (cdr pair))
+          (goto-char beg)
+          (setq chunk (buffer-substring-no-properties beg (+ beg 2)))
+          (cond
+           ((string= chunk "//")
+            (setq delim-beg "//"
+                  delim-end "EOL"))
+           ((string= chunk "/*")
+            (setq delim-beg "/*"
+                  delim-end "*/"))
+           ((string= chunk "{#")
+            (setq delim-beg "{#"
+                  delim-end "#}"))
+           ((string= chunk "<!")
+            (setq delim-beg "<!--"
+                  delim-end "-->"))
+           )
+          ;;          (subst-char-in-region beg end ?\n ?\s)
+          ;;          (message "fill-column=%S pt=%S pair=%S chunk=%S"
+          ;;                   fill-column (point) pair chunk)
+          )
+        ) ;comment - case
+
+       ((web-mode-is-content)
+;;        (message "prop(%S)" prop)
+        (setq pair (web-mode-content-boundaries pos))
+        (setq beg (car pair)
+              end (cdr pair))
+        )
+
+       ) ;cond
+;;      (message "beg(%S) end(%S)" beg end)
+      (when (and beg end)
+        (fill-region beg end)
+;;        (indent-for-tab-command)
+        )
+      t)))
+
+(defun web-mode-property-boundaries (prop &optional pos)
+  "property boundaries (cdr is 1+)"
+  (unless pos (setq pos (point)))
+  (let (beg end val)
+    (setq val (get-text-property pos prop))
+    (if (null val)
+        val
+      (if (or (bobp)
+              (not (eq (get-text-property (1- pos) prop) val)))
+          (setq beg pos)
+        (setq beg (previous-single-property-change pos prop))
+        (when (null beg) (setq beg (point-min))))
+      (if (or (eobp)
+              (not (eq (get-text-property (1+ pos) prop) val)))
+          (setq end pos)
+        (setq end (next-single-property-change pos prop))
+        (when (null end) (setq end (point-min))))
+      (cons beg end))))
+
+;; verifier avec text-property-any si 'block-side
+(defun web-mode-content-apply (&optional fun)
+  "web-mode-content-apply"
   (interactive)
-  (let (tag
-        last-tag
-        tag-pos block-pos
-        state
-        n
-        ret
-        (continue t)
-        (buffer (current-buffer))
-        (h (make-hash-table :test 'equal))
-        (h2 (make-hash-table :test 'equal))
-        ctrl)
+  (save-excursion
+    (let (beg (i 0) (continue t))
+      (goto-char (point-min))
+      (when (get-text-property (point) 'tag-type)
+        (web-mode-tag-end)
+        (setq beg (point)))
+      (while (and continue
+                  (or (get-text-property (point) 'tag-beg)
+                      (web-mode-tag-next)))
+        (setq i (1+ i))
+        (when (> i 2000)
+          (setq continue nil))
+        (when (and beg (> (point) beg))
+          (message "content=%S > %S" beg (point)))
+        (if (web-mode-tag-end)
+            (setq beg (point))
+          (setq continue nil))
+        ) ;while
+      )))
+
+(defun web-mode-content-boundaries (&optional pos)
+  "Text boundaries"
+  (unless pos (setq pos (point)))
+  (let (beg end)
+    (setq beg (or (previous-property-change pos (current-buffer))
+                  (point-max)))
+    (setq end (or (next-property-change pos (current-buffer))
+                  (point-min)))
+    (while (and (< beg end) (member (char-after beg) '(?\s ?\n)))
+      (setq beg (1+ beg)))
+    (while (and (> end beg) (member (char-after (1- end)) '(?\s ?\n)))
+      (setq end (1- end)))
+    (message "beg(%S) end(%S)" beg end)
+    (cons beg end)
+    ))
+
+(defun web-mode-coord-pos (line column)
+  "Return pos at Line / Column pos"
+  (save-excursion
+    (when (stringp line) (setq line (string-to-number line)))
+    (when (stringp column) (setq column (string-to-number column)))
+    (goto-char (point-min))
+    (forward-line (1- line))
+    (move-to-column (1- column))
+    (point)))
+
+(defun web-mode-jshint ()
+  "Run JSHint on all the JavaScript parts."
+  (interactive)
+  (let (proc lines)
+    (when (buffer-file-name)
+      (setq proc (start-process
+                  "jshint-proc"
+                  nil
+                  "jshint" "--extract=auto" (buffer-file-name)))
+      (setq web-mode-jshint-errors 0)
+      (set-process-filter proc
+                          (lambda (proc output)
+                            (let ((offset 0) overlay pos (old 0) msg)
+                              (remove-overlays (point-min) (point-max) 'font-lock-face 'web-mode-error-face)
+                              (while (string-match
+                                      "line \\([[:digit:]]+\\), col \\([[:digit:]]+\\), \\(.+\\)\\.$"
+                                      output offset)
+                                (setq web-mode-jshint-errors (1+ web-mode-jshint-errors))
+                                (setq offset (match-end 0))
+                                (setq pos (web-mode-coord-pos (match-string-no-properties 1 output)
+                                                              (match-string-no-properties 2 output)))
+                                (when (get-text-property pos 'tag-beg)
+                                  (setq pos (1- pos)))
+                                (when (not (= pos old))
+                                  (setq old pos)
+                                  (setq overlay (make-overlay pos (1+ pos)))
+                                  (overlay-put overlay 'font-lock-face 'web-mode-error-face)
+                                  )
+                                (setq msg (or (overlay-get overlay 'help-echo)
+                                               (concat "l="
+                                                       (match-string-no-properties 1 output)
+                                                       " c="
+                                                       (match-string-no-properties 2 output)
+                                                       )))
+                                (overlay-put overlay 'help-echo
+                                             (concat msg " ## " (match-string-no-properties 3 output)))
+                                ) ;while
+                              ))
+                          )
+      ) ;when
+    ))
+
+(defun web-mode-dom-errors-show ()
+  "Show unclosed tags."
+  (interactive)
+  (let (beg end tag pos l n tags i cont cell overlay overlays first
+            (ori (point))
+            (errors 0)
+            (continue t)
+        )
+    (setq overlays (overlays-in (point-min) (point-max)))
+    (when overlays
+      (dolist (overlay overlays)
+        (when (eq (overlay-get overlay 'face) 'web-mode-warning-face)
+          (delete-overlay overlay)
+          )
+        )
+      )
+    (goto-char (point-min))
+    (when (not (or (get-text-property (point) 'tag-beg)
+                   (web-mode-tag-next)))
+      (setq continue nil))
     (while continue
-      (setq ctrl nil
-            last-tag nil)
-      (when (or (and (get-text-property pos 'tag-beg)
-                     (member (get-text-property pos 'tag-type) '(start end)))
-                (and (get-text-property pos 'block-beg)
-                     (setq ctrl (web-mode-is-active-block pos))))
-        (if ctrl
-            (setq tag (car ctrl)
-                  state (cdr ctrl))
-          (setq tag (get-text-property pos 'tag-name)
-                state (eq (get-text-property pos 'tag-type) 'start))
-          (if (null state) (setq last-tag (cons tag pos)))
+      (setq pos (point))
+      (setq tag (get-text-property pos 'tag-name))
+      (cond
+       ((eq (get-text-property (point) 'tag-type) 'start)
+        (setq tags (add-to-list 'tags (list tag pos)))
+;;        (message "(%S) opening %S" pos tag)
+        )
+       ((eq (get-text-property (point) 'tag-type) 'end)
+        (setq i 0
+              l (length tags)
+              cont t)
+        (while (and (< i l) cont)
+          (setq cell (nth i tags))
+;;          (message "cell=%S" cell)
+          (setq i (1+ i))
+          (cond
+           ((string= tag (nth 0 cell))
+            (setq cont nil)
+            )
+           (t
+            (setq errors (1+ errors))
+            (setq beg (nth 1 cell))
+            (setq end (web-mode-tag-end-position beg))
+            (unless first
+              (setq first beg))
+            (setq overlay (make-overlay beg (1+ end)))
+            (overlay-put overlay 'font-lock-face 'web-mode-warning-face)
+;;            (message "invalid <%S> at %S" (nth 0 cell) (nth 1 cell))
+            )
+           ) ;cond
+          ) ;while
+
+        (dotimes (i i)
+          (setq tags (cdr tags))
+;;          (setq cell (nth i tags))
+;;          (message "removing=%S" cell)
+          )
+
+        )
+       ) ;cond
+      (when (not (web-mode-tag-next))
+        (setq continue nil))
+      ) ;while
+    (message "%S error(s) detected" errors)
+    (if (> errors 0)
+        (progn (goto-char first)
+               (recenter))
+      (goto-char ori)
+      ) ;if
+    ;;    (message "%S" tags)
+    ))
+
+(defun web-mode-whitespaces-show ()
+  "Toggle whitespaces."
+  (interactive)
+  (if web-mode-enable-whitespaces
+      (web-mode-whitespaces-off)
+    (web-mode-whitespaces-on))
+  (web-mode-scan-buffer))
+
+(defun web-mode-whitespaces-on ()
+  "Show whitespaces."
+  (interactive)
+  (when web-mode-hl-line-mode-flag
+    (global-hl-line-mode -1))
+  (when web-mode-display-table
+    (setq buffer-display-table web-mode-display-table))
+  (setq web-mode-enable-whitespaces t))
+
+(defun web-mode-whitespaces-off ()
+  "Hide whitespaces."
+  (when web-mode-hl-line-mode-flag
+    (global-hl-line-mode 1))
+  (setq buffer-display-table nil)
+  (setq web-mode-enable-whitespaces nil))
+
+(defun web-mode-buffer-indent ()
+  "Indent all buffer."
+  (interactive)
+  (indent-region (point-min) (point-max))
+  (delete-trailing-whitespace))
+
+(defun web-mode-buffer-refresh ()
+  "Indent and fontify buffer."
+  (interactive)
+  (web-mode-scan-buffer)
+  (web-mode-buffer-indent))
+
+(defun web-mode-buffer-change-tag-case (&optional type)
+  "Change HTML tag case."
+  (interactive)
+  (save-excursion
+    (goto-char (point-min))
+    (let ((continue t) f)
+      (setq f (if (member type '("upper" "uppercase" "upper-case")) 'uppercase 'downcase))
+      (when (and (not (get-text-property (point) 'tag-beg))
+                 (not (web-mode-tag-next)))
+        (setq continue nil))
+      (while continue
+        (skip-chars-forward "<!/")
+        (if (looking-at "\\([[:alnum:]-]+\\)")
+            (replace-match (funcall f (match-string 0)) t))
+;;        (message "tag: %S (%S)"
+;;                 (get-text-property (point) 'tag-name)
+;;                 (point))
+        (unless (web-mode-tag-next)
+          (setq continue nil))
+        ) ;while
+      )))
+
+(defun web-mode-buffer-change-attr-case (&optional type)
+  "alter tag case"
+  (interactive)
+  (save-excursion
+    (goto-char (point-min))
+    (let ((continue t) f)
+      (setq f (if (member type '("upper" "uppercase" "upper-case")) 'uppercase 'downcase))
+      (while continue
+        (if (web-mode-attribute-next)
+            (when (looking-at "\\([[:alnum:]-]+\\)")
+              (replace-match (funcall f (match-string 0)) t)
+;;              (message "tag: %S (%S)" (match-string 0) (point))
+              ) ;when
+          (setq continue nil))
+        ) ;while
+      )))
+
+;; todo : passer de règle en règle et mettre un \n à la fin
+(defun web-mode-css-indent ()
+  "Indent CSS parts"
+  (interactive)
+  (save-excursion
+    (goto-char (point-min))
+    (let ((continue t) rule part-end)
+      (while continue
+        (if (web-mode-part-next)
+            (when (eq (get-text-property (point) 'part-side) 'css)
+              (setq part-end (web-mode-part-end-position))
+              (while (setq rule (web-mode-css-rule-next part-end))
+                (when (not (looking-at-p "[[:space:]]*\\($\\|<\\)"))
+                  (newline)
+                  (indent-for-tab-command)
+                  (setq part-end (web-mode-part-end-position)))
+                )
+              )
+          (setq continue nil)
+          )
+        )
+      )))
+
+;; tag-case=lower|upper-case , attr-case=lower|upper-case
+;; special-chars=unicode|html-entities
+;; smart-apostrophes=bool , smart-quotes=bool , indentation=bool
+(defun web-mode-buffer-normalize ()
+  "Normalize buffer"
+  (interactive)
+  (save-excursion
+    (let ((rules web-mode-normalization-rules) elt)
+      (when (setq elt (cdr (assoc "tag-case" rules)))
+        (web-mode-buffer-change-tag-case elt))
+      (when (setq elt (cdr (assoc "attr-case" rules)))
+        (web-mode-buffer-change-attr-case elt))
+      (when (setq elt (cdr (assoc "css-indentation" rules)))
+        (web-mode-css-indent))
+      (when (setq elt (cdr (assoc "smart-apostrophes" rules)))
+        (web-mode-dom-apostrophes-replace))
+      (when (setq elt (cdr (assoc "smart-quotes" rules)))
+        (web-mode-dom-quotes-replace))
+      (when (setq elt (cdr (assoc "special-chars" rules)))
+        (if (string= elt "entities")
+            (web-mode-dom-entities-encode)
+          (web-mode-dom-entities-replace)))
+      (when (setq elt (cdr (assoc "whitespaces" rules)))
+        (goto-char (point-min))
+        (while (not (eobp))
+          (forward-line)
+          (delete-blank-lines))
+        (delete-trailing-whitespace)
+        (untabify (point-min) (point-max)))
+      (when (setq elt (cdr (assoc "indentation" rules)))
+        (web-mode-buffer-indent))
+      )))
+
+(defun web-mode-block-previous-live-line ()
+  "Return previous non blank/comment/string line and return this line (trimmed)."
+  (interactive)
+  (save-excursion
+    (let ((continue t)
+          (line "")
+          (pos (point)))
+      (beginning-of-line)
+      (while (and continue
+                  (not (bobp))
+                  (forward-line -1))
+        (if (not (web-mode-block-is-token-line))
+            (setq line (web-mode-trim (buffer-substring (point) (line-end-position)))))
+        (when (not (string= line "")) (setq continue nil))
+        ) ;while
+      (if (string= line "")
+          (progn (goto-char pos) nil)
+        (cons line (current-indentation)))
+      )))
+
+(defun web-mode-previous-usable-client-line ()
+  "Return previous non blank/comment/string line and return this line (trimmed)."
+  (interactive)
+  (save-excursion
+    (let ((continue t)
+          (line "")
+          (pos (point)))
+      (beginning-of-line)
+      (while (and continue
+                  (not (bobp))
+                  (forward-line -1))
+        (if (not (web-mode-is-part-token-line))
+            (setq line (web-mode-trim (buffer-substring (point) (line-end-position)))))
+        (when (not (string= line "")) (setq continue nil))
+        )
+      (if (string= line "")
+          (progn (goto-char pos) nil)
+        (cons line (current-indentation)))
+      )))
+
+(defun web-mode-in-code-block (open close &optional prop)
+  "Detect if point is in a block delimited by open and close."
+  (save-excursion
+    (let ((pos (point)) pos-open pos-close start end ret)
+      (when prop
+        (setq start pos
+              end pos)
+        (when (eq (get-text-property pos prop) (get-text-property (1- pos) prop))
+          (setq start (or (previous-single-property-change pos prop) (point-min))))
+        (when (eq (get-text-property pos prop) (get-text-property (1+ pos) prop))
+          (setq end (next-single-property-change pos prop)))
+        ;;        (message "start(%S) end(%S)" start end)
+        )
+      (setq ret (and (web-mode-sb open start t)
+                     (setq pos-open (point))
+                     (web-mode-sf close end t)
+                     (setq pos-close (point))
+                     (>= pos-close pos)))
+      (if ret
+          (cons pos-open pos-close)
+        ret)
+      )))
+
+;; voir line-number-at-pos
+(defun web-mode-line-number (&optional pos)
+  "Return line number at point."
+  (unless pos (setq pos (point)))
+  (let (ret)
+    (setq ret (+ (count-lines 1 pos)
+                 (if (= (web-mode-column-at-pos pos) 0) 1 0)))
+    ret))
+
+(defun web-mode-clean-client-line (input)
+  "Remove comments and server scripts."
+  (let ((out "")
+        (beg 0)
+        (keep t)
+        (n (length input)))
+    (dotimes (i n)
+      (if (or (get-text-property i 'block-side input)
+              (eq (get-text-property i 'part-token input) 'comment)
+              (eq (get-text-property i 'tag-type input) 'comment))
+          (when keep
+            (setq out (concat out (substring input beg i))
+                  beg 0
+                  keep nil))
+        (when (null keep)
+          (setq beg i
+                keep t))
+        ) ;if
+      ;;      (message "out=%s beg=%d" out beg)
+      ) ;dotimes
+    (if (> beg 0) (setq out (concat out (substring input beg n))))
+    (setq out (if (= (length out) 0) input out))
+    (web-mode-trim out)
+    ;;    (message "%S [%s] > [%s]" beg input out)
+    ))
+
+(defun web-mode-clean-server-line (input)
+  "Remove comments from server line."
+  (let ((out "")
+        (beg 0)
+        (keep t)
+        (n (length input)))
+    (dotimes (i n)
+      (if (or (not (get-text-property i 'block-side input))
+              (member (get-text-property i 'block-token input) '(comment delimiter)))
+          (when keep
+            (setq out (concat out (substring input beg i))
+                  beg 0
+                  keep nil))
+        (when (null keep)
+          (setq beg i
+                keep t))
+        ) ;if
+      ) ;dotimes
+    (if (> beg 0) (setq out (concat out (substring input beg n))))
+    (setq out (if (= (length out) 0) input out))
+    (web-mode-trim out)
+    ;;    (message "%S [%s] > [%s]" beg input out)
+    ))
+
+(defun web-mode-language-at-pos (&optional pos)
+  "Return the language at pos."
+  (unless pos (setq pos (point)))
+  (cond
+   ((get-text-property pos 'block-side)
+    web-mode-engine)
+   ((get-text-property pos 'part-side)
+    (symbol-name (get-text-property pos 'part-side)))
+   (t
+    web-mode-content-type)
+   ) ;cond
+  )
+
+(defun web-mode-column-at-pos (&optional pos)
+  "Column at point"
+  (unless pos (setq pos (point)))
+  (save-excursion
+    (goto-char pos)
+    (current-column)
+    ))
+
+;; doit-on considérer que '=' est un bloc ouvrant avec ';' comme char de fin ?
+;; renommer block-beg en reg-beg
+(defun web-mode-point-context (pos)
+  "POS should be at the beginning of the indentation.
+   Return ctx = plist containing
+    :block-beg, :block-column,
+    :first-char, :line (trimmed)
+    :type (live, comment, string),
+    :language (html, php, jsp, aspx, asp + javascript, css),
+    :indent-offset
+    :prev-line :prev-char :prev-props :prev-indentation"
+  (save-excursion
+    (let (ctx pos-min
+              block-beg block-column first-char line type language indent-offset
+              prev prev-line prev-char prev-props prev-indentation)
+
+      (setq pos-min (point-min))
+      (setq block-beg pos-min
+            block-column 0
+            type "live"
+            language ""
+            prev-line ""
+            prev-char 0)
+      (cond
+
+       ((bobp)
+        (setq language "html")
+        )
+
+       ((string= web-mode-content-type "css")
+        (setq language "css"
+              indent-offset web-mode-css-indent-offset))
+
+       ((member web-mode-content-type '("javascript" "json"))
+        (setq language "javascript"
+              indent-offset web-mode-code-indent-offset))
+
+       ((member web-mode-content-type '("jsx"))
+        (setq language "jsx"
+              indent-offset web-mode-code-indent-offset)
+        (when (and (get-text-property pos 'part-expr)
+                   (get-text-property (1- pos) 'part-expr))
+          (setq language "javascript")
+          (setq block-beg (1+ (previous-single-property-change pos 'part-expr)))
+          (goto-char block-beg)
+          (setq block-column (current-column))
+          )
+        )
+
+       ((string= web-mode-content-type "php")
+        (setq language "php"
+              indent-offset web-mode-code-indent-offset))
+
+       ((or (string= web-mode-content-type "xml"))
+        (setq language "xml"
+              indent-offset web-mode-markup-indent-offset))
+
+       ((and (get-text-property pos 'tag-beg)
+             (get-text-property pos 'tag-name)
+             (not (get-text-property pos 'part-side)))
+        (setq language "html"
+              indent-offset web-mode-markup-indent-offset)
+        )
+
+       ((or (and (eq (get-text-property pos 'part-token) 'comment)
+                 (eq (get-text-property (1- pos) 'part-token) 'comment)
+                 (progn
+                   (setq block-beg (previous-single-property-change pos 'part-token))
+                   t))
+            (and (eq (get-text-property pos 'block-token) 'comment)
+                 (eq (get-text-property (1- pos) 'block-token) 'comment)
+                 (progn
+                   (setq block-beg (previous-single-property-change pos 'block-token))
+                   t)))
+        (setq type "comment"))
+
+       ((or (and (member (get-text-property pos 'part-token) '(string context key))
+                 (member (get-text-property (1- pos) 'part-token) '(string context key)))
+            (and (eq (get-text-property pos 'block-token) 'string)
+                 (eq (get-text-property (1- pos) 'block-token) 'string)))
+        (setq type "string"))
+
+       ((and (get-text-property pos 'block-side)
+             (not (get-text-property pos 'block-beg)))
+        (setq block-beg (or (web-mode-block-beginning-position pos) pos-min))
+        (goto-char block-beg)
+        (setq block-column (current-column))
+        (setq language web-mode-engine)
+        (setq indent-offset web-mode-code-indent-offset)
+        (cond
+         ((and (string= web-mode-engine "php")
+               (not (web-mode-looking-at-pos "<\\?\\(=\\|php\\)?[ ]*$" block-beg)))
+          (save-excursion
+            (goto-char block-beg)
+            (looking-at "<\\?\\(=\\|php\\)?[ ]*")
+            (goto-char (match-end 0))
+            (setq block-column (current-column))
+            )
+          )
+         ((string= web-mode-engine "blade")
+          (setq block-beg (+ block-beg 2)
+                block-column (+ block-column 2))
           )
-
-        (setq n (gethash tag h 0))
-        (if (null state)
-            (progn
-              (when (> n 0) (puthash tag (1- n) h))
-              (puthash tag (1- n) h2))
-          (puthash tag (1+ n) h)
-          (puthash tag (1+ n) h2))
-        );when
-      (setq pos (1+ pos))
-      (when (null tag-pos)
-        (setq tag-pos (next-single-property-change pos 'tag-beg buffer limit)))
-      (when (null block-pos)
-        (setq block-pos (next-single-property-change pos 'block-beg buffer limit)))
-      (cond
-       ((and (null tag-pos)
-             (null block-pos))
-        (setq pos nil)
-        )
-       ((or (null block-pos)
-            (< tag-pos block-pos))
-        (setq pos tag-pos)
-        (setq tag-pos nil)
-        )
-       (t
-        (setq pos block-pos)
-        (setq block-pos nil)
+         ((string= web-mode-engine "razor")
+          (setq block-beg (+ block-beg 2))
+          )
+         ((string= web-mode-engine "template-toolkit")
+          (setq block-beg (+ block-beg 3)
+                block-column (+ block-column 3))
+          )
+         ((and (string= web-mode-engine "jsp")
+               (web-mode-looking-at-pos "<%@\\|<[[:alpha:]]" block-beg))
+          (save-excursion
+            (goto-char block-beg)
+            (looking-at "<%@[ ]*[[:alpha:]]+[ ]+\\|</?[[:alpha:]]+:[[:alpha:]]+[ ]+")
+            (goto-char (match-end 0))
+            (setq block-column (current-column))
+            )
+          )
+         ((and (string= web-mode-engine "django")
+               (not (web-mode-looking-at-pos "{{[{]?[ ]*$" block-beg)))
+          (save-excursion
+            (goto-char block-beg)
+            (looking-at "{{[{]?[ ]*")
+            (goto-char (match-end 0))
+            (setq block-column (current-column))
+            )
+          )
+         ((and (string= web-mode-engine "freemarker")
+               (web-mode-looking-at-pos "<@\\|<%@\\|<[[:alpha:]]" block-beg))
+          (save-excursion
+            (goto-char block-beg)
+            (looking-at "<@[[:alpha:].]+[ ]+\\|<%@[ ]*[[:alpha:]]+[ ]+\\|<[[:alpha:]]+:[[:alpha:]]+[ ]+")
+            (goto-char (match-end 0))
+            (setq block-column (current-column))
+            )
+          )
+         ) ;cond
         )
-       )
-      (when (or (null pos)
-                (>= pos limit))
-        (setq continue nil))
-      );while
-;;    (message "hashtable=%S" h)
-    (maphash (lambda (k v) (if (> v 0) (setq ret t))) h)
-    (when (and (null ret)
-               last-tag
-               (> (hash-table-count h2) 1)
-               (< (gethash (car last-tag) h2) 0))
-;;      (message "last-tag=%S" last-tag)
-      (save-excursion
-        (goto-char (cdr last-tag))
-        (web-mode-match-html-tag)
-        (when (not (= (point) (cdr last-tag)))
-          (setq n (point))
-          (back-to-indentation)
-          (if (= n (point)) (setq ret (current-indentation))))
-        ))
-    ret))
 
-(defun web-mode-ruby-indentation (pos line initial-column language-offset limit)
-  "Calc indent column."
-  (interactive)
-  (unless limit (setq limit nil))
-  (let (h out prev-line prev-indentation ctx)
-    (setq ctx (web-mode-count-opened-blocks pos limit))
-    (if (cddr ctx)
-        (progn
-;;          (message "ctx=%S" (car (cdr ctx)))
-          (setq out (cadr ctx))
-;;          (message "out=%S" out)
-          )
-      (setq h (web-mode-previous-line pos limit))
-      (setq out initial-column)
-      (when h
-        (setq prev-line (car h))
-        (setq prev-indentation (cdr h))
+       ((get-text-property pos 'part-side)
+;;        (message "pos-min=%S block-beg=%S part-beg=%S" pos-min block-beg (web-mode-part-beginning-position pos))
+        (setq block-beg (web-mode-part-beginning-position pos))
+;;        (message "block-beg %S" block-beg)
+        (setq block-beg (or block-beg pos-min))
+        (goto-char block-beg)
+        (search-backward "<" nil t)
+        (setq block-column (current-column))
+        (setq language (symbol-name (get-text-property pos 'part-side)))
         (cond
-         ((string-match-p "^\\(end\\|else\\|elsif\\|when\\)" line)
-          (setq out (- prev-indentation language-offset))
+         ((string= language "css")
+          (setq indent-offset web-mode-css-indent-offset)
           )
-         ((string-match-p "\\(when\\|if\\|else\\|elsif\\|unless\\|for\\|while\\|def\\|class\\)" prev-line)
-          (setq out (+ prev-indentation language-offset))
+         ((string= language "jsx")
+          (setq indent-offset web-mode-code-indent-offset)
           )
          (t
-          (setq out prev-indentation)
+          (setq language "javascript"
+                indent-offset web-mode-code-indent-offset)
           )
          )
-        );when
-      );if
-    out
-    ))
+        ) ; part-side
 
-(defun web-mode-asp-indentation (pos line initial-column language-offset limit)
-  "Calc indent column."
-  (interactive)
-  (unless limit (setq limit nil))
-  (let (h out prev-line prev-indentation)
-    (setq h (web-mode-previous-line pos limit))
-    (setq out initial-column)
-    (when h
-      (setq prev-line (car h))
-      (setq prev-indentation (cdr h))
-      (cond
-       ;; ----------------------------------------------------------------------
-       ;; unindent
-       ((string-match-p "\\<\\(\\(end \\(if\\|function\\|class\\|sub\\|with\\)\\)\\|else\\|elseif\\|next\\|loop\\)\\>" line)
-        (setq out (- prev-indentation language-offset)))
-       ;; ----------------------------------------------------------------------
-       ;; select case statement
-       ((string-match-p "\\<\\(select case\\)\\>" line)
-        (setq out (- prev-indentation 0)))
-       ((string-match-p "\\<\\(end select\\)" line)
-        (setq out (- prev-indentation (* 2 language-offset))))
-       ((and (string-match-p "\\<\\(case\\)\\>" line) (not (string-match-p "\\<\\(select case\\)\\>" prev-line)))
-        (setq out (- prev-indentation language-offset)))
-       ;; ----------------------------------------------------------------------
-       ;; do nothing
-       ((string-match-p "\\<\\(\\(end \\(if\\|function\\|class\\|sub\\|select\\|with\\)\\)\\|loop\\( until\\| while\\)?\\)\\>" prev-line)
-        (setq out (+ prev-indentation 0)))
-       ;; indent
-       ((string-match-p "\\<\\(\\(select \\)?case\\|else\\|elseif\\|unless\\|for\\|class\\|with\\|do\\( until\\| while\\)?\\|while\\|\\(public \\|private \\)?\\(function\\|sub\\|class\\)\\)\\>" prev-line)
-        (setq out (+ prev-indentation language-offset)))
-       ;; single line if statement
-       ((string-match-p "\\<if\\>.*\\<then\\>[ \t]*[[:alpha:]]+" prev-line)
-        (setq out (+ prev-indentation 0)))
-       ;; normal if statement
-       ((string-match-p "\\<\\if\\>" prev-line)
-        (setq out (+ prev-indentation language-offset)))
        (t
-        (setq out prev-indentation))
-       )
-      );when
-    out
-    ))
-
-(defun web-mode-previous-line (pos limit)
-  "Previous line"
-  (save-excursion
-    (let (beg end line (continue t))
-      (goto-char pos)
-      (while continue
-        (forward-line -1)
-        (setq end (line-end-position))
-        (setq line (buffer-substring-no-properties (point) end))
-        (when (or (not (string-match-p "^[ \t]*$" line))
-                  (bobp)
-                  (<= (point) limit))
-          (setq continue nil))
+        (setq language "html"
+              indent-offset web-mode-markup-indent-offset)
         )
-      (if (<= (point) limit)
-          ;;todo : affiner (le + 3 n est pas générique cf. <?php <% <%- etc.)
-          (setq beg (if (< (+ limit 3) end) (+ limit 3) end))
-        (setq beg (line-beginning-position))
-        );if
-      (setq line (buffer-substring-no-properties beg end))
-      ;;      (message "line=%s" line)
-      (cons line (current-indentation))
-      )))
 
-(defun web-mode-bracket-indentation (pos initial-column language-offset &optional limit)
-  "Calc indent column."
-  (interactive)
-  (unless limit (setq limit nil))
-  (save-excursion
-    (let (offset n first-char block-info col block-column (continue t))
+       ) ;cond
+
       (goto-char pos)
-      (setq first-char (char-after)
-            block-column initial-column)
-      (while continue
-        (forward-line -1)
-        (back-to-indentation)
+      (setq line (web-mode-trim (buffer-substring-no-properties (line-beginning-position)
+                                                                (line-end-position))))
+      (setq first-char (if (string= line "") 0 (aref line 0)))
+
+      (when (or (member language '("php" "javascript" "jsx" "razor"))
+                (and (string= language "html")
+                     (not (eq ?\< first-char))))
         (cond
-         ((or (> limit (point))
-              (bobp))
-          (setq continue nil)
+         ((member language '("html" "javascript" "jsx"))
+          (setq prev (web-mode-previous-usable-client-line))
+          ;;          (message "prev-line=%S" prev-line)
+          (when prev
+            (setq prev-line (car prev)
+                  prev-indentation (cdr prev))
+            (setq prev-line (web-mode-clean-client-line prev-line))
+;;            (message "prev-line[%s]" prev-line)
+            (setq prev-props (text-properties-at (1- (length prev-line)) prev-line)))
           )
-         ((and (= (current-indentation) initial-column)
-               (not (eolp)))
-          (setq continue nil)
-          (setq limit (point))
+         (t
+          (setq prev (web-mode-block-previous-live-line))
+          (when prev
+            (setq prev-line (car prev)
+                  prev-indentation (cdr prev))
+            (setq prev-line (web-mode-clean-server-line prev-line))
+;;            (message "pl=%s" prev-line)
+            ) ;when
+          )
+         ) ;cond
+        (when (>= (length prev-line) 1)
+          (setq prev-char (aref prev-line (1- (length prev-line))))
+          (setq prev-line (substring-no-properties prev-line))
           )
+        )
+
+      (when (string= web-mode-content-type "html")
+        (cond
+         ((member language '("javascript" "jsx"))
+          (setq block-column (+ block-column web-mode-script-padding)))
+         ((string= language "css")
+          (setq block-column (+ block-column web-mode-style-padding)))
+         ((not (member language '("html" "razor")))
+          (setq block-column (+ block-column web-mode-block-padding)))
          )
         )
-;;      (message "ic=%S point=%S limit=%S" initial-column (point) limit)
-      (goto-char pos)
 
-      (setq block-info (web-mode-count-opened-blocks pos limit))
-      (setq col initial-column)
-;;      (message "bi=%S" block-info)
-      (if (cddr block-info)
-          (progn
-            (setq col (car (cdr block-info)))
-            )
-        (setq n (car block-info))
-        (setq col initial-column)
-;;        (message "initial-col=%S n=%S col=%S" initial-column n col)
-        (if (member first-char '(?\} ?\) ?\])) (setq n (1- n)))
-        (setq col (+ initial-column (* n language-offset)))
-        );if
-      (if (< col block-column) block-column col)
+      (setq ctx (list :block-beg block-beg
+                      :block-column block-column
+                      :first-char first-char
+                      :line line
+                      :type type
+                      :language language
+                      :indent-offset indent-offset
+                      :prev-line prev-line
+                      :prev-char prev-char
+                      :prev-props prev-props
+                      :prev-indentation prev-indentation))
+;;      (message "%S" ctx)
+      ctx
       )))
 
-;; return (opened-blocks . (col-num . arg-inline))
-(defun web-mode-count-opened-blocks (pos &optional limit)
-  "Count opened opened block at point."
-  (interactive)
-  (unless limit (setq limit nil))
-  (save-excursion
-    (goto-char pos)
-    (let ((continue t)
-          (match "")
-          (case-found nil)
-          (case-count 0)
-          (queues (make-hash-table :test 'equal))
-          (opened-blocks 0)
-          (col-num 0)
-          (regexp "[\]\[}{)(]\\|[ ;\t]\\(break[ ;]\\|case[ :]\\|default[ :]\\)")
-          (num-opened 0)
-          close-char n queue arg-inline arg-inline-checked char lines)
+(defun web-mode-indent-cycle (regex-line regex-sym block-beg indent-offset)
+  "Returns next position in the indent cycle for REGEX-SYM on
+positions from the previous line matching REGEX-LINE withing
+BLOCK-BEGIN. Loops to start at INDENT-OFFSET."
+  (letrec
+      ((match-indices-all (lambda  (regex string)
+                            (let ((i (string-match-p regex string)))
+                              (if i (cons
+                                     i
+                                     (mapcar (lambda (x) (+ x i 1))
+                                             (funcall match-indices-all regex
+                                                      (substring string (+ i 1)))))))))
+       (filter (lambda (condp lst)
+                 (delq nil
+                       (mapcar (lambda (x)
+                                 (and (funcall condp x) x)) lst))))
+       (this-line (thing-at-point 'line))
+       (rsb-prev-line (progn
+                        (web-mode-rsb regex-line block-beg)
+                        (thing-at-point 'line)))
+       (pos-of-this-sym (string-match-p regex-sym this-line))
+       (prev-sym-locations (funcall match-indices-all regex-sym rsb-prev-line))
+       (farther-syms (progn
+                       (add-to-list 'prev-sym-locations (+ indent-offset web-mode-code-indent-offset))
+                       (funcall filter (lambda (i) (> i pos-of-this-sym))
+                                (sort prev-sym-locations '<)))))
+    (cond ((null farther-syms) indent-offset)
+          ((or web-mode-indent-cycle-left-first
+               (equal last-command 'indent-for-tab-command)) (car farther-syms))
+          (t (car (last farther-syms))))))
+
+(defun web-mode-indent-line ()
+  "Indent current line according to language."
+
+  (let ((offset nil)
+        (char nil)
+        (inhibit-modification-hooks t))
+
+    (save-excursion
+      (back-to-indentation)
+      (setq char (char-after))
+      (let* ((pos (point))
+             (ctx (web-mode-point-context pos))
+             (block-beg (plist-get ctx :block-beg))
+             (block-column (plist-get ctx :block-column))
+             (first-char (plist-get ctx :first-char))
+             (line (plist-get ctx :line))
+             (type (plist-get ctx :type))
+             (language (plist-get ctx :language))
+             (indent-offset (plist-get ctx :indent-offset))
+             (prev-line (plist-get ctx :prev-line))
+             (prev-char (plist-get ctx :prev-char))
+             (prev-props (plist-get ctx :prev-props))
+             (prev-indentation (plist-get ctx :prev-indentation)))
+
+        (cond
+
+         ((or (bobp) (= (line-number-at-pos pos) 1))
+          (setq offset 0)
+          )
+
+         ((string= type "string")
+          (setq offset nil)
+          )
 
-      (while (and continue (re-search-backward regexp limit t))
-;;        (message "%S: %c" (point) (char-before))
-        (unless (web-mode-is-comment-or-string)
-          (setq match (match-string-no-properties 0))
-          (when (> (length match) 1)
-            (skip-chars-forward "[ \t]")
-            (setq match (replace-regexp-in-string "\\`[ ;\t]*" "" (replace-regexp-in-string "[ :;]*\\'" "" match)))
+         ((string= type "comment")
+          (goto-char (car
+                      (web-mode-property-boundaries
+                       (if (eq (get-text-property pos 'part-token) 'comment)
+                           'part-token
+                         'block-token)
+                       pos)))
+          (setq offset (current-column))
+          (cond
+           ((and (string= (buffer-substring-no-properties (point) (+ (point) 2)) "/*")
+                 (eq ?\* first-char))
+            (setq offset (1+ offset)))
+           ((and (string= web-mode-engine "django")
+                 (looking-back "{% comment %}"))
+            (setq offset (- offset 12))
             )
-          (setq char (aref match 0))
-;;          (message "match:%S" match)
+           ((and (string= web-mode-engine "mako")
+                 (looking-back "<%doc%>"))
+            (setq offset (- offset 6))
+            )
+           ) ;cond
+          ) ;case comment
 
-          (cond
+         ((and (string= language "html")
+               (string= web-mode-engine "razor")
+               (get-text-property pos 'block-side)
+               (string-match-p "^}" line))
+          ;;        (message "ici")
+          (goto-char (web-mode-opening-paren-position (point)))
+          (back-to-indentation)
+          (setq offset (current-column))
+          )
 
-           ((member char '(?\{ ?\( ?\[))
-            (cond
-             ((eq char ?\() (setq close-char ?\)))
-             ((eq char ?\{) (setq close-char ?\}))
-             ((eq char ?\[) (setq close-char ?\])))
+         ((and (or (web-mode-block-is-close pos)
+                   (web-mode-block-is-inside pos))
+               (web-mode-block-match))
+          (setq offset (current-indentation))
+          )
 
-            (setq queue (gethash char queues nil))
-            (setq queue (push (cons (point) (web-mode-line-number)) queue))
-            (puthash char queue queues)
-            ;;(message "%c queue=%S" char queue)
+         ((and (eq (get-text-property pos 'tag-type) 'end)
+               (web-mode-tag-match))
+          (setq offset (current-indentation))
+          )
 
-            (setq queue (gethash close-char queues nil))
-            (setq n (length queue))
-            (cond
-             ((> n 0)
-              (setq queue (cdr queue))
-              (puthash close-char queue queues)
-              ;;(message "%c queue=%S" close-char queue)
-              (setq queue (gethash char queues nil))
-              (setq queue (cdr queue))
-              (puthash char queue queues)
-              ;;(message "%c queue=%S" char queue)
-              )
-             ((= n 0)
-              (setq num-opened (1+ num-opened))
-              ;;(message "num-opened=%S %S" num-opened (point))
-              )
-             )
+         ((and prev-props (plist-get prev-props 'tag-attr))
+          (web-mode-tag-beginning)
+          (let (skip)
+            (setq skip (next-single-property-change (point) 'tag-attr))
+            (when skip
+              (goto-char skip)
+              (setq offset (current-column))
+              ))
+          )
 
-            (when (and (= num-opened 1) (null arg-inline-checked))
-              (setq arg-inline-checked t)
-;;              (when (not (member (char-after (1+ (point))) '(?\n ?\r ?\{)))
-              (when (not (looking-at-p ".[ ]*$"))
-                (setq arg-inline t
-                      continue nil
-                      col-num (1+ (current-column))))
-;;              (message "pt=%S" (point))
-              )
+         ((and (get-text-property pos 'tag-beg)
+               (not (get-text-property pos 'part-side))
+               (not (member web-mode-content-type '("jsx"))))
+          (setq offset (web-mode-markup-indentation pos))
+          )
 
-            );case
+         ((member language '("asp" "aspx" "blade" "code" "django" "erb"
+                             "freemarker" "javascript" "jsp" "jsx" "lsp"
+                             "mako" "mason" "mojolicious"
+                             "php" "python" "razor" "react"
+                             "template-toolkit" "web2py"))
 
-           ((member char '(?\} ?\) ?\]))
-            (setq queue (gethash char queues nil))
-            (setq queue (push (point) queue))
-            (puthash char queue queues)
-            ;;            (message "%c queue=%S" char queue)
-            )
+          (cond
 
-           ((member match '("case" "default"))
-            (setq case-found t
-                  case-count (1+ case-count))
+           ((and (get-text-property (1- pos) 'block-side)
+                 (eq (get-text-property pos 'block-token) 'delimiter))
+            (if (web-mode-block-beginning pos)
+                (setq offset (current-column)))
             )
 
-           ((string= match "break")
-            (setq case-count (1- case-count))
+           ((string= language "lsp")
+            ;;            (message "iwi")
+            (setq offset (web-mode-bracket-indentation pos
+                                                       block-column
+                                                       indent-offset
+                                                       language
+                                                       block-beg))
             )
 
-           );cond
-
-          );unless
-        );while
-
-      (unless arg-inline
-        (maphash
-         (lambda (char queue)
-           (when (member char '(?\{ ?\( ?\[))
-             ;;(message "%c => %S" char queue)
-             (dolist (pair queue)
-               (setq n (cdr pair))
-               (unless (member n lines)
-                 (push n lines))
-               )
-             );when
-           )
-         queues)
-        (setq opened-blocks (length lines))
-        (when (and case-found (> case-count 0))
-          (goto-char pos)
-          (back-to-indentation)
-          (when (not (looking-at-p "case\\|}"))
-            (setq opened-blocks (1+ opened-blocks))
+           ((and (string= language "mason")
+                 (string-match-p "</%" line))
+            (if (web-mode-block-beginning pos)
+                (setq offset (current-column)))
             )
-          )
-        );unless
 
-;;      (message "opened-blocks(%S) col-num(%S) arg-inline(%S)" opened-blocks col-num arg-inline)
+           ((and (string= language "razor")
+                 (string-match-p "^\\." line)
+                 (string-match-p "^\\." prev-line))
+            (setq offset prev-indentation)
+            )
 
-      (cons opened-blocks (cons col-num arg-inline))
+           ((and (string= language "razor")
+                 (string-match-p "^case " line)
+                 (string-match-p "^case " prev-line))
+            (search-backward "case ")
+            (setq offset (current-column))
+            )
 
-      )))
+           ((and (string-match-p "^[=]?%]" line)
+                 (string= web-mode-engine "template-toolkit"))
+            (if (web-mode-block-beginning pos)
+                (setq offset (current-column)))
+            )
 
-(defun web-mode-count-char-in-string (char string)
-  "Count char in string."
-  (let ((n 0))
-    (dotimes (i (length string))
-      (if (eq (elt string i) char)
-          (setq n (1+ n))))
-    n))
+           ((and (string= language "php") (string-match-p "^->" line))
+            (when (web-mode-translate-backward pos "->" language block-beg)
+              (setq offset (current-column)))
+            )
 
-(defun web-mode-scan-at-pos ()
-  "web mode scan at point"
-  (save-excursion
-    (let (scan-beg scan-end (pos (point)))
-      (cond
-       ((web-mode-rsb-client "^[ ]*<")
-        (setq scan-beg (point))
-        (goto-char pos)
-        (setq scan-end (if (web-mode-rsf-client "[[:alnum:] /\"]>[ ]*$") (point) (point-max)))
-        ;;              (message "scan-end=%S" scan-end)
-        ;;            (setq scan-end (point-max))
-        )
-       (t
-        (setq scan-beg 1
-              scan-end (point-max))
-        )
-       );cond
-      ;;(message "scan-region (%S) > (%S)" scan-beg scan-end)
-      ;;          (setq scan-end (point-max))
-      (web-mode-scan-region scan-beg scan-end)
-      );save-excursion
-    ))
+           ((and (string= language "php") (string-match-p "\\.$" prev-line))
+            (cond
+             ((and (string-match-p "\\(=\\|echo \\|return \\)" prev-line)
+                   (web-mode-rsb "\\(=\\|echo\\|return\\)[ ]+" block-beg))
+              (goto-char (match-end 0))
+              (setq offset (current-column))
+              )
+             ((string-match-p "^['\"$0-9.]" prev-line)
+              (setq offset prev-indentation)
+              )
+             (t
+              (setq offset block-column)
+              )
+             )
+            )
 
-(defun web-mode-mark-and-expand ()
-  "Mark and expand."
-  (interactive)
-;;  (message "last-input-event=%S" last-input-event)
-  (web-mode-mark (point)))
+           ((and (string= language "php")
+                 (or (string-match-p "^else$" prev-line)
+                     (string-match-p "^\\(if\\|for\\|foreach\\|while\\)[ ]*(.+)$" prev-line))
+                 (not (string-match-p "^{" line)))
+            (setq offset (+ prev-indentation web-mode-code-indent-offset))
+            )
 
-;; todo : pb du engine=go ... selection d'un bloc
-(defun web-mode-mark (pos)
-  "Mark at point."
+           ((and (member language '("javascript" "jsx")) (eq ?\. first-char))
+            (if web-mode-enable-indent-cycle
+                (setq offset
+                      (web-mode-indent-cycle
+                       "[[:alnum:][:blank:]]\\.[[:alpha:]]"
+                       "\\."
+                       block-beg
+                       indent-offset))
+              (when (web-mode-translate-backward pos "[[:alnum:][:blank:]]\\.[[:alpha:]]" language block-beg)
+                (setq offset (1+ (current-column))))
+              ))
 
-  (let ((beg pos) (end pos) prop reg-beg boundaries)
+           ((and (member first-char '(?\? ?\. ?\:))
+                 (not (string= language "erb")))
+            (web-mode-rsb "[^!=][=(]" block-beg)
+            (setq offset (1+ (current-column)))
+            (when (and (string= web-mode-engine "php")
+                       (looking-at-p " =>"))
+              (setq offset (1+ offset))
+              )
+            )
 
-    (if mark-active
-        (setq reg-beg (region-beginning))
-      (setq web-mode-expand-initial-pos (point)))
+           ((and (member prev-char '(?\? ?\:))
+                 (not (string-match-p "^\\(case\\|default\\)[ :]" prev-line)))
+            (web-mode-sb "?" block-beg)
+            (when (looking-back ")[ ]*")
+              (web-mode-sb ")" block-beg)
+              (goto-char (web-mode-opening-paren-position (point)))
+              )
+            (web-mode-rsb "[=(]" block-beg)
+            (if (eq (char-after) ?\=) (skip-chars-forward "= ") (skip-chars-forward "( "))
+            ;;          (message "pt=%S" (point))
+            (setq offset (current-column))
+            )
 
-    ;;    (message "regs=%S %S %S %S" (region-beginning) (region-end) (point-min) (point-max))
+           ((and (member prev-char '(?\. ?\+ ?\? ?\:))
+                 (not (string-match-p "^\\(case\\|default\\)[ :]" prev-line)))
+            (web-mode-rsb "=\\|(" block-beg)
+            (if (eq (char-after) ?\=) (skip-chars-forward "= ") (skip-chars-forward "( "))
+            (setq offset (current-column))
+            )
 
-    ;;    (message "before=%S" web-mode-expand-previous-state)
+           ((string= language "erb")
+            (setq offset (web-mode-ruby-indentation pos
+                                                    line
+                                                    block-column
+                                                    indent-offset
+                                                    block-beg))
+            )
 
-    (cond
+           ((member language '("mako" "web2py"))
+            (setq offset (web-mode-python-indentation pos
+                                                      line
+                                                      block-column
+                                                      indent-offset
+                                                      block-beg))
+            )
 
-     ((and mark-active
-           (= (region-beginning) (point-min))
-           (or (= (region-end) (point-max)) (= (1+ (region-end)) (point-max))))
-      (deactivate-mark)
-      (goto-char (or web-mode-expand-initial-pos (point-min)))
-      (recenter))
+           ((string= language "asp")
+            (setq offset (web-mode-asp-indentation pos
+                                                   line
+                                                   block-column
+                                                   indent-offset
+                                                   block-beg))
+            )
 
-    ((and (member (get-text-property pos 'block-token) '(comment string))
-          (not (string= web-mode-expand-previous-state "block-token")))
+           ;; ((and (string= language "jsx")
+           ;;       (get-text-property pos 'part-expr)
+           ;;       (get-text-property (1- pos) 'part-expr))
+           ;;  (setq offset (web-mode-bracket-indentation pos
+           ;;                                             block-column
+           ;;                                             indent-offset
+           ;;                                             language
+           ;;                                             block-beg))
+           ;;  )
+
+           ((and (string= language "jsx")
+                 (eq (get-text-property pos 'tag-type) 'end)
+                 (web-mode-tag-match))
+            (setq offset (current-indentation))
+            )
 
-      (when (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token))
-        (setq beg (or (previous-single-property-change pos 'block-token) (point-min))))
-      (when (eq (get-text-property pos 'block-token) (get-text-property (1+ pos) 'block-token))
-        (setq end (next-single-property-change pos 'block-token)))
-      (set-mark beg)
-      (goto-char end)
-      (exchange-point-and-mark)
-      (setq web-mode-expand-previous-state "block-token"))
+           ((and (string= language "jsx")
+                 (eq (get-text-property pos 'part-token) 'html)
+                 (and prev-props (eq (plist-get prev-props 'part-token) 'html))
+;;                 (eq (get-text-property (1- pos) 'part-token) 'html)
+                 )
+;;            (message "jsx %S" prev-props)
+            (setq offset (web-mode-markup-indentation pos))
+            )
 
-     ((and (eq (get-text-property pos 'block-side) t)
-           (not (member web-mode-engine '(django go)))
-           (setq boundaries (web-mode-in-code-block "{" "}" 'block-side))
-           (not (string= web-mode-expand-previous-state "server-block")))
-      (set-mark (car boundaries))
-      (goto-char (cdr boundaries))
-      ;;      (message "char=[%c]" (char-before (- (point) 1)))
-      (if (eq ?\% (char-before (- (point) 1)))
-          (setq web-mode-expand-previous-state "block-side")
-        (setq web-mode-expand-previous-state "server-block"))
-      (exchange-point-and-mark)
-      )
+           (t
+;;            (message "%S %S %S" language pos block-beg)
+            (setq offset (web-mode-bracket-indentation pos
+                                                       block-column
+                                                       indent-offset
+                                                       language
+                                                       block-beg))
+            ) ;t
 
-     ((and (eq (get-text-property pos 'block-side) t)
-           (not (string= web-mode-expand-previous-state "block-side")))
-      (when (eq (get-text-property pos 'block-side) (get-text-property (1- pos) 'block-side))
-        (setq beg (or (previous-single-property-change pos 'block-side) (point-min))))
-      (when (eq (get-text-property pos 'block-side) (get-text-property (1+ pos) 'block-side))
-        (setq end (next-single-property-change pos 'block-side)))
-      (set-mark beg)
-      (goto-char end)
-      (exchange-point-and-mark)
-      (setq web-mode-expand-previous-state "block-side"))
+           )) ;end case script block
 
-     ((and (member (get-text-property pos 'part-token) '(comment string))
-           (not (string= web-mode-expand-previous-state "part-token")))
+         ((string= language "css")
+          (setq offset (web-mode-bracket-indentation pos
+                                                     block-column
+                                                     indent-offset
+                                                     "css"
+                                                     block-beg))
+          ) ;case style
 
-      (when (eq (get-text-property pos 'part-token) (get-text-property (1- pos) 'part-token))
-        (setq beg (previous-single-property-change pos 'part-token)))
-      (when (eq (get-text-property pos 'part-token) (get-text-property (1+ pos) 'part-token))
-        (setq end (next-single-property-change pos 'part-token)))
-      (set-mark beg)
-      (goto-char end)
-      (exchange-point-and-mark)
-      (setq web-mode-expand-previous-state "part-token"))
+         (t ; case html
 
-     ((and (get-text-property pos 'part-side)
-           (not (string= web-mode-expand-previous-state "client-part"))
-           (setq boundaries (web-mode-in-code-block "{" "}" 'part-side)))
-      (set-mark (car boundaries))
-      (goto-char (cdr boundaries))
-      (exchange-point-and-mark)
-      (setq web-mode-expand-previous-state "client-part")
-      )
+          (cond
 
-     ((and (eq (get-text-property pos 'part-side) t)
-           (not (string= web-mode-expand-previous-state "part-side")))
+           ((and (string= web-mode-engine "mason")
+                 (string-match-p "^%" line))
+            (setq offset 0)
+            )
 
-      (when (eq (get-text-property pos 'part-side) (get-text-property (1- pos) 'part-side))
-        (setq beg (previous-single-property-change pos 'part-side)))
-      (when (eq (get-text-property pos 'part-side) (get-text-property (1+ pos) 'part-side))
-        (setq end (next-single-property-change pos 'part-side)))
-      (set-mark beg)
-      (goto-char end)
-      (exchange-point-and-mark)
-      (setq web-mode-expand-previous-state "part-side"))
+           ;;          ((and (string= web-mode-engine "razor")
+           ;; ;;               (get-text-property pos 'block-side)
+           ;;                (string-match-p "^}" line))
+           ;;           (message "ici")
+           ;;           (goto-char (web-mode-opening-paren-position (point)))
+           ;;           (back-to-indentation)
+           ;;           (setq offset (current-column))
+           ;;           )
+
+           ;; ((or (and (eq (get-text-property pos 'tag-type) 'end)
+           ;;           (web-mode-tag-match)))
+           ;;  (setq offset (current-indentation))
+           ;;  )
+
+           ((or (eq (length line) 0)
+                (= web-mode-indent-style 2)
+                (get-text-property pos 'tag-beg)
+                (get-text-property pos 'block-beg))
+            ;;          (message "ici")
+            (setq offset (web-mode-markup-indentation pos))
+            )
 
-     ;;     ((and (eq (get-text-property pos 'markup-type) 'attr)
-     ((and (eq (get-text-property pos 'part-token) 'attr)
-           (not (string= web-mode-expand-previous-state "html-attr")))
+           ) ;cond
 
-      ;; todo: tester que le car précédent n'est pas un
-      (when (eq (get-text-property pos 'part-token) (get-text-property (1- pos) 'part-token))
-        (setq beg (previous-single-property-change pos 'part-token)))
-      (when (eq (get-text-property pos 'part-token) (get-text-property (1+ pos) 'part-token))
-        (setq end (next-single-property-change pos 'part-token)))
-      (set-mark beg)
-      (goto-char end)
-      (exchange-point-and-mark)
-      (setq web-mode-expand-previous-state "html-attr"))
+          ) ;end case html block
 
-     ((and mark-active
-           (eq ?\< (char-after)))
+         ) ;end switch language block
 
-      (web-mode-element-parent)
-      (if (= reg-beg (region-beginning))
-          (mark-whole-buffer)
-        (web-mode-element-select))
-      )
+        )) ;save-excursion
 
-     (t
-      (web-mode-element-select)
-      ;;(mark-whole-buffer)
-      )
+    ;;    (message "offset=%S" offset)
+    (when offset
+      (let ((diff (- (current-column) (current-indentation))))
+        (setq offset (max 0 offset))
+        (indent-line-to offset)
+        (if (> diff 0) (forward-char diff))
 
-     ) ; cond
+        (when (and (string= web-mode-engine "mason")
+                   (= offset 0)
+                   (eq char ?\%))
+          (web-mode-highlight-region (line-beginning-position) (line-end-position)))
 
-;;    (message "after=%S" web-mode-expand-previous-state)
+        ) ;let
+      ) ;when
 
     ))
 
-(defun web-mode-block-select ()
-  "Select the current block."
-  (interactive)
-  (let (beg)
-    (setq beg (web-mode-block-beginning-position (point)))
-    (when beg
-      (goto-char beg)
-      (set-mark (point))
-      (web-mode-block-end)
-      (exchange-point-and-mark)
-      )
-    beg))
-
-(defun web-mode-tag-select ()
-  "Select the current HTML tag."
-  (interactive)
-  (let (beg)
-    (setq beg (web-mode-tag-beginning-position (point)))
-    (when beg
-      (goto-char beg)
-      (set-mark (point))
-      (web-mode-tag-end)
-      (exchange-point-and-mark)
-      )
-    beg))
-
-(defun web-mode-element-content-select ()
-  "Select the content of a HTML element."
-  (interactive)
-  (let (pos beg end)
-    (web-mode-element-select)
-    (when mark-active
-      (setq pos (point))
-      (deactivate-mark)
-      (web-mode-tag-match)
-      (setq end (point))
+(defun web-mode-block-is-control (pos)
+  "web-mode-block-is-control"
+  (save-excursion
+    (let (control state controls pair)
       (goto-char pos)
-      (web-mode-tag-end)
-      (set-mark (point))
-      (goto-char end)
-      (exchange-point-and-mark)
+      (setq controls (web-mode-block-controls-get pos))
+      (setq pair (car controls))
+      (cond
+       ((eq (car pair) 'inside)
+        )
+       ((eq (car pair) 'open)
+        (setq state t
+              control (cdr pair)))
+       ((eq (car pair) 'close)
+        (setq state nil
+              control (cdr pair)))
+       ) ;cond
+      ;;      (message "engine=%S control=%S state=%S" web-mode-engine control state)
+      (if control (cons control state) nil)
       )))
 
-(defun web-mode-element-select ()
-  "Select the current HTML element (including opening and closing tags)."
-  (interactive)
-  (let (type (pos (point)))
-    (setq type (get-text-property pos 'tag-type))
-    (if type
+;; TODO : prendre en compte le debut de la zone 'part-token -> html
+(defun web-mode-markup-indentation-origin ()
+  "web-mode-indentation-origin-pos"
+  (let ((continue t) pos)
+    (while continue
+      (forward-line -1)
+      (back-to-indentation)
+      (setq continue (not (bobp)))
+      (when (or (get-text-property (point) 'tag-beg)
+                (and (get-text-property (point) 'block-beg)
+                     (web-mode-block-is-control (point))
+                     (not (looking-at-p "{% comment"))))
+        (setq continue nil
+              pos (point))
+        )
+      ) ;while
+;;    (message "indent-origin=%S" pos)
+    pos
+    ))
+
+(defun web-mode-markup-indentation (pos)
+  "markup indentation"
+  (save-excursion
+    (goto-char pos)
+    (let ((offset 0) beg ret)
+      (setq beg (web-mode-markup-indentation-origin))
+      (when beg
+        (goto-char beg)
+        (setq ret (web-mode-element-is-opened beg pos))
         (cond
-         ((member type '(start void))
-          (web-mode-tag-beginning)
-          (set-mark (point))
-          (web-mode-tag-match)
-          (web-mode-tag-end)
-          (exchange-point-and-mark))
+         ((null ret)
+          (setq offset (current-indentation)))
+         ((eq ret t)
+          (setq offset (+ (current-indentation) web-mode-markup-indent-offset)))
          (t
-          (web-mode-tag-match)
-          (set-mark (point))
-          (web-mode-tag-match)
-          (web-mode-tag-end)
-          (exchange-point-and-mark))
-         );cond
-      (web-mode-element-parent)
-      (unless (= (point) pos) (web-mode-element-select))
-      );if
-    ))
+          (setq offset ret))
+         ) ;cond
+        ) ;when
+      offset)))
 
-(defun web-mode-element-vanish ()
-  "Vanish the current HTML element. The content of the element is kept."
+;; state=t <=> start tag
+(defun web-mode-element-is-opened (pos limit)
+  "Is there any HTML element without a closing tag ?"
   (interactive)
-  (let (type (pos (point)) start-b start-e end-b end-e)
-    (setq type (get-text-property pos 'tag-type))
-    (when type
+  (let (tag
+        last-tag
+        tag-pos block-pos
+        state
+        n
+        ret
+        (continue t)
+        (buffer (current-buffer))
+        (h (make-hash-table :test 'equal))
+        (h2 (make-hash-table :test 'equal))
+        ctrl)
+    (while continue
+      (setq ctrl nil
+            last-tag nil)
+      (when (or (and (get-text-property pos 'tag-beg)
+                     (member (get-text-property pos 'tag-type) '(start end)))
+                (and (get-text-property pos 'block-beg)
+;;                     (progn (message "pos=%S" pos) t)
+                     (setq ctrl (web-mode-block-is-control pos))))
+;;        (message "ctrl=%S" ctrl)
+        (if ctrl
+            (setq tag (car ctrl)
+                  state (cdr ctrl))
+          (setq tag (get-text-property pos 'tag-name)
+                state (eq (get-text-property pos 'tag-type) 'start))
+          (if (null state) (setq last-tag (cons tag pos)))
+          )
+;;        (message "pos=%S tag=%S state=%S" pos tag state)
+        (setq n (gethash tag h 0))
+        (if (null state)
+            (progn
+              (when (> n 0) (puthash tag (1- n) h))
+              (puthash tag (1- n) h2))
+          (puthash tag (1+ n) h)
+          (puthash tag (1+ n) h2))
+        ) ;when
+      (setq pos (1+ pos))
+      (when (null tag-pos)
+        (setq tag-pos (next-single-property-change pos 'tag-beg buffer limit)))
+      (when (null block-pos)
+        (setq block-pos (next-single-property-change pos 'block-beg buffer limit))
+;;        (message "block-pos=%S limit=%S" block-pos limit)
+        )
       (cond
-       ((member type '(void))
-        (web-mode-element-kill)
-        (set-mark (point))
-        (web-mode-tag-match)
-        (web-mode-tag-end)
-        (exchange-point-and-mark))
-       ((member type '(start))
-        (setq start-b (web-mode-tag-beginning-position)
-              start-e (web-mode-tag-end-position))
-        (when (web-mode-tag-match)
-          (setq end-b (web-mode-tag-beginning-position)
-                end-e (web-mode-tag-end-position)))
+       ((and (null tag-pos)
+             (null block-pos))
+        (setq pos nil)
+        )
+       ((or (null block-pos)
+            (< tag-pos block-pos))
+        (setq pos tag-pos)
+        (setq tag-pos nil)
         )
        (t
-        (setq end-b (web-mode-tag-beginning-position)
-              end-e (web-mode-tag-end-position))
-        (when (web-mode-tag-match)
-          (setq start-b (web-mode-tag-beginning-position)
-                start-e (web-mode-tag-end-position)))
-        );t
-       );cond
-      (when (and start-b end-b)
-        (goto-char end-b)
-        (delete-region end-b (1+ end-e))
-        (delete-blank-lines)
-        (goto-char start-b)
-        (delete-region start-b (1+ start-e))
-        (delete-blank-lines)
-        (web-mode-buffer-indent)
+        (setq pos block-pos)
+        (setq block-pos nil)
         )
-;;        (message "start %S %S - end %S %S" start-b start-e end-b end-e))
-      );when
-    ))
-
-(defun web-mode-element-kill ()
-  "Kill the current HTML element."
-  (interactive)
-  (web-mode-element-select)
-  (when mark-active
-    (kill-region (region-beginning) (region-end))))
-
-(defun web-mode-block-kill ()
-  "Kill the current block."
+       )
+      (when (or (null pos)
+                (>= pos limit))
+        (setq continue nil))
+      ) ;while
+;;    (message "hashtable=%S" h)
+    (maphash (lambda (k v) (if (> v 0) (setq ret t))) h)
+    (when (and (null ret)
+               last-tag
+               (> (hash-table-count h2) 1)
+               (< (gethash (car last-tag) h2) 0))
+;;      (message "last-tag=%S" last-tag)
+      (save-excursion
+        (goto-char (cdr last-tag))
+        (web-mode-tag-match)
+        (when (not (= (point) (cdr last-tag)))
+          (setq n (point))
+          (back-to-indentation)
+          (if (= n (point)) (setq ret (current-indentation))))
+        ))
+    ret))
+;; :opened-blocks :col-num :inline-pos
+(defun web-mode-ruby-indentation (pos line initial-column language-offset limit)
+  "Calc indent column."
   (interactive)
-  (web-mode-block-select)
-  (when mark-active
-    (kill-region (region-beginning) (region-end))))
+  (unless limit (setq limit nil))
+  (let (h out prev-line prev-indentation ctx)
+    (setq ctx (web-mode-count-opened-brackets pos "ruby" limit))
+    (if (plist-get ctx :inline-pos)
+        (setq out (plist-get ctx :col-num))
+      (setq h (web-mode-previous-line pos limit))
+      (setq out initial-column)
+      (when h
+        (setq prev-line (car h))
+        (setq prev-indentation (cdr h))
+        (cond
+         ((string-match-p "^\\(end\\|else\\|elsif\\|when\\)" line)
+          (setq out (- prev-indentation language-offset))
+          )
+         ((string-match-p "\\(when\\|if\\|else\\|elsif\\|unless\\|for\\|while\\|def\\|class\\)" prev-line)
+          (setq out (+ prev-indentation language-offset))
+          )
+         (t
+          (setq out prev-indentation)
+          )
+         )
+        ) ;when
+      ) ;if
+    out))
 
-(defun web-mode-element-clone ()
-  "Clone the current HTML element."
+(defun web-mode-python-indentation (pos line initial-column language-offset limit)
+  "Calc indent column."
   (interactive)
-  (let ((offset 0))
-    (web-mode-element-select)
-    (when mark-active
-      (save-excursion
-        (goto-char (region-beginning))
-        (setq offset (current-column)))
-      (kill-region (region-beginning) (region-end))
-      (yank)
-      (newline)
-      (indent-line-to offset)
-      (yank))))
+  (unless limit (setq limit nil))
+  (let (h out prev-line prev-indentation ctx)
+    (setq h (web-mode-previous-line pos limit))
+    (setq out initial-column)
+    (when h
+      (setq prev-line (car h))
+      (setq prev-indentation (cdr h))
+      (cond
+       ((string-match-p "^\\(pass\\|else\\|elif\\|when\\)" line)
+        (setq out (- prev-indentation language-offset))
+        )
+       ((string-match-p "\\(if\\|else\\|elif\\|for\\|while\\)" prev-line)
+        (setq out (+ prev-indentation language-offset))
+        )
+       (t
+        (setq out prev-indentation)
+        )
+       ) ;cond
+      ) ;when
+    out))
 
-(defun web-mode-element-rename ()
-  "Rename the current HTML element."
+(defun web-mode-asp-indentation (pos line initial-column language-offset limit)
+  "Calc indent column."
   (interactive)
-  (save-excursion
-    (let (pos tag-name)
-      (setq tag-name (read-from-minibuffer "Tag name? "))
-      (when (and (> (length tag-name) 0)
-                 (web-mode-element-beginning)
-                 (looking-at "<\\([[:alnum:]]+\\)"))
-        (setq pos (point))
-        (unless (web-mode-is-void-element)
-            (save-match-data
-              (web-mode-tag-match)
-              (if (looking-at "</[ ]*\\([[:alnum:]]+\\)")
-                  (replace-match (concat "</" tag-name))
-                )))
-        (goto-char pos)
-        (replace-match (concat "<" tag-name))
-        (web-mode-scan-at-pos)
-        ))))
+  (unless limit (setq limit nil))
+  (let (h out prev-line prev-indentation)
+    (setq h (web-mode-previous-line pos limit))
+    (setq out initial-column)
+    (when h
+      (setq prev-line (car h))
+      (setq prev-indentation (cdr h))
+      (cond
+       ;; ----------------------------------------------------------------------
+       ;; unindent
+       ((string-match-p "\\<\\(\\(end \\(if\\|function\\|class\\|sub\\|with\\)\\)\\|else\\|elseif\\|next\\|loop\\)\\>" line)
+        (setq out (- prev-indentation language-offset)))
+       ;; ----------------------------------------------------------------------
+       ;; select case statement
+       ((string-match-p "\\<\\(select case\\)\\>" line)
+        (setq out (- prev-indentation 0)))
+       ((string-match-p "\\<\\(end select\\)" line)
+        (setq out (- prev-indentation (* 2 language-offset))))
+       ((and (string-match-p "\\<\\(case\\)\\>" line) (not (string-match-p "\\<\\(select case\\)\\>" prev-line)))
+        (setq out (- prev-indentation language-offset)))
+       ;; ----------------------------------------------------------------------
+       ;; do nothing
+       ((string-match-p "\\<\\(\\(end \\(if\\|function\\|class\\|sub\\|select\\|with\\)\\)\\|loop\\( until\\| while\\)?\\)\\>" prev-line)
+        (setq out (+ prev-indentation 0)))
+       ;; indent
+       ((string-match-p "\\<\\(\\(select \\)?case\\|else\\|elseif\\|unless\\|for\\|class\\|with\\|do\\( until\\| while\\)?\\|while\\|\\(public \\|private \\)?\\(function\\|sub\\|class\\)\\)\\>" prev-line)
+        (setq out (+ prev-indentation language-offset)))
+       ;; single line if statement
+       ((string-match-p "\\<if\\>.*\\<then\\>[ \t]*[[:alpha:]]+" prev-line)
+        (setq out (+ prev-indentation 0)))
+       ;; normal if statement
+       ((string-match-p "\\<\\if\\>" prev-line)
+        (setq out (+ prev-indentation language-offset)))
+       (t
+        (setq out prev-indentation))
+       )
+      ) ;when
+    out
+    ))
 
-(defun web-mode-current-trimmed-line ()
-  "Line at point, trimmed."
-  (web-mode-trim (buffer-substring-no-properties
-                  (line-beginning-position)
-                  (line-end-position))))
+(defun web-mode-previous-line (pos limit)
+  "Previous line"
+  (save-excursion
+    (let (beg end line (continue t))
+      (goto-char pos)
+      (while continue
+        (forward-line -1)
+        (setq end (line-end-position))
+        (setq line (buffer-substring-no-properties (point) end))
+        (when (or (not (string-match-p "^[ \t]*$" line))
+                  (bobp)
+                  (<= (point) limit))
+          (setq continue nil))
+        )
+      (if (<= (point) limit)
+          ;;todo : affiner (le + 3 n est pas générique cf. <?php <% <%- etc.)
+          (setq beg (if (< (+ limit 3) end) (+ limit 3) end))
+        (setq beg (line-beginning-position))
+        ) ;if
+      (setq line (buffer-substring-no-properties beg end))
+      ;;      (message "line=%s" line)
+      (cons line (current-indentation))
+      )))
 
-(defun web-mode-trim (string)
-  "Remove white spaces in beginning and ending of STRING."
-  (replace-regexp-in-string "\\`[ \t\n]*" "" (replace-regexp-in-string "[ \t\n]*\\'" "" string)))
+(defun web-mode-translate-backward (pos regexp language limit)
+  "translate left"
+  (setq pos (web-mode-translate-backward-pos pos regexp language limit))
+  (if pos (goto-char pos) nil)
+  )
 
-(defun web-mode-is-void-element (&optional tag)
-  "Test if tag is a void tag."
-  (if tag
-      (car (member (downcase tag) web-mode-void-elements))
-    (eq (get-text-property (point) 'tag-type) 'void)
-    ))
+(defun web-mode-translate-backward-pos (pos regexp language limit)
+  "web-mode-search-backward-at-same-depth-pos"
+  (save-excursion
+    (goto-char pos)
+    (let ((continue t) searcher depth (i 0))
+      (setq depth (web-mode-bracket-depth (point) language limit))
+;;      (message "depth=%S" depth)
+      (setq i (1+ i))
+      (if (> (length regexp) 3)
+          (setq searcher 'web-mode-rsb)
+        (setq searcher 'web-mode-sb))
+      (while continue
+        (cond
+         ((> i 200)
+          (setq continue nil
+                pos nil)
+          (message "*** dangerous loop (translate-backward) ***")
+          )
+         ((not (funcall searcher regexp limit))
+          (setq continue nil
+                pos nil)
+          )
+         ((= depth (web-mode-bracket-depth (point) language limit))
+          (setq continue nil
+                pos (point))
+          )
+         ) ;cond
+        ) ;while
+;;      (message "%S: %S" regexp pos)
+      pos)))
 
-(defun web-mode-fold-or-unfold ()
-  "Toggle folding on an HTML element or a control block."
+(defun web-mode-bracket-depth (pos language &optional limit)
+  "Count opened brackets at POS."
   (interactive)
-  (web-mode-with-silent-modifications
-   (save-excursion
-     (let (beg-inside beg-outside end-inside end-outside overlay overlays regexp)
-       (back-to-indentation)
-       (setq overlays (overlays-at (point)))
-       (cond
-        ;; *** unfolding
-        (overlays
-         (setq overlay (car overlays))
-         (setq beg-inside (overlay-start overlay)
-               end-inside (overlay-end overlay))
-         (remove-overlays beg-inside end-inside)
-         (put-text-property beg-inside end-inside 'invisible nil)
-         )
-        ;; *** tag folding
-        ((eq (get-text-property (point) 'tag-type) 'start)
-         (setq beg-outside (point))
-         (web-mode-tag-end)
-         (setq beg-inside (point))
-         (goto-char beg-outside)
-         (when (web-mode-tag-match)
-           (setq end-inside (point))
-           (web-mode-tag-end)
-           (setq end-outside (point)))
-         )
-        ;; *** block folding
-        ((cdr (web-mode-is-active-block (point)))
-         (setq beg-outside (point))
-         (web-mode-block-end)
-         (setq beg-inside (point))
-         (goto-char beg-outside)
-         (when (web-mode-tag-match)
-           (setq end-inside (point))
-           (web-mode-block-end)
-           (setq end-outside (point)))
-         )
-        );cond
-       (when end-outside
-         ;;          (message "beg-out(%d) beg-in(%d) end-in(%d) end-out(%d)" beg-outside beg-inside end-inside end-outside)
-         (setq overlay (make-overlay beg-outside end-outside))
-         (overlay-put overlay 'face 'web-mode-folded-face)
-         (put-text-property beg-inside end-inside 'invisible t)
-         )
-       ))))
+  (unless limit (setq limit nil))
+  (save-excursion
+    (goto-char pos)
+    (let ((assoc (make-hash-table :test 'equal))
+          (char nil)
+          (continue t)
+          (regexp "[\]\[}{)(]"))
+      (while (and continue (re-search-backward regexp limit t))
+        (setq char (aref (match-string-no-properties 0) 0))
+        (cond
+         ((web-mode-is-comment-or-string))
+         ((member char '(?\{ ?\( ?\[))
+          (puthash char (1+ (gethash char assoc 0)) assoc))
+         (t ;;(member char '(?\} ?\) ?\]))
+          (cond
+           ((eq char ?\)) (setq char ?\())
+           ((eq char ?\}) (setq char ?\{))
+           (t             (setq char ?\[)))
+          (puthash char (1- (gethash char assoc 0)) assoc))
+         ) ;cond
+;;        (message "(%S) %c : %S" (point) char (gethash char assoc 0))
+        ) ;while
+      (+ (gethash ?\( assoc 0)
+         (gethash ?\{ assoc 0)
+         (gethash ?\[ assoc 0))
+      )))
 
-(defun web-mode-toggle-comments ()
-  "Toggle comments visbility"
+;; (plist-get ctx :block-beg)
+;; :opened-blocks :col-num :inline-pos
+;;                         cddr
+(defun web-mode-bracket-indentation (pos initial-column language-offset language &optional limit)
+  "Calc indent column."
   (interactive)
+  (unless limit (setq limit nil))
   (save-excursion
-    (if web-mode-comments-invisible
-        (remove-overlays))
-    (setq web-mode-comments-invisible (null web-mode-comments-invisible))
-    (let ((continue t)
-          (pos (point-min))
-          (visibility web-mode-comments-invisible)
-          overlay end)
+    (let (offset n first-char block-info col block-column (continue t))
+      (goto-char pos)
+      (setq first-char (char-after)
+            block-column initial-column)
+;;      (message "first-char=%c" first-char)
       (while continue
-        (setq pos (next-single-property-change pos 'face))
-        (if (null pos)
-            (setq continue nil)
-          (when (eq (get-text-property pos 'face) 'web-mode-comment-face)
-            (setq end (next-single-property-change pos 'face))
-            (put-text-property pos end 'invisible visibility)
-            (when visibility
-              (setq overlay (make-overlay pos end)))
-            (goto-char pos)
-            )
+        (forward-line -1)
+        (back-to-indentation)
+        (cond
+         ((or (> limit (point))
+              (bobp))
+          (setq continue nil)
+          )
+         ((and (= (current-indentation) initial-column)
+               (not (eolp)))
+          (setq continue nil)
+          (setq limit (point))
           )
+         ) ;cond
+        ) ;while
+      (goto-char pos)
+      (setq block-info (web-mode-count-opened-brackets pos language limit))
+;;      (message "%S" block-info)
+      (setq col initial-column)
+      (cond
+       ((plist-get block-info :inline-arg) ;;lsp
+        (cond
+         ((numberp (plist-get block-info :inline-arg))
+          (setq col (+ (plist-get block-info :inline-arg) (plist-get block-info :col-num))))
+;;         ((string= (plist-get block-info :inline-arg) "loop")
+;;          (setq col (+ (plist-get block-info :col-num) 5)))
+         (t
+          (setq col (+ (plist-get block-info :col-num) web-mode-code-indent-offset)))
+         )
         )
-      );let
-    ))
-
-(defun web-mode-is-single-line-block (pos)
-  "Is block at POS spread on a single line ?"
-  (= (web-mode-line-number (web-mode-block-beginning-position pos))
-     (web-mode-line-number (web-mode-block-end-position pos))))
+       ((plist-get block-info :inline-pos)
+        (setq col (plist-get block-info :col-num)))
+       (t
+        (setq n (plist-get block-info :opened-blocks))
+        (setq col initial-column)
+        (when (member first-char '(?\} ?\) ?\]))
+          (setq n (1- n)))
+        (setq col (+ initial-column (* n language-offset)))
+        ) ;t
+       ) ;cond
+      (if (< col block-column) block-column col)
+      )))
 
-(defun web-mode-comment-or-uncomment ()
-  "Comment or uncomment line(s), block or region at POS."
-  (interactive)
-;;  (message "%S" (point))
+(defun web-mode-count-opened-blocks (pos &optional limit)
+  "Count opened opened control blocks at POS."
   (save-excursion
-    (unless mark-active
-      (skip-chars-forward "[:space:]" (line-end-position)))
-    (if (web-mode-is-comment)
-	(web-mode-uncomment (point))
-      (web-mode-comment (point))))
-;;  (message "%S" (point))
-  (web-mode-scan-region (point-min) (point-max))
-  )
+    (goto-char pos)
+    (let ((continue t) pair controls control type (counter 0))
+      (when (null limit)
+        (cond
+         ((get-text-property pos 'part-side)
+          (setq limit (web-mode-part-beginning-position pos)))
+         ((get-text-property pos 'block-side)
+          (setq limit (web-mode-block-beginning-position pos)))
+         ) ;cond
+        ) ;when
+      (while continue
+        (cond
+         ((bobp)
+          (setq continue nil))
+         ((not (web-mode-block-previous))
+          (setq continue nil)
+          )
+         ((null (web-mode-block-controls-get (point)))
+          )
+         (t
+          (setq controls (web-mode-block-controls-get (point)))
+          (setq pair (car controls))
+          (cond
+           ((eq (car pair) 'open)
+            (setq counter (1+ counter)))
+           ((eq (car pair) 'inside)
+            )
+           (t
+            (setq counter (1- counter)))
+           )
+          ) ;t
+         ) ;cond
+        ) ;while
+      (if (>= counter 0) counter 0)
+      )))
 
-(defun web-mode-comment (pos)
-  "Comment line(s) at point."
+
+(defun web-mode-count-opened-brackets (pos language &optional limit)
+  "Count opened brackets at POS."
   (interactive)
-;;  (message "pt=%S" pos)
+  (unless limit (setq limit nil))
   (save-excursion
-    (let (ctx language sel beg end tmp block-side single-line-block)
-
-      (setq block-side (get-text-property pos 'block-side))
-      (setq single-line-block (web-mode-is-single-line-block pos))
+    (goto-char pos)
+    (let ((continue t)
+          (match "")
+          (switch-level 0)
+          (queues (make-hash-table :test 'equal))
+          (opened-blocks 0)
+          (col-num 0)
+          (num-opened 0)
+          regexp
+          close-char n queue inline-pos inline-checked inline-arg char lines reg-end)
 
       (cond
+       ((string= language "css")
+        (setq regexp "[\]\[}{)(]"))
+       ((string= language "lsp")
+        (setq regexp "[)(]"))
+       (t
+        (setq regexp "[\]\[}{)(]\\|[ ;\t]\\(switch\\)"))
+       )
 
-       ((and block-side
-             (string= web-mode-engine "django")
-             single-line-block)
-        (web-mode-comment-django-block pos)
-        )
+;;      (message "limit=%S" limit)
+      (while (and continue (re-search-backward regexp limit t))
+;;        (message "%S: %c" (point) (char-after))
+        (unless (web-mode-is-comment-or-string)
+          (setq match (match-string-no-properties 0))
+;;          (message "match=%S" match)
+          (when (> (length match) 1)
+;;            (message "match=%S" (match-string-no-properties 0))
+            (skip-chars-forward "[ \t]")
+            (setq match (replace-regexp-in-string "\\`[ ;\t]*" "" (replace-regexp-in-string "[ ]*\\'" "" match)))
+            )
+          (setq char (aref match 0))
+;;          (message "match:%S" match)
 
-       ((and block-side
-             (string= web-mode-engine "dust")
-             single-line-block)
-        (web-mode-comment-dust-block pos)
-        )
+;;          (when (member char '(?\{ ?\( ?\[ ?\} ?\) ?\])) (message "(%S) c=%c" (point) char))
 
-       ((and block-side
-             (string= web-mode-engine "erb")
-             single-line-block)
-        (web-mode-comment-erb-block pos)
-        )
+          (cond
 
-       ((and block-side
-             (string= web-mode-engine "aspx")
-             single-line-block)
-        (web-mode-comment-aspx-block pos)
-        )
+           ((member char '(?\{ ?\( ?\[))
+            (cond
+             ((eq char ?\() (setq close-char ?\)))
+             ((eq char ?\{) (setq close-char ?\}))
+             ((eq char ?\[) (setq close-char ?\])))
 
-       ((and block-side
-             (string= web-mode-engine "jsp")
-             single-line-block)
-        (web-mode-comment-jsp-block pos)
-        )
+            (setq queue (gethash char queues nil))
+            (setq queue (push (cons (point) (web-mode-line-number)) queue))
+            (puthash char queue queues)
+;;            (message "%c queue=%S" char queue)
+            (setq queue (gethash close-char queues nil))
+            (setq n (length queue))
+            (cond
+             ((> n 0)
+              (setq queue (cdr queue))
+              (puthash close-char queue queues)
+              ;;(message "%c queue=%S" close-char queue)
+              (setq queue (gethash char queues nil))
+              (setq queue (cdr queue))
+              (puthash char queue queues)
+;;              (message "(%S) %c queue=%S" (point) char queue)
+              )
+             ((= n 0)
+              (setq num-opened (1+ num-opened))
+;;              (message "num-opened=%S %S" num-opened (point))
+              )
+             )
 
-       ((and block-side
-             (string= web-mode-engine "go")
-             single-line-block)
-        (web-mode-comment-go-block pos)
-        )
+            (when (and (= num-opened 1) (null inline-checked))
+              (setq inline-checked t)
+;;              (message "la%S" (point))
+              (when (not (web-mode-is-void-after (1+ (point)))) ;(not (looking-at-p ".[ ]*$"))
+                (setq inline-pos t
+                      col-num (1+ (current-column)))
+                (when (string= language "lsp")
+                  (cond
+                   ((looking-at "(\\(let\\|when\\|def\\|lambda\\|with\\)")
+                    (setq inline-arg (match-string-no-properties 1)))
+                   ((looking-at "(\\([[:alpha:]-]+[ ]+\\).+$")
+                    (setq inline-arg (length (match-string-no-properties 1))))
+                   )
+                  ;;                  (message "pos=%S %S" (point) inline-arg)
+                  )
+                (when (looking-at ".[ ]+")
+                  (setq col-num (+ col-num (1- (length (match-string-no-properties 0)))))
+                  )
+                )
+              )
+;;            (message "%c queue=%S" char queue)
+            ) ;case (?\{ ?\( ?\[)
+
+           ((member char '(?\} ?\) ?\]))
+            (setq queue (gethash char queues nil))
+            (setq queue (push (point) queue))
+            (puthash char queue queues)
+;;            (message "%c queue=%S" char queue)
+            )
+
+           ((and (string= match "switch")
+                 (looking-at-p "switch[ ]*("))
+;;            (message "pos=%S" (point))
+;;            (setq case-num 0)
+;;            (setq is-breaked nil)
+            ;;            (message "switch=%S" (match-end 1))
+;;            (message "ln=%S" language)
+            (let (tmp)
+              (when (null reg-end)
+                (cond
+                 ((member language '("css" "javascript"))
+                  (setq reg-end (web-mode-part-end-position pos))
+;;                  (message "reg-end%S" reg-end)
+                  )
+                 (t
+                  (setq reg-end (web-mode-block-end-position pos))
+                  )
+                 )
+                ) ;when
+;;              (message "reg-end=%S" reg-end)
+              (setq tmp (web-mode-bracket-block-end-position (point) reg-end))
+              (when (and tmp (< pos tmp))
+;;                (message "bol(%S) is inside switch(%S)" pos (point))
+                (setq switch-level (1+ switch-level))
+                )
+              )
+            ) ;case switch
+
+           ) ;cond
+
+          ) ;unless
+        ) ;while
+
+      ;;      (unless inline-pos
+      ;;(message "%S" queues)
+      (maphash
+       (lambda (char queue)
+         (when (member char '(?\{ ?\( ?\[))
+           ;;             (message "%c : " char queue)
+           (dolist (pair queue)
+             ;;               (message "   %S" pair)
+             (if (not (web-mode-is-void-after (1+ (car pair))))
+                 ()
+               (setq n (cdr pair))
+               (unless (member n lines)
+                 (push n lines))
+               ) ;if
+             ) ;dolist
+           ) ;when
+         )
+       queues)
+
+      (setq opened-blocks (length lines)) ;; il faut calculer opened-blocks meme lorsque inline-pos pour code-depth
+
+      (goto-char pos)
 
-       ((and block-side
-             (string= web-mode-engine "php")
-             single-line-block)
-        (web-mode-comment-php-block pos)
+      (when (and (> switch-level 0)
+                 (not (looking-at-p "\\(case[ ]\\|default[ :]\\)")))
+        (setq opened-blocks (+ opened-blocks switch-level)))
+
+      (when (member language '("jsx"))
+        (setq opened-blocks (+ opened-blocks (web-mode-count-opened-blocks pos))))
+
+      (list :opened-blocks opened-blocks
+            :col-num col-num
+            :inline-pos inline-pos
+            :inline-arg inline-arg)
+
+      )))
+
+(defun web-mode-bracket-block-end-position (pos limit)
+  "web-mode-blk-end-pos"
+  (save-excursion
+    (goto-char pos)
+    (setq pos nil)
+;;    (message "limit=%S pos=%S" limit (point))
+    (when (web-mode-sf "{" limit)
+      (backward-char)
+;;      (message "pos=%S" (point))
+      (when (web-mode-closing-paren limit)
+        (setq pos (point))
         )
+      )
+    )
+  pos)
 
-       (t
+(defun web-mode-is-void-after (pos)
+  "Only spaces or comment after pos"
+  (save-excursion
+    (goto-char pos)
+;;    (message "pos=%S" pos)
+    (let ((eol (line-end-position)) (continue t) c (ret t) part-side)
+      (setq part-side (or (member web-mode-content-type '("javascript" "css"))
+                          (not (null (get-text-property pos 'part-side)))))
+      (while continue
+        (setq c (char-after pos))
+;;        (message "%S c='%c'" pos c)
+        (cond
+         ((member c '(?\s ?\n)) )
+         ((and part-side (eq (get-text-property pos 'part-token) 'comment)) )
+         ((and part-side (get-text-property pos 'block-side)) )
+         ((and (not part-side) (eq (get-text-property pos 'block-token) 'comment)) )
+         (t (setq ret nil
+                  continue nil))
+         )
+        (when continue
+          (setq pos (1+ pos))
+          (when (>= pos eol) (setq continue nil)))
+        ) ;while
+      ret)))
 
-        (setq ctx (web-mode-point-context
-                   (if mark-active (region-beginning) (line-beginning-position))))
-;;        (message "ctx=%S" ctx)
-        (setq language (plist-get ctx :language))
+(defun web-mode-count-char-in-string (char string)
+  "Count char in string."
+  (let ((n 0))
+    (dotimes (i (length string))
+      (if (eq (elt string i) char)
+          (setq n (1+ n))))
+    n))
 
-        (if mark-active
-            (progn
-              (setq beg (region-beginning)
-                    end (region-end))
-;;              (message "beg=%S end=%S" beg end)
-              )
-          (if (and (string= language "html")
-                   (progn (back-to-indentation) t)
-                   (get-text-property (point) 'tag-beg))
-              ;;              (progn
-              ;;                (back-to-indentation)
-              (web-mode-element-select)
-            ;;            )
-            (end-of-line)
-            (set-mark (line-beginning-position))
-            );if
-          (setq beg (region-beginning)
-                end (region-end))
-          ); if mark-active
+(defun web-mode-mark-and-expand ()
+  "Mark and expand."
+  (interactive)
+  (when (not (eq last-command this-command))
+    (setq web-mode-expand-previous-state nil))
+  (web-mode-mark (point)))
 
-        (when (> (point) (mark))
-          (exchange-point-and-mark))
+;; todo : pb du engine=go ... selection d'un bloc
+(defun web-mode-mark (pos)
+  "Mark at point."
 
-        (if (eq (char-before end) ?\n)
-            (setq end (1- end)))
+  (let ((beg pos) (end pos) prop reg-beg boundaries)
 
-;;        (message "language=%S beg=%S end=%S" language beg end)
-        (setq sel (web-mode-trim (buffer-substring-no-properties beg end)))
-        ;;      (message "[language=%s] sel=%s" language sel)
-        (delete-region beg end)
-        (deactivate-mark)
+    (if mark-active
+        (setq reg-beg (region-beginning))
+      (setq web-mode-expand-initial-pos (point)))
 
-        (cond
+    ;;    (message "regs=%S %S %S %S" (region-beginning) (region-end) (point-min) (point-max))
+    ;;    (message "before=%S" web-mode-expand-previous-state)
 
-         ((string= language "html")
+    (cond
 
-          (cond
-           ((and (= web-mode-comment-style 2) (string= web-mode-engine "django"))
-            (web-mode-insert-and-indent (concat "{# " sel " #}"))
-            )
-           ((and (= web-mode-comment-style 2) (string= web-mode-engine "erb"))
-            (web-mode-insert-and-indent (concat "<%# " sel " %>"))
-            )
-           ((and (= web-mode-comment-style 2) (string= web-mode-engine "aspx"))
-            (web-mode-insert-and-indent (concat "<%-- " sel " --%>"))
-            )
-           ((and (= web-mode-comment-style 2) (string= web-mode-engine "smarty"))
-            (web-mode-insert-and-indent (concat "{* " sel " *}"))
-            )
-           ((and (= web-mode-comment-style 2) (string= web-mode-engine "blade"))
-            (web-mode-insert-and-indent (concat "{{-- " sel " --}}"))
-            )
-           ((and (= web-mode-comment-style 2) (string= web-mode-engine "razor"))
-            (web-mode-insert-and-indent (concat "@* " sel " *@"))
-            )
-           (t
-            (web-mode-insert-and-indent (concat "<!-- " sel " -->"))
-            )
-           )
+     ((and mark-active
+           (= (region-beginning) (point-min))
+           (or (= (region-end) (point-max))
+               (= (1+ (region-end)) (point-max))))
+      (deactivate-mark)
+      (goto-char (or web-mode-expand-initial-pos (point-min)))
+      (setq web-mode-expand-previous-state nil)
+      (recenter))
 
-          )
+     ((and (member (get-text-property pos 'block-token) '(comment string))
+           (not (member web-mode-expand-previous-state '("block-token" "block-body" "block-side"))))
+      (when (eq (get-text-property pos 'block-token) (get-text-property (1- pos) 'block-token))
+        (setq beg (or (previous-single-property-change pos 'block-token) (point-min))))
+      (when (eq (get-text-property pos 'block-token) (get-text-property (1+ pos) 'block-token))
+        (setq end (next-single-property-change pos 'block-token)))
+      (set-mark beg)
+      (goto-char end)
+      (exchange-point-and-mark)
+      (setq web-mode-expand-previous-state "block-token"))
 
-         ((member language '("php" "javascript" "css"))
-          (web-mode-insert-and-indent (concat "/* " sel " */")))
+     ((and (get-text-property pos 'block-side)
+           (not (member web-mode-expand-previous-state '("block-body" "block-side")))
+           (not (member web-mode-engine '(django go)))
+           (setq boundaries (web-mode-in-code-block "{" "}" 'block-side)))
+      (set-mark (car boundaries))
+      (goto-char (cdr boundaries))
+      (exchange-point-and-mark)
+      (setq web-mode-expand-previous-state "block-body"))
 
-         ((member language '("erb"))
-          (web-mode-insert-and-indent (replace-regexp-in-string "^" "#" sel)))
+     ((and (get-text-property pos 'block-side)
+           (not (member web-mode-expand-previous-state '("block-side"))))
+      (set-mark (web-mode-block-beginning-position pos))
+      (goto-char (1+ (web-mode-block-end-position pos)))
+      (exchange-point-and-mark)
+      (setq web-mode-expand-previous-state "block-side"))
 
-         ((member language '("asp"))
-          (web-mode-insert-and-indent (replace-regexp-in-string "^" "''" sel)))
+     ((and (get-text-property pos 'part-token)
+           (not (string= web-mode-expand-previous-state "part-token")))
+      (when (eq (get-text-property pos 'part-token) (get-text-property (1- pos) 'part-token))
+        (setq beg (previous-single-property-change pos 'part-token)))
+      (when (eq (get-text-property pos 'part-token) (get-text-property (1+ pos) 'part-token))
+        (setq end (next-single-property-change pos 'part-token)))
+      (set-mark beg)
+      (goto-char end)
+      (exchange-point-and-mark)
+      (setq web-mode-expand-previous-state "part-token"))
 
-         (t
-          (web-mode-insert-and-indent (concat "/* " sel " */")))
+     ((and (get-text-property pos 'part-side)
+           (not (string= web-mode-expand-previous-state "client-part"))
+           (setq boundaries (web-mode-in-code-block "{" "}" 'part-side)))
+      (set-mark (car boundaries))
+      (goto-char (cdr boundaries))
+      (exchange-point-and-mark)
+      (setq web-mode-expand-previous-state "client-part"))
 
-         );cond
+     ((and (get-text-property pos 'part-side)
+           (not (string= web-mode-expand-previous-state "part-side")))
+      (when (eq (get-text-property pos 'part-side) (get-text-property (1- pos) 'part-side))
+        (setq beg (previous-single-property-change pos 'part-side)))
+      (when (eq (get-text-property pos 'part-side) (get-text-property (1+ pos) 'part-side))
+        (setq end (next-single-property-change pos 'part-side)))
+      (when (eq (char-after beg) ?\n)
+        (setq beg (1+ beg)))
+      (set-mark beg)
+      (goto-char end)
+      (when (looking-back "^[ \t]+")
+        (beginning-of-line))
+      (exchange-point-and-mark)
+      (setq web-mode-expand-previous-state "part-side"))
 
-        );t
-       );cond
+     ((and (get-text-property pos 'tag-attr)
+           (not (member web-mode-expand-previous-state '("html-attr" "html-tag"))))
+      (web-mode-attribute-select pos)
+      (setq web-mode-expand-previous-state "html-attr"))
 
-      )
-    );save-excursion
-;;  (message "%S" (point))
-;;  (goto-char pos)
-  )
+     ((and (get-text-property pos 'tag-name)
+           (not (member web-mode-expand-previous-state '("html-tag" "html-elt" "html-parent"))))
+      (web-mode-tag-select)
+      (setq web-mode-expand-previous-state "html-tag"))
 
-(defun web-mode-looking-at-pos (regexp pos)
-  "Performs a looking-at at POS."
-  (save-excursion
-    (goto-char pos)
-    (looking-at regexp)
-    ))
+     ((and (get-text-property pos 'tag-beg)
+           (string= web-mode-expand-previous-state "html-tag"))
+      (web-mode-element-select)
+      (setq web-mode-expand-previous-state "html-elt"))
 
-(defun web-mode-insert-text-at-pos (text pos)
-  "Insert TEXT at POS."
-  (save-excursion
-    (goto-char pos)
-    (insert text)
-    ))
+     (t
+      (web-mode-element-parent)
+      (if (and reg-beg (= reg-beg (region-beginning)))
+          (progn
+            (mark-whole-buffer)
+            (setq web-mode-expand-previous-state "mark-whole"))
+        (web-mode-element-select)
+        (setq web-mode-expand-previous-state "html-parent"))
+      ) ;t
 
-(defun web-mode-remove-text-at-pos (n &optional pos)
-  "Remove N chars at POS."
-  (unless pos (setq pos (point)))
-  (delete-region pos (+ pos n)))
+     ) ;cond
 
-(defun web-mode-uncomment-erb-block (pos)
-  "Uncomment an erb block."
-  (let (beg end)
-    (setq beg (web-mode-block-beginning-position pos)
-          end (web-mode-block-end-position pos))
-    (web-mode-remove-text-at-pos 1 (+ beg 2))
-    ))
+;;    (message "after=%S\n-----------------------" web-mode-expand-previous-state)
 
-(defun web-mode-comment-erb-block (pos)
-  "Turn an erb block into a comment block."
-  (let (beg end)
-    (setq beg (web-mode-block-beginning-position pos)
-          end (web-mode-block-end-position pos))
-    (web-mode-insert-text-at-pos "#" (+ beg 2))
     ))
 
-(defun web-mode-uncomment-django-block (pos)
-  "Uncomment a django block."
-  (let (beg end)
-    (setq beg (web-mode-block-beginning-position pos)
-          end (web-mode-block-end-position pos))
-    (web-mode-remove-text-at-pos 2 (1- end))
-    (web-mode-remove-text-at-pos 2 beg)
-    ))
+(defun web-mode-block-select ()
+  "Select the current block."
+  (interactive)
+  (let (beg)
+    (setq beg (web-mode-block-beginning-position (point)))
+    (when beg
+      (goto-char beg)
+      (set-mark (point))
+      (web-mode-block-end)
+      (exchange-point-and-mark)
+      )
+    beg))
 
-(defun web-mode-comment-django-block (pos)
-  "Turn a django block into a comment block."
-  (let (beg end)
-    (setq beg (web-mode-block-beginning-position pos)
-          end (web-mode-block-end-position pos))
-    (web-mode-insert-text-at-pos "#" end)
-    (web-mode-insert-text-at-pos "#" (1+ beg))
-    ))
+(defun web-mode-tag-select ()
+  "Select the current HTML tag."
+  (interactive)
+  (let (beg)
+    (setq beg (web-mode-tag-beginning-position (point)))
+    (when beg
+      (goto-char beg)
+      (set-mark (point))
+      (web-mode-tag-end)
+      (exchange-point-and-mark)
+      )
+    beg))
 
-(defun web-mode-uncomment-dust-block (pos)
-  "Uncomment a dust block."
-  (let (beg end)
-    (setq beg (web-mode-block-beginning-position pos)
-          end (web-mode-block-end-position pos))
-    (web-mode-remove-text-at-pos 1 (1- end))
-    (web-mode-remove-text-at-pos 1 (1+ beg))
-    ))
+(defun web-mode-element-content-select ()
+  "Select the content of a HTML element."
+  (interactive)
+  (let (pos beg end)
+    (web-mode-element-select)
+    (when mark-active
+      (setq pos (point))
+      (deactivate-mark)
+      (web-mode-tag-match)
+      (setq end (point))
+      (goto-char pos)
+      (web-mode-tag-end)
+      (set-mark (point))
+      (goto-char end)
+      (exchange-point-and-mark)
+      )))
 
-(defun web-mode-comment-dust-block (pos)
-  "Turn a dust block into a comment block."
-  (let (beg end)
-    (setq beg (web-mode-block-beginning-position pos)
-          end (web-mode-block-end-position pos))
-    (web-mode-insert-text-at-pos "!" end)
-    (web-mode-insert-text-at-pos "!" (1+ beg))
+(defun web-mode-element-select ()
+  "Select the current HTML element (including opening and closing tags)."
+  (interactive)
+  (let (type (pos (point)))
+    (setq type (get-text-property pos 'tag-type))
+    (if type
+        (cond
+         ((member type '(start void))
+          (web-mode-tag-beginning)
+          (set-mark (point))
+          (web-mode-tag-match)
+          (web-mode-tag-end)
+          (exchange-point-and-mark))
+         (t
+          (web-mode-tag-match)
+          (set-mark (point))
+          (web-mode-tag-match)
+          (web-mode-tag-end)
+          (exchange-point-and-mark))
+         ) ;cond
+      (web-mode-element-parent)
+      (unless (= (point) pos) (web-mode-element-select))
+      ) ;if
     ))
 
-(defun web-mode-comment-aspx-block (pos)
-  "Turn a aspx block into a comment block."
-  (let (beg end)
-    (setq beg (web-mode-block-beginning-position pos)
-          end (web-mode-block-end-position pos))
-    (web-mode-insert-text-at-pos "#" end)
-    (web-mode-insert-text-at-pos "#" (1+ beg))
-    ))
+(defun web-mode-element-is-collapsed (&optional pos)
+  "Is the HTML element collapsed ?"
+  (unless pos (setq pos (point)))
+  (let (boundaries ret)
+    (setq boundaries (web-mode-element-boundaries pos))
+    (setq ret (and boundaries
+                   (or (= (car (car boundaries)) (car (cdr boundaries)))
+                       (= (cdr (car boundaries)) (1- (car (cdr boundaries)))))
+                   ))
+;;    (when ret (message "elt(%S) is collapsed" pos))
+    ret))
 
-(defun web-mode-uncomment-aspx-block (pos)
-  "Uncomment a aspx block."
-  (let (beg end)
-    (setq beg (web-mode-block-beginning-position pos)
-          end (web-mode-block-end-position pos))
-    (web-mode-remove-text-at-pos 1 (1- end))
-    (web-mode-remove-text-at-pos 1 (1+ beg))
+(defun web-mode-element-transpose ()
+  "Transpose two HTML elements."
+  (interactive)
+  (let (pos start1 end1 start2 end2)
+    (save-excursion
+      (setq pos (point))
+      (cond
+       ((get-text-property pos 'tag-type)
+        (setq start1 (web-mode-element-beginning-position pos)
+            end1 (1+ (web-mode-element-end-position pos)))
+        )
+       ((setq start1 (web-mode-element-parent-position pos))
+        (setq end1 (1+ (web-mode-element-end-position pos)))
+        )
+       ) ;cond
+      (when (and start1 end1 (> end1 0))
+        (goto-char end1)
+        (unless (get-text-property (point) 'tag-beg)
+          (skip-chars-forward "\n\t "))
+        (when (get-text-property (point) 'tag-beg)
+          (setq start2 (web-mode-element-beginning-position (point))
+                end2 (1+ (web-mode-element-end-position (point))))
+          )
+        )
+;;      (message "start1(%S) end1(%S) start2(%S) end2(%S)"
+;;               start1 end1 start2 end2)
+      (transpose-regions start1 end1 start2 end2)
+      ) ;save-excursion
+    start2
     ))
 
-(defun web-mode-uncomment-jsp-block (pos)
-  "Uncomment a jsp block."
-  (let (beg end)
-    (setq beg (web-mode-block-beginning-position pos)
-          end (web-mode-block-end-position pos))
-    (web-mode-remove-text-at-pos 2 (+ beg 2))
-    ))
+(defun web-mode-element-children-fold-or-unfold (&optional pos)
+  "Fold/Unfold all the children of the current HTML element."
+  (interactive)
+  (unless pos (setq pos (point)))
+  (let (child children)
+    (save-excursion
+      (setq children (reverse (web-mode-element-children-position pos)))
+      (dolist (child children)
+;;        (message "child(%S)" child)
+        (goto-char child)
+        (web-mode-fold-or-unfold)
+        )
+      )))
 
-(defun web-mode-comment-jsp-block (pos)
-  "Turn a jsp block into a comment block."
-  (let (beg end)
-    (setq beg (web-mode-block-beginning-position pos)
-          end (web-mode-block-end-position pos))
-    (web-mode-insert-text-at-pos "--" (+ beg 2))
-    ))
+(defun web-mode-element-mute-blanks ()
+  "Mute blanks."
+  (interactive)
+  (let (pos parent beg end child children elt)
+    (setq pos (point))
+    (save-excursion
+      (when (and (setq parent (web-mode-element-boundaries pos))
+                 (setq child (web-mode-element-child-position (point))))
+        (setq children (reverse (web-mode-element-children-position)))
+;;        (message "%S %S" parent children)
+        ;;        (setq end (car (cdr parent)))
+        ;;        (message "end=%S" end)
+        (goto-char (car (cdr parent)))
+        (dolist (child children)
+          (setq elt (web-mode-element-boundaries child))
+          ;;          (message "child=%S elt=%S" child elt)
+          (when (> (point) (1+ (cddr elt)))
+            ;;(message "%S-->" (point))
+            ;;(message "%S<!--" (1+ (cddr elt)))
+            (when (and (not (eq (get-text-property (point) 'part-token) 'comment))
+                       (not (eq (get-text-property (1+ (cddr elt)) 'part-token) 'comment)))
+              (web-mode-insert-text-at-pos "-->" (point))
+              (web-mode-insert-text-at-pos "<!--" (1+ (cddr elt))))
+            )
+          (goto-char child)
+          )
+        (when (and (> (point) (1+ (cdr (car parent))))
+                   (not (eq (get-text-property (point) 'part-token) 'comment))
+                   (not (eq (get-text-property (1+ (cdr (car parent))) 'part-token) 'comment)))
+          (web-mode-insert-text-at-pos "-->" (point))
+          (web-mode-insert-text-at-pos "<!--" (1+ (cdr (car parent)))))
 
-(defun web-mode-uncomment-go-block (pos)
-  "Uncomment a go block."
-  (let (beg end)
-    (setq beg (web-mode-block-beginning-position pos)
-          end (web-mode-block-end-position pos))
-    (web-mode-remove-text-at-pos 1 (+ beg 2))
-    ))
+        ) ;when
+      )))
 
-(defun web-mode-comment-go-block (pos)
-  "Turn a go block into a comment block."
-  (let (beg end)
-    (setq beg (web-mode-block-beginning-position pos)
-          end (web-mode-block-end-position pos))
-    (web-mode-insert-text-at-pos "/" (+ beg 2))
+(defun web-mode-element-children-position (&optional pos)
+  (unless pos (setq pos (point)))
+  (let ((continue t) (i 0) child children)
+    (save-excursion
+      (when (and (member (get-text-property pos 'tag-type) '(start end))
+                 (setq child (web-mode-element-child-position pos)))
+        (while continue
+          (setq i (1+ i))
+          (cond
+           ((= i 1)
+            (goto-char child)
+            )
+           ((web-mode-element-sibling-next)
+            )
+           (t
+            (setq continue nil)
+            )
+           ) ;cond
+          (when (> i 100)
+            (message "** invalid loop **")
+            (setq continue nil))
+          (when continue
+;;            (message "child(%S)" (point))
+            (setq children (append children (list (point)))))
+          ) ;while
+        ) ;when
+      ) ;save-excursion
+    children
     ))
 
-(defun web-mode-comment-php-block (pos)
-  "Turn a php block into a comment block."
-  (let (beg end)
-    (setq beg (web-mode-block-beginning-position pos)
-          end (web-mode-block-end-position pos))
-    (web-mode-insert-text-at-pos "*/" (- end 1))
-    (web-mode-insert-text-at-pos "/*" (+ beg (if (web-mode-looking-at-pos "<\\?php" beg) 5 3)))
+;; return ((start-tag-beg . start-tag-end) . (end-tag-beg end-tag-end))
+;; car and cdr are the same with void elements
+(defun web-mode-element-boundaries (&optional pos)
+  "pos should be in a tag"
+  (unless pos (setq pos (point)))
+  (let (start-tag-beg start-tag-end end-tag-beg end-tag-end)
+    (save-excursion
+      (cond
+       ((eq (get-text-property pos 'tag-type) 'start)
+        (setq start-tag-beg (web-mode-tag-beginning-position pos)
+              start-tag-end (web-mode-tag-end-position pos))
+        (web-mode-tag-match pos)
+;;        (message "pos=%S point=%S" pos (point))
+        (setq end-tag-beg (point)
+              end-tag-end (web-mode-tag-end-position (point)))
+        )
+       ((eq (get-text-property pos 'tag-type) 'end)
+        (setq end-tag-beg (web-mode-tag-beginning-position pos)
+              end-tag-end (web-mode-tag-end-position pos))
+        (web-mode-tag-match pos)
+        (setq start-tag-beg (point)
+              start-tag-end (web-mode-tag-end-position (point)))
+        )
+       ((eq (get-text-property pos 'tag-type) 'void)
+        (setq start-tag-beg (web-mode-tag-beginning-position pos)
+              start-tag-end (web-mode-tag-end-position pos))
+        (setq end-tag-beg start-tag-beg
+              end-tag-end start-tag-end)
+        )
+       ) ;cond
+      )
+    (if (and start-tag-beg start-tag-end end-tag-beg end-tag-end)
+        (cons (cons start-tag-beg start-tag-end) (cons end-tag-beg end-tag-end))
+      nil)
     ))
 
-(defun web-mode-uncomment (&optional pos)
-  "Uncomment line(s) at point."
+(defun web-mode-element-wrap ()
+  "Wrap current REGION with start and end tags."
   (interactive)
-  (unless pos (setq pos (point)))
-  (let ((beg pos)
-        (end pos)
-        (sub2 "")
-        comment prop)
-
-    (cond
-
-     ((and (get-text-property pos 'block-side)
-           (string= web-mode-engine "django"))
-        (web-mode-uncomment-django-block pos)
+  (let (beg end pos tag sep)
+    (save-excursion
+      (setq tag (read-from-minibuffer "Tag name? "))
+      (setq pos (point))
+      (cond
+       (mark-active
+        (setq beg (region-beginning)
+              end (region-end)))
+       ((get-text-property pos 'tag-type)
+        (setq beg (web-mode-element-beginning-position pos)
+              end (1+ (web-mode-element-end-position pos)))
         )
-
-     ((and (get-text-property pos 'block-side)
-           (string= web-mode-engine "dust"))
-        (web-mode-uncomment-dust-block pos)
+       ((setq beg (web-mode-element-parent-position pos))
+        (setq end (1+ (web-mode-element-end-position pos)))
         )
+       )
+      ;;      (message "beg(%S) end(%S)" beg end)
+      (when (and beg end (> end 0))
+        (setq sep (if (get-text-property beg 'tag-beg) "\n" ""))
+        (web-mode-insert-text-at-pos (concat sep "</" tag ">") end)
+        (web-mode-insert-text-at-pos (concat "<" tag ">" sep) beg)
+        (when (string= sep "\n") (indent-region beg (+ end (* (+ 3 (length tag)) 2))))
+        )
+      ) ;save-excursion
+    (if beg (goto-char beg))
+    beg))
 
-     ((and (get-text-property pos 'block-side)
-           (string= web-mode-engine "erb"))
-        (web-mode-uncomment-erb-block pos)
+(defun web-mode-element-vanish ()
+  "Vanish the current HTML element. The content of the element is kept."
+  (interactive)
+  (let (type (pos (point)) start-b start-e end-b end-e)
+    (setq type (get-text-property pos 'tag-type))
+    (when type
+      (cond
+       ((member type '(void))
+        (web-mode-element-kill)
+        (set-mark (point))
+        (web-mode-tag-match)
+        (web-mode-tag-end)
+        (exchange-point-and-mark))
+       ((member type '(start))
+        (setq start-b (web-mode-tag-beginning-position)
+              start-e (web-mode-tag-end-position))
+        (when (web-mode-tag-match)
+          (setq end-b (web-mode-tag-beginning-position)
+                end-e (web-mode-tag-end-position)))
+        )
+       (t
+        (setq end-b (web-mode-tag-beginning-position)
+              end-e (web-mode-tag-end-position))
+        (when (web-mode-tag-match)
+          (setq start-b (web-mode-tag-beginning-position)
+                start-e (web-mode-tag-end-position)))
+        ) ;t
+       ) ;cond
+      (when (and start-b end-b)
+        (goto-char end-b)
+        (delete-region end-b (1+ end-e))
+        (delete-blank-lines)
+        (goto-char start-b)
+        (delete-region start-b (1+ start-e))
+        (delete-blank-lines)
+        (web-mode-buffer-indent)
         )
+;;        (message "start %S %S - end %S %S" start-b start-e end-b end-e))
+      ) ;when
+    ))
 
-     ((and (get-text-property pos 'block-side)
-           (string= web-mode-engine "aspx"))
-      (web-mode-uncomment-aspx-block pos)
-      )
+(defun web-mode-element-kill ()
+  "Kill the current HTML element."
+  (interactive)
+  (web-mode-element-select)
+  (when mark-active
+    (kill-region (region-beginning) (region-end))))
 
-     ((and (get-text-property pos 'block-side)
-           (string= web-mode-engine "jsp"))
-      (web-mode-uncomment-jsp-block pos)
-      )
+(defun web-mode-block-kill ()
+  "Kill the current block."
+  (interactive)
+  (web-mode-block-select)
+  (when mark-active
+    (kill-region (region-beginning) (region-end))))
 
-     ((and (get-text-property pos 'block-side)
-           (string= web-mode-engine "go"))
-      (web-mode-uncomment-go-block pos)
-      )
+(defun web-mode-element-clone ()
+  "Clone the current HTML element."
+  (interactive)
+  (let ((offset 0))
+    (web-mode-element-select)
+    (when mark-active
+      (save-excursion
+        (goto-char (region-beginning))
+        (setq offset (current-column)))
+      (kill-region (region-beginning) (region-end))
+      (yank)
+      (newline)
+      (indent-line-to offset)
+      (yank))))
 
-     (t
+(defun web-mode-element-rename ()
+  "Rename the current HTML element."
+  (interactive)
+  (save-excursion
+    (let (pos tag-name)
+      (setq tag-name (read-from-minibuffer "Tag name? "))
+      (when (and (> (length tag-name) 0)
+                 (web-mode-element-beginning)
+                 (looking-at "<\\([[:alnum:]]+\\(:?[-][[:alpha:]]+\\)?\\)"))
+        (setq pos (point))
+;;        (message "match=%S" (match-string-no-properties 1))
+        (unless (web-mode-element-is-void)
+            (save-match-data
+              (web-mode-tag-match)
+              (if (looking-at "</[ ]*\\([[:alnum:]]+\\(:?[-][[:alpha:]]+\\)?\\)")
+                  (replace-match (concat "</" tag-name))
+                )))
+        (goto-char pos)
+        (replace-match (concat "<" tag-name))
+;;        (web-mode-scan-at-pos)
+        ))))
 
-      (if (eq (get-text-property pos 'block-token) 'comment)
-          (setq prop 'block-token)
-        (setq prop 'part-token))
+(defun web-mode-current-trimmed-line ()
+  "Line at point, trimmed."
+  (web-mode-trim (buffer-substring-no-properties
+                  (line-beginning-position)
+                  (line-end-position))))
 
-      (if (and (not (bobp))
-               (eq (get-text-property pos prop) (get-text-property (- pos 1) prop)))
-          (setq beg (previous-single-property-change pos prop)))
+(defun web-mode-trim (string)
+  "Remove white spaces in beginning and ending of STRING."
+  (replace-regexp-in-string "\\`[ \t\n]*" "" (replace-regexp-in-string "[ \t\n]*\\'" "" string)))
 
-      (if (and (not (eobp))
-               (eq (get-text-property pos prop) (get-text-property (+ pos 1) prop)))
-          (setq end (next-single-property-change pos prop)))
+;; on regarde le dernier
+(defun web-mode-block-is-open (&optional pos)
+  "web-mode-block-is-open"
+  (unless pos (setq pos (point)))
+  )
 
-      ;;    (message "beg(%d) end(%d)" beg end)
+;; on regarde le premier
+(defun web-mode-block-is-close (&optional pos)
+  "web-mode-block-is-close"
+  (unless pos (setq pos (point)))
+  (and (get-text-property pos 'block-side)
+       (eq (caar (web-mode-block-controls-get pos)) 'close))
+  )
 
-      (when (> (- end beg) 4)
+;; on regarde le premier
+(defun web-mode-block-is-inside (&optional pos)
+  "web-mode-block-is-inside"
+  (unless pos (setq pos (point)))
+  (and (get-text-property pos 'block-side)
+       (eq (caar (web-mode-block-controls-get pos)) 'inside))
+  )
 
-        (setq comment (buffer-substring-no-properties beg end))
-        ;;    (message "before[%s]" comment)
+(defun web-mode-element-is-void (&optional tag)
+  "Test if tag is a void tag."
+  (if tag
+      (car (member (downcase tag) web-mode-void-elements))
+    (eq (get-text-property (point) 'tag-type) 'void)
+    ))
 
-        (setq sub2 (substring comment 0 2))
+(defun web-mode-toggle-current-element-highlight ()
+  "toggle current element highliht"
+  (interactive)
+  (if web-mode-enable-current-element-highlight
+      (progn
+        (web-mode-delete-tag-overlays)
+        (setq web-mode-enable-current-element-highlight nil)
+        (remove-hook 'post-command-hook 'web-mode-highlight-current-element t))
+    (setq web-mode-enable-current-element-highlight t)
+    (add-hook 'post-command-hook 'web-mode-highlight-current-element nil t))
+  )
 
-        (cond
+(defun web-mode-fold-or-unfold (&optional pos)
+  "Toggle folding on an HTML element or a control block."
+  (interactive)
+  (web-mode-with-silent-modifications
+   (save-excursion
+     (if pos (goto-char pos))
+     (let (beg-inside beg-outside end-inside end-outside overlay overlays regexp)
+       (when (looking-back "^[\t ]*")
+         (back-to-indentation))
+       (setq overlays (overlays-at (point)))
+       (cond
+        ;; *** unfolding
+        (overlays
+         (setq overlay (car overlays))
+         (setq beg-inside (overlay-start overlay)
+               end-inside (overlay-end overlay))
+         (remove-overlays beg-inside end-inside)
+         (put-text-property beg-inside end-inside 'invisible nil)
+         )
+        ;; *** tag folding
+        ((member (get-text-property (point) 'tag-type) '(start end))
+         (when (not (web-mode-element-is-collapsed (point)))
+           (web-mode-tag-beginning)
+           (when (eq (get-text-property (point) 'tag-type) 'end)
+             (web-mode-tag-match))
+           (setq beg-outside (point))
+           (web-mode-tag-end)
+           (setq beg-inside (point))
+           (goto-char beg-outside)
+           (when (web-mode-tag-match)
+             (setq end-inside (point))
+             (web-mode-tag-end)
+             (setq end-outside (point)))
+           )
+         )
+        ;; *** block folding
+        ((cdr (web-mode-block-is-control (point)))
+         (setq beg-outside (web-mode-block-beginning-position (point)))
+         (setq beg-inside (1+ (web-mode-block-end-position (point))))
+         (when (web-mode-block-match)
+           (setq end-inside (point))
+           (setq end-outside (1+ (web-mode-block-end-position (point)))))
+         ) ;block-control
+        ) ;cond
+       (when (and beg-inside beg-outside end-inside end-outside)
+         ;;(message "beg-out(%d) beg-in(%d) end-in(%d) end-out(%d)" beg-outside beg-inside end-inside end-outside)
+         (setq overlay (make-overlay beg-outside end-outside))
+         (overlay-put overlay 'font-lock-face 'web-mode-folded-face)
+         (put-text-property beg-inside end-inside 'invisible t)
+         )
+       ))))
 
-         ((member sub2 '("<!" "<%"))
-          (setq comment (replace-regexp-in-string "\\(^<[!%]--[ ]?\\|[ ]?--[%]?>$\\)" "" comment)))
+(defun web-mode-toggle-comments ()
+  "Toggle comments visbility"
+  (interactive)
+  (save-excursion
+    (if web-mode-comments-invisible
+        (remove-overlays))
+    (setq web-mode-comments-invisible (null web-mode-comments-invisible))
+    (let ((continue t)
+          (pos (point-min))
+          (visibility web-mode-comments-invisible)
+          overlay end)
+      (while continue
+        (setq pos (next-single-property-change pos 'font-lock-face))
+        (if (null pos)
+            (setq continue nil)
+          (when (eq (get-text-property pos 'font-lock-face) 'web-mode-comment-face)
+            (setq end (next-single-property-change pos 'font-lock-face))
+            (put-text-property pos end 'invisible visibility)
+            (when visibility
+              (setq overlay (make-overlay pos end)))
+            (goto-char pos)
+            )
+          )
+        )
+      ) ;let
+    ))
 
-         ((string= sub2 "{#")
-          (setq comment (replace-regexp-in-string "\\(^{#[ ]?\\|[ ]?#}$\\)" "" comment)))
+(defun web-mode-is-single-line-block (pos)
+  "Is block at POS spread on a single line ?"
+  (= (web-mode-line-number (web-mode-block-beginning-position pos))
+     (web-mode-line-number (web-mode-block-end-position pos))))
 
-         ((string= sub2 "/*")
-          (setq comment (replace-regexp-in-string "\\(^/\\*[ ]?\\|[ ]?\\*/$\\)" "" comment)))
+(defun web-mode-comment-or-uncomment ()
+  "Comment or uncomment line(s), block or region at POS."
+  (interactive)
+;;  (message "%S" (point))
+  (save-excursion
+    (unless mark-active
+      (skip-chars-forward "[:space:]" (line-end-position)))
+    (if (web-mode-is-comment)
+	(web-mode-uncomment (point))
+      (web-mode-comment (point))))
+;;  (message "%S" (point))
+;;  (web-mode-highlight-region (point-min) (point-max))
+  )
 
-         ((string= sub2 "//")
-          (setq comment (replace-regexp-in-string "\\(^//\\)" "" comment)))
+(defun web-mode-comment (pos)
+  "Comment line(s) at point."
+  (interactive)
+;;  (message "pt=%S" pos)
+  (save-excursion
+    (let (ctx language sel beg end tmp block-side single-line-block)
 
-         )
+      (setq block-side (get-text-property pos 'block-side))
+      (setq single-line-block (web-mode-is-single-line-block pos))
 
-        ;;    (message "after[%s]" comment)
+      (cond
 
-        (delete-region beg end)
-        (web-mode-insert-and-indent comment)
-        (goto-char beg)
-;;        (back-to-indentation)
+       ((and block-side
+             (string= web-mode-engine "django")
+             single-line-block)
+        (web-mode-comment-django-block pos)
+        )
 
-        );;when
+       ((and block-side
+             (string= web-mode-engine "dust")
+             single-line-block)
+        (web-mode-comment-dust-block pos)
+        )
 
-      ))
-    (indent-for-tab-command)
-    ))
+       ((and block-side
+             (string= web-mode-engine "erb")
+             single-line-block)
+        (web-mode-comment-erb-block pos)
+        )
 
-(defun web-mode-snippet-names ()
-  "Return the snippet names."
-  (interactive)
-  (let (codes snippet)
-    (dolist (snippet web-mode-snippets)
-      (add-to-list 'codes (car snippet) t))
-    codes))
+       ((and block-side
+             (string= web-mode-engine "aspx")
+             single-line-block)
+        (web-mode-comment-aspx-block pos)
+        )
 
-(defun web-mode-snippet-insert (code)
-  "Insert snippet."
-  (interactive
-   (list (completing-read
-          "Snippet: " (web-mode-snippet-names))))
-  (let (beg
-        (continue t)
-        (counter 0)
-        end
-        sel
-        snippet
-        (l (length web-mode-snippets))
-        pos)
-    (when mark-active
-      (setq sel (web-mode-trim
-                 (buffer-substring-no-properties
-                  (region-beginning) (region-end))))
-      (delete-region (region-beginning) (region-end)))
-    (while (and continue (< counter l))
-      (setq snippet (nth counter web-mode-snippets))
-      (when (string= (car snippet) code)
-        (setq continue nil))
-      (setq counter (1+ counter)))
-    (when snippet
-      (setq snippet (cdr snippet))
-      (setq beg (point-at-bol))
-      (insert (car snippet))
-      (setq pos (point))
-      (when sel
-        (insert sel)
-        (setq pos (point)))
-      (if (cdr snippet) (insert (cdr snippet)))
-      (setq end (point-at-eol))
-      (unless sel (goto-char pos))
-      (indent-region beg end))
-    ))
+       ((and block-side
+             (string= web-mode-engine "jsp")
+             single-line-block)
+        (web-mode-comment-jsp-block pos)
+        )
 
-(defun web-mode-insert-and-indent (text)
-  "Insert and indent text."
-  (interactive)
-  (let (beg end)
-    (setq beg (point-at-bol))
-    (insert text)
-    (setq end (point-at-eol))
-    (indent-region beg end)))
+       ((and block-side
+             (string= web-mode-engine "go")
+             single-line-block)
+        (web-mode-comment-go-block pos)
+        )
 
-(defun web-mode-tag-match (&optional pos)
-  "Match tag."
-  (interactive)
-  (unless pos (setq pos (point)))
-  (let (init)
-    (goto-char pos)
-    (setq init (point))
-    (when (> (current-indentation) (current-column))
-      (back-to-indentation))
-    (setq pos (point))
-    (cond
-     ((web-mode-is-comment-or-string)
-      (goto-char init))
-     ((and (get-text-property pos 'block-side)
-           (web-mode-block-beginning)
-           (looking-at-p web-mode-active-block-regexp))
-      (funcall web-mode-engine-control-matcher))
-     ((member (get-text-property pos 'tag-type) '(start end))
-      (web-mode-tag-beginning)
-      (web-mode-match-html-tag))
-     (t
-      (goto-char init))
-     )
-    ))
+       ((and block-side
+             (string= web-mode-engine "php")
+             single-line-block)
+        (web-mode-comment-php-block pos)
+        )
 
-(defun web-mode-match-html-tag (&optional pos)
-  "Fetch HTML block."
-  (unless pos (setq pos (point)))
-  (let (tag regexp)
-    (setq tag (get-text-property pos 'tag-name))
-    (setq regexp (concat "</?" tag))
-    (if (eq (get-text-property pos 'tag-type) 'end)
-        (web-mode-fetch-html-opening-tag regexp pos)
-      (web-mode-fetch-html-closing-tag regexp pos))
-    t))
+       (t
 
-(defun web-mode-fetch-html-opening-tag (regexp pos)
-  "Fetch opening HTML block."
-  (let ((counter 1) (n 0))
-    (while (and (> counter 0) (re-search-backward regexp nil t))
-      (when (get-text-property (point) 'tag-beg)
-        (setq n (1+ n))
-        (if (eq (get-text-property (point) 'tag-type) 'end)
-            (setq counter (1+ counter))
-          (setq counter (1- counter))))
-      )
-    (if (= n 0) (goto-char pos))
-    ))
+        (setq ctx (web-mode-point-context
+                   (if mark-active (region-beginning) (line-beginning-position))))
+;;        (message "ctx=%S" ctx)
+        (setq language (plist-get ctx :language))
 
-(defun web-mode-fetch-html-closing-tag (regexp pos)
-  "Fetch closing HTML closing block."
-  (let ((counter 1) (n 0))
-    (web-mode-tag-end)
-    (while (and (> counter 0) (re-search-forward regexp nil t))
-      (when (get-text-property (match-beginning 0) 'tag-beg)
-        (setq n (1+ n))
-        (if (eq (get-text-property (point) 'tag-type) 'end)
-            (setq counter (1- counter))
-          (setq counter (1+ counter))))
-      )
-    (if (> n 0)
-        (web-mode-tag-beginning)
-      (goto-char pos))
-    ))
+        (if mark-active
+            (progn
+              (setq beg (region-beginning)
+                    end (region-end))
+;;              (message "beg=%S end=%S" beg end)
+              )
+          (if (and (string= language "html")
+                   (progn (back-to-indentation) t)
+                   (get-text-property (point) 'tag-beg))
+              ;;              (progn
+              ;;                (back-to-indentation)
+              (web-mode-element-select)
+            ;;            )
+            (end-of-line)
+            (set-mark (line-beginning-position))
+            ) ;if
+          (setq beg (region-beginning)
+                end (region-end))
+          ) ;if mark-active
 
-(defun web-mode-match-underscore-block ()
-  "Fetch underscore block."
-  (let (open)
-    (cond
+        (when (> (point) (mark))
+          (exchange-point-and-mark))
 
-     ((looking-at-p "<%[ ]*}")
-      (search-forward "}")
-      (backward-char)
-      (setq open (web-mode-opening-paren-position))
-      (when open
-        (goto-char open)
-        (web-mode-block-beginning)
-        )
-      )
+        (if (eq (char-before end) ?\n)
+            (setq end (1- end)))
 
-     ((web-mode-block-ends-with "{[ ]*%>")
-      (web-mode-block-end)
-      (search-backward "{")
-      (setq open (web-mode-closing-paren-position))
-      (when open
-        (goto-char open)
-        (web-mode-block-beginning)
-        )
-      )
+;;        (message "language=%S beg=%S end=%S" language beg end)
+        (setq sel (web-mode-trim (buffer-substring-no-properties beg end)))
+        ;;      (message "[language=%s] sel=%s" language sel)
+        (delete-region beg end)
+        (deactivate-mark)
 
-     );cond
+        (cond
 
-    ))
+         ((string= language "html")
 
-(defun web-mode-match-php-block ()
-  "Fetch PHP block."
-  (let (regexp match)
-    (cond
+          (cond
+           ((and (= web-mode-comment-style 2) (string= web-mode-engine "django"))
+            (web-mode-insert-and-indent (concat "{# " sel " #}"))
+            )
+           ((and (= web-mode-comment-style 2) (string= web-mode-engine "erb"))
+            (web-mode-insert-and-indent (concat "<%# " sel " %>"))
+            )
+           ((and (= web-mode-comment-style 2) (string= web-mode-engine "aspx"))
+            (web-mode-insert-and-indent (concat "<%-- " sel " --%>"))
+            )
+           ((and (= web-mode-comment-style 2) (string= web-mode-engine "smarty"))
+            (web-mode-insert-and-indent (concat
+                                         (web-mode-engine-delimiter-open web-mode-engine "{")
+                                         "* "
+                                         sel
+                                         " *"
+                                         (web-mode-engine-delimiter-close web-mode-engine "}")))
+            )
+           ((and (= web-mode-comment-style 2) (string= web-mode-engine "blade"))
+            (web-mode-insert-and-indent (concat "{{-- " sel " --}}"))
+            )
+           ((and (= web-mode-comment-style 2) (string= web-mode-engine "razor"))
+            (web-mode-insert-and-indent (concat "@* " sel " *@"))
+            )
+           (t
+            (web-mode-insert-and-indent (concat "<!-- " sel " -->"))
+            )
+           )
 
-     ((looking-at-p "<\\?\\(php\\)?[ ]*}")
-      (let (open)
-        (search-forward "}")
-        (backward-char)
-        (setq open (web-mode-opening-paren-position))
-        (when open
-          (goto-char open)
-          (web-mode-block-beginning)
           )
-        ))
 
-     ((looking-at-p "<\\?php.+{[ ]*\\?>")
-      (let (close)
-        (web-mode-block-end)
-        (search-backward "{")
-        (setq close (web-mode-closing-paren-position))
-        (when close
-          (goto-char close)
-          (web-mode-block-beginning)
-          )
-        ))
+         ((member language '("php" "javascript" "css"))
+          (web-mode-insert-and-indent (concat "/* " sel " */")))
 
-     (t
-      (looking-at web-mode-active-block-regexp)
-      (setq match (match-string-no-properties 3))
-      (setq regexp (concat "<\\?\\(php[ ]+\\|[ ]*\\)?\\(end\\)?\\("
-                         (if (member match '("else" "elseif")) "if" match)
-                         "\\)"))
-      (if (or (string= "end" (match-string-no-properties 2))
-              (member match '("else" "elseif")))
-          (web-mode-fetch-opening-php-block regexp)
-        (web-mode-fetch-closing-php-block regexp))
-      );t
-
-     );cond
-    t))
+         ((member language '("erb"))
+          (web-mode-insert-and-indent (replace-regexp-in-string "^" "#" sel)))
 
-(defun web-mode-fetch-opening-php-block (regexp)
-  "Fetch PHP opening block."
-  (let ((counter 1))
-    (while (and (> counter 0) (re-search-backward regexp nil t))
-      (if (string= "end" (match-string-no-properties 2))
-          (setq counter (1+ counter))
-        (setq counter (1- counter)))
-      )
-    ))
+         ((member language '("asp"))
+          (web-mode-insert-and-indent (replace-regexp-in-string "^" "''" sel)))
 
-(defun web-mode-fetch-closing-php-block (regexp)
-  "Fetch PHP closing block."
-  (let ((counter 1))
-    (web-mode-block-end)
-    (while (and (> counter 0) (re-search-forward regexp nil t))
-      (if (string= "end" (match-string-no-properties 2))
-          (setq counter (1- counter))
-        (setq counter (1+ counter))
-        );if
-      );while
-    (web-mode-block-beginning)
-    ))
+         (t
+          (web-mode-insert-and-indent (concat "/* " sel " */")))
 
-(defun web-mode-match-erb-block ()
-  "Fetch ERB block."
-  (let (regexp chunk)
-    (setq chunk (buffer-substring-no-properties (+ (point) 3)
-                                                (- (web-mode-block-end-position) 2)))
-    (setq regexp web-mode-active-block-regexp)
-    (if (string-match-p "else\\|end" chunk)
-        (web-mode-fetch-opening-erb-block regexp)
-      (web-mode-fetch-closing-erb-block regexp))
-    t))
+         ) ;cond
+
+        ) ;t
+       ) ;cond
 
-(defun web-mode-fetch-opening-erb-block (regexp)
-  "Fetch erb opening block."
-  (let ((counter 1) match)
-    (while (and (> counter 0) (web-mode-rsb regexp nil t))
-      (setq match (match-string-no-properties 1))
-      (cond
-       ((string= "else" match)
-        )
-       ((not (string= "end" match))
-        (setq counter (1- counter)))
-       (t
-        (setq counter (1+ counter)))
-       )
       )
+    ) ;save-excursion
+;;  (message "%S" (point))
+;;  (goto-char pos)
+  )
+
+(defun web-mode-looking-at-pos (regexp pos)
+  "Performs a looking-at at POS."
+  (save-excursion
+    (goto-char pos)
+    (looking-at regexp)
     ))
 
-(defun web-mode-fetch-closing-erb-block (regexp)
-  "Fetch erb closing block."
-  (let ((counter 1) match)
-    (web-mode-block-end)
-    (while (and (> counter 0) (web-mode-rsf regexp nil t))
-      (setq match (match-string-no-properties 1))
-      (cond
-       ((string= "else" match)
-        )
-       ((not (string= "end" match))
-        (setq counter (1+ counter)))
-       (t
-        (setq counter (1- counter)))
-       )
-      )
-    (web-mode-block-beginning)
+(defun web-mode-insert-text-at-pos (text pos)
+  "Insert TEXT at POS."
+  (save-excursion
+    (goto-char pos)
+    (insert text)
     ))
 
-(defun web-mode-match-template-toolkit-block ()
-  "Fetch TEMPLATE-TOOLKIT block."
-  (let (regexp chunk)
-    (setq chunk (buffer-substring-no-properties (+ (point) 3)
-                                                (- (web-mode-block-end-position) 2)))
-    (setq regexp web-mode-active-block-regexp)
-    (if (string-match-p "else\\|end\\|END" chunk)
-        (web-mode-fetch-opening-template-toolkit-block regexp)
-      (web-mode-fetch-closing-template-toolkit-block regexp))
-    t))
+(defun web-mode-remove-text-at-pos (n &optional pos)
+  "Remove N chars at POS."
+  (unless pos (setq pos (point)))
+  (delete-region pos (+ pos n)))
 
-(defun web-mode-fetch-opening-template-toolkit-block (regexp)
-  "Fetch template-toolkit opening block."
-  (let ((counter 1) match)
-    (while (and (> counter 0) (web-mode-rsb regexp nil t))
-      (setq match (match-string-no-properties 1))
-      (cond
-       ((member match '("else" "ELSE" "elsif" "ELSIF"))
-        )
-       ((not (member match '("end" "END")))
-        (setq counter (1- counter)))
-       (t
-        (setq counter (1+ counter)))
-       )
-      )
+(defun web-mode-uncomment-erb-block (pos)
+  "Uncomment an erb block."
+  (let (beg end)
+    (setq beg (web-mode-block-beginning-position pos)
+          end (web-mode-block-end-position pos))
+    (web-mode-remove-text-at-pos 1 (+ beg 2))
     ))
 
-(defun web-mode-fetch-closing-template-toolkit-block (regexp)
-  "Fetch template-toolkit closing block."
-  (let ((counter 1) match)
-    (web-mode-block-end)
-    (while (and (> counter 0) (web-mode-rsf regexp nil t))
-      (setq match (match-string-no-properties 1))
-      (cond
-       ((member match '("else" "ELSE" "elsif" "ELSIF"))
-        )
-       ((not (member match '("end" "END")))
-        (setq counter (1+ counter)))
-       (t
-        (setq counter (1- counter)))
-       )
-      )
-    (web-mode-block-beginning)
+(defun web-mode-comment-erb-block (pos)
+  "Turn an erb block into a comment block."
+  (let (beg end)
+    (setq beg (web-mode-block-beginning-position pos)
+          end (web-mode-block-end-position pos))
+    (web-mode-insert-text-at-pos "#" (+ beg 2))
     ))
 
-
-(defun web-mode-match-blade-block ()
-  "Fetch blade block."
-  (let (beg end match regexp)
-    (looking-at web-mode-active-block-regexp)
-    (setq match (match-string-no-properties 2))
-    (setq regexp (cond
-                  ((member match '("else" "elseif")) "@\\(end\\)?\\(if\\)")
-                  ((string= match "stop") "@\\(section\\|stop\\)")
-                  ((string= match "section") "@\\(endsection\\|stop\\|section\\)")
-                  (t (concat "@\\(end\\)?\\(" match "\\)"))))
-    (if (or (string= "end" (match-string-no-properties 1))
-            (member match '("else" "elseif" "stop")))
-        (web-mode-fetch-opening-blade-block regexp)
-      (web-mode-fetch-closing-blade-block regexp))
-    t))
-
-(defun web-mode-fetch-opening-blade-block (regexp)
-  "Fetch blade opening block."
-  (let ((counter 1))
-    (while (and (> counter 0) (web-mode-rsb regexp nil t))
-      (if (member (match-string-no-properties 1) '("end" "endsection" "stop"))
-          (setq counter (1+ counter))
-        (setq counter (1- counter)))
-      )
+(defun web-mode-uncomment-django-block (pos)
+  "Uncomment a django block."
+  (let (beg end)
+    (setq beg (web-mode-block-beginning-position pos)
+          end (web-mode-block-end-position pos))
+    (web-mode-remove-text-at-pos 2 (1- end))
+    (web-mode-remove-text-at-pos 2 beg)
     ))
 
-(defun web-mode-fetch-closing-blade-block (regexp)
-  "Fetch blade closing block."
-  (let ((counter 1))
-    (web-mode-block-end)
-    (while (and (> counter 0) (web-mode-rsf regexp nil t))
-      (if (member (match-string-no-properties 1) '("end" "endsection" "stop"))
-          (setq counter (1- counter))
-        (setq counter (1+ counter)))
-      )
-    (goto-char (match-beginning 0))
+(defun web-mode-comment-django-block (pos)
+  "Turn a django block into a comment block."
+  (let (beg end)
+    (setq beg (web-mode-block-beginning-position pos)
+          end (web-mode-block-end-position pos))
+    (web-mode-insert-text-at-pos "#" end)
+    (web-mode-insert-text-at-pos "#" (1+ beg))
     ))
 
-(defun web-mode-match-django-block ()
-  "Fetch django block."
-  (let (match regexp)
-    (looking-at web-mode-active-block-regexp)
-    (setq match (match-string-no-properties 2))
-    (setq regexp (concat "{%[-]?[ ]+\\(end\\)?\\("
-                         (cond
-                          ((member match '("else" "elseif" "elsif" "elif")) "if")
-                          ((member match '("empty")) "for")
-                          (t match))
-                         "\\)"))
-;;    (message "%S" regexp)
-    (if (or (string= "end" (match-string-no-properties 1))
-            (member match '("else" "elseif" "elsif" "elif" "empty")))
-        (web-mode-fetch-opening-django-block regexp)
-      (web-mode-fetch-closing-django-block regexp))
-    t))
+(defun web-mode-uncomment-dust-block (pos)
+  "Uncomment a dust block."
+  (let (beg end)
+    (setq beg (web-mode-block-beginning-position pos)
+          end (web-mode-block-end-position pos))
+    (web-mode-remove-text-at-pos 1 (1- end))
+    (web-mode-remove-text-at-pos 1 (1+ beg))
+    ))
 
-(defun web-mode-fetch-opening-django-block (regexp)
-  "Fetch django opening block."
-  (let ((counter 1))
-    (while (and (> counter 0) (web-mode-rsb regexp nil t))
-      (if (string= "end" (match-string-no-properties 1))
-          (setq counter (1+ counter))
-        (setq counter (1- counter)))
-      )
+(defun web-mode-comment-dust-block (pos)
+  "Turn a dust block into a comment block."
+  (let (beg end)
+    (setq beg (web-mode-block-beginning-position pos)
+          end (web-mode-block-end-position pos))
+    (web-mode-insert-text-at-pos "!" end)
+    (web-mode-insert-text-at-pos "!" (1+ beg))
     ))
 
-(defun web-mode-fetch-closing-django-block (regexp)
-  "Fetch django closing block."
-  (let ((counter 1))
-    (web-mode-block-end)
-    (while (and (> counter 0) (web-mode-rsf regexp nil t))
-      (if (string= "end" (match-string-no-properties 1))
-          (setq counter (1- counter))
-        (setq counter (1+ counter)))
-      )
-    (web-mode-block-beginning)
+(defun web-mode-comment-aspx-block (pos)
+  "Turn a aspx block into a comment block."
+  (let (beg end)
+    (setq beg (web-mode-block-beginning-position pos)
+          end (web-mode-block-end-position pos))
+    (web-mode-insert-text-at-pos "#" end)
+    (web-mode-insert-text-at-pos "#" (1+ beg))
     ))
 
-(defun web-mode-match-smarty-block ()
-  "Fetch smarty block."
-  (let (match regexp)
-    (looking-at web-mode-active-block-regexp)
-    (setq match (match-string-no-properties 1))
-    (setq regexp (concat "{/?" (if (string= match "else") "if" match)))
-    (if (or (eq ?\/ (aref (match-string-no-properties 0) 1))
-            (string= match "else"))
-        (web-mode-fetch-opening-smarty-block regexp)
-      (web-mode-fetch-closing-smarty-block regexp))
-    t))
+(defun web-mode-uncomment-aspx-block (pos)
+  "Uncomment a aspx block."
+  (let (beg end)
+    (setq beg (web-mode-block-beginning-position pos)
+          end (web-mode-block-end-position pos))
+    (web-mode-remove-text-at-pos 1 (1- end))
+    (web-mode-remove-text-at-pos 1 (1+ beg))
+    ))
 
-(defun web-mode-fetch-opening-smarty-block (regexp)
-  "Fetch smarty opening block."
-  (let ((counter 1))
-    (while (and (> counter 0) (web-mode-rsb regexp nil t))
-      (if (eq ?\/ (aref (match-string-no-properties 0) 1))
-          (setq counter (1+ counter))
-        (setq counter (1- counter)))
-      )
+(defun web-mode-uncomment-jsp-block (pos)
+  "Uncomment a jsp block."
+  (let (beg end)
+    (setq beg (web-mode-block-beginning-position pos)
+          end (web-mode-block-end-position pos))
+    (web-mode-remove-text-at-pos 2 (+ beg 2))
     ))
 
-(defun web-mode-fetch-closing-smarty-block (regexp)
-  "Fetch smarty closing block."
-  (let ((counter 1))
-    (web-mode-block-end)
-    (while (and (> counter 0) (web-mode-rsf regexp nil t))
-      (if (eq ?\/ (aref (match-string-no-properties 0) 1))
-          (setq counter (1- counter))
-        (setq counter (1+ counter)))
-      )
-    (web-mode-block-beginning)
+(defun web-mode-comment-jsp-block (pos)
+  "Turn a jsp block into a comment block."
+  (let (beg end)
+    (setq beg (web-mode-block-beginning-position pos)
+          end (web-mode-block-end-position pos))
+    (web-mode-insert-text-at-pos "--" (+ beg 2))
     ))
 
-(defun web-mode-match-dust-block ()
-  "Fetch dust block."
-  (let (match regexp (continue t))
-    (looking-at web-mode-active-block-regexp)
-    (cond
-     ((string= (match-string-no-properties 0) "{:else")
-      (while continue
-        (if (web-mode-block-previous)
-            (when (cdr (web-mode-is-active-block (point)))
-              (setq continue nil))
-          (setq continue nil)
-          )
-        );while
-      )
-     (t
-      (setq match (match-string-no-properties 1))
-      (setq regexp (concat "{[#/:?@><+^]?" match))
-      (if (eq ?\/ (aref (match-string-no-properties 0) 1))
-          (web-mode-fetch-opening-dust-block regexp)
-        (web-mode-fetch-closing-dust-block regexp)))
-     );cond
-    t))
+(defun web-mode-uncomment-go-block (pos)
+  "Uncomment a go block."
+  (let (beg end)
+    (setq beg (web-mode-block-beginning-position pos)
+          end (web-mode-block-end-position pos))
+    (web-mode-remove-text-at-pos 1 (+ beg 2))
+    ))
 
-(defun web-mode-fetch-opening-dust-block (regexp)
-  "Fetch dust opening block."
-  (let ((counter 1))
-    (while (and (> counter 0) (web-mode-rsb regexp nil t))
-      (if (eq ?\/ (aref (match-string-no-properties 0) 1))
-          (setq counter (1+ counter))
-        (setq counter (1- counter)))
-      )
+(defun web-mode-comment-go-block (pos)
+  "Turn a go block into a comment block."
+  (let (beg end)
+    (setq beg (web-mode-block-beginning-position pos)
+          end (web-mode-block-end-position pos))
+    (web-mode-insert-text-at-pos "/" (+ beg 2))
     ))
 
-(defun web-mode-fetch-closing-dust-block (regexp)
-  "Fetch dust closing block."
-  (let ((counter 1))
-    (web-mode-block-end)
-    (while (and (> counter 0) (web-mode-rsf regexp nil t))
-      (if (eq ?\/ (aref (match-string-no-properties 0) 1))
-          (setq counter (1- counter))
-        (setq counter (1+ counter)))
-      )
-    (web-mode-block-beginning)
+(defun web-mode-comment-php-block (pos)
+  "Turn a php block into a comment block."
+  (let (beg end)
+    (setq beg (web-mode-block-beginning-position pos)
+          end (web-mode-block-end-position pos))
+    (web-mode-insert-text-at-pos "*/" (- end 1))
+    (web-mode-insert-text-at-pos "/*" (+ beg (if (web-mode-looking-at-pos "<\\?php" beg) 5 3)))
     ))
 
-(defun web-mode-match-closure-block ()
-  "Fetch closure block."
-  (let (match regexp (continue t))
-    (looking-at web-mode-active-block-regexp)
+(defun web-mode-uncomment (&optional pos)
+  "Uncomment line(s) at point."
+  (interactive)
+  (unless pos (setq pos (point)))
+  (let ((beg pos)
+        (end pos)
+        (sub2 "")
+        comment prop)
+
     (cond
-     ((member (match-string-no-properties 0) '("{else" "{elseif"))
-      (while continue
-        (if (web-mode-block-previous)
-            (when (looking-at-p "{if")
-              (setq continue nil))
-          (setq continue nil)
-          )
-        );while
-      )
-     ((member (match-string-no-properties 0) '("{ifempty"))
-      (while continue
-        (if (web-mode-block-previous)
-            (when (looking-at-p "{foreach")
-              (setq continue nil))
-          (setq continue nil)
-          )
-        );while
-      )
-     ((member (match-string-no-properties 0) '("{case" "{default"))
-      (while continue
-        (if (web-mode-block-previous)
-            (when (looking-at-p "{switch")
-              (setq continue nil))
-          (setq continue nil)
-          )
-        );while
+
+     ((and (get-text-property pos 'block-side)
+           (string= web-mode-engine "django"))
+        (web-mode-uncomment-django-block pos)
+        )
+
+     ((and (get-text-property pos 'block-side)
+           (string= web-mode-engine "dust"))
+        (web-mode-uncomment-dust-block pos)
+        )
+
+     ((and (get-text-property pos 'block-side)
+           (string= web-mode-engine "erb"))
+        (web-mode-uncomment-erb-block pos)
+        )
+
+     ((and (get-text-property pos 'block-side)
+           (string= web-mode-engine "aspx"))
+      (web-mode-uncomment-aspx-block pos)
       )
-     (t
-      (setq match (match-string-no-properties 1))
-      (setq regexp (concat "{/?" match))
-      (if (eq ?\/ (aref (match-string-no-properties 0) 1))
-          (web-mode-fetch-opening-closure-block regexp)
-        (web-mode-fetch-closing-closure-block regexp)))
-     );cond
-    t))
 
-(defun web-mode-fetch-opening-closure-block (regexp)
-  "Fetch closure opening block."
-  (let ((counter 1))
-    (while (and (> counter 0) (web-mode-rsb regexp nil t))
-      (if (eq ?\/ (aref (match-string-no-properties 0) 1))
-          (setq counter (1+ counter))
-        (setq counter (1- counter)))
+     ((and (get-text-property pos 'block-side)
+           (string= web-mode-engine "jsp"))
+      (web-mode-uncomment-jsp-block pos)
       )
-    ))
 
-(defun web-mode-fetch-closing-closure-block (regexp)
-  "Fetch closure closing block."
-  (let ((counter 1))
-    (web-mode-block-end)
-    (while (and (> counter 0) (web-mode-rsf regexp nil t))
-      (if (eq ?\/ (aref (match-string-no-properties 0) 1))
-          (setq counter (1- counter))
-        (setq counter (1+ counter)))
+     ((and (get-text-property pos 'block-side)
+           (string= web-mode-engine "go"))
+      (web-mode-uncomment-go-block pos)
       )
-    (web-mode-block-beginning)
-    ))
 
-(defun web-mode-match-velocity-block ()
-  "Fetch velocity block."
-  (let (regexp match)
-    (looking-at web-mode-active-block-regexp)
-    (setq match (match-string-no-properties 1))
-    (setq regexp web-mode-active-block-regexp)
-    (if (member match '("else" "elseif" "end"))
-        (web-mode-fetch-opening-velocity-block regexp)
-      (web-mode-fetch-closing-velocity-block regexp))
-    t))
+     (t
 
-(defun web-mode-fetch-opening-velocity-block (regexp)
-  "Fetch velocity opening block."
-  (let ((counter 1) match)
-    (while (and (> counter 0) (web-mode-rsb regexp nil t))
-      (setq match (match-string-no-properties 1))
       (cond
-       ((string= "end" match)
-        (setq counter (1+ counter)))
-       ((string= "else" match)
-        )
-       (t
-        (setq counter (1- counter)))
+       ((eq (get-text-property pos 'block-token) 'comment)
+        (setq prop 'block-token))
+       ((eq (get-text-property pos 'tag-type) 'comment)
+        (setq prop 'tag-type))
+       ((eq (get-text-property pos 'part-token) 'comment)
+        (setq prop 'part-token))
        )
-      )
-    ))
 
-(defun web-mode-fetch-closing-velocity-block (regexp)
-  "Fetch velocity closing block."
-  (let ((counter 1) match)
-    (web-mode-block-end)
-    (while (and (> counter 0) (web-mode-rsf regexp nil t))
-      (setq match (match-string-no-properties 1))
-      (cond
-       ((string= "end" match)
-        (setq counter (1- counter)))
-       ((string= "else" match)
-        )
-       (t
-        (setq counter (1+ counter)))
-       )
-      )
-    (goto-char (match-beginning 0))
-    ))
+      (if (and (not (bobp))
+               (eq (get-text-property pos prop) (get-text-property (- pos 1) prop)))
+          (setq beg (or (previous-single-property-change pos prop)
+                        (point-min))))
 
-(defun web-mode-match-ctemplate-block ()
-  "Fetch ctemplate block."
-  (let (regexp)
-    (looking-at web-mode-active-block-regexp)
-    (setq regexp (concat "{{[#^/]" (match-string-no-properties 1)))
-    (if (looking-at-p "{{/")
-        (web-mode-fetch-opening-ctemplate-block regexp)
-      (web-mode-fetch-closing-ctemplate-block regexp))
-    t))
+      (if (and (not (eobp))
+               (eq (get-text-property pos prop) (get-text-property (+ pos 1) prop)))
+          (setq end (or (next-single-property-change pos prop)
+                        (point-max))))
 
-(defun web-mode-fetch-opening-ctemplate-block (regexp)
-  "Fetch ctemplate opening block."
-  (let ((counter 1))
-    (while (and (> counter 0) (web-mode-rsb regexp nil t))
-      (if (eq ?\/ (aref (match-string-no-properties 0) 2))
-          (setq counter (1+ counter))
-        (setq counter (1- counter)))
-      )
-    ))
+      ;;    (message "beg(%d) end(%d)" beg end)
 
-(defun web-mode-fetch-closing-ctemplate-block (regexp)
-  "Fetch ctemplate closing block."
-  (let ((counter 1))
-    (web-mode-block-end)
-    (while (and (> counter 0) (web-mode-rsf regexp nil t))
-      (if (eq ?\/ (aref (match-string-no-properties 0) 2))
-          (setq counter (1- counter))
-        (setq counter (1+ counter)))
-      )
-    (web-mode-block-beginning)
-    ))
+      (when (> (- end beg) 4)
 
-(defun web-mode-match-go-block ()
-  "Fetch go block."
-  (let (regexp match)
-    (looking-at web-mode-active-block-regexp)
-    (setq match (match-string-no-properties 1))
-    (setq regexp web-mode-active-block-regexp)
-    (if (member match '("end" "else"))
-        (web-mode-fetch-opening-go-block regexp)
-      (web-mode-fetch-closing-go-block regexp))
-    t))
+        (setq comment (buffer-substring-no-properties beg end))
+        ;;    (message "before[%s]" comment)
 
-(defun web-mode-fetch-opening-go-block (regexp)
-  "Fetch go opening block."
-  (let ((counter 1) match)
-    (while (and (> counter 0) (web-mode-rsb regexp nil t))
-      (setq match (match-string-no-properties 1))
-      (cond
-       ((string= "end" match)
-        (setq counter (1+ counter)))
-       ((string= "else" match)
-        )
-       (t
-        (setq counter (1- counter)))
-       )
-      )
+        (setq sub2 (substring comment 0 2))
+
+        (cond
+
+         ((member sub2 '("<!" "<%"))
+          (setq comment (replace-regexp-in-string "\\(^<[!%]--[ ]?\\|[ ]?--[%]?>$\\)" "" comment)))
+
+         ((string= sub2 "{#")
+          (setq comment (replace-regexp-in-string "\\(^{#[ ]?\\|[ ]?#}$\\)" "" comment)))
+
+         ((string= sub2 "/*")
+          (setq comment (replace-regexp-in-string "\\(^/\\*[ ]?\\|[ ]?\\*/$\\)" "" comment)))
+
+         ((string= sub2 "//")
+          (setq comment (replace-regexp-in-string "\\(^//\\)" "" comment)))
+
+         )
+
+        ;;    (message "after[%s]" comment)
+
+        (delete-region beg end)
+        (web-mode-insert-and-indent comment)
+        (goto-char beg)
+;;        (back-to-indentation)
+
+        ) ;when
+
+      ))
+    (indent-for-tab-command)
     ))
 
-(defun web-mode-fetch-closing-go-block (regexp)
-  "Fetch go closing block."
-  (let ((counter 1) match)
-    (web-mode-block-end)
-    (while (and (> counter 0) (web-mode-rsf regexp nil t))
-      (setq match (match-string-no-properties 1))
-      (cond
-       ((string= "end" match)
-        (setq counter (1- counter))
-        )
-       ((string= "else" match)
-        )
-       (t
-        (setq counter (1+ counter))
-        )
-       )
-      )
-    (web-mode-block-beginning)
+(defun web-mode-snippet-names ()
+  "Return the snippet names."
+  (interactive)
+  (let (codes snippet)
+    (dolist (snippet web-mode-snippets)
+      (add-to-list 'codes (car snippet) t))
+    codes))
+
+(defun web-mode-snippet-insert (code)
+  "Insert snippet."
+  (interactive
+   (list (completing-read
+          "Snippet: " (web-mode-snippet-names))))
+  (let (beg
+        (continue t)
+        (counter 0)
+        end
+        sel
+        snippet
+        (l (length web-mode-snippets))
+        pos)
+    (when mark-active
+      (setq sel (web-mode-trim
+                 (buffer-substring-no-properties
+                  (region-beginning) (region-end))))
+      (delete-region (region-beginning) (region-end)))
+    (while (and continue (< counter l))
+      (setq snippet (nth counter web-mode-snippets))
+      (when (string= (car snippet) code)
+        (setq continue nil))
+      (setq counter (1+ counter)))
+    (when snippet
+      (setq snippet (cdr snippet))
+      (setq beg (point-at-bol))
+      (insert (car snippet))
+;;      (message "insert[1] (%S)" (point))
+      (setq pos (point))
+      (when sel
+        (insert sel)
+        (setq pos (point)))
+      (if (cdr snippet) (insert (cdr snippet)))
+;;      (message "insert[2] (%S)" (point))
+      (setq end (point-at-eol))
+      (unless sel (goto-char pos))
+      (indent-region beg end))
+;;      (message "indent : beg(%S) end(%S)" beg end)
     ))
 
-(defun web-mode-match-razor-block ()
-  "Fetch razor block."
-  (let (regexp pos)
-    (cond
-     ((looking-at-p "}")
-      (setq pos (web-mode-opening-paren-position))
-      (when pos
-        (goto-char pos))
-      (web-mode-block-beginning)
-      )
-     ((looking-at-p ".*{[ ]*$")
-      (end-of-line)
-      (search-backward "{")
-      (setq pos (web-mode-closing-paren-position))
-      (when pos
-        (goto-char pos))
-      )
-     )
-    t))
+(defun web-mode-insert-and-indent (text)
+  "Insert and indent text."
+  (interactive)
+  (let (beg end)
+    (setq beg (point-at-bol))
+    (insert text)
+    (setq end (point-at-eol))
+    (indent-region beg end)))
 
-(defun web-mode-match-jsp-block ()
-  "Fetch jsp block."
-  (let (regexp)
+(defun web-mode-navigate (&optional pos)
+  "Match tag."
+  (interactive)
+  (unless pos (setq pos (point)))
+  (let (init)
+    (goto-char pos)
+    (setq init (point))
+    (when (> (current-indentation) (current-column))
+      (back-to-indentation))
+    (setq pos (point))
     (cond
-     ((looking-at-p "<% }")
-      (let (open)
-        (search-forward "}")
-        (backward-char)
-        (setq open (web-mode-opening-paren-position))
-        (when open
-          (goto-char open)
-          (web-mode-block-beginning))
-        ))
+     ((and (get-text-property pos 'block-side)
+           (web-mode-block-beginning)
+           (web-mode-block-controls-get (point)))
+      (web-mode-block-match))
+     ((member (get-text-property pos 'tag-type) '(start end))
+      (web-mode-tag-beginning)
+      (web-mode-tag-match))
      (t
-      (looking-at web-mode-active-block-regexp)
-      (setq regexp (concat "<\\(/?" (match-string-no-properties 1) "\\)\\>"))
-      (if (eq ?\/ (aref (match-string-no-properties 0) 1))
-          (web-mode-fetch-opening-jsp-block regexp)
-        (web-mode-fetch-closing-jsp-block regexp)))
+      (goto-char init))
      )
-    t))
-
-(defun web-mode-fetch-opening-jsp-block (regexp)
-  "Fetch jsp opening block."
-  (let ((counter 1))
-    (while (and (> counter 0) (web-mode-rsb regexp nil t))
-      (cond
-       ((eq ?\/ (aref (match-string-no-properties 1) 0))
-        (setq counter (1+ counter)))
-       (t
-        (setq counter (1- counter)))
-       )
-      )
     ))
 
-(defun web-mode-fetch-closing-jsp-block (regexp)
-  "Fetch jsp closing block."
-  (let ((counter 1))
-    (web-mode-block-end)
-    (while (and (> counter 0) (web-mode-rsf regexp nil t))
-      (cond
-       ((eq ?\/ (aref (match-string-no-properties 1) 0))
-        (setq counter (1- counter)))
-       (t
-        (setq counter (1+ counter)))
-       )
-      )
-    (web-mode-block-beginning)
+(defun web-mode-block-match (&optional pos)
+  "Block match"
+  (unless pos (setq pos (point)))
+  (let (init controls (counter 1) type control (continue t) pair)
+    (setq init pos)
+    (goto-char pos)
+    (setq controls (web-mode-block-controls-get pos))
+    (cond
+     (controls
+      (setq pair (car controls))
+      (setq type (car pair))
+      (when (eq type 'inside)
+        (setq type 'close))
+      (setq control (cdr pair))
+      (while continue
+        (cond
+         ((and (> init 1) (bobp))
+          (setq continue nil))
+         ((or (and (eq type 'open) (not (web-mode-block-next)))
+              (and (eq type 'close) (not (web-mode-block-previous))))
+;;          (message "ici%S" (point))
+          (setq continue nil)
+          )
+         ((null (web-mode-block-controls-get (point)))
+          )
+         (t
+          (setq controls (web-mode-block-controls-get (point)))
+          (setq pair (car controls))
+;;          (message "%S-%S (%S) type=%S control=%S" type control (point) (car pair) (cdr pair))
+          (when (string= control (cdr pair))
+            (cond
+             ((eq (car pair) type)
+              (setq counter (1+ counter)))
+             ((eq (car pair) 'inside)
+              )
+             (t
+              (setq counter (1- counter)))
+             )
+            ) ;when
+          (when (= counter 0)
+            (setq continue nil))
+          ) ;t
+         ) ;cond
+        ) ;while
+      (if (= counter 0) (point) nil)
+      ) ;controls
+     (t
+      (goto-char init)
+      nil)
+     ) ;conf
     ))
 
-(defun web-mode-match-freemarker-block ()
-  "Fetch freemarker block."
-  (let (regexp match tag char)
-    (looking-at "[<[]/?\\([[:alpha:]]+:[[:alpha:]]+\\|[@#][[:alpha:]._]+\\)")
-    (setq match (match-string-no-properties 0)
-          tag (match-string-no-properties 1)
-          char (if (string= (substring (match-string-no-properties 0) 0 1) "<") "<" "\\["))
-
-    (cond
-     ((member tag '("#else" "#elseif"))
-      (setq match (concat char "/#if")
-            tag "#if")
-      )
-     ((string= tag "#break")
-      (setq match (concat char "/#case")
-            tag "#case"))
-     );cond
-    (setq regexp (concat char "\\(/?" tag "\\)\\>"))
-;;    (message "tag=%S regexp=%S" tag regexp)
-    (if (eq ?\/ (aref match 1))
-        (web-mode-fetch-opening-freemarker-block regexp)
-      (web-mode-fetch-closing-freemarker-block regexp))
+(defun web-mode-tag-match (&optional pos)
+  "Fetch HTML block."
+  (unless pos (setq pos (point)))
+  (let (regexp)
+    (setq regexp (concat "</?" (get-text-property pos 'tag-name)))
+    (when (member (get-text-property pos 'tag-type) '(start end))
+      (web-mode-tag-beginning)
+      (setq pos (point)))
+    (if (eq (get-text-property pos 'tag-type) 'end)
+        (web-mode-tag-fetch-opening regexp pos)
+      (web-mode-tag-fetch-closing regexp pos))
     t))
 
-(defun web-mode-fetch-opening-freemarker-block (regexp)
-  "Fetch freemarker opening block."
-  (let ((counter 1))
-    (while (and (> counter 0) (web-mode-rsb regexp nil t))
-      (cond
-       ((eq ?\/ (aref (match-string-no-properties 1) 0))
-        (setq counter (1+ counter)))
-       (t
-        (setq counter (1- counter)))
-       )
+(defun web-mode-tag-fetch-opening (regexp pos)
+  "Fetch opening HTML block."
+  (let ((counter 1) (n 0))
+    (goto-char pos)
+    (while (and (> counter 0) (re-search-backward regexp nil t))
+      (when (get-text-property (point) 'tag-beg)
+        (setq n (1+ n))
+        (if (eq (get-text-property (point) 'tag-type) 'end)
+            (setq counter (1+ counter))
+          (setq counter (1- counter))))
       )
+    (if (= n 0) (goto-char pos))
     ))
 
-(defun web-mode-fetch-closing-freemarker-block (regexp)
-  "Fetch freemarker closing block."
-  (let ((counter 1))
-    (web-mode-block-end)
-    (while (and (> counter 0) (web-mode-rsf regexp nil t))
-      (cond
-       ((eq ?\/ (aref (match-string-no-properties 1) 0))
-        (setq counter (1- counter)))
-       (t
-        (setq counter (1+ counter)))
-       )
+(defun web-mode-tag-fetch-closing (regexp pos)
+  "Fetch closing HTML closing block."
+  (let ((counter 1) (n 0))
+    (goto-char pos)
+    (web-mode-tag-end)
+    (while (and (> counter 0) (re-search-forward regexp nil t))
+      (when (get-text-property (match-beginning 0) 'tag-beg)
+        (setq n (1+ n))
+        (if (eq (get-text-property (point) 'tag-type) 'end)
+            (setq counter (1- counter))
+          (setq counter (1+ counter))))
       )
-    (web-mode-block-beginning)
+    (if (> n 0)
+        (web-mode-tag-beginning)
+      (goto-char pos))
     ))
 
 (defun web-mode-element-close ()
@@ -6451,17 +8176,36 @@ Must be used in conjunction with web-mode-enable-block-face."
        ((looking-back "<")
         (setq ins (concat "/" tag)))
        (t
-        (setq ins (concat "</" tag)))
-       )
-      (unless (looking-at-p "[ ]*>")
-        (setq ins (concat ins ">")))
-      (insert ins)
-      (save-excursion
-        (search-backward "<")
-        (setq jump (looking-back (concat "<" tag ">"))))
-      (when jump
-        (search-backward "<"))
-      );when epp
+        ;; auto-close-style = 2
+;;        (message "%S %c" (point) (char-after))
+        (when (and (looking-at-p "[[:alpha:]]") (> (length tag) 4))
+          (dolist (elt '("div" "span" "strong" "pre" "li"))
+            (when (and (string-match-p (concat "^" elt) tag) (not (string= tag elt)))
+              (setq tag elt)
+              (put-text-property epp (point) 'tag-name tag))
+            )
+          ) ;when
+        (if (web-mode-element-is-void (get-text-property (point) 'tag-name))
+            (setq ins nil
+                  epp nil)
+          (setq ins (concat "</" tag)))
+        )
+       ) ;cond
+      (when ins
+        ;;        (message "ins=%S" ins)
+        (unless (looking-at-p "[ ]*>")
+          (setq ins (concat ins ">")))
+        (insert ins)
+        (save-excursion
+          (search-backward "<")
+          (setq jump (and (eq (char-before) ?\>)
+                          (string= (get-text-property (1- (point)) 'tag-name) tag)))
+          (if jump (setq jump (point)))
+          ;;        (setq jump (looking-back (concat "<" tag ">")))
+          ) ;save-excursion
+        (if jump (goto-char jump))
+        ) ;when not ins
+      ) ;when epp
     epp
     ))
 
@@ -6472,7 +8216,7 @@ Must be used in conjunction with web-mode-enable-block-face."
        ((eq (get-text-property pos 'tag-type) 'start)
         (setq start-beg (web-mode-tag-beginning-position pos)
               start-end (web-mode-tag-end-position pos))
-        (when (web-mode-match-html-tag)
+        (when (web-mode-tag-match)
           (setq end-beg (point)
                 end-end (web-mode-tag-end-position (point))))
 ;;        (message "%S %S %S %S" start-beg start-end end-beg end-end)
@@ -6480,9 +8224,12 @@ Must be used in conjunction with web-mode-enable-block-face."
        ((eq (get-text-property pos 'tag-type) 'end)
         (setq end-beg (web-mode-tag-beginning-position pos)
               end-end (web-mode-tag-end-position pos))
-        (when (web-mode-match-html-tag)
+        (when (web-mode-tag-match)
+;;          (message "ici%S" (point))
           (setq start-beg (point)
-                start-end (web-mode-tag-end-position (point))))
+                start-end (web-mode-tag-end-position (point)))
+;;          (message "%S %S %S %S" start-beg start-end end-beg end-end)
+          ) ;when
         )
        )
       (if (and start-beg end-beg)
@@ -6496,10 +8243,10 @@ Must be used in conjunction with web-mode-enable-block-face."
     (setq web-mode-start-tag-overlay (make-overlay 1 1)
           web-mode-end-tag-overlay (make-overlay 1 1))
     (overlay-put web-mode-start-tag-overlay
-                 'face
+                 'font-lock-face
                  'web-mode-current-element-highlight-face)
     (overlay-put web-mode-end-tag-overlay
-                 'face
+                 'font-lock-face
                  'web-mode-current-element-highlight-face)))
 
 (defun web-mode-delete-tag-overlays ()
@@ -6507,9 +8254,9 @@ Must be used in conjunction with web-mode-enable-block-face."
     (delete-overlay web-mode-start-tag-overlay)
     (delete-overlay web-mode-end-tag-overlay)))
 
-(defun web-mode-hightlight-current-element ()
+(defun web-mode-highlight-current-element ()
   (let ((ctx (web-mode-tags-pos)))
-;;    (message "ctx=%S" ctx)
+;;    (message "%S" ctx)
     (if (null ctx)
         (web-mode-delete-tag-overlays)
       (web-mode-make-tag-overlays)
@@ -6517,6 +8264,32 @@ Must be used in conjunction with web-mode-enable-block-face."
       (move-overlay web-mode-end-tag-overlay (cadr ctx) (cddr ctx)))
     ))
 
+;; (1)inside block
+(defun web-mode-on-before-change (beg end)
+  "Useful for partial block / part invalidation."
+  (setq web-mode-change-flags 0)
+;;  (message "ct=%S" web-mode-content-type)
+  (cond
+   ((and (get-text-property beg 'block-side)
+         (get-text-property end 'block-side)
+         (member web-mode-engine '("php" "asp"))
+         (not (eq (get-text-property beg 'block-token) 'delimiter))
+         (not (eq (get-text-property end 'block-token) 'delimiter))
+         )
+    ;;    (message "beg=%S end=%S" beg end)
+    (setq web-mode-change-flags 1)
+    )
+   ((or (member web-mode-content-type '("css" "javascript"))
+        (and (get-text-property beg 'part-side)
+             (get-text-property end 'part-side)
+             (member (get-text-property beg 'part-side) '(css javascript))))
+;;    (message "beg=%S end=%S" beg end)
+    (setq web-mode-change-flags 2)
+    )
+   )
+;;  (message "point=%S beg=%S end=%S" (point) beg end)
+  )
+
 (defun web-mode-on-after-change (beg end len)
   "Handles auto-pairing, auto-closing, and region-refresh after buffer alteration."
 
@@ -6531,46 +8304,67 @@ Must be used in conjunction with web-mode-enable-block-face."
     (setq atomic-insertion (and (= len 0)
                                 (= 1 (- end beg))))
 
-    (if (not (= (point-max) (+ (buffer-size) 1)))
-
+    (if (web-mode-buffer-narrowed-p)  ;;    (if (not (= (point-max) (+ (buffer-size) 1)))
        (setq web-mode-is-narrowed t)
 
+      ;;not narrowed
+      (setq web-mode-is-narrowed nil)
       ;;-- auto-closing and auto-pairing
-      (when (and (> pos 3)
-                 (not (get-text-property pos 'part-side))
-                 atomic-insertion)
+
+      (when (and (> web-mode-jshint-errors 0)
+                 (get-text-property pos 'part-side)
+                 )
+        ;;        (message "%S %S" beg (1+ end))
+        (remove-overlays beg (1+ end) 'font-lock-face 'web-mode-error-face)
+        )
+
+      (when (and (> pos 3) atomic-insertion)
 
         (setq chunk (buffer-substring-no-properties (- beg 1) end))
 
         ;;-- auto-opening
-        (when (and (not web-mode-disable-auto-opening)
-                   (string= ">\n" chunk)
-                   (not (eobp))
-                   (eq (get-text-property (- beg 1) 'tag-type) 'start)
-                   (eq (get-text-property end 'tag-type) 'end)
-                   (string= (get-text-property (- beg 1) 'tag-name)
-                            (get-text-property end 'tag-name)))
+        (cond
+         ((null web-mode-enable-auto-opening)
+          )
+         ((and (string= ">\n" chunk)
+               (not (eobp))
+               (eq (get-text-property (1- beg) 'tag-type) 'start)
+               (eq (get-text-property end 'tag-type) 'end)
+               (string= (get-text-property (1- beg) 'tag-name)
+                        (get-text-property end 'tag-name)))
           (setq auto-opened t)
-          (newline)
-          (indent-for-tab-command)
-          (forward-line -1)
-          (indent-for-tab-command))
+          (newline-and-indent)
+          (forward-line -1))
+         ((and ;;(not auto-opened)
+               (get-text-property beg 'block-side)
+               (string= web-mode-engine "php")
+               (looking-back "<\\?php[ ]*\n")
+               (looking-at-p "[ ]*\\?>"))
+          (setq auto-opened t)
+          (newline-and-indent)
+          (forward-line -1))
+         ) ;cond
 
         ;;-- auto-closing
-        (when (and (> web-mode-tag-auto-close-style 0)
+        (when (and (not auto-opened)
+                   (> web-mode-tag-auto-close-style 0)
                    (or (and (= web-mode-tag-auto-close-style 2)
+                            (not (get-text-property pos 'part-side))
                             (string-match-p "[[:alnum:]'\"]>" chunk))
-                       (string= "</" chunk)))
+                       (string= "</" chunk))
+                   (not (get-text-property (- beg 1) 'block-side)))
           (when (web-mode-element-close)
             (setq auto-closed t
                   self-insertion t))
           )
 
         ;;-- auto-pairing
-        (when (and (not web-mode-disable-auto-pairing)
+        (when (and (not auto-opened)
+                   web-mode-enable-auto-pairing
+                   (not (get-text-property pos 'part-side))
                    (not self-insertion))
           (let ((i 0) expr p after pos-end (l (length web-mode-auto-pairs)))
-            (setq pos-end (if (> (+ end 10) (line-end-position))
+            (setq pos-end (if (> (+ end 32) (line-end-position))
                               (line-end-position)
                             (+ end 10)))
             (setq chunk (buffer-substring-no-properties (- beg 2) end)
@@ -6580,8 +8374,10 @@ Must be used in conjunction with web-mode-enable-block-face."
               (setq i (1+ i))
 ;;              (message "%S" expr)
 ;;              (when (string= (elt expr 0) chunk)
+;;              (message "expr1=%S after=%S" (or (elt expr 2) (elt expr 1)) after)
               (when (and (string= (elt expr 0) chunk)
-                         (not (string-match-p (elt expr 1) after)))
+;;                         (progn (message "%S %S" (elt expr 1) after) t)
+                         (not (string-match-p (or (elt expr 2) (elt expr 1)) after)))
                 (setq self-insertion t)
                 (insert (elt expr 1))
                 (if (not (elt expr 2))
@@ -6589,65 +8385,63 @@ Must be used in conjunction with web-mode-enable-block-face."
                   (setq p (point))
                   (insert (elt expr 2))
                   (goto-char p))
-                );when
-              );while
-            );let
-          );when
+                ) ;when
+              ) ;while
+            ) ;let
+          ) ;when
 
-        );end auto-pairing auto-closing
+        ) ;end auto-pairing auto-closing
 
       ;;-- region-refresh
       ;;      (save-match-data
       (cond
 
-       ;; ((and nil (web-mode-is-html-text beg)
-       ;;       atomic-insertion
-       ;;       (not self-insertion)
-       ;;       (not (member (char-before) web-mode-electric-chars)))
-       ;;  (message "no invalidation %c" (char-before))
-       ;;  )
-
-       ((and web-mode-has-any-large-part
-             atomic-insertion
-             (not self-insertion)
-             (or (member (get-text-property beg 'part-language)
-                         '(css
-                           ;;javascript json
-                           ))
-                 (member web-mode-content-type '("css"
-                                                 ;;"javascript" "json"
-                                                 ))))
-        (if (or (string= web-mode-content-type "css")
-                (eq (get-text-property beg 'part-language) 'css))
-            (web-mode-invalidate-css-region beg end)
-          (web-mode-invalidate-javascript-region beg end))
+       ((and web-mode-enable-block-partial-invalidation
+             (= web-mode-change-flags 1)
+             (not (looking-back "\\*/\\|\\?>"))
+             (progn
+               (setq chunk (buffer-substring-no-properties beg end))
+               (not (string-match-p "\\*/\\|\\?>" chunk))
+               )
+             (not self-insertion))
+        (web-mode-invalidate-block-region beg end)
         )
 
-       ((and nil
-             web-mode-has-any-large-block
-             atomic-insertion
-             (not self-insertion)
-             (get-text-property beg 'block-side)
-             (member web-mode-engine '("asp")))
-        (web-mode-invalidate-asp-region beg end)
+       ((and web-mode-enable-part-partial-invalidation
+             (= web-mode-change-flags 2)
+             (not (looking-back "\\*/\\|</"))
+             (progn
+               (setq chunk (buffer-substring-no-properties beg end))
+               (not (string-match-p "\\*/\\|</" chunk))
+               )
+             (not self-insertion))
+;;        (message "partial")
+        (web-mode-invalidate-part-region beg end)
         )
 
        (t
-        (web-mode-scan-region (or (web-mode-previous-tag-at-bol-pos beg)
-                                  (point-min))
-                              (or (web-mode-next-tag-at-eol-pos end)
-                                  (point-max))))
-       )
-      ;;        );save-match-data
+        (setq web-mode-change-flags 0)
+        (web-mode-invalidate-region beg (if auto-opened (1+ end) end))
+        ) ;t
+
+       ) ;cond
+      ;;        ) ;save-match-data
+
+      (when auto-opened
+;;        (message "indent(%S)" (point))
+        (indent-for-tab-command)
+        )
 
       ;;-- auto-indentation
-      (when (and (not web-mode-disable-auto-indentation)
+      (when (and web-mode-enable-auto-indentation
                  (not auto-opened)
                  (or auto-closed
                      (and (> end (point-min))
                           (get-text-property (1- end) 'tag-end)
                           (get-text-property (line-beginning-position) 'tag-beg))))
         (indent-for-tab-command)
+        (when (and web-mode-highlight-end (> web-mode-highlight-end (point-max)))
+          (setq web-mode-highlight-end (point-max)))
         )
 
       (when (and (string= web-mode-engine "none")
@@ -6659,79 +8453,119 @@ Must be used in conjunction with web-mode-enable-block-face."
         (web-mode-set-engine "php")
         )
 
-      );if narrowed
+      (when (and (string= web-mode-content-type "javascript")
+                 (< (point) 16)
+                 (eq (char-after 1) ?\/)
+                 (string-match-p "@jsx" (buffer-substring-no-properties
+                                         (line-beginning-position)
+                                         (line-end-position))))
+        (web-mode-set-content-type "jsx")
+        )
+
+      ) ;if narrowed
+
+    (setq chunk nil)
+
     ))
 
-(defun web-mode-invalidate-css-region (pos-beg pos-end)
-  "Invalidate css region (only when one char has been inserted)"
-  (save-excursion
-    (let (pair part-beg part-end)
-      (if (string= web-mode-content-type "css")
-          (setq part-beg (point-min)
-                part-end (point-max))
-        (setq part-beg (web-mode-part-beginning-position pos-beg)
-              part-end (web-mode-part-end-position pos-beg)))
-      (setq pair (web-mode-css-current-rule pos-beg part-beg part-end))
-;;      (message "css region : %S > %S" (car pair) (cdr pair))
-      (web-mode-scan-region (car pair) (cdr pair) "css")
-      )))
+(defun web-mode-invalidate-region (reg-beg reg-end)
+  "Invalidate region"
+  (setq web-mode-highlight-beg (or (web-mode-previous-tag-at-bol-pos reg-beg)
+                                   (point-min))
+        web-mode-highlight-end (or (web-mode-next-tag-at-eol-pos reg-end)
+                                   (point-max)))
+;;  (message "reg-beg(%S) reg-end(%S) : hl-beg(%S) hl-end(%S)"
+;;           reg-beg reg-end web-mode-highlight-beg web-mode-highlight-end)
+  (web-mode-scan-region web-mode-highlight-beg web-mode-highlight-end)
+  )
 
-(defun web-mode-invalidate-javascript-region (pos-beg pos-end)
-  "Invalidate javascript region (only when one char has been inserted)"
+;; Note : il est important d'identifier des caractères en fin de ligne
+;; web-mode-block-tokenize travaille en effet sur les fins de lignes pour
+;; les commentaires de type //
+(defun web-mode-invalidate-block-region (pos-beg pos-end)
+  "Invalidate php region."
   (save-excursion
-    (let (beg end part-beg part-end lang is-token-char)
-      (goto-char pos-beg)
-      (setq is-token-char (not (null (member (char-before) '(?\" ?\' ?\/ ?\< ?\*)))))
-;;      (message "%S %c(%S)" pos-beg (char-before) is-token-char)
-      (if (member web-mode-content-type '("javascript" "json"))
-          (setq part-beg (point-min)
-                part-end (point-max)
-                lang web-mode-content-type)
-        (setq part-beg (web-mode-part-beginning-position pos-beg)
-              part-end (web-mode-part-end-position pos-beg)
-              lang (symbol-name (get-text-property pos-beg 'part-language))))
-      (cond
-       ((and (not is-token-char)
-             (get-text-property (1- pos-beg) 'part-token))
-;;        (message "nothing")
-        )
-       ((and (not is-token-char)
-             (progn (back-to-indentation) (setq beg (point)))
-             (if (>= beg part-beg) beg part-beg)
-             (progn (goto-char pos-end) (end-of-line) (setq end (point)))
-             (if (<= end part-end) end part-end))
-        ;;            (message "%S" (buffer-substring-no-properties beg end))
-        (web-mode-scan-part beg end lang)
-        )
-       ;;        (message "%S" (buffer-substring-no-properties part-beg part-end))
-       (t
-        (web-mode-scan-part part-beg part-end lang))
-       )
+    (let (beg end block-beg block-end)
+;;      (message "pos-beg(%S)=%S" pos-beg (get-text-property pos 'block-side))
+      (setq block-beg (web-mode-block-code-beginning-position pos-beg)
+            block-end (web-mode-block-code-end-position pos-beg))
+;;      (message "block-beg(%S) block-end(%S) pos-beg(%S) pos-end(%S)" block-beg block-end pos-beg pos-end)
+      (if (and block-beg block-end
+               (>= pos-beg block-beg)
+               (<= pos-end block-end)
+               (> block-end block-beg))
+          (progn
+            (goto-char pos-beg)
+            (if (web-mode-block-rsb "[;{}(][ ]*\n" block-beg)
+                (setq beg (match-end 0))
+              (setq beg block-beg))
+            (goto-char pos-end)
+            (if (web-mode-block-rsf "[;{})][ ]*\n" block-end)
+                (setq end (1- (match-end 0)))
+              (setq end block-end))
+            (setq web-mode-highlight-beg beg
+                  web-mode-highlight-end end)
+            (web-mode-block-tokenize beg end)
+;;            (message "tokenize beg=%S end=%S" beg end)
+            ) ;progn
+        (web-mode-invalidate-region pos-beg pos-end)
+        ) ;if
       )))
 
-;; todo : gestion du remove-text-properties (ne pas toucher à pas mal de properties : block-beg, part-side etc.)
-(defun web-mode-invalidate-asp-region (pos-beg pos-end)
-  "Invalidate asp region."
+(defun web-mode-invalidate-part-region (pos-beg pos-end)
+  "Invalidate part."
   (save-excursion
-    (let (beg end part-beg part-end)
-      (setq part-beg (web-mode-block-beginning-position pos-beg)
-            part-end (web-mode-block-end-position pos-beg))
+    (let (beg end part-beg part-end language)
+      (if (member web-mode-content-type '("css" "javascript"))
+          (setq language web-mode-content-type)
+        (setq language (symbol-name (get-text-property pos-beg 'part-side))))
+      (setq part-beg (web-mode-part-beginning-position pos-beg)
+            part-end (web-mode-part-end-position pos-beg))
+;;      (message "language(%S) pos-beg(%S) pos-end(%S) part-beg(%S) part-end(%S)"
+;;               language pos-beg pos-end part-beg part-end)
       (if (and part-beg part-end
-               (progn (goto-char pos-beg) t)
-               (not (member (char-after) '(?\" ?\' ?\/)))
-               (progn (back-to-indentation) t)
-               (setq beg (point))
-               (if (>= beg part-beg) beg part-beg)
-               (progn (goto-char pos-end) t)
-               (progn (end-of-line) t)
-               (setq end (point))
-               (if (<= end part-end) end part-end))
-            (web-mode-scan-region beg end "asp")
-        (web-mode-scan-region part-beg part-end "asp")
-        )
+               (>= pos-beg part-beg)
+               (<= pos-end part-end)
+               (> part-end part-beg))
+          (progn
+            (goto-char pos-beg)
+            (cond
+             ((string= language "javascript")
+              (if (web-mode-part-rsb "[;{}(][ ]*\n" part-beg)
+                  (setq beg (match-end 0))
+                (setq beg part-beg))
+              (goto-char pos-end)
+              (if (web-mode-part-rsf "[;{})][ ]*\n" part-end)
+                  (setq end (1- (match-end 0)))
+                (setq end part-end))
+              )
+             ((string= language "css")
+              (let (rule1 rule2)
+                (setq rule1 (web-mode-css-rule-current pos-beg))
+                (setq rule2 rule1)
+                (when (> pos-end (cdr rule1))
+                  (setq rule2 (web-mode-css-rule-current pos-end)))
+                (setq beg (car rule1)
+                      end (cdr rule2))
+                )
+;;              (message "rule-beg(%S) rule-end(%S)" beg end)
+              )
+             (t
+              (setq beg part-beg
+                    end part-end))
+             ) ;cond
+            (setq web-mode-highlight-beg beg
+                  web-mode-highlight-end end)
+            (web-mode-scan-region beg end language)
+;;            (message "[%S] scan-region beg=%S end=%S" language beg end)
+            ) ;progn
+;;        nil
+        (setq web-mode-change-flags 0)
+        (web-mode-invalidate-region pos-beg pos-end)
+        ) ;if
       )))
 
-(defun web-mode-apostrophes-replace ()
+(defun web-mode-dom-apostrophes-replace ()
   "Replace ' with ’."
   (interactive)
   (save-excursion
@@ -6743,10 +8577,10 @@ Must be used in conjunction with web-mode-enable-block-face."
       (goto-char min)
       (while (web-mode-rsf-content "\\([[:alpha:]]\\)'\\([[:alpha:]]\\)" max)
         (replace-match "\\1’\\2")
-        );while
+        ) ;while
       )))
 
-(defun web-mode-entities-encode ()
+(defun web-mode-dom-entities-encode ()
   "Replace special chars with HTML entities (e.g. é becomes &eacute;)"
   (save-excursion
     (let (regexp ms pair elt (min (point-min)) (max (point-max)))
@@ -6766,11 +8600,11 @@ Must be used in conjunction with web-mode-enable-block-face."
         (setq elt (car (rassoc elt web-mode-html-entities)))
 ;;        (message "%S" elt)
         (replace-match (concat "&" elt ";"))
-        );while
+        ) ;while
       )))
 
 ;; ½ &frac12; &#189; &#x00BD;
-(defun web-mode-entities-replace ()
+(defun web-mode-dom-entities-replace ()
   "Replace HTML entities e.g. entities &eacute; &#233; &#x00E9; become é"
   (interactive)
   (save-excursion
@@ -6799,12 +8633,12 @@ Must be used in conjunction with web-mode-enable-block-face."
           ;;        (message "pos=%S name=%S pair=%S" (point) name pair)
           (if pair (setq elt (cdr pair)))
           (if elt (setq elt (char-to-string elt)))
-          );if
+          ) ;if
         (if elt (replace-match elt))
-        );while
+        ) ;while
       )))
 
-(defun web-mode-xml-replace ()
+(defun web-mode-dom-xml-replace ()
   "Replace &, > and < in HTML content."
   (interactive)
   (save-excursion
@@ -6818,7 +8652,7 @@ Must be used in conjunction with web-mode-enable-block-face."
         (replace-match (cdr (assq (char-before) web-mode-xml-chars)) t t))
       )))
 
-(defun web-mode-quotes-replace ()
+(defun web-mode-dom-quotes-replace ()
   "Replace dumb quotes."
   (interactive)
   (save-excursion
@@ -6831,10 +8665,10 @@ Must be used in conjunction with web-mode-enable-block-face."
       (setq expr (concat (car web-mode-smart-quotes) "\\2" (cdr web-mode-smart-quotes)))
       (while (web-mode-rsf-content "\\(\"\\)\\(.\\{1,200\\}\\)\\(\"\\)" max)
         (replace-match expr)
-        );while
+        ) ;while
       )))
 
-(defun web-mode-xpath (&optional pos)
+(defun web-mode-dom-xpath (&optional pos)
   "HTML path"
   (interactive)
   (unless pos (setq pos (point)))
@@ -6847,11 +8681,68 @@ Must be used in conjunction with web-mode-enable-block-face."
       (message "/%s" (mapconcat 'identity path "/"))
       )))
 
-(defun web-mode-block-ends-with (regexp)
-  "Check if current ends with regexp"
+(defun web-mode-block-ends-with (regexp &optional pos)
+  "Check if current block ends with regexp"
+  (unless pos (setq pos (point)))
+  (save-excursion
+    (goto-char pos)
+    (save-match-data
+      (if (stringp regexp)
+          (and (web-mode-block-end)
+               (progn (backward-char) t)
+               (web-mode-block-skip-blank-backward)
+               (progn (forward-char) t)
+               (looking-back regexp))
+        (let ((pair regexp)
+              (block-beg (web-mode-block-beginning-position pos))
+              (block-end (web-mode-block-end-position pos)))
+          (and (web-mode-block-end pos)
+               (web-mode-sb (car pair) block-beg t)
+               (not (web-mode-sf (cdr pair) block-end t)))
+          ) ;let
+        ) ;if
+      )))
+
+(defun web-mode-block-starts-with (regexp &optional pos)
+  "Check if current block starts with regexp"
+  (unless pos (setq pos (point)))
   (save-excursion
-    (and (web-mode-block-end)
-         (looking-back regexp))
+    (and (web-mode-block-beginning)
+         (web-mode-block-skip-blank-forward)
+         (looking-at regexp))
+    ))
+
+(defun web-mode-block-skip-blank-backward (&optional pos)
+  "skip backward"
+  (unless pos (setq pos (point)))
+  (let ((continue t))
+    (goto-char pos)
+    (while continue
+      (if (and (get-text-property (point) 'block-side)
+               (not (bobp))
+               (or (member (char-after) '(?\s ?\n))
+                   (member (get-text-property (point) 'block-token) '(delimiter comment))))
+          (backward-char)
+        (setq continue nil))
+      ) ;while
+;;    (message "pt=%S" (point))
+    (point)
+    ))
+
+(defun web-mode-block-skip-blank-forward (&optional pos)
+  "skip forward"
+  (unless pos (setq pos (point)))
+  (let ((continue t))
+    (goto-char pos)
+    (while continue
+      (if (and (get-text-property (point) 'block-side)
+               (or (eq (char-after) ?\s)
+                   (member (get-text-property (point) 'block-token) '(delimiter comment))))
+          (forward-char)
+        (setq continue nil))
+      ) ;while
+;;    (message "pt=%S" (point))
+    (point)
     ))
 
 ;;-- position -----------------------------------------------------------------------
@@ -6871,6 +8762,7 @@ Must be used in conjunction with web-mode-enable-block-face."
                    ("]" . "[\]\[]")
                    ("}" . "[}{]")))
           pt
+          (counter 0)
           regexp)
       (setq paren (string (char-after)))
       ;;      (message "paren=%S" paren)
@@ -6890,13 +8782,42 @@ Must be used in conjunction with web-mode-enable-block-face."
                           pt (point))))
             (setq n (1- n)))
           ;;          (message "n=%S" n)
-          );unless
+          ) ;unless
+        (setq counter (1+ counter))
+        (when (> counter 500)
+          (message "** web-mode-opening-paren-position invalid loop **")
+          (setq continue nil
+                pt nil))
         )
       pt
       )))
 
+(defun web-mode-closing-delimiter-position (delimiter &optional pos limit)
+  "Fetch closing delimiter."
+  (save-excursion
+    (unless pos (setq pos (point)))
+    (unless limit (setq limit nil))
+    (goto-char pos)
+    (setq pos nil)
+    (let ((continue t))
+      (while (and continue (re-search-forward delimiter limit t))
+        (setq continue nil
+              pos (1- (point)))
+        ) ;while
+      pos)))
+
+(defun web-mode-closing-paren (limit)
+  "web-mode-closing-paren"
+  (let (pos)
+    (setq pos (web-mode-closing-paren-position (point) limit))
+    (if (or (null pos) (> pos limit))
+        nil
+      (goto-char pos)
+      pos)
+    ))
+
 (defun web-mode-closing-paren-position (&optional pos limit)
-  "Fetch opening paren."
+  "Fetch closing paren."
   (save-excursion
     (unless pos (setq pos (point)))
     (unless limit (setq limit nil))
@@ -6912,13 +8833,16 @@ Must be used in conjunction with web-mode-enable-block-face."
           regexp)
       (setq paren (string (char-after)))
       (setq regexp (cdr (assoc paren pairs)))
-      (if (null regexp) (setq continue nil))
-      (setq block-side (and (get-text-property pos 'block-side)
-                            (not (string= web-mode-engine "razor"))))
+      (if (null regexp)
+          (setq continue nil)
+        (setq block-side (and (get-text-property pos 'block-side)
+                              (not (string= web-mode-engine "razor")))))
+;;      (message "limit=%S" limit)
       (while (and continue (re-search-forward regexp limit t))
+;;        (message "paren=%S regexp=%S ici=%S %S bs=%S" paren regexp (point) (web-mode-is-comment-or-string) block-side)
         (unless (or (web-mode-is-comment-or-string)
                     (and block-side (not (get-text-property (point) 'block-side))))
-          ;;          (message "char-before=%S pt=%S" (string (char-before)) (point))
+;;          (message "char-before=%S pt=%S" (string (char-before)) (point))
           (if (string= (string (char-before)) paren)
               (setq n (1+ n))
             (setq n (1- n))
@@ -6926,14 +8850,20 @@ Must be used in conjunction with web-mode-enable-block-face."
               (setq continue nil
                     pt (1- (point))))
             )
-          ;;        (message "pt=%S char=%S n=%S" (point) (string (char-before)) n)
-          )
-        )
+;;          (message "pt=%S char=%S n=%S" (point) (string (char-before)) n)
+          ) ;unless
+        ) ;while
       ;;      (message "n=%S pt=%S" n pt)
       pt
       )))
 
-(defun web-mode-opening-paren-block-position (pos limit)
+(defun web-mode-block-opening-paren (pos limit)
+  "opening paren"
+  (setq pos (web-mode-block-opening-paren-position pos limit))
+  (when pos (goto-char pos))
+  )
+
+(defun web-mode-block-opening-paren-position (pos limit)
   "Is opened code line."
   (save-excursion
     (goto-char pos)
@@ -6961,21 +8891,24 @@ Must be used in conjunction with web-mode-enable-block-face."
             (setq c (cdr (assoc c pairs)))
             (setq n (gethash c h 0))
             (puthash c (1- n) h))
-           );cond
-          );unless
-        );while
+           ) ;cond
+          ) ;unless
+        ) ;while
       ;;      (message "h=%S pt=%S" h pt)
       pt
       )))
 
 (defun web-mode-previous-tag-at-bol-pos (pos)
-  "Line beginning with and HTML tag. BOL is returned or nil."
+  "Line beginning with an HTML tag. BOL is returned or nil."
   (save-excursion
     (goto-char pos)
     (setq pos nil)
     (let ((continue t))
       (back-to-indentation)
-      (if (get-text-property (point) 'tag-beg)
+      (if (and (get-text-property (point) 'tag-beg)
+               (not (get-text-property (point) 'part-side))
+               (not (get-text-property (point) 'block-side))
+               )
           (setq pos (line-beginning-position))
         (while continue
           (forward-line -1)
@@ -6983,11 +8916,15 @@ Must be used in conjunction with web-mode-enable-block-face."
           (when (bobp)
             (setq continue nil))
           (back-to-indentation)
-          (if (get-text-property (point) 'tag-beg)
+          (if (and (get-text-property (point) 'tag-beg)
+                   (not (get-text-property (point) 'part-side))
+                   (not (get-text-property (point) 'block-side))
+                   )
               (setq continue nil)
             (setq pos nil))
-          );while
-        );if
+          ) ;while
+        ) ;if
+;;      (message "pos=%S" pos)
       pos)))
 
 (defun web-mode-next-tag-at-eol-pos (pos)
@@ -7002,20 +8939,37 @@ Must be used in conjunction with web-mode-enable-block-face."
           (setq continue nil))
         (skip-chars-backward " ")
         (if (and (> (point) (point-min))
-                 (get-text-property (1- (point)) 'tag-end))
-            (setq continue nil)
+                 (get-text-property (1- (point)) 'tag-end)
+                 (not (and (member (get-text-property (1- (point)) 'tag-name) '("script" "style"))
+                           (eq (get-text-property (1- (point)) 'tag-type) 'start)))
+                 (not (get-text-property (1- (point)) 'part-side))
+                 (not (get-text-property (1- (point)) 'block-side)))
+            (progn
+              ;; (message "point(%S) %S %S %S"
+              ;;          (point)
+              ;;          (get-text-property (1- (point)) 'tag-end)
+              ;;          (get-text-property (1- (point)) 'part-side)
+              ;;          (get-text-property (1- (point)) 'block-side))
+              (setq continue nil))
           (setq pos nil))
         (if continue (forward-line))
-        );while
+        ) ;while
       pos)))
 
 (defun web-mode-tag-match-position (&optional pos)
-  "Match tag position."
+  "Html tag match position."
   (unless pos (setq pos (point)))
   (save-excursion
     (web-mode-tag-match pos)
     (if (= pos (point)) nil (point))))
 
+(defun web-mode-block-match-position (&optional pos)
+  "Match block position."
+  (unless pos (setq pos (point)))
+  (save-excursion
+    (web-mode-block-match pos)
+    (if (= pos (point)) nil (point))))
+
 (defun web-mode-tag-beginning-position (&optional pos)
   "Beginning position of the current tag. POINT is at <."
   (unless pos (setq pos (point)))
@@ -7025,13 +8979,13 @@ Must be used in conjunction with web-mode-enable-block-face."
       (setq beg pos))
      ((and (> pos 1) (get-text-property (1- pos) 'tag-beg))
       (setq beg (1- pos)))
-     ((get-text-property pos 'tag-name)
+     ((get-text-property pos 'tag-type)
       (setq beg (1- (previous-single-property-change pos 'tag-beg)))
       (when (not (get-text-property beg 'tag-beg))
         (setq beg nil)))
      (t
       (setq beg nil))
-     );cond
+     ) ;cond
     beg))
 
 (defun web-mode-tag-end-position (&optional pos)
@@ -7039,48 +8993,81 @@ Must be used in conjunction with web-mode-enable-block-face."
   (unless pos (setq pos (point)))
   (let (end)
     (cond
+     ((null pos)
+      (setq end nil))
      ((get-text-property pos 'tag-end)
       (setq end pos))
-     ((get-text-property pos 'tag-name)
+     ((get-text-property pos 'tag-type)
       (setq end (next-single-property-change pos 'tag-end))
       (when (not (get-text-property end 'tag-end))
         (setq end nil)))
      (t
       (setq end nil))
-     );cond
+     ) ;cond
+    end))
+
+(defun web-mode-attribute-beginning-position (&optional pos)
+  "Beginning position of the current attr."
+  (unless pos (setq pos (point)))
+  (cond
+   ((null (get-text-property pos 'tag-attr))
+    nil)
+   ((null (get-text-property (1- pos) 'tag-attr))
+    pos)
+   (t
+    (previous-single-property-change pos 'tag-attr))
+   ))
+
+(defun web-mode-attribute-end-position (&optional pos)
+  "End position of the current attr."
+  (unless pos (setq pos (point)))
+  (let (end)
+    (cond
+     ((null pos)
+      (setq end nil))
+     ((get-text-property pos 'tag-attr-end)
+      (setq end pos))
+     ((get-text-property pos 'tag-attr)
+      (setq end (next-single-property-change pos 'tag-attr-end))
+      (when (not (get-text-property end 'tag-attr-end))
+        (setq end nil)))
+     (t
+      (setq end nil))
+     ) ;cond
     end))
 
 (defun web-mode-part-end-position (&optional pos)
   "End position of the current part."
   (unless pos (setq pos (point)))
   (cond
-   ((member web-mode-content-type '("css" "javascript" "json"))
+   ((member web-mode-content-type '("css" "javascript" "json" "jsx"))
     (setq pos (point-max)))
    ((not (get-text-property pos 'part-side))
     (setq pos nil))
+   ((= pos (point-max))
+    (setq pos nil))
+   ((not (get-text-property (1+ pos) 'part-side))
+    pos)
    (t
-    (setq pos (next-single-property-change pos 'tag-beg))
-    (if (not (get-text-property pos 'tag-beg))
-        (setq pos nil)
-      (setq pos (1- pos)))
-    )
-   );cond
+    (setq pos (next-single-property-change pos 'part-side)))
+   ) ;cond
   pos)
 
 (defun web-mode-part-beginning-position (&optional pos)
-  "Beginning of pat"
+  "Beginning of part"
   (unless pos (setq pos (point)))
   (cond
-   ((member web-mode-content-type '("css" "javascript" "json"))
+   ((member web-mode-content-type '("css" "javascript" "json" "jsx"))
     (setq pos (point-min)))
    ((not (get-text-property pos 'part-side))
     (setq pos nil))
+   ((= pos (point-min))
+    (setq pos nil))
+   ((not (get-text-property (1- pos) 'part-side))
+    pos)
    (t
-    (setq pos (previous-single-property-change pos 'tag-end))
-    (when (or (= pos (point-min))
-              (not (get-text-property (1- pos) 'tag-end)))
-      (setq pos nil)))
-   );cond
+    (setq pos (previous-single-property-change pos 'part-side)))
+   ) ;cond
   pos)
 
 (defun web-mode-element-beginning-position (&optional pos)
@@ -7096,7 +9083,7 @@ Must be used in conjunction with web-mode-enable-block-face."
     (setq pos (web-mode-tag-beginning-position pos)))
    (t
     (setq pos nil))
-   );cond
+   ) ;cond
   pos)
 
 (defun web-mode-element-end-position (&optional pos)
@@ -7118,7 +9105,7 @@ Must be used in conjunction with web-mode-enable-block-face."
     (when pos (setq pos (web-mode-tag-end-position pos))))
    (t
     (setq pos nil))
-   );cond
+   ) ;cond
   pos)
 
 (defun web-mode-element-child-position (&optional pos)
@@ -7129,7 +9116,7 @@ Must be used in conjunction with web-mode-enable-block-face."
       (goto-char pos)
       (cond
        ((eq (get-text-property pos 'tag-type) 'start)
-        (web-mode-match-html-tag)
+        (web-mode-tag-match)
         (setq close (point))
         (goto-char pos)
         )
@@ -7138,15 +9125,15 @@ Must be used in conjunction with web-mode-enable-block-face."
        ((eq (get-text-property pos 'tag-type) 'end)
         (web-mode-tag-beginning)
         (setq close (point))
-        (web-mode-match-html-tag)
+        (web-mode-tag-match)
         )
        ((web-mode-element-parent-position pos)
         (setq pos (point))
-        (web-mode-match-html-tag)
+        (web-mode-tag-match)
         (setq close (point))
         (goto-char pos)
         )
-       );cond
+       ) ;cond
       (when (and close
                  (web-mode-element-next)
                  (< (point) close))
@@ -7174,13 +9161,21 @@ Must be used in conjunction with web-mode-enable-block-face."
               (puthash tag-name (1- n) h)
             (puthash tag-name (1+ n) h)
             (when (= n 0) (setq continue nil))
-            );if
-          );when
-        );while
-      );save-excursion
+            ) ;if
+          ) ;when
+        ) ;while
+      ) ;save-excursion
     (if (null continue) pos nil)
     ))
 
+(defun web-mode-block-code-beginning-position (&optional pos)
+  "Block beginning position, just after the start delimiter (e.g. just after <?php)."
+  (unless pos (setq pos (point)))
+  (setq pos (web-mode-block-beginning-position pos))
+  (when (and pos (eq (get-text-property pos 'block-token) 'delimiter))
+    (setq pos (next-single-property-change pos 'block-token)))
+  pos)
+
 (defun web-mode-block-beginning-position (&optional pos)
   "web-mode-block-beginning-position"
   (unless pos (setq pos (point)))
@@ -7201,24 +9196,29 @@ Must be used in conjunction with web-mode-enable-block-face."
     )
    (t
     (setq pos nil))
-   );cond
+   ) ;cond
 ;;  (message "web-mode-block-beginning-position=%S" pos)
   pos)
 
+(defun web-mode-block-code-end-position (&optional pos)
+  (unless pos (setq pos (point)))
+  (setq pos (web-mode-block-end-position pos))
+  (when (and pos (eq (get-text-property pos 'block-token) 'delimiter) pos)
+    (setq pos (previous-single-property-change pos 'block-token)))
+  pos)
+
 (defun web-mode-block-end-position (&optional pos)
   "web-mode-block-end-position"
   (unless pos (setq pos (point)))
   (cond
    ((get-text-property pos 'block-end)
-    )
+    pos)
    ((get-text-property pos 'block-side)
-    (setq pos (or (next-single-property-change pos 'block-end)
-                  (point-max)))
-    )
+    (or (next-single-property-change pos 'block-end)
+        (point-max)))
    (t
-    (setq pos nil))
-   );cond
-  pos)
+    nil)
+   ))
 
 (defun web-mode-block-previous-position (&optional pos)
   "web-mode-block-previous-position"
@@ -7232,37 +9232,63 @@ Must be used in conjunction with web-mode-enable-block-face."
                   (eq (char-after pos) ?\n))
         (setq pos (1- pos))
         )
-      ;;            (message "pos=%S  <%c>" pos (char-after pos))
+      ;;(message "pos=%S  <%c>" pos (char-after pos))
       (if (get-text-property pos 'block-side)
           (setq pos (web-mode-block-beginning-position pos))
         (setq pos (previous-single-property-change pos 'block-side))
-        (when (and pos (> pos (point-min)))
+        (cond
+         ((and pos (get-text-property pos 'block-beg))
+          )
+         ((and pos (> pos (point-min)))
           (setq pos (web-mode-block-beginning-position (1- pos))))
-        );if
-      );when
-    )
+         )
+        ) ;if
+      ) ;when
+    ) ;block-side
    (t
     (setq pos (previous-single-property-change pos 'block-side))
     (when (and pos (> pos (point-min)))
       (setq pos (web-mode-block-beginning-position (1- pos))))
     )
-   );conf
+   ) ;conf
   pos)
 
 (defun web-mode-block-next-position (&optional pos)
   "web-mode-block-next-position"
   (unless pos (setq pos (point)))
-  (if (get-text-property pos 'block-side)
+  (cond
+   ((and (get-text-property pos 'block-side)
+         (setq pos (web-mode-block-end-position pos))
+         (setq pos (1+ pos))
+         ;;    (when (and
+         ;;         pos
+         (> (point-max) pos)
+         (not (get-text-property pos 'block-side)))
+    ;;      (setq pos (1+ pos))
+    ;;      (when (not (get-text-property pos 'block-side))
+    (setq pos (next-single-property-change pos 'block-side))
+    ;;      )
+    ;;    ) ;when
+    )
+   (t
+    (setq pos (next-single-property-change pos 'block-side)))
+   ) ;cond
+  pos)
+
+(defun web-mode-part-next-position (&optional pos)
+  "web-mode-part-next-position"
+  (unless pos (setq pos (point)))
+  (if (get-text-property pos 'part-side)
       (if (= pos (point-min))
           (set pos (point-min))
-        (setq pos (web-mode-block-end-position pos))
+        (setq pos (web-mode-part-end-position pos))
         (when (and pos (> (point-max) pos))
           (setq pos (1+ pos))
-          (if (not (get-text-property pos 'block-side))
-              (setq pos (next-single-property-change pos 'block-side)))
-          );when
+          (if (not (get-text-property pos 'part-side))
+              (setq pos (next-single-property-change pos 'part-side)))
+          ) ;when
         )
-    (setq pos (next-single-property-change pos 'block-side)))
+    (setq pos (next-single-property-change pos 'part-side)))
   pos)
 
 ;;--- /positions
@@ -7314,11 +9340,67 @@ Must be used in conjunction with web-mode-enable-block-face."
     (when pos (goto-char pos)))
   pos)
 
+(defun web-mode-tag-attributes-sort (&optional pos)
+  "Sort attributes"
+  (interactive)
+  (unless pos (setq pos (point)))
+  (save-excursion
+    (let (attrs (continue t) min max tag-beg tag-end attr attr-name attr-beg attr-end indent indentation sorter ins)
+      (if (not (member (get-text-property pos 'tag-type) '(start void)))
+          nil
+        (setq tag-beg (web-mode-tag-beginning-position pos)
+              tag-end (web-mode-tag-end-position))
+;;        (message "%S %S" tag-beg tag-end)
+        (goto-char tag-beg)
+        (while continue
+          (if (or (not (web-mode-attribute-next))
+                  (>= (point) tag-end))
+              (setq continue nil)
+            ;;(message "attr=%S" (point))
+            (setq attr-beg (web-mode-attribute-beginning-position)
+                  attr-end (1+ (web-mode-attribute-end-position)))
+            (when (null min)
+              (setq min attr-beg))
+            (setq max attr-end)
+            (goto-char attr-beg)
+            (setq attr (buffer-substring-no-properties attr-beg attr-end))
+            (if (string-match "^\\([[:alnum:]-]+\\)=" attr)
+                (setq attr-name (match-string-no-properties 1 attr))
+              (setq attr-name attr))
+            (setq indent (looking-back "^[ \t]*"))
+            (setq attrs (append attrs (list (list attr-beg attr-end attr-name attr indent))))
+            ) ;if
+          ) ;while
+        ) ;if in tag
+      (when attrs
+        (setq sorter (function
+                      (lambda (elt1 elt2)
+                        (string< (nth 2 elt1) (nth 2 elt2))
+                        )))
+        (setq attrs (sort attrs sorter))
+        (delete-region (1- min) max)
+        (setq ins "")
+        (dolist (elt attrs)
+          (if (and (nth 4 elt) (> (length ins) 1))
+              (setq ins (concat ins "\n"))
+            (setq ins (concat ins " ")))
+          (setq ins (concat ins (nth 3 elt)))
+          )
+        (goto-char (1- min))
+        (insert ins)
+        (web-mode-tag-beginning)
+        (setq min (line-beginning-position))
+        (web-mode-tag-end)
+        (setq max (line-end-position))
+        (indent-region min max)
+        )
+      ;;(message "attrs=%S" attrs)
+      )))
+
 (defun web-mode-skip-html-tag (&optional back bound context)
   "Skip html tag. (smartparens helper)"
   (interactive)
   (let ((pos (point)) mb me skipped back delim)
-
     (cond
      (back
       (unless (or (bobp)
@@ -7326,15 +9408,14 @@ Must be used in conjunction with web-mode-enable-block-face."
         (when (web-mode-tag-previous)
           (web-mode-tag-end)
           )
-        );unless
+        ) ;unless
       )
      (t
       (unless (or (eobp)
                   (get-text-property pos 'tag-beg))
         (web-mode-tag-next))
       )
-     );cond
-
+     ) ;cond
     (cond
      ((get-text-property (point) 'tag-beg)
       (setq mb (point)
@@ -7343,10 +9424,9 @@ Must be used in conjunction with web-mode-enable-block-face."
      ((and (not (bobp))
            (get-text-property (1- (point)) 'tag-end))
       (setq mb (point)
-            me (web-mode-tag-beginning-position (1- point)))
+            me (web-mode-tag-beginning-position (1- (point))))
       )
-     );cond
-
+     ) ;cond
     (if (and mb me)
         (progn
           (setq skipped (- (point) pos))
@@ -7355,16 +9435,15 @@ Must be used in conjunction with web-mode-enable-block-face."
           (list :mb mb :me me :skipped skipped :back back :delim delim)
           )
       nil)
-
     ))
 
 (defun web-mode-get-html-tag (&optional back bound context)
   "Get html tag. (smartparens helper)"
   (interactive)
   (let (ctx beg end (pos (point)))
-    (message "pos=%S" pos)
+;;    (message "pos=%S" pos)
     (setq ctx (web-mode-skip-html-tag back bound context))
-    (message "ctx=%S" ctx)
+;;    (message "ctx=%S" ctx)
     (cond
      ((null ctx)
 ;;      (message "ici")
@@ -7395,30 +9474,82 @@ Must be used in conjunction with web-mode-enable-block-face."
      (t
       (setq out "")
       )
-     );cond
+     ) ;cond
     out
     ))
 
-(defun web-mode-attr-next (&optional pos)
-  "Fetch next attr."
+(defun web-mode-attribute-beginning (&optional pos)
+  "Fetch html attribute end."
+  (interactive)
+  (unless pos (setq pos (point)))
+  (setq pos (web-mode-attribute-beginning-position pos))
+  (when pos (goto-char pos))
+  pos)
+
+(defun web-mode-attribute-end (&optional pos)
+  "Fetch html attribute end."
   (interactive)
+  (unless pos (setq pos (point)))
+  (setq pos (web-mode-attribute-end-position pos))
+  (when pos
+    (setq pos (1+ pos))
+    (goto-char pos))
+  pos)
+
+(defun web-mode-attribute-next-position (&optional pos)
+  "Next attribute position."
   (let ((continue t))
     (unless pos (setq pos (point)))
     (while continue
-      (setq pos (next-single-property-change pos 'part-token))
-;;      (message "pos=%S" pos)
+      (setq pos (next-single-property-change pos 'tag-attr))
       (cond
        ((null pos)
         (setq continue nil
               pos nil))
-       ((eq (get-text-property pos 'part-token) 'attr)
+       ((get-text-property pos 'tag-attr)
         (setq continue nil)
         )
        )
-      );while
-    (when pos (goto-char pos))
+      ) ;while
     pos))
 
+(defun web-mode-attribute-next (&optional pos)
+  "Fetch next attribute."
+  (interactive)
+  (setq pos (web-mode-attribute-next-position pos))
+  (when pos (goto-char pos))
+  pos)
+
+(defun web-mode-attribute-transpose (&optional pos)
+  "Transpose attribute"
+  (interactive)
+  (unless pos (setq pos (point)))
+  (let (ret attr-beg attr-end next-beg next-end tag-end)
+    (when (and (get-text-property pos 'tag-attr)
+               (setq next-beg (web-mode-attribute-next-position pos))
+               (setq next-end (web-mode-attribute-end-position next-beg))
+               (setq tag-end (web-mode-tag-end-position pos))
+               (> tag-end next-end)
+               )
+      (setq attr-beg (web-mode-attribute-beginning-position pos)
+            attr-end (web-mode-attribute-end-position pos))
+;;      (message "%S %S - %S %S" attr-beg attr-end next-beg next-end)
+      (transpose-regions attr-beg (1+ attr-end) next-beg (1+ next-end))
+      )))
+
+(defun web-mode-attribute-select (&optional pos)
+  "Select attribute."
+  (interactive)
+  (unless pos (setq pos (point)))
+  (if (null (get-text-property pos 'tag-attr))
+      nil
+    (goto-char pos)
+    (web-mode-attribute-beginning)
+    (set-mark (point))
+    (web-mode-attribute-end)
+    (point)
+    ))
+
 (defun web-mode-element-previous ()
   "Fetch previous element."
   (interactive)
@@ -7430,7 +9561,7 @@ Must be used in conjunction with web-mode-enable-block-face."
                 (member (get-text-property (point) 'tag-type) props))
         (setq continue nil)
         )
-      );while
+      ) ;while
     (unless ret (goto-char pos))
     ret))
 
@@ -7445,7 +9576,7 @@ Must be used in conjunction with web-mode-enable-block-face."
                 (member (get-text-property (point) 'tag-type) props))
         (setq continue nil)
         )
-      );while
+      ) ;while
     (unless ret (goto-char pos))
     ret))
 
@@ -7457,29 +9588,25 @@ Must be used in conjunction with web-mode-enable-block-face."
       (cond
        ((not (get-text-property pos 'tag-type))
         (when (and (web-mode-element-parent)
-                   (web-mode-match-html-tag)
+                   (web-mode-tag-match)
                    (web-mode-element-next))
           (setq ret (point))
           )
         )
        ((eq (get-text-property pos 'tag-type) 'start)
-        (when (and (web-mode-match-html-tag)
+        (when (and (web-mode-tag-match)
                    (web-mode-element-next))
           (setq ret (point))
           )
         )
-       (t
-        (when (web-mode-element-next)
-          (setq ret (point))
-          )
+       ((web-mode-element-next)
+        (setq ret (point))
         )
-       );cond
-
-      );save
+       ) ;cond
+      ) ;save
     (if ret (goto-char ret))
     ))
 
-
 (defun web-mode-element-beginning (&optional pos)
   "Move to beginning of element."
   (interactive)
@@ -7514,7 +9641,7 @@ Must be used in conjunction with web-mode-enable-block-face."
   (when pos (goto-char pos))
   pos)
 
-(defun web-mode-element-traverse ()
+(defun web-mode-dom-traverse ()
   "Traverse html dom tree."
   (interactive)
   (cond
@@ -7526,7 +9653,7 @@ Must be used in conjunction with web-mode-enable-block-face."
     (unless (web-mode-element-sibling-next)
       (goto-char (point-min)))
     )
-   );cond
+   ) ;cond
   )
 
 (defun web-mode-block-close (&optional pos)
@@ -7537,7 +9664,7 @@ Must be used in conjunction with web-mode-enable-block-face."
     (save-excursion
       (setq h (make-hash-table :test 'equal))
       (while (and continue (web-mode-block-previous))
-        (when (setq ctx (web-mode-is-active-block (point)))
+        (when (setq ctx (web-mode-block-is-control (point)))
           (setq ctrl (car ctx))
           (setq n (gethash ctrl h 0))
           (if (cdr ctx)
@@ -7548,8 +9675,8 @@ Must be used in conjunction with web-mode-enable-block-face."
             (setq continue nil))
 ;;          (if ctx (message "(%S) %S : %S" (point) ctrl (gethash ctrl h)))
           )
-        );while
-      );save-excursion
+        ) ;while
+      ) ;save-excursion
     (when (and (null continue)
                (setq closing-block (web-mode-closing-block ctrl)))
       (insert closing-block)
@@ -7574,7 +9701,7 @@ Must be used in conjunction with web-mode-enable-block-face."
     "<% end %>")
    (t
     (cdr (assoc type web-mode-closing-blocks)))
-   );cond
+   ) ;cond
   )
 
 (defun web-mode-block-previous (&optional pos)
@@ -7593,6 +9720,14 @@ Must be used in conjunction with web-mode-enable-block-face."
   (when pos (goto-char pos))
   pos)
 
+(defun web-mode-part-next (&optional pos)
+  "Move point to the beginning of the next part."
+  (interactive)
+  (unless pos (setq pos (point)))
+  (setq pos (web-mode-part-next-position pos))
+  (when pos (goto-char pos))
+  pos)
+
 (defun web-mode-block-beginning (&optional pos)
   "Move point to the beginning of the current block."
   (interactive)
@@ -7638,49 +9773,119 @@ Must be used in conjunction with web-mode-enable-block-face."
         (when (< level 1)
           (setq continue nil)
           )
-        );t
-       );cond
-      );while
+        ) ;t
+       ) ;cond
+      ) ;while
+    ret))
+
+(defun web-mode-block-rsb (regexp &optional limit)
+  "re-search-backward inside a block (outside tokens)."
+  (unless limit (setq limit (web-mode-block-beginning-position (point))))
+  (let ((continue t) ret)
+    (while continue
+      (setq ret (re-search-backward regexp limit t))
+      (when (or (null ret)
+                (not (get-text-property (point) 'block-token)))
+        (setq continue nil)
+        ) ;when
+      ) ;while
+    ret))
+
+(defun web-mode-block-rsf (regexp &optional limit)
+  "re-search-backward inside a block (outside tokens)."
+  (unless limit (setq limit (web-mode-block-end-position (point))))
+  (let ((continue t) ret)
+    (while continue
+      (setq ret (re-search-forward regexp limit t))
+      (when (or (null ret)
+                (not (get-text-property (point) 'block-token)))
+        (setq continue nil)
+        ) ;when
+      ) ;while
     ret))
 
-(defun web-mode-sb-client (regexp &optional limit noerror)
-  "search-backward in client."
+(defun web-mode-part-sb (expr &optional limit noerror)
+  "search-backward inside a part (outside part tokens and blocks)."
+  (unless limit (setq limit (web-mode-part-beginning-position (point))))
   (unless noerror (setq noerror t))
   (let ((continue t) ret)
     (while continue
-      (setq ret (search-backward regexp limit noerror))
-      (if (or (null ret)
-              (not (get-text-property (point) 'block-side)))
-          (setq continue nil))
-      )
+      (setq ret (search-backward expr limit noerror))
+      (when (or (null ret)
+                (and (not (get-text-property (point) 'part-token))
+                     (not (get-text-property (point) 'block-side)))
+                )
+        (setq continue nil)
+        ) ;when
+      ) ;while
     ret))
 
-(defun web-mode-rsb-client (regexp &optional limit noerror)
-  "re-search-backward in client."
+(defun web-mode-part-rsb (regexp &optional limit noerror)
+  "re-search-backward inside a part (outside part tokens and blocks)."
+  (unless limit (setq limit (web-mode-part-beginning-position (point))))
   (unless noerror (setq noerror t))
   (let ((continue t) ret)
     (while continue
       (setq ret (re-search-backward regexp limit noerror))
-      (if (or (null ret)
-              (not (get-text-property (point) 'block-side)))
-          (setq continue nil))
-      )
+      (when (or (null ret)
+                (and (not (get-text-property (point) 'part-token))
+                     (not (get-text-property (point) 'block-side)))
+                )
+        (setq continue nil)
+        ) ;when
+      ) ;while
+    ret))
+
+(defun web-mode-part-sf (expr &optional limit noerror)
+  "search-forward inside a part (outside part tokens and block)."
+  (unless limit (setq limit (web-mode-part-end-position (point))))
+  (unless noerror (setq noerror t))
+  (let ((continue t) ret)
+    (while continue
+      (setq ret (search-forward expr limit noerror))
+      (when (or (null ret)
+                (and (not (get-text-property (point) 'part-token))
+                     (not (get-text-property (point) 'block-side)))
+                )
+        (setq continue nil)
+        ) ;when
+      ) ;while
     ret))
 
-(defun web-mode-rsf-client (regexp &optional limit noerror)
-  "re-search-forward in client."
+(defun web-mode-part-rsf (regexp &optional limit noerror)
+  "re-search-forward inside a part (outside part tokens and block)."
+  (unless limit (setq limit (web-mode-part-end-position (point))))
   (unless noerror (setq noerror t))
   (let ((continue t) ret)
+    (while continue
+      (setq ret (re-search-forward regexp limit t))
+      (when (or (null ret)
+                (and (not (get-text-property (point) 'part-token))
+                     (not (get-text-property (point) 'block-side)))
+                )
+        (setq continue nil)
+        ) ;when
+      ) ;while
+    ret))
+
+(defun web-mode-dom-rsf (regexp &optional limit noerror)
+  "re-search-forward outside blocks."
+  (unless noerror (setq noerror t))
+  (let ((continue t)
+        (ret nil))
+;;    (when (> (point) limit)
+;;      (message "(web-mode-dom-rsf) point(%S) is after limit(%S)" (point) limit)
+;;      (setq continue nil))
     (while continue
       (setq ret (re-search-forward regexp limit noerror))
       (if (or (null ret)
               (not (get-text-property (match-beginning 0) 'block-side)))
           (setq continue nil))
-      );while
+      )
     ret))
 
-(defun web-mode-sf-client (expr &optional limit noerror)
-  "search-forward in client."
+(defun web-mode-dom-sf (expr &optional limit noerror)
+  "search-forward outside blocks."
   (unless noerror (setq noerror t))
   (let ((continue t) ret)
     (while continue
@@ -7768,8 +9973,8 @@ Must be used in conjunction with web-mode-enable-block-face."
             end (if (null ret) (point) (1- (match-end 0))))
 ;;      (message "pt=%S" pos)
       (if (or (null ret)
-              (and (web-mode-is-html-text beg)
-                   (web-mode-is-html-text end)))
+              (and (web-mode-is-content beg)
+                   (web-mode-is-content end)))
           (setq continue nil)))
     ret))
 
@@ -7783,23 +9988,45 @@ Must be used in conjunction with web-mode-enable-block-face."
   (save-excursion
     (let ((continue t) (counter 0))
       (beginning-of-line)
+      (back-to-indentation)
       (while (and continue (not (eolp)))
-        (if (web-mode-is-comment-or-string)
-            (setq counter (1+ counter))
-          (when (not (eq ?\s (following-char)))
-            (setq continue nil
-                  counter 0))
-          );if
+        (cond
+         ((web-mode-is-comment-or-string)
+          (setq counter (1+ counter)))
+         ((not (eq ?\s (following-char)))
+          (setq continue nil
+                counter 0))
+         ) ;cond
+        (forward-char)
+        ) ;while
+      (> counter 0)
+      )))
+
+(defun web-mode-block-is-token-line ()
+  "Detect if current line is a comment or a string."
+  (save-excursion
+    (let ((continue t) (counter 0))
+      (beginning-of-line)
+      (back-to-indentation)
+      (while (and continue (not (eolp)))
+        (cond
+         ((web-mode-block-is-token)
+          (setq counter (1+ counter)))
+         ((not (eq ?\s (following-char)))
+          (setq continue nil
+                counter 0))
+         ) ;cond
         (forward-char)
-        );while
+        ) ;while
       (> counter 0)
       )))
 
 (defun web-mode-is-part-token-or-server (&optional pos)
   "Detect if POS is in a comment, a string or in server script."
   (unless pos (setq pos (point)))
-  (or (get-text-property pos 'block-side)
-      (not (null (member (get-text-property pos 'part-token) '(string comment))))))
+  (not (null (or (get-text-property pos 'block-side)
+                 (member (get-text-property pos 'part-token) '(comment string)))))
+  )
 
 (defun web-mode-is-part-token-line ()
   "Detect if current line has only client tokens (string/comment) or server blocks."
@@ -7812,34 +10039,53 @@ Must be used in conjunction with web-mode-enable-block-face."
           (when (not (eq ?\s (following-char)))
             (setq continue nil
                   counter 0))
-          );if
+          ) ;if
         (forward-char)
-        );while
+        ) ;while
       (> counter 0)
       )))
 
-(defun web-mode-is-html-text (&optional pos)
-  "Is point in a html text."
+(defun web-mode-is-content (&optional pos)
+  "Is pos in a html text."
   (unless pos (setq pos (point)))
   (not (or (get-text-property pos 'part-side)
            (get-text-property pos 'tag-type)
            (get-text-property pos 'block-side)
            )))
 
+(defun web-mode-block-is-token (&optional pos)
+  "Detect if point is in a comment or in a string."
+  (unless pos (setq pos (point)))
+  (not (null (get-text-property pos 'block-token)))
+  )
+
 (defun web-mode-is-comment-or-string (&optional pos)
   "Detect if point is in a comment or in a string."
   (unless pos (setq pos (point)))
-  (or (memq (get-text-property pos 'block-token) '(string comment))
-      (memq (get-text-property pos 'part-token) '(string comment))))
+  (not (null (or (eq (get-text-property pos 'tag-type) 'comment)
+                 (member (get-text-property pos 'block-token) '(comment string))
+                 (member (get-text-property pos 'part-token) '(comment string)))))
+  )
 
 (defun web-mode-is-comment (&optional pos)
   "Detect if point is in a comment."
   (unless pos (setq pos (point)))
-  (or (eq (get-text-property pos 'block-token) 'comment)
-      (eq (get-text-property pos 'part-token) 'comment)))
+  (not (null (or (eq (get-text-property pos 'tag-type) 'comment)
+                 (eq (get-text-property pos 'block-token) 'comment)
+                 (eq (get-text-property pos 'part-token) 'comment))))
+  )
 
 ;;--- end search
 
+(defun web-mode-on-exit ()
+  "Exit web-mode."
+  (interactive)
+  (web-mode-with-silent-modifications
+   (put-text-property (point-min) (point-max) 'invisible nil)
+   (remove-overlays)
+   (remove-hook 'change-major-mode-hook 'web-mode-on-exit t)
+   ))
+
 (defun web-mode-reload ()
   "Reload web-mode."
   (interactive)
@@ -7847,8 +10093,8 @@ Must be used in conjunction with web-mode-enable-block-face."
    (setq web-mode-time nil)
    (put-text-property (point-min) (point-max) 'invisible nil)
    (remove-overlays)
-   (unload-feature 'web-mode)
-   (setq web-mode-disable-css-colorization t)
+   (unload-feature 'web-mode t)
+   (load "web-mode.el")
    (web-mode)
    (if (fboundp 'web-mode-hook)
        (web-mode-hook))))
@@ -7856,13 +10102,28 @@ Must be used in conjunction with web-mode-enable-block-face."
 (defun web-mode-trace (msg)
   "Benchmark."
   (interactive)
-  (let (sub)
-    (when nil
+  (let (sub trace)
+    (setq trace nil)
+    (when trace
       (when (null web-mode-time) (setq web-mode-time (current-time)))
       (setq sub (time-subtract (current-time) web-mode-time))
       (message "%18s: time elapsed = %Ss %9Sµs" msg (nth 1 sub) (nth 2 sub))
       )))
 
+(defun web-mode-reveal ()
+  "Display text properties at point"
+  (interactive)
+  (let (symbol symbols out)
+    (setq symbols (append web-mode-scan-properties '(face)))
+    (setq out (format "[point=%S engine=%S content-type=%S]\n" (point) web-mode-engine web-mode-content-type))
+    (dolist (symbol symbols)
+      (when symbol
+        (setq out (concat out (format "%s(%S) " (symbol-name symbol) (get-text-property (point) symbol)))))
+      )
+    (message "%s\n" out)
+    (message nil)
+    ))
+
 (defun web-mode-debug ()
   "Display informations useful for debuging"
   (interactive)
@@ -7891,7 +10152,7 @@ Must be used in conjunction with web-mode-enable-block-face."
                 (if (and (symbolp mode) (symbol-value mode))
                     (add-to-list 'modes mode))
               (error nil))
-            );lambda
+            ) ;lambda
           minor-mode-list)
     (message "%S" modes)
     (message "--- WEB-MODE DEBUG END ---")
@@ -7900,11 +10161,168 @@ Must be used in conjunction with web-mode-enable-block-face."
     (recenter)
   ))
 
+;;; web-mode.el ends here
 (provide 'web-mode)
 
+;; tag-beg: flags
+;; (1)attrs (2)custom (4)slash-beg (8)slash-end (16)bracket-end
+
 ;; Local Variables:
 ;; coding: utf-8
 ;; indent-tabs-mode: nil
 ;; End:
 
-;;; web-mode.el ends here
+
+
+
+;; ;; http://www.w3.org/TR/html-markup/syntax.html#syntax-attributes
+;; ;; states:
+;; ;; nil(0) space(1) name(2) space-before(3) equal(4) space-after(5) value-uq(6) value-sq(7) value-dq(8)
+;; (defun web-mode-scan-attrs (beg end)
+;;   "Scan html attributes."
+;;   (save-excursion
+;; ;;    (message "beg(%S) end(%S)" beg end)
+;;     (let (name-beg name-end val-beg (count 0) (state 0) (flags 0) (equal-offset 0) char pos escaped spaced)
+
+;;       (goto-char (1- beg))
+
+;;       (while (< (point) end)
+;;         (forward-char)
+;;         (setq pos (point)
+;;               char (char-after))
+;;         (setq spaced (eq char ?\s))
+
+;;         (cond
+
+;;          ((= pos end)
+;;           (when name-beg
+;;             (setq count (+ count (web-mode-scan-attr state char name-beg name-end val-beg flags equal-offset) 0)))
+;;           (setq state 0
+;;                 flags 0
+;;                 equal-offset 0
+;;                 name-beg nil
+;;                 name-end nil
+;;                 val-beg nil)
+;;           )
+
+;;          ((get-text-property pos 'block-side)
+;;           )
+
+;;          ((and spaced (= state 0))
+;;           (setq state 1)
+;;           )
+
+;;          ((and spaced (member state '(1 3 5)))
+;;           )
+
+;;          ((and spaced (= state 2))
+;;           (setq state 3)
+;;           )
+
+;;          ((and spaced (= state 4))
+;;           (setq state 5)
+;;           )
+
+;;          ((and (= state 3)
+;; ;;               (progn (message "pt=%S state=%S char=%c" (point) state char) t)
+;;                (or (eq char ?\-)
+;;                    (and (>= char 65) (<= char 90)) ;A - Z
+;;                    (and (>= char 97) (<= char 122)) ;a - z
+;;                    ;; (= char 34) (= char 39) ; " '
+;;                    ;; (and (>= char 48) (<= char 57)) ;0 - 9
+;;                    ))
+;;           (setq count (+ count (web-mode-scan-attr state char name-beg name-end val-beg flags equal-offset)))
+;;           (setq state 2
+;;                 flags 0
+;;                 equal-offset 0
+;;                 name-beg pos
+;;                 name-end pos
+;;                 val-beg nil)
+;;           )
+
+;;          ((and (eq char ?\n) (not (member state '(7 8))))
+;;           (setq count (+ count (web-mode-scan-attr state char name-beg name-end val-beg flags equal-offset)))
+;;           (setq state 1
+;;                 flags 0
+;;                 equal-offset 0
+;;                 name-beg nil
+;;                 name-end nil
+;;                 val-beg nil)
+;;           )
+
+;;          ((or (and (eq ?\" char) (= state 8) (not escaped))
+;;               (and (eq ?\' char) (= state 7) (not escaped))
+;;               (and (member char '(?\s ?\n ?\>)) (= state 6)))
+;; ;;          (message "ici%S %S" (point) state)
+;;           (setq count (+ count (web-mode-scan-attr state char name-beg name-end val-beg flags equal-offset)))
+;;           (setq state (if (= state 6) 1 0)
+;;                 flags 0
+;;                 equal-offset 0
+;;                 name-beg nil
+;;                 name-end nil
+;;                 val-beg nil)
+;;           )
+
+;;          ((and (not spaced) (= state 1))
+;;           (setq state 2)
+;;           (setq name-beg pos
+;;                 name-end pos)
+;;           )
+
+;;          ((and (eq ?\= char) (member state '(2 3)))
+;;           (setq equal-offset (- pos name-beg))
+;;           (setq state 4)
+;;           )
+
+;;          ((and (eq ?\" char) (member state '(4 5)))
+;;           (setq val-beg pos)
+;;           (setq state 8)
+;; ;;          (setq count (+ count (web-mode-scan-attr state char name-beg name-end val-beg flags equal-offset)))
+;;           )
+
+;;          ((and (eq ?\' char) (member state '(4 5)))
+;;           (setq val-beg pos)
+;;           (setq state 7)
+;; ;;          (setq count (+ count (web-mode-scan-attr state char name-beg name-end val-beg flags equal-offset)))
+;;           )
+
+;;          ((member state '(4 5))
+;;           (setq val-beg pos)
+;;           (setq state 6)
+;;           )
+
+;;          ((= state 1)
+;;           (setq state 2)
+;;           )
+
+;;          ((= state 2)
+;;           (setq name-end pos)
+;;           (when (and (= flags 0) (eq char ?\-))
+;;             (setq flags (logior flags 1)))
+;;           (when (= (logand flags 1) 1)
+;;             (let (attr)
+;;               (setq attr (buffer-substring-no-properties name-beg (1+ name-end)))
+;;               (cond
+;;                ((member attr '("http-equiv"))
+;;                 (setq flags (1- flags))
+;;                 )
+;;                ((and web-mode-engine-attr-regexp
+;;                      (string-match-p web-mode-engine-attr-regexp attr))
+;;                 ;;            (message "%S" web-mode-engine-attr-regexp)
+;;                 (setq flags (logior flags 2))
+;;                 (setq flags (1- flags))
+;;                 )
+;;                ) ;cond
+;;               ) ;let
+;;             ) ;when flags = 1
+;;           ) ;state=2
+
+;;          ) ;cond
+
+;;         ;;(message "point(%S) end(%S) state(%S) c(%S) name-beg(%S) name-end(%S) val-beg(%S) flags(%S) equal-offset(%S)" pos end state char name-beg name-end val-beg flags equal-offset)
+
+;;         (setq escaped (eq ?\\ char))
+
+;;         ) ;while
+
+;;       count)))
diff --git a/scripts/webservice_aloes.php b/scripts/webservice_aloes.php
index d8234bd55fb1fb1842f6935fe3ca70027e5e5dad..6ac735a2586cc49db88713f574fef089e50c6781 100644
--- a/scripts/webservice_aloes.php
+++ b/scripts/webservice_aloes.php
@@ -27,14 +27,19 @@ try {
                         )
                 );
 
-        $soap_client->__soapCall("FermerSession", array("FermerSession" => array(
+				$soap_client->__soapCall("FermerSession", array("FermerSession" => array(
                         "Param" => array(
-                        "GUIDSession" => $guid
+													"NomMachine" => "INTERNET",
+													"GUIDSession" => $guid,
+													"ListeServeurs" => array(array( "BasesServeurs"=> array(),"NomServeur" => "INTERNET"))
+
                 ))));
 
         if ($notice->RecupererNoticeResult->Notice->NumNotice==$id_notice)
                 {
                 print "OK : Aloes Web Service is available.\n";
+								// to check if soap client returns errors uncomment :
+								// print $soap_client->__getLastResponse().'\n';
                 exit(0);
                 }
         else
diff --git a/tests/application/modules/AbstractControllerTestCase.php b/tests/application/modules/AbstractControllerTestCase.php
index 6be8dc4647f144017d99aea3161339a48a6fb512..a698fe5ad8003d4bf24bdbe785e1d7cc2ae93981 100644
--- a/tests/application/modules/AbstractControllerTestCase.php
+++ b/tests/application/modules/AbstractControllerTestCase.php
@@ -95,6 +95,8 @@ abstract class AbstractControllerTestCase extends Zend_Test_PHPUnit_ControllerTe
 	public function setUp() {
 		Storm_Model_Abstract::unsetLoaders();
 		$this->_registry_sql = Zend_Registry::get('sql');
+		if (!is_object($this->_registry_sql))
+			$this->fail('SQL in registry should be an object');
 		Class_ScriptLoader::resetInstance();
 
 		$this->_initMockProfil();
@@ -146,6 +148,7 @@ abstract class AbstractControllerTestCase extends Zend_Test_PHPUnit_ControllerTe
 		Class_WebService_Abstract::resetHttpClient();
 		Class_WebService_AllServices::setHttpClient(null);
 		Class_I18n::reset();
+    ZendAfi_Form_Element_Captcha::reset();
 	}
 
 
@@ -156,16 +159,6 @@ abstract class AbstractControllerTestCase extends Zend_Test_PHPUnit_ControllerTe
 	}
 
 
-	public function getSqlMock() {
-		$mock_sql = $this->getMockBuilder('Class_Systeme_Sql')
-                         			->disableOriginalConstructor()
-                        			->getMock();
-
-		Zend_Registry::set('sql', $mock_sql);
-		return $mock_sql;
-	}
-
-
 	public function postDispatch($url, $data) {
 		$this->getRequest()
 			->setMethod('POST')
diff --git a/tests/application/modules/admin/controllers/AccueilControllerFormationsTest.php b/tests/application/modules/admin/controllers/AccueilControllerFormationsTest.php
index 730133446f8f808cdaf5cc2cee7ea1192af0d6e5..0f0273eb6904f164abc59144f2f281f5844c7f48 100644
--- a/tests/application/modules/admin/controllers/AccueilControllerFormationsTest.php
+++ b/tests/application/modules/admin/controllers/AccueilControllerFormationsTest.php
@@ -31,7 +31,7 @@ class Admin_AccueilControllerFormationsTestWithDefaultSettings extends Admin_Abs
 			->updateModuleConfigAccueil(1, ['type_module' => 'FORMATIONS_WIDGET',
 																			'division' => 1,
 																			'id_module' => 1,
-																			'selected_formations' => ''])
+																			'preferences' => ['selected_formations' => '']])
 			->beCurrentProfil();
 
 		$this->dispatch('admin/accueil/formations-widget?config=accueil&id_profil=1&id_module=1&type_module=FORMATIONS_WIDGET', true);
diff --git a/tests/application/modules/admin/controllers/AccueilControllerTest.php b/tests/application/modules/admin/controllers/AccueilControllerTest.php
index 8f9b27d90f5f950c6874fe4eb94317850202ea7c..c0a876410c530bfa6ecb56d72bc4b6bc6528a8a4 100644
--- a/tests/application/modules/admin/controllers/AccueilControllerTest.php
+++ b/tests/application/modules/admin/controllers/AccueilControllerTest.php
@@ -21,26 +21,37 @@
 require_once 'AdminAbstractControllerTestCase.php';
 
 
-class AccueilControllerBoite2ColTest extends Admin_AbstractControllerTestCase {
+abstract class AccueilControllerBoite2ColTestCase 
+extends Admin_AbstractControllerTestCase {
+	protected $_request_url = '/admin/accueil/conteneur2colonnes?id_profil=34&id_module=3&type_module=CONTENEUR_DEUX_COLONNES&config=accueil';
+
 	public function setUp() {
 		parent::setUp();
+		$boite2cols = ['type_module' => 'CONTENEUR_DEUX_COLONNES',
+									 'division' => 2,
+									 'id_module' => 3,
+									 'preferences' => ['col_gauche_type' => 'NEWS',
+																		 'col_droite_type' => 'CRITIQUES',
+																		 'boite' => 'boite_de_la_division_du_milieu',
+																		 'titre' => 'A la Une']];
+
+		$this->profil_biologie = $this
+			->fixture('Class_Profil', ['id' => 34, 'libelle' => 'Biologie'])
+			->updateModuleConfigAccueil(3, $boite2cols);
+	}
+}
 
-		$boite2cols = array('type_module' => 'CONTENEUR_DEUX_COLONNES',
-												'division' => 2,
-												'id_module' => 3,
-												'preferences' => array('col_gauche_type' => 'NEWS',
-																							 'col_droite_type' => 'CRITIQUES',
-																							 'boite' => 'boite_de_la_division_du_milieu',
-																							 'titre' => 'A la Une'));
 
-		$this->profil_biologie = Class_Profil::getLoader()
-			->newInstanceWithId(34)
-			->setLibelle('Biologie')
-			->updateModuleConfigAccueil(3, $boite2cols);
-		$this->assertTrue($this->profil_biologie->isValid());
+class AccueilControllerBoite2ColTest extends AccueilControllerBoite2ColTestCase {
+	public function setUp() {
+		parent::setUp();
+		$this->dispatch($this->_request_url, true);
+	}
 
-		$this->request_url = '/admin/accueil/conteneur2colonnes?id_profil=34&id_module=3&type_module=CONTENEUR_DEUX_COLONNES&config=accueil';
-		$this->dispatch($this->request_url, true);
+
+	/** @test */
+	public function profilShouldBeValid() {
+		$this->assertTrue($this->profil_biologie->isValid());
 	}
 
 
@@ -67,59 +78,49 @@ class AccueilControllerBoite2ColTest extends Admin_AbstractControllerTestCase {
 	public function selectColDroiteTypeShouldHaveCRITIQUESSelected() {
 		$this->assertXPath("//select[@name='col_droite_type']/option[@value='CRITIQUES'][@selected='selected']");
 	}
+}
 
 
-	/** @test */
-	public function postDataShouldSaveTheProfil() {
-		$this->profil_wrapper = Storm_Test_ObjectWrapper
-			::onLoaderOfModel('Class_Profil')
-			->whenCalled('save')
-			->answers(true)
-			->getWrapper();
-
-
-		$data = array('col_gauche_type' => 'KIOSQUE',
-									'col_droite_type' => 'TAGS',
-									'titre' => 'Ce mois ci');
+class AccueilControllerBoite2ColPostTest extends AccueilControllerBoite2ColTestCase {
+	public function setUp() {
+		parent::setUp();
+		$this->postDispatch($this->_request_url, ['col_gauche_type' => 'KIOSQUE',
+																							'col_droite_type' => 'TAGS',
+																							'titre' => 'Ce mois ci']);
+	}
 
-		$this
-			->getRequest()
-			->setMethod('POST')
-			->setPost($data);
 
-		$this->dispatch($this->request_url);
+	/** @test */
+	public function moduleKiosqueShouldHaveBeenCreated() {
+		$this->assertEquals('KIOSQUE', $this->_getModuleTypeOf(1000));
+	}
 
-		$this->assertTrue($this->profil_wrapper->methodHasBeenCalled('save'));
 
-		return $this->profil_biologie;
+	/** @test */
+	public function moduleKiosqueShouldHaveBeenAddedToBox() {
+		$this->assertEquals(1000, $this->_getModulePrefOf(3, 'col_gauche_module_id'));
 	}
 
 
-	/**
-	 * @depends postDataShouldSaveTheProfil
-	 * @test
-	 */
-	public function moduleKiosqueShouldHaveBeenCreated($profil_biologie) {
-		$module = $profil_biologie->getModuleAccueilConfig(1000);
-		$this->assertEquals('KIOSQUE',$module['type_module']);
+	/** @test */
+	public function moduleTagsShouldHaveBeenCreated() {
+		$this->assertEquals('TAGS', $this->_getModuleTypeOf(1001));
+	}
 
 
-		$boite2cols = $profil_biologie->getModuleAccueilConfig(3);
-		$this->assertEquals(1000, $boite2cols['preferences']['col_gauche_module_id']);
+	/** @test */
+	public function moduleTagsShouldHaveBeenAddedToBox() {
+		$this->assertEquals(1001, $this->_getModulePrefOf(3, 'col_droite_module_id'));
 	}
 
 
-	/**
-	 * @depends postDataShouldSaveTheProfil
-	 * @test
-	 */
-	public function moduleTagsShouldHaveBeenCreated($profil_biologie) {
-		$module = $profil_biologie->getModuleAccueilConfig(1001);
-		$this->assertEquals('TAGS',$module['type_module']);
+	protected function _getModuleTypeOf($id_module) {
+		return $this->profil_biologie->getModuleAccueilConfig($id_module)['type_module'];
+	}
 
 
-		$boite2cols = $profil_biologie->getModuleAccueilConfig(3);
-		$this->assertEquals(1001, $boite2cols['preferences']['col_droite_module_id']);
+	protected function _getModulePrefOf($id_module, $pref) {
+		return $this->profil_biologie->getModuleAccueilConfig($id_module)['preferences'][$pref];
 	}
 }
 
@@ -467,24 +468,31 @@ class AccueilControllerConfigRSSDefaultsTest extends Admin_AbstractControllerTes
 
 
 
-
-class AccueilControllerConfigBoiteLoginTest extends Admin_AbstractControllerTestCase  {
-	public function setUp() {
-		parent::setUp();
+abstract class AccueilControllerConfigBoiteLoginTestCase extends Admin_AbstractControllerTestCase {
+	protected function prepareProfile() {
 		Class_Profil::getCurrentProfil()
 			->updateModuleConfigAccueil(32,
 																	['type_module' => 'LOGIN',
 																	 'division' => 4,
 																	 'id_module' => 32,
 																	 'preferences' => ['profil_redirect'=>'1',
+																										 'profil_logout_redirect' => '1',
 																										 'mot_de_pass_exemple' => 'dd/mm/aaaa']]);		
-		$this->dispatch('/admin/accueil/login?config=accueil&type_module=LOGIN&id_module=32', true);
 	}
 
 
-		/** @test */
-	public function selectProfilRedirectShouldContainsProfil1() {
-		$this->assertXPathContentContains('//select[@id="profil_redirect"][@name="profil_redirect"]/optgroup/option[@value="1"][@selected="selected"]', 'portail: Accueil', $this->_response->getBody());
+	public function setUp() {
+		parent::setUp();
+		$this->prepareProfile();
+	}
+}
+
+
+
+class AccueilControllerConfigBoiteLoginTest extends AccueilControllerConfigBoiteLoginTestCase {
+	public function setUp() {
+		parent::setUp();
+		$this->dispatch('/admin/accueil/login?config=accueil&type_module=LOGIN&id_module=32', true);
 	}
 
 
@@ -548,14 +556,132 @@ class AccueilControllerConfigBoiteLoginTest extends Admin_AbstractControllerTest
 	}
 
 
-	/** @test **/
-	public function selectProfilShloudBeEmptyValue() {
-		$this->assertXPath('//td/select[@id="profil_redirect"]/option');
+	/** @test */
+	public function profilRedirectShouldContainsProfil1() {
+		$this->assertXPathContentContains('//select[@name="profil_redirect"]/optgroup/option[@value="1"][@selected="selected"]', 
+																			'portail: Accueil');
+	}
+
+
+	/** @test */
+	public function profilLogoutRedirectShouldContainsProfil1() {
+		$this->assertXPathContentContains('//select[@name="profil_logout_redirect"]/optgroup/option[@value="1"][@selected="selected"]', 
+																			'portail: Accueil');
+	}
+
+}
+
+
+
+class AccueilControllerConfigBoiteLoginPostTest extends AccueilControllerConfigBoiteLoginTestCase {
+	protected $_prefs;
+
+	public function setUp() {
+		parent::setUp();
+		$this->postDispatch('/admin/accueil/login?config=accueil&type_module=LOGIN&id_module=32', 
+												['boite' => '',
+												 'titre' => 'Se connecter',
+												 'profil_redirect' => 678,
+												 'profil_logout_redirect' => 345]);
+
+		$this->_prefs = Class_Profil::getCurrentProfil()->getModuleAccueilPreferences(32);
+	}
+
+
+	/** @test */
+	public function profilRedirectShouldBe678() {
+		$this->assertEquals(678, $this->_prefs['profil_redirect']);
+	}
+
+
+	/** @test */
+	public function profilLogoutRedirectShouldBe345() {
+		$this->assertEquals(345, $this->_prefs['profil_logout_redirect']);
+	}
+}
+
+
+
+
+abstract class AccueilControllerWithParentProfileConfigBoiteLoginTestCase 
+extends AccueilControllerConfigBoiteLoginTestCase {
+	protected function prepareProfile() {
+		parent::prepareProfile();
+		$this->fixture('Class_Profil', ['id' => 3]);
+		$parent = $this->fixture('Class_Profil', ['id' => 44])
+			->updateModuleConfigAccueil(32,
+																	['type_module' => 'LOGIN',
+																	 'division' => 4,
+																	 'id_module' => 32,
+																	 'preferences' => ['profil_redirect' => '3',
+																										 'profil_logout_redirect' => '3',
+																										 'mot_de_pass_exemple' => 'dd/mm/aaaa']]);;
+
+		Class_Profil::getCurrentProfil()
+			->setParentProfil($parent);
+	}
+}
+
+
+
+
+class AccueilControllerWithParentProfileConfigBoiteLoginTest extends AccueilControllerWithParentProfileConfigBoiteLoginTestCase {
+	public function setUp() {
+		parent::setUp();
+		$this->dispatch('/admin/accueil/login?config=accueil&type_module=LOGIN&id_module=32', true);
+	}
+
+
+	/** @test */
+	public function profilRedirectShouldBeParentsOne() {
+		$this->assertXPath('//select[@name="profil_redirect"]/optgroup/option[@value="3"][@selected="selected"]',
+											 $this->_response->getBody());
+	}
+
+
+	/** @test */
+	public function profilLogoutRedirectShouldBeParentsOne() {
+		$this->assertXPath('//select[@name="profil_logout_redirect"]/optgroup/option[@value="3"][@selected="selected"]',
+											 $this->_response->getBody());
 	}
 }
 
 
 
+class AccueilControllerWithParentProfileConfigBoiteLoginPostTest 
+extends AccueilControllerWithParentProfileConfigBoiteLoginTestCase {
+	protected $_prefs;
+
+	public function setUp() {
+		parent::setUp();
+		$this->postDispatch('/admin/accueil/login?config=accueil&type_module=LOGIN&id_module=32', 
+												['boite' => '',
+												 'titre' => 'Se connecter',
+												 'profil_redirect' => 678,
+												 'profil_logout_redirect' => 345]);
+
+		$this->_prefs = Class_Profil::getCurrentProfil()
+			->getParentProfil()
+			->getModuleAccueilPreferences(32);
+	}
+
+
+	/** @test */
+	public function parentProfilRedirectShouldBe678() {
+		$this->assertEquals(678, $this->_prefs['profil_redirect']);
+	}
+
+
+	/** @test */
+	public function parentProfilLogoutRedirectShouldBe345() {
+		$this->assertEquals(345, $this->_prefs['profil_logout_redirect']);
+	}
+}
+
+
+
+
+
 class AccueilControllerPostConfigBoiteKiosqueProfilLognesTestCase extends Admin_AbstractControllerTestCase {
 	public function setUp() {
 		parent::setUp();
@@ -564,11 +690,10 @@ class AccueilControllerPostConfigBoiteKiosqueProfilLognesTestCase extends Admin_
 			->setLibelle('Lognes');
 
 		Class_Profil::getCurrentProfil()
-			->updateModuleConfigAccueil(25,
-																	array('type_module' => 'KIOSQUE',
-																				'division' => 4,
-																				'id_module' => 32,
-																				'preferences' => array()))
+			->updateModuleConfigAccueil(32, ['type_module' => 'KIOSQUE',
+																			 'division' => 4,
+																			 'id_module' => 32,
+																			 'preferences' => []])
 			->setIdSite(3);
 		$this->postDispatch('/admin/accueil/kiosque?config=accueil&type_module=KIOSQUE&id_module=32',
 												['id_panier'=>'5','titre' => 'titre du /kiosque']);
diff --git a/tests/application/modules/admin/controllers/ModulesControllerTest.php b/tests/application/modules/admin/controllers/ModulesControllerTest.php
index a34b7d22d4c04b43c844f8f98170de843ab08f0e..81e24a318f1710e529458e1abfbdc6215b76126b 100644
--- a/tests/application/modules/admin/controllers/ModulesControllerTest.php
+++ b/tests/application/modules/admin/controllers/ModulesControllerTest.php
@@ -216,6 +216,45 @@ class ModulesControllerVariousConfigTest extends Admin_AbstractControllerTestCas
 
 
 
+class ModulesControllerRegisterConfigTest extends Admin_AbstractControllerTestCase {
+	public function setUp() {
+		parent::setUp();
+		$this->dispatch('/admin/modules/auth?config=site&type_module=auth&id_profil=1&action1=register&action2=', true);
+	}
+
+
+  /** @test */
+	public function modulesAuthRegisterInputBarreNavShouldContainsSInscrire() {
+		$this->assertXPath('//input[@name="barre_nav"][@value="S\'inscrire"]');
+	}
+
+
+  /** @test */
+	public function modulesAuthRegisterInputTitreShouldContainsDemandeDinscription() {
+		$this->assertXPath('//input[@type="text"][@name="titre"][@value="Demande d\'inscription"]');
+	}
+
+
+  /** @test */
+	public function modulesAuthRegisterTextareaRegisterHelpShouldContainsDefautMessage() {
+
+		$this->assertXPathContentContains('//textarea[@name="register_help"]',
+																			'mail de confirmation');
+	}
+
+
+  /** @test */
+	public function modulesAuthRegisterTextareaRegisterConfirmShouldContainsDefautMessage() {
+
+		$this->assertXPathContentContains('//textarea[@name="register_confirm"]',
+																			'Cher Internaute,');
+	}
+
+}
+
+
+
+
 class ModulesControllerBibIndexTest extends Admin_AbstractControllerTestCase {
 	/** @test */
 	function optionCacherArticlesShouldBePresentOnIndex() {
diff --git a/tests/application/modules/admin/controllers/SitothequeControllerTest.php b/tests/application/modules/admin/controllers/SitothequeControllerTest.php
index e38c8e9b860bfaf03a358ba6275eaadab37ab4b1..d7b675e01df3c43b9297e9584cd35064c5b4b1fe 100644
--- a/tests/application/modules/admin/controllers/SitothequeControllerTest.php
+++ b/tests/application/modules/admin/controllers/SitothequeControllerTest.php
@@ -27,67 +27,61 @@ abstract class SitothequeControllerTestCase extends Admin_AbstractControllerTest
 		parent::setUp();
 		
 		$this->setupDomaines();
-		$categorie_informations = Class_SitothequeCategorie::newInstanceWithId(2, 
-																																					 ['libelle' => 'Informations',
-																																						'id_site' => 3])
-		->setSousCategories([])
-		->setSitotheques([Class_Sitotheque::newInstanceWithId(22, 
-																									['titre' => 'Le Canard',
-																									 'url' => 'http://www.canard.fr',
-																									 'description' => 'indépendant',
-																									 'domaine_ids' => [10]]),
 
-											$this->_le_monde = Class_Sitotheque::newInstanceWithId(23, 
-																													['titre' => 'Le Monde',
-																													 'url' => 'http://www.monde.fr'])]);
-
-
-		$bib_annecy = Class_Bib::newInstanceWithId(3, ['libelle' => 'Annecy'])
-			->setSitothequeCategories([$categorie_informations]);
-
-		Storm_Test_ObjectWrapper::onLoaderOfModel('Class_Bib')
-		->whenCalled('findAllBy')
-		->with(['order' => 'libelle'])
-		->answers([$bib_annecy])
-
-		->whenCalled('findAll')
-		->answers([$bib_annecy]);
+		Class_Notice::beVolatile();
+		Class_CodifThesaurus::beVolatile();
+
+		$categorie_informations = $this->fixture('Class_SitothequeCategorie',
+																						 ['id' => 2, 
+																							'libelle' => 'Informations',
+																							'id_site' => 3,
+																							'sous_categories' => [],
+																							'sitotheques' => [
+																								$this->fixture('Class_Sitotheque',
+																															 ['id' => 22, 
+																																'titre' => 'Le Canard',
+																																'url' => 'http://www.canard.fr',
+																																'description' => 'indépendant',
+																																'domaine_ids' => [10]]),
+
+																								$this->_le_monde = $this->fixture('Class_Sitotheque',
+																																									['id' => 23, 
+																																									 'titre' => 'Le Monde',
+																																									 'url' => 'http://www.monde.fr'])]
+																							 ]);
+																						 
+
+		$bib_annecy = $this->fixture('Class_Bib',
+																 ['id' => 3, 
+																	'libelle' => 'Annecy',
+																	'sitotheque_categories' => [$categorie_informations]]);
 
 		Class_Bib::getPortail()->setSitothequeCategories([]);
-
-
-		Storm_Test_ObjectWrapper::onLoaderOfModel('Class_Sitotheque')
-		->whenCalled('save')->answers(true)
-		->whenCalled('delete')->answers(true);
-
-		Storm_Test_ObjectWrapper::onLoaderOfModel('Class_SitothequeCategorie')
-		->whenCalled('save')->answers(true)
-		->whenCalled('delete')->answers(true)
-		
-		->whenCalled('findAllBy')
-		->with(['id_site' => 3,
-						'order' => 'libelle'])
-		->answers([$categorie_informations]);
 	}
 
 
 	public function setupDomaines() {
-		$domaine_histoire = Class_Catalogue::newInstanceWithId(10,
-																													 ['libelle' => 'Histoire',
-																														'sous_domaines' => []]);
-
-		$domaine_informations = Class_Catalogue::newInstanceWithId(66,
-																															 ['libelle' => 'Informations',
-																																'sous_domaines' => []]);
-
-		Storm_Test_ObjectWrapper::onLoaderOfModel('Class_Catalogue')
-			->whenCalled('findAllBy')
-			->answers([$domaine_histoire])
-
-			->whenCalled('findFirstBy')
-			->with(['parent_id' => null,
-							'libelle' => 'Informations'])
-			->answers($domaine_informations);
+		$this->fixture('Class_Catalogue', ['id' => 10,
+																			 'libelle' => 'Histoire',
+																			 'sous_domaines' => []]);
+
+		$this->fixture('Class_Catalogue', ['id' => 66,
+																			 'libelle' => 'Informations',
+																			 'sous_domaines' => []]);
+
+		$this->fixture('Class_CodifThesaurus',
+									 ['id' => 1,
+										'id_thesaurus' => 'C0001',
+										'id_origine' => 10,
+										'libelle' => 'Histoire',
+										'code' => 'Catalogue']);
+
+		$this->fixture('Class_CodifThesaurus',
+									 ['id' => 2,
+										'id_thesaurus' => 'C0002',
+										'id_origine' => 66,
+										'libelle' => 'Informations',
+										'code' => 'Catalogue']);
 	}
 }
 
@@ -239,25 +233,51 @@ class SitothequeControllerPostAddActionTest extends SitothequeControllerTestCase
 	public function setUp() {
 		parent::setUp();
 
-		Class_Sitotheque::whenCalled('save')->willDo(function($site) {$site->setId(25);});
+		$this->cache = Storm_Test_ObjectWrapper::mock()->whenCalled('clean')->answers(true);
+		Storm_Cache::setDefaultZendCache($this->cache);
+
 		$this->postDispatch('/admin/sito/sitoadd/id_cat/2', 
 												['titre' => 'google',
 												 'url' => 'http://www.google.fr',
-												 'id_items' => '23-23'], 
+												 'id_items' => '23-23',
+												 'domaine_ids' => 10], 
 												true);
 	}
 
 
 	/** @test */
-	public function anwersShouldRedirectToSitoEdit25() {
-		$this->assertRedirectTo('/admin/sito/sitoedit/id/25');
+	public function anwersShouldRedirectToSitoEdit24() {
+		$this->assertRedirectTo('/admin/sito/sitoedit/id/24');
 	}
 
 
 	/** @test */
 	public function sitoShouldNotHaveIdItems() {
-		$new_site = Class_Sitotheque::getFirstAttributeForLastCallOn('save');
-		$this->assertTrue($new_site->isAttributeEmpty('id_items'));
+		$this->assertTrue(Class_Sitotheque::find(24)->isAttributeEmpty('id_items'));
+	}
+
+
+
+	/** @test */
+	public function pseudoNoticeShouldBeCreated() {
+		$this->assertNotEmpty(Class_Notice::find(1));
+	}
+
+
+	/** @test */
+	public function pseudoNoticeTitleShouldBeGoogle() {
+		$this->assertEquals('google', Class_Notice::find(1)->getTitrePrincipal());
+	}
+
+
+	/** @test */
+	public function pseudoNoticeShouldHaveIndexForTypeDocAndDomaineHistoire() {
+		$this->assertEquals('T10 HC0001', Class_Notice::find(1)->getFacettes());
+	}
+
+	/** @test */
+	public function cacheShouldHaveBeenCleaned() {
+		$this->assertTrue($this->cache->methodHasBeenCalled('clean'));
 	}
 }
 
@@ -285,6 +305,8 @@ class SitothequeControllerSitoPostEditLeMondeTest extends SitothequeControllerTe
 		$this->postDispatch('/admin/sito/sitoedit/id/23', 
 												['titre' => 'Times'],
 												true);
+		Class_Sitotheque::clearCache();
+		$this->_le_monde = Class_Sitotheque::find(23);
 	}
 
 
@@ -294,12 +316,6 @@ class SitothequeControllerSitoPostEditLeMondeTest extends SitothequeControllerTe
 	}
 
 
-	/** @test */
-	public function siteShouldHaveBeenSaved() {
-		$this->assertTrue(Class_Sitotheque::methodHasBeenCalled('save'));
-	}
-
-
 	/** @test */
 	public function anwersShouldRedirectToSitoEdit23() {
 		$this->assertRedirectTo('/admin/sito/sitoedit/id/23');
@@ -318,7 +334,7 @@ class SitothequeControllerSitoDeleteLeMondeTest extends SitothequeControllerTest
 
 	/** @test */
 	public function siteShouldHaveBeenDeleted() {
-		$this->assertTrue(Class_Sitotheque::methodHasBeenCalled('delete'));
+		$this->assertEmpty(Class_Sitotheque::find(23));
 	}
 
 
@@ -383,6 +399,7 @@ class SitothequeControllerPostEditCategorieInformationsTest extends SitothequeCo
 		$this->postDispatch('/admin/sito/catedit/id/2', 
 												['libelle' => 'News'],
 												true);
+		Class_SitothequeCategorie::clearCache();
 	}
 
 
@@ -390,12 +407,6 @@ class SitothequeControllerPostEditCategorieInformationsTest extends SitothequeCo
 	public function libelleShouldBeNews() {
 		$this->assertEquals('News', Class_SitothequeCategorie::find(2)->getLibelle());
 	}
-
-
-	/** @test */
-	public function categorieShouldHaveBeenSaved() {
-		$this->assertTrue(Class_SitothequeCategorie::methodHasBeenCalled('save'));
-	}
 }
 
 
@@ -448,18 +459,11 @@ class SitothequeControllerPostAddCategorieNationalesTest extends SitothequeContr
 	public function setUp() {
 		parent::setUp();
 
-		Class_SitothequeCategorie::whenCalled('save')
-		->willDo(
-			function($cat) {
-				$cat->setId(5)->cache(); 
-				return true;
-			});
-
 		$this->postDispatch('/admin/sito/catadd/id/2', 
 												['libelle' => 'Nationales'],
 												true);
 
-		$this->_new_cat = Class_SitothequeCategorie::find(5);
+		$this->_new_cat = Class_SitothequeCategorie::find(3);
 	}
 
 
@@ -467,12 +471,6 @@ class SitothequeControllerPostAddCategorieNationalesTest extends SitothequeContr
 	public function libelleShouldBeNationales() {
 		$this->assertEquals('Nationales', $this->_new_cat->getLibelle());
 	}
-
-
-	/** @test */
-	public function categorieShouldHaveBeenSaved() {
-		$this->assertTrue(Class_SitothequeCategorie::methodHasBeenCalled('save'));
-	}
 }
 
 
@@ -484,18 +482,11 @@ class SitothequeControllerPostAddCategorieInBibTest extends SitothequeController
 	public function setUp() {
 		parent::setUp();
 
-		Class_SitothequeCategorie::whenCalled('save')
-		->willDo(
-			function($cat) {
-				$cat->setId(5)->cache(); 
-				return true;
-			});
-
 		$this->postDispatch('/admin/sito/catadd/id_bib/5', 
 												['libelle' => 'Dans la bib'],
 												true);
 
-		$this->_new_cat = Class_SitothequeCategorie::find(5);
+		$this->_new_cat = Class_SitothequeCategorie::find(3);
 	}
 
 
@@ -523,7 +514,7 @@ class SitothequeControllerDeleteCategorieInformationsTest extends SitothequeCont
 
 	/** @test */
 	public function categorieShouldHaveBeenDeleted() {
-		$this->assertTrue(Class_SitothequeCategorie::methodHasBeenCalled('delete'));
+		$this->assertEmpty(Class_SitothequeCategorie::find(2));
 	}
 }
 
diff --git a/tests/application/modules/opac/controllers/AbonneControllerAvisTest.php b/tests/application/modules/opac/controllers/AbonneControllerAvisTest.php
index fad72779c31d3edd4516821a40690a805f7916b1..343fca9b677e92b0aae80e1ee5e6e46fa237c0b6 100644
--- a/tests/application/modules/opac/controllers/AbonneControllerAvisTest.php
+++ b/tests/application/modules/opac/controllers/AbonneControllerAvisTest.php
@@ -862,4 +862,29 @@ class AbonneControllerEditAvisNoticeAdminLoggedPostActionTest extends AbstractCo
 	}
 }
 
+
+
+class AbonneControllerDeleteAvisNoticeAdminLoggedActionTest extends AbstractControllerTestCase {
+	public function setUp() {
+		parent::setUp();
+		$_SERVER['HTTP_REFERER'] ='opac/recherche/viewnotice/id/1';
+		$avis = $this->fixture('Class_AvisNotice', ['id' => 54,
+																								'entete' => 'Bonjour !',
+																								'avis' => 'Ceci est le contenu de l\'avis']);
+		$this->dispatch('/opac/abonne/delavisnotice/id/54/expressionRecherche/1', true);
+	}
+
+
+	/** @test */
+	public function avisShouldBeRemoved() {
+		$this->assertEmpty(Class_AvisNotice::findAll());
+	}
+
+	
+	/** @test */
+	public function shouldContainsSciptToRedirectToReferer() {
+		$this->assertContains('window.location=\"opac\/recherche\/viewnotice\/id\/1\"', $this->_response->getBody());
+	}
+}
+
 ?>
\ No newline at end of file
diff --git a/tests/application/modules/opac/controllers/AuthControllerTest.php b/tests/application/modules/opac/controllers/AuthControllerTest.php
index 0e57bc576d1845c9adfa856bcad983cb9862573b..3646ec660acf36a72a307cdad5e121c1dc0de145 100644
--- a/tests/application/modules/opac/controllers/AuthControllerTest.php
+++ b/tests/application/modules/opac/controllers/AuthControllerTest.php
@@ -39,7 +39,8 @@ abstract class PortailWithOneLoginModuleTestCase extends AbstractControllerTestC
 																					'titre_connecte' => 'Vous êtes connecté(e)',
 																					'lien_connexion' => 'please, log me',
 																					'lien_mot_de_passe_oublie' => 'me rappelle plus',
-																					'profil_redirect' => 1]]],
+																					'profil_redirect' => 1,
+																					'profil_logout_redirect' => 0]]],
 										'options' => []];
 
 		Class_Profil::getCurrentProfil()
@@ -153,47 +154,67 @@ class AuthControllerAbonneSIGBLoggedTest extends PortailWithOneLoginModuleTestCa
 
 
 
-class AuthControllerAbonneSIGBLoggedLogoutTest extends PortailWithOneLoginModuleTestCase {
+class AuthControllerAbonneSIGBLoggedLogoutTest 
+extends PortailWithOneLoginModuleTestCase {
 	public function setUp() {
 		parent::setUp();
 		$this->dispatch('/opac/auth/logout');
 	}
 
+
 	/** @test */
-	public function answerShouldRedirectToRoot() {
+	public function shouldRedirectToRoot() {
 		$this->assertRedirectTo('/');
 	}
 }
 
 
-class AuthControllerWithProfilPageAbonneSIGBLoggedLogoutTest extends PortailWithOneLoginModuleTestCase {
+
+class AuthControllerWithProfilPageAbonneSIGBLoggedLogoutTest 
+extends PortailWithOneLoginModuleTestCase {
+	protected $_profile, $_parent_profile;
+
 	public function setUp() {
 		parent::setUp();
-		$this->profil_adulte = $this->fixture('Class_Profil', ['id' => 22])
-			->setBrowser('opac')
-			->setLibelle('Profil Adulte')
-			->setHauteurBanniere(150)
-			->setCouleurTexteBandeau('#F2C')
-			->setCouleurLienBandeau('#234')
-			->setMenuHautOn(true)
-			->setCfgMenus([])
-			->setCommentaire('Super bib')
-			->setRefTags('bib,Adulte')
-			->setParentProfil(Class_Profil::getCurrentProfil());
-		$this->profil_adulte->assertSave();
-		Class_Profil::setCurrentProfil($this->profil_adulte);
-		$this->dispatch('/opac/auth/logout');
+		$this->_parent_profile = Class_Profil::getCurrentProfil();
+		$this->_profile = $this->fixture('Class_Profil', 
+																		 ['id' => 22,
+																			'browser' => 'opac',
+																			'libelle' => 'Profil Adulte',
+																			'hauteur_banniere' => 150,
+																			'couleur_texte_bandeau' => '#F2C',
+																			'couleur_lien_bandeau' => '#234',
+																			'menu_haut_on' => true,
+																			'cfg_menus' => [],
+																			'commentaire' => 'Super bib',
+																			'ref_tags' => 'bib,Adulte',
+																			'parent_profil' => $this->_parent_profile]);
+		Class_Profil::setCurrentProfil($this->_profile);
 	}
 
 	
 	/** @test **/
-	public function linkSeDeconnecterShouldRedirectToParentProfil() {
+	public function withoutLogoutProfileShouldRedirectToParentProfile() {
+		$this->dispatch('/opac/auth/logout');
 		$this->assertRedirectTo('/opac/index/index/id_profil/2');
 	}
 
+
+	/** @test **/
+	public function withLogoutProfile6InParentShouldRedirectToIt() {
+		$cfg_accueil = $this->_parent_profile->getCfgAccueilAsArray();
+		$cfg_accueil['modules'][4]['preferences']['profil_logout_redirect'] = 6;
+		$this->_parent_profile
+			->setCfgAccueil(ZendAfi_Filters_Serialize::serialize($cfg_accueil));
+
+		$this->dispatch('/opac/auth/logout');
+		$this->assertRedirectTo('/opac/index/index/id_profil/6');
+	}
 }
 
 
+
+
 abstract class AuthControllerNobodyLoggedTestCase extends PortailWithOneLoginModuleTestCase {
 	public function setUp() {
 		parent::setUp();
@@ -246,7 +267,8 @@ class AuthControllerNobodyLoggedActivateTest extends AuthControllerNobodyLoggedT
 }
 
 
-class AuthControllerNobodyLoggedAndRegistrationAllowedBoiteLoginTest extends AuthControllerNobodyLoggedTestCase {
+class AuthControllerNobodyLoggedAndRegistrationAllowedBoiteLoginTest 
+extends AuthControllerNobodyLoggedTestCase {
 	public function setUp() {
 		parent::setUp();
 
@@ -257,40 +279,48 @@ class AuthControllerNobodyLoggedAndRegistrationAllowedBoiteLoginTest extends Aut
 		$this->dispatch('/opac/',true);
 	}
 
+
 	/** @test */
-	public function submitButtonSeConnecterShouldBeDisplay(){
-		$this->assertXPath('//div[@id="boite_login"]//input[@type="submit"]',$this->_response->getBody());
+	public function loginSubmitShouldBePresent(){
+		$this->assertXPath('//div[@id="boite_login"]//input[@type="submit"]',
+											 $this->_response->getBody());
 	}
 
+
 	/** @test */
-	public function titreDelaBoiteShouldBeSeConnecter(){
+	public function titleShouldBeSeConnecter(){
 		$this->assertXPathContentContains('//h1','Se connecter');
 	}
 
+
 	/** @test **/
-	public function inputLoginTypePasswordShouldCOntainsOnkeypressFormSubmit() {
+	public function inputLoginShouldSubmitOnKey13Pressed() {
 		$this->assertXPath('//div[@id="boite_login"]//input[contains(@onkeypress,"if (event.keyCode == 13) {this.form.submit();return false;}")]');
 	}
 
-	public function testLinkSeConnecter() {
-		$this->assertXPath('//div[@id="boite_login"]//a[contains(@onclick,"submit")]');
+
+	/** @test */
+	public function loginLinkShouldBePresent() {
 		$this->assertXPathContentContains('//div[@id="boite_login"]//a[contains(@onclick, "submit")]',
 																			'please, log me');
 	}
 
-	public function testLinkLostPassword() {
-		$this->assertXPath('//div[@id="boite_login"]//a[contains(@href, "auth/lostpass")]');
+
+	/** @test */
+	public function lostPassLinkShouldBePresent() {
 		$this->assertXPathContentContains('//div[@id="boite_login"]//tr/td[@colspan="2"]/a[contains(@href, "auth/lostpass")]',
 																			'me rappelle plus');
 	}
 
-	public function testLinkSenregistrer() {
-		$this->assertXPath('//div[@id="boite_login"]//a[contains(@href, "auth/register")]');
+
+	/** @test */
+	public function registerLinkShouldBePresent() {
 		$this->assertXPathContentContains('//div[@id="boite_login"]//a[contains(@href, "auth/register")]', "S'enregistrer");
 	}
 
 
-	public function testCanAccessRegisterPage() {
+	/** @test */
+	public function shouldAccessRegisterPage() {
 		$this->bootstrap();
 		$this->dispatch('auth/register', true);
 		$this->assertAction('register');
@@ -841,7 +871,7 @@ class AuthControllerPostSuccessfulFromCASClientTest extends AuthControllerPostSi
 
 	/** @test */
 	public function responseShouldRedirectToCasClientWithTicket() {
-		$this->assertRedirectTo('http://www.numilog.com/view?book=bilbo&ticket='.md5(Zend_Session::getId().'2'));
+		$this->assertRedirectTo('http://www.numilog.com/view?book=bilbo&ticket=ST-'.md5(Zend_Session::getId().'2'));
 	}
 
 	/** @test */
@@ -865,7 +895,7 @@ class AuthControllerPostSuccessfulFromMusicMeCASClientTest extends AuthControlle
 
 	/** @test */
 	public function responseShouldRedirectToMusicMeCasClientWithTicketAndBibId() {
-		$ticket=md5(Zend_Session::getId(). '2');
+		$ticket='ST-'.md5(Zend_Session::getId(). '2');
 		$this->assertRedirectTo('http://musicmeurl/?iduser=foo&ticket='.$ticket.'&MediaLibraryID=888&service=http%3A%2F%2Fmusicmeurl%2F%3Fiduser%3Dfoo%26ticket%3D'.$ticket.'%26MediaLibraryID%3D888');
 	}
 
@@ -888,7 +918,7 @@ class AuthControllerFromCASClientUserConnectedTest extends AuthControllerNobodyL
 
 	/** @test */
 	public function responseShouldRedirectToCasClientServiceWithTicket() {
-		$this->assertRedirectTo('http://numilog.com/actionredirected?ticket='.md5(Zend_Session::getId().'22'));
+		$this->assertRedirectTo('http://numilog.com/actionredirected?ticket=ST-'.md5(Zend_Session::getId().'22'));
 	}
 
 	/** @test */
@@ -1007,50 +1037,286 @@ class AuthControllerLostPasswordTest extends AuthControllerNobodyLoggedTestCase
 class AuthControllerNobodyLoggedAndRegistrationAllowedRegisterTest extends AuthControllerNobodyLoggedTestCase {
 	public function setUp() {
 		parent::setUp();
+		Class_AdminVar::newInstanceWithId('INTERDIRE_ENREG_UTIL', ['valeur' => 0]);
+		$this->dispatch('auth/register', true);
+	}
 
-		Class_AdminVar::getLoader()
-			->newInstanceWithId('INTERDIRE_ENREG_UTIL')
-			->setValeur(0);
 
-		$this->dispatch('auth/register', true);
+	/** @test */
+	public function H1ShouldContainsDemandDInscription() {
+		$this->assertXPathContentContains('//h1', 'Demande d\'inscription');
 	}
 
-	
+
+	/** @test */
+	public function ParagraphRegisterHelpShouldContainsMailDeConfirmation() {
+		$this->assertXPathContentContains('//p', 'mail de confirmation');
+	}
+
+
 	/** @test */
 	public function inputMailShouldBePresent() {
-		$this->assertXPath('//input[@name="mail"]');
+		$this->assertXPath('//input[@name="mail"][@type="email"]');
+	}
+
+	
+	/** @test */
+	public function inputConfirmMailShouldBePresent() {
+		$this->assertXPath('//input[@name="mail2"][@type="email"]');
 	}
 
+
 	/** @test */
 	public function inputLoginShouldBePresent() {
 		$this->assertXPath('//input[@name="login"]');
-	}	
+	}
+
 
 	/** @test */
 	public function inputMdpShouldBePresent() {
 		$this->assertXPath('//input[@name="mdp"]');
 	}
 
+
 	/** @test */
 	public function inputMdp2ShouldBePresent() {
 		$this->assertXPath('//input[@name="mdp2"]');
 	}
 
+
 	/** @test */
 	public function inputCaptchaShouldBePresent() {
-		$this->assertXPath('//input[@name="captcha"]');
+		$this->assertXPath('//input[@name="captcha[input]"]');
 	}
 }
 
 
 
-class portailWithOneLoginModuleTestAndLoggedUserCase extends AbstractControllerTestCase {
+
+class AuthControllerNobodyLoggedRegisterPostRightDatasTest extends AuthControllerNobodyLoggedTestCase {
 	public function setUp() {
 		parent::setUp();
+		Class_Users::beVolatile();
+		Class_UsersNonValid::beVolatile();
+		ZendAfi_Form_Element_Captcha::beValid();
+
+		$this->mock_transport = new MockMailTransport();
+		Zend_Mail::setDefaultTransport($this->mock_transport);
+
+		Class_Profil::getCurrentProfil()
+			->setMailSite('chef@afi.fr')
+			->setModulePreference('auth',
+														'register',
+														'register_confirm',
+														'Coucou, merci pour ton inscription');
+
+		Class_AdminVar::newInstanceWithId('REGISTER_OK', ['valeur' => '']);
+
+
+		Class_AdminVar::newInstanceWithId('INTERDIRE_ENREG_UTIL', ['valeur' => 0]);
+
+		$this->postDispatch('auth/register', 
+												['login' => 'mario',
+												 'mail' => 'mario@afi-sa.fr',
+												 'mail2' => 'mario@afi-sa.fr',
+												 'mdp' => 'secret',
+												 'mdp2' => 'secret',
+												 'captcha[id]' => '1234',
+												 'captcha[input]' => '1234']);
+	}
+
+
+	protected function getSentMail() {
+		return $this->mock_transport->sent_mail;
+	}
+
+
+	protected function getSentMailRecipients() {
+		return $this->getSentMail()->getRecipients();
+	}
+
+
+	protected function getSentMailFrom() {
+		return $this->getSentMail()->getFrom();
+	}
+
+
+	protected function getSentMailContent() {
+		return quoted_printable_decode($this->getSentMail()->getBodyText()->getContent());
+	}
+
+
+	/** @test */
+	public function recipientShouldBeMario() {
+		$this->assertContains('mario@afi-sa.fr', $this->getSentMailRecipients());
+	}
+
+	/** @test */
+	public function recipientsShouldContainsChefAtAfiDotFr() {
+		$this->assertContains('chef@afi.fr', $this->getSentMailRecipients());
+	}
+
+
+	/** @test */
+	public function contentShouldBeAsExpected() {
+		$this->assertContains('Vous avez fait une demande d\'inscription', $this->getSentMailContent());
+	}
 
-		Storm_Test_ObjectWrapper::onLoaderOfModel('Class_IntBib')
-			->whenCalled('findAllBy')
-			->answers([]);
+
+	/** @test */
+	public function confirmationShouldBeAsExpected() {
+		$this->assertXPathContentContains('//div',
+																			'Coucou, merci pour ton inscription');
+	}
+
+
+	/** @test */
+	public function withoutProfilMailSenderShouldBeAdmin() {
+		$this->assertContains('chef@afi.fr', $this->getSentMailFrom());
+	}
+
+
+	/** @test */
+	public function newUsersNonValidShouldBeCreated() {
+		$user = Class_UsersNonValid::findFirstBy(['login' => 'mario']);
+		$this->assertEquals(['id' => 1,
+												 'id_user' => 1,
+												 'login' => 'mario',
+												 'password' => 'secret',
+												 'mail' => 'mario@afi-sa.fr',
+												 'cle' => md5('mario@afi-sa.fr')],
+												$user->getRawAttributes());
+	}
+}
+
+
+
+
+class AuthControllerNobodyLoggedRegisterPostWrongDataTest extends AuthControllerNobodyLoggedTestCase {
+	public function setUp() {
+		parent::setUp();
+		$this->fixture('Class_Users',
+									 ['id' => 2,
+										'login' => 'alexa',
+										'password' => 'secret',
+										'mail' => 'alex.arnaud@biblibre.com']);
+		$this->fixture('Class_UsersNonValid',
+									 ['id' => 3,
+										'login' => 'laurent',
+										'password' => 'secret_aussi',
+										'mail' => 'lolo@biblibre.com']);
+
+		Class_AdminVar::newInstanceWithId('INTERDIRE_ENREG_UTIL', ['valeur' => 0]);
+	}
+
+	public function fields() {
+		return [
+			['login',],
+			['mail'],
+			['mail2'],
+			['mdp'],
+			['mdp2'],
+			];
+	}
+	
+
+	/** 
+	 * @dataProvider fields
+	 * @test 
+	 */
+	public function errorForEmptyFieldShouldBeVisible($field) {
+		$this->postDispatch('auth/register', 
+												['login' => '',
+												 'mail' => '',
+												 'mail2' => '',
+												 'mdp' => '',
+												 'mdp2' => '',
+												 'captcha[id]' => '93248',
+												 'captcha[input]' => '']);
+
+		$this->assertXPathContentContains('//ul[@class="errors"][preceding-sibling::input[@name="'.$field.'"]]//li', 
+																			'Une valeur est requise',
+																			$this->_response->getBody());
+	}
+
+
+	/** @test */
+	public function withMailsNotWellFormedShouldDisplayErrorInvalidMail() {
+		$this->postDispatch('auth/register', 
+												['mail' => 'blib',
+												 'mail2' => 'blib']);
+		$this->assertXPathContentContains('//ul[@class="errors"][preceding-sibling::input[@name="mail"]]//li', 
+																			"'blib' n'est pas un email valide de la forme 'compte@hote.ext'");
+												 
+	}
+
+
+	/** @test */
+	public function withDifferentMailsShouldDisplayErrorMailAreNotTheSame() {
+		$this->postDispatch('auth/register', 
+												['mail' => 'grand-schtroumpf@champi.gnon',
+												 'mail2' => 'schtroumpfette@champi.gnon']);
+		$this->assertXPathContentContains('//ul[@class="errors"][preceding-sibling::input[@name="mail2"]]//li', 
+																			"Les champs 'E-mail' sont différents");
+	}
+
+
+	/** @test */
+	public function withDifferentPasswordsShouldDisplayErrorPasswordsAreNotTheSame() {
+		$this->postDispatch('auth/register', 
+												['mdp' => 'secret',
+												 'mdp2' => 'sicrette']);
+		$this->assertXPathContentContains('//ul[@class="errors"][preceding-sibling::input[@name="mdp2"]]//li', 
+																			"Les champs 'Mot de passe' sont différents");
+	}
+
+
+	/** @test */
+	public function existingMailsShouldDisplayErrorMailAlreadyExists() {
+		$this->postDispatch('auth/register', 
+												['mail' => 'alex.arnaud@biblibre.com',
+												 'mail2' => 'alex.arnaud@biblibre.com']);
+		$this->assertXPathContentContains('//ul[@class="errors"][preceding-sibling::input[@name="mail"]]//li', 
+																			"L'e-mail 'alex.arnaud@biblibre.com' existe déjà.");
+	}
+
+
+	/** @test */
+	public function existingMailInUsersNonValidShouldDisplayErrorMailAlreadyExists() {
+		$this->postDispatch('auth/register', 
+												['mail' => 'lolo@biblibre.com',
+												 'mail2' => 'lolo@biblibre.com']);
+		$this->assertXPathContentContains('//ul[@class="errors"][preceding-sibling::input[@name="mail"]]//li', 
+																			"L'e-mail 'lolo@biblibre.com' existe déjà.");
+	}
+
+
+	/** @test */
+	public function existingLoginShouldDisplayErrorLoginAlreadyExists() {
+		$this->postDispatch('auth/register', 
+												['login' => 'alexa']);
+		$this->assertXPathContentContains('//ul[@class="errors"][preceding-sibling::input[@name="login"]]//li', 
+																			"L'identifiant 'alexa' existe déjà.");
+	}
+
+
+	/** @test */
+	public function existingLoginInUsersNonValidShouldDisplayErrorLoginAlreadyExists() {
+		$this->postDispatch('auth/register', 
+												['login' => 'laurent']);
+		$this->assertXPathContentContains('//ul[@class="errors"][preceding-sibling::input[@name="login"]]//li', 
+																			"L'identifiant 'laurent' existe déjà.");
+	}
+}
+
+
+
+
+class PortailWithOneLoginModuleTestAndLoggedUserCase extends AbstractControllerTestCase {
+	public function setUp() {
+		parent::setUp();
+
+		Class_IntBib::beVolatile();
 
 		$cfg_accueil = ['modules' => [4 => ['division' => '4',
 																				'id_module' => 4,
@@ -1072,14 +1338,14 @@ class portailWithOneLoginModuleTestAndLoggedUserCase extends AbstractControllerT
 
 
 		ZendAfi_Auth::getInstance()->logUser(
-			Class_Users::newInstanceWithId(5, 
-																		 ['login' => 'Pioup',
-																			'idabon' => 48,
-																			'role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB,
-																			'id_site' => 1,
-																			'fiche_sigb' => []]));
-
-
+			$this->fixture('Class_Users',
+										 ['id' => 5,
+											'login' => 'Pioup',
+											'idabon' => 48,
+											'password' => 'one ok password',
+											'role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB,
+											'id_site' => 1,
+											'fiche_sigb' => []]));
 
 		$this->dispatch('/opac/');
 	}
diff --git a/tests/application/modules/opac/controllers/CasServerControllerTest.php b/tests/application/modules/opac/controllers/CasServerControllerTest.php
index e0b6fb69c6adea0d92f39183d5dc8b262529424c..5aaa827bbed24d6bc8274664a49f06d9839dc9ac 100644
--- a/tests/application/modules/opac/controllers/CasServerControllerTest.php
+++ b/tests/application/modules/opac/controllers/CasServerControllerTest.php
@@ -49,17 +49,39 @@ class CasServerControllerValidateActionTest extends AbstractControllerTestCase {
 	}
 
 
+	/** @test */
+	public function requestWithInvalidTicketOnAuthShouldRespondInvalidTicketFailureXML() {		
+		$this->dispatch('/opac/auth/validate?ticket=STmarchepo&service=http://test.com',true);
+		$this->assertContains('<cas:authenticationFailure code="INVALID_TICKET"> Ticket STmarchepo not recognized</cas:authenticationFailure>',$this->_response->getBody());
+	}
+
+
 	/** @test */
 	public function requestWithValidTicketShouldRespondValidXML() {		
-	
 		$this->dispatch('/opac/cas-server/validate?ticket='.md5(Zend_Session::getId().'300').'&service=http://test.com');
 		$this->assertContains('<cas:user>300</cas:user>',$this->_response->getBody());
 		$this->assertContains('<cas:proxyGrantingTicket>',$this->_response->getBody());
 	}
 
+	/** @test */
+	public function requestWithValidTicketPrefixedBySTShouldRespondValidXML() {		
+		$this->dispatch('/opac/cas-server/validate?ticket=ST-'.md5(Zend_Session::getId().'300').'&service=http://test.com');
+		$this->assertContains('<cas:user>300</cas:user>',$this->_response->getBody());
+		$this->assertContains('<cas:proxyGrantingTicket>',$this->_response->getBody());
+	}
+
+
+	/** @test */
+	public function requestWithValidTicketPrefixedBySTOnAuthenticateControllerShouldRespondValidXML() {		
+		$this->dispatch('/opac/auth/validate?ticket=ST-'.md5(Zend_Session::getId().'300').'&service=http://test.com');
+		$this->assertContains('<cas:user>300</cas:user>',$this->_response->getBody());
+		$this->assertContains('<cas:proxyGrantingTicket>',$this->_response->getBody());
+	}
 }
 
 
+
+
 class CasServerControllerMusicMeValidateActionTest extends AbstractControllerTestCase {
 	protected $session_file_contents_logged;
 	protected $session_file_contents_nologin;
@@ -75,21 +97,21 @@ class CasServerControllerMusicMeValidateActionTest extends AbstractControllerTes
 	
 	/** @test */
 	public function requestMusicMeWithNoTicketShouldRespondAccountDisabledXML() {		
-		$this->dispatch('/opac/cas-server/validate-musicme?MediaLibraryID=150&ticket=0a1b2c3d');
+		$this->dispatch('/opac/cas-server/validate-musicme?MediaLibraryID=150&ticket=ST-0a1b2c3d');
 		$this->assertContains('<User />',$this->_response->getBody());
 	}
 
 
 	/** @test */
 	public function requestMusicMeWithValidTicketShouldRespondValidXML() {			
-		$this->dispatch('/opac/cas-server/validate-musicme?ticket='.md5(Zend_Session::getId().'300').'&MediaLibraryID=http://test.com');
+		$this->dispatch('/opac/cas-server/validate-musicme?ticket=ST-'.md5(Zend_Session::getId().'300').'&MediaLibraryID=http://test.com');
 		$this->assertContains('<ID>300</ID>',$this->_response->getBody());
 	}
 
 
 	/** @test */
 	public function musicmeUrlShouldContainsTicket0a1b2c3d() {
-		$expected_ticket = md5(Zend_Session::getId().'300');
+		$expected_ticket = 'ST-'.md5(Zend_Session::getId().'300');
 		$this->assertContains('ticket='.$expected_ticket.'&', Class_MusicMeLink::forUser(Class_Users::find(300))->url());
 	}
 
diff --git a/tests/application/modules/opac/controllers/FormulaireContactTest.php b/tests/application/modules/opac/controllers/FormulaireContactTest.php
index 915c08b20a794b166a3ff03122eaae8915ca982d..31bfbb9d9ff88277d1adf583d7f9a289bae93efe 100644
--- a/tests/application/modules/opac/controllers/FormulaireContactTest.php
+++ b/tests/application/modules/opac/controllers/FormulaireContactTest.php
@@ -103,7 +103,7 @@ abstract class FormulaireContactValidPostTestCase extends AbstractControllerTest
 	}
 
 	public function sendValidMail() {
-		defineConstant('NOCAPTCHA', true);
+		ZendAfi_Form_Element_Captcha::beValid();
 
 		$mock_transport = $this->newMailTransport();
 		Zend_Mail::setDefaultTransport($mock_transport);
@@ -123,6 +123,29 @@ abstract class FormulaireContactValidPostTestCase extends AbstractControllerTest
 
 
 
+
+class FormulaireContactInvalidCaptchaPostTest extends AbstractControllerTestCase {
+	public function setUp() {
+		parent::setUp();
+		Zend_Mail::setDefaultTransport(new MockMailTransport());
+
+		$this->postDispatch('/opac/index/formulairecontact',
+												['captcha[id]' => 'c1333d8036f53e6fd5386af854713144',
+												 'captcha[input]' => 'wrong']);
+	}
+
+
+	/** @test */
+	public function errorShouldContainsWrongCaptcha() {
+		$this->assertXPathContentContains('//ul[@class="errors"]', 
+																			"captcha",
+																			$this->_response->getBody());
+	}
+}
+
+
+
+
 class FormulaireContactValidPostThrowErrorTest extends FormulaireContactValidPostTestCase {
 	public function newMailTransport() {
 		$transport = new MockMailTransport();
diff --git a/tests/application/modules/opac/controllers/NoticeAjaxControllerTest.php b/tests/application/modules/opac/controllers/NoticeAjaxControllerTest.php
index b48a707746340a2e1075a66712d62f2af4e971c0..679692f442173b33dedb71e5867939a806531e79 100644
--- a/tests/application/modules/opac/controllers/NoticeAjaxControllerTest.php
+++ b/tests/application/modules/opac/controllers/NoticeAjaxControllerTest.php
@@ -1053,6 +1053,12 @@ class NoticeAjaxControllerNoticeWithAvisEditLinkModoLoggedTest extends NoticeAja
 	public function editLinkShouldBePopup() {
 		$this->assertXPath('//a[contains(@href, "abonne/editavisnotice")][@data-popup="true"]');
 	}
+
+
+	/** @test */
+	public function deleteLinkShouldBePresent() {
+		$this->assertXPath('//a[contains(@href, "abonne/delavisnotice")]');
+	}
 }
 
 
diff --git a/tests/library/Class/CatalogueTest.php b/tests/library/Class/CatalogueTest.php
index 68fb736523a6650f7ca87b223aca8aa541827618..d630c8686ec7dbfbb2703ee7c8f64ef22a3a64a8 100644
--- a/tests/library/Class/CatalogueTest.php
+++ b/tests/library/Class/CatalogueTest.php
@@ -799,8 +799,11 @@ class CatalogueBuildCriteresRechercheTest extends Storm_Test_ModelTestCase {
 
 
 class CatalogueAddOrCreateTest extends CatalogueParentTest {
+	protected $_old_sql;
+
 	public function setUp() {
 		parent::setUp();
+		$this->_old_sql = Zend_Registry::get('sql');
 		$this->mock_sql = Storm_Test_ObjectWrapper::mock();
 		Zend_Registry::set('sql', $this->mock_sql);
 
@@ -815,6 +818,11 @@ class CatalogueAddOrCreateTest extends CatalogueParentTest {
 			->answers(null);
 	}
 
+	public function tearDown() {
+		Zend_Registry::set('sql', $this->_old_sql);
+		parent::tearDown();
+	}
+
 
 	/** @test */
 	public function saveCatalogueHistoireShouldCreateThesaurus() {
diff --git a/tests/library/Class/CodifThesaurusTest.php b/tests/library/Class/CodifThesaurusTest.php
index 114ee0dd5434cdafa804ac9c1294fb9c3c80190c..71de5c48d308d062c90e7936e999d0bba30f3ed5 100644
--- a/tests/library/Class/CodifThesaurusTest.php
+++ b/tests/library/Class/CodifThesaurusTest.php
@@ -22,8 +22,7 @@
 class CodifThesaurusTest extends ModelTestCase {
 	public function setUp() {
 		parent::setUp();
-		$this->old_sql = Zend_Registry::get('sql');
-//		$this->mock_sql
+
 		Storm_Test_ObjectWrapper::onLoaderOfModel('Class_CodifThesaurus')
 
 			->whenCalled('findFirstBy')
diff --git a/tests/library/Class/CriteresRechercheTest.php b/tests/library/Class/CriteresRechercheTest.php
index e4348bb89c05d5d053ff63cc716ce20d317d5e62..7422e660e1f79ae9a19f6ef991cd2051ab5ba43f 100644
--- a/tests/library/Class/CriteresRechercheTest.php
+++ b/tests/library/Class/CriteresRechercheTest.php
@@ -21,6 +21,7 @@
 
 class CriteresRechercheRetourTest extends AbstractControllerTestCase {
 	public function setUp() {
+		parent::setUp();
 		$this->criteres_recherche= new Class_CriteresRecherche();
 	}
 
@@ -169,6 +170,7 @@ class CriteresRechercheRetourRechercheInitialeTest extends AbstractControllerTes
 
 class CriteresRechercheNouvelleTest extends AbstractControllerTestCase {
 	public function setUp() {
+		parent::setUp();
 		$this->criteres_recherche= new Class_CriteresRecherche();
 	}
 
@@ -207,6 +209,7 @@ class CriteresRechercheNouvelleTest extends AbstractControllerTestCase {
 
 class CriteresRechercheUrlFacetteTest extends AbstractControllerTestCase {
 	public function setUp() {
+		parent::setUp();
 		$this->criteres_recherche= new Class_CriteresRecherche();
 	}
 
@@ -274,6 +277,7 @@ class CriteresRechercheUrlFacetteTest extends AbstractControllerTestCase {
 
 class CriteresRechercheFilterParamsTest extends AbstractControllerTestCase {
 	public function setUp() {
+		parent::setUp();
 		$this->criteres_recherche= new Class_CriteresRecherche();
 	}
 
diff --git a/tests/library/Class/DecodageUnimarcTest.php b/tests/library/Class/DecodageUnimarcTest.php
index 50320399895a61bddb4ce5d12f7ef7ceba1c0574..25b9b04922e0be49e8a95846b02e566447045b0f 100644
--- a/tests/library/Class/DecodageUnimarcTest.php
+++ b/tests/library/Class/DecodageUnimarcTest.php
@@ -20,16 +20,9 @@
  */
 
 
-class DecodageUnimarcDVDLaJeuneFilleTest extends PHPUnit_Framework_TestCase {
+class DecodageUnimarcDVDLaJeuneFilleTest extends Storm_Test_ModelTestCase {
 	public function setUp() {
-		$mock_sql = $this->getMockBuilder('Class_Systeme_Sql')
-                         			->disableOriginalConstructor()
-                        			->getMock();
-		Zend_Registry::set('sql', $mock_sql);
-		$mock_sql
-			->expects($this->any())
-			->method('fetchOne');
-
+		parent::setUp();
 		Class_CodifLangue::getLoader()
 			->newInstanceWithId('bam')
 			->setLibelle('');
@@ -40,7 +33,6 @@ class DecodageUnimarcDVDLaJeuneFilleTest extends PHPUnit_Framework_TestCase {
 			->setExemplaires(array());
 	}
 
-
 	public function testNotesSizeIsTwo() {
 		$this->assertEquals(2, count($this->dvd_jeune_fille->getNotes()));
 	}
diff --git a/tests/library/Class/GlobalSqlRefactoringTest.php b/tests/library/Class/GlobalSqlRefactoringTest.php
index 2ee092c0e22b22042a6930a8e5f0bf1e96c6395f..a2a68b98d62840e3255b613b6b63172066be8d13 100644
--- a/tests/library/Class/GlobalSqlRefactoringTest.php
+++ b/tests/library/Class/GlobalSqlRefactoringTest.php
@@ -19,8 +19,12 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA 
  */
 
-class GlobalSqlRefactoringTest extends PHPUnit_Framework_TestCase {
+class GlobalSqlRefactoringTest extends Storm_Test_ModelTestCase {
+	protected $_old_sql;
+
 	public function setUp() {
+		parent::setUp();
+		$this->_old_sql = Zend_Registry::get('sql');
 		$this->mock_sql = $this->getMockBuilder('Class_Systeme_Sql')
                          			->disableOriginalConstructor()
                         			->getMock();
@@ -28,6 +32,12 @@ class GlobalSqlRefactoringTest extends PHPUnit_Framework_TestCase {
 	}
 
 
+	public function tearDown() {
+		Zend_Registry::set('sql', $this->_old_sql);
+		parent::tearDown();
+	}
+
+
 	/** @test */
 	public function rssGetLastRss() {
 		$rss = new Class_Rss();
diff --git a/tests/library/Class/Indexation/PseudoNoticeTest.php b/tests/library/Class/Indexation/PseudoNoticeTest.php
index 99ed09366fd2d6b5a6405163f0d3cab7c2630816..955ee80e51b748f0f921547cd905743b2454f9f9 100644
--- a/tests/library/Class/Indexation/PseudoNoticeTest.php
+++ b/tests/library/Class/Indexation/PseudoNoticeTest.php
@@ -69,6 +69,39 @@ class Class_Indexation_PseudoNoticeAlbumTest extends Class_Indexation_PseudoNoti
 
 
 
+class Class_Indexation_PseudoNoticeSitothequeFromRawSQLTest extends Class_Indexation_PseudoNoticeTestCase {
+	protected $_sito;
+	protected $_notice;
+
+
+	public function setUp() {
+		parent::setUp();
+		$this->fixture('Class_Sitotheque', ['id' => 12,
+																				'titre' => 'Thot cursus',
+																				'url' => 'http://cursus.edu/',
+																				'description' => 'Top notch site',
+																				'tags' => 'VOD']);
+
+    /** as done in Cosmogramme */
+		Class_Indexation_PseudoNotice::newWith(Class_Indexation_PseudoNotice::TYPE_SITO,
+																					 ['ID_SITO' => 12,
+																						'TITRE' => 'Thot cursus',
+																						'URL' => 'http://cursus.edu/',
+																						'DESCRIPTION' => 'Top notch site',
+																						'TAGS' => 'VOD'])->save();
+
+		$this->_notice = Class_Notice::find(1);
+	}
+
+	/** @test */
+	public function titleShouldBeIndexed() {
+		$this->assertEquals('Thot cursus', $this->_notice->getTitrePrincipal());
+	}
+}
+
+
+
+
 class Class_Indexation_PseudoNoticeSitothequeTest extends Class_Indexation_PseudoNoticeTestCase {
 	protected $_sito;
 	protected $_notice;
diff --git a/tests/library/Class/MatiereTest.php b/tests/library/Class/MatiereTest.php
index b8d160efc14326940cd50ead481a56d64679719d..c5d44a29d73b8dcb56d80200e2a62febc72d2f35 100644
--- a/tests/library/Class/MatiereTest.php
+++ b/tests/library/Class/MatiereTest.php
@@ -19,16 +19,7 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA 
  */
 
-class MatiereTest extends PHPUnit_Framework_TestCase {
-	public function setUp() {
-		$this->mock_sql = $this
-												->getMockBuilder('Class_Systeme_Sql')
-												->disableOriginalConstructor()
-												->getMock();
-		Zend_Registry::set('sql', $this->mock_sql);
-	}
-
-
+class MatiereTest extends Storm_Test_ModelTestCase {
 	/** @test */
 	function sqlQueriesShouldBeEscaped() {
 		Storm_Test_ObjectWrapper::onLoaderOfModel('Class_Matiere')
diff --git a/tests/library/Class/MoteurRechercheTest.php b/tests/library/Class/MoteurRechercheTest.php
index 40487f55719b43d17d4756e4a8831edac2c620b7..990583835e6f42a7e606fd7e8d6d020623da818f 100644
--- a/tests/library/Class/MoteurRechercheTest.php
+++ b/tests/library/Class/MoteurRechercheTest.php
@@ -20,8 +20,10 @@
  */
 
 abstract class MoteurRechercheAbstractTest extends Storm_Test_ModelTestCase {
-	protected $mock_sql;
-	protected $expected_date = '2012-05-03';
+	protected 
+		$mock_sql,
+		$_original_sql,
+		$expected_date = '2012-05-03';
 	
 
 	public function setUp() {
@@ -696,12 +698,6 @@ class MoteurRechercheCatalogueTest extends MoteurRechercheAbstractTest {
 	}
 
 
-	public function tearDown() {
-		Zend_Registry::set('sql', $this->_original_sql);
-		parent::tearDown();
-	}
-
-
 	public function expectedSql() {
 		return [
 			[ 
diff --git a/tests/library/Class/MusicMeLinkTest.php b/tests/library/Class/MusicMeLinkTest.php
index b9cd713887c52c8513beb6659cb44ac9e2e940b8..7e6912a3e9e9d736391180cb81d44396ec798017 100644
--- a/tests/library/Class/MusicMeLinkTest.php
+++ b/tests/library/Class/MusicMeLinkTest.php
@@ -57,7 +57,7 @@ class MusicMeLinkWithAbonTest extends MusicMeLinkTestCase {
 
 /** @test */
 	public function musicMeUrlShouldExtractUrlFromResponse() {
-		$ticket=md5( Zend_Session::getId() . '4');
+		$ticket='ST-'.md5( Zend_Session::getId() . '4');
 		$this->assertEquals('http://musicmeurl/?iduser=34&ticket='.$ticket.
 												'&MediaLibraryID=888&service=http%3A%2F%2Fmusicmeurl%2F%3Fiduser%3D34%26ticket%3D'.$ticket.'%26MediaLibraryID%3D888',
 												$this->_musicme->url());
diff --git a/tests/library/Class/NumilogLinkTest.php b/tests/library/Class/NumilogLinkTest.php
index e9e506002355fe4e9c2d3be4f39a458ba7578eea..1e8e705062cf1000b3fe257432c43babb600b17b 100644
--- a/tests/library/Class/NumilogLinkTest.php
+++ b/tests/library/Class/NumilogLinkTest.php
@@ -63,14 +63,14 @@ abstract class NumilogLinkTestCase extends Storm_Test_ModelTestCase {
 
   /** @test */
 	public function numilogUrlShouldReturnUrlWithTicket() {
-		$this->assertEquals('http://urlnumilog/action?ticket='.md5( Zend_Session::getId() . '4'), 
+		$this->assertEquals('http://urlnumilog/action?ticket=ST-'.md5( Zend_Session::getId() . '4'), 
 												$this->_numilog->url());
 	}
 
 
   /** @test */
 	public function numilogUrlExternalShouldReturnUrlWithTicket() {
-		$this->assertEquals('http://url-given-bynumilog?withparam=2&ticket='.md5( Zend_Session::getId() . '4'), 
+		$this->assertEquals('http://url-given-bynumilog?withparam=2&ticket=ST-'.md5( Zend_Session::getId() . '4'), 
 												$this->_numilog->urlExternal('http://url-given-bynumilog?withparam=2'));
 	}
 
diff --git a/tests/library/Class/ProfilTest.php b/tests/library/Class/ProfilTest.php
index b5cedc0a3d97242653cccefea6c996e737b2e630..120ffb72230ac5af5f37cc016b75e2ab23ed41d8 100644
--- a/tests/library/Class/ProfilTest.php
+++ b/tests/library/Class/ProfilTest.php
@@ -1241,4 +1241,159 @@ class ProfilHeaderImgAccessTest extends Storm_Test_ModelTestCase {
 }
 
 
+
+abstract class ProfilUpdateConfigAccueilOnModuleInBannerTestCase 
+extends Storm_Test_ModelTestCase {
+	protected $_profil;
+
+	public function setUp() {
+		parent::setUp();
+		$this->_profil = $this->fixture('Class_Profil', ['id' => 1])
+			->setBoiteLoginInBanniere(true);
+
+		$this->prepareProfile();
+
+		$config = $this->_profil->getModuleAccueilConfig(1);
+		$config['preferences']['profil_redirect'] = 123;
+
+		$this->_profil->updateModuleConfigAccueil(1, $config);
+	}
+
+
+	protected function prepareProfile() {}
+
+
+	protected function getPreferenceOfModule($profil, $id_module, $preference) {
+		return $profil->getModuleAccueilConfig($id_module)['preferences'][$preference];
+	}
+}
+
+
+
+
+class ProfilUpdateConfigAccueilOnModuleInBannerTest 
+extends ProfilUpdateConfigAccueilOnModuleInBannerTestCase {
+	/** @test */
+	public function profilRedirectShouldBeUpdated() {
+		$this->assertEquals(123, 
+												$this->getPreferenceOfModule($this->_profil, 
+																										 1, 'profil_redirect'));
+	}
+}
+
+
+
+class ProfilUpdateConfigAccueilOnModuleInBannerWithParentTest 
+extends ProfilUpdateConfigAccueilOnModuleInBannerTestCase {
+	protected function prepareProfile() {
+		$this->_profil->setParentProfil($this->fixture('Class_Profil', ['id' => 2])
+																		->setBoiteLoginInBanniere(true));
+	}
+
+
+	/** @test */
+	public function profilRedirectShouldBeUpdatedInParent() {
+		$this->assertEquals(123, 
+												$this->getPreferenceOfModule($this->_profil->getParentProfil(), 
+																										 1, 'profil_redirect'));
+	}
+}
+
+
+
+class ProfilGetModuleAccueilConfigTest extends Storm_Test_ModelTestCase {
+	protected $_profil, $_parent, $_module_config;
+
+	public function setUp() {
+		parent::setUp();
+		$this->_parent = $this->fixture('Class_Profil', ['id' => 1])
+			->setBoiteLoginInBanniere(true);
+
+		$this->_profil = $this->fixture('Class_Profil', ['id' => 2,
+																										 'parent_profil' => $this->_parent]);
+
+		$this->_module_config = $this->_profil->getModuleAccueilConfig(1);
+	}
+
+
+	/** @test */
+	public function parentShouldHaveLoginInBanner() {
+		$this->assertTrue($this->_parent->getBoiteLoginInBanniere());
+	}
+
+
+	/** @test */
+	public function moduleDivisionShouldBeBanner() {
+		$this->assertEquals(Class_Profil::DIV_BANNIERE, $this->_module_config['division']);
+	}
+}
+
+
+
+class ProfilPreferenceAuthRegisterTest extends Storm_Test_ModelTestCase {
+	public function setUp() {
+		parent::setUp();
+		$this->portal = $this->fixture('Class_Profil',
+																	 ['id' => 1,
+																		'libelle' => 'portail']);
+
+		$this->youth = $this->fixture('Class_Profil',
+																	['id' => 5,
+																	 'libelle' => 'jeunesse']);
+
+		$this->modules = new Class_Systeme_ModulesAppli();
+	}
+
+	
+	/** @test */
+	public function withoutConfigurationYouthProfilPrefsShouldBeDefaultValues() {
+		$this->assertEquals($this->modules->getValeursParDefaut('auth','register'),
+												$this->youth->getCfgModulesPreferences('auth', 'register'));
+	}
+
+
+	/** @test */
+	public function withConfigInPortalYouthProfilPrefsShouldBePortalValues() {
+		$this->portal->setModulePreference('auth', 'register', 'register_confirm', 'I confirm');
+		$this->assertEquals('I confirm',
+												$this->youth->getModulePreference('auth', 'register', 'register_confirm'));
+	}
+
+
+	/** @test */
+	public function withConfigInYouthProfilPrefsShouldBeYouthValues() {
+		$this->portal->setModulePreference('auth', 'register', 'register_confirm', 'I confirm');
+		$this->youth->setModulePreference('auth', 'register', 'register_confirm', 'Youpi');
+		$this->assertEquals('Youpi',
+												$this->youth->getModulePreference('auth', 'register', 'register_confirm'));
+	}
+}
+
+
+
+class ProfilIsPortalTest extends Storm_Test_ModelTestCase {
+	/** @test */
+	public function profilWithIdOneIntShouldBePortal() {
+		$this->assertTrue($this->fixture('Class_Profil', ['id' => 1])->isPortail());
+	}
+
+
+	/** @test */
+	public function profilWithIdOneStringShouldBePortal() {
+		$this->assertTrue($this->fixture('Class_Profil', ['id' => '1'])->isPortail());
+	}
+
+
+	/** @test */
+	public function profilWithIdSevenIntShouldBePortal() {
+		$this->assertFalse($this->fixture('Class_Profil', ['id' => 7])->isPortail());
+	}
+
+
+	/** @test */
+	public function profilWithIdSevenStringShouldNotBePortal() {
+		$this->assertFalse($this->fixture('Class_Profil', ['id' => '7'])->isPortail());
+	}
+
+}
 ?>
\ No newline at end of file
diff --git a/tests/library/Class/UsersTest.php b/tests/library/Class/UsersTest.php
index 57defe28a184f6a3b7f55976318f6a34b2bc3291..16de7b7fde52ee1ed5cfa6a1d4267569a92742f1 100644
--- a/tests/library/Class/UsersTest.php
+++ b/tests/library/Class/UsersTest.php
@@ -455,19 +455,17 @@ class UsersTestAge extends ModelTestCase {
 
 
 abstract class UsersMailingActionTestCase extends Storm_Test_ModelTestCase {
-	protected $mock_transport, $user ,$mock_sql;
+	protected $mock_transport, $user;
 
 	public function setUp() {
 		parent::setUp();
+		Zend_Registry::get('translate')->setLocale('fr');
 		$this->mock_transport = new MockMailTransport();
 		Zend_Mail::setDefaultTransport($this->mock_transport);
 
 
 		$this->user = new Class_Users();
 
-		$this->mock_sql = Storm_Test_ObjectWrapper::on(Zend_Registry::get('sql'));
-		Zend_Registry::set('sql', $this->mock_sql);
-
 
 		Class_CosmoVar::getLoader()
 			->newInstanceWithId('mail_admin')
@@ -477,23 +475,22 @@ abstract class UsersMailingActionTestCase extends Storm_Test_ModelTestCase {
 			->setMailSite('');
 	}
 
-	public function tearDown() {
-		Zend_Registry::set('sql', $this->mock_sql->getWrappedObject());
-		parent::tearDown();
-	}
 
 	protected function getSentMail() {
 		return $this->mock_transport->sent_mail;
 	}
 
+
 	protected function getSentMailRecipients() {
 		return $this->getSentMail()->getRecipients();
 	}
 
+
 	protected function getSentMailFrom() {
 		return $this->getSentMail()->getFrom();
 	}
 
+
 	protected function getSentMailContent() {
 		return quoted_printable_decode($this->getSentMail()->getBodyText()->getContent());
 	}
@@ -508,13 +505,18 @@ class UsersLostPassTest extends UsersMailingActionTestCase {
 	public function setUp() {
 		parent::setUp();
 
-		$this->mock_sql
-			->whenCalled('fetchEnreg')
-			->with("Select * from bib_admin_users where LOGIN='zork'", false)
-			->answers(array('LOGIN' => 'zork',
-											'MAIL' => 'zork@afi.fr',
-											'PASSWORD' => '123'))
-			->beStrict();
+		$this->fixture('Class_Users',
+									 ['id' => '8',
+										'login' => 'zork',
+										'mail' => 'zork@afi.fr',
+										'password' => '123']);
+
+
+		$this->fixture('Class_UsersNonValid',
+									 ['id' => '9',
+										'login' => 'glub',
+										'mail' => 'glub@afi.fr',
+										'password' => '456']);
 
 		$this->ret = $this->user->lostPass('zork');
 	}
@@ -538,159 +540,22 @@ class UsersLostPassTest extends UsersMailingActionTestCase {
 		$this->assertContains('Votre identifiant : zork', $body);
 		$this->assertContains('Votre mot de passe : 123', $body);
 	}
-}
-
-
-
-abstract class UsersRegistrationTestCase extends UsersMailingActionTestCase {
-	protected $user;
-
-	public function setUp() {
-		parent::setUp();
-
-		Class_AdminVar::getLoader()
-			->newInstanceWithId('REGISTER_OK')
-			->setValeur('');
-
-		$this->mock_sql
-			->whenCalled('fetchOne')
-			->answers(0)
-
-			->whenCalled('insert')
-			->answers(true)
-			
-			->whenCalled('fetchOne')
-			->with("select count(*) from bib_admin_users_non_valid Where MAIL='zork@afi-sa.fr'")
-			->answers(1)
-
-
-			->whenCalled('fetchOne')
-			->with("select count(*) from bib_admin_users Where MAIL='glub@afi-sa.fr'")
-			->answers(1);
-
-
-		Storm_Test_ObjectWrapper::onLoaderOfModel('Class_Users')
-			->whenCalled('findFirstBy')
-			->answers(false)
-
-			->whenCalled('findFirstBy')
-			->with(array('login' => 'laurent'))
-			->answers(true);
-	}
-}
-
-
-class UsersRegistrationMailVerifTest extends UsersRegistrationTestCase {
-	/** @test */
-	public function verifMailWithMalformedAdressShouldReturnFalse() {
-		$this->assertFalse($this->user->verifMail('wrong'));
-	}
 
 
 	/** @test */
-	public function verifMailWithZorkAtAfiSaDotFrShouldReturnFalse() {
-		$this->assertFalse($this->user->verifMail('zork@afi-sa.fr'));
-	}
-
-
-	/** @test */
-	public function verifMailWithGlubAtAfiSaDotFrShouldReturnFalse() {
-		$this->assertFalse($this->user->verifMail('glub@afi-sa.fr'));
-	}
-
-
-	/** @test */
-	public function verifMailWithLlaffontAtAfiSaDotFrShouldReturnTrue() {
-		$this->assertTrue($this->user->verifMail('llaffont@afi-sa.fr'));
+	public function withUserNonValidGlubMailShouldHaveBeenSentToGlub() {
+		$this->ret = $this->user->lostPass('glub');
+		$this->assertContains('glub@afi.fr', $this->getSentMailRecipients());
 	}
 }
 
 
-class UsersRegistrationLoginLaurentTest extends UsersRegistrationTestCase {
-	public function setUp() {
-		parent::setUp();
-		$_SESSION['captcha_code'] = '1234';
-		$this->ret = $this->user->registerUser(['login' => 'laurent',
-																						'mail' => '',
-																						'test_mail' => '',
-																						'mdp' => 'bug',
-																						'mdp2' => 'hoho',
-																						'captcha' => '--']);
-	}
-
-	/** @test */
-	public function shouldHaveAlreadyRegisteredError() {
-		$this->assertErrorContains('Cet identifiant existe déjà');
-	}
-
-	/** @test */
-	public function shouldHavePasswordError() {
-		$this->assertErrorContains('Vous n\'avez pas saisi les mêmes mots de passe');
-	}
-
-	/** @test */
-	public function shouldHaveMailError() {
-		$this->assertErrorContains('L\'adresse e-mail est invalide ou est déjà utilisée.');
-	}
-
-	protected function assertErrorContains($value) {
-		$this->assertContains($value, $this->ret['error']);
-	}
-}
-
-
-class UsersRegistrationLoginMarioTest extends UsersRegistrationTestCase {
-	public function setUp() {
-		parent::setUp();
-		$_SESSION['captcha_code'] = '1234';
-		$this->_datas = ['login' => 'mario',
-										 'mail' => 'mario@afi-sa.fr',
-										 'test_mail' => 'mario@afi-sa.fr',
-										 'mdp' => 'secret',
-										 'mdp2' => 'secret',
-										 'captcha' => '1234',
-										 'cle' => 'xxx'];
-	}
-
-	/** @test */
-	public function recipientShouldBeMario() {
-		$this->user->registerUser($this->_datas);
-		$this->assertContains('mario@afi-sa.fr', $this->getSentMailRecipients());
-	}
-
-	/** @test */
-	public function contentShouldBeAsExpected() {
-		$this->user->registerUser($this->_datas);
-		$this->assertContains('Vous avez fait une demande d\'inscription', $this->getSentMailContent());
-	}
-
-	/** @test */
-	public function confirmationShouldBeAsExpected() {
-		$ret = $this->user->registerUser($this->_datas);
-		$this->assertContains('Un mail viens de vous être envoyé pour confirmer votre inscription', 
-													$ret['message_mail']);
-	}
-
-	/** @test */
-	public function withoutProfilMailSenderShouldBeAdmin() {
-		$this->user->registerUser($this->_datas);
-		$this->assertContains('admin@afi-sa.fr', $this->getSentMailFrom());
-	}
-
-	/** @test */
-	public function withProfilMailSenderShouldBeProfil() {
-		Class_Profil::getCurrentProfil()->setMailSite('profil@afi-sa.fr');
-		$this->user->registerUser($this->_datas);
-		$this->assertContains('profil@afi-sa.fr', $this->getSentMailFrom());
-	}
-}
-
 
 
 class UsersFicheAbonneTest extends Storm_Test_ModelTestCase {
 	public function setUp() {
 		parent::setUp();
-
+		Zend_Registry::get('translate')->setLocale('fr');
 		Storm_Cache::setDefaultZendCache(null);
 
 		$this->bib_astro = Class_IntBib::getLoader()
@@ -789,6 +654,7 @@ class UsersFicheAbonneTest extends Storm_Test_ModelTestCase {
 
 
 
+
 class UserStabiloUpdatedWithUserTomTest extends Storm_Test_ModelTestCase {
 
 	protected $stabilo, $tom;
diff --git a/tests/library/Class/WebService/SIGB/OpsysServiceTest.php b/tests/library/Class/WebService/SIGB/OpsysServiceTest.php
index b32ce8f99db8873bba10730c2749a0fdcb4635a7..05bdac979d91f2a46a640b5e03c7f5e13d6cf3e0 100644
--- a/tests/library/Class/WebService/SIGB/OpsysServiceTest.php
+++ b/tests/library/Class/WebService/SIGB/OpsysServiceTest.php
@@ -1626,4 +1626,42 @@ class OpsysServiceEmprAuthentifierParamsTest extends OpsysServiceWithSessionTest
 	}
 }
 
+
+
+
+class OpsysServiceDisconnectTest extends OpsysServiceWithSessionTestCase {
+	protected $_fermer_session;
+
+	public function setUp() {
+		parent::setUp();
+		
+		$this->search_client			
+			->whenCalled('FermerSession')
+			->willDo(
+				function($fs) {
+					$this->_fermer_session = $fs;
+				});
+
+		$this->opsys->disconnect();
+	}
+
+
+	/** @test */
+	public function guidShouldBe12345() {
+		$this->assertEquals('guid_12345', $this->_fermer_session->Param->GUIDSession);
+	}
+
+
+	/** @test */
+	public function nomMachineShouldBeInternet() {
+		$this->assertEquals('INTERNET', $this->_fermer_session->Param->NomMachine);
+	}
+
+
+	/** @test */
+	public function serveurSessionNomServeurShouldBeInternet() {
+		$this->assertEquals('INTERNET', $this->_fermer_session->Param->ListeServeurs[0]->NomServeur);
+	}
+}
+
 ?>
\ No newline at end of file
diff --git a/tests/library/ZendAfi/View/Helper/Accueil/KiosqueTest.php b/tests/library/ZendAfi/View/Helper/Accueil/KiosqueTest.php
index edb9118d20d978131a2497be9f1149ad8d450935..86a87019940e6a5b8c2ae2dd801a44a44d5f7feb 100644
--- a/tests/library/ZendAfi/View/Helper/Accueil/KiosqueTest.php
+++ b/tests/library/ZendAfi/View/Helper/Accueil/KiosqueTest.php
@@ -353,6 +353,8 @@ class ZendAfi_View_Helper_Accueil_KiosqueRequetesWithCacheEnabledTest extends Ze
 	}
 }
 
+
+
 class ZendAfi_View_Helper_Accueil_KiosqueChangeSelectRequetesTest extends ZendAfi_View_Helper_Accueil_KiosqueMurTestCase{
 	
 	public function getExtraPreferences() {
diff --git a/tests/library/ZendAfi/View/Helper/Notice/ExemplairesTest.php b/tests/library/ZendAfi/View/Helper/Notice/ExemplairesTest.php
index 9dba30a78a7786074d6875804b116ca9fb9db15a..5b36fbc1192e16e5cc227b6b65516772d9cd497d 100644
--- a/tests/library/ZendAfi/View/Helper/Notice/ExemplairesTest.php
+++ b/tests/library/ZendAfi/View/Helper/Notice/ExemplairesTest.php
@@ -28,15 +28,6 @@ abstract class ZendAfi_View_Helper_Notice_ExemplairesTestCase extends ViewHelper
 		parent::setUp();
 		$this->_helper = new ZendAfi_View_Helper_Notice_Exemplaires();
 		$this->_helper->setView(new ZendAfi_Controller_Action_Helper_View());
-
-		$this->mock_sql = Storm_Test_ObjectWrapper::on(Zend_Registry::get('sql'));
-		Zend_Registry::set('sql', $this->mock_sql);
-
-		$this->mock_sql
-			->whenCalled('fetchEnreg')
-			->answers(['LIBELLE' => 'libelle',
-								 'GOOGLE_MAP' => 'map',
-								 'INTERDIRE_RESA' => false]);
 	}
 }
 
@@ -105,7 +96,6 @@ abstract class NoticeHtmlGetExemplairesWithOneExemplaireAndWebServiceTestCase ex
 			->beReservable()
 			->setNbReservations(4);
 
-		Class_Profil::setCurrentProfil(
 			Class_Profil::getLoader()
 			->newInstanceWithId(4)
 			->setCfgNotice(array('exemplaires' => array('grouper' => 1,
@@ -117,7 +107,8 @@ abstract class NoticeHtmlGetExemplairesWithOneExemplaireAndWebServiceTestCase ex
 																									'date_retour' => 1,
 																									'localisation' => 1,
 																									'plan' => 1,
-																									'resa' => 1))));
+																									'resa' => 1)))
+				->beCurrentProfil();
 
 
 		Class_IntBib::getLoader()
diff --git a/tests/library/ZendAfi/View/Helper/ViewHelperTestCase.php b/tests/library/ZendAfi/View/Helper/ViewHelperTestCase.php
index e2a9e42243f899aa8ee23f9c46b0ef5ee64d06fc..6a4436c04c7c0ed1a9e4f1d6893f299f44848114 100644
--- a/tests/library/ZendAfi/View/Helper/ViewHelperTestCase.php
+++ b/tests/library/ZendAfi/View/Helper/ViewHelperTestCase.php
@@ -118,6 +118,8 @@ abstract class ViewHelperTestCase extends PHPUnit_Framework_TestCase {
 			->setValeur(null);
 
 		Storm_Cache::setDefaultZendCache(null);
+
+		Zend_Registry::get('translate')->setLocale('fr');
 	}
 
 
diff --git a/tests/library/fonctions/UserAgentTest.php b/tests/library/fonctions/UserAgentTest.php
index 13c8bdfb0320d3799f74b3e9f999bbcf3aa1422f..6fa6eb8bc767ba03d9d96836431426f91cad890b 100644
--- a/tests/library/fonctions/UserAgentTest.php
+++ b/tests/library/fonctions/UserAgentTest.php
@@ -42,6 +42,40 @@ class BotUserAgentTest extends PHPUnit_Framework_TestCase {
 																															 date('H')+1,
 																															 date('H')+2));
 	}
+
+
+	public function botUserAgents() {
+		return [
+			['Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)'],
+			['Mozilla/5.0 (compatible; SISTRIX Crawler; http://crawler.sistrix.net/)'],
+			['Mozilla/5.0 (Windows NT 5.1; U; Win64; fr; rv:1.8.1) VoilaBot BETA 1.2 (support.voilabot@orange-ftgroup.com)'],
+			];
+	}
+
+	/** 
+	 * @dataProvider botUserAgents
+	 * @test 
+	 */
+	public function isUserAgentShouldReturnTrueForAgent($agent) {
+		$this->assertTrue(isUserAgentBot($agent));
+	}
+
+
+	public function browserUserAgents() {
+		return [
+			['Mozilla/5.0'],
+			['Webkit'],
+			['Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; )']
+			];
+	}
+
+	/** 
+	 * @dataProvider browserUserAgents
+	 * @test 
+	 */
+	public function isUserAgentShouldReturnFalseForAgent($agent) {
+		$this->assertFalse(isUserAgentBot($agent));
+	}
 }
 
 ?>
\ No newline at end of file