diff --git a/src/dictionary-parser.mjs b/src/dictionary-parser.mjs
index 71f208be7e3067bf7380944dce6eaf3a31d02cd8..5ae91798b97a08a1691593f7bb2fda47d95cfc11 100644
--- a/src/dictionary-parser.mjs
+++ b/src/dictionary-parser.mjs
@@ -17,43 +17,14 @@ function parseLine(theLine, allLines) {
 function combineUnspecified2IdSecPwd(lines) {
 	const idSecPwdLines = [];
 	const unspecifiedLines = [];
-	lines.forEach(line => line.includes('@@@@') ? deepUnspecifiedExtractor(line, unspecifiedLines, idSecPwdLines) : unspecifiedLines.push(line));
+	lines.forEach(line => line.includes('@@@@') ? idSecPwdLines.push(line) : unspecifiedLines.push(line));
 	if (unspecifiedLines.length) idSecPwdLines.push(`${mergeLines(unspecifiedLines)}@@@@${mergeLines(unspecifiedLines)}`)
 	return mergeLines(idSecPwdLines);
 }
 
-function deepUnspecifiedExtractor(line, unspecifiedLines, idSecPwdLines) {
-	const hybridTree = tree.buildTreeStruct(line);
-
-	/*
-	buildTree (à créer dans un module à part)
-	parcours en profondeur jusqu'à trouver des branches unspecified.
-	extraction de celles-ci pour les ajouter (avec leur chaine de parents) aux unspecifiedlines
-	ajout de l'arbre restant aux idSecPwdLines
-	 */
-	idSecPwdLines.push(line);
-}
-
 function mergeLines(lines) {
-	//console.log('lines:',lines);
 	if (!lines.length) return '';
 	lines = lines.filter(l => l.length);
 	if (lines.length === 1) return lines[0];
 	return `(${lines.join('|')})`;
 }
-
-/*
-const json1 = '(a(b@@@@c|d)|(e|f)|g|h@@@@i)'
-const json2 = {
-	'a':'a'{
-						'b@@@@c':'b@@@@c',
-						'd':'d'
-					},
-	{
-		'e':'e',
-		'f':'f'
-	},
-	'g':'g',
-	'h@@@@i':'h@@@@i'
-}
-*/
diff --git a/src/dictionary-parser.test.mjs b/src/dictionary-parser.test.mjs
index fdd9aaee09f526f0924d380685199b2abed6ffa7..b414b48bc38c0f37f4fedba036719db3107cda5c 100644
--- a/src/dictionary-parser.test.mjs
+++ b/src/dictionary-parser.test.mjs
@@ -15,6 +15,3 @@ a@@@@(b|c)
 h@@@@(i|j)
 `), '(a@@@@(b|c)|h@@@@(i|j)|((d|e)|(f|g))@@@@((d|e)|(f|g)))');
 });
-test.skip('no @@@@ cases combined with @@@@ case on same line recombine to allways finish with @@@@ case', t => {
-	t.is(app.parse('(a(b@@@@c|d)|(e|f)|g|h@@@@i)'), '(g@@@@h|(a|b|c)@@@@(a|b|c))');
-});
diff --git a/src/dictionary-tree.mjs b/src/dictionary-tree.mjs
index 21f4dc23a98327d47a4bcd254f5f89ebc48f432e..fbf9a37e8ed66a347e0a23ae3ac5d139f18a960a 100644
--- a/src/dictionary-tree.mjs
+++ b/src/dictionary-tree.mjs
@@ -2,21 +2,23 @@ export function build(dictionaryString) {
 }
 
 export function buildTreeStruct(monoLineString) {
-	//console.log('srcTree', monoLineString);
 	const stringAsArray = monoLineString.split('');
 	const rawTree = leftParser(stringAsArray);
-	//console.log('rawTree', JSON.stringify(rawTree));
 	const outOfScope = stringAsArray.length;
 	if (outOfScope) throw `fail to build tree from : "${monoLineString}" parsed: ${JSON.stringify(rawTree)} unparsed/failed: ${stringAsArray.join('')}`;
-	//return rawTree;//trivialDedup(flattenTree(rawTree))
-	return flattenTree(flattenTree(flattenTree(rawTree)));
+	let lastTree, tree = rawTree;
+	do {
+		lastTree = JSON.stringify(tree);
+		tree = flattenTree(tree);
+	} while (JSON.stringify(tree) !== lastTree)
+	return tree;
 }
 
 /**
  * leftParser stuff
  */
 function flushNoEmptyString(data) {
-	if (data.str.length) data.tree[data.tree.length - 1].step.push(data.str);
+	if (data.str.length) data.tree.alt[data.tree.alt.length - 1].step.push(data.str);
 	data.str = '';
 }
 
@@ -25,11 +27,11 @@ function appendToString(chr, data) {
 }
 
 function nextAlt(data) {
-	data.tree.push({step: []});
+	data.tree.alt.push({step: []});
 }
 
 function goIntoNewAlt(data) {
-	data.tree[data.tree.length - 1].step.push(leftParser(data.input));
+	data.tree.alt[data.tree.alt.length - 1].step.push(leftParser(data.input));
 }
 
 function returnTrue() {
@@ -50,7 +52,7 @@ function leftParser(inputChrArray) {
 	const data = {
 		input: inputChrArray,
 		str: '',
-		tree: [{step: []}],
+		tree: {alt: [{step: []}]},
 	};
 	while (data.input.length) {
 		const chr = data.input.shift();
@@ -68,90 +70,69 @@ function concatStrings(array) {
 	const data = {
 		input: array,
 		str: '',
-		tree: [{step: []}],
+		tree: {alt: [{step: []}]}, // Output array
 	};
 	array.forEach(e => {
-		if (typeof e === 'string') appendToString(e, data);
+		if (isString(e)) appendToString(e, data);
 		else {
 			flushNoEmptyString(data)
-			data.tree[data.tree.length - 1].step.push(e);
+			data.tree.alt[data.tree.alt.length - 1].step.push(e);
 		}
 	});
 	flushNoEmptyString(data)
-	return data.tree[data.tree.length - 1].step;
+	return data.tree.alt[data.tree.alt.length - 1].step;
 }
 
 function flattenTree(tree) {
-	if (typeof tree === 'string') return tree;
-	if (Array.isArray(tree) && tree.length === 0) return '';
-	if (Array.isArray(tree) && tree.length === 1) return flattenTree(tree[0]);
-	if (isStep(tree)) {
-		tree.step = tree.step.map(flattenTree);
-		if (!Array.isArray(tree.step)) return flattenTree(tree.step);
-		if (tree.step.length === 1) return flattenTree(tree.step);
-		if (tree.step.length === 0) return '';
-		if (!tree.step.reduce((acc, cur) => Array.isArray(cur) || acc, false)) return concatStrings(tree.step);
+	if (isString(tree)) return tree;
+	const objType = isAlt(tree)?'alt':'step';
+	tree[objType] = tree[objType].map(flattenTree);
+	if (tree[objType].length === 0) return '';
+	if (tree[objType].length === 1) return tree[objType][0];
+
+	if (isAlt(tree)) {
+		tree.alt = trivialDedup(tree.alt);
+		tree.alt = [].concat(...tree.alt.map(e => isAlt(e) ? e.alt : [e]));
 		return tree;
 	}
-
-	if (tree.length === 1) {
-		//console.log('aloneChild', JSON.stringify(tree[0]));
-		if (typeof tree[0] === 'string') return tree[0];
-		if (Array.isArray(tree[0])) return flattenTree(tree[0]);
-		//return flattenTree(tree[0].step);
+	if (isStep(tree)) {
+		tree.step = concatStrings(tree.step);
+		return tree;
 	}
+}
 
-	if (!Array.isArray(tree)) throw `Error : ${tree} should be an Array. ${JSON.stringify(tree)}`;
-	//console.log('tree:', JSON.stringify(tree));
-	///if(isStep(tree[0])) tree[0].step = flattenTree(tree[0].step);
-	tree = trivialDedup(tree.map(flattenTree));
-	tree = [].concat(...tree.map(e => Array.isArray(e) ? e : [e]));
-
-	return tree;
+function isString(element) {
+	return typeof element === 'string';
 }
 
 function isStep(element) {
 	return typeof element === 'object' && typeof element.step !== 'undefined';
 }
 
+function isAlt(element) {
+	return typeof element === 'object' && typeof element.alt !== 'undefined';
+}
+
 function trivialDedup(tree) {
-	if (typeof tree === 'string') return tree;
-	if (isStep(tree)) return {step: tree.step.map(subTree => trivialDedup(subTree))};
-	if (Array.isArray(tree)) {
-		const dedupKeys = {};
-		tree.forEach(v => dedupKeys[JSON.stringify(v)] = v); // eslint-disable-line no-return-assign
-		return Object.keys(dedupKeys).map(json => trivialDedup(JSON.parse(json)));
-	}
-	throw `unknown case : ${tree}`;
+	const dedupKeys = {};
+	tree.sort();
+	tree.forEach(v => dedupKeys[JSON.stringify(v)] = v); // eslint-disable-line no-return-assign
+	return Object.keys(dedupKeys).map(JSON.parse);
 }
 
 export function serialize(treeStruct) {
-	if (typeof treeStruct === 'string') return treeStruct;
-	if (Array.isArray(treeStruct)) return `(${treeStruct.map(serialize).join('|')})`;
+	if (isString(treeStruct)) return treeStruct;
 	if (isStep(treeStruct)) return treeStruct.step.map(serialize).join('');
+	if (isAlt(treeStruct)) return `(${treeStruct.alt.map(serialize).join('|')})`;
 	throw new Error(`Error: how to serialize ${JSON.stringify(treeStruct)} RAW: ${treeStruct}`);
 }
 
-/*
-export function extract(treeNavArray,fromTreeWrapped){
-	if(!Array.isArray(treeNavArray)) throw new Error(`treeNav: ${JSON.stringify(treeNavArray)} should be an integer array.`);
-	let extractedTree = '';
-	if(treeNavArray.length === 0) return fromTreeWrapped.pop();
-	if (typeof fromTreeWrapped[0] === 'string') throw new Error(`invalid treeNav pointer ${JSON.stringify(treeNavArray)} in ${serialize(fromTreeWrapped[0])} no branch ${treeNavArray[0]}.`);
-	if (Array.isArray(fromTreeWrapped[0])) {
-		const branch = treeNavArray.shift();
-		const extractedTree = fromTreeWrapped[0][branch]; // recursive here ?
-		//fromTreeWrapped[0] = [].concat(branch>0?fromTreeWrapped[0].slice(0,branch-1):[],fromTreeWrapped[0].slice(branch+1,fromTreeWrapped[0].length));
-		return extractedTree;
-	}
-	if (isStep(fromTreeWrapped[0])) {
-		const extractedTree = {step:[]};
-		fromTreeWrapped[0].step.forEach()
-
-		f
-	}
-
+export function altCount(treeStruct) {
+	if (isString(treeStruct)) return 1;
+	if (isStep(treeStruct)) return treeStruct.step.reduce((acc, cur) => acc * altCount(cur), 1);
+	if (isAlt(treeStruct)) return treeStruct.reduce((acc, cur) => acc + altCount(cur), 0);
+}
 
-	return extractedTree;
+export function getAlternative(altNumber, tree) {
+	return 'abc';
 }
-*/
diff --git a/src/dictionary-tree.test.mjs b/src/dictionary-tree.test.mjs
index 74c45015a113be407be2cc851714aaf2481fd620..8fd0f4c695e8ebf8261d9c45aae5640cafb4867d 100644
--- a/src/dictionary-tree.test.mjs
+++ b/src/dictionary-tree.test.mjs
@@ -1,38 +1,25 @@
 import test from 'ava';
 import * as app from './dictionary-tree.mjs';
 
-const buildTreeStruct = str => JSON.stringify(app.buildTreeStruct(str));
-const expected = str => JSON.stringify(str);
+const buildTreeThenSerialize = str => app.serialize(app.buildTreeStruct(str));
 
-test('simple string still simple string', t => t.is(buildTreeStruct('abc'), expected('abc')));
-test('(a|b) alt as array', t => t.is(buildTreeStruct('(a|b)'), expected(['a', 'b'])));
-// Ok to be permissive test('a) throw',t=>t.throws(()=>buildTreeStruct('a)')));
+test('simple string still simple string', t => t.is(buildTreeThenSerialize('abc'), 'abc'));
+test('(a|b) alt still (a|b)', t => t.is(buildTreeThenSerialize('(a|b)'), '(a|b)'));
+test('a)b throw', t => t.throws(() => buildTreeStruct('a)b')));
 // Ok to be permissive test('(a throw',t=>t.throws(()=>buildTreeStruct('(a')));
 // Ok to be permissive test('a|b throw',t=>t.throws(()=>buildTreeStruct('a|b')));
-test('(|b) empty choice is choice', t => t.is(buildTreeStruct('(|b)'), expected(['', 'b'])));
-test('(b|b) trivial dedup', t => t.is(buildTreeStruct('(|b||b|)'), expected(['', 'b'])));
-test('a(b|c) ordered part in step obj', t => t.is(buildTreeStruct('a(b|c)'), expected({step: ['a', ['b', 'c']]})));
-test('a(b) flat merge when no alt', t => t.is(buildTreeStruct('a(b)'), expected('ab')));
-test('build complexe tree with (|) pattern', t => t.is(buildTreeStruct('(a(|b@@@@c|d|)|(e|f)|g|h@@@@i)'),
-	expected([{step: ['a', ['', 'b@@@@c', 'd']]}, 'e', 'f', 'g', 'h@@@@i'])
-));
-test('serialize tree to a(b|c)', t => t.is(app.serialize({step: ['a', ['b', 'c']]}), 'a(b|c)'));
-test('serialize incorrect tree throw', t => t.throws(() => app.serialize({plop: ['a']})));
+test('(|b) keep empty choice', t => t.is(buildTreeThenSerialize('(|b)'), '(|b)'));
+test('(b|b) trivial dedup', t => t.is(buildTreeThenSerialize('(|b||b|)'), '(|b)'));
+test('a(b|c) mix fix and alt', t => t.is(buildTreeThenSerialize('a(b|c)'), 'a(b|c)'));
+test('a(b) flat merge when no alt', t => t.is(buildTreeThenSerialize('a(b)'), 'ab'));
+test('build complexe tree with (|) pattern', t => t.is(buildTreeThenSerialize('(a(|b@@@@c|d|)|(e|f)|g|h@@@@i)'), '(a(|b@@@@c|d)|e|f|g|h@@@@i)'));
 
-const exempleTree = ()=>app.buildTreeStruct('a(b(c|d)|e(f|g|h)ij(k|l)|@@@@m)')
-test.skip('extract subtree ae(f|g|h)ij(k|l) from a(b(c|d)|e(f|g|h)ij(k|l)|@@@@m)',t =>{
-	const srcTree = exempleTree();
-	const treePointer = [1];
-	const extractedTree = app.extract(treePointer,[srcTree]);
+test('serialize incorrect tree throw', t => t.throws(() => app.serialize({plop: ['a']})));
 
-	t.is(JSON.stringify(extractedTree), expected({step: ['ae', ['f', 'g', 'h'], 'ij']}))
-	t.is(app.serialize(srcTree), 'a(b(c|d)|@@@@k)')
-});
-test.skip('extract subtree aehij from a(b(c|d)|e(f|g|h)ij(k|l)|@@@@m)',t =>{
-	const srcTree = exempleTree();
-	const treePointer = [1,2];
-	const extractedTree = app.extract(treePointer,[srcTree]);
 
-	t.is(extractedTree, 'aehij');
-	t.is(app.serialize(srcTree), 'a(b(c|d)|e(f|g)ij|@@@@k)')
-});
+const exampleTree = () => app.buildTreeStruct('a(b(c|d)|e(f|g|h)ij(k|l)|@@@@m)')
+test.skip('mono altCount', t => t.is(app.altCount(app.buildTreeStruct('ipsum')), 1));
+test.skip('simple altCount', t => t.is(app.altCount(app.buildTreeStruct('(lore|ipsu)m')), 2));
+test.skip('multi altCount', t => t.is(app.altCount(app.buildTreeStruct('(a|b|c)(d|e|f)g(h|i|j|k)')), 36));
+test.skip('multi level tree altCount', t => t.is(app.altCount(app.buildTreeStruct('a(b(c|d)|e(f|g|h)ij(k|l)|@@@@m)')), 9));
+test.skip('getAlternative 0', t => t.is(app.getAlternative(0, exampleTree()), 'abc'));