diff --git a/CHANGES b/CHANGES
index 48813cbd6b0a796db72bfb2e222d68bb3bd704fb..1eaa08cb207378db109c8b8d945c3a1c739af56a 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,24 @@
+v1.9
+----
+
+- By default, client.StorageManager now ignores update requests for unknown
+  results.  A delegate can be provided to examine each of those requests and
+  decide whether they should be accepted --for details, see
+  StorageManager.StorageManagerDelegateInterface.
+
+  This also fixes the situation where "ghost" execution-in-progress items
+  where coming back each time the application was relaunched, no matter how
+  many time you delete them (these items are processes in the RUNNING state
+  whose processes is not executed anymore but which remain in the server
+  database after a crash e.g.).
+
+- Enhanced logging:
+
+  - the number of connected users is now logged when a user successfully
+    connects (it was only logged when a user disconnects).
+
+  - the list of programs'ids in every executed workflow
+
 v1.8.1
 ------
 
diff --git a/LICENSE/LICENCE.fr b/LICENSE/LICENCE.fr
index 383a7724284d4c7f1eac86cccc31e2f103b13ae7..f8be916eb350a0cda0d983fce2d6bbadf3c3cc49 100644
--- a/LICENSE/LICENCE.fr
+++ b/LICENSE/LICENCE.fr
@@ -1,8 +1,7 @@
-Copyright Institut Télécom-Télécom Bretagne, 2002-2012
+Copyright Institut Télécom-Télécom Bretagne, 2002-2013
 
-Contributeurs:
+Project leader, maintenance:
   Sébastien Bigaret <sebastien.bigaret@telecom-bretagne.eu>
-  Philippe Picouet  <philippe.picouet@telecom-bretagne.eu>
 
 Ce logiciel, Praxis, est un environnement logiciel de fédération et de
 combinaison de services distribués au sein de workflows.
diff --git a/LICENSE/LICENSE.en b/LICENSE/LICENSE.en
index f1b703216d8f1dc92b8d231884f2a42a93e2b160..a20f17c73fd4e677fdb39714a9355811b00643ec 100644
--- a/LICENSE/LICENSE.en
+++ b/LICENSE/LICENSE.en
@@ -1,8 +1,7 @@
-Copyright Institut Télécom-Télécom Bretagne, 2002-2012
+Copyright Institut Télécom-Télécom Bretagne, 2002-2013
 
-Contributors:
+Project leader, maintainer:
   Sébastien Bigaret <sebastien.bigaret@telecom-bretagne.eu>
-  Philippe Picouet  <philippe.picouet@telecom-bretagne.eu>
 
 This software, Praxis, is a software environment for federating and
 combining distributed services using workflows.
diff --git a/data/i18n/praxis_en.properties b/data/i18n/praxis_en.properties
index a8d17f1dc86e0a803afad417b7a4d51b774b9d12..775ef70b783edfd367b6d6e843bc46261276c631 100644
--- a/data/i18n/praxis_en.properties
+++ b/data/i18n/praxis_en.properties
@@ -16,6 +16,10 @@ UI.actions.finished_exec_with_warnings.msg            = The execution of {0} is
 UI.actions.finished_exec.title                        = End of execution
 UI.actions.wf_close                                   = Close
 UI.actions.wf_close_tt                                = Close current workflow
+UI.actions.wf_close_all                               = Close all
+UI.actions.wf_close_all_tt                            = Close all workflows
+UI.actions.wf_close_others                            = Close others
+UI.actions.wf_close_others_tt                         = Close other workflows
 UI.actions.wf_export                                  = Export without input files...
 UI.actions.wf_export_tt                               = Export a workflow
 UI.actions.wf_export_with_infiles                     = Export with input files...
@@ -64,7 +68,7 @@ UI.dialog.about_content                               = <html>\
   {3}\
   <hr>\
   <i>Powered by Praxis - Version {0} - date: {2}<br>\
-     Copyright Institut Telecom-Telecom Bretagne, 2002-2012<br>\
+     Copyright Institut Telecom-Telecom Bretagne, 2002-2013<br>\
      All rights reserved</i>\
 </html>
 UI.dialog.about_msg                                   = 
@@ -174,7 +178,7 @@ UI.dialog.wf.open_failure                             = An unexpected error occu
 UI.dialog.wf.rename_save_before_confirm               = The workflow has been modified and needs to be saved before it is renamed.\n\
 Do you want to save it now?
 UI.dialog.wf.open_failure_title                       = Failed to open a workflow
-UI.dialog.wf.open_select_workflows                    = Select the workflow(s) to be opene:
+UI.dialog.wf.open_select_workflows                    = Select the workflow(s) to be opened:
 UI.dialog.wf.rename_enter_new_name                    = Please enter the new name of this workflow:
 UI.dialog.wf.rename_failure_title                     = Failed to rename a workflow
 UI.dialog.wf.rename_impossible                        = Failed to rename the workflow (unknown reason).\n\
diff --git a/data/i18n/praxis_fr.properties b/data/i18n/praxis_fr.properties
index a63f9131242a07cdb7f2212ceeabb3ba7d6c08e8..e60a2b81fd0259d624a52bf344c5e5f776bc0f9c 100644
--- a/data/i18n/praxis_fr.properties
+++ b/data/i18n/praxis_fr.properties
@@ -16,6 +16,10 @@ UI.actions.finished_exec_with_warnings.msg            = L''ex\u00E9cution du wor
 UI.actions.finished_exec.title                        = Fin de l''ex\u00E9cution d''un workflow
 UI.actions.wf_close                                   = Fermer
 UI.actions.wf_close_tt                                = Fermer le workflow courant
+UI.actions.wf_close_all                               = Tout fermer
+UI.actions.wf_close_all_tt                            = Fermer tous les workflows
+UI.actions.wf_close_others                            = Fermer les autres
+UI.actions.wf_close_others_tt                         = Fermer les autres workflows
 UI.actions.wf_export                                  = Exporter sans les fichiers d''entr\u00E9es......
 UI.actions.wf_export_tt                               = Exporter un workflow
 UI.actions.wf_export_with_infiles                     = Exporter avec les fichiers d''entr\u00E9es...
@@ -64,7 +68,7 @@ UI.dialog.about_content                                   = <html>\
   {3}\
   <hr>\
   <i>Elabor\u00e9 avec Praxis - Version {0} - dat\u00E9 du {2}<br>\
-     Copyright Institut T\u00E9l\u00E9com-T\u00E9l\u00E9com Bretagne, 2002-2012<br>\
+     Copyright Institut T\u00E9l\u00E9com-T\u00E9l\u00E9com Bretagne, 2002-2013<br>\
      Tous droits r\u00E9serv\u00E9s</i>\
 </html>
 UI.dialog.about_msg                                   = 
diff --git a/src/eu/telecom_bretagne/praxis/client/StorageManager.java b/src/eu/telecom_bretagne/praxis/client/StorageManager.java
index 19626e9a66a57bc67a64e17921c3db3c9f4c2012..be7213a3ef37e50b401f6747edfb8e1319d3a488 100644
--- a/src/eu/telecom_bretagne/praxis/client/StorageManager.java
+++ b/src/eu/telecom_bretagne/praxis/client/StorageManager.java
@@ -131,6 +131,40 @@ public class StorageManager
         }
 	}
 
+	/**
+	 * Interface for the {@link StorageManager}'s delegate.
+	 * @author Sébastien Bigaret
+	 */
+	static public interface StorageManagerDelegateInterface
+	{
+		/**
+		 * Called by the storage manager when it is receives update requests concerning unknown results, i.e. results
+		 * whose worklow ID and execution ID do not {@link StorageManager#getResult(WorkflowID, ExecutionID) correspond}
+		 * to any result it holds.
+		 * 
+		 * @param result 
+		 * @return {@code true} if the result should be accepted by the storage manager.
+		 */
+		public boolean acceptUnknownResult(Result result);
+	}
+
+	/**
+	 * The default delegate when none is supplied, or when the delegate is reset (set to {@code null}).
+	 * @author Sébastien Bigaret
+	 */
+	static public class DefaultStorageManagerDelegate implements StorageManagerDelegateInterface
+	{
+		/**
+		 * Rejects all requests
+		 * 
+		 * @return {@code false}
+		 */
+		public boolean acceptUnknownResult(Result result)
+		{
+			return false;
+		}
+	}
+
 	static public final String SERIALIZED_RESULT_FILENAME = "praxis_serialized_result.xml";
 	
 	/** Paths of workflows */
@@ -158,6 +192,7 @@ public class StorageManager
 	 * */
 	static public boolean storeReceivedExecutionResults = true;
 	
+	static private StorageManagerDelegateInterface delegate = new DefaultStorageManagerDelegate();
 
 	static synchronized private void init()
 	{
@@ -238,6 +273,13 @@ public class StorageManager
 		return results_DO_NOT_USE_DIRECTLY_SEE_IMPLEMENTATION_COMMENT_ON_TOP;
 	}
 
+	public static void setDelegate(StorageManagerDelegateInterface delegate)
+	{
+		if (delegate==null)
+			delegate=new DefaultStorageManagerDelegate();
+		StorageManager.delegate = delegate;
+	}
+
 	/**
 	 * @param dir
 	 * @return
@@ -318,7 +360,7 @@ public class StorageManager
 		catch (InvalidXMLException e) // incl. FileNotFoundExc
 		{
 			Log.log.warning("Invalid workflow in directory: " + dir.getName() + ": "
-			                + (e.getMessage() != null ? e.getMessage() : "<unknown reason>\n"));
+			                + (e.getMessage() != null ? e.getMessage() : "<unknown reason>"));
 		}
 		return null;
 	}
@@ -636,6 +678,22 @@ public class StorageManager
 		return result;
 	}
 
+	/**
+	 * Asks the delegate whether an unknown result should be accepted. A result is considered as unknown if
+	 * {@link #getResult(WorkflowID, ExecutionID)} returns {@code null} for its execution- and workflow-ids.
+	 * When the result is already known by the storage manager, this methods return {@code true}.
+	 * 
+	 * @param result
+	 *            the result to test
+	 * @return {@code true} if the result is accepted.
+	 */
+	protected static boolean acceptResult(Result result)
+	{
+		if (getResult(result.workflowID(), result.executionID()) == null)
+			return delegate.acceptUnknownResult(result);
+		return true;
+	}
+
 	/**
 	 * Stores the supplied result in the persistent store.
 	 * @param result the stored result
@@ -855,6 +913,11 @@ public class StorageManager
 			Log.log.severe("Received a null result!?!");
 			return;
 		}
+		if (!acceptResult(result))
+		{
+			Log.log.info("Rejecting unknown result "+result);
+			return;
+		}
 		try
         {
 	        updateResult(result, event.file_conveyor);
@@ -879,6 +942,11 @@ public class StorageManager
 		
 		for (Result result: results)
 		{
+			if (!acceptResult(result))
+			{
+				Log.log.info("Rejecting unknown result "+result);
+				continue;
+			}
 			switch (result.getStatus())
 			{
 				case CANCELLED:
@@ -918,6 +986,11 @@ public class StorageManager
 			Log.log.severe("Received a null result!?!");
 			return;
 		}
+		if (!acceptResult(result))
+		{
+			Log.log.info("Rejecting unknown result "+result);
+			return;
+		}
 		try
         {
 	        updateResult(result, event.file_conveyor);
diff --git a/src/eu/telecom_bretagne/praxis/common/ReleaseInfo.java b/src/eu/telecom_bretagne/praxis/common/ReleaseInfo.java
index 052c0a9a384a5f3fadb63a7a1001858473225ebf..c70977117f31efc679832f89c2b73617bebf3875 100644
--- a/src/eu/telecom_bretagne/praxis/common/ReleaseInfo.java
+++ b/src/eu/telecom_bretagne/praxis/common/ReleaseInfo.java
@@ -7,15 +7,15 @@ package eu.telecom_bretagne.praxis.common;
  */
 public abstract class ReleaseInfo
 {
-	public static final String release              = "1.8.1";
+	public static final String release              = "1.9";
 
 	public static final int    revision             = 0;
 
 	public static final int    application_revision = Configuration.getInt("revision");
 
-	public static final String release_date         = "2012-11-23";
+	public static final String release_date         = "2013-02-19";
 
-	public static final String package_date         = "2012-11-23";
+	public static final String package_date         = "2013-02-19";
 
 	/**
 	 * Returns a array of three strings: the release, the application_revision number, and the release date
diff --git a/src/eu/telecom_bretagne/praxis/common/RemoteComponents.java b/src/eu/telecom_bretagne/praxis/common/RemoteComponents.java
index c54721a1b9f0a48189c0d7582daffcca4da25eea..f5ccd97f0ae15e0e9a653bd8ab114a9c5a0600d8 100644
--- a/src/eu/telecom_bretagne/praxis/common/RemoteComponents.java
+++ b/src/eu/telecom_bretagne/praxis/common/RemoteComponents.java
@@ -59,7 +59,7 @@ public class RemoteComponents
 	 * should be set to false as soon as possible, ideally at application startup.<br>
 	 * Setting this parameter does not reset the existing cache, if it exists; as a consequence, setting it to false
 	 * then reverting its value to true makes the component re-use any value previously cached.<br>
-	 * Callers should be careful when disabling the cached. It should not be disabled in a normal, standard praxis
+	 * Callers should be careful when disabling the cache. It should not be disabled in a normal, standard praxis
 	 * project, because many elements expects that the description returned by
 	 * {@link eu.telecom_bretagne.praxis.core.workflow.Program#getDescription() Program.getDescription()} is always the same objects. However,
 	 * there exists special contexts when this is needed, especially for applications working on the descriptions
diff --git a/src/eu/telecom_bretagne/praxis/common/Utile.java b/src/eu/telecom_bretagne/praxis/common/Utile.java
index 118255253314eb7fe28e6863008e03ad1180aa0d..e66d78adc278021a54d186b1fdbbda6d8e3925c9 100644
--- a/src/eu/telecom_bretagne/praxis/common/Utile.java
+++ b/src/eu/telecom_bretagne/praxis/common/Utile.java
@@ -1,6 +1,7 @@
 /* License: please refer to the file README.license located at the root directory of the project */
 package eu.telecom_bretagne.praxis.common;
 
+import java.awt.Desktop;
 import java.io.BufferedInputStream;
 import java.io.BufferedReader;
 import java.io.ByteArrayInputStream;
@@ -17,6 +18,7 @@ import java.io.ObjectOutputStream;
 import java.io.OutputStream;
 import java.io.Reader;
 import java.io.StringWriter;
+import java.net.URI;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Comparator;
@@ -934,6 +936,79 @@ public class Utile
 		return null;
 	}
 	
+	/**
+	 * Tests whether the method {@link #browse(URI)} is supported on the current platform.
+	 * @return {@code true} if the method {@link #browse(URI)} is supported
+	 */
+	public static boolean isBrowseSupported()
+	{
+		if (!org.apache.commons.lang.SystemUtils.IS_OS_LINUX)
+			return Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE);
+		File url_open = searchSystemPath("xdg-open");
+		if (url_open==null)
+			url_open = searchSystemPath("gnome-open");
+		return ( (url_open != null && url_open.canExecute())
+				|| Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE) );
+	}
+
+	/**
+	 * Opens an URI in the default browser. This method basically calls {@link Desktop#browse(URI)}, except on Linux
+	 * where it tries to open it with {@code xdg-open} and {@code gnome-open}. Reason is that on Linux, Desktop.browse()
+	 * uses a different browser when the URI points to a local file (URI starting with {@code file://}), while
+	 * {@code xdg-open} and {@code gnome-open} opens such URI with the default web browser (the same as the one
+	 * used when the URI starts with {@code http://} or {@code https://}).
+	 * 
+	 * @param uri
+	 *            the URI to open in the default browser
+	 * @return {@code true} if the URI could be opened
+	 * @see #isBrowseSupported()
+	 */
+	public static boolean browse(URI uri)
+	{
+		if (!org.apache.commons.lang.SystemUtils.IS_OS_LINUX)
+		{
+			try
+            {
+	            java.awt.Desktop.getDesktop().browse(uri);
+            }
+            catch (IOException e)
+            {
+            	return false;
+            }
+			return true;
+		}
+		// Linux
+		/*
+		 * Desktop.browse() calls gnome_open_url() which behaves differently for http:// or file://, while
+		 * xdg-open does not (and neither does gnome-open).
+		 */
+		File url_open = searchSystemPath("xdg-open");
+		if (url_open==null)
+			url_open = searchSystemPath("gnome-open");
+		if (url_open==null)
+		{
+			try
+			{
+				java.awt.Desktop.getDesktop().browse(uri);
+			}
+			catch (IOException e)
+			{
+				return false;
+			}
+			return true;
+		}
+		try
+        {
+	        Runtime.getRuntime().exec(new String[]{url_open.toString(),uri.toString()});
+        }
+        catch (IOException e)
+        {
+	        e.printStackTrace();
+			return false;
+        }
+		return true;
+	}
+	
 	/**
 	 * Determines whether a program is registered within the Windows registry, and returns a array suitable for
 	 * executing it by creating a {@link ProcessBuilder}. The method searches if the program is declared in the
diff --git a/src/eu/telecom_bretagne/praxis/core/execution/WorkflowPlanner.java b/src/eu/telecom_bretagne/praxis/core/execution/WorkflowPlanner.java
index c8e5802ea7f3cea861523287a26e9781945b7c54..b29639df81fd8cb287e74f503e101ab017e57343 100644
--- a/src/eu/telecom_bretagne/praxis/core/execution/WorkflowPlanner.java
+++ b/src/eu/telecom_bretagne/praxis/core/execution/WorkflowPlanner.java
@@ -5,7 +5,7 @@ import java.io.ByteArrayInputStream;
 import java.util.ArrayList;
 
 import eu.telecom_bretagne.praxis.common.InvalidXMLException;
-import eu.telecom_bretagne.praxis.core.execution.ActivityContext;
+import eu.telecom_bretagne.praxis.common.Log;
 import eu.telecom_bretagne.praxis.core.workflow.Program;
 import eu.telecom_bretagne.praxis.core.workflow.Workflow;
 import eu.telecom_bretagne.praxis.server.Serveur;
@@ -63,6 +63,21 @@ public class WorkflowPlanner
 			activity.getExecutionSet().add(program);
 		}
 
+		// log details on the workflow being executed
+		try
+		{
+			StringBuffer log = new StringBuffer("Executing WF ");
+			log.append(workflow.id().dumpID()).append(":");
+			for (Program program: workflow.getPrograms())
+			{
+				log.append(" ").append(program.getDescription().id());
+			}
+			Log.log.info(log.toString());
+		}
+		catch (Throwable t)
+		{
+			Log.log.log(java.util.logging.Level.WARNING, "Unable to log info on the execution", t);
+		}
 	}
 
 	/**
diff --git a/src/eu/telecom_bretagne/praxis/server/Serveur.java b/src/eu/telecom_bretagne/praxis/server/Serveur.java
index 4982bf92227bb648ba9d8f44a404b67e778ff339..656bb11fdd3a7c21bcbbe5b97b45a01770875acc 100644
--- a/src/eu/telecom_bretagne/praxis/server/Serveur.java
+++ b/src/eu/telecom_bretagne/praxis/server/Serveur.java
@@ -9,6 +9,8 @@ import java.rmi.RemoteException;
 import java.rmi.server.UnicastRemoteObject;
 import java.sql.Connection;
 import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.sql.Statement;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -25,11 +27,11 @@ import eu.telecom_bretagne.praxis.common.Configuration;
 import eu.telecom_bretagne.praxis.common.Console;
 import eu.telecom_bretagne.praxis.common.Facade_xml;
 import eu.telecom_bretagne.praxis.common.FileResources;
+import eu.telecom_bretagne.praxis.common.FileResources.ResourceNotFoundException;
 import eu.telecom_bretagne.praxis.common.InvalidXMLException;
 import eu.telecom_bretagne.praxis.common.Log;
 import eu.telecom_bretagne.praxis.common.PraxisPreferences;
 import eu.telecom_bretagne.praxis.common.RemoteComponents;
-import eu.telecom_bretagne.praxis.common.FileResources.ResourceNotFoundException;
 import eu.telecom_bretagne.praxis.common.events.RMICommunicationFacade;
 import eu.telecom_bretagne.praxis.common.events.SSLSocketCommunicationFacade;
 import eu.telecom_bretagne.praxis.common.events.SocketCommunicationFacade;
@@ -47,6 +49,13 @@ import eu.telecom_bretagne.praxis.server.execution.platform.PlatformDescription;
  */
 public class Serveur extends UnicastRemoteObject implements RemoteServerInterface, ApplicationListener
 {
+	/**
+	 * This is used to log the number of clients connected, when a client {@link #registerClient(Client) connects} or
+	 * {@link #removeClient(Client) disconnects}. This may be used by an external tool to monitor the number of
+	 * connected users by examining the logs.
+	 */
+	public static final String NUMBER_OF_CLIENTS_CURRENTLY_CONNECTED = "Number of clients currently connected: ";
+
 	private static final long serialVersionUID = 6870908801969839494L;
 
 	/**
@@ -97,6 +106,17 @@ public class Serveur extends UnicastRemoteObject implements RemoteServerInterfac
 			{
 				c.createStatement().execute(ResultStore.RESULT_db_schema);
 			}
+			try
+			{
+				final Statement statement = c.createStatement();
+				statement.execute("PRAGMA synchronous = NORMAL;");
+				statement.execute("PRAGMA journal_mode=WAL;");
+				statement.close();
+			}
+			catch(SQLException e)
+			{
+				Log.log.log(Level.WARNING, "Unable to set journal_mode to WAL w/ synchronous=normal", e);
+			}
 			resultStore = new ResultStore(c);
 		}
 		catch (Exception e)
@@ -226,6 +246,7 @@ public class Serveur extends UnicastRemoteObject implements RemoteServerInterfac
 			
 			Log.log.fine("Registered client: " + client.toString());
 			clients.add(client);
+			Log.log.info(NUMBER_OF_CLIENTS_CURRENTLY_CONNECTED+clients.size());
 		}
 		/* now that the client is registered, messages can be sent safely */
 		clientConnected(client);
@@ -266,7 +287,7 @@ public class Serveur extends UnicastRemoteObject implements RemoteServerInterfac
 			Log.log.fine("Unregistering client: null");
 		
 		boolean ret_status = clients.remove(client);
-		Log.log.info("Number of clients currently connected: "+clients.size());
+		Log.log.info(NUMBER_OF_CLIENTS_CURRENTLY_CONNECTED+clients.size());
 		if (Configuration.getBoolean("server.exit_on_last_client_exit") && clients.size()==0)
 		{
 			for (Server platform: platforms)