Index: tmp/org.txm.groovy.core/src/groovy/org/txm/macro/projects/antract/ExporterIdentifiantsSujetsMacro.groovy
===================================================================
--- tmp/org.txm.groovy.core/src/groovy/org/txm/macro/projects/antract/ExporterIdentifiantsSujetsMacro.groovy	(revision 3186)
+++ tmp/org.txm.groovy.core/src/groovy/org/txm/macro/projects/antract/ExporterIdentifiantsSujetsMacro.groovy	(revision 3187)
@@ -1,69 +0,0 @@
-// Copyright © 2021 ENS-LYON
-// Licensed under the terms of the GNU General Public License version 3 (http://www.gnu.org/licenses/gpl-3.0.html)
-// @author mdecorde
-
-// STANDARD DECLARATIONS
-package org.txm.macro.projects.antract
-
-import org.txm.searchengine.cqp.corpus.CQPCorpus
-import org.txm.searchengine.cqp.corpus.query.CQLQuery
-import org.txm.searchengine.cqp.CQPSearchEngine
-
-if (!(corpusViewSelection instanceof CQPCorpus)) {
-	println "Erreur: la sélection n'est pas un corpus."
-	return false
-} 
-
-CQPCorpus corpus = corpusViewSelection
-corpus.compute()
-CQPCorpus parentCorpus = corpus.getMainCorpus()
-
-String parentCorpusName = parentCorpus.getCqpId()
-
-def struct_prop = null
-def finalValues = []
-def ids = null
-
-if (parentCorpusName.startsWith("AF-VOIX-OFF-")) {
-
-	struct_prop = corpus.getStructuralUnit("div").getProperty("id")
-	values = struct_prop.getValues(corpus)
-	for (def id : values) {
-		if (id.startsWith("AFE")) {
-			finalValues << id
-		}
-	}
-	
-} else if (parentCorpusName.startsWith("AFNOTICES") || parentCorpusName.startsWith("AF-NOTICES")) {
-
-	struct_prop = corpus.getStructuralUnit("notice").getProperty("identifiantdelanotice")
-	def values = struct_prop.getValues(corpus)
-	
-	def struct_prop2 = corpus.getStructuralUnit("notice").getProperty("typedenotice")
-	def qr = corpus.query(new CQLQuery("<notice_typedenotice=\"Notice sujet\">[]"), "TMP", false)
-	int[] positions = qr.getStarts()
-	int[] strucs = CQPSearchEngine.getCqiClient().cpos2Struc(struct_prop2.getQualifiedName(), positions)
-	String sujetsIDS = CQPSearchEngine.getCqiClient().struc2Str(struct_prop.getQualifiedName(), strucs)
-	for (String id : values) {
-		int idx = sujetsIDS.indexOf(id)
-		if (idx > 0) {
-			finalValues << id // this id is actually in the sujetsIDS
-		}
-	}
-
-} else {
-	println "Erreur: le corpus n'est pas un corpus d'AF-VOIX-OFF ni AFNOTICE"
-	return false
-}
-
-ids = finalValues.sort().join("|")
-
-println "Liste des identifiants (${finalValues.size()}) : "+ids
-
-monitor.syncExec(new Runnable() {
-	public void run() {
-		IOClipboard.write(ids)
-	}
-})
-
-return ids
Index: tmp/org.txm.groovy.core/src/groovy/org/txm/macro/projects/antract/ExporterLeCorpusVersOkapiMacro.groovy
===================================================================
--- tmp/org.txm.groovy.core/src/groovy/org/txm/macro/projects/antract/ExporterLeCorpusVersOkapiMacro.groovy	(revision 3186)
+++ tmp/org.txm.groovy.core/src/groovy/org/txm/macro/projects/antract/ExporterLeCorpusVersOkapiMacro.groovy	(revision 3187)
@@ -1,65 +0,0 @@
-// Copyright © 2021 ENS-LYON
-// Licensed under the terms of the GNU General Public License version 3 (http://www.gnu.org/licenses/gpl-3.0.html)
-// @author mdecorde
-
-// STANDARD DECLARATIONS
-package org.txm.macro.projects.antract
-
-import org.txm.searchengine.cqp.corpus.CQPCorpus
-import org.txm.searchengine.cqp.corpus.query.CQLQuery
-import org.txm.macro.projects.antract.OkapiSaphirAPI
-import org.txm.searchengine.cqp.CQPSearchEngine
-
-import org.txm.backtomedia.preferences.BackToMediaPreferences
-
-if (!(corpusViewSelection instanceof CQPCorpus)) {
-	println "Erreur: la sélection n'est pas un corpus."
-	return false
-} 
-
-@Field @Option(name="titre_du_nouveau_corpus_okapi", usage="Nom du corpus à créer", widget="String", required=false, def="")
-def titre_du_nouveau_corpus_okapi
-
-if (!ParametersDialog.open(this)) return;
-
-CQPCorpus corpus = corpusViewSelection
-corpus.compute()
-CQPCorpus parentCorpus = corpus.getMainCorpus()
-
-String parentCorpusName = parentCorpus.getCqpId()
-
-def struct_prop = null
-def finalValues = []
-def ids = null
-
-if (parentCorpusName.startsWith("AF-VOIX-OFF-")) {
-	ids = gse.run(ExporterIdentifiantsSujetsMacro, ["args":[:], "corpusViewSelection":corpusViewSelection, "monitor":monitor])
-} else if (parentCorpusName.startsWith("AFNOTICES") || parentCorpusName.startsWith("AF-NOTICES")) {
-	ids = gse.run(ExporterIdentifiantsSujetsMacro, ["args":[:], "corpusViewSelection":corpusViewSelection, "monitor":monitor])
-} else {
-	println "Erreur: le corpus n'est pas un corpus d'AF-VOIX-OFF ni AFNOTICE"
-	return false
-}
-
-if (!OkapiSaphirAPI.initializeCredentials(BackToMediaPreferences.MEDIA_AUTH_LOGIN, BackToMediaPreferences.MEDIA_AUTH_PASSWORD, 
-	"OKAPI - Antract", "You must authenticate to access the okapi corpus API", "OKAPI - Antract", monitor)) {
-	println "Cancel corpus export"
-	return null;
-}
-
-String user = System.getProperty(BackToMediaPreferences.MEDIA_AUTH_LOGIN)
-String password = System.getProperty(BackToMediaPreferences.MEDIA_AUTH_PASSWORD)
-
-String sessionID = OkapiSaphirAPI.login(user, password)
-if (sessionID.length() > 0) {
-	String corpusID = OkapiSaphirAPI.create_corpus(sessionID, titre_du_nouveau_corpus_okapi, ids)
-	if (sessionID.length() > 0 && sessionID.startsWith("http")) {
-		println "New Okapi corpus $titre_du_nouveau_corpus_okapi created: "+corpusID
-	} else {
-		println "Error: Okapi corpus not created: "+corpusID
-	}
-} else {
-	println "Error: Okapi session not started. Resetting credentials."
-	System.setProperty(BackToMediaPreferences.MEDIA_AUTH_LOGIN, "")
-	System.setProperty(BackToMediaPreferences.MEDIA_AUTH_PASSWORD, "")
-}
\ No newline at end of file
Index: tmp/org.txm.groovy.core/src/groovy/org/txm/macro/projects/antract/ListerIdentifiantsSujetsMacro.groovy
===================================================================
--- tmp/org.txm.groovy.core/src/groovy/org/txm/macro/projects/antract/ListerIdentifiantsSujetsMacro.groovy	(revision 0)
+++ tmp/org.txm.groovy.core/src/groovy/org/txm/macro/projects/antract/ListerIdentifiantsSujetsMacro.groovy	(revision 3187)
@@ -0,0 +1,69 @@
+// Copyright © 2021 ENS-LYON
+// Licensed under the terms of the GNU General Public License version 3 (http://www.gnu.org/licenses/gpl-3.0.html)
+// @author mdecorde
+
+// STANDARD DECLARATIONS
+package org.txm.macro.projects.antract
+
+import org.txm.searchengine.cqp.corpus.CQPCorpus
+import org.txm.searchengine.cqp.corpus.query.CQLQuery
+import org.txm.searchengine.cqp.CQPSearchEngine
+
+if (!(corpusViewSelection instanceof CQPCorpus)) {
+	println "Erreur: la sélection n'est pas un corpus."
+	return false
+} 
+
+CQPCorpus corpus = corpusViewSelection
+corpus.compute()
+CQPCorpus parentCorpus = corpus.getMainCorpus()
+
+String parentCorpusName = parentCorpus.getCqpId()
+
+def struct_prop = null
+def finalValues = []
+def ids = null
+
+if (parentCorpusName.startsWith("AF-VOIX-OFF-")) {
+
+	struct_prop = corpus.getStructuralUnit("div").getProperty("id")
+	values = struct_prop.getValues(corpus)
+	for (def id : values) {
+		if (id.startsWith("AFE")) {
+			finalValues << id
+		}
+	}
+	
+} else if (parentCorpusName.startsWith("AFNOTICES") || parentCorpusName.startsWith("AF-NOTICES")) {
+
+	struct_prop = corpus.getStructuralUnit("notice").getProperty("identifiantdelanotice")
+	def values = struct_prop.getValues(corpus)
+	
+	def struct_prop2 = corpus.getStructuralUnit("notice").getProperty("typedenotice")
+	def qr = corpus.query(new CQLQuery("<notice_typedenotice=\"Notice sujet\">[]"), "TMP", false)
+	int[] positions = qr.getStarts()
+	int[] strucs = CQPSearchEngine.getCqiClient().cpos2Struc(struct_prop2.getQualifiedName(), positions)
+	String sujetsIDS = CQPSearchEngine.getCqiClient().struc2Str(struct_prop.getQualifiedName(), strucs)
+	for (String id : values) {
+		int idx = sujetsIDS.indexOf(id)
+		if (idx > 0) {
+			finalValues << id // this id is actually in the sujetsIDS
+		}
+	}
+
+} else {
+	println "Erreur: le corpus n'est pas un corpus d'AF-VOIX-OFF ni AFNOTICE"
+	return false
+}
+
+ids = finalValues.sort().join("|")
+
+println "Liste des identifiants (${finalValues.size()}) : "+ids
+
+monitor.syncExec(new Runnable() {
+	public void run() {
+		IOClipboard.write(ids)
+	}
+})
+
+return ids
Index: tmp/org.txm.groovy.core/src/groovy/org/txm/macro/projects/antract/OkapiSaphirAPI.groovy
===================================================================
--- tmp/org.txm.groovy.core/src/groovy/org/txm/macro/projects/antract/OkapiSaphirAPI.groovy	(revision 3186)
+++ tmp/org.txm.groovy.core/src/groovy/org/txm/macro/projects/antract/OkapiSaphirAPI.groovy	(revision 3187)
@@ -11,6 +11,7 @@
 import java.net.URLEncoder;
 import java.util.List;
 import java.util.Map;
+import javax.ws.rs.core.UriBuilder
 
 import org.eclipse.swt.widgets.Display;
 import org.eclipse.swt.widgets.Shell;
@@ -25,8 +26,13 @@
 	
 	public static final String baseUrl = "https://okapi.ina.fr/antract/api/saphir/";
 	public static final String okapiUrl = "https://okapi.ina.fr/antract/html/resource_587884135/resource_996999332.html";
+
 	public static boolean debug = true;
 	
+	public static String getDirectAccessURL(String id) {
+		return OkapiSaphirAPI.okapiUrl+"?linkedObjectUri="+URLEncoder.encode(id, "UTF-8")
+	}
+	
 	public static String login(String user, String password) {
 		URL url1;
 		try {
@@ -46,12 +52,17 @@
 			}
 
 			String sessionID = getOkapiSessionID(conn)
+			String content1 = getContent(conn);
+			if (debug) {
+				println "content="+content1
+				println "sessionID="+sessionID
+			}
+			
 			if (sessionID.length() == 0) {
 				if (debug) System.out.println("Error: not connected no session ID found");
 				return "";
 			}
 			
-			String content1 = getContent(conn);
 			if (!content1.contains("Welcome "+user)) {
 				if (debug) System.out.println("Error: not connected, welcome message not found: "+content1);
 				return "";
@@ -67,6 +78,8 @@
 		}
 	}
 	
+	
+	
 	public static String update_corpus(String sessionID, String corpusID, String ids) {
 		return create_or_update_corpus(sessionID, corpusID, null, ids);
 	}
@@ -75,7 +88,7 @@
 		return create_or_update_corpus(sessionID, null, title, ids);
 	}
 	
-	public static String create_or_update_corpus(String sessionID, String corpusID, String title, String ids) {
+	protected static String create_or_update_corpus(String sessionID, String corpusID, String title, String ids) {
 		URL url2;
 		String action = "";
 		try {
@@ -93,39 +106,38 @@
 				return "";
 			}
 			
-			url2 = new URL(baseUrl+"create_corpus");
+			if (action == "create") {
+				url2 = new URL(baseUrl+"create_corpus?title="+URLEncoder.encode(title, "UTF-8"));
+			} else if (action == "update") {
+				url2 = new URL(baseUrl+"create_corpus?uri="+URLEncoder.encode(corpusID, "UTF-8"));
+			}
 			
 			if (debug) System.out.println("Requesting: "+action+" : "+url2);
 			HttpURLConnection conn2 = (HttpURLConnection) url2.openConnection();
-			conn2.setRequestMethod("POST");
+			conn2.setRequestProperty("content-type", "text/plain; charset=UTF-8");
 			conn2.setRequestProperty("session", sessionID);
-						
+			conn2.setDoOutput(true);
+			
 			if (debug) System.out.println("Writing POST...");		
 			
-			conn2.setDoOutput(true);
 			DataOutputStream wr = new DataOutputStream(conn2.getOutputStream());
-			String str = ""
-			if (action == "create") {
-				str += "title="+title
-			} else if (action == "update") {
-				str += "uri="+corpusID
-			}
-			str += "&content="+ids
-			if (debug) println "POST="+str
-			wr.writeBytes(str);
+			
+			if (debug) println "POST="+URLEncoder.encode(ids, "UTF-8")
+			wr.writeBytes(ids);
 			wr.flush();
 			wr.close();
-				
-			conn2.connect()
 			
 			if (debug) System.out.println("getResponseCode...");	
 			int code2 = conn2.getResponseCode();
 			if (code2 != HttpURLConnection.HTTP_OK) {
-				if (debug) System.out.println("Error: during corpus "+action+" error='"+code2+"' and command="+url2);
+				if (debug) System.out.println("Error: during corpus "+action+" error='"+code2+"', command="+url2+", post="+URLEncoder.encode(ids, "UTF-8"));
 				return "";
 			}
 			if (debug) System.out.println("getContent...");	
-			String content2 = getContent(conn2);
+			String content2 = getContent(conn2).trim();
+			if (content2.startsWith("\"") && content2.endsWith("\"")) {
+				content2 = content2.substring(1, content2.length() -1)
+			}
 			
 			conn2.disconnect();
 			
@@ -254,17 +266,13 @@
 	}
 	
 	//TODO remove this and call UsernamePasswordDialog.initializeCredentials
-	public static boolean initializeCredentials(String userKey, String passwordKey, String target, String title, String details) {
+	public static boolean initializeCredentials(Shell shell, String userKey, String passwordKey, String target, String title, String details) {
 		
 		if (System.getProperty(userKey) == null
-		|| System.getProperty(passwordKey) == null) {
+		|| System.getProperty(passwordKey) == null
+		|| System.getProperty(userKey).length() == 0
+		|| System.getProperty(passwordKey).length() == 0) {
 			
-			Shell shell = Display.getCurrent().getActiveShell();
-			if (shell == null) {
-				System.out.println("Error: could not open crendetial dialog on current Thread.");
-				return false;
-			}
-			
 			UsernamePasswordDialog dialog = new UsernamePasswordDialog(shell, [userKey != null, passwordKey != null ] as boolean[], target);
 			if (userKey != null) dialog.setUsername(System.getProperty(userKey));
 			dialog.setTitle(title);
@@ -283,7 +291,7 @@
 	}
 	
 	//TODO remove this and call UsernamePasswordDialog.initializeCredentials
-	public static boolean initializeCredentials(String userKey, String passwordKey, String target, String title, String details, JobHandler monitor) {
+	public static boolean initializeCredentials(Shell shell, String userKey, String passwordKey, String target, String title, String details, JobHandler monitor) {
 		
 		final def ret = [false]
 		
@@ -291,7 +299,7 @@
 			public void run() {
 				System.out.println("Opening credential dialog...");
 				try {
-					ret[0] = initializeCredentials(userKey, passwordKey, target, title, details);
+					ret[0] = initializeCredentials(shell, userKey, passwordKey, target, title, details);
 				} catch(Throwable t) {
 					t.printStackTrace();
 				}
Index: tmp/org.txm.groovy.core/src/groovy/org/txm/macro/projects/antract/ImporterUnCorpusOkapiMacro.groovy
===================================================================
--- tmp/org.txm.groovy.core/src/groovy/org/txm/macro/projects/antract/ImporterUnCorpusOkapiMacro.groovy	(revision 0)
+++ tmp/org.txm.groovy.core/src/groovy/org/txm/macro/projects/antract/ImporterUnCorpusOkapiMacro.groovy	(revision 3187)
@@ -0,0 +1,67 @@
+// Copyright © 2021 MY_INSTITUTION
+// Licensed under the terms of the GNU General Public License version 3 (http://www.gnu.org/licenses/gpl-3.0.html)
+// @author mdecorde
+
+// STANDARD DECLARATIONS
+package org.txm.macro
+
+import org.kohsuke.args4j.*
+import groovy.transform.Field
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.searchengine.cqp.corpus.CQPCorpus
+import org.txm.searchengine.cqp.corpus.Subcorpus
+import org.txm.searchengine.cqp.corpus.query.CQLQuery
+import org.txm.rcp.views.corpora.CorporaView
+
+// BEGINNING OF PARAMETERS
+
+@Field @Option(name="name", usage="Nom du sous-corpus à créer", widget="String", required=true, def="")
+def name
+@Field @Option(name="identifiants", usage="Liste des identifiants de notice séparés par des '|'", widget="Text", required=true, def="")
+def identifiants
+
+if (!(corpusViewSelection instanceof CQPCorpus)) {
+	println "Erreur: la sélection n'est pas un corpus."
+	return false
+} 
+
+CQPCorpus corpus = corpusViewSelection
+corpus.compute()
+CQPCorpus parentCorpus = corpus.getMainCorpus()
+
+String parentCorpusName = parentCorpus.getCqpId()
+
+if (parentCorpusName.startsWith("AF-VOIX-OFF-")) {
+	
+} else if (parentCorpusName.startsWith("AFNOTICES") || parentCorpusName.startsWith("AF-NOTICES")) {
+	
+} else {
+	println "Erreur: le corpus n'est pas un corpus d'AF-VOIX-OFF ni AFNOTICE"
+	return false
+}
+
+// Open the parameters input dialog box
+if (!ParametersDialog.open(this)) return;
+
+println "Création du sous-corpus avec la liste: $identifiants"
+String prop = "div_id"
+if (parentCorpusName.startsWith("AFNOTICES") || parentCorpusName.startsWith("AF-NOTICES")) {
+	prop = "notice_identifiantdelanotice"
+}
+
+String query = "[_.$prop=\"$identifiants\"] expand to $prop"
+println "Query=$query"
+Subcorpus sub = parentCorpus.createSubcorpus(new CQLQuery(query), name)
+
+int s = sub.getSize()
+if (s > 0) {
+	println "$name subcorpus is created."
+	monitor.syncExec(new Runnable() {
+					public void run() {
+						CorporaView.refresh();
+						CorporaView.expand(parentCorpus);
+					}
+				});
+} else {
+	println "Error: the created corpus is empty!"
+}
\ No newline at end of file
Index: tmp/org.txm.groovy.core/src/groovy/org/txm/macro/projects/antract/ExporterSousCorpusSujetsDansOkapiMacro.groovy
===================================================================
--- tmp/org.txm.groovy.core/src/groovy/org/txm/macro/projects/antract/ExporterSousCorpusSujetsDansOkapiMacro.groovy	(revision 0)
+++ tmp/org.txm.groovy.core/src/groovy/org/txm/macro/projects/antract/ExporterSousCorpusSujetsDansOkapiMacro.groovy	(revision 3187)
@@ -0,0 +1,70 @@
+// Copyright © 2021 ENS-LYON
+// Licensed under the terms of the GNU General Public License version 3 (http://www.gnu.org/licenses/gpl-3.0.html)
+// @author mdecorde
+
+// STANDARD DECLARATIONS
+package org.txm.macro.projects.antract
+
+import org.txm.searchengine.cqp.corpus.CQPCorpus
+import org.txm.searchengine.cqp.corpus.query.CQLQuery
+import org.txm.macro.projects.antract.OkapiSaphirAPI
+import org.txm.searchengine.cqp.CQPSearchEngine
+
+import org.txm.backtomedia.preferences.BackToMediaPreferences
+
+if (!(corpusViewSelection instanceof CQPCorpus)) {
+	println "Erreur: la sélection n'est pas un corpus."
+	return false
+} 
+
+@Field @Option(name="titre_du_nouveau_corpus_okapi", usage="Nom du corpus à créer", widget="String", required=false, def="")
+def titre_du_nouveau_corpus_okapi
+
+if (!ParametersDialog.open(this)) return;
+
+CQPCorpus corpus = corpusViewSelection
+corpus.compute()
+CQPCorpus parentCorpus = corpus.getMainCorpus()
+
+String parentCorpusName = parentCorpus.getCqpId()
+
+def struct_prop = null
+def finalValues = []
+def ids = null
+
+if (parentCorpusName.startsWith("AF-VOIX-OFF-")) {
+	ids = gse.run(ListerIdentifiantsSujetsMacro, ["args":[:], "corpusViewSelection":corpusViewSelection, "monitor":monitor])
+} else if (parentCorpusName.startsWith("AFNOTICES") || parentCorpusName.startsWith("AF-NOTICES")) {
+	ids = gse.run(ListerIdentifiantsSujetsMacro, ["args":[:], "corpusViewSelection":corpusViewSelection, "monitor":monitor])
+} else {
+	println "Erreur: le corpus n'est pas un corpus d'AF-VOIX-OFF ni AFNOTICE"
+	return false
+}
+
+monitor.syncExec(new Runnable() {
+	public void run() {
+		if (!OkapiSaphirAPI.initializeCredentials(org.eclipse.swt.widgets.Display.getCurrent().getActiveShell(), BackToMediaPreferences.MEDIA_AUTH_LOGIN, BackToMediaPreferences.MEDIA_AUTH_PASSWORD, "OKAPI - Antract", "You must authenticate to access the okapi corpus API", "OKAPI - Antract", monitor)) {
+			println "Cancel corpus export"
+			return null;
+		}
+	}
+});
+
+
+String user = System.getProperty(BackToMediaPreferences.MEDIA_AUTH_LOGIN)
+String password = System.getProperty(BackToMediaPreferences.MEDIA_AUTH_PASSWORD)
+
+String sessionID = OkapiSaphirAPI.login(user, password)
+if (sessionID.length() > 0) {
+	String corpusID = OkapiSaphirAPI.create_corpus(sessionID, titre_du_nouveau_corpus_okapi, ids)
+	if (corpusID.length() > 0 && corpusID.startsWith("http")) {
+		println "New Okapi corpus $titre_du_nouveau_corpus_okapi created with ID "+corpusID
+		println "Direct access link: "+OkapiSaphirAPI.getDirectAccessURL(corpusID)
+	} else {
+		println "Error: Okapi corpus not created (return value="+corpusID+")"
+	}
+} else {
+	println "Error: Okapi session not started. Resetting credentials."
+	System.setProperty(BackToMediaPreferences.MEDIA_AUTH_LOGIN, "")
+	System.setProperty(BackToMediaPreferences.MEDIA_AUTH_PASSWORD, "")
+}
\ No newline at end of file
Index: tmp/org.txm.groovy.core/src/groovy/org/txm/macro/projects/antract/AjouterDesSujetsAuCorpusOkapiMacro.groovy
===================================================================
--- tmp/org.txm.groovy.core/src/groovy/org/txm/macro/projects/antract/AjouterDesSujetsAuCorpusOkapiMacro.groovy	(revision 3186)
+++ tmp/org.txm.groovy.core/src/groovy/org/txm/macro/projects/antract/AjouterDesSujetsAuCorpusOkapiMacro.groovy	(revision 3187)
@@ -17,6 +17,9 @@
 	return false
 }
 
+@Field @Option(name="liste_des_identifiants", usage="Listes des identifiants sujets à ajouter", widget="String", required=false, def="")
+def liste_des_identifiants
+
 @Field @Option(name="identifiant_du_corpus_okapi_a_modifier", usage="Identifiant Okapi du corpus à modifier", widget="String", required=false, def="")
 def identifiant_du_corpus_okapi_a_modifier
 
@@ -30,17 +33,7 @@
 
 def struct_prop = null
 def finalValues = []
-def ids = null
 
-if (parentCorpusName.startsWith("AF-VOIX-OFF-")) {
-	ids = gse.run(ExporterIdentifiantsSujetsMacro, ["args":[:], "corpusViewSelection":corpusViewSelection, "monitor":monitor])
-} else if (parentCorpusName.startsWith("AFNOTICES") || parentCorpusName.startsWith("AF-NOTICES")) {
-	ids = gse.run(ExporterIdentifiantsSujetsMacro, ["args":[:], "corpusViewSelection":corpusViewSelection, "monitor":monitor])
-} else {
-	println "Erreur: le corpus n'est pas un corpus d'AF-VOIX-OFF ni AFNOTICE"
-	return false
-}
-
 // set Okapi user&password
 if (OkapiSaphirAPI.initializeCredentials(BackToMediaPreferences.MEDIA_AUTH_LOGIN, BackToMediaPreferences.MEDIA_AUTH_PASSWORD,
 	"OKAPI - Antract", "You must authenticate to access the okapi corpus API", "OKAPI - Antract", monitor)) {
@@ -58,9 +51,9 @@
 // start the Okapi session
 String sessionID = OkapiSaphirAPI.login(user, password)
 if (sessionID.length() > 0) {
-	String corpusID = OkapiSaphirAPI.update_corpus(sessionID, identifiant_du_corpus_okapi_a_modifier, ids)
+	String corpusID = OkapiSaphirAPI.update_corpus(sessionID, identifiant_du_corpus_okapi_a_modifier, liste_des_identifiants)
 	if (sessionID.length() > 0 && sessionID.startsWith("http")) {
-		println "Okapi corpus $identifiant_du_corpus_okapi_a_modifier updated with "+ids
+		println "Okapi corpus $identifiant_du_corpus_okapi_a_modifier updated with "+liste_des_identifiants
 	} else {
 		println "Error: Okapi corpus not updated: "+sessionID
 	}
Index: tmp/org.txm.groovy.core/src/groovy/org/txm/macro/projects/antract/WordProperty2WordMacro.groovy
===================================================================
--- tmp/org.txm.groovy.core/src/groovy/org/txm/macro/projects/antract/WordProperty2WordMacro.groovy	(revision 0)
+++ tmp/org.txm.groovy.core/src/groovy/org/txm/macro/projects/antract/WordProperty2WordMacro.groovy	(revision 3187)
@@ -0,0 +1,87 @@
+
+package org.txm.macro.annotation
+
+// STANDARD DECLARATIONS
+import org.txm.rcpapplication.swt.widget.parameters.*
+import org.txm.searchengine.cqp.corpus.*
+import org.txm.xml.DOMIdentityHook
+import org.txm.xml.LocalNameHookActivator
+import org.txm.xml.XMLProcessor
+import org.txm.objects.*
+import org.txm.rcp.utils.JobHandler
+import org.txm.rcp.views.corpora.CorporaView
+import org.eclipse.core.runtime.Status
+import org.txm.annotation.kr.core.KRAnnotationEngine
+import org.txm.annotation.kr.core.repository.*
+import org.txm.annotation.kr.rcp.commands.SaveAnnotations
+import org.txm.annotation.kr.rcp.concordance.WordAnnotationToolbar
+import org.txm.importer.StaxIdentityParser
+
+def scriptName = this.class.getSimpleName()
+
+if (!(corpusViewSelection instanceof MainCorpus)) {
+	println "** $scriptName: please select a Corpus in the Corpus view."
+	return 0
+}
+
+MainCorpus mcorpus = corpusViewSelection
+Project project = mcorpus.getProject()
+File txmDir = new File(project.getProjectDirectory(), "txm/"+mcorpus.getName())
+
+@Field @Option(name="outputDirectory", usage="Directory of resulting XML-TXM files", widget="Folder", required=true, def="result_directory")
+File outputDirectory
+
+@Field @Option(name="word_property", usage="The word property to move", widget="String", required=true, def="type")
+String word_property
+
+//@Field @Option(name="word_property_value_to_ignore", usage="The annotation type", widget="String", required=true, def="__undef__")
+//String word_property_value_to_ignore
+
+// Open the parameters input dialog box
+if (!ParametersDialog.open(this)) return
+
+if (!outputDirectory.exists()) {
+	println "Error: output directory not found: "+outputDirectory
+	return false
+}
+
+for (Text text : project.getChildren(Text.class)) {
+	println "Text: "+text
+	
+	File orig = text.getXMLTXMFile()
+	if (!orig.exists()) {
+		println "Warning: no XML-TXM file found for "+text
+		continue // next !
+	}
+	
+	File result = new File(outputDirectory, orig.getName())
+	
+	if (false && result.lastModified() > orig.lastModified()) {
+		println "Skipping $text: result file is more recent: $result"
+		continue // next !
+	}
+	
+	XMLProcessor xp = new XMLProcessor(orig);
+	LocalNameHookActivator activator = new LocalNameHookActivator("w");
+	new DOMIdentityHook("word", activator, xp) {
+		@Override
+		public void processDom() {
+			//println dom
+			use(groovy.xml.dom.DOMCategory) {
+				def form = dom.form[0]
+				def anatype = dom.ana.findAll(){ a -> a['@type'] == "#$word_property"}
+//				println form.text()+" -> $anatype"
+				if (anatype.size() > 0) { // keep the word
+					anatype = anatype[0]
+					def s = form.text()
+					form.setTextContent(anatype.text())
+					anatype['@type'] = "#form"
+					anatype.setTextContent(s)
+				} else {
+					dom = null;
+				}
+			}
+		}
+	}
+	xp.process(result)
+}
\ No newline at end of file
