diff --git a/cmake/externals/crashpad/CMakeLists.txt b/cmake/externals/crashpad/CMakeLists.txt
new file mode 100644
index 0000000000..c464dcbc1b
--- /dev/null
+++ b/cmake/externals/crashpad/CMakeLists.txt
@@ -0,0 +1,35 @@
+include(ExternalProject)
+set(EXTERNAL_NAME crashpad)
+
+string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
+
+if (WIN32)
+    ExternalProject_Add(
+      ${EXTERNAL_NAME}
+      URL https://backtrace.io/download/crashpad_062317.zip
+      URL_MD5 65817e564b3628492abfc1dbd2a1e98b
+      CONFIGURE_COMMAND ""
+      BUILD_COMMAND ""
+      INSTALL_COMMAND ""
+      LOG_DOWNLOAD 1
+    )
+
+    ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
+
+    set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/include CACHE PATH "List of Crashpad include directories")
+
+    set(LIB_EXT "lib")
+
+    set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${SOURCE_DIR}/out/Release_x64/lib_MD/${LIB_PREFIX}crashpad_client.${LIB_EXT} CACHE FILEPATH "Path to Crashpad release library")
+    set(${EXTERNAL_NAME_UPPER}_BASE_LIBRARY_RELEASE ${SOURCE_DIR}/out/Release_x64/lib_MD/${LIB_PREFIX}base.${LIB_EXT} CACHE FILEPATH "Path to Crashpad base release library")
+    set(${EXTERNAL_NAME_UPPER}_UTIL_LIBRARY_RELEASE ${SOURCE_DIR}/out/Release_x64/lib_MD/${LIB_PREFIX}crashpad_util.${LIB_EXT} CACHE FILEPATH "Path to Crashpad util release library")
+
+    set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${SOURCE_DIR}/out/Debug_x64/lib_MD/${LIB_PREFIX}crashpad_client.${LIB_EXT} CACHE FILEPATH "Path to Crashpad debug library")
+    set(${EXTERNAL_NAME_UPPER}_BASE_LIBRARY_DEBUG ${SOURCE_DIR}/out/Debug_x64/lib_MD/${LIB_PREFIX}base.${LIB_EXT} CACHE FILEPATH "Path to Crashpad base debug library")
+    set(${EXTERNAL_NAME_UPPER}_UTIL_LIBRARY_DEBUG ${SOURCE_DIR}/out/Debug_x64/lib_MD/${LIB_PREFIX}crashpad_util.${LIB_EXT} CACHE FILEPATH "Path to Crashpad util debug library")
+
+    set(CRASHPAD_HANDLER_EXE_PATH ${SOURCE_DIR}/out/Release_x64/crashpad_handler.exe CACHE FILEPATH "Path to the Crashpad handler executable")
+endif ()
+
+# Hide this external target (for ide users)
+set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
diff --git a/cmake/macros/AddBugSplat.cmake b/cmake/macros/AddBugSplat.cmake
deleted file mode 100644
index 979dcfe817..0000000000
--- a/cmake/macros/AddBugSplat.cmake
+++ /dev/null
@@ -1,34 +0,0 @@
-#
-#  AddBugSplat.cmake
-#  cmake/macros
-#
-#  Created by Ryan Huffman on 02/09/16.
-#  Copyright 2016 High Fidelity, Inc.
-#
-#  Distributed under the Apache License, Version 2.0.
-#  See the accompanying file LICENSE or http:#www.apache.org/licenses/LICENSE-2.0.html
-#
-
-macro(add_bugsplat)
-  get_property(BUGSPLAT_CHECKED GLOBAL PROPERTY CHECKED_FOR_BUGSPLAT_ONCE)
-
-  if (NOT BUGSPLAT_CHECKED)
-    find_package(BugSplat)
-    set_property(GLOBAL PROPERTY CHECKED_FOR_BUGSPLAT_ONCE TRUE)
-  endif ()
-
-  if (BUGSPLAT_FOUND)
-    add_definitions(-DHAS_BUGSPLAT)
-
-    target_include_directories(${TARGET_NAME} PRIVATE ${BUGSPLAT_INCLUDE_DIRS})
-    target_link_libraries(${TARGET_NAME} ${BUGSPLAT_LIBRARIES})
-    add_paths_to_fixup_libs(${BUGSPLAT_DLL_PATH})
-
-    add_custom_command(TARGET ${TARGET_NAME}
-      POST_BUILD
-      COMMAND ${CMAKE_COMMAND} -E copy ${BUGSPLAT_RC_DLL_PATH} "$<TARGET_FILE_DIR:${TARGET_NAME}>/")
-    add_custom_command(TARGET ${TARGET_NAME}
-      POST_BUILD
-      COMMAND ${CMAKE_COMMAND} -E copy ${BUGSPLAT_EXE_PATH} "$<TARGET_FILE_DIR:${TARGET_NAME}>/")
-  endif ()
-endmacro()
diff --git a/cmake/macros/AddCrashpad.cmake b/cmake/macros/AddCrashpad.cmake
new file mode 100644
index 0000000000..bf59418f37
--- /dev/null
+++ b/cmake/macros/AddCrashpad.cmake
@@ -0,0 +1,58 @@
+#
+#  AddCrashpad.cmake
+#  cmake/macros
+#
+#  Created by Clement Brisset on 01/19/18.
+#  Copyright 2018 High Fidelity, Inc.
+#
+#  Distributed under the Apache License, Version 2.0.
+#  See the accompanying file LICENSE or http:#www.apache.org/licenses/LICENSE-2.0.html
+#
+
+macro(add_crashpad)
+  set (USE_CRASHPAD TRUE)
+  if ("$ENV{CMAKE_BACKTRACE_URL}" STREQUAL "")
+    set(USE_CRASHPAD FALSE)
+  else()
+    set(CMAKE_BACKTRACE_URL $ENV{CMAKE_BACKTRACE_URL})
+  endif()
+
+  if ("$ENV{CMAKE_BACKTRACE_TOKEN}" STREQUAL "")
+    set(USE_CRASHPAD FALSE)
+  else()
+    set(CMAKE_BACKTRACE_TOKEN $ENV{CMAKE_BACKTRACE_TOKEN})
+  endif()
+
+  if (WIN32 AND USE_CRASHPAD)
+    get_property(CRASHPAD_CHECKED GLOBAL PROPERTY CHECKED_FOR_CRASHPAD_ONCE)
+    if (NOT CRASHPAD_CHECKED)
+
+      add_dependency_external_projects(crashpad)
+      find_package(crashpad REQUIRED)
+
+      set_property(GLOBAL PROPERTY CHECKED_FOR_CRASHPAD_ONCE TRUE)
+    endif()
+
+    add_definitions(-DHAS_CRASHPAD)
+    add_definitions(-DCMAKE_BACKTRACE_URL=\"${CMAKE_BACKTRACE_URL}\")
+    add_definitions(-DCMAKE_BACKTRACE_TOKEN=\"${CMAKE_BACKTRACE_TOKEN}\")
+
+    target_include_directories(${TARGET_NAME} PRIVATE ${CRASHPAD_INCLUDE_DIRS})
+    target_link_libraries(${TARGET_NAME} ${CRASHPAD_LIBRARY} ${CRASHPAD_BASE_LIBRARY} ${CRASHPAD_UTIL_LIBRARY})
+
+    if (WIN32)
+      set_target_properties(${TARGET_NAME} PROPERTIES LINK_FLAGS "/ignore:4099")
+    endif()
+
+    add_custom_command(
+      TARGET ${TARGET_NAME}
+      POST_BUILD
+      COMMAND ${CMAKE_COMMAND} -E copy ${CRASHPAD_HANDLER_EXE_PATH} "$<TARGET_FILE_DIR:${TARGET_NAME}>/"
+    )
+    install(
+      PROGRAMS ${CRASHPAD_HANDLER_EXE_PATH}
+      DESTINATION ${CLIENT_COMPONENT}
+      COMPONENT ${INTERFACE_INSTALL_DIR}
+    )
+  endif ()
+endmacro()
diff --git a/cmake/modules/FindBugSplat.cmake b/cmake/modules/FindBugSplat.cmake
deleted file mode 100644
index 8bea1cb1e1..0000000000
--- a/cmake/modules/FindBugSplat.cmake
+++ /dev/null
@@ -1,30 +0,0 @@
-#
-#  FindBugSplat.cmake
-#  cmake/modules
-#
-#  Created by Ryan Huffman on 02/09/16.
-#  Copyright 2016 High Fidelity, Inc.
-#
-#  Distributed under the Apache License, Version 2.0.
-#  See the accompanying file LICENSE or http:#www.apache.org/licenses/LICENSE-2.0.html
-#
-
-if (WIN32)
-  include("${MACRO_DIR}/HifiLibrarySearchHints.cmake")
-  hifi_library_search_hints("BugSplat")
-
-  find_path(BUGSPLAT_INCLUDE_DIRS NAMES BugSplat.h PATH_SUFFIXES inc HINTS ${BUGSPLAT_SEARCH_DIRS})
-
-  find_library(BUGSPLAT_LIBRARY_RELEASE "BugSplat64.lib" PATH_SUFFIXES "lib64" HINTS ${BUGSPLAT_SEARCH_DIRS})
-  find_path(BUGSPLAT_DLL_PATH NAMES "BugSplat64.dll" PATH_SUFFIXES "bin64" HINTS ${BUGSPLAT_SEARCH_DIRS})
-  find_file(BUGSPLAT_RC_DLL_PATH NAMES "BugSplatRc64.dll" PATH_SUFFIXES "bin64" HINTS ${BUGSPLAT_SEARCH_DIRS})
-  find_file(BUGSPLAT_EXE_PATH NAMES "BsSndRpt64.exe" PATH_SUFFIXES "bin64" HINTS ${BUGSPLAT_SEARCH_DIRS})
-
-  include(SelectLibraryConfigurations)
-  select_library_configurations(BUGSPLAT)
-
-  set(BUGSPLAT_LIBRARIES ${BUGSPLAT_LIBRARY_RELEASE})
-endif ()
-
-set(BUGSPLAT_REQUIREMENTS BUGSPLAT_INCLUDE_DIRS BUGSPLAT_LIBRARIES BUGSPLAT_DLL_PATH BUGSPLAT_RC_DLL_PATH BUGSPLAT_EXE_PATH)
-find_package_handle_standard_args(BugSplat DEFAULT_MSG ${BUGSPLAT_REQUIREMENTS})
diff --git a/cmake/modules/FindCrashpad.cmake b/cmake/modules/FindCrashpad.cmake
new file mode 100644
index 0000000000..283058336d
--- /dev/null
+++ b/cmake/modules/FindCrashpad.cmake
@@ -0,0 +1,41 @@
+#
+#  FindCrashpad.cmake
+#
+#  Try to find Crashpad libraries and include path.
+#  Once done this will define
+#
+#  CRASHPAD_FOUND
+#  CRASHPAD_INCLUDE_DIRS
+#  CRASHPAD_LIBRARY
+#  CRASHPAD_BASE_LIBRARY
+#  CRASHPAD_UTIL_LIBRARY
+#
+#  Created on 01/19/2018 by Clement Brisset
+#  Copyright 2018 High Fidelity, Inc.
+#
+#  Distributed under the Apache License, Version 2.0.
+#  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+#
+
+include("${MACRO_DIR}/HifiLibrarySearchHints.cmake")
+hifi_library_search_hints("crashpad")
+
+find_path(CRASHPAD_INCLUDE_DIRS base/macros.h PATH_SUFFIXES include HINTS ${CRASHPAD_SEARCH_DIRS})
+
+find_library(CRASHPAD_LIBRARY_RELEASE crashpad PATH_SUFFIXES "Release_x64/lib_MD" HINTS ${CRASHPAD_SEARCH_DIRS})
+find_library(CRASHPAD_BASE_LIBRARY_RELEASE base PATH_SUFFIXES "Release_x64/lib_MD" HINTS ${CRASHPAD_SEARCH_DIRS})
+find_library(CRASHPAD_UTIL_LIBRARY_RELEASE util PATH_SUFFIXES "Release_x64/lib_MD" HINTS ${CRASHPAD_SEARCH_DIRS})
+
+find_library(CRASHPAD_LIBRARY_DEBUG crashpad PATH_SUFFIXES "Debug_x64/lib_MD" HINTS ${CRASHPAD_SEARCH_DIRS})
+find_library(CRASHPAD_BASE_LIBRARY_DEBUG base PATH_SUFFIXES "Debug_x64/lib_MD" HINTS ${CRASHPAD_SEARCH_DIRS})
+find_library(CRASHPAD_UTIL_LIBRARY_DEBUG util PATH_SUFFIXES "Debug_x64/lib_MD" HINTS ${CRASHPAD_SEARCH_DIRS})
+
+find_file(CRASHPAD_HANDLER_EXE_PATH NAME "crashpad_handler.exe" PATH_SUFFIXES "Release_x64" HINTS ${CRASHPAD_SEARCH_DIRS})
+
+include(SelectLibraryConfigurations)
+select_library_configurations(CRASHPAD)
+select_library_configurations(CRASHPAD_BASE)
+select_library_configurations(CRASHPAD_UTIL)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(CRASHPAD DEFAULT_MSG CRASHPAD_INCLUDE_DIRS CRASHPAD_LIBRARY CRASHPAD_BASE_LIBRARY CRASHPAD_UTIL_LIBRARY)
diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp
index 290f4a7f53..22273ae85f 100644
--- a/domain-server/src/DomainServer.cpp
+++ b/domain-server/src/DomainServer.cpp
@@ -157,7 +157,6 @@ DomainServer::DomainServer(int argc, char* argv[]) :
     DependencyManager::set<StatTracker>();
 
     LogUtils::init();
-    Setting::init();
 
     qDebug() << "Setting up domain-server";
     qDebug() << "[VERSION] Build sequence:" << qPrintable(applicationVersion());
diff --git a/domain-server/src/main.cpp b/domain-server/src/main.cpp
index 725a04ec46..dc3ee54fe7 100644
--- a/domain-server/src/main.cpp
+++ b/domain-server/src/main.cpp
@@ -29,6 +29,8 @@ int main(int argc, char* argv[]) {
     QCoreApplication::setOrganizationDomain(BuildInfo::ORGANIZATION_DOMAIN);
     QCoreApplication::setApplicationVersion(BuildInfo::VERSION);
 
+    Setting::init();
+
 #ifndef WIN32
     setvbuf(stdout, NULL, _IOLBF, 0);
 #endif
diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt
index 383c50ed44..ee2997e216 100644
--- a/interface/CMakeLists.txt
+++ b/interface/CMakeLists.txt
@@ -206,6 +206,7 @@ target_include_directories(${TARGET_NAME} PRIVATE "${CMAKE_BINARY_DIR}/libraries
 
 target_bullet()
 target_opengl()
+add_crashpad()
 
 # perform standard include and linking for found externals
 foreach(EXTERNAL ${OPTIONAL_EXTERNALS})
@@ -350,8 +351,6 @@ if (SCRIPTS_INSTALL_DIR)
   )
 endif()
 
-add_bugsplat()
-
 if (WIN32)
     set(EXTRA_DEPLOY_OPTIONS "--qmldir  \"${PROJECT_SOURCE_DIR}/resources/qml\"")
 
diff --git a/interface/resources/qml/hifi/Feed.qml b/interface/resources/qml/hifi/Feed.qml
index a9629c0e4e..3f3a47a297 100644
--- a/interface/resources/qml/hifi/Feed.qml
+++ b/interface/resources/qml/hifi/Feed.qml
@@ -33,6 +33,7 @@ Column {
     property int labelSize: 20;
 
     property string metaverseServerUrl: '';
+    property string protocol: '';
     property string actions: 'snapshot';
     // sendToScript doesn't get wired until after everything gets created. So we have to queue fillDestinations on nextTick.
     property string labelText: actions;
@@ -102,7 +103,7 @@ Column {
             'include_actions=' + actions,
             'restriction=' + (Account.isLoggedIn() ? 'open,hifi' : 'open'),
             'require_online=true',
-            'protocol=' + encodeURIComponent(Window.protocolSignature()),
+            'protocol=' + protocol,
             'page=' + pageNumber
         ];
         var url = metaverseBase + 'user_stories?' + options.join('&');
diff --git a/interface/resources/qml/hifi/tablet/Edit.qml b/interface/resources/qml/hifi/tablet/Edit.qml
index e2e8c4362e..efd797e12d 100644
--- a/interface/resources/qml/hifi/tablet/Edit.qml
+++ b/interface/resources/qml/hifi/tablet/Edit.qml
@@ -12,7 +12,7 @@ StackView {
     HifiConstants { id: hifi }
 
     function pushSource(path) {
-        editRoot.push(Qt.resolvedUrl(path));
+        editRoot.push(Qt.resolvedUrl("../../" + path));
         editRoot.currentItem.sendToScript.connect(editRoot.sendToScript);
     }
 
diff --git a/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml b/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml
index f3cda533e9..d4550d3843 100644
--- a/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml
+++ b/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml
@@ -54,6 +54,7 @@ StackView {
             console.debug('TabletAddressDialog::fromScript: refreshFeeds', 'feeds = ', feeds);
 
             feeds.forEach(function(feed) {
+                feed.protocol = encodeURIComponent(message.protocolSignature);
                 Qt.callLater(feed.fillDestinations);
             });
 
diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index 3390e71b07..808f6eb890 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -149,6 +149,7 @@
 #include "avatar/AvatarManager.h"
 #include "avatar/MyHead.h"
 #include "CrashHandler.h"
+#include "Crashpad.h"
 #include "devices/DdeFaceTracker.h"
 #include "DiscoverabilityManager.h"
 #include "GLCanvas.h"
@@ -668,8 +669,6 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
     }
 #endif
 
-    Setting::init();
-
     // Tell the plugin manager about our statically linked plugins
     auto pluginManager = PluginManager::getInstance();
     pluginManager->setInputPluginProvider([] { return getInputPlugins(); });
@@ -921,6 +920,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
 
     _logger->setSessionID(accountManager->getSessionID());
 
+    setCrashAnnotation("metaverse_session_id", accountManager->getSessionID().toString().toStdString());
+
     if (steamClient) {
         qCDebug(interfaceapp) << "[VERSION] SteamVR buildID:" << steamClient->getSteamVRBuildID();
     }
@@ -2294,6 +2295,11 @@ void Application::initializeGL() {
     _renderEngine->addJob<SecondaryCameraRenderTask>("SecondaryCameraJob", cullFunctor, !DISABLE_DEFERRED);
 #endif
     _renderEngine->addJob<RenderViewTask>("RenderMainView", cullFunctor, !DISABLE_DEFERRED);
+
+#ifdef Q_OS_OSX
+    DeadlockWatchdogThread::resume();
+#endif
+
     _renderEngine->load();
     _renderEngine->registerScene(_main3DScene);
 
@@ -6293,7 +6299,7 @@ void Application::showAssetServerWidget(QString filePath) {
         if (!hmd->getShouldShowTablet() && !isHMDMode()) {
             DependencyManager::get<OffscreenUi>()->show(url, "AssetServer", startUpload);
         } else {
-            static const QUrl url("../dialogs/TabletAssetServer.qml");
+            static const QUrl url("hifi/dialogs/TabletAssetServer.qml");
             tablet->pushOntoStack(url);
         }
     }
diff --git a/interface/src/CrashReporter.cpp b/interface/src/CrashReporter.cpp
deleted file mode 100644
index 596c34ca92..0000000000
--- a/interface/src/CrashReporter.cpp
+++ /dev/null
@@ -1,166 +0,0 @@
-//
-//  CrashReporter.cpp
-//  interface/src
-//
-//  Created by Ryan Huffman on 11 April 2016.
-//  Copyright 2016 High Fidelity, Inc.
-//
-//  Distributed under the Apache License, Version 2.0.
-//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
-//
-
-
-#include "Application.h"
-#include "CrashReporter.h"
-
-#ifdef _WIN32
-#include <new.h>
-#include <Windows.h>
-#include <DbgHelp.h>
-
-#include <csignal>
-#include <QDebug>
-
-
-#pragma comment(lib, "Dbghelp.lib")
-
-// SetUnhandledExceptionFilter can be overridden by the CRT at the point that an error occurs. More information
-// can be found here: http://www.codeproject.com/Articles/154686/SetUnhandledExceptionFilter-and-the-C-C-Runtime-Li
-// A fairly common approach is to patch the SetUnhandledExceptionFilter so that it cannot be overridden and so
-// that the applicaiton can handle it itself.
-// The CAPIHook class referenced in the above article is not openly available, but a similar implementation
-// can be found here: http://blog.kalmbach-software.de/2008/04/02/unhandled-exceptions-in-vc8-and-above-for-x86-and-x64/
-// The below has been adapted to work with different library and functions.
-BOOL redirectLibraryFunctionToFunction(char* library, char* function, void* fn)
-{
-    HMODULE lib = LoadLibrary(library);
-    if (lib == NULL) return FALSE;
-    void *pOrgEntry = GetProcAddress(lib, function);
-    if (pOrgEntry == NULL) return FALSE;
-
-    DWORD dwOldProtect = 0;
-    SIZE_T jmpSize = 5;
-#ifdef _M_X64
-    jmpSize = 13;
-#endif
-    BOOL bProt = VirtualProtect(pOrgEntry, jmpSize,
-        PAGE_EXECUTE_READWRITE, &dwOldProtect);
-    BYTE newJump[20];
-    void *pNewFunc = fn;
-#ifdef _M_IX86
-    DWORD dwOrgEntryAddr = (DWORD)pOrgEntry;
-    dwOrgEntryAddr += jmpSize; // add 5 for 5 op-codes for jmp rel32
-    DWORD dwNewEntryAddr = (DWORD)pNewFunc;
-    DWORD dwRelativeAddr = dwNewEntryAddr - dwOrgEntryAddr;
-    // JMP rel32: Jump near, relative, displacement relative to next instruction.
-    newJump[0] = 0xE9;  // JMP rel32
-    memcpy(&newJump[1], &dwRelativeAddr, sizeof(pNewFunc));
-#elif _M_X64
-    // We must use R10 or R11, because these are "scratch" registers 
-    // which need not to be preserved accross function calls
-    // For more info see: Register Usage for x64 64-Bit
-    // http://msdn.microsoft.com/en-us/library/ms794547.aspx
-    // Thanks to Matthew Smith!!!
-    newJump[0] = 0x49;  // MOV R11, ...
-    newJump[1] = 0xBB;  // ...
-    memcpy(&newJump[2], &pNewFunc, sizeof(pNewFunc));
-    //pCur += sizeof (ULONG_PTR);
-    newJump[10] = 0x41;  // JMP R11, ...
-    newJump[11] = 0xFF;  // ...
-    newJump[12] = 0xE3;  // ...
-#endif
-    SIZE_T bytesWritten;
-    BOOL bRet = WriteProcessMemory(GetCurrentProcess(),
-        pOrgEntry, newJump, jmpSize, &bytesWritten);
-
-    if (bProt != FALSE)
-    {
-        DWORD dwBuf;
-        VirtualProtect(pOrgEntry, jmpSize, dwOldProtect, &dwBuf);
-    }
-    return bRet;
-}
-
-void printStackTrace(ULONG framesToSkip = 1) {
-    HANDLE process = GetCurrentProcess();
-    SymInitialize(process, NULL, TRUE);
-    void* stack[100];
-    uint16_t frames = CaptureStackBackTrace(framesToSkip, 100, stack, NULL);
-    SYMBOL_INFO* symbol = (SYMBOL_INFO *)calloc(sizeof(SYMBOL_INFO) + 256 * sizeof(char), 1);
-    symbol->MaxNameLen = 255;
-    symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
-
-    for (uint16_t i = 0; i < frames; ++i) {
-        SymFromAddr(process, (DWORD64)(stack[i]), 0, symbol);
-        qWarning() << QString("%1: %2 - 0x%0X").arg(QString::number(frames - i - 1), QString(symbol->Name), QString::number(symbol->Address, 16));
-    }
-
-    free(symbol);
-
-    // Try to force the log to sync to the filesystem
-    auto app = qApp;
-    if (app && app->getLogger()) {
-        app->getLogger()->sync();
-    }
-}
-
-void handleSignal(int signal) {
-    // Throw so BugSplat can handle
-    throw(signal);
-}
-
-void __cdecl handlePureVirtualCall() {
-    qWarning() << "Pure virtual function call detected";
-    printStackTrace(2);
-    // Throw so BugSplat can handle
-    throw("ERROR: Pure virtual call");
-}
-
-void handleInvalidParameter(const wchar_t * expression, const wchar_t * function, const wchar_t * file,
-                            unsigned int line, uintptr_t pReserved ) {
-    // Throw so BugSplat can handle
-    throw("ERROR: Invalid parameter");
-}
-
-int handleNewError(size_t size) {
-    // Throw so BugSplat can handle
-    throw("ERROR: Errors calling new");
-}
-
-LPTOP_LEVEL_EXCEPTION_FILTER WINAPI noop_SetUnhandledExceptionFilter(LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter) {
-    return nullptr;
-}
-
-_purecall_handler __cdecl noop_set_purecall_handler(_purecall_handler pNew) {
-    return nullptr;
-}
-
-#ifdef HAS_BUGSPLAT
-
-static const DWORD BUG_SPLAT_FLAGS = MDSF_PREVENTHIJACKING | MDSF_USEGUARDMEMORY;
-
-CrashReporter::CrashReporter(QString bugSplatDatabase, QString bugSplatApplicationName, QString version)
-    : mpSender(qPrintable(bugSplatDatabase), qPrintable(bugSplatApplicationName), qPrintable(version), nullptr, BUG_SPLAT_FLAGS)
-{
-    signal(SIGSEGV, handleSignal);
-    signal(SIGABRT, handleSignal);
-    _set_purecall_handler(handlePureVirtualCall);
-    _set_invalid_parameter_handler(handleInvalidParameter);
-    _set_new_mode(1);
-    _set_new_handler(handleNewError);
-
-    // Disable WER popup
-    //SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);
-    //_set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
-
-    // QtWebEngineCore internally sets its own purecall handler, overriding our own error handling. This disables that.
-    if (!redirectLibraryFunctionToFunction("msvcr120.dll", "_set_purecall_handler", &noop_set_purecall_handler)) {
-        qWarning() << "Failed to patch _set_purecall_handler";
-    }
-    // Patch SetUnhandledExceptionFilter to keep the CRT from overriding our own error handling.
-    if (!redirectLibraryFunctionToFunction("kernel32.dll", "SetUnhandledExceptionFilter", &noop_SetUnhandledExceptionFilter)) {
-        qWarning() << "Failed to patch setUnhandledExceptionFilter";
-    }
-}
-#endif
-#endif
diff --git a/interface/src/CrashReporter.h b/interface/src/CrashReporter.h
deleted file mode 100644
index 5f02066a74..0000000000
--- a/interface/src/CrashReporter.h
+++ /dev/null
@@ -1,32 +0,0 @@
-//
-//  CrashReporter.h
-//  interface/src
-//
-//  Created by Ryan Huffman on 11 April 2016.
-//  Copyright 2016 High Fidelity, Inc.
-//
-//  Distributed under the Apache License, Version 2.0.
-//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
-//
-
-#pragma once
-
-#ifndef hifi_CrashReporter_h
-#define hifi_CrashReporter_h
-
-#include <QString>
-
-#ifdef HAS_BUGSPLAT
-
-#include <BugSplat.h>
-
-class CrashReporter {
-public:
-    CrashReporter(QString bugSplatDatabase, QString bugSplatApplicationName, QString version);
-    
-    MiniDmpSender mpSender;
-};
-
-#endif
-
-#endif // hifi_CrashReporter_h
\ No newline at end of file
diff --git a/interface/src/Crashpad.cpp b/interface/src/Crashpad.cpp
new file mode 100644
index 0000000000..8ed3fc23bd
--- /dev/null
+++ b/interface/src/Crashpad.cpp
@@ -0,0 +1,101 @@
+//
+//  Crashpad.cpp
+//  interface/src
+//
+//  Created by Clement Brisset on 01/19/18.
+//  Copyright 2018 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include "Crashpad.h"
+
+#include <QDebug>
+
+#if HAS_CRASHPAD
+
+#include <QStandardPaths>
+#include <QDir>
+
+#include <BuildInfo.h>
+
+#include <client/crashpad_client.h>
+#include <client/crash_report_database.h>
+#include <client/settings.h>
+// #include <client/annotation_list.h>
+// #include <client/crashpad_info.h>
+
+using namespace crashpad;
+
+static const std::string BACKTRACE_URL { CMAKE_BACKTRACE_URL };
+static const std::string BACKTRACE_TOKEN { CMAKE_BACKTRACE_TOKEN };
+
+extern QString qAppFileName();
+
+// crashpad::AnnotationList* crashpadAnnotations { nullptr };
+
+bool startCrashHandler() {
+    if (BACKTRACE_URL.empty() || BACKTRACE_TOKEN.empty()) {
+        return false;
+    }
+
+    CrashpadClient client;
+    std::vector<std::string> arguments;
+
+    std::map<std::string, std::string> annotations;
+    annotations["token"] = BACKTRACE_TOKEN;
+    annotations["format"] = "minidump";
+    annotations["version"] = BuildInfo::VERSION.toStdString();
+
+    arguments.push_back("--no-rate-limit");
+
+    // Setup Crashpad DB directory
+    const auto crashpadDbName = "crashpad-db";
+    const auto crashpadDbDir = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation);
+    QDir(crashpadDbDir).mkpath(crashpadDbName); // Make sure the directory exists
+    const auto crashpadDbPath = crashpadDbDir.toStdString() + "/" + crashpadDbName;
+
+    // Locate Crashpad handler
+    const std::string CRASHPAD_HANDLER_PATH = QFileInfo(qAppFileName()).absolutePath().toStdString() + "/crashpad_handler.exe";
+
+    // Setup different file paths
+    base::FilePath::StringType dbPath;
+    base::FilePath::StringType handlerPath;
+    dbPath.assign(crashpadDbPath.cbegin(), crashpadDbPath.cend());
+    handlerPath.assign(CRASHPAD_HANDLER_PATH.cbegin(), CRASHPAD_HANDLER_PATH.cend());
+
+    base::FilePath db(dbPath);
+    base::FilePath handler(handlerPath);
+
+    auto database = crashpad::CrashReportDatabase::Initialize(db);
+    if (database == nullptr || database->GetSettings() == nullptr) {
+        return false;
+    }
+
+    // Enable automated uploads.
+    database->GetSettings()->SetUploadsEnabled(true);
+
+    return client.StartHandler(handler, db, db, BACKTRACE_URL, annotations, arguments, true, true);
+}
+
+void setCrashAnnotation(std::string name, std::string value) {
+    // if (!crashpadAnnotations) {
+    //     crashpadAnnotations = new crashpad::AnnotationList(); // don't free this, let it leak
+    //     crashpad::CrashpadInfo* crashpad_info = crashpad::GetCrashpadInfo();
+    //     crashpad_info->set_simple_annotations(crashpadAnnotations);
+    // }
+    // crashpadAnnotations->SetKeyValue(name, value);
+}
+
+#else
+
+bool startCrashHandler() {
+    qDebug() << "No crash handler available.";
+    return false;
+}
+
+void setCrashAnnotation(std::string name, std::string value) {
+}
+
+#endif
diff --git a/interface/src/Crashpad.h b/interface/src/Crashpad.h
new file mode 100644
index 0000000000..a815ed701a
--- /dev/null
+++ b/interface/src/Crashpad.h
@@ -0,0 +1,20 @@
+//
+//  Crashpad.h
+//  interface/src
+//
+//  Created by Clement Brisset on 01/19/18.
+//  Copyright 2018 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#ifndef hifi_Crashpad_h
+#define hifi_Crashpad_h
+
+#include <string>
+
+bool startCrashHandler();
+void setCrashAnnotation(std::string name, std::string value);
+
+#endif // hifi_Crashpad_h
diff --git a/interface/src/LODManager.h b/interface/src/LODManager.h
index ca6be9380b..7b10579077 100644
--- a/interface/src/LODManager.h
+++ b/interface/src/LODManager.h
@@ -20,7 +20,7 @@
 #include <render/Args.h>
 
 const float DEFAULT_DESKTOP_LOD_DOWN_FPS = 30.0f;
-const float DEFAULT_HMD_LOD_DOWN_FPS = 45.0f;
+const float DEFAULT_HMD_LOD_DOWN_FPS = 34.0f;
 const float DEFAULT_DESKTOP_MAX_RENDER_TIME = (float)MSECS_PER_SECOND / DEFAULT_DESKTOP_LOD_DOWN_FPS; // msec
 const float DEFAULT_HMD_MAX_RENDER_TIME = (float)MSECS_PER_SECOND / DEFAULT_HMD_LOD_DOWN_FPS; // msec
 const float MAX_LIKELY_DESKTOP_FPS = 59.0f; // this is essentially, V-synch - 1 fps
diff --git a/interface/src/main.cpp b/interface/src/main.cpp
index 80ec78f118..30e8439985 100644
--- a/interface/src/main.cpp
+++ b/interface/src/main.cpp
@@ -26,15 +26,11 @@
 
 #include "AddressManager.h"
 #include "Application.h"
+#include "Crashpad.h"
 #include "InterfaceLogging.h"
 #include "UserActivityLogger.h"
 #include "MainWindow.h"
 
-#ifdef HAS_BUGSPLAT
-#include <BugSplat.h>
-#include <CrashReporter.h>
-#endif
-
 #ifdef Q_OS_WIN
 extern "C" {
     typedef int(__stdcall * CHECKMINSPECPROC) ();
@@ -42,11 +38,6 @@ extern "C" {
 #endif
 
 int main(int argc, const char* argv[]) {
-#if HAS_BUGSPLAT
-    static QString BUG_SPLAT_DATABASE = "interface_alpha";
-    static QString BUG_SPLAT_APPLICATION_NAME = "Interface";
-    CrashReporter crashReporter { BUG_SPLAT_DATABASE, BUG_SPLAT_APPLICATION_NAME, BuildInfo::VERSION };
-#endif
 
 #ifdef Q_OS_LINUX
     QApplication::setAttribute(Qt::AA_DontUseNativeMenuBar);
@@ -71,6 +62,17 @@ int main(int argc, const char* argv[]) {
     QCoreApplication::setOrganizationDomain(BuildInfo::ORGANIZATION_DOMAIN);
     QCoreApplication::setApplicationVersion(BuildInfo::VERSION);
 
+    Setting::init();
+
+    // Instance UserActivityLogger now that the settings are loaded
+    auto& ual = UserActivityLogger::getInstance();
+    qDebug() << "UserActivityLogger is enabled:" << ual.isEnabled();
+
+    if (ual.isEnabled()) {
+        auto crashHandlerStarted = startCrashHandler();
+        qDebug() << "Crash handler started:" << crashHandlerStarted;
+    }
+
     QStringList arguments;
     for (int i = 0; i < argc; ++i) {
         arguments << argv[i];
@@ -259,7 +261,6 @@ int main(int argc, const char* argv[]) {
             }
         }
 #endif
-        
 
         // Setup local server
         QLocalServer server { &app };
@@ -268,29 +269,8 @@ int main(int argc, const char* argv[]) {
         server.removeServer(applicationName);
         server.listen(applicationName);
 
-        QObject::connect(&server, &QLocalServer::newConnection, &app, &Application::handleLocalServerConnection, Qt::DirectConnection);
-
-#ifdef HAS_BUGSPLAT
-        auto accountManager = DependencyManager::get<AccountManager>();
-        crashReporter.mpSender.setDefaultUserName(qPrintable(accountManager->getAccountInfo().getUsername()));
-        QObject::connect(accountManager.data(), &AccountManager::usernameChanged, &app, [&crashReporter](const QString& newUsername) {
-            crashReporter.mpSender.setDefaultUserName(qPrintable(newUsername));
-        });
-
-        // BugSplat WILL NOT work with file paths that do not use OS native separators.
-        auto logger = app.getLogger();
-        auto logPath = QDir::toNativeSeparators(logger->getFilename());
-        crashReporter.mpSender.sendAdditionalFile(qPrintable(logPath));
-
-        QMetaObject::Connection connection;
-        connection = QObject::connect(logger, &FileLogger::rollingLogFile, &app, [&crashReporter, &connection](QString newFilename) {
-            // We only want to add the first rolled log file (the "beginning" of the log) to BugSplat to ensure we don't exceed the 2MB
-            // zipped limit, so we disconnect here.
-            QObject::disconnect(connection);
-            auto rolledLogPath = QDir::toNativeSeparators(newFilename);
-            crashReporter.mpSender.sendAdditionalFile(qPrintable(rolledLogPath));
-        });
-#endif
+        QObject::connect(&server, &QLocalServer::newConnection,
+                         &app, &Application::handleLocalServerConnection, Qt::DirectConnection);
 
         printSystemInformation();
 
diff --git a/libraries/render-utils/src/CauterizedModel.cpp b/libraries/render-utils/src/CauterizedModel.cpp
index e3f26a43d8..0b8c636678 100644
--- a/libraries/render-utils/src/CauterizedModel.cpp
+++ b/libraries/render-utils/src/CauterizedModel.cpp
@@ -115,6 +115,7 @@ void CauterizedModel::updateClusterMatrices() {
             Transform clusterTransform;
             Transform::mult(clusterTransform, jointTransform, cluster.inverseBindTransform);
             state.clusterTransforms[j] = Model::TransformDualQuaternion(clusterTransform);
+            state.clusterTransforms[j].setCauterizationParameters(0.0f, jointPose.trans());
 #else
             auto jointMatrix = _rig.getJointTransform(cluster.jointIndex);
             glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterTransforms[j]);
@@ -151,6 +152,7 @@ void CauterizedModel::updateClusterMatrices() {
                     Transform clusterTransform;
                     Transform::mult(clusterTransform, jointTransform, cluster.inverseBindTransform);
                     state.clusterTransforms[j] = Model::TransformDualQuaternion(clusterTransform);
+                    state.clusterTransforms[j].setCauterizationParameters(1.0f, cauterizePose.trans());
 #else
                     glm_mat4u_mul(cauterizeMatrix, cluster.inverseBindMatrix, state.clusterTransforms[j]);
 #endif
diff --git a/libraries/render-utils/src/LightAmbient.slh b/libraries/render-utils/src/LightAmbient.slh
index eb565d60e4..097b4f4335 100644
--- a/libraries/render-utils/src/LightAmbient.slh
+++ b/libraries/render-utils/src/LightAmbient.slh
@@ -99,7 +99,6 @@ void evalLightingAmbient(out vec3 diffuse, out vec3 specular, LightAmbient ambie
 
         // Diffuse from ambient
         diffuse = sphericalHarmonics_evalSphericalLight(getLightAmbientSphere(ambient), lowNormalCurvature.xyz).xyz;
-        diffuse /= 3.1415926;
         specular = vec3(0.0);
     }
 <@endif@>
diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h
index 27eaedec40..027d52ecfd 100644
--- a/libraries/render-utils/src/Model.h
+++ b/libraries/render-utils/src/Model.h
@@ -263,26 +263,34 @@ public:
             _scale.x = p.scale().x;
             _scale.y = p.scale().y;
             _scale.z = p.scale().z;
+            _scale.w = 0.0f;
             _dq = DualQuaternion(p.rot(), p.trans());
         }
         TransformDualQuaternion(const glm::vec3& scale, const glm::quat& rot, const glm::vec3& trans) {
             _scale.x = scale.x;
             _scale.y = scale.y;
             _scale.z = scale.z;
+            _scale.w = 0.0f;
             _dq = DualQuaternion(rot, trans);
         }
         TransformDualQuaternion(const Transform& transform) {
             _scale = glm::vec4(transform.getScale(), 0.0f);
+            _scale.w = 0.0f;
             _dq = DualQuaternion(transform.getRotation(), transform.getTranslation());
         }
         glm::vec3 getScale() const { return glm::vec3(_scale); }
         glm::quat getRotation() const { return _dq.getRotation(); }
         glm::vec3 getTranslation() const { return _dq.getTranslation(); }
         glm::mat4 getMatrix() const { return createMatFromScaleQuatAndPos(getScale(), getRotation(), getTranslation()); };
+
+        void setCauterizationParameters(float cauterizationAmount, const glm::vec3& cauterizedPosition) {
+            _scale.w = cauterizationAmount;
+            _cauterizedPosition = glm::vec4(cauterizedPosition, 1.0f);
+        }
     protected:
         glm::vec4 _scale { 1.0f, 1.0f, 1.0f, 0.0f };
         DualQuaternion _dq;
-        glm::vec4 _padding;
+        glm::vec4 _cauterizedPosition { 0.0f, 0.0f, 0.0f, 1.0f };
     };
 #endif
 
diff --git a/libraries/render-utils/src/Skinning.slh b/libraries/render-utils/src/Skinning.slh
index a7edfb14a6..6048ba4ade 100644
--- a/libraries/render-utils/src/Skinning.slh
+++ b/libraries/render-utils/src/Skinning.slh
@@ -58,17 +58,19 @@ mat4 dualQuatToMat4(vec4 real, vec4 dual) {
 void skinPosition(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, out vec4 skinnedPosition) {
 
     // linearly blend scale and dual quaternion components
-    vec3 sAccum = vec3(0.0, 0.0, 0.0);
+    vec4 sAccum = vec4(0.0, 0.0, 0.0, 0.0);
     vec4 rAccum = vec4(0.0, 0.0, 0.0, 0.0);
     vec4 dAccum = vec4(0.0, 0.0, 0.0, 0.0);
+    vec4 cAccum = vec4(0.0, 0.0, 0.0, 0.0);
     vec4 polarityReference = clusterMatrices[skinClusterIndex[0]][1];
     for (int i = 0; i < INDICES_PER_VERTEX; i++) {
         mat4 clusterMatrix = clusterMatrices[(skinClusterIndex[i])];
         float clusterWeight = skinClusterWeight[i];
 
-        vec3 scale = vec3(clusterMatrix[0]);
+        vec4 scale = clusterMatrix[0];
         vec4 real = clusterMatrix[1];
         vec4 dual = clusterMatrix[2];
+        vec4 cauterizedPos = clusterMatrix[3];
 
         // to ensure that we rotate along the shortest arc, reverse dual quaternions with negative polarity.
         float dqClusterWeight = clusterWeight;
@@ -79,6 +81,7 @@ void skinPosition(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPositio
         sAccum += scale * clusterWeight;
         rAccum += real * dqClusterWeight;
         dAccum += dual * dqClusterWeight;
+        cAccum += cauterizedPos * clusterWeight;
     }
 
     // normalize dual quaternion
@@ -88,25 +91,37 @@ void skinPosition(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPositio
 
     // conversion from dual quaternion to 4x4 matrix.
     mat4 m = dualQuatToMat4(rAccum, dAccum);
-    skinnedPosition = m * (vec4(sAccum, 1) * inPosition);
+
+    // sAccum.w indicates the amount of cauterization for this vertex.
+    // 0 indicates no cauterization and 1 indicates full cauterization.
+    // TODO: make this cauterization smoother or implement full dual-quaternion scale support.
+    const float CAUTERIZATION_THRESHOLD = 0.1;
+    if (sAccum.w > CAUTERIZATION_THRESHOLD) {
+        skinnedPosition = cAccum;
+    } else {
+        sAccum.w = 1.0;
+        skinnedPosition = m * (sAccum * inPosition);
+    }
 }
 
 void skinPositionNormal(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, vec3 inNormal,
                         out vec4 skinnedPosition, out vec3 skinnedNormal) {
 
     // linearly blend scale and dual quaternion components
-    vec3 sAccum = vec3(0.0, 0.0, 0.0);
+    vec4 sAccum = vec4(0.0, 0.0, 0.0, 0.0);
     vec4 rAccum = vec4(0.0, 0.0, 0.0, 0.0);
     vec4 dAccum = vec4(0.0, 0.0, 0.0, 0.0);
+    vec4 cAccum = vec4(0.0, 0.0, 0.0, 0.0);
     vec4 polarityReference = clusterMatrices[skinClusterIndex[0]][1];
 
     for (int i = 0; i < INDICES_PER_VERTEX; i++) {
         mat4 clusterMatrix = clusterMatrices[(skinClusterIndex[i])];
         float clusterWeight = skinClusterWeight[i];
 
-        vec3 scale = vec3(clusterMatrix[0]);
+        vec4 scale = clusterMatrix[0];
         vec4 real = clusterMatrix[1];
         vec4 dual = clusterMatrix[2];
+        vec4 cauterizedPos = clusterMatrix[3];
 
         // to ensure that we rotate along the shortest arc, reverse dual quaternions with negative polarity.
         float dqClusterWeight = clusterWeight;
@@ -117,6 +132,7 @@ void skinPositionNormal(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inP
         sAccum += scale * clusterWeight;
         rAccum += real * dqClusterWeight;
         dAccum += dual * dqClusterWeight;
+        cAccum += cauterizedPos * clusterWeight;
     }
 
     // normalize dual quaternion
@@ -126,7 +142,18 @@ void skinPositionNormal(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inP
 
     // conversion from dual quaternion to 4x4 matrix.
     mat4 m = dualQuatToMat4(rAccum, dAccum);
-    skinnedPosition = m * (vec4(sAccum, 1) * inPosition);
+
+    // sAccum.w indicates the amount of cauterization for this vertex.
+    // 0 indicates no cauterization and 1 indicates full cauterization.
+    // TODO: make this cauterization smoother or implement full dual-quaternion scale support.
+    const float CAUTERIZATION_THRESHOLD = 0.1;
+    if (sAccum.w > CAUTERIZATION_THRESHOLD) {
+        skinnedPosition = cAccum;
+    } else {
+        sAccum.w = 1.0;
+        skinnedPosition = m * (sAccum * inPosition);
+    }
+
     skinnedNormal = vec3(m * vec4(inNormal, 0));
 }
 
@@ -134,18 +161,20 @@ void skinPositionNormalTangent(ivec4 skinClusterIndex, vec4 skinClusterWeight, v
                                out vec4 skinnedPosition, out vec3 skinnedNormal, out vec3 skinnedTangent) {
 
     // linearly blend scale and dual quaternion components
-    vec3 sAccum = vec3(0.0, 0.0, 0.0);
+    vec4 sAccum = vec4(0.0, 0.0, 0.0, 0.0);
     vec4 rAccum = vec4(0.0, 0.0, 0.0, 0.0);
     vec4 dAccum = vec4(0.0, 0.0, 0.0, 0.0);
+    vec4 cAccum = vec4(0.0, 0.0, 0.0, 0.0);
     vec4 polarityReference = clusterMatrices[skinClusterIndex[0]][1];
 
     for (int i = 0; i < INDICES_PER_VERTEX; i++) {
         mat4 clusterMatrix = clusterMatrices[(skinClusterIndex[i])];
         float clusterWeight = skinClusterWeight[i];
 
-        vec3 scale = vec3(clusterMatrix[0]);
+        vec4 scale = clusterMatrix[0];
         vec4 real = clusterMatrix[1];
         vec4 dual = clusterMatrix[2];
+        vec4 cauterizedPos = clusterMatrix[3];
 
         // to ensure that we rotate along the shortest arc, reverse dual quaternions with negative polarity.
         float dqClusterWeight = clusterWeight;
@@ -156,6 +185,7 @@ void skinPositionNormalTangent(ivec4 skinClusterIndex, vec4 skinClusterWeight, v
         sAccum += scale * clusterWeight;
         rAccum += real * dqClusterWeight;
         dAccum += dual * dqClusterWeight;
+        cAccum += cauterizedPos * clusterWeight;
     }
 
     // normalize dual quaternion
@@ -165,7 +195,18 @@ void skinPositionNormalTangent(ivec4 skinClusterIndex, vec4 skinClusterWeight, v
 
     // conversion from dual quaternion to 4x4 matrix.
     mat4 m = dualQuatToMat4(rAccum, dAccum);
-    skinnedPosition = m * (vec4(sAccum, 1) * inPosition);
+
+    // sAccum.w indicates the amount of cauterization for this vertex.
+    // 0 indicates no cauterization and 1 indicates full cauterization.
+    // TODO: make this cauterization smoother or implement full dual-quaternion scale support.
+    const float CAUTERIZATION_THRESHOLD = 0.1;
+    if (sAccum.w > CAUTERIZATION_THRESHOLD) {
+        skinnedPosition = cAccum;
+    } else {
+        sAccum.w = 1.0;
+        skinnedPosition = m * (sAccum * inPosition);
+    }
+
     skinnedNormal = vec3(m * vec4(inNormal, 0));
     skinnedTangent = vec3(m * vec4(inTangent, 0));
 }
diff --git a/libraries/render/src/render/ShapePipeline.cpp b/libraries/render/src/render/ShapePipeline.cpp
index a6d73897ae..f6ed00b493 100644
--- a/libraries/render/src/render/ShapePipeline.cpp
+++ b/libraries/render/src/render/ShapePipeline.cpp
@@ -70,8 +70,11 @@ void ShapePlumber::addPipeline(const Key& key, const gpu::ShaderPointer& program
 
 void ShapePlumber::addPipeline(const Filter& filter, const gpu::ShaderPointer& program, const gpu::StatePointer& state,
         BatchSetter batchSetter, ItemSetter itemSetter) {
+
     ShapeKey key{ filter._flags };
 
+
+    // don't call makeProgram on shaders that are already made.
     if (program->getNumCompilationAttempts() < 1) {
         gpu::Shader::BindingSet slotBindings;
         slotBindings.insert(gpu::Shader::Binding(std::string("lightingModelBuffer"), Slot::BUFFER::LIGHTING_MODEL));
diff --git a/libraries/shared/CMakeLists.txt b/libraries/shared/CMakeLists.txt
index 3d61765988..a8fe14e23e 100644
--- a/libraries/shared/CMakeLists.txt
+++ b/libraries/shared/CMakeLists.txt
@@ -12,4 +12,4 @@ if (ANDROID)
 endif()
 
 target_zlib()
-target_nsight()
\ No newline at end of file
+target_nsight()
diff --git a/libraries/shared/src/SettingInterface.cpp b/libraries/shared/src/SettingInterface.cpp
index 01b9f3884f..327668574e 100644
--- a/libraries/shared/src/SettingInterface.cpp
+++ b/libraries/shared/src/SettingInterface.cpp
@@ -20,6 +20,7 @@
 #include "SettingHelpers.h"
 #include "SettingManager.h"
 #include "SharedLogging.h"
+#include "SharedUtil.h"
 
 namespace Setting {
     static QSharedPointer<Manager> globalManager;
@@ -32,14 +33,34 @@ namespace Setting {
         // tell the private instance to clean itself up on its thread
         DependencyManager::destroy<Manager>();
 
-        //
         globalManager.reset();
-        
+
         // quit the settings manager thread and wait on it to make sure it's gone
         settingsManagerThread->quit();
         settingsManagerThread->wait();
     }
-    
+
+    void setupPrivateInstance() {
+        // Ensure Setting::init has already ran and qApp exists
+        if (qApp && globalManager) {
+            // Let's set up the settings Private instance on its own thread
+            QThread* thread = new QThread();
+            Q_CHECK_PTR(thread);
+            thread->setObjectName("Settings Thread");
+
+            QObject::connect(thread, SIGNAL(started()), globalManager.data(), SLOT(startTimer()));
+            QObject::connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
+            QObject::connect(thread, SIGNAL(finished()), globalManager.data(), SLOT(deleteLater()));
+            globalManager->moveToThread(thread);
+            thread->start();
+            qCDebug(shared) << "Settings thread started.";
+
+            // Register cleanupPrivateInstance to run inside QCoreApplication's destructor.
+            qAddPostRoutine(cleanupPrivateInstance);
+        }
+    }
+    FIXED_Q_COREAPP_STARTUP_FUNCTION(setupPrivateInstance)
+
     // Sets up the settings private instance. Should only be run once at startup. preInit() must be run beforehand,
     void init() {
         // Set settings format
@@ -59,23 +80,9 @@ namespace Setting {
             qCDebug(shared) << (deleted ? "Deleted" : "Failed to delete") << "settings lock file" << settingsLockFilename;
         }
 
-
-        // Let's set up the settings Private instance on its own thread
-        QThread* thread = new QThread();
-        Q_CHECK_PTR(thread);
-        thread->setObjectName("Settings Thread");
-
         globalManager = DependencyManager::set<Manager>();
 
-        QObject::connect(thread, SIGNAL(started()), globalManager.data(), SLOT(startTimer()));
-        QObject::connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
-        QObject::connect(thread, SIGNAL(finished()), globalManager.data(), SLOT(deleteLater()));
-        globalManager->moveToThread(thread);
-        thread->start();
-        qCDebug(shared) << "Settings thread started.";    
-
-        // Register cleanupPrivateInstance to run inside QCoreApplication's destructor.
-        qAddPostRoutine(cleanupPrivateInstance);
+        setupPrivateInstance();
     }
     
     void Interface::init() {
diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp
index 2d2ec7c28f..8e5c30711c 100644
--- a/libraries/shared/src/SharedUtil.cpp
+++ b/libraries/shared/src/SharedUtil.cpp
@@ -20,6 +20,7 @@
 #include <mutex>
 #include <thread>
 #include <set>
+#include <unordered_map>
 
 #include <glm/glm.hpp>
 
@@ -62,6 +63,43 @@ extern "C" FILE * __cdecl __iob_func(void) {
 #include "OctalCode.h"
 #include "SharedLogging.h"
 
+static std::unordered_map<std::string, QVariant> stagedGlobalInstances;
+
+
+std::mutex& globalInstancesMutex() {
+    static std::mutex mutex;
+    return mutex;
+}
+
+static void commitGlobalInstances() {
+    std::unique_lock<std::mutex> lock(globalInstancesMutex());
+    for (const auto& it : stagedGlobalInstances) {
+        qApp->setProperty(it.first.c_str(), it.second);
+    }
+    stagedGlobalInstances.clear();
+}
+FIXED_Q_COREAPP_STARTUP_FUNCTION(commitGlobalInstances)
+
+QVariant getGlobalInstance(const char* propertyName) {
+    if (qApp) {
+        return qApp->property(propertyName);
+    } else {
+        auto it = stagedGlobalInstances.find(propertyName);
+        if (it != stagedGlobalInstances.end()) {
+            return it->second;
+        }
+    }
+    return QVariant();
+}
+
+void setGlobalInstance(const char* propertyName, const QVariant& variant) {
+    if (qApp) {
+        qApp->setProperty(propertyName, variant);
+    } else {
+        stagedGlobalInstances[propertyName] = variant;
+    }
+}
+
 static qint64 usecTimestampNowAdjust = 0; // in usec
 void usecTimestampNowForceClockSkew(qint64 clockSkew) {
     ::usecTimestampNowAdjust = clockSkew;
diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h
index 6cf5a4755d..5a1e48d9c0 100644
--- a/libraries/shared/src/SharedUtil.h
+++ b/libraries/shared/src/SharedUtil.h
@@ -25,6 +25,22 @@
 #include <QtCore/QCoreApplication>
 #include <QUuid>
 
+// Workaround for https://bugreports.qt.io/browse/QTBUG-54479
+// Wrap target function inside another function that holds
+// a unique string identifier and uses it to ensure it only runs once
+// by storing a state within the qApp
+// We cannot used std::call_once with a static once_flag because
+// this is used in shared libraries that are linked by several DLLs
+// (ie. plugins), meaning the static will be useless in that case
+#define FIXED_Q_COREAPP_STARTUP_FUNCTION(AFUNC)                        \
+    static void AFUNC ## _fixed() {                                    \
+        const auto propertyName = std::string(Q_FUNC_INFO) + __FILE__; \
+        if (!qApp->property(propertyName.c_str()).toBool()) {          \
+            AFUNC();                                                   \
+            qApp->setProperty(propertyName.c_str(), QVariant(true));   \
+        }                                                              \
+    }                                                                  \
+    Q_COREAPP_STARTUP_FUNCTION(AFUNC ## _fixed)
 
 // When writing out avatarEntities to a QByteArray, if the parentID is the ID of MyAvatar, use this ID instead.  This allows
 // the value to be reset when the sessionID changes.
@@ -52,6 +68,10 @@ bool destroyGlobalInstance() {
     return false;
 }
 
+std::mutex& globalInstancesMutex();
+QVariant getGlobalInstance(const char* propertyName);
+void setGlobalInstance(const char* propertyName, const QVariant& variant);
+
 // Provides efficient access to a named global type.  By storing the value
 // in the QApplication by name we can implement the singleton pattern and 
 // have the single instance function across DLL boundaries.  
@@ -60,9 +80,9 @@ T* globalInstance(const char* propertyName, Args&&... args) {
     static T* resultInstance { nullptr };
     static std::mutex mutex;
     if (!resultInstance) {
-        std::unique_lock<std::mutex> lock(mutex);
+        std::unique_lock<std::mutex> lock(globalInstancesMutex());
         if (!resultInstance) {
-            auto variant = qApp->property(propertyName);
+            auto variant = getGlobalInstance(propertyName);
             if (variant.isNull()) {
                 std::unique_ptr<T>& instancePtr = globalInstancePointer<T>();
                 if (!instancePtr.get()) {
@@ -72,7 +92,7 @@ T* globalInstance(const char* propertyName, Args&&... args) {
                 }
                 void* voidInstance = &(*instancePtr);
                 variant = QVariant::fromValue(voidInstance);
-                qApp->setProperty(propertyName, variant);
+                setGlobalInstance(propertyName, variant);
             }
             void* returnedVoidInstance = variant.value<void*>();
             resultInstance = static_cast<T*>(returnedVoidInstance);
diff --git a/scripts/system/commerce/wallet.js b/scripts/system/commerce/wallet.js
index ad864622ed..46672a3f66 100644
--- a/scripts/system/commerce/wallet.js
+++ b/scripts/system/commerce/wallet.js
@@ -78,7 +78,7 @@
         });
     }
     function getAvailableConnections(domain, callback) { // callback([{usename, location}...]) if successful. (Logs otherwise)
-        url = METAVERSE_BASE + '/api/v1/users?'
+        url = METAVERSE_BASE + '/api/v1/users?per_page=400&'
         if (domain) {
             url += 'status=' + domain.slice(1, -1); // without curly braces
         } else {
diff --git a/scripts/system/edit.js b/scripts/system/edit.js
index f8c097795a..863c185cb4 100644
--- a/scripts/system/edit.js
+++ b/scripts/system/edit.js
@@ -469,7 +469,7 @@ var toolBar = (function () {
 
             // tablet version of new-model dialog
             var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
-            tablet.pushOntoStack("NewModelDialog.qml");
+            tablet.pushOntoStack("hifi/tablet/NewModelDialog.qml");
         });
 
         addButton("newCubeButton", "cube-01.svg", function () {
diff --git a/scripts/system/pal.js b/scripts/system/pal.js
index 1b93bdde32..5a656c4ba0 100644
--- a/scripts/system/pal.js
+++ b/scripts/system/pal.js
@@ -361,7 +361,7 @@ function getProfilePicture(username, callback) { // callback(url) if successfull
     });
 }
 function getAvailableConnections(domain, callback) { // callback([{usename, location}...]) if successfull. (Logs otherwise)
-    url = METAVERSE_BASE + '/api/v1/users?'
+    url = METAVERSE_BASE + '/api/v1/users?per_page=400&'
     if (domain) {
         url += 'status=' + domain.slice(1, -1); // without curly braces
     } else {
diff --git a/scripts/system/tablet-goto.js b/scripts/system/tablet-goto.js
index 43dae9625a..9cd8420a88 100644
--- a/scripts/system/tablet-goto.js
+++ b/scripts/system/tablet-goto.js
@@ -100,7 +100,7 @@
             button.editProperties({isActive: shouldActivateButton});
             wireEventBridge(true);
             messagesWaiting(false);
-            tablet.sendToQml({ method: 'refreshFeeds' })
+            tablet.sendToQml({ method: 'refreshFeeds', protocolSignature: Window.protocolSignature() })
 
         } else {
             shouldActivateButton = false;
diff --git a/tests/qt59/src/main.cpp b/tests/qt59/src/main.cpp
index c66a5e6f9a..7b95cabd6c 100644
--- a/tests/qt59/src/main.cpp
+++ b/tests/qt59/src/main.cpp
@@ -33,8 +33,6 @@ private:
 Qt59TestApp::Qt59TestApp(int argc, char* argv[]) :
     QCoreApplication(argc, argv)
 {
-
-    Setting::init();
     DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
     DependencyManager::set<AccountManager>([&] { return QString("Mozilla/5.0 (HighFidelityACClient)"); });
     DependencyManager::set<AddressManager>();
diff --git a/tools/ac-client/src/ACClientApp.cpp b/tools/ac-client/src/ACClientApp.cpp
index 88884a4fee..9eadc1dec2 100644
--- a/tools/ac-client/src/ACClientApp.cpp
+++ b/tools/ac-client/src/ACClientApp.cpp
@@ -97,7 +97,6 @@ ACClientApp::ACClientApp(int argc, char* argv[]) :
         _password = pieces[1];
     }
 
-    Setting::init();
     DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
 
     DependencyManager::set<AccountManager>([&]{ return QString("Mozilla/5.0 (HighFidelityACClient)"); });
diff --git a/tools/ac-client/src/main.cpp b/tools/ac-client/src/main.cpp
index 12c5e6f5f8..c9affde3b5 100644
--- a/tools/ac-client/src/main.cpp
+++ b/tools/ac-client/src/main.cpp
@@ -25,6 +25,8 @@ int main(int argc, char * argv[]) {
     QCoreApplication::setOrganizationDomain(BuildInfo::ORGANIZATION_DOMAIN);
     QCoreApplication::setApplicationVersion(BuildInfo::VERSION);
 
+    Setting::init();
+
     ACClientApp app(argc, argv);
 
     return app.exec();
diff --git a/tools/atp-client/src/ATPClientApp.cpp b/tools/atp-client/src/ATPClientApp.cpp
index 307c913a96..1623cf01cd 100644
--- a/tools/atp-client/src/ATPClientApp.cpp
+++ b/tools/atp-client/src/ATPClientApp.cpp
@@ -135,7 +135,6 @@ ATPClientApp::ATPClientApp(int argc, char* argv[]) :
         _domainServerAddress = domainURL.toString();
     }
 
-    Setting::init();
     DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
 
     DependencyManager::set<StatTracker>();
diff --git a/tools/atp-client/src/main.cpp b/tools/atp-client/src/main.cpp
index 88119604cf..830c049bc7 100644
--- a/tools/atp-client/src/main.cpp
+++ b/tools/atp-client/src/main.cpp
@@ -25,6 +25,8 @@ int main(int argc, char * argv[]) {
     QCoreApplication::setOrganizationDomain(BuildInfo::ORGANIZATION_DOMAIN);
     QCoreApplication::setApplicationVersion(BuildInfo::VERSION);
 
+    Setting::init();
+
     ATPClientApp app(argc, argv);
 
     return app.exec();
diff --git a/tools/oven/src/Oven.cpp b/tools/oven/src/Oven.cpp
index 9de06a35bb..69d2ef84ce 100644
--- a/tools/oven/src/Oven.cpp
+++ b/tools/oven/src/Oven.cpp
@@ -14,7 +14,6 @@
 #include <QtCore/QCommandLineParser>
 
 #include <image/Image.h>
-#include <SettingInterface.h>
 
 #include "ui/OvenMainWindow.h"
 #include "Oven.h"
@@ -29,12 +28,6 @@ static const QString CLI_TYPE_PARAMETER = "t";
 Oven::Oven(int argc, char* argv[]) :
     QApplication(argc, argv)
 {
-    QCoreApplication::setOrganizationName("High Fidelity");
-    QCoreApplication::setApplicationName("Oven");
-
-    // init the settings interface so we can save and load settings
-    Setting::init();
-
     // parse the command line parameters
     QCommandLineParser parser;
    
diff --git a/tools/oven/src/main.cpp b/tools/oven/src/main.cpp
index 9c778245b5..788470b75e 100644
--- a/tools/oven/src/main.cpp
+++ b/tools/oven/src/main.cpp
@@ -10,7 +10,15 @@
 
 #include "Oven.h"
 
+#include <SettingInterface.h>
+
 int main (int argc, char** argv) {
+    QCoreApplication::setOrganizationName("High Fidelity");
+    QCoreApplication::setApplicationName("Oven");
+
+    // init the settings interface so we can save and load settings
+    Setting::init();
+
     Oven app(argc, argv);
     return app.exec();
 }