diff --git a/apps/dashboard-app/src/main/js/src/app/common/authentication/authentication.service.js b/apps/dashboard-app/src/main/js/src/app/common/authentication/authentication.service.js
index cb0869232..5ace12af7 100644
--- a/apps/dashboard-app/src/main/js/src/app/common/authentication/authentication.service.js
+++ b/apps/dashboard-app/src/main/js/src/app/common/authentication/authentication.service.js
@@ -1,165 +1,165 @@
 (function () {
     'use strict';
 
     // -- angular module -- //
     angular.module('shrine.commmon.authentication')
         .factory('AuthenticationService', AuthenticationService);
 
 
     AuthenticationService.$inject = ['$http', '$q', '$app', '$rootScope', '$interval', '$location'];
     function AuthenticationService ($http, $q, $app, $rootScope, $interval, $location) {
 
         idleHandle();
 
         // -- private const -- //
         var Config = {
             AuthenticationEndpoint: 'user/whoami',
             FailureResponse:        'AuthenticationFailed'
         };
 
 
         // -- public -- //
         return {
             login:                  login,
             setAuthorizationHeader: setAuthorizationHeader,
             setCredentials:         setCredentials,
             clearCredentials:       clearCredentials
         };
 
 
         function idleHandle() {
             // -- auto logout on idle -- //
             var twentyMinutes = 20*60*1000;
             var logoutPromise = $interval(timeout, twentyMinutes);
             var idleEvent = 'idleEvent';
             $rootScope.$on('$destroy', function () {
                 $interval.cancel(logoutPromise);
             });
             $rootScope.$on(idleEvent, function () {
                 $interval.cancel(logoutPromise);
                 logoutPromise = $interval(timeout, twentyMinutes);
             });
 
 
             /**
              * When the interval is called, that means the user has gone idle, so we
              * clear their credentials then navigate them back to the home page.
              */
             function timeout() {
                 clearCredentials();
-                $location.url("/login");
+                $app.model.safeLogout();
             }
 
             $rootScope.idleBroadcast = function() {
                 $rootScope.$broadcast(idleEvent);
             }
         }
 
 
         // -- private methods -- //
         /**
         * Wrapper for authenticate call.
         */
         function login () {
             return authenticate();
         }
 
 
         /**
          * Encrypt Authorization Data.
          * @param username
          * @param password
          * @returns {string}
          * @constructor
          */
         function getAuthorizationData(username, password) {
             return 'Basic ' + $app.utils.toBase64(username + ':' + password);
         }
 
 
         /**
          * Set the Authorization header for requests.
          * @param username
          * @param password
          * @constructor
          */
         function setAuthorizationHeader (username, password) {
             $http.defaults.headers.common['Authorization'] =
                 getAuthorizationData(username, password);
         }
 
 
         /**
          * Set credentials of the current user.
          * @param username
          * @param password
          * @param roles
          * @constructor
          */
         function setCredentials(username, password, roles) {
             var data = getAuthorizationData(username, password)
             $app.utils.setAppUser(username, data, roles);
         };
 
 
         /**
          * Remove the credentials of the current user.
          */
         function clearCredentials () {
             if($app.globals.currentUser !== undefined) {
                 $app.globals.currentUser.isLoggedIn = false;
             }
 
             $app.utils.deleteAppUser();
             $http.defaults.headers.common.Authorization = ' Basic ';
         }
 
 
         /**
          * Parse out authentication data.
          * @param result
          * @returns {*}
          */
         function parseResult(result) {
             //reject promise on fail.
             if(result.data === Config.FailureResponse) {
                 return $q.reject(response);
             }
 
             var response = {
                 success: true,
                 msg:     result.data.statusText,
                 userId:  result.data.userId,
                 roles:   result.data.roles
             };
 
             return response;
         }
 
 
         /**
          * Reject invalid login.
          * @param result
          * @returns {Promise}
          */
         function rejectResult (result) {
             var response = {
                 success: false,
                 msg: "invalid login " + result.data.statusText
             };
             return $q.reject(response);
         }
 
         /**
          * Authentication Promise.
          * @returns {*}
          */
         function authenticate (baseUrl) {
 
             var url = $app.utils.getUrl(Config.AuthenticationEndpoint);
 
             return $http.get(url)
                 .then(parseResult, rejectResult);
         }
     }
 })();
diff --git a/apps/dashboard-app/src/main/js/src/app/diagnostic/diagnostic.model.js b/apps/dashboard-app/src/main/js/src/app/diagnostic/diagnostic.model.js
index cc634af0f..97e3f5c12 100644
--- a/apps/dashboard-app/src/main/js/src/app/diagnostic/diagnostic.model.js
+++ b/apps/dashboard-app/src/main/js/src/app/diagnostic/diagnostic.model.js
@@ -1,208 +1,227 @@
 (function (){
     'use strict';
 
 
     // -- angular module -- //
     angular.module('shrine-tools')
         .factory('DiagnosticModel', DiagnosticModel);
 
 
-    DiagnosticModel.$inject = ['$http', '$q', 'UrlGetter'];
-    function DiagnosticModel (h, q, urlGetter) {
+    DiagnosticModel.$inject = ['$http', '$q', 'UrlGetter', '$location'];
+    function DiagnosticModel (h, q, urlGetter, $location) {
 
         var toDashboard = {url:''};
         var cache = {};
+        // used solely for remote dashboard persistence
         var m = {};
 
         m.remoteSiteStatuses = [];
         m.siteAlias = '';
 
         // -- private const -- //
         var Config = {
             AdapterEndpoint:  'admin/status/adapter',
             ConfigEndpoint:   'admin/status/config',
             HubEndpoint:      'admin/status/hub',
             I2B2Endpoint:     'admin/status/i2b2',
             KeystoreEndpoint: 'admin/status/keystore',
             OptionsEndpoint:  'admin/status/optionalParts',
             ProblemEndpoint:  'admin/status/problems',
             QepEndpoint:      'admin/status/qep',
             SummaryEndpoint:  'admin/status/summary'
         };
 
 
         // -- public -- //
         return {
             getAdapter:        getJsonMaker(Config.AdapterEndpoint, 'adapter'),
             getConfig:         getJsonMaker(Config.ConfigEndpoint, 'config', parseConfig),
             getHub:            getJsonMaker(Config.HubEndpoint, 'hub'),
             getI2B2:           getJsonMaker(Config.I2B2Endpoint, 'i2b2'),
             getKeystore:       getJsonMaker(Config.KeystoreEndpoint, 'keystore', storeRemoteSites),
             getOptionalParts:  getJsonMaker(Config.OptionsEndpoint, 'optionalParts'),
             getProblems:       getProblemsMaker(),
             getQep:            getJsonMaker(Config.QepEndpoint, 'qep'),
             getSummary:        getJsonMaker(Config.SummaryEndpoint, 'summary'),
+            safeLogout:        safeLogout,
+            clearCache:        clearCache,
             map:               map,
             cache:             cache,
             toDashboard:       toDashboard,
             m:                 m
         };
 
         function map(func, list) {
             var result = [];
             for(var i = 0; i < list.length; i++) {
                 result.push(func(list[i]))
             }
             return result;
         }
 
+        /**
+         * Clears the current remote dashboard before logging out.
+         */
+        function safeLogout() {
+            clearCache();
+            toDashboard.url = '';
+            m.siteAlias = '';
+            $location.path('/login');
+        }
+
+        function clearCache() {
+            for (var member in cache) {
+                if(cache.hasOwnProperty(member)) delete cache[member];
+            }
+        }
+
 
         /**
          * Method for Handling a failed rest call.
          * @param failedResult
          * @returns {*}
          */
         function onFail(failedResult) {
             return q.reject(failedResult);
         }
 
 
         /***
          * Method for handling a successful rest call. Simply caches it and returns it.
          * @param result
          * @param cacheKey
          * @returns {*}
          */
         function parseJsonResult(result, cacheKey) {
             cache[cacheKey] = result.data;
             return result.data;
         }
 
         /**
          * Still cache and return the result, however, save the RemoteSites outside of the cache,
          * as we don't want these values to change between cache resets (which occur when switching sites)
          * @param result
          * @param cacheKey
          */
         function storeRemoteSites(result, cacheKey) {
             cache[cacheKey] = result.data;
             if (m.remoteSiteStatuses.length == 0) {
                 m.remoteSiteStatuses = result.data.remoteSiteStatuses;
             }
             return result.data
         }
 
         /**
          * Parses the json config map and turns it into a nested json object
          * @param json the flat config map
          * @param cacheKey a unique identifier for the function
          */
         function parseConfig (json, cacheKey) {
             var configMap = json.data.configMap;
             var processed =  preProcessJson(configMap);
             cache[cacheKey] = processed;
             return processed;
         }
 
         // IE11 doesn't support string includes
         function stringIncludes(haystack, needle) {
             var arr = haystack.split("");
             for (var i = 0; i < arr.length; i++) {
                 if (arr[i] == needle) {
                     return true;
                 }
             }
             return false;
         }
 
         // "explodes" and merges the flag config map.
         // e.g., {"key.foo": 10, "key.baz": 5} -> {"key": {"foo": 10, "baz": 5}}
         function preProcessJson (object) {
             var result = {};
             for (var key in object) {
                 if (object.hasOwnProperty(key)) {
                     if (!stringIncludes(key, ".")) {
                         result[key] = object[key]
                     } else {
                         var split = key.split(".");
                         var prev = result;
                         for (var i = 0; i < split.length; i++) {
                             var cur = split[i];
                             if (!(cur in prev)) {
                                 prev[cur] = {}
                             }
                             if (i == split.length - 1) {
                                 prev[cur] = object[key];
                             } else {
                                 prev = prev[cur]
                             }
                         }
                     }
                 }
             }
             return result;
         }
 
         /**
          * There's a lot going on here. Essentially, this is a function factory that allows one to
          * define backend calls just through the path. It also implements a simple caching
          * strategy.
          * Essentially the get function only needs to be called once, and from then on it will spit
          * back a cached promise. This lets you write the code and not care whether it's cached or
          * not, but also get the caching performance anyways. For this function to work, the
          * resolver function has to take in the http response and the cache key to set, and make
          * sure that it caches what it returns (see parseJsonResult or parseConfig).
          * @param endpoint
          * @param cacheKey
          * @param resolverDefault
          * @returns {Function}
          */
         function getJsonMaker(endpoint, cacheKey, resolverDefault) {
             var resolver = (typeof resolverDefault !== 'undefined')?
                            function (response) { return resolverDefault(response, cacheKey) }:
                            function (response) { return parseJsonResult(response, cacheKey) };
             return function() {
                 var cachedValue = cache[cacheKey];
                 if (cachedValue === undefined) {
                     var url = urlGetter(endpoint, undefined, toDashboard.url);
                     return h.get(url)
                         .then(resolver, onFail)
                 } else {
                     return q(function(resolver) { resolver(cachedValue)});
                 }
             }
         }
 
         function getProblemsMaker() {
             // Caches the last offset and page size to hold onto it between different views
             var prevOffset = 0;
             var prevN = 20;
 
             /**
              * ProblemEndpoint:  'admin/status/problems',
              * @returns {*}
              */
             return function(offset, n, epoch) {
                 if (offset != null) {
                     prevOffset = offset;
                 } else {
                     offset = prevOffset;
                 }
                 if (n != null) {
                     prevN = n;
                 } else {
                     n = prevN;
                 }
 
                 var epochString = epoch && isFinite(epoch) ? '&epoch=' + epoch : '';
                 var url = urlGetter(
                     Config.ProblemEndpoint + '?offset=' + offset + '&n=' + n + epochString,
                     undefined,
                     toDashboard.url
                 );
                 return h.get(url)
                     .then(parseJsonResult, onFail);
             }
         }
     }
 })();
diff --git a/apps/dashboard-app/src/main/js/src/app/diagnostic/sidebar/sidebar.js b/apps/dashboard-app/src/main/js/src/app/diagnostic/sidebar/sidebar.js
index 36367e60b..4c8a947c5 100755
--- a/apps/dashboard-app/src/main/js/src/app/diagnostic/sidebar/sidebar.js
+++ b/apps/dashboard-app/src/main/js/src/app/diagnostic/sidebar/sidebar.js
@@ -1,83 +1,81 @@
 (function() {
     'use strict';
 
   // -- angular -- //
   angular.module('shrine-tools')
       .directive('sidebar', Sidebar);
 
 
   /**
   * - Directive Config -
   *
   */
   function Sidebar () {
 
     var sidebar = {
       templateUrl:  'src/app/diagnostic/sidebar/sidebar.tpl.html',
       restrict:     'E',
       replace:      true,
       link:         SidebarLinker,
       controller:   SidebarController,
       controllerAs: 'vm',
       scope: {
         options: '='
       }
     };
 
     return sidebar;
   }
 
 
   /**
    *  - Controller -
    *
    */
   SidebarController.$inject = ['$scope','$app'];
   function SidebarController ($scope, $app) {
 
     // -- scope --//
     var vm = this;
     vm.toDashboard = $app.model.toDashboard;
-
+    vm.hasHub = function() {return false};
     init();
 
     function init() {
       $app.model.getOptionalParts()
-          .then(setOptions);
-
-      $app.model.getQep()
+          .then(setOptions)
+          .then($app.model.getQep)
           .then(setQep);
-
-      vm.hasHub = function() {return hasHub(vm.trustModelIsHub, vm.options.isHub, vm.toDashboard.url)};
     }
 
 
 
     function setOptions(data) {
       vm.options = data;
     }
 
     function setQep(data) {
       vm.trustModelIsHub = data.trustModelIsHub;
+      vm.hasHub = function() {return hasHub(vm.trustModelIsHub, vm.options.isHub, vm.toDashboard.url)};
     }
 
     function hasHub(trustModelIsHub, isHub, toDashboardUrl) {
       return !trustModelIsHub || isHub && toDashboardUrl == '';
     }
 
   }
 
   /**
    * Controller renamed to 'vm'
    * @param scope
    * @param el
    * @param attr
    * @param vm -- renamed to vm.
    */
   SidebarLinker.$inject = ['scope', 'element', 'attributes', 'sbVM']
   function SidebarLinker(scope, el, attr, vm) {
 
   }
 })();
 
 
diff --git a/apps/dashboard-app/src/main/js/src/app/diagnostic/views/dashboard.controller.js b/apps/dashboard-app/src/main/js/src/app/diagnostic/views/dashboard.controller.js
index 31e3d5873..bc270e795 100644
--- a/apps/dashboard-app/src/main/js/src/app/diagnostic/views/dashboard.controller.js
+++ b/apps/dashboard-app/src/main/js/src/app/diagnostic/views/dashboard.controller.js
@@ -1,83 +1,81 @@
 /**
  * Created by ty on 11/7/16.
  */
 (function () {
     'use strict';
 
     // -- register controller with angular -- //
     angular.module('shrine-tools')
         .controller('DashboardController', DashboardController);
 
 
     /**
      *
      * @type {string[]}
      */
     DashboardController.$inject = ['$app', '$log', '$location'];
     function DashboardController ($app, $log, $location) {
         var vm = this;
         var map = $app.model.map;
         vm.keyStoreError = false;
 
         init();
 
         /**
          *
          */
         function init () {
             $app.model.getKeystore()
                 .then(setDashboard, handleFailure);
         }
 
         function handleFailure (failure) {
             vm.keyStoreError = failure;
         }
 
         /**
          *
          * @param keystore
          */
         function setDashboard (keystore) {
             var modelStatuses = $app.model.m.remoteSiteStatuses;
             var tempList = [];
             for (var i = 0; i < modelStatuses.length; i++) {
                 var abbreviatedEntry = modelStatuses[i];
                 if (abbreviatedEntry.url != "")
                     tempList.push(abbreviatedEntry)
             }
 
             vm.otherDashboards = [['Hub', '']].concat(map(entryToPair, tempList));
             vm.otherDashboards.sort(comparator);
             vm.clearCache = clearCache;
             vm.switchDashboard = switchDashboard;
         }
 
         function comparator(first, second) {
             if (first[0] == 'Hub') {
                 return -2;
             } else {
                 var less = first[0].toLowerCase() < second[0].toLowerCase();
                 var eq = first[0].toLowerCase() == second[0].toLowerCase();
                 return less? -1: eq? 0 : 1
             }
         }
 
         function switchDashboard(url, alias) {
             $app.model.toDashboard.url = url;
             $app.model.m.siteAlias = alias == 'Hub'? '': alias;
             clearCache();
             $location.url("/diagnostic/summary");
         }
 
         function clearCache() {
-            for (var member in $app.model.cache) {
-                if($app.model.cache.hasOwnProperty(member)) delete $app.model.cache[member];
-            }
+            $app.model.clearCache();
         }
 
         function entryToPair(entry){
             return [entry.siteAlias, entry.url];
         }
     }
 })();
 
diff --git a/apps/dashboard-app/src/main/js/src/app/header/user-status.js b/apps/dashboard-app/src/main/js/src/app/header/user-status.js
index bd66b0a4e..9f86e885d 100755
--- a/apps/dashboard-app/src/main/js/src/app/header/user-status.js
+++ b/apps/dashboard-app/src/main/js/src/app/header/user-status.js
@@ -1,80 +1,80 @@
 (function () {
 
     // -- register directive with angular -- //
     angular.module('shrine-tools')
         .directive('userStatus', UserStatus);
 
     /***
      *
      * @returns {{restict: string, replace: boolean, templateUrl: string,
      * controller: UserStatusController, controllerAs: string, link: UserStatusLinker, scope: {}}}
      * @constructor
      */
     function UserStatus () {
         return {
             restict:        'E',
             replace:        true,
             templateUrl:    'src/app/header/user-status.tpl.html',
             controller:     UserStatusController,
             controllerAs:   'vm',
             link:           UserStatusLinker,
             scope: {
             }
         }
     }
 
 
     /**
      *
      * @type {string[]}
      */
-    UserStatusController.$inject = ['$location', '$app'];
-    function UserStatusController ($location, $app) {
+    UserStatusController.$inject = ['$app'];
+    function UserStatusController ($app, $log) {
         var vm = this;
 
         vm.isUserLoggedIn   = isUserLoggedIn;
         vm.getUsername      = getUsername;
         vm.logout           = logout;
 
 
         /**
          *
          * @returns {boolean}
          */
         function isUserLoggedIn () {
             return ($app.globals.currentUser !== undefined && $app.globals.currentUser.isLoggedIn === true);
         }
 
 
         /**
          *
          * @returns {*}
          */
         function getUsername () {
             return ($app.globals.currentUser) ?
                 $app.globals.currentUser.username : '';
         }
 
 
         /**
          *
          *
          */
         function logout () {
-            $location.path('/login');
+            $app.model.safeLogout();
         }
     }
 
 
     /**
      *
      * @type {string[]}
      */
     UserStatusLinker.$inject = ['scope', 'element', 'attributes'];
     function UserStatusLinker (s, e, a) {
         var vm = s.vm;
     }
 
 })();