Index: TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/EmptyPropValuesMacro.groovy
===================================================================
--- TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/EmptyPropValuesMacro.groovy	(revision 0)
+++ TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/EmptyPropValuesMacro.groovy	(revision 3288)
@@ -0,0 +1,75 @@
+// Copyright © 2016 ENS de Lyon, CNRS, University of Franche-Comté
+// Licensed under the terms of the GNU General Public License (http://www.gnu.org/licenses)
+// @author mdecorde
+// @author sheiden
+// STANDARD DECLARATIONS
+package org.txm.macroprototypes.urs.misc
+
+import org.apache.commons.lang.StringUtils
+import org.kohsuke.args4j.*
+
+import groovy.transform.Field
+
+import org.txm.Toolbox
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import org.txm.macro.urs.AnalecUtils
+import org.txm.searchengine.cqp.AbstractCqiClient
+import org.txm.searchengine.cqp.corpus.*
+import org.txm.searchengine.cqp.corpus.query.CQLQuery
+
+import visuAnalec.donnees.Structure
+import visuAnalec.elements.*
+
+def scriptName = this.class.getSimpleName()
+
+def selection = []
+for (def s : corpusViewSelections) {
+	if (s instanceof CQPCorpus) selection << s
+	else if (s instanceof Partition) selection.addAll(s.getParts())
+}
+
+if (selection.size() == 0) {
+	println "** $scriptName: please select a Corpus or a Partition in the Corpus view: "+corpusViewSelections
+	return false
+}
+
+// BEGINNING OF PARAMETERS
+@Field @Option(name="schema_ursql", usage="TYPE@PROP=VALUE", widget="String", required=true, def="CHAINE")
+		String schema_ursql
+@Field @Option(name="minimum_schema_size", usage="Minimum size needed to consider a schema", widget="Integer", required=true, def="3")
+		int minimum_schema_size
+@Field @Option(name="unit_ursql", usage="TYPE@PROP=VALUE", widget="String", required=false, def="MENTION")
+		String unit_ursql
+@Field @Option(name="limit_cql", usage="CQL to build structure limits", widget="Query", required=true, def="<div> [] expand to div")
+		limit_cql
+@Field @Option(name="strict_inclusion", usage="Units must be strictly included into corpus matches", widget="Boolean", required=true, def="true")
+		boolean strict_inclusion
+@Field @Option(name="limit_distance", usage="Unit distance to structure limit (0 = no selection, 1 = first after limit, -1 = last before limit, etc.)", widget="Integer", required=true, def="0")
+		int limit_distance
+@Field @Option(name="debug", usage="Show internal variable content", widget="Boolean", required=true, def="false")
+		debug
+if (!ParametersDialog.open(this)) return
+
+	def CQI = CQPSearchEngine.getCqiClient()
+
+//corpus = corpusViewSelection
+for (def corpus : selection) {
+
+	mainCorpus = corpus.getMainCorpus()
+
+	def word = mainCorpus.getWordProperty()
+	def analecCorpus = URSCorpora.getCorpus(mainCorpus.getName())
+
+	def selectedUnits = AnalecUtils.selectUnitsInSchema(debug, analecCorpus, corpus, schema_ursql, minimum_schema_size, Integer.MAX_VALUE,
+			unit_ursql, limit_cql, strict_inclusion, limit_distance);
+
+	for (def unit : selectedUnits) {
+		def props = unit.getProps();
+		for (def k : props.keySet()) {
+			if (props[k] == null) {
+				println "$corpus\t"+unit.getDeb()+"->"+unit.getFin()+"\t"+k
+			}
+		}
+	}
+}
Index: TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/ChercherSupprimer.txt
===================================================================
--- TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/ChercherSupprimer.txt	(revision 0)
+++ TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/ChercherSupprimer.txt	(revision 3288)
@@ -0,0 +1,15 @@
+Macro ChercherSupprimer
+Auteur : Matthieu QUIGNARD
+Version : 05 Février 2019
+
+Supprime de façon **DEFINITIVE** les mentions qui ont une certaine valeur de propriété.
+Comme pour ChercherRemplacer, on peut choisir d'inclure aussi 
+les mentions qui ont une valeur vide pour la propriété donnée.
+
+Par exemple : 
+    CATEGORIE=ERREUR
+    CHECK=
+    REF=NON_REF (suppression des mentions non référentielles)
+    REF=SI (suppression de tous les singletons)
+    
+    
\ No newline at end of file

Property changes on: TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/ChercherSupprimer.txt
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/UnitTypesMacro.groovy
===================================================================
--- TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/UnitTypesMacro.groovy	(revision 0)
+++ TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/UnitTypesMacro.groovy	(revision 3288)
@@ -0,0 +1,48 @@
+// Copyright © 2016 ENS de Lyon, CNRS, University of Franche-Comté
+// Licensed under the terms of the GNU General Public License (http://www.gnu.org/licenses)
+// @author mdecorde
+// @author sheiden
+// STANDARD DECLARATIONS
+package org.txm.macroprototypes.urs.misc
+
+import org.kohsuke.args4j.*
+import groovy.transform.Field
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import org.txm.searchengine.cqp.corpus.*
+
+if (!(corpusViewSelection instanceof MainCorpus)) {
+	println "Corpora selection is not a Corpus"
+	return;
+}
+
+// BEGINNING OF PARAMETERS
+@Field @Option(name="schema_type",usage="", widget="String", required=true, def="MENTION")
+String schema_type
+
+if (!ParametersDialog.open(this)) return;
+
+MainCorpus corpus = corpusViewSelection
+def analecCorpus = URSCorpora.getCorpus(corpus);
+def map = new HashMap()
+def unitesInSchema = []
+def n = 0
+for (def schema : analecCorpus.getSchemas(schema_type)) {
+	def unites = schema.getUnitesSousjacentes()
+	unitesInSchema.addAll(unites)
+	n += unites.size()
+}
+
+def counts = unitesInSchema.countBy() { it };
+for (def c : counts.keySet()) {
+	if (counts[c] > 1) println "ERROR UNIT IN MULTIPLE SCHEMA["+c.getDeb()+", "+c.getFin()+"]="+c.getProps()+" in "+c.getSchemas().collect() {it.getProps()}
+}
+
+def set = new HashSet()
+set.addAll(unitesInSchema)
+for (def s : set.collect { it.getType() }) {
+	if (!map.containsKey(s)) map[s] = 0;
+	map[s] = map[s] +1
+}
+
+println "Unites types: "+map.sort() { it -> map[it]}
\ No newline at end of file
Index: TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/UnitsCorrelationMacro.groovy
===================================================================
--- TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/UnitsCorrelationMacro.groovy	(revision 0)
+++ TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/UnitsCorrelationMacro.groovy	(revision 3288)
@@ -0,0 +1,201 @@
+// Copyright © 2016 ENS de Lyon, CNRS, University of Franche-Comté
+// Licensed under the terms of the GNU General Public License (http://www.gnu.org/licenses)
+// @author mdecorde
+// @author sheiden
+// STANDARD DECLARATIONS
+package org.txm.macroprototypes.urs.misc
+
+import org.apache.commons.lang.StringUtils
+import org.txm.rcp.views.corpora.CorporaView
+import groovy.transform.Field
+
+import org.kohsuke.args4j.*
+import org.txm.Toolbox
+import org.txm.annotation.urs.*
+import org.txm.lexicaltable.core.statsengine.r.data.LexicalTableImpl
+import org.txm.macro.urs.*
+import org.txm.rcp.commands.*
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.searchengine.cqp.CQPSearchEngine
+import org.txm.searchengine.cqp.corpus.*
+import org.txm.searchengine.cqp.corpus.query.CQLQuery;
+import org.txm.statsengine.r.core.RWorkspace
+
+import visuAnalec.donnees.*
+import visuAnalec.elements.*
+import cern.colt.matrix.DoubleFactory2D
+import cern.colt.matrix.DoubleMatrix2D
+
+def scriptName = this.class.getSimpleName()
+def parent
+def selection = []
+if (!(corpusViewSelection instanceof CQPCorpus)) {
+	println "** $scriptName please select a Corpus to run the macro"
+}
+
+
+// BEGINNING OF PARAMETERS
+@Field @Option(name="schema_ursql", usage="TYPE@PROP=VALUE", widget="String", required=false, def="CHAINE")
+		String schema_ursql
+@Field @Option(name="minimum_schema_size", usage="Minimum size needed to consider a schema", widget="Integer", required=true, def="3")
+		int minimum_schema_size
+@Field @Option(name="maximum_schema_size", usage="Maximum size needed to consider a schema", widget="Integer", required=true, def="9999999")
+		int maximum_schema_size
+@Field @Option(name="unit_ursql", usage="TYPE@PROP=VALUE", widget="String", required=false, def="MENTION")
+		String unit_ursql
+@Field @Option(name="limit_distance_in_schema", usage="Unit distance in schema (0 = no selection, 1 = first after limit, -1 = last before limit, etc.)", widget="Integer", required=true, def="0")
+		int limit_distance_in_schema
+@Field @Option(name="limit_cql", usage="CQL to build structure limits", widget="Query", required=true, def="<div> [] expand to div")
+		limit_cql
+@Field @Option(name="strict_inclusion", usage="Units must be strictly included into corpus matches", widget="Boolean", required=true, def="true")
+		boolean strict_inclusion
+@Field @Option(name="limit_distance", usage="Unit distance to structure limit (0 = no selection, 1 = first after limit, -1 = last before limit, etc.)", widget="Integer", required=true, def="0")
+		int limit_distance
+@Field @Option(name="unit_prop1", usage="PROP1", widget="String", required=false, def="PROP1")
+		String unit_prop1
+@Field @Option(name="unit_prop2", usage="PROP2", widget="String", required=false, def="PROP2")
+		String unit_prop2
+@Field @Option(name="corr_method", usage="try them all", widget="StringArray", metaVar="pearson	spearman	kendall", required=false, def="pearson")
+		String corr_method
+@Field @Option(name="corr_style", usage="try them all", widget="StringArray", metaVar="circle	square	ellipse	number	shade	color	pie", required=false, def="number")
+		String corr_style
+@Field @Option(name="corr_layout", usage="try them all", widget="StringArray", metaVar="full	lower	upper", required=false, def="upper")
+		String corr_layout
+@Field @Option(name="corr_order", usage="try them all", widget="StringArray", metaVar="AOE	FPC	hclust	alphabet", required=false, def="hclust")
+		String corr_order
+@Field @Option(name="output_lexicaltable", usage="create or not a lexical table with the result", widget="Boolean", required=true, def="false")
+		output_lexicaltable
+@Field @Option(name="debug", usage="Show internal variable content", widget="StringArray", metaVar="OFF	ON	ALL	REALLY ALL", required=true, def="OFF")
+		debug
+if (!ParametersDialog.open(this)) return
+	if (debug == "OFF") debug = 0; else if (debug == "ON") debug = 1; else if (debug == "ALL") debug = 2 else if (debug == "REALLY ALL") debug = 3
+
+
+def CQI = CQPSearchEngine.getCqiClient()
+
+def correlations = [:]
+def values1 = new HashSet()
+def values2 = new HashSet()
+def corpus = corpusViewSelection
+
+mainCorpus = corpus.getMainCorpus()
+
+def word = mainCorpus.getWordProperty()
+def analecCorpus = URSCorpora.getCorpus(mainCorpus)
+
+
+
+def selectedUnits = AnalecUtils.selectUnitsInSchema(debug, analecCorpus, corpus, schema_ursql, minimum_schema_size, maximum_schema_size,
+		unit_ursql, limit_distance_in_schema, limit_cql, strict_inclusion, limit_distance);
+
+for (def unit : selectedUnits) {
+	def value1 = unit.getProp(unit_prop1)
+	if (value1 == null) value1 = "<null>"
+	if (value1.length() == 0) value1 = "<empty>"
+	def value2 = unit.getProp(unit_prop2)
+	if (value2 == null) value2 = "<null>"
+	if (value2.length() == 0) value2 = "<empty>"
+
+	values1 << value1
+	values2 << value2
+
+	if (!correlations.containsKey(value1)) correlations[value1] = [:]
+	def line = correlations[value1]
+	if (!line.containsKey(value2)) line[value2] = 0
+	line[value2] += 1
+}
+
+def matrix = new int[values1.size()][values2.size()];
+println "\t"+values2.join("\t")
+int i = 0;
+for (def value1 : values1) {
+	print value1
+	int j = 0;
+	for (def value2 : values2) {
+		if (correlations[value1][value2] == null) correlations[value1][value2] = 0;
+		print "\t"+correlations[value1][value2]
+
+		matrix[i][j] = correlations[value1][value2]
+		j++
+	}
+	println ""
+	i++
+}
+
+def r = RWorkspace.getRWorkspaceInstance()
+r.addVectorToWorkspace("corrlines", values1 as String[])
+r.addVectorToWorkspace("corrcols", values2 as String[])
+r.addMatrixToWorkspace("corrmatrix", matrix)
+r.eval("rownames(corrmatrix) = corrlines")
+r.eval("colnames(corrmatrix) = corrcols")
+
+def resultsDir = new File(Toolbox.getTxmHomePath(), "results")
+resultsDir.mkdirs()
+file = File.createTempFile("txm_corr_pairs_", ".svg", resultsDir)
+
+def title = "${corpus.getMainCorpus()}.${corpus}\n${unit_ursql}"
+if (limit_distance > 1) title += "[${limit_distance}]."
+if (limit_cql != null && !limit_cql.getQueryString().equals("\"\"")) title += "\n(${limit_cql} limits)"
+title += "\t P1=$unit_prop1 P2=unit_prop2"
+
+def plotScript = """
+
+r1 = cor(corrmatrix, use="complete.obs", method="$corr_method");
+r2 = cov(corrmatrix, use="complete.obs") ;
+
+corrplot(r1, type="$corr_layout", order="$corr_order", method="$corr_style")
+"""
+
+
+// execute R script
+if (!output_lexicaltable) {
+	try {
+		r.eval("library(corrplot)")
+		try {
+			r.plot(file, plotScript)
+		} catch (Exception e) {
+			println "** Error: "+e
+		}
+	} catch (Exception e) {
+		println "** The 'corrplot' R package is not installed. Start R ("+RWorkspace.getExecutablePath()+") and run 'install.packages(\"corrplot\");'."
+	}
+}
+title = "$unit_prop1 $corr_method correlations"
+
+
+def lt = null;
+if (output_lexicaltable) {
+	mFactory = DoubleFactory2D.dense
+	dmatrix = mFactory.make(values1.size(), values2.size())
+	for (int ii = 0 ; ii < values1.size() ; ii++) {
+		for (int jj = 0 ; jj < values2.size() ; jj++) {
+			dmatrix.set(ii, jj, matrix[ii][jj])
+		}
+	}
+	if (corpusViewSelection instanceof Partition) {
+		lt = new LexicalTableImpl(dmatrix, corpusViewSelection, corpusViewSelection.getCorpus().getProperty("word"),
+				values1 as String[], values2 as String[])
+		lt.setCorpus(corpusViewSelection.getCorpus());
+		corpusViewSelection.storeResult(lt)
+	} else {
+		lt = new LexicalTableImpl(dmatrix, corpus.getProperty("word"),
+				values1 as String[], values2 as String[])
+		lt.setCorpus(corpus);
+		corpus.storeResult(lt)
+	}
+}
+
+monitor.syncExec(new Runnable() {
+			@Override
+			public void run() { try {
+
+					if (output_lexicaltable) {
+						CorporaView.refreshObject(corpus)
+						CorporaView.expand(lt)
+					} else {
+						OpenBrowser.openfile(file.getAbsolutePath(), "Correlations Units")
+					}
+				} catch (e) { e.printStackTrace() }}
+		})
+
+return correlations
\ No newline at end of file
Index: TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/SchemaTypesMacro.groovy
===================================================================
--- TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/SchemaTypesMacro.groovy	(revision 0)
+++ TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/SchemaTypesMacro.groovy	(revision 3288)
@@ -0,0 +1,28 @@
+// Copyright © 2016 ENS de Lyon, CNRS, University of Franche-Comté
+// Licensed under the terms of the GNU General Public License (http://www.gnu.org/licenses)
+// @author mdecorde
+// @author sheiden
+// STANDARD DECLARATIONS
+package org.txm.macroprototypes.urs.misc
+
+import org.kohsuke.args4j.*
+import groovy.transform.Field
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import org.txm.searchengine.cqp.corpus.*
+
+if (!(corpusViewSelection instanceof MainCorpus)) {
+	println "Corpora selection is not a Corpus"
+	return;
+}
+
+MainCorpus corpus = corpusViewSelection
+def analecCorpus = URSCorpora.getCorpus(corpus);
+
+def schemas = analecCorpus.getTousSchemas()
+def set = new HashMap()
+for (def s : schemas.collect { it.getType() }) {
+	if (!set.containsKey(s)) set[s] = 0;
+	set[s] = set[s] +1
+}
+println "Schemas types: "+set.sort() { it -> set[it]}
\ No newline at end of file
Index: TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/ChercherRemplacer.txt
===================================================================
--- TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/ChercherRemplacer.txt	(revision 0)
+++ TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/ChercherRemplacer.txt	(revision 3288)
@@ -0,0 +1,13 @@
+Macro ChercherRemplacer
+Auteur : Matthieu QUIGNARD
+Version : 05 Février 2019
+
+Retouche la valeur d'une propriété pour la remplacer par une autre.
+Par exemple : CATEGORIE=PRO.CHECK => CATEGORIE=ERREUR
+
+Possibilité d'inclure aussi les mentions dont la valeur initiale est vide.
+Par exemple : CATEGORIE=          => CATEGORIE=ERREUR
+
+NB : on peut utiliser cette macro pour retoucher le nom des référents.
+Exemple : REF=roi de france       => REF=Le Roi de France
+

Property changes on: TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/ChercherRemplacer.txt
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/ChercherSupprimerMacro.groovy
===================================================================
--- TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/ChercherSupprimerMacro.groovy	(revision 0)
+++ TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/ChercherSupprimerMacro.groovy	(revision 3288)
@@ -0,0 +1,97 @@
+// ChercherSupprimer
+// Auteur Matthieu Quignard
+// Date : 14 janvier 2019
+
+/**********
+Sert à supprimer des mentions qui une valeur particulière attribuée
+Par exemple : CATEGORIE=ERREUR
+ou bien : REF=NON_REF
+ou encore : CHECK=
+
+ATTENTION : CETTE MACRO N'EST PAS REVERSIBLE
+***********/
+
+package org.txm.macroprototypes.urs.misc
+
+import org.apache.commons.lang.*
+import org.kohsuke.args4j.*
+import groovy.transform.*
+import org.txm.*
+import org.txm.rcpapplication.swt.widget.parameters.*
+import org.txm.analec.*
+import org.txm.searchengine.cqp.*
+import org.txm.searchengine.cqp.corpus.*
+import visuAnalec.Message.*
+import visuAnalec.donnees.*
+import visuAnalec.elements.*
+import visuAnalec.vue.*
+
+// CORPS DU SCRIPT
+
+if (!(corpusViewSelection instanceof MainCorpus)) {
+	println "Corpora selection is not a Corpus"
+	return
+}
+
+// BEGINNING OF PARAMETERS
+@Field @Option(name="unit_type", usage="Unité", widget="String", required=true, def="MENTION")
+def unit_type
+@Field @Option(name="prop_name", usage="Propriété", widget="String", required=true, def="CATEGORIE")
+def prop_name
+@Field @Option(name="val_cherche", usage="Valeur recherchée", widget="String", required=true, def="")
+def val_cherche
+@Field @Option(name="inclureVides", usage="Inclure les valeurs vides", widget="Boolean", required=true, def="true")
+def inclureVides
+
+if (!ParametersDialog.open(this)) return
+
+corpus = corpusViewSelection
+analecCorpus = AnalecCorpora.getCorpus(corpus.getName())
+vue = AnalecCorpora.getVue(corpus.getName())
+structure = analecCorpus.getStructure()
+
+if (!structure.getUnites().contains(unit_type)) { // check if the structure contains the unit_type units
+	println "Erreur : le corpus ne contient d'unité de type $unit_type"
+	println "Script terminé"
+	return
+}
+
+if (!structure.getUniteProperties(unit_type).contains(prop_name)) { 
+	println "Erreur : les unités $unit_type n'ont pas de propriété $prop_name"
+	println "Script terminé"
+	return
+}
+
+println "Option 'inclure les valeurs vides' : $inclureVides"
+
+def nDeleted = 0
+def nIgnored = 0
+
+def units = analecCorpus.getUnites(unit_type)
+units.sort() { a, b -> a.getDeb() <=> b.getDeb() ?: a.getFin() <=> b.getFin() }
+
+def garbageBin = []
+
+for (Unite unit : units) { // process all units
+    def val = unit.getProp( prop_name )
+    
+    if ( (val == val_cherche) || ( inclureVides && (val == "")) ) {
+    	garbageBin.add( unit )
+    	nDeleted++
+    } else {
+    	nIgnored++
+    }
+}
+
+// Suppression effective des unités ciblées
+garbageBin.each {
+   analecCorpus.supUnite( it )
+}
+
+if (nDeleted > 0) corpus.setIsModified(true);
+
+println "Result:"
+println "- $nDeleted units of type $unit_type have been deleted."
+println "- $nIgnored units of type $unit_type have not been modified."
+
+AnalecCorpora.getVue(analecCorpus).retablirVueParDefaut()
Index: TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/CompUnitPropertiesMacro.groovy
===================================================================
--- TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/CompUnitPropertiesMacro.groovy	(revision 0)
+++ TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/CompUnitPropertiesMacro.groovy	(revision 3288)
@@ -0,0 +1,66 @@
+// Copyright © 2016 ENS de Lyon, CNRS, University of Franche-Comté
+// Licensed under the terms of the GNU General Public License (http://www.gnu.org/licenses)
+// @author mdecorde
+// @author sheiden
+// STANDARD DECLARATIONS
+package org.txm.macroprototypes.urs.misc
+
+import org.apache.commons.lang.StringUtils;
+import org.kohsuke.args4j.*
+import groovy.transform.Field
+import org.txm.Toolbox;
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import org.txm.searchengine.cqp.AbstractCqiClient;
+import org.txm.searchengine.cqp.corpus.*
+import org.txm.searchengine.cqp.CQPSearchEngine
+import visuAnalec.donnees.Structure;
+import visuAnalec.elements.Unite;
+
+if (!(corpusViewSelection instanceof MainCorpus)) {
+	println "Corpora selection is not a Corpus"
+	return;
+}
+
+// BEGINNING OF PARAMETERS
+@Field @Option(name="unit_type",usage="", widget="String", required=true, def="MENTION")
+String unit_type
+
+@Field @Option(name="print_diff",usage="", widget="Boolean", required=true, def="true")
+boolean print_diff
+
+@Field @Option(name="unit_property_name1", usage="", widget="String", required=false, def="CATEGORIE")
+String unit_property_name1
+
+@Field @Option(name="unit_property_name2", usage="", widget="String", required=false, def="CATEGORIE_ORIG")
+String unit_property_name2
+
+if (!ParametersDialog.open(this)) return;
+
+int n = 1;
+int nDiff = 0;
+MainCorpus corpus = corpusViewSelection
+AbstractCqiClient CQI = CQPSearchEngine.getCqiClient();
+def word = corpus.getWordProperty()
+def analecCorpus = URSCorpora.getCorpus(corpus);
+
+def units = analecCorpus.getUnites(unit_type)
+units.sort() { a, b -> a.getDeb() <=> b.getDeb() ?: a.getFin() <=> b.getFin() }
+for (Unite unit : units) {
+	int[] pos = null
+	if (unit.getDeb() == unit.getFin()) pos = [unit.getDeb()]
+	else pos = (unit.getDeb()..unit.getFin())
+	def form = StringUtils.join(CQI.cpos2Str(word.getQualifiedName(), pos), " ")
+	def props = unit.getProps()
+	def v1 = props.get(unit_property_name1);
+	def v2 = props.get(unit_property_name2);
+	
+	if (v1 != v2) {
+		if (print_diff) println "$n - ${unit.getDeb()} -> ${unit.getFin()} - $props : $form"
+		nDiff++
+	}
+	n++
+}
+
+if (nDiff == 0) println "$unit_property_name1 and $unit_property_name2 have the same values."
+else println "$unit_property_name1 and $unit_property_name2 have $nDiff/$n different values."
\ No newline at end of file
Index: TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/RelationsListMacro.groovy
===================================================================
--- TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/RelationsListMacro.groovy	(revision 0)
+++ TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/RelationsListMacro.groovy	(revision 3288)
@@ -0,0 +1,71 @@
+// Copyright © 2016 ENS de Lyon, CNRS, University of Franche-Comté
+// Licensed under the terms of the GNU General Public License (http://www.gnu.org/licenses)
+// @author mdecorde
+// @author sheiden
+// STANDARD DECLARATIONS
+package org.txm.macroprototypes.urs.misc
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.tools.ant.types.resources.selectors.InstanceOf;
+import org.kohsuke.args4j.*
+
+import groovy.transform.Field
+
+import org.txm.Toolbox;
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import org.txm.searchengine.cqp.AbstractCqiClient;
+import org.txm.searchengine.cqp.corpus.*
+import org.txm.searchengine.cqp.CQPSearchEngine
+
+import visuAnalec.donnees.Structure;
+import visuAnalec.elements.Relation
+import visuAnalec.elements.Unite;
+
+if (!(corpusViewSelection instanceof MainCorpus)) {
+	println "Corpora selection is not a Corpus"
+	return;
+}
+
+// BEGINNING OF PARAMETERS
+@Field @Option(name="relation_type",usage="", widget="String", required=true, def="ANAPHORE")
+String relation_type
+
+if (!ParametersDialog.open(this)) return;
+
+MainCorpus corpus = corpusViewSelection
+AbstractCqiClient CQI = CQPSearchEngine.getCqiClient();
+def word = corpus.getWordProperty()
+visuAnalec.donnees.Corpus analecCorpus = URSCorpora.getCorpus(corpus);
+
+int n = 1;
+def relations = null
+if (relation_type.length() > 0) {
+	relations = []
+	for (String type : analecCorpus.getStructure().getTypes(Relation.class))
+		relations.addAll(analecCorpus.getRelations(type))
+} else {
+	relations = analecCorpus.getToutesRelations()
+}
+
+for (Relation relation : relations) {
+	def unit1 = relation.getElt1();
+	def unit2 = relation.getElt2();
+	def props = relation.getProps()
+	if (unit1 instanceof Unite && unit2 instanceof Unite) {
+		int[] pos1 = null
+		if (unit1.getDeb() == unit1.getFin()) pos1 = [unit1.getDeb()]
+		else pos1 = (unit1.getDeb()..unit1.getFin())
+		def form1 = StringUtils.join(CQI.cpos2Str(word.getQualifiedName(), pos1), " ")
+		
+		int[] pos2 = null
+		if (unit2.getDeb() == unit2.getFin()) pos2 = [unit2.getDeb()]
+		else pos2 = (unit2.getDeb()..unit2.getFin())
+		def form2 = StringUtils.join(CQI.cpos2Str(word.getQualifiedName(), pos2), " ")
+		
+		println "$n - $props : $form1 -> $form2"
+	} else {
+		println "$n - $props"
+	}
+	n++
+}
\ No newline at end of file
Index: TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/UnitTypesInSchemaMacro.groovy
===================================================================
--- TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/UnitTypesInSchemaMacro.groovy	(revision 0)
+++ TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/UnitTypesInSchemaMacro.groovy	(revision 3288)
@@ -0,0 +1,48 @@
+// Copyright © 2016 ENS de Lyon, CNRS, University of Franche-Comté
+// Licensed under the terms of the GNU General Public License (http://www.gnu.org/licenses)
+// @author mdecorde
+// @author sheiden
+// STANDARD DECLARATIONS
+package org.txm.macroprototypes.urs.misc
+
+import org.kohsuke.args4j.*
+import groovy.transform.Field
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import org.txm.searchengine.cqp.corpus.*
+
+if (!(corpusViewSelection instanceof MainCorpus)) {
+	println "Corpora selection is not a Corpus"
+	return;
+}
+
+// BEGINNING OF PARAMETERS
+@Field @Option(name="schema_type",usage="", widget="String", required=true, def="CHAINE")
+String schema_type
+
+if (!ParametersDialog.open(this)) return;
+
+MainCorpus corpus = corpusViewSelection
+def analecCorpus = URSCorpora.getCorpus(corpus);
+def map = new HashMap()
+def unitesInSchema = []
+def n = 0
+for (def schema : analecCorpus.getSchemas(schema_type)) {
+	def unites = schema.getUnitesSousjacentes()
+	unitesInSchema.addAll(unites)
+	n += unites.size()
+}
+
+def counts = unitesInSchema.countBy() { it };
+for (def c : counts.keySet()) {
+	if (counts[c] > 1) println "ERROR UNIT IN MULTIPLE SCHEMA["+c.getDeb()+", "+c.getFin()+"]="+c.getProps()+" in "+c.getSchemas().collect() {it.getProps()}
+}
+
+def set = new HashSet()
+set.addAll(unitesInSchema)
+for (def s : set.collect { it.getType() }) {
+	if (!map.containsKey(s)) map[s] = 0;
+	map[s] = map[s] +1
+}
+
+println "Unites types: "+map.sort() { it -> map[it]}
\ No newline at end of file
Index: TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/UnitTypesNotInSchemaMacro.groovy
===================================================================
--- TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/UnitTypesNotInSchemaMacro.groovy	(revision 0)
+++ TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/UnitTypesNotInSchemaMacro.groovy	(revision 3288)
@@ -0,0 +1,42 @@
+// Copyright © 2016 ENS de Lyon, CNRS, University of Franche-Comté
+// Licensed under the terms of the GNU General Public License (http://www.gnu.org/licenses)
+// @author mdecorde
+// @author sheiden
+// STANDARD DECLARATIONS
+package org.txm.macroprototypes.urs.misc
+
+import org.kohsuke.args4j.*
+import groovy.transform.Field
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import org.txm.searchengine.cqp.corpus.*
+
+if (!(corpusViewSelection instanceof MainCorpus)) {
+	println "Corpora selection is not a Corpus"
+	return;
+}
+
+// BEGINNING OF PARAMETERS
+@Field @Option(name="schema_type",usage="", widget="String", required=true, def="CHAINE")
+String schema_type
+if (!ParametersDialog.open(this)) return;
+
+MainCorpus corpus = corpusViewSelection
+def analecCorpus = URSCorpora.getCorpus(corpus);
+
+def unitesInSchema = new HashSet()
+for (def schema : analecCorpus.getSchemas(schema_type)) {
+	unitesInSchema.addAll(schema.getUnitesSousjacentes())
+}
+println "unites: "+analecCorpus.getToutesUnites().size()
+println "unites in schema: "+unitesInSchema.size()
+
+def set = new HashMap()
+for (def u : analecCorpus.getToutesUnites()) {
+	if (unitesInSchema.contains(u)) continue;
+	
+	if (!set.containsKey(u.getType())) set[u.getType()] = 0;
+	set[u.getType()] = set[u.getType()] +1
+}
+
+println "unites not in schema: "+set.sort() { it -> set[it]}
\ No newline at end of file
Index: TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/UnitsProgressionMacro.groovy
===================================================================
--- TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/UnitsProgressionMacro.groovy	(revision 0)
+++ TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/UnitsProgressionMacro.groovy	(revision 3288)
@@ -0,0 +1,178 @@
+// Copyright © 2016 ENS de Lyon, CNRS, University of Franche-Comté
+// Licensed under the terms of the GNU General Public License (http://www.gnu.org/licenses)
+// @author mdecorde
+// @author sheiden
+// STANDARD DECLARATIONS
+package org.txm.macroprototypes.urs.misc
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.lang.StringUtils
+import org.jfree.chart.JFreeChart
+import org.jfree.chart.plot.XYPlot
+import org.kohsuke.args4j.*
+
+import groovy.transform.Field
+
+import org.txm.Toolbox
+import org.txm.progression.core.chartsengine.jfreechart.themes.highcharts.renderers.ProgressionItemSelectionRenderer
+import org.txm.progression.core.functions.Progression
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import org.txm.chartsengine.rcp.editors.ChartEditor
+import org.txm.macro.urs.AnalecUtils
+import org.txm.searchengine.cqp.AbstractCqiClient
+import org.txm.searchengine.cqp.corpus.*
+import org.txm.searchengine.cqp.corpus.query.Match;
+import org.txm.searchengine.cqp.corpus.query.CQLQuery
+import org.txm.rcp.Application
+import org.txm.rcp.IImageKeys
+
+import visuAnalec.donnees.Structure
+import visuAnalec.elements.*
+
+def scriptName = this.class.getSimpleName()
+def parent
+def selection = []
+if (!(corpusViewSelection instanceof CQPCorpus)) {
+	println "** $scriptName please select a Corpus to run the macro"
+}
+selection << corpusViewSelection
+parent = corpusViewSelection
+
+// BEGINNING OF PARAMETERS
+@Field @Option(name="schema_ursql", usage="TYPE@PROP=VALUE", widget="String", required=false, def="CHAINE")
+		String schema_ursql
+@Field @Option(name="minimum_schema_size", usage="Minimum size needed to consider a schema", widget="Integer", required=true, def="3")
+		int minimum_schema_size
+@Field @Option(name="maximum_schema_size", usage="Maximum size needed to consider a schema", widget="Integer", required=true, def="9999999")
+		int maximum_schema_size
+@Field @Option(name="unit_ursql", usage="TYPE@PROP=VALUE", widget="String", required=false, def="MENTION")
+		String unit_ursql
+@Field @Option(name="limit_distance_in_schema", usage="Unit distance in schema (0 = no selection, 1 = first after limit, -1 = last before limit, etc.)", widget="Integer", required=true, def="0")
+		int limit_distance_in_schema
+@Field @Option(name="limit_cql", usage="CQL to build structure limits", widget="Query", required=true, def="<div> [] expand to div")
+		limit_cql
+@Field @Option(name="strict_inclusion", usage="Units must be strictly included into corpus matches", widget="Boolean", required=true, def="true")
+		boolean strict_inclusion
+@Field @Option(name="limit_distance", usage="Unit distance to structure limit (0 = no selection, 1 = first after limit, -1 = last before limit, etc.)", widget="Integer", required=true, def="0")
+		int limit_distance
+@Field @Option(name="unit_property_display", usage="Unit property to count", widget="String", required=true, def="CATEGORIE")
+		String unit_property_display
+@Field @Option(name="struct_name", usage="Structure to display", widget="String", required=true, def="div")
+		String struct_name
+@Field @Option(name="struct_prop", usage="Structure property to display", widget="String", required=true, def="n")
+		String struct_prop
+@Field @Option(name="line_width", usage="line width", widget="Integer", required=true, def="1")
+		int line_width = 2
+@Field @Option(name="bande_width", usage="bande width", widget="Float", required=true, def="1.0f")
+		float bande_width = 1.0f
+@Field @Option(name="debug", usage="Show internal variable content", widget="StringArray", metaVar="OFF	ON	ALL	REALLY ALL", required=true, def="OFF")
+		debug
+if (!ParametersDialog.open(this)) return
+if (debug == "OFF") debug = 0; else if (debug == "ON") debug = 1; else if (debug == "ALL") debug = 2 else if (debug == "REALLY ALL") debug = 3
+
+
+	def CQI = CQPSearchEngine.getCqiClient()
+
+def queries = []
+def queryResults = []
+def informations = []
+for (def corpus : selection) {
+	
+	mainCorpus = corpus.getMainCorpus()
+
+	def word = mainCorpus.getWordProperty()
+	def analecCorpus = URSCorpora.getCorpus(mainCorpus.getName())
+
+	def selectedUnits = AnalecUtils.selectUnitsInSchema(debug, analecCorpus, corpus, schema_ursql, minimum_schema_size, maximum_schema_size, 
+	unit_ursql, limit_distance_in_schema, limit_cql, strict_inclusion, limit_distance);
+
+	def query = ""
+	if (limit_cql != null && !limit_cql.getQueryString().equals("\"\"")) query += limit_cql
+	if (schema_ursql != null && schema_ursql.length() > 0) { if (query.length() > 0) query += " & "; query += ""+schema_ursql+ " >"}
+	if (unit_ursql != null && unit_ursql.length() > 0) query += " "+unit_ursql
+	query = new CQLQuery(query)
+	int[] starts = new int[selectedUnits.size()];
+	int[] ends = new int[selectedUnits.size()];
+	def unitsinformations = []
+	int n = 0;
+	for (Unite unite : selectedUnits) {
+		starts[n] = unite.getDeb()
+		ends[n] = unite.getFin()
+		unitsinformations << AnalecUtils.toString(CQI, word, unite);
+		n++
+	}
+	def queryResult = new FakeQueryResult(corpus.getID(), corpus, query, starts, ends, null)
+	queries << query
+	queryResults << queryResult
+	informations << unitsinformations
+
+	if (unit_property_display != null && unit_property_display.length() > 0) {
+		def propvalues = [:]
+		for (def unit : selectedUnits) {
+			def v = unit.getProp(unit_property_display)
+			if (v == null) v = "<null>"
+			else if (v.length() == 0) v = "<empty>"
+			
+			if (!propvalues.containsKey(v))propvalues[v] = []
+			propvalues[v] << unit
+		}
+		
+		for (def v : propvalues.keySet().sort()) {
+			selectedUnits = propvalues[v]
+			query = corpus.getID()+" "+limit_cql
+			query = new CQLQuery(v)
+			starts = new int[selectedUnits.size()];
+			ends = new int[selectedUnits.size()];
+			unitsinformations = []
+			n = 0;
+			for (Unite unite : selectedUnits) {
+				starts[n] = unite.getDeb()
+				ends[n] = unite.getFin()
+				unitsinformations << AnalecUtils.toString(CQI, word, unite);
+				n++
+			}
+			queryResult = new FakeQueryResult(corpus.getID(), corpus, query, starts, ends, null)
+			queries << query
+			queryResults << queryResult
+			informations << unitsinformations
+		}
+	}
+}
+
+corpus = parent
+try {
+	def struct = corpus.getStructuralUnit(struct_name)
+	def struct_p = struct.getProperty(struct_prop)
+
+	Progression progression = new Progression(corpus, queries,
+			struct, struct_p,	".*",
+			true, false, false,
+			line_width, false, bande_width)
+
+	progression.stepQueries(queryResults); // new
+
+	if (!progression.stepStructuralUnits() || monitor.isCanceled())	return
+		monitor.worked(20)
+	if (!progression.stepFinalize() || monitor.isCanceled()) return
+		monitor.worked(20)
+
+	monitor.syncExec(new Runnable() {
+				@Override
+				public void run() {
+					try {
+						ChartEditor charteditorpart = SWTChartsComponentProvider.openEditor(Application.swtComponentProvider.createProgressionChartEditorPart(IImageKeys.getImage(IImageKeys.ACTION_PROGRESSION), progression, progression.isMonochrome(), progression.isMonostyle(), progression.isDoCumulative()))
+						JFreeChart chart = charteditorpart.getChart()
+						def plot = chart.getXYPlot()
+						ProgressionItemSelectionRenderer renderer = plot.getRenderer();
+						renderer.setAdditionalLabelInformation(informations)
+					} catch(Exception e) {e.printStackTrace()}
+				}
+			})
+
+} catch(Exception e) {
+	e.printStackTrace()
+	return false
+}
Index: TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/ChercherRemplacerMacro.groovy
===================================================================
--- TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/ChercherRemplacerMacro.groovy	(revision 0)
+++ TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/ChercherRemplacerMacro.groovy	(revision 3288)
@@ -0,0 +1,92 @@
+// ChercherRemplacer
+// Auteur Matthieu Quignard
+// Date : 14 janvier 2019
+
+/**********
+Sert à retoucher une valeur attribuée à une mention et la remplacer par une autre
+Par exemple : CATEGORIE=PRO.CHECK => CATEGORIE=PRO.PER
+ou bien : REF=roi de France => REF=Le Roi de France
+ou encore : REF=      => REF=<EMPTY>
+***********/
+
+package org.txm.macroprototypes.urs.misc
+
+import org.apache.commons.lang.*
+import org.kohsuke.args4j.*
+import groovy.transform.*
+import org.txm.*
+import org.txm.rcpapplication.swt.widget.parameters.*
+import org.txm.analec.*
+import org.txm.searchengine.cqp.*
+import org.txm.searchengine.cqp.corpus.*
+import visuAnalec.Message.*
+import visuAnalec.donnees.*
+import visuAnalec.elements.*
+import visuAnalec.vue.*
+
+// CORPS DU SCRIPT
+
+if (!(corpusViewSelection instanceof MainCorpus)) {
+	println "Corpora selection is not a Corpus"
+	return
+}
+
+// BEGINNING OF PARAMETERS
+@Field @Option(name="unit_type", usage="Unité", widget="String", required=true, def="MENTION")
+def unit_type
+@Field @Option(name="prop_name", usage="Propriété", widget="String", required=true, def="CATEGORIE")
+def prop_name
+@Field @Option(name="val_cherche", usage="Valeur recherchée", widget="String", required=true, def="")
+def val_cherche
+@Field @Option(name="val_remplace", usage="Valeur de remplacement", widget="String", required=true, def="")
+def val_remplace
+@Field @Option(name="inclureVides", usage="Inclure les valeurs vides", widget="Boolean", required=true, def="true")
+def inclureVides
+
+if (!ParametersDialog.open(this)) return
+
+corpus = corpusViewSelection
+analecCorpus = AnalecCorpora.getCorpus(corpus.getName())
+vue = AnalecCorpora.getVue(corpus.getName())
+structure = analecCorpus.getStructure()
+
+if (!structure.getUnites().contains(unit_type)) { // check if the structure contains the unit_type units
+	println "Erreur : le corpus ne contient d'unité de type $unit_type"
+	println "Script terminé"
+	return
+}
+
+if (!structure.getUniteProperties(unit_type).contains(prop_name)) { 
+	println "Erreur : les unités $unit_type n'ont pas de propriété $prop_name"
+	println "Script terminé"
+	return
+}
+
+println "Option 'inclure les valeurs vides' : $inclureVides"
+
+def nModified = 0
+def nIgnored = 0
+
+def units = analecCorpus.getUnites(unit_type)
+units.sort() { a, b -> a.getDeb() <=> b.getDeb() ?: a.getFin() <=> b.getFin() }
+
+for (Unite unit : units) { // process all units
+    def val = unit.getProp( prop_name )
+    
+    if ( (val == val_cherche) || ( inclureVides && (val == "")) ) {
+    	vue.setValeurChamp(unit, prop_name, val_remplace)
+    	nModified++
+    } else {
+    	nIgnored++
+    }
+}
+
+
+
+if (nModified > 0) corpus.setIsModified(true);
+
+println "Result:"
+println "- $nModified units of type $unit_type have been modified."
+println "- $nIgnored units of type $unit_type have not been modified."
+
+AnalecCorpora.getVue(analecCorpus).retablirVueParDefaut()
Index: TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/SchemasListOldMacro.groovy
===================================================================
--- TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/SchemasListOldMacro.groovy	(revision 0)
+++ TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/misc/SchemasListOldMacro.groovy	(revision 3288)
@@ -0,0 +1,181 @@
+// Copyright © 2016 ENS de Lyon, CNRS, University of Franche-Comté
+// Licensed under the terms of the GNU General Public License (http://www.gnu.org/licenses)
+// @author mdecorde
+// @author sheiden
+
+// STANDARD DECLARATIONS
+package org.txm.macroprototypes.urs.misc
+
+import org.kohsuke.args4j.*
+import groovy.transform.Field
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import org.txm.searchengine.cqp.corpus.*
+import org.txm.Toolbox
+import org.txm.rcp.commands.*
+import org.apache.commons.lang.StringUtils
+
+// BEGINNING OF PARAMETERS
+@Field @Option(name="schema_type",usage="", widget="String", required=true, def="CHAIE")
+String schema_type
+
+@Field @Option(name="minimum_schema_size",usage="", widget="Integer", required=true, def="3")
+int minimum_schema_size
+
+@Field @Option(name="schema_property_name",usage="", widget="String", required=false, def="")
+String schema_property_name
+
+@Field @Option(name="schema_property_value",usage="", widget="String", required=false, def=".*")
+String schema_property_value
+
+@Field @Option(name="unit_type",usage="", widget="String", required=false, def="MENTION")
+String unit_type
+
+@Field @Option(name="unit_property_name", usage="", widget="String", required=false, def="")
+String unit_property_name
+
+@Field @Option(name="unit_property_value", usage="", widget="String", required=false, def=".*")
+String unit_property_value
+
+@Field @Option(name="word_property", usage="", widget="StringArray", metaVar="word	lemma	frlemma	frolemma	#forme#	id", required=false, def="word")
+String word_property
+
+@Field @Option(name="separator", usage="", widget="String", required=true, def=", ")
+String separator
+
+@Field @Option(name="buildCQL", usage="générer la requête des unités", widget="Boolean", required=true, def='false')
+def buildCQL
+
+if (!(corpusViewSelection instanceof MainCorpus)) {
+	println "Corpus view selection is not a Corpus"
+	return;
+}
+
+if (!ParametersDialog.open(this)) return;
+// END OF PARAMETERS
+
+MainCorpus corpus = corpusViewSelection
+def analecCorpus = URSCorpora.getCorpus(corpus)
+
+// check Schema parameters
+if (!analecCorpus.getStructure().getSchemas().contains(schema_type)) {
+	println "No schema with name=$schema_type"
+	return;
+} else {
+	if (schema_property_name.length() > 0 && schema_property_value.length() > 0) {
+		// test property existance
+		def props = analecCorpus.getStructure().getSchemaProperties(schema_type);
+		if (!props.contains(schema_property_name)) {
+			println "Schema $schema_type has no property named $schema_property_name"
+			return;
+		}
+	}
+}
+
+// check unit parameters
+if (!analecCorpus.getStructure().getUnites().contains(unit_type)) {
+	println "No unit with name=$unit_type"
+	return;
+} else {
+	if (unit_property_name.length() > 0 && unit_property_value.length() > 0) {
+		// test property existance
+		def props = analecCorpus.getStructure().getUniteProperties(unit_type);
+		if (!props.contains(unit_property_name)) {
+			println "Unit $unit_type has no property named $unit_property_name"
+			return;
+		}
+	}
+}
+
+def CQI = CQPSearchEngine.getCqiClient()
+
+if (buildCQL) {
+	word_prop = corpus.getProperty("id")
+} else {
+	word_prop = corpus.getProperty(word_property)
+}
+
+def schemas = analecCorpus.getSchemas(schema_type)
+schemas.sort() {it.getProps()}
+def nSchemas = 0
+
+def lens = [:]
+for (def schema : schemas) {
+
+	if (schema_property_name.length() > 0 && schema_property_value.length() > 0) {
+		if (!schema.getProp(schema_property_name).matches(schema_property_value)) {
+			// ignoring this schema
+			continue
+		}
+	}
+	
+	def nUnites = 0
+	for (def unit : schema.getUnitesSousjacentes()) {
+		if (unit_type.length() > 0) {
+			if (!unit.getType().equals(unit_type)) {
+				continue
+			}
+		}
+		
+		if (unit_property_name.length() > 0 && unit_property_value.length() > 0) {
+			if (!unit.getProp(unit_property_name).matches(unit_property_value)) {
+				// ignoring this schema
+				continue
+			}
+		}
+
+		nUnites++
+	}
+
+	if (nUnites < minimum_schema_size) continue
+
+	print schema.getProps().toString()+ ": "
+	def first = true
+	for (def unit : schema.getUnitesSousjacentes()) {
+		if (unit_type.length() > 0) {
+			if (!unit.getType().equals(unit_type)) {
+				continue
+			}
+		}
+		
+		if (unit_property_name.length() > 0 && unit_property_value.length() > 0) {
+			if (!unit.getProp(unit_property_name).matches(unit_property_value)) {
+				// ignoring this schema
+				continue
+			}
+		}
+
+		String forme =  null;
+
+		if (buildCQL) {
+			int[] pos = null
+			if (unit.getDeb() == unit.getFin()) pos = [unit.getDeb()]
+			else pos = (unit.getDeb()..unit.getFin())
+			def first2= true
+			q = ""
+			pos.each {
+				if (first2) { first2 = false } else { q = q+" " }
+				int[] pos2 = [it]
+				q = q+"["+word_prop+"=\""+CQI.cpos2Str(word_prop.getQualifiedName(), pos2)[0]+"\"]"
+			}
+			if (first) { first = false } else { print "|" }
+			print "("+q+")"
+		} else {
+			if (word_prop == null) { // word_property is the analec unit property to use
+			forme = unit.getProp(word_property)
+			} else {
+			int[] pos = null
+			if (unit.getDeb() == unit.getFin()) pos = [unit.getDeb()]
+			else pos = (unit.getDeb()..unit.getFin())
+				
+			forme = StringUtils.join(CQI.cpos2Str(word_prop.getQualifiedName(), pos), " ") // ids is enough
+			}
+
+			if (first) { first = false } else { print separator }
+			print forme
+		}
+	}
+	println ""
+
+	nSchemas++
+}
Index: TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/cqp/URSUnits2CQPStructMacro.groovy
===================================================================
--- TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/cqp/URSUnits2CQPStructMacro.groovy	(revision 0)
+++ TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/cqp/URSUnits2CQPStructMacro.groovy	(revision 3288)
@@ -0,0 +1,135 @@
+// STANDARD DECLARATIONS
+package org.txm.macro.urs.prototypes.cqp
+
+import org.kohsuke.args4j.*
+import groovy.transform.Field
+import org.txm.annotation.urs.*
+import org.txm.importer.ValidateXml
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.searchengine.cqp.corpus.*
+import visuAnalec.elements.*
+
+// BEGINNING OF PARAMETERS
+
+// Open the parameters input dialog box
+//if (!ParametersDialog.open(this)) return;
+
+if (!(corpusViewSelection instanceof MainCorpus)) {
+	println "Selection must be a Corpus"
+	return
+}
+
+MainCorpus corpus = corpusViewSelection
+def analecCorpus = URSCorpora.getCorpus(corpus)
+
+def texts = corpus.getCorpusTextIdsList();
+def texts_startlimits = corpus.getTextStartLimits()
+def texts_endlimits = corpus.getTextEndLimits()
+
+for (int i = 0 ; i < texts.size() ; i++) {
+
+	println "Processing annotations of "+texts[i]+"..."
+
+	def text_id = texts[i]
+	def text_start = texts_startlimits[i]
+	def text_end = texts_endlimits[i]
+
+	File xmltxmFile = new File(corpus.getProject().getProjectDirectory(), "txm/"+corpus.getID()+"/"+text_id+".xml")
+	File xmltxmFileCopy = new File(corpus.getProject().getProjectDirectory(), text_id+"_copy.xml")
+
+	if (!xmltxmFile.exists()) {
+		println "Warning: no text file found: "+xmltxmFile
+		continue
+	}
+
+	// WRITE MILESTONES UNITS
+
+	println "-> MILESTONES UNITS"
+
+	def units = []
+	for (String unit_type : analecCorpus.getStructure().getTypes(Unite.class)) {
+		def corpus_units = []
+		ArrayList<Unite> all_units = analecCorpus.getUnites(unit_type)
+		corpus_units = all_units.findAll() {
+			it.getProp("type") != null && it.getProp("type").trim().length() > 0 && "yes".equals(it.getProp("milestone")) && text_start <= it.getDeb() && it.getFin() < text_end && !("true".equals(it.getProp("written")))
+		}
+		units.addAll(corpus_units)
+	}
+
+	if (units.size()== 0) {
+		println "No milestones to write"
+	} else {
+		try {
+			println "processing milestones Units ${text_id} and its units "+units.size()
+			MileStoneInserter inserter = new MileStoneInserter(corpus, xmltxmFile, units);
+			if (inserter.process(xmltxmFileCopy) && ValidateXml.test(xmltxmFileCopy)) {
+				xmltxmFile.delete()
+				xmltxmFileCopy.renameTo(xmltxmFile)
+
+				for (Unite unit : units) {
+					unit.getProps()["written"] = "true"
+				}
+				URSCorpora.saveCorpus(corpus);
+				println "Done, "+units.size()+ " milestones written"
+
+			} else {
+				println "Error while processing milestones $xmltxmFile file"
+				File error = new File(corpus.getProject().getProjectDirectory(), "error/"+xmltxmFile.getName())
+				error.getParentFile().mkdirs()
+				println "	moving created file to $error"
+				error.delete()
+				xmltxmFileCopy.renameTo(error)
+			}
+		} catch(Exception e) {
+			println "Error while processing milestones $xmltxmFile file: "+e
+			File error = new File(corpus.getProject().getProjectDirectory(), "error/"+xmltxmFile.getName())
+			error.getParentFile().mkdirs()
+			println "	moving created file to $error"
+			error.delete()
+			xmltxmFileCopy.renameTo(error)
+		}
+	}
+	// WRITE NON MILESTONES UNITS
+	println "-> OTHER UNITS"
+
+	for (String unit_type : analecCorpus.getStructure().getTypes(Unite.class)) {
+		
+		def corpus_units = []
+		ArrayList<Unite> all_units = analecCorpus.getUnites(unit_type)
+		corpus_units = all_units.findAll() {
+			it.getProp("type") != null && it.getProp("type").trim().length() > 0 && !"no".equals(it.getProp("milestone")) && text_start <= it.getDeb() && it.getFin() < text_end && !("true".equals(it.getProp("written")))
+		}
+
+		if (corpus_units.size() == 0) continue;
+		
+		println "processing Units ${text_id} and its $unit_type units "+corpus_units.size()
+		UnitsInserter inserter2 = new UnitsInserter(corpus, xmltxmFile, corpus_units, unit_type);
+		try {
+			if (inserter2.process(xmltxmFileCopy) && ValidateXml.test(xmltxmFileCopy)) {
+				xmltxmFile.delete()
+				xmltxmFileCopy.renameTo(xmltxmFile)
+
+				for (Unite unit : corpus_units) {
+					unit.getProps()["written"] = "true"
+				}
+				URSCorpora.saveCorpus(corpus);
+				println "Done, "+corpus_units.size()+ " units written"
+
+			} else {
+				println "Error while processing milestones $xmltxmFile file"
+				File error = new File(corpus.getProject().getProjectDirectory(), "error/"+xmltxmFile.getName())
+				error.getParentFile().mkdirs()
+				println "	moving created file to $error"
+				error.delete()
+				xmltxmFileCopy.renameTo(error)
+			}
+		} catch(Exception e) {
+			println "Error while processing milestones $xmltxmFile file: "+e
+			File error = new File(corpus.getProject().getProjectDirectory(), "error/"+xmltxmFile.getName())
+			error.getParentFile().mkdirs()
+			println "	moving created file to $error"
+			error.delete()
+			xmltxmFileCopy.renameTo(error)
+		}
+	}
+}
Index: TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/cqp/WordUnitsInserter.groovy
===================================================================
--- TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/cqp/WordUnitsInserter.groovy	(revision 0)
+++ TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/cqp/WordUnitsInserter.groovy	(revision 3288)
@@ -0,0 +1,167 @@
+package org.txm.macro.urs.prototypes.cqp
+
+import java.io.IOException
+import java.util.Date
+import java.util.LinkedHashMap
+
+import javax.xml.stream.XMLStreamException
+
+import org.txm.Toolbox
+import org.txm.importer.StaxIdentityParser
+import org.txm.macro.urs.AnalecUtils
+import org.txm.scripts.importer.GetAttributeValue
+import org.txm.searchengine.cqp.CQPSearchEngine
+import org.txm.searchengine.cqp.corpus.MainCorpus
+import visuAnalec.elements.Unite
+
+public class WordUnitsInserter extends StaxIdentityParser {
+
+	List<Unite> units
+	String[] ids
+	File inputFile
+	def id2Units = [:]
+	def unit_properties // "*" or list (String)
+	def unit_word // ALL START END
+	LinkedHashMap<String, String> anaValues = new LinkedHashMap<String, String>();
+
+	public WordUnitsInserter(MainCorpus corpus, File inputFile, List<Unite> units, String unit_properties, String unit_word) {
+		super(inputFile)
+		this.inputFile = inputFile
+		
+		this.unit_properties = unit_properties
+		this.unit_word = unit_word
+		if (!("*".equals(unit_properties))) {
+			this.unit_properties = this.unit_properties.split(",")
+		}
+
+		this.units = units
+		this.units.sort() { a, b -> a.getDeb() <=> b.getDeb() ?: a.getFin() <=> b.getFin() }
+
+		for (int i = 0 ; i < units.size() ; i++) {
+			Unite u = units[i]
+			int[] positions = null;
+			if ("START".equals(unit_word)) {
+				positions = [u.getDeb()] as int[]
+			} else if ("END".equals(unit_word)) {
+				positions = [u.getFin()] as int[]
+			} else {
+				positions = u.getDeb()..u.getFin()
+			}
+
+			ids = CQPSearchEngine.getCqiClient().cpos2Str(corpus.getProperty("id").getQualifiedName(), positions)
+
+			for (String id : ids) {
+				if (!id2Units.containsKey(id)) {
+					id2Units[id] = []
+				}
+				id2Units[id] << u
+			}
+		}
+	}
+
+	boolean inAna = false
+	String ana_type, ana_resp, ana_value
+	boolean inW = false
+	String word_id = null
+
+	protected void processStartElement() throws XMLStreamException, IOException {
+
+		if ("w".equals(localname)) {
+			
+			inW = true
+			word_id = this.getParserAttributeValue("id")
+
+			if (id2Units.containsKey(word_id)) {
+				for (Unite u : id2Units[word_id]) {
+					def props = u.getProps()
+					
+					def propNames = props.keySet();
+					if (!("*".equals(unit_properties))) {
+						propNames = unit_properties
+					}				
+					
+					for (String p : propNames) {
+						if ("type".equals(p)) continue;
+						if ("written".equals(p)) continue;
+						if ("milestone".equals(p)) continue;
+						
+						if (!anaValues.containsKey(p)) {
+							anaValues[p] = ""
+							ana_resp = "#txm"
+						}
+						anaValues[p] = (anaValues[p]+" "+props.get(p)).trim()
+					}
+				}
+				if (anaValues.size() > 0) println anaValues
+			}
+
+			super.processStartElement(); // write the tag
+			
+		} else if ("ana".equals(localname) && inW) {
+			
+			inAna = true
+			ana_type = this.getParserAttributeValue("type").substring(1)
+			ana_resp = this.getParserAttributeValue("resp")
+			ana_value = ""
+			
+		} else {
+			super.processStartElement()
+		}
+	}
+
+	@Override
+	public void processCharacters() throws XMLStreamException {
+		if (inAna) {
+			ana_value += parser.getText().trim()
+		} else {
+			super.processCharacters()
+		}
+	}
+
+	protected void processEndElement() throws XMLStreamException {
+
+		if ("w".equals(localname)) {
+			
+			// write the last values
+			for (String ana_type : anaValues.keySet()) {
+				writer.writeStartElement("txm:ana")
+				writer.writeAttribute("type", "#" + ana_type)
+				writer.writeAttribute("resp", "#txm") // change
+				writer.writeCharacters(anaValues[ana_type])
+				writer.writeEndElement()
+			}
+			
+			anaValues.clear()
+			super.processEndElement() // finally write word then close annotations
+			inW = false
+			
+		} else if ("ana".equals(localname) && inW) {
+
+			if (!anaValues.containsKey(ana_type)) {
+				anaValues[ana_type] = ana_value.trim()
+			} else {
+				ana_resp = "#txm" // set the resp to txm since anaValues update the ana value
+				anaValues[ana_type] = (anaValues[ana_type]+" "+ana_value.trim()).trim()
+			}
+
+			String value = anaValues[ana_type]
+
+			writer.writeStartElement("txm:ana")
+			writer.writeAttribute("type", "#" + ana_type)
+			writer.writeAttribute("resp", ana_resp) // change
+			writer.writeCharacters(value)
+			writer.writeEndElement()
+			
+			anaValues.remove(ana_type)
+			
+			inAna = false
+			ana_type = null
+			ana_resp = null
+			ana_value = null
+
+			// write ana later
+		} else {
+			super.processEndElement()
+		}
+	}
+}
\ No newline at end of file
Index: TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/cqp/MileStoneInserter.groovy
===================================================================
--- TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/cqp/MileStoneInserter.groovy	(revision 0)
+++ TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/cqp/MileStoneInserter.groovy	(revision 3288)
@@ -0,0 +1,94 @@
+package org.txm.macro.urs.prototypes.cqp
+
+import java.io.IOException
+
+import javax.xml.stream.XMLStreamException
+
+import org.txm.importer.StaxIdentityParser
+import org.txm.macro.urs.AnalecUtils
+import org.txm.searchengine.cqp.CQPSearchEngine
+import org.txm.searchengine.cqp.corpus.MainCorpus
+import visuAnalec.elements.Unite
+
+public class MileStoneInserter extends StaxIdentityParser {
+	
+	List<Unite> units
+	String[] ids
+	File inputFile
+	def id2Units = [:]
+	
+	public MileStoneInserter(MainCorpus corpus, File inputFile, List<Unite> units) {
+		super(inputFile);
+		this.inputFile = inputFile;
+		
+		this.units = units;
+		this.units.sort() { a, b -> a.getDeb() <=> b.getDeb() ?: a.getFin() <=> b.getFin() }
+		
+		int[] positions = new int[units.size()];
+		for( int i = 0 ; i < units.size() ; i++) {
+			positions[i] = units.get(i).getDeb();
+		}
+		
+		ids = CQPSearchEngine.getCqiClient().cpos2Str(corpus.getProperty("id").getQualifiedName(), positions);
+		
+		for (int i = 0 ; i < ids.length ; i++) {
+			String id = ids[i]
+			if (id != null) {
+				if (!id2Units.containsKey(id)) id2Units[id] = []
+				
+				id2Units[id] << units[i]
+			}
+		}
+	}
+	
+	boolean start = false;
+	String word_id = null;
+	@Override
+	protected void processStartElement() throws XMLStreamException, IOException {
+		
+		if ("text".equals(localname)) {
+			start = true;
+		} else if ("w".equals(localname) && start) {
+			word_id = getParserAttributeValue("id");
+			if (word_id == null) {
+				println "Warning: found <w> without id at line "+parser.getLocation().getLineNumber()+" in "+inputFile
+			} else {
+				writeAllUnits(word_id, "before")
+			}
+		}
+		
+		super.processStartElement();
+	}
+	
+	protected void writeAllUnits(String id, String position) {
+		
+		def units = id2Units[id]
+		if (units == null) return; // no units to write
+		
+		for (Unite currentUnit : units) {
+			
+			if (!position.equals(currentUnit.getProp("position"))) return;
+				
+			writer.writeStartElement(currentUnit.getProp("type"));
+			HashMap props = currentUnit.getProps();
+			for (String p : props.keySet()) {
+				if (p.equals("type")) continue; // ignore the type since written in tag name
+				writer.writeAttribute(p, ""+props.get(p));
+			}
+			writer.writeEndElement();
+		}
+	}
+	
+	@Override
+	protected void processEndElement() throws XMLStreamException {
+		super.processEndElement();
+	
+		if ("w".equals(localname) && start && word_id != null) {
+			writeAllUnits(word_id, "after")
+		}
+		
+		if ("w".equals(localname)) {
+			word_id = null;
+		}
+	}
+}
\ No newline at end of file
Index: TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/cqp/UnitsInserter.groovy
===================================================================
--- TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/cqp/UnitsInserter.groovy	(revision 0)
+++ TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/cqp/UnitsInserter.groovy	(revision 3288)
@@ -0,0 +1,170 @@
+package org.txm.macro.urs.prototypes.cqp
+
+import java.io.IOException
+
+import javax.xml.stream.XMLStreamException
+
+import org.txm.importer.StaxIdentityParser
+import org.txm.macro.urs.AnalecUtils
+import org.txm.searchengine.cqp.CQPSearchEngine
+import org.txm.searchengine.cqp.corpus.MainCorpus
+import visuAnalec.elements.Unite
+
+public class UnitsInserter extends StaxIdentityParser {
+
+	List<Unite> units
+	String[] ids
+	File inputFile
+	def open_id2Units = [:]
+	def close_id2Units = [:]
+	def writing_units = []
+	def writing_stacks = []
+	
+	def stack = "";
+
+	def writing_start, writing_end;
+	
+	def positions2id = [:] // used to relocate end of units
+
+	public UnitsInserter(MainCorpus corpus, File inputFile, List<Unite> units, String type) {
+		super(inputFile);
+		this.inputFile = inputFile;
+		this.units = units;
+		
+		this.units.sort() { a, b -> a.getDeb() <=> b.getDeb() ?: b.getFin() <=> a.getFin() }
+
+		// get words id limits
+		int[] positions = new int[units.size()];
+		for( int i = 0 ; i < units.size() ; i++) {
+			positions[i] = units.get(i).getDeb();
+		}
+		ids = CQPSearchEngine.getCqiClient().cpos2Str(corpus.getProperty("id").getQualifiedName(), positions);
+		for (int i = 0 ; i < ids.length ; i++) {
+			String id = ids[i]
+			
+			if (id != null) {
+				positions2id[positions[i]] = id
+				if (!open_id2Units.containsKey(id)) open_id2Units[id] = []
+				open_id2Units[id] << units[i]
+			}
+		}
+
+		positions = new int[units.size()];
+		for( int i = 0 ; i < units.size() ; i++) {
+			positions[i] = units.get(i).getFin();
+		}
+		ids = CQPSearchEngine.getCqiClient().cpos2Str(corpus.getProperty("id").getQualifiedName(), positions);
+		for (int i = 0 ; i < ids.length ; i++) {
+			String id = ids[i]
+			if (id != null) {
+				positions2id[positions[i]] = id
+				if (!close_id2Units.containsKey(id)) close_id2Units[id] = new HashSet<Unite>()
+				close_id2Units[id] << units[i]
+			}
+		}
+	}
+
+	boolean start = false;
+	String word_id = null;
+	@Override
+	protected void processStartElement() throws XMLStreamException, IOException {
+
+		stack += "/"+localname
+
+		if ("text".equals(localname)) {
+			start = true;
+		} else if ("w".equals(localname) && start) {
+			word_id = getParserAttributeValue("id");
+			if (word_id == null) {
+				println "Warning: found <w> without id at line "+parser.getLocation().getLineNumber()+" in "+inputFile
+			} else {
+				writeOpenUnits()
+			}
+		}
+
+		super.processStartElement();
+	}
+
+	protected void writeOpenUnits() {
+		
+		def toWrite = open_id2Units[word_id]
+		
+		if (toWrite != null) {
+			for (Unite unite : toWrite) {
+				
+				for (int i = 0 ; i < writing_units.size() ; i++) {
+					Unite u = writing_units.get(i);
+					if (unite.getFin() > u.getFin()) {
+						// add unite to close_id2Units
+						String id = positions2id[u.getFin()]
+						close_id2Units[id] << unite // close the unite at the same moment
+					}
+				}
+				
+				writeUnit(unite);
+			}
+		}
+	}
+
+	protected void writeCloseUnits() {
+		if (word_id != null) {
+			def toClose = close_id2Units[word_id]
+			if (toClose != null) {
+				for (int i = 0 ; i < writing_units.size() ; i++) {
+					Unite u = writing_units.get(i);
+					if (toClose.contains(u)) {
+						writing_stacks.remove(i)
+						writing_units.remove(i)
+						writer.writeEndElement();
+						i--;
+					}
+				}
+			}
+		} else {
+			for (int i = 0 ; i < writing_stacks.size() ; i++) {
+				if (writing_stacks[i].equals(stack)) {
+					writing_stacks.remove(i)
+					writing_units.remove(i)
+					writer.writeEndElement();
+					i--
+				}
+			}
+		}
+	}
+
+	protected void writeUnit(Unite currentUnit) {
+
+		writing_units << currentUnit
+		writing_stacks << currentUnit
+		if (currentUnit.getDeb() > writing_start)
+
+		writer.writeStartElement(currentUnit.getProp("type"));
+		HashMap props = currentUnit.getProps();
+		for (String p : props.keySet()) {
+			if (p.equals("type")) continue; // ignore the type since written in tag name
+			writer.writeAttribute(p, ""+props.get(p));
+		}
+	}
+
+	@Override
+	protected void processEndElement() throws XMLStreamException {
+		
+//		println "writing_stacks=$writing_stacks"
+//		println "stack=$stack"
+		
+		if (writing_stacks.size() > 0 && writing_stacks[-1].equals(stack)) {
+			writeCloseUnits()
+		}
+
+		super.processEndElement();
+		
+		stack = stack.substring(0, stack.length() - localname.length() - 1);
+		
+		if ("w".equals(localname)) {
+			if (start && word_id != null) {
+				writeCloseUnits()
+			}
+			word_id = null;
+		}
+	}
+}
\ No newline at end of file
Index: TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/cqp/URSUnits2CQPWordsMacro.groovy
===================================================================
--- TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/cqp/URSUnits2CQPWordsMacro.groovy	(revision 0)
+++ TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/cqp/URSUnits2CQPWordsMacro.groovy	(revision 3288)
@@ -0,0 +1,95 @@
+package org.txm.macro.urs.prototypes.cqp
+
+import org.kohsuke.args4j.*
+import groovy.transform.Field
+import org.txm.annotation.urs.*
+import org.txm.importer.ValidateXml
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.searchengine.cqp.corpus.*
+import visuAnalec.elements.*
+
+// BEGINNING OF PARAMETERS
+
+// Open the parameters input dialog box
+//if (!ParametersDialog.open(this)) return;
+
+if (!(corpusViewSelection instanceof MainCorpus)) {
+	println "Selection must be a Corpus"
+	return
+}
+
+@Field @Option(name="unit_type", usage="Corpus name in uppercase", widget="String", required=true, def="word")
+String unit_type
+
+@Field @Option(name="unit_properties", usage="Corpus name in uppercase", widget="String", required=true, def="*")
+String unit_properties
+
+@Field @Option(name="unit_word", usage="Corpus name in uppercase", widget="StringArray", metaVar="START	END	ALL", required=true, def="START")
+String unit_word
+
+if (!ParametersDialog.open(this)) return
+
+MainCorpus corpus = corpusViewSelection
+def analecCorpus = URSCorpora.getCorpus(corpus)
+
+def texts = corpus.getCorpusTextIdsList();
+def texts_startlimits = corpus.getTextStartLimits()
+def texts_endlimits = corpus.getTextEndLimits()
+
+for (int i = 0 ; i < texts.size() ; i++) {
+	
+	println "Processing annotations of "+texts[i]+"..."
+
+	def text_id = texts[i]
+	def text_start = texts_startlimits[i]
+	def text_end = texts_endlimits[i]
+
+	File xmltxmFile = new File(corpus.getProject().getProjectDirectory(), "txm/"+corpus.getID()+"/"+text_id+".xml")
+	File xmltxmFileCopy = new File(corpus.getProject().getProjectDirectory(), text_id+"_copy.xml")
+
+	if (!xmltxmFile.exists()) {
+		println "Warning: no text file found: "+xmltxmFile
+		continue
+	}
+	
+	for (String uType : analecCorpus.getStructure().getTypes(Unite.class)) {
+		def corpus_units = []
+		ArrayList<Unite> all_units = analecCorpus.getUnites(uType)
+		corpus_units = all_units.findAll() {
+			unit_type.equals(it.getProp("type")) && text_start <= it.getDeb() && it.getFin() < text_end && !("true".equals(it.getProp("written")))
+		}
+		
+		if (corpus_units.size() == 0) continue;
+		
+		try {
+			println " processing word Units ${text_id} and its '$uType' units ("+corpus_units.size()+")"
+			WordUnitsInserter inserter = new WordUnitsInserter(corpus, xmltxmFile, corpus_units, unit_properties, unit_word);
+			if (inserter.process(xmltxmFileCopy) && ValidateXml.test(xmltxmFileCopy)) {
+				xmltxmFile.delete()
+				xmltxmFileCopy.renameTo(xmltxmFile)
+
+				for (Unite unit : corpus_units) {
+					unit.getProps()["written"] = "true"
+				}
+				URSCorpora.saveCorpus(corpus);
+				println "Done, "+corpus_units.size()+ " units written"
+
+			} else {
+				println "Error while processing the XML-TXM $xmltxmFile file"
+				File error = new File(corpus.getProject().getProjectDirectory(), "error/"+xmltxmFile.getName())
+				error.getParentFile().mkdirs()
+				println "	moving created file to $error"
+				error.delete()
+				xmltxmFileCopy.renameTo(error)
+			}
+		} catch(Exception e) {
+			println "Error while processing milestones $xmltxmFile file: "+e
+			e.printStackTrace();
+			File error = new File(corpus.getProject().getProjectDirectory(), "error/"+xmltxmFile.getName())
+			error.getParentFile().mkdirs()
+			println "	moving created file to $error"
+			error.delete()
+			xmltxmFileCopy.renameTo(error)
+		}
+	}
+}
\ No newline at end of file
Index: TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/exploit/GrammaticalCategoryMacro.groovy
===================================================================
--- TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/exploit/GrammaticalCategoryMacro.groovy	(revision 0)
+++ TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/exploit/GrammaticalCategoryMacro.groovy	(revision 3288)
@@ -0,0 +1,126 @@
+// Copyright © 2016 ENS de Lyon, CNRS, University of Franche-Comté
+// Licensed under the terms of the GNU General Public License (http://www.gnu.org/licenses)
+// @author mdecorde
+// @author sheiden
+// STANDARD DECLARATIONS
+package org.txm.macro.urs.prototypes.exploit
+
+import org.kohsuke.args4j.*
+import groovy.transform.Field
+import org.txm.*
+import org.txm.macro.urs.AnalecUtils
+import visuAnalec.elements.*
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import org.txm.searchengine.cqp.*
+import org.txm.searchengine.cqp.corpus.*
+import org.apache.commons.lang.StringUtils;
+
+// BEGINNING OF PARAMETERS
+
+@Field @Option(name="schema_ursql", usage="TYPE@PROP=VALUE", widget="String", required=true, def="CHAINE")
+String schema_ursql
+
+@Field @Option(name="minimum_schema_size", usage="minimal schema size", widget="Integer", required=true, def="3")
+int minimum_schema_size
+
+@Field @Option(name="schema_display_property_name",usage="", widget="String", required=false, def="REF")
+String schema_display_property_name
+
+@Field @Option(name="unit_ursql", usage="TYPE@PROP=VALUE", widget="String", required=false, def="MENTION")
+String unit_ursql
+
+@Field @Option(name="property", usage="", widget="String", required=false, def="CATEGORIE")
+String property
+
+@Field @Option(name="debug", usage="Show internal variable content", widget="StringArray", metaVar="OFF	ON	ALL	REALLY ALL", required=true, def="OFF")
+debug
+
+if (!(corpusViewSelection instanceof CQPCorpus)) {
+	println "Corpora selection is not a Corpus"
+	return;
+}
+
+// Open the parameters input dialog box
+if (!ParametersDialog.open(this)) return;
+if (debug == "OFF") debug = 0; else if (debug == "ON") debug = 1; else if (debug == "ALL") debug = 2 else if (debug == "REALLY ALL") debug = 3
+
+// END OF PARAMETERS
+
+MainCorpus corpus = corpusViewSelection
+def analecCorpus = URSCorpora.getCorpus(corpus)
+
+if (!AnalecUtils.isPropertyDefined(Schema.class, analecCorpus, schema_ursql)) {
+	println "** The $schema_ursql schema URSQL cannot be computed in the corpus."
+	return;
+}
+
+if (!AnalecUtils.isPropertyDefined(Unite.class, analecCorpus, unit_ursql)) {
+	println "** $unit_ursql unit URSQL cannot be computed in the corpus."
+	return;
+}
+
+def CQI = CQPSearchEngine.getCqiClient()
+
+def prop = corpus.getProperty(property)
+if (prop == null) {
+	analecCorpus.getStructure()
+}
+def schemas = AnalecUtils.selectSchemasInCorpus(debug, analecCorpus, corpus, schema_ursql, minimum_schema_size, 999999);
+def allFreqs = [:]
+def n = 0
+for (def schema : schemas) {
+	n++
+	
+	def freqs = [:]
+		
+	def allUnites = schema.getUnitesSousjacentesNonTriees()
+
+	def units = AnalecUtils.filterElements(debug, allUnites, unit_ursql)
+	
+	for (def unit : units) { // no need to sort units
+
+		String forme =  null;
+		if (prop == null) { // property is the analec unit property to use
+			forme = unit.getProp(property)
+		} else {
+			int[] pos = null;
+			if (unit.getDeb() == unit.getFin()) pos = [unit.getDeb()]
+			else pos = unit.getDeb()..unit.getFin()
+				
+			forme = StringUtils.join(CQI.cpos2Str(prop.getQualifiedName(), pos), " ") // ids is enough
+		}
+		
+		if (!freqs.containsKey(forme)) freqs[forme] = 0;
+		freqs[forme] = freqs[forme] + 1;
+		
+		if (!allFreqs.containsKey(forme)) allFreqs[forme] = 0;
+		allFreqs[forme] = allFreqs[forme] + 1;
+	}
+	
+	if (schema_display_property_name != null) {
+		println "Index des natures de $unit_ursql de '"+schema.getProp(schema_display_property_name)+"' : "
+	} else {
+		println "Index des natures de $schema_ursql - $n : "
+	}
+	
+	int max = 0;
+	def result = "";
+	for (def forme : freqs.sort() { a, b -> -a.value <=> -b.value ?: a.key <=> b.key }) {
+		println forme.key+"\t"+forme.value
+	}
+}
+
+int max = 0;
+def result = "";
+
+println "Index des natures de $schema_ursql : "
+for (def forme : allFreqs.sort() { a, b -> -a.value <=> -b.value ?: a.key <=> b.key }) {
+	println forme.key+"\t"+forme.value
+	if (max < forme.value) {
+		max = forme.value
+		result = "$forme: "+forme.value
+	}
+}
+
+return ["result":result, "data":allFreqs]
\ No newline at end of file
Index: TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/exploit/AllMesuresMacro.groovy
===================================================================
--- TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/exploit/AllMesuresMacro.groovy	(revision 0)
+++ TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/exploit/AllMesuresMacro.groovy	(revision 3288)
@@ -0,0 +1,132 @@
+// Copyright © 2016 ENS de Lyon, CNRS, University of Franche-Comté
+// Licensed under the terms of the GNU General Public License (http://www.gnu.org/licenses)
+// @author mdecorde
+// @author sheiden
+// STANDARD DECLARATIONS
+package org.txm.macro.urs.prototypes.exploit
+
+import org.kohsuke.args4j.*
+
+import groovy.transform.Field
+
+import org.txm.*
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import org.txm.searchengine.cqp.corpus.*
+import org.apache.commons.lang.StringUtils;
+
+// BEGINNING OF PARAMETERS
+
+@Field @Option(name="tsvFile",usage="", widget="FileSave", required=true, def="result.tsv")
+File tsvFile
+
+@Field @Option(name="default_schema_ursql", usage="TYPE@PROP=REGEX", widget="String", required=true, def="CHAINE")
+String default_schema_ursql
+
+@Field @Option(name="default_minimum_schema_size", usage="", widget="Integer", required=true, def="3")
+int default_minimum_schema_size
+
+
+@Field @Option(name="schema_property_display_name",usage="", widget="String", required=false, def="REF")
+String schema_property_display_name
+
+@Field @Option(name="default_unit_ursql", usage="TYPE@PROP=REGEX", widget="String", required=false, def="MENTION")
+String default_unit_ursql
+
+@Field @Option(name="default_word_property", usage="", widget="String", required=false, def="word")
+String default_word_property
+@Field @Option(name="default_pos_property", usage="", widget="String", required=false, def="CATEGORIE")
+String default_pos_property
+
+if (!ParametersDialog.open(this)) return;
+// END OF PARAMETERS
+
+println "Corpora selections: "+corpusViewSelections
+
+table = [] // contains all table lines
+mesures = []
+
+for (def corpus : corpusViewSelections) { // for each corpus selected in the corpora view
+	if (!(corpus instanceof MainCorpus)) continue; // check if the corpus is a maincorpus
+	def line = [] ; table << line // create and add a new table line
+	line << corpus.getID() // add the corpus name in the first column
+	
+	println "*** Computing mesures for $corpus" // each macro return a "result" and a "data"
+
+	params = [
+		"unit_ursql":default_unit_ursql,
+	]
+	returnedValue = execMesure(UnitsReferentialDensityMacro, line, corpus, params)
+	line << returnedValue["result"]
+	
+	params = [
+		"schema_ursql":default_schema_ursql,
+		"minimum_schema_size":default_minimum_schema_size,
+		"unit_ursql":default_unit_ursql,
+	]
+	returnedValue = execMesure(SchemaLengthsMacro, line, corpus, params)
+	line << returnedValue["result"]
+	
+	params = [
+		"schema_ursql":default_schema_ursql,
+		"minimum_schema_size":default_minimum_schema_size,
+		"unit_ursql":default_unit_ursql,
+	]
+	returnedValue = execMesure(NumberOfSchemaMacro, line, corpus, params)
+	line << returnedValue["result"]
+	
+	params = [
+		"schema_ursql":default_schema_ursql,
+		"minimum_schema_size":default_minimum_schema_size,
+		"schema_property_display_name":schema_property_display_name,
+		"unit_ursql":default_unit_ursql+"@CATEGORIE=GN Défini|GN Démonstratif|Nom Propre",
+		"word_property":default_word_property,
+	]
+	returnedValue = execMesure(UnitsStabilityScoreMacro, line, corpus, params)
+	line << returnedValue["result"]
+	
+	params = [
+		"schema_ursql":default_schema_ursql,
+		"minimum_schema_size":default_minimum_schema_size,
+		"unit_ursql":default_unit_ursql,
+	]
+	returnedValue = execMesure(UnitsInterDistanceMacro, line, corpus, params)
+	line << returnedValue["result"]
+
+	params = [
+		"schema_ursql":default_schema_ursql,
+		"minimum_schema_size":default_minimum_schema_size,
+		"unit_ursql":default_unit_ursql,
+		"word_property":default_pos_property,
+	]
+	returnedValue = execMesure(NatureOfTheFirstUnitMacro, line, corpus, params)
+	line << returnedValue["data"]
+	
+	params = [
+		"schema_ursql":default_schema_ursql,
+		"minimum_schema_size":default_minimum_schema_size,
+		"schema_property_display_name":schema_property_display_name,
+		"unit_ursql":default_unit_ursql,
+		"word_property":default_pos_property,
+	]
+	returnedValue = execMesure(GrammaticalCategoryMacro, line, corpus, params)
+	line << returnedValue["data"]
+}
+
+// WRITE RESULTS IN THE TSV FILE
+tsvFile.withWriter("UTF-8") { writer ->
+	writer.println "\t"+mesures.join("\t")
+	table.each { line -> writer.println line.join("\t")	}
+}
+
+println "Done. Results are saved in ${tsvFile.getAbsolutePath()} file."
+
+// UTILITY FUNCTIONS
+def execMesure(def mesure, def line, def corpus, def params) {
+	def m = mesure.getSimpleName().substring(0, mesure.getSimpleName().indexOf("Macro"))
+	mesures << m
+	println "***** ${mesures.size()}- $m with parameters: $params"
+	def r = gse.run(mesure, ["args":params, "corpusViewSelection":corpus, "monitor":monitor])
+	if (r == null) throw new Exception("Null result");
+	return r;
+}
\ No newline at end of file
Index: TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/exploit/NatureOfTheFirstUnitMacro.groovy
===================================================================
--- TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/exploit/NatureOfTheFirstUnitMacro.groovy	(revision 0)
+++ TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/exploit/NatureOfTheFirstUnitMacro.groovy	(revision 3288)
@@ -0,0 +1,105 @@
+// Copyright © 2016 ENS de Lyon, CNRS, University of Franche-Comté
+// Licensed under the terms of the GNU General Public License (http://www.gnu.org/licenses)
+// @author mdecorde
+// @author sheiden
+// STANDARD DECLARATIONS
+package org.txm.macro.urs.prototypes.exploit
+
+import org.kohsuke.args4j.*
+import groovy.transform.Field
+import org.txm.*
+import org.txm.macro.urs.AnalecUtils
+import visuAnalec.elements.*
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import org.txm.searchengine.cqp.corpus.*
+import org.txm.searchengine.cqp.CQPSearchEngine
+import org.apache.commons.lang.StringUtils;
+
+if (!(corpusViewSelection instanceof CQPCorpus)) {
+	println "Corpora selection is not a Corpus"
+	return;
+}
+
+// BEGINNING OF PARAMETERS
+@Field @Option(name="schema_ursql", usage="TYPE@PROP=REGEX", widget="String", required=true, def="CHAINE")
+String schema_ursql
+
+@Field @Option(name="minimum_schema_size", usage="minimal schema size", widget="Integer", required=true, def="3")
+int minimum_schema_size
+
+@Field @Option(name="unit_ursql", usage="TYPE@PROP=REGEX", widget="String", required=false, def="MENTION")
+String unit_ursql
+
+@Field @Option(name="word_property", usage="", widget="String", required=false, def="CATEGORIE")
+String word_property
+
+@Field @Option(name="debug", usage="Show internal variable content", widget="StringArray", metaVar="OFF	ON	ALL	REALLY ALL", required=true, def="OFF")
+debug
+
+if (!ParametersDialog.open(this)) return;
+if (debug == "OFF") debug = 0; else if (debug == "ON") debug = 1; else if (debug == "ALL") debug = 2 else if (debug == "REALLY ALL") debug = 3
+
+
+CQPCorpus corpus = corpusViewSelection
+def analecCorpus = URSCorpora.getCorpus(corpus)
+
+if (!AnalecUtils.isPropertyDefined(Schema.class, analecCorpus, schema_ursql)) {
+	println "** The $schema_ursql schema URSQL cannot be computed in the corpus."
+	return;
+}
+
+if (!AnalecUtils.isPropertyDefined(Unite.class, analecCorpus, unit_ursql)) {
+	println "** $unit_ursql unit URSQL cannot be computed in the corpus."
+	return;
+}
+
+def CQI = CQPSearchEngine.getCqiClient()
+
+def prop = corpus.getProperty(word_property)
+
+def schemas = AnalecUtils.selectSchemasInCorpus(debug, analecCorpus, corpus, schema_ursql, minimum_schema_size, 999999);
+def freqs = [:]
+
+def distances = 0;
+def nDistances = 0
+for (def schema : schemas) {
+	
+	def allUnites = schema.getUnitesSousjacentesNonTriees()
+	
+	def units = AnalecUtils.filterElements(debug, allUnites, unit_ursql)
+	
+	int nUnites = units.size();
+	
+	if (units.size() == 0) continue;
+	
+	def unit = units[0]
+	
+	String forme =  null;
+	if (prop == null) { // word_property is the analec unit property to use
+		forme = unit.getProp(word_property)
+	} else {
+		int[] pos = null;
+		if (unit.getDeb() == unit.getFin()) pos = [unit.getDeb()]
+		else pos = unit.getDeb()..unit.getFin()
+			
+		forme = StringUtils.join(CQI.cpos2Str(prop.getQualifiedName(), pos), " ") // ids is enough
+	}
+	
+	if (!freqs.containsKey(forme)) freqs[forme] = 0;
+	
+	freqs[forme] = freqs[forme] + 1;
+}
+
+println "Index des natures de premier maillon :"
+int max = 0;
+def result = "";
+for (def forme : freqs.keySet().sort() {it -> -freqs[it]}) {
+	println "$forme\t"+freqs[forme]
+	if (max < freqs[forme]) {
+		max = freqs[forme]
+		result = "$forme: "+freqs[forme]
+	}
+}
+
+["result": result, "data": freqs]
\ No newline at end of file
Index: TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/exploit/NumberOfSchemaMacro.groovy
===================================================================
--- TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/exploit/NumberOfSchemaMacro.groovy	(revision 0)
+++ TXM/trunk/org.txm.analec.rcp/src/org/txm/macro/urs/prototypes/exploit/NumberOfSchemaMacro.groovy	(revision 3288)
@@ -0,0 +1,50 @@
+// Copyright © 2016 ENS de Lyon, CNRS, University of Franche-Comté
+// Licensed under the terms of the GNU General Public License (http://www.gnu.org/licenses)
+// @author mdecorde
+// @author sheiden
+// STANDARD DECLARATIONS
+package org.txm.macro.urs.prototypes.exploit
+
+import org.kohsuke.args4j.*
+import groovy.transform.Field
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.annotation.urs.*
+import visuAnalec.elements.*
+import org.txm.searchengine.cqp.corpus.*
+import org.txm.macro.urs.AnalecUtils
+
+if (!(corpusViewSelection instanceof CQPCorpus)) {
+	println "Corpora selection is not a Corpus"
+	return;
+}
+
+// BEGINNING OF PARAMETERS
+@Field @Option(name="schema_ursql", usage="TYPE@PROP=REGEX", widget="String", required=true, def="CHAINE")
+String schema_ursql
+
+@Field @Option(name="minimum_schema_size", usage="minimal schema size", widget="Integer", required=true, def="3")
+int minimum_schema_size
+
+@Field @Option(name="debug", usage="Show internal variable content", widget="StringArray", metaVar="OFF	ON	ALL	REALLY ALL", required=true, def="OFF")
+debug
+
+if (!ParametersDialog.open(this)) return;
+if (debug == "OFF") debug = 0; else if (debug == "ON") debug = 1; else if (debug == "ALL") debug = 2 else if (debug == "REALLY ALL") debug = 3
+
+
+CQPCorpus corpus = corpusViewSelection
+def analecCorpus = URSCorpora.getCorpus(corpus)
+
+// check Schema parameters
+if (!AnalecUtils.isPropertyDefined(Schema.class, analecCorpus, schema_ursql)) {
+	println "** The $schema_ursql schema URSQL cannot be computed in the corpus."
+	return;
+}
+
+def schemas = AnalecUtils.selectSchemasInCorpus(debug, analecCorpus, corpus, schema_ursql, minimum_schema_size, 999999);
+
+int nSchemas = schemas.size();
+
+println "Nombre de chaînes de référence d'un texte : $nSchemas"
+
+["result":nSchemas, "data":schemas]
\ No newline at end of file
