diff --git a/.storybook/preview-head.html b/.storybook/preview-head.html
index 0257abdbb7f26fc10a58b7ce42f19c7cd719c4eb..f63b14cd95658b20dc7795ad8804b6e322020b50 100644
--- a/.storybook/preview-head.html
+++ b/.storybook/preview-head.html
@@ -10,5 +10,5 @@
   }
 </style>
 <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.1/css/all.css" integrity="sha384-50oBUHEmvpQ+1lW4y57PTFmhCaXp0ML5d60M1M7uH2+nqUivzIebhndOJK28anvf" crossorigin="anonymous">
-<script type="module" src="https://unpkg.com/hbp-connectivity-component@0.6.2/dist/connectivity-component/connectivity-component.js" defer></script>
+<script type="module" src="https://unpkg.com/hbp-connectivity-component@0.6.5/dist/connectivity-component/connectivity-component.js" defer></script>
 <link rel="stylesheet" href="icons/iav-icons.css">
diff --git a/Dockerfile b/Dockerfile
index 8425647048ad716c0b86edb66ad609b36aa01a84..9bd522fc48e09b4cfc52ae0c09cece083e7ce276 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -24,18 +24,20 @@ ENV EXPERIMENTAL_FEATURE_FLAG=${EXPERIMENTAL_FEATURE_FLAG:-false}
 ARG ENABLE_LEAP_MOTION
 ENV ENABLE_LEAP_MOTION=${ENABLE_LEAP_MOTION:-false}
 
+# mkdir, and copy package.json and package-lock.json and npm i
+# to effectively use the caching layer
 
-COPY . /iv
+RUN mkdir /iv
 WORKDIR /iv
+COPY ./package.json /iv/
+COPY ./package-lock.json /iv/
+RUN npm i
+
+COPY . /iv/
 
 # angular 12 echo the env var into src/environments/environment.prod.ts
 RUN node ./src/environments/parseEnv.js
 
-# When building in local, where node_module already exist, prebuilt binary may throw an error
-RUN rm -rf ./node_modules
-
-
-RUN npm i
 RUN npm run build
 RUN node third_party/matomo/processMatomo.js
 RUN npm run build-storybook
diff --git a/common/constants.js b/common/constants.js
index c1fe2db5b6981123c9811587a0523a859b95c234..ce25c3a98844ed6fd872ad6be2a86f08d4bc8e4f 100644
--- a/common/constants.js
+++ b/common/constants.js
@@ -84,6 +84,11 @@
     MESH_LOADING_STATUS: 'mesh-loading-status'
   }
 
+  exports.VALUES = {
+    ROOT_2: 0.7071067690849304,
+    THRESHOLD: 1e-3
+  }
+
   exports.CONST = {
     KG_TOS: `The interactive viewer queries HBP Knowledge Graph Data Platform ("KG") for published datasets.
 
@@ -103,6 +108,8 @@ These outlines are based on the authoritative Terms and Conditions are found <ht
 If you do not accept the Terms & Conditions you are not permitted to access or use the KG to search for, to submit, to post, or to download any materials found there-in.
 `,
 
+    NEHUBA_DRAG_DROP_TEXT: `Drag and drop any .nii.gz, .nii or .swc files.`,
+
     LOADING_TXT: `Loading ...`,
 
     CANNOT_DECIPHER_HEMISPHERE: 'Cannot decipher region hemisphere.',
@@ -113,10 +120,6 @@ If you do not accept the Terms & Conditions you are not permitted to access or u
     CONNECTIVITY: 'Connectivity',
     NO_ADDIONTAL_INFO_AVAIL: `Currently, no additional information is linked to this region.`,
 
-    ATLAS_NOT_FOUND: `Atlas not found. Maybe it is still loading. Try again in a few seconds?`,
-    TEMPLATE_NOT_FOUND: `Template not found. Maybe it is still loading. Try again in a few seconds?`,
-    PARC_NOT_FOUND: ``,
-
     PINNED_DATASETS_BADGE_DESC: `Number of pinned datasets`,
 
     GDPR_TEXT: `This dataset is currently reviewed by the EBRAINS Data Protection Office regarding GDPR compliance. Therefore the atlas does not provide access to the underlying data files yet. The data will be available after this review.`,
@@ -140,14 +143,16 @@ If you do not accept the Terms & Conditions you are not permitted to access or u
 
     TOGGLE_LAYER_VISILITY: 'Toggle layer visility',
     ORIENT_TO_LAYER: 'Orient to layer native orientation',
-    CONFIGURE_LAYER: 'Configure layer'
+    CONFIGURE_LAYER: 'Configure layer',
+
+    REMOVE_FRONTAL_OCTANT_HELPER_TEXT: `Hide the octant facing the user, and overlaying the slice views.`,
   }
 
   exports.QUICKTOUR_DESC ={
     REGION_SEARCH: `Use the region quick search for finding, selecting and navigating brain regions in the selected parcellation map.`,
     ATLAS_SELECTOR: `This is the atlas selector. Click here to choose between EBRAINS reference atlases of different species.`,
     CHIPS: `These "chips" indicate the currently selected parcellation map as well as selected region. Click the chip to see different versions, if any. Click (i) to read more about a selected item. Click (x) to clear a selection.`,
-    SLICE_VIEW: `The planar views allow you to zoom in to full resolution (mouse wheel), pan the view (click+drag), and select oblique sections (shift+click+drag). You can double-click brain regions to select them.`,
+    SLICE_VIEW: `The planar views allow you to zoom in to full resolution (mouse wheel), pan the view (click+drag), and select oblique sections (shift+click+drag). You can click any brain regions to select them.`,
     PERSPECTIVE_VIEW: `The 3D view gives an overview of the brain with limited resolution. It can be independently rotated. On the 3d view you can find additional settings.`,
     VIEW_ICONS: `Use these icons in any of the views to maximize it and zoom in/out.`,
     TOP_MENU: `These icons provide access to plugins, pinned datasets, and user documentation. Use the profile icon to login with your EBRAINS account.`,
diff --git a/common/util.js b/common/util.js
index 44f458cafc4884e64f1a225c6d11a3425fbbda68..1e383c5c61fdcda758debbc5dafa11bd8bc396b9 100644
--- a/common/util.js
+++ b/common/util.js
@@ -312,5 +312,8 @@
     }
   }
 
+  exports.floatEquality = (v1, v2, threshold) => {
+    return Math.abs(v1 - v2) < threshold
+  }
 
 })(typeof exports === 'undefined' ? module.exports : exports)
diff --git a/deploy/auth/index.js b/deploy/auth/index.js
index 413afb7088e2cfc62b429c07043a566045461308..62b41fa21e1468d38c91b11ba9bfbda6d7b46097 100644
--- a/deploy/auth/index.js
+++ b/deploy/auth/index.js
@@ -23,8 +23,12 @@ const configureAuth = async (app) => {
 
   app.get('/logout', (req, res) => {
     if (req.user && req.user.id) objStoreDb.delete(req.user.id)
-    req.logout()
-    res.redirect(`${HOST_PATHNAME}/`)
+    req.logout(err => {
+      if (!!err) {
+        console.log(`err during logout: ${err.toString()}`)
+      }
+      res.redirect(`${HOST_PATHNAME}/`)
+    })
   })
 }
 
diff --git a/deploy/csp/index.js b/deploy/csp/index.js
index 898228ce845b95c747d027704c08ab96f8196c30..9cc365a20323aad04d461fc9143c81f56cc91db4 100644
--- a/deploy/csp/index.js
+++ b/deploy/csp/index.js
@@ -109,11 +109,11 @@ module.exports = {
           "'self'",
           ...userScriptSrc,
           'unpkg.com/kg-dataset-previewer@1.2.0/', // preview component
-          'cdnjs.cloudflare.com/ajax/libs/d3/', // required for preview component
-          'cdnjs.cloudflare.com/ajax/libs/mathjax/', // math jax
+          'https://unpkg.com/d3@6.2.0/', // required for preview component
+          'https://unpkg.com/mathjax@3.1.2/', // math jax
           'https://unpkg.com/three-surfer@0.0.11/dist/bundle.js', // for threeSurfer (freesurfer support in browser)
           'https://unpkg.com/ng-layer-tune@0.0.6/dist/ng-layer-tune/', // needed for ng layer control
-          'https://unpkg.com/hbp-connectivity-component@0.6.2/', // needed for connectivity component
+          'https://unpkg.com/hbp-connectivity-component@0.6.5/', // needed for connectivity component
           (req, res) => res.locals.nonce ? `'nonce-${res.locals.nonce}'` : null,
           ...SCRIPT_SRC,
           ...WHITE_LIST_SRC,
diff --git a/deploy/package-lock.json b/deploy/package-lock.json
index 85a12542dc7b71eca0510d03a3d5ce1178f09567..84c1240626e2182b52390fda558107e7a36d6ffb 100644
--- a/deploy/package-lock.json
+++ b/deploy/package-lock.json
@@ -95,12 +95,6 @@
         "@types/node": "*"
       }
     },
-    "@ungap/promise-all-settled": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz",
-      "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==",
-      "dev": true
-    },
     "accepts": {
       "version": "1.3.5",
       "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz",
@@ -141,6 +135,15 @@
       "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
       "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
     },
+    "ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "requires": {
+        "color-convert": "^2.0.1"
+      }
+    },
     "anymatch": {
       "version": "3.1.2",
       "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
@@ -197,9 +200,9 @@
       "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA=="
     },
     "balanced-match": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
-      "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+      "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
       "dev": true
     },
     "bcrypt-pbkdf": {
@@ -314,27 +317,11 @@
       "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
       "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg=="
     },
-    "cacheable-lookup": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-2.0.0.tgz",
-      "integrity": "sha512-s2piO6LvA7xnL1AR03wuEdSx3BZT3tIJpZ56/lcJwzO/6DTJZlTs7X3lrvPxk6d1PlDe6PrVe2TjlUIZNFglAQ==",
-      "requires": {
-        "keyv": "^4.0.0"
-      }
-    },
-    "cacheable-request": {
-      "version": "7.0.1",
-      "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.1.tgz",
-      "integrity": "sha512-lt0mJ6YAnsrBErpTMWeu5kl/tg9xMAWjavYTN6VQXM1A/teBITuNcccXsCxF0tDQQJf9DfAaX5O4e0zp0KlfZw==",
-      "requires": {
-        "clone-response": "^1.0.2",
-        "get-stream": "^5.1.0",
-        "http-cache-semantics": "^4.0.0",
-        "keyv": "^4.0.0",
-        "lowercase-keys": "^2.0.0",
-        "normalize-url": "^4.1.0",
-        "responselike": "^2.0.0"
-      }
+    "camelcase": {
+      "version": "6.3.0",
+      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
+      "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
+      "dev": true
     },
     "caseless": {
       "version": "0.12.0",
@@ -374,30 +361,6 @@
         "supports-color": "^7.1.0"
       },
       "dependencies": {
-        "ansi-styles": {
-          "version": "4.3.0",
-          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-          "dev": true,
-          "requires": {
-            "color-convert": "^2.0.1"
-          }
-        },
-        "color-convert": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-          "dev": true,
-          "requires": {
-            "color-name": "~1.1.4"
-          }
-        },
-        "color-name": {
-          "version": "1.1.4",
-          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-          "dev": true
-        },
         "supports-color": {
           "version": "7.2.0",
           "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
@@ -466,6 +429,21 @@
         }
       }
     },
+    "color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "requires": {
+        "color-name": "~1.1.4"
+      }
+    },
+    "color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true
+    },
     "combined-stream": {
       "version": "1.0.8",
       "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
@@ -477,7 +455,7 @@
     "concat-map": {
       "version": "0.0.1",
       "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
-      "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
+      "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
       "dev": true
     },
     "connect-redis": {
@@ -558,13 +536,11 @@
         "ms": "2.0.0"
       }
     },
-    "decompress-response": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-5.0.0.tgz",
-      "integrity": "sha512-TLZWWybuxWgoW7Lykv+gq9xvzOsUjQ9tF09Tj6NSTYGMTCHNXzrPnD6Hi+TgZq19PyTAGH4Ll/NIM/eTGglnMw==",
-      "requires": {
-        "mimic-response": "^2.0.0"
-      }
+    "decamelize": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz",
+      "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==",
+      "dev": true
     },
     "deep-eql": {
       "version": "3.0.1",
@@ -620,11 +596,6 @@
       "integrity": "sha512-HygQCKUBSFl8wKQZBSemMywRWcEDNidvNbjGVyZu3nbZ8qq9ubiPoGLMdRDpfSrpkkm9BXYFkpKxxFX38o/76w==",
       "dev": true
     },
-    "duplexer3": {
-      "version": "0.1.4",
-      "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz",
-      "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI="
-    },
     "ecc-jsbn": {
       "version": "0.1.2",
       "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
@@ -829,6 +800,16 @@
         "unpipe": "~1.0.0"
       }
     },
+    "find-up": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+      "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+      "dev": true,
+      "requires": {
+        "locate-path": "^6.0.0",
+        "path-exists": "^4.0.0"
+      }
+    },
     "flat": {
       "version": "5.0.2",
       "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz",
@@ -863,7 +844,7 @@
     "fs.realpath": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
-      "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
+      "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
       "dev": true
     },
     "fsevents": {
@@ -912,6 +893,17 @@
         "minimatch": "^3.0.4",
         "once": "^1.3.0",
         "path-is-absolute": "^1.0.0"
+      },
+      "dependencies": {
+        "minimatch": {
+          "version": "3.1.2",
+          "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+          "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+          "dev": true,
+          "requires": {
+            "brace-expansion": "^1.1.7"
+          }
+        }
       }
     },
     "glob-parent": {
@@ -980,12 +972,6 @@
         }
       }
     },
-    "growl": {
-      "version": "1.10.5",
-      "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz",
-      "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==",
-      "dev": true
-    },
     "har-schema": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
@@ -1076,7 +1062,7 @@
     "inflight": {
       "version": "1.0.6",
       "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
-      "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+      "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
       "dev": true,
       "requires": {
         "once": "^1.3.0",
@@ -1088,11 +1074,6 @@
       "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
       "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
     },
-    "ip-regex": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz",
-      "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk="
-    },
     "ipaddr.js": {
       "version": "1.8.0",
       "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.8.0.tgz",
@@ -1110,7 +1091,7 @@
     "is-extglob": {
       "version": "2.1.1",
       "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
-      "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
+      "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
       "dev": true
     },
     "is-glob": {
@@ -1150,21 +1131,15 @@
       "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
       "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
     },
-    "isexe": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
-      "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
-      "dev": true
-    },
     "isstream": {
       "version": "0.1.2",
       "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
       "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
     },
     "jose": {
-      "version": "2.0.5",
-      "resolved": "https://registry.npmjs.org/jose/-/jose-2.0.5.tgz",
-      "integrity": "sha512-BAiDNeDKTMgk4tvD0BbxJ8xHEHBZgpeRZ1zGPPsitSyMgjoMWiLGYAE7H7NpP5h0lPppQajQs871E8NHUrzVPA==",
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/jose/-/jose-2.0.6.tgz",
+      "integrity": "sha512-FVoPY7SflDodE4lknJmbAHSUjLCzE2H1F6MS0RYKMQ8SR+lNccpMf8R4eqkNYyyUjR5qZReOzZo5C5YiHOCjjg==",
       "requires": {
         "@panva/asn1.js": "^1.0.0"
       }
@@ -1228,6 +1203,15 @@
         "json-buffer": "3.0.1"
       }
     },
+    "locate-path": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+      "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+      "dev": true,
+      "requires": {
+        "p-locate": "^5.0.0"
+      }
+    },
     "lodash": {
       "version": "4.17.21",
       "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
@@ -1343,56 +1327,59 @@
         "mime-db": "~1.38.0"
       }
     },
-    "mimic-response": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.0.0.tgz",
-      "integrity": "sha512-8ilDoEapqA4uQ3TwS0jakGONKXVJqpy+RpM+3b7pLdOjghCrEiGp9SRkFbUHAmZW9vdnrENWHjaweIoTIJExSQ=="
-    },
     "minimatch": {
-      "version": "3.0.4",
-      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
-      "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz",
+      "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==",
       "dev": true,
       "requires": {
-        "brace-expansion": "^1.1.7"
+        "brace-expansion": "^2.0.1"
+      },
+      "dependencies": {
+        "brace-expansion": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+          "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+          "dev": true,
+          "requires": {
+            "balanced-match": "^1.0.0"
+          }
+        }
       }
     },
     "mocha": {
-      "version": "9.2.1",
-      "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.1.tgz",
-      "integrity": "sha512-T7uscqjJVS46Pq1XDXyo9Uvey9gd3huT/DD9cYBb4K2Xc/vbKRPUWK067bxDQRK0yIz6Jxk73IrnimvASzBNAQ==",
+      "version": "10.1.0",
+      "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.1.0.tgz",
+      "integrity": "sha512-vUF7IYxEoN7XhQpFLxQAEMtE4W91acW4B6En9l97MwE9stL1A9gusXfoHZCLVHDUJ/7V5+lbCM6yMqzo5vNymg==",
       "dev": true,
       "requires": {
-        "@ungap/promise-all-settled": "1.1.2",
         "ansi-colors": "4.1.1",
         "browser-stdout": "1.3.1",
         "chokidar": "3.5.3",
-        "debug": "4.3.3",
+        "debug": "4.3.4",
         "diff": "5.0.0",
         "escape-string-regexp": "4.0.0",
         "find-up": "5.0.0",
         "glob": "7.2.0",
-        "growl": "1.10.5",
         "he": "1.2.0",
         "js-yaml": "4.1.0",
         "log-symbols": "4.1.0",
-        "minimatch": "3.0.4",
+        "minimatch": "5.0.1",
         "ms": "2.1.3",
-        "nanoid": "3.2.0",
+        "nanoid": "3.3.3",
         "serialize-javascript": "6.0.0",
         "strip-json-comments": "3.1.1",
         "supports-color": "8.1.1",
-        "which": "2.0.2",
-        "workerpool": "6.2.0",
+        "workerpool": "6.2.1",
         "yargs": "16.2.0",
         "yargs-parser": "20.2.4",
         "yargs-unparser": "2.0.0"
       },
       "dependencies": {
         "debug": {
-          "version": "4.3.3",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz",
-          "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==",
+          "version": "4.3.4",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+          "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
           "dev": true,
           "requires": {
             "ms": "2.1.2"
@@ -1406,54 +1393,11 @@
             }
           }
         },
-        "find-up": {
-          "version": "5.0.0",
-          "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
-          "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
-          "dev": true,
-          "requires": {
-            "locate-path": "^6.0.0",
-            "path-exists": "^4.0.0"
-          }
-        },
-        "locate-path": {
-          "version": "6.0.0",
-          "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
-          "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
-          "dev": true,
-          "requires": {
-            "p-locate": "^5.0.0"
-          }
-        },
         "ms": {
           "version": "2.1.3",
           "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
           "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
           "dev": true
-        },
-        "p-limit": {
-          "version": "3.1.0",
-          "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
-          "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
-          "dev": true,
-          "requires": {
-            "yocto-queue": "^0.1.0"
-          }
-        },
-        "p-locate": {
-          "version": "5.0.0",
-          "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
-          "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
-          "dev": true,
-          "requires": {
-            "p-limit": "^3.0.2"
-          }
-        },
-        "path-exists": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
-          "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
-          "dev": true
         }
       }
     },
@@ -1463,9 +1407,9 @@
       "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
     },
     "nanoid": {
-      "version": "3.2.0",
-      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.2.0.tgz",
-      "integrity": "sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==",
+      "version": "3.3.3",
+      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz",
+      "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==",
       "dev": true
     },
     "negotiator": {
@@ -1544,11 +1488,6 @@
       "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
       "dev": true
     },
-    "normalize-url": {
-      "version": "4.5.1",
-      "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz",
-      "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA=="
-    },
     "oauth-sign": {
       "version": "0.9.0",
       "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
@@ -1696,25 +1635,22 @@
       "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.0.0.tgz",
       "integrity": "sha512-wvPXDmbMmu2ksjkB4Z3nZWTSkJEb9lqVdMaCKpZUGJG9TMiNp9XcbG3fn9fPKjem04fJMJnXoyFPk2FmgiaiNg=="
     },
-    "p-event": {
-      "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/p-event/-/p-event-4.1.0.tgz",
-      "integrity": "sha512-4vAd06GCsgflX4wHN1JqrMzBh/8QZ4j+rzp0cd2scXRwuBEv+QR3wrVA5aLhWDLw4y2WgDKvzWF3CCLmVM1UgA==",
+    "p-limit": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+      "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+      "dev": true,
       "requires": {
-        "p-timeout": "^2.0.1"
+        "yocto-queue": "^0.1.0"
       }
     },
-    "p-finally": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
-      "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4="
-    },
-    "p-timeout": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-2.0.1.tgz",
-      "integrity": "sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA==",
+    "p-locate": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+      "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+      "dev": true,
       "requires": {
-        "p-finally": "^1.0.0"
+        "p-limit": "^3.0.2"
       }
     },
     "parseurl": {
@@ -1723,23 +1659,30 @@
       "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M="
     },
     "passport": {
-      "version": "0.4.0",
-      "resolved": "https://registry.npmjs.org/passport/-/passport-0.4.0.tgz",
-      "integrity": "sha1-xQlWkTR71a07XhgCOMORTRbwWBE=",
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/passport/-/passport-0.6.0.tgz",
+      "integrity": "sha512-0fe+p3ZnrWRW74fe8+SvCyf4a3Pb2/h7gFkQ8yTJpAO50gDzlfjZUZTO1k5Eg9kUct22OxHLqDZoKUWRHOh9ug==",
       "requires": {
         "passport-strategy": "1.x.x",
-        "pause": "0.0.1"
+        "pause": "0.0.1",
+        "utils-merge": "^1.0.1"
       }
     },
     "passport-strategy": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz",
-      "integrity": "sha1-tVOaqPwiWj0a0XlHbd8ja0QPUuQ="
+      "integrity": "sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA=="
+    },
+    "path-exists": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+      "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+      "dev": true
     },
     "path-is-absolute": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
-      "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
+      "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
       "dev": true
     },
     "path-to-regexp": {
@@ -1756,7 +1699,7 @@
     "pause": {
       "version": "0.0.1",
       "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz",
-      "integrity": "sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10="
+      "integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg=="
     },
     "performance-now": {
       "version": "2.1.0",
@@ -2116,54 +2059,6 @@
         }
       }
     },
-    "soswrap": {
-      "version": "0.0.2",
-      "resolved": "https://registry.npmjs.org/soswrap/-/soswrap-0.0.2.tgz",
-      "integrity": "sha512-OooZXmh5r57UDRg6z9L5xpXP2OZNNqvbmNmnUHfjccL+Cr4KGRpNIs/FPWO/+sgtDnUniLwFPwzRGn3VxOtlug==",
-      "requires": {
-        "got": "^10.7.0",
-        "tough-cookie": "^3.0.1"
-      },
-      "dependencies": {
-        "@sindresorhus/is": {
-          "version": "2.1.1",
-          "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-2.1.1.tgz",
-          "integrity": "sha512-/aPsuoj/1Dw/kzhkgz+ES6TxG0zfTMGLwuK2ZG00k/iJzYHTLCE8mVU8EPqEOp/lmxPoq1C1C9RYToRKb2KEfg=="
-        },
-        "got": {
-          "version": "10.7.0",
-          "resolved": "https://registry.npmjs.org/got/-/got-10.7.0.tgz",
-          "integrity": "sha512-aWTDeNw9g+XqEZNcTjMMZSy7B7yE9toWOFYip7ofFTLleJhvZwUxxTxkTpKvF+p1SAA4VHmuEy7PiHTHyq8tJg==",
-          "requires": {
-            "@sindresorhus/is": "^2.0.0",
-            "@szmarczak/http-timer": "^4.0.0",
-            "@types/cacheable-request": "^6.0.1",
-            "cacheable-lookup": "^2.0.0",
-            "cacheable-request": "^7.0.1",
-            "decompress-response": "^5.0.0",
-            "duplexer3": "^0.1.4",
-            "get-stream": "^5.0.0",
-            "lowercase-keys": "^2.0.0",
-            "mimic-response": "^2.1.0",
-            "p-cancelable": "^2.0.0",
-            "p-event": "^4.0.0",
-            "responselike": "^2.0.0",
-            "to-readable-stream": "^2.0.0",
-            "type-fest": "^0.10.0"
-          }
-        },
-        "mimic-response": {
-          "version": "2.1.0",
-          "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz",
-          "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA=="
-        },
-        "type-fest": {
-          "version": "0.10.0",
-          "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.10.0.tgz",
-          "integrity": "sha512-EUV9jo4sffrwlg8s0zDhP0T2WD3pru5Xi0+HTE3zTUmBaZNhfkite9PdSJwdXLwPVW0jnAHT56pZHIOYckPEiw=="
-        }
-      }
-    },
     "sshpk": {
       "version": "1.16.1",
       "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz",
@@ -2246,11 +2141,6 @@
         "readable-stream": "2 || 3"
       }
     },
-    "to-readable-stream": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-2.1.0.tgz",
-      "integrity": "sha512-o3Qa6DGg1CEXshSdvWNX2sN4QHqg03SPq7U6jPXRahlQdl5dK8oXjkU/2/sGrnOZKeGV1zLSO8qPwyKklPPE7w=="
-    },
     "to-regex-range": {
       "version": "5.0.1",
       "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
@@ -2265,16 +2155,6 @@
       "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
       "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw=="
     },
-    "tough-cookie": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz",
-      "integrity": "sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg==",
-      "requires": {
-        "ip-regex": "^2.1.0",
-        "psl": "^1.1.28",
-        "punycode": "^2.1.1"
-      }
-    },
     "tunnel-agent": {
       "version": "0.6.0",
       "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
@@ -2354,19 +2234,10 @@
         "extsprintf": "^1.2.0"
       }
     },
-    "which": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
-      "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
-      "dev": true,
-      "requires": {
-        "isexe": "^2.0.0"
-      }
-    },
     "workerpool": {
-      "version": "6.2.0",
-      "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz",
-      "integrity": "sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==",
+      "version": "6.2.1",
+      "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz",
+      "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==",
       "dev": true
     },
     "wrap-ansi": {
@@ -2430,14 +2301,6 @@
         "string-width": "^4.2.0",
         "y18n": "^5.0.5",
         "yargs-parser": "^20.2.2"
-      },
-      "dependencies": {
-        "y18n": {
-          "version": "5.0.8",
-          "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
-          "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
-          "dev": true
-        }
       }
     },
     "yargs-parser": {
@@ -2456,20 +2319,6 @@
         "decamelize": "^4.0.0",
         "flat": "^5.0.2",
         "is-plain-obj": "^2.1.0"
-      },
-      "dependencies": {
-        "camelcase": {
-          "version": "6.3.0",
-          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
-          "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
-          "dev": true
-        },
-        "decamelize": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz",
-          "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==",
-          "dev": true
-        }
       }
     },
     "yocto-queue": {
diff --git a/deploy/package.json b/deploy/package.json
index 9470dcf3c16f707ecd0c023fcff17e3e843d2bc8..72e28bf6872c7a12ec0c95def03a4e988ca4d959 100644
--- a/deploy/package.json
+++ b/deploy/package.json
@@ -25,12 +25,11 @@
     "memorystore": "^1.6.1",
     "nomiseco": "0.0.2",
     "openid-client": "^4.4.0",
-    "passport": "^0.4.0",
+    "passport": "^0.6.0",
     "rate-limit-redis": "^2.1.0",
     "redis": "^3.1.2",
     "request": "^2.88.2",
     "showdown": "^2.0.0",
-    "soswrap": "^0.0.2",
     "through2": "^3.0.1"
   },
   "devDependencies": {
@@ -39,7 +38,7 @@
     "cookie": "^0.4.0",
     "cors": "^2.8.5",
     "dotenv": "^6.2.0",
-    "mocha": "^9.2.1",
+    "mocha": "^10.1.0",
     "nock": "^12.0.3",
     "sinon": "^8.0.2"
   }
diff --git a/docs/releases/v2.7.6.md b/docs/releases/v2.7.6.md
new file mode 100644
index 0000000000000000000000000000000000000000..d41518c5b123f8cf2742e4a5d6795319e159e9e1
--- /dev/null
+++ b/docs/releases/v2.7.6.md
@@ -0,0 +1,15 @@
+# v2.7.6
+
+## Features
+
+- Emitting navigation state for plugin API
+- Reintroduced snap perspective orientation functionality
+
+## Bugfix
+
+- Fixed drag and drop in nehuba viewer
+
+## Under the hood
+
+- bumped siibra-api version for updated julich brain hierarchy
+- updated some dependencies
diff --git a/docs/releases/v2.7.7.md b/docs/releases/v2.7.7.md
new file mode 100644
index 0000000000000000000000000000000000000000..1c270ee78a5e88b5c4faaa0fe16137dc7b99e35c
--- /dev/null
+++ b/docs/releases/v2.7.7.md
@@ -0,0 +1,5 @@
+# v2.7.7
+
+## Bugfix
+
+- Fixed region hierarchy losing interactivity
diff --git a/mkdocs.yml b/mkdocs.yml
index a0e078dcf75975c2a310b01c52b83b97f8c51865..8d57d34a5eec63f8e99f62cf4a40e554b0821b8c 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -34,6 +34,8 @@ nav:
     - Display non-atlas volumes: 'advanced/otherVolumes.md'
   - Release notes:
     - v2.8.0: 'releases/v2.8.0.md'
+    - v2.7.7: 'releases/v2.7.7.md'
+    - v2.7.6: 'releases/v2.7.6.md'
     - v2.7.5: 'releases/v2.7.5.md'
     - v2.7.4: 'releases/v2.7.4.md'
     - v2.7.3: 'releases/v2.7.3.md'
diff --git a/package-lock.json b/package-lock.json
index a430b1fb3e4bb0ca1d9daea0579ba57778c1315c..64caee7979753a961071de10bd41f8f360fae0eb 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,7 +1,8 @@
 {
   "name": "interactive-viewer",
-  "requires": true,
+  "version": "2.7.7",
   "lockfileVersion": 1,
+  "requires": true,
   "dependencies": {
     "@aduh95/viz.js": {
       "version": "3.6.0",
@@ -172,6 +173,12 @@
             }
           }
         },
+        "commander": {
+          "version": "2.20.3",
+          "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+          "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+          "dev": true
+        },
         "esbuild": {
           "version": "0.13.8",
           "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.13.8.tgz",
@@ -209,6 +216,15 @@
             "json5": "^2.1.2"
           }
         },
+        "minimatch": {
+          "version": "3.0.4",
+          "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+          "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+          "dev": true,
+          "requires": {
+            "brace-expansion": "^1.1.7"
+          }
+        },
         "postcss": {
           "version": "8.3.6",
           "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.3.6.tgz",
@@ -243,6 +259,25 @@
           "integrity": "sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug==",
           "dev": true
         },
+        "terser": {
+          "version": "5.7.1",
+          "resolved": "https://registry.npmjs.org/terser/-/terser-5.7.1.tgz",
+          "integrity": "sha512-b3e+d5JbHAe/JSjwsC3Zn55wsBIM7AsHLjKxT31kGCldgbpFePaFo+PiddtO6uwRZWRw7sPXmAN8dTW61xmnSg==",
+          "dev": true,
+          "requires": {
+            "commander": "^2.20.0",
+            "source-map": "~0.7.2",
+            "source-map-support": "~0.5.19"
+          },
+          "dependencies": {
+            "source-map": {
+              "version": "0.7.4",
+              "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz",
+              "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==",
+              "dev": true
+            }
+          }
+        },
         "tslib": {
           "version": "2.3.0",
           "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz",
@@ -3047,6 +3082,16 @@
       "integrity": "sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ==",
       "dev": true
     },
+    "@jridgewell/source-map": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz",
+      "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==",
+      "dev": true,
+      "requires": {
+        "@jridgewell/gen-mapping": "^0.3.0",
+        "@jridgewell/trace-mapping": "^0.3.9"
+      }
+    },
     "@jridgewell/sourcemap-codec": {
       "version": "1.4.13",
       "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz",
@@ -5103,8 +5148,7 @@
         },
         "terser": {
           "version": "5.13.1",
-          "resolved": "https://registry.npmjs.org/terser/-/terser-5.13.1.tgz",
-          "integrity": "sha512-hn4WKOfwnwbYfe48NgrQjqNOH9jzLqRcIfbYytOXCOv46LBfWr9bDS17MQqOi+BWGD0sJK3Sj5NC/gJjiojaoA==",
+          "resolved": "",
           "dev": true,
           "requires": {
             "acorn": "^8.5.0",
@@ -5171,7 +5215,6 @@
           "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==",
           "dev": true,
           "requires": {
-            "lodash.sortby": "^4.7.0",
             "tr46": "^1.0.1",
             "webidl-conversions": "^4.0.2"
           }
@@ -8126,8 +8169,7 @@
         },
         "terser": {
           "version": "5.13.1",
-          "resolved": "https://registry.npmjs.org/terser/-/terser-5.13.1.tgz",
-          "integrity": "sha512-hn4WKOfwnwbYfe48NgrQjqNOH9jzLqRcIfbYytOXCOv46LBfWr9bDS17MQqOi+BWGD0sJK3Sj5NC/gJjiojaoA==",
+          "resolved": "",
           "dev": true,
           "requires": {
             "acorn": "^8.5.0",
@@ -8194,7 +8236,6 @@
           "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==",
           "dev": true,
           "requires": {
-            "lodash.sortby": "^4.7.0",
             "tr46": "^1.0.1",
             "webidl-conversions": "^4.0.2"
           }
@@ -17493,12 +17534,6 @@
       "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
       "dev": true
     },
-    "lodash.sortby": {
-      "version": "4.7.0",
-      "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
-      "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=",
-      "dev": true
-    },
     "lodash.truncate": {
       "version": "4.4.2",
       "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz",
@@ -18109,9 +18144,9 @@
       "dev": true
     },
     "minimatch": {
-      "version": "3.0.4",
-      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
-      "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
       "dev": true,
       "requires": {
         "brace-expansion": "^1.1.7"
@@ -22864,9 +22899,9 @@
       "dev": true
     },
     "socket.io-parser": {
-      "version": "4.0.4",
-      "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.0.4.tgz",
-      "integrity": "sha512-t+b0SS+IxG7Rxzda2EVvyBZbvFPBCjJoyHuE0P//7OAsN23GItzDRdWa6ALxZI/8R5ygK7jAR6t028/z+7295g==",
+      "version": "4.0.5",
+      "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.0.5.tgz",
+      "integrity": "sha512-sNjbT9dX63nqUFIOv95tTVm6elyIU4RvB1m8dOeZt+IgWwcWklFDOdmGcfo3zSiRsnR/3pJkjY5lfoGqEe4Eig==",
       "dev": true,
       "requires": {
         "@types/component-emitter": "^1.2.10",
@@ -23642,14 +23677,15 @@
       }
     },
     "terser": {
-      "version": "5.7.1",
-      "resolved": "https://registry.npmjs.org/terser/-/terser-5.7.1.tgz",
-      "integrity": "sha512-b3e+d5JbHAe/JSjwsC3Zn55wsBIM7AsHLjKxT31kGCldgbpFePaFo+PiddtO6uwRZWRw7sPXmAN8dTW61xmnSg==",
+      "version": "5.15.1",
+      "resolved": "https://registry.npmjs.org/terser/-/terser-5.15.1.tgz",
+      "integrity": "sha512-K1faMUvpm/FBxjBXud0LWVAGxmvoPbZbfTCYbSgaaYQaIXI3/TdI7a7ZGA73Zrou6Q8Zmz3oeUTsp/dj+ag2Xw==",
       "dev": true,
       "requires": {
+        "@jridgewell/source-map": "^0.3.2",
+        "acorn": "^8.5.0",
         "commander": "^2.20.0",
-        "source-map": "~0.7.2",
-        "source-map-support": "~0.5.19"
+        "source-map-support": "~0.5.20"
       },
       "dependencies": {
         "commander": {
@@ -23657,6 +23693,22 @@
           "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
           "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
           "dev": true
+        },
+        "source-map": {
+          "version": "0.6.1",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+          "dev": true
+        },
+        "source-map-support": {
+          "version": "0.5.21",
+          "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
+          "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
+          "dev": true,
+          "requires": {
+            "buffer-from": "^1.0.0",
+            "source-map": "^0.6.0"
+          }
         }
       }
     },
diff --git a/src/api/service.ts b/src/api/service.ts
index 67269b96039a13ff4f246fea991a7b8adecdba8a..89a5f262aef9a15a03b795cc380e4286c3f0acc3 100644
--- a/src/api/service.ts
+++ b/src/api/service.ts
@@ -140,6 +140,7 @@ export type BroadCastingApiEvents = {
   parcellationSelected: SapiParcellationModel
   allRegions: SapiRegionModel[]
   regionsSelected: SapiRegionModel[]
+  navigation: MainState['[state.atlasSelection]']['navigation']
 }
 
 const broadCastDefault: BroadCastingApiEvents = {
@@ -148,6 +149,7 @@ const broadCastDefault: BroadCastingApiEvents = {
   parcellationSelected: null,
   allRegions: [],
   regionsSelected: [],
+  navigation: null,
 }
 
 @Injectable({
@@ -269,6 +271,11 @@ export class ApiService implements BoothResponder<ApiBoothEvents>{
     ).subscribe(regions => {
       this.broadcastCh.emit('allRegions', regions)
     })
+    this.store.pipe(
+      select(atlasSelection.selectors.navigation)
+    ).subscribe(navigation => {
+      this.broadcastCh.emit('navigation', navigation)
+    })
   }
   async onRequest(event: JRPCRequest<keyof ApiBoothEvents, unknown>): Promise<void | JRPCResp<ApiBoothEvents[keyof ApiBoothEvents]['response'], string>> {
     /**
diff --git a/src/dragDropFile/dragDrop.directive.ts b/src/dragDropFile/dragDrop.directive.ts
index 99e82c0c23b1cfbf957e74f872e37e7f3485a847..abca56ad261aa39bf58f27768134608038bc26da 100644
--- a/src/dragDropFile/dragDrop.directive.ts
+++ b/src/dragDropFile/dragDrop.directive.ts
@@ -1,14 +1,14 @@
-import { Directive, ElementRef, EventEmitter, HostBinding, HostListener, Input, OnDestroy, OnInit, Output } from "@angular/core";
+import { ChangeDetectorRef, Directive, ElementRef, EventEmitter, HostBinding, HostListener, Input, OnDestroy, Output } from "@angular/core";
 import { fromEvent, merge, Observable, of, Subscription } from "rxjs";
-import { debounceTime, map, scan, switchMap } from "rxjs/operators";
-import {MatSnackBar, MatSnackBarRef, SimpleSnackBar} from "@angular/material/snack-bar";
+import { debounceTime, distinctUntilChanged, map, scan, switchMap } from "rxjs/operators";
+import { MatSnackBar, MatSnackBarRef, SimpleSnackBar } from "@angular/material/snack-bar";
 
 @Directive({
   selector: '[drag-drop-file]',
   exportAs: 'dragDropFile'
 })
 
-export class DragDropFileDirective implements OnInit, OnDestroy {
+export class DragDropFileDirective implements OnDestroy {
 
   @Input()
   public snackText: string
@@ -20,7 +20,15 @@ export class DragDropFileDirective implements OnInit, OnDestroy {
   public transition = `opacity 300ms ease-in`
 
   @HostBinding('style.opacity')
-  public opacity = null
+  public hostOpacity = null
+
+  get opacity() {
+    return this.hostOpacity
+  }
+  set opacity(val: number) {
+    this.hostOpacity = val
+    this.cdr.markForCheck()
+  }
 
   public snackbarRef: MatSnackBarRef<SimpleSnackBar>
 
@@ -49,37 +57,13 @@ export class DragDropFileDirective implements OnInit, OnDestroy {
 
   private subscriptions: Subscription[] = []
 
-  public ngOnInit() {
-    this.subscriptions.push(
-      this.dragover$.pipe(
-        debounceTime(16),
-      ).subscribe(flag => {
-        if (flag) {
-          this.snackbarRef = this.snackBar.open(this.snackText || `Drop file(s) here.`, 'Dismiss')
-
-          /**
-           * In buggy scenarios, user could at least dismiss by action
-           */
-          this.snackbarRef.afterDismissed().subscribe(reason => {
-            if (reason.dismissedByAction) {
-              this.reset()
-            }
-          })
-          this.opacity = 0.2
-        } else {
-          this.reset()
-        }
-      }),
-    )
-  }
-
   public ngOnDestroy() {
     while (this.subscriptions.length > 0) {
       this.subscriptions.pop().unsubscribe()
     }
   }
 
-  constructor(private snackBar: MatSnackBar, private el: ElementRef) {
+  constructor(private snackBar: MatSnackBar, private el: ElementRef, private cdr: ChangeDetectorRef) {
     this.dragover$ = merge(
       of(null),
       fromEvent(this.el.nativeElement, 'drop'),
@@ -96,5 +80,33 @@ export class DragDropFileDirective implements OnInit, OnDestroy {
         map(val => val > 0),
       )),
     )
+
+    this.subscriptions.push(
+      this.dragover$.pipe(
+        debounceTime(16),
+        distinctUntilChanged(),
+      ).subscribe(flag => {
+        if (flag) {
+          this.snackbarRef = this.snackBar.open(
+            this.snackText || `Drop file(s) here.`, 'Dismiss',
+            {
+              panelClass: 'sxplr-pe-none'
+            }
+          )
+
+          /**
+           * In buggy scenarios, user could at least dismiss by action
+           */
+          this.snackbarRef.afterDismissed().subscribe(reason => {
+            if (reason.dismissedByAction) {
+              this.reset()
+            }
+          })
+          this.opacity = 0.2
+        } else {
+          this.reset()
+        }
+      }),
+    )
   }
 }
diff --git a/src/extra_styles.css b/src/extra_styles.css
index 643ab1e507c31fc6e833ca777748a16714e83982..913f83b9dac50b67b5a00387c726933aeb1ed583 100644
--- a/src/extra_styles.css
+++ b/src/extra_styles.css
@@ -427,6 +427,11 @@ markdown-dom p
   height:20em!important;
 }
 
+.overflow-hidden
+{
+  overflow: hidden!important;
+}
+
 .overflow-x-auto
 {
   overflow-x: auto;
@@ -876,3 +881,10 @@ how-to-cite img
 {
   max-width: 100vw;
 }
+
+/* this is required to set snackbar to be none-interactive */
+/* ignore css lint error, they don't know what they are talking about */
+.cdk-overlay-pane:has(> .sxplr-pe-none)
+{
+  pointer-events: none;
+}
diff --git a/src/index.html b/src/index.html
index 3a856105768123945f81f4837560f75d0bdf8f46..763f059da834646019a8679113757031d3383804 100644
--- a/src/index.html
+++ b/src/index.html
@@ -15,7 +15,7 @@
   <script src="https://unpkg.com/kg-dataset-previewer@1.2.0/dist/kg-dataset-previewer/kg-dataset-previewer.js" defer></script>
   <script src="https://unpkg.com/three-surfer@0.0.11/dist/bundle.js" defer></script>
   <script type="module" src="https://unpkg.com/ng-layer-tune@0.0.6/dist/ng-layer-tune/ng-layer-tune.esm.js"></script>
-  <script type="module" src="https://unpkg.com/hbp-connectivity-component@0.6.2/dist/connectivity-component/connectivity-component.js" ></script>
+  <script type="module" src="https://unpkg.com/hbp-connectivity-component@0.6.5/dist/connectivity-component/connectivity-component.js" ></script>
   <script defer src="https://unpkg.com/mathjax@3.1.2/es5/tex-svg.js"></script>
   <script defer src="https://unpkg.com/d3@6.2.0/dist/d3.min.js"></script>
   <title>Siibra Explorer</title>
diff --git a/src/main.module.ts b/src/main.module.ts
index da570799012cb86e814b3760f110174c943f8f36..b681764f400aa4f8fabea3a4544a3ca03b64dc9a 100644
--- a/src/main.module.ts
+++ b/src/main.module.ts
@@ -36,7 +36,6 @@ import { MessagingGlue } from './messagingGlue';
 import { QuickTourModule } from './ui/quickTour';
 import { of } from 'rxjs';
 import { CANCELLABLE_DIALOG, CANCELLABLE_DIALOG_OPTS } from './util/interfaces';
-import { environment } from 'src/environments/environment' 
 import { NotSupportedCmp } from './notSupportedCmp/notSupported.component';
 import {
   atlasSelection,
diff --git a/src/util/fn.spec.ts b/src/util/fn.spec.ts
index efd5e418d29f6d46df2442bb8d02cb1a63b14840..faec974673835d984923e5b61960592cfc188f03 100644
--- a/src/util/fn.spec.ts
+++ b/src/util/fn.spec.ts
@@ -1,9 +1,8 @@
 import { fakeAsync, tick } from '@angular/core/testing'
-import {} from 'jasmine'
 import { hot } from 'jasmine-marbles'
 import { Observable, of } from 'rxjs'
 import { switchMap } from 'rxjs/operators'
-import { switchMapWaitFor, bufferUntil } from './fn'
+import { switchMapWaitFor, bufferUntil, arrayOfPrimitiveEqual } from './fn'
 
 describe(`> util/fn.ts`, () => {
 
@@ -81,4 +80,51 @@ describe(`> util/fn.ts`, () => {
       )
     })
   })
+
+  describe("> #arrayOfPrimitiveEqual", () => {
+
+    const primitives: {text: string, examples: (string|number)[][]}[] = [{
+      text: 'string',
+      examples: [
+        ['foo', 'bar'], 
+        ['foo', 'bar'], 
+        ['buzz', 'boo'], 
+        ['hello'], 
+      ]
+    }, {
+      text: 'number',
+      examples: [
+        [0, 1],
+        [0, 1],
+        [-1, -2],
+        [1, 3, 4],
+      ]
+    }]
+
+    for (const { text, examples } of primitives) {
+      describe(`> for ${text}`, () => {
+
+        describe("> when elements length unequal", () => {
+          it("> returns false", () => {
+            expect(arrayOfPrimitiveEqual(examples[0], examples[3])).toBeFalse()
+            expect(arrayOfPrimitiveEqual(examples[3], examples[0])).toBeFalse()
+          })
+        })
+
+        describe("> when element element unequal", () => {
+          it("> returns false", () => {
+            expect(arrayOfPrimitiveEqual(examples[0], examples[2])).toBeFalse()
+            expect(arrayOfPrimitiveEqual(examples[2], examples[0])).toBeFalse()
+          })
+        })
+
+        describe("> when elementwise equal", () => {
+          it("> returns true", () => {
+            expect(arrayOfPrimitiveEqual(examples[0], examples[1])).toBeTrue()
+            expect(arrayOfPrimitiveEqual(examples[1], examples[0])).toBeTrue()
+          })
+        })
+      })
+    }
+  })
 })
diff --git a/src/util/fn.ts b/src/util/fn.ts
index e5ef8ac6bde4b72b67c2fb76f7b94edde8123476..b74bf3b0ede872912da6a3bd4ac78a0708ccb1e6 100644
--- a/src/util/fn.ts
+++ b/src/util/fn.ts
@@ -45,10 +45,9 @@ export function getUuid(){
 
 type TPrimitive = string | number
 
-const include = <T extends TPrimitive>(el: T, arr: T[]) => arr.indexOf(el) >= 0
 export const arrayOfPrimitiveEqual = <T extends TPrimitive>(o: T[], n: T[]) =>
-  o.every(el => include(el, n))
-  && n.every(el => include(el, o))
+  o.length === n.length &&
+  o.every((el, idx) => n[idx] === el)
 
 interface ISwitchMapWaitFor {
   interval?: number
diff --git a/src/viewerModule/nehuba/layoutOverlay/nehuba.layoutOverlay/nehuba.layoutOverlay.template.html b/src/viewerModule/nehuba/layoutOverlay/nehuba.layoutOverlay/nehuba.layoutOverlay.template.html
index 245fb9f07ed2da09550b1bc63a6f1d9497a924cb..e43354b855f1e5ef945172019993701c1b6e8fa3 100644
--- a/src/viewerModule/nehuba/layoutOverlay/nehuba.layoutOverlay/nehuba.layoutOverlay.template.html
+++ b/src/viewerModule/nehuba/layoutOverlay/nehuba.layoutOverlay/nehuba.layoutOverlay.template.html
@@ -128,7 +128,7 @@
 <!-- viewer ctrl -->
 <mat-menu #viewerCtrlMenu>
   <viewer-ctrl-component
-    class="d-block m-2 ml-3 mr-3"
+    class="d-block m-2 ml-3 mr-3 sxplr-custom-cmp"
     (click)="$event.stopPropagation()">
   </viewer-ctrl-component>
 </mat-menu>
diff --git a/src/viewerModule/nehuba/module.ts b/src/viewerModule/nehuba/module.ts
index 087c53efda843dfa3eb33112d666fbc6746af4f6..c9666e5aa1878c27d553ebf9ce15ef2aa836863d 100644
--- a/src/viewerModule/nehuba/module.ts
+++ b/src/viewerModule/nehuba/module.ts
@@ -28,6 +28,7 @@ import { MeshEffects } from "./mesh.effects/mesh.effects";
 import { NehubaLayoutOverlayModule } from "./layoutOverlay";
 import { NgAnnotationService } from "./annotation/service";
 import { NgAnnotationEffects } from "./annotation/effects";
+import { NehubaViewerContainer } from "./nehubaViewerInterface/nehubaViewerContainer.component";
 
 @NgModule({
   imports: [
@@ -66,6 +67,7 @@ import { NgAnnotationEffects } from "./annotation/effects";
     NehubaGlueCmp,
     StatusCardComponent,
     NgLayerCtrlCmp,
+    NehubaViewerContainer,
   ],
   exports: [
     NehubaViewerUnit,
diff --git a/src/viewerModule/nehuba/navigation.service/navigation.effects.ts b/src/viewerModule/nehuba/navigation.service/navigation.effects.ts
index ae3c4d4e977b6190f2303bc8d2b00ccf72fd3084..fd615fb7e25ba2141e534a71b836b2d923ff9753 100644
--- a/src/viewerModule/nehuba/navigation.service/navigation.effects.ts
+++ b/src/viewerModule/nehuba/navigation.service/navigation.effects.ts
@@ -73,7 +73,7 @@ export class NehubaNavigationEffects implements OnDestroy{
         const n = navAdd(src, navMul(delta, d))
         this.nehubaInst.setNavigationState({
           ...n,
-          positionReal: true
+          positionReal: physical
         })
 
         if ( !next.done ) {
diff --git a/src/viewerModule/nehuba/nehubaViewerGlue/nehubaViewerGlue.component.ts b/src/viewerModule/nehuba/nehubaViewerGlue/nehubaViewerGlue.component.ts
index 5c16b0a065f1f5b2d14be81d724230ed30b7b301..88d05fbee161a4f871b51c72c8b92e586a4f3f0a 100644
--- a/src/viewerModule/nehuba/nehubaViewerGlue/nehubaViewerGlue.component.ts
+++ b/src/viewerModule/nehuba/nehubaViewerGlue/nehubaViewerGlue.component.ts
@@ -1,15 +1,12 @@
-import { AfterViewInit, ChangeDetectionStrategy, Component, EventEmitter, Inject, OnDestroy, Optional, Output, TemplateRef, ViewChild } from "@angular/core";
+import { ChangeDetectionStrategy, Component, EventEmitter, Inject, OnDestroy, Optional, Output, TemplateRef, ViewChild } from "@angular/core";
 import { select, Store } from "@ngrx/store";
-import { Subscription } from "rxjs";
 import { ClickInterceptor, CLICK_INTERCEPTOR_INJECTOR } from "src/util";
-import { distinctUntilChanged, startWith } from "rxjs/operators";
-import { ARIA_LABELS } from 'common/constants'
-import { EnumViewerEvt, IViewer, TViewerEvent } from "../../viewer.interface";
-import { NehubaViewerContainerDirective, TMouseoverEvent } from "../nehubaViewerInterface/nehubaViewerInterface.directive";
+import { distinctUntilChanged } from "rxjs/operators";
+import { ARIA_LABELS, CONST } from 'common/constants'
+import { IViewer, TViewerEvent } from "../../viewer.interface";
 import { NehubaMeshService } from "../mesh.service";
 import { NehubaLayerControlService, SET_COLORMAP_OBS, SET_LAYER_VISIBILITY } from "../layerCtrl.service";
 import { getExportNehuba, getUuid } from "src/util/fn";
-import { INavObj } from "../navigation.service";
 import { NG_LAYER_CONTROL, SET_SEGMENT_VISIBILITY } from "../layerCtrl.service/layerCtrl.util";
 import { MatSnackBar } from "@angular/material/snack-bar";
 import { getShader } from "src/util/constants";
@@ -17,12 +14,12 @@ import { EnumColorMapName } from "src/util/colorMaps";
 import { MatDialog } from "@angular/material/dialog";
 import { AtlasWorkerService } from "src/atlasViewer/atlasViewer.workerService.service";
 import { SapiRegionModel } from "src/atlasComponents/sapi";
-import { NehubaConfig, getParcNgId, getRegionLabelIndex } from "../config.service";
+import { NehubaConfig } from "../config.service";
 import { SET_MESHES_TO_LOAD } from "../constants";
-import { annotation, atlasAppearance, atlasSelection, userInteraction } from "src/state";
+import { atlasAppearance, atlasSelection, userInteraction } from "src/state";
 import { linearTransform, TVALID_LINEAR_XFORM_DST, TVALID_LINEAR_XFORM_SRC } from "src/atlasComponents/sapi/core/space/interspaceLinearXform";
 
-export const INVALID_FILE_INPUT = `Exactly one (1) nifti file is required!`
+export const INVALID_FILE_INPUT = `Exactly one (1) file is required!`
 
 @Component({
   selector: 'iav-cmp-viewer-nehuba-glue',
@@ -64,119 +61,23 @@ export const INVALID_FILE_INPUT = `Exactly one (1) nifti file is required!`
   changeDetection: ChangeDetectionStrategy.OnPush
 })
 
-export class NehubaGlueCmp implements IViewer<'nehuba'>, OnDestroy, AfterViewInit {
+export class NehubaGlueCmp implements IViewer<'nehuba'>, OnDestroy {
 
-  @ViewChild('layerCtrlTmpl', { read: TemplateRef }) layerCtrlTmpl: TemplateRef<any>
+  @ViewChild('layerCtrlTmpl', { static: true })
+  layerCtrlTmpl: TemplateRef<any>
 
   public ARIA_LABELS = ARIA_LABELS
-
-  @ViewChild(NehubaViewerContainerDirective, { static: true })
-  public nehubaContainerDirective: NehubaViewerContainerDirective
+  public CONST = CONST
 
   private onhoverSegments: SapiRegionModel[] = []
   private onDestroyCb: (() => void)[] = []
-  private multiNgIdsRegionsLabelIndexMap = new Map<string, Map<number, SapiRegionModel>>()
 
   public nehubaConfig: NehubaConfig
 
-  public customLandmarks$ = this.store$.pipe(
-    select(annotation.selectors.annotations),
-  )
-
-  private nehubaContainerSub: Subscription[] = []
-  private setupNehubaEvRelay() {
-    while (this.nehubaContainerSub.length > 0) this.nehubaContainerSub.pop().unsubscribe()
-    
-    if (!this.nehubaContainerDirective) return
-    const {
-      mouseOverSegments,
-      navigationEmitter,
-      mousePosEmitter,
-    } = this.nehubaContainerDirective
-
-    this.nehubaContainerSub.push(
-
-      mouseOverSegments.pipe(
-        startWith(null as TMouseoverEvent[])
-      ).subscribe(seg => {
-        this.viewerEvent.emit({
-          type: EnumViewerEvt.VIEWER_CTX,
-          data: {
-            viewerType: 'nehuba',
-            payload: {
-              nehuba: seg && seg.map(v => {
-                return {
-                  layerName: v.layer.name,
-                  labelIndices: [ Number(v.segmentId) ],
-                  regions: (() => {
-                    const map = this.multiNgIdsRegionsLabelIndexMap.get(v.layer.name)
-                    if (!map) return []
-                    return [map.get(Number(v.segmentId))]
-                  })()
-                }
-              })
-            }
-          }
-        })
-      }),
-
-      navigationEmitter.pipe(
-        startWith(null as INavObj)
-      ).subscribe(nav => {
-        this.viewerEvent.emit({
-          type: EnumViewerEvt.VIEWER_CTX,
-          data: {
-            viewerType: 'nehuba',
-            payload: {
-              nav
-            }
-          }
-        })
-      }),
-
-      mousePosEmitter.pipe(
-        startWith(null as {
-          voxel: number[]
-          real: number[]
-        })
-      ).subscribe(mouse => {
-        this.viewerEvent.emit({
-          type: EnumViewerEvt.VIEWER_CTX,
-          data: {
-            viewerType: 'nehuba',
-            payload: {
-              mouse
-            }
-          }
-        })
-      })
-    )
-
-    this.onDestroyCb.push(
-      () => {
-        if (this.nehubaContainerSub) {
-          while(this.nehubaContainerSub.length > 0) this.nehubaContainerSub.pop().unsubscribe()
-        }
-      }
-    )
-  }
-
-  ngAfterViewInit(): void {
-    this.setupNehubaEvRelay()
-  }
-
   ngOnDestroy(): void {
     while (this.onDestroyCb.length) this.onDestroyCb.pop()()
   }
 
-
-  private disposeViewer() {
-    /**
-     * clear existing container
-     */
-    this.nehubaContainerDirective && this.nehubaContainerDirective.clear()
-  }
-
   @Output()
   public viewerEvent = new EventEmitter<TViewerEvent<'nehuba'>>()
 
@@ -185,7 +86,6 @@ export class NehubaGlueCmp implements IViewer<'nehuba'>, OnDestroy, AfterViewIni
     private snackbar: MatSnackBar,
     private dialog: MatDialog,
     private worker: AtlasWorkerService,
-    private layerCtrlService: NehubaLayerControlService,
     @Optional() @Inject(CLICK_INTERCEPTOR_INJECTOR) clickInterceptor: ClickInterceptor,
   ){
 
@@ -199,29 +99,6 @@ export class NehubaGlueCmp implements IViewer<'nehuba'>, OnDestroy, AfterViewIni
       this.onDestroyCb.push(() => deregister(selOnhoverRegion))
     }
 
-    const onATPClear = this.store$.pipe(
-      atlasSelection.fromRootStore.distinctATP()
-    ).subscribe(this.disposeViewer.bind(this))
-    this.onDestroyCb.push(() => onATPClear.unsubscribe())
-    
-    /**
-     * subscribe to ngIdtolblIdxToRegion
-     */
-    const ngIdSub = this.layerCtrlService.selectedATPR$.subscribe(({ atlas, parcellation, template, regions }) => {
-      this.multiNgIdsRegionsLabelIndexMap.clear()
-      for (const r of regions) {
-        const ngId = getParcNgId(atlas, template, parcellation, r)
-        if (!ngId) continue
-        if (!this.multiNgIdsRegionsLabelIndexMap.has(ngId)) {
-          this.multiNgIdsRegionsLabelIndexMap.set(ngId, new Map())
-        }
-        const labelIndex = getRegionLabelIndex(atlas, template, parcellation, r)
-        if (!labelIndex) continue
-        this.multiNgIdsRegionsLabelIndexMap.get(ngId).set(labelIndex, r)
-      }
-    })
-    this.onDestroyCb.push(() => ngIdSub.unsubscribe())
-
     /**
      * on hover segment
      */
@@ -234,14 +111,6 @@ export class NehubaGlueCmp implements IViewer<'nehuba'>, OnDestroy, AfterViewIni
     this.onDestroyCb.push(() => onhovSegSub.unsubscribe())
   }
 
-
-  handleViewerLoadedEvent(flag: boolean): void {
-    this.viewerEvent.emit({
-      type: EnumViewerEvt.VIEWERLOADED,
-      data: flag
-    })
-  }
-
   private selectHoveredRegion(_ev: any): boolean{
     /**
      * If label indicies are not defined by the ontology, it will be a string in the format of `{ngId}#{labelIndex}`
diff --git a/src/viewerModule/nehuba/nehubaViewerGlue/nehubaViewerGlue.template.html b/src/viewerModule/nehuba/nehubaViewerGlue/nehubaViewerGlue.template.html
index 1b24745daa5b9d1234601f736888a472fa7a4705..595ee6a14bd31629df752a60b92f3dc858b4c82a 100644
--- a/src/viewerModule/nehuba/nehubaViewerGlue/nehubaViewerGlue.template.html
+++ b/src/viewerModule/nehuba/nehubaViewerGlue/nehubaViewerGlue.template.html
@@ -1,14 +1,14 @@
 <div class="nehuba-viewer-container-parent"
   iav-viewer-touch-interface
   (touchmove)="$event.preventDefault()"
+  [snackText]="CONST.NEHUBA_DRAG_DROP_TEXT"
   (drag-drop-file)="handleFileDrop($event)">
 
-  <div class="sxplr-d-block"
-    iav-nehuba-viewer-container
-    #iavContainer="iavNehubaViewerContainer"
-    (iavNehubaViewerContainerViewerLoading)="handleViewerLoadedEvent($event)">
+  <sxplr-nehuba-viewer-container
+    class="sxplr-w-100 sxplr-h-100 sxplr-d-block"
+    (viewerEvent)="viewerEvent.emit($event)">
+  </sxplr-nehuba-viewer-container>
 
-  </div>
 </div>
 
 <nehuba-layout-overlay></nehuba-layout-overlay>
diff --git a/src/viewerModule/nehuba/nehubaViewerInterface/nehubaViewerContainer.component.ts b/src/viewerModule/nehuba/nehubaViewerInterface/nehubaViewerContainer.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f4ad7e41191010356daec181ad362ce655cc661c
--- /dev/null
+++ b/src/viewerModule/nehuba/nehubaViewerInterface/nehubaViewerContainer.component.ts
@@ -0,0 +1,139 @@
+import { AfterViewInit, Component, EventEmitter, OnDestroy, Output, ViewChild } from "@angular/core";
+import { concat, Observable, of, Subscription } from "rxjs";
+import { map, withLatestFrom } from "rxjs/operators";
+import { SapiRegionModel } from "src/atlasComponents/sapi";
+import { EnumViewerEvt, TViewerEvent } from "../../viewer.interface";
+import { NehubaLayerControlService } from "../layerCtrl.service";
+import { NehubaViewerContainerDirective } from "./nehubaViewerInterface.directive";
+import { getParcNgId, getRegionLabelIndex } from "../config.service";
+import { Store } from "@ngrx/store";
+import { atlasSelection } from "src/state";
+
+@Component({
+  selector: `sxplr-nehuba-viewer-container`,
+  templateUrl: `./nehubaViewerContainer.template.html`,
+  styleUrls: [`./nehubaViewerContainer.style.css`]
+})
+
+export class NehubaViewerContainer implements AfterViewInit, OnDestroy {
+
+  handleViewerLoadedEvent(flag: boolean) {
+    this.viewerEvent.emit({
+      type: EnumViewerEvt.VIEWERLOADED,
+      data: flag
+    })
+  }
+
+  @Output()
+  viewerEvent = new EventEmitter<TViewerEvent<'nehuba'>>()
+
+  ngAfterViewInit(): void {
+    if (!this.nehubaContainerDirective) {
+      console.warn('cannot setup nehubaContainerDirective hooks')
+      return
+    }
+
+    const {
+      mouseOverSegments,
+      navigationEmitter,
+      mousePosEmitter,
+    } = this.nehubaContainerDirective
+
+    this.subscriptions.push(
+      this.store.pipe(
+        atlasSelection.fromRootStore.distinctATP()
+      ).subscribe(() => {
+        this.nehubaContainerDirective.clear()
+      }),
+
+      concat(
+        of(null),
+        mouseOverSegments
+      ).pipe(
+        withLatestFrom(
+          this.multiNgIdsRegionsLabelMap$
+        )
+      ).subscribe(([seg, multiNgIdsRegionsLabelIndexMap]) => {
+        this.viewerEvent.emit({
+          type: EnumViewerEvt.VIEWER_CTX,
+          data: {
+            viewerType: 'nehuba',
+            payload: {
+              nehuba: seg && seg.map(v => {
+                return {
+                  layerName: v.layer.name,
+                  labelIndices: [ Number(v.segmentId) ],
+                  regions: (() => {
+                    const map = multiNgIdsRegionsLabelIndexMap.get(v.layer.name)
+                    if (!map) return []
+                    return [map.get(Number(v.segmentId))]
+                  })()
+                }
+              })
+            }
+          }
+        })
+      }),
+
+      concat(
+        of(null),
+        navigationEmitter,
+      ).subscribe(nav => {
+        this.viewerEvent.emit({
+          type: EnumViewerEvt.VIEWER_CTX,
+          data: {
+            viewerType: 'nehuba',
+            payload: {
+              nav
+            }
+          }
+        })
+      }),
+
+      concat(
+        of(null),
+        mousePosEmitter,
+      ).subscribe(mouse => {
+        this.viewerEvent.emit({
+          type: EnumViewerEvt.VIEWER_CTX,
+          data: {
+            viewerType: 'nehuba',
+            payload: {
+              mouse
+            }
+          }
+        })
+      })
+    )
+
+  }
+
+  ngOnDestroy(): void {
+    while (this.subscriptions.length) this.subscriptions.pop().unsubscribe()
+  }
+
+  constructor(private store: Store, private layerCtrlService: NehubaLayerControlService) {}
+
+  @ViewChild(NehubaViewerContainerDirective, { static: true })
+  private nehubaContainerDirective: NehubaViewerContainerDirective
+
+  private multiNgIdsRegionsLabelMap$: Observable<Map<string, Map<number, SapiRegionModel>>> = this.layerCtrlService.selectedATPR$.pipe(
+    map(( { atlas, parcellation, template, regions } ) => {
+      
+      const retMap = new Map<string, Map<number, SapiRegionModel>>()
+      for (const r of regions) {
+        const ngId = getParcNgId(atlas, template, parcellation, r)
+        if (!ngId) continue
+        if (!retMap.has(ngId)) {
+          retMap.set(ngId, new Map())
+        }
+        const labelIndex = getRegionLabelIndex(atlas, template, parcellation, r)
+        if (!labelIndex) continue
+        retMap.get(ngId).set(labelIndex, r)
+      }
+      return retMap
+    })
+  )
+
+  private subscriptions: Subscription[] = []
+}
diff --git a/src/viewerModule/nehuba/viewerCtrl/change-perspective-orientation/changePerspectiveOrientation.component.sass b/src/viewerModule/nehuba/nehubaViewerInterface/nehubaViewerContainer.style.css
similarity index 100%
rename from src/viewerModule/nehuba/viewerCtrl/change-perspective-orientation/changePerspectiveOrientation.component.sass
rename to src/viewerModule/nehuba/nehubaViewerInterface/nehubaViewerContainer.style.css
diff --git a/src/viewerModule/nehuba/nehubaViewerInterface/nehubaViewerContainer.template.html b/src/viewerModule/nehuba/nehubaViewerInterface/nehubaViewerContainer.template.html
new file mode 100644
index 0000000000000000000000000000000000000000..da71f827a9fc330845256754521fe98fefcb5fc0
--- /dev/null
+++ b/src/viewerModule/nehuba/nehubaViewerInterface/nehubaViewerContainer.template.html
@@ -0,0 +1,6 @@
+<div
+  class="sxplr-d-block"
+  iav-nehuba-viewer-container
+  #iavContainer="iavNehubaViewerContainer"
+  (iavNehubaViewerContainerViewerLoading)="handleViewerLoadedEvent($event)">
+</div>
\ No newline at end of file
diff --git a/src/viewerModule/nehuba/viewerCtrl/change-perspective-orientation/changePerspectiveOrientation.component.html b/src/viewerModule/nehuba/viewerCtrl/change-perspective-orientation/changePerspectiveOrientation.component.html
deleted file mode 100644
index 4aa94fa5d1bce357ba7caba1c6a1b3f901cdc30c..0000000000000000000000000000000000000000
--- a/src/viewerModule/nehuba/viewerCtrl/change-perspective-orientation/changePerspectiveOrientation.component.html
+++ /dev/null
@@ -1,40 +0,0 @@
-<button mat-menu-item [mat-menu-trigger-for]="perspectiveOrientationMenu">
-    Change orientation to
-</button>
-
-<mat-menu #perspectiveOrientationMenu="matMenu">
-
-    <div class="d-flex align-items-center sxplr-custom-cmp text">
-        <button mat-button color="basic" class="flex-grow-1 text-left font-weight-normal"
-                (click)="set3DViewPoint('coronal', 'first')">
-            Coronal view
-        </button>
-        <button class="flex-grow-0" mat-button
-                (click)="set3DViewPoint('coronal', 'second')">
-            <i class="fas fa-arrows-alt-h"></i>
-        </button>
-    </div>
-
-    <div class="d-flex align-items-center sxplr-custom-cmp text"> <!--mat-menu-item-->
-        <button mat-button color="basic" class="flex-grow-1 text-left font-weight-normal"
-                (click)="set3DViewPoint('sagittal', 'first')">
-            Sagittal view
-        </button>
-        <button class="flex-grow-0" mat-button
-                (click)="set3DViewPoint('sagittal', 'second')">
-            <i class="fas fa-arrows-alt-h"></i>
-        </button>
-    </div>
-
-    <div class="d-flex align-items-center sxplr-custom-cmp text"> <!--mat-menu-item-->
-        <button mat-button color="basic" class="flex-grow-1 text-left font-weight-normal"
-                (click)="set3DViewPoint('axial', 'first')">
-            Axial view
-        </button>
-        <button class="flex-grow-0" mat-button
-                (click)="set3DViewPoint('axial', 'second')">
-            <i class="fas fa-arrows-alt-h"></i>
-        </button>
-    </div>
-
-</mat-menu>
diff --git a/src/viewerModule/nehuba/viewerCtrl/change-perspective-orientation/changePerspectiveOrientation.component.ts b/src/viewerModule/nehuba/viewerCtrl/change-perspective-orientation/changePerspectiveOrientation.component.ts
deleted file mode 100644
index 9f9d10f7b6467a186111d749e22b17dbebeb3129..0000000000000000000000000000000000000000
--- a/src/viewerModule/nehuba/viewerCtrl/change-perspective-orientation/changePerspectiveOrientation.component.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-import { Component } from '@angular/core';
-import {Store} from "@ngrx/store";
-import { actions } from 'src/state/atlasSelection';
-
-@Component({
-  selector: 'app-change-perspective-orientation',
-  templateUrl: './changePerspectiveOrientation.component.html',
-  styleUrls: ['./changePerspectiveOrientation.component.sass']
-})
-export class ChangePerspectiveOrientationComponent {
-
-  private viewOrientations = {
-    coronal: [[0,-1,1,0], [-1,0,0,1]],
-    sagittal: [[-1,-1,1,1], [-1,1,-1,1]],
-    axial: [[0,0,1,0], [1,0,0,0]]
-  }
-
-  constructor(private store$: Store<any>,) { }
-
-  public set3DViewPoint(plane: 'coronal' | 'sagittal' | 'axial', view: 'first' | 'second') {
-
-    const orientation = this.viewOrientations[plane][view === 'first'? 0 : 1]
-
-    this.store$.dispatch(
-      actions.navigateTo({
-        navigation: {
-          perspectiveOrientation: orientation,
-        },
-        animation: true
-      })
-    )
-  }
-
-}
diff --git a/src/viewerModule/nehuba/viewerCtrl/module.ts b/src/viewerModule/nehuba/viewerCtrl/module.ts
index 7be1186474bddac9d4c33772d28fb682bfa61794..4052de0ac81de5cc6dd9effc75163429de938b4b 100644
--- a/src/viewerModule/nehuba/viewerCtrl/module.ts
+++ b/src/viewerModule/nehuba/viewerCtrl/module.ts
@@ -5,7 +5,7 @@ import { ComponentsModule } from "src/components";
 import { AngularMaterialModule } from "src/sharedModules";
 import { UtilModule } from "src/util";
 import { ViewerCtrlCmp } from "./viewerCtrlCmp/viewerCtrlCmp.component";
-import {ChangePerspectiveOrientationComponent} from "src/viewerModule/nehuba/viewerCtrl/change-perspective-orientation/changePerspectiveOrientation.component";
+import { SnapPerspectiveOrientationCmp } from "src/viewerModule/nehuba/viewerCtrl/snapPerspectiveOrientation/snapPerspectiveOrientation.component";
 
 @NgModule({
   imports: [
@@ -18,7 +18,7 @@ import {ChangePerspectiveOrientationComponent} from "src/viewerModule/nehuba/vie
   ],
   declarations: [
     ViewerCtrlCmp,
-    ChangePerspectiveOrientationComponent
+    SnapPerspectiveOrientationCmp
   ],
   exports: [
     ViewerCtrlCmp
diff --git a/src/viewerModule/nehuba/viewerCtrl/change-perspective-orientation/changePerspectiveOrientation.component.spec.ts b/src/viewerModule/nehuba/viewerCtrl/snapPerspectiveOrientation/snapPerspectiveOrientation.component.spec.ts
similarity index 61%
rename from src/viewerModule/nehuba/viewerCtrl/change-perspective-orientation/changePerspectiveOrientation.component.spec.ts
rename to src/viewerModule/nehuba/viewerCtrl/snapPerspectiveOrientation/snapPerspectiveOrientation.component.spec.ts
index 48c4d290030e11728232a182bf7aa200131b8876..cf325802c6c041e498e0925f9320fb1dfd41298a 100644
--- a/src/viewerModule/nehuba/viewerCtrl/change-perspective-orientation/changePerspectiveOrientation.component.spec.ts
+++ b/src/viewerModule/nehuba/viewerCtrl/snapPerspectiveOrientation/snapPerspectiveOrientation.component.spec.ts
@@ -1,12 +1,12 @@
 import { ComponentFixture, TestBed } from '@angular/core/testing';
-import { ChangePerspectiveOrientationComponent } from './changePerspectiveOrientation.component';
+import { SnapPerspectiveOrientationCmp } from './snapPerspectiveOrientation.component';
 import { MockStore, provideMockStore } from "@ngrx/store/testing"
 import { AngularMaterialModule } from 'src/sharedModules';
 import { CommonModule } from '@angular/common';
 
-describe('ChangePerspectiveOrientationComponent', () => {
-  let component: ChangePerspectiveOrientationComponent;
-  let fixture: ComponentFixture<ChangePerspectiveOrientationComponent>;
+describe('SnapPerspectiveOrientationCmp', () => {
+  let component: SnapPerspectiveOrientationCmp;
+  let fixture: ComponentFixture<SnapPerspectiveOrientationCmp>;
   let mockStore: MockStore;
 
   beforeEach(async () => {
@@ -15,7 +15,7 @@ describe('ChangePerspectiveOrientationComponent', () => {
         AngularMaterialModule,
         CommonModule
       ],
-      declarations: [ ChangePerspectiveOrientationComponent ],
+      declarations: [ SnapPerspectiveOrientationCmp ],
       providers: [provideMockStore()],
 
     })
@@ -23,7 +23,7 @@ describe('ChangePerspectiveOrientationComponent', () => {
   });
 
   beforeEach(() => {
-    fixture = TestBed.createComponent(ChangePerspectiveOrientationComponent);
+    fixture = TestBed.createComponent(SnapPerspectiveOrientationCmp);
     component = fixture.componentInstance;
     fixture.detectChanges();
   });
diff --git a/src/viewerModule/nehuba/viewerCtrl/snapPerspectiveOrientation/snapPerspectiveOrientation.component.ts b/src/viewerModule/nehuba/viewerCtrl/snapPerspectiveOrientation/snapPerspectiveOrientation.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..6d936f0c3b2c62c21de377b7205676d56c2eee33
--- /dev/null
+++ b/src/viewerModule/nehuba/viewerCtrl/snapPerspectiveOrientation/snapPerspectiveOrientation.component.ts
@@ -0,0 +1,77 @@
+import { ChangeDetectionStrategy, Component } from '@angular/core';
+import { select, Store } from "@ngrx/store";
+import { concat, Observable, of } from 'rxjs';
+import { atlasSelection } from 'src/state';
+import { actions } from 'src/state/atlasSelection';
+import { VALUES } from "common/constants"
+import { floatEquality } from "common/util"
+import { filter, map } from 'rxjs/operators';
+
+enum EnumClassicalView {
+  CORONAL = "Coronal",
+  SAGITTAL = "Sagittal",
+  AXIAL = "Axial",
+}
+
+const viewOrientations : Record<EnumClassicalView, number[][]> = {
+  [EnumClassicalView.CORONAL]: [[0,-1 * VALUES.ROOT_2,VALUES.ROOT_2,0], [-1 * VALUES.ROOT_2,0,0,VALUES.ROOT_2]],
+  [EnumClassicalView.SAGITTAL]: [[-0.5,-0.5,0.5,0.5], [-0.5,0.5,-0.5,0.5]],
+  [EnumClassicalView.AXIAL]: [[0,0,1,0], [1,0,0,0]]
+}
+
+@Component({
+  selector: 'snap-perspective-orientation-cmp',
+  templateUrl: './snapPerspectiveOrientation.template.html',
+  styleUrls: ['./snapPerspectiveOrientation.style.sass'],
+  changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class SnapPerspectiveOrientationCmp {
+
+  public currentView: EnumClassicalView = null
+  public EnumClassicalView = EnumClassicalView
+  public currentPersView$: Observable<null|EnumClassicalView> = concat(
+    of(null),
+    this.store$.pipe(
+      select(atlasSelection.selectors.navigation),
+      filter(v => !!v),
+      map(({ perspectiveOrientation }) => {
+        if (
+          perspectiveOrientation.some(v => floatEquality( Math.abs (v), 1, VALUES.THRESHOLD))
+        ) {
+          return EnumClassicalView.AXIAL
+        }
+  
+        if (
+          perspectiveOrientation.every(v => floatEquality( Math.abs(v), 0.5, VALUES.THRESHOLD))
+        ) {
+          return EnumClassicalView.SAGITTAL
+        }
+  
+        if (
+          perspectiveOrientation.filter(v => floatEquality( Math.abs(v), VALUES.ROOT_2, VALUES.THRESHOLD )).length === 2
+        ) {
+          return EnumClassicalView.CORONAL
+        }
+        return null
+      }),
+    )
+  )
+
+  constructor(private store$: Store) {}
+
+  public set3DViewPoint(plane: EnumClassicalView) {
+
+    this.counter ++
+    const orientation = viewOrientations[plane][this.counter % 2]
+
+    this.store$.dispatch(
+      actions.navigateTo({
+        navigation: {
+          perspectiveOrientation: orientation,
+        },
+        animation: true
+      })
+    )
+  }
+  private counter = 0
+}
diff --git a/src/viewerModule/nehuba/viewerCtrl/snapPerspectiveOrientation/snapPerspectiveOrientation.style.sass b/src/viewerModule/nehuba/viewerCtrl/snapPerspectiveOrientation/snapPerspectiveOrientation.style.sass
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/viewerModule/nehuba/viewerCtrl/snapPerspectiveOrientation/snapPerspectiveOrientation.template.html b/src/viewerModule/nehuba/viewerCtrl/snapPerspectiveOrientation/snapPerspectiveOrientation.template.html
new file mode 100644
index 0000000000000000000000000000000000000000..3f2d7015b58a1e285dc958131b67877346d18d78
--- /dev/null
+++ b/src/viewerModule/nehuba/viewerCtrl/snapPerspectiveOrientation/snapPerspectiveOrientation.template.html
@@ -0,0 +1,18 @@
+<h3 class="text mat-h3">
+    Snap perspective orientation
+</h3>
+
+<ng-container *ngTemplateOutlet="btnTmpl; context: { $implicit: EnumClassicalView.CORONAL }">
+</ng-container>
+<ng-container *ngTemplateOutlet="btnTmpl; context: { $implicit: EnumClassicalView.SAGITTAL }">
+</ng-container>
+<ng-container *ngTemplateOutlet="btnTmpl; context: { $implicit: EnumClassicalView.AXIAL }">
+</ng-container>
+
+<ng-template #btnTmpl let-orientation>
+    <button mat-button
+        [color]="(currentPersView$ | async) === orientation ? 'primary': 'default'"
+        (click)="set3DViewPoint(orientation)">
+        {{ orientation }}
+    </button>
+</ng-template>
diff --git a/src/viewerModule/nehuba/viewerCtrl/viewerCtrlCmp/viewerCtrlCmp.component.ts b/src/viewerModule/nehuba/viewerCtrl/viewerCtrlCmp/viewerCtrlCmp.component.ts
index 2a44980c9fd4639d227129dc84005ce306323d64..030ed06547f29b4632edddb65a1dab8f35d5a0af 100644
--- a/src/viewerModule/nehuba/viewerCtrl/viewerCtrlCmp/viewerCtrlCmp.component.ts
+++ b/src/viewerModule/nehuba/viewerCtrl/viewerCtrlCmp/viewerCtrlCmp.component.ts
@@ -1,10 +1,8 @@
-import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Inject, OnInit, Optional } from "@angular/core";
+import { ChangeDetectionStrategy, Component, OnInit } from "@angular/core";
 import { select, Store } from "@ngrx/store";
-import { merge, Observable, of, Subscription } from "rxjs";
+import { merge, of, Subscription } from "rxjs";
 import { pairwise, withLatestFrom} from "rxjs/operators";
-import { NehubaViewerUnit } from "src/viewerModule/nehuba";
-import { NEHUBA_INSTANCE_INJTKN } from "src/viewerModule/nehuba/util";
-import { ARIA_LABELS } from 'common/constants'
+import { ARIA_LABELS, CONST } from 'common/constants'
 import { actionSetAuxMeshes, selectorAuxMeshes } from "../../store";
 import { FormBuilder, FormControl, FormGroup } from "@angular/forms";
 import { atlasAppearance } from "src/state";
@@ -22,6 +20,7 @@ import { atlasAppearance } from "src/state";
 export class ViewerCtrlCmp implements OnInit{
 
   public ARIA_LABELS = ARIA_LABELS
+  public CONST = CONST
 
   private sub: Subscription[] = []
 
@@ -33,7 +32,6 @@ export class ViewerCtrlCmp implements OnInit{
     if (val === this._removeOctantFlag) return
     this._removeOctantFlag = val
     this.setOctantRemoval(this._removeOctantFlag)
-    this.cdr.detectChanges()
   }
 
   public nehubaViewerPerspectiveOctantRemoval$ = this.store$.pipe(
@@ -47,7 +45,6 @@ export class ViewerCtrlCmp implements OnInit{
   )
 
   ngOnInit(): void {
-
     this.sub.push(
 
       this.nehubaViewerPerspectiveOctantRemoval$.subscribe(
@@ -73,7 +70,6 @@ export class ViewerCtrlCmp implements OnInit{
           this.auxMeshesNamesSet.add(mesh.ngId)
           this.auxMeshFormGroup.addControl(mesh['@id'], new FormControl(mesh.visible))
         }
-        this.cdr.detectChanges()
       }),
 
       this.auxMeshFormGroup.valueChanges.pipe(
@@ -98,7 +94,6 @@ export class ViewerCtrlCmp implements OnInit{
             })
           )
         }
-        this.cdr.detectChanges()
       })
     )
   }
@@ -106,8 +101,6 @@ export class ViewerCtrlCmp implements OnInit{
   constructor(
     private store$: Store<any>,
     private formBuilder: FormBuilder,
-    private cdr: ChangeDetectorRef,
-    @Optional() @Inject(NEHUBA_INSTANCE_INJTKN) private nehubaInst$: Observable<NehubaViewerUnit>,
   ){
 
   }
diff --git a/src/viewerModule/nehuba/viewerCtrl/viewerCtrlCmp/viewerCtrlCmp.template.html b/src/viewerModule/nehuba/viewerCtrl/viewerCtrlCmp/viewerCtrlCmp.template.html
index 50f326abfe12df716ca25a14c9b73043cb53b004..e723b4cd9d7a4d84dd430f0987f8b9f76560fcc4 100644
--- a/src/viewerModule/nehuba/viewerCtrl/viewerCtrlCmp/viewerCtrlCmp.template.html
+++ b/src/viewerModule/nehuba/viewerCtrl/viewerCtrlCmp/viewerCtrlCmp.template.html
@@ -1,28 +1,39 @@
-<h3 class="sxplr-custom-cmp text mat-h3">
+<h3 class="text mat-h3">
   Perspective View
 </h3>
 
 <mat-slide-toggle [(ngModel)]="removeOctantFlag"
   [aria-label]="ARIA_LABELS.TOGGLE_FRONTAL_OCTANT"
   name="remove-frontal-octant">
-  <span class="sxplr-custom-cmp text">
+  <span class="text">
     Remove frontal octant
   </span>
+  <i [matTooltip]="CONST.REMOVE_FRONTAL_OCTANT_HELPER_TEXT" class="fas fa-question"></i>
 </mat-slide-toggle>
 
+<!-- aux mesh controller -->
 <ng-container *ngIf="auxMeshes$ | async as auxMeshes">
-  <mat-divider class="mt-1 mb-1"></mat-divider>
-  <form [formGroup]="auxMeshFormGroup">
-    <mat-slide-toggle *ngFor="let auxMesh of auxMeshes; trackBy: trackByAtId"
-      [formControlName]="auxMesh['@id']"
-      class="d-block"
-      [name]="'toggle-aux-mesh-' + auxMesh['@id']">
-      <span class="sxplr-custom-cmp text">
-        {{ auxMesh.displayName || auxMesh.name }}
-      </span>
-    </mat-slide-toggle>
-  </form>
+  <ng-template [ngIf]="auxMeshes.length > 0">
+    <mat-divider class="mt-1 mb-1"></mat-divider>
+
+    <h3 class="text mat-h3">
+      Toggle auxiliary meshes
+    </h3>
+    
+    <form [formGroup]="auxMeshFormGroup">
+      <mat-slide-toggle *ngFor="let auxMesh of auxMeshes; trackBy: trackByAtId"
+        [formControlName]="auxMesh['@id']"
+        class="d-block"
+        [name]="'toggle-aux-mesh-' + auxMesh['@id']">
+        <span class="text">
+          {{ auxMesh.displayName || auxMesh.name }}
+        </span>
+      </mat-slide-toggle>
+    </form>
+  </ng-template>
 </ng-container>
 
-<!-- TODO menu no longer showing, likely something to do with detaching cdr on nehubaGlue.component -->
-<app-change-perspective-orientation *ngIf="false"></app-change-perspective-orientation>
+<mat-divider class="mt-1 mb-1"></mat-divider>
+<snap-perspective-orientation-cmp></snap-perspective-orientation-cmp>
+
+
diff --git a/worker/worker-nifti.js b/worker/worker-nifti.js
index 56f0aabaef84833182d543db3b0f08a56f147f42..c754e6e885008c3310ad0c1d4821ebb893219946 100644
--- a/worker/worker-nifti.js
+++ b/worker/worker-nifti.js
@@ -244,7 +244,7 @@
             if (val < min) min = val
             if (val > max) max = val
           } catch (e) {
-            console.error(`error in while true block`)
+            // erroring here is expected. Since we will overread the buffer.
             break
           }
           pointer.offset += increment