From 56c120ef8d4844576ead633fb2eedf60ca4c4a1a Mon Sep 17 00:00:00 2001
From: Manos Angelidis <angelidis@fortiss.org>
Date: Wed, 6 Nov 2019 15:14:22 +0000
Subject: [PATCH] Merged in ubuntu18 (pull request #31)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

[NRRPLT-6970] Update gzbridge to OSRF repository

ref. ec3a56cb7f10597fc639d2e7980968bd49334abc

Approved-by: Florian Grötzner <groetzner@fortiss.org>
Approved-by: Ugo Albanese <ugo.albanese@santannapisa.it>
---
 deploy-gzbridge-nrp.sh         |   9 -
 gzbridge/CMakeLists.txt        |  12 -
 gzbridge/ConfigLoader.hh       |   4 +-
 gzbridge/GZNode.cc             | 339 ++++++++++-----------
 gzbridge/GZNode.hh             |  71 ++---
 gzbridge/GazeboInterface.cc    | 534 +++++++++++++++++++++------------
 gzbridge/GazeboInterface.hh    | 116 ++++---
 gzbridge/OgreMaterialParser.cc |   7 +-
 gzbridge/OgreMaterialParser.hh |   6 +-
 gzbridge/pb2json.cc            | 131 +++++++-
 gzbridge/pb2json.hh            |  67 ++++-
 gzbridge/server.js             | 175 +++++++++++
 gzbridge/ws_server.js          | 152 ----------
 tools/gzcoarse.cc              |  24 ++
 14 files changed, 983 insertions(+), 664 deletions(-)
 create mode 100755 gzbridge/server.js
 delete mode 100755 gzbridge/ws_server.js

diff --git a/deploy-gzbridge-nrp.sh b/deploy-gzbridge-nrp.sh
index be72a62..42aed7e 100755
--- a/deploy-gzbridge-nrp.sh
+++ b/deploy-gzbridge-nrp.sh
@@ -4,15 +4,6 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
 cd $DIR
 
 source $HOME/.bashrc
-[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"
-if ! node --version | grep  -q v0.10
-then
-  if ! nvm use 0.10 2>/dev/null
-  then
-    printf "\033[0;31mYou must use node v0.10 or use nvm and install v0.10 (ie. nvm install 0.10)\033[0m\n"
-    exit 1
-  fi
-fi
 
 # Install node modules
 npm install
diff --git a/gzbridge/CMakeLists.txt b/gzbridge/CMakeLists.txt
index 42e850d..db9c15c 100644
--- a/gzbridge/CMakeLists.txt
+++ b/gzbridge/CMakeLists.txt
@@ -1,6 +1,5 @@
 include_directories(
   include_directories(${GAZEBO_INCLUDE_DIRS})
-  ${PROJECT_SOURCE_DIR}/deps/libwebsockets/lib
 )
 
 link_directories(${GAZEBO_LIBRARY_DIRS})
@@ -15,14 +14,3 @@ set (headers
   pb2json.hh
   GazeboInterface.hh
 )
-
-# add_executable(gzbridge ${sources})
-
-# target_link_libraries(gzbridge websockets_shared ${GAZEBO_LIBRARIES} ${Boost_LIBRARIES} ${PROTOBUF_LIBRARIES} ${JANSSON_LIBRARIES})
-#add_dependencies(${TEST_NAME} websockets_shared)
-
-# Set test app specific defines.
-# set_property(TARGET gzbridge
-#      PROPERTY COMPILE_DEFINITIONS
-#        INSTALL_DATADIR="${CMAKE_INSTALL_PREFIX}/share"
-#      )
diff --git a/gzbridge/ConfigLoader.hh b/gzbridge/ConfigLoader.hh
index 69a78ec..93db86e 100644
--- a/gzbridge/ConfigLoader.hh
+++ b/gzbridge/ConfigLoader.hh
@@ -1,5 +1,5 @@
-#ifndef _CONFIG_LOADER_HH_
-#define _CONFIG_LOADER_HH_
+#ifndef GZBRIDGE_CONFIG_LOADER_HH_
+#define GZBRIDGE_CONFIG_LOADER_HH_
 
 #include <map>
 #include <vector>
diff --git a/gzbridge/GZNode.cc b/gzbridge/GZNode.cc
index f2cd144..f688edc 100644
--- a/gzbridge/GZNode.cc
+++ b/gzbridge/GZNode.cc
@@ -27,20 +27,27 @@ using namespace gzweb;
 /////////////////////////////////////////////////
 GZNode::GZNode()
 {
-  isGzServerConnected = false;
   if (!gazebo::transport::init()) {
     return;
   }
 
+  this->isGzServerConnected = true;
   this->ConnectGzServer();
-};
+}
 
-GZNode::GZNode(const v8::Arguments& args) {
+GZNode::GZNode(const FunctionCallbackInfo<Value>& args) {
   isGzServerConnected = false;
 
+  Isolate* isolate = args.GetIsolate();
+
   if (args.Length() != 2) {
-    ThrowException(Exception::TypeError(
-        String::New("Wrong number of arguments")));
+    isolate->ThrowException(Exception::TypeError(
+        String::NewFromUtf8(
+            isolate,
+            "Wrong number of arguments"
+            )
+        )
+    );
     return;
   }
 
@@ -53,7 +60,8 @@ GZNode::GZNode(const v8::Arguments& args) {
   }
 
   this->ConnectGzServer();
-};
+
+}
 
 void GZNode::ConnectGzServer() {
   isGzServerConnected = true;
@@ -62,6 +70,7 @@ void GZNode::ConnectGzServer() {
   this->gzIface = new GazeboInterface();
   this->gzIface->Init();
   this->gzIface->RunThread();
+
 }
 
 /////////////////////////////////////////////////
@@ -69,103 +78,80 @@ GZNode::~GZNode()
 {
   // Make sure to shut everything down.
   gazebo::transport::fini();
-};
+}
 
 /////////////////////////////////////////////////
 void GZNode::Init(Handle<Object> exports)
 {
+  Isolate* isolate = exports->GetIsolate();
   // Prepare constructor template
-  Local<FunctionTemplate> tpl = FunctionTemplate::New(New);
-  tpl->SetClassName(String::NewSymbol("GZNode"));
+  Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, New);
+  tpl->SetClassName(String::NewFromUtf8(isolate, "GZNode"));
   tpl->InstanceTemplate()->SetInternalFieldCount(1);
   // Prototype
-  tpl->PrototypeTemplate()->Set(String::NewSymbol("loadMaterialScripts"),
-      FunctionTemplate::New(LoadMaterialScripts)->GetFunction());
-
-  tpl->PrototypeTemplate()->Set(String::NewSymbol("setCallback"),
-      FunctionTemplate::New(Callback)->GetFunction());
+  NODE_SET_PROTOTYPE_METHOD(tpl, "loadMaterialScripts", LoadMaterialScripts);
 
-  tpl->PrototypeTemplate()->Set(String::NewSymbol("request"),
-      FunctionTemplate::New(Request)->GetFunction());
+  NODE_SET_PROTOTYPE_METHOD(tpl, "setConnected", SetConnected);
 
-  tpl->PrototypeTemplate()->Set(String::NewSymbol("getMessages"),
-      FunctionTemplate::New(GetMessages)->GetFunction());
+  NODE_SET_PROTOTYPE_METHOD(tpl, "setPoseMsgFilterMinimumDistanceSquared", SetPoseMsgFilterMinimumDistanceSquared);
+  NODE_SET_PROTOTYPE_METHOD(tpl, "getPoseMsgFilterMinimumDistanceSquared", GetPoseMsgFilterMinimumDistanceSquared);
+  NODE_SET_PROTOTYPE_METHOD(tpl, "setPoseMsgFilterMinimumQuaternionSquared", SetPoseMsgFilterMinimumQuaternionSquared);
+  NODE_SET_PROTOTYPE_METHOD(tpl, "getPoseMsgFilterMinimumQuaternionSquared", GetPoseMsgFilterMinimumQuaternionSquared);
 
-  tpl->PrototypeTemplate()->Set(String::NewSymbol("getPoseMsgFilterMinimumAge"),
-      FunctionTemplate::New(GetPoseMsgFilterMinimumAge)->GetFunction());
+  NODE_SET_PROTOTYPE_METHOD(tpl, "getPoseMsgFilterMinimumAge",
+      GetPoseMsgFilterMinimumAge);
 
-  tpl->PrototypeTemplate()->Set(String::NewSymbol("setPoseMsgFilterMinimumAge"),
-      FunctionTemplate::New(SetPoseMsgFilterMinimumAge)->GetFunction());
+  NODE_SET_PROTOTYPE_METHOD(tpl, "setPoseMsgFilterMinimumAge",
+      SetPoseMsgFilterMinimumAge);
 
-  tpl->PrototypeTemplate()->Set(
-		  String::NewSymbol("getPoseMsgFilterMinimumDistanceSquared"),
-      FunctionTemplate::New(
-    		  GetPoseMsgFilterMinimumDistanceSquared)->GetFunction());
+  NODE_SET_PROTOTYPE_METHOD(tpl, "getMessages", GetMessages);
 
-  tpl->PrototypeTemplate()->Set(
-      String::NewSymbol("setPoseMsgFilterMinimumDistanceSquared"),
-      FunctionTemplate::New(
-          SetPoseMsgFilterMinimumDistanceSquared)->GetFunction());
+  NODE_SET_PROTOTYPE_METHOD(tpl, "request", Request);
 
-  tpl->PrototypeTemplate()->Set(
-      String::NewSymbol("getPoseMsgFilterMinimumQuaternionSquared"),
-      FunctionTemplate::New(
-          GetPoseMsgFilterMinimumQuaternionSquared)->GetFunction());
+  NODE_SET_PROTOTYPE_METHOD(tpl, "getIsGzServerConnected",
+      GetIsGzServerConnected);
 
-  tpl->PrototypeTemplate()->Set(
-      String::NewSymbol("setPoseMsgFilterMinimumQuaternionSquared"),
-      FunctionTemplate::New(
-          SetPoseMsgFilterMinimumQuaternionSquared)->GetFunction());
+  NODE_SET_PROTOTYPE_METHOD(tpl, "getMaterialScriptsMessage",
+      GetMaterialScriptsMessage);
 
-  tpl->PrototypeTemplate()->Set(String::NewSymbol("setConnected"),
-      FunctionTemplate::New(
-          SetConnected)->GetFunction());
-
-  tpl->PrototypeTemplate()->Set(
-       String::NewSymbol("getIsGzServerConnected"),
-       FunctionTemplate::New(
-           GetIsGzServerConnected)->GetFunction());
-
-  tpl->PrototypeTemplate()->Set(String::NewSymbol("getMaterialScriptsMessage"),
-       FunctionTemplate::New(GetMaterialScriptsMessage)->GetFunction());
-
-  Persistent<Function> constructor =
-      Persistent<Function>::New(tpl->GetFunction());
-
-  exports->Set(String::NewSymbol("GZNode"), constructor);
+  exports->Set(String::NewFromUtf8(isolate, "GZNode"),
+               tpl->GetFunction());
 }
 
 /////////////////////////////////////////////////
-Handle<Value> GZNode::New(const Arguments& args)
+void GZNode::New(const FunctionCallbackInfo<Value>& args)
 {
-  HandleScope scope;
-  GZNode* obj;
-
-  if (args.Length() == 0) obj = new GZNode();
-  else if (args.Length() == 2) obj = new GZNode(args);
-
-  obj->Wrap(args.This());
-
-  return args.This();
+  if (args.IsConstructCall()) {
+    // Invoked as constructor: `new MyObject(...)`
+    GZNode* gzObj = nullptr;
+    if (args.Length() == 0)
+	    gzObj = new GZNode();
+    else 
+        if (args.Length() == 2)
+           gzObj = new GZNode(args);
+
+    gzObj->Wrap(args.This());
+    args.GetReturnValue().Set(args.This());
+  }
 }
 
 /////////////////////////////////////////////////
-Handle<Value> GZNode::LoadMaterialScripts(const Arguments& args)
+void GZNode::LoadMaterialScripts(const FunctionCallbackInfo<Value>& args)
 {
-  HandleScope scope;
+  Isolate* isolate = args.GetIsolate();
 
   if (args.Length() < 1)
   {
-    ThrowException(Exception::TypeError(
-        String::New("Wrong number of arguments")));
-    return scope.Close(Undefined());
+    isolate->ThrowException(Exception::TypeError(
+        String::NewFromUtf8(isolate, "Wrong number of arguments")));
+    return;
   }
 
   if (!args[0]->IsString())
   {
-    ThrowException(Exception::TypeError(
-        String::New("Wrong argument type. String expected.")));
-    return scope.Close(Undefined());
+    isolate->ThrowException(Exception::TypeError(
+        String::NewFromUtf8(isolate, "Wrong argument type. String expected.")));
+    return;
   }
 
   GZNode* obj = ObjectWrap::Unwrap<GZNode>(args.This());
@@ -173,187 +159,170 @@ Handle<Value> GZNode::LoadMaterialScripts(const Arguments& args)
   String::Utf8Value path(args[0]->ToString());
   obj->gzIface->LoadMaterialScripts(std::string(*path));
 
-  return scope.Close(Undefined());
+  return;
 }
 
-Handle<Value> GZNode::GetMaterialScriptsMessage(const Arguments& args)
+/////////////////////////////////////////////////
+void GZNode::SetConnected(const FunctionCallbackInfo<Value>& args)
 {
-  HandleScope scope;
-
-  if (args.Length() < 1)
-   {
-     ThrowException(Exception::TypeError(
-         String::New("Wrong number of arguments")));
-     return scope.Close(Undefined());
-   }
-
-   if (!args[0]->IsString())
-   {
-     ThrowException(Exception::TypeError(
-         String::New("Wrong argument type. String expected.")));
-     return scope.Close(Undefined());
-   }
+  GZNode *obj = ObjectWrap::Unwrap<GZNode>(args.This());
+  bool value = args[0]->BooleanValue();
+  obj->gzIface->SetConnected(value);
 
-   String::Utf8Value path(args[0]->ToString());
+  return;
+}
 
-  OgreMaterialParser materialParser;
-  materialParser.Load(std::string(*path));
-  std::string topic = "~/material";
-  std::string materialJson = materialParser.GetMaterialAsJson();
-  std::string msg;
-  msg += "{\"op\":\"publish\",\"topic\":\"" + topic + "\", \"msg\":";
-  msg += materialJson;
-  msg += "}";
+/////////////////////////////////////////////////
+void GZNode::GetIsGzServerConnected(const FunctionCallbackInfo<Value>& args)
+{
+  GZNode *obj = ObjectWrap::Unwrap<GZNode>(args.This());
+  bool value = obj->isGzServerConnected;
 
-  return scope.Close(String::New(msg.c_str()));
+  args.GetReturnValue().Set(value);
 }
 
 /////////////////////////////////////////////////
-Handle<Value> GZNode::Request(const Arguments& args)
+void GZNode::GetMaterialScriptsMessage(const FunctionCallbackInfo<Value>& args)
 {
-  HandleScope scope;
+  Isolate* isolate = args.GetIsolate();
 
   if (args.Length() < 1)
   {
-    ThrowException(Exception::TypeError(
-        String::New("Wrong number of arguments")));
-    return scope.Close(Undefined());
+    isolate->ThrowException(Exception::TypeError(
+        String::NewFromUtf8(isolate, "Wrong number of arguments")));
+    return;
   }
 
   if (!args[0]->IsString())
   {
-    ThrowException(Exception::TypeError(
-        String::New("Wrong argument type. String expected.")));
-    return scope.Close(Undefined());
+    isolate->ThrowException(Exception::TypeError(
+        String::NewFromUtf8(isolate, "Wrong argument type. String expected.")));
+    return;
   }
 
-  GZNode* obj = ObjectWrap::Unwrap<GZNode>(args.This());
-
-  String::Utf8Value request(args[0]->ToString());
-  obj->gzIface->PushRequest(std::string(*request));
-
-  return scope.Close(Undefined());
-}
-
-/////////////////////////////////////////////////
-Handle<Value> GZNode::Callback(const Arguments& args) {
-  HandleScope scope;
+  String::Utf8Value path(args[0]->ToString());
 
-  v8::Local<v8::Function> cb = Local<Function>::Cast(args[0]);
-  const unsigned argc = 1;
-  Local<Value> argv[argc] = { Local<Value>::New(String::New("hello world")) };
-  cb->Call(Context::GetCurrent()->Global(), argc, argv);
+  OgreMaterialParser materialParser;
+  materialParser.Load(std::string(*path));
+  std::string topic = "~/material";
+  std::string materialJson = materialParser.GetMaterialAsJson();
+  std::string msg;
+  msg += "{\"op\":\"publish\",\"topic\":\"" + topic + "\", \"msg\":";
+  msg += materialJson;
+  msg += "}";
 
-  return scope.Close(Undefined());
+  args.GetReturnValue().Set(String::NewFromUtf8(isolate, msg.c_str()));
 }
 
 /////////////////////////////////////////////////
-Handle<v8::Value> GZNode::SetPoseMsgFilterMinimumAge(const v8::Arguments& args)
+void GZNode::SetPoseMsgFilterMinimumDistanceSquared(const
+    FunctionCallbackInfo<Value>& args)
 {
-  HandleScope scope;
+  GZNode *obj = ObjectWrap::Unwrap<GZNode>(args.This());
 
-  GZNode* obj = ObjectWrap::Unwrap<GZNode>(args.This());
   Local<Number> v = Local<Number>::Cast(args[0]);
   double value = v->Value();
-  obj->gzIface->SetPoseFilterMinimumMsgAge(value);
+  obj->gzIface->SetPoseFilterMinimumDistanceSquared(value);
 
-  return scope.Close(Undefined());
+  return;
 }
 
 /////////////////////////////////////////////////
-Handle<v8::Value> GZNode::GetPoseMsgFilterMinimumAge(const \
-														v8::Arguments& args)
+void GZNode::GetPoseMsgFilterMinimumDistanceSquared(const
+    FunctionCallbackInfo<Value>& args)
 {
-  HandleScope scope;
-  GZNode* obj = ObjectWrap::Unwrap<GZNode>(args.This());
-  double value  = obj->gzIface->GetPoseFilterMinimumMsgAge();
-  return scope.Close(Number::New(value));
+  Isolate* isolate = args.GetIsolate();
+  GZNode *obj = ObjectWrap::Unwrap<GZNode>(args.This());
+  double value  = obj->gzIface->GetPoseFilterMinimumDistanceSquared();
+  args.GetReturnValue().Set(Number::New(isolate ,value));
 }
 
-/////////////////////////////////////////////////
-Handle<v8::Value> GZNode::SetPoseMsgFilterMinimumDistanceSquared(const
-    v8::Arguments& args)
+/////////////////////////////////////////////////////
+void GZNode::SetPoseMsgFilterMinimumQuaternionSquared(const
+    FunctionCallbackInfo<Value>& args)
 {
-  HandleScope scope;
-
-  GZNode* obj = ObjectWrap::Unwrap<GZNode>(args.This());
+  GZNode *obj = ObjectWrap::Unwrap<GZNode>(args.This());
   Local<Number> v = Local<Number>::Cast(args[0]);
   double value = v->Value();
-  obj->gzIface->SetPoseFilterMinimumDistanceSquared(value);
+  obj->gzIface->SetPoseFilterMinimumQuaternionSquared(value);
 
-  return scope.Close(Undefined());
+  return;
 }
 
 /////////////////////////////////////////////////
-Handle<v8::Value> GZNode::GetPoseMsgFilterMinimumDistanceSquared(const
-    v8::Arguments& args)
+void GZNode::GetPoseMsgFilterMinimumQuaternionSquared(const
+    FunctionCallbackInfo<Value>& args)
 {
-  HandleScope scope;
-  GZNode* obj = ObjectWrap::Unwrap<GZNode>(args.This());
-  double value  = obj->gzIface->GetPoseFilterMinimumDistanceSquared();
-  return scope.Close(Number::New(value));
+  Isolate* isolate = args.GetIsolate();
+  GZNode *obj = ObjectWrap::Unwrap<GZNode>(args.This());
+  double value  = obj->gzIface->GetPoseFilterMinimumQuaternionSquared();
+  args.GetReturnValue().Set(Number::New(isolate ,value));
 }
 
 /////////////////////////////////////////////////
-Handle<v8::Value> GZNode::SetPoseMsgFilterMinimumQuaternionSquared(const
-    v8::Arguments& args)
+void GZNode::GetMessages(const FunctionCallbackInfo<Value>& args)
 {
-  HandleScope scope;
+  Isolate* isolate = args.GetIsolate();
 
   GZNode* obj = ObjectWrap::Unwrap<GZNode>(args.This());
-  Local<Number> v = Local<Number>::Cast(args[0]);
-  double value = v->Value();
-  obj->gzIface->SetPoseFilterMinimumQuaternionSquared(value);
 
-  return scope.Close(Undefined());
+  std::vector<std::string> msgs = obj->gzIface->PopOutgoingMessages();
+  // args.GetReturnValue().Set(Number::New(isolate ,msgs.size()));
+  Local<Array> arguments = Array::New(isolate, msgs.size());
+  for (unsigned int i = 0; i < msgs.size(); ++i) {
+    arguments->Set(i ,String::NewFromUtf8(isolate, msgs[i].c_str()));
+  }
+
+  args.GetReturnValue().Set(arguments);
 }
 
-/////////////////////////////////////////////////
-Handle<v8::Value> GZNode::SetConnected(const v8::Arguments& args)
+
+////////////////////////////////////////////////
+void GZNode::Request(const FunctionCallbackInfo<Value>& args)
 {
-  HandleScope scope;
+  Isolate* isolate = args.GetIsolate();
 
-  GZNode *obj = ObjectWrap::Unwrap<GZNode>(args.This());
-  bool value = args[0]->BooleanValue();
-  obj->gzIface->SetConnected(value);
+  if (args.Length() < 1)
+  {
+    isolate->ThrowException(Exception::TypeError(
+        String::NewFromUtf8(isolate, "Wrong number of arguments")));
+    return;
+  }
 
-  return scope.Close(Undefined());
-}
+  if (!args[0]->IsString())
+  {
+    isolate->ThrowException(Exception::TypeError(
+        String::NewFromUtf8(isolate, "Wrong argument type. String expected.")));
+    return;
+  }
 
-Handle<v8::Value> GZNode::GetIsGzServerConnected(const v8::Arguments& args)
-{
-  HandleScope scope;
+  GZNode* obj = ObjectWrap::Unwrap<GZNode>(args.This());
 
-  GZNode *obj = ObjectWrap::Unwrap<GZNode>(args.This());
-  bool value = obj->isGzServerConnected;
+  String::Utf8Value request(args[0]->ToString());
+  obj->gzIface->PushRequest(std::string(*request));
 
-  return scope.Close(Boolean::New(value));
+  return;
 }
 
 /////////////////////////////////////////////////
-Handle<v8::Value> GZNode::GetPoseMsgFilterMinimumQuaternionSquared(const
-    v8::Arguments& args)
+void GZNode::SetPoseMsgFilterMinimumAge(const
+    FunctionCallbackInfo<Value>& args)
 {
-  HandleScope scope;
   GZNode* obj = ObjectWrap::Unwrap<GZNode>(args.This());
-  double value  = obj->gzIface->GetPoseFilterMinimumQuaternionSquared();
-  return scope.Close(Number::New(value));
+  Local<Number> v = Local<Number>::Cast(args[0]);
+  double value = v->Value();
+  obj->gzIface->SetPoseFilterMinimumMsgAge(value);
+
+  return;
 }
 
 /////////////////////////////////////////////////
-Handle<Value> GZNode::GetMessages(const Arguments& args)
+void GZNode::GetPoseMsgFilterMinimumAge(const
+    FunctionCallbackInfo<Value>& args)
 {
-  HandleScope scope;
-
   GZNode* obj = ObjectWrap::Unwrap<GZNode>(args.This());
-
-  std::vector<std::string> msgs = obj->gzIface->PopOutgoingMessages();
-  Local<Array> arguments = Array::New(msgs.size());
-  for (unsigned int i = 0; i < msgs.size(); ++i) {
-    arguments->Set(i ,String::New(msgs[i].c_str()));
-  }
-
-  return scope.Close(arguments);
+  double value  = obj->gzIface->GetPoseFilterMinimumMsgAge();
+  args.GetReturnValue().Set(value);
 }
 
 /////////////////////////////////////////////////
diff --git a/gzbridge/GZNode.hh b/gzbridge/GZNode.hh
index 24944e0..5d3f041 100644
--- a/gzbridge/GZNode.hh
+++ b/gzbridge/GZNode.hh
@@ -15,15 +15,20 @@
  *
 */
 
-#ifndef _GZNODE_HH_
-#define _GZNODE_HH_
+#ifndef GZBRIDGE_GZNODE_HH_
+#define GZBRIDGE_GZNODE_HH_
 
 #include <node.h>
-#include <string>
-#include <vector>
+#include <node_object_wrap.h>
 
 namespace gzweb
 {
+  using v8::FunctionCallbackInfo;
+  using v8::Value;
+  using v8::FunctionTemplate;
+  using v8::Object;
+  using v8::Persistent;
+
   class GazeboInterface;
 
   class GZNode : public node::ObjectWrap
@@ -32,53 +37,51 @@ namespace gzweb
 
     private: GZNode();
 
-    private: GZNode(const v8::Arguments& args);
-
-    private: void ConnectGzServer();
+    private: GZNode(const FunctionCallbackInfo<Value>& args);
 
     private: ~GZNode();
 
-    private: static v8::Handle<v8::Value> New(const v8::Arguments& args);
+    private: static void New(const FunctionCallbackInfo<Value>& args);
 
-    private: static v8::Handle<v8::Value> Callback(const v8::Arguments& args);
+    private: static void LoadMaterialScripts(
+        const FunctionCallbackInfo<Value>& args);
 
-    private: static v8::Handle<v8::Value> Request(const v8::Arguments& args);
+    private: static void SetConnected(
+        const FunctionCallbackInfo<Value>& args);
 
-    private: static v8::Handle<v8::Value> SetPoseMsgFilterMinimumAge(const
-      v8::Arguments& args);
+    private: static void GetIsGzServerConnected(
+        const FunctionCallbackInfo<Value>& args);
 
-    private: static v8::Handle<v8::Value> GetPoseMsgFilterMinimumAge(const
-      v8::Arguments& args);
+    private: static void GetMaterialScriptsMessage(
+        const FunctionCallbackInfo<Value>& args);
 
-    private: static v8::Handle<v8::Value>
-        SetPoseMsgFilterMinimumDistanceSquared(const v8::Arguments& args);
+    private: static void SetPoseMsgFilterMinimumDistanceSquared(
+        const FunctionCallbackInfo<Value>& args);
 
-    private: static v8::Handle<v8::Value>
-        GetPoseMsgFilterMinimumDistanceSquared(const v8::Arguments& args);
+    private: static void GetPoseMsgFilterMinimumDistanceSquared(
+        const FunctionCallbackInfo<Value>& args);
 
-    private: static v8::Handle<v8::Value>
-        SetPoseMsgFilterMinimumQuaternionSquared(const v8::Arguments& args);
+    private: static void SetPoseMsgFilterMinimumQuaternionSquared(
+        const FunctionCallbackInfo<Value>& args);
 
-    private: static v8::Handle<v8::Value>
-        SetConnected(const v8::Arguments& args);
+    private: static void GetPoseMsgFilterMinimumQuaternionSquared(
+        const FunctionCallbackInfo<Value>& args);
 
-    private: static v8::Handle<v8::Value>
-        GetPoseMsgFilterMinimumQuaternionSquared(const v8::Arguments& args);
+    private: static void GetMessages(const FunctionCallbackInfo<Value>& args);
 
-    private: static v8::Handle<v8::Value>
-        GetMessages(const v8::Arguments& args);
+    private: static void Request(const FunctionCallbackInfo<Value>& args);
 
-    private: static v8::Handle<v8::Value>
-        LoadMaterialScripts(const v8::Arguments& args);
+    private: static void SetPoseMsgFilterMinimumAge(
+        const FunctionCallbackInfo<Value>& args);
 
-    private: static v8::Handle<v8::Value>
-        GetIsGzServerConnected(const v8::Arguments& args);
+    private: static void GetPoseMsgFilterMinimumAge(
+        const FunctionCallbackInfo<Value>& args);
+
+    private: void ConnectGzServer();
 
-    private: static v8::Handle<v8::Value>
-        GetMaterialScriptsMessage(const v8::Arguments& args);
+    private: GazeboInterface* gzIface = nullptr;
 
-    private: GazeboInterface* gzIface;
-    private: bool isGzServerConnected;
+    private: bool isGzServerConnected = false;
 
   };
 }
diff --git a/gzbridge/GazeboInterface.cc b/gzbridge/GazeboInterface.cc
index 2780e59..7851c35 100644
--- a/gzbridge/GazeboInterface.cc
+++ b/gzbridge/GazeboInterface.cc
@@ -15,7 +15,7 @@
  *
 */
 
-#include <boost/thread.hpp>
+#include <gazebo/gazebo_config.h>
 
 #include "pb2json.hh"
 #include "OgreMaterialParser.hh"
@@ -25,18 +25,9 @@
 
 using namespace gzweb;
 
-std::vector<std::string> GazeboInterface::incoming;
-std::vector<std::string> GazeboInterface::outgoing;
-
-boost::recursive_mutex incomingMutex;
-boost::recursive_mutex outgoingMutex;
-
 /////////////////////////////////////////////////
 GazeboInterface::GazeboInterface()
 {
-//  this->socketServer = _server;
-  this->receiveMutex = new boost::recursive_mutex();
-  this->serviceMutex = new boost::recursive_mutex();
   this->stop = false;
 
   // Create our node for communication
@@ -71,6 +62,7 @@ GazeboInterface::GazeboInterface()
   this->roadTopic = "~/roads";
   this->heightmapService = "~/heightmap_data";
   this->deleteTopic = "~/entity_delete";
+  this->playbackControlTopic = "~/playback_control";
 
   // material topic
   this->materialTopic = "~/material";
@@ -149,20 +141,22 @@ GazeboInterface::GazeboInterface()
       this->node->Advertise<gazebo::msgs::WorldControl>(
       this->worldControlTopic);
 
+  // For controlling playback
+  this->playbackControlPub =
+      this->node->Advertise<gazebo::msgs::LogPlaybackControl>(
+      this->playbackControlTopic);
+
+
   this->responseSub = this->node->Subscribe("~/response",
       &GazeboInterface::OnResponse, this);
 
   this->materialParser = new OgreMaterialParser();
 
-  this->lastStatsTime = gazebo::common::Time::Zero;
   this->lastPausedState = true;
 
   // message filtering apparatus
   this->minimumDistanceSquared = 0.0001;
   this->minimumQuaternionSquared = 0.0001;
-  this->minimumDistanceSquaredTooEarly = 0.01;
-  this->minimumQuaternionSquaredTooEarly = 0.01;
-
   this->minimumMsgAge = 0.03;
   this->skippedMsgCount = 0;
   this->messageWindowSize = 10000;
@@ -170,14 +164,7 @@ GazeboInterface::GazeboInterface()
 
   this->isConnected = false;
 
-  // initialize thread variables
-  this->runThread = NULL;
-  this->serviceThread = NULL;
-  this->connectionCondition = new boost::condition_variable();
-  this->connectionMutex = new boost::mutex();
-  this->serviceCondition = new boost::condition_variable_any();
   this->receivedMessage = false;
-  this->receiveCondition = new boost::condition_variable_any();
 }
 
 /////////////////////////////////////////////////
@@ -230,22 +217,11 @@ GazeboInterface::~GazeboInterface()
   this->node.reset();
 
   if (this->runThread)
-  {
     this->runThread->join();
-    delete this->runThread;
-  }
   if (this->serviceThread)
-  {
     this->serviceThread->join();
-    delete this->serviceThread;
-  }
 
-  delete this->receiveMutex;
-  delete this->serviceMutex;
-  delete this->connectionCondition;
-  delete this->connectionMutex;
-  delete this->serviceCondition;
-  delete this->receiveCondition;
+  delete this->materialParser;
 }
 
 /////////////////////////////////////////////////
@@ -257,10 +233,10 @@ void GazeboInterface::Init()
 /////////////////////////////////////////////////
 void GazeboInterface::RunThread()
 {
-  this->runThread = new boost::thread(boost::bind(&GazeboInterface::Run, this));
-  this->serviceThread = new boost::thread(
-      boost::bind(&GazeboInterface::RunService, this));
-
+  this->runThread.reset(
+      new std::thread(std::bind(&GazeboInterface::Run, this)));
+  this->serviceThread.reset(new std::thread(
+      std::bind(&GazeboInterface::RunService, this)));
 }
 
 /////////////////////////////////////////////////
@@ -294,28 +270,8 @@ void GazeboInterface::Fini()
 /////////////////////////////////////////////////
 void GazeboInterface::ProcessMessages()
 {
-  static RequestMsgs_L::iterator rIter;
-  static SceneMsgs_L::iterator sIter;
-  static PhysicsMsgs_L::iterator physicsIter;
-  static WorldStatsMsgs_L::iterator wIter;
-  static ModelMsgs_L::iterator modelIter;
-  static VisualMsgs_L::iterator visualIter;
-  static LightMsgs_L::iterator lightIter;
-  static PoseMsgs_L::iterator pIter;
-  // static SkeletonPoseMsgs_L::iterator spIter;
-  static JointMsgs_L::iterator jointIter;
-  static SensorMsgs_L::iterator sensorIter;
-
-#ifdef GAZEBO_HBP_SUPPORT_JOINT_STATE_MESSAGES
-  static JointStateMsgs_L::iterator jointStateIter;
-#endif
-  
-#ifdef GAZEBO_HBP_SUPPORT_MUSCLE_VISUALIZATION_MESSAGES
-  static MuscleVisualizationMsgs_L::iterator muscleVisualizationIter;
-#endif  
-
   {
-    boost::recursive_mutex::scoped_lock lock(*this->receiveMutex);
+    std::lock_guard<std::recursive_mutex> lock(this->receiveMutex);
 
     // Process incoming messages.
     std::vector<std::string> msgs = this->PopIncomingMessages();
@@ -348,7 +304,8 @@ void GazeboInterface::ProcessMessages()
         {
           gazebo::msgs::Request *requestPhysicsMsg;
           requestPhysicsMsg = gazebo::msgs::CreateRequest("physics_info", "");
-          if (this->requests.find(requestPhysicsMsg->id()) != this->requests.end())
+          if (this->requests.find(requestPhysicsMsg->id()) !=
+               this->requests.end())
             requests.erase(requestPhysicsMsg->id());
           this->requests[requestPhysicsMsg->id()] = requestPhysicsMsg;
           this->requestPub->Publish(*requestPhysicsMsg);
@@ -361,36 +318,115 @@ void GazeboInterface::ProcessMessages()
         }
         else if (topic == this->modelModifyTopic)
         {
-          std::string name = get_value(msg, "msg:name");
-          int id = atoi(get_value(msg, "msg:id").c_str());
+          JsonObj jsonObj(msg);
+          JsonObj msgObj = jsonObj.Object("msg");
+          if (!msgObj)
+          {
+            std::cerr << "No msg key in json object" << std::endl;
+            continue;
+          }
 
+          std::string name = msgObj.Object("name").String();
           if (name == "")
             continue;
 
-          ignition::math::Vector3d pos(
-            atof(get_value(msg, "msg:position:x").c_str()),
-            atof(get_value(msg, "msg:position:y").c_str()),
-            atof(get_value(msg, "msg:position:z").c_str()));
-          ignition::math::Vector3d scale(
-            atof(get_value(msg, "msg:scale:x").c_str()),
-            atof(get_value(msg, "msg:scale:y").c_str()),
-            atof(get_value(msg, "msg:scale:z").c_str()));
-          ignition::math::Quaterniond quat(
-            atof(get_value(msg, "msg:orientation:w").c_str()),
-            atof(get_value(msg, "msg:orientation:x").c_str()),
-            atof(get_value(msg, "msg:orientation:y").c_str()),
-            atof(get_value(msg, "msg:orientation:z").c_str()));
+          unsigned int id =
+              static_cast<unsigned int>(msgObj.Object("id").Number());
+
+          JsonObj posObj = msgObj.Object("position");
+          if (!posObj)
+          {
+            std::cerr << "model pose msg is missing 'position' field"
+                      << std::endl;
+            continue;
+          }
+
+          double posX = posObj.Object("x").Number();
+          double posY = posObj.Object("y").Number();
+          double posZ = posObj.Object("z").Number();
+          JsonObj quatObj = msgObj.Object("orientation");
+          if (!quatObj)
+          {
+            std::cerr << "model pose msg is missing 'orientation' field"
+                      << std::endl;
+            continue;
+          }
+          double quatW = quatObj.Object("w").Number();
+          double quatX = quatObj.Object("x").Number();
+          double quatY = quatObj.Object("y").Number();
+          double quatZ = quatObj.Object("z").Number();
+
+
+          JsonObj scaleObj = msgObj.Object("scale");
+          if (!scaleObj)
+          {
+            std::cerr << "model pose msg is missing 'scale' field"
+                      << std::endl;
+            continue;
+          }
+          double scaleX = scaleObj.Object("x").Number();
+          double scaleY = scaleObj.Object("y").Number();
+          double scaleZ = scaleObj.Object("z").Number();
+
+          ignition::math::Vector3d pos(posX, posY, posZ);
+          ignition::math::Quaterniond quat(quatW, quatX, quatY, quatZ);
+
           ignition::math::Pose3d pose(pos, quat);
 
+          ignition::math::Vector3d scale(scaleX, scaleY, scaleZ);
+
           gazebo::msgs::Model modelMsg;
           modelMsg.set_id(id);
           modelMsg.set_name(name);
           gazebo::msgs::Set(modelMsg.mutable_pose(), pose);
           gazebo::msgs::Set(modelMsg.mutable_scale(), scale);
 
+          JsonObj linksObj = msgObj.Object("link");
+          if (linksObj)
+          {
+            for (unsigned int i = 0; i < linksObj.ArraySize(); ++i)
+            {
+              JsonObj linkObj = linksObj.ArrayObject(i);
+              std::string linkName = linkObj.Object("name").String();
+              unsigned int linkId =
+                  static_cast<unsigned int>(linkObj.Object("id").Number());
+              JsonObj linkPosObj = linkObj.Object("position");
+              if (!linkPosObj)
+              {
+                std::cerr << "link pose msg is missing 'position' field"
+                          << std::endl;
+                continue;
+              }
+              double linkPosX = linkPosObj.Object("x").Number();
+              double linkPosY = linkPosObj.Object("y").Number();
+              double linkPosZ = linkPosObj.Object("z").Number();
+              JsonObj linkQuatObj = linkObj.Object("orientation");
+              if (!linkQuatObj)
+              {
+                std::cerr << "link pose msg is missing 'orientation' field"
+                          << std::endl;
+                continue;
+              }
+              double linkQuatW = linkQuatObj.Object("w").Number();
+              double linkQuatX = linkQuatObj.Object("x").Number();
+              double linkQuatY = linkQuatObj.Object("y").Number();
+              double linkQuatZ = linkQuatObj.Object("z").Number();
+
+              ignition::math::Vector3d linkPos(linkPosX, linkPosY, linkPosZ);
+              ignition::math::Quaterniond linkQuat(
+                  linkQuatW, linkQuatX, linkQuatY, linkQuatZ);
+              ignition::math::Pose3d linkPose(linkPos, linkQuat);
+
+              gazebo::msgs::Link *linkMsg = modelMsg.add_link();
+              linkMsg->set_id(linkId);
+              linkMsg->set_name(linkName);
+              gazebo::msgs::Set(linkMsg->mutable_pose(), linkPose);
+            }
+          }
           this->modelPub->Publish(modelMsg);
         }
-        else if (topic == this->lightFactoryTopic || topic == this->lightModifyTopic)
+        else if (topic == this->lightFactoryTopic ||
+            topic == this->lightModifyTopic)
         {
           std::string name = get_value(msg, "msg:name");
           std::string type = get_value(msg, "msg:type");
@@ -424,13 +460,20 @@ void GazeboInterface::ProcessMessages()
               atof(get_value(msg, "msg:direction:z").c_str()));
             gazebo::msgs::Set(lightMsg.mutable_direction(), direction);
 
+#if GAZEBO_MAJOR_VERSION >= 9
+            ignition::math::Color diffuse(
+#else
             gazebo::common::Color diffuse(
+#endif
                 atof(get_value(msg, "msg:diffuse:r").c_str()),
                 atof(get_value(msg, "msg:diffuse:g").c_str()),
                 atof(get_value(msg, "msg:diffuse:b").c_str()), 1);
             gazebo::msgs::Set(lightMsg.mutable_diffuse(), diffuse);
-
+#if GAZEBO_MAJOR_VERSION >= 9
+            ignition::math::Color specular(
+#else
             gazebo::common::Color specular(
+#endif
                 atof(get_value(msg, "msg:specular:r").c_str()),
                 atof(get_value(msg, "msg:specular:g").c_str()),
                 atof(get_value(msg, "msg:specular:b").c_str()), 1);
@@ -464,11 +507,20 @@ void GazeboInterface::ProcessMessages()
               gazebo::msgs::Set(lightMsg.mutable_direction(),
                   ignition::math::Vector3d(0,0,-1));
             }
-
             gazebo::msgs::Set(lightMsg.mutable_diffuse(),
+
+#if GAZEBO_MAJOR_VERSION >= 9
+                ignition::math::Color(0.5, 0.5, 0.5, 1));
+#else
                 gazebo::common::Color(0.5, 0.5, 0.5, 1));
+#endif
             gazebo::msgs::Set(lightMsg.mutable_specular(),
+
+#if GAZEBO_MAJOR_VERSION >= 9
+                ignition::math::Color(0.1, 0.1, 0.1, 1));
+#else
                 gazebo::common::Color(0.1, 0.1, 0.1, 1));
+#endif
             lightMsg.set_attenuation_constant(0.5);
             lightMsg.set_attenuation_linear(0.01);
             lightMsg.set_attenuation_quadratic(0.001);
@@ -501,7 +553,8 @@ void GazeboInterface::ProcessMessages()
               linkName = linkName.substr(index+1);
           linkMsg->set_name(linkName);
 
-          std::string self_collideStr = get_value(msg, "msg:link:self_collide").c_str();
+          std::string self_collideStr =
+              get_value(msg, "msg:link:self_collide").c_str();
           bool self_collide = false;
           if (self_collideStr == "1")
           {
@@ -509,7 +562,8 @@ void GazeboInterface::ProcessMessages()
           }
           linkMsg->set_self_collide(self_collide);
 
-          std::string gravityStr = get_value(msg, "msg:link:gravity").c_str();
+          std::string gravityStr =
+              get_value(msg, "msg:link:gravity").c_str();
           bool gravity = false;
           if (gravityStr == "1")
           {
@@ -517,7 +571,8 @@ void GazeboInterface::ProcessMessages()
           }
           linkMsg->set_gravity(gravity);
 
-          std::string kinematicStr = get_value(msg, "msg:link:kinematic").c_str();
+          std::string kinematicStr =
+              get_value(msg, "msg:link:kinematic").c_str();
           bool kinematic = false;
           if (kinematicStr == "1")
           {
@@ -571,8 +626,10 @@ void GazeboInterface::ProcessMessages()
 
             newModelStr << "<sdf version ='" << SDF_VERSION << "'>"
                 << "<model name='" << name << "'>"
-                << "<pose>" << pos.X() << " " << pos.Y() << " " << pos.Z() << " "
-                            << rpy.X() << " " << rpy.Y() << " " << rpy.Z() << "</pose>"
+                << "<pose>" << pos.X() << " " << pos.Y() << " " << pos.Z()
+                            << " "
+                            << rpy.X() << " " << rpy.Y() << " " << rpy.Z()
+                            << "</pose>"
                 << "<link name ='link'>"
                 <<   "<inertial><mass>1.0</mass></inertial>"
                 <<   "<collision name ='collision'>"
@@ -596,6 +653,11 @@ void GazeboInterface::ProcessMessages()
                 << "</model>"
                 << "</sdf>";
           }
+          else if (type == "sdf")
+          {
+            std::string sdfStr = get_value(msg, "msg:sdf");
+            newModelStr << sdfStr;
+          }
           else
           {
             newModelStr << "<sdf version ='" << SDF_VERSION << "'>"
@@ -611,8 +673,16 @@ void GazeboInterface::ProcessMessages()
           }
 
           // Spawn the model in the physics server
-          factoryMsg.set_sdf(newModelStr.str());
-          this->factoryPub->Publish(factoryMsg);
+          if (!newModelStr.str().empty())
+          {
+            factoryMsg.set_sdf(newModelStr.str());
+            this->factoryPub->Publish(factoryMsg);
+          }
+          else
+          {
+            std::cerr << "Empty model SDF string when publishing to ~/factory"
+                      << std::endl;
+          }
         }
         else if (topic == this->worldControlTopic)
         {
@@ -635,7 +705,6 @@ void GazeboInterface::ProcessMessages()
             else if (reset == "world")
             {
               worldControlMsg.mutable_reset()->set_all(true);
-
             }
           }
           if (!pause.empty() || !reset.empty())
@@ -654,8 +723,53 @@ void GazeboInterface::ProcessMessages()
         }
         else if (topic == this->deleteTopic)
         {
-            std::string name = get_value(msg, "msg:name");
-            gazebo::transport::requestNoReply(this->node, "entity_delete", name);
+          std::string name = get_value(msg, "msg:name");
+          gazebo::transport::requestNoReply(this->node, "entity_delete", name);
+        }
+        else if (topic == this->playbackControlTopic)
+        {
+          gazebo::msgs::LogPlaybackControl playbackControlMsg;
+          std::string pause = get_value(msg, "msg:pause");
+          std::string multiStep = get_value(msg, "msg:multi_step");
+          std::string rewind = get_value(msg, "msg:rewind");
+          std::string forward = get_value(msg, "msg:forward");
+          std::string seekSec = get_value(msg, "msg:seek:sec");
+          std::string seekNSec = get_value(msg, "msg:seek:nsec");
+          if (!pause.empty())
+          {
+            int pauseValue = atoi(pause.c_str());
+            playbackControlMsg.set_pause(pauseValue);
+          }
+          if (!multiStep.empty())
+          {
+            int multiStepValue = atoi(multiStep.c_str());
+            playbackControlMsg.set_multi_step(multiStepValue);
+          }
+          if (!rewind.empty())
+          {
+            int rewindValue = atoi(rewind.c_str());
+            playbackControlMsg.set_rewind(rewindValue);
+          }
+          if (!forward.empty())
+          {
+            int forwardValue = atoi(forward.c_str());
+            playbackControlMsg.set_forward(forwardValue);
+          }
+          if (!seekSec.empty() && !seekNSec.empty())
+          {
+            auto seek = playbackControlMsg.mutable_seek();
+            seek->set_sec(atof(seekSec.c_str()));
+            seek->set_nsec(atof(seekNSec.c_str()));
+          }
+          this->playbackControlPub->Publish(playbackControlMsg);
+        }
+        else if (topic == this->statsTopic)
+        {
+          // simulate latching stats topic
+          if (this->statsMsgs.empty())
+          {
+            this->statsMsgs.push_back(this->statsMsg);
+          }
         }
       }
       else
@@ -664,18 +778,18 @@ void GazeboInterface::ProcessMessages()
         std::string service = get_value(msg.c_str(), "service");
         if (!service.empty())
         {
-          boost::recursive_mutex::scoped_lock lock(*this->serviceMutex);
+          std::unique_lock<std::recursive_mutex> lock(this->serviceMutex);
           this->serviceRequests.push_back(msg);
           lock.unlock();
-          this->serviceCondition->notify_one();
+          this->serviceCondition.notify_one();
         }
       }
 
     }
 
-    std::string msg = "";
+    std::string msg;
     // Forward the scene messages.
-    for (sIter = this->sceneMsgs.begin(); sIter != this->sceneMsgs.end();
+    for (auto sIter = this->sceneMsgs.begin(); sIter != this->sceneMsgs.end();
         ++sIter)
     {
       msg = this->PackOutgoingTopicMsg(this->sceneTopic,
@@ -685,7 +799,7 @@ void GazeboInterface::ProcessMessages()
     this->sceneMsgs.clear();
 
     // Forward the physics messages.
-    for (physicsIter = this->physicsMsgs.begin();
+    for (auto physicsIter = this->physicsMsgs.begin();
         physicsIter != this->physicsMsgs.end(); ++physicsIter)
     {
       msg = this->PackOutgoingTopicMsg(this->physicsTopic,
@@ -695,7 +809,7 @@ void GazeboInterface::ProcessMessages()
     this->physicsMsgs.clear();
 
     // Forward the model messages.
-    for (modelIter = this->modelMsgs.begin();
+    for (auto modelIter = this->modelMsgs.begin();
         modelIter != this->modelMsgs.end(); ++modelIter)
     {
       msg = this->PackOutgoingTopicMsg(this->modelTopic,
@@ -705,7 +819,7 @@ void GazeboInterface::ProcessMessages()
     this->modelMsgs.clear();
 
     // Forward the sensor messages.
-    for (sensorIter = this->sensorMsgs.begin();
+    for (auto sensorIter = this->sensorMsgs.begin();
         sensorIter != this->sensorMsgs.end(); ++sensorIter)
     {
       msg = this->PackOutgoingTopicMsg(this->sensorTopic,
@@ -715,7 +829,7 @@ void GazeboInterface::ProcessMessages()
     this->sensorMsgs.clear();
 
     // Forward the light factory messages.
-    for (lightIter = this->lightFactoryMsgs.begin();
+    for (auto lightIter = this->lightFactoryMsgs.begin();
         lightIter != this->lightFactoryMsgs.end(); ++lightIter)
     {
       msg = this->PackOutgoingTopicMsg(this->lightFactoryTopic,
@@ -725,7 +839,7 @@ void GazeboInterface::ProcessMessages()
     this->lightFactoryMsgs.clear();
 
     // Forward the light modify messages.
-    for (lightIter = this->lightModifyMsgs.begin();
+    for (auto lightIter = this->lightModifyMsgs.begin();
         lightIter != this->lightModifyMsgs.end(); ++lightIter)
     {
       msg = this->PackOutgoingTopicMsg(this->lightModifyTopic,
@@ -735,7 +849,7 @@ void GazeboInterface::ProcessMessages()
     this->lightModifyMsgs.clear();
 
     // Forward the visual messages.
-    for (visualIter = this->visualMsgs.begin();
+    for (auto visualIter = this->visualMsgs.begin();
         visualIter != this->visualMsgs.end(); ++visualIter)
     {
       msg = this->PackOutgoingTopicMsg(this->visualTopic,
@@ -745,7 +859,7 @@ void GazeboInterface::ProcessMessages()
     this->visualMsgs.clear();
 
     // Forward the joint messages.
-    for (jointIter = this->jointMsgs.begin();
+    for (auto jointIter = this->jointMsgs.begin();
         jointIter != this->jointMsgs.end(); ++jointIter)
     {
       msg = this->PackOutgoingTopicMsg(this->jointTopic,
@@ -756,7 +870,7 @@ void GazeboInterface::ProcessMessages()
 
 #ifdef GAZEBO_HBP_SUPPORT_JOINT_STATE_MESSAGES
     // Forward joint state messages.
-    for (jointStateIter = this->jointStateMsgs.begin();
+    for (auto jointStateIter = this->jointStateMsgs.begin();
         jointStateIter != this->jointStateMsgs.end(); ++jointStateIter)
     {
       msg = this->PackOutgoingTopicMsg(this->jointStatesTopic,
@@ -768,7 +882,7 @@ void GazeboInterface::ProcessMessages()
     
 #ifdef GAZEBO_HBP_SUPPORT_MUSCLE_VISUALIZATION_MESSAGES
     // Forward muscle visualization messages.
-    for (muscleVisualizationIter = this->muscleVisualizationMsgs.begin();
+    for (auto muscleVisualizationIter = this->muscleVisualizationMsgs.begin();
         muscleVisualizationIter != this->muscleVisualizationMsgs.end(); ++muscleVisualizationIter)
     {
       msg = this->PackOutgoingTopicMsg(this->muscleVisualizationTopic,
@@ -779,8 +893,8 @@ void GazeboInterface::ProcessMessages()
 #endif    
 
     // Forward the request messages
-    for (rIter =  this->requestMsgs.begin(); rIter != this->requestMsgs.end();
-        ++rIter)
+    for (auto rIter =  this->requestMsgs.begin();
+        rIter != this->requestMsgs.end(); ++rIter)
     {
       msg = this->PackOutgoingTopicMsg(this->requestTopic,
           pb2json(*(*rIter).get()));
@@ -789,7 +903,7 @@ void GazeboInterface::ProcessMessages()
     this->requestMsgs.clear();
 
     // Forward the stats messages.
-    for (wIter = this->statsMsgs.begin(); wIter != this->statsMsgs.end();
+    for (auto wIter = this->statsMsgs.begin(); wIter != this->statsMsgs.end();
         ++wIter)
     {
       msg = this->PackOutgoingTopicMsg(this->statsTopic,
@@ -799,7 +913,7 @@ void GazeboInterface::ProcessMessages()
     this->statsMsgs.clear();
 
     // Forward all the pose messages.
-    pIter = this->poseMsgs.begin();
+    auto pIter = this->poseMsgs.begin();
     while (pIter != this->poseMsgs.end())
     {
       msg = this->PackOutgoingTopicMsg(this->poseTopic,
@@ -808,7 +922,6 @@ void GazeboInterface::ProcessMessages()
       ++pIter;
     }
     this->poseMsgs.clear();
-
     this->receivedMessage = false;
   }
 }
@@ -818,7 +931,7 @@ void GazeboInterface::ProcessServiceRequests()
 {
   std::vector<std::string> services;
   {
-    boost::recursive_mutex::scoped_lock lock(*this->serviceMutex);
+    std::lock_guard<std::recursive_mutex> lock(this->serviceMutex);
     services = this->serviceRequests;
     this->serviceRequests.clear();
   }
@@ -863,11 +976,11 @@ void GazeboInterface::OnModelMsg(ConstModelPtr &_msg)
   if (!this->IsConnected())
     return;
 
-  boost::recursive_mutex::scoped_lock lock(*this->receiveMutex);
+  std::unique_lock<std::recursive_mutex> lock(this->receiveMutex);
   this->modelMsgs.push_back(_msg);
   this->receivedMessage = true;
   lock.unlock();
-  this->receiveCondition->notify_one();
+  this->receiveCondition.notify_one();
 }
 
 /////////////////////////////////////////////////
@@ -879,7 +992,6 @@ bool GazeboInterface::FilterPoses(const TimedPose &_old,
     // double ratio =  100.0 * this->skippedMsgCount  / this->messageWindowSize;
     // std::cout << "Message filter: " << ratio << " %" << std::endl;
     // std::cout << "Message count : " << this->skippedMsgCount;
-    // std::cout << " "  << << std::endl;
     this->skippedMsgCount = 0;
     this->messageCount = 0;
   }
@@ -941,7 +1053,7 @@ void GazeboInterface::OnPoseMsg(ConstPosesStampedPtr &_msg)
   if (!this->IsConnected())
     return;
 
-  boost::recursive_mutex::scoped_lock lock(*this->receiveMutex);
+  std::unique_lock<std::recursive_mutex> lock(this->receiveMutex);
   PoseMsgs_L::iterator iter;
 
   for (int i = 0; i < _msg->pose_size(); ++i)
@@ -976,7 +1088,7 @@ void GazeboInterface::OnPoseMsg(ConstPosesStampedPtr &_msg)
     else
     {
       TimedPose oldPose = it->second;
-      filtered = FilterPoses(oldPose, currentPose);
+      filtered = this->FilterPoses(oldPose, currentPose);
       if (!filtered)
       {
         // update the map
@@ -989,7 +1101,7 @@ void GazeboInterface::OnPoseMsg(ConstPosesStampedPtr &_msg)
   std::cout.flush();
   this->receivedMessage = true;
   lock.unlock();
-  this->receiveCondition->notify_one();
+  this->receiveCondition.notify_one();
 }
 
 /////////////////////////////////////////////////
@@ -998,11 +1110,11 @@ void GazeboInterface::OnRequest(ConstRequestPtr &_msg)
   if (!this->IsConnected())
     return;
 
-  boost::recursive_mutex::scoped_lock lock(*this->receiveMutex);
+  std::unique_lock<std::recursive_mutex> lock(this->receiveMutex);
   this->requestMsgs.push_back(_msg);
   this->receivedMessage = true;
   lock.unlock();
-  this->receiveCondition->notify_one();
+  this->receiveCondition.notify_one();
 }
 
 /////////////////////////////////////////////////
@@ -1018,7 +1130,8 @@ void GazeboInterface::OnResponse(ConstResponsePtr &_msg)
   {
     gazebo::msgs::Scene sceneMsg;
     sceneMsg.ParseFromString(_msg->serialized_data());
-    boost::shared_ptr<gazebo::msgs::Scene> sm(new gazebo::msgs::Scene(sceneMsg));
+    boost::shared_ptr<gazebo::msgs::Scene> sm(
+        new gazebo::msgs::Scene(sceneMsg));
     this->sceneMsgs.push_back(sm);
     this->requests.erase(_msg->id());
   }
@@ -1026,12 +1139,13 @@ void GazeboInterface::OnResponse(ConstResponsePtr &_msg)
   {
     gazebo::msgs::Physics physicsMsg;
     physicsMsg.ParseFromString(_msg->serialized_data());
-    boost::shared_ptr<gazebo::msgs::Physics> pm(new gazebo::msgs::Physics(physicsMsg));
+    boost::shared_ptr<gazebo::msgs::Physics> pm(
+        new gazebo::msgs::Physics(physicsMsg));
     this->physicsMsgs.push_back(pm);
     this->requests.erase(_msg->id());
   }
   this->receivedMessage = true;
-  this->receiveCondition->notify_one();
+  this->receiveCondition.notify_one();
 }
 
 /////////////////////////////////////////////////
@@ -1040,11 +1154,11 @@ void GazeboInterface::OnLightFactoryMsg(ConstLightPtr &_msg)
   if (!this->IsConnected())
     return;
 
-  boost::recursive_mutex::scoped_lock lock(*this->receiveMutex);
+  std::unique_lock<std::recursive_mutex> lock(this->receiveMutex);
   this->lightFactoryMsgs.push_back(_msg);
   this->receivedMessage = true;
   lock.unlock();
-  this->receiveCondition->notify_one();
+  this->receiveCondition.notify_one();
 }
 
 /////////////////////////////////////////////////
@@ -1053,11 +1167,11 @@ void GazeboInterface::OnLightModifyMsg(ConstLightPtr &_msg)
   if (!this->IsConnected())
     return;
 
-  boost::recursive_mutex::scoped_lock lock(*this->receiveMutex);
+  std::unique_lock<std::recursive_mutex> lock(this->receiveMutex);
   this->lightModifyMsgs.push_back(_msg);
   this->receivedMessage = true;
   lock.unlock();
-  this->receiveCondition->notify_one();
+  this->receiveCondition.notify_one();
 }
 
 /////////////////////////////////////////////////
@@ -1066,11 +1180,11 @@ void GazeboInterface::OnScene(ConstScenePtr &_msg)
   if (!this->IsConnected())
     return;
 
-  boost::recursive_mutex::scoped_lock lock(*this->receiveMutex);
+  std::unique_lock<std::recursive_mutex> lock(this->receiveMutex);
   this->sceneMsgs.push_back(_msg);
   this->receivedMessage = true;
   lock.unlock();
-  this->receiveCondition->notify_one();
+  this->receiveCondition.notify_one();
 }
 
 /////////////////////////////////////////////////
@@ -1079,49 +1193,56 @@ void GazeboInterface::OnPhysicsMsg(ConstPhysicsPtr &_msg)
   if (!this->IsConnected())
     return;
 
-  boost::recursive_mutex::scoped_lock lock(*this->receiveMutex);
+  std::unique_lock<std::recursive_mutex> lock(this->receiveMutex);
   this->physicsMsgs.push_back(_msg);
   this->receivedMessage = true;
   lock.unlock();
-  this->receiveCondition->notify_one();
+  this->receiveCondition.notify_one();
 }
 
 /////////////////////////////////////////////////
 void GazeboInterface::OnStats(ConstWorldStatisticsPtr &_msg)
 {
+  // store stats msg. This is sent to all clients when they first connect to
+  // the bridge to determine if gazebo is in sim or playback mode
+  this->statsMsg = _msg;
+
   if (!this->IsConnected())
     return;
 
   gazebo::common::Time wallTime;
   wallTime = gazebo::msgs::Convert(_msg->real_time());
+
+  gazebo::common::Time lastStatsTime;
+  if (this->lastStatsMsg)
+    lastStatsTime = gazebo::msgs::Convert(this->lastStatsMsg->real_time());
+  // bool playback = this->lastStatsMsg->has_log_playback_stats();
+  double timeDelta = (wallTime - lastStatsTime).Double();
   bool paused = _msg->paused();
 
   // pub at 1Hz, but force pub if world state changes
-  if (((wallTime - this->lastStatsTime).Double() >= 1.0) ||
-      wallTime < this->lastStatsTime ||
+  if (timeDelta >= 1.0 || wallTime < lastStatsTime ||
       this->lastPausedState != paused)
   {
-    this->lastStatsTime = wallTime;
     this->lastPausedState = paused;
-    boost::recursive_mutex::scoped_lock lock(*this->receiveMutex);
+    this->lastStatsMsg = _msg;
+
+    std::unique_lock<std::recursive_mutex> lock(this->receiveMutex);
     this->statsMsgs.push_back(_msg);
     this->receivedMessage = true;
     lock.unlock();
-    this->receiveCondition->notify_one();
+    this->receiveCondition.notify_one();
   }
 }
 
 /////////////////////////////////////////////////
 void GazeboInterface::OnRoad(ConstRoadPtr &_msg)
 {
-  if (!this->IsConnected())
-    return;
-
-  boost::recursive_mutex::scoped_lock lock(*this->receiveMutex);
+  std::unique_lock<std::recursive_mutex> lock(this->receiveMutex);
   this->roadMsgs.push_back(_msg);
   this->receivedMessage = true;
   lock.unlock();
-  this->receiveCondition->notify_one();
+  this->receiveCondition.notify_one();
 }
 
 /////////////////////////////////////////////////
@@ -1130,11 +1251,11 @@ void GazeboInterface::OnJointMsg(ConstJointPtr &_msg)
   if (!this->IsConnected())
     return;
 
-  boost::recursive_mutex::scoped_lock lock(*this->receiveMutex);
+  std::unique_lock<std::recursive_mutex> lock(this->receiveMutex);
   this->jointMsgs.push_back(_msg);
   this->receivedMessage = true;
   lock.unlock();
-  this->receiveCondition->notify_one();
+  this->receiveCondition.notify_one();
 }
 
 #ifdef GAZEBO_HBP_SUPPORT_JOINT_STATE_MESSAGES
@@ -1144,11 +1265,11 @@ void GazeboInterface::OnJointStateMsg(ConstJointStatePtr &_msg)
   if (!this->IsConnected())
     return;
 
-  boost::recursive_mutex::scoped_lock lock(*this->receiveMutex);
+  std::unique_lock<std::recursive_mutex> lock(this->receiveMutex);
   this->jointStateMsgs.push_back(_msg);
   this->receivedMessage = true;
   lock.unlock();
-  this->receiveCondition->notify_one();
+  this->receiveCondition.notify_one();
 }
 #endif
 
@@ -1158,11 +1279,11 @@ void GazeboInterface::OnMuscleVisualizationMsg(ConstOpenSimMusclesPtr &_msg)
   if (!this->IsConnected())
     return;
 
-  boost::recursive_mutex::scoped_lock lock(*this->receiveMutex);
+  std::unique_lock<std::recursive_mutex> lock(this->receiveMutex);
   this->muscleVisualizationMsgs.push_back(_msg);
   this->receivedMessage = true;
   lock.unlock();
-  this->receiveCondition->notify_one();
+  this->receiveCondition.notify_one();
 }  
 #endif
 
@@ -1172,11 +1293,11 @@ void GazeboInterface::OnSensorMsg(ConstSensorPtr &_msg)
   if (!this->IsConnected())
     return;
 
-  boost::recursive_mutex::scoped_lock lock(*this->receiveMutex);
+  std::unique_lock<std::recursive_mutex> lock(this->receiveMutex);
   this->sensorMsgs.push_back(_msg);
   this->receivedMessage = true;
   lock.unlock();
-  this->receiveCondition->notify_one();
+  this->receiveCondition.notify_one();
 }
 
 /////////////////////////////////////////////////
@@ -1185,11 +1306,11 @@ void GazeboInterface::OnVisualMsg(ConstVisualPtr &_msg)
   if (!this->IsConnected())
     return;
 
-  boost::recursive_mutex::scoped_lock lock(*this->receiveMutex);
+  std::unique_lock<std::recursive_mutex> lock(this->receiveMutex);
   this->visualMsgs.push_back(_msg);
   this->receivedMessage = true;
   lock.unlock();
-  this->receiveCondition->notify_one();
+  this->receiveCondition.notify_one();
 }
 
 /////////////////////////////////////////////////
@@ -1219,63 +1340,52 @@ std::string GazeboInterface::PackOutgoingServiceMsg(const std::string &_id,
 /////////////////////////////////////////////////
 void GazeboInterface::Send(const std::string &_msg)
 {
-//  if (this->socketServer)
-//    this->socketServer->Write(_msg);
-  boost::recursive_mutex::scoped_lock lock(outgoingMutex);
+  std::lock_guard<std::recursive_mutex> lock(this->outgoingMutex);
   if (outgoing.size() < MAX_NUM_MSG_SIZE)
-    outgoing.push_back(_msg);
+    this->outgoing.push_back(_msg);
 }
 
-/*
-/////////////////////////////////////////////////
-void GazeboInterface::Write(const std::string &_msg)
-{
-  boost::recursive_mutex::scoped_lock lock(outgoingMutex);
-  if (outgoing.size() < MAX_NUM_MSG_SIZE)
-    outgoing.push_back(_msg);
-}*/
-
 /////////////////////////////////////////////////
 std::vector<std::string> GazeboInterface::PopIncomingMessages()
 {
-  boost::recursive_mutex::scoped_lock lock(incomingMutex);
-  std::vector<std::string> in = incoming;
-  incoming.clear();
+  std::lock_guard<std::recursive_mutex> lock(this->incomingMutex);
+  std::vector<std::string> in = this->incoming;
+  this->incoming.clear();
   return in;
 }
 
 /////////////////////////////////////////////////
 void GazeboInterface::ClearIncomingMessages()
 {
-  boost::recursive_mutex::scoped_lock lock(incomingMutex);
-  incoming.clear();
+  std::lock_guard<std::recursive_mutex> lock(incomingMutex);
+  this->incoming.clear();
 }
 
 /////////////////////////////////////////////////
 std::vector<std::string> GazeboInterface::PopOutgoingMessages()
 {
-  boost::recursive_mutex::scoped_lock lock(outgoingMutex);
-  std::vector<std::string> out = outgoing;
-  outgoing.clear();
+  std::lock_guard<std::recursive_mutex> lock(this->outgoingMutex);
+  std::vector<std::string> out = this->outgoing;
+  this->outgoing.clear();
   return out;
 }
 
 /////////////////////////////////////////////////
 void GazeboInterface::ClearOutgoingMessages()
 {
-  boost::recursive_mutex::scoped_lock lock(outgoingMutex);
+  std::lock_guard<std::recursive_mutex> lock(outgoingMutex);
   outgoing.clear();
 }
 
 /////////////////////////////////////////////////
 void GazeboInterface::PushRequest(const std::string &_msg)
 {
-  boost::recursive_mutex::scoped_lock lock(incomingMutex);
+  std::unique_lock<std::recursive_mutex> lock(this->incomingMutex);
   if (incoming.size() < MAX_NUM_MSG_SIZE)
-    incoming.push_back(_msg);
+    this->incoming.push_back(_msg);
   this->receivedMessage = true;
   lock.unlock();
-  this->receiveCondition->notify_one();
+  this->receiveCondition.notify_one();
 }
 
 /////////////////////////////////////////////////
@@ -1286,46 +1396,84 @@ void GazeboInterface::LoadMaterialScripts(const std::string &_path)
 }
 
 /////////////////////////////////////////////////
-void GazeboInterface::WaitForServiceRequest() const
+void GazeboInterface::WaitForConnection()
 {
-  boost::recursive_mutex::scoped_lock lock(*this->serviceMutex);
-  while (this->serviceRequests.empty())
+  std::unique_lock<std::mutex> lock(this->connectionMutex);
+  while (!this->isConnected)
   {
-    this->serviceCondition->wait(lock);
+    this->connectionCondition.wait(lock);
   }
 }
 
 /////////////////////////////////////////////////
-void GazeboInterface::WaitForMessage() const
+void GazeboInterface::SetConnected(bool _connected)
 {
-  boost::recursive_mutex::scoped_lock lock(*this->receiveMutex);
-  while (!this->receivedMessage)
-  {
-    this->receiveCondition->wait(lock);
-  }
+  std::lock_guard<std::mutex> lock(this->connectionMutex);
+  this->isConnected = _connected;
+  this->connectionCondition.notify_all();
 }
 
 /////////////////////////////////////////////////
-void GazeboInterface::WaitForConnection() const
+bool GazeboInterface::IsConnected()
 {
-  boost::mutex::scoped_lock lock(*this->connectionMutex);
-  while (!this->isConnected)
-  {
-    this->connectionCondition->wait(lock);
-  }
+  std::lock_guard<std::mutex> lock(this->connectionMutex);
+  return this->isConnected;
 }
 
 /////////////////////////////////////////////////
-void GazeboInterface::SetConnected(bool _connected)
+void GazeboInterface::SetPoseFilterMinimumDistanceSquared(double _m)
 {
-  boost::mutex::scoped_lock lock(*this->connectionMutex);
-  this->isConnected = _connected;
-  this->connectionCondition->notify_all();
+  this->minimumDistanceSquared = _m;
 }
 
 /////////////////////////////////////////////////
-bool GazeboInterface::IsConnected() const
+double GazeboInterface::GetPoseFilterMinimumDistanceSquared()
 {
-  boost::mutex::scoped_lock lock(*this->connectionMutex);
-  return this->isConnected;
+  return this->minimumDistanceSquared;
+}
+
+/////////////////////////////////////////////////
+void GazeboInterface::SetPoseFilterMinimumQuaternionSquared(double _m)
+{
+  this->minimumQuaternionSquared = _m;
+}
+
+/////////////////////////////////////////////////
+double GazeboInterface::GetPoseFilterMinimumQuaternionSquared()
+{
+  return this->minimumQuaternionSquared;
+}
+
+/////////////////////////////////////////////////
+void GazeboInterface::SetPoseFilterMinimumMsgAge(double _m)
+{
+  this->minimumMsgAge = _m;
+}
+
+/////////////////////////////////////////////////
+double GazeboInterface::GetPoseFilterMinimumMsgAge()
+{
+  return this->minimumMsgAge;
 }
+
+/////////////////////////////////////////////////
+void GazeboInterface::WaitForMessage()
+{
+  std::unique_lock<std::recursive_mutex> lock(this->receiveMutex);
+  while (!this->receivedMessage)
+  {
+    this->receiveCondition.wait(lock);
+  }
+}
+
+/////////////////////////////////////////////////
+void GazeboInterface::WaitForServiceRequest()
+{
+  std::unique_lock<std::recursive_mutex> lock(this->serviceMutex);
+  while (this->serviceRequests.empty())
+  {
+    this->serviceCondition.wait(lock);
+  }
+}
+
+
diff --git a/gzbridge/GazeboInterface.hh b/gzbridge/GazeboInterface.hh
index 7960ee8..5e1ec7d 100644
--- a/gzbridge/GazeboInterface.hh
+++ b/gzbridge/GazeboInterface.hh
@@ -15,12 +15,16 @@
  *
 */
 
-#ifndef _GAZEBO_INTERFACE_HH_
-#define _GAZEBO_INTERFACE_HH_
+#ifndef GZBRIDGE_GAZEBOINTERFACE_HH_
+#define GZBRIDGE_GAZEBOINTERFACE_HH_
 
 #include <string>
 #include <list>
 #include <map>
+#include <memory>
+#include <mutex>
+#include <thread>
+#include <condition_variable>
 
 #include <gazebo/msgs/msgs.hh>
 #include <gazebo/transport/TransportIface.hh>
@@ -33,12 +37,6 @@
   #pragma message("Found no HBP Gazebo version : disabling HBP features")
 #endif
 
-
-namespace boost
-{
-  class thread;
-}
-
 namespace gzweb
 {
   class OgreMaterialParser;
@@ -93,7 +91,7 @@ namespace gzweb
 
     /// \brief Get the connected state
     /// \return True if there are client connections.
-    public: bool IsConnected() const;
+    public: bool IsConnected();
 
     /// \brief Pack topic publish message.
     private: std::string PackOutgoingTopicMsg(const std::string &_topic,
@@ -185,13 +183,13 @@ namespace gzweb
     private: void OnResponse(ConstResponsePtr &_msg);
 
     /// \brief Block if there are no connections.
-    private: void WaitForConnection() const;
+    private: void WaitForConnection();
 
     /// \brief Block if there are no service requests.
-    private: void WaitForServiceRequest() const;
+    private: void WaitForServiceRequest();
 
     /// \brief Block if there are no messages.
-    private: void WaitForMessage() const;
+    private: void WaitForMessage();
 
     /// \brief a pose at a specific time
     typedef std::pair<gazebo::common::Time, ignition::math::Pose3d> TimedPose;
@@ -204,16 +202,16 @@ namespace gzweb
         const TimedPose &_current);
 
     /// \brief Incoming messages.
-    public: static std::vector<std::string> incoming;
+    public: std::vector<std::string> incoming;
 
     /// \brief Outgoing messages.
-    public: static std::vector<std::string> outgoing;
+    public: std::vector<std::string> outgoing;
 
     /// \brief Thread to run the main loop.
-    private: boost::thread *runThread;
+    private: std::unique_ptr<std::thread> runThread;
 
     /// \brief Thread for processing services requests.
-    private: boost::thread *serviceThread;
+    private: std::unique_ptr<std::thread> serviceThread;
 
     /// \brief Gazebo transport node.
     private: gazebo::transport::NodePtr node;
@@ -285,29 +283,38 @@ namespace gzweb
     /// \brief Subscribe to reponses.
     private: gazebo::transport::SubscriberPtr responseSub;
 
+    /// \brief Publish playback control messages
+    private: gazebo::transport::PublisherPtr playbackControlPub;
+
     /// \brief Request message for getting initial scene info.
     private: std::map<int, gazebo::msgs::Request *> requests;
 
     /// \brief Mutex to lock the various message buffers.
-    private: boost::recursive_mutex *receiveMutex;
+    private: std::recursive_mutex receiveMutex;
 
     /// \brief Mutex to lock the service request buffer.
-    private: boost::recursive_mutex *serviceMutex;
+    private: std::recursive_mutex serviceMutex;
+
+    /// \brief Mutex to lock the incoming message request buffer.
+    private: std::recursive_mutex incomingMutex;
+
+    /// \brief Mutex to lock the outgoing message request buffer.
+    private: std::recursive_mutex outgoingMutex;
 
     /// \brief Mutex to protect the isConnected variable.
-    private: boost::mutex *connectionMutex;
+    private: std::mutex connectionMutex;
 
     /// \brief The condition to notify when connection state changes.
-    private: boost::condition_variable *connectionCondition;
+    public: std::condition_variable connectionCondition;
 
     /// \brief The condition to notify the service thread when new requests arrived.
-    private: boost::condition_variable_any *serviceCondition;
+    private: std::condition_variable_any serviceCondition;
 
     /// \brief The number of received messages not processed so far
     private: bool receivedMessage;
 
     /// \brief The condition to notify the message thread when new messages arrived.
-    private: boost::condition_variable_any *receiveCondition;
+    private: std::condition_variable_any receiveCondition;
 
     /// \def ModelMsgs_L
     /// \brief List of model messages.
@@ -428,7 +435,7 @@ namespace gzweb
     private: std::vector<std::string> serviceRequests;
 
     /// \brief True to stop the interface.
-    private: bool stop;
+    private: bool stop = false;
 
     /// \brief Name of sensor topic.
     private: std::string sensorTopic;
@@ -498,17 +505,25 @@ namespace gzweb
     /// \brief Name of delete topic.
     private: std::string deleteTopic;
 
+    /// \brief Name of playback control topic.
+    private: std::string playbackControlTopic;
+
     /// \brief Ogre material parser.
-    private: OgreMaterialParser *materialParser;
+    private: OgreMaterialParser *materialParser = nullptr;
 
-    /// \brief Last world stats time received
-    private: gazebo::common::Time lastStatsTime;
+    /// \brief Last world stats msg received
+    private: boost::shared_ptr<gazebo::msgs::WorldStatistics const>
+        lastStatsMsg;
+
+    /// \brief Most recent world stats msg received
+    private: boost::shared_ptr<gazebo::msgs::WorldStatistics const>
+        statsMsg;
 
     /// \brief Last world state received, play or paused.
     private: bool lastPausedState;
 
     /// \brief filter pose message based on minimum distance criteria
-    private: double minimumDistanceSquared;
+    private: double minimumDistanceSquared = 0;
 
     /// \brief filter pose message based on minimum rotation criteria
     private: double minimumQuaternionSquared;
@@ -519,45 +534,22 @@ namespace gzweb
     /// \brief filter pose message based on minimum rotation criteria  when message arrives too early
     private: double minimumQuaternionSquaredTooEarly;
 
-
     /// \brief filter pose message based on minimum elapsed time (seconds)
-    private: double minimumMsgAge;
+    private: double minimumMsgAge = 0;
 
-    private: int skippedMsgCount;
-    private: int messageWindowSize;
-    private: int messageCount;
+    private: int skippedMsgCount = 0;
+    private: int messageWindowSize = 0;
+    private: int messageCount = 0;
 
     /// \brief True if there is a client connection.
-    private: bool isConnected;
-
-    public: inline void SetPoseFilterMinimumDistanceSquared(double m)
-    {
-      this->minimumDistanceSquared = m;
-    }
-    public: inline double GetPoseFilterMinimumDistanceSquared()
-    {
-      return this->minimumDistanceSquared;
-    }
-
-    public: inline void SetPoseFilterMinimumQuaternionSquared(double m)
-    {
-      this->minimumQuaternionSquared = m;
-    }
-
-    public: inline double GetPoseFilterMinimumQuaternionSquared()
-    {
-      return this->minimumQuaternionSquared;
-    }
-
-    public: inline void SetPoseFilterMinimumMsgAge(double m)
-    {
-      this->minimumMsgAge = m;
-    }
-
-    public: inline double GetPoseFilterMinimumMsgAge()
-    {
-      return this->minimumMsgAge;
-    }
+    private: bool isConnected = false;
+
+    public: void SetPoseFilterMinimumDistanceSquared(double _m);
+    public: double GetPoseFilterMinimumDistanceSquared();
+    public: void SetPoseFilterMinimumQuaternionSquared(double _m);
+    public: double GetPoseFilterMinimumQuaternionSquared();
+    public: void SetPoseFilterMinimumMsgAge(double _m);
+    public: double GetPoseFilterMinimumMsgAge();
   };
 }
 
diff --git a/gzbridge/OgreMaterialParser.cc b/gzbridge/OgreMaterialParser.cc
index 12b2cb3..acc1657 100644
--- a/gzbridge/OgreMaterialParser.cc
+++ b/gzbridge/OgreMaterialParser.cc
@@ -62,7 +62,6 @@ std::string OgreMaterialParser::GetMaterialAsJson() const
 
   std::map<std::string, ConfigNode *>::iterator it;
   bool first = true;
-
   for (it = scripts.begin(); it != scripts.end(); ++it)
   {
     std::string name = it->first;
@@ -122,6 +121,12 @@ std::string OgreMaterialParser::GetMaterialAsJson() const
           if (textureNode)
           {
             std::string textureStr = textureNode->getValue(0);
+            index = textureStr.rfind(".");
+            if (index != std::string::npos)
+            {
+              textureStr = textureStr.substr(0, index+1) + "png";
+            }
+
             jsonStr += "\"texture\":\"" + textureStr + "\",";
           }
           ConfigNode *scaleNode = textureUnitNode->findChild("scale");
diff --git a/gzbridge/OgreMaterialParser.hh b/gzbridge/OgreMaterialParser.hh
index d5797d0..afdb887 100644
--- a/gzbridge/OgreMaterialParser.hh
+++ b/gzbridge/OgreMaterialParser.hh
@@ -1,5 +1,5 @@
-#ifndef _OGRE_MATERIAL_PARSER_HH_
-#define _OGRE_MATERIAL_PARSER_HH_
+#ifndef GZBRIDGE_OGREMATERIALPARSER_HH_
+#define GZBRIDGE_OGREMATERIALPARSER_HH_
 
 #include <string>
 
@@ -18,7 +18,7 @@ namespace gzweb
 
     public: std::string GetMaterialAsJson() const;
 
-    private: ConfigLoader *configLoader;
+    private: ConfigLoader *configLoader = nullptr;
   };
 
 }
diff --git a/gzbridge/pb2json.cc b/gzbridge/pb2json.cc
index dc39e6d..c85a9d3 100644
--- a/gzbridge/pb2json.cc
+++ b/gzbridge/pb2json.cc
@@ -43,22 +43,26 @@ namespace gzweb {
     return output;
   }
 
-  char *pb2json(const Message &msg)
+  std::string pb2json(const Message &msg)
   {
     json_t *root = parse_msg(&msg);
     char *json = json_dumps(root, 0);
+    std::string str(json);
     json_decref(root);
-    return json; // should be freed by caller
+    delete json;
+    return str;
   }
 
-  char *pb2json(Message *msg, const char *buf, int len)
+  std::string pb2json(Message *msg, const char *buf, int len)
   {
     std::string s (buf, len);
     msg->ParseFromString(s);
     json_t *root = parse_msg(msg);
     char *json = json_dumps(root, 0);
+    std::string str(json);
     json_decref(root);
-    return json; // should be freed by caller
+    delete json;
+    return str;
   }
 
   json_t *parse_repeated_field(const Message *msg,
@@ -294,13 +298,126 @@ namespace gzweb {
     return "";
   }
 
-  std::string get_value(const std::string &msg, const std::string &key)
+  std::string get_value(const std::string &_msg, const std::string &_key)
   {
     json_t *root;
     json_error_t error;
-    root = json_loads(msg.c_str(), 0, &error);
-    std::string result = get(root, key);
+    root = json_loads(_msg.c_str(), 0, &error);
+    std::string result = get(root, _key);
     json_decref(root);
     return result;
   }
+
+  /// \brief Private class of the JsonObj
+  class JsonObjPrivate
+  {
+    /// \brief Pointer to internal json object
+    public: json_t *json = nullptr;
+
+    /// \brief True if we should decrement ref count on internal json obj
+    public: bool decref = true;
+  };
+}
+
+using namespace gzweb;
+
+//////////////////////////////////////////////////
+JsonObj::JsonObj(const std::string &_str)
+  : dataPtr(new JsonObjPrivate)
+{
+  json_error_t error;
+  this->dataPtr->json = json_loads(_str.c_str(), 0, &error);
+}
+
+//////////////////////////////////////////////////
+JsonObj::JsonObj(json_t *_obj)
+  : dataPtr(new JsonObjPrivate)
+{
+  this->dataPtr->json = _obj;
+  this->dataPtr->decref = false;
+}
+
+//////////////////////////////////////////////////
+JsonObj::JsonObj(const JsonObj &_other)
+  : dataPtr(new JsonObjPrivate)
+{
+  *this->dataPtr = *_other.dataPtr;
+}
+
+//////////////////////////////////////////////////
+JsonObj::~JsonObj()
+{
+  if (this->dataPtr->decref)
+    json_decref(this->dataPtr->json);
+}
+
+//////////////////////////////////////////////////
+JsonObj JsonObj::Object(const std::string &_key) const
+{
+  if (json_is_object(this->dataPtr->json))
+  {
+    json_t *obj = json_object_get(this->dataPtr->json, _key.c_str());
+    return JsonObj(obj);
+  }
+  return JsonObj(nullptr);
+}
+
+//////////////////////////////////////////////////
+double JsonObj::Number() const
+{
+  if (json_is_number(this->dataPtr->json))
+  {
+    return json_number_value(this->dataPtr->json);
+  }
+  return 0.0;
+}
+
+//////////////////////////////////////////////////
+bool JsonObj::Bool() const
+{
+  if (json_is_boolean(this->dataPtr->json))
+  {
+    return json_boolean_value(this->dataPtr->json);
+  }
+  return false;
+}
+
+//////////////////////////////////////////////////
+std::string JsonObj::String() const
+{
+  if (json_is_string(this->dataPtr->json))
+  {
+    return json_string_value(this->dataPtr->json);
+  }
+  return std::string();
+}
+
+
+//////////////////////////////////////////////////
+JsonObj JsonObj::ArrayObject(const unsigned int _index) const
+{
+  if (json_is_array(this->dataPtr->json))
+  {
+    json_t *obj = json_array_get(this->dataPtr->json, _index);
+    return JsonObj(obj);
+  }
+
+  return JsonObj(nullptr);
+}
+
+//////////////////////////////////////////////////
+unsigned int JsonObj::ArraySize() const
+{
+  if (json_is_array(this->dataPtr->json))
+  {
+    return json_array_size(this->dataPtr->json);
+  }
+
+  return 0u;
+}
+
+//////////////////////////////////////////////////
+JsonObj::operator bool() const
+{
+  return this->dataPtr->json != nullptr;
 }
diff --git a/gzbridge/pb2json.hh b/gzbridge/pb2json.hh
index 3ece65e..a5bfd10 100644
--- a/gzbridge/pb2json.hh
+++ b/gzbridge/pb2json.hh
@@ -15,8 +15,10 @@
  *
 */
 
-#ifndef _PB2JSON_H_
-#define _PB2JSON_H_
+#ifndef GZBRIDGE_PB2JSON_HH_
+#define GZBRIDGE_PB2JSON_HH_
+
+#include <memory>
 
 #include <google/protobuf/descriptor.h>
 #include <google/protobuf/message.h>
@@ -24,9 +26,9 @@
 
 namespace gzweb
 {
-  char *pb2json(const google::protobuf::Message &msg);
+  std::string pb2json(const google::protobuf::Message &msg);
 
-  char *pb2json(google::protobuf::Message *msg,const char *buf,int len);
+  std::string pb2json(google::protobuf::Message *msg,const char *buf,int len);
 
   std::string get_value(const std::string &msg, const std::string &key);
 
@@ -35,6 +37,63 @@ namespace gzweb
   json_t *parse_repeated_field(const google::protobuf::Message *msg,
       const google::protobuf::Reflection *ref,
       const google::protobuf::FieldDescriptor *field);
+
+
+  // forward declaration
+  class JsonObjPrivate;
+
+  /// \brief C++ interface for manipulating json object
+  class JsonObj
+  {
+    /// \brief Constructor
+    /// \param[in] _str input json string
+    public: JsonObj(const std::string &_str);
+
+    /// \brief Copy constructor
+    /// \param[in] _other Other JsonObj
+    public: JsonObj(const JsonObj &_other);
+
+    /// \brief Destructor
+    public: ~JsonObj();
+
+    /// \brief Get child json object
+    /// \param[in] _key Json key
+    /// \return JsonObj, false if key not found.
+    public: JsonObj Object(const std::string &_key) const;
+
+    /// \brief Get number value
+    /// \return Double value, zero if value is not a number.
+    public: double Number() const;
+
+    /// \brief Get bool value
+    /// \return Bool value, always false if value is not a bool.
+    public: bool Bool() const;
+
+    /// \brief Get string value
+    /// \return String value, empty if value is not a string.
+    public: std::string String() const;
+
+    /// \brief If this object is an array, get json object at specified
+    /// array index.
+    /// \param[in] _index Index in the array
+    /// \return JsonObj array, false if not an array.
+    public: JsonObj ArrayObject(const unsigned int _index) const;
+
+    /// \brief If this object is an array, get the size of the array
+    /// \return Size of array, 0u if not an array.
+    public: unsigned int ArraySize() const;
+
+    /// \brief Bool operator
+    /// \return True if pointer to json object is not null
+    public: operator bool() const;
+
+    /// \brief Private constructor
+    /// \param[in] _obj Internal json object
+    private: JsonObj(json_t *_obj);
+
+    /// \brief Internal private data pointer.
+    private: std::unique_ptr<JsonObjPrivate> dataPtr;
+  };
 }
 
 #endif
diff --git a/gzbridge/server.js b/gzbridge/server.js
new file mode 100755
index 0000000..1a16eef
--- /dev/null
+++ b/gzbridge/server.js
@@ -0,0 +1,175 @@
+#!/usr/bin/env node
+
+"use strict"
+
+const debug = require('debug')('ws_server');
+
+if (process.argv.length != 2 && process.argv.length != 4) {
+    console.error('Server called with wrong parameters: usage ws_server [gzserver_host gzserver_port]')
+    process.exit(1);
+}
+
+const WebSocketServer = require('websocket').server;
+const http = require('http');
+const gzbridge = require('./build/Release/gzbridge');
+
+/**
+ * Path from where the static site is served
+ */
+const staticBasePath = './../http/client';
+
+/**
+ * Port to connect websocket
+ */
+const wsPort = 7681;
+
+/**
+ * Array of websocket connections currently active
+ */
+let connections = [];
+
+/**
+ * Holds the message containing all material scripts in case there is no
+ * gzserver connected
+ */
+let materialScriptsMessage = {};
+
+/**
+ * Whether the websocket is connected to a gzserver
+ */
+let isConnected = false;
+
+// process.argv[2] is gzserver host, process.argv[3] is gzserver port.
+let gzNode =
+    (process.argv.length === 2) ?
+    new gzbridge.GZNode() : new gzbridge.GZNode(process.argv[2], process.argv[3]);
+
+if (gzNode.getIsGzServerConnected()) {
+    gzNode.loadMaterialScripts(staticBasePath + '/assets');
+
+    var x = parseFloat(process.env.GZBRIDGE_POSE_FILTER_DELTA_TRANSLATION || '0.001')
+    gzNode.setPoseMsgFilterMinimumDistanceSquared(x);
+    var x = parseFloat(process.env.GZBRIDGE_POSE_FILTER_DELTA_ROTATION || '0.001')
+    gzNode.setPoseMsgFilterMinimumQuaternionSquared(x);
+    var x = parseFloat(process.env.GZBRIDGE_UPDATE_EARLY_THRESHOLD || '0.02')
+    gzNode.setPoseMsgFilterMinimumAge(x);
+
+    console.log('Pose message filter parameters: ');
+    console.log('  minimum seconds between successive messages: ' +
+        gzNode.getPoseMsgFilterMinimumAge());
+    console.log('  minimum XYZ distance squared between successive messages: ' +
+        gzNode.getPoseMsgFilterMinimumDistanceSquared());
+    console.log('  minimum Quaternion distance squared between successive messages:'
+        + ' ' + gzNode.getPoseMsgFilterMinimumQuaternionSquared());
+    console.log('--------------------------------------------------------------');
+} else {
+    materialScriptsMessage =
+        gzNode.getMaterialScriptsMessage(staticBasePath + '/assets');
+}
+
+let httpServer = http.createServer(function (request, response) {
+    console.log(new Date() + ' Received request for ' + request.url);
+    response.writeHead(404);
+    response.end();
+});
+
+httpServer.listen(wsPort, function () {
+    console.log(new Date() + ' gzbridge Websocket is listening on port: ' + wsPort);
+});
+
+// Start websocket server
+let wsServer = new WebSocketServer({
+    httpServer: httpServer,
+    // You should not use autoAcceptConnections for production
+    // applications, as it defeats all standard cross-origin protection
+    // facilities built into the protocol and the browser.  You should
+    // *always* verify the connection's origin and decide whether or not
+    // to accept it.
+    autoAcceptConnections: false
+});
+
+function originIsAllowed(_origin) {
+    // put logic here to detect whether the specified origin is allowed.
+    return true;
+}
+
+wsServer.on('request', function (request) {
+    console.log(new Date() + ' New request from: ' + request.origin);
+
+    if (!originIsAllowed(request.origin)) {
+        // Make sure we only accept requests from an allowed origin
+        request.reject();
+        console.log((new Date()) + ' Connection from origin ' +
+            request.origin + ' rejected.');
+        return;
+    }
+    // Accept request
+    let connection = request.accept(null, request.origin);
+
+    // If gzserver is not connected just send material scripts and status
+    if (!gzNode.getIsGzServerConnected()) {
+        // create error status and send it
+        let statusMessage =
+            '{"op":"publish","topic":"~/status","msg":{"status":"error"}}';
+        connection.sendUTF(statusMessage);
+        // send material scripts message
+        connection.sendUTF(materialScriptsMessage);
+        return;
+    }
+
+    connections.push(connection);
+
+    if (!isConnected) {
+        isConnected = true;
+        gzNode.setConnected(isConnected);
+    }
+
+    console.log(new Date() + ' New connection accepted from: ' + request.origin +
+        ' ' + connection.remoteAddress);
+
+    // Handle messages received from client
+    connection.on('message', function (message) {
+        debug("On message");
+
+        if (message.type === 'utf8') {
+            debug(new Date() + ' Received Message: ' + message.utf8Data +
+                ' from ' + request.origin + ' ' + connection.remoteAddress);
+            gzNode.request(message.utf8Data);
+        } else if (message.type === 'binary') {
+            debug(new Date() + ' Received Binary Message of ' +
+                message.binaryData.length + ' bytes from ' + request.origin + ' ' +
+                connection.remoteAddress);
+            connection.sendBytes(message.binaryData);
+        }
+    });
+    // Handle client disconnection
+    connection.on('close', function (reasonCode, description) {
+        console.log(new Date() + ' Peer ' + request.origin + ' ' +
+            connection.remoteAddress + ' disconnected.');
+
+        // remove connection from array
+        let conIndex = connections.indexOf(connection);
+        connections.splice(conIndex, 1);
+
+        // if there is no connection notify server that there is no connected client
+        if (connections.length === 0) {
+            isConnected = false;
+            gzNode.setConnected(isConnected);
+        }
+    });
+});
+
+// If not connected, periodically send messages
+if (gzNode.getIsGzServerConnected()) {
+    setInterval(function () {
+        if (connections.length > 0) {
+            let msgs = gzNode.getMessages();
+            for (let i = 0; i < connections.length; ++i) {
+                for (let j = 0; j < msgs.length; ++j) {
+                    connections[i].sendUTF(msgs[j]);
+                }
+            }
+        }
+    }, 10);
+}
+
diff --git a/gzbridge/ws_server.js b/gzbridge/ws_server.js
deleted file mode 100755
index ef93f42..0000000
--- a/gzbridge/ws_server.js
+++ /dev/null
@@ -1,152 +0,0 @@
-#!/usr/bin/env node
-
-var debug = require('debug')('ws_server');
-
-if (process.argv.length != 2 && process.argv.length != 4) {
-  console.error('Server called with wrong parameters: usage ws_server [gzserver_host gzserver_port]')
-  process.exit(1);
-}
-
-var WebSocketServer = require('websocket').server;
-var http = require('http');
-
-var connections = [];
-var materialScriptsMessage = {};
-var addon = require('./build/Release/gzbridge');
-
-if (process.argv.length == 2) {
-  var gzconnection = new addon.GZNode();
-}
-else {
-  // process.argv[2] is gzserver host, process.argv[3] is gzserver port.
-  var gzconnection = new addon.GZNode(process.argv[2], process.argv[3]);
-}
-
-if (gzconnection.getIsGzServerConnected())
-{
-  gzconnection.loadMaterialScripts('../http/client/assets');
-
-  var x = parseFloat(process.env.GZBRIDGE_POSE_FILTER_DELTA_TRANSLATION || '0.001')
-  gzconnection.setPoseMsgFilterMinimumDistanceSquared(x);
-  var x = parseFloat(process.env.GZBRIDGE_POSE_FILTER_DELTA_ROTATION || '0.001')
-  gzconnection.setPoseMsgFilterMinimumQuaternionSquared(x);
-  var x = parseFloat(process.env.GZBRIDGE_UPDATE_EARLY_THRESHOLD || '0.02')
-  gzconnection.setPoseMsgFilterMinimumAge(x);
-
-  console.log('Pose message filter parameters: ');
-  console.log('  minimum seconds between successive messages: ' +
-      gzconnection.getPoseMsgFilterMinimumAge());
-  console.log('  minimum XYZ distance squared between successive messages: ' +
-      gzconnection.getPoseMsgFilterMinimumDistanceSquared());
-  console.log('  minimum Quaternion distance squared between successive messages:'
-      + ' ' + gzconnection.getPoseMsgFilterMinimumQuaternionSquared());
-}
-else
-{
-  materialScriptsMessage = gzconnection.getMaterialScriptsMessage('../http/client/assets');
-}
-
-var isConnected = false;
-
-var server = http.createServer(function(request, response) {
-    console.log((new Date()) + ' Received request for ' + request.url);
-    response.writeHead(404);
-    response.end();
-});
-server.listen(7681, function() {
-    console.log((new Date()) + ' Server is listening on port 7681');
-});
-
-wsServer = new WebSocketServer({
-    httpServer: server,
-    // You should not use autoAcceptConnections for production
-    // applications, as it defeats all standard cross-origin protection
-    // facilities built into the protocol and the browser.  You should
-    // *always* verify the connection's origin and decide whether or not
-    // to accept it.
-    autoAcceptConnections: false
-});
-
-function originIsAllowed(origin) {
-  // put logic here to detect whether the specified origin is allowed.
-  return true;
-}
-
-wsServer.on('request', function(request) {
-    if (!originIsAllowed(request.origin)) {
-      // Make sure we only accept requests from an allowed origin
-      request.reject();
-      console.log((new Date()) + ' Connection from origin ' +
-          request.origin + ' rejected.');
-      return;
-    }
-
-    var connection = request.accept(null, request.origin);
-
-    // if gzserver is not connected just send material scripts and status
-    if (!gzconnection.getIsGzServerConnected())
-    {
-      // create error status and send it
-      var statusMessage = '{"op":"publish","topic":"~/status","msg":{"status":"error"}}';
-      connection.sendUTF(statusMessage);
-      // send material scripts message
-      connection.sendUTF(materialScriptsMessage);
-      return;
-    }
-
-    connections.push(connection);
-
-    if (!isConnected)
-    {
-      isConnected = true;
-      gzconnection.setConnected(isConnected);
-    }
-
-    console.log((new Date()) + ' Connection accepted.');
-    connection.on('message', function(message) {
-      if (message.type === 'utf8') {
-        debug('Received Message: ' + message.utf8Data + ' from ' +
-            request.origin + ' ' + connection.remoteAddress);
-        gzconnection.request(message.utf8Data);
-      }
-      else if (message.type === 'binary') {
-        debug('Received Binary Message of ' +
-            message.binaryData.length + ' bytes');
-        connection.sendBytes(message.binaryData);
-      }
-    });
-    connection.on('close', function(reasonCode, description) {
-        console.log((new Date()) + ' Peer ' + connection.remoteAddress +
-            ' disconnected.');
-
-      // remove connection from array
-      var conIndex = connections.indexOf(connection);
-      connections.splice(conIndex, 1);
-
-      // if there is no connection notify server that there is no connected client
-      if (connections.length == 0) {
-        isConnected = false;
-        gzconnection.setConnected(isConnected);
-      }
-    });
-});
-
-if (gzconnection.getIsGzServerConnected())
-{
-  setInterval(update, 10);
-
-  function update()
-  {
-    if (connections.length > 0)
-    {
-      var msgs = gzconnection.getMessages();
-      for (var i = 0; i < connections.length; ++i)
-      {
-        for (var j = 0; j < msgs.length; ++j)
-        {
-          connections[i].sendUTF(msgs[j]);
-        }
-      }
-    }
-  }
-}
diff --git a/tools/gzcoarse.cc b/tools/gzcoarse.cc
index fbdad7d..589ed49 100644
--- a/tools/gzcoarse.cc
+++ b/tools/gzcoarse.cc
@@ -18,6 +18,7 @@
 #include <gts.h>
 #include <tinyxml.h>
 #include <math.h>
+#include <gazebo/gazebo_config.h>
 #include <gazebo/common/Mesh.hh>
 #include <gazebo/common/Material.hh>
 #include <gazebo/common/ColladaLoader.hh>
@@ -535,7 +536,11 @@ void ExportEffects(TiXmlElement *_libraryEffectsXml,
     techniqueXml->LinkEndChild(phongXml);
 
     // ambient
+#if GAZEBO_MAJOR_VERSION >= 9
+    unsigned int RGBAcolor = material->Ambient().AsRGBA();
+#else
     unsigned int RGBAcolor = material->GetAmbient().GetAsRGBA();
+#endif
     float r = ((RGBAcolor >> 24) & 0xFF) / 255.0f;
     float g = ((RGBAcolor >> 16) & 0xFF) / 255.0f;
     float b = ((RGBAcolor >> 8) & 0xFF) / 255.0f;
@@ -550,7 +555,11 @@ void ExportEffects(TiXmlElement *_libraryEffectsXml,
     ambientXml->LinkEndChild(colorXml);
 
     // emission
+#if GAZEBO_MAJOR_VERSION >= 9
+    RGBAcolor = material->Emissive().AsRGBA();
+#else
     RGBAcolor = material->GetEmissive().GetAsRGBA();
+#endif
     r = ((RGBAcolor >> 24) & 0xFF) / 255.0f;
     g = ((RGBAcolor >> 16) & 0xFF) / 255.0f;
     b = ((RGBAcolor >> 8) & 0xFF) / 255.0f;
@@ -578,7 +587,11 @@ void ExportEffects(TiXmlElement *_libraryEffectsXml,
     }
     else
     {
+#if GAZEBO_MAJOR_VERSION >= 9
+      RGBAcolor = material->Diffuse().AsRGBA();
+#else
       RGBAcolor = material->GetDiffuse().GetAsRGBA();
+#endif
       r = ((RGBAcolor >> 24) & 0xFF) / 255.0f;
       g = ((RGBAcolor >> 16) & 0xFF) / 255.0f;
       b = ((RGBAcolor >> 8) & 0xFF) / 255.0f;
@@ -591,7 +604,11 @@ void ExportEffects(TiXmlElement *_libraryEffectsXml,
     }
 
     // specular
+#if GAZEBO_MAJOR_VERSION >= 9
+    RGBAcolor = material->Specular().AsRGBA();
+#else
     RGBAcolor = material->GetSpecular().GetAsRGBA();
+#endif
     r = ((RGBAcolor >> 24) & 0xFF) / 255.0f;
     g = ((RGBAcolor >> 16) & 0xFF) / 255.0f;
     b = ((RGBAcolor >> 8) & 0xFF) / 255.0f;
@@ -1287,10 +1304,17 @@ int main(int argc, char **argv)
     gazebo::common::Material *outMaterial = new gazebo::common::Material();
 
     outMaterial->SetTextureImage(inMaterial->GetTextureImage());
+#if GAZEBO_MAJOR_VERSION >= 9
+    outMaterial->SetAmbient(inMaterial->Ambient());
+    outMaterial->SetDiffuse(inMaterial->Diffuse());
+    outMaterial->SetSpecular(inMaterial->Specular());
+    outMaterial->SetEmissive(inMaterial->Emissive());
+#else
     outMaterial->SetAmbient(inMaterial->GetAmbient());
     outMaterial->SetDiffuse(inMaterial->GetDiffuse());
     outMaterial->SetSpecular(inMaterial->GetSpecular());
     outMaterial->SetEmissive(inMaterial->GetEmissive());
+#endif
     outMaterial->SetTransparency(inMaterial->GetTransparency());
     outMaterial->SetShininess(inMaterial->GetShininess());
 
-- 
GitLab