From 7b46138b25e49299b87f72aa3ada76d8b5e9d4de Mon Sep 17 00:00:00 2001
From: Werner Wiedenmann <wiedenat@cern.ch>
Date: Tue, 4 Oct 2016 16:41:42 +0200
Subject: [PATCH] fix for ATR-14403 (TrigServices-20-10-11)

---
 .../TrigControl/TrigServices/CMakeLists.txt   |   55 +
 .../TrigServices/HltEventLoopMgr.h            |  476 +++
 .../TrigServices/HltROBDataProviderSvc.h      |  224 ++
 .../TrigServices/TrigServices/TrigHLTIssues.h |   37 +
 .../TrigServices/TrigServices/TrigIS.h        |   79 +
 .../TrigServices/TrigServices/TrigISHelper.h  |  211 ++
 .../TrigServices/TrigMessageSvc.h             |  226 ++
 .../TrigControl/TrigServices/cmt/requirements |   49 +
 .../TrigServices/python/HltTHistSvcConfig.py  |   28 +
 .../TrigServices/python/TrigServicesConfig.py |   27 +
 .../python/TriggerUnixStandardSetup.py        |  243 ++
 .../TrigServices/python/__init__.py           |    6 +
 .../TrigServices/share/MessageSvc.py          |   79 +
 .../TrigServices/share/OfflineTHistSvc.py     |   17 +
 .../share/TrigServicesBootstrap.py            |   29 +
 .../share/TrigServicesCommonBegin.py          |   20 +
 .../share/TrigServicesCommonEnd.py            |   19 +
 .../share/TrigServicesEventLoopMgr.py         |   76 +
 .../share/TrigServicesTHistSvc.py             |   59 +
 .../TrigControl/TrigServices/share/hadd.C     |  212 ++
 .../TrigControl/TrigServices/share/hadd.sh    |   66 +
 .../TrigServices/src/HltEventLoopMgr.cxx      | 3234 +++++++++++++++++
 .../src/HltROBDataProviderSvc.cxx             | 1279 +++++++
 .../TrigServices/src/THistSvcHLT.cxx          | 2089 +++++++++++
 .../TrigServices/src/THistSvcHLT.h            |  230 ++
 .../TrigServices/src/THistSvcHLT.icc          |  311 ++
 .../TrigServices/src/TrigCOOLUpdateHelper.cxx |  404 ++
 .../TrigServices/src/TrigCOOLUpdateHelper.h   |  191 +
 .../TrigControl/TrigServices/src/TrigIS.cxx   |   85 +
 .../TrigServices/src/TrigISHelper.cxx         |  139 +
 .../TrigServices/src/TrigMessageSvc.cxx       | 1203 ++++++
 .../TrigServices/src/TrigMonTHistSvc.cxx      |  403 ++
 .../TrigServices/src/TrigMonTHistSvc.h        |  134 +
 .../TrigServices/src/TrigPreFlightCheck.cxx   |   87 +
 .../TrigServices/src/TrigPreFlightCheck.h     |   70 +
 .../src/TrigSORFromPtreeHelper.cxx            |  253 ++
 .../TrigServices/src/TrigSORFromPtreeHelper.h |   65 +
 .../src/components/TrigServices_entries.cxx   |   30 +
 .../src/components/TrigServices_load.cxx      |    3 +
 39 files changed, 12448 insertions(+)
 create mode 100644 HLT/Trigger/TrigControl/TrigServices/CMakeLists.txt
 create mode 100644 HLT/Trigger/TrigControl/TrigServices/TrigServices/HltEventLoopMgr.h
 create mode 100644 HLT/Trigger/TrigControl/TrigServices/TrigServices/HltROBDataProviderSvc.h
 create mode 100644 HLT/Trigger/TrigControl/TrigServices/TrigServices/TrigHLTIssues.h
 create mode 100644 HLT/Trigger/TrigControl/TrigServices/TrigServices/TrigIS.h
 create mode 100644 HLT/Trigger/TrigControl/TrigServices/TrigServices/TrigISHelper.h
 create mode 100644 HLT/Trigger/TrigControl/TrigServices/TrigServices/TrigMessageSvc.h
 create mode 100755 HLT/Trigger/TrigControl/TrigServices/cmt/requirements
 create mode 100644 HLT/Trigger/TrigControl/TrigServices/python/HltTHistSvcConfig.py
 create mode 100644 HLT/Trigger/TrigControl/TrigServices/python/TrigServicesConfig.py
 create mode 100644 HLT/Trigger/TrigControl/TrigServices/python/TriggerUnixStandardSetup.py
 create mode 100644 HLT/Trigger/TrigControl/TrigServices/python/__init__.py
 create mode 100644 HLT/Trigger/TrigControl/TrigServices/share/MessageSvc.py
 create mode 100644 HLT/Trigger/TrigControl/TrigServices/share/OfflineTHistSvc.py
 create mode 100644 HLT/Trigger/TrigControl/TrigServices/share/TrigServicesBootstrap.py
 create mode 100644 HLT/Trigger/TrigControl/TrigServices/share/TrigServicesCommonBegin.py
 create mode 100644 HLT/Trigger/TrigControl/TrigServices/share/TrigServicesCommonEnd.py
 create mode 100644 HLT/Trigger/TrigControl/TrigServices/share/TrigServicesEventLoopMgr.py
 create mode 100644 HLT/Trigger/TrigControl/TrigServices/share/TrigServicesTHistSvc.py
 create mode 100644 HLT/Trigger/TrigControl/TrigServices/share/hadd.C
 create mode 100755 HLT/Trigger/TrigControl/TrigServices/share/hadd.sh
 create mode 100644 HLT/Trigger/TrigControl/TrigServices/src/HltEventLoopMgr.cxx
 create mode 100644 HLT/Trigger/TrigControl/TrigServices/src/HltROBDataProviderSvc.cxx
 create mode 100644 HLT/Trigger/TrigControl/TrigServices/src/THistSvcHLT.cxx
 create mode 100644 HLT/Trigger/TrigControl/TrigServices/src/THistSvcHLT.h
 create mode 100644 HLT/Trigger/TrigControl/TrigServices/src/THistSvcHLT.icc
 create mode 100644 HLT/Trigger/TrigControl/TrigServices/src/TrigCOOLUpdateHelper.cxx
 create mode 100644 HLT/Trigger/TrigControl/TrigServices/src/TrigCOOLUpdateHelper.h
 create mode 100644 HLT/Trigger/TrigControl/TrigServices/src/TrigIS.cxx
 create mode 100644 HLT/Trigger/TrigControl/TrigServices/src/TrigISHelper.cxx
 create mode 100644 HLT/Trigger/TrigControl/TrigServices/src/TrigMessageSvc.cxx
 create mode 100644 HLT/Trigger/TrigControl/TrigServices/src/TrigMonTHistSvc.cxx
 create mode 100644 HLT/Trigger/TrigControl/TrigServices/src/TrigMonTHistSvc.h
 create mode 100644 HLT/Trigger/TrigControl/TrigServices/src/TrigPreFlightCheck.cxx
 create mode 100644 HLT/Trigger/TrigControl/TrigServices/src/TrigPreFlightCheck.h
 create mode 100644 HLT/Trigger/TrigControl/TrigServices/src/TrigSORFromPtreeHelper.cxx
 create mode 100644 HLT/Trigger/TrigControl/TrigServices/src/TrigSORFromPtreeHelper.h
 create mode 100644 HLT/Trigger/TrigControl/TrigServices/src/components/TrigServices_entries.cxx
 create mode 100644 HLT/Trigger/TrigControl/TrigServices/src/components/TrigServices_load.cxx

diff --git a/HLT/Trigger/TrigControl/TrigServices/CMakeLists.txt b/HLT/Trigger/TrigControl/TrigServices/CMakeLists.txt
new file mode 100644
index 00000000000..007f3f211fc
--- /dev/null
+++ b/HLT/Trigger/TrigControl/TrigServices/CMakeLists.txt
@@ -0,0 +1,55 @@
+################################################################################
+# Package: TrigServices
+################################################################################
+
+# Declare the package name:
+atlas_subdir( TrigServices )
+
+# Declare the package's dependencies:
+atlas_depends_on_subdirs( PUBLIC
+                          Control/AthenaBaseComps
+                          Control/AthenaKernel
+                          Control/StoreGate
+                          Event/ByteStreamCnvSvcBase
+                          Event/ByteStreamData
+                          Event/EventInfo
+                          Event/xAOD/xAODEventInfo
+                          GaudiKernel
+                          HLT/Trigger/TrigControl/TrigKernel
+                          Trigger/TrigDataAccess/TrigDataAccessMonitoring
+                          Trigger/TrigDataAccess/TrigROBDataProviderSvc
+                          Trigger/TrigEvent/TrigSteeringEvent
+                          PRIVATE
+                          Control/CLIDSvc
+                          Control/SGTools
+                          Database/AthenaPOOL/AthenaPoolUtilities
+                          Trigger/TrigConfiguration/TrigConfInterfaces
+                          Trigger/TrigEvent/TrigNavigation
+                          Trigger/TrigMonitoring/TrigMonitorBase
+                          Trigger/TrigSteer/TrigInterfaces )
+
+# External dependencies:
+find_package( Boost COMPONENTS filesystem thread system )
+find_package( CORAL COMPONENTS CoralBase CoralKernel RelationalAccess )
+find_package( ROOT COMPONENTS Core Tree MathCore Hist RIO pthread )
+find_package( tdaq COMPONENTS omniORB4 omnithread ipc is owl )
+find_package( tdaq-common COMPONENTS CTPfragment eformat eformat_write hltinterface )
+
+# Component(s) in the package:
+atlas_add_library( TrigServicesLib
+                   src/*.cxx
+                   PUBLIC_HEADERS TrigServices
+                   INCLUDE_DIRS ${TDAQ-COMMON_INCLUDE_DIRS} ${TDAQ_INCLUDE_DIRS}
+                   PRIVATE_INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS} ${CORAL_INCLUDE_DIRS}
+                   LINK_LIBRARIES ${TDAQ-COMMON_LIBRARIES} ${TDAQ_LIBRARIES} AthenaBaseComps AthenaKernel ByteStreamData EventInfo xAODEventInfo GaudiKernel TrigKernel TrigSteeringEvent StoreGateLib SGtests ByteStreamCnvSvcBaseLib ByteStreamData_test TrigDataAccessMonitoringLib TrigROBDataProviderSvcLib TrigNavigationLib TrigMonitorBaseLib TrigInterfacesLib
+                   PRIVATE_LINK_LIBRARIES ${ROOT_LIBRARIES} ${Boost_LIBRARIES} ${CORAL_LIBRARIES} SGTools AthenaPoolUtilities )
+
+atlas_add_component( TrigServices
+                     src/components/*.cxx
+                     INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS} ${CORAL_INCLUDE_DIRS} ${TDAQ-COMMON_INCLUDE_DIRS} ${TDAQ_INCLUDE_DIRS}
+                     LINK_LIBRARIES ${ROOT_LIBRARIES} ${Boost_LIBRARIES} ${CORAL_LIBRARIES} ${TDAQ-COMMON_LIBRARIES} ${TDAQ_LIBRARIES} AthenaBaseComps AthenaKernel StoreGateLib SGtests ByteStreamCnvSvcBaseLib ByteStreamData ByteStreamData_test EventInfo xAODEventInfo GaudiKernel TrigKernel TrigDataAccessMonitoringLib TrigROBDataProviderSvcLib TrigSteeringEvent SGTools AthenaPoolUtilities TrigNavigationLib TrigMonitorBaseLib TrigInterfacesLib TrigServicesLib )
+
+# Install files from the package:
+atlas_install_python_modules( python/*.py )
+atlas_install_joboptions( share/*.py )
+
diff --git a/HLT/Trigger/TrigControl/TrigServices/TrigServices/HltEventLoopMgr.h b/HLT/Trigger/TrigControl/TrigServices/TrigServices/HltEventLoopMgr.h
new file mode 100644
index 00000000000..e13807e457e
--- /dev/null
+++ b/HLT/Trigger/TrigControl/TrigServices/TrigServices/HltEventLoopMgr.h
@@ -0,0 +1,476 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef TRIGSERVICES_HLTEVENTLOOPMGR_H
+#define TRIGSERVICES_HLTEVENTLOOPMGR_H
+
+#include "TrigKernel/ITrigEventLoopMgr.h"
+#include "EventInfo/EventID.h"  /* number_type */
+#include "EventInfo/TriggerInfo.h"
+#include "xAODEventInfo/EventInfo.h"
+#include "eformat/eformat.h"
+
+// Framework include files
+#include "GaudiKernel/ServiceHandle.h"
+#include "GaudiKernel/SmartIF.h"
+#include "GaudiKernel/ToolHandle.h"
+#include "GaudiKernel/MinimalEventLoopMgr.h"
+#include "GaudiKernel/MsgStream.h"
+#include "GaudiKernel/HistoProperty.h"
+#include "AthenaKernel/Timeout.h"
+#include "TrigKernel/HltOstreams.h"
+#include "TrigKernel/HltAcceptFlag.h"
+#include "TrigKernel/HltResultStatusCode.h"
+#include "TrigKernel/HltPscErrorCode.h"
+#include "TrigKernel/IHltTHistSvc.h"
+#include "TrigROBDataProviderSvc/ITrigROBDataProviderSvc.h"
+
+#include <tuple>
+#include <utility>
+#include <functional>
+#include <memory>
+#include <vector>
+#include <set>
+#include <stdint.h>
+
+// Forward declarations
+class IIncidentSvc;
+class IAlgContextSvc;
+class StoreGateSvc;
+class IROBDataProviderSvc;
+class ITHistSvc;
+class TrigISHelper;
+class TH1F;
+class TH2I;
+class TProfile;
+class EventInfo;
+class TrigCOOLUpdateHelper;
+class CondAttrListCollection;
+namespace coral {
+  class AttributeList;
+}
+namespace TrigConf {
+  class IHLTConfigSvc;
+}
+namespace HLT {
+  class HLTResult;
+}
+namespace eformat {
+  namespace write {
+    class ROBFragment;
+  }
+}
+
+class HltEventLoopMgr : public MinimalEventLoopMgr,
+                        virtual public ITrigEventLoopMgr,
+                        virtual public Athena::TimeoutMaster
+{
+
+public:
+  /// Creator friend class
+  friend class SvcFactory<HltEventLoopMgr>;
+
+  /// Standard Constructor
+  HltEventLoopMgr(const std::string& nam, ISvcLocator* svcLoc);
+  /// Standard Destructor
+  virtual ~HltEventLoopMgr();
+
+  /// implementation of IInterface: queryInterface
+  virtual StatusCode queryInterface(const InterfaceID& riid, void** ppvInterface);
+
+  /// \name State transitions
+  //@{
+  virtual StatusCode sysInitialize();
+  virtual StatusCode initialize();
+  
+  virtual StatusCode prepareForRun(const boost::property_tree::ptree & pt);
+
+  virtual StatusCode hltUpdateAfterFork(const boost::property_tree::ptree & pt);
+
+  virtual StatusCode stop();
+
+  virtual StatusCode sysFinalize();
+  virtual StatusCode finalize();
+
+  virtual StatusCode sysReinitialize();
+  virtual StatusCode reinitialize();  
+  //@}
+  
+  /// Event processing
+  virtual StatusCode executeEvent(void* par);
+  
+  virtual StatusCode
+  processRoIs(const std::vector<eformat::ROBFragment<const uint32_t*> >& l1_result,
+              hltinterface::HLTResult& hlt_result,
+              const hltinterface::EventId& evId);
+
+  /// Event timoeut reached
+  virtual StatusCode timeOutReached(const boost::property_tree::ptree& pt);
+
+  /// return the application Name
+  std::string applicationName() const { return m_applicationName.value(); }
+
+    /// \name Obsolete methods for online running
+  //@{
+  virtual StatusCode nextEvent(int maxevt);          ///< Obsolete
+  virtual StatusCode executeRun(int runNumber);      ///< Obsolete
+  virtual StatusCode stopRun();                      ///< Obsolete
+  virtual StatusCode start();                        ///< Obsolete
+  //@}
+  
+private:
+
+  /**
+   * @brief Accessor method for the MsgStream.
+   * @return handle to the MsgStream.
+   */
+  inline MsgStream& logStream() const { return *m_msg; }
+
+  /**
+   * @brief Accessor method for the message level variable.
+   * @return value of the message level for this algorithm.
+   */
+  inline MSG::Level logLevel() const { return  (m_msg != 0) ? m_msg->level() : MSG::NIL; }
+
+   /**
+   * @brief Call execute method of algorithms
+   * @return FAILURE in case one algorithm failed
+   */
+  StatusCode executeAlgorithms();
+
+  /**
+   * @brief Check if an HLT prescale update is required
+   * @param hltCounter  list of "HLT counters" from CTP fragment (only one used)
+   */
+  StatusCode checkHltPrescaleUpdate(std::vector<uint32_t>& hltCounter);
+
+  /**
+   * @brief Do HLT prescale update
+   * @param lumiBlock  LB for which the update should be done
+   */
+  StatusCode hltPrescaleUpdate(uint32_t lumiBlock);
+  
+  /**
+   * @brief Helper to fill histograms from HLT result
+   * @param hlt_result          reference to dataflow HLTResult object
+   */
+  void fillHltResultHistograms(const hltinterface::HLTResult& hlt_result);
+  
+  /// Check if running in partition
+  bool validPartition() const {
+    return (m_partitionName.value()!="None" && m_partitionName.value()!="NONE");  
+  }
+
+  /**
+   * @brief Helper to set PSC error word
+   * @param hlt_result    reference to dataflow HLTResult object; filled on return
+   * @param pscErrorCode  PSC Error code which should be set
+   */
+  void HltSetPscError(hltinterface::HLTResult& hlt_result,
+                      hltonl::PSCErrorCode pscErrorCode) const;
+
+  /**
+   * @brief Helper to build an empty dataflow HLT Result object
+   * @param hlt_result          reference to dataflow HLTResult object; filled on return
+   * @param run_no              for ROB fragment 
+   * @param lvl1_id             for ROB fragment 
+   * @param bunch_crossing_id   for ROB fragment
+   * @param l1_Trigger_Type     for ROB fragment
+   * @param l1_detev_type       for ROB fragment
+   * @param pscErrorCode        PSC Error code which should be set
+   */
+  void HltEmptyResultROB(hltinterface::HLTResult& hlt_result,
+			 uint32_t run_no, uint32_t lvl1_id, uint32_t bunch_crossing_id, 
+			 uint32_t l1_Trigger_Type, uint32_t l1_detev_type,
+			 hltonl::PSCErrorCode pscErrorCode);
+
+  /**
+   * @brief Helper to build the dataflow HLT Result object.
+   * @return value              error code hltonl::PSCErrorCode 
+   * @param hlt_result          reference to dataflow HLTResult object; filled on return
+   * @param run_no              for ROB fragment 
+   * @param lvl1_id             for ROB fragment 
+   * @param bunch_crossing_id   for ROB fragment
+   * @param l1_Trigger_Type     for ROB fragment
+   * @param l1_detev_type       for ROB fragment
+   * @param trigger_info        trigger info words for the HLT
+   * @param stream_tags         stream tags generated during HLT processing
+   */
+  hltonl::PSCErrorCode HltResultROBs(hltinterface::HLTResult& hlt_result,
+				       uint32_t run_no, uint32_t lvl1_id, uint32_t bunch_crossing_id, 
+				       uint32_t l1_Trigger_Type, uint32_t l1_detev_type,
+				       const std::vector<TriggerInfo::number_type>& trigger_info, 
+				       const std::vector<TriggerInfo::StreamTag>& stream_tags,
+				       const std::vector<xAOD::EventInfo::StreamTag>& xsts);
+
+  /// Helper to build an empty HLTResult object
+  void HltEmptyResultROB(hltinterface::HLTResult& hlt_result,
+                         hltonl::PSCErrorCode pscErrorCode);
+  /// Helper to build HLTResult object from Steering result
+  void HltResult(hltinterface::HLTResult& hlt_result,
+                 const EventInfo* pEvent,
+                 const xAOD::EventInfo* xev);
+  /// Helpers to book histograms
+  void bookHistograms();
+  void HltBookHistograms();
+  void bookAllHistograms();
+  void updateDFProps();
+  // Call a simple IAlgorithm (usually member) function on all algorithms
+  StatusCode callOnAlgs(const std::function<StatusCode(IAlgorithm&)> & func,
+                        const std::string & fname, bool failureIsError = false);
+  StatusCode prepareAlgs(const EventInfo& evinfo);
+  /// Helper to reset necessary data at prepareForRun
+  StatusCode internalPrepareResets();
+  /// Helper to do whatever is necessary with RunParams (prepare) ptree
+  const CondAttrListCollection *
+  processRunParams(const boost::property_tree::ptree & pt);
+  // Helper to update internally kept data from new sor
+  void updInternal(const coral::AttributeList & sor_attrlist);
+  // Helper to get update the metadata store with a new metadata record
+  void updMetadaStore(const coral::AttributeList & sor_attrlist);
+  /// Helper to clear per-event stores
+  StatusCode clearTemporaryStores();
+  /// Helper to update the detector mask
+  void updDetMask(const std::pair<uint64_t, uint64_t>& dm);
+  /// Helper to update the SOR time stamp
+  void updSorTime(unsigned long long st);
+  /// Helper to extract the single attr list off the SOR CondAttrListCollection
+  const coral::AttributeList &
+  getSorAttrList(const CondAttrListCollection * sor) const;
+  /// Update the HLTConfigSvc (only required to succeed with DB based config)
+  StatusCode updHLTConfigSvc();
+  /// Set the EventInfo in the event store and return it
+  const EventInfo * prepEventInfo() const;
+  /// Set the xAOD::EventInfo in the event store
+  StatusCode prepXAODEventInfo() const;
+  /// Update the magnet field from IS when necessary and possible
+  StatusCode updMagField(const boost::property_tree::ptree& pt) const;
+  /// Reset selected proxies / IOV folders
+  StatusCode resetCoolValidity();
+  /// Helper to log a message with some details when ready to run
+  void readyMsg() const;
+  /// Helper to fill in HLTResult with stream tags
+  void setStreamTags(hltinterface::HLTResult& hltr,
+                  const std::vector<TriggerInfo::StreamTag>& stream_tags) const;
+  void mergeStreamTags(hltinterface::HLTResult& hltr,
+                     const std::vector<xAOD::EventInfo::StreamTag>& xsts) const;
+  /// get the right hlt decision, setting debug stream tag if necessary
+  hltonl::AcceptFlag processHltDecision(hltinterface::HLTResult& hltr) const;
+  /// Serializes Steering's result into hltinterface's result robs
+  hltonl::PSCErrorCode serializeRobs(hltinterface::HLTResult& hltr, bool& serOk,
+                                     HLT::HLTResult* dobj, uint32_t rn,
+                                     uint32_t l1id, uint32_t bcid,
+                                     uint32_t l1tt, uint32_t dett);
+  // Check whether a rob fits the space left. If not, issue an error
+  bool checkRobSize(uint32_t robsize, uint32_t spaceleft, uint32_t maxsize);
+  // Check consistency of the info received in the EventId and the CTP fragment
+  bool checkEventIdConsistency(const hltinterface::EventId& evId) const;
+  // serialize rob from steering's HLTResult
+  bool serializeRob(uint32_t*& tmpstor,
+                    eformat::write::ROBFragment& rob,
+                    HLT::HLTResult& dobj,
+                    unsigned int robid,
+                    int payload_max);
+  // add rob to hltinterface::HLTResult
+  void addRobToHLTResult(hltinterface::HLTResult& hltr,
+                         eformat::write::ROBFragment& rob,
+                         uint32_t*& next_fragment,
+                         uint32_t& spaceleft); /* don't pass original
+                         fragment_pointer or max_result_size (notice parameters
+                         passed by reference) */
+  // Get monitoring information for navigation sizes of HLT EDM
+  void recordEDMSizeInfo(size_t nav_size, bool serializationOk) const;
+  // check if a ROB is enabled for readout in OKS
+  bool isRobEnabled(uint32_t robid) const;
+  // check if a Sub Detector is enabled for readout in OKS
+  bool isSubDetectorEnabled(uint32_t subdetid) const;
+  // filter a set of robs according to whether or not they are enabled
+  std::set<uint32_t> filterRobs(const std::set<uint32_t> robs) const;
+  // filter a set of dets according to whether or not they are enabled
+  std::set<eformat::SubDetector>
+  filterDets(const std::set<uint32_t> dets) const;
+
+  // act on failure to process event
+  void failedEvent(hltinterface::HLTResult& hlt_result,
+                   hltonl::PSCErrorCode ecode,
+                   const std::string& emsg,
+                   bool empty_result = true);
+
+  // get a vector with the ids of the expected L1R robs that are missing
+  std::vector<uint32_t>
+  missingL1Robs(const std::vector<eformat::ROBFragment<const uint32_t*>>& l1r)
+  const;
+
+  // check whether a subdetector is in the run, according to the current detmask
+  bool isSubDetectorIn(eformat::SubDetector sd) const;
+
+  /** Handles to required services/tools **/
+  typedef ServiceHandle<IIncidentSvc> IIncidentSvc_t;
+  IIncidentSvc_t         m_incidentSvc;
+
+  typedef ServiceHandle<StoreGateSvc> StoreGateSvc_t;
+  StoreGateSvc_t         m_evtStore;
+  StoreGateSvc_t         m_detectorStore;
+  StoreGateSvc_t         m_inputMetaDataStore;
+
+  typedef ServiceHandle<IROBDataProviderSvc> IIROBDataProviderSvc_t;
+  IIROBDataProviderSvc_t m_robDataProviderSvc;
+
+  typedef ServiceHandle<ITHistSvc> ITHistSvc_t;
+  ITHistSvc_t            m_THistSvc;
+
+  ToolHandle<TrigISHelper>            m_isHelper;
+  ToolHandle<TrigCOOLUpdateHelper>    m_coolHelper;
+
+  /** Pointers to optional services/tools **/
+  TrigConf::IHLTConfigSvc* m_hltConfigSvc;
+  IAlgContextSvc*          m_algContextSvc;
+
+  IntegerProperty          m_lvl1CTPROBid ;       // Source ID for CTP ROB fragment
+  BooleanProperty          m_doMonitoring;        // Monitoring
+
+  /// Helper classes for error codes
+  hltonl::MapPscErrorCode  m_mapPscError;
+  hltonl::MapResultStatusCode m_mapResultStatus;
+  hltonl::MapAcceptFlag       m_mapAccept;
+
+  MsgStream*                m_msg       ;   //!< Pointer to MsgStream
+  EventID::number_type      m_currentRun;   //!< current run number
+  EventID::number_type      m_currentLB;    //!< current lumiblock
+  const EventInfo*          m_currentEvent; //!< current EventInfo object in StoreGate
+  
+  /// Start of Run Time: posix time in seconds since 1970/01/01
+  /// Start of Run Time: time stamp ns - ns time offset for time_stamp, 32 bit unsigned
+  std::vector<EventID::number_type> m_sorTime_stamp;
+
+  /// detector mask0,1,2,3 - bit field indicating which TTC zones have been
+  /// built into the event, one bit per zone, 128 bit total
+  /// significance increases from first to last
+  typedef EventID::number_type numt;
+  std::tuple<numt, numt, numt, numt> m_detector_mask;
+
+  uint32_t                  m_l1_hltPrescaleUpdateLB;    //!< LB of prescale update from CTP fragment
+  
+  // --------------------------- Monitoring Histograms --------------------------
+  TH1F*                     m_hist_eventAcceptFlags;            //!< Accept flags for processed events
+  TH1F*                     m_hist_frameworkErrorCodes;         //!< PSC error codes
+  TH1F*                     m_hist_Hlt_result_size;             //!< size of HLT result
+  TH1F*                     m_hist_Hlt_result_status;           //!< Status flags in HLT result
+  TH1F*                     m_hist_numStreamTags;               //!< Number of StreamTags from HLT
+  TH1F*                     m_hist_streamTagTypes;              //!< StreamTag types from HLT   
+  TH1F*                     m_hist_streamTagNames;              //!< StreamTag names from HLT
+  TH1F*                     m_hist_num_partial_eb_robs;         //!< Number of ROBs for partial event building from HLT   
+  TH1F*                     m_hist_num_partial_eb_SubDetectors; //!< Number of SubDetectors for partial event building from HLT 
+  TH1F*                     m_hist_partial_eb_SubDetectors_ROBs;//!< SubDetectors for partial event building derived from ROB list
+  TH1F*                     m_hist_partial_eb_SubDetectors_SDs; //!< SubDetectors for partial event building derived from SubDetector list
+  TH1F*                     m_hist_Hlt_result_size_physics;           //!< size of HLT result in physics Main
+  TH1F*                     m_hist_Hlt_result_size_express;           //!< size of HLT result in express stream
+  TH1F*                     m_hist_Hlt_result_size_DataScouting;      //!< size of HLT result in express stream
+  TProfile*                 m_hist_HltResultSizes_Stream_physics;     //!< HLT Result sizes for physiscs streams
+  TProfile*                 m_hist_HltResultSizes_Stream_DataScouting;//!< HLT Result sizes for DataScouting streams
+  TProfile*                 m_hist_HltEdmSizes_No_Truncation;   //!< HLT EDM sizes for all events without a truncated HLT result 
+  TProfile*                 m_hist_HltEdmSizes_With_Truncation; //!< HLT EDM sizes for all events with a truncated HLT result 
+  TProfile*                 m_hist_HltEdmSizes_TruncatedResult_Retained_Collections; //!< HLT EDM sizes for all collections which were retained in a truncated HLT result
+  TProfile*                 m_hist_HltEdmSizes_TruncatedResult_Truncated_Collections;//!< HLT EDM sizes for all collections which were truncated in a truncated HLT result
+  // --------------------------- Properties -------------------------------------
+  BooleanProperty           m_setMagFieldFromPtree; //!< Read magnet currents from ptree
+  StringProperty            m_applicationName;      //!< Application Name (="None" or "athenaHLT" for simulated data, "HLTMPPU-xx"? in online environment) */
+  StringProperty            m_partitionName;        //!< Partition Name (="None" for offline, real partion name in online environment)
+  BooleanProperty           m_forceHltReject;      // force reject of all events 
+  BooleanProperty           m_forceHltAccept;      // force accept of all events
+  StringProperty            m_HltResultName;       // name of HLT result in StoreGate
+  StringProperty            m_HltDebugStreamName;  // stream name for Debug events 
+  StringProperty            m_HltForcedStreamName; // stream name for forced accept events
+  IntegerProperty           m_predefinedLumiBlock;
+  IntegerProperty           m_prepareForRunSleep;    //!< max random sleep during prepareForRun in sec
+
+  typedef SimpleProperty< std::vector<uint32_t> > Uint32ArrayProperty;
+  Uint32ArrayProperty       m_enabledROBs;         //!< list of all enabled ROBs which can be retrieved
+  Uint32ArrayProperty       m_enabledSubDetectors; //!< list of all enabled Sub Detectors which can be retrieved
+  Uint32ArrayProperty       m_mandatoryL1ROBs;     //!< list of mandatory ROB IDs coming from the RoIB (must come in L1R seed)
+
+  StringArrayProperty       m_hltEdmCollectionNames; //!< names of all HLT EDM collections for histogram label 
+  
+  StringProperty            m_jobOptionsType;        //!< JobOptions type (="NONE" or "DB", same as in PSC)
+
+  Histo1DProperty           m_histProp_Hlt_result_size;  
+  Histo1DProperty           m_histProp_numStreamTags;              
+  Histo1DProperty           m_histProp_streamTagNames;  
+  Histo1DProperty           m_histProp_num_partial_eb_robs;
+  Histo1DProperty           m_histProp_Hlt_Edm_Sizes;       //!< HLT EDM sizes profile plots 
+
+  int                       m_total_evt;
+  int                       m_failed_evt;
+  int                       m_invalid_lvl1_result;
+  int                       m_invalid_hlt_result;
+  int                       m_truncated_hlt_result;
+  int                       m_truncated_hlt_result_to_debug;
+  int                       m_truncated_hlt_result_not_to_debug;
+
+  // for CTP Lvl1 Rob
+  std::vector<uint32_t>     m_ctpRobIdVec ;
+  // event number - 32 bit unsigned
+  uint32_t                  m_lvl1id  ;
+  // run number - 32 bit unsigned
+  EventID::number_type      m_run_no ;
+  // bunch crossing ID,  32 bit unsigned
+  EventID::number_type      m_bunch_crossing_id ;
+  // time stamp - posix time in seconds from 1970, 32 bit unsigned
+  EventID::number_type      m_time_stamp ;
+  // time stamp ns - ns time offset for time_stamp, 32 bit unsigned
+  EventID::number_type      m_time_stamp_ns_offset ;
+  // luminosity block identifier, 32 bit unsigned
+  EventID::number_type      m_lumi_block ;
+  // status element
+  TriggerInfo::number_type  m_l1_Status_Element ;
+  // LVL1 trigger type
+  TriggerInfo::number_type  m_l1_Trigger_Type ;
+  // LVL1 trigger info
+  std::vector<TriggerInfo::number_type> m_l1_Trigger_Info ;
+  // LVL1 detev type
+  uint32_t                  m_l1_detev_type ;
+
+  /// Reference to a THistSvc which implements also the Hlt additions
+  SmartIF<IHltTHistSvc>     m_hltTHistSvc;
+
+  /// Reference to a ROBDataProviderSvc which implements also the Hlt additions
+  SmartIF<ITrigROBDataProviderSvc> m_hltROBDataProviderSvc;
+
+  /// Check integrity of CTP ROB and put event to debug stream when it fails
+  BooleanProperty           m_lvl1CTPROBcheck ;
+
+  /// Monitoring
+  TH1F*                     m_hist_l1_robs;
+
+  /// Flag to write events with truncated HLT result to a special debug stream
+  BooleanProperty           m_writeHltTruncationToDebug ;
+  /// Debug stream name for events with a truncated HLT result 
+  StringProperty            m_HltTruncationDebugStreamName; 
+  /// Stream names for which events should be not send to the debug stream even when the HLT result is truncated
+  StringArrayProperty       m_excludeFromHltTruncationDebugStream; 
+  /// Monitoring histogram for truncated HLT results
+  TH1F*                     m_hist_Hlt_truncated_result;
+
+  /// we need this maintain the data
+  uint32_t                  m_status_words[3];
+
+};
+
+//=========================================================================
+inline StatusCode HltEventLoopMgr::start()
+{
+  // This method might be called by ServiceManager::start and does nothing.
+  // The real start method is prepareForRun and invoked by the PSC.
+  return StatusCode::SUCCESS;
+}
+
+//=========================================================================
+inline void
+HltEventLoopMgr::HltSetPscError(hltinterface::HLTResult& hlt_result,
+                                hltonl::PSCErrorCode pscErrorCode) const
+{
+  hlt_result.psc_errors.push_back(pscErrorCode);
+}
+
+#endif // TRIGSERVICES_HLTEVENTLOOPMGR_H
diff --git a/HLT/Trigger/TrigControl/TrigServices/TrigServices/HltROBDataProviderSvc.h b/HLT/Trigger/TrigControl/TrigServices/TrigServices/HltROBDataProviderSvc.h
new file mode 100644
index 00000000000..1a336a23814
--- /dev/null
+++ b/HLT/Trigger/TrigControl/TrigServices/TrigServices/HltROBDataProviderSvc.h
@@ -0,0 +1,224 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef TRIGSERVICES_HLTROBDATAPROVIDERSVC_H
+#define TRIGSERVICES_HLTROBDATAPROVIDERSVC_H
+
+/** ===============================================================
+ *     HltROBDataProviderSvc.h
+ *  ===============================================================
+ *    Description:  ROBDataProvider class for accessing ROBData
+ *                  To be used for Offline/Online
+ *
+ *    Requirements: define a ROBData class in the scope
+ *                  provide a method
+ *       void getROBData(const vector<uint>& ids, vector<ROBData*>& v)
+ *    Implementation: Use an interal map to store all ROBs
+ *                    We can not assume any ROB/ROS relationship, no easy 
+ *                    way to search.
+ * 
+ *    Created:      Sept 19, 2002
+ *         By:      Hong Ma 
+ *    Modified:     Aug. 18  2003 (common class for Online/Offline)
+ *         By:      Werner Wiedenmann 
+ *    Modified:     Apr  21  2005 (implementation for online)
+ *         By:      Werner Wiedenmann
+ *    Modified:     Jun. 02 2006 (added monitoring horograms)
+ *         By:      Tomasz Bold
+ *    Modified:     May  21  2007 (updates for release 13)
+ *         By:      Werner Wiedenmann
+ *    Modified:     Nov. 10  2008 (updates for L2/EF result node ID handling)   
+ *         By:      Werner Wiedenmann
+ *    Modified:     Mar. 05, 2013 (adapted from L2 for merged HLT)
+ *         By:      Ricardo Abreu
+ *    Modified:     Nov. 04, 2013 (implement complete hltinterface definitions)
+ *         By:      Werner Wiedenmann
+ */ 
+#include "GaudiKernel/Service.h"
+#include "GaudiKernel/ISvcLocator.h"
+#include "GaudiKernel/StatusCode.h"
+#include "GaudiKernel/IIncidentListener.h"
+#include "GaudiKernel/MsgStream.h"
+#include "GaudiKernel/ServiceHandle.h"
+#include "GaudiKernel/HistoProperty.h"
+#include "GaudiKernel/Property.h"
+#include "TrigROBDataProviderSvc/ITrigROBDataProviderSvc.h"
+#include "ByteStreamCnvSvcBase/ROBDataProviderSvc.h"
+#include "ByteStreamData/RawEvent.h"
+#include "TrigDataAccessMonitoring/ROBDataMonitor.h"
+#include "eformat/Status.h"
+#include "hltinterface/DCM_ROBInfo.h"
+#include <vector>
+#include <map>
+
+// Forward declarations
+class StoreGateSvc;  
+class IAlgContextSvc;
+class TH1F;   /// for monitoring purposes
+class TH2F;   /// for monitoring purposes
+
+class HltROBDataProviderSvc : public ROBDataProviderSvc,
+			       virtual public ITrigROBDataProviderSvc,
+			       virtual public IIncidentListener
+{
+public:
+
+    typedef OFFLINE_FRAGMENTS_NAMESPACE::ROBFragment ROBF ; 
+
+    HltROBDataProviderSvc(const std::string& name, ISvcLocator* svcloc);
+
+    virtual ~HltROBDataProviderSvc(void);
+  
+    virtual StatusCode initialize();
+
+    virtual StatusCode finalize();
+
+    virtual StatusCode queryInterface( const InterfaceID& riid, void** ppvInterface );
+
+    /// --- Implementation of IROBDataProviderSvc interface ---    
+
+    /// Add ROBFragments to cache for given ROB ids, ROB fragments may be retrieved with DataCollector 
+    virtual void addROBData(const std::vector<uint32_t>& robIds,
+			    const std::string callerName="UNKNOWN");
+
+    /// Add a given LVL1/HLT ROBFragment to cache
+    virtual void setNextEvent(const std::vector<ROBF>& result);
+
+    /// Add all ROBFragments of a RawEvent to cache 
+    virtual void setNextEvent(const RawEvent* re);
+
+    /// Retrieve ROBFragments for given ROB ids from cache 
+    virtual void getROBData(const std::vector<uint32_t>& robIds, 
+			    std::vector<const ROBF*>& robFragments,
+			    const std::string callerName="UNKNOWN");
+ 
+    /// Retrieve the whole event.
+    virtual const RawEvent* getEvent() ;
+
+    /// --- Implementation of ITrigROBDataProviderSvc interface ---
+
+    /// Return vector with all ROBFragments stored in the cache 
+    virtual void getAllROBData(std::vector<const ROBF*>& robFragments) ;
+
+    // Dump ROB cache
+    virtual std::string dumpROBcache() const ;
+
+    /// Return size of ROBFragments cache 
+    virtual int sizeROBCache() { return m_online_robmap.size(); }
+
+    /// iterators over cache entries
+    virtual std::map<uint32_t, ROBF>::iterator beginROBCache() { return m_online_robmap.begin(); }
+    virtual std::map<uint32_t, ROBF>::iterator endROBCache()   { return m_online_robmap.end(); }
+
+    /// Flag to check if complete event data are already in cache
+    virtual bool isEventComplete() { return m_isEventComplete; }
+
+    /// Collect all data for an event from the ROS and put them into the cache
+    /// Return value: number of ROBs which were retrieved to complete the event
+    /// Optinonally the name of the caller of this method can be specified for cost monitoring
+    virtual int collectCompleteEventData(const std::string callerName="UNKNOWN");
+
+    /// set the name of the program which uses the ROBDataProviderSvc
+    virtual void setCallerName(const std::string);
+
+    /// get the name of the program which is presently registered in the ROBDataProviderSvc
+    virtual std::string getCallerName() { return m_callerName; };
+
+    /// --- Implementation of IIncidentListener interface ---
+
+    // handler for BeginRun actions
+    void handle(const Incident& incident);
+
+protected:
+    /**
+     * @brief Accessor method for the MsgStream.
+     * @return handle to the MsgStream.
+     */
+    inline MsgStream& logStream() const { return *m_msg; }
+
+    /**
+     * @brief Accessor method for the message level variable.
+     * @return value of the message level for this algorithm.
+     */
+    inline MSG::Level logLevel() const { return  (m_msg != 0) ? m_msg->level() : MSG::NIL; }
+
+private:
+    typedef ServiceHandle<StoreGateSvc> StoreGateSvc_t;
+    /// Reference to StoreGateSvc;
+    StoreGateSvc_t         m_storeGateSvc;
+    
+    /// Pointer to AlgContextSvc 
+    IAlgContextSvc*        m_algContextSvc;
+
+    typedef SimpleProperty< std::vector<uint32_t> > Uint32ArrayProperty;
+    typedef SimpleProperty< std::map<int,int> >     IntegerMapProperty;
+
+    // flag indicates if running in online/offline 
+    bool m_onlineRunning ;
+
+    // read enabled ROBs from OKS when possible
+    BooleanProperty m_readROBfromOKS;
+
+    // list of all enabled ROBs which can be retrieved    
+    Uint32ArrayProperty m_enabledROBs;
+
+    // list of ROBs which should be ignored for retrieval    
+    Uint32ArrayProperty m_ignoreROB;
+
+    // list of all LAr MET ROBs which can be retrieved    
+    Uint32ArrayProperty m_enabledLArMetROBs ;
+    UnsignedIntegerProperty m_genericLArMetModuleID ;
+
+    // list of all Tile MET ROBs which can be retrieved    
+    Uint32ArrayProperty m_enabledTileMetROBs;
+    UnsignedIntegerProperty m_genericTileMetModuleID ;
+
+    // Separate data collector calls to ROS for normal ROBs and MET ROBs
+    BooleanProperty m_separateMETandDetROBRetrieval ;
+
+    // Filter out empty ROB fragments which are send by the ROS
+    bool m_removeEmptyROB;
+
+    // map for all the ROB fragments (cache for ROB data so that they are 
+    // not deleted when local containers go out of scope)
+    typedef std::map<uint32_t, ROBF> ONLINE_ROBMAP;
+    ONLINE_ROBMAP m_online_robmap; 
+
+    // helper function to retrieve ROB fragments over the network and to add them to the cache 
+    void addROBDataToCache(std::vector<uint32_t>& robIdsForRetrieval,         // vector of ROBs to retrieve 
+			   robmonitor::ROBDataMonitorStruct* p_robMonStruct); // pointer to ROB monitoring structure for retrieval
+
+    // helper function to put retrieved ROB fragments into the local cache and update the monitoring records 
+    void updateROBDataCache(std::vector<hltinterface::DCM_ROBInfo>& vRobInfo,  // vector of ROB Info records with retrieved fragments 
+			    robmonitor::ROBDataMonitorStruct* p_robMonStruct); // pointer to ROB monitoring structure
+
+    // Flag to indicate if all event data are already in the cache
+    bool m_isEventComplete;
+
+    // name of the program which presently uses the ROBDataProviderSvc
+    std::string m_callerName;
+
+    /** @brief Pointer to MsgStream.*/
+    MsgStream* m_msg;
+
+    // monitoring
+    std::map<eformat::GenericStatus, std::string> m_map_GenericStatus;
+    std::vector<std::string>                      m_vec_SpecificStatus;
+
+    BooleanProperty m_doMonitoring;
+    BooleanProperty m_doDetailedROBMonitoring;
+    StringProperty  m_ROBDataMonitorCollection_SG_Name;
+
+    Histo1DProperty m_histProp_requestedROBsPerCall;
+    Histo1DProperty m_histProp_receivedROBsPerCall;
+    Histo1DProperty m_histProp_timeROBretrieval;
+
+    TH1F* m_hist_requestedROBsPerCall;
+    TH1F* m_hist_receivedROBsPerCall;
+    TH1F* m_hist_timeROBretrieval;
+    TH2F* m_hist_genericStatusForROB;
+    TH2F* m_hist_specificStatusForROB;
+};
+
+#endif
diff --git a/HLT/Trigger/TrigControl/TrigServices/TrigServices/TrigHLTIssues.h b/HLT/Trigger/TrigControl/TrigServices/TrigServices/TrigHLTIssues.h
new file mode 100644
index 00000000000..3e282bed7f2
--- /dev/null
+++ b/HLT/Trigger/TrigControl/TrigServices/TrigServices/TrigHLTIssues.h
@@ -0,0 +1,37 @@
+// Dear emacs, this is -*- c++ -*-
+
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+/**
+ * @file TrigHLTIssues.h
+ * @author <a href="mailto:Werner.Wiedenmann@cern.ch">Werner Wiedenmann</a>
+ *
+ * @brief ERS issue classes for HLT
+ */
+
+#ifndef TRIG_HLT_ISSUES_H
+#define TRIG_HLT_ISSUES_H
+
+#include "ers/ers.h"
+
+ERS_DECLARE_ISSUE( ers, HLTMessage, , )
+ERS_DECLARE_ISSUE( ers, HLTAbort, "Fatal error during event processing", )
+  
+#define ERS_HLT_WARNING( message ) \
+{ \
+    ERS_REPORT_IMPL( ers::warning, ers::HLTMessage, message, ); \
+}
+
+#define ERS_HLT_ERROR( message ) \
+{ \
+    ERS_REPORT_IMPL( ers::error, ers::HLTMessage, message, ); \
+}
+
+#define ERS_HLT_FATAL( message ) \
+{ \
+    ERS_REPORT_IMPL( ers::fatal, ers::HLTMessage, message, ); \
+}
+  
+#endif /* TRIG_HLT_ISSUES_H */
diff --git a/HLT/Trigger/TrigControl/TrigServices/TrigServices/TrigIS.h b/HLT/Trigger/TrigControl/TrigServices/TrigServices/TrigIS.h
new file mode 100644
index 00000000000..31ecb9f5e7a
--- /dev/null
+++ b/HLT/Trigger/TrigControl/TrigServices/TrigServices/TrigIS.h
@@ -0,0 +1,79 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef TRIGSERVICES_TRIGIS_H
+#define TRIGSERVICES_TRIGIS_H
+
+/**@class TrigIS
+ * @brief IS publication service
+ *
+ * This service is a simple wrapper around ISInfoDictionary. Mainly to handle
+ * exceptions and to setup the IPC infrastrucure. In addition, it may provide
+ * asynchronous publishing (currently not implemented). By default the ownership
+ * of the ISInfo object remains with the client. Hoever, for asynchronous publishing
+ * this service takes the ownership and deletes the objects after publication.
+ *
+ * @author  Frank Winklmeier
+ * @version $Id: TrigIS.h 5 2013-05-14 10:33:04Z ricab $
+ */
+
+#include "TrigKernel/ITrigIS.h"
+#include "AthenaBaseComps/AthService.h"
+
+#undef PACKAGE_VERSION
+#include "ipc/partition.h"
+#include "is/infodictionary.h"
+
+// Forward declarations
+class IPCPartition;
+class ISInfoDictionary;
+class ISInfo;
+
+template <class TYPE> class SvcFactory;
+
+class TrigIS : virtual public ITrigIS,
+               public AthService {
+
+public:
+  TrigIS(const std::string& name, ISvcLocator* pSvcLocator);
+  virtual ~TrigIS();
+
+  /*
+   * Publish ISInfo object
+   *
+   * Forwards to IsInfoDictionary::checkin and catches exceptions.
+   * Ownership of info remains with caller.
+   */
+  virtual StatusCode publish(const std::string& name, const ISInfo& info, bool keep_history=false);
+  
+  /*
+   * Same as publish but might publish ISInfo object asynchronously.
+   * Ownership of info is transfered to this service.
+   */
+  virtual void publish_async(const std::string& name, ISInfo* info, bool keep_history=false);
+
+  /*
+   * Return reference to ISInfoDictionary
+   */
+  virtual ISInfoDictionary& infoDict() { return m_isDict; }
+  
+  virtual StatusCode queryInterface( const InterfaceID& riid, void** ppvInterface );
+  virtual StatusCode initialize();
+
+protected:
+  friend class SvcFactory<TrigIS>;
+
+  /// default constructor (do not use)
+  TrigIS();
+
+private:
+  IPCPartition        m_partition;
+  ISInfoDictionary    m_isDict;
+  bool                m_validPartition;
+  
+  /* Properties */
+  std::string         m_partitionName;  ///< partition name
+};
+
+#endif
diff --git a/HLT/Trigger/TrigControl/TrigServices/TrigServices/TrigISHelper.h b/HLT/Trigger/TrigControl/TrigServices/TrigServices/TrigISHelper.h
new file mode 100644
index 00000000000..53b82877f07
--- /dev/null
+++ b/HLT/Trigger/TrigControl/TrigServices/TrigServices/TrigISHelper.h
@@ -0,0 +1,211 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef TRIGSERVICES_TRIGISHELPER_H
+#define TRIGSERVICES_TRIGISHELPER_H
+
+/**
+ * @file   TrigISHelper.h
+ * @brief  Helper tool for IS access
+ * @author Frank Winklmeier, Werner Wiedenmann
+ *
+ * $Id: TrigISHelper.h 5 2013-05-14 10:33:04Z ricab $
+ */
+
+// STL includes
+#include <string>
+#include <vector>
+#include <map>
+#include <utility>
+
+// Framework includes
+#include "AthenaBaseComps/AthAlgTool.h"
+#include "GaudiKernel/StatusCode.h"
+
+// To avoid compiler warnings about redefinition through omni includes
+#undef PACKAGE_VERSION
+// TDAQ includes
+#include "is/info.h"
+#include "is/infodictionary.h"
+#include "is/infodynany.h"
+#include "ipc/partition.h"
+
+
+/**
+ * @brief Helper tool for IS access
+ *
+ * This tool wraps some of the IS methods. Mainly to allow for configurable
+ * partition and IS names. Use the properties (e.g. RunParams) to specify
+ * them:
+ *
+ * Example: TrigISHelper.MyISInfo = initial/MyISServer.ISInfoName
+ *
+ * This will read the IS value from partition initial. If no partition is
+ * explicitly specified use the value of the PartitionName property.
+ */
+class TrigISHelper : public AthAlgTool {
+
+public:
+  /// Aliases for IS objects this tool can read
+  enum ISObject {
+    RunParams,
+    LumiBlock,
+    SolenoidCurrent,
+    ToroidCurrent
+  };
+    
+public:
+
+  TrigISHelper(const std::string &type, const std::string &name, const IInterface *parent);    
+  virtual ~TrigISHelper();
+
+  static const InterfaceID& interfaceID();  
+  virtual StatusCode initialize();
+  
+  /**
+   * @brief Wrapper for ISInfoDictionary::findValue
+   *
+   * Main difference to the IS method is that it returns immediatelly
+   * if running without a partition.
+   *
+   * @param name      Name of IS value
+   * @param value     Filled with IS value
+   *
+   * @return SUCCESS  Value retrieved or running without partition
+   *         FAILURE  Could not retrieve value from IS
+   */
+  StatusCode findValue(ISObject obj, ISInfo& value);
+
+  /**
+   * @brief Get attributes of a given type for IS objects
+   *
+   * This method retrieves all attributes of type T from the
+   * given IS object. This can be used in case there is no IS type
+   * definition available.
+   *
+   * @param name      Name of IS value
+   * @param values    Vector to be filled with attributes of type T
+   *                 
+   * @return SUCCESS  Value retrieved or running without partition
+   *         FAILURE  Could not retrieve value from IS
+   */
+  template <class T>
+  StatusCode getAttributes(ISObject obj, std::vector<T>& values);
+
+  /**
+   * @brief Read attribute of an ISNamedInfo object
+   *
+   * T is the type of the ISNamedInfo object, R the value type and
+   * G is a function object that reads the attribute of T.
+   *
+   * @param name      Name of IS value
+   * @param value     Filled with value of attribute
+   * @param getter    Functor of type 'void (const T& t, R& r)' that fills r
+   *                  with the value of an attribute of t.
+   *                 
+   * @return SUCCESS  Value retrieved or running without partition
+   *         FAILURE  Could not retrieve value from IS
+   */
+  template <class T, class R, class G>
+  StatusCode findValue(ISObject obj, R& value, G getter);
+
+  /*
+   * Check if partition for ISObject obj is valid (!= 'none')
+   */
+  bool validPartition(ISObject obj);
+
+  const std::string& partition(ISObject obj) const;
+  const std::string& isName(ISObject obj) const;
+  
+private:
+  // Properties
+  StringProperty                  m_partitionName;    ///< Default partition name
+  bool                            m_ignoreIfMissing;
+  std::map<ISObject, std::string> m_isprop;           ///< Names of IS objects
+
+  /// Property handler
+  void initPartitionName(Property& prop);
+  
+  /// Map ISObject -> (partition, IS name)
+  typedef std::map<ISObject, std::pair<std::string, std::string> > ISObjectMap_t;
+  ISObjectMap_t  m_isid;                      ///< partition and IS name for each ISObject
+ 
+  /// Return (partition, IS) name pair from isid property
+  std::pair<std::string,std::string> split(const std::string& isid); 
+};
+
+
+//--------------------------------------------------------------------------------
+// Inline
+//--------------------------------------------------------------------------------
+inline bool TrigISHelper::validPartition(ISObject obj)
+{
+  const std::string& name = m_isid[obj].first;
+  return (name!="None" && name!="NONE");  
+}
+
+
+inline const InterfaceID& TrigISHelper::interfaceID()
+{
+  static const InterfaceID _IID("TrigISHelper", 1, 0);
+  return _IID;
+}
+
+//--------------------------------------------------------------------------------
+// Templates
+//--------------------------------------------------------------------------------
+template <class T, class R, class G>
+StatusCode TrigISHelper::findValue(ISObject obj, R& value, G getter)
+{
+  const std::string& partName = m_isid[obj].first;
+  const std::string& isName = m_isid[obj].second;
+  
+  try {
+    IPCPartition part(partName);
+    T namedInfo(part, isName);
+    namedInfo.checkout();
+    getter(namedInfo, value);   // set 'value'
+  }
+  catch (daq::is::Exception& e) {
+    msg() << MSG::WARNING << "IS Exception reading " << isName << " from partition "
+          << partName << ". Exception was: " << e.what() << endreq;
+
+    return m_ignoreIfMissing ? StatusCode::SUCCESS : StatusCode::FAILURE;
+  }
+
+  if ( msgLvl(MSG::DEBUG) ) {
+    msg() << MSG::DEBUG << "Successfully read " << isName << " from IS: " << value << endreq;
+  }
+  return StatusCode::SUCCESS;
+}
+
+
+template <class T>
+StatusCode TrigISHelper::getAttributes(ISObject obj, std::vector<T>& values)
+{
+  const std::string& partName = m_isid[obj].first;
+  const std::string& isName = m_isid[obj].second;
+
+  ISInfoDynAny ida;
+  try {
+    IPCPartition part(partName);
+    ISInfoDictionary isInfoDict(part);
+    isInfoDict.findValue(isName, ida);
+  }
+  catch (daq::is::Exception e) {
+    msg() << MSG::WARNING << "IS Exception reading " << isName << " from partition "
+          << partName << ". Exception was: " << e.what() << endreq;
+
+    return m_ignoreIfMissing ? StatusCode::SUCCESS : StatusCode::FAILURE;
+  }
+  
+  for (size_t i=0; i<ida.getAttributesNumber(); ++i) {
+    if ( is::type2id<T>::id == ida.getAttributeType(i) ) {
+      values.push_back(ida.getAttributeValue<T>(i));
+    }
+  }
+  return StatusCode::SUCCESS;
+}
+
+#endif
diff --git a/HLT/Trigger/TrigControl/TrigServices/TrigServices/TrigMessageSvc.h b/HLT/Trigger/TrigControl/TrigServices/TrigServices/TrigMessageSvc.h
new file mode 100644
index 00000000000..8666170d971
--- /dev/null
+++ b/HLT/Trigger/TrigControl/TrigServices/TrigServices/TrigMessageSvc.h
@@ -0,0 +1,226 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+/**
+ * @file TrigMessageSvc.h
+ *
+ * $Id: TrigMessageSvc.h 5 2013-05-14 10:33:04Z ricab $
+ */
+#ifndef TRIGSERVICES_TRIGMESSAGESVC_H
+#define TRIGSERVICES_TRIGMESSAGESVC_H
+
+// Include files
+#include <string>
+#include <vector>
+#include <map>
+
+#include "GaudiKernel/StatusCode.h"
+#include "GaudiKernel/Service.h"
+#include "GaudiKernel/ServiceHandle.h"
+#include "GaudiKernel/IMessageSvc.h"
+#include "GaudiKernel/IIncidentListener.h"
+#include "GaudiKernel/Message.h"
+#include "GaudiKernel/Property.h"
+
+#include "StoreGate/StoreGateSvc.h"
+
+#include "TrigKernel/ITrigMessageSvc.h"
+
+// Forward declarations
+class ISvcLocator;
+class TH1I;
+class TH2I;
+
+/**@class TrigMessageSvc
+ * @brief MessageSvc used by the HLT applications
+ *
+ * This MessageSvc implementation it used by the HLT applications. It has some additional
+ * features compared to the default Gaudi MessageSvc. Most notably the forwarding of messages
+ * to the TDAQ ERS message system.
+ *
+ * The message suppression is configured with the following parameters:
+ * @param <level>Limit = 0:       no message suppression for <level>
+ * @param <level>Limit = N > 0:   suppress messages after N messages (per source)
+ * @param <level>Limit = -N < 0:  use logarithmic suppression after N messages (per message)
+ *
+ * Note, that the logarithmic suppression works on a per-message basis (ignoring any digits
+ * in the message).
+ *
+ * @author    Iain Last, Werner Wiedenmann, Frank Winklmeier
+ */
+
+class TrigMessageSvc : public Service,
+                       virtual public IMessageSvc,
+                       virtual public ITrigMessageSvc,
+                       virtual public IIncidentListener {
+public:  
+  typedef std::pair< std::string, std::ostream* > NamedStream;
+  typedef std::multimap< int, NamedStream > StreamMap;
+  typedef std::multimap< StatusCode, Message > MessageMap;
+  typedef std::map< std::string, int > ThresholdMap;
+  
+  // Default constructor.
+  TrigMessageSvc( const std::string& name, ISvcLocator* svcloc );
+  // Destructor.
+  virtual ~TrigMessageSvc();
+
+  // Implementation of IService::reinitialize()
+  virtual StatusCode reinitialize();
+  // Implementation of IService::initialize()
+  virtual StatusCode initialize();
+  // Implementation of IService::finalize()
+  virtual StatusCode finalize();
+
+  // Implementation of IMessageSvc::reportMessage()
+  virtual void reportMessage( const Message& message );
+
+  // Implementation of IMessageSvc::reportMessage()
+  virtual void reportMessage( const Message& message, int outputLevel );
+
+  // Implementation of IMessageSvc::reportMessage()
+  virtual void reportMessage( const StatusCode& code, const std::string& source = "");
+
+  // Implementation of IMessageSvc::reportMessage()
+  virtual void reportMessage( const char* source, int type, const char* message);
+
+  // Implementation of IMessageSvc::reportMessage()
+  virtual void reportMessage( const std::string& source, int type, const std::string& message);
+  
+  // Implementation of IMessageSvc::insertMessage()
+  virtual void insertMessage( const StatusCode& code, const Message& message );
+
+  // Implementation of IMessageSvc::eraseMessage()
+  virtual void eraseMessage();
+
+  // Implementation of IMessageSvc::eraseMessage()
+  virtual void eraseMessage( const StatusCode& code ) ;
+
+  // Implementation of IMessageSvc::eraseMessage()
+  virtual void eraseMessage( const StatusCode& code, const Message& message );
+
+  // Implementation of IMessageSvc::insertStream()
+  virtual void insertStream( int message_type, const std::string& name, std::ostream* stream );
+  
+  // Implementation of IMessageSvc::eraseStream()
+  virtual void eraseStream();
+  
+  // Implementation of IMessageSvc::eraseStream()
+  virtual void eraseStream( int message_type );
+  
+  // Implementation of IMessageSvc::eraseStream()
+  virtual void eraseStream( int message_type, std::ostream* stream );
+
+  // Implementation of IMessageSvc::eraseStream()
+  virtual void eraseStream( std::ostream* stream );
+
+  // Implementation of IMessageSvc::desaultStream()
+  virtual std::ostream* defaultStream() const { 
+    return m_defaultStream; 
+  }
+
+  // Implementation of IMessageSvc::setDefaultStream()
+  virtual void setDefaultStream( std::ostream* stream ) { 
+    m_defaultStream = stream;
+  }
+
+  // Implementation of IMessageSvc::ouputLevel()
+  virtual int outputLevel()   const;
+
+  // Implementation of IMessageSvc::ouputLevel()
+  virtual int outputLevel(const std::string& source)   const;
+
+  // Implementation of IMessageSvc::setOuputLevel()
+  virtual void setOutputLevel(int new_level);
+
+  // Implementation of IMessageSvc::setOuputLevel()
+  virtual void setOutputLevel(const std::string& source, int new_level);
+
+  // Implementation of IInterface::queryInterface()
+  virtual StatusCode queryInterface(const InterfaceID& riid, void** ppvUnknown);
+
+  // Implementation of IMessageSvc::useColor()
+  virtual bool useColor() const { return m_color; }
+
+  // Implementation of IMessageSvc::getLogColor()
+  virtual std::string getLogColor(int logLevel) const;
+
+  // Implementation of IMessageSvc::messageCount()
+  virtual int messageCount( MSG::Level logLevel ) const;
+ 
+  /// \name ITrigMessageSvc implementation
+  //@{
+  /// Reset all individual output levels
+  virtual void resetOutputLevels();
+  //@}
+
+  // Implemenation of IIncidentListener::handle()
+  virtual void handle(const Incident& inc);
+
+private:
+  typedef std::map<std::string, MSG::Color> ColorMap;
+  typedef std::map< unsigned int, unsigned int > MsgCountMap;
+  
+  std::ostream* m_defaultStream;      ///< Pointer to the output stream.
+  Message m_defaultMessage;           ///< Default Message
+  StreamMap m_streamMap;              ///< Stream map
+  MessageMap m_messageMap;            ///< Message map
+  ThresholdMap m_thresholdMap;        ///< Output level threshold map
+  std::string m_defaultFormat;        ///< Default format for the messages
+  std::string m_defaultTimeFormat;    ///< Default time format for the messages
+  int m_defaultLimit;                 ///< Original default message limit
+  bool m_doSuppress;                  ///< Message suppression currently active?
+  bool m_running;                     ///< In RUNNING state
+  bool m_canEnter;                    ///< used to avoid infinite recursions
+  
+  ServiceHandle<StoreGateSvc> m_evtStore;   ///< Event store
+  
+  /* Properties */
+  StringArrayProperty m_thresholdProp[MSG::NUM_LEVELS];
+  StringArrayProperty m_logColors[MSG::NUM_LEVELS];
+  UnsignedIntegerProperty m_statLevel;
+  UnsignedIntegerProperty m_statLevelRun;
+  UnsignedIntegerProperty m_publishLevel;
+  UnsignedIntegerProperty m_eventIDLevel;
+  IntegerProperty m_msgLimit[MSG::NUM_LEVELS];
+  BooleanProperty m_color;
+  BooleanProperty m_stats;
+  BooleanProperty m_publishStats;
+  BooleanProperty m_resetStats;
+  StringArrayProperty m_useERS[MSG::NUM_LEVELS];
+  BooleanProperty m_alwaysUseMsgStream;
+  BooleanProperty m_useErsRunningOnly;  
+  BooleanProperty m_suppress;
+  BooleanProperty m_suppressRunningOnly;
+  BooleanProperty m_forceOutputLevel;
+  
+  /* Message colors */
+  std::string m_logColorCodes[MSG::NUM_LEVELS];
+  std::string colTrans(std::string, int);
+  ColorMap m_colMap;
+
+  /* Message counting */
+  struct msgAry { int msg[MSG::NUM_LEVELS]; };
+  std::map<std::string, msgAry> m_sourceMap;      ///< Current message counting per source
+  std::map<std::string, msgAry> m_sourceMapTotal; ///< Total message counting per source
+  int m_msgCount[MSG::NUM_LEVELS];                ///< Message counting per level
+  MsgCountMap m_msgCountMap;                      ///< Message counting per message
+  TH1I* m_msgCountHist;                           ///< Message counting per level histogram
+  TH2I* m_msgCountSrcHist;                        ///< Message counting per message source
+
+  /* Update handlers */
+  void initColors(Property& prop);
+  void setupColors(Property& prop);
+  void setupLimits(Property& prop);
+  void setupThreshold(Property& prop);
+  void setupSuppression(Property& prop);
+  
+  unsigned int msgHash(const Message& msg);   ///< Hash of message (for log. suppression)
+  void resetMsgStats();                       ///< Reset message statistics
+  void reportMsgStats(uint statLevel, bool total=false);        ///< Report message statistics
+  void setOutputLevelViaJobOptSvc();          ///< Change OutputLevel properties in JobOptionsSvc
+  void bookHistograms();                      ///< Book histograms for message statistics
+  bool passErsFilter(const std::string& source, const std::vector<std::string>& filter);  ///< Source passes ERS filter?
+};
+
+#endif
diff --git a/HLT/Trigger/TrigControl/TrigServices/cmt/requirements b/HLT/Trigger/TrigControl/TrigServices/cmt/requirements
new file mode 100755
index 00000000000..48161de2595
--- /dev/null
+++ b/HLT/Trigger/TrigControl/TrigServices/cmt/requirements
@@ -0,0 +1,49 @@
+package TrigServices
+
+author W. Wiedenmann     <Werner.Wiedenmann@cern.ch>
+author Frank Winklmeier  <Frank.Winklmeier@cern.ch>
+author Ricardo Abreu     <Ricardo.Abreu@cern.ch>
+
+use AtlasPolicy           AtlasPolicy-*
+use GaudiInterface        GaudiInterface-*         External
+use AthenaKernel          AthenaKernel-*           Control
+use StoreGate             StoreGate-*              Control
+use TrigKernel            TrigKernel-*             HLT/Trigger/TrigControl
+use EventInfo             EventInfo-*              Event
+use xAODEventInfo         xAODEventInfo-*          Event/xAOD
+use AthenaBaseComps       AthenaBaseComps-*        Control
+use TrigSteeringEvent     TrigSteeringEvent-*      Trigger/TrigEvent
+use TrigDataAccessMonitoring  TrigDataAccessMonitoring-*  Trigger/TrigDataAccess
+use TrigROBDataProviderSvc    TrigROBDataProviderSvc-*    Trigger/TrigDataAccess
+use ByteStreamCnvSvcBase  ByteStreamCnvSvcBase-*   Event
+use ByteStreamData        ByteStreamData-*         Event
+use DataCollection        DataCollection-*         External
+use HLTtdaq               HLTtdaq-*                HLT/HLTExternal
+use HLTtdaqcommon         HLTtdaqcommon-*          HLT/HLTExternal
+
+private
+use AtlasBoost            AtlasBoost-*             External
+use AtlasROOT             AtlasROOT-*              External
+use AtlasCORAL            AtlasCORAL-*             External
+use AthenaPoolUtilities   AthenaPoolUtilities-*    Database/AthenaPOOL
+use TrigInterfaces        TrigInterfaces-*         Trigger/TrigSteer
+use TrigConfInterfaces    TrigConfInterfaces-*     Trigger/TrigConfiguration
+use TrigMonitorBase       TrigMonitorBase-*        Trigger/TrigMonitoring
+use TrigNavigation        TrigNavigation-*         Trigger/TrigEvent
+use CLIDSvc               CLIDSvc-*                Control
+use CTPfragment           *
+end_private
+
+apply_pattern dual_use_library files="*.cxx"
+
+apply_pattern declare_joboptions files="*.py"
+
+apply_pattern declare_python_modules files="*.py"
+
+#--- leave this as public
+macro_append TrigServices_linkopts \
+             " $(HLTtdaq_linkopts) -lers -leformat -leformat_write "
+
+private
+macro_append TrigServices_linkopts " $(Boost_linkopts) $(Boost_linkopts_regex) "
+macro_append TrigServices_linkopts " $(HLTtdaq_linkopts) -lhltinterface -lCTPfragment -lomniORB4 -lomnithread -lipc -lis -lowl "
diff --git a/HLT/Trigger/TrigControl/TrigServices/python/HltTHistSvcConfig.py b/HLT/Trigger/TrigControl/TrigServices/python/HltTHistSvcConfig.py
new file mode 100644
index 00000000000..f2568e66d00
--- /dev/null
+++ b/HLT/Trigger/TrigControl/TrigServices/python/HltTHistSvcConfig.py
@@ -0,0 +1,28 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+from TrigServicesConf import HltTHistSvc
+
+# just a helper function
+# def defineTHistSvcOutputFile(dir, name, service, opt='NEW'):
+#     if globals().has_key('numberOfThreads'):
+#         threads = globals()['numberOfThreads']
+#     else:
+#         threads=0
+        
+#     if threads.value() == 0:
+#         THistSvc = Service(service)
+#         THistSvc.Output += [dir+" DATAFILE=\'"+name+"' OPT=\'"+opt+"\'" ]
+#         return
+#     for n in range(0,threads.value()):
+#         threadID = '__%(#)d' % { '#': n}
+#         THistSvc = Service ( service+threadID )
+#         THistSvc.Output += [dir+" DATAFILE=\'"+name+threadID+"' OPT=\'"+opt+"\'" ]
+
+
+class HltTHistSvcConfig(HltTHistSvc):
+    def __init__(self, name='THistSvc'):
+        super(HltTHistSvcConfig, self).__init__(name)
+        self.Output += ["SHIFT   DATAFILE='shift-monitoring.root'   OPT='RECREATE'"]
+        self.Output += ["EXPERT  DATAFILE='expert-monitoring.root'  OPT='RECREATE'"]
+        self.Output += ["DEBUG   DATAFILE='debug-monitoring.root'   OPT='RECREATE'"]
+        self.Output += ["RUNSTAT DATAFILE='runstat-monitoring.root' OPT='RECREATE'"]        
diff --git a/HLT/Trigger/TrigControl/TrigServices/python/TrigServicesConfig.py b/HLT/Trigger/TrigControl/TrigServices/python/TrigServicesConfig.py
new file mode 100644
index 00000000000..0e3b4824c04
--- /dev/null
+++ b/HLT/Trigger/TrigControl/TrigServices/python/TrigServicesConfig.py
@@ -0,0 +1,27 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+# @file: TrigServicesConfig.py
+# @purpose: customized configurables
+
+from TrigServicesConf import TrigCOOLUpdateHelper as _TrigCOOLUpdateHelper
+      
+class TrigCOOLUpdateHelper(_TrigCOOLUpdateHelper):
+   __slots__ = ()
+
+   def __init__(self, name='TrigCOOLUpdateHelper'):
+      super(TrigCOOLUpdateHelper, self).__init__(name)
+      return
+
+   def enable(self, folder='/TRIGGER/HLT/COOLUPDATE', tag=None):
+      """Enable the COOL folder updates (only use this for data)"""
+      
+      from AthenaCommon.AppMgr import ServiceMgr as svcMgr
+      if not hasattr(svcMgr,'IOVDbSvc'): return
+      
+      self.coolFolder = folder
+      from IOVDbSvc.CondDB import conddb
+      if tag==None:
+         conddb.addFolder('TRIGGER',self.coolFolder)
+      else:
+         conddb.addFolderWithTag('TRIGGER',self.coolFolder,tag)
+      
diff --git a/HLT/Trigger/TrigControl/TrigServices/python/TriggerUnixStandardSetup.py b/HLT/Trigger/TrigControl/TrigServices/python/TriggerUnixStandardSetup.py
new file mode 100644
index 00000000000..0b3d8e892d0
--- /dev/null
+++ b/HLT/Trigger/TrigControl/TrigServices/python/TriggerUnixStandardSetup.py
@@ -0,0 +1,243 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+## @file TriggerUnixStandardSetup.py
+## @brief py-module to configure the Athena AppMgr for trigger
+## @author Werner Wiedenmann <Werner.Wiedenmann@cern.ch>
+###############################################################
+
+class _Conf:
+    """Some configuration flags for this module with defaults"""
+    useOnlineTHistSvc = True    # set via TrigServices/OfflineTHistSvc.py
+    athenaXT = False            # set below in _setupCommonServices
+
+
+def _setupRoot6IfNeeded():
+    import cppyy
+    try:
+        # try to touch ROOT5-only attribute (success means we have ROOT5)
+        cppyy.Cintex.Debug
+    except AttributeError:
+        # ROOT 6
+        from PyUtils.Helpers import ROOT6Setup
+        ROOT6Setup()
+
+def _eventLoopMgr(svcMgr):
+    if hasattr(svcMgr, 'HltEventLoopMgr'): return svcMgr.HltEventLoopMgr
+    return None
+    
+def _setupCommonServices():
+    from AthenaCommon.Constants import VERBOSE, DEBUG, INFO, ERROR
+    
+    # Add timestamp to python logger
+    from AthenaCommon.Logging import log
+    log.setFormat("%(asctime)s  Py:%(name)-31s %(levelname)7s %(message)s")
+
+    from AthenaCommon.Logging import logging
+    log = logging.getLogger( 'TriggerUnixStandardSetup::setupCommonServices:' )
+     
+    # Do the default Atlas job configuration first
+    import AthenaCommon.AtlasUnixStandardJob
+
+    # Now do HLT specific configuration
+    from AthenaCommon import CfgMgr
+    from AthenaCommon.AppMgr import theApp
+    from AthenaCommon.AppMgr import ServiceMgr as svcMgr
+    from AthenaCommon.AppMgr import ToolSvc
+
+    # Check whether we are running in athenaXT
+    # Only a minimal set of properties should depend on this
+    import sys
+    if sys.modules.has_key('HLTTestApps'):
+        _Conf.athenaXT = True
+        log.debug("Configuration for athenaXT running")
+    else:
+        _Conf.athenaXT = False
+        log.debug("Configuration for online running")
+        
+    # setup ROOT6 if needed
+    _setupRoot6IfNeeded()
+
+    # StoreGateSvc
+    svcMgr.StoreGateSvc.ActivateHistory = False
+    
+    # ProxyProviderSvc services configuration
+    svcMgr += CfgMgr.ProxyProviderSvc()
+
+    # --- ByteStreamAddressProviderSvc configuration
+    svcMgr += CfgMgr.ByteStreamAddressProviderSvc()
+    svcMgr.ProxyProviderSvc.ProviderNames += [ "ByteStreamAddressProviderSvc" ]
+    theApp.CreateSvc += [ svcMgr.ByteStreamAddressProviderSvc.getFullName() ]
+
+    # Initialization of DetDescrCnvSvc
+    svcMgr += CfgMgr.DetDescrCnvSvc(
+        # specify primary Identifier dictionary to be used
+        IdDictName = "IdDictParser/ATLAS_IDS.xml"
+        )
+    theApp.CreateSvc += [ svcMgr.DetDescrCnvSvc.getFullName() ]
+    svcMgr.EventPersistencySvc.CnvServices += [ "DetDescrCnvSvc" ]
+
+    # --- ByteStreamCnvSvc configuration
+    svcMgr += CfgMgr.ByteStreamCnvSvc("ByteStreamCnvSvc")
+    svcMgr.EventPersistencySvc.CnvServices += [ "ByteStreamCnvSvc" ]
+    
+    # Disable history
+    svcMgr += CfgMgr.HistorySvc()
+    svcMgr.HistorySvc.Activate = False
+
+    # Configuration of Interval of Validity Service
+    svcMgr += CfgMgr.IOVSvc()
+    
+    # Configure TrigISHelper
+    from TrigServices.TrigServicesConf import TrigISHelper
+    ToolSvc += TrigISHelper("TrigISHelper")
+
+    # Configure TrigPreFlightCheck
+    from TrigServices.TrigServicesConf import TrigPreFlightCheck
+    ToolSvc += TrigPreFlightCheck("TrigPreFlightCheck",
+                                  ReleaseDirs = ["AtlasP1HLT","AtlasHLT"]
+                                  )
+
+    # Configure CoreDumpSvc
+    if not hasattr(svcMgr,"CoreDumpSvc"):
+        from AthenaServices.Configurables import CoreDumpSvc
+        svcMgr += CoreDumpSvc()
+        
+    # Configure COOL update helper tool
+    from TrigServices.TrigServicesConfig import TrigCOOLUpdateHelper
+    _eventLoopMgr(svcMgr).CoolUpdateTool = TrigCOOLUpdateHelper()
+            
+    # Setup online THistSvc unless specifically configured otherwise
+    if _Conf.useOnlineTHistSvc:
+        if hasattr(svcMgr, 'THistSvc'):
+            log.fatal("The offline histogramming THistSvc is already in place.")
+            raise RuntimeError("Cannot setup online histogramming TrigMonTHistSvc")
+        log.debug("Using online histogramming service (TrigMonTHistSvc)")
+        from TrigServices.TrigServicesConf import TrigMonTHistSvc
+        svcMgr += TrigMonTHistSvc("THistSvc")
+    else:
+        log.debug("Using offline histogramming service (THistSvc)")
+        from GaudiSvc.GaudiSvcConf import THistSvc
+        svcMgr += THistSvc()
+
+    # Explicitly set a few OutputLevels (needed because some services are created in
+    # different order when running with the PSC)
+    svcMgr.StatusCodeSvc.OutputLevel = theApp.OutputLevel
+    svcMgr.IncidentSvc.OutputLevel = theApp.OutputLevel
+    svcMgr.ProxyProviderSvc.OutputLevel = theApp.OutputLevel
+    svcMgr.StoreGateSvc.OutputLevel = theApp.OutputLevel
+    
+    return
+
+
+def _setupCommonServicesEnd():
+    from AthenaCommon.AppMgr import theApp
+    from AthenaCommon.AppMgr import ServiceMgr as svcMgr    
+    from AthenaCommon.Logging import logging
+    from TriggerJobOpts.TriggerFlags import TriggerFlags
+    
+    log = logging.getLogger( 'TriggerUnixStandardSetup::setupCommonServicesEnd:' )
+    
+    # --- create the ByteStreamCnvSvc after the Detector Description otherwise
+    # --- the initialization of converters fails
+    theApp.CreateSvc += [ svcMgr.ByteStreamCnvSvc.getFullName() ]    
+
+    # Make sure no THistSvc output/input stream is defined for online running
+    if _Conf.useOnlineTHistSvc:
+        svcMgr.THistSvc.Output = []
+        if len(svcMgr.THistSvc.Input)>0:
+            log.error('THistSvc.Input = %s. Input not allowed for online running. Disabling input.' % svcMgr.THistSvc.Input)
+            svcMgr.THistSvc.Input = []
+
+    # For offline running make sure at least the EXPERT stream is defined
+    else:
+        if 1 not in [ o.count('EXPERT') for o in svcMgr.THistSvc.Output ]:
+            svcMgr.THistSvc.Output += ["EXPERT DATAFILE='expert-monitoring.root' OPT='RECREATE'"]
+
+
+    # Set default properties for some important services after all user job options
+    log.info('Configure core services for online runnig')
+
+    svcMgr.CoreDumpSvc.CoreDumpStream = "stdout"
+    svcMgr.CoreDumpSvc.CallOldHandler = True
+    svcMgr.CoreDumpSvc.FatalHandler = 0   # no extra fatal handler
+    svcMgr.CoreDumpSvc.TimeOut = 0        # no timeout for stack trace generation
+
+    # Disable StatusCodeSvc (causes problems with shutting down children at stop in HLTPU)
+    svcMgr.StatusCodeSvc.SuppressCheck = True
+    svcMgr.StatusCodeSvc.AbortOnError = False
+        
+    svcMgr.IOVSvc.updateInterval = "RUN"
+    svcMgr.IOVSvc.preLoadData = True  
+    svcMgr.IOVSvc.forceResetAtBeginRun = False 
+
+    if hasattr(svcMgr,'IOVDbSvc'):
+        svcMgr.IOVDbSvc.CacheAlign = 0  # VERY IMPORTANT to get unique queries for folder udpates (see Savannah #81092)
+        svcMgr.IOVDbSvc.CacheRun = 0
+        svcMgr.IOVDbSvc.CacheTime = 0
+        
+    # Flag to extract trigger configuration
+    if TriggerFlags.Online.doDBConfig():
+        from TrigConfigSvc import DoDBConfig
+        
+    # --- print out configuration details
+    _printConfiguration(log.name)
+    
+    return 
+    
+def _printConfiguration(loggerName):
+    from AthenaCommon.Constants import VERBOSE, DEBUG, INFO, ERROR
+
+    from AthenaCommon.Logging import logging
+    if loggerName == '':
+        loggerName = 'TriggerUnixStandardSetup::_printConfiguration'
+        
+    log = logging.getLogger( loggerName )
+    
+    # --- print out configuration details
+    # ---
+    from AthenaCommon.AppMgr import theApp
+    log.debug("---> Application Manager")
+    log.debug(theApp)
+    
+    from AthenaCommon.AppMgr import ServiceMgr as svcMgr
+    log.debug("---> Service Manager")
+    log.debug(svcMgr)
+
+    from AthenaCommon.AlgSequence import AlgSequence
+    topSequence = AlgSequence()
+    log.debug("---> Algorithm Sequence")
+    log.debug(topSequence)
+    
+    return
+
+def setupHLTServicesBegin():
+    from AthenaCommon import CfgMgr
+    from AthenaCommon.Constants import VERBOSE, DEBUG, INFO, ERROR
+    from AthenaCommon.AppMgr import theApp
+    from AthenaCommon.AppMgr import ServiceMgr as svcMgr
+    from AthenaCommon.Logging import logging
+    log = logging.getLogger( 'TriggerUnixStandardSetup::setupHLTServicesBegin:' )
+    log.debug( "---> Start" )
+
+    # --- setup the standard services
+    _setupCommonServices()   
+
+    # --- Hlt ROBDataProvider configuration
+    svcMgr += CfgMgr.HltROBDataProviderSvc("ROBDataProviderSvc")
+    theApp.CreateSvc += [ svcMgr.ROBDataProviderSvc.getFullName() ]
+
+    log.debug( "---> End" )
+    return
+
+def setupHLTServicesEnd():
+    from AthenaCommon.Constants import VERBOSE, DEBUG, INFO, ERROR
+
+    from AthenaCommon.Logging import logging
+    log = logging.getLogger( 'TriggerUnixStandardSetup::setupHLTServicesEnd:' )
+    log.debug( "---> Start" )
+
+    # --- final modifications to standard services
+    _setupCommonServicesEnd()      
+
+    log.debug( "---> End" )
+    return
diff --git a/HLT/Trigger/TrigControl/TrigServices/python/__init__.py b/HLT/Trigger/TrigControl/TrigServices/python/__init__.py
new file mode 100644
index 00000000000..96403d7b4bb
--- /dev/null
+++ b/HLT/Trigger/TrigControl/TrigServices/python/__init__.py
@@ -0,0 +1,6 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+# File: TrigServices/__init__.py
+
+__version__ = '1.0.0'
+__author__  = 'Werner.Wiedenmann@cern.ch'
diff --git a/HLT/Trigger/TrigControl/TrigServices/share/MessageSvc.py b/HLT/Trigger/TrigControl/TrigServices/share/MessageSvc.py
new file mode 100644
index 00000000000..cde14a414ff
--- /dev/null
+++ b/HLT/Trigger/TrigControl/TrigServices/share/MessageSvc.py
@@ -0,0 +1,79 @@
+#**************************************************************
+#
+#  MessageSvc configuration file
+#
+#==============================================================
+from AthenaCommon.AppMgr import theApp
+from AthenaCommon.AppMgr import ServiceMgr as svcMgr
+from AthenaCommon.Constants import *
+
+# make the message service available
+svcMgr.MessageSvc = theApp.service( "MessageSvc" )     # already instantiated
+MessageSvc = svcMgr.MessageSvc
+
+MessageSvc.OutputLevel  = OutputLevel
+
+# Use color for different message levels
+# --------------------------------------
+MessageSvc.useColors    = False
+
+# Format string for all messages
+# ------------------------------
+MessageSvc.Format       = "%t  % F%35W%S%7W%R%T %0W%M"
+
+# Message suppression
+# -------------------
+MessageSvc.enableSuppression    = False
+MessageSvc.suppressRunningOnly  = True
+MessageSvc.resetStatsAtBeginRun = True
+
+# 0 = no suppression, negative = log-suppression, positive = normal suppression
+# Do not rely on the defaultLimit property, always set each limit separately
+MessageSvc.defaultLimit = -100
+MessageSvc.verboseLimit = MessageSvc.defaultLimit
+MessageSvc.debugLimit   = MessageSvc.defaultLimit
+MessageSvc.infoLimit    = MessageSvc.defaultLimit
+MessageSvc.warningLimit = MessageSvc.defaultLimit
+MessageSvc.errorLimit   = 0
+MessageSvc.fatalLimit   = 0
+
+# set message limit to unlimited when general DEBUG is requested
+if (("OutputLevel" in dir()) and (OutputLevel<=DEBUG)) :
+    MessageSvc.defaultLimit = 0
+    MessageSvc.enableSuppression = False
+if (("HLTOutputLevel" in dir()) and (HLTOutputLevel<=DEBUG)) :
+    MessageSvc.defaultLimit = 0
+    MessageSvc.enableSuppression = False
+
+# show summary statistics of messages in finalize
+# -----------------------------------------------
+MessageSvc.showStats = True
+MessageSvc.statLevel = WARNING
+MessageSvc.statLevelRun = VERBOSE
+
+# publish message counts during RUNNING in histogram
+# --------------------------------------------------
+MessageSvc.publishStats = True
+MessageSvc.publishLevel = INFO
+
+
+# report messages via ERS
+# -----------------------
+# report given message severities via ERS
+# MessageSvc.useErsVerbose = ['*']
+# MessageSvc.useErsDebug = ['*']
+# MessageSvc.useErsInfo = ['*']
+# MessageSvc.useErsWarning = ['*']
+# MessageSvc.useErsError = ['*']
+# MessageSvc.useErsFatal = ['*']
+
+# Set to True, if ERS messages should be duplicated to the MsgStream
+# MessageSvc.alwaysUseMsgStream = True
+# Only forward message during RUNNING
+# MessageSvc.useErsRunningOnly = True
+
+#==============================================================
+#
+# End of MessageSvc configuration file
+#
+#**************************************************************
diff --git a/HLT/Trigger/TrigControl/TrigServices/share/OfflineTHistSvc.py b/HLT/Trigger/TrigControl/TrigServices/share/OfflineTHistSvc.py
new file mode 100644
index 00000000000..51d2d0913bc
--- /dev/null
+++ b/HLT/Trigger/TrigControl/TrigServices/share/OfflineTHistSvc.py
@@ -0,0 +1,17 @@
+## @file   OfflineTHistSvc.py
+## @brief  Configure the offline THistSvc
+## @author Frank Winklmeier <fwinkl@cern>
+##
+## This fragment will be included by atheanMT/PT if we are
+## running withtout the OH monitoring. Otherwise, the default
+## is to use the online histogramming service (TrigMonTHistSvc)
+###################################################################
+
+from TrigServices.TriggerUnixStandardSetup import _Conf
+_Conf.useOnlineTHistSvc = False
+del _Conf
+
+## Couple validation flag (i.e. time stamps in messages) to "-M" option
+from TriggerJobOpts.TriggerFlags import TriggerFlags
+TriggerFlags.Online.doValidation = True
+del TriggerFlags
diff --git a/HLT/Trigger/TrigControl/TrigServices/share/TrigServicesBootstrap.py b/HLT/Trigger/TrigControl/TrigServices/share/TrigServicesBootstrap.py
new file mode 100644
index 00000000000..3bf4063c5b7
--- /dev/null
+++ b/HLT/Trigger/TrigControl/TrigServices/share/TrigServicesBootstrap.py
@@ -0,0 +1,29 @@
+#**************************************************************
+#
+# HLT bootstrap options file
+#
+#==============================================================
+
+#--------------------------------------------------------------
+# HLT specific event loop and output stream
+#--------------------------------------------------------------
+theApp.EventLoop         = "HltEventLoopMgr"
+#theApp.OutStreamType     = "AthenaOutputStream"
+
+#--------------------------------------------------------------
+# in Hlt the EventLoop is controlled by the HLT Processing Unit
+# so the default is no Event Selector
+#--------------------------------------------------------------
+theApp.EvtSel            = "NONE"
+
+#--------------------------------------------------------------
+# take care of job options legacy
+#--------------------------------------------------------------
+theApp.JobOptionsPath    = ""
+theApp.JobOptionsType    = "NONE"
+
+#==============================================================
+#
+# End of HLT bootstrap options file
+#
+#**************************************************************
diff --git a/HLT/Trigger/TrigControl/TrigServices/share/TrigServicesCommonBegin.py b/HLT/Trigger/TrigControl/TrigServices/share/TrigServicesCommonBegin.py
new file mode 100644
index 00000000000..ab547b95b65
--- /dev/null
+++ b/HLT/Trigger/TrigControl/TrigServices/share/TrigServicesCommonBegin.py
@@ -0,0 +1,20 @@
+#**************************************************************
+#
+# HLT common configuration file: TrigServicesCommonBegin.py
+#
+#==============================================================
+
+include( "TrigServices/MessageSvc.py" )
+include( "TrigServices/TrigServicesEventLoopMgr.py" )
+
+## HLT standard service configuration
+from TrigServices.TriggerUnixStandardSetup import setupHLTServicesBegin
+setupHLTServicesBegin()
+## clean-up: avoid running multiple times this method
+del setupHLTServicesBegin
+
+#==============================================================
+#
+# End of HLT common configuration file: TrigServicesCommonBegin.py
+#
+#**************************************************************
diff --git a/HLT/Trigger/TrigControl/TrigServices/share/TrigServicesCommonEnd.py b/HLT/Trigger/TrigControl/TrigServices/share/TrigServicesCommonEnd.py
new file mode 100644
index 00000000000..dc98afa1a7a
--- /dev/null
+++ b/HLT/Trigger/TrigControl/TrigServices/share/TrigServicesCommonEnd.py
@@ -0,0 +1,19 @@
+#**************************************************************
+#
+# HLT common configuration file: TrigServicesCommonEnd.py
+#
+#==============================================================
+
+## get a handle on the ServiceMgr
+from AthenaCommon.AppMgr import ServiceMgr as svcMgr
+
+## HLT standard service configuration 
+from TrigServices.TriggerUnixStandardSetup import setupHLTServicesEnd
+setupHLTServicesEnd()
+## clean-up: avoid running multiple times this method
+del setupHLTServicesEnd
+#==============================================================
+#
+# End of HLT common configuration file: TrigServicesCommonEnd.py
+#
+#**************************************************************
diff --git a/HLT/Trigger/TrigControl/TrigServices/share/TrigServicesEventLoopMgr.py b/HLT/Trigger/TrigControl/TrigServices/share/TrigServicesEventLoopMgr.py
new file mode 100644
index 00000000000..9eaddbeae6b
--- /dev/null
+++ b/HLT/Trigger/TrigControl/TrigServices/share/TrigServicesEventLoopMgr.py
@@ -0,0 +1,76 @@
+#**************************************************************
+#
+# TrigServicesEventLoopMgr configuration file
+#
+#==============================================================
+from AthenaCommon.AppMgr import theApp
+from AthenaCommon.AppMgr import ServiceMgr as svcMgr
+from AthenaCommon.Constants import *
+
+# make the HltEventLoopMgr service available
+svcMgr.HltEventLoopMgr = theApp.service( "HltEventLoopMgr" )     # already instantiated
+HltEventLoopMgr = svcMgr.HltEventLoopMgr
+
+# configure here Level-1 CTP ROB identifier which is used in HLT
+HltEventLoopMgr.Lvl1CTPROBid = 0x770001
+
+# request that events with invalid or missing CTP ROBs are skipped by the HltEventLoopMgr
+# (default: don't skip these events)
+HltEventLoopMgr.Lvl1CTPROBcheck = TRUE
+
+#
+# name of the HLT Result object in StoreGate
+#
+HltEventLoopMgr.HltResultName = "HLTResult_HLT"
+
+#
+# handling of truncated HLT Results
+#
+# switch on saving of events with truncated HLT results to DEBUG stream (default FALSE)
+#HltEventLoopMgr.WriteTruncatedHLTtoDebug = FALSE 
+# name of DEBUG Stream (default "TruncatedHLTResult")
+#HltEventLoopMgr.HltTruncationDebugStreamName = "TruncatedHLTResult"
+# list of stream names which should not be send to the truncation DEBUG stream (default ["CostMonitoring"]) 
+#HltEventLoopMgr.ExcludeFromHltTruncationDebugStream = ["CostMonitoring"]
+
+#
+# properties for the HLT result size histogram
+# --> set upper edge of histogram to maximum allowed number of words in HLT
+#
+HltEventLoopMgr.histHltResultSize=("HltResultSize",0,125000,100)
+
+#
+# Configuration of EDM size monitoring plots
+#
+try:
+    from TrigEDMConfig.TriggerEDM import EDMDetails,getTypeAndKey,keyToLabel
+    from TrigEDMConfig.TriggerEDM import TriggerHLTList
+    
+    # TODO update to use import TriggerHLTList directly
+    #from TrigEDMConfig.TriggerEDM import TriggerL2List,TriggerEFList
+    #TriggerHLTList = list(set(TriggerL2List).union(TriggerEFList))
+    
+    l = []
+    for item in TriggerHLTList:
+        if ('BS' in item[1].split()) or ('DS' in item[1].split()):
+            t,k = getTypeAndKey(item[0])
+            ctype = t
+            if EDMDetails[t].has_key('collection'):
+                ctype = EDMDetails[t]['collection']
+            l += [ctype+'__'+keyToLabel(k)]
+    # add a bin for not accounted collections
+    l += ['not__configured']
+
+    HltEventLoopMgr.HltEDMCollectionNames = l
+    number_of_collections=len( HltEventLoopMgr.HltEDMCollectionNames )
+    HltEventLoopMgr.histHltEdmSizes=("HltEDMSizes",0., 15000., number_of_collections)
+except ImportError,e:
+    print " +----------------------------------------------------------------------+ "
+    print " | No initial configuration for EDM monitoring plots will be available! | "
+    print " +----------------------------------------------------------------------+ "
+    print e
+#==============================================================
+#
+# End of TrigServicesEventLoopMgr configuration file
+#
+#**************************************************************
diff --git a/HLT/Trigger/TrigControl/TrigServices/share/TrigServicesTHistSvc.py b/HLT/Trigger/TrigControl/TrigServices/share/TrigServicesTHistSvc.py
new file mode 100644
index 00000000000..5cb0622e166
--- /dev/null
+++ b/HLT/Trigger/TrigControl/TrigServices/share/TrigServicesTHistSvc.py
@@ -0,0 +1,59 @@
+#**************************************************************
+#
+# TrigServicesTHistSvc configuration file
+#
+#==============================================================
+
+# loading of this library (not a problem if done twice)
+theApp.Dlls += [ "TrigServices" ]
+
+# service creation
+theApp.ExtSvc += [ "HltTHistSvc/THistSvc" ]
+theApp.MultiThreadExtSvc += [ "HltTHistSvc/THistSvc" ]
+
+
+# just a helper function
+def defineTHistSvcOutputFile(dir, name, opt='NEW', service='THistSvc'):
+    if numberOfThreads.value() == 0:
+        THistSvc = Service(service)
+        THistSvc.Output += [dir+" DATAFILE=\'"+name+"' OPT=\'"+opt+"\'" ]
+        return
+    for n in range(0,numberOfThreads.value()):
+        threadID = '__%(#)d' % { '#': n}
+        THistSvc = Service ( service+threadID )
+        THistSvc.Output += [dir+" DATAFILE=\'"+name+threadID+"' OPT=\'"+opt+"\'" ]
+
+# default settings 
+defineTHistSvcOutputFile("SHIFT", "monitoring-shift.root")
+defineTHistSvcOutputFile("EXPERT", "monitoring-expert.root")
+defineTHistSvcOutputFile("DEBUG", "monitoring-debug.root") 
+defineTHistSvcOutputFile("RUNSTAT", "monitoring-runstat.root") 
+
+
+
+# user can also specify REGEX used to check Histograms Naming Convention
+# THistSvc = Service("THistSvc")
+#
+# all sort of regex can be given
+# THistSvc.ExcludeName = ".+LAr.+" # no LAr histograms any more
+# THistSvc.IncludeName = "/SHIFT/.+"   # only monitoring allowed 
+#
+# the default is (implementation of the naming convention):
+# see: https://edms.cern.ch/document/710911/1
+# see: https://twiki.cern.ch/twiki/bin/view/Atlas/AthenaMTHistogramming
+#
+# THistSvc.ExcludeName = ".*\..*"
+# THistSvc.IncludeName = "^/((SHIFT)|(EXPERT)|(DEBUG)|(RUNSTAT))/.+/.+"
+# 
+# Similar can be specified for histogram types (name of the ROOT class)
+# example below can be used to exclude 2dim histograms from being registered
+# THistSvc.ExcludeType = ".+2.+" 
+# example below accepts only 1 dimensional integer histogram
+# THistSvc.ExcludeType = ".+"
+# THistSvc.IncludeType = "TH1I"
+
+#==============================================================
+#
+# End of TrigServicesTHistSvc configuration file
+#
+#**************************************************************
diff --git a/HLT/Trigger/TrigControl/TrigServices/share/hadd.C b/HLT/Trigger/TrigControl/TrigServices/share/hadd.C
new file mode 100644
index 00000000000..f566a4f55c1
--- /dev/null
+++ b/HLT/Trigger/TrigControl/TrigServices/share/hadd.C
@@ -0,0 +1,212 @@
+/*
+
+  NOTE: This macro is kept for back compatibility only.
+  Use instead the executable $ROOTSYS/bin/hadd
+  
+  This macro will add histograms from a list of root files and write them
+  to a target root file. The target file is newly created and must not be
+  identical to one of the source files.
+
+  Author: Sven A. Schmidt, sven.schmidt@cern.ch
+  Date:   13.2.2001
+
+  This code is based on the hadd.C example by Rene Brun and Dirk Geppert,
+  which had a problem with directories more than one level deep.
+  (see macro hadd_old.C for this previous implementation).
+  
+  The macro from Sven has been enhanced by 
+     Anne-Sylvie Nicollerat <Anne-Sylvie.Nicollerat@cern.ch>
+   to automatically add Trees (via a chain of trees).
+  
+  To use this macro, modify the file names in function hadd.
+  
+  NB: This macro is provided as a tutorial.
+      Use $ROOTSYS/bin/hadd to merge many histogram files
+
+  ATLAS HLT COMMENT by T. Bold:
+  This is modified macro used to deal with the sort of strange
+  ROOT files generated while athenaMT is run. There possibly
+  number of the output files. With this one can work whit standard hadd.
+  But in fact there is number of the TTrees in the file 
+  having the same name, just subsequent sequence(version) number. 
+  This can only be handled by this script. 
+ */
+
+
+#include <string.h>
+#include "TChain.h"
+#include "TFile.h"
+#include "TH1.h"
+#include "TTree.h"
+#include "TKey.h"
+#include "Riostream.h"
+
+TList *FileList;
+TFile *Target;
+
+void MergeRootfile( TDirectory *target, TList *sourcelist );
+
+
+void hadd() {
+   // in an interactive ROOT session, edit the file names
+   // Target and FileList, then
+   // root > .L hadd.C
+   // root > hadd()
+   
+  Target = TFile::Open( "result.root", "RECREATE" );
+  
+  FileList = new TList();
+  FileList->Add( TFile::Open("hsimple1.root") );
+  FileList->Add( TFile::Open("hsimple2.root") );
+  
+  MergeRootfile( Target, FileList );
+
+}   
+
+TTree * mergeCircularTrees(const char* treename, TDirectory *dir, TTree *nTree = 0) {
+    
+    TString basename(treename);
+    TIter nextIter(gDirectory->GetListOfKeys()); 
+    gDirectory->GetListOfKeys()->Print();                          
+    TKey *obj;
+    TTree *tptr;
+    TList myTreesList;
+
+    while ( (obj = (TKey *)nextIter()) != 0 ) {                                
+
+	if ( TString(obj->GetClassName()) == TString("TTree") ) {
+	    // it is the tree let's read it in
+	    tptr = (TTree *)obj->ReadObj();
+	    if ( TString(tptr->GetName()) == basename  ) { 
+		if ( nTree == 0 ) {
+		    nTree = (TTree*)tptr->Clone();
+		    nTree->SetCircular(kMaxLong64); // maximum circularity
+		}
+		else
+		    myTreesList.AddLast(tptr);
+	    }    
+	}
+    }
+
+    dir->cd();
+    nTree->SetDirectory(dir);
+    nTree->Merge(&myTreesList);
+    return nTree;
+}
+
+void MergeRootfile( TDirectory *target, TList *sourcelist ) {
+
+  //  cout << "Target path: " << target->GetPath() << endl;
+  TString path( (char*)strstr( target->GetPath(), ":" ) );
+  path.Remove( 0, 2 );
+
+  TFile *first_source = (TFile*)sourcelist->First();
+  first_source->cd( path );
+  TDirectory *current_sourcedir = gDirectory;
+  //gain time, do not add the objects in the list in memory
+  Bool_t status = TH1::AddDirectoryStatus();
+  TH1::AddDirectory(kFALSE);
+
+  // loop over all keys in this directory
+  TTree *nTree = 0;
+  TIter nextkey( current_sourcedir->GetListOfKeys() );
+  TKey *key, *oldkey=0;
+  while ( (key = (TKey*)nextkey())) {
+      //      cout << "found key " << key->GetName() << endl;
+      //keep only the highest cycle number for each key
+      if (oldkey)
+	  if ( strcmp(oldkey->GetName(),key->GetName()) == 0 ) {
+	      //      cout << "skipping key " << key->GetName() << endl;
+	      continue;
+	  }
+      // always set oldkey ptr
+      oldkey = key;
+    
+    // read object from first source file
+    first_source->cd( path );
+    TObject *obj = key->ReadObj();
+
+    if ( obj->IsA()->InheritsFrom( "TH1" ) ) {
+      // descendant of TH1 -> merge it
+
+      //      cout << "Merging histogram " << obj->GetName() << endl;
+      TH1 *h1 = (TH1*)obj;
+
+      // loop over all source files and add the content of the
+      // correspondant histogram to the one pointed to by "h1"
+      TFile *nextsource = (TFile*)sourcelist->After( first_source );
+      while ( nextsource ) {
+        
+        // make sure we are at the correct directory level by cd'ing to path
+        nextsource->cd( path );
+        TKey *key2 = (TKey*)gDirectory->GetListOfKeys()->FindObject(h1->GetName());
+        if (key2) {
+           TH1 *h2 = (TH1*)key2->ReadObj();
+           h1->Add( h2 );
+           delete h2;
+        }
+
+        nextsource = (TFile*)sourcelist->After( nextsource );
+      }
+    }
+    else if ( obj->IsA()->InheritsFrom( "TTree" ) ) {
+      
+      // loop over all source files create a chain of Trees "globChain"
+      const char* obj_name= obj->GetName();
+      cout << "merging all trees in first file" << endl;
+      nTree = mergeCircularTrees(obj_name, target);
+      cout << "merged trees in first file" << endl;
+
+      TFile *nextsource = (TFile*)sourcelist->After( first_source );
+
+     while ( nextsource ) {
+	 nextsource->cd( path );
+	 cout << "merging all trees in file "<< nextsource->GetName() << endl;
+	 mergeCircularTrees(obj_name, target, nTree);
+	 cout << "merged all trees "<< nextsource->GetName() << endl;
+	 nextsource = (TFile*)sourcelist->After( nextsource );
+     }
+
+    } else if ( obj->IsA()->InheritsFrom( "TDirectory" ) ) {
+      // it's a subdirectory
+
+      cout << "Found subdirectory " << obj->GetName() << endl;
+
+      // create a new subdir of same name and title in the target file
+      target->cd();
+      TDirectory *newdir = target->mkdir( obj->GetName(), obj->GetTitle() );
+
+      // newdir is now the starting point of another round of merging
+      // newdir still knows its depth within the target file via
+      // GetPath(), so we can still figure out where we are in the recursion
+      MergeRootfile( newdir, sourcelist );
+
+    } else {
+
+      // object is of no type that we know or can handle
+      cout << "Unknown object type, name: " 
+           << obj->GetName() << " title: " << obj->GetTitle() << endl;
+    }
+
+    // now write the merged histogram (which is "in" obj) to the target file
+    // note that this will just store obj in the current directory level,
+    // which is not persistent until the complete directory itself is stored
+    // by "target->Write()" below
+    if ( obj ) {
+      target->cd();
+
+      //!!if the object is a tree, it is stored in globChain...
+      if(obj->IsA()->InheritsFrom( "TTree" )) {
+	  nTree->Write();
+	  nTree->Print();
+      }
+      else
+	obj->Write( key->GetName() );
+    }
+
+  } // while ( ( TKey *key = (TKey*)nextkey() ) )
+
+  // save modifications to target file
+  target->SaveSelf(kTRUE);
+  TH1::AddDirectory(status);
+}
diff --git a/HLT/Trigger/TrigControl/TrigServices/share/hadd.sh b/HLT/Trigger/TrigControl/TrigServices/share/hadd.sh
new file mode 100755
index 00000000000..f68f3bd59d3
--- /dev/null
+++ b/HLT/Trigger/TrigControl/TrigServices/share/hadd.sh
@@ -0,0 +1,66 @@
+#!/bin/bash
+# generate the script for ROOT hadd.C
+
+#script which will be generated in order to do the merging job
+sums=thishadd.C
+
+# find out where hadd.C is located
+haddmacro=$( dirname $(which hadd.sh))"/hadd.C"
+#echo $haddmacro
+
+if [ ! -f $haddmacro ]
+    then
+    echo "$haddmacro macro could not be found"
+    echo "It is expected to be in the same directory as hadd.sh"
+    echo "Check your installation!"
+    exit 0
+fi
+
+
+# make local copy of the macro
+cp $haddmacro .
+
+
+if [ $# -lt 2 ]
+    then
+    echo "Usage: hadd.sh destination source1|source2|..."
+    exit 127
+fi
+
+output=$1
+shift 1
+
+#build the actual script 
+echo "{
+gROOT->LoadMacro(\"hadd.C+\");
+TFile *foutput = TFile::Open(\"$output\",\"NEW\");
+if ( foutput == 0 ) {
+    cout << \"output file already exist, exitting ...\" << endl;
+    gROOT->ProcessLine(\".q\");
+}
+TList *inputs = new TList();
+
+" > $sums
+
+
+
+echo "INPUT FILES: " `ls $@` 
+echo "OUTPUT FILE: "  $output
+
+# trick to expand wildcards
+for f in `ls $@`
+do
+  echo "inputs->AddLast( TFile::Open (\"$f\") );" >> $sums
+done
+
+echo "
+MergeRootfile(foutput , inputs);
+foutput->Close();
+gROOT->ProcessLine(\".q\");
+}
+" >> $sums
+echo "EXECUTING ROOT to merge files: "
+root -l -b $sums
+# do cleanup
+rm -f $sums hadd.C
+echo "done"
\ No newline at end of file
diff --git a/HLT/Trigger/TrigControl/TrigServices/src/HltEventLoopMgr.cxx b/HLT/Trigger/TrigControl/TrigServices/src/HltEventLoopMgr.cxx
new file mode 100644
index 00000000000..4197a6e621c
--- /dev/null
+++ b/HLT/Trigger/TrigControl/TrigServices/src/HltEventLoopMgr.cxx
@@ -0,0 +1,3234 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+// Gaudi includes
+#include "GaudiKernel/IAlgorithm.h"
+#include "GaudiKernel/Incident.h"
+#include "GaudiKernel/IIncidentSvc.h"
+#include "GaudiKernel/IEvtSelector.h"
+#include "GaudiKernel/IJobOptionsSvc.h"
+#include "GaudiKernel/IssueSeverity.h"
+#include "GaudiKernel/ITHistSvc.h"
+#include "GaudiKernel/ThreadGaudi.h"
+#include "GaudiKernel/Timing.h"
+#include "GaudiKernel/IAlgContextSvc.h"
+#include "GaudiKernel/IAlgManager.h"
+#include "GaudiKernel/ServiceLocatorHelper.h"
+#include "GaudiKernel/SmartIF.h"
+
+// Athena includes
+#include "StoreGate/StoreGateSvc.h"
+#include "EventInfo/EventIncident.h"
+#include "EventInfo/EventInfo.h"
+#include "EventInfo/EventType.h"
+#include "xAODEventInfo/EventAuxInfo.h"
+#include "ByteStreamData/ByteStreamMetadata.h"
+#include "ByteStreamCnvSvcBase/IROBDataProviderSvc.h"
+#include "AthenaPoolUtilities/CondAttrListCollection.h"
+#include "CLIDSvc/CLASS_DEF.h"
+
+// omni redefines this macro, so we save it
+namespace {
+static std::string CMT_PACKAGE_VERSION = PACKAGE_VERSION;
+}
+
+// Trigger includes
+#include "TrigServices/HltEventLoopMgr.h"
+#include "TrigServices/TrigISHelper.h"
+#include "TrigServices/TrigHLTIssues.h"
+#include "TrigPreFlightCheck.h"
+#include "TrigCOOLUpdateHelper.h"
+#include "TrigSORFromPtreeHelper.h"
+#include "TrigConfInterfaces/IHLTConfigSvc.h"
+#include "TrigInterfaces/Incidents.h"
+#include "TrigMonitorBase/TrigLockedHist.h"
+#include "TrigKernel/HltAcceptFlag.h"
+#include "TrigKernel/HltResultStatusCode.h"
+#include "TrigKernel/HltExtraStatusCode.h"
+#include "TrigKernel/IHltTHistSvc.h"
+#include "TrigSteeringEvent/HLTResult.h"
+#include "TrigSteeringEvent/HLTExtraData.h"
+#include "TrigNavigation/TrigEDMSizes.h"
+
+// TDAQ includes
+#include "ers/ers.h"
+#include "eformat/eformat.h"
+#include "eformat/write/ROBFragment.h"
+#include "TTCInfo/LumiBlock.h"
+#include "ddc/DdcFloatInfoNamed.h"
+#include "hltinterface/HLTInterface.h"
+#include "hltinterface/EventId.h"
+#include "hltinterface/HLTResult.h"
+#include "CTPfragment/CTPfragment.h"
+#include "CTPfragment/CTPExtraWordsFormat.h"
+#include "CTPfragment/Issue.h"
+
+// ROOT includes
+#include "TH1F.h"
+#include "TH2I.h"
+#include "TProfile.h"
+#include "TClass.h"
+
+// Other includes
+#include <set>
+#include <string>
+#include <algorithm>
+#include <ctime>
+#include <mutex>
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <boost/property_tree/ptree.hpp>
+#include <boost/algorithm/string.hpp>
+#include <boost/lexical_cast.hpp>
+
+#undef PACKAGE_VERSION      // use the CMT_PACKAGE_VERSION std::string instead
+
+#define ST_WHERE "HltEventLoopMgr::" << __func__ << "(): "
+
+#if ROOT_VERSION_CODE >= ROOT_VERSION(6,0,0)
+#   define CAN_REBIN(hist)  hist->SetCanExtend(TH1::kAllAxes)
+#else
+#   define CAN_REBIN(hist)  hist->SetBit(TH1::kCanRebin)
+#endif
+
+using namespace boost::property_tree;
+using std::string;
+using std::function;
+using std::begin;
+using std::end;
+using SOR = TrigSORFromPtreeHelper::SOR;
+
+namespace
+{
+  //=========================================================================
+  const eformat::helper::Status SW_UNCLASSIFIED(eformat::UNCLASSIFIED, 0),
+                                SW_FAIL(eformat::DATA_CORRUPTION, 0),
+                                SW_TRUNCATION(eformat::INTERNAL_OVERFLOW, 0);
+  constexpr unsigned 
+      INITIAL_ROB_SIZE_MARGIN = 4; /* margin for the rob size, to account for 
+                                      possible additional status words that may
+                                      still be unknonw */
+
+  //=========================================================================
+  constexpr std::array<uint32_t, 7> L1R_MANDATORY_ROBS =
+    {{
+      0x7300a8, 0x7300a9, 0x7300aa, 0x7300ab, // TDAQ_CALO_CLUSTER_PROC_ROI ROBs
+      0x7500ac, 0x7500ad,                     // TDAQ_CALO_JET_PROC_ROI ROBs
+      0x760001                                // TDAQ_MUON_CTP_INTERFACE ROB
+    }}; // default list of IDs of ROBs that must come in the L1R from the RoIB
+
+  //=========================================================================
+  constexpr std::array<uint32_t, 12> L1R_SKIP_ROB_CHECK =
+    {{
+      0x7300a8, 0x7300a9, 0x7300aa, 0x7300ab, // TDAQ_CALO_CLUSTER_PROC_ROI ROBs
+      0x7500ac, 0x7500ad,                     // TDAQ_CALO_JET_PROC_ROI ROBs
+      0x760001,                               // TDAQ_MUON_CTP_INTERFACE ROB
+      0x770001,                               // TDAQ_CTP ROB
+      0x910081, 0x910091, 0x910082, 0x910092  // TDAQ_CALO_TOPO_PROC ROBs
+    }}; //concrete IDs still unknown for TDAQ_FTK and TDAQ_CALO_FEAT_EXTRACT_ROI
+
+  //=========================================================================
+  constexpr std::array<eformat::SubDetector, 7> L1R_SKIP_SD_CHECK =
+    {{
+      eformat::TDAQ_CALO_CLUSTER_PROC_ROI,
+      eformat::TDAQ_CALO_JET_PROC_ROI,
+      eformat::TDAQ_HLT,
+      eformat::TDAQ_FTK,
+      eformat::TDAQ_CALO_TOPO_PROC,
+      eformat::TDAQ_CALO_DIGITAL_PROC,
+      eformat::TDAQ_CALO_FEAT_EXTRACT_ROI
+    }};
+
+  //=========================================================================
+  constexpr std::array<eformat::SubDetector, 8> L1R_BINS =
+    {{
+      eformat::TDAQ_CALO_CLUSTER_PROC_ROI,
+      eformat::TDAQ_CALO_JET_PROC_ROI,
+      eformat::TDAQ_MUON_CTP_INTERFACE,
+      eformat::TDAQ_CTP,
+      eformat::TDAQ_FTK,
+      eformat::TDAQ_CALO_TOPO_PROC,
+      eformat::TDAQ_CALO_DIGITAL_PROC,
+      eformat::TDAQ_CALO_FEAT_EXTRACT_ROI
+    }};
+
+  //=========================================================================
+  constexpr const char * UNEXPECTED_L1R_ROB_LABEL = "Unexpected_ROB";
+  constexpr const char * MISSING_L1R_CTP_LABEL = "Missing_CTP_Fragment";
+
+  //=========================================================================
+  std::mutex timeout_mutex; // To synchronize main and time out threads
+
+  //=========================================================================
+  bool skipEnabledCheck(eformat::SubDetector sd)
+  {
+    // Skip check for HLT Result ROBs (for DataScouting)
+    if (sd == eformat::TDAQ_HLT) return true;
+    
+    // Skip check for certain L1 input ROBs
+    return std::find(begin(L1R_SKIP_SD_CHECK),
+                     end(L1R_SKIP_SD_CHECK),
+                     sd) != end(L1R_SKIP_SD_CHECK);
+  }
+
+  //=========================================================================
+  bool skipEnabledCheck(uint32_t robid)
+  {
+    // Skip check for HLT Result ROBs (for DataScouting)
+    if (eformat::helper::SourceIdentifier(robid).subdetector_id() == eformat::TDAQ_HLT) return true;
+    
+    // Skip check for certain L1 input ROBs
+    return std::find(begin(L1R_SKIP_ROB_CHECK),
+                     end(L1R_SKIP_ROB_CHECK),
+                     robid) != end(L1R_SKIP_ROB_CHECK);
+  }
+
+  //=========================================================================
+  std::string
+  missingL1RobsMsg(const std::vector<uint32_t>& rob_ids)
+  {
+    std::ostringstream ost;
+    if(!rob_ids.empty())
+    {
+      ost << "L1 result ROBs missing: ";
+
+      ost << "0x" << std::hex << std::setfill('0') << std::setw(6);
+      std::copy(std::begin(rob_ids),
+                std::end(rob_ids) - 1, // leave one to avoid delimiter
+                std::ostream_iterator<uint32_t>{ost, ", 0x"});
+      ost << rob_ids.back() << "."; // append without delimiter
+    }
+
+    return ost.str();
+  }
+
+  //=========================================================================
+  void fillEdmHist(TProfile * hist, const std::string& colname,
+                   const HLT::TrigEDMSizes::EDMObjectInfo& info)
+  {
+    if(hist)
+      hist->Fill(colname.c_str(), static_cast<double>(info.words));
+  }
+
+  //=========================================================================
+  void addDebugStreamTag(hltinterface::HLTResult& hlt_result,
+                         const std::string& tagname)
+  {
+    hlt_result.stream_tag.emplace_back(tagname, eformat::DEBUG_TAG, false);
+  }
+
+  //=========================================================================
+  std::unique_ptr<eformat::write::ROBFragment>
+  initRob(uint16_t modid, uint32_t rn, uint32_t l1id, uint32_t bcid,
+          uint32_t l1tt, uint32_t dett, uint32_t * status_words)
+  {
+    using namespace eformat;
+    using write::ROBFragment;
+
+    auto src = helper::SourceIdentifier{TDAQ_HLT, modid}.code();
+    auto robp = std::unique_ptr<ROBFragment>{
+        new ROBFragment{src, rn, l1id, bcid, l1tt, dett, 0, 0, STATUS_FRONT}};
+
+    status_words[0] = SW_UNCLASSIFIED.code();
+    status_words[1] = hltonl::NORMAL_HLT_RESULT;
+    status_words[2] = hltonl::PSC_ERROR_UNCLASSIFIED;
+
+    robp->status(1, status_words);
+    robp->rod_status(1, status_words);
+
+    return robp;
+  }
+
+  //=========================================================================
+  // Class that resets a pointer upon destruction, locking given mutex
+  template <typename T, typename MUTEX>
+  class PtrResetter
+  {
+  public:
+    explicit PtrResetter(T*& ptr, MUTEX& mut)
+      : m_ptr{ptr}
+      , m_mut(mut) // cannot use uniform init due to gcc4.8 bug
+    {}
+    ~PtrResetter() // this is where the work happens
+    {
+      std::lock_guard<MUTEX>{m_mut};
+      m_ptr = nullptr;
+    }
+    PtrResetter(const PtrResetter&) = delete;
+    PtrResetter operator=(const PtrResetter&) = delete;
+    // no need to delete move ops explicitly in this case - not generated
+
+  private:
+    T*& m_ptr;
+    MUTEX& m_mut;
+  };
+}
+
+
+//=========================================================================
+// Standard Constructor
+//=========================================================================
+HltEventLoopMgr::HltEventLoopMgr(const std::string& nam,
+    ISvcLocator* svcLoc)
+: MinimalEventLoopMgr(nam, svcLoc),
+  m_incidentSvc ( "IncidentSvc",  nam ),
+  m_evtStore( "StoreGateSvc", nam ),
+  m_detectorStore( "DetectorStore", nam ),
+  m_inputMetaDataStore( "StoreGateSvc/InputMetaDataStore", nam ),
+  m_robDataProviderSvc( "ROBDataProviderSvc",nam ),
+  m_THistSvc( "THistSvc", nam ),
+  m_isHelper( "TrigISHelper", this),
+  m_coolHelper( "TrigCOOLUpdateHelper", this),
+  m_hltConfigSvc(0),
+  m_algContextSvc(0),
+  m_msg(0),
+  m_currentRun(0),
+  m_currentLB(0),
+  m_currentEvent(0),
+  m_sorTime_stamp(2,0),
+  m_detector_mask(0xffffffff, 0xffffffff, 0, 0),
+  m_l1_hltPrescaleUpdateLB(0xffffffff),
+  m_hist_eventAcceptFlags(0),
+  m_hist_frameworkErrorCodes(0),
+  m_hist_Hlt_result_size(0),
+  m_hist_Hlt_result_status(0),
+  m_hist_numStreamTags(0),
+  m_hist_streamTagTypes(0),
+  m_hist_streamTagNames(0),
+  m_hist_num_partial_eb_robs(0),
+  m_hist_num_partial_eb_SubDetectors(0),
+  m_hist_partial_eb_SubDetectors_ROBs(0),
+  m_hist_partial_eb_SubDetectors_SDs(0),
+  m_hist_Hlt_result_size_physics(0),
+  m_hist_Hlt_result_size_express(0),
+  m_hist_Hlt_result_size_DataScouting(0),
+  m_hist_HltResultSizes_Stream_physics(0),
+  m_hist_HltResultSizes_Stream_DataScouting(0),
+  m_hist_HltEdmSizes_No_Truncation(0),
+  m_hist_HltEdmSizes_With_Truncation(0),
+  m_hist_HltEdmSizes_TruncatedResult_Retained_Collections(0),
+  m_hist_HltEdmSizes_TruncatedResult_Truncated_Collections(0),
+  m_mandatoryL1ROBs{{begin(L1R_MANDATORY_ROBS), end(L1R_MANDATORY_ROBS)}},
+  m_histProp_Hlt_result_size(Gaudi::Histo1DDef("HltResultSize",0,200000,100)),
+  m_histProp_numStreamTags(Gaudi::Histo1DDef("NumberOfStreamTags",-.5,9.5,10)),
+  m_histProp_streamTagNames(Gaudi::Histo1DDef("StreamTagNames",-.5,.5,1)),
+  m_histProp_num_partial_eb_robs(Gaudi::Histo1DDef("NumberROBsPartialEB",-.5,99.5,100)),
+  m_histProp_Hlt_Edm_Sizes(Gaudi::Histo1DDef("HltEDMSizes",0.,10000.,100)),
+  m_total_evt(0),
+  m_failed_evt(0),
+  m_invalid_lvl1_result(0),
+  m_invalid_hlt_result(0),
+  m_truncated_hlt_result(0),
+  m_truncated_hlt_result_to_debug(0),
+  m_truncated_hlt_result_not_to_debug(0),
+  m_lvl1id(0),
+  m_run_no(0),
+  m_bunch_crossing_id(0),
+  m_time_stamp(0),
+  m_time_stamp_ns_offset(0),
+  m_lumi_block(0),
+  m_l1_Status_Element(0),
+  m_l1_Trigger_Type(0),
+  m_l1_detev_type(0),
+  m_hist_l1_robs(0),
+  m_hist_Hlt_truncated_result(0)
+{
+  // General properties for event loop managers
+  declareProperty("predefinedLumiBlock",      m_predefinedLumiBlock=0);
+  declareProperty("Lvl1CTPROBid",             m_lvl1CTPROBid=0x770001);
+  declareProperty("ApplicationName",          m_applicationName="None");
+  declareProperty("PartitionName",            m_partitionName="None");
+  declareProperty("setMagFieldFromPtree",     m_setMagFieldFromPtree=false);
+  declareProperty("enabledROBs",              m_enabledROBs);
+  declareProperty("enabledSubDetectors",      m_enabledSubDetectors);
+  declareProperty("MandatoryL1ROBs",          m_mandatoryL1ROBs, "List of mandatory ROB IDs coming from the RoIB (must come in L1R seed)");
+  declareProperty("HltEDMCollectionNames",    m_hltEdmCollectionNames, "Names of all HLT EDM Collections");
+  declareProperty("JobOptionsType",           m_jobOptionsType="NONE");
+  declareProperty("doMonitoring",             m_doMonitoring=true, "Produce framework monitoring histograms");
+  declareProperty("histHltResultSize",        m_histProp_Hlt_result_size, "Histogram for HLT result size in words");
+  declareProperty("histNumberOfStreamTags",   m_histProp_numStreamTags, "Histogram with number of stream tags");
+  declareProperty("histStreamTagNames",       m_histProp_streamTagNames,"Histogram with stream tag names");  
+  declareProperty("histNumberROBsPartialEB",  m_histProp_num_partial_eb_robs, "Histogram with number of ROBs for PEB" );
+  declareProperty("histHltEdmSizes",          m_histProp_Hlt_Edm_Sizes, "Histogram with sizes of HLT EDM collections" );
+  declareProperty("ForceHltReject",           m_forceHltReject=false);
+  declareProperty("ForceHltAccept",           m_forceHltAccept=false);
+  declareProperty("HltResultName",            m_HltResultName="HLTResult_HLT");
+  declareProperty("HltDebugStreamName",       m_HltDebugStreamName ="HLTMissingData");
+  declareProperty("HltForcedStreamName",      m_HltForcedStreamName ="HLTEventAcceptForced");
+  declareProperty("CoolUpdateTool",           m_coolHelper);
+  declareProperty("maxPrepareForRunSleepSec", m_prepareForRunSleep = 0, "Max number of seconds to sleep at the beginning of prepareForRun");
+  declareProperty("Lvl1CTPROBcheck",          m_lvl1CTPROBcheck=true);
+  declareProperty("WriteTruncatedHLTtoDebug", m_writeHltTruncationToDebug=true);
+  declareProperty("HltTruncationDebugStreamName",  m_HltTruncationDebugStreamName ="TruncatedHLTResult");
+  declareProperty("ExcludeFromHltTruncationDebugStream",  m_excludeFromHltTruncationDebugStream ={"CostMonitoring"});
+}
+
+//=========================================================================
+// Standard Destructor
+//=========================================================================
+HltEventLoopMgr::~HltEventLoopMgr()
+{
+}
+
+//=========================================================================
+// implementation of IInterface: queryInterface
+//=========================================================================
+StatusCode HltEventLoopMgr::queryInterface(const InterfaceID& riid, void** ppvInterface)
+{
+  if(!ppvInterface)
+      return StatusCode::FAILURE;
+
+  if(ITrigEventLoopMgr::interfaceID().versionMatch(riid))
+    *ppvInterface = static_cast<ITrigEventLoopMgr*>(this);
+  else
+    return MinimalEventLoopMgr::queryInterface(riid, ppvInterface);
+
+  addRef();
+  return StatusCode::SUCCESS;
+}
+
+//=========================================================================
+// implementation of IService::sysInitalize
+//=========================================================================
+StatusCode HltEventLoopMgr::sysInitialize()
+{
+  // set message stream
+  m_msg  = new MsgStream( msgSvc(), name() );
+
+  // initialize the base class
+  StatusCode sc = MinimalEventLoopMgr::sysInitialize();
+  sc.setChecked();
+  return sc;
+}
+
+void HltEventLoopMgr::updateDFProps()
+{
+  ServiceHandle<IJobOptionsSvc> p_jobOptionsSvc("JobOptionsSvc", name());
+  if ((p_jobOptionsSvc.retrieve()).isFailure()) {
+    logStream() << MSG::WARNING << "Could not find JobOptionsSvc to set "
+                << "DataFlow properties" << endreq;
+  } else {
+    auto dfprops = p_jobOptionsSvc->getProperties("DataFlowConfig");
+
+    // Application name
+    auto pname = "DF_ApplicationName";
+    const auto * prop = Gaudi::Utils::getProperty(dfprops, pname);
+    if(prop && m_applicationName.assign(*prop)) {
+      logStream() << MSG::DEBUG << " ---> Read from DataFlow configuration: "
+                  << m_applicationName << endreq;
+    } else {
+      logStream() << MSG::WARNING << "Could not set Property '" << pname
+                  << "' from DataFlow." << endreq;
+    }
+
+    // Partition name
+    pname = "DF_PartitionName";
+    prop = Gaudi::Utils::getProperty(dfprops, pname);
+    if (prop && m_partitionName.assign(*prop)) {
+      logStream() << MSG::DEBUG << " ---> Read from DataFlow configuration: "
+                  << m_partitionName << endreq;
+    } else {
+      logStream() << MSG::WARNING << "Could not set Property '" << pname
+                  << "' from DataFlow." << endreq;
+    }
+
+    // get the list of enabled ROBs
+    pname = "DF_Enabled_ROB_IDs";
+    prop = Gaudi::Utils::getProperty(dfprops, pname);
+    if (prop && m_enabledROBs.assign(*prop)) {
+      logStream() << MSG::DEBUG << " ---> Read from DataFlow configuration: "
+                  << m_enabledROBs.value().size() << " enabled ROB IDs."
+                  << endreq;
+    } else {
+      // this is only info, because it is normal in athenaHLT
+      logStream() << MSG::INFO << "Could not set Property '" << pname
+                  << "' from DataFlow." << endreq;
+    }
+
+    // get the list of enabled Sub Detectors
+    pname = "DF_Enabled_SubDet_IDs";
+    prop = Gaudi::Utils::getProperty(dfprops, pname);
+    if (prop && m_enabledSubDetectors.assign(*prop)) {
+      logStream() << MSG::DEBUG << " ---> Read from DataFlow configuration: "
+                  << m_enabledSubDetectors.value().size()
+                  << " enabled Sub Detector IDs." << endreq;
+    } else {
+      // this is only info, because it is normal in athenaHLT
+      logStream() << MSG::INFO << "Could not set Property '"
+                  << pname << "' from DataFlow." << endreq;
+    }
+  }
+
+  p_jobOptionsSvc.release().ignore();
+}
+
+//=========================================================================
+// implementation of IService::initalize
+//=========================================================================
+StatusCode HltEventLoopMgr::initialize()
+{
+  // initialize the base class
+  StatusCode sc = MinimalEventLoopMgr::initialize();
+
+  // leave this after initialization of base class, otherwise msgSvc is not correctly set up
+  //            -----
+  logStream() << MSG::INFO << " ---> HltEventLoopMgr = " << name() << " initialize "
+      << " - package version " << CMT_PACKAGE_VERSION << endreq ;
+  if (sc.isFailure()) {
+    logStream() << MSG::ERROR << "Failed to initialize base class MinimalEventLoopMgr" << endreq;
+    return sc;
+  }
+
+  updateDFProps();
+
+  // JobOptions type
+  SmartIF<IProperty> propMgr ( Gaudi::createApplicationMgr() );
+  if( propMgr.isValid() ) {
+    try {
+      if (m_jobOptionsType.assign( propMgr->getProperty("JobOptionsType") ))
+        logStream() << MSG::DEBUG << " ---> Read from DataFlow configuration: " << m_jobOptionsType << endreq;
+    }
+    catch (...) {
+      logStream() << MSG::WARNING << "Could not set Property '" << m_jobOptionsType.name() << "' from DataFlow." << endreq;
+    }
+  }
+  else {
+    logStream() << MSG::WARNING << "Error retrieving IProperty interface of ApplicationMgr" << endreq;
+  }
+
+  // print properties
+  logStream() << MSG::INFO << " ---> predefinedLumiBlock    = " << m_predefinedLumiBlock << endreq ;
+  logStream() << MSG::INFO << " ---> Lvl1 CTP ROB Id        = " << m_lvl1CTPROBid 
+      << " SourceID in hex = 0x" << MSG::hex << m_lvl1CTPROBid.value() << MSG::dec << endreq ;
+  logStream() << MSG::INFO << " ---> ApplicationName        = " << m_applicationName << endreq ;
+  logStream() << MSG::INFO << " ---> PartitionName          = " << m_partitionName << endreq ;
+  logStream() << MSG::INFO << " ---> JobOptionsType         = " << m_jobOptionsType << endreq ;
+
+  logStream() << MSG::INFO << " ---> Enabled ROBs: size = "
+              << m_enabledROBs.value().size();
+  if (m_enabledROBs.value().size() == 0)
+  {
+    logStream() << MSG::INFO << ". No check will be performed ";
+  }
+  logStream() << endreq;
+
+  logStream() << MSG::INFO << " ---> Enabled Sub Detectors: size = "
+              << m_enabledSubDetectors.value().size();
+  if (m_enabledSubDetectors.value().size() == 0)
+  {
+     logStream() << ". No check will be performed " << endreq;
+  }
+  logStream() << endreq;
+
+  logStream() << MSG::INFO << " ---> Fill monitoring histograms   = " << m_doMonitoring << endreq ;
+  logStream() << MSG::INFO << " ---> Hist: histHltResultSize      = " << m_histProp_Hlt_result_size << endreq ;
+  logStream() << MSG::INFO << " ---> Hist: histNumberOfStreamTags = " << m_histProp_numStreamTags << endreq ;
+  logStream() << MSG::INFO << " ---> Hist: histStreamTagNames     = " << m_histProp_streamTagNames << endreq ;
+  logStream() << MSG::INFO << " ---> Hist: histNumberROBsPartialEB= " << m_histProp_num_partial_eb_robs << endreq ;
+  logStream() << MSG::INFO << " ---> Hist: histHltEdmSizes        = " << m_histProp_Hlt_Edm_Sizes << endreq;
+  logStream() << MSG::INFO << " ---> HLT EDM Collection Names     = " << m_hltEdmCollectionNames << endreq;
+  logStream() << MSG::INFO << " ---> HltResult SG key             = " << m_HltResultName << endreq ;
+  logStream() << MSG::INFO << " ---> HLT debug stream name        = " << m_HltDebugStreamName << endreq ;
+  logStream() << MSG::INFO << " ---> HLT stream for forced events = " << m_HltForcedStreamName << endreq ;
+  logStream() << MSG::INFO << " ---> ForceHltReject               = " << m_forceHltReject << endreq ;
+  logStream() << MSG::INFO << " ---> ForceHltAccept               = " << m_forceHltAccept << endreq;
+
+  if (m_forceHltReject.value()) {
+    logStream() << MSG::INFO << " +------------------------------------------+ "  << endreq ;
+    logStream() << MSG::INFO << " | >>>   ForceHltReject is enabled !    <<< | "  << endreq ;
+    logStream() << MSG::INFO << " | It takes precedence over ForceHltAccept  | "  << endreq ;
+    logStream() << MSG::INFO << " +------------------------------------------+ "  << endreq ;
+  }
+
+  logStream() << MSG::INFO << " ---> Write events with truncated HLT result to debug stream  = " << m_writeHltTruncationToDebug << endreq;
+  logStream() << MSG::INFO << " ---> Debug stream name for events with truncated HLT result  = " << m_HltTruncationDebugStreamName << endreq;
+  logStream() << MSG::INFO << " ---> Stream names of events with a truncated HLT result which will not be send to the debug stream  = " << m_excludeFromHltTruncationDebugStream << endreq;
+
+  //-------------------------------------------------------------------------
+  // Setup the StoreGateSvc
+  //-------------------------------------------------------------------------
+  sc = m_evtStore.retrieve();
+  if(sc.isFailure())
+  {
+    logStream() << MSG::FATAL << "Error retrieving StoreGateSvc "+m_evtStore << endreq;
+    return sc;
+  }
+
+  //-------------------------------------------------------------------------
+  // Setup the DetectorStore
+  //-------------------------------------------------------------------------
+  sc = m_detectorStore.retrieve();
+  if(sc.isFailure())
+  {
+    logStream() << MSG::FATAL << "Error retrieving DetectorStore "+m_detectorStore << endreq;
+    return sc;
+  }
+
+  //-------------------------------------------------------------------------
+  // Setup the InputMetaDataStore
+  //-------------------------------------------------------------------------
+  sc = m_inputMetaDataStore.retrieve();
+  if(sc.isFailure())
+  {
+    logStream() << MSG::FATAL << "Error retrieving InputMetaDataStore"+m_inputMetaDataStore << endreq;
+    return sc;
+  }
+
+  //--------------------------------------------------------------------------
+  // Setup the IncidentSvc
+  //--------------------------------------------------------------------------
+  sc = m_incidentSvc.retrieve();
+  if(sc.isFailure())
+  {
+    logStream() << MSG::FATAL << "Error retrieving IncidentSvc "+m_incidentSvc << endreq;
+    return sc;
+  }
+
+  //--------------------------------------------------------------------------
+  // Setup the ROBDataProviderSvc 
+  //--------------------------------------------------------------------------
+  sc = m_robDataProviderSvc.retrieve();
+  if(sc.isFailure())
+  {
+    logStream() << MSG::FATAL << "Error retrieving ROBDataProviderSvc "+m_robDataProviderSvc << endreq;
+    return sc;
+  }
+
+  //--------------------------------------------------------------------------
+  // Setup the Histogram Service
+  //--------------------------------------------------------------------------
+  sc = m_THistSvc.retrieve();
+  if(sc.isFailure())
+  {
+    logStream() << MSG::FATAL << "Error retrieving THistSvc "+m_THistSvc << endreq;
+    return sc;
+  }
+
+  //--------------------------------------------------------------------------
+  // Setup the TrigISHelper
+  //--------------------------------------------------------------------------
+  sc = m_isHelper.retrieve();
+  if(sc.isFailure())
+  {
+    logStream() << MSG::FATAL << "Error retrieving TrigISHelper "+m_isHelper << endreq;
+    return sc;
+  }
+  sc = m_isHelper->setProperty(m_partitionName);
+  if(sc.isFailure())
+  {
+    logStream() << MSG::FATAL << "Error setting " << m_partitionName.name()
+                    << " of " << m_isHelper << endreq;
+    return sc;
+  }
+
+  //--------------------------------------------------------------------------
+  // COOL helper
+  //--------------------------------------------------------------------------
+  if (m_coolHelper.retrieve().isFailure()) {
+    logStream() << MSG::FATAL << "Error retrieving" << m_coolHelper << endreq;
+    return StatusCode::FAILURE;
+  }
+
+  //--------------------------------------------------------------------------
+  // Setup optional services/tools
+  //--------------------------------------------------------------------------
+  if (service("AlgContextSvc", m_algContextSvc, /*createIf=*/ false).isFailure()) {
+    m_algContextSvc = 0;
+    logStream() << MSG::DEBUG << "No AlgContextSvc available" << endreq;
+  }
+
+  //--------------------------------------------------------------------------
+  // Pre flight check
+  //--------------------------------------------------------------------------
+  ToolHandle<TrigPreFlightCheck> preFlightCheck;
+  if (preFlightCheck.retrieve().isFailure()) {
+    logStream() << MSG::FATAL << "Error retrieving TrigPreFlightCheck "+preFlightCheck << endreq;
+    return StatusCode::FAILURE;
+  }
+
+  // A failed pre-flight check is fatal in a partition
+  if ( validPartition() ) {
+    if ( preFlightCheck->check(MSG::ERROR).isFailure() ) {
+      logStream() << MSG::FATAL << "Pre-flight check for HLT failed." << endreq;
+      return StatusCode::FAILURE;
+    }
+  }
+  else {
+    if ( preFlightCheck->check(MSG::WARNING).isFailure() )
+      logStream() << MSG::WARNING << "Pre-flight check for HLT failed." << endreq;
+  }    
+  preFlightCheck->release();
+
+  // The remainder of this method used to be in the L2/EF specialization
+
+  // fill CTP ROB id vector
+  m_ctpRobIdVec.clear();
+  if (m_lvl1CTPROBid.value() != 0) {
+    m_ctpRobIdVec.push_back( m_lvl1CTPROBid.value() );
+  }
+
+  // print properties
+  logStream() << MSG::INFO << " ---> HltEventLoopMgr            = " << name() << " special properties <--- " << endreq ;
+  logStream() << MSG::INFO << " ---> Lvl1 CTP ROB Id vec.        = 0x" << MSG::hex << m_ctpRobIdVec[0] << MSG::dec
+      << " size of vector = " << m_ctpRobIdVec.size() << endreq ;
+  logStream() << MSG::INFO << " ---> Check for invalid CTP ROBs  = " << m_lvl1CTPROBcheck << endreq ;
+
+//-------------------------------------------------------------------------
+// Reset counters
+//-------------------------------------------------------------------------
+  m_total_evt                         = 0;
+  m_failed_evt                        = 0;
+  m_invalid_lvl1_result               = 0;
+  m_invalid_hlt_result                = 0;
+  m_truncated_hlt_result              = 0;
+  m_truncated_hlt_result_to_debug     = 0;
+  m_truncated_hlt_result_not_to_debug = 0;
+
+//--------------------------------------------------------------------------
+// Setup the HLT Histogram Service when configured
+//--------------------------------------------------------------------------
+  if ( &*m_THistSvc ) {
+    m_hltTHistSvc = SmartIF<IHltTHistSvc>( &*m_THistSvc );
+    if (m_hltTHistSvc.isValid()) {
+      logStream() << MSG::INFO << "A THistSvc implementing the HLT interface IHltTHistSvc was found."
+    << endreq;
+    } else {
+      logStream() << MSG::INFO << "No THistSvc implementing the HLT interface IHltTHistSvc was found."
+    << endreq;
+    }
+  }
+
+//--------------------------------------------------------------------------
+// Setup the HLT ROB Data Provider Service when configured
+//--------------------------------------------------------------------------
+  if ( &*m_robDataProviderSvc ) {
+    m_hltROBDataProviderSvc = SmartIF<ITrigROBDataProviderSvc>( &*m_robDataProviderSvc );
+    if (m_hltROBDataProviderSvc.isValid()) {
+      logStream() << MSG::INFO << "A ROBDataProviderSvc implementing the HLT interface ITrigROBDataProviderSvc was found."
+    << endreq;
+    } else {
+      logStream() << MSG::INFO << "No ROBDataProviderSvc implementing the HLT interface ITrigROBDataProviderSvc was found."
+    << endreq;
+    }
+  }
+
+  return StatusCode::SUCCESS;
+}
+
+//=========================================================================
+// implementation of IService::sysFinalize
+//=========================================================================
+StatusCode HltEventLoopMgr::sysFinalize()
+{
+  // initialize the base class
+  StatusCode sc = MinimalEventLoopMgr::sysFinalize();
+  sc.setChecked();
+  // delete message stream
+  if ( m_msg ) delete m_msg;
+  return sc;
+}
+
+//=========================================================================
+// implementation of IService::finalize
+//=========================================================================
+StatusCode HltEventLoopMgr::finalize()
+{
+  MsgStream log(msgSvc(), name());
+  log << MSG::INFO << " ---> HltEventLoopMgr = " << name() << " finalize " << endreq;
+  log << MSG::INFO << " Total number of events processed :                                     " << m_total_evt << endreq;
+  log << MSG::INFO << "    Events with error in event processing                               " << m_failed_evt << endreq;
+  log << MSG::INFO << "    Events with invalid Lvl1 Result                                     " << m_invalid_lvl1_result << endreq;
+  log << MSG::INFO << "    Events with invalid Hlt Result                                      " << m_invalid_hlt_result << endreq;
+  log << MSG::INFO << "    Events with truncated Hlt Result payload                            " << m_truncated_hlt_result << endreq;   
+  log << MSG::INFO << "    Events with truncated Hlt Result payload (send to debug stream)     " << m_truncated_hlt_result_to_debug << endreq;   
+  log << MSG::INFO << "    Events with truncated Hlt Result payload (not send to debug stream) " << m_truncated_hlt_result_not_to_debug << endreq;   
+
+  // Need to release now. Automatic release in destructor is too late since services are already gone.
+  m_hltTHistSvc.reset();
+  m_hltROBDataProviderSvc.reset();
+
+  StatusCode sc = MinimalEventLoopMgr::finalize();
+  if (sc.isFailure()) {
+    logStream() << MSG::ERROR << "Error in MinimalEventLoopMgr Finalize" << endreq;
+  }
+
+  // Release all interfaces
+  m_incidentSvc.release().ignore();
+  m_robDataProviderSvc.release().ignore();
+  m_evtStore.release().ignore();
+  m_detectorStore.release().ignore();
+  m_inputMetaDataStore.release().ignore();
+  m_THistSvc.release().ignore();
+  m_isHelper.release().ignore();
+
+  return sc;
+}
+
+//=========================================================================
+// implementation of IService::sysReinitialize
+//=========================================================================
+StatusCode HltEventLoopMgr::sysReinitialize()
+{
+  // initialize the base class
+  StatusCode sc = MinimalEventLoopMgr::sysReinitialize();
+  sc.setChecked();
+  // set message stream if not already done
+  if ( !m_msg ) {
+    m_msg  = new MsgStream( msgSvc(), name() );
+  }
+  return sc;
+}
+
+//=========================================================================
+// implementation of IService::reinitialize
+//=========================================================================
+StatusCode HltEventLoopMgr::reinitialize()
+{
+  MsgStream log(msgSvc(), name());
+  log << MSG::INFO << " ---> HltEventLoopMgr = " << name() << " reinitialize " << endreq;
+
+//-------------------------------------------------------------------------
+// Reset counters
+//-------------------------------------------------------------------------
+  m_total_evt                         = 0;
+  m_failed_evt                        = 0;
+  m_invalid_lvl1_result               = 0;
+  m_invalid_hlt_result                = 0;
+  m_truncated_hlt_result              = 0;
+  m_truncated_hlt_result_to_debug     = 0;
+  m_truncated_hlt_result_not_to_debug = 0;
+
+  StatusCode sc = MinimalEventLoopMgr::reinitialize();
+  if (sc.isFailure()) {
+    logStream() << MSG::ERROR << "Error in MinimalEventLoopMgr Reinitialize" << endreq;
+  }
+
+  return sc;
+}
+
+StatusCode HltEventLoopMgr::executeAlgorithms()
+{
+  // Call the resetExecuted() method of ALL "known" algorithms
+  // (before we were reseting only the topalgs)
+  SmartIF<IAlgManager> algMan(serviceLocator());
+  if ( algMan.isValid() ) {
+    const auto& allAlgs = algMan->getAlgorithms() ;
+    for( auto ialg = allAlgs.begin() ; allAlgs.end() != ialg ; ++ialg ) {
+      if ( 0 != *ialg ) (*ialg)->resetExecuted();
+    }
+  }
+
+  // Call the execute() method of all top algorithms
+  return callOnAlgs(&IAlgorithm::sysExecute, "sysExecute", true);
+}
+
+
+//=========================================================================
+// implementation of IEventProcessor::executeEvent(void* par) ---> for "online" running
+//=========================================================================
+StatusCode HltEventLoopMgr::executeEvent(void* par)
+{
+  StatusCode  sc;
+  if (logLevel() <= MSG::DEBUG) {  
+    logStream() << MSG::DEBUG << " ---> HltEventLoopMgr = " << name()
+		    << " executeEvent(par): par = 0x" << MSG::hex << par << MSG::dec << endreq;
+  }
+
+  {
+    std::lock_guard<std::mutex>{timeout_mutex};
+
+    resetTimeout(Athena::Timeout::instance());
+    sc = m_evtStore->retrieve(m_currentEvent);
+  }
+
+  if( sc.isFailure() ) {
+    logStream() << MSG::ERROR << "Expected an EventInfo object." << endreq;
+    return StatusCode::FAILURE;
+  } else {
+    const auto eventrn = m_currentEvent->event_ID()->run_number();
+    if ( (m_currentRun != eventrn))
+      logStream() << (m_currentRun ? MSG::WARNING : MSG::DEBUG)
+                  << "Run number changed from " << m_currentRun << " to "
+                  << eventrn << " Complete EventID   = "
+                  << *(m_currentEvent->event_ID()) << endreq;
+  }
+
+  //-----------------------------------------------------------------------
+  // obtain the HLT conditions update counters from the CTP fragment
+  //-----------------------------------------------------------------------
+  std::vector<uint32_t> l1_hltCounters(1,0);    // HLT counters from CTP fragment
+  std::vector<uint32_t> l1_extraPayload;        // extra paylaod from CTP fragment
+
+  // find the CTP ROB and get the HLT conditions update counters
+  bool b_invalidCTPRob = false;
+  std::vector<uint32_t> ctpRobIdVec(1,m_lvl1CTPROBid.value());
+  std::vector<const OFFLINE_FRAGMENTS_NAMESPACE::ROBFragment*> ctpRobFragmentVec;
+  m_robDataProviderSvc->getROBData(ctpRobIdVec,ctpRobFragmentVec);
+  if( ctpRobFragmentVec.size() == 1 ) {
+    try {
+      // get the HLT Counter
+      l1_hltCounters[0] = CTPfragment::hltCounter( ctpRobFragmentVec[0] );
+      l1_extraPayload = CTPfragment::extraPayloadWords( ctpRobFragmentVec[0] );
+    }
+    catch (CTPfragment::NullFragmentPointer& ex) {
+      b_invalidCTPRob=true;
+      ISSUE(IssueSeverity::ERROR,ex.what());
+    }
+    catch (CTPfragment::Inconsistency& ex) {
+      b_invalidCTPRob=true;
+      ISSUE(IssueSeverity::ERROR,ex.what());
+    }
+    catch (CTPfragment::TimeOutOfRange& ex) {
+      b_invalidCTPRob=true;
+      ISSUE(IssueSeverity::ERROR,ex.what());
+    }
+    catch (CTPfragment::TriggerWordsOutOfRange& ex) {
+      b_invalidCTPRob=true;
+      ISSUE(IssueSeverity::ERROR,ex.what());
+    }
+    catch (CTPfragment::GenericIssue& ex) {
+      b_invalidCTPRob=true;
+      ISSUE(IssueSeverity::ERROR,ex.what());
+    }
+    catch (eformat::Issue& ex) {
+      std::string issue_msg = std::string("Uncaught eformat issue:    ")+std::string(ex.what());
+      b_invalidCTPRob=true;
+      ISSUE(IssueSeverity::ERROR, issue_msg);
+    }
+    catch (ers::Issue& ex) {
+      std::string issue_msg = std::string("Uncaught ERS issue:        ")+std::string(ex.what());
+      b_invalidCTPRob=true;
+      ISSUE(IssueSeverity::ERROR, issue_msg);
+    }
+    catch (std::exception& ex) {
+      std::string issue_msg = std::string("Uncaught std exception:    ")+std::string(ex.what());
+      b_invalidCTPRob=true;
+      ISSUE(IssueSeverity::ERROR, issue_msg);
+    }
+    catch (...) {
+      b_invalidCTPRob=true;
+      ISSUE(IssueSeverity::ERROR,"Uncaught unknown exception.");
+    }
+  } else {
+    // no valid CTP fragment found
+    std::string issue_msg = std::string("No valid CTP fragment found.  ") ;
+    b_invalidCTPRob=true;
+    ISSUE(IssueSeverity::ERROR, issue_msg);
+  }
+
+  //-----------------------------------------------------------------------
+  // create an empty HLT Result Object and register it in StoreGate
+  // (if this fails, steering will try to create a HLT result object)
+  //-----------------------------------------------------------------------
+  auto pHltResult = new HLT::HLTResult;
+  pHltResult->setLvl1Id(m_currentEvent->event_ID()->event_number());
+  HLT::HLTExtraData& extraData = pHltResult->getExtraData();
+  extraData.appName = applicationName();
+  extraData.statusCode |= hltonl::HLT_PRESCALE_UPDATE;  // OK
+
+  // Record it in StoreGate (object can be modified)
+  sc = m_evtStore->record(pHltResult, m_HltResultName, true);
+  if(sc.isFailure()) {
+    logStream() << MSG::ERROR << "Error declaring HLT Result object in SG" << endreq;
+  }
+
+  //-----------------------------------------------------------------------
+  // Decode CTP extra payload words
+  //-----------------------------------------------------------------------
+  CTPfragment::ExtraPayload ctp_payload;
+  try {
+    ctp_payload = CTPfragment::ExtraPayload(l1_extraPayload);
+  }
+  catch (CTPfragment::ExtraPayloadTooLong& ex) {
+    b_invalidCTPRob=true;
+    ISSUE(IssueSeverity::ERROR, std::string("Invalid CTP fragment. Exception = ")+ex.what());
+  }
+
+  if ( logLevel() <= MSG::DEBUG ) {
+    logStream() << MSG::DEBUG << "CTP extra payload (" << l1_extraPayload.size() << " words): ";
+    for (std::size_t i=0; i<l1_extraPayload.size(); ++i) logStream() << " " << l1_extraPayload[i];
+
+    logStream() << ctp_payload << endreq;
+  }
+
+  // Schedule COOL updates
+  m_coolHelper->setFolderUpdates(ctp_payload.getFolderUpdates());
+
+  //-----------------------------------------------------------------------
+  // Check if an HLT conditions update is required
+  //-----------------------------------------------------------------------
+  if (!b_invalidCTPRob) {
+    sc = checkHltPrescaleUpdate(l1_hltCounters);
+    if(sc.isFailure()) {
+      if (pHltResult) {
+        std::vector<uint32_t>& vExtraData = pHltResult->getExtras();
+        // set the HLT PSK flag to 0 to indicate error
+        vExtraData[vExtraData.size()-2] = 0;       // one word for prescale counter (=1 ok, =0 error)
+      }
+      logStream() << MSG::FATAL << "HLT Conditions update failed" << endreq;
+      throw ers::HLTAbort(ERS_HERE, name()+": HLT Conditions update failed");
+    }
+  }
+
+  // Fire BeginEvent "Incident"
+  m_incidentSvc->fireIncident(EventIncident(*m_currentEvent, name(),"BeginEvent"));
+
+  //-----------------------------------------------------------------------
+  // COOL updates for LB changes
+  //-----------------------------------------------------------------------
+  if ( m_currentLB != m_currentEvent->event_ID()->lumi_block() ) {  // LB change
+    m_currentLB = m_currentEvent->event_ID()->lumi_block();
+
+    if ( m_coolHelper->hltCoolUpdate(m_currentLB, m_currentRun,
+                                     m_sorTime_stamp[0], m_sorTime_stamp[1]).isFailure() ) {
+      logStream() << MSG::FATAL << "COOL update failed. Aborting." << endreq;
+      throw ers::HLTAbort(ERS_HERE, name()+": Failure during COOL update");
+    }
+  }
+
+  // Execute Algorithms
+  bool eventFailed = false;
+  try {
+    sc = executeAlgorithms();
+  }
+  catch ( const std::exception& e ) {
+    logStream() << MSG::ERROR << "Caught a standard exception "
+                << e.what() << endreq;
+    sc = StatusCode::FAILURE;
+  }
+  catch (...) {
+    logStream() << MSG::ERROR << "Unknown exception" << endreq;
+    sc = StatusCode::FAILURE;
+  }
+
+  if (sc.isSuccess()) {
+    // Call the execute() method of all output streams
+    for (ListAlg::iterator ito = m_outStreamList.begin(); ito != m_outStreamList.end(); ito++ ) {
+      (*ito)->resetExecuted();
+      sc = (*ito)->sysExecute();
+      if(sc.isFailure())  {
+        logStream() << MSG::WARNING << "Execution of output stream " << (*ito)->name() << " failed" << endmsg;
+        eventFailed = true;
+      }
+    }
+  }
+  else {
+    eventFailed = true;
+  }     
+
+  // Fire EndEvent "Incident"
+  m_incidentSvc->fireIncident(EventIncident(*m_currentEvent, name(),"EndEvent"));
+
+  return eventFailed ? StatusCode::FAILURE : StatusCode::SUCCESS;
+}
+
+//=========================================================================
+// prepare for run step
+//=========================================================================
+StatusCode HltEventLoopMgr::prepareForRun(const ptree & pt)
+{
+  try
+  {
+    
+    (void)TClass::GetClass("vector<unsigned short>"); // preload to overcome an issue with dangling references in serialization
+    (void)TClass::GetClass("vector<unsigned long>");
+
+    const SOR * sor;
+    if(internalPrepareResets().isFailure() || // do the necessary resets and
+       !(sor = processRunParams(pt))) // update SOR in det store and get it back
+      return StatusCode::FAILURE;
+
+    auto & soral = getSorAttrList(sor);
+    updInternal(soral);     // update internally kept info
+    updMetadaStore(soral);  // update metadata store
+
+    const EventInfo * evinfo;
+    if(updMagField(pt).isFailure() ||     // update mag field when appropriate
+       updHLTConfigSvc().isFailure() ||   // update config svc when appropriate
+       resetCoolValidity().isFailure() || // reset selected proxies/IOV folders
+       prepXAODEventInfo().isFailure() || // update xAOD event data in SG
+       !(evinfo = prepEventInfo()))       // update old event data in SG
+      return StatusCode::FAILURE;
+
+    bookAllHistograms();
+
+    if(prepareAlgs(*evinfo).isSuccess())
+      return StatusCode::SUCCESS;
+  }
+  catch(const ptree_bad_path & e)
+  {
+    logStream() << MSG::ERROR << ST_WHERE
+                << "Bad ptree path: \""
+                << e.path<ptree::path_type>().dump() << "\" - " << e.what()
+                << endreq;
+  }
+  catch(const ptree_bad_data & e)
+  {
+    logStream() << MSG::ERROR << ST_WHERE
+                << "Bad ptree data: \""
+                << e.data<ptree::data_type>() << "\" - " << e.what() << endreq;
+  }
+  catch(const std::runtime_error& e)
+  {
+    logStream() << MSG::ERROR << ST_WHERE
+                << "Runtime error: " << e.what() << endreq;
+  }
+
+  return StatusCode::FAILURE;
+}
+
+//=========================================================================
+// allow for updates after forking the workers and issue an incident
+// to inform the clients
+//=========================================================================
+StatusCode HltEventLoopMgr::hltUpdateAfterFork(const ptree & pt)
+{
+  updateDFProps();
+
+  //-----------------------------------------------------------------------
+  // Fire "UpdateAfterFork" "Incident"
+  //-----------------------------------------------------------------------
+  int worker_id  = atoi( (pt.get_child("workerId").data()).c_str() );
+  int process_id = getpid();
+  m_incidentSvc->fireIncident(HLT::Incidents::UpdateAfterFork(worker_id,process_id,name()));
+
+  readyMsg(); // The event processing will start now
+
+  return StatusCode::SUCCESS;
+}
+
+//=========================================================================
+// Hlt: process one event/RoI  ---> for "online" running
+//=========================================================================
+StatusCode HltEventLoopMgr::processRoIs (
+            const std::vector<eformat::ROBFragment<const uint32_t*>>& l1_result,
+            hltinterface::HLTResult& hlt_result,
+            const hltinterface::EventId& evId)
+{
+  PtrResetter<const EventInfo, std::mutex> currentEventResetter{m_currentEvent,
+                                                                timeout_mutex};
+  StatusCode sc;
+
+  //-----------------------------------------------------------------------
+  // increase event counter
+  //-----------------------------------------------------------------------
+  m_total_evt++;
+
+  if ( logLevel() <= MSG::DEBUG ) {
+    logStream() << MSG::DEBUG << " " << endreq;
+    logStream() << MSG::DEBUG << " +------------+" << endreq;
+    logStream() << MSG::DEBUG << " | processRoI | for " << name()
+                << " and event number = " << m_total_evt  << " called."
+                << endreq;
+    logStream() << MSG::DEBUG << " +------------+" << endreq;
+  }
+
+  //-----------------------------------------------------------------------
+  // If HLT THistSvc flush N-tuple buffer
+  //-----------------------------------------------------------------------
+  if ( m_hltTHistSvc.isValid() ) {
+    (m_hltTHistSvc->send()).ignore() ;
+    if ( logLevel() <= MSG::DEBUG ) {
+      logStream() << MSG::DEBUG << " ---> THistSvc->send(): m_hltTHistSvc = "
+      << m_hltTHistSvc << endreq;
+    }
+  }
+
+  //-----------------------------------------------------------------------
+  // reset event qualifiers
+  //-----------------------------------------------------------------------
+  m_lvl1id               = 0; // Level-1 ID=event no., 32 bit unsigned
+  m_run_no               = 0; // run number,           32 bit unsigned
+  m_bunch_crossing_id    = 0; // bunch crossing ID,    32 bit unsigned
+  m_l1_Status_Element    = 0;
+  m_l1_Trigger_Type      = 0;
+  m_l1_detev_type        = 0;
+  m_time_stamp           = 0; // time stamp - posix time in seconds from 1970,   32 bit unsigned
+  m_time_stamp_ns_offset = 0; // time stamp ns - ns time offset for time_stamp,  32 bit unsigned
+  m_lumi_block           = 0; // luminosity block identifier,                    32 bit unsigned
+  m_l1_Trigger_Info.assign(16,0);  // triggerInfo
+
+  // clear hlt_result structure
+  // -------------------------
+  hlt_result.trigger_info.clear();
+  hlt_result.stream_tag.clear();
+  hlt_result.psc_errors.clear();
+  (*hlt_result.fragment_pointer) = 0;
+
+  //-----------------------------------------------------------------------
+  // Check received Lvl1 result (Integrity is checked by HLTPU)
+  // get basic event parameters
+  // Store LVL1 Result in ROBDataProviderSvc cache
+  // Get extended information from the CTP ROB
+  //-----------------------------------------------------------------------
+  if( l1_result.size() == 0 ) {   // no Lvl1 result robs
+    m_invalid_lvl1_result++;
+
+    failedEvent(hlt_result,
+                hltonl::PSC_ERROR_NO_L1_RESULT,
+                "No Lvl1 result ROBs received.");
+
+    return StatusCode::RECOVERABLE;
+  }
+
+  // *-- SubDetectors in received L1 ROB list
+  if (m_hist_l1_robs) {
+    scoped_lock_histogram lock;
+    for(const auto& rob : l1_result)
+    {
+      auto sid = eformat::helper::SourceIdentifier(rob.rob_source_id());
+      auto label = std::string{UNEXPECTED_L1R_ROB_LABEL};
+      if(std::find(begin(L1R_BINS), end(L1R_BINS), sid.subdetector_id())
+         != end(L1R_BINS))
+        label = sid.human_detector();
+
+      m_hist_l1_robs->Fill(label.c_str(), 1.);
+    }
+  }
+
+  const OFFLINE_FRAGMENTS_NAMESPACE::DataType* buffer;
+  // at least 1 Lvl1 rob, set basic parameters
+  m_lvl1id               = l1_result[0].rod_lvl1_id();  // Level-1 ID=event no., 32 bit unsigned
+  m_run_no               = l1_result[0].rod_run_no();   // run number,           32 bit unsigned
+  m_bunch_crossing_id    = l1_result[0].rod_bc_id();    // bunch crossing ID,    32 bit unsigned
+  l1_result[0].status(buffer);
+  m_l1_Status_Element    = *buffer;
+  m_l1_Trigger_Type      = l1_result[0].rod_lvl1_trigger_type();
+  m_l1_detev_type        = l1_result[0].rod_detev_type();
+  m_time_stamp           = 0; // time stamp - posix time in seconds from 1970,   32 bit unsigned
+  m_time_stamp_ns_offset = 0; // time stamp ns - ns time offset for time_stamp,  32 bit unsigned
+  m_lumi_block           = 0; // luminosity block identifier,                    32 bit unsigned
+  m_l1_Trigger_Info.assign(16,0);  // triggerInfo can be obtained from CTP fragment
+
+  // put Lvl1 result in ROBDataProviderSvc cache
+  m_robDataProviderSvc->setNextEvent(l1_result);
+
+  // find the CTP ROB and get the complete event info data
+  std::vector<const OFFLINE_FRAGMENTS_NAMESPACE::ROBFragment*> ctpRobFragmentVec;
+  m_robDataProviderSvc->getROBData(m_ctpRobIdVec,ctpRobFragmentVec);
+  bool b_invalidCTPRob = false;
+  std::ostringstream ost;
+  if( ctpRobFragmentVec.size() == 1 ) {
+    try {
+      m_lvl1id            = ctpRobFragmentVec[0]->rod_lvl1_id();  // Level-1 ID=event no., 32 bit unsigned
+      m_run_no            = ctpRobFragmentVec[0]->rod_run_no();   // run number,           32 bit unsigned
+      m_bunch_crossing_id = ctpRobFragmentVec[0]->rod_bc_id();    // bunch crossing ID,    32 bit unsigned
+      ctpRobFragmentVec[0]->status(buffer);
+      m_l1_Status_Element = *buffer;
+      m_l1_Trigger_Type   = ctpRobFragmentVec[0]->rod_lvl1_trigger_type();
+      m_l1_detev_type     = ctpRobFragmentVec[0]->rod_detev_type();
+      // get time_stamp - posix time in seconds from 1970, and time_stamp_ns - ns time offset for time_stamp
+      CTPfragment::time( ctpRobFragmentVec[0], m_time_stamp, m_time_stamp_ns_offset );
+      // luminosity block identifier, 32 bit unsigned
+      m_lumi_block = CTPfragment::lumiBlockNumber( ctpRobFragmentVec[0] );
+      // get the L1 trigger info
+      m_l1_Trigger_Info   = CTPfragment::triggerDecision( ctpRobFragmentVec[0] );
+
+      b_invalidCTPRob = !checkEventIdConsistency(evId);
+     }
+    catch (CTPfragment::NullFragmentPointer& ex) {
+      m_invalid_lvl1_result++;
+      if (m_lvl1CTPROBcheck) {
+        b_invalidCTPRob=true;
+        ost << " Invalid CTP fragment. Exception = " << ex.what();
+      }
+      ISSUE(IssueSeverity::ERROR,ex.what());
+    }
+    catch (CTPfragment::Inconsistency& ex) {
+      m_invalid_lvl1_result++;
+      if (m_lvl1CTPROBcheck) {
+        b_invalidCTPRob=true;
+        ost << " Invalid CTP fragment. Exception = " << ex.what();
+      }
+      ISSUE(IssueSeverity::ERROR,ex.what());
+    }
+    catch (CTPfragment::TimeOutOfRange& ex) {
+      m_invalid_lvl1_result++;
+      if (m_lvl1CTPROBcheck) {
+        b_invalidCTPRob=true;
+        ost << " Invalid CTP fragment. Exception = " << ex.what();
+      }
+      ISSUE(IssueSeverity::ERROR,ex.what());
+    }
+    catch (CTPfragment::TriggerWordsOutOfRange& ex) {
+      m_invalid_lvl1_result++;
+      if (m_lvl1CTPROBcheck) {
+        b_invalidCTPRob=true;
+        ost << " Invalid CTP fragment. Exception = " << ex.what();
+      }
+      ISSUE(IssueSeverity::ERROR,ex.what());
+    }
+    catch (CTPfragment::GenericIssue& ex) {
+      m_invalid_lvl1_result++;
+      if (m_lvl1CTPROBcheck) {
+        b_invalidCTPRob=true;
+        ost << " Invalid CTP fragment. Exception = " << ex.what();
+      }
+      ISSUE(IssueSeverity::ERROR,ex.what());
+    }
+    catch (eformat::Issue& ex) {
+      m_invalid_lvl1_result++;
+      std::string issue_msg = std::string("Uncaught eformat issue:    ")+std::string(ex.what());
+      if (m_lvl1CTPROBcheck) {
+        b_invalidCTPRob=true;
+        ost << " Invalid CTP fragment. Exception = " << ex.what();
+      }
+      ISSUE(IssueSeverity::ERROR, issue_msg);
+    }
+    catch (ers::Issue& ex) {
+      m_invalid_lvl1_result++;
+      std::string issue_msg = std::string("Uncaught ERS issue:        ")+std::string(ex.what());
+      if (m_lvl1CTPROBcheck) {
+        b_invalidCTPRob=true;
+        ost << " Invalid CTP fragment. Exception = " << ex.what();
+      }
+      ISSUE(IssueSeverity::ERROR, issue_msg);
+    }
+    catch (std::exception& ex) {
+      m_invalid_lvl1_result++;
+      std::string issue_msg = std::string("Uncaught std exception:    ")+std::string(ex.what());
+      if (m_lvl1CTPROBcheck) {
+        b_invalidCTPRob=true;
+        ost << " Invalid CTP fragment. Exception = " << ex.what();
+      }
+      ISSUE(IssueSeverity::ERROR, issue_msg);
+    }
+    catch (...) {
+      m_invalid_lvl1_result++;
+      if (m_lvl1CTPROBcheck) {
+        b_invalidCTPRob=true;
+        ost << " Invalid CTP fragment. Uncaught unknown exception.";
+      }
+      ISSUE(IssueSeverity::ERROR,"Uncaught unknown exception.");
+    }
+  } else {
+    // no valid CTP fragment found
+    m_invalid_lvl1_result++;
+    if (m_hist_l1_robs)
+      lock_histogram_operation<TH1F>(m_hist_l1_robs)->Fill(MISSING_L1R_CTP_LABEL, 1.);
+
+    std::string issue_msg = std::string("No valid CTP fragment found.  ") ;
+    if (m_hltROBDataProviderSvc.isValid()) issue_msg = issue_msg + std::string("\n") +
+                m_hltROBDataProviderSvc->dumpROBcache() ;
+    if (m_lvl1CTPROBcheck) {
+      b_invalidCTPRob=true;
+      ost << " No valid CTP fragment found. " ;
+    }
+    ISSUE(IssueSeverity::ERROR, issue_msg);
+  }
+
+  // in case a check of the CTP Rob is requested and an invalid fragment was found
+  // skip the event and put it on the debug stream
+  // -----------------------------------------------------------------------------
+  if (m_lvl1CTPROBcheck && b_invalidCTPRob) {
+    ost << " Skip event requested. ";
+    failedEvent(hlt_result,
+                hltonl::PSC_ERROR_INVALID_CTP_RESULT,
+                ost.str());
+
+    return StatusCode::RECOVERABLE;
+  }
+
+  // Check for other missing L1 ROBs
+  auto missing_l1_robs = missingL1Robs(l1_result);
+  if(!missing_l1_robs.empty())
+  {
+    ++m_invalid_lvl1_result;
+    failedEvent(hlt_result, hltonl::PSC_ERROR_NO_L1_RESULT,
+                missingL1RobsMsg(missing_l1_robs));
+
+    return StatusCode::RECOVERABLE;
+  }
+
+  //-----------------------------------------------------------------------
+  // Clear the event store, if used in the event loop
+  //-----------------------------------------------------------------------
+  sc = m_evtStore->clearStore();
+  if ( logLevel() <= MSG::DEBUG ) {
+    logStream() << MSG::DEBUG << " ---> Clear of Event data store " << sc << endreq;
+  }
+  if(sc.isFailure()) {
+    failedEvent(hlt_result, hltonl::PSC_ERROR_SG_CLEAR_FAILED,
+                "Clear of Event data store failed.");
+    return sc;
+  }
+
+  // create an EventInfo Object to fire the incidents and register in evt store
+  auto pEvent = new EventInfo(new EventID(m_run_no,
+                                          evId.globalId,
+                                          m_time_stamp,
+                                          m_time_stamp_ns_offset,
+                                          m_lumi_block,
+                                          m_bunch_crossing_id,
+                                          std::get<0>(m_detector_mask),
+                                          std::get<1>(m_detector_mask),
+                                          std::get<2>(m_detector_mask),
+                                          std::get<3>(m_detector_mask)),
+                              new EventType(),
+                              new TriggerInfo(m_l1_Status_Element,
+                                              m_lvl1id,
+                                              m_l1_Trigger_Type,
+                                              m_l1_Trigger_Info));
+
+  if ( logLevel() <= MSG::DEBUG ) {
+    logStream() << MSG::DEBUG << " +-----------+ " << endreq;
+    logStream() << MSG::DEBUG << " | New Event | Run = " << m_run_no 
+		<< " / Level-1 ID = "      << m_lvl1id 
+		<< " / global Event ID = " << evId.globalId
+		<< endreq;
+    logStream() << MSG::DEBUG << " +-----------+ " << endreq;
+    logStream() << MSG::DEBUG << " Complete EventID    = " << *(pEvent->event_ID()) << endreq;
+    logStream() << MSG::DEBUG << "        EventType    = " << ((pEvent->event_type())->typeToString()) << endreq;
+    logStream() << MSG::DEBUG << "      TriggerInfo    = " << *(pEvent->trigger_info()) << endreq;
+    logStream() << MSG::DEBUG << " Current Run number  = " << m_currentRun << endreq;
+  }
+
+  // Record it in StoreGate
+  if(m_evtStore->record(pEvent, "EventInfo").isFailure())
+  {
+    failedEvent(hlt_result, hltonl::PSC_ERROR_NO_EVENTINFO,
+        "Error recording EventInfo object in SG");
+
+    return StatusCode::FAILURE;
+  }
+
+  //-----------------------------------------------------------------------
+  // process the RoI(s)/Event
+  //-----------------------------------------------------------------------
+  sc = executeEvent(NULL);
+  if(sc.isFailure()) {
+    failedEvent(hlt_result, hltonl::PSC_ERROR_UNCLASSIFIED,
+                "An unknown error occured during event processing",
+                false /* no empty result */);
+  }
+
+  // Get the xAOD::EventInfo from SG
+  xAOD::EventInfo * xev{nullptr};
+  if(m_evtStore->retrieve(xev, "EventInfo").isFailure())
+  {
+    logStream() << MSG::WARNING << ST_WHERE
+                << "Could not retrieve xAOD::EventInfo in store gate. "
+                << "If running in HelloWorld algorithms, this is OK."
+                << endreq;
+  }
+
+  logStream() << MSG::DEBUG << " new xAOD::EventInfo: " << xev << endreq;
+
+  //-----------------------------------------------------------------------
+  // build HLT result
+  //-----------------------------------------------------------------------
+  HltResult(hlt_result, pEvent, xev);
+  // fill histograms
+  fillHltResultHistograms(hlt_result);
+
+  return sc;
+}
+
+//=========================================================================
+// implementation of IService::stop() ---> for "online" running
+//=========================================================================
+StatusCode HltEventLoopMgr::stop()
+{
+  // Do nothing if we are already stopped
+  if ( FSMState() != Gaudi::StateMachine::RUNNING )
+    return StatusCode::SUCCESS;
+
+  if (logLevel() <= MSG::DEBUG) {  
+    logStream() << MSG::DEBUG << " ---> HltEventLoopMgr = " << name() << " stop() " << endreq;
+  }
+
+  //-----------------------------------------------------------------------
+  // Fire EndRun "Incident"
+  //-----------------------------------------------------------------------
+  m_incidentSvc->fireIncident(Incident(name(), IncidentType::EndRun));
+
+  //-----------------------------------------------------------------------
+  // Call endRun() and stop() of all algorithms
+  //-----------------------------------------------------------------------
+  auto suc1 = callOnAlgs(&IAlgorithm::sysEndRun, "sysEndRun").isSuccess();
+  auto suc2 = callOnAlgs(&IAlgorithm::sysStop, "sysStop").isSuccess();
+
+  return (suc1 && suc2) ? StatusCode::SUCCESS : StatusCode::FAILURE;
+}
+
+//=========================================================================
+// implementation of ITrigEventLoopMgr::timeOutReached ---> for "online" running
+//=========================================================================
+/**
+ * Called by the PSC once the HLTPU signals the timeout warning.
+ *
+ * !!! This method is executed in the context of the timeout thread !!!
+ * !!! Make sure the code is thread-safe                            !!!
+ *
+ */
+StatusCode HltEventLoopMgr::timeOutReached(const ptree& pt)
+{
+  IAlgorithm* alg = m_algContextSvc ? m_algContextSvc->currentAlg() : 0;
+
+  // add current algorithm info
+  std::ostringstream tmsg;
+  tmsg << "Timeout warning received"
+       << (alg ? (" while executing '"+alg->name()+"'. ") : ". ");
+
+  // set timeout and add current event info
+  {
+    std::lock_guard<std::mutex>{timeout_mutex};
+
+    setTimeout(Athena::Timeout::instance());
+    if (m_currentEvent)
+      tmsg << " On event " << *m_currentEvent->event_ID() << ". ";
+    else
+      tmsg << " Unknown event - outside of event processing? ";
+  }
+
+  // add time interval info
+  auto starts = pt.get_optional<long long>("StartTime_s");
+  if(starts)
+  {
+    auto ends = std::chrono::duration_cast<std::chrono::seconds>(
+        std::chrono::steady_clock::now().time_since_epoch()).count();
+    tmsg << (ends - *starts) << " seconds elapsed since ";
+  }
+  else
+    tmsg << "No information of when ";
+
+  tmsg << "the HLTPU last started counting.";
+
+  // log timeout message
+  ERS_HLT_WARNING(tmsg.str());
+
+  // Also fire timeout incident (this seems to cause problems, see #66066)
+  // m_incidentSvc->fireIncident( HLT::Incidents::EventTimeout(name()) );  
+
+  return StatusCode::SUCCESS;
+}
+
+
+
+//=========================================================================
+// implementation of ITrigEventLoopMgr::checkHltPrescaleUpdate() ---> for "online" running
+//=========================================================================
+StatusCode HltEventLoopMgr::checkHltPrescaleUpdate(std::vector<uint32_t>& hltCounter)
+{
+  if (logLevel() <= MSG::DEBUG) {  
+    logStream() << MSG::DEBUG << " ---> HltEventLoopMgr = " << name()
+		    << " hltConditionsUpdate(std::vector<uint32_t>&): size of input = " << hltCounter.size() << ": ";
+    for (size_t i=0; i<hltCounter.size(); ++i) logStream() << hltCounter[i] << " ";
+    logStream() << endreq;
+  }
+  if ( hltCounter.empty() ) return StatusCode::SUCCESS;  
+
+  // First (and only used) element is LB of the prescale update
+  uint32_t new_hltPrescaleUpdateLB = hltCounter[0];
+
+  // Only update if counter (lumiblock for update) changed (or first event)
+  if ( m_l1_hltPrescaleUpdateLB != new_hltPrescaleUpdateLB ) {    
+    m_l1_hltPrescaleUpdateLB = new_hltPrescaleUpdateLB;
+
+    // Retrieve EventInfo object
+    const EventInfo* pEvent(0);
+    StatusCode sc = m_evtStore->retrieve(pEvent);
+    if(sc.isFailure()) {
+      logStream() << MSG::ERROR << "Unable to retrieve EventInfo object" << endreq;
+      return sc;
+    }
+
+    logStream() << MSG::INFO << "Prescale update requested for lumiblock "
+        << m_l1_hltPrescaleUpdateLB << ". Current event: " << *pEvent->event_ID() << endreq;
+
+    // Perform prescale update right away (including on first event)
+    sc = hltPrescaleUpdate(m_l1_hltPrescaleUpdateLB);
+    return sc;
+  }
+
+  return StatusCode::SUCCESS;
+}
+
+
+//=========================================================================
+// implementation of ITrigEventLoopMgr::hltPrescaleUpdate() ---> for "online" running
+//=========================================================================
+StatusCode HltEventLoopMgr::hltPrescaleUpdate(uint32_t lumiBlock)
+{
+  if ( !m_hltConfigSvc ) {
+    return StatusCode::SUCCESS;
+  }
+
+  // ID must be unqiue across runs until DbProxy gets restarted
+  unsigned int id = m_currentRun*10000 + lumiBlock;
+  logStream() << MSG::INFO << " ---> HltEventLoopMgr = " << name()
+                  << " calling HLTConfigSvc::updatePrescaleSets(" << id << ")" << endreq;
+  StatusCode sc = m_hltConfigSvc->updatePrescaleSets(id);
+
+  return sc;
+}
+
+//=========================================================================
+// check that a ROB ID is enabled for readout in OKS  ---> for "online" running
+//=========================================================================
+bool HltEventLoopMgr::isRobEnabled(uint32_t robid) const
+{
+  bool b_enabled = true;
+
+  // check if given ROB is actually enabled for readout
+  // Consider some ROBs from SubDetectorGroup TDAQ as always enabled
+  if ((m_enabledROBs.value().size() != 0) &&
+      !skipEnabledCheck(robid))
+  {
+    auto rob_enabled_it = std::find(m_enabledROBs.value().begin(),
+                                    m_enabledROBs.value().end(),
+                                    robid);
+    if(rob_enabled_it == m_enabledROBs.value().end())
+    {
+      if(logLevel() <= MSG::DEBUG)
+        logStream() << MSG::DEBUG << "---> ROB Id : 0x" << MSG::hex << robid
+                    << MSG::dec << " will not be retrieved, since it is not on "
+                                   "the list of enabled ROBs." << endreq;
+
+      b_enabled = false;
+    }
+  }
+
+  return b_enabled;
+}
+
+//=========================================================================
+// check that a Sub Detector ID is enabled for readout in OKS  ---> for "online" running
+//=========================================================================
+bool HltEventLoopMgr::isSubDetectorEnabled(uint32_t subdetid) const
+{
+  bool b_enabled = true;
+
+  // check if given subdetector is actually enabled for readout
+  if ((m_enabledSubDetectors.value().size() != 0) &&
+      !skipEnabledCheck(static_cast<eformat::SubDetector>(subdetid)))
+  {
+    auto sd_enabled_it = std::find(m_enabledSubDetectors.value().begin(),
+                                   m_enabledSubDetectors.value().end(),
+                                   subdetid);
+    if(sd_enabled_it == m_enabledSubDetectors.value().end())
+    {
+      if(logLevel() <= MSG::DEBUG)
+        logStream() << MSG::DEBUG << "---> Sub Detector Id : 0x" << MSG::hex
+                    << subdetid << MSG::dec << " will not be retrieved, since "
+                    "it is not on the list of enabled Sub Detectors." << endreq;
+      b_enabled = false;
+    }
+  }
+
+  return b_enabled;
+}
+
+//=========================================================================
+// filter a set of robs according to whether or not they are enabled
+//=========================================================================
+std::set<uint32_t>
+HltEventLoopMgr::filterRobs(const std::set<uint32_t> robs) const
+{
+  auto ret = decltype(robs){};
+  for(const auto& r : robs)
+    if(isRobEnabled(r))
+      ret.insert(r);
+
+  return ret;
+}
+
+//=========================================================================
+// filter a set of dets according to whether or not they are enabled
+//=========================================================================
+std::set<eformat::SubDetector>
+HltEventLoopMgr::filterDets(const std::set<uint32_t> dets) const
+{
+  auto ret = std::set<eformat::SubDetector>{};
+  for(const auto& d : dets)
+    if(isSubDetectorEnabled(d))
+      ret.insert(static_cast<eformat::SubDetector>(d));
+
+  return ret;
+}
+
+//=========================================================================
+// Obsolete methods for online running
+//=========================================================================
+StatusCode HltEventLoopMgr::nextEvent(int maxevt)
+{
+  logStream() << MSG::ERROR << " +-------------------------------------------------------------------------+ " << endreq;
+  logStream() << MSG::ERROR << " | method --->  HltEventLoopMgr::nextEvent(int maxevt) <--- called         | " << endreq;
+  logStream() << MSG::ERROR << " | This method can not be used in trigger since the event loop is          | " << endreq;
+  logStream() << MSG::ERROR << " | controlled by the data flow software.                                   | " << endreq;
+  logStream() << MSG::ERROR << " | Method is not implemented                                               | " << endreq;
+  logStream() << MSG::ERROR << " +-------------------------------------------------------------------------+ " << endreq;
+  logStream() << MSG::ERROR << " maxevt = " << maxevt << endreq;
+  logStream() << MSG::ERROR << " Type info = " << System::typeinfoName(typeid(*this)) << endreq;
+  return StatusCode::FAILURE;
+}
+
+StatusCode HltEventLoopMgr::executeRun(int)
+{
+  logStream() << MSG::ERROR << " +-------------------------------------------------------------------------+ " << endreq;
+  logStream() << MSG::ERROR << " | method --->  HltEventLoopMgr::executeRun(int) <--- called               | " << endreq;
+  logStream() << MSG::ERROR << " | This method can not be used in trigger since the event loop is          | " << endreq;
+  logStream() << MSG::ERROR << " | controlled by the data flow software.                                   | " << endreq;
+  logStream() << MSG::ERROR << " | Method is not implemented                                               | " << endreq;
+  logStream() << MSG::ERROR << " +-------------------------------------------------------------------------+ " << endreq;
+  logStream() << MSG::ERROR << " Type info = " << System::typeinfoName(typeid(*this)) << endreq;
+  return StatusCode::FAILURE;
+}
+
+StatusCode HltEventLoopMgr::stopRun()
+{
+  logStream() << MSG::ERROR << " +-------------------------------------------------------------------------+ " << endreq;
+  logStream() << MSG::ERROR << " | method --->  HltEventLoopMgr::stopRun() <--- called                     | " << endreq;
+  logStream() << MSG::ERROR << " | This method is not implemented for online usage. Call stop() instead.   | " << endreq;
+  logStream() << MSG::ERROR << " +-------------------------------------------------------------------------+ " << endreq;
+  logStream() << MSG::ERROR << " Type info = " << System::typeinfoName(typeid(*this)) << endreq;
+  return StatusCode::FAILURE;
+}
+
+//=========================================================================
+// HltEmptyResultROB()
+//=========================================================================
+void HltEventLoopMgr::HltEmptyResultROB(hltinterface::HLTResult& hlt_result,
+    uint32_t run_no, uint32_t lvl1_id, uint32_t bunch_crossing_id,
+    uint32_t l1_Trigger_Type, uint32_t l1_detev_type,
+    hltonl::PSCErrorCode pscErrorCode)
+{
+  if ( logLevel() <= MSG::DEBUG ) {
+    logStream() << MSG::DEBUG << "---> HltEmptyResultROB() for " << name() 
+		    << " and sub detector = " << eformat::helper::SubDetectorDictionary.string(eformat::TDAQ_HLT)
+		    << " called " << endreq;
+  }
+
+  //
+  // Set the PSC error words
+  // -----------------------
+  //
+  HltSetPscError(hlt_result, pscErrorCode);
+
+  //
+  // Create a dummy HLT result ROB
+  // -----------------------------
+  //
+
+  // the second status element
+  hltonl::ResultStatusCode hlt_status = hltonl::DUMMY_HLT_RESULT ;
+
+  // Build the third status elements for the dummy HLT result
+  // number of status words used (in case of PSC error = 3, otherwise = 2)
+  uint32_t n_status_word = 3;
+  m_status_words[0] = SW_FAIL.code();
+  m_status_words[1] = hlt_status;
+  m_status_words[2] = pscErrorCode; //this means "dummy HLT result, with no data due PSC error"
+
+  if (!pscErrorCode) {
+    m_status_words[0] = SW_UNCLASSIFIED.code(); //this means "dummy HLT result, with no data, no PSC error"
+    n_status_word = 2;
+  }
+
+  // Build an empty HLT result
+  eformat::helper::SourceIdentifier src(eformat::TDAQ_HLT, 0);
+  eformat::write::ROBFragment rob(src.code(), run_no, lvl1_id, bunch_crossing_id, l1_Trigger_Type, l1_detev_type,
+      0, 0, eformat::STATUS_FRONT);
+  rob.status(n_status_word, m_status_words);
+  rob.rod_status(n_status_word, m_status_words);
+
+  // find the maximum allowed payload
+  int hltr_max_payload = hlt_result.max_result_size - rob.size_word() ;
+  if ( hlt_result.max_result_size <= rob.size_word() ) {
+    logStream() << MSG::ERROR
+        << "Can not create empty HLT result ROB with available ROB buffer size ! Available buffer size = "
+        << hlt_result.max_result_size << " Number of header words used by empty ROB = " << rob.size_word()
+        << endreq;
+    return;
+  }
+
+  // Create a dummy HLT result and check data size
+  uint32_t* hltr_data(0);
+  int       hltr_data_size = 0;
+  HLT::HLTResult emptyHLTResult;
+  emptyHLTResult.setLvl1Id(lvl1_id);
+
+  HLT::HLTExtraData& extraData = emptyHLTResult.getExtraData();
+  extraData.appName = applicationName();
+  extraData.statusCode &= ~hltonl::HLT_PRESCALE_UPDATE;  // error (clear bit)
+
+  bool serializationOk = emptyHLTResult.serialize( hltr_data, hltr_data_size, hltr_max_payload);
+
+  if ( !serializationOk ) {
+    // Update status words for dummy HLT result
+    hlt_status = hltonl::DUMMY_HLT_RESULT_TRUNCATED;
+    m_status_words[0] = SW_TRUNCATION.code() ;
+    m_status_words[1] = hlt_status ;
+  }
+
+  if (( hltr_data_size > hltr_max_payload)) { // consistency check
+    logStream() << MSG::ERROR 
+        << "Inconsistency for created dummy HLT result ROB. Returned data size = " << hltr_data_size
+        << " is greater than allowed max. payload size = " << hltr_max_payload << "."
+        << endreq;
+    hltr_data_size = hltr_max_payload;
+
+    // Update status words for dummy HLT result
+    hlt_status = hltonl::DUMMY_HLT_RESULT_TRUNCATED;
+    m_status_words[0] = SW_TRUNCATION.code();
+    m_status_words[1] = hlt_status ;
+  }
+
+  // build the fragment
+  rob.status(n_status_word, m_status_words);
+  rob.rod_status(n_status_word, m_status_words);
+  rob.rod_data(hltr_data_size, hltr_data);
+
+  //
+  // store the dummy HLT ROB fragment in the hlt_result structure
+  // ------------------------------------------------------------ 
+  //
+  // The maximum possible space is already allocated by the HLTMPPU
+  // copy the ROB contents into the allocated memory
+  auto next_fragment = hlt_result.fragment_pointer;
+  auto spaceleft = hlt_result.max_result_size;
+  addRobToHLTResult(hlt_result, rob, next_fragment, spaceleft);
+
+  // delete the data array
+  if (hltr_data != 0) delete[] hltr_data;
+
+  return;
+} // end method HltEventLoopMgr::HltEmptyResultROB
+
+//=========================================================================
+// HltEmptyResultROB()  ---> for "online" running
+//=========================================================================
+void HltEventLoopMgr::HltEmptyResultROB(hltinterface::HLTResult& hlt_result, hltonl::PSCErrorCode pscErrorCode)
+{
+  if ( logLevel() <= MSG::DEBUG ) {
+    logStream() << MSG::DEBUG << "---> HltEmptyResultROB() for "
+                << name() << " called " << endreq;
+  }
+
+  HltEmptyResultROB(hlt_result,
+                    m_run_no, m_lvl1id, m_bunch_crossing_id,
+                    m_l1_Trigger_Type, m_l1_detev_type,
+                    pscErrorCode);
+  return;
+} //  end method HltEventLoopMgr::HltEmptyResult
+
+//=========================================================================
+// HltResultROBs()
+//=========================================================================
+hltonl::PSCErrorCode HltEventLoopMgr::HltResultROBs(
+    hltinterface::HLTResult& hlt_result,
+    uint32_t run_no, uint32_t lvl1_id, uint32_t bunch_crossing_id,
+    uint32_t l1_Trigger_Type, uint32_t l1_detev_type,
+    const std::vector<TriggerInfo::number_type>& trigger_info,
+    const std::vector<TriggerInfo::StreamTag>& stream_tags,
+    const std::vector<xAOD::EventInfo::StreamTag>& xsts)
+{
+  HLT::HLTResult* dobj{0};
+  auto hlt_decision = hltonl::PSC_FORCED_REJECT;
+  auto ecode = hltonl::PSC_ERROR_UNCLASSIFIED;
+  if(!m_forceHltReject)
+  {
+    // preliminary hlt_result setup
+    setStreamTags(hlt_result, stream_tags);
+    mergeStreamTags(hlt_result, xsts);
+    hlt_result.trigger_info = trigger_info;
+
+    // Get Pesa HLT Result from Steering
+    StatusCode sc;
+    if(!(m_evtStore->transientContains<HLT::HLTResult>(m_HltResultName)) ||
+       (sc = m_evtStore->retrieve(dobj,m_HltResultName)).isFailure())
+    {
+      hlt_decision = hltonl::PSC_DEBUG;
+      logStream() << MSG::ERROR << ST_WHERE
+                  << "Error retrieving HLTResult from StoreGate with key = "
+                  << m_HltResultName << endreq;
+
+      ecode = sc.isFailure() ? hltonl::PSC_ERROR_NO_HLTRESULT_RETRIEVED
+                             : hltonl::PSC_ERROR_NO_HLTRESULT_FOUND;
+    }
+    else if((hlt_decision = processHltDecision(hlt_result)) !=
+            hltonl::STEERING_REJECT)
+    {
+      // Got Steering's HLT Result and confirmed the event should be accepted
+      auto serializationOk = true;
+      ecode = serializeRobs(hlt_result, serializationOk, dobj, run_no, lvl1_id,
+                            bunch_crossing_id, l1_Trigger_Type, l1_detev_type);
+      if(!ecode)
+        recordEDMSizeInfo(dobj->getNavigationResult().size(), serializationOk);
+
+      // The HLT result got truncated, put the event on a special debug stream if requested 
+      if (!serializationOk) {
+	m_truncated_hlt_result++;
+	if (m_hist_Hlt_truncated_result) {
+	  scoped_lock_histogram lock;
+	  m_hist_Hlt_truncated_result->Fill(1.);
+	}
+ 	if ((!m_HltTruncationDebugStreamName.value().empty()) &&
+	    (m_writeHltTruncationToDebug.value())) {
+      	  // check if event should be not send to the debug stream (e.g. Cost Monitoring)
+	  bool sendToDebug(true);
+	  for (auto it_st : hlt_result.stream_tag) {
+	    auto p = std::find(m_excludeFromHltTruncationDebugStream.value().begin(), 
+			       m_excludeFromHltTruncationDebugStream.value().end(),
+			       (it_st).name);
+	    if (p != m_excludeFromHltTruncationDebugStream.value().end()) sendToDebug=false;
+	  }
+	  if (sendToDebug) {
+	    m_truncated_hlt_result_to_debug++;	 
+	    if (m_hist_Hlt_truncated_result) {
+	      scoped_lock_histogram lock;
+	      m_hist_Hlt_truncated_result->Fill(2.);
+	    }
+	    hlt_result.stream_tag.clear();
+	    addDebugStreamTag(hlt_result, m_HltTruncationDebugStreamName);
+	    logStream() << MSG::ERROR << ST_WHERE
+			<< "HLTResult was truncated. Event send to debug stream  = "
+			<< m_HltTruncationDebugStreamName << endreq;
+	  } else {
+	    m_truncated_hlt_result_not_to_debug++;	 
+	    if (m_hist_Hlt_truncated_result) {
+	      scoped_lock_histogram lock;
+	      m_hist_Hlt_truncated_result->Fill(3.);
+	    }
+	    logStream() << MSG::WARNING << ST_WHERE
+			<< "HLTResult was truncated. Event was NOT send to debug stream  = "
+			<< m_HltTruncationDebugStreamName
+			<< " because an exclusion stream tag name matched from = " << m_excludeFromHltTruncationDebugStream.value()  
+			<< endreq;
+	  }
+	} else {
+	  m_truncated_hlt_result_not_to_debug++;
+	  if (m_hist_Hlt_truncated_result) {
+	    scoped_lock_histogram lock;
+	    m_hist_Hlt_truncated_result->Fill(3.);
+	  }
+	}
+      }
+    }
+  }
+
+  if (m_hist_eventAcceptFlags)
+    lock_histogram_operation<TH1F>(m_hist_eventAcceptFlags)->Fill(
+        static_cast<float>(m_mapAccept.codeToHash(hlt_decision)));
+
+  if(logLevel() <= MSG::DEBUG)
+  {
+    logStream() << MSG::DEBUG << ST_WHERE << "Decision = "
+                << hltonl::PrintHltAcceptFlag(hlt_decision) << "\n"
+                << hlt_result << endreq;
+    if(dobj)
+    {
+      const auto& extraData = dobj->getExtraData();
+      logStream() << MSG::DEBUG << ST_WHERE
+          << "HltResult extra data: Host name = " << extraData.appName
+          << ", status code = " << extraData.statusCode << endreq;
+    }
+  }
+
+  return ecode;
+} // end method HltEventLoopMgr::HltResultROBs
+
+//=========================================================================
+// HltResult()  ---> for "online" running
+//=========================================================================
+void HltEventLoopMgr::HltResult(hltinterface::HLTResult& hlt_result,
+                                const EventInfo* pEvent,
+                                const xAOD::EventInfo * xev)
+{
+  if ( logLevel() <= MSG::DEBUG ) {
+    logStream() << MSG::DEBUG << "---> HltResult() for " << name() << " called " << endreq;
+  }
+
+  using xev_stags_t = decltype(xev->streamTags());
+  auto xev_stags = xev ? xev->streamTags() : xev_stags_t{};
+
+  hltonl::PSCErrorCode hlt_psc_error = HltResultROBs(hlt_result,
+                         m_run_no, m_lvl1id, m_bunch_crossing_id,
+                         m_l1_Trigger_Type, m_l1_detev_type,
+                         pEvent->trigger_info()->eventFilterInfo(),
+                         pEvent->trigger_info()->streamTags(),
+                         xev_stags);
+  // If there was an error when building the HLT result ROB,
+  // put the event on the debug stream and try to create a dummy result ROB
+  if (hlt_psc_error) {
+    // put event on debug stream
+    addDebugStreamTag(hlt_result, m_HltDebugStreamName.value());
+    // make empty HLT result ROB
+    HltEmptyResultROB(hlt_result,hlt_psc_error);
+    // increase counter
+    m_invalid_hlt_result++;
+  }
+
+  return;
+} //  end method HltEventLoopMgr::HltResult
+
+//=========================================================================
+void HltEventLoopMgr::bookHistograms()
+{
+  if ( logLevel() <= MSG::DEBUG ) {
+    logStream() << MSG::DEBUG << "---> bookHistograms() for " << name()
+                    << " called. Do monitoring = " << m_doMonitoring.value() << endreq;
+  }
+
+  // return if no monitoring is requested
+  if ( !m_doMonitoring.value() ) { return; }
+
+  std::vector<TH1F**> regHistsTH1F;
+  regHistsTH1F.reserve(14);
+  std::vector<TProfile**> regHistsTProfile;
+  regHistsTProfile.reserve(4);
+
+  // monitoring information root directory
+  const std::string histPath = std::string("/EXPERT/") + getGaudiThreadGenericName(name()) + "/";
+
+  //     +--------------------+
+  // *-- | Event accept flags |
+  //     +--------------------+
+  uint32_t n_bins_eventAcceptFlags = hltonl::NUM_ACCEPTANCE_FLAGS;
+  m_hist_eventAcceptFlags    = new TH1F ("EventAcceptFlags",
+      "EventAcceptFlags;;entries", n_bins_eventAcceptFlags, 0.5, n_bins_eventAcceptFlags+0.5);
+
+  if (m_hist_eventAcceptFlags) {
+    for (hltonl::MapAcceptFlag::EnumMap::const_iterator map_it = m_mapAccept.begin(); map_it != m_mapAccept.end(); map_it++) {
+      m_hist_eventAcceptFlags->GetXaxis()->SetBinLabel( ((*map_it).second).second , (((*map_it).second).first).c_str() );
+    }
+    regHistsTH1F.push_back(&m_hist_eventAcceptFlags);
+  }
+
+  //     +-----------------------+
+  // *-- | HLT result properties |
+  //     +-----------------------+
+  // *-- HLT result size plot
+  m_hist_Hlt_result_size      = new TH1F ((m_histProp_Hlt_result_size.value().title()).c_str(),
+      (m_histProp_Hlt_result_size.value().title() + ";words;entries").c_str(),
+      m_histProp_Hlt_result_size.value().bins(),
+      m_histProp_Hlt_result_size.value().lowEdge(),
+      m_histProp_Hlt_result_size.value().highEdge());
+  if (m_hist_Hlt_result_size) {
+    CAN_REBIN(m_hist_Hlt_result_size);
+    regHistsTH1F.push_back(&m_hist_Hlt_result_size);
+  }
+
+  // *-- HLT result status codes
+  uint32_t n_bins_ResultStatus = hltonl::NUM_HLT_STATUS_CODES;
+  m_hist_Hlt_result_status =    new TH1F ("HltResultStatusCodes",
+      "HltResultStatusCodes;;entries", n_bins_ResultStatus, 0.5, n_bins_ResultStatus+0.5);
+
+  if (m_hist_Hlt_result_status) {
+    // do not print label for normal HLT result with no errors, it is not filled
+    for (hltonl::MapResultStatusCode::EnumMap::const_iterator map_it = m_mapResultStatus.begin(); map_it != m_mapResultStatus.end(); map_it++) {
+      if ( (*map_it).first == hltonl ::NORMAL_HLT_RESULT ) {
+        m_hist_Hlt_result_status->GetXaxis()->SetBinLabel( ((*map_it).second).second, (((*map_it).second).first+" (bin not filled)").c_str() );
+      } else {
+        m_hist_Hlt_result_status->GetXaxis()->SetBinLabel( ((*map_it).second).second, (((*map_it).second).first).c_str() );
+      }
+    }
+    regHistsTH1F.push_back(&m_hist_Hlt_result_status);
+  }
+
+  // *-- HLT result truncation
+  uint32_t n_bins_ResultTruncation = 3;
+  m_hist_Hlt_truncated_result =    new TH1F ("HltResultTruncation",
+      "HltResultTruncation;;entries", n_bins_ResultTruncation, 0.5, n_bins_ResultTruncation+0.5);
+
+  if (m_hist_Hlt_truncated_result) {
+    m_hist_Hlt_truncated_result->GetXaxis()->SetBinLabel( 1, std::string("Truncated HLT result").c_str() );
+    m_hist_Hlt_truncated_result->GetXaxis()->SetBinLabel( 2, std::string("Truncated HLT result (send to debug stream)").c_str() );
+    m_hist_Hlt_truncated_result->GetXaxis()->SetBinLabel( 3, std::string("Truncated HLT result (not send to debug stream)").c_str() );
+    regHistsTH1F.push_back(&m_hist_Hlt_truncated_result);
+  }
+
+  // *-- HLT result size plot (Stream Physiscs Main)
+  m_hist_Hlt_result_size_physics = new TH1F (((m_histProp_Hlt_result_size.value().title()) + "-(Stream (Main,physiscs))").c_str(),
+      (m_histProp_Hlt_result_size.value().title() + "-(StreamType Physiscs)" + ";words;entries").c_str(),
+      m_histProp_Hlt_result_size.value().bins(),
+      m_histProp_Hlt_result_size.value().lowEdge(),
+      m_histProp_Hlt_result_size.value().highEdge());
+  if (m_hist_Hlt_result_size_physics) {
+    CAN_REBIN(m_hist_Hlt_result_size_physics);
+    regHistsTH1F.push_back(&m_hist_Hlt_result_size_physics);
+  }
+
+  // *-- HLT result size plot (Stream Express)
+  m_hist_Hlt_result_size_express = new TH1F (((m_histProp_Hlt_result_size.value().title()) + "-(Stream (express,express))").c_str(),
+      (m_histProp_Hlt_result_size.value().title() + "-(StreamType Express)" + ";words;entries").c_str(),
+      m_histProp_Hlt_result_size.value().bins(),
+      m_histProp_Hlt_result_size.value().lowEdge(),
+      m_histProp_Hlt_result_size.value().highEdge());
+  if (m_hist_Hlt_result_size_express) {
+    CAN_REBIN(m_hist_Hlt_result_size_express);
+    regHistsTH1F.push_back(&m_hist_Hlt_result_size_express);
+  }
+
+  // *-- HLT result size plot (Stream calibration, DataScouting results)
+  m_hist_Hlt_result_size_DataScouting = new TH1F (((m_histProp_Hlt_result_size.value().title()) + "-(Streams (DataScouting_*,calibration))").c_str(),
+      (m_histProp_Hlt_result_size.value().title() + "-(StreamType Calibration, DataScouting)" + ";words;entries").c_str(),
+      m_histProp_Hlt_result_size.value().bins(),
+      m_histProp_Hlt_result_size.value().lowEdge(),
+      m_histProp_Hlt_result_size.value().highEdge());
+  if (m_hist_Hlt_result_size_DataScouting) {
+    CAN_REBIN(m_hist_Hlt_result_size_DataScouting);
+    regHistsTH1F.push_back(&m_hist_Hlt_result_size_DataScouting);
+  }
+
+  // *-- HLT result size profile plot for all stream types "physiscs"
+  m_hist_HltResultSizes_Stream_physics = new TProfile( std::string("Average Hlt Result size for physics streams").c_str(),
+						       std::string("Stream Name;;Average size in words").c_str(),
+						       1,
+						       (double) 0., (double) 1.,
+						       (double) 0., (double) 3000000.);
+  if (m_hist_HltResultSizes_Stream_physics) {
+    m_hist_HltResultSizes_Stream_physics->GetXaxis()->SetBinLabel(1,std::string("NoTag").c_str() );
+    CAN_REBIN(m_hist_HltResultSizes_Stream_physics);
+    regHistsTProfile.push_back(&m_hist_HltResultSizes_Stream_physics);
+  }
+
+  // *-- HLT result size profile plot for all stream names "DataScouting"
+  m_hist_HltResultSizes_Stream_DataScouting = new TProfile( std::string("Average Hlt Result size for data scouting streams").c_str(),
+						       std::string("Stream Name;;Average size in words").c_str(),
+						       1,
+						       (double) 0., (double) 1.,
+						       (double) 0., (double) 3000000.);
+  if (m_hist_HltResultSizes_Stream_DataScouting) {
+    m_hist_HltResultSizes_Stream_DataScouting->GetXaxis()->SetBinLabel(1,std::string("NoTag").c_str() );
+    CAN_REBIN(m_hist_HltResultSizes_Stream_DataScouting);
+    regHistsTProfile.push_back(&m_hist_HltResultSizes_Stream_DataScouting);
+  }
+
+  //     +-----------------------+
+  // *-- | framework error codes |
+  //     +-----------------------+
+  uint32_t n_bins_error = hltonl::NUM_PSC_ERROR_CODES;
+  m_hist_frameworkErrorCodes = new TH1F ("FrameworkErrorCodes",
+      "FrameworkErrorCodes;;entries", n_bins_error, 0.5, n_bins_error+0.5);
+
+  if (m_hist_frameworkErrorCodes) {
+    for (hltonl::MapPscErrorCode::EnumMap::const_iterator map_it = m_mapPscError.begin(); map_it != m_mapPscError.end(); map_it++) {
+      m_hist_frameworkErrorCodes->GetXaxis()->SetBinLabel( ((*map_it).second).second , (((*map_it).second).first).c_str() );
+    }
+    regHistsTH1F.push_back(&m_hist_frameworkErrorCodes);
+  }
+
+  //     +-------------+
+  // *-- | Stream Tags |
+  //     +-------------+
+  // *-- number of set stream tags
+  m_hist_numStreamTags       = new TH1F ((m_histProp_numStreamTags.value().title()).c_str(),
+      (m_histProp_numStreamTags.value().title() + ";tags;entries").c_str(),
+      m_histProp_numStreamTags.value().bins(),
+      m_histProp_numStreamTags.value().lowEdge(),
+      m_histProp_numStreamTags.value().highEdge());
+  if (m_hist_numStreamTags) {
+    CAN_REBIN(m_hist_numStreamTags);
+    regHistsTH1F.push_back(&m_hist_numStreamTags);
+  }
+
+  // *-- stream tag types
+  uint32_t n_bins_tag = eformat::helper::TagTypeDictionary.size() + 1;
+  m_hist_streamTagTypes      = new TH1F ("StreamTagTypes",
+      "StreamTagTypes;tags;entries", n_bins_tag, -0.5 , n_bins_tag-0.5);
+  if (m_hist_streamTagTypes) {
+    using eformat::helper::tagtype_to_string;
+    for(uint32_t i=0; i < n_bins_tag; i++ ) { // StreamTag labels
+      uint32_t bit = (1u << i);
+      m_hist_streamTagTypes->GetXaxis()->SetBinLabel( i+1, tagtype_to_string( static_cast<eformat::TagType>(bit) ).c_str() );
+    }
+    m_hist_streamTagTypes->GetXaxis()->SetBinLabel(n_bins_tag, "NoTag(=Rejected)");
+    regHistsTH1F.push_back(&m_hist_streamTagTypes);
+  }
+
+  // *-- stream tag names
+  m_hist_streamTagNames      = new TH1F ((m_histProp_streamTagNames.value().title()).c_str(),
+      (m_histProp_streamTagNames.value().title() + ";tags;entries").c_str(),
+      m_histProp_streamTagNames.value().bins(),
+      m_histProp_streamTagNames.value().lowEdge(),
+      m_histProp_streamTagNames.value().highEdge());
+  if (m_hist_streamTagNames) {
+    if (m_histProp_streamTagNames.value().bins()>0) m_hist_streamTagNames->GetXaxis()->SetBinLabel(1,std::string("NoTag").c_str() );
+    CAN_REBIN(m_hist_streamTagNames);
+    regHistsTH1F.push_back(&m_hist_streamTagNames);
+  }
+
+  //     +------------------------+
+  // *-- | Partial event building |
+  //     +------------------------+
+  // *-- number of bins for sub detector plots (55 SubDet max.)
+  uint32_t n_bins_partEBSubDet = eformat::helper::SubDetectorDictionary.size();
+
+  // *-- number of ROBs for partial event building
+  m_hist_num_partial_eb_robs = new TH1F ((m_histProp_num_partial_eb_robs.value().title()).c_str(),
+      (m_histProp_num_partial_eb_robs.value().title() + ";robs;entries").c_str(),
+      m_histProp_num_partial_eb_robs.value().bins(),
+      m_histProp_num_partial_eb_robs.value().lowEdge(),
+      m_histProp_num_partial_eb_robs.value().highEdge());
+  if (m_hist_num_partial_eb_robs) {
+    CAN_REBIN(m_hist_num_partial_eb_robs);
+    regHistsTH1F.push_back(&m_hist_num_partial_eb_robs);
+  }
+
+  // *-- number of SubDetectors used in partial event building
+  m_hist_num_partial_eb_SubDetectors = new TH1F ("NumberSubDetectorsPartialEB",
+      "NumberSubDetectorsPartialEB;subdet;entries",
+      n_bins_partEBSubDet,-0.5,(float) n_bins_partEBSubDet-0.5);
+  if (m_hist_num_partial_eb_SubDetectors) {
+    CAN_REBIN(m_hist_num_partial_eb_SubDetectors);
+    regHistsTH1F.push_back(&m_hist_num_partial_eb_SubDetectors);
+  }
+
+  // *-- SubDetectors used in partial event building: ROB list
+  m_hist_partial_eb_SubDetectors_ROBs = new TH1F ("SubDetectorsPartialEBFromROBList",
+      "SubDetectorsPartialEBFromROBList;;entries",
+      n_bins_partEBSubDet,0.,(float) n_bins_partEBSubDet);
+  if (m_hist_partial_eb_SubDetectors_ROBs) {
+    uint32_t n_tmp_bin = 1;
+    for (eformat::helper::EnumClass<eformat::SubDetector>::const_iterator it_sub=eformat::helper::SubDetectorDictionary.begin();
+        it_sub != eformat::helper::SubDetectorDictionary.end(); it_sub++ ) {
+      m_hist_partial_eb_SubDetectors_ROBs->GetXaxis()->SetBinLabel( n_tmp_bin, (it_sub->second).c_str() );
+      n_tmp_bin++;
+    }
+    CAN_REBIN(m_hist_partial_eb_SubDetectors_ROBs);
+    regHistsTH1F.push_back(&m_hist_partial_eb_SubDetectors_ROBs);
+  }
+
+  // *-- SubDetectors used in partial event building: SD list
+  m_hist_partial_eb_SubDetectors_SDs = new TH1F ("SubDetectorsPartialEBFromSDList",
+      "SubDetectorsPartialEBFromSDList;;entries",
+      n_bins_partEBSubDet,0.,(float) n_bins_partEBSubDet);
+  if (m_hist_partial_eb_SubDetectors_SDs) {
+    uint32_t n_tmp_bin = 1;
+    for (eformat::helper::EnumClass<eformat::SubDetector>::const_iterator it_sub=eformat::helper::SubDetectorDictionary.begin();
+        it_sub != eformat::helper::SubDetectorDictionary.end(); it_sub++ ) {
+      m_hist_partial_eb_SubDetectors_SDs->GetXaxis()->SetBinLabel( n_tmp_bin, (it_sub->second).c_str() );
+      n_tmp_bin++;
+    }
+    CAN_REBIN(m_hist_partial_eb_SubDetectors_SDs);
+    regHistsTH1F.push_back(&m_hist_partial_eb_SubDetectors_SDs);
+  }
+
+  //     +---------------+
+  // *-- | HLT EDM Sizes |
+  //     +---------------+
+  // *-- EDM sizes for all events without a truncated HLT result
+  m_hist_HltEdmSizes_No_Truncation = new TProfile( (m_histProp_Hlt_Edm_Sizes.value().title()+":Events_Without_Truncation").c_str(),
+      (m_histProp_Hlt_Edm_Sizes.value().title()+":Events_Without_Truncation;;Average size in words").c_str(),
+      m_histProp_Hlt_Edm_Sizes.value().bins(),
+      (double) 0., (double) m_histProp_Hlt_Edm_Sizes.value().bins(),
+      (double) m_histProp_Hlt_Edm_Sizes.value().lowEdge(),
+      (double) m_histProp_Hlt_Edm_Sizes.value().highEdge());
+  if (m_hist_HltEdmSizes_No_Truncation) {
+    uint32_t n_tmp_bin = 1;
+    for (std::vector<std::string>::const_iterator it_col_name = m_hltEdmCollectionNames.value().begin();
+        it_col_name != m_hltEdmCollectionNames.value().end(); it_col_name++ ) {
+      m_hist_HltEdmSizes_No_Truncation->GetXaxis()->SetBinLabel( n_tmp_bin, (*it_col_name).c_str() );
+      n_tmp_bin++;
+    }
+    //    m_hist_HltEdmSizes_No_Truncation->SetBit(TProfile::kCanRebin);
+    regHistsTProfile.push_back(&m_hist_HltEdmSizes_No_Truncation);
+  }
+  // *-- EDM sizes for all events with a truncated HLT result
+  m_hist_HltEdmSizes_With_Truncation = new TProfile( (m_histProp_Hlt_Edm_Sizes.value().title()+":Events_With_Truncation").c_str(),
+      (m_histProp_Hlt_Edm_Sizes.value().title()+":Events_With_Truncation;;Average size in words").c_str(),
+      m_histProp_Hlt_Edm_Sizes.value().bins(),
+      (double) 0., (double) m_histProp_Hlt_Edm_Sizes.value().bins(),
+      (double) m_histProp_Hlt_Edm_Sizes.value().lowEdge(),
+      (double) m_histProp_Hlt_Edm_Sizes.value().highEdge());
+  if (m_hist_HltEdmSizes_With_Truncation) {
+    uint32_t n_tmp_bin = 1;
+    for (std::vector<std::string>::const_iterator it_col_name = m_hltEdmCollectionNames.value().begin();
+        it_col_name != m_hltEdmCollectionNames.value().end(); it_col_name++ ) {
+      m_hist_HltEdmSizes_With_Truncation->GetXaxis()->SetBinLabel( n_tmp_bin, (*it_col_name).c_str() );
+      n_tmp_bin++;
+    }
+    //    m_hist_HltEdmSizes_With_Truncation->SetBit(TProfile::kCanRebin);
+    regHistsTProfile.push_back(&m_hist_HltEdmSizes_With_Truncation);
+  }
+  // *-- Sizes of collections which were retained for events with a truncated HLT result
+  m_hist_HltEdmSizes_TruncatedResult_Retained_Collections = new TProfile( "Events_With_HLTResult_Truncation:Size_of_Not_Truncated_Collections",
+      "Events_With_HLTResult_Truncation:Size_of_Not_Truncated_Collections;;Average size in words",
+      m_histProp_Hlt_Edm_Sizes.value().bins(),
+      (double) 0., (double) m_histProp_Hlt_Edm_Sizes.value().bins(),
+      (double) m_histProp_Hlt_Edm_Sizes.value().lowEdge(),
+      (double) m_histProp_Hlt_Edm_Sizes.value().highEdge());
+  if (m_hist_HltEdmSizes_TruncatedResult_Retained_Collections) {
+    uint32_t n_tmp_bin = 1;
+    for (std::vector<std::string>::const_iterator it_col_name = m_hltEdmCollectionNames.value().begin();
+        it_col_name != m_hltEdmCollectionNames.value().end(); it_col_name++ ) {
+      m_hist_HltEdmSizes_TruncatedResult_Retained_Collections->GetXaxis()->SetBinLabel( n_tmp_bin, (*it_col_name).c_str() );
+      n_tmp_bin++;
+    }
+    //    m_hist_HltEdmSizes_TruncatedResult_Retained_Collections->SetBit(TProfile::kCanRebin);
+    regHistsTProfile.push_back(&m_hist_HltEdmSizes_TruncatedResult_Retained_Collections);
+  }
+  // *-- Sizes of collections which were truncated for events with a truncated HLT result
+  m_hist_HltEdmSizes_TruncatedResult_Truncated_Collections = new TProfile( "Events_With_HLTResult_Truncation:Size_of_Truncated_Collections",
+      "Events_With_HLTResult_Truncation:Size_of_Truncated_Collections;;Average size in words",
+      m_histProp_Hlt_Edm_Sizes.value().bins(),
+      (double) 0., (double) m_histProp_Hlt_Edm_Sizes.value().bins(),
+      (double) m_histProp_Hlt_Edm_Sizes.value().lowEdge(),
+      (double) m_histProp_Hlt_Edm_Sizes.value().highEdge());
+  if (m_hist_HltEdmSizes_TruncatedResult_Truncated_Collections) {
+    uint32_t n_tmp_bin = 1;
+    for (std::vector<std::string>::const_iterator it_col_name = m_hltEdmCollectionNames.value().begin();
+        it_col_name != m_hltEdmCollectionNames.value().end(); it_col_name++ ) {
+      m_hist_HltEdmSizes_TruncatedResult_Truncated_Collections->GetXaxis()->SetBinLabel( n_tmp_bin, (*it_col_name).c_str() );
+      n_tmp_bin++;
+    }
+    //    m_hist_HltEdmSizes_TruncatedResult_Truncated_Collections->SetBit(TProfile::kCanRebin);
+    regHistsTProfile.push_back(&m_hist_HltEdmSizes_TruncatedResult_Truncated_Collections);
+  }
+  //     +---------------------+
+  // *-- | register histograms |
+  //     +---------------------+
+  // *-- TH1F
+  for (std::vector<TH1F**>::iterator it_hist=regHistsTH1F.begin(); it_hist != regHistsTH1F.end(); ++it_hist) {
+    if ( (*it_hist) && m_THistSvc->regHist(histPath + (**it_hist)->GetName(), (**it_hist)).isFailure() ) {
+      logStream() << MSG::WARNING << "Cannot register histogram " << (**it_hist)->GetName() << endreq;
+      delete (**it_hist);
+      **it_hist = 0;
+    }
+  }
+  // *-- TProfile
+  for (std::vector<TProfile**>::iterator it_hist=regHistsTProfile.begin(); it_hist != regHistsTProfile.end(); ++it_hist) {
+    if ( (**it_hist) && m_THistSvc->regHist(histPath + (**it_hist)->GetName(), (**it_hist)).isFailure() ) {
+      logStream() << MSG::WARNING << "Cannot register histogram " << (**it_hist)->GetName() << endreq;
+      delete (**it_hist);
+      **it_hist = 0;
+    }
+  }
+}
+
+//=========================================================================
+void HltEventLoopMgr::HltBookHistograms()
+{
+  if ( logLevel() <= MSG::DEBUG ) {
+    logStream() << MSG::DEBUG << "---> HltBookHistograms() for " << name()
+        << " called. Do monitoring = " << m_doMonitoring.value() << endreq;
+  }
+
+  // return if no monitoring is requested
+  if ( !m_doMonitoring.value() ) { return; }
+
+  // monitoring information root directory
+  std::string path = std::string("/EXPERT/")+getGaudiThreadGenericName(name())+"/";
+
+  // *-- SubDetectors from l1 ROBs
+  auto nbins = L1R_BINS.size() + 2;
+  m_hist_l1_robs = new TH1F ("HLTROBsReceivedFromL1",
+                             "HLTROBsReceivedFromL1;;entries",
+                             nbins,
+                             0.,
+                             static_cast<double>(nbins));
+
+  // Set labels from L1R_BINS
+  unsigned short i = 0;
+  while(i < L1R_BINS.size())
+  {
+    auto sid = eformat::helper::SourceIdentifier(L1R_BINS[i], 0);
+    m_hist_l1_robs->GetXaxis()->SetBinLabel(++i, sid.human_detector().c_str());
+  }
+
+  // Add a label for unexpected robs and another for missing CTP fragment
+  m_hist_l1_robs->GetXaxis()->SetBinLabel(++i, UNEXPECTED_L1R_ROB_LABEL);
+  m_hist_l1_robs->GetXaxis()->SetBinLabel(++i, MISSING_L1R_CTP_LABEL);
+
+  // Register it
+  if(m_THistSvc->regHist(path + m_hist_l1_robs->GetName(), m_hist_l1_robs).isFailure())
+  {
+    logStream() << MSG::WARNING << "Can not register monitoring histogram: "
+                << m_hist_l1_robs->GetName() << endreq;
+  }
+} //  end method HltEventLoopMgr::HltBookHistograms
+
+//=========================================================================
+void HltEventLoopMgr::fillHltResultHistograms(const hltinterface::HLTResult& hlt_result)
+{
+  if ( logLevel() <= MSG::DEBUG ) {
+    logStream() << MSG::DEBUG << "---> fillHltResultHistograms(hltinterface::HLTResult& hlt_result) for " << name() << " called " << endreq;
+  }
+
+  // return if no monitoring is requested
+  if ( !m_doMonitoring.value() ) { return; }
+
+  //     +-----------------------+
+  // *-- | HLT result properties |
+  //     +-----------------------+
+  if ( (hlt_result.fragment_pointer != 0) && ( (*hlt_result.fragment_pointer) != 0 ) ) {
+    eformat::ROBFragment<uint32_t*> hltrob(hlt_result.fragment_pointer);
+    uint16_t hltrob_moduleID = eformat::helper::SourceIdentifier( hltrob.rob_source_id() ).module_id();
+
+    // *-- HLT result size plots
+    if ((m_hist_Hlt_result_size) && (hltrob_moduleID == 0)) lock_histogram_operation<TH1F>(m_hist_Hlt_result_size)->Fill( (float) hltrob.fragment_size_word() ) ;
+
+    if ( (m_hist_Hlt_result_size_physics) || (m_hist_Hlt_result_size_express) || (m_hist_Hlt_result_size_DataScouting) ||
+	 (m_hist_HltResultSizes_Stream_physics) || (m_hist_HltResultSizes_Stream_DataScouting) ) {
+      scoped_lock_histogram lock;
+      for(std::vector<eformat::read::ROBFragment>::const_iterator it_rob = hlt_result.hltResult_robs.begin(); it_rob != hlt_result.hltResult_robs.end(); it_rob++) {
+	uint16_t moduleID = eformat::helper::SourceIdentifier( (*it_rob).rob_source_id() ).module_id();
+	for(std::vector<eformat::helper::StreamTag>::const_iterator it = hlt_result.stream_tag.begin(); it != hlt_result.stream_tag.end(); it++) {
+          // only normal HLT Results
+	  if (moduleID == 0) {
+	    if ((*it).type == "physics") {
+	      if (((*it).name == "Main") && (m_hist_Hlt_result_size_physics)) m_hist_Hlt_result_size_physics->Fill( (float) (*it_rob).fragment_size_word() ) ;
+	      if (m_hist_HltResultSizes_Stream_physics) m_hist_HltResultSizes_Stream_physics->Fill( ((*it).name).c_str(), (double) (*it_rob).fragment_size_word() ) ;
+	    }
+	    if ((*it).type == "express") {
+	      if (m_hist_Hlt_result_size_express) m_hist_Hlt_result_size_express->Fill( (float) (*it_rob).fragment_size_word() ) ;
+	    }
+	  }
+	  // DataScouting HLT ROBs
+	  if (moduleID != 0) {
+	    if (((*it).type == "calibration") && (((*it).name).find("DataScouting_") != std::string::npos)) {
+	      if (m_hist_Hlt_result_size_DataScouting) m_hist_Hlt_result_size_DataScouting->Fill( (float) (*it_rob).fragment_size_word() ) ;
+	      if (m_hist_HltResultSizes_Stream_DataScouting) m_hist_HltResultSizes_Stream_DataScouting->Fill( ((*it).name).c_str(), (double) (*it_rob).fragment_size_word() ) ;
+	    }
+	  }
+	}
+      }
+      // deflate bins for profile histograms
+      m_hist_HltResultSizes_Stream_physics->LabelsDeflate("X");
+      m_hist_HltResultSizes_Stream_DataScouting->LabelsDeflate("X");
+    }
+
+    // *-- HLT result status codes
+    if ((hltrob.nstatus() > 1) && (m_hist_Hlt_result_status) && (hltrob_moduleID == 0)) {
+      scoped_lock_histogram lock;
+      const uint32_t* it;
+      hltrob.status(it);
+      m_hist_Hlt_result_status->Fill( (float) m_mapResultStatus.codeToHash( (hltonl::ResultStatusCode) *(it+1)) );
+    }
+  }
+
+  //     +-----------------------+
+  // *-- | framework error codes |
+  //     +-----------------------+
+  if ((hlt_result.psc_errors.size() > 0) &&  (m_hist_frameworkErrorCodes))  {
+    scoped_lock_histogram lock;
+    for (std::vector<uint32_t>::const_iterator it=hlt_result.psc_errors.begin();it!=hlt_result.psc_errors.end();it++) {
+      m_hist_frameworkErrorCodes->Fill( (float) m_mapPscError.codeToHash( (hltonl::PSCErrorCode) (*it)) );
+    }
+  }
+
+  //     +-------------+
+  // *-- | Stream Tags |
+  //     +-------------+
+  //     number of set stream tags
+  if (m_hist_numStreamTags) lock_histogram_operation<TH1F>(m_hist_numStreamTags)->Fill( (float) hlt_result.stream_tag.size() );
+
+  //     stream tag types
+  if (m_hist_streamTagTypes) {
+    scoped_lock_histogram lock;
+    if(hlt_result.stream_tag.empty())
+      m_hist_streamTagTypes->Fill( (float) m_hist_streamTagTypes->GetXaxis()->GetNbins() - 1. );
+    using namespace eformat::helper;
+    for(int32_t i=0; i < m_hist_streamTagTypes->GetXaxis()->GetNbins(); i++) {
+      uint32_t bit = (1u<<i);
+      if( contains_type(hlt_result.stream_tag, static_cast<eformat::TagType>(bit)) ) {
+        m_hist_streamTagTypes->Fill( (float) i);
+      }
+    }
+  }
+
+  //     stream tag names
+  if (m_hist_streamTagNames) {
+    scoped_lock_histogram lock;
+    if(hlt_result.stream_tag.empty()) {
+      m_hist_streamTagNames->Fill(0.);
+    } else {
+      for(std::vector<eformat::helper::StreamTag>::const_iterator it = hlt_result.stream_tag.begin(); it != hlt_result.stream_tag.end(); it++) {
+        m_hist_streamTagNames->Fill((*it).name.c_str(),1.);
+      }
+    }
+    m_hist_streamTagNames->LabelsDeflate("X");
+  }
+
+  //     +------------------------+
+  // *-- | Partial Event Building |
+  //     +------------------------+
+  // *-- loop over stream tags and get total number of ROBs and SDs
+  uint32_t num_robs(0), num_sd(0);
+  std::set<uint32_t> peb_robs;
+  std::set<eformat::SubDetector> peb_sd;
+  for(std::vector<eformat::helper::StreamTag>::const_iterator it = hlt_result.stream_tag.begin(); it != hlt_result.stream_tag.end(); it++) {
+    num_robs = num_robs + (it->robs).size();
+    num_sd = num_sd + (it->dets).size();
+    peb_robs.insert( (it->robs).begin(),(it->robs).end() );
+    peb_sd.insert(   (it->dets).begin(),(it->dets).end() );
+  }
+
+  // *-- number of ROBs for partial event building
+  if (m_hist_num_partial_eb_robs) lock_histogram_operation<TH1F>(m_hist_num_partial_eb_robs)->Fill( (float) num_robs);
+
+  // *-- number of SubDetectors for partial event building
+  if (m_hist_num_partial_eb_SubDetectors) lock_histogram_operation<TH1F>(m_hist_num_partial_eb_SubDetectors)->Fill( (float) num_sd);
+
+  // *-- SubDetectors for partial event building in ROB list
+  if (m_hist_partial_eb_SubDetectors_ROBs) {
+    scoped_lock_histogram lock;
+    for(std::set<uint32_t>::const_iterator it = peb_robs.begin(); it != peb_robs.end(); it++) {
+      m_hist_partial_eb_SubDetectors_ROBs->Fill(eformat::helper::SourceIdentifier(*it).human_detector().c_str(),1.);
+      m_hist_partial_eb_SubDetectors_ROBs->LabelsDeflate("X");
+    }
+  }
+
+  // *-- SubDetectors for partial event building in SD list
+  if (m_hist_partial_eb_SubDetectors_SDs) {
+    scoped_lock_histogram lock;
+    for(std::set<eformat::SubDetector>::const_iterator it = peb_sd.begin(); it != peb_sd.end(); it++) {
+      m_hist_partial_eb_SubDetectors_SDs->Fill(eformat::helper::SourceIdentifier(*it,0).human_detector().c_str(),1.);
+      m_hist_partial_eb_SubDetectors_SDs->LabelsDeflate("X");
+    }
+  }
+
+  return;
+} // end method HltEventLoopMgr::fillHltResultHistograms
+
+//=========================================================================
+void HltEventLoopMgr::bookAllHistograms()
+{
+  // Book the monitoring histograms
+  HltBookHistograms(); // (histograms that were booked differently in l2/ef)
+  // Book own histograms
+  bookHistograms();
+}
+
+//=========================================================================
+StatusCode
+HltEventLoopMgr::callOnAlgs(const function<StatusCode(IAlgorithm&)> & func,
+                            const string & fname, bool failureIsError)
+{
+  logStream() << MSG::DEBUG << ST_WHERE
+              << "calling " << fname << "() on all algorithms" << endreq;
+
+  StatusCode sc;
+  for(auto alg : m_topAlgList)
+  {
+    if(func(*alg).isFailure())
+    {
+      logStream() << (failureIsError ? MSG::ERROR : MSG::WARNING) << ST_WHERE
+                  << "Calling " << fname << "() on algorithm " << alg->name()
+                  << " failed" << endreq;
+      sc = StatusCode::FAILURE;
+      if(failureIsError)
+        break;
+    }
+  }
+
+  return sc;
+}
+
+//=========================================================================
+StatusCode HltEventLoopMgr::prepareAlgs(const EventInfo& evinfo)
+{
+  auto suc1 = callOnAlgs(&IAlgorithm::sysStart, "sysStart").isSuccess();
+  m_incidentSvc->fireIncident(EventIncident(evinfo, name(),
+                                            IncidentType::BeginRun));
+  auto suc2 = callOnAlgs(&IAlgorithm::sysBeginRun, "sysBeginRun").isSuccess();
+  m_incidentSvc->fireIncident(EventIncident(evinfo, name(), "EndOfBeginRun"));
+
+  return (suc1 && suc2) ? StatusCode::SUCCESS : StatusCode::FAILURE;
+}
+
+//=========================================================================
+StatusCode HltEventLoopMgr::internalPrepareResets()
+{
+  m_currentEvent = nullptr; // no time out would make sense here, so not locking
+  m_currentLB = 0;
+  if (m_predefinedLumiBlock > 0)
+  {
+    m_currentLB = m_predefinedLumiBlock;
+    logStream() << MSG::DEBUG << ST_WHERE
+                << "Using predefined lumi block " << m_currentLB << endreq;
+  }
+
+  // The real CTP counter only has 16 bits and never reaches this value
+  m_l1_hltPrescaleUpdateLB = 0xffffffff;
+
+  return clearTemporaryStores();
+}
+
+//=========================================================================
+const SOR * HltEventLoopMgr::processRunParams(const ptree & pt)
+{
+  // update the run number
+  m_currentRun = pt.get<uint32_t>("RunParams.run_number");
+
+  // Fill SOR parameters from the ptree
+  TrigSORFromPtreeHelper sorhelp{logStream()};
+  auto sor = sorhelp.fillSOR(pt.get_child("RunParams"));
+  if(!sor)
+    logStream() << MSG::ERROR << ST_WHERE
+                << "setup of SOR from ptree failed" << endreq;
+
+  return sor;
+}
+
+//=========================================================================
+void HltEventLoopMgr::updInternal(const coral::AttributeList & sor_attrlist)
+{
+  auto detMaskFst = sor_attrlist["DetectorMaskFst"].data<unsigned long long>();
+  auto detMaskSnd = sor_attrlist["DetectorMaskSnd"].data<unsigned long long>();
+  updDetMask({detMaskFst, detMaskSnd});
+
+  auto sorTime = sor_attrlist["SORTime"].data<unsigned long long>();
+  updSorTime(sorTime);
+
+  if(logLevel() <= MSG::DEBUG)
+  {
+    // save current stream flags for later reset
+    // cast needed (stream thing returns long, but doesn't take it back)
+    auto previous_stream_flags =
+        static_cast<std::ios::fmtflags>(logStream().flags());
+    logStream() << MSG::DEBUG << ST_WHERE
+                << "Full detector mask (128 bits) = 0x"
+                << MSG::hex << std::setfill('0')
+                << std::setw(8) << std::get<3>(m_detector_mask)
+                << std::setw(8) << std::get<2>(m_detector_mask)
+                << std::setw(8) << std::get<1>(m_detector_mask)
+                << std::setw(8) << std::get<0>(m_detector_mask) << endreq;
+    logStream().flags(previous_stream_flags);
+
+    logStream() << MSG::DEBUG << ST_WHERE
+                << "sorTimeStamp[0] [sec] = " << m_sorTime_stamp[0] << endreq;
+    logStream() << MSG::DEBUG << ST_WHERE
+                << "sorTimeStamp[1] [ns]  = " << m_sorTime_stamp[1] << endreq;
+  }
+}
+
+//=========================================================================
+void HltEventLoopMgr::updMetadaStore(const coral::AttributeList & sor_attrlist)
+{
+  // least significant part is "snd" in sor but "fst" for ByteStreamMetadata
+  auto bs_dm_fst = sor_attrlist["DetectorMaskSnd"].data<unsigned long long>();
+  // most significant part is "fst" in sor but "snd" for ByteStreamMetadata
+  auto bs_dm_snd = sor_attrlist["DetectorMaskFst"].data<unsigned long long>();
+
+  auto metadata = new ByteStreamMetadata(
+    sor_attrlist["RunNumber"].data<unsigned int>(),
+    0,
+    0,
+    sor_attrlist["RecordingEnabled"].data<bool>(),
+    0,
+    bs_dm_fst,
+    bs_dm_snd,
+    0,
+    0,
+    "",
+    "",
+    "",
+    0,
+    std::vector<std::string>());
+
+  // Record ByteStreamMetadata in MetaData Store
+  if(m_inputMetaDataStore->record(metadata,"ByteStreamMetadata").isFailure())
+  {
+    logStream() << MSG::WARNING << ST_WHERE
+                << "Unable to record MetaData in InputMetaDataStore."
+                << endreq;
+    delete metadata;
+  }
+  else
+    logStream() << MSG::DEBUG << ST_WHERE
+                << "Recorded MetaData in InputMetaDataStore." << endreq;
+}
+
+//=========================================================================
+StatusCode HltEventLoopMgr::clearTemporaryStores()
+{
+  //-----------------------------------------------------------------------
+  // Clear the event store, if used in the event loop
+  //-----------------------------------------------------------------------
+  auto sc = m_evtStore->clearStore();
+  logStream() << MSG::DEBUG << ST_WHERE
+              << "clear of Event Store " << sc << endreq;
+  if(sc.isFailure()) {
+    logStream() << MSG::ERROR << ST_WHERE
+                << "clear of Event Store failed" << endreq;
+    return sc;
+  }
+
+  //-----------------------------------------------------------------------
+  // Clear the InputMetaDataStore
+  //-----------------------------------------------------------------------
+  sc = m_inputMetaDataStore->clearStore();
+  logStream() << MSG::DEBUG << ST_WHERE
+              << "clear of InputMetaDataStore store " << sc << endreq;
+  if(sc.isFailure())
+    logStream() << MSG::ERROR << ST_WHERE
+                << "clear of InputMetaDataStore failed" << endreq;
+
+  return sc;
+}
+
+//=========================================================================
+void HltEventLoopMgr::updDetMask(const std::pair<uint64_t, uint64_t>& dm)
+{
+  m_detector_mask = std::make_tuple(
+                        // least significant 4 bytes
+                        static_cast<EventID::number_type>(dm.second),
+                        // next least significant 4 bytes
+                        static_cast<EventID::number_type>(dm.second >> 32),
+                        // next least significant 4 bytes
+                        static_cast<EventID::number_type>(dm.first),
+                        // most significant 4 bytes
+                        static_cast<EventID::number_type>(dm.first >> 32));
+}
+
+//=========================================================================
+void HltEventLoopMgr::updSorTime(unsigned long long st)
+{
+  m_sorTime_stamp[0]=0;
+  m_sorTime_stamp[1]=0;
+  if(st)
+  {
+    m_sorTime_stamp[0] = (unsigned int)(st/1000000000);
+    m_sorTime_stamp[1] = (unsigned int)(st-m_sorTime_stamp[0]*1000000000);
+  }
+}
+
+namespace
+{
+  // Helper to print SOR record
+  void printSORAttrList(const coral::AttributeList& atr,
+                        MsgStream& log, const MSG::Level& lvl)
+  {
+    unsigned long long sorTime_ns(atr["SORTime"].data<unsigned long long>());
+
+    // Human readable format of SOR time if available
+    time_t sorTime_sec = sorTime_ns/1000000000;
+    const auto sorTime_readable = OWLTime(sorTime_sec);
+
+    log << lvl << "SOR parameters:" << endreq;
+    log << "   RunNumber        = "
+        << atr["RunNumber"].data<unsigned int>() << endreq;
+    log << "   SORTime [ns]     = "
+        << sorTime_ns << " (" << sorTime_readable << ") " << endreq;
+
+    // save current stream flags for later reset
+    // cast needed (stream thing returns long, but doesn't take it back)
+    auto previous_stream_flags = static_cast<std::ios::fmtflags>(log.flags());
+    auto dmfst = atr["DetectorMaskFst"].data<unsigned long long>();
+    auto dmsnd = atr["DetectorMaskSnd"].data<unsigned long long>();
+    log << MSG::hex << std::setfill('0');
+    log << "   DetectorMaskFst     = 0x" << std::setw(16) << dmfst << endreq;
+    log << "   DetectorMaskSnd     = 0x" << std::setw(16) << dmsnd << endreq;
+    log << "   (complete DetectorMask = 0x"
+        << std::setw(16) << dmfst << std::setw(16) << dmsnd << ")" << endreq;
+    // reset stream flags
+    log.flags(previous_stream_flags);
+
+    log << "   RunType          = "
+        << atr["RunType"].data<std::string>() << endreq;
+    log << "   RecordingEnabled = "
+        << (atr["RecordingEnabled"].data<bool>() ? "true" : "false") << endreq;
+  }
+}
+
+//=========================================================================
+const coral::AttributeList &
+HltEventLoopMgr::getSorAttrList(const SOR * sor) const
+{
+  if(sor->size() != 1)
+  {
+    // This branch should never be entered (the CondAttrListCollection
+    //corresponding to the SOR should contain one single AttrList). Since
+    //that's required by code ahead but not checked at compile time, we
+    //explicitly guard against any potential future mistake with this check
+    logStream() << MSG::ERROR << ST_WHERE
+                << "Wrong SOR: size = " << sor->size() << endreq;
+    throw std::runtime_error("SOR record should have one and one only attribute"
+                             " list, but it has " + sor->size());
+  }
+
+  const auto & soral = sor->begin()->second;
+  printSORAttrList(soral, logStream(), MSG::INFO);
+  return soral;
+}
+
+//=========================================================================
+StatusCode HltEventLoopMgr::updHLTConfigSvc()
+{
+  // Get HLTConfigSvc if available and do sanity check
+  service("TrigConf::HLTConfigSvc/HLTConfigSvc",
+          m_hltConfigSvc, /*createIf=*/false).ignore();
+
+  if ( (m_hltConfigSvc==0) && (m_jobOptionsType.value()=="DB") ) {
+    logStream() << MSG::ERROR << ST_WHERE
+                << "JobOptionsType==DB but could not retrieve HLTConfigSvc"
+                << endreq;
+    return StatusCode::FAILURE;
+  }
+
+  return StatusCode::SUCCESS;
+}
+
+//=========================================================================
+const EventInfo * HltEventLoopMgr::prepEventInfo() const
+{
+  const EventInfo * pEvent =
+      new EventInfo(new EventID(m_currentRun,
+                                0,
+                                m_sorTime_stamp[0],
+                                m_sorTime_stamp[1],
+                                m_currentLB,
+                                0,
+                                std::get<0>(m_detector_mask),
+                                std::get<1>(m_detector_mask),
+                                std::get<2>(m_detector_mask),
+                                std::get<3>(m_detector_mask)),
+                    new EventType());
+
+  // Record it in StoreGate
+  if(m_evtStore->record(pEvent,"EventInfo").isFailure())
+  {
+    logStream() << MSG::ERROR << ST_WHERE
+                << "Could not record EventInfo object" << endreq;
+    return nullptr;
+  }
+
+  logStream() << MSG::DEBUG << ST_WHERE
+              << "Recorded EventInfo object: "
+              << *pEvent->event_ID() << endreq;
+
+  return pEvent;
+}
+
+//=========================================================================
+StatusCode HltEventLoopMgr::prepXAODEventInfo() const
+{
+  auto aux = new xAOD::EventAuxInfo;
+  auto ev = new xAOD::EventInfo;
+  ev->setStore(aux);
+  ev->setRunNumber(m_currentRun);
+  ev->setEventNumber(0);
+  ev->setLumiBlock(m_currentLB);
+  ev->setTimeStamp(m_sorTime_stamp[0]);
+  ev->setTimeStampNSOffset(m_sorTime_stamp[1]);
+  ev->setBCID(0);
+  ev->setDetectorMask0(std::get<0>(m_detector_mask));
+  ev->setDetectorMask1(std::get<1>(m_detector_mask));
+  ev->setDetectorMask2(std::get<2>(m_detector_mask));
+  ev->setDetectorMask3(std::get<3>(m_detector_mask));
+
+  // Record it in StoreGate
+  if(m_evtStore->record(aux, "EventInfoAux.").isFailure() ||
+     m_evtStore->record(ev, "EventInfo").isFailure())
+  {
+    logStream() << MSG::ERROR << ST_WHERE
+                << "Could not record xAOD::EventInfo object" << endreq;
+
+    return StatusCode::FAILURE;
+  }
+
+  logStream() << MSG::DEBUG << ST_WHERE
+              << "Recorded xAOD::EventInfo object: "
+              << *ev << endreq;
+
+  return StatusCode::SUCCESS;
+}
+
+//=========================================================================
+StatusCode HltEventLoopMgr::updMagField(const ptree& pt) const
+{
+  if(m_setMagFieldFromPtree && validPartition())
+  {
+    try
+    {
+      auto tor_cur = pt.get<float>("Magnets.ToroidsCurrent.value");
+      auto sol_cur = pt.get<float>("Magnets.SolenoidCurrent.value");
+
+      IProperty* magfsvc(0);
+      service("AtlasFieldSvc", magfsvc, /*createIf=*/false).ignore();
+      if ( magfsvc==0 ) {
+        logStream() << MSG::ERROR << ST_WHERE
+                    << "Cannot retrieve AtlasFieldSvc" << endreq;
+        return StatusCode::FAILURE;
+      }
+
+      auto sc = Gaudi::Utils::setProperty(magfsvc, "UseSoleCurrent", sol_cur);
+      if ( sc.isFailure() ) {
+        logStream() << MSG::ERROR << ST_WHERE
+                    << "Cannot set property AtlasFieldSvc.UseSoleCurrent"
+                    << endreq;
+        return StatusCode::FAILURE;
+      }
+
+      sc = Gaudi::Utils::setProperty(magfsvc, "UseToroCurrent", tor_cur);
+      if ( sc.isFailure() ) {
+        logStream() << MSG::ERROR << ST_WHERE
+                    << "Cannot set property AtlasFieldSvc.UseToroCurrent"
+                    << endreq;
+        return StatusCode::FAILURE;
+      }
+
+      logStream() << MSG::INFO << "*****************************************" << endreq;
+      logStream() << MSG::INFO << "  Auto-configuration of magnetic field:  " << endreq;
+      logStream() << MSG::INFO << "    solenoid current from IS = " << sol_cur << endreq;
+      logStream() << MSG::INFO << "     torroid current from IS = " << tor_cur << endreq;
+      logStream() << MSG::INFO << "*****************************************" << endreq;
+    }
+    catch(ptree_bad_path& e)
+    {
+      logStream() << MSG::ERROR << ST_WHERE
+                  << "Magnet auto-configuration failed: " << e.what() << endreq;
+      return StatusCode::FAILURE;
+    }
+  }
+  else
+  {
+    logStream() << MSG::DEBUG << ST_WHERE
+                << "Magnetic fields not available" << endreq;
+  }
+
+  return StatusCode::SUCCESS;
+}
+
+//=========================================================================
+StatusCode HltEventLoopMgr::resetCoolValidity()
+{
+  if ( m_coolHelper->resetBeginRunFolders(m_currentRun).isFailure() ) {
+    logStream() << MSG::ERROR << ST_WHERE
+                << "Reset of at least one proxy failed" << endreq;
+    return StatusCode::FAILURE;
+  }
+
+  return StatusCode::SUCCESS;
+}
+
+//=========================================================================
+void HltEventLoopMgr::readyMsg() const
+{
+  if (logLevel() <= MSG::INFO)
+  {
+    LumiBlock lb;
+    lb.LumiBlockNumber = 0;
+    if(validPartition() &&
+       m_isHelper->findValue(TrigISHelper::LumiBlock, lb).isFailure())
+    { // Lumiblock only used for information. Do not make this a failure.
+      logStream() << MSG::WARNING << ST_WHERE
+                  << "Cannot read lumiblock number from IS" << endreq;
+    }
+
+    const auto& ilbn = lb.LumiBlockNumber;
+    logStream() << MSG::INFO  << ST_WHERE
+                << "Ready to start event processing. Run = "
+                <<  m_currentRun << " (LB = "
+                << (ilbn ? boost::lexical_cast<string>(ilbn) : string{"??"})
+                << ")" << endreq;
+  }
+}
+
+//=========================================================================
+void HltEventLoopMgr::
+setStreamTags(hltinterface::HLTResult& hltr,
+              const std::vector<TriggerInfo::StreamTag>& stream_tags) const
+{
+  hltr.stream_tag.reserve(stream_tags.size());
+  for(const auto& st : stream_tags)
+  {
+    // get robs, filtering disabled ones
+    auto robs = filterRobs(st.robs());
+    // get subdetectors, filtering disabled ones
+    auto dets = filterDets(st.dets());
+
+    hltr.stream_tag.emplace_back(st.name(), st.type(), st.obeysLumiblock(),
+                                 robs, dets);
+  }
+}
+
+//=========================================================================
+void HltEventLoopMgr::
+mergeStreamTags(hltinterface::HLTResult& hltr,
+                const std::vector<xAOD::EventInfo::StreamTag>& xsts) const
+{
+  auto& stags = hltr.stream_tag;
+  for(const auto& st : xsts)
+  {
+    // get robs, filtering disabled ones
+    auto robs = filterRobs(st.robs());
+    // get subdetectors, filtering disabled ones
+    auto dets = filterDets(st.dets());
+
+    // is there already a tag with the same type, name and obeysLumi flag?
+    auto it = find_if(begin(stags), end(stags),
+                      [&st](const eformat::helper::StreamTag& current){
+      return current.name == st.name() &&
+             current.type == st.type() &&
+             current.obeys_lumiblock == st.obeysLumiblock();
+    });
+
+    if(it != stags.end()) // if so, unite robs and dets
+    {
+      it->robs.insert(begin(robs), end(robs));
+      it->dets.insert(begin(dets), end(dets));
+    }
+    else // otherwise, add the tag
+      stags.emplace_back(st.name(), st.type(), st.obeysLumiblock(), robs, dets);
+  }
+}
+
+//=========================================================================
+hltonl::AcceptFlag
+HltEventLoopMgr::processHltDecision(hltinterface::HLTResult& hltr) const
+{
+  if(m_forceHltAccept)
+  {
+    // we force accept independently of what the Steering decided for the event
+    addDebugStreamTag(hltr, m_HltForcedStreamName.value());
+    return hltonl::PSC_FORCED_ACCEPT;
+  }
+
+  return hltr.stream_tag.size() ? hltonl::STEERING_ACCEPT
+                                : hltonl::STEERING_REJECT;
+}
+
+//=========================================================================
+hltonl::PSCErrorCode
+HltEventLoopMgr::serializeRobs(hltinterface::HLTResult& hltr, bool& serOk,
+                               HLT::HLTResult* dobj, uint32_t rn, uint32_t l1id,
+                               uint32_t bcid, uint32_t l1tt, uint32_t dett)
+{
+  auto fp = hltr.fragment_pointer;
+  auto spaceleft = hltr.max_result_size;
+  
+  // obtain the module ids that need serialization
+  auto modids = dobj->listOfModIDs(); // hope for copy ellision
+
+  if(find(begin(modids), end(modids), 0) == end(modids))
+  {
+    const auto& sts = hltr.stream_tag;
+    using ST = decltype(sts[0]);
+    auto pred = [](const ST& st){ return st.type == "debug"; };
+
+    if (m_forceHltAccept ||
+        find_if(begin(sts), end(sts), pred) != end(sts))
+    {
+      modids.push_back(0);
+    }
+  }
+
+  // loop over module ids and build a rob for each one
+  for(const auto& modid : modids)
+  {
+    // Initialize a ROB
+    auto robp = initRob(modid, rn, l1id, bcid, l1tt, dett, m_status_words);
+    auto initial_robsize = robp->size_word() + INITIAL_ROB_SIZE_MARGIN;
+    if(!checkRobSize(initial_robsize, spaceleft, hltr.max_result_size))
+      return hltonl::PSC_ERROR_ROB_BUILD_FAILED;
+    
+    // serialize data and fill rob up
+    uint32_t* tmp{nullptr};
+    serOk &= serializeRob(tmp, *robp, *dobj, modid,
+                          spaceleft - initial_robsize);
+
+    // Hold this until we've copied it into the HLTResult
+    auto tmpstor = std::unique_ptr<uint32_t[]>{tmp};
+
+    // copy it in and delete temporary data, updating spaceleft
+    addRobToHLTResult(hltr, *robp, fp, spaceleft);
+  }
+
+  return hltonl::PSC_ERROR_UNCLASSIFIED;
+}
+
+//=========================================================================
+bool HltEventLoopMgr::serializeRob(uint32_t*& tmpstor,
+                                   eformat::write::ROBFragment& rob,
+                                   HLT::HLTResult& dobj,
+                                   unsigned int modid,
+                                   int payload_max)
+{
+  // find the remaining space for this rob's payload
+  int payload = 0;
+
+  // serialize current rob
+  auto ret = dobj.serialize(tmpstor, payload, payload_max, modid);
+
+  if(payload > payload_max)
+  {
+    logStream() << MSG::ERROR << ST_WHERE
+                << "Serialized ROB's size (" << payload << ") is bigger "
+                   "than max allowed size (" << payload_max << ")"
+                << endreq;
+
+    payload = payload_max;
+    ret = false;
+  }
+
+  if(!ret) // otherwise, it's already correct
+  {
+    m_status_words[0] = SW_TRUNCATION.code();
+    m_status_words[1] = hltonl::NORMAL_HLT_RESULT_TRUNCATED;
+    rob.status(2, m_status_words);
+    rob.rod_status(2, m_status_words);
+  }
+
+  rob.rod_data(payload, tmpstor);
+
+  return ret;
+}
+
+//=========================================================================
+void HltEventLoopMgr::addRobToHLTResult(hltinterface::HLTResult& hltr,
+                                        eformat::write::ROBFragment& rob,
+                                        uint32_t*& next_fragment, // don't pass original fragment pointer!
+                                        uint32_t& spaceleft)
+{
+  // Store the HLT ROB fragment in the HLT result
+  // (Maximum possible space is already allocated by the HLTMPPU)
+  auto copied = eformat::write::copy(*rob.bind(), next_fragment, rob.size_word());
+  hltr.hltResult_robs.emplace_back(next_fragment);
+
+  next_fragment += copied;
+  spaceleft -= copied;
+
+  if(copied == 0 || copied != rob.size_word())  {
+    logStream() << MSG::ERROR
+                << "Memory copy operation for HLT result ROB failed. "
+                   "Returned number of copied words = " << copied
+                << ". Number of words in ROB which should be copied = "
+                << rob.size_word() << "." << endreq;
+  }
+}
+
+//=========================================================================
+void HltEventLoopMgr::recordEDMSizeInfo(size_t nav_size,
+                                        bool serializationOk) const
+{
+  const HLT::TrigEDMSizes* dobjNavSizes(0);
+
+  if (m_evtStore->transientContains<HLT::TrigEDMSizes>("TrigEDMSizes")) {
+    if ( m_evtStore->retrieve(dobjNavSizes).isSuccess() ) {
+      for(const auto& navSizeInfo : dobjNavSizes->info())
+      {
+        std::string colname(navSizeInfo.collection+"__"+navSizeInfo.label);
+        // Protection for invalid collection names in TProfile
+        // (avoid bug in TProfile memory alloc)
+        auto it_col_name = std::find(m_hltEdmCollectionNames.value().begin(),
+                                     m_hltEdmCollectionNames.value().end(),
+                                     colname);
+        if(it_col_name == m_hltEdmCollectionNames.value().end())
+        {
+          if ( logLevel() <= MSG::DEBUG )
+            logStream() << MSG::DEBUG << "EDM collection name = " << colname
+                        << " is not in the configured list of EDM collections."
+                        << endreq;
+
+          colname=m_hltEdmCollectionNames.value().back();
+        }
+
+        auto * edmhist = serializationOk ? m_hist_HltEdmSizes_No_Truncation
+                                         : m_hist_HltEdmSizes_With_Truncation;
+        fillEdmHist(edmhist, colname, navSizeInfo);
+
+        if(!serializationOk)
+        {
+          edmhist = navSizeInfo.isTruncated(nav_size) ?
+              m_hist_HltEdmSizes_TruncatedResult_Truncated_Collections :
+              m_hist_HltEdmSizes_TruncatedResult_Retained_Collections;
+          fillEdmHist(edmhist, colname, navSizeInfo);
+        }
+      }
+    }
+    else
+      logStream() << MSG::WARNING << "cannot access EDM sizes information"
+                  << endreq;
+  }
+}
+
+//=========================================================================
+bool HltEventLoopMgr::checkRobSize(uint32_t robsize, uint32_t spaceleft,
+                                   uint32_t maxsize)
+{
+  if(spaceleft <= robsize)
+  {
+    logStream() << MSG::ERROR << ST_WHERE
+                << "Can not create HLT result ROB with available ROB "
+                   "buffer size ! Total available buffer size = "
+                << maxsize << "; buffer size left = " << spaceleft
+                << "; Number of header words used by empty ROB = "
+                << robsize << endreq;
+
+    return false;
+  }
+
+  return true;
+}
+
+//=========================================================================
+bool HltEventLoopMgr::
+checkEventIdConsistency(const hltinterface::EventId& evId) const
+{
+  if(evId.l1Id != m_lvl1id || evId.lbNumber != m_lumi_block)
+  {
+    logStream() << MSG::WARNING << ST_WHERE
+                << "EventId information does not match CTP fragment contents: "
+                << "EventId = {globalId: " << evId.globalId << ", l1Id: "
+                << evId.l1Id << ", lbNumber: " << evId.lbNumber
+                << "}, but the CTP fragment included l1Id = " << m_lvl1id
+                << " and lumiblock = " << m_lumi_block << "." << endreq;
+    return false;
+  }
+
+  return true;
+}
+
+//=========================================================================
+void HltEventLoopMgr::failedEvent(hltinterface::HLTResult& hlt_result,
+                                  hltonl::PSCErrorCode ecode,
+                                  const std::string& emsg,
+                                  bool empty_result)
+{
+  m_failed_evt++;
+
+  addDebugStreamTag(hlt_result, m_HltDebugStreamName.value());
+  if(empty_result)
+  {
+    HltEmptyResultROB(hlt_result, ecode);
+    fillHltResultHistograms(hlt_result);
+  }
+
+  logStream() << MSG::ERROR << ST_WHERE
+              << emsg << " PSC error code = "
+              << hltonl::PrintPscErrorCode(ecode)
+              << "\n" << hlt_result << "\n" << endreq;
+}
+
+//=========================================================================
+std::vector<uint32_t> HltEventLoopMgr::
+missingL1Robs(const std::vector<eformat::ROBFragment<const uint32_t*>>& l1r)
+const
+{
+  using eformat::helper::SourceIdentifier;
+  using ROB = eformat::ROBFragment<const uint32_t*>;
+
+  std::vector<uint32_t> ret{};
+  for(const auto& robid : m_mandatoryL1ROBs.value())
+  {
+    if(isSubDetectorIn(SourceIdentifier(robid).subdetector_id()))
+    {
+      auto it = std::find_if(begin(l1r), end(l1r), [robid](const ROB& rob){
+        return rob.rob_source_id() == robid;
+      });
+      if(it == end(l1r))
+        ret.push_back(robid);
+    }
+  }
+
+  return ret;
+}
+
+//=========================================================================
+bool HltEventLoopMgr::isSubDetectorIn(eformat::SubDetector sd) const
+{
+  uint64_t most = std::get<3>(m_detector_mask);
+  most <<= 32;
+  most |= std::get<2>(m_detector_mask);
+
+  uint64_t least = std::get<1>(m_detector_mask);
+  least <<= 32;
+  least |= std::get<0>(m_detector_mask);
+
+  return eformat::helper::DetectorMask{least, most}.is_set(sd);
+}
diff --git a/HLT/Trigger/TrigControl/TrigServices/src/HltROBDataProviderSvc.cxx b/HLT/Trigger/TrigControl/TrigServices/src/HltROBDataProviderSvc.cxx
new file mode 100644
index 00000000000..1ce8e9342bd
--- /dev/null
+++ b/HLT/Trigger/TrigControl/TrigServices/src/HltROBDataProviderSvc.cxx
@@ -0,0 +1,1279 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+// Include files.
+#include "TrigServices/HltROBDataProviderSvc.h"
+#include "TrigMonitorBase/TrigLockedHist.h"
+#include "StoreGate/StoreGateSvc.h"
+#include "GaudiKernel/MsgStream.h"
+#include "GaudiKernel/ISvcLocator.h"
+#include "GaudiKernel/ThreadGaudi.h"
+#include "GaudiKernel/ITHistSvc.h"
+#include "GaudiKernel/IJobOptionsSvc.h"
+#include "GaudiKernel/Property.h"
+#include "GaudiKernel/IIncidentSvc.h"
+#include "GaudiKernel/IAlgContextSvc.h"
+#include "GaudiKernel/IAlgorithm.h"
+#include "hltinterface/DataCollector.h"
+#include "eformat/Version.h"
+
+#include <iostream>
+#include <sstream>
+#include <iomanip>
+#include <cassert> 
+#include <bitset> 
+#include <TH1F.h>
+#include <TH2F.h>
+
+#if ROOT_VERSION_CODE >= ROOT_VERSION(6,0,0)
+#   define CAN_REBIN(hist)  hist->SetCanExtend(TH1::kAllAxes)
+#else
+#   define CAN_REBIN(hist)  hist->SetBit(TH1::kCanRebin)
+#endif
+
+namespace HltROBDataProviderConstants {
+  // reserve a number of ROB monitor collections
+  static const int Number_of_Rob_Monitor_Structs = 10;
+  // number of ROBs in an event, used to reserve space in an array
+  static const int Max_Number_Of_ROBs = 1800;
+}
+
+// Constructor.
+HltROBDataProviderSvc::HltROBDataProviderSvc(const std::string& name, ISvcLocator* svcloc)
+:ROBDataProviderSvc(name,svcloc),
+ m_storeGateSvc( "StoreGateSvc", name ),
+ m_algContextSvc(0),
+ m_onlineRunning(false),
+ m_removeEmptyROB(false),
+ m_isEventComplete(false),
+ m_callerName("UNKNOWN"),
+ m_msg(0),
+ m_histProp_requestedROBsPerCall(Gaudi::Histo1DDef("RequestedROBsPerCall" ,0,300,50)),
+ m_histProp_receivedROBsPerCall(Gaudi::Histo1DDef("ReceivedROBsPerCall" ,0,300,50)),
+ m_histProp_timeROBretrieval(Gaudi::Histo1DDef("TimeForROBretrieval" ,0.,500.,50)),
+ m_hist_requestedROBsPerCall(0),
+ m_hist_receivedROBsPerCall(0),
+ m_hist_timeROBretrieval(0),
+ m_hist_genericStatusForROB(0),
+ m_hist_specificStatusForROB(0)
+{
+  declareProperty("ignoreROB", m_ignoreROB,"List of ROBs to ignore for retrieval");
+  declareProperty("enabledROBs", m_enabledROBs,"List of enabled detector ROBs");
+  declareProperty("LArMetROBs", m_enabledLArMetROBs,"List of enabled LAr MET ROBs");
+  declareProperty("TileMetROBs", m_enabledTileMetROBs,"List of enabled Tile MET ROBs");
+  declareProperty("readROBfromOKS", m_readROBfromOKS=true,"Read enabled ROBs from OKS");
+  declareProperty("doMonitoring", m_doMonitoring=false,"Enable histograms");
+  declareProperty("doDetailedROBMonitoring", m_doDetailedROBMonitoring=false,"Produce ROB cost data");
+  declareProperty("ROBDataMonitorCollectionSGName", m_ROBDataMonitorCollection_SG_Name="ROBDataMonitorCollection","Name of cost monitoring collection in SG");
+  declareProperty("HistRequestedROBsPerCall", m_histProp_requestedROBsPerCall,"Number of ROBs requested");
+  declareProperty("HistReceivedROBsPerCall", m_histProp_receivedROBsPerCall,"Number of ROBs received");
+  declareProperty("HistTimeROBretrieval", m_histProp_timeROBretrieval,"Timing for ROB retrieval");
+  declareProperty("ModuleIDGenericLArMetROB", m_genericLArMetModuleID=0xffff,"Generic module id for LAr MET ROB retrieval");  
+  declareProperty("ModuleIDGenericTileMetROB", m_genericTileMetModuleID=0xffff,"Generic module id for Tile MET ROB retrieval");
+  declareProperty("SeparateMETandDetROBRetrieval", m_separateMETandDetROBRetrieval=true,"Separate retrieval of MET and detector ROBs");
+
+  // fill map with generic status codes
+  m_map_GenericStatus[eformat::UNCLASSIFIED]      = "UNCLASSIFIED"; 
+  m_map_GenericStatus[eformat::BCID_CHECK_FAIL]   = "BCID_CHECK_FAIL"; 
+  m_map_GenericStatus[eformat::LVL1ID_CHECK_FAIL] = "LVL1ID_CHECK_FAIL"; 
+  m_map_GenericStatus[eformat::TIMEOUT]           = "TIMEOUT"; 
+  m_map_GenericStatus[eformat::DATA_CORRUPTION]   = "DATA_CORRUPTION"; 
+  m_map_GenericStatus[eformat::INTERNAL_OVERFLOW] = "INTERNAL_OVERFLOW"; 
+  m_map_GenericStatus[eformat::DUMMY_FRAGMENT]    = "DUMMY_FRAGMENT"; 
+
+  // fill vector with specific status codes
+  m_vec_SpecificStatus.reserve(16);
+  m_vec_SpecificStatus.push_back("TRIGGER_TYPE_SYNC_ERROR/DATAFLOW_DUMMY"); 
+  m_vec_SpecificStatus.push_back("FRAGMENT_SIZE_ERROR"); 
+  m_vec_SpecificStatus.push_back("DATABLOCK_ERROR"); 
+  m_vec_SpecificStatus.push_back("CTRL_WORD_ERROR"); 
+  m_vec_SpecificStatus.push_back("MISSING_BOF"); 
+  m_vec_SpecificStatus.push_back("MISSING_EOF"); 
+  m_vec_SpecificStatus.push_back("INVALID_HEADER_MARKER"); 
+  m_vec_SpecificStatus.push_back("FORMAT_ERROR"); 
+  m_vec_SpecificStatus.push_back("DUPLICATE_EVENT"); 
+  m_vec_SpecificStatus.push_back("SEQUENCE_ERROR"); 
+  m_vec_SpecificStatus.push_back("TRANSMISSION_ERROR"); 
+  m_vec_SpecificStatus.push_back("TRUNCATION"); 
+  m_vec_SpecificStatus.push_back("SHORT_FRAGMENT"); 
+  m_vec_SpecificStatus.push_back("FRAGMENT_LOST"); 
+  m_vec_SpecificStatus.push_back("FRAGMENT_PENDING"); 
+  m_vec_SpecificStatus.push_back("ROBIN_DISCARD_MODE"); 
+}
+
+// Destructor.
+HltROBDataProviderSvc::~HltROBDataProviderSvc()
+{
+}
+
+// Initialization 
+StatusCode HltROBDataProviderSvc::initialize()
+{
+  StatusCode sc = ROBDataProviderSvc::initialize();
+
+  // set message stream
+  m_msg  = new MsgStream( msgSvc(), name() );
+
+  MsgStream log(msgSvc(), name());
+  log << MSG::INFO << " ---> HltROBDataProviderSvc = " << name() << " initialize "
+      << " - package version " << PACKAGE_VERSION << endreq ;
+
+  // get Property filterEmptyROB from base class
+  if ( !sc.isSuccess() ) {
+    log << MSG::ERROR << " ROBDataProviderSvc::initialize() failed." << endreq;
+    return sc;
+  } else {
+    BooleanProperty filterEmptyROB;
+    filterEmptyROB.setName("filterEmptyROB");
+    if (filterEmptyROB.assign(getProperty("filterEmptyROB"))) {
+      m_removeEmptyROB = filterEmptyROB.value() ;
+      log << MSG::INFO << " ---> getProperty('filterEmptyROB')       = " << filterEmptyROB << endreq;
+    } else {
+      log << MSG::WARNING << " ROBDataProviderSvc::getProperty('filterEmptyROB') failed." << endreq;
+    }
+  }
+
+  // get the list of enabled ROBs from OKS
+  bool robOKSconfigFound = false;
+  bool robLArMetOKSconfigFound = false;
+  bool robTileMetOKSconfigFound = false;
+
+  if ( m_readROBfromOKS.value() ) {
+    ServiceHandle<IJobOptionsSvc> p_jobOptionsSvc("JobOptionsSvc", name());
+    if ((p_jobOptionsSvc.retrieve()).isFailure()) {
+      log << MSG::ERROR << "Could not find JobOptionsSvc" << endreq;
+    } else {
+      const std::vector<const Property*>* dataFlowProps = p_jobOptionsSvc->getProperties("DataFlowConfig");
+      if(!dataFlowProps)
+        log << MSG::ERROR << "Could not find DataFlowConfig properties" << endreq;
+      else
+      {
+        for ( std::vector<const Property*>::const_iterator cur = dataFlowProps->begin();
+            cur != dataFlowProps->end(); cur++) {
+          // the enabled ROB list is found
+          if ( (*cur)->name() == "DF_Enabled_ROB_IDs" ) {
+            if (m_enabledROBs.assign(**cur)) {
+              robOKSconfigFound = true;
+              log << MSG::INFO << " ---> Read from OKS                       = " << m_enabledROBs.value().size() << " enabled ROB IDs." << endreq;
+            } else {
+              log << MSG::WARNING << " Could not set Property 'enabledROBs' from OKS." << endreq;
+            }
+          }
+
+          // the LAr MET ROB list is found
+          if ( (*cur)->name() == "DF_LAr_MET_ROB_IDs" ) {
+            if (m_enabledLArMetROBs.assign(**cur)) {
+              robLArMetOKSconfigFound = true;
+              log << MSG::INFO << " ---> Read from OKS                       = " << m_enabledLArMetROBs.value().size() << " LAr MET ROB IDs." << endreq;
+            } else {
+              log << MSG::WARNING << " Could not set Property 'LArMetROBs' from OKS." << endreq;
+            }
+          }
+
+          // the Tile MET ROB list is found
+          if ( (*cur)->name() == "DF_Tile_MET_ROB_IDs" ) {
+            if (m_enabledTileMetROBs.assign(**cur)) {
+              robTileMetOKSconfigFound = true;
+              log << MSG::INFO << " ---> Read from OKS                       = " << m_enabledTileMetROBs.value().size() << " Tile MET ROB IDs." << endreq;
+            } else {
+              log << MSG::WARNING << " Could not set Property 'TileMetROBs' from OKS." << endreq;
+            }
+          }
+        }
+      }
+      p_jobOptionsSvc.release().ignore();
+    }
+  }
+
+  log << MSG::INFO << " ---> HltROBDataProviderSvc               = " << name() << " special properties <---" << endreq;
+  log << MSG::INFO << " ---> Filter out empty ROB fragments      = " << m_removeEmptyROB << endreq;
+  log << MSG::INFO << " ---> Fill monitoring histograms          = " << m_doMonitoring << endreq;
+  log << MSG::INFO << "        Hist:RequestedROBsPerCall         = " << m_histProp_requestedROBsPerCall << endreq; 
+  log << MSG::INFO << "        Hist:ReceivedROBsPerCall          = " << m_histProp_receivedROBsPerCall << endreq; 
+  log << MSG::INFO << "        Hist:TimeROBretrieval             = " << m_histProp_timeROBretrieval << endreq; 
+  log << MSG::INFO << " ---> Do detailed ROB monitoring          = " << m_doDetailedROBMonitoring << endreq;
+  log << MSG::INFO << " ---> SG name for ROB monitoring collect. = " << m_ROBDataMonitorCollection_SG_Name << endreq;
+  log << MSG::INFO << " ---> Read list of enabled ROBs from OKS  = " << m_readROBfromOKS << endreq;
+  if (m_enabledROBs.value().size() == 0) {
+    log << MSG::INFO << " ---> The list of enabled ROBs has size   = 0. No check will be performed " << endreq;
+  } else {
+    if (m_readROBfromOKS.value() && robOKSconfigFound) {
+      log << MSG::INFO << " ---> The list of enabled ROBs has size   = " << m_enabledROBs.value().size() 
+	      << ". It was read from the partition database."  << endreq;
+    } else {
+      log << MSG::INFO << " ---> The list of enabled ROBs has size   = " << m_enabledROBs.value().size() 
+	      << ". It was read from job options."  << endreq;
+    }
+  }
+
+  log << MSG::INFO << " ---> Generic Module ID for LAr MET ROB   = " << m_genericLArMetModuleID << endreq;
+  if (m_enabledLArMetROBs.value().size() == 0) {
+    log << MSG::INFO << " ---> The list of LAr MET ROBs has size   = 0. No LAr MET ROB access will be done." << endreq;
+  } else {
+    if (m_readROBfromOKS.value() && robLArMetOKSconfigFound) {
+      log << MSG::INFO << " ---> The list of LAr MET ROBs has size   = " << m_enabledLArMetROBs.value().size() 
+	      << ". It was read from the partition database."  << endreq;
+    } else {
+      log << MSG::INFO << " ---> The list of LAr MET ROBs has size   = " << m_enabledLArMetROBs.value().size() 
+	      << ". It was read from job options."  << endreq;
+    }
+  }
+
+  log << MSG::INFO << " ---> Generic Module ID for Tile MET ROB  = " << m_genericTileMetModuleID << endreq;
+  if (m_enabledTileMetROBs.value().size() == 0) {
+    log << MSG::INFO << " ---> The list of Tile MET ROBs has size  = 0. No Tile MET ROB access will be done." << endreq;
+  } else {
+    if (m_readROBfromOKS.value() && robTileMetOKSconfigFound) {
+      log << MSG::INFO << " ---> The list of Tile MET ROBs has size  = " << m_enabledTileMetROBs.value().size() 
+	      << ". It was read from the partition database."  << endreq;
+    } else {
+      log << MSG::INFO << " ---> The list of Tile MET ROBs has size  = " << m_enabledTileMetROBs.value().size() 
+	      << ". It was read from job options."  << endreq;
+    }
+  }
+
+  log << MSG::INFO << " ---> Separate MET and Det ROB Retrieval  = " << m_separateMETandDetROBRetrieval << endreq;
+
+  if (m_ignoreROB.value().size() == 0) {
+    log << MSG::INFO << " ---> The list of ROBs to ignore has size = 0. No check will be performed " << endreq;
+  } else {
+    log << MSG::INFO << " ---> The list of ROBs to ignore has size = " << m_ignoreROB.value().size() << endreq;
+  }
+
+  for (unsigned int i=0; i<m_ignoreROB.value().size(); i++) {
+    log << MSG::INFO << " ---> do not retrieve ROB[" << i << "]: hex(id)=0x"
+        << MSG::hex << m_ignoreROB.value()[i]<<MSG::dec
+        << " dec(id)="<< m_ignoreROB.value()[i] << endreq;
+  }
+
+  // register incident handler for begin run
+  ServiceHandle<IIncidentSvc> incidentSvc("IncidentSvc", name());
+  if ((incidentSvc.retrieve()).isFailure()) {
+    log << MSG::ERROR << "Unable to locate IncidentSvc" << endreq;
+    incidentSvc.release().ignore();
+    return StatusCode::FAILURE;
+  }
+  long int pri=100;
+  incidentSvc->addListener(this,"BeginRun",pri);
+  incidentSvc.release().ignore();
+
+  // Setup the StoreGateSvc
+  if( (m_storeGateSvc.retrieve()).isFailure() ) {
+    log << MSG::ERROR << "Error retrieving StoreGateSvc " << m_storeGateSvc << endreq;
+    m_storeGateSvc.release().ignore();
+    return StatusCode::FAILURE;
+  }
+
+  return sc;
+}
+
+// Initialization 
+StatusCode HltROBDataProviderSvc::finalize()
+{
+  StatusCode sc = ROBDataProviderSvc::finalize();
+  MsgStream log(msgSvc(), name());
+  log << MSG::DEBUG << "finalize()" << endreq; 
+  if ( !sc.isSuccess() ) {
+    log << MSG::ERROR << " ROBDataProviderSvc::finalize() failed." << endreq;
+  }
+
+  // delete message stream
+  if ( m_msg ) delete m_msg;
+
+  // release the AlgContextSvc if used
+  if ( m_algContextSvc ) m_algContextSvc->release();
+
+  return sc;
+}
+
+/// Query interface
+StatusCode HltROBDataProviderSvc::queryInterface(const InterfaceID& riid, void** ppvInterface)
+{
+  if ( IROBDataProviderSvc::interfaceID().versionMatch(riid) )  {
+    *ppvInterface = (IROBDataProviderSvc*)this;
+  } else if ( ITrigROBDataProviderSvc::interfaceID().versionMatch(riid) )  {
+    *ppvInterface = (ITrigROBDataProviderSvc*)this;
+  } else if ( IIncidentListener::interfaceID().versionMatch(riid) )  {
+    *ppvInterface = (IIncidentListener*)this;
+  } else {
+    return Service::queryInterface(riid, ppvInterface);
+  } 
+  addRef(); 
+  return StatusCode::SUCCESS; 
+}
+
+/** - in online add ROB fragments for given ROB ids to the map
+      call the DataCollector to retrieve the ROB fragments 
+
+    - in offline only check that given ROB ids are in the map, issue an
+      error if not
+ */
+void HltROBDataProviderSvc::addROBData(const std::vector<uint32_t>& robIds, const std::string callerName)
+{ 
+  //-------------------
+  // remove empty calls
+  //-------------------
+  if (robIds.size() == 0) return;
+
+  //--------------------
+  // set the caller name
+  //--------------------
+  if (callerName != "UNKNOWN") m_callerName = callerName;
+
+  //--------------------
+  // make unique ROB IDs
+  //--------------------
+  std::vector<uint32_t>::iterator remove_duplicate;
+  std::vector<uint32_t> robIdsUnique(robIds);
+
+  sort(robIdsUnique.begin(), robIdsUnique.end()); 
+  remove_duplicate = unique(robIdsUnique.begin(), robIdsUnique.end()); 
+  robIdsUnique.erase(remove_duplicate, robIdsUnique.end());
+
+  //------------------------------------------------------------------
+  // Replace the generic MET ROB ID with the full list of all MET ROBs
+  //------------------------------------------------------------------
+  // LAr MET ROBs
+  uint32_t generic_LAr_MET_id = eformat::helper::SourceIdentifier(eformat::TDAQ_LAR_MET,m_genericLArMetModuleID.value()).code();
+  std::vector<uint32_t>::iterator rob_LAr_Met_it = std::find(robIdsUnique.begin(), robIdsUnique.end(), generic_LAr_MET_id);
+  if (rob_LAr_Met_it != robIdsUnique.end()) {
+    robIdsUnique.erase(rob_LAr_Met_it);
+    if (m_enabledLArMetROBs.value().size() != 0) robIdsUnique.insert(robIdsUnique.end(),m_enabledLArMetROBs.value().begin(),m_enabledLArMetROBs.value().end());
+  }
+
+  // Tile MET ROBs
+  uint32_t generic_Tile_MET_id = eformat::helper::SourceIdentifier(eformat::TDAQ_TILE_MET,m_genericTileMetModuleID.value()).code();
+  std::vector<uint32_t>::iterator rob_Tile_Met_it = std::find(robIdsUnique.begin(), robIdsUnique.end(), generic_Tile_MET_id);
+  if (rob_Tile_Met_it != robIdsUnique.end()) {
+    robIdsUnique.erase(rob_Tile_Met_it);
+    if (m_enabledTileMetROBs.value().size() != 0) robIdsUnique.insert(robIdsUnique.end(),m_enabledTileMetROBs.value().begin(),m_enabledTileMetROBs.value().end());
+  }
+
+  //-------------------
+  //--- offline running
+  //-------------------
+  if (!m_onlineRunning) {
+
+    // for offline running all requested ROBs should be found in cache
+    // if not issue error
+    ROBDataProviderSvc::addROBData(robIdsUnique);
+    //------------------
+    //--- online running
+    //------------------
+  } else {
+    // detailed ROB monitoring
+    //------------------------
+    // Create a ROB monitoring collection and register it to StoreGate
+    ROBDataMonitorCollection* p_robMonCollection(0); 
+    if ( m_doDetailedROBMonitoring.value() ) {
+      if ( !(m_storeGateSvc->transientContains<ROBDataMonitorCollection>(m_ROBDataMonitorCollection_SG_Name.value())) ) {
+        p_robMonCollection = new ROBDataMonitorCollection;
+        if ( p_robMonCollection ) {
+          p_robMonCollection->reserve( HltROBDataProviderConstants::Number_of_Rob_Monitor_Structs ) ;
+          if ( (m_storeGateSvc->record(p_robMonCollection, m_ROBDataMonitorCollection_SG_Name.value(), true)).isFailure() ) {
+            logStream() << MSG::WARNING << " Registering ROB Monitoring collection in StoreGate failed." << endreq;
+            delete p_robMonCollection;
+            p_robMonCollection = 0;
+          }
+        }
+      } else {
+        if ( m_storeGateSvc->retrieve(p_robMonCollection).isFailure() ) {
+          logStream() << MSG::WARNING << " Retrieval of ROB Monitoring collection from StoreGate failed." << endreq;
+          p_robMonCollection = 0;
+        }
+      }
+    }
+
+    // create a new ROBDataMonitorStruct and fill it
+    robmonitor::ROBDataMonitorStruct* p_robMonStruct(0);
+    if ( p_robMonCollection ) {
+      // caller name
+      std::string caller_name("UNKNOWN");
+      if (callerName != "UNKNOWN") {
+        caller_name = callerName;
+      } else if ((callerName == "UNKNOWN") && (m_callerName != "UNKNOWN")) {
+        caller_name = m_callerName;
+      } else {
+        IAlgorithm* alg(0);
+        if ( m_algContextSvc ) {
+          alg = m_algContextSvc->currentAlg();
+          caller_name = (alg ? alg->name() : "<NONE>");
+        }
+      }
+
+      // initialize new ROBDataMonitorStruct
+      p_robMonStruct = new robmonitor::ROBDataMonitorStruct(m_currentLvl1ID, robIdsUnique, caller_name);
+    }
+
+    // for online running the requested ROBs should be not found in cache
+    // ------------------------------------------------------------------
+    // vector with missing ROB ids for DataCollector
+    std::vector<uint32_t> vRobIds;
+    vRobIds.reserve( robIdsUnique.size() ) ;
+
+    // find missing ROB ids which should be retrieved  
+    if(logLevel() <= MSG::DEBUG)
+      logStream() << MSG::DEBUG << " ---> addROBData: Number of ROB Ids requested : " << robIdsUnique.size() << endreq;
+
+    for(std::vector<uint32_t>::const_iterator it=robIdsUnique.begin(); it!=robIdsUnique.end(); ++it){
+      uint32_t id = (*it);
+
+      // check if ROB is already in cache
+      ONLINE_ROBMAP::iterator map_it = m_online_robmap.find(id) ;
+      if(map_it != m_online_robmap.end()) {
+        if(logLevel() <= MSG::DEBUG)
+          logStream() << MSG::DEBUG << " ---> addROBData: Found   ROB Id : 0x" << MSG::hex << (*map_it).second.source_id() << MSG::dec
+          <<" in cache "<< endreq;
+        //* detailed monitoring
+        if ( p_robMonStruct ) {
+          (p_robMonStruct->requested_ROBs)[id].rob_history = robmonitor::CACHED;
+          (p_robMonStruct->requested_ROBs)[id].rob_size    = ((*map_it).second).fragment_size_word();
+          if ( (*map_it).second.nstatus() != 0 ) {
+            const uint32_t* it_status;
+            (*map_it).second.status(it_status);
+            for (uint32_t k=0; k < (*map_it).second.nstatus(); k++) {
+              (p_robMonStruct->requested_ROBs)[id].rob_status_words.push_back( *(it_status+k) );
+            }
+          }
+        }
+        continue;
+      } 
+
+      // check if ROB should be ignored
+      if (m_ignoreROB.value().size() != 0) {
+        std::vector<uint32_t>::const_iterator rob_ignore_it =
+            std::find(m_ignoreROB.value().begin(), m_ignoreROB.value().end(),id);
+        if(rob_ignore_it != m_ignoreROB.value().end()) {
+          if(logLevel() <= MSG::DEBUG)
+            logStream() << MSG::DEBUG << " ---> addROBData: ROB Id : 0x" << MSG::hex << id << MSG::dec
+            << " will be not retrieved, since it is on the veto list."<< endreq;
+          //* detailed monitoring
+          if ( p_robMonStruct ) {
+            (p_robMonStruct->requested_ROBs)[id].rob_history = robmonitor::IGNORED;
+          }
+          continue;
+        }
+      }
+
+      // check if ROB is actually enabled for readout
+      // do not perform this check for MET ROBs
+      if ( (m_enabledROBs.value().size() != 0) && 
+          (eformat::helper::SourceIdentifier(id).subdetector_id() != eformat::TDAQ_LAR_MET) &&
+          (eformat::helper::SourceIdentifier(id).subdetector_id() != eformat::TDAQ_TILE_MET) ){
+        std::vector<uint32_t>::const_iterator rob_enabled_it =
+            std::find(m_enabledROBs.value().begin(), m_enabledROBs.value().end(),id);
+        if(rob_enabled_it == m_enabledROBs.value().end()) {
+          if(logLevel() <= MSG::DEBUG)
+            logStream() << MSG::DEBUG << " ---> addROBData: ROB Id : 0x" << MSG::hex << id << MSG::dec
+            << " will be not retrieved, since it is not on the list of enabled ROBs."<< endreq;
+          //* detailed monitoring
+          if ( p_robMonStruct ) {
+            (p_robMonStruct->requested_ROBs)[id].rob_history = robmonitor::DISABLED;
+          }
+          continue;
+        }
+      }
+
+      // the ROB should be retrieved from the ROS
+      if (logLevel() <= MSG::DEBUG)
+        logStream() << MSG::DEBUG << " ---> addROBData: Request ROB Id : 0x" << MSG::hex << id << MSG::dec
+        <<" from ROS "<< endreq;
+      vRobIds.push_back( *it ) ;
+    } // end loop over requested input ROBs
+
+    if (vRobIds.size() == 0) {
+      if(logLevel() <= MSG::DEBUG)
+        logStream() << MSG::DEBUG
+        << " ---> addROBData: either all requested ROBs are found in cache for running mode ONLINE, \n"
+        << "      or input ROB Id list was empty, \n"
+        << "      or all requested ROBs were not retrieved due to the veto list.\n"
+        << "      Number of requested ROB Ids = " << robIdsUnique.size() << "\n"
+        << "      Lvl1 id                     = " << m_currentLvl1ID
+        << endreq;
+      // Set ROB request time also in the case when no DataCollector request is necessary 
+      // to allow correlation with RoI request times
+      // start and stop times will be equal
+      if ( p_robMonStruct ) {
+        struct timeval time_start;
+        struct timeval time_stop;
+
+        gettimeofday(&time_start, 0);
+        gettimeofday(&time_stop, 0);
+
+        p_robMonStruct->start_time_of_ROB_request    = time_start;
+        p_robMonStruct->end_time_of_ROB_request      = time_stop;
+      }
+    } else {
+      //
+      // Tell the DCM that these ROBs may be needed
+      // ---------------------------------------------------------------
+      //
+      if(logLevel() <= MSG::DEBUG) {
+	std::ostringstream ost;
+	ost << "      Number of scheduled ROB Ids = " << vRobIds.size() << "\n" ;
+	unsigned int rob_counter = 1;
+	for (std::vector<uint32_t>::const_iterator rob_it=vRobIds.begin(); rob_it!=vRobIds.end(); ++rob_it,++rob_counter)
+	  ost << "       # = "<< std::setw(5) << rob_counter << " ROB id = 0x" << std::hex << (*rob_it) << std::dec << "\n";
+
+	logStream() << MSG::DEBUG
+	      << " ---> addROBData: The following ROB Ids are scheduled for retrieval and are reserved in the DCM: \n"
+              << "      Lvl1 id                     = " << m_currentLvl1ID << "\n"
+              << ost.str()
+              << endreq;
+      }
+      // reserve the ROBs in the DCM
+      hltinterface::DataCollector::instance()->reserveROBData(m_currentLvl1ID, vRobIds);
+    }
+
+    // add the ROB monitoring structure to the collection
+    if ( p_robMonCollection && p_robMonStruct ) p_robMonCollection->push_back( p_robMonStruct );
+  } // end online running   
+  return;
+}
+
+/** - in online add the LVL1/HLT result
+    - rebuild the map
+    - set flag for online running
+ */
+void HltROBDataProviderSvc::setNextEvent(const std::vector<ROBF>& result)
+{ 
+  // clear the ROB map
+  m_online_robmap.clear(); 
+  m_currentLvl1ID = 0;
+
+  // set the online flag
+  m_onlineRunning = true ;
+
+  // set the complete event flag
+  m_isEventComplete = false;
+
+  if ( result.size() == 0 ) {
+    logStream()<<MSG::ERROR<< " ---> setNextEvent online for "<< name() 
+	           <<" failed: Size of received vector of ROB fragments = " << result.size()
+	           <<endreq;
+    return;
+  }
+
+  // set the LVL1 id
+  m_currentLvl1ID = result[0].rod_lvl1_id();
+
+  // add fragments to map
+  std::vector<ROBF>::const_iterator it_robf     = result.begin();
+  std::vector<ROBF>::const_iterator it_robf_end = result.end();
+  for(; it_robf!=it_robf_end; ++it_robf) {
+    uint32_t id = it_robf->source_id() ;
+    // check current L1 ID against CTP fragment when possible
+    if ( (eformat::helper::SourceIdentifier(id).subdetector_id() == eformat::TDAQ_CTP) &&
+        (it_robf->rod_lvl1_id() != m_currentLvl1ID) ) {
+      logStream() << MSG::ERROR << " ---> Lvl1 ID mismatch for CTP fragment with SourceId = 0x" << MSG::hex << id << MSG::dec
+          << " and L1 Id = " << it_robf->rod_lvl1_id()
+          << " to currently used L1 Id = " << m_currentLvl1ID
+          << " -> Use CTP version from now on."<< endreq;
+      m_currentLvl1ID = it_robf->rod_lvl1_id() ;
+    }
+    // remove empty ROB fragments or ones with bad status, if requested
+    if ((it_robf->rod_ndata() == 0) && (m_removeEmptyROB)) { 
+      if(logLevel() <= MSG::DEBUG) { 
+        logStream() << MSG::DEBUG << " ---> Empty ROB Id = 0x" << MSG::hex << id << MSG::dec
+            << " removed for L1 Id = " << m_currentLvl1ID << endreq;
+      }  
+    } else if ( ROBDataProviderSvc::filterRobWithStatus(&*it_robf) ) {
+      if ((logLevel() <= MSG::DEBUG) && (it_robf->nstatus() > 0)) {
+        const uint32_t* it_status;
+        it_robf->status(it_status);
+        eformat::helper::Status tmpstatus( (*it_status) ) ;
+        logStream() << MSG::DEBUG << " ---> ROB Id = 0x" << MSG::hex << id
+            << std::setfill( '0' )
+        << " with Generic Status Code = 0x" << std::setw(4) << tmpstatus.generic()
+        << " and Specific Status Code = 0x" << std::setw(4) << tmpstatus.specific()
+        << MSG::dec
+        << " removed for L1 Id = " << m_currentLvl1ID << endreq;
+      }
+    } else {
+      m_online_robmap[id]= (*it_robf) ;
+    }
+
+    //* fill monitoring histogram for ROB generic status
+    if ( ( m_hist_genericStatusForROB ) && ( it_robf->nstatus() != 0 ) ) {
+      const uint32_t* it_status;
+      it_robf->status(it_status);
+      if ((*it_status) != 0) {
+        scoped_lock_histogram lock;
+        m_hist_genericStatusForROB->Fill(eformat::helper::SourceIdentifier(it_robf->source_id()).human_detector().c_str(),
+            m_map_GenericStatus[eformat::helper::Status(*it_status).generic()].c_str(),1.);
+      }
+    }
+
+    //* fill monitoring histogram for ROB specific status
+    if ( ( m_hist_specificStatusForROB ) && ( it_robf->nstatus() != 0 ) ) {
+      const uint32_t* it_status;
+      it_robf->status(it_status);
+      if ((*it_status) != 0) {
+        scoped_lock_histogram lock;
+        std::bitset<16> specificBits(eformat::helper::Status(*it_status).specific());
+        for (unsigned int index=0; index < 16; ++index) {
+          if (specificBits[index]) m_hist_specificStatusForROB->Fill(eformat::helper::SourceIdentifier(it_robf->source_id()).human_detector().c_str(),
+              m_vec_SpecificStatus[index].c_str(),1.);
+        }
+      }
+    }
+  }
+
+  if(logLevel() <= MSG::DEBUG) {
+    logStream()<<MSG::DEBUG<< " ---> setNextEvent online for "<< name()<<endreq; 
+    logStream()<<MSG::DEBUG<< "      online running    = " << m_onlineRunning <<endreq;
+    logStream()<<MSG::DEBUG<< "      current LVL1 id   = " << m_currentLvl1ID <<endreq;
+    logStream()<<MSG::DEBUG<< "      # LVL1 ROBs       = " << result.size() <<endreq;
+    logStream()<<MSG::DEBUG<< "      size of ROB cache = " << m_online_robmap.size() <<endreq;
+    logStream()<<MSG::DEBUG<< dumpROBcache() <<endreq; 
+  }
+  return; 
+}
+
+/** - add a new Raw event
+    - rebuild the map
+    - set flag for offline running
+ */
+void HltROBDataProviderSvc::setNextEvent(const RawEvent* re)
+{ 
+  // set the offline flag
+  m_onlineRunning = false ;
+  
+  // set the event complete flag
+  m_isEventComplete = true ;
+
+  ROBDataProviderSvc::setNextEvent(re);
+  return ;
+}
+
+/** return ROBData for ROBID
+ */ 
+void HltROBDataProviderSvc::getROBData(const std::vector<uint32_t>& robIds, std::vector<const ROBF*>& robFragments, std::string callerName)
+{
+  //--------------------
+  // set the caller name
+  //--------------------
+  if (callerName != "UNKNOWN") m_callerName = callerName;
+
+  //-------------------
+  //--- offline running
+  //-------------------
+  if (!m_onlineRunning) {
+    ROBDataProviderSvc::getROBData(robIds,robFragments);
+    //------------------
+    //--- online running
+    //------------------
+  } else {
+    //--------------------
+    // make unique ROB IDs
+    //--------------------
+    std::vector<uint32_t>::iterator remove_duplicate;
+    std::vector<uint32_t> robIdsUnique(robIds);
+
+    sort(robIdsUnique.begin(), robIdsUnique.end()); 
+    remove_duplicate = unique(robIdsUnique.begin(), robIdsUnique.end()); 
+    robIdsUnique.erase(remove_duplicate, robIdsUnique.end());
+
+    //------------------------------------------------------------------
+    // Replace the generic MET ROB ID with the full list of all MET ROBs
+    //------------------------------------------------------------------
+    // LAr MET ROBs
+    uint32_t generic_LAr_MET_id = eformat::helper::SourceIdentifier(eformat::TDAQ_LAR_MET,m_genericLArMetModuleID.value()).code();
+    std::vector<uint32_t>::iterator rob_LAr_Met_it = std::find(robIdsUnique.begin(), robIdsUnique.end(), generic_LAr_MET_id);
+    if (rob_LAr_Met_it != robIdsUnique.end()) {
+      robIdsUnique.erase(rob_LAr_Met_it);
+      if (m_enabledLArMetROBs.value().size() != 0) robIdsUnique.insert(robIdsUnique.end(),m_enabledLArMetROBs.value().begin(),m_enabledLArMetROBs.value().end());
+    }
+
+    // Tile MET ROBs
+    uint32_t generic_Tile_MET_id = eformat::helper::SourceIdentifier(eformat::TDAQ_TILE_MET,m_genericTileMetModuleID.value()).code();
+    std::vector<uint32_t>::iterator rob_Tile_Met_it = std::find(robIdsUnique.begin(), robIdsUnique.end(), generic_Tile_MET_id);
+    if (rob_Tile_Met_it != robIdsUnique.end()) {
+      robIdsUnique.erase(rob_Tile_Met_it);
+      if (m_enabledTileMetROBs.value().size() != 0) robIdsUnique.insert(robIdsUnique.end(),m_enabledTileMetROBs.value().begin(),m_enabledTileMetROBs.value().end());
+    }
+
+    // detailed ROB monitoring
+    //------------------------
+    // Create a ROB monitoring collection and register it to StoreGate
+    ROBDataMonitorCollection* p_robMonCollection(0); 
+    if ((m_doDetailedROBMonitoring.value()) && (robIdsUnique.size() != 0)) {
+      if ( !(m_storeGateSvc->transientContains<ROBDataMonitorCollection>(m_ROBDataMonitorCollection_SG_Name.value())) ) {
+	p_robMonCollection = new ROBDataMonitorCollection;
+	if ( p_robMonCollection ) {
+	  p_robMonCollection->reserve( HltROBDataProviderConstants::Number_of_Rob_Monitor_Structs ) ;
+	  if ( (m_storeGateSvc->record(p_robMonCollection, m_ROBDataMonitorCollection_SG_Name.value(), true)).isFailure() ) {
+	    logStream() << MSG::WARNING << " getROBData: Registering ROB Monitoring collection in StoreGate failed." << endreq;
+	    delete p_robMonCollection;
+	    p_robMonCollection = 0;
+	  }
+	}
+      } else {
+	if ( m_storeGateSvc->retrieve(p_robMonCollection).isFailure() ) {
+	  logStream() << MSG::WARNING << " getROBData: Retrieval of ROB Monitoring collection from StoreGate failed." << endreq;
+	  p_robMonCollection = 0;
+	}
+      }
+    }
+
+    // create a new ROBDataMonitorStruct and fill it
+    robmonitor::ROBDataMonitorStruct* p_robMonStruct(0);
+    if ( p_robMonCollection ) {
+      // caller name
+      std::string caller_name("UNKNOWN");
+      if (callerName != "UNKNOWN") {
+	caller_name = callerName;
+      } else if ((callerName == "UNKNOWN") && (m_callerName != "UNKNOWN")) {
+	caller_name = m_callerName;
+      } else {
+	IAlgorithm* alg(0);
+	if ( m_algContextSvc ) {
+	  alg = m_algContextSvc->currentAlg();
+	  caller_name = (alg ? alg->name() : "<NONE>");
+	}
+      }
+
+      // initialize new ROBDataMonitorStruct
+      p_robMonStruct = new robmonitor::ROBDataMonitorStruct(m_currentLvl1ID, robIdsUnique, caller_name);
+    }
+
+    //--------------------------
+    // update internal ROB cache
+    //--------------------------
+    addROBDataToCache(robIdsUnique, p_robMonStruct);
+
+    // add the ROB monitoring structure to the collection
+    if ( p_robMonCollection && p_robMonStruct ) p_robMonCollection->push_back( p_robMonStruct );
+
+
+    //------------------------------------------------------------------
+    // Return requested ROBs from internal cache
+    //------------------------------------------------------------------
+    for(std::vector<uint32_t>::const_iterator it = robIdsUnique.begin(); it != robIdsUnique.end(); ++it){
+      uint32_t id = (*it); 
+      ONLINE_ROBMAP::iterator map_it = m_online_robmap.find(id) ; 
+      if(map_it != m_online_robmap.end()) {      
+        robFragments.push_back( &((*map_it).second) );
+      } else {
+        if(logLevel() <= MSG::DEBUG) {
+          logStream()<<MSG::DEBUG<<" ---> getROBData: Failed to find ROB for id 0x"
+              <<MSG::hex<< id <<MSG::dec<<endreq;
+          if(logLevel() <= MSG::VERBOSE) { logStream()<<MSG::VERBOSE<< dumpROBcache() <<endreq; }
+        }
+      }
+    }
+  }
+
+  return ; 
+}
+
+/// Retrieve the whole event.
+const RawEvent* HltROBDataProviderSvc::getEvent(){
+  if (m_onlineRunning) return 0;
+  return ROBDataProviderSvc::getEvent(); 
+}
+
+/// Return vector with all ROBFragments stored in the cache 
+void HltROBDataProviderSvc::getAllROBData(std::vector<const ROBF*>& robFragments)
+{
+  //------------------
+  //--- online running
+  //------------------
+  if (m_onlineRunning) {
+    for(ONLINE_ROBMAP::iterator it=m_online_robmap.begin(); it!=m_online_robmap.end(); ++it) {
+      robFragments.push_back( &((*it).second) ); 
+    } 
+  }
+  return ; 
+}
+
+// Dump ROB cache
+std::string HltROBDataProviderSvc::dumpROBcache() const {
+
+  ONLINE_ROBMAP::const_iterator cache_it  = m_online_robmap.begin() ; 
+  ONLINE_ROBMAP::const_iterator cache_end = m_online_robmap.end() ;
+  int nrob = 0;
+
+  std::ostringstream ost;
+  ost << " --- Dump of ROB cache ids --- total size = "
+      << m_online_robmap.size() <<"\n";  
+  for(; cache_it!=cache_end; ++cache_it){
+    ++nrob;
+    ost <<" # = "<< std::setw(5) << nrob << " cache id = 0x" << std::hex << (*cache_it).first 
+        << " hex: source id = 0x" << std::hex << (*cache_it).second.source_id()
+        << std::dec << "  decimal: source id = " << (*cache_it).second.source_id() << "\n";
+  }
+  std::string ret(ost.str());
+  return ret;
+}
+
+/// Collect all data for an event from the ROS and put them into the cache
+/// Return value: number of ROBs which were retrieved to complete event
+int HltROBDataProviderSvc::collectCompleteEventData(const std::string callerName) {
+
+  // return if call was already issued
+  if (m_isEventComplete) return 0;
+
+  //--------------------
+  // set the caller name
+  //--------------------
+  if (callerName != "UNKNOWN") m_callerName = callerName;
+
+  typedef std::vector<hltinterface::DCM_ROBInfo> ROBInfoVec;
+  ROBInfoVec vRobInfos ;
+  if (m_enabledROBs.value().size() != 0) {
+    vRobInfos.reserve( m_enabledROBs.value().size() ) ;
+  } else {
+    vRobInfos.reserve( HltROBDataProviderConstants::Max_Number_Of_ROBs ) ;
+  }
+
+  struct timeval time_start;
+  struct timeval time_stop;
+  if ( m_doMonitoring || m_doDetailedROBMonitoring.value() ) gettimeofday(&time_start, 0);
+
+  // Get ROB Fragments for complete event with DataCollector
+  hltinterface::DataCollector::instance()->collect(vRobInfos, m_currentLvl1ID);
+
+  if ( m_doMonitoring || m_doDetailedROBMonitoring.value() ) gettimeofday(&time_stop, 0);
+
+  if (logLevel() <= MSG::DEBUG) {
+    std::ostringstream ost;
+    unsigned int rob_counter = 1;
+    for (ROBInfoVec::const_iterator rob_it = vRobInfos.begin(); rob_it != vRobInfos.end(); ++rob_it,++rob_counter)
+      ost << "       # = "<< std::setw(5) << rob_counter << " ROB id = 0x" << std::hex << rob_it->robFragment.source_id() << std::dec << "\n" ; 
+    logStream() << MSG::DEBUG 
+        << " ---> collectCompleteEventData: The following ROB Ids were received from DataCollector : \n"
+        << "      Lvl1 id                                             = " << m_currentLvl1ID << "\n"
+        << "      Number of actually received ROB Ids                 = " << vRobInfos.size() << "\n"
+        << ost.str()
+        << endreq;
+  }
+
+  // detailed ROB monitoring
+  //------------------------
+  // Create a ROB monitoring collection and register it to StoreGate
+  ROBDataMonitorCollection* p_robMonCollection(0); 
+  if ( m_doDetailedROBMonitoring.value() ) {
+    if ( !(m_storeGateSvc->transientContains<ROBDataMonitorCollection>(m_ROBDataMonitorCollection_SG_Name.value())) ) {
+      p_robMonCollection = new ROBDataMonitorCollection;
+      if ( p_robMonCollection ) {
+	p_robMonCollection->reserve( HltROBDataProviderConstants::Number_of_Rob_Monitor_Structs ) ;
+	if ( (m_storeGateSvc->record(p_robMonCollection, m_ROBDataMonitorCollection_SG_Name.value(), true)).isFailure() ) {
+	  logStream() << MSG::WARNING << " Registering ROB Monitoring collection in StoreGate failed." << endreq;
+	  delete p_robMonCollection;
+	  p_robMonCollection = 0;
+	}
+      }
+    } else {
+      if ( m_storeGateSvc->retrieve(p_robMonCollection).isFailure() ) {
+	logStream() << MSG::WARNING << " Retrieval of ROB Monitoring collection from StoreGate failed." << endreq;
+	p_robMonCollection = 0;
+      }
+    }
+  }
+
+  // create a new ROBDataMonitorStruct and fill it
+  robmonitor::ROBDataMonitorStruct* p_robMonStruct(0);
+  if ( p_robMonCollection ) {
+    // caller name
+    std::string caller_name("UNKNOWN");
+    if (callerName != "UNKNOWN") {
+      caller_name = callerName;
+    } else if ((callerName == "UNKNOWN") && (m_callerName != "UNKNOWN")) {
+      caller_name = m_callerName;
+    } else {
+      IAlgorithm* alg(0);
+      if ( m_algContextSvc ) {
+        alg = m_algContextSvc->currentAlg();
+        caller_name = (alg ? alg->name() : "<NONE>");
+      }
+    }
+
+    // get ROB Ids
+    std::vector<uint32_t> robIds;
+    robIds.reserve(vRobInfos.size());
+    for(ROBInfoVec::const_iterator it=vRobInfos.begin(); it!=vRobInfos.end(); ++it) {
+      robIds.push_back( it->robFragment.source_id() ) ;
+    }
+
+    // initialize new ROBDataMonitorStruct
+    p_robMonStruct = new robmonitor::ROBDataMonitorStruct(m_currentLvl1ID, robIds, caller_name);
+  }
+
+  if ( m_doMonitoring || p_robMonStruct ) {
+    int secs = 0 ;
+    if (time_stop.tv_sec >= time_start.tv_sec)
+      secs = time_stop.tv_sec - time_start.tv_sec;
+
+    int usecs = time_stop.tv_usec - time_start.tv_usec;
+    float mtime = static_cast<float>(secs)*1000 + static_cast<float>(usecs)/1000;
+
+    //* timing histogram
+    if (m_hist_timeROBretrieval) {
+      scoped_lock_histogram lock;
+      m_hist_timeROBretrieval->Fill(mtime);
+      m_hist_timeROBretrieval->LabelsDeflate("X");
+    }
+    //* number of received ROBs
+    if ( m_hist_receivedROBsPerCall ) {
+      scoped_lock_histogram lock;
+      m_hist_receivedROBsPerCall->Fill(vRobInfos.size());
+      m_hist_receivedROBsPerCall->LabelsDeflate("X");
+    }
+
+    //* detailed monitoring
+    if ( p_robMonStruct ) {
+      p_robMonStruct->start_time_of_ROB_request    = time_start;
+      p_robMonStruct->end_time_of_ROB_request      = time_stop;
+    }
+  }
+
+  // add ROBs to cache
+  updateROBDataCache(vRobInfos,p_robMonStruct);
+
+  // add the ROB monitoring structure to the collection
+  if ( p_robMonCollection && p_robMonStruct ) p_robMonCollection->push_back( p_robMonStruct );
+
+  // update event complete flag
+  m_isEventComplete = true;
+
+  return vRobInfos.size();
+} // end int collectCompleteEventData(...)
+
+/// set the name of the program which uses the ROBDataProviderSvc
+void HltROBDataProviderSvc::setCallerName(const std::string callerName) {
+  m_callerName = callerName;
+}
+
+// handler for BeginRun
+void HltROBDataProviderSvc::handle(const Incident& incident) {
+  if (incident.type()!="BeginRun") return;
+  if(logLevel() <= MSG::DEBUG)
+    logStream() <<MSG::DEBUG << "In BeginRun incident." << endreq;
+
+  // if detailed ROB monitoring is requested, check if the AlgContextSvc is running, 
+  // if yes use it to obtain the calling algorithm name
+  if ( m_doDetailedROBMonitoring.value() ) {
+    if ( service("AlgContextSvc", m_algContextSvc, /*createIf=*/ false).isFailure() ) {
+      logStream() << MSG::ERROR << "Error retrieving AlgContextSvc."  
+          << "Calling algorithm name not available in detailed ROB monitoring" << endreq;
+      m_algContextSvc=0;
+    }
+  }
+
+  // define histograms if monitoring is requested
+  if ( !m_doMonitoring.value() ) return;
+
+  // find histogramming service
+  ServiceHandle<ITHistSvc> rootHistSvc("THistSvc", name());
+  if ((rootHistSvc.retrieve()).isFailure()) {
+    logStream() << MSG::ERROR << "Unable to locate THistSvc" << endreq;
+    rootHistSvc.release().ignore();
+    return;
+  }
+
+  // *-- booking path
+  std::string path = std::string("/EXPERT/")+getGaudiThreadGenericName(name())+"/";
+
+  // *-- number of bins for sub detector plots (55 SubDet max.)
+  uint32_t n_bins_partEBSubDet = eformat::helper::SubDetectorDictionary.size();
+
+  // *-- number of requested ROBs per call
+  m_hist_requestedROBsPerCall = new TH1F (m_histProp_requestedROBsPerCall.value().title().c_str(),
+      (m_histProp_requestedROBsPerCall.value().title()+";number of ROBs").c_str(),
+      m_histProp_requestedROBsPerCall.value().bins(),
+      m_histProp_requestedROBsPerCall.value().lowEdge(),
+      m_histProp_requestedROBsPerCall.value().highEdge());
+  if (m_hist_requestedROBsPerCall) {
+    CAN_REBIN(m_hist_requestedROBsPerCall);
+    if( rootHistSvc->regHist(path + m_hist_requestedROBsPerCall->GetName(), m_hist_requestedROBsPerCall).isFailure() ) {
+      logStream() << MSG::WARNING << "Can not register monitoring histogram: " << m_hist_requestedROBsPerCall->GetName() << endreq;
+    }
+  }
+
+  // *-- number of received ROBs per call
+  m_hist_receivedROBsPerCall  = new TH1F (m_histProp_receivedROBsPerCall.value().title().c_str(),
+      (m_histProp_receivedROBsPerCall.value().title()+";number of ROBs").c_str(),
+      m_histProp_receivedROBsPerCall.value().bins(),
+      m_histProp_receivedROBsPerCall.value().lowEdge(),
+      m_histProp_receivedROBsPerCall.value().highEdge());
+  if (m_hist_receivedROBsPerCall) {
+    CAN_REBIN(m_hist_receivedROBsPerCall);
+    if( rootHistSvc->regHist(path + m_hist_receivedROBsPerCall->GetName(), m_hist_receivedROBsPerCall).isFailure() ) {
+      logStream() << MSG::WARNING << "Can not register monitoring histogram: " << m_hist_receivedROBsPerCall->GetName() << endreq;
+    }
+  }
+
+  // *-- timing of ROB retrieval
+  m_hist_timeROBretrieval     = new TH1F (m_histProp_timeROBretrieval.value().title().c_str(),
+      (m_histProp_timeROBretrieval.value().title()+";time [ms]").c_str(),
+      m_histProp_timeROBretrieval.value().bins(),
+      m_histProp_timeROBretrieval.value().lowEdge(),
+      m_histProp_timeROBretrieval.value().highEdge());
+  if (m_hist_timeROBretrieval) {
+    CAN_REBIN(m_hist_timeROBretrieval);
+    if( rootHistSvc->regHist(path + m_hist_timeROBretrieval->GetName(), m_hist_timeROBretrieval).isFailure() ) {
+      logStream() << MSG::WARNING << "Can not register monitoring histogram: " << m_hist_timeROBretrieval->GetName() << endreq;
+    }
+  }
+
+  // *-- Generic Status for ROBs per sub detector
+  m_hist_genericStatusForROB = new TH2F ("GenericStatusForROBsFromSubDetectors",
+      "GenericStatusForROBsFromSubDetectors;;",
+      n_bins_partEBSubDet,0.,(float) n_bins_partEBSubDet,
+      m_map_GenericStatus.size(),0., (float) m_map_GenericStatus.size());
+  if (m_hist_genericStatusForROB) {
+    uint32_t n_tmp_bin = 1;
+    for (eformat::helper::EnumClass<eformat::SubDetector>::const_iterator it_sub=eformat::helper::SubDetectorDictionary.begin();
+        it_sub != eformat::helper::SubDetectorDictionary.end(); it_sub++ ) {
+      m_hist_genericStatusForROB->GetXaxis()->SetBinLabel( n_tmp_bin, (it_sub->second).c_str() );
+      n_tmp_bin++;
+    }
+
+    n_tmp_bin = 1;
+    for (std::map<eformat::GenericStatus, std::string>::const_iterator it = m_map_GenericStatus.begin();it != m_map_GenericStatus.end();++it) {
+      m_hist_genericStatusForROB->GetYaxis()->SetBinLabel( n_tmp_bin, (*it).second.c_str() );
+      n_tmp_bin++;
+    }
+    if( rootHistSvc->regHist(path + m_hist_genericStatusForROB->GetName(), m_hist_genericStatusForROB).isFailure() ) {
+      logStream() << MSG::WARNING << "Can not register monitoring histogram: " << m_hist_genericStatusForROB->GetName() << endreq;
+    }
+  }
+
+  // *-- Specific Status Bits for ROBs per sub detector
+  m_hist_specificStatusForROB = new TH2F ("SpecificStatusBitsForROBsFromSubDetectors",
+      "SpecificStatusBitsForROBsFromSubDetectors;;",
+      n_bins_partEBSubDet,0.,(float) n_bins_partEBSubDet,
+      m_vec_SpecificStatus.size(),0., (float) m_vec_SpecificStatus.size());
+  if (m_hist_specificStatusForROB) {
+    uint32_t n_tmp_bin = 1;
+    for (eformat::helper::EnumClass<eformat::SubDetector>::const_iterator it_sub=eformat::helper::SubDetectorDictionary.begin();
+        it_sub != eformat::helper::SubDetectorDictionary.end(); it_sub++ ) {
+      m_hist_specificStatusForROB->GetXaxis()->SetBinLabel( n_tmp_bin, (it_sub->second).c_str() );
+      n_tmp_bin++;
+    }
+
+    n_tmp_bin = 1;
+    for (std::vector<std::string>::const_iterator it = m_vec_SpecificStatus.begin();it != m_vec_SpecificStatus.end();++it) {
+      m_hist_specificStatusForROB->GetYaxis()->SetBinLabel( n_tmp_bin, (*it).c_str() );
+      n_tmp_bin++;
+    }
+    if( rootHistSvc->regHist(path + m_hist_specificStatusForROB->GetName(), m_hist_specificStatusForROB).isFailure() ) {
+      logStream() << MSG::WARNING << "Can not register monitoring histogram: " << m_hist_specificStatusForROB->GetName() << endreq;
+    }
+  }
+
+  // release histogramming service
+  rootHistSvc.release().ignore();
+} // end handler for BeginRun
+
+// helper function to retrieve ROB fragments over the network and to add them to the cache 
+void HltROBDataProviderSvc::addROBDataToCache(std::vector<uint32_t>& robIdsForRetrieval,
+					      robmonitor::ROBDataMonitorStruct* p_robMonStruct) {
+
+  struct timeval time_start;
+  struct timeval time_stop;
+
+  if(logLevel() <= MSG::DEBUG)
+    logStream() << MSG::DEBUG << " ---> addROBDataToCache: Number of ROB Ids requested for retrieval : " << robIdsForRetrieval.size() 
+    << ", Lvl1 id = " << m_currentLvl1ID << endreq;
+
+  // return if no ROBs are requested
+  if (robIdsForRetrieval.size() == 0) return;
+
+  std::vector<uint32_t> vRobIds, vMETRobIds;
+  vRobIds.reserve( robIdsForRetrieval.size() );
+  vMETRobIds.reserve( robIdsForRetrieval.size() );
+
+  // Check requested ROBs
+  for (std::vector<uint32_t>::const_iterator rob_it=robIdsForRetrieval.begin(); rob_it!=robIdsForRetrieval.end(); ++rob_it) {
+
+    // check first if ROB is already in cache
+    ONLINE_ROBMAP::iterator map_it = m_online_robmap.find(*rob_it) ;
+    if(map_it != m_online_robmap.end()) {
+      if(logLevel() <= MSG::DEBUG)
+	logStream() << MSG::DEBUG << " ---> addROBDataToCache: Found   ROB Id : 0x" << MSG::hex << (*map_it).second.source_id() << MSG::dec
+		    <<" in cache "<< endreq;
+      continue;
+    } 
+
+    // check if ROB is actually enabled for readout
+    // do not perform this check for MET ROBs
+    if ( (m_enabledROBs.value().size() != 0) && 
+	 (eformat::helper::SourceIdentifier(*rob_it).subdetector_id() != eformat::TDAQ_LAR_MET) &&
+	 (eformat::helper::SourceIdentifier(*rob_it).subdetector_id() != eformat::TDAQ_TILE_MET) ){
+      std::vector<uint32_t>::const_iterator rob_enabled_it =
+	std::find(m_enabledROBs.value().begin(), m_enabledROBs.value().end(),(*rob_it));
+      if(rob_enabled_it == m_enabledROBs.value().end()) {
+	if(logLevel() <= MSG::DEBUG)
+	  logStream() << MSG::DEBUG << " ---> addROBDataToCache: ROB Id : 0x" << MSG::hex << (*rob_it) << MSG::dec
+		      << " will be not retrieved, since it is not on the list of enabled ROBs."<< endreq;
+	continue;
+      }
+    }
+
+    // separate MET and detector ROBs if requested
+    if ( (m_separateMETandDetROBRetrieval.value()) &&
+      ( (eformat::helper::SourceIdentifier(*rob_it).subdetector_id() == eformat::TDAQ_LAR_MET) || 
+	(eformat::helper::SourceIdentifier(*rob_it).subdetector_id() == eformat::TDAQ_TILE_MET) ) )  {
+        vMETRobIds.push_back( *rob_it ) ;
+    } else {
+      vRobIds.push_back( *rob_it );
+    }
+  }
+ 
+  typedef std::vector<hltinterface::DCM_ROBInfo> ROBInfoVec;
+  ROBInfoVec vRobInfos ;
+
+  // Get ROB Fragments with DataCollector
+  if ( m_doMonitoring || p_robMonStruct ) gettimeofday(&time_start, 0);
+  if ( vRobIds.size() != 0 ) {
+    vRobInfos.reserve( vRobIds.size() ) ;
+    hltinterface::DataCollector::instance()->collect(vRobInfos, m_currentLvl1ID, vRobIds);
+  }
+
+  // Do a separate data collect call for MET ROBs if required
+  if ( (m_separateMETandDetROBRetrieval.value()) && (vMETRobIds.size() != 0) ) {
+    ROBInfoVec vMETRobInfos;
+    vMETRobInfos.reserve( vMETRobIds.size() ) ;
+    // retrieve MET ROBs
+    hltinterface::DataCollector::instance()->collect(vMETRobInfos, m_currentLvl1ID, vMETRobIds);
+
+    // add MET ROBs to Det ROBs
+    vRobInfos.insert( vRobInfos.end(), vMETRobInfos.begin(), vMETRobInfos.end() );
+  }
+
+  if((logLevel() <= MSG::DEBUG) && ((vRobIds.size()!=0) || (vMETRobIds.size()!=0))) {
+    std::ostringstream ost;
+    unsigned int rob_counter = 1;
+    for (ROBInfoVec::const_iterator rob_it = vRobInfos.begin(); rob_it != vRobInfos.end(); ++rob_it,++rob_counter)
+      ost << "       # = "<< std::setw(5) << rob_counter << " ROB id = 0x" << std::hex << rob_it->robFragment.source_id() << std::dec << "\n" ; 
+    logStream() << MSG::DEBUG 
+        << " ---> addROBDataToCache: The following ROB Ids were received from DataCollector : \n"
+        << "      Lvl1 id                                             = " << m_currentLvl1ID << "\n"
+        << "      Number of detector ROB Ids requested for retrieval  = " << vRobIds.size() << "\n"
+        << "      Number of MET ROB Ids requested for retrieval       = " << vMETRobIds.size() << "\n"
+        << "      Number of actually received ROB Ids                 = " << vRobInfos.size() << "\n"
+        << ost.str()
+        << endreq;
+  }
+
+  if ( m_doMonitoring || p_robMonStruct ) {
+    gettimeofday(&time_stop, 0);
+    int secs = 0 ;
+    if (time_stop.tv_sec >= time_start.tv_sec)
+      secs = time_stop.tv_sec - time_start.tv_sec;
+
+    int usecs = time_stop.tv_usec - time_start.tv_usec;
+    float mtime = static_cast<float>(secs)*1000 + static_cast<float>(usecs)/1000;
+
+    //* timing histogram
+    if (m_hist_timeROBretrieval) {
+      scoped_lock_histogram lock;
+      m_hist_timeROBretrieval->Fill(mtime);
+      m_hist_timeROBretrieval->LabelsDeflate("X");
+    }
+
+    //* detailed monitoring
+    if ( p_robMonStruct ) {
+      p_robMonStruct->start_time_of_ROB_request    = time_start;
+      p_robMonStruct->end_time_of_ROB_request      = time_stop;
+    }
+  }
+
+  //* histograms for number of requested/received ROBs
+  if ( m_hist_requestedROBsPerCall ) {
+    scoped_lock_histogram lock;
+    m_hist_requestedROBsPerCall->Fill(robIdsForRetrieval.size());
+    m_hist_requestedROBsPerCall->LabelsDeflate("X");
+  }
+  if ( m_hist_receivedROBsPerCall ) {
+    scoped_lock_histogram lock;
+    m_hist_receivedROBsPerCall->Fill(vRobInfos.size());
+    m_hist_receivedROBsPerCall->LabelsDeflate("X");
+  }
+
+  // add ROBs to cache
+  updateROBDataCache(vRobInfos,p_robMonStruct);
+
+  return;
+} // end void addROBDataToCache(...)
+
+
+// helper function to put retrieved ROB fragments into the local cache and update the monitoring records 
+void HltROBDataProviderSvc::updateROBDataCache(std::vector<hltinterface::DCM_ROBInfo>& vRobInfo,
+					      robmonitor::ROBDataMonitorStruct* p_robMonStruct) {
+
+  if(logLevel() <= MSG::DEBUG)
+    logStream() << MSG::DEBUG << " ---> updateROBDataCache: Number of ROB Info records for cache update : " << vRobInfo.size() 
+    << ", Lvl1 id = " << m_currentLvl1ID << endreq;
+
+  // return if no ROB Info records are available
+  if (vRobInfo.size() == 0) return;
+
+  // add ROBs to cache
+  typedef std::vector<hltinterface::DCM_ROBInfo> ROBInfoVec;
+  for(ROBInfoVec::const_iterator it=vRobInfo.begin(); it!=vRobInfo.end(); ++it) {
+    uint32_t id = it->robFragment.source_id() ;
+    if ((it->robFragment.rod_ndata() == 0) && (m_removeEmptyROB)) {
+      if(logLevel() <= MSG::DEBUG) { 
+        logStream() << MSG::DEBUG << " ---> addROBDataToCache: Empty ROB Id = 0x" << MSG::hex << id << MSG::dec
+            << " removed for L1 Id = " << m_currentLvl1ID << endreq;
+      }
+    } else if ( ROBDataProviderSvc::filterRobWithStatus(&it->robFragment)) {
+      if ((logLevel() <= MSG::DEBUG) && (it->robFragment.nstatus() > 0)) {
+        const uint32_t* it_status;
+        it->robFragment.status(it_status);
+        eformat::helper::Status tmpstatus( (*it_status) ) ;
+        logStream() << MSG::DEBUG << " ---> addROBDataToCache: ROB Id = 0x" << MSG::hex << id
+            << std::setfill( '0' )
+        << " with Generic Status Code = 0x" << std::setw(4) << tmpstatus.generic()
+        << " and Specific Status Code = 0x" << std::setw(4) << tmpstatus.specific()
+        << MSG::dec
+        << " removed for L1 Id = " << m_currentLvl1ID << endreq;
+      }
+    } else {
+      m_online_robmap[id]= (it->robFragment);
+    }
+
+    //* fill monitoring histogram for ROB generic status
+    if ( ( m_hist_genericStatusForROB ) && ( it->robFragment.nstatus() != 0 ) ) {
+      const uint32_t* it_status;
+      it->robFragment.status(it_status);
+      if ((*it_status) != 0) {
+        scoped_lock_histogram lock;
+        m_hist_genericStatusForROB->Fill(eformat::helper::SourceIdentifier(it->robFragment.source_id()).human_detector().c_str(),
+            m_map_GenericStatus[eformat::helper::Status(*it_status).generic()].c_str(),1.);
+      }
+    }
+
+    //* fill monitoring histogram for ROB specific status
+    if ( ( m_hist_specificStatusForROB ) && ( it->robFragment.nstatus() != 0 ) ) {
+      const uint32_t* it_status;
+      it->robFragment.status(it_status);
+      if ((*it_status) != 0) {
+        scoped_lock_histogram lock;
+        std::bitset<16> specificBits(eformat::helper::Status(*it_status).specific());
+        for (unsigned int index=0; index < 16; ++index) {
+          if (specificBits[index]) m_hist_specificStatusForROB->Fill(eformat::helper::SourceIdentifier(it->robFragment.source_id()).human_detector().c_str(),
+              m_vec_SpecificStatus[index].c_str(),1.);
+        }
+      }
+    }
+
+    //* detailed monitoring
+    if ( p_robMonStruct ) {
+      (p_robMonStruct->requested_ROBs)[id].rob_history = robmonitor::RETRIEVED;
+      (p_robMonStruct->requested_ROBs)[id].rob_size    = it->robFragment.fragment_size_word();
+      if ( it->robFragment.nstatus() != 0 ) {
+        const uint32_t* it_status;
+        it->robFragment.status(it_status);
+        for (uint32_t k=0; k < it->robFragment.nstatus(); k++) {
+          (p_robMonStruct->requested_ROBs)[id].rob_status_words.push_back( *(it_status+k) );
+        }
+      }
+    } // end detailed monitoring
+  }   // end loop over ROBInfo records
+  return;
+} // end void updateROBDataCache(...)
diff --git a/HLT/Trigger/TrigControl/TrigServices/src/THistSvcHLT.cxx b/HLT/Trigger/TrigControl/TrigServices/src/THistSvcHLT.cxx
new file mode 100644
index 00000000000..47a3bf6730b
--- /dev/null
+++ b/HLT/Trigger/TrigControl/TrigServices/src/THistSvcHLT.cxx
@@ -0,0 +1,2089 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifdef __ICC
+// disable icc remark #2259: non-pointer conversion from "X" to "Y" may lose significant bits
+//   TODO: To be removed, since it comes from ROOT TMathBase.h
+#pragma warning(disable:2259)
+#endif
+
+#include "THistSvcHLT.h"
+
+#include "GaudiKernel/ISvcLocator.h"
+#include "GaudiKernel/AttribStringParser.h"
+#include "GaudiKernel/GaudiException.h"
+#include "GaudiKernel/Property.h"
+#include "GaudiKernel/IIncidentSvc.h"
+#include "GaudiKernel/FileIncident.h"
+#include "GaudiKernel/IEventProcessor.h"
+#include "GaudiKernel/IJobOptionsSvc.h"
+#include "GaudiKernel/IIoComponentMgr.h"
+#include "GaudiKernel/IFileMgr.h"
+#include "boost/algorithm/string/case_conv.hpp"
+
+#include "TROOT.h"
+#include "TFile.h"
+#include "TDirectory.h"
+#include "TKey.h"
+#include "TError.h"
+#include "TGraph.h"
+
+#include <sstream>
+#include <streambuf>
+#include <cstdio>
+
+using namespace std;
+
+
+DECLARE_COMPONENT(THistSvcHLT)
+
+namespace {
+
+template <typename InputIterator, typename OutputIterator, typename UnaryOperation, typename UnaryPredicate>
+OutputIterator transform_if( InputIterator first, InputIterator last,
+                             OutputIterator result,
+                             UnaryOperation op, 
+                             UnaryPredicate pred) {
+    while (first != last) {
+        if (pred(*first)) *result++ = op(*first);
+        ++first;
+    }
+    return result;
+}
+
+constexpr struct select1st_t {
+    template <typename T, typename S> 
+    const T& operator()(const std::pair<T,S>& p) const { return p.first; }
+} select1st {} ;
+
+
+}
+
+
+//*************************************************************************//
+
+THistSvcHLT::THistSvcHLT( const std::string& name, ISvcLocator* svc )
+  : base_class(name, svc), m_log(msgSvc(), name )
+{    
+  declareProperty ("AutoSave", m_autoSave=0 );
+  declareProperty ("AutoFlush", m_autoFlush=0 );
+  declareProperty ("PrintAll", m_print=false);
+  declareProperty ("MaxFileSize", m_maxFileSize=10240,
+		   "maximum file size in MB. if exceeded, will cause an abort. -1 to never check.");
+  declareProperty ("CompressionLevel", m_compressionLevel=1 )->declareUpdateHandler( &THistSvcHLT::setupCompressionLevel, this );
+  declareProperty ("Output", m_outputfile )->declareUpdateHandler( &THistSvcHLT::setupOutputFile, this );
+  declareProperty ("Input", m_inputfile )->declareUpdateHandler ( &THistSvcHLT::setupInputFile,  this );
+}
+
+//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
+
+StatusCode
+THistSvcHLT::initialize() {
+  GlobalDirectoryRestore restore;
+
+  // Super ugly hack to make sure we have the OutputLevel set first, so we
+  // can see DEBUG printouts in update handlers.
+  auto jos = serviceLocator()->service<IJobOptionsSvc>( "JobOptionsSvc", true );
+  if( jos ) { 
+    const auto props = jos->getProperties( name() );
+
+    if ( props ) {
+      auto i = std::find_if(std::begin(*props),std::end(*props),
+                            [](const Property* p) { return p->name() == "OutputLevel"; } );
+      if ( i != std::end(*props)) {
+          setProperty( **i ).ignore();
+          m_log.setLevel( m_outputLevel.value() );
+      }
+    }
+  }
+
+
+  StatusCode status = Service::initialize();
+  m_log.setLevel( m_outputLevel.value() );
+
+  if (status.isFailure()) {
+    m_log << MSG::ERROR << "initializing service" << endmsg;
+    return status;
+  }
+
+  StatusCode st(StatusCode::SUCCESS);
+
+  try {
+    setupOutputFile( m_outputfile );
+  } catch ( GaudiException& err ) {
+    m_log << MSG::ERROR
+          << "Caught: " << err << endmsg;
+    st = StatusCode::FAILURE;
+  }
+
+  try {
+    setupInputFile( m_inputfile );
+  } catch ( GaudiException& err ) {
+    m_log << MSG::ERROR
+          << "Caught: " << err << endmsg;
+    st = StatusCode::FAILURE;
+  }
+
+  // Protect against multiple instances of TROOT
+  if ( !gROOT )   {
+    static TROOT root("root","ROOT I/O");
+    //    gDebug = 99;
+  } else {
+    if (m_log.level() <= MSG::VERBOSE)
+      m_log << MSG::VERBOSE << "ROOT already initialized, debug = "
+            << gDebug<< endmsg;
+  }
+
+  if (service("IncidentSvc", p_incSvc, true).isFailure()) {
+    m_log << MSG::ERROR << "unable to get the IncidentSvc" << endmsg;
+    st = StatusCode::FAILURE;
+  } else {
+    p_incSvc->addListener( this, "EndEvent", 100, true);
+  }
+
+  if (service("FileMgr",p_fileMgr,true).isFailure()) {
+    m_log << MSG::ERROR << "unable to get the FileMgr" << endmsg;
+    st = StatusCode::FAILURE;
+  } else {
+    m_log << MSG::DEBUG << "got the FileMgr" << endmsg;
+  }
+
+
+  // Register open/close callback actions
+
+  using namespace std::placeholders;
+  auto boa = [this](const Io::FileAttr* fa, const std::string& caller) { return this->rootOpenAction(fa,caller); };
+  if (p_fileMgr->regAction(boa, Io::OPEN, Io::ROOT).isFailure()) {
+    m_log << MSG::ERROR
+	  << "unable to register ROOT file open action with FileMgr"
+	  << endmsg;
+  }
+  auto bea = [this](const Io::FileAttr* fa, const std::string& caller) { return this->rootOpenErrAction(fa,caller); };
+  if (p_fileMgr->regAction(bea, Io::OPEN_ERR, Io::ROOT).isFailure()) {
+    m_log << MSG::ERROR
+	  << "unable to register ROOT file open Error action with FileMgr"
+	  << endmsg;
+  }
+
+
+  m_okToConnect = true;
+
+  if (m_delayConnect) {
+    if (!m_inputfile.value().empty()) { setupInputFile(m_inputfile); }
+    if (!m_outputfile.value().empty()) { setupOutputFile(m_outputfile); }
+
+    m_delayConnect = false;
+
+  }
+  m_alreadyConnectedOutFiles.clear();
+  m_alreadyConnectedInFiles.clear();
+
+
+  IIoComponentMgr* iomgr = nullptr;
+
+  if (service("IoComponentMgr", iomgr, true).isFailure()) {
+    m_log << MSG::ERROR << "unable to get the IoComponentMgr" << endmsg;
+    st = StatusCode::FAILURE;
+  } else {
+
+    if ( !iomgr->io_register (this).isSuccess() ) {
+      m_log << MSG::ERROR
+            << "could not register with the I/O component manager !"
+            << endmsg;
+      st = StatusCode::FAILURE;
+    } else {
+      bool all_good = true;
+      // register input/output files...
+      for ( const auto& reg : m_files ) { 
+        const std::string& fname = reg.second.first->GetName();
+        const IIoComponentMgr::IoMode::Type iomode =
+          ( reg.second.second==THistSvcHLT::READ
+	    ? IIoComponentMgr::IoMode::READ
+	    : IIoComponentMgr::IoMode::WRITE );
+        if ( !iomgr->io_register (this, iomode, fname).isSuccess () ) {
+          m_log << MSG::WARNING << "could not register file ["
+                << fname << "] with the I/O component manager..." << endmsg;
+          all_good = false;
+        } else {
+          m_log << MSG::INFO << "registered file [" << fname << "]... [ok]"
+              << endmsg;
+        }
+      }
+      if (!all_good) {
+        m_log << MSG::ERROR
+              << "problem while registering input/output files with "
+              << "the I/O component manager !" << endmsg;
+        st = StatusCode::FAILURE;
+      }
+    }
+
+  }
+
+  if (st.isFailure()) {
+    m_log << MSG::FATAL << "Unable to initialize THistSvcHLT" << endmsg;
+  }
+
+  return st;
+
+}
+
+//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
+
+StatusCode
+THistSvcHLT::reinitialize() {
+
+  GlobalDirectoryRestore restore;
+  m_log << MSG::WARNING << "reinitialize not implemented" << endmsg;
+  return StatusCode::SUCCESS;
+
+}
+
+//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
+
+StatusCode
+THistSvcHLT::finalize() {
+
+  GlobalDirectoryRestore restore;
+
+  if (m_log.level() <= MSG::DEBUG)
+    m_log << MSG::DEBUG << "THistSvcHLT::finalize" << endmsg;
+
+#ifndef NDEBUG
+  if (m_log.level() <= MSG::DEBUG) {
+  for (const auto& uid : m_uids ) {
+
+    TObject* to = uid.second.obj;
+
+    string dirname("none");
+      if (to && to->IsA()->InheritsFrom("TTree")) {
+      TTree* tr = dynamic_cast<TTree*>(to);
+      if (tr->GetDirectory() != 0) {
+        dirname = tr->GetDirectory()->GetPath();
+      }
+      } else if (to && to->IsA()->InheritsFrom("TGraph")) {
+      if (!uid.second.temp) {
+        dirname = uid.second.file->GetPath();
+        string id2(uid.second.id);
+        id2.erase(0,id2.find("/",1));
+        id2.erase(id2.rfind("/"), id2.length());
+        if (id2.find("/") == 0) {
+          id2.erase(0,1);
+        }
+        dirname += id2;
+      } else {
+        dirname = "/tmp";
+      }
+      } else if (to && to->IsA()->InheritsFrom("TH1")) {
+      TH1* th = dynamic_cast<TH1*>(to);
+      if (th == 0) {
+        m_log << MSG::ERROR << "Couldn't dcast: " << uid.first << endmsg;
+      } else {
+        if (th->GetDirectory() != 0) {
+          dirname = th->GetDirectory()->GetPath();
+        }
+      }
+      } else if (! to ) {
+	m_log << MSG::WARNING << uid.first << " has NULL TObject ptr"
+	      << endmsg;
+    }
+
+      m_log << MSG::DEBUG << "uid: \"" << uid.first << "\"  temp: "
+            << uid.second.temp << "  dir: " << dirname
+            << endmsg;
+  }
+  }
+#endif
+
+  StatusCode sc = write();
+  if (sc.isFailure()) {
+    m_log << MSG::ERROR << "problems writing histograms" << endmsg;
+  }
+
+  if (m_print) {
+    m_log << MSG::INFO << "Listing contents of ROOT files: " << endmsg;
+  }
+  vector<TFile*> deleted_files;
+  for (auto& itr : m_files ) {
+
+    if (find(deleted_files.begin(), deleted_files.end(), itr.second.first) ==
+        deleted_files.end()) {
+      deleted_files.push_back(itr.second.first);
+
+#ifndef NDEBUG
+      if (m_log.level() <= MSG::DEBUG)
+        m_log << MSG::DEBUG << "finalizing stream/file " << itr.first << ":"
+              << itr.second.first->GetName()
+              << endmsg;
+#endif
+    } else {
+#ifndef NDEBUG
+      if (m_log.level() <= MSG::DEBUG)
+        m_log << MSG::DEBUG << "already finalized stream " << itr.first << endmsg;
+#endif
+      continue;
+    }
+
+
+    if (m_print && m_log.level() <= MSG::INFO) {
+
+      m_log << MSG::INFO;
+      m_log << "==> File: " << itr.second.first->GetName()
+            << "  stream: " << itr.first << endmsg;
+
+      itr.second.first->Print("base");
+    }
+
+    string tmpfn=itr.second.first->GetName();
+
+    p_fileMgr->close(itr.second.first, name());
+
+    IIncidentSvc *pi = nullptr;
+    if (service("IncidentSvc",pi).isFailure()) {
+      m_log << MSG::ERROR << "Unable to get the IncidentSvc" << endmsg;
+      return StatusCode::FAILURE;
+    }
+
+    if (itr.second.second==SHARE) {
+
+      //Merge File
+      void* vf = nullptr;
+      int r = p_fileMgr->open(Io::ROOT,name(), m_sharedFiles[itr.first],
+			      Io::WRITE|Io::APPEND,vf,"HIST");
+
+      if (r) {
+	m_log << MSG::ERROR << "unable to open Final Output File: \""
+	      << m_sharedFiles[itr.first] << "\" for merging"
+	      << endmsg;
+        return StatusCode::FAILURE;
+      }
+
+      TFile *outputfile = (TFile*) vf;
+      pi->fireIncident(FileIncident(name(), IncidentType::WroteToOutputFile,
+                                     m_sharedFiles[itr.first]));
+
+      if (m_log.level() <= MSG::DEBUG)
+        m_log << MSG::DEBUG << "THistSvcHLT::write()::Merging Rootfile "<<endmsg;
+
+      vf = nullptr;
+      r = p_fileMgr->open(Io::ROOT,name(),tmpfn,Io::READ,vf,"HIST");
+
+      if (r) {
+	m_log << MSG::ERROR << "unable to open temporary file: \""
+	      << tmpfn << endmsg;
+        return StatusCode::FAILURE;
+      }
+
+      TFile *inputfile = (TFile*) vf;
+
+      outputfile->SetCompressionLevel( inputfile->GetCompressionLevel() );
+
+      MergeRootFile(outputfile, inputfile);
+
+      outputfile->Write();
+      p_fileMgr->close(outputfile,name());
+      p_fileMgr->close(inputfile,name());
+
+      if (m_log.level() <= MSG::DEBUG)
+        m_log << MSG::DEBUG << "Trying to remove temporary file \"" << tmpfn
+              << "\""<<endmsg;
+
+      std::remove(tmpfn.c_str());
+    }
+    delete itr.second.first;
+  }
+
+  m_sharedFiles.clear();
+  m_fileStreams.clear();
+  m_files.clear();
+  m_uids.clear();
+  m_ids.clear();
+  m_tobjs.clear();
+
+  return Service::finalize();
+}
+
+//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
+
+bool
+THistSvcHLT::browseTDir(TDirectory *dir) const {
+
+  if (!dir) {
+    std::cerr << "TDirectory == 0" << std::endl;
+    return false;
+  }
+
+  GlobalDirectoryRestore restore;
+
+  dir->cd();
+
+
+  cout << "-> " << dir->GetPath() << "  "
+       << dir->GetListOfKeys()->GetSize() << endl;
+
+  //  TIter nextkey(dir->GetListOfKeys());
+  TIter nextkey(dir->GetList());
+  while (TKey *key = (TKey*)nextkey()) {
+
+    TObject *obj = key->ReadObj();
+    if (!obj) { cout << key->GetName() << " obj==0"<< endl; continue; }
+    //    if (obj->IsA()->InheritsFrom("TDirectory")) {
+      cout << "  Key: " << key->GetName() << "   "
+           << " tit: " << obj->GetTitle() << "   "
+           << " (" << key->GetClassName() << ")" << endl;
+      //    }
+  }
+
+  nextkey = dir->GetListOfKeys();
+  while (TKey *key = (TKey*)nextkey()) {
+
+    TObject *obj = key->ReadObj();
+    if (!obj) { cout << key->GetName() << " obj==0"<< endl; continue; }
+    if (obj->IsA()->InheritsFrom("TDirectory")) {
+      TDirectory *tt = dynamic_cast<TDirectory*>(obj);
+      browseTDir(tt);
+    }
+  }
+
+  return true;
+}
+
+
+//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
+
+StatusCode
+THistSvcHLT::getTHists(TDirectory *td, TList & tl, bool rcs) const {
+  GlobalDirectoryRestore restore;
+
+  gErrorIgnoreLevel = kBreak;
+
+  if (!td->cd()) {
+    m_log << MSG::ERROR << "getTHists: No such TDirectory \"" << td->GetPath()
+          << "\"" << endmsg;
+    return StatusCode::FAILURE;
+  }
+
+  if (m_log.level() <= MSG::DEBUG)
+    m_log << MSG::DEBUG << "getTHists: \"" << td->GetPath() << "\": found "
+          << td->GetListOfKeys()->GetSize() << " keys" << endmsg;
+
+  TIter nextkey(td->GetListOfKeys());
+  while (TKey *key = (TKey*)nextkey()) {
+    if (m_log.level() <= MSG::DEBUG)
+      m_log << MSG::DEBUG << "  key: " << key->GetName();
+    TObject *obj = key->ReadObj();
+    if (obj != 0 && obj->IsA()->InheritsFrom("TDirectory")) {
+      if (m_log.level() <= MSG::DEBUG)
+        m_log << " (" << obj->IsA()->GetName() << ")";
+    } else if (obj != 0 && obj->IsA()->InheritsFrom("TH1")) {
+      if (m_log.level() <= MSG::DEBUG)
+        m_log << " (" << obj->IsA()->GetName() << ")";
+      tl.Add(obj);
+    } else if (obj != 0) {
+      if (m_log.level() <= MSG::DEBUG)
+        m_log << " [" << obj->IsA()->GetName() << "]";
+    }
+    if (m_log.level() <= MSG::DEBUG)
+      m_log << endmsg;
+  }
+
+  // operate recursively
+  if (rcs) {
+    nextkey = td->GetListOfKeys();
+    while (TKey *key = (TKey*)nextkey()) {
+      TObject *obj = key->ReadObj();
+      if (obj && obj->IsA()->InheritsFrom("TDirectory")) {
+          TDirectory *tt = dynamic_cast<TDirectory*>(obj);
+          getTHists(tt, tl, rcs);
+      }
+    }
+  }
+
+  return StatusCode::SUCCESS;
+
+
+}
+
+//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
+
+StatusCode
+THistSvcHLT::getTHists(const std::string& dir, TList & tl, bool rcs) const {
+
+  GlobalDirectoryRestore restore;
+
+  gErrorIgnoreLevel = kBreak;
+
+  StatusCode sc;
+
+  std::string stream,rem,r2;
+  parseString(dir,stream,rem);
+
+  auto itr = m_files.find(stream);
+  if (itr != m_files.end()) {
+    r2 = itr->second.first->GetName();
+    r2 += ":/";
+    r2 += rem;
+
+    if (m_log.level() <= MSG::DEBUG)
+      m_log << MSG::DEBUG << "getTHists: \"" << dir
+            << "\" looks like a stream name."  << " associated TFile: \""
+            << itr->second.first->GetName() << "\"" << endmsg;
+
+    if (gDirectory->cd(r2.c_str())) {
+      m_curstream = stream;
+      sc = getTHists(gDirectory,tl,rcs);
+      m_curstream = "";
+      return sc;
+    } else {
+      if (m_log.level() <= MSG::DEBUG)
+        m_log << MSG::DEBUG << "getTHists: no such TDirectory \""
+              << r2 << "\"" << endmsg;
+    }
+
+  } else {
+    if (m_log.level() <= MSG::DEBUG)
+      m_log << MSG::DEBUG << "getTHists: stream \"" << stream << "\" not found"
+            << endmsg;
+  }
+
+  if (!gDirectory->cd(dir.c_str())) {
+    m_log << MSG::ERROR << "getTHists: No such TDirectory/stream \"" << dir
+          << "\"" << endmsg;
+    sc = StatusCode::FAILURE;
+  } else {
+    sc = getTHists(gDirectory,tl,rcs);
+  }
+
+  return sc;
+
+}
+//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
+
+StatusCode
+THistSvcHLT::getTTrees(TDirectory *td, TList & tl, bool rcs) const {
+  GlobalDirectoryRestore restore;
+
+  gErrorIgnoreLevel = kBreak;
+
+  if (!td->cd()) {
+    m_log << MSG::ERROR << "getTTrees: No such TDirectory \""
+          << td->GetPath() << "\"" << endmsg;
+    return StatusCode::FAILURE;
+  }
+
+  if (m_log.level() <= MSG::DEBUG)
+    m_log << MSG::DEBUG << "getTHists: \"" << td->GetPath() << "\": found "
+          << td->GetListOfKeys()->GetSize() << " keys" << endmsg;
+
+  TIter nextkey(td->GetListOfKeys());
+  while (TKey *key = (TKey*)nextkey()) {
+    if (m_log.level() <= MSG::DEBUG)
+      m_log << MSG::DEBUG << "  key: " << key->GetName();
+    TObject *obj = key->ReadObj();
+    if (obj != 0 && obj->IsA()->InheritsFrom("TDirectory")) {
+      if (m_log.level() <= MSG::DEBUG)
+        m_log << " (" << obj->IsA()->GetName() << ")";
+    } else if (obj != 0 && obj->IsA()->InheritsFrom("TTree")) {
+      if (m_log.level() <= MSG::DEBUG)
+        m_log << " (" << obj->IsA()->GetName() << ")";
+      tl.Add(obj);
+    } else if (obj != 0) {
+      if (m_log.level() <= MSG::DEBUG)
+        m_log << " [" << obj->IsA()->GetName() << "]";
+    }
+    m_log << endmsg;
+  }
+
+  // operate recursively
+  if (rcs) {
+    nextkey = td->GetListOfKeys();
+    while (TKey *key = (TKey*)nextkey()) {
+      TObject *obj = key->ReadObj();
+      if (obj && obj->IsA()->InheritsFrom("TDirectory")) {
+          TDirectory *tt = dynamic_cast<TDirectory*>(obj);
+          getTTrees(tt, tl, rcs);
+      }
+    }
+  }
+
+  return StatusCode::SUCCESS;
+
+}
+
+//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
+
+StatusCode
+THistSvcHLT::getTTrees(const std::string& dir, TList & tl, bool rcs) const {
+  GlobalDirectoryRestore restore;
+
+  gErrorIgnoreLevel = kBreak;
+
+  StatusCode sc;
+
+  std::string stream,rem,r2;
+  parseString(dir,stream,rem);
+
+  auto itr = m_files.find(stream);
+  if (itr != m_files.end()) {
+    r2 = itr->second.first->GetName();
+    r2 += ":/";
+    r2 += rem;
+
+    if (m_log.level() <= MSG::DEBUG)
+      m_log << MSG::DEBUG << "getTTrees: \"" << dir
+            << "\" looks like a stream name."  << " associated TFile: \""
+            << itr->second.first->GetName() << "\"" << endmsg;
+
+    if (gDirectory->cd(r2.c_str())) {
+      return getTTrees(gDirectory,tl,rcs);
+    }
+    if (m_log.level() <= MSG::DEBUG)
+      m_log << MSG::DEBUG << "getTTrees: no such TDirectory \""
+            << r2 << "\"" << endmsg;
+  } else {
+    if (m_log.level() <= MSG::DEBUG)
+      m_log << MSG::DEBUG << "getTTrees: stream \"" << stream << "\" not found"
+            << endmsg;
+  }
+
+  if (!gDirectory->cd(dir.c_str())) {
+    m_log << MSG::ERROR << "getTTrees: No such TDirectory/stream \"" << dir
+          << "\"" << endmsg;
+    sc = StatusCode::FAILURE;
+  } else {
+    sc = getTTrees(gDirectory,tl,rcs);
+  }
+  return sc;
+}
+
+
+//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
+
+StatusCode
+THistSvcHLT::getTHists(TDirectory *td, TList & tl, bool rcs, bool reg) {
+
+  GlobalDirectoryRestore restore;
+
+  gErrorIgnoreLevel = kBreak;
+
+  if (!td->cd()) {
+    m_log << MSG::ERROR << "getTHists: No such TDirectory \"" << td->GetPath()
+          << "\"" << endmsg;
+    return StatusCode::FAILURE;
+  }
+
+  if (m_log.level() <= MSG::DEBUG)
+    m_log << MSG::DEBUG << "getTHists: \"" << td->GetPath() << "\": found "
+          << td->GetListOfKeys()->GetSize() << " keys" << endmsg;
+
+  TIter nextkey(td->GetListOfKeys());
+  while (TKey *key = (TKey*)nextkey()) {
+    if (m_log.level() <= MSG::DEBUG)
+      m_log << MSG::DEBUG << "  key: " << key->GetName();
+    TObject *obj = key->ReadObj();
+    if (obj && obj->IsA()->InheritsFrom("TDirectory")) {
+      if (m_log.level() <= MSG::DEBUG)
+        m_log << " (" << obj->IsA()->GetName() << ")";
+    } else if (obj && obj->IsA()->InheritsFrom("TH1")) {
+      if (m_log.level() <= MSG::DEBUG)
+        m_log << " (" << obj->IsA()->GetName() << ")";
+      tl.Add(obj);
+      if (reg && m_curstream != "") {
+        string dir = td->GetPath();
+        string fil = td->GetFile()->GetName();
+        dir.erase(0,fil.length()+1);
+        string id = "/" + m_curstream;
+        if ( dir == "/" ) {
+          id = id + "/" + key->GetName();
+        } else {
+          id = id + dir + "/" + key->GetName();
+        }
+        if (!exists(id)) {
+          if (m_log.level() <= MSG::DEBUG)
+            m_log << "  reg as \"" << id << "\"";
+          regHist(id).ignore();
+        } else {
+          if (m_log.level() <= MSG::DEBUG)
+            m_log << "  already registered";
+        }
+      }
+    } else if (obj) {
+      if (m_log.level() <= MSG::DEBUG)
+        m_log << " [" << obj->IsA()->GetName() << "]";
+    }
+    if (m_log.level() <= MSG::DEBUG)
+      m_log << endmsg;
+  }
+
+  // operate recursively
+  if (rcs) {
+    nextkey = td->GetListOfKeys();
+    while (TKey *key = (TKey*)nextkey()) {
+      TObject *obj = key->ReadObj();
+      if (obj && obj->IsA()->InheritsFrom("TDirectory")) {
+          TDirectory *tt = dynamic_cast<TDirectory*>(obj);
+          getTHists(tt, tl, rcs, reg);
+      }
+    }
+  }
+
+  return StatusCode::SUCCESS;
+
+}
+
+//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
+
+StatusCode
+THistSvcHLT::getTHists(const std::string& dir, TList & tl, bool rcs, bool reg) {
+
+  GlobalDirectoryRestore restore;
+
+  gErrorIgnoreLevel = kBreak;
+
+  StatusCode sc;
+
+  std::string stream,rem,r2;
+  parseString(dir,stream,rem);
+
+  auto itr = m_files.find(stream);
+  if (itr != m_files.end()) {
+    r2 = itr->second.first->GetName();
+    r2 += ":/";
+    r2 += rem;
+
+    if (m_log.level() <= MSG::DEBUG)
+      m_log << MSG::DEBUG << "getTHists: \"" << dir
+            << "\" looks like a stream name."  << " associated TFile: \""
+            << itr->second.first->GetName() << "\"" << endmsg;
+
+    if (gDirectory->cd(r2.c_str())) {
+      m_curstream = stream;
+      sc = getTHists(gDirectory,tl,rcs,reg);
+      m_curstream.clear();
+      return sc;
+    } 
+    if (m_log.level() <= MSG::DEBUG)
+      m_log << MSG::DEBUG << "getTHists: no such TDirectory \""
+            << r2 << "\"" << endmsg;
+
+  } else {
+    if (m_log.level() <= MSG::DEBUG)
+      m_log << MSG::DEBUG << "getTHists: stream \"" << stream << "\" not found"
+            << endmsg;
+  }
+
+  if (!gDirectory->cd(dir.c_str())) {
+    m_log << MSG::ERROR << "getTHists: No such TDirectory/stream \"" << dir
+          << "\"" << endmsg;
+    sc = StatusCode::FAILURE;
+  } else {
+    if (reg) {
+      m_log << MSG::WARNING << "Unable to register histograms automatically "
+            << "without a valid stream name" << endmsg;
+      reg = false;
+    }
+    sc = getTHists(gDirectory,tl,rcs,reg);
+  }
+
+  return sc;
+
+}
+//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
+
+StatusCode
+THistSvcHLT::getTTrees(TDirectory *td, TList & tl, bool rcs, bool reg) {
+
+  GlobalDirectoryRestore restore;
+
+  gErrorIgnoreLevel = kBreak;
+
+  if (!td->cd()) {
+    m_log << MSG::ERROR << "getTTrees: No such TDirectory \""
+          << td->GetPath() << "\"" << endmsg;
+    return StatusCode::FAILURE;
+  }
+
+  if (m_log.level() <= MSG::DEBUG)
+    m_log << MSG::DEBUG << "getTHists: \"" << td->GetPath() << "\": found "
+          << td->GetListOfKeys()->GetSize() << " keys" << endmsg;
+
+  TIter nextkey(td->GetListOfKeys());
+  while (TKey *key = (TKey*)nextkey()) {
+    if (m_log.level() <= MSG::DEBUG)
+      m_log << MSG::DEBUG << "  key: " << key->GetName();
+    TObject *obj = key->ReadObj();
+    if (obj && obj->IsA()->InheritsFrom("TDirectory")) {
+      if (m_log.level() <= MSG::DEBUG)
+        m_log << " (" << obj->IsA()->GetName() << ")";
+    } else if (obj && obj->IsA()->InheritsFrom("TTree")) {
+      if (m_log.level() <= MSG::DEBUG)
+        m_log << " (" << obj->IsA()->GetName() << ")";
+      tl.Add(obj);
+      if (reg && m_curstream != "") {
+        string dir = td->GetPath();
+        string fil = td->GetFile()->GetName();
+        dir.erase(0,fil.length()+1);
+        string id = "/" + m_curstream;
+        if ( dir == "/" ) {
+          id = id + "/" + key->GetName();
+        } else {
+          id = id + dir + "/" + key->GetName();
+        }
+        if (!exists(id)) {
+          if (m_log.level() <= MSG::DEBUG)
+            m_log << "  reg as \"" << id << "\"";
+          regHist(id).ignore();
+        } else {
+          if (m_log.level() <= MSG::DEBUG)
+            m_log << "  already registered";
+        }
+      }
+    } else if (obj != 0) {
+      if (m_log.level() <= MSG::DEBUG)
+        m_log << " [" << obj->IsA()->GetName() << "]";
+    }
+    if (m_log.level() <= MSG::DEBUG)
+      m_log << endmsg;
+  }
+
+  // operate recursively
+  if (rcs) {
+    nextkey = td->GetListOfKeys();
+    while (TKey *key = (TKey*)nextkey()) {
+      TObject *obj = key->ReadObj();
+      if (obj && obj->IsA()->InheritsFrom("TDirectory")) {
+          TDirectory *tt = dynamic_cast<TDirectory*>(obj);
+          getTTrees(tt, tl, rcs, reg);
+      }
+    }
+  }
+
+  return StatusCode::SUCCESS;
+
+}
+
+//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
+
+StatusCode
+THistSvcHLT::getTTrees(const std::string& dir, TList & tl, bool rcs, bool reg) {
+
+  GlobalDirectoryRestore restore;
+
+  gErrorIgnoreLevel = kBreak;
+
+  StatusCode sc;
+
+  std::string stream,rem,r2;
+  parseString(dir,stream,rem);
+
+  auto itr = m_files.find(stream);
+  if (itr != m_files.end()) {
+    r2 = itr->second.first->GetName();
+    r2 += ":/";
+    r2 += rem;
+
+    if (m_log.level() <= MSG::DEBUG)
+      m_log << MSG::DEBUG << "getTTrees: \"" << dir
+            << "\" looks like a stream name."  << " associated TFile: \""
+            << itr->second.first->GetName() << "\"" << endmsg;
+
+    if (gDirectory->cd(r2.c_str())) {
+      return getTTrees(gDirectory,tl,rcs,reg);
+    } else {
+      if (m_log.level() <= MSG::DEBUG)
+        m_log << MSG::DEBUG << "getTTrees: no such TDirectory \""
+              << r2 << "\"" << endmsg;
+    }
+
+  } else {
+    if (m_log.level() <= MSG::DEBUG)
+      m_log << MSG::DEBUG << "getTTrees: stream \"" << stream << "\" not found"
+            << endmsg;
+  }
+
+  if (!gDirectory->cd(dir.c_str())) {
+    m_log << MSG::ERROR << "getTTrees: No such TDirectory/stream \"" << dir
+          << "\"" << endmsg;
+    return StatusCode::FAILURE;
+  } 
+
+  return getTTrees(gDirectory,tl,rcs,reg);
+
+}
+
+//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
+
+StatusCode
+THistSvcHLT::deReg(TObject* obj) {
+
+  auto itr = m_tobjs.find(obj);
+  if (itr != m_tobjs.end()) {
+    THistID hid = itr->second;
+
+    auto itr2 = m_uids.find(hid.id);
+    if (itr2 == m_uids.end()) {
+      m_log << MSG::ERROR << "Problems deregistering TObject \""
+            << obj->GetName()
+            << "\" with id \"" << hid.id << "\"" << endmsg;
+      return StatusCode::FAILURE;
+    }
+
+    std::string id,root,rem;
+    parseString(hid.id, root, rem);
+
+    auto mitr = m_ids.equal_range(rem);
+    auto itr3 = std::find_if( mitr.first, mitr.second, [&](idMap::const_reference i) 
+                                   { return i.second.obj == obj; } ) ;
+    if (itr3 != mitr.second ) {
+      m_log << MSG::ERROR << "Problems deregistering TObject \""
+            << obj->GetName()
+            << "\" with id \"" << hid.id << "\"" << endmsg;
+      return StatusCode::FAILURE;
+    }
+
+    m_tobjs.erase(itr);
+    m_uids.erase(itr2);
+    m_ids.erase(itr3);
+
+    return StatusCode::SUCCESS;
+
+  } else {
+    m_log << MSG::ERROR << "Cannot unregister TObject \"" << obj->GetName()
+          << "\": not known to THistSvcHLT" << endmsg;
+    return StatusCode::FAILURE;
+  }
+
+}
+
+
+//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
+
+StatusCode
+THistSvcHLT::deReg(const std::string& id) {
+
+  auto itr = m_uids.find(id);
+  if (itr == m_uids.end()) {
+    m_log << MSG::ERROR << "Problems deregistering id \""
+          << id << "\"" << endmsg;
+    return StatusCode::FAILURE;
+  }
+
+  TObject* obj = itr->second.obj;
+  return deReg(obj);
+}
+
+//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
+
+StatusCode
+THistSvcHLT::regHist(const std::string& id) {
+
+  TH1 *hist = nullptr;
+  return regHist_i(hist, id);
+}
+
+//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
+
+StatusCode
+THistSvcHLT::regHist(const std::string& id, TH1* hist) {
+  return regHist_i(hist, id);
+}
+
+//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
+
+StatusCode
+THistSvcHLT::regHist(const std::string& id, TH2* hist) {
+  return regHist_i(hist, id);
+}
+
+//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
+
+StatusCode
+THistSvcHLT::regHist(const std::string& id, TH3* hist) {
+  return regHist_i(hist, id);
+}
+
+//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
+
+StatusCode
+THistSvcHLT::regTree(const std::string& id) {
+  TTree *hist = nullptr;
+  return regHist_i(hist, id);
+}
+
+//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
+
+StatusCode
+THistSvcHLT::regTree(const std::string& id, TTree* hist) {
+  StatusCode sc = regHist_i(hist, id);
+  if (hist && sc.isSuccess()) {
+    if (m_autoSave != 0) hist->SetAutoSave(m_autoSave);
+    hist->SetAutoFlush(m_autoFlush);
+  }
+  return sc;
+}
+
+//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
+
+StatusCode
+THistSvcHLT::regGraph(const std::string& id) {
+  TGraph *hist = nullptr;
+  return regHist_i(hist, id);
+}
+
+//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
+
+StatusCode
+THistSvcHLT::regGraph(const std::string& id, TGraph* hist) {
+  if ( strcmp(hist->GetName(),"Graph") == 0 ) {
+
+    std::string id2(id);
+    string::size_type i = id2.rfind("/");
+    if (i != string::npos) {
+      id2.erase(0,i+1);
+    }
+
+    m_log << MSG::INFO << "setting name of TGraph id: \"" << id << "\" to \""
+          << id2 << "\" since it is unset" << endmsg;
+    hist->SetName(id2.c_str());
+  }
+
+  return regHist_i(hist, id);
+}
+
+//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
+
+StatusCode
+THistSvcHLT::getHist(const std::string& id, TH1*& hist) const {
+  return getHist_i(id, hist);
+}
+
+//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
+
+StatusCode
+THistSvcHLT::getHist(const std::string& id, TH2*& hist) const {
+  return getHist_i(id, hist);
+}
+
+//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
+
+StatusCode
+THistSvcHLT::getHist(const std::string& id, TH3*& hist) const {
+  return getHist_i(id, hist);
+}
+
+//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
+
+std::vector<std::string>
+THistSvcHLT::getHists() const {
+
+  std::vector<std::string> names;
+  names.reserve(m_uids.size());
+  transform_if( std::begin(m_uids), std::end(m_uids),
+                std::back_inserter(names), select1st,
+                [](uidMap::const_reference i) { 
+                    return i.second.obj->IsA()->InheritsFrom("TH11"); }
+  );
+  return names;
+
+}
+//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
+
+StatusCode
+THistSvcHLT::getTree(const std::string& id, TTree*& hist) const {
+  return getHist_i(id, hist);
+}
+
+//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
+
+std::vector<std::string>
+THistSvcHLT::getTrees() const {
+
+  std::vector<std::string> names;
+  names.reserve(m_uids.size());
+  transform_if( std::begin(m_uids), std::end(m_uids),
+                std::back_inserter(names),
+                select1st,
+                [](uidMap::const_reference i) { 
+                    return i.second.obj->IsA()->InheritsFrom("TTree"); }
+  );
+  return names;
+
+}
+//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
+
+StatusCode
+THistSvcHLT::getGraph(const std::string& id, TGraph*& hist) const {
+  return getHist_i(id, hist);
+}
+
+//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
+
+std::vector<std::string>
+THistSvcHLT::getGraphs() const {
+
+  std::vector<std::string> names;
+  names.reserve(m_uids.size());
+  transform_if( std::begin(m_uids), std::end(m_uids),
+                std::back_inserter(names), select1st,
+                [](uidMap::const_reference i) { 
+                    return i.second.obj->IsA()->InheritsFrom("TTree"); }
+  );
+  return names;
+
+}
+//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
+
+StatusCode
+THistSvcHLT::readHist(const std::string& id, TH1*& hist) const {
+  return readHist_i(id, hist);
+}
+
+//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
+
+StatusCode
+THistSvcHLT::readHist(const std::string& id, TH2*& hist) const {
+  return readHist_i(id, hist);
+}
+
+//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
+
+StatusCode
+THistSvcHLT::readHist(const std::string& id, TH3*& hist) const {
+  return readHist_i(id, hist);
+}
+
+//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
+
+StatusCode
+THistSvcHLT::readTree(const std::string& id, TTree*& hist) const {
+  return readHist_i(id, hist);
+}
+
+//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
+
+bool
+THistSvcHLT::findStream(const string& id, string& stream, string& rem,
+                   TFile*& file) const {
+
+  auto pos = id.find("/");
+
+  if (pos == string::npos) {
+    stream = "temp";
+    rem = id;
+  } else if (pos != 0) {
+    stream = "temp";
+    rem = id;
+  } else {
+
+    auto pos2 = id.find("/",pos+1);
+
+    if (pos2 == string::npos) {
+      m_log << MSG::ERROR << "badly formed Hist/Tree id: \"" << id << "\""
+            << endmsg;
+      return false;
+    }
+
+    parseString(id,stream,rem);
+
+  }
+
+  if (stream == "temp") {
+    file = nullptr;
+    return true;
+  }
+
+  auto itr = m_files.find(stream);
+  file = (itr != m_files.end() ? itr->second.first : nullptr );
+  if (!file) {
+    m_log << MSG::WARNING << "no stream \"" << stream
+          << "\" associated with id: \"" << id << "\""
+          << endmsg;
+  }
+
+  return true;
+}
+
+//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
+
+void
+THistSvcHLT::parseString(const string& id, string& root, string& rem) const {
+  auto pos = id.find("/");
+
+  if (pos == string::npos) {
+    root.clear();
+    rem = id;
+  } else if (pos == 0) {
+    parseString(id.substr(1),root,rem);
+  } else {
+    root = id.substr(0,pos);
+    rem = id.substr(pos+1);
+  }
+
+}
+
+//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
+
+void
+THistSvcHLT::setupCompressionLevel( Property& /* cl */ )
+{
+
+  m_log << MSG::WARNING << "\"CompressionLevel\" Property has been deprecated. "
+        << "Set it via the \"CL=\" parameter in the \"Output\" Property"
+        << endmsg;
+
+}
+
+
+//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
+
+void
+THistSvcHLT::setupInputFile( Property& /*m_inputfile*/ )
+{
+
+  if (FSMState() < Gaudi::StateMachine::CONFIGURED || !m_okToConnect ) {
+
+    m_log <<MSG::DEBUG << "Delaying connection of Input Files until Initialize"
+	  << ". now in " << FSMState()
+	  << endmsg;
+
+    m_delayConnect = true;
+  } else {
+
+    m_log <<MSG::DEBUG << "Now connecting of Input Files"
+	  << endmsg;
+
+    StatusCode sc = StatusCode::SUCCESS;
+
+    for ( const auto& itr : m_inputfile.value() ) {
+      if ( m_alreadyConnectedInFiles.end() != 
+           m_alreadyConnectedInFiles.find( itr ) ) continue;
+      if ( connect(itr).isFailure() ) {
+        sc = StatusCode::FAILURE;
+      } else {
+        m_alreadyConnectedInFiles.insert( itr );
+      }
+      
+    }
+
+    if ( !sc.isSuccess() ) {
+      throw GaudiException( "Problem connecting inputfile !!", name(),
+                            StatusCode::FAILURE );
+    }
+
+  }
+}
+
+//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
+
+void
+THistSvcHLT::setupOutputFile( Property& /*m_outputfile*/ )
+{
+  if (FSMState() < Gaudi::StateMachine::CONFIGURED || !m_okToConnect) {
+    m_log <<MSG::DEBUG << "Delaying connection of Input Files until Initialize"
+	  << ". now in " << FSMState()
+	  << endmsg;
+    m_delayConnect = true;
+  } else {
+
+    StatusCode sc = StatusCode::SUCCESS;
+    for ( const auto & itr : m_outputfile.value() ) {
+      if ( m_alreadyConnectedOutFiles.end() !=
+           m_alreadyConnectedOutFiles.find( itr ) ) continue;
+      if ( connect(itr).isFailure() ) {
+        sc = StatusCode::FAILURE;
+      } else {
+        m_alreadyConnectedOutFiles.insert( itr );
+      }
+    }
+
+    if ( !sc.isSuccess() ) {
+      throw GaudiException( "Problem connecting outputfile !!", name(),
+                            StatusCode::FAILURE );
+    }
+  }
+}
+
+//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
+
+void
+THistSvcHLT::updateFiles() {
+
+  // If TTrees grow beyond TTree::fgMaxTreeSize, a new file is
+  // automatically created by root, and the old one closed. We
+  // need to migrate all the UIDs over to show the correct file
+  // pointer. This is ugly.
+
+  if (m_log.level() <= MSG::DEBUG)
+    m_log << MSG::DEBUG << "updateFiles()" << endmsg;
+
+
+  for (auto uitr=m_uids.begin(); uitr != m_uids.end(); ++uitr) {
+#ifndef NDEBUG
+    if (m_log.level() <= MSG::VERBOSE)
+      m_log << MSG::VERBOSE << " update: " << uitr->first << " "
+	    << uitr->second.id << " " << uitr->second.mode << endmsg;
+#endif
+    TObject* to = uitr->second.obj;
+    TFile* oldFile = uitr->second.file;
+    if (!to) {
+      m_log << MSG::WARNING << uitr->first << ": TObject == 0" << endmsg;
+    } else if ( uitr->second.temp || uitr->second.mode == READ ) {
+      // do nothing - no need to check how big the file is since we
+      // are just reading it.
+#ifndef NDEBUG
+    if (m_log.level() <= MSG::VERBOSE)
+      m_log << MSG::VERBOSE << "     skipping" << endmsg;
+#endif
+
+    } else if (to->IsA()->InheritsFrom("TTree")) {
+      TTree* tr = dynamic_cast<TTree*>(to);
+      TFile* newFile = tr->GetCurrentFile();
+
+      if (oldFile != newFile) {
+        std::string newFileName = newFile->GetName();
+        std::string oldFileName, streamName, rem;
+        TFile* dummy = nullptr;
+        findStream(uitr->second.id, streamName, rem, dummy);
+
+        for (auto& itr : m_files ) {
+          if (itr.second.first == oldFile) itr.second.first = newFile;
+        }
+
+        for (auto uitr2 = uitr; uitr2 != m_uids.end(); ++uitr2) {
+          if (uitr2->second.file == oldFile) {
+            uitr2->second.file = newFile;
+          }
+        }
+
+        auto sitr = std::find_if( std::begin(m_fileStreams), std::end(m_fileStreams),
+                                  [&](streamMap::const_reference s) {
+                                      return s.second == streamName;
+        });
+        if (sitr!=std::end(m_fileStreams)) oldFileName = sitr->first;
+
+#ifndef NDEBUG
+      if (m_log.level() <= MSG::DEBUG)
+        m_log << MSG::DEBUG << "migrating uid: " << uitr->second.id
+              << "   stream: " << streamName
+              << "   oldFile: " << oldFileName
+              << "   newFile: " << newFileName
+              << endmsg;
+#endif
+
+
+        if (!oldFileName.empty()) {
+          auto i = m_fileStreams.lower_bound(oldFileName);
+          while (i != std::end(m_fileStreams) && i->first == oldFileName) {
+
+#ifndef NDEBUG
+            if (m_log.level() <= MSG::DEBUG)
+              m_log << MSG::DEBUG << "changing filename \"" << i->first
+                    << "\" to \"" << newFileName << "\" for stream \""
+                    << i->second << "\"" << endmsg;
+#endif
+            std::string nm = std::move(i->second);
+            i = m_fileStreams.erase(i);
+	        m_fileStreams.emplace( newFileName, std::move(nm) ); 
+          }
+
+
+        } else {
+          m_log << MSG::ERROR
+                << "Problems updating fileStreams with new file name" << endmsg;
+        }
+
+      }
+    }
+  }
+}
+
+//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
+
+StatusCode
+THistSvcHLT::write() {
+
+  updateFiles();
+
+  std::for_each( m_files.begin(), m_files.end(), [](std::pair<const std::string,std::pair<TFile*,Mode>>& i) {
+      auto mode = i.second.second;
+      auto file = i.second.first;
+      if ( mode == WRITE || mode == UPDATE || mode == SHARE ) {
+          file->Write("",TObject::kOverwrite);
+      } else if ( mode == APPEND ) {
+          file->Write("");
+      }
+  } );
+
+  if (m_log.level() <= MSG::DEBUG) {
+    m_log << MSG::DEBUG << "THistSvcHLT::write()::List of Files connected in ROOT "
+          << endmsg;
+    TSeqCollection *filelist=gROOT->GetListOfFiles();
+    for (int ii=0; ii<filelist->GetEntries(); ii++) {
+        m_log << MSG::DEBUG
+              << "THistSvcHLT::write()::List of Files connected in ROOT: \""
+              << filelist->At(ii)->GetName()<<"\""<<endmsg;
+    }
+  }
+
+  return StatusCode::SUCCESS;
+
+}
+
+//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
+
+StatusCode
+THistSvcHLT::connect(const std::string& ident) {
+
+  auto loc = ident.find(" ");
+  string stream = ident.substr(0,loc);
+  char typ(0);
+  typedef std::pair<std::string,std::string>      Prop;
+  std::vector<Prop> props;
+  string filename, db_typ("ROOT");
+  int cl(1);
+
+  if (loc != string::npos) {
+    using Parser = Gaudi::Utils::AttribStringParser;
+    for (auto attrib: Parser(ident.substr(loc + 1))) {
+      auto TAG = boost::algorithm::to_upper_copy(attrib.tag);
+      auto VAL = boost::algorithm::to_upper_copy(attrib.value);
+
+      if (TAG == "FILE" || TAG == "DATAFILE") {
+        filename = attrib.value;
+        removeDoubleSlash( filename );
+      } else if ( TAG == "OPT" ) {
+        if ( VAL == "APPEND" || VAL == "UPDATE" ) {
+          typ = 'A';
+        } else if ( VAL == "CREATE" || VAL == "NEW" || VAL == "WRITE" ) {
+          typ = 'N';
+        } else if ( VAL == "RECREATE" ) {
+          typ = 'R';
+        } else if (VAL == "SHARE") {
+          typ = 'S';
+        } else if ( VAL == "OLD" || VAL == "READ" ) {
+          typ = 'O';
+        } else {
+          m_log << MSG::ERROR << "Unknown OPT: \"" << attrib.value << "\""
+              << endmsg;
+          typ = 0;
+        }
+      } else if (TAG == "TYP") {
+        db_typ = std::move(attrib.value);
+      } else if (TAG == "CL") {
+        cl = std::stoi(attrib.value);
+      } else {
+        props.emplace_back( attrib.tag, attrib.value);
+      }
+
+    }
+  }
+
+  if (stream == "temp") {
+    m_log << MSG::ERROR << "in JobOption \"" << ident
+          << "\": stream name \"temp\" reserved."
+          << endmsg;
+    return StatusCode::FAILURE;
+  }
+
+  if (db_typ != "ROOT") {
+    m_log << MSG::ERROR << "in JobOption \"" << ident
+          << "\": technology type \"" << db_typ << "\" not supported."
+          << endmsg;
+    return StatusCode::FAILURE;
+  }
+
+
+  if (m_files.find(stream) != m_files.end()) {
+    m_log << MSG::ERROR << "in JobOption \"" << ident
+          << "\":\n stream \"" << stream << "\" already connected to file: \""
+          << m_files[stream].first->GetName() << "\""
+          << endmsg;
+    return StatusCode::FAILURE;
+  }
+
+  Mode newMode;
+  if (typ == 'O') {
+    newMode = THistSvcHLT::READ;
+  } else if (typ == 'N') {
+    newMode = THistSvcHLT::WRITE;
+  } else if (typ == 'A') {
+    newMode = THistSvcHLT::APPEND;
+  } else if (typ == 'R') {
+    newMode = THistSvcHLT::UPDATE;
+  } else if (typ == 'S') {
+    newMode = THistSvcHLT::SHARE;
+  } else {
+    // something else?
+    m_log << MSG::ERROR << "No OPT= specified or unknown access mode in: "
+          << ident << endmsg;
+    return StatusCode::FAILURE;
+  }
+
+  // Is this file already connected to another stream?
+  if (m_fileStreams.find(filename) != m_fileStreams.end()) {
+    auto fitr = m_fileStreams.equal_range(filename);
+
+    const std::string& oldstream = fitr.first->second;
+
+    const auto& f_info = m_files[oldstream];
+
+    if (newMode != f_info.second) {
+      m_log << MSG::ERROR << "in JobOption \"" << ident
+            << "\":\n file \"" << filename << "\" already opened by stream: \""
+            << oldstream << "\" with different access mode."
+            << endmsg;
+      return StatusCode::FAILURE;
+    } else {
+      TFile *f2 = f_info.first;
+      m_files[stream] = make_pair(f2,newMode);
+      if (m_log.level() <= MSG::DEBUG)
+        m_log << MSG::DEBUG << "Connecting stream: \"" << stream
+              << "\" to previously opened TFile: \"" << filename << "\""
+              << endmsg;
+      return StatusCode::SUCCESS;
+    }
+  }
+
+
+  IIncidentSvc *pi = nullptr;
+  if (service("IncidentSvc",pi).isFailure()) {
+    m_log << MSG::ERROR << "Unable to get the IncidentSvc" << endmsg;
+    return StatusCode::FAILURE;
+  }
+
+  void* vf = nullptr;
+  TFile *f = nullptr;
+
+  if (newMode == THistSvcHLT::READ) {
+    // old file
+
+    int r = p_fileMgr->open(Io::ROOT,name(), filename,Io::READ,vf,"HIST");
+
+    if (r != 0) {
+      m_log << "Unable to open ROOT file " << filename << " for reading"
+	    << endmsg;
+      return StatusCode::FAILURE;
+    }
+
+
+    f = (TFile*) vf;
+
+    // FIX ME!
+    pi->fireIncident(FileIncident(name(), "BeginHistFile", filename));
+
+
+  } else if (newMode == THistSvcHLT::WRITE) {
+    // new file. error if file exists
+
+    int r = p_fileMgr->open(Io::ROOT,name(),filename, (Io::WRITE|Io::CREATE|Io::EXCL),
+			    vf,"HIST");
+
+    if (r != 0) {
+      m_log << "Unable to open ROOT file " << filename << " for writing"
+	    << endmsg;
+      return StatusCode::FAILURE;
+    }
+
+    f = (TFile*)vf;
+
+  } else if (newMode == THistSvcHLT::APPEND) {
+    // update file
+
+    int r = p_fileMgr->open(Io::ROOT,name(),filename, (Io::WRITE | Io::APPEND),
+			    vf,"HIST");
+    if (r != 0) {
+      m_log << MSG::ERROR << "unable to open file \"" << filename
+            << "\" for appending" << endmsg;
+      return StatusCode::FAILURE;
+    }
+
+    f = (TFile*) vf;
+
+
+  } else if (newMode == THistSvcHLT::SHARE) {
+    // SHARE file type
+    //For SHARE files, all data will be stored in a temp file and will be merged into the target file
+    //in write() when finalize(), this help to solve some confliction. e.g. with storegate
+
+    static int ishared = 0;
+    string realfilename=filename;
+    filename = "tmp_THistSvcHLT_"+ std::to_string(ishared++)+".root";
+
+    if (m_log.level() <= MSG::DEBUG)
+      m_log << MSG::DEBUG << "Creating temp file \"" << filename
+            << "\" and realfilename="<<realfilename << endmsg;
+    m_sharedFiles[stream]=realfilename;
+
+
+    int r = p_fileMgr->open(Io::ROOT,name(), filename, (Io::WRITE|Io::CREATE|Io::EXCL),
+			    vf,"HIST");
+
+    if (r != 0) {
+      m_log << "Unable to open ROOT file " << filename << " for writing"
+	    << endmsg;
+      return StatusCode::FAILURE;
+    }
+
+    f = (TFile*)vf;
+
+  } else if (newMode == THistSvcHLT::UPDATE) {
+    // update file
+
+    int r = p_fileMgr->open(Io::ROOT,name(), filename, (Io::WRITE|Io::CREATE),
+			    vf, "HIST");
+
+    if (r != 0) {
+      m_log << "Unable to open ROOT file " << filename << " for appending"
+	    << endmsg;
+      return StatusCode::FAILURE;
+    }
+
+    f = (TFile*)vf;
+
+  }
+
+  m_files[stream] = make_pair(f,newMode);
+  m_fileStreams.insert(make_pair(filename,stream));
+
+  if (m_log.level() <= MSG::DEBUG)
+    m_log << MSG::DEBUG << "Opening TFile \"" << filename << "\"  stream: \""
+          << stream << "\"  mode: \"" << typ << "\"" << " comp level: " << cl
+          << endmsg;
+
+  return StatusCode::SUCCESS;
+}
+
+//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
+
+TDirectory*
+THistSvcHLT::changeDir(const THistSvcHLT::THistID& hid) const {
+
+  string uid = hid.id;
+  TFile* file = hid.file;
+  string stream, fdir, bdir, dir, id;
+
+  if (file) {
+    file->cd("/");
+  } else {
+    gROOT->cd();
+  }
+
+  fdir = uid;
+  bdir = dirname(fdir);
+
+  while ( (dir = dirname(fdir)) != "") {
+    if (! gDirectory->GetKey(dir.c_str())) {
+      gDirectory->mkdir(dir.c_str());
+    }
+    gDirectory->cd(dir.c_str());
+  }
+
+  return gDirectory;
+
+}
+
+//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
+
+std::string
+THistSvcHLT::dirname(std::string& dir) const {
+
+
+  string::size_type i = dir.find("/");
+
+  if (i == string::npos) return {};
+
+  if ( i == 0 ) {
+    dir.erase(0,1);
+    return dirname(dir);
+  }
+
+  string root = dir.substr(0,i);
+  dir.erase(0,i);
+
+  return root;
+
+}
+
+//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
+
+THistSvcHLT::GlobalDirectoryRestore::GlobalDirectoryRestore() {
+  m_gd = gDirectory;
+  m_gf = gFile;
+  m_ge = gErrorIgnoreLevel;
+}
+
+THistSvcHLT::GlobalDirectoryRestore::~GlobalDirectoryRestore() {
+  gDirectory = m_gd;
+  gFile = m_gf;
+  gErrorIgnoreLevel = m_ge;
+}
+
+//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
+
+void
+THistSvcHLT::removeDoubleSlash(std::string& id) const {
+
+  while (id.find("//") != std::string::npos) {
+    id.replace(id.find("//"),2,"/");
+  }
+
+}
+
+//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
+
+void THistSvcHLT::MergeRootFile(TDirectory *target, TDirectory *source) {
+
+  if (m_log.level() <= MSG::DEBUG)
+    m_log <<MSG::DEBUG << "Target path: " << target->GetPath() << endmsg;
+  TString path( (char*)strstr(target->GetPath(), ":") );
+  path.Remove( 0, 2);
+
+  source->cd(path);
+  TDirectory *current_sourcedir = gDirectory;
+
+  // loop over all keys in this directory
+  TList *lkeys=current_sourcedir->GetListOfKeys();
+  int nkeys=lkeys->GetEntries();
+  TKey *key;
+  for (int jj=0; jj<nkeys; jj++) {
+    key=(TKey*) lkeys->At(jj);
+    string pathnameinsource=current_sourcedir->GetPath()+string("/")+key->GetName();
+    if (m_log.level() <= MSG::DEBUG)
+      m_log <<MSG::DEBUG << "Reading Key:" << pathnameinsource << endmsg;
+    //key->Dump();
+    //TObject *obj=key->ReadObj();
+    TObject *obj=source->Get(pathnameinsource.c_str());
+
+    if (obj) {
+    if (obj->IsA()->InheritsFrom("TDirectory") ) {
+      // it's a subdirectory
+
+      if (m_log.level() <= MSG::DEBUG)
+        m_log <<MSG::DEBUG << "Found subdirectory " << obj->GetName()
+              << endmsg;
+
+      // create a new subdir of same name and title in the target file
+      target->cd();
+      TDirectory *newtargetdir =
+        target->mkdir(obj->GetName(), obj->GetTitle() );
+
+      MergeRootFile(newtargetdir, source);
+
+    } else if (obj->IsA()->InheritsFrom("TTree")) {
+      if (m_log.level() <= MSG::DEBUG)
+        m_log <<MSG::DEBUG << "Found TTree " << obj->GetName() << endmsg;
+      TTree *mytree=dynamic_cast<TTree*>(obj);
+      int nentries=(int) mytree->GetEntries();
+      mytree->SetBranchStatus("*",1);
+
+      if (m_log.level() <= MSG::DEBUG)
+        m_log <<MSG::DEBUG << "Dumping TTree " << nentries <<" entries"
+              << endmsg;
+      //mytree->Print();
+      //for (int ij=0; ij<nentries; ij++) {
+      //m_log <<MSG::DEBUG << "Dumping TTree Show( " << ij <<" )"
+      //<< endmsg;
+      //mytree->Show(ij);
+      //}
+      target->cd();
+      mytree->CloneTree();
+
+      //m_log <<MSG::DEBUG << "Writing TTree to target file: ( "
+      //<< mycopiedtree->Write(key->GetName()) <<" ) bytes written"
+      //<< endmsg;
+
+    } else {
+      target->cd();
+      obj->Write(key->GetName() );
+    }
+    }
+
+  } // while ( ( TKey *key = (TKey*)nextkey() ) )
+
+  // save modifications to target file
+
+}
+
+//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
+
+bool
+THistSvcHLT::exists( const std::string& name ) const {
+
+  TH1* h;
+  return getHist_i(name,h,true).isSuccess();
+
+}
+
+//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
+
+void
+THistSvcHLT::handle( const Incident& /* inc */ ) {
+
+  if (signaledStop) return ;
+
+  if (m_maxFileSize.value() == -1) return;
+
+  // convert to bytes.
+  Long64_t mfs = (Long64_t)m_maxFileSize.value() * (Long64_t)1048576;
+  Long64_t mfs_warn = mfs * 95 / 100;
+
+  updateFiles();
+
+  map<string, pair<TFile*,Mode> >::const_iterator itr;
+  for (const auto& f : m_files) {
+    TFile* tf = f.second.first;
+
+#ifndef NDEBUG
+    if (m_log.level() <= MSG::DEBUG)
+      m_log << MSG::DEBUG << "stream: " << f.first << "  name: "
+            << tf->GetName() << "  size: " << tf->GetSize()
+            << endmsg;
+#endif
+
+    // Signal job to terminate if output file is too large
+    if (tf->GetSize() > mfs) {
+
+      signaledStop = true;
+
+      m_log << MSG::FATAL << "file \"" << tf->GetName()
+            << "\" associated with stream \"" << f.first
+            << "\" has exceeded the max file size of "
+            << m_maxFileSize.value() << "MB. Terminating Job."
+            << endmsg;
+
+      IEventProcessor* evt = nullptr;
+      if (service("ApplicationMgr", evt, true).isSuccess()) {
+        evt->stopRun();
+        evt->release();
+      } else {
+        abort();
+      }
+    } else if (tf->GetSize() > mfs_warn) {
+      m_log << MSG::WARNING << "file \"" << tf->GetName()
+            << "\" associated with stream \"" << f.first
+            << "\" is at 95% of its maximum allowable file size of "
+            << m_maxFileSize.value() << "MB"
+            << endmsg;
+    }
+  }
+}
+
+//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
+
+/** helper function to recursively copy the layout of a TFile into a new TFile
+ */
+void
+THistSvcHLT::copyFileLayout (TDirectory *dst, TDirectory *src) {
+
+  if (m_log.level() <= MSG::DEBUG)
+    m_log << MSG::DEBUG
+	  << "copyFileLayout() to dst path: " << dst->GetPath () << endmsg;
+
+    // strip out URLs
+    TString path ((char*)strstr (dst->GetPath(), ":"));
+    path.Remove (0, 2);
+
+    src->cd (path);
+    TDirectory *cur_src_dir = gDirectory;
+
+    // loop over all keys in this directory
+    TList *key_list = cur_src_dir->GetListOfKeys ();
+    int n = key_list->GetEntries ();
+    for ( int j = 0; j < n; ++j ) {
+      TKey *k = (TKey*)key_list->At (j);
+      const std::string src_pathname = cur_src_dir->GetPath()
+                                     + std::string("/")
+                                     + k->GetName();
+      TObject *o=src->Get (src_pathname.c_str());
+
+    if ( o && o->IsA()->InheritsFrom ("TDirectory")) {
+      if (m_log.level() <= MSG::VERBOSE)
+	m_log << MSG::VERBOSE << " subdir [" << o->GetName() << "]..."
+	      << endmsg;
+        dst->cd ();
+        TDirectory * dst_dir = dst->mkdir (o->GetName(), o->GetTitle());
+      copyFileLayout (dst_dir, src);
+      }
+    } // loop over keys
+    return;
+}
+
+//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
+/** @brief callback method to reinitialize the internal state of
+ *         the component for I/O purposes (e.g. upon @c fork(2))
+ */
+StatusCode
+THistSvcHLT::io_reinit ()
+{
+  bool all_good = true;
+  if (m_log.level() <= MSG::DEBUG)
+    m_log << MSG::DEBUG << "reinitializing I/O..." << endmsg;
+
+  // retrieve the I/O component manager...
+
+  IIoComponentMgr* iomgr = nullptr;
+
+  if (service("IoComponentMgr", iomgr, true).isFailure()) {
+    m_log << MSG::ERROR << "could not retrieve I/O component manager !"
+          << endmsg;
+    return StatusCode::FAILURE;
+  }
+
+  GlobalDirectoryRestore restore;
+  // to hide the expected errors upon closing the files whose
+  // file descriptors have been swept under the rug...
+  gErrorIgnoreLevel = kFatal;
+
+  typedef std::map<std::string, std::pair<TFile*,Mode> > FileReg_t;
+
+  for (auto & ifile : m_files ) {
+    TFile *f = ifile.second.first;
+    std::string fname = f->GetName();
+    if (m_log.level() <= MSG::DEBUG)
+      m_log << MSG::DEBUG << "file [" << fname << "] mode: ["
+          << f->GetOption() << "] r:"
+          << f->GetFileBytesRead()
+          << " w:" << f->GetFileBytesWritten()
+          << " cnt:" << f->GetFileCounter()
+          << endmsg;
+
+    if ( ifile.second.second == READ ) {
+      if (m_log.level() <= MSG::DEBUG)
+	m_log << MSG::DEBUG
+            << "  TFile opened in READ mode: not reassigning names" << endmsg;
+      continue;
+    }
+
+    if ( !iomgr->io_retrieve (this, fname).isSuccess () ) {
+      m_log << MSG::ERROR << "could not retrieve new name for [" << fname
+            << "] !!" << endmsg;
+      all_good = false;
+      continue;
+    } else {
+      if (m_log.level() <= MSG::DEBUG)
+	m_log << MSG::DEBUG << "got a new name [" << fname << "]..." << endmsg;
+    }
+    // create a new TFile
+    // TFile *newfile = TFile::Open (fname.c_str(), f->GetOption());
+
+    void* vf;
+    Option_t *opts = f->GetOption();
+    int r = p_fileMgr->open(Io::ROOT,name(),fname,Io::WRITE,vf,"HIST");
+    if (r != 0) {
+      m_log << MSG::ERROR << "unable to open file \"" << fname
+	    << "\" for writing" << endmsg;
+      return StatusCode::FAILURE;
+    }
+    TFile *newfile = (TFile*) vf;
+    newfile->SetOption(opts);
+
+
+    if (ifile.second.second != THistSvcHLT::READ) {
+      copyFileLayout (newfile, f);
+      ifile.second.first = newfile;
+    }
+
+    // loop over all uids and migrate them to the new file
+    // XXX FIXME: this double loop sucks...
+    for ( auto& uid : m_uids ) {
+      THistID& hid = uid.second;
+      if ( hid.file != f ) continue;
+      TDirectory *olddir = this->changeDir (hid);
+      hid.file = newfile;
+      // side-effect: create needed directories...
+      TDirectory *newdir = this->changeDir (hid);
+      TClass *cl = hid.obj->IsA();
+
+      // migrate the objects to the new file.
+      // thanks to the object model of ROOT, it is super easy.
+      if (cl->InheritsFrom ("TTree")) {
+        dynamic_cast<TTree*> (hid.obj)->SetDirectory (newdir);
+        dynamic_cast<TTree*> (hid.obj)->Reset();
+      }
+      else if (cl->InheritsFrom ("TH1")) {
+        dynamic_cast<TH1*> (hid.obj)->SetDirectory (newdir);
+        dynamic_cast<TH1*> (hid.obj)->Reset();
+      }
+      else if (cl->InheritsFrom ("TGraph")) {
+        olddir->Remove (hid.obj);
+        newdir->Append (hid.obj);
+      } else {
+        m_log << MSG::ERROR
+              << "id: \"" << hid.id << "\" is not a inheriting from a class "
+              << "we know how to handle (received [" << cl->GetName()
+              << "], " << "expected [TTree, TH1 or TGraph]) !"
+              << endmsg
+              << "attaching to current dir [" << newdir->GetPath() << "] "
+              << "nonetheless..." << endmsg;
+        olddir->Remove (hid.obj);
+        newdir->Append (hid.obj);
+      }
+    }
+    f->ReOpen ("READ");
+    p_fileMgr->close(f,name());
+    f = newfile;
+  }
+
+  return all_good ? StatusCode::SUCCESS : StatusCode::FAILURE;
+}
+
+
+//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
+
+StatusCode
+THistSvcHLT::rootOpenAction( const Io::FileAttr* fa, const std::string& caller) {
+
+  if (fa->tech() != Io::ROOT) {
+    // This should never happen
+    return StatusCode::SUCCESS;
+  }
+
+  if (fa->desc() != "HIST") {
+    return StatusCode::SUCCESS;
+  }
+
+  p_incSvc->fireIncident(FileIncident(caller, "OpenHistFile", fa->name()));
+
+  if ( fa->flags().isRead() ) {
+    p_incSvc->fireIncident(FileIncident(caller, "BeginHistFile", fa->name()));
+  } else if ( fa->flags().isWrite() ) {
+    p_incSvc->fireIncident(FileIncident(caller, IncidentType::BeginOutputFile,
+					fa->name()));
+  } else {
+    // for Io::RW
+    p_incSvc->fireIncident(FileIncident(caller, IncidentType::BeginOutputFile,
+					fa->name()));
+  }
+
+  return StatusCode::SUCCESS;
+
+
+}
+
+//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
+
+StatusCode
+THistSvcHLT::rootOpenErrAction( const Io::FileAttr* fa, const std::string& caller) {
+
+  if (fa->tech() != Io::ROOT) {
+    // This should never happen
+    return StatusCode::SUCCESS;
+  }
+
+  if (fa->desc() != "HIST") {
+    return StatusCode::SUCCESS;
+  }
+
+  if ( fa->flags().isRead() ) {
+    p_incSvc->fireIncident(FileIncident(caller, IncidentType::FailInputFile,
+					fa->name()));
+  } else if ( fa->flags().isWrite() ) {
+    p_incSvc->fireIncident(FileIncident(caller, IncidentType::FailOutputFile,
+					fa->name()));
+  } else {
+    // for Io::RW
+    p_incSvc->fireIncident(FileIncident(caller, "FailRWFile", fa->name()));
+  }
+
+  return StatusCode::SUCCESS;
+}
diff --git a/HLT/Trigger/TrigControl/TrigServices/src/THistSvcHLT.h b/HLT/Trigger/TrigControl/TrigServices/src/THistSvcHLT.h
new file mode 100644
index 00000000000..cec1ef7d50e
--- /dev/null
+++ b/HLT/Trigger/TrigControl/TrigServices/src/THistSvcHLT.h
@@ -0,0 +1,230 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef THISTSVCHLT_H
+#define THISTSVCHLT_H
+
+#include "GaudiKernel/Service.h"
+#include "GaudiKernel/ITHistSvc.h"
+#include "GaudiKernel/IFileMgr.h"
+#include "GaudiKernel/IIncidentListener.h"
+#include "GaudiKernel/IIoComponent.h"
+#include "GaudiKernel/MsgStream.h"
+
+#include "TObject.h"
+#include "TH1.h"
+#include "TH2.h"
+#include "TH3.h"
+#include "TTree.h"
+#include "TGraph.h"
+#include "TList.h"
+
+
+#include <vector>
+#include <string>
+#include <set>
+#include <map>
+
+class IIncidentSvc;
+class THistSvcHLT: public extends3<Service, ITHistSvc, IIncidentListener,
+				IIoComponent> {
+
+public:
+
+  StatusCode initialize() override;
+  StatusCode reinitialize() override;
+  StatusCode finalize() override;
+
+  StatusCode regHist(const std::string& name) override;
+  StatusCode regHist(const std::string& name, TH1*) override;
+  StatusCode regHist(const std::string& name, TH2*) override;
+  StatusCode regHist(const std::string& name, TH3*) override;
+
+  StatusCode getHist(const std::string& name, TH1*&) const override;
+  StatusCode getHist(const std::string& name, TH2*&) const override;
+  StatusCode getHist(const std::string& name, TH3*&) const override;
+
+  StatusCode regTree(const std::string& name) override;
+  StatusCode regTree(const std::string& name, TTree*) override;
+  StatusCode getTree(const std::string& name, TTree*&) const override;
+
+  StatusCode regGraph(const std::string& name) override;
+  StatusCode regGraph(const std::string& name, TGraph*) override;
+  StatusCode getGraph(const std::string& name, TGraph*&) const override;
+
+  StatusCode deReg(TObject* obj) override;
+  StatusCode deReg(const std::string& name) override;
+
+  std::vector<std::string> getHists() const override;
+  std::vector<std::string> getTrees() const override;
+  std::vector<std::string> getGraphs() const override;
+
+  StatusCode getTHists(TDirectory *td, TList &,
+           bool recurse=false) const override;
+  StatusCode getTHists(const std::string& name, TList &,
+           bool recurse=false) const override;
+
+  StatusCode getTHists(TDirectory *td, TList &tl,
+           bool recurse=false, bool reg=false) override;
+  StatusCode getTHists(const std::string& name, TList &tl,
+		  bool recurse=false, bool reg=false) override;
+
+  StatusCode getTTrees(TDirectory *td, TList &,
+           bool recurse=false) const override;
+  StatusCode getTTrees(const std::string& name, TList &,
+           bool recurse=false) const override;
+
+  StatusCode getTTrees(TDirectory *td, TList & tl,
+           bool recurse=false, bool reg=false) override;
+  StatusCode getTTrees(const std::string& name, TList & tl,
+           bool recurse=false, bool reg=false) override;
+
+  bool exists(const std::string& name) const override;
+
+  THistSvcHLT(const std::string& name, ISvcLocator *svc );
+
+  void handle(const Incident&) override;
+
+  // From IIoComponent
+  StatusCode io_reinit () override;
+
+
+protected:
+
+  ~THistSvcHLT() override = default;
+
+private:
+
+  class GlobalDirectoryRestore {
+  public:
+    GlobalDirectoryRestore();
+    ~GlobalDirectoryRestore();
+  private:
+    TDirectory* m_gd;
+    TFile* m_gf;
+    int m_ge;
+  };
+
+  enum Mode {
+    READ,
+    WRITE,
+    UPDATE,
+    APPEND,
+    SHARE,
+    INVALID
+  };
+
+  struct THistID {
+    std::string id;
+    bool        temp;
+    TObject*    obj;
+    TFile*      file;
+    Mode        mode;
+
+    THistID():id(""),temp(true),obj(0),file(0),mode(INVALID) {}
+    THistID(const THistID& rhs):id(rhs.id), temp(rhs.temp),
+                                obj(rhs.obj), file(rhs.file), mode(rhs.mode) {}
+    THistID(std::string& i, bool& t, TObject* o, TFile* f)
+      : id(i), temp(t), obj(o), file(f), mode(INVALID){
+    }
+    THistID(std::string& i, bool& t, TObject* o, TFile* f, Mode m)
+      : id(i), temp(t), obj(o), file(f), mode(m){
+    }
+
+    bool operator < (THistID const &rhs) const {
+      return (obj < rhs.obj);
+    }
+  };
+
+
+  template <typename T>
+  StatusCode regHist_i(T* hist, const std::string& name);
+  template <typename T>
+  StatusCode getHist_i(const std::string& name, T*& hist, bool quiet=false) const;
+  template <typename T>
+  StatusCode readHist_i(const std::string& name, T*& hist) const;
+
+
+  StatusCode readHist(const std::string& name, TH1*&) const;
+  StatusCode readHist(const std::string& name, TH2*&) const;
+  StatusCode readHist(const std::string& name, TH3*&) const;
+  StatusCode readTree(const std::string& name, TTree*&) const;
+
+  void updateFiles();
+  StatusCode write();
+  StatusCode connect(const std::string&);
+  TDirectory* changeDir(const THistSvcHLT::THistID& hid) const;
+  std::string dirname(std::string& dir) const;
+  void removeDoubleSlash(std::string&) const;
+
+  bool browseTDir(TDirectory* dir) const;
+
+  bool findStream(const std::string& name, std::string& root,
+                  std::string& rem, TFile*& file) const;
+  void parseString(const std::string& id, std::string& root, std::string& rem)
+    const;
+
+  /// call-back method to handle input stream property
+  void setupInputFile( Property& inputfile );
+
+  /// call-back method to handle output stream property
+  void setupOutputFile( Property& outputfile );
+
+  void setupCompressionLevel( Property& cmp );
+
+  void copyFileLayout(TDirectory*, TDirectory*);
+
+  void MergeRootFile( TDirectory *target, TDirectory *source); 
+
+  ////////
+
+  mutable MsgStream m_log;
+
+  StringArrayProperty m_inputfile, m_outputfile;
+  std::vector<std::string> m_Rstream, m_Wstream;
+  IntegerProperty m_autoSave, m_autoFlush, m_compressionLevel, m_maxFileSize;
+  BooleanProperty m_print;
+
+  /// list of already connected files. This is to keep track of files
+  /// registered by the setupInputFile callback method
+  std::set<std::string> m_alreadyConnectedInFiles;
+
+  /// list of already connected files. This is to keep track of files
+  /// registered by the setupOutputFile callback method
+  std::set<std::string> m_alreadyConnectedOutFiles;
+
+
+  typedef std::map<std::string, THistID> uidMap;
+  typedef std::multimap<std::string, THistID> idMap;
+  typedef std::map<TObject*, THistID> objMap;
+  typedef std::multimap<std::string, std::string> streamMap;
+
+  uidMap m_uids;
+  idMap  m_ids;
+  objMap m_tobjs;
+
+  std::map<std::string, std::pair<TFile*,Mode> > m_files; // stream->file
+  streamMap m_fileStreams;                                // fileName->streams
+
+  std::map<std::string, std::string > m_sharedFiles; // stream->filename of shared files
+
+  bool signaledStop = false;
+  bool m_delayConnect = false, m_okToConnect = false;
+
+  mutable std::string m_curstream;
+
+  IIncidentSvc* p_incSvc = nullptr;
+  IFileMgr* p_fileMgr = nullptr;
+
+  StatusCode rootOpenAction( FILEMGR_CALLBACK_ARGS );
+  StatusCode rootOpenErrAction( FILEMGR_CALLBACK_ARGS );
+
+};
+
+#ifndef THISTSVCHLT_ICC
+ #include "THistSvcHLT.icc"
+#endif
+
+
+#endif
diff --git a/HLT/Trigger/TrigControl/TrigServices/src/THistSvcHLT.icc b/HLT/Trigger/TrigControl/TrigServices/src/THistSvcHLT.icc
new file mode 100644
index 00000000000..45c635ac545
--- /dev/null
+++ b/HLT/Trigger/TrigControl/TrigServices/src/THistSvcHLT.icc
@@ -0,0 +1,311 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef THISTSVCHLT_ICC
+#define THISTSVCHLT_ICC
+
+#ifndef GAUDIKERNEL_MSGSTREAM_H
+ #include "GaudiKernel/MsgStream.h"
+#endif
+
+#include "GaudiKernel/System.h"
+
+#include <string>
+#include <map>
+
+#include "TObject.h"
+#include "TFile.h"
+
+template <typename T>
+StatusCode THistSvcHLT::regHist_i(T* hist, const std::string& id) {
+
+  GlobalDirectoryRestore restore;
+
+  std::string idr(id);
+  removeDoubleSlash( idr );
+
+  if (idr.find("/") == idr.length()) {
+    m_log << MSG::ERROR << "Badly formed identifier \"" << idr << "\": "
+        << "Must not end with a /" << endmsg;
+    return StatusCode::FAILURE;
+  }
+
+
+  TFile *f = nullptr;
+  std::string stream,rem;
+  if (!findStream(idr, stream, rem, f)) {
+    m_log << MSG::ERROR << "Could not register id: \"" << idr << "\""
+        << endmsg;
+    return StatusCode::FAILURE;
+  }
+
+  std::string uid = "/" + stream + "/" + rem;
+  auto itr = m_uids.find(uid);
+  if (itr != m_uids.end()) {
+    m_log << MSG::ERROR << "already registered an object with identifier \""
+	  << idr << "\"" << endmsg;
+    return StatusCode::FAILURE;
+  }
+
+
+  bool temp = false;
+  if ( !f ) {
+    temp = true;
+    if (m_log.level() <= MSG::DEBUG)
+      m_log << MSG::DEBUG << "Historgram with id \"" << idr << "\" is temporary"
+	    << endmsg;
+  }
+
+
+  TObject *to = nullptr;
+  THistID hid;
+
+  // check to see if this hist is to be read in;
+  if (!temp && m_files.find(stream)->second.second == READ) {
+
+    if (hist != 0) {
+      m_log << MSG::WARNING <<  "Registering id: \"" << idr
+	    << "\" with non zero pointer!" << endmsg;
+    }
+
+    if (readHist_i(idr,hist).isFailure()) {
+      m_log << MSG::ERROR <<  "Unable to read in hist" << endmsg;
+      return StatusCode::FAILURE;
+    }
+    to = dynamic_cast<TObject*>(hist);
+    hid = THistID(uid,temp,to,f,m_files.find(stream)->second.second);
+
+  } else if (hist == 0) {
+    m_log << MSG::ERROR << "Unable to read in hist with id: \""
+	  << idr << "\"" << endmsg;
+    return StatusCode::FAILURE;
+
+  } else {
+
+    to = dynamic_cast<TObject*>(hist);
+    if (to == 0) {
+      m_log << MSG::ERROR << "Could not dcast to TObject. id: \"" << idr
+	    << "\"" << endmsg;
+      return StatusCode::FAILURE;
+    }
+
+    auto oitr = m_tobjs.find(to);
+    if (oitr != m_tobjs.end()) {
+      m_log << MSG::ERROR << "already registered id: \"" << idr
+	    << "\" with identifier \"" << oitr->second.id << "\"" << endmsg;
+      return StatusCode::FAILURE;
+    }
+
+    hid = THistID(uid,temp,to,f,m_files.find(stream)->second.second);
+    TDirectory* dir = changeDir(hid);
+
+    if ( dynamic_cast<TTree*>(hist) ) {
+      dynamic_cast<TTree*>(hist)->SetDirectory(dir);
+    } else if ( dynamic_cast<TH1*>(hist) ) {
+      dynamic_cast<TH1*>(hist)->SetDirectory(dir);
+    } else if ( dynamic_cast<TGraph*>(hist) ) {
+      dir->Append(hist);
+    } else {
+      m_log << MSG::ERROR << "id: \"" << idr
+	    << "\" is not a TH, TTree, or TGraph. Attaching it to current dir."
+	    << endmsg;
+      dir->Append(hist);
+    }
+
+  }
+
+  std::string fname;
+  if ( !f ) {
+    fname = "none";
+  } else {
+    fname = f->GetName();
+  }
+
+  if (m_log.level() <= MSG::DEBUG) 
+    m_log << MSG::DEBUG << "Registering " << System::typeinfoName(typeid(*hist))
+	  << " title: \"" << hist->GetTitle()
+	  << "\"  id: \"" << uid << "\"  dir: "
+      //      << hist->GetDirectory()->GetPath() << "  "
+	  << changeDir(hid)->GetPath()
+	  << "  file: " << fname
+	  << endmsg;
+
+  m_ids.emplace(rem, hid);
+  m_uids[uid] = hid;
+  m_tobjs[to] = hid;
+
+  return StatusCode::SUCCESS;
+
+}
+
+//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
+
+template <typename T>
+StatusCode 
+THistSvcHLT::getHist_i(const std::string& id, T*& hist, bool quiet) const {
+  // id starts with "/": unique
+
+  GlobalDirectoryRestore restore;
+
+  std::string idr(id);
+  removeDoubleSlash( idr );
+
+  if (idr.find("/") == 0) {
+    auto itr = m_uids.find(id);
+    if (itr == m_uids.end()) {
+      if (!quiet) {
+	m_log << MSG::ERROR << "Could not locate Hist with id \"" << idr << "\""
+	      << endmsg;
+      }
+      hist = nullptr;
+      return StatusCode::FAILURE;
+    }
+
+    THistID hid = itr->second;
+    if (!quiet) {
+      hist = dynamic_cast<T*>(hid.obj);
+      if ( !hist ) {
+	m_log << MSG::ERROR << "dcast failed, Hist id: \"" << idr << "\"" 
+	      << endmsg;
+	return StatusCode::FAILURE;
+      }
+      if (m_log.level() <= MSG::VERBOSE) {
+	m_log << MSG::VERBOSE << "found unique Hist title: \"" 
+	      << hist->GetTitle()
+	      << "\"  id: \"" << idr << "\"" << endmsg;
+      }
+    } else {
+      if (m_log.level() <= MSG::VERBOSE) {
+	m_log << MSG::VERBOSE << "found unique Hist id: \"" << idr 
+	      << "\" type: \"" << hid.obj->IsA()->GetName() << "\""
+	      << endmsg;
+      }
+    }
+
+    return StatusCode::SUCCESS;
+
+
+    // not necessarily unique
+  } else {
+
+      auto mitr = m_ids.equal_range(idr);
+
+
+    if (mitr.first == mitr.second) {
+      m_log << MSG::ERROR << "Could not locate Hist with id \"" << idr << "\""
+	    << endmsg;
+      hist = nullptr;
+      return StatusCode::FAILURE;
+    } else {
+
+      if (distance(mitr.first,mitr.second) == 1) {
+        THistID hid = mitr.first->second;
+	if (!quiet) {
+	  hist = dynamic_cast<T*>(hid.obj);
+	  if (hist == 0) {
+	    m_log << MSG::ERROR << "dcast failed" << endmsg;
+	    return StatusCode::FAILURE;
+	  }
+	  if (m_log.level() <= MSG::VERBOSE) {
+	    m_log << MSG::VERBOSE << "found Hist title: \"" << hist->GetTitle()
+		  << "\"  id: \"" << idr << "\"" << endmsg;
+	  }
+	} else {
+	  if (m_log.level() <= MSG::VERBOSE) {
+	    m_log << MSG::VERBOSE << "found Hist id: \"" << idr << "\" type: \""
+		  << hid.obj->IsA()->GetName() << "\""
+		  << endmsg;
+	  }
+	}
+        return StatusCode::SUCCESS;
+      } else {
+	if (!quiet) {
+	  // return failure if trying to GET a single hist
+	  m_log << MSG::ERROR << "Multiple matches with id \"" << idr << "\"."
+		<< " Further specifications required."
+		<< endmsg;
+	  hist = nullptr;
+	  return StatusCode::FAILURE;
+	} else {
+	  // return a SUCCESS if just INQUIRING
+	  m_log << MSG::INFO << "Found multiple matches with id \"" << idr 
+	      << "\"" << endmsg;
+	  hist = nullptr;
+	  return StatusCode::SUCCESS;
+	}
+      }
+    }
+  }
+}
+
+//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
+
+template <typename T>
+StatusCode
+THistSvcHLT::readHist_i(const std::string& id, T*& hist) const {
+
+  GlobalDirectoryRestore restore;
+
+  std::string idr(id);
+  removeDoubleSlash( idr );
+
+  std::string stream, rem, dir, fdir, bdir, fdir2;
+  TFile *file;
+
+  if (!findStream(idr, stream, rem, file) ) {
+    return StatusCode::FAILURE;
+  }
+
+  if ( !file ) {
+    m_log << MSG::ERROR << "no associated file found" << endmsg;
+    return StatusCode::FAILURE;
+  }
+
+  file->cd("/");
+
+  fdir = idr;
+  bdir = dirname(fdir);
+  fdir2 = fdir;
+  while ( (dir=dirname(fdir)) != "" ) {
+    if (! gDirectory->GetKey(dir.c_str())) {
+      m_log << MSG::ERROR << "Directory \"" << fdir2 << "\" doesnt exist in "
+	    << file->GetName() << endmsg;
+      return StatusCode::FAILURE;
+    }
+    gDirectory->cd(dir.c_str());
+  }
+
+  TObject *to=nullptr;
+  gDirectory->GetObject(fdir.c_str(), to);
+
+  if ( !to ) {
+    m_log << MSG::ERROR << "Could not get obj \"" << fdir << "\" in "
+	  << gDirectory->GetPath() << endmsg;
+    return StatusCode::FAILURE;
+  }
+
+
+
+  hist = dynamic_cast<T*>(to);
+  if ( !hist ) {
+    m_log << MSG::ERROR << "Could not convert \"" << idr << "\" to a "
+	  << System::typeinfoName(typeid(*hist)) << " as is a "
+	  << to->IsA()->GetName()
+	  << endmsg;
+    return StatusCode::FAILURE;
+  }
+
+
+  if (m_log.level() <= MSG::DEBUG) {
+    m_log << MSG::DEBUG << "Read in " << hist->IsA()->GetName() << "  \""
+	  << hist->GetName() << "\" from file "
+	  << file->GetName() << endmsg;
+    hist->Print();
+  }
+
+  return StatusCode::SUCCESS;
+
+}
+
+#endif
diff --git a/HLT/Trigger/TrigControl/TrigServices/src/TrigCOOLUpdateHelper.cxx b/HLT/Trigger/TrigControl/TrigServices/src/TrigCOOLUpdateHelper.cxx
new file mode 100644
index 00000000000..9d632e7cd02
--- /dev/null
+++ b/HLT/Trigger/TrigControl/TrigServices/src/TrigCOOLUpdateHelper.cxx
@@ -0,0 +1,404 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+/**
+ * @file   TrigCOOLUpdateHelper.h
+ * @brief  Helper tool for COOL updates
+ * @author Frank Winklmeier
+ *
+ * $Id: TrigCOOLUpdateHelper.cxx 666321 2015-05-11 17:32:34Z fwinkl $
+ */
+
+#include "TrigCOOLUpdateHelper.h"
+
+#include "TrigServices/TrigHLTIssues.h"
+
+#include "GaudiKernel/INamedInterface.h"
+#include "GaudiKernel/IIncidentSvc.h"
+#include "GaudiKernel/ITHistSvc.h"
+
+#include "AthenaKernel/errorcheck.h"
+#include "AthenaKernel/IIOVDbSvc.h"
+#include "AthenaKernel/IIOVSvc.h"
+#include "AthenaKernel/IOVTime.h"
+#include "AthenaKernel/IOVRange.h"
+#include "EventInfo/EventIncident.h"
+#include "EventInfo/EventInfo.h"
+#include "EventInfo/EventType.h"
+#include "AthenaPoolUtilities/CondAttrListCollection.h"
+
+#include "CoralBase/AttributeListException.h"
+
+#include "TH1F.h"
+
+#include <boost/foreach.hpp>
+#include <boost/algorithm/string.hpp>
+
+using namespace std;
+
+
+//=========================================================================
+// Standard methods
+//=========================================================================
+TrigCOOLUpdateHelper::TrigCOOLUpdateHelper(const std::string &type,
+                                           const std::string &name,
+                                           const IInterface *parent)
+  : AthAlgTool(type, name, parent),
+    m_iovSvc(0),
+    m_iovDbSvc(0),
+    m_incidentSvc("IncidentSvc", name),
+    m_hist_timeCondUpdate(0)
+{
+  // No abstract interface
+  declareInterface<TrigCOOLUpdateHelper>(this);
+
+  declareProperty("coolFolder", m_coolFolderName = "", "Name of COOL folder containing folder map");
+  declareProperty("foldersToResetOnBeginRun", m_beginRunFolders, "COOL folders to reset at beginning of run");
+}
+
+
+TrigCOOLUpdateHelper::~TrigCOOLUpdateHelper()
+{}
+
+
+StatusCode TrigCOOLUpdateHelper::initialize()
+{
+  // Do not create these services if they are not available already
+  service("IOVSvc", m_iovSvc, /*createIf=*/false).ignore();
+  service("IOVDbSvc", m_iovDbSvc, /*createIf=*/false).ignore();
+
+  CHECK( m_incidentSvc.retrieve() );
+
+  ATH_MSG_INFO(" ---> foldersToResetOnBeginRun = ["
+               << boost::algorithm::join(m_beginRunFolders, ",") << "]");
+  
+  // Register DataHandle with COOLUPDATE folder
+  if (!m_coolFolderName.empty()) {
+    CHECK( detStore()->regHandle(m_folderMapHandle, m_coolFolderName) );
+  }
+
+  // Register incident listener
+  m_incidentSvc->addListener(this, "EndOfBeginRun");
+  
+  return StatusCode::SUCCESS;
+}
+
+
+StatusCode TrigCOOLUpdateHelper::start()
+{
+  m_folderInfo.clear();
+
+  // Book histograms
+  ServiceHandle<ITHistSvc> histSvc("THistSvc",name());
+  if ( histSvc.retrieve().isFailure() ) {
+    ATH_MSG_ERROR("Histogram service can not be retrieved");
+    return StatusCode::FAILURE;
+  }
+  
+  m_hist_timeCondUpdate = new TH1F("CoolFolderUpdateTime",
+                                   "Time for conditions update;time [ms]",
+                                   100, 0, 200);
+
+  // monitoring information root directory
+  string histPath = string("/EXPERT/");
+
+  const INamedInterface* p_parent = dynamic_cast<const INamedInterface*>(parent());
+  if (p_parent != 0) {
+    histPath = histPath + p_parent->name() + string("/");
+  } else {
+    histPath = histPath + name() + string("/");
+  }
+  if ( (histSvc->regHist(histPath + m_hist_timeCondUpdate->GetName(), m_hist_timeCondUpdate)).isFailure() ) {
+    ATH_MSG_ERROR("Registration of histogram '" << (histPath + m_hist_timeCondUpdate->GetName()) << "' failed.");
+    return StatusCode::FAILURE;
+  }
+
+  return StatusCode::SUCCESS;
+}
+
+StatusCode TrigCOOLUpdateHelper::stop()
+{
+  std::ostringstream pending;
+  // Loop over folder updates
+  for (auto f : m_folderUpdates) {
+    if (f.second.needsUpdate) pending << "[" << f.second.lumiBlock << "," << f.second.folderIndex << "]";
+  }
+  
+  if (pending.str().empty()) pending << "NONE";
+  ATH_MSG_INFO("[LB,Folder] with pending COOL updates: " << pending.str());
+
+  return StatusCode::SUCCESS;
+}
+
+void TrigCOOLUpdateHelper::handle(const Incident&)
+{
+  m_folderUpdates.clear();
+    
+  // Triggered on EndOfBeginRun, i.e. when all folders are available
+  readFolderInfo();
+  if (m_coolFolderName.empty()) return;
+  
+  if (!m_folderMapHandle.isInitialized()) {
+    ATH_MSG_ERROR("DataHandle for '" << m_coolFolderName << "' not initialized.");
+  }
+  else {
+    ATH_MSG_INFO("COOL folder map in " << m_coolFolderName << ":");
+    for (CondAttrListCollection::const_iterator c = m_folderMapHandle->begin();
+         c != m_folderMapHandle->end(); ++c) {
+      ATH_MSG_INFO("   (" << c->first << ") " << c->second["FolderName"].data<string>());
+    }
+  }
+}
+
+
+//=========================================================================
+// Read COOL folder info
+// Loop over all registered keys and get folder name and CLID
+//=========================================================================
+void TrigCOOLUpdateHelper::readFolderInfo()
+{
+  if (m_iovDbSvc==0) return;
+  
+  // Loop over all keys registered with IOVDbSvc
+  vector<string> keyList(m_iovDbSvc->getKeyList());
+  BOOST_FOREACH(string key, keyList) {
+    string foldername, tag;
+    IOVRange range;
+    bool retrieved;
+    unsigned long long bytesRead;
+    float readTime;
+
+    // Get folder name and CLID for each key
+    bool found = m_iovDbSvc->getKeyInfo(key, foldername, tag, range,
+					retrieved, bytesRead, readTime);
+
+    if ( !found || m_folderInfo.find(foldername)!=m_folderInfo.end() )
+      continue;
+    
+    CLID clid = detStore()->clid(key);
+    if (clid!=CLID_NULL)
+      m_folderInfo.insert(FolderInfoMap::value_type(foldername,FolderInfo(clid, key)));
+    else
+      ATH_MSG_ERROR("Cannot find CLID for " << key);
+  }
+}
+
+
+//=========================================================================
+// Reset COOL folders
+//=========================================================================
+StatusCode TrigCOOLUpdateHelper::resetBeginRunFolders(EventID::number_type currentRun)
+{
+  readFolderInfo();   // Folders might be only partially avaiable
+  return resetFolders(m_beginRunFolders, currentRun, false);
+}
+
+StatusCode TrigCOOLUpdateHelper::resetFolders(const std::vector<std::string>& folders,
+                                              EventID::number_type currentRun,
+                                              bool dropObject)
+{
+  if (folders.empty()) return StatusCode::SUCCESS;
+  
+  StatusCode sc(StatusCode::SUCCESS);
+  BOOST_FOREACH(string folder, folders) {
+    if ( resetFolder(folder, currentRun, dropObject).isFailure() ) sc = StatusCode::FAILURE;
+  }
+  return sc;
+}
+
+StatusCode TrigCOOLUpdateHelper::resetFolder(const std::string& folder,
+                                             EventID::number_type currentRun,
+                                             bool dropObject)
+{
+  // Force a reset of folders by setting an IOVRange in the past
+
+  if (m_iovSvc==0 || m_iovDbSvc==0) return StatusCode::SUCCESS;
+  
+  // Set IOV in the past to trigger reload in IOVSvc
+  IOVRange iov_range(IOVTime(currentRun-2, 0),
+                     IOVTime(currentRun-1, 0));
+
+  FolderInfoMap::const_iterator f = m_folderInfo.find(folder);
+  if ( f==m_folderInfo.end() ) {
+    ATH_MSG_DEBUG("Folder " << folder << " not registered with IOVDbSvc");
+    return StatusCode::SUCCESS;
+  }
+    
+  const CLID& clid = f->second.clid;
+  const string& key = f->second.key;
+  // Check if proxy exists
+  if ( detStore()->proxy(clid, key)==0 ) {
+    ATH_MSG_DEBUG("No proxy for " << key << " found");
+    return StatusCode::SUCCESS;  // on purpose not a failure
+  }
+
+  // Make sure we are not trying to reset a time-based folder    
+  IOVRange iov;
+  if ( m_iovSvc->getRange(clid, key, iov).isSuccess() ) {         
+    if ( iov.start().isTimestamp() || iov.start().isBoth() ) {
+      ATH_MSG_ERROR(folder << " is not a Run/LB based folder. Cannot perform COOL update.");
+      return StatusCode::FAILURE;
+    }
+  }
+       
+  // Invalidate IOV range
+  ATH_MSG_DEBUG("Setting IOV range of " << folder << " to " << iov_range);
+    
+  if ((m_iovSvc->setRange(clid, key, iov_range, "StoreGateSvc")).isFailure()) {
+    ATH_MSG_WARNING("Could not set IOV range for " << folder << " to " << iov_range);
+    return StatusCode::FAILURE;        
+  }
+    
+  // Drop object and reset cache
+  if (dropObject) {
+    if (not m_iovDbSvc->dropObject(key, /*resetCache=*/true)) {
+      ATH_MSG_WARNING("IOVDbSvc could not drop " << folder);
+      return StatusCode::FAILURE;
+    }
+  }
+    
+  // All OK
+  ATH_MSG_INFO("Invalidated IOV" << (dropObject ? " and dropped payload " : " ")
+               << "of folder " << folder << (key!=folder ? " (key="+key+")" : "") );
+  
+  return StatusCode::SUCCESS;
+}
+
+
+//=========================================================================
+// Folder update during the run
+//=========================================================================
+
+StatusCode TrigCOOLUpdateHelper::hltCoolUpdate(EventID::number_type currentLB,
+                                               EventID::number_type currentRun,
+                                               EventID::number_type sor_time_sec,
+                                               EventID::number_type sor_time_nsec)
+{
+  bool checkIOV_done = false;
+  
+  // Loop over folders to be updated
+  std::map<CTPfragment::FolderIndex, FolderUpdate>::iterator f = m_folderUpdates.begin();
+  for (; f!=m_folderUpdates.end(); ++f) {
+          
+    if (f->second.needsUpdate) {
+      string folderName;
+      if (getFolderName(f->second.folderIndex, folderName).isFailure()) {
+        continue;  // On purpose not a failure
+      }
+
+      const EventInfo* currentEvent(0);
+      CHECK(evtStore()->retrieve(currentEvent));
+      ATH_MSG_INFO("Reload of COOL folder " << folderName << " for IOV change in lumiblock " << f->second.lumiBlock
+                   << ". Current event: "  << *currentEvent->event_ID());
+              
+      if ( hltCoolUpdate(folderName, currentLB, currentRun,
+                         sor_time_sec, sor_time_nsec).isFailure() ) { 
+        ATH_MSG_FATAL("COOL update failed for " << folderName << ". Aborting.");
+        throw ers::HLTAbort(ERS_HERE, name()+": Failure during COOL update of "+folderName);
+      }
+      // All OK
+      checkIOV_done = true;
+      f->second.needsUpdate = false;
+    }      
+  }
+  
+  // Needs to be done on every LB change
+  if (!checkIOV_done) checkIOV(currentLB, currentRun, sor_time_sec, sor_time_nsec);
+  
+  return StatusCode::SUCCESS;
+}
+
+
+StatusCode TrigCOOLUpdateHelper::hltCoolUpdate(const std::string& folderName,
+                                               EventID::number_type currentLB,
+                                               EventID::number_type currentRun,
+                                               EventID::number_type sor_time_sec,
+                                               EventID::number_type sor_time_nsec)
+{
+  if ( m_iovSvc==0 || m_coolFolderName.empty() ) {
+    ATH_MSG_DEBUG("Passive mode. Not updating COOL folders");
+    return StatusCode::SUCCESS;
+  }
+
+  // Start timer
+  longlong t1_ms = System::currentTime(System::milliSec);
+
+  // Reset folder and make IOVDbSvc drop objects
+  
+  if (resetFolder(folderName, currentRun, true).isFailure()) {
+    ATH_MSG_ERROR("Reset of " << folderName << " failed");
+    return StatusCode::FAILURE;
+  }
+
+  checkIOV(currentLB, currentRun, sor_time_sec, sor_time_nsec);
+
+  // Stop timer and fill histogram
+  longlong t2_ms = System::currentTime(System::milliSec);
+  if (m_hist_timeCondUpdate) m_hist_timeCondUpdate->Fill(t2_ms-t1_ms);
+
+  return StatusCode::SUCCESS;
+}
+
+void TrigCOOLUpdateHelper::checkIOV(EventID::number_type currentLB,
+                                    EventID::number_type currentRun,                           
+                                    EventID::number_type sor_time_sec,
+                                    EventID::number_type sor_time_nsec)
+{
+  // Force IOVSvc to check IOV ranges    
+  EventInfo eventInfo(new EventID(currentRun, /*event*/ 0, 
+                                  sor_time_sec, sor_time_nsec,
+                                  currentLB, /*bcid*/ 0),
+                      new EventType());
+
+  EventIncident incident(eventInfo, name(), "CheckIOV");  
+  m_incidentSvc->fireIncident(incident);
+}
+
+
+StatusCode TrigCOOLUpdateHelper::getFolderName(CTPfragment::FolderIndex idx, std::string& folderName)
+{
+  if (m_coolFolderName.empty()) return StatusCode::SUCCESS;
+  
+  if (!m_folderMapHandle.isInitialized()) {
+    ATH_MSG_ERROR("DataHandle for '" << m_coolFolderName << "' not initialized.");
+    return StatusCode::FAILURE;
+  }
+  try {
+    folderName = m_folderMapHandle->attributeList(idx)["FolderName"].data<string>();      
+  }
+  catch (coral::AttributeListException &) {
+    ATH_MSG_ERROR(m_coolFolderName << " does not contain a folder for index/channel " << idx
+                  << ". Existing folders are:");
+    m_folderMapHandle->dump();
+    return StatusCode::FAILURE;
+  }
+  return StatusCode::SUCCESS;
+}
+
+
+//=========================================================================
+// Schedule COOL folder updates (called on every event by EventLoopMgr)
+//=========================================================================
+void TrigCOOLUpdateHelper::setFolderUpdates(const std::map<CTPfragment::FolderIndex, CTPfragment::FolderEntry>& folderUpdates)
+{
+  // Loop over potential new folder updates
+  std::map<CTPfragment::FolderIndex, CTPfragment::FolderEntry>::const_iterator i = folderUpdates.begin();
+  for (; i!=folderUpdates.end(); ++i) {
+
+    // Check if we already have an update for this folder
+    std::map<CTPfragment::FolderIndex, FolderUpdate>::const_iterator f = m_folderUpdates.find(i->first);
+
+    // No updates yet or this update superseds the previous one
+    if (f==m_folderUpdates.end() || (f->second.lumiBlock != i->second.lumiBlock)) {
+      m_folderUpdates[i->first] = FolderUpdate(i->second);   // new folder update
+      
+      ATH_MSG_DEBUG("Conditions update for folder " << i->second.folderIndex
+                   << " on lumiblock " << i->second.lumiBlock);
+    }
+    /* The above could be optmized by handling events from a previous lumiblock in a special way
+       and not forcing a COOL update. However, this would complicate the code and in the merged HLT
+       system events from already seen LBs will be very rare (or even impossible).
+    */
+  }
+}
diff --git a/HLT/Trigger/TrigControl/TrigServices/src/TrigCOOLUpdateHelper.h b/HLT/Trigger/TrigControl/TrigServices/src/TrigCOOLUpdateHelper.h
new file mode 100644
index 00000000000..cd47aa31dd3
--- /dev/null
+++ b/HLT/Trigger/TrigControl/TrigServices/src/TrigCOOLUpdateHelper.h
@@ -0,0 +1,191 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef TRIGSERVICES_TRIGCOOLUPDATEHELPER_H
+#define TRIGSERVICES_TRIGCOOLUPDATEHELPER_H
+/**
+ * @file   TrigCOOLUpdateHelper.h
+ * @brief  Helper tool for COOL updates
+ * @author Frank Winklmeier
+ *
+ * $Id: $
+ */
+
+// STL includes
+#include <string>
+#include <vector>
+#include <map>
+
+// Framework includes
+#include "GaudiKernel/StatusCode.h"
+#include "GaudiKernel/ServiceHandle.h"
+#include "GaudiKernel/IIncidentListener.h"
+
+#include "AthenaBaseComps/AthAlgTool.h"
+#include "StoreGate/DataHandle.h"
+#include "EventInfo/EventID.h"
+
+#include "CTPfragment/CTPExtraWordsFormat.h"
+
+class TH1F;
+class IIOVSvc;
+class IIOVDbSvc;
+class IIncidentSvc;
+class CondAttrListCollection;
+
+/**
+ * Struct to hold CLID <-> folder name mapping
+ */
+struct FolderInfo {
+  FolderInfo() : clid(CLID_NULL) {}
+  FolderInfo(const CLID& cl, const std::string& k) : clid(cl), key(k) {}
+  CLID clid;
+  std::string key;
+};
+
+/**
+ * Folder update entry
+ */
+struct FolderUpdate {
+  FolderUpdate() : lumiBlock(0), folderIndex(0), needsUpdate(true) {}
+  FolderUpdate(const CTPfragment::FolderEntry& entry) :
+    lumiBlock(entry.lumiBlock),
+    folderIndex(entry.folderIndex),
+    needsUpdate(true) {}
+  
+  EventID::number_type lumiBlock;
+  CTPfragment::FolderIndex folderIndex;
+  bool needsUpdate;
+};
+
+/**
+ * @brief Tool to perform COOL updates during the run
+ *
+ */
+class TrigCOOLUpdateHelper : public AthAlgTool,
+                             public IIncidentListener
+{
+public:
+  
+  TrigCOOLUpdateHelper(const std::string &type, const std::string &name, const IInterface *parent);    
+  virtual ~TrigCOOLUpdateHelper();
+
+  static const InterfaceID& interfaceID();  
+  virtual StatusCode initialize();
+  virtual StatusCode start();
+  virtual StatusCode stop();
+  virtual void handle (const Incident&);
+  
+  /**
+   * @brief Reset folders configured to be reset on BeginRun
+   * @param currentRun  Current run number
+   */
+  StatusCode resetBeginRunFolders(EventID::number_type currentRun);
+
+  /**
+   * @brief Perform COOL udpates if needed
+   * @param currentLB      Current lumiblock
+   * @param currentRun     Current run number   
+   * @param sor_time_sec   Start-Of-Run time in seconds
+   * @param sor_time_nsec  Start-Of-Run time offset in nanoseconds
+   */
+  StatusCode hltCoolUpdate(EventID::number_type currentLB,
+                           EventID::number_type currentRun,
+                           EventID::number_type sor_time_sec,
+                           EventID::number_type sor_time_nsec);
+  
+  /**
+   * @brief Update specified COOL folder
+   * @param folder         COOL folder to reset
+   * @param currentLB      Current lumiblock
+   * @param currentRun     Current run number
+   * @param sor_time_sec   Start-Of-Run time in seconds
+   * @param sor_time_nsec  Start-Of-Run time offset in nanoseconds
+   * @param doProxyReset   Drop object and reset cache
+   */
+  StatusCode hltCoolUpdate(const std::string& folder,
+                           EventID::number_type currentLB,
+                           EventID::number_type currentRun,                           
+                           EventID::number_type sor_time_sec,
+                           EventID::number_type sor_time_nsec);
+
+  /**
+   * @brief Force IOVSvc to recheck all IOVs (needs to be called on every LB change)
+   * @param currentLB      Current lumiblock
+   * @param currentRun     Current run number      
+   * @param sor_time_sec   Start-Of-Run time in seconds
+   * @param sor_time_nsec  Start-Of-Run time offset in nanoseconds   
+   */
+  void checkIOV(EventID::number_type currentLB,
+                EventID::number_type currentRun,                           
+                EventID::number_type sor_time_sec,
+                EventID::number_type sor_time_nsec);
+
+  /**
+   * @brief Return folder name to index
+   * @param idx         Folder index
+   * @param folderName  Returns folder name
+   */
+  StatusCode getFolderName(CTPfragment::FolderIndex idx, std::string& folderName);
+  
+  /**
+   * @brief Set the folder updates as retrieved from the CTP fragment
+   * @param map returned by CTPfragment::ExtraPayload::getFolderUpdates()
+   */
+  void setFolderUpdates(const std::map<CTPfragment::FolderIndex, CTPfragment::FolderEntry>& folderUpdates);
+  
+private:
+
+  /**
+   * @brief Reset COOL folder
+   * @param folder COOL folder name
+   * @param currentRun Current run number
+   * @param dropObject Drop object and reset cache
+   */
+  StatusCode resetFolder(const std::string& folder,
+                         EventID::number_type currentRun,
+                         bool dropObject = false);
+  
+  /**
+   * @brief Reset list of COOL folders
+   * @param folders List of folder names
+   * @param currentRun Current run number
+   * @param dropObject Drop object and reset cache
+   */
+  StatusCode resetFolders(const std::vector<std::string>& folders,
+                          EventID::number_type currentRun,
+                          bool dropObject = false);
+
+  /**
+   * Read information about existing COOL folders
+   */
+  void readFolderInfo();
+
+  typedef std::map<std::string, FolderInfo> FolderInfoMap;
+  FolderInfoMap m_folderInfo;  //!< COOL folder info
+  
+  const DataHandle<CondAttrListCollection> m_folderMapHandle;
+  std::map<CTPfragment::FolderIndex, FolderUpdate> m_folderUpdates;
+  
+  // Services and Tools
+  IIOVSvc*                    m_iovSvc;
+  IIOVDbSvc*                  m_iovDbSvc;
+  ServiceHandle<IIncidentSvc> m_incidentSvc;
+
+  // Histograms
+  TH1F*        m_hist_timeCondUpdate;   //!< Timing histogram for conditions updates
+  
+  // Properties
+  std::string               m_coolFolderName;        //!< COOL folder name
+  std::vector<std::string>  m_beginRunFolders;  //!< Folders to reset before BeginRun
+};
+
+
+inline const InterfaceID& TrigCOOLUpdateHelper::interfaceID()
+{
+  static const InterfaceID _IID("TrigCOOLUpdateHelper", 1, 0);
+  return _IID;
+}
+
+#endif
diff --git a/HLT/Trigger/TrigControl/TrigServices/src/TrigIS.cxx b/HLT/Trigger/TrigControl/TrigServices/src/TrigIS.cxx
new file mode 100644
index 00000000000..e4a39857e59
--- /dev/null
+++ b/HLT/Trigger/TrigControl/TrigServices/src/TrigIS.cxx
@@ -0,0 +1,85 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+/**
+ * @file   TrigIS.cxx
+ * @brief  Implementation of TrigIS service
+ * @author Frank Winklmeier
+ *
+ * $Id: TrigIS.cxx 5 2013-05-14 10:33:04Z ricab $
+ */
+
+#include "TrigServices/TrigIS.h"
+#include "is/info.h"
+
+TrigIS::TrigIS(const std::string& name, ISvcLocator* pSvcLocator) :
+  AthService(name, pSvcLocator),
+  m_validPartition(false)
+{
+  declareProperty("Partition", m_partitionName = "NONE", "Partition name");
+}
+
+TrigIS::~TrigIS()
+{
+}
+
+StatusCode TrigIS::queryInterface(const InterfaceID& riid, void** ppvInterface)
+{
+  if ( ppvInterface==0 ) return StatusCode::FAILURE;
+
+  if ( ITrigIS::interfaceID().versionMatch(riid) ) {
+    *ppvInterface = static_cast<ITrigIS*>(this);
+    addRef();
+    return StatusCode::SUCCESS;
+  }
+  else {
+    return AthService::queryInterface(riid, ppvInterface);
+  }
+}
+
+StatusCode TrigIS::initialize()
+{
+  if (m_partitionName=="NONE") {
+    msg() << MSG::WARNING << "No partition specified. Will not publish any data to IS." << endreq;    
+    return StatusCode::SUCCESS;
+  }
+  
+  // Try to initialize IPC core
+  try {
+    int nIPCOpts = 0;
+    IPCCore::init(nIPCOpts, 0);
+    m_partition = IPCPartition(m_partitionName);
+    m_isDict = ISInfoDictionary(m_partition);
+  }
+  catch ( daq::ipc::Exception & ex ) {
+    msg() << MSG::ERROR << "Failure during initialize: " << ex.what() << endreq;
+    return StatusCode::FAILURE;
+  }
+
+  m_validPartition = true;
+  return StatusCode::SUCCESS;
+}
+
+
+StatusCode TrigIS::publish(const std::string& name, const ISInfo& info, bool keep_history)
+{
+  if (m_validPartition) {
+    try {
+      m_isDict.checkin(name, info, keep_history);
+    }
+    catch ( daq::is::Exception& ex ) {
+      msg() << MSG::ERROR << "Failure publishing " << name << ": " << ex.what() << endreq;
+      return StatusCode::FAILURE;
+    }
+  }
+  return StatusCode::SUCCESS;
+}
+
+// Dummy implementation for now
+void TrigIS::publish_async(const std::string& name, ISInfo* info, bool keep_history)
+{
+  publish(name, *info, keep_history).ignore();
+  delete info;
+}
+
diff --git a/HLT/Trigger/TrigControl/TrigServices/src/TrigISHelper.cxx b/HLT/Trigger/TrigControl/TrigServices/src/TrigISHelper.cxx
new file mode 100644
index 00000000000..23a5159c2b5
--- /dev/null
+++ b/HLT/Trigger/TrigControl/TrigServices/src/TrigISHelper.cxx
@@ -0,0 +1,139 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+/**
+ * @file   TrigISHelper.cxx
+ * @brief  Helper tool for IS access
+ * @author Frank Winklmeier, Werner Wiedenmann
+ *
+ * $Id: TrigISHelper.cxx 5 2013-05-14 10:33:04Z ricab $
+ */
+
+#include "TrigServices/TrigISHelper.h"
+
+
+using namespace std;
+
+//=========================================================================
+// Standard methods
+//=========================================================================
+TrigISHelper::TrigISHelper(const std::string &type,
+                           const std::string &name,
+                           const IInterface *parent)
+  : AthAlgTool(type, name, parent)
+{
+  // No abstract interface due to templates
+  declareInterface<TrigISHelper>(this);
+  
+  declareProperty("PartitionName", m_partitionName = "NONE",
+                  "Default partition name if not explicitly specified in IS identifier properties");
+  m_partitionName.declareUpdateHandler(&TrigISHelper::initPartitionName, this);
+
+  declareProperty("ignoreIfMissing", m_ignoreIfMissing = false,
+                  "Return SUCCESS if IS object is missing (for testing only)");
+
+  const string& help = "IS identifier: [Partition/]ISServer.ISInfoName";
+
+  declareProperty("RunParams",
+                  m_isprop[RunParams] = "RunParams.RunParams",
+                  help);
+  
+  declareProperty("LumiBlock",
+                  m_isprop[LumiBlock] = "RunParams.LumiBlock",
+		  help);
+    
+  declareProperty("SolenoidCurrent",
+                  m_isprop[SolenoidCurrent] = "initial/DCS_GENERAL.MagnetSolenoidCurrent.value",
+                  help);
+  
+  declareProperty("ToroidCurrent",
+                  m_isprop[ToroidCurrent] = "initial/DCS_GENERAL.MagnetToroidsCurrent.value",
+                  help);
+}
+
+
+TrigISHelper::~TrigISHelper()
+{}
+
+
+StatusCode TrigISHelper::initialize()
+{
+  if (m_ignoreIfMissing ) {
+    msg() << MSG::WARNING << "Will ignore any missing IS objects and return SUCCESS" << endreq;
+  }
+
+  return StatusCode::SUCCESS;
+}
+
+
+
+void TrigISHelper::initPartitionName(Property& /*prop*/)
+{
+  m_isid.clear();
+  
+  if (msgLvl(MSG::DEBUG))
+    msg() << MSG::DEBUG << "Configured ISInfo objects (partition : name):" << endreq;
+  
+  // Fill map with partition and IS names
+  map<ISObject, string>::const_iterator iter = m_isprop.begin();
+  for (; iter != m_isprop.end(); ++iter ) {
+    m_isid[iter->first] = split(iter->second);
+
+    if (msgLvl(MSG::DEBUG))
+      msg() << MSG::DEBUG << "   " << m_isid[iter->first].first
+            << " : " << m_isid[iter->first].second << endreq;
+  } 
+}
+
+//=========================================================================
+// Read IS value
+//=========================================================================
+StatusCode TrigISHelper::findValue(ISObject obj, ISInfo& value)
+{
+  const string& partName = m_isid[obj].first;
+  const string& isName = m_isid[obj].second;
+
+  // read values from IS
+  try {
+    IPCPartition part(partName);
+    ISInfoDictionary isInfoDict(part);
+    isInfoDict.findValue(isName, value);
+  }
+  catch (daq::is::Exception& e) {
+    msg() << MSG::WARNING << "IS Exception reading " << isName << " from partition "
+          << partName << ". Exception was: " << e << endreq;
+    
+    return m_ignoreIfMissing ? StatusCode::SUCCESS : StatusCode::FAILURE;
+  }
+
+  if ( msgLvl(MSG::DEBUG) ) {
+    msg() << MSG::DEBUG << "Successfully read " << isName << " from IS: " << value << endreq;
+  }
+  return StatusCode::SUCCESS;  
+}
+
+
+const std::string& TrigISHelper::partition(ISObject obj) const
+{
+  return m_isid.find(obj)->second.first;
+}
+
+
+const std::string& TrigISHelper::isName(ISObject obj) const
+{
+  return m_isid.find(obj)->second.second;
+}
+
+
+
+//=========================================================================
+// Helper to split ISObject property string
+//=========================================================================
+pair<string,string> TrigISHelper::split(const std::string& isid)
+{
+  size_t i = isid.find("/");
+  if (i==string::npos) return make_pair(m_partitionName.value(), isid);
+
+  return make_pair(isid.substr(0, i), isid.substr(i+1, isid.length()-i));
+}
diff --git a/HLT/Trigger/TrigControl/TrigServices/src/TrigMessageSvc.cxx b/HLT/Trigger/TrigControl/TrigServices/src/TrigMessageSvc.cxx
new file mode 100644
index 00000000000..bfada2b9306
--- /dev/null
+++ b/HLT/Trigger/TrigControl/TrigServices/src/TrigMessageSvc.cxx
@@ -0,0 +1,1203 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+// $Id: TrigMessageSvc.cxx 5 2013-05-14 10:33:04Z ricab $
+
+#include "GaudiKernel/Kernel.h"
+#include "GaudiKernel/IIncidentSvc.h"
+#include "GaudiKernel/ITHistSvc.h"
+#include "GaudiKernel/StatusCode.h"
+#include "GaudiKernel/SvcFactory.h"
+#include "GaudiKernel/Message.h"
+#include "GaudiKernel/xtoa.h"
+#include "GaudiKernel/IJobOptionsSvc.h"
+#include "EventInfo/EventInfo.h"
+#include "EventInfo/EventID.h"
+#include "TrigServices/TrigMessageSvc.h"
+#include "TrigServices/TrigHLTIssues.h"
+#include "TrigMonitorBase/TrigLockedHist.h"
+
+#include <TH1I.h>
+#include <TH2I.h>
+
+#include <sstream>
+#include <iostream>
+
+#include <pthread.h>
+#include <boost/thread/recursive_mutex.hpp>
+
+
+static pthread_mutex_t msgsvcmutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
+
+using namespace std;
+
+static std::string levelNames[MSG::NUM_LEVELS];
+
+// ERS debug level for which to enforce DEBUG OutputLevel
+static int ersGaudiDebugOffset = 8;
+
+// Constructor
+TrigMessageSvc::TrigMessageSvc( const std::string& name, ISvcLocator* svcloc )
+  : Service(name, svcloc)
+  , m_doSuppress{false}
+  , m_running{false}
+  , m_canEnter{false}
+  , m_evtStore{"StoreGateSvc/StoreGateSvc", name}
+  , m_msgCountHist{nullptr}
+  , m_msgCountSrcHist{nullptr}
+{
+  m_defaultStream = &std::cout;
+  m_outputLevel   = MSG::NIL;
+  declareProperty( "Format",      m_defaultFormat = "% F%18W%S%7W%R%T %0W%M" );
+  declareProperty( "timeFormat",  m_defaultTimeFormat = "%Y-%m-%d %H:%M:%S,%f" );
+
+  declareProperty( "showStats",    m_stats = false );
+  declareProperty( "statLevel",    m_statLevel = 0, "Show statistics for messages >= level" );
+  declareProperty( "statLevelRun", m_statLevelRun = 0, "Show per-run statistics for messages >= level" );
+  
+  declareProperty( "publishStats", m_publishStats = false,
+                   "Publish message statistics as histogram");
+  
+  declareProperty( "publishLevel", m_publishLevel = MSG::INFO,
+                   "Publish message statistics for this and higher message levels");
+  
+  declareProperty( "resetStatsAtBeginRun", m_resetStats = false );  
+
+  declareProperty( "printEventIDLevel", m_eventIDLevel = MSG::WARNING,
+                   "Print event ID for this and higher message levels");
+                   
+  // Special properties to control output level of individual sources
+  declareProperty( "setVerbose",  m_thresholdProp[MSG::VERBOSE] );
+  declareProperty( "setDebug",    m_thresholdProp[MSG::DEBUG] );
+  declareProperty( "setInfo",     m_thresholdProp[MSG::INFO] );
+  declareProperty( "setWarning",  m_thresholdProp[MSG::WARNING] );
+  declareProperty( "setError",    m_thresholdProp[MSG::ERROR] );
+  declareProperty( "setFatal",    m_thresholdProp[MSG::FATAL] );
+  declareProperty( "setAlways",   m_thresholdProp[MSG::ALWAYS] );
+
+  declareProperty( "useColors",        m_color=false);
+  m_color.declareUpdateHandler(&TrigMessageSvc::initColors, this);
+
+  declareProperty( "fatalColorCode",   m_logColors[MSG::FATAL] );
+  declareProperty( "errorColorCode",   m_logColors[MSG::ERROR] );
+  declareProperty( "warningColorCode", m_logColors[MSG::WARNING] );
+  declareProperty( "infoColorCode",    m_logColors[MSG::INFO] );
+  declareProperty( "debugColorCode",   m_logColors[MSG::DEBUG] );
+  declareProperty( "verboseColorCode", m_logColors[MSG::VERBOSE] );
+  declareProperty( "alwaysColorCode",  m_logColors[MSG::ALWAYS] );
+
+  m_defaultLimit = 500;
+  declareProperty( "fatalLimit",    m_msgLimit[MSG::FATAL]   = m_defaultLimit );
+  declareProperty( "errorLimit",    m_msgLimit[MSG::ERROR]   = m_defaultLimit );
+  declareProperty( "warningLimit",  m_msgLimit[MSG::WARNING] = m_defaultLimit );
+  declareProperty( "infoLimit",     m_msgLimit[MSG::INFO]    = m_defaultLimit );
+  declareProperty( "debugLimit",    m_msgLimit[MSG::DEBUG]   = m_defaultLimit );
+  declareProperty( "verboseLimit",  m_msgLimit[MSG::VERBOSE] = m_defaultLimit );
+  declareProperty( "alwaysLimit",   m_msgLimit[MSG::ALWAYS]  = 0 );
+
+  declareProperty( "defaultLimit",  m_msgLimit[MSG::NIL]     = m_defaultLimit );
+
+  declareProperty( "enableSuppression", m_suppress = false,
+                   "Enable message suppression");
+  
+  declareProperty( "suppressRunningOnly", m_suppressRunningOnly = true,
+                   "Use message suppression only during RUNNING state");
+
+  m_suppress.declareUpdateHandler(&TrigMessageSvc::setupSuppression, this);
+  m_suppressRunningOnly.declareUpdateHandler(&TrigMessageSvc::setupSuppression, this);
+  
+  /* Special properties to control output to ERS of individual sources.
+     The syntax is as follows (these are NOT regular expressions):
+     
+     useErsFatal = []                       # forward none (default)
+     useErsFatal = ['*']                    # forward all
+     useErsFatal = ['CoreDumpSvc','MyAlg']  # forward these sources
+     useErsFatal = ['*','!MyAlg']           # forward all except MyAlg
+  */
+    
+  const vector<string> defaultErsUse;
+  declareProperty( "useErsVerbose",  m_useERS[MSG::VERBOSE] = defaultErsUse );
+  declareProperty( "useErsDebug",    m_useERS[MSG::DEBUG]   = defaultErsUse );
+  declareProperty( "useErsInfo",     m_useERS[MSG::INFO]    = defaultErsUse );
+  declareProperty( "useErsWarning",  m_useERS[MSG::WARNING] = defaultErsUse );
+  declareProperty( "useErsError",    m_useERS[MSG::ERROR]   = defaultErsUse );
+  declareProperty( "useErsFatal",    m_useERS[MSG::FATAL]   = defaultErsUse );
+  declareProperty( "useErsAlways",   m_useERS[MSG::ALWAYS]  = defaultErsUse );
+
+  declareProperty( "alwaysUseMsgStream", m_alwaysUseMsgStream = true,
+                   "Print all messages to MsgStream, even if forwarded to ERS");
+  
+  declareProperty( "useErsRunningOnly", m_useErsRunningOnly = false,
+                   "Forward messages to ERS only during RUNNING state");  
+                   
+  declareProperty( "forceOutputLevel", m_forceOutputLevel = false,
+                   "Enforce the global OutputLevel for all sources");
+
+  for (int ic=0; ic<MSG::NUM_LEVELS; ++ic) {
+    m_logColors[ic].declareUpdateHandler(&TrigMessageSvc::setupColors, this);
+    m_msgLimit[ic].declareUpdateHandler(&TrigMessageSvc::setupLimits, this);
+    m_thresholdProp[ic].declareUpdateHandler(&TrigMessageSvc::setupThreshold, this);
+  }
+
+  levelNames[0] = "NIL";
+  levelNames[1] = "VERBOSE";
+  levelNames[2] = "DEBUG";
+  levelNames[3] = "INFO";
+  levelNames[4] = "WARNING";
+  levelNames[5] = "ERROR";
+  levelNames[6] = "FATAL";
+  levelNames[7] = "ALWAYS";
+
+}
+//#############################################################################
+// Destructor
+TrigMessageSvc::~TrigMessageSvc()
+{
+  pthread_mutex_destroy(&msgsvcmutex);
+}
+
+/// Initialize Service 
+StatusCode TrigMessageSvc::initialize() {
+
+  StatusCode sc;
+  sc = Service::initialize();
+  if( sc.isFailure() ) return sc;
+  
+  m_running = false;
+  m_canEnter = true;
+  
+#ifdef _WIN32
+  m_color = false;
+#endif  
+  
+  // Reset message counters
+  resetMsgStats();
+  m_sourceMapTotal.clear();
+
+  // Initialize message suppression
+  setupSuppression(m_suppress);
+
+  m_colMap["black"]  = MSG::BLACK;
+  m_colMap["red"]    = MSG::RED;
+  m_colMap["green"]  = MSG::GREEN;
+  m_colMap["yellow"] = MSG::YELLOW;
+  m_colMap["blue"]   = MSG::BLUE;
+  m_colMap["purple"] = MSG::PURPLE;
+  m_colMap["cyan"]   = MSG::CYAN;
+  m_colMap["white"]  = MSG::WHITE;
+
+  /*
+   * m_state is set in the base class sysInitialize after initialize succeeded.
+   * However, we need to set it already here otherwise the following
+   * use of IncidentSvc/JobOptionsSvc creates a service initialization loop.
+   */
+  m_state = Gaudi::StateMachine::INITIALIZED;
+
+  /*
+   * This will force the OutputLevel of all components to be the global
+   * OutputLevel (m_outputLevel of this service). It should cover the use-cases:
+   *    1) 'MsgStream(msgSvc(),name())'
+   *    2) 'MsgStream::setLevel(m_outputLevel)'
+   * For 2) we rely on the fact that the MessageSvc is created/initialized after
+   * the JobOptionsSvc in ApplicationMgr::i_startup().
+   */
+  int ers_debug = ers::Configuration::instance().debug_level();
+  if ( ers_debug >= ersGaudiDebugOffset+1 ) {
+    setOutputLevel(MSG::VERBOSE);
+    m_forceOutputLevel.setValue(true);
+  }
+  else if ( ers_debug >= ersGaudiDebugOffset ) {
+    setOutputLevel(MSG::DEBUG);
+    m_forceOutputLevel.setValue(true);
+  }
+  
+  if ( m_forceOutputLevel.value() ) {
+    resetOutputLevels();             // Clear all individual OutputLevels (to cover use-case 1)
+    setOutputLevelViaJobOptSvc();    // Set 'OutputLevel' in JobOptionsSvc (to cover use-case 2)
+    reportMessage(name(), MSG::INFO, "Enforcing global OutputLevel = "+levelNames[m_outputLevel.value()]);
+  }
+  
+  // Register incident handlers
+  ServiceHandle<IIncidentSvc> incSvc("IncidentSvc",name());
+  sc = incSvc.retrieve();
+  if (sc.isFailure()) {
+    reportMessage(name(), MSG::WARNING, "Cannot find IncidentSvc");
+  }
+  else {
+    incSvc->addListener(this, "BeginRun", LONG_MAX);
+    incSvc->addListener(this, "EndOfBeginRun", LONG_MAX);
+    incSvc->addListener(this, "EndRun", LONG_MAX);
+  }
+
+ return StatusCode::SUCCESS;
+}
+
+//#############################################################################
+
+/// Reinitialize Service 
+StatusCode TrigMessageSvc::reinitialize() {
+  m_state = Gaudi::StateMachine::OFFLINE;
+  return initialize();
+}
+
+
+//#############################################################################
+void TrigMessageSvc::handle(const Incident& inc) {
+
+  // We cannot use start/stop for the MessageSvc due to bug #46216
+  if (inc.type()=="BeginRun") {
+    if (m_suppressRunningOnly.value()) {
+      m_doSuppress = m_suppress.value();
+    }
+    if (m_publishStats) bookHistograms();
+  }
+  else if (inc.type()=="EndOfBeginRun") {
+    if (m_resetStats) {
+      reportMessage(name(), MSG::INFO, "Resetting message counts");
+      resetMsgStats();
+    }
+    m_running = true;
+  }
+  else if (inc.type()=="EndRun") {
+    m_running = false;
+    if (m_resetStats) reportMsgStats(MSG::INFO);
+    if (m_suppressRunningOnly.value()) m_doSuppress = false;
+  }
+}
+
+
+//#############################################################################
+void TrigMessageSvc::resetMsgStats()
+{
+  // Copy current counts to total counts map
+  std::map<std::string,msgAry>::const_iterator itr;
+  std::map<std::string,msgAry>::iterator tot;
+  for (itr=m_sourceMap.begin(); itr!=m_sourceMap.end(); ++itr) {
+    tot = m_sourceMapTotal.find(itr->first);
+    if (tot==m_sourceMapTotal.end()) {  // new entry
+      for (int i=0; i<MSG::NUM_LEVELS; i++) m_sourceMapTotal[itr->first].msg[i] = itr->second.msg[i];
+    }
+    else {  // existing entry
+      for (int i=0; i<MSG::NUM_LEVELS; i++) tot->second.msg[i] += itr->second.msg[i];
+    }
+  }
+      
+  m_sourceMap.clear();
+  m_msgCountMap.clear();
+  for (int i=0; i<MSG::NUM_LEVELS; i++) m_msgCount[i] = 0;
+}
+
+
+// ---------------------------------------------------------------------------
+// Book the message stats histograms
+// ---------------------------------------------------------------------------
+void TrigMessageSvc::bookHistograms()
+{
+  ServiceHandle<ITHistSvc> histSvc("THistSvc",name());
+  if ( histSvc.retrieve().isFailure() ) {
+    reportMessage(name(), MSG::WARNING,
+                  "Cannot find THistSvc. Message stats will not be published.");
+    return;
+  }
+  
+  // monitoring information root directory
+  const string path = "/EXPERT/" + name() + "/";
+  const int nLevelBins = MSG::NUM_LEVELS - m_publishLevel;
+  m_msgCountHist = new TH1I("MessageCount", "Messages while RUNNING;Severity;Count",
+                            nLevelBins, 0, nLevelBins);
+
+  const int nSrcBins = 1;
+  m_msgCountSrcHist = new TH2I("MessageCountBySource", "Messages while RUNNING;Severity;Source",
+                               nLevelBins, 0, nLevelBins, nSrcBins, 0, nSrcBins);
+
+    
+  for (int i=m_publishLevel; i<MSG::NUM_LEVELS; i++) {
+    m_msgCountHist->GetXaxis()->SetBinLabel(i-m_publishLevel+1, levelNames[i].c_str());
+    m_msgCountSrcHist->GetXaxis()->SetBinLabel(i-m_publishLevel+1, levelNames[i].c_str());    
+  }
+  
+  if ( histSvc->regHist(path + m_msgCountHist->GetName(), m_msgCountHist).isFailure() ) {
+    reportMessage(name(), MSG::WARNING, "Cannot register monitoring histogram 'MessageCount'");
+  }  
+  if ( histSvc->regHist(path + m_msgCountSrcHist->GetName(), m_msgCountSrcHist).isFailure() ) {
+    reportMessage(name(), MSG::WARNING, "Cannot register monitoring histogram 'MessageCountBySource'");
+  }
+}
+
+void TrigMessageSvc::initColors(Property& /*prop*/) {
+
+  if (m_color == true) {
+
+    if (m_logColors[MSG::FATAL].value().size() == 0) {
+      vector<string> fatDef;
+      fatDef.push_back( "[94;101;1m" );
+      m_logColors[MSG::FATAL].set( fatDef );
+    } else {
+      TrigMessageSvc::setupColors( m_logColors[MSG::FATAL] );
+    }
+    
+    if (m_logColors[MSG::ERROR].value().size() == 0) {
+      vector<string> errDef;
+      errDef.push_back( "[97;101;1m" );
+      m_logColors[MSG::ERROR].set( errDef );
+    } else {
+      TrigMessageSvc::setupColors( m_logColors[MSG::ERROR] );
+    }
+    
+    if (m_logColors[MSG::WARNING].value().size() == 0) {
+      vector<string> warDef;
+      warDef.push_back( "[93;1m" );
+      m_logColors[MSG::WARNING].set( warDef );
+    } else {
+      TrigMessageSvc::setupColors( m_logColors[MSG::WARNING] );
+    }
+
+  } else {
+    
+    // reset all color codes;
+    for (int ic=0; ic<MSG::NUM_LEVELS; ++ic) {
+      vector<string> def;
+      m_logColors[ic].set( def );
+    }
+
+  }
+
+}
+
+//#############################################################################
+
+void TrigMessageSvc::setupColors(Property& prop) {
+
+  if (! m_color) return;
+
+  int ic;
+  if (prop.name() == "fatalColorCode") {
+    ic = MSG::FATAL;
+  } else if (prop.name() == "errorColorCode") {
+    ic = MSG::ERROR;
+  } else if (prop.name() == "warningColorCode") {
+    ic = MSG::WARNING;
+  } else if (prop.name() == "infoColorCode") {
+    ic = MSG::INFO;
+  } else if (prop.name() == "debugColorCode") {
+    ic = MSG::DEBUG;
+  } else if (prop.name() == "verboseColorCode") {
+    ic = MSG::VERBOSE;
+  } else if (prop.name() == "alwaysColorCode") {
+    ic = MSG::ALWAYS;
+  } else {
+    std::ostringstream internal_msg ;
+    internal_msg << "ERROR: Unknown message color parameter: " << prop.name();
+    if (passErsFilter(name(), m_useERS[MSG::ERROR])) {
+      ers::error( ers::HLTMessage(ERS_HERE,internal_msg.str()) );
+    } else {
+      std::cerr << internal_msg.str() << std::endl;
+    }
+    return;
+  }
+
+  string code;
+  vector<string>::const_iterator itr;
+  itr = m_logColors[ic].value().begin();
+
+  if ( m_logColors[ic].value().size() == 1 ) {
+
+    if (*itr == "") {
+      code = "";
+    } else if (itr->substr(0,1) == "[") {
+      code = "\033" + *itr;
+    } else {
+      code = "\033[" + colTrans(*itr, 90) + ";1m";
+    }
+
+  } else if (m_logColors[ic].value().size() == 2) {
+    vector<string>::const_iterator itr2 = itr + 1;
+
+    code =  "\033[" + colTrans(*itr, 90) + ";"
+      + colTrans(*itr2, 100) + ";1m";
+
+  }
+
+  m_logColorCodes[ic] = code; 
+
+}
+//#############################################################################
+
+void TrigMessageSvc::setupLimits(Property& prop) {
+  const auto& pname = prop.name();
+  if (pname == "alwaysLimit") {
+    IntegerProperty *p = dynamic_cast<IntegerProperty*>(&prop);
+    if (p && p->value() != 0) {
+      std::ostringstream internal_msg ;
+      internal_msg << "TrigMessageSvc ERROR: cannot suppress ALWAYS messages" ;
+      if (passErsFilter(name(), m_useERS[MSG::ERROR])) {
+        ers::error( ers::HLTMessage(ERS_HERE,internal_msg.str()) );
+      } else {
+        std::cerr << internal_msg.str() << std::endl;
+      }
+      p->setValue(0);
+    }
+  } else if (pname == "defaultLimit") {
+    // Only change the limits that are still on the default value
+    for (int i = MSG::VERBOSE; i< MSG::NUM_LEVELS; ++i) {
+      if ( (i != MSG::ALWAYS) && (m_msgLimit[i].value() == m_defaultLimit) ) {
+        m_msgLimit[i] = m_msgLimit[MSG::NIL].value();
+      }
+    }
+  } else if (pname != "fatalLimit" &&
+             pname != "errorLimit" &&
+             pname != "warningLimit" &&
+             pname != "infoLimit" &&
+             pname != "debugLimit" &&
+             pname != "verboseLimit") {
+    std::ostringstream internal_msg ;
+    internal_msg << "TrigMessageSvc ERROR: Unknown message limit parameter: " << prop.name() ;
+    if (passErsFilter(name(), m_useERS[MSG::ERROR])) {
+      ers::error( ers::HLTMessage(ERS_HERE,internal_msg.str()) );
+    } else {
+      std::cerr << internal_msg.str() << std::endl;
+    }
+    return;
+  }
+}
+//#############################################################################
+
+void TrigMessageSvc::setupThreshold(Property& prop) {
+
+  int ic = 0;
+  if (prop.name() == "setFatal") {
+    ic = MSG::FATAL;
+  } else if (prop.name() == "setError") {
+    ic = MSG::ERROR;
+  } else if (prop.name() == "setWarning") {
+    ic = MSG::WARNING;
+  } else if (prop.name() == "setInfo") {
+    ic = MSG::INFO;
+  } else if (prop.name() == "setDebug") {
+    ic = MSG::DEBUG;
+  } else if (prop.name() == "setVerbose") {
+    ic = MSG::VERBOSE;
+  } else if (prop.name() == "setAlways") {
+    ic = MSG::ALWAYS;
+  } else {
+    std::ostringstream internal_msg ;
+    internal_msg << "TrigMessageSvc ERROR: Unknown message theshold parameter: " << prop.name();
+    if (passErsFilter(name(), m_useERS[MSG::ERROR])) {
+      ers::error( ers::HLTMessage(ERS_HERE,internal_msg.str()) );
+    } else {
+      std::cerr << internal_msg.str() << std::endl;
+    }
+    return;
+  }
+
+  StringArrayProperty *sap = dynamic_cast<StringArrayProperty*>( &prop);
+  if (sap == 0) {
+    std::ostringstream internal_msg ;
+    internal_msg << "could not dcast " << prop.name() 
+		 << " to a StringArrayProperty (which it should be!)";
+    if (passErsFilter(name(),m_useERS[MSG::ERROR])) {
+      ers::error( ers::HLTMessage(ERS_HERE,internal_msg.str()) );
+    } else {
+      std::cerr << internal_msg.str() << std::endl;
+    }
+    return;
+  } else {
+    std::vector<std::string>::const_iterator itr;
+    for ( itr =  sap->value().begin();
+	  itr != sap->value().end(); 
+	  ++itr) {
+      setOutputLevel( *itr, ic );
+    }
+  }
+
+}
+
+//#############################################################################
+
+bool TrigMessageSvc::passErsFilter(const std::string& source,
+                                   const std::vector<std::string>& filter)
+{
+  if (m_useErsRunningOnly.value() and not m_running) return false;
+  if (filter.empty()) return false;   // forward none
+  vector<string>::const_iterator it = filter.begin();
+  if (filter.size()==1 && (*it)=="*") return true;   // forward all
+
+  bool pass(false);
+  for (; it!=filter.end(); ++it) {
+    if ((*it)=="*") pass=true;           // forward except if there is a veto later
+    if (source==(*it)) return true;      // forward specific source
+    if ("!"+source==(*it)) return false; // veto specific source
+  }
+  return pass;
+}
+
+  
+//#############################################################################
+
+void TrigMessageSvc::setupSuppression(Property& /*prop*/) {
+  // (De)activate suppression
+  if ( m_suppressRunningOnly.value() ) {
+    m_doSuppress = (m_running && m_suppress.value());
+  }
+  else {
+    m_doSuppress = m_suppress.value();
+  }
+}
+
+//#############################################################################
+/// Finalize Service
+StatusCode TrigMessageSvc::finalize() {
+
+  m_running = false;
+  m_doSuppress = false;
+  resetMsgStats();  // to get the final total sum
+  reportMsgStats(m_statLevel.value(),true);
+  m_state = Gaudi::StateMachine::OFFLINE;
+  return StatusCode::SUCCESS;
+}
+
+
+//#############################################################################
+/// Report message counts
+void TrigMessageSvc::reportMsgStats(uint statLevel, bool total) {
+
+  std::ostringstream os;
+
+  if (m_stats) {
+    os << "Summarizing all message counts";
+    if (!total){
+      const EventInfo* pEvent(0);
+      if ( m_evtStore->retrieve(pEvent).isSuccess() ) {
+        os  << " for run " << pEvent->event_ID()->run_number();
+      }
+    }	
+    os << " (severity >= " << levelNames[statLevel] << ")" << endl;
+  } else {
+    os << "Listing sources of suppressed message: " << endl;
+  }
+
+  os << "==========================================================" << endl;
+  os << " Message Source                   |   Level |    Count" << endl;
+  os << "----------------------------------+---------+-------------" << endl;
+
+  bool found(false);
+
+  std::map<std::string,msgAry>::const_iterator itr = m_sourceMap.begin();
+  std::map<std::string,msgAry>::const_iterator enditr = m_sourceMap.end();
+
+  if (total) {
+    itr = m_sourceMapTotal.begin();
+    enditr = m_sourceMapTotal.end();
+  }
+  
+  for (; itr!=enditr; ++itr) {
+    for (unsigned int ic = 0; ic < MSG::NUM_LEVELS; ++ic) {
+      if ( (m_suppress.value() && itr->second.msg[ic] >= abs(m_msgLimit[ic]) && m_msgLimit[ic] != 0 ) || 
+	   (m_stats && itr->second.msg[ic] > 0 && ic >= statLevel) ) {
+	os << " ";
+	os.width(33);
+	os.setf(ios_base::left,ios_base::adjustfield);
+	os << itr->first;
+
+	os << "|";
+
+	os.width(8);
+	os.setf(ios_base::right,ios_base::adjustfield);
+	os << levelNames[ic];
+
+	os << " |";
+
+	os.width(9);
+	os << itr->second.msg[ic];	
+
+	os << endl;
+
+	found = true;
+      }
+    }
+  }
+  os << "==========================================================" << endl;
+
+  if (found || m_stats) {
+    reportMessage(name(), MSG::INFO, os.str());
+  }
+}
+
+//#############################################################################
+std::string TrigMessageSvc::colTrans(std::string col, int offset) {
+  ColorMap::const_iterator itr = m_colMap.find(col);
+  int icol;
+  if (itr != m_colMap.end()) {
+    icol = offset + itr->second;
+  } else {
+    icol = offset + 8;
+  }
+  std::ostringstream os1;
+      
+  os1 << icol;
+
+  return os1.str();
+
+}
+
+//#############################################################################
+// ---------------------------------------------------------------------------
+// Routine: reportMessage
+// Purpose: dispatches a message to the relevant streams.
+// ---------------------------------------------------------------------------
+//
+
+void TrigMessageSvc::reportMessage( const Message& msg, int outputLevel )    {
+
+  int nmsg;
+
+  pthread_mutex_lock(&msgsvcmutex);
+  int key = msg.getType();
+  ++m_msgCount[key];
+
+  // Publish message statistics if enabled and only while RUNNING
+  if ( m_publishStats && m_running && key>=static_cast<int>(m_publishLevel) ) {
+    m_msgCountHist->Fill(key-m_publishLevel, 1);
+    { // Adding bins on the fly needs to be protected by mutex
+      scoped_lock_histogram lock;
+      m_msgCountSrcHist->Fill(key-m_publishLevel, msg.getSource().c_str(), 1);
+      m_msgCountSrcHist->LabelsDeflate("Y");
+    }
+  }
+
+  const Message *cmsg = &msg;
+
+  if ( m_doSuppress || m_stats.value() ) {
+    
+    std::map<std::string,msgAry>::iterator itr = m_sourceMap.find(msg.getSource());
+    if ( itr != m_sourceMap.end() ) {
+      nmsg = ++(itr->second.msg[key]);
+    }
+    else {
+      msgAry A;
+      for (int i=0; i<MSG::NUM_LEVELS; ++i) A.msg[i] = 0;
+      A.msg[key] = 1;
+      m_sourceMap[msg.getSource()] = A;
+      nmsg = 1;
+    }
+    
+    if (m_doSuppress) {
+      const int msgLimit = m_msgLimit[key].value();
+      
+      if ( msgLimit > 0 ) {         // regular suppression
+	if (nmsg == msgLimit) {
+          std::ostringstream os;
+          os << levelNames[key] << " message limit (" << msgLimit << ") reached for "
+             << msg.getSource() + ". Suppressing further output.";
+	  cmsg = new Message(msg.getSource(), MSG::WARNING, os.str());
+	  cmsg->setFormat(msg.getFormat());
+          cmsg->setTimeFormat(msg.getTimeFormat());
+	}
+        else if (nmsg > msgLimit) {
+          pthread_mutex_unlock(&msgsvcmutex);
+          return;
+        }
+      }
+      else if ( msgLimit < 0 ) {    // logarithmic suppression
+
+        // Use source/level/message as identifier and calculate hash
+        const unsigned int msgKey = msgHash(*cmsg);
+        MsgCountMap::iterator itr = m_msgCountMap.find(msgKey);
+        
+        // Check if we saw this message already and increase counter
+        if (itr != m_msgCountMap.end())
+          nmsg = ++itr->second;
+        else
+          nmsg = m_msgCountMap[msgKey] = 1;
+
+        if ( nmsg == abs(msgLimit) ) {
+          std::ostringstream os;
+          os << msg.getMessage() << " [Message limit (" << abs(msgLimit)
+             << ") reached. Log-suppression of further output.]";
+          cmsg = new Message(msg.getSource(), msg.getType(), os.str());
+          cmsg->setFormat(msg.getFormat());
+          cmsg->setTimeFormat(msg.getTimeFormat());
+        }
+        else if ( nmsg > abs(msgLimit) ) {          
+          const int everyNth = (int)exp10((int)log10(nmsg));
+          if ((nmsg % everyNth)==0) {
+            std::ostringstream os;
+            os << msg.getMessage() << " [suppressed " << everyNth << " similar messages]";
+            cmsg = new Message(msg.getSource(), msg.getType(), os.str());
+            cmsg->setFormat(msg.getFormat());
+            cmsg->setTimeFormat(msg.getTimeFormat());
+          }
+          else {
+            pthread_mutex_unlock(&msgsvcmutex);
+            return;
+          }
+        }
+      }
+    }
+  }   // suppression
+
+  // Optional message trailer (ignored in hash)
+  std::ostringstream msgTrailer;
+
+  // Avoid recursion in case StoreGateSvc::retrieve prints a message
+  if ( m_canEnter ) {
+    m_canEnter = false;
+    if ( m_running &&
+         key >= static_cast<int>(m_eventIDLevel.value()) &&
+         m_evtStore.retrieve().isSuccess() ) {
+      const EventInfo* pEvent(0);
+      if ( m_evtStore->retrieve(pEvent).isSuccess() ) {
+        // Add EventID
+        msgTrailer << " " << *pEvent->event_ID();
+      }
+    }
+    m_canEnter = true;
+  }
+
+  StreamMap::const_iterator first = m_streamMap.lower_bound( key );
+  if ( first != m_streamMap.end() ) {
+    StreamMap::const_iterator last = m_streamMap.upper_bound( key );
+    while( first != last ) {
+      std::ostream& stream = *( (*first).second.second );
+      stream << *cmsg << msgTrailer.str() << std::endl;
+      first++;
+    }
+  }
+  else if ( key >= outputLevel )   {
+    cmsg->setFormat(m_defaultFormat);
+    cmsg->setTimeFormat(m_defaultTimeFormat);
+    std::ostringstream out_string_stream ;
+    if (!m_color) {
+      (out_string_stream) << *cmsg << msgTrailer.str();
+    } else {
+      (out_string_stream) <<  m_logColorCodes[key] << *cmsg << msgTrailer.str() << "\033[m" ;
+    }
+
+    bool useERS = passErsFilter(cmsg->getSource(), m_useERS[key]);
+    
+    if ( m_alwaysUseMsgStream.value() || !useERS ) {
+      // output to the default stream
+      (*m_defaultStream) << out_string_stream.str() << std::endl << std::flush;
+    }
+
+    // output to ERS
+    if (useERS) {
+      
+      /*
+       * Create ERS context object
+       *
+       * The (cross-node) MRS throttling is based on filename+line_number, i.e. ignoring
+       * the message text itself. We therefor use the message source as filename and the
+       * message hash as line_number. That way the same message from different nodes
+       * gets properly throttled by MRS.
+       */
+      const char* filename = cmsg->getSource().c_str();
+      unsigned int line_number = msgHash(*cmsg);
+      const char* function_name = filename;
+      const char* package_name = "HLT";
+      ers::LocalContext hlt_context_info(package_name, filename, line_number, function_name);
+
+      /*
+       * Create ERS issue object
+       *
+       * Add the source to the ERS message text. Otherwise the source is not visible
+       * in the MRS monitor, for example.
+       * The "HLT" qualifier can be used to filter ERS messages from the log file.
+       */
+      ers::HLTMessage ersMsg(hlt_context_info, cmsg->getSource() + ": " +  cmsg->getMessage() + msgTrailer.str());
+      ersMsg.add_qualifier("HLT");   // used for filtering
+      
+      // forward Gaudi message to ERS
+      switch (key) {
+        case MSG::NIL:      ers::debug( ersMsg, 3 ); break;
+        case MSG::VERBOSE:  ers::debug( ersMsg, 2 ); break;
+        case MSG::DEBUG:    ers::debug( ersMsg, 1 ); break;
+        case MSG::INFO:     ers::info( ersMsg );     break;
+        case MSG::WARNING:  ers::warning( ersMsg );  break;
+        case MSG::ERROR:    ers::error( ersMsg );    break;
+        case MSG::FATAL:    ers::fatal( ersMsg );    break;
+        default:
+          std::ostringstream internal_msg ;
+          internal_msg << "ERROR: Unknown message severity level: " << key ;
+          ers::error( ers::HLTMessage(ERS_HERE,internal_msg.str()) );
+      }
+    }
+  }
+  
+  if (cmsg != &msg) { delete cmsg; }
+  pthread_mutex_unlock(&msgsvcmutex);
+}
+
+
+void TrigMessageSvc::reportMessage( const Message& msg )
+{
+  reportMessage(msg, outputLevel(msg.getSource()));
+}
+
+void TrigMessageSvc::reportMessage (const char* source,
+                                int type,
+                                const char* message) {
+  Message msg( source, type, message);
+  reportMessage( msg );
+}
+
+
+void TrigMessageSvc::reportMessage (const std::string& source,
+                                int type,
+                                const std::string& message) {
+  Message msg( source, type, message);
+  reportMessage( msg );
+}
+
+//#############################################################################
+// ---------------------------------------------------------------------------
+// Routine: sendMessage
+// Purpose: finds a message for a given status code and dispatches it.
+// ---------------------------------------------------------------------------
+//
+
+void TrigMessageSvc::reportMessage (const StatusCode& key,
+                                const std::string& source)
+{  
+  pthread_mutex_lock(&msgsvcmutex);
+  MessageMap::const_iterator first = m_messageMap.lower_bound( key );
+  if ( first != m_messageMap.end() ) {
+    MessageMap::const_iterator last = m_messageMap.upper_bound( key );
+    while( first != last ) {
+      Message msg = (*first).second;
+      msg.setSource( source );
+      std::ostringstream os1;
+      os1 << "Status Code " << key.getCode() << std::ends;
+      Message stat_code1( source, msg.getType(), os1.str() );
+      reportMessage( stat_code1 );
+      reportMessage( msg );
+      first++;
+    }
+  }
+  else {
+    Message mesg = m_defaultMessage;
+    mesg.setSource( source );
+      std::ostringstream os2;
+    os2 << "Status Code " << key.getCode() << std::ends;
+    Message stat_code2( source,  mesg.getType(), os2.str() );
+    reportMessage( stat_code2 );
+    reportMessage( mesg );
+  }
+  pthread_mutex_unlock(&msgsvcmutex);
+}
+
+//#############################################################################
+// ---------------------------------------------------------------------------
+// Routine: insertStream
+// Purpose: inserts a stream for a message type.
+// ---------------------------------------------------------------------------
+//
+
+void TrigMessageSvc::insertStream (int key,
+                               const std::string& name,
+                               std::ostream *stream)
+{
+  typedef StreamMap::value_type value_type;
+  pthread_mutex_lock(&msgsvcmutex);  
+  m_streamMap.insert( value_type( key, NamedStream(name,stream) ) );
+  pthread_mutex_unlock(&msgsvcmutex);
+}
+
+//#############################################################################
+// ---------------------------------------------------------------------------
+// Routine: eraseStream
+// Purpose: erases all the streams for all the message types.
+// ---------------------------------------------------------------------------
+//
+
+void TrigMessageSvc::eraseStream()
+{
+  pthread_mutex_lock(&msgsvcmutex);
+  m_streamMap.erase( m_streamMap.begin(), m_streamMap.end() );
+  pthread_mutex_unlock(&msgsvcmutex);
+}
+
+//#############################################################################
+// ---------------------------------------------------------------------------
+// Routine: eraseStream
+// Purpose: erases all the streams for a message type.
+// ---------------------------------------------------------------------------
+//
+
+void TrigMessageSvc::eraseStream( int message_type )
+{
+  pthread_mutex_lock(&msgsvcmutex);
+  m_streamMap.erase( message_type );
+  pthread_mutex_unlock(&msgsvcmutex);
+}
+
+//#############################################################################
+// ---------------------------------------------------------------------------
+// Routine: eraseStream
+// Purpose: erases one stream for a message type.
+// ---------------------------------------------------------------------------
+//
+
+void TrigMessageSvc::eraseStream( int key, std::ostream* stream )   {
+  pthread_mutex_lock(&msgsvcmutex);
+  if ( 0 != stream )    {
+    bool changed = true;
+    while( changed ) {
+      changed = false;
+      StreamMap::iterator first = m_streamMap.lower_bound( key );
+      StreamMap::iterator last = m_streamMap.upper_bound( key );
+      while( first != last ) {
+        if ( (*first).second.second == stream ) {
+          m_streamMap.erase( first );
+          changed = true;
+          break;
+        }
+      }
+    }      
+  }
+  pthread_mutex_unlock(&msgsvcmutex);
+}
+
+//#############################################################################
+// ---------------------------------------------------------------------------
+// Routine: eraseStream
+// Purpose: erases one stream for all message types.
+// ---------------------------------------------------------------------------
+//
+
+void TrigMessageSvc::eraseStream( std::ostream* stream )    {
+  pthread_mutex_lock(&msgsvcmutex);
+  if ( 0 != stream )    {
+    bool changed = true;
+    while( changed ) {
+      changed = false;
+      StreamMap::iterator first = m_streamMap.begin();
+      while( first != m_streamMap.end() ) {
+        if ( (*first).second.second == stream ) {
+          m_streamMap.erase( first );
+          changed = true;
+          break;
+        }
+      }
+    }      
+  }
+  pthread_mutex_unlock(&msgsvcmutex);
+}
+
+
+//#############################################################################
+// ---------------------------------------------------------------------------
+// Routine: insertMessage
+// Purpose: inserts a message for a status code.
+// ---------------------------------------------------------------------------
+//
+
+void TrigMessageSvc::insertMessage( const StatusCode& key, const Message& msg )
+{
+  typedef MessageMap::value_type value_type;
+  pthread_mutex_lock(&msgsvcmutex);  
+  m_messageMap.insert( value_type( key, msg ) );
+  pthread_mutex_unlock(&msgsvcmutex);
+}
+
+//#############################################################################
+// ---------------------------------------------------------------------------
+// Routine: eraseMessage
+// Purpose: erases all the messages for all the status codes.
+// ---------------------------------------------------------------------------
+//
+
+void TrigMessageSvc::eraseMessage()
+{
+  pthread_mutex_lock(&msgsvcmutex);  
+  m_messageMap.erase( m_messageMap.begin(), m_messageMap.end() );
+  pthread_mutex_unlock(&msgsvcmutex);
+}
+
+//#############################################################################
+// ---------------------------------------------------------------------------
+// Routine: eraseMessage
+// Purpose: erases all the messages for a status code.
+// ---------------------------------------------------------------------------
+//
+
+void TrigMessageSvc::eraseMessage( const StatusCode& key )
+{
+  pthread_mutex_lock(&msgsvcmutex);
+  m_messageMap.erase( key );
+  pthread_mutex_unlock(&msgsvcmutex);
+}
+
+//#############################################################################
+// ---------------------------------------------------------------------------
+// Routine: eraseMessage
+// Purpose: erases one message for a status code.
+// ---------------------------------------------------------------------------
+//
+
+void TrigMessageSvc::eraseMessage( const StatusCode& key, const Message& msg )
+{
+  pthread_mutex_lock(&msgsvcmutex);
+  bool changed = true;
+  while( changed ) {
+    changed = false;
+    MessageMap::iterator first = m_messageMap.lower_bound( key );
+    MessageMap::iterator last = m_messageMap.upper_bound( key );
+    while( first != last ) {
+      const Message& message = (*first).second;
+      if ( message == msg ) {
+        m_messageMap.erase( first );
+        changed = true;
+        break;
+      }
+    }      
+  }
+  pthread_mutex_unlock(&msgsvcmutex);
+}
+
+// ---------------------------------------------------------------------------
+StatusCode TrigMessageSvc::queryInterface(const InterfaceID& riid, void** ppvInterface) {
+// ---------------------------------------------------------------------------
+  if ( IMessageSvc::interfaceID().versionMatch(riid) )  {
+    *ppvInterface = (IMessageSvc*)this;
+  }
+  else if ( ITrigMessageSvc::interfaceID().versionMatch(riid) ) {
+    *ppvInterface = static_cast<ITrigMessageSvc*>(this);
+  }
+  else  {
+    return Service::queryInterface(riid, ppvInterface);
+  }
+  addRef();
+  return StatusCode::SUCCESS;
+}
+
+// ---------------------------------------------------------------------------
+int TrigMessageSvc::outputLevel()   const {
+// ---------------------------------------------------------------------------
+  return m_outputLevel;
+}
+// ---------------------------------------------------------------------------
+int TrigMessageSvc::outputLevel( const std::string& source )   const {
+// ---------------------------------------------------------------------------
+  ThresholdMap::const_iterator it;
+
+  pthread_mutex_lock(&msgsvcmutex);
+  it = m_thresholdMap.find( source );
+  int level;
+
+  if( it != m_thresholdMap.end() ) {
+    level = (*it).second;
+  }
+  else {
+    level = m_outputLevel;
+  }
+  pthread_mutex_unlock(&msgsvcmutex);
+  return level;
+}
+
+// ---------------------------------------------------------------------------
+void TrigMessageSvc::setOutputLevel(int new_level)    {
+// ---------------------------------------------------------------------------
+  pthread_mutex_lock(&msgsvcmutex);  
+  m_outputLevel = new_level;
+  pthread_mutex_unlock(&msgsvcmutex);
+}
+
+// ---------------------------------------------------------------------------
+void TrigMessageSvc::setOutputLevel(const std::string& source, int level)    {
+// ---------------------------------------------------------------------------
+  // Ignore in case we enforce the global OutputLevel
+  if (m_forceOutputLevel.value()) return;
+  
+  pthread_mutex_lock(&msgsvcmutex);
+  std::pair<ThresholdMap::iterator, bool> p;
+  p = m_thresholdMap.insert(ThresholdMap::value_type( source, level) );
+  if( p.second == false ) {
+    // Already existing an output level for that source. Erase and enter it again
+    m_thresholdMap.erase ( p.first );
+    m_thresholdMap.insert(ThresholdMap::value_type( source, level) );
+  }
+  pthread_mutex_unlock(&msgsvcmutex);
+}
+
+
+// ---------------------------------------------------------------------------
+void TrigMessageSvc::setOutputLevelViaJobOptSvc() {
+// ---------------------------------------------------------------------------
+  ServiceHandle<IJobOptionsSvc> jobOptSvc("JobOptionsSvc", name());    
+  if ( jobOptSvc.retrieve()==StatusCode::FAILURE ) {
+    reportMessage(name(), MSG::ERROR, "Cannot retrieve JobOptionsSvc");
+    return;
+  }
+
+  std::vector<std::string> clients = jobOptSvc->getClients();
+  std::vector<std::string>::iterator cl;
+  std::vector<const Property*>::const_iterator pr;
+  
+  // Loop over all clients/properties and set OutputLevel accordingly
+  for (cl=clients.begin(); cl!=clients.end(); ++cl) {
+    const std::vector<const Property*> *props = jobOptSvc->getProperties(*cl);
+    for (pr=props->begin(); pr!=props->end(); ++pr) {
+      if ( (*pr)->name()=="OutputLevel" ) {        
+        if ( jobOptSvc->addPropertyToCatalogue(*cl, m_outputLevel).isSuccess() ){
+          std::ostringstream msg;
+          msg << "Setting " << (*pr)->name() << ".OutputLevel = " << m_outputLevel.value();
+          reportMessage(name(), MSG::DEBUG, msg.str());
+        }
+        else {
+          std::ostringstream msg;
+          msg << "Cannot set " << (*pr)->name() << ".OutputLevel";
+          reportMessage(name(), MSG::WARNING, msg.str());
+        }
+      }
+    }
+  }
+}
+                                                               
+// ---------------------------------------------------------------------------
+void TrigMessageSvc::resetOutputLevels()    {
+// ---------------------------------------------------------------------------
+  m_thresholdMap.clear();  
+}
+
+// ---------------------------------------------------------------------------
+std::string TrigMessageSvc::getLogColor(int logLevel) const   {
+// ---------------------------------------------------------------------------
+  if (logLevel < MSG::NUM_LEVELS) {
+    return m_logColorCodes[logLevel];
+  } else {
+    return "";
+  }
+}
+
+// ---------------------------------------------------------------------------
+int TrigMessageSvc::messageCount( MSG::Level level) const   {
+  return m_msgCount[level];
+}
+// ---------------------------------------------------------------------------
+
+
+// ---------------------------------------------------------------------------
+// Calculate message hash (ignoring any numbers)
+// ---------------------------------------------------------------------------
+unsigned int TrigMessageSvc::msgHash(const Message& msg)
+{
+  // Message type is lowest decimal
+  unsigned int hash = msg.getType();
+  
+  // Add all characters of source
+  const std::string& src = msg.getSource();
+  for (size_t i=0; i<src.length(); ++i) {
+    hash += 10*(int)src[i];
+  }
+
+  // Add all letters of message
+  const std::string& str = msg.getMessage();
+  for (size_t i=0; i<str.length(); ++i) {
+    const char& ch = str[i];
+    if (ch<',' || ch>'9') hash += 10*(int)ch;
+  }
+     
+  return hash;
+}
diff --git a/HLT/Trigger/TrigControl/TrigServices/src/TrigMonTHistSvc.cxx b/HLT/Trigger/TrigControl/TrigServices/src/TrigMonTHistSvc.cxx
new file mode 100644
index 00000000000..fde05437715
--- /dev/null
+++ b/HLT/Trigger/TrigControl/TrigServices/src/TrigMonTHistSvc.cxx
@@ -0,0 +1,403 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+
+#include "GaudiKernel/SvcFactory.h"
+#include "GaudiKernel/ISvcLocator.h"
+#include "GaudiKernel/ThreadGaudi.h"
+
+#include "AthenaKernel/errorcheck.h"
+#include "TrigMonTHistSvc.h"
+#include "TrigMonitorBase/TrigLockedHist.h"
+
+#include "hltinterface/IInfoRegister.h"
+
+#include "TROOT.h"
+#include "TError.h"
+#include "TObject.h"
+#include "TH1.h"
+#include "TH2.h"
+#include "TH3.h"
+#include "TGraph.h"
+#include "TTree.h"
+
+#include <iostream>
+#include <sstream>
+#include <streambuf>
+#include <sstream>
+#include <map>
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
+TrigMonTHistSvc::TrigMonTHistSvc( const std::string& name, ISvcLocator* svc ) 
+    : THistSvcHLT(name, svc),
+      AthMessaging(msgSvc(), name),
+      m_add(true),      
+      m_excludeType("()"), 
+      m_includeType(".+"),
+      m_excludeName(".*\\..*"),                                            
+      m_includeName("^/((run_[0-9]+/lb_[0-9]+/LB)|(SHIFT)|(EXPERT)|(DEBUG)|(EXPRESS)|(RUNSTAT))/.+/.+") {
+      //m_includeName("^/((SHIFT)|(EXPERT)|(DEBUG)|(RUNSTAT))/.+/.+") {     
+  declareProperty("SumUpHistograms", m_add, "In multi-threaded application decides to publish separate histograms for each thread or sum them up before publishing.");
+  declareProperty("ExcludeType", m_excludeType);   
+  declareProperty("IncludeType", m_includeType);
+  declareProperty("ExcludeName", m_excludeName);
+  declareProperty("IncludeName", m_includeName);
+}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+TrigMonTHistSvc::~TrigMonTHistSvc() {
+
+}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+StatusCode TrigMonTHistSvc::queryInterface(const InterfaceID & riid,
+                                           void **ppvInterface) {
+  return THistSvcHLT::queryInterface(riid, ppvInterface);
+}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+StatusCode TrigMonTHistSvc::initialize() {
+
+  CHECK(THistSvcHLT::initialize());
+  CHECK(setProperties());
+
+  AthMessaging::msg().setLevel(outputLevel());
+  // fix summing up flag if not running in separate threads
+  if ( ! isGaudiThreaded(name()) )
+    m_add = true;
+ 
+  // Protect against multiple instances of TROOT
+  if ( 0 == gROOT )   {
+    static TROOT root("root","ROOT I/O");  
+    
+  } else {
+    ATH_MSG_VERBOSE("ROOT already initialized, debug = " << gDebug);
+  }
+  gErrorIgnoreLevel=kBreak; // ignore warnings see TError.h in ROOT base src
+
+  // compile regexes
+  m_excludeTypeRegex = boost::regex(m_excludeType);
+  m_includeTypeRegex = boost::regex(m_includeType);
+  m_excludeNameRegex = boost::regex(m_excludeName);
+  m_includeNameRegex = boost::regex(m_includeName);
+  
+  // Retrieve and set OH mutex
+  ATH_MSG_INFO("Enabling use of OH histogram mutex");
+  lock_histogram_mutex::set_histogram_mutex(
+      hltinterface::IInfoRegister::instance()->getPublicationMutex());
+  
+  return StatusCode::SUCCESS;
+}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+StatusCode TrigMonTHistSvc::reinitialize() {
+    
+    return StatusCode::SUCCESS;
+}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+StatusCode TrigMonTHistSvc::finalize() {
+    
+  // Reset OH mutex
+  ATH_MSG_DEBUG("Resetting OH histogram mutex");
+  lock_histogram_mutex::reset_histogram_mutex();
+        
+  std::stringstream f;
+  hltinterface::IInfoRegister::THList thlist;
+  hltinterface::IInfoRegister::instance()->get(".*", thlist); 
+  hltinterface::IInfoRegister::THList::iterator lIter;
+  // just listing
+  for ( lIter = thlist.begin() ; lIter != thlist.end(); ++lIter ){
+    ATH_MSG_INFO("Histogram " <<  lIter->first << " ");    
+  }
+  return StatusCode::SUCCESS;
+}
+
+
+StatusCode TrigMonTHistSvc::regHist(const std::string& id) {  
+  ATH_MSG_DEBUG("registering histogram: " << id <<  " to get it");
+  return THistSvcHLT::regHist(id);
+}
+
+StatusCode TrigMonTHistSvc::regHist(const std::string& id, TH1* hist) {
+    return regHist_i(hist, id);
+}
+
+StatusCode TrigMonTHistSvc::regHist(const std::string& id, TH2* hist) {
+    return regHist_i(hist, id);
+}
+
+StatusCode TrigMonTHistSvc::regHist(const std::string& id, TH3* hist) {
+    return regHist_i(hist, id);
+}
+
+StatusCode TrigMonTHistSvc::regTree(const std::string& id) {
+  return THistSvcHLT::regTree(id);
+}
+
+StatusCode TrigMonTHistSvc::regTree(const std::string&, TTree* hist) {
+    // we do not support the trees; then let's make them not to be memory consumers
+  ATH_MSG_WARNING("The ROOT TTree is not supported by this service" 
+                  << " TTree \"" << hist->GetName() << "\" will be unsaved but will not consume all memory as well" 
+                  );
+  hist->SetCircular(1);
+  return StatusCode::SUCCESS;
+}
+
+StatusCode TrigMonTHistSvc::getHist(const std::string& id, TH1*& hist) const {
+  return THistSvcHLT::getHist(id, hist);  
+}
+
+
+StatusCode TrigMonTHistSvc::getHist(const std::string& id, TH2*& hist) const {
+  return THistSvcHLT::getHist(id, hist);  
+}
+
+
+StatusCode TrigMonTHistSvc::getHist(const std::string& id, TH3*& hist) const {
+  return THistSvcHLT::getHist(id, hist);
+}
+
+StatusCode TrigMonTHistSvc::getTree(const std::string& id, TTree*& hist) const {
+  return THistSvcHLT::getTree(id, hist);
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+//  Needs proper implementation
+//
+StatusCode TrigMonTHistSvc::regGraph(const std::string& id) {
+  return THistSvcHLT::regGraph(id);
+}
+
+StatusCode TrigMonTHistSvc::regGraph(const std::string&, TGraph*) {
+  ATH_MSG_WARNING("The regGraph is not suported by this service");
+  return StatusCode::SUCCESS; 
+}
+
+StatusCode TrigMonTHistSvc::getGraph(const std::string& id, TGraph*& g) const {
+  return THistSvcHLT::getGraph(id, g); 
+}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+template <typename T> StatusCode TrigMonTHistSvc::regHist_i(T* hist, const std::string& id) {
+
+    std::string regid;
+    if ( isObjectAllowed(id, hist).isFailure() ) {
+	return  StatusCode::FAILURE;
+    }
+    // prepend by  service name if the histograms are not going to be added
+    // this way they are registered under different unique names
+    // from each service
+    if ( m_add )
+	regid = id;
+    else {
+	std::string n = getGaudiThreadIDfromName(name());
+
+	// strip blanks at the end of service name
+	std::string::size_type pos;
+	while ( (pos = n.find('\0', 0)) != std::string::npos) 
+	    n.erase(pos,1);
+	// build the name used for registration
+	regid = id+n;
+    }
+
+    if (hist->Class()->InheritsFrom(TH1::Class())) {
+        hltinterface::IInfoRegister::instance()->registerTObject(name(), regid, hist);
+        ATH_MSG_DEBUG("Histogram " << hist->GetName() 
+                      << " registered under " << regid << " " << m_add << " " << name());
+    } else {
+      ATH_MSG_ERROR("Trying to register " << hist->ClassName() 
+                    << " but this does not inherit from TH1 histogram");
+      return StatusCode::SUCCESS; 
+    }
+    return StatusCode::SUCCESS; 
+}
+
+StatusCode TrigMonTHistSvc::deReg(TObject* optr) {
+
+  std::map<std::string, std::vector<TObject*> > allObjs;
+  std::map<std::string, std::vector<TObject*> >::const_iterator mapIt;
+  hltinterface::IInfoRegister::instance()->getUnsummed(".+", allObjs); 
+  
+  // we need now to loop over all this histograms and find if the 
+  for ( mapIt = allObjs.begin(); mapIt != allObjs.end(); ++mapIt ) {
+    for (std::vector<TObject*>::const_iterator tIt = mapIt->second.begin(); tIt != mapIt->second.end(); ++tIt ) { 
+      if ( optr == *tIt ) {
+        ATH_MSG_DEBUG("Found histogram by pointer " << optr << " booked under " 
+                      << mapIt->first << " will deregister it");
+	return deReg(mapIt->first);
+      }  
+    }
+  }    
+  return StatusCode::FAILURE;  
+}
+
+StatusCode TrigMonTHistSvc::deReg(const std::string& id ) {
+
+  hltinterface::IInfoRegister::instance()->releaseTObject(name(), id);
+  ATH_MSG_DEBUG("Deregistration of " << id << " done");
+  return StatusCode::SUCCESS;
+}
+
+std::vector<std::string> TrigMonTHistSvc::getHists() const {
+  std::vector<std::string> l = THistSvcHLT::getHists();   // we need to update the list by objects holded by offline SVC
+                 
+  hltinterface::IInfoRegister::THList thlist;
+  hltinterface::IInfoRegister::instance()->get(".+", thlist); 
+  hltinterface::IInfoRegister::THList::iterator lIter;
+
+  l.reserve(l.size()+thlist.size());
+  for ( lIter = thlist.begin() ; lIter != thlist.end(); ++lIter ){
+    l.push_back(lIter->first);                     // by ones from online
+  }
+  return l;
+}
+
+
+std::vector<std::string> TrigMonTHistSvc::getTrees() const {
+
+  // we do not keep TTrees
+  ATH_MSG_DEBUG("TTres not suported by this implementation");
+  std::vector<std::string> l;
+  return l;
+}
+
+
+StatusCode TrigMonTHistSvc::getTHists(TDirectory *td, TList &tl) const {
+  return getTHists_i(std::string(td->GetPath()), tl);
+}
+
+StatusCode TrigMonTHistSvc::getTHists(const std::string& dir, TList &tl) const {
+  return getTHists_i(dir, tl);
+}
+
+
+StatusCode TrigMonTHistSvc::getTTrees(TDirectory *, TList &) const {
+  // we do not have TTrees
+  ATH_MSG_DEBUG("TTres not suported by this implementation");
+  return StatusCode::SUCCESS;
+}
+
+StatusCode TrigMonTHistSvc::getTTrees(const std::string&, TList &) const {
+  // we do not have TTrees
+  ATH_MSG_DEBUG("TTres not suported by this implementation");
+  return StatusCode::SUCCESS;
+}
+
+
+//
+//==========================================================================
+//  internal methods 
+//==========================================================================
+//
+StatusCode  TrigMonTHistSvc::isObjectAllowed(std::string path, const TObject *o) {
+
+    boost::cmatch what;
+
+    if ( ! boost::regex_match(o->ClassName(),
+			      what, m_includeTypeRegex) ) {
+      ATH_MSG_WARNING("Object " << path 
+                      << " of type " << o->ClassName()
+                      << " does NOT match IncludeTypeRegex \"" 
+                      << m_includeType << "\"");
+      return StatusCode::FAILURE;
+    }
+      
+    if ( boost::regex_match(o->ClassName(),
+			    what, m_excludeTypeRegex) ) {
+      ATH_MSG_WARNING("Object " << path 
+                      << " of type " << o->ClassName()
+                      << " matches ExcludeTypeRegex \"" 
+                      << m_excludeType << "\"");
+      return StatusCode::FAILURE;
+    }
+
+    if ( ! boost::regex_match(path.c_str(), what, m_includeNameRegex) ) {
+      ATH_MSG_WARNING("Object " << path 
+                      << " does NOT match IncludeNameRegex \"" 
+                      << m_includeName << "\"");
+      return StatusCode::FAILURE;
+    }
+
+    if ( boost::regex_match(path.c_str(), what, m_excludeNameRegex) ) {
+      ATH_MSG_WARNING("Object " << path 
+                      << " matches ExcludeNameRegex \"" 
+                      << m_excludeName << "\"");
+      return StatusCode::FAILURE;
+    }
+    // temp hack
+    return StatusCode::SUCCESS;
+
+}
+
+StatusCode TrigMonTHistSvc::getTHists_i(const std::string& dir, TList &tl) const {
+    hltinterface::IInfoRegister::THList thlist;
+    hltinterface::IInfoRegister::instance()->get(".+", thlist); 
+    hltinterface::IInfoRegister::THList::iterator lIter;
+
+    std::vector<std::string> l; 
+    for ( lIter = thlist.begin() ; lIter != thlist.end(); ++lIter ){
+	if ( lIter->first.find(dir) == 0 ) {
+	    // histogram booking path starts from the dir 
+	    tl.Add(lIter->second);
+	}
+    }
+    return StatusCode::SUCCESS;
+}
+
+//
+//==========================================================================
+//  Declarations to avoid compiler warning about hidden methods 
+//==========================================================================
+//
+
+StatusCode TrigMonTHistSvc::getTHists(TDirectory *td, TList &tl, bool recurse) const {
+  if (recurse != false)
+    ATH_MSG_DEBUG("Recursive flag is not supported in this implementation");
+  return getTHists_i(std::string(td->GetPath()), tl);
+}
+
+StatusCode TrigMonTHistSvc::getTHists(const std::string& dir, TList &tl, bool recurse) const {
+  if (recurse != false)
+      ATH_MSG_DEBUG("Recursive flag is not supported in this implementation");
+  return getTHists_i(dir, tl);
+}
+
+StatusCode TrigMonTHistSvc::getTHists(TDirectory *td, TList &tl, bool recurse, bool reg) {
+  if ((recurse != false) || (reg != false))
+    ATH_MSG_DEBUG("Recursive flag and automatic registration flag is not supported in this implementation");
+  return getTHists_i(std::string(td->GetPath()), tl);
+}
+
+StatusCode TrigMonTHistSvc::getTHists(const std::string& dir, TList &tl, bool recurse, bool reg) {
+  if ((recurse != false) || (reg != false))
+    ATH_MSG_DEBUG("Recursive flag and automatic registration flag is not supported in this implementation");
+  return getTHists_i(dir, tl);
+}
+
+StatusCode TrigMonTHistSvc::getTTrees(TDirectory *, TList &, bool) const {
+  // we do not have TTrees
+  ATH_MSG_DEBUG("TTres not suported by this implementation");
+  return StatusCode::SUCCESS;
+}
+StatusCode TrigMonTHistSvc::getTTrees(const std::string&, TList &, bool) const {
+  // we do not have TTrees
+  ATH_MSG_DEBUG("TTres not suported by this implementation");
+  return StatusCode::SUCCESS;
+}
+StatusCode TrigMonTHistSvc::getTTrees(TDirectory *, TList &, bool, bool) {
+  // we do not have TTrees
+  ATH_MSG_DEBUG("TTres not suported by this implementation");
+  return StatusCode::SUCCESS;
+}
+StatusCode TrigMonTHistSvc::getTTrees(const std::string&, TList &, bool, bool) {
+  // we do not have TTrees
+  ATH_MSG_DEBUG("TTres not suported by this implementation");
+  return StatusCode::SUCCESS;
+}
+
+bool TrigMonTHistSvc::exists( const std::string& name ) const {
+  return THistSvcHLT::exists(name);
+}
diff --git a/HLT/Trigger/TrigControl/TrigServices/src/TrigMonTHistSvc.h b/HLT/Trigger/TrigControl/TrigServices/src/TrigMonTHistSvc.h
new file mode 100644
index 00000000000..44747c4fca6
--- /dev/null
+++ b/HLT/Trigger/TrigControl/TrigServices/src/TrigMonTHistSvc.h
@@ -0,0 +1,134 @@
+// -*- c++ -*-
+
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef TRIGMONTHISTSVC_THISTSVC_H
+#define TRIGMONTHISTSVC_THISTSVC_H
+
+
+/**
+ * @file TrigMonTHistSvc.h
+ * @author Tomasz Bold
+ * @date 2005-09-27
+ * @brief The HLT histogramming service 
+ * It forwards histograms to the monitoring infrastructure.
+ */
+
+
+#include "GaudiKernel/Service.h"
+#include "THistSvcHLT.h"
+#include "AthenaBaseComps/AthMessaging.h"
+
+class TObject;
+class TH1;
+class TH2;
+class TH3;
+class TGraph;
+class TTree;
+
+#include <vector>
+#include <string>
+
+#include <boost/regex.hpp>
+
+// Forward declarations
+template <class TYPE> class SvcFactory;
+
+class TrigMonTHistSvc: virtual public THistSvcHLT,
+                       public AthMessaging
+{ 
+public:
+  
+  // fwd compat w/ gaudi-21
+  using AthMessaging::msg;
+
+  // implemenataion of the interface from TrigNetTHistSvc
+  virtual StatusCode initialize();
+  virtual StatusCode reinitialize();
+  virtual StatusCode finalize();
+  
+  // Query the interfaces.
+  virtual StatusCode queryInterface( const InterfaceID& riid, 
+  				     void** ppvInterface );
+  
+
+  virtual StatusCode regHist(const std::string& name);
+  virtual StatusCode regHist(const std::string& name, TH1*);
+  virtual StatusCode regHist(const std::string& name, TH2*);
+  virtual StatusCode regHist(const std::string& name, TH3*);
+  
+  virtual StatusCode getHist(const std::string& name, TH1*&) const;
+  virtual StatusCode getHist(const std::string& name, TH2*&) const;
+  virtual StatusCode getHist(const std::string& name, TH3*&) const;
+
+  virtual StatusCode regTree(const std::string& name);
+  virtual StatusCode regTree(const std::string& name, TTree*);
+  virtual StatusCode getTree(const std::string& name, TTree*&) const;
+
+  // new since Gaudi 0.16.1.11
+  virtual StatusCode deReg(TObject* obj);            //<! very slow
+  virtual StatusCode deReg(const std::string& name); //<! use this instead
+
+  virtual std::vector<std::string> getHists() const;
+  virtual std::vector<std::string> getTrees() const;
+
+  virtual StatusCode getTHists(TDirectory *td, TList &) const;
+  virtual StatusCode getTHists(const std::string& name, TList &) const;
+
+  virtual StatusCode getTTrees(TDirectory *td, TList &) const;
+  virtual StatusCode getTTrees(const std::string& name, TList &) const;
+
+  // new since Gaudi 19
+  virtual StatusCode regGraph(const std::string& name);
+  virtual StatusCode regGraph(const std::string& name, TGraph*);
+  virtual StatusCode getGraph(const std::string& name, TGraph*&) const;
+
+  TrigMonTHistSvc(const std::string& name, ISvcLocator *svc );
+
+  // new since Gaudi 20
+
+  virtual StatusCode getTHists(TDirectory *td, TList &,
+                               bool recurse=false) const;
+  virtual StatusCode getTHists(const std::string& name, TList &,
+                               bool recurse=false) const;
+  virtual StatusCode getTHists(TDirectory *td, TList &tl,
+                               bool recurse=false, bool reg=false);
+  virtual StatusCode getTHists(const std::string& name, TList &tl,
+                               bool recurse=false, bool reg=false);
+
+  virtual StatusCode getTTrees(TDirectory *td, TList &,
+                               bool recurse=false) const;
+  virtual StatusCode getTTrees(const std::string& name, TList &,
+                               bool recurse=false) const;
+  virtual StatusCode getTTrees(TDirectory *td, TList & tl,
+                               bool recurse=false, bool reg=false);
+  virtual StatusCode getTTrees(const std::string& name, TList & tl,
+                               bool recurse=false, bool reg=false);
+
+  virtual bool exists(const std::string& name) const;
+
+protected:
+  StatusCode  isObjectAllowed(std::string path, const TObject *o);
+
+  StatusCode getTHists_i(const std::string& name, TList &) const;
+  
+  virtual ~TrigMonTHistSvc();
+
+private:
+  template <typename T>
+  StatusCode regHist_i(T* hist, const std::string& name);
+  bool m_add;
+  std::string m_excludeType;
+  std::string m_includeType;
+  std::string m_excludeName;
+  std::string m_includeName;
+  // compiled regexes
+  boost::regex m_excludeTypeRegex;
+  boost::regex m_includeTypeRegex;
+  boost::regex m_excludeNameRegex;
+  boost::regex m_includeNameRegex;
+};
+
+#endif // TRIGMONTHISTSVC_THISTSVC_H
diff --git a/HLT/Trigger/TrigControl/TrigServices/src/TrigPreFlightCheck.cxx b/HLT/Trigger/TrigControl/TrigServices/src/TrigPreFlightCheck.cxx
new file mode 100644
index 00000000000..99ed9f88f50
--- /dev/null
+++ b/HLT/Trigger/TrigControl/TrigServices/src/TrigPreFlightCheck.cxx
@@ -0,0 +1,87 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+/**
+ * @file   TrigPreFlightCheck.cxx
+ * @brief  Does some generic checks to make sure we can run the HLT
+ * @author Frank Winklmeier
+ *
+ * $Id: TrigPreFlightCheck.cxx 5 2013-05-14 10:33:04Z ricab $
+ */
+
+#include "TrigPreFlightCheck.h"
+
+#include <boost/tokenizer.hpp>
+#include <boost/filesystem.hpp>
+
+#include <stdlib.h>
+
+using namespace std;
+namespace fs = boost::filesystem;
+
+//=========================================================================
+// Standard methods
+//=========================================================================
+TrigPreFlightCheck::TrigPreFlightCheck(const std::string &type,
+                           const std::string &name,
+                           const IInterface *parent)
+  : AthAlgTool(type, name, parent)
+{
+  // No abstract interface
+  declareInterface<TrigPreFlightCheck>(this);
+
+  declareProperty("ReleaseDirs",
+                  m_releaseDirs,
+                  "Directories within LD_LIBRARY_PATH to check for existence");  
+}
+
+
+TrigPreFlightCheck::~TrigPreFlightCheck()
+{}
+
+
+StatusCode TrigPreFlightCheck::initialize()
+{
+  return StatusCode::SUCCESS;
+}
+
+StatusCode TrigPreFlightCheck::check(const MSG::Level& errLvl)
+{
+  // Only one check so far
+  return checkRelease(errLvl);
+}
+
+
+StatusCode TrigPreFlightCheck::checkRelease(const MSG::Level& errLvl)
+{
+  const char* ld_lib_path = getenv("LD_LIBRARY_PATH");
+  if ( ld_lib_path==0 ) {
+    msg() << errLvl << "Cannot read LD_LIBRARY_PATH" << endreq;
+    return StatusCode::FAILURE;
+  }
+  
+  typedef boost::tokenizer<boost::char_separator<char> > Tokenizer;
+  string s(ld_lib_path);
+  Tokenizer tok(s, boost::char_separator<char>(":"));
+
+  // Loop over elements of LD_LIBRARY_PATH
+  for (Tokenizer::iterator it = tok.begin(); it!=tok.end(); ++it) {
+    
+    // Loop over directories to check
+    for (vector<string>::const_iterator dir = m_releaseDirs.begin();
+         dir != m_releaseDirs.end(); ++dir) {
+      
+      if ( it->find(*dir)!=string::npos ) {
+        if ( fs::exists(*it) ) {
+          msg() << MSG::DEBUG << "Checking " << (*it) << ": OK" << endreq;
+        }
+        else {
+          msg() << errLvl << (*it) << " does not exist" << endreq;
+          return StatusCode::FAILURE;
+        }
+      }
+    }
+  }
+  return StatusCode::SUCCESS;
+}
diff --git a/HLT/Trigger/TrigControl/TrigServices/src/TrigPreFlightCheck.h b/HLT/Trigger/TrigControl/TrigServices/src/TrigPreFlightCheck.h
new file mode 100644
index 00000000000..21e5f8c893b
--- /dev/null
+++ b/HLT/Trigger/TrigControl/TrigServices/src/TrigPreFlightCheck.h
@@ -0,0 +1,70 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef TRIGSERVICES_TRIGPREFLIGHTCHECK_H
+#define TRIGSERVICES_TRIGPREFLIGHTCHECK_H
+/**
+ * @file   TrigPreFlightCheck.h
+ * @brief  Does some generic checks to make sure we can run the HLT
+ * @author Frank Winklmeier
+ *
+ * $Id: TrigPreFlightCheck.h 5 2013-05-14 10:33:04Z ricab $
+ */
+
+// STL includes
+#include <string>
+#include <vector>
+
+// Framework includes
+#include "AthenaBaseComps/AthAlgTool.h"
+#include "GaudiKernel/StatusCode.h"
+
+/**
+ * @brief Tool to do some basic checks ensuring the HLT is usable
+ *
+ * The tool has several checkXYZ() methods each returning a StatusCode for
+ * the specific check it is doing. In addition, the check() method performs
+ * all the checks and returns the logical AND of the individual checks.
+ */
+class TrigPreFlightCheck : public AthAlgTool {
+
+public:
+
+  TrigPreFlightCheck(const std::string &type, const std::string &name, const IInterface *parent);    
+  virtual ~TrigPreFlightCheck();
+
+  static const InterfaceID& interfaceID();  
+  virtual StatusCode initialize();
+  
+  /**
+   * @brief Check whether the relase is installed properly
+   *
+   * @param  errLvl   Message level used for failure messages
+   * @return SUCCESS  Release properly installed
+   *         FAILURE  Some parts of the release is missing
+   */
+  StatusCode checkRelease(const MSG::Level& errLvl);
+
+  /**
+   * @brief Perform all checks
+   *
+   * @param  errLvl   Message level used for failure messages
+   * @return SUCCESS  All checks OK
+   *         FAILURE  At least one check failed
+   */
+  StatusCode check(const MSG::Level& errLvl);
+
+private:
+  /** Directories to check for existence in checkRelease() */
+  std::vector<std::string> m_releaseDirs;
+};
+
+
+inline const InterfaceID& TrigPreFlightCheck::interfaceID()
+{
+  static const InterfaceID _IID("TrigPreFlightCheck", 1, 0);
+  return _IID;
+}
+
+#endif
diff --git a/HLT/Trigger/TrigControl/TrigServices/src/TrigSORFromPtreeHelper.cxx b/HLT/Trigger/TrigControl/TrigServices/src/TrigSORFromPtreeHelper.cxx
new file mode 100644
index 00000000000..ae00dfb92fe
--- /dev/null
+++ b/HLT/Trigger/TrigControl/TrigServices/src/TrigSORFromPtreeHelper.cxx
@@ -0,0 +1,253 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+/**
+ * @file TrigSORFromPtreeHelper.cxx
+ * @author Ricardo Abreu
+ *
+ * @brief Helper class to retrieve the Start Of Run parameters from the
+ * prepareForRun ptree and put them into the detector store with whole-run
+ * validity. This class replaces it's old analogous TrigSORFromISHelper.
+ */
+
+#include "TrigSORFromPtreeHelper.h"
+#include "AthenaKernel/IIOVDbSvc.h"
+#include "AthenaKernel/IAddressProvider.h"
+#include "owl/time.h"
+#include <eformat/DetectorMask.h>
+
+#define ST_WHERE CLNAME << "::" << __func__ << "(): "
+
+using namespace boost::property_tree;
+using std::string;
+using SORHelper = TrigSORFromPtreeHelper;
+
+namespace
+{
+  //////////////////////////////////////////////////////////////////////////////
+  const string CLNAME{"TrigSORFromPtreeHelper"};
+  const string SORPATH{"/TDAQ/RunCtrl/SOR_Params"};
+
+  //////////////////////////////////////////////////////////////////////////////
+  void printSOR(MsgStream& log, const SORHelper::SOR * sor)
+  {
+    log << MSG::DEBUG << ST_WHERE
+        << "Dump SOR CondAttrListCollection: size=" << sor->size() << endreq;
+    sor->dump();
+  }
+
+  //////////////////////////////////////////////////////////////////////////////
+  void setSpec(coral::AttributeListSpecification * attrSpec)
+  {
+    attrSpec->extend("RunNumber", "unsigned int");
+    attrSpec->extend("SORTime", "unsigned long long");
+    attrSpec->extend("RunType", "string");
+    attrSpec->extend("DetectorMaskFst", "unsigned long long");
+    attrSpec->extend("DetectorMaskSnd", "unsigned long long");
+    attrSpec->extend("RecordingEnabled", "bool");
+  }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+const SORHelper::SOR * SORHelper::fillSOR(const ptree & rparams) const
+{
+  m_log << MSG::DEBUG << ST_WHERE << "Setup SOR in DetectorStore" << endreq;
+  SG dstore("DetectorStore", CLNAME);
+  if((dstore.retrieve()).isFailure())
+    m_log << MSG::ERROR << ST_WHERE << "could not find DetectorStore" << endreq;
+
+  // get handle to the IOVDbSvc
+  ServiceHandle<IIOVDbSvc> iovdbsvc("IOVDbSvc", CLNAME);
+  if ((iovdbsvc.retrieve()).isFailure()) {
+    m_log << MSG::ERROR << ST_WHERE 
+          << "could not find IOVDbSvc. Time dependent conditions data may be not properly handled." << endreq;
+  } else {
+    IOVTime currentIOVTime(rparams.get<unsigned int>("run_number"), 
+			   IOVTime::MINEVENT,
+			   OWLTime{(rparams.get_child("timeSOR").data()).c_str()}.total_mksec_utc() * 1000);
+
+    // Signal BeginRun directly to IOVDbSvc to set complete IOV start time
+    if (StatusCode::SUCCESS != iovdbsvc->signalBeginRun(currentIOVTime)) {
+      m_log << MSG::ERROR << ST_WHERE 
+            << "Unable to signal begin run IOVTime to IOVDbSvc. IOVTime = " << currentIOVTime << endreq;
+    } else {
+      m_log << MSG::DEBUG << ST_WHERE 
+            << "Set start of run time to IOVTime = " << currentIOVTime << endreq;
+    }
+  }
+
+  auto sor = getSOR(dstore);
+  if(!sor || fillSor(rparams, sor).isFailure() ||
+      updateProxy(dstore, sor).isFailure())
+  {
+    m_log << MSG::ERROR << ST_WHERE << "could not properly setup SOR" << endreq;
+    return nullptr;
+  }
+
+  m_log << MSG::DEBUG << ST_WHERE << "successfully setup SOR" << endreq;
+  printSOR(m_log, sor);
+
+  return sor;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+SORHelper::SOR * SORHelper::getSOR(const SG & dstore) const
+{
+  auto sc = StatusCode{};
+  auto sor = new SOR(true);
+  if(dstore->transientContains<SOR>(SORPATH))
+  {
+    const SOR * oldsor = dstore->retrieve<const SOR>(SORPATH);
+    m_log << MSG::INFO << ST_WHERE
+          << "overwriting SOR contents (a dump of the old one follows)"<<endreq;
+    printSOR(m_log, oldsor);
+    sc = dstore->overwrite(sor, SORPATH, true);
+  }
+  else
+  {
+    m_log << MSG::INFO << ST_WHERE << "recording new SOR" << endreq;
+    sc = dstore->record(sor, SORPATH, true);
+  }
+
+  if(sc.isFailure())
+  {
+    m_log << MSG::ERROR << ST_WHERE
+          << "could not record SOR in DetectorStore\n" << dstore->dump()
+          << endreq;
+    delete sor;
+    sor = nullptr;
+  }
+
+  return sor;
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+coral::AttributeList SORHelper::getAttrList(const ptree& rparams) const
+{
+  // First create attribute specification
+  // ugly new needed:
+  // dtor is protected, have to use ptr and release it explicitly... go figure
+  auto attrSpec = new coral::AttributeListSpecification{};
+  setSpec(attrSpec);
+
+  // now create the attribute list and fill it in
+  coral::AttributeList attrList(*attrSpec);
+
+  attrList["RunNumber"].data<unsigned int>() =
+      rparams.get<unsigned int>("run_number");
+  attrList["RunType"].data<string>() =
+      rparams.get<string>("run_type");
+  attrList["RecordingEnabled"].data<bool>() =
+      rparams.get<bool>("recording_enabled");
+
+  const auto& t = rparams.get_child("timeSOR").data();
+  attrList["SORTime"].data<unsigned long long>() =
+      OWLTime{t.c_str()}.total_mksec_utc() * 1000;
+
+  auto dm = getDetMask(rparams);
+  attrList["DetectorMaskFst"].data<unsigned long long>() = dm.first;
+  attrList["DetectorMaskSnd"].data<unsigned long long>() = dm.second;
+
+  // coral wants us to have to do this explicitly...
+  attrSpec->release(); // we don't delete because the dtor is private
+                       // we have to hope the CORAL framework will
+
+  return attrList;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+std::pair<uint64_t, uint64_t>
+SORHelper::getDetMask(const ptree& rparams) const
+{
+  const auto& dmstr = rparams.get_child("det_mask").data();
+  return eformat::helper::DetectorMask(dmstr).serialize();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+StatusCode SORHelper::fillSor(const ptree & rparams, SOR * sor) const
+{
+  // obtain SOR contents from ptree
+  auto attrList = getAttrList(rparams);
+
+  // Validity stuff
+  IOVTime iovTimeStart(attrList["RunNumber"].data<unsigned int>() ,0);
+  IOVTime iovTimeStop(attrList["RunNumber"].data<unsigned int>()+1,0);
+  IOVRange iovRange(iovTimeStart, iovTimeStop);
+  auto channum = SOR::ChanNum{0};
+
+  sor->add(channum, attrList);
+  sor->add(channum,iovRange);
+  sor->resetMinRange();
+  sor->addNewStart(iovTimeStart);
+  sor->addNewStop(iovTimeStop);
+
+  return setIOVRange(iovRange);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+StatusCode SORHelper::setIOVRange(IOVRange & iovRange) const
+{
+  // set IOVRange on the IOVSvc
+  ServiceHandle<IIOVSvc> iovsvc("IOVSvc", CLNAME);
+  if ((iovsvc.retrieve()).isFailure())
+  {
+    m_log << MSG::ERROR << ST_WHERE << "could not find IOVSvc" << endreq;
+    return StatusCode::FAILURE;
+  }
+
+  auto clid = ClassID_traits<SOR>::ID();
+  if ((iovsvc->setRange(clid, SORPATH, iovRange, "StoreGateSvc")).isFailure())
+  {
+    m_log << MSG::ERROR << ST_WHERE
+          << "could not set IOVRange for SOR folder in IOVSvc." << endreq;
+    return StatusCode::FAILURE;
+  }
+
+  return StatusCode::SUCCESS;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+StatusCode
+SORHelper::updateProxy(const SG & dstore, SOR * sor) const
+{
+  // check the SOR_Params proxy and add if necessary an IAddressProvider
+  //(typically for MC)
+  auto proxy = dstore->proxy(sor);
+  if (!proxy) {
+    m_log << MSG::ERROR << ST_WHERE
+          << "could not find proxy for SOR_Params folder." << endreq;
+    return StatusCode::FAILURE;
+  }
+
+  auto transientAddr = proxy->transientAddress();
+  if (!transientAddr) {
+    m_log << MSG::ERROR << ST_WHERE
+          << "could not find transient address for SOR_Params folder" << endreq;
+    return StatusCode::FAILURE;
+  }
+
+  // check if the transient address has an IAddressProvider, if not set
+  //IOVDbSvc as provider
+  if (!transientAddr->provider()) {
+    // get handle to the IOVDbSvc
+    ServiceHandle<IIOVDbSvc> iovdbsvc("IOVDbSvc", CLNAME);
+    if ((iovdbsvc.retrieve()).isFailure()) {
+      m_log << MSG::ERROR << ST_WHERE << "could not find IOVDbSvc." << endreq;
+      return StatusCode::FAILURE;
+    }
+
+    IAddressProvider* provider = dynamic_cast<IAddressProvider*>(&*iovdbsvc);
+    if (!provider) {
+      m_log << MSG::ERROR << ST_WHERE
+            << "could not cast to IAddressProvider interface and set the "
+               "provider for SOR_Params." << endreq;
+      return StatusCode::FAILURE;
+    }
+    transientAddr->setProvider(provider, transientAddr->storeID());
+  }
+
+  return StatusCode::SUCCESS;
+}
+
diff --git a/HLT/Trigger/TrigControl/TrigServices/src/TrigSORFromPtreeHelper.h b/HLT/Trigger/TrigControl/TrigServices/src/TrigSORFromPtreeHelper.h
new file mode 100644
index 00000000000..d32a297f27a
--- /dev/null
+++ b/HLT/Trigger/TrigControl/TrigServices/src/TrigSORFromPtreeHelper.h
@@ -0,0 +1,65 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+/**
+ * @file TrigSORFromPtreeHelper.h
+ * @author Ricardo Abreu
+ *
+ * @brief Helper class to retrieve the Start Of Run parameters from the
+ * prepareForRun ptree and put them into the detector store with whole-run
+ * validity. This class replaces it's old analogous TrigSORFromISHelper.
+ */
+
+#ifndef TRIGSORFROMPTREEHELPER_H_
+#define TRIGSORFROMPTREEHELPER_H_
+
+#include "AthenaPoolUtilities/CondAttrListCollection.h"
+#include "StoreGate/StoreGateSvc.h"
+#include "GaudiKernel/MsgStream.h"
+#include "GaudiKernel/StatusCode.h"
+#include "GaudiKernel/ServiceHandle.h"
+#include <boost/property_tree/ptree.hpp>
+#include <utility>
+
+class CondAttrListCollection;
+
+////////////////////////////////////////////////////////////////////////////////
+class TrigSORFromPtreeHelper
+{
+public:
+  typedef CondAttrListCollection SOR;
+
+  TrigSORFromPtreeHelper(const MsgStream & log);
+
+  /*
+   * Fill SOR record in Detector Store, reusing if present or creating new one
+   * otherwise. SOR contents filled according to what is specified by rparams.
+   * Validity of SOR set to this run
+   */
+  const SOR * fillSOR(const boost::property_tree::ptree & rparams) const;
+
+private:
+  typedef ServiceHandle<StoreGateSvc> SG;
+  typedef boost::property_tree::ptree PT;
+
+  SOR * getSOR(const SG & dstore) const;
+  coral::AttributeList getAttrList(const PT & rparams) const;
+  std::pair<uint64_t, uint64_t> getDetMask(const PT & rparams) const;
+
+  StatusCode fillSor(const PT & rparams, SOR * sor) const;
+  StatusCode setIOVRange(IOVRange & iovRange) const;
+  StatusCode updateProxy(const SG & dstore, SOR * sor) const;
+
+  mutable MsgStream m_log;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+inline TrigSORFromPtreeHelper::
+TrigSORFromPtreeHelper(const MsgStream & log)
+  : m_log(log)
+{
+}
+
+
+#endif /* TRIGSORFROMPTREEHELPER_H_ */
diff --git a/HLT/Trigger/TrigControl/TrigServices/src/components/TrigServices_entries.cxx b/HLT/Trigger/TrigControl/TrigServices/src/components/TrigServices_entries.cxx
new file mode 100644
index 00000000000..cde6e20dfa0
--- /dev/null
+++ b/HLT/Trigger/TrigControl/TrigServices/src/components/TrigServices_entries.cxx
@@ -0,0 +1,30 @@
+#include "GaudiKernel/DeclareFactoryEntries.h"
+#include "TrigServices/TrigMessageSvc.h"
+#include "../TrigMonTHistSvc.h"
+#include "TrigServices/HltEventLoopMgr.h"
+#include "TrigServices/HltROBDataProviderSvc.h"
+#include "TrigServices/TrigIS.h"
+#include "TrigServices/TrigISHelper.h"
+#include "../TrigPreFlightCheck.h"
+#include "../TrigCOOLUpdateHelper.h"
+
+DECLARE_SERVICE_FACTORY( TrigMessageSvc )
+DECLARE_SERVICE_FACTORY( TrigMonTHistSvc )
+DECLARE_SERVICE_FACTORY( TrigIS )
+DECLARE_SERVICE_FACTORY( HltEventLoopMgr )
+DECLARE_SERVICE_FACTORY( HltROBDataProviderSvc )
+DECLARE_TOOL_FACTORY( TrigISHelper )
+DECLARE_TOOL_FACTORY( TrigPreFlightCheck )
+DECLARE_TOOL_FACTORY( TrigCOOLUpdateHelper )  
+
+
+DECLARE_FACTORY_ENTRIES( TrigServices ) {
+  DECLARE_SERVICE( TrigMessageSvc );
+  DECLARE_SERVICE( TrigMonTHistSvc );
+  DECLARE_SERVICE( TrigIS );  
+  DECLARE_SERVICE( HltEventLoopMgr );
+  DECLARE_SERVICE( HltROBDataProviderSvc );
+  DECLARE_TOOL( TrigISHelper );
+  DECLARE_TOOL( TrigPreFlightCheck );
+  DECLARE_TOOL( TrigCOOLUpdateHelper );
+}
diff --git a/HLT/Trigger/TrigControl/TrigServices/src/components/TrigServices_load.cxx b/HLT/Trigger/TrigControl/TrigServices/src/components/TrigServices_load.cxx
new file mode 100644
index 00000000000..0e7b58ee4de
--- /dev/null
+++ b/HLT/Trigger/TrigControl/TrigServices/src/components/TrigServices_load.cxx
@@ -0,0 +1,3 @@
+#include "GaudiKernel/LoadFactoryEntries.h"
+
+LOAD_FACTORY_ENTRIES( TrigServices )
-- 
GitLab