diff --git a/services/histserv/app/Application.cxx b/services/histserv/app/Application.cxx
index a391c615df5650611825e3dfbbbd44be95075a0e..a32af9d323cf450338f04bbe57700afe3d77de56 100644
--- a/services/histserv/app/Application.cxx
+++ b/services/histserv/app/Application.cxx
@@ -1,6 +1,6 @@
-/* Copyright (C) 2023 Facility for Antiproton and Ion Research in Europe, Darmstadt
+/* Copyright (C) 2023-2024 Facility for Antiproton and Ion Research in Europe, Darmstadt
    SPDX-License-Identifier: GPL-3.0-only
-   Authors: Pierre-Alain Loizeau [committer] */
+   Authors: Pierre-Alain Loizeau [committer], Sergei Zharko */
 
 #include "Application.h"
 
@@ -38,63 +38,69 @@ std::mutex mtx;
 namespace b_io = boost::iostreams;
 namespace b_ar = boost::archive;
 
-namespace cbm::services::histserv
-{
-  // -----   Constructor   ---------------------------------------------------------------------------------------------
-  Application::Application(ProgramOptions const& opt) : fOpt(opt)
-  {
-    /// Read options from executable
-    LOG(info) << "Options for Application:";
-    LOG(info) << " Input ZMQ channel: " << fOpt.ComChan();
-    LOG(info) << " HTTP server port:  " << fOpt.HttpPort();
-    if ("" != fOpt.HistoFile()) {  //
-      LOG(info) << " Output filename:   " << fOpt.HistoFile() << (fOpt.Overwrite() ? " (in overwrite mode)" : "");
-    }
-
-    /// FIXME: SOMETHING_To_Replace_FairMQ!!!!!!!!!!!!!
-    /// FIXME: Initialize communication channels of SOMETHING_To_Replace_FairMQ
-    /// FIXME: Link channel to method in order to process received messages
-    // fZmqSocket.set(zmq::sockopt::rcvhwm, int(hwm));  // FIXME: need for HWM?
-    fZmqSocket.set(zmq::sockopt::rcvtimeo, fOpt.ComChanZmqRcvTo());  // Timeout in ms to avoid stuck in loop!
-    fZmqSocket.bind(fOpt.ComChan().c_str());  // This side "binds" the socket => Other side should connect!!!!
-
-    fServer = new THttpServer(Form("http:%u", fOpt.HttpPort()));
-    /// To avoid the server sucking all Histos from gROOT when no output file is used
-    fServer->GetSniffer()->SetScanGlobalDir(kFALSE);
-    const char* jsrootsys = gSystem->Getenv("JSROOTSYS");
-    if (!jsrootsys) jsrootsys = gEnv->GetValue("HttpServ.JSRootPath", jsrootsys);
-
-    fUiCmdActor = std::make_unique<UiCmdActor>();
-    fServer->Register("/", fUiCmdActor.get());
-    fServer->Hide("/UiCmdActor");
-
-    fServer->RegisterCommand("/Reset_Hist", "/UiCmdActor/->SetResetHistos()");
-    fServer->RegisterCommand("/Save_Hist", "/UiCmdActor/->SetSaveHistos()");
-    fServer->RegisterCommand("/Stop_Server", "/UiCmdActor/->SetServerStop()");
-
-    /*
-    fServer->RegisterCommand("/Reset_Hist", "this->ResetHistograms()");
-    fServer->RegisterCommand("/Save_Hist", "this->SaveHistograms()");
-    */
-
-    fServer->Restrict("/Reset_Hist", "allow=admin");
-    fServer->Restrict("/Save_Hist", "allow=admin");
-    fServer->Restrict("/Stop_Server", "allow=admin");
+using cbm::services::histserv::Application;
 
-
-    LOG(info) << "JSROOT location: " << jsrootsys;
+// ---------------------------------------------------------------------------------------------------------------------
+//
+Application::Application(ProgramOptions const& opt) : fOpt(opt)
+{
+  /// Read options from executable
+  LOG(info) << "Options for Application:";
+  LOG(info) << " Input ZMQ channel: " << fOpt.ComChan();
+  LOG(info) << " HTTP server port:  " << fOpt.HttpPort();
+  if ("" != fOpt.HistoFile()) {  //
+    LOG(info) << " Output filename:   " << fOpt.HistoFile() << (fOpt.Overwrite() ? " (in overwrite mode)" : "");
   }
-  // -------------------------------------------------------------------------------------------------------------------
 
-
-  // -----   Main Loop   -----------------------------------------------------------------------------------------------
-  void Application::Exec()
-  {
-    fStopThread = false;
-    fThread     = std::thread(&Application::UpdateHttpServer, this);
-    while (!(fUiCmdActor->GetServerStop())) {  //
+  /// FIXME: SOMETHING_To_Replace_FairMQ!!!!!!!!!!!!!
+  /// FIXME: Initialize communication channels of SOMETHING_To_Replace_FairMQ
+  /// FIXME: Link channel to method in order to process received messages
+  // fZmqSocket.set(zmq::sockopt::rcvhwm, int(hwm));  // FIXME: need for HWM?
+  fZmqSocket.set(zmq::sockopt::rcvtimeo, fOpt.ComChanZmqRcvTo());  // Timeout in ms to avoid stuck in loop!
+  fZmqSocket.bind(fOpt.ComChan().c_str());  // This side "binds" the socket => Other side should connect!!!!
+
+  fServer = new THttpServer(Form("http:%u", fOpt.HttpPort()));
+  /// To avoid the server sucking all Histos from gROOT when no output file is used
+  fServer->GetSniffer()->SetScanGlobalDir(kFALSE);
+  const char* jsrootsys = gSystem->Getenv("JSROOTSYS");
+  if (!jsrootsys) jsrootsys = gEnv->GetValue("HttpServ.JSRootPath", jsrootsys);
+
+  fUiCmdActor = std::make_unique<UiCmdActor>();
+  fServer->Register("/", fUiCmdActor.get());
+  fServer->Hide("/UiCmdActor");
+
+  fServer->RegisterCommand("/Reset_Hist", "/UiCmdActor/->SetResetHistos()");
+  fServer->RegisterCommand("/Save_Hist", "/UiCmdActor/->SetSaveHistos()");
+  fServer->RegisterCommand("/Stop_Server", "/UiCmdActor/->SetServerStop()");
+
+  /*
+  fServer->RegisterCommand("/Reset_Hist", "this->ResetHistograms()");
+  fServer->RegisterCommand("/Save_Hist", "this->SaveHistograms()");
+  */
+
+  fServer->Restrict("/Reset_Hist", "allow=admin");
+  fServer->Restrict("/Save_Hist", "allow=admin");
+  fServer->Restrict("/Stop_Server", "allow=admin");
+
+  // Provide signal handling for external interruptions
+  // NOTE: SZh 02.04.2024:
+  //    This function is needed for ZMQ to throw an exception (zmq::error_t) on the interrupt signal. It seems, that
+  //    the actual body of the function does not matter. This behaviour is not understood.
+  signal(SIGINT, [](int) {});
+
+  LOG(info) << "JSROOT location: " << jsrootsys;
+}
+
+// ---------------------------------------------------------------------------------------------------------------------
+//
+void Application::Exec()
+{
+  fStopThread = false;
+  fThread     = std::thread(&Application::UpdateHttpServer, this);
+  LOG(info) << "Listening to ZMQ messages ...";
+  while (!(fUiCmdActor->GetServerStop())) {  //
+    try {
       /// Infinite loop, this is a service which should survive until told otherwise after all
-
       /// FIXME: Start listening to <SOMETHING?!?> to receive histograms and configuration
       /// FIXME: handle signals from OS/console
       /* Jan suggestion with zmq_addon CPP interface */
@@ -113,96 +119,153 @@ namespace cbm::services::histserv
         LOG(error) << "Invalid number of message parts received: should be either 1 or more than 3 vs " << *ret;
       }
     }
+    catch (const zmq::error_t& err) {
+      if (err.num() == EINTR) {
+        // FIXME: SZh: Are the socket and the context finished properly?
+        LOG(info) << "Histogram server execution was interrupted by user. Finishing application";
+        break;
+      }
+      else {
+        throw err;
+      }
+    }
   }
-  // -------------------------------------------------------------------------------------------------------------------
+}
 
-  // -----   Constructor   ---------------------------------------------------------------------------------------------
-  Application::~Application()
-  {
-    SaveHistograms();
-    fStopThread = true;
-    fThread.join();
-    SaveHistograms();
+// ---------------------------------------------------------------------------------------------------------------------
+//
+Application::~Application()
+{
+  SaveHistograms();
+  fStopThread = true;
+  fThread.join();
+  SaveHistograms();
+}
+
+// ---------------------------------------------------------------------------------------------------------------------
+//
+void Application::UpdateHttpServer()
+{
+  /// This is needed to have a reactive GUI independently of histogram updates reception
+  while (!fStopThread) {
+    std::this_thread::sleep_for(std::chrono::milliseconds(10));
+    std::lock_guard<std::mutex> lk(mtx);
+
+    fServer->ProcessRequests();
+
+    /// TODO: control flags communication from histo server to histograms sources?
+    /// Idea: 1 req channel (per process or not, mixup?), polling every N TS and/or M s
+    if (fUiCmdActor->GetResetHistos()) {
+      LOG(info) << "Reset Monitor histos ";
+      ResetHistograms();
+      fUiCmdActor->SetResetHistos(false);
+    }  // if( fUiCmdActor->GetResetHistos() )
+
+    if (fUiCmdActor->GetSaveHistos()) {
+      LOG(info) << "Save All histos & canvases";
+      SaveHistograms();
+      fUiCmdActor->SetSaveHistos(false);
+    }  // if( fUiCmdActor->GetSaveHistos() )
   }
-  // -------------------------------------------------------------------------------------------------------------------
-
-  // -----   Server update background thread   -------------------------------------------------------------------------
-  void Application::UpdateHttpServer()
-  {
-    /// This is needed to have a reactive GUI independently of histogram updates reception
-    while (!fStopThread) {
-      std::this_thread::sleep_for(std::chrono::milliseconds(10));
-      std::lock_guard<std::mutex> lk(mtx);
+}
 
-      fServer->ProcessRequests();
-
-      /// TODO: control flags communication from histo server to histograms sources?
-      /// Idea: 1 req channel (per process or not, mixup?), polling every N TS and/or M s
-      if (fUiCmdActor->GetResetHistos()) {
-        LOG(info) << "Reset Monitor histos ";
-        ResetHistograms();
-        fUiCmdActor->SetResetHistos(false);
-      }  // if( fUiCmdActor->GetResetHistos() )
-
-      if (fUiCmdActor->GetSaveHistos()) {
-        LOG(info) << "Save All histos & canvases";
-        SaveHistograms();
-        fUiCmdActor->SetSaveHistos(false);
-      }  // if( fUiCmdActor->GetSaveHistos() )
+// ---------------------------------------------------------------------------------------------------------------------
+//
+bool Application::ReceiveData(zmq::message_t& msg)
+{
+  LOG(debug) << "Application::ReceiveData => Processing histograms update";
+
+  /// FIXME: Something to replace FairMQ and extract the histograms!!!!
+  /// FIXME: Need something to replace the ROOT serializer which allowed to have any of TH1x, TH2x, TH3x or TProfile
+  /// FIXME: Need something to replace the TObjArray which allowed to have a mix of of TH1x, TH2x, TH3x or TProfile
+  b_io::basic_array_source<char> device(static_cast<char*>(msg.data()), msg.size());
+  b_io::stream<b_io::basic_array_source<char>> s(device);
+  b_ar::binary_iarchive iarch(s);
+
+  cbm::algo::qa::HistogramContainer vHist;
+  iarch >> vHist;
+
+  /// copied from CbmTaskDigiEventQa::ToTH1D
+  /// FIXME: Should be placed in a tools/interface/whatever library with all similar functions!!
+  /// FIXME: Reverse OP need to be implemented + CI unit tests for back and forth in each direction (ROOT <-> Algo)
+  /// FIXME: Lead to "Warning in <TROOT::Append>: Replacing existing TH1: xxxxxx (Potential memory leak)."
+
+  // Collect histograms
+  for (auto& source : vHist.fvH1) {
+    TH1* result = cbm::qa::OnlineInterface::ROOTHistogram(source);
+    if (!ReadHistogram<TH1>(result)) {  //
+      return false;
     }
+    delete result;
   }
-  // -------------------------------------------------------------------------------------------------------------------
-
-  // -----   Server update background thread   -------------------------------------------------------------------------
-  bool Application::ReceiveData(zmq::message_t& msg)
-  {
-    LOG(debug) << "Application::ReceiveData => Processing histograms update";
-
-    /// FIXME: Something to replace FairMQ and extract the histograms!!!!
-    /// FIXME: Need something to replace the ROOT serializer which allowed to have any of TH1x, TH2x, TH3x or TProfile
-    /// FIXME: Need something to replace the TObjArray which allowed to have a mix of of TH1x, TH2x, TH3x or TProfile
-    b_io::basic_array_source<char> device(static_cast<char*>(msg.data()), msg.size());
-    b_io::stream<b_io::basic_array_source<char>> s(device);
-    b_ar::binary_iarchive iarch(s);
-
-    cbm::algo::qa::HistogramContainer vHist;
-    iarch >> vHist;
-
-    /// copied from CbmTaskDigiEventQa::ToTH1D
-    /// FIXME: Should be placed in a tools/interface/whatever library with all similar functions!!
-    /// FIXME: Reverse OP need to be implemented + CI unit tests for back and forth in each direction (ROOT <-> Algo)
-    /// FIXME: Lead to "Warning in <TROOT::Append>: Replacing existing TH1: xxxxxx (Potential memory leak)."
-
-    // Collect histograms
-    for (auto& source : vHist.fvH1) {
-      TH1* result = cbm::qa::OnlineInterface::ROOTHistogram(source);
-      if (!ReadHistogram<TH1>(result)) {  //
-        return false;
-      }
-      delete result;
+  for (auto& source : vHist.fvH2) {
+    TH1* result = cbm::qa::OnlineInterface::ROOTHistogram(source);
+    if (!ReadHistogram<TH1>(result)) {  //
+      return false;
     }
-    for (auto& source : vHist.fvH2) {
-      TH1* result = cbm::qa::OnlineInterface::ROOTHistogram(source);
-      if (!ReadHistogram<TH1>(result)) {  //
-        return false;
-      }
-      delete result;
+    delete result;
+  }
+  for (auto& source : vHist.fvP1) {
+    TH1* result = cbm::qa::OnlineInterface::ROOTHistogram(source);
+    if (!ReadHistogram<TH1>(result)) {  //
+      return false;
     }
-    for (auto& source : vHist.fvP1) {
-      TH1* result = cbm::qa::OnlineInterface::ROOTHistogram(source);
-      if (!ReadHistogram<TH1>(result)) {  //
-        return false;
-      }
-      delete result;
+    delete result;
+  }
+  for (auto& source : vHist.fvP2) {
+    TH1* result = cbm::qa::OnlineInterface::ROOTHistogram(source);
+    if (!ReadHistogram<TH1>(result)) {  //
+      return false;
     }
-    for (auto& source : vHist.fvP2) {
-      TH1* result = cbm::qa::OnlineInterface::ROOTHistogram(source);
-      if (!ReadHistogram<TH1>(result)) {  //
-        return false;
+    delete result;
+  }
+
+
+  /// If new histos received, try to prepare as many canvases as possible
+  /// Should be expensive on start and cheap afterward
+  if (!fbAllCanvasReady) {
+    LOG(debug) << "Application::ReceiveData => Checking for canvases updates";
+    for (uint32_t uCanv = 0; uCanv < fvpsCanvasConfig.size(); ++uCanv) {
+      /// Jump canvases already ready
+      if (fvbCanvasReady[uCanv]) {  //
+        continue;
       }
-      delete result;
-    }
 
+      /// Now come the expensive part as we unpack its config and check each histo
+      fvbCanvasReady[uCanv] = PrepareCanvas(uCanv);
+    }  // for( uint32_t uCanv = 0; uCanv < fvpsCanvasConfig.size(); ++uCanv )
+  }    // if( !fbAllCanvasReady )
+
+  /*
+  TObject* tempObject = nullptr;
+  if (TString(tempObject->ClassName()).EqualTo("TObjArray")) {
+    std::lock_guard<std::mutex> lk(mtx);
+    TObjArray* arrayHisto = static_cast<TObjArray*>(tempObject);
+    for (Int_t i = 0; i < arrayHisto->GetEntriesFast(); i++) {
+      TObject* pObj = arrayHisto->At(i);
+
+      if (nullptr != dynamic_cast<TProfile*>(pObj)) {
+        if (!ReadHistogram<TProfile>(dynamic_cast<TProfile*>(pObj))) {  //
+          return false;
+        }
+      }  // if( nullptr != dynamic_cast< TProfile *>( pObj ) )
+      else if (nullptr != dynamic_cast<TH2*>(pObj)) {
+        if (!ReadHistogram<TH2>(dynamic_cast<TH2*>(pObj))) {  //
+          return false;
+        }
+      }  // if( nullptr != dynamic_cast< TH2 *>( pObj ) )
+      else if (nullptr != dynamic_cast<TH1*>(pObj)) {
+        if (!ReadHistogram<TH1>(dynamic_cast<TH1*>(pObj))) {  //
+          return false;
+        }
+      }  // if( nullptr != dynamic_cast< TH1 *>( pObj ) )
+      else
+        LOG(warning) << "Unsupported object type for " << pObj->GetName();
+    }  // for (Int_t i = 0; i < arrayHisto->GetEntriesFast(); i++)
+
+    LOG(debug) << "Application::ReceiveData => Deleting array";
+    /// Need to use Delete instead of Clear to avoid memory leak!!!
+    arrayHisto->Delete();
 
     /// If new histos received, try to prepare as many canvases as possible
     /// Should be expensive on start and cheap afterward
@@ -218,453 +281,419 @@ namespace cbm::services::histserv
         fvbCanvasReady[uCanv] = PrepareCanvas(uCanv);
       }  // for( uint32_t uCanv = 0; uCanv < fvpsCanvasConfig.size(); ++uCanv )
     }    // if( !fbAllCanvasReady )
+  }      // if (TString(tempObject->ClassName()).EqualTo("TObjArray"))
+  else {
+    fStopThread         = true;
+    std::string err_msg = "Application::ReceiveData => Wrong object type at input: ";
+    err_msg += tempObject->ClassName();
+    throw std::runtime_error(err_msg);
+  }
 
-    /*
-    TObject* tempObject = nullptr;
-    if (TString(tempObject->ClassName()).EqualTo("TObjArray")) {
-      std::lock_guard<std::mutex> lk(mtx);
-      TObjArray* arrayHisto = static_cast<TObjArray*>(tempObject);
-      for (Int_t i = 0; i < arrayHisto->GetEntriesFast(); i++) {
-        TObject* pObj = arrayHisto->At(i);
-
-        if (nullptr != dynamic_cast<TProfile*>(pObj)) {
-          if (!ReadHistogram<TProfile>(dynamic_cast<TProfile*>(pObj))) {  //
-            return false;
-          }
-        }  // if( nullptr != dynamic_cast< TProfile *>( pObj ) )
-        else if (nullptr != dynamic_cast<TH2*>(pObj)) {
-          if (!ReadHistogram<TH2>(dynamic_cast<TH2*>(pObj))) {  //
-            return false;
-          }
-        }  // if( nullptr != dynamic_cast< TH2 *>( pObj ) )
-        else if (nullptr != dynamic_cast<TH1*>(pObj)) {
-          if (!ReadHistogram<TH1>(dynamic_cast<TH1*>(pObj))) {  //
-            return false;
-          }
-        }  // if( nullptr != dynamic_cast< TH1 *>( pObj ) )
-        else
-          LOG(warning) << "Unsupported object type for " << pObj->GetName();
-      }  // for (Int_t i = 0; i < arrayHisto->GetEntriesFast(); i++)
-
-      LOG(debug) << "Application::ReceiveData => Deleting array";
-      /// Need to use Delete instead of Clear to avoid memory leak!!!
-      arrayHisto->Delete();
-
-      /// If new histos received, try to prepare as many canvases as possible
-      /// Should be expensive on start and cheap afterward
-      if (!fbAllCanvasReady) {
-        LOG(debug) << "Application::ReceiveData => Checking for canvases updates";
-        for (uint32_t uCanv = 0; uCanv < fvpsCanvasConfig.size(); ++uCanv) {
-          /// Jump canvases already ready
-          if (fvbCanvasReady[uCanv]) {  //
-            continue;
-          }
-
-          /// Now come the expensive part as we unpack its config and check each histo
-          fvbCanvasReady[uCanv] = PrepareCanvas(uCanv);
-        }  // for( uint32_t uCanv = 0; uCanv < fvpsCanvasConfig.size(); ++uCanv )
-      }    // if( !fbAllCanvasReady )
-    }      // if (TString(tempObject->ClassName()).EqualTo("TObjArray"))
-    else {
-      fStopThread         = true;
-      std::string err_msg = "Application::ReceiveData => Wrong object type at input: ";
-      err_msg += tempObject->ClassName();
-      throw std::runtime_error(err_msg);
-    }
+  if (nullptr != tempObject) delete tempObject;
+  */
 
-    if (nullptr != tempObject) delete tempObject;
-    */
+  fNMessages += 1;
 
-    fNMessages += 1;
+  LOG(debug) << "Application::ReceiveData => Finished processing histograms update";
 
-    LOG(debug) << "Application::ReceiveData => Finished processing histograms update";
+  return true;
+}
 
-    return true;
+// ---------------------------------------------------------------------------------------------------------------------
+//
+bool Application::ReceiveHistoConfig(zmq::message_t& msg)
+{
+  /// FIXME: Something to replace FairMQ and extract the config!!!!
+  //  BoostSerializer<std::pair<std::string, std::string>>().Deserialize(msg, tempObject);
+  b_io::basic_array_source<char> device(static_cast<char*>(msg.data()), msg.size());
+  b_io::stream<b_io::basic_array_source<char>> s(device);
+  b_ar::binary_iarchive iarch(s);
+
+  std::pair<std::string, std::string> tempObject("", "");
+  iarch >> tempObject;
+
+  LOG(info) << " Received configuration for histo " << tempObject.first << " : " << tempObject.second;
+
+  /// Check if histo name already received in previous messages
+  /// Linear search should be ok as config is shared only at startup
+  UInt_t uPrevHist = 0;
+  for (uPrevHist = 0; uPrevHist < fvpsHistosFolder.size(); ++uPrevHist) {
+    if (fvpsHistosFolder[uPrevHist].first == tempObject.first) {  //
+      break;
+    }
+  }  // for( UInt_t uPrevHist = 0; uPrevHist < fvpsHistosFolder.size(); ++uPrevHist )
+
+  if (uPrevHist < fvpsHistosFolder.size()) {
+    LOG(info) << " Ignored new configuration for histo " << tempObject.first
+              << " due to previously received one: " << tempObject.second;
+    /// Not sure if we should return false here...
+  }  // if( uPrevHist < fvpsHistosFolder.size() )
+  else {
+    fvpsHistosFolder.push_back(tempObject);
+    fvHistos.push_back(std::pair<TNamed*, std::string>(nullptr, ""));
+    fvbHistoRegistered.push_back(false);
+    fbAllHistosRegistered = false;
+  }  // else of if( uPrevHist < fvpsHistosFolder.size() )
+
+  return true;
+}
+
+// ---------------------------------------------------------------------------------------------------------------------
+//
+bool Application::ReceiveCanvasConfig(zmq::message_t& msg)
+{
+  /// FIXME: Something to replace FairMQ and extract the config!!!!
+  //  BoostSerializer<std::pair<std::string, std::string>>().Deserialize(msg, tempObject);
+  b_io::basic_array_source<char> device(static_cast<char*>(msg.data()), msg.size());
+  b_io::stream<b_io::basic_array_source<char>> s(device);
+  b_ar::binary_iarchive iarch(s);
+
+  std::pair<std::string, std::string> tempObject("", "");
+  iarch >> tempObject;
+
+  LOG(info) << " Received configuration for canvas " << tempObject.first << " : " << tempObject.second;
+
+  /// Check if canvas name already received in previous messages
+  /// Linear search should be ok as config is shared only at startup
+  uint32_t uPrevCanv = 0;
+  for (uPrevCanv = 0; uPrevCanv < fvpsCanvasConfig.size(); ++uPrevCanv) {
+    if (fvpsCanvasConfig[uPrevCanv].first == tempObject.first) {  //
+      break;
+    }
+  }  // for( UInt_t uPrevCanv = 0; uPrevCanv < fvpsCanvasConfig.size(); ++uPrevCanv )
+
+  if (uPrevCanv < fvpsCanvasConfig.size()) {
+    LOG(warning) << " Ignored new configuration for Canvas " << tempObject.first
+                 << " due to previously received one: " << tempObject.second;
+    /// Not sure if we should return false here...
+  }  // if( uPrevCanv < fvpsCanvasConfig.size() )
+  else {
+    fvpsCanvasConfig.push_back(tempObject);
+    fvbCanvasReady.push_back(false);
+    fbAllCanvasReady = false;
+
+    fvCanvas.push_back(std::pair<TCanvas*, std::string>(nullptr, ""));
+    fvbCanvasRegistered.push_back(false);
+    fbAllCanvasRegistered = false;
+  }  // else of if( uPrevCanv < fvpsCanvasConfig.size() )
+  return true;
+}
+
+// ---------------------------------------------------------------------------------------------------------------------
+//
+bool Application::ReceiveConfigAndData(std::vector<zmq::message_t>& vMsg)
+{
+  /// FIXME: Something to replace FairMQ and extract the histograms!!!!
+  LOG(debug) << "Application::ReceiveConfigAndData => Received composed message with " << vMsg.size() << " parts";
+
+  /// Header contains a pair of unsigned integers
+  /// FIXME: Something to replace FairMQ and extract the header!!!!
+  // BoostSerializer<std::pair<uint32_t, uint32_t>>().Deserialize(vMsg.at(0), pairHeader);
+  b_io::basic_array_source<char> device_header(static_cast<char*>(vMsg.at(0).data()), vMsg.at(0).size());
+  b_io::stream<b_io::basic_array_source<char>> s_header(device_header);
+  b_ar::binary_iarchive iarch_header(s_header);
+
+  std::pair<uint32_t, uint32_t> pairHeader;
+  iarch_header >> pairHeader;
+  LOG(debug) << "Application::ReceiveConfigAndData => Received configuration for " << pairHeader.first << " histos and "
+             << pairHeader.second << " canvases";
+
+  uint32_t uOffsetHistoConfig = pairHeader.first;
+  if (0 == pairHeader.first) {
+    uOffsetHistoConfig = 1;
+    if (0 < vMsg[uOffsetHistoConfig].size()) {
+      fStopThread = true;
+      fUiCmdActor->SetServerStop();
+      std::string err_msg = "Application::ReceiveConfigAndData => No histo config expected but corresponding message";
+      err_msg += " is not empty: ";
+      err_msg += vMsg[uOffsetHistoConfig].size();
+      throw std::runtime_error(err_msg);
+    }
   }
 
-  bool Application::ReceiveHistoConfig(zmq::message_t& msg)
-  {
-    /// FIXME: Something to replace FairMQ and extract the config!!!!
-    //  BoostSerializer<std::pair<std::string, std::string>>().Deserialize(msg, tempObject);
-    b_io::basic_array_source<char> device(static_cast<char*>(msg.data()), msg.size());
-    b_io::stream<b_io::basic_array_source<char>> s(device);
-    b_ar::binary_iarchive iarch(s);
-
-    std::pair<std::string, std::string> tempObject("", "");
-    iarch >> tempObject;
-
-    LOG(info) << " Received configuration for histo " << tempObject.first << " : " << tempObject.second;
+  uint32_t uOffsetCanvasConfig = pairHeader.second;
+  if (0 == pairHeader.second) {
+    uOffsetCanvasConfig = 1;
+    if (0 < vMsg[uOffsetHistoConfig + uOffsetCanvasConfig].size()) {
+      fStopThread = true;
+      fUiCmdActor->SetServerStop();
+      std::string err_msg = "Application::ReceiveConfigAndData => No Canvas config expected but corresponding ";
+      err_msg += " message is not empty: ";
+      err_msg += vMsg[uOffsetHistoConfig + uOffsetCanvasConfig].size();
+      throw std::runtime_error(err_msg);
+    }
+  }
 
-    /// Check if histo name already received in previous messages
-    /// Linear search should be ok as config is shared only at startup
-    UInt_t uPrevHist = 0;
-    for (uPrevHist = 0; uPrevHist < fvpsHistosFolder.size(); ++uPrevHist) {
-      if (fvpsHistosFolder[uPrevHist].first == tempObject.first) {  //
-        break;
-      }
-    }  // for( UInt_t uPrevHist = 0; uPrevHist < fvpsHistosFolder.size(); ++uPrevHist )
-
-    if (uPrevHist < fvpsHistosFolder.size()) {
-      LOG(info) << " Ignored new configuration for histo " << tempObject.first
-                << " due to previously received one: " << tempObject.second;
-      /// Not sure if we should return false here...
-    }  // if( uPrevHist < fvpsHistosFolder.size() )
-    else {
-      fvpsHistosFolder.push_back(tempObject);
-      fvHistos.push_back(std::pair<TNamed*, std::string>(nullptr, ""));
-      fvbHistoRegistered.push_back(false);
-      fbAllHistosRegistered = false;
-    }  // else of if( uPrevHist < fvpsHistosFolder.size() )
-
-    return true;
+  if ((1 + uOffsetHistoConfig + uOffsetCanvasConfig + 1) != vMsg.size()) {
+    fStopThread = true;
+    fUiCmdActor->SetServerStop();
+    std::string err_msg = "Application::ReceiveConfigAndData => Nb parts in message not matching configs numbers ";
+    err_msg += " declared in header";
+    err_msg += vMsg.size();
+    err_msg += " VS ";
+    err_msg += 1 + uOffsetHistoConfig + uOffsetCanvasConfig + 1;
+    throw std::runtime_error(err_msg);
   }
 
-  bool Application::ReceiveCanvasConfig(zmq::message_t& msg)
-  {
-    /// FIXME: Something to replace FairMQ and extract the config!!!!
-    //  BoostSerializer<std::pair<std::string, std::string>>().Deserialize(msg, tempObject);
-    b_io::basic_array_source<char> device(static_cast<char*>(msg.data()), msg.size());
-    b_io::stream<b_io::basic_array_source<char>> s(device);
-    b_ar::binary_iarchive iarch(s);
+  /// Decode parts for histograms configuration (auto-skip empty message if 0 declared in header)
+  for (uint32_t uHisto = 0; uHisto < pairHeader.first; ++uHisto) {
+    ReceiveHistoConfig(vMsg[1 + uHisto]);
+  }  // for (UInt_t uHisto = 0; uHisto < pairHeader.first; ++uHisto)
+  LOG(debug) << "Application::ReceiveConfigAndData => Processed configuration for " << pairHeader.first << " histos";
 
-    std::pair<std::string, std::string> tempObject("", "");
-    iarch >> tempObject;
+  /// Decode parts for histograms configuration (auto-skip empty message if 0 declared in header)
+  for (uint32_t uCanv = 0; uCanv < pairHeader.second; ++uCanv) {
+    ReceiveCanvasConfig(vMsg[1 + uOffsetHistoConfig + uCanv]);
+  }  // for (UInt_t uCanv = 0; uCanv < pairHeader.second; ++uCanv)
+  LOG(debug) << "Application::ReceiveConfigAndData => Processed configuration for " << pairHeader.second << " canvases";
 
-    LOG(info) << " Received configuration for canvas " << tempObject.first << " : " << tempObject.second;
+  /// Decode the histograms data now that the configuration is loaded
+  ReceiveData(vMsg[1 + uOffsetHistoConfig + uOffsetCanvasConfig]);
 
-    /// Check if canvas name already received in previous messages
-    /// Linear search should be ok as config is shared only at startup
-    uint32_t uPrevCanv = 0;
-    for (uPrevCanv = 0; uPrevCanv < fvpsCanvasConfig.size(); ++uPrevCanv) {
-      if (fvpsCanvasConfig[uPrevCanv].first == tempObject.first) {  //
-        break;
-      }
-    }  // for( UInt_t uPrevCanv = 0; uPrevCanv < fvpsCanvasConfig.size(); ++uPrevCanv )
-
-    if (uPrevCanv < fvpsCanvasConfig.size()) {
-      LOG(warning) << " Ignored new configuration for Canvas " << tempObject.first
-                   << " due to previously received one: " << tempObject.second;
-      /// Not sure if we should return false here...
-    }  // if( uPrevCanv < fvpsCanvasConfig.size() )
-    else {
-      fvpsCanvasConfig.push_back(tempObject);
-      fvbCanvasReady.push_back(false);
-      fbAllCanvasReady = false;
-
-      fvCanvas.push_back(std::pair<TCanvas*, std::string>(nullptr, ""));
-      fvbCanvasRegistered.push_back(false);
-      fbAllCanvasRegistered = false;
-    }  // else of if( uPrevCanv < fvpsCanvasConfig.size() )
-    return true;
-  }
+  return true;
+}
 
-  bool Application::ReceiveConfigAndData(std::vector<zmq::message_t>& vMsg)
-  {
-    /// FIXME: Something to replace FairMQ and extract the histograms!!!!
-    LOG(debug) << "Application::ReceiveConfigAndData => Received composed message with " << vMsg.size() << " parts";
-
-    /// Header contains a pair of unsigned integers
-    /// FIXME: Something to replace FairMQ and extract the header!!!!
-    // BoostSerializer<std::pair<uint32_t, uint32_t>>().Deserialize(vMsg.at(0), pairHeader);
-    b_io::basic_array_source<char> device_header(static_cast<char*>(vMsg.at(0).data()), vMsg.at(0).size());
-    b_io::stream<b_io::basic_array_source<char>> s_header(device_header);
-    b_ar::binary_iarchive iarch_header(s_header);
-
-    std::pair<uint32_t, uint32_t> pairHeader;
-    iarch_header >> pairHeader;
-    LOG(debug) << "Application::ReceiveConfigAndData => Received configuration for " << pairHeader.first
-               << " histos and " << pairHeader.second << " canvases";
-
-    uint32_t uOffsetHistoConfig = pairHeader.first;
-    if (0 == pairHeader.first) {
-      uOffsetHistoConfig = 1;
-      if (0 < vMsg[uOffsetHistoConfig].size()) {
-        fStopThread         = true;
-        fUiCmdActor->SetServerStop();
-        std::string err_msg = "Application::ReceiveConfigAndData => No histo config expected but corresponding message";
-        err_msg += " is not empty: ";
-        err_msg += vMsg[uOffsetHistoConfig].size();
-        throw std::runtime_error(err_msg);
-      }
-    }
+// ---------------------------------------------------------------------------------------------------------------------
+//
+template<class HistoT>
+bool Application::ReadHistogram(HistoT* pHist)
+{
+  int index1 = FindHistogram(pHist->GetName());
+  if (-1 == index1) {
+    HistoT* histogram_new = static_cast<HistoT*>(pHist->Clone());
+    fArrayHisto.Add(histogram_new);
+
+    LOG(info) << "Received new histo " << pHist->GetName();
+
+    /// If new histo received, try to register it if configuration available
+    if (!fbAllHistosRegistered) {
+      for (uint32_t uHist = 0; uHist < fvpsHistosFolder.size(); ++uHist) {
+        /// Jump histos already ready
+        if (fvbHistoRegistered[uHist]) {  //
+          continue;
+        }
 
-    uint32_t uOffsetCanvasConfig = pairHeader.second;
-    if (0 == pairHeader.second) {
-      uOffsetCanvasConfig = 1;
-      if (0 < vMsg[uOffsetHistoConfig + uOffsetCanvasConfig].size()) {
-        fStopThread         = true;
-        fUiCmdActor->SetServerStop();
-        std::string err_msg = "Application::ReceiveConfigAndData => No Canvas config expected but corresponding ";
-        err_msg += " message is not empty: ";
-        err_msg += vMsg[uOffsetHistoConfig + uOffsetCanvasConfig].size();
-        throw std::runtime_error(err_msg);
-      }
-    }
+        /// Check if name matches one in config for others
+        if (fvpsHistosFolder[uHist].first == histogram_new->GetName()) {
+          fvHistos[uHist] = std::pair<TNamed*, std::string>(histogram_new, fvpsHistosFolder[uHist].second);
+          fServer->Register(Form("/%s", fvHistos[uHist].second.data()), fvHistos[uHist].first);
+          fvbHistoRegistered[uHist] = true;
+
+          LOG(info) << "registered histo " << fvHistos[uHist].first->GetName() << " in folder "
+                    << fvHistos[uHist].second;
+
+
+          /// Update flag telling whether all known histos are registered
+          fbAllHistosRegistered = true;
+          for (uint32_t uIdx = 0; uIdx < fvbHistoRegistered.size(); ++uIdx) {
+            if (!fvbHistoRegistered[uIdx]) {
+              fbAllHistosRegistered = false;
+              break;
+            }  // if( !fvbHistoRegistered[ uIdx ] )
+          }    // for( uint32_t uIdx = 0; uIdx < fvbHistoRegistered.size(); ++uIdx )
+
+          break;
+        }  // if( fvpsHistosFolder[ uHist ].first == histogram_new->GetName() )
+      }    // for( uint32_t uCanv = 0; uCanv < fvpsCanvasConfig.size(); ++uCanv )
+    }      // if( !fbAllCanvasReady )
+  }        // if (-1 == index1)
+  else {
+    LOG(debug) << "Received update for: " << pHist->GetName();
+    HistoT* histogram_existing = dynamic_cast<HistoT*>(fArrayHisto.At(index1));
+    if (nullptr == histogram_existing) {
+      LOG(error) << "CbmMqHistoServer::ReadHistogram => "
+                 << "Incompatible type found during update for histo " << pHist->GetName();
+      return false;
+    }  // if( nullptr == histogram_existing )
 
-    if ((1 + uOffsetHistoConfig + uOffsetCanvasConfig + 1) != vMsg.size()) {
-      fStopThread         = true;
-      fUiCmdActor->SetServerStop();
-      std::string err_msg = "Application::ReceiveConfigAndData => Nb parts in message not matching configs numbers ";
-      err_msg += " declared in header";
-      err_msg += vMsg.size();
-      err_msg += " VS ";
-      err_msg += 1 + uOffsetHistoConfig + uOffsetCanvasConfig + 1;
-      throw std::runtime_error(err_msg);
-    }
+    histogram_existing->Add(pHist);
+  }  // else of if (-1 == index1)
+  return true;
+}
 
-    /// Decode parts for histograms configuration (auto-skip empty message if 0 declared in header)
-    for (uint32_t uHisto = 0; uHisto < pairHeader.first; ++uHisto) {
-      ReceiveHistoConfig(vMsg[1 + uHisto]);
-    }  // for (UInt_t uHisto = 0; uHisto < pairHeader.first; ++uHisto)
-    LOG(debug) << "Application::ReceiveConfigAndData => Processed configuration for " << pairHeader.first << " histos";
+// ---------------------------------------------------------------------------------------------------------------------
+//
+int Application::FindHistogram(const std::string& name)
+{
+  for (int iHist = 0; iHist < fArrayHisto.GetEntriesFast(); ++iHist) {
+    TObject* obj = fArrayHisto.At(iHist);
+    if (TString(obj->GetName()).EqualTo(name)) {  //
+      return iHist;
+    }
+  }  // for( int iHist = 0; iHist < fArrayHisto.GetEntriesFast(); ++iHist )
+  return -1;
+}
 
-    /// Decode parts for histograms configuration (auto-skip empty message if 0 declared in header)
-    for (uint32_t uCanv = 0; uCanv < pairHeader.second; ++uCanv) {
-      ReceiveCanvasConfig(vMsg[1 + uOffsetHistoConfig + uCanv]);
-    }  // for (UInt_t uCanv = 0; uCanv < pairHeader.second; ++uCanv)
-    LOG(debug) << "Application::ReceiveConfigAndData => Processed configuration for " << pairHeader.second
-               << " canvases";
+// ---------------------------------------------------------------------------------------------------------------------
+//
+bool Application::PrepareCanvas(uint32_t uCanvIdx)
+{
+  LOG(info) << " Extracting configuration for canvas index " << uCanvIdx;
+  CanvasConfig conf(ExtractCanvasConfigFromString(fvpsCanvasConfig[uCanvIdx].second));
+
+  /// First check if all objects to be drawn are present
+  uint32_t uNbPads(conf.GetNbPads());
+  for (uint32_t uPadIdx = 0; uPadIdx < uNbPads; ++uPadIdx) {
+    uint32_t uNbObj(conf.GetNbObjsInPad(uPadIdx));
+    for (uint32_t uObjIdx = 0; uObjIdx < uNbObj; ++uObjIdx) {
+      std::string sName(conf.GetObjName(uPadIdx, uObjIdx));
+      /// Check for empty pads!
+      if ("nullptr" != sName) {
+        if (FindHistogram(sName) < 0) {
+          return false;
+        }  // if( FindHistogram( conf.GetObjName( uPadIdx, uObjIdx ) ) < 0 )
+      }    // if( "nullptr" != sName )
+    }      // for( uint32_t uObjIdx = 0; uObjIdx < uNbObj; ++uObjIdx )
+  }        // for( uint32_t uPadIdx = 0; uPadIdx < uNbPads; ++uPadIdx )
+
+  LOG(info) << " All histos found for canvas " << conf.GetName().data() << ", now preparing it";
+
+  // Temporary solution to save canvases into directories
+  std::string sNameFull = conf.GetName();
+  size_t lastSlashPos   = sNameFull.find_last_of('/');
+  std::string sNamePart = lastSlashPos > sNameFull.size() ? sNameFull : sNameFull.substr(lastSlashPos + 1);
+  std::string sDir      = lastSlashPos > sNameFull.size() ? "" : sNameFull.substr(0, lastSlashPos);
+  std::string canvDir   = sDir.empty() ? "canvases" : fmt::format("canvases/{}", sDir);
+
+  /// Create new canvas and pads
+  TCanvas* pNewCanv = new TCanvas(sNamePart.c_str(), conf.GetTitle().data());
+  pNewCanv->Divide(conf.GetNbPadsX(), conf.GetNbPadsY());
+
+  /// Loop on pads
+  for (uint32_t uPadIdx = 0; uPadIdx < uNbPads; ++uPadIdx) {
+    pNewCanv->cd(1 + uPadIdx);
+
+    /// Pad settings
+    gPad->SetGrid(conf.GetGridx(uPadIdx), conf.GetGridy(uPadIdx));
+    gPad->SetLogx(conf.GetLogx(uPadIdx));
+    gPad->SetLogy(conf.GetLogy(uPadIdx));
+    gPad->SetLogz(conf.GetLogz(uPadIdx));
+
+    /// Add objects (we know they are there
+    uint32_t uNbObj(conf.GetNbObjsInPad(uPadIdx));
+    for (uint32_t uObjIdx = 0; uObjIdx < uNbObj; ++uObjIdx) {
+      std::string sName(conf.GetObjName(uPadIdx, uObjIdx));
+      if ("nullptr" != sName) {
+        TObject* pObj = fArrayHisto[FindHistogram(sName)];
+
+        if (nullptr != dynamic_cast<TProfile2D*>(pObj)) {
+          dynamic_cast<TProfile2D*>(pObj)->Draw(conf.GetOption(uPadIdx, uObjIdx).data());
+        }  // if( nullptr != dynamic_cast< TProfile *>( pObj ) )
+        else if (nullptr != dynamic_cast<TProfile*>(pObj)) {
+          dynamic_cast<TProfile*>(pObj)->Draw(conf.GetOption(uPadIdx, uObjIdx).data());
+        }  // if( nullptr != dynamic_cast< TProfile *>( pObj ) )
+        else if (nullptr != dynamic_cast<TH2*>(pObj)) {
+          dynamic_cast<TH2*>(pObj)->Draw(conf.GetOption(uPadIdx, uObjIdx).data());
+        }  // if( nullptr != dynamic_cast< TH2 *>( pObj ) )
+        else if (nullptr != dynamic_cast<TH1*>(pObj)) {
+          dynamic_cast<TH1*>(pObj)->Draw(conf.GetOption(uPadIdx, uObjIdx).data());
+        }  // if( nullptr != dynamic_cast< TH1 *>( pObj ) )
+        else
+          LOG(warning) << "  Unsupported object type for " << sName << " when preparing canvas " << conf.GetName();
 
-    /// Decode the histograms data now that the configuration is loaded
-    ReceiveData(vMsg[1 + uOffsetHistoConfig + uOffsetCanvasConfig]);
+        LOG(info) << "  Configured histo " << sName << " on pad " << (1 + uPadIdx) << " for canvas "
+                  << conf.GetName().data();
+      }  // if( "nullptr" != sName )
+    }    // for( uint32_t uObjIdx = 0; uObjIdx < uNbObj; ++uObjIdx )
+  }      // for( uint32_t uPadIdx = 0; uPadIdx < uNbPads; ++uPadIdx )
 
-    return true;
-  }
-  // -------------------------------------------------------------------------------------------------------------------
-
-  template<class HistoT>
-  bool Application::ReadHistogram(HistoT* pHist)
-  {
-    int index1 = FindHistogram(pHist->GetName());
-    if (-1 == index1) {
-      HistoT* histogram_new = static_cast<HistoT*>(pHist->Clone());
-      fArrayHisto.Add(histogram_new);
-
-      LOG(info) << "Received new histo " << pHist->GetName();
-
-      /// If new histo received, try to register it if configuration available
-      if (!fbAllHistosRegistered) {
-        for (uint32_t uHist = 0; uHist < fvpsHistosFolder.size(); ++uHist) {
-          /// Jump histos already ready
-          if (fvbHistoRegistered[uHist]) {  //
-            continue;
-          }
-
-          /// Check if name matches one in config for others
-          if (fvpsHistosFolder[uHist].first == histogram_new->GetName()) {
-            fvHistos[uHist] = std::pair<TNamed*, std::string>(histogram_new, fvpsHistosFolder[uHist].second);
-            fServer->Register(Form("/%s", fvHistos[uHist].second.data()), fvHistos[uHist].first);
-            fvbHistoRegistered[uHist] = true;
-
-            LOG(info) << "registered histo " << fvHistos[uHist].first->GetName() << " in folder "
-                      << fvHistos[uHist].second;
-
-
-            /// Update flag telling whether all known histos are registered
-            fbAllHistosRegistered = true;
-            for (uint32_t uIdx = 0; uIdx < fvbHistoRegistered.size(); ++uIdx) {
-              if (!fvbHistoRegistered[uIdx]) {
-                fbAllHistosRegistered = false;
-                break;
-              }  // if( !fvbHistoRegistered[ uIdx ] )
-            }    // for( uint32_t uIdx = 0; uIdx < fvbHistoRegistered.size(); ++uIdx )
-
-            break;
-          }  // if( fvpsHistosFolder[ uHist ].first == histogram_new->GetName() )
-        }    // for( uint32_t uCanv = 0; uCanv < fvpsCanvasConfig.size(); ++uCanv )
-      }      // if( !fbAllCanvasReady )
-    }        // if (-1 == index1)
-    else {
-      LOG(debug) << "Received update for: " << pHist->GetName();
-      HistoT* histogram_existing = dynamic_cast<HistoT*>(fArrayHisto.At(index1));
-      if (nullptr == histogram_existing) {
-        LOG(error) << "CbmMqHistoServer::ReadHistogram => "
-                   << "Incompatible type found during update for histo " << pHist->GetName();
-        return false;
-      }  // if( nullptr == histogram_existing )
-
-      histogram_existing->Add(pHist);
-    }  // else of if (-1 == index1)
-    return true;
-  }
+  fvCanvas[uCanvIdx] = std::pair<TCanvas*, std::string>(pNewCanv, canvDir);
+  fServer->Register(Form("/%s", fvCanvas[uCanvIdx].second.data()), fvCanvas[uCanvIdx].first);
+  fvbCanvasRegistered[uCanvIdx] = true;
 
-  int Application::FindHistogram(const std::string& name)
-  {
-    for (int iHist = 0; iHist < fArrayHisto.GetEntriesFast(); ++iHist) {
-      TObject* obj = fArrayHisto.At(iHist);
-      if (TString(obj->GetName()).EqualTo(name)) {  //
-        return iHist;
-      }
-    }  // for( int iHist = 0; iHist < fArrayHisto.GetEntriesFast(); ++iHist )
-    return -1;
-  }
+  LOG(info) << " Registered canvas " << fvCanvas[uCanvIdx].first->GetName() << " in folder "
+            << fvCanvas[uCanvIdx].second;
 
-  bool Application::PrepareCanvas(uint32_t uCanvIdx)
-  {
-    LOG(info) << " Extracting configuration for canvas index " << uCanvIdx;
-    CanvasConfig conf(ExtractCanvasConfigFromString(fvpsCanvasConfig[uCanvIdx].second));
-
-    /// First check if all objects to be drawn are present
-    uint32_t uNbPads(conf.GetNbPads());
-    for (uint32_t uPadIdx = 0; uPadIdx < uNbPads; ++uPadIdx) {
-      uint32_t uNbObj(conf.GetNbObjsInPad(uPadIdx));
-      for (uint32_t uObjIdx = 0; uObjIdx < uNbObj; ++uObjIdx) {
-        std::string sName(conf.GetObjName(uPadIdx, uObjIdx));
-        /// Check for empty pads!
-        if ("nullptr" != sName) {
-          if (FindHistogram(sName) < 0) {
-            return false;
-          }  // if( FindHistogram( conf.GetObjName( uPadIdx, uObjIdx ) ) < 0 )
-        }    // if( "nullptr" != sName )
-      }      // for( uint32_t uObjIdx = 0; uObjIdx < uNbObj; ++uObjIdx )
-    }        // for( uint32_t uPadIdx = 0; uPadIdx < uNbPads; ++uPadIdx )
-
-    LOG(info) << " All histos found for canvas " << conf.GetName().data() << ", now preparing it";
-
-    // Temporary solution to save canvases into directories
-    std::string sNameFull = conf.GetName();
-    size_t lastSlashPos   = sNameFull.find_last_of('/');
-    std::string sNamePart = lastSlashPos > sNameFull.size() ? sNameFull : sNameFull.substr(lastSlashPos + 1);
-    std::string sDir      = lastSlashPos > sNameFull.size() ? "" : sNameFull.substr(0, lastSlashPos);
-    std::string canvDir   = sDir.empty() ? "canvases" : fmt::format("canvases/{}", sDir);
-
-    /// Create new canvas and pads
-    TCanvas* pNewCanv = new TCanvas(sNamePart.c_str(), conf.GetTitle().data());
-    pNewCanv->Divide(conf.GetNbPadsX(), conf.GetNbPadsY());
-
-    /// Loop on pads
-    for (uint32_t uPadIdx = 0; uPadIdx < uNbPads; ++uPadIdx) {
-      pNewCanv->cd(1 + uPadIdx);
-
-      /// Pad settings
-      gPad->SetGrid(conf.GetGridx(uPadIdx), conf.GetGridy(uPadIdx));
-      gPad->SetLogx(conf.GetLogx(uPadIdx));
-      gPad->SetLogy(conf.GetLogy(uPadIdx));
-      gPad->SetLogz(conf.GetLogz(uPadIdx));
-
-      /// Add objects (we know they are there
-      uint32_t uNbObj(conf.GetNbObjsInPad(uPadIdx));
-      for (uint32_t uObjIdx = 0; uObjIdx < uNbObj; ++uObjIdx) {
-        std::string sName(conf.GetObjName(uPadIdx, uObjIdx));
-        if ("nullptr" != sName) {
-          TObject* pObj = fArrayHisto[FindHistogram(sName)];
-
-          if (nullptr != dynamic_cast<TProfile2D*>(pObj)) {
-            dynamic_cast<TProfile2D*>(pObj)->Draw(conf.GetOption(uPadIdx, uObjIdx).data());
-          }  // if( nullptr != dynamic_cast< TProfile *>( pObj ) )
-          else if (nullptr != dynamic_cast<TProfile*>(pObj)) {
-            dynamic_cast<TProfile*>(pObj)->Draw(conf.GetOption(uPadIdx, uObjIdx).data());
-          }  // if( nullptr != dynamic_cast< TProfile *>( pObj ) )
-          else if (nullptr != dynamic_cast<TH2*>(pObj)) {
-            dynamic_cast<TH2*>(pObj)->Draw(conf.GetOption(uPadIdx, uObjIdx).data());
-          }  // if( nullptr != dynamic_cast< TH2 *>( pObj ) )
-          else if (nullptr != dynamic_cast<TH1*>(pObj)) {
-            dynamic_cast<TH1*>(pObj)->Draw(conf.GetOption(uPadIdx, uObjIdx).data());
-          }  // if( nullptr != dynamic_cast< TH1 *>( pObj ) )
-          else
-            LOG(warning) << "  Unsupported object type for " << sName << " when preparing canvas " << conf.GetName();
-
-          LOG(info) << "  Configured histo " << sName << " on pad " << (1 + uPadIdx) << " for canvas "
-                    << conf.GetName().data();
-        }  // if( "nullptr" != sName )
-      }    // for( uint32_t uObjIdx = 0; uObjIdx < uNbObj; ++uObjIdx )
-    }      // for( uint32_t uPadIdx = 0; uPadIdx < uNbPads; ++uPadIdx )
-
-    fvCanvas[uCanvIdx] = std::pair<TCanvas*, std::string>(pNewCanv, canvDir);
-    fServer->Register(Form("/%s", fvCanvas[uCanvIdx].second.data()), fvCanvas[uCanvIdx].first);
-    fvbCanvasRegistered[uCanvIdx] = true;
-
-    LOG(info) << " Registered canvas " << fvCanvas[uCanvIdx].first->GetName() << " in folder "
-              << fvCanvas[uCanvIdx].second;
-
-    /// Update flag telling whether all known canvases are registered
-    fbAllCanvasRegistered = true;
-    for (uint32_t uIdx = 0; uIdx < fvbCanvasRegistered.size(); ++uIdx) {
-      if (!fvbCanvasRegistered[uIdx]) {
-        fbAllCanvasRegistered = false;
-        break;
-      }  // if( !fvbCanvasRegistered[ uIdx ] )
-    }    // for( uint32_t uIdx = 0; uIdx < fvbCanvasRegistered.size(); ++uIdx )
+  /// Update flag telling whether all known canvases are registered
+  fbAllCanvasRegistered = true;
+  for (uint32_t uIdx = 0; uIdx < fvbCanvasRegistered.size(); ++uIdx) {
+    if (!fvbCanvasRegistered[uIdx]) {
+      fbAllCanvasRegistered = false;
+      break;
+    }  // if( !fvbCanvasRegistered[ uIdx ] )
+  }    // for( uint32_t uIdx = 0; uIdx < fvbCanvasRegistered.size(); ++uIdx )
 
-    return true;
-  }
+  return true;
+}
 
-  bool Application::ResetHistograms()
-  {
-    for (int iHist = 0; iHist < fArrayHisto.GetEntriesFast(); ++iHist) {
-      dynamic_cast<TH1*>(fArrayHisto.At(iHist))->Reset();
-    }  // for( int iHist = 0; iHist < fArrayHisto.GetEntriesFast(); ++iHist )
-    return true;
+// ---------------------------------------------------------------------------------------------------------------------
+//
+bool Application::ResetHistograms()
+{
+  for (int iHist = 0; iHist < fArrayHisto.GetEntriesFast(); ++iHist) {
+    dynamic_cast<TH1*>(fArrayHisto.At(iHist))->Reset();
+  }  // for( int iHist = 0; iHist < fArrayHisto.GetEntriesFast(); ++iHist )
+  return true;
+}
+
+// ---------------------------------------------------------------------------------------------------------------------
+//
+bool Application::SaveHistograms()
+{
+  if ("" == fOpt.HistoFile()) {  //
+    LOG(error) << "Filename for saving histograms and canvases not defined. Ignoring request.";
+    return false;
   }
 
-  bool Application::SaveHistograms()
-  {
-    if ("" == fOpt.HistoFile()) {  //
-      LOG(error) << "Filename for saving histograms and canvases not defined. Ignoring request.";
-      return false;
-    }
+  /// Save old global file and folder pointer to avoid messing with FairRoot
+  TFile* oldFile     = gFile;
+  TDirectory* oldDir = gDirectory;
 
-    /// Save old global file and folder pointer to avoid messing with FairRoot
-    TFile* oldFile     = gFile;
-    TDirectory* oldDir = gDirectory;
+  /// (Re-)Create ROOT file to store the histos
+  TFile* histoFile = nullptr;
 
-    /// (Re-)Create ROOT file to store the histos
-    TFile* histoFile = nullptr;
+  // open separate histo file in recreate mode
+  histoFile = new TFile(fOpt.HistoFile().data(), fOpt.Overwrite() ? "RECREATE" : "CREATE");
 
-    // open separate histo file in recreate mode
-    histoFile = new TFile(fOpt.HistoFile().data(), fOpt.Overwrite() ? "RECREATE" : "CREATE");
-
-    if (nullptr == histoFile) {  //
-      gFile      = oldFile;
-      gDirectory = oldDir;
-      LOG(error) << "Ignoring request to save histograms and canvases: could not open output file " << fOpt.HistoFile();
-      return false;
-    }
-
-    LOG(info) << "Saving Histograms and canvases in file: " << fOpt.HistoFile();
+  if (nullptr == histoFile) {  //
+    gFile      = oldFile;
+    gDirectory = oldDir;
+    LOG(error) << "Ignoring request to save histograms and canvases: could not open output file " << fOpt.HistoFile();
+    return false;
+  }
 
-    /// Register the histos in the HTTP server
-    for (UInt_t uHisto = 0; uHisto < fvHistos.size(); ++uHisto) {
-      /// catch case of histograms declared in config but not yet received
-      if (nullptr != fvHistos[uHisto].first) {
-        /// Make sure we end up in chosen folder
-        TString sFolder = fvHistos[uHisto].second.data();
-        if (nullptr == gDirectory->Get(sFolder)) {  //
-          gDirectory->mkdir(sFolder);
-        }
-        gDirectory->cd(sFolder);
+  LOG(info) << "Saving Histograms and canvases in file: " << fOpt.HistoFile();
 
-        /// Write plot
-        fvHistos[uHisto].first->Write();
+  /// Register the histos in the HTTP server
+  for (UInt_t uHisto = 0; uHisto < fvHistos.size(); ++uHisto) {
+    /// catch case of histograms declared in config but not yet received
+    if (nullptr != fvHistos[uHisto].first) {
+      /// Make sure we end up in chosen folder
+      TString sFolder = fvHistos[uHisto].second.data();
+      if (nullptr == gDirectory->Get(sFolder)) {  //
+        gDirectory->mkdir(sFolder);
       }
+      gDirectory->cd(sFolder);
 
-      histoFile->cd();
-    }  // for( UInt_t uHisto = 0; uHisto < fvHistos.size(); ++uHisto )
+      /// Write plot
+      fvHistos[uHisto].first->Write();
+    }
 
-    for (UInt_t uCanvas = 0; uCanvas < fvCanvas.size(); ++uCanvas) {
-      /// catch case of canvases declared in config but for which not all histos were yet received
-      if (nullptr != fvCanvas[uCanvas].first) {
-        /// Make sure we end up in chosen folder
-        TString sFolder = fvCanvas[uCanvas].second.data();
-        if (nullptr == gDirectory->Get(sFolder)) {  //
-          gDirectory->mkdir(sFolder);
-        }
-        gDirectory->cd(sFolder);
+    histoFile->cd();
+  }  // for( UInt_t uHisto = 0; uHisto < fvHistos.size(); ++uHisto )
 
-        /// Write plot
-        fvCanvas[uCanvas].first->Write();
+  for (UInt_t uCanvas = 0; uCanvas < fvCanvas.size(); ++uCanvas) {
+    /// catch case of canvases declared in config but for which not all histos were yet received
+    if (nullptr != fvCanvas[uCanvas].first) {
+      /// Make sure we end up in chosen folder
+      TString sFolder = fvCanvas[uCanvas].second.data();
+      if (nullptr == gDirectory->Get(sFolder)) {  //
+        gDirectory->mkdir(sFolder);
       }
+      gDirectory->cd(sFolder);
 
-      histoFile->cd();
-    }  // for( UInt_t uHisto = 0; uHisto < fvCanvas.size(); ++uHisto )
+      /// Write plot
+      fvCanvas[uCanvas].first->Write();
+    }
 
-    /// Restore old global file and folder pointer to avoid messing with FairRoot
-    gFile      = oldFile;
-    gDirectory = oldDir;
+    histoFile->cd();
+  }  // for( UInt_t uHisto = 0; uHisto < fvCanvas.size(); ++uHisto )
 
-    histoFile->Close();
+  /// Restore old global file and folder pointer to avoid messing with FairRoot
+  gFile      = oldFile;
+  gDirectory = oldDir;
 
-    return true;
-  }
+  histoFile->Close();
 
-}  // namespace cbm::services::histserv
+  return true;
+}
diff --git a/services/histserv/app/Application.h b/services/histserv/app/Application.h
index a4f41f10090a16b549da49dfad59a04ef222db63..69ee11b6797c8143cef418d8bfd35d919c3555b6 100644
--- a/services/histserv/app/Application.h
+++ b/services/histserv/app/Application.h
@@ -5,17 +5,17 @@
 #ifndef CBM_SERVICES_HISTSERV_APP_APPLICATION_H
 #define CBM_SERVICES_HISTSERV_APP_APPLICATION_H 1
 
+#include "ProgramOptions.h"
 #include "THttpServer.h"
 #include "TObjArray.h"
+#include "ui_callbacks.h"
 
+#include <csignal>
 #include <memory>
 #include <string>
 #include <thread>
 #include <zmq.hpp>
 
-#include "ProgramOptions.h"
-#include "ui_callbacks.h"
-
 class TCanvas;
 class TNamed;
 
@@ -44,18 +44,43 @@ namespace cbm::services::histserv
   private:
     //const std::string& ConfigFile() const;
 
-    bool ReceiveData(zmq::message_t& msg);
-    bool ReceiveHistoConfig(zmq::message_t& msg);
-    bool ReceiveCanvasConfig(zmq::message_t& msg);
-    bool ReceiveConfigAndData(std::vector<zmq::message_t>& vMsg);
+   /// \brief Receives histograms
+   bool ReceiveData(zmq::message_t& msg);
+
+   /// \brief Receives histogram configuration
+   bool ReceiveHistoConfig(zmq::message_t& msg);
+
+   /// \brief Receives canvas configuration
+   bool ReceiveCanvasConfig(zmq::message_t& msg);
+
+   /// \brief Receives a list of canvases and histograms
+   /// \param vMsg  Message with the histograms and canvases list
+   bool ReceiveConfigAndData(std::vector<zmq::message_t>& vMsg);
+
+   /// \brief  Read a histogram
+   /// \tparam HistoT  Histogram type
+   /// \param  pHist   Pointer to the histogram
+   template<class HistoT>
+   bool ReadHistogram(HistoT* pHist);
+
+   /// \brief Find histogram index in the histogram array
+   /// \param name  A name of the histogram
+   int FindHistogram(const std::string& name);
+
+   /// \brief Prepares canvases using received canvas configuration
+   /// \param uCanvIdx Index of canvas
+   bool PrepareCanvas(uint32_t uCanvIdx);
+
+   /// \brief Resets handled histograms
+   bool ResetHistograms();
+
+   /// \brief Saves handled histograms
+   bool SaveHistograms();
 
-    template<class HistoT>
-    bool ReadHistogram(HistoT* pHist);
-    int FindHistogram(const std::string& name);
-    bool PrepareCanvas(uint32_t uCanvIdx);
+   /// \brief A handler for system signals
+   /// \param signal  Signal ID
+   //static void SignalHandler(int signal);
 
-    bool ResetHistograms();
-    bool SaveHistograms();
 
   private:
     ProgramOptions const& fOpt;      ///< Program options object
@@ -74,7 +99,7 @@ namespace cbm::services::histserv
     /// Vector of string with ( HistoName, FolderPath ) to configure the histogram
     std::vector<std::pair<std::string, std::string>> fvpsHistosFolder = {};
     /// Vector of string pairs with ( CanvasName, CanvasConfig ) to configure the canvases and histos within
-    /// Format of Can config is "Name;Title;NbPadX(U);NbPadY(U);ConfigPad1(s);....;ConfigPadXY(s)"
+    /// Format of Can config is "Name;Title;NbPadX(U);NbPadY(U);ConfigPad2(s);....;ConfigPadXY(s)"
     /// Format of Pad config is "GrixX(b),GridY(b),LogX(b),LogY(b),LogZ(b),HistoName(s),DrawOptions(s)"
     std::vector<std::pair<std::string, std::string>> fvpsCanvasConfig = {};
     std::vector<bool> fvbCanvasReady                                  = {};