diff --git a/README.md b/README.md
index dba54d92d9fc4ea241fe64b167549781b9059926..cc2a4e7fc5bae03b36ff7b9da8f66dfdb6bbde0d 100644
--- a/README.md
+++ b/README.md
@@ -21,3 +21,148 @@ En sécurité informatique ce que des outils tel que Gsper font est appellé [at
 [3006 Ǧ1 (6h)](https://cesium.ǧ1.money/api/#/v1/payment/22TTh6fD8uEC9CYq5sB8QpqjyXEHH5QnAiEdy68D2Y7S?name=Financement%20de%20Gsper&amount=3006&comment=REFERENCE)
 
 Le temps entre parentèse est l'équivalent temps de dev au tarifs indiqué sur le site du développeur : https://1forma-tic.fr
+
+## Guide d'utilisation
+
+1. Indiquer la clef publique de votre compte (si vous ne la connaissez pas, chercher votre profil sur [cesium](https://cesium.ǧ1.money/#/app/wot/lg) via la fonction recherche de l'annuaire)
+2. Indiquer les variantes d'identifiant secret que vous souhaitez tester. (Il est possible de générer plus de variantes automatiquement. [La documentation](#Documentation) ci dessous explique comment.)
+3. Indiquer les variantes de mot de passe que vous souhaitez tester.
+4. Cliquer sur le bouton `Gsper !` pour lancer la tentative de récupération des accès au compte.
+5. Patienter jusqu'à l'apparition du message de fin de recherche (avec ou sans succès).
+
+## Documentation
+Gsper met à votre disposition plusieurs boutons pour générer des variantes à tester à partir de celles que vous avez indiqué.
+Voici comment les utiliser.
+
+### Bouton `MaJusculeS` 
+Génère des variantes des combinaisons à tester :
+- entièrement en majuscule
+- entièrement en minuscule
+- avec le premier caractère en majuscule uniquement
+- tel quel, sans modifier les majuscule et minuscule
+
+**Exemple :** 
+```
+moT
+```
+sera remplacé par :
+```
+mot
+MOT
+Mot
+moT
+```
+### Bouton `désaccentué` 
+Génère la variante désaccentué des combinaisons à tester.
+
+**Exemple :** 
+```
+Gavé de Ǧ1
+```
+sera remplacé par :
+```
+Gavé de Ǧ1
+Gave de G1
+```
+
+### Bouton `<({[Avancé]})>` 
+
+Génère des variantes avancées selon un syntaxe spécifique.
+
+<!-- **/!\ Attention /!\\** Générer un trop grand nombre de combinaison à tester peut faire planter le navigateur, et mettre des année à tester de toute façon. --> 
+
+Détail de la syntaxe :
+
+###### `<référence>` remplace `<référence>` par les lignes commançant par `référence::`
+**Exemple :** 
+```
+&lt;pre&gt; de passe
+pre::mot
+pre::phrase
+```
+sera remplacé par :
+```
+mot de passe
+phrase de passe
+```
+
+###### `(variante|autre variante)` décline les séquences listées comme des combinaisons différentes.
+**Exemple :** 
+```
+(mot|phrase) de passe
+```
+sera remplacé par :
+```
+mot de passe
+phrase de passe
+```
+
+###### `[a-z§¤]` décline les caractères listés comme des combinaisons différentes.
+**Exemple :** 
+```
+J'ai oublié la suite[!.]
+```
+sera remplacé par :
+```
+J'ai oublié la suite!
+J'ai oublié la suite.
+```
+
+**Exemple :** 
+```
+Spam [0-3]
+```
+sera remplacé par :
+```
+Spam 0
+Spam 1
+Spam 2
+Spam 3
+```
+
+###### `A{0,2}` décline l'élément précédent selon les quantités définies.
+**Exemple :** 
+```
+c'est (mat|tic){0,3}
+```
+sera remplacé par :
+```
+c'est 
+c'est mat
+c'est matmat
+c'est matmatmat
+c'est matmattic
+c'est mattic
+c'est matticmat
+c'est mattictic
+c'est tic
+c'est ticmat
+c'est ticmatmat
+c'est ticmattic
+c'est tictic
+c'est ticticmat
+c'est tictictic
+```
+
+###### `\ ` permet de banaliser le caractère suivant
+**/!\ Pas encore implémenté**
+**Exemple :** 
+```
+un (am\||\|nconu)
+```
+sera remplacé par :
+```
+un am|
+un |nconu
+```
+**Contre exemple :**
+```
+un (am|||nconu)
+```
+sera remplacé par :
+```
+un am
+un 
+un 
+un nconu
+```
diff --git a/public/dictionaryBuilder.js b/public/dictionaryBuilder.js
new file mode 100644
index 0000000000000000000000000000000000000000..ab378484b5442ad404f04cbe8548998709b19b33
--- /dev/null
+++ b/public/dictionaryBuilder.js
@@ -0,0 +1,65 @@
+export {dedup,noAccentVariant,casesVariants,regLikeVariants}
+
+function dedup(array) {
+	const res = {};
+	array.forEach(v=>res[v]=v);
+	return Object.keys(res);
+}
+function noAccentVariant(string) {
+	const conversionMap = {'Á':'A','Ă':'A','Ắ':'A','Ặ':'A','Ằ':'A','Ẳ':'A','Ẵ':'A','Ǎ':'A','Â':'A','Ấ':'A','Ậ':'A','Ầ':'A','Ẩ':'A','Ẫ':'A','Ä':'A','Ǟ':'A','Ȧ':'A','Ǡ':'A','Ạ':'A','Ȁ':'A','À':'A','Ả':'A','Ȃ':'A','Ā':'A','Ą':'A','Å':'A','Ǻ':'A','Ḁ':'A','Ⱥ':'A','Ã':'A','Ꜳ':'AA','Æ':'AE','Ǽ':'AE','Ǣ':'AE','Ꜵ':'AO','Ꜷ':'AU','Ꜹ':'AV','Ꜻ':'AV','Ꜽ':'AY','Ḃ':'B','Ḅ':'B','Ɓ':'B','Ḇ':'B','Ƀ':'B','Ƃ':'B','Ć':'C','Č':'C','Ç':'C','Ḉ':'C','Ĉ':'C','Ċ':'C','Ƈ':'C','Ȼ':'C','Ď':'D','Ḑ':'D','Ḓ':'D','Ḋ':'D','Ḍ':'D','Ɗ':'D','Ḏ':'D','Dz':'D','Dž':'D','Đ':'D','Ƌ':'D','DZ':'DZ','DŽ':'DZ','É':'E','Ĕ':'E','Ě':'E','Ȩ':'E','Ḝ':'E','Ê':'E','Ế':'E','Ệ':'E','Ề':'E','Ể':'E','Ễ':'E','Ḙ':'E','Ë':'E','Ė':'E','Ẹ':'E','Ȅ':'E','È':'E','Ẻ':'E','Ȇ':'E','Ē':'E','Ḗ':'E','Ḕ':'E','Ę':'E','Ɇ':'E','Ẽ':'E','Ḛ':'E','Ꝫ':'ET','Ḟ':'F','Ƒ':'F','Ǵ':'G','Ğ':'G','Ǧ':'G','Ģ':'G','Ĝ':'G','Ġ':'G','Ɠ':'G','Ḡ':'G','Ǥ':'G','Ḫ':'H','Ȟ':'H','Ḩ':'H','Ĥ':'H','Ⱨ':'H','Ḧ':'H','Ḣ':'H','Ḥ':'H','Ħ':'H','Í':'I','Ĭ':'I','Ǐ':'I','Î':'I','Ï':'I','Ḯ':'I','İ':'I','Ị':'I','Ȉ':'I','Ì':'I','Ỉ':'I','Ȋ':'I','Ī':'I','Į':'I','Ɨ':'I','Ĩ':'I','Ḭ':'I','Ꝺ':'D','Ꝼ':'F','Ᵹ':'G','Ꞃ':'R','Ꞅ':'S','Ꞇ':'T','Ꝭ':'IS','Ĵ':'J','Ɉ':'J','Ḱ':'K','Ǩ':'K','Ķ':'K','Ⱪ':'K','Ꝃ':'K','Ḳ':'K','Ƙ':'K','Ḵ':'K','Ꝁ':'K','Ꝅ':'K','Ĺ':'L','Ƚ':'L','Ľ':'L','Ļ':'L','Ḽ':'L','Ḷ':'L','Ḹ':'L','Ⱡ':'L','Ꝉ':'L','Ḻ':'L','Ŀ':'L','Ɫ':'L','Lj':'L','Ł':'L','LJ':'LJ','Ḿ':'M','Ṁ':'M','Ṃ':'M','Ɱ':'M','Ń':'N','Ň':'N','Ņ':'N','Ṋ':'N','Ṅ':'N','Ṇ':'N','Ǹ':'N','Ɲ':'N','Ṉ':'N','Ƞ':'N','Nj':'N','Ñ':'N','NJ':'NJ','Ó':'O','Ŏ':'O','Ǒ':'O','Ô':'O','Ố':'O','Ộ':'O','Ồ':'O','Ổ':'O','Ỗ':'O','Ö':'O','Ȫ':'O','Ȯ':'O','Ȱ':'O','Ọ':'O','Ő':'O','Ȍ':'O','Ò':'O','Ỏ':'O','Ơ':'O','Ớ':'O','Ợ':'O','Ờ':'O','Ở':'O','Ỡ':'O','Ȏ':'O','Ꝋ':'O','Ꝍ':'O','Ō':'O','Ṓ':'O','Ṑ':'O','Ɵ':'O','Ǫ':'O','Ǭ':'O','Ø':'O','Ǿ':'O','Õ':'O','Ṍ':'O','Ṏ':'O','Ȭ':'O','Ƣ':'OI','Ꝏ':'OO','Ɛ':'E','Ɔ':'O','Ȣ':'OU','Ṕ':'P','Ṗ':'P','Ꝓ':'P','Ƥ':'P','Ꝕ':'P','Ᵽ':'P','Ꝑ':'P','Ꝙ':'Q','Ꝗ':'Q','Ŕ':'R','Ř':'R','Ŗ':'R','Ṙ':'R','Ṛ':'R','Ṝ':'R','Ȑ':'R','Ȓ':'R','Ṟ':'R','Ɍ':'R','Ɽ':'R','Ꜿ':'C','Ǝ':'E','Ś':'S','Ṥ':'S','Š':'S','Ṧ':'S','Ş':'S','Ŝ':'S','Ș':'S','Ṡ':'S','Ṣ':'S','Ṩ':'S','Ť':'T','Ţ':'T','Ṱ':'T','Ț':'T','Ⱦ':'T','Ṫ':'T','Ṭ':'T','Ƭ':'T','Ṯ':'T','Ʈ':'T','Ŧ':'T','Ɐ':'A','Ꞁ':'L','Ɯ':'M','Ʌ':'V','Ꜩ':'TZ','Ú':'U','Ŭ':'U','Ǔ':'U','Û':'U','Ṷ':'U','Ü':'U','Ǘ':'U','Ǚ':'U','Ǜ':'U','Ǖ':'U','Ṳ':'U','Ụ':'U','Ű':'U','Ȕ':'U','Ù':'U','Ủ':'U','Ư':'U','Ứ':'U','Ự':'U','Ừ':'U','Ử':'U','Ữ':'U','Ȗ':'U','Ū':'U','Ṻ':'U','Ų':'U','Ů':'U','Ũ':'U','Ṹ':'U','Ṵ':'U','Ꝟ':'V','Ṿ':'V','Ʋ':'V','Ṽ':'V','Ꝡ':'VY','Ẃ':'W','Ŵ':'W','Ẅ':'W','Ẇ':'W','Ẉ':'W','Ẁ':'W','Ⱳ':'W','Ẍ':'X','Ẋ':'X','Ý':'Y','Ŷ':'Y','Ÿ':'Y','Ẏ':'Y','Ỵ':'Y','Ỳ':'Y','Ƴ':'Y','Ỷ':'Y','Ỿ':'Y','Ȳ':'Y','Ɏ':'Y','Ỹ':'Y','Ź':'Z','Ž':'Z','Ẑ':'Z','Ⱬ':'Z','Ż':'Z','Ẓ':'Z','Ȥ':'Z','Ẕ':'Z','Ƶ':'Z','IJ':'IJ','Œ':'OE','ᴀ':'A','ᴁ':'AE','ʙ':'B','ᴃ':'B','ᴄ':'C','ᴅ':'D','ᴇ':'E','ꜰ':'F','ɢ':'G','ʛ':'G','ʜ':'H','ɪ':'I','ʁ':'R','ᴊ':'J','ᴋ':'K','ʟ':'L','ᴌ':'L','ᴍ':'M','ɴ':'N','ᴏ':'O','ɶ':'OE','ᴐ':'O','ᴕ':'OU','ᴘ':'P','ʀ':'R','ᴎ':'N','ᴙ':'R','ꜱ':'S','ᴛ':'T','ⱻ':'E','ᴚ':'R','ᴜ':'U','ᴠ':'V','ᴡ':'W','ʏ':'Y','ᴢ':'Z','á':'a','ă':'a','ắ':'a','ặ':'a','ằ':'a','ẳ':'a','ẵ':'a','ǎ':'a','â':'a','ấ':'a','ậ':'a','ầ':'a','ẩ':'a','ẫ':'a','ä':'a','ǟ':'a','ȧ':'a','ǡ':'a','ạ':'a','ȁ':'a','à':'a','ả':'a','ȃ':'a','ā':'a','ą':'a','ᶏ':'a','ẚ':'a','å':'a','ǻ':'a','ḁ':'a','ⱥ':'a','ã':'a','ꜳ':'aa','æ':'ae','ǽ':'ae','ǣ':'ae','ꜵ':'ao','ꜷ':'au','ꜹ':'av','ꜻ':'av','ꜽ':'ay','ḃ':'b','ḅ':'b','ɓ':'b','ḇ':'b','ᵬ':'b','ᶀ':'b','ƀ':'b','ƃ':'b','ɵ':'o','ć':'c','č':'c','ç':'c','ḉ':'c','ĉ':'c','ɕ':'c','ċ':'c','ƈ':'c','ȼ':'c','ď':'d','ḑ':'d','ḓ':'d','ȡ':'d','ḋ':'d','ḍ':'d','ɗ':'d','ᶑ':'d','ḏ':'d','ᵭ':'d','ᶁ':'d','đ':'d','ɖ':'d','ƌ':'d','ı':'i','ȷ':'j','ɟ':'j','ʄ':'j','dz':'dz','dž':'dz','é':'e','ĕ':'e','ě':'e','ȩ':'e','ḝ':'e','ê':'e','ế':'e','ệ':'e','ề':'e','ể':'e','ễ':'e','ḙ':'e','ë':'e','ė':'e','ẹ':'e','ȅ':'e','è':'e','ẻ':'e','ȇ':'e','ē':'e','ḗ':'e','ḕ':'e','ⱸ':'e','ę':'e','ᶒ':'e','ɇ':'e','ẽ':'e','ḛ':'e','ꝫ':'et','ḟ':'f','ƒ':'f','ᵮ':'f','ᶂ':'f','ǵ':'g','ğ':'g','ǧ':'g','ģ':'g','ĝ':'g','ġ':'g','ɠ':'g','ḡ':'g','ᶃ':'g','ǥ':'g','ḫ':'h','ȟ':'h','ḩ':'h','ĥ':'h','ⱨ':'h','ḧ':'h','ḣ':'h','ḥ':'h','ɦ':'h','ẖ':'h','ħ':'h','ƕ':'hv','í':'i','ĭ':'i','ǐ':'i','î':'i','ï':'i','ḯ':'i','ị':'i','ȉ':'i','ì':'i','ỉ':'i','ȋ':'i','ī':'i','į':'i','ᶖ':'i','ɨ':'i','ĩ':'i','ḭ':'i','ꝺ':'d','ꝼ':'f','ᵹ':'g','ꞃ':'r','ꞅ':'s','ꞇ':'t','ꝭ':'is','ǰ':'j','ĵ':'j','ʝ':'j','ɉ':'j','ḱ':'k','ǩ':'k','ķ':'k','ⱪ':'k','ꝃ':'k','ḳ':'k','ƙ':'k','ḵ':'k','ᶄ':'k','ꝁ':'k','ꝅ':'k','ĺ':'l','ƚ':'l','ɬ':'l','ľ':'l','ļ':'l','ḽ':'l','ȴ':'l','ḷ':'l','ḹ':'l','ⱡ':'l','ꝉ':'l','ḻ':'l','ŀ':'l','ɫ':'l','ᶅ':'l','ɭ':'l','ł':'l','lj':'lj','ſ':'s','ẜ':'s','ẛ':'s','ẝ':'s','ḿ':'m','ṁ':'m','ṃ':'m','ɱ':'m','ᵯ':'m','ᶆ':'m','ń':'n','ň':'n','ņ':'n','ṋ':'n','ȵ':'n','ṅ':'n','ṇ':'n','ǹ':'n','ɲ':'n','ṉ':'n','ƞ':'n','ᵰ':'n','ᶇ':'n','ɳ':'n','ñ':'n','nj':'nj','ó':'o','ŏ':'o','ǒ':'o','ô':'o','ố':'o','ộ':'o','ồ':'o','ổ':'o','ỗ':'o','ö':'o','ȫ':'o','ȯ':'o','ȱ':'o','ọ':'o','ő':'o','ȍ':'o','ò':'o','ỏ':'o','ơ':'o','ớ':'o','ợ':'o','ờ':'o','ở':'o','ỡ':'o','ȏ':'o','ꝋ':'o','ꝍ':'o','ⱺ':'o','ō':'o','ṓ':'o','ṑ':'o','ǫ':'o','ǭ':'o','ø':'o','ǿ':'o','õ':'o','ṍ':'o','ṏ':'o','ȭ':'o','ƣ':'oi','ꝏ':'oo','ɛ':'e','ᶓ':'e','ɔ':'o','ᶗ':'o','ȣ':'ou','ṕ':'p','ṗ':'p','ꝓ':'p','ƥ':'p','ᵱ':'p','ᶈ':'p','ꝕ':'p','ᵽ':'p','ꝑ':'p','ꝙ':'q','ʠ':'q','ɋ':'q','ꝗ':'q','ŕ':'r','ř':'r','ŗ':'r','ṙ':'r','ṛ':'r','ṝ':'r','ȑ':'r','ɾ':'r','ᵳ':'r','ȓ':'r','ṟ':'r','ɼ':'r','ᵲ':'r','ᶉ':'r','ɍ':'r','ɽ':'r','ↄ':'c','ꜿ':'c','ɘ':'e','ɿ':'r','ś':'s','ṥ':'s','š':'s','ṧ':'s','ş':'s','ŝ':'s','ș':'s','ṡ':'s','ṣ':'s','ṩ':'s','ʂ':'s','ᵴ':'s','ᶊ':'s','ȿ':'s','ɡ':'g','ᴑ':'o','ᴓ':'o','ᴝ':'u','ť':'t','ţ':'t','ṱ':'t','ț':'t','ȶ':'t','ẗ':'t','ⱦ':'t','ṫ':'t','ṭ':'t','ƭ':'t','ṯ':'t','ᵵ':'t','ƫ':'t','ʈ':'t','ŧ':'t','ᵺ':'th','ɐ':'a','ᴂ':'ae','ǝ':'e','ᵷ':'g','ɥ':'h','ʮ':'h','ʯ':'h','ᴉ':'i','ʞ':'k','ꞁ':'l','ɯ':'m','ɰ':'m','ᴔ':'oe','ɹ':'r','ɻ':'r','ɺ':'r','ⱹ':'r','ʇ':'t','ʌ':'v','ʍ':'w','ʎ':'y','ꜩ':'tz','ú':'u','ŭ':'u','ǔ':'u','û':'u','ṷ':'u','ü':'u','ǘ':'u','ǚ':'u','ǜ':'u','ǖ':'u','ṳ':'u','ụ':'u','ű':'u','ȕ':'u','ù':'u','ủ':'u','ư':'u','ứ':'u','ự':'u','ừ':'u','ử':'u','ữ':'u','ȗ':'u','ū':'u','ṻ':'u','ų':'u','ᶙ':'u','ů':'u','ũ':'u','ṹ':'u','ṵ':'u','ᵫ':'ue','ꝸ':'um','ⱴ':'v','ꝟ':'v','ṿ':'v','ʋ':'v','ᶌ':'v','ⱱ':'v','ṽ':'v','ꝡ':'vy','ẃ':'w','ŵ':'w','ẅ':'w','ẇ':'w','ẉ':'w','ẁ':'w','ⱳ':'w','ẘ':'w','ẍ':'x','ẋ':'x','ᶍ':'x','ý':'y','ŷ':'y','ÿ':'y','ẏ':'y','ỵ':'y','ỳ':'y','ƴ':'y','ỷ':'y','ỿ':'y','ȳ':'y','ẙ':'y','ɏ':'y','ỹ':'y','ź':'z','ž':'z','ẑ':'z','ʑ':'z','ⱬ':'z','ż':'z','ẓ':'z','ȥ':'z','ẕ':'z','ᵶ':'z','ᶎ':'z','ʐ':'z','ƶ':'z','ɀ':'z','ff':'ff','ffi':'ffi','ffl':'ffl','fi':'fi','fl':'fl','ij':'ij','œ':'oe','st':'st','ₐ':'a','ₑ':'e','ᵢ':'i','ⱼ':'j','ₒ':'o','ᵣ':'r','ᵤ':'u','ᵥ':'v','ₓ':'x'};
+	return dedup([
+		string,
+		string.replace( /[^A-Za-z0-9]/g, (a) => conversionMap[a]||a )
+	]);
+}
+function casesVariants(string) {
+	return dedup([
+		string,
+		string.toLowerCase(),
+		string.split(" ").map(str=>str.charAt(0).toUpperCase() + str.slice(1).toLowerCase()).join(" "),
+		string.toUpperCase()
+	]);
+}
+function regLikeVariants(theString,allStrings) {
+	//TODO: allStringsPreRenderCache
+
+	// handle []
+	const lower = "abcdefghijklmnopqrstuvwxyz";
+	const upper = lower.toUpperCase();
+	const number= "0123456789";
+	theString = theString.replace(/(\[[^\]]*)([a-z]-[a-z])([^\]]*\])/g,(osef,before,chrs,after)=> before+lower.slice(lower.indexOf(chrs.split('-')[0]),lower.indexOf(chrs.split('-')[1])+1)+after );
+	theString = theString.replace(/(\[[^\]]*)([A-Z]-[A-Z])([^\]]*\])/g,(osef,before,chrs,after)=> before+upper.slice(upper.indexOf(chrs.split('-')[0]),upper.indexOf(chrs.split('-')[1])+1)+after );
+	theString = theString.replace(/(\[[^\]]*)([0-9]-[0-9])([^\]]*\])/g,(osef,before,chrs,after)=> before+number.slice(number.indexOf(chrs.split('-')[0]),number.indexOf(chrs.split('-')[1])+1)+after );
+	theString = theString.replace(/\[([^\]]+)\]/g,(osef,chrs)=> `(${chrs.split('').join('|')})` );
+
+	// handle <ref>
+	if(theString.indexOf('::')>0) return [];
+	theString = theString.replace(/<([^>]+)>/g,(osef,ref)=> `(${allStrings.filter(str=>str.indexOf(`${ref}::`)!== -1).map(str=>`(${regLikeVariants(str.slice(`${ref}::`.length),allStrings).join('|')})`).join('|')})` );
+
+	// handle {qty} and {min,max}
+	const qtyApply = (all,chr,qty)=> {
+		const mm = qty.split(",").map(n=>n.trim()*1);
+		const min = mm[0];
+		const max = (mm.length === 2)?mm[1]:min;
+		const res = [];
+		for (let i = min; i<=max; i++) res.push( new Array(i + 1).join(chr) )
+		return `(${res.join('|')})`;
+	};
+	theString = theString.replace(/([^\)]){([^}]+)}/g,qtyApply);
+
+
+	// handle (|)
+	let multiString = theString.replace(/^(.*)\(([^)]*)\)(.*)$/,(all,before,choices,after)=>choices.split('|').map(c=>{
+		if(after.indexOf('{')!==0) return before+c+after;
+		else {
+			console.log(c);
+			const end = after.slice(1).split('}');
+			const qty = end.shift();
+			const afterQty = end.join('}');
+			return before+qtyApply('',c,qty)+afterQty;
+		}
+	}).join('=$##$=') ).split('=$##$=');
+	console.log(multiString);
+	multiString = [].concat(...multiString.map(str => (str.indexOf('(')!== -1)?regLikeVariants(str,allStrings):str));
+	return multiString;
+}
diff --git a/public/dictionaryBuilder.test.js b/public/dictionaryBuilder.test.js
new file mode 100644
index 0000000000000000000000000000000000000000..92a40aee80781dce06bf46c8978c348ae7f77755
--- /dev/null
+++ b/public/dictionaryBuilder.test.js
@@ -0,0 +1,53 @@
+import * as app from "./dictionaryBuilder.js";
+describe('dictionaryBuilder', () => {
+	it('add no accents variant', () => {
+		expect(app.noAccentVariant("Ǧ1")).toEqual(["Ǧ1","G1"]);
+	});
+	it('add case variants', () => {
+		expect(app.casesVariants("moT")).toEqual(["moT","mot","Mot","MOT"]);
+	});
+	it('add multi word case variants', () => {
+		expect(app.casesVariants("autre mot")).toEqual(["autre mot","Autre Mot","AUTRE MOT"]);
+	});
+	it('regLikeVariants remove ref:: lines', () => {
+		expect(app.regLikeVariants("ref::truc")).toEqual([]);
+	});
+	it('regLikeVariants handle <ref>', () => {
+		expect(app.regLikeVariants("<ref> <ref>",["ref::truc","ref::bidule","<ref> <ref>"])).toEqual(["truc truc","bidule truc", "truc bidule", "bidule bidule"]);
+	});
+	it('regLikeVariants handle (this|that)', () => {
+		expect(app.regLikeVariants("(this|that)")).toEqual(["this","that"]);
+	});
+	it('regLikeVariants handle [ -_]', () => {
+		expect(app.regLikeVariants("[ -_]")).toEqual([" ","-","_"]);
+	});
+	it('regLikeVariants handle [a-f]', () => {
+		expect(app.regLikeVariants("[a-f]")).toEqual(["a","b","c","d","e","f"]);
+		expect(app.regLikeVariants("[7-9]")).toEqual(["7","8","9"]);
+		expect(app.regLikeVariants("[C-F]")).toEqual(["C","D","E","F"]);
+	});
+	it('regLikeVariants handle [a-c-]', () => {
+		expect(app.regLikeVariants("[a-c-]")).toEqual(["a","b","c","-"]);
+	});
+	it('regLikeVariants handle {qty}', () => {
+		expect(app.regLikeVariants("a{5}")).toEqual(["aaaaa"]);
+	});
+	it('regLikeVariants handle {min,max}', () => {
+		expect(app.regLikeVariants("b{3,5}")).toEqual(["bbb","bbbb","bbbbb"]);
+	});
+	it('regLikeVariants handle (string){qty}', () => {
+		expect(app.regLikeVariants("(toto|tata){0,2}")).toEqual(["","toto","tata","totototo","tototata","tatatoto","tatatata"]);
+	});
+	xit('regLikeVariants handle nested ([a-f]|<ref>){0,1}', () => {
+		expect(app.regLikeVariants("autre mot")).toEqual(["autre mot","Autre Mot","AUTRE MOT"]);
+	});
+	xit('regLikeVariants handle plop:\\:', () => {
+		expect(app.regLikeVariants("autre mot")).toEqual(["autre mot","Autre Mot","AUTRE MOT"]);
+	});
+	xit('regLikeVariants handle plop\\::', () => {
+		expect(app.regLikeVariants("autre mot")).toEqual(["autre mot","Autre Mot","AUTRE MOT"]);
+	});
+	xit('regLikeVariants handle [\\]*]', () => {
+		expect(app.regLikeVariants("autre mot")).toEqual(["autre mot","Autre Mot","AUTRE MOT"]);
+	});
+});
diff --git a/public/index.html b/public/index.html
index 9bd9ec11d7bb44da13eeedf6636f5276510165fe..49d2915fd667720a2c039d055a252412cb7a5f6d 100644
--- a/public/index.html
+++ b/public/index.html
@@ -52,28 +52,28 @@
 <fieldset class="salt">
     <legend title="dictionnaire">Liste d'identifiants secrets à tester :</legend>
     <div class="actions">
-        <button class="case">MaJusculeS</button> <button class="accent">désaccentué</button> <button class="lessDouble">tt → t</button>
+        <button class="case">MaJusculeS</button> <button class="accent">désaccentué</button> <button class="regLike">&lt;({[Avancé]})&gt;</button>
     </div>
     <textarea id="salt">
 exemple
 mon super login
-login
-Ǧrooonnnimoooo !
+Ǧ1
     </textarea>
 </fieldset>
 <fieldset class="pass">
     <legend title="dictionnaire">Liste de mot de passe à tester :</legend>
     <div class="actions">
-        <button class="case">MaJusculeS</button> <button class="accent">désaccentué</button> <button class="lessDouble">tt → t</button>
+        <button class="case">MaJusculeS</button> <button class="accent">désaccentué</button> <button class="regLike">&lt;({[Avancé]})&gt;</button>
     </div>
     <textarea id="pass">
-exemple
-1234
-password
+exemple avancé :
+space::[ _-.]{0,1}
+(m[o0]t|phra[s5]e)<space>de<space>pa[s5][s5]e
     </textarea>
 </fieldset>
 </div>
 <footer>
+    <a href="https://git.duniter.org/tools/gsper#Guide-d-utilisation" id="doc">⇉⇛⇒ Guide et documentation ⇐⇚⇇</a>
     <a href="https://git.duniter.org/tools/gsper" id="sourceRibbon" title="Fork me !">
         <span>AGPL-3.0</span>
         <span>Logiciel Libre</span>
diff --git a/public/main.js b/public/main.js
index 52e8abbc8534677b5dcb543e049b58c8aa2ea2c0..15287a7a49824774ec82506193212cfddd29c7f0 100644
--- a/public/main.js
+++ b/public/main.js
@@ -1,3 +1,5 @@
+import * as dico from "./dictionaryBuilder.js";
+
 const workers = [];
 function startWorkers() {
 	for (let i=0;i<navigator.hardwareConcurrency;i++){
@@ -35,20 +37,15 @@ function combiTested(event){
 	}
 }
 
-
-
-//const separators = ['',' ','-','.','_'];
-//const specialEndChar = ['','!','.','?',':','§'];
-//const motsMax = 6;
 function genAction(event,func){
 	const textarea = event.target.parentNode.parentNode.querySelector("textArea");
-	textarea.value = dedup(apply(multiLineString2cleanArray(textarea.value),[func])).join("\n");
+	textarea.value = dico.dedup(apply(multiLineString2cleanArray(textarea.value),[func])).join("\n");
 	updateEstimate();
 }
 
-addEventsListeners(document.querySelectorAll(".accent"),"click",(e)=>genAction(e,noAccentVariant));
-addEventsListeners(document.querySelectorAll(".case"),"click",(e)=>genAction(e,casesVariants));
-addEventsListeners(document.querySelectorAll(".lessDouble"),"click",(e)=>genAction(e,lessDoubleLetters));
+addEventsListeners(document.querySelectorAll(".accent"),"click",(e)=>genAction(e,dico.noAccentVariant));
+addEventsListeners(document.querySelectorAll(".case"),"click",(e)=>genAction(e,dico.casesVariants));
+addEventsListeners(document.querySelectorAll(".regLike"),"click",(e)=>genAction(e,dico.regLikeVariants));
 
 
 
@@ -110,42 +107,9 @@ function apply(data,funcList){
 	for (let f of funcList){
 		let nextData = [];
 		for (let str of oldData){
-			nextData = nextData.concat(f(str));
+			nextData = nextData.concat(f(str,oldData));
 		}
 		oldData = nextData;
 	}
 	return oldData;
 }
-
-function lessDoubleLetters(string){
-	let variantes = [];
-	for (let i in string){
-		const j = i*1+1;
-		if(i < string.length-2 && string[i] === string[j]){
-			const variante = string.substr(0,i) + string.substr(j);
-			variantes = variantes.concat(lessDoubleLetters(variante));
-		}
-	}
-	variantes.push(string);
-	return dedup(variantes);
-}
-function dedup(array) {
-	const res = {};
-	array.forEach(v=>res[v]=v);
-	return Object.keys(res);
-}
-function casesVariants(string) {
-	return dedup([
-		string,
-		string.charAt(0).toUpperCase() + string.slice(1),
-		string.toLowerCase(),
-		string.toUpperCase()
-	]);
-}
-function noAccentVariant(string) {
-	const conversionMap = {'Á':'A','Ă':'A','Ắ':'A','Ặ':'A','Ằ':'A','Ẳ':'A','Ẵ':'A','Ǎ':'A','Â':'A','Ấ':'A','Ậ':'A','Ầ':'A','Ẩ':'A','Ẫ':'A','Ä':'A','Ǟ':'A','Ȧ':'A','Ǡ':'A','Ạ':'A','Ȁ':'A','À':'A','Ả':'A','Ȃ':'A','Ā':'A','Ą':'A','Å':'A','Ǻ':'A','Ḁ':'A','Ⱥ':'A','Ã':'A','Ꜳ':'AA','Æ':'AE','Ǽ':'AE','Ǣ':'AE','Ꜵ':'AO','Ꜷ':'AU','Ꜹ':'AV','Ꜻ':'AV','Ꜽ':'AY','Ḃ':'B','Ḅ':'B','Ɓ':'B','Ḇ':'B','Ƀ':'B','Ƃ':'B','Ć':'C','Č':'C','Ç':'C','Ḉ':'C','Ĉ':'C','Ċ':'C','Ƈ':'C','Ȼ':'C','Ď':'D','Ḑ':'D','Ḓ':'D','Ḋ':'D','Ḍ':'D','Ɗ':'D','Ḏ':'D','Dz':'D','Dž':'D','Đ':'D','Ƌ':'D','DZ':'DZ','DŽ':'DZ','É':'E','Ĕ':'E','Ě':'E','Ȩ':'E','Ḝ':'E','Ê':'E','Ế':'E','Ệ':'E','Ề':'E','Ể':'E','Ễ':'E','Ḙ':'E','Ë':'E','Ė':'E','Ẹ':'E','Ȅ':'E','È':'E','Ẻ':'E','Ȇ':'E','Ē':'E','Ḗ':'E','Ḕ':'E','Ę':'E','Ɇ':'E','Ẽ':'E','Ḛ':'E','Ꝫ':'ET','Ḟ':'F','Ƒ':'F','Ǵ':'G','Ğ':'G','Ǧ':'G','Ģ':'G','Ĝ':'G','Ġ':'G','Ɠ':'G','Ḡ':'G','Ǥ':'G','Ḫ':'H','Ȟ':'H','Ḩ':'H','Ĥ':'H','Ⱨ':'H','Ḧ':'H','Ḣ':'H','Ḥ':'H','Ħ':'H','Í':'I','Ĭ':'I','Ǐ':'I','Î':'I','Ï':'I','Ḯ':'I','İ':'I','Ị':'I','Ȉ':'I','Ì':'I','Ỉ':'I','Ȋ':'I','Ī':'I','Į':'I','Ɨ':'I','Ĩ':'I','Ḭ':'I','Ꝺ':'D','Ꝼ':'F','Ᵹ':'G','Ꞃ':'R','Ꞅ':'S','Ꞇ':'T','Ꝭ':'IS','Ĵ':'J','Ɉ':'J','Ḱ':'K','Ǩ':'K','Ķ':'K','Ⱪ':'K','Ꝃ':'K','Ḳ':'K','Ƙ':'K','Ḵ':'K','Ꝁ':'K','Ꝅ':'K','Ĺ':'L','Ƚ':'L','Ľ':'L','Ļ':'L','Ḽ':'L','Ḷ':'L','Ḹ':'L','Ⱡ':'L','Ꝉ':'L','Ḻ':'L','Ŀ':'L','Ɫ':'L','Lj':'L','Ł':'L','LJ':'LJ','Ḿ':'M','Ṁ':'M','Ṃ':'M','Ɱ':'M','Ń':'N','Ň':'N','Ņ':'N','Ṋ':'N','Ṅ':'N','Ṇ':'N','Ǹ':'N','Ɲ':'N','Ṉ':'N','Ƞ':'N','Nj':'N','Ñ':'N','NJ':'NJ','Ó':'O','Ŏ':'O','Ǒ':'O','Ô':'O','Ố':'O','Ộ':'O','Ồ':'O','Ổ':'O','Ỗ':'O','Ö':'O','Ȫ':'O','Ȯ':'O','Ȱ':'O','Ọ':'O','Ő':'O','Ȍ':'O','Ò':'O','Ỏ':'O','Ơ':'O','Ớ':'O','Ợ':'O','Ờ':'O','Ở':'O','Ỡ':'O','Ȏ':'O','Ꝋ':'O','Ꝍ':'O','Ō':'O','Ṓ':'O','Ṑ':'O','Ɵ':'O','Ǫ':'O','Ǭ':'O','Ø':'O','Ǿ':'O','Õ':'O','Ṍ':'O','Ṏ':'O','Ȭ':'O','Ƣ':'OI','Ꝏ':'OO','Ɛ':'E','Ɔ':'O','Ȣ':'OU','Ṕ':'P','Ṗ':'P','Ꝓ':'P','Ƥ':'P','Ꝕ':'P','Ᵽ':'P','Ꝑ':'P','Ꝙ':'Q','Ꝗ':'Q','Ŕ':'R','Ř':'R','Ŗ':'R','Ṙ':'R','Ṛ':'R','Ṝ':'R','Ȑ':'R','Ȓ':'R','Ṟ':'R','Ɍ':'R','Ɽ':'R','Ꜿ':'C','Ǝ':'E','Ś':'S','Ṥ':'S','Š':'S','Ṧ':'S','Ş':'S','Ŝ':'S','Ș':'S','Ṡ':'S','Ṣ':'S','Ṩ':'S','Ť':'T','Ţ':'T','Ṱ':'T','Ț':'T','Ⱦ':'T','Ṫ':'T','Ṭ':'T','Ƭ':'T','Ṯ':'T','Ʈ':'T','Ŧ':'T','Ɐ':'A','Ꞁ':'L','Ɯ':'M','Ʌ':'V','Ꜩ':'TZ','Ú':'U','Ŭ':'U','Ǔ':'U','Û':'U','Ṷ':'U','Ü':'U','Ǘ':'U','Ǚ':'U','Ǜ':'U','Ǖ':'U','Ṳ':'U','Ụ':'U','Ű':'U','Ȕ':'U','Ù':'U','Ủ':'U','Ư':'U','Ứ':'U','Ự':'U','Ừ':'U','Ử':'U','Ữ':'U','Ȗ':'U','Ū':'U','Ṻ':'U','Ų':'U','Ů':'U','Ũ':'U','Ṹ':'U','Ṵ':'U','Ꝟ':'V','Ṿ':'V','Ʋ':'V','Ṽ':'V','Ꝡ':'VY','Ẃ':'W','Ŵ':'W','Ẅ':'W','Ẇ':'W','Ẉ':'W','Ẁ':'W','Ⱳ':'W','Ẍ':'X','Ẋ':'X','Ý':'Y','Ŷ':'Y','Ÿ':'Y','Ẏ':'Y','Ỵ':'Y','Ỳ':'Y','Ƴ':'Y','Ỷ':'Y','Ỿ':'Y','Ȳ':'Y','Ɏ':'Y','Ỹ':'Y','Ź':'Z','Ž':'Z','Ẑ':'Z','Ⱬ':'Z','Ż':'Z','Ẓ':'Z','Ȥ':'Z','Ẕ':'Z','Ƶ':'Z','IJ':'IJ','Œ':'OE','ᴀ':'A','ᴁ':'AE','ʙ':'B','ᴃ':'B','ᴄ':'C','ᴅ':'D','ᴇ':'E','ꜰ':'F','ɢ':'G','ʛ':'G','ʜ':'H','ɪ':'I','ʁ':'R','ᴊ':'J','ᴋ':'K','ʟ':'L','ᴌ':'L','ᴍ':'M','ɴ':'N','ᴏ':'O','ɶ':'OE','ᴐ':'O','ᴕ':'OU','ᴘ':'P','ʀ':'R','ᴎ':'N','ᴙ':'R','ꜱ':'S','ᴛ':'T','ⱻ':'E','ᴚ':'R','ᴜ':'U','ᴠ':'V','ᴡ':'W','ʏ':'Y','ᴢ':'Z','á':'a','ă':'a','ắ':'a','ặ':'a','ằ':'a','ẳ':'a','ẵ':'a','ǎ':'a','â':'a','ấ':'a','ậ':'a','ầ':'a','ẩ':'a','ẫ':'a','ä':'a','ǟ':'a','ȧ':'a','ǡ':'a','ạ':'a','ȁ':'a','à':'a','ả':'a','ȃ':'a','ā':'a','ą':'a','ᶏ':'a','ẚ':'a','å':'a','ǻ':'a','ḁ':'a','ⱥ':'a','ã':'a','ꜳ':'aa','æ':'ae','ǽ':'ae','ǣ':'ae','ꜵ':'ao','ꜷ':'au','ꜹ':'av','ꜻ':'av','ꜽ':'ay','ḃ':'b','ḅ':'b','ɓ':'b','ḇ':'b','ᵬ':'b','ᶀ':'b','ƀ':'b','ƃ':'b','ɵ':'o','ć':'c','č':'c','ç':'c','ḉ':'c','ĉ':'c','ɕ':'c','ċ':'c','ƈ':'c','ȼ':'c','ď':'d','ḑ':'d','ḓ':'d','ȡ':'d','ḋ':'d','ḍ':'d','ɗ':'d','ᶑ':'d','ḏ':'d','ᵭ':'d','ᶁ':'d','đ':'d','ɖ':'d','ƌ':'d','ı':'i','ȷ':'j','ɟ':'j','ʄ':'j','dz':'dz','dž':'dz','é':'e','ĕ':'e','ě':'e','ȩ':'e','ḝ':'e','ê':'e','ế':'e','ệ':'e','ề':'e','ể':'e','ễ':'e','ḙ':'e','ë':'e','ė':'e','ẹ':'e','ȅ':'e','è':'e','ẻ':'e','ȇ':'e','ē':'e','ḗ':'e','ḕ':'e','ⱸ':'e','ę':'e','ᶒ':'e','ɇ':'e','ẽ':'e','ḛ':'e','ꝫ':'et','ḟ':'f','ƒ':'f','ᵮ':'f','ᶂ':'f','ǵ':'g','ğ':'g','ǧ':'g','ģ':'g','ĝ':'g','ġ':'g','ɠ':'g','ḡ':'g','ᶃ':'g','ǥ':'g','ḫ':'h','ȟ':'h','ḩ':'h','ĥ':'h','ⱨ':'h','ḧ':'h','ḣ':'h','ḥ':'h','ɦ':'h','ẖ':'h','ħ':'h','ƕ':'hv','í':'i','ĭ':'i','ǐ':'i','î':'i','ï':'i','ḯ':'i','ị':'i','ȉ':'i','ì':'i','ỉ':'i','ȋ':'i','ī':'i','į':'i','ᶖ':'i','ɨ':'i','ĩ':'i','ḭ':'i','ꝺ':'d','ꝼ':'f','ᵹ':'g','ꞃ':'r','ꞅ':'s','ꞇ':'t','ꝭ':'is','ǰ':'j','ĵ':'j','ʝ':'j','ɉ':'j','ḱ':'k','ǩ':'k','ķ':'k','ⱪ':'k','ꝃ':'k','ḳ':'k','ƙ':'k','ḵ':'k','ᶄ':'k','ꝁ':'k','ꝅ':'k','ĺ':'l','ƚ':'l','ɬ':'l','ľ':'l','ļ':'l','ḽ':'l','ȴ':'l','ḷ':'l','ḹ':'l','ⱡ':'l','ꝉ':'l','ḻ':'l','ŀ':'l','ɫ':'l','ᶅ':'l','ɭ':'l','ł':'l','lj':'lj','ſ':'s','ẜ':'s','ẛ':'s','ẝ':'s','ḿ':'m','ṁ':'m','ṃ':'m','ɱ':'m','ᵯ':'m','ᶆ':'m','ń':'n','ň':'n','ņ':'n','ṋ':'n','ȵ':'n','ṅ':'n','ṇ':'n','ǹ':'n','ɲ':'n','ṉ':'n','ƞ':'n','ᵰ':'n','ᶇ':'n','ɳ':'n','ñ':'n','nj':'nj','ó':'o','ŏ':'o','ǒ':'o','ô':'o','ố':'o','ộ':'o','ồ':'o','ổ':'o','ỗ':'o','ö':'o','ȫ':'o','ȯ':'o','ȱ':'o','ọ':'o','ő':'o','ȍ':'o','ò':'o','ỏ':'o','ơ':'o','ớ':'o','ợ':'o','ờ':'o','ở':'o','ỡ':'o','ȏ':'o','ꝋ':'o','ꝍ':'o','ⱺ':'o','ō':'o','ṓ':'o','ṑ':'o','ǫ':'o','ǭ':'o','ø':'o','ǿ':'o','õ':'o','ṍ':'o','ṏ':'o','ȭ':'o','ƣ':'oi','ꝏ':'oo','ɛ':'e','ᶓ':'e','ɔ':'o','ᶗ':'o','ȣ':'ou','ṕ':'p','ṗ':'p','ꝓ':'p','ƥ':'p','ᵱ':'p','ᶈ':'p','ꝕ':'p','ᵽ':'p','ꝑ':'p','ꝙ':'q','ʠ':'q','ɋ':'q','ꝗ':'q','ŕ':'r','ř':'r','ŗ':'r','ṙ':'r','ṛ':'r','ṝ':'r','ȑ':'r','ɾ':'r','ᵳ':'r','ȓ':'r','ṟ':'r','ɼ':'r','ᵲ':'r','ᶉ':'r','ɍ':'r','ɽ':'r','ↄ':'c','ꜿ':'c','ɘ':'e','ɿ':'r','ś':'s','ṥ':'s','š':'s','ṧ':'s','ş':'s','ŝ':'s','ș':'s','ṡ':'s','ṣ':'s','ṩ':'s','ʂ':'s','ᵴ':'s','ᶊ':'s','ȿ':'s','ɡ':'g','ᴑ':'o','ᴓ':'o','ᴝ':'u','ť':'t','ţ':'t','ṱ':'t','ț':'t','ȶ':'t','ẗ':'t','ⱦ':'t','ṫ':'t','ṭ':'t','ƭ':'t','ṯ':'t','ᵵ':'t','ƫ':'t','ʈ':'t','ŧ':'t','ᵺ':'th','ɐ':'a','ᴂ':'ae','ǝ':'e','ᵷ':'g','ɥ':'h','ʮ':'h','ʯ':'h','ᴉ':'i','ʞ':'k','ꞁ':'l','ɯ':'m','ɰ':'m','ᴔ':'oe','ɹ':'r','ɻ':'r','ɺ':'r','ⱹ':'r','ʇ':'t','ʌ':'v','ʍ':'w','ʎ':'y','ꜩ':'tz','ú':'u','ŭ':'u','ǔ':'u','û':'u','ṷ':'u','ü':'u','ǘ':'u','ǚ':'u','ǜ':'u','ǖ':'u','ṳ':'u','ụ':'u','ű':'u','ȕ':'u','ù':'u','ủ':'u','ư':'u','ứ':'u','ự':'u','ừ':'u','ử':'u','ữ':'u','ȗ':'u','ū':'u','ṻ':'u','ų':'u','ᶙ':'u','ů':'u','ũ':'u','ṹ':'u','ṵ':'u','ᵫ':'ue','ꝸ':'um','ⱴ':'v','ꝟ':'v','ṿ':'v','ʋ':'v','ᶌ':'v','ⱱ':'v','ṽ':'v','ꝡ':'vy','ẃ':'w','ŵ':'w','ẅ':'w','ẇ':'w','ẉ':'w','ẁ':'w','ⱳ':'w','ẘ':'w','ẍ':'x','ẋ':'x','ᶍ':'x','ý':'y','ŷ':'y','ÿ':'y','ẏ':'y','ỵ':'y','ỳ':'y','ƴ':'y','ỷ':'y','ỿ':'y','ȳ':'y','ẙ':'y','ɏ':'y','ỹ':'y','ź':'z','ž':'z','ẑ':'z','ʑ':'z','ⱬ':'z','ż':'z','ẓ':'z','ȥ':'z','ẕ':'z','ᵶ':'z','ᶎ':'z','ʐ':'z','ƶ':'z','ɀ':'z','ff':'ff','ffi':'ffi','ffl':'ffl','fi':'fi','fl':'fl','ij':'ij','œ':'oe','st':'st','ₐ':'a','ₑ':'e','ᵢ':'i','ⱼ':'j','ₒ':'o','ᵣ':'r','ᵤ':'u','ᵥ':'v','ₓ':'x'};
-	return dedup([
-		string,
-		string.replace( /[^A-Za-z0-9]/g, (a) => conversionMap[a]||a )
-	]);
-}
diff --git a/public/style.css b/public/style.css
index e4e6cb390ba8cd11bcc14d5f3d3f73f405248bd8..c4bbe5effbf6ba9457e4cbdc657485d4ab58f089 100644
--- a/public/style.css
+++ b/public/style.css
@@ -20,6 +20,7 @@ textarea {height: 100%; width: 100%;}
 button {width: 100%; height: 32px}
 header {height: 180px;position: fixed;top:0;left:0;right: 0;}
 #lists{position: fixed;top:180px;left:0;right: 0;bottom: 0;}
+#doc{position: fixed;top:20px;left:28px;line-height: 50px;}
 .actions {
     display: flex;
     flex-wrap: wrap;
diff --git a/public/test.html b/public/test.html
index bec82767c065dda5a3fa8c7664bdb663851a76f0..c0c1d6ba5ac7d42926fa2f9aeff13be7b2f2c386 100644
--- a/public/test.html
+++ b/public/test.html
@@ -7,3 +7,4 @@
 <script type="text/javascript" src="../node_modules/jasmine-core/lib/jasmine-core/boot.js"></script>
 
 <script type="module" src="crypto.test.js"></script>
+<script type="module" src="dictionaryBuilder.test.js"></script>