diff --git a/interface/resources/qml/dialogs/FileDialog.qml b/interface/resources/qml/dialogs/FileDialog.qml
index ef82ce4884..fc10bd4f68 100644
--- a/interface/resources/qml/dialogs/FileDialog.qml
+++ b/interface/resources/qml/dialogs/FileDialog.qml
@@ -82,6 +82,12 @@ ModalWindow {
 
         // Clear selection when click on external frame.
         frameClicked.connect(function() { d.clearSelection(); });
+
+        if (selectDirectory) {
+            currentSelection.text = d.capitalizeDrive(helper.urlToPath(initialFolder));
+        }
+
+        fileTableView.forceActiveFocus();
     }
 
     Item {
@@ -703,7 +709,6 @@ ModalWindow {
                 if (!helper.urlIsWritable(selection)) {
                     desktop.messageBox({
                                            icon: OriginalDialogs.StandardIcon.Warning,
-                                           buttons: OriginalDialogs.StandardButton.Yes | OriginalDialogs.StandardButton.No,
                                            text: "Unable to write to location " + selection
                                        })
                     return;
diff --git a/interface/resources/qml/dialogs/preferences/BrowsablePreference.qml b/interface/resources/qml/dialogs/preferences/BrowsablePreference.qml
index 9a19889938..2cf50891c9 100644
--- a/interface/resources/qml/dialogs/preferences/BrowsablePreference.qml
+++ b/interface/resources/qml/dialogs/preferences/BrowsablePreference.qml
@@ -65,7 +65,10 @@ Preference {
                 verticalCenter: dataTextField.verticalCenter
             }
             onClicked: {
-                var browser = fileBrowserBuilder.createObject(desktop, { selectDirectory: true, folder: fileDialogHelper.pathToUrl(preference.value) });
+                var browser = fileBrowserBuilder.createObject(desktop, {
+                    selectDirectory: true,
+                    dir: fileDialogHelper.pathToUrl(preference.value)
+                });
                 browser.selectedFile.connect(function(fileUrl){
                     console.log(fileUrl);
                     dataTextField.text = fileDialogHelper.urlToPath(fileUrl);
diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp
index 0443c65453..f0ae221566 100644
--- a/interface/src/scripting/WindowScriptingInterface.cpp
+++ b/interface/src/scripting/WindowScriptingInterface.cpp
@@ -14,6 +14,8 @@
 #include <QMessageBox>
 #include <QScriptValue>
 
+#include <SettingHandle.h>
+
 #include "Application.h"
 #include "DomainHandler.h"
 #include "MainWindow.h"
@@ -23,6 +25,10 @@
 
 #include "WindowScriptingInterface.h"
 
+static const QString DESKTOP_LOCATION = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
+static const QString LAST_BROWSE_LOCATION_SETTING = "LastBrowseLocation";
+
+
 WindowScriptingInterface::WindowScriptingInterface() {
     const DomainHandler& domainHandler = DependencyManager::get<NodeList>()->getDomainHandler();
     connect(&domainHandler, &DomainHandler::connectedToDomain, this, &WindowScriptingInterface::domainChanged);
@@ -101,6 +107,14 @@ QString fixupPathForMac(const QString& directory) {
     return path;
 }
 
+QString WindowScriptingInterface::getPreviousBrowseLocation() const {
+    return Setting::Handle<QString>(LAST_BROWSE_LOCATION_SETTING, DESKTOP_LOCATION).get();
+}
+
+void WindowScriptingInterface::setPreviousBrowseLocation(const QString& location) {
+    Setting::Handle<QVariant>(LAST_BROWSE_LOCATION_SETTING).set(location);
+}
+
 /// Display an open file dialog.  If `directory` is an invalid file or directory the browser will start at the current
 /// working directory.
 /// \param const QString& title title of the window
@@ -108,8 +122,17 @@ QString fixupPathForMac(const QString& directory) {
 /// \param const QString& nameFilter filter to filter filenames by - see `QFileDialog`
 /// \return QScriptValue file path as a string if one was selected, otherwise `QScriptValue::NullValue`
 QScriptValue WindowScriptingInterface::browse(const QString& title, const QString& directory, const QString& nameFilter) {
-    QString path = fixupPathForMac(directory);
+    QString path = directory;
+    if (path.isEmpty()) {
+        path = getPreviousBrowseLocation();
+    }
+#ifndef Q_OS_WIN
+    path = fixupPathForMac(directory);
+#endif
     QString result = OffscreenUi::getOpenFileName(nullptr, title, path, nameFilter);
+    if (!result.isEmpty()) {
+        setPreviousBrowseLocation(QFileInfo(result).absolutePath());
+    }
     return result.isEmpty() ? QScriptValue::NullValue : QScriptValue(result);
 }
 
@@ -120,8 +143,17 @@ QScriptValue WindowScriptingInterface::browse(const QString& title, const QStrin
 /// \param const QString& nameFilter filter to filter filenames by - see `QFileDialog`
 /// \return QScriptValue file path as a string if one was selected, otherwise `QScriptValue::NullValue`
 QScriptValue WindowScriptingInterface::save(const QString& title, const QString& directory, const QString& nameFilter) {
-    QString path = fixupPathForMac(directory);
+    QString path = directory;
+    if (path.isEmpty()) {
+        path = getPreviousBrowseLocation();
+    }
+#ifndef Q_OS_WIN
+    path = fixupPathForMac(directory);
+#endif
     QString result = OffscreenUi::getSaveFileName(nullptr, title, path, nameFilter);
+    if (!result.isEmpty()) {
+        setPreviousBrowseLocation(QFileInfo(result).absolutePath());
+    }
     return result.isEmpty() ? QScriptValue::NullValue : QScriptValue(result);
 }
 
diff --git a/interface/src/scripting/WindowScriptingInterface.h b/interface/src/scripting/WindowScriptingInterface.h
index dfe02a5064..b92114c1bf 100644
--- a/interface/src/scripting/WindowScriptingInterface.h
+++ b/interface/src/scripting/WindowScriptingInterface.h
@@ -49,6 +49,10 @@ signals:
 
 private slots:
     WebWindowClass* doCreateWebWindow(const QString& title, const QString& url, int width, int height);
+
+private:
+    QString getPreviousBrowseLocation() const;
+    void setPreviousBrowseLocation(const QString& location);
 };
 
 #endif // hifi_WindowScriptingInterface_h
diff --git a/libraries/entities/src/EntityTypes.cpp b/libraries/entities/src/EntityTypes.cpp
index 7b1133c2aa..4ba4ad5676 100644
--- a/libraries/entities/src/EntityTypes.cpp
+++ b/libraries/entities/src/EntityTypes.cpp
@@ -17,6 +17,7 @@
 #include "EntityItem.h"
 #include "EntityItemProperties.h"
 #include "EntityTypes.h"
+#include "EntitiesLogging.h"
 
 #include "LightEntityItem.h"
 #include "ModelEntityItem.h"
@@ -63,6 +64,9 @@ EntityTypes::EntityType EntityTypes::getEntityTypeFromName(const QString& name)
     if (matchedTypeName != _nameToTypeMap.end()) {
         return matchedTypeName.value();
     }
+    if (name.size() > 0 && name[0].isLower()) {
+        qCDebug(entities) << "Entity types must start with an uppercase letter. Please change the type" << name;
+    }
     return Unknown;
 }
 
diff --git a/libraries/networking/src/DomainHandler.cpp b/libraries/networking/src/DomainHandler.cpp
index 6880b7a329..170669dede 100644
--- a/libraries/networking/src/DomainHandler.cpp
+++ b/libraries/networking/src/DomainHandler.cpp
@@ -97,7 +97,6 @@ void DomainHandler::softReset() {
     
     clearSettings();
 
-    _domainConnectionRefusals.clear();
     _connectionDenialsSinceKeypairRegen = 0;
 
     // cancel the failure timeout for any pending requests for settings
@@ -118,6 +117,9 @@ void DomainHandler::hardReset() {
     _hostname = QString();
     _sockAddr.clear();
 
+    _hasSignalledProtocolMismatch = false;
+    _domainConnectionRefusals.clear();
+
     _hasCheckedForAccessToken = false;
 
     // clear any pending path we may have wanted to ask the previous DS about
@@ -405,9 +407,25 @@ void DomainHandler::processDomainServerConnectionDeniedPacket(QSharedPointer<Rec
     // and check and signal for an access token so that we can make sure they are logged in
     qCWarning(networking) << "The domain-server denied a connection request: " << reasonMessage;
 
-    if (!_domainConnectionRefusals.contains(reasonMessage)) {
-        _domainConnectionRefusals.append(reasonMessage);
-        emit domainConnectionRefused(reasonMessage, (int)reasonCode);
+    if (!_domainConnectionRefusals.contains(reasonCode)) {
+
+        _domainConnectionRefusals.append(reasonCode);
+
+        bool shouldSignal = true;
+
+        // only signal once for a protocol mismatch, even between soft resets that will reset the _domainConnectionRefusals
+        if (reasonCode == ConnectionRefusedReason::ProtocolMismatch) {
+            if (_hasSignalledProtocolMismatch) {
+                shouldSignal = false;
+            } else {
+                _hasSignalledProtocolMismatch = true;
+            }
+        }
+
+        if (shouldSignal) {
+            emit domainConnectionRefused(reasonMessage, (int)reasonCode);
+        }
+
     }
 
     auto accountManager = DependencyManager::get<AccountManager>();
diff --git a/libraries/networking/src/DomainHandler.h b/libraries/networking/src/DomainHandler.h
index 1328174e87..3ab583d597 100644
--- a/libraries/networking/src/DomainHandler.h
+++ b/libraries/networking/src/DomainHandler.h
@@ -144,7 +144,8 @@ private:
     QString _pendingPath;
     QTimer _settingsTimer;
 
-    QStringList _domainConnectionRefusals;
+    QList<ConnectionRefusedReason> _domainConnectionRefusals;
+    bool _hasSignalledProtocolMismatch { false };
     bool _hasCheckedForAccessToken { false };
     int _connectionDenialsSinceKeypairRegen { 0 };
 
diff --git a/libraries/shared/src/SettingHandle.h b/libraries/shared/src/SettingHandle.h
index f19fc5875b..8e07d28dad 100644
--- a/libraries/shared/src/SettingHandle.h
+++ b/libraries/shared/src/SettingHandle.h
@@ -77,15 +77,40 @@ namespace Setting {
         virtual ~Handle() { deinit(); }
         
         // Returns setting value, returns its default value if not found
-        T get() { return get(_defaultValue); }
+        T get() const { 
+            return get(_defaultValue); 
+        }
+
         // Returns setting value, returns other if not found
-        T get(const T& other) { maybeInit(); return (_isSet) ? _value : other; }
-        T getDefault() const { return _defaultValue; }
+        T get(const T& other) const { 
+            maybeInit(); 
+            return (_isSet) ? _value : other; 
+        }
+
+        const T& getDefault() const { 
+            return _defaultValue; 
+        }
         
-        void set(const T& value) { maybeInit(); _value = value; _isSet = true; }
-        void reset() { set(_defaultValue); }
-        
-        void remove() { maybeInit(); _isSet = false; }
+        void reset() { 
+            set(_defaultValue); 
+        }
+
+        void set(const T& value) { 
+            maybeInit(); 
+            if ((!_isSet && (value != _defaultValue)) || _value != value) {
+                _value = value; 
+                _isSet = true; 
+                save(); 
+            } 
+        }
+
+        void remove() { 
+            maybeInit(); 
+            if (_isSet) { 
+                _isSet = false; 
+                save(); 
+            }  
+        }
         
     protected:
         virtual void setVariant(const QVariant& variant);
diff --git a/libraries/shared/src/SettingInterface.cpp b/libraries/shared/src/SettingInterface.cpp
index 1ebaa5cf82..95c6bc1efc 100644
--- a/libraries/shared/src/SettingInterface.cpp
+++ b/libraries/shared/src/SettingInterface.cpp
@@ -119,9 +119,9 @@ namespace Setting {
     }
 
     
-    void Interface::maybeInit() {
+    void Interface::maybeInit() const {
         if (!_isInitialized) {
-            init();
+            const_cast<Interface*>(this)->init();
         }
     }
     
diff --git a/libraries/shared/src/SettingInterface.h b/libraries/shared/src/SettingInterface.h
index 2b32e8a3b4..5e23d42223 100644
--- a/libraries/shared/src/SettingInterface.h
+++ b/libraries/shared/src/SettingInterface.h
@@ -39,19 +39,20 @@ namespace Setting {
         virtual ~Interface() = default;
 
         void init();
-        void maybeInit();
+        void maybeInit() const;
         void deinit();
         
         void save();
         void load();
-        
-        bool _isInitialized = false;
+
         bool _isSet = false;
         const QString _key;
+
+    private:
+        mutable bool _isInitialized = false;
         
         friend class Manager;
-
-        QWeakPointer<Manager> _manager;
+        mutable QWeakPointer<Manager> _manager;
     };
 }
 
diff --git a/libraries/shared/src/SettingManager.cpp b/libraries/shared/src/SettingManager.cpp
index bacec2ee0c..abb8525b03 100644
--- a/libraries/shared/src/SettingManager.cpp
+++ b/libraries/shared/src/SettingManager.cpp
@@ -33,8 +33,8 @@ namespace Setting {
     void Manager::customDeleter() { }
 
 
-    void Manager::registerHandle(Setting::Interface* handle) {
-        QString key = handle->getKey();
+    void Manager::registerHandle(Interface* handle) {
+        const QString& key = handle->getKey();
         withWriteLock([&] {
             if (_handles.contains(key)) {
                 qWarning() << "Setting::Manager::registerHandle(): Key registered more than once, overriding: " << key;
@@ -58,7 +58,9 @@ namespace Setting {
             } else {
                 loadedValue = value(key);
             }
-            handle->setVariant(loadedValue);
+            if (loadedValue.isValid()) {
+                handle->setVariant(loadedValue);
+            }
         });
     }
 
@@ -94,6 +96,7 @@ namespace Setting {
     }
 
     void Manager::saveAll() {
+        bool forceSync = false;
         withWriteLock([&] {
             for (auto key : _pendingChanges.keys()) {
                 auto newValue = _pendingChanges[key];
@@ -101,15 +104,21 @@ namespace Setting {
                 if (newValue == savedValue) {
                     continue;
                 }
-                if (newValue == UNSET_VALUE) {
+                if (newValue == UNSET_VALUE || !newValue.isValid()) {
+                    forceSync = true;
                     remove(key);
                 } else {
+                    forceSync = true;
                     setValue(key, newValue);
                 }
             }
             _pendingChanges.clear();
         });
 
+        if (forceSync) {
+            sync();
+        }
+
         // Restart timer
         if (_saveTimer) {
             _saveTimer->start();
diff --git a/plugins/openvr/src/ViveControllerManager.cpp b/plugins/openvr/src/ViveControllerManager.cpp
index 83b72c5c08..69c98d48c3 100644
--- a/plugins/openvr/src/ViveControllerManager.cpp
+++ b/plugins/openvr/src/ViveControllerManager.cpp
@@ -366,6 +366,10 @@ void ViveControllerManager::InputDevice::handleButtonEvent(float deltaTime, uint
         } else if (button == vr::k_EButton_SteamVR_Touchpad) {
             _buttonPressedMap.insert(isLeftHand ? LS : RS);
         }
+    } else {
+        if (button == vr::k_EButton_Grip) {
+            _axisStateMap[isLeftHand ? LEFT_GRIP : RIGHT_GRIP] = 0.0f;
+        }
     }
 
     if (touched) {
diff --git a/scripts/system/edit.js b/scripts/system/edit.js
index 0c4f4f3c5c..b39c843411 100644
--- a/scripts/system/edit.js
+++ b/scripts/system/edit.js
@@ -1221,8 +1221,7 @@ function handeMenuEvent(menuItem) {
         if (!selectionManager.hasSelection()) {
             Window.alert("No entities have been selected.");
         } else {
-            var filename = "entities__" + Window.location.hostname + ".svo.json";
-            filename = Window.save("Select Where to Save", filename, "*.json")
+            var filename = Window.save("Select Where to Save", "", "*.json")
             if (filename) {
                 var success = Clipboard.exportEntities(filename, selectionManager.selections);
                 if (!success) {