diff --git a/VERSIONS_WIP/27641 b/VERSIONS_WIP/27641
new file mode 100644
index 0000000000000000000000000000000000000000..8cbc32ed4041b8ee6f335c70925a2c72e39c43e3
--- /dev/null
+++ b/VERSIONS_WIP/27641
@@ -0,0 +1 @@
+ - ticket #27641 : Les renvois d'autorités BNF (auteur et mot matières) ne sont plus perdus à l'import total suivant
\ No newline at end of file
diff --git a/cosmogramme/php/classes/classe_http_request.php b/cosmogramme/php/classes/classe_http_request.php
index d5efa92e1e7de4c7f8f500b84bcdad978de3160c..bfd1c8b7c50c6c26a8f0e76b8ed0ece469214aa7 100644
--- a/cosmogramme/php/classes/classe_http_request.php
+++ b/cosmogramme/php/classes/classe_http_request.php
@@ -16,7 +16,7 @@
  *
  * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
  * along with BOKEH; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA 
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
  */
 //////////////////////////////////////////////////////////////////////////////////////////
 //	RECUPERE LE CONTENU D'UNE URL
@@ -31,7 +31,7 @@ class HTTPRequest
    private $_port;								// port
    private $proxy;								// Param�tres de connexion proxy
    private $header;								// Header de retour
-   
+
    // constructor
    function __construct($url)
    {
@@ -40,30 +40,30 @@ class HTTPRequest
        $this->proxy["port"]=$cfg["PROXY_PORT"];
        $this->proxy["user"]=$cfg["PROXY_USER"];
        $this->proxy["passe"]=$cfg["PROXY_PASSE"];
-    
+
        $this->_url = $url;
        if((strScan(strtoupper($url),"LOCALHOST",0)>0) or (strScan($url,"127.0.0.1",0)>0)) unset($this->proxy);
        $this->_scan_url();
    }
-   
+
    // scan url
    function _scan_url()
    {
-       $req = $this->_url;    
+       $req = $this->_url;
        $pos = strpos($req, '://');
        $this->_protocol = strtolower(substr($req, 0, $pos));
-       
+
        $req = substr($req, $pos+3);
        $pos = strpos($req, '/');
        if($pos === false)
            $pos = strlen($req);
        $host = substr($req, 0, $pos);
-       
+
        if(strpos($host, ':') !== false)
        {
            list($this->_host, $this->_port) = explode(':', $host);
        }
-       else 
+       else
        {
            $this->_host = $host;
            $this->_port = ($this->_protocol == 'https') ? 443 : 80;
@@ -75,7 +75,7 @@ class HTTPRequest
        	if($this->_uri == '') $this->_uri = '/';
       }
    }
-   
+
    // download URL to string
    function DownloadToString()
    {
@@ -92,10 +92,10 @@ class HTTPRequest
        $req.='Content-type: text/html; charset=ISO-8859-1'.$crlf;
 
        $req.=$crlf;
-       
-       
+
+
       // print($req); exit;
-       
+
        // open
        if($this->proxy["host"]) $fp = @fsockopen( $this->proxy["host"], $this->proxy["port"]);
        else $fp = @fsockopen(($this->_protocol == 'https' ? 'ssl://' : '') . $this->_host, $this->_port);
@@ -104,14 +104,14 @@ class HTTPRequest
        // get data
        while(is_resource($fp) && $fp && !feof($fp)) $response .= fread($fp, 512);
        fclose($fp);
-       
+
        // split header and body
        $pos = strpos($response, $crlf . $crlf);
        if($pos === false)
            return($response);
        $header = substr($response, 0, $pos);$this->header=$header;
        $body = substr($response, $pos + 2 * strlen($crlf));
-       
+
        // parse headers
        $headers = array();
        $lines = explode($crlf, $header);
@@ -124,10 +124,9 @@ class HTTPRequest
            $http = new HTTPRequest($headers['location']);
            return($http->DownloadToString($http));
        }
-       else 
+       else
        {
            return($body);
        }
    }
-}
-?> 
+}
\ No newline at end of file
diff --git a/cosmogramme/php/classes/classe_indexation.php b/cosmogramme/php/classes/classe_indexation.php
index c340edaaea13d528dfb96521192569d5e18c8e52..dde19fe198ac13e7993f3b55e2da822a5440a76d 100644
--- a/cosmogramme/php/classes/classe_indexation.php
+++ b/cosmogramme/php/classes/classe_indexation.php
@@ -22,23 +22,10 @@
 class indexation extends Class_Indexation {
 	protected static $phonetixCache = [];
 
-	public function __construct() {
-		if (empty(static::$phonetixCache))
-			static::$phonetixCache = unserialize(file_get_contents(dirname(__FILE__).'/phonetix.txt'));
-		parent::__construct();
-	}
-
-
-	function phonetix($sIn) {
+	public function phonetix($sIn) {
 		if (strlen($sIn)<4 || is_numeric($sIn))
 			return false;
 
-		/* if (count(static::$phonetixCache) > 60000) { */
-		/* 	ksort(static::$phonetixCache); */
-		/* 	file_put_contents('/tmp/phonetix.txt', serialize(static::$phonetixCache)); */
-		/* 	exit; */
-		/* } */
-
 		return isset(static::$phonetixCache[$sIn])
 			? static::$phonetixCache[$sIn]
 			: static::$phonetixCache[$sIn] = $this->phonetixCompute($sIn);
diff --git a/cosmogramme/php/classes/classe_notice_integration.php b/cosmogramme/php/classes/classe_notice_integration.php
index 8535dd79fd62ca2d9a64fdace65811279c4af7cb..5f369c6f244c4e5007cbbe0d6e54ef2c1ac8b356 100644
--- a/cosmogramme/php/classes/classe_notice_integration.php
+++ b/cosmogramme/php/classes/classe_notice_integration.php
@@ -19,12 +19,13 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
  */
 
-require_once("Class/Isbn.php");
-require_once("classe_indexation.php");
-require_once("classe_unimarc.php");
-require_once("classe_codif_matiere.php");
-require_once("classe_codif_langue.php");
-require_once("classe_profil_donnees.php");
+require_once 'Class/Isbn.php';
+require_once 'classe_indexation.php';
+require_once 'classe_unimarc.php';
+require_once 'classe_codif_matiere.php';
+require_once 'classe_codif_langue.php';
+require_once 'classe_profil_donnees.php';
+require_once 'classe_communication.php';
 
 class notice_integration {
   const
@@ -72,11 +73,13 @@ class notice_integration {
   /** @category testing */
   protected $_service_runner;
 
+  protected $_codif_provider;
+
   public function __construct() {
-    $this->indexation=new indexation();
+    $this->indexation = indexation::getInstance();
     $this->filtrer_fulltext = Class_CosmoVar::get("filtrer_fulltext");
     $this->mode_doublon = Class_CosmoVar::get("mode_doublon");
-    $this->notice_sgbd=new notice_unimarc();
+    $this->notice_sgbd = new notice_unimarc();
   }
 
 
@@ -534,37 +537,78 @@ class notice_integration {
 
 
   public function noticeToDBEnreg() {
-    return [
-      "type_doc" => $this->notice["type_doc"],
-      "alpha_titre" => $this->notice["alpha_titre"],
-      "alpha_auteur" => $this->notice["alpha_auteur"],
-
-      "titres" => $this->indexation->getfullText(array_merge($this->notice["titres"],
-                                                             [$this->notice["clef_chapeau"],
-                                                              $this->notice["tome_alpha"]])),
-
-      "auteurs" => $this->indexation->getfullText( $this->notice["auteurs"]
-                                                   ? array_merge($this->notice["auteurs"],$this->notice["auteurs_renvois"])
-                                                   : $this->notice["200_f"]),
-
-      "editeur" => $this->indexation->getfullText($this->notice["editeur"]),
-      "collection" => $this->indexation->getfullText($this->notice["collection"]),
-      "matieres" => $this->indexation->getfullText(array_merge($this->notice["matieres"],$this->notice["matieres_renvois"])),
-      "dewey" => $this->indexation->getfullText($this->notice["full_dewey"]),
-      "facettes" => $this->notice["facettes"],
-      "isbn" => $this->notice["isbn"],
-      "ean" => $this->notice["ean"],
-      "id_commerciale" => $this->notice["id_commerciale"],
-      "clef_alpha" => $this->notice["clef_alpha"],
-      "clef_chapeau" => $this->notice["clef_chapeau"],
-      "clef_oeuvre" => $this->notice["clef_oeuvre"],
-      "tome_alpha" => $this->notice["tome_alpha"],
-      "annee" => $this->notice["annee"],
-      "qualite" => $this->notice["qualite"],
-      "exportable" => $this->notice["exportable"],
-      "cote" => $this->notice["cote"],
-      "unimarc" => $this->notice['unimarc'],
-      "date_maj" => dateDuJour(2) ];
+    return ["type_doc" => $this->notice["type_doc"],
+            "alpha_titre" => $this->notice["alpha_titre"],
+            "alpha_auteur" => $this->notice["alpha_auteur"],
+
+            "titres" => $this->indexation->getfullText(array_merge($this->notice["titres"],
+                                                                   [$this->notice["clef_chapeau"],
+                                                                    $this->notice["tome_alpha"]])),
+
+            "auteurs" => $this->indexation->getfullText($this->_getFulltextAuthors()),
+
+            "editeur" => $this->indexation->getfullText($this->notice["editeur"]),
+            "collection" => $this->indexation->getfullText($this->notice["collection"]),
+            "matieres" => $this->indexation->getfullText($this->_getFulltextTopics()),
+            "dewey" => $this->indexation->getfullText($this->notice["full_dewey"]),
+            "facettes" => $this->notice["facettes"],
+            "isbn" => $this->notice["isbn"],
+            "ean" => $this->notice["ean"],
+            "id_commerciale" => $this->notice["id_commerciale"],
+            "clef_alpha" => $this->notice["clef_alpha"],
+            "clef_chapeau" => $this->notice["clef_chapeau"],
+            "clef_oeuvre" => $this->notice["clef_oeuvre"],
+            "tome_alpha" => $this->notice["tome_alpha"],
+            "annee" => $this->notice["annee"],
+            "qualite" => $this->notice["qualite"],
+            "exportable" => $this->notice["exportable"],
+            "cote" => $this->notice["cote"],
+            "unimarc" => $this->notice['unimarc'],
+            "date_maj" => dateDuJour(2) ];
+  }
+
+
+  protected function _getFulltextAuthors() {
+    if (!$this->notice['auteurs'])
+      return $this->notice["200_f"];
+
+    return array_merge($this->notice["auteurs"],
+                       $this->notice["auteurs_renvois"],
+                       $this->_getCodifAuteurRenvois());
+  }
+
+
+  protected function _getCodifAuteurRenvois() {
+    $see_also = [];
+    foreach($this->notice['auteurs'] as $author) {
+      if (($codif = $this->_getCodifAuteur($author))
+          && $codif->hasMotsRenvois())
+        $see_also[] = $codif->getMotsRenvois();
+    }
+
+    return $see_also;
+  }
+
+
+  protected function _getFulltextTopics() {
+    if (!$this->notice['matieres'])
+      return ;
+
+    return array_merge($this->notice["matieres"],
+                       $this->notice["matieres_renvois"],
+                       $this->_getCodifTopicsRenvois());
+  }
+
+
+  protected function _getCodifTopicsRenvois() {
+    $see_also = [];
+
+    foreach($this->notice['matieres'] as $topic) {
+      if (($codif = $this->_getCodifTopic($topic))
+          && $codif->hasMotsRenvois())
+        $see_also[] = $codif->getMotsRenvois();
+    }
+    return $see_also;
   }
 
 
@@ -832,18 +876,8 @@ class notice_integration {
     // Matieres
     if($this->notice["matieres"])  {
       foreach($this->notice["matieres"] as $matiere)  {
-        // limit to the maximum size of code_alpha column in db to avoid duplicates
-        $code_alpha = substr($this->indexation->alphaMaj($matiere), 0, 255);
-        if(!$code_alpha) continue;
-
-        if (!$codif_matiere = Class_CodifMatiere::findFirstBy(['code_alpha' => $code_alpha])) {
-          $codif_matiere = Class_CodifMatiere::newInstance(['libelle' => $matiere,
-                                                            'code_alpha' => $code_alpha]);
-          $codif_matiere->save();
-        }
-
-        $id_matiere = $codif_matiere->getId();
-        $facettes[]="M".$id_matiere;
+        if (!$codif_matiere = $this->_getCodifTopic($matiere)) continue;
+        $facettes[]="M".$codif_matiere->getId();
       }
     }
 
@@ -897,24 +931,21 @@ class notice_integration {
 
 
   public function getFacetteAuteur($auteur) {
-    $code_alpha = $this->indexation->alphaMaj($auteur);
-    if (!$code_alpha = str_replace(" ","x",$code_alpha))
-      return;
+    return ($codif = $this->_getCodifAuteur($auteur))
+      ? 'A' . $codif->getId() : '';
+  }
 
-    if (!$codif_auteur = Class_CodifAuteur::findByCodeAlpha($code_alpha)) {
-      $nom_prenom = (-1 < $pos=strscan($auteur,"|"))
-        ? trim(substr($auteur,($pos+1))." ".substr($auteur,0,$pos))
-        : $auteur;
 
-      $codif_auteur = Class_CodifAuteur::newInstance()
-        ->setLibelle($nom_prenom)
-        ->setFormes($code_alpha);
-      $codif_auteur->save();
-    }
+  protected function _getCodifAuteur($auteur) {
+    return $this->getCodifProvider()->getAuthor($auteur);
+  }
 
-    return 'A'.$codif_auteur->getId();
+
+  protected function _getCodifTopic($topic) {
+    return $this->getCodifProvider()->getTopic($topic);
   }
 
+
 // --------------------------------------------------------------------------------
 // Ecrit une notice : article de périodique
 // --------------------------------------------------------------------------------
@@ -1347,23 +1378,44 @@ class notice_integration {
   }
 
 
-  /** @category testing */
-  public function getServiceRunner() {
-    if (null != $this->_service_runner)
-      return $this->_service_runner;
-    return new Service_Runner();
+  protected function getServiceRunner() {
+    return null != $this->_service_runner
+      ? $this->_service_runner : new Service_Runner();
   }
 
 
+  /** @category testing */
   public function setServiceRunner($runner) {
     $this->_service_runner = $runner;
     return $this;
   }
 
 
+
   public function getStatut() {
     return $this->statut;
   }
+
+
+  protected function getCodifProvider() {
+    if (null == $this->_codif_provider)
+      $this->_codif_provider = (new Class_Cosmogramme_Integration_CodifProvider)
+        ->setIndexation($this->indexation);
+
+    return $this->_codif_provider;
+  }
+
+
+  protected function _isIncremental() {
+    return Class_Cosmogramme_Integration::TYPE_OPERATION_INCREMENT == $this->type_operation;
+  }
+
+
+  /** @category testing */
+  public function setCodifProvider($provider) {
+    $this->_codif_provider = $provider;
+    return $this;
+  }
 }
 
 
@@ -1371,6 +1423,4 @@ class Service_Runner {
   public function run($type, $args) {
     return communication::runService($type, $args);
   }
-}
-
-?>
+}
\ No newline at end of file
diff --git a/cosmogramme/php/classes/classe_unimarc.php b/cosmogramme/php/classes/classe_unimarc.php
index cafc31c55cfdd06d008e02f995c940233f234bd7..abeed734b48c4517d52499d60201586df3f5f563 100644
--- a/cosmogramme/php/classes/classe_unimarc.php
+++ b/cosmogramme/php/classes/classe_unimarc.php
@@ -45,7 +45,7 @@ class notice_unimarc extends iso2709_record {
 
   public function __construct() {
     $this->profil_unimarc = new profil_donnees();
-    $this->indexation = new indexation();
+    $this->indexation = indexation::getInstance();
     $data = getVariable('non_exportable');
     $this->copyright = explode(';', $data);
     $this->controle_codes_barres = getVariable('controle_codes_barres');
diff --git a/cosmogramme/tests/bootstrap.php b/cosmogramme/tests/bootstrap.php
index 0edd1446415f7a93dd62ee56cae6fc9e2b0e4cda..2394fc2af1c3634d693ae452860a6cc8a1df8c6a 100644
--- a/cosmogramme/tests/bootstrap.php
+++ b/cosmogramme/tests/bootstrap.php
@@ -27,7 +27,4 @@ $_SESSION['passe'] = 'admin_systeme';
 define("BASE_URL", "/opac");
 
 include_once "_init.php";
-require_once("classe_communication.php");
-
-
-?>
+require_once("classe_communication.php");
\ No newline at end of file
diff --git a/cosmogramme/tests/php/classes/ModelTestCase.php b/cosmogramme/tests/php/classes/ModelTestCase.php
index 7fb5bc9125af5e6ed34913db3e77d8a8892db62c..a20794e25a7b7bc404e8cf5dd42add4aa1fe975a 100644
--- a/cosmogramme/tests/php/classes/ModelTestCase.php
+++ b/cosmogramme/tests/php/classes/ModelTestCase.php
@@ -16,7 +16,7 @@
  *
  * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
  * along with BOKEH; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA 
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
  */
 
 abstract class TestFixtures {
@@ -39,6 +39,8 @@ abstract class TestFixtures {
 abstract class ModelTestCase extends PHPUnit_Framework_TestCase {
 	use Storm_Test_THelpers;
 
+  protected $_storm_default_to_volatile = false;
+
 	protected function _buildTableMock($model, $methods) {
 		$table = $this->getMock('Storm_Model_Table'.$model,$methods);
 		$loader = call_user_func(array($model, 'getLoader'));
@@ -61,11 +63,22 @@ abstract class ModelTestCase extends PHPUnit_Framework_TestCase {
 			->will($this->returnValue($mock_results));
 	}
 
-	protected function tearDown() {
+
+  public function setUp() {
+    Storm_Model_Abstract::unsetLoaders();
+    if ($this->_storm_default_to_volatile)
+      Storm_Model_Loader::defaultToVolatile();
+  }
+
+
+  protected function tearDown() {
+    if($this->_storm_default_to_volatile)
+      Storm_Model_Loader::defaultToDb();
 		Storm_Model_Abstract::unsetLoaders();
 	}
 
-	protected function _setFindAllExpectation($model, $fixtures) {
+
+  protected function _setFindAllExpectation($model, $fixtures) {
 		if (!is_array($fixtures)) {
 			$finst = new $fixtures;
 			$fixtures = $finst->all();
@@ -81,11 +94,10 @@ abstract class ModelTestCase extends PHPUnit_Framework_TestCase {
 		return $tbl_newsletters;
 	}
 
-	protected function _generateLoaderFor($model, $methods) {
+
+  protected function _generateLoaderFor($model, $methods) {
 		$loader = $this->getMock('Mock'.$model, $methods);
 		Storm_Model_Abstract::setLoaderFor($model, $loader);
 		return $loader;
 	}
-}
-
-?>
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/cosmogramme/tests/php/classes/NoticeIntegrationTest.php b/cosmogramme/tests/php/classes/NoticeIntegrationTest.php
index 718568f4b601b7439d02da9ca39a7fccd3bc8456..0436e3e78fa5ecf417e1a428027f0d8c1596fdb8 100644
--- a/cosmogramme/tests/php/classes/NoticeIntegrationTest.php
+++ b/cosmogramme/tests/php/classes/NoticeIntegrationTest.php
@@ -46,8 +46,7 @@ abstract class NoticeIntegrationTestCase extends ModelTestCase {
 
 		$req_profils = 'select * from profil_donnees where id_profil='.$this->_profil_donnees['id_profil'];
 
-		$this->fixture('Class_IntProfilDonnees',
-									 $this->_profil_donnees);
+		$this->fixture('Class_IntProfilDonnees', $this->_profil_donnees);
 
 		$this->_mock_sql
 			->whenCalled('fetchEnreg')
@@ -64,7 +63,7 @@ abstract class NoticeIntegrationTestCase extends ModelTestCase {
 		parent::setUp();
 
 		global $sql;
-		$sql = $this->_mock_sql = Storm_Test_ObjectWrapper::mock();
+		$sql = $this->_mock_sql = $this->mock();
 		profil_donnees::clearCache();
 
 		$this->_mock_sql
@@ -87,16 +86,16 @@ abstract class NoticeIntegrationTestCase extends ModelTestCase {
 
 		VariableCache::getInstance()
 		  ->setValeurCache(['filtrer_fulltext' => 1,
-			'mode_doublon'=> 1,
-			'tracer_accents_iso'=>1,
-			'non_exportable'=> 'electre;decitre;gam;zebris',
-			'controle_codes_barres'=> 0,
-			'unimarc_zone_titre' => '200$a;461$t',
-			'unicite_code_barres' => 0,
-			'champs_sup' => '',
-			'ean_345' => ''])
+                        'mode_doublon'=> 1,
+                        'tracer_accents_iso'=>1,
+                        'non_exportable'=> 'electre;decitre;gam;zebris',
+                        'controle_codes_barres'=> 0,
+                        'unimarc_zone_titre' => '200$a;461$t',
+                        'unicite_code_barres' => 0,
+                        'champs_sup' => '',
+                        'ean_345' => ''])
 			->setListeCache(['nature_docs'=> "1:Collection\r\n2:Dataset\r\n3:Event\r\n4:Image",
-			'types_docs' => "0:non identifié\r\n1:livres\r\n2:périodiques\r\n3:disques\r\n4:DVD\r\n5:cédéroms\r\n8:articles cms\r\n9:fils rss\r\n10:sites internet\r\n100:Livre Numérique\r\n101:Diaporamas\r\n102:Type doc\r\n103:OAI\r\n104:Type doc\r\n105:Formation Vodéclic\r\n106:Livres Numériques\r\n107:Vidéos à la demande\r\n108:Tout apprendre\r\n109:Enregistrement audio\r\n110:Numérique Premium"]);
+                       'types_docs' => "0:non identifié\r\n1:livres\r\n2:périodiques\r\n3:disques\r\n4:DVD\r\n5:cédéroms\r\n8:articles cms\r\n9:fils rss\r\n10:sites internet\r\n100:Livre Numérique\r\n101:Diaporamas\r\n102:Type doc\r\n103:OAI\r\n104:Type doc\r\n105:Formation Vodéclic\r\n106:Livres Numériques\r\n107:Vidéos à la demande\r\n108:Tout apprendre\r\n109:Enregistrement audio\r\n110:Numérique Premium"]);
 
 		Class_Notice::beVolatile();
 		Class_Exemplaire::beVolatile();
@@ -129,17 +128,19 @@ abstract class NoticeIntegrationTestCase extends ModelTestCase {
 
 
 	public function loadNotice($filename) {
-		$this->loadNoticeFromString(file_get_contents(dirname(__FILE__)."/".$filename.".txt"));
+		$this->loadNoticeFromString(file_get_contents(__DIR__ . '/' . $filename . '.txt'));
 	}
 
 
 	public function loadNoticeFromString($unimarc) {
-		Codif_langue::getInstance()->setCodif(['fre' => ['id_langue' => 'fre',
-																										 'libelle' => 'français']]);
-
 		$this->notice_integration = new notice_integration();
 		$this->notice_integration->setParamsIntegration(1, 0, isset($this->_profil_donnees['id_profil']) ? $this->_profil_donnees['id_profil'] : 1);
 
+    $this->_service_runner = $this->mock()
+                                  ->whenCalled('run')
+                                  ->answers(['statut' => 'KO']);
+    $this->notice_integration->setServiceRunner($this->_service_runner);
+
 		$this->notice_integration->traiteNotice($unimarc);
 		$this->notice_integration->traiteFacettes();
 		$this->notice_data = $this->notice_integration->getNotice();
@@ -173,7 +174,8 @@ class NoticeIntegrationLollipopGeneratedNoticeRecordTest extends NoticeIntegrati
 
 	/** @test */
 	public function codeAlphaShouldBeLollipop() {
-		$this->assertEquals('LOLLIPOP--NOSTLINGERC--ECOLEDESLOISIRS-1987-1', $this->notice_data['clef_alpha']);
+		$this->assertEquals('LOLLIPOP--NOSTLINGERC--ECOLEDESLOISIRS-1987-1',
+                        $this->notice_data['clef_alpha']);
 	}
 
 
@@ -209,16 +211,19 @@ class NoticeIntegrationLollipopGeneratedNoticeRecordTest extends NoticeIntegrati
 abstract class NoticeIntegrationMarc21ToUnimarcTest extends NoticeIntegrationTestCase {
 	public function setUp() {
 		parent::setUp();
+
 		$this->notice_marc21 = new notice_marc21();
 		$this->notice_marc21->ouvrirNotice(file_get_contents(dirname(__FILE__)."/marc21_etalon.txt"), 0);
 		$this->notice_sgbd->ouvrirNotice($this->notice_marc21->getFullRecord());
 	}
 
+
 	/** @test */
 	public function zone461TInUnimarcShouldContainsTitres() {
 		$this->assertEquals(['Titre général ;', 'titre general ;'], $this->notice_sgbd->get_subfield('461', 't'));
 	}
 
+
 	/** @test */
 	public function zone461TInMarc21ShouldContainsTitres() {
 		$this->assertEquals(['Titre général ;', 'titre general ;'], $this->notice_marc21->get_subfield('461', 't'));
@@ -227,7 +232,8 @@ abstract class NoticeIntegrationMarc21ToUnimarcTest extends NoticeIntegrationTes
 
 
 abstract class NoticeIntegrationMarc21DynixTestCase extends NoticeIntegrationTestCase {
-	protected $_profil_donnees = ['id_profil' => 150,
+	protected $_profil_donnees = ['id' => 150,
+                                'id_profil' => 150,
 																'libelle' => 'MARC21 Dynix',
 																'accents' => '4',
 																'rejet_periodiques' =>  '1',
@@ -237,23 +243,29 @@ abstract class NoticeIntegrationMarc21DynixTestCase extends NoticeIntegrationTes
 																'attributs' => 'a:7:{i:0;a:8:{s:8:"type_doc";a:12:{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:22:"LIV;MS;LDV;LVI;LV;LIVC";}i:2;a:3:{s:4:"code";s:1:"2";s:5:"label";s:2:"as";s:8:"zone_995";s:12:"PER;REVC;REV";}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:25:"DIAPO;DVD;VHS;VHD;VD;DVDJ";}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:"7";s:5:"label";s:0:"";s:8:"zone_995";s:7:"LCA;LCD";}i:7;a:3:{s:4:"code";s:1:"8";s:5:"label";s:0:"";s:8:"zone_995";s:3:"DOS";}i:8;a:3:{s:4:"code";s:1:"9";s:5:"label";s:0:"";s:8:"zone_995";s:0:"";}i:9;a:3:{s:4:"code";s:2:"10";s:5:"label";s:0:"";s:8:"zone_995";s:6:"WEB;MF";}i:10;a:3:{s:4:"code";s:2:"11";s:5:"label";s:0:"";s:8:"zone_995";s:2:"JV";}i:11;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:3:"999";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:"z";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";}i:6;a:2:{s:4:"zone";s:3:"901";s:5:"champ";s:1:"a";}}'];
 }
 
-class NoticeIntegrationMarc21CoupCavalierToUnimarcTest extends NoticeIntegrationMarc21DynixTestCase {
+
+
+
+class NoticeIntegrationMarc21CoupCavalierToUnimarcTest
+  extends NoticeIntegrationMarc21DynixTestCase {
+
 	public function setUp() {
 		parent::setUp();
 
 		$this->fixture('Class_CodifSection',
-									 ['id' => 2,
-										'regles' => '996$z=ADU']);
+									 ['id' => 2, 'regles' => '996$z=ADU']);
 
 		$this->notice_marc21 = new notice_marc21();
-		$this->notice_marc21->ouvrirNotice(file_get_contents(dirname(__FILE__)."/marc21_coup_cavalier.txt"), $this->_profil_donnees['id_profil']);
+		$this->notice_marc21->ouvrirNotice(file_get_contents(dirname(__FILE__)."/marc21_coup_cavalier.txt"),
+                                       $this->_profil_donnees['id_profil']);
 		$this->notice_data = $this->notice_marc21->getNoticeIntegration();
 	}
 
 
 	/** @test */
 	public function zone200AShouldBeLeCoupDuCavalier() {
-		$this->assertEquals('Le coup du cavalier', $this->notice_marc21->get_subfield('200', 'a')[0]);
+		$this->assertEquals('Le coup du cavalier',
+                        $this->notice_marc21->get_subfield('200', 'a')[0]);
 	}
 
 
@@ -271,7 +283,7 @@ class NoticeIntegrationMarc21CoupCavalierToUnimarcTest extends NoticeIntegration
 
 	/** @test */
 	public function sectionShouldHaveId2() {
-		$this->assertEquals(2,	$this->notice_data['exemplaires'][0]['section']);
+		$this->assertEquals(2, $this->notice_data['exemplaires'][0]['section']);
 	}
 
 
@@ -639,7 +651,7 @@ class NoticeIntegrationBearsBeerMicrobibTest extends NoticeIntegrationTestCase {
 
 	public function setUp() {
 		parent::setUp();
-		$this->loadNotice("unimarc_bears_beer");
+		$this->loadNotice('unimarc_bears_beer');
 	}
 
 
@@ -1710,7 +1722,4 @@ class NoticeIntegrationAloesSerialIndexpressBellesHistoireTest extends NoticeInt
 	public function noArticleShouldHaveBeenSaved() {
 		$this->assertCount(0, Class_Notice_SerialArticles::findAll());
 	}
-}
-
-
-?>
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/library/Class/CodifAuteur.php b/library/Class/CodifAuteur.php
index 59e71f1c17a29ff3568a8e77b665539d47d2bf3f..61a804dc17de3014eacc033fe8f8fbc3265fa6ad 100644
--- a/library/Class/CodifAuteur.php
+++ b/library/Class/CodifAuteur.php
@@ -21,8 +21,8 @@
 
 
 class CodifAuteurLoader extends Storm_Model_Loader {
-  public function findOrCreate($code_alpha,$auteur) {
-    $existing = Class_CodifAuteur::getLoader()->findByCodeAlpha($code_alpha);
+  public function findOrCreate($code_alpha, $auteur) {
+    $existing = Class_CodifAuteur::findByCodeAlpha($code_alpha);
 
     if(!$existing) {
       $nom_prenom = (-1 < $pos = strscan($auteur, "|", 0))
@@ -38,7 +38,7 @@ class CodifAuteurLoader extends Storm_Model_Loader {
 
 
   public function findByCodeAlpha($code_alpha) {
-    return Class_CodifAuteur::getLoader()->findFirstBy(
+    return Class_CodifAuteur::findFirstBy(
       ['where' => "MATCH(formes) AGAINST('" . $code_alpha . "' IN BOOLEAN MODE)"]);
   }
 
@@ -78,10 +78,13 @@ class CodifAuteurLoader extends Storm_Model_Loader {
 
 
 class Class_CodifAuteur extends Storm_Model_Abstract {
-  const CODE_FACETTE='A';
+  const CODE_FACETTE = 'A';
+
   protected $_table_name = 'codif_auteur';
   protected $_table_primary = 'id_auteur';
   protected $_loader_class = 'CodifAuteurLoader';
-}
 
-?>
\ No newline at end of file
+  protected $_default_attribute_values = ['mots_renvois' => '',
+                                          'id_bnf' => '',
+                                          'date_creation' => ''];
+}
\ No newline at end of file
diff --git a/library/Class/CodifMatiere.php b/library/Class/CodifMatiere.php
index ca0e6a0a6cc1f5127bf01b57518d0825ea2a5a1c..ddc10c8176691ddb8a5cb67db5e98bb8d80207ed 100644
--- a/library/Class/CodifMatiere.php
+++ b/library/Class/CodifMatiere.php
@@ -16,12 +16,32 @@
  *
  * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
  * along with BOKEH; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA 
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
  */
 
+class Class_CodifMatiereLoader extends Storm_Model_Loader {
+  public function findOrCreate($code, $label) {
+    if ($model = Class_CodifMatiere::findFirstBy(['code_alpha' => $code]))
+      return $model;
+
+    $model = Class_CodifMatiere::newInstance(['libelle' => $label,
+                                              'code_alpha' => $code]);
+    $model->save();
+
+    return $model;
+  }
+}
+
+
+
 class Class_CodifMatiere extends Storm_Model_Abstract {
-  const CODE_FACETTE='M';
+  const CODE_FACETTE = 'M';
+
   protected $_table_name = 'codif_matiere';
   protected $_table_primary = 'id_matiere';
+  protected $_loader_class = 'Class_CodifMatiereLoader';
+
+  protected $_default_attribute_values = ['mots_renvois' => '',
+                                          'id_bnf' => '',
+                                          'date_creation' => ''];
 }
-?>
diff --git a/library/Class/Cosmogramme/Integration/CodifProvider.php b/library/Class/Cosmogramme/Integration/CodifProvider.php
new file mode 100644
index 0000000000000000000000000000000000000000..2057fedd9c49d677755230757589af96499ea86a
--- /dev/null
+++ b/library/Class/Cosmogramme/Integration/CodifProvider.php
@@ -0,0 +1,58 @@
+<?php
+/**
+ * Copyright (c) 2012-2015, Agence Française Informatique (AFI). All rights reserved.
+ *
+ * BOKEH is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by
+ * the Free Software Foundation.
+ *
+ * There are special exceptions to the terms and conditions of the AGPL as it
+ * is applied to this software (see README file).
+ *
+ * BOKEH is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * along with BOKEH; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
+ */
+
+
+class Class_Cosmogramme_Integration_CodifProvider {
+  use Trait_TimeSource;
+
+  protected $_indexation;
+
+
+  public function setIndexation($indexation) {
+    $this->_indexation = $indexation;
+    return $this;
+  }
+
+
+  public function getAuthor($label) {
+    return $this->_getFrom($label,
+                           str_replace(' ', 'x', $this->_indexation->alphaMaj($label)),
+                           'Class_CodifAuteur');
+  }
+
+
+  public function getTopic($label) {
+    // limit to the maximum size of code_alpha column in db to avoid duplicates
+    $code = substr($this->_indexation->alphaMaj($label), 0, 255);
+    return $this->_getFrom($label, $code, 'Class_CodifMatiere');
+  }
+
+
+  protected function _getFrom($value, $code, $model_class) {
+    if (!$code)
+      return;
+
+    $model = call_user_func_array([$model_class, 'findOrCreate'],
+                                  [$code, $value]);
+
+    return $model;
+  }
+}
\ No newline at end of file
diff --git a/library/Class/Cosmogramme/Integration/PhaseNotice.php b/library/Class/Cosmogramme/Integration/PhaseNotice.php
index 04e10f3e85bb7fb95db4bdc1528d9bf88293bbde..0be2dac0a66dac676b6b87a0094c145cf6425c21 100644
--- a/library/Class/Cosmogramme/Integration/PhaseNotice.php
+++ b/library/Class/Cosmogramme/Integration/PhaseNotice.php
@@ -21,9 +21,13 @@
 require_once('cosmogramme/php/classes/classe_notice_integration.php');
 
 
-class Class_Cosmogramme_Integration_PhaseNotice extends Class_Cosmogramme_Integration_PhaseOnDataSource {
+class Class_Cosmogramme_Integration_PhaseNotice
+  extends Class_Cosmogramme_Integration_PhaseOnDataSource {
+
   const MY_ID = 0;
 
+  protected static $_service_runner;
+
   protected function _init($phase) {}
 
 
@@ -37,13 +41,14 @@ class Class_Cosmogramme_Integration_PhaseNotice extends Class_Cosmogramme_Integr
 
 
   public function importRecord($data, $integration) {
-    $notice = new notice_integration();
-    $notice->setParamsIntegration($integration->getIdBib(),
-                                  $integration->getTypeOperation(),
-                                  $integration->getProfil(),
-                                  $integration->getTypeDoc());
-    $notice->traiteNotice($data);
-    $this->_incrementCount($notice->getStatut());
+    $integrator = new notice_integration();
+    $integrator->setParamsIntegration($integration->getIdBib(),
+                                      $integration->getTypeOperation(),
+                                      $integration->getProfil(),
+                                      $integration->getTypeDoc());
+    $integrator->setServiceRunner(static::$_service_runner);
+    $integrator->traiteNotice($data);
+    $this->_incrementCount($integrator->getStatut());
   }
 
 
@@ -105,5 +110,10 @@ class Class_Cosmogramme_Integration_PhaseNotice extends Class_Cosmogramme_Integr
       $this->_log->ecrire($trace) :
       $this->_getPrinter()->nextPutAll($trace . '<br>');
   }
-}
-?>
\ No newline at end of file
+
+
+  /** @category testing */
+  public static function setServiceRunner($runner) {
+    static::$_service_runner = $runner;
+  }
+}
\ No newline at end of file
diff --git a/library/Class/Indexation.php b/library/Class/Indexation.php
index 40dd5297d561e200dccea14a48c961b4aa98ecc0..dc6a5e674c7f5578949b2181c1f1329d514edc64 100644
--- a/library/Class/Indexation.php
+++ b/library/Class/Indexation.php
@@ -44,7 +44,7 @@ class Class_Indexation {
 
   public static function getInstance() {
     if(!static::$_instance)
-      static::$_instance = new Class_Indexation();
+      static::$_instance = new static();
     return static::$_instance;
   }
 
@@ -107,486 +107,513 @@ class Class_Indexation {
                       ['PC','PC'],
                       ['DS','DS']];
 
-                      // Init table ascii pour majuscules
-                      $this->tableMajTo = str_split(str_repeat( ' ', 42 )
-                                                    . '*     0123456789       '
-                                                    . 'ABCDEFGHIJKLMNOPQRSTUVWXYZ      '
-                                                    . 'ABCDEFGHIJKLMNOPQRSTUVWXYZ      '
-                                                    . str_repeat( ' ', 63)
-                                                    .'AAAAAAACEEEEIIII NOOOOO  UUUUY  AAAAAAACEEEEIIII NOOOOO  UUUUY Y');
-
-                      for($i=0; $i<count($this->tableMajTo); $i++)
-                        $this->tableMajFrom[] = chr($i);
-
-
-                      $this->tableMajUtf8=array(chr(0xC9) => 'E', 'È' => 'E', 'Ë' => 'E', 'Ê' => 'E','Á' => 'A', 'À' => 'A', 'Ä' => 'A', 'Â' => 'A',
-                                                'Å' => 'A', 'Ã' => 'A', 'Æ' => 'E','Ï' => 'I', 'Î' => 'I', 'Ì' => 'I', 'Í' => 'I',
-                                                'Ô' => 'O', 'Ö' => 'O', 'Ò' => 'O', 'Ó' => 'O', 'Õ' => 'O', 'Ø' => 'O', 'Œ' => 'OEU',
-                                                'Ú' => 'U', 'Ù' => 'U', 'Û' => 'U', 'Ü' => 'U','Ñ' => 'N', 'Ç' => 'S', '¿' => 'E');
-                      }
-      // Indexation d'un titre
-      public function codeAlphaTitre($titre)
-      {
-        $titre=$this->alphaMaj($titre);
-        foreach($this->articles as $article)
-          {
-            $lg=strlen($article);
-            if(strLeft($titre, $lg)==$article) {$titre=strMid($titre,$lg,256); break;}
-          }
-        $titre=$this->alphaMaj($titre);
-        return $titre;
-      }
+    // Init table ascii pour majuscules
+    $this->tableMajTo = str_split(str_repeat( ' ', 42 )
+                                  . '*     0123456789       '
+                                  . 'ABCDEFGHIJKLMNOPQRSTUVWXYZ      '
+                                  . 'ABCDEFGHIJKLMNOPQRSTUVWXYZ      '
+                                  . str_repeat( ' ', 63)
+                                  .'AAAAAAACEEEEIIII NOOOOO  UUUUY  AAAAAAACEEEEIIII NOOOOO  UUUUY Y');
+
+    for($i=0; $i<count($this->tableMajTo); $i++)
+      $this->tableMajFrom[] = chr($i);
+
+
+    $this->tableMajUtf8 = [chr(0xC9) => 'E',
+                           'È' => 'E',
+                           'Ë' => 'E',
+                           'Ê' => 'E',
+                           'Á' => 'A',
+                           'À' => 'A',
+                           'Ä' => 'A',
+                           'Â' => 'A',
+                           'Ã…' => 'A',
+                           'Ã' => 'A',
+                           'Æ' => 'E',
+                           'Ï' => 'I',
+                           'ÃŽ' => 'I',
+                           'Ì' => 'I',
+                           'Í' => 'I',
+                           'Ô' => 'O',
+                           'Ö' => 'O',
+                           'Ã’' => 'O',
+                           'Ó' => 'O',
+                           'Õ' => 'O',
+                           'Ø' => 'O',
+                           'Å’' => 'OEU',
+                           'Ú' => 'U',
+                           'Ù' => 'U',
+                           'Û' => 'U',
+                           'Ü' => 'U',
+                           'Ñ' => 'N',
+                           'Ç' => 'S',
+                           '¿' => 'E'];
+  }
 
-    // Rend une suite de mots complete pour les formes plurielles
-    public function getExpressionRecherche($mot) {
-      if (!$mot=trim($mot))
-        return false;
 
-      // Pluriel
-      $etoile = '';
-      if(strRight($mot,1) == '*') {
-        $etoile='*';
-        $mot=strLeft($mot, strlen($mot)-1);
+  // Indexation d'un titre
+  public function codeAlphaTitre($titre)
+  {
+    $titre=$this->alphaMaj($titre);
+    foreach($this->articles as $article)
+      {
+        $lg=strlen($article);
+        if(strLeft($titre, $lg)==$article) {$titre=strMid($titre,$lg,256); break;}
       }
+    $titre=$this->alphaMaj($titre);
+    return $titre;
+  }
+
+  // Rend une suite de mots complete pour les formes plurielles
+  public function getExpressionRecherche($mot) {
+    if (!$mot=trim($mot))
+      return false;
 
-      $m = $this->getPluriel($mot);
-      $m[2] = $this->phonetix($m[0]);
-      return trim('('.$m[0].$etoile.' '.$m[1].' '.$m[2].')');
+    // Pluriel
+    $etoile = '';
+    if(strRight($mot,1) == '*') {
+      $etoile='*';
+      $mot=strLeft($mot, strlen($mot)-1);
     }
 
+    $m = $this->getPluriel($mot);
+    $m[2] = $this->phonetix($m[0]);
+    return trim('('.$m[0].$etoile.' '.$m[1].' '.$m[2].')');
+  }
 
-    public function alphaMaj( $chaine ) {
-      if (isset(static::$_alpha_maj_cache[$chaine]))
-        return static::$_alpha_maj_cache[$chaine];
 
-      return static::$_alpha_maj_cache[$chaine] = trim(str_replace($this->tableMajFrom,
-                                                                   $this->tableMajTo,
-                                                                   utf8_decode($chaine)));
-    }
+  public function alphaMaj( $chaine ) {
+    if (isset(static::$_alpha_maj_cache[$chaine]))
+      return static::$_alpha_maj_cache[$chaine];
 
+    return static::$_alpha_maj_cache[$chaine] = trim(str_replace($this->tableMajFrom,
+                                                                 $this->tableMajTo,
+                                                                 utf8_decode($chaine)));
+  }
 
-    public function getClefAlpha($type_doc,$titre,$complement_titre,$auteur,$tome,$editeur,$annee)
-    {
-      $clef=$this->getClefOeuvre($titre,$complement_titre,$auteur,$tome).'-';
-      $clef.=substr($this->alphaMaj(str_replace(' ','',$editeur)),0,80).'-';
-      $clef.=$annee.'-';
-      $clef.=$type_doc;
-      $clef=str_replace(' ','',$clef);
-      return $clef;
-    }
+
+  public function getClefAlpha($type_doc,$titre,$complement_titre,$auteur,$tome,$editeur,$annee)
+  {
+    $clef=$this->getClefOeuvre($titre,$complement_titre,$auteur,$tome).'-';
+    $clef.=substr($this->alphaMaj(str_replace(' ','',$editeur)),0,80).'-';
+    $clef.=$annee.'-';
+    $clef.=$type_doc;
+    $clef=str_replace(' ','',$clef);
+    return $clef;
+  }
 
 // Rend une clef alpha pour les oeuvres
-    public function getClefOeuvre($titre,$complement_titre,$auteur,$tome)
-    {
-      $clef = substr($this->codeAlphaTitre(strtoupper(str_replace(' ','',$titre))),0,80).'-';
-      $clef.=substr($this->codeAlphaTitre(strtoupper(str_replace(' ','',$complement_titre))),0,20).'-';
-      $clef.=substr($this->alphaMaj(str_replace(' ','',$auteur)),0,80).'-';
-      $clef.=$this->alphaMaj($tome);
-      $clef=str_replace(' ','',$clef);
-      return $clef;
-    }
+  public function getClefOeuvre($titre,$complement_titre,$auteur,$tome)
+  {
+    $clef = substr($this->codeAlphaTitre(strtoupper(str_replace(' ','',$titre))),0,80).'-';
+    $clef.=substr($this->codeAlphaTitre(strtoupper(str_replace(' ','',$complement_titre))),0,20).'-';
+    $clef.=substr($this->alphaMaj(str_replace(' ','',$auteur)),0,80).'-';
+    $clef.=$this->alphaMaj($tome);
+    $clef=str_replace(' ','',$clef);
+    return $clef;
+  }
 
 // Decoupe une expression en mots en tenant compte des exclusions / inclusions
-    public function getMots( $chaine ) {
-      $new = [];
-      $chaine = str_replace( '.', '', $chaine);
-      $chaine = trim($this->alphaMaj($chaine));
-      $words = explode(' ', $chaine);
-
-      foreach($words as $word) {
-        if(strlen($word) < 3 && intVal($word) == false) {
-          if(false == in_array($word, $this->inclu))
-            continue;
-
-          if( 1 == strlen($word))
-            $word .= '00';
-        }
-
-        if(true == in_array($word, $this->exclu))
+  public function getMots( $chaine ) {
+    $new = [];
+    $chaine = str_replace( '.', '', $chaine);
+    $chaine = trim($this->alphaMaj($chaine));
+    $words = explode(' ', $chaine);
+
+    foreach($words as $word) {
+      if(strlen($word) < 3 && intVal($word) == false) {
+        if(false == in_array($word, $this->inclu))
           continue;
 
-        $new[] = $word;
+        if( 1 == strlen($word))
+          $word .= '00';
       }
 
-      return $new;
+      if(true == in_array($word, $this->exclu))
+        continue;
+
+      $new[] = $word;
     }
 
+    return $new;
+  }
+
 // Rend une chaine de mots dedoublonnes et filtres
-    public function getFulltext($data) {
-      if (gettype($data) != 'array')
-        $data=array($data);
-
-      $new=' ';
-      foreach($data as $chaine)
-        {
-          $mots=$this->getMots($chaine);
-          foreach($mots as $mot)
-            {
-              $mot=' '.$mot.' ';
-              if(strpos($new,$mot) === false )
-                {
-                  $new.=trim($mot).' ';
-                  $phonem=' '.$this->phonetix(trim($mot)).' ';
-                  if($phonem and strpos($new,$phonem) === false ) $new.=trim($phonem).' ';
-                }
-            }
-        }
-      return trim($new);
-    }
+  public function getFulltext($data) {
+    if (gettype($data) != 'array')
+      $data=array($data);
+
+    $new=' ';
+    foreach($data as $chaine)
+      {
+        $mots=$this->getMots($chaine);
+        foreach($mots as $mot)
+          {
+            $mot=' '.$mot.' ';
+            if(strpos($new,$mot) === false )
+              {
+                $new.=trim($mot).' ';
+                $phonem=' '.$this->phonetix(trim($mot)).' ';
+                if($phonem and strpos($new,$phonem) === false ) $new.=trim($phonem).' ';
+              }
+          }
+      }
+    return trim($new);
+  }
 
 // Rend le mot au singulier et au pluriel
-    public function getPluriel( $mot )
-    {
-      if( strToUpper($mot) != $mot ) $mot=$this->alphaMaj($mot);
-      if(!trim($mot)) return false;
-      foreach($this->pluriel as $regle)
-        {
-          if(strLeft($regle[0],1) != '*')
-            {
-              if($mot==$regle[0] or $mot==$regle[1]) return $regle;
-              else continue;
-            }
-          $regle[0]=str_replace('*','',$regle[0]);
-          $regle[1]=str_replace('*','',$regle[1]);
-          $pattern_singulier = '('.$regle[0].'$)';
-          $pattern_pluriel='('.$regle[1].'$)';
-
-          $pluriel=ereg_replace($pattern_singulier, $regle[1], $mot);
-          $singulier=ereg_replace($pattern_pluriel, $regle[0], $mot);
-          if($singulier != $mot or $pluriel != $mot) break;
-        }
-      // Si inchangé on ajoute le S
-      if($singulier == $pluriel)
-        {
-          if(strRight($mot,1)=='S') {$pluriel=$singulier; $singulier=strLeft($singulier,strlen($singulier)-1);}
-          else $pluriel=$singulier.'S';
-        }
-      return array($singulier,$pluriel);
-    }
+  public function getPluriel( $mot )
+  {
+    if( strToUpper($mot) != $mot ) $mot=$this->alphaMaj($mot);
+    if(!trim($mot)) return false;
+    foreach($this->pluriel as $regle)
+      {
+        if(strLeft($regle[0],1) != '*')
+          {
+            if($mot==$regle[0] or $mot==$regle[1]) return $regle;
+            else continue;
+          }
+        $regle[0]=str_replace('*','',$regle[0]);
+        $regle[1]=str_replace('*','',$regle[1]);
+        $pattern_singulier = '('.$regle[0].'$)';
+        $pattern_pluriel='('.$regle[1].'$)';
+
+        $pluriel=ereg_replace($pattern_singulier, $regle[1], $mot);
+        $singulier=ereg_replace($pattern_pluriel, $regle[0], $mot);
+        if($singulier != $mot or $pluriel != $mot) break;
+      }
+    // Si inchangé on ajoute le S
+    if($singulier == $pluriel)
+      {
+        if(strRight($mot,1)=='S') {$pluriel=$singulier; $singulier=strLeft($singulier,strlen($singulier)-1);}
+        else $pluriel=$singulier.'S';
+      }
+    return array($singulier,$pluriel);
+  }
 
 // ---------------------------------------------------
 // Rend true si mot inclu
 // ---------------------------------------------------
-    public function  isMotInclu($mot)
-    {
-      return in_array($mot, $this->inclu);
-    }
+  public function  isMotInclu($mot)
+  {
+    return in_array($mot, $this->inclu);
+  }
 
 // ---------------------------------------------------
 // Othographe approchante
 // ---------------------------------------------------
-    function phonetix($sIn) {
-      if (strlen($sIn)<4 || is_numeric($sIn))
-        return false;
-      return $this->phonetixCompute($sIn);
-    }
+  function phonetix($sIn) {
+    if (strlen($sIn)<4 || is_numeric($sIn))
+      return false;
+    return $this->phonetixCompute($sIn);
+  }
 
-    function phonetixCompute($sIn)  {
-      $sIn = strtr( $sIn, $this->accents);          // minuscules accentuées ou composées en majuscules simples
-      $sIn = strtr( $sIn, $this->min2maj);          // majuscules accentuées ou composées en majuscules simples
-      $sIn = strtoupper( $sIn );              // on passe tout le reste en majuscules
-      $sIn = preg_replace( '`[^A-Z]`', '', $sIn );  // on garde uniquement les lettres de A à Z
-
-      $sBack=$sIn;                  // on sauve le code (utilisé pour les mots très courts)
-
-      $sIn = preg_replace( '`O[O]+`', 'OU', $sIn );   // pré traitement OO... -> OU
-      $sIn = str_replace( 'SAOU', 'SOU', $sIn );  // pré traitement SAOU -> SOU
-      $sIn = str_replace( 'OES', 'OS', $sIn );  // pré traitement OES -> OS
-      $sIn = str_replace( 'CCH', 'K', $sIn );     // pré traitement CCH -> K
-      $sIn = preg_replace( '`CC([IYE])`', 'KS$1', $sIn ); // CCI CCY CCE
-      $sIn = preg_replace( '`(.)\1`', '$1', $sIn );   // supression des répétitions
-
-      // quelques cas particuliers
-      if ($sIn=='CD') return($sIn);
-      if ($sIn=='BD') return($sIn);
-      if ($sIn=='BV') return($sIn);
-      if ($sIn=='TABAC') return('TABA');
-      if ($sIn=='FEU') return('FE');
-      if ($sIn=='FE') return($sIn);
-      if ($sIn=='FER') return($sIn);
-      if ($sIn=='FIEF') return($sIn);
-      if ($sIn=='FJORD') return($sIn);
-      if ($sIn=='GOAL') return('GOL');
-      if ($sIn=='FLEAU') return('FLEO');
-      if ($sIn=='HIER') return('IER');
-      if ($sIn=='HEU') return('E');
-      if ($sIn=='HE') return('E');
-      if ($sIn=='OS') return($sIn);
-      if ($sIn=='RIZ') return('RI');
-      if ($sIn=='RAZ') return('RA');
-
-      // pré-traitements
-      $sIn = preg_replace( '`OIN[GT]$`', 'OIN', $sIn );                 // terminaisons OING -> OIN
-      $sIn = preg_replace( '`E[RS]$`', 'E', $sIn );                     // supression des terminaisons infinitifs et participes pluriels
-      $sIn = preg_replace( '`(C|CH)OEU`', 'KE', $sIn );                   // pré traitement OEU -> EU
-      $sIn = str_replace( 'MOEU', 'ME', $sIn );                     // pré traitement OEU -> EU
-      $sIn = preg_replace( '`OE([UI]+)([BCDFGHJKLMNPQRSTVWXZ])`', 'E$1$2', $sIn );    // pré traitement OEU OEI -> E
-      $sIn = preg_replace( '`^GEN[TS]$`', 'JAN', $sIn );                  // pré traitement GEN -> JAN
-      $sIn = str_replace( 'CUEI', 'KEI', $sIn );                    // pré traitement accueil
-      $sIn = preg_replace( '`([^AEIOUYC])AE([BCDFGHJKLMNPQRSTVWXZ])`', '$1E$2', $sIn );   // pré traitement AE -> E
-      $sIn = preg_replace( '`AE([QS])`', 'E$1', $sIn );                   // pré traitement AE -> E
-      $sIn = preg_replace( '`AIE([BCDFGJKLMNPQRSTVWXZ])`', 'AI$1', $sIn );        // pré-traitement AIE(consonne) -> AI
-      $sIn = str_replace( 'ANIEM', 'ANIM', $sIn );                  // pré traitement NIEM -> NIM
-      $sIn = preg_replace( '`(DRA|TRO|IRO)P$`', '$1', $sIn );               // P terminal muet
-      $sIn = preg_replace( '`(LOM)B$`', '$1', $sIn );                   // B terminal muet
-      $sIn = preg_replace( '`(RON|POR)C$`', '$1', $sIn );                 // C terminal muet
-      $sIn = preg_replace( '`PECT$`', 'PET', $sIn );                    // C terminal muet
-      $sIn = preg_replace( '`ECUL$`', 'CU', $sIn );                     // L terminal muet
-      $sIn = preg_replace( '`(CHA|CA|E)M(P|PS)$`', '$1N', $sIn );             // P ou PS terminal muet
-      $sIn = preg_replace( '`(TAN|RAN)G$`', '$1', $sIn );                 // G terminal muet
-
-
-      // sons YEUX
-      $sIn = preg_replace( '`([^VO])ILAG`', '$1IAJ', $sIn );
-      $sIn = preg_replace( '`([^TRH])UIL(AR|E)(.+)`', '$1UI$2$3', $sIn );
-      $sIn = preg_replace( '`([G])UIL([AEO])`', '$1UI$2', $sIn );
-      $sIn = preg_replace( '`([NSPM])AIL([AEO])`', '$1AI$2', $sIn );
-      $convMIn  = array('DILAI','DILON','DILER','DILEM','RILON','TAILE','GAILET','AILAI','AILAR',
-                        'OUILA','EILAI','EILAR','EILER','EILEM','REILET','EILET','AILOL' );
-      $convMOut = array( 'DIAI', 'DION','DIER', 'DIEM', 'RION', 'TAIE', 'GAIET', 'AIAI', 'AIAR',
-                        'OUIA', 'AIAI', 'AIAR', 'AIER', 'AIEM',  'RAIET', 'EIET', 'AIOL' );
-      $sIn = str_replace( $convMIn, $convMOut, $sIn );
-      $sIn = preg_replace( '`([^AEIOUY])(SC|S)IEM([EA])`', '$1$2IAM$3', $sIn );   // IEM -> IAM
-      $sIn = preg_replace( '`^(SC|S)IEM([EA])`', '$1IAM$2', $sIn );         // IEM -> IAM
-
-      // MP MB -> NP NB
-      $convMIn  = array( 'OMB', 'AMB', 'OMP', 'AMP', 'IMB', 'EMP','GEMB','EMB', 'UMBL','CIEN');
-      $convMOut = array( 'ONB', 'ANB', 'ONP', 'ANP', 'INB', 'ANP','JANB','ANB', 'INBL','SIAN');
-      $sIn = str_replace( $convMIn, $convMOut, $sIn );
-
-      // Sons en K
-      $sIn = preg_replace( '`^ECHO$`', 'EKO', $sIn );   // cas particulier écho
-      $sIn = preg_replace( '`^ECEUR`', 'EKEUR', $sIn );   // cas particulier écœuré
-      // Choléra Chœur mais pas chocolat!
-      $sIn = preg_replace( '`^CH(OG+|OL+|OR+|EU+|ARIS|M+|IRO|ONDR)`', 'K$1', $sIn );        //En début de mot
-      $sIn = preg_replace( '`(YN|RI)CH(OG+|OL+|OC+|OP+|OM+|ARIS|M+|IRO|ONDR)`', '$1K$2', $sIn );  //Ou devant une consonne
-      $sIn = preg_replace( '`CHS`', 'CH', $sIn );
-      $sIn = preg_replace( '`CH(AIQ)`', 'K$1', $sIn );
-      $sIn = preg_replace( '`^ECHO([^UIPY])`', 'EKO$1', $sIn );
-      $sIn = preg_replace( '`ISCH(I|E)`', 'ISK$1', $sIn );
-      $sIn = preg_replace( '`^ICHT`', 'IKT', $sIn );
-      $sIn = preg_replace( '`ORCHID`', 'ORKID', $sIn );
-      $sIn = preg_replace( '`ONCHIO`', 'ONKIO', $sIn );
-      $sIn = preg_replace( '`ACHIA`', 'AKIA', $sIn );     // retouche ACHIA -> AKIA
-      $sIn = preg_replace( '`([^C])ANICH`', '$1ANIK', $sIn ); // ANICH -> ANIK  1/2
-      $sIn = preg_replace( '`OMANIK`', 'OMANICH', $sIn );   // cas particulier  2/2
-      $sIn = preg_replace( '`ACHY([^D])`', 'AKI$1', $sIn );
-      $sIn = preg_replace( '`([AEIOU])C([BDFGJKLMNPQRTVWXZ])`', '$1K$2', $sIn ); // voyelle, C, consonne sauf H
-      $convPrIn  = array('EUCHA','YCHIA','YCHA','YCHO','YCHED','ACHEO','RCHEO','RCHES',
-                         'ECHN','OCHTO','CHORA','CHONDR','CHORE','MACHM','BRONCHO','LICHOS','LICHOC');
-      $convPrOut = array('EKA',  'IKIA', 'IKA', 'IKO',  'IKED','AKEO','RKEO',  'RKES',
-                         'EKN',  'OKTO', 'KORA', 'KONDR' ,'KORE' ,'MAKM', 'BRONKO', 'LIKOS', 'LIKOC');
-      $sIn = str_replace( $convPrIn, $convPrOut, $sIn );
-
-      // Weuh (perfectible)
-      $convPrIn  = array( 'WA','WO', 'WI','WHI','WHY','WHA','WHO');
-      $convPrOut = array( 'OI', 'O','OUI','OUI','OUI','OUA', 'OU');
-      $sIn = str_replace( $convPrIn, $convPrOut, $sIn );
-
-      // Gueu, Gneu, Jeu et quelques autres
-      $convPrIn  = array( 'GNES','GNET','GNER','GNE',  'GI', 'GNI','GNA','GNOU','GNUR','GY','OUGAIN',
-                         'AGEOL', 'AGEOT','GEOLO','GEOM','GEOP','GEOG','GEOS','GEORG','GEOR','NGEOT','UGEOT','GEOT','GEOD','GEOC','GEO','GEA','GE',
-                         'QU', 'Q',  'CY', 'CI', 'CN','ICM','CEAT','CE',
-                         'CR', 'CO', 'CUEI','CU', 'VENCA','CA', 'CS','CLEN','CL', 'CZ', 'CTIQ',
-                         'CTIF','CTIC','CTIS','CTIL','CTIO','CTI', 'CTU', 'CTE','CTO','CTR','CT', 'PH', 'TH',
-                         'OW', 'LH', 'RDL', 'CHLO', 'CHR', 'PTIA');
-      $convPrOut = array( 'NIES','NIET','NIER', 'NE',  'JI',  'NI','NIA','NIOU','NIUR','JI','OUGIN',
-                         'AJOL',  'AJOT','JEOLO','JEOM','JEOP','JEOG','JEOS','JORJ','JEOR','NJOT','UJOT','JEOT','JEOD','JEOC', 'JO','JA' ,'JE',
-                         'K', 'K',  'SI', 'SI', 'KN','IKM', 'SAT','SE',
-                         'KR', 'KO', 'KEI','KU', 'VANSA','KA', 'KS','KLAN','KL', 'KZ', 'KTIK',
-                         'KTIF','KTIS','KTIS','KTIL','KSIO','KTI', 'KTU', 'KTE','KTO','KTR','KT', 'F',  'T',
-                         'OU',  'L',  'RL',  'KLO',  'KR', 'PSIA');
-      $sIn = str_replace( $convPrIn, $convPrOut, $sIn );
-
-      $sIn = preg_replace( '`GU([^RLMBSTPZN])`', 'G$1', $sIn ); // Gueu !
-      $sIn = preg_replace( '`GNO([MLTNRKG])`', 'NIO$1', $sIn ); // GNO ! Tout sauf S pour gnos
-      $sIn = preg_replace( '`GNO([MLTNRKG])`', 'NIO$1', $sIn ); // bis -> gnognotte! Si quelqu'un sait le faire en une seule regexp...
-
-
-      // TI -> SI v2.0
-      $convPrIn  = array( 'BUTIE','BUTIA','BATIA','ANTIEL','RETION','ENTIEL','ENTIAL','ENTIO','ENTIAI','UJETION','ATIEM','PETIEN',
-                         'CETIE','OFETIE','IPETI','LBUTION','BLUTION','LETION','LATION','SATIET');
-      $convPrOut = array( 'BUSIE','BUSIA','BASIA','ANSIEL','RESION','ENSIEL','ENSIAL','ENSIO','ENSIAI','UJESION','ASIAM','PESIEN',
-                         'CESIE','OFESIE','IPESI','LBUSION','BLUSION','LESION','LASION','SASIET');
-      $sIn = str_replace( $convPrIn, $convPrOut, $sIn );
-      $sIn = preg_replace( '`(.+)ANTI(AL|O)`', '$1ANSI$2', $sIn ); // sauf antialcoolique, antialbumine, antialarmer, ...
-      $sIn = preg_replace( '`(.+)INUTI([^V])`', '$1INUSI$2', $sIn ); // sauf inutilité, inutilement, diminutive, ...
-      $sIn = preg_replace( '`([^O])UTIEN`', '$1USIEN', $sIn ); // sauf soutien, ...
-      $sIn = preg_replace( '`([^DE])RATI[E]$`', '$1RASI$2', $sIn ); // sauf xxxxxcratique, ...
-      // TIEN TION -> SIEN SION v3.1
-      $sIn = preg_replace( '`([^SNEU]|KU|KO|RU|LU|BU|TU|AU)T(IEN|ION)`', '$1S$2', $sIn );
-
-
-      // H muet
-      $sIn = preg_replace( '`([^CS])H`', '$1', $sIn );  // H muet
-      $sIn = str_replace( 'ESH', 'ES', $sIn );      // H muet
-      $sIn = str_replace( 'NSH', 'NS', $sIn );      // H muet
-      $sIn = str_replace( 'SH', 'CH', $sIn );       // ou pas!
-
-      // NASALES
-      $convNasIn  = array( 'OMT','IMB', 'IMP','UMD','TIENT','RIENT','DIENT','IEN',
-                          'YMU','YMO','YMA','YME', 'YMI','YMN','YM', 'AHO','FAIM','DAIM','SAIM','EIN','AINS');
-      $convNasOut = array( 'ONT','INB', 'INP','OND','TIANT','RIANT','DIANT', 'IN',
-                          'IMU','IMO','IMA','IME', 'IMI','IMN','IN',  'AO', 'FIN','DIN', 'SIN','AIN','INS');
-      $sIn = str_replace( $convNasIn, $convNasOut, $sIn );
-      // AIN -> IN v2.0
-      $sIn = preg_replace( '`AIN$`', 'IN', $sIn );
-      $sIn = preg_replace( '`AIN([BTDK])`', 'IN$1', $sIn );
-      // UN -> IN
-      $sIn = preg_replace( '`([^O])UND`', '$1IND', $sIn ); // aucun mot français ne commence par UND!
-      $sIn = preg_replace( '`([JTVLFMRPSBD])UN([^IAE])`', '$1IN$2', $sIn );
-      $sIn = preg_replace( '`([JTVLFMRPSBD])UN$`', '$1IN', $sIn );
-      $sIn = preg_replace( '`RFUM$`', 'RFIN', $sIn );
-      $sIn = str_replace( 'LUMB', 'LINB', $sIn );
-      // EN -> AN
-      $sIn = preg_replace( '`([^BCDFGHJKLMNPQRSTVWXZ])EN`', '$1AN', $sIn );
-      $sIn = preg_replace( '`([VTLJMRPDSBFKNG])EN([BRCTDKZSVN])`', '$1AN$2', $sIn ); // deux fois pour les motifs recouvrants malentendu, pendentif, ...
-      $sIn = preg_replace( '`([VTLJMRPDSBFKNG])EN([BRCTDKZSVN])`', '$1AN$2', $sIn ); // si quelqu'un sait faire avec une seule regexp!
-      $sIn = preg_replace( '`^EN([BCDFGHJKLNPQRSTVXZ]|CH|IV|ORG|OB|UI|UA|UY)`', 'AN$1', $sIn );
-      $sIn = preg_replace( '`(^[JRVTH])EN([DRTFGSVJMP])`', '$1AN$2', $sIn );
-      $sIn = preg_replace( '`SEN([ST])`', 'SAN$1', $sIn );
-      $sIn = preg_replace( '`^DESENIV`', 'DESANIV', $sIn );
-      $sIn = preg_replace( '`([^M])EN(UI)`', '$1AN$2', $sIn );
-      $sIn = preg_replace( '`(.+[JTVLFMRPSBD])EN([JLFDSTG])`', '$1AN$2', $sIn );
-      // EI -> AI
-      $sIn = preg_replace( '`([VSBSTNRLPM])E[IY]([ACDFRJLGZ])`', '$1AI$2', $sIn );
-
-      // Histoire d'Ô
-      $convNasIn  = array( 'EAU', 'EU',  'Y', 'EOI', 'JEA','OIEM','OUANJ','OUA','OUENJ');
-      $convNasOut = array(   'O',  'E',  'I',  'OI', 'JA' ,'OIM' ,'OUENJ', 'OI','OUANJ');
-      $sIn = str_replace( $convNasIn, $convNasOut, $sIn );
-      $sIn = preg_replace( '`AU([^E])`', 'O$1', $sIn ); // AU sans E qui suit
-
-      // Les retouches!
-      $sIn = preg_replace( '`^BENJ`', 'BINJ', $sIn );       // retouche BENJ -> BINJ
-      $sIn = str_replace( 'RTIEL', 'RSIEL', $sIn );     // retouche RTIEL -> RSIEL
-      $sIn = str_replace( 'PINK', 'PONK', $sIn );       // retouche PINK -> PONK
-      $sIn = str_replace( 'KIND', 'KOND', $sIn );       // retouche KIND -> KOND
-      $sIn = preg_replace( '`KUM(N|P)`', 'KON$1', $sIn );     // retouche KUMN KUMP
-      $sIn = str_replace( 'LKOU', 'LKO', $sIn );        // retouche LKOU -> LKO
-      $sIn = str_replace( 'EDBE', 'EBE', $sIn );        // retouche EDBE pied-bœuf
-      $sIn = str_replace( 'ARCM', 'ARKM', $sIn );       // retouche SCH -> CH
-      $sIn = str_replace( 'SCH', 'CH', $sIn );          // retouche SCH -> CH
-      $sIn = preg_replace( '`^OINI`', 'ONI', $sIn );        // retouche début OINI -> ONI
-      $sIn = preg_replace( '`([^NDCGRHKO])APT`', '$1AT', $sIn );  // retouche APT -> AT
-      $sIn = preg_replace( '`([L]|KON)PT`', '$1T', $sIn );    // retouche LPT -> LT
-      $sIn = str_replace( 'OTB', 'OB', $sIn );          // retouche OTB -> OB (hautbois)
-      $sIn = str_replace( 'IXA', 'ISA', $sIn );       // retouche IXA -> ISA
-      $sIn = str_replace( 'TG', 'G', $sIn );          // retouche TG -> G
-      $sIn = preg_replace( '`^TZ`', 'TS', $sIn );         // retouche début TZ -> TS
-      $sIn = str_replace( 'PTIE', 'TIE', $sIn );        // retouche PTIE -> TIE
-      $sIn = str_replace( 'GT', 'T', $sIn );          // retouche GT -> T
-      $sIn = str_replace( 'ANKIEM', 'ANKILEM', $sIn );      // retouche tranquillement
-      $sIn = preg_replace( '`(LO|RE)KEMAN`', '$1KAMAN', $sIn ); // KEMAN -> KAMAN
-      $sIn = preg_replace( '`NT(B|M)`', 'N$1', $sIn );      // retouche TB -> B  TM -> M
-      $sIn = str_replace( 'GSU', 'SU', $sIn );          // retouche GS -> SU
-      $sIn = str_replace( 'ESD', 'ED', $sIn );          // retouche ESD -> ED
-      $sIn = str_replace( 'LESKEL', 'LEKEL', $sIn );      // retouche LESQUEL -> LEKEL
-      $sIn = str_replace( 'CK', 'K', $sIn );          // retouche CK -> K
-
-      // Terminaisons
-      $sIn = preg_replace( '`USIL$`', 'USI', $sIn );        // terminaisons USIL -> USI
-      $sIn = preg_replace( '`X$|[TD]S$|[DS]$`', '', $sIn );   // terminaisons TS DS LS X T D S...  v2.0
-      $sIn = preg_replace( '`([^KL]+)T$`', '$1', $sIn );      // sauf KT LT terminal
-      $sIn = preg_replace( '`^[H]`', '', $sIn );          // H pseudo muet en début de mot, je sais, ce n'est pas une terminaison
-      $sBack2=$sIn;                       // on sauve le code (utilisé pour les mots très courts)
-
-      $convPartIn = [
-                     '`TIL$`', // terminaisons TIL -> TI
-                     '`LC$`', // terminaisons LC -> LK
-                     '`L[E]?[S]?$`',      // terminaisons LE LES -> L
-                     '`(.+)N[E]?[S]?$`',    // terminaisons NE NES -> N
-                     '`EZ$`',         // terminaisons EZ -> E
-                     '`OIG$`',        // terminaisons OIG -> OI
-                     '`OUP$`',        // terminaisons OUP -> OU
-                     '`([^R])OM$`',     // terminaisons OM -> ON sauf ROM
-                     '`LOP$`',        // terminaisons LOP -> LO
-                     '`NTANP$`',      // terminaisons NTANP -> NTAN
-                     '`TUN$`',        // terminaisons TUN -> TIN
-                     '`AU$`',         // terminaisons AU -> O
-                     '`EI$`',         // terminaisons EI -> AI
-                     '`R[DG]$`',        // terminaisons RD RG -> R
-                     '`ANC$`',        // terminaisons ANC -> AN
-                     '`KROC$`',       // terminaisons C muet de CROC, ESCROC
-                     '`HOUC$`', // terminaisons C muet de CAOUTCHOUC
-                     '`OMAC$`',       // terminaisons C muet de ESTOMAC (mais pas HAMAC)
-                     '`([J])O([NU])[CG]$`',// terminaisons C et G muet de OUC ONC OUG
-                     '`([^GTR])([AO])NG$`',// terminaisons G muet ANG ONG sauf GANG GONG TANG TONG
-                     '`UC$`',         // terminaisons UC -> UK
-                     '`AING$`',       // terminaisons AING -> IN
-                     '`([EISOARN])C$`',   // terminaisons C -> K
-                     '`([ABD-MO-Z]+)[EH]+$`', // terminaisons E ou H sauf pour C et N
-                     '`EN$`',         // terminaisons EN -> AN (difficile à faire avant sans avoir des soucis) Et encore,
-                     '`(NJ)EN$`',// terminaisons EN -> AN
-                     '`^PAIEM`',      // PAIE -> PAI
-                     '`([^NTB])EF$`',     // F muet en fin de mot
-                     '`(.)\1`'        // supression des répétitions (suite à certains remplacements)
-      ];
-
-      $convPartOut = [
-                      'TI',       // terminaisons TIL -> TI
-                      'LK',         // terminaisons LC -> LK
-                      'L',      // terminaisons LE LES -> L
-                      '$1N',    // terminaisons NE NES -> N
-                      'E',          // terminaisons EZ -> E
-                      'OI',       // terminaisons OIG -> OI
-                      'OU',       // terminaisons OUP -> OU
-                      '$1ON',     // terminaisons OM -> ON sauf ROM
-                      'LO',       // terminaisons LOP -> LO
-                      'NTAN',     // terminaisons NTANP -> NTAN
-                      'TIN',        // terminaisons TUN -> TIN
-                      'O',          // terminaisons AU -> O
-                      'AI',         // terminaisons EI -> AI
-                      'R',        // terminaisons RD RG -> R
-                      'AN',       // terminaisons ANC -> AN
-                      'KRO',        // terminaisons C muet de CROC, ESCROC
-                      'HOU',        // terminaisons C muet de CAOUTCHOUC
-                      'OMA',        // terminaisons C muet de ESTOMAC (mais pas HAMAC)
-                      '$1O$2',// terminaisons C et G muet de OUC ONC OUG
-                      '$1$2N',// terminaisons G muet ANG ONG sauf GANG GONG TANG TONG
-                      'UK',         // terminaisons UC -> UK
-                      'IN',       // terminaisons AING -> IN
-                      '$1K',    // terminaisons C -> K
-                      '$1', // terminaisons E ou H sauf pour C et N
-                      'AN',         // terminaisons EN -> AN (difficile à faire avant sans avoir des soucis) Et encore, c'est pas top!
-                      '$1AN',     // terminaisons EN -> AN
-                      'PAIM',       // PAIE -> PAI
-                      '\1',     // F muet en fin de mot
-                      '$1'        // supression des répétitions (suite à certains remplacements)
-      ];
-
-      $sIn = preg_replace( $convPartIn, $convPartOut, $sIn );
-
-      // cas particuliers, bah au final, je n'en ai qu'un ici
-      $convPartIn  = array( 'FUEL');
-      $convPartOut = array( 'FIOUL');
-      $sIn = str_replace( $convPartIn, $convPartOut, $sIn );
-
-      // Ce sera le seul code retourné à une seule lettre!
-      if ($sIn=='O') return($sIn);
-
-      // seconde chance sur les mots courts qui ont souffert de la simplification
-      if (strlen($sIn)<2)
-        {
-          // Sigles ou abréviations
-          if (preg_match('`[BCDFGHJKLMNPQRSTVWXYZ][BCDFGHJKLMNPQRSTVWXYZ][BCDFGHJKLMNPQRSTVWXYZ][BCDFGHJKLMNPQRSTVWXYZ]*`',$sBack))
-            return($sBack);
-
-          if (preg_match('`[RFMLVSPJDF][AEIOU]`',$sBack))
-            {
-              if (strlen($sBack)==3)
-                return(substr($sBack,0,2));// mots de trois lettres supposés simples
-              if (strlen($sBack)==4)
-                return(substr($sBack,0,3));// mots de quatre lettres supposés simples
-            }
-
-          if (strlen($sBack2)>1) return $sBack2;
-        }
-      if (strlen($sIn)>1)
-        {
-          return substr($sIn,0,16); // Je limite à 16 caractères mais vous faites comme vous voulez!
-        }
-      else return '';
-    }
+  function phonetixCompute($sIn)  {
+    $sIn = strtr( $sIn, $this->accents);          // minuscules accentuées ou composées en majuscules simples
+    $sIn = strtr( $sIn, $this->min2maj);          // majuscules accentuées ou composées en majuscules simples
+    $sIn = strtoupper( $sIn );              // on passe tout le reste en majuscules
+    $sIn = preg_replace( '`[^A-Z]`', '', $sIn );  // on garde uniquement les lettres de A à Z
+
+    $sBack=$sIn;                  // on sauve le code (utilisé pour les mots très courts)
+
+    $sIn = preg_replace( '`O[O]+`', 'OU', $sIn );   // pré traitement OO... -> OU
+    $sIn = str_replace( 'SAOU', 'SOU', $sIn );  // pré traitement SAOU -> SOU
+    $sIn = str_replace( 'OES', 'OS', $sIn );  // pré traitement OES -> OS
+    $sIn = str_replace( 'CCH', 'K', $sIn );     // pré traitement CCH -> K
+    $sIn = preg_replace( '`CC([IYE])`', 'KS$1', $sIn ); // CCI CCY CCE
+    $sIn = preg_replace( '`(.)\1`', '$1', $sIn );   // supression des répétitions
+
+    // quelques cas particuliers
+    if ($sIn=='CD') return($sIn);
+    if ($sIn=='BD') return($sIn);
+    if ($sIn=='BV') return($sIn);
+    if ($sIn=='TABAC') return('TABA');
+    if ($sIn=='FEU') return('FE');
+    if ($sIn=='FE') return($sIn);
+    if ($sIn=='FER') return($sIn);
+    if ($sIn=='FIEF') return($sIn);
+    if ($sIn=='FJORD') return($sIn);
+    if ($sIn=='GOAL') return('GOL');
+    if ($sIn=='FLEAU') return('FLEO');
+    if ($sIn=='HIER') return('IER');
+    if ($sIn=='HEU') return('E');
+    if ($sIn=='HE') return('E');
+    if ($sIn=='OS') return($sIn);
+    if ($sIn=='RIZ') return('RI');
+    if ($sIn=='RAZ') return('RA');
+
+    // pré-traitements
+    $sIn = preg_replace( '`OIN[GT]$`', 'OIN', $sIn );                 // terminaisons OING -> OIN
+    $sIn = preg_replace( '`E[RS]$`', 'E', $sIn );                     // supression des terminaisons infinitifs et participes pluriels
+    $sIn = preg_replace( '`(C|CH)OEU`', 'KE', $sIn );                   // pré traitement OEU -> EU
+    $sIn = str_replace( 'MOEU', 'ME', $sIn );                     // pré traitement OEU -> EU
+    $sIn = preg_replace( '`OE([UI]+)([BCDFGHJKLMNPQRSTVWXZ])`', 'E$1$2', $sIn );    // pré traitement OEU OEI -> E
+    $sIn = preg_replace( '`^GEN[TS]$`', 'JAN', $sIn );                  // pré traitement GEN -> JAN
+    $sIn = str_replace( 'CUEI', 'KEI', $sIn );                    // pré traitement accueil
+    $sIn = preg_replace( '`([^AEIOUYC])AE([BCDFGHJKLMNPQRSTVWXZ])`', '$1E$2', $sIn );   // pré traitement AE -> E
+    $sIn = preg_replace( '`AE([QS])`', 'E$1', $sIn );                   // pré traitement AE -> E
+    $sIn = preg_replace( '`AIE([BCDFGJKLMNPQRSTVWXZ])`', 'AI$1', $sIn );        // pré-traitement AIE(consonne) -> AI
+    $sIn = str_replace( 'ANIEM', 'ANIM', $sIn );                  // pré traitement NIEM -> NIM
+    $sIn = preg_replace( '`(DRA|TRO|IRO)P$`', '$1', $sIn );               // P terminal muet
+    $sIn = preg_replace( '`(LOM)B$`', '$1', $sIn );                   // B terminal muet
+    $sIn = preg_replace( '`(RON|POR)C$`', '$1', $sIn );                 // C terminal muet
+    $sIn = preg_replace( '`PECT$`', 'PET', $sIn );                    // C terminal muet
+    $sIn = preg_replace( '`ECUL$`', 'CU', $sIn );                     // L terminal muet
+    $sIn = preg_replace( '`(CHA|CA|E)M(P|PS)$`', '$1N', $sIn );             // P ou PS terminal muet
+    $sIn = preg_replace( '`(TAN|RAN)G$`', '$1', $sIn );                 // G terminal muet
+
+
+    // sons YEUX
+    $sIn = preg_replace( '`([^VO])ILAG`', '$1IAJ', $sIn );
+    $sIn = preg_replace( '`([^TRH])UIL(AR|E)(.+)`', '$1UI$2$3', $sIn );
+    $sIn = preg_replace( '`([G])UIL([AEO])`', '$1UI$2', $sIn );
+    $sIn = preg_replace( '`([NSPM])AIL([AEO])`', '$1AI$2', $sIn );
+    $convMIn  = array('DILAI','DILON','DILER','DILEM','RILON','TAILE','GAILET','AILAI','AILAR',
+                      'OUILA','EILAI','EILAR','EILER','EILEM','REILET','EILET','AILOL' );
+    $convMOut = array( 'DIAI', 'DION','DIER', 'DIEM', 'RION', 'TAIE', 'GAIET', 'AIAI', 'AIAR',
+                      'OUIA', 'AIAI', 'AIAR', 'AIER', 'AIEM',  'RAIET', 'EIET', 'AIOL' );
+    $sIn = str_replace( $convMIn, $convMOut, $sIn );
+    $sIn = preg_replace( '`([^AEIOUY])(SC|S)IEM([EA])`', '$1$2IAM$3', $sIn );   // IEM -> IAM
+    $sIn = preg_replace( '`^(SC|S)IEM([EA])`', '$1IAM$2', $sIn );         // IEM -> IAM
+
+    // MP MB -> NP NB
+    $convMIn  = array( 'OMB', 'AMB', 'OMP', 'AMP', 'IMB', 'EMP','GEMB','EMB', 'UMBL','CIEN');
+    $convMOut = array( 'ONB', 'ANB', 'ONP', 'ANP', 'INB', 'ANP','JANB','ANB', 'INBL','SIAN');
+    $sIn = str_replace( $convMIn, $convMOut, $sIn );
+
+    // Sons en K
+    $sIn = preg_replace( '`^ECHO$`', 'EKO', $sIn );   // cas particulier écho
+    $sIn = preg_replace( '`^ECEUR`', 'EKEUR', $sIn );   // cas particulier écœuré
+    // Choléra Chœur mais pas chocolat!
+    $sIn = preg_replace( '`^CH(OG+|OL+|OR+|EU+|ARIS|M+|IRO|ONDR)`', 'K$1', $sIn );        //En début de mot
+    $sIn = preg_replace( '`(YN|RI)CH(OG+|OL+|OC+|OP+|OM+|ARIS|M+|IRO|ONDR)`', '$1K$2', $sIn );  //Ou devant une consonne
+    $sIn = preg_replace( '`CHS`', 'CH', $sIn );
+    $sIn = preg_replace( '`CH(AIQ)`', 'K$1', $sIn );
+    $sIn = preg_replace( '`^ECHO([^UIPY])`', 'EKO$1', $sIn );
+    $sIn = preg_replace( '`ISCH(I|E)`', 'ISK$1', $sIn );
+    $sIn = preg_replace( '`^ICHT`', 'IKT', $sIn );
+    $sIn = preg_replace( '`ORCHID`', 'ORKID', $sIn );
+    $sIn = preg_replace( '`ONCHIO`', 'ONKIO', $sIn );
+    $sIn = preg_replace( '`ACHIA`', 'AKIA', $sIn );     // retouche ACHIA -> AKIA
+    $sIn = preg_replace( '`([^C])ANICH`', '$1ANIK', $sIn ); // ANICH -> ANIK  1/2
+    $sIn = preg_replace( '`OMANIK`', 'OMANICH', $sIn );   // cas particulier  2/2
+    $sIn = preg_replace( '`ACHY([^D])`', 'AKI$1', $sIn );
+    $sIn = preg_replace( '`([AEIOU])C([BDFGJKLMNPQRTVWXZ])`', '$1K$2', $sIn ); // voyelle, C, consonne sauf H
+    $convPrIn  = array('EUCHA','YCHIA','YCHA','YCHO','YCHED','ACHEO','RCHEO','RCHES',
+                       'ECHN','OCHTO','CHORA','CHONDR','CHORE','MACHM','BRONCHO','LICHOS','LICHOC');
+    $convPrOut = array('EKA',  'IKIA', 'IKA', 'IKO',  'IKED','AKEO','RKEO',  'RKES',
+                       'EKN',  'OKTO', 'KORA', 'KONDR' ,'KORE' ,'MAKM', 'BRONKO', 'LIKOS', 'LIKOC');
+    $sIn = str_replace( $convPrIn, $convPrOut, $sIn );
+
+    // Weuh (perfectible)
+    $convPrIn  = array( 'WA','WO', 'WI','WHI','WHY','WHA','WHO');
+    $convPrOut = array( 'OI', 'O','OUI','OUI','OUI','OUA', 'OU');
+    $sIn = str_replace( $convPrIn, $convPrOut, $sIn );
+
+    // Gueu, Gneu, Jeu et quelques autres
+    $convPrIn  = array( 'GNES','GNET','GNER','GNE',  'GI', 'GNI','GNA','GNOU','GNUR','GY','OUGAIN',
+                       'AGEOL', 'AGEOT','GEOLO','GEOM','GEOP','GEOG','GEOS','GEORG','GEOR','NGEOT','UGEOT','GEOT','GEOD','GEOC','GEO','GEA','GE',
+                       'QU', 'Q',  'CY', 'CI', 'CN','ICM','CEAT','CE',
+                       'CR', 'CO', 'CUEI','CU', 'VENCA','CA', 'CS','CLEN','CL', 'CZ', 'CTIQ',
+                       'CTIF','CTIC','CTIS','CTIL','CTIO','CTI', 'CTU', 'CTE','CTO','CTR','CT', 'PH', 'TH',
+                       'OW', 'LH', 'RDL', 'CHLO', 'CHR', 'PTIA');
+    $convPrOut = array( 'NIES','NIET','NIER', 'NE',  'JI',  'NI','NIA','NIOU','NIUR','JI','OUGIN',
+                       'AJOL',  'AJOT','JEOLO','JEOM','JEOP','JEOG','JEOS','JORJ','JEOR','NJOT','UJOT','JEOT','JEOD','JEOC', 'JO','JA' ,'JE',
+                       'K', 'K',  'SI', 'SI', 'KN','IKM', 'SAT','SE',
+                       'KR', 'KO', 'KEI','KU', 'VANSA','KA', 'KS','KLAN','KL', 'KZ', 'KTIK',
+                       'KTIF','KTIS','KTIS','KTIL','KSIO','KTI', 'KTU', 'KTE','KTO','KTR','KT', 'F',  'T',
+                       'OU',  'L',  'RL',  'KLO',  'KR', 'PSIA');
+    $sIn = str_replace( $convPrIn, $convPrOut, $sIn );
+
+    $sIn = preg_replace( '`GU([^RLMBSTPZN])`', 'G$1', $sIn ); // Gueu !
+    $sIn = preg_replace( '`GNO([MLTNRKG])`', 'NIO$1', $sIn ); // GNO ! Tout sauf S pour gnos
+    $sIn = preg_replace( '`GNO([MLTNRKG])`', 'NIO$1', $sIn ); // bis -> gnognotte! Si quelqu'un sait le faire en une seule regexp...
+
+
+    // TI -> SI v2.0
+    $convPrIn  = array( 'BUTIE','BUTIA','BATIA','ANTIEL','RETION','ENTIEL','ENTIAL','ENTIO','ENTIAI','UJETION','ATIEM','PETIEN',
+                       'CETIE','OFETIE','IPETI','LBUTION','BLUTION','LETION','LATION','SATIET');
+    $convPrOut = array( 'BUSIE','BUSIA','BASIA','ANSIEL','RESION','ENSIEL','ENSIAL','ENSIO','ENSIAI','UJESION','ASIAM','PESIEN',
+                       'CESIE','OFESIE','IPESI','LBUSION','BLUSION','LESION','LASION','SASIET');
+    $sIn = str_replace( $convPrIn, $convPrOut, $sIn );
+    $sIn = preg_replace( '`(.+)ANTI(AL|O)`', '$1ANSI$2', $sIn ); // sauf antialcoolique, antialbumine, antialarmer, ...
+    $sIn = preg_replace( '`(.+)INUTI([^V])`', '$1INUSI$2', $sIn ); // sauf inutilité, inutilement, diminutive, ...
+    $sIn = preg_replace( '`([^O])UTIEN`', '$1USIEN', $sIn ); // sauf soutien, ...
+    $sIn = preg_replace( '`([^DE])RATI[E]$`', '$1RASI$2', $sIn ); // sauf xxxxxcratique, ...
+    // TIEN TION -> SIEN SION v3.1
+    $sIn = preg_replace( '`([^SNEU]|KU|KO|RU|LU|BU|TU|AU)T(IEN|ION)`', '$1S$2', $sIn );
+
+
+    // H muet
+    $sIn = preg_replace( '`([^CS])H`', '$1', $sIn );  // H muet
+    $sIn = str_replace( 'ESH', 'ES', $sIn );      // H muet
+    $sIn = str_replace( 'NSH', 'NS', $sIn );      // H muet
+    $sIn = str_replace( 'SH', 'CH', $sIn );       // ou pas!
+
+    // NASALES
+    $convNasIn  = array( 'OMT','IMB', 'IMP','UMD','TIENT','RIENT','DIENT','IEN',
+                        'YMU','YMO','YMA','YME', 'YMI','YMN','YM', 'AHO','FAIM','DAIM','SAIM','EIN','AINS');
+    $convNasOut = array( 'ONT','INB', 'INP','OND','TIANT','RIANT','DIANT', 'IN',
+                        'IMU','IMO','IMA','IME', 'IMI','IMN','IN',  'AO', 'FIN','DIN', 'SIN','AIN','INS');
+    $sIn = str_replace( $convNasIn, $convNasOut, $sIn );
+    // AIN -> IN v2.0
+    $sIn = preg_replace( '`AIN$`', 'IN', $sIn );
+    $sIn = preg_replace( '`AIN([BTDK])`', 'IN$1', $sIn );
+    // UN -> IN
+    $sIn = preg_replace( '`([^O])UND`', '$1IND', $sIn ); // aucun mot français ne commence par UND!
+    $sIn = preg_replace( '`([JTVLFMRPSBD])UN([^IAE])`', '$1IN$2', $sIn );
+    $sIn = preg_replace( '`([JTVLFMRPSBD])UN$`', '$1IN', $sIn );
+    $sIn = preg_replace( '`RFUM$`', 'RFIN', $sIn );
+    $sIn = str_replace( 'LUMB', 'LINB', $sIn );
+    // EN -> AN
+    $sIn = preg_replace( '`([^BCDFGHJKLMNPQRSTVWXZ])EN`', '$1AN', $sIn );
+    $sIn = preg_replace( '`([VTLJMRPDSBFKNG])EN([BRCTDKZSVN])`', '$1AN$2', $sIn ); // deux fois pour les motifs recouvrants malentendu, pendentif, ...
+    $sIn = preg_replace( '`([VTLJMRPDSBFKNG])EN([BRCTDKZSVN])`', '$1AN$2', $sIn ); // si quelqu'un sait faire avec une seule regexp!
+    $sIn = preg_replace( '`^EN([BCDFGHJKLNPQRSTVXZ]|CH|IV|ORG|OB|UI|UA|UY)`', 'AN$1', $sIn );
+    $sIn = preg_replace( '`(^[JRVTH])EN([DRTFGSVJMP])`', '$1AN$2', $sIn );
+    $sIn = preg_replace( '`SEN([ST])`', 'SAN$1', $sIn );
+    $sIn = preg_replace( '`^DESENIV`', 'DESANIV', $sIn );
+    $sIn = preg_replace( '`([^M])EN(UI)`', '$1AN$2', $sIn );
+    $sIn = preg_replace( '`(.+[JTVLFMRPSBD])EN([JLFDSTG])`', '$1AN$2', $sIn );
+    // EI -> AI
+    $sIn = preg_replace( '`([VSBSTNRLPM])E[IY]([ACDFRJLGZ])`', '$1AI$2', $sIn );
+
+    // Histoire d'Ô
+    $convNasIn  = array( 'EAU', 'EU',  'Y', 'EOI', 'JEA','OIEM','OUANJ','OUA','OUENJ');
+    $convNasOut = array(   'O',  'E',  'I',  'OI', 'JA' ,'OIM' ,'OUENJ', 'OI','OUANJ');
+    $sIn = str_replace( $convNasIn, $convNasOut, $sIn );
+    $sIn = preg_replace( '`AU([^E])`', 'O$1', $sIn ); // AU sans E qui suit
+
+    // Les retouches!
+    $sIn = preg_replace( '`^BENJ`', 'BINJ', $sIn );       // retouche BENJ -> BINJ
+    $sIn = str_replace( 'RTIEL', 'RSIEL', $sIn );     // retouche RTIEL -> RSIEL
+    $sIn = str_replace( 'PINK', 'PONK', $sIn );       // retouche PINK -> PONK
+    $sIn = str_replace( 'KIND', 'KOND', $sIn );       // retouche KIND -> KOND
+    $sIn = preg_replace( '`KUM(N|P)`', 'KON$1', $sIn );     // retouche KUMN KUMP
+    $sIn = str_replace( 'LKOU', 'LKO', $sIn );        // retouche LKOU -> LKO
+    $sIn = str_replace( 'EDBE', 'EBE', $sIn );        // retouche EDBE pied-bœuf
+    $sIn = str_replace( 'ARCM', 'ARKM', $sIn );       // retouche SCH -> CH
+    $sIn = str_replace( 'SCH', 'CH', $sIn );          // retouche SCH -> CH
+    $sIn = preg_replace( '`^OINI`', 'ONI', $sIn );        // retouche début OINI -> ONI
+    $sIn = preg_replace( '`([^NDCGRHKO])APT`', '$1AT', $sIn );  // retouche APT -> AT
+    $sIn = preg_replace( '`([L]|KON)PT`', '$1T', $sIn );    // retouche LPT -> LT
+    $sIn = str_replace( 'OTB', 'OB', $sIn );          // retouche OTB -> OB (hautbois)
+    $sIn = str_replace( 'IXA', 'ISA', $sIn );       // retouche IXA -> ISA
+    $sIn = str_replace( 'TG', 'G', $sIn );          // retouche TG -> G
+    $sIn = preg_replace( '`^TZ`', 'TS', $sIn );         // retouche début TZ -> TS
+    $sIn = str_replace( 'PTIE', 'TIE', $sIn );        // retouche PTIE -> TIE
+    $sIn = str_replace( 'GT', 'T', $sIn );          // retouche GT -> T
+    $sIn = str_replace( 'ANKIEM', 'ANKILEM', $sIn );      // retouche tranquillement
+    $sIn = preg_replace( '`(LO|RE)KEMAN`', '$1KAMAN', $sIn ); // KEMAN -> KAMAN
+    $sIn = preg_replace( '`NT(B|M)`', 'N$1', $sIn );      // retouche TB -> B  TM -> M
+    $sIn = str_replace( 'GSU', 'SU', $sIn );          // retouche GS -> SU
+    $sIn = str_replace( 'ESD', 'ED', $sIn );          // retouche ESD -> ED
+    $sIn = str_replace( 'LESKEL', 'LEKEL', $sIn );      // retouche LESQUEL -> LEKEL
+    $sIn = str_replace( 'CK', 'K', $sIn );          // retouche CK -> K
+
+    // Terminaisons
+    $sIn = preg_replace( '`USIL$`', 'USI', $sIn );        // terminaisons USIL -> USI
+    $sIn = preg_replace( '`X$|[TD]S$|[DS]$`', '', $sIn );   // terminaisons TS DS LS X T D S...  v2.0
+    $sIn = preg_replace( '`([^KL]+)T$`', '$1', $sIn );      // sauf KT LT terminal
+    $sIn = preg_replace( '`^[H]`', '', $sIn );          // H pseudo muet en début de mot, je sais, ce n'est pas une terminaison
+    $sBack2=$sIn;                       // on sauve le code (utilisé pour les mots très courts)
+
+    $convPartIn = [
+                   '`TIL$`', // terminaisons TIL -> TI
+                   '`LC$`', // terminaisons LC -> LK
+                   '`L[E]?[S]?$`',      // terminaisons LE LES -> L
+                   '`(.+)N[E]?[S]?$`',    // terminaisons NE NES -> N
+                   '`EZ$`',         // terminaisons EZ -> E
+                   '`OIG$`',        // terminaisons OIG -> OI
+                   '`OUP$`',        // terminaisons OUP -> OU
+                   '`([^R])OM$`',     // terminaisons OM -> ON sauf ROM
+                   '`LOP$`',        // terminaisons LOP -> LO
+                   '`NTANP$`',      // terminaisons NTANP -> NTAN
+                   '`TUN$`',        // terminaisons TUN -> TIN
+                   '`AU$`',         // terminaisons AU -> O
+                   '`EI$`',         // terminaisons EI -> AI
+                   '`R[DG]$`',        // terminaisons RD RG -> R
+                   '`ANC$`',        // terminaisons ANC -> AN
+                   '`KROC$`',       // terminaisons C muet de CROC, ESCROC
+                   '`HOUC$`', // terminaisons C muet de CAOUTCHOUC
+                   '`OMAC$`',       // terminaisons C muet de ESTOMAC (mais pas HAMAC)
+                   '`([J])O([NU])[CG]$`',// terminaisons C et G muet de OUC ONC OUG
+                   '`([^GTR])([AO])NG$`',// terminaisons G muet ANG ONG sauf GANG GONG TANG TONG
+                   '`UC$`',         // terminaisons UC -> UK
+                   '`AING$`',       // terminaisons AING -> IN
+                   '`([EISOARN])C$`',   // terminaisons C -> K
+                   '`([ABD-MO-Z]+)[EH]+$`', // terminaisons E ou H sauf pour C et N
+                   '`EN$`',         // terminaisons EN -> AN (difficile à faire avant sans avoir des soucis) Et encore,
+                   '`(NJ)EN$`',// terminaisons EN -> AN
+                   '`^PAIEM`',      // PAIE -> PAI
+                   '`([^NTB])EF$`',     // F muet en fin de mot
+                   '`(.)\1`'        // supression des répétitions (suite à certains remplacements)
+    ];
+
+    $convPartOut = [
+                    'TI',       // terminaisons TIL -> TI
+                    'LK',         // terminaisons LC -> LK
+                    'L',      // terminaisons LE LES -> L
+                    '$1N',    // terminaisons NE NES -> N
+                    'E',          // terminaisons EZ -> E
+                    'OI',       // terminaisons OIG -> OI
+                    'OU',       // terminaisons OUP -> OU
+                    '$1ON',     // terminaisons OM -> ON sauf ROM
+                    'LO',       // terminaisons LOP -> LO
+                    'NTAN',     // terminaisons NTANP -> NTAN
+                    'TIN',        // terminaisons TUN -> TIN
+                    'O',          // terminaisons AU -> O
+                    'AI',         // terminaisons EI -> AI
+                    'R',        // terminaisons RD RG -> R
+                    'AN',       // terminaisons ANC -> AN
+                    'KRO',        // terminaisons C muet de CROC, ESCROC
+                    'HOU',        // terminaisons C muet de CAOUTCHOUC
+                    'OMA',        // terminaisons C muet de ESTOMAC (mais pas HAMAC)
+                    '$1O$2',// terminaisons C et G muet de OUC ONC OUG
+                    '$1$2N',// terminaisons G muet ANG ONG sauf GANG GONG TANG TONG
+                    'UK',         // terminaisons UC -> UK
+                    'IN',       // terminaisons AING -> IN
+                    '$1K',    // terminaisons C -> K
+                    '$1', // terminaisons E ou H sauf pour C et N
+                    'AN',         // terminaisons EN -> AN (difficile à faire avant sans avoir des soucis) Et encore, c'est pas top!
+                    '$1AN',     // terminaisons EN -> AN
+                    'PAIM',       // PAIE -> PAI
+                    '\1',     // F muet en fin de mot
+                    '$1'        // supression des répétitions (suite à certains remplacements)
+    ];
+
+    $sIn = preg_replace( $convPartIn, $convPartOut, $sIn );
+
+    // cas particuliers, bah au final, je n'en ai qu'un ici
+    $convPartIn  = array( 'FUEL');
+    $convPartOut = array( 'FIOUL');
+    $sIn = str_replace( $convPartIn, $convPartOut, $sIn );
+
+    // Ce sera le seul code retourné à une seule lettre!
+    if ($sIn=='O') return($sIn);
+
+    // seconde chance sur les mots courts qui ont souffert de la simplification
+    if (strlen($sIn)<2)
+      {
+        // Sigles ou abréviations
+        if (preg_match('`[BCDFGHJKLMNPQRSTVWXYZ][BCDFGHJKLMNPQRSTVWXYZ][BCDFGHJKLMNPQRSTVWXYZ][BCDFGHJKLMNPQRSTVWXYZ]*`',$sBack))
+          return($sBack);
+
+        if (preg_match('`[RFMLVSPJDF][AEIOU]`',$sBack))
+          {
+            if (strlen($sBack)==3)
+              return(substr($sBack,0,2));// mots de trois lettres supposés simples
+            if (strlen($sBack)==4)
+              return(substr($sBack,0,3));// mots de quatre lettres supposés simples
+          }
+
+        if (strlen($sBack2)>1) return $sBack2;
+      }
+    if (strlen($sIn)>1)
+      {
+        return substr($sIn,0,16); // Je limite à 16 caractères mais vous faites comme vous voulez!
+      }
+    else return '';
   }
+}
 ?>
\ No newline at end of file
diff --git a/library/Class/TimeSource.php b/library/Class/TimeSource.php
index 3872031f727f69bd2e91c6f51c85f268ca27d12b..5045e4662fdc87322aa59bcd1cd805ea88a90a5d 100644
--- a/library/Class/TimeSource.php
+++ b/library/Class/TimeSource.php
@@ -16,7 +16,7 @@
  *
  * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
  * along with BOKEH; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA 
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
  */
 
 /**
@@ -29,7 +29,7 @@ class Class_TimeSource {
     return time();
   }
 
-  
+
   public function dateYmd() {
     return date('Y-m-d', $this->time());
   }
@@ -53,20 +53,20 @@ class Class_TimeSource {
 
   public function nextDate() {
     $time = $this->time();
-    return $this->midnightTime(date('n', $time), 
-                               date('j', $time) + 1, 
+    return $this->midnightTime(date('n', $time),
+                               date('j', $time) + 1,
                                date('Y', $time));
   }
 
 
   public function nextMonths($number_of_months=1) {
     $time = $this->time();
-    return $this->midnightTime(date('n', $time) + $number_of_months, 
-                               date('j', $time), 
+    return $this->midnightTime(date('n', $time) + $number_of_months,
+                               date('j', $time),
                                date('Y', $time));
   }
 
-  
+
   public function getMonth($month) {
     $time = $this->time();
     $year = date('m', $time) > $month ? date('Y', $time) + 1 : date('Y', $time);
@@ -77,5 +77,11 @@ class Class_TimeSource {
   protected function midnightTime($month, $day, $year) {
     return mktime(0, 0, 0, $month, $day, $year);
   }
+
+
+  public function lastYear() {
+    $time = $this->time();
+    return date('Y', $time) - 1 . date('-m-d', $time);
+  }
 }
 ?>
\ No newline at end of file
diff --git a/tests/library/Class/Cosmogramme/Integration/PhaseNoticeTest.php b/tests/library/Class/Cosmogramme/Integration/PhaseNoticeTest.php
index 0ea327da795f0ebcdff099925a457505410c824d..5eba2a3792ac8fd535a3b1e0fd37bf049816f30f 100644
--- a/tests/library/Class/Cosmogramme/Integration/PhaseNoticeTest.php
+++ b/tests/library/Class/Cosmogramme/Integration/PhaseNoticeTest.php
@@ -22,7 +22,8 @@
 require_once 'cosmogramme/php/fonctions/variables.php';
 require_once __DIR__ . '/PhaseNoticeTestCase.php';
 
-class PhaseNoticeImportTest extends PhaseNoticeTestCase {
+
+abstract class PhaseNoticeImportTestCase extends PhaseNoticeTestCase {
   protected function _prepareFixtures() {
     parent::_prepareFixtures();
 
@@ -41,16 +42,53 @@ class PhaseNoticeImportTest extends PhaseNoticeTestCase {
                     'code' => null,
                     'rules' => null]);
 
-    Class_CodifThesaurus::addFacetForSigb('Public' , '993$a',Class_IntBib::COM_NANOOK);
+    Class_CodifThesaurus::addFacetForSigb('Public', '993$a', Class_IntBib::COM_NANOOK);
 
     $this->fixture('Class_Exemplaire',
                    ['id' => 889039, 'id_int_bib' => 2]);
 
-    $time_source = $this->mock()->whenCalled('dateYmd')->answers('2015-06-26');
+    $oscar = $this->fixture('Class_CodifAuteur',
+                            ['id' => 42,
+                             'libelle' => 'WILDE oscar',
+                             'formes' => 'WILDExOSCAR',
+                             'mots_renvois' => 'HARLOCK;ARCADIA',
+                             'date_creation' => '2014-01-01']);
+
+    $edmond = $this->fixture('Class_CodifAuteur',
+                            ['id' => 43,
+                             'libelle' => 'JALOUX edmond',
+                             'formes' => 'JALOUXxEDMOND',
+                             'mots_renvois' => '',
+                             'date_creation' => '2015-01-01']);
+
+    $this->onLoaderOfModel('Class_CodifAuteur')
+         ->whenCalled('findByCodeAlpha')
+         ->with('WILDExOSCAR')
+         ->answers($oscar)
+
+         ->whenCalled('findByCodeAlpha')
+         ->with('JALOUXxEDMOND')
+         ->answers($edmond)
+
+         ->whenCalled('findByCodeAlpha')
+         ->answers(null);
+
+    $this->fixture('Class_CodifMatiere',
+                   ['id' => 43,
+                    'libelle' => 'Renaissance',
+                    'code_alpha' => 'RENAISSANCE',
+                    'mots_renvois' => 'LUMIERE',
+                    'date_creation' => '2015-01-01']);
+
+    $time_source = (new TimeSourceForTest('2015-10-19'))->atCoffeeTime();
     Class_Cosmogramme_Integration_PhaseNotice::setTimeSource($time_source);
+    Class_Cosmogramme_Integration_CodifProvider::setTimeSource($time_source);
   }
+}
 
 
+
+class PhaseNoticeImportFullTest extends PhaseNoticeImportTestCase {
   /** @test */
   public function totalNumberOfRecordsShouldBe109() {
     $this->assertEquals(109, Class_Notice::countBy([]));
@@ -107,7 +145,28 @@ class PhaseNoticeImportTest extends PhaseNoticeTestCase {
    * @see http://forge.afi-sa.fr/issues/26261
    */
   public function libraryLastImportDateShouldBeSet() {
-    $this->assertEquals('2015-06-26', Class_IntBib::find(2)->getDernierAjout());
+    $this->assertEquals('2015-10-19', Class_IntBib::find(2)->getDernierAjout());
+  }
+
+
+  /** @test */
+  public function firstRecordAuthorsShouldContainsSeeAlso() {
+    $this->assertContains('HARLOCK', Class_Notice::find(1)->getAuteurs());
+  }
+
+
+  /** @test */
+  public function recordTopicsShouldContainsSeeAlso() {
+    $record = Class_Notice::findFirstBy(['isbn' => '2-215-06225-8']);
+    $this->assertContains('LUMIERE',
+                          $record->getRawAttributes()['matieres'],
+                          $record->getTitrePrincipal());
+  }
+
+
+  /** @test */
+  public function shouldNotHarvestSeeAlsos() {
+    $this->assertFalse($this->_service_runner->methodHasBeenCalled('run'));
   }
 
 
diff --git a/tests/library/Class/Cosmogramme/Integration/PhaseNoticeTestCase.php b/tests/library/Class/Cosmogramme/Integration/PhaseNoticeTestCase.php
index ad5aef2189b81e74495020ac6d67be7a333c3c9b..7095a3c7a522e35e6ca13893fe7b320e97a33da1 100644
--- a/tests/library/Class/Cosmogramme/Integration/PhaseNoticeTestCase.php
+++ b/tests/library/Class/Cosmogramme/Integration/PhaseNoticeTestCase.php
@@ -21,10 +21,12 @@
 
 
 class PhaseNoticeTestCase extends Class_Cosmogramme_Integration_PhaseTestCase {
-  protected $_phase;
+  protected $_phase, $_service_runner;
 
   public function setUp() {
     parent::setUp();
+    $this->fixture('Class_CosmoVar',
+                   ['id' => 'unimarc_zone_matiere', 'valeur' => '610a']);
 
     $this->_phase = $this->_buildPhase('Notice')->run();
     Class_Notice::clearCache();
@@ -89,6 +91,11 @@ class PhaseNoticeTestCase extends Class_Cosmogramme_Integration_PhaseTestCase {
                     'traite' => 'non',
                     'fichier' => 'records.txt',
                     'pointeur_reprise' => 0]);
+
+    $this->_service_runner = $this->mock()
+                                  ->whenCalled('run')
+                                  ->answers(['statut' => 'KO']);
+    Class_Cosmogramme_Integration_PhaseNotice::setServiceRunner($this->_service_runner);
   }
 
 
diff --git a/tests/library/Class/TimeSourceForTest.php b/tests/library/Class/TimeSourceForTest.php
index 9ed1bf6a49dc3faa17246be13537a015ce23b81d..192f1897c64dd7c9f8fbe2c4f7ff57f2898cd9f9 100644
--- a/tests/library/Class/TimeSourceForTest.php
+++ b/tests/library/Class/TimeSourceForTest.php
@@ -16,7 +16,7 @@
  *
  * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
  * along with BOKEH; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA 
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
  */
 
 class TimeSourceForTest extends Class_TimeSource {
@@ -41,6 +41,10 @@ class TimeSourceForTest extends Class_TimeSource {
   public function time() {
     return $this->_time;
   }
-}
 
-?>
\ No newline at end of file
+
+  public function atCoffeeTime() {
+    $this->_time = strtotime(date('Y-m-d', $this->_time) . ' 16:00:00');
+    return $this;
+  }
+}
\ No newline at end of file