From 6c18ce78d6b238d210cae1a1aa16afba76deed61 Mon Sep 17 00:00:00 2001
From: Christophe Geuzaine <cgeuzaine@ulg.ac.be>
Date: Thu, 4 Oct 2012 16:07:05 +0000
Subject: [PATCH] merge onelab project into contrib/

---
 CMakeLists.txt                   |    7 +
 Common/GmshConfig.h.in           |    1 +
 Common/GmshMessage.cpp           |   20 +-
 Common/GmshMessage.h             |    1 +
 Common/OpenFile.cpp              |    7 +
 Fltk/onelabWindow.cpp            |  117 ++-
 Fltk/onelabWindow.h              |    2 +
 contrib/onelab/CMakeLists.txt    |   14 +
 contrib/onelab/OnelabClients.cpp | 1071 ++++++++++++++++++++++++
 contrib/onelab/OnelabClients.h   |  316 +++++++
 contrib/onelab/OnelabMessage.cpp |  664 +++++++++++++++
 contrib/onelab/OnelabMessage.h   |  132 +++
 contrib/onelab/OnelabParser.cpp  | 1344 ++++++++++++++++++++++++++++++
 contrib/onelab/loader.cpp        |  264 ++++++
 contrib/onelab/metamodel.cpp     |   56 ++
 contrib/onelab/metamodel.h       |    6 +
 16 files changed, 3991 insertions(+), 31 deletions(-)
 create mode 100644 contrib/onelab/CMakeLists.txt
 create mode 100644 contrib/onelab/OnelabClients.cpp
 create mode 100644 contrib/onelab/OnelabClients.h
 create mode 100644 contrib/onelab/OnelabMessage.cpp
 create mode 100644 contrib/onelab/OnelabMessage.h
 create mode 100644 contrib/onelab/OnelabParser.cpp
 create mode 100644 contrib/onelab/loader.cpp
 create mode 100644 contrib/onelab/metamodel.cpp
 create mode 100644 contrib/onelab/metamodel.h

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 859bbc7f0d..afe0f732ee 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -53,6 +53,7 @@ option(ENABLE_NATIVE_FILE_CHOOSER "Enable native file chooser in GUI" ${DEFAULT}
 option(ENABLE_NETGEN "Enable Netgen mesh generator" ${DEFAULT})
 option(ENABLE_OCC "Enable Open CASCADE geometrical models" ${DEFAULT})
 option(ENABLE_ONELAB "Enable OneLab solver interface" ${DEFAULT})
+option(ENABLE_ONELAB_METAMODEL "Enable OneLab metamodel" ${DEFAULT})
 option(ENABLE_OSMESA "Use OSMesa for offscreen rendering" OFF)
 option(ENABLE_PARSER "Build the GEO file parser" ${DEFAULT})
 option(ENABLE_PETSC "Enable PETSc linear algebra solvers" ${DEFAULT})
@@ -902,6 +903,12 @@ if(ENABLE_ONELAB)
   set_config_option(HAVE_ONELAB "OneLab")
 endif(ENABLE_ONELAB)
 
+if(ENABLE_ONELAB_METAMODEL)
+  add_subdirectory(contrib/onelab)
+  include_directories(contrib/onelab)
+  set_config_option(HAVE_ONELAB_METAMODEL "OneLabMetamodel")
+endif(ENABLE_ONELAB_METAMODEL)
+
 check_function_exists(vsnprintf HAVE_VSNPRINTF)
 if(NOT HAVE_VSNPRINTF)
   set_config_option(HAVE_NO_VSNPRINTF "NoVsnprintf")
diff --git a/Common/GmshConfig.h.in b/Common/GmshConfig.h.in
index 0248ac92b9..c83a17dc8d 100644
--- a/Common/GmshConfig.h.in
+++ b/Common/GmshConfig.h.in
@@ -43,6 +43,7 @@
 #cmakedefine HAVE_NO_VSNPRINTF
 #cmakedefine HAVE_OCC
 #cmakedefine HAVE_ONELAB
+#cmakedefine HAVE_ONELAB_METAMODEL
 #cmakedefine HAVE_OPENGL
 #cmakedefine HAVE_OSMESA
 #cmakedefine HAVE_PARSER
diff --git a/Common/GmshMessage.cpp b/Common/GmshMessage.cpp
index 523c34b93e..2824dc42cb 100644
--- a/Common/GmshMessage.cpp
+++ b/Common/GmshMessage.cpp
@@ -16,6 +16,7 @@
 #include "GModel.h"
 #include "Options.h"
 #include "Context.h"
+#include "OpenFile.h"
 #include "OS.h"
 
 #if defined(HAVE_ONELAB)
@@ -660,12 +661,25 @@ void Msg::SetOnelabString(std::string name, std::string val, bool visible)
   }
 }
 
+class localGmsh : public onelab::localClient {
+public:
+  localGmsh() : onelab::localClient("Gmsh") {}
+  void sendMergeFileRequest(const std::string &msg)
+  {
+    MergePostProcessingFile(msg, CTX::instance()->solver.autoShowLastStep,
+                            CTX::instance()->solver.autoHideNewViews, true);
+  }
+  void sendInfo(const std::string &msg){ Msg::Info("%s", msg.c_str()); }
+  void sendWarning(const std::string &msg){ Msg::Warning("%s", msg.c_str()); }
+  void sendError(const std::string &msg){ Msg::Error("%s", msg.c_str()); }
+};
+
 void Msg::InitializeOnelab(const std::string &name, const std::string &sockname)
 {
 #if defined(HAVE_ONELAB)
   if(_onelabClient) delete _onelabClient;
   if(sockname.empty()){
-    _onelabClient = new onelab::localClient("Gmsh");
+    _onelabClient = new localGmsh();
     if(name != "Gmsh"){ // load db from file:
       if(!_onelabClient->fromFile(name))
         Error("Error loading onelab database '%s'", name.c_str());
@@ -796,9 +810,6 @@ void Msg::ImportPhysicalsAsOnelabRegions()
   if(_onelabClient){
     std::map<int, std::vector<GEntity*> > groups[4];
     GModel::current()->getPhysicalGroups(groups);
-    // FIXME 
-    // for(int dim = 0; dim < 3; dim++) is clearly a mistake
-    // should the loop start at dim=0 or dim=1?
     for(int dim = 0; dim <= 3; dim++){
       for(std::map<int, std::vector<GEntity*> >::iterator it = groups[dim].begin();
           it != groups[dim].end(); it++){
@@ -814,6 +825,7 @@ void Msg::ImportPhysicalsAsOnelabRegions()
         onelab::region p(name, num.str());
         p.setDimension(dim);
         p.setReadOnly(true);
+        p.setAttribute("Closed", "1");
         _onelabClient->set(p);
       }
     }
diff --git a/Common/GmshMessage.h b/Common/GmshMessage.h
index a1ee370189..4a65a163e1 100644
--- a/Common/GmshMessage.h
+++ b/Common/GmshMessage.h
@@ -84,6 +84,7 @@ class Msg {
                        const char *one, const char *two=0);
   static void InitializeOnelab(const std::string &name, const std::string &sockname="");
   static GmshClient *GetGmshClient(){ return _client; }
+  static onelab::client *GetOnelabClient(){ return _onelabClient; }
   static void FinalizeOnelab();
   static bool UseOnelab();
   static void SetOnelabNumber(std::string name, double val, bool visible);
diff --git a/Common/OpenFile.cpp b/Common/OpenFile.cpp
index 23b2be1348..da305a1482 100644
--- a/Common/OpenFile.cpp
+++ b/Common/OpenFile.cpp
@@ -37,6 +37,7 @@
 #if defined(HAVE_FLTK)
 #include <FL/fl_ask.H>
 #include "FlGui.h"
+#include "onelabWindow.h"
 #include "menuWindow.h"
 #include "drawContext.h"
 #endif
@@ -372,6 +373,12 @@ int MergeFile(const std::string &fileName, bool warnIfMissing)
   else if(ext == ".csv"){
     status = readFile3M(fileName);
   }
+#endif
+#if defined(HAVE_ONELAB_METAMODEL)
+  else if(ext == ".ol"){
+    // TODO: allow passing action to metamodel from command line
+    status = metamodel_cb(fileName);
+  }
 #endif
   else {
     CTX::instance()->geom.draw = 1;
diff --git a/Fltk/onelabWindow.cpp b/Fltk/onelabWindow.cpp
index 2518585f94..05fb3abf04 100644
--- a/Fltk/onelabWindow.cpp
+++ b/Fltk/onelabWindow.cpp
@@ -11,6 +11,10 @@
 #include "onelab.h"
 #endif
 
+#if defined(HAVE_ONELAB_METAMODEL)
+#include "metamodel.h"
+#endif
+
 #if defined(HAVE_ONELAB) && (FL_MAJOR_VERSION == 1) && (FL_MINOR_VERSION == 3)
 
 #include <FL/Fl_Check_Button.H>
@@ -402,6 +406,24 @@ static void saveDb(const std::string &fileName, bool withTimeStamp=false)
     //       rename(old, new); on disk (in stdio.h)
     // need to detect if a file is already stamped. We could simply check the
     // sequence of _ - - - _ - - - . characters for this.
+    std::vector<onelab::string> strings;
+    onelab::server::instance()->get(strings);
+    for(unsigned int i = 0; i < strings.size(); i++){
+      if(strings[i].getName().find("Output files") != std::string::npos){
+        for(unsigned int j = 0; j < strings[i].getChoices().size(); j++){
+          std::vector<std::string> split = SplitFileName(strings[i].getChoices()[j]);
+          int n = split[1].size();
+          if(n > 18 &&
+             split[1][n-3] == '-' && split[1][n-6] == '-' && split[1][n-9] == '_' &&
+             split[1][n-12] == '-' && split[1][n-15] == '-' && split[1][n-18] == '_'){
+            printf("already stamped! %s\n", strings[i].getChoices()[j].c_str());
+          }
+          else{
+            printf("renaming %s\n", strings[i].getChoices()[j].c_str());
+          }
+        }
+      }
+    }
   }
 
   Msg::StatusBar(2, true, "Saving database '%s'...", name.c_str());
@@ -501,14 +523,15 @@ void onelab_cb(Fl_Widget *w, void *data)
 
   if(action == "compute") initializeLoops();
 
+  // check whether we are running a metamodel
+  std::vector<onelab::number> n;
+  onelab::server::instance()->get(n, "IsMetamodel");
+  bool isMetamodel = (n.size() && n[0].getValue());
+
   do{ // enter loop
 
-    // check whether the client is a onelab Metamodel
-    std::vector<onelab::number> n;
-    onelab::server::instance()->get(n, "HasGmsh");
-    bool metamodel = (n.size() && n[0].getValue());
     // if the client is a not a metamodel, run Gmsh
-    if(!metamodel){
+    if(!isMetamodel){
       if(onelabUtils::runGmshClient(action, CTX::instance()->solver.autoMesh))
         drawContext::global()->draw();
     }
@@ -517,31 +540,32 @@ void onelab_cb(Fl_Widget *w, void *data)
       FlGui::instance()->onelab->checkForErrors("Gmsh");
     if(FlGui::instance()->onelab->stop()) break;
 
-    // iterate over all other clients (there should narmally only be one)
-    for(onelab::server::citer it = onelab::server::instance()->firstClient();
-        it != onelab::server::instance()->lastClient(); it++){
-      onelab::client *c = it->second;
-      if(c->getName() == "Gmsh" || // local Gmsh client
-         c->getName() == "Listen" || // unknown client connecting through "-listen"
-         c->getName() == "GmshRemote") // distant post-processing Gmsh client
-        continue;
-      if(action != "initialize") onelabUtils::guessModelName(c);
-      onelab::string o(c->getName() + "/Action", action);
-      o.setVisible(false);
-      onelab::server::instance()->set(o);
-      c->run();
-      if(action == "compute"){
-        FlGui::instance()->onelab->checkForErrors(c->getName());
-	if(metamodel)
-	  onelab::server::instance()->setChanged(false,c->getName());
+    if(isMetamodel){
+#if defined(HAVE_ONELAB_METAMODEL)
+      metamodel(action);
+#endif
+    }
+    else{
+      // iterate over all other clients (there should narmally only be one)
+      for(onelab::server::citer it = onelab::server::instance()->firstClient();
+          it != onelab::server::instance()->lastClient(); it++){
+        onelab::client *c = it->second;
+        if(c->getName() == "Gmsh" || // local Gmsh client
+           c->getName() == "Listen" || // unknown client connecting through "-listen"
+           c->getName() == "GmshRemote") // distant post-processing Gmsh client
+          continue;
+        if(action != "initialize") onelabUtils::guessModelName(c);
+        onelab::string o(c->getName() + "/Action", action);
+        o.setVisible(false);
+        onelab::server::instance()->set(o);
+        c->run();
+        if(action == "compute"){
+          FlGui::instance()->onelab->checkForErrors(c->getName());
+        }
+        if(FlGui::instance()->onelab->stop()) break;
       }
-      if(FlGui::instance()->onelab->stop()) break;
-
     }
 
-    // update geometry which might have been changed by the metamodel
-    if(metamodel) geometry_reload_cb(0, 0);
-
     if(action != "initialize"){
       updateGraphs();
       FlGui::instance()->onelab->rebuildTree();
@@ -1298,6 +1322,39 @@ void solver_cb(Fl_Widget *w, void *data)
     onelab_cb(0, (void*)"check");
 }
 
+int metamodel_cb(const std::string &name, const std::string &action)
+{
+#if defined(HAVE_ONELAB_METAMODEL)
+  Msg::ResetErrorCounter();
+  if(FlGui::instance()->onelab->isBusy())
+    FlGui::instance()->onelab->show();
+  else{
+    initializeMetamodel(Msg::GetOnelabClient());
+
+    onelab::number n("IsMetamodel", 1.);
+    n.setVisible(false);
+    onelab::server::instance()->set(n);
+    std::vector<std::string> split = SplitFileName(name);
+    onelab::string s1("Arguments/WorkingDir", split[0]);
+    s1.setVisible(false);
+    onelab::server::instance()->set(s1);
+    onelab::string s2("Arguments/FileName", split[1]);
+    s2.setVisible(false);
+    onelab::server::instance()->set(s2);
+
+    FlGui::instance()->onelab->rebuildSolverList();
+
+    if(FlGui::instance()->available())
+      onelab_cb(0, (void*)"check");
+    else
+      metamodel(action);
+  }
+  return 1;
+#else
+  return 0;
+#endif
+}
+
 #else
 
 #if defined(HAVE_ONELAB)
@@ -1321,4 +1378,10 @@ void solver_cb(Fl_Widget *w, void *data)
   Msg::Error("The solver interface requires OneLab and FLTK 1.3");
 }
 
+int metamodel_cb(const std::string &name, const std::string &action)
+{
+  Msg::Error("Metamodels require OneLab and FLTK 1.3");
+  return 0;
+}
+
 #endif
diff --git a/Fltk/onelabWindow.h b/Fltk/onelabWindow.h
index 38024e39f4..58fcb7f04c 100644
--- a/Fltk/onelabWindow.h
+++ b/Fltk/onelabWindow.h
@@ -14,6 +14,7 @@
 #include <FL/Fl_Window.H>
 #include <FL/Fl_Tree.H>
 #include <FL/Fl_Button.H>
+#include <FL/Fl_Menu_Button.H>
 #include <FL/Fl_Input.H>
 #include "onelab.h"
 
@@ -70,5 +71,6 @@ void onelab_cb(Fl_Widget *w, void *data);
 #endif
 
 void solver_cb(Fl_Widget *w, void *data);
+int metamodel_cb(const std::string &name, const std::string &action="");
 
 #endif
diff --git a/contrib/onelab/CMakeLists.txt b/contrib/onelab/CMakeLists.txt
new file mode 100644
index 0000000000..a1953f75f3
--- /dev/null
+++ b/contrib/onelab/CMakeLists.txt
@@ -0,0 +1,14 @@
+# Gmsh - Copyright (C) 1997-2012 C. Geuzaine, J.-F. Remacle
+#
+# See the LICENSE.txt file for license information. Please report all
+# bugs and problems to <gmsh@geuz.org>.
+
+set(SRC
+  OnelabClients.cpp 
+  OnelabMessage.cpp
+  OnelabParser.cpp
+  metamodel.cpp
+)
+
+file(GLOB_RECURSE HDR RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.hxx)
+append_gmsh_src(contrib/onelab "${SRC};${HDR}")
diff --git a/contrib/onelab/OnelabClients.cpp b/contrib/onelab/OnelabClients.cpp
new file mode 100644
index 0000000000..3bc2772117
--- /dev/null
+++ b/contrib/onelab/OnelabClients.cpp
@@ -0,0 +1,1071 @@
+#include "OnelabMessage.h"
+#include "OnelabClients.h"
+#include "StringUtils.h"
+#include <algorithm>
+
+
+class onelabMetaModelServer : public GmshServer{
+ private:
+  localNetworkSolverClient *_client;
+ public:
+  onelabMetaModelServer(localNetworkSolverClient *client)
+    : GmshServer(), _client(client) {}
+  ~onelabMetaModelServer(){}
+  int NonBlockingSystemCall(const char *command)
+  {
+#if defined(WIN32)
+    STARTUPINFO suInfo;
+    PROCESS_INFORMATION prInfo;
+    memset(&suInfo, 0, sizeof(suInfo));
+    suInfo.cb = sizeof(suInfo);
+    std::string cmd(command);
+    OLMsg::Info("Calling <%s>", cmd.c_str());
+    // DETACHED_PROCESS removes the console (useful if the program to launch is
+    // a console-mode exe)
+    CreateProcess(NULL,(char *)cmd.c_str(), NULL, NULL, FALSE,
+		  NORMAL_PRIORITY_CLASS|DETACHED_PROCESS, NULL, NULL,
+		  &suInfo, &prInfo);
+    return 0;
+#else
+    if(!system(NULL)) {
+      OLMsg::Error("Could not find /bin/sh: aborting system call");
+      return 1;
+    }
+    std::string cmd(command);
+    int pos;
+    if((pos=cmd.find("incomp_ssh ")) != std::string::npos){
+      cmd.assign(cmd.substr(pos+7));  // remove "incomp_"
+      cmd.append(" & '");
+    }
+    else
+      cmd.append(" & ");
+
+    OLMsg::Info("Calling <%s>", cmd.c_str());
+    return system(cmd.c_str());
+#endif
+  }// non blocking
+  int NonBlockingWait(int socket, double waitint, double timeout)
+  {
+    double start = GetTimeInSeconds();
+    while(1){
+      if(timeout > 0 && GetTimeInSeconds() - start > timeout)
+        return 2; // timout
+      // if(_client->getPid() < 0 || (_client->getCommandLine().empty() &&
+      //                              !CTX::instance()->solver.listen))
+      if(_client->getPid() < 0 || (_client->getCommandLine().empty()))
+        return 1; // process has been killed or we stopped listening
+      // check if there is data (call select with a zero timeout to
+      // return immediately, i.e., do polling)
+      int ret = Select(0, 0, socket);
+      if(ret == 0){ // nothing available
+        // if asked, refresh the onelab GUI
+        std::vector<onelab::string> ps;
+        onelab::server::instance()->get(ps, "Gmsh/Action");
+        if(ps.size() && ps[0].getValue() == "refresh"){
+          ps[0].setVisible(false);
+          ps[0].setValue("");
+          onelab::server::instance()->set(ps[0]);
+          //onelab_cb(0, (void*)"refresh");
+        }
+        // wait at most waitint seconds and respond to FLTK events
+        //FlGui::instance()->wait(waitint);
+      }
+      else if(ret > 0){
+        return 0; // data is there!
+      }
+      else{
+        // an error happened
+        _client->setPid(-1);
+        _client->setGmshServer(0);
+        return 1;
+      }
+    }
+  }
+};
+
+std::string localNetworkSolverClient::buildCommandLine(){
+  std::string command;
+  command.assign("");
+  if(!getWorkingDir().empty())
+    command.append("cd " + getWorkingDir() + cmdSep);
+  command.append(FixWindowsPath(getCommandLine()));
+  return command;
+}
+
+std::string localNetworkSolverClient::appendArguments(){
+
+  std::string action = getString("Action");
+  std::string checkCommand = getString("9CheckCommand");
+  std::string computeCommand = getString("9ComputeCommand");
+
+  std::string command;
+  if(action == "initialize"){
+    command.assign(" " + getSocketSwitch() + " " + getName() + " %s");
+  }
+  else if(action == "check") {
+    command.assign(" " + getString("Arguments") + " " + checkCommand) ;
+    command.append(" " + getSocketSwitch() + " " + getName() + " %s");
+  }
+  else if(action == "compute"){
+    command.assign(" " + getString("Arguments") + " " + computeCommand);
+    command.append(" " + getSocketSwitch() + " " + getName() + " %s");
+  }
+  else
+    OLMsg::Fatal("buildCommandLine: Unknown Action <%s>", action.c_str());
+  return command;
+}
+
+bool localNetworkSolverClient::run()
+{
+ new_connection:
+  _pid = 0;
+  _gmshServer = 0;
+
+  onelabMetaModelServer *server = new onelabMetaModelServer(this);
+
+#if defined(WIN32)
+  std::string socketName = ":";
+#else
+  std::string socketName;
+  if(getRemote())
+    socketName = ":";
+  else
+    socketName = getUserHomedir() + ".gmshsock";
+#endif
+
+  std::string sockname;
+  std::ostringstream tmp;
+  if(!strstr(socketName.c_str(), ":")){
+    // Unix socket
+    tmp << socketName << getId();
+    sockname = FixWindowsPath(tmp.str());
+  }
+  else{
+    // TCP/IP socket
+    if(socketName.size() && socketName[0] == ':')
+      // prepend hostname if only the port number is given
+      tmp << GetHostName();
+    tmp << socketName ;
+    sockname = tmp.str();
+  }
+
+  std::string command = buildCommandLine();
+  if(command.size()) command.append(appendArguments());
+
+  // std::cout << "sockname=<" << sockname << ">" << std::endl;
+  // std::cout << "command=<" << command << ">" << std::endl;
+
+  int sock;
+  try{
+    sock = server->Start(command.c_str(), sockname.c_str(), 10);
+  }
+  catch(const char *err){
+    OLMsg::Error("%s (on socket '%s')", err, sockname.c_str());
+    sock = -1;
+  }
+
+  if(sock < 0){
+    server->Shutdown();
+    delete server;
+    return false;
+  }
+
+  OLMsg::StatusBar(2, true, "Now running client <%s>", _name.c_str());
+
+  while(1) {
+    if(_pid < 0) break;
+
+    int stop = server->NonBlockingWait(sock, 0.1, 0.);
+    if(stop || _pid < 0) {
+      OLMsg::Info("Stop=%d _pid=%d",stop, _pid);
+      break;
+    }
+    int type, length, swap;
+    if(!server->ReceiveHeader(&type, &length, &swap)){
+      OLMsg::Error("Did not receive message header: stopping server");
+      break;
+    }
+     // else
+     //   std::cout << "FHF: Received header=" << type << std::endl;
+
+    std::string message(length, ' ');
+    if(!server->ReceiveMessage(length, &message[0])){
+      OLMsg::Error("Did not receive message body: stopping server");
+      break;
+    }
+    // else
+    //   std::cout << "FHF: Received message=" << message << std::endl;
+
+    switch (type) {
+    case GmshSocket::GMSH_START:
+      _pid = atoi(message.c_str());
+      _gmshServer = server;
+      break;
+    case GmshSocket::GMSH_STOP:
+      _pid = -1;
+      _gmshServer = 0;
+      break;
+    case GmshSocket::GMSH_PARAMETER:
+      {
+        std::string version, type, name;
+        onelab::parameter::getInfoFromChar(message, version, type, name);
+        if(onelab::parameter::version() != version){
+          OLMsg::Error("OneLab version mismatch for %s (server: %s / client: %s)",
+	   message.c_str(), onelab::parameter::version().c_str(), version.c_str());
+        }
+        if(type == "number"){
+          onelab::number p; p.fromChar(message); set(p);
+        }
+        else if(type == "string"){
+          onelab::string p; p.fromChar(message); set(p);
+        }
+	else if(type == "region"){
+          onelab::region p; p.fromChar(message); set(p);
+        }
+        else if(type == "function"){
+          onelab::function p; p.fromChar(message); set(p);
+        }
+        else
+          OLMsg::Fatal("FIXME query not done for this parameter type: <%s>",
+		     message.c_str());
+      }
+      break;
+    case GmshSocket::GMSH_PARAMETER_QUERY:
+      {
+        std::string version, type, name, reply;
+        onelab::parameter::getInfoFromChar(message, version, type, name);
+        if(onelab::parameter::version() != version){
+          OLMsg::Error("OneLab version mismatch for %s (server: %s / client: %s)",
+	   message.c_str(), onelab::parameter::version().c_str(), version.c_str());
+        }
+        else if(type == "number"){
+          std::vector<onelab::number> par; get(par, name);
+          if(par.size() == 1) reply = par[0].toChar();
+	}
+        else if(type == "string"){
+          std::vector<onelab::string> par; get(par, name);
+          if(par.size() == 1) reply = par[0].toChar();
+        }
+        else if(type == "region"){
+          std::vector<onelab::region> par; get(par, name);
+          if(par.size() == 1) par[0].toChar();
+        }
+        else if(type == "function"){
+          std::vector<onelab::function> par; get(par, name);
+          if(par.size() == 1) reply = par[0].toChar();
+        }
+        else
+          OLMsg::Error("Unknown OneLab parameter type in query: %s",
+		     type.c_str());
+
+        if(reply.size()){
+          server->SendMessage(GmshSocket::GMSH_PARAMETER,
+			      reply.size(), &reply[0]);
+        }
+        else{
+          reply = "OneLab parameter '" + name + "' not found";
+          server->SendMessage(GmshSocket::GMSH_INFO, reply.size(), &reply[0]);
+        }
+      }
+      break;
+    case GmshSocket::GMSH_PARAM_QUERY_ALL:
+      {
+        std::string version, type, name, reply;
+        std::vector<std::string> replies;
+        onelab::parameter::getInfoFromChar(message, version, type, name);
+	if(onelab::parameter::version() != version){
+          OLMsg::Error("OneLab version mismatch for %s (server: %s / client: %s)",
+           message.c_str(), onelab::parameter::version().c_str(), version.c_str());
+        }
+	else if(type == "number"){
+	  std::vector<onelab::number> numbers; get(numbers);
+	  for(std::vector<onelab::number>::iterator it = numbers.begin();
+	      it != numbers.end(); it++) replies.push_back((*it).toChar());
+	}
+	else if(type == "string"){
+	  std::vector<onelab::string> strings; get(strings);
+	  for(std::vector<onelab::string>::iterator it = strings.begin();
+	      it != strings.end(); it++) replies.push_back((*it).toChar());
+	}
+        else if(type == "region"){
+	  std::vector<onelab::region> regions; get(regions);
+	  for(std::vector<onelab::region>::iterator it = regions.begin();
+              it != regions.end(); it++) replies.push_back((*it).toChar());
+        }
+        else if(type == "function"){
+	  std::vector<onelab::function> functions; get(functions);
+	  for(std::vector<onelab::function>::iterator it = functions.begin();
+              it != functions.end(); it++) replies.push_back((*it).toChar());
+        }
+        else
+          OLMsg::Error("Unknown OneLab parameter type in query: %s",
+		     type.c_str());
+
+        for(unsigned int i = 0; i < replies.size(); i++)
+          server->SendMessage(GmshSocket::GMSH_PARAM_QUERY_ALL,
+	     replies[i].size(), &replies[i][0]);
+        reply = "Sent all OneLab " + type + "s";
+        server->SendMessage(GmshSocket::GMSH_PARAM_QUERY_END,
+			    reply.size(), &reply[0]);
+      }
+      break;
+    case GmshSocket::GMSH_PROGRESS:
+      OLMsg::StatusBar(2, false, "%s %s", _name.c_str(), message.c_str());
+      break;
+    case GmshSocket::GMSH_INFO:
+      OLMsg::Direct("%-8.8s: %s", _name.c_str(), message.c_str());
+      break;
+    case GmshSocket::GMSH_WARNING:
+      OLMsg::Direct(2, "%-8.8s: %s", _name.c_str(), message.c_str());
+      break;
+    case GmshSocket::GMSH_ERROR:
+      //OLMsg::Direct(1, "%-8.8s: %s", _name.c_str(), message.c_str());
+      OLMsg::Fatal("%-8.8s: %s", _name.c_str(), message.c_str());
+      break;
+    case GmshSocket::GMSH_MERGE_FILE:
+      OLMsg::Info("Merge Post-Processing File %s",message.c_str());
+      SystemCall("gmsh "+ message);
+      //implémentation pour le cas du loader en mode console.
+      break;
+    default:
+      OLMsg::Warning("Received unknown message type (%d)", type);
+      break;
+    }
+  }
+
+  server->Shutdown();
+  delete server;
+  OLMsg::StatusBar(2, true, "Done running '%s'", _name.c_str());
+  return true;
+}
+
+bool localNetworkSolverClient::kill()
+{
+  if(_pid > 0) {
+    if(KillProcess(_pid)){
+      OLMsg::Info("Killed '%s' (pid %d)", _name.c_str(), _pid);
+      _pid = -1;
+      return true;
+    }
+  }
+  _pid = -1;
+  return false;
+}
+
+
+// client LOCALSOLVERCLIENT
+
+std::string localSolverClient::toChar(){
+  std::ostringstream sstream;
+  if(getCommandLine().size()){
+    sstream << getName() << "." << "commandLine("
+	    << getCommandLine() << ");\n";
+  }
+  return sstream.str();
+}
+
+void localSolverClient::setAction(const std::string action){
+  std::string name=getName() + "/Action";
+  onelab::string s(name, action);
+  s.setVisible(false);
+  set(s);
+}
+
+const std::string localSolverClient::getString(const std::string what){
+  std::vector<onelab::string> strings;
+  get(strings, getName() + "/" + what);
+  if(strings.size())
+    return strings[0].getValue();
+  else
+    return "";
+}
+
+const bool localSolverClient::getList(const std::string type, std::vector<std::string> &choices){
+  std::vector<onelab::string> strings;
+  get(strings, getName() + "/" + type);
+  if(strings.size()){
+    choices= strings[0].getChoices();
+    return true;
+  }
+  else
+    return false;
+}
+
+bool localSolverClient::checkCommandLine(){
+  OLMsg::Info("Check command line for <%s>",getName().c_str());
+  // if(getCommandLine().empty()){
+  //   // look if one has a commandLine on server
+  //   std::string commandLine = getString("CommandLine");
+
+  if(getCommandLine().empty())
+    OLMsg::Fatal("No commandline for client <%s>", getName().c_str());
+
+  if(!isActive()) return true;
+
+  if(!getCommandLine().empty()){
+    setAction("initialize");
+    run();
+  }
+  else{
+    if(OLMsg::hasGmsh) {
+      // exits metamodel and restores control to the onelab window
+      OLMsg::Error("The command line of client <%s> is undefined.",
+		 getName().c_str());
+      std::cout << "\n\nBrowse for executable in the ONELAB window.\n\n"
+		<< std::endl;
+      return false;
+    }
+    else{ // asks the user in console mode
+      std::cout << "\nONELAB:Enter the command line (with path) of the executable file of <" << getName() << ">" << std::endl;
+      std::string cmdl;
+      std::getline (std::cin,cmdl);
+      setCommandLine(cmdl);
+      return cmdl.size();
+    }
+  }
+  return true;
+}
+
+bool localSolverClient::buildRmCommand(std::string &cmd){
+  std::vector<std::string> choices;
+
+  cmd.assign("");
+  if(!getWorkingDir().empty())
+    cmd.append("cd " + getWorkingDir() + cmdSep);
+
+  if(getList("OutputFiles",choices)){
+#if defined(WIN32)
+    cmd.append("del ");
+#else
+    cmd.append("rm -rf ");
+#endif
+    for(unsigned int i = 0; i < choices.size(); i++)
+      cmd.append(choices[i]+" ");
+    return true;
+  }
+  else
+    return false;
+}
+
+void localSolverClient::PostArray(std::vector<std::string> choices)
+{
+  int nb=0;
+  while( 4*(nb+1) <= choices.size()){
+    //std::cout << "Nb Choices" << choices.size() << std::endl;
+    int lin= atof(choices[4*nb+1].c_str());
+    int col= atof(choices[4*nb+2].c_str());
+    std::string fileName = getWorkingDir()+choices[4*nb];
+      //checkIfPresent or make available locally
+    double val=find_in_array(lin,col,read_array(fileName,' '));
+    OLMsg::AddOnelabNumberChoice(choices[4*nb+3],val);
+    OLMsg::Info("Upload parameter <%s>=%e from file <%s>",
+		choices[4*nb+3].c_str(),val,fileName.c_str());
+    nb++;
+  }
+}
+
+void localSolverClient::GmshMerge(std::vector<std::string> choices)
+{
+  //if(!OLMsg::hasGmsh || choices.empty()) return;
+  for(unsigned int i = 0; i < choices.size(); i++){
+    if(!choices[i].empty()){
+      std::string fileName=getWorkingDir()+choices[i];
+      //checkIfPresent or make available locally
+      OLMsg::SendMergeFileRequest(fileName);
+      OLMsg::Info("Send merge request <%s>",fileName.c_str());
+    }
+  }
+}
+
+
+// REMOTE CLIENT
+
+bool remoteClient::checkCommandLine(const std::string &commandLine){
+  struct stat buf;
+  std::string cmd;
+  char cbuf [1024];
+  FILE *fp;
+
+  cmd.assign("ssh "+getRemoteHost()+" 'mkdir -p "+getRemoteDir()+"'");
+  mySystem(cmd);
+
+  cmd.assign("ssh "+getRemoteHost()+" 'which "+commandLine+"'");
+  fp = popen(cmd.c_str(), "r");
+  if(fgets(cbuf, 1024, fp) == NULL){
+    OLMsg::Warning("The executable <%s> does not exist",
+		 commandLine.c_str());
+    pclose(fp);
+    return false;
+  }
+  OLMsg::Info("The executable <%s> exists", commandLine.c_str());
+  pclose(fp);
+
+  return true;
+}
+
+bool remoteClient::checkIfPresentRemote(const std::string &fileName){
+  struct stat buf;
+  std::string cmd;
+  char cbuf [1024];
+  FILE *fp;
+
+  cmd.assign("ssh "+_remoteHost+" 'cd "+_remoteDir+"; ls "+fileName+" 2>/dev/null'");
+  //std::cout << "check remote<" << cmd << ">" << std::endl;
+  fp = popen(cmd.c_str(), "r");
+  if(fgets(cbuf, 1024, fp) == NULL){
+    OLMsg::Fatal("The file <%s> is not present", fileName.c_str());
+    pclose(fp);
+    return false;
+  }
+  OLMsg::Info("The file <%s> is present", fileName.c_str());
+  pclose(fp);
+  return true;
+}
+
+bool remoteClient::syncInputFile(const std::string &wdir, const std::string &fileName){
+  int pos;
+  std::string cmd;
+  if((pos=fileName.find(onelabExtension)) != std::string::npos){
+    // .ol file => local
+    // remove ext .ol
+    std::string trueName =
+      fileName.substr(fileName.find_first_not_of(" "),pos);
+    std::string fullName = wdir+trueName;
+    if(checkIfPresent(fullName)){
+      cmd.assign("rsync -e ssh -auv "+fullName+" "+_remoteHost+":"+_remoteDir+"/"+trueName);
+      return mySystem(cmd);
+    }
+    else{
+      OLMsg::Fatal("The input file <%s> is not present", fullName.c_str());
+      return false;
+    }
+  }
+  else { // not a .ol file, apply the . rule
+    if(!fileName.compare(fileName.find_first_not_of(" "),1,".")){
+      //should be found local
+      std::string fullName = wdir+fileName;
+      if(checkIfPresent(fullName)){
+	cmd.assign("rsync -e ssh -auv "+fullName+" "+_remoteHost+":"+_remoteDir+"/"+fileName);
+	return mySystem(cmd);
+      }
+      else{
+	OLMsg::Fatal("The input file <%s> is not present", fullName.c_str());
+	return false;
+      }
+    }
+    else { //should be found remote
+      if(!checkIfPresentRemote(fileName)){
+	OLMsg::Fatal("The input file <%s> is not present", fileName.c_str());
+	return false;
+      }
+      else
+	return true;
+    }
+  }
+}
+
+bool remoteClient::syncOutputFile(const std::string &wdir, const std::string &fileName){
+  std::string cmd;
+
+  if(checkIfPresentRemote(fileName)){
+    int pos=fileName.find_first_not_of(" ");
+    if(!fileName.compare(pos,1,".")){ // the file must be copied back locally
+      cmd.assign("rsync -e ssh -auv "+_remoteHost+":"+_remoteDir+dirSep
+		 +fileName.substr(pos,std::string::npos)+" .");
+      if(!wdir.empty())
+	cmd.append(dirSep+wdir);
+      return mySystem(cmd);
+    }
+  }
+  else
+    return false;
+}
+
+// client METAMODEL
+
+void MetaModel::saveCommandLines(const std::string fileName){
+  //save client command lines
+  std::string fileNameSave = getWorkingDir()+fileName+onelabExtension+".save";
+  std::ofstream outfile(fileNameSave.c_str());
+
+  if (outfile.is_open())
+    for(citer it = _clients.begin(); it != _clients.end(); it++)
+      outfile << (*it)->toChar();
+  else
+    OLMsg::Fatal("The file <%s> cannot be opened",fileNameSave.c_str());
+  outfile.close();
+}
+
+bool MetaModel::checkCommandLines(){
+  bool allDefined=true;
+  for(citer it = _clients.begin(); it != _clients.end(); it++){
+    allDefined = allDefined && (*it)->checkCommandLine();
+  }
+  saveCommandLines(genericNameFromArgs);
+  return allDefined;
+}
+
+void MetaModel::initialize()
+{
+  OLMsg::Info("Initialize Metamodel by the loader");
+  OLMsg::SetOnelabString(clientName + "/9CheckCommand","-a",false);
+  OLMsg::SetOnelabNumber(clientName + "/UseCommandLine",1,false);
+  OLMsg::SetOnelabNumber(clientName + "/Initialized",1,false);
+}
+
+void MetaModel::analyze() {
+  std::string fileName = genericNameFromArgs + onelabExtension;
+  OLMsg::Info("Metamodel now ANALYZING",fileName.c_str());
+  openOnelabBlock();
+  parse_onefile(fileName);
+  closeOnelabBlock();
+}
+
+
+void MetaModel::compute() {
+  std::string fileName = genericNameFromArgs + onelabExtension;
+  OLMsg::Info("Metamodel now COMPUTING",fileName.c_str());
+  openOnelabBlock();
+  parse_onefile(fileName);
+  closeOnelabBlock();
+  onelab::server::instance()->setChanged(false);
+}
+
+void MetaModel::registerClient(const std::string &name, const std::string &type, const std::string &cmdl, const std::string &host, const std::string &rdir) {
+  localSolverClient *c;
+  // Clients are assigned by default the same working dir as the MetaModel
+  // i.e. the working dir from args
+  if(host.empty() || rdir.empty()){ //local client
+    if(!type.compare(0,6,"interf"))
+      c= new InterfacedClient(name,cmdl,getWorkingDir());
+    else if(!type.compare(0,6,"encaps"))
+      c= new NativeClient(name,cmdl,getWorkingDir());
+    else
+      OLMsg::Fatal("Unknown client type", type.c_str());
+  }
+  else{ // remote client
+    if(!type.compare(0,6,"interf"))
+      c= new RemoteInterfacedClient(name,cmdl,getWorkingDir(),host,rdir);
+    else if(!type.compare(0,6,"encaps"))
+      c= new RemoteNativeClient(name,cmdl,getWorkingDir(),host,rdir);
+    else
+      OLMsg::Fatal("Unknown remote client type", type.c_str());
+  }
+  _clients.push_back(c);
+}
+
+void MetaModel::PostArray(std::vector<std::string> choices)
+{
+  int nb=0;
+  //onelab::number o;
+  while( 4*(nb+1) <= choices.size()){
+    int lin= atof(choices[4*nb+1].c_str());
+    int col= atof(choices[4*nb+2].c_str());
+    std::string fileName =
+      OLMsg::GetOnelabString("Arguments/WorkingDir")+choices[4*nb];
+    double val=find_in_array(lin,col,read_array(fileName,' '));
+    OLMsg::AddOnelabNumberChoice(choices[4*nb+3],val);
+    OLMsg::Info("PostArray <%s>=%e",choices[4*nb+3].c_str(),val);
+    nb++;
+  }
+}
+
+// INTERFACED client
+
+void InterfacedClient::analyze() {
+  int pos;
+  std::vector<std::string> choices;
+
+  setAction("check");
+  OLMsg::Info("Analyses <%s> changed=%d", getName().c_str(),
+	      onelab::server::instance()->getChanged(getName()));
+  getList("InputFiles", choices);
+  for(unsigned int i = 0; i < choices.size(); i++){
+    if((pos=choices[i].find(onelabExtension)) != std::string::npos){
+      // if .ol file
+      checkIfPresentLocal(choices[i]);
+      parse_onefile(choices[i]);
+    }
+  }
+  convert();
+}
+
+void InterfacedClient::convert() {
+  int pos;
+  std::vector<std::string> choices;
+  getList("InputFiles", choices);
+  for(unsigned int i = 0; i < choices.size(); i++){
+    if((pos=choices[i].find(onelabExtension)) != std::string::npos){
+      checkIfPresentLocal(choices[i]);
+      // remove .ol extension
+      std::string ofileName = getWorkingDir() + choices[i].substr(0,pos);
+      std::ofstream outfile(ofileName.c_str());
+      if (outfile.is_open())
+	convert_onefile(choices[i],outfile);
+      else
+	OLMsg::Fatal("The file <%s> cannot be opened",ofileName.c_str());
+      outfile.close();
+    }
+  }
+}
+
+void InterfacedClient::compute(){
+  std::string cmd;
+  std::vector<std::string> choices;
+
+  setAction("compute");
+  OLMsg::Info("Computes <%s> changed=%d", getName().c_str(),
+	      onelab::server::instance()->getChanged(getName()));
+
+  if(getActive() && onelab::server::instance()->getChanged(getName())){
+    analyze();
+    //convert();
+    if(getList("InputFiles",choices)){
+      for(unsigned int i = 0; i < choices.size(); i++){
+	//remove .ol ext
+	checkIfPresentLocal(
+	     choices[i].substr(0,choices[i].find(onelabExtension)));
+      }
+    }
+
+    if(buildRmCommand(cmd))
+      SystemCall(cmd,true); //blocking
+
+    cmd.assign("");
+    if(!getWorkingDir().empty())
+      cmd.append("cd " + getWorkingDir() + cmdSep);
+    cmd.append(FixWindowsPath(getCommandLine() + " "));
+    cmd.append(getString("Arguments"));
+
+    SystemCall(cmd.c_str(),true); //blocking
+
+    if(getList("OutputFiles",choices)){
+      for(unsigned int i = 0; i < choices.size(); i++){
+	checkIfPresentLocal(choices[i]);
+      }
+    }
+  }
+  OLMsg::Info("Client %s completed",_name.c_str());
+}
+
+// NATIVE Client
+
+void NativeClient::analyze() {
+  setAction("check");
+  OLMsg::Info("Analyses <%s> changed=%d", getName().c_str(),
+	      onelab::server::instance()->getChanged(getName()));
+  run();
+}
+
+void NativeClient::compute() {
+  std::string cmd;
+  std::vector<std::string> choices;
+
+  setAction("compute");
+  OLMsg::Info("Computes <%s> changed=%d", getName().c_str(),
+	      onelab::server::instance()->getChanged(getName()));
+  if(getActive() && onelab::server::instance()->getChanged(getName())){
+    if(buildRmCommand(cmd))
+      SystemCall(cmd,true);
+
+    if(getList("InputFiles",choices)){
+      for(unsigned int i = 0; i < choices.size(); i++){
+	checkIfPresentLocal(choices[i]);
+      }
+    }
+    run();
+
+    if(getList("OutputFiles",choices)){
+      for(unsigned int i = 0; i < choices.size(); i++){
+	checkIfPresentLocal(choices[i]);
+      }
+    }
+  }
+}
+
+// REMOTE INTERFACED Client
+
+bool RemoteInterfacedClient::checkCommandLine(){
+  return remoteClient::checkCommandLine(getCommandLine());
+}
+
+void RemoteInterfacedClient::compute(){
+  std::string cmd,rmcmd;
+  std::vector<std::string> choices;
+
+  setAction("compute");
+  OLMsg::Info("Computes <%s> changed=%d", getName().c_str(),
+	      onelab::server::instance()->getChanged(getName()));
+
+  if(getActive() && onelab::server::instance()->getChanged(getName())){
+    if(getList("InputFiles",choices)){
+      for(unsigned int i = 0; i < choices.size(); i++)
+	syncInputFile(getWorkingDir(),choices[i]);
+    }
+
+    if(buildRmCommand(rmcmd)){
+      cmd.assign("ssh "+getRemoteHost()+" 'cd "+getRemoteDir()+"; "+rmcmd+"'");
+      mySystem(cmd);
+    }
+
+    cmd.assign("ssh "+getRemoteHost()+" 'cd "+getRemoteDir()+"; "
+	       +getCommandLine()+" "+getString("Arguments")+"'");
+    mySystem(cmd);
+
+    if(getList("OutputFiles",choices)){
+      for(unsigned int i = 0; i < choices.size(); i++)
+	syncOutputFile(getWorkingDir(),choices[i]);
+    }
+
+    if(getList("PostArray",choices))
+      PostArray(choices);
+  }
+}
+
+// REMOTE NATIVE Client
+
+std::string RemoteNativeClient::buildCommandLine(){
+  std::string command;
+  command.assign("incomp_ssh -f "+getRemoteHost());
+  command.append(" 'cd "+getRemoteDir()+"; ");
+  command.append(FixWindowsPath(getCommandLine())+" ");
+  return command;
+}
+
+bool RemoteNativeClient::checkCommandLine(){
+  return remoteClient::checkCommandLine(getCommandLine());
+}
+
+void RemoteNativeClient::analyze(){
+  std::string cmd,rmcmd;
+  std::vector<std::string> choices;
+
+  setAction("check");
+  OLMsg::Info("Analyses <%s> changed=%d", getName().c_str(),
+	      onelab::server::instance()->getChanged(getName()));
+
+  if(getList("InputFiles",choices)){
+    for(unsigned int i = 0; i < choices.size(); i++)
+      syncInputFile(getWorkingDir(),choices[i]);
+  }
+  run();
+}
+
+
+void RemoteNativeClient::compute(){
+  std::string cmd,rmcmd;
+  std::vector<std::string> choices;
+
+  setAction("compute");
+  OLMsg::Info("Analyses <%s> changed=%d", getName().c_str(),
+	      onelab::server::instance()->getChanged(getName()));
+
+  if(getActive() && onelab::server::instance()->getChanged(getName())){
+    if(getList("InputFiles",choices)){
+      for(unsigned int i = 0; i < choices.size(); i++)
+	syncInputFile(getWorkingDir(),choices[i]);
+    }
+
+    if(buildRmCommand(rmcmd)){
+      cmd.assign("ssh "+getRemoteHost()+" 'cd "+getRemoteDir()+"; "+rmcmd+"'");
+      mySystem(cmd);
+    }
+
+    run();
+
+    if(getList("OutputFiles",choices)){
+      for(unsigned int i = 0; i < choices.size(); i++)
+	syncOutputFile(getWorkingDir(),choices[i]);
+    }
+
+    if(getList("PostArray",choices))
+      PostArray(choices);
+  }
+}
+
+// ONELAB additional TOOLS (no access to server in tools)
+// options for 'onelab_client'
+
+int getOptions(int argc, char *argv[], parseMode &todo, std::string &commandLine, std::string &caseName, std::string &clientName, std::string &sockName){
+
+  commandLine=argv[0];
+  todo=COMPUTE;
+  caseName="untitled";
+  int i= 1;
+  while(i < argc) {
+    if(argv[i][0] == '-') {
+      if(!strcmp(argv[i] + 1, "onelab")) {
+	i++;
+	clientName = argv[i];
+        i++;
+	sockName = argv[i];
+        i++;
+      }
+      else if(!strcmp(argv[i] + 1, "a")) {
+	i++;
+	todo=ANALYZE;
+      }
+      else if(!strcmp(argv[i] + 1, "c")) {
+	i++;
+	std::cout << "\nONELAB: Present state of the onelab clients\n"
+		  << std::endl;
+	for(onelab::server::citer it=onelab::server::instance()->firstClient();
+	    it != onelab::server::instance()->lastClient(); it++){
+	  std::string name= it->second->getName();
+	  std::cout << "<" << onelab::server::instance()->getChanged(name)
+		    << "> " << name << std::endl;
+	}
+	todo=ANALYZE;
+      }
+      else {
+	i++;
+	printf("Usage: %s [-m num -a -c]\n", argv[0]);
+	printf("Options are:\nm      model number\n");
+	printf("a      analyze only\n");
+	exit(1);
+      }
+    }
+    else{
+      caseName=argv[i];
+      i++;
+    }
+  }
+}
+
+std::string itoa(const int i){
+  std::ostringstream tmp;
+  tmp << i ;
+  return tmp.str();
+}
+
+std::string ftoa(const double x){
+  std::stringstream Num;
+  Num << x;
+  return Num.str();
+}
+
+int mySystem(std::string commandLine){
+  //std::cout << "mySystem<" << commandLine << ">" << std::endl;
+  return SystemCall(commandLine.c_str(), true);
+}
+
+#include <sys/stat.h>
+#include <ctime>
+bool checkIfPresent(std::string fileName){
+  struct stat buf;
+  if (!stat(fileName.c_str(), &buf))
+    return true;
+  else{
+    OLMsg::Fatal("The file <%s> is not present.",fileName.c_str());
+    return false;
+  }
+}
+
+#include <unistd.h>
+#include <sys/types.h>
+#if not defined WIN32
+#include <pwd.h>
+std::string getUserHomedir(){
+  struct passwd *pw = getpwuid(getuid());
+  std::string str(pw->pw_dir);
+  str.append("/");
+  return str;
+}
+#endif
+
+#include <sys/param.h>
+std::string getCurrentWorkdir(){
+  char path[MAXPATHLEN];
+  getcwd(path, MAXPATHLEN);
+  std::string str = path;
+  return str;
+}
+
+std::string sanitize(const std::string &in)
+{
+  std::string out, forbidden(" ();");
+  for(unsigned int i = 0; i < in.size(); i++)
+    if ( forbidden.find(in[i]) == std::string::npos)
+      out.push_back(in[i]);
+  return out;
+}
+std::string removeBlanks(const std::string &in)
+{
+  int pos0=in.find_first_not_of(" ");
+  int pos=in.find_last_not_of(" ");
+  if( (pos0 != std::string::npos) && (pos != std::string::npos))
+    return in.substr(pos0,pos-pos0+1);
+  else
+    return "";
+}
+bool isPath(const std::string &in)
+{
+  int pos=in.find_last_not_of(" 0123456789");
+  if(in.compare(pos,1,dirSep))
+    OLMsg::Fatal("The argument <%s> is not a valid path (must end with '/')",in.c_str());
+  return true;
+}
+
+void GmshDisplay(onelab::remoteNetworkClient *loader, std::string fileName, std::vector<std::string> choices){
+  if(choices.empty()) return;
+#if defined(WIN32)
+  std::string cmd = "gmsh.exe ";
+#else
+  std::string cmd = "gmsh ";
+#endif
+  cmd.append( fileName + ".geo ");
+  for(unsigned int i = 0; i < choices.size(); i++){
+    std::string fileName=OLMsg::GetOnelabString("Arguments/WorkingDir")+choices[i];
+    cmd.append(fileName+" ");
+    if(OLMsg::hasGmsh){
+      loader->sendMergeFileRequest(fileName);
+      OLMsg::Info("Send merge request <%s>",fileName.c_str());
+    }
+  }
+  if(!OLMsg::hasGmsh) system(cmd.c_str());
+}
+
+std::vector <double> extract_column(const int col, array data){
+  std::vector<double> column;
+  for ( int i=0; i<data.size(); i++)
+    if (  col>0 && col<=data[i].size())
+      column.push_back(data[i][col-1]);
+    else
+      OLMsg::Fatal("Column number (%d) out of range.",col);
+  return column;
+}
+
+double find_in_array(int lin, int col, const std::vector <std::vector <double> > &data){
+  if ( lin<0 ) {
+    lin=data.size();
+  }
+  if ( lin>=1 && lin<=data.size()){
+    if ( col>=1 && col<=data[lin-1].size() )
+      return data[lin-1][col-1];
+  }
+  OLMsg::Fatal("The value has not been calculated: (%d,%d) out of range",lin,col);
+}
+
+array read_array(std::string fileName, char sep){
+  std::ifstream infile(sanitize(fileName).c_str());
+  std::vector <std::vector <double> > array;
+
+  int deb,end;
+  double temp;
+  while (infile){
+    std::string s;
+    if (!getline( infile, s )) break;
+    std::vector <double> record;
+    end=0;
+    while ( (deb=s.find_first_not_of(" \t\n", end)) != std::string::npos ) {
+      end=s.find_first_of(" \t\n",deb);
+      temp=atof( s.substr(deb,end).c_str() );
+      record.push_back( temp );
+    }
+    array.push_back( record );
+  }
+  if (!infile.eof()){
+    std::cerr << "Error reading array\n";
+  }
+  return array;
+}
diff --git a/contrib/onelab/OnelabClients.h b/contrib/onelab/OnelabClients.h
new file mode 100644
index 0000000000..ffcaf6619b
--- /dev/null
+++ b/contrib/onelab/OnelabClients.h
@@ -0,0 +1,316 @@
+// ONELAB - Copyright (C) 2010-2012 C. Geuzaine, F. Henrotte
+//
+// See the LICENSE.txt file for license information. Please report all
+// bugs and problems to <gmsh@geuz.org>.
+
+#ifndef _ONELAB_CLIENTS_H_
+#define _ONELAB_CLIENTS_H_
+
+#include <stdlib.h>
+#include <fstream>
+#include <iostream>
+#include <sstream>
+
+#include "OS.h"
+#include "onelab.h"
+#include "OnelabMessage.h"
+
+// Onelab file extension
+static std::string onelabExtension(".ol");
+// Possible actions for clients
+enum parseMode {INITIALIZE, REGISTER, ANALYZE, COMPUTE, EXIT, STOP};
+
+static char charSep() { return '\0'; }
+#if defined(WIN32)
+static std::string dirSep("\\");
+static std::string cmdSep(" & ");
+#else
+static std::string dirSep("/");
+static std::string cmdSep(" ; ");
+#endif
+
+// TOOLS 
+int getOptions(int argc, char *argv[], parseMode &todo, std::string &commandLine, std::string &caseName, std::string &clientName, std::string &sockName);
+std::string itoa(const int i);
+std::string ftoa(const double x);
+bool checkIfPresent(std::string fileName);
+int mySystem(std::string commandLine);
+void GmshDisplay(onelab::remoteNetworkClient *loader, std::string fileName, std::vector<std::string> choices);
+std::string getCurrentWorkdir();
+std::string getUserHomedir();
+std::string sanitize(const std::string &in);
+std::string removeBlanks(const std::string &in);
+bool isPath(const std::string &in);
+
+// Parser TOOLS 
+int enclosed(const std::string &in, std::vector<std::string> &arguments);
+int extract(const std::string &in, std::string &paramName, std::string &action, std::vector<std::string> &arguments);
+bool extractRange(const std::string &in, std::vector<double> &arguments);
+std::string extractExpandPattern(const std::string& str);
+
+
+typedef std::vector <std::vector <double> > array;
+array read_array(std::string fileName, char sep);
+double find_in_array(int i, int j, const std::vector <std::vector <double> > &data);
+std::vector<double> extract_column(const int j, array data);
+
+static std::string getShortName(const std::string &name) {
+  std::string s = name;
+  // remove path
+  std::string::size_type last = name.find_last_of('/');
+  if(last != std::string::npos)
+    s = name.substr(last + 1);
+  // remove starting numbers
+  while(s.size() && s[0] >= '0' && s[0] <= '9')
+    s = s.substr(1);
+  return s;
+}
+
+class ShortNameLessThan{
+ public:
+  bool operator()(const std::string p1, const std::string p2) const
+  {
+    return getShortName(p1) < getShortName(p2);
+  }
+};
+
+/*
+VIRTUAL and BASE CLASSES
+
+"localSolverClient" is the base class 
+for all onelab clients called from a metamodel.
+It inherits from the "LocalClient" class of "onelab.h" 
+and has the additional metamodel specific functions: 
+analyze(), compute(), checkIfPresent(), checkCommandLine(),
+inputFile(), outputFile()
+
+The subclass "localSolverNetworkClient" of "localSolverClient"
+is for native clients (Gmsh and getDP so far)
+that communicate with the server through sockets. 
+It has a GmshServer member,
+uses localNetworkSolverClient::run instead of onelab::client::run().
+
+Both "localSolverNetworkClient" and "localSolverClient" are pure virtual.
+
+The combination of two alternatives native/interfaced and local/remote
+yields 4 clients: 
+InterfacedClient, RemoteInterfacesClient
+NativeClient, RemoteINterfacedClient
+
+The base class "remoteClient" is a base class 
+for clients running on a remote host.
+It provides appropriate versions of checkIfPresent() and checkCommandLine().
+*/
+class localSolverClient : public onelab::localClient{
+ private:
+  std::string _commandLine;
+  std::string _workingDir;
+  int _active;
+  bool _onelabBlock;
+  std::set<std::string, ShortNameLessThan> _parameters;
+  std::string longName(const std::string name);
+ public:
+ localSolverClient(const std::string &name, const std::string &cmdl, 
+		   const std::string &wdir) 
+   : onelab::localClient(name), _commandLine(cmdl), _workingDir(wdir),
+    _active(1), _onelabBlock(false) {
+  }
+  virtual ~localSolverClient(){}
+  const std::string &getCommandLine(){ return _commandLine; }
+  const std::string &getWorkingDir() { return _workingDir; }
+  virtual void setCommandLine(const std::string &s){ _commandLine = s; }
+  virtual void setWorkingDir(const std::string &s){ _workingDir = s; }
+
+  void setAction(const std::string action);
+  const std::string getString(const std::string what);
+  const bool getList(const std::string type, 
+		     std::vector<std::string> &choices);
+  const bool isActive() { return (bool)_active; }
+  const void setActive(int val) { _active=val; }
+  int getActive() { return _active; }
+  virtual std::string toChar();
+
+  // parser
+  void modify_tags(const std::string lab, const std::string com);
+  const bool isOnelabBlock() { return _onelabBlock; }
+  const void openOnelabBlock() { _onelabBlock=true; }
+  const void closeOnelabBlock() { _onelabBlock=false; }
+  std::string resolveGetVal(std::string line);
+  bool resolveLogicExpr(std::vector<std::string> arguments);
+  void parse_sentence(std::string line) ;
+  void parse_oneline(std::string line, std::ifstream &infile) ;
+  bool parse_block(std::ifstream &infile) ;
+  bool parse_ifstatement(std::ifstream &infile, bool condition) ;
+  void parse_onefile(std::string ifileName, bool mandatory=true);
+  void convert_oneline(std::string line, std::ifstream &infile, 
+		       std::ofstream &outfile);
+  bool convert_ifstatement(std::ifstream &infile, 
+			   std::ofstream &outfile, bool condition) ;
+  void convert_onefile(std::string ifileName, std::ofstream &outfile);
+  virtual void client_sentence(const std::string &name, 
+			       const std::string &action, 
+			       const std::vector<std::string> &arguments);
+
+  // execution
+  bool buildRmCommand(std::string &cmd);
+  bool checkIfPresentLocal(const std::string &fileName){
+    return checkIfPresent(getWorkingDir()+fileName);
+  }
+  virtual bool checkCommandLine();
+  virtual void analyze() =0;
+  virtual void compute() =0;
+  void PostArray(std::vector<std::string> choices);
+  void GmshMerge(std::vector<std::string> choices);
+};
+
+class localNetworkSolverClient : public localSolverClient{
+ private:
+  // command line option to specify socket
+  std::string _socketSwitch;
+  // pid of the remote network client
+  int _pid;
+  // underlying GmshServer
+  GmshServer *_gmshServer;
+  // flag indicating if the client is a remote one
+  bool _remote;
+ public:
+ localNetworkSolverClient(const std::string &name, const std::string &cmdl, const std::string &wdir)
+   : localSolverClient(name,cmdl,wdir), _socketSwitch("-onelab"),
+    _pid(-1), _gmshServer(0), _remote(false) {}
+  virtual ~localNetworkSolverClient(){}
+  virtual bool isNetworkClient(){ return true; }
+  const std::string &getSocketSwitch(){ return _socketSwitch; }
+  void setSocketSwitch(const std::string &s){ _socketSwitch = s; }
+  int getPid(){ return _pid; }
+  void setPid(int pid){ _pid = pid; }
+  GmshServer *getGmshServer(){ return _gmshServer; }
+  void setGmshServer(GmshServer *server){ _gmshServer = server; }
+  int getRemote(){ return _remote; }
+  void setRemote(bool rem){ _remote = rem; }
+
+  virtual std::string buildCommandLine();
+  std::string appendArguments();
+  virtual bool run();
+  virtual bool kill();
+
+  virtual void analyze() =0;
+  virtual void compute() =0;
+};
+
+class remoteClient {
+ private:
+  std::string _remoteHost;
+  std::string _remoteDir;
+ public:
+ remoteClient(const std::string &host, const std::string &rdir) 
+   : _remoteHost(host), _remoteDir(rdir) {}
+  ~remoteClient(){}
+
+  const std::string &getRemoteHost() const { return _remoteHost; }
+  const std::string &getRemoteDir() const { return _remoteDir; }
+
+  bool checkCommandLine(const std::string &commandLine);
+  bool checkIfPresentRemote(const std::string &fileName);
+  bool syncInputFile(const std::string &wdir, const std::string &fileName);
+  bool syncOutputFile(const std::string &wdir, const std::string &fileName);
+};
+
+// ONELAB CLIENTS
+
+class MetaModel : public localSolverClient {
+ private:
+  std::vector<localSolverClient *> _clients;
+  parseMode _todo;
+ public:
+ MetaModel(const std::string &cmdl, const std::string &wdir, const std::string &cname, const std::string &fname) 
+   : localSolverClient(cname,cmdl,wdir){
+    clientName = cname;
+    genericNameFromArgs = fname.size() ? fname : cmdl;
+    setWorkingDir(wdir); // wdir from args
+    openOnelabBlock();
+    _todo=REGISTER;
+    parse_onefile( genericNameFromArgs + onelabExtension + ".save",false);
+    parse_onefile( genericNameFromArgs + onelabExtension);
+    closeOnelabBlock();
+  }
+  ~MetaModel(){}
+  typedef std::vector<localSolverClient*>::iterator citer;
+  void setTodo(const parseMode x) { _todo=x; }
+  parseMode getTodo() { return _todo; }
+  bool isTodo(const parseMode x) { return (_todo==x);}
+  citer firstClient(){ return _clients.begin(); }
+  citer lastClient(){ return _clients.end(); }
+  int getNumClients() { return _clients.size(); };
+
+  void registerClient(const std::string &name, const std::string &type, 
+		      const std::string &cmdl, const std::string &host, 
+		      const std::string &rdir);
+  bool checkCommandLines();
+  void saveCommandLines(const std::string fileName);
+  localSolverClient *findClientByName(std::string name){
+    for(unsigned int i=0; i<_clients.size(); i++)
+      if(_clients[i]->getName() == name) return _clients[i];
+    return 0;
+  }
+  std::string genericNameFromArgs, clientName;
+  void client_sentence(const std::string &name, const std::string &action, 
+		       const std::vector<std::string> &arguments);
+  std::string toChar(){}
+  void PostArray(std::vector<std::string> choices);
+  void initialize();
+  void analyze();
+  void compute();
+};
+
+class InterfacedClient : public localSolverClient { 
+  // n'utilise pas localNetworkSolverClient::run mais client::run()
+ public:
+ InterfacedClient(const std::string &name, const std::string &cmdl, const std::string &wdir)
+   : localSolverClient(name,cmdl,wdir) {}
+  ~InterfacedClient(){}
+
+  void analyze();
+  void convert();
+  virtual void compute();
+};
+
+class NativeClient : public localNetworkSolverClient { 
+  // utilise localNetworkClient::run
+public:
+ NativeClient(const std::string &name, const std::string &cmdl, const std::string &wdir) 
+   : localNetworkSolverClient(name,cmdl,wdir) {}
+  ~NativeClient(){}
+
+  //uses localNetworkSolver::buildCommandLine();
+  virtual void analyze();
+  virtual void compute() ;
+};
+
+class RemoteInterfacedClient : public InterfacedClient, public remoteClient {
+public:
+ RemoteInterfacedClient(const std::string &name, const std::string &cmdl, const std::string &wdir, const std::string &host, const std::string &rdir) 
+   : InterfacedClient(name,cmdl,wdir), remoteClient(host,rdir) {}
+  ~RemoteInterfacedClient(){}
+
+  bool checkCommandLine();
+  // uses InterfacedClient::analyze()
+  void compute() ;
+};
+
+class RemoteNativeClient : public NativeClient, public remoteClient {
+public:
+ RemoteNativeClient(const std::string &name, const std::string &cmdl, const std::string &wdir, const std::string &host, const std::string &rdir) 
+   : NativeClient(name,cmdl,wdir), remoteClient(host,rdir) {
+    setRemote(true);
+  }
+  ~RemoteNativeClient(){}
+
+  std::string buildCommandLine();
+  bool checkCommandLine();
+  void analyze();
+  void compute() ;
+};
+
+#endif
+
+
diff --git a/contrib/onelab/OnelabMessage.cpp b/contrib/onelab/OnelabMessage.cpp
new file mode 100644
index 0000000000..8416063622
--- /dev/null
+++ b/contrib/onelab/OnelabMessage.cpp
@@ -0,0 +1,664 @@
+// Gmsh - Copyright (C) 1997-2012 C. Geuzaine, J.-F. Remacle
+//
+// See the LICENSE.txt file for license information. Please report all
+// bugs and problems to <gmsh@geuz.org>.
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <algorithm>
+#include "OnelabMessage.h"
+#include "GmshSocket.h"
+#include "OS.h"
+
+#define ALWAYS_TRUE 1
+
+onelab::remoteNetworkClient *OLMsg::loader = 0;
+
+int OLMsg::_commRank = 0;
+int OLMsg::_commSize = 1;
+int OLMsg::_verbosity = 4;
+// int OLMsg::_progressMeterStep = 10;
+// int OLMsg::_progressMeterCurrent = 0;
+// std::map<std::string, double> OLMsg::_timers;
+int OLMsg::_warningCount = 0;
+int OLMsg::_errorCount = 0;
+GmshMessage *OLMsg::_callback = 0;
+std::string OLMsg::_commandLine;
+std::string OLMsg::_launchDate;
+GmshClient *OLMsg::_client = 0;
+onelab::client *OLMsg::_onelabClient = 0;
+bool OLMsg::hasGmsh=false;
+std::set<std::string, fullNameLessThan> OLMsg::_fullNameDict;
+
+#if defined(HAVE_NO_VSNPRINTF)
+static int vsnprintf(char *str, size_t size, const char *fmt, va_list ap)
+{
+  if(strlen(fmt) > size - 1){ // just copy the format
+    strncpy(str, fmt, size - 1);
+    str[size - 1] = '\0';
+    return size;
+  }
+  return vsprintf(str, fmt, ap);
+}
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER == 1310) //NET 2003
+#define vsnprintf _vsnprintf
+#endif
+
+void OLMsg::Init(int argc, char **argv)
+{
+  time_t now;
+  time(&now);
+  _launchDate = ctime(&now);
+  _launchDate.resize(_launchDate.size() - 1);
+  _commandLine.clear();
+  for(int i = 0; i < argc; i++){
+    if(i) _commandLine += " ";
+    _commandLine += argv[i];
+  }
+}
+
+void OLMsg::Exit(int level)
+{
+  if(level){
+    exit(level);
+  }
+  exit(_errorCount);
+}
+
+void OLMsg::Fatal(const char *fmt, ...)
+{
+  _errorCount++;
+
+  char str[1024];
+  va_list args;
+  va_start(args, fmt);
+  vsnprintf(str, sizeof(str), fmt, args);
+  va_end(args);
+
+  if(_callback) (*_callback)("Fatal", str);
+  if(_client) _client->Error(str);
+
+  if(ALWAYS_TRUE){
+    if(_commSize > 1)
+      fprintf(stderr, "Fatal   : [On processor %d] %s\n", _commRank, str);
+    else
+      fprintf(stderr, "Fatal   : %s\n", str);
+   fflush(stderr);
+  }
+
+  OLMsg::SetOnelabString("MetaModel/STATUS","STOP");
+  FinalizeClient();
+  FinalizeOnelab();
+  delete loader;
+  Exit(1);
+}
+
+void OLMsg::Error(const char *fmt, ...)
+{
+  _errorCount++;
+
+  if(_verbosity < 1) return;
+
+  char str[1024];
+  va_list args;
+  va_start(args, fmt);
+  vsnprintf(str, sizeof(str), fmt, args);
+  va_end(args);
+
+  if(_callback) (*_callback)("Error", str);
+  if(_client) _client->Error(str);
+
+  if(ALWAYS_TRUE){
+    if(_commSize > 1)
+      fprintf(stderr, "Error   : [On processor %d] %s\n", _commRank, str);
+    else
+      fprintf(stderr, "Error   : %s\n", str);
+    fflush(stderr);
+  }
+}
+
+void OLMsg::Warning(const char *fmt, ...)
+{
+  _warningCount++;
+
+  if(_commRank || _verbosity < 2) return;
+
+  char str[1024];
+  va_list args;
+  va_start(args, fmt);
+  vsnprintf(str, sizeof(str), fmt, args);
+  va_end(args);
+
+  if(_callback) (*_callback)("Warning", str);
+  if(_client) _client->Warning(str);
+
+  if(ALWAYS_TRUE){
+    fprintf(stderr, "Warning : %s\n", str);
+    fflush(stderr);
+  }
+}
+
+
+
+void OLMsg::Info(const char *fmt, ...)
+{
+  if(_commRank || _verbosity < 3) return;
+
+  char str[1024];
+  va_list args;
+  va_start(args, fmt);
+  vsnprintf(str, sizeof(str), fmt, args);
+  va_end(args);
+
+  if(_callback) (*_callback)("Info", str);
+  if(_client) _client->Info(str);
+
+  if(ALWAYS_TRUE){
+    fprintf(stdout, "Onelab  : %s\n", str);
+    fflush(stdout);
+  }
+}
+
+void OLMsg::Direct(const char *fmt, ...)
+{
+  if(_commRank || _verbosity < 3) return;
+
+  char str[1024];
+  va_list args;
+  va_start(args, fmt);
+  vsnprintf(str, sizeof(str), fmt, args);
+  va_end(args);
+
+  Direct(3, str);
+}
+
+void OLMsg::Direct(int level, const char *fmt, ...)
+{
+  if(_commRank || _verbosity < level) return;
+
+  char str[1024];
+  va_list args;
+  va_start(args, fmt);
+  vsnprintf(str, sizeof(str), fmt, args);
+  va_end(args);
+
+  if(_callback) (*_callback)("Direct", str);
+  if(_client) _client->Info(str);
+
+  if(ALWAYS_TRUE){
+    fprintf(stdout, "%s\n", str);
+    fflush(stdout);
+  }
+}
+
+void OLMsg::StatusBar(int num, bool log, const char *fmt, ...)
+{
+  if(_commRank || _verbosity < 3) return;
+  if(num < 1 || num > 3) return;
+
+  char str[1024];
+  va_list args;
+  va_start(args, fmt);
+  vsnprintf(str, sizeof(str), fmt, args);
+  va_end(args);
+
+  if(_callback && log) (*_callback)("Info", str);
+  if(_client && log) _client->Info(str);
+
+  if(log && ALWAYS_TRUE){
+    fprintf(stdout, "Info    : %s\n", str);
+    fflush(stdout);
+  }
+}
+
+/*
+void OLMsg::Debug(const char *fmt, ...)
+{
+  if(_verbosity < 99) return;
+
+  char str[1024];
+  va_list args;
+  va_start(args, fmt);
+  vsnprintf(str, sizeof(str), fmt, args);
+  va_end(args);
+
+  if(_callback) (*_callback)("Debug", str);
+  if(_client) _client->Info(str);
+
+  if(ALWAYS_TRUE){
+    if(_commSize > 1)
+      fprintf(stdout, "Debug   : [On processor %d] %s\n", _commRank, str);
+    else
+      fprintf(stdout, "Debug   : %s\n", str);
+    fflush(stdout);
+  }
+}
+
+void OLMsg::ProgressMeter(int n, int N, const char *fmt, ...)
+{
+  if(_commRank || _verbosity < 3) return;
+
+  double percent = 100. * (double)n/(double)N;
+
+  if(percent >= _progressMeterCurrent){
+    char str[1024];
+    va_list args;
+    va_start(args, fmt);
+    vsnprintf(str, sizeof(str), fmt, args);
+    va_end(args);
+
+    if(strlen(fmt)) strcat(str, " ");
+
+    char str2[1024];
+    sprintf(str2, "(%d %%)", _progressMeterCurrent);
+    strcat(str, str2);
+
+    if(_client) _client->Progress(str);
+
+    if(ALWAYS_TRUE){
+      fprintf(stdout, "%s                     \r", str);
+      fflush(stdout);
+    }
+
+    while(_progressMeterCurrent < percent)
+      _progressMeterCurrent += _progressMeterStep;
+  }
+
+  if(n > N - 1){
+    if(_client) _client->Progress("Done!");
+
+    if(ALWAYS_TRUE){
+      fprintf(stdout, "Done!                                              \r");
+      fflush(stdout);
+    }
+  }
+}
+
+void OLMsg::PrintTimers()
+{
+  // do a single stdio call!
+  std::string str;
+  for(std::map<std::string, double>::iterator it = _timers.begin();
+      it != _timers.end(); it++){
+    if(it != _timers.begin()) str += ", ";
+    char tmp[256];
+    sprintf(tmp, "%s = %gs ", it->first.c_str(), it->second);
+    str += std::string(tmp);
+  }
+  if(!str.size()) return;
+
+  if(ALWAYS_TRUE){
+    if(_commSize > 1)
+      fprintf(stdout, "Timers  : [On processor %d] %s\n", _commRank, str.c_str());
+    else
+      fprintf(stdout, "Timers  : %s\n", str.c_str());
+    fflush(stdout);
+  }
+}
+
+void OLMsg::PrintErrorCounter(const char *title)
+{
+  if(_commRank || _verbosity < 1) return;
+  if(!_warningCount && !_errorCount) return;
+
+  std::string prefix = _errorCount ? "Error   : " : "Warning : ";
+  std::string help("Check the full log for details");
+  std::string line(std::max(strlen(title), help.size()), '-');
+  char warn[128], err[128];
+  sprintf(warn, "%5d warning%s", _warningCount, _warningCount == 1 ? "" : "s");
+  sprintf(err, "%5d error%s", _errorCount, _errorCount == 1 ? "" : "s");
+
+  if(ALWAYS_TRUE){
+    fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n", (prefix + line).c_str(),
+            (prefix + title).c_str(), (prefix + warn).c_str(),
+            (prefix + err).c_str(), (prefix + help).c_str(),
+            (prefix + line).c_str());
+    fflush(stderr);
+  }
+}
+
+double OLMsg::GetValue(const char *text, double defaultval)
+{
+  printf("%s (default=%.16g): ", text, defaultval);
+  char str[256];
+  char *ret = fgets(str, sizeof(str), stdin);
+  if(!ret || !strlen(str) || !strcmp(str, "\n"))
+    return defaultval;
+  else
+    return atof(str);
+}
+
+std::string OLMsg::GetString(const char *text, std::string defaultval)
+{
+  printf("%s (default=%s): ", text, defaultval.c_str());
+  char str[256];
+  char *ret = fgets(str, sizeof(str), stdin);
+  if(!ret || !strlen(str) || !strcmp(str, "\n"))
+    return defaultval;
+  else
+    return std::string(str);
+}
+
+int OLMsg::GetAnswer(const char *question, int defaultval, const char *zero,
+                   const char *one, const char *two)
+{
+  if(two)
+    printf("%s\n\n0=[%s] 1=[%s] 2=[%s] (default=%d): ", question,
+           zero, one, two, defaultval);
+  else
+    printf("%s\n\n0=[%s] 1=[%s] (default=%d): ", question,
+           zero, one, defaultval);
+  char str[256];
+  char *ret = fgets(str, sizeof(str), stdin);
+  if(!ret || !strlen(str) || !strcmp(str, "\n"))
+    return defaultval;
+  else
+    return atoi(ret);
+}
+
+void OLMsg::InitClient(std::string sockname)
+{
+  if(_client) delete _client;
+  _client = new GmshClient();
+  if(_client->Connect(sockname.c_str()) < 0){
+    OLMsg::Error("Unable to connect to server on %s", sockname.c_str());
+    delete _client;
+    _client = 0;
+  }
+  else
+    _client->Start();
+}
+
+void OLMsg::Barrier()
+{
+}
+*/
+void OLMsg::FinalizeClient()
+{
+  if(_client){
+    _client->Stop();
+    _client->Disconnect();
+    delete _client;
+  }
+  _client = 0;
+}
+
+void OLMsg::InitializeOnelab(const std::string &name, const std::string &sockname)
+{
+  if(_onelabClient) delete _onelabClient;
+  if (sockname.empty())
+    _onelabClient = new onelab::localClient(name);
+  else{
+    onelab::remoteNetworkClient *c =
+      new onelab::remoteNetworkClient(name, sockname);
+    _onelabClient = c;
+    _client = c->getGmshClient();
+  }
+}
+
+double OLMsg::GetOnelabNumber(std::string name)
+{
+  if(_onelabClient){
+    std::vector<onelab::number> ps;
+    _onelabClient->get(ps, name);
+    if(ps.size())
+      return ps[0].getValue();
+  }
+  return 0;
+}
+
+void OLMsg::GetOnelabNumber(std::string name, double *val)
+{
+  if(_onelabClient){
+    std::vector<onelab::number> ps;
+    _onelabClient->get(ps, name);
+    if(ps.size()){
+      *val = ps[0].getValue();
+      return;
+    }
+  }
+  *val = 0;
+}
+
+void OLMsg::SetOnelabNumber(std::string name, double val, bool visible)
+{
+  if(_onelabClient){
+    std::vector<onelab::number> numbers;
+    _onelabClient->get(numbers, name);
+    if(numbers.empty()){
+      numbers.resize(1);
+      numbers[0].setName(name);
+    }
+    numbers[0].setValue(val);
+    numbers[0].setVisible(visible);
+    _onelabClient->set(numbers[0]);
+  }
+}
+
+std::string OLMsg::GetOnelabString(std::string name)
+{
+  std::string str="";
+  if(_onelabClient){
+    std::vector<onelab::string> ps;
+    _onelabClient->get(ps, name);
+    if(ps.size() && ps[0].getValue().size())
+      str = ps[0].getValue();
+  }
+  return str;
+}
+
+bool OLMsg::GetOnelabChoices(std::string name, std::vector<std::string> &choices){
+  if(_onelabClient){
+    std::vector<onelab::string> ps;
+    _onelabClient->get(ps, name);
+    if(ps.size() && ps[0].getValue().size()){
+      choices=ps[0].getChoices();
+      return true;
+    }
+  }
+  return false;
+}
+
+void OLMsg::SetOnelabString(std::string name, std::string val, bool visible)
+{
+  if(_onelabClient){
+    std::vector<onelab::string> strings;
+    _onelabClient->get(strings, name);
+    if(strings.empty()){
+      strings.resize(1);
+      strings[0].setName(name);
+    }
+    strings[0].setValue(val);
+    strings[0].setVisible(visible);
+    _onelabClient->set(strings[0]);
+  }
+}
+
+void OLMsg::SetOnelabAttributeString(std::string name,
+				   std::string attrib,std::string val){
+  if(_onelabClient){
+    std::vector<onelab::string> ps;
+    _onelabClient->get(ps, name);
+    if(ps.size()){
+      ps[0].setAttribute(attrib,val);
+    }
+  }
+}
+std::string OLMsg::GetOnelabAttributeString(std::string name,std::string attrib){
+  std::string str="";
+  if(_onelabClient){
+    std::vector<onelab::string> ps;
+    _onelabClient->get(ps, name);
+    if(ps.size())
+      str = ps[0].getAttribute(attrib);
+  }
+  return str;
+}
+std::string OLMsg::GetOnelabAttributeNumber(std::string name,std::string attrib){
+  std::string str="";
+  if(_onelabClient){
+    std::vector<onelab::number> ps;
+    _onelabClient->get(ps, name);
+    if(ps.size())
+      str = ps[0].getAttribute(attrib);
+  }
+  return str;
+}
+
+void OLMsg::AddOnelabNumberChoice(std::string name, double val)
+{
+  if(_onelabClient){
+    std::vector<double> choices;
+    std::vector<onelab::number> ps;
+    _onelabClient->get(ps, name);
+    if(ps.size()){
+      choices = ps[0].getChoices();
+    }
+    else{
+      ps.resize(1);
+      ps[0].setName(name);
+    }
+    ps[0].setAttribute("Highlight","Coral"); // only used by PostArray
+    ps[0].setReadOnly(false);
+    ps[0].setVisible(true);
+    ps[0].setValue(val);
+    choices.push_back(val);
+    ps[0].setChoices(choices);
+    _onelabClient->set(ps[0]);
+  }
+}
+
+int fullNameLessThan::compareFullNames(const std::string a, const std::string b) const{
+  std::string::const_iterator ita, itb;
+  ita=a.begin(); itb=b.begin();
+  if( (*ita >= '0') && (*ita <= '9')) ita++;
+  if( (*itb >= '0') && (*itb <= '9')) itb++;
+
+  while( (ita<a.end()) && (itb<b.end()) && (*ita == *itb) ){
+    if(*ita == '/'){
+      ita++;
+      if( (*ita >= '0') && (*ita <= '9')) ita++;
+    }
+    else
+      ita++;
+
+    if(*itb == '/'){
+      itb++;
+      if( (*itb >= '0') && (*itb <= '9')) itb++;
+    }
+    else
+      itb++;
+  }
+  return *ita < *itb ;
+}
+void OLMsg::recordFullName(const std::string &name){
+  OLMsg::_fullNameDict.insert(name);
+}
+std::string OLMsg::obtainFullName(const std::string &name){
+  std::set<std::string, fullNameLessThan>::iterator it;
+
+  // fullNameLessThan* comp=new fullNameLessThan;
+  // std::cout << "Dict=" << OLMsg::_fullNameDict.size() << std::endl;
+  // std::cout << "Looking for " << name << std::endl;
+  // for ( it=OLMsg::_fullNameDict.begin() ; it != OLMsg::_fullNameDict.end(); it++ )
+  //   std::cout << *it << " <" << comp->operator()(*it,name) << ">" << std::endl;
+  // std::cout << std::endl;
+
+  it = OLMsg::_fullNameDict.find(name);
+  if(it == OLMsg::_fullNameDict.end()){
+    return name;
+  }
+  else{
+    return *it;
+  }
+}
+
+void OLMsg::SendMergeFileRequest(const std::string &name){
+  _onelabClient->sendMergeFileRequest(name);
+}
+
+int OLMsg::Synchronize_Down(){
+  OLMsg::_fullNameDict.clear();
+  std::vector<onelab::number> numbers;
+  loader->get(numbers,"");
+  if(numbers.size()){
+    for(std::vector<onelab::number>::const_iterator it = numbers.begin();
+	it != numbers.end(); it++){
+      if(_onelabClient) _onelabClient->set(*it);
+      OLMsg::recordFullName((*it).getName());
+      //std::cout << "FHF d " << (*it).getName() << "=" << (*it).getChanged() << std::endl;
+    }
+  }
+  std::vector<onelab::string> strings;
+  loader->get(strings,"");
+  if(strings.size()){
+    for(std::vector<onelab::string>::const_iterator it = strings.begin();
+  	it != strings.end(); it++){
+      if(_onelabClient) _onelabClient->set(*it);
+      OLMsg::recordFullName((*it).getName());
+      //std::cout << "FHF d " << (*it).getName() << "=" << (*it).getChanged() << std::endl;
+    }
+  }
+  std::vector<onelab::region> regions;
+  loader->get(regions,"");
+  if(regions.size()){
+    for(std::vector<onelab::region>::const_iterator it = regions.begin();
+  	it != regions.end(); it++){
+      if(_onelabClient) _onelabClient->set(*it);
+      OLMsg::recordFullName((*it).getName());
+    }
+  }
+  return(numbers.size()+strings.size()+regions.size());
+}
+
+int OLMsg::Synchronize_Up(){
+  std::vector<onelab::number> numbers;
+  _onelabClient->get(numbers,"");
+  if(numbers.size()){
+    for(std::vector<onelab::number>::const_iterator it = numbers.begin();
+  	it != numbers.end(); it++){
+      loader->set(*it);
+      //std::cout << "FHF u " << (*it).getName() << "="
+      //<< (*it).getChanged() << std::endl;
+    }
+  }
+  loader->get(numbers,"");
+  if(numbers.size()){
+    for(std::vector<onelab::number>::const_iterator it = numbers.begin();
+  	it != numbers.end(); it++){
+      //std::cout << "FHF control " << (*it).getName() << "="
+      //<< (*it).getChanged() << std::endl;
+    }
+  }
+
+  std::vector<onelab::string> strings;
+  _onelabClient->get(strings,"");
+  if(strings.size()){
+    for(std::vector<onelab::string>::const_iterator it = strings.begin();
+	it != strings.end(); it++){
+      loader->set(*it);
+      //std::cout << "FHF u " << (*it).getName() << "=" << (*it).getChanged() << std::endl;
+    }
+  }
+  std::vector<onelab::region> regions;
+  _onelabClient->get(regions,"");
+  if(regions.size()){
+    for(std::vector<onelab::region>::const_iterator it = regions.begin();
+	it != regions.end(); it++){
+      loader->set(*it);
+    }
+  }
+  return(numbers.size()+strings.size()+regions.size());
+}
+
+void OLMsg::FinalizeOnelab(){
+  if(_onelabClient){
+    delete _onelabClient;
+    _onelabClient = 0;
+    _client = 0;
+  }
+}
diff --git a/contrib/onelab/OnelabMessage.h b/contrib/onelab/OnelabMessage.h
new file mode 100644
index 0000000000..5e5b8f1894
--- /dev/null
+++ b/contrib/onelab/OnelabMessage.h
@@ -0,0 +1,132 @@
+// Gmsh - Copyright (C) 1997-2012 C. Geuzaine, J.-F. Remacle
+//
+// See the LICENSE.txt file for license information. Please report all
+// bugs and problems to <gmsh@geuz.org>.
+
+#ifndef _ONELAB_MESSAGE_H_
+#define _ONELAB_MESSAGE_H_
+
+#include <map>
+#include <string>
+#include <set>
+#include <stdarg.h>
+#include "onelab.h"
+
+class GmshClient;
+
+// the external message handler
+class GmshMessage{
+ public:
+  GmshMessage(){}
+  virtual ~GmshMessage(){}
+  virtual void operator()(std::string level, std::string message){}
+};
+
+class fullNameLessThan{
+public:
+  int compareFullNames(const std::string a, const std::string b) const;
+  bool operator()(const std::string p1, const std::string p2) const{
+    return compareFullNames(p1,p2);
+  }
+};
+
+// a class to manage messages
+class OLMsg {
+ private:
+  // current cpu number and total number of cpus
+  static int _commRank, _commSize;
+  // verbosity level (0: silent except fatal errors, 1: +errors, 2:
+  // +warnings, 3: +info except status bar, 4: normal, 99: debug)
+  static int _verbosity;
+  // step (in %) of the progress meter and current progress %
+  static int _progressMeterStep, _progressMeterCurrent;
+  // timers
+  static std::map<std::string, double> _timers;
+  // counters
+  static int _warningCount, _errorCount;
+  // callback
+  static GmshMessage *_callback;
+  // command-line and startup time
+  static std::string _commandLine, _launchDate;
+  // communication with Gmsh when run remotely
+  static GmshClient *_client;
+  // communication with onelab server
+  static onelab::client *_onelabClient;
+  // dictionnary for parameter names
+  static std::set<std::string, fullNameLessThan> _fullNameDict;
+ public:
+  OLMsg() {}
+  static void Init(int argc, char **argv);
+  static void Exit(int level);
+  /* static int GetCommRank(){ return _commRank; } */
+  /* static int GetCommSize(){ return _commSize; } */
+  /* static void SetCommRank(int val){ _commRank = val; } */
+  /* static void SetCommSize(int val){ _commSize = val; } */
+  /* static void SetCallback(GmshMessage *callback){ _callback = callback; } */
+  /* static void Barrier(); */
+  /* static int GetNumThreads(); */
+  /* static int GetMaxThreads(); */
+  /* static int GetThreadNum(); */
+  /* static void SetVerbosity(int val){ _verbosity = val; } */
+  /* static int GetVerbosity(){ return _verbosity; } */
+  /* static std::string GetLaunchDate(){ return _launchDate; } */
+  /* static std::string GetCommandLineArgs(){ return _commandLine; } */
+  static void Fatal(const char *fmt, ...);
+  static void Error(const char *fmt, ...);
+  static void Warning(const char *fmt, ...);
+  static void Info(const char *fmt, ...);
+  static void Direct(const char *fmt, ...);
+  static void Direct(int level, const char *fmt, ...);
+  static void StatusBar(int num, bool log, const char *fmt, ...);
+  static void Debug(const char *fmt, ...);
+  static void ProgressMeter(int n, int N, const char *fmt, ...);
+  static void ProgressMeter(int n, int N){ ProgressMeter(n, N, ""); }
+  static void SetProgressMeterStep(int step){ _progressMeterStep = step; }
+  static void ResetProgressMeter(){ if(!_commRank) _progressMeterCurrent = 0; }
+  static double &Timer(std::string str){ return _timers[str]; }
+  static void PrintTimers();
+  static void ResetErrorCounter(){ _warningCount = 0; _errorCount = 0; }
+  static void PrintErrorCounter(const char *title);
+  static double GetValue(const char *text, double defaultval);
+  static std::string GetString(const char *text, std::string defaultval);
+  static int GetAnswer(const char *question, int defaultval, const char *zero,
+                       const char *one, const char *two=0);
+  static void InitClient(std::string sockname);
+  static GmshClient *GetClient(){ return _client; }
+  static void FinalizeClient();
+  static void InitializeOnelab(const std::string &name,
+			       const std::string &sockname);
+  static void SetOnelabClient(onelab::client *client){ _onelabClient = client; }
+  static void SetOnelabNumber(std::string name, double val, bool visible=true);
+  static void GetOnelabNumber(std::string name, double *val);
+  static double GetOnelabNumber(std::string name);
+  static void SetOnelabString(std::string name, std::string val, bool visible=true);
+  static std::string GetOnelabString(std::string name);
+  static void SetOnelabAttributeString(std::string name,
+				       std::string attrib,std::string val);
+  static std::string GetOnelabAttributeString(std::string name,std::string attrib);
+  static std::string GetOnelabAttributeNumber(std::string name,
+					      std::string attrib);
+  //static std::vector<std::string> GetOnelabChoices(std::string name);
+  static bool GetOnelabChoices(std::string name, std::vector<std::string> &choices);
+  static void ExchangeOnelabParameter(const std::string &key,
+				      std::vector<double> &val,
+				      std::map<std::string,
+				      std::vector<double> > &fopt,
+				      std::map<std::string,
+				      std::vector<std::string> > &copt);
+  static void AddOnelabNumberChoice(std::string name, double val);
+
+  static void SendMergeFileRequest(const std::string &name);
+
+  // communication with loader
+  static onelab::remoteNetworkClient *loader;
+  static bool hasGmsh;
+  static int Synchronize_Down();
+  static int Synchronize_Up();
+  static void FinalizeOnelab();
+  static void recordFullName(const std::string &name);
+  static std::string obtainFullName(const std::string &name);
+};
+
+#endif
diff --git a/contrib/onelab/OnelabParser.cpp b/contrib/onelab/OnelabParser.cpp
new file mode 100644
index 0000000000..821ca83d84
--- /dev/null
+++ b/contrib/onelab/OnelabParser.cpp
@@ -0,0 +1,1344 @@
+#include "OnelabClients.h"
+#include <algorithm>
+#include "mathex.h"
+
+// reserved keywords for the onelab parser
+
+namespace olkey{ 
+  static std::string deflabel("onelab.tags");
+  static std::string label("OL."), comment("#"), separator(";");
+  static std::string line(label+"line");
+  static std::string begin(label+"block");
+  static std::string end(label+"endblock");
+  static std::string include(label+"include");
+  static std::string message(label+"msg");
+  static std::string showParam(label+"show");
+  static std::string dump(label+"dump");
+  static std::string ifcond(label+"if");
+  static std::string iftrue(label+"iftrue"), ifntrue(label+"ifntrue");
+  static std::string olelse(label+"else"), olendif(label+"endif");
+  static std::string getValue(label+"get");
+  static std::string mathex(label+"eval");
+  static std::string getRegion(label+"region");
+}
+
+int enclosed(const std::string &in, std::vector<std::string> &arguments,
+	     int &end){
+  // syntax: (arguments[Ø], arguments[1], ... , arguments[n])
+  // arguments[i] may contain parenthesis
+  int pos, cursor;
+  arguments.resize(0);
+  cursor=0;
+  if ( (pos=in.find("(",cursor)) == std::string::npos )
+     OLMsg::Fatal("Syntax error: <%s>",in.c_str());
+
+  if (pos>0){
+    std::cout << pos << in << std::endl;
+     OLMsg::Fatal("Syntax error: <%s>",in.c_str());
+  }
+  unsigned int count=1;
+  pos++; // skips '('
+  cursor = pos; 
+  do{
+    if(in[pos]=='(') count++;
+    else if(in[pos]==')') count--;
+    else if(in[pos]==',' && (count==1)) {
+      arguments.push_back(removeBlanks(in.substr(cursor,pos-cursor)));
+      if(count!=1)
+	OLMsg::Fatal("Syntax error: mismatched parenthesis <%s>",in.c_str());
+      cursor=pos+1; // skips ','
+    }
+    else if(in[pos]==';') 
+	OLMsg::Fatal("Syntax error: unterminated sentence <%s>",in.c_str());
+
+    pos++;
+  } while( count && (pos!=std::string::npos) );
+  // count is 0 when the closing brace is found. 
+
+  if(count)
+     OLMsg::Fatal("Syntax error: <%s>",in.c_str());
+  else
+    arguments.push_back(removeBlanks(in.substr(cursor,pos-1-cursor)));
+  end=pos;
+  return arguments.size();
+}
+
+int extractLogic(const std::string &in, std::vector<std::string> &arguments){
+  // syntax: ( argument[0], argument[1]\in{<,>,<=,>=,==,!=}, arguments[2])
+  int pos, cursor;
+  arguments.resize(0);
+  cursor=0;
+  if ( (pos=in.find("(",cursor)) == std::string::npos )
+     OLMsg::Fatal("Syntax error: <%s>",in.c_str());
+
+  unsigned int count=1;
+  pos++; // skips '('
+  cursor=pos; 
+  do{
+    if(in[pos]=='(') count++;
+    if(in[pos]==')') count--;
+    if( (in[pos]=='<') || (in[pos]=='=') || (in[pos]=='>') ){
+      arguments.push_back(removeBlanks(in.substr(cursor,pos-cursor)));
+      if(count!=1)
+	OLMsg::Fatal("Syntax error: <%s>",in.c_str());
+      cursor=pos;
+      if(in[pos+1]=='='){
+	arguments.push_back(in.substr(cursor,2));
+	pos++;
+      }
+      else{
+      	arguments.push_back(in.substr(cursor,1));
+      }
+      cursor=pos+1;
+    }
+    pos++;
+  } while( count && (pos!=std::string::npos) );
+  // count is 0 when the closing brace is found. 
+
+  if(count)
+    OLMsg::Fatal("Syntax error: mismatched parenthesis in <%s>",in.c_str());
+  else
+    arguments.push_back(removeBlanks(in.substr(cursor,pos-1-cursor)));
+
+  if((arguments.size()!=1) && (arguments.size()!=3))
+    OLMsg::Fatal("Syntax error: <%s>",in.c_str());
+  return arguments.size();
+}
+
+int extract(const std::string &in, std::string &paramName, 
+	    std::string &action, std::vector<std::string> &arguments){
+  // syntax: paramName.action( arg1, arg2, ... )
+  int pos, cursor;
+  cursor=0;
+  if ( (pos=in.find(".",cursor)) == std::string::npos )
+     OLMsg::Fatal("Syntax error: <%s>",in.c_str());
+  else
+    paramName.assign(sanitize(in.substr(cursor,pos-cursor)));
+  cursor = pos+1; // skips '.'
+  if ( (pos=in.find("(",cursor)) == std::string::npos )
+     OLMsg::Fatal("Syntax error: <%s>",in.c_str());
+  else
+    action.assign(sanitize(in.substr(cursor,pos-cursor)));
+  cursor = pos;
+  return enclosed(in.substr(cursor),arguments,pos);
+}
+
+bool extractRange(const std::string &in, std::vector<double> &arguments){
+  // syntax: a:b:c or a:b#n
+  int pos, cursor;
+  arguments.resize(0);
+  cursor=0;
+  if ( (pos=in.find(":",cursor)) == std::string::npos )
+     OLMsg::Fatal("Syntax error in range <%s>",in.c_str());
+  else{
+    arguments.push_back(atof(in.substr(cursor,pos-cursor).c_str()));
+  }
+  cursor = pos+1; // skips ':'
+  if ( (pos=in.find(":",cursor)) != std::string::npos ){
+    arguments.push_back(atof(in.substr(cursor,pos-cursor).c_str()));
+    arguments.push_back(atof(in.substr(pos+1).c_str()));
+  }
+  else if ( (pos=in.find("#",cursor)) != std::string::npos ){
+    arguments.push_back(atof(in.substr(cursor,pos-cursor).c_str()));
+    double NumStep = atof(in.substr(pos+1).c_str());
+    arguments.push_back((arguments[1]-arguments[0])/((NumStep==0)?1:NumStep));
+  }
+  else
+     OLMsg::Fatal("Syntax error in range <%s>",in.c_str());
+  return (arguments.size()==3);
+}
+
+std::string extractExpandPattern(const std::string& str){
+  int posa,posb;
+  posa=str.find_first_of("\"\'<");
+  posb=str.find_last_of("\"\'>");
+  std::string pattern=str.substr(posa+1,posb-posa-1);
+  posa=pattern.find("comma");
+  if(posa!=std::string::npos) 
+    pattern.replace(posa,5,",");
+  if(pattern.size()!=3)
+    OLMsg::Fatal("Incorrect expand pattern <%s>",
+	       str.c_str());
+  return pattern; 
+}
+
+std::string localSolverClient::longName(const std::string name){
+  std::set<std::string>::iterator it;
+  std::string fullName;
+  if((it = _parameters.find(name)) != _parameters.end())
+    fullName.assign(OLMsg::obtainFullName(*it));
+  else
+    fullName.assign(OLMsg::obtainFullName(name));
+  //std::cout << "Full name=<" << name << "> => <" << fullName << ">" << std::endl;
+  return fullName;
+}
+
+std::string localSolverClient::resolveGetVal(std::string line) {
+  std::vector<onelab::number> numbers;
+  std::vector<onelab::string> strings;
+  std::vector<std::string> arguments;
+  std::string buff;
+  int pos,pos0,cursor;
+
+  cursor=0;
+  while ( (pos=line.find(olkey::getValue,cursor)) != std::string::npos){
+    pos0=pos; // for further use
+    cursor = pos+olkey::getValue.length();
+    int NumArg=enclosed(line.substr(cursor),arguments,pos);
+    if(NumArg<1)
+      OLMsg::Fatal("Misformed %s statement: <%s>",
+		 olkey::getValue.c_str(),line.c_str());
+    std::string paramName=longName(arguments[0]);
+    get(numbers,paramName);
+    if (numbers.size()){
+      std::stringstream Num;
+      if(NumArg==1){
+	Num << numbers[0].getValue();
+	buff.assign(Num.str());
+      }
+      else if(NumArg==2){
+	std::string name, action;
+	std::vector<std::string> args;
+	extract(arguments[1],name,action,args);
+	if(!name.compare("choices")) { 
+	  std::vector<double> choices=numbers[0].getChoices();
+	  if(!action.compare("size")) {
+	    buff.assign(ftoa(choices.size()));
+	  }
+	  else if(!action.compare("begin")) {
+	    buff.assign(ftoa(*choices.begin()));
+	  }
+	  else if(!action.compare("rbegin")) {
+	    buff.assign(ftoa(*choices.rbegin()));
+	  }
+	  else if(!action.compare("comp")) {
+	    int i=atoi(args[0].c_str());
+	    if( (i>=0) && (i<choices.size()) )
+	      Num << choices[i];
+	    buff.assign(ftoa(choices[i]));
+	  }
+	  else if(!action.compare("expand")) {
+	    std::string pattern;
+	    pattern.assign(extractExpandPattern(args[0]));
+	    OLMsg::Info("Expand parameter <%s> with pattern <%s>",
+		      paramName.c_str(),pattern.c_str());
+	    buff.assign(1,pattern[0]);
+	    for(std::vector<double>::iterator it = choices.begin();
+		it != choices.end(); it++){
+	      if(it != choices.begin())
+		buff.append(1,pattern[1]);
+	      buff.append(ftoa(*it));
+	    }
+	    buff.append(1,pattern[2]);	  
+	  }
+	  else if(!action.compare("index")) {
+	    Num << numbers[0].getIndex();
+	    buff.assign(Num.str());
+	  }
+	  else
+	    OLMsg::Fatal("Unknown action <%s> in %s statement",
+		       action.c_str(),olkey::getValue.c_str());
+	}
+	else if(!name.compare("range")) {
+	  double stp, min, max;
+	  if( ((stp=numbers[0].getStep()) == 0) ||
+	      ((min=numbers[0].getMin()) ==-onelab::parameter::maxNumber()) ||
+	      ((max=numbers[0].getMax()) ==onelab::parameter::maxNumber()) )
+	    OLMsg::Fatal("Invalid range description for parameter <%s>",
+		       paramName.c_str());
+	  if(!action.compare("size")) {
+	    buff.assign(ftoa(fabs((max-min)/stp)));
+	  }
+	  else if(!action.compare("comp")) {
+	    int i= atof(args[0].c_str());
+	    if(stp > 0)
+		Num << min+i*stp;
+	    else if(stp < 0)
+	      Num << max-i*stp;
+	  }
+	  else if(!action.compare("expand")) {
+	  }
+	  else
+	    OLMsg::Fatal("Unknown action <%s> in %s statement",
+		       action.c_str(),olkey::getValue.c_str());
+	}
+      }
+    }
+    else{
+      get(strings,longName(paramName));
+      if (strings.size())
+	buff.assign(strings[0].getValue());
+      else
+	OLMsg::Fatal("resolveGetVal: unknown variable: <%s>",paramName.c_str());
+    }
+    line.replace(pos0,cursor+pos-pos0,buff); 
+    cursor=pos0+buff.length();
+  }
+
+  // Check now wheter the line contains OL.mathex and resolve them
+  cursor=0;
+  while ( (pos=line.find(olkey::mathex,cursor)) != std::string::npos){
+    int pos0=pos;
+    cursor=pos+olkey::mathex.length();
+    if(enclosed(line.substr(cursor),arguments,pos) != 1)
+      OLMsg::Fatal("Misformed %s statement: <%s>",
+		 olkey::mathex.c_str(),line.c_str());
+    //std::cout << "MathEx evaluates now <"<< arguments[0]<< "> " << std::endl;
+    smlib::mathex* mathExp = new smlib::mathex();
+    mathExp->expression(arguments[0]); 
+    double val=mathExp->eval();
+    //std::cout << "MathEx <" << arguments[0] << "> ="<< val << std::endl;
+    line.replace(pos0,cursor+pos-pos0,ftoa(val));
+  }
+
+  // Check now wheter the line still contains OL.
+  if ( (pos=line.find(olkey::label)) != std::string::npos)
+    OLMsg::Fatal("Unidentified onelab command in <%s>",line.c_str());
+
+  return line;
+}
+
+bool localSolverClient::resolveLogicExpr(std::vector<std::string> arguments) {
+  std::vector<onelab::number> numbers;
+  double val1, val2;
+  bool condition;
+
+  val1= atof( resolveGetVal(arguments[0]).c_str() );
+  if(arguments.size()==1)
+    return (bool)val1;
+
+  if(arguments.size()==3){
+    val2=atof( resolveGetVal(arguments[2]).c_str() );
+    if(!arguments[1].compare("<"))
+      condition = (val1<val2);
+    else if (!arguments[1].compare("<="))
+      condition = (val1<=val2);
+    else if (!arguments[1].compare(">"))
+      condition = (val1>val2);
+    else if (!arguments[1].compare(">="))
+      condition = (val1>=val2);
+    else if (!arguments[1].compare("=="))
+      condition = (val1==val2);   
+    else if (!arguments[1].compare("!="))
+      condition = (val1!=val2);
+  }
+
+  return condition;
+}
+
+void localSolverClient::parse_sentence(std::string line) { 
+  int pos,cursor,NumArg;
+  std::string name,action,path;
+  std::vector<std::string> arguments;
+  std::vector<onelab::number> numbers;
+  std::vector<onelab::string> strings;
+
+  cursor = 0;
+  while ( (pos=line.find(olkey::separator,cursor)) != std::string::npos){
+    std::string name, action;
+    extract(line.substr(cursor,pos-cursor),name,action,arguments);
+
+    if(!action.compare("number")) { 
+      double val;
+      // syntax: paramName.number(val,path,help,range(optional))
+      if((arguments.size()>1) && isPath(arguments[1]))
+	name.assign(arguments[1] + name);
+      _parameters.insert(name);
+      OLMsg::recordFullName(name);
+      get(numbers, name);
+      if(numbers.empty()){ 
+	numbers.resize(1);
+	numbers[0].setName(name);
+	if(arguments[0].empty())
+	  val=0;
+	else
+	  val=atof(resolveGetVal(arguments[0]).c_str());
+	numbers[0].setValue(val);
+      }
+      // parameters defined with no value are ReadOnly
+      // if(arguments[0].empty()) numbers[0].setReadOnly(1);
+
+      if(arguments.size()>2)
+	numbers[0].setLabel(arguments[2]);
+      if(arguments.size()>3){
+	std::vector<double> bounds;
+	if (extractRange(arguments[3],bounds)){
+	  numbers[0].setMin(bounds[0]);
+	  numbers[0].setMax(bounds[1]);
+	  numbers[0].setStep(bounds[2]);
+	}
+      }
+      set(numbers[0]);
+    }
+    else if(!action.compare("string")) { 
+      // syntax: paramName.string(val,path,help)
+      if((arguments.size()>1) && isPath(arguments[1]))
+	name.assign(arguments[1] + name); // append path
+      _parameters.insert(name);
+      OLMsg::recordFullName(name);
+      get(strings, name);
+      if(strings.empty()){
+	strings.resize(1);
+	strings[0].setName(name);
+	std::string val=resolveGetVal(arguments[0]);
+	strings[0].setValue(val);
+      }
+
+      // parameters defined with no value are ReadOnly
+      // if(arguments[0].empty()) strings[0].setReadOnly(1);
+
+      // choices list is reset
+      std::vector<std::string> choices;
+      strings[0].setChoices(choices);
+
+      if(arguments.size()>2) strings[0].setLabel(arguments[2]);
+      set(strings[0]);
+    }
+    else if(!action.compare("radioButton")) { 
+      // syntax: paramName.radioButton(val,path,label)
+      if(arguments[0].empty())
+	OLMsg::Fatal("No value given for param <%s>",name.c_str());
+      double val=atof(arguments[0].c_str());
+      if((arguments.size()>1) && isPath(arguments[1]))
+	name.assign(arguments[1] + name);
+      _parameters.insert(name);
+      OLMsg::recordFullName(name);
+      get(numbers, name);
+      if(numbers.size()){ 
+	val = numbers[0].getValue(); // use value from server
+      }
+      else{
+	numbers.resize(1);
+	numbers[0].setName(name);
+	numbers[0].setValue(val);
+      }
+      if(arguments.size()>2)
+	numbers[0].setLabel(arguments[2]);
+      std::vector<double> choices;
+      choices.push_back(0);
+      choices.push_back(1);
+      numbers[0].setChoices(choices);
+      set(numbers[0]);
+    }
+    else if(!action.compare("range")){ 
+      // set the range of an existing number
+      // syntax: paramName.range({a:b:c|a:b#n|min,max,step})
+      if(arguments[0].empty())
+	OLMsg::Fatal("No argument given for MinMax <%s>",name.c_str());
+      name.assign(longName(name));
+      get(numbers,name);
+      if(numbers.size()){ // parameter must exist
+	if(arguments.size()==1){
+	  std::vector<double> bounds;
+	  if (extractRange(arguments[1],bounds)){
+	    numbers[0].setMin(bounds[0]);
+	    numbers[0].setMax(bounds[1]);
+	    numbers[0].setStep(bounds[2]);
+	  }
+	}
+	else if(arguments.size()==3){
+	  numbers[0].setMin(atof(arguments[0].c_str()));
+	  numbers[0].setMax(atof(arguments[1].c_str()));
+	  numbers[0].setStep(atof(arguments[2].c_str()));
+	}
+	else
+	  OLMsg::Fatal("Wrong number of arguments for MinMax <%s>",name.c_str());
+      }
+      set(numbers[0]);
+    }
+    else if(!action.compare("resetChoices")){
+      name.assign(longName(name));
+      get(numbers,name);
+
+      if(numbers.size()){ // parameter must exist
+	std::vector<double> choices;
+	numbers[0].setChoices(choices);
+	std::map<double, std::string> valuelabels;
+	numbers[0].setValueLabels(valuelabels);
+	set(numbers[0]);
+      }
+      else{
+	get(strings,name);
+	if(strings.size()){
+	  std::vector<std::string> choices;
+	  strings[0].setChoices(choices);
+	  set(strings[0]);
+	}
+	else{
+	  OLMsg::Fatal("The parameter <%s> does not exist",name.c_str());
+	}
+      }
+    }
+    else if(!action.compare("addChoices")){
+      name.assign(longName(name));
+      get(numbers,name);
+      if(numbers.size()){ // parameter must exist
+	std::vector<double> choices=numbers[0].getChoices();
+	for(unsigned int i = 0; i < arguments.size(); i++){
+	  double val=atof(resolveGetVal(arguments[i]).c_str());
+	  //if(std::find(choices.begin(),choices.end(),val)==choices.end())
+	  choices.push_back(val);
+	}
+	numbers[0].setChoices(choices);
+	set(numbers[0]);
+      }
+      else{
+	get(strings,name);
+	if(strings.size()){
+	  std::vector<std::string> choices=strings[0].getChoices();
+	  for(unsigned int i = 0; i < arguments.size(); i++)
+	    if(std::find(choices.begin(),choices.end(),
+			 arguments[i])==choices.end())
+	      choices.push_back(arguments[i]);
+	  strings[0].setChoices(choices);
+	  set(strings[0]);
+	}
+	else{
+	  OLMsg::Fatal("The parameter <%s> does not exist",name.c_str());
+	}
+      }
+    }
+    else if(!action.compare("valueLabels")){
+      name.assign(longName(name));
+      get(numbers,name);
+      if(numbers.size()){ // parameter must exist
+	if(arguments.size() % 2)
+	  OLMsg::Fatal("Nb of labels does not match nb of choices for <%s>",
+		     name.c_str());
+	std::vector<double> choices=numbers[0].getChoices();
+	for(unsigned int i = 0; i < arguments.size(); i=i+2){
+	  double val=atof(resolveGetVal(arguments[i]).c_str());
+	  if(std::find(choices.begin(),choices.end(),val)==choices.end())
+	    choices.push_back(val);
+	  numbers[0].setValueLabel(val,arguments[i+1]);
+	}
+	numbers[0].setChoices(choices);
+	set(numbers[0]);
+      }
+      else
+	OLMsg::Fatal("The number <%s> does not exist",name.c_str());
+    }
+    else if(!action.compare("setValue")){ // force change on server
+      name.assign(longName(name));
+      get(numbers,name); 
+      if(numbers.size()){
+	if(arguments[0].empty())
+	  numbers[0].setValue(0);
+	else
+	  numbers[0].setValue(atof(resolveGetVal(arguments[0]).c_str()));
+	numbers[0].setReadOnly(1);
+	set(numbers[0]);
+      }
+      else{
+	get(strings,name); 
+	if(strings.size()){
+	  if(arguments[0].empty())
+	    strings[0].setValue("");
+	  else
+	    strings[0].setValue(arguments[0]);
+	  set(strings[0]);
+	}
+	else{
+	  OLMsg::Fatal("The parameter <%s> does not exist",name.c_str());
+	}
+      }
+    }
+    else if(!action.compare("setVisible")){
+      if(arguments[0].empty())
+	OLMsg::Fatal("Missing argument SetVisible <%s>",name.c_str());
+      name.assign(longName(name));
+      get(numbers,name); 
+      if(numbers.size()){ 
+	numbers[0].setVisible(atof(resolveGetVal(arguments[0]).c_str()));
+	set(numbers[0]);
+      }
+      else{
+	get(strings,name); 
+	if(strings.size()){
+	  strings[0].setVisible(atof(resolveGetVal(arguments[0]).c_str()));
+	  set(strings[0]);
+	}
+	else{
+	  OLMsg::Fatal("The parameter <%s> does not exist",name.c_str());
+	}
+      }
+    }
+    else if(!action.compare("setReadOnly")){
+      if(arguments[0].empty())
+	OLMsg::Fatal("Missing argument SetReadOnly <%s>",name.c_str());
+      name.assign(longName(name));
+      get(numbers,name); 
+      if(numbers.size()){ 
+	numbers[0].setReadOnly(atof(resolveGetVal(arguments[0]).c_str()));
+	set(numbers[0]);
+      }
+      else{
+	get(strings,name); 
+	if(strings.size()){
+	  strings[0].setReadOnly(atof(resolveGetVal(arguments[0]).c_str()));
+	  set(strings[0]);
+	}
+	else{
+	  OLMsg::Fatal("The parameter <%s> does not exist",name.c_str());
+	}
+      }
+    }
+    else if(!action.compare("layout")){
+      name.assign(longName(name));
+      get(numbers,name); 
+      if(numbers.size()){ 
+	numbers[0].setReadOnly(0);
+	numbers[0].setAttribute("Highlight","Ivory");
+	set(numbers[0]);
+      }
+      else{
+	get(strings,name); 
+	if(strings.size()){
+	  strings[0].setReadOnly(0);
+	  strings[0].setAttribute("Highlight","Ivory");
+	  set(strings[0]);
+	}
+	else{
+	  OLMsg::Fatal("The parameter <%s> does not exist",name.c_str());
+	}
+      }
+    }
+    else if(!action.compare("setAttribute")){
+      if(arguments.size() !=2 )
+	OLMsg::Fatal("SetAttribute <%s> needs two arguments %d", 
+		   name.c_str(), arguments.size());
+      name.assign(longName(name));
+      get(numbers,name); 
+      if(numbers.size()){ 
+	numbers[0].setAttribute(arguments[0].c_str(),
+				resolveGetVal(arguments[1]).c_str());
+	set(numbers[0]);
+      }
+      else{
+	get(strings,name); 
+	if(strings.size()){
+	  strings[0].setAttribute(arguments[0].c_str(),arguments[1].c_str());
+	  set(strings[0]);
+	}
+	else{
+	  OLMsg::Fatal("The parameter <%s> does not exist",name.c_str());
+	}
+      }
+    }
+    else{
+      client_sentence(name,action,arguments);
+    }
+    cursor=pos+1;
+  }
+}
+
+void localSolverClient::modify_tags(const std::string lab, const std::string com){
+  bool changed=false;
+  if(lab.compare(olkey::label) && lab.size()){
+    changed=true;
+    olkey::label.assign(lab);
+    olkey::line.assign(olkey::label+"line");
+    olkey::begin.assign(olkey::label+"block");
+    olkey::end.assign(olkey::label+"endblock");
+    olkey::include.assign(olkey::label+"include");
+    olkey::message.assign(olkey::label+"msg");
+    olkey::showParam.assign(olkey::label+"show");
+    olkey::dump.assign(olkey::label+"dump");
+    olkey::ifcond.assign(olkey::label+"if");
+    olkey::iftrue.assign(olkey::label+"iftrue");
+    olkey::ifntrue.assign(olkey::label+"ifntrue"); 
+    olkey::olelse.assign(olkey::label+"else");
+    olkey::olendif.assign(olkey::label+"endif");
+    olkey::getValue.assign(olkey::label+"get");
+    olkey::mathex.assign(olkey::label+"eval");
+    olkey::getRegion.assign(olkey::label+"region");
+  }
+  if(com.compare(olkey::comment) && com.size()){
+    changed=true;
+    olkey::comment.assign(com);
+  }
+
+  if(changed)
+    OLMsg::Info("Using now onelab tags <%s,%s>",
+	      olkey::label.c_str(), olkey::comment.c_str());
+}
+
+void localSolverClient::parse_oneline(std::string line, std::ifstream &infile) { 
+  int pos,cursor;
+  std::vector<std::string> arguments;
+  std::vector<onelab::number> numbers;
+  std::vector<onelab::string> strings;
+
+  if((pos=line.find_first_not_of(" \t"))==std::string::npos){
+    // empty line, skip
+  }
+  else if(!line.compare(pos,olkey::comment.size(),olkey::comment)){
+    // commented out line, skip
+  }
+  else if ( (pos=line.find(olkey::deflabel)) != std::string::npos){
+    // onelab.tags(label,comment);
+    // onelab.tags(); -> reset to default
+    cursor = pos+olkey::deflabel.length();
+    int NumArg=enclosed(line.substr(cursor),arguments,pos);
+    if((NumArg==1) && arguments[0].empty())
+      modify_tags("","");
+    else if(NumArg==2)
+      modify_tags(arguments[0],arguments[1]);
+    else
+      OLMsg::Fatal("Misformed <%s> statement", olkey::deflabel.c_str());
+  }
+  else if( (pos=line.find(olkey::begin)) != std::string::npos) {
+    // onelab.begin
+    if (!parse_block(infile))
+      OLMsg::Fatal("Misformed <%s> block <%s>",
+		 olkey::begin.c_str(),olkey::end.c_str());
+  }
+  else if ( (pos=line.find(olkey::iftrue)) != std::string::npos) {
+    // onelab.iftrue
+    cursor = pos+olkey::iftrue.length();
+    if(enclosed(line.substr(cursor),arguments,pos)<1)
+      OLMsg::Fatal("Misformed <%s> statement: (%s)",
+		 olkey::iftrue.c_str(),line.c_str());
+    bool condition = false;
+    get(strings,longName(arguments[0]));
+    if (strings.size())
+      condition= true;
+    else{
+      get(numbers,longName(arguments[0]));
+      if (numbers.size())
+	condition = (bool) numbers[0].getValue();
+      else
+	OLMsg::Fatal("Unknown parameter <%s> in <%s> statement",
+		   arguments[0].c_str(),olkey::iftrue.c_str());
+    }
+    if (!parse_ifstatement(infile,condition))
+      OLMsg::Fatal("Misformed <%s> statement: <%s>",
+		 olkey::iftrue.c_str(),arguments[0].c_str());
+  }
+  else if ( (pos=line.find(olkey::ifntrue)) != std::string::npos) {
+    // onelab.ifntrue
+    cursor = pos+olkey::ifntrue.length();
+    if(enclosed(line.substr(cursor),arguments,pos)<1)
+      OLMsg::Fatal("Misformed <%s> statement: (%s)",
+		 olkey::ifntrue.c_str(),line.c_str());
+    bool condition = false;
+    get(strings,longName(arguments[0]));
+    if (strings.size())
+      condition= true;
+    else{
+      get(numbers,longName(arguments[0]));
+      if (numbers.size())
+	condition = (bool) numbers[0].getValue();
+      else
+	OLMsg::Fatal("Unknown parameter <%s> in <%s> statement",
+		   arguments[0].c_str(),olkey::ifntrue.c_str());
+    }
+    std::cout << "cond=" << condition << std::endl;
+    if (!parse_ifstatement(infile,!condition))
+      OLMsg::Fatal("Misformed <%s> statement: <%s>",
+		 olkey::ifntrue.c_str(),arguments[0].c_str());
+  }
+  else if ( (pos=line.find(olkey::ifcond)) != std::string::npos) {
+    // onelab.ifcond
+    cursor = pos+olkey::ifcond.length();
+    int NumArgs=extractLogic(line.substr(cursor),arguments);
+    bool condition= resolveLogicExpr(arguments);
+    if (!parse_ifstatement(infile,condition)){
+      OLMsg::Fatal("Misformed %s statement: <%s>", 
+		 olkey::ifcond.c_str(), line.c_str());
+    }
+  }
+  else if ( (pos=line.find(olkey::include)) != std::string::npos) { 
+    // onelab.include
+    cursor = pos+olkey::include.length();
+    if(enclosed(line.substr(cursor),arguments,pos)<1)
+      OLMsg::Fatal("Misformed <%s> statement: (%s)",
+		 olkey::include.c_str(),line.c_str());
+    parse_onefile(arguments[0]);
+  }
+  else if ( (pos=line.find(olkey::message)) != std::string::npos) { 
+    // onelab.message
+    cursor = pos+olkey::message.length();
+    if(enclosed(line.substr(cursor),arguments,pos)<1)
+      OLMsg::Fatal("Misformed <%s> statement: (%s)",
+		 olkey::message.c_str(),line.c_str());
+    std::string msg = resolveGetVal(arguments[0]);
+    OLMsg::Info("%s",msg.c_str());
+  }
+  else if ( (pos=line.find(olkey::showParam)) != std::string::npos) { 
+    // onelab.showParam
+    cursor = pos+olkey::showParam.length();
+    if(enclosed(line.substr(cursor),arguments,pos)<1)
+      OLMsg::Fatal("Misformed <%s> statement: (%s)",
+		 olkey::showParam.c_str(),line.c_str());
+    std::string lname=longName(arguments[0]);
+    std::string msg;
+    get(numbers,lname);
+    if (numbers.size())
+      msg.assign(numbers[0].toChar());
+    else{
+      get(strings,lname);
+      if (strings.size())
+	msg.assign(strings[0].toChar());
+      else
+	OLMsg::Fatal("Unknown parameter <%s> in <%s> statement",
+		     arguments[0].c_str(),olkey::showParam.c_str());
+    }
+    for(unsigned int i = 0; i < msg.size(); i++)
+      if(msg[i] == onelab::parameter::charSep()) msg[i] = '|';
+    OLMsg::Info("%s",msg.c_str());
+  }
+  else if ( (pos=line.find(olkey::dump)) != std::string::npos) { 
+    // onelab.dump 
+    cursor = pos+olkey::dump.length();
+    if(enclosed(line.substr(cursor),arguments,pos)<1)
+      OLMsg::Fatal("Misformed <%s> statement: (%s)",
+		 olkey::dump.c_str(),line.c_str());
+    onelab::server::instance()->toFile(resolveGetVal(arguments[0]));
+  }
+  else if( isOnelabBlock() ||
+	 ( !isOnelabBlock() &&
+	   ((pos=line.find(olkey::line)) != std::string::npos)) ){
+    // either any other line within a onelabBlock or a line 
+    // introduced by a "onelab.line" tag not within a onelabBlock
+    std::string cmds="",cmd;
+    int posa, posb, NbLines=1;
+    do{
+      if( (pos=line.find(olkey::line)) != std::string::npos)
+	posa=pos + olkey::line.size();
+      else
+	posa=0; // skip tag 'olkey::line' if any
+
+      posb=line.find(olkey::comment); // skip trailing comments if any
+      if(posb==std::string::npos)
+	cmd.assign(line.substr(posa));
+      else
+	cmd.assign(line.substr(posa,posb-posa));
+      cmds.append(cmd);
+
+      //std::cout << "cmds=<" << cmds << ">" << std::endl;
+
+      // check whether "cmd" ends now with "olkey::separator"
+      posb=cmd.find_last_not_of(" \t")-olkey::separator.length()+1;
+      if(posb<0) posb=0;
+      if(cmd.compare(posb,olkey::separator.length(),olkey::separator)){
+	// append the next line
+	getline (infile,line);
+	if((pos=line.find_first_not_of(" \t"))==std::string::npos){
+	  OLMsg::Fatal("Empty line not allowed within a command <%s>",
+		     cmds.c_str());
+	}
+	else if(!line.compare(pos,olkey::comment.size(),olkey::comment)){
+	  OLMsg::Fatal("Comment lines not allowed within a command <%s>",
+		     cmds.c_str());
+	}
+	NbLines++; // command should not span over more than 10 lines
+      }
+      else
+	break;
+    } while (infile.good() && NbLines<=10);
+    if(NbLines>=10)
+      OLMsg::Fatal("Command <%s> should not span over more than 10 lines",
+		 cmds.c_str());
+    parse_sentence(cmds);
+  }
+  else if ( (pos=line.find(olkey::getValue)) != std::string::npos) {
+    // onelab.getValue: nothing to do
+  }
+  else if ( (pos=line.find(olkey::mathex)) != std::string::npos) {
+    // onelab.mathex: nothing to do
+  }
+  else if ( (pos=line.find(olkey::getRegion)) != std::string::npos) {
+    // onelab.getRegion: nothing to do
+  }
+  else if( (pos=line.find(olkey::label)) != std::string::npos) {
+      OLMsg::Fatal("Unknown ONELAB keyword in <%s>",line.c_str());
+  }
+  else{
+    // not a onelab line, skip
+  }
+}
+
+bool localSolverClient::parse_block(std::ifstream  &infile) { 
+  int pos;
+  std::string line;
+  openOnelabBlock();
+  while (infile.good()){
+    getline (infile,line);
+    if ((pos=line.find(olkey::end)) != std::string::npos){
+      closeOnelabBlock();
+      return true;
+    }
+    parse_oneline(line,infile);
+  }
+  return false;
+} 
+
+bool localSolverClient::parse_ifstatement(std::ifstream &infile, 
+					  bool condition) { 
+  int level, pos;
+  std::string line;
+
+  bool trueclause=true; 
+  level=1;
+  while ( infile.good() && level) {
+    getline (infile,line);
+    if ( ((pos=line.find(olkey::olelse)) != std::string::npos) && (level==1) ) 
+      trueclause=false;
+    else if ( (pos=line.find(olkey::olendif)) != std::string::npos) 
+      level--;
+    else if ( !(trueclause ^ condition) ) // xor bitwise operator
+      parse_oneline(line,infile);
+    else { // check for opening if statements
+      if ( (pos=line.find(olkey::iftrue)) != std::string::npos) 
+	level++; 
+      else if ( (pos=line.find(olkey::ifntrue)) != std::string::npos) 
+	level++; 
+      else if ( (pos=line.find(olkey::ifcond)) != std::string::npos) 
+	level++; 
+    }
+  }
+  return level?false:true ;
+} 
+
+void localSolverClient::parse_onefile(std::string fileName, bool mandatory) { 
+  int pos;
+  std::string fullName=getWorkingDir()+fileName;
+  std::ifstream infile(fullName.c_str());
+  if (infile.is_open()){
+    OLMsg::Info("Parse file <%s>",fullName.c_str());
+    while (infile.good()){
+      std::string line;
+      getline(infile,line);
+      parse_oneline(line,infile);
+    }
+    infile.close();
+  }
+  else
+    if(mandatory)
+      OLMsg::Fatal("The file <%s> does not exist",fullName.c_str());
+    else
+      OLMsg::Info("The file <%s> does not exist",fullName.c_str());
+} 
+
+bool localSolverClient::convert_ifstatement(std::ifstream &infile, std::ofstream &outfile, bool condition) { 
+  int level, pos;
+  std::string line;
+
+  bool trueclause=true; 
+  level=1;
+  while ( infile.good() && level) {
+    getline (infile,line);
+    if ( ((pos=line.find(olkey::olelse)) != std::string::npos) && (level==1) ) 
+      trueclause=false;
+    else if ( (pos=line.find(olkey::olendif)) != std::string::npos) 
+     level--;
+    else if ( !(trueclause ^ condition) ) // xor bitwise operator
+      convert_oneline(line,infile,outfile);
+    else { // check for opening if statements
+      if ( (pos=line.find(olkey::iftrue)) != std::string::npos) 
+	level++; 
+      else if ( (pos=line.find(olkey::ifntrue)) != std::string::npos) 
+	level++; 
+      else if ( (pos=line.find(olkey::ifcond)) != std::string::npos) 
+	level++; 
+    }
+  }
+  return level?false:true ;
+} 
+
+void localSolverClient::convert_oneline(std::string line, std::ifstream &infile, std::ofstream &outfile) { 
+  int pos,cursor;
+  std::vector<std::string> arguments;
+  std::vector<onelab::number> numbers;
+  std::vector<onelab::string> strings;
+  std::vector<onelab::region> regions;
+
+  if((pos=line.find_first_not_of(" \t"))==std::string::npos){
+    // empty line, we keep them
+    outfile << line << std::endl;  
+  }
+  else if(!line.compare(pos,olkey::comment.size(),olkey::comment)){
+    // commented out, skip the line
+  }
+  else if ( (pos=line.find(olkey::deflabel)) != std::string::npos){
+    // onelab.tags(label,comment,separator)
+    cursor = pos+olkey::deflabel.length();
+    int NumArg=enclosed(line.substr(cursor),arguments,pos);
+    if(NumArg==0)
+      modify_tags("","");
+    else if(NumArg==2)
+      modify_tags(arguments[0],arguments[1]);
+    else
+      OLMsg::Fatal("Misformed <%s> statement", olkey::deflabel.c_str());
+  }
+  else if( (pos=line.find(olkey::begin)) != std::string::npos) {
+    // onelab.begin
+    while (infile.good()){
+      getline (infile,line);
+      if( (pos=line.find(olkey::end)) != std::string::npos) return;
+    }
+    OLMsg::Fatal("Misformed <%s> block <%s>",
+	       olkey::begin.c_str(),olkey::end.c_str());
+  }
+  else if ( (pos=line.find(olkey::iftrue)) != std::string::npos) {
+    // onelab.iftrue
+    cursor = pos+olkey::iftrue.length();
+    // pos=line.find_first_of(')',cursor)+1;
+    // if(enclosed(line.substr(cursor,pos-cursor),arguments)<1)
+    if(enclosed(line.substr(cursor),arguments,pos)<1)
+      OLMsg::Fatal("Misformed <%s> statement: (%s)",
+		 olkey::iftrue.c_str(),line.c_str());
+    bool condition = false;
+    get(strings,longName(arguments[0]));
+    if (strings.size())
+      condition= true;
+    else{
+      get(numbers,longName(arguments[0]));
+      if (numbers.size())
+	condition = (bool) numbers[0].getValue();
+      else
+	OLMsg::Fatal("Unknown parameter <%s> in <%s> statement",
+		   arguments[0].c_str(),olkey::iftrue.c_str());
+    }
+    if (!convert_ifstatement(infile,outfile,condition))
+      OLMsg::Fatal("Misformed <%s> statement: %s",
+		 olkey::iftrue.c_str(),arguments[0].c_str());     
+  }
+  else if ( (pos=line.find(olkey::ifntrue)) != std::string::npos) {
+    // onelab.ifntrue
+    cursor = pos+olkey::ifntrue.length();
+    // pos=line.find_first_of(')',cursor)+1;
+    // if(enclosed(line.substr(cursor,pos-cursor),arguments)<1)    
+    if(enclosed(line.substr(cursor),arguments,pos)<1)
+      OLMsg::Fatal("Misformed <%s> statement: (%s)",
+		 olkey::ifntrue.c_str(),line.c_str());
+    bool condition = false;
+    get(strings,longName(arguments[0]));
+    if (strings.size())
+      condition= true;
+    else{
+      get(numbers,longName(arguments[0]));
+      if (numbers.size())
+	condition = (bool) numbers[0].getValue();
+      else
+	OLMsg::Fatal("Unknown parameter <%s> in <%s> statement",
+		   arguments[0].c_str(),olkey::ifntrue.c_str());
+    }
+    if (!convert_ifstatement(infile,outfile,!condition))
+      OLMsg::Fatal("Misformed <%s> statement: %s",
+		 olkey::ifntrue.c_str(),arguments[0].c_str());  
+  }
+  else if ( (pos=line.find(olkey::ifcond)) != std::string::npos) {
+    // onelab.ifcond
+    cursor = pos+olkey::ifcond.length();
+    int NumArgs=extractLogic(line.substr(cursor),arguments);
+    bool condition= resolveLogicExpr(arguments);
+    if (!convert_ifstatement(infile,outfile,condition))
+      OLMsg::Fatal("Misformed %s statement: <%s>", line.c_str());
+  }
+  else if ( (pos=line.find(olkey::include)) != std::string::npos) {
+    // onelab.include
+    cursor = pos+olkey::include.length();
+    if(enclosed(line.substr(cursor),arguments,pos)<1)
+      OLMsg::Fatal("Misformed <%s> statement: (%s)",
+		 olkey::include.c_str(),line.c_str());
+    convert_onefile(arguments[0],outfile);
+  }
+  else if ( (pos=line.find(olkey::message)) != std::string::npos) { 
+    // onelab.message
+    cursor = pos+olkey::message.length();
+    if(enclosed(line.substr(cursor),arguments,pos)<1)
+      OLMsg::Fatal("Misformed <%s> statement: (%s)",
+		 olkey::message.c_str(),line.c_str());
+    std::string msg = resolveGetVal(arguments[0]);
+    OLMsg::Info("%s",msg.c_str());
+  }
+  else if ( (pos=line.find(olkey::getValue)) != std::string::npos) {
+    outfile << resolveGetVal(line) << std::endl;
+  }
+  else if ( (pos=line.find(olkey::getRegion)) != std::string::npos) {
+    // onelab.getRegion, possibly several times on the line
+    cursor=0;
+    std::string buff,action;
+    while ( (pos=line.find(olkey::getRegion,cursor)) != std::string::npos){
+      int pos0=pos;
+      cursor = pos+olkey::getRegion.length();
+      int NumArg=enclosed(line.substr(cursor),arguments,pos);
+
+      if(NumArg>0){
+	std::string paramName;
+	paramName.assign("Gmsh/Physical groups/"+arguments[0]);
+	get(regions,paramName);
+	if (regions.size()){
+	  std::set<std::string> region;
+	  region=regions[0].getValue();
+
+	  if(NumArg>1)
+	    action.assign(arguments[1]);
+	  else
+	    action.assign("expand");
+
+	  if(!action.compare("size"))
+	    buff.assign(ftoa(region.size()));
+	  else if(!action.compare("expand")){
+	    std::string pattern;
+	    if(NumArg>=3)
+	      pattern.assign(extractExpandPattern(arguments[2]));
+	    else
+	      pattern.assign("   ");
+
+	    buff.assign(1,pattern[0]);
+	    for(std::set<std::string>::const_iterator it = region.begin();
+		it != region.end(); it++){
+	      if(it != region.begin())
+		buff.append(1,pattern[1]);
+	      buff.append((*it));
+	    }
+	    buff.append(1,pattern[2]);
+	  }
+	  else
+	    OLMsg::Fatal("Unknown %s action: <%s>",
+		       olkey::getRegion.c_str(), arguments[1].c_str());
+	}
+	else
+	  OLMsg::Fatal("Unknown region: <%s>",paramName.c_str());
+      }
+      else
+	OLMsg::Fatal("Misformed <%s> statement: (%s)",
+		   olkey::getRegion.c_str(),line.c_str());
+      line.replace(pos0,cursor+pos-pos0,buff);
+      cursor=pos0+buff.length();
+    }
+    outfile << line << std::endl; 
+  }
+  else if ( (pos=line.find(olkey::label)) != std::string::npos){
+    OLMsg::Fatal("Unidentified onelab command in <%s>",line.c_str());
+  }
+  else{
+    outfile << line << std::endl; 
+  }
+}
+
+void localSolverClient::convert_onefile(std::string fileName, std::ofstream &outfile) {
+  int pos;
+  std::string fullName=getWorkingDir()+fileName;
+  std::ifstream infile(fullName.c_str());
+  if (infile.is_open()){
+    OLMsg::Info("Convert file <%s>",fullName.c_str());
+    while ( infile.good() ) {
+      std::string line;
+      getline (infile,line);
+      convert_oneline(line,infile,outfile);
+    }
+    infile.close();
+  }
+  else
+    OLMsg::Fatal("The file %s cannot be opened",fullName.c_str());
+}
+
+void localSolverClient::client_sentence(const std::string &name, 
+					const std::string &action, 
+		       const std::vector<std::string> &arguments) {
+  OLMsg::Fatal("The action <%s> is unknown in this context",action.c_str());
+}
+
+void MetaModel::client_sentence(const std::string &name, 
+				const std::string &action, 
+		 const std::vector<std::string> &arguments){
+  std::vector<onelab::string> strings;
+
+  if(!action.compare("register")){
+    if(isTodo(REGISTER)){
+      // syntax name.register([interf...|encaps...]{,cmdl{host{,rdir}}}}) ;
+      if(!findClientByName(name)){
+	OLMsg::Info("Define client <%s>", name.c_str());
+	std::string cmdl="",host="",rdir="";
+	if(arguments.size()>=2) cmdl.assign(resolveGetVal(arguments[1]));
+	if(arguments.size()>=3) host.assign(resolveGetVal(arguments[2]));
+	if(arguments.size()>=4) rdir.assign(resolveGetVal(arguments[3]));
+	if(arguments.size()>=5) 
+	  OLMsg::Warning("Unused arguments for client <%s>", name.c_str());
+
+	if(cmdl.empty()) {
+	  // if argument 'cmdl' is empty, look for one on the server
+	  // (read beforehand from the file metamodel.ol.save)
+	  // otherwise register with empty cmdl
+	  // (this situation is dealt with later on)
+	  cmdl=OLMsg::GetOnelabString(name + "/CommandLine");
+	  if(cmdl.empty()) {
+	    onelab::string str;
+	    str.setName(name + "/CommandLine");
+	    str.setKind("file");
+	    str.setVisible(cmdl.empty());
+	    str.setAttribute("Highlight","Ivory");
+	    set(str);
+	  }
+	}
+	registerClient(name,resolveGetVal(arguments[0]),cmdl,host,rdir);
+      }
+      else
+	OLMsg::Error("Redefinition of client <%s>", name.c_str());
+    }
+  }
+  else if(!action.compare("commandLine")){
+    if(isTodo(REGISTER)){
+      if(arguments[0].size()){
+	OLMsg::SetOnelabString(name + "/CommandLine",arguments[0],false);
+	// get(strings, name);
+	// if(strings.empty()){
+	//   strings.resize(1);
+	//   strings[0].setName(name + "/CommandLine");
+	//   strings[0].setValue(arguments[0]);
+	//   strings[0].setKind("file");
+	//   strings[0].setVisible(false);
+	//   set(strings[0]);
+	// }
+      }
+      else
+	OLMsg::Error("No pathname given for client <%s>", name.c_str());
+    }
+  }
+  else if(!action.compare("workingDir")){
+    localSolverClient *c;
+    if(c=findClientByName(name))
+      c->setWorkingDir(c->getWorkingDir()+arguments[0]);
+    else
+      OLMsg::Fatal("Unknown client <%s>", name.c_str());
+  }
+  else if(!action.compare("active")){
+    localSolverClient *c;
+    if(arguments[0].size()){
+      if(c=findClientByName(name))
+	c->setActive(atof( resolveGetVal(arguments[0]).c_str() ));
+      else
+	OLMsg::Fatal("Unknown client <%s>", name.c_str());
+    }
+    else
+      OLMsg::Error("No argument for <%s.Active> statement", name.c_str());
+  }
+  else if(!action.compare("in")){
+    if(isTodo(REGISTER)){
+      get(strings, name + "/InputFiles");
+      if(strings.empty()){
+	strings.resize(1);
+	strings[0].setName(name + "/InputFiles");
+      }
+      strings[0].setKind("file");
+      strings[0].setVisible(false);
+      std::vector<std::string> choices;
+      if(arguments[0].size()){
+	for(unsigned int i = 0; i < arguments.size(); i++){
+	  std::string fileName=resolveGetVal(arguments[i]);
+	  if(std::find(choices.begin(),choices.end(),fileName)==choices.end())
+	  choices.push_back(fileName);
+	}
+	strings[0].setValue(resolveGetVal(arguments[0]));
+      }
+      strings[0].setChoices(choices);
+      set(strings[0]);
+    }
+  }
+  else if(!action.compare("out")){
+    if(isTodo(REGISTER)){
+      get(strings, name + "/OutputFiles");
+      if(strings.empty()){
+	strings.resize(1);
+	strings[0].setName(name + "/OutputFiles");
+      }
+      strings[0].setKind("file");
+      strings[0].setVisible(false);
+      std::vector<std::string> choices;
+      if(arguments[0].size()){
+	for(unsigned int i = 0; i < arguments.size(); i++){
+	  std::string fileName=resolveGetVal(arguments[i]);
+	  if(std::find(choices.begin(),choices.end(),fileName)==choices.end())
+	  choices.push_back(fileName);
+	}
+	strings[0].setValue(resolveGetVal(arguments[0]));
+      }
+      strings[0].setChoices(choices);
+      set(strings[0]);
+    }
+  }
+  else if(!action.compare("run")){
+    if(isTodo(REGISTER)){
+      if(arguments[0].size()){
+	get(strings, name + "/Arguments");
+	if(strings.empty()){
+	  strings.resize(1);
+	  strings[0].setName(name + "/Arguments");
+	}
+	strings[0].setValue(resolveGetVal(arguments[0]));
+	strings[0].setVisible(false);
+	set(strings[0]);
+      }
+    }
+    else if(isTodo(ANALYZE)){
+      localSolverClient *c;
+      if(c=findClientByName(name)) c->analyze();
+    }
+    else if(isTodo(COMPUTE)){
+      localSolverClient *c;
+      if(c=findClientByName(name)){
+	c->analyze();
+	c->compute();
+      }
+    }
+  }
+  else if(!action.compare("check")){
+    localSolverClient *c;
+    if(c=findClientByName(name)){
+      c->checkCommandLine();
+      c->analyze();
+    }
+    else
+      OLMsg::Fatal("Unknown client <%s>", name.c_str());
+  }
+  else if(!action.compare("up")){
+    if(arguments.size()%4==0){
+      if(isTodo(REGISTER)){
+	// predefine the parameters to upload
+	for(unsigned int i = 0; i < arguments.size(); i++){
+	  if(i%4==3){ 
+	    std::string str=resolveGetVal(arguments[i]);
+	    OLMsg::recordFullName(str);
+	    std::vector<onelab::number> numbers;
+	    get(numbers, str);
+	    if(numbers.empty()){ 
+	      numbers.resize(1);
+	      numbers[0].setName(str);
+	      numbers[0].setValue(0);
+	      set(numbers[0]);
+	    }
+	  }
+	}
+      }
+      else if(isTodo(COMPUTE)){
+	std::vector<std::string> choices;
+	for(unsigned int i = 0; i < arguments.size(); i++){
+	  std::string str=resolveGetVal(arguments[i]);
+	  OLMsg::recordFullName(str);
+	  choices.push_back(str);
+	}
+	localSolverClient *c;
+	if(c=findClientByName(name)) c->PostArray(choices);
+      }
+    }
+    else
+      OLMsg::Fatal("Wrong number of arguments <%d> for <%s>",
+		 arguments.size(), action.c_str());
+  }
+  else if(!action.compare("merge")){
+    if(isTodo(COMPUTE)){
+      std::vector<std::string> choices;
+      for(unsigned int i = 0; i < arguments.size(); i++){
+	choices.push_back(resolveGetVal(arguments[i]));
+      }
+      localSolverClient *c;
+      if(c=findClientByName(name)) c->GmshMerge(choices);
+    }
+  }
+  else
+    OLMsg::Fatal("Unknown action <%s>",action.c_str());
+}
diff --git a/contrib/onelab/loader.cpp b/contrib/onelab/loader.cpp
new file mode 100644
index 0000000000..5b37b49c23
--- /dev/null
+++ b/contrib/onelab/loader.cpp
@@ -0,0 +1,264 @@
+#include "StringUtils.h"
+#include "onelabUtils.h"
+#include "OnelabClients.h"
+
+onelab::server *onelab::server::_server = 0;
+
+std::string clientName;
+
+std::string stateToChar(){
+  std::vector<onelab::number> numbers;
+  std::ostringstream sstream;
+  onelab::server::instance()->get(numbers);
+  for(std::vector<onelab::number>::iterator it = numbers.begin();
+      it != numbers.end(); it++)
+    sstream << (*it).getValue() << '\t';
+  return sstream.str();
+}
+
+std::string showParamSpace(){
+  std::vector<std::string> parameters=onelab::server::instance()->toChar();
+  std::string db = "ONELAB parameter space: size="
+    + itoa(onelab::server::instance()->getNumParameters()) + "\n";
+  for(unsigned int i = 0; i < parameters.size(); i++)
+    db.append(parameters[i] + '\n');
+  for(unsigned int i = 0; i < db.size(); i++)
+    if(db[i] == onelab::parameter::charSep()) db[i] = ' ';
+  return db.c_str();
+}
+
+std::string showClientStatus(){
+  std::ostringstream sstream;
+  std::string name;
+  std::cout << "\nONELAB: Present state of the onelab clients" << std::endl;
+  for(onelab::server::citer it = onelab::server::instance()->firstClient();
+      it != onelab::server::instance()->lastClient(); it++){
+    name.assign(it->first);
+    sstream << "<" << onelab::server::instance()->getChanged(name) << "> "
+	    << name << std::endl;
+  }
+  return sstream.str();
+}
+
+void initializeLoop(const std::string &level)
+{
+  bool changed = false;
+  std::vector<onelab::number> numbers;
+  onelab::server::instance()->get(numbers);
+  for(unsigned int i = 0; i < numbers.size(); i++){
+
+    if(numbers[i].getAttribute("Loop") == level){
+      if(numbers[i].getChoices().size() > 1){
+	numbers[i].setIndex(0);
+	numbers[i].setValue(numbers[i].getChoices()[0]);
+	onelab::server::instance()->set(numbers[i]);
+	changed = true;
+      }
+      else if(numbers[i].getStep() > 0){
+	if(numbers[i].getMin() != -onelab::parameter::maxNumber()){
+	  numbers[i].setValue(numbers[i].getMin());
+	  onelab::server::instance()->set(numbers[i]);
+	  changed = true;
+	}
+      }
+      else if(numbers[i].getStep() < 0){
+	if(numbers[i].getMax() != onelab::parameter::maxNumber()){
+	  numbers[i].setValue(numbers[i].getMax());
+	  onelab::server::instance()->set(numbers[i]);
+	  changed = true;
+	}
+      }
+    }
+  }
+
+  // force this to make sure that we remesh, even if a mesh exists and
+  // we did not actually change a Gmsh parameter
+  if(changed)
+    onelab::server::instance()->setChanged(true, "Gmsh");
+}
+
+bool incrementLoop(const std::string &level)
+{
+  bool recompute = false, loop = false;
+  std::vector<onelab::number> numbers;
+  onelab::server::instance()->get(numbers);
+  for(unsigned int i = 0; i < numbers.size(); i++){
+    if(numbers[i].getAttribute("Loop") == level){
+      loop = true;
+
+      if(numbers[i].getChoices().size() > 1){
+	int j = numbers[i].getIndex() + 1;
+	if((j >= 0) && (j < (int)numbers[i].getChoices().size())){
+	  numbers[i].setValue(numbers[i].getChoices()[j]);
+	  numbers[i].setIndex(j);
+	  onelab::server::instance()->set(numbers[i]);
+	  OLMsg::Info("Recomputing with %dth choice %s=%g", j,
+		    numbers[i].getName().c_str(), numbers[i].getValue());
+	  recompute = true;
+	}
+      }
+      else if(numbers[i].getStep() > 0){
+	if(numbers[i].getMax() != onelab::parameter::maxNumber() &&
+	   numbers[i].getValue() < numbers[i].getMax()){
+	  numbers[i].setValue(numbers[i].getValue() + numbers[i].getStep());
+	  onelab::server::instance()->set(numbers[i]);
+	  OLMsg::Info("Recomputing with new step %s=%g",
+		    numbers[i].getName().c_str(), numbers[i].getValue());
+	  recompute = true;
+	}
+      }
+      else if(numbers[i].getStep() < 0){
+	if(numbers[i].getMin() != -onelab::parameter::maxNumber() &&
+	   numbers[i].getValue() > numbers[i].getMin()){
+	  numbers[i].setValue(numbers[i].getValue() + numbers[i].getStep());
+	  onelab::server::instance()->set(numbers[i]);
+	  OLMsg::Info("Recomputing with new step %s=%g",
+		    numbers[i].getName().c_str(), numbers[i].getValue());
+	  recompute = true;
+	}
+      }
+    }
+  }
+
+  if(loop && !recompute) // end of this loop level
+    initializeLoop(level);
+
+  return recompute;
+}
+
+void initializeLoops()
+{
+  initializeLoop("1");
+  initializeLoop("2");
+  initializeLoop("3");
+}
+
+bool incrementLoops()
+{
+  bool ret = false;
+  if(incrementLoop("3"))      ret = true;
+  else if(incrementLoop("2")) ret = true;
+  else if(incrementLoop("1")) ret = true;
+  return ret;
+}
+
+bool menu() {
+  int choice, counter1=0, counter2=0;
+  std::vector<onelab::number> numbers;
+  std::vector<onelab::string> strings;
+
+  do {
+    std::cout << "\nONELAB: menu" << std::endl ;
+    std::cout << " 1- View parameter space\n 2- Client status\n 3- Set value\n 4- Analyze\n 5- Compute\n 6- Loop\n 7- Quit metamodel" << std::endl;
+    choice=0;
+    std::string mystr;
+    while( (choice<1 || choice>7) && ++counter1<10 ) {
+      std::cout << "\nONELAB: your choice? ";
+      std::getline (std::cin, mystr);
+      std::stringstream myStream(mystr);
+      if (myStream >> choice) break;
+      std::cout << "Invalid choice" << std::endl;
+    }
+    std::cout << "Your choice is <" << choice << ">" << std::endl;
+
+    if (choice==1){
+      std::cout << showParamSpace();
+      choice=0;
+    }
+    if (choice==2){
+      std::cout << showClientStatus();
+      choice=0;
+    }
+    else if (choice==3){
+      std::string name;
+      std::cout << "ONELAB: Variable name? "; std::cin >> name;
+      onelab::server::instance()->get(numbers,name);
+      if (numbers.size()) {
+	float fval;
+	std::cout << "ONELAB: Value? "; std::cin >> fval;
+	numbers[0].setValue(fval);
+	bool allowed = onelab::server::instance()->set(numbers[0]);
+      }
+      else{
+	onelab::server::instance()->get(strings,name);
+	if (strings.size()) {
+	  std::string sval;
+	  std::cout << "ONELAB: Value? "; std::cin >> sval;
+	  strings[0].setValue(sval);
+	  onelab::server::instance()->set(strings[0]);
+	}
+	else
+	  std::cout << "ONELAB: The variable " << name
+		    << " is not defined" << std::endl;
+      }
+      choice=0;
+    }
+    else if (choice==4){
+      metamodel(ANALYZE);
+      choice=0;
+    }
+    else if (choice==5){
+      metamodel(COMPUTE);
+      choice=0;
+    }
+    else if (choice==6){
+      initializeLoops();
+      do{
+	metamodel(COMPUTE);
+      }while(incrementLoops());
+      choice=0;
+    }
+    else if (choice==7)
+      exit(1);
+    else
+      choice=0;
+  } while(!choice && ++counter2<20);
+}
+
+void PrintUsage(const char *name){
+  printf("\nUsage:       %s [-a -i] modelName\n", name);
+  exit(1);
+}
+
+int main(int argc, char *argv[]){
+  bool launchMenu=false;
+  parseMode todo=COMPUTE;
+  int i = 1;
+
+  clientName.assign("meta");
+  OLMsg::loader = new onelab::remoteNetworkClient(clientName, "");
+  // OLMsg::_onelabclient is a onelab:LocalClient independent of MetaModel
+  OLMsg::InitializeOnelab("onelab","");
+
+
+  while(i < argc) {
+    if(argv[i][0] == '-') {
+      if(!strcmp(argv[i] + 1, "a")) {
+        i++;
+	todo=ANALYZE;
+      }
+      else if(!strcmp(argv[i] + 1, "i")) {
+	i++;
+	launchMenu=true;
+      }
+    }
+    else {
+      std::string caseName=argv[i];
+      if(caseName.size()){
+	modelName.assign(SplitFileName(caseName)[1]);
+	workingDir.assign(SplitFileName(caseName)[0]);
+      }
+      else
+	OLMsg::Fatal("No valid input model name.");
+      i++;
+    }
+  }
+
+  if(launchMenu)
+    menu();
+  else
+    metamodel(todo);
+
+  OLMsg::FinalizeOnelab();
+}
+
diff --git a/contrib/onelab/metamodel.cpp b/contrib/onelab/metamodel.cpp
new file mode 100644
index 0000000000..818d31fa4a
--- /dev/null
+++ b/contrib/onelab/metamodel.cpp
@@ -0,0 +1,56 @@
+#include "OnelabClients.h"
+#include "metamodel.h"
+
+void initializeMetamodel(onelab::client *client)
+{
+  OLMsg::SetOnelabClient(client);
+}
+
+int metamodel(const std::string &action){
+
+  parseMode todo;
+  if(action == "check"){
+    todo = ANALYZE;
+  }
+  else if(action == "compute"){
+    todo = COMPUTE;
+  }
+  else{
+    todo = STOP;
+  }
+
+  std::string modelName = OLMsg::GetOnelabString("Arguments/FileName");
+  std::string workingDir = OLMsg::GetOnelabString("Arguments/WorkingDir");
+  std::string clientName = "meta";
+
+  MetaModel *myModel =
+    new MetaModel(clientName, workingDir, clientName, modelName);
+  myModel->setTodo(todo);
+
+  if(OLMsg::GetOnelabNumber("LOGFILES")){
+    freopen("stdout.txt","w",stdout);
+    freopen("stderr.txt","w",stderr);
+  }
+
+  //if not all clients have valid commandlines -> exit metamodel
+  if(!myModel->checkCommandLines())
+    myModel->setTodo(EXIT);
+
+  if( myModel->isTodo(EXIT)){
+    // exit metamodel
+  }
+  else if( myModel->isTodo(INITIALIZE)){
+    myModel->initialize();
+  }
+  else if( myModel->isTodo(ANALYZE)){
+    myModel->analyze();
+  }
+  else if( myModel->isTodo(COMPUTE)){
+    myModel->compute();
+  }
+  else
+    OLMsg::Fatal("Main: Unknown Action <%d>", todo);
+
+  delete myModel;
+  OLMsg::Info("Leave metamodel");
+}
diff --git a/contrib/onelab/metamodel.h b/contrib/onelab/metamodel.h
new file mode 100644
index 0000000000..72104246b2
--- /dev/null
+++ b/contrib/onelab/metamodel.h
@@ -0,0 +1,6 @@
+#include <string>
+
+namespace onelab{ class client; }
+
+int metamodel(const std::string &todo);
+void initializeMetamodel(onelab::client *);
-- 
GitLab