diff --git a/.gitignore b/.gitignore
index 3c3629e647f5ddf82548912e337bea9826b434af..97008e5b868ddbfa6767109cebdf00d7868ee8aa 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
 node_modules
+yarn.lock
\ No newline at end of file
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..091b8c160afb1760f82d7dfaa4ca1c374a81a049
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,33 @@
+stages:
+    - github-sync
+    - deploy
+
+push_to_github:
+    stage: github-sync
+    variables:
+        GIT_STRATEGY: none
+    tags:
+        - github
+    script:
+        - rm -rf ./*
+        - rm -rf .git
+        - git clone --mirror $CI_REPOSITORY_URL .
+        - git remote add github $GITHUB_URL_AND_KEY
+        - git config --global user.email "contact@duniter.org"
+        - git config --global user.name "Duniter"
+        # Job would fail if we don't remove refs about pull requests
+        - bash -c "cat packed-refs | grep -v 'refs/pull' > packed-refs-new; echo 'Removed pull refs.'"
+        - mv packed-refs-new packed-refs
+        - bash -c "git push --force --mirror github 2>&1 | grep -v duniter-gitlab; echo $?"
+      
+publish:  
+  stage: deploy
+  image: node:6.12-alpine
+  tags:
+    - nodejs
+  only:
+    - tags
+    - triggers
+  script:
+    - echo '//registry.npmjs.org/:_authToken=${NPM_TOKEN}'>.npmrc
+    - npm publish
\ No newline at end of file
diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000000000000000000000000000000000000..5f8c823f02f8246a92338f638282888f6697885f
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,15 @@
+{
+    // Use IntelliSense to learn about possible Node.js debug attributes.
+    // Hover to view descriptions of existing attributes.
+    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+    "version": "0.2.0",
+    "configurations": [
+        {
+            "type": "node",
+            "request": "launch",
+            "name": "Launch Currency-Monit",
+            "program": "${workspaceRoot}/run.js",
+            "args": ["currency-monit"]
+        }
+    ]
+}
\ No newline at end of file
diff --git a/lg/about_en.txt b/lg/about_en.txt
new file mode 100644
index 0000000000000000000000000000000000000000..615596ca85d8b0f76bb61e1f128b2f11cfde405d
--- /dev/null
+++ b/lg/about_en.txt
@@ -0,0 +1,9 @@
+LG en
+VERSION Version
+AUTHOR Author
+CONTRIBUTORS Others Contributors
+LICENSE license
+GIT_REPOSITORY git repository
+IF_YOU_WANT If you want you can
+DISABLE_HELP disable help
+DONATE You can support the development of this module by a gift in Ğ1
\ No newline at end of file
diff --git a/lg/about_fr.txt b/lg/about_fr.txt
new file mode 100644
index 0000000000000000000000000000000000000000..de67524f20240dc70391630f858f0ce06893f7b3
--- /dev/null
+++ b/lg/about_fr.txt
@@ -0,0 +1,9 @@
+LG fr
+VERSION Version
+AUTHOR Auteur
+CONTRIBUTORS Autres contributeurs
+LICENSE licence
+GIT_REPOSITORY dépôt git
+IF_YOU_WANT Si vous le souhaitez vous pouvez
+DISABLE_HELP désactiver l'aide
+DONATE Vous pouvez soutenir le développement de ce module par un don en Ğ1
\ No newline at end of file
diff --git a/lg/blockCount_en.txt b/lg/blockCount_en.txt
index fef7489111f66bba719ebcb5e5fb4a6c9e08ac28..0b4c69051b82ef71af69167872ea971d21f4f437 100755
--- a/lg/blockCount_en.txt
+++ b/lg/blockCount_en.txt
@@ -1 +1,13 @@
-SUBMIT_BUTTON submit
\ No newline at end of file
+SUBMIT_BUTTON submit
+WRITTEN_BLOCKS Written blocks
+BLOCKCHAIN blockchain
+SINCE_BECOME_MEMBER since become member
+MEAN_NONCE Mean nonce
+RANGE members have written blocks in the range
+BEGIN Begin
+END End
+NB_BLOCKS Number of written Blocks
+PERCENT_OF_WRITTEN_BLOCKS Percent of written Blocks
+DETAIL_BY_NODE detail by node
+SIGNIFICANT_LIMIT significant limit
+PERCENT_OF_BLOCKS % of blocks
\ No newline at end of file
diff --git a/lg/blockCount_fr.txt b/lg/blockCount_fr.txt
index 5ed9c4264d6b35bc0503f19338397fdb00f4ae95..1f5aaef14b425ad20c141a6ee001a5f6c0ff3bf3 100755
--- a/lg/blockCount_fr.txt
+++ b/lg/blockCount_fr.txt
@@ -1 +1,13 @@
-SUBMIT_BUTTON recharger
\ No newline at end of file
+SUBMIT_BUTTON recharger
+WRITTEN_BLOCKS blocs écrits
+BLOCKCHAIN blockchain
+SINCE_BECOME_MEMBER par chaque membre depuis qu'il est devenu membre
+MEAN_NONCE Nonce moyen
+RANGE membres ayant écrit des blocs sur la période
+BEGIN Début
+END Fin
+NB_BLOCKS Nombre de blocs écrits
+PERCENT_OF_WRITTEN_BLOCKS % de blocs écrits
+DETAIL_BY_NODE detail par noeud
+SIGNIFICANT_LIMIT noeud significatif à partir de
+PERCENT_OF_BLOCKS % de blocs
\ No newline at end of file
diff --git a/lg/gaussianWotQuality_en.txt b/lg/gaussianWotQuality_en.txt
new file mode 100644
index 0000000000000000000000000000000000000000..d006671f1a47aaad43a3a5c1eb82d4c7d9a06c12
--- /dev/null
+++ b/lg/gaussianWotQuality_en.txt
@@ -0,0 +1,7 @@
+SUBMIT_BUTTON submit
+DISTRIBUTION_QUALITY gaussian distribution of quality members
+IF_NO_SENTRIES If the concept of referring members didn't exist
+NEXT_YN Feign the following Y[n] landing
+QUALITY quality
+PERCENT_REACHED % of referring members reached
+NB_REACHED number of referring members reached
\ No newline at end of file
diff --git a/lg/gaussianWotQuality_fr.txt b/lg/gaussianWotQuality_fr.txt
new file mode 100644
index 0000000000000000000000000000000000000000..ef3af141bffe963987ace30a05b6ba7dd49c93ba
--- /dev/null
+++ b/lg/gaussianWotQuality_fr.txt
@@ -0,0 +1,7 @@
+SUBMIT_BUTTON recharger
+DISTRIBUTION_QUALITY distribution gaussienne de la qualité des membres
+IF_NO_SENTRIES si le concept de membre référent n'existait pas
+NEXT_YN Simuler le palier Y[n] suivant
+QUALITY qualité
+PERCENT_REACHED % de nombres référents atteints
+NB_REACHED nombre de membres référents atteints
\ No newline at end of file
diff --git a/lg/membersCount_en.txt b/lg/membersCount_en.txt
index ffe695c55960acfcf91692439409a16e363e4433..6284013e0b9f5a944c4b46b12bedf59ca636ca60 100755
--- a/lg/membersCount_en.txt
+++ b/lg/membersCount_en.txt
@@ -17,4 +17,7 @@ Afficher l'évolution de la difficulté commune du réseau (preuve de travail)
 MEMBERS_COUNT members
 SENTRIES_COUNT referring* members
 ISSUERS_COUNT Members co-writers blockchain
-POW_MIN Common difficulty network (proof of work)
\ No newline at end of file
+POW_MIN Common difficulty network (proof of work)
+MAX max
+POINTS points
+REGULATE_BY_ADAPTING regulate by adapting
\ No newline at end of file
diff --git a/lg/membersCount_fr.txt b/lg/membersCount_fr.txt
index 1c0a036c1e69c5327cfaf806c7243f2326cf46e1..5605b8e8a30a4d4cfa02d0f7f468920a6dce714f 100755
--- a/lg/membersCount_fr.txt
+++ b/lg/membersCount_fr.txt
@@ -16,4 +16,7 @@ SHOW_POW_MIN Afficher l'évolution de la difficulté commune du réseau (preuve
 MEMBERS_COUNT Membres
 SENTRIES_COUNT Membres référents*
 ISSUERS_COUNT Membres co-écrivains de la blockchain Ğ1
-POW_MIN Difficulté commune du réseau (preuve de travail)
\ No newline at end of file
+POW_MIN Difficulté commune du réseau (preuve de travail)
+MAX max
+POINTS points
+REGULATE_BY_ADAPTING réguler en adaptant
\ No newline at end of file
diff --git a/lg/members_en.txt b/lg/members_en.txt
index b29593eff33df15a945d8300e7be69bc91a3bcc6..84d2f38affce5880c8eaf082d95872f130c96fc6 100755
--- a/lg/members_en.txt
+++ b/lg/members_en.txt
@@ -30,7 +30,7 @@ PROPORTION_OF_EXIST_PATH Percent of pairs directed for which there is a path of
 MEAN_LENGTH_PATH mean length shortest path
 WOT_TENSION_FACTOR Wot tension factor*
 DATA_AT Data at
-meanMembersReachedByMembersInSingleExtCert Mean members/sentries reached in single member/sentry certification
+meanMembersReachedByMembers Mean members/sentries reached in single member/sentry certification
 SENTRIES_REACHED sentries reached
 MEMBERS_REACHED members reached
 SENTRY_CERT sentry certification
@@ -40,6 +40,8 @@ PROPORTION_MEMBERS_WITH_QUALITY_UPPER_1 Proportion of members with an upper qual
 CURRENT_BLOCKCHAIN_TIME Current blockchain time
 TABLE_TITLE Members that will expire in less than
 DAYS days
+OF_WHICH of which
+ARE_REFERRING_MEMBERS are referrings
 COL_UID uid
 COL_IDTY_WRITTEN_TIME identity written time
 COL_LAST_RENEWAL last renewal
@@ -60,5 +62,9 @@ EMITTED emitted
 WRITTEN written
 INVALID_BLOCKSTAMP invalid blockstamp
 CERT_AVAILABLE available
-OVERALL Overall
+MEMBERS members
+NEXT_YN Feign the following Y[n] landing
+MEMBER_FILTER search a member
+EXPIRE_TIME expiration datetime
+RANDOM_LIST Draw lots
 MEMBERS members
\ No newline at end of file
diff --git a/lg/members_fr.txt b/lg/members_fr.txt
index d84826be44e77c190401262569a633082aa0a35a..5a13228d6573952715dd1a83e33b72894b36d739 100755
--- a/lg/members_fr.txt
+++ b/lg/members_fr.txt
@@ -30,7 +30,7 @@ PROPORTION_OF_EXIST_PATH Proportion de couples orientés pour lesquels il existe
 MEAN_LENGTH_PATH Longueur moyenne d'un plus court chemin
 WOT_TENSION_FACTOR Facteur de tension de la toile*
 DATA_AT Données au
-meanMembersReachedByMembersInSingleExtCert Taux moyen de membres joiniables via une seule certification
+meanMembersReachedByMembers Taux moyen de membres joiniables via une seule certification
 MEMBER_CERT certification d'un membre
 MEMBERS_REACHED membres joiniables
 SENTRY_CERT certification d'un membre référent
@@ -40,6 +40,8 @@ PROPORTION_MEMBERS_WITH_QUALITY_UPPER_1 Proportion de membre avec une qualité >
 CURRENT_BLOCKCHAIN_TIME Temps Blockchain actuel
 TABLE_TITLE Membres dont le statut de membre va expirer dans moins de
 DAYS jours
+OF_WHICH dont
+ARE_REFERRING_MEMBERS sont référents
 COL_UID uid
 COL_IDTY_WRITTEN_TIME obtention statut membre
 COL_LAST_RENEWAL dernier renouvellement
@@ -60,5 +62,9 @@ EMITTED émise
 WRITTEN écrite
 INVALID_BLOCKSTAMP blockstamp incorrect
 CERT_AVAILABLE disponible
-OVERALL Total
+MEMBERS membres
+NEXT_YN Simuler le palier Y[n] suivant
+MEMBER_FILTER rechercher un membre
+EXPIRE_TIME date et heure d'expiration
+RANDOM_LIST Tirer au sort
 MEMBERS membres
\ No newline at end of file
diff --git a/lg/menu_en.txt b/lg/menu_en.txt
index 876b5a55881ff15b122f7f1e0ef1710db6858c96..4adc1d3601c310b39c37e4e253a3ef2101b36310 100755
--- a/lg/menu_en.txt
+++ b/lg/menu_en.txt
@@ -2,7 +2,8 @@ LG en
 WILL_MEMBERS willMembers
 MEMBERS members
 MEMBERS_COUNT membersCount
+WOTEX wotex
+GAUSSIAN_WOT_QUALITY gaussianWotQuality
 BLOCK_COUNT blockCount
 MONETARY_MASS monetaryMass
-WOTEX wotex
 ABOUT about
\ No newline at end of file
diff --git a/lg/menu_fr.txt b/lg/menu_fr.txt
index 244a325cd9fae537084711876ec28f395504c64e..f0ca603d23741e016034ae22f3c257d825ec8e7d 100755
--- a/lg/menu_fr.txt
+++ b/lg/menu_fr.txt
@@ -2,7 +2,8 @@ LG fr
 WILL_MEMBERS futurs membres
 MEMBERS listes des membres
 MEMBERS_COUNT nombre de membres
+WOTEX wotex
+GAUSSIAN_WOT_QUALITY qualité toile
 BLOCK_COUNT nombre de blocs
 MONETARY_MASS masse monétaire
-WOTEX wotex
 ABOUT a propos
\ No newline at end of file
diff --git a/lg/monetaryMass_en.txt b/lg/monetaryMass_en.txt
index fef7489111f66bba719ebcb5e5fb4a6c9e08ac28..090024dbb3d7f63611e7d4c51e6c406946c2f957 100755
--- a/lg/monetaryMass_en.txt
+++ b/lg/monetaryMass_en.txt
@@ -1 +1,22 @@
-SUBMIT_BUTTON submit
\ No newline at end of file
+SUBMIT_BUTTON submit
+DESC1 The currency will be full when the money supply by member will be worth
+UD UD
+FULL_CURRENCY_FORMULA because 1/c * dtReeval/dt =
+CURRENTLY Currently
+AND_WE_HAVE and we have
+DESC2 members. Thus in full currency we would have a total money supply of
+MEMBER member
+BEGIN Begin
+END End
+QUANTITATIVE quantitative
+RELATIVE relative
+PERCENT_OF_FULL_CURRENCY percent of full currency
+MASS_BY_MEMBERS mass by members
+TOTAL_MASS total mass
+LOGARITHMIC logarithmic
+LINEAR linear
+MONETARY_MASS monetaryMass
+IN_PERCENT_OF_FULL_CURRENCY in % of full currency
+PERCENT_VARIATION_MONETARY_MASS % of variation of the monetary mass
+BY_MEMBERS by members
+IN_THE_RANGE in the range
\ No newline at end of file
diff --git a/lg/monetaryMass_fr.txt b/lg/monetaryMass_fr.txt
index 5ed9c4264d6b35bc0503f19338397fdb00f4ae95..2e1331f1aded6c27c6255b3992bdb2f6a5734a26 100755
--- a/lg/monetaryMass_fr.txt
+++ b/lg/monetaryMass_fr.txt
@@ -1 +1,23 @@
-SUBMIT_BUTTON recharger
\ No newline at end of file
+SUBMIT_BUTTON recharger
+DESC1 La monnaie sera pleine lorsque la masse monétaire par membre atteindra
+The currency will be full when the money supply by member will be worth
+UD DU
+FULL_CURRENCY_FORMULA car 1/c * dtReeval/dt
+CURRENTLY Actuellement
+AND_WE_HAVE et nous sommes
+DESC2 membres. Donc si la monnaie était pleine nous aurions une masse totale de
+MEMBER membre
+BEGIN Début
+END Fin
+QUANTITATIVE quantitatif
+RELATIVE relatif
+PERCENT_OF_FULL_CURRENCY pourcentage de monnaie pleine
+MASS_BY_MEMBERS masse par membre
+TOTAL_MASS masse totale
+LOGARITHMIC logarithmique
+LINEAR linéaire
+MONETARY_MASS masse monetaire
+IN_PERCENT_OF_FULL_CURRENCY en % de monnaie pleine
+PERCENT_VARIATION_MONETARY_MASS % de variation de la masse monétaire
+BY_MEMBER par membre
+IN_THE_RANGE dans la période
\ No newline at end of file
diff --git a/lg/willMembers_en.txt b/lg/willMembers_en.txt
index 47d0f60971b02dd7ffdae69dddcd133c1911a52f..d66105996bdac8ba75fbb9acb8c2ed85c6b8ab34 100755
--- a/lg/willMembers_en.txt
+++ b/lg/willMembers_en.txt
@@ -30,25 +30,28 @@ MEAN_SENTRIES_REACHED mean sentries reached
 MEAN_QUALITY_CERTS Quality averages of the set of certifications
 MEAN_MEMBERS_REACHED mean members reached
 IDENTITY Identity
-MEMBERSHIP_CASE membership case
+MEMBERSHIP_CASE_FULL complete case ?
+DISTANCE_RULE distance
 COL_4 List of received certifications (recent -> old)
 COL_4_WITH_AVAIlABILITY_SORT List of received certifications (by availability time)
+PUBKEY_PART pubkey (first 16 characters)
+EMITTE emitted
 EMITTED_ON emitted on
-AT_BLOCK at block
-EXPIRE_ON expire on 
+EXPIRE_TIME expiration datetime
 KO KO
 OK OK
-MEMBERSHIP_ASKED Membership asked
+MEMBERSHIP_NOT_ASKED Membership not asked
 YES yes
 NO no
-QUALITY_CERTIFIERS quality certifiers
+QUALITY_CERTIFIERS package quality
 DISTANCE Distance
-CERTIFIERS_COUNT certifiers count
+CERTS certifications
 QUALITY quality
 SIG_PERIOD_OK available
 IDTY_REVOKED [identity revoked]
 INVALID_BLOCKSTAMP invalid blockstamp
 LAST_TR1  total
 LAST_TR2  identities
-LICENSE licence GPL-3.0
-SRC source code
+ON_WOTEX on wotex
+IDTY_FILTER filter identities
+MISS it's missing
diff --git a/lg/willMembers_fr.txt b/lg/willMembers_fr.txt
index 589ccb14926c58e66b690a8386e429ddb250cbac..09d3fbe18bbd51bed1b7be110cb9bad3d015460d 100755
--- a/lg/willMembers_fr.txt
+++ b/lg/willMembers_fr.txt
@@ -30,25 +30,28 @@ MEAN_SENTRIES_REACHED Taux moyen de membres référents joiniables
 MEAN_QUALITY_CERTS Qualité moyenne par groupe de certifications reçues
 MEAN_MEMBERS_REACHED Taux moyen de membres joiniables
 IDENTITY Identité
-MEMBERSHIP_CASE dossier d'adhésion
+MEMBERSHIP_CASE_FULL dossier complet ?
+DISTANCE_RULE distance
 COL_4 liste des certifications reçues (récentes -> anciennes)
 COL_4_WITH_AVAIlABILITY_SORT liste des certifications reçues (par date de disponibilité)
+PUBKEY_PART clé publique (16 premiers caractères)
+EMITTED émise
 EMITTED_ON émise le
-AT_BLOCK au bloc
-EXPIRE_ON expire le
+EXPIRE_TIME date et heure d'expiration
 KO KO
 OK OK
-MEMBERSHIP_ASKED Adhésion demandée
+MEMBERSHIP_NOT_ASKED Adhésion non demandée
 YES oui
 NO non
-QUALITY_CERTIFIERS qualité certificateurs
+QUALITY_CERTIFIERS qualité dossier
 DISTANCE Distance
-CERTIFIERS_COUNT Nombre de certificateurs
+CERTS certifications
 QUALITY qualité
 SIG_PERIOD_OK disponible
 IDTY_REVOKED [identité revoquée]
 INVALID_BLOCKSTAMP blockstamp incorrect
 LAST_TR1  total
 LAST_TR2  identités
-LICENSE licence GPL-3.0
-SRC code source
+ON_WOTEX sur wotex
+IDTY_FILTER filtrer les identités
+MISS il manque
diff --git a/lib/constants.js b/lib/constants.js
index d97be3bd6a649d7076c3831954cbd5d44d91937e..557f407e58822165deba4714cc1dc614974fbe9f 100755
--- a/lib/constants.js
+++ b/lib/constants.js
@@ -1,10 +1,18 @@
 "use strict";
 
 module.exports = {
-  USE_WOTB6: true,
+  DEFAULT_LANGUAGE: "fr",
   MIN_WILLMEMBERS_UPDATE_FREQ: 180,
   MIN_MEMBERS_UPDATE_FREQ: 180,
 	STEP_COUNT_MIN: 4,
 	STEP_COUNT_MAX: 150,
-	MIN_CACHE_UPDATE_FREQ: 150 // 2 min 30 (150 sec)
+  MIN_CACHE_UPDATE_FREQ: 150, // 2 min 30 (150 sec)
+  MIN_WOT_QUALITY_CACHE_UPDATE_FREQ: 300,
+  QUALITY_CACHE_ACTION : {
+    GET_QUALITY: 0,
+    GET_MEANS: 1,
+    INIT: 2,
+    GET_SENTRIES_COUNT: 3,
+    GET_D_SEN: 3
+  }
 };
\ No newline at end of file
diff --git a/lib/main.js b/lib/main.js
index 064c8bba5ab7b3eb3addff154cdc2f037d473ea9..0877d4da2b411e1f4e10b970921ebf724d7be61e 100755
--- a/lib/main.js
+++ b/lib/main.js
@@ -1,14 +1,28 @@
 "use strict";
 
 const co = require('co');
+const os = require('os');
+const fs = require('fs');
 
 const webserver = require(__dirname + '/webserver.js');
-//const duniter = require(__dirname + '/duniter.js');
+const timestampToDatetime = require(__dirname + '/timestampToDatetime.js');
 
 /****************************
  * Main algorithm
  */
 module.exports = (duniterServer, host, port, appParente, program) => co(function *() {
+
+  // Get local timezone offset
+  var x = new Date();
+  var offset = -x.getTimezoneOffset();
+  //timestampToDatetime(1000000, true, offset);
+
+  // Get monitDatasPath
+  const mdb = program.mdb || "duniter_default";
+  const monitDatasPath = os.homedir() + "/.config/duniter/" + mdb + "/currency-monit/";
+
+  // Create monitDatasPath
+  if (!fs.existsSync(monitDatasPath)) { fs.mkdirSync(monitDatasPath) }
   
   // Define cache
   var cache = {
@@ -34,7 +48,7 @@ module.exports = (duniterServer, host, port, appParente, program) => co(function
   console.log("module currency-monit started");
   
   // Specialized node's UI
-  let httpServer = webserver(host, port, appParente, duniterServer, cache);
+  let httpServer = webserver(host, port, appParente, duniterServer, monitDatasPath, offset, cache);
   yield httpServer.openConnection();
 
 })
diff --git a/lib/randomInt.js b/lib/randomInt.js
new file mode 100644
index 0000000000000000000000000000000000000000..62d607c3d8c926bed68868dcdb8a7a43d14668d8
--- /dev/null
+++ b/lib/randomInt.js
@@ -0,0 +1,3 @@
+module.exports = function randomInt (low, high) {
+    return Math.floor(Math.random() * (high - low) + low);
+}
diff --git a/lib/timestampToDatetime.js b/lib/timestampToDatetime.js
index b44f46505f749d496837239fa1355785bd00cfbb..5b86854aef88cc4a7f5642aed7dab831f7068fd3 100755
--- a/lib/timestampToDatetime.js
+++ b/lib/timestampToDatetime.js
@@ -1,4 +1,14 @@
-module.exports = function timestampToDatetime(timestamp, onlyDate = false) {
+// cache offset
+var offset = 0;
+
+module.exports = function timestampToDatetime(timestamp, onlyDate = false, offset_ = 0) {
+  if (offset_ != 0) {
+    offset = offset_;
+  }
+
+  // Apply offset
+  timestamp += offset*60; // offset is in minutes
+
   // Convertir le timestamp en datetime
   let tmptimestampExpireCertif = new Date(timestamp*1000);//tmpQueryGetTimeWrittenCert[0].medianTime)*1000);
   let tmptimestampExpireCertifDay = tmptimestampExpireCertif.getDate();
diff --git a/lib/updateCache.js b/lib/updateCache.js
index b57f720ce503624c69f674efa778011b2d16ee54..0f2fd076d5dd81a9f7de3d1a8ef9dfa5de6aa897 100755
--- a/lib/updateCache.js
+++ b/lib/updateCache.js
@@ -38,68 +38,25 @@ module.exports = (req, res, next) => co(function *() {
       let checkBlock = yield duniterServer.dal.peerDAL.query('SELECT `hash` FROM block WHERE `fork`=0 AND `number`='+(cache.blockchain[cache.blockchain.length-1].number)+' LIMIT 1 ');
 			if (cache.blockchain.length > 0 && cache.blockchain[cache.blockchain.length-1].hash != checkBlock[0].hash && upgradeCache)
       {
-			/*// unstack loop
-			while (cache.blockchain.length > 0  && cache.blockchain[cache.blockchain.length-1].hash != checkBlock[0].hash)
-			{
-				// unstack cache.blockchain
-				cache.blockchain.pop();
-				
-				// unstack block
-				checkBlock = yield duniterServer.dal.peerDAL.query('SELECT `hash` FROM block WHERE `fork`=0 AND `number`='+(cache.blockchain.length-1)+' LIMIT 1 ');
+				// reinitialize cache
+				cache.lastUptime = 0;
+				cache.lockMembersCount = false;
+				cache.beginBlock = null;
+				cache.currentBlockNumber = 0;
+				cache.currentBlockTime = 0;
+				cache.currentSentries = 0;
+				cache.endBlock = null;
+				cache.step = null;
+				cache.stepUnit = null;
+				cache.stepTime = null;
+				cache.onlyDate = null;
+				cache.Yn = 0;
+				cache.pubkeys = new Array();
+				cache.pub_index = new Array();
+				cache.blockchain = new Array();
 				
-				console.log("unstack block #%s", cache.blockchain.length-1);
-			}
-			
-			let cacheTime = 0;
-			if (cache.blockchain.length > 0 )
-			{
-				cacheTime = cache.blockchain[cache.blockchain.length-1].medianTime;
-			}
-			else
-			{*/
-	  // reinitialize cache
-	  cache.lastUptime = 0;
-		cache.lockMembersCount = false;
-		cache.beginBlock = null;
-		cache.currentBlockNumber = 0;
-		cache.currentBlockTime = 0;
-		cache.currentSentries = 0;
-		cache.endBlock = null;
-		cache.step = null;
-		cache.stepUnit = null;
-		cache.stepTime = null;
-		cache.onlyDate = null;
-		cache.Yn = 0;
-		cache.pubkeys = new Array();
-		cache.pub_index = new Array();
-		cache.blockchain = new Array();
-	  
-	  // reinitialize bdd
-	  reinitBdd = true;
-	/*}
-	
-	// unstak pubkeys joins during the fork (no-member pubkeys has considered join when then received currency for the first time)
-	while (cache.pubkeys.length > 0 && cache.pubkeys[cache.pubkeys.length-1].join >= cache.blockchain.length) { cache.pubkeys.pop(); cache.pub_index.pop(); }
-
-	// unstak transactions and certifications written during the fork
-	for (let m=0;cache.pubkeys.length;m++)
-	{
-	  // unstak inputs
-	  while (cache.pubkeys[m].inputsTime.length > 0 && cache.pubkeys[m].inputsTime[cache.pubkeys[m].inputsTime.length-1] > cacheTime)
-	  {
-	      cache.pubkeys[m].inputsTime.pop();
-	      cache.pubkeys[m].inputsAmount.pop();
-	  }
-	  // unstak outputs
-	  while (cache.pubkeys[m].outputsTime.length > 0 && cache.pubkeys[m].outputsTime[cache.pubkeys[m].outputsTime.length-1] > cacheTime)
-	  {
-	      cache.pubkeys[m].outputsTime.pop();
-	      cache.pubkeys[m].outputsAmount.pop();
-	  }
-	  // unstak certs
-	  while (cache.pubkeys[m].writtenCerts.length > 0 && cache.pubkeys[m].writtenCerts[cache.pubkeys[m].writtenCerts.length-1] > cache.blockchain.length) { cache.pubkeys[m].writtenCerts.pop(); }
-	  while (cache.pubkeys[m].receivedCerts.length > 0 && cache.pubkeys[m].receivedCerts[cache.pubkeys[m].receivedCerts.length-1] > cache.blockchain.length) { cache.pubkeys[m].receivedCerts.pop(); }
-	}*/
+				// reinitialize bdd
+				reinitBdd = true;
       }
     }
     
@@ -113,12 +70,12 @@ module.exports = (req, res, next) => co(function *() {
     {
       switch (req.query.stepUnit)
       {
-	  case "blocks": unitTime = 3600; cache.onlyDate = false; cache.stepUnit = "blocks"; break;
-	  case "hours": unitTime = 3600; cache.onlyDate = false; cache.stepUnit = "hours"; break;
-	  case "days": unitTime = 86400; cache.onlyDate = true; cache.stepUnit = "days"; break;
-	  case "weeks": unitTime = 604800; cache.onlyDate = true; cache.stepUnit = "weeks"; break;
-	  case "months": unitTime = 18144000; cache.onlyDate = true; cache.stepUnit = "months"; break;
-	  case "years": unitTime = 31557600; cache.onlyDate = true; cache.stepUnit = "years"; break;
+				case "blocks": unitTime = 3600; cache.onlyDate = false; cache.stepUnit = "blocks"; break;
+				case "hours": unitTime = 3600; cache.onlyDate = false; cache.stepUnit = "hours"; break;
+				case "days": unitTime = 86400; cache.onlyDate = true; cache.stepUnit = "days"; break;
+				case "weeks": unitTime = 604800; cache.onlyDate = true; cache.stepUnit = "weeks"; break;
+				case "months": unitTime = 18144000; cache.onlyDate = true; cache.stepUnit = "months"; break;
+				case "years": unitTime = 31557600; cache.onlyDate = true; cache.stepUnit = "years"; break;
       }
     }
     // Default values
@@ -140,7 +97,7 @@ module.exports = (req, res, next) => co(function *() {
       {
 				cache.endBlock = yield duniterServer.dal.peerDAL.query('SELECT `hash`,`medianTime`,`number`,`membersCount` FROM block WHERE `fork`=0 ORDER BY `medianTime` DESC LIMIT 1 ');
       }
-    }
+		}
     
     // fix begin value
     if ( typeof(req.query.begin) == 'undefined' || req.query.begin < 0 )
@@ -150,21 +107,43 @@ module.exports = (req, res, next) => co(function *() {
 			let beginTime = cache.endBlock[0].medianTime-(parseInt(cache.step)*unitTime*constants.STEP_COUNT_MIN);
       cache.beginBlock =  yield duniterServer.dal.peerDAL.query('SELECT `medianTime`,`number` FROM block WHERE `fork`=0 AND `medianTime` >= \''+beginTime+'\' ORDER BY `medianTime` ASC LIMIT 1 ');
     }
-    else { cache.beginBlock = yield duniterServer.dal.peerDAL.query('SELECT `medianTime`,`number` FROM block WHERE `fork`=0 AND `number`='+req.query.begin+' LIMIT 1 '); }
-    
-    // Apply STEP_COUNT_MAX and calculate stepTime
-    if ( Math.ceil((cache.endBlock[0].medianTime-cache.beginBlock[0].medianTime)/(cache.step*unitTime)) > constants.STEP_COUNT_MAX  )
+		else { cache.beginBlock = yield duniterServer.dal.peerDAL.query('SELECT `medianTime`,`number` FROM block WHERE `fork`=0 AND `number`='+req.query.begin+' LIMIT 1 '); }
+
+		// Define nbMaxPoints and adaptMaxPoints
+		if ( typeof(req.query.nbMaxPoints) != 'undefined' && req.query.nbMaxPoints > 0 ) {
+			cache.nbMaxPoints = req.query.nbMaxPoints;
+		} else {
+			cache.nbMaxPoints = constants.STEP_COUNT_MAX;
+		}
+		if ( typeof(req.query.adaptMaxPoints) != 'undefined' && (req.query.adaptMaxPoints == "step" || req.query.adaptMaxPoints == "end")) {
+			cache.adaptMaxPoints = req.query.adaptMaxPoints;
+		} else {
+			cache.adaptMaxPoints = "begin";
+		}
+		
+		// Apply nbMaxPoints and adaptMaxPoints
+		if (cache.adaptMaxPoints == "begin")
 		{
+			if ( Math.ceil((cache.endBlock[0].medianTime-cache.beginBlock[0].medianTime)/(cache.step*unitTime)) > cache.nbMaxPoints  )
+			{
+				let newBeginTime = cache.endBlock[0].medianTime-cache.step*cache.nbMaxPoints*unitTime;
+				cache.beginBlock =  yield duniterServer.dal.peerDAL.query('SELECT `medianTime`,`number` FROM block WHERE `fork`=0 AND `medianTime` >= \''+newBeginTime+'\' ORDER BY `medianTime` ASC LIMIT 1 ');
+			}
+		} else if (cache.adaptMaxPoints == "step") {
 			cache.step = Math.ceil((cache.endBlock[0].medianTime-cache.beginBlock[0].medianTime)/(constants.STEP_COUNT_MAX*unitTime));
+		} else {
+			let newEndTime = cache.beginBlock[0].medianTime+cache.step*cache.nbMaxPoints*unitTime;
+			cache.endBlock =  yield duniterServer.dal.peerDAL.query('SELECT `medianTime`,`number` FROM block WHERE `fork`=0 AND `medianTime` <= \''+newEndTime+'\' ORDER BY `medianTime` DESC LIMIT 1 ');
 		}
+    
+		// Calculate stepTime
     cache.stepTime = parseInt(cache.step)*unitTime;
 
     // if new blocks and MIN_CACHE_UPDATE_FREQ pass, update cache
 		if ( parseInt(cache.endBlock[0].number) >= cache.currentBlockNumber && Math.floor(Date.now() / 1000) > (cache.lastUptime + constants.MIN_CACHE_UPDATE_FREQ))
     {
       // let previousCacheTime = (cache.blockchain.length > 0) ? cache.blockchain[cache.blockchain.length-1].medianTime:0;
-      var newBlocks = yield duniterServer.dal.peerDAL.query(
-	'SELECT `hash`,`membersCount`,`medianTime`,`number`,`certifications`,`joiners`,`actives`,`revoked` FROM block WHERE `fork`=0 AND `medianTime` > '+cache.currentBlockTime+' AND `medianTime` <= '+cache.endBlock[0].medianTime+' ORDER BY `medianTime` ASC');
+      var newBlocks = yield duniterServer.dal.peerDAL.query('SELECT `hash`,`membersCount`,`medianTime`,`number`,`certifications`,`joiners`,`actives`,`revoked` FROM block WHERE `fork`=0 AND `medianTime` > '+cache.currentBlockTime+' AND `medianTime` <= '+cache.endBlock[0].medianTime+' ORDER BY `medianTime` ASC');
       
       // Initialise newJoiners
       let newJoiners = new Array();
@@ -206,162 +185,11 @@ module.exports = (req, res, next) => co(function *() {
 				{
 					for (let m=0;m<cache.pubkeys.length;m++)
 					{
-						if (cache.pubkeys[m].writtenCerts.length >= cache.Yn && cache.pubkeys[m].receivedCerts.length >= minReceivedCerts && cache.pubkeys[m].writtenCerts.length < newYn && cache.pubkeys[m].receivedCerts.length < newYn) { newSentries -= 1; }
+						if (cache.pubkeys[m].writtenCerts.length >= cache.Yn && cache.pubkeys[m].receivedCerts.length >= minReceivedCerts && (cache.pubkeys[m].writtenCerts.length < newYn || cache.pubkeys[m].receivedCerts.length < newYn)) { newSentries -= 1; }
 					}
 					minReceivedCerts = (newYn<conf.sigQty) ? conf.sigQty:newYn; // recalculate minReceivedCerts
 				}
 				cache.Yn = newYn;
-	
-	/*
-	// add dividend to members balance
-	if (parseInt(newBlocks[b].dividend) > 0)
-	{
-	  for (let k=0;k<cache.pubkeys.length;k++)
-	  {
-	    if ( cache.pubkeys[k].receivedCerts != null && cache.pubkeys[k].receivedCerts.length >= sigQty)
-	    { cache.pubkeys[k].balance += parseInt(newBlocks[b].dividend); }
-	  }
-	}
-	
-	// parse and push transactions
-	transactions = JSON.parse(newBlocks[b].transactions);
-	for (let t=0;t<transactions.length;t++)
-	{
-	  // Calculate inputsSum
-	  let inputsSum = 0;
-	  for (let i=0;i<transactions[t].inputs.length;i++)
-	  {
-	    //console.log("(b, t, i) = %s, %s, %s", b, t, i);
-	    let input = transactions[t].inputs[i].split(":");
-	    inputsSum += (parseInt(input[0])*Math.pow(10, parseInt(input[1])));
-	  }
-	  
-	  // get issuer
-	  let issuer = transactions[t].issuers[0];
-	  
-	  // Push issuer inputs
-	  if (typeof(cache.pub_index[issuer]) == 'undefined')
-	  {
-	    cache.pubkeys.push({
-		join: cache.blockchain.length+1,
-		pub: issuer,
-		balance: inputsSum,
-		balanceWithOthers: new Array(),
-		pubkeyBalanceWithOthers: new Array(),
-		inputsTime: new Array(parseInt(newBlocks[b].medianTime)),
-		inputsAmount: new Array(inputsSum),
-		outputsTime: new Array(),
-		outputsAmount: new Array(),
-		writtenCerts: null, // tab of blocks number (only for members pubkeys)
-		receivedCerts: null // tab of blocks number (only for members pubkeys)
-	      });
-	      cache.pub_index[issuer] = cache.pubkeys.length-1;
-	      //console.log("w : issuer first : cache.pub_index[%s] = %s", issuer, cache.pub_index[issuer]); // DEBUG
-	  }
-	  else
-	  {
-	    let pubkeyId = cache.pub_index[issuer];
-	    if (cache.pubkeys[pubkeyId].inputsTime[cache.pubkeys[pubkeyId].inputsTime.length-1] == parseInt(newBlocks[b].medianTime))
-	    {
-	      cache.pubkeys[pubkeyId].inputsAmount[cache.pubkeys[pubkeyId].inputsAmount.length-1] += inputsSum;
-	      cache.pubkeys[pubkeyId].balance -= inputsSum;
-	    }
-	    else
-	    {
-	      //console.log("cache.pubkeys[%s] = %s", pubkeyId, cache.pubkeys[pubkeyId].pub); // DEBUG
-	      cache.pubkeys[pubkeyId].inputsTime.push(parseInt(newBlocks[b].medianTime));
-	      cache.pubkeys[pubkeyId].inputsAmount.push(inputsSum);
-	      cache.pubkeys[pubkeyId].balance -= inputsSum;
-	    }
-	  }
-	    
-	  // split and push outputs 
-	  for (let o=0;o<transactions[t].outputs.length;o++)
-	  {
-	    let output = transactions[t].outputs[o].split(":");
-	    let ouputAmout = parseInt(output[0])*Math.pow(10, parseInt(output[1]));
-	    
-	    // get receiver pubkey
-	    let pubkey = output[2].substr(4, output[2].length-5);
-	    
-	    if (typeof(cache.pub_index[pubkey]) == 'undefined')
-	    {
-	      cache.pubkeys.push({
-		join: cache.blockchain.length+1,
-		pub: pubkey,
-		balance: ouputAmout,
-		balanceWithOthers: new Array(),
-		pubkeyBalanceWithOthers: new Array(),
-		inputsTime: new Array(),
-		inputsAmount: new Array(),
-		outputsTime: new Array(),
-		outputsAmount: new Array(),
-		writtenCerts: null, // tab of blocks number (only for members pubkeys)
-		receivedCerts: null // tab of blocks number (only for members pubkeys)
-	      });
-	      cache.pub_index[pubkey] = cache.pubkeys.length-1;
-	      cache.pubkeys[cache.pubkeys.length-1].outputsTime.push(parseInt(newBlocks[b].medianTime));
-	      cache.pubkeys[cache.pubkeys.length-1].outputsAmount.push(ouputAmout);
-	    }
-	    else
-	    {
-	      let pubkeyId = cache.pub_index[pubkey];
-	      cache.pubkeys[pubkeyId].balance += ouputAmout;
-	      if (pubkey == issuer)
-	      {
-		cache.pubkeys[pubkeyId].inputsAmount[cache.pubkeys[pubkeyId].inputsAmount.length-1] -= ouputAmout;
-		ouputAmout = 0;
-	      }
-	      else
-	      {
-		if (cache.pubkeys[pubkeyId].outputsTime[cache.pubkeys[pubkeyId].outputsTime.length-1] == parseInt(newBlocks[b].medianTime))
-		{
-		  cache.pubkeys[pubkeyId].outputsAmount[cache.pubkeys[pubkeyId].outputsAmount.length-1] += ouputAmout;
-		}
-		else
-		{
-		  cache.pubkeys[pubkeyId].outputsTime.push(parseInt(newBlocks[b].medianTime));
-		  cache.pubkeys[pubkeyId].outputsAmount.push(ouputAmout);
-		}
-	      }
-	    }
-	    
-	    // Push balanceWithOthers
-	      let pubkeyId = cache.pub_index[pubkey];
-	      if ( typeof(cache.pubkeys[cache.pub_index[issuer]].pubkeyBalanceWithOthers[pubkey]) != 'undefined')
-	      {
-		let idBalanceKey = cache.pubkeys[cache.pub_index[issuer]].pubkeyBalanceWithOthers[pubkey];
-		cache.pubkeys[cache.pub_index[issuer]].balanceWithOthers[idBalanceKey] -= ouputAmout;
-	      }
-	      else if ( typeof(cache.pubkeys[pubkeyId].pubkeyBalanceWithOthers[issuer]) != 'undefined')
-	      {
-		let idBalanceKey = cache.pubkeys[pubkeyId].pubkeyBalanceWithOthers[issuer];
-		cache.pubkeys[pubkeyId].balanceWithOthers[idBalanceKey] += ouputAmout;
-	      }
-	      else
-	      {
-		  cache.pubkeys[pubkeyId].balanceWithOthers.push(ouputAmout);
-		  cache.pubkeys[pubkeyId].pubkeyBalanceWithOthers[issuer] = cache.pubkeys[pubkeyId].balanceWithOthers.length-1;
-	      }
-	    
-	    // If receiver pubkey balance <= 1,00, destroy money
-	    if ( cache.pubkeys[cache.pub_index[pubkey]].balance < 100)
-	    {
-	      cache.destroyAmount += cache.pubkeys[cache.pub_index[pubkey]].balance;
-	      cache.pubkeys[cache.pub_index[pubkey]].outputsAmount[cache.pubkeys[cache.pub_index[pubkey]].outputsAmount.length-1] -= cache.pubkeys[cache.pub_index[pubkey]].balance;
-	      cache.pubkeys[cache.pub_index[pubkey]].balance = 0;
-	    }
-	  }
-	  
-	  // If issuer pubkey balance <= 1,00, destroy money
-	  if ( cache.pubkeys[cache.pub_index[issuer]].balance < 100)
-	  {
-	    cache.destroyAmount += cache.pubkeys[cache.pub_index[issuer]].balance;
-	    cache.pubkeys[cache.pub_index[issuer]].inputsAmount[cache.pubkeys[cache.pub_index[issuer]].inputsAmount.length-1] += cache.pubkeys[cache.pub_index[issuer]].balance;
-	    cache.pubkeys[cache.pub_index[issuer]].balance = 0;
-	  }
-	}
-	*/
 
 				// parse and split revoked
 				revoked = JSON.parse(newBlocks[b].revoked);
@@ -370,32 +198,6 @@ module.exports = (req, res, next) => co(function *() {
 					revoked[r] = revoked[r].split(":");
 					delIdtys.push(revoked[r][0]);
 					let tmpPubIndex = cache.pub_index[revoked[r][0]];
-					/*// Suppr receivers of writtenCerts
-					for (let wc=0;wc<cache.pubkeys[tmpPubIndex].writtenCerts.length;wc++)
-					{
-						let tmpPubIndex2 = cache.pub_index[cache.pubkeys[tmpPubIndex].writtenCerts[wc][1]];
-						for (let wc2=0;wc2<cache.pubkeys[tmpPubIndex2].receivedCerts.length;wc2++)
-						{
-							if ( cache.pubkeys[tmpPubIndex2].receivedCerts[wc2][1] == revoked[r][0] )
-							{
-					cache.pubkeys[tmpPubIndex2].receivedCerts.splice(wc2,1);
-					wc2 = cache.pubkeys[tmpPubIndex2].receivedCerts.length;
-							}
-						}
-					}
-					// Suppr issuers of receivedCerts
-					for (let rc=0;rc<cache.pubkeys[tmpPubIndex].receivedCerts.length;rc++)
-					{
-						let tmpPubIndex2 = cache.pub_index[cache.pubkeys[tmpPubIndex].receivedCerts[rc][1]];
-						for (let rc2=0;rc2<cache.pubkeys[tmpPubIndex2].writtenCerts.length;rc2++)
-						{
-							if ( cache.pubkeys[tmpPubIndex2].writtenCerts[rc2][1] == revoked[r][0] )
-							{
-					cache.pubkeys[tmpPubIndex2].writtenCerts.splice(rc2,1);
-					rc2 = cache.pubkeys[tmpPubIndex2].writtenCerts.length;
-							}
-						}
-					}*/
 					//cache.pubkeys.splice(tmpPubIndex,1);
 				}
 
diff --git a/lib/webserver.js b/lib/webserver.js
index f8dfb79cefa6da0223fb923d7ade2568522f216a..567b5acc4343c27b04e1a06c14f8a3c120aa05a6 100755
--- a/lib/webserver.js
+++ b/lib/webserver.js
@@ -13,7 +13,7 @@ const bodyParser = require('body-parser');
 const routes = require(__dirname + '/../routes');
 const tpl = require(__dirname + '/tplit.js');
 
-module.exports = (host, port, appParente, duniterServer, cache) => {
+module.exports = (host, port, appParente, duniterServer, monitDatasPath, offset, cache) => {
   
   var app = express();
   
@@ -31,13 +31,31 @@ module.exports = (host, port, appParente, duniterServer, cache) => {
   app.set('view engine', 'html') // register the template engine
   
   app.locals.duniterServer = duniterServer
+  app.locals.monitDatasPath = monitDatasPath
   app.locals.currencyName = duniterServer.conf.currency
+  app.locals.offset = offset
   app.locals.cache = cache
   
   app.locals.HTML_HEAD = fs.readFileSync(__dirname + '/../views/HEAD.html', 'utf-8')
   app.locals.HTML_TOR_HEAD = fs.readFileSync(__dirname + '/../views/TOR_HEAD.html', 'utf-8')
   
   app.use( routes )
+
+  /***************************************
+  * CSV des membres calculants
+  ***************************************/
+  app.get('/csvCalculatorsRank', function(req, res) {
+    let files = fs.readdirSync(monitDatasPath + '/calculators_rank/')
+    let maxTimestamp = 0
+    for (let file of files) {
+      let fileTimestamp = parseInt(file.split('_')[2])
+      if (fileTimestamp > maxTimestamp) {
+        maxTimestamp = fileTimestamp
+      }
+    }
+    var file = monitDatasPath + '/calculators_rank/calculators_rank_' + maxTimestamp + '.csv';
+    res.download(file); // Set disposition and send it.
+  });
   
   // Si l'on ne dispose pas d'un serveur web parent, lancer notre propre serveur web
   if ( appParente == null )
diff --git a/package.json b/package.json
index 2e9df9aede7c3bb7ed69a0eb53213b1d6a538d03..79fb8dcd3616c8b259dfcffa90ef6cb460e8fb98 100755
--- a/package.json
+++ b/package.json
@@ -1,29 +1,24 @@
 {
   "name": "duniter-currency-monit",
-  "version": "0.3.7",
+  "version": "0.4.11",
   "main": "index.js",
   "license": "AGPLv3",
   "dependencies": {
-    "body-parser": "1.15.1",
-    "co": "^4.6.0",
-    "express": "4.13.4",
+    "body-parser": "1.17.1",
+    "co": "4.6.0",
+    "express": "4.15.2",
     "fs-extra": "^3.0.1",
     "http": "0.0.0",
-    "morgan": "1.7.0",
-    "node-pre-gyp": "^0.6.34",
+    "morgan": "1.8.1",
+    "node-pre-gyp": "0.6.34",
     "q": "1.5.0",
-    "request": "^2.81.0",
-    "request-promise": "4.2.0",
-    "wotb": "^0.6.2",
+    "request": "2.81.0",
+    "request-promise": "4.2.0"
   },
   "devDependencies": {
-    "duniter": "1.3.14",
-    "duniter-bma": "1.3.x",
-    "duniter-crawler": "1.3.x",
-    "duniter-keypair": "1.3.x",
-    "duniter-prover": "1.3.x"
+    "duniter": "1.6.x"
   },
   "peerDependencies": {
-    "duniter": "1.3.14"
+    "duniter": "1.6.x"
   }
 }
diff --git a/readme.md b/readme.md
index 0ff25800dbd2de88ad8dbe4170b0bfc265a4e701..91ee838f004844367e4d56848c3bd72a9bde151c 100644
--- a/readme.md
+++ b/readme.md
@@ -1,14 +1,35 @@
-# Currency-Monit
+# Currency-Monit Module
 
-Requires Node.js v6
+Requires Duniter 1.5.4 or higher
 
 ## Installation
 
-    git clone https://github.com/librelois/duniter-currency-monit.git
-    cd duniter-currency-monit
-    npm install
-    node index.js config --autoconf
-    node index.js sync g1.duniter.org 10901
-    node index.js currency-monit
+**Warning: only tar.gz format works ! Don't use zip format.**
 
-Then, visit http://localhost:10501.
+### If you use web-ui, install it very easy:
+
+1. go to localhost:9220/#/main/settings/modules
+and at the foot of page enter:
+```bash
+duniter-currency-monit@0.4.5
+```
+
+then clik to button INSTALL THIS MODULE
+
+2. restart your duniter node
+
+### If you don't use web-ui:
+
+1. download and uncompress archive at the location of your choice
+2. plug the plugin to your duniter node:
+
+```bash
+duniter plug duniter-currency-monit@0.4.5
+```
+
+3. Stop your duniter node and restart it in the following method:
+```bash
+duniter currency-monit [host] [port]
+```
+
+then visit `host:port` (default is `localhost:10500`)
\ No newline at end of file
diff --git a/release.sh b/release.sh
new file mode 100755
index 0000000000000000000000000000000000000000..12e1be47d934aabdef17c2600bcaec9cdd87c85a
--- /dev/null
+++ b/release.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+current=`grep -P "version\": \"\d+.\d+.\d+(\w*)" package.json | grep -oP "\d+.\d+.\d+(\w*)"`
+echo "Current version: $current"
+
+if [[ $1 =~ ^[0-9]+.[0-9]+.[0-9]+((a|b)[0-9]+)?$ ]]; then
+  # Change the version in package.json and test file
+  sed -i "s/version\": \"$current/version\": \"$1/g" package.json
+  sed -i "s/$current/$1/g" views/about.html
+
+  # Commit
+  git reset HEAD
+  git add package.json views/about.html
+  git commit -m "v$1"
+  git tag "v$1"
+else
+  echo "Wrong version format"
+fi
diff --git a/routes/blockCount.js b/routes/blockCount.js
index 097c5cf06b490b0b08c05aa7de3c3a00b0185c2d..80316026e81de396b59a71a69343c6fee20d1b73 100755
--- a/routes/blockCount.js
+++ b/routes/blockCount.js
@@ -1,8 +1,10 @@
 "use strict";
 
 const co = require('co')
+const fs = require('fs')
 const timestampToDatetime = require(__dirname + '/../lib/timestampToDatetime')
 const colorScale = require(__dirname + '/../lib/colorScale')
+const getLang = require(__dirname + '/../lib/getLang')
 
 // Garder l'index des blocs en mémoire vive
 var blockchain = [];
@@ -11,7 +13,7 @@ var previousBlockchainTime= 0;
 
 module.exports = (req, res, next) => co(function *() {
   
-  var { duniterServer  } = req.app.locals
+  var { duniterServer, monitDatasPath } = req.app.locals
   
   try {
     // get GET parameters
@@ -22,6 +24,9 @@ module.exports = (req, res, next) => co(function *() {
     var data = req.query.data || 'nbBlocks';
     var perNode = (req.query.perNode == 'yes') ? 'yes':'no';
     var significantPercent = req.query.significantPercent || 3;
+
+    // get lg file
+    const LANG = getLang(`${__dirname}/../lg/blockCount_${req.query.lg||constants.DEFAULT_LANGUAGE}.txt`);
     
     // detect fork
     if ( blockchain.length > 0 )
@@ -78,17 +83,17 @@ module.exports = (req, res, next) => co(function *() {
       tabBlockMembers.push ({
         uid: idtys[i].uid,
         pubkey: idtys[i].pub,
-	becomeMember: (tmpBecomeMember[0] > begin) ? tmpBecomeMember[0]:begin,
-	coreCount: 0,
-	blockCount: 0, 
+        becomeMember: (tmpBecomeMember[0] > begin) ? tmpBecomeMember[0]:begin,
+        coreCount: 0,
+        blockCount: 0, 
         data: 0
       });
       // initialize tabBlockCountPerNode and tabDataPerNode
       if (perNode == 'yes')
       {
-	tabCoreCountPerNode.push(new Array());
-	tabBlockCountPerNode.push(new Array());
-	tabDataPerNode.push(new Array());
+        tabCoreCountPerNode.push(new Array());
+        tabBlockCountPerNode.push(new Array());
+        tabDataPerNode.push(new Array());
       }
     }
     
@@ -97,40 +102,77 @@ module.exports = (req, res, next) => co(function *() {
     {
       for (let m=0;m<tabBlockMembers.length;m++)
       {
-	for (let n=0;n<9;n++)
-	{
-	  tabCoreCountPerNode[m].push(0);
-	  tabBlockCountPerNode[m].push(0);
-	  if (data == 'meanNonce') { tabDataPerNode[m].push(0); }
-	}
+        for (let n=0;n<9;n++)
+        {
+          tabCoreCountPerNode[m].push(0);
+          tabBlockCountPerNode[m].push(0);
+          if (data == 'meanNonce') { tabDataPerNode[m].push(0); }
+        }
       }
     }
+
+    // Open a write stream into a new calculators_rank file
+    let pathToCalculatorsRankFile = monitDatasPath + 'calculators_rank/'
+    let calculatorsRankFilename = 'calculators_rank_' + Date.now() + '.csv'
+    if (!fs.existsSync(pathToCalculatorsRankFile)) { fs.mkdirSync(pathToCalculatorsRankFile) }
+    var ws = fs.createWriteStream(pathToCalculatorsRankFile + calculatorsRankFilename, {
+      flags: 'a',
+      encoding: 'utf8',
+      fd: null,
+      mode: 0o666,
+      autoClose: true
+    });
     
     // Calculate the sum of blocks and their nonce and number of core
+    let calculatorsCount = 1;
     for (let b=begin;b<blockchain.length;b++)
     {
       for (let m=0;m<tabBlockMembers.length;m++)
       {
         if (tabBlockMembers[m].pubkey == blockchain[b].issuer)
         {
-	  tabBlockMembers[m].blockCount++;
-	  let nonce = parseInt((blockchain[b].nonce).toString().substr(3));
-	  if (data == 'meanNonce') { tabBlockMembers[m].data += nonce; }
-	  
-	  let idCore = parseInt((blockchain[b].nonce).toString().substr(1, 2));
-	  tabBlockMembers[m].coreCount = (tabBlockMembers[m].coreCount < idCore) ? idCore:tabBlockMembers[m].coreCount;
-	  
-	  let idNode = parseInt((blockchain[b].nonce).toString().substr(0, 1));
-	  if (perNode == 'yes')
-	  {
-	    maxIdNode = (idNode > maxIdNode) ? idNode:maxIdNode;
-	    tabCoreCountPerNode[m][idNode-1] = (tabCoreCountPerNode[m][idNode-1] < idCore) ? idCore:tabCoreCountPerNode[m][idNode-1];
-	    tabBlockCountPerNode[m][idNode-1]++;
-	    if (data == 'meanNonce') { tabDataPerNode[m][idNode-1] += nonce; }
-	  }
+          if (tabBlockMembers[m].blockCount == 0) {
+            //console.log("%s, %s, #%s, %s", calculatorsCount, tabBlockMembers[m].uid, b, timestampToDatetime(blockchain[b].medianTime));
+            ws.write(calculatorsCount + ', ' + tabBlockMembers[m].uid + ', #' + b + ', ' + timestampToDatetime(blockchain[b].medianTime) + '\r\n');
+            calculatorsCount++;
+          }
+          
+          tabBlockMembers[m].blockCount++;
+          let nonce = parseInt((blockchain[b].nonce).toString().substr(3));
+          if (data == 'meanNonce') { tabBlockMembers[m].data += nonce; }
+          
+          let idCore = parseInt((blockchain[b].nonce).toString().substr(1, 2));
+          tabBlockMembers[m].coreCount = (tabBlockMembers[m].coreCount < idCore) ? idCore:tabBlockMembers[m].coreCount;
+          
+          let idNode = parseInt((blockchain[b].nonce).toString().substr(0, 1));
+          if (perNode == 'yes')
+          {
+            maxIdNode = (idNode > maxIdNode) ? idNode:maxIdNode;
+            tabCoreCountPerNode[m][idNode-1] = (tabCoreCountPerNode[m][idNode-1] < idCore) ? idCore:tabCoreCountPerNode[m][idNode-1];
+            tabBlockCountPerNode[m][idNode-1]++;
+            if (data == 'meanNonce') { tabDataPerNode[m][idNode-1] += nonce; }
+          }
         }
       }
     }
+
+    // Close write stream into calculators_rank file
+    ws.end(); 
+
+    // Remove oldest calculators_rank file
+    let files = fs.readdirSync(pathToCalculatorsRankFile);
+    if (files.length > 10) {
+      let minTimestamp = parseInt(Date.now())
+      for (let file of files) {
+        let fileTimestamp = parseInt(file.split('_')[2])
+        if (fileTimestamp < minTimestamp) {
+          minTimestamp = fileTimestamp;
+        }
+      }
+      fs.unlink(pathToCalculatorsRankFile + 'calculators_rank_' + minTimestamp + '.csv',function(err){
+        if(err) return console.log(err);
+      });  
+    }
     
     // Delete non-significant nodes
     // A node is considered as significant if its blockCount represents more than 3 % of the total member blockCount
@@ -140,24 +182,24 @@ module.exports = (req, res, next) => co(function *() {
       for (let m=0;m<tabBlockMembers.length;m++)
       {
         let significantLimit = parseInt(tabBlockMembers[m].blockCount * significantPercent / 100);
-	for (let n=0;n<maxIdNode;n++)
-	{
-	      if (tabBlockCountPerNode[m][n] <= significantLimit)
-	      {
-	        tabBlockMembers[m].blockCount -= tabBlockCountPerNode[m][n];
-		tabCoreCountPerNode[m][n] = 0;
-		tabBlockCountPerNode[m][n] = 0;
-		if (data == 'meanNonce')
-		{
-		  tabBlockMembers[m].data -= tabDataPerNode[m][n];
-		  tabDataPerNode[m][n] = 0;
-		}
-	      }
-	      else if (tabBlockCountPerNode[m][n] > 0)
+	      for (let n=0;n<maxIdNode;n++)
 	      {
-		maxSignificantIdNode = ((n+1) > maxSignificantIdNode) ? (n+1):maxSignificantIdNode;
-	      }
-	}
+          if (tabBlockCountPerNode[m][n] <= significantLimit)
+          {
+            tabBlockMembers[m].blockCount -= tabBlockCountPerNode[m][n];
+            tabCoreCountPerNode[m][n] = 0;
+            tabBlockCountPerNode[m][n] = 0;
+            if (data == 'meanNonce')
+            {
+              tabBlockMembers[m].data -= tabDataPerNode[m][n];
+              tabDataPerNode[m][n] = 0;
+            }
+          }
+          else if (tabBlockCountPerNode[m][n] > 0)
+          {
+            maxSignificantIdNode = ((n+1) > maxSignificantIdNode) ? (n+1):maxSignificantIdNode;
+          }
+        }
       }
     }
     
@@ -166,38 +208,38 @@ module.exports = (req, res, next) => co(function *() {
     {
       if (data == 'nbBlocks')
       {
-	tabBlockMembers[m].data = tabBlockMembers[m].blockCount;
-	if (perNode == 'yes') {
-	  for (let n=0;n<maxSignificantIdNode;n++) { tabDataPerNode[m].push(tabBlockCountPerNode[m][n]); }
-	}
+        tabBlockMembers[m].data = tabBlockMembers[m].blockCount;
+        if (perNode == 'yes') {
+          for (let n=0;n<maxSignificantIdNode;n++) { tabDataPerNode[m].push(tabBlockCountPerNode[m][n]); }
+        }
       }
       else if (data == 'writtenPercent')
       {
-	tabBlockMembers[m].data = parseFloat( ((tabBlockMembers[m].blockCount * 100) / (blockchain.length-begin)).toFixed(2) );
-	if (perNode == 'yes') {
-	  for (let n=0;n<maxSignificantIdNode;n++) {
-            tabDataPerNode[m].push( parseFloat( ((tabBlockCountPerNode[m][n] * 100) / (blockchain.length-begin)).toFixed(2) ) );
-	  }
-	}
+        tabBlockMembers[m].data = parseFloat( ((tabBlockMembers[m].blockCount * 100) / (blockchain.length-begin)).toFixed(2) );
+        if (perNode == 'yes') {
+          for (let n=0;n<maxSignificantIdNode;n++) {
+                  tabDataPerNode[m].push( parseFloat( ((tabBlockCountPerNode[m][n] * 100) / (blockchain.length-begin)).toFixed(2) ) );
+          }
+        }
       }
       else if (data == 'meanNonce' && tabBlockMembers[m].blockCount > 0)    
       {
-	tabBlockMembers[m].data = parseInt( (tabBlockMembers[m].data / (tabBlockMembers[m].blockCount)).toFixed(0) );
-	if (perNode == 'yes') {
-	  for (let n=0;n<maxSignificantIdNode;n++) {
-            tabDataPerNode[m][n] = parseInt( (tabDataPerNode[m][n] / (tabBlockCountPerNode[m][n])).toFixed(0) );
-	  }
-	}
+        tabBlockMembers[m].data = parseInt( (tabBlockMembers[m].data / (tabBlockMembers[m].blockCount)).toFixed(0) );
+        if (perNode == 'yes') {
+          for (let n=0;n<maxSignificantIdNode;n++) {
+                  tabDataPerNode[m][n] = parseInt( (tabDataPerNode[m][n] / (tabBlockCountPerNode[m][n])).toFixed(0) );
+          }
+        }
       }
       else if (data == 'writtenPercentSinceBecomeMember')
       {
-	let nbBlockwithThisMember = (tabBlockMembers[m].becomeMember > begin) ? (blockchain.length-tabBlockMembers[m].becomeMember) : (blockchain.length-begin);
-	tabBlockMembers[m].data = parseFloat( ((tabBlockMembers[m].blockCount * 100) / nbBlockwithThisMember).toFixed(2) );
-	if (perNode == 'yes') {
-	  for (let n=0;n<maxSignificantIdNode;n++) {
-	    tabDataPerNode[m].push( parseFloat( ((tabBlockCountPerNode[m][n] * 100) / nbBlockwithThisMember).toFixed(2) ) );
-	  }
-	}
+        let nbBlockwithThisMember = (tabBlockMembers[m].becomeMember > begin) ? (blockchain.length-tabBlockMembers[m].becomeMember) : (blockchain.length-begin);
+        tabBlockMembers[m].data = parseFloat( ((tabBlockMembers[m].blockCount * 100) / nbBlockwithThisMember).toFixed(2) );
+        if (perNode == 'yes') {
+          for (let n=0;n<maxSignificantIdNode;n++) {
+            tabDataPerNode[m].push( parseFloat( ((tabBlockCountPerNode[m][n] * 100) / nbBlockwithThisMember).toFixed(2) ) );
+          }
+        }
       }
     }
     
@@ -227,22 +269,22 @@ module.exports = (req, res, next) => co(function *() {
       tabBlockMembersSort.push({
         uid: tabBlockMembers[idMax].uid,
         pubkey: tabBlockMembers[idMax].pub,
-	becomeMember: tabBlockMembers[idMax].becomeMember,
-	coreCount: tabBlockMembers[m].coreCount,
-	coreCountPerNode: (perNode == 'yes') ? tabCoreCountPerNode[idMax]:null,
-	blockCount: tabBlockMembers[idMax].blockCount,
-	blockCountPerNode: (perNode == 'yes') ? tabBlockCountPerNode[idMax]:null,
-        data: tabBlockMembers[idMax].data,
-	dataPerNode: (perNode == 'yes') ? tabDataPerNode[idMax]:null
+        becomeMember: tabBlockMembers[idMax].becomeMember,
+        coreCount: tabBlockMembers[m].coreCount,
+        coreCountPerNode: (perNode == 'yes') ? tabCoreCountPerNode[idMax]:null,
+        blockCount: tabBlockMembers[idMax].blockCount,
+        blockCountPerNode: (perNode == 'yes') ? tabBlockCountPerNode[idMax]:null,
+              data: tabBlockMembers[idMax].data,
+	      dataPerNode: (perNode == 'yes') ? tabDataPerNode[idMax]:null
       });
       tabExcluded.push(tabBlockMembers[idMax].uid);
     }
     
     //define dataLabel
-    var dataLabel = '#Written blocks';
-    if (data == 'writtenPercent') { dataLabel = "\% blockchain"; }
-    else if (data == 'writtenPercentSinceBecomeMember') { dataLabel = "\% blockchain (since become member)"; }
-    else if (data == 'meanNonce') { dataLabel = '#Mean nonce'; }
+    var dataLabel = '#'+LANG['WRITTEN_BLOCKS'];
+    if (data == 'writtenPercent') { dataLabel = "\% "+LANG['BLOCKCHAIN']; }
+    else if (data == 'writtenPercentSinceBecomeMember') { dataLabel = "\% "+LANG['BLOCKCHAIN']+" ("+LANG['SINCE_BECOME_MEMBER']+")"; }
+    else if (data == 'meanNonce') { dataLabel = '#'+LANG['MEAN_NONCE']; }
     
     // Si le client demande la réponse au format JSON, le faire
     if (format == 'JSON')
@@ -260,98 +302,98 @@ module.exports = (req, res, next) => co(function *() {
       for (let n=0;n<maxIdNode;n++) { tabDataXperNode.push(new Array()); }
       for (let m=0;m<tabBlockMembersSort.length;m++)
       {
-	if (tabBlockMembersSort[m].data > 0)
-	{
-	  if (perNode == 'yes')
-	  {
-	    tabLabels.push(tabBlockMembersSort[m].uid+"(");
-	    for (let n=0;n<maxSignificantIdNode;n++)
-	    {
-	      tabDataXperNode[n].push(tabBlockMembersSort[m].dataPerNode[n]);
-	      if (tabBlockMembersSort[m].coreCountPerNode[n] > 0) { tabLabels[tabLabels.length-1] += tabBlockMembersSort[m].coreCountPerNode[n]+"c,"; }
-	    }
-	    tabLabels[tabLabels.length-1] = tabLabels[tabLabels.length-1].substr(0, tabLabels[tabLabels.length-1].length-1);
-	    tabLabels[tabLabels.length-1] += ")";
-	  }
-	  else
-	  {
-	    tabLabels.push(tabBlockMembersSort[m].uid/*+"("+tabBlockMembersSort[m].coreCount+"c)"*/);
-	    tabDataX.push(tabBlockMembersSort[m].data);
-	  }
-	  nbMembers++;
-	}
+        if (tabBlockMembersSort[m].data > 0)
+        {
+          if (perNode == 'yes')
+          {
+            tabLabels.push(tabBlockMembersSort[m].uid+"(");
+            for (let n=0;n<maxSignificantIdNode;n++)
+            {
+              tabDataXperNode[n].push(tabBlockMembersSort[m].dataPerNode[n]);
+              if (tabBlockMembersSort[m].coreCountPerNode[n] > 0) { tabLabels[tabLabels.length-1] += tabBlockMembersSort[m].coreCountPerNode[n]+"c,"; }
+            }
+            tabLabels[tabLabels.length-1] = tabLabels[tabLabels.length-1].substr(0, tabLabels[tabLabels.length-1].length-1);
+            tabLabels[tabLabels.length-1] += ")";
+          }
+          else
+          {
+            tabLabels.push(tabBlockMembersSort[m].uid);
+            tabDataX.push(tabBlockMembersSort[m].data);
+          }
+          nbMembers++;
+        }
       }
       
       var datasets = [ [] ];
       if (perNode == 'yes')
       {
-	for (let n=0;n<maxSignificantIdNode;n++)
-	{
-	  datasets.push({
-		label: dataLabel,
-		data: tabDataXperNode[n],
-		backgroundColor: colorScale(nbMembers, 0.5),
-		borderWidth: 0,
-		hoverBackgroundColor: colorScale(nbMembers, 0.2)
-	      });
-	}
+        for (let n=0;n<maxSignificantIdNode;n++)
+        {
+          datasets.push({
+          label: dataLabel,
+          data: tabDataXperNode[n],
+          backgroundColor: colorScale(nbMembers, 0.5),
+          borderWidth: 0,
+          hoverBackgroundColor: colorScale(nbMembers, 0.2)
+              });
+        }
       }
       else
       {
-	datasets = [{
-		label: dataLabel,
-		data: tabDataX,
-		backgroundColor: colorScale(nbMembers, 0.5),
-                borderColor: colorScale(nbMembers, 1.0),
-		borderWidth: 1,
-		hoverBackgroundColor: colorScale(nbMembers, 0.2),
-		hoverBorderColor: colorScale(nbMembers, 0.2)
+	      datasets = [{
+          label: dataLabel,
+          data: tabDataX,
+          backgroundColor: colorScale(nbMembers, 0.5),
+                      borderColor: colorScale(nbMembers, 1.0),
+          borderWidth: 1,
+          hoverBackgroundColor: colorScale(nbMembers, 0.2),
+          hoverBorderColor: colorScale(nbMembers, 0.2)
 	      }];
       }
       
       res.locals = {
-	 host: req.headers.host.toString(),
-         tabBlockMembersSort, 
-         begin, 
-         end,
-	 help,
-	 data,
-	 perNode,
-	 description: ``,
-	 chart: {
-	    type: 'bar',
-	    data: {
-	      labels: tabLabels,
-	      datasets: datasets
-	    },
-	    options: {
-	      title: {
-		display: true,
-		text: nbMembers+' members have written blocks in the range #'+begin+'-#'+end
-	      },
-	      legend: {
-		display: false
-	      },
-	      scales: {
-		yAxes: [{
-		  ticks: {
-		      beginAtZero: true,
-		  }
-		}]
-	      },
-	      categoryPercentage: 1.0,
-	      barPercentage: 1.0
-	    }
-	  },
-	  form: `Begin #<input type="number" name="begin" value="${begin}" size="7" style="width:60px;"> - End #<input type="number" name="end" value="${end}" size="7" style="width:60px;">
-	    <select name="data">
-	      <option name="data" value ="nbBlocks">Number of written Blocks
-	      <option name="data" value ="writtenPercent" ${data == 'writtenPercent' ? 'selected' : ''}>Percent of written Blocks
-	      <option name="data" value ="writtenPercentSinceBecomeMember" ${data == 'writtenPercentSinceBecomeMember' ? 'selected' : ''}>Percent of written Blocks since become member
-	      <option name="data" value ="meanNonce" ${data == 'meanNonce' ? 'selected' : ''}>mean nonce
-	    </select>
-	    <input type="checkbox" name="perNode" value="yes" ${perNode == 'yes' ? 'checked' : ''}>detail by node - 
-	    significant limit <input type="number" name="significantPercent" value="${significantPercent}" size="2" style="width:30px;">% of blocks`
+	      host: req.headers.host.toString(),
+        tabBlockMembersSort, 
+        begin, 
+        end,
+	      help,
+        data,
+        perNode,
+        description: ``,
+        chart: {
+          type: 'bar',
+          data: {
+            labels: tabLabels,
+            datasets: datasets
+          },
+          options: {
+            title: {
+              display: true,
+              text: nbMembers+' '+LANG["RANGE"]+' #'+begin+'-#'+end
+            },
+            legend: {
+              display: false
+            },
+            scales: {
+              yAxes: [{
+                ticks: {
+                  beginAtZero: true,
+                }
+              }]
+            },
+            categoryPercentage: 1.0,
+            barPercentage: 1.0
+          }
+        },
+          form: `${LANG['BEGIN']} #<input type="number" name="begin" value="${begin}" size="7" style="width:60px;"> - ${LANG['END']} #<input type="number" name="end" value="${end}" size="7" style="width:60px;">
+            <select name="data">
+              <option name="data" value ="nbBlocks">${LANG["NB_BLOCKS"]}
+              <option name="data" value ="writtenPercent" ${data == 'writtenPercent' ? 'selected' : ''}>${LANG["PERCENT_OF_WRITTEN_BLOCKS"]}
+              <option name="data" value ="writtenPercentSinceBecomeMember" ${data == 'writtenPercentSinceBecomeMember' ? 'selected' : ''}>${LANG["PERCENT_OF_WRITTEN_BLOCKS"]} ${LANG["SINCE_BECOME_MEMBER"]}
+              <option name="data" value ="meanNonce" ${data == 'meanNonce' ? 'selected' : ''}>${LANG['MEAN_NONCE']}
+            </select>
+            <input type="checkbox" name="perNode" value="yes" ${perNode == 'yes' ? 'checked' : ''}>${LANG['DETAIL_BY_NODE']} - 
+            ${LANG['SIGNIFICANT_LIMIT']} <input type="number" name="significantPercent" value="${significantPercent}" size="2" style="width:30px;">${LANG['PERCENT_OF_BLOCKS']}`
       }
       next()
     }
diff --git a/routes/gaussianWotQuality.js b/routes/gaussianWotQuality.js
new file mode 100644
index 0000000000000000000000000000000000000000..d8b6d370942fff4934614f6a31b7ac291e1f8ddd
--- /dev/null
+++ b/routes/gaussianWotQuality.js
@@ -0,0 +1,241 @@
+"use strict";
+
+const co = require('co')
+
+const constants = require(__dirname + '/../lib/constants')
+const membersQuality = require(__dirname + '/tools/membersQuality')
+const getLang = require(__dirname + '/../lib/getLang')
+
+// gaussianWotQuality cache
+var previousNextYn = "no";
+
+module.exports = (req, res, next) => co(function *() {
+  
+  var { duniterServer  } = req.app.locals
+  
+  try {
+      // get GET parameters
+      const format = req.query.format || 'HTML';
+      const sentries = req.query.sentries || 'yes';
+      const unit = req.query.unit || 'quality';
+      const nextYn = (req.query.nextYn=="yes") ? "yes":"no";
+
+      // get lg file
+      const LANG = getLang(`${__dirname}/../lg/gaussianWotQuality_${req.query.lg||constants.DEFAULT_LANGUAGE}.txt`);
+
+      // Définition des contantes
+      const conf = duniterServer.conf;
+      const qualityMax = (1/conf.xpercent);
+
+      // Définition des variables
+      let lastUpgradeTimeDatas = membersQuality(constants.QUALITY_CACHE_ACTION.INIT);
+      let tabUidIndex = [];
+      let tabMembersQuality= [];
+      let tabMembersQualitySorted = [];
+      let tabLabels = [];
+      let tabColors = [];
+      let tabLimit1 = [];
+
+      // Récupérer la liste des identités ayant actuellement le statut de membre
+      let membersList = yield duniterServer.dal.peerDAL.query('SELECT `uid`,`wotb_id` FROM i_index WHERE `member`=1');
+
+      // Si les données de qualité n'ont jamais été calculés, le faire
+      if (lastUpgradeTimeDatas == 0 || (lastUpgradeTimeDatas+constants.MIN_WOT_QUALITY_CACHE_UPDATE_FREQ) < (Math.floor(Date.now() / 1000)) || (previousNextYn != nextYn))
+      {
+        // Calculer dSen
+        var dSen = Math.ceil(Math.pow(membersList.length, 1 / conf.stepMax));
+        if (nextYn == "yes") { dSen++; }
+
+        // récupérer la wot
+        const wot = duniterServer.dal.wotb;
+
+        // Initialiser le cache des données de qualité
+        membersQuality(constants.QUALITY_CACHE_ACTION.INIT, 0, dSen, conf.stepMax, conf.xpercent, wot.memCopy());
+      }
+
+      // Mettre a jour previousNextYn
+      previousNextYn = (nextYn=="yes") ? "yes":"no";
+
+      // Calculer nbSentries, limit1 and label
+      const nbSentries = (sentries=="no") ? membersList.length:membersQuality(constants.QUALITY_CACHE_ACTION.GET_SENTRIES_COUNT);
+      let limit1 = 1;
+      let label = LANG['QUALITY'];
+      switch (unit)
+      {
+          case 'percentReached': limit1 = conf.xpercent*100; label = LANG['PERCENT_REACHED']; break;
+          case 'nbReached': limit1 = parseInt(conf.xpercent*nbSentries); label = LANG['NB_REACHED']; break;
+          default: break;
+      }
+
+      // Remplir les tableaux tabUidIndex et tabLimit1
+      for(const member of membersList)
+      {
+        tabUidIndex[member.wotb_id] = member.uid;
+        tabLimit1.push(limit1);
+      }
+
+      // Récupérer le tableau de qualité des membres
+      tabMembersQuality= [];
+      for (let i=0;membersQuality(constants.QUALITY_CACHE_ACTION.GET_QUALITY, i) >= 0;i++)
+      {
+        if (sentries == "no")
+        {
+          tabMembersQuality[i] = membersQuality(constants.QUALITY_CACHE_ACTION.GET_QUALITY, i, -1);
+        }
+        else
+        {
+          tabMembersQuality[i] = membersQuality(constants.QUALITY_CACHE_ACTION.GET_QUALITY, i);
+        }
+      }
+
+      // Initialisation du tableau tabMembersQualitySorted
+      for (let i=0;i<tabMembersQuality.length;i++)
+      {
+        tabMembersQualitySorted.push(0);
+      }
+
+      // Trier le tableau de façon gaussienne
+      let debut = true;
+      let membersQualityAlreadyCounted = [];
+      for (let i=0;i<tabMembersQuality.length;i++)
+      {
+        let min = qualityMax;
+        let idMin = 0;
+
+        for (let j=0;j<tabMembersQuality.length;j++)
+        {
+          if (tabMembersQuality[j] < min && typeof(membersQualityAlreadyCounted[j])=='undefined')
+          {
+            min = tabMembersQuality[j];
+            idMin = j;
+          }
+        }
+
+        // Remplir les tableaux triée de façon gaussienne
+        let idGaussian = parseInt(i/2);
+        if(!debut)
+        {
+          idGaussian = parseInt(tabMembersQuality.length-(i/2));
+        }
+        debut = !debut;
+        tabMembersQualitySorted[idGaussian] = tabMembersQuality[idMin];
+
+        // Exclure les membres déjà traités
+        membersQualityAlreadyCounted[idMin] = true;
+
+        // Définir le label pour cet abscisse
+        tabLabels[idGaussian] = tabUidIndex[idMin];
+
+        // Définir la couleur
+        if (tabMembersQuality[idMin] >= 1.10)
+        {
+          tabColors[idGaussian] = 'rgba(128, 0, 128, 0.5)';
+        }
+        else if (tabMembersQuality[idMin] >= 1.05)
+        {
+          tabColors[idGaussian] = 'rgba(0, 0, 255, 0.5)';
+        }
+        else if (tabMembersQuality[idMin] >= 1.00)
+        {
+          tabColors[idGaussian] = 'rgba(0, 255, 0, 0.5)';
+        }
+        else if (tabMembersQuality[idMin] >= 0.95)
+        {
+          tabColors[idGaussian] = 'rgba(255, 128, 0, 0.5)';
+        }
+        else if (tabMembersQuality[idMin] >= 0.90)
+        {
+          tabColors[idGaussian] = 'rgba(255, 0, 0, 0.5)';
+        }
+        else
+        {
+          tabColors[idGaussian] = 'rgba(0, 0, 0, 0.5)';
+        }
+      }
+
+      // Si le client demande les données dans une autre unité, faire la transformation
+      let unitCoeff = 1.0;
+      if (unit=='percentReached' || unit=='nbReached')
+      {
+        unitCoeff = parseFloat(conf.xpercent);
+        if (unit=='nbReached') { unitCoeff *= parseFloat(nbSentries); }
+        else { unitCoeff *= 100.0; }
+        for (let i=0;i<tabMembersQualitySorted.length;i++)
+        {
+          tabMembersQualitySorted[i] = parseInt(tabMembersQualitySorted[i]*unitCoeff);
+        }
+      }
+      
+      // Si le client demande la réponse au format JSON, le faire
+      if (format == 'JSON')
+      {
+        let tabJson = [];
+        for (let i=0;i<tabMembersQualitySorted.length;i++)
+        {
+          tabJson.push({
+            label: tabLabels[i],
+            quality: tabMembersQualitySorted[i]
+          });
+        }
+        res.status(200).jsonp( tabJson )
+      }
+      else
+      {
+        res.locals = {
+        host: req.headers.host.toString(),
+          form: `
+            <select name="unit">
+              <option name="unit" value ="quality">${LANG['QUALITY']}
+              <option name="unit" value ="percentReached" ${unit == 'percentReached' ? 'selected' : ''}>${LANG['PERCENT_REACHED']}
+              <option name="unit" value ="nbReached" ${unit == 'nbReached' ? 'selected' : ''}>${LANG['NB_REACHED']}
+            </select>`,
+          form2: `<input type="checkbox" name="sentries" value="no" ${sentries == 'no' ? 'checked' : ''}> ${LANG["IF_NO_SENTRIES"]}<br>
+            <input type="checkbox" name="nextYn" value="yes" ${nextYn == 'yes' ? 'checked' : ''}> ${LANG["NEXT_YN"]}`,
+          chart: {
+            type: 'bar',
+            data: {
+              labels: tabLabels,
+              datasets: [{
+                label: label,
+                data: tabMembersQualitySorted,
+                backgroundColor: tabColors,
+                borderWidth: 0
+              },
+              {
+                label: 'limit',
+                data: tabLimit1,
+                backgroundColor: 'rgba(0, 255, 0, 0.5)',
+                borderColor: 'rgba(0, 255, 0, 1)',
+                borderWidth: 2,
+                type: 'line',
+                fill: false,
+                pointStyle: 'dash'
+              }]
+            },
+            options: {
+              title: {
+                display: true,
+                text: LANG['DISTRIBUTION_QUALITY']
+              },
+              legend: {
+                display: false
+              },
+              scales: {
+                yAxes: [{
+                  position: 'left',
+                  ticks: {
+                    min: 0,
+                    max: parseFloat(((1/conf.xpercent)*unitCoeff).toFixed(2))
+                  }
+                }]
+              }
+            }
+          }
+        }
+        next()
+      }
+  } catch (e) {
+    // En cas d'exception, afficher le message
+    res.status(500).send(`<pre>${e.stack || e.message}</pre>`);
+  }
+})
\ No newline at end of file
diff --git a/routes/index.js b/routes/index.js
index 921e1dde7f001f29201b30d0a9c78f056da3e139..a1cb8ec0994c22f44b3f7b770389468ec7e9ba23 100755
--- a/routes/index.js
+++ b/routes/index.js
@@ -1,6 +1,9 @@
 const fs = require('fs')
 const express = require('express')
+
+const constants = require(__dirname + '/../lib/constants')
 const getLang = require(__dirname + '/../lib/getLang')
+const printMenu = require(__dirname + '/../views/printMenu')
 
 var app = express.Router()
 
@@ -25,96 +28,135 @@ Par exemple, home et about n'ont pas besoin de controleur
 /***************************************
 * Home Page
 ***************************************/
-app.get('/', (req, res)=> res.render('about.html', {
-            host: req.headers.host.toString(),
-	    help: req.query.help,
-	    MENU_LANG: getLang(`${__dirname}/../lg/menu_${req.query.lg||'fr'}.txt`)
-         })
- )
+app.get('/', // chemin (endpoint)
+  (req, res)=> res.render('about.html', { // rendu (template)
+    host: req.headers.host.toString(),
+    printMenu,
+	  help: req.query.help,
+	  MENU_LANG: getLang(`${__dirname}/../lg/menu_${req.query.lg||constants.DEFAULT_LANGUAGE}.txt`),
+    LANG: getLang(`${__dirname}/../lg/about_${req.query.lg||constants.DEFAULT_LANGUAGE}.txt`)
+  })
+)
 
 /***************************************
 * About Page
 ***************************************/
-app.get('/about', (req, res)=> res.render('about.html', {
-	    host: req.headers.host.toString(),
-	    help: req.query.help,
-            MENU_LANG: getLang(`${__dirname}/../lg/menu_${req.query.lg||'fr'}.txt`)
-         })
- )
+app.get('/about', // chemin (endpoint)
+  (req, res)=> res.render('about.html', { // rendu (template)
+    host: req.headers.host.toString(),
+    printMenu,
+    help: req.query.help,
+    MENU_LANG: getLang(`${__dirname}/../lg/menu_${req.query.lg||constants.DEFAULT_LANGUAGE}.txt`),
+    LANG: getLang(`${__dirname}/../lg/about_${req.query.lg||constants.DEFAULT_LANGUAGE}.txt`)
+  })
+)
 
 /***************************************
 * Lister les futurs membres
 ***************************************/
-app.get('/willMembers', 
-  require(__dirname + '/willMembers.js'), // the route controler
-  (req, res)=> // Send html page
-      res.status(200) // 200 n'est pas obligatoire, si on renvoie une réponse
-         .render('willMembers.html', {
-	    help: req.query.help,
-	    MENU_LANG: getLang(`${__dirname}/../lg/menu_${req.query.lg||'fr'}.txt`),
-            LANG: getLang(`${__dirname}/../lg/willMembers_${req.query.lg||'fr'}.txt`)
-         })
+app.get('/willMembers', // chemin (endpoint)
+  require(__dirname + '/willMembers.js'), // controleur (route)
+  (req, res)=> res.render('willMembers.html', { // rendu (template)
+    printMenu,
+	  help: req.query.help,
+	  MENU_LANG: getLang(`${__dirname}/../lg/menu_${req.query.lg||constants.DEFAULT_LANGUAGE}.txt`),
+    LANG: getLang(`${__dirname}/../lg/willMembers_${req.query.lg||constants.DEFAULT_LANGUAGE}.txt`)
+  })
 )
 
 /***************************************
 * Lister les membres
 ***************************************/
-app.get('/members', /*require('../lib/updateCache.js'),*/ require(__dirname + '/members.js'),
+app.get('/members',
+  require(__dirname + '/members.js'),
   (req, res)=> res.render('members.html', {
-		    help: req.query.help,
-		    MENU_LANG: getLang(`${__dirname}/../lg/menu_${req.query.lg||'fr'}.txt`),
-                    LANG: getLang(`${__dirname}/../lg/members_${req.query.lg||'fr'}.txt`)
-                  })
+    printMenu,
+		help: req.query.help,
+		MENU_LANG: getLang(`${__dirname}/../lg/menu_${req.query.lg||constants.DEFAULT_LANGUAGE}.txt`),
+    LANG: getLang(`${__dirname}/../lg/members_${req.query.lg||constants.DEFAULT_LANGUAGE}.txt`)
+  })
 )
 
 /***************************************
 * Lister les anciens membres
 ***************************************/
-/*app.get('/wasMembers', require(__dirname + '/wasMembers.js'), (req, res)=> res.render('wasMembers.html', {
-	    help: req.query.help,
-            MENU_LANG: getLang(`${__dirname}/../lg/menu_${req.query.lg||'fr'}.txt`),
-            LANG: getLang(`${__dirname}/../lg/wasMembers_${lg}.txt`)
-         })
- )*/
+/*app.get('/wasMembers',
+  require(__dirname + '/wasMembers.js'),
+  (req, res)=> res.render('wasMembers.html', {
+    printMenu,
+    help: req.query.help,
+    MENU_LANG: getLang(`${__dirname}/../lg/menu_${req.query.lg||constants.DEFAULT_LANGUAGE}.txt`),
+    LANG: getLang(`${__dirname}/../lg/wasMembers_${lg}.txt`)
+  })
+)*/
 
 /***************************************
 * Évolution du nombre de membres
 ***************************************/
-app.get('/membersCount', require(__dirname + '/../lib/updateCache.js'), require(__dirname + '/membersCount.js'), (req, res)=> res.render('Chart.html', {
-	    help: req.query.help,
-            MENU_LANG: getLang(`${__dirname}/../lg/menu_${req.query.lg||'fr'}.txt`),
-            LANG: getLang(`${__dirname}/../lg/membersCount_${req.query.lg||'fr'}.txt`)
-         })
- )
+app.get('/membersCount',
+  require(__dirname + '/../lib/updateCache.js'), require(__dirname + '/membersCount.js'),
+  (req, res)=> res.render('Chart.html', {
+    printMenu,
+    pageName: 'MEMBERS_COUNT',
+    help: req.query.help,
+    MENU_LANG: getLang(`${__dirname}/../lg/menu_${req.query.lg||constants.DEFAULT_LANGUAGE}.txt`),
+    LANG: getLang(`${__dirname}/../lg/membersCount_${req.query.lg||constants.DEFAULT_LANGUAGE}.txt`)
+  })
+)
 
 /***************************************
-* Lister les block en graph
+* Wotex
 ***************************************/
-app.get('/blockCount', /*require('${__dirname}/../lib/updateCache.js'),*/ require(__dirname + '/blockCount.js'), (req, res)=> res.render('Chart.html', {
-	    help: req.query.help,
-            MENU_LANG: getLang(`${__dirname}/../lg/menu_${req.query.lg||'fr'}.txt`),
-            LANG: getLang(`${__dirname}/../lg/blockCount_${req.query.lg||'fr'}.txt`)
-         })
- )
+app.get('/wotex',
+  require(__dirname + '/wotex.js'),
+  (req, res)=> res.render('wotex.html', {
+    printMenu,
+    help: req.query.help,
+    MENU_LANG: getLang(`${__dirname}/../lg/menu_${req.query.lg||constants.DEFAULT_LANGUAGE}.txt`),
+    LANG: getLang(`${__dirname}/../lg/wotex_${req.query.lg||constants.DEFAULT_LANGUAGE}.txt`)
+  })
+)
+
+/*******************************************
+* Graphe gaussien de la qualité des membres
+********************************************/
+app.get('/gaussianWotQuality', 
+  require(__dirname + '/gaussianWotQuality.js'),
+  (req, res)=> res.render('Chart.html', {
+    printMenu,
+    pageName: 'GAUSSIAN_WOT_QUALITY',
+    help: req.query.help,
+    MENU_LANG: getLang(`${__dirname}/../lg/menu_${req.query.lg||constants.DEFAULT_LANGUAGE}.txt`),
+    LANG: getLang(`${__dirname}/../lg/gaussianWotQuality_${req.query.lg||constants.DEFAULT_LANGUAGE}.txt`)
+  })
+)
 
 /***************************************
-* Évolution de la masse monétaire totale
+* Lister les block en graphe
 ***************************************/
-app.get('/monetaryMass', require(__dirname + '/monetaryMass.js'), (req, res)=> res.render('Chart.html', {
-	    help: req.query.help,
-            MENU_LANG: getLang(`${__dirname}/../lg/menu_${req.query.lg||'fr'}.txt`),
-            LANG: getLang(`${__dirname}/../lg/monetaryMass_${req.query.lg||'fr'}.txt`)
-         })
- )
+app.get('/blockCount', 
+  require(__dirname + '/blockCount.js'),
+  (req, res)=> res.render('Chart.html', {
+    printMenu,
+    pageName: 'BLOCK_COUNT',
+    help: req.query.help,
+    MENU_LANG: getLang(`${__dirname}/../lg/menu_${req.query.lg||constants.DEFAULT_LANGUAGE}.txt`),
+    LANG: getLang(`${__dirname}/../lg/blockCount_${req.query.lg||constants.DEFAULT_LANGUAGE}.txt`)
+  })
+)
 
 /***************************************
-* Wotex
+* Évolution de la masse monétaire totale
 ***************************************/
-app.get('/wotex', require(__dirname + '/wotex.js'), (req, res)=> res.render('wotex.html', {
-	    help: req.query.help,
-            MENU_LANG: getLang(`${__dirname}/../lg/menu_${req.query.lg||'fr'}.txt`),
-            LANG: getLang(`${__dirname}/../lg/wotex_${req.query.lg||'fr'}.txt`)
-         })
- )
+app.get('/monetaryMass',
+  require(__dirname + '/monetaryMass.js'),
+  (req, res)=> res.render('Chart.html', {
+    printMenu,
+    pageName: 'MONETARY_MASS',
+    help: req.query.help,
+    MENU_LANG: getLang(`${__dirname}/../lg/menu_${req.query.lg||constants.DEFAULT_LANGUAGE}.txt`),
+    LANG: getLang(`${__dirname}/../lg/monetaryMass_${req.query.lg||constants.DEFAULT_LANGUAGE}.txt`)
+  })
+)
 
 module.exports = app
\ No newline at end of file
diff --git a/routes/members.js b/routes/members.js
index 713ae6c11e25bb476dca3db0d1204f72a01d172b..d5ab20d22cca2a8c258563c8e7bdbd52205b25bf 100755
--- a/routes/members.js
+++ b/routes/members.js
@@ -4,15 +4,18 @@ const co = require('co')
 
 const constants = require(__dirname + '/../lib/constants')
 
-const wotb = (constants.USE_WOTB6) ? require('wotb'):null;
-
+const randomInt = require(__dirname + '/../lib/randomInt')
 const timestampToDatetime = require(__dirname + '/../lib/timestampToDatetime')
+const membersQuality = require(__dirname + '/tools/membersQuality')
 
 // Préserver les résultats en cache
 var lockMembers = false;
 var membersLastUptime = 0;
 var previousMode = null;
 var previousCentrality = null;
+var previousNextYn = "no";
+var previousRandomList = "no"
+var previousRandomCounts = 10
 var membersList = [];
 var membersIdentity = [];
 var membersFirstCertifExpire = [];
@@ -24,11 +27,11 @@ var membershipsExpireTimeList = [];
 var nbMaxCertifs = 0;
 var sentries = [];
 var sentriesIndex = [];
-var membersQualityExt = [];
-var meanSentriesReachedBySentriesInSingleExtCert = 0;
+var countSentries = 0;
+/*var meanSentriesReachedBySentriesInSingleExtCert = 0;
 var meanMembersReachedBySentriesInSingleExtCert = 0;
 var meanSentriesReachedByMembersInSingleExtCert = 0;
-var meanMembersReachedByMembersInSingleExtCert = 0;
+var meanMembersReachedByMembersInSingleExtCert = 0;*/
 var proportionMembersWithQualityUpper1 = 0;
 var proportionMembersWithQualityUpper1IfNoSentries = 0;
 
@@ -51,13 +54,12 @@ module.exports = (req, res, next) => co(function *() {
     const head = yield duniterServer.dal.getCurrentBlockOrNull();
     const currentBlockchainTimestamp =  head ? head.medianTime : 0;
     const membersCount = head ? head.membersCount : 0;
-    const dSen = Math.ceil(Math.pow(membersCount, 1 / conf.stepMax));
+    var dSen = Math.ceil(Math.pow(membersCount, 1 / conf.stepMax));
     
     // Initaliser les variables
 		let membersListOrdered = [];
 		let membersCertifsListSorted = [];
 		let tabSort = [];
-		let countSentries = 0;
 		let membersNbSentriesUnreached = [];
 
     // Récupéré les paramètres
@@ -65,18 +67,26 @@ module.exports = (req, res, next) => co(function *() {
     var mode = req.query.mode || 'received' // Valeur par défaut
     var order = req.query.d && req.query.order || 'desc' // Valeur par défaut
     var sort_by = req.query.sort_by || "idtyWritten" // Valeur par défaut
-		var pendingSigs = req.query.pendingSigs || "no"; // Valeur par défaut
-		var centrality = req.query.centrality || "no"; // Valeur par défaut
-		var format = req.query.format || 'HTML'; // Valeur par défaut
+	var pendingSigs = req.query.pendingSigs || "no"; // Valeur par défaut
+	var centrality = req.query.centrality || "no"; // Valeur par défaut
+	var format = req.query.format || 'HTML'; // Valeur par défaut
+	const nextYn = (req.query.nextYn=="yes") ? "yes":"no";
+	const randomList = (req.query.randomList=="yes") ? "yes":"no";
+	const numberOfRandomMembers = req.query.randomCounts || 10
+
+	// Vérifier la valeur de nextYn dans le cache
+	let lastUpgradeTimeDatas = membersQuality(constants.QUALITY_CACHE_ACTION.INIT);
+	let dSenCache = membersQuality(constants.QUALITY_CACHE_ACTION.GET_D_SEN);
+	if (lastUpgradeTimeDatas > 0 && dSenCache > dSen) { previousNextYn == "yes"; }
     
     // Alimenter wotb avec la toile actuelle
-		const wotbInstance = (constants.USE_WOTB6) ? wotb.newFileInstance(duniterServer.home + '/wotb.bin'):duniterServer.dal.wotb;
+	const wotbInstance = duniterServer.dal.wotb;
 		
-		// Vérifier si le cache doit être Réinitialiser
-		let reinitCache = (Math.floor(Date.now() / 1000) > (membersLastUptime + constants.MIN_MEMBERS_UPDATE_FREQ));
+	// Vérifier si le cache doit être Réinitialiser
+	let reinitCache = (Math.floor(Date.now() / 1000) > (membersLastUptime + constants.MIN_MEMBERS_UPDATE_FREQ));
 		
-		// Si changement de conditions, alors forcer le rechargement du cache s'il n'est pas, vérouillé, sinon forcer les conditions à celles en mémoire
-		if (previousMode != mode || previousCentrality != centrality)
+		// Si changement de conditions, alors forcer le rechargement du cache s'il n'est pas vérouillé, sinon forcer les conditions à celles en mémoire
+		if (previousMode != mode || previousCentrality != centrality || previousNextYn != nextYn || previousRandomList != randomList || numberOfRandomMembers != previousRandomCounts)
 		{
 			if (!lockMembers)
 			{
@@ -87,6 +97,9 @@ module.exports = (req, res, next) => co(function *() {
 			{
 				mode = previousMode;
 				centrality = previousCentrality;
+				nextYn = previousNextYn;
+				randomList = previousRandomList;
+				numberOfRandomMembers = previousRandomCounts;
 			}
 		}
 		// Sinon, si les conditions sont identiques :
@@ -106,6 +119,9 @@ module.exports = (req, res, next) => co(function *() {
 			membersLastUptime = Math.floor(Date.now() / 1000);
 			previousMode = mode;
 			previousCentrality = centrality;
+			previousNextYn = nextYn;
+			previousRandomList = randomList;
+			previousRandomCounts = numberOfRandomMembers;
 			membersList = [];
 			membersIdentity = [];
 			membersFirstCertifExpire = [];
@@ -117,13 +133,19 @@ module.exports = (req, res, next) => co(function *() {
 			nbMaxCertifs = 0;
 			sentries = [];
 			sentriesIndex = [];
-			membersQualityExt = [];
-			meanSentriesReachedBySentriesInSingleExtCert = 0;
+			countSentries = 0;
+			/*meanSentriesReachedBySentriesInSingleExtCert = 0;
 			meanMembersReachedBySentriesInSingleExtCert = 0;
 			meanSentriesReachedByMembersInSingleExtCert = 0;
-			meanMembersReachedByMembersInSingleExtCert = 0;
+			meanMembersReachedByMembersInSingleExtCert = 0;*/
 			proportionMembersWithQualityUpper1 = 0;
 			proportionMembersWithQualityUpper1IfNoSentries = 0;
+
+			// Appliquer le paramètre nextYn
+			if (nextYn=="yes") { dSen++; }
+
+			// réinitialiser le cache des données de qualité
+			membersQuality(constants.QUALITY_CACHE_ACTION.INIT, 0, dSen, conf.stepMax, conf.xpercent, wotbInstance.memCopy());
 			
 			// Réinitialiser le cache des données de centralité
 			if (centrality=='yes')
@@ -140,6 +162,19 @@ module.exports = (req, res, next) => co(function *() {
     
 			// Récupérer la liste des identités ayant actuellement le statut de membre
 			membersList = yield duniterServer.dal.peerDAL.query('SELECT `uid`,`pub`,`member`,`written_on`,`wotb_id` FROM i_index WHERE `member`=1');
+
+			if (randomList == "yes") {
+				// Tirer au sort randomCounts membres
+				const maxLengthRandomMembers = Math.min(numberOfRandomMembers,membersList.length)
+				let randomMembers = []
+				while (randomMembers.length < maxLengthRandomMembers) {
+					const randomInt_ = randomInt(0, membersList.length)
+					if (randomMembers.indexOf(membersList[randomInt_].uid) == -1) {
+						randomMembers.push(membersList[randomInt_])
+					}
+				}
+				membersList = randomMembers
+			}
     
 			// Récupérer pour chaque identité, le numéro du block d'écriture du dernier membership
 			// Ainsi que la première ou dernière certification
@@ -184,51 +219,27 @@ module.exports = (req, res, next) => co(function *() {
 				let tmpWot = wotbInstance.memCopy();
 				
 				// Récupérer les informations détaillés de distance pour le membre courant
-				let detailedDistance = null;
-				if (constants.USE_WOTB6)
+				let detailedDistance = tmpWot.detailedDistance(membersList[m].wotb_id, dSen, conf.stepMax, conf.xpercent);
+				
+				// Calculer le nombre de membres référents
+				if (currentMemberIsSentry)
 				{
-					detailedDistance = tmpWot.detailedDistance(membersList[m].wotb_id, dSen, conf.stepMax, conf.xpercent);
+					countSentries++;
 				}
-				else
-				{
-					detailedDistance = {
-						isOutdistanced: tmpWot.isOutdistanced(membersList[m].wotb_id, dSen, conf.stepMax, conf.xpercent)
-					};
+
+				// Calculate membersNbSentriesUnreached
+				membersNbSentriesUnreached[membersList[m].uid] = parseInt(detailedDistance.nbSentries) - parseInt(detailedDistance.nbSuccess);
+
+				// Calculer la qualité du membre courant
+				if (membersQuality(constants.QUALITY_CACHE_ACTION.GET_QUALITY, membersList[m].wotb_id, (currentMemberIsSentry) ? 1 : 0) >= 1.0) {
+					proportionMembersWithQualityUpper1++;
 				}
-				
-				
-				if (constants.USE_WOTB6)
-				{
-					// Calculate membersNbSentriesUnreached
-					membersNbSentriesUnreached[membersList[m].uid] =  parseInt(detailedDistance.nbSentries)-parseInt(detailedDistance.nbSuccess);
-					
-					// Récupérer les informations détaillés de distance pour une nouvelle identité qui ne serait certifiée que par le membre courant (ce qui équivaut à récupérer les informations de distance pour le membre courant en décrémentant stepMax de 1)
-					let detailedDistanceQualityExt = tmpWot.detailedDistance(membersList[m].wotb_id, dSen, conf.stepMax-1, conf.xpercent);
-					
-					// Calculer la qualité du membre courant
-					membersQualityExt[membersList[m].uid] = ((detailedDistanceQualityExt.nbSuccess/detailedDistanceQualityExt.nbSentries)/conf.xpercent).toFixed(2);
-					if (membersQualityExt[membersList[m].uid] >= 1.0)
-					{
-						proportionMembersWithQualityUpper1++;
-					}
-					
-					// Calculer la qualité du membre courant s'il n'y avait pas de référents (autrement di si tout les membres était référents)
-					let membersQualityIfNoSentries = ((detailedDistanceQualityExt.nbReached/membersList.length)/conf.xpercent).toFixed(2);
-					//console.log("membersQualityIfNoSentries[%s] = %s", membersList[m].uid, membersQualityIfNoSentries);
-					if (membersQualityIfNoSentries >= 1.0)
-					{
-						proportionMembersWithQualityUpper1IfNoSentries++;
-					}
-					
-					// Calculate meanSentriesReachedBySentriesInSingleExtCert, meanMembersReachedBySentriesInSingleExtCert, meanSentriesReachedByMembersInSingleExtCert and meanMembersReachedByMembersInSingleExtCert
-					if (currentMemberIsSentry)
-					{
-						meanSentriesReachedBySentriesInSingleExtCert += parseFloat(((detailedDistanceQualityExt.nbSuccess/detailedDistanceQualityExt.nbSentries)*100).toFixed(2));
-						meanMembersReachedBySentriesInSingleExtCert += parseFloat(((detailedDistanceQualityExt.nbReached/membersList.length)*100).toFixed(2));
-						countSentries++;
-					}
-					meanSentriesReachedByMembersInSingleExtCert += parseFloat(((detailedDistanceQualityExt.nbSuccess/detailedDistanceQualityExt.nbSentries)*100).toFixed(2));
-					meanMembersReachedByMembersInSingleExtCert += parseFloat(((detailedDistanceQualityExt.nbReached/membersList.length)*100).toFixed(2));
+
+				// Calculer la qualité du membre courant s'il n'y avait pas de référents (autrement di si tout les membres était référents)
+				//let membersQualityIfNoSentries = ((detailedDistanceQualityExt.nbReached/membersList.length)/conf.xpercent).toFixed(2);
+				//console.log("membersQualityIfNoSentries[%s] = %s", membersList[m].uid, membersQualityIfNoSentries);
+				if (membersQuality(constants.QUALITY_CACHE_ACTION.GET_QUALITY, membersList[m].wotb_id, -1) >= 1.0) {
+					proportionMembersWithQualityUpper1IfNoSentries++;
 				}
 				
 				// Nettoyer la wot temporaire
@@ -470,14 +481,21 @@ module.exports = (req, res, next) => co(function *() {
 		{ 
 			for (const member of membersList)
 			{
-				tabSort.push(membersQualityExt[member.uid]);
+				tabSort.push(membersQuality(constants.QUALITY_CACHE_ACTION.GET_QUALITY, member.wotb_id));
 			}
 		}
     else if (sort_by == "sigCount")
     { 
       for (const memberCertifsList of membersCertifsList)
       {
-        tabSort.push(memberCertifsList.length);
+		if (memberCertifsList.length > 0)
+		{
+			tabSort.push(memberCertifsList.length+1);
+		}
+		else
+		{
+			tabSort.push(1);
+		}
       }
     }
     else { res.status(500).send(`<pre><p>ERREUR : param <i>sort_by</i> invalid !</p></pre>`) } //
@@ -529,24 +547,9 @@ module.exports = (req, res, next) => co(function *() {
     
     if (reinitCache)
 		{
-			if (constants.USE_WOTB6)
-			{
-				// Calculate mean Members/Sentries ReachedBy Members/Sentries InSingleExtCert
-				if (countSentries > 0)
-				{
-					meanSentriesReachedBySentriesInSingleExtCert = parseFloat((meanSentriesReachedBySentriesInSingleExtCert/countSentries).toFixed(2));
-					meanMembersReachedBySentriesInSingleExtCert = parseFloat((meanMembersReachedBySentriesInSingleExtCert/countSentries).toFixed(2));
-				}
-				if (membersList.length > 0)
-				{
-					meanSentriesReachedByMembersInSingleExtCert = parseFloat((meanSentriesReachedByMembersInSingleExtCert/membersList.length).toFixed(2));
-					meanMembersReachedByMembersInSingleExtCert = parseFloat((meanMembersReachedByMembersInSingleExtCert/membersList.length).toFixed(2));
-				}
-				
-				//Calculate proportionMembersWithQualityUpper1 and proportionMembersWithQualityUpper1IfNoSentries
-				proportionMembersWithQualityUpper1 /= membersList.length;
-				proportionMembersWithQualityUpper1IfNoSentries /= membersList.length;
-			}
+			//Calculate proportionMembersWithQualityUpper1 and proportionMembersWithQualityUpper1IfNoSentries
+			proportionMembersWithQualityUpper1 /= membersList.length;
+			proportionMembersWithQualityUpper1IfNoSentries /= membersList.length;
 			
 			// recalculate meanCentrality and meanShortestsPathLength
 			if (centrality=='yes')
@@ -572,21 +575,23 @@ module.exports = (req, res, next) => co(function *() {
     // Sinon, printer le tableau html
     else
     {
-      
+	  let meansMembersQuality = membersQuality(constants.QUALITY_CACHE_ACTION.GET_MEANS);
+
       res.locals = {
 				host: req.headers.host.toString(),
-				USE_WOTB6: constants.USE_WOTB6,
 				// get parameters
-        days, mode, sort_by, order,
-				pendingSigs, centrality,
+        		days, mode, sort_by, order,
+				pendingSigs, centrality, nextYn,
+				numberOfRandomMembers, randomList,
 				
 				// page data
-        currentBlockchainTimestamp,
+        		currentBlockchainTimestamp,
 				limitTimestamp, nbMaxCertifs,
 				membersListFiltered: membersListOrdered.filter( member=> 
-				member.expireMembershipTimestamp < limitTimestamp 
-				&& member.expireMembershipTimestamp > currentBlockchainTimestamp
+					member.expireMembershipTimestamp < limitTimestamp 
+					&& member.expireMembershipTimestamp > currentBlockchainTimestamp
 				),
+				countSentries,
 				// currency parameters
 				xpercent: conf.xpercent,
 				sigWindow: conf.sigWindow,
@@ -597,13 +602,10 @@ module.exports = (req, res, next) => co(function *() {
 				
 				// members cache data
 				membersLastUptime,
-				membersQualityExt,
-				meanSentriesReachedBySentriesInSingleExtCert,
-				meanMembersReachedBySentriesInSingleExtCert,
-				meanSentriesReachedByMembersInSingleExtCert,
-				meanMembersReachedByMembersInSingleExtCert,
+				membersQuality,
 				proportionMembersWithQualityUpper1,
 				proportionMembersWithQualityUpper1IfNoSentries,
+				meansMembersQuality,
 				
 				// centrality cache data
 				lockCentralityCalc,
diff --git a/routes/membersCount.js b/routes/membersCount.js
index bba380baa0c4f79c5a3a8d9001e4f0d6aa54d3cf..b69854554865f7fc7251cbb946ae80d006e163ef 100755
--- a/routes/membersCount.js
+++ b/routes/membersCount.js
@@ -3,8 +3,9 @@
 const co = require('co')
 const timestampToDatetime = require(__dirname + '/../lib/timestampToDatetime')
 const getLang = require(__dirname + '/../lib/getLang')
+//const constants = require(__dirname + '/../lib/constants.js')
 
-const STEP_COUNT_MAX = 150;
+//const STEP_COUNT_MAX = 150;
 
 module.exports = (req, res, next) => co(function *() {
   
@@ -16,13 +17,13 @@ module.exports = (req, res, next) => co(function *() {
 		var pow = req.query.pow || 'no';
     
     // get lg file
-    const LANG = getLang(`${__dirname}/../lg/membersCount_${req.query.lg||'fr'}.txt`); //
+		const LANG = getLang(`${__dirname}/../lg/membersCount_${req.query.lg||constants.DEFAULT_LANGUAGE}.txt`);
     
     // get medianTime of beginBlock
     var beginBlock = yield duniterServer.dal.peerDAL.query('SELECT `medianTime`,`hash` FROM block WHERE `fork`=0 AND `number` = '+cache.beginBlock[0].number+' LIMIT 1');
     
     // get blockchain
-    var blockchain = yield duniterServer.dal.peerDAL.query('SELECT `hash`,`membersCount`,`medianTime`,`number`,`certifications`,`issuersCount`,`powMin` FROM block WHERE `fork`=0 AND `medianTime` <= '+cache.endBlock[0].medianTime+' AND `medianTime` >= '+beginBlock[0].medianTime+' ORDER BY `medianTime` ASC');
+    var blockchain = yield duniterServer.dal.peerDAL.query('SELECT `hash`,`membersCount`,`medianTime`,`number`,`certifications`,`issuersCount`,`powMin` FROM block WHERE `fork`=0 AND `medianTime` <= '+cache.endBlock[0].medianTime+' ORDER BY `medianTime` ASC');
 
     
     // Get blockchain timestamp
@@ -32,11 +33,11 @@ module.exports = (req, res, next) => co(function *() {
     // Traiter le cas stepUnit == "blocks"
     if (cache.stepUnit == "blocks")
     {
-      if ( Math.ceil((cache.endBlock[0].number-cache.beginBlock[0].number)/cache.step) > STEP_COUNT_MAX  ) { cache.step = Math.ceil((cache.endBlock[0].number-cache.beginBlock[0].number)/STEP_COUNT_MAX); }
+      if ( Math.ceil((cache.endBlock[0].number-cache.beginBlock[0].number)/cache.step) > constants.STEP_COUNT_MAX  ) { cache.step = Math.ceil((cache.endBlock[0].number-cache.beginBlock[0].number)/constants.STEP_COUNT_MAX); }
     }
     
     // Initialize nextStepTime, stepIssuerCount and bStep
-    var nextStepTime = blockchain[0].medianTime;
+    var nextStepTime = cache.beginBlock[0].medianTime;
     let stepIssuerCount = 0;
 		let stepPowMin = 0;
     let bStep = 0;
@@ -44,25 +45,32 @@ module.exports = (req, res, next) => co(function *() {
     // Adapt nextStepTime initial value
     switch (cache.stepUnit)
     {
-	  case "hours": nextStepTime -= (blockchain[0].medianTime % 3600); break;
-	  case "days":case "weeks":case "months":case "years": nextStepTime -= (blockchain[0].medianTime % 86400); break;
-	  default: break;
-    }
+			case "hours": nextStepTime -= (cache.beginBlock[0].medianTime % 3600); break;
+			case "days":case "weeks":case "months":case "years": nextStepTime -= (cache.beginBlock[0].medianTime % 86400); break;
+			default: break;
+		}
+
+		// Calculate initial cacheIndex value
+		let cacheIndex = 0;
+		while (cache.blockchain[cacheIndex].number <= cache.beginBlock[0].number && (cache.blockchain.length-1) > cacheIndex) { cacheIndex++; }
+		console.log("cache.blockchain[cacheIndex].number = %s", cache.blockchain[cacheIndex].number); // DEBUG
 
     // fill tabMembersCount
     var tabMembersCount = [];
-    let cacheIndex = 0;
-    for (let b=0;b<blockchain.length;b++)
+    for (let b=cache.beginBlock[0].number;b<blockchain.length;b++)
     {
       stepIssuerCount += blockchain[b].issuersCount;
 			stepPowMin += blockchain[b].powMin;
-      bStep++;
+			bStep++;
       
-      while (cacheIndex < (cache.blockchain.length-1) && cache.blockchain[cacheIndex+1].number <= b) { cacheIndex++; }
-
       // If achieve next step
-      if ( (cache.stepUnit == "blocks" && bStep == cache.step) || (cache.stepUnit != "blocks" && blockchain[b].medianTime >= nextStepTime))
+		if ( b==cache.beginBlock[0].number || (cache.stepUnit == "blocks" && bStep == cache.step) || (cache.stepUnit != "blocks" && blockchain[b].medianTime >= nextStepTime/*(tabMembersCount[tabMembersCount.length-1].timestamp+cache.stepTime)*/))
       {
+				let blockIndex = b;//-cache.beginBlock[0].number;//b-blockchain[0].number;
+
+				// Calculate if increment cacheIndex
+				while ((cache.blockchain.length-1) > cacheIndex && cache.blockchain[cacheIndex].number <= b) { cacheIndex++; }
+
 				let previousDateTime = "";
 				if(tabMembersCount.length > 0)
 				{
@@ -70,7 +78,7 @@ module.exports = (req, res, next) => co(function *() {
 				}
 				else
 				{
-					previousDateTime = timestampToDatetime(blockchain[0].medianTime);
+					previousDateTime = timestampToDatetime(cache.beginBlock[0].medianTime);
 				}
 				let dateTime = "";
 				if (cache.stepUnit != "blocks")
@@ -79,11 +87,11 @@ module.exports = (req, res, next) => co(function *() {
 					{
 						switch (cache.stepUnit)
 						{
-							case "hours": dateTime = previousDateTime+" - "+timestampToDatetime(blockchain[b].medianTime, cache.onlyDate); break;
-							case "days": dateTime = previousDateTime+" - "+timestampToDatetime(blockchain[b].medianTime-(cache.stepTime/cache.step), cache.onlyDate); break;
-							case "weeks": dateTime = previousDateTime+" - "+timestampToDatetime(blockchain[b].medianTime, cache.onlyDate); break;
-							case "months": dateTime = previousDateTime+" - "+timestampToDatetime(blockchain[b].medianTime, cache.onlyDate); break;
-							case "years": dateTime = previousDateTime+" - "+timestampToDatetime(blockchain[b].medianTime, cache.onlyDate); break;
+							case "hours": dateTime = previousDateTime+" - "+timestampToDatetime(blockchain[blockIndex].medianTime, cache.onlyDate); break;
+							case "days": dateTime = previousDateTime+" - "+timestampToDatetime(blockchain[blockIndex].medianTime-(cache.stepTime/cache.step), cache.onlyDate); break;
+							case "weeks": dateTime = previousDateTime+" - "+timestampToDatetime(blockchain[blockIndex].medianTime, cache.onlyDate); break;
+							case "months": dateTime = previousDateTime+" - "+timestampToDatetime(blockchain[blockIndex].medianTime, cache.onlyDate); break;
+							case "years": dateTime = previousDateTime+" - "+timestampToDatetime(blockchain[blockIndex].medianTime, cache.onlyDate); break;
 						}
 					}
 					else
@@ -94,10 +102,10 @@ module.exports = (req, res, next) => co(function *() {
 				
 				// push tabMembersCount
 				tabMembersCount.push({
-						blockNumber: blockchain[b].number,
-						timestamp: blockchain[b].medianTime,
+						blockNumber: blockchain[blockIndex].number,
+						timestamp: blockchain[blockIndex].medianTime,
 						dateTime: dateTime,
-						membersCount: blockchain[b].membersCount,
+						membersCount: blockchain[blockIndex].membersCount,
 						sentriesCount: cache.blockchain[cacheIndex].sentries,
 						issuersCount: parseInt(stepIssuerCount/bStep),
 						powMin: parseInt(stepPowMin/bStep)
@@ -178,17 +186,23 @@ module.exports = (req, res, next) => co(function *() {
         tabMembersCount,
         begin: cache.beginBlock[0].number,
         end: cache.endBlock[0].number,
-        form: `${LANG["BEGIN"]} #<input type="number" name="begin" value="${cache.beginBlock[0].number}" min="0"> - ${LANG["END"]} #<input type="number" name="end" value="${cache.endBlock[0].number}" > - 		${LANG["STEP"]} <input type="number" name="step" value="${cache.step}" min="1">
+        form: `${LANG["BEGIN"]} #<input type="number" name="begin" value="${cache.beginBlock[0].number}" min="0" size="7" style="width:60px;"> - ${LANG["END"]} #<input type="number" name="end" value="${cache.endBlock[0].number}" size="7" style="width:60px;"> - 		${LANG["STEP"]} <input type="number" name="step" value="${cache.step}" min="1" size="4" style="width:50px;">
 					<select name="stepUnit">
-						<option name="stepUnit" value ="blocks"${cache.stepUnit == 'blocks' ? 'selected' : ''}>${LANG["BLOCKS"]}
-						<option name="stepUnit" value ="hours"${cache.stepUnit == 'hours' ? 'selected' : ''}>${LANG["HOURS"]}
+						<option name="stepUnit" value ="blocks" ${cache.stepUnit == 'blocks' ? 'selected' : ''}>${LANG["BLOCKS"]}
+						<option name="stepUnit" value ="hours" ${cache.stepUnit == 'hours' ? 'selected' : ''}>${LANG["HOURS"]}
 						<option name="stepUnit" value ="days" ${cache.stepUnit == 'days' ? 'selected' : ''}>${LANG["DAYS"]}
 						<option name="stepUnit" value ="weeks" ${cache.stepUnit == 'weeks' ? 'selected' : ''}>${LANG["WEEKS"]}
 						<option name="stepUnit" value ="months" ${cache.stepUnit == 'months' ? 'selected' : ''}>${LANG["MONTHS"]}
 						<option name="stepUnit" value ="years" ${cache.stepUnit == 'years' ? 'selected' : ''}>${LANG["YEARS"]}
-					</select>`,
+					</select> - ${LANG["MAX"]} <input type="number" name="nbMaxPoints" value="${cache.nbMaxPoints}" min="1" size="4" style="width:50px;"> ${LANG["POINTS"]} (${LANG["REGULATE_BY_ADAPTING"]} 
+					<select name="adaptMaxPoints">
+						<option name="adaptMaxPoints" value ="begin"> ${LANG["BEGIN"]}
+						<option name="adaptMaxPoints" value ="step" ${cache.adaptMaxPoints == 'step' ? 'selected' : ''}> ${LANG["STEP"]}
+						<option name="adaptMaxPoints" value ="end" ${cache.adaptMaxPoints == 'end' ? 'selected' : ''}> ${LANG["END"]}
+					</select>)`,
 				description: `${LANG["DESCRIPTION1"]+'<br>'+LANG["DESCRIPTION2"]+'<b>'+cache.Yn+'</b>.'}`,
-				form2: `<input type="checkbox" name="pow" value="yes" ${pow == 'yes' ? 'checked' : ''}> ${LANG["SHOW_POW_MIN"]}`,
+				form2: `
+					<input type="checkbox" name="pow" value="yes" ${pow == 'yes' ? 'checked' : ''}> ${LANG["SHOW_POW_MIN"]}`,
         chart: {
           type: 'line',
           data: {
diff --git a/routes/monetaryMass.js b/routes/monetaryMass.js
index 6ca6471b4cb7d034aeea255fdae2b43ada98e108..90da810fd6bf08bc818b178e41eb79ed2f8e63ed 100755
--- a/routes/monetaryMass.js
+++ b/routes/monetaryMass.js
@@ -2,6 +2,7 @@
 
 const co = require('co')
 const timestampToDatetime = require(__dirname + '/../lib/timestampToDatetime')
+const getLang = require(__dirname + '/../lib/getLang')
 
 module.exports = (req, res, next) => co(function *() {
   
@@ -9,9 +10,16 @@ module.exports = (req, res, next) => co(function *() {
   
   try {
     // get GET parameters
-    var begin = req.query.begin >= 2 && req.query.begin || 2;// Default Value
-    var end = req.query.end || -1;// Default Value is current timestamp
+    var begin = req.query.begin >= 2 && req.query.begin || 2; // Default Value
+    var end = req.query.end || -1; // Default Value is current timestamp
+    var unit = req.query.unit || 'relative';
     var format = req.query.format || 'HTML';
+
+    // get lg file
+    const LANG = getLang(`${__dirname}/../lg/monetaryMass_${req.query.lg||constants.DEFAULT_LANGUAGE}.txt`);
+
+    // calculate meanMonetaryMassAtFullCurrency
+    const meanMonetaryMassAtFullCurrency = Math.ceil((1/duniterServer.conf.c)*(duniterServer.conf.dtReeval / duniterServer.conf.dt));
     
     // get beginBlock and endBlock
     var beginBlock = yield duniterServer.dal.peerDAL.query('SELECT `medianTime` FROM block WHERE `number` = '+begin+' LIMIT 1');
@@ -60,8 +68,7 @@ module.exports = (req, res, next) => co(function *() {
           membersCount: blockchain[b].membersCount,
           monetaryMass: parseInt(blockchain[b].monetaryMass / 100),
           monetaryMassPerMembers: parseFloat(((blockchain[b].monetaryMass / 100) / blockchain[b].membersCount).toFixed(2)),
-          relativeMonetaryMass: 0,
-          relativeMonetaryMassPerMembers: 0
+          derivedChoiceMonetaryMass: 0
         });
       
         if ( blockchain[b].dividend > 0 )
@@ -72,11 +79,20 @@ module.exports = (req, res, next) => co(function *() {
       }
     }
     
-    // calculate relativMonetaryMass
+    // calculate choiceMonetaryMass and derivedChoiceMonetaryMass
     for (let i=0;i<tabCurrency.length;i++)
     {
-      tabCurrency[i].relativeMonetaryMass = parseFloat(((tabCurrency[i].monetaryMass / currentDividend) * 100).toFixed(2));
-      tabCurrency[i].relativeMonetaryMassPerMembers = parseFloat(((tabCurrency[i].monetaryMassPerMembers / currentDividend) * 100).toFixed(2));
+      if (unit == "relative")
+      {
+        tabCurrency[i].monetaryMass = parseFloat(((tabCurrency[i].monetaryMass / currentDividend) * 100).toFixed(2));
+        tabCurrency[i].monetaryMassPerMembers = parseFloat(((tabCurrency[i].monetaryMassPerMembers / currentDividend) * 100).toFixed(2));
+      }
+      else if  (unit == "percentOfFullCurrency")
+      {
+        tabCurrency[i].monetaryMass = parseFloat((((tabCurrency[i].monetaryMassPerMembers / currentDividend) / meanMonetaryMassAtFullCurrency) * 10000).toFixed(2));
+        tabCurrency[i].monetaryMassPerMembers = tabCurrency[i].monetaryMass;
+      }
+      if (i>0) { tabCurrency[i].derivedChoiceMonetaryMass = parseFloat((((tabCurrency[i].monetaryMass / tabCurrency[i-1].monetaryMass) - 1.0) * 100).toFixed(2)); }
     }
     
     // Si le client demande la réponse au format JSON, le faire
@@ -85,64 +101,72 @@ module.exports = (req, res, next) => co(function *() {
     else
     {
       // GET parameters
-      var unit = req.query.unit == 'quantitative' ? 'quantitative' : 'relative';
-      var massByMembers = req.query.massByMembers == 'no' ? 'no' : 'yes';
-      var type = req.query.type == 'linear' ? 'linear' : 'logarithmic';
-      
-      
+      var massByMembers = req.query.massByMembers == 'no' && unit != "percentOfFullCurrency" ? 'no' : 'yes';
+      var type = req.query.type || 'logarithmic';
+      if (unit == "percentOfFullCurrency") { type = 'linear'; }
+      if (type != 'linear') { type = 'logarithmic'; }
     
       // Define full currency description
-      let meanMonetaryMassAtFullCurrency = Math.ceil((1/duniterServer.conf.c)*(duniterServer.conf.dtReeval / duniterServer.conf.dt));
-      var fullCurrency = "The currency will be full when the money supply by member will be worth <b>"+meanMonetaryMassAtFullCurrency
-	  +" DU</b> (because 1/c * dtReeval/dt = <b>"+meanMonetaryMassAtFullCurrency+" DU</b>)<br>"
-	  +"Currently, 1 DU<sub>"+duniterServer.conf.currency+"</sub> = <b>"+(currentDividend/100)+"</b> "+duniterServer.conf.currency+" and we have <b>"
-	  +endBlock[0].membersCount+"</b> members. Thus in full currency we would have a total money supply of <b>"
+      var fullCurrency = LANG['DESC1']+" <b>"+meanMonetaryMassAtFullCurrency
+	  +" "+LANG['UD']+"</b> ("+LANG['FULL_CURRENCY_FORMULA']+" = <b>"+meanMonetaryMassAtFullCurrency+" "+LANG['UD']+"</b>)<br>"
+	  +LANG['CURRENTLY']+", 1 "+LANG['UD']+"<sub>"+duniterServer.conf.currency+"</sub> = <b>"+(currentDividend/100)+"</b> "+duniterServer.conf.currency+" "+LANG['AND_WE_HAVE']+" <b>"
+	  +endBlock[0].membersCount+"</b> "+LANG['DESC2']+" <b>"
 	  +(meanMonetaryMassAtFullCurrency*currentDividend*endBlock[0].membersCount/100)+"</b> "+duniterServer.conf.currency
-	  +" (<b>"+(meanMonetaryMassAtFullCurrency*currentDividend/100)+"</b> "+duniterServer.conf.currency+"/member)." ;
+	  +" (<b>"+(meanMonetaryMassAtFullCurrency*currentDividend/100)+"</b> "+duniterServer.conf.currency+"/"+LANG['MEMBER']+")." ;
 	  
       // Define max yAxes
       var maxYAxes = meanMonetaryMassAtFullCurrency;
+      let indexEnd = tabCurrency.length-1;
       if (unit == "quantitative") { maxYAxes = maxYAxes*currentDividend/100; }
-      if (massByMembers == "no") { maxYAxes = maxYAxes*endBlock[0].membersCount; }
+      if (unit == "percentOfFullCurrency") { maxYAxes = 100; }
+      else if (massByMembers == "no") { maxYAxes = maxYAxes*endBlock[0].membersCount; }
       
       res.locals = {
-	 host: req.headers.host.toString(),
-         tabCurrency,
-	 currentDividend,
-         begin, 
-         end,
-         unit,
-         massByMembers,
-	 type,
-         form: `Begin #<input type="number" name="begin" value="${begin}"> - End #<input type="number" name="end" value="${end}"> <select name="unit">
-  <option name="unit" value ="quantitative">quantitative
-  <option name="unit" value ="relative" ${unit == 'relative' ? 'selected' : ''}>relative
-</select> <select name="massByMembers">
-  <option name="massByMembers" value ="yes">mass by members
-  <option name="massByMembers" value ="no" ${massByMembers == 'no' ? 'selected' : ''}>total mass
-</select> <select name="type">
-  <option name="type" value ="logarithmic">logarithmic
-  <option name="type" value ="linear" ${type == 'linear' ? 'selected' : ''}>linear
-</select>`,
-	description: `${fullCurrency}`,
+	      host: req.headers.host.toString(),
+        tabCurrency,
+	      currentDividend,
+        begin, 
+        end,
+        unit,
+        massByMembers,
+	      type,
+        form: `${LANG['BEGIN']} #<input type="number" name="begin" value="${begin}"> - ${LANG['END']} #<input type="number" name="end" value="${end}"> <select name="unit">
+            <option name="unit" value ="quantitative">${LANG['QUANTITATIVE']}
+            <option name="unit" value ="relative" ${unit == 'relative' ? 'selected' : ''}>${LANG['RELATIVE']}
+            <option name="unit" value ="percentOfFullCurrency" ${unit == 'percentOfFullCurrency' ? 'selected' : ''}>${LANG['PERCENT_OF_FULL_CURRENCY']}
+          </select> <select name="massByMembers">
+            <option name="massByMembers" value ="yes">${LANG['MASS_BY_MEMBERS']}
+            <option name="massByMembers" value ="no" ${massByMembers == 'no' ? 'selected' : ''}>${LANG['TOTAL_MASS']}
+          </select> <select name="type">
+            <option name="type" value ="logarithmic">${LANG['LOGARITHMIC']}
+            <option name="type" value ="linear" ${type == 'linear' ? 'selected' : ''}>${LANG['LINEAR']}
+          </select>`,
+	      description: `${fullCurrency}`,
         chart: {
           type: 'bar',
           data: {
             labels: tabCurrency.map( item=> item.dateTime ),
+            //yLabels: tabCurrency.map( item=> item.monetaryMass, item=>derivedChoiceMonetaryMass),
             datasets: [{
-              label: `#${unit == "relative" ? "DUğ1" : 'Ğ1'}${massByMembers == "yes" ? '/member' : ''}`,
-              data: unit == 'quantitative' 
-                ? tabCurrency.map( item=>
+              //yAxisID: 1,
+              label: `${unit == "percentOfFullCurrency" ? `${LANG['MONETARY_MASS']} (${LANG['IN_PERCENT_OF_FULL_CURRENCY']})`:`#${unit == "relative" ? LANG['UD']+"ğ1" : 'Ğ1'}${massByMembers == "yes" ? '/'+LANG['MEMBER'] : ''}`}`,
+              data: tabCurrency.map( item=>
                     massByMembers == "no" 
                     ? item.monetaryMass 
-                    : item.monetaryMassPerMembers)
-                : tabCurrency.map( item=>
-                    massByMembers == "no" 
-                    ? item.relativeMonetaryMass 
-                    : item.relativeMonetaryMassPerMembers),
+                    : item.monetaryMassPerMembers),
               backgroundColor: 'rgba(54, 162, 235, 0.5)',
               borderColor: 'rgba(54, 162, 235, 1)',
               borderWidth: 1
+            },
+            {
+              //yAxisID: 2,
+              label: LANG['PERCENT_VARIATION_MONETARY_MASS'],
+              data: tabCurrency.map( item=> item.derivedChoiceMonetaryMass),
+              backgroundColor: 'rgba(0, 162, 0, 0.5)',
+              borderColor: 'rgba(0, 162, 0, 1)',
+              borderWidth: 1,
+              type: 'line',
+              fill: false
             }]
           },
           options: {
@@ -154,20 +178,33 @@ module.exports = (req, res, next) => co(function *() {
             // },
             title: {
               display: true,
-              text: `${unit == "relative" ? "DUğ1" : 'Ğ1'} Monetary Mass ${massByMembers == "yes" ? 'by members ' : ''}in the range #${begin}-#${end  }`
+              text: `${unit == "percentOfFullCurrency" ? LANG['MONETARY_MASS']+' '+LANG['IN_PERCENT_OF_FULL_CURRENCY']:`${unit == "relative" ? LANG['UD']+"ğ1 " : 'Ğ1 '} ${massByMembers == "yes" ? LANG['BY_MEMBER']: ''}`} ${LANG['IN_THE_RANGE']} #${begin}-#${end  }`
             },
             legend: {
-              display: false
+              display: true
             },
             scales: {
               yAxes: [{
-		type: type,
+                //yAxisID: 1,
+		            type: type,
                 position: 'left',
                 ticks: {
-                    min: 1,
-                    max: maxYAxes
+                    callback: function(value, index, values) {//needed to change the scientific notation results from using logarithmic scale
+                            return Number(value.toString()); //pass tick values as a string into Number function
+                    },
+                    max: maxYAxes,
+                }
+              }/*,
+              {
+                //yAxisID: 2,
+		            type: type,
+                position: 'right',
+                ticks: {
+                    callback: function(value, index, values) {//needed to change the scientific notation results from using logarithmic scale
+                            return Number(value.toString()); //pass tick values as a string into Number function
+                    }
                 }
-              }]
+              }*/]
             }
           }
         }
diff --git a/routes/tools/membersQuality.js b/routes/tools/membersQuality.js
new file mode 100644
index 0000000000000000000000000000000000000000..bc65860ee6057ca903b53339dbaec10662517681
--- /dev/null
+++ b/routes/tools/membersQuality.js
@@ -0,0 +1,113 @@
+const constants = require(__dirname + '/../../lib/constants')
+
+// membersQuality cache
+var lastUpgradeTime = 0;
+var wot = null;
+var membersCount = 0;
+var sentriesCount = 0;
+var conf = {
+	dSen : 0,
+	stepMax: 0,
+	xprecent: 1.0
+};
+var tabMembersQuality = [];
+var tabMembersQualityIfNoSentries = [];
+var tabMembersQualityDetailedDistance = [];
+var meansCalculate = false;
+var means = {
+	meanSentriesReachedBySentries: 0,
+	meanMembersReachedBySentries: 0,
+	meanSentriesReachedByMembers: 0,
+	meanMembersReachedByMembers: 0
+};
+
+module.exports = function membersQuality(action, wotb_id = 0, dSen = 0, stepMax = 0, xpercent = 0, wotCopy = null) {
+
+  	if (action == constants.QUALITY_CACHE_ACTION.GET_QUALITY) {
+		if (typeof(tabMembersQuality[wotb_id])=='undefined')
+		{
+			// Si le wotb_id n'existe pas, renvoyer -1
+			if (wotb_id > membersCount)
+			{
+				return -1;
+			}
+
+			// Récupérer les informations détaillés de distance pour une nouvelle identité qui ne serait certifiée que par le membre courant (ce qui équivaut à récupérer les informations de distance pour le membre courant en décrémentant stepMax de 1)
+			let detailedDistance = wot.detailedDistance(wotb_id, conf.dSen, conf.stepMax-1, conf.xpercent);
+
+			// Calculer la qualité du membre
+			tabMembersQuality[wotb_id] = parseFloat(((detailedDistance.nbSuccess/detailedDistance.nbSentries)/conf.xpercent).toFixed(2));
+			tabMembersQualityIfNoSentries[wotb_id] = parseFloat(((detailedDistance.nbReached/membersCount)/conf.xpercent).toFixed(2));
+
+			if (dSen > 0)
+			{
+				means.meanSentriesReachedBySentries += parseFloat(((detailedDistance.nbSuccess/detailedDistance.nbSentries)*100).toFixed(2));
+				means.meanMembersReachedBySentries += parseFloat(((detailedDistance.nbReached/membersCount)*100).toFixed(2));
+			}
+			means.meanSentriesReachedByMembers += parseFloat(((detailedDistance.nbSuccess/detailedDistance.nbSentries)*100).toFixed(2));
+			means.meanMembersReachedByMembers += parseFloat(((detailedDistance.nbReached/membersCount)*100).toFixed(2));
+		}
+		if (dSen < 0)
+		{
+			return tabMembersQualityIfNoSentries[wotb_id];
+		}
+		else
+		{
+			return tabMembersQuality[wotb_id];
+		}
+	}
+	else if (action == constants.QUALITY_CACHE_ACTION.GET_MEANS) {
+		if (!meansCalculate)
+		{
+			// Calculate mean Members/Sentries ReachedBy Members/Sentries
+			if (sentriesCount > 0)
+			{
+				means.meanSentriesReachedBySentries = parseFloat((means.meanSentriesReachedBySentries/sentriesCount).toFixed(2));
+				means.meanMembersReachedBySentries = parseFloat((means.meanMembersReachedBySentries/sentriesCount).toFixed(2));
+			}
+			if (membersCount > 0)
+			{
+				means.meanSentriesReachedByMembers = parseFloat((means.meanSentriesReachedByMembers/membersCount).toFixed(2));
+				means.meanMembersReachedByMembers = parseFloat((means.meanMembersReachedByMembers/membersCount).toFixed(2));
+			}
+			meansCalculate = true;
+		}
+
+		return means;
+	}
+	else if (action == constants.QUALITY_CACHE_ACTION.INIT) {
+		if (wot != null)
+		{
+			wot.clear();
+			wot = null
+		}
+		if (wotCopy != null)
+		{
+			lastUpgradeTime = Math.floor(Date.now() / 1000);
+			
+			wot = wotCopy;
+			membersCount = wot.getWoTSize()-wot.getDisabled().length;
+			sentriesCount = wot.getSentries(dSen).length;
+			conf.dSen = dSen;
+			conf.stepMax = stepMax;
+			conf.xpercent = xpercent;
+
+			tabMembersQuality = [];
+			tabMembersQualityIfNoSentries = [];
+
+			meansCalculate = false;
+			means.meanSentriesReachedBySentries = 0;
+			means.meanMembersReachedBySentries = 0;
+			means.meanSentriesReachedByMembers = 0;
+			means.meanMembersReachedByMembers = 0;
+		}
+
+		return lastUpgradeTime;
+	}
+	else if (action == constants.QUALITY_CACHE_ACTION.GET_SENTRIES_COUNT) {
+	  return sentriesCount;
+	}
+	else if (action == constants.QUALITY_CACHE_ACTION.GET_D_SEN) {
+	  return conf.dSen;
+	}
+}
diff --git a/routes/willMembers.js b/routes/willMembers.js
index 42857c873e4ac5ae14cfbf8e32d0eda0c8f2d218..e6a66f0e4a83a7b1693c9d3eac7edb345b1ea901 100755
--- a/routes/willMembers.js
+++ b/routes/willMembers.js
@@ -5,8 +5,6 @@ const crypto = require('crypto')
 
 const constants = require(__dirname + '/../lib/constants')
 
-const wotb = (constants.USE_WOTB6) ? require('wotb'):null;
-
 const timestampToDatetime = require(__dirname + '/../lib/timestampToDatetime')
 
 // Préserver les résultats en cache
@@ -58,40 +56,37 @@ module.exports = (req, res, next) => co(function *() {
     let limitTimestamp = currentBlockchainTimestamp + (days*86400);
     
     // Alimenter wotb avec la toile de confiance 
-		const wotbInstance = (constants.USE_WOTB6) ? wotb.newFileInstance(duniterServer.home + '/wotb.bin'):duniterServer.dal.wotb;
+	const wotbInstance = duniterServer.dal.wotb;
 		
 		
-		// Vérifier si le cache doit être Réinitialiser
-		let reinitCache = (Math.floor(Date.now() / 1000) > (willMembersLastUptime + constants.MIN_WILLMEMBERS_UPDATE_FREQ));
+	// Vérifier si le cache doit être Réinitialiser
+	let reinitCache = (Math.floor(Date.now() / 1000) > (willMembersLastUptime + constants.MIN_WILLMEMBERS_UPDATE_FREQ));
 		
-		// Si le cache willMembers est dévérouillé, le vérouiller, sinon ne pas réinitialiser le cache
-		if (reinitCache && !lockWillMembers)
-		{
-			lockWillMembers = true;
-		}
-		else if(lockWillMembers)
-		{
-			reinitCache = false;
-		}
+	// Si le cache willMembers est dévérouillé, le vérouiller, sinon ne pas réinitialiser le cache
+	if (reinitCache && !lockWillMembers) {
+		lockWillMembers = true;
+	} else if(lockWillMembers) {
+		reinitCache = false;
+	}
 
-		if (reinitCache)
+	if (reinitCache)
     {
-      // Réinitialiser le cache
-      identitiesList = [];
-			idtysPendingCertifsList = [];
-      nbMaxCertifs = 0;
-      countMembersWithSigQtyValidCert = 0;
-      sentries = [];
-      sentriesIndex = [];
-      wotbIdIndex = [];
-			membersQualityExt = [];
-      willMembersLastUptime = Math.floor(Date.now() / 1000);
+      	// Réinitialiser le cache
+      	identitiesList = [];
+		idtysPendingCertifsList = [];
+      	nbMaxCertifs = 0;
+      	countMembersWithSigQtyValidCert = 0;
+      	sentries = [];
+      	sentriesIndex = [];
+      	wotbIdIndex = [];
+		membersQualityExt = [];
+      	willMembersLastUptime = Math.floor(Date.now() / 1000);
       
       // Récupérer la liste des membres référents
       sentries = wotbInstance.getSentries(dSen);
       
       // Récupérer la liste des identités en piscine
-      const resultQueryIdtys = yield duniterServer.dal.peerDAL.query('SELECT `buid`,`pubkey`,`uid`,`hash`,`expires_on` FROM identities_pending WHERE `member`=0');
+      const resultQueryIdtys = yield duniterServer.dal.peerDAL.query('SELECT `buid`,`pubkey`,`uid`,`hash`,`expires_on`,`revocation_sig` FROM identities_pending WHERE `member`=0');
 	
       // Récupérer pour chaque identité, l'ensemble des certifications qu'elle à reçue.
       for (let i=0;i<resultQueryIdtys.length;i++)
@@ -101,12 +96,12 @@ module.exports = (req, res, next) => co(function *() {
 				let idtyBlockNumber = idtyBlockStamp[0];
 	
 				// récupérer le medianTime et le hash du bloc d'émission de l'identité
-				let idtyEmittedBlock = yield duniterServer.dal.peerDAL.query('SELECT `medianTime`,`hash` FROM block WHERE `number`=\''+idtyBlockNumber+'\' LIMIT 1');
+				let idtyEmittedBlock = yield duniterServer.dal.peerDAL.query('SELECT `medianTime`,`hash` FROM block WHERE `number`=\''+idtyBlockNumber+'\' AND fork=0 LIMIT 1');
 				
 				// Récupérer l'identifiant wotex de l'identité (en cas d'identité multiple)
 				let idties = yield duniterServer.dal.idtyDAL.query('' +
-					'SELECT hash, uid, pub, wotb_id FROM i_index WHERE (uid = ? or pub = ?) ' +
-					'UNION ALL ' + 'SELECT hash, uid, pubkey as pub, (SELECT NULL) AS wotb_id FROM idty WHERE (uid = ? or pubkey = ?)', [resultQueryIdtys[i].uid, resultQueryIdtys[i].uid, resultQueryIdtys[i].uid, resultQueryIdtys[i].uid]);
+					'SELECT hash, uid, pub, wotb_id FROM i_index WHERE uid = ? ' +
+					'UNION ALL ' + 'SELECT hash, uid, pubkey as pub, (SELECT NULL) AS wotb_id FROM idty WHERE uid = ?', [resultQueryIdtys[i].uid, resultQueryIdtys[i].uid]);
 				let wotexId = '';
 				if (idties.length > 1)
 				{
@@ -123,6 +118,13 @@ module.exports = (req, res, next) => co(function *() {
 				if (typeof(idtyEmittedBlock[0]) == 'undefined' || idtyEmittedBlock[0].hash == idtyBlockStamp[1])
 				{ validIdtyBlockStamp = true; }
 
+				// vérifier si l'identité a été révoquée ou non
+				let idtyRevoked = false;
+				if (resultQueryIdtys[i].revocation_sig != null)
+				{
+				  idtyRevoked = true;
+				}	
+
 				// Stocker les informations de l'identité
 				identitiesList.push({
 						BlockNumber: idtyBlockNumber,
@@ -135,7 +137,8 @@ module.exports = (req, res, next) => co(function *() {
 						nbCert: 0,
 						nbValidPendingCert: 0,
 						registrationAvailability: 0,
-						validBlockStamp: validIdtyBlockStamp
+						validBlockStamp: validIdtyBlockStamp,
+						idtyRevoked: idtyRevoked
 				});
 				idtysPendingCertifsList.push(new Array());
 	
@@ -215,6 +218,7 @@ module.exports = (req, res, next) => co(function *() {
 										wotb_id: wotb_id,
 										issuerIsSentry: issuerIsSentry,
 										blockNumber: tmpQueryPendingCertifsList[j].block_number,
+										creationTimestamp: emittedBlock[0].medianTime,
 										timestampExpire: tmpQueryPendingCertifsList[j].expires_on,
 										timestampWritable: certTimestampWritable,
 										validBlockStamp: validBlockStamp
@@ -273,6 +277,7 @@ module.exports = (req, res, next) => co(function *() {
 							wotb_id: idtysPendingCertifsList[i][idMin].wotb_id,
 							issuerIsSentry: idtysPendingCertifsList[i][idMin].issuerIsSentry,
 							blockNumber: idtysPendingCertifsList[i][idMin].blockNumber,
+							creationTimestamp: idtysPendingCertifsList[i][idMin].creationTimestamp,
 							timestampExpire: idtysPendingCertifsList[i][idMin].timestampExpire,
 							timestampWritable: idtysPendingCertifsList[i][idMin].timestampWritable,
 							validBlockStamp: idtysPendingCertifsList[i][idMin].validBlockStamp
@@ -370,15 +375,10 @@ module.exports = (req, res, next) => co(function *() {
 						let tmpWot = wotbInstance.memCopy();
 						
 						// Mesurer la qualité externe de chaque emetteur de chaque certification
-						if (constants.USE_WOTB6)
-						{
-							for (const cert of idtysPendingCertifsList[idMax])
-							{
-								if ( typeof(membersQualityExt[cert.from]) == 'undefined' )
-								{
-									let detailedDistanceQualityExt = tmpWot.detailedDistance(cert.wotb_id, dSen, conf.stepMax-1, conf.xpercent);
-									membersQualityExt[cert.from] = ((detailedDistanceQualityExt.nbSuccess/detailedDistanceQualityExt.nbSentries)/conf.xpercent).toFixed(2);
-								}
+						for (const cert of idtysPendingCertifsList[idMax]) {
+							if (typeof (membersQualityExt[cert.from]) == 'undefined') {
+								let detailedDistanceQualityExt = tmpWot.detailedDistance(cert.wotb_id, dSen, conf.stepMax - 1, conf.xpercent);
+								membersQualityExt[cert.from] = ((detailedDistanceQualityExt.nbSuccess / detailedDistanceQualityExt.nbSentries) / conf.xpercent).toFixed(2);
 							}
 						}
 						
@@ -392,14 +392,14 @@ module.exports = (req, res, next) => co(function *() {
 							}
 						}
 						// Récupérer les données de distance du dossier d'adhésion de l'indentité idMax
-						let detailedDistance = (constants.USE_WOTB6) ? tmpWot.detailedDistance(pendingIdtyWID, dSen, conf.stepMax, conf.xpercent):tmpWot.isOutdistanced(pendingIdtyWID, dSen, conf.stepMax, conf.xpercent);
+						let detailedDistance = tmpWot.detailedDistance(pendingIdtyWID, dSen, conf.stepMax, conf.xpercent);
 
 						// Nettoyer la wot temporaire
 						tmpWot.clear();
 						
 						// Calculer percentSentriesReached et percentMembersReached
-						let percentSentriesReached = (constants.USE_WOTB6) ? parseFloat(((detailedDistance.nbSuccess/detailedDistance.nbSentries)*100).toFixed(2)):null;
-						let percentMembersReached = (constants.USE_WOTB6) ? parseFloat(((detailedDistance.nbReached/currentMembersCount)*100).toFixed(2)):null;
+						let percentSentriesReached = parseFloat(((detailedDistance.nbSuccess/detailedDistance.nbSentries)*100).toFixed(2));
+						let percentMembersReached = parseFloat(((detailedDistance.nbReached/currentMembersCount)*100).toFixed(2));
 						
 						// Pousser l'identité dans le tableau idtysListOrdered
 						idtysListOrdered.push({
@@ -415,11 +415,12 @@ module.exports = (req, res, next) => co(function *() {
 							percentMembersReached: percentMembersReached,
 							membership: membership,
 							pendingCertifications: idtysPendingCertifsList[idMax],
-							validBlockStamp: identitiesList[idMax].validBlockStamp
+							validBlockStamp: identitiesList[idMax].validBlockStamp,
+							idtyRevoked: identitiesList[idMax].idtyRevoked
 						});
 						
 						// Si le cache a été réinitialiser, recalculer les sommes meanSentriesReachedByIdtyPerCert et meanMembersReachedByIdtyPerCert
-						if (constants.USE_WOTB6 && reinitCache && identitiesList[idMax].nbValidPendingCert > 0)
+						if (reinitCache && identitiesList[idMax].nbValidPendingCert > 0)
 						{
 						  let nbReceiveCert = identitiesList[idMax].nbValidPendingCert;
 							meanSentriesReachedByIdtyPerCert[nbReceiveCert-1] += percentSentriesReached;
@@ -445,29 +446,22 @@ module.exports = (req, res, next) => co(function *() {
 				idtysListOrdered = idtysListOrdered2;
       }
       
-		if (reinitCache)
-		{
+	  if (reinitCache) {
 		  // Calculate meanSentriesReachedByIdtyPerCert and meanMembersReachedByIdtyPerCert
-			if (constants.USE_WOTB6)
-			{
-				for (let i=0;i<=nbMaxCertifs;i++)
-				{
-					if ( countIdtiesPerReceiveCert[i] > 0 )
-					{
-						meanSentriesReachedByIdtyPerCert[i] = parseFloat((meanSentriesReachedByIdtyPerCert[i]/countIdtiesPerReceiveCert[i]).toFixed(2));
-						meanMembersReachedByIdtyPerCert[i] = parseFloat((meanMembersReachedByIdtyPerCert[i]/countIdtiesPerReceiveCert[i]).toFixed(2));
-					}
-					else
-					{
-						meanSentriesReachedByIdtyPerCert[i] = 0.0;
-						meanMembersReachedByIdtyPerCert[i] = 0.0;
-					}
-				}
-			}
-			
-			// Dévérouiller le cache willMembers
-			lockWillMembers = false;
-		}
+		  for (let i = 0; i <= nbMaxCertifs; i++) {
+			  if (countIdtiesPerReceiveCert[i] > 0) {
+				  meanSentriesReachedByIdtyPerCert[i] = parseFloat((meanSentriesReachedByIdtyPerCert[i] / countIdtiesPerReceiveCert[i]).toFixed(2));
+				  meanMembersReachedByIdtyPerCert[i] = parseFloat((meanMembersReachedByIdtyPerCert[i] / countIdtiesPerReceiveCert[i]).toFixed(2));
+			  }
+			  else {
+				  meanSentriesReachedByIdtyPerCert[i] = 0.0;
+				  meanMembersReachedByIdtyPerCert[i] = 0.0;
+			  }
+		  }
+
+		  // Dévérouiller le cache willMembers
+		  lockWillMembers = false;
+	  }
     
     // Si le client demande la réponse au format JSON, le faire
     if (format == 'JSON')
@@ -481,7 +475,6 @@ module.exports = (req, res, next) => co(function *() {
       res.locals = {
         // Les varibles à passer au template
 				host: req.headers.host.toString(),
-				USE_WOTB6: constants.USE_WOTB6,
 				// get parameters
         days, sort_by, order, sortSig,
         showIdtyWithZeroCert,
diff --git a/routes/wotex.js b/routes/wotex.js
index 7c3222f6aa7058409b7d1cfa0574b30350e1da8a..828adb22eb97ca54768e6316600b4e4c90668ce2 100755
--- a/routes/wotex.js
+++ b/routes/wotex.js
@@ -16,7 +16,7 @@ module.exports = (req, res, next) => co(function *() {
       var help = req.query.help || 'yes';
       
       // get lg file
-      const LANG = getLang(`${__dirname}/../lg/wotex_${req.query.lg||'fr'}.txt`);
+      const LANG = getLang(`${__dirname}/../lg/wotex_${req.query.lg||constants.DEFAULT_LANGUAGE}.txt`);
       
       // Trouve les points de contrôle efficacement grâce au module C (nommé "wotb")
       const wotb = duniterServer.dal.wotb.memCopy();
diff --git a/views/Chart.html b/views/Chart.html
index 3a695de2d8b441f8210e55cdb5da895ee9513fd6..8c1236dd93d9924ac3c067a10aa32b377393d3fd 100755
--- a/views/Chart.html
+++ b/views/Chart.html
@@ -1,29 +1,11 @@
 ${(host.substr(host.length-6,6) == '.onion') ? HTML_TOR_HEAD:HTML_HEAD}
-  <title>${currencyName}-monit</title>
+  <title>${currencyName}-monit : ${MENU_LANG[pageName]}</title>
 </head>
 <body>
 
 <!-- Afficher le menu -->
 <script src=${(host.substr(host.length-6,6) == '.onion') ? "http://722iprlhm7pw4mx7.onion/js/Chart.min.js":"https://librelois.fr/js/Chart.min.js"}></script>
-<table align="center" width="100%">
-  <tr>
-    <td><a href="willMembers?lg=${MENU_LANG['LG']}${(typeof(help) != 'undefined' && help == 'no') ? '&help=no':''}">${MENU_LANG["WILL_MEMBERS"]}</a></td>
-    <td><a href="members?lg=${MENU_LANG['LG']}${(typeof(help) != 'undefined' && help == 'no') ? '&help=no':''}">${MENU_LANG["MEMBERS"]}</a></td>
-    <td><a href="membersCount?lg=${MENU_LANG['LG']}${(typeof(help) != 'undefined' && help == 'no') ? '&help=no':''}">${MENU_LANG["MEMBERS_COUNT"]}</a></td>
-    <td><a href="blockCount?lg=${MENU_LANG['LG']}${(typeof(help) != 'undefined' && help == 'no') ? '&help=no':''}">${MENU_LANG["BLOCK_COUNT"]}</a></td>
-    <td><a href="monetaryMass?lg=${MENU_LANG['LG']}${(typeof(help) != 'undefined' && help == 'no') ? '&help=no':''}">${MENU_LANG["MONETARY_MASS"]}</a></td>
-    <td><a href="wotex?lg=${MENU_LANG['LG']}${(typeof(help) != 'undefined' && help == 'no') ? '&help=no':''}">${MENU_LANG["WOTEX"]}</a></td>
-    <td><a href="about?lg=${MENU_LANG['LG']}${(typeof(help) != 'undefined' && help == 'no') ? '&help=no':''}">${MENU_LANG["ABOUT"]}</a></td>
-    <td>
-      <form action="" method="GET">
-	<select name="lg" onchange="this.form.submit()">
-	  <option name="lg" value="fr" ${MENU_LANG['LG'] == 'fr' ? 'selected' : ''}>FR
-	  <option name="lg" value="en" ${MENU_LANG['LG'] == 'en' ? 'selected' : ''}>EN
-	</select>
-    </td>
-</tr>
-</table>
-<hr>
+${printMenu(MENU_LANG, help, pageName)}
 
 <!-- Afficher le formulaire -->
 ${form||''} <input type="submit" value="${LANG['SUBMIT_BUTTON']}"><br>${(typeof(form2) != 'undefined') ? form2:''}</form><br>
diff --git a/views/HEAD.html b/views/HEAD.html
index 3436a2795c4f8da18c15d282e34fe2d9e443c30b..4ce1c8115c223024c62d5cffd5038c9a028c4c13 100755
--- a/views/HEAD.html
+++ b/views/HEAD.html
@@ -12,4 +12,58 @@
       html, body, *, pre {
         font-family: "Ubuntu";
       }
+      ul {
+        list-style-type: none;
+        margin: 0;
+        padding: 0;
+        overflow: hidden;
+        background-color: #333;
+      }
+      .menu li {
+        float: left;
+      }
+      li a {
+          display: block;
+          color: white;
+          text-align: center;
+          padding: 14px 16px;
+          text-decoration: none;
+      }
+      li a:hover:not(.active) {
+          background-color: #111;
+      }
+      .active {
+          background-color: #4CAF50;
+      }
+      span[data-tip]{
+        border-bottom: 1px dotted #000;
+      }
+      [data-tip]{
+        display: inline-block;
+        position: relative;
+      }
+      [data-tip]:hover:before {
+        content: attr(data-tip);
+        position: absolute;
+        padding: 0 8px;
+        height: 28px;
+        line-height: 28px;
+        background-color: rgba(0, 0, 0, 0.8);
+        left: -10px;
+        top: -38px;
+        font-size: 14px;
+        border-radius: 3px;
+        white-space: nowrap;
+        color: #fff;
+        font-size: 11px;
+      }
+      [data-tip]:hover:after {
+        content: "";
+        position: absolute;
+        border-top: 8px solid rgba(0, 0, 0, 0.8);
+        border-left: 8px solid transparent;
+        border-right: 8px solid transparent;
+        left: 0;
+        top: -10px;
+      }
     </style>
\ No newline at end of file
diff --git a/views/about.html b/views/about.html
index 60d1c27c1f94e535bfbb08004b882387e85afd3d..464f5769f161d58c441416577cd03fb62a5aae57 100755
--- a/views/about.html
+++ b/views/about.html
@@ -1,38 +1,21 @@
 ${(host.substr(host.length-6,6) == '.onion') ? HTML_TOR_HEAD:HTML_HEAD}
-  <title>${currencyName}-monit</title>
+  <title>${currencyName}-monit : ${MENU_LANG['ABOUT']}</title>
 </head>
 <body>
   
 <!-- Afficher le menu -->
-<table align="center" width="100%">
-  <tr>
-    <td><a href="willMembers?lg=${MENU_LANG['LG']}${(typeof(help) != 'undefined' && help == 'no') ? '&help=no':''}">${MENU_LANG["WILL_MEMBERS"]}</a></td>
-    <td><a href="members?lg=${MENU_LANG['LG']}${(typeof(help) != 'undefined' && help == 'no') ? '&help=no':''}">${MENU_LANG["MEMBERS"]}</a></td>
-    <td><a href="membersCount?lg=${MENU_LANG['LG']}${(typeof(help) != 'undefined' && help == 'no') ? '&help=no':''}">${MENU_LANG["MEMBERS_COUNT"]}</a></td>
-    <td><a href="blockCount?lg=${MENU_LANG['LG']}${(typeof(help) != 'undefined' && help == 'no') ? '&help=no':''}">${MENU_LANG["BLOCK_COUNT"]}</a></td>
-    <td><a href="monetaryMass?lg=${MENU_LANG['LG']}${(typeof(help) != 'undefined' && help == 'no') ? '&help=no':''}">${MENU_LANG["MONETARY_MASS"]}</a></td>
-    <td><a href="wotex?lg=${MENU_LANG['LG']}${(typeof(help) != 'undefined' && help == 'no') ? '&help=no':''}">${MENU_LANG["WOTEX"]}</a></td>
-    <td><a href="about?lg=${MENU_LANG['LG']}${(typeof(help) != 'undefined' && help == 'no') ? '&help=no':''}">${MENU_LANG["ABOUT"]}</a></td>
-    <td>
-      <form action="" method="GET">
-	<select name="lg" onchange="this.form.submit()">
-	  <option name="lg" value="fr" ${MENU_LANG['LG'] == 'fr' ? 'selected' : ''}>FR
-	  <option name="lg" value="en" ${MENU_LANG['LG'] == 'en' ? 'selected' : ''}>EN
-	</select>
-    </td>
-</tr>
-</table>
-</select> 
+${printMenu(MENU_LANG, help, "ABOUT")}
 
 </form>
-<hr>
-<div align="center">
-  <br>
-  <a href="https://github.com/duniter/duniter-currency-monit/blob/master/LICENSE">License AGPL V 3.0</a><br>
-  <a href="https://github.com/duniter/duniter-currency-monit/">github repository</a>
+<div align="left">${LANG['VERSION']} : <a href="https://git.duniter.org/nodes/typescript/modules/duniter-currency-monit/tree/v0.4.11">0.4.11</a></div><br>
+<div align="left">${LANG['AUTHOR']} : <a href="https://github.com/librelois">Éloïs Librelois</a></div><br>
+<div align="left"><small>${LANG['CONTRIBUTORS']}: <a href="https://github.com/jytou">jytou</a> (translator), <a href="https://github.com/devingfx">devingfx</a> (frontend), <a href="https://github.com/c-geek">cgeek</a> (willMembers and wotex),<a href="https://github.com/M5oul">M5oul</a> (adjustments)</small></div><br>
+<div align="left">
+  ${LANG['LICENSE']} : <a href="https://github.com/duniter/duniter-currency-monit/blob/master/LICENSE">AGPL V 3.0</a><br>
+  <a href="https://git.duniter.org/nodes/typescript/modules/duniter-currency-monit">${LANG['GIT_REPOSITORY']}</a>
 </div><br>
-<div align="left">Version : <a href="https://github.com/duniter/duniter-currency-monit/releases/tag/0.3.7">module-0.3.7</a></div><br>
-<div align="left">Author : <a href="https://github.com/librelois">Éloïs Librelois</a></div><br>
-<div align="left">Contributors : <a href="https://github.com/jytou">jytou</a> (translator), <a href="https://github.com/devingfx">devingfx</a> (frontend), <a href="https://github.com/c-geek">cgeek</a> (willMembers and wotex),<a href="https://github.com/M5oul">M5oul</a> (adjustments)</div><br>
-<br>
-<div align="left">If you want you can <a href="?lg=${MENU_LANG['LG']}&help=no">disable help</a>.</div><br>
\ No newline at end of file
+<div align="left">${LANG['IF_YOU_WANT']} <a href="?lg=${MENU_LANG['LG']}&help=no">${LANG['DISABLE_HELP']}</a>.</div><br>
+<div align="left">${LANG['DONATE']} :<br>
+      <a href="https://g1.duniter.fr/#/app/transfer/D9D2zaJoWYWveii1JRYLVK3J4Z7ZH3QczoKrnQeiM6mx?comment=thank for currency-monit"><img src="https://librelois.fr/public/duniter_button.png"></a><br>
+    </div>
+<br>
\ No newline at end of file
diff --git a/views/members.html b/views/members.html
index df0c293d08f2eacd24c12f725d8ad7f15eae0bbe..462045c5c590858926962919ed65c154f8b0655a 100755
--- a/views/members.html
+++ b/views/members.html
@@ -1,38 +1,43 @@
 ${(host.substr(host.length-6,6) == '.onion') ? HTML_TOR_HEAD:HTML_HEAD}
-  <title>${currencyName}-monit</title>
+  <title>${currencyName}-monit : ${MENU_LANG['MEMBERS']}</title>
+  <script type="text/javascript">// <![CDATA[
+	var table = document.getElementById('table')
+	var filter = document.getElementById('filter')
+
+	/*filter.onchange = function() {
+		return filterRows(table, 1, 0, this.value);
+  }*/
+
+	// tableElem : HTMLElement
+	// rowIndex  : index du row pour commencer le filtrage (0 indexed)
+	// tableElem : index du col à prendre en compte (0 indexed)
+	// tableElem : lettre pour la comparaison
+	function filterRows(tableElem, rowIndex, colIndex, filterString) {
+		for (var i = rowIndex, val; i < tableElem.rows.length; ++i) {
+			val = tableElem.rows[i].cells[colIndex].firstChild.nodeValue;
+			if (val.substr(0,filterString.length).toLowerCase() != filterString.toLowerCase())
+				tableElem.rows[i].style.display = 'none';
+			else
+				tableElem.rows[i].style.display = '';
+		}  
+		return false;
+	}
+// ]]></script>
 </head>
 <body>
 
 <!-- Afficher le menu -->
-<table align="center" width="100%">
-  <tr>
-    <td><a href="willMembers?lg=${MENU_LANG['LG']}${(typeof(help) != 'undefined' && help == 'no') ? '&help=no':''}">${MENU_LANG["WILL_MEMBERS"]}</a></td>
-    <td><a href="members?lg=${MENU_LANG['LG']}${(typeof(help) != 'undefined' && help == 'no') ? '&help=no':''}">${MENU_LANG["MEMBERS"]}</a></td>
-    <td><a href="membersCount?lg=${MENU_LANG['LG']}${(typeof(help) != 'undefined' && help == 'no') ? '&help=no':''}">${MENU_LANG["MEMBERS_COUNT"]}</a></td>
-    <td><a href="blockCount?lg=${MENU_LANG['LG']}${(typeof(help) != 'undefined' && help == 'no') ? '&help=no':''}">${MENU_LANG["BLOCK_COUNT"]}</a></td>
-    <td><a href="monetaryMass?lg=${MENU_LANG['LG']}${(typeof(help) != 'undefined' && help == 'no') ? '&help=no':''}">${MENU_LANG["MONETARY_MASS"]}</a></td>
-    <td><a href="wotex?lg=${MENU_LANG['LG']}${(typeof(help) != 'undefined' && help == 'no') ? '&help=no':''}">${MENU_LANG["WOTEX"]}</a></td>
-    <td><a href="about?lg=${MENU_LANG['LG']}${(typeof(help) != 'undefined' && help == 'no') ? '&help=no':''}">${MENU_LANG["ABOUT"]}</a></td>
-    <td>
-      <form action="" method="GET">
-	<select name="lg" onchange="this.form.submit()">
-	  <option name="lg" value="fr" ${MENU_LANG['LG'] == 'fr' ? 'selected' : ''}>FR
-	  <option name="lg" value="en" ${MENU_LANG['LG'] == 'en' ? 'selected' : ''}>EN
-	</select>
-    </td>
-</tr>
-</table>
-<hr>
+${printMenu(MENU_LANG, help, "MEMBERS")}
 
 <!-- Afficher le formulaire -->
-<input type="number" name="d" value="${days}"/>${LANG["FORM1"]} <select name="sort_by">
+<input type="number" name="d" value="${days}"/> ${LANG["FORM1"]} <select name="sort_by">
 <option name="sort_by" value ="idtyWritten">${LANG["SORT_BY_IDTY_WRITTEN"]}
 <option name="sort_by" value ="expireMembership" ${sort_by == 'expireMembership' ? 'selected' : ''}>${LANG["SORT_BY_EXPIRE_MEMBERSHIP"]}
 <option name="sort_by" value ="lastRenewal" ${sort_by == 'lastRenewal' ? 'selected' : ''}>${LANG["SORT_LAST_RENEWAL"]}
 <option name="sort_by" value ="oldestSig" ${sort_by == 'oldestSig' ? 'selected' : ''}>${LANG["SORT_BY_OLDEST_SIG"]}
 <option name="sort_by" value ="lastSig" ${sort_by == 'lastSig' ? 'selected' : ''}>${LANG["SORT_BY_LAST_SIG"]}
 <option name="sort_by" value ="centrality" ${sort_by == 'centrality' ? 'selected' : ''}>${LANG["SORT_BY_CENTRALITY"]}
-${(USE_WOTB6) ? `<option name="sort_by" value ="quality" ${sort_by == 'quality' ? 'selected' : ''}>${LANG["SORT_BY_QUALITY"]}`:``}
+<option name="sort_by" value ="quality" ${sort_by == 'quality' ? 'selected' : ''}>${LANG["SORT_BY_QUALITY"]}
 <option name="sort_by" value ="sigCount" ${sort_by == 'sigCount' ? 'selected' : ''}>${LANG["SORT_BY_SIG_COUNT"]}
 </select> ${LANG["ORDER_BY"]} <select name="order">
 <option name="order" value ="asc"> ${LANG["ASC"]}
@@ -41,7 +46,9 @@ ${(USE_WOTB6) ? `<option name="sort_by" value ="quality" ${sort_by == 'quality'
 <input type="checkbox" name="centrality" value="yes">${LANG["CHECKBOX_CENTRALITY"]}.<br>
 <input type="checkbox" name="pendingSigs" value="yes" ${pendingSigs == 'yes' ? 'checked' : ''}>${LANG["CHECKBOX_PENDING_SIGS"]}.<br>
 <input type="checkbox" name="mode" value="emitted" ${mode == 'emitted' ? 'checked' : ''}>${LANG["CHECKBOX_MODE_SIG"]}.<br>
-</form>
+<input type="checkbox" name="nextYn" value="yes" ${nextYn == 'yes' ? 'checked' : ''}> ${LANG["NEXT_YN"]}<br>
+<input type="checkbox" name="randomList" value="yes" ${randomList == 'yes' ? 'checked' : ''}> ${LANG["RANDOM_LIST"]} 
+<input type="number" name="randomCounts" value="${numberOfRandomMembers}"/> ${LANG["MEMBERS"]}.<br>
 <hr>
 
 <!-- Afficher la légende et l'aide -->
@@ -76,27 +83,31 @@ ${(membersLastCentralityCalcTime==0) ? `
 	`}
 `}
 <br>
-${(USE_WOTB6) ? `
 	<table border="1">
 		<tr><td align='center' colspan='3'>${LANG["DATA_AT"]} ${timestampToDatetime(membersLastUptime)}</td></tr>
-		<tr><td align='center'>${LANG["meanMembersReachedByMembersInSingleExtCert"]}</td><td align='center'>${LANG["SENTRIES_REACHED"]}</td><td align='center'>${LANG["MEMBERS_REACHED"]}</td></tr>
-		<tr><td align='center'>${LANG["SENTRY_CERT"]}</td><td align='center'>${meanSentriesReachedBySentriesInSingleExtCert}%</td><td align='center'>${meanMembersReachedBySentriesInSingleExtCert}%</td></tr>
-		<tr><td align='center'>${LANG["MEMBER_CERT"]}</td><td align='center'><font color="${(meanSentriesReachedByMembersInSingleExtCert<xpercent) ? 'DarkRed' : 'blue' }"><b>${meanSentriesReachedByMembersInSingleExtCert}%</b></font></td><td align='center'><b>${meanMembersReachedByMembersInSingleExtCert}%</b></td></tr>
-		<tr><td align='center'><b>${LANG["MEAN_QUALITY"]}</b></td><td align='center'><font color="red"><b>${(meanSentriesReachedByMembersInSingleExtCert/(xpercent*100)).toFixed(2)}</b></font></td><td align='center'><b>${(meanMembersReachedByMembersInSingleExtCert/(xpercent*100)).toFixed(2)}</b></td></tr>
+		<tr><td align='center'>${LANG["meanMembersReachedByMembers"]}</td><td align='center'>${LANG["SENTRIES_REACHED"]}</td><td align='center'>${LANG["MEMBERS_REACHED"]}</td></tr>
+		<tr><td align='center'>${LANG["SENTRY_CERT"]}</td><td align='center'>${(meansMembersQuality.meanSentriesReachedBySentries).toFixed(2)}%</td><td align='center'>${(meansMembersQuality.meanMembersReachedBySentries).toFixed(2)}%</td></tr>
+		<tr><td align='center'>${LANG["MEMBER_CERT"]}</td><td align='center'><font ${(meansMembersQuality.meanSentriesReachedByMembers<xpercent) ? 'color="DarkRed"' : 'color="blue"' }><b>${meansMembersQuality.meanSentriesReachedByMembers}%</b></font></td><td align='center'><b>${meansMembersQuality.meanMembersReachedByMembers}%</b></td></tr>
+		<tr><td align='center'><b>${LANG["MEAN_QUALITY"]}</b></td><td align='center'><font color="red"><b>${(meansMembersQuality.meanSentriesReachedByMembers/(xpercent*100)).toFixed(2)}</b></font></td><td align='center'><b>${(meansMembersQuality.meanMembersReachedByMembers/(xpercent*100)).toFixed(2)}</b></td></tr>
 		<tr><td align='center'><b>${LANG["PROPORTION_MEMBERS_WITH_QUALITY_UPPER_1"]}</b></td><td align='center'><font color="red"><b>${(proportionMembersWithQualityUpper1*100).toFixed(2)}%</b></font></td><td align='center'><b>${(proportionMembersWithQualityUpper1IfNoSentries*100).toFixed(2)}%</b></td></tr>
 	</table>
 	<br>
-`:``}
 
 <!-- Afficher le currentBlockchainTimestamp -->
-<i>${LANG["CURRENT_BLOCKCHAIN_TIME"]} : ${timestampToDatetime(currentBlockchainTimestamp)}.</i><br>
+<i>${LANG["CURRENT_BLOCKCHAIN_TIME"]} : ${timestampToDatetime(currentBlockchainTimestamp)}.<br>
+<!-- Afficher le nombre de membres et de membres référents -->
+<b>${membersListFiltered.length}</b> ${LANG["MEMBERS"]} ${LANG["OF_WHICH"]} <b>${countSentries}</b> ${LANG['ARE_REFERRING_MEMBERS']} (<b>${((countSentries/membersListFiltered.length)*100).toFixed(2)}%</b>).</i><br>
 <br>
+<!-- Afficher le filtre des membres -->
+${LANG["MEMBER_FILTER"]} : <input type="text" name="filter" id="filter" value="" maxlength="20" onchange="filterRows(document.getElementById('table'),1,0,this.value);" onkeypress="this.onchange();" onpaste="this.onchange();" oninput="this.onchange();"/><br>
+</form>
 
 <!-- On parcour tout les membres pour afficher ceux dont la date d'expiration est dans moins de 'd' jours -->
 <b>${LANG["TABLE_TITLE"]} ${days} ${LANG["DAYS"]} :</b>
-<table border="1">
+<table id="table" border="1">
   <!-- Printer les nom des colonnes -->
   <tr>
+    <td align="center" style="display :none"></td>
     <td align="center">${LANG["COL_UID"]}</td>
     <td align="center">${LANG["COL_IDTY_WRITTEN_TIME"]}</td>
     <td align="center">${LANG["COL_LAST_RENEWAL"]}</td>
@@ -105,19 +116,16 @@ ${(USE_WOTB6) ? `
     <td style="background:#000000">-</td>
     <td align="left" colspan="${nbMaxCertifs}">${(mode=='emitted') ? LANG['COL_LIST_EMITTED_CERT']:LANG['COL_LIST_RECEIVED_CERT']} (${sort_by == 'lastSig' ? LANG["LAST2OLDEST"] : LANG["OLDEST2LAST"]})</td>
   </tr>
-  
   ${membersListFiltered
     .map( member=> `
       <!-- Printer la ligne -->
       <tr>
         ${(member.proportion = proportion(member.expireMembershipTimestamp,msValidity,0,120),'')}
-        <td align="center" style="background:hsla(${member.proportion}, 100%, 50%, 1)">
-          <b>${member.uid}</b><br>
+        <td align="center" style="display :none">${member.uid}</td>
+        <td align="center" style="background:hsla(${member.proportion}, 100%, 50%, 1)"><b>${member.uid}</b><br>
           
           ${(member.isSentry) ? `<font color="blue">${LANG['REFERRING_MEMBER']} : ${LANG['YES']}</font>`:`${LANG['REFERRING_MEMBER']} : ${LANG['NO']}`}<br>
-          ${(USE_WOTB6) ? `
-            ${LANG['QUALITY_EXT']} : <b>${(typeof(membersQualityExt[member.uid])=='undefined') ? `0.00`:membersQualityExt[member.uid]}</b><br>
-					`:``}
+            ${LANG['QUALITY_EXT']} : <b>${(typeof(membersQuality(0, member.wotb_id))=='undefined') ? `0.00`:membersQuality(0, member.wotb_id)}</b><br>
           <b>${(membersLastCentralityCalcTime==0) ? `${LANG['CENTRALITY']} : ?`:`
 						${LANG['CENTRALITY']} : <b>${(typeof(membersCentrality[member.wotb_id])=='undefined') ? `0`:membersCentrality[member.wotb_id]}
 					`}</b><br>
@@ -127,12 +135,10 @@ ${(USE_WOTB6) ? `
             : ''}
         </td>
         <td align="center" style="background:hsla(${member.proportion}, 100%, 50%, 1)">
-          ${timestampToDatetime(member.idtyWrittenTimestamp)}<br>
-          #${member.idtyWrittenBloc}
+          <span data-tip="${timestampToDatetime(member.idtyWrittenTimestamp)}">#${member.idtyWrittenBloc}</span>
         </td>
         <td align="center" style="background:hsla(${member.proportion}, 100%, 50%, 1)">
-          ${timestampToDatetime(member.lastRenewalTimestamp)}<br>
-          #${member.lastRenewalWrittenBloc}
+          <span data-tip="${timestampToDatetime(member.lastRenewalTimestamp)}">#${member.lastRenewalWrittenBloc}</span>
         </td>
         <td align="center" style="background:hsla(${member.proportion}, 100%, 50%, 1)">
           ${timestampToDatetime(member.expireMembershipTimestamp)}</td>
@@ -140,9 +146,7 @@ ${(USE_WOTB6) ? `
           
 						<font color="${member.detailedDistance.isOutdistanced ? 'red' : 'blue' }">
 							${member.detailedDistance.isOutdistanced ? LANG['COL_DISTANCE_isOutdistanced'] : LANG['COL_DISTANCE_isNotOutdistanced'] }
-							${(USE_WOTB6) ? `
 								<br>${member.percentSentriesReached}% (${member.detailedDistance.nbSuccess}/${member.detailedDistance.nbSentries})
-							`:``}
 						</font>
         </td>
         <td style="background:#000000">-</td>
@@ -153,7 +157,8 @@ ${(USE_WOTB6) ? `
               <!-- Printer la certification -->
               <td align="center" style="background:${(cert.validBlockStamp) ? cert.colorPending=color(cert.expires_on,idtyWindow,250) : cert.colorPending='#FF8000'}">
 								<b>${cert.protagonist}</b><br>
-                ${timestampToDatetime(cert.timestampExpire)}<br>
+                <span data-tip="${LANG['EXPIRE_TIME']}">${timestampToDatetime(cert.timestampExpire)}</span><br>
+                
                 ${LANG["EMITTED"]} #${cert.blockNumber}<br>
                 ${ ( !cert.validBlockStamp || cert.timestampWritable > currentBlockchainTimestamp ) ? `
 									<font color="DarkRed">[${ (cert.validBlockStamp) ? timestampToDatetime(cert.timestampWritable):LANG['INVALID_BLOCKSTAMP']}]</font>
@@ -170,16 +175,13 @@ ${(USE_WOTB6) ? `
           <!-- Printer la certification -->
           <td align="center" style="background:hsla(${proportion(cert.timestampExpire,sigValidity,0,120)}, 100%, 50%, 1 )">
             <b>${(mode=='emitted') ? cert.receiver:cert.issuer}</b><br>
-            ${timestampToDatetime(cert.timestampExpire)}<br>
+            <span data-tip="${LANG['EXPIRE_TIME']}">${timestampToDatetime(cert.timestampExpire)}</span><br>
             ${LANG["WRITTEN"]} #${cert.writtenBloc}
           </td>
         `).join('')}
       </tr>
     `).join('')
   }
-  <tr>
-    <td colspan="${4+nbMaxCertifs}" align="center"> ${LANG["OVERALL"]} : <b>${membersListFiltered.length}</b> ${LANG["MEMBERS"]}.</td>
-  </tr>
 </table><br>
 
 <hr>
diff --git a/views/printMenu.js b/views/printMenu.js
new file mode 100644
index 0000000000000000000000000000000000000000..82854f66fd045b972eaf193494820c11f1ef7efb
--- /dev/null
+++ b/views/printMenu.js
@@ -0,0 +1,20 @@
+const constants = require(__dirname + '/../lib/constants')
+
+module.exports = function printMenu(lang, help, location) {
+  let htmlMenu = '<ul class="menu">';//'<table align="center" width="100%"><tr>';
+
+  htmlMenu += `<li class="menu"><a class="${(location=="WILL_MEMBERS") ? 'active':'menu'}" href="willMembers?lg=${lang['LG']}${(typeof(help) != 'undefined' && help == 'no') ? '&help=no':''}">${lang["WILL_MEMBERS"]}</a></li>`;
+  htmlMenu += `<li class="menu"><a class="${(location=="MEMBERS") ? 'active':'menu'}" href="members?lg=${lang['LG']}${(typeof(help) != 'undefined' && help == 'no') ? '&help=no':''}">${lang["MEMBERS"]}</a></li>`;
+  htmlMenu += `<li class="menu"><a class="${(location=="MEMBERS_COUNT") ? 'active':'menu'}" href="membersCount?lg=${lang['LG']}${(typeof(help) != 'undefined' && help == 'no') ? '&help=no':''}">${lang["MEMBERS_COUNT"]}</a></li>`;
+  htmlMenu += `<li class="menu"><a class="${(location=="WOTEX") ? 'active':'menu'}" href="wotex?lg=${lang['LG']}${(typeof(help) != 'undefined' && help == 'no') ? '&help=no':''}">${lang["WOTEX"]}</a></li>`;
+  htmlMenu += `<li class="menu"><a class="${(location=="GAUSSIAN_WOT_QUALITY") ? 'active':'menu'}" href="gaussianWotQuality?lg=${lang['LG']}${(typeof(help) != 'undefined' && help == 'no') ? '&help=no':''}">${lang["GAUSSIAN_WOT_QUALITY"]}</a></li>`;
+  htmlMenu += `<li class="menu"><a class="${(location=="BLOCK_COUNT") ? 'active':'menu'}" href="blockCount?lg=${lang['LG']}${(typeof(help) != 'undefined' && help == 'no') ? '&help=no':''}">${lang["BLOCK_COUNT"]}</a></li>`;
+  htmlMenu += `<li class="menu"><a class="${(location=="MONETARY_MASS") ? 'active':'menu'}" href="monetaryMass?lg=${lang['LG']}${(typeof(help) != 'undefined' && help == 'no') ? '&help=no':''}">${lang["MONETARY_MASS"]}</a></li>`;
+  htmlMenu += `<li class="menu"><a class="${(location=="ABOUT") ? 'active':'menu'}" href="about?lg=${lang['LG']}${(typeof(help) != 'undefined' && help == 'no') ? '&help=no':''}">${lang["ABOUT"]}</a></li>`;
+  htmlMenu += `<li class="menu" style="float:right"><form action="" method="GET"><a class="menu"><select name="lg" onchange="this.form.submit()">`;
+	htmlMenu += `<option name="lg" value="fr" ${lang['LG'] == 'fr' ? 'selected' : ''}>FR`;
+	htmlMenu += `<option name="lg" value="en" ${lang['LG'] == 'en' ? 'selected' : ''}>EN`;
+	htmlMenu += '</select></a></li></ul><br>';//</td></tr></table><hr>';
+        
+    return htmlMenu;
+}
diff --git a/views/willMembers.html b/views/willMembers.html
index b8b4ec30e07c37e016b25ff7307f501cf3cc0839..da3010ddbb056c3aefb9602767c6e10788ba565a 100755
--- a/views/willMembers.html
+++ b/views/willMembers.html
@@ -1,7 +1,29 @@
 ${(host.substr(host.length-6,6) == '.onion') ? HTML_TOR_HEAD:HTML_HEAD}
-  <title>${currencyName}-monit</title>
+  <title>${currencyName}-monit : ${MENU_LANG['WILL_MEMBERS']}</title>
   
 <script type="text/javascript">// <![CDATA[
+	var table = document.getElementById('table')
+	var filter = document.getElementById('filter')
+
+	/*filter.onchange = function() {
+		return filterRows(table, 1, 0, this.value);
+  }*/
+
+	// tableElem : HTMLElement
+	// rowIndex  : index du row pour commencer le filtrage (0 indexed)
+	// tableElem : index du col à prendre en compte (0 indexed)
+	// tableElem : lettre pour la comparaison
+	function filterRows(tableElem, rowIndex, colIndex, filterString) {
+		for (var i = rowIndex, val; i < tableElem.rows.length; ++i) {
+			val = tableElem.rows[i].cells[colIndex].firstChild.nodeValue;
+			if (val.substr(0,filterString.length).toLowerCase() != filterString.toLowerCase())
+				tableElem.rows[i].style.display = 'none';
+			else
+				tableElem.rows[i].style.display = '';
+		}  
+		return false;
+	}
+	
 	function deroule(champ,valeur)
 	{
 		/*valeur est la hauteur en pixel de la zone*/
@@ -20,25 +42,7 @@ ${(host.substr(host.length-6,6) == '.onion') ? HTML_TOR_HEAD:HTML_HEAD}
 <body>
 
 <!-- Afficher le menu -->
-<table align="center" width="100%">
-  <tr>
-    <td><a href="willMembers?lg=${MENU_LANG['LG']}${(typeof(help) != 'undefined' && help == 'no') ? '&help=no':''}">${MENU_LANG["WILL_MEMBERS"]}</a></td>
-    <td><a href="members?lg=${MENU_LANG['LG']}${(typeof(help) != 'undefined' && help == 'no') ? '&help=no':''}">${MENU_LANG["MEMBERS"]}</a></td>
-    <td><a href="membersCount?lg=${MENU_LANG['LG']}${(typeof(help) != 'undefined' && help == 'no') ? '&help=no':''}">${MENU_LANG["MEMBERS_COUNT"]}</a></td>
-    <td><a href="blockCount?lg=${MENU_LANG['LG']}${(typeof(help) != 'undefined' && help == 'no') ? '&help=no':''}">${MENU_LANG["BLOCK_COUNT"]}</a></td>
-    <td><a href="monetaryMass?lg=${MENU_LANG['LG']}${(typeof(help) != 'undefined' && help == 'no') ? '&help=no':''}">${MENU_LANG["MONETARY_MASS"]}</a></td>
-    <td><a href="wotex?lg=${MENU_LANG['LG']}${(typeof(help) != 'undefined' && help == 'no') ? '&help=no':''}">${MENU_LANG["WOTEX"]}</a></td>
-    <td><a href="about?lg=${MENU_LANG['LG']}${(typeof(help) != 'undefined' && help == 'no') ? '&help=no':''}">${MENU_LANG["ABOUT"]}</a></td>
-    <td>
-      <form action="" method="GET"><input type="hidden" name="help" value="${help}">
-	<select name="lg" onchange="this.form.submit()">
-	  <option name="lg" value="fr" ${MENU_LANG['LG'] == 'fr' ? 'selected' : ''}>FR
-	  <option name="lg" value="en" ${MENU_LANG['LG'] == 'en' ? 'selected' : ''}>EN
-	</select>
-    </td>
-</tr>
-</table>
-<hr>
+${printMenu(MENU_LANG, help, "WILL_MEMBERS")}
 
 <!-- Afficher le formulaire -->
 	<input type="number" name="d" value="${days}"/>${LANG["DAYS"]} - ${LANG["SORT_BY"]}
@@ -50,10 +54,9 @@ ${(host.substr(host.length-6,6) == '.onion') ? HTML_TOR_HEAD:HTML_HEAD}
 		<option name="order" value ="asc">${LANG["ORDER_ASC"]}
 		<option name="order" value ="desc" ${order == 'desc' ? 'selected' : ''}>${LANG["ORDER_DESC"]}
 	</select> <input type="submit" value="${LANG["SUBMIT_TXT"]}"><br>
-	
 	<input type="checkbox" name="showIdtyWithZeroCert" value="yes" ${showIdtyWithZeroCert == 'yes' ? 'checked' : ''}>${LANG["CHECKBOX_SHOW_IDTY_WITH_ZERO_CERT"]}<br>
-	
-	<input type="checkbox" name="sortSig" value="Availability" ${sortSig == 'Availability' ? 'checked' : ''}>${LANG["CHECKBOX_SORT_SIG"]}
+	<input type="checkbox" name="sortSig" value="Availability" ${sortSig == 'Availability' ? 'checked' : ''}>${LANG["CHECKBOX_SORT_SIG"]}<br>
+	${LANG["IDTY_FILTER"]} : <input type="text" name="filter" id="filter" value="" maxlength="20" onchange="filterRows(document.getElementById('table'),2,0,this.value);" onkeypress="this.onchange();" onpaste="this.onchange();" oninput="this.onchange();"/>
 </form>
 <br>
 <hr>
@@ -83,7 +86,6 @@ ${(help != 'no') ? `
 `:''}
 
 <!-- Afficher l'état de tension de la toile de confiance -->
-${ (USE_WOTB6) ? `
 	<div id="zone2" style="width: 100%; height: 20px; background: White; border: 1px solid DimGrey; transition: height 1s; -moz-transition: height 1s;-webkit-transition: height 1s;-o-transition: height 1s; overflow: hidden;">
 		<div id="bandeau2" style="height: 20px; width: 100%; font-size: medium; color: white; background-color: darkgrey;" onmouseover="deroule(2,150);" onmouseout="deroule(2,20);"><b>${LANG["WOT_TENSION_STATE"]}</b>
 		</div>
@@ -142,18 +144,18 @@ ${ (USE_WOTB6) ? `
 			</table>
 		</div>
 	</div>
-`:``}
 
 <!-- Afficher le currentBlockchainTimestamp et le nombre d'identités au dossier complet -->
   ${LANG["BLOCKCHAIN_TIME"]} : <b>${timestampToDatetime(currentBlockchainTimestamp)}</b> (#<b>${currentBlockNumber}</b>).<br>
   ${LANG["COUNT_READY_MEMBERS"]} : <b>${countMembersWithSigQtyValidCert}</b>.<br>
 
 <!-- Tableau de toutes les identités en piscine -->
-<table border="1">
-  <tr><td colspan="${nbMaxCertifs+3}" align='center'>${LANG["TABLE_TITLE1"]} <b>${days}</b> ${LANG["TABLE_TITLE2"]}</td></tr>
+<table id="table" border="1">
+  <tr><td colspan="${nbMaxCertifs+4}" align='center'>${LANG["TABLE_TITLE1"]} <b>${days}</b> ${LANG["TABLE_TITLE2"]}</td></tr>
   <!-- Printer les nom des colonnes -->
   <tr>
-    <td align='center'>${LANG['IDENTITY']}</td><td align='center'>${LANG['MEMBERSHIP_CASE']}</td>
+		<td align="center" style="display :none"></td>
+    <td align='center'>${LANG['IDENTITY']}</td><td align='center'>${LANG['MEMBERSHIP_CASE_FULL']}</td><td align='center'>${LANG['DISTANCE_RULE']}</td>
     <td style="background:#000000">-</td>
     <td align='center' colspan="${nbMaxCertifs}">${sortSig == "Availability" 
                                                   ? LANG['COL_4_WITH_AVAIlABILITY_SORT']
@@ -165,30 +167,34 @@ ${ (USE_WOTB6) ? `
       
       <!--Printer la ligne-->
       <tr>
+				<td align="center" style="display :none">${idty['uid']}</td>
         <td align="center" style="background:${(idty.validBlockStamp) ? ((idty.expires_on > 0) ? idty.colorPending=color(idty.expires_on,idtyWindow,250):idty.colorPending='#FF0000'): idty.colorPending='#FF8000'}">
-          <a href="wotex?lg=${MENU_LANG['LG']}${(typeof(help) != 'undefined' && help == 'no') ? '&help=no':''}&to=${idty['uid']}${idty['wotexId']}&pending=on&mode=undefined">${idty['uid'].substring(0, 25)}</a>
-          <br>${idty['pubkey'].substring(0, 16)}
-          <br>${LANG['EMITTED_ON']} ${timestampToDatetime(idty['creationTimestamp'])}
-          <br>${LANG['AT_BLOCK']} #${idty['BlockNumber']}
-          ${(idty.expires_on > 0) ? '<br><b>'+LANG['EXPIRE_ON']+' '+timestampToDatetime(idty.expires_on)+'</b>':``}
+					<a href="wotex?lg=${MENU_LANG['LG']}${(typeof(help) != 'undefined' && help == 'no') ? '&help=no':''}&to=${idty['uid']}${idty['wotexId']}&pending=on&mode=undefined">${idty['uid'].substring(0, 25)}</a>
+					<br><span data-tip="${LANG['PUBKEY_PART']} ">${idty['pubkey'].substring(0, 16)}</span>
+          <br><b><span data-tip="${LANG['EMITTED_ON']} ${timestampToDatetime(idty['creationTimestamp'])}">#${idty['BlockNumber']}</span></b>
+          ${(idty.expires_on > 0) ? '<br><b><span data-tip="'+LANG['EXPIRE_TIME']+'">'+timestampToDatetime(idty.expires_on)+'</span></b>':``}
         ${(!idty.validBlockStamp) ? `
           <br><font color="DarkRed">[${LANG['INVALID_BLOCKSTAMP']}]</font>
         `:``}
         </td>
-        ${(idty.expires_on > 0) ? `
+        ${(idty.expires_on && !idty.idtyRevoked > 0) ? `
 					<td align='center' style="background:${idty.colorPending}">
-						${(idty.membership && !idty.detailedDistance.isOutdistanced && idty.nbValidPendingCert >= sigQty) ? `<font color="green">${LANG['OK']}` : `<font color="DarkRed">${LANG['KO']}` }</font><br>
-						${LANG['MEMBERSHIP_ASKED']} : ${idty.membership? `<font color="green">${LANG['YES']}` : `<font color="DarkRed">${LANG['NO']}` }</font><br>
-						${ (USE_WOTB6) ? `
-							<font color="${idty.detailedDistance.isOutdistanced ? 'DarkRed' : 'blue' }">${idty.percentSentriesReached}% (${idty.detailedDistance.nbSuccess}/${idty.detailedDistance.nbSentries})
-							<br>${LANG['QUALITY_CERTIFIERS']} : <b>${(idty.validBlockStamp) ? ((idty.detailedDistance.nbSuccess/idty.detailedDistance.nbSentries)/xpercent).toFixed(2):`0.00`}</b></font>
+						${(idty.membership && !idty.detailedDistance.isOutdistanced && idty.nbValidPendingCert >= sigQty) ? `
+							<font color="green">${LANG['YES']}
 						`:`
-						  <font color="${idty.detailedDistance ? 'DarkRed' : 'blue' }">${LANG['DISTANCE']} : ${idty.detailedDistance ? LANG['KO']:LANG['OK'] }</font>
+							<font color="DarkRed">${LANG['NO']}
+								${!idty.membership? `<br>${LANG['MEMBERSHIP_NOT_ASKED']}`:``}
+								${(idty.nbValidPendingCert < sigQty) ? `<br>${LANG['MISS']} <b>${(sigQty-idty.nbValidPendingCert)}</b> ${LANG['CERTS']}`:``}
+								${idty.detailedDistance.isOutdistanced? `<br>${LANG['DISTANCE']} ${LANG['KO']}`:``}
+							</font>
 						`}
-						<br>${LANG['CERTIFIERS_COUNT']} : ${(idty.nbValidPendingCert >= sigQty) ? `<font color="green">${idty.nbValidPendingCert}/${sigQty}` : `<font color="DarkRed">${idty.nbValidPendingCert}/${sigQty}` }</font>
+					</td>
+					<td align='center' style="background:${idty.colorPending}">
+							<font color="${idty.detailedDistance.isOutdistanced ? 'DarkRed' : 'blue' }">${idty.percentSentriesReached}% (${idty.detailedDistance.nbSuccess}/${idty.detailedDistance.nbSentries})
+							<br>${LANG['QUALITY_CERTIFIERS']} : <b>${(idty.validBlockStamp) ? ((idty.detailedDistance.nbSuccess/idty.detailedDistance.nbSentries)/xpercent).toFixed(2):`0.00`}</b></font>
 					</td>
 				`:`
-					<td align='center' style="background:#FF0000"><b>${LANG['IDTY_REVOKED']}</b></td>
+					<td align='center' colspan=2 style="background:#FF0000"><b>${LANG['IDTY_REVOKED']}</b></td>
 				`}
         <td style="background:#000000">-</td>
         
@@ -199,11 +205,9 @@ ${ (USE_WOTB6) ? `
 							${cert.issuerIsSentry ? '<b>':''}
 								<a href="wotex?lg=${MENU_LANG['LG']}${(typeof(help) != 'undefined' && help == 'no') ? '&help=no':''}&to=${cert['from']}&pending=on&mode=undefined">${cert['from']}</a>
 							${cert.issuerIsSentry ? '</b>':''}
-							${ (USE_WOTB6) ? `
 								<br>${LANG['QUALITY']} : <b>${(typeof(membersQualityExt[cert.from])=='undefined' || !cert.validBlockStamp) ? `0.00`:membersQualityExt[cert.from]}</b>
-							`:''}
-							<br>${timestampToDatetime(cert.timestampExpire)}
-							<br>#${cert['blockNumber']}
+							<br><b><span data-tip="${LANG['EMITTED_ON']}  ${timestampToDatetime(cert['creationTimestamp'])}">#${cert['blockNumber']}</span></b>
+							<br><span data-tip="${LANG['EXPIRE_TIME']}">${timestampToDatetime(cert.timestampExpire)}</span>
 							${j==(4+idty.pendingCertifications.length-idty.nbValidPendingCert)?'<b>':''}
 							${ ( !cert.validBlockStamp || cert['timestampWritable'] > currentBlockchainTimestamp ) ? `
 								<br><font color="DarkRed">[${ (cert.validBlockStamp) ? timestampToDatetime(cert['timestampWritable']):LANG['INVALID_BLOCKSTAMP']}]</font>
@@ -220,7 +224,7 @@ ${ (USE_WOTB6) ? `
   `).join('')}
   
   <tr>
-    <td colspan="${nbMaxCertifs+3}" align="center">
+    <td colspan="${nbMaxCertifs+4}" align="center">
       ${LANG['LAST_TR1']} : <b>${idtysListFiltered.length}</b> ${LANG['LAST_TR2']}.
     </td>
   </tr>
diff --git a/views/wotex.html b/views/wotex.html
index 86d8dfc0c9dbaa85ebf213b5cbd13b2f0f27d9f2..a697e76a13549e6127f3c8e2c2666e0875fad06b 100755
--- a/views/wotex.html
+++ b/views/wotex.html
@@ -1,6 +1,6 @@
 <!-- Inclure l'en-tête commun -->
 ${(host.substr(host.length-6,6) == '.onion') ? HTML_TOR_HEAD:HTML_HEAD}
-  <title>${currencyName}-monit</title>
+  <title>${currencyName}-monit : ${MENU_LANG['WOTEX']}</title>
 		<!-- Style css spécifique de wotex -->
                 <style>
                 .sentry {
@@ -117,25 +117,7 @@ ${(host.substr(host.length-6,6) == '.onion') ? HTML_TOR_HEAD:HTML_HEAD}
   <body onload="onLoadedPage()">
 
     <!-- Afficher le menu -->
-    <table align="center" width="100%">
-      <tr>
-	<td><a href="willMembers?lg=${MENU_LANG['LG']}${(typeof(help) != 'undefined' && help == 'no') ? '&help=no':''}">${MENU_LANG["WILL_MEMBERS"]}</a></td>
-	<td><a href="members?lg=${MENU_LANG['LG']}${(typeof(help) != 'undefined' && help == 'no') ? '&help=no':''}">${MENU_LANG["MEMBERS"]}</a></td>
-	<td><a href="membersCount?lg=${MENU_LANG['LG']}${(typeof(help) != 'undefined' && help == 'no') ? '&help=no':''}">${MENU_LANG["MEMBERS_COUNT"]}</a></td>
-	<td><a href="blockCount?lg=${MENU_LANG['LG']}${(typeof(help) != 'undefined' && help == 'no') ? '&help=no':''}">${MENU_LANG["BLOCK_COUNT"]}</a></td>
-	<td><a href="monetaryMass?lg=${MENU_LANG['LG']}${(typeof(help) != 'undefined' && help == 'no') ? '&help=no':''}">${MENU_LANG["MONETARY_MASS"]}</a></td>
-	<td><a href="wotex?lg=${MENU_LANG['LG']}${(typeof(help) != 'undefined' && help == 'no') ? '&help=no':''}">${MENU_LANG["WOTEX"]}</a></td>
-	<td><a href="about?lg=${MENU_LANG['LG']}${(typeof(help) != 'undefined' && help == 'no') ? '&help=no':''}">${MENU_LANG["ABOUT"]}</a></td>
-	<td>
-	  <form action="" method="GET">
-	    <select name="lg" onchange="this.form.submit()">
-	      <option name="lg" value="fr" ${MENU_LANG['LG'] == 'fr' ? 'selected' : ''}>FR
-	      <option name="lg" value="en" ${MENU_LANG['LG'] == 'en' ? 'selected' : ''}>EN
-	    </select>
-	</td>
-    </tr>
-    </table>
-    <hr/>
+    ${printMenu(MENU_LANG, help, "WOTEX")}
 
     <!-- Afficher le titre et le formulaire -->
     <h1>${LANG['TITLE']}</h1>
@@ -158,12 +140,12 @@ ${(host.substr(host.length-6,6) == '.onion') ? HTML_TOR_HEAD:HTML_HEAD}
       <!-- Afficher la légende -->
       ${(typeof(help) == 'undefined' || help != 'no') ? `
       <p>${LANG['LEGEND_TITLE']} :</p>
-      <ul>
-	<li><span class="isMember">${LANG['LEGEND_BLACK']}</span></li>
-	<li><span class="isSentry">${LANG['LEGEND_BLUE']}</span></li>
-	<li><span class="isPending">${LANG['LEGEND_ORANGE']}</span></li>
-	<li><span class="isNonMember">${LANG['LEGEND_RED']}</span></li>
-      </ul>
+
+  <span class="isMember">${LANG['LEGEND_BLACK']}</span></br>
+  <span class="isSentry">${LANG['LEGEND_BLUE']}</span></br>
+	<span class="isPending">${LANG['LEGEND_ORANGE']}</span></br>
+	<span class="isNonMember">${LANG['LEGEND_RED']}</span></br>
+
       <hr/>
       `:``}
     <!-- Afficher tout les plus courts chemins -->