diff --git a/animation-server/src/AnimationServer.cpp b/animation-server/src/AnimationServer.cpp
index e4f2dbc530..f684a6e672 100644
--- a/animation-server/src/AnimationServer.cpp
+++ b/animation-server/src/AnimationServer.cpp
@@ -598,10 +598,10 @@ void* animateVoxels(void* args) {
     
     bool firstTime = true;
     
-    qDebug() << "Setting PPS to " << ::packetsPerSecond << "\n";
+    qDebug() << "Setting PPS to " << ::packetsPerSecond;
     ::voxelEditPacketSender->setPacketsPerSecond(::packetsPerSecond);
     
-    qDebug() << "PPS set to " << ::voxelEditPacketSender->getPacketsPerSecond() << "\n";
+    qDebug() << "PPS set to " << ::voxelEditPacketSender->getPacketsPerSecond();
     
     while (true) {
         
diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp
index 2bbd549d4a..6b5a4923f8 100644
--- a/assignment-client/src/Agent.cpp
+++ b/assignment-client/src/Agent.cpp
@@ -67,7 +67,7 @@ void Agent::run() {
     QNetworkAccessManager *networkManager = new QNetworkAccessManager(this);
     QNetworkReply *reply = networkManager->get(QNetworkRequest(QUrl(scriptURLString)));
     
-    qDebug() << "Downloading script at" << scriptURLString << "\n";
+    qDebug() << "Downloading script at" << scriptURLString;
     
     QEventLoop loop;
     QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
@@ -76,7 +76,7 @@ void Agent::run() {
     
     QString scriptContents(reply->readAll());
     
-    qDebug() << "Downloaded script:" << scriptContents << "\n";
+    qDebug() << "Downloaded script:" << scriptContents;
     
     timeval startTime;
     gettimeofday(&startTime, NULL);
diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp
index f3458c8afb..40d3adab62 100644
--- a/assignment-client/src/AssignmentClient.cpp
+++ b/assignment-client/src/AssignmentClient.cpp
@@ -83,7 +83,7 @@ AssignmentClient::AssignmentClient(int &argc, char **argv) :
     }
     
     // call a timer function every ASSIGNMENT_REQUEST_INTERVAL_MSECS to ask for assignment, if required
-    qDebug() << "Waiting for assignment -" << _requestAssignment << "\n";
+    qDebug() << "Waiting for assignment -" << _requestAssignment;
     
     QTimer* timer = new QTimer(this);
     connect(timer, SIGNAL(timeout()), SLOT(sendAssignmentRequest()));
@@ -121,20 +121,19 @@ void AssignmentClient::readPendingDatagrams() {
             } else if (packetData[0] == PACKET_TYPE_DEPLOY_ASSIGNMENT || packetData[0] == PACKET_TYPE_CREATE_ASSIGNMENT) {
                 
                 if (_currentAssignment) {
-                    qDebug() << "Dropping received assignment since we are currently running one.\n";
+                    qDebug() << "Dropping received assignment since we are currently running one.";
                 } else {
                     // construct the deployed assignment from the packet data
                     _currentAssignment = AssignmentFactory::unpackAssignment(packetData, receivedBytes);
                     
-                    qDebug() << "Received an assignment -" << *_currentAssignment << "\n";
+                    qDebug() << "Received an assignment -" << *_currentAssignment;
                     
                     // switch our nodelist domain IP and port to whoever sent us the assignment
                     if (packetData[0] == PACKET_TYPE_CREATE_ASSIGNMENT) {
                         nodeList->setDomainSockAddr(senderSockAddr);
                         nodeList->setOwnerUUID(_currentAssignment->getUUID());
                         
-                        qDebug("Destination IP for assignment is %s\n",
-                               nodeList->getDomainIP().toString().toStdString().c_str());
+                        qDebug() << "Destination IP for assignment is" << nodeList->getDomainIP().toString();
                         
                         // start the deployed assignment
                         QThread* workerThread = new QThread(this);
@@ -148,10 +147,13 @@ void AssignmentClient::readPendingDatagrams() {
                         
                         _currentAssignment->moveToThread(workerThread);
                         
+                        // move the NodeList to the thread used for the _current assignment
+                        nodeList->moveToThread(workerThread);
+                        
                         // Starts an event loop, and emits workerThread->started()
                         workerThread->start();
                     } else {
-                        qDebug("Received a bad destination socket for assignment.\n");
+                        qDebug("Received a bad destination socket for assignment.");
                     }
                 }
             } else {
@@ -166,12 +168,15 @@ void AssignmentClient::assignmentCompleted() {
     // reset the logging target to the the CHILD_TARGET_NAME
     Logging::setTargetName(ASSIGNMENT_CLIENT_TARGET_NAME);
     
-    qDebug("Assignment finished or never started - waiting for new assignment\n");
+    qDebug("Assignment finished or never started - waiting for new assignment.");
     
     _currentAssignment = NULL;
     
     NodeList* nodeList = NodeList::getInstance();
     
+    // move the NodeList back to our thread
+    nodeList->moveToThread(thread());
+    
     // reset our NodeList by switching back to unassigned and clearing the list
     nodeList->setOwnerType(NODE_TYPE_UNASSIGNED);
     nodeList->reset();
diff --git a/assignment-client/src/AssignmentClientMonitor.cpp b/assignment-client/src/AssignmentClientMonitor.cpp
index fa050a0dac..4386ccfff0 100644
--- a/assignment-client/src/AssignmentClientMonitor.cpp
+++ b/assignment-client/src/AssignmentClientMonitor.cpp
@@ -47,10 +47,10 @@ void AssignmentClientMonitor::spawnChildClient() {
     connect(assignmentClient, SIGNAL(finished(int, QProcess::ExitStatus)), this,
             SLOT(childProcessFinished(int, QProcess::ExitStatus)));
     
-    qDebug() << "Spawned a child client with PID" << assignmentClient->pid() << "\n";
+    qDebug() << "Spawned a child client with PID" << assignmentClient->pid();
 }
 
 void AssignmentClientMonitor::childProcessFinished(int exitCode, QProcess::ExitStatus exitStatus) {
-    qDebug() << "Replacing dead child assignment client with a new one.\n";
+    qDebug("Replacing dead child assignment client with a new one");
     spawnChildClient();
 }
\ No newline at end of file
diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp
index 8037313fb3..bad297e5df 100644
--- a/assignment-client/src/audio/AudioMixer.cpp
+++ b/assignment-client/src/audio/AudioMixer.cpp
@@ -182,15 +182,13 @@ void AudioMixer::addBufferToMixForListeningNodeWithBuffer(PositionalAudioRingBuf
 }
 
 void AudioMixer::prepareMixForListeningNode(Node* node) {
-	NodeList* nodeList = NodeList::getInstance();
-
     AvatarAudioRingBuffer* nodeRingBuffer = ((AudioMixerClientData*) node->getLinkedData())->getAvatarAudioRingBuffer();
 
     // zero out the client mix for this node
     memset(_clientSamples, 0, sizeof(_clientSamples));
 
     // loop through all other nodes that have sufficient audio to mix
-    for (NodeList::iterator otherNode = nodeList->begin(); otherNode != nodeList->end(); otherNode++) {
+    foreach (const SharedNodePointer& otherNode, NodeList::getInstance()->getNodeHash()) {
         if (otherNode->getLinkedData()) {
 
             AudioMixerClientData* otherNodeClientData = (AudioMixerClientData*) otherNode->getLinkedData();
@@ -200,7 +198,7 @@ void AudioMixer::prepareMixForListeningNode(Node* node) {
                 PositionalAudioRingBuffer* otherNodeBuffer = otherNodeClientData->getRingBuffers()[i];
 
                 if ((*otherNode != *node
-                    || otherNodeBuffer->shouldLoopbackForNode())
+                     || otherNodeBuffer->shouldLoopbackForNode())
                     && otherNodeBuffer->willBeAddedToMix()) {
                     addBufferToMixForListeningNodeWithBuffer(otherNodeBuffer, nodeRingBuffer);
                 }
@@ -219,12 +217,12 @@ void AudioMixer::processDatagram(const QByteArray& dataByteArray, const HifiSock
                                                               NUM_BYTES_RFC4122_UUID));
 
         NodeList* nodeList = NodeList::getInstance();
-
-        Node* matchingNode = nodeList->nodeWithUUID(nodeUUID);
-
+        
+        SharedNodePointer matchingNode = nodeList->nodeWithUUID(nodeUUID);
+        
         if (matchingNode) {
-            nodeList->updateNodeWithData(matchingNode, senderSockAddr, (unsigned char*) dataByteArray.data(), dataByteArray.size());
-
+            nodeList->updateNodeWithData(matchingNode.data(), senderSockAddr, (unsigned char*) dataByteArray.data(), dataByteArray.size());
+            
             if (!matchingNode->getActiveSocket()) {
                 // we don't have an active socket for this node, but they're talking to us
                 // this means they've heard from us and can reply, let's assume public is active
@@ -268,18 +266,18 @@ void AudioMixer::run() {
         if (_isFinished) {
             break;
         }
-
-        for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
+        
+        foreach (const SharedNodePointer& node, nodeList->getNodeHash()) {
             if (node->getLinkedData()) {
                 ((AudioMixerClientData*) node->getLinkedData())->checkBuffersBeforeFrameSend(JITTER_BUFFER_SAMPLES);
             }
         }
 
-        for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
+        foreach (const SharedNodePointer& node, nodeList->getNodeHash()) {
             if (node->getType() == NODE_TYPE_AGENT && node->getActiveSocket() && node->getLinkedData()
                 && ((AudioMixerClientData*) node->getLinkedData())->getAvatarAudioRingBuffer()) {
-                prepareMixForListeningNode(&(*node));
-
+                prepareMixForListeningNode(node.data());
+                
                 memcpy(clientPacket + numBytesPacketHeader, _clientSamples, sizeof(_clientSamples));
                 nodeList->getNodeSocket().writeDatagram((char*) clientPacket, sizeof(clientPacket),
                                                         node->getActiveSocket()->getAddress(),
@@ -288,7 +286,7 @@ void AudioMixer::run() {
         }
 
         // push forward the next output pointers for any audio buffers we used
-        for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
+        foreach (const SharedNodePointer& node, nodeList->getNodeHash()) {
             if (node->getLinkedData()) {
                 ((AudioMixerClientData*) node->getLinkedData())->pushBuffersAfterFrameSend();
             }
@@ -299,7 +297,7 @@ void AudioMixer::run() {
         if (usecToSleep > 0) {
             usleep(usecToSleep);
         } else {
-            qDebug("Took too much time, not sleeping!\n");
+            qDebug() << "AudioMixer loop took" << -usecToSleep << "of extra time. Not sleeping.";
         }
 
     }
diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp
index f6096fd18a..9c6d2f4714 100644
--- a/assignment-client/src/avatars/AvatarMixer.cpp
+++ b/assignment-client/src/avatars/AvatarMixer.cpp
@@ -67,7 +67,7 @@ void broadcastAvatarData() {
     
     NodeList* nodeList = NodeList::getInstance();
     
-    for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
+    foreach (const SharedNodePointer& node, nodeList->getNodeHash()) {
         if (node->getLinkedData() && node->getType() == NODE_TYPE_AGENT && node->getActiveSocket()) {
             
             // reset packet pointers for this node
@@ -76,11 +76,11 @@ void broadcastAvatarData() {
             
             // this is an AGENT we have received head data from
             // send back a packet with other active node data to this node
-            for (NodeList::iterator otherNode = nodeList->begin(); otherNode != nodeList->end(); otherNode++) {
+            foreach (const SharedNodePointer& otherNode, nodeList->getNodeHash()) {
                 if (otherNode->getLinkedData() && otherNode->getUUID() != node->getUUID()) {
                     
                     unsigned char* avatarDataEndpoint = addNodeToBroadcastPacket((unsigned char*)&avatarDataBuffer[0],
-                                                                                 &*otherNode);
+                                                                                 otherNode.data());
                     int avatarDataLength = avatarDataEndpoint - (unsigned char*)&avatarDataBuffer;
                     
                     if (avatarDataLength + packetLength <= MAX_PACKET_SIZE) {
@@ -109,13 +109,11 @@ void broadcastAvatarData() {
             
             packetsSent++;
             //printf("packetsSent=%d packetLength=%d\n", packetsSent, packetLength);
-            NodeList::getInstance()->getNodeSocket().writeDatagram((char*) broadcastPacket, currentBufferPosition - broadcastPacket,
-                                                                   node->getActiveSocket()->getAddress(),
-                                                                   node->getActiveSocket()->getPort());
+            nodeList->getNodeSocket().writeDatagram((char*) broadcastPacket, currentBufferPosition - broadcastPacket,
+                                                    node->getActiveSocket()->getAddress(),
+                                                    node->getActiveSocket()->getPort());
         }
     }
-    
-    
 }
 
 void AvatarMixer::processDatagram(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr) {
@@ -128,11 +126,11 @@ void AvatarMixer::processDatagram(const QByteArray& dataByteArray, const HifiSoc
                                                                   NUM_BYTES_RFC4122_UUID));
             
             // add or update the node in our list
-            Node* avatarNode = nodeList->nodeWithUUID(nodeUUID);
+            SharedNodePointer avatarNode = nodeList->nodeWithUUID(nodeUUID);
             
             if (avatarNode) {
                 // parse positional data from an node
-                nodeList->updateNodeWithData(avatarNode, senderSockAddr,
+                nodeList->updateNodeWithData(avatarNode.data(), senderSockAddr,
                                              (unsigned char*) dataByteArray.data(), dataByteArray.size());
             } else {
                 break;
@@ -144,7 +142,7 @@ void AvatarMixer::processDatagram(const QByteArray& dataByteArray, const HifiSoc
             QUuid nodeUUID = QUuid::fromRfc4122(dataByteArray.mid(numBytesForPacketHeader((unsigned char*) dataByteArray.data()),
                                                                   NUM_BYTES_RFC4122_UUID));
             // let everyone else know about the update
-            for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
+            foreach (const SharedNodePointer& node, nodeList->getNodeHash()) {
                 if (node->getActiveSocket() && node->getUUID() != nodeUUID) {
                     nodeList->getNodeSocket().writeDatagram(dataByteArray,
                                                             node->getActiveSocket()->getAddress(),
@@ -189,7 +187,7 @@ void AvatarMixer::run() {
         if (usecToSleep > 0) {
             usleep(usecToSleep);
         } else {
-            qDebug() << "Took too much time, not sleeping!\n";
+            qDebug() << "AvatarMixer loop took too" << -usecToSleep << "of extra time. Won't sleep.";
         }
     }
 }
diff --git a/assignment-client/src/metavoxels/MetavoxelServer.cpp b/assignment-client/src/metavoxels/MetavoxelServer.cpp
index fc586599ce..bb3787137d 100644
--- a/assignment-client/src/metavoxels/MetavoxelServer.cpp
+++ b/assignment-client/src/metavoxels/MetavoxelServer.cpp
@@ -29,8 +29,10 @@ void MetavoxelServer::removeSession(const QUuid& sessionId) {
     delete _sessions.take(sessionId);
 }
 
+const char METAVOXEL_SERVER_LOGGING_NAME[] = "avatar-mixer";
+
 void MetavoxelServer::run() {
-    commonInit("metavoxel-server", NODE_TYPE_METAVOXEL_SERVER);
+    commonInit(METAVOXEL_SERVER_LOGGING_NAME, NODE_TYPE_METAVOXEL_SERVER);
     
     _lastSend = QDateTime::currentMSecsSinceEpoch();
     _sendTimer.start(SEND_INTERVAL);
@@ -121,7 +123,7 @@ void MetavoxelSession::sendDelta() {
 }
 
 void MetavoxelSession::timedOut() {
-    qDebug() << "Session timed out [sessionId=" << _sessionId << ", sender=" << _sender << "]\n";
+    qDebug() << "Session timed out [sessionId=" << _sessionId << ", sender=" << _sender << "]";
     _server->removeSession(_sessionId);
 }
 
diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp
index 82e8e5c37d..9997d6e7ef 100644
--- a/domain-server/src/DomainServer.cpp
+++ b/domain-server/src/DomainServer.cpp
@@ -76,9 +76,9 @@ DomainServer::DomainServer(int argc, char* argv[]) :
 
     // Start the web server.
     mg_start(&callbacks, NULL, options);
-
-    nodeList->addHook(this);
-
+    
+    connect(nodeList, SIGNAL(nodeKilled(SharedNodePointer)), this, SLOT(nodeKilled(SharedNodePointer)));
+    
     if (!_staticAssignmentFile.exists() || _voxelServerConfig) {
 
         if (_voxelServerConfig) {
@@ -173,11 +173,11 @@ void DomainServer::readAvailableDatagrams() {
                                                               nodeLocalAddress,
                                                               nodeUUID)))
                 {
-                    Node* checkInNode = nodeList->addOrUpdateNode(nodeUUID,
-                                                                  nodeType,
-                                                                  nodePublicAddress,
-                                                                  nodeLocalAddress);
-
+                    SharedNodePointer checkInNode = nodeList->addOrUpdateNode(nodeUUID,
+                                                                              nodeType,
+                                                                              nodePublicAddress,
+                                                                              nodeLocalAddress);
+                    
                     if (matchingStaticAssignment) {
                         // this was a newly added node with a matching static assignment
 
@@ -203,13 +203,13 @@ void DomainServer::readAvailableDatagrams() {
 
                     if (numInterestTypes > 0) {
                         // if the node has sent no types of interest, assume they want nothing but their own ID back
-                        for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
+                        foreach (const SharedNodePointer& node, nodeList->getNodeHash()) {
                             if (node->getUUID() != nodeUUID &&
                                 memchr(nodeTypesOfInterest, node->getType(), numInterestTypes)) {
 
                                 // don't send avatar nodes to other avatars, that will come from avatar mixer
                                 if (nodeType != NODE_TYPE_AGENT || node->getType() != NODE_TYPE_AGENT) {
-                                    currentBufferPos = addNodeToBroadcastPacket(currentBufferPos, &(*node));
+                                    currentBufferPos = addNodeToBroadcastPacket(currentBufferPos, node.data());
                                 }
 
                             }
@@ -230,9 +230,10 @@ void DomainServer::readAvailableDatagrams() {
                 if (_assignmentQueue.size() > 0) {
                     // construct the requested assignment from the packet data
                     Assignment requestAssignment(packetData, receivedBytes);
-
-                    qDebug("Received a request for assignment type %i from %s.\n", requestAssignment.getType(), qPrintable(senderSockAddr.getAddress().toString()));
-
+                    
+                    qDebug("Received a request for assignment type %i from %s.",
+                           requestAssignment.getType(), qPrintable(senderSockAddr.getAddress().toString()));
+                    
                     Assignment* assignmentToDeploy = deployableAssignmentForRequest(requestAssignment);
 
                     if (assignmentToDeploy) {
@@ -251,7 +252,7 @@ void DomainServer::readAvailableDatagrams() {
                     }
 
                 } else {
-                    qDebug("Received an invalid assignment request from %s.\n", qPrintable(senderSockAddr.getAddress().toString()));
+                    qDebug() << "Received an invalid assignment request from" << senderSockAddr.getAddress();
                 }
             }
         }
@@ -320,13 +321,11 @@ int DomainServer::civetwebRequestHandler(struct mg_connection *connection) {
             QJsonObject assignedNodesJSON;
 
             // enumerate the NodeList to find the assigned nodes
-            NodeList* nodeList = NodeList::getInstance();
-
-            for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
+            foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
                 if (node->getLinkedData()) {
                     // add the node using the UUID as the key
                     QString uuidString = uuidStringWithoutCurlyBraces(node->getUUID());
-                    assignedNodesJSON[uuidString] = jsonObjectForNode(&(*node));
+                    assignedNodesJSON[uuidString] = jsonObjectForNode(node.data());
                 }
             }
 
@@ -373,11 +372,11 @@ int DomainServer::civetwebRequestHandler(struct mg_connection *connection) {
 
             // enumerate the NodeList to find the assigned nodes
             NodeList* nodeList = NodeList::getInstance();
-
-            for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
+            
+            foreach (const SharedNodePointer& node, nodeList->getNodeHash()) {
                 // add the node using the UUID as the key
                 QString uuidString = uuidStringWithoutCurlyBraces(node->getUUID());
-                nodesJSON[uuidString] = jsonObjectForNode(&(*node));
+                nodesJSON[uuidString] = jsonObjectForNode(node.data());
             }
 
             rootJSON["nodes"] = nodesJSON;
@@ -412,15 +411,15 @@ int DomainServer::civetwebRequestHandler(struct mg_connection *connection) {
             QUuid deleteUUID = QUuid(QString(ri->uri + strlen(URI_NODE) + sizeof('/')));
 
             if (!deleteUUID.isNull()) {
-                Node *nodeToKill = NodeList::getInstance()->nodeWithUUID(deleteUUID);
-
+                SharedNodePointer nodeToKill = NodeList::getInstance()->nodeWithUUID(deleteUUID);
+                
                 if (nodeToKill) {
                     // start with a 200 response
                     mg_printf(connection, "%s", RESPONSE_200);
 
                     // we have a valid UUID and node - kill the node that has this assignment
-                    NodeList::getInstance()->killNode(nodeToKill);
-
+                    NodeList::getInstance()->killNodeWithUUID(deleteUUID);
+                    
                     // successfully processed request
                     return 1;
                 }
@@ -465,9 +464,9 @@ void DomainServer::civetwebUploadHandler(struct mg_connection *connection, const
 
     // rename the saved script to the GUID of the assignment and move it to the script host locaiton
     rename(path, newPath.toLocal8Bit().constData());
-
-    qDebug("Saved a script for assignment at %s\n", newPath.toLocal8Bit().constData());
-
+    
+    qDebug("Saved a script for assignment at %s", newPath.toLocal8Bit().constData());
+    
     // add the script assigment to the assignment queue
     // lock the assignment queue mutex since we're operating on a different thread than DS main
     domainServerInstance->_assignmentQueueMutex.lock();
@@ -476,8 +475,8 @@ void DomainServer::civetwebUploadHandler(struct mg_connection *connection, const
 }
 
 void DomainServer::addReleasedAssignmentBackToQueue(Assignment* releasedAssignment) {
-    qDebug() << "Adding assignment" << *releasedAssignment << " back to queue.\n";
-
+    qDebug() << "Adding assignment" << *releasedAssignment << " back to queue.";
+    
     // find this assignment in the static file
     for (int i = 0; i < MAX_STATIC_ASSIGNMENT_FILE_ASSIGNMENTS; i++) {
         if (_staticAssignments[i].getUUID() == releasedAssignment->getUUID()) {
@@ -496,11 +495,7 @@ void DomainServer::addReleasedAssignmentBackToQueue(Assignment* releasedAssignme
     }
 }
 
-void DomainServer::nodeAdded(Node* node) {
-
-}
-
-void DomainServer::nodeKilled(Node* node) {
+void DomainServer::nodeKilled(SharedNodePointer node) {
     // if this node has linked data it was from an assignment
     if (node->getLinkedData()) {
         Assignment* nodeAssignment =  (Assignment*) node->getLinkedData();
@@ -537,18 +532,18 @@ void DomainServer::prepopulateStaticAssignmentFile() {
 
     // Handle Domain/Voxel Server configuration command line arguments
     if (_voxelServerConfig) {
-        qDebug("Reading Voxel Server Configuration.\n");
-        qDebug() << "config: " << _voxelServerConfig << "\n";
-
+        qDebug("Reading Voxel Server Configuration.");
+        qDebug() << "config: " << _voxelServerConfig;
+        
         QString multiConfig((const char*) _voxelServerConfig);
         QStringList multiConfigList = multiConfig.split(";");
 
         // read each config to a payload for a VS assignment
         for (int i = 0; i < multiConfigList.size(); i++) {
             QString config = multiConfigList.at(i);
-
-            qDebug("config[%d]=%s\n", i, config.toLocal8Bit().constData());
-
+            
+            qDebug("config[%d]=%s", i, config.toLocal8Bit().constData());
+            
             // Now, parse the config to check for a pool
             const char ASSIGNMENT_CONFIG_POOL_OPTION[] = "--pool";
             QString assignmentPool;
@@ -560,7 +555,7 @@ void DomainServer::prepopulateStaticAssignmentFile() {
                 int spaceAfterPoolIndex = config.indexOf(' ', spaceBeforePoolIndex);
 
                 assignmentPool = config.mid(spaceBeforePoolIndex + 1, spaceAfterPoolIndex);
-                qDebug() << "The pool for this voxel-assignment is" << assignmentPool << "\n";
+                qDebug() << "The pool for this voxel-assignment is" << assignmentPool;
             }
 
             Assignment voxelServerAssignment(Assignment::CreateCommand,
@@ -579,18 +574,18 @@ void DomainServer::prepopulateStaticAssignmentFile() {
 
     // Handle Domain/Particle Server configuration command line arguments
     if (_particleServerConfig) {
-        qDebug("Reading Particle Server Configuration.\n");
-        qDebug() << "config: " << _particleServerConfig << "\n";
-
+        qDebug("Reading Particle Server Configuration.");
+        qDebug() << "config: " << _particleServerConfig;
+        
         QString multiConfig((const char*) _particleServerConfig);
         QStringList multiConfigList = multiConfig.split(";");
 
         // read each config to a payload for a VS assignment
         for (int i = 0; i < multiConfigList.size(); i++) {
             QString config = multiConfigList.at(i);
-
-            qDebug("config[%d]=%s\n", i, config.toLocal8Bit().constData());
-
+            
+            qDebug("config[%d]=%s", i, config.toLocal8Bit().constData());
+            
             // Now, parse the config to check for a pool
             const char ASSIGNMENT_CONFIG_POOL_OPTION[] = "--pool";
             QString assignmentPool;
@@ -602,7 +597,7 @@ void DomainServer::prepopulateStaticAssignmentFile() {
                 int spaceAfterPoolIndex = config.indexOf(' ', spaceBeforePoolIndex);
 
                 assignmentPool = config.mid(spaceBeforePoolIndex + 1, spaceAfterPoolIndex);
-                qDebug() << "The pool for this particle-assignment is" << assignmentPool << "\n";
+                qDebug() << "The pool for this particle-assignment is" << assignmentPool;
             }
 
             Assignment particleServerAssignment(Assignment::CreateCommand,
@@ -625,9 +620,9 @@ void DomainServer::prepopulateStaticAssignmentFile() {
     if (_metavoxelServerConfig) {
         metavoxelAssignment.setPayload((const unsigned char*)_metavoxelServerConfig, strlen(_metavoxelServerConfig));
     }
-
-    qDebug() << "Adding" << numFreshStaticAssignments << "static assignments to fresh file.\n";
-
+    
+    qDebug() << "Adding" << numFreshStaticAssignments << "static assignments to fresh file.";
+    
     _staticAssignmentFile.open(QIODevice::WriteOnly);
     _staticAssignmentFile.write((char*) &freshStaticAssignments, sizeof(freshStaticAssignments));
     _staticAssignmentFile.resize(MAX_STATIC_ASSIGNMENT_FILE_ASSIGNMENTS * sizeof(Assignment));
@@ -742,8 +737,8 @@ bool DomainServer::checkInWithUUIDMatchesExistingNode(const HifiSockAddr& nodePu
                                                       const HifiSockAddr& nodeLocalSocket,
                                                       const QUuid& checkInUUID) {
     NodeList* nodeList = NodeList::getInstance();
-
-    for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
+    
+    foreach (const SharedNodePointer& node, nodeList->getNodeHash()) {
         if (node->getLinkedData()
             && nodePublicSocket == node->getPublicSocket()
             && nodeLocalSocket == node->getLocalSocket()
@@ -775,7 +770,7 @@ void DomainServer::addStaticAssignmentsBackToQueueAfterRestart() {
         NodeList* nodeList = NodeList::getInstance();
 
         // enumerate the nodes and check if there is one with an attached assignment with matching UUID
-        for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
+        foreach (const SharedNodePointer& node, nodeList->getNodeHash()) {
             if (node->getLinkedData()) {
                 Assignment* linkedAssignment = (Assignment*) node->getLinkedData();
                 if (linkedAssignment->getUUID() == _staticAssignments[i].getUUID()) {
@@ -788,9 +783,9 @@ void DomainServer::addStaticAssignmentsBackToQueueAfterRestart() {
         if (!foundMatchingAssignment) {
             // this assignment has not been fulfilled - reset the UUID and add it to the assignment queue
             _staticAssignments[i].resetUUID();
-
-            qDebug() << "Adding static assignment to queue -" << _staticAssignments[i] << "\n";
-
+            
+            qDebug() << "Adding static assignment to queue -" << _staticAssignments[i];
+            
             _assignmentQueueMutex.lock();
             _assignmentQueue.push_back(&_staticAssignments[i]);
             _assignmentQueueMutex.unlock();
diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h
index 10cb58b786..40cebdfa3f 100644
--- a/domain-server/src/DomainServer.h
+++ b/domain-server/src/DomainServer.h
@@ -22,7 +22,7 @@
 
 const int MAX_STATIC_ASSIGNMENT_FILE_ASSIGNMENTS = 1000;
 
-class DomainServer : public QCoreApplication, public NodeListHook {
+class DomainServer : public QCoreApplication {
     Q_OBJECT
 public:
     DomainServer(int argc, char* argv[]);
@@ -31,10 +31,10 @@ public:
 
     static void setDomainServerInstance(DomainServer* domainServer);
     
-    /// Called by NodeList to inform us that a node has been added.
-    void nodeAdded(Node* node);
+public slots:
     /// Called by NodeList to inform us that a node has been killed.
-    void nodeKilled(Node* node);
+    void nodeKilled(SharedNodePointer node);
+    
 private:    
     static int civetwebRequestHandler(struct mg_connection *connection);
     static void civetwebUploadHandler(struct mg_connection *connection, const char *path);
diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index 9f80bf8714..c565c8e92d 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -92,15 +92,15 @@ const float MIRROR_REARVIEW_DISTANCE = 0.65f;
 const float MIRROR_REARVIEW_BODY_DISTANCE = 2.3f;
 
 void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString &message) {
-    fprintf(stdout, "%s", message.toLocal8Bit().constData());
-    Application::getInstance()->getLogger()->addMessage(message.toLocal8Bit().constData());
+    QString messageWithNewLine = message + "\n";
+    fprintf(stdout, "%s", messageWithNewLine.toLocal8Bit().constData());
+    Application::getInstance()->getLogger()->addMessage(messageWithNewLine.toLocal8Bit().constData());
 }
 
 Application::Application(int& argc, char** argv, timeval &startup_time) :
         QApplication(argc, argv),
         _window(new QMainWindow(desktop())),
         _glWidget(new GLCanvas()),
-        _displayLevels(false),
         _frameCount(0),
         _fps(120.0f),
         _justStarted(true),
@@ -133,7 +133,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
         _lookatIndicatorScale(1.0f),
         _chatEntryOn(false),
         _audio(&_audioScope, STARTUP_JITTER_SAMPLES),
-        _stopNetworkReceiveThread(false),
+        _enableProcessVoxelsThread(true),
         _voxelProcessor(),
         _voxelHideShowThread(&_voxels),
         _voxelEditSender(this),
@@ -160,7 +160,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
     // call Menu getInstance static method to set up the menu
     _window->setMenuBar(Menu::getInstance());
 
-    qDebug("[VERSION] Build sequence: %i\n", BUILD_VERSION);
+    qDebug("[VERSION] Build sequence: %i", BUILD_VERSION);
 
     unsigned int listenPort = 0; // bind to an ephemeral port by default
     const char** constArgv = const_cast<const char**>(argv);
@@ -170,6 +170,9 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
     }
 
     NodeList* nodeList = NodeList::createInstance(NODE_TYPE_AGENT, listenPort);
+    
+    // connect our processDatagrams slot to the QUDPSocket readyRead() signal
+    connect(&nodeList->getNodeSocket(), SIGNAL(readyRead()), SLOT(processDatagrams()));
 
     // put the audio processing on a separate thread
     QThread* audioThread = new QThread(this);
@@ -178,13 +181,12 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
     connect(audioThread, SIGNAL(started()), &_audio, SLOT(start()));
 
     audioThread->start();
+    
+    connect(nodeList, SIGNAL(domainChanged(const QString&)), SLOT(domainChanged(const QString&)));
 
-    nodeList->addHook(&_voxels);
-    nodeList->addHook(this);
-    nodeList->addDomainListener(this);
-
-    // network receive thread and voxel parsing thread are both controlled by the --nonblocking command line
-    _enableProcessVoxelsThread = _enableNetworkThread = !cmdOptionExists(argc, constArgv, "--nonblocking");
+    connect(nodeList, SIGNAL(nodeKilled(SharedNodePointer)), SLOT(nodeKilled(SharedNodePointer)));
+    connect(nodeList, SIGNAL(nodeAdded(SharedNodePointer)), &_voxels, SLOT(nodeAdded(SharedNodePointer)));
+    connect(nodeList, SIGNAL(nodeKilled(SharedNodePointer)), &_voxels, SLOT(nodeKilled(SharedNodePointer)));
 
     // read the ApplicationInfo.ini file for Name/Version/Domain information
     QSettings applicationInfo("resources/info/ApplicationInfo.ini", QSettings::IniFormat);
@@ -268,9 +270,6 @@ Application::~Application() {
     _audio.thread()->wait();
 
     storeSizeAndPosition();
-    NodeList::getInstance()->removeHook(&_voxels);
-    NodeList::getInstance()->removeHook(this);
-    NodeList::getInstance()->removeDomainListener(this);
 
     _sharedVoxelSystem.changeTree(new VoxelTree);
 
@@ -279,7 +278,6 @@ Application::~Application() {
 
     delete _logger;
     delete _settings;
-    delete _followMode;
     delete _glWidget;
 }
 
@@ -315,7 +313,7 @@ void Application::storeSizeAndPosition() {
 }
 
 void Application::initializeGL() {
-    qDebug( "Created Display Window.\n" );
+    qDebug( "Created Display Window.");
 
     // initialize glut for shape drawing; Qt apparently initializes it on OS X
     #ifndef __APPLE__
@@ -330,16 +328,10 @@ void Application::initializeGL() {
     _viewFrustumOffsetCamera.setFarClip(500.0f * TREE_SCALE);
 
     initDisplay();
-    qDebug( "Initialized Display.\n" );
+    qDebug( "Initialized Display.");
 
     init();
-    qDebug( "Init() complete.\n" );
-
-    // create thread for receipt of data via UDP
-    if (_enableNetworkThread) {
-        pthread_create(&_networkReceiveThread, NULL, networkReceive, NULL);
-        qDebug("Network receive thread created.\n");
-    }
+    qDebug( "init() complete.");
 
     // create thread for parsing of voxel data independent of the main network and rendering threads
     _voxelProcessor.initialize(_enableProcessVoxelsThread);
@@ -347,7 +339,7 @@ void Application::initializeGL() {
     _voxelHideShowThread.initialize(_enableProcessVoxelsThread);
     _particleEditSender.initialize(_enableProcessVoxelsThread);
     if (_enableProcessVoxelsThread) {
-        qDebug("Voxel parsing thread created.\n");
+        qDebug("Voxel parsing thread created.");
     }
 
     // call terminate before exiting
@@ -367,9 +359,7 @@ void Application::initializeGL() {
     if (_justStarted) {
         float startupTime = (usecTimestampNow() - usecTimestamp(&_applicationStartupTime)) / 1000000.0;
         _justStarted = false;
-        char title[50];
-        sprintf(title, "Interface: %4.2f seconds\n", startupTime);
-        qDebug("%s", title);
+        qDebug("Startup time: %4.2f seconds.", startupTime);
         const char LOGSTASH_INTERFACE_START_TIME_KEY[] = "interface-start-time";
 
         // ask the Logstash class to record the startup time
@@ -676,9 +666,7 @@ void Application::keyPressEvent(QKeyEvent* event) {
                 _audioScope.inputPaused = !_audioScope.inputPaused;
                 break;
             case Qt::Key_L:
-                if (!isShifted && !isMeta) {
-                    _displayLevels = !_displayLevels;
-                } else if (isShifted) {
+                if (isShifted) {
                     Menu::getInstance()->triggerOption(MenuOption::LodTools);
                 } else if (isMeta) {
                     Menu::getInstance()->triggerOption(MenuOption::Log);
@@ -1344,11 +1332,6 @@ void Application::timer() {
 
     gettimeofday(&_timerStart, NULL);
 
-    // if we haven't detected gyros, check for them now
-    if (!_serialHeadSensor.isActive()) {
-        _serialHeadSensor.pair();
-    }
-
     // ask the node list to check in with the domain server
     NodeList::getInstance()->sendDomainServerCheckIn();
 
@@ -1431,11 +1414,6 @@ void Application::terminate() {
     // let the avatar mixer know we're out
     NodeList::getInstance()->sendKillNode(&NODE_TYPE_AVATAR_MIXER, 1);
 
-    if (_enableNetworkThread) {
-        _stopNetworkReceiveThread = true;
-        pthread_join(_networkReceiveThread, NULL);
-    }
-
     printf("");
     _voxelProcessor.terminate();
     _voxelHideShowThread.terminate();
@@ -1448,7 +1426,7 @@ void Application::terminate() {
 static Avatar* processAvatarMessageHeader(unsigned char*& packetData, size_t& dataBytes) {
     // record the packet for stats-tracking
     Application::getInstance()->getBandwidthMeter()->inputStream(BandwidthMeter::AVATARS).updateValue(dataBytes);
-    Node* avatarMixerNode = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_AVATAR_MIXER);
+    SharedNodePointer avatarMixerNode = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_AVATAR_MIXER);
     if (avatarMixerNode) {
         avatarMixerNode->recordBytesReceived(dataBytes);
     }
@@ -1465,7 +1443,7 @@ static Avatar* processAvatarMessageHeader(unsigned char*& packetData, size_t& da
     dataBytes -= NUM_BYTES_RFC4122_UUID;
 
     // make sure the node exists
-    Node* node = NodeList::getInstance()->nodeWithUUID(nodeUUID);
+    SharedNodePointer node = NodeList::getInstance()->nodeWithUUID(nodeUUID);
     if (!node || !node->getLinkedData()) {
         return NULL;
     }
@@ -1713,9 +1691,9 @@ void Application::exportVoxels() {
 
 void Application::importVoxels() {
     if (_voxelImporter.exec()) {
-        qDebug("[DEBUG] Import succedded.\n");
+        qDebug("[DEBUG] Import succeeded.");
     } else {
-        qDebug("[DEBUG] Import failed.\n");
+        qDebug("[DEBUG] Import failed.");
     }
 
     // restore the main window's active state
@@ -1896,7 +1874,7 @@ void Application::init() {
     if (Menu::getInstance()->getAudioJitterBufferSamples() != 0) {
         _audio.setJitterBufferSamples(Menu::getInstance()->getAudioJitterBufferSamples());
     }
-    qDebug("Loaded settings.\n");
+    qDebug("Loaded settings");
 
     if (!_profile.getUsername().isEmpty()) {
         // we have a username for this avatar, ask the data-server for the mesh URL for this avatar
@@ -1930,10 +1908,6 @@ void Application::init() {
                   _glWidget->width(),
                   _glWidget->height());
 
-    _followMode = new QAction(this);
-    connect(_followMode, SIGNAL(triggered()), this, SLOT(toggleFollowMode()));
-    _pieMenu.addAction(_followMode);
-
     _audio.init(_glWidget);
 
     _rearMirrorTools = new RearMirrorTools(_glWidget, _mirrorViewRect, _settings);
@@ -1991,16 +1965,16 @@ void Application::updateLookatTargetAvatar(const glm::vec3& mouseRayOrigin, cons
 Avatar* Application::findLookatTargetAvatar(const glm::vec3& mouseRayOrigin, const glm::vec3& mouseRayDirection,
     glm::vec3& eyePosition, QUuid& nodeUUID = DEFAULT_NODE_ID_REF) {
 
-    NodeList* nodeList = NodeList::getInstance();
-    for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
+    foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
         if (node->getLinkedData() != NULL && node->getType() == NODE_TYPE_AGENT) {
             Avatar* avatar = (Avatar*)node->getLinkedData();
             float distance;
+            
             if (avatar->findRayIntersection(mouseRayOrigin, mouseRayDirection, distance)) {
                 // rescale to compensate for head embiggening
                 eyePosition = (avatar->getHead().calculateAverageEyePosition() - avatar->getHead().getScalePivot()) *
-                    (avatar->getScale() / avatar->getHead().getScale()) + avatar->getHead().getScalePivot();
-
+                (avatar->getScale() / avatar->getHead().getScale()) + avatar->getHead().getScalePivot();
+                
                 _lookatIndicatorScale = avatar->getHead().getScale();
                 _lookatOtherPosition = avatar->getHead().getPosition();
                 nodeUUID = avatar->getOwningNode()->getUUID();
@@ -2008,6 +1982,7 @@ Avatar* Application::findLookatTargetAvatar(const glm::vec3& mouseRayOrigin, con
             }
         }
     }
+    
     return NULL;
 }
 
@@ -2032,71 +2007,6 @@ void Application::renderLookatIndicator(glm::vec3 pointOfInterest) {
     renderCircle(haloOrigin, INDICATOR_RADIUS, IDENTITY_UP, NUM_SEGMENTS);
 }
 
-void maybeBeginFollowIndicator(bool& began) {
-    if (!began) {
-        Application::getInstance()->getGlowEffect()->begin();
-        glLineWidth(5);
-        glBegin(GL_LINES);
-        began = true;
-    }
-}
-
-void Application::renderFollowIndicator() {
-    NodeList* nodeList = NodeList::getInstance();
-
-    // initialize lazily so that we don't enable the glow effect unnecessarily
-    bool began = false;
-
-    for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); ++node) {
-        if (node->getLinkedData() != NULL && node->getType() == NODE_TYPE_AGENT) {
-            Avatar* avatar = (Avatar *) node->getLinkedData();
-            Avatar* leader = NULL;
-
-            if (!avatar->getLeaderUUID().isNull()) {
-                if (avatar->getLeaderUUID() == NodeList::getInstance()->getOwnerUUID()) {
-                    leader = &_myAvatar;
-                } else {
-                    for (NodeList::iterator it = nodeList->begin(); it != nodeList->end(); ++it) {
-                        if(it->getUUID() == avatar->getLeaderUUID()
-                                && it->getType() == NODE_TYPE_AGENT) {
-                            leader = (Avatar*) it->getLinkedData();
-                        }
-                    }
-                }
-
-                if (leader != NULL) {
-                    maybeBeginFollowIndicator(began);
-                    glColor3f(1.f, 0.f, 0.f);
-                    glVertex3f((avatar->getHead().getPosition().x + avatar->getPosition().x) / 2.f,
-                               (avatar->getHead().getPosition().y + avatar->getPosition().y) / 2.f,
-                               (avatar->getHead().getPosition().z + avatar->getPosition().z) / 2.f);
-                    glColor3f(0.f, 1.f, 0.f);
-                    glVertex3f((leader->getHead().getPosition().x + leader->getPosition().x) / 2.f,
-                               (leader->getHead().getPosition().y + leader->getPosition().y) / 2.f,
-                               (leader->getHead().getPosition().z + leader->getPosition().z) / 2.f);
-                }
-            }
-        }
-    }
-
-    if (_myAvatar.getLeadingAvatar() != NULL) {
-        maybeBeginFollowIndicator(began);
-        glColor3f(1.f, 0.f, 0.f);
-        glVertex3f((_myAvatar.getHead().getPosition().x + _myAvatar.getPosition().x) / 2.f,
-                   (_myAvatar.getHead().getPosition().y + _myAvatar.getPosition().y) / 2.f,
-                   (_myAvatar.getHead().getPosition().z + _myAvatar.getPosition().z) / 2.f);
-        glColor3f(0.f, 1.f, 0.f);
-        glVertex3f((_myAvatar.getLeadingAvatar()->getHead().getPosition().x + _myAvatar.getLeadingAvatar()->getPosition().x) / 2.f,
-                   (_myAvatar.getLeadingAvatar()->getHead().getPosition().y + _myAvatar.getLeadingAvatar()->getPosition().y) / 2.f,
-                   (_myAvatar.getLeadingAvatar()->getHead().getPosition().z + _myAvatar.getLeadingAvatar()->getPosition().z) / 2.f);
-    }
-
-    if (began) {
-        glEnd();
-        _glowEffect.end();
-    }
-}
-
 void Application::renderHighlightVoxel(VoxelDetail voxel) {
     glDisable(GL_LIGHTING);
     glPushMatrix();
@@ -2114,10 +2024,9 @@ void Application::renderHighlightVoxel(VoxelDetail voxel) {
 void Application::updateAvatars(float deltaTime, glm::vec3 mouseRayOrigin, glm::vec3 mouseRayDirection) {
     bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
     PerformanceWarning warn(showWarnings, "Application::updateAvatars()");
-    NodeList* nodeList = NodeList::getInstance();
-
-    for(NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
-        node->lock();
+    
+    foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
+        QMutexLocker(&node->getMutex());
         if (node->getLinkedData()) {
             Avatar *avatar = (Avatar *)node->getLinkedData();
             if (!avatar->isInitialized()) {
@@ -2126,7 +2035,6 @@ void Application::updateAvatars(float deltaTime, glm::vec3 mouseRayOrigin, glm::
             avatar->simulate(deltaTime, NULL);
             avatar->setMouseRay(mouseRayOrigin, mouseRayDirection);
         }
-        node->unlock();
     }
 
     // simulate avatar fades
@@ -2386,21 +2294,12 @@ void Application::updateSixense(float deltaTime) {
 void Application::updateSerialDevices(float deltaTime) {
     bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
     PerformanceWarning warn(showWarnings, "Application::updateSerialDevices()");
-
-    if (_serialHeadSensor.isActive()) {
-        _serialHeadSensor.readData(deltaTime);
-    }
 }
 
 void Application::updateThreads(float deltaTime) {
     bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
     PerformanceWarning warn(showWarnings, "Application::updateThreads()");
 
-    // read incoming packets from network
-    if (!_enableNetworkThread) {
-        networkReceive(0);
-    }
-
     // parse voxel packets
     if (!_enableProcessVoxelsThread) {
         _voxelProcessor.threadRoutine();
@@ -2633,41 +2532,6 @@ void Application::updateAvatar(float deltaTime) {
         _headMouseY -= headVelocity.x * HEADMOUSE_FACESHIFT_PITCH_SCALE;
     }
 
-    if (_serialHeadSensor.isActive()) {
-
-        //  Grab latest readings from the gyros
-        float measuredPitchRate = _serialHeadSensor.getLastPitchRate();
-        float measuredYawRate = _serialHeadSensor.getLastYawRate();
-
-        //  Update gyro-based mouse (X,Y on screen)
-        const float MIN_MOUSE_RATE = 3.0;
-        const float HORIZONTAL_PIXELS_PER_DEGREE = 2880.f / 45.f;
-        const float VERTICAL_PIXELS_PER_DEGREE = 1800.f / 30.f;
-        if (powf(measuredYawRate * measuredYawRate +
-                 measuredPitchRate * measuredPitchRate, 0.5) > MIN_MOUSE_RATE) {
-            _headMouseX -= measuredYawRate * HORIZONTAL_PIXELS_PER_DEGREE * deltaTime;
-            _headMouseY -= measuredPitchRate * VERTICAL_PIXELS_PER_DEGREE * deltaTime;
-        }
-
-        const float MIDPOINT_OF_SCREEN = 0.5;
-
-        // Only use gyro to set lookAt if mouse hasn't selected an avatar
-        if (!_lookatTargetAvatar) {
-
-            // Set lookAtPosition if an avatar is at the center of the screen
-            glm::vec3 screenCenterRayOrigin, screenCenterRayDirection;
-            _viewFrustum.computePickRay(MIDPOINT_OF_SCREEN, MIDPOINT_OF_SCREEN, screenCenterRayOrigin, screenCenterRayDirection);
-
-            glm::vec3 eyePosition;
-            updateLookatTargetAvatar(screenCenterRayOrigin, screenCenterRayDirection, eyePosition);
-            if (_lookatTargetAvatar) {
-                glm::vec3 myLookAtFromMouse(eyePosition);
-                _myAvatar.getHead().setLookAtPosition(myLookAtFromMouse);
-            }
-        }
-
-    }
-
     //  Constrain head-driven mouse to edges of screen
     _headMouseX = glm::clamp(_headMouseX, 0, _glWidget->width());
     _headMouseY = glm::clamp(_headMouseY, 0, _glWidget->height());
@@ -2748,39 +2612,36 @@ void Application::queryOctree(NODE_TYPE serverType, PACKET_TYPE packetType, Node
 
     unsigned char voxelQueryPacket[MAX_PACKET_SIZE];
 
-    NodeList* nodeList = NodeList::getInstance();
-
     // Iterate all of the nodes, and get a count of how many voxel servers we have...
     int totalServers = 0;
     int inViewServers = 0;
     int unknownJurisdictionServers = 0;
-
-    for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
-
+    
+    foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
         // only send to the NodeTypes that are serverType
         if (node->getActiveSocket() != NULL && node->getType() == serverType) {
             totalServers++;
-
+            
             // get the server bounds for this server
             QUuid nodeUUID = node->getUUID();
-
+            
             // if we haven't heard from this voxel server, go ahead and send it a query, so we
             // can get the jurisdiction...
             if (jurisdictions.find(nodeUUID) == jurisdictions.end()) {
                 unknownJurisdictionServers++;
             } else {
                 const JurisdictionMap& map = (jurisdictions)[nodeUUID];
-
+                
                 unsigned char* rootCode = map.getRootOctalCode();
-
+                
                 if (rootCode) {
                     VoxelPositionSize rootDetails;
                     voxelDetailsForCode(rootCode, rootDetails);
                     AABox serverBounds(glm::vec3(rootDetails.x, rootDetails.y, rootDetails.z), rootDetails.s);
                     serverBounds.scale(TREE_SCALE);
-
+                    
                     ViewFrustum::location serverFrustumLocation = _viewFrustum.boxInFrustum(serverBounds);
-
+                    
                     if (serverFrustumLocation != ViewFrustum::OUTSIDE) {
                         inViewServers++;
                     }
@@ -2790,7 +2651,7 @@ void Application::queryOctree(NODE_TYPE serverType, PACKET_TYPE packetType, Node
     }
 
     if (wantExtraDebugging && unknownJurisdictionServers > 0) {
-        qDebug("Servers: total %d, in view %d, unknown jurisdiction %d \n",
+        qDebug("Servers: total %d, in view %d, unknown jurisdiction %d",
             totalServers, inViewServers, unknownJurisdictionServers);
     }
 
@@ -2811,38 +2672,40 @@ void Application::queryOctree(NODE_TYPE serverType, PACKET_TYPE packetType, Node
     }
 
     if (wantExtraDebugging && unknownJurisdictionServers > 0) {
-        qDebug("perServerPPS: %d perUnknownServer: %d\n", perServerPPS, perUnknownServer);
+        qDebug("perServerPPS: %d perUnknownServer: %d", perServerPPS, perUnknownServer);
     }
-
-    for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
+    
+    NodeList* nodeList = NodeList::getInstance();
+    
+    foreach (const SharedNodePointer& node, nodeList->getNodeHash()) {
         // only send to the NodeTypes that are serverType
         if (node->getActiveSocket() != NULL && node->getType() == serverType) {
-
-
+            
+            
             // get the server bounds for this server
             QUuid nodeUUID = node->getUUID();
-
+            
             bool inView = false;
             bool unknownView = false;
-
+            
             // if we haven't heard from this voxel server, go ahead and send it a query, so we
             // can get the jurisdiction...
             if (jurisdictions.find(nodeUUID) == jurisdictions.end()) {
                 unknownView = true; // assume it's in view
                 if (wantExtraDebugging) {
-                    qDebug() << "no known jurisdiction for node " << *node << ", assume it's visible.\n";
+                    qDebug() << "no known jurisdiction for node " << *node << ", assume it's visible.";
                 }
             } else {
                 const JurisdictionMap& map = (jurisdictions)[nodeUUID];
-
+                
                 unsigned char* rootCode = map.getRootOctalCode();
-
+                
                 if (rootCode) {
                     VoxelPositionSize rootDetails;
                     voxelDetailsForCode(rootCode, rootDetails);
                     AABox serverBounds(glm::vec3(rootDetails.x, rootDetails.y, rootDetails.z), rootDetails.s);
                     serverBounds.scale(TREE_SCALE);
-
+                    
                     ViewFrustum::location serverFrustumLocation = _viewFrustum.boxInFrustum(serverBounds);
                     if (serverFrustumLocation != ViewFrustum::OUTSIDE) {
                         inView = true;
@@ -2851,19 +2714,19 @@ void Application::queryOctree(NODE_TYPE serverType, PACKET_TYPE packetType, Node
                     }
                 } else {
                     if (wantExtraDebugging) {
-                        qDebug() << "Jurisdiction without RootCode for node " << *node << ". That's unusual!\n";
+                        qDebug() << "Jurisdiction without RootCode for node " << *node << ". That's unusual!";
                     }
                 }
             }
-
+            
             if (inView) {
                 _voxelQuery.setMaxOctreePacketsPerSecond(perServerPPS);
             } else if (unknownView) {
                 if (wantExtraDebugging) {
                     qDebug() << "no known jurisdiction for node " << *node << ", give it budget of "
-                            << perUnknownServer << " to send us jurisdiction.\n";
+                            << perUnknownServer << " to send us jurisdiction.";
                 }
-
+                
                 // set the query's position/orientation to be degenerate in a manner that will get the scene quickly
                 // If there's only one server, then don't do this, and just let the normal voxel query pass through
                 // as expected... this way, we will actually get a valid scene if there is one to be seen
@@ -2874,11 +2737,11 @@ void Application::queryOctree(NODE_TYPE serverType, PACKET_TYPE packetType, Node
                     _voxelQuery.setCameraNearClip(0.1f);
                     _voxelQuery.setCameraFarClip(0.1f);
                     if (wantExtraDebugging) {
-                        qDebug() << "Using 'minimal' camera position for node " << *node << "\n";
+                        qDebug() << "Using 'minimal' camera position for node" << *node;
                     }
                 } else {
                     if (wantExtraDebugging) {
-                        qDebug() << "Using regular camera position for node " << *node << "\n";
+                        qDebug() << "Using regular camera position for node" << *node;
                     }
                 }
                 _voxelQuery.setMaxOctreePacketsPerSecond(perUnknownServer);
@@ -2887,24 +2750,24 @@ void Application::queryOctree(NODE_TYPE serverType, PACKET_TYPE packetType, Node
             }
             // set up the packet for sending...
             unsigned char* endOfVoxelQueryPacket = voxelQueryPacket;
-
+            
             // insert packet type/version and node UUID
             endOfVoxelQueryPacket += populateTypeAndVersion(endOfVoxelQueryPacket, packetType);
             QByteArray ownerUUID = nodeList->getOwnerUUID().toRfc4122();
             memcpy(endOfVoxelQueryPacket, ownerUUID.constData(), ownerUUID.size());
             endOfVoxelQueryPacket += ownerUUID.size();
-
+            
             // encode the query data...
             endOfVoxelQueryPacket += _voxelQuery.getBroadcastData(endOfVoxelQueryPacket);
-
+            
             int packetLength = endOfVoxelQueryPacket - voxelQueryPacket;
-
+            
             // make sure we still have an active socket
             if (node->getActiveSocket()) {
                 nodeList->getNodeSocket().writeDatagram((char*) voxelQueryPacket, packetLength,
-                                                    node->getActiveSocket()->getAddress(), node->getActiveSocket()->getPort());
+                                                        node->getActiveSocket()->getAddress(), node->getActiveSocket()->getPort());
             }
-
+            
             // Feed number of bytes to corresponding channel of the bandwidth meter
             _bandwidthMeter.outputStream(BandwidthMeter::VOXELS).updateValue(packetLength);
         }
@@ -3261,12 +3124,6 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) {
             }
         }
 
-        {
-            PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
-                "Application::displaySide() ... renderFollowIndicator...");
-            renderFollowIndicator();
-        }
-
         // render transmitter pick ray, if non-empty
         if (_transmitterPickStart != _transmitterPickEnd) {
             PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
@@ -3334,8 +3191,7 @@ void Application::displayOverlay() {
 
        //noiseTest(_glWidget->width(), _glWidget->height());
 
-    if (Menu::getInstance()->isOptionChecked(MenuOption::HeadMouse)
-        && USING_INVENSENSE_MPU9150) {
+    if (Menu::getInstance()->isOptionChecked(MenuOption::HeadMouse)) {
         //  Display small target box at center or head mouse target that can also be used to measure LOD
         glColor3f(1.0, 1.0, 1.0);
         glDisable(GL_LINE_SMOOTH);
@@ -3371,9 +3227,6 @@ void Application::displayOverlay() {
         }
     }
 
-    //  Show detected levels from the serial I/O ADC channel sensors
-    if (_displayLevels) _serialHeadSensor.renderLevels(_glWidget->width(), _glWidget->height());
-
     //  Show hand transmitter data if detected
     if (_myTransmitter.isConnected()) {
         _myTransmitter.renderLevels(_glWidget->width(), _glWidget->height());
@@ -3393,12 +3246,12 @@ void Application::displayOverlay() {
         glPointSize(1.0f);
         char nodes[100];
 
-        NodeList* nodeList = NodeList::getInstance();
         int totalAvatars = 0, totalServers = 0;
-
-        for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
+        
+        foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
             node->getType() == NODE_TYPE_AGENT ? totalAvatars++ : totalServers++;
         }
+
         sprintf(nodes, "Servers: %d, Avatars: %d\n", totalServers, totalAvatars);
         drawtext(_glWidget->width() - 150, 20, 0.10f, 0, 1.0f, 0, nodes, 1, 0, 0);
     }
@@ -3499,8 +3352,8 @@ void Application::displayStats() {
         int pingAudio = 0, pingAvatar = 0, pingVoxel = 0, pingVoxelMax = 0;
 
         NodeList* nodeList = NodeList::getInstance();
-        Node* audioMixerNode = nodeList->soloNodeOfType(NODE_TYPE_AUDIO_MIXER);
-        Node* avatarMixerNode = nodeList->soloNodeOfType(NODE_TYPE_AVATAR_MIXER);
+        SharedNodePointer audioMixerNode = nodeList->soloNodeOfType(NODE_TYPE_AUDIO_MIXER);
+        SharedNodePointer avatarMixerNode = nodeList->soloNodeOfType(NODE_TYPE_AVATAR_MIXER);
 
         pingAudio = audioMixerNode ? audioMixerNode->getPingMs() : 0;
         pingAvatar = avatarMixerNode ? avatarMixerNode->getPingMs() : 0;
@@ -3509,7 +3362,8 @@ void Application::displayStats() {
         // Now handle voxel servers, since there could be more than one, we average their ping times
         unsigned long totalPingVoxel = 0;
         int voxelServerCount = 0;
-        for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
+        
+        foreach (const SharedNodePointer& node, nodeList->getNodeHash()) {
             if (node->getType() == NODE_TYPE_VOXEL_SERVER) {
                 totalPingVoxel += node->getPingMs();
                 voxelServerCount++;
@@ -3518,6 +3372,7 @@ void Application::displayStats() {
                 }
             }
         }
+        
         if (voxelServerCount) {
             pingVoxel = totalPingVoxel/voxelServerCount;
         }
@@ -3534,7 +3389,7 @@ void Application::displayStats() {
     sprintf(avatarStats, "Avatar: pos %.3f, %.3f, %.3f, vel %.1f, yaw = %.2f", avatarPos.x, avatarPos.y, avatarPos.z, glm::length(_myAvatar.getVelocity()), _myAvatar.getBodyYaw());
     drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, avatarStats);
 
-    Node* avatarMixer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_AVATAR_MIXER);
+    SharedNodePointer avatarMixer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_AVATAR_MIXER);
     char avatarMixerStats[200];
     if (avatarMixer) {
         sprintf(avatarMixerStats, "Avatar Mixer: %.f kbps, %.f pps",
@@ -3722,9 +3577,6 @@ glm::vec2 Application::getScaledScreenPoint(glm::vec2 projectedPoint) {
 
 // render the coverage map on screen
 void Application::renderCoverageMapV2() {
-
-    //qDebug("renderCoverageMap()\n");
-
     glDisable(GL_LIGHTING);
     glLineWidth(2.0);
     glBegin(GL_LINES);
@@ -3768,8 +3620,6 @@ void Application::renderCoverageMapsV2Recursively(CoverageMapV2* map) {
 // render the coverage map on screen
 void Application::renderCoverageMap() {
 
-    //qDebug("renderCoverageMap()\n");
-
     glDisable(GL_LIGHTING);
     glLineWidth(2.0);
     glBegin(GL_LINES);
@@ -3844,10 +3694,10 @@ void Application::renderAvatars(bool forceRenderHead, bool selfAvatarOnly) {
     if (!selfAvatarOnly) {
         //  Render avatars of other nodes
         NodeList* nodeList = NodeList::getInstance();
-
-        for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
-            node->lock();
-
+        
+        foreach (const SharedNodePointer& node, nodeList->getNodeHash()) {
+            QMutexLocker(&node->getMutex());
+            
             if (node->getLinkedData() != NULL && node->getType() == NODE_TYPE_AGENT) {
                 Avatar *avatar = (Avatar *)node->getLinkedData();
                 if (!avatar->isInitialized()) {
@@ -3856,8 +3706,6 @@ void Application::renderAvatars(bool forceRenderHead, bool selfAvatarOnly) {
                 avatar->render(false);
                 avatar->setDisplayingLookatVectors(Menu::getInstance()->isOptionChecked(MenuOption::LookAtVectors));
             }
-
-            node->unlock();
         }
 
         // render avatar fades
@@ -4102,25 +3950,10 @@ void Application::eyedropperVoxelUnderCursor() {
     }
 }
 
-void Application::toggleFollowMode() {
-    glm::vec3 mouseRayOrigin, mouseRayDirection;
-    _viewFrustum.computePickRay(_pieMenu.getX() / (float)_glWidget->width(),
-                                _pieMenu.getY() / (float)_glWidget->height(),
-                                mouseRayOrigin, mouseRayDirection);
-    glm::vec3 eyePositionIgnored;
-    QUuid nodeUUIDIgnored;
-    Avatar* leadingAvatar = findLookatTargetAvatar(mouseRayOrigin, mouseRayDirection, eyePositionIgnored, nodeUUIDIgnored);
-
-    _myAvatar.follow(leadingAvatar);
-}
-
 void Application::resetSensors() {
     _headMouseX = _mouseX = _glWidget->width() / 2;
     _headMouseY = _mouseY = _glWidget->height() / 2;
 
-    if (_serialHeadSensor.isActive()) {
-        _serialHeadSensor.resetAverages();
-    }
     _webcam.reset();
     _faceshift.reset();
 
@@ -4173,13 +4006,13 @@ void Application::updateWindowTitle(){
     title += _profile.getLastDomain();
     title += buildVersion;
 
-    qDebug("Application title set to: %s.\n", title.toStdString().c_str());
+    qDebug("Application title set to: %s", title.toStdString().c_str());
     _window->setWindowTitle(title);
 }
 
-void Application::domainChanged(QString domain) {
+void Application::domainChanged(const QString& domainHostname) {
     // update the user's last domain in their Profile (which will propagate to data-server)
-    _profile.updateDomain(domain);
+    _profile.updateDomain(domainHostname);
 
     updateWindowTitle();
 
@@ -4192,15 +4025,11 @@ void Application::domainChanged(QString domain) {
     _particleServerJurisdictions.clear();
 
     // reset our persist thread
-    qDebug() << "domainChanged()... domain=" << domain << " swapping persist cache\n";
+    qDebug() << "Domain changed to" << domainHostname << ". Swapping persist cache.";
     updateLocalOctreeCache();
 }
 
-void Application::nodeAdded(Node* node) {
-
-}
-
-void Application::nodeKilled(Node* node) {
+void Application::nodeKilled(SharedNodePointer node) {
     if (node->getType() == NODE_TYPE_VOXEL_SERVER) {
         QUuid nodeUUID = node->getUUID();
         // see if this is the first we've heard of this node...
@@ -4280,7 +4109,7 @@ void Application::trackIncomingVoxelPacket(unsigned char* messageData, ssize_t m
                         const HifiSockAddr& senderSockAddr, bool wasStatsPacket) {
 
     // Attempt to identify the sender from it's address.
-    Node* serverNode = NodeList::getInstance()->nodeWithAddress(senderSockAddr);
+    SharedNodePointer serverNode = NodeList::getInstance()->nodeWithAddress(senderSockAddr);
     if (serverNode) {
         QUuid nodeUUID = serverNode->getUUID();
 
@@ -4297,7 +4126,7 @@ void Application::trackIncomingVoxelPacket(unsigned char* messageData, ssize_t m
 int Application::parseOctreeStats(unsigned char* messageData, ssize_t messageLength, const HifiSockAddr& senderSockAddr) {
 
     // But, also identify the sender, and keep track of the contained jurisdiction root for this server
-    Node* server = NodeList::getInstance()->nodeWithAddress(senderSockAddr);
+    SharedNodePointer server = NodeList::getInstance()->nodeWithAddress(senderSockAddr);
 
     // parse the incoming stats datas stick it in a temporary object for now, while we
     // determine which server it belongs to
@@ -4354,105 +4183,95 @@ int Application::parseOctreeStats(unsigned char* messageData, ssize_t messageLen
 }
 
 //  Receive packets from other nodes/servers and decide what to do with them!
-void* Application::networkReceive(void* args) {
+void Application::processDatagrams() {
     PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
         "Application::networkReceive()");
 
     HifiSockAddr senderSockAddr;
     ssize_t bytesReceived;
 
-    Application* app = Application::getInstance();
-    while (!app->_stopNetworkReceiveThread) {
-        if (NodeList::getInstance()->getNodeSocket().hasPendingDatagrams() &&
-            (bytesReceived = NodeList::getInstance()->getNodeSocket().readDatagram((char*) app->_incomingPacket,
-                                                                                    MAX_PACKET_SIZE,
-                                                                                    senderSockAddr.getAddressPointer(),
-                                                                                    senderSockAddr.getPortPointer()))) {
-
-            app->_packetCount++;
-            app->_bytesCount += bytesReceived;
-
-            if (packetVersionMatch(app->_incomingPacket)) {
-                // only process this packet if we have a match on the packet version
-                switch (app->_incomingPacket[0]) {
-                    case PACKET_TYPE_TRANSMITTER_DATA_V2:
-                        //  V2 = IOS transmitter app
-                        app->_myTransmitter.processIncomingData(app->_incomingPacket, bytesReceived);
-
-                        break;
-                    case PACKET_TYPE_MIXED_AUDIO:
-                        QMetaObject::invokeMethod(&app->_audio, "addReceivedAudioToBuffer", Qt::QueuedConnection,
-                                                  Q_ARG(QByteArray, QByteArray((char*) app->_incomingPacket, bytesReceived)));
-                        break;
-
-                    case PACKET_TYPE_PARTICLE_ADD_RESPONSE:
-                        // look up our ParticleEditHanders....
-                        ParticleEditHandle::handleAddResponse(app->_incomingPacket, bytesReceived);
-                        break;
-
-                    case PACKET_TYPE_PARTICLE_DATA:
-                    case PACKET_TYPE_VOXEL_DATA:
-                    case PACKET_TYPE_VOXEL_ERASE:
-                    case PACKET_TYPE_OCTREE_STATS:
-                    case PACKET_TYPE_ENVIRONMENT_DATA: {
-                        PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
-                            "Application::networkReceive()... _voxelProcessor.queueReceivedPacket()");
-
-                        bool wantExtraDebugging = app->getLogger()->extraDebugging();
-                        if (wantExtraDebugging && app->_incomingPacket[0] == PACKET_TYPE_VOXEL_DATA) {
-                            int numBytesPacketHeader = numBytesForPacketHeader(app->_incomingPacket);
-                            unsigned char* dataAt = app->_incomingPacket + numBytesPacketHeader;
-                            dataAt += sizeof(VOXEL_PACKET_FLAGS);
-                            VOXEL_PACKET_SEQUENCE sequence = (*(VOXEL_PACKET_SEQUENCE*)dataAt);
-                            dataAt += sizeof(VOXEL_PACKET_SEQUENCE);
-                            VOXEL_PACKET_SENT_TIME sentAt = (*(VOXEL_PACKET_SENT_TIME*)dataAt);
-                            dataAt += sizeof(VOXEL_PACKET_SENT_TIME);
-                            VOXEL_PACKET_SENT_TIME arrivedAt = usecTimestampNow();
-                            int flightTime = arrivedAt - sentAt;
-
-                            printf("got PACKET_TYPE_VOXEL_DATA, sequence:%d flightTime:%d\n", sequence, flightTime);
-                        }
-
-                        // add this packet to our list of voxel packets and process them on the voxel processing
-                        app->_voxelProcessor.queueReceivedPacket(senderSockAddr, app->_incomingPacket, bytesReceived);
-                        break;
+    while (NodeList::getInstance()->getNodeSocket().hasPendingDatagrams() &&
+        (bytesReceived = NodeList::getInstance()->getNodeSocket().readDatagram((char*) _incomingPacket,
+                                                                               MAX_PACKET_SIZE,
+                                                                               senderSockAddr.getAddressPointer(),
+                                                                               senderSockAddr.getPortPointer()))) {
+        
+        _packetCount++;
+        _bytesCount += bytesReceived;
+        
+        if (packetVersionMatch(_incomingPacket)) {
+            // only process this packet if we have a match on the packet version
+            switch (_incomingPacket[0]) {
+                case PACKET_TYPE_TRANSMITTER_DATA_V2:
+                    //  V2 = IOS transmitter app
+                    _myTransmitter.processIncomingData(_incomingPacket, bytesReceived);
+                    
+                    break;
+                case PACKET_TYPE_MIXED_AUDIO:
+                    QMetaObject::invokeMethod(&_audio, "addReceivedAudioToBuffer", Qt::QueuedConnection,
+                                              Q_ARG(QByteArray, QByteArray((char*) _incomingPacket, bytesReceived)));
+                    break;
+                    
+                case PACKET_TYPE_PARTICLE_ADD_RESPONSE:
+                    // look up our ParticleEditHanders....
+                    ParticleEditHandle::handleAddResponse(_incomingPacket, bytesReceived);
+                    break;
+                    
+                case PACKET_TYPE_PARTICLE_DATA:
+                case PACKET_TYPE_VOXEL_DATA:
+                case PACKET_TYPE_VOXEL_ERASE:
+                case PACKET_TYPE_OCTREE_STATS:
+                case PACKET_TYPE_ENVIRONMENT_DATA: {
+                    PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
+                                            "Application::networkReceive()... _voxelProcessor.queueReceivedPacket()");
+                    
+                    bool wantExtraDebugging = getLogger()->extraDebugging();
+                    if (wantExtraDebugging && _incomingPacket[0] == PACKET_TYPE_VOXEL_DATA) {
+                        int numBytesPacketHeader = numBytesForPacketHeader(_incomingPacket);
+                        unsigned char* dataAt = _incomingPacket + numBytesPacketHeader;
+                        dataAt += sizeof(VOXEL_PACKET_FLAGS);
+                        VOXEL_PACKET_SEQUENCE sequence = (*(VOXEL_PACKET_SEQUENCE*)dataAt);
+                        dataAt += sizeof(VOXEL_PACKET_SEQUENCE);
+                        VOXEL_PACKET_SENT_TIME sentAt = (*(VOXEL_PACKET_SENT_TIME*)dataAt);
+                        dataAt += sizeof(VOXEL_PACKET_SENT_TIME);
+                        VOXEL_PACKET_SENT_TIME arrivedAt = usecTimestampNow();
+                        int flightTime = arrivedAt - sentAt;
+                        
+                        printf("got PACKET_TYPE_VOXEL_DATA, sequence:%d flightTime:%d\n", sequence, flightTime);
                     }
-                    case PACKET_TYPE_METAVOXEL_DATA:
-                        app->_metavoxels.processData(QByteArray((const char*)app->_incomingPacket, bytesReceived),
-                            senderSockAddr);
-                        break;
-                    case PACKET_TYPE_BULK_AVATAR_DATA:
-                        NodeList::getInstance()->processBulkNodeData(senderSockAddr,
-                                                                     app->_incomingPacket,
-                                                                     bytesReceived);
-                        getInstance()->_bandwidthMeter.inputStream(BandwidthMeter::AVATARS).updateValue(bytesReceived);
-                        break;
-                    case PACKET_TYPE_AVATAR_URLS:
-                        processAvatarURLsMessage(app->_incomingPacket, bytesReceived);
-                        break;
-                    case PACKET_TYPE_AVATAR_FACE_VIDEO:
-                        processAvatarFaceVideoMessage(app->_incomingPacket, bytesReceived);
-                        break;
-                    case PACKET_TYPE_DATA_SERVER_GET:
-                    case PACKET_TYPE_DATA_SERVER_PUT:
-                    case PACKET_TYPE_DATA_SERVER_SEND:
-                    case PACKET_TYPE_DATA_SERVER_CONFIRM:
-                        DataServerClient::processMessageFromDataServer(app->_incomingPacket, bytesReceived);
-                        break;
-                    default:
-                        NodeList::getInstance()->processNodeData(senderSockAddr, app->_incomingPacket, bytesReceived);
-                        break;
+                    
+                    // add this packet to our list of voxel packets and process them on the voxel processing
+                    _voxelProcessor.queueReceivedPacket(senderSockAddr, _incomingPacket, bytesReceived);
+                    break;
                 }
+                case PACKET_TYPE_METAVOXEL_DATA:
+                    _metavoxels.processData(QByteArray((const char*) _incomingPacket, bytesReceived),
+                                                 senderSockAddr);
+                    break;
+                case PACKET_TYPE_BULK_AVATAR_DATA:
+                    NodeList::getInstance()->processBulkNodeData(senderSockAddr,
+                                                                 _incomingPacket,
+                                                                 bytesReceived);
+                    getInstance()->_bandwidthMeter.inputStream(BandwidthMeter::AVATARS).updateValue(bytesReceived);
+                    break;
+                case PACKET_TYPE_AVATAR_URLS:
+                    processAvatarURLsMessage(_incomingPacket, bytesReceived);
+                    break;
+                case PACKET_TYPE_AVATAR_FACE_VIDEO:
+                    processAvatarFaceVideoMessage(_incomingPacket, bytesReceived);
+                    break;
+                case PACKET_TYPE_DATA_SERVER_GET:
+                case PACKET_TYPE_DATA_SERVER_PUT:
+                case PACKET_TYPE_DATA_SERVER_SEND:
+                case PACKET_TYPE_DATA_SERVER_CONFIRM:
+                    DataServerClient::processMessageFromDataServer(_incomingPacket, bytesReceived);
+                    break;
+                default:
+                    NodeList::getInstance()->processNodeData(senderSockAddr, _incomingPacket, bytesReceived);
+                    break;
             }
-        } else if (!app->_enableNetworkThread) {
-            break;
         }
     }
-
-    if (app->_enableNetworkThread) {
-        pthread_exit(0);
-    }
-    return NULL;
 }
 
 void Application::packetSentNotification(ssize_t length) {
@@ -4469,14 +4288,12 @@ void Application::loadScript() {
     QByteArray fileNameAscii = fileNameString.toLocal8Bit();
     const char* fileName = fileNameAscii.data();
 
-    printf("fileName:%s\n",fileName);
-
     std::ifstream file(fileName, std::ios::in|std::ios::binary|std::ios::ate);
     if(!file.is_open()) {
-        printf("error loading file\n");
+        qDebug("Error loading file %s", fileName);
         return;
     }
-    qDebug("loading file %s...\n", fileName);
+    qDebug("Loading file %s...", fileName);
 
     // get file length....
     unsigned long fileLength = file.tellg();
@@ -4568,7 +4385,7 @@ void Application::updateLocalOctreeCache(bool firstTime) {
         _persistThread = new OctreePersistThread(_voxels.getTree(),
                                         localVoxelCacheFileName.toLocal8Bit().constData(),LOCAL_CACHE_PERSIST_INTERVAL);
 
-        qDebug() << "updateLocalOctreeCache()... localVoxelCacheFileName=" << localVoxelCacheFileName << "\n";
+        qDebug() << "updateLocalOctreeCache()... localVoxelCacheFileName=" << localVoxelCacheFileName;
 
         if (_persistThread) {
             _voxels.beginLoadingLocalVoxelCache(); // while local voxels are importing, don't do individual node VBO updates
diff --git a/interface/src/Application.h b/interface/src/Application.h
index ba89030ccc..dcc7eb4b43 100644
--- a/interface/src/Application.h
+++ b/interface/src/Application.h
@@ -52,7 +52,6 @@
 #include "avatar/MyAvatar.h"
 #include "avatar/Profile.h"
 #include "devices/Faceshift.h"
-#include "devices/SerialInterface.h"
 #include "devices/SixenseManager.h"
 #include "devices/Webcam.h"
 #include "renderer/AmbientOcclusionEffect.h"
@@ -93,7 +92,7 @@ static const float NODE_KILLED_RED   = 1.0f;
 static const float NODE_KILLED_GREEN = 0.0f;
 static const float NODE_KILLED_BLUE  = 0.0f;
 
-class Application : public QApplication, public NodeListHook, public PacketSenderNotify, public DomainChangeListener {
+class Application : public QApplication, public PacketSenderNotify {
     Q_OBJECT
 
     friend class VoxelPacketProcessor;
@@ -153,7 +152,6 @@ public:
     VoxelTree* getClipboard() { return &_clipboard; }
     Environment* getEnvironment() { return &_environment; }
     bool isMouseHidden() const { return _mouseHidden; }
-    SerialInterface* getSerialHeadSensor() { return &_serialHeadSensor; }
     Webcam* getWebcam() { return &_webcam; }
     Faceshift* getFaceshift() { return &_faceshift; }
     SixenseManager* getSixenseManager() { return &_sixenseManager; }
@@ -192,12 +190,9 @@ public:
     void computeOffAxisFrustum(float& left, float& right, float& bottom, float& top, float& nearVal,
         float& farVal, glm::vec4& nearClipPlane, glm::vec4& farClipPlane) const;
 
-    virtual void nodeAdded(Node* node);
-    virtual void nodeKilled(Node* node);
+    
     virtual void packetSentNotification(ssize_t length);
 
-    virtual void domainChanged(QString domain);
-
     VoxelShader& getVoxelShader() { return _voxelShader; }
     PointShader& getPointShader() { return _pointShader; }
     FileLogger* getLogger() { return _logger; }
@@ -212,6 +207,11 @@ public:
     void setIsHighlightVoxel(bool isHighlightVoxel) { _isHighlightVoxel = isHighlightVoxel; }
 
 public slots:
+    void domainChanged(const QString& domainHostname);
+    void nodeKilled(SharedNodePointer node);
+    
+    void processDatagrams();
+    
     void sendAvatarFaceVideoMessage(int frameCount, const QByteArray& data);
     void exportVoxels();
     void importVoxels();
@@ -248,8 +248,6 @@ private slots:
 
     glm::vec2 getScaledScreenPoint(glm::vec2 projectedPoint);
 
-    void toggleFollowMode();
-
     void closeMirrorView();
     void restoreMirrorView();
     void shrinkMirrorView();
@@ -299,7 +297,6 @@ private:
     bool isLookingAtMyAvatar(Avatar* avatar);
 
     void renderLookatIndicator(glm::vec3 pointOfInterest);
-    void renderFollowIndicator();
     void renderHighlightVoxel(VoxelDetail voxel);
 
     void updateAvatar(float deltaTime);
@@ -333,14 +330,10 @@ private:
     QMainWindow* _window;
     QGLWidget* _glWidget;
 
-    QAction* _followMode;
-
     BandwidthMeter _bandwidthMeter;
 
-    SerialInterface _serialHeadSensor;
     QNetworkAccessManager* _networkAccessManager;
     QSettings* _settings;
-    bool _displayLevels;
 
     glm::vec3 _gravity;
 
@@ -463,10 +456,6 @@ private:
 
     Audio _audio;
 
-    bool _enableNetworkThread;
-    pthread_t _networkReceiveThread;
-    bool _stopNetworkReceiveThread;
-
     bool _enableProcessVoxelsThread;
     VoxelPacketProcessor _voxelProcessor;
     VoxelHideShowThread _voxelHideShowThread;
diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp
index 84b693c282..d1e2f59cae 100644
--- a/interface/src/Audio.cpp
+++ b/interface/src/Audio.cpp
@@ -138,9 +138,9 @@ bool adjustedFormatForAudioDevice(const QAudioDeviceInfo& audioDevice,
                                   const QAudioFormat& desiredAudioFormat,
                                   QAudioFormat& adjustedAudioFormat) {
     if (!audioDevice.isFormatSupported(desiredAudioFormat)) {
-        qDebug() << "The desired format for audio I/O is" << desiredAudioFormat << "\n";
-        qDebug() << "The desired audio format is not supported by this device.\n";
-
+        qDebug() << "The desired format for audio I/O is" << desiredAudioFormat;
+        qDebug("The desired audio format is not supported by this device");
+        
         if (desiredAudioFormat.channelCount() == 1) {
             adjustedAudioFormat = desiredAudioFormat;
             adjustedAudioFormat.setChannelCount(2);
@@ -245,12 +245,11 @@ void Audio::start() {
     _desiredOutputFormat.setChannelCount(2);
 
     QAudioDeviceInfo inputDeviceInfo = defaultAudioDeviceForMode(QAudio::AudioInput);
-
-    qDebug() << "The audio input device is" << inputDeviceInfo.deviceName() << "\n";
-
+    qDebug() << "The audio input device is" << inputDeviceInfo.deviceName();
+    
     if (adjustedFormatForAudioDevice(inputDeviceInfo, _desiredInputFormat, _inputFormat)) {
-        qDebug() << "The format to be used for audio input is" << _inputFormat << "\n";
-
+        qDebug() << "The format to be used for audio input is" << _inputFormat;
+        
         _audioInput = new QAudioInput(inputDeviceInfo, _inputFormat, this);
         _numInputCallbackBytes = NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL * _inputFormat.channelCount()
             * (_inputFormat.sampleRate() / SAMPLE_RATE)
@@ -258,12 +257,11 @@ void Audio::start() {
         _audioInput->setBufferSize(_numInputCallbackBytes);
 
         QAudioDeviceInfo outputDeviceInfo = defaultAudioDeviceForMode(QAudio::AudioOutput);
-
-        qDebug() << "The audio output device is" << outputDeviceInfo.deviceName() << "\n";
+        qDebug() << "The audio output device is" << outputDeviceInfo.deviceName();
 
         if (adjustedFormatForAudioDevice(outputDeviceInfo, _desiredOutputFormat, _outputFormat)) {
-            qDebug() << "The format to be used for audio output is" << _outputFormat << "\n";
-
+            qDebug() << "The format to be used for audio output is" << _outputFormat;
+            
             _inputRingBuffer.resizeForFrameSize(_numInputCallbackBytes * CALLBACK_ACCELERATOR_RATIO / sizeof(int16_t));
             _inputDevice = _audioInput->start();
             connect(_inputDevice, SIGNAL(readyRead()), this, SLOT(handleAudioInput()));
@@ -280,8 +278,8 @@ void Audio::start() {
 
         return;
     }
-
-    qDebug() << "Unable to set up audio I/O because of a problem with input or output formats.\n";
+    
+    qDebug() << "Unable to set up audio I/O because of a problem with input or output formats.";
 }
 
 void Audio::handleAudioInput() {
@@ -367,9 +365,9 @@ void Audio::handleAudioInput() {
                             NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL);
 
         NodeList* nodeList = NodeList::getInstance();
-        Node* audioMixer = nodeList->soloNodeOfType(NODE_TYPE_AUDIO_MIXER);
-
-        if (audioMixer && nodeList->getNodeActiveSocketOrPing(audioMixer)) {
+        SharedNodePointer audioMixer = nodeList->soloNodeOfType(NODE_TYPE_AUDIO_MIXER);
+        
+        if (audioMixer && nodeList->getNodeActiveSocketOrPing(audioMixer.data())) {
             MyAvatar* interfaceAvatar = Application::getInstance()->getAvatar();
 
             glm::vec3 headPosition = interfaceAvatar->getHeadJointPosition();
@@ -451,7 +449,7 @@ void Audio::addReceivedAudioToBuffer(const QByteArray& audioByteArray) {
         if (!_ringBuffer.isNotStarvedOrHasMinimumSamples(NETWORK_BUFFER_LENGTH_SAMPLES_STEREO
                                                          + (_jitterBufferSamples * 2))) {
             // starved and we don't have enough to start, keep waiting
-            qDebug() << "Buffer is starved and doesn't have enough samples to start. Held back.\n";
+            qDebug() << "Buffer is starved and doesn't have enough samples to start. Held back.";
         } else {
             //  We are either already playing back, or we have enough audio to start playing back.
             _ringBuffer.setIsStarved(false);
@@ -521,7 +519,7 @@ void Audio::addReceivedAudioToBuffer(const QByteArray& audioByteArray) {
     } else if (_audioOutput->bytesFree() == _audioOutput->bufferSize()) {
         // we don't have any audio data left in the output buffer, and the ring buffer from
         // the network has nothing in it either - we just starved
-        qDebug() << "Audio output just starved.\n";
+        qDebug() << "Audio output just starved.";
         _ringBuffer.setIsStarved(true);
         _numFramesDisplayStarve = 10;
     }
diff --git a/interface/src/BuckyBalls.cpp b/interface/src/BuckyBalls.cpp
index 8227205523..e236a8ea7d 100644
--- a/interface/src/BuckyBalls.cpp
+++ b/interface/src/BuckyBalls.cpp
@@ -30,7 +30,7 @@ BuckyBalls::BuckyBalls() {
     colors[1] = glm::vec3(0.64f, 0.16f, 0.16f);
     colors[2] = glm::vec3(0.31f, 0.58f, 0.80f);
 
-    qDebug("Creating buckyballs...\n");
+    qDebug("Creating buckyballs...");
     for (int i = 0; i < NUM_BBALLS; i++) {
         _bballPosition[i] = CORNER_BBALLS + randVector() * RANGE_BBALLS;
         int element = (rand() % NUM_ELEMENTS);
diff --git a/interface/src/DataServerClient.cpp b/interface/src/DataServerClient.cpp
index 1eb4738b0d..45bdd6f6a9 100644
--- a/interface/src/DataServerClient.cpp
+++ b/interface/src/DataServerClient.cpp
@@ -140,18 +140,18 @@ void DataServerClient::processSendFromDataServer(unsigned char* packetData, int
             if (keyList[i] == DataServerKey::FaceMeshURL) {
 
                 if (userUUID.isNull() || userUUID == Application::getInstance()->getProfile()->getUUID()) {
-                    qDebug("Changing user's face model URL to %s\n", valueList[i].toLocal8Bit().constData());
+                    qDebug("Changing user's face model URL to %s", valueList[i].toLocal8Bit().constData());
                     Application::getInstance()->getProfile()->setFaceModelURL(QUrl(valueList[i]));
                 } else {
                     // mesh URL for a UUID, find avatar in our list
-                    NodeList* nodeList = NodeList::getInstance();
-                    for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
+                    
+                    foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
                         if (node->getLinkedData() != NULL && node->getType() == NODE_TYPE_AGENT) {
                             Avatar* avatar = (Avatar *) node->getLinkedData();
 
                             if (avatar->getUUID() == userUUID) {
                                 QMetaObject::invokeMethod(&avatar->getHead().getFaceModel(),
-                                    "setURL", Q_ARG(QUrl, QUrl(valueList[i])));
+                                                          "setURL", Q_ARG(QUrl, QUrl(valueList[i])));
                             }
                         }
                     }
@@ -159,18 +159,17 @@ void DataServerClient::processSendFromDataServer(unsigned char* packetData, int
             } else if (keyList[i] == DataServerKey::SkeletonURL) {
 
                 if (userUUID.isNull() || userUUID == Application::getInstance()->getProfile()->getUUID()) {
-                    qDebug("Changing user's skeleton URL to %s\n", valueList[i].toLocal8Bit().constData());
+                    qDebug("Changing user's skeleton URL to %s", valueList[i].toLocal8Bit().constData());
                     Application::getInstance()->getProfile()->setSkeletonModelURL(QUrl(valueList[i]));
                 } else {
                     // skeleton URL for a UUID, find avatar in our list
-                    NodeList* nodeList = NodeList::getInstance();
-                    for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
+                    foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
                         if (node->getLinkedData() != NULL && node->getType() == NODE_TYPE_AGENT) {
                             Avatar* avatar = (Avatar *) node->getLinkedData();
 
                             if (avatar->getUUID() == userUUID) {
                                 QMetaObject::invokeMethod(&avatar->getSkeletonModel(), "setURL",
-                                    Q_ARG(QUrl, QUrl(valueList[i])));
+                                                          Q_ARG(QUrl, QUrl(valueList[i])));
                             }
                         }
                     }
@@ -190,8 +189,8 @@ void DataServerClient::processSendFromDataServer(unsigned char* packetData, int
                     qDebug() << "Changing domain to" << valueList[i].toLocal8Bit().constData() <<
                         ", position to" << valueList[i + 1].toLocal8Bit().constData() <<
                         ", and orientation to" << valueList[i + 2].toLocal8Bit().constData() <<
-                        "to go to" << userString << "\n";
-
+                        "to go to" << userString;
+                    
                     NodeList::getInstance()->setDomainHostname(valueList[i]);
                     // orient the user to face the target
                     glm::quat newOrientation = glm::quat(glm::radians(glm::vec3(orientationItems[0].toFloat(),
diff --git a/interface/src/Environment.cpp b/interface/src/Environment.cpp
index c82356ba65..46c156f860 100644
--- a/interface/src/Environment.cpp
+++ b/interface/src/Environment.cpp
@@ -40,7 +40,7 @@ Environment::~Environment() {
 
 void Environment::init() {
     if (_initialized) {
-        qDebug("[ERROR] Environment is already initialized.\n");
+        qDebug("[ERROR] Environment is already initialized.");
         return;
     }
 
diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp
index 8871d22a2b..166b57b377 100644
--- a/interface/src/Menu.cpp
+++ b/interface/src/Menu.cpp
@@ -42,7 +42,7 @@ Menu* Menu::getInstance() {
     menuInstanceMutex.lock();
     
     if (!_instance) {
-        qDebug("First call to Menu::getInstance() - initing menu.\n");
+        qDebug("First call to Menu::getInstance() - initing menu.");
         
         _instance = new Menu();
     }
@@ -984,7 +984,7 @@ void Menu::goToLocation() {
                 // send a node kill request, indicating to other clients that they should play the "disappeared" effect
                 NodeList::getInstance()->sendKillNode(&NODE_TYPE_AVATAR_MIXER, 1);
                 
-                qDebug("Going To Location: %f, %f, %f...\n", x, y, z);
+                qDebug("Going To Location: %f, %f, %f...", x, y, z);
                 myAvatar->setPosition(newAvatarPos); 
             }
         }
@@ -1033,7 +1033,7 @@ void Menu::pasteToVoxel() {
         if (locationToPaste == octalCodeToHexString(octalCodeDestination)) {
             Application::getInstance()->pasteVoxelsToOctalCode(octalCodeDestination);
         } else {
-            qDebug() << "problem with octcode...\n";
+            qDebug() << "Problem with octcode...";
         }
     }
     
diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp
index 355b027e93..fc72f7444e 100644
--- a/interface/src/MetavoxelSystem.cpp
+++ b/interface/src/MetavoxelSystem.cpp
@@ -26,10 +26,6 @@ MetavoxelSystem::MetavoxelSystem() :
     _buffer(QOpenGLBuffer::VertexBuffer) {
 }
 
-MetavoxelSystem::~MetavoxelSystem() {
-    NodeList::getInstance()->removeHook(this);
-}
-
 void MetavoxelSystem::init() {
     if (!_program.isLinked()) {
         switchToResourcesParentIfRequired();
@@ -39,7 +35,10 @@ void MetavoxelSystem::init() {
         _pointScaleLocation = _program.uniformLocation("pointScale");
     }
     
-    NodeList::getInstance()->addHook(this);
+    NodeList* nodeList = NodeList::getInstance();
+    
+    connect(nodeList, SIGNAL(nodeAdded(SharedNodePointer)), SLOT(nodeAdded(SharedNodePointer)));
+    connect(nodeList, SIGNAL(nodeKilled(SharedNodePointer)), SLOT(nodeKilled(SharedNodePointer)));
     
     AttributeRegistry::getInstance()->configureScriptEngine(&_scriptEngine);
     
@@ -117,14 +116,14 @@ void MetavoxelSystem::render() {
     _program.release();
 }
 
-void MetavoxelSystem::nodeAdded(Node* node) {
+void MetavoxelSystem::nodeAdded(SharedNodePointer node) {
     if (node->getType() == NODE_TYPE_METAVOXEL_SERVER) {
         QMetaObject::invokeMethod(this, "addClient", Q_ARG(const QUuid&, node->getUUID()),
             Q_ARG(const HifiSockAddr&, node->getLocalSocket()));
     }
 }
 
-void MetavoxelSystem::nodeKilled(Node* node) {
+void MetavoxelSystem::nodeKilled(SharedNodePointer node) {
     if (node->getType() == NODE_TYPE_METAVOXEL_SERVER) {
         QMetaObject::invokeMethod(this, "removeClient", Q_ARG(const QUuid&, node->getUUID()));
     }
diff --git a/interface/src/MetavoxelSystem.h b/interface/src/MetavoxelSystem.h
index ddb69644d5..a58729285d 100644
--- a/interface/src/MetavoxelSystem.h
+++ b/interface/src/MetavoxelSystem.h
@@ -26,13 +26,11 @@
 class MetavoxelClient;
 
 /// Renders a metavoxel tree.
-class MetavoxelSystem : public QObject, public NodeListHook {
+class MetavoxelSystem : public QObject {
     Q_OBJECT
 
 public:
-
     MetavoxelSystem();
-    ~MetavoxelSystem();
 
     void init();
     
@@ -41,9 +39,9 @@ public:
     void simulate(float deltaTime);
     void render();
     
-    virtual void nodeAdded(Node* node);
-    virtual void nodeKilled(Node* node);
-    
+public slots:
+    void nodeAdded(SharedNodePointer node);
+    void nodeKilled(SharedNodePointer node);
 private:
 
     Q_INVOKABLE void addClient(const QUuid& uuid, const HifiSockAddr& address);
diff --git a/interface/src/Oscilloscope.cpp b/interface/src/Oscilloscope.cpp
index ddbae9d920..90d2d49926 100644
--- a/interface/src/Oscilloscope.cpp
+++ b/interface/src/Oscilloscope.cpp
@@ -11,7 +11,6 @@
 #include <algorithm>
 
 #include <stdint.h>
-
 #include <QtCore/QDebug>
 
 #include "InterfaceConfig.h"
diff --git a/interface/src/PairingHandler.cpp b/interface/src/PairingHandler.cpp
index 755dadf335..b06a6248e4 100644
--- a/interface/src/PairingHandler.cpp
+++ b/interface/src/PairingHandler.cpp
@@ -46,9 +46,8 @@ void PairingHandler::sendPairRequest() {
             (localAddress >> 16) & 0xFF,
             (localAddress >> 24) & 0xFF,
             NodeList::getInstance()->getNodeSocket().localPort());
-
-    qDebug("Sending pair packet: %s\n", pairPacket);
-
+    qDebug("Sending pair packet: %s", pairPacket);
+    
     HifiSockAddr pairingServerSocket(PAIRING_SERVER_HOSTNAME, PAIRING_SERVER_PORT);
 
     // send the pair request to the pairing server
diff --git a/interface/src/Util.cpp b/interface/src/Util.cpp
index 958fc02640..d557eb67b3 100644
--- a/interface/src/Util.cpp
+++ b/interface/src/Util.cpp
@@ -616,8 +616,8 @@ void runTimingTests() {
         gettimeofday(&endTime, NULL);
     }
     elapsedMsecs = diffclock(&startTime, &endTime);
-    qDebug("gettimeofday() usecs: %f\n", 1000.0f * elapsedMsecs / (float) numTests);
-
+    qDebug("gettimeofday() usecs: %f", 1000.0f * elapsedMsecs / (float) numTests);
+    
     // Random number generation
     gettimeofday(&startTime, NULL);
     for (int i = 1; i < numTests; i++) {
@@ -625,7 +625,7 @@ void runTimingTests() {
     }
     gettimeofday(&endTime, NULL);
     elapsedMsecs = diffclock(&startTime, &endTime);
-    qDebug("rand() stored in array usecs: %f\n", 1000.0f * elapsedMsecs / (float) numTests);
+    qDebug("rand() stored in array usecs: %f", 1000.0f * elapsedMsecs / (float) numTests);
 
     // Random number generation using randFloat()
     gettimeofday(&startTime, NULL);
@@ -634,7 +634,7 @@ void runTimingTests() {
     }
     gettimeofday(&endTime, NULL);
     elapsedMsecs = diffclock(&startTime, &endTime);
-    qDebug("randFloat() stored in array usecs: %f\n", 1000.0f * elapsedMsecs / (float) numTests);
+    qDebug("randFloat() stored in array usecs: %f", 1000.0f * elapsedMsecs / (float) numTests);
 
     //  PowF function
     fTest = 1145323.2342f;
@@ -644,7 +644,7 @@ void runTimingTests() {
     }
     gettimeofday(&endTime, NULL);
     elapsedMsecs = diffclock(&startTime, &endTime);
-    qDebug("powf(f, 0.5) usecs: %f\n", 1000.0f * elapsedMsecs / (float) numTests);
+    qDebug("powf(f, 0.5) usecs: %f", 1000.0f * elapsedMsecs / (float) numTests);
 
     //  Vector Math
     float distance;
@@ -657,7 +657,7 @@ void runTimingTests() {
     }
     gettimeofday(&endTime, NULL);
     elapsedMsecs = diffclock(&startTime, &endTime);
-    qDebug("vector math usecs: %f [%f msecs total for %d tests]\n",
+    qDebug("vector math usecs: %f [%f msecs total for %d tests]",
              1000.0f * elapsedMsecs / (float) numTests, elapsedMsecs, numTests);
 
     //  Vec3 test
@@ -671,7 +671,7 @@ void runTimingTests() {
     }
     gettimeofday(&endTime, NULL);
     elapsedMsecs = diffclock(&startTime, &endTime);
-    qDebug("vec3 assign and dot() usecs: %f\n", 1000.0f * elapsedMsecs / (float) numTests);
+    qDebug("vec3 assign and dot() usecs: %f", 1000.0f * elapsedMsecs / (float) numTests);
 }
 
 float loadSetting(QSettings* settings, const char* name, float defaultValue) {
diff --git a/interface/src/VoxelHideShowThread.cpp b/interface/src/VoxelHideShowThread.cpp
index 512d269bd2..2a42db7f70 100644
--- a/interface/src/VoxelHideShowThread.cpp
+++ b/interface/src/VoxelHideShowThread.cpp
@@ -33,7 +33,7 @@ bool VoxelHideShowThread::process() {
 
     bool showExtraDebugging = Application::getInstance()->getLogger()->extraDebugging();
     if (showExtraDebugging && elapsed > USECS_PER_FRAME) {
-        qDebug() << "VoxelHideShowThread::process()... checkForCulling took " << elapsed << "\n";
+        qDebug() << "VoxelHideShowThread::process()... checkForCulling took" << elapsed;
     }
 
     if (isStillRunning()) {
diff --git a/interface/src/VoxelImporter.cpp b/interface/src/VoxelImporter.cpp
index ce8d5d3894..570eb5043c 100644
--- a/interface/src/VoxelImporter.cpp
+++ b/interface/src/VoxelImporter.cpp
@@ -181,7 +181,7 @@ void ImportTask::run() {
     } else if (_filename.endsWith(".schematic", Qt::CaseInsensitive)) {
         voxelSystem->readFromSchematicFile(_filename.toLocal8Bit().data());
     } else {
-        qDebug("[ERROR] Invalid file extension.\n");
+        qDebug("[ERROR] Invalid file extension.");
     }
 
     voxelSystem->getTree()->reaverageOctreeElements();
diff --git a/interface/src/VoxelPacketProcessor.cpp b/interface/src/VoxelPacketProcessor.cpp
index 6e5d4ca85c..9c2ec2a539 100644
--- a/interface/src/VoxelPacketProcessor.cpp
+++ b/interface/src/VoxelPacketProcessor.cpp
@@ -21,7 +21,7 @@ void VoxelPacketProcessor::processPacket(const HifiSockAddr& senderSockAddr, uns
     const int WAY_BEHIND = 300;
 
     if (packetsToProcessCount() > WAY_BEHIND && Application::getInstance()->getLogger()->extraDebugging()) {
-        qDebug("VoxelPacketProcessor::processPacket() packets to process=%d\n", packetsToProcessCount());
+        qDebug("VoxelPacketProcessor::processPacket() packets to process=%d", packetsToProcessCount());
     }
     ssize_t messageLength = packetLength;
 
@@ -57,12 +57,13 @@ void VoxelPacketProcessor::processPacket(const HifiSockAddr& senderSockAddr, uns
     if (Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) {
         app->trackIncomingVoxelPacket(packetData, messageLength, senderSockAddr, wasStatsPacket);
         
-        Node* serverNode = NodeList::getInstance()->nodeWithAddress(senderSockAddr);
+        SharedNodePointer serverNode = NodeList::getInstance()->nodeWithAddress(senderSockAddr);
         if (serverNode && serverNode->getActiveSocket() && *serverNode->getActiveSocket() == senderSockAddr) {
         
             switch(packetData[0]) {
                 case PACKET_TYPE_PARTICLE_DATA: {
-                    app->_particles.processDatagram(QByteArray((char*) packetData, messageLength), senderSockAddr, serverNode);
+                    app->_particles.processDatagram(QByteArray((char*) packetData, messageLength),
+                                                    senderSockAddr, serverNode.data());
                 } break;
                 
                 case PACKET_TYPE_ENVIRONMENT_DATA: {
diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp
index 2c0203cb1f..a6c12ac481 100644
--- a/interface/src/VoxelSystem.cpp
+++ b/interface/src/VoxelSystem.cpp
@@ -197,7 +197,7 @@ glBufferIndex VoxelSystem::getNextBufferIndex() {
 // will be "invisible"
 void VoxelSystem::freeBufferIndex(glBufferIndex index) {
     if (_voxelsInWriteArrays == 0) {
-        qDebug() << "freeBufferIndex() called when _voxelsInWriteArrays == 0!!!!\n";
+        qDebug() << "freeBufferIndex() called when _voxelsInWriteArrays == 0!";
     }
 
     // if the "freed" index was our max index, then just drop the _voxelsInWriteArrays down one...
@@ -207,7 +207,7 @@ void VoxelSystem::freeBufferIndex(glBufferIndex index) {
     if (Menu::getInstance()->isOptionChecked(MenuOption::AutomaticallyAuditTree)) {
         for (unsigned long i = 0; i < _freeIndexes.size(); i++) {
             if (_freeIndexes[i] == index) {
-                printf("freeBufferIndex(glBufferIndex index)... index=%ld already in free list!\n", index);
+                printf("freeBufferIndex(glBufferIndex index)... index=%ld already in free list!", index);
                 inList = true;
                 break;
             }
@@ -605,7 +605,7 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) {
                     if (Application::getInstance()->getLogger()->extraDebugging()) {
                         qDebug("VoxelSystem::parseData() ... Got Packet Section"
                                " color:%s compressed:%s sequence: %u flight:%d usec size:%d data:%d"
-                               " subsection:%d sectionLength:%d uncompressed:%d\n",
+                               " subsection:%d sectionLength:%d uncompressed:%d",
                             debug::valueOf(packetIsColored), debug::valueOf(packetIsCompressed),
                             sequence, flightTime, numBytes, dataBytes, subsection, sectionLength, packetData.getUncompressedSize());
                     }
@@ -694,7 +694,7 @@ void VoxelSystem::setupNewVoxelsForDrawing() {
 
     bool extraDebugging = Application::getInstance()->getLogger()->extraDebugging();
     if (extraDebugging) {
-        qDebug("setupNewVoxelsForDrawing()... _voxelsUpdated=%lu...\n",_voxelsUpdated);
+        qDebug("setupNewVoxelsForDrawing()... _voxelsUpdated=%lu...",_voxelsUpdated);
         _viewFrustum->printDebugDetails();
     }
 }
@@ -791,7 +791,7 @@ void VoxelSystem::cleanupRemovedVoxels() {
     // This handles cleanup of voxels that were culled as part of our regular out of view culling operation
     if (!_removedVoxels.isEmpty()) {
         if (Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings)) {
-            qDebug() << "cleanupRemovedVoxels().. _removedVoxels=" << _removedVoxels.count() << "\n";
+            qDebug() << "cleanupRemovedVoxels().. _removedVoxels=" << _removedVoxels.count();
         }
         while (!_removedVoxels.isEmpty()) {
             delete _removedVoxels.extract();
@@ -805,7 +805,7 @@ void VoxelSystem::cleanupRemovedVoxels() {
     if (!_writeRenderFullVBO && (_abandonedVBOSlots > (_voxelsInWriteArrays * TOO_MANY_ABANDONED_RATIO))) {
         if (Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings)) {
             qDebug() << "cleanupRemovedVoxels().. _abandonedVBOSlots ["
-                << _abandonedVBOSlots << "] > TOO_MANY_ABANDONED_RATIO \n";
+                << _abandonedVBOSlots << "] > TOO_MANY_ABANDONED_RATIO";
         }
         _writeRenderFullVBO = true;
     }
@@ -972,7 +972,7 @@ int VoxelSystem::updateNodeInArrays(VoxelTreeElement* node, bool reuseIndex, boo
         // possibly shifting down to lower LOD or something. This debug message is to help identify, if/when/how this
         // state actually occurs.
         if (Application::getInstance()->getLogger()->extraDebugging()) {
-            qDebug("OHHHH NOOOOOO!!!! updateNodeInArrays() BAILING (_voxelsInWriteArrays >= _maxVoxels)\n");
+            qDebug("OH NO! updateNodeInArrays() BAILING (_voxelsInWriteArrays >= _maxVoxels)");
         }
         return 0;
     }
@@ -1052,7 +1052,7 @@ ProgramObject VoxelSystem::_shadowMapProgram;
 
 void VoxelSystem::init() {
     if (_initialized) {
-        qDebug("[ERROR] VoxelSystem is already initialized.\n");
+        qDebug("[ERROR] VoxelSystem is already initialized.");
         return;
     }
 
@@ -1426,7 +1426,7 @@ void VoxelSystem::clearAllNodesBufferIndex() {
     _tree->recurseTreeWithOperation(clearAllNodesBufferIndexOperation);
     unlockTree();
     if (Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings)) {
-        qDebug("clearing buffer index of %d nodes\n", _nodeCount);
+        qDebug("clearing buffer index of %d nodes", _nodeCount);
     }
 }
 
@@ -1439,7 +1439,7 @@ bool VoxelSystem::forceRedrawEntireTreeOperation(OctreeElement* element, void* e
 void VoxelSystem::forceRedrawEntireTree() {
     _nodeCount = 0;
     _tree->recurseTreeWithOperation(forceRedrawEntireTreeOperation);
-    qDebug("forcing redraw of %d nodes\n", _nodeCount);
+    qDebug("forcing redraw of %d nodes", _nodeCount);
     _tree->setDirtyBit();
     setupNewVoxelsForDrawing();
 }
@@ -1457,7 +1457,7 @@ bool VoxelSystem::randomColorOperation(OctreeElement* element, void* extraData)
 void VoxelSystem::randomizeVoxelColors() {
     _nodeCount = 0;
     _tree->recurseTreeWithOperation(randomColorOperation);
-    qDebug("setting randomized true color for %d nodes\n", _nodeCount);
+    qDebug("setting randomized true color for %d nodes", _nodeCount);
     _tree->setDirtyBit();
     setupNewVoxelsForDrawing();
 }
@@ -1473,7 +1473,7 @@ bool VoxelSystem::falseColorizeRandomOperation(OctreeElement* element, void* ext
 void VoxelSystem::falseColorizeRandom() {
     _nodeCount = 0;
     _tree->recurseTreeWithOperation(falseColorizeRandomOperation);
-    qDebug("setting randomized false color for %d nodes\n", _nodeCount);
+    qDebug("setting randomized false color for %d nodes", _nodeCount);
     _tree->setDirtyBit();
     setupNewVoxelsForDrawing();
 }
@@ -1489,7 +1489,7 @@ void VoxelSystem::trueColorize() {
     PerformanceWarning warn(true, "trueColorize()",true);
     _nodeCount = 0;
     _tree->recurseTreeWithOperation(trueColorizeOperation);
-    qDebug("setting true color for %d nodes\n", _nodeCount);
+    qDebug("setting true color for %d nodes", _nodeCount);
     _tree->setDirtyBit();
     setupNewVoxelsForDrawing();
 }
@@ -1511,7 +1511,7 @@ bool VoxelSystem::falseColorizeInViewOperation(OctreeElement* element, void* ext
 void VoxelSystem::falseColorizeInView() {
     _nodeCount = 0;
     _tree->recurseTreeWithOperation(falseColorizeInViewOperation,(void*)_viewFrustum);
-    qDebug("setting in view false color for %d nodes\n", _nodeCount);
+    qDebug("setting in view false color for %d nodes", _nodeCount);
     _tree->setDirtyBit();
     setupNewVoxelsForDrawing();
 }
@@ -1594,13 +1594,13 @@ void VoxelSystem::falseColorizeBySource() {
     };
 
     // create a bunch of colors we'll use during colorization
-    NodeList* nodeList = NodeList::getInstance();
-    for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
+    
+    foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
         if (node->getType() == NODE_TYPE_VOXEL_SERVER) {
             uint16_t nodeID = VoxelTreeElement::getSourceNodeUUIDKey(node->getUUID());
             int groupColor = voxelServerCount % NUMBER_OF_COLOR_GROUPS;
             args.colors[nodeID] = groupColors[groupColor];
-
+            
             if (groupColors[groupColor].red > 0) {
                 groupColors[groupColor].red = ((groupColors[groupColor].red - MIN_COLOR)/2) + MIN_COLOR;
             }
@@ -1610,13 +1610,13 @@ void VoxelSystem::falseColorizeBySource() {
             if (groupColors[groupColor].blue > 0) {
                 groupColors[groupColor].blue = ((groupColors[groupColor].blue - MIN_COLOR)/2) + MIN_COLOR;
             }
-
+            
             voxelServerCount++;
         }
     }
 
     _tree->recurseTreeWithOperation(falseColorizeBySourceOperation, &args);
-    qDebug("setting false color by source for %d nodes\n", _nodeCount);
+    qDebug("setting false color by source for %d nodes", _nodeCount);
     _tree->setDirtyBit();
     setupNewVoxelsForDrawing();
 }
@@ -1669,10 +1669,10 @@ void VoxelSystem::falseColorizeDistanceFromView() {
     _maxDistance = 0.0;
     _minDistance = FLT_MAX;
     _tree->recurseTreeWithOperation(getDistanceFromViewRangeOperation, (void*) _viewFrustum);
-    qDebug("determining distance range for %d nodes\n", _nodeCount);
+    qDebug("determining distance range for %d nodes", _nodeCount);
     _nodeCount = 0;
     _tree->recurseTreeWithOperation(falseColorizeDistanceFromViewOperation, (void*) _viewFrustum);
-    qDebug("setting in distance false color for %d nodes\n", _nodeCount);
+    qDebug("setting in distance false color for %d nodes", _nodeCount);
     _tree->setDirtyBit();
     setupNewVoxelsForDrawing();
 }
@@ -1803,7 +1803,7 @@ void VoxelSystem::removeOutOfView() {
     }
     bool showRemoveDebugDetails = false;
     if (showRemoveDebugDetails) {
-        qDebug("removeOutOfView() scanned=%ld removed=%ld inside=%ld intersect=%ld outside=%ld _removedVoxels.count()=%d \n",
+        qDebug("removeOutOfView() scanned=%ld removed=%ld inside=%ld intersect=%ld outside=%ld _removedVoxels.count()=%d",
                 args.nodesScanned, args.nodesRemoved, args.nodesInside,
                 args.nodesIntersect, args.nodesOutside, _removedVoxels.count()
             );
@@ -1832,7 +1832,7 @@ void VoxelSystem::showAllLocalVoxels() {
 
     bool showRemoveDebugDetails = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
     if (showRemoveDebugDetails) {
-        qDebug("showAllLocalVoxels() scanned=%ld \n",args.nodesScanned );
+        qDebug("showAllLocalVoxels() scanned=%ld",args.nodesScanned );
     }
 }
 
@@ -1969,15 +1969,15 @@ void VoxelSystem::hideOutOfView(bool forceFullFrustum) {
 
     bool extraDebugDetails = false; // Application::getInstance()->getLogger()->extraDebugging();
     if (extraDebugDetails) {
-        qDebug("hideOutOfView() scanned=%ld removed=%ld show=%ld inside=%ld intersect=%ld outside=%ld\n",
+        qDebug("hideOutOfView() scanned=%ld removed=%ld show=%ld inside=%ld intersect=%ld outside=%ld",
                 args.nodesScanned, args.nodesRemoved, args.nodesShown, args.nodesInside,
                 args.nodesIntersect, args.nodesOutside
             );
-        qDebug("    inside/inside=%ld intersect/inside=%ld outside/outside=%ld\n",
+        qDebug("inside/inside=%ld intersect/inside=%ld outside/outside=%ld",
                 args.nodesInsideInside, args.nodesIntersectInside, args.nodesOutsideOutside
             );
 
-        qDebug() << "args.thisViewFrustum....\n";
+        qDebug() << "args.thisViewFrustum....";
         args.thisViewFrustum.printDebugDetails();
     }
     _inhideOutOfView = false;
@@ -2214,7 +2214,7 @@ bool VoxelSystem::falseColorizeRandomEveryOtherOperation(OctreeElement* element,
 void VoxelSystem::falseColorizeRandomEveryOther() {
     falseColorizeRandomEveryOtherArgs args;
     _tree->recurseTreeWithOperation(falseColorizeRandomEveryOtherOperation,&args);
-    qDebug("randomized false color for every other node: total %ld, colorable %ld, colored %ld\n",
+    qDebug("randomized false color for every other node: total %ld, colorable %ld, colored %ld",
         args.totalNodes, args.colorableNodes, args.coloredNodes);
     _tree->setDirtyBit();
     setupNewVoxelsForDrawing();
@@ -2284,14 +2284,14 @@ bool VoxelSystem::collectStatsForTreesAndVBOsOperation(OctreeElement* element, v
 
         const bool extraDebugging = false; // enable for extra debugging
         if (extraDebugging) {
-            qDebug("node In VBO... [%f,%f,%f] %f ... index=%ld, isDirty=%s, shouldRender=%s \n",
+            qDebug("node In VBO... [%f,%f,%f] %f ... index=%ld, isDirty=%s, shouldRender=%s",
                     voxel->getCorner().x, voxel->getCorner().y, voxel->getCorner().z, voxel->getScale(),
                     nodeIndex, debug::valueOf(voxel->isDirty()), debug::valueOf(voxel->getShouldRender()));
         }
 
         if (args->hasIndexFound[nodeIndex]) {
             args->duplicateVBOIndex++;
-            qDebug("duplicateVBO found... index=%ld, isDirty=%s, shouldRender=%s \n", nodeIndex,
+            qDebug("duplicateVBO found... index=%ld, isDirty=%s, shouldRender=%s", nodeIndex,
                     debug::valueOf(voxel->isDirty()), debug::valueOf(voxel->getShouldRender()));
         } else {
             args->hasIndexFound[nodeIndex] = true;
@@ -2325,17 +2325,17 @@ void VoxelSystem::collectStatsForTreesAndVBOs() {
     collectStatsForTreesAndVBOsArgs args(_maxVoxels);
     args.expectedMax = _voxelsInWriteArrays;
 
-    qDebug("CALCULATING Local Voxel Tree Statistics >>>>>>>>>>>>\n");
+    qDebug("CALCULATING Local Voxel Tree Statistics >>>>>>>>>>>>");
 
     _tree->recurseTreeWithOperation(collectStatsForTreesAndVBOsOperation,&args);
 
-    qDebug("Local Voxel Tree Statistics:\n total nodes %ld \n leaves %ld \n dirty %ld \n colored %ld \n shouldRender %ld \n",
+    qDebug("Local Voxel Tree Statistics:\n total nodes %ld \n leaves %ld \n dirty %ld \n colored %ld \n shouldRender %ld",
         args.totalNodes, args.leafNodes, args.dirtyNodes, args.coloredNodes, args.shouldRenderNodes);
 
-    qDebug(" _voxelsDirty=%s \n _voxelsInWriteArrays=%ld \n minDirty=%ld \n maxDirty=%ld \n", debug::valueOf(_voxelsDirty),
+    qDebug(" _voxelsDirty=%s \n _voxelsInWriteArrays=%ld \n minDirty=%ld \n maxDirty=%ld", debug::valueOf(_voxelsDirty),
         _voxelsInWriteArrays, minDirty, maxDirty);
 
-    qDebug(" inVBO %ld \n nodesInVBOOverExpectedMax %ld \n duplicateVBOIndex %ld \n nodesInVBONotShouldRender %ld \n",
+    qDebug(" inVBO %ld \n nodesInVBOOverExpectedMax %ld \n duplicateVBOIndex %ld \n nodesInVBONotShouldRender %ld",
         args.nodesInVBO, args.nodesInVBOOverExpectedMax, args.duplicateVBOIndex, args.nodesInVBONotShouldRender);
 
     glBufferIndex minInVBO = GLBUFFER_INDEX_UNKNOWN;
@@ -2348,13 +2348,13 @@ void VoxelSystem::collectStatsForTreesAndVBOs() {
         }
     }
 
-    qDebug(" minInVBO=%ld \n maxInVBO=%ld \n _voxelsInWriteArrays=%ld \n _voxelsInReadArrays=%ld \n",
+    qDebug(" minInVBO=%ld \n maxInVBO=%ld \n _voxelsInWriteArrays=%ld \n _voxelsInReadArrays=%ld",
             minInVBO, maxInVBO, _voxelsInWriteArrays, _voxelsInReadArrays);
 
-    qDebug(" _freeIndexes.size()=%ld \n",
+    qDebug(" _freeIndexes.size()=%ld",
             _freeIndexes.size());
 
-    qDebug("DONE WITH Local Voxel Tree Statistics >>>>>>>>>>>>\n");
+    qDebug("DONE WITH Local Voxel Tree Statistics >>>>>>>>>>>>");
 }
 
 
@@ -2534,7 +2534,7 @@ void VoxelSystem::falseColorizeOccluded() {
 
     _tree->recurseTreeWithOperationDistanceSorted(falseColorizeOccludedOperation, position, (void*)&args);
 
-    qDebug("falseColorizeOccluded()\n    position=(%f,%f)\n    total=%ld\n    colored=%ld\n    occluded=%ld\n    notOccluded=%ld\n    outOfView=%ld\n    subtreeVoxelsSkipped=%ld\n    nonLeaves=%ld\n    nonLeavesOutOfView=%ld\n    nonLeavesOccluded=%ld\n    pointInside_calls=%ld\n    occludes_calls=%ld\n intersects_calls=%ld\n",
+    qDebug("falseColorizeOccluded()\n    position=(%f,%f)\n    total=%ld\n    colored=%ld\n    occluded=%ld\n    notOccluded=%ld\n    outOfView=%ld\n    subtreeVoxelsSkipped=%ld\n    nonLeaves=%ld\n    nonLeavesOutOfView=%ld\n    nonLeavesOccluded=%ld\n    pointInside_calls=%ld\n    occludes_calls=%ld\n intersects_calls=%ld",
         position.x, position.y,
         args.totalVoxels, args.coloredVoxels, args.occludedVoxels,
         args.notOccludedVoxels, args.outOfView, args.subtreeVoxelsSkipped,
@@ -2667,9 +2667,9 @@ void VoxelSystem::falseColorizeOccludedV2() {
     setupNewVoxelsForDrawing();
 }
 
-void VoxelSystem::nodeAdded(Node* node) {
+void VoxelSystem::nodeAdded(SharedNodePointer node) {
     if (node->getType() == NODE_TYPE_VOXEL_SERVER) {
-        qDebug("VoxelSystem... voxel server %s added...\n", node->getUUID().toString().toLocal8Bit().constData());
+        qDebug("VoxelSystem... voxel server %s added...", node->getUUID().toString().toLocal8Bit().constData());
         _voxelServerCount++;
     }
 }
@@ -2688,11 +2688,11 @@ bool VoxelSystem::killSourceVoxelsOperation(OctreeElement* element, void* extraD
     return true;
 }
 
-void VoxelSystem::nodeKilled(Node* node) {
+void VoxelSystem::nodeKilled(SharedNodePointer node) {
     if (node->getType() == NODE_TYPE_VOXEL_SERVER) {
         _voxelServerCount--;
         QUuid nodeUUID = node->getUUID();
-        qDebug("VoxelSystem... voxel server %s removed...\n", nodeUUID.toString().toLocal8Bit().constData());
+        qDebug("VoxelSystem... voxel server %s removed...", nodeUUID.toString().toLocal8Bit().constData());
     }
 }
 
@@ -2761,7 +2761,7 @@ void VoxelSystem::unlockTree() {
 
 
 void VoxelSystem::localVoxelCacheLoaded() {
-    qDebug() << "localVoxelCacheLoaded()\n";
+    qDebug() << "localVoxelCacheLoaded()";
 
     // Make sure that the application has properly set up the view frustum for our loaded state
     Application::getInstance()->initAvatarAndViewFrustum();
@@ -2774,11 +2774,11 @@ void VoxelSystem::localVoxelCacheLoaded() {
 }
 
 void VoxelSystem::beginLoadingLocalVoxelCache() {
-    qDebug() << "beginLoadingLocalVoxelCache()\n";
+    qDebug() << "beginLoadingLocalVoxelCache()";
     _writeRenderFullVBO = true; // this will disable individual node updates
     _inhideOutOfView = true; // this will disable hidOutOfView which we want to do until local cache is loaded
     killLocalVoxels();
-    qDebug() << "DONE beginLoadingLocalVoxelCache()\n";
+    qDebug() << "DONE beginLoadingLocalVoxelCache()";
 }
 
 
diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h
index dff0c36bbc..728106a922 100644
--- a/interface/src/VoxelSystem.h
+++ b/interface/src/VoxelSystem.h
@@ -37,8 +37,7 @@ struct VoxelShaderVBOData
 };
 
 
-class VoxelSystem : public NodeData, public OctreeElementDeleteHook, public OctreeElementUpdateHook,
-                    public NodeListHook {
+class VoxelSystem : public NodeData, public OctreeElementDeleteHook, public OctreeElementUpdateHook {
     Q_OBJECT
 
     friend class VoxelHideShowThread;
@@ -110,8 +109,6 @@ public:
 
     virtual void elementDeleted(OctreeElement* element);
     virtual void elementUpdated(OctreeElement* element);
-    virtual void nodeAdded(Node* node);
-    virtual void nodeKilled(Node* node);
 
     bool treeIsBusy() const { return _treeIsBusy; }
 
@@ -122,6 +119,9 @@ signals:
     void importProgress(int progress);
 
 public slots:
+    void nodeAdded(SharedNodePointer node);
+    void nodeKilled(SharedNodePointer node);
+                        
     void collectStatsForTreesAndVBOs();
 
     // Methods that recurse tree
diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp
old mode 100755
new mode 100644
index e2a80e2f60..b9383474dd
--- a/interface/src/avatar/Avatar.cpp
+++ b/interface/src/avatar/Avatar.cpp
@@ -95,7 +95,6 @@ Avatar::Avatar(Node* owningNode) :
     _mouseRayOrigin(0.0f, 0.0f, 0.0f),
     _mouseRayDirection(0.0f, 0.0f, 0.0f),
     _isCollisionsOn(true),
-    _leadingAvatar(NULL),
     _moving(false),
     _initialized(false),
     _handHoldingPosition(0.0f, 0.0f, 0.0f),
@@ -146,27 +145,7 @@ glm::quat Avatar::getWorldAlignedOrientation () const {
     return computeRotationFromBodyToWorldUp() * getOrientation();
 }
 
-void Avatar::follow(Avatar* leadingAvatar) {
-    const float MAX_STRING_LENGTH = 2;
-
-    _leadingAvatar = leadingAvatar;
-    if (_leadingAvatar != NULL) {
-        _leaderUUID = leadingAvatar->getOwningNode()->getUUID();
-        _stringLength = glm::length(_position - _leadingAvatar->getPosition()) / _scale;
-        if (_stringLength > MAX_STRING_LENGTH) {
-            _stringLength = MAX_STRING_LENGTH;
-        }
-    } else {
-        _leaderUUID = QUuid();
-    }
-}
-
 void Avatar::simulate(float deltaTime, Transmitter* transmitter) {
-    
-    if (_leadingAvatar && !_leadingAvatar->getOwningNode()->isAlive()) {
-        follow(NULL);
-    }
-    
     if (_scale != _targetScale) {
         setScale(_targetScale);
     }
@@ -434,27 +413,27 @@ void Avatar::renderJointConnectingCone(glm::vec3 position1, glm::vec3 position2,
 }
 
 void Avatar::goHome() {
-    qDebug("Going Home!\n");
+    qDebug("Going Home!");
     setPosition(START_LOCATION);
 }
 
 void Avatar::increaseSize() {
     if ((1.f + SCALING_RATIO) * _targetScale < MAX_AVATAR_SCALE) {
         _targetScale *= (1.f + SCALING_RATIO);
-        qDebug("Changed scale to %f\n", _targetScale);
+        qDebug("Changed scale to %f", _targetScale);
     }
 }
 
 void Avatar::decreaseSize() {
     if (MIN_AVATAR_SCALE < (1.f - SCALING_RATIO) * _targetScale) {
         _targetScale *= (1.f - SCALING_RATIO);
-        qDebug("Changed scale to %f\n", _targetScale);
+        qDebug("Changed scale to %f", _targetScale);
     }
 }
 
 void Avatar::resetSize() {
     _targetScale = 1.0f;
-    qDebug("Reseted scale to %f\n", _targetScale);
+    qDebug("Reseted scale to %f", _targetScale);
 }
 
 void Avatar::setScale(const float scale) {
diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h
index c750b69647..da93ff6761 100755
--- a/interface/src/avatar/Avatar.h
+++ b/interface/src/avatar/Avatar.h
@@ -21,7 +21,6 @@
 #include "Skeleton.h"
 #include "SkeletonModel.h"
 #include "world.h"
-#include "devices/SerialInterface.h"
 #include "devices/Transmitter.h"
 
 static const float SCALING_RATIO = .05f;
@@ -135,7 +134,6 @@ public:
 
     void init();
     void simulate(float deltaTime, Transmitter* transmitter);
-    void follow(Avatar* leadingAvatar);
     void render(bool forceRenderHead);
 
     //setters
@@ -217,7 +215,6 @@ protected:
     glm::vec3 _mouseRayOrigin;
     glm::vec3 _mouseRayDirection;
     bool _isCollisionsOn;
-    Avatar* _leadingAvatar;
     float _stringLength;
 
     bool _moving; ///< set when position is changing
diff --git a/interface/src/avatar/FaceModel.cpp b/interface/src/avatar/FaceModel.cpp
index ebcb8cfa34..f2115810c4 100644
--- a/interface/src/avatar/FaceModel.cpp
+++ b/interface/src/avatar/FaceModel.cpp
@@ -60,7 +60,7 @@ bool FaceModel::render(float alpha) {
 void FaceModel::maybeUpdateNeckRotation(const JointState& parentState, const FBXJoint& joint, JointState& state) {
     // get the rotation axes in joint space and use them to adjust the rotation
     glm::mat3 axes = glm::mat3_cast(_rotation);
-    glm::mat3 inverse = glm::mat3(glm::inverse(parentState.transform *
+    glm::mat3 inverse = glm::mat3(glm::inverse(parentState.transform * glm::translate(state.translation) *
         joint.preTransform * glm::mat4_cast(joint.preRotation)));
     state.rotation = glm::angleAxis(-_owningHead->getRoll(), glm::normalize(inverse * axes[2])) *
         glm::angleAxis(_owningHead->getYaw(), glm::normalize(inverse * axes[1])) *
diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp
index 5f85885c1e..ef6b97d6cd 100644
--- a/interface/src/avatar/Hand.cpp
+++ b/interface/src/avatar/Hand.cpp
@@ -368,8 +368,7 @@ void Hand::updateCollisions() {
         glm::vec3 totalPenetration;
         
         // check other avatars
-        NodeList* nodeList = NodeList::getInstance();
-        for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
+        foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
             if (node->getLinkedData() && node->getType() == NODE_TYPE_AGENT) {
                 Avatar* otherAvatar = (Avatar*)node->getLinkedData();
                 if (Menu::getInstance()->isOptionChecked(MenuOption::PlaySlaps)) {
@@ -388,21 +387,21 @@ void Hand::updateCollisions() {
                         if (glm::length(otherPalmPosition - myPalmPosition) < palmCollisionDistance) {
                             palm.setIsCollidingWithPalm(true);
                             if (!wasColliding) {
-                            const float PALM_COLLIDE_VOLUME = 1.f;
-                            const float PALM_COLLIDE_FREQUENCY = 1000.f;
-                            const float PALM_COLLIDE_DURATION_MAX = 0.75f;
-                            const float PALM_COLLIDE_DECAY_PER_SAMPLE = 0.01f;
-                            Application::getInstance()->getAudio()->startDrumSound(PALM_COLLIDE_VOLUME,
-                                                                                   PALM_COLLIDE_FREQUENCY,
-                                                                                   PALM_COLLIDE_DURATION_MAX,
-                                                                                   PALM_COLLIDE_DECAY_PER_SAMPLE);
-                            //  If the other person's palm is in motion, move mine downward to show I was hit
-                            const float MIN_VELOCITY_FOR_SLAP = 0.05f;
+                                const float PALM_COLLIDE_VOLUME = 1.f;
+                                const float PALM_COLLIDE_FREQUENCY = 1000.f;
+                                const float PALM_COLLIDE_DURATION_MAX = 0.75f;
+                                const float PALM_COLLIDE_DECAY_PER_SAMPLE = 0.01f;
+                                Application::getInstance()->getAudio()->startDrumSound(PALM_COLLIDE_VOLUME,
+                                                                                       PALM_COLLIDE_FREQUENCY,
+                                                                                       PALM_COLLIDE_DURATION_MAX,
+                                                                                       PALM_COLLIDE_DECAY_PER_SAMPLE);
+                                //  If the other person's palm is in motion, move mine downward to show I was hit
+                                const float MIN_VELOCITY_FOR_SLAP = 0.05f;
                                 if (glm::length(otherPalm.getVelocity()) > MIN_VELOCITY_FOR_SLAP) {
                                     // add slapback here
                                 }
                             }
-
+                            
                             
                         }
                     }
diff --git a/interface/src/avatar/Hand.h b/interface/src/avatar/Hand.h
index 8c368a4c37..8a672fc1d9 100755
--- a/interface/src/avatar/Hand.h
+++ b/interface/src/avatar/Hand.h
@@ -24,7 +24,6 @@
 #include "BuckyBalls.h"
 #include "InterfaceConfig.h"
 #include "world.h"
-#include "devices/SerialInterface.h"
 #include "VoxelSystem.h"
 
 
diff --git a/interface/src/avatar/Head.h b/interface/src/avatar/Head.h
index 55c3dffc50..6d0f69d8ed 100644
--- a/interface/src/avatar/Head.h
+++ b/interface/src/avatar/Head.h
@@ -21,7 +21,6 @@
 #include "InterfaceConfig.h"
 #include "VideoFace.h"
 #include "world.h"
-#include "devices/SerialInterface.h"
 #include "renderer/TextureCache.h"
 
 enum eyeContactTargets {
diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp
index ca9a6a9476..10a30abfa2 100644
--- a/interface/src/avatar/MyAvatar.cpp
+++ b/interface/src/avatar/MyAvatar.cpp
@@ -88,15 +88,6 @@ void MyAvatar::simulate(float deltaTime, Transmitter* transmitter) {
         _elapsedTimeMoving += deltaTime;
     }
 
-    if (_leadingAvatar && !_leadingAvatar->getOwningNode()->isAlive()) {
-        follow(NULL);
-    }
-
-    // Ajust, scale, position and lookAt position when following an other avatar
-    if (_leadingAvatar && _targetScale != _leadingAvatar->getScale()) {
-        _targetScale = _leadingAvatar->getScale();
-    }
-
     if (_scale != _targetScale) {
         float scale = (1.f - SMOOTHING_RATIO) * _scale + SMOOTHING_RATIO * _targetScale;
         setScale(scale);
@@ -300,7 +291,6 @@ const float MAX_PITCH = 90.0f;
 //  Update avatar head rotation with sensor data
 void MyAvatar::updateFromGyrosAndOrWebcam(bool turnWithHead) {
     Faceshift* faceshift = Application::getInstance()->getFaceshift();
-    SerialInterface* gyros = Application::getInstance()->getSerialHeadSensor();
     Webcam* webcam = Application::getInstance()->getWebcam();
     glm::vec3 estimatedPosition, estimatedRotation;
 
@@ -321,16 +311,11 @@ void MyAvatar::updateFromGyrosAndOrWebcam(bool turnWithHead) {
                 }
             }
         }
-    } else if (gyros->isActive()) {
-        estimatedRotation = gyros->getEstimatedRotation();
-
     } else if (webcam->isActive()) {
         estimatedRotation = webcam->getEstimatedRotation();
 
     } else {
-        if (!_leadingAvatar) {
-            _head.setPitch(_head.getMousePitch());
-        }
+        _head.setPitch(_head.getMousePitch());
         _head.getVideoFace().clearFrame();
 
         // restore rotation, lean to neutral positions
@@ -634,47 +619,6 @@ void MyAvatar::updateThrust(float deltaTime, Transmitter * transmitter) {
         _shouldJump = false;
     }
 
-
-    // Add thrusts from leading avatar
-    const float FOLLOWING_RATE = 0.02f;
-    const float MIN_YAW = 5.0f;
-    const float MIN_PITCH = 1.0f;
-    const float PITCH_RATE = 0.1f;
-    const float MIN_YAW_BEFORE_PITCH = 30.0f;
-
-    if (_leadingAvatar != NULL) {
-        glm::vec3 toTarget = _leadingAvatar->getPosition() - _position;
-
-        if (glm::length(_position - _leadingAvatar->getPosition()) > _scale * _stringLength) {
-            _position += toTarget * FOLLOWING_RATE;
-        } else {
-            toTarget = _leadingAvatar->getHead().getLookAtPosition() - _head.getPosition();
-        }
-        toTarget = glm::vec3(glm::dot(right, toTarget),
-                             glm::dot(up   , toTarget),
-                             glm::dot(front, toTarget));
-
-        float yawAngle = angleBetween(-IDENTITY_FRONT, glm::vec3(toTarget.x, 0.f, toTarget.z));
-        if (glm::abs(yawAngle) > MIN_YAW){
-            if (IDENTITY_RIGHT.x * toTarget.x + IDENTITY_RIGHT.y * toTarget.y + IDENTITY_RIGHT.z * toTarget.z > 0) {
-                _bodyYawDelta -= yawAngle;
-            } else {
-                _bodyYawDelta += yawAngle;
-            }
-        }
-
-        float pitchAngle = glm::abs(90.0f - angleBetween(IDENTITY_UP, toTarget));
-        if (glm::abs(pitchAngle) > MIN_PITCH && yawAngle < MIN_YAW_BEFORE_PITCH){
-            if (IDENTITY_UP.x * toTarget.x + IDENTITY_UP.y * toTarget.y + IDENTITY_UP.z * toTarget.z > 0) {
-                _head.setMousePitch(_head.getMousePitch() + PITCH_RATE * pitchAngle);
-            } else {
-                _head.setMousePitch(_head.getMousePitch() - PITCH_RATE * pitchAngle);
-            }
-            _head.setPitch(_head.getMousePitch());
-        }
-    }
-
-
     //  Add thrusts from Transmitter
     if (transmitter) {
         transmitter->checkForLostTransmitter();
@@ -872,16 +816,7 @@ void MyAvatar::updateAvatarCollisions(float deltaTime) {
 
     //  Reset detector for nearest avatar
     _distanceToNearestAvatar = std::numeric_limits<float>::max();
-
-    // loop through all the other avatars for potential interactions...
-    NodeList* nodeList = NodeList::getInstance();
-    for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
-        if (node->getLinkedData() && node->getType() == NODE_TYPE_AGENT) {
-            //Avatar *otherAvatar = (Avatar *)node->getLinkedData();
-            //
-            // Placeholder:  Add code here when we want to add Avatar<->Avatar collision stuff
-        }
-    }
+    // loop through all the other avatars for potential interactions
 }
 
 class SortedAvatar {
@@ -902,8 +837,8 @@ void MyAvatar::updateChatCircle(float deltaTime) {
 
     // find all circle-enabled members and sort by distance
     QVector<SortedAvatar> sortedAvatars;
-    NodeList* nodeList = NodeList::getInstance();
-    for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
+    
+    foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
         if (node->getLinkedData() && node->getType() == NODE_TYPE_AGENT) {
             SortedAvatar sortedAvatar;
             sortedAvatar.avatar = (Avatar*)node->getLinkedData();
@@ -914,6 +849,7 @@ void MyAvatar::updateChatCircle(float deltaTime) {
             sortedAvatars.append(sortedAvatar);
         }
     }
+    
     qSort(sortedAvatars.begin(), sortedAvatars.end());
 
     // compute the accumulated centers
diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h
index 99cc360d59..474c212623 100644
--- a/interface/src/avatar/MyAvatar.h
+++ b/interface/src/avatar/MyAvatar.h
@@ -51,7 +51,6 @@ public:
     float getAbsoluteHeadYaw() const;
     const glm::vec3& getMouseRayOrigin() const { return _mouseRayOrigin; }
     const glm::vec3& getMouseRayDirection() const { return _mouseRayDirection; }
-    Avatar* getLeadingAvatar() const { return _leadingAvatar; }
     glm::vec3 getGravity() const { return _gravity; }
     glm::vec3 getUprightHeadPosition() const;
     glm::vec3 getEyeLevelPosition() const;
diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp
index 7ef2f54fde..50b6c4f072 100644
--- a/interface/src/avatar/SkeletonModel.cpp
+++ b/interface/src/avatar/SkeletonModel.cpp
@@ -154,7 +154,6 @@ void SkeletonModel::applyPalmData(int jointIndex, const QVector<int>& fingerJoin
         return;
     }
     const FBXGeometry& geometry = _geometry->getFBXGeometry();
-    setJointPosition(jointIndex, palm.getPosition());
     float sign = (jointIndex == geometry.rightHandJointIndex) ? 1.0f : -1.0f;
     glm::quat palmRotation;
     getJointRotation(jointIndex, palmRotation, true);
@@ -186,6 +185,7 @@ void SkeletonModel::applyPalmData(int jointIndex, const QVector<int>& fingerJoin
 
     // no point in continuing if there are no fingers
     if (palm.getNumFingers() == 0 || fingerJointIndices.isEmpty()) {
+        stretchArm(jointIndex, palm.getPosition());
         return;
     }
 
@@ -203,6 +203,8 @@ void SkeletonModel::applyPalmData(int jointIndex, const QVector<int>& fingerJoin
 
         setJointRotation(fingerJointIndex, rotationBetween(palmRotation * jointVector, fingerVector) * palmRotation, true);
     }
+    
+    stretchArm(jointIndex, palm.getPosition());
 }
 
 void SkeletonModel::updateJointState(int index) {
@@ -219,9 +221,47 @@ void SkeletonModel::updateJointState(int index) {
 void SkeletonModel::maybeUpdateLeanRotation(const JointState& parentState, const FBXJoint& joint, JointState& state) {
     // get the rotation axes in joint space and use them to adjust the rotation
     glm::mat3 axes = glm::mat3_cast(_rotation);
-    glm::mat3 inverse = glm::mat3(glm::inverse(parentState.transform *
+    glm::mat3 inverse = glm::mat3(glm::inverse(parentState.transform * glm::translate(state.translation) * 
         joint.preTransform * glm::mat4_cast(joint.preRotation * joint.rotation)));
     state.rotation = glm::angleAxis(-_owningAvatar->getHead().getLeanSideways(), glm::normalize(inverse * axes[2])) *
         glm::angleAxis(-_owningAvatar->getHead().getLeanForward(), glm::normalize(inverse * axes[0])) * joint.rotation;
 }
 
+void SkeletonModel::stretchArm(int jointIndex, const glm::vec3& position) {
+    // find out where the hand is pointing
+    glm::quat handRotation;
+    getJointRotation(jointIndex, handRotation, true);
+    const FBXGeometry& geometry = _geometry->getFBXGeometry();
+    glm::vec3 forwardVector(jointIndex == geometry.rightHandJointIndex ? -1.0f : 1.0f, 0.0f, 0.0f);
+    glm::vec3 handVector = handRotation * forwardVector;
+    
+    // align elbow with hand
+    const FBXJoint& joint = geometry.joints.at(jointIndex);
+    if (joint.parentIndex == -1) {
+        return;
+    }
+    glm::quat elbowRotation;
+    getJointRotation(joint.parentIndex, elbowRotation, true);
+    applyRotationDelta(joint.parentIndex, rotationBetween(elbowRotation * forwardVector, handVector), false);
+    
+    // set position according to normal length
+    float scale = extractUniformScale(_scale);
+    glm::vec3 handPosition = position - _translation;
+    glm::vec3 elbowPosition = handPosition - handVector * joint.distanceToParent * scale;
+    
+    // set shoulder orientation to point to elbow
+    const FBXJoint& parentJoint = geometry.joints.at(joint.parentIndex);
+    if (parentJoint.parentIndex == -1) {
+        return;
+    }
+    glm::quat shoulderRotation;
+    getJointRotation(parentJoint.parentIndex, shoulderRotation, true);
+    applyRotationDelta(parentJoint.parentIndex, rotationBetween(shoulderRotation * forwardVector,
+        elbowPosition - extractTranslation(_jointStates.at(parentJoint.parentIndex).transform)), false);
+        
+    // update the shoulder state
+    updateJointState(parentJoint.parentIndex);
+    
+    // adjust the elbow's local translation
+    setJointTranslation(joint.parentIndex, elbowPosition);
+}
diff --git a/interface/src/avatar/SkeletonModel.h b/interface/src/avatar/SkeletonModel.h
index caf08c823b..776eb29e3b 100644
--- a/interface/src/avatar/SkeletonModel.h
+++ b/interface/src/avatar/SkeletonModel.h
@@ -40,6 +40,10 @@ protected:
     
 private:
     
+    /// Using the current position and rotation of the identified (hand) joint, computes a
+    /// reasonable stretched configuration for the connected arm.
+    void stretchArm(int jointIndex, const glm::vec3& position);
+    
     Avatar* _owningAvatar;
 };
 
diff --git a/interface/src/devices/Faceshift.cpp b/interface/src/devices/Faceshift.cpp
index 6e895c96b6..437a3268d2 100644
--- a/interface/src/devices/Faceshift.cpp
+++ b/interface/src/devices/Faceshift.cpp
@@ -116,7 +116,7 @@ void Faceshift::setTCPEnabled(bool enabled) {
 void Faceshift::connectSocket() {
     if (_tcpEnabled) {
         if (!_tcpRetryCount) {
-            qDebug("Faceshift: Connecting...\n");
+            qDebug("Faceshift: Connecting...");
         }
 
         _tcpSocket.connectToHost("localhost", FACESHIFT_PORT);
@@ -125,8 +125,7 @@ void Faceshift::connectSocket() {
 }
 
 void Faceshift::noteConnected() {
-    qDebug("Faceshift: Connected.\n");
-
+    qDebug("Faceshift: Connected.");
     // request the list of blendshape names
     string message;
     fsBinaryStream::encode_message(message, fsMsgSendBlendshapeNames());
@@ -136,7 +135,7 @@ void Faceshift::noteConnected() {
 void Faceshift::noteError(QAbstractSocket::SocketError error) {
     if (!_tcpRetryCount) {
        // Only spam log with fail to connect the first time, so that we can keep waiting for server
-       qDebug() << "Faceshift: " << _tcpSocket.errorString() << "\n";
+       qDebug() << "Faceshift: " << _tcpSocket.errorString();
     }
     // retry connection after a 2 second delay
     if (_tcpEnabled) {
diff --git a/interface/src/devices/SerialInterface.cpp b/interface/src/devices/SerialInterface.cpp
deleted file mode 100644
index 0fdb48e4a8..0000000000
--- a/interface/src/devices/SerialInterface.cpp
+++ /dev/null
@@ -1,422 +0,0 @@
-//
-//  SerialInterface.cpp
-//  2012 by Philip Rosedale for High Fidelity Inc.
-//
-//  Read interface data from the gyros/accelerometer Invensense board using the SerialUSB
-//
-
-#ifndef _WIN32
-#include <regex.h>
-#include <sys/time.h>
-#include <string>
-#endif
-
-#include <math.h>
-
-#include <glm/gtx/vector_angle.hpp>
-
-extern "C" {
-    #include <inv_tty.h>
-    #include <inv_mpu.h>
-}
-
-#include <SharedUtil.h>
-
-#include "Application.h"
-#include "SerialInterface.h"
-#include "Util.h"
-#include "Webcam.h"
-
-const short NO_READ_MAXIMUM_MSECS = 3000;
-const int GRAVITY_SAMPLES = 60;                     //  Use the first few samples to baseline values
-const int NORTH_SAMPLES = 30;
-const int ACCELERATION_SENSOR_FUSION_SAMPLES = 20;
-const int COMPASS_SENSOR_FUSION_SAMPLES = 100;
-const int LONG_TERM_RATE_SAMPLES = 1000;            
-
-const bool USING_INVENSENSE_MPU9150 = 1;
-
-SerialInterface::SerialInterface() :
-    _active(false),
-    _gravity(0, 0, 0),
-    _averageRotationRates(0, 0, 0),
-    _averageAcceleration(0, 0, 0),
-    _estimatedRotation(0, 0, 0),
-    _estimatedPosition(0, 0, 0),
-    _estimatedVelocity(0, 0, 0),
-    _lastAcceleration(0, 0, 0),
-    _lastRotationRates(0, 0, 0),
-    _compassMinima(-211, -132, -186),
-    _compassMaxima(89, 95, 98),
-    _angularVelocityToLinearAccel(0.003f, -0.001f, -0.006f,
-                                  -0.005f, -0.001f, -0.006f,
-                                  0.010f, 0.004f, 0.007f),
-    _angularAccelToLinearAccel(0.0f, 0.0f, 0.002f,
-                               0.0f, 0.0f, 0.001f,
-                               -0.002f, -0.002f, 0.0f)
-{
-
-}
-
-void SerialInterface::pair() {
-    
-#ifndef _WIN32
-    // look for a matching gyro setup
-    DIR *devDir;
-    struct dirent *entry;
-    int matchStatus;
-    regex_t regex;
-    
-    // for now this only works on OS X, where the usb serial shows up as /dev/tty.usb*,
-    // and (possibly just Ubuntu) Linux, where it shows up as /dev/ttyACM*
-    if((devDir = opendir("/dev"))) {
-        while((entry = readdir(devDir))) {
-#ifdef __APPLE__
-            regcomp(&regex, "tty\\.usb", REG_EXTENDED|REG_NOSUB);
-#else
-            regcomp(&regex, "ttyACM", REG_EXTENDED|REG_NOSUB);
-#endif
-            matchStatus = regexec(&regex, entry->d_name, (size_t) 0, NULL, 0);
-            if (matchStatus == 0) {
-                char *serialPortname = new char[100];
-                sprintf(serialPortname, "/dev/%s", entry->d_name);
-                
-                initializePort(serialPortname);
-                
-                delete [] serialPortname;
-            }
-            regfree(&regex);
-        }
-        closedir(devDir);
-    }    
-#endif
-}
-
-//  connect to the serial port
-void SerialInterface::initializePort(char* portname) {
-#ifndef _WIN32
-    _serialDescriptor = open(portname, O_RDWR | O_NOCTTY | O_NDELAY);
-    
-    qDebug("Opening SerialUSB %s: ", portname);
-    
-    if (_serialDescriptor == -1) {
-        qDebug("Failed.\n");
-        return;
-    }
-    
-    struct termios options;
-    tcgetattr(_serialDescriptor, &options);
-        
-    options.c_cflag |= (CLOCAL | CREAD | CS8);
-    options.c_cflag &= ~PARENB;
-    options.c_cflag &= ~CSTOPB;
-    options.c_cflag &= ~CSIZE;
-    tcsetattr(_serialDescriptor, TCSANOW, &options);
-    
-    cfsetispeed(&options,B115200);
-    cfsetospeed(&options,B115200);
-    
-    if (USING_INVENSENSE_MPU9150) {
-        // block on invensense reads until there is data to read
-        int currentFlags = fcntl(_serialDescriptor, F_GETFL);
-        fcntl(_serialDescriptor, F_SETFL, currentFlags & ~O_NONBLOCK);
-        
-        // make sure there's nothing queued up to be read
-        tcflush(_serialDescriptor, TCIOFLUSH);
-        
-        // this disables streaming so there's no garbage data on reads
-        if (write(_serialDescriptor, "SD\n", 3) != 3) {
-            qDebug("Failed.\n");
-            return;
-        }
-        char result[4];
-        if (read(_serialDescriptor, result, 4) != 4) {
-            qDebug("Failed.\n");
-            return;
-        }
-        
-        tty_set_file_descriptor(_serialDescriptor);
-        mpu_init(0);
-        mpu_set_sensors(INV_XYZ_GYRO | INV_XYZ_ACCEL | INV_XYZ_COMPASS);
-    }
-    
-    qDebug("Connected.\n");
-    resetSerial();
-    
-    _active = true;
- #endif
-}
-
-//  Render the serial interface channel values onscreen as vertical lines
-void SerialInterface::renderLevels(int width, int height) {
-    char val[40];
-    if (USING_INVENSENSE_MPU9150) {
-        //  For invensense gyros, render as horizontal bars
-        const int LEVEL_CORNER_X = 10;
-        const int LEVEL_CORNER_Y = 200;
-        
-        // Draw the numeric degree/sec values from the gyros
-        sprintf(val, "Yaw    %4.1f", _estimatedRotation.y);
-        drawtext(LEVEL_CORNER_X, LEVEL_CORNER_Y, 0.10f, 0, 1.0f, 1, val, 0, 1, 0);
-        sprintf(val, "Pitch %4.1f", _estimatedRotation.x);
-        drawtext(LEVEL_CORNER_X, LEVEL_CORNER_Y + 15, 0.10f, 0, 1.0f, 1, val, 0, 1, 0);
-        sprintf(val, "Roll  %4.1f", _estimatedRotation.z);
-        drawtext(LEVEL_CORNER_X, LEVEL_CORNER_Y + 30, 0.10f, 0, 1.0f, 1, val, 0, 1, 0);
-        sprintf(val, "X     %4.3f", _lastAcceleration.x - _gravity.x);
-        drawtext(LEVEL_CORNER_X, LEVEL_CORNER_Y + 45, 0.10f, 0, 1.0f, 1, val, 0, 1, 0);
-        sprintf(val, "Y     %4.3f", _lastAcceleration.y - _gravity.y);
-        drawtext(LEVEL_CORNER_X, LEVEL_CORNER_Y + 60, 0.10f, 0, 1.0f, 1, val, 0, 1, 0);
-        sprintf(val, "Z     %4.3f", _lastAcceleration.z - _gravity.z);
-        drawtext(LEVEL_CORNER_X, LEVEL_CORNER_Y + 75, 0.10f, 0, 1.0f, 1, val, 0, 1, 0);
-        
-        //  Draw the levels as horizontal lines        
-        const int LEVEL_CENTER = 150;
-        const float ACCEL_VIEW_SCALING = 10.f;
-        const float POSITION_SCALING = 400.f;
-
-        glLineWidth(2.0);
-        glBegin(GL_LINES);
-        // Rotation rates
-        glColor4f(1, 1, 1, 1);
-        glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y - 3);
-        glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER + getLastYawRate(), LEVEL_CORNER_Y - 3);
-        glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y + 12);
-        glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER + getLastPitchRate(), LEVEL_CORNER_Y + 12);
-        glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y + 27);
-        glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER + getLastRollRate(), LEVEL_CORNER_Y + 27);
-        // Estimated Rotation
-        glColor4f(0, 1, 1, 1);
-        glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y - 1);
-        glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER + _estimatedRotation.y, LEVEL_CORNER_Y - 1);
-        glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y + 14);
-        glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER + _estimatedRotation.x, LEVEL_CORNER_Y + 14);
-        glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y + 29);
-        glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER + _estimatedRotation.z, LEVEL_CORNER_Y + 29);
-
-        // Acceleration rates
-        glColor4f(1, 1, 1, 1);
-        glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y + 42);
-        glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER + (int)(_estimatedAcceleration.x * ACCEL_VIEW_SCALING), LEVEL_CORNER_Y + 42);
-        glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y + 57);
-        glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER + (int)(_estimatedAcceleration.y * ACCEL_VIEW_SCALING), LEVEL_CORNER_Y + 57);
-        glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y + 72);
-        glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER + (int)(_estimatedAcceleration.z * ACCEL_VIEW_SCALING), LEVEL_CORNER_Y + 72);
-        
-        // Estimated Position
-        glColor4f(0, 1, 1, 1);
-        glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y + 44);
-        glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER + (int)(_estimatedPosition.x * POSITION_SCALING), LEVEL_CORNER_Y + 44);
-        glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y + 59);
-        glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER + (int)(_estimatedPosition.y * POSITION_SCALING), LEVEL_CORNER_Y + 59);
-        glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y + 74);
-        glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER + (int)(_estimatedPosition.z * POSITION_SCALING), LEVEL_CORNER_Y + 74);
-
-
-        glEnd();
-        //  Draw green vertical centerline
-        glColor4f(0, 1, 0, 0.5);
-        glBegin(GL_LINES);
-        glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y - 6);
-        glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y + 30);
-        glEnd();
-    }
-}
-
-void SerialInterface::readData(float deltaTime) {
-#ifndef _WIN32
-    
-    int initialSamples = totalSamples;
-    
-    if (USING_INVENSENSE_MPU9150) { 
-
-        // ask the invensense for raw gyro data
-        short accelData[3];
-        if (mpu_get_accel_reg(accelData, 0)) {
-            close(_serialDescriptor);
-            qDebug("Disconnected SerialUSB.\n");
-            _active = false;
-            return; // disconnected
-        }
-        
-        const float LSB_TO_METERS_PER_SECOND2 = 1.f / 16384.f * GRAVITY_EARTH;
-                                                                //  From MPU-9150 register map, with setting on
-                                                                //  highest resolution = +/- 2G
-        
-        _lastAcceleration = glm::vec3(-accelData[2], -accelData[1], -accelData[0]) * LSB_TO_METERS_PER_SECOND2;
-          
-        short gyroData[3];
-        mpu_get_gyro_reg(gyroData, 0);
-        
-        //  Convert the integer rates to floats
-        const float LSB_TO_DEGREES_PER_SECOND = 1.f / 16.4f;     //  From MPU-9150 register map, 2000 deg/sec.
-        glm::vec3 rotationRates;
-        rotationRates[0] = ((float) -gyroData[2]) * LSB_TO_DEGREES_PER_SECOND;
-        rotationRates[1] = ((float) -gyroData[1]) * LSB_TO_DEGREES_PER_SECOND;
-        rotationRates[2] = ((float) -gyroData[0]) * LSB_TO_DEGREES_PER_SECOND;
-      
-        short compassData[3];
-        mpu_get_compass_reg(compassData, 0);
-      
-        // Convert integer values to floats, update extents
-        _lastCompass = glm::vec3(compassData[2], -compassData[0], -compassData[1]);
-        
-        // update and subtract the long term average
-        _averageRotationRates = (1.f - 1.f/(float)LONG_TERM_RATE_SAMPLES) * _averageRotationRates +
-                1.f/(float)LONG_TERM_RATE_SAMPLES * rotationRates;
-        rotationRates -= _averageRotationRates;
-
-        // compute the angular acceleration
-        glm::vec3 angularAcceleration = (deltaTime < EPSILON) ? glm::vec3() : (rotationRates - _lastRotationRates) / deltaTime;
-        _lastRotationRates = rotationRates;
-        
-        //  Update raw rotation estimates
-        glm::quat estimatedRotation = glm::quat(glm::radians(_estimatedRotation)) *
-            glm::quat(glm::radians(deltaTime * _lastRotationRates));
-        
-        //  Update acceleration estimate: first, subtract gravity as rotated into current frame
-        _estimatedAcceleration = (totalSamples < GRAVITY_SAMPLES) ? glm::vec3() :
-            _lastAcceleration - glm::inverse(estimatedRotation) * _gravity;
-        
-        // update and subtract the long term average
-        _averageAcceleration = (1.f - 1.f/(float)LONG_TERM_RATE_SAMPLES) * _averageAcceleration +
-                1.f/(float)LONG_TERM_RATE_SAMPLES * _estimatedAcceleration;
-        _estimatedAcceleration -= _averageAcceleration;
-        
-        //  Consider updating our angular velocity/acceleration to linear acceleration mapping
-        if (glm::length(_estimatedAcceleration) > EPSILON &&
-                (glm::length(_lastRotationRates) > EPSILON || glm::length(angularAcceleration) > EPSILON)) {
-            // compute predicted linear acceleration, find error between actual and predicted
-            glm::vec3 predictedAcceleration = _angularVelocityToLinearAccel * _lastRotationRates +
-                _angularAccelToLinearAccel * angularAcceleration;
-            glm::vec3 error = _estimatedAcceleration - predictedAcceleration;
-            
-            // the "error" is actually what we want: the linear acceleration minus rotational influences
-            _estimatedAcceleration = error;
-            
-            // adjust according to error in each dimension, in proportion to input magnitudes
-            for (int i = 0; i < 3; i++) {
-                if (fabsf(error[i]) < EPSILON) {
-                    continue;
-                }
-                const float LEARNING_RATE = 0.001f;
-                float rateSum = fabsf(_lastRotationRates.x) + fabsf(_lastRotationRates.y) + fabsf(_lastRotationRates.z);
-                if (rateSum > EPSILON) {
-                    for (int j = 0; j < 3; j++) {
-                        float proportion = LEARNING_RATE * fabsf(_lastRotationRates[j]) / rateSum;
-                        if (proportion > EPSILON) {
-                            _angularVelocityToLinearAccel[j][i] += error[i] * proportion / _lastRotationRates[j];
-                        }
-                    }
-                }
-                float accelSum = fabsf(angularAcceleration.x) + fabsf(angularAcceleration.y) + fabsf(angularAcceleration.z);
-                if (accelSum > EPSILON) {
-                    for (int j = 0; j < 3; j++) {
-                        float proportion = LEARNING_RATE * fabsf(angularAcceleration[j]) / accelSum;
-                        if (proportion > EPSILON) {
-                            _angularAccelToLinearAccel[j][i] += error[i] * proportion / angularAcceleration[j];
-                        }
-                    }                
-                }
-            }
-        }
-        
-        // rotate estimated acceleration into global rotation frame
-        _estimatedAcceleration = estimatedRotation * _estimatedAcceleration;
-        
-        //  Update estimated position and velocity
-        float const DECAY_VELOCITY = 0.975f;
-        float const DECAY_POSITION = 0.975f;
-        _estimatedVelocity += deltaTime * _estimatedAcceleration;
-        _estimatedPosition += deltaTime * _estimatedVelocity;
-        _estimatedVelocity *= DECAY_VELOCITY;
-        
-        //  Attempt to fuse gyro position with webcam position
-        Webcam* webcam = Application::getInstance()->getWebcam();
-        if (webcam->isActive()) {
-            const float WEBCAM_POSITION_FUSION = 0.5f;
-            _estimatedPosition = glm::mix(_estimatedPosition, webcam->getEstimatedPosition(), WEBCAM_POSITION_FUSION);
-               
-        } else {
-            _estimatedPosition *= DECAY_POSITION;
-        }
-            
-        //  Accumulate a set of initial baseline readings for setting gravity
-        if (totalSamples == 0) {
-            _gravity = _lastAcceleration;
-        } 
-        else {
-            if (totalSamples < GRAVITY_SAMPLES) {
-                _gravity = glm::mix(_gravity, _lastAcceleration, 1.0f / GRAVITY_SAMPLES);
-                
-                //  North samples start later, because the initial compass readings are screwy
-                int northSample = totalSamples - (GRAVITY_SAMPLES - NORTH_SAMPLES);
-                if (northSample == 0) {
-                    _north = _lastCompass;
-                    
-                } else if (northSample > 0) {
-                    _north = glm::mix(_north, _lastCompass, 1.0f / NORTH_SAMPLES);
-                }
-            } else {
-                //  Use gravity reading to do sensor fusion on the pitch and roll estimation
-                estimatedRotation = safeMix(estimatedRotation,
-                    rotationBetween(estimatedRotation * _lastAcceleration, _gravity) * estimatedRotation,
-                    1.0f / ACCELERATION_SENSOR_FUSION_SAMPLES);
-                
-                //  Update the compass extents
-                _compassMinima = glm::min(_compassMinima, _lastCompass);
-                _compassMaxima = glm::max(_compassMaxima, _lastCompass);
-        
-                //  Same deal with the compass heading
-                estimatedRotation = safeMix(estimatedRotation,
-                    rotationBetween(estimatedRotation * recenterCompass(_lastCompass),
-                        recenterCompass(_north)) * estimatedRotation,
-                    1.0f / COMPASS_SENSOR_FUSION_SAMPLES);
-            }
-        }
-        
-        _estimatedRotation = safeEulerAngles(estimatedRotation); 
-        
-        totalSamples++;
-    } 
-    
-    if (initialSamples == totalSamples) {        
-        timeval now;
-        gettimeofday(&now, NULL);
-        
-        if (diffclock(&lastGoodRead, &now) > NO_READ_MAXIMUM_MSECS) {
-            qDebug("No data - Shutting down SerialInterface.\n");
-            resetSerial();
-        }
-    } else {
-        gettimeofday(&lastGoodRead, NULL);
-    }
-#endif
-}
-
-void SerialInterface::resetAverages() {
-    totalSamples = 0;
-    _gravity = glm::vec3(0, 0, 0);
-    _averageRotationRates = glm::vec3(0, 0, 0);
-    _averageAcceleration = glm::vec3(0, 0, 0);
-    _lastRotationRates = glm::vec3(0, 0, 0);
-    _estimatedRotation = glm::vec3(0, 0, 0);
-    _estimatedPosition = glm::vec3(0, 0, 0);
-    _estimatedVelocity = glm::vec3(0, 0, 0);
-    _estimatedAcceleration = glm::vec3(0, 0, 0);
-}
-
-void SerialInterface::resetSerial() {
-#ifndef _WIN32
-    resetAverages();
-    _active = false;
-    gettimeofday(&lastGoodRead, NULL);
-#endif
-}
-
-glm::vec3 SerialInterface::recenterCompass(const glm::vec3& compass) {
-    // compensate for "hard iron" distortion by subtracting the midpoint on each axis; see
-    // http://www.sensorsmag.com/sensors/motion-velocity-displacement/compensating-tilt-hard-iron-and-soft-iron-effects-6475
-    return (compass - (_compassMinima + _compassMaxima) * 0.5f) / (_compassMaxima - _compassMinima);
-}
-
-
diff --git a/interface/src/devices/SerialInterface.h b/interface/src/devices/SerialInterface.h
deleted file mode 100644
index 711ff56757..0000000000
--- a/interface/src/devices/SerialInterface.h
+++ /dev/null
@@ -1,76 +0,0 @@
-//
-//  SerialInterface.h
-//  hifi
-//
-//  Created by Stephen Birarda on 2/15/13.
-//  Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
-//
-
-#ifndef __interface__SerialInterface__
-#define __interface__SerialInterface__
-
-// These includes are for serial port reading/writing
-#ifndef _WIN32
-#include <unistd.h>
-#include <fcntl.h>
-#include <termios.h>
-#include <dirent.h>
-#endif
-
-#include <glm/glm.hpp>
-
-#include "InterfaceConfig.h"
-#include "Util.h"
-
-extern const bool USING_INVENSENSE_MPU9150;
-
-class SerialInterface {
-public:
-    SerialInterface();
-    
-    void pair();
-    void readData(float deltaTime);
-    const float getLastPitchRate() const { return _lastRotationRates[0]; }
-    const float getLastYawRate() const { return _lastRotationRates[1]; }
-    const float getLastRollRate() const { return _lastRotationRates[2]; }
-    const glm::vec3& getLastRotationRates() const { return _lastRotationRates; };
-    const glm::vec3& getEstimatedRotation() const { return _estimatedRotation; };
-    const glm::vec3& getEstimatedPosition() const { return _estimatedPosition; };
-    const glm::vec3& getEstimatedVelocity() const { return _estimatedVelocity; };
-    const glm::vec3& getEstimatedAcceleration() const { return _estimatedAcceleration; };
-    const glm::vec3& getLastAcceleration() const { return _lastAcceleration; };
-    const glm::vec3& getGravity() const { return _gravity; };
-    
-    void renderLevels(int width, int height);
-    void resetAverages();
-    bool isActive() const { return _active; }
-    
-private:
-    void initializePort(char* portname);
-    void resetSerial();
-
-    glm::vec3 recenterCompass(const glm::vec3& compass);
-
-    bool _active;
-    int _serialDescriptor;
-    int totalSamples;
-    timeval lastGoodRead;
-    glm::vec3 _gravity;
-    glm::vec3 _north;
-    glm::vec3 _averageRotationRates;
-    glm::vec3 _averageAcceleration;
-    glm::vec3 _estimatedRotation;
-    glm::vec3 _estimatedPosition;
-    glm::vec3 _estimatedVelocity;
-    glm::vec3 _estimatedAcceleration;
-    glm::vec3 _lastAcceleration;
-    glm::vec3 _lastRotationRates;
-    glm::vec3 _lastCompass;
-    glm::vec3 _compassMinima;
-    glm::vec3 _compassMaxima;
-    
-    glm::mat3 _angularVelocityToLinearAccel;
-    glm::mat3 _angularAccelToLinearAccel;
-};
-
-#endif
diff --git a/interface/src/devices/SixenseManager.cpp b/interface/src/devices/SixenseManager.cpp
index 9ebe4b35d1..24caa33533 100644
--- a/interface/src/devices/SixenseManager.cpp
+++ b/interface/src/devices/SixenseManager.cpp
@@ -30,10 +30,10 @@ SixenseManager::~SixenseManager() {
 void SixenseManager::setFilter(bool filter) {
 #ifdef HAVE_SIXENSE
     if (filter) {
-        qDebug("Sixense Filter ON\n");
+        qDebug("Sixense Filter ON");
         sixenseSetFilterEnabled(1);
     } else {
-        qDebug("Sixense Filter OFF\n");
+        qDebug("Sixense Filter OFF");
         sixenseSetFilterEnabled(0);
     }
 #endif
diff --git a/interface/src/devices/Transmitter.cpp b/interface/src/devices/Transmitter.cpp
index 011de567cd..8ae6bdc405 100644
--- a/interface/src/devices/Transmitter.cpp
+++ b/interface/src/devices/Transmitter.cpp
@@ -49,7 +49,7 @@ void Transmitter::checkForLostTransmitter() {
         int msecsSinceLast = diffclock(_lastReceivedPacket, &now);
         if (msecsSinceLast > TIME_TO_ASSUME_LOST_MSECS) {
             resetLevels();
-            qDebug("Transmitter signal lost.\n");
+            qDebug("Transmitter signal lost.");
         }
     }
 }
@@ -104,12 +104,12 @@ void Transmitter::processIncomingData(unsigned char* packetData, int numBytes) {
         _estimatedRotation.y *= (1.f - DECAY_RATE * DELTA_TIME);
 
         if (!_isConnected) {
-            qDebug("Transmitter Connected.\n");
+            qDebug("Transmitter Connected.");
             _isConnected = true;
             _estimatedRotation *= 0.0;
         }
     } else {
-        qDebug("Transmitter packet read error, %d bytes.\n", numBytes);
+        qDebug("Transmitter packet read error, %d bytes.", numBytes);
     }
 }
 
diff --git a/interface/src/devices/Webcam.cpp b/interface/src/devices/Webcam.cpp
index 04a7e71ff8..f6a49a9407 100644
--- a/interface/src/devices/Webcam.cpp
+++ b/interface/src/devices/Webcam.cpp
@@ -501,26 +501,26 @@ static glm::quat xnToGLM(const XnMatrix3X3& matrix) {
 }
 
 static void XN_CALLBACK_TYPE newUser(UserGenerator& generator, XnUserID id, void* cookie) {
-    qDebug("Found user %d.\n", id);
+    qDebug("Found user %d.", id);
     generator.GetSkeletonCap().RequestCalibration(id, false);
 }
 
 static void XN_CALLBACK_TYPE lostUser(UserGenerator& generator, XnUserID id, void* cookie) {
-    qDebug("Lost user %d.\n", id);
+    qDebug("Lost user %d.", id);
 }
 
 static void XN_CALLBACK_TYPE calibrationStarted(SkeletonCapability& capability, XnUserID id, void* cookie) {
-    qDebug("Calibration started for user %d.\n", id);
+    qDebug("Calibration started for user %d.", id);
 }
 
 static void XN_CALLBACK_TYPE calibrationCompleted(SkeletonCapability& capability,
         XnUserID id, XnCalibrationStatus status, void* cookie) {
     if (status == XN_CALIBRATION_STATUS_OK) {
-        qDebug("Calibration completed for user %d.\n", id);
+        qDebug("Calibration completed for user %d.", id);
         capability.StartTracking(id);
 
     } else {
-        qDebug("Calibration failed to user %d.\n", id);
+        qDebug("Calibration failed to user %d.", id);
         capability.RequestCalibration(id, true);
     }
 }
@@ -633,7 +633,7 @@ void FrameGrabber::grabFrame() {
         // make sure it's in the format we expect
         if (image->nChannels != 3 || image->depth != IPL_DEPTH_8U || image->dataOrder != IPL_DATA_ORDER_PIXEL ||
                 image->origin != 0) {
-            qDebug("Invalid webcam image format.\n");
+            qDebug("Invalid webcam image format.");
             return;
         }
         color = image;
@@ -965,7 +965,7 @@ bool FrameGrabber::init() {
     // load our face cascade
     switchToResourcesParentIfRequired();
     if (_faceCascade.empty() && !_faceCascade.load("resources/haarcascades/haarcascade_frontalface_alt.xml")) {
-        qDebug("Failed to load Haar cascade for face tracking.\n");
+        qDebug("Failed to load Haar cascade for face tracking.");
         return false;
     }
 
@@ -998,7 +998,7 @@ bool FrameGrabber::init() {
 
     // next, an ordinary webcam
     if ((_capture = cvCaptureFromCAM(-1)) == 0) {
-        qDebug("Failed to open webcam.\n");
+        qDebug("Failed to open webcam.");
         return false;
     }
     const int IDEAL_FRAME_WIDTH = 320;
diff --git a/interface/src/main.cpp b/interface/src/main.cpp
index 7a5703a881..71e9a3fc2f 100644
--- a/interface/src/main.cpp
+++ b/interface/src/main.cpp
@@ -33,16 +33,16 @@ int main(int argc, const char * argv[]) {
     if (clockSkewOption) {
         int clockSkew = atoi(clockSkewOption);
         usecTimestampNowForceClockSkew(clockSkew);
-        qDebug("clockSkewOption=%s clockSkew=%d\n", clockSkewOption, clockSkew);
+        qDebug("clockSkewOption=%s clockSkew=%d", clockSkewOption, clockSkew);
     }
     
     int exitCode;
     {
         Application app(argc, const_cast<char**>(argv), startup_time);
     
-        qDebug( "Created QT Application.\n" );
+        qDebug( "Created QT Application.");
         exitCode = app.exec();
     }
-    qDebug("Normal exit.\n");
+    qDebug("Normal exit.");
     return exitCode;
 }   
diff --git a/interface/src/renderer/FBXReader.cpp b/interface/src/renderer/FBXReader.cpp
index 141ee7d166..5e8eef879e 100644
--- a/interface/src/renderer/FBXReader.cpp
+++ b/interface/src/renderer/FBXReader.cpp
@@ -483,7 +483,7 @@ public:
     QString name;
 
     int parentIndex;
-
+    glm::vec3 translation;
     glm::mat4 preTransform;
     glm::quat preRotation;
     glm::quat rotation;
@@ -499,8 +499,8 @@ glm::mat4 getGlobalTransform(const QMultiHash<QString, QString>& parentMap,
     glm::mat4 globalTransform;
     while (!nodeID.isNull()) {
         const FBXModel& model = models.value(nodeID);
-        globalTransform = model.preTransform * glm::mat4_cast(model.preRotation * model.rotation * model.postRotation) *
-            model.postTransform * globalTransform;
+        globalTransform = glm::translate(model.translation) * model.preTransform * glm::mat4_cast(model.preRotation *
+            model.rotation * model.postRotation) * model.postTransform * globalTransform;
 
         QList<QString> parentIDs = parentMap.values(nodeID);
         nodeID = QString();
@@ -523,11 +523,13 @@ public:
 
 void printNode(const FBXNode& node, int indent) {
     QByteArray spaces(indent, ' ');
-    qDebug("%s%s: ", spaces.data(), node.name.data());
+    QDebug nodeDebug = qDebug();
+    
+    nodeDebug.nospace() << spaces.data() << node.name.data() << ": ";
     foreach (const QVariant& property, node.properties) {
-        qDebug() << property;
+        nodeDebug << property;
     }
-    qDebug() << "\n";
+    
     foreach (const FBXNode& child, node.children) {
         printNode(child, indent + 1);
     }
@@ -956,9 +958,9 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
                         }
                     }
                     // see FBX documentation, http://download.autodesk.com/us/fbx/20112/FBX_SDK_HELP/index.html
-                    model.preTransform = glm::translate(translation) * glm::translate(rotationOffset) *
-                        glm::translate(rotationPivot);
-                    model.preRotation = glm::quat(glm::radians(preRotation));
+                    model.translation = translation;
+                    model.preTransform = glm::translate(rotationOffset) * glm::translate(rotationPivot);      
+                    model.preRotation = glm::quat(glm::radians(preRotation));            
                     model.rotation = glm::quat(glm::radians(rotation));
                     model.postRotation = glm::quat(glm::radians(postRotation));
                     model.postTransform = glm::translate(-rotationPivot) * glm::translate(scalePivot) *
@@ -1141,7 +1143,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
             joint.freeLineage.append(index);
         }
         joint.freeLineage.remove(lastFreeIndex + 1, joint.freeLineage.size() - lastFreeIndex - 1);
-
+        joint.translation = model.translation;
         joint.preTransform = model.preTransform;
         joint.preRotation = model.preRotation;
         joint.rotation = model.rotation;
@@ -1151,13 +1153,14 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
         joint.rotationMax = model.rotationMax;
         glm::quat combinedRotation = model.preRotation * model.rotation * model.postRotation;
         if (joint.parentIndex == -1) {
-            joint.transform = geometry.offset * model.preTransform * glm::mat4_cast(combinedRotation) * model.postTransform;
+            joint.transform = geometry.offset * glm::translate(model.translation) * model.preTransform * 
+                glm::mat4_cast(combinedRotation) * model.postTransform;
             joint.inverseDefaultRotation = glm::inverse(combinedRotation);
             joint.distanceToParent = 0.0f;
 
         } else {
             const FBXJoint& parentJoint = geometry.joints.at(joint.parentIndex);
-            joint.transform = parentJoint.transform *
+            joint.transform = parentJoint.transform * glm::translate(model.translation) *
                 model.preTransform * glm::mat4_cast(combinedRotation) * model.postTransform;
             joint.inverseDefaultRotation = glm::inverse(combinedRotation) * parentJoint.inverseDefaultRotation;
             joint.distanceToParent = glm::distance(extractTranslation(parentJoint.transform),
@@ -1271,7 +1274,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
                 QString jointID = childMap.value(clusterID);
                 fbxCluster.jointIndex = modelIDs.indexOf(jointID);
                 if (fbxCluster.jointIndex == -1) {
-                    qDebug() << "Joint not in model list: " << jointID << "\n";
+                    qDebug() << "Joint not in model list: " << jointID;
                     fbxCluster.jointIndex = 0;
                 }
                 fbxCluster.inverseBindMatrix = glm::inverse(cluster.transformLink) * modelTransform;
@@ -1289,7 +1292,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
             FBXCluster cluster;
             cluster.jointIndex = modelIDs.indexOf(modelID);
             if (cluster.jointIndex == -1) {
-                qDebug() << "Model not in model list: " << modelID << "\n";
+                qDebug() << "Model not in model list: " << modelID;
                 cluster.jointIndex = 0;
             }
             extracted.mesh.clusters.append(cluster);
diff --git a/interface/src/renderer/FBXReader.h b/interface/src/renderer/FBXReader.h
index 6cc08a1549..45410500d9 100644
--- a/interface/src/renderer/FBXReader.h
+++ b/interface/src/renderer/FBXReader.h
@@ -48,6 +48,7 @@ public:
     int parentIndex;
     float distanceToParent;
     float boneRadius;
+    glm::vec3 translation;
     glm::mat4 preTransform;
     glm::quat preRotation;
     glm::quat rotation;
diff --git a/interface/src/renderer/GeometryCache.cpp b/interface/src/renderer/GeometryCache.cpp
index 7ec61a8942..9fff306aca 100644
--- a/interface/src/renderer/GeometryCache.cpp
+++ b/interface/src/renderer/GeometryCache.cpp
@@ -329,10 +329,8 @@ void NetworkGeometry::handleModelReplyError() {
     const int BASE_DELAY_MS = 1000;
     if (++_attempts < MAX_ATTEMPTS) {
         QTimer::singleShot(BASE_DELAY_MS * (int)pow(2.0, _attempts), this, SLOT(makeModelRequest()));
-        debug << " -- retrying...\n";    
+        debug << " -- retrying...";
         
-    } else {
-        debug << "\n";
     }
 }
 
@@ -367,7 +365,7 @@ void NetworkGeometry::maybeReadModelWithMapping() {
         _geometry = url.path().toLower().endsWith(".svo") ? readSVO(model) : readFBX(model, mapping);
         
     } catch (const QString& error) {
-        qDebug() << "Error reading " << url << ": " << error << "\n";
+        qDebug() << "Error reading " << url << ": " << error;
         return;
     }
     
diff --git a/interface/src/renderer/GlowEffect.cpp b/interface/src/renderer/GlowEffect.cpp
index 3bd71b2dd4..cbaa5c4829 100644
--- a/interface/src/renderer/GlowEffect.cpp
+++ b/interface/src/renderer/GlowEffect.cpp
@@ -54,7 +54,7 @@ static ProgramObject* createProgram(const QString& name) {
 
 void GlowEffect::init() {
     if (_initialized) {
-        qDebug("[ERROR] GlowEffeect is already initialized.\n");
+        qDebug("[ERROR] GlowEffeect is already initialized.");
         return;
     }
 
@@ -284,20 +284,20 @@ QOpenGLFramebufferObject* GlowEffect::render(bool toTexture) {
 void GlowEffect::cycleRenderMode() {
     switch(_renderMode = (RenderMode)((_renderMode + 1) % RENDER_MODE_COUNT)) {
         case ADD_MODE:
-            qDebug() << "Glow mode: Add\n";
+            qDebug() << "Glow mode: Add";
             break;
             
         case BLUR_ADD_MODE:
-            qDebug() << "Glow mode: Blur/add\n";
+            qDebug() << "Glow mode: Blur/add";
             break;
             
         case BLUR_PERSIST_ADD_MODE:
-            qDebug() << "Glow mode: Blur/persist/add\n";
+            qDebug() << "Glow mode: Blur/persist/add";
             break;
         
         default:    
         case DIFFUSE_ADD_MODE:
-            qDebug() << "Glow mode: Diffuse/add\n";
+            qDebug() << "Glow mode: Diffuse/add";
             break;
     }
     _isFirstFrame = true;
diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp
index 1702e984bc..570d778c96 100644
--- a/interface/src/renderer/Model.cpp
+++ b/interface/src/renderer/Model.cpp
@@ -99,6 +99,7 @@ void Model::simulate(float deltaTime) {
     if (_jointStates.isEmpty()) {
         foreach (const FBXJoint& joint, geometry.joints) {
             JointState state;
+            state.translation = joint.translation;
             state.rotation = joint.rotation;
             _jointStates.append(state);
         }
@@ -626,7 +627,7 @@ void Model::updateJointState(int index) {
         glm::mat4 baseTransform = glm::mat4_cast(_rotation) * glm::scale(_scale) * glm::translate(_offset);
     
         glm::quat combinedRotation = joint.preRotation * state.rotation * joint.postRotation;    
-        state.transform = baseTransform * geometry.offset * joint.preTransform *
+        state.transform = baseTransform * geometry.offset * glm::translate(state.translation) * joint.preTransform *
             glm::mat4_cast(combinedRotation) * joint.postTransform;
         state.combinedRotation = _rotation * combinedRotation;
     
@@ -642,7 +643,7 @@ void Model::updateJointState(int index) {
             maybeUpdateEyeRotation(parentState, joint, state);
         }
         glm::quat combinedRotation = joint.preRotation * state.rotation * joint.postRotation;    
-        state.transform = parentState.transform * joint.preTransform *
+        state.transform = parentState.transform * glm::translate(state.translation) * joint.preTransform *
             glm::mat4_cast(combinedRotation) * joint.postTransform;
         state.combinedRotation = parentState.combinedRotation * combinedRotation;
     }
@@ -747,6 +748,23 @@ bool Model::setJointRotation(int jointIndex, const glm::quat& rotation, bool fro
     return true;
 }
 
+void Model::setJointTranslation(int jointIndex, const glm::vec3& translation) {
+    const FBXGeometry& geometry = _geometry->getFBXGeometry();
+    const FBXJoint& joint = geometry.joints.at(jointIndex);
+    
+    glm::mat4 parentTransform;
+    if (joint.parentIndex == -1) {
+        parentTransform = glm::mat4_cast(_rotation) * glm::scale(_scale) * glm::translate(_offset) * geometry.offset;
+        
+    } else {
+        parentTransform = _jointStates.at(joint.parentIndex).transform;
+    }
+    JointState& state = _jointStates[jointIndex];
+    glm::vec3 preTranslation = extractTranslation(joint.preTransform * glm::mat4_cast(joint.preRotation *
+        state.rotation * joint.postRotation) * joint.postTransform); 
+    state.translation = glm::vec3(glm::inverse(parentTransform) * glm::vec4(translation, 1.0f)) - preTranslation;
+}
+
 bool Model::restoreJointPosition(int jointIndex, float percent) {
     if (jointIndex == -1 || _jointStates.isEmpty()) {
         return false;
@@ -824,25 +842,6 @@ void Model::renderCollisionProxies(float alpha) {
     glPopMatrix();
 }
 
-void Model::setJointTranslation(int jointIndex, int parentIndex, int childIndex, const glm::vec3& translation) {
-    const FBXGeometry& geometry = _geometry->getFBXGeometry();
-    JointState& state = _jointStates[jointIndex];
-    if (childIndex != -1 && geometry.joints.at(jointIndex).isFree) {
-        // if there's a child, then I must adjust *my* rotation
-        glm::vec3 childTranslation = extractTranslation(_jointStates.at(childIndex).transform);
-        applyRotationDelta(jointIndex, rotationBetween(childTranslation - extractTranslation(state.transform),
-            childTranslation - translation));
-    }
-    if (parentIndex != -1 && geometry.joints.at(parentIndex).isFree) {
-        // if there's a parent, then I must adjust *its* rotation
-        JointState& parent = _jointStates[parentIndex];
-        glm::vec3 parentTranslation = extractTranslation(parent.transform);
-        applyRotationDelta(parentIndex, rotationBetween(extractTranslation(state.transform) - parentTranslation, 
-            translation - parentTranslation));
-    }
-    ::setTranslation(state.transform, translation);
-}
-
 void Model::deleteGeometry() {
     foreach (Model* attachment, _attachments) {
         delete attachment;
diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h
index 3b1f66938b..fc3a0687b8 100644
--- a/interface/src/renderer/Model.h
+++ b/interface/src/renderer/Model.h
@@ -141,6 +141,7 @@ protected:
     
     class JointState {
     public:
+        glm::vec3 translation;
         glm::quat rotation;
         glm::mat4 transform;
         glm::quat combinedRotation;
@@ -172,6 +173,8 @@ protected:
         bool allIntermediatesFree = false, const glm::vec3& alignment = glm::vec3(0.0f, -1.0f, 0.0f));
     bool setJointRotation(int jointIndex, const glm::quat& rotation, bool fromBind = false);
     
+    void setJointTranslation(int jointIndex, const glm::vec3& translation);
+    
     /// Restores the indexed joint to its default position.
     /// \param percent the percentage of the default position to apply (i.e., 0.25f to slerp one fourth of the way to
     /// the original position
@@ -188,8 +191,6 @@ protected:
     
 private:
     
-    void setJointTranslation(int jointIndex, int parentIndex, int childIndex, const glm::vec3& translation);
-    
     void deleteGeometry();
     
     float _pupilDilation;
diff --git a/interface/src/renderer/PointShader.cpp b/interface/src/renderer/PointShader.cpp
index 32139903be..ed4225fbcd 100644
--- a/interface/src/renderer/PointShader.cpp
+++ b/interface/src/renderer/PointShader.cpp
@@ -36,7 +36,7 @@ ProgramObject* PointShader::createPointShaderProgram(const QString& name) {
 
 void PointShader::init() {
     if (_initialized) {
-        qDebug("[ERROR] PointShader is already initialized.\n");
+        qDebug("[ERROR] PointShader is already initialized.");
         return;
     }
     switchToResourcesParentIfRequired();
diff --git a/interface/src/renderer/TextureCache.cpp b/interface/src/renderer/TextureCache.cpp
index 6fdf00d05d..0ba8f84ad2 100644
--- a/interface/src/renderer/TextureCache.cpp
+++ b/interface/src/renderer/TextureCache.cpp
@@ -333,10 +333,8 @@ void NetworkTexture::handleReplyError() {
     const int BASE_DELAY_MS = 1000;
     if (++_attempts < MAX_ATTEMPTS) {
         QTimer::singleShot(BASE_DELAY_MS * (int)pow(2.0, _attempts), this, SLOT(makeRequest()));
-        debug << " -- retrying...\n";    
+        debug << " -- retrying...";
         
-    } else {
-        debug << "\n";
     }
 }
 
diff --git a/interface/src/renderer/VoxelShader.cpp b/interface/src/renderer/VoxelShader.cpp
index b8a907c917..b630006b4b 100644
--- a/interface/src/renderer/VoxelShader.cpp
+++ b/interface/src/renderer/VoxelShader.cpp
@@ -43,7 +43,7 @@ ProgramObject* VoxelShader::createGeometryShaderProgram(const QString& name) {
 
 void VoxelShader::init() {
     if (_initialized) {
-        qDebug("[ERROR] TestProgram is already initialized.\n");
+        qDebug("[ERROR] TestProgram is already initialized.");
         return;
     }
     switchToResourcesParentIfRequired();
diff --git a/interface/src/starfield/Controller.cpp b/interface/src/starfield/Controller.cpp
index cc510cbe0e..b738749416 100755
--- a/interface/src/starfield/Controller.cpp
+++ b/interface/src/starfield/Controller.cpp
@@ -24,7 +24,7 @@ bool Controller::computeStars(unsigned numStars, unsigned seed) {
     
     this->retile(numStars, _tileResolution);
     
-    qDebug() << "Total time to generate stars: " << ((usecTimestampNow() - usecTimestamp(&startTime)) / 1000) << " msec\n";
+    qDebug() << "Total time to generate stars: " << ((usecTimestampNow() - usecTimestamp(&startTime)) / 1000) << "msec";
     
     return true;
 }
diff --git a/interface/src/starfield/Generator.cpp b/interface/src/starfield/Generator.cpp
index 024ea57fc7..72f5e6c859 100644
--- a/interface/src/starfield/Generator.cpp
+++ b/interface/src/starfield/Generator.cpp
@@ -67,7 +67,7 @@ void Generator::computeStarPositions(InputVertices& destination, unsigned limit,
         vertices->push_back(InputVertex(azimuth, altitude, computeStarColor(STAR_COLORIZATION)));
     }
     
-    qDebug() << "Total time to generate stars: " << ((usecTimestampNow() - usecTimestamp(&startTime)) / 1000) << " msec\n";
+    qDebug() << "Total time to generate stars: " << ((usecTimestampNow() - usecTimestamp(&startTime)) / 1000) << " msec";
 }
 
 // computeStarColor
diff --git a/interface/src/ui/VoxelStatsDialog.cpp b/interface/src/ui/VoxelStatsDialog.cpp
index 3a2c8468ad..9bf755b174 100644
--- a/interface/src/ui/VoxelStatsDialog.cpp
+++ b/interface/src/ui/VoxelStatsDialog.cpp
@@ -241,9 +241,10 @@ void VoxelStatsDialog::showOctreeServersOfType(int& serverCount, NODE_TYPE serve
                                                 NodeToJurisdictionMap& serverJurisdictions) {
                                                 
     QLocale locale(QLocale::English);
-
+    
     NodeList* nodeList = NodeList::getInstance();
-    for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
+
+    foreach (const SharedNodePointer& node, nodeList->getNodeHash()) {
         // only send to the NodeTypes that are NODE_TYPE_VOXEL_SERVER
         if (node->getType() == serverType) {
             serverCount++;
@@ -261,8 +262,8 @@ void VoxelStatsDialog::showOctreeServersOfType(int& serverCount, NODE_TYPE serve
             std::stringstream serverDetails("");
             std::stringstream extraDetails("");
             std::stringstream linkDetails("");
-        
-            if (nodeList->getNodeActiveSocketOrPing(&(*node))) {
+            
+            if (nodeList->getNodeActiveSocketOrPing(node.data())) {
                 serverDetails << "active ";
             } else {
                 serverDetails << "inactive ";
@@ -270,29 +271,29 @@ void VoxelStatsDialog::showOctreeServersOfType(int& serverCount, NODE_TYPE serve
             
             QUuid nodeUUID = node->getUUID();
             
-            // lookup our nodeUUID in the jurisdiction map, if it's missing then we're 
+            // lookup our nodeUUID in the jurisdiction map, if it's missing then we're
             // missing at least one jurisdiction
             if (serverJurisdictions.find(nodeUUID) == serverJurisdictions.end()) {
                 serverDetails << " unknown jurisdiction ";
             } else {
                 const JurisdictionMap& map = serverJurisdictions[nodeUUID];
-
+                
                 unsigned char* rootCode = map.getRootOctalCode();
-            
+                
                 if (rootCode) {
                     QString rootCodeHex = octalCodeToHexString(rootCode);
-
+                    
                     VoxelPositionSize rootDetails;
                     voxelDetailsForCode(rootCode, rootDetails);
                     AABox serverBounds(glm::vec3(rootDetails.x, rootDetails.y, rootDetails.z), rootDetails.s);
                     serverBounds.scale(TREE_SCALE);
-                    serverDetails << " jurisdiction: " 
-                        << rootCodeHex.toLocal8Bit().constData()
-                        << " [" 
-                        << rootDetails.x << ", "
-                        << rootDetails.y << ", "
-                        << rootDetails.z << ": "
-                        << rootDetails.s << "] ";
+                    serverDetails << " jurisdiction: "
+                    << rootCodeHex.toLocal8Bit().constData()
+                    << " ["
+                    << rootDetails.x << ", "
+                    << rootDetails.y << ", "
+                    << rootDetails.z << ": "
+                    << rootDetails.s << "] ";
                 } else {
                     serverDetails << " jurisdiction has no rootCode";
                 } // root code
@@ -304,7 +305,7 @@ void VoxelStatsDialog::showOctreeServersOfType(int& serverCount, NODE_TYPE serve
                 NodeToVoxelSceneStats* sceneStats = Application::getInstance()->getOcteeSceneStats();
                 if (sceneStats->find(nodeUUID) != sceneStats->end()) {
                     VoxelSceneStats& stats = sceneStats->at(nodeUUID);
-
+                    
                     switch (_extraServerDetails[serverCount-1]) {
                         case MOST: {
                             extraDetails << "<br/>" ;
@@ -312,14 +313,14 @@ void VoxelStatsDialog::showOctreeServersOfType(int& serverCount, NODE_TYPE serve
                             const unsigned long USECS_PER_MSEC = 1000;
                             float lastFullEncode = stats.getLastFullTotalEncodeTime() / USECS_PER_MSEC;
                             float lastFullSend = stats.getLastFullElapsedTime() / USECS_PER_MSEC;
-
+                            
                             QString lastFullEncodeString = locale.toString(lastFullEncode);
                             QString lastFullSendString = locale.toString(lastFullSend);
-
-                            extraDetails << "<br/>" << "Last Full Scene... " << 
-                                "Encode Time: " << lastFullEncodeString.toLocal8Bit().constData() << " ms " << 
-                                "Send Time: " << lastFullSendString.toLocal8Bit().constData() << " ms ";
-                    
+                            
+                            extraDetails << "<br/>" << "Last Full Scene... " <<
+                            "Encode Time: " << lastFullEncodeString.toLocal8Bit().constData() << " ms " <<
+                            "Send Time: " << lastFullSendString.toLocal8Bit().constData() << " ms ";
+                            
                             for (int i = 0; i < VoxelSceneStats::ITEM_COUNT; i++) {
                                 VoxelSceneStats::Item item = (VoxelSceneStats::Item)(i);
                                 VoxelSceneStats::ItemInfo& itemInfo = stats.getItemInfo(item);
@@ -330,44 +331,44 @@ void VoxelStatsDialog::showOctreeServersOfType(int& serverCount, NODE_TYPE serve
                             QString totalString = locale.toString((uint)stats.getTotalElements());
                             QString internalString = locale.toString((uint)stats.getTotalInternal());
                             QString leavesString = locale.toString((uint)stats.getTotalLeaves());
-
+                            
                             serverDetails << "<br/>" << "Node UUID: " <<
-                                    nodeUUID.toString().toLocal8Bit().constData() << " ";
-
+                            nodeUUID.toString().toLocal8Bit().constData() << " ";
+                            
                             serverDetails << "<br/>" << "Voxels: " <<
-                                totalString.toLocal8Bit().constData() << " total " << 
-                                internalString.toLocal8Bit().constData() << " internal " <<
-                                leavesString.toLocal8Bit().constData() << " leaves ";
-
+                            totalString.toLocal8Bit().constData() << " total " <<
+                            internalString.toLocal8Bit().constData() << " internal " <<
+                            leavesString.toLocal8Bit().constData() << " leaves ";
+                            
                             QString incomingPacketsString = locale.toString((uint)stats.getIncomingPackets());
                             QString incomingBytesString = locale.toString((uint)stats.getIncomingBytes());
                             QString incomingWastedBytesString = locale.toString((uint)stats.getIncomingWastedBytes());
                             QString incomingOutOfOrderString = locale.toString((uint)stats.getIncomingOutOfOrder());
                             QString incomingLikelyLostString = locale.toString((uint)stats.getIncomingLikelyLost());
-
+                            
                             int clockSkewInMS = node->getClockSkewUsec() / (int)USECS_PER_MSEC;
                             QString incomingFlightTimeString = locale.toString((int)stats.getIncomingFlightTimeAverage());
                             QString incomingPingTimeString = locale.toString(node->getPingMs());
                             QString incomingClockSkewString = locale.toString(clockSkewInMS);
-                
+                            
                             serverDetails << "<br/>" << "Incoming Packets: " <<
-                                incomingPacketsString.toLocal8Bit().constData() << 
-                                " Out of Order: " << incomingOutOfOrderString.toLocal8Bit().constData() <<
-                                " Likely Lost: " << incomingLikelyLostString.toLocal8Bit().constData();
-
+                            incomingPacketsString.toLocal8Bit().constData() <<
+                            " Out of Order: " << incomingOutOfOrderString.toLocal8Bit().constData() <<
+                            " Likely Lost: " << incomingLikelyLostString.toLocal8Bit().constData();
+                            
                             serverDetails << "<br/>" <<
-                                " Average Flight Time: " << incomingFlightTimeString.toLocal8Bit().constData() << " msecs";
-
-                            serverDetails << "<br/>" << 
-                                " Average Ping Time: " << incomingPingTimeString.toLocal8Bit().constData() << " msecs";
-
-                            serverDetails << "<br/>" << 
-                                " Average Clock Skew: " << incomingClockSkewString.toLocal8Bit().constData() << " msecs";
-                    
+                            " Average Flight Time: " << incomingFlightTimeString.toLocal8Bit().constData() << " msecs";
+                            
+                            serverDetails << "<br/>" <<
+                            " Average Ping Time: " << incomingPingTimeString.toLocal8Bit().constData() << " msecs";
+                            
+                            serverDetails << "<br/>" <<
+                            " Average Clock Skew: " << incomingClockSkewString.toLocal8Bit().constData() << " msecs";
+                            
                             serverDetails << "<br/>" << "Incoming" <<
-                                " Bytes: " <<  incomingBytesString.toLocal8Bit().constData() <<
-                                " Wasted Bytes: " << incomingWastedBytesString.toLocal8Bit().constData();
-
+                            " Bytes: " <<  incomingBytesString.toLocal8Bit().constData() <<
+                            " Wasted Bytes: " << incomingWastedBytesString.toLocal8Bit().constData();
+                            
                             serverDetails << extraDetails.str();
                             if (_extraServerDetails[serverCount-1] == MORE) {
                                 linkDetails << "   " << " [<a href='most-" << serverCount << "'>most...</a>]";
@@ -376,7 +377,7 @@ void VoxelStatsDialog::showOctreeServersOfType(int& serverCount, NODE_TYPE serve
                                 linkDetails << "   " << " [<a href='more-" << serverCount << "'>less...</a>]";
                                 linkDetails << "   " << " [<a href='less-" << serverCount << "'>least...</a>]";
                             }
-                    
+                            
                         } break;
                         case LESS: {
                             // nothing
@@ -391,7 +392,7 @@ void VoxelStatsDialog::showOctreeServersOfType(int& serverCount, NODE_TYPE serve
             serverDetails << linkDetails.str();
             _labels[_voxelServerLables[serverCount - 1]]->setText(serverDetails.str().c_str());
         } // is VOXEL_SERVER
-    } // Node Loop
+    }
 }
 
 void VoxelStatsDialog::reject() {
diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp
index 722c2a6dbd..60ff777452 100644
--- a/libraries/audio/src/AudioInjector.cpp
+++ b/libraries/audio/src/AudioInjector.cpp
@@ -103,9 +103,9 @@ void AudioInjector::injectAudio() {
             
             
             // grab our audio mixer from the NodeList, if it exists
-            Node* audioMixer = nodeList->soloNodeOfType(NODE_TYPE_AUDIO_MIXER);
+            SharedNodePointer audioMixer = nodeList->soloNodeOfType(NODE_TYPE_AUDIO_MIXER);
             
-            if (audioMixer && nodeList->getNodeActiveSocketOrPing(audioMixer)) {
+            if (audioMixer && nodeList->getNodeActiveSocketOrPing(audioMixer.data())) {
                 // send off this audio packet
                 nodeList->getNodeSocket().writeDatagram((char*) injectedAudioPacket,
                                                         (currentPacketPosition - injectedAudioPacket) + bytesToCopy,
diff --git a/libraries/audio/src/AudioRingBuffer.cpp b/libraries/audio/src/AudioRingBuffer.cpp
index cfbcd95daa..c471c896a4 100644
--- a/libraries/audio/src/AudioRingBuffer.cpp
+++ b/libraries/audio/src/AudioRingBuffer.cpp
@@ -101,7 +101,7 @@ qint64 AudioRingBuffer::writeData(const char* data, qint64 maxSize) {
         && (less(_endOfLastWrite, _nextOutput)
             && lessEqual(_nextOutput, shiftedPositionAccomodatingWrap(_endOfLastWrite, samplesToCopy)))) {
         // this read will cross the next output, so call us starved and reset the buffer
-        qDebug() << "Filled the ring buffer. Resetting.\n";
+        qDebug() << "Filled the ring buffer. Resetting.";
         _endOfLastWrite = _buffer;
         _nextOutput = _buffer;
         _isStarved = true;
diff --git a/libraries/audio/src/PositionalAudioRingBuffer.cpp b/libraries/audio/src/PositionalAudioRingBuffer.cpp
index f1eba07906..97793a98fb 100644
--- a/libraries/audio/src/PositionalAudioRingBuffer.cpp
+++ b/libraries/audio/src/PositionalAudioRingBuffer.cpp
@@ -26,7 +26,8 @@ PositionalAudioRingBuffer::PositionalAudioRingBuffer(PositionalAudioRingBuffer::
     _position(0.0f, 0.0f, 0.0f),
     _orientation(0.0f, 0.0f, 0.0f, 0.0f),
     _willBeAddedToMix(false),
-    _shouldLoopbackForNode(false)
+    _shouldLoopbackForNode(false),
+    _shouldOutputStarveDebug(true)
 {
 
 }
@@ -63,11 +64,19 @@ int PositionalAudioRingBuffer::parsePositionalData(unsigned char* sourceBuffer,
 
 bool PositionalAudioRingBuffer::shouldBeAddedToMix(int numJitterBufferSamples) {
     if (!isNotStarvedOrHasMinimumSamples(NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL + numJitterBufferSamples)) {
-        qDebug() << "Starved and do not have minimum samples to start. Buffer held back.\n";
+        if (_shouldOutputStarveDebug) {
+            qDebug() << "Starved and do not have minimum samples to start. Buffer held back.";
+            _shouldOutputStarveDebug = false;
+        }
+        
         return false;
     } else if (samplesAvailable() < NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL) {
-        qDebug() << "Do not have number of samples needed for interval. Buffer starved.\n";
+        qDebug() << "Do not have number of samples needed for interval. Buffer starved.";
         _isStarved = true;
+        
+        // reset our _shouldOutputStarveDebug to true so the next is printed
+        _shouldOutputStarveDebug = true;
+        
         return false;
     } else {
         // good buffer, add this to the mix
diff --git a/libraries/audio/src/PositionalAudioRingBuffer.h b/libraries/audio/src/PositionalAudioRingBuffer.h
index 189ac34058..55ed627c4d 100644
--- a/libraries/audio/src/PositionalAudioRingBuffer.h
+++ b/libraries/audio/src/PositionalAudioRingBuffer.h
@@ -49,6 +49,7 @@ protected:
     glm::quat _orientation;
     bool _willBeAddedToMix;
     bool _shouldLoopbackForNode;
+    bool _shouldOutputStarveDebug;
 };
 
 #endif /* defined(__hifi__PositionalAudioRingBuffer__) */
diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp
index f663f26cbf..f20d35e4c8 100644
--- a/libraries/avatars/src/AvatarData.cpp
+++ b/libraries/avatars/src/AvatarData.cpp
@@ -30,7 +30,6 @@ AvatarData::AvatarData(Node* owningNode) :
     _bodyPitch(0.0),
     _bodyRoll(0.0),
     _targetScale(1.0f),
-    _leaderUUID(),
     _handState(0),
     _keyState(NO_KEY_DOWN),
     _isChatCirclingEnabled(false),
@@ -77,10 +76,6 @@ int AvatarData::getBroadcastData(unsigned char* destinationBuffer) {
 
     // Body scale
     destinationBuffer += packFloatRatioToTwoByte(destinationBuffer, _targetScale);
-    
-    // Follow mode info
-    memcpy(destinationBuffer, _leaderUUID.toRfc4122().constData(), NUM_BYTES_RFC4122_UUID);
-    destinationBuffer += NUM_BYTES_RFC4122_UUID;
 
     // Head rotation (NOTE: This needs to become a quaternion to save two bytes)
     destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _headData->_yaw);
@@ -200,10 +195,6 @@ int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) {
     // Body scale
     sourceBuffer += unpackFloatRatioFromTwoByte(sourceBuffer, _targetScale);
 
-    // Follow mode info
-    _leaderUUID = QUuid::fromRfc4122(QByteArray((char*) sourceBuffer, NUM_BYTES_RFC4122_UUID));
-    sourceBuffer += NUM_BYTES_RFC4122_UUID;
-
     // Head rotation (NOTE: This needs to become a quaternion to save two bytes)
     float headYaw, headPitch, headRoll;
     sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &headYaw);
@@ -301,5 +292,5 @@ void AvatarData::setClampedTargetScale(float targetScale) {
     targetScale =  glm::clamp(targetScale, MIN_AVATAR_SCALE, MAX_AVATAR_SCALE);
     
     _targetScale = targetScale;
-    qDebug() << "Changed scale to " << _targetScale << "\n";
+    qDebug() << "Changed scale to " << _targetScale;
 }
diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h
index 67e234c67e..83bcb41eea 100755
--- a/libraries/avatars/src/AvatarData.h
+++ b/libraries/avatars/src/AvatarData.h
@@ -114,9 +114,6 @@ public:
     QString getQStringChatMessage() { return QString(_chatMessage.data()); }
 
     bool isChatCirclingEnabled() const { return _isChatCirclingEnabled; }
-
-    const QUuid& getLeaderUUID() const { return _leaderUUID; }
-
     const HeadData* getHeadData() const { return _headData; }
     const HandData* getHandData() const { return _handData; }
 
@@ -148,9 +145,6 @@ protected:
     // Body scale
     float _targetScale;
 
-    // Following mode infos
-    QUuid _leaderUUID;
-
     //  Hand state (are we grabbing something or not)
     char _handState;
 
diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp
index c04ee9f297..5b7e71ca20 100644
--- a/libraries/metavoxels/src/MetavoxelData.cpp
+++ b/libraries/metavoxels/src/MetavoxelData.cpp
@@ -429,7 +429,7 @@ void ScriptedMetavoxelGuide::guide(MetavoxelVisitation& visitation) {
     _visitation = &visitation;
     _guideFunction.call(QScriptValue(), _arguments);
     if (_guideFunction.engine()->hasUncaughtException()) {
-        qDebug() << "Script error: " << _guideFunction.engine()->uncaughtException().toString() << "\n";
+        qDebug() << "Script error: " << _guideFunction.engine()->uncaughtException().toString();
     }
 }
 
diff --git a/libraries/octree-server/src/OctreeInboundPacketProcessor.cpp b/libraries/octree-server/src/OctreeInboundPacketProcessor.cpp
index 020c1b274b..e6a89c76ed 100644
--- a/libraries/octree-server/src/OctreeInboundPacketProcessor.cpp
+++ b/libraries/octree-server/src/OctreeInboundPacketProcessor.cpp
@@ -57,7 +57,7 @@ void OctreeInboundPacketProcessor::processPacket(const HifiSockAddr& senderSockA
         PerformanceWarning warn(debugProcessPacket, "processPacket KNOWN TYPE",debugProcessPacket);
         _receivedPacketCount++;
 
-        Node* senderNode = NodeList::getInstance()->nodeWithAddress(senderSockAddr);
+        SharedNodePointer senderNode = NodeList::getInstance()->nodeWithAddress(senderSockAddr);
         
         unsigned short int sequence = (*((unsigned short int*)(packetData + numBytesPacketHeader)));
         uint64_t sentAt = (*((uint64_t*)(packetData + numBytesPacketHeader + sizeof(sequence))));
@@ -70,7 +70,7 @@ void OctreeInboundPacketProcessor::processPacket(const HifiSockAddr& senderSockA
         if (_myServer->wantsDebugReceiving()) {
             qDebug() << "PROCESSING THREAD: got '" << packetType << "' packet - " << _receivedPacketCount 
                     << " command from client receivedBytes=" << packetLength 
-                    << " sequence=" << sequence << " transitTime=" << transitTime << " usecs\n";
+                    << " sequence=" << sequence << " transitTime=" << transitTime << " usecs";
         }
         int atByte = numBytesPacketHeader + sizeof(sequence) + sizeof(sentAt);
         unsigned char* editData = (unsigned char*)&packetData[atByte];
@@ -87,7 +87,9 @@ void OctreeInboundPacketProcessor::processPacket(const HifiSockAddr& senderSockA
             _myServer->getOctree()->lockForWrite();
             uint64_t startProcess = usecTimestampNow();
             int editDataBytesRead = _myServer->getOctree()->processEditPacketData(packetType, 
-                                                                packetData, packetLength, editData, maxSize, senderNode);
+                                                                                  packetData,
+                                                                                  packetLength,
+                                                                                  editData, maxSize, senderNode.data());
             _myServer->getOctree()->unlock();
             uint64_t endProcess = usecTimestampNow();
 
@@ -114,16 +116,16 @@ void OctreeInboundPacketProcessor::processPacket(const HifiSockAddr& senderSockA
             senderNode->setLastHeardMicrostamp(usecTimestampNow());
             nodeUUID = senderNode->getUUID();
             if (debugProcessPacket) {
-                qDebug() << "sender has uuid=" << nodeUUID << "\n";
+                qDebug() << "sender has uuid=" << nodeUUID;
             }
         } else {
             if (debugProcessPacket) {
-                qDebug() << "sender has no known nodeUUID.\n";
+                qDebug() << "sender has no known nodeUUID.";
             }
         }
         trackInboundPackets(nodeUUID, sequence, transitTime, editsInPacket, processTime, lockWaitTime);
     } else {
-        printf("unknown packet ignored... packetData[0]=%c\n", packetData[0]);
+        qDebug("unknown packet ignored... packetData[0]=%c", packetData[0]);
     }
 }
 
diff --git a/libraries/octree-server/src/OctreeSendThread.cpp b/libraries/octree-server/src/OctreeSendThread.cpp
index ccdf1ed8e2..6aba5fafaf 100644
--- a/libraries/octree-server/src/OctreeSendThread.cpp
+++ b/libraries/octree-server/src/OctreeSendThread.cpp
@@ -30,11 +30,11 @@ bool OctreeSendThread::process() {
 
     // don't do any send processing until the initial load of the octree is complete...
     if (_myServer->isInitialLoadComplete()) {
-        Node* node = NodeList::getInstance()->nodeWithUUID(_nodeUUID);
+        SharedNodePointer node = NodeList::getInstance()->nodeWithUUID(_nodeUUID);
 
         if (node) {
             // make sure the node list doesn't kill our node while we're using it
-            if (node->trylock()) {
+            if (node->getMutex().tryLock()) {
                 gotLock = true;
                 OctreeQueryNode* nodeData = NULL;
 
@@ -48,15 +48,15 @@ bool OctreeSendThread::process() {
                     if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) {
                         printf("nodeData->updateCurrentViewFrustum() changed=%s\n", debug::valueOf(viewFrustumChanged));
                     }
-                    packetsSent = packetDistributor(node, nodeData, viewFrustumChanged);
+                    packetsSent = packetDistributor(node.data(), nodeData, viewFrustumChanged);
                 }
 
-                node->unlock(); // we're done with this node for now.
+                node->getMutex().unlock(); // we're done with this node for now.
             }
         }
     } else {
         if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) {
-            qDebug("OctreeSendThread::process() waiting for isInitialLoadComplete()\n");
+            qDebug("OctreeSendThread::process() waiting for isInitialLoadComplete()");
         }
     }
 
@@ -131,7 +131,7 @@ int OctreeSendThread::handlePacketSend(Node* node, OctreeQueryNode* nodeData, in
                 qDebug() << "Adding stats to packet at " << now << " [" << _totalPackets <<"]: sequence: " << sequence <<
                         " statsMessageLength: " << statsMessageLength <<
                         " original size: " << nodeData->getPacketLength() << " [" << _totalBytes <<
-                        "] wasted bytes:" << thisWastedBytes << " [" << _totalWastedBytes << "]\n";
+                        "] wasted bytes:" << thisWastedBytes << " [" << _totalWastedBytes << "]";
             }
 
             // actually send it
@@ -154,7 +154,7 @@ int OctreeSendThread::handlePacketSend(Node* node, OctreeQueryNode* nodeData, in
             if (debug) {
                 qDebug() << "Sending separate stats packet at " << now << " [" << _totalPackets <<"]: sequence: " << sequence <<
                         " size: " << statsMessageLength << " [" << _totalBytes <<
-                        "] wasted bytes:" << thisWastedBytes << " [" << _totalWastedBytes << "]\n";
+                        "] wasted bytes:" << thisWastedBytes << " [" << _totalWastedBytes << "]";
             }
 
             trueBytesSent += statsMessageLength;
@@ -174,7 +174,7 @@ int OctreeSendThread::handlePacketSend(Node* node, OctreeQueryNode* nodeData, in
             if (debug) {
                 qDebug() << "Sending packet at " << now << " [" << _totalPackets <<"]: sequence: " << sequence <<
                         " size: " << nodeData->getPacketLength() << " [" << _totalBytes <<
-                        "] wasted bytes:" << thisWastedBytes << " [" << _totalWastedBytes << "]\n";
+                        "] wasted bytes:" << thisWastedBytes << " [" << _totalWastedBytes << "]";
             }
         }
         nodeData->stats.markAsSent();
@@ -194,7 +194,7 @@ int OctreeSendThread::handlePacketSend(Node* node, OctreeQueryNode* nodeData, in
             if (debug) {
                 qDebug() << "Sending packet at " << now << " [" << _totalPackets <<"]: sequence: " << sequence <<
                         " size: " << nodeData->getPacketLength() << " [" << _totalBytes <<
-                        "] wasted bytes:" << thisWastedBytes << " [" << _totalWastedBytes << "]\n";
+                        "] wasted bytes:" << thisWastedBytes << " [" << _totalWastedBytes << "]";
             }
         }
     }
@@ -236,7 +236,7 @@ int OctreeSendThread::packetDistributor(Node* node, OctreeQueryNode* nodeData, b
             if (forceDebugging || (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug())) {
                 qDebug("about to call handlePacketSend() .... line: %d -- format change "
                         "wantColor=%s wantCompression=%s SENDING PARTIAL PACKET! currentPacketIsColor=%s "
-                        "currentPacketIsCompressed=%s\n",
+                        "currentPacketIsCompressed=%s",
                         __LINE__,
                         debug::valueOf(wantColor), debug::valueOf(wantCompression),
                         debug::valueOf(nodeData->getCurrentPacketIsColor()),
@@ -245,7 +245,7 @@ int OctreeSendThread::packetDistributor(Node* node, OctreeQueryNode* nodeData, b
             packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent);
         } else {
             if (forceDebugging || (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug())) {
-                qDebug("wantColor=%s wantCompression=%s FIXING HEADER! currentPacketIsColor=%s currentPacketIsCompressed=%s\n",
+                qDebug("wantColor=%s wantCompression=%s FIXING HEADER! currentPacketIsColor=%s currentPacketIsCompressed=%s",
                         debug::valueOf(wantColor), debug::valueOf(wantCompression),
                         debug::valueOf(nodeData->getCurrentPacketIsColor()),
                         debug::valueOf(nodeData->getCurrentPacketIsCompressed()) );
@@ -257,7 +257,7 @@ int OctreeSendThread::packetDistributor(Node* node, OctreeQueryNode* nodeData, b
             targetSize = nodeData->getAvailable() - sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE);
         }
         if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) {
-            qDebug("line:%d _packetData.changeSettings() wantCompression=%s targetSize=%d\n", __LINE__,
+            qDebug("line:%d _packetData.changeSettings() wantCompression=%s targetSize=%d", __LINE__,
                 debug::valueOf(wantCompression), targetSize);
         }
 
@@ -265,7 +265,7 @@ int OctreeSendThread::packetDistributor(Node* node, OctreeQueryNode* nodeData, b
     }
 
     if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) {
-        qDebug("wantColor/isColor=%s/%s wantCompression/isCompressed=%s/%s viewFrustumChanged=%s, getWantLowResMoving()=%s\n",
+        qDebug("wantColor/isColor=%s/%s wantCompression/isCompressed=%s/%s viewFrustumChanged=%s, getWantLowResMoving()=%s",
                 debug::valueOf(wantColor), debug::valueOf(nodeData->getCurrentPacketIsColor()),
                 debug::valueOf(wantCompression), debug::valueOf(nodeData->getCurrentPacketIsCompressed()),
                 debug::valueOf(viewFrustumChanged), debug::valueOf(nodeData->getWantLowResMoving()));
@@ -274,7 +274,7 @@ int OctreeSendThread::packetDistributor(Node* node, OctreeQueryNode* nodeData, b
     const ViewFrustum* lastViewFrustum =  wantDelta ? &nodeData->getLastKnownViewFrustum() : NULL;
 
     if (forceDebugging || (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug())) {
-        qDebug("packetDistributor() viewFrustumChanged=%s, nodeBag.isEmpty=%s, viewSent=%s\n",
+        qDebug("packetDistributor() viewFrustumChanged=%s, nodeBag.isEmpty=%s, viewSent=%s",
                 debug::valueOf(viewFrustumChanged), debug::valueOf(nodeData->nodeBag.isEmpty()),
                 debug::valueOf(nodeData->getViewSent())
             );
@@ -285,7 +285,7 @@ int OctreeSendThread::packetDistributor(Node* node, OctreeQueryNode* nodeData, b
     if (viewFrustumChanged || nodeData->nodeBag.isEmpty()) {
         uint64_t now = usecTimestampNow();
         if (forceDebugging || (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug())) {
-            qDebug("(viewFrustumChanged=%s || nodeData->nodeBag.isEmpty() =%s)...\n",
+            qDebug("(viewFrustumChanged=%s || nodeData->nodeBag.isEmpty() =%s)...",
                    debug::valueOf(viewFrustumChanged), debug::valueOf(nodeData->nodeBag.isEmpty()));
             if (nodeData->getLastTimeBagEmpty() > 0) {
                 float elapsedSceneSend = (now - nodeData->getLastTimeBagEmpty()) / 1000000.0f;
@@ -294,7 +294,7 @@ int OctreeSendThread::packetDistributor(Node* node, OctreeQueryNode* nodeData, b
                 } else {
                     qDebug("elapsed time to send scene = %f seconds", elapsedSceneSend);
                 }
-                qDebug(" [occlusionCulling:%s, wantDelta:%s, wantColor:%s ]\n",
+                qDebug("[ occlusionCulling:%s, wantDelta:%s, wantColor:%s ]",
                        debug::valueOf(nodeData->getWantOcclusionCulling()), debug::valueOf(wantDelta),
                        debug::valueOf(wantColor));
             }
@@ -323,12 +323,12 @@ int OctreeSendThread::packetDistributor(Node* node, OctreeQueryNode* nodeData, b
         unsigned long elapsedTime = nodeData->stats.getElapsedTime();
 
         if (forceDebugging || (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug())) {
-            qDebug("about to call handlePacketSend() .... line: %d -- completed scene \n", __LINE__ );
+            qDebug("about to call handlePacketSend() .... line: %d -- completed scene", __LINE__ );
         }
         int packetsJustSent = handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent);
         packetsSentThisInterval += packetsJustSent;
         if (forceDebugging) {
-            qDebug("packetsJustSent=%d packetsSentThisInterval=%d\n", packetsJustSent, packetsSentThisInterval);
+            qDebug("packetsJustSent=%d packetsSentThisInterval=%d", packetsJustSent, packetsSentThisInterval);
         }
 
         if (forceDebugging || _myServer->wantsDebugSending()) {
@@ -338,7 +338,7 @@ int OctreeSendThread::packetDistributor(Node* node, OctreeQueryNode* nodeData, b
                 << " elapsed:" << elapsedTime
                 << " Packets:" << _totalPackets
                 << " Bytes:" << _totalBytes
-                << " Wasted:" << _totalWastedBytes << "\n";
+                << " Wasted:" << _totalWastedBytes;
         }
 
         // start tracking our stats
@@ -354,7 +354,7 @@ int OctreeSendThread::packetDistributor(Node* node, OctreeQueryNode* nodeData, b
             qDebug() << "Scene started at " << usecTimestampNow()
                 << " Packets:" << _totalPackets
                 << " Bytes:" << _totalBytes
-                << " Wasted:" << _totalWastedBytes << "\n";
+                << " Wasted:" << _totalWastedBytes;
         }
 
         ::startSceneSleepTime = _usleepTime;
@@ -382,7 +382,7 @@ int OctreeSendThread::packetDistributor(Node* node, OctreeQueryNode* nodeData, b
         int maxPacketsPerInterval = std::min(clientMaxPacketsPerInterval, _myServer->getPacketsPerClientPerInterval());
 
         if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) {
-            qDebug("truePacketsSent=%d packetsSentThisInterval=%d maxPacketsPerInterval=%d server PPI=%d nodePPS=%d nodePPI=%d\n",
+            qDebug("truePacketsSent=%d packetsSentThisInterval=%d maxPacketsPerInterval=%d server PPI=%d nodePPS=%d nodePPI=%d",
                 truePacketsSent, packetsSentThisInterval, maxPacketsPerInterval, _myServer->getPacketsPerClientPerInterval(),
                 nodeData->getMaxOctreePacketsPerSecond(), clientMaxPacketsPerInterval);
         }
@@ -391,7 +391,7 @@ int OctreeSendThread::packetDistributor(Node* node, OctreeQueryNode* nodeData, b
         bool completedScene = false;
         while (somethingToSend && packetsSentThisInterval < maxPacketsPerInterval) {
             if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) {
-                qDebug("truePacketsSent=%d packetsSentThisInterval=%d maxPacketsPerInterval=%d server PPI=%d nodePPS=%d nodePPI=%d\n",
+                qDebug("truePacketsSent=%d packetsSentThisInterval=%d maxPacketsPerInterval=%d server PPI=%d nodePPS=%d nodePPI=%d",
                     truePacketsSent, packetsSentThisInterval, maxPacketsPerInterval, _myServer->getPacketsPerClientPerInterval(),
                     nodeData->getMaxOctreePacketsPerSecond(), clientMaxPacketsPerInterval);
             }
@@ -471,14 +471,14 @@ int OctreeSendThread::packetDistributor(Node* node, OctreeQueryNode* nodeData, b
                     if (writtenSize > nodeData->getAvailable()) {
                         if (forceDebugging || (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug())) {
                             qDebug("about to call handlePacketSend() .... line: %d -- "
-                                   "writtenSize[%d] > available[%d] too big, sending packet as is.\n",
+                                   "writtenSize[%d] > available[%d] too big, sending packet as is.",
                                     __LINE__, writtenSize, nodeData->getAvailable());
                         }
                         packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent);
                     }
 
                     if (forceDebugging || (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug())) {
-                        qDebug(">>>>>> calling writeToPacket() available=%d compressedSize=%d uncompressedSize=%d target=%d\n",
+                        qDebug(">>>>>> calling writeToPacket() available=%d compressedSize=%d uncompressedSize=%d target=%d",
                                 nodeData->getAvailable(), _packetData.getFinalizedSize(),
                                 _packetData.getUncompressedSize(), _packetData.getTargetSize());
                     }
@@ -499,7 +499,7 @@ int OctreeSendThread::packetDistributor(Node* node, OctreeQueryNode* nodeData, b
                 int targetSize = MAX_OCTREE_PACKET_DATA_SIZE;
                 if (sendNow) {
                     if (forceDebugging) {
-                        qDebug("about to call handlePacketSend() .... line: %d -- sendNow = TRUE\n", __LINE__);
+                        qDebug("about to call handlePacketSend() .... line: %d -- sendNow = TRUE", __LINE__);
                     }
                     packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent);
                     if (wantCompression) {
@@ -515,7 +515,7 @@ int OctreeSendThread::packetDistributor(Node* node, OctreeQueryNode* nodeData, b
                     targetSize = nodeData->getAvailable() - sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE) - COMPRESS_PADDING;
                 }
                 if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) {
-                    qDebug("line:%d _packetData.changeSettings() wantCompression=%s targetSize=%d\n",__LINE__,
+                    qDebug("line:%d _packetData.changeSettings() wantCompression=%s targetSize=%d",__LINE__,
                         debug::valueOf(nodeData->getWantCompression()), targetSize);
                 }
                 _packetData.changeSettings(nodeData->getWantCompression(), targetSize); // will do reset
@@ -546,18 +546,18 @@ int OctreeSendThread::packetDistributor(Node* node, OctreeQueryNode* nodeData, b
             if (elapsedmsec > 1000) {
                 int elapsedsec = (end - start)/1000000;
                 qDebug("WARNING! packetLoop() took %d seconds [%d milliseconds %d calls in compress] "
-                        "to generate %d bytes in %d packets %d nodes still to send\n",
+                        "to generate %d bytes in %d packets %d nodes still to send",
                         elapsedsec, elapsedCompressTimeMsecs, elapsedCompressCalls,
                         trueBytesSent, truePacketsSent, nodeData->nodeBag.count());
             } else {
                 qDebug("WARNING! packetLoop() took %d milliseconds [%d milliseconds %d calls in compress] "
-                        "to generate %d bytes in %d packets, %d nodes still to send\n",
+                        "to generate %d bytes in %d packets, %d nodes still to send",
                         elapsedmsec, elapsedCompressTimeMsecs, elapsedCompressCalls,
                         trueBytesSent, truePacketsSent, nodeData->nodeBag.count());
             }
         } else if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) {
             qDebug("packetLoop() took %d milliseconds [%d milliseconds %d calls in compress] "
-                    "to generate %d bytes in %d packets, %d nodes still to send\n",
+                    "to generate %d bytes in %d packets, %d nodes still to send",
                     elapsedmsec, elapsedCompressTimeMsecs, elapsedCompressCalls,
                     trueBytesSent, truePacketsSent, nodeData->nodeBag.count());
         }
@@ -575,7 +575,7 @@ int OctreeSendThread::packetDistributor(Node* node, OctreeQueryNode* nodeData, b
 
         if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) {
             qDebug("truePacketsSent=%d packetsSentThisInterval=%d maxPacketsPerInterval=%d "
-                    "server PPI=%d nodePPS=%d nodePPI=%d\n",
+                    "server PPI=%d nodePPS=%d nodePPI=%d",
                     truePacketsSent, packetsSentThisInterval, maxPacketsPerInterval,
                     _myServer->getPacketsPerClientPerInterval(), nodeData->getMaxOctreePacketsPerSecond(),
                     clientMaxPacketsPerInterval);
diff --git a/libraries/octree-server/src/OctreeServer.cpp b/libraries/octree-server/src/OctreeServer.cpp
index 1b663503c7..e583d585c3 100644
--- a/libraries/octree-server/src/OctreeServer.cpp
+++ b/libraries/octree-server/src/OctreeServer.cpp
@@ -28,11 +28,7 @@ void OctreeServer::attachQueryNodeToNode(Node* newNode) {
     }
 }
 
-void OctreeServer::nodeAdded(Node* node) {
-    // do nothing
-}
-
-void OctreeServer::nodeKilled(Node* node) {
+void OctreeServer::nodeKilled(SharedNodePointer node) {
     // Use this to cleanup our node
     if (node->getType() == NODE_TYPE_AGENT) {
         OctreeQueryNode* nodeData = (OctreeQueryNode*)node->getLinkedData();
@@ -92,13 +88,10 @@ OctreeServer::~OctreeServer() {
         delete _persistThread;
     }
 
-    // tell our NodeList we're done with notifications
-    NodeList::getInstance()->removeHook(this);
-
     delete _jurisdiction;
     _jurisdiction = NULL;
-
-    qDebug() << "OctreeServer::run()... DONE\n";
+    
+    qDebug() << "OctreeServer::run()... DONE";
 }
 
 void OctreeServer::initMongoose(int port) {
@@ -128,7 +121,7 @@ int OctreeServer::civetwebRequestHandler(struct mg_connection* connection) {
 
 #ifdef FORCE_CRASH
     if (strcmp(ri->uri, "/force_crash") == 0 && strcmp(ri->request_method, "GET") == 0) {
-        qDebug() << "About to force a crash!\n";
+        qDebug() << "About to force a crash!";
         int foo;
         int* forceCrash = &foo;
         mg_printf(connection, "%s", "HTTP/1.0 200 OK\r\n\r\n");
@@ -459,9 +452,9 @@ void OctreeServer::setArguments(int argc, char** argv) {
     _argc = argc;
     _argv = const_cast<const char**>(argv);
 
-    qDebug("OctreeServer::setArguments()\n");
+    qDebug("OctreeServer::setArguments()");
     for (int i = 0; i < _argc; i++) {
-        qDebug("_argv[%d]=%s\n", i, _argv[i]);
+        qDebug("_argv[%d]=%s", i, _argv[i]);
     }
 
 }
@@ -476,7 +469,7 @@ void OctreeServer::parsePayload() {
 
         int argCount = configList.size() + 1;
 
-        qDebug("OctreeServer::parsePayload()... argCount=%d\n",argCount);
+        qDebug("OctreeServer::parsePayload()... argCount=%d",argCount);
 
         _parsedArgV = new char*[argCount];
         const char* dummy = "config-from-payload";
@@ -487,7 +480,7 @@ void OctreeServer::parsePayload() {
             QString configItem = configList.at(i-1);
             _parsedArgV[i] = new char[configItem.length() + sizeof(char)];
             strcpy(_parsedArgV[i], configItem.toLocal8Bit().constData());
-            qDebug("OctreeServer::parsePayload()... _parsedArgV[%d]=%s\n", i, _parsedArgV[i]);
+            qDebug("OctreeServer::parsePayload()... _parsedArgV[%d]=%s", i, _parsedArgV[i]);
         }
 
         setArguments(argCount, _parsedArgV);
@@ -502,7 +495,7 @@ void OctreeServer::processDatagram(const QByteArray& dataByteArray, const HifiSo
     if (packetType == getMyQueryMessageType()) {
         bool debug = false;
         if (debug) {
-            qDebug() << "Got PACKET_TYPE_VOXEL_QUERY at" << usecTimestampNow() << "\n";
+            qDebug() << "Got PACKET_TYPE_VOXEL_QUERY at" << usecTimestampNow();
         }
 
         int numBytesPacketHeader = numBytesForPacketHeader((unsigned char*) dataByteArray.data());
@@ -511,11 +504,11 @@ void OctreeServer::processDatagram(const QByteArray& dataByteArray, const HifiSo
         // need to make sure we have it in our nodeList.
         QUuid nodeUUID = QUuid::fromRfc4122(dataByteArray.mid(numBytesPacketHeader,
                                                               NUM_BYTES_RFC4122_UUID));
-
-        Node* node = nodeList->nodeWithUUID(nodeUUID);
-
+        
+        SharedNodePointer node = nodeList->nodeWithUUID(nodeUUID);
+        
         if (node) {
-            nodeList->updateNodeWithData(node, senderSockAddr, (unsigned char *) dataByteArray.data(),
+            nodeList->updateNodeWithData(node.data(), senderSockAddr, (unsigned char *) dataByteArray.data(),
                                          dataByteArray.size());
             if (!node->getActiveSocket()) {
                 // we don't have an active socket for this node, but they're talking to us
@@ -567,22 +560,22 @@ void OctreeServer::run() {
     const char* JURISDICTION_FILE = "--jurisdictionFile";
     const char* jurisdictionFile = getCmdOption(_argc, _argv, JURISDICTION_FILE);
     if (jurisdictionFile) {
-        qDebug("jurisdictionFile=%s\n", jurisdictionFile);
+        qDebug("jurisdictionFile=%s", jurisdictionFile);
 
-        qDebug("about to readFromFile().... jurisdictionFile=%s\n", jurisdictionFile);
+        qDebug("about to readFromFile().... jurisdictionFile=%s", jurisdictionFile);
         _jurisdiction = new JurisdictionMap(jurisdictionFile);
-        qDebug("after readFromFile().... jurisdictionFile=%s\n", jurisdictionFile);
+        qDebug("after readFromFile().... jurisdictionFile=%s", jurisdictionFile);
     } else {
         const char* JURISDICTION_ROOT = "--jurisdictionRoot";
         const char* jurisdictionRoot = getCmdOption(_argc, _argv, JURISDICTION_ROOT);
         if (jurisdictionRoot) {
-            qDebug("jurisdictionRoot=%s\n", jurisdictionRoot);
+            qDebug("jurisdictionRoot=%s", jurisdictionRoot);
         }
 
         const char* JURISDICTION_ENDNODES = "--jurisdictionEndNodes";
         const char* jurisdictionEndNodes = getCmdOption(_argc, _argv, JURISDICTION_ENDNODES);
         if (jurisdictionEndNodes) {
-            qDebug("jurisdictionEndNodes=%s\n", jurisdictionEndNodes);
+            qDebug("jurisdictionEndNodes=%s", jurisdictionEndNodes);
         }
 
         if (jurisdictionRoot || jurisdictionEndNodes) {
@@ -600,29 +593,29 @@ void OctreeServer::run() {
     setvbuf(stdout, NULL, _IOLBF, 0);
 
     // tell our NodeList about our desire to get notifications
-    nodeList->addHook(this);
+    connect(nodeList, SIGNAL(nodeKilled(SharedNodePointer)), SLOT(nodeKilled(SharedNodePointer)));
     nodeList->linkedDataCreateCallback = &OctreeServer::attachQueryNodeToNode;
 
     srand((unsigned)time(0));
 
     const char* VERBOSE_DEBUG = "--verboseDebug";
     _verboseDebug =  cmdOptionExists(_argc, _argv, VERBOSE_DEBUG);
-    qDebug("verboseDebug=%s\n", debug::valueOf(_verboseDebug));
+    qDebug("verboseDebug=%s", debug::valueOf(_verboseDebug));
 
     const char* DEBUG_SENDING = "--debugSending";
     _debugSending =  cmdOptionExists(_argc, _argv, DEBUG_SENDING);
-    qDebug("debugSending=%s\n", debug::valueOf(_debugSending));
+    qDebug("debugSending=%s", debug::valueOf(_debugSending));
 
     const char* DEBUG_RECEIVING = "--debugReceiving";
     _debugReceiving =  cmdOptionExists(_argc, _argv, DEBUG_RECEIVING);
-    qDebug("debugReceiving=%s\n", debug::valueOf(_debugReceiving));
+    qDebug("debugReceiving=%s", debug::valueOf(_debugReceiving));
 
     // By default we will persist, if you want to disable this, then pass in this parameter
     const char* NO_PERSIST = "--NoPersist";
     if (cmdOptionExists(_argc, _argv, NO_PERSIST)) {
         _wantPersist = false;
     }
-    qDebug("wantPersist=%s\n", debug::valueOf(_wantPersist));
+    qDebug("wantPersist=%s", debug::valueOf(_wantPersist));
 
     // if we want Persistence, set up the local file and persist thread
     if (_wantPersist) {
@@ -636,7 +629,7 @@ void OctreeServer::run() {
             strcpy(_persistFilename, getMyDefaultPersistFilename());
         }
 
-        qDebug("persistFilename=%s\n", _persistFilename);
+        qDebug("persistFilename=%s", _persistFilename);
 
         // now set up PersistThread
         _persistThread = new OctreePersistThread(_tree, _persistFilename);
@@ -653,7 +646,7 @@ void OctreeServer::run() {
     if (clockSkewOption) {
         int clockSkew = atoi(clockSkewOption);
         usecTimestampNowForceClockSkew(clockSkew);
-        qDebug("clockSkewOption=%s clockSkew=%d\n", clockSkewOption, clockSkew);
+        qDebug("clockSkewOption=%s clockSkew=%d", clockSkewOption, clockSkew);
     }
 
     // Check to see if the user passed in a command line option for setting packet send rate
@@ -664,7 +657,7 @@ void OctreeServer::run() {
         if (_packetsPerClientPerInterval < 1) {
             _packetsPerClientPerInterval = 1;
         }
-        qDebug("packetsPerSecond=%s PACKETS_PER_CLIENT_PER_INTERVAL=%d\n", packetsPerSecond, _packetsPerClientPerInterval);
+        qDebug("packetsPerSecond=%s PACKETS_PER_CLIENT_PER_INTERVAL=%d", packetsPerSecond, _packetsPerClientPerInterval);
     }
 
     HifiSockAddr senderSockAddr;
@@ -691,8 +684,8 @@ void OctreeServer::run() {
     if (gmtm != NULL) {
         strftime(utcBuffer, MAX_TIME_LENGTH, " [%m/%d/%Y %X UTC]", gmtm);
     }
-    qDebug() << "Now running... started at: " << localBuffer << utcBuffer << "\n";
-
+    qDebug() << "Now running... started at: " << localBuffer << utcBuffer;
+    
     QTimer* domainServerTimer = new QTimer(this);
     connect(domainServerTimer, SIGNAL(timeout()), this, SLOT(checkInWithDomainServerOrExit()));
     domainServerTimer->start(DOMAIN_SERVER_CHECK_IN_USECS / 1000);
diff --git a/libraries/octree-server/src/OctreeServer.h b/libraries/octree-server/src/OctreeServer.h
index 4de602aecb..708addfd1f 100644
--- a/libraries/octree-server/src/OctreeServer.h
+++ b/libraries/octree-server/src/OctreeServer.h
@@ -23,8 +23,9 @@
 #include "OctreeInboundPacketProcessor.h"
 
 /// Handles assignments of type OctreeServer - sending octrees to various clients.
-class OctreeServer : public ThreadedAssignment, public NodeListHook {
-public:
+class OctreeServer : public ThreadedAssignment {
+    Q_OBJECT
+public:                
     OctreeServer(const unsigned char* dataBuffer, int numBytes);
     ~OctreeServer();
 
@@ -60,15 +61,12 @@ public:
     virtual int sendSpecialPacket(Node* node) { return 0; }
 
     static void attachQueryNodeToNode(Node* newNode);
-
-    // NodeListHook
-    virtual void nodeAdded(Node* node);
-    virtual void nodeKilled(Node* node);
-
 public slots:
     /// runs the voxel server assignment
     void run();
     void processDatagram(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr);
+    
+    void nodeKilled(SharedNodePointer node);
 
 protected:
     int _argc;
diff --git a/libraries/octree/src/CoverageMap.cpp b/libraries/octree/src/CoverageMap.cpp
index ace29ccf57..a7717b8107 100644
--- a/libraries/octree/src/CoverageMap.cpp
+++ b/libraries/octree/src/CoverageMap.cpp
@@ -71,19 +71,19 @@ CoverageMap::~CoverageMap() {
 };
 
 void CoverageMap::printStats() {
-    qDebug("CoverageMap::printStats()...\n");
-    qDebug("MINIMUM_POLYGON_AREA_TO_STORE=%f\n",MINIMUM_POLYGON_AREA_TO_STORE);
-    qDebug("_mapCount=%d\n",_mapCount);
-    qDebug("_checkMapRootCalls=%d\n",_checkMapRootCalls);
-    qDebug("_notAllInView=%d\n",_notAllInView);
-    qDebug("_maxPolygonsUsed=%d\n",CoverageRegion::_maxPolygonsUsed);
-    qDebug("_totalPolygons=%d\n",CoverageRegion::_totalPolygons);
-    qDebug("_occlusionTests=%d\n",CoverageRegion::_occlusionTests);
-    qDebug("_regionSkips=%d\n",CoverageRegion::_regionSkips);
-    qDebug("_tooSmallSkips=%d\n",CoverageRegion::_tooSmallSkips);
-    qDebug("_regionFullSkips=%d\n",CoverageRegion::_regionFullSkips);
-    qDebug("_outOfOrderPolygon=%d\n",CoverageRegion::_outOfOrderPolygon);
-    qDebug("_clippedPolygons=%d\n",CoverageRegion::_clippedPolygons);
+    qDebug("CoverageMap::printStats()...");
+    qDebug("MINIMUM_POLYGON_AREA_TO_STORE=%f",MINIMUM_POLYGON_AREA_TO_STORE);
+    qDebug("_mapCount=%d",_mapCount);
+    qDebug("_checkMapRootCalls=%d",_checkMapRootCalls);
+    qDebug("_notAllInView=%d",_notAllInView);
+    qDebug("_maxPolygonsUsed=%d",CoverageRegion::_maxPolygonsUsed);
+    qDebug("_totalPolygons=%d",CoverageRegion::_totalPolygons);
+    qDebug("_occlusionTests=%d",CoverageRegion::_occlusionTests);
+    qDebug("_regionSkips=%d",CoverageRegion::_regionSkips);
+    qDebug("_tooSmallSkips=%d",CoverageRegion::_tooSmallSkips);
+    qDebug("_regionFullSkips=%d",CoverageRegion::_regionFullSkips);
+    qDebug("_outOfOrderPolygon=%d",CoverageRegion::_outOfOrderPolygon);
+    qDebug("_clippedPolygons=%d",CoverageRegion::_clippedPolygons);
 }
 
 void CoverageMap::erase() {
@@ -102,7 +102,7 @@ void CoverageMap::erase() {
     }
 
     if (_isRoot && wantDebugging) {
-        qDebug("CoverageMap last to be deleted...\n");
+        qDebug("CoverageMap last to be deleted...");
         printStats();
         
         CoverageRegion::_maxPolygonsUsed = 0;
diff --git a/libraries/octree/src/CoverageMapV2.cpp b/libraries/octree/src/CoverageMapV2.cpp
index 8353e02eef..afb341fcba 100644
--- a/libraries/octree/src/CoverageMapV2.cpp
+++ b/libraries/octree/src/CoverageMapV2.cpp
@@ -78,11 +78,11 @@ void CoverageMapV2::erase() {
     }
 
     if (_isRoot && wantDebugging) {
-        qDebug("CoverageMapV2 last to be deleted...\n");
-        qDebug("MINIMUM_POLYGON_AREA_TO_STORE=%f\n",MINIMUM_POLYGON_AREA_TO_STORE);
-        qDebug("_mapCount=%d\n",_mapCount);
-        qDebug("_checkMapRootCalls=%d\n",_checkMapRootCalls);
-        qDebug("_notAllInView=%d\n",_notAllInView);
+        qDebug("CoverageMapV2 last to be deleted...");
+        qDebug("MINIMUM_POLYGON_AREA_TO_STORE=%f",MINIMUM_POLYGON_AREA_TO_STORE);
+        qDebug("_mapCount=%d",_mapCount);
+        qDebug("_checkMapRootCalls=%d",_checkMapRootCalls);
+        qDebug("_notAllInView=%d",_notAllInView);
         _mapCount = 0;
         _checkMapRootCalls = 0;
         _notAllInView = 0;
diff --git a/libraries/octree/src/JurisdictionListener.cpp b/libraries/octree/src/JurisdictionListener.cpp
index 2080d0f2aa..ae27259f83 100644
--- a/libraries/octree/src/JurisdictionListener.cpp
+++ b/libraries/octree/src/JurisdictionListener.cpp
@@ -15,29 +15,20 @@
 #include <PacketHeaders.h>
 #include "JurisdictionListener.h"
 
-
 JurisdictionListener::JurisdictionListener(NODE_TYPE type, PacketSenderNotify* notify) : 
     PacketSender(notify, JurisdictionListener::DEFAULT_PACKETS_PER_SECOND)
 {
     _nodeType = type;
     ReceivedPacketProcessor::_dontSleep = true; // we handle sleeping so this class doesn't need to
     NodeList* nodeList = NodeList::getInstance();
-    nodeList->addHook(this);
-
+    
+    connect(nodeList, SIGNAL(nodeKilled(SharedNodePointer)), SLOT(nodeKilled(SharedNodePointer)));
+    
     //qDebug("JurisdictionListener::JurisdictionListener(NODE_TYPE type=%c)\n", type);
 
 }
 
-JurisdictionListener::~JurisdictionListener() {
-    NodeList* nodeList = NodeList::getInstance();
-    nodeList->removeHook(this);
-}
-
-void JurisdictionListener::nodeAdded(Node* node) {
-    // nothing to do. But need to implement it.
-}
-
-void JurisdictionListener::nodeKilled(Node* node) {
+void JurisdictionListener::nodeKilled(SharedNodePointer node) {
     if (_jurisdictions.find(node->getUUID()) != _jurisdictions.end()) {
         _jurisdictions.erase(_jurisdictions.find(node->getUUID()));
     }
@@ -52,8 +43,9 @@ bool JurisdictionListener::queueJurisdictionRequest() {
     int nodeCount = 0;
 
     NodeList* nodeList = NodeList::getInstance();
-    for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
-        if (nodeList->getNodeActiveSocketOrPing(&(*node)) && 
+    
+    foreach (const SharedNodePointer& node, nodeList->getNodeHash()) {
+        if (nodeList->getNodeActiveSocketOrPing(node.data()) &&
             node->getType() == getNodeType()) {
             const HifiSockAddr* nodeAddress = node->getActiveSocket();
             PacketSender::queuePacketForSending(*nodeAddress, bufferOut, sizeOut);
@@ -73,7 +65,7 @@ bool JurisdictionListener::queueJurisdictionRequest() {
 
 void JurisdictionListener::processPacket(const HifiSockAddr& senderAddress, unsigned char*  packetData, ssize_t packetLength) {
     if (packetData[0] == PACKET_TYPE_JURISDICTION) {
-        Node* node = NodeList::getInstance()->nodeWithAddress(senderAddress);
+        SharedNodePointer node = NodeList::getInstance()->nodeWithAddress(senderAddress);
         if (node) {
             QUuid nodeUUID = node->getUUID();
             JurisdictionMap map;
diff --git a/libraries/octree/src/JurisdictionListener.h b/libraries/octree/src/JurisdictionListener.h
index b8951683a5..393ca80420 100644
--- a/libraries/octree/src/JurisdictionListener.h
+++ b/libraries/octree/src/JurisdictionListener.h
@@ -15,32 +15,32 @@
 #include <PacketSender.h>
 #include <ReceivedPacketProcessor.h>
 
+
 #include "JurisdictionMap.h"
 
 /// Sends out PACKET_TYPE_JURISDICTION_REQUEST packets to all voxel servers and then listens for and processes
 /// the PACKET_TYPE_JURISDICTION packets it receives in order to maintain an accurate state of all jurisidictions
 /// within the domain. As with other ReceivedPacketProcessor classes the user is responsible for reading inbound packets
 /// and adding them to the processing queue by calling queueReceivedPacket()
-class JurisdictionListener : public NodeListHook, public PacketSender, public ReceivedPacketProcessor {
+class JurisdictionListener : public PacketSender, public ReceivedPacketProcessor {
 public:
     static const int DEFAULT_PACKETS_PER_SECOND = 1;
     static const int NO_SERVER_CHECK_RATE = 60; // if no servers yet detected, keep checking at 60fps
 
     JurisdictionListener(NODE_TYPE type = NODE_TYPE_VOXEL_SERVER, PacketSenderNotify* notify = NULL);
-    ~JurisdictionListener();
     
     virtual bool process();
 
     NodeToJurisdictionMap* getJurisdictions() { return &_jurisdictions; };
 
-    /// Called by NodeList to inform us that a node has been added.
-    void nodeAdded(Node* node);
-    /// Called by NodeList to inform us that a node has been killed.
-    void nodeKilled(Node* node);
 
     NODE_TYPE getNodeType() const { return _nodeType; }
     void setNodeType(NODE_TYPE type) { _nodeType = type; }
 
+public slots:
+    /// Called by NodeList to inform us that a node has been killed.
+    void nodeKilled(SharedNodePointer node);
+    
 protected:
     /// Callback for processing of received packets. Will process any queued PACKET_TYPE_JURISDICTION and update the
     /// jurisdiction map member variable
diff --git a/libraries/octree/src/JurisdictionMap.cpp b/libraries/octree/src/JurisdictionMap.cpp
index 0da13ee6ec..53cc955553 100644
--- a/libraries/octree/src/JurisdictionMap.cpp
+++ b/libraries/octree/src/JurisdictionMap.cpp
@@ -145,7 +145,7 @@ void myDebugPrintOctalCode(const unsigned char* octalCode, bool withNewLine) {
 
 JurisdictionMap::JurisdictionMap(const char* rootHexCode, const char* endNodesHexCodes) {
 
-    qDebug("JurisdictionMap::JurisdictionMap(const char* rootHexCode=[%p] %s, const char* endNodesHexCodes=[%p] %s)\n",
+    qDebug("JurisdictionMap::JurisdictionMap(const char* rootHexCode=[%p] %s, const char* endNodesHexCodes=[%p] %s)",
         rootHexCode, rootHexCode, endNodesHexCodes, endNodesHexCodes);
 
     _rootOctalCode = hexStringToOctalCode(QString(rootHexCode));
@@ -162,7 +162,7 @@ JurisdictionMap::JurisdictionMap(const char* rootHexCode, const char* endNodesHe
 
         unsigned char* endNodeOctcode = hexStringToOctalCode(endNodeHexString);
         
-        qDebug("JurisdictionMap::JurisdictionMap()  endNodeList(%d)=%s\n",
+        qDebug("JurisdictionMap::JurisdictionMap()  endNodeList(%d)=%s",
             i, endNodeHexString.toLocal8Bit().constData());
         
         //printOctalCode(endNodeOctcode);
@@ -209,7 +209,7 @@ bool JurisdictionMap::readFromFile(const char* filename) {
     QString     settingsFile(filename);
     QSettings   settings(settingsFile, QSettings::IniFormat);
     QString     rootCode = settings.value("root","00").toString();
-    qDebug() << "rootCode=" << rootCode << "\n";
+    qDebug() << "rootCode=" << rootCode;
 
     _rootOctalCode = hexStringToOctalCode(rootCode);
     printOctalCode(_rootOctalCode);
@@ -220,7 +220,7 @@ bool JurisdictionMap::readFromFile(const char* filename) {
     foreach (const QString &childKey, childKeys) {
         QString childValue = settings.value(childKey).toString();
         values.insert(childKey, childValue);
-        qDebug() << childKey << "=" << childValue << "\n";
+        qDebug() << childKey << "=" << childValue;
 
         unsigned char* octcode = hexStringToOctalCode(childValue);
         printOctalCode(octcode);
@@ -234,11 +234,11 @@ bool JurisdictionMap::readFromFile(const char* filename) {
 void JurisdictionMap::displayDebugDetails() const {
     QString rootNodeValue = octalCodeToHexString(_rootOctalCode);
 
-    qDebug() << "root:" << rootNodeValue << "\n";
+    qDebug() << "root:" << rootNodeValue;
     
     for (size_t i = 0; i < _endNodes.size(); i++) {
         QString value = octalCodeToHexString(_endNodes[i]);
-        qDebug() << "End node[" << i << "]: " << rootNodeValue << "\n";
+        qDebug() << "End node[" << i << "]: " << rootNodeValue;
     }
 }
 
diff --git a/libraries/octree/src/JurisdictionSender.cpp b/libraries/octree/src/JurisdictionSender.cpp
index c165f29ece..ab31f9356b 100644
--- a/libraries/octree/src/JurisdictionSender.cpp
+++ b/libraries/octree/src/JurisdictionSender.cpp
@@ -30,7 +30,7 @@ JurisdictionSender::~JurisdictionSender() {
 
 void JurisdictionSender::processPacket(const HifiSockAddr& senderAddress, unsigned char*  packetData, ssize_t packetLength) {
     if (packetData[0] == PACKET_TYPE_JURISDICTION_REQUEST) {
-        Node* node = NodeList::getInstance()->nodeWithAddress(senderAddress);
+        SharedNodePointer node = NodeList::getInstance()->nodeWithAddress(senderAddress);
         if (node) {
             QUuid nodeUUID = node->getUUID();
             lockRequestingNodes();
@@ -62,7 +62,7 @@ bool JurisdictionSender::process() {
 
             QUuid nodeUUID = _nodesRequestingJurisdictions.front();
             _nodesRequestingJurisdictions.pop();
-            Node* node = NodeList::getInstance()->nodeWithUUID(nodeUUID);
+            SharedNodePointer node = NodeList::getInstance()->nodeWithUUID(nodeUUID);
 
             if (node->getActiveSocket() != NULL) {
                 const HifiSockAddr* nodeAddress = node->getActiveSocket();
diff --git a/libraries/octree/src/JurisdictionSender.h b/libraries/octree/src/JurisdictionSender.h
index 77127e201f..441bb5ee1e 100644
--- a/libraries/octree/src/JurisdictionSender.h
+++ b/libraries/octree/src/JurisdictionSender.h
@@ -22,6 +22,7 @@
 /// to requesting parties. As with other ReceivedPacketProcessor classes the user is responsible for reading inbound packets
 /// and adding them to the processing queue by calling queueReceivedPacket()
 class JurisdictionSender : public PacketSender, public ReceivedPacketProcessor {
+    Q_OBJECT
 public:
     static const int DEFAULT_PACKETS_PER_SECOND = 1;
 
diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp
index b76468499e..c090ea1512 100644
--- a/libraries/octree/src/Octree.cpp
+++ b/libraries/octree/src/Octree.cpp
@@ -61,7 +61,7 @@ void Octree::recurseTreeWithOperation(RecurseOctreeOperation operation, void* ex
 void Octree::recurseNodeWithOperation(OctreeElement* node, RecurseOctreeOperation operation, void* extraData,
                         int recursionCount) {
     if (recursionCount > DANGEROUSLY_DEEP_RECURSION) {
-        qDebug() << "Octree::recurseNodeWithOperation() reached DANGEROUSLY_DEEP_RECURSION, bailing!\n";
+        qDebug() << "Octree::recurseNodeWithOperation() reached DANGEROUSLY_DEEP_RECURSION, bailing!";
         return;
     }
 
@@ -88,7 +88,7 @@ void Octree::recurseNodeWithOperationDistanceSorted(OctreeElement* node, Recurse
                                                        const glm::vec3& point, void* extraData, int recursionCount) {
 
     if (recursionCount > DANGEROUSLY_DEEP_RECURSION) {
-        qDebug() << "Octree::recurseNodeWithOperationDistanceSorted() reached DANGEROUSLY_DEEP_RECURSION, bailing!\n";
+        qDebug() << "Octree::recurseNodeWithOperationDistanceSorted() reached DANGEROUSLY_DEEP_RECURSION, bailing!";
         return;
     }
 
@@ -486,7 +486,7 @@ void Octree::reaverageOctreeElements(OctreeElement* startNode) {
             recursionCount++;
         }
         if (recursionCount > UNREASONABLY_DEEP_RECURSION) {
-            qDebug("Octree::reaverageOctreeElements()... bailing out of UNREASONABLY_DEEP_RECURSION\n");
+            qDebug("Octree::reaverageOctreeElements()... bailing out of UNREASONABLY_DEEP_RECURSION");
             recursionCount--;
             return;
         }
@@ -666,7 +666,7 @@ int Octree::encodeTreeBitstream(OctreeElement* node,
 
     // you can't call this without a valid node
     if (!node) {
-        qDebug("WARNING! encodeTreeBitstream() called with node=NULL\n");
+        qDebug("WARNING! encodeTreeBitstream() called with node=NULL");
         params.stopReason = EncodeBitstreamParams::NULL_NODE;
         return bytesWritten;
     }
@@ -755,7 +755,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* node,
 
     // you can't call this without a valid node
     if (!node) {
-        qDebug("WARNING! encodeTreeBitstreamRecursion() called with node=NULL\n");
+        qDebug("WARNING! encodeTreeBitstreamRecursion() called with node=NULL");
         params.stopReason = EncodeBitstreamParams::NULL_NODE;
         return bytesAtThisLevel;
     }
@@ -1304,7 +1304,7 @@ bool Octree::readFromSVOFile(const char* fileName) {
         emit importSize(1.0f, 1.0f, 1.0f);
         emit importProgress(0);
 
-        qDebug("loading file %s...\n", fileName);
+        qDebug("Loading file %s...", fileName);
 
         // get file length....
         unsigned long fileLength = file.tellg();
@@ -1333,10 +1333,10 @@ bool Octree::readFromSVOFile(const char* fileName) {
                     dataLength -= sizeof(expectedVersion);
                     fileOk = true;
                 } else {
-                    qDebug("SVO file version mismatch. Expected: %d Got: %d\n", expectedVersion, gotVersion);
+                    qDebug("SVO file version mismatch. Expected: %d Got: %d", expectedVersion, gotVersion);
                 }
             } else {
-                qDebug("SVO file type mismatch. Expected: %c Got: %c\n", expectedType, gotType);
+                qDebug("SVO file type mismatch. Expected: %c Got: %c", expectedType, gotType);
             }
         } else {
             fileOk = true; // assume the file is ok
@@ -1359,7 +1359,7 @@ void Octree::writeToSVOFile(const char* fileName, OctreeElement* node) {
     std::ofstream file(fileName, std::ios::out|std::ios::binary);
 
     if(file.is_open()) {
-        qDebug("saving to file %s...\n", fileName);
+        qDebug("Saving to file %s...", fileName);
 
         // before reading the file, check to see if this version of the Octree supports file versions
         if (getWantSVOfileVersions()) {
diff --git a/libraries/octree/src/OctreeEditPacketSender.cpp b/libraries/octree/src/OctreeEditPacketSender.cpp
index 9f7978c342..ff6a1ded61 100644
--- a/libraries/octree/src/OctreeEditPacketSender.cpp
+++ b/libraries/octree/src/OctreeEditPacketSender.cpp
@@ -57,14 +57,15 @@ bool OctreeEditPacketSender::serversExist() const {
     bool hasServers = false;
     bool atLeastOnJurisdictionMissing = false; // assume the best
     NodeList* nodeList = NodeList::getInstance();
-    for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
+    
+    foreach (const SharedNodePointer& node, nodeList->getNodeHash()) {
         // only send to the NodeTypes that are getMyNodeType()
         if (node->getType() == getMyNodeType()) {
-            if (nodeList->getNodeActiveSocketOrPing(&(*node))) {
+            if (nodeList->getNodeActiveSocketOrPing(node.data())) {
                 QUuid nodeUUID = node->getUUID();
                 // If we've got Jurisdictions set, then check to see if we know the jurisdiction for this server
                 if (_serverJurisdictions) {
-                    // lookup our nodeUUID in the jurisdiction map, if it's missing then we're 
+                    // lookup our nodeUUID in the jurisdiction map, if it's missing then we're
                     // missing at least one jurisdiction
                     if ((*_serverJurisdictions).find(nodeUUID) == (*_serverJurisdictions).end()) {
                         atLeastOnJurisdictionMissing = true;
@@ -77,6 +78,7 @@ bool OctreeEditPacketSender::serversExist() const {
             break; // no point in looking further...
         }
     }
+    
     return (hasServers && !atLeastOnJurisdictionMissing);
 }
 
@@ -84,11 +86,12 @@ bool OctreeEditPacketSender::serversExist() const {
 // a known nodeID. 
 void OctreeEditPacketSender::queuePacketToNode(const QUuid& nodeUUID, unsigned char* buffer, ssize_t length) {
     NodeList* nodeList = NodeList::getInstance();
-    for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
+    
+    foreach (const SharedNodePointer& node, nodeList->getNodeHash()) {
         // only send to the NodeTypes that are getMyNodeType()
         if (node->getType() == getMyNodeType() &&
             ((node->getUUID() == nodeUUID) || (nodeUUID.isNull()))) {
-            if (nodeList->getNodeActiveSocketOrPing(&(*node))) {
+            if (nodeList->getNodeActiveSocketOrPing(node.data())) {
                 const HifiSockAddr* nodeAddress = node->getActiveSocket();
                 queuePacketForSending(*nodeAddress, buffer, length);
                 
@@ -100,11 +103,12 @@ void OctreeEditPacketSender::queuePacketToNode(const QUuid& nodeUUID, unsigned c
                     uint64_t createdAt = (*((uint64_t*)(buffer + numBytesPacketHeader + sizeof(sequence))));
                     uint64_t queuedAt = usecTimestampNow();
                     uint64_t transitTime = queuedAt - createdAt;
+                    
                     qDebug() << "OctreeEditPacketSender::queuePacketToNode() queued " << buffer[0] << 
                             " - command to node bytes=" << length << 
                             " sequence=" << sequence << 
-                            " transitTimeSoFar=" << transitTime << " usecs\n";
-                }                
+                            " transitTimeSoFar=" << transitTime << " usecs";
+                }
             }
         }
     }
@@ -166,13 +170,13 @@ void OctreeEditPacketSender::queuePacketToNodes(unsigned char* buffer, ssize_t l
     // But we can't really do that with a packed message, since each edit message could be destined 
     // for a different server... So we need to actually manage multiple queued packets... one
     // for each server
-    NodeList* nodeList = NodeList::getInstance();
-    for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
+    
+    foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
         // only send to the NodeTypes that are getMyNodeType()
         if (node->getActiveSocket() != NULL && node->getType() == getMyNodeType()) {
             QUuid nodeUUID = node->getUUID();
             bool isMyJurisdiction = true;
-            // we need to get the jurisdiction for this 
+            // we need to get the jurisdiction for this
             // here we need to get the "pending packet" for this server
             const JurisdictionMap& map = (*_serverJurisdictions)[nodeUUID];
             isMyJurisdiction = (map.isMyJurisdiction(octCode, CHECK_NODE_ONLY) == JurisdictionMap::WITHIN);
@@ -212,15 +216,15 @@ void OctreeEditPacketSender::queueOctreeEditMessage(PACKET_TYPE type, unsigned c
     // But we can't really do that with a packed message, since each edit message could be destined 
     // for a different server... So we need to actually manage multiple queued packets... one
     // for each server
-    NodeList* nodeList = NodeList::getInstance();
-    for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
+    
+    foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
         // only send to the NodeTypes that are getMyNodeType()
         if (node->getActiveSocket() != NULL && node->getType() == getMyNodeType()) {
             QUuid nodeUUID = node->getUUID();
             bool isMyJurisdiction = true;
-
+            
             if (_serverJurisdictions) {
-                // we need to get the jurisdiction for this 
+                // we need to get the jurisdiction for this
                 // here we need to get the "pending packet" for this server
                 if ((*_serverJurisdictions).find(nodeUUID) != (*_serverJurisdictions).end()) {
                     const JurisdictionMap& map = (*_serverJurisdictions)[nodeUUID];
@@ -232,19 +236,19 @@ void OctreeEditPacketSender::queueOctreeEditMessage(PACKET_TYPE type, unsigned c
             if (isMyJurisdiction) {
                 EditPacketBuffer& packetBuffer = _pendingEditPackets[nodeUUID];
                 packetBuffer._nodeUUID = nodeUUID;
-            
+                
                 // If we're switching type, then we send the last one and start over
-                if ((type != packetBuffer._currentType && packetBuffer._currentSize > 0) || 
+                if ((type != packetBuffer._currentType && packetBuffer._currentSize > 0) ||
                     (packetBuffer._currentSize + length >= _maxPacketSize)) {
                     releaseQueuedPacket(packetBuffer);
                     initializePacket(packetBuffer, type);
                 }
-
+                
                 // If the buffer is empty and not correctly initialized for our type...
                 if (type != packetBuffer._currentType && packetBuffer._currentSize == 0) {
                     initializePacket(packetBuffer, type);
                 }
-
+                
                 // This is really the first time we know which server/node this particular edit message
                 // is going to, so we couldn't adjust for clock skew till now. But here's our chance.
                 // We call this virtual function that allows our specific type of EditPacketSender to
@@ -252,7 +256,7 @@ void OctreeEditPacketSender::queueOctreeEditMessage(PACKET_TYPE type, unsigned c
                 if (node->getClockSkewUsec() != 0) {
                     adjustEditPacketForClockSkew(codeColorBuffer, length, node->getClockSkewUsec());
                 }
-
+                
                 memcpy(&packetBuffer._currentBuffer[packetBuffer._currentSize], codeColorBuffer, length);
                 packetBuffer._currentSize += length;
             }
diff --git a/libraries/octree/src/OctreeElement.cpp b/libraries/octree/src/OctreeElement.cpp
index 31eb9a94bb..70c615e121 100644
--- a/libraries/octree/src/OctreeElement.cpp
+++ b/libraries/octree/src/OctreeElement.cpp
@@ -246,23 +246,25 @@ void OctreeElement::auditChildren(const char* label) const {
 
     const bool alwaysReport = false; // set this to true to get additional debugging
     if (alwaysReport || auditFailed) {
-        qDebug("%s... auditChildren() %s <<<< \n", label, (auditFailed ? "FAILED" : "PASSED"));
-        qDebug("    _childrenExternal=%s\n", debug::valueOf(_childrenExternal));
-        qDebug("    childCount=%d\n", getChildCount());
-        qDebug("    _childBitmask=");
-        outputBits(_childBitmask);
+        qDebug("%s... auditChildren() %s <<<<", label, (auditFailed ? "FAILED" : "PASSED"));
+        qDebug("    _childrenExternal=%s", debug::valueOf(_childrenExternal));
+        qDebug("    childCount=%d", getChildCount());
+
+        QDebug bitOutput = qDebug().nospace();
+        bitOutput << "    _childBitmask=";
+        outputBits(_childBitmask, bitOutput);
 
 
         for (int childIndex = 0; childIndex < NUMBER_OF_CHILDREN; childIndex++) {
             OctreeElement* testChildNew = getChildAtIndex(childIndex);
             OctreeElement* testChildOld = _childrenArray[childIndex];
 
-            qDebug("child at index %d... testChildOld=%p testChildNew=%p %s \n",
+            qDebug("child at index %d... testChildOld=%p testChildNew=%p %s",
                     childIndex, testChildOld, testChildNew ,
                     ((testChildNew != testChildOld) ? " DOES NOT MATCH <<<< BAD <<<<" : " - OK ")
             );
         }
-        qDebug("%s... auditChildren() <<<< DONE <<<< \n", label);
+        qDebug("%s... auditChildren() <<<< DONE <<<<", label);
     }
 }
 #endif // def HAS_AUDIT_CHILDREN
@@ -410,7 +412,8 @@ OctreeElement* OctreeElement::getChildAtIndex(int childIndex) const {
                         if (externalIndex < childCount && externalIndex >= 0) {
                             result = _children.external[externalIndex];
                         } else {
-                            qDebug("getChildAtIndex() attempt to access external client out of bounds externalIndex=%d <<<<<<<<<< WARNING!!! \n",externalIndex);
+                            qDebug("getChildAtIndex() attempt to access external client out of bounds externalIndex=%d <<<<<<<<<< WARNING!!!
+                                   ",externalIndex);
                         }
                         break;
                     }
@@ -420,7 +423,7 @@ OctreeElement* OctreeElement::getChildAtIndex(int childIndex) const {
     }
 #ifdef HAS_AUDIT_CHILDREN
     if (result != _childrenArray[childIndex]) {
-        qDebug("getChildAtIndex() case:%s result<%p> != _childrenArray[childIndex]<%p> <<<<<<<<<< WARNING!!! \n",
+        qDebug("getChildAtIndex() case:%s result<%p> != _childrenArray[childIndex]<%p> <<<<<<<<<< WARNING!!!",
             caseStr, result,_childrenArray[childIndex]);
     }
 #endif // def HAS_AUDIT_CHILDREN
@@ -1083,7 +1086,7 @@ void OctreeElement::setChildAtIndex(int childIndex, OctreeElement* child) {
         _externalChildrenMemoryUsage += newChildCount * sizeof(OctreeElement*);
     } else {
         //assert(false);
-        qDebug("THIS SHOULD NOT HAPPEN previousChildCount == %d && newChildCount == %d\n",previousChildCount, newChildCount);
+        qDebug("THIS SHOULD NOT HAPPEN previousChildCount == %d && newChildCount == %d",previousChildCount, newChildCount);
     }
 
     // check to see if we could store these 4 children locally
@@ -1123,7 +1126,7 @@ OctreeElement* OctreeElement::addChildAtIndex(int childIndex) {
 bool OctreeElement::safeDeepDeleteChildAtIndex(int childIndex, int recursionCount) {
     bool deleteApproved = false;
     if (recursionCount > DANGEROUSLY_DEEP_RECURSION) {
-        qDebug() << "OctreeElement::safeDeepDeleteChildAtIndex() reached DANGEROUSLY_DEEP_RECURSION, bailing!\n";
+        qDebug() << "OctreeElement::safeDeepDeleteChildAtIndex() reached DANGEROUSLY_DEEP_RECURSION, bailing!";
         return deleteApproved;
     }
     OctreeElement* childToDelete = getChildAtIndex(childIndex);
@@ -1162,13 +1165,17 @@ void OctreeElement::printDebugDetails(const char* label) const {
             setAtBit(childBits,i);
         }
     }
+    
+    QDebug elementDebug = qDebug().nospace();
 
-    qDebug("%s - Voxel at corner=(%f,%f,%f) size=%f\n isLeaf=%s isDirty=%s shouldRender=%s\n children=", label,
-        _box.getCorner().x, _box.getCorner().y, _box.getCorner().z, _box.getScale(),
-        debug::valueOf(isLeaf()), debug::valueOf(isDirty()), debug::valueOf(getShouldRender()));
+    QString resultString;
+    resultString.sprintf("%s - Voxel at corner=(%f,%f,%f) size=%f\n isLeaf=%s isDirty=%s shouldRender=%s\n children=", label,
+                         _box.getCorner().x, _box.getCorner().y, _box.getCorner().z, _box.getScale(),
+                         debug::valueOf(isLeaf()), debug::valueOf(isDirty()), debug::valueOf(getShouldRender()));
+    elementDebug << resultString;
 
-    outputBits(childBits, false);
-    qDebug("\n octalCode=");
+    outputBits(childBits, &elementDebug);
+    qDebug("octalCode=");
     printOctalCode(getOctalCode());
 }
 
diff --git a/libraries/octree/src/OctreePersistThread.cpp b/libraries/octree/src/OctreePersistThread.cpp
index 5564abc1df..052773f475 100644
--- a/libraries/octree/src/OctreePersistThread.cpp
+++ b/libraries/octree/src/OctreePersistThread.cpp
@@ -26,7 +26,7 @@ bool OctreePersistThread::process() {
 
     if (!_initialLoadComplete) {
         uint64_t loadStarted = usecTimestampNow();
-        qDebug() << "loading Octrees from file: " << _filename << "...\n";
+        qDebug() << "loading Octrees from file: " << _filename << "...";
 
         bool persistantFileRead;
 
@@ -41,20 +41,20 @@ bool OctreePersistThread::process() {
         _loadTimeUSecs = loadDone - loadStarted;
 
         _tree->clearDirtyBit(); // the tree is clean since we just loaded it
-        qDebug("DONE loading Octrees from file... fileRead=%s\n", debug::valueOf(persistantFileRead));
+        qDebug("DONE loading Octrees from file... fileRead=%s", debug::valueOf(persistantFileRead));
 
         unsigned long nodeCount = OctreeElement::getNodeCount();
         unsigned long internalNodeCount = OctreeElement::getInternalNodeCount();
         unsigned long leafNodeCount = OctreeElement::getLeafNodeCount();
-        qDebug("Nodes after loading scene %lu nodes %lu internal %lu leaves\n", nodeCount, internalNodeCount, leafNodeCount);
+        qDebug("Nodes after loading scene %lu nodes %lu internal %lu leaves", nodeCount, internalNodeCount, leafNodeCount);
 
         double usecPerGet = (double)OctreeElement::getGetChildAtIndexTime() / (double)OctreeElement::getGetChildAtIndexCalls();
         qDebug() << "getChildAtIndexCalls=" << OctreeElement::getGetChildAtIndexCalls()
-                << " getChildAtIndexTime=" << OctreeElement::getGetChildAtIndexTime() << " perGet=" << usecPerGet << " \n";
+                << " getChildAtIndexTime=" << OctreeElement::getGetChildAtIndexTime() << " perGet=" << usecPerGet;
 
         double usecPerSet = (double)OctreeElement::getSetChildAtIndexTime() / (double)OctreeElement::getSetChildAtIndexCalls();
         qDebug() << "setChildAtIndexCalls=" << OctreeElement::getSetChildAtIndexCalls()
-                << " setChildAtIndexTime=" << OctreeElement::getSetChildAtIndexTime() << " perset=" << usecPerSet << " \n";
+                << " setChildAtIndexTime=" << OctreeElement::getSetChildAtIndexTime() << " perset=" << usecPerSet;
 
         _initialLoadComplete = true;
         _lastCheck = usecTimestampNow(); // we just loaded, no need to save again
@@ -80,10 +80,10 @@ bool OctreePersistThread::process() {
             // check the dirty bit and persist here...
             _lastCheck = usecTimestampNow();
             if (_tree->isDirty()) {
-                qDebug() << "saving Octrees to file " << _filename << "...\n";
+                qDebug() << "saving Octrees to file " << _filename << "...";
                 _tree->writeToSVOFile(_filename.toLocal8Bit().constData());
                 _tree->clearDirtyBit(); // tree is clean after saving
-                qDebug("DONE saving Octrees to file...\n");
+                qDebug("DONE saving Octrees to file...");
             }
         }
     }
diff --git a/libraries/octree/src/OctreeProjectedPolygon.cpp b/libraries/octree/src/OctreeProjectedPolygon.cpp
index 0f9e66c42a..6e5cea28cd 100644
--- a/libraries/octree/src/OctreeProjectedPolygon.cpp
+++ b/libraries/octree/src/OctreeProjectedPolygon.cpp
@@ -90,13 +90,9 @@ void BoundingBox::explandToInclude(const BoundingBox& box) {
 
 
 void BoundingBox::printDebugDetails(const char* label) const {
-    if (label) {
-        qDebug() << label;
-    } else {
-        qDebug("BoundingBox");
-    }
-    qDebug("\n    _set=%s\n    corner=%f,%f size=%f,%f\n    bounds=[(%f,%f) to (%f,%f)]\n", 
-        debug::valueOf(_set), corner.x, corner.y, size.x, size.y, corner.x, corner.y, corner.x+size.x, corner.y+size.y);
+    qDebug("%s _set=%s\n    corner=%f,%f size=%f,%f\n    bounds=[(%f,%f) to (%f,%f)]",
+           (label ? label : "BoundingBox"),
+           debug::valueOf(_set), corner.x, corner.y, size.x, size.y, corner.x, corner.y, corner.x+size.x, corner.y+size.y);
 }
 
 
diff --git a/libraries/octree/src/OctreeRenderer.cpp b/libraries/octree/src/OctreeRenderer.cpp
index 0482a38b5b..63cef54c7d 100644
--- a/libraries/octree/src/OctreeRenderer.cpp
+++ b/libraries/octree/src/OctreeRenderer.cpp
@@ -65,10 +65,9 @@ void OctreeRenderer::processDatagram(const QByteArray& dataByteArray, const Hifi
 
         if (extraDebugging) {
             qDebug("OctreeRenderer::processDatagram() ... Got Packet Section"
-                   " color:%s compressed:%s sequence: %u flight:%d usec size:%d data:%d"
-                   "\n",
-                debug::valueOf(packetIsColored), debug::valueOf(packetIsCompressed), 
-                sequence, flightTime, packetLength, dataBytes);
+                   " color:%s compressed:%s sequence: %u flight:%d usec size:%d data:%d",
+                   debug::valueOf(packetIsColored), debug::valueOf(packetIsCompressed),
+                   sequence, flightTime, packetLength, dataBytes);
         }
         
         int subsection = 1;
@@ -96,9 +95,10 @@ void OctreeRenderer::processDatagram(const QByteArray& dataByteArray, const Hifi
                 if (extraDebugging) {
                     qDebug("OctreeRenderer::processDatagram() ... Got Packet Section"
                            " color:%s compressed:%s sequence: %u flight:%d usec size:%d data:%d"
-                           " subsection:%d sectionLength:%d uncompressed:%d\n",
-                        debug::valueOf(packetIsColored), debug::valueOf(packetIsCompressed), 
-                        sequence, flightTime, packetLength, dataBytes, subsection, sectionLength, packetData.getUncompressedSize());
+                           " subsection:%d sectionLength:%d uncompressed:%d",
+                           debug::valueOf(packetIsColored), debug::valueOf(packetIsCompressed),
+                           sequence, flightTime, packetLength, dataBytes, subsection, sectionLength,
+                           packetData.getUncompressedSize());
                 }
                 _tree->readBitstreamToTree(packetData.getUncompressedData(), packetData.getUncompressedSize(), args);
                 _tree->unlock();
diff --git a/libraries/octree/src/OctreeSceneStats.cpp b/libraries/octree/src/OctreeSceneStats.cpp
index f36e387a6d..35fe8a5d16 100644
--- a/libraries/octree/src/OctreeSceneStats.cpp
+++ b/libraries/octree/src/OctreeSceneStats.cpp
@@ -624,52 +624,51 @@ int OctreeSceneStats::unpackFromMessage(unsigned char* sourceBuffer, int availab
 
 
 void OctreeSceneStats::printDebugDetails() {
-    qDebug("\n------------------------------\n");
-    qDebug("OctreeSceneStats:\n");
-    qDebug("    start    : %llu \n", (long long unsigned int)_start);
-    qDebug("    end      : %llu \n", (long long unsigned int)_end);
-    qDebug("    elapsed  : %llu \n", (long long unsigned int)_elapsed);
-    qDebug("    encoding : %llu \n", (long long unsigned int)_totalEncodeTime);
-    qDebug("\n");
-    qDebug("    full scene: %s\n", debug::valueOf(_isFullScene));
-    qDebug("    moving: %s\n", debug::valueOf(_isMoving));
-    qDebug("\n");
-    qDebug("    packets: %d\n", _packets);
-    qDebug("    bytes  : %ld\n", _bytes);
-    qDebug("\n");
-    qDebug("    total elements      : %lu\n", _totalElements              );
-    qDebug("        internal        : %lu\n", _totalInternal            );
-    qDebug("        leaves          : %lu\n", _totalLeaves              );
-    qDebug("    traversed           : %lu\n", _traversed                );
-    qDebug("        internal        : %lu\n", _internal                 );
-    qDebug("        leaves          : %lu\n", _leaves                   );
-    qDebug("    skipped distance    : %lu\n", _skippedDistance          );
-    qDebug("        internal        : %lu\n", _internalSkippedDistance  );
-    qDebug("        leaves          : %lu\n", _leavesSkippedDistance    );
-    qDebug("    skipped out of view : %lu\n", _skippedOutOfView         );
-    qDebug("        internal        : %lu\n", _internalSkippedOutOfView );
-    qDebug("        leaves          : %lu\n", _leavesSkippedOutOfView   );
-    qDebug("    skipped was in view : %lu\n", _skippedWasInView         );
-    qDebug("        internal        : %lu\n", _internalSkippedWasInView );
-    qDebug("        leaves          : %lu\n", _leavesSkippedWasInView   );
-    qDebug("    skipped no change   : %lu\n", _skippedNoChange          );
-    qDebug("        internal        : %lu\n", _internalSkippedNoChange  );
-    qDebug("        leaves          : %lu\n", _leavesSkippedNoChange    );
-    qDebug("    skipped occluded    : %lu\n", _skippedOccluded          );
-    qDebug("        internal        : %lu\n", _internalSkippedOccluded  );
-    qDebug("        leaves          : %lu\n", _leavesSkippedOccluded    );
-
-    qDebug("\n");
-    qDebug("    color sent          : %lu\n", _colorSent                );
-    qDebug("        internal        : %lu\n", _internalColorSent        );
-    qDebug("        leaves          : %lu\n", _leavesColorSent          );
-    qDebug("    Didn't Fit          : %lu\n", _didntFit                 );
-    qDebug("        internal        : %lu\n", _internalDidntFit         );
-    qDebug("        leaves          : %lu\n", _leavesDidntFit           );
-    qDebug("    color bits          : %lu\n", _colorBitsWritten         );
-    qDebug("    exists bits         : %lu\n", _existsBitsWritten        );
-    qDebug("    in packet bit       : %lu\n", _existsInPacketBitsWritten);
-    qDebug("    trees removed       : %lu\n", _treesRemoved             );
+    qDebug("\n------------------------------");
+    qDebug("OctreeSceneStats:");
+    qDebug("    start    : %llu", (long long unsigned int)_start);
+    qDebug("    end      : %llu", (long long unsigned int)_end);
+    qDebug("    elapsed  : %llu", (long long unsigned int)_elapsed);
+    qDebug("    encoding : %llu", (long long unsigned int)_totalEncodeTime);
+    qDebug();
+    qDebug("    full scene: %s", debug::valueOf(_isFullScene));
+    qDebug("    moving: %s", debug::valueOf(_isMoving));
+    qDebug();
+    qDebug("    packets: %d", _packets);
+    qDebug("    bytes  : %ld", _bytes);
+    qDebug();
+    qDebug("    total elements      : %lu", _totalElements              );
+    qDebug("        internal        : %lu", _totalInternal            );
+    qDebug("        leaves          : %lu", _totalLeaves              );
+    qDebug("    traversed           : %lu", _traversed                );
+    qDebug("        internal        : %lu", _internal                 );
+    qDebug("        leaves          : %lu", _leaves                   );
+    qDebug("    skipped distance    : %lu", _skippedDistance          );
+    qDebug("        internal        : %lu", _internalSkippedDistance  );
+    qDebug("        leaves          : %lu", _leavesSkippedDistance    );
+    qDebug("    skipped out of view : %lu", _skippedOutOfView         );
+    qDebug("        internal        : %lu", _internalSkippedOutOfView );
+    qDebug("        leaves          : %lu", _leavesSkippedOutOfView   );
+    qDebug("    skipped was in view : %lu", _skippedWasInView         );
+    qDebug("        internal        : %lu", _internalSkippedWasInView );
+    qDebug("        leaves          : %lu", _leavesSkippedWasInView   );
+    qDebug("    skipped no change   : %lu", _skippedNoChange          );
+    qDebug("        internal        : %lu", _internalSkippedNoChange  );
+    qDebug("        leaves          : %lu", _leavesSkippedNoChange    );
+    qDebug("    skipped occluded    : %lu", _skippedOccluded          );
+    qDebug("        internal        : %lu", _internalSkippedOccluded  );
+    qDebug("        leaves          : %lu", _leavesSkippedOccluded    );
+    qDebug();
+    qDebug("    color sent          : %lu", _colorSent                );
+    qDebug("        internal        : %lu", _internalColorSent        );
+    qDebug("        leaves          : %lu", _leavesColorSent          );
+    qDebug("    Didn't Fit          : %lu", _didntFit                 );
+    qDebug("        internal        : %lu", _internalDidntFit         );
+    qDebug("        leaves          : %lu", _leavesDidntFit           );
+    qDebug("    color bits          : %lu", _colorBitsWritten         );
+    qDebug("    exists bits         : %lu", _existsBitsWritten        );
+    qDebug("    in packet bit       : %lu", _existsInPacketBitsWritten);
+    qDebug("    trees removed       : %lu", _treesRemoved             );
 }
 
 OctreeSceneStats::ItemInfo OctreeSceneStats::_ITEMS[] = {
diff --git a/libraries/octree/src/ViewFrustum.cpp b/libraries/octree/src/ViewFrustum.cpp
index d556dc68d3..b6fdcc3e99 100644
--- a/libraries/octree/src/ViewFrustum.cpp
+++ b/libraries/octree/src/ViewFrustum.cpp
@@ -326,43 +326,43 @@ bool ViewFrustum::matches(const ViewFrustum& compareTo, bool debug) const {
            testMatches(compareTo._eyeOffsetOrientation, _eyeOffsetOrientation);
 
     if (!result && debug) {
-        qDebug("ViewFrustum::matches()... result=%s\n", debug::valueOf(result));
-        qDebug("%s -- compareTo._position=%f,%f,%f _position=%f,%f,%f\n",
+        qDebug("ViewFrustum::matches()... result=%s", debug::valueOf(result));
+        qDebug("%s -- compareTo._position=%f,%f,%f _position=%f,%f,%f",
             (testMatches(compareTo._position,_position) ? "MATCHES " : "NO MATCH"),
             compareTo._position.x, compareTo._position.y, compareTo._position.z,
             _position.x, _position.y, _position.z );
-        qDebug("%s -- compareTo._direction=%f,%f,%f _direction=%f,%f,%f\n",
+        qDebug("%s -- compareTo._direction=%f,%f,%f _direction=%f,%f,%f",
             (testMatches(compareTo._direction, _direction) ? "MATCHES " : "NO MATCH"),
             compareTo._direction.x, compareTo._direction.y, compareTo._direction.z,
             _direction.x, _direction.y, _direction.z );
-        qDebug("%s -- compareTo._up=%f,%f,%f _up=%f,%f,%f\n",
+        qDebug("%s -- compareTo._up=%f,%f,%f _up=%f,%f,%f",
             (testMatches(compareTo._up, _up) ? "MATCHES " : "NO MATCH"),
             compareTo._up.x, compareTo._up.y, compareTo._up.z,
             _up.x, _up.y, _up.z );
-        qDebug("%s -- compareTo._right=%f,%f,%f _right=%f,%f,%f\n",
+        qDebug("%s -- compareTo._right=%f,%f,%f _right=%f,%f,%f",
             (testMatches(compareTo._right, _right) ? "MATCHES " : "NO MATCH"),
             compareTo._right.x, compareTo._right.y, compareTo._right.z,
             _right.x, _right.y, _right.z );
-        qDebug("%s -- compareTo._fieldOfView=%f _fieldOfView=%f\n",
+        qDebug("%s -- compareTo._fieldOfView=%f _fieldOfView=%f",
             (testMatches(compareTo._fieldOfView, _fieldOfView) ? "MATCHES " : "NO MATCH"),
             compareTo._fieldOfView, _fieldOfView);
-        qDebug("%s -- compareTo._aspectRatio=%f _aspectRatio=%f\n",
+        qDebug("%s -- compareTo._aspectRatio=%f _aspectRatio=%f",
             (testMatches(compareTo._aspectRatio, _aspectRatio) ? "MATCHES " : "NO MATCH"),
             compareTo._aspectRatio, _aspectRatio);
-        qDebug("%s -- compareTo._nearClip=%f _nearClip=%f\n",
+        qDebug("%s -- compareTo._nearClip=%f _nearClip=%f",
             (testMatches(compareTo._nearClip, _nearClip) ? "MATCHES " : "NO MATCH"),
             compareTo._nearClip, _nearClip);
-        qDebug("%s -- compareTo._farClip=%f _farClip=%f\n",
+        qDebug("%s -- compareTo._farClip=%f _farClip=%f",
             (testMatches(compareTo._farClip, _farClip) ? "MATCHES " : "NO MATCH"),
             compareTo._farClip, _farClip);
-        qDebug("%s -- compareTo._focalLength=%f _focalLength=%f\n",
+        qDebug("%s -- compareTo._focalLength=%f _focalLength=%f",
             (testMatches(compareTo._focalLength, _focalLength) ? "MATCHES " : "NO MATCH"),
             compareTo._focalLength, _focalLength);
-        qDebug("%s -- compareTo._eyeOffsetPosition=%f,%f,%f _eyeOffsetPosition=%f,%f,%f\n",
+        qDebug("%s -- compareTo._eyeOffsetPosition=%f,%f,%f _eyeOffsetPosition=%f,%f,%f",
             (testMatches(compareTo._eyeOffsetPosition, _eyeOffsetPosition) ? "MATCHES " : "NO MATCH"),
             compareTo._eyeOffsetPosition.x, compareTo._eyeOffsetPosition.y, compareTo._eyeOffsetPosition.z,
             _eyeOffsetPosition.x, _eyeOffsetPosition.y, _eyeOffsetPosition.z);
-        qDebug("%s -- compareTo._eyeOffsetOrientation=%f,%f,%f,%f _eyeOffsetOrientation=%f,%f,%f,%f\n",
+        qDebug("%s -- compareTo._eyeOffsetOrientation=%f,%f,%f,%f _eyeOffsetOrientation=%f,%f,%f,%f",
             (testMatches(compareTo._eyeOffsetOrientation, _eyeOffsetOrientation) ? "MATCHES " : "NO MATCH"),
             compareTo._eyeOffsetOrientation.x, compareTo._eyeOffsetOrientation.y,
                 compareTo._eyeOffsetOrientation.z, compareTo._eyeOffsetOrientation.w,
@@ -413,45 +413,45 @@ bool ViewFrustum::isVerySimilar(const ViewFrustum& compareTo, bool debug) const
 
     if (!result && debug) {
         qDebug("ViewFrustum::isVerySimilar()... result=%s\n", debug::valueOf(result));
-        qDebug("%s -- compareTo._position=%f,%f,%f _position=%f,%f,%f\n",
+        qDebug("%s -- compareTo._position=%f,%f,%f _position=%f,%f,%f",
             (testMatches(compareTo._position,_position, POSITION_SIMILAR_ENOUGH) ? "IS SIMILAR ENOUGH " : "IS NOT SIMILAR ENOUGH"),
             compareTo._position.x, compareTo._position.y, compareTo._position.z,
             _position.x, _position.y, _position.z );
 
-        qDebug("%s -- positionDistance=%f\n",
+        qDebug("%s -- positionDistance=%f",
             (testMatches(0,positionDistance, POSITION_SIMILAR_ENOUGH) ? "IS SIMILAR ENOUGH " : "IS NOT SIMILAR ENOUGH"),
             positionDistance);
 
-        qDebug("%s -- angleOrientation=%f\n",
+        qDebug("%s -- angleOrientation=%f",
             (testMatches(0, angleOrientation, ORIENTATION_SIMILAR_ENOUGH) ? "IS SIMILAR ENOUGH " : "IS NOT SIMILAR ENOUGH"),
             angleOrientation);
-
-        qDebug("%s -- compareTo._fieldOfView=%f _fieldOfView=%f\n",
+        
+        qDebug("%s -- compareTo._fieldOfView=%f _fieldOfView=%f",
             (testMatches(compareTo._fieldOfView, _fieldOfView) ? "MATCHES " : "NO MATCH"),
             compareTo._fieldOfView, _fieldOfView);
-        qDebug("%s -- compareTo._aspectRatio=%f _aspectRatio=%f\n",
+        qDebug("%s -- compareTo._aspectRatio=%f _aspectRatio=%f",
             (testMatches(compareTo._aspectRatio, _aspectRatio) ? "MATCHES " : "NO MATCH"),
             compareTo._aspectRatio, _aspectRatio);
-        qDebug("%s -- compareTo._nearClip=%f _nearClip=%f\n",
+        qDebug("%s -- compareTo._nearClip=%f _nearClip=%f",
             (testMatches(compareTo._nearClip, _nearClip) ? "MATCHES " : "NO MATCH"),
             compareTo._nearClip, _nearClip);
-        qDebug("%s -- compareTo._farClip=%f _farClip=%f\n",
+        qDebug("%s -- compareTo._farClip=%f _farClip=%f",
             (testMatches(compareTo._farClip, _farClip) ? "MATCHES " : "NO MATCH"),
             compareTo._farClip, _farClip);
-        qDebug("%s -- compareTo._focalLength=%f _focalLength=%f\n",
+        qDebug("%s -- compareTo._focalLength=%f _focalLength=%f",
             (testMatches(compareTo._focalLength, _focalLength) ? "MATCHES " : "NO MATCH"),
             compareTo._focalLength, _focalLength);
 
-        qDebug("%s -- compareTo._eyeOffsetPosition=%f,%f,%f _eyeOffsetPosition=%f,%f,%f\n",
+        qDebug("%s -- compareTo._eyeOffsetPosition=%f,%f,%f _eyeOffsetPosition=%f,%f,%f",
             (testMatches(compareTo._eyeOffsetPosition, _eyeOffsetPosition, POSITION_SIMILAR_ENOUGH) ? "IS SIMILAR ENOUGH " : "IS NOT SIMILAR ENOUGH"),
             compareTo._eyeOffsetPosition.x, compareTo._eyeOffsetPosition.y, compareTo._eyeOffsetPosition.z,
             _eyeOffsetPosition.x, _eyeOffsetPosition.y, _eyeOffsetPosition.z);
 
-        qDebug("%s -- eyeOffsetpositionDistance=%f\n",
+        qDebug("%s -- eyeOffsetpositionDistance=%f",
             (testMatches(0,eyeOffsetpositionDistance, EYEOFFSET_POSITION_SIMILAR_ENOUGH) ? "IS SIMILAR ENOUGH " : "IS NOT SIMILAR ENOUGH"),
             eyeOffsetpositionDistance);
 
-        qDebug("%s -- angleEyeOffsetOrientation=%f\n",
+        qDebug("%s -- angleEyeOffsetOrientation=%f",
             (testMatches(0, angleEyeOffsetOrientation, ORIENTATION_SIMILAR_ENOUGH) ? "IS SIMILAR ENOUGH " : "IS NOT SIMILAR ENOUGH"),
             angleEyeOffsetOrientation);
     }
@@ -518,19 +518,19 @@ void ViewFrustum::computeOffAxisFrustum(float& left, float& right, float& bottom
 }
 
 void ViewFrustum::printDebugDetails() const {
-    qDebug("ViewFrustum::printDebugDetails()... \n");
-    qDebug("_position=%f,%f,%f\n",  _position.x, _position.y, _position.z );
-    qDebug("_direction=%f,%f,%f\n", _direction.x, _direction.y, _direction.z );
-    qDebug("_up=%f,%f,%f\n", _up.x, _up.y, _up.z );
-    qDebug("_right=%f,%f,%f\n", _right.x, _right.y, _right.z );
-    qDebug("_fieldOfView=%f\n", _fieldOfView);
-    qDebug("_aspectRatio=%f\n", _aspectRatio);
-    qDebug("_keyHoleRadius=%f\n", _keyholeRadius);
-    qDebug("_nearClip=%f\n", _nearClip);
-    qDebug("_farClip=%f\n", _farClip);
-    qDebug("_focalLength=%f\n", _focalLength);
-    qDebug("_eyeOffsetPosition=%f,%f,%f\n",  _eyeOffsetPosition.x, _eyeOffsetPosition.y, _eyeOffsetPosition.z );
-    qDebug("_eyeOffsetOrientation=%f,%f,%f,%f\n",  _eyeOffsetOrientation.x, _eyeOffsetOrientation.y, _eyeOffsetOrientation.z,
+    qDebug("ViewFrustum::printDebugDetails()...");
+    qDebug("_position=%f,%f,%f",  _position.x, _position.y, _position.z );
+    qDebug("_direction=%f,%f,%f", _direction.x, _direction.y, _direction.z );
+    qDebug("_up=%f,%f,%f", _up.x, _up.y, _up.z );
+    qDebug("_right=%f,%f,%f", _right.x, _right.y, _right.z );
+    qDebug("_fieldOfView=%f", _fieldOfView);
+    qDebug("_aspectRatio=%f", _aspectRatio);
+    qDebug("_keyHoleRadius=%f", _keyholeRadius);
+    qDebug("_nearClip=%f", _nearClip);
+    qDebug("_farClip=%f", _farClip);
+    qDebug("_focalLength=%f", _focalLength);
+    qDebug("_eyeOffsetPosition=%f,%f,%f",  _eyeOffsetPosition.x, _eyeOffsetPosition.y, _eyeOffsetPosition.z );
+    qDebug("_eyeOffsetOrientation=%f,%f,%f,%f",  _eyeOffsetOrientation.x, _eyeOffsetOrientation.y, _eyeOffsetOrientation.z,
         _eyeOffsetOrientation.w );
 }
 
diff --git a/libraries/particles/src/Particle.cpp b/libraries/particles/src/Particle.cpp
index 5345e15bd0..dcb344f164 100644
--- a/libraries/particles/src/Particle.cpp
+++ b/libraries/particles/src/Particle.cpp
@@ -467,10 +467,10 @@ void Particle::adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, ssiz
     memcpy(dataAt, &lastEditedInServerTime, sizeof(lastEditedInServerTime));
     const bool wantDebug = false;
     if (wantDebug) {
-        qDebug("Particle::adjustEditPacketForClockSkew()...\n");
-        qDebug() << "     lastEditedInLocalTime: " << lastEditedInLocalTime << "\n";
-        qDebug() << "                 clockSkew: " << clockSkew << "\n";
-        qDebug() << "    lastEditedInServerTime: " << lastEditedInServerTime << "\n";
+        qDebug("Particle::adjustEditPacketForClockSkew()...");
+        qDebug() << "     lastEditedInLocalTime: " << lastEditedInLocalTime;
+        qDebug() << "                 clockSkew: " << clockSkew;
+        qDebug() << "    lastEditedInServerTime: " << lastEditedInServerTime;
     }
 }
 
diff --git a/libraries/particles/src/ParticleCollisionSystem.cpp b/libraries/particles/src/ParticleCollisionSystem.cpp
index 24d907667a..f478fe9cf1 100644
--- a/libraries/particles/src/ParticleCollisionSystem.cpp
+++ b/libraries/particles/src/ParticleCollisionSystem.cpp
@@ -188,22 +188,22 @@ void ParticleCollisionSystem::updateCollisionWithAvatars(Particle* particle) {
     }
 
     // loop through all the other avatars for potential interactions...
-    NodeList* nodeList = NodeList::getInstance();
-    for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
+    
+    foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
         //qDebug() << "updateCollisionWithAvatars()... node:" << *node << "\n";
         if (node->getLinkedData() && node->getType() == NODE_TYPE_AGENT) {
             // TODO: dot collidingPalm and hand velocities and skip collision when they are moving apart.
             AvatarData* avatar = static_cast<AvatarData*>(node->getLinkedData());
             //printf("updateCollisionWithAvatars()...avatar=%p\n", avatar);
-
+            
             // check hands...
             const HandData* handData = avatar->getHandData();
-
+            
             if (handData->findSpherePenetration(center, radius, penetration, collidingPalm)) {
                 // apply a hard collision when ball collides with hand
                 penetration /= (float)(TREE_SCALE);
                 updateCollisionSound(particle, penetration, COLLISION_FREQUENCY);
-
+                
                 // determine if the palm that collided was moving, if so, then we add that palm velocity as well...
                 glm::vec3 addedVelocity = NO_ADDED_VELOCITY;
                 if (collidingPalm) {
@@ -211,9 +211,9 @@ void ParticleCollisionSystem::updateCollisionWithAvatars(Particle* particle) {
                     //printf("collidingPalm Velocity=%f,%f,%f\n", palmVelocity.x, palmVelocity.y, palmVelocity.z);
                     addedVelocity = palmVelocity;
                 }
-
+                
                 applyHardCollision(particle, penetration, ELASTICITY, DAMPING, addedVelocity);
-
+                
             } else if (avatar->findSpherePenetration(center, radius, penetration)) {
                 penetration /= (float)(TREE_SCALE);
                 updateCollisionSound(particle, penetration, COLLISION_FREQUENCY);
diff --git a/libraries/particles/src/ParticleTreeElement.cpp b/libraries/particles/src/ParticleTreeElement.cpp
index 2f59c924fa..44cb8db008 100644
--- a/libraries/particles/src/ParticleTreeElement.cpp
+++ b/libraries/particles/src/ParticleTreeElement.cpp
@@ -6,8 +6,6 @@
 //  Copyright (c) 2013 HighFidelity, Inc. All rights reserved.
 //
 
-#include <QtCore/QDebug>
-
 #include <GeometryUtil.h>
 
 #include "ParticleTree.h"
diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp
index 86b6e8884e..db486f9bb9 100644
--- a/libraries/script-engine/src/ScriptEngine.cpp
+++ b/libraries/script-engine/src/ScriptEngine.cpp
@@ -145,11 +145,11 @@ void ScriptEngine::evaluate() {
     }
 
     QScriptValue result = _engine.evaluate(_scriptContents);
-    qDebug() << "Evaluated script.\n";
+    qDebug("Evaluated script.");
 
     if (_engine.hasUncaughtException()) {
         int line = _engine.uncaughtExceptionLineNumber();
-        qDebug() << "Uncaught exception at line" << line << ":" << result.toString() << "\n";
+        qDebug() << "Uncaught exception at line" << line << ":" << result.toString();
     }
 }
 
@@ -160,11 +160,11 @@ void ScriptEngine::run() {
     _isRunning = true;
 
     QScriptValue result = _engine.evaluate(_scriptContents);
-    qDebug() << "Evaluated script.\n";
+    qDebug("Evaluated script");
 
     if (_engine.hasUncaughtException()) {
         int line = _engine.uncaughtExceptionLineNumber();
-        qDebug() << "Uncaught exception at line" << line << ":" << result.toString() << "\n";
+        qDebug() << "Uncaught exception at line" << line << ":" << result.toString();
     }
 
     timeval startTime;
@@ -221,7 +221,7 @@ void ScriptEngine::run() {
 
         if (_engine.hasUncaughtException()) {
             int line = _engine.uncaughtExceptionLineNumber();
-            qDebug() << "Uncaught exception at line" << line << ":" << _engine.uncaughtException().toString() << "\n";
+            qDebug() << "Uncaught exception at line" << line << ":" << _engine.uncaughtException().toString();
         }
     }
     cleanMenuItems();
diff --git a/libraries/shared/src/Assignment.cpp b/libraries/shared/src/Assignment.cpp
index ef57f838cb..8e67e7a178 100644
--- a/libraries/shared/src/Assignment.cpp
+++ b/libraries/shared/src/Assignment.cpp
@@ -160,7 +160,7 @@ void Assignment::swap(Assignment& otherAssignment) {
 void Assignment::setPayload(const uchar* payload, int numBytes) {
     
     if (numBytes > MAX_PAYLOAD_BYTES) {
-        qDebug("Set payload called with number of bytes greater than maximum (%d). Will only transfer %d bytes.\n",
+        qDebug("Set payload called with number of bytes greater than maximum (%d). Will only transfer %d bytes.",
                MAX_PAYLOAD_BYTES,
                MAX_PAYLOAD_BYTES);
         
diff --git a/libraries/shared/src/GeometryUtil.cpp b/libraries/shared/src/GeometryUtil.cpp
index 7ffe4edfde..5d6e216ad5 100644
--- a/libraries/shared/src/GeometryUtil.cpp
+++ b/libraries/shared/src/GeometryUtil.cpp
@@ -7,8 +7,6 @@
 
 #include <cstring>
 
-#include <QtCore/QDebug>
-
 #include "SharedUtil.h"
 #include "GeometryUtil.h"
 
diff --git a/libraries/shared/src/HifiSockAddr.cpp b/libraries/shared/src/HifiSockAddr.cpp
index 55c950c580..52198ef2e1 100644
--- a/libraries/shared/src/HifiSockAddr.cpp
+++ b/libraries/shared/src/HifiSockAddr.cpp
@@ -98,7 +98,7 @@ quint32 getHostOrderLocalAddress() {
                 foreach(const QNetworkAddressEntry &entry, interface.addressEntries()) {
                     // make sure it's an IPv4 address that isn't the loopback
                     if (entry.ip().protocol() == QAbstractSocket::IPv4Protocol && !entry.ip().isLoopback()) {
-                        qDebug("Node's local address is %s\n", entry.ip().toString().toLocal8Bit().constData());
+                        qDebug("Node's local address is %s", entry.ip().toString().toLocal8Bit().constData());
                         
                         // set our localAddress and break out
                         localAddress = entry.ip().toIPv4Address();
diff --git a/libraries/shared/src/Logging.cpp b/libraries/shared/src/Logging.cpp
index c9b2734619..6fb716e638 100644
--- a/libraries/shared/src/Logging.cpp
+++ b/libraries/shared/src/Logging.cpp
@@ -124,6 +124,6 @@ void Logging::verboseMessageHandler(QtMsgType type, const QMessageLogContext& co
     if (Logging::targetName) {
         prefixString.append(QString(" [%1]").arg(Logging::targetName));
     }
-
-    fprintf(stdout, "%s %s", prefixString.toLocal8Bit().constData(), message.toLocal8Bit().constData());
+    
+    fprintf(stdout, "%s %s\n", prefixString.toLocal8Bit().constData(), message.toLocal8Bit().constData());
 }
\ No newline at end of file
diff --git a/libraries/shared/src/NetworkPacket.cpp b/libraries/shared/src/NetworkPacket.cpp
index 575e80b59b..768e82cab3 100644
--- a/libraries/shared/src/NetworkPacket.cpp
+++ b/libraries/shared/src/NetworkPacket.cpp
@@ -29,7 +29,7 @@ void NetworkPacket::copyContents(const HifiSockAddr& sockAddr, const unsigned ch
         _packetLength = packetLength;
         memcpy(&_packetData[0], packetData, packetLength);
     } else {
-        qDebug(">>> NetworkPacket::copyContents() unexpected length=%lu\n",packetLength);
+        qDebug(">>> NetworkPacket::copyContents() unexpected length=%lu",packetLength);
     }
 }
 
diff --git a/libraries/shared/src/Node.cpp b/libraries/shared/src/Node.cpp
index f4a33d84c8..b07422969c 100644
--- a/libraries/shared/src/Node.cpp
+++ b/libraries/shared/src/Node.cpp
@@ -32,7 +32,8 @@ Node::Node(const QUuid& uuid, char type, const HifiSockAddr& publicSocket, const
     _bytesReceivedMovingAverage(NULL),
     _linkedData(NULL),
     _isAlive(true),
-    _clockSkewUsec(0)
+    _clockSkewUsec(0),
+    _mutex()
 {
 }
 
@@ -40,7 +41,7 @@ Node::~Node() {
     if (_linkedData) {
         _linkedData->deleteOrDeleteLater();
     }
-    
+
     delete _bytesReceivedMovingAverage;
 }
 
@@ -89,7 +90,7 @@ void Node::setPublicSocket(const HifiSockAddr& publicSocket) {
         // if the active socket was the public socket then reset it to NULL
         _activeSocket = NULL;
     }
-    
+
     _publicSocket = publicSocket;
 }
 
@@ -98,17 +99,17 @@ void Node::setLocalSocket(const HifiSockAddr& localSocket) {
         // if the active socket was the local socket then reset it to NULL
         _activeSocket = NULL;
     }
-    
+
     _localSocket = localSocket;
 }
 
 void Node::activateLocalSocket() {
-    qDebug() << "Activating local socket for node" << *this << "\n";
+    qDebug() << "Activating local socket for node" << *this;
     _activeSocket = &_localSocket;
 }
 
 void Node::activatePublicSocket() {
-    qDebug() << "Activating public socket for node" << *this << "\n";
+    qDebug() << "Activating public socket for node" << *this;
     _activeSocket = &_publicSocket;
 }
 
@@ -116,7 +117,7 @@ void Node::recordBytesReceived(int bytesReceived) {
     if (_bytesReceivedMovingAverage == NULL) {
         _bytesReceivedMovingAverage = new SimpleMovingAverage(100);
     }
-    
+
     _bytesReceivedMovingAverage->updateAverage((float) bytesReceived);
 }
 
diff --git a/libraries/shared/src/Node.h b/libraries/shared/src/Node.h
index 841f0a2813..352498cd61 100644
--- a/libraries/shared/src/Node.h
+++ b/libraries/shared/src/Node.h
@@ -19,6 +19,7 @@
 #endif
 
 #include <QtCore/QDebug>
+#include <QtCore/QMutex>
 #include <QtCore/QUuid>
 #include <QMutex>
 
@@ -26,7 +27,8 @@
 #include "NodeData.h"
 #include "SimpleMovingAverage.h"
 
-class Node {
+class Node : public QObject {
+    Q_OBJECT
 public:
     Node(const QUuid& uuid, char type, const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket);
     ~Node();
@@ -72,14 +74,7 @@ public:
 
     int getClockSkewUsec() const { return _clockSkewUsec; }
     void setClockSkewUsec(int clockSkew) { _clockSkewUsec = clockSkew; }
-
-    void lock() { _mutex.lock(); }
-
-    /// returns false if lock failed, true if you got the lock
-    bool trylock() { return _mutex.tryLock(); }
-    void unlock() { _mutex.unlock(); }
-
-    static void printLog(Node const&);
+    QMutex& getMutex() { return _mutex; }
 
 private:
     // privatize copy and assignment operator to disallow Node copying
@@ -101,9 +96,6 @@ private:
     QMutex _mutex;
 };
 
-int unpackNodeId(unsigned char *packedData, uint16_t *nodeId);
-int packNodeId(unsigned char *packStore, uint16_t nodeId);
-
 QDebug operator<<(QDebug debug, const Node &message);
 
 #endif /* defined(__hifi__Node__) */
diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp
index 8d7dd5b5af..87c80cf442 100644
--- a/libraries/shared/src/NodeList.cpp
+++ b/libraries/shared/src/NodeList.cpp
@@ -36,6 +36,9 @@ NodeList* NodeList::_sharedInstance = NULL;
 NodeList* NodeList::createInstance(char ownerType, unsigned short int socketListenPort) {
     if (!_sharedInstance) {
         _sharedInstance = new NodeList(ownerType, socketListenPort);
+
+        // register the SharedNodePointer meta-type for signals/slots
+        qRegisterMetaType<SharedNodePointer>();
     } else {
         qDebug("NodeList createInstance called with existing instance.");
     }
@@ -52,17 +55,16 @@ NodeList* NodeList::getInstance() {
 }
 
 #ifdef WIN32
-//warning C4351: new behavior: elements of array 'NodeList::_nodeBuckets' will be default initialized 
+//warning C4351: new behavior: elements of array 'NodeList::_nodeBuckets' will be default initialized
 // We're disabling this warning because the new behavior which is to initialize the array with 0 is acceptable to us.
-#pragma warning(disable:4351) 
+#pragma warning(disable:4351)
 #endif
 
 
 NodeList::NodeList(char newOwnerType, unsigned short int newSocketListenPort) :
+    _nodeHash(),
     _domainHostname(DEFAULT_DOMAIN_HOSTNAME),
     _domainSockAddr(HifiSockAddr(QHostAddress::Null, DEFAULT_DOMAIN_SERVER_PORT)),
-    _nodeBuckets(),
-    _numNodes(0),
     _nodeSocket(),
     _ownerType(newOwnerType),
     _nodeTypesOfInterest(NULL),
@@ -74,12 +76,12 @@ NodeList::NodeList(char newOwnerType, unsigned short int newSocketListenPort) :
     _stunRequestsSinceSuccess(0)
 {
     _nodeSocket.bind(QHostAddress::AnyIPv4, newSocketListenPort);
-    qDebug() << "NodeList socket is listening on" << _nodeSocket.localPort() << "\n";
+    qDebug() << "NodeList socket is listening on" << _nodeSocket.localPort();
 }
 
 #ifdef WIN32
-//warning C4351: new behavior: elements of array 'NodeList::_nodeBuckets' will be default initialized 
-#pragma warning(default:4351) 
+//warning C4351: new behavior: elements of array 'NodeList::_nodeBuckets' will be default initialized
+#pragma warning(default:4351)
 #endif
 
 
@@ -103,7 +105,7 @@ void NodeList::setDomainHostname(const QString& domainHostname) {
             // grab the port by reading the string after the colon
             _domainSockAddr.setPort(atoi(domainHostname.mid(colonIndex + 1, domainHostname.size()).toLocal8Bit().constData()));
 
-            qDebug() << "Updated hostname to" << _domainHostname << "and port to" << _domainSockAddr.getPort() << "\n";
+            qDebug() << "Updated hostname to" << _domainHostname << "and port to" << _domainSockAddr.getPort();
 
         } else {
             // no port included with the hostname, simply set the member variable and reset the domain server port to default
@@ -116,12 +118,12 @@ void NodeList::setDomainHostname(const QString& domainHostname) {
 
         // reset our _domainIP to the null address so that a lookup happens on next check in
         _domainSockAddr.setAddress(QHostAddress::Null);
-        notifyDomainChanged();
+        emit domainChanged(_domainHostname);
     }
 }
 
 void NodeList::timePingReply(const HifiSockAddr& nodeAddress, unsigned char *packetData) {
-    for(NodeList::iterator node = begin(); node != end(); node++) {
+    foreach (const SharedNodePointer& node, _nodeHash) {
         if (node->getPublicSocket() == nodeAddress ||
             node->getLocalSocket() == nodeAddress) {
 
@@ -150,7 +152,7 @@ void NodeList::timePingReply(const HifiSockAddr& nodeAddress, unsigned char *pac
                     "        oneWayFlightTime: " << oneWayFlightTime << "\n" <<
                     "         othersReplyTime: " << othersReplyTime << "\n" <<
                     "    othersExprectedReply: " << othersExprectedReply << "\n" <<
-                    "               clockSkew: " << clockSkew << "\n";
+                    "               clockSkew: " << clockSkew;
             }
             break;
         }
@@ -197,10 +199,9 @@ void NodeList::processNodeData(const HifiSockAddr& senderSockAddr, unsigned char
 }
 
 void NodeList::processBulkNodeData(const HifiSockAddr& senderAddress, unsigned char *packetData, int numTotalBytes) {
+    SharedNodePointer bulkSendNode = nodeWithAddress(senderAddress);
 
     // find the avatar mixer in our node list and update the lastRecvTime from it
-    Node* bulkSendNode = nodeWithAddress(senderAddress);
-
     if (bulkSendNode) {
 
         bulkSendNode->setLastHeardMicrostamp(usecTimestampNow());
@@ -222,14 +223,14 @@ void NodeList::processBulkNodeData(const HifiSockAddr& senderAddress, unsigned c
                    numTotalBytes - (currentPosition - startPosition));
 
             QUuid nodeUUID = QUuid::fromRfc4122(QByteArray((char*)currentPosition, NUM_BYTES_RFC4122_UUID));
-            Node* matchingNode = nodeWithUUID(nodeUUID);
+            SharedNodePointer matchingNode = nodeWithUUID(nodeUUID);
 
             if (!matchingNode) {
                 // we're missing this node, we need to add it to the list
                 matchingNode = addOrUpdateNode(nodeUUID, NODE_TYPE_AGENT, HifiSockAddr(), HifiSockAddr());
             }
 
-            currentPosition += updateNodeWithData(matchingNode,
+            currentPosition += updateNodeWithData(matchingNode.data(),
                                                   HifiSockAddr(),
                                                   packetHolder,
                                                   numTotalBytes - (currentPosition - startPosition));
@@ -241,7 +242,7 @@ void NodeList::processBulkNodeData(const HifiSockAddr& senderAddress, unsigned c
 }
 
 int NodeList::updateNodeWithData(Node *node, const HifiSockAddr& senderSockAddr, unsigned char *packetData, int dataBytes) {
-    node->lock();
+    QMutexLocker(&node->getMutex());
 
     node->setLastHeardMicrostamp(usecTimestampNow());
 
@@ -257,64 +258,43 @@ int NodeList::updateNodeWithData(Node *node, const HifiSockAddr& senderSockAddr,
         }
 
         int numParsedBytes = node->getLinkedData()->parseData(packetData, dataBytes);
-
-        node->unlock();
-
         return numParsedBytes;
     } else {
         // we weren't able to match the sender address to the address we have for this node, unlock and don't parse
-        node->unlock();
         return 0;
     }
 }
 
-Node* NodeList::nodeWithAddress(const HifiSockAddr &senderSockAddr) {
-    for(NodeList::iterator node = begin(); node != end(); node++) {
+SharedNodePointer NodeList::nodeWithAddress(const HifiSockAddr &senderSockAddr) {
+    // naively returns the first node that has a matching active HifiSockAddr
+    // note that there can be multiple nodes that have a matching active socket, so this isn't a good way to uniquely identify
+    foreach (const SharedNodePointer& node, _nodeHash) {
         if (node->getActiveSocket() && *node->getActiveSocket() == senderSockAddr) {
-            return &(*node);
+            return node;
         }
     }
 
-    return NULL;
+    return SharedNodePointer();
 }
 
-Node* NodeList::nodeWithUUID(const QUuid& nodeUUID) {
-    for(NodeList::iterator node = begin(); node != end(); node++) {
-        if (node->getUUID() == nodeUUID) {
-            return &(*node);
-        }
+SharedNodePointer NodeList::nodeWithUUID(const QUuid& nodeUUID) {
+    QHash<QUuid, QSharedPointer<Node> >::const_iterator foundIterator = _nodeHash.find(nodeUUID);
+    if (foundIterator != _nodeHash.end()) {
+        return foundIterator.value();
+    } else {
+        return SharedNodePointer();
     }
-
-    return NULL;
-}
-
-int NodeList::getNumAliveNodes() const {
-    int numAliveNodes = 0;
-
-    for (NodeList::iterator node = begin(); node != end(); node++) {
-        if (node->isAlive()) {
-            ++numAliveNodes;
-        }
-    }
-
-    return numAliveNodes;
 }
 
 void NodeList::clear() {
-    qDebug() << "Clearing the NodeList. Deleting all nodes in list.\n";
+    qDebug() << "Clearing the NodeList. Deleting all nodes in list.";
 
-    // delete all of the nodes in the list, set the pointers back to NULL and the number of nodes to 0
-    for (int i = 0; i < _numNodes; i++) {
-        Node** nodeBucket = _nodeBuckets[i / NODES_PER_BUCKET];
-        Node* node = nodeBucket[i % NODES_PER_BUCKET];
+    NodeHash::iterator nodeItem = _nodeHash.begin();
 
-        node->lock();
-        notifyHooksOfKilledNode(&*node);
-
-        delete node;
+    // iterate the nodes in the list
+    while (nodeItem != _nodeHash.end()) {
+        nodeItem = killNodeAtHashIterator(nodeItem);
     }
-
-    _numNodes = 0;
 }
 
 void NodeList::reset() {
@@ -373,7 +353,7 @@ void NodeList::sendSTUNRequest() {
     static HifiSockAddr stunSockAddr(STUN_SERVER_HOSTNAME, STUN_SERVER_PORT);
 
     if (!_hasCompletedInitialSTUNFailure) {
-        qDebug("Sending intial stun request to %s\n", stunSockAddr.getAddress().toString().toLocal8Bit().constData());
+        qDebug("Sending intial stun request to %s", stunSockAddr.getAddress().toString().toLocal8Bit().constData());
     }
 
     _nodeSocket.writeDatagram((char*) stunRequestPacket, sizeof(stunRequestPacket),
@@ -385,7 +365,7 @@ void NodeList::sendSTUNRequest() {
         if (!_hasCompletedInitialSTUNFailure) {
             // if we're here this was the last failed STUN request
             // use our DS as our stun server
-            qDebug("Failed to lookup public address via STUN server at %s:%hu. Using DS for STUN.\n",
+            qDebug("Failed to lookup public address via STUN server at %s:%hu. Using DS for STUN.",
                    STUN_SERVER_HOSTNAME, STUN_SERVER_PORT);
 
             _hasCompletedInitialSTUNFailure = true;
@@ -448,7 +428,7 @@ void NodeList::processSTUNResponse(unsigned char* packetData, size_t dataBytes)
                     if (newPublicAddress != _publicSockAddr.getAddress() || newPublicPort != _publicSockAddr.getPort()) {
                         _publicSockAddr = HifiSockAddr(newPublicAddress, newPublicPort);
 
-                        qDebug("New public socket received from STUN server is %s:%hu\n",
+                        qDebug("New public socket received from STUN server is %s:%hu",
                                _publicSockAddr.getAddress().toString().toLocal8Bit().constData(),
                                _publicSockAddr.getPort());
 
@@ -472,6 +452,21 @@ void NodeList::processSTUNResponse(unsigned char* packetData, size_t dataBytes)
     }
 }
 
+void NodeList::killNodeWithUUID(const QUuid& nodeUUID) {
+    NodeHash::iterator nodeItemToKill = _nodeHash.find(nodeUUID);
+    if (nodeItemToKill != _nodeHash.end()) {
+        killNodeAtHashIterator(nodeItemToKill);
+    }
+}
+
+NodeHash::iterator NodeList::killNodeAtHashIterator(NodeHash::iterator& nodeItemToKill) {
+    qDebug() << "Killed" << *nodeItemToKill.value();
+    emit nodeKilled(nodeItemToKill.value());
+
+    return _nodeHash.erase(nodeItemToKill);
+}
+
+
 void NodeList::sendKillNode(const char* nodeTypes, int numNodeTypes) {
     unsigned char packet[MAX_PACKET_SIZE];
     unsigned char* packetPosition = packet;
@@ -496,12 +491,8 @@ void NodeList::processKillNode(unsigned char* packetData, size_t dataBytes) {
 
     packetData += NUM_BYTES_RFC4122_UUID;
     dataBytes -= NUM_BYTES_RFC4122_UUID;
-
-    // make sure the node exists
-    Node* node = nodeWithUUID(nodeUUID);
-    if (node) {
-        killNode(node, true);
-    }
+    // kill the node with this UUID, if it exists
+    killNodeWithUUID(nodeUUID);
 }
 
 void NodeList::sendDomainServerCheckIn() {
@@ -509,15 +500,13 @@ void NodeList::sendDomainServerCheckIn() {
 
     //  Lookup the IP address of the domain server if we need to
     if (_domainSockAddr.getAddress().isNull()) {
-        qDebug("Looking up DS hostname %s.\n", _domainHostname.toLocal8Bit().constData());
-
+        qDebug("Looking up DS hostname %s.", _domainHostname.toLocal8Bit().constData());
         QHostInfo domainServerHostInfo = QHostInfo::fromName(_domainHostname);
 
         for (int i = 0; i < domainServerHostInfo.addresses().size(); i++) {
             if (domainServerHostInfo.addresses()[i].protocol() == QAbstractSocket::IPv4Protocol) {
                 _domainSockAddr.setAddress(domainServerHostInfo.addresses()[i]);
-
-                qDebug("DS at %s is at %s\n", _domainHostname.toLocal8Bit().constData(),
+                qDebug("DS at %s is at %s", _domainHostname.toLocal8Bit().constData(),
                        _domainSockAddr.getAddress().toString().toLocal8Bit().constData());
 
                 printedDomainServerIP = true;
@@ -527,11 +516,11 @@ void NodeList::sendDomainServerCheckIn() {
 
             // if we got here without a break out of the for loop then we failed to lookup the address
             if (i == domainServerHostInfo.addresses().size() - 1) {
-                qDebug("Failed domain server lookup\n");
+                qDebug("Failed domain server lookup");
             }
         }
     } else if (!printedDomainServerIP) {
-        qDebug("Domain Server IP: %s\n", _domainSockAddr.getAddress().toString().toLocal8Bit().constData());
+        qDebug("Domain Server IP: %s", _domainSockAddr.getAddress().toString().toLocal8Bit().constData());
         printedDomainServerIP = true;
     }
 
@@ -700,26 +689,25 @@ void NodeList::pingPublicAndLocalSocketsForInactiveNode(Node* node) {
                               node->getPublicSocket().getAddress(), node->getPublicSocket().getPort());
 }
 
-Node* NodeList::addOrUpdateNode(const QUuid& uuid, char nodeType,
+SharedNodePointer NodeList::addOrUpdateNode(const QUuid& uuid, char nodeType,
                                 const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket) {
-    NodeList::iterator node = end();
+    NodeHash::iterator matchingNodeItem = _nodeHash.find(uuid);
 
-    for (node = begin(); node != end(); node++) {
-        if (node->getUUID() == uuid) {
-            // we already have this node, stop checking
-            break;
-        }
-    }
-
-    if (node == end()) {
+    if (matchingNodeItem == _nodeHash.end()) {
         // we didn't have this node, so add them
         Node* newNode = new Node(uuid, nodeType, publicSocket, localSocket);
+        SharedNodePointer newNodeSharedPointer(newNode, &QObject::deleteLater);
 
-        addNodeToList(newNode);
+        _nodeHash.insert(newNode->getUUID(), newNodeSharedPointer);
 
-        return newNode;
+        qDebug() << "Added" << *newNode;
+
+        emit nodeAdded(newNodeSharedPointer);
+
+        return newNodeSharedPointer;
     } else {
-        node->lock();
+        SharedNodePointer node = matchingNodeItem.value();
+        QMutexLocker(&node->getMutex());
 
         if (node->getType() == NODE_TYPE_AUDIO_MIXER ||
             node->getType() == NODE_TYPE_VOXEL_SERVER ||
@@ -732,44 +720,25 @@ Node* NodeList::addOrUpdateNode(const QUuid& uuid, char nodeType,
         // check if we need to change this node's public or local sockets
         if (publicSocket != node->getPublicSocket()) {
             node->setPublicSocket(publicSocket);
-            qDebug() << "Public socket change for node" << *node << "\n";
+            qDebug() << "Public socket change for node" << *node;
         }
 
         if (localSocket != node->getLocalSocket()) {
             node->setLocalSocket(localSocket);
-            qDebug() << "Local socket change for node" << *node << "\n";
+            qDebug() << "Local socket change for node" << *node;
         }
-
-        node->unlock();
-
         // we had this node already, do nothing for now
-        return &*node;
+        return node;
     }
 }
 
-void NodeList::addNodeToList(Node* newNode) {
-    // find the correct array to add this node to
-    int bucketIndex = _numNodes / NODES_PER_BUCKET;
-
-    if (!_nodeBuckets[bucketIndex]) {
-        _nodeBuckets[bucketIndex] = new Node*[NODES_PER_BUCKET]();
-    }
-
-    _nodeBuckets[bucketIndex][_numNodes % NODES_PER_BUCKET] = newNode;
-
-    ++_numNodes;
-
-    qDebug() << "Added" << *newNode << "\n";
-
-    notifyHooksOfAddedNode(newNode);
-}
-
 unsigned NodeList::broadcastToNodes(unsigned char* broadcastData, size_t dataBytes, const char* nodeTypes, int numNodeTypes) {
     unsigned n = 0;
-    for(NodeList::iterator node = begin(); node != end(); node++) {
+
+    foreach (const SharedNodePointer& node, _nodeHash) {
         // only send to the NodeTypes we are asked to send to.
         if (memchr(nodeTypes, node->getType(), numNodeTypes)) {
-            if (getNodeActiveSocketOrPing(&(*node))) {
+            if (getNodeActiveSocketOrPing(node.data())) {
                 // we know which socket is good for this node, send there
                 _nodeSocket.writeDatagram((char*) broadcastData, dataBytes,
                                           node->getActiveSocket()->getAddress(), node->getActiveSocket()->getPort());
@@ -777,14 +746,15 @@ unsigned NodeList::broadcastToNodes(unsigned char* broadcastData, size_t dataByt
             }
         }
     }
+
     return n;
 }
 
 void NodeList::pingInactiveNodes() {
-    for(NodeList::iterator node = begin(); node != end(); node++) {
+    foreach (const SharedNodePointer& node, _nodeHash) {
         if (!node->getActiveSocket()) {
             // we don't have an active link to this node, ping it to set that up
-            pingPublicAndLocalSocketsForInactiveNode(&(*node));
+            pingPublicAndLocalSocketsForInactiveNode(node.data());
         }
     }
 }
@@ -799,7 +769,8 @@ const HifiSockAddr* NodeList::getNodeActiveSocketOrPing(Node* node) {
 }
 
 void NodeList::activateSocketFromNodeCommunication(const HifiSockAddr& nodeAddress) {
-    for(NodeList::iterator node = begin(); node != end(); node++) {
+
+    foreach (const SharedNodePointer& node, _nodeHash) {
         if (!node->getActiveSocket()) {
             // check both the public and local addresses for each node to see if we find a match
             // prioritize the private address so that we prune erroneous local matches
@@ -814,46 +785,34 @@ void NodeList::activateSocketFromNodeCommunication(const HifiSockAddr& nodeAddre
     }
 }
 
-Node* NodeList::soloNodeOfType(char nodeType) {
+SharedNodePointer NodeList::soloNodeOfType(char nodeType) {
+
     if (memchr(SOLO_NODE_TYPES, nodeType, sizeof(SOLO_NODE_TYPES)) != NULL) {
-        for(NodeList::iterator node = begin(); node != end(); node++) {
+        foreach (const SharedNodePointer& node, _nodeHash) {
             if (node->getType() == nodeType) {
-                return &(*node);
+                return node;
             }
         }
     }
-
-    return NULL;
-}
-
-void NodeList::killNode(Node* node, bool mustLockNode) {
-    if (mustLockNode) {
-        node->lock();
-    }
-
-    qDebug() << "Killed " << *node << "\n";
-
-    notifyHooksOfKilledNode(&*node);
-
-    node->setAlive(false);
-
-    if (mustLockNode) {
-        node->unlock();
-    }
+    return SharedNodePointer();
 }
 
 void NodeList::removeSilentNodes() {
-    NodeList* nodeList = NodeList::getInstance();
 
-    for(NodeList::iterator node = nodeList->begin(); node != nodeList->end(); ++node) {
-        node->lock();
+    NodeHash::iterator nodeItem = _nodeHash.begin();
+
+    while (nodeItem != _nodeHash.end()) {
+        SharedNodePointer node = nodeItem.value();
+
+        QMutexLocker(&node->getMutex());
 
         if ((usecTimestampNow() - node->getLastHeardMicrostamp()) > NODE_SILENCE_THRESHOLD_USECS) {
-            // kill this node, don't lock - we already did it
-            nodeList->killNode(&(*node), false);
+            // call our private method to kill this node (removes it and emits the right signal)
+            nodeItem = killNodeAtHashIterator(nodeItem);
+        } else {
+            // we didn't kill this node, push the iterator forwards
+            ++nodeItem;
         }
-
-        node->unlock();
     }
 }
 
@@ -867,7 +826,7 @@ void NodeList::loadData(QSettings *settings) {
 
     if (domainServerHostname.size() > 0) {
         _domainHostname = domainServerHostname;
-        notifyDomainChanged();
+        emit domainChanged(_domainHostname);
     }
 
     settings->endGroup();
@@ -886,125 +845,3 @@ void NodeList::saveData(QSettings* settings) {
 
     settings->endGroup();
 }
-
-NodeList::iterator NodeList::begin() const {
-    Node** nodeBucket = NULL;
-
-    for (int i = 0; i < _numNodes; i++) {
-        if (i % NODES_PER_BUCKET == 0) {
-            nodeBucket =  _nodeBuckets[i / NODES_PER_BUCKET];
-        }
-
-        if (nodeBucket[i % NODES_PER_BUCKET]->isAlive()) {
-            return NodeListIterator(this, i);
-        }
-    }
-
-    // there's no alive node to start from - return the end
-    return end();
-}
-
-NodeList::iterator NodeList::end() const {
-    return NodeListIterator(this, _numNodes);
-}
-
-NodeListIterator::NodeListIterator(const NodeList* nodeList, int nodeIndex) :
-    _nodeIndex(nodeIndex) {
-    _nodeList = nodeList;
-}
-
-NodeListIterator& NodeListIterator::operator=(const NodeListIterator& otherValue) {
-    _nodeList = otherValue._nodeList;
-    _nodeIndex = otherValue._nodeIndex;
-    return *this;
-}
-
-bool NodeListIterator::operator==(const NodeListIterator &otherValue) {
-    return _nodeIndex == otherValue._nodeIndex;
-}
-
-bool NodeListIterator::operator!=(const NodeListIterator &otherValue) {
-    return !(*this == otherValue);
-}
-
-Node& NodeListIterator::operator*() {
-    Node** nodeBucket = _nodeList->_nodeBuckets[_nodeIndex / NODES_PER_BUCKET];
-    return *nodeBucket[_nodeIndex % NODES_PER_BUCKET];
-}
-
-Node* NodeListIterator::operator->() {
-    Node** nodeBucket = _nodeList->_nodeBuckets[_nodeIndex / NODES_PER_BUCKET];
-    return nodeBucket[_nodeIndex % NODES_PER_BUCKET];
-}
-
-NodeListIterator& NodeListIterator::operator++() {
-    skipDeadAndStopIncrement();
-    return *this;
-}
-
-NodeList::iterator NodeListIterator::operator++(int) {
-    NodeListIterator newIterator = NodeListIterator(*this);
-    skipDeadAndStopIncrement();
-    return newIterator;
-}
-
-void NodeListIterator::skipDeadAndStopIncrement() {
-    while (_nodeIndex != _nodeList->_numNodes) {
-        ++_nodeIndex;
-
-        if (_nodeIndex == _nodeList->_numNodes) {
-            break;
-        } else if ((*(*this)).isAlive()) {
-            // skip over the dead nodes
-            break;
-        }
-    }
-}
-
-void NodeList::addDomainListener(DomainChangeListener* listener) {
-    _domainListeners.push_back(listener);
-    QString domain = _domainHostname.isEmpty() ? _domainSockAddr.getAddress().toString() : _domainHostname;
-    listener->domainChanged(domain);
-}
-
-void NodeList::removeDomainListener(DomainChangeListener* listener) {
-    for (size_t i = 0; i < _domainListeners.size(); i++) {
-        if (_domainListeners[i] == listener) {
-            _domainListeners.erase(_domainListeners.begin() + i);
-            return;
-        }
-    }
-}
-
-void NodeList::addHook(NodeListHook* hook) {
-    _hooks.push_back(hook);
-}
-
-void NodeList::removeHook(NodeListHook* hook) {
-    for (size_t i = 0; i < _hooks.size(); i++) {
-        if (_hooks[i] == hook) {
-            _hooks.erase(_hooks.begin() + i);
-            return;
-        }
-    }
-}
-
-void NodeList::notifyHooksOfAddedNode(Node* node) {
-    for (size_t i = 0; i < _hooks.size(); i++) {
-        //printf("NodeList::notifyHooksOfAddedNode() i=%d\n", i);
-        _hooks[i]->nodeAdded(node);
-    }
-}
-
-void NodeList::notifyHooksOfKilledNode(Node* node) {
-    for (size_t i = 0; i < _hooks.size(); i++) {
-        //printf("NodeList::notifyHooksOfKilledNode() i=%d\n", i);
-        _hooks[i]->nodeKilled(node);
-    }
-}
-
-void NodeList::notifyDomainChanged() {
-    for (size_t i = 0; i < _domainListeners.size(); i++) {
-        _domainListeners[i]->domainChanged(_domainHostname);
-    }
-}
diff --git a/libraries/shared/src/NodeList.h b/libraries/shared/src/NodeList.h
index 28241f1cb0..556e6fde95 100644
--- a/libraries/shared/src/NodeList.h
+++ b/libraries/shared/src/NodeList.h
@@ -19,9 +19,10 @@
 
 //#include <unistd.h> // not on windows, not needed for mac or windows
 
+#include <QtCore/QSettings>
+#include <QtCore/QSharedPointer>
 #include <QtNetwork/QHostAddress>
 #include <QtNetwork/QUdpSocket>
-#include <QtCore/QSettings>
 
 #include "Node.h"
 #include "NodeTypes.h"
@@ -48,31 +49,16 @@ const int MAX_SILENT_DOMAIN_SERVER_CHECK_INS = 5;
 
 class Assignment;
 class HifiSockAddr;
-class NodeListIterator;
 
-// Callers who want to hook add/kill callbacks should implement this class
-class NodeListHook {
-public:
-    virtual void nodeAdded(Node* node) = 0;
-    virtual void nodeKilled(Node* node) = 0;
-};
-
-class DomainChangeListener {
-public:
-    virtual void domainChanged(QString domain) = 0;
-};
+typedef QSharedPointer<Node> SharedNodePointer;
+typedef QHash<QUuid, SharedNodePointer> NodeHash;
+Q_DECLARE_METATYPE(SharedNodePointer)
 
 class NodeList : public QObject {
     Q_OBJECT
 public:
     static NodeList* createInstance(char ownerType, unsigned short int socketListenPort = 0);
     static NodeList* getInstance();
-
-    typedef NodeListIterator iterator;
-
-    NodeListIterator begin() const;
-    NodeListIterator end() const;
-
     NODE_TYPE getOwnerType() const { return _ownerType; }
     void setOwnerType(NODE_TYPE ownerType) { _ownerType = ownerType; }
 
@@ -93,8 +79,8 @@ public:
 
     void(*linkedDataCreateCallback)(Node *);
 
-    int size() { return _numNodes; }
-    int getNumAliveNodes() const;
+    const NodeHash& getNodeHash() { return _nodeHash; }
+    int size() const { return _nodeHash.size(); }
 
     int getNumNoReplyDomainCheckIns() const { return _numNoReplyDomainCheckIns; }
 
@@ -111,14 +97,13 @@ public:
     int fillPingPacket(unsigned char* buffer);
     int fillPingReplyPacket(unsigned char* pingBuffer, unsigned char* replyBuffer);
     void pingPublicAndLocalSocketsForInactiveNode(Node* node);
-
+    void killNodeWithUUID(const QUuid& nodeUUID);
     void sendKillNode(const char* nodeTypes, int numNodeTypes);
 
-    Node* nodeWithAddress(const HifiSockAddr& senderSockAddr);
-    Node* nodeWithUUID(const QUuid& nodeUUID);
+    SharedNodePointer nodeWithAddress(const HifiSockAddr& senderSockAddr);
+    SharedNodePointer nodeWithUUID(const QUuid& nodeUUID);
 
-    Node* addOrUpdateNode(const QUuid& uuid, char nodeType, const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket);
-    void killNode(Node* node, bool mustLockNode = true);
+    SharedNodePointer addOrUpdateNode(const QUuid& uuid, char nodeType, const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket);
 
     void processNodeData(const HifiSockAddr& senderSockAddr, unsigned char *packetData, size_t dataBytes);
     void processBulkNodeData(const HifiSockAddr& senderSockAddr, unsigned char *packetData, int numTotalBytes);
@@ -126,27 +111,20 @@ public:
     int updateNodeWithData(Node *node, const HifiSockAddr& senderSockAddr, unsigned char *packetData, int dataBytes);
 
     unsigned broadcastToNodes(unsigned char *broadcastData, size_t dataBytes, const char* nodeTypes, int numNodeTypes);
-
-    Node* soloNodeOfType(char nodeType);
+    SharedNodePointer soloNodeOfType(char nodeType);
 
     void loadData(QSettings* settings);
     void saveData(QSettings* settings);
 
-    friend class NodeListIterator;
-
-    void addHook(NodeListHook* hook);
-    void removeHook(NodeListHook* hook);
-    void notifyHooksOfAddedNode(Node* node);
-    void notifyHooksOfKilledNode(Node* node);
-
-    void addDomainListener(DomainChangeListener* listener);
-    void removeDomainListener(DomainChangeListener* listener);
-
     const HifiSockAddr* getNodeActiveSocketOrPing(Node* node);
 public slots:
     void sendDomainServerCheckIn();
     void pingInactiveNodes();
     void removeSilentNodes();
+signals:
+    void domainChanged(const QString& domainHostname);
+    void nodeAdded(SharedNodePointer);
+    void nodeKilled(SharedNodePointer);
 private:
     static NodeList* _sharedInstance;
 
@@ -154,18 +132,15 @@ private:
     ~NodeList();
     NodeList(NodeList const&); // Don't implement, needed to avoid copies of singleton
     void operator=(NodeList const&); // Don't implement, needed to avoid copies of singleton
-
-    void addNodeToList(Node* newNode);
-
     void sendSTUNRequest();
     void processSTUNResponse(unsigned char* packetData, size_t dataBytes);
 
     void processKillNode(unsigned char* packetData, size_t dataBytes);
+    NodeHash::iterator killNodeAtHashIterator(NodeHash::iterator& nodeItemToKill);
 
+    NodeHash _nodeHash;
     QString _domainHostname;
     HifiSockAddr _domainSockAddr;
-    Node** _nodeBuckets[MAX_NUM_NODES / NODES_PER_BUCKET];
-    int _numNodes;
     QUdpSocket _nodeSocket;
     char _ownerType;
     char* _nodeTypesOfInterest;
@@ -178,36 +153,8 @@ private:
 
     void activateSocketFromNodeCommunication(const HifiSockAddr& nodeSockAddr);
     void timePingReply(const HifiSockAddr& nodeAddress, unsigned char *packetData);
-
-    std::vector<NodeListHook*> _hooks;
-    std::vector<DomainChangeListener*> _domainListeners;
-
     void resetDomainData(char domainField[], const char* domainData);
-    void notifyDomainChanged();
     void domainLookup();
 };
 
-class NodeListIterator : public std::iterator<std::input_iterator_tag, Node> {
-public:
-    NodeListIterator(const NodeList* nodeList, int nodeIndex);
-
-    int getNodeIndex() { return _nodeIndex; }
-
-	NodeListIterator& operator=(const NodeListIterator& otherValue);
-
-    bool operator==(const NodeListIterator& otherValue);
-	bool operator!= (const NodeListIterator& otherValue);
-
-    Node& operator*();
-    Node* operator->();
-
-	NodeListIterator& operator++();
-    NodeListIterator operator++(int);
-private:
-    void skipDeadAndStopIncrement();
-
-    const NodeList* _nodeList;
-    int _nodeIndex;
-};
-
 #endif /* defined(__hifi__NodeList__) */
diff --git a/libraries/shared/src/OctalCode.cpp b/libraries/shared/src/OctalCode.cpp
index 5ac27efd40..3f9cf8edcb 100644
--- a/libraries/shared/src/OctalCode.cpp
+++ b/libraries/shared/src/OctalCode.cpp
@@ -32,12 +32,12 @@ int numberOfThreeBitSectionsInCode(const unsigned char* octalCode, int maxBytes)
 
 void printOctalCode(const unsigned char* octalCode) {
     if (!octalCode) {
-        qDebug("NULL\n");
+        qDebug("NULL");
     } else {
+        QDebug continuedDebug = qDebug().nospace();
         for (int i = 0; i < bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(octalCode)); i++) {
-            outputBits(octalCode[i],false);
+            outputBits(octalCode[i], &continuedDebug);
         }
-        qDebug("\n");
     }
 }
 
diff --git a/libraries/shared/src/PacketHeaders.cpp b/libraries/shared/src/PacketHeaders.cpp
index ec5e8ee692..973738280f 100644
--- a/libraries/shared/src/PacketHeaders.cpp
+++ b/libraries/shared/src/PacketHeaders.cpp
@@ -20,7 +20,7 @@ PACKET_VERSION versionForPacketType(PACKET_TYPE type) {
             return 2;
             
         case PACKET_TYPE_HEAD_DATA:
-            return 12;
+            return 13;
         
         case PACKET_TYPE_AVATAR_URLS:
             return 2;
@@ -70,7 +70,7 @@ bool packetVersionMatch(unsigned char* packetHeader) {
     if (packetHeader[1] == versionForPacketType(packetHeader[0]) || packetHeader[0] == PACKET_TYPE_STUN_RESPONSE) {
         return true;
     } else {
-        qDebug("There is a packet version mismatch for packet with header %c\n", packetHeader[0]);
+        qDebug("There is a packet version mismatch for packet with header %c", packetHeader[0]);
         return false;
     }
 }
diff --git a/libraries/shared/src/PerfStat.cpp b/libraries/shared/src/PerfStat.cpp
index 24fb15d88e..b99b323751 100644
--- a/libraries/shared/src/PerfStat.cpp
+++ b/libraries/shared/src/PerfStat.cpp
@@ -29,20 +29,20 @@ PerformanceWarning::~PerformanceWarning() {
     if ((_alwaysDisplay || _renderWarningsOn) && elapsedmsec > 1) {
         if (elapsedmsec > 1000) {
             double elapsedsec = (end - _start) / 1000000.0;
-            qDebug("%s took %.2lf seconds %s\n", _message, elapsedsec, (_alwaysDisplay ? "" : "WARNING!") );
+            qDebug("%s took %.2lf seconds %s", _message, elapsedsec, (_alwaysDisplay ? "" : "WARNING!") );
         } else {
             if (_suppressShortTimings) {
                 if (elapsedmsec > 10) {
-                    qDebug("%s took %.1lf milliseconds %s\n", _message, elapsedmsec,
+                    qDebug("%s took %.1lf milliseconds %s", _message, elapsedmsec,
                         (_alwaysDisplay || (elapsedmsec < 10) ? "" : "WARNING!"));
                 }
             } else {
-                qDebug("%s took %.2lf milliseconds %s\n", _message, elapsedmsec,
+                qDebug("%s took %.2lf milliseconds %s", _message, elapsedmsec,
                     (_alwaysDisplay || (elapsedmsec < 10) ? "" : "WARNING!"));
             }
         }
     } else if (_alwaysDisplay) {
-        qDebug("%s took %.2lf milliseconds\n", _message, elapsedmsec);
+        qDebug("%s took %.2lf milliseconds", _message, elapsedmsec);
     }
     // if the caller gave us a pointer to store the running total, track it now.
     if (_runningTotal) {
diff --git a/libraries/shared/src/ReceivedPacketProcessor.cpp b/libraries/shared/src/ReceivedPacketProcessor.cpp
index 4ad869460e..d61db2b184 100644
--- a/libraries/shared/src/ReceivedPacketProcessor.cpp
+++ b/libraries/shared/src/ReceivedPacketProcessor.cpp
@@ -18,7 +18,7 @@ ReceivedPacketProcessor::ReceivedPacketProcessor() {
 
 void ReceivedPacketProcessor::queueReceivedPacket(const HifiSockAddr& address, unsigned char* packetData, ssize_t packetLength) {
     // Make sure our Node and NodeList knows we've heard from this node.
-    Node* node = NodeList::getInstance()->nodeWithAddress(address);
+    SharedNodePointer node = NodeList::getInstance()->nodeWithAddress(address);
     if (node) {
         node->setLastHeardMicrostamp(usecTimestampNow());
     }
diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp
index 8b18f81f8a..11fd72d977 100644
--- a/libraries/shared/src/SharedUtil.cpp
+++ b/libraries/shared/src/SharedUtil.cpp
@@ -65,30 +65,33 @@ bool shouldDo(float desiredInterval, float deltaTime) {
     return randFloat() < deltaTime / desiredInterval;
 }
 
-void outputBufferBits(const unsigned char* buffer, int length, bool withNewLine) {
+void outputBufferBits(const unsigned char* buffer, int length, QDebug* continuedDebug) {
     for (int i = 0; i < length; i++) {
-        outputBits(buffer[i], false);
-    }
-    if (withNewLine) {
-        qDebug("\n");
+        outputBits(buffer[i], continuedDebug);
     }
 }
 
-void outputBits(unsigned char byte, bool withNewLine, bool usePrintf) {
-    if (isalnum(byte)) {
-        usePrintf ? (void)printf("[ %d (%c): ", byte, byte) : qDebug("[ %d (%c): ", byte, byte);
-    } else {
-        usePrintf ? (void)printf("[ %d (0x%x): ", byte, byte) : qDebug("[ %d (0x%x): ", byte, byte);
+void outputBits(unsigned char byte, QDebug* continuedDebug) {
+    QDebug debug = qDebug().nospace();
+
+    if (continuedDebug) {
+        debug = *continuedDebug;
     }
 
+    QString resultString;
+
+    if (isalnum(byte)) {
+        resultString.sprintf("[ %d (%c): ", byte, byte);
+    } else {
+        resultString.sprintf("[ %d (0x%x): ", byte, byte);
+    }
+    debug << resultString;
+
     for (int i = 0; i < 8; i++) {
-        usePrintf ? (void)printf("%d", byte >> (7 - i) & 1) : qDebug("%d", byte >> (7 - i) & 1);
-    }
-    usePrintf ? (void)printf(" ] ") : qDebug(" ] ");
-
-    if (withNewLine) {
-        usePrintf ? (void)printf("\n") : qDebug("\n");
+        resultString.sprintf("%d", byte >> (7 - i) & 1);
     }
+    debug << resultString;
+    debug << " ]";
 }
 
 int numberOfOnes(unsigned char byte) {
@@ -465,15 +468,16 @@ void printVoxelCode(unsigned char* voxelCode) {
 	unsigned int voxelSizeInOctets = (voxelSizeInBits/3);
 	unsigned int voxelBufferSize = voxelSizeInBytes+1+3; // 1 for size, 3 for color
 
-    qDebug("octets=%d\n",octets);
-    qDebug("voxelSizeInBits=%d\n",voxelSizeInBits);
-    qDebug("voxelSizeInBytes=%d\n",voxelSizeInBytes);
-    qDebug("voxelSizeInOctets=%d\n",voxelSizeInOctets);
-    qDebug("voxelBufferSize=%d\n",voxelBufferSize);
+    qDebug("octets=%d",octets);
+    qDebug("voxelSizeInBits=%d",voxelSizeInBits);
+    qDebug("voxelSizeInBytes=%d",voxelSizeInBytes);
+    qDebug("voxelSizeInOctets=%d",voxelSizeInOctets);
+    qDebug("voxelBufferSize=%d",voxelBufferSize);
 
-    for(unsigned int i=0;i<voxelBufferSize;i++) {
-        qDebug("i=%d ",i);
-        outputBits(voxelCode[i]);
+    for(int i=0; i < voxelBufferSize; i++) {
+        QDebug voxelBufferDebug = qDebug();
+        voxelBufferDebug << "i =" << i;
+        outputBits(voxelCode[i], &voxelBufferDebug);
     }
 }
 
diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h
index acbe1535a7..01d33bbf37 100644
--- a/libraries/shared/src/SharedUtil.h
+++ b/libraries/shared/src/SharedUtil.h
@@ -69,8 +69,8 @@ bool randomBoolean();
 
 bool shouldDo(float desiredInterval, float deltaTime);
 
-void outputBufferBits(const unsigned char* buffer, int length, bool withNewLine = true);
-void outputBits(unsigned char byte, bool withNewLine = true, bool usePrintf = false);
+void outputBufferBits(const unsigned char* buffer, int length, QDebug* continuedDebug = NULL);
+void outputBits(unsigned char byte, QDebug* continuedDebug = NULL);
 void printVoxelCode(unsigned char* voxelCode);
 int numberOfOnes(unsigned char byte);
 bool oneAtBit(unsigned char byte, int bitIndex);
diff --git a/libraries/shared/src/ThreadedAssignment.cpp b/libraries/shared/src/ThreadedAssignment.cpp
index b16c180c9d..8411c26fc6 100644
--- a/libraries/shared/src/ThreadedAssignment.cpp
+++ b/libraries/shared/src/ThreadedAssignment.cpp
@@ -41,9 +41,9 @@ void ThreadedAssignment::commonInit(const char* targetName, NODE_TYPE nodeType)
     connect(pingNodesTimer, SIGNAL(timeout()), nodeList, SLOT(pingInactiveNodes()));
     pingNodesTimer->start(PING_INACTIVE_NODE_INTERVAL_USECS / 1000);
     
-    QTimer* silentNodeTimer = new QTimer(this);
-    connect(silentNodeTimer, SIGNAL(timeout()), nodeList, SLOT(removeSilentNodes()));
-    silentNodeTimer->start(NODE_SILENCE_THRESHOLD_USECS / 1000);
+    QTimer* silentNodeRemovalTimer = new QTimer(this);
+    connect(silentNodeRemovalTimer, SIGNAL(timeout()), nodeList, SLOT(removeSilentNodes()));
+    silentNodeRemovalTimer->start(NODE_SILENCE_THRESHOLD_USECS / 1000);
 }
 
 void ThreadedAssignment::checkInWithDomainServerOrExit() {
diff --git a/libraries/voxel-server/src/VoxelServer.cpp b/libraries/voxel-server/src/VoxelServer.cpp
index 4f0140d892..1147718486 100644
--- a/libraries/voxel-server/src/VoxelServer.cpp
+++ b/libraries/voxel-server/src/VoxelServer.cpp
@@ -58,14 +58,14 @@ void VoxelServer::beforeRun() {
     const char* SEND_ENVIRONMENTS = "--sendEnvironments";
     bool dontSendEnvironments =  !cmdOptionExists(_argc, _argv, SEND_ENVIRONMENTS);
     if (dontSendEnvironments) {
-        qDebug("Sending environments suppressed...\n");
+        qDebug("Sending environments suppressed...");
         _sendEnvironments = false;
     } else {
         _sendEnvironments = true;
         // should we send environments? Default is yes, but this command line suppresses sending
         const char* MINIMAL_ENVIRONMENT = "--minimalEnvironment";
         _sendMinimalEnvironment =  cmdOptionExists(_argc, _argv, MINIMAL_ENVIRONMENT);
-        qDebug("Using Minimal Environment=%s\n", debug::valueOf(_sendMinimalEnvironment));
+        qDebug("Using Minimal Environment=%s", debug::valueOf(_sendMinimalEnvironment));
     }
-    qDebug("Sending environments=%s\n", debug::valueOf(_sendEnvironments));
+    qDebug("Sending environments=%s", debug::valueOf(_sendEnvironments));
 }
diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp
index 3f305605e7..e55cc119ee 100644
--- a/libraries/voxels/src/VoxelTree.cpp
+++ b/libraries/voxels/src/VoxelTree.cpp
@@ -337,14 +337,14 @@ bool VoxelTree::readFromSchematicFile(const char *fileName) {
     std::stringstream ss;
     int err = retrieveData(std::string(fileName), ss);
     if (err && ss.get() != TAG_Compound) {
-        qDebug("[ERROR] Invalid schematic file.\n");
+        qDebug("[ERROR] Invalid schematic file.");
         return false;
     }
 
     ss.get();
     TagCompound schematics(ss);
     if (!schematics.getBlocksId() || !schematics.getBlocksData()) {
-        qDebug("[ERROR] Invalid schematic data.\n");
+        qDebug("[ERROR] Invalid schematic data.");
         return false;
     }
 
@@ -369,7 +369,7 @@ bool VoxelTree::readFromSchematicFile(const char *fileName) {
 
             for (int x = 0; x < schematics.getWidth(); ++x) {
                 if (_stopImport) {
-                    qDebug("[DEBUG] Canceled import at %d voxels.\n", count);
+                    qDebug("[DEBUG] Canceled import at %d voxels.", count);
                     _stopImport = false;
                     return true;
                 }
@@ -420,7 +420,7 @@ bool VoxelTree::readFromSchematicFile(const char *fileName) {
     }
 
     emit importProgress(100);
-    qDebug("Created %d voxels from minecraft import.\n", count);
+    qDebug("Created %d voxels from minecraft import.", count);
 
     return true;
 }
@@ -459,7 +459,7 @@ void VoxelTree::readCodeColorBufferToTreeRecursion(VoxelTreeElement* node, ReadC
             }
         } else {
             if (!node->isLeaf()) {
-                qDebug("WARNING! operation would require deleting children, add Voxel ignored!\n ");
+                qDebug("WARNING! operation would require deleting children, add Voxel ignored!");
             }
         }
 
diff --git a/libraries/voxels/src/VoxelTreeElement.cpp b/libraries/voxels/src/VoxelTreeElement.cpp
index e3d0bf3f18..557d401311 100644
--- a/libraries/voxels/src/VoxelTreeElement.cpp
+++ b/libraries/voxels/src/VoxelTreeElement.cpp
@@ -6,7 +6,6 @@
 //  Copyright (c) 2013 HighFidelity, Inc. All rights reserved.
 //
 
-#include <QtCore/QDebug>
 #include <NodeList.h>
 #include <PerfStat.h>
 
diff --git a/libraries/voxels/src/VoxelTreeElement.h b/libraries/voxels/src/VoxelTreeElement.h
index d30007aca1..1eee7e4a5b 100644
--- a/libraries/voxels/src/VoxelTreeElement.h
+++ b/libraries/voxels/src/VoxelTreeElement.h
@@ -92,4 +92,4 @@ protected:
 };
 
 
-#endif /* defined(__hifi__VoxelTreeElement__) */
+#endif /* defined(__hifi__VoxelTreeElement__) */
\ No newline at end of file
diff --git a/voxel-edit/src/main.cpp b/voxel-edit/src/main.cpp
index 9f655061ed..e2529a4599 100644
--- a/voxel-edit/src/main.cpp
+++ b/voxel-edit/src/main.cpp
@@ -23,36 +23,36 @@ bool countVoxelsOperation(VoxelTreeElement* node, void* extraData) {
 }
 
 void addLandscape(VoxelTree * tree) {
-    printf("Adding Landscape...\n");
+    qDebug("Adding Landscape...");
 }
 
 void voxelTutorial(VoxelTree * tree) {
-    printf("adding scene...\n");
+    qDebug("adding scene...");
 
     // We want our corner voxels to be about 1/2 meter high, and our TREE_SCALE is in meters, so...
     float voxelSize = 0.5f / TREE_SCALE;
 
     // Here's an example of how to create a voxel.
-    printf("creating corner points...\n");
+    qDebug("creating corner points...");
     tree->createVoxel(0, 0, 0, voxelSize, 255, 255 ,255);
 
     // Here's an example of how to test if a voxel exists
     VoxelTreeElement* node = tree->getVoxelAt(0, 0, 0, voxelSize);
     if (node) {
         // and how to access it's color
-        printf("corner point 0,0,0 exists... color is (%d,%d,%d) \n",
+        qDebug("corner point 0,0,0 exists... color is (%d,%d,%d)",
             node->getColor()[0], node->getColor()[1], node->getColor()[2]);
     }
 
     // here's an example of how to delete a voxel
-    printf("attempting to delete corner point 0,0,0\n");
+    qDebug("attempting to delete corner point 0,0,0");
     tree->deleteVoxelAt(0, 0, 0, voxelSize);
 
     // Test to see that the delete worked... it should be FALSE...
     if (tree->getVoxelAt(0, 0, 0, voxelSize)) {
-        printf("corner point 0,0,0 exists...\n");
+        qDebug("corner point 0,0,0 exists...");
     } else {
-        printf("corner point 0,0,0 does not exists...\n");
+        qDebug("corner point 0,0,0 does not exists...");
     }
 }
 
@@ -60,7 +60,7 @@ void voxelTutorial(VoxelTree * tree) {
 void processSplitSVOFile(const char* splitSVOFile,const char* splitJurisdictionRoot,const char*  splitJurisdictionEndNodes) {
     char outputFileName[512];
 
-    printf("splitSVOFile: %s Jurisdictions Root: %s EndNodes: %s\n",
+    qDebug("splitSVOFile: %s Jurisdictions Root: %s EndNodes: %s",
             splitSVOFile, splitJurisdictionRoot, splitJurisdictionEndNodes);
 
     VoxelTree rootSVO;
@@ -68,13 +68,13 @@ void processSplitSVOFile(const char* splitSVOFile,const char* splitJurisdictionR
     rootSVO.readFromSVOFile(splitSVOFile);
     JurisdictionMap jurisdiction(splitJurisdictionRoot, splitJurisdictionEndNodes);
 
-    printf("Jurisdiction Root Octcode: ");
+    qDebug("Jurisdiction Root Octcode: ");
     printOctalCode(jurisdiction.getRootOctalCode());
 
-    printf("Jurisdiction End Nodes: %d \n", jurisdiction.getEndNodeCount());
+    qDebug("Jurisdiction End Nodes: %d ", jurisdiction.getEndNodeCount());
     for (int i = 0; i < jurisdiction.getEndNodeCount(); i++) {
         unsigned char* endNodeCode = jurisdiction.getEndNodeOctalCode(i);
-        printf("End Node: %d ", i);
+        qDebug("End Node: %d ", i);
         printOctalCode(endNodeCode);
 
         // get the endNode details
@@ -113,7 +113,7 @@ void processSplitSVOFile(const char* splitSVOFile,const char* splitJurisdictionR
         rootSVO.copySubTreeIntoNewTree(endNode, &endNodeTree, false);
 
         sprintf(outputFileName, "splitENDNODE%d%s", i, splitSVOFile);
-        printf("outputFile: %s\n", outputFileName);
+        qDebug("outputFile: %s", outputFileName);
         endNodeTree.writeToSVOFile(outputFileName);
 
         // Delete the voxel for the EndNode from the root tree...
@@ -133,10 +133,10 @@ void processSplitSVOFile(const char* splitSVOFile,const char* splitJurisdictionR
     }
 
     sprintf(outputFileName, "splitROOT%s", splitSVOFile);
-    printf("outputFile: %s\n", outputFileName);
+    qDebug("outputFile: %s", outputFileName);
     rootSVO.writeToSVOFile(outputFileName);
 
-    printf("exiting now\n");
+    qDebug("exiting now");
 }
 
 class copyAndFillArgs {
@@ -198,40 +198,39 @@ bool copyAndFillOperation(OctreeElement* element, void* extraData) {
 void processFillSVOFile(const char* fillSVOFile) {
     char outputFileName[512];
 
-    printf("fillSVOFile: %s\n", fillSVOFile);
+    qDebug("fillSVOFile: %s", fillSVOFile);
 
     VoxelTree originalSVO(true); // reaveraging
     VoxelTree filledSVO(true); // reaveraging
 
     originalSVO.readFromSVOFile(fillSVOFile);
-    qDebug("Nodes after loading %lu nodes\n", originalSVO.getOctreeElementsCount());
+    qDebug("Nodes after loading %lu nodes", originalSVO.getOctreeElementsCount());
     originalSVO.reaverageOctreeElements();
-    qDebug("Original Voxels reAveraged\n");
-    qDebug("Nodes after reaveraging %lu nodes\n", originalSVO.getOctreeElementsCount());
+    qDebug("Original Voxels reAveraged");
+    qDebug("Nodes after reaveraging %lu nodes", originalSVO.getOctreeElementsCount());
 
     copyAndFillArgs args;
     args.destinationTree = &filledSVO;
     args.inCount = 0;
     args.outCount = 0;
     args.originalCount = originalSVO.getOctreeElementsCount();
-
-    printf("Begin processing...\n");
+    qDebug("Begin processing...");
     originalSVO.recurseTreeWithOperation(copyAndFillOperation, &args);
-    printf("DONE processing...\n");
+    qDebug("DONE processing...");
 
-    qDebug("Original input nodes used for filling %lu nodes\n", args.originalCount);
-    qDebug("Input nodes traversed during filling %lu nodes\n", args.inCount);
-    qDebug("Nodes created during filling %lu nodes\n", args.outCount);
-    qDebug("Nodes after filling %lu nodes\n", filledSVO.getOctreeElementsCount());
+    qDebug("Original input nodes used for filling %lu nodes", args.originalCount);
+    qDebug("Input nodes traversed during filling %lu nodes", args.inCount);
+    qDebug("Nodes created during filling %lu nodes", args.outCount);
+    qDebug("Nodes after filling %lu nodes", filledSVO.getOctreeElementsCount());
 
     filledSVO.reaverageOctreeElements();
-    qDebug("Nodes after reaveraging %lu nodes\n", filledSVO.getOctreeElementsCount());
+    qDebug("Nodes after reaveraging %lu nodes", filledSVO.getOctreeElementsCount());
 
     sprintf(outputFileName, "filled%s", fillSVOFile);
-    printf("outputFile: %s\n", outputFileName);
+    qDebug("outputFile: %s", outputFileName);
     filledSVO.writeToSVOFile(outputFileName);
 
-    printf("exiting now\n");
+    qDebug("exiting now");
 }
 
 void unitTest(VoxelTree * tree);
@@ -265,18 +264,18 @@ int main(int argc, const char * argv[])
             float z = zStr.toFloat()/TREE_SCALE; // 0.56540045166016;
             float s = sStr.toFloat()/TREE_SCALE; // 0.015625;
 
-            qDebug() << "Get Octal Code for:\n";
-            qDebug() << "    x:" << xStr << " [" << x << "] \n";
-            qDebug() << "    y:" << yStr << " [" << y << "] \n";
-            qDebug() << "    z:" << zStr << " [" << z << "] \n";
-            qDebug() << "    s:" << sStr << " [" << s << "] \n";
+            qDebug() << "Get Octal Code for:";
+            qDebug() << "    x:" << xStr << " [" << x << "]";
+            qDebug() << "    y:" << yStr << " [" << y << "]";
+            qDebug() << "    z:" << zStr << " [" << z << "]";
+            qDebug() << "    s:" << sStr << " [" << s << "]";
 
             unsigned char* octalCode = pointToVoxel(x, y, z, s);
             QString octalCodeStr = octalCodeToHexString(octalCode);
-            qDebug() << "octal code: " << octalCodeStr << "\n";
+            qDebug() << "octal code: " << octalCodeStr;
 
         } else {
-            qDebug() << "Unexpected number of parameters for getOctCode\n";
+            qDebug() << "Unexpected number of parameters for getOctCode";
         }
         return 0;
     }
@@ -293,12 +292,12 @@ int main(int argc, const char * argv[])
 
         delete[] octalCodeToDecode;
 
-        qDebug() << "octal code to decode: " << decodeParamsString << "\n";
-        qDebug() << "Details for Octal Code:\n";
-        qDebug() << "    x:" << details.x << "[" << details.x * TREE_SCALE << "]" << "\n";
-        qDebug() << "    y:" << details.y << "[" << details.y * TREE_SCALE << "]" << "\n";
-        qDebug() << "    z:" << details.z << "[" << details.z * TREE_SCALE << "]" << "\n";
-        qDebug() << "    s:" << details.s << "[" << details.s * TREE_SCALE << "]" << "\n";
+        qDebug() << "octal code to decode: " << decodeParamsString;
+        qDebug() << "Details for Octal Code:";
+        qDebug() << "    x:" << details.x << "[" << details.x * TREE_SCALE << "]";
+        qDebug() << "    y:" << details.y << "[" << details.y * TREE_SCALE << "]";
+        qDebug() << "    z:" << details.z << "[" << details.z * TREE_SCALE << "]";
+        qDebug() << "    s:" << details.s << "[" << details.s * TREE_SCALE << "]";
         return 0;
     }
 
@@ -329,9 +328,9 @@ int main(int argc, const char * argv[])
     bool dontCreateFile = cmdOptionExists(argc, argv, DONT_CREATE_FILE);
 
     if (dontCreateFile) {
-        printf("You asked us not to create a scene file, so we will not.\n");
+        qDebug("You asked us not to create a scene file, so we will not.");
     } else {
-        printf("Creating Scene File...\n");
+        qDebug("Creating Scene File...");
 
         const char* RUN_TUTORIAL = "--runTutorial";
         if (cmdOptionExists(argc, argv, RUN_TUTORIAL)) {
@@ -349,7 +348,7 @@ int main(int argc, const char * argv[])
         }
 
         unsigned long nodeCount = myTree.getOctreeElementsCount();
-        printf("Nodes after adding scenes: %ld nodes\n", nodeCount);
+        qDebug("Nodes after adding scenes: %ld nodes", nodeCount);
 
         myTree.writeToSVOFile("voxels.svo");
     }
@@ -358,123 +357,123 @@ int main(int argc, const char * argv[])
 
 void unitTest(VoxelTree * tree) {
     VoxelTreeElement* node = NULL;
-    printf("unit tests...\n");
+    qDebug("unit tests...");
     unsigned long nodeCount;
 
     // We want our corner voxels to be about 1/2 meter high, and our TREE_SCALE is in meters, so...
     float voxelSize = 0.5f / TREE_SCALE;
 
     // Here's an example of how to create a voxel.
-    printf("creating corner points...\n");
+    qDebug("creating corner points...");
     tree->createVoxel(0, 0, 0, voxelSize, 255, 255 ,255);
-    printf("Nodes at line %d... %ld nodes\n", __LINE__, tree->getOctreeElementsCount());
+    qDebug("Nodes at line %d... %ld nodes", __LINE__, tree->getOctreeElementsCount());
 
 
     // Here's an example of how to test if a voxel exists
     node = tree->getVoxelAt(0, 0, 0, voxelSize);
     if (node) {
         // and how to access it's color
-        printf("CORRECT - corner point 0,0,0 exists... color is (%d,%d,%d) \n",
+        qDebug("CORRECT - corner point 0,0,0 exists... color is (%d,%d,%d) ",
             node->getColor()[0], node->getColor()[1], node->getColor()[2]);
     }
 
-    printf("Nodes at line %d... %ld nodes\n", __LINE__, tree->getOctreeElementsCount());
+    qDebug("Nodes at line %d... %ld nodes", __LINE__, tree->getOctreeElementsCount());
 
     // here's an example of how to delete a voxel
-    printf("attempting to delete corner point 0,0,0\n");
+    qDebug("attempting to delete corner point 0,0,0");
     tree->deleteVoxelAt(0, 0, 0, voxelSize);
 
-    printf("Nodes at line %d... %ld nodes\n", __LINE__, tree->getOctreeElementsCount());
+    qDebug("Nodes at line %d... %ld nodes", __LINE__, tree->getOctreeElementsCount());
 
     // Test to see that the delete worked... it should be FALSE...
     if ((node = tree->getVoxelAt(0, 0, 0, voxelSize))) {
-        printf("FAIL corner point 0,0,0 exists...\n");
+        qDebug("FAIL corner point 0,0,0 exists...");
     } else {
-        printf("CORRECT corner point 0,0,0 does not exists...\n");
+        qDebug("CORRECT corner point 0,0,0 does not exists...");
     }
 
-    printf("Nodes at line %d... %ld nodes\n", __LINE__, tree->getOctreeElementsCount());
+    qDebug("Nodes at line %d... %ld nodes", __LINE__, tree->getOctreeElementsCount());
 
     tree->createVoxel(0, 0, 0, voxelSize, 255, 255 ,255);
     if ((node = tree->getVoxelAt(0, 0, 0, voxelSize))) {
-        printf("CORRECT - corner point 0,0,0 exists... color is (%d,%d,%d) \n",
+        qDebug("CORRECT - corner point 0,0,0 exists... color is (%d,%d,%d) ",
             node->getColor()[0], node->getColor()[1], node->getColor()[2]);
     } else {
-        printf("FAIL corner point 0,0,0 does not exists...\n");
+        qDebug("FAIL corner point 0,0,0 does not exists...");
     }
 
-    printf("Nodes at line %d... %ld nodes\n", __LINE__, tree->getOctreeElementsCount());
+    qDebug("Nodes at line %d... %ld nodes", __LINE__, tree->getOctreeElementsCount());
 
     tree->createVoxel(voxelSize, 0, 0, voxelSize, 255, 255 ,0);
     if ((node = tree->getVoxelAt(voxelSize, 0, 0, voxelSize))) {
-        printf("CORRECT - corner point voxelSize,0,0 exists... color is (%d,%d,%d) \n",
+        qDebug("CORRECT - corner point voxelSize,0,0 exists... color is (%d,%d,%d) ",
             node->getColor()[0], node->getColor()[1], node->getColor()[2]);
     } else {
-        printf("FAIL corner point voxelSize,0,0 does not exists...\n");
+        qDebug("FAIL corner point voxelSize,0,0 does not exists...");
     }
 
-    printf("Nodes at line %d... %ld nodes\n", __LINE__, tree->getOctreeElementsCount());
+    qDebug("Nodes at line %d... %ld nodes", __LINE__, tree->getOctreeElementsCount());
 
     tree->createVoxel(0, 0, voxelSize, voxelSize, 255, 0 ,0);
     if ((node = tree->getVoxelAt(0, 0, voxelSize, voxelSize))) {
-        printf("CORRECT - corner point 0, 0, voxelSize exists... color is (%d,%d,%d) \n",
+        qDebug("CORRECT - corner point 0, 0, voxelSize exists... color is (%d,%d,%d) ",
             node->getColor()[0], node->getColor()[1], node->getColor()[2]);
     } else {
-        printf("FAILED corner point 0, 0, voxelSize does not exists...\n");
+        qDebug("FAILED corner point 0, 0, voxelSize does not exists...");
     }
 
-    printf("Nodes at line %d... %ld nodes\n", __LINE__, tree->getOctreeElementsCount());
+    qDebug("Nodes at line %d... %ld nodes", __LINE__, tree->getOctreeElementsCount());
 
     tree->createVoxel(voxelSize, 0, voxelSize, voxelSize, 0, 0 ,255);
     if ((node = tree->getVoxelAt(voxelSize, 0, voxelSize, voxelSize))) {
-        printf("CORRECT - corner point voxelSize, 0, voxelSize exists... color is (%d,%d,%d) \n",
+        qDebug("CORRECT - corner point voxelSize, 0, voxelSize exists... color is (%d,%d,%d) ",
             node->getColor()[0], node->getColor()[1], node->getColor()[2]);
     } else {
-        printf("corner point voxelSize, 0, voxelSize does not exists...\n");
+        qDebug("corner point voxelSize, 0, voxelSize does not exists...");
     }
 
-    printf("Nodes at line %d... %ld nodes\n", __LINE__, tree->getOctreeElementsCount());
+    qDebug("Nodes at line %d... %ld nodes", __LINE__, tree->getOctreeElementsCount());
 
-    printf("check root voxel exists...\n");
+    qDebug("check root voxel exists...");
     if (tree->getVoxelAt(0,0,0,1.0)) {
-        printf("of course it does\n");
+        qDebug("of course it does");
     } else {
-        printf("WTH!?!\n");
+        qDebug("WTH!?!");
     }
 
     nodeCount = tree->getOctreeElementsCount();
-    printf("Nodes before writing file: %ld nodes\n", nodeCount);
+    qDebug("Nodes before writing file: %ld nodes", nodeCount);
 
     tree->writeToSVOFile("voxels.svo");
 
-    printf("erasing the tree...\n");
+    qDebug("erasing the tree...");
     tree->eraseAllOctreeElements();
 
-    printf("check root voxel exists...\n");
+    qDebug("check root voxel exists...");
     if (tree->getVoxelAt(0,0,0,1.0)) {
-        printf("of course it does\n");
+        qDebug("of course it does");
     } else {
-        printf("WTH!?!\n");
+        qDebug("WTH!?!");
     }
 
     // this should not exist... we just deleted it...
     if (tree->getVoxelAt(voxelSize, 0, voxelSize, voxelSize)) {
-        printf("corner point voxelSize, 0, voxelSize exists...\n");
+        qDebug("corner point voxelSize, 0, voxelSize exists...");
     } else {
-        printf("corner point voxelSize, 0, voxelSize does not exists...\n");
+        qDebug("corner point voxelSize, 0, voxelSize does not exists...");
     }
 
     tree->readFromSVOFile("voxels.svo");
 
     // this should exist... we just loaded it...
     if (tree->getVoxelAt(voxelSize, 0, voxelSize, voxelSize)) {
-        printf("corner point voxelSize, 0, voxelSize exists...\n");
+        qDebug("corner point voxelSize, 0, voxelSize exists...");
     } else {
-        printf("corner point voxelSize, 0, voxelSize does not exists...\n");
+        qDebug("corner point voxelSize, 0, voxelSize does not exists...");
     }
 
     nodeCount = tree->getOctreeElementsCount();
-    printf("Nodes after loading file: %ld nodes\n", nodeCount);
+    qDebug("Nodes after loading file: %ld nodes", nodeCount);
 
 
 }