From 9fa2b56bfa9d830a87ee6e67cbba0e772e449b16 Mon Sep 17 00:00:00 2001
From: Lamar Moore <lamar.moore@stfc.ac.uk>
Date: Wed, 14 Nov 2018 12:25:32 +0000
Subject: [PATCH] IKafkaStreamDecoder and unit tests

---
 Framework/LiveData/CMakeLists.txt             |    3 +
 .../Kafka/IKafkaStreamDecoder.h               |  294 ++++
 .../Kafka/KafkaEventStreamDecoder.h           |  146 +-
 .../MantidLiveData/Kafka/KafkaHistoListener.h |    3 +
 .../Kafka/KafkaHistoStreamDecoder.h           |   70 +-
 .../src/Kafka/IKafkaStreamDecoder.cpp         |  503 ++++++
 .../src/Kafka/KafkaEventStreamDecoder.cpp     |  578 +------
 .../LiveData/src/Kafka/KafkaHistoListener.cpp |   31 +-
 .../src/Kafka/KafkaHistoStreamDecoder.cpp     |  242 +--
 .../private/Schema/f142_logdata_generated.h   | 1401 +++++++++--------
 .../Schema/hs00_event_histogram_generated.h   |  943 +++++------
 .../test/KafkaHistoStreamDecoderTest.h        |  189 +++
 Framework/LiveData/test/KafkaTesting.h        |   98 +-
 13 files changed, 2499 insertions(+), 2002 deletions(-)
 create mode 100644 Framework/LiveData/inc/MantidLiveData/Kafka/IKafkaStreamDecoder.h
 create mode 100644 Framework/LiveData/src/Kafka/IKafkaStreamDecoder.cpp
 create mode 100644 Framework/LiveData/test/KafkaHistoStreamDecoderTest.h

diff --git a/Framework/LiveData/CMakeLists.txt b/Framework/LiveData/CMakeLists.txt
index 2629c652ab1..27d59394c54 100644
--- a/Framework/LiveData/CMakeLists.txt
+++ b/Framework/LiveData/CMakeLists.txt
@@ -56,6 +56,7 @@ find_package ( LibRDKafka 0.11 )
 if ( LIBRDKAFKA_FOUND )
   set ( SRC_FILES
     ${SRC_FILES}
+    src/Kafka/IKafkaStreamDecoder.cpp
     src/Kafka/KafkaEventListener.cpp
     src/Kafka/KafkaEventStreamDecoder.cpp
     src/Kafka/KafkaHistoListener.cpp
@@ -69,6 +70,7 @@ if ( LIBRDKAFKA_FOUND )
     inc/MantidLiveData/Kafka/KafkaEventStreamDecoder.h
     inc/MantidLiveData/Kafka/IKafkaStreamSubscriber.h
     inc/MantidLiveData/Kafka/IKafkaBroker.h
+    inc/MantidLiveData/Kafka/IKafkaStreamDecoder.h
     inc/MantidLiveData/Kafka/KafkaBroker.h
     inc/MantidLiveData/Kafka/KafkaHistoListener.h
     inc/MantidLiveData/Kafka/KafkaHistoStreamDecoder.h
@@ -87,6 +89,7 @@ if ( LIBRDKAFKA_FOUND )
   set ( TEST_FILES
     ${TEST_FILES}
     KafkaEventStreamDecoderTest.h
+    KafkaHistoStreamDecoderTest.h
     KafkaTopicSubscriberTest.h
   )
 endif()
diff --git a/Framework/LiveData/inc/MantidLiveData/Kafka/IKafkaStreamDecoder.h b/Framework/LiveData/inc/MantidLiveData/Kafka/IKafkaStreamDecoder.h
new file mode 100644
index 00000000000..a255a0c524d
--- /dev/null
+++ b/Framework/LiveData/inc/MantidLiveData/Kafka/IKafkaStreamDecoder.h
@@ -0,0 +1,294 @@
+// Mantid Repository : https://github.com/mantidproject/mantid
+//
+// Copyright &copy; 2016 ISIS Rutherford Appleton Laboratory UKRI,
+//     NScD Oak Ridge National Laboratory, European Spallation Source
+//     & Institut Laue - Langevin
+// SPDX - License - Identifier: GPL - 3.0 +
+#ifndef MANTID_LIVEDATA_IKAFKASTREAMDECODER_H_
+#define MANTID_LIVEDATA_IKAFKASTREAMDECODER_H_
+
+#include "MantidAPI/SpectraDetectorTypes.h"
+#include "MantidDataObjects/EventWorkspace.h"
+#include "MantidLiveData/Kafka/IKafkaBroker.h"
+#include "MantidLiveData/Kafka/IKafkaStreamSubscriber.h"
+
+#include <atomic>
+#include <condition_variable>
+#include <mutex>
+#include <thread>
+#include <unordered_map>
+
+namespace Mantid {
+namespace LiveData {
+
+/**
+Kafka stream decoder interface. Handles (implements) all thread synchronization
+functionality for accessing the data stream and processing data.
+*/
+class DLLExport IKafkaStreamDecoder {
+public:
+  using CallbackFn = std::function<void()>;
+
+public:
+  IKafkaStreamDecoder(std::shared_ptr<IKafkaBroker> broker,
+                      const std::string &streamTopic,
+                      const std::string &runInfoTopic,
+                      const std::string &spDetTopic,
+                      const std::string &sampleEnvTopic);
+  virtual ~IKafkaStreamDecoder();
+  IKafkaStreamDecoder(const IKafkaStreamDecoder &) = delete;
+  IKafkaStreamDecoder &operator=(const IKafkaStreamDecoder &) = delete;
+
+public:
+  ///@name Start/stop
+  ///@{
+  void startCapture(bool startNow = true);
+  void stopCapture() noexcept;
+  ///@}
+
+  ///@name Querying
+  ///@{
+  bool isCapturing() const noexcept { return m_capturing; }
+  virtual bool hasData() const noexcept = 0;
+  int runNumber() const noexcept { return m_runNumber; }
+  virtual bool hasReachedEndOfRun() noexcept = 0;
+  bool dataReset();
+  ///@}
+
+  ///@name Callbacks
+  ///@{
+  virtual void registerIterationEndCb(CallbackFn cb) {
+    m_cbIterationEnd = std::move(cb);
+  }
+  virtual void registerErrorCb(CallbackFn cb) { m_cbError = std::move(cb); }
+  ///@}
+
+  ///@name Modifying
+  ///@{
+  API::Workspace_sptr extractData();
+  ///@}
+
+protected:
+  struct RunStartStruct {
+    std::string instrumentName;
+    int runNumber;
+    uint64_t startTime;
+    size_t nPeriods;
+    int64_t runStartMsgOffset;
+  };
+
+  /// Main loop of listening for data messages and populating the cache
+  /// workspaces
+  void captureImpl() noexcept;
+  virtual void captureImplExcept() = 0;
+
+  /// Create the cache workspaces, LoadLiveData extracts data from these
+  virtual void initLocalCaches(const std::string &rawMsgBuffer,
+                               const RunStartStruct &runStartData) = 0;
+
+  /// Get an expected message from the run information topic
+  int64_t getRunInfoMessage(std::string &rawMsgBuffer);
+
+  /// Get an expected RunStart message
+  RunStartStruct getRunStartMessage(std::string &rawMsgBuffer);
+
+  /// Populate cache workspaces with data from messages
+  virtual void sampleDataFromMessage(const std::string &buffer) = 0;
+
+  /// For LoadLiveData to extract the cached data
+  virtual API::Workspace_sptr extractDataImpl() = 0;
+
+  /// Broker to use to subscribe to topics
+  std::shared_ptr<IKafkaBroker> m_broker;
+  /// Topic names
+  const std::string m_streamTopic;
+  const std::string m_runInfoTopic;
+  const std::string m_spDetTopic;
+  const std::string m_sampleEnvTopic;
+  /// Flag indicating if user interruption has been requested
+  std::atomic<bool> m_interrupt;
+  /// Subscriber for the data stream
+  std::unique_ptr<IKafkaStreamSubscriber> m_dataStream;
+  /// Mapping of spectrum number to workspace index.
+  spec2index_map m_specToIdx;
+  /// Start time of the run
+  Types::Core::DateAndTime m_runStart;
+  /// Subscriber for the run info stream
+  std::unique_ptr<IKafkaStreamSubscriber> m_runStream;
+  /// Subscriber for the run info stream
+  std::unique_ptr<IKafkaStreamSubscriber> m_spDetStream;
+  /// Run number
+  int m_runNumber;
+
+  /// Associated thread running the capture process
+  std::thread m_thread;
+  /// Mutex protecting event buffers
+  mutable std::mutex m_mutex;
+  /// Mutex protecting the wait flag
+  mutable std::mutex m_waitMutex;
+  /// Mutex protecting the runStatusSeen flag
+  mutable std::mutex m_runStatusMutex;
+  /// Flag indicating that the decoder is capturing
+  std::atomic<bool> m_capturing;
+  /// Exception object indicating there was an error
+  boost::shared_ptr<std::runtime_error> m_exception;
+
+  /// For notifying other threads of changes to conditions (the following bools)
+  std::condition_variable m_cv;
+  std::condition_variable m_cvRunStatus;
+  /// Indicate that decoder has reached the last message in a run
+  std::atomic<bool> m_endRun;
+  /// Indicate that LoadLiveData is waiting for access to the buffer workspace
+  std::atomic<bool> m_extractWaiting;
+  /// Indicate that MonitorLiveData has seen the runStatus since it was set to
+  /// EndRun
+  bool m_runStatusSeen;
+  std::atomic<bool> m_extractedEndRunData;
+  /// Indicate if the next data to be extracted should replace LoadLiveData's
+  /// output workspace
+  std::atomic<bool> m_dataReset;
+
+  void waitForDataExtraction();
+  void waitForRunEndObservation();
+
+  std::map<int32_t, std::set<int32_t>>
+  buildSpectrumToDetectorMap(const size_t nspectra, const int32_t *spec,
+                             const int32_t *udet, uint32_t length);
+
+  template <typename T>
+  boost::shared_ptr<T>
+  createBufferWorkspace(const std::string &workspaceClassName, size_t nspectra,
+                        const int32_t *spec, const int32_t *udet,
+                        uint32_t length);
+  template <typename T>
+  boost::shared_ptr<T>
+  createBufferWorkspace(const std::string &workspaceClassName,
+                        const boost::shared_ptr<T> &parent);
+
+  template <typename T>
+  void loadInstrument(const std::string &name, boost::shared_ptr<T> workspace);
+
+  void checkRunMessage(
+      const std::string &buffer, bool &checkOffsets,
+      std::unordered_map<std::string, std::vector<int64_t>> &stopOffsets,
+      std::unordered_map<std::string, std::vector<bool>> &reachedEnd);
+
+  void checkRunEnd(
+      const std::string &topicName, bool &checkOffsets, const int64_t offset,
+      const int32_t partition,
+      std::unordered_map<std::string, std::vector<int64_t>> &stopOffsets,
+      std::unordered_map<std::string, std::vector<bool>> &reachedEnd);
+
+  /// Methods for checking if the end of a run was reached
+  std::unordered_map<std::string, std::vector<int64_t>> getStopOffsets(
+      std::unordered_map<std::string, std::vector<int64_t>> &stopOffsets,
+      std::unordered_map<std::string, std::vector<bool>> &reachedEnd,
+      uint64_t stopTime) const;
+  void checkIfAllStopOffsetsReached(
+      const std::unordered_map<std::string, std::vector<bool>> &reachedEnd,
+      bool &checkOffsets);
+
+  /// Callbacks for unit tests
+  CallbackFn m_cbIterationEnd;
+  CallbackFn m_cbError;
+
+  /// Waits until a run start message with higher run number is received
+  bool waitForNewRunStartMessage(RunStartStruct &runStartStructOutput);
+  /// Subscribe to data stream at the time specified in a run start message
+  void joinStreamAtTime(const RunStartStruct &runStartData);
+  /// Convert a duration in nanoseconds to milliseconds
+  int64_t nanosecondsToMilliseconds(uint64_t timeNanoseconds) const;
+  /// Get a det-spec map message using the time specified in a run start message
+  std::string getDetSpecMapForRun(const RunStartStruct &runStartStruct);
+};
+
+/**
+ * Create a buffer workspace of the correct size based on the values given.
+ * @param workspaceClassName the name of the workspace class to be created e.g
+ * Workspace2D or EventWorkspace
+ * @param nspectra The number of unique spectrum numbers
+ * @param spec An array of length ndet specifying the spectrum number of each
+ * detector
+ * @param udet An array of length ndet specifying the detector ID of each
+ * detector
+ * @param length The length of the spec/udet arrays
+ * @return A new workspace of the appropriate size
+ */
+template <typename T>
+boost::shared_ptr<T> IKafkaStreamDecoder::createBufferWorkspace(
+    const std::string &workspaceClassName, size_t nspectra, const int32_t *spec,
+    const int32_t *udet, uint32_t length) {
+  // Get spectra to detector mapping
+  auto spdetMap = buildSpectrumToDetectorMap(nspectra, spec, udet, length);
+
+  // Create histo workspace
+  auto buffer =
+      boost::static_pointer_cast<T>(API::WorkspaceFactory::Instance().create(
+          workspaceClassName, nspectra, 2, 1));
+
+  // Set the units
+  buffer->getAxis(0)->unit() = Kernel::UnitFactory::Instance().create("TOF");
+  buffer->setYUnit("Counts");
+  // Setup spectra-detector mapping.
+  size_t wsIdx(0);
+  for (const auto &spIter : spdetMap) {
+    auto &spectrum = buffer->getSpectrum(wsIdx);
+    spectrum.setSpectrumNo(spIter.first);
+    spectrum.addDetectorIDs(spIter.second);
+    ++wsIdx;
+  }
+  return buffer;
+}
+
+/**
+ * Create new buffer workspace from an existing copy
+ * @param workspaceClassName the name of the workspace class to be created e.g
+ * Workspace2D or EventWorkspace
+ * @param parent A reference to an existing workspace
+ */
+template <typename T>
+boost::shared_ptr<T> IKafkaStreamDecoder::createBufferWorkspace(
+    const std::string &workspaceClassName, const boost::shared_ptr<T> &parent) {
+  auto buffer =
+      boost::static_pointer_cast<T>(API::WorkspaceFactory::Instance().create(
+          workspaceClassName, parent->getNumberHistograms(), 2, 1));
+  // Copy meta data
+  API::WorkspaceFactory::Instance().initializeFromParent(*parent, *buffer,
+                                                         false);
+  // Clear out the old logs, except for the most recent entry
+  buffer->mutableRun().clearOutdatedTimeSeriesLogValues();
+  return buffer;
+}
+
+/**
+ * Run LoadInstrument for the given instrument name. If it cannot succeed it
+ * does nothing to the internal workspace
+ * @param name Name of an instrument to load
+ * @param workspace A pointer to the workspace receiving the instrument
+ */
+template <typename T>
+void IKafkaStreamDecoder::loadInstrument(const std::string &name,
+                                         boost::shared_ptr<T> workspace) {
+  if (name.empty()) {
+    g_log.warning("Empty instrument name found");
+    return;
+  }
+  try {
+    auto alg =
+        API::AlgorithmManager::Instance().createUnmanaged("LoadInstrument");
+    // Do not put the workspace in the ADS
+    alg->setChild(true);
+    alg->initialize();
+    alg->setPropertyValue("InstrumentName", name);
+    alg->setProperty("Workspace", workspace);
+    alg->setProperty("RewriteSpectraMap", Kernel::OptionalBool(false));
+    alg->execute();
+  } catch (std::exception &exc) {
+    g_log.warning() << "Error loading instrument '" << name
+                    << "': " << exc.what() << "\n";
+  }
+}
+
+} // namespace LiveData
+} // namespace Mantid
+#endif // MANTID_LIVEDATA_IKAFKASTREAMDECODER_H_
diff --git a/Framework/LiveData/inc/MantidLiveData/Kafka/KafkaEventStreamDecoder.h b/Framework/LiveData/inc/MantidLiveData/Kafka/KafkaEventStreamDecoder.h
index 472d18bc409..8236e6fe8b8 100644
--- a/Framework/LiveData/inc/MantidLiveData/Kafka/KafkaEventStreamDecoder.h
+++ b/Framework/LiveData/inc/MantidLiveData/Kafka/KafkaEventStreamDecoder.h
@@ -10,13 +10,9 @@
 #include "MantidAPI/SpectraDetectorTypes.h"
 #include "MantidDataObjects/EventWorkspace.h"
 #include "MantidLiveData/Kafka/IKafkaBroker.h"
+#include "MantidLiveData/Kafka/IKafkaStreamDecoder.h"
 #include "MantidLiveData/Kafka/IKafkaStreamSubscriber.h"
 
-#include <atomic>
-#include <condition_variable>
-#include <mutex>
-#include <thread>
-
 namespace Mantid {
 namespace LiveData {
 
@@ -27,10 +23,7 @@ namespace LiveData {
   A call to capture() starts the process of capturing the stream on a separate
   thread.
 */
-class DLLExport KafkaEventStreamDecoder {
-public:
-  using CallbackFn = std::function<void()>;
-
+class DLLExport KafkaEventStreamDecoder : public IKafkaStreamDecoder {
 public:
   KafkaEventStreamDecoder(std::shared_ptr<IKafkaBroker> broker,
                           const std::string &eventTopic,
@@ -42,150 +35,29 @@ public:
   KafkaEventStreamDecoder &operator=(const KafkaEventStreamDecoder &) = delete;
 
 public:
-  ///@name Start/stop
-  ///@{
-  void startCapture(bool startNow = true);
-  void stopCapture() noexcept;
-  ///@}
-
   ///@name Querying
   ///@{
-  bool isCapturing() const noexcept { return m_capturing; }
-  bool hasData() const noexcept;
-  int runNumber() const noexcept { return m_runNumber; }
-  bool hasReachedEndOfRun() noexcept;
-  bool dataReset();
-  ///@}
-
-  ///@name Callbacks
-  ///@{
-  void registerIterationEndCb(CallbackFn cb) {
-    m_cbIterationEnd = std::move(cb);
-  }
-  void registerErrorCb(CallbackFn cb) { m_cbError = std::move(cb); }
-  ///@}
-
-  ///@name Modifying
-  ///@{
-  API::Workspace_sptr extractData();
+  bool hasData() const noexcept override;
+  bool hasReachedEndOfRun() noexcept override;
   ///@}
 
 private:
-  struct RunStartStruct {
-    std::string instrumentName;
-    int runNumber;
-    uint64_t startTime;
-    size_t nPeriods;
-    int64_t runStartMsgOffset;
-  };
-  /// Main loop of listening for data messages and populating the cache
-  /// workspaces
-  void captureImpl() noexcept;
-  void captureImplExcept();
+  void captureImplExcept() override;
 
   /// Create the cache workspaces, LoadLiveData extracts data from these
   void initLocalCaches(const std::string &rawMsgBuffer,
-                       const RunStartStruct &runStartData);
-  DataObjects::EventWorkspace_sptr createBufferWorkspace(size_t nspectra,
-                                                         const int32_t *spec,
-                                                         const int32_t *udet,
-                                                         uint32_t length);
-  DataObjects::EventWorkspace_sptr
-  createBufferWorkspace(const DataObjects::EventWorkspace_sptr &parent);
-
-  /// Load a named instrument into a workspace
-  void loadInstrument(const std::string &name,
-                      DataObjects::EventWorkspace_sptr workspace);
-
-  /// Get an expected message from the run information topic
-  int64_t getRunInfoMessage(std::string &rawMsgBuffer);
-
-  /// Get an expected RunStart message
-  RunStartStruct getRunStartMessage(std::string &rawMsgBuffer);
+                       const RunStartStruct &runStartData) override;
 
   /// Populate cache workspaces with data from messages
   void eventDataFromMessage(const std::string &buffer);
-  void sampleDataFromMessage(const std::string &buffer);
+
+  void sampleDataFromMessage(const std::string &buffer) override;
 
   /// For LoadLiveData to extract the cached data
-  API::Workspace_sptr extractDataImpl();
+  API::Workspace_sptr extractDataImpl() override;
 
-  /// Broker to use to subscribe to topics
-  std::shared_ptr<IKafkaBroker> m_broker;
-  /// Topic names
-  const std::string m_eventTopic;
-  const std::string m_runInfoTopic;
-  const std::string m_spDetTopic;
-  const std::string m_sampleEnvTopic;
-  /// Flag indicating if user interruption has been requested
-  std::atomic<bool> m_interrupt;
-  /// Subscriber for the event stream
-  std::unique_ptr<IKafkaStreamSubscriber> m_eventStream;
   /// Local event workspace buffers
   std::vector<DataObjects::EventWorkspace_sptr> m_localEvents;
-  /// Mapping of spectrum number to workspace index.
-  spec2index_map m_specToIdx;
-  /// Start time of the run
-  Types::Core::DateAndTime m_runStart;
-  /// Subscriber for the run info stream
-  std::unique_ptr<IKafkaStreamSubscriber> m_runStream;
-  /// Subscriber for the run info stream
-  std::unique_ptr<IKafkaStreamSubscriber> m_spDetStream;
-  /// Run number
-  int m_runNumber;
-
-  /// Associated thread running the capture process
-  std::thread m_thread;
-  /// Mutex protecting event buffers
-  mutable std::mutex m_mutex;
-  /// Mutex protecting the wait flag
-  mutable std::mutex m_waitMutex;
-  /// Mutex protecting the runStatusSeen flag
-  mutable std::mutex m_runStatusMutex;
-  /// Flag indicating that the decoder is capturing
-  std::atomic<bool> m_capturing;
-  /// Exception object indicating there was an error
-  boost::shared_ptr<std::runtime_error> m_exception;
-
-  /// For notifying other threads of changes to conditions (the following bools)
-  std::condition_variable m_cv;
-  std::condition_variable m_cvRunStatus;
-  /// Indicate that decoder has reached the last message in a run
-  std::atomic<bool> m_endRun;
-  /// Indicate that LoadLiveData is waiting for access to the buffer workspace
-  std::atomic<bool> m_extractWaiting;
-  /// Indicate that MonitorLiveData has seen the runStatus since it was set to
-  /// EndRun
-  bool m_runStatusSeen;
-  std::atomic<bool> m_extractedEndRunData;
-  /// Indicate if the next data to be extracted should replace LoadLiveData's
-  /// output workspace
-  std::atomic<bool> m_dataReset;
-
-  void waitForDataExtraction();
-  void waitForRunEndObservation();
-
-  /// Methods for checking if the end of a run was reached
-  std::unordered_map<std::string, std::vector<int64_t>> getStopOffsets(
-      std::unordered_map<std::string, std::vector<int64_t>> &stopOffsets,
-      std::unordered_map<std::string, std::vector<bool>> &reachedEnd,
-      uint64_t stopTime) const;
-  void checkIfAllStopOffsetsReached(
-      const std::unordered_map<std::string, std::vector<bool>> &reachedEnd,
-      bool &checkOffsets);
-
-  /// Callbacks for unit tests
-  CallbackFn m_cbIterationEnd;
-  CallbackFn m_cbError;
-
-  /// Waits until a run start message with higher run number is received
-  bool waitForNewRunStartMessage(RunStartStruct &runStartStructOutput);
-  /// Subscribe to event stream at the time specified in a run start message
-  void joinEventStreamAtTime(const RunStartStruct &runStartData);
-  /// Convert a duration in nanoseconds to milliseconds
-  int64_t nanosecondsToMilliseconds(uint64_t timeNanoseconds) const;
-  /// Get a det-spec map message using the time specified in a run start message
-  std::string getDetSpecMapForRun(const RunStartStruct &runStartStruct);
 };
 
 } // namespace LiveData
diff --git a/Framework/LiveData/inc/MantidLiveData/Kafka/KafkaHistoListener.h b/Framework/LiveData/inc/MantidLiveData/Kafka/KafkaHistoListener.h
index 796962d211f..b87aa173543 100644
--- a/Framework/LiveData/inc/MantidLiveData/Kafka/KafkaHistoListener.h
+++ b/Framework/LiveData/inc/MantidLiveData/Kafka/KafkaHistoListener.h
@@ -39,6 +39,8 @@ public:
   /// Does this listener buffer events (true) or histogram data (false)
   bool buffersEvents() const override { return false; }
 
+  void setAlgorithm(const Mantid::API::IAlgorithm &callingAlgorithm) override;
+
   //----------------------------------------------------------------------
   // Actions
   //----------------------------------------------------------------------
@@ -56,6 +58,7 @@ public:
 
 private:
   std::unique_ptr<KafkaHistoStreamDecoder> m_decoder = nullptr;
+  std::string m_instrumentName;
 };
 
 } // namespace LiveData
diff --git a/Framework/LiveData/inc/MantidLiveData/Kafka/KafkaHistoStreamDecoder.h b/Framework/LiveData/inc/MantidLiveData/Kafka/KafkaHistoStreamDecoder.h
index c40b313764e..25e5a6133fc 100644
--- a/Framework/LiveData/inc/MantidLiveData/Kafka/KafkaHistoStreamDecoder.h
+++ b/Framework/LiveData/inc/MantidLiveData/Kafka/KafkaHistoStreamDecoder.h
@@ -8,12 +8,9 @@
 #define MANTID_LIVEDATA_ISISKAFKAHISTOSTREAMDECODER_H_
 
 #include "MantidDataObjects/Workspace2D.h"
+#include "MantidLiveData/Kafka/IKafkaBroker.h"
+#include "MantidLiveData/Kafka/IKafkaStreamDecoder.h"
 #include "MantidLiveData/Kafka/IKafkaStreamSubscriber.h"
-#include "MantidLiveData/Kafka/KafkaBroker.h"
-
-#include <atomic>
-#include <mutex>
-#include <thread>
 
 namespace Mantid {
 namespace LiveData {
@@ -24,65 +21,34 @@ namespace LiveData {
   A call to startCapture() starts the process of capturing the stream on a
   separate thread.
 */
-class DLLExport KafkaHistoStreamDecoder {
+class DLLExport KafkaHistoStreamDecoder : public IKafkaStreamDecoder {
 public:
-  KafkaHistoStreamDecoder(const std::string &brokerAddress,
+  KafkaHistoStreamDecoder(std::shared_ptr<IKafkaBroker> broker,
                           const std::string &histoTopic,
-                          const std::string &instrumentName);
+                          const std::string &runInfoTopic,
+                          const std::string &spDetTopic,
+                          const std::string &sampleEnvTopic);
   ~KafkaHistoStreamDecoder();
   KafkaHistoStreamDecoder(const KafkaHistoStreamDecoder &) = delete;
   KafkaHistoStreamDecoder &operator=(const KafkaHistoStreamDecoder &) = delete;
 
-public:
-  ///@name Start/stop
-  ///@{
-  void startCapture(bool startNow = true);
-  void stopCapture() noexcept;
-  ///@}
+  bool hasData() const noexcept override;
+  bool hasReachedEndOfRun() noexcept override { return !m_capturing; }
 
-  ///@name Querying
-  ///@{
-  bool isCapturing() const { return m_capturing; }
-  bool hasData() const;
-  int runNumber() const { return 1; }
-  bool hasReachedEndOfRun() { return !m_capturing; }
-  ///@}
+private:
+  void captureImplExcept() override;
 
-  ///@name Modifying
-  ///@{
-  API::Workspace_sptr extractData();
-  ///@}
+  /// Create the cache workspaces, LoadLiveData extracts data from these
+  void initLocalCaches(const std::string &rawMsgBuffer,
+                       const RunStartStruct &runStartData) override;
 
-private:
-  void captureImpl();
-  void captureImplExcept();
-  API::Workspace_sptr extractDataImpl();
+  void sampleDataFromMessage(const std::string &buffer) override;
 
-  DataObjects::Workspace2D_sptr createBufferWorkspace();
+  API::Workspace_sptr extractDataImpl() override;
 
-  /// Broker to use to subscribe to topics
-  KafkaBroker m_broker;
-  /// Topic name
-  const std::string m_histoTopic;
-  /// Instrument name
-  const std::string m_instrumentName;
-  /// Subscriber for the histo stream
-  std::unique_ptr<IKafkaStreamSubscriber> m_histoStream;
-  /// Workspace used as template for workspaces created when extracting
-  DataObjects::Workspace2D_sptr m_workspace;
-  /// Buffer for latest FlatBuffers message
+private:
   std::string m_buffer;
-
-  /// Associated thread running the capture process
-  std::thread m_thread;
-  /// Mutex protecting histo buffers
-  mutable std::mutex m_buffer_mutex;
-  /// Flag indicating if user interruption has been requested
-  std::atomic<bool> m_interrupt;
-  /// Flag indicating that the decoder is capturing
-  std::atomic<bool> m_capturing;
-  /// Exception object indicating there was an error
-  std::unique_ptr<std::runtime_error> m_exception;
+  DataObjects::Workspace2D_sptr m_workspace;
 };
 
 } // namespace LiveData
diff --git a/Framework/LiveData/src/Kafka/IKafkaStreamDecoder.cpp b/Framework/LiveData/src/Kafka/IKafkaStreamDecoder.cpp
new file mode 100644
index 00000000000..448c20eca1f
--- /dev/null
+++ b/Framework/LiveData/src/Kafka/IKafkaStreamDecoder.cpp
@@ -0,0 +1,503 @@
+// Mantid Repository : https://github.com/mantidproject/mantid
+//
+// Copyright &copy; 2018 ISIS Rutherford Appleton Laboratory UKRI,
+//     NScD Oak Ridge National Laboratory, European Spallation Source
+//     & Institut Laue - Langevin
+// SPDX - License - Identifier: GPL - 3.0 +
+#include "MantidLiveData/Kafka/IKafkaStreamDecoder.h"
+#include "MantidKernel/Logger.h"
+#include "MantidKernel/WarningSuppressions.h"
+#include "MantidLiveData/Exception.h"
+#include "MantidLiveData/Kafka/KafkaTopicSubscriber.h"
+
+GNU_DIAG_OFF("conversion")
+#include "private/Schema/ba57_run_info_generated.h"
+#include "private/Schema/df12_det_spec_map_generated.h"
+#include "private/Schema/f142_logdata_generated.h"
+GNU_DIAG_ON("conversion")
+
+using namespace Mantid::Types;
+using namespace LogSchema;
+
+namespace {
+/// Logger
+Mantid::Kernel::Logger g_log("IKafkaStreamDecoder");
+
+// File identifiers from flatbuffers schema
+const std::string RUN_MESSAGE_ID = "ba57";
+
+const std::chrono::seconds MAX_LATENCY(1);
+} // namespace
+
+namespace Mantid {
+namespace LiveData {
+// -----------------------------------------------------------------------------
+// Public members
+// -----------------------------------------------------------------------------
+/**
+ * Constructor
+ * @param broker A reference to a Broker object for creating topic streams
+ * @param streamTopic The name of the topic streaming the stream data
+ * @param runInfoTopic The name of the topic streaming the run information
+ * @param spDetTopic The name of the topic streaming the spectrum-detector
+ * @param sampleEnvTopic The name of the topic stream sample environment
+ * information. run mapping
+ */
+IKafkaStreamDecoder::IKafkaStreamDecoder(std::shared_ptr<IKafkaBroker> broker,
+                                         const std::string &streamTopic,
+                                         const std::string &runInfoTopic,
+                                         const std::string &spDetTopic,
+                                         const std::string &sampleEnvTopic)
+    : m_broker(broker), m_streamTopic(streamTopic),
+      m_runInfoTopic(runInfoTopic), m_spDetTopic(spDetTopic),
+      m_sampleEnvTopic(sampleEnvTopic), m_interrupt(false), m_specToIdx(),
+      m_runStart(), m_runNumber(-1), m_thread(), m_capturing(false),
+      m_exception(), m_extractWaiting(false), m_cbIterationEnd([] {}),
+      m_cbError([] {}) {}
+
+/**
+ * Destructor.
+ * Stops capturing from the stream
+ */
+IKafkaStreamDecoder::~IKafkaStreamDecoder() { stopCapture(); }
+
+/**
+ * Start capturing from the stream on a separate thread. This is a non-blocking
+ * call and will return after the thread has started
+ */
+void IKafkaStreamDecoder::startCapture(bool startNow) {
+
+  // If we are not starting now, then we want to start at the start of the run
+  if (!startNow) {
+    // Get last two messages in run topic to ensure we get a runStart message
+    m_runStream =
+        m_broker->subscribe({m_runInfoTopic}, SubscribeAtOption::LASTTWO);
+    std::string rawMsgBuffer;
+    auto runStartData = getRunStartMessage(rawMsgBuffer);
+    joinStreamAtTime(runStartData);
+  } else {
+    m_dataStream =
+        m_broker->subscribe({m_streamTopic, m_runInfoTopic, m_sampleEnvTopic},
+                            SubscribeAtOption::LATEST);
+  }
+
+  // Get last two messages in run topic to ensure we get a runStart message
+  m_runStream =
+      m_broker->subscribe({m_runInfoTopic}, SubscribeAtOption::LASTTWO);
+  m_spDetStream =
+      m_broker->subscribe({m_spDetTopic}, SubscribeAtOption::LASTONE);
+
+  m_thread = std::thread([this]() { this->captureImpl(); });
+  m_thread.detach();
+}
+
+/** Indicate if the next data to be extracted should replace LoadLiveData's
+ * output workspace,
+ *  for example the first data of a new run
+ */
+bool IKafkaStreamDecoder::dataReset() {
+  bool result = (m_dataReset == true); // copy from atomic bool
+  m_dataReset = false;                 // reset to false
+  return result;
+}
+
+void IKafkaStreamDecoder::joinStreamAtTime(
+    const IKafkaStreamDecoder::RunStartStruct &runStartData) {
+  auto runStartTime = runStartData.startTime;
+  int64_t startTimeMilliseconds = nanosecondsToMilliseconds(runStartTime);
+  m_dataStream =
+      m_broker->subscribe({m_streamTopic, m_runInfoTopic, m_sampleEnvTopic},
+                          startTimeMilliseconds, SubscribeAtOption::TIME);
+  // make sure we listen to the run start topic starting from the run start
+  // message we already got the start time from
+  m_dataStream->seek(m_runInfoTopic, 0, runStartData.runStartMsgOffset);
+}
+
+int64_t
+IKafkaStreamDecoder::nanosecondsToMilliseconds(uint64_t timeNanoseconds) const {
+  return static_cast<int64_t>(timeNanoseconds / 1000000);
+}
+
+/**
+ * Stop capturing from the stream. This is a blocking call until the capturing
+ * function has completed
+ */
+void IKafkaStreamDecoder::stopCapture() noexcept {
+  // This will interrupt the "event" loop
+  m_interrupt = true;
+  // Wait until the function has completed. The background thread
+  // will exit automatically
+  while (m_capturing) {
+    std::this_thread::sleep_for(std::chrono::milliseconds(50));
+  };
+}
+
+/**
+ * Check if a message has indicated that end of run has been reached
+ * @return  True if end of run has been reached
+ */
+bool IKafkaStreamDecoder::hasReachedEndOfRun() noexcept {
+  // Notify the decoder that MonitorLiveData knows it has reached end of run
+  // and after giving it opportunity to interrupt, decoder can continue with
+  // messages of the next run
+  if (!m_extractedEndRunData || m_extractWaiting)
+    return false;
+  if (m_endRun) {
+    std::lock_guard<std::mutex> runStatusLock(m_runStatusMutex);
+    m_runStatusSeen = true;
+    m_cvRunStatus.notify_one();
+    return true;
+  }
+  return false;
+}
+
+/**
+ * Check for an exception thrown by the background thread and rethrow
+ * it if necessary. If no error occurred swap the current internal buffer
+ * for a fresh one and return the old buffer.
+ * @return A pointer to the data collected since the last call to this
+ * method
+ */
+API::Workspace_sptr IKafkaStreamDecoder::extractData() {
+  if (m_exception) {
+    throw std::runtime_error(*m_exception);
+  }
+
+  m_extractWaiting = true;
+  m_cv.notify_one();
+
+  auto workspace_ptr = extractDataImpl();
+
+  m_extractWaiting = false;
+  m_cv.notify_one();
+
+  return workspace_ptr;
+}
+
+/**
+ * Start decoding data from the streams into the internal buffers.
+ * Implementation designed to be entry point for new thread of execution.
+ * It catches all thrown exceptions.
+ */
+void IKafkaStreamDecoder::captureImpl() noexcept {
+  m_capturing = true;
+  try {
+    captureImplExcept();
+  } catch (std::exception &exc) {
+    m_cbError();
+    m_exception = boost::make_shared<std::runtime_error>(exc.what());
+  } catch (...) {
+    m_cbError();
+    m_exception = boost::make_shared<std::runtime_error>(
+        "IKafkaStreamDecoder: Unknown exception type caught.");
+  }
+  m_capturing = false;
+}
+
+/**
+ * Check if we've reached the stop offset on every partition of every topic
+ *
+ * @param reachedEnd : Bool for each topic and partition to mark when stop
+ * offset reached
+ */
+void IKafkaStreamDecoder::checkIfAllStopOffsetsReached(
+    const std::unordered_map<std::string, std::vector<bool>> &reachedEnd,
+    bool &checkOffsets) {
+
+  if (std::all_of(reachedEnd.cbegin(), reachedEnd.cend(),
+                  [](std::pair<std::string, std::vector<bool>> kv) {
+                    return std::all_of(
+                        kv.second.cbegin(), kv.second.cend(),
+                        [](bool partitionEnd) { return partitionEnd; });
+                  }) ||
+      reachedEnd.empty()) {
+    m_endRun = true;
+    // If we've reached the end of a run then set m_extractWaiting to true
+    // so that we wait until the buffer is emptied before continuing.
+    // Otherwise we can end up with data from two different runs in the
+    // same buffer workspace which is problematic if the user wanted the
+    // "Stop" or "Rename" run transition option.
+    m_extractedEndRunData = false;
+    checkOffsets = false;
+    g_log.notice("Reached end of run in data streams.");
+  }
+}
+
+std::unordered_map<std::string, std::vector<int64_t>>
+IKafkaStreamDecoder::getStopOffsets(
+    std::unordered_map<std::string, std::vector<int64_t>> &stopOffsets,
+    std::unordered_map<std::string, std::vector<bool>> &reachedEnd,
+    uint64_t stopTime) const {
+  reachedEnd.clear();
+  stopOffsets.clear();
+  // Wait for max latency so that we don't miss any late messages
+  std::this_thread::sleep_for(MAX_LATENCY);
+  stopOffsets = m_dataStream->getOffsetsForTimestamp(
+      static_cast<int64_t>(stopTime / 1000000));
+  // /1000000 to convert nanosecond precision from message to millisecond
+  // precision which Kafka offset query supports
+
+  auto currentOffsets = m_dataStream->getCurrentOffsets();
+
+  // Set reachedEnd to false for each topic and partition
+  for (auto &topicOffsets : stopOffsets) {
+    auto topicName = topicOffsets.first;
+    // Ignore the runInfo topic
+    if (topicName.substr(topicName.length() -
+                         KafkaTopicSubscriber::RUN_TOPIC_SUFFIX.length()) !=
+        KafkaTopicSubscriber::RUN_TOPIC_SUFFIX) {
+      g_log.debug() << "TOPIC: " << topicName
+                    << " PARTITIONS: " << topicOffsets.second.size()
+                    << std::endl;
+      reachedEnd.insert(
+          {topicName, std::vector<bool>(topicOffsets.second.size(), false)});
+
+      auto &partitionOffsets = topicOffsets.second;
+      for (uint32_t partitionNumber = 0;
+           partitionNumber < partitionOffsets.size(); partitionNumber++) {
+        auto offset = partitionOffsets[partitionNumber];
+        // If the stop offset is negative then there are no messages for us
+        // to collect on this topic, so mark reachedEnd as true already
+        reachedEnd[topicName][partitionNumber] = offset < 0;
+        // If the stop offset has already been reached then mark reachedEnd as
+        // true
+        if (currentOffsets[topicName][partitionNumber] >= offset)
+          reachedEnd[topicName][partitionNumber] = true;
+      }
+    }
+  }
+  return stopOffsets;
+}
+
+/**
+ * If extractData method is waiting for access to the buffer workspace
+ * then we wait for it to finish
+ */
+void IKafkaStreamDecoder::waitForDataExtraction() {
+  {
+    std::unique_lock<std::mutex> readyLock(m_waitMutex);
+    m_cv.wait(readyLock, [&] { return !m_extractWaiting; });
+  }
+}
+
+void IKafkaStreamDecoder::waitForRunEndObservation() {
+  m_extractWaiting = true;
+  // Mark extractedEndRunData true before waiting on the extraction to ensure
+  // an immediate request for run status after extracting the data will return
+  // the correct value - avoids race condition in MonitorLiveData and tests
+  m_extractedEndRunData = true;
+  waitForDataExtraction();
+
+  // Wait until MonitorLiveData has seen that end of run was
+  // reached before setting m_endRun back to false and continuing
+  std::unique_lock<std::mutex> runStatusLock(m_runStatusMutex);
+  m_cvRunStatus.wait(runStatusLock, [&] { return m_runStatusSeen; });
+  m_endRun = false;
+  m_runStatusSeen = false;
+  runStatusLock.unlock();
+
+  // Set to zero until we have the new run number, MonitorLiveData will
+  // queries before each time it extracts data until it gets non-zero
+  m_runNumber = 0;
+
+  // Get new run message now so that new run number is available for
+  // MonitorLiveData as early as possible
+  RunStartStruct runStartStruct;
+  if (waitForNewRunStartMessage(runStartStruct))
+    return;
+
+  // Give time for MonitorLiveData to act on runStatus information
+  // and trigger m_interrupt for next loop iteration if user requested
+  // LiveData algorithm to stop at the end of the run
+  std::this_thread::sleep_for(std::chrono::milliseconds(100));
+  if (m_interrupt)
+    return;
+
+  // Rejoin event stream at start of new run
+  joinStreamAtTime(runStartStruct);
+  std::string detSpecMapMsgBuffer = getDetSpecMapForRun(runStartStruct);
+  initLocalCaches(detSpecMapMsgBuffer, runStartStruct);
+}
+
+/**
+ * Try to find a detector-spectrum map message published after the
+ * current run start time
+ *
+ * @param runStartStruct details of the current run
+ * @return received detector-spectrum map message buffer
+ */
+std::string IKafkaStreamDecoder::getDetSpecMapForRun(
+    const IKafkaStreamDecoder::RunStartStruct &runStartStruct) {
+  std::string rawMsgBuffer;
+  int64_t offset;
+  int32_t partition;
+  std::string topicName;
+  m_spDetStream = m_broker->subscribe(
+      {m_spDetTopic}, nanosecondsToMilliseconds(runStartStruct.startTime),
+      SubscribeAtOption::TIME);
+  m_spDetStream->consumeMessage(&rawMsgBuffer, offset, partition, topicName);
+  if (rawMsgBuffer.empty()) {
+    std::runtime_error(
+        "No detector-spectrum map message found for run number " +
+        std::to_string(runStartStruct.runNumber));
+  }
+  return rawMsgBuffer;
+}
+
+/**
+ * Wait for a run start message until we get one with a higher run number
+ * than the current run or the algorithm is interrupted
+ *
+ * @param runStartStructOutput details of the new run
+ * @return true if interrupted, false if got a new run start message
+ */
+bool IKafkaStreamDecoder::waitForNewRunStartMessage(
+    RunStartStruct &runStartStructOutput) {
+  while (!m_interrupt) {
+    std::string runMsgBuffer;
+
+    int64_t offset;
+    int32_t partition;
+    std::string topicName;
+    m_runStream->consumeMessage(&runMsgBuffer, offset, partition, topicName);
+    if (runMsgBuffer.empty()) {
+      continue; // no message available, try again
+    } else {
+      auto runMsg =
+          GetRunInfo(reinterpret_cast<const uint8_t *>(runMsgBuffer.c_str()));
+      if (runMsg->info_type_type() == InfoTypes_RunStart) {
+        // We got a run start message, deserialise it
+        auto runStartData = static_cast<const RunStart *>(runMsg->info_type());
+        IKafkaStreamDecoder::RunStartStruct runStartStruct = {
+            runStartData->instrument_name()->str(), runStartData->run_number(),
+            runStartData->start_time(),
+            static_cast<size_t>(runStartData->n_periods()), offset};
+        if (runStartStruct.runNumber > m_runNumber) {
+          runStartStructOutput = runStartStruct;
+          m_runNumber = runStartStruct.runNumber;
+          return false; // not interrupted
+        }
+      } else {
+        continue; // received message wasn't a RunStart message, try again
+      }
+    }
+  }
+  return true; // interrupted
+}
+
+IKafkaStreamDecoder::RunStartStruct
+IKafkaStreamDecoder::getRunStartMessage(std::string &rawMsgBuffer) {
+  auto offset = getRunInfoMessage(rawMsgBuffer);
+  auto runMsg =
+      GetRunInfo(reinterpret_cast<const uint8_t *>(rawMsgBuffer.c_str()));
+  if (runMsg->info_type_type() != InfoTypes_RunStart) {
+    // We want a runStart message, try the next one
+    offset = getRunInfoMessage(rawMsgBuffer);
+    runMsg =
+        GetRunInfo(reinterpret_cast<const uint8_t *>(rawMsgBuffer.c_str()));
+    if (runMsg->info_type_type() != InfoTypes_RunStart) {
+      throw std::runtime_error("IKafkaStreamDecoder::initLocalCaches() - "
+                               "Could not find a run start message"
+                               "in the run info topic. Unable to continue");
+    }
+  }
+  auto runStartData = static_cast<const RunStart *>(runMsg->info_type());
+  IKafkaStreamDecoder::RunStartStruct runStart = {
+      runStartData->instrument_name()->str(), runStartData->run_number(),
+      runStartData->start_time(),
+      static_cast<size_t>(runStartData->n_periods()), offset};
+  return runStart;
+}
+
+/**
+ * Try to get a runInfo message from Kafka, throw error if it fails
+ * @param rawMsgBuffer : string to use as message buffer
+ */
+int64_t IKafkaStreamDecoder::getRunInfoMessage(std::string &rawMsgBuffer) {
+  int64_t offset;
+  int32_t partition;
+  std::string topicName;
+  m_runStream->consumeMessage(&rawMsgBuffer, offset, partition, topicName);
+  if (rawMsgBuffer.empty()) {
+    throw std::runtime_error("IKafkaStreamDecoder::getRunInfoMessage() - "
+                             "Empty message received from run info "
+                             "topic. Unable to continue");
+  }
+  if (!flatbuffers::BufferHasIdentifier(
+          reinterpret_cast<const uint8_t *>(rawMsgBuffer.c_str()),
+          RUN_MESSAGE_ID.c_str())) {
+    throw std::runtime_error("IKafkaStreamDecoder::getRunInfoMessage() - "
+                             "Received unexpected message type from run info "
+                             "topic. Unable to continue");
+  }
+  return offset;
+}
+
+std::map<int32_t, std::set<int32_t>>
+IKafkaStreamDecoder::buildSpectrumToDetectorMap(const size_t nspectra,
+                                                const int32_t *spec,
+                                                const int32_t *udet,
+                                                uint32_t length) {
+  // Order is important here
+  std::map<int32_t, std::set<int32_t>> spdetMap;
+  for (uint32_t i = 0; i < length; ++i) {
+    auto specNo = spec[i];
+    auto detId = udet[i];
+    auto search = spdetMap.find(specNo);
+    if (search != spdetMap.end()) {
+      search->second.insert(detId);
+    } else {
+      spdetMap.insert({specNo, {detId}});
+    }
+  }
+
+  assert(nspectra == spdetMap.size());
+
+  return spdetMap;
+}
+
+void IKafkaStreamDecoder::checkRunMessage(
+    const std::string &buffer, bool &checkOffsets,
+    std::unordered_map<std::string, std::vector<int64_t>> &stopOffsets,
+    std::unordered_map<std::string, std::vector<bool>> &reachedEnd) {
+  if (flatbuffers::BufferHasIdentifier(
+          reinterpret_cast<const uint8_t *>(buffer.c_str()),
+          RUN_MESSAGE_ID.c_str())) {
+    auto runMsg = GetRunInfo(reinterpret_cast<const uint8_t *>(buffer.c_str()));
+    if (!checkOffsets && runMsg->info_type_type() == InfoTypes_RunStop) {
+      auto runStopMsg = static_cast<const RunStop *>(runMsg->info_type());
+      auto stopTime = runStopMsg->stop_time();
+      g_log.debug() << "Received an end-of-run message with stop time = "
+                    << stopTime << std::endl;
+      stopOffsets = getStopOffsets(stopOffsets, reachedEnd, stopTime);
+      checkOffsets = true;
+      checkIfAllStopOffsetsReached(reachedEnd, checkOffsets);
+    }
+  }
+}
+
+void IKafkaStreamDecoder::checkRunEnd(
+    const std::string &topicName, bool &checkOffsets, const int64_t offset,
+    const int32_t partition,
+    std::unordered_map<std::string, std::vector<int64_t>> &stopOffsets,
+    std::unordered_map<std::string, std::vector<bool>> &reachedEnd) {
+  if (reachedEnd.count(topicName) &&
+      offset >= stopOffsets[topicName][static_cast<size_t>(partition)]) {
+
+    reachedEnd[topicName][static_cast<size_t>(partition)] = true;
+
+    if (offset == stopOffsets[topicName][static_cast<size_t>(partition)]) {
+      g_log.debug() << "Reached end-of-run in " << topicName << " topic."
+                    << std::endl;
+      g_log.debug() << "topic: " << topicName << " offset: " << offset
+                    << " stopOffset: "
+                    << stopOffsets[topicName][static_cast<size_t>(partition)]
+                    << std::endl;
+    }
+    checkIfAllStopOffsetsReached(reachedEnd, checkOffsets);
+  }
+}
+
+} // namespace LiveData
+
+} // namespace Mantid
diff --git a/Framework/LiveData/src/Kafka/KafkaEventStreamDecoder.cpp b/Framework/LiveData/src/Kafka/KafkaEventStreamDecoder.cpp
index bdf5a0145ef..9bc1a458be7 100644
--- a/Framework/LiveData/src/Kafka/KafkaEventStreamDecoder.cpp
+++ b/Framework/LiveData/src/Kafka/KafkaEventStreamDecoder.cpp
@@ -29,6 +29,7 @@ GNU_DIAG_OFF("conversion")
 GNU_DIAG_ON("conversion")
 
 using namespace Mantid::Types;
+using namespace LogSchema;
 
 namespace {
 /// Logger
@@ -43,8 +44,6 @@ const std::string RUN_MESSAGE_ID = "ba57";
 const std::string EVENT_MESSAGE_ID = "ev42";
 const std::string SAMPLE_MESSAGE_ID = "f142";
 
-const std::chrono::seconds MAX_LATENCY(1);
-
 /**
  * Append sample log data to existing log or create a new log if one with
  * specified name does not already exist
@@ -88,88 +87,14 @@ KafkaEventStreamDecoder::KafkaEventStreamDecoder(
     std::shared_ptr<IKafkaBroker> broker, const std::string &eventTopic,
     const std::string &runInfoTopic, const std::string &spDetTopic,
     const std::string &sampleEnvTopic)
-    : m_broker(broker), m_eventTopic(eventTopic), m_runInfoTopic(runInfoTopic),
-      m_spDetTopic(spDetTopic), m_sampleEnvTopic(sampleEnvTopic),
-      m_interrupt(false), m_localEvents(), m_specToIdx(), m_runStart(),
-      m_runNumber(-1), m_thread(), m_capturing(false), m_exception(),
-      m_extractWaiting(false), m_cbIterationEnd([] {}), m_cbError([] {}) {}
+    : IKafkaStreamDecoder(broker, eventTopic, runInfoTopic, spDetTopic,
+                          sampleEnvTopic) {}
 
 /**
  * Destructor.
  * Stops capturing from the stream
  */
-KafkaEventStreamDecoder::~KafkaEventStreamDecoder() { stopCapture(); }
-
-/**
- * Start capturing from the stream on a separate thread. This is a non-blocking
- * call and will return after the thread has started
- */
-void KafkaEventStreamDecoder::startCapture(bool startNow) {
-
-  // If we are not starting now, then we want to start at the start of the run
-  if (!startNow) {
-    // Get last two messages in run topic to ensure we get a runStart message
-    m_runStream =
-        m_broker->subscribe({m_runInfoTopic}, SubscribeAtOption::LASTTWO);
-    std::string rawMsgBuffer;
-    auto runStartData = getRunStartMessage(rawMsgBuffer);
-    joinEventStreamAtTime(runStartData);
-  } else {
-    m_eventStream =
-        m_broker->subscribe({m_eventTopic, m_runInfoTopic, m_sampleEnvTopic},
-                            SubscribeAtOption::LATEST);
-  }
-
-  // Get last two messages in run topic to ensure we get a runStart message
-  m_runStream =
-      m_broker->subscribe({m_runInfoTopic}, SubscribeAtOption::LASTTWO);
-  m_spDetStream =
-      m_broker->subscribe({m_spDetTopic}, SubscribeAtOption::LASTONE);
-
-  m_thread = std::thread([this]() { this->captureImpl(); });
-  m_thread.detach();
-}
-
-/** Indicate if the next data to be extracted should replace LoadLiveData's
- * output workspace,
- *  for example the first data of a new run
- */
-bool KafkaEventStreamDecoder::dataReset() {
-  bool result = (m_dataReset == true); // copy from atomic bool
-  m_dataReset = false;                 // reset to false
-  return result;
-}
-
-void KafkaEventStreamDecoder::joinEventStreamAtTime(
-    const KafkaEventStreamDecoder::RunStartStruct &runStartData) {
-  auto runStartTime = runStartData.startTime;
-  int64_t startTimeMilliseconds = nanosecondsToMilliseconds(runStartTime);
-  m_eventStream =
-      m_broker->subscribe({m_eventTopic, m_runInfoTopic, m_sampleEnvTopic},
-                          startTimeMilliseconds, SubscribeAtOption::TIME);
-  // make sure we listen to the run start topic starting from the run start
-  // message we already got the start time from
-  m_eventStream->seek(m_runInfoTopic, 0, runStartData.runStartMsgOffset);
-}
-
-int64_t KafkaEventStreamDecoder::nanosecondsToMilliseconds(
-    uint64_t timeNanoseconds) const {
-  return static_cast<int64_t>(timeNanoseconds / 1000000);
-}
-
-/**
- * Stop capturing from the stream. This is a blocking call until the capturing
- * function has completed
- */
-void KafkaEventStreamDecoder::stopCapture() noexcept {
-  // This will interrupt the "event" loop
-  m_interrupt = true;
-  // Wait until the function has completed. The background thread
-  // will exit automatically
-  while (m_capturing) {
-    std::this_thread::sleep_for(std::chrono::milliseconds(50));
-  };
-}
+KafkaEventStreamDecoder::~KafkaEventStreamDecoder() {}
 
 /**
  * Check if there is data available to extract
@@ -200,29 +125,6 @@ bool KafkaEventStreamDecoder::hasReachedEndOfRun() noexcept {
   return false;
 }
 
-/**
- * Check for an exception thrown by the background thread and rethrow
- * it if necessary. If no error occurred swap the current internal buffer
- * for a fresh one and return the old buffer.
- * @return A pointer to the data collected since the last call to this
- * method
- */
-API::Workspace_sptr KafkaEventStreamDecoder::extractData() {
-  if (m_exception) {
-    throw std::runtime_error(*m_exception);
-  }
-
-  m_extractWaiting = true;
-  m_cv.notify_one();
-
-  auto workspace_ptr = extractDataImpl();
-
-  m_extractWaiting = false;
-  m_cv.notify_one();
-
-  return workspace_ptr;
-}
-
 // -----------------------------------------------------------------------------
 // Private members
 // -----------------------------------------------------------------------------
@@ -230,14 +132,16 @@ API::Workspace_sptr KafkaEventStreamDecoder::extractData() {
 API::Workspace_sptr KafkaEventStreamDecoder::extractDataImpl() {
   std::lock_guard<std::mutex> lock(m_mutex);
   if (m_localEvents.size() == 1) {
-    auto temp = createBufferWorkspace(m_localEvents.front());
+    auto temp = createBufferWorkspace<DataObjects::EventWorkspace>(
+        "EventWorkspace", m_localEvents.front());
     std::swap(m_localEvents.front(), temp);
     return temp;
   } else if (m_localEvents.size() > 1) {
     auto group = boost::make_shared<API::WorkspaceGroup>();
     size_t index(0);
     for (auto &filledBuffer : m_localEvents) {
-      auto temp = createBufferWorkspace(filledBuffer);
+      auto temp = createBufferWorkspace<DataObjects::EventWorkspace>(
+          "EventWorkspace", filledBuffer);
       std::swap(m_localEvents[index++], temp);
       group->addWorkspace(temp);
     }
@@ -247,26 +151,6 @@ API::Workspace_sptr KafkaEventStreamDecoder::extractDataImpl() {
   }
 }
 
-/**
- * Start decoding data from the streams into the internal buffers.
- * Implementation designed to be entry point for new thread of execution.
- * It catches all thrown exceptions.
- */
-void KafkaEventStreamDecoder::captureImpl() noexcept {
-  m_capturing = true;
-  try {
-    captureImplExcept();
-  } catch (std::exception &exc) {
-    m_cbError();
-    m_exception = boost::make_shared<std::runtime_error>(exc.what());
-  } catch (...) {
-    m_cbError();
-    m_exception = boost::make_shared<std::runtime_error>(
-        "KafkaEventStreamDecoder: Unknown exception type caught.");
-  }
-  m_capturing = false;
-}
-
 /**
  * Exception-throwing variant of captureImpl(). Do not call this directly
  */
@@ -302,7 +186,7 @@ void KafkaEventStreamDecoder::captureImplExcept() {
       waitForDataExtraction();
     }
     // Pull in events
-    m_eventStream->consumeMessage(&buffer, offset, partition, topicName);
+    m_dataStream->consumeMessage(&buffer, offset, partition, topicName);
     // No events, wait for some to come along...
     if (buffer.empty()) {
       m_cbIterationEnd();
@@ -310,28 +194,13 @@ void KafkaEventStreamDecoder::captureImplExcept() {
     }
 
     if (checkOffsets) {
-      if (reachedEnd.count(topicName) &&
-          offset >= stopOffsets[topicName][static_cast<size_t>(partition)]) {
-
-        reachedEnd[topicName][static_cast<size_t>(partition)] = true;
-
-        if (offset == stopOffsets[topicName][static_cast<size_t>(partition)]) {
-          g_log.debug() << "Reached end-of-run in " << topicName << " topic."
-                        << std::endl;
-          g_log.debug()
-              << "topic: " << topicName << " offset: " << offset
-              << " stopOffset: "
-              << stopOffsets[topicName][static_cast<size_t>(partition)]
-              << std::endl;
-        }
-        checkIfAllStopOffsetsReached(reachedEnd, checkOffsets);
-
-        if (offset > stopOffsets[topicName][static_cast<size_t>(partition)]) {
-          // If the offset is beyond the end of the current run, then skip to
-          // the next iteration and don't process the message
-          m_cbIterationEnd();
-          continue;
-        }
+      checkRunEnd(topicName, checkOffsets, offset, partition, stopOffsets,
+                  reachedEnd);
+      if (offset > stopOffsets[topicName][static_cast<size_t>(partition)]) {
+        // If the offset is beyond the end of the current run, then skip to
+        // the next iteration and don't process the message
+        m_cbIterationEnd();
+        continue;
       }
     }
 
@@ -349,225 +218,51 @@ void KafkaEventStreamDecoder::captureImplExcept() {
       sampleDataFromMessage(buffer);
     }
     // Check if we have a runMessage
-    else if (flatbuffers::BufferHasIdentifier(
-                 reinterpret_cast<const uint8_t *>(buffer.c_str()),
-                 RUN_MESSAGE_ID.c_str())) {
-      auto runMsg =
-          GetRunInfo(reinterpret_cast<const uint8_t *>(buffer.c_str()));
-      if (!checkOffsets && runMsg->info_type_type() == InfoTypes_RunStop) {
-        auto runStopMsg = static_cast<const RunStop *>(runMsg->info_type());
-        auto stopTime = runStopMsg->stop_time();
-        g_log.debug() << "Received an end-of-run message with stop time = "
-                      << stopTime << std::endl;
-        stopOffsets = getStopOffsets(stopOffsets, reachedEnd, stopTime);
-        checkOffsets = true;
-        checkIfAllStopOffsetsReached(reachedEnd, checkOffsets);
-      }
-    }
+    else
+      checkRunMessage(buffer, checkOffsets, stopOffsets, reachedEnd);
     m_cbIterationEnd();
   }
   g_log.debug("Event capture finished");
 }
 
-/**
- * Check if we've reached the stop offset on every partition of every topic
- *
- * @param reachedEnd : Bool for each topic and partition to mark when stop
- * offset reached
- */
-void KafkaEventStreamDecoder::checkIfAllStopOffsetsReached(
-    const std::unordered_map<std::string, std::vector<bool>> &reachedEnd,
-    bool &checkOffsets) {
-
-  if (std::all_of(reachedEnd.cbegin(), reachedEnd.cend(),
-                  [](std::pair<std::string, std::vector<bool>> kv) {
-                    return std::all_of(
-                        kv.second.cbegin(), kv.second.cend(),
-                        [](bool partitionEnd) { return partitionEnd; });
-                  }) ||
-      reachedEnd.empty()) {
-    m_endRun = true;
-    // If we've reached the end of a run then set m_extractWaiting to true
-    // so that we wait until the buffer is emptied before continuing.
-    // Otherwise we can end up with data from two different runs in the
-    // same buffer workspace which is problematic if the user wanted the
-    // "Stop" or "Rename" run transition option.
-    m_extractedEndRunData = false;
-    checkOffsets = false;
-    g_log.notice("Reached end of run in data streams.");
-  }
-}
-
-std::unordered_map<std::string, std::vector<int64_t>>
-KafkaEventStreamDecoder::getStopOffsets(
-    std::unordered_map<std::string, std::vector<int64_t>> &stopOffsets,
-    std::unordered_map<std::string, std::vector<bool>> &reachedEnd,
-    uint64_t stopTime) const {
-  reachedEnd.clear();
-  stopOffsets.clear();
-  // Wait for max latency so that we don't miss any late messages
-  std::this_thread::sleep_for(MAX_LATENCY);
-  stopOffsets = m_eventStream->getOffsetsForTimestamp(
-      static_cast<int64_t>(stopTime / 1000000));
-  // /1000000 to convert nanosecond precision from message to millisecond
-  // precision which Kafka offset query supports
-
-  auto currentOffsets = m_eventStream->getCurrentOffsets();
-
-  // Set reachedEnd to false for each topic and partition
-  for (auto &topicOffsets : stopOffsets) {
-    auto topicName = topicOffsets.first;
-    // Ignore the runInfo topic
-    if (topicName.substr(topicName.length() -
-                         KafkaTopicSubscriber::RUN_TOPIC_SUFFIX.length()) !=
-        KafkaTopicSubscriber::RUN_TOPIC_SUFFIX) {
-      g_log.debug() << "TOPIC: " << topicName
-                    << " PARTITIONS: " << topicOffsets.second.size()
-                    << std::endl;
-      reachedEnd.insert(
-          {topicName, std::vector<bool>(topicOffsets.second.size(), false)});
-
-      auto &partitionOffsets = topicOffsets.second;
-      for (uint32_t partitionNumber = 0;
-           partitionNumber < partitionOffsets.size(); partitionNumber++) {
-        auto offset = partitionOffsets[partitionNumber];
-        // If the stop offset is negative then there are no messages for us
-        // to collect on this topic, so mark reachedEnd as true already
-        reachedEnd[topicName][partitionNumber] = offset < 0;
-        // If the stop offset has already been reached then mark reachedEnd as
-        // true
-        if (currentOffsets[topicName][partitionNumber] >= offset)
-          reachedEnd[topicName][partitionNumber] = true;
-      }
-    }
-  }
-  return stopOffsets;
-}
-
-/**
- * If extractData method is waiting for access to the buffer workspace
- * then we wait for it to finish
- */
-void KafkaEventStreamDecoder::waitForDataExtraction() {
-  {
-    std::unique_lock<std::mutex> readyLock(m_waitMutex);
-    m_cv.wait(readyLock, [&] { return !m_extractWaiting; });
-  }
-}
+void KafkaEventStreamDecoder::eventDataFromMessage(const std::string &buffer) {
+  auto eventMsg =
+      GetEventMessage(reinterpret_cast<const uint8_t *>(buffer.c_str()));
 
-void KafkaEventStreamDecoder::waitForRunEndObservation() {
-  m_extractWaiting = true;
-  // Mark extractedEndRunData true before waiting on the extraction to ensure
-  // an immediate request for run status after extracting the data will return
-  // the correct value - avoids race condition in MonitorLiveData and tests
-  m_extractedEndRunData = true;
-  waitForDataExtraction();
-
-  // Wait until MonitorLiveData has seen that end of run was
-  // reached before setting m_endRun back to false and continuing
-  std::unique_lock<std::mutex> runStatusLock(m_runStatusMutex);
-  m_cvRunStatus.wait(runStatusLock, [&] { return m_runStatusSeen; });
-  m_endRun = false;
-  m_runStatusSeen = false;
-  runStatusLock.unlock();
-
-  // Set to zero until we have the new run number, MonitorLiveData will
-  // queries before each time it extracts data until it gets non-zero
-  m_runNumber = 0;
-
-  // Get new run message now so that new run number is available for
-  // MonitorLiveData as early as possible
-  RunStartStruct runStartStruct;
-  if (waitForNewRunStartMessage(runStartStruct))
-    return;
-
-  // Give time for MonitorLiveData to act on runStatus information
-  // and trigger m_interrupt for next loop iteration if user requested
-  // LiveData algorithm to stop at the end of the run
-  std::this_thread::sleep_for(std::chrono::milliseconds(100));
-  if (m_interrupt)
-    return;
-
-  // Rejoin event stream at start of new run
-  joinEventStreamAtTime(runStartStruct);
-  std::string detSpecMapMsgBuffer = getDetSpecMapForRun(runStartStruct);
-  initLocalCaches(detSpecMapMsgBuffer, runStartStruct);
-}
+  DateAndTime pulseTime = static_cast<int64_t>(eventMsg->pulse_time());
+  const auto &tofData = *(eventMsg->time_of_flight());
+  const auto &detData = *(eventMsg->detector_id());
+  auto nEvents = tofData.size();
 
-/**
- * Try to find a detector-spectrum map message published after the
- * current run start time
- *
- * @param runStartStruct details of the current run
- * @return received detector-spectrum map message buffer
- */
-std::string KafkaEventStreamDecoder::getDetSpecMapForRun(
-    const KafkaEventStreamDecoder::RunStartStruct &runStartStruct) {
-  std::string rawMsgBuffer;
-  int64_t offset;
-  int32_t partition;
-  std::string topicName;
-  m_spDetStream = m_broker->subscribe(
-      {m_spDetTopic}, nanosecondsToMilliseconds(runStartStruct.startTime),
-      SubscribeAtOption::TIME);
-  m_spDetStream->consumeMessage(&rawMsgBuffer, offset, partition, topicName);
-  if (rawMsgBuffer.empty()) {
-    std::runtime_error(
-        "No detector-spectrum map message found for run number " +
-        std::to_string(runStartStruct.runNumber));
+  DataObjects::EventWorkspace_sptr periodBuffer;
+  std::lock_guard<std::mutex> lock(m_mutex);
+  if (eventMsg->facility_specific_data_type() == FacilityData_ISISData) {
+    auto ISISMsg =
+        static_cast<const ISISData *>(eventMsg->facility_specific_data());
+    periodBuffer = m_localEvents[static_cast<size_t>(ISISMsg->period_number())];
+    auto &mutableRunInfo = periodBuffer->mutableRun();
+    mutableRunInfo.getTimeSeriesProperty<double>(PROTON_CHARGE_PROPERTY)
+        ->addValue(pulseTime, ISISMsg->proton_charge());
+  } else {
+    periodBuffer = m_localEvents[0];
   }
-  return rawMsgBuffer;
-}
-
-/**
- * Wait for a run start message until we get one with a higher run number
- * than the current run or the algorithm is interrupted
- *
- * @param runStartStructOutput details of the new run
- * @return true if interrupted, false if got a new run start message
- */
-bool KafkaEventStreamDecoder::waitForNewRunStartMessage(
-    RunStartStruct &runStartStructOutput) {
-  while (!m_interrupt) {
-    std::string runMsgBuffer;
-
-    int64_t offset;
-    int32_t partition;
-    std::string topicName;
-    m_runStream->consumeMessage(&runMsgBuffer, offset, partition, topicName);
-    if (runMsgBuffer.empty()) {
-      continue; // no message available, try again
-    } else {
-      auto runMsg =
-          GetRunInfo(reinterpret_cast<const uint8_t *>(runMsgBuffer.c_str()));
-      if (runMsg->info_type_type() == InfoTypes_RunStart) {
-        // We got a run start message, deserialise it
-        auto runStartData = static_cast<const RunStart *>(runMsg->info_type());
-        KafkaEventStreamDecoder::RunStartStruct runStartStruct = {
-            runStartData->instrument_name()->str(), runStartData->run_number(),
-            runStartData->start_time(),
-            static_cast<size_t>(runStartData->n_periods()), offset};
-        if (runStartStruct.runNumber > m_runNumber) {
-          runStartStructOutput = runStartStruct;
-          m_runNumber = runStartStruct.runNumber;
-          return false; // not interrupted
-        }
-      } else {
-        continue; // received message wasn't a RunStart message, try again
-      }
-    }
+  for (decltype(nEvents) i = 0; i < nEvents; ++i) {
+    auto &spectrum = periodBuffer->getSpectrum(
+        m_specToIdx[static_cast<int32_t>(detData[i])]);
+    spectrum.addEventQuickly(TofEvent(static_cast<double>(tofData[i]) *
+                                          1e-3, // nanoseconds to microseconds
+                                      pulseTime));
   }
-  return true; // interrupted
 }
 
 /**
- * Get sample environment log data from the flatbuffer and append it to the
- * workspace
- *
- * @param seData : flatbuffer offset of the sample environment log data
- * @param nSEEvents : number of sample environment log values in the flatbuffer
- * @param mutableRunInfo : Log manager containing the existing sample logs
- */
+* Get sample environment log data from the flatbuffer and append it to the
+* workspace
+*
+* @param seData : flatbuffer offset of the sample environment log data
+* @param nSEEvents : number of sample environment log values in the flatbuffer
+* @param mutableRunInfo : Log manager containing the existing sample logs
+*/
 void KafkaEventStreamDecoder::sampleDataFromMessage(const std::string &buffer) {
 
   std::lock_guard<std::mutex> lock(m_mutex);
@@ -608,60 +303,6 @@ void KafkaEventStreamDecoder::sampleDataFromMessage(const std::string &buffer) {
   }
 }
 
-void KafkaEventStreamDecoder::eventDataFromMessage(const std::string &buffer) {
-  auto eventMsg =
-      GetEventMessage(reinterpret_cast<const uint8_t *>(buffer.c_str()));
-
-  DateAndTime pulseTime = static_cast<int64_t>(eventMsg->pulse_time());
-  const auto &tofData = *(eventMsg->time_of_flight());
-  const auto &detData = *(eventMsg->detector_id());
-  auto nEvents = tofData.size();
-
-  DataObjects::EventWorkspace_sptr periodBuffer;
-  std::lock_guard<std::mutex> lock(m_mutex);
-  if (eventMsg->facility_specific_data_type() == FacilityData_ISISData) {
-    auto ISISMsg =
-        static_cast<const ISISData *>(eventMsg->facility_specific_data());
-    periodBuffer = m_localEvents[static_cast<size_t>(ISISMsg->period_number())];
-    auto &mutableRunInfo = periodBuffer->mutableRun();
-    mutableRunInfo.getTimeSeriesProperty<double>(PROTON_CHARGE_PROPERTY)
-        ->addValue(pulseTime, ISISMsg->proton_charge());
-  } else {
-    periodBuffer = m_localEvents[0];
-  }
-  for (decltype(nEvents) i = 0; i < nEvents; ++i) {
-    auto &spectrum = periodBuffer->getSpectrum(
-        m_specToIdx[static_cast<int32_t>(detData[i])]);
-    spectrum.addEventQuickly(TofEvent(static_cast<double>(tofData[i]) *
-                                          1e-3, // nanoseconds to microseconds
-                                      pulseTime));
-  }
-}
-
-KafkaEventStreamDecoder::RunStartStruct
-KafkaEventStreamDecoder::getRunStartMessage(std::string &rawMsgBuffer) {
-  auto offset = getRunInfoMessage(rawMsgBuffer);
-  auto runMsg =
-      GetRunInfo(reinterpret_cast<const uint8_t *>(rawMsgBuffer.c_str()));
-  if (runMsg->info_type_type() != InfoTypes_RunStart) {
-    // We want a runStart message, try the next one
-    offset = getRunInfoMessage(rawMsgBuffer);
-    runMsg =
-        GetRunInfo(reinterpret_cast<const uint8_t *>(rawMsgBuffer.c_str()));
-    if (runMsg->info_type_type() != InfoTypes_RunStart) {
-      throw std::runtime_error("KafkaEventStreamDecoder::initLocalCaches() - "
-                               "Could not find a run start message"
-                               "in the run info topic. Unable to continue");
-    }
-  }
-  auto runStartData = static_cast<const RunStart *>(runMsg->info_type());
-  KafkaEventStreamDecoder::RunStartStruct runStart = {
-      runStartData->instrument_name()->str(), runStartData->run_number(),
-      runStartData->start_time(),
-      static_cast<size_t>(runStartData->n_periods()), offset};
-  return runStart;
-}
-
 /**
  * Pull information from the run & detector-spectrum stream and initialize
  * the internal EventWorkspace buffer + other cached information such as run
@@ -693,14 +334,14 @@ void KafkaEventStreamDecoder::initLocalCaches(
   m_runNumber = runStartData.runNumber;
 
   // Create buffer
-  auto eventBuffer = createBufferWorkspace(
-      static_cast<size_t>(spDetMsg->n_spectra()), spDetMsg->spectrum()->data(),
-      spDetMsg->detector_id()->data(), nudet);
+  auto eventBuffer = createBufferWorkspace<DataObjects::EventWorkspace>(
+      "EventWorkspace", static_cast<size_t>(spDetMsg->n_spectra()),
+      spDetMsg->spectrum()->data(), spDetMsg->detector_id()->data(), nudet);
 
   // Load the instrument if possible but continue if we can't
   auto instName = runStartData.instrumentName;
   if (!instName.empty())
-    loadInstrument(instName, eventBuffer);
+    loadInstrument<DataObjects::EventWorkspace>(instName, eventBuffer);
   else
     g_log.warning(
         "Empty instrument name received. Continuing without instrument");
@@ -743,120 +384,7 @@ void KafkaEventStreamDecoder::initLocalCaches(
   m_dataReset = true;
 }
 
-/**
- * Try to get a runInfo message from Kafka, throw error if it fails
- * @param rawMsgBuffer : string to use as message buffer
- */
-int64_t KafkaEventStreamDecoder::getRunInfoMessage(std::string &rawMsgBuffer) {
-  int64_t offset;
-  int32_t partition;
-  std::string topicName;
-  m_runStream->consumeMessage(&rawMsgBuffer, offset, partition, topicName);
-  if (rawMsgBuffer.empty()) {
-    throw std::runtime_error("KafkaEventStreamDecoder::getRunInfoMessage() - "
-                             "Empty message received from run info "
-                             "topic. Unable to continue");
-  }
-  if (!flatbuffers::BufferHasIdentifier(
-          reinterpret_cast<const uint8_t *>(rawMsgBuffer.c_str()),
-          RUN_MESSAGE_ID.c_str())) {
-    throw std::runtime_error("KafkaEventStreamDecoder::getRunInfoMessage() - "
-                             "Received unexpected message type from run info "
-                             "topic. Unable to continue");
-  }
-  return offset;
-}
-
-/**
- * Create a buffer workspace of the correct size based on the values given.
- * @param nspectra The number of unique spectrum numbers
- * @param spec An array of length ndet specifying the spectrum number of each
- * detector
- * @param udet An array of length ndet specifying the detector ID of each
- * detector
- * @param length The length of the spec/udet arrays
- * @return A new workspace of the appropriate size
- */
-DataObjects::EventWorkspace_sptr KafkaEventStreamDecoder::createBufferWorkspace(
-    const size_t nspectra, const int32_t *spec, const int32_t *udet,
-    const uint32_t length) {
-  // Order is important here
-  std::map<int32_t, std::set<int32_t>> spdetMap;
-  for (uint32_t i = 0; i < length; ++i) {
-    auto specNo = spec[i];
-    auto detId = udet[i];
-    auto search = spdetMap.find(specNo);
-    if (search != spdetMap.end()) {
-      search->second.insert(detId);
-    } else {
-      spdetMap.insert({specNo, {detId}});
-    }
-  }
-  assert(nspectra == spdetMap.size());
-
-  // Create event workspace
-  auto eventBuffer = boost::static_pointer_cast<DataObjects::EventWorkspace>(
-      API::WorkspaceFactory::Instance().create("EventWorkspace", nspectra, 2,
-                                               1));
-  // Set the units
-  eventBuffer->getAxis(0)->unit() =
-      Kernel::UnitFactory::Instance().create("TOF");
-  eventBuffer->setYUnit("Counts");
-  // Setup spectra-detector mapping.
-  size_t wsIdx(0);
-  for (const auto &spIter : spdetMap) {
-    auto &spectrum = eventBuffer->getSpectrum(wsIdx);
-    spectrum.setSpectrumNo(spIter.first);
-    spectrum.addDetectorIDs(spIter.second);
-    ++wsIdx;
-  }
-  return eventBuffer;
-}
-
-/**
- * Create new buffer workspace from an existing copy
- * @param parent A pointer to an existing workspace
- */
-DataObjects::EventWorkspace_sptr KafkaEventStreamDecoder::createBufferWorkspace(
-    const DataObjects::EventWorkspace_sptr &parent) {
-  auto buffer = boost::static_pointer_cast<DataObjects::EventWorkspace>(
-      API::WorkspaceFactory::Instance().create(
-          "EventWorkspace", parent->getNumberHistograms(), 2, 1));
-  // Copy meta data
-  API::WorkspaceFactory::Instance().initializeFromParent(*parent, *buffer,
-                                                         false);
-  // Clear out the old logs, except for the most recent entry
-  buffer->mutableRun().clearOutdatedTimeSeriesLogValues();
-  return buffer;
-}
 
-/**
- * Run LoadInstrument for the given instrument name. If it cannot succeed it
- * does nothing to the internal workspace
- * @param name Name of an instrument to load
- * @param workspace A pointer to the workspace receiving the instrument
- */
-void KafkaEventStreamDecoder::loadInstrument(
-    const std::string &name, DataObjects::EventWorkspace_sptr workspace) {
-  if (name.empty()) {
-    g_log.warning("Empty instrument name found");
-    return;
-  }
-  try {
-    auto alg =
-        API::AlgorithmManager::Instance().createUnmanaged("LoadInstrument");
-    // Do not put the workspace in the ADS
-    alg->setChild(true);
-    alg->initialize();
-    alg->setPropertyValue("InstrumentName", name);
-    alg->setProperty("Workspace", workspace);
-    alg->setProperty("RewriteSpectraMap", Kernel::OptionalBool(false));
-    alg->execute();
-  } catch (std::exception &exc) {
-    g_log.warning() << "Error loading instrument '" << name
-                    << "': " << exc.what() << "\n";
-  }
-}
 } // namespace LiveData
 
 } // namespace Mantid
diff --git a/Framework/LiveData/src/Kafka/KafkaHistoListener.cpp b/Framework/LiveData/src/Kafka/KafkaHistoListener.cpp
index b7f3d5ed22f..aaf35a39928 100644
--- a/Framework/LiveData/src/Kafka/KafkaHistoListener.cpp
+++ b/Framework/LiveData/src/Kafka/KafkaHistoListener.cpp
@@ -25,14 +25,37 @@ KafkaHistoListener::KafkaHistoListener() {
   declareProperty("InstrumentName", "");
 }
 
+void KafkaHistoListener::setAlgorithm(
+    const Mantid::API::IAlgorithm &callingAlgorithm) {
+  this->updatePropertyValues(callingAlgorithm);
+  // Get the instrument name from StartLiveData so we can sub to correct topics
+  if (callingAlgorithm.existsProperty("Instrument")) {
+    m_instrumentName = callingAlgorithm.getPropertyValue("Instrument");
+  } else {
+    g_log.error("KafkaEventListener requires Instrument property to be set in "
+                "calling algorithm");
+  }
+}
+
 /// @copydoc ILiveListener::connect
 bool KafkaHistoListener::connect(const Poco::Net::SocketAddress &address) {
+  if (m_instrumentName.empty()) {
+    g_log.error(
+        "KafkaHistoListener::connect requires a non-empty instrument name");
+  }
+
   try {
-    std::string instrumentName = getProperty("InstrumentName");
-    const std::string histoTopic(instrumentName +
-                                 KafkaTopicSubscriber::HISTO_TOPIC_SUFFIX);
+    const std::string histoTopic(m_instrumentName +
+                                 KafkaTopicSubscriber::HISTO_TOPIC_SUFFIX),
+        runInfoTopic(m_instrumentName + KafkaTopicSubscriber::RUN_TOPIC_SUFFIX),
+        spDetInfoTopic(m_instrumentName +
+                       KafkaTopicSubscriber::DET_SPEC_TOPIC_SUFFIX),
+        sampleEnvTopic(m_instrumentName +
+                       KafkaTopicSubscriber::SAMPLE_ENV_TOPIC_SUFFIX);
+
     m_decoder = Kernel::make_unique<KafkaHistoStreamDecoder>(
-        address.toString(), histoTopic, instrumentName);
+        std::make_shared<KafkaBroker>(address.toString()), histoTopic,
+        runInfoTopic, spDetInfoTopic, sampleEnvTopic);
   } catch (std::exception &exc) {
     g_log.error() << "KafkaHistoListener::connect - Connection Error: "
                   << exc.what() << "\n";
diff --git a/Framework/LiveData/src/Kafka/KafkaHistoStreamDecoder.cpp b/Framework/LiveData/src/Kafka/KafkaHistoStreamDecoder.cpp
index d127e3d2575..d3bb4d20448 100644
--- a/Framework/LiveData/src/Kafka/KafkaHistoStreamDecoder.cpp
+++ b/Framework/LiveData/src/Kafka/KafkaHistoStreamDecoder.cpp
@@ -12,16 +12,25 @@
 #include "MantidDataObjects/WorkspaceCreation.h"
 #include "MantidGeometry/Instrument/DetectorInfo.h"
 #include "MantidHistogramData/BinEdges.h"
+#include "MantidIndexing/IndexInfo.h"
 #include "MantidKernel/Logger.h"
 #include "MantidKernel/OptionalBool.h"
+#include "MantidKernel/TimeSeriesProperty.h"
+#include "MantidKernel/UnitFactory.h"
 #include "MantidKernel/WarningSuppressions.h"
 #include "MantidLiveData/Exception.h"
 
 GNU_DIAG_OFF("conversion")
+#include "private/Schema/df12_det_spec_map_generated.h"
 #include "private/Schema/hs00_event_histogram_generated.h"
 GNU_DIAG_ON("conversion")
 
+using namespace HistoSchema;
+
 namespace {
+const std::string PROTON_CHARGE_PROPERTY = "proton_charge";
+const std::string RUN_NUMBER_PROPERTY = "run_number";
+const std::string RUN_START_PROPERTY = "run_start";
 /// Logger
 Mantid::Kernel::Logger g_log("KafkaHistoStreamDecoder");
 } // namespace
@@ -35,95 +44,41 @@ namespace LiveData {
 
 /**
  * Constructor
- * @param brokerAddress The physical ipAddress of the broker
+ * @param broker Kafka broker
  * @param histoTopic The name of the topic streaming the histo data
  * @param spDetTopic The name of the topic streaming the spectrum-detector
  * run mapping
  */
 KafkaHistoStreamDecoder::KafkaHistoStreamDecoder(
-    const std::string &brokerAddress, const std::string &histoTopic,
-    const std::string &instrumentName)
-    : m_broker(brokerAddress), m_histoTopic(histoTopic),
-      m_instrumentName(instrumentName), m_histoStream(), m_workspace(),
-      m_buffer(), m_thread(), m_interrupt(false), m_capturing(false),
-      m_exception(nullptr) {
-  if (histoTopic.empty())
-    throw std::invalid_argument(
-        "KafkaHistoStreamDecoder::KafkaHistoStreamDecorder "
-        ": histogramTopic cannot be an empty string.");
-  if (instrumentName.empty())
-    throw std::invalid_argument(
-        "KafkaHistoStreamDecoder::KafkaHistoStreamDecorder "
-        ": instrumentName cannot be an empty string.");
-  // Initialize buffer workspace
-  m_workspace = createBufferWorkspace();
-}
+    std::shared_ptr<IKafkaBroker> broker, const std::string &histoTopic,
+    const std::string &runInfoTopic, const std::string &spDetTopic,
+    const std::string &sampleEnvTopic)
+    : IKafkaStreamDecoder(broker, histoTopic, runInfoTopic, spDetTopic,
+                          sampleEnvTopic),
+      m_workspace() {}
 
 /**
  * Destructor.
  * Stops capturing from the stream
  */
-KafkaHistoStreamDecoder::~KafkaHistoStreamDecoder() { stopCapture(); }
-
-/**
- * Start capturing from the stream on a separate thread. This is a non-blocking
- * call and will return after the thread has started
- */
-void KafkaHistoStreamDecoder::startCapture(bool) {
-  g_log.debug() << "Starting capture on topic: " << m_histoTopic << "\n";
-  m_histoStream = m_broker.subscribe({m_histoTopic}, SubscribeAtOption::LATEST);
-
-  m_thread = std::thread([this]() { this->captureImpl(); });
-  m_thread.detach();
-}
-
-/**
- * Stop capturing from the stream. This is a blocking call until the capturing
- * function has completed
- */
-void KafkaHistoStreamDecoder::stopCapture() noexcept {
-  g_log.debug() << "Stopping capture\n";
-
-  // This will interrupt the "event" loop
-  m_interrupt = true;
-  // Wait until the function has completed. The background thread will exit
-  // automatically
-  while (m_capturing) {
-    std::this_thread::sleep_for(std::chrono::milliseconds(50));
-  };
-}
+KafkaHistoStreamDecoder::~KafkaHistoStreamDecoder() {}
 
 /**
  * Check if there is data available to extract
  * @return True if data has been accumulated so that extractData()
  * can be called, false otherwise
  */
-bool KafkaHistoStreamDecoder::hasData() const {
-  std::lock_guard<std::mutex> lock(m_buffer_mutex);
+bool KafkaHistoStreamDecoder::hasData() const noexcept {
+  std::lock_guard<std::mutex> lock(m_mutex);
   return !m_buffer.empty();
 }
 
-/**
- * Check for an exception thrown by the background thread and rethrow
- * it if necessary.
- * @return A pointer to the data collected since the last call to this
- * method
- */
-API::Workspace_sptr KafkaHistoStreamDecoder::extractData() {
-  if (m_exception) {
-    throw *m_exception;
-  }
-
-  auto workspace_ptr = extractDataImpl();
-  return workspace_ptr;
-}
-
 // -----------------------------------------------------------------------------
 // Private members
 // -----------------------------------------------------------------------------
 
 API::Workspace_sptr KafkaHistoStreamDecoder::extractDataImpl() {
-  std::lock_guard<std::mutex> lock(m_buffer_mutex);
+  std::lock_guard<std::mutex> lock(m_mutex);
 
   if (!m_capturing) {
     throw Exception::NotYet("Local buffers not initialized.");
@@ -169,78 +124,143 @@ API::Workspace_sptr KafkaHistoStreamDecoder::extractDataImpl() {
   return ws;
 }
 
-/**
- * Start decoding data from the streams into the internal buffers.
- * Implementation designed to be entry point for new thread of execution.
- * It catches all thrown exceptions.
- */
-void KafkaHistoStreamDecoder::captureImpl() {
-  m_capturing = true;
-  try {
-    captureImplExcept();
-  } catch (std::exception &exc) {
-    m_exception.reset(new std::runtime_error(exc.what()));
-  } catch (...) {
-    m_exception.reset(new std::runtime_error(
-        "KafkaEventStreamDecoder: Unknown exception type caught."));
-  }
-  m_capturing = false;
-}
-
 /**
  * Exception-throwing variant of captureImpl(). Do not call this directly
  */
 void KafkaHistoStreamDecoder::captureImplExcept() {
   g_log.information("Event capture starting");
 
-  m_interrupt = false;
+  m_interrupt = false; // Allow MonitorLiveData or user to interrupt
+  m_endRun = false;
+  m_runStatusSeen = false; // Flag to ensure MonitorLiveData observes end of run
   std::string buffer;
+  std::string runBuffer;
   int64_t offset;
   int32_t partition;
   std::string topicName;
+  auto runStartStruct = getRunStartMessage(runBuffer);
+  m_spDetStream->consumeMessage(&buffer, offset, partition, topicName);
+  initLocalCaches(buffer, runStartStruct);
 
-  while (!m_interrupt) {
-    // Pull in events
-    m_histoStream->consumeMessage(&buffer, offset, partition, topicName);
+  // Keep track of whether we've reached the end of a run
+  std::unordered_map<std::string, std::vector<int64_t>> stopOffsets;
+  std::unordered_map<std::string, std::vector<bool>> reachedEnd;
+  bool checkOffsets = false;
 
-    // No events, wait for some to come along...
-    if (buffer.empty()) {
-      std::this_thread::sleep_for(std::chrono::milliseconds(100));
+  while (!m_interrupt) {
+    if (m_endRun) {
+      waitForRunEndObservation();
       continue;
+    } else {
+      waitForDataExtraction();
     }
 
-    // Lock so we don't overwrite buffer while workspace is being extracted
     {
-      std::lock_guard<std::mutex> lock(m_buffer_mutex);
+      // Lock so we don't overwrite buffer while workspace is being extracted or
+      // try to access data before it is read.
+      std::lock_guard<std::mutex> lock(m_mutex);
+      // Pull in data
+      m_dataStream->consumeMessage(&buffer, offset, partition, topicName);
+
+      // No events, wait for some to come along...
+      if (buffer.empty()) {
+        std::this_thread::sleep_for(std::chrono::milliseconds(100));
+        m_cbIterationEnd();
+        continue;
+      }
+
+      if (checkOffsets) {
+        checkRunEnd(topicName, checkOffsets, offset, partition, stopOffsets,
+                    reachedEnd);
+        if (offset > stopOffsets[topicName][static_cast<size_t>(partition)]) {
+          // If the offset is beyond the end of the current run, then skip to
+          // the next iteration and don't process the message
+          m_cbIterationEnd();
+          continue;
+        }
+      }
+
+      // Data being accumulated before being streamed so no need to store
+      // messages.
       m_buffer = buffer;
     }
 
+    checkRunMessage(buffer, checkOffsets, stopOffsets, reachedEnd);
+
     std::this_thread::sleep_for(std::chrono::milliseconds(100));
+    m_cbIterationEnd();
   }
   g_log.debug("Histo capture finished");
 }
 
-DataObjects::Workspace2D_sptr KafkaHistoStreamDecoder::createBufferWorkspace() {
-  DataObjects::Workspace2D_sptr workspace;
-
-  try {
-    auto alg = API::AlgorithmManager::Instance().createUnmanaged(
-        "LoadEmptyInstrument");
-    // Do not put the workspace in the ADS
-    alg->setChild(true);
-    alg->initialize();
-    alg->setPropertyValue("InstrumentName", m_instrumentName);
-    // Dummy workspace value "ws" as not placed in ADS
-    alg->setPropertyValue("OutputWorkspace", "ws");
-    alg->execute();
-    workspace = alg->getProperty("OutputWorkspace");
-  } catch (std::exception &exc) {
-    g_log.error() << "Error loading empty instrument '" << m_instrumentName
-                  << "': " << exc.what() << "\n";
-    throw;
+void KafkaHistoStreamDecoder::initLocalCaches(
+    const std::string &rawMsgBuffer, const RunStartStruct &runStartData) {
+  if (rawMsgBuffer.empty()) {
+    throw std::runtime_error("KafkaEventStreamDecoder::initLocalCaches() - "
+                             "Empty message received from spectrum-detector "
+                             "topic. Unable to continue");
   }
+  auto spDetMsg = GetSpectraDetectorMapping(
+      reinterpret_cast<const uint8_t *>(rawMsgBuffer.c_str()));
+  auto nspec = static_cast<uint32_t>(spDetMsg->n_spectra());
+  auto nudet = spDetMsg->detector_id()->size();
+  if (nudet != nspec) {
+    std::ostringstream os;
+    os << "KafkaEventStreamDecoder::initLocalEventBuffer() - Invalid "
+          "spectra/detector mapping. Expected matched length arrays but "
+          "found nspec="
+       << nspec << ", ndet=" << nudet;
+    throw std::runtime_error(os.str());
+  }
+
+  m_runNumber = runStartData.runNumber;
+
+  // Create buffer
+  auto histoBuffer = createBufferWorkspace<DataObjects::Workspace2D>(
+      "Workspace2D", static_cast<size_t>(spDetMsg->n_spectra()),
+      spDetMsg->spectrum()->data(), spDetMsg->detector_id()->data(), nudet);
+
+  // Load the instrument if possible but continue if we can't
+  auto instName = runStartData.instrumentName;
+  if (!instName.empty())
+    loadInstrument<DataObjects::Workspace2D>(instName, histoBuffer);
+  else
+    g_log.warning(
+        "Empty instrument name received. Continuing without instrument");
+
+  auto &mutableRun = histoBuffer->mutableRun();
+  // Run start. Cache locally for computing frame times
+  // Convert nanoseconds to seconds (and discard the extra precision)
+  auto runStartTime = static_cast<time_t>(runStartData.startTime / 1000000000);
+  m_runStart.set_from_time_t(runStartTime);
+  auto timeString = m_runStart.toISO8601String();
+  // Run number
+  mutableRun.addProperty(RUN_START_PROPERTY, std::string(timeString));
+  mutableRun.addProperty(RUN_NUMBER_PROPERTY,
+                         std::to_string(runStartData.runNumber));
+  // Create the proton charge property
+  mutableRun.addProperty(
+      new Kernel::TimeSeriesProperty<double>(PROTON_CHARGE_PROPERTY));
+
+  // Cache spec->index mapping. We assume it is the same across all periods
+  m_specToIdx = histoBuffer->getSpectrumToWorkspaceIndexMap();
+
+  // Buffers for each period
+  const size_t nperiods = runStartData.nPeriods;
+  if (nperiods > 1) {
+    throw std::runtime_error(
+        "KafkaHistoStreamDecoder - Does not support multi-period data.");
+  }
+  // New caches so LoadLiveData's output workspace needs to be replaced
+  m_dataReset = true;
+
+  m_workspace = histoBuffer;
+}
 
-  return workspace;
+void KafkaHistoStreamDecoder::sampleDataFromMessage(const std::string &) {
+  throw Kernel::Exception::NotImplementedError("This method will require "
+                                               "implementation when processing "
+                                               "sample environment messages.");
 }
 
 } // namespace LiveData
diff --git a/Framework/LiveData/src/Kafka/private/Schema/f142_logdata_generated.h b/Framework/LiveData/src/Kafka/private/Schema/f142_logdata_generated.h
index 0f84e9cf09c..af688ca8a43 100644
--- a/Framework/LiveData/src/Kafka/private/Schema/f142_logdata_generated.h
+++ b/Framework/LiveData/src/Kafka/private/Schema/f142_logdata_generated.h
@@ -14,762 +14,765 @@
 
 #include "fwdi_forwarder_internal_generated.h"
 
-struct fwdinfo_1_t;
-
-
-struct Byte;
-struct UByte;
-struct Short;
-struct UShort;
-struct Int;
-struct UInt;
-struct Long;
-struct ULong;
-struct Float;
-struct Double;
-struct ArrayByte;
-struct ArrayUByte;
-struct ArrayShort;
-struct ArrayUShort;
-struct ArrayInt;
-struct ArrayUInt;
-struct ArrayLong;
-struct ArrayULong;
-struct ArrayFloat;
-struct ArrayDouble;
-struct LogData;
-
-enum Value {
-  Value_NONE = 0,
-  Value_Byte = 1,
-  Value_UByte = 2,
-  Value_Short = 3,
-  Value_UShort = 4,
-  Value_Int = 5,
-  Value_UInt = 6,
-  Value_Long = 7,
-  Value_ULong = 8,
-  Value_Float = 9,
-  Value_Double = 10,
-  Value_ArrayByte = 11,
-  Value_ArrayUByte = 12,
-  Value_ArrayShort = 13,
-  Value_ArrayUShort = 14,
-  Value_ArrayInt = 15,
-  Value_ArrayUInt = 16,
-  Value_ArrayLong = 17,
-  Value_ArrayULong = 18,
-  Value_ArrayFloat = 19,
-  Value_ArrayDouble = 20,
-  Value_MIN = Value_NONE,
-  Value_MAX = Value_ArrayDouble
-};
-
-inline const char **EnumNamesValue() {
-  static const char *names[] = { "NONE", "Byte", "UByte", "Short", "UShort", "Int", "UInt", "Long", "ULong", "Float", "Double", "ArrayByte", "ArrayUByte", "ArrayShort", "ArrayUShort", "ArrayInt", "ArrayUInt", "ArrayLong", "ArrayULong", "ArrayFloat", "ArrayDouble", nullptr };
-  return names;
-}
+/// Due to type conflicts with other schemas it was necessary to 
+/// add this namespace LogSchema. 
+namespace LogSchema {
+  struct fwdinfo_1_t;
+
+
+  struct Byte;
+  struct UByte;
+  struct Short;
+  struct UShort;
+  struct Int;
+  struct UInt;
+  struct Long;
+  struct ULong;
+  struct Float;
+  struct Double;
+  struct ArrayByte;
+  struct ArrayUByte;
+  struct ArrayShort;
+  struct ArrayUShort;
+  struct ArrayInt;
+  struct ArrayUInt;
+  struct ArrayLong;
+  struct ArrayULong;
+  struct ArrayFloat;
+  struct ArrayDouble;
+  struct LogData;
+
+  enum Value {
+    Value_NONE = 0,
+    Value_Byte = 1,
+    Value_UByte = 2,
+    Value_Short = 3,
+    Value_UShort = 4,
+    Value_Int = 5,
+    Value_UInt = 6,
+    Value_Long = 7,
+    Value_ULong = 8,
+    Value_Float = 9,
+    Value_Double = 10,
+    Value_ArrayByte = 11,
+    Value_ArrayUByte = 12,
+    Value_ArrayShort = 13,
+    Value_ArrayUShort = 14,
+    Value_ArrayInt = 15,
+    Value_ArrayUInt = 16,
+    Value_ArrayLong = 17,
+    Value_ArrayULong = 18,
+    Value_ArrayFloat = 19,
+    Value_ArrayDouble = 20,
+    Value_MIN = Value_NONE,
+    Value_MAX = Value_ArrayDouble
+  };
+
+  inline const char **EnumNamesValue() {
+    static const char *names[] = { "NONE", "Byte", "UByte", "Short", "UShort", "Int", "UInt", "Long", "ULong", "Float", "Double", "ArrayByte", "ArrayUByte", "ArrayShort", "ArrayUShort", "ArrayInt", "ArrayUInt", "ArrayLong", "ArrayULong", "ArrayFloat", "ArrayDouble", nullptr };
+    return names;
+  }
 
-inline const char *EnumNameValue(Value e) { return EnumNamesValue()[static_cast<int>(e)]; }
+  inline const char *EnumNameValue(Value e) { return EnumNamesValue()[static_cast<int>(e)]; }
 
-inline bool VerifyValue(flatbuffers::Verifier &verifier, const void *union_obj, Value type);
+  inline bool VerifyValue(flatbuffers::Verifier &verifier, const void *union_obj, Value type);
 
-struct Byte FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
-  enum {
-    VT_VALUE = 4
+  struct Byte FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+    enum {
+      VT_VALUE = 4
+    };
+    int8_t value() const { return GetField<int8_t>(VT_VALUE, 0); }
+    bool Verify(flatbuffers::Verifier &verifier) const {
+      return VerifyTableStart(verifier) &&
+        VerifyField<int8_t>(verifier, VT_VALUE) &&
+        verifier.EndTable();
+    }
   };
-  int8_t value() const { return GetField<int8_t>(VT_VALUE, 0); }
-  bool Verify(flatbuffers::Verifier &verifier) const {
-    return VerifyTableStart(verifier) &&
-           VerifyField<int8_t>(verifier, VT_VALUE) &&
-           verifier.EndTable();
-  }
-};
-
-struct ByteBuilder {
-  flatbuffers::FlatBufferBuilder &fbb_;
-  flatbuffers::uoffset_t start_;
-  void add_value(int8_t value) { fbb_.AddElement<int8_t>(Byte::VT_VALUE, value, 0); }
-  ByteBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
-  ByteBuilder &operator=(const ByteBuilder &);
-  flatbuffers::Offset<Byte> Finish() {
-    auto o = flatbuffers::Offset<Byte>(fbb_.EndTable(start_, 1));
-    return o;
-  }
-};
 
-inline flatbuffers::Offset<Byte> CreateByte(flatbuffers::FlatBufferBuilder &_fbb,
-   int8_t value = 0) {
-  ByteBuilder builder_(_fbb);
-  builder_.add_value(value);
-  return builder_.Finish();
-}
+  struct ByteBuilder {
+    flatbuffers::FlatBufferBuilder &fbb_;
+    flatbuffers::uoffset_t start_;
+    void add_value(int8_t value) { fbb_.AddElement<int8_t>(Byte::VT_VALUE, value, 0); }
+    ByteBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
+    ByteBuilder &operator=(const ByteBuilder &);
+    flatbuffers::Offset<Byte> Finish() {
+      auto o = flatbuffers::Offset<Byte>(fbb_.EndTable(start_, 1));
+      return o;
+    }
+  };
 
-struct UByte FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
-  enum {
-    VT_VALUE = 4
+  inline flatbuffers::Offset<Byte> CreateByte(flatbuffers::FlatBufferBuilder &_fbb,
+    int8_t value = 0) {
+    ByteBuilder builder_(_fbb);
+    builder_.add_value(value);
+    return builder_.Finish();
+  }
+
+  struct UByte FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+    enum {
+      VT_VALUE = 4
+    };
+    uint8_t value() const { return GetField<uint8_t>(VT_VALUE, 0); }
+    bool Verify(flatbuffers::Verifier &verifier) const {
+      return VerifyTableStart(verifier) &&
+        VerifyField<uint8_t>(verifier, VT_VALUE) &&
+        verifier.EndTable();
+    }
   };
-  uint8_t value() const { return GetField<uint8_t>(VT_VALUE, 0); }
-  bool Verify(flatbuffers::Verifier &verifier) const {
-    return VerifyTableStart(verifier) &&
-           VerifyField<uint8_t>(verifier, VT_VALUE) &&
-           verifier.EndTable();
-  }
-};
-
-struct UByteBuilder {
-  flatbuffers::FlatBufferBuilder &fbb_;
-  flatbuffers::uoffset_t start_;
-  void add_value(uint8_t value) { fbb_.AddElement<uint8_t>(UByte::VT_VALUE, value, 0); }
-  UByteBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
-  UByteBuilder &operator=(const UByteBuilder &);
-  flatbuffers::Offset<UByte> Finish() {
-    auto o = flatbuffers::Offset<UByte>(fbb_.EndTable(start_, 1));
-    return o;
-  }
-};
 
-inline flatbuffers::Offset<UByte> CreateUByte(flatbuffers::FlatBufferBuilder &_fbb,
-   uint8_t value = 0) {
-  UByteBuilder builder_(_fbb);
-  builder_.add_value(value);
-  return builder_.Finish();
-}
+  struct UByteBuilder {
+    flatbuffers::FlatBufferBuilder &fbb_;
+    flatbuffers::uoffset_t start_;
+    void add_value(uint8_t value) { fbb_.AddElement<uint8_t>(UByte::VT_VALUE, value, 0); }
+    UByteBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
+    UByteBuilder &operator=(const UByteBuilder &);
+    flatbuffers::Offset<UByte> Finish() {
+      auto o = flatbuffers::Offset<UByte>(fbb_.EndTable(start_, 1));
+      return o;
+    }
+  };
 
-struct Short FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
-  enum {
-    VT_VALUE = 4
+  inline flatbuffers::Offset<UByte> CreateUByte(flatbuffers::FlatBufferBuilder &_fbb,
+    uint8_t value = 0) {
+    UByteBuilder builder_(_fbb);
+    builder_.add_value(value);
+    return builder_.Finish();
+  }
+
+  struct Short FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+    enum {
+      VT_VALUE = 4
+    };
+    int16_t value() const { return GetField<int16_t>(VT_VALUE, 0); }
+    bool Verify(flatbuffers::Verifier &verifier) const {
+      return VerifyTableStart(verifier) &&
+        VerifyField<int16_t>(verifier, VT_VALUE) &&
+        verifier.EndTable();
+    }
   };
-  int16_t value() const { return GetField<int16_t>(VT_VALUE, 0); }
-  bool Verify(flatbuffers::Verifier &verifier) const {
-    return VerifyTableStart(verifier) &&
-           VerifyField<int16_t>(verifier, VT_VALUE) &&
-           verifier.EndTable();
-  }
-};
-
-struct ShortBuilder {
-  flatbuffers::FlatBufferBuilder &fbb_;
-  flatbuffers::uoffset_t start_;
-  void add_value(int16_t value) { fbb_.AddElement<int16_t>(Short::VT_VALUE, value, 0); }
-  ShortBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
-  ShortBuilder &operator=(const ShortBuilder &);
-  flatbuffers::Offset<Short> Finish() {
-    auto o = flatbuffers::Offset<Short>(fbb_.EndTable(start_, 1));
-    return o;
-  }
-};
 
-inline flatbuffers::Offset<Short> CreateShort(flatbuffers::FlatBufferBuilder &_fbb,
-   int16_t value = 0) {
-  ShortBuilder builder_(_fbb);
-  builder_.add_value(value);
-  return builder_.Finish();
-}
+  struct ShortBuilder {
+    flatbuffers::FlatBufferBuilder &fbb_;
+    flatbuffers::uoffset_t start_;
+    void add_value(int16_t value) { fbb_.AddElement<int16_t>(Short::VT_VALUE, value, 0); }
+    ShortBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
+    ShortBuilder &operator=(const ShortBuilder &);
+    flatbuffers::Offset<Short> Finish() {
+      auto o = flatbuffers::Offset<Short>(fbb_.EndTable(start_, 1));
+      return o;
+    }
+  };
 
-struct UShort FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
-  enum {
-    VT_VALUE = 4
+  inline flatbuffers::Offset<Short> CreateShort(flatbuffers::FlatBufferBuilder &_fbb,
+    int16_t value = 0) {
+    ShortBuilder builder_(_fbb);
+    builder_.add_value(value);
+    return builder_.Finish();
+  }
+
+  struct UShort FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+    enum {
+      VT_VALUE = 4
+    };
+    uint16_t value() const { return GetField<uint16_t>(VT_VALUE, 0); }
+    bool Verify(flatbuffers::Verifier &verifier) const {
+      return VerifyTableStart(verifier) &&
+        VerifyField<uint16_t>(verifier, VT_VALUE) &&
+        verifier.EndTable();
+    }
   };
-  uint16_t value() const { return GetField<uint16_t>(VT_VALUE, 0); }
-  bool Verify(flatbuffers::Verifier &verifier) const {
-    return VerifyTableStart(verifier) &&
-           VerifyField<uint16_t>(verifier, VT_VALUE) &&
-           verifier.EndTable();
-  }
-};
-
-struct UShortBuilder {
-  flatbuffers::FlatBufferBuilder &fbb_;
-  flatbuffers::uoffset_t start_;
-  void add_value(uint16_t value) { fbb_.AddElement<uint16_t>(UShort::VT_VALUE, value, 0); }
-  UShortBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
-  UShortBuilder &operator=(const UShortBuilder &);
-  flatbuffers::Offset<UShort> Finish() {
-    auto o = flatbuffers::Offset<UShort>(fbb_.EndTable(start_, 1));
-    return o;
-  }
-};
 
-inline flatbuffers::Offset<UShort> CreateUShort(flatbuffers::FlatBufferBuilder &_fbb,
-   uint16_t value = 0) {
-  UShortBuilder builder_(_fbb);
-  builder_.add_value(value);
-  return builder_.Finish();
-}
+  struct UShortBuilder {
+    flatbuffers::FlatBufferBuilder &fbb_;
+    flatbuffers::uoffset_t start_;
+    void add_value(uint16_t value) { fbb_.AddElement<uint16_t>(UShort::VT_VALUE, value, 0); }
+    UShortBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
+    UShortBuilder &operator=(const UShortBuilder &);
+    flatbuffers::Offset<UShort> Finish() {
+      auto o = flatbuffers::Offset<UShort>(fbb_.EndTable(start_, 1));
+      return o;
+    }
+  };
 
-struct Int FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
-  enum {
-    VT_VALUE = 4
+  inline flatbuffers::Offset<UShort> CreateUShort(flatbuffers::FlatBufferBuilder &_fbb,
+    uint16_t value = 0) {
+    UShortBuilder builder_(_fbb);
+    builder_.add_value(value);
+    return builder_.Finish();
+  }
+
+  struct Int FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+    enum {
+      VT_VALUE = 4
+    };
+    int32_t value() const { return GetField<int32_t>(VT_VALUE, 0); }
+    bool Verify(flatbuffers::Verifier &verifier) const {
+      return VerifyTableStart(verifier) &&
+        VerifyField<int32_t>(verifier, VT_VALUE) &&
+        verifier.EndTable();
+    }
   };
-  int32_t value() const { return GetField<int32_t>(VT_VALUE, 0); }
-  bool Verify(flatbuffers::Verifier &verifier) const {
-    return VerifyTableStart(verifier) &&
-           VerifyField<int32_t>(verifier, VT_VALUE) &&
-           verifier.EndTable();
-  }
-};
-
-struct IntBuilder {
-  flatbuffers::FlatBufferBuilder &fbb_;
-  flatbuffers::uoffset_t start_;
-  void add_value(int32_t value) { fbb_.AddElement<int32_t>(Int::VT_VALUE, value, 0); }
-  IntBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
-  IntBuilder &operator=(const IntBuilder &);
-  flatbuffers::Offset<Int> Finish() {
-    auto o = flatbuffers::Offset<Int>(fbb_.EndTable(start_, 1));
-    return o;
-  }
-};
 
-inline flatbuffers::Offset<Int> CreateInt(flatbuffers::FlatBufferBuilder &_fbb,
-   int32_t value = 0) {
-  IntBuilder builder_(_fbb);
-  builder_.add_value(value);
-  return builder_.Finish();
-}
+  struct IntBuilder {
+    flatbuffers::FlatBufferBuilder &fbb_;
+    flatbuffers::uoffset_t start_;
+    void add_value(int32_t value) { fbb_.AddElement<int32_t>(Int::VT_VALUE, value, 0); }
+    IntBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
+    IntBuilder &operator=(const IntBuilder &);
+    flatbuffers::Offset<Int> Finish() {
+      auto o = flatbuffers::Offset<Int>(fbb_.EndTable(start_, 1));
+      return o;
+    }
+  };
 
-struct UInt FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
-  enum {
-    VT_VALUE = 4
+  inline flatbuffers::Offset<Int> CreateInt(flatbuffers::FlatBufferBuilder &_fbb,
+    int32_t value = 0) {
+    IntBuilder builder_(_fbb);
+    builder_.add_value(value);
+    return builder_.Finish();
+  }
+
+  struct UInt FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+    enum {
+      VT_VALUE = 4
+    };
+    uint32_t value() const { return GetField<uint32_t>(VT_VALUE, 0); }
+    bool Verify(flatbuffers::Verifier &verifier) const {
+      return VerifyTableStart(verifier) &&
+        VerifyField<uint32_t>(verifier, VT_VALUE) &&
+        verifier.EndTable();
+    }
   };
-  uint32_t value() const { return GetField<uint32_t>(VT_VALUE, 0); }
-  bool Verify(flatbuffers::Verifier &verifier) const {
-    return VerifyTableStart(verifier) &&
-           VerifyField<uint32_t>(verifier, VT_VALUE) &&
-           verifier.EndTable();
-  }
-};
-
-struct UIntBuilder {
-  flatbuffers::FlatBufferBuilder &fbb_;
-  flatbuffers::uoffset_t start_;
-  void add_value(uint32_t value) { fbb_.AddElement<uint32_t>(UInt::VT_VALUE, value, 0); }
-  UIntBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
-  UIntBuilder &operator=(const UIntBuilder &);
-  flatbuffers::Offset<UInt> Finish() {
-    auto o = flatbuffers::Offset<UInt>(fbb_.EndTable(start_, 1));
-    return o;
-  }
-};
 
-inline flatbuffers::Offset<UInt> CreateUInt(flatbuffers::FlatBufferBuilder &_fbb,
-   uint32_t value = 0) {
-  UIntBuilder builder_(_fbb);
-  builder_.add_value(value);
-  return builder_.Finish();
-}
+  struct UIntBuilder {
+    flatbuffers::FlatBufferBuilder &fbb_;
+    flatbuffers::uoffset_t start_;
+    void add_value(uint32_t value) { fbb_.AddElement<uint32_t>(UInt::VT_VALUE, value, 0); }
+    UIntBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
+    UIntBuilder &operator=(const UIntBuilder &);
+    flatbuffers::Offset<UInt> Finish() {
+      auto o = flatbuffers::Offset<UInt>(fbb_.EndTable(start_, 1));
+      return o;
+    }
+  };
 
-struct Long FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
-  enum {
-    VT_VALUE = 4
+  inline flatbuffers::Offset<UInt> CreateUInt(flatbuffers::FlatBufferBuilder &_fbb,
+    uint32_t value = 0) {
+    UIntBuilder builder_(_fbb);
+    builder_.add_value(value);
+    return builder_.Finish();
+  }
+
+  struct Long FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+    enum {
+      VT_VALUE = 4
+    };
+    int64_t value() const { return GetField<int64_t>(VT_VALUE, 0); }
+    bool Verify(flatbuffers::Verifier &verifier) const {
+      return VerifyTableStart(verifier) &&
+        VerifyField<int64_t>(verifier, VT_VALUE) &&
+        verifier.EndTable();
+    }
   };
-  int64_t value() const { return GetField<int64_t>(VT_VALUE, 0); }
-  bool Verify(flatbuffers::Verifier &verifier) const {
-    return VerifyTableStart(verifier) &&
-           VerifyField<int64_t>(verifier, VT_VALUE) &&
-           verifier.EndTable();
-  }
-};
-
-struct LongBuilder {
-  flatbuffers::FlatBufferBuilder &fbb_;
-  flatbuffers::uoffset_t start_;
-  void add_value(int64_t value) { fbb_.AddElement<int64_t>(Long::VT_VALUE, value, 0); }
-  LongBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
-  LongBuilder &operator=(const LongBuilder &);
-  flatbuffers::Offset<Long> Finish() {
-    auto o = flatbuffers::Offset<Long>(fbb_.EndTable(start_, 1));
-    return o;
-  }
-};
 
-inline flatbuffers::Offset<Long> CreateLong(flatbuffers::FlatBufferBuilder &_fbb,
-   int64_t value = 0) {
-  LongBuilder builder_(_fbb);
-  builder_.add_value(value);
-  return builder_.Finish();
-}
+  struct LongBuilder {
+    flatbuffers::FlatBufferBuilder &fbb_;
+    flatbuffers::uoffset_t start_;
+    void add_value(int64_t value) { fbb_.AddElement<int64_t>(Long::VT_VALUE, value, 0); }
+    LongBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
+    LongBuilder &operator=(const LongBuilder &);
+    flatbuffers::Offset<Long> Finish() {
+      auto o = flatbuffers::Offset<Long>(fbb_.EndTable(start_, 1));
+      return o;
+    }
+  };
 
-struct ULong FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
-  enum {
-    VT_VALUE = 4
+  inline flatbuffers::Offset<Long> CreateLong(flatbuffers::FlatBufferBuilder &_fbb,
+    int64_t value = 0) {
+    LongBuilder builder_(_fbb);
+    builder_.add_value(value);
+    return builder_.Finish();
+  }
+
+  struct ULong FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+    enum {
+      VT_VALUE = 4
+    };
+    uint64_t value() const { return GetField<uint64_t>(VT_VALUE, 0); }
+    bool Verify(flatbuffers::Verifier &verifier) const {
+      return VerifyTableStart(verifier) &&
+        VerifyField<uint64_t>(verifier, VT_VALUE) &&
+        verifier.EndTable();
+    }
   };
-  uint64_t value() const { return GetField<uint64_t>(VT_VALUE, 0); }
-  bool Verify(flatbuffers::Verifier &verifier) const {
-    return VerifyTableStart(verifier) &&
-           VerifyField<uint64_t>(verifier, VT_VALUE) &&
-           verifier.EndTable();
-  }
-};
-
-struct ULongBuilder {
-  flatbuffers::FlatBufferBuilder &fbb_;
-  flatbuffers::uoffset_t start_;
-  void add_value(uint64_t value) { fbb_.AddElement<uint64_t>(ULong::VT_VALUE, value, 0); }
-  ULongBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
-  ULongBuilder &operator=(const ULongBuilder &);
-  flatbuffers::Offset<ULong> Finish() {
-    auto o = flatbuffers::Offset<ULong>(fbb_.EndTable(start_, 1));
-    return o;
-  }
-};
 
-inline flatbuffers::Offset<ULong> CreateULong(flatbuffers::FlatBufferBuilder &_fbb,
-   uint64_t value = 0) {
-  ULongBuilder builder_(_fbb);
-  builder_.add_value(value);
-  return builder_.Finish();
-}
+  struct ULongBuilder {
+    flatbuffers::FlatBufferBuilder &fbb_;
+    flatbuffers::uoffset_t start_;
+    void add_value(uint64_t value) { fbb_.AddElement<uint64_t>(ULong::VT_VALUE, value, 0); }
+    ULongBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
+    ULongBuilder &operator=(const ULongBuilder &);
+    flatbuffers::Offset<ULong> Finish() {
+      auto o = flatbuffers::Offset<ULong>(fbb_.EndTable(start_, 1));
+      return o;
+    }
+  };
 
-struct Float FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
-  enum {
-    VT_VALUE = 4
+  inline flatbuffers::Offset<ULong> CreateULong(flatbuffers::FlatBufferBuilder &_fbb,
+    uint64_t value = 0) {
+    ULongBuilder builder_(_fbb);
+    builder_.add_value(value);
+    return builder_.Finish();
+  }
+
+  struct Float FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+    enum {
+      VT_VALUE = 4
+    };
+    float value() const { return GetField<float>(VT_VALUE, 0); }
+    bool Verify(flatbuffers::Verifier &verifier) const {
+      return VerifyTableStart(verifier) &&
+        VerifyField<float>(verifier, VT_VALUE) &&
+        verifier.EndTable();
+    }
   };
-  float value() const { return GetField<float>(VT_VALUE, 0); }
-  bool Verify(flatbuffers::Verifier &verifier) const {
-    return VerifyTableStart(verifier) &&
-           VerifyField<float>(verifier, VT_VALUE) &&
-           verifier.EndTable();
-  }
-};
-
-struct FloatBuilder {
-  flatbuffers::FlatBufferBuilder &fbb_;
-  flatbuffers::uoffset_t start_;
-  void add_value(float value) { fbb_.AddElement<float>(Float::VT_VALUE, value, 0); }
-  FloatBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
-  FloatBuilder &operator=(const FloatBuilder &);
-  flatbuffers::Offset<Float> Finish() {
-    auto o = flatbuffers::Offset<Float>(fbb_.EndTable(start_, 1));
-    return o;
-  }
-};
 
-inline flatbuffers::Offset<Float> CreateFloat(flatbuffers::FlatBufferBuilder &_fbb,
-   float value = 0) {
-  FloatBuilder builder_(_fbb);
-  builder_.add_value(value);
-  return builder_.Finish();
-}
+  struct FloatBuilder {
+    flatbuffers::FlatBufferBuilder &fbb_;
+    flatbuffers::uoffset_t start_;
+    void add_value(float value) { fbb_.AddElement<float>(Float::VT_VALUE, value, 0); }
+    FloatBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
+    FloatBuilder &operator=(const FloatBuilder &);
+    flatbuffers::Offset<Float> Finish() {
+      auto o = flatbuffers::Offset<Float>(fbb_.EndTable(start_, 1));
+      return o;
+    }
+  };
 
-struct Double FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
-  enum {
-    VT_VALUE = 4
+  inline flatbuffers::Offset<Float> CreateFloat(flatbuffers::FlatBufferBuilder &_fbb,
+    float value = 0) {
+    FloatBuilder builder_(_fbb);
+    builder_.add_value(value);
+    return builder_.Finish();
+  }
+
+  struct Double FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+    enum {
+      VT_VALUE = 4
+    };
+    double value() const { return GetField<double>(VT_VALUE, 0); }
+    bool Verify(flatbuffers::Verifier &verifier) const {
+      return VerifyTableStart(verifier) &&
+        VerifyField<double>(verifier, VT_VALUE) &&
+        verifier.EndTable();
+    }
   };
-  double value() const { return GetField<double>(VT_VALUE, 0); }
-  bool Verify(flatbuffers::Verifier &verifier) const {
-    return VerifyTableStart(verifier) &&
-           VerifyField<double>(verifier, VT_VALUE) &&
-           verifier.EndTable();
-  }
-};
-
-struct DoubleBuilder {
-  flatbuffers::FlatBufferBuilder &fbb_;
-  flatbuffers::uoffset_t start_;
-  void add_value(double value) { fbb_.AddElement<double>(Double::VT_VALUE, value, 0); }
-  DoubleBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
-  DoubleBuilder &operator=(const DoubleBuilder &);
-  flatbuffers::Offset<Double> Finish() {
-    auto o = flatbuffers::Offset<Double>(fbb_.EndTable(start_, 1));
-    return o;
-  }
-};
 
-inline flatbuffers::Offset<Double> CreateDouble(flatbuffers::FlatBufferBuilder &_fbb,
-   double value = 0) {
-  DoubleBuilder builder_(_fbb);
-  builder_.add_value(value);
-  return builder_.Finish();
-}
+  struct DoubleBuilder {
+    flatbuffers::FlatBufferBuilder &fbb_;
+    flatbuffers::uoffset_t start_;
+    void add_value(double value) { fbb_.AddElement<double>(Double::VT_VALUE, value, 0); }
+    DoubleBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
+    DoubleBuilder &operator=(const DoubleBuilder &);
+    flatbuffers::Offset<Double> Finish() {
+      auto o = flatbuffers::Offset<Double>(fbb_.EndTable(start_, 1));
+      return o;
+    }
+  };
 
-struct ArrayByte FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
-  enum {
-    VT_VALUE = 4
+  inline flatbuffers::Offset<Double> CreateDouble(flatbuffers::FlatBufferBuilder &_fbb,
+    double value = 0) {
+    DoubleBuilder builder_(_fbb);
+    builder_.add_value(value);
+    return builder_.Finish();
+  }
+
+  struct ArrayByte FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+    enum {
+      VT_VALUE = 4
+    };
+    const flatbuffers::Vector<int8_t> *value() const { return GetPointer<const flatbuffers::Vector<int8_t> *>(VT_VALUE); }
+    bool Verify(flatbuffers::Verifier &verifier) const {
+      return VerifyTableStart(verifier) &&
+        VerifyField<flatbuffers::uoffset_t>(verifier, VT_VALUE) &&
+        verifier.Verify(value()) &&
+        verifier.EndTable();
+    }
   };
-  const flatbuffers::Vector<int8_t> *value() const { return GetPointer<const flatbuffers::Vector<int8_t> *>(VT_VALUE); }
-  bool Verify(flatbuffers::Verifier &verifier) const {
-    return VerifyTableStart(verifier) &&
-           VerifyField<flatbuffers::uoffset_t>(verifier, VT_VALUE) &&
-           verifier.Verify(value()) &&
-           verifier.EndTable();
-  }
-};
-
-struct ArrayByteBuilder {
-  flatbuffers::FlatBufferBuilder &fbb_;
-  flatbuffers::uoffset_t start_;
-  void add_value(flatbuffers::Offset<flatbuffers::Vector<int8_t>> value) { fbb_.AddOffset(ArrayByte::VT_VALUE, value); }
-  ArrayByteBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
-  ArrayByteBuilder &operator=(const ArrayByteBuilder &);
-  flatbuffers::Offset<ArrayByte> Finish() {
-    auto o = flatbuffers::Offset<ArrayByte>(fbb_.EndTable(start_, 1));
-    return o;
-  }
-};
 
-inline flatbuffers::Offset<ArrayByte> CreateArrayByte(flatbuffers::FlatBufferBuilder &_fbb,
-   flatbuffers::Offset<flatbuffers::Vector<int8_t>> value = 0) {
-  ArrayByteBuilder builder_(_fbb);
-  builder_.add_value(value);
-  return builder_.Finish();
-}
+  struct ArrayByteBuilder {
+    flatbuffers::FlatBufferBuilder &fbb_;
+    flatbuffers::uoffset_t start_;
+    void add_value(flatbuffers::Offset<flatbuffers::Vector<int8_t>> value) { fbb_.AddOffset(ArrayByte::VT_VALUE, value); }
+    ArrayByteBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
+    ArrayByteBuilder &operator=(const ArrayByteBuilder &);
+    flatbuffers::Offset<ArrayByte> Finish() {
+      auto o = flatbuffers::Offset<ArrayByte>(fbb_.EndTable(start_, 1));
+      return o;
+    }
+  };
 
-struct ArrayUByte FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
-  enum {
-    VT_VALUE = 4
+  inline flatbuffers::Offset<ArrayByte> CreateArrayByte(flatbuffers::FlatBufferBuilder &_fbb,
+    flatbuffers::Offset<flatbuffers::Vector<int8_t>> value = 0) {
+    ArrayByteBuilder builder_(_fbb);
+    builder_.add_value(value);
+    return builder_.Finish();
+  }
+
+  struct ArrayUByte FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+    enum {
+      VT_VALUE = 4
+    };
+    const flatbuffers::Vector<uint8_t> *value() const { return GetPointer<const flatbuffers::Vector<uint8_t> *>(VT_VALUE); }
+    bool Verify(flatbuffers::Verifier &verifier) const {
+      return VerifyTableStart(verifier) &&
+        VerifyField<flatbuffers::uoffset_t>(verifier, VT_VALUE) &&
+        verifier.Verify(value()) &&
+        verifier.EndTable();
+    }
   };
-  const flatbuffers::Vector<uint8_t> *value() const { return GetPointer<const flatbuffers::Vector<uint8_t> *>(VT_VALUE); }
-  bool Verify(flatbuffers::Verifier &verifier) const {
-    return VerifyTableStart(verifier) &&
-           VerifyField<flatbuffers::uoffset_t>(verifier, VT_VALUE) &&
-           verifier.Verify(value()) &&
-           verifier.EndTable();
-  }
-};
-
-struct ArrayUByteBuilder {
-  flatbuffers::FlatBufferBuilder &fbb_;
-  flatbuffers::uoffset_t start_;
-  void add_value(flatbuffers::Offset<flatbuffers::Vector<uint8_t>> value) { fbb_.AddOffset(ArrayUByte::VT_VALUE, value); }
-  ArrayUByteBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
-  ArrayUByteBuilder &operator=(const ArrayUByteBuilder &);
-  flatbuffers::Offset<ArrayUByte> Finish() {
-    auto o = flatbuffers::Offset<ArrayUByte>(fbb_.EndTable(start_, 1));
-    return o;
-  }
-};
 
-inline flatbuffers::Offset<ArrayUByte> CreateArrayUByte(flatbuffers::FlatBufferBuilder &_fbb,
-   flatbuffers::Offset<flatbuffers::Vector<uint8_t>> value = 0) {
-  ArrayUByteBuilder builder_(_fbb);
-  builder_.add_value(value);
-  return builder_.Finish();
-}
+  struct ArrayUByteBuilder {
+    flatbuffers::FlatBufferBuilder &fbb_;
+    flatbuffers::uoffset_t start_;
+    void add_value(flatbuffers::Offset<flatbuffers::Vector<uint8_t>> value) { fbb_.AddOffset(ArrayUByte::VT_VALUE, value); }
+    ArrayUByteBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
+    ArrayUByteBuilder &operator=(const ArrayUByteBuilder &);
+    flatbuffers::Offset<ArrayUByte> Finish() {
+      auto o = flatbuffers::Offset<ArrayUByte>(fbb_.EndTable(start_, 1));
+      return o;
+    }
+  };
 
-struct ArrayShort FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
-  enum {
-    VT_VALUE = 4
+  inline flatbuffers::Offset<ArrayUByte> CreateArrayUByte(flatbuffers::FlatBufferBuilder &_fbb,
+    flatbuffers::Offset<flatbuffers::Vector<uint8_t>> value = 0) {
+    ArrayUByteBuilder builder_(_fbb);
+    builder_.add_value(value);
+    return builder_.Finish();
+  }
+
+  struct ArrayShort FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+    enum {
+      VT_VALUE = 4
+    };
+    const flatbuffers::Vector<int16_t> *value() const { return GetPointer<const flatbuffers::Vector<int16_t> *>(VT_VALUE); }
+    bool Verify(flatbuffers::Verifier &verifier) const {
+      return VerifyTableStart(verifier) &&
+        VerifyField<flatbuffers::uoffset_t>(verifier, VT_VALUE) &&
+        verifier.Verify(value()) &&
+        verifier.EndTable();
+    }
   };
-  const flatbuffers::Vector<int16_t> *value() const { return GetPointer<const flatbuffers::Vector<int16_t> *>(VT_VALUE); }
-  bool Verify(flatbuffers::Verifier &verifier) const {
-    return VerifyTableStart(verifier) &&
-           VerifyField<flatbuffers::uoffset_t>(verifier, VT_VALUE) &&
-           verifier.Verify(value()) &&
-           verifier.EndTable();
-  }
-};
-
-struct ArrayShortBuilder {
-  flatbuffers::FlatBufferBuilder &fbb_;
-  flatbuffers::uoffset_t start_;
-  void add_value(flatbuffers::Offset<flatbuffers::Vector<int16_t>> value) { fbb_.AddOffset(ArrayShort::VT_VALUE, value); }
-  ArrayShortBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
-  ArrayShortBuilder &operator=(const ArrayShortBuilder &);
-  flatbuffers::Offset<ArrayShort> Finish() {
-    auto o = flatbuffers::Offset<ArrayShort>(fbb_.EndTable(start_, 1));
-    return o;
-  }
-};
 
-inline flatbuffers::Offset<ArrayShort> CreateArrayShort(flatbuffers::FlatBufferBuilder &_fbb,
-   flatbuffers::Offset<flatbuffers::Vector<int16_t>> value = 0) {
-  ArrayShortBuilder builder_(_fbb);
-  builder_.add_value(value);
-  return builder_.Finish();
-}
+  struct ArrayShortBuilder {
+    flatbuffers::FlatBufferBuilder &fbb_;
+    flatbuffers::uoffset_t start_;
+    void add_value(flatbuffers::Offset<flatbuffers::Vector<int16_t>> value) { fbb_.AddOffset(ArrayShort::VT_VALUE, value); }
+    ArrayShortBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
+    ArrayShortBuilder &operator=(const ArrayShortBuilder &);
+    flatbuffers::Offset<ArrayShort> Finish() {
+      auto o = flatbuffers::Offset<ArrayShort>(fbb_.EndTable(start_, 1));
+      return o;
+    }
+  };
 
-struct ArrayUShort FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
-  enum {
-    VT_VALUE = 4
+  inline flatbuffers::Offset<ArrayShort> CreateArrayShort(flatbuffers::FlatBufferBuilder &_fbb,
+    flatbuffers::Offset<flatbuffers::Vector<int16_t>> value = 0) {
+    ArrayShortBuilder builder_(_fbb);
+    builder_.add_value(value);
+    return builder_.Finish();
+  }
+
+  struct ArrayUShort FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+    enum {
+      VT_VALUE = 4
+    };
+    const flatbuffers::Vector<uint16_t> *value() const { return GetPointer<const flatbuffers::Vector<uint16_t> *>(VT_VALUE); }
+    bool Verify(flatbuffers::Verifier &verifier) const {
+      return VerifyTableStart(verifier) &&
+        VerifyField<flatbuffers::uoffset_t>(verifier, VT_VALUE) &&
+        verifier.Verify(value()) &&
+        verifier.EndTable();
+    }
   };
-  const flatbuffers::Vector<uint16_t> *value() const { return GetPointer<const flatbuffers::Vector<uint16_t> *>(VT_VALUE); }
-  bool Verify(flatbuffers::Verifier &verifier) const {
-    return VerifyTableStart(verifier) &&
-           VerifyField<flatbuffers::uoffset_t>(verifier, VT_VALUE) &&
-           verifier.Verify(value()) &&
-           verifier.EndTable();
-  }
-};
-
-struct ArrayUShortBuilder {
-  flatbuffers::FlatBufferBuilder &fbb_;
-  flatbuffers::uoffset_t start_;
-  void add_value(flatbuffers::Offset<flatbuffers::Vector<uint16_t>> value) { fbb_.AddOffset(ArrayUShort::VT_VALUE, value); }
-  ArrayUShortBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
-  ArrayUShortBuilder &operator=(const ArrayUShortBuilder &);
-  flatbuffers::Offset<ArrayUShort> Finish() {
-    auto o = flatbuffers::Offset<ArrayUShort>(fbb_.EndTable(start_, 1));
-    return o;
-  }
-};
 
-inline flatbuffers::Offset<ArrayUShort> CreateArrayUShort(flatbuffers::FlatBufferBuilder &_fbb,
-   flatbuffers::Offset<flatbuffers::Vector<uint16_t>> value = 0) {
-  ArrayUShortBuilder builder_(_fbb);
-  builder_.add_value(value);
-  return builder_.Finish();
-}
+  struct ArrayUShortBuilder {
+    flatbuffers::FlatBufferBuilder &fbb_;
+    flatbuffers::uoffset_t start_;
+    void add_value(flatbuffers::Offset<flatbuffers::Vector<uint16_t>> value) { fbb_.AddOffset(ArrayUShort::VT_VALUE, value); }
+    ArrayUShortBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
+    ArrayUShortBuilder &operator=(const ArrayUShortBuilder &);
+    flatbuffers::Offset<ArrayUShort> Finish() {
+      auto o = flatbuffers::Offset<ArrayUShort>(fbb_.EndTable(start_, 1));
+      return o;
+    }
+  };
 
-struct ArrayInt FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
-  enum {
-    VT_VALUE = 4
+  inline flatbuffers::Offset<ArrayUShort> CreateArrayUShort(flatbuffers::FlatBufferBuilder &_fbb,
+    flatbuffers::Offset<flatbuffers::Vector<uint16_t>> value = 0) {
+    ArrayUShortBuilder builder_(_fbb);
+    builder_.add_value(value);
+    return builder_.Finish();
+  }
+
+  struct ArrayInt FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+    enum {
+      VT_VALUE = 4
+    };
+    const flatbuffers::Vector<int32_t> *value() const { return GetPointer<const flatbuffers::Vector<int32_t> *>(VT_VALUE); }
+    bool Verify(flatbuffers::Verifier &verifier) const {
+      return VerifyTableStart(verifier) &&
+        VerifyField<flatbuffers::uoffset_t>(verifier, VT_VALUE) &&
+        verifier.Verify(value()) &&
+        verifier.EndTable();
+    }
   };
-  const flatbuffers::Vector<int32_t> *value() const { return GetPointer<const flatbuffers::Vector<int32_t> *>(VT_VALUE); }
-  bool Verify(flatbuffers::Verifier &verifier) const {
-    return VerifyTableStart(verifier) &&
-           VerifyField<flatbuffers::uoffset_t>(verifier, VT_VALUE) &&
-           verifier.Verify(value()) &&
-           verifier.EndTable();
-  }
-};
-
-struct ArrayIntBuilder {
-  flatbuffers::FlatBufferBuilder &fbb_;
-  flatbuffers::uoffset_t start_;
-  void add_value(flatbuffers::Offset<flatbuffers::Vector<int32_t>> value) { fbb_.AddOffset(ArrayInt::VT_VALUE, value); }
-  ArrayIntBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
-  ArrayIntBuilder &operator=(const ArrayIntBuilder &);
-  flatbuffers::Offset<ArrayInt> Finish() {
-    auto o = flatbuffers::Offset<ArrayInt>(fbb_.EndTable(start_, 1));
-    return o;
-  }
-};
 
-inline flatbuffers::Offset<ArrayInt> CreateArrayInt(flatbuffers::FlatBufferBuilder &_fbb,
-   flatbuffers::Offset<flatbuffers::Vector<int32_t>> value = 0) {
-  ArrayIntBuilder builder_(_fbb);
-  builder_.add_value(value);
-  return builder_.Finish();
-}
+  struct ArrayIntBuilder {
+    flatbuffers::FlatBufferBuilder &fbb_;
+    flatbuffers::uoffset_t start_;
+    void add_value(flatbuffers::Offset<flatbuffers::Vector<int32_t>> value) { fbb_.AddOffset(ArrayInt::VT_VALUE, value); }
+    ArrayIntBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
+    ArrayIntBuilder &operator=(const ArrayIntBuilder &);
+    flatbuffers::Offset<ArrayInt> Finish() {
+      auto o = flatbuffers::Offset<ArrayInt>(fbb_.EndTable(start_, 1));
+      return o;
+    }
+  };
 
-struct ArrayUInt FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
-  enum {
-    VT_VALUE = 4
+  inline flatbuffers::Offset<ArrayInt> CreateArrayInt(flatbuffers::FlatBufferBuilder &_fbb,
+    flatbuffers::Offset<flatbuffers::Vector<int32_t>> value = 0) {
+    ArrayIntBuilder builder_(_fbb);
+    builder_.add_value(value);
+    return builder_.Finish();
+  }
+
+  struct ArrayUInt FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+    enum {
+      VT_VALUE = 4
+    };
+    const flatbuffers::Vector<uint32_t> *value() const { return GetPointer<const flatbuffers::Vector<uint32_t> *>(VT_VALUE); }
+    bool Verify(flatbuffers::Verifier &verifier) const {
+      return VerifyTableStart(verifier) &&
+        VerifyField<flatbuffers::uoffset_t>(verifier, VT_VALUE) &&
+        verifier.Verify(value()) &&
+        verifier.EndTable();
+    }
   };
-  const flatbuffers::Vector<uint32_t> *value() const { return GetPointer<const flatbuffers::Vector<uint32_t> *>(VT_VALUE); }
-  bool Verify(flatbuffers::Verifier &verifier) const {
-    return VerifyTableStart(verifier) &&
-           VerifyField<flatbuffers::uoffset_t>(verifier, VT_VALUE) &&
-           verifier.Verify(value()) &&
-           verifier.EndTable();
-  }
-};
-
-struct ArrayUIntBuilder {
-  flatbuffers::FlatBufferBuilder &fbb_;
-  flatbuffers::uoffset_t start_;
-  void add_value(flatbuffers::Offset<flatbuffers::Vector<uint32_t>> value) { fbb_.AddOffset(ArrayUInt::VT_VALUE, value); }
-  ArrayUIntBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
-  ArrayUIntBuilder &operator=(const ArrayUIntBuilder &);
-  flatbuffers::Offset<ArrayUInt> Finish() {
-    auto o = flatbuffers::Offset<ArrayUInt>(fbb_.EndTable(start_, 1));
-    return o;
-  }
-};
 
-inline flatbuffers::Offset<ArrayUInt> CreateArrayUInt(flatbuffers::FlatBufferBuilder &_fbb,
-   flatbuffers::Offset<flatbuffers::Vector<uint32_t>> value = 0) {
-  ArrayUIntBuilder builder_(_fbb);
-  builder_.add_value(value);
-  return builder_.Finish();
-}
+  struct ArrayUIntBuilder {
+    flatbuffers::FlatBufferBuilder &fbb_;
+    flatbuffers::uoffset_t start_;
+    void add_value(flatbuffers::Offset<flatbuffers::Vector<uint32_t>> value) { fbb_.AddOffset(ArrayUInt::VT_VALUE, value); }
+    ArrayUIntBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
+    ArrayUIntBuilder &operator=(const ArrayUIntBuilder &);
+    flatbuffers::Offset<ArrayUInt> Finish() {
+      auto o = flatbuffers::Offset<ArrayUInt>(fbb_.EndTable(start_, 1));
+      return o;
+    }
+  };
 
-struct ArrayLong FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
-  enum {
-    VT_VALUE = 4
+  inline flatbuffers::Offset<ArrayUInt> CreateArrayUInt(flatbuffers::FlatBufferBuilder &_fbb,
+    flatbuffers::Offset<flatbuffers::Vector<uint32_t>> value = 0) {
+    ArrayUIntBuilder builder_(_fbb);
+    builder_.add_value(value);
+    return builder_.Finish();
+  }
+
+  struct ArrayLong FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+    enum {
+      VT_VALUE = 4
+    };
+    const flatbuffers::Vector<int64_t> *value() const { return GetPointer<const flatbuffers::Vector<int64_t> *>(VT_VALUE); }
+    bool Verify(flatbuffers::Verifier &verifier) const {
+      return VerifyTableStart(verifier) &&
+        VerifyField<flatbuffers::uoffset_t>(verifier, VT_VALUE) &&
+        verifier.Verify(value()) &&
+        verifier.EndTable();
+    }
   };
-  const flatbuffers::Vector<int64_t> *value() const { return GetPointer<const flatbuffers::Vector<int64_t> *>(VT_VALUE); }
-  bool Verify(flatbuffers::Verifier &verifier) const {
-    return VerifyTableStart(verifier) &&
-           VerifyField<flatbuffers::uoffset_t>(verifier, VT_VALUE) &&
-           verifier.Verify(value()) &&
-           verifier.EndTable();
-  }
-};
-
-struct ArrayLongBuilder {
-  flatbuffers::FlatBufferBuilder &fbb_;
-  flatbuffers::uoffset_t start_;
-  void add_value(flatbuffers::Offset<flatbuffers::Vector<int64_t>> value) { fbb_.AddOffset(ArrayLong::VT_VALUE, value); }
-  ArrayLongBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
-  ArrayLongBuilder &operator=(const ArrayLongBuilder &);
-  flatbuffers::Offset<ArrayLong> Finish() {
-    auto o = flatbuffers::Offset<ArrayLong>(fbb_.EndTable(start_, 1));
-    return o;
-  }
-};
 
-inline flatbuffers::Offset<ArrayLong> CreateArrayLong(flatbuffers::FlatBufferBuilder &_fbb,
-   flatbuffers::Offset<flatbuffers::Vector<int64_t>> value = 0) {
-  ArrayLongBuilder builder_(_fbb);
-  builder_.add_value(value);
-  return builder_.Finish();
-}
+  struct ArrayLongBuilder {
+    flatbuffers::FlatBufferBuilder &fbb_;
+    flatbuffers::uoffset_t start_;
+    void add_value(flatbuffers::Offset<flatbuffers::Vector<int64_t>> value) { fbb_.AddOffset(ArrayLong::VT_VALUE, value); }
+    ArrayLongBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
+    ArrayLongBuilder &operator=(const ArrayLongBuilder &);
+    flatbuffers::Offset<ArrayLong> Finish() {
+      auto o = flatbuffers::Offset<ArrayLong>(fbb_.EndTable(start_, 1));
+      return o;
+    }
+  };
 
-struct ArrayULong FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
-  enum {
-    VT_VALUE = 4
+  inline flatbuffers::Offset<ArrayLong> CreateArrayLong(flatbuffers::FlatBufferBuilder &_fbb,
+    flatbuffers::Offset<flatbuffers::Vector<int64_t>> value = 0) {
+    ArrayLongBuilder builder_(_fbb);
+    builder_.add_value(value);
+    return builder_.Finish();
+  }
+
+  struct ArrayULong FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+    enum {
+      VT_VALUE = 4
+    };
+    const flatbuffers::Vector<uint64_t> *value() const { return GetPointer<const flatbuffers::Vector<uint64_t> *>(VT_VALUE); }
+    bool Verify(flatbuffers::Verifier &verifier) const {
+      return VerifyTableStart(verifier) &&
+        VerifyField<flatbuffers::uoffset_t>(verifier, VT_VALUE) &&
+        verifier.Verify(value()) &&
+        verifier.EndTable();
+    }
   };
-  const flatbuffers::Vector<uint64_t> *value() const { return GetPointer<const flatbuffers::Vector<uint64_t> *>(VT_VALUE); }
-  bool Verify(flatbuffers::Verifier &verifier) const {
-    return VerifyTableStart(verifier) &&
-           VerifyField<flatbuffers::uoffset_t>(verifier, VT_VALUE) &&
-           verifier.Verify(value()) &&
-           verifier.EndTable();
-  }
-};
-
-struct ArrayULongBuilder {
-  flatbuffers::FlatBufferBuilder &fbb_;
-  flatbuffers::uoffset_t start_;
-  void add_value(flatbuffers::Offset<flatbuffers::Vector<uint64_t>> value) { fbb_.AddOffset(ArrayULong::VT_VALUE, value); }
-  ArrayULongBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
-  ArrayULongBuilder &operator=(const ArrayULongBuilder &);
-  flatbuffers::Offset<ArrayULong> Finish() {
-    auto o = flatbuffers::Offset<ArrayULong>(fbb_.EndTable(start_, 1));
-    return o;
-  }
-};
 
-inline flatbuffers::Offset<ArrayULong> CreateArrayULong(flatbuffers::FlatBufferBuilder &_fbb,
-   flatbuffers::Offset<flatbuffers::Vector<uint64_t>> value = 0) {
-  ArrayULongBuilder builder_(_fbb);
-  builder_.add_value(value);
-  return builder_.Finish();
-}
+  struct ArrayULongBuilder {
+    flatbuffers::FlatBufferBuilder &fbb_;
+    flatbuffers::uoffset_t start_;
+    void add_value(flatbuffers::Offset<flatbuffers::Vector<uint64_t>> value) { fbb_.AddOffset(ArrayULong::VT_VALUE, value); }
+    ArrayULongBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
+    ArrayULongBuilder &operator=(const ArrayULongBuilder &);
+    flatbuffers::Offset<ArrayULong> Finish() {
+      auto o = flatbuffers::Offset<ArrayULong>(fbb_.EndTable(start_, 1));
+      return o;
+    }
+  };
 
-struct ArrayFloat FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
-  enum {
-    VT_VALUE = 4
+  inline flatbuffers::Offset<ArrayULong> CreateArrayULong(flatbuffers::FlatBufferBuilder &_fbb,
+    flatbuffers::Offset<flatbuffers::Vector<uint64_t>> value = 0) {
+    ArrayULongBuilder builder_(_fbb);
+    builder_.add_value(value);
+    return builder_.Finish();
+  }
+
+  struct ArrayFloat FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+    enum {
+      VT_VALUE = 4
+    };
+    const flatbuffers::Vector<float> *value() const { return GetPointer<const flatbuffers::Vector<float> *>(VT_VALUE); }
+    bool Verify(flatbuffers::Verifier &verifier) const {
+      return VerifyTableStart(verifier) &&
+        VerifyField<flatbuffers::uoffset_t>(verifier, VT_VALUE) &&
+        verifier.Verify(value()) &&
+        verifier.EndTable();
+    }
   };
-  const flatbuffers::Vector<float> *value() const { return GetPointer<const flatbuffers::Vector<float> *>(VT_VALUE); }
-  bool Verify(flatbuffers::Verifier &verifier) const {
-    return VerifyTableStart(verifier) &&
-           VerifyField<flatbuffers::uoffset_t>(verifier, VT_VALUE) &&
-           verifier.Verify(value()) &&
-           verifier.EndTable();
-  }
-};
-
-struct ArrayFloatBuilder {
-  flatbuffers::FlatBufferBuilder &fbb_;
-  flatbuffers::uoffset_t start_;
-  void add_value(flatbuffers::Offset<flatbuffers::Vector<float>> value) { fbb_.AddOffset(ArrayFloat::VT_VALUE, value); }
-  ArrayFloatBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
-  ArrayFloatBuilder &operator=(const ArrayFloatBuilder &);
-  flatbuffers::Offset<ArrayFloat> Finish() {
-    auto o = flatbuffers::Offset<ArrayFloat>(fbb_.EndTable(start_, 1));
-    return o;
-  }
-};
 
-inline flatbuffers::Offset<ArrayFloat> CreateArrayFloat(flatbuffers::FlatBufferBuilder &_fbb,
-   flatbuffers::Offset<flatbuffers::Vector<float>> value = 0) {
-  ArrayFloatBuilder builder_(_fbb);
-  builder_.add_value(value);
-  return builder_.Finish();
-}
+  struct ArrayFloatBuilder {
+    flatbuffers::FlatBufferBuilder &fbb_;
+    flatbuffers::uoffset_t start_;
+    void add_value(flatbuffers::Offset<flatbuffers::Vector<float>> value) { fbb_.AddOffset(ArrayFloat::VT_VALUE, value); }
+    ArrayFloatBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
+    ArrayFloatBuilder &operator=(const ArrayFloatBuilder &);
+    flatbuffers::Offset<ArrayFloat> Finish() {
+      auto o = flatbuffers::Offset<ArrayFloat>(fbb_.EndTable(start_, 1));
+      return o;
+    }
+  };
 
-struct ArrayDouble FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
-  enum {
-    VT_VALUE = 4
+  inline flatbuffers::Offset<ArrayFloat> CreateArrayFloat(flatbuffers::FlatBufferBuilder &_fbb,
+    flatbuffers::Offset<flatbuffers::Vector<float>> value = 0) {
+    ArrayFloatBuilder builder_(_fbb);
+    builder_.add_value(value);
+    return builder_.Finish();
+  }
+
+  struct ArrayDouble FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+    enum {
+      VT_VALUE = 4
+    };
+    const flatbuffers::Vector<double> *value() const { return GetPointer<const flatbuffers::Vector<double> *>(VT_VALUE); }
+    bool Verify(flatbuffers::Verifier &verifier) const {
+      return VerifyTableStart(verifier) &&
+        VerifyField<flatbuffers::uoffset_t>(verifier, VT_VALUE) &&
+        verifier.Verify(value()) &&
+        verifier.EndTable();
+    }
   };
-  const flatbuffers::Vector<double> *value() const { return GetPointer<const flatbuffers::Vector<double> *>(VT_VALUE); }
-  bool Verify(flatbuffers::Verifier &verifier) const {
-    return VerifyTableStart(verifier) &&
-           VerifyField<flatbuffers::uoffset_t>(verifier, VT_VALUE) &&
-           verifier.Verify(value()) &&
-           verifier.EndTable();
-  }
-};
-
-struct ArrayDoubleBuilder {
-  flatbuffers::FlatBufferBuilder &fbb_;
-  flatbuffers::uoffset_t start_;
-  void add_value(flatbuffers::Offset<flatbuffers::Vector<double>> value) { fbb_.AddOffset(ArrayDouble::VT_VALUE, value); }
-  ArrayDoubleBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
-  ArrayDoubleBuilder &operator=(const ArrayDoubleBuilder &);
-  flatbuffers::Offset<ArrayDouble> Finish() {
-    auto o = flatbuffers::Offset<ArrayDouble>(fbb_.EndTable(start_, 1));
-    return o;
-  }
-};
 
-inline flatbuffers::Offset<ArrayDouble> CreateArrayDouble(flatbuffers::FlatBufferBuilder &_fbb,
-   flatbuffers::Offset<flatbuffers::Vector<double>> value = 0) {
-  ArrayDoubleBuilder builder_(_fbb);
-  builder_.add_value(value);
-  return builder_.Finish();
-}
+  struct ArrayDoubleBuilder {
+    flatbuffers::FlatBufferBuilder &fbb_;
+    flatbuffers::uoffset_t start_;
+    void add_value(flatbuffers::Offset<flatbuffers::Vector<double>> value) { fbb_.AddOffset(ArrayDouble::VT_VALUE, value); }
+    ArrayDoubleBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
+    ArrayDoubleBuilder &operator=(const ArrayDoubleBuilder &);
+    flatbuffers::Offset<ArrayDouble> Finish() {
+      auto o = flatbuffers::Offset<ArrayDouble>(fbb_.EndTable(start_, 1));
+      return o;
+    }
+  };
 
-struct LogData FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
-  enum {
-    VT_SOURCE_NAME = 4,
-    VT_VALUE_TYPE = 6,
-    VT_VALUE = 8,
-    VT_TIMESTAMP = 10,
-    VT_FWDINFO_TYPE = 12,
-    VT_FWDINFO = 14
-  };
-  const flatbuffers::String *source_name() const { return GetPointer<const flatbuffers::String *>(VT_SOURCE_NAME); }
-  Value value_type() const { return static_cast<Value>(GetField<uint8_t>(VT_VALUE_TYPE, 0)); }
-  const void *value() const { return GetPointer<const void *>(VT_VALUE); }
-  uint64_t timestamp() const { return GetField<uint64_t>(VT_TIMESTAMP, 0); }
-  forwarder_internal fwdinfo_type() const { return static_cast<forwarder_internal>(GetField<uint8_t>(VT_FWDINFO_TYPE, 0)); }
-  const void *fwdinfo() const { return GetPointer<const void *>(VT_FWDINFO); }
-  bool Verify(flatbuffers::Verifier &verifier) const {
-    return VerifyTableStart(verifier) &&
-           VerifyField<flatbuffers::uoffset_t>(verifier, VT_SOURCE_NAME) &&
-           verifier.Verify(source_name()) &&
-           VerifyField<uint8_t>(verifier, VT_VALUE_TYPE) &&
-           VerifyField<flatbuffers::uoffset_t>(verifier, VT_VALUE) &&
-           VerifyValue(verifier, value(), value_type()) &&
-           VerifyField<uint64_t>(verifier, VT_TIMESTAMP) &&
-           VerifyField<uint8_t>(verifier, VT_FWDINFO_TYPE) &&
-           VerifyField<flatbuffers::uoffset_t>(verifier, VT_FWDINFO) &&
-           Verifyforwarder_internal(verifier, fwdinfo(), fwdinfo_type()) &&
-           verifier.EndTable();
-  }
-};
-
-struct LogDataBuilder {
-  flatbuffers::FlatBufferBuilder &fbb_;
-  flatbuffers::uoffset_t start_;
-  void add_source_name(flatbuffers::Offset<flatbuffers::String> source_name) { fbb_.AddOffset(LogData::VT_SOURCE_NAME, source_name); }
-  void add_value_type(Value value_type) { fbb_.AddElement<uint8_t>(LogData::VT_VALUE_TYPE, static_cast<uint8_t>(value_type), 0); }
-  void add_value(flatbuffers::Offset<void> value) { fbb_.AddOffset(LogData::VT_VALUE, value); }
-  void add_timestamp(uint64_t timestamp) { fbb_.AddElement<uint64_t>(LogData::VT_TIMESTAMP, timestamp, 0); }
-  void add_fwdinfo_type(forwarder_internal fwdinfo_type) { fbb_.AddElement<uint8_t>(LogData::VT_FWDINFO_TYPE, static_cast<uint8_t>(fwdinfo_type), 0); }
-  void add_fwdinfo(flatbuffers::Offset<void> fwdinfo) { fbb_.AddOffset(LogData::VT_FWDINFO, fwdinfo); }
-  LogDataBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
-  LogDataBuilder &operator=(const LogDataBuilder &);
-  flatbuffers::Offset<LogData> Finish() {
-    auto o = flatbuffers::Offset<LogData>(fbb_.EndTable(start_, 6));
-    return o;
-  }
-};
-
-inline flatbuffers::Offset<LogData> CreateLogData(flatbuffers::FlatBufferBuilder &_fbb,
-   flatbuffers::Offset<flatbuffers::String> source_name = 0,
-   Value value_type = Value_NONE,
-   flatbuffers::Offset<void> value = 0,
-   uint64_t timestamp = 0,
-   forwarder_internal fwdinfo_type = forwarder_internal_NONE,
-   flatbuffers::Offset<void> fwdinfo = 0) {
-  LogDataBuilder builder_(_fbb);
-  builder_.add_timestamp(timestamp);
-  builder_.add_fwdinfo(fwdinfo);
-  builder_.add_value(value);
-  builder_.add_source_name(source_name);
-  builder_.add_fwdinfo_type(fwdinfo_type);
-  builder_.add_value_type(value_type);
-  return builder_.Finish();
-}
+  inline flatbuffers::Offset<ArrayDouble> CreateArrayDouble(flatbuffers::FlatBufferBuilder &_fbb,
+    flatbuffers::Offset<flatbuffers::Vector<double>> value = 0) {
+    ArrayDoubleBuilder builder_(_fbb);
+    builder_.add_value(value);
+    return builder_.Finish();
+  }
+
+  struct LogData FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+    enum {
+      VT_SOURCE_NAME = 4,
+      VT_VALUE_TYPE = 6,
+      VT_VALUE = 8,
+      VT_TIMESTAMP = 10,
+      VT_FWDINFO_TYPE = 12,
+      VT_FWDINFO = 14
+    };
+    const flatbuffers::String *source_name() const { return GetPointer<const flatbuffers::String *>(VT_SOURCE_NAME); }
+    Value value_type() const { return static_cast<Value>(GetField<uint8_t>(VT_VALUE_TYPE, 0)); }
+    const void *value() const { return GetPointer<const void *>(VT_VALUE); }
+    uint64_t timestamp() const { return GetField<uint64_t>(VT_TIMESTAMP, 0); }
+    forwarder_internal fwdinfo_type() const { return static_cast<forwarder_internal>(GetField<uint8_t>(VT_FWDINFO_TYPE, 0)); }
+    const void *fwdinfo() const { return GetPointer<const void *>(VT_FWDINFO); }
+    bool Verify(flatbuffers::Verifier &verifier) const {
+      return VerifyTableStart(verifier) &&
+        VerifyField<flatbuffers::uoffset_t>(verifier, VT_SOURCE_NAME) &&
+        verifier.Verify(source_name()) &&
+        VerifyField<uint8_t>(verifier, VT_VALUE_TYPE) &&
+        VerifyField<flatbuffers::uoffset_t>(verifier, VT_VALUE) &&
+        VerifyValue(verifier, value(), value_type()) &&
+        VerifyField<uint64_t>(verifier, VT_TIMESTAMP) &&
+        VerifyField<uint8_t>(verifier, VT_FWDINFO_TYPE) &&
+        VerifyField<flatbuffers::uoffset_t>(verifier, VT_FWDINFO) &&
+        Verifyforwarder_internal(verifier, fwdinfo(), fwdinfo_type()) &&
+        verifier.EndTable();
+    }
+  };
 
-inline bool VerifyValue(flatbuffers::Verifier &verifier, const void *union_obj, Value type) {
-  switch (type) {
+  struct LogDataBuilder {
+    flatbuffers::FlatBufferBuilder &fbb_;
+    flatbuffers::uoffset_t start_;
+    void add_source_name(flatbuffers::Offset<flatbuffers::String> source_name) { fbb_.AddOffset(LogData::VT_SOURCE_NAME, source_name); }
+    void add_value_type(Value value_type) { fbb_.AddElement<uint8_t>(LogData::VT_VALUE_TYPE, static_cast<uint8_t>(value_type), 0); }
+    void add_value(flatbuffers::Offset<void> value) { fbb_.AddOffset(LogData::VT_VALUE, value); }
+    void add_timestamp(uint64_t timestamp) { fbb_.AddElement<uint64_t>(LogData::VT_TIMESTAMP, timestamp, 0); }
+    void add_fwdinfo_type(forwarder_internal fwdinfo_type) { fbb_.AddElement<uint8_t>(LogData::VT_FWDINFO_TYPE, static_cast<uint8_t>(fwdinfo_type), 0); }
+    void add_fwdinfo(flatbuffers::Offset<void> fwdinfo) { fbb_.AddOffset(LogData::VT_FWDINFO, fwdinfo); }
+    LogDataBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
+    LogDataBuilder &operator=(const LogDataBuilder &);
+    flatbuffers::Offset<LogData> Finish() {
+      auto o = flatbuffers::Offset<LogData>(fbb_.EndTable(start_, 6));
+      return o;
+    }
+  };
+
+  inline flatbuffers::Offset<LogData> CreateLogData(flatbuffers::FlatBufferBuilder &_fbb,
+    flatbuffers::Offset<flatbuffers::String> source_name = 0,
+    Value value_type = Value_NONE,
+    flatbuffers::Offset<void> value = 0,
+    uint64_t timestamp = 0,
+    forwarder_internal fwdinfo_type = forwarder_internal_NONE,
+    flatbuffers::Offset<void> fwdinfo = 0) {
+    LogDataBuilder builder_(_fbb);
+    builder_.add_timestamp(timestamp);
+    builder_.add_fwdinfo(fwdinfo);
+    builder_.add_value(value);
+    builder_.add_source_name(source_name);
+    builder_.add_fwdinfo_type(fwdinfo_type);
+    builder_.add_value_type(value_type);
+    return builder_.Finish();
+  }
+
+  inline bool VerifyValue(flatbuffers::Verifier &verifier, const void *union_obj, Value type) {
+    switch (type) {
     case Value_NONE: return true;
     case Value_Byte: return verifier.VerifyTable(reinterpret_cast<const Byte *>(union_obj));
     case Value_UByte: return verifier.VerifyTable(reinterpret_cast<const UByte *>(union_obj));
@@ -792,19 +795,19 @@ inline bool VerifyValue(flatbuffers::Verifier &verifier, const void *union_obj,
     case Value_ArrayFloat: return verifier.VerifyTable(reinterpret_cast<const ArrayFloat *>(union_obj));
     case Value_ArrayDouble: return verifier.VerifyTable(reinterpret_cast<const ArrayDouble *>(union_obj));
     default: return false;
+    }
   }
-}
 
-inline const LogData *GetLogData(const void *buf) { return flatbuffers::GetRoot<LogData>(buf); }
+  inline const LogData *GetLogData(const void *buf) { return flatbuffers::GetRoot<LogData>(buf); }
 
-inline bool VerifyLogDataBuffer(flatbuffers::Verifier &verifier) { return verifier.VerifyBuffer<LogData>(); }
+  inline bool VerifyLogDataBuffer(flatbuffers::Verifier &verifier) { return verifier.VerifyBuffer<LogData>(); }
 
-inline const char *LogDataIdentifier() { return "f142"; }
+  inline const char *LogDataIdentifier() { return "f142"; }
 
-inline bool LogDataBufferHasIdentifier(const void *buf) { return flatbuffers::BufferHasIdentifier(buf, LogDataIdentifier()); }
-
-inline void FinishLogDataBuffer(flatbuffers::FlatBufferBuilder &fbb, flatbuffers::Offset<LogData> root) { fbb.Finish(root, LogDataIdentifier()); }
+  inline bool LogDataBufferHasIdentifier(const void *buf) { return flatbuffers::BufferHasIdentifier(buf, LogDataIdentifier()); }
 
+  inline void FinishLogDataBuffer(flatbuffers::FlatBufferBuilder &fbb, flatbuffers::Offset<LogData> root) { fbb.Finish(root, LogDataIdentifier()); }
+}
 
 #endif  // FLATBUFFERS_GENERATED_F142LOGDATA_H_
 // clang-format on
diff --git a/Framework/LiveData/src/Kafka/private/Schema/hs00_event_histogram_generated.h b/Framework/LiveData/src/Kafka/private/Schema/hs00_event_histogram_generated.h
index 3a55e3dcd53..5494b08e0c0 100644
--- a/Framework/LiveData/src/Kafka/private/Schema/hs00_event_histogram_generated.h
+++ b/Framework/LiveData/src/Kafka/private/Schema/hs00_event_histogram_generated.h
@@ -8,504 +8,508 @@
 
 #include "flatbuffers/flatbuffers.h"
 
-struct ArrayUInt;
+/// Due to type conflicts with other schemas it was necessary to 
+/// add this namespace HistoSchema. 
+namespace HistoSchema {
 
-struct ArrayULong;
+  struct ArrayUInt;
 
-struct ArrayDouble;
+  struct ArrayULong;
 
-struct DimensionMetaData;
+  struct ArrayDouble;
 
-struct EventHistogram;
+  struct DimensionMetaData;
 
-enum Array {
-  Array_NONE = 0,
-  Array_ArrayUInt = 1,
-  Array_ArrayULong = 2,
-  Array_ArrayDouble = 3,
-  Array_MIN = Array_NONE,
-  Array_MAX = Array_ArrayDouble
-};
+  struct EventHistogram;
 
-inline const Array (&EnumValuesArray())[4] {
-  static const Array values[] = {
-    Array_NONE,
-    Array_ArrayUInt,
-    Array_ArrayULong,
-    Array_ArrayDouble
+  enum Array {
+    Array_NONE = 0,
+    Array_ArrayUInt = 1,
+    Array_ArrayULong = 2,
+    Array_ArrayDouble = 3,
+    Array_MIN = Array_NONE,
+    Array_MAX = Array_ArrayDouble
   };
-  return values;
-}
 
-inline const char * const *EnumNamesArray() {
-  static const char * const names[] = {
-    "NONE",
-    "ArrayUInt",
-    "ArrayULong",
-    "ArrayDouble",
-    nullptr
-  };
-  return names;
-}
+  inline const Array(&EnumValuesArray())[4]{
+    static const Array values[] = {
+      Array_NONE,
+      Array_ArrayUInt,
+      Array_ArrayULong,
+      Array_ArrayDouble
+    };
+    return values;
+  }
 
-inline const char *EnumNameArray(Array e) {
-  const size_t index = static_cast<int>(e);
-  return EnumNamesArray()[index];
-}
+    inline const char * const *EnumNamesArray() {
+    static const char * const names[] = {
+      "NONE",
+      "ArrayUInt",
+      "ArrayULong",
+      "ArrayDouble",
+      nullptr
+    };
+    return names;
+  }
 
-template<typename T> struct ArrayTraits {
-  static const Array enum_value = Array_NONE;
-};
+  inline const char *EnumNameArray(Array e) {
+    const size_t index = static_cast<int>(e);
+    return EnumNamesArray()[index];
+  }
+
+  template<typename T> struct ArrayTraits {
+    static const Array enum_value = Array_NONE;
+  };
 
-template<> struct ArrayTraits<ArrayUInt> {
-  static const Array enum_value = Array_ArrayUInt;
-};
+  template<> struct ArrayTraits<ArrayUInt> {
+    static const Array enum_value = Array_ArrayUInt;
+  };
 
-template<> struct ArrayTraits<ArrayULong> {
-  static const Array enum_value = Array_ArrayULong;
-};
+  template<> struct ArrayTraits<ArrayULong> {
+    static const Array enum_value = Array_ArrayULong;
+  };
 
-template<> struct ArrayTraits<ArrayDouble> {
-  static const Array enum_value = Array_ArrayDouble;
-};
+  template<> struct ArrayTraits<ArrayDouble> {
+    static const Array enum_value = Array_ArrayDouble;
+  };
 
-bool VerifyArray(flatbuffers::Verifier &verifier, const void *obj, Array type);
-bool VerifyArrayVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector<flatbuffers::Offset<void>> *values, const flatbuffers::Vector<uint8_t> *types);
+  bool VerifyArray(flatbuffers::Verifier &verifier, const void *obj, Array type);
+  bool VerifyArrayVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector<flatbuffers::Offset<void>> *values, const flatbuffers::Vector<uint8_t> *types);
 
-struct ArrayUInt FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
-  enum {
-    VT_VALUE = 4
+  struct ArrayUInt FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+    enum {
+      VT_VALUE = 4
+    };
+    const flatbuffers::Vector<uint32_t> *value() const {
+      return GetPointer<const flatbuffers::Vector<uint32_t> *>(VT_VALUE);
+    }
+    bool Verify(flatbuffers::Verifier &verifier) const {
+      return VerifyTableStart(verifier) &&
+        VerifyOffset(verifier, VT_VALUE) &&
+        verifier.Verify(value()) &&
+        verifier.EndTable();
+    }
   };
-  const flatbuffers::Vector<uint32_t> *value() const {
-    return GetPointer<const flatbuffers::Vector<uint32_t> *>(VT_VALUE);
-  }
-  bool Verify(flatbuffers::Verifier &verifier) const {
-    return VerifyTableStart(verifier) &&
-           VerifyOffset(verifier, VT_VALUE) &&
-           verifier.Verify(value()) &&
-           verifier.EndTable();
-  }
-};
 
-struct ArrayUIntBuilder {
-  flatbuffers::FlatBufferBuilder &fbb_;
-  flatbuffers::uoffset_t start_;
-  void add_value(flatbuffers::Offset<flatbuffers::Vector<uint32_t>> value) {
-    fbb_.AddOffset(ArrayUInt::VT_VALUE, value);
-  }
-  explicit ArrayUIntBuilder(flatbuffers::FlatBufferBuilder &_fbb)
-        : fbb_(_fbb) {
-    start_ = fbb_.StartTable();
-  }
-  ArrayUIntBuilder &operator=(const ArrayUIntBuilder &);
-  flatbuffers::Offset<ArrayUInt> Finish() {
-    const auto end = fbb_.EndTable(start_);
-    auto o = flatbuffers::Offset<ArrayUInt>(end);
-    return o;
-  }
-};
+  struct ArrayUIntBuilder {
+    flatbuffers::FlatBufferBuilder &fbb_;
+    flatbuffers::uoffset_t start_;
+    void add_value(flatbuffers::Offset<flatbuffers::Vector<uint32_t>> value) {
+      fbb_.AddOffset(ArrayUInt::VT_VALUE, value);
+    }
+    explicit ArrayUIntBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+      : fbb_(_fbb) {
+      start_ = fbb_.StartTable();
+    }
+    ArrayUIntBuilder &operator=(const ArrayUIntBuilder &);
+    flatbuffers::Offset<ArrayUInt> Finish() {
+      const auto end = fbb_.EndTable(start_);
+      auto o = flatbuffers::Offset<ArrayUInt>(end);
+      return o;
+    }
+  };
 
-inline flatbuffers::Offset<ArrayUInt> CreateArrayUInt(
+  inline flatbuffers::Offset<ArrayUInt> CreateArrayUInt(
     flatbuffers::FlatBufferBuilder &_fbb,
     flatbuffers::Offset<flatbuffers::Vector<uint32_t>> value = 0) {
-  ArrayUIntBuilder builder_(_fbb);
-  builder_.add_value(value);
-  return builder_.Finish();
-}
+    ArrayUIntBuilder builder_(_fbb);
+    builder_.add_value(value);
+    return builder_.Finish();
+  }
 
-inline flatbuffers::Offset<ArrayUInt> CreateArrayUIntDirect(
+  inline flatbuffers::Offset<ArrayUInt> CreateArrayUIntDirect(
     flatbuffers::FlatBufferBuilder &_fbb,
     const std::vector<uint32_t> *value = nullptr) {
-  return CreateArrayUInt(
+    return CreateArrayUInt(
       _fbb,
       value ? _fbb.CreateVector<uint32_t>(*value) : 0);
-}
+  }
 
-struct ArrayULong FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
-  enum {
-    VT_VALUE = 4
+  struct ArrayULong FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+    enum {
+      VT_VALUE = 4
+    };
+    const flatbuffers::Vector<uint64_t> *value() const {
+      return GetPointer<const flatbuffers::Vector<uint64_t> *>(VT_VALUE);
+    }
+    bool Verify(flatbuffers::Verifier &verifier) const {
+      return VerifyTableStart(verifier) &&
+        VerifyOffset(verifier, VT_VALUE) &&
+        verifier.Verify(value()) &&
+        verifier.EndTable();
+    }
   };
-  const flatbuffers::Vector<uint64_t> *value() const {
-    return GetPointer<const flatbuffers::Vector<uint64_t> *>(VT_VALUE);
-  }
-  bool Verify(flatbuffers::Verifier &verifier) const {
-    return VerifyTableStart(verifier) &&
-           VerifyOffset(verifier, VT_VALUE) &&
-           verifier.Verify(value()) &&
-           verifier.EndTable();
-  }
-};
 
-struct ArrayULongBuilder {
-  flatbuffers::FlatBufferBuilder &fbb_;
-  flatbuffers::uoffset_t start_;
-  void add_value(flatbuffers::Offset<flatbuffers::Vector<uint64_t>> value) {
-    fbb_.AddOffset(ArrayULong::VT_VALUE, value);
-  }
-  explicit ArrayULongBuilder(flatbuffers::FlatBufferBuilder &_fbb)
-        : fbb_(_fbb) {
-    start_ = fbb_.StartTable();
-  }
-  ArrayULongBuilder &operator=(const ArrayULongBuilder &);
-  flatbuffers::Offset<ArrayULong> Finish() {
-    const auto end = fbb_.EndTable(start_);
-    auto o = flatbuffers::Offset<ArrayULong>(end);
-    return o;
-  }
-};
+  struct ArrayULongBuilder {
+    flatbuffers::FlatBufferBuilder &fbb_;
+    flatbuffers::uoffset_t start_;
+    void add_value(flatbuffers::Offset<flatbuffers::Vector<uint64_t>> value) {
+      fbb_.AddOffset(ArrayULong::VT_VALUE, value);
+    }
+    explicit ArrayULongBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+      : fbb_(_fbb) {
+      start_ = fbb_.StartTable();
+    }
+    ArrayULongBuilder &operator=(const ArrayULongBuilder &);
+    flatbuffers::Offset<ArrayULong> Finish() {
+      const auto end = fbb_.EndTable(start_);
+      auto o = flatbuffers::Offset<ArrayULong>(end);
+      return o;
+    }
+  };
 
-inline flatbuffers::Offset<ArrayULong> CreateArrayULong(
+  inline flatbuffers::Offset<ArrayULong> CreateArrayULong(
     flatbuffers::FlatBufferBuilder &_fbb,
     flatbuffers::Offset<flatbuffers::Vector<uint64_t>> value = 0) {
-  ArrayULongBuilder builder_(_fbb);
-  builder_.add_value(value);
-  return builder_.Finish();
-}
+    ArrayULongBuilder builder_(_fbb);
+    builder_.add_value(value);
+    return builder_.Finish();
+  }
 
-inline flatbuffers::Offset<ArrayULong> CreateArrayULongDirect(
+  inline flatbuffers::Offset<ArrayULong> CreateArrayULongDirect(
     flatbuffers::FlatBufferBuilder &_fbb,
     const std::vector<uint64_t> *value = nullptr) {
-  return CreateArrayULong(
+    return CreateArrayULong(
       _fbb,
       value ? _fbb.CreateVector<uint64_t>(*value) : 0);
-}
+  }
 
-struct ArrayDouble FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
-  enum {
-    VT_VALUE = 4
+  struct ArrayDouble FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+    enum {
+      VT_VALUE = 4
+    };
+    const flatbuffers::Vector<double> *value() const {
+      return GetPointer<const flatbuffers::Vector<double> *>(VT_VALUE);
+    }
+    bool Verify(flatbuffers::Verifier &verifier) const {
+      return VerifyTableStart(verifier) &&
+        VerifyOffset(verifier, VT_VALUE) &&
+        verifier.Verify(value()) &&
+        verifier.EndTable();
+    }
   };
-  const flatbuffers::Vector<double> *value() const {
-    return GetPointer<const flatbuffers::Vector<double> *>(VT_VALUE);
-  }
-  bool Verify(flatbuffers::Verifier &verifier) const {
-    return VerifyTableStart(verifier) &&
-           VerifyOffset(verifier, VT_VALUE) &&
-           verifier.Verify(value()) &&
-           verifier.EndTable();
-  }
-};
 
-struct ArrayDoubleBuilder {
-  flatbuffers::FlatBufferBuilder &fbb_;
-  flatbuffers::uoffset_t start_;
-  void add_value(flatbuffers::Offset<flatbuffers::Vector<double>> value) {
-    fbb_.AddOffset(ArrayDouble::VT_VALUE, value);
-  }
-  explicit ArrayDoubleBuilder(flatbuffers::FlatBufferBuilder &_fbb)
-        : fbb_(_fbb) {
-    start_ = fbb_.StartTable();
-  }
-  ArrayDoubleBuilder &operator=(const ArrayDoubleBuilder &);
-  flatbuffers::Offset<ArrayDouble> Finish() {
-    const auto end = fbb_.EndTable(start_);
-    auto o = flatbuffers::Offset<ArrayDouble>(end);
-    return o;
-  }
-};
+  struct ArrayDoubleBuilder {
+    flatbuffers::FlatBufferBuilder &fbb_;
+    flatbuffers::uoffset_t start_;
+    void add_value(flatbuffers::Offset<flatbuffers::Vector<double>> value) {
+      fbb_.AddOffset(ArrayDouble::VT_VALUE, value);
+    }
+    explicit ArrayDoubleBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+      : fbb_(_fbb) {
+      start_ = fbb_.StartTable();
+    }
+    ArrayDoubleBuilder &operator=(const ArrayDoubleBuilder &);
+    flatbuffers::Offset<ArrayDouble> Finish() {
+      const auto end = fbb_.EndTable(start_);
+      auto o = flatbuffers::Offset<ArrayDouble>(end);
+      return o;
+    }
+  };
 
-inline flatbuffers::Offset<ArrayDouble> CreateArrayDouble(
+  inline flatbuffers::Offset<ArrayDouble> CreateArrayDouble(
     flatbuffers::FlatBufferBuilder &_fbb,
     flatbuffers::Offset<flatbuffers::Vector<double>> value = 0) {
-  ArrayDoubleBuilder builder_(_fbb);
-  builder_.add_value(value);
-  return builder_.Finish();
-}
+    ArrayDoubleBuilder builder_(_fbb);
+    builder_.add_value(value);
+    return builder_.Finish();
+  }
 
-inline flatbuffers::Offset<ArrayDouble> CreateArrayDoubleDirect(
+  inline flatbuffers::Offset<ArrayDouble> CreateArrayDoubleDirect(
     flatbuffers::FlatBufferBuilder &_fbb,
     const std::vector<double> *value = nullptr) {
-  return CreateArrayDouble(
+    return CreateArrayDouble(
       _fbb,
       value ? _fbb.CreateVector<double>(*value) : 0);
-}
-
-struct DimensionMetaData FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
-  enum {
-    VT_LENGTH = 4,
-    VT_UNIT = 6,
-    VT_LABEL = 8,
-    VT_BIN_BOUNDARIES_TYPE = 10,
-    VT_BIN_BOUNDARIES = 12
-  };
-  uint32_t length() const {
-    return GetField<uint32_t>(VT_LENGTH, 0);
-  }
-  const flatbuffers::String *unit() const {
-    return GetPointer<const flatbuffers::String *>(VT_UNIT);
-  }
-  const flatbuffers::String *label() const {
-    return GetPointer<const flatbuffers::String *>(VT_LABEL);
-  }
-  Array bin_boundaries_type() const {
-    return static_cast<Array>(GetField<uint8_t>(VT_BIN_BOUNDARIES_TYPE, 0));
-  }
-  const void *bin_boundaries() const {
-    return GetPointer<const void *>(VT_BIN_BOUNDARIES);
-  }
-  template<typename T> const T *bin_boundaries_as() const;
-  const ArrayUInt *bin_boundaries_as_ArrayUInt() const {
-    return bin_boundaries_type() == Array_ArrayUInt ? static_cast<const ArrayUInt *>(bin_boundaries()) : nullptr;
   }
-  const ArrayULong *bin_boundaries_as_ArrayULong() const {
-    return bin_boundaries_type() == Array_ArrayULong ? static_cast<const ArrayULong *>(bin_boundaries()) : nullptr;
-  }
-  const ArrayDouble *bin_boundaries_as_ArrayDouble() const {
-    return bin_boundaries_type() == Array_ArrayDouble ? static_cast<const ArrayDouble *>(bin_boundaries()) : nullptr;
-  }
-  bool Verify(flatbuffers::Verifier &verifier) const {
-    return VerifyTableStart(verifier) &&
-           VerifyField<uint32_t>(verifier, VT_LENGTH) &&
-           VerifyOffset(verifier, VT_UNIT) &&
-           verifier.Verify(unit()) &&
-           VerifyOffset(verifier, VT_LABEL) &&
-           verifier.Verify(label()) &&
-           VerifyField<uint8_t>(verifier, VT_BIN_BOUNDARIES_TYPE) &&
-           VerifyOffset(verifier, VT_BIN_BOUNDARIES) &&
-           VerifyArray(verifier, bin_boundaries(), bin_boundaries_type()) &&
-           verifier.EndTable();
-  }
-};
-
-template<> inline const ArrayUInt *DimensionMetaData::bin_boundaries_as<ArrayUInt>() const {
-  return bin_boundaries_as_ArrayUInt();
-}
 
-template<> inline const ArrayULong *DimensionMetaData::bin_boundaries_as<ArrayULong>() const {
-  return bin_boundaries_as_ArrayULong();
-}
-
-template<> inline const ArrayDouble *DimensionMetaData::bin_boundaries_as<ArrayDouble>() const {
-  return bin_boundaries_as_ArrayDouble();
-}
+  struct DimensionMetaData FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+    enum {
+      VT_LENGTH = 4,
+      VT_UNIT = 6,
+      VT_LABEL = 8,
+      VT_BIN_BOUNDARIES_TYPE = 10,
+      VT_BIN_BOUNDARIES = 12
+    };
+    uint32_t length() const {
+      return GetField<uint32_t>(VT_LENGTH, 0);
+    }
+    const flatbuffers::String *unit() const {
+      return GetPointer<const flatbuffers::String *>(VT_UNIT);
+    }
+    const flatbuffers::String *label() const {
+      return GetPointer<const flatbuffers::String *>(VT_LABEL);
+    }
+    Array bin_boundaries_type() const {
+      return static_cast<Array>(GetField<uint8_t>(VT_BIN_BOUNDARIES_TYPE, 0));
+    }
+    const void *bin_boundaries() const {
+      return GetPointer<const void *>(VT_BIN_BOUNDARIES);
+    }
+    template<typename T> const T *bin_boundaries_as() const;
+    const ArrayUInt *bin_boundaries_as_ArrayUInt() const {
+      return bin_boundaries_type() == Array_ArrayUInt ? static_cast<const ArrayUInt *>(bin_boundaries()) : nullptr;
+    }
+    const ArrayULong *bin_boundaries_as_ArrayULong() const {
+      return bin_boundaries_type() == Array_ArrayULong ? static_cast<const ArrayULong *>(bin_boundaries()) : nullptr;
+    }
+    const ArrayDouble *bin_boundaries_as_ArrayDouble() const {
+      return bin_boundaries_type() == Array_ArrayDouble ? static_cast<const ArrayDouble *>(bin_boundaries()) : nullptr;
+    }
+    bool Verify(flatbuffers::Verifier &verifier) const {
+      return VerifyTableStart(verifier) &&
+        VerifyField<uint32_t>(verifier, VT_LENGTH) &&
+        VerifyOffset(verifier, VT_UNIT) &&
+        verifier.Verify(unit()) &&
+        VerifyOffset(verifier, VT_LABEL) &&
+        verifier.Verify(label()) &&
+        VerifyField<uint8_t>(verifier, VT_BIN_BOUNDARIES_TYPE) &&
+        VerifyOffset(verifier, VT_BIN_BOUNDARIES) &&
+        VerifyArray(verifier, bin_boundaries(), bin_boundaries_type()) &&
+        verifier.EndTable();
+    }
+  };
 
-struct DimensionMetaDataBuilder {
-  flatbuffers::FlatBufferBuilder &fbb_;
-  flatbuffers::uoffset_t start_;
-  void add_length(uint32_t length) {
-    fbb_.AddElement<uint32_t>(DimensionMetaData::VT_LENGTH, length, 0);
-  }
-  void add_unit(flatbuffers::Offset<flatbuffers::String> unit) {
-    fbb_.AddOffset(DimensionMetaData::VT_UNIT, unit);
-  }
-  void add_label(flatbuffers::Offset<flatbuffers::String> label) {
-    fbb_.AddOffset(DimensionMetaData::VT_LABEL, label);
-  }
-  void add_bin_boundaries_type(Array bin_boundaries_type) {
-    fbb_.AddElement<uint8_t>(DimensionMetaData::VT_BIN_BOUNDARIES_TYPE, static_cast<uint8_t>(bin_boundaries_type), 0);
-  }
-  void add_bin_boundaries(flatbuffers::Offset<void> bin_boundaries) {
-    fbb_.AddOffset(DimensionMetaData::VT_BIN_BOUNDARIES, bin_boundaries);
+  template<> inline const ArrayUInt *DimensionMetaData::bin_boundaries_as<ArrayUInt>() const {
+    return bin_boundaries_as_ArrayUInt();
   }
-  explicit DimensionMetaDataBuilder(flatbuffers::FlatBufferBuilder &_fbb)
-        : fbb_(_fbb) {
-    start_ = fbb_.StartTable();
+
+  template<> inline const ArrayULong *DimensionMetaData::bin_boundaries_as<ArrayULong>() const {
+    return bin_boundaries_as_ArrayULong();
   }
-  DimensionMetaDataBuilder &operator=(const DimensionMetaDataBuilder &);
-  flatbuffers::Offset<DimensionMetaData> Finish() {
-    const auto end = fbb_.EndTable(start_);
-    auto o = flatbuffers::Offset<DimensionMetaData>(end);
-    return o;
+
+  template<> inline const ArrayDouble *DimensionMetaData::bin_boundaries_as<ArrayDouble>() const {
+    return bin_boundaries_as_ArrayDouble();
   }
-};
 
-inline flatbuffers::Offset<DimensionMetaData> CreateDimensionMetaData(
+  struct DimensionMetaDataBuilder {
+    flatbuffers::FlatBufferBuilder &fbb_;
+    flatbuffers::uoffset_t start_;
+    void add_length(uint32_t length) {
+      fbb_.AddElement<uint32_t>(DimensionMetaData::VT_LENGTH, length, 0);
+    }
+    void add_unit(flatbuffers::Offset<flatbuffers::String> unit) {
+      fbb_.AddOffset(DimensionMetaData::VT_UNIT, unit);
+    }
+    void add_label(flatbuffers::Offset<flatbuffers::String> label) {
+      fbb_.AddOffset(DimensionMetaData::VT_LABEL, label);
+    }
+    void add_bin_boundaries_type(Array bin_boundaries_type) {
+      fbb_.AddElement<uint8_t>(DimensionMetaData::VT_BIN_BOUNDARIES_TYPE, static_cast<uint8_t>(bin_boundaries_type), 0);
+    }
+    void add_bin_boundaries(flatbuffers::Offset<void> bin_boundaries) {
+      fbb_.AddOffset(DimensionMetaData::VT_BIN_BOUNDARIES, bin_boundaries);
+    }
+    explicit DimensionMetaDataBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+      : fbb_(_fbb) {
+      start_ = fbb_.StartTable();
+    }
+    DimensionMetaDataBuilder &operator=(const DimensionMetaDataBuilder &);
+    flatbuffers::Offset<DimensionMetaData> Finish() {
+      const auto end = fbb_.EndTable(start_);
+      auto o = flatbuffers::Offset<DimensionMetaData>(end);
+      return o;
+    }
+  };
+
+  inline flatbuffers::Offset<DimensionMetaData> CreateDimensionMetaData(
     flatbuffers::FlatBufferBuilder &_fbb,
     uint32_t length = 0,
     flatbuffers::Offset<flatbuffers::String> unit = 0,
     flatbuffers::Offset<flatbuffers::String> label = 0,
     Array bin_boundaries_type = Array_NONE,
     flatbuffers::Offset<void> bin_boundaries = 0) {
-  DimensionMetaDataBuilder builder_(_fbb);
-  builder_.add_bin_boundaries(bin_boundaries);
-  builder_.add_label(label);
-  builder_.add_unit(unit);
-  builder_.add_length(length);
-  builder_.add_bin_boundaries_type(bin_boundaries_type);
-  return builder_.Finish();
-}
+    DimensionMetaDataBuilder builder_(_fbb);
+    builder_.add_bin_boundaries(bin_boundaries);
+    builder_.add_label(label);
+    builder_.add_unit(unit);
+    builder_.add_length(length);
+    builder_.add_bin_boundaries_type(bin_boundaries_type);
+    return builder_.Finish();
+  }
 
-inline flatbuffers::Offset<DimensionMetaData> CreateDimensionMetaDataDirect(
+  inline flatbuffers::Offset<DimensionMetaData> CreateDimensionMetaDataDirect(
     flatbuffers::FlatBufferBuilder &_fbb,
     uint32_t length = 0,
     const char *unit = nullptr,
     const char *label = nullptr,
     Array bin_boundaries_type = Array_NONE,
     flatbuffers::Offset<void> bin_boundaries = 0) {
-  return CreateDimensionMetaData(
+    return CreateDimensionMetaData(
       _fbb,
       length,
       unit ? _fbb.CreateString(unit) : 0,
       label ? _fbb.CreateString(label) : 0,
       bin_boundaries_type,
       bin_boundaries);
-}
+  }
 
-struct EventHistogram FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
-  enum {
-    VT_SOURCE = 4,
-    VT_TIMESTAMP = 6,
-    VT_DIM_METADATA = 8,
-    VT_LAST_METADATA_TIMESTAMP = 10,
-    VT_CURRENT_SHAPE = 12,
-    VT_OFFSET = 14,
-    VT_DATA_TYPE = 16,
-    VT_DATA = 18,
-    VT_ERRORS_TYPE = 20,
-    VT_ERRORS = 22,
-    VT_INFO = 24
+  struct EventHistogram FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+    enum {
+      VT_SOURCE = 4,
+      VT_TIMESTAMP = 6,
+      VT_DIM_METADATA = 8,
+      VT_LAST_METADATA_TIMESTAMP = 10,
+      VT_CURRENT_SHAPE = 12,
+      VT_OFFSET = 14,
+      VT_DATA_TYPE = 16,
+      VT_DATA = 18,
+      VT_ERRORS_TYPE = 20,
+      VT_ERRORS = 22,
+      VT_INFO = 24
+    };
+    const flatbuffers::String *source() const {
+      return GetPointer<const flatbuffers::String *>(VT_SOURCE);
+    }
+    uint64_t timestamp() const {
+      return GetField<uint64_t>(VT_TIMESTAMP, 0);
+    }
+    const flatbuffers::Vector<flatbuffers::Offset<DimensionMetaData>> *dim_metadata() const {
+      return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<DimensionMetaData>> *>(VT_DIM_METADATA);
+    }
+    uint64_t last_metadata_timestamp() const {
+      return GetField<uint64_t>(VT_LAST_METADATA_TIMESTAMP, 0);
+    }
+    const flatbuffers::Vector<uint32_t> *current_shape() const {
+      return GetPointer<const flatbuffers::Vector<uint32_t> *>(VT_CURRENT_SHAPE);
+    }
+    const flatbuffers::Vector<uint32_t> *offset() const {
+      return GetPointer<const flatbuffers::Vector<uint32_t> *>(VT_OFFSET);
+    }
+    Array data_type() const {
+      return static_cast<Array>(GetField<uint8_t>(VT_DATA_TYPE, 0));
+    }
+    const void *data() const {
+      return GetPointer<const void *>(VT_DATA);
+    }
+    template<typename T> const T *data_as() const;
+    const ArrayUInt *data_as_ArrayUInt() const {
+      return data_type() == Array_ArrayUInt ? static_cast<const ArrayUInt *>(data()) : nullptr;
+    }
+    const ArrayULong *data_as_ArrayULong() const {
+      return data_type() == Array_ArrayULong ? static_cast<const ArrayULong *>(data()) : nullptr;
+    }
+    const ArrayDouble *data_as_ArrayDouble() const {
+      return data_type() == Array_ArrayDouble ? static_cast<const ArrayDouble *>(data()) : nullptr;
+    }
+    Array errors_type() const {
+      return static_cast<Array>(GetField<uint8_t>(VT_ERRORS_TYPE, 0));
+    }
+    const void *errors() const {
+      return GetPointer<const void *>(VT_ERRORS);
+    }
+    template<typename T> const T *errors_as() const;
+    const ArrayUInt *errors_as_ArrayUInt() const {
+      return errors_type() == Array_ArrayUInt ? static_cast<const ArrayUInt *>(errors()) : nullptr;
+    }
+    const ArrayULong *errors_as_ArrayULong() const {
+      return errors_type() == Array_ArrayULong ? static_cast<const ArrayULong *>(errors()) : nullptr;
+    }
+    const ArrayDouble *errors_as_ArrayDouble() const {
+      return errors_type() == Array_ArrayDouble ? static_cast<const ArrayDouble *>(errors()) : nullptr;
+    }
+    const flatbuffers::String *info() const {
+      return GetPointer<const flatbuffers::String *>(VT_INFO);
+    }
+    bool Verify(flatbuffers::Verifier &verifier) const {
+      return VerifyTableStart(verifier) &&
+        VerifyOffset(verifier, VT_SOURCE) &&
+        verifier.Verify(source()) &&
+        VerifyField<uint64_t>(verifier, VT_TIMESTAMP) &&
+        VerifyOffset(verifier, VT_DIM_METADATA) &&
+        verifier.Verify(dim_metadata()) &&
+        verifier.VerifyVectorOfTables(dim_metadata()) &&
+        VerifyField<uint64_t>(verifier, VT_LAST_METADATA_TIMESTAMP) &&
+        VerifyOffsetRequired(verifier, VT_CURRENT_SHAPE) &&
+        verifier.Verify(current_shape()) &&
+        VerifyOffset(verifier, VT_OFFSET) &&
+        verifier.Verify(offset()) &&
+        VerifyField<uint8_t>(verifier, VT_DATA_TYPE) &&
+        VerifyOffset(verifier, VT_DATA) &&
+        VerifyArray(verifier, data(), data_type()) &&
+        VerifyField<uint8_t>(verifier, VT_ERRORS_TYPE) &&
+        VerifyOffset(verifier, VT_ERRORS) &&
+        VerifyArray(verifier, errors(), errors_type()) &&
+        VerifyOffset(verifier, VT_INFO) &&
+        verifier.Verify(info()) &&
+        verifier.EndTable();
+    }
   };
-  const flatbuffers::String *source() const {
-    return GetPointer<const flatbuffers::String *>(VT_SOURCE);
-  }
-  uint64_t timestamp() const {
-    return GetField<uint64_t>(VT_TIMESTAMP, 0);
-  }
-  const flatbuffers::Vector<flatbuffers::Offset<DimensionMetaData>> *dim_metadata() const {
-    return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<DimensionMetaData>> *>(VT_DIM_METADATA);
-  }
-  uint64_t last_metadata_timestamp() const {
-    return GetField<uint64_t>(VT_LAST_METADATA_TIMESTAMP, 0);
-  }
-  const flatbuffers::Vector<uint32_t> *current_shape() const {
-    return GetPointer<const flatbuffers::Vector<uint32_t> *>(VT_CURRENT_SHAPE);
-  }
-  const flatbuffers::Vector<uint32_t> *offset() const {
-    return GetPointer<const flatbuffers::Vector<uint32_t> *>(VT_OFFSET);
-  }
-  Array data_type() const {
-    return static_cast<Array>(GetField<uint8_t>(VT_DATA_TYPE, 0));
-  }
-  const void *data() const {
-    return GetPointer<const void *>(VT_DATA);
-  }
-  template<typename T> const T *data_as() const;
-  const ArrayUInt *data_as_ArrayUInt() const {
-    return data_type() == Array_ArrayUInt ? static_cast<const ArrayUInt *>(data()) : nullptr;
-  }
-  const ArrayULong *data_as_ArrayULong() const {
-    return data_type() == Array_ArrayULong ? static_cast<const ArrayULong *>(data()) : nullptr;
-  }
-  const ArrayDouble *data_as_ArrayDouble() const {
-    return data_type() == Array_ArrayDouble ? static_cast<const ArrayDouble *>(data()) : nullptr;
-  }
-  Array errors_type() const {
-    return static_cast<Array>(GetField<uint8_t>(VT_ERRORS_TYPE, 0));
-  }
-  const void *errors() const {
-    return GetPointer<const void *>(VT_ERRORS);
-  }
-  template<typename T> const T *errors_as() const;
-  const ArrayUInt *errors_as_ArrayUInt() const {
-    return errors_type() == Array_ArrayUInt ? static_cast<const ArrayUInt *>(errors()) : nullptr;
-  }
-  const ArrayULong *errors_as_ArrayULong() const {
-    return errors_type() == Array_ArrayULong ? static_cast<const ArrayULong *>(errors()) : nullptr;
-  }
-  const ArrayDouble *errors_as_ArrayDouble() const {
-    return errors_type() == Array_ArrayDouble ? static_cast<const ArrayDouble *>(errors()) : nullptr;
-  }
-  const flatbuffers::String *info() const {
-    return GetPointer<const flatbuffers::String *>(VT_INFO);
-  }
-  bool Verify(flatbuffers::Verifier &verifier) const {
-    return VerifyTableStart(verifier) &&
-           VerifyOffset(verifier, VT_SOURCE) &&
-           verifier.Verify(source()) &&
-           VerifyField<uint64_t>(verifier, VT_TIMESTAMP) &&
-           VerifyOffset(verifier, VT_DIM_METADATA) &&
-           verifier.Verify(dim_metadata()) &&
-           verifier.VerifyVectorOfTables(dim_metadata()) &&
-           VerifyField<uint64_t>(verifier, VT_LAST_METADATA_TIMESTAMP) &&
-           VerifyOffsetRequired(verifier, VT_CURRENT_SHAPE) &&
-           verifier.Verify(current_shape()) &&
-           VerifyOffset(verifier, VT_OFFSET) &&
-           verifier.Verify(offset()) &&
-           VerifyField<uint8_t>(verifier, VT_DATA_TYPE) &&
-           VerifyOffset(verifier, VT_DATA) &&
-           VerifyArray(verifier, data(), data_type()) &&
-           VerifyField<uint8_t>(verifier, VT_ERRORS_TYPE) &&
-           VerifyOffset(verifier, VT_ERRORS) &&
-           VerifyArray(verifier, errors(), errors_type()) &&
-           VerifyOffset(verifier, VT_INFO) &&
-           verifier.Verify(info()) &&
-           verifier.EndTable();
-  }
-};
-
-template<> inline const ArrayUInt *EventHistogram::data_as<ArrayUInt>() const {
-  return data_as_ArrayUInt();
-}
-
-template<> inline const ArrayULong *EventHistogram::data_as<ArrayULong>() const {
-  return data_as_ArrayULong();
-}
-
-template<> inline const ArrayDouble *EventHistogram::data_as<ArrayDouble>() const {
-  return data_as_ArrayDouble();
-}
-
-template<> inline const ArrayUInt *EventHistogram::errors_as<ArrayUInt>() const {
-  return errors_as_ArrayUInt();
-}
-
-template<> inline const ArrayULong *EventHistogram::errors_as<ArrayULong>() const {
-  return errors_as_ArrayULong();
-}
 
-template<> inline const ArrayDouble *EventHistogram::errors_as<ArrayDouble>() const {
-  return errors_as_ArrayDouble();
-}
-
-struct EventHistogramBuilder {
-  flatbuffers::FlatBufferBuilder &fbb_;
-  flatbuffers::uoffset_t start_;
-  void add_source(flatbuffers::Offset<flatbuffers::String> source) {
-    fbb_.AddOffset(EventHistogram::VT_SOURCE, source);
-  }
-  void add_timestamp(uint64_t timestamp) {
-    fbb_.AddElement<uint64_t>(EventHistogram::VT_TIMESTAMP, timestamp, 0);
-  }
-  void add_dim_metadata(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<DimensionMetaData>>> dim_metadata) {
-    fbb_.AddOffset(EventHistogram::VT_DIM_METADATA, dim_metadata);
-  }
-  void add_last_metadata_timestamp(uint64_t last_metadata_timestamp) {
-    fbb_.AddElement<uint64_t>(EventHistogram::VT_LAST_METADATA_TIMESTAMP, last_metadata_timestamp, 0);
-  }
-  void add_current_shape(flatbuffers::Offset<flatbuffers::Vector<uint32_t>> current_shape) {
-    fbb_.AddOffset(EventHistogram::VT_CURRENT_SHAPE, current_shape);
-  }
-  void add_offset(flatbuffers::Offset<flatbuffers::Vector<uint32_t>> offset) {
-    fbb_.AddOffset(EventHistogram::VT_OFFSET, offset);
-  }
-  void add_data_type(Array data_type) {
-    fbb_.AddElement<uint8_t>(EventHistogram::VT_DATA_TYPE, static_cast<uint8_t>(data_type), 0);
+  template<> inline const ArrayUInt *EventHistogram::data_as<ArrayUInt>() const {
+    return data_as_ArrayUInt();
   }
-  void add_data(flatbuffers::Offset<void> data) {
-    fbb_.AddOffset(EventHistogram::VT_DATA, data);
-  }
-  void add_errors_type(Array errors_type) {
-    fbb_.AddElement<uint8_t>(EventHistogram::VT_ERRORS_TYPE, static_cast<uint8_t>(errors_type), 0);
+
+  template<> inline const ArrayULong *EventHistogram::data_as<ArrayULong>() const {
+    return data_as_ArrayULong();
   }
-  void add_errors(flatbuffers::Offset<void> errors) {
-    fbb_.AddOffset(EventHistogram::VT_ERRORS, errors);
+
+  template<> inline const ArrayDouble *EventHistogram::data_as<ArrayDouble>() const {
+    return data_as_ArrayDouble();
   }
-  void add_info(flatbuffers::Offset<flatbuffers::String> info) {
-    fbb_.AddOffset(EventHistogram::VT_INFO, info);
+
+  template<> inline const ArrayUInt *EventHistogram::errors_as<ArrayUInt>() const {
+    return errors_as_ArrayUInt();
   }
-  explicit EventHistogramBuilder(flatbuffers::FlatBufferBuilder &_fbb)
-        : fbb_(_fbb) {
-    start_ = fbb_.StartTable();
+
+  template<> inline const ArrayULong *EventHistogram::errors_as<ArrayULong>() const {
+    return errors_as_ArrayULong();
   }
-  EventHistogramBuilder &operator=(const EventHistogramBuilder &);
-  flatbuffers::Offset<EventHistogram> Finish() {
-    const auto end = fbb_.EndTable(start_);
-    auto o = flatbuffers::Offset<EventHistogram>(end);
-    fbb_.Required(o, EventHistogram::VT_CURRENT_SHAPE);
-    return o;
+
+  template<> inline const ArrayDouble *EventHistogram::errors_as<ArrayDouble>() const {
+    return errors_as_ArrayDouble();
   }
-};
 
-inline flatbuffers::Offset<EventHistogram> CreateEventHistogram(
+  struct EventHistogramBuilder {
+    flatbuffers::FlatBufferBuilder &fbb_;
+    flatbuffers::uoffset_t start_;
+    void add_source(flatbuffers::Offset<flatbuffers::String> source) {
+      fbb_.AddOffset(EventHistogram::VT_SOURCE, source);
+    }
+    void add_timestamp(uint64_t timestamp) {
+      fbb_.AddElement<uint64_t>(EventHistogram::VT_TIMESTAMP, timestamp, 0);
+    }
+    void add_dim_metadata(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<DimensionMetaData>>> dim_metadata) {
+      fbb_.AddOffset(EventHistogram::VT_DIM_METADATA, dim_metadata);
+    }
+    void add_last_metadata_timestamp(uint64_t last_metadata_timestamp) {
+      fbb_.AddElement<uint64_t>(EventHistogram::VT_LAST_METADATA_TIMESTAMP, last_metadata_timestamp, 0);
+    }
+    void add_current_shape(flatbuffers::Offset<flatbuffers::Vector<uint32_t>> current_shape) {
+      fbb_.AddOffset(EventHistogram::VT_CURRENT_SHAPE, current_shape);
+    }
+    void add_offset(flatbuffers::Offset<flatbuffers::Vector<uint32_t>> offset) {
+      fbb_.AddOffset(EventHistogram::VT_OFFSET, offset);
+    }
+    void add_data_type(Array data_type) {
+      fbb_.AddElement<uint8_t>(EventHistogram::VT_DATA_TYPE, static_cast<uint8_t>(data_type), 0);
+    }
+    void add_data(flatbuffers::Offset<void> data) {
+      fbb_.AddOffset(EventHistogram::VT_DATA, data);
+    }
+    void add_errors_type(Array errors_type) {
+      fbb_.AddElement<uint8_t>(EventHistogram::VT_ERRORS_TYPE, static_cast<uint8_t>(errors_type), 0);
+    }
+    void add_errors(flatbuffers::Offset<void> errors) {
+      fbb_.AddOffset(EventHistogram::VT_ERRORS, errors);
+    }
+    void add_info(flatbuffers::Offset<flatbuffers::String> info) {
+      fbb_.AddOffset(EventHistogram::VT_INFO, info);
+    }
+    explicit EventHistogramBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+      : fbb_(_fbb) {
+      start_ = fbb_.StartTable();
+    }
+    EventHistogramBuilder &operator=(const EventHistogramBuilder &);
+    flatbuffers::Offset<EventHistogram> Finish() {
+      const auto end = fbb_.EndTable(start_);
+      auto o = flatbuffers::Offset<EventHistogram>(end);
+      fbb_.Required(o, EventHistogram::VT_CURRENT_SHAPE);
+      return o;
+    }
+  };
+
+  inline flatbuffers::Offset<EventHistogram> CreateEventHistogram(
     flatbuffers::FlatBufferBuilder &_fbb,
     flatbuffers::Offset<flatbuffers::String> source = 0,
     uint64_t timestamp = 0,
@@ -518,22 +522,22 @@ inline flatbuffers::Offset<EventHistogram> CreateEventHistogram(
     Array errors_type = Array_NONE,
     flatbuffers::Offset<void> errors = 0,
     flatbuffers::Offset<flatbuffers::String> info = 0) {
-  EventHistogramBuilder builder_(_fbb);
-  builder_.add_last_metadata_timestamp(last_metadata_timestamp);
-  builder_.add_timestamp(timestamp);
-  builder_.add_info(info);
-  builder_.add_errors(errors);
-  builder_.add_data(data);
-  builder_.add_offset(offset);
-  builder_.add_current_shape(current_shape);
-  builder_.add_dim_metadata(dim_metadata);
-  builder_.add_source(source);
-  builder_.add_errors_type(errors_type);
-  builder_.add_data_type(data_type);
-  return builder_.Finish();
-}
-
-inline flatbuffers::Offset<EventHistogram> CreateEventHistogramDirect(
+    EventHistogramBuilder builder_(_fbb);
+    builder_.add_last_metadata_timestamp(last_metadata_timestamp);
+    builder_.add_timestamp(timestamp);
+    builder_.add_info(info);
+    builder_.add_errors(errors);
+    builder_.add_data(data);
+    builder_.add_offset(offset);
+    builder_.add_current_shape(current_shape);
+    builder_.add_dim_metadata(dim_metadata);
+    builder_.add_source(source);
+    builder_.add_errors_type(errors_type);
+    builder_.add_data_type(data_type);
+    return builder_.Finish();
+  }
+
+  inline flatbuffers::Offset<EventHistogram> CreateEventHistogramDirect(
     flatbuffers::FlatBufferBuilder &_fbb,
     const char *source = nullptr,
     uint64_t timestamp = 0,
@@ -546,7 +550,7 @@ inline flatbuffers::Offset<EventHistogram> CreateEventHistogramDirect(
     Array errors_type = Array_NONE,
     flatbuffers::Offset<void> errors = 0,
     const char *info = nullptr) {
-  return CreateEventHistogram(
+    return CreateEventHistogram(
       _fbb,
       source ? _fbb.CreateString(source) : 0,
       timestamp,
@@ -559,10 +563,10 @@ inline flatbuffers::Offset<EventHistogram> CreateEventHistogramDirect(
       errors_type,
       errors,
       info ? _fbb.CreateString(info) : 0);
-}
+  }
 
-inline bool VerifyArray(flatbuffers::Verifier &verifier, const void *obj, Array type) {
-  switch (type) {
+  inline bool VerifyArray(flatbuffers::Verifier &verifier, const void *obj, Array type) {
+    switch (type) {
     case Array_NONE: {
       return true;
     }
@@ -579,59 +583,60 @@ inline bool VerifyArray(flatbuffers::Verifier &verifier, const void *obj, Array
       return verifier.VerifyTable(ptr);
     }
     default: return false;
+    }
   }
-}
 
-inline bool VerifyArrayVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector<flatbuffers::Offset<void>> *values, const flatbuffers::Vector<uint8_t> *types) {
-  if (!values || !types) return !values && !types;
-  if (values->size() != types->size()) return false;
-  for (flatbuffers::uoffset_t i = 0; i < values->size(); ++i) {
-    if (!VerifyArray(
-        verifier,  values->Get(i), types->GetEnum<Array>(i))) {
-      return false;
+  inline bool VerifyArrayVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector<flatbuffers::Offset<void>> *values, const flatbuffers::Vector<uint8_t> *types) {
+    if (!values || !types) return !values && !types;
+    if (values->size() != types->size()) return false;
+    for (flatbuffers::uoffset_t i = 0; i < values->size(); ++i) {
+      if (!VerifyArray(
+        verifier, values->Get(i), types->GetEnum<Array>(i))) {
+        return false;
+      }
     }
+    return true;
   }
-  return true;
-}
 
-inline const EventHistogram *GetEventHistogram(const void *buf) {
-  return flatbuffers::GetRoot<EventHistogram>(buf);
-}
+  inline const EventHistogram *GetEventHistogram(const void *buf) {
+    return flatbuffers::GetRoot<EventHistogram>(buf);
+  }
 
-inline const EventHistogram *GetSizePrefixedEventHistogram(const void *buf) {
-  return flatbuffers::GetSizePrefixedRoot<EventHistogram>(buf);
-}
+  inline const EventHistogram *GetSizePrefixedEventHistogram(const void *buf) {
+    return flatbuffers::GetSizePrefixedRoot<EventHistogram>(buf);
+  }
 
-inline const char *EventHistogramIdentifier() {
-  return "hs00";
-}
+  inline const char *EventHistogramIdentifier() {
+    return "hs00";
+  }
 
-inline bool EventHistogramBufferHasIdentifier(const void *buf) {
-  return flatbuffers::BufferHasIdentifier(
+  inline bool EventHistogramBufferHasIdentifier(const void *buf) {
+    return flatbuffers::BufferHasIdentifier(
       buf, EventHistogramIdentifier());
-}
+  }
 
-inline bool VerifyEventHistogramBuffer(
+  inline bool VerifyEventHistogramBuffer(
     flatbuffers::Verifier &verifier) {
-  return verifier.VerifyBuffer<EventHistogram>(EventHistogramIdentifier());
-}
+    return verifier.VerifyBuffer<EventHistogram>(EventHistogramIdentifier());
+  }
 
-inline bool VerifySizePrefixedEventHistogramBuffer(
+  inline bool VerifySizePrefixedEventHistogramBuffer(
     flatbuffers::Verifier &verifier) {
-  return verifier.VerifySizePrefixedBuffer<EventHistogram>(EventHistogramIdentifier());
-}
+    return verifier.VerifySizePrefixedBuffer<EventHistogram>(EventHistogramIdentifier());
+  }
 
-inline void FinishEventHistogramBuffer(
+  inline void FinishEventHistogramBuffer(
     flatbuffers::FlatBufferBuilder &fbb,
     flatbuffers::Offset<EventHistogram> root) {
-  fbb.Finish(root, EventHistogramIdentifier());
-}
+    fbb.Finish(root, EventHistogramIdentifier());
+  }
 
-inline void FinishSizePrefixedEventHistogramBuffer(
+  inline void FinishSizePrefixedEventHistogramBuffer(
     flatbuffers::FlatBufferBuilder &fbb,
     flatbuffers::Offset<EventHistogram> root) {
-  fbb.FinishSizePrefixed(root, EventHistogramIdentifier());
-}
+    fbb.FinishSizePrefixed(root, EventHistogramIdentifier());
+  }
 
+}
 #endif  // FLATBUFFERS_GENERATED_HS00EVENTHISTOGRAM_H_
 // clang-format on
diff --git a/Framework/LiveData/test/KafkaHistoStreamDecoderTest.h b/Framework/LiveData/test/KafkaHistoStreamDecoderTest.h
new file mode 100644
index 00000000000..d23e084e3ce
--- /dev/null
+++ b/Framework/LiveData/test/KafkaHistoStreamDecoderTest.h
@@ -0,0 +1,189 @@
+// Mantid Repository : https://github.com/mantidproject/mantid
+//
+// Copyright &copy; 2018 ISIS Rutherford Appleton Laboratory UKRI,
+//     NScD Oak Ridge National Laboratory, European Spallation Source
+//     & Institut Laue - Langevin
+// SPDX - License - Identifier: GPL - 3.0 +
+#ifndef MANTID_LIVEDATA_KAFKAHISTOSTREAMDECODERTEST_H_
+#define MANTID_LIVEDATA_KAFKAHISTOSTREAMDECODERTEST_H_
+
+#include <cxxtest/TestSuite.h>
+
+#include "KafkaTesting.h"
+#include "MantidAPI/Run.h"
+#include "MantidGeometry/Instrument.h"
+#include "MantidHistogramData/FixedLengthVector.h"
+#include "MantidHistogramData/HistogramX.h"
+#include "MantidHistogramData/HistogramY.h"
+#include "MantidKernel/ConfigService.h"
+#include "MantidKernel/TimeSeriesProperty.h"
+#include "MantidKernel/make_unique.h"
+#include "MantidLiveData/Kafka/KafkaHistoStreamDecoder.h"
+#include <Poco/Path.h>
+
+using Mantid::LiveData::KafkaHistoStreamDecoder;
+using namespace KafkaTesting;
+
+class KafkaHistoStreamDecoderTest : public CxxTest::TestSuite {
+public:
+  // This pair of boilerplate methods prevent the suite being created statically
+  // This means the constructor isn't called when running other tests
+  static KafkaHistoStreamDecoderTest *createSuite() {
+    return new KafkaHistoStreamDecoderTest();
+  }
+  static void destroySuite(KafkaHistoStreamDecoderTest *suite) { delete suite; }
+
+  void setUp() override {
+    // Temporarily change the instrument directory to the testing one
+    using Mantid::Kernel::ConfigService;
+    auto &config = ConfigService::Instance();
+    auto baseInstDir = config.getInstrumentDirectory();
+    Poco::Path testFile =
+        Poco::Path(baseInstDir)
+            .resolve("IDFs_for_UNIT_TESTING/UnitTestFacilities.xml");
+    // Load the test facilities file
+    config.updateFacilities(testFile.toString());
+    config.setFacility("TEST");
+    // Update instrument search directory
+    config.setString("instrumentDefinition.directory",
+                     baseInstDir + "/IDFs_for_UNIT_TESTING");
+  }
+
+  void tearDown() override {
+    using Mantid::Kernel::ConfigService;
+    auto &config = ConfigService::Instance();
+    config.reset();
+    // Restore the main facilities file
+    config.updateFacilities();
+  }
+
+  void test_Histo_Stream() {
+    using namespace ::testing;
+    using namespace KafkaTesting;
+    using Mantid::API::Workspace_sptr;
+    using Mantid::DataObjects::Workspace2D;
+    using namespace Mantid::LiveData;
+
+    auto mockBroker = std::make_shared<MockKafkaBroker>();
+    EXPECT_CALL(*mockBroker, subscribe_(_, _))
+        .Times(Exactly(3))
+        .WillOnce(Return(new FakeHistoSubscriber()))
+        .WillOnce(Return(new FakeRunInfoStreamSubscriber(1)))
+        .WillOnce(Return(new FakeISISSpDetStreamSubscriber));
+    auto decoder = createTestDecoder(mockBroker);
+    TSM_ASSERT("Decoder should not have create data buffers yet",
+               !decoder->hasData());
+    startCapturing(*decoder, 1);
+
+    // Checks
+    Workspace_sptr workspace;
+    TSM_ASSERT("Decoder's data buffers should be created now",
+               decoder->hasData());
+    TS_ASSERT_THROWS_NOTHING(workspace = decoder->extractData());
+    TS_ASSERT_THROWS_NOTHING(decoder->stopCapture());
+    TS_ASSERT(!decoder->isCapturing());
+
+    // -- Workspace checks --
+    TSM_ASSERT("Expected non-null workspace pointer from extractData()",
+               workspace);
+    auto histoWksp = boost::dynamic_pointer_cast<Workspace2D>(workspace);
+    TSM_ASSERT(
+        "Expected a Workspace2D from extractData(). Found something else",
+        histoWksp);
+    checkWorkspaceMetadata(*histoWksp);
+    checkWorkspaceHistoData(*histoWksp);
+  }
+
+private:
+  std::unique_ptr<Mantid::LiveData::KafkaHistoStreamDecoder>
+  createTestDecoder(std::shared_ptr<Mantid::LiveData::IKafkaBroker> broker) {
+    using namespace Mantid::LiveData;
+    return Mantid::Kernel::make_unique<KafkaHistoStreamDecoder>(broker, "", "",
+                                                                "", "");
+  }
+
+  // Start decoding and wait until we have gathered enough data to test
+  void startCapturing(Mantid::LiveData::KafkaHistoStreamDecoder &decoder,
+                      uint8_t maxIterations) {
+    // Register callback to know when a whole loop as been iterated through
+    m_niterations = 0;
+    auto callback = [this, maxIterations]() {
+      this->iterationCallback(maxIterations);
+    };
+    decoder.registerIterationEndCb(callback);
+    decoder.registerErrorCb(callback);
+    TS_ASSERT_THROWS_NOTHING(decoder.startCapture());
+    continueCapturing(decoder, maxIterations);
+  }
+
+  void iterationCallback(uint8_t maxIterations) {
+    std::unique_lock<std::mutex> lock(this->m_callbackMutex);
+    this->m_niterations++;
+    if (this->m_niterations == maxIterations) {
+      lock.unlock();
+      this->m_callbackCondition.notify_one();
+    }
+  }
+
+  void continueCapturing(Mantid::LiveData::KafkaHistoStreamDecoder &decoder,
+                         uint8_t maxIterations) {
+    // Re-register callback with the (potentially) new value of maxIterations
+    auto callback = [this, maxIterations]() {
+      this->iterationCallback(maxIterations);
+    };
+    decoder.registerIterationEndCb(callback);
+    decoder.registerErrorCb(callback);
+    {
+      std::unique_lock<std::mutex> lk(m_callbackMutex);
+      this->m_callbackCondition.wait(lk, [this, maxIterations]() {
+        return this->m_niterations == maxIterations;
+      });
+    }
+  }
+
+  void
+  checkWorkspaceMetadata(const Mantid::DataObjects::Workspace2D &histoWksp) {
+    TS_ASSERT(histoWksp.getInstrument());
+    TS_ASSERT_EQUALS("HRPDTEST", histoWksp.getInstrument()->getName());
+    TS_ASSERT_EQUALS(
+        "2016-08-31T12:07:42",
+        histoWksp.run().getPropertyValueAsType<std::string>("run_start"));
+    std::array<Mantid::specnum_t, 5> specs = {{1, 2, 3, 4, 5}};
+    std::array<Mantid::detid_t, 5> ids = {{1001, 1002, 1100, 901000, 10100}};
+    TS_ASSERT_EQUALS(specs.size(), histoWksp.getNumberHistograms());
+    for (size_t i = 0; i < histoWksp.getNumberHistograms(); ++i) {
+      const auto &spec = histoWksp.getSpectrum(i);
+      TS_ASSERT_EQUALS(specs[i], spec.getSpectrumNo());
+      const auto &sid = spec.getDetectorIDs();
+      TS_ASSERT_EQUALS(ids[i], *(sid.begin()));
+    }
+  }
+
+  void
+  checkWorkspaceHistoData(const Mantid::DataObjects::Workspace2D &histoWksp) {
+    // Inspect all 5 HRPDTEST Spectra
+    auto data = histoWksp.histogram(0);
+    // std::vector<double> xbins(data.x().cbegin(), data.x().cend());
+    TS_ASSERT_EQUALS(data.x().rawData(), (std::vector<double>{0, 1, 2}));
+    TS_ASSERT_EQUALS(data.y().rawData(), (std::vector<double>{100, 140}));
+
+    data = histoWksp.histogram(1);
+    TS_ASSERT_EQUALS(data.y().rawData(), (std::vector<double>{210, 100}));
+
+    data = histoWksp.histogram(2);
+    TS_ASSERT_EQUALS(data.y().rawData(), (std::vector<double>{110, 70}));
+
+    data = histoWksp.histogram(3);
+    TS_ASSERT_EQUALS(data.y().rawData(), (std::vector<double>{5, 3}));
+
+    data = histoWksp.histogram(4);
+    TS_ASSERT_EQUALS(data.y().rawData(), (std::vector<double>{20, 4}));
+  }
+
+private:
+  std::mutex m_callbackMutex;
+  std::condition_variable m_callbackCondition;
+  uint8_t m_niterations = 0;
+};
+
+#endif /* MANTID_LIVEDATA_KAFKAHISTOSTREAMDECODERTEST_H_ */
\ No newline at end of file
diff --git a/Framework/LiveData/test/KafkaTesting.h b/Framework/LiveData/test/KafkaTesting.h
index 5b470219653..b8fec70e8a6 100644
--- a/Framework/LiveData/test/KafkaTesting.h
+++ b/Framework/LiveData/test/KafkaTesting.h
@@ -20,6 +20,7 @@ GNU_DIAG_OFF("conversion")
 #include "Kafka/private/Schema/ev42_events_generated.h"
 #include "Kafka/private/Schema/f142_logdata_generated.h"
 #include "Kafka/private/Schema/is84_isis_events_generated.h"
+#include "kafka/private/Schema/hs00_event_histogram_generated.h"
 GNU_DIAG_ON("conversion")
 
 #include <ctime>
@@ -134,6 +135,7 @@ public:
   }
 };
 
+namespace {
 void fakeReceiveAnISISEventMessage(std::string *buffer, int32_t nextPeriod) {
   flatbuffers::FlatBufferBuilder builder;
   std::vector<uint32_t> spec = {5, 4, 3, 2, 1, 2};
@@ -172,12 +174,43 @@ void fakeReceiveAnEventMessage(std::string *buffer) {
                  builder.GetSize());
 }
 
+void fakeReceiveHistoMessage(std::string *buffer) {
+  flatbuffers::FlatBufferBuilder builder;
+  // shape is binedges=2 nspectra=5
+  std::vector<uint32_t> current_shape{3, 5};
+  auto bin_edges = builder.CreateVector(std::vector<double>{0, 1, 2});
+  auto xbins = HistoSchema::CreateArrayDouble(builder, bin_edges);
+  auto bin_metadata = HistoSchema::CreateDimensionMetaData(
+      builder, 3, builder.CreateString("TOF"), builder.CreateString("TOF"),
+      HistoSchema::Array_ArrayDouble, xbins.Union());
+  auto unit_metadata = HistoSchema::CreateDimensionMetaData(
+      builder, 1, builder.CreateString("Counts"));
+
+  auto dim_metadata = builder.CreateVector(
+      std::vector<flatbuffers::Offset<HistoSchema::DimensionMetaData>>{
+          bin_metadata, unit_metadata});
+
+  // Data values are nspectra*nbins
+  auto data_values = builder.CreateVector(
+      std::vector<double>{100, 140, 210, 100, 110, 70, 5, 3, 20, 4});
+  auto data = HistoSchema::CreateArrayDouble(builder, data_values);
+
+  auto messageFlatBuf = HistoSchema::CreateEventHistogram(
+      builder, builder.CreateString("KafkaTesting"), 0, dim_metadata, 0,
+      builder.CreateVector(current_shape), 0, HistoSchema::Array_ArrayDouble,
+      data.Union());
+
+  FinishEventHistogramBuffer(builder, messageFlatBuf);
+  buffer->assign(reinterpret_cast<const char *>(builder.GetBufferPointer()),
+                 builder.GetSize());
+}
+
 void fakeReceiveASampleEnvMessage(std::string *buffer) {
   flatbuffers::FlatBufferBuilder builder;
   // Sample environment log
-  auto logDataMessage =
-      CreateLogData(builder, builder.CreateString("fake source"), Value_Int,
-                    CreateInt(builder, 42).Union(), 1495618188000000000L);
+  auto logDataMessage = LogSchema::CreateLogData(
+      builder, builder.CreateString("fake source"), LogSchema::Value_Int,
+      LogSchema::CreateInt(builder, 42).Union(), 1495618188000000000L);
   FinishLogDataBuffer(builder, logDataMessage);
 
   // Copy to provided buffer
@@ -221,7 +254,7 @@ void fakeReceiveARunStopMessage(std::string *buffer,
   buffer->assign(reinterpret_cast<const char *>(builder.GetBufferPointer()),
                  builder.GetSize());
 }
-
+} // namespace
 // -----------------------------------------------------------------------------
 // Fake ISIS event stream to provide event and sample environment data
 // -----------------------------------------------------------------------------
@@ -281,6 +314,61 @@ public:
                       std::string &topic) override {
     assert(message);
 
+    switch (m_nextOffset) {
+    // case 0:
+    //  fakeReceiveARunStartMessage(message, 1000, "2016-08-31T12:07:42",
+    //                              "HRPDTEST", 1);
+    //  break;
+    case 1:
+      fakeReceiveARunStopMessage(message, m_stopTime);
+      break;
+    default:
+      fakeReceiveAnEventMessage(message);
+    }
+    m_nextOffset++;
+
+    UNUSED_ARG(offset);
+    UNUSED_ARG(partition);
+    UNUSED_ARG(topic);
+  }
+
+  std::unordered_map<std::string, std::vector<int64_t>>
+  getOffsetsForTimestamp(int64_t timestamp) override {
+    UNUSED_ARG(timestamp);
+    return {std::pair<std::string, std::vector<int64_t>>(m_topicName, {1})};
+  }
+
+  std::unordered_map<std::string, std::vector<int64_t>>
+  getCurrentOffsets() override {
+    std::unordered_map<std::string, std::vector<int64_t>> offsets;
+    return {std::pair<std::string, std::vector<int64_t>>(m_topicName, {1})};
+  }
+
+  void seek(const std::string &topic, uint32_t partition,
+            int64_t offset) override {
+    UNUSED_ARG(topic);
+    UNUSED_ARG(partition);
+    UNUSED_ARG(offset);
+  }
+
+private:
+  std::string m_topicName = "topic_name";
+  int m_nextOffset = 0;
+  std::string m_stopTime = "2016-08-31T12:07:52";
+};
+
+// ---------------------------------------------------------------------------------------
+// Fake non-institution-specific histo stream to provide histogram and sample
+// environment data
+// ---------------------------------------------------------------------------------------
+class FakeHistoSubscriber : public Mantid::LiveData::IKafkaStreamSubscriber {
+public:
+  void subscribe() override {}
+  void subscribe(int64_t offset) override { UNUSED_ARG(offset) }
+  void consumeMessage(std::string *message, int64_t &offset, int32_t &partition,
+                      std::string &topic) override {
+    assert(message);
+
     switch (m_nextOffset) {
     case 0:
       fakeReceiveARunStartMessage(message, 1000, "2016-08-31T12:07:42",
@@ -290,7 +378,7 @@ public:
       fakeReceiveARunStopMessage(message, m_stopTime);
       break;
     default:
-      fakeReceiveAnEventMessage(message);
+      fakeReceiveHistoMessage(message);
     }
     m_nextOffset++;
 
-- 
GitLab