diff --git a/.dockerignore b/.dockerignore
index 5889e7a85c0d4d2e5e97b5e010d9070bfc386c56..3b81744d2d843e03daa69ca95bed0af945451375 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -1,21 +1,28 @@
 .git
-node-modules
-__build__
-__server_build__
+.idea
+.vscode
+.DS_Store
+*.iml
+
+# Build folders
+node_modules
+build
+dist
 typings
 tsd_typings
-npm-debug.log
-dist
 coverage
-.idea
-*.iml
+__build__
+__server_build__
+
+# Node
+*.log
+npm-debug.log.*
+
+# Angular files
 *.ngfactory.ts
 *.css.shim.ts
 *.scss.shim.ts
-.DS_Store
+
+# Webpack files
 webpack.records.json
-npm-debug.log.*
-morgan.log
-yarn-error.log
-*.css
 package-lock.json
diff --git a/.travis.yml b/.travis.yml
index 5e4bae7892e4ae070ab82617d20658d6434259c4..8debdcd88eb969b94a7d1913ec89e4d488429d68 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -44,8 +44,8 @@ after_script:
 language: node_js
 
 node_js:
-  - "8"
   - "10"
+  - "12"
 
 cache:
   yarn: true
diff --git a/Dockerfile b/Dockerfile
index f10164ebd034a85b7525ef8ab7a150348064867c..d848666175e065e44d4a125a5a8447f60d70961d 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,10 +1,12 @@
 # This image will be published as dspace/dspace-angular
 # See https://dspace-labs.github.io/DSpace-Docker-Images/ for usage details
 
-FROM node:8-alpine
+FROM node:12-alpine
 WORKDIR /app
 ADD . /app/
 EXPOSE 3000
 
-RUN yarn install
+# We run yarn install with an increased network timeout (5min) to avoid "ESOCKETTIMEDOUT" errors from hub.docker.com
+# See, for example https://github.com/yarnpkg/yarn/issues/5540
+RUN yarn install --network-timeout 300000
 CMD yarn run watch
diff --git a/README.md b/README.md
index 27e61afe765525b067f5de8facd4e253a102a9af..47c040bb936850a8ab76c65df5e90c8cf5a78d2a 100644
--- a/README.md
+++ b/README.md
@@ -13,7 +13,7 @@ You can find additional information on the DSpace 7 Angular UI on the [wiki](htt
 Quick start
 -----------
 
-**Ensure you're running [Node](https://nodejs.org) `v8.0.x` or `v10.0.x`, [npm](https://www.npmjs.com/) >= `v5.x` and [yarn](https://yarnpkg.com) >= `v1.x`**
+**Ensure you're running [Node](https://nodejs.org) `v10.x` or `v12.x`, [npm](https://www.npmjs.com/) >= `v5.x` and [yarn](https://yarnpkg.com) >= `v1.x`**
 
 ```bash
 # clone the repo
@@ -65,7 +65,7 @@ Requirements
 ------------
 
 -	[Node.js](https://nodejs.org), [npm](https://www.npmjs.com/), and [yarn](https://yarnpkg.com)
--	Ensure you're running node `v8.x` or `v10.x`, npm >= `v5.x` and yarn >= `v1.x`
+-	Ensure you're running node `v10.x` or `v12.x`, npm >= `v5.x` and yarn >= `v1.x`
 
 If you have [`nvm`](https://github.com/creationix/nvm#install-script) or [`nvm-windows`](https://github.com/coreybutler/nvm-windows) installed, which is highly recommended, you can run `nvm install --lts && nvm use` to install and start using the latest Node LTS.
 
diff --git a/config/environment.default.js b/config/environment.default.js
index 58193d31bc6898742bfc019d0601fb767f9c6f2c..1ea9787a550119602834460448598cc67a548b2e 100644
--- a/config/environment.default.js
+++ b/config/environment.default.js
@@ -140,7 +140,7 @@ module.exports = {
   }, {
     code: 'nl',
     label: 'Nederlands',
-    active: false,
+    active: true,
   }, {
     code: 'pt',
     label: 'Português',
diff --git a/docker/docker-compose-rest.yml b/docker/docker-compose-rest.yml
index 222557bc81e091f137d92a02c1b32d4852e712a1..6f5a1d6c83c326137dabe7dd0333eaf7d38a94eb 100644
--- a/docker/docker-compose-rest.yml
+++ b/docker/docker-compose-rest.yml
@@ -5,7 +5,7 @@ services:
     container_name: dspace
     depends_on:
     - dspacedb
-    image: dspace/dspace:dspace-7_x-jdk8-test
+    image: dspace/dspace:dspace-7_x-test
     networks:
       dspacenet:
     ports:
diff --git a/docker/docker-compose-travis.yml b/docker/docker-compose-travis.yml
index 6ca44e4e4704bd549063241c60bff89c3728032c..f0f5ef70e8d84a7ee436e3fb6e2ce3686797c38c 100644
--- a/docker/docker-compose-travis.yml
+++ b/docker/docker-compose-travis.yml
@@ -5,7 +5,7 @@ services:
     container_name: dspace
     depends_on:
     - dspacedb
-    image: dspace/dspace:dspace-7_x-jdk8-test
+    image: dspace/dspace:dspace-7_x-test
     networks:
       dspacenet:
     ports:
diff --git a/docker/local.cfg b/docker/local.cfg
index 947b3c8248f6e3745477d414a6ed59e981d6388f..70bc45c112c50984e137e89d5b9e393137c77489 100644
--- a/docker/local.cfg
+++ b/docker/local.cfg
@@ -1,6 +1,5 @@
 dspace.dir=/dspace
 db.url=jdbc:postgresql://dspacedb:5432/dspace
-dspace.hostname=dspace
-dspace.baseUrl=http://localhost:8080/server
+dspace.server.url=http://localhost:8080/server
 dspace.name=DSpace Started with Docker Compose
 solr.server=http://dspacesolr:8983/solr
diff --git a/e2e/search-navbar/search-navbar.po.ts b/e2e/search-navbar/search-navbar.po.ts
index 17112ab468acfe23c3fd6137feac022462d671ce..7401e881e76c0a470ad3985e56f21da58381a6ff 100644
--- a/e2e/search-navbar/search-navbar.po.ts
+++ b/e2e/search-navbar/search-navbar.po.ts
@@ -1,4 +1,4 @@
-import { browser, element, by, protractor } from 'protractor';
+import { browser, by, element, protractor } from 'protractor';
 import { promise } from 'selenium-webdriver';
 
 export class ProtractorPage {
@@ -32,9 +32,4 @@ export class ProtractorPage {
   submitByPressingEnter() {
     element(by.css('#search-navbar-container form input[name="query"]')).sendKeys(protractor.Key.ENTER);
   }
-
-  submitByPressingEnter() {
-    element(by.css('#search-navbar-container form input[name="query"]')).sendKeys(protractor.Key.ENTER);
-  }
-
 }
diff --git a/package.json b/package.json
index 03a3c1b41a1cb9899f3cc6711e85fba267414779..0f3fa03c1ee1858cd0c33e307649cae4d2633899 100644
--- a/package.json
+++ b/package.json
@@ -8,7 +8,7 @@
   },
   "license": "BSD-2-Clause",
   "engines": {
-    "node": "8.* || >= 10.*"
+    "node": "10.* || >= 12.*"
   },
   "resolutions": {
     "serialize-javascript": ">= 2.1.2",
@@ -75,30 +75,28 @@
     "sync-i18n": "node ./scripts/sync-i18n-files.js"
   },
   "dependencies": {
-    "@angular/animations": "^7.2.15",
-    "@angular/cdk": "^7.3.7",
-    "@angular/cli": "^7.3.5",
-    "@angular/common": "^7.2.15",
-    "@angular/core": "^7.2.15",
-    "@angular/forms": "^7.2.15",
-    "@angular/http": "^7.2.15",
-    "@angular/platform-browser": "^7.2.15",
-    "@angular/platform-browser-dynamic": "^7.2.15",
-    "@angular/platform-server": "^7.2.15",
-    "@angular/router": "^7.2.15",
+    "@angular/animations": "^8.2.14",
+    "@angular/cdk": "8.2.3",
+    "@angular/cli": "^8.3.25",
+    "@angular/common": "^8.2.14",
+    "@angular/core": "^8.2.14",
+    "@angular/forms": "^8.2.14",
+    "@angular/platform-browser": "^8.2.14",
+    "@angular/platform-browser-dynamic": "^8.2.14",
+    "@angular/platform-server": "^8.2.14",
+    "@angular/router": "^8.2.14",
     "@angularclass/bootloader": "1.0.1",
-    "@ng-bootstrap/ng-bootstrap": "^4.1.0",
-    "@ng-dynamic-forms/core": "^7.1.0",
-    "@ng-dynamic-forms/ui-ng-bootstrap": "^7.1.0",
-    "@ngrx/effects": "^7.3.0",
-    "@ngrx/router-store": "^7.3.0",
-    "@ngrx/store": "^7.3.0",
-    "@nguniversal/express-engine": "^7.1.1",
+    "@ng-bootstrap/ng-bootstrap": "^5.2.1",
+    "@ng-dynamic-forms/core": "8.1.1",
+    "@ng-dynamic-forms/ui-ng-bootstrap": "8.1.1",
+    "@ngrx/effects": "^8.6.0",
+    "@ngrx/router-store": "^8.6.0",
+    "@ngrx/store": "^8.6.0",
+    "@nguniversal/express-engine": "^8.2.6",
     "@ngx-translate/core": "11.0.1",
     "@ngx-translate/http-loader": "4.0.0",
-    "@nicky-lenaers/ngx-scroll-to": "^1.0.0",
+    "@nicky-lenaers/ngx-scroll-to": "^3.0.1",
     "angular-idle-preload": "3.0.0",
-    "angular-sortablejs": "^2.5.0",
     "angular2-text-mask": "9.0.0",
     "angulartics2": "7.5.2",
     "body-parser": "1.18.2",
@@ -106,7 +104,7 @@
     "cerialize": "0.1.18",
     "compression": "1.7.1",
     "cookie-parser": "1.4.3",
-    "core-js": "^2.6.5",
+    "core-js": "^3.6.4",
     "debug-loader": "^0.0.1",
     "express": "4.16.2",
     "express-session": "1.15.6",
@@ -126,17 +124,18 @@
     "moment": "^2.22.1",
     "moment-range": "^4.0.2",
     "morgan": "^1.9.1",
-    "ng-mocks": "^7.6.0",
+    "ng-mocks": "^8.1.0",
     "ng2-file-upload": "1.2.1",
     "ng2-nouislider": "^1.8.2",
-    "ngx-bootstrap": "^3.2.0",
+    "ngx-bootstrap": "^5.3.2",
     "ngx-infinite-scroll": "6.0.1",
     "ngx-moment": "^3.4.0",
     "ngx-pagination": "3.0.3",
+    "ngx-sortablejs": "^3.1.4",
     "nouislider": "^11.0.0",
     "pem": "1.13.2",
-    "reflect-metadata": "0.1.12",
-    "rxjs": "6.4.0",
+    "reflect-metadata": "^0.1.13",
+    "rxjs": "6.5.4",
     "rxjs-spy": "^7.5.1",
     "sass-resources-loader": "^2.0.0",
     "sortablejs": "1.7.0",
@@ -147,17 +146,17 @@
     "uuid": "^3.2.1",
     "webfontloader": "1.6.28",
     "webpack-cli": "^3.2.0",
-    "zone.js": "^0.8.29"
+    "zone.js": "^0.9.1"
   },
   "devDependencies": {
-    "@angular-devkit/build-angular": "^0.13.5",
-    "@angular/compiler": "^7.2.15",
-    "@angular/compiler-cli": "^7.2.15",
+    "@angular-devkit/build-angular": "^0.803.25",
+    "@angular/compiler": "^8.2.14",
+    "@angular/compiler-cli": "^8.2.14",
     "@fortawesome/fontawesome-free": "^5.5.0",
-    "@ngrx/entity": "^7.3.0",
-    "@ngrx/schematics": "^7.3.0",
-    "@ngrx/store-devtools": "^7.3.0",
-    "@ngtools/webpack": "^7.3.9",
+    "@ngrx/entity": "^8.6.0",
+    "@ngrx/schematics": "^8.6.0",
+    "@ngrx/store-devtools": "^8.6.0",
+    "@ngtools/webpack": "^8.3.25",
     "@schematics/angular": "^0.7.5",
     "@types/acorn": "^4.0.3",
     "@types/cookie-parser": "1.4.1",
@@ -215,8 +214,6 @@
     "karma-webdriver-launcher": "^1.0.7",
     "karma-webpack": "3.0.0",
     "ncp": "^2.0.0",
-    "ngrx-store-freeze": "^0.2.4",
-    "node-sass": "^4.11.0",
     "nodemon": "^1.15.0",
     "npm-run-all": "4.1.3",
     "optimize-css-assets-webpack-plugin": "^5.0.1",
@@ -247,7 +244,7 @@
     "ts-node": "4.1.0",
     "tslint": "5.11.0",
     "typedoc": "^0.9.0",
-    "typescript": "3.1.6",
+    "typescript": "3.5.3",
     "webdriver-manager": "^12.1.7",
     "webpack": "^4.29.6",
     "webpack-bundle-analyzer": "^3.3.2",
diff --git a/resources/i18n/en.json5 b/resources/i18n/en.json5
index fcfa4a4861f1e753e733c91ebbfc7c8d60303c36..4a58ade3cb193a85cda0785433f14b9ec6c34697 100644
--- a/resources/i18n/en.json5
+++ b/resources/i18n/en.json5
@@ -232,6 +232,14 @@
 
   "browse.metadata.title": "Title",
 
+  "browse.metadata.author.breadcrumbs": "Browse by Author",
+
+  "browse.metadata.dateissued.breadcrumbs": "Browse by Date",
+
+  "browse.metadata.subject.breadcrumbs": "Browse by Subject",
+
+  "browse.metadata.title.breadcrumbs": "Browse by Title",
+
   "browse.startsWith.choose_start": "(Choose start)",
 
   "browse.startsWith.choose_year": "(Choose year)",
@@ -273,7 +281,6 @@
   "browse.title": "Browsing {{ collection }} by {{ field }} {{ value }}",
 
 
-
   "chips.remove": "Remove chip",
 
 
@@ -302,6 +309,8 @@
 
   "collection.edit.head": "Edit Collection",
 
+  "collection.edit.breadcrumbs": "Edit Collection",
+
 
 
   "collection.edit.item-mapper.cancel": "Cancel",
@@ -486,6 +495,7 @@
 
   "community.edit.head": "Edit Community",
 
+  "community.edit.breadcrumbs": "Edit Community",
 
 
   "community.edit.logo.label": "Community logo",
@@ -772,6 +782,8 @@
 
   "item.edit.head": "Edit Item",
 
+  "item.edit.breadcrumbs": "Edit Item",
+
 
 
   "item.edit.item-mapper.buttons.add": "Map item to selected collections",
@@ -1196,6 +1208,8 @@
 
   "login.title": "Login",
 
+  "login.breadcrumbs": "Login",
+
 
 
   "logout.form.header": "Log out from DSpace",
@@ -1592,6 +1606,7 @@
 
   "search.title": "DSpace Angular :: Search",
 
+  "search.breadcrumbs": "Search",
 
 
   "search.filters.applied.f.author": "Author",
diff --git a/resources/i18n/nl.json5 b/resources/i18n/nl.json5
index 3eb7b7c7c332e68c0f8abcc7b84a39331bf77643..344a36e2e8c2ab5c277d67509f0ae86284e8bead 100644
--- a/resources/i18n/nl.json5
+++ b/resources/i18n/nl.json5
@@ -1,3087 +1,2455 @@
 {
-  
+
   // "404.help": "We can't find the page you're looking for. The page may have been moved or deleted. You can use the button below to get back to the home page. ",
   "404.help": "De pagina die u zoekt kan niet gevonden worden. De pagina werd mogelijk verplaatst of verwijderd. U kan onderstaande knop gebruiken om terug naar de homepagina te gaan. ",
-  
+
   // "404.link.home-page": "Take me to the home page",
   "404.link.home-page": "Terug naar de homepagina",
-  
+
   // "404.page-not-found": "page not found",
   "404.page-not-found": "Pagina niet gevonden",
-  
-  
-  
+
+
+
   // "admin.registries.bitstream-formats.create.failure.content": "An error occurred while creating the new bitstream format.",
-  // TODO New key - Add a translation
-  "admin.registries.bitstream-formats.create.failure.content": "An error occurred while creating the new bitstream format.",
-  
+  "admin.registries.bitstream-formats.create.failure.content": "Er is een fout opgetreden bij het maken van het nieuwe bitstream-formaat.",
+
   // "admin.registries.bitstream-formats.create.failure.head": "Failure",
-  // TODO New key - Add a translation
-  "admin.registries.bitstream-formats.create.failure.head": "Failure",
-  
+  "admin.registries.bitstream-formats.create.failure.head": "Gefaald",
+
   // "admin.registries.bitstream-formats.create.head": "Create Bitstream format",
-  // TODO New key - Add a translation
-  "admin.registries.bitstream-formats.create.head": "Create Bitstream format",
-  
+   "admin.registries.bitstream-formats.create.head": "Maak een bitstream-formaat aan",
+
   // "admin.registries.bitstream-formats.create.new": "Add a new bitstream format",
-  // TODO New key - Add a translation
-  "admin.registries.bitstream-formats.create.new": "Add a new bitstream format",
-  
+  "admin.registries.bitstream-formats.create.new": "Voeg een nieuw bitstream-formaat toe",
+
   // "admin.registries.bitstream-formats.create.success.content": "The new bitstream format was successfully created.",
-  // TODO New key - Add a translation
-  "admin.registries.bitstream-formats.create.success.content": "The new bitstream format was successfully created.",
-  
+  "admin.registries.bitstream-formats.create.success.content": "Het nieuwe bitstream-formaat is aangemaakt.",
+
   // "admin.registries.bitstream-formats.create.success.head": "Success",
   "admin.registries.bitstream-formats.create.success.head": "Succes",
-  
+
   // "admin.registries.bitstream-formats.delete.failure.amount": "Failed to remove {{ amount }} format(s)",
-  // TODO New key - Add a translation
-  "admin.registries.bitstream-formats.delete.failure.amount": "Failed to remove {{ amount }} format(s)",
-  
+   "admin.registries.bitstream-formats.delete.failure.amount": "Het verwijderen van {{ amount }} forma(a)t(en) is mislukt.",
+
   // "admin.registries.bitstream-formats.delete.failure.head": "Failure",
   "admin.registries.bitstream-formats.delete.failure.head": "Gefaald",
-  
+
   // "admin.registries.bitstream-formats.delete.success.amount": "Successfully removed {{ amount }} format(s)",
-  // TODO New key - Add a translation
-  "admin.registries.bitstream-formats.delete.success.amount": "Successfully removed {{ amount }} format(s)",
-  
+   "admin.registries.bitstream-formats.delete.success.amount": "{{ amount }} Forma(a)t(en) zijn succesvol verwijderd.",
+
   // "admin.registries.bitstream-formats.delete.success.head": "Success",
   "admin.registries.bitstream-formats.delete.success.head": "Succes",
-  
+
   // "admin.registries.bitstream-formats.description": "This list of bitstream formats provides information about known formats and their support level.",
-  "admin.registries.bitstream-formats.description": "Deze lijst van Bitstream formaten biedt informatie over de formaten die in deze repository zijn toegelaten en op welke manier ze ondersteund worden. De term Bitstream wordt in DSpace gebruikt om een bestand aan te duiden dat samen met metadata onderdeel uitmaakt van een item. De naam bitstream duidt op het feit dat het bestand achterliggend wordt opgeslaan zonder bestandsextensie.",
-  
+  "admin.registries.bitstream-formats.description": "Deze lijst van bitstream-formaten biedt informatie over de formaten die in deze repository zijn toegelaten en op welke manier ze ondersteund worden. De term Bitstream wordt in DSpace gebruikt om een bestand aan te duiden dat samen met metadata onderdeel uitmaakt van een item. De naam bitstream duidt op het feit dat het bestand achterliggend wordt opgeslaan zonder bestandsextensie.",
+
   // "admin.registries.bitstream-formats.edit.description.hint": "",
-  // TODO New key - Add a translation
   "admin.registries.bitstream-formats.edit.description.hint": "",
-  
+
   // "admin.registries.bitstream-formats.edit.description.label": "Description",
-  // TODO New key - Add a translation
-  "admin.registries.bitstream-formats.edit.description.label": "Description",
-  
+  "admin.registries.bitstream-formats.edit.description.label": "Beschrijving",
+
   // "admin.registries.bitstream-formats.edit.extensions.hint": "Extensions are file extensions that are used to automatically identify the format of uploaded files. You can enter several extensions for each format.",
-  // TODO New key - Add a translation
-  "admin.registries.bitstream-formats.edit.extensions.hint": "Extensions are file extensions that are used to automatically identify the format of uploaded files. You can enter several extensions for each format.",
-  
+   "admin.registries.bitstream-formats.edit.extensions.hint": "Extensies zijn bestandsextensies die worden gebruikt om automatisch het formaat van geuploade bestanden te bepalen. U kunt meerdere extensies voor een formaat invullen.",
+
   // "admin.registries.bitstream-formats.edit.extensions.label": "File extensions",
-  // TODO New key - Add a translation
-  "admin.registries.bitstream-formats.edit.extensions.label": "File extensions",
-  
+  "admin.registries.bitstream-formats.edit.extensions.label": "Bestandsextensies",
+
   // "admin.registries.bitstream-formats.edit.extensions.placeholder": "Enter a file extenstion without the dot",
-  // TODO New key - Add a translation
-  "admin.registries.bitstream-formats.edit.extensions.placeholder": "Enter a file extenstion without the dot",
-  
+  "admin.registries.bitstream-formats.edit.extensions.placeholder": "Vul een bestandsextensie toe zonder de punt",
+
   // "admin.registries.bitstream-formats.edit.failure.content": "An error occurred while editing the bitstream format.",
-  // TODO New key - Add a translation
-  "admin.registries.bitstream-formats.edit.failure.content": "An error occurred while editing the bitstream format.",
-  
+  "admin.registries.bitstream-formats.edit.failure.content": "Er is een fout opgetreden bij het bewerken van het bitstream-formaat.",
+
   // "admin.registries.bitstream-formats.edit.failure.head": "Failure",
-  // TODO New key - Add a translation
-  "admin.registries.bitstream-formats.edit.failure.head": "Failure",
-  
+  "admin.registries.bitstream-formats.edit.failure.head": "Gefaald",
+
   // "admin.registries.bitstream-formats.edit.head": "Bitstream format: {{ format }}",
-  // TODO New key - Add a translation
-  "admin.registries.bitstream-formats.edit.head": "Bitstream format: {{ format }}",
-  
+  "admin.registries.bitstream-formats.edit.head": "Bitstream-formaat: {{ format }}",
+
   // "admin.registries.bitstream-formats.edit.internal.hint": "Formats marked as internal are hidden from the user, and used for administrative purposes.",
-  // TODO New key - Add a translation
-  "admin.registries.bitstream-formats.edit.internal.hint": "Formats marked as internal are hidden from the user, and used for administrative purposes.",
-  
+  "admin.registries.bitstream-formats.edit.internal.hint": "Formaten die als intern gemarkeerd zijn, worden niet getoond aan de gebruiker en zijn bedoeld voor administratieve doeleinden.",
+
   // "admin.registries.bitstream-formats.edit.internal.label": "Internal",
-  // TODO New key - Add a translation
-  "admin.registries.bitstream-formats.edit.internal.label": "Internal",
-  
+   "admin.registries.bitstream-formats.edit.internal.label": "Intern",
+
   // "admin.registries.bitstream-formats.edit.mimetype.hint": "The MIME type associated with this format, does not have to be unique.",
-  // TODO New key - Add a translation
-  "admin.registries.bitstream-formats.edit.mimetype.hint": "The MIME type associated with this format, does not have to be unique.",
-  
+  "admin.registries.bitstream-formats.edit.mimetype.hint": "Het MIME type dat bij dit formaat hoort. Het hoeft niet uniek te zijn.",
+
   // "admin.registries.bitstream-formats.edit.mimetype.label": "MIME Type",
-  // TODO New key - Add a translation
-  "admin.registries.bitstream-formats.edit.mimetype.label": "MIME Type",
-  
+   "admin.registries.bitstream-formats.edit.mimetype.label": "MIME Type",
+
   // "admin.registries.bitstream-formats.edit.shortDescription.hint": "A unique name for this format, (e.g. Microsoft Word XP or Microsoft Word 2000)",
-  // TODO New key - Add a translation
-  "admin.registries.bitstream-formats.edit.shortDescription.hint": "A unique name for this format, (e.g. Microsoft Word XP or Microsoft Word 2000)",
-  
+  "admin.registries.bitstream-formats.edit.shortDescription.hint": "Een unieke naam voor dit formaat (b.v. Microsoft Word XP of Microsoft Word 2000)",
+
   // "admin.registries.bitstream-formats.edit.shortDescription.label": "Name",
-  // TODO New key - Add a translation
-  "admin.registries.bitstream-formats.edit.shortDescription.label": "Name",
-  
+  "admin.registries.bitstream-formats.edit.shortDescription.label": "Naam",
+
   // "admin.registries.bitstream-formats.edit.success.content": "The bitstream format was successfully edited.",
-  // TODO New key - Add a translation
-  "admin.registries.bitstream-formats.edit.success.content": "The bitstream format was successfully edited.",
-  
+  "admin.registries.bitstream-formats.edit.success.content": "Het bitstream-formaat is bewerkt.",
+
   // "admin.registries.bitstream-formats.edit.success.head": "Success",
-  // TODO New key - Add a translation
-  "admin.registries.bitstream-formats.edit.success.head": "Success",
-  
+  "admin.registries.bitstream-formats.edit.success.head": "Succes",
+
   // "admin.registries.bitstream-formats.edit.supportLevel.hint": "The level of support your institution pledges for this format.",
-  // TODO New key - Add a translation
-  "admin.registries.bitstream-formats.edit.supportLevel.hint": "The level of support your institution pledges for this format.",
-  
+  "admin.registries.bitstream-formats.edit.supportLevel.hint": "Het niveau van ondersteuning dat uw instituut belooft te bieden voor dit formaat.",
+
   // "admin.registries.bitstream-formats.edit.supportLevel.label": "Support level",
-  // TODO New key - Add a translation
-  "admin.registries.bitstream-formats.edit.supportLevel.label": "Support level",
-  
+  "admin.registries.bitstream-formats.edit.supportLevel.label": "Ondersteuningsniveau",
+
   // "admin.registries.bitstream-formats.head": "Bitstream Format Registry",
-  "admin.registries.bitstream-formats.head": "Bitstream Formaat Register",
-  
+  "admin.registries.bitstream-formats.head": "Bitstream-formaat Register",
+
   // "admin.registries.bitstream-formats.no-items": "No bitstream formats to show.",
-  // TODO New key - Add a translation
-  "admin.registries.bitstream-formats.no-items": "No bitstream formats to show.",
-  
+  "admin.registries.bitstream-formats.no-items": "Geen bitstream-formaten om te tonen.",
+
   // "admin.registries.bitstream-formats.table.delete": "Delete selected",
-  // TODO New key - Add a translation
-  "admin.registries.bitstream-formats.table.delete": "Delete selected",
-  
+  "admin.registries.bitstream-formats.table.delete": "Verwijder geselecteerde",
+
   // "admin.registries.bitstream-formats.table.deselect-all": "Deselect all",
-  // TODO New key - Add a translation
-  "admin.registries.bitstream-formats.table.deselect-all": "Deselect all",
-  
+  "admin.registries.bitstream-formats.table.deselect-all": "De-selecteer alle",
+
   // "admin.registries.bitstream-formats.table.internal": "internal",
-  // TODO New key - Add a translation
-  "admin.registries.bitstream-formats.table.internal": "internal",
-  
+  "admin.registries.bitstream-formats.table.internal": "intern",
+
   // "admin.registries.bitstream-formats.table.mimetype": "MIME Type",
-  // TODO New key - Add a translation
   "admin.registries.bitstream-formats.table.mimetype": "MIME Type",
-  
+
   // "admin.registries.bitstream-formats.table.name": "Name",
-  // TODO New key - Add a translation
-  "admin.registries.bitstream-formats.table.name": "Name",
-  
+  "admin.registries.bitstream-formats.table.name": "Naam",
+
   // "admin.registries.bitstream-formats.table.return": "Return",
-  // TODO New key - Add a translation
-  "admin.registries.bitstream-formats.table.return": "Return",
-  
+  "admin.registries.bitstream-formats.table.return": "Terug",
+
   // "admin.registries.bitstream-formats.table.supportLevel.KNOWN": "Known",
-  // TODO New key - Add a translation
-  "admin.registries.bitstream-formats.table.supportLevel.KNOWN": "Known",
-  
+  "admin.registries.bitstream-formats.table.supportLevel.KNOWN": "Bekend",
+
   // "admin.registries.bitstream-formats.table.supportLevel.SUPPORTED": "Supported",
-  // TODO New key - Add a translation
-  "admin.registries.bitstream-formats.table.supportLevel.SUPPORTED": "Supported",
-  
+  "admin.registries.bitstream-formats.table.supportLevel.SUPPORTED": "Ondersteund",
+
   // "admin.registries.bitstream-formats.table.supportLevel.UNKNOWN": "Unknown",
-  // TODO New key - Add a translation
-  "admin.registries.bitstream-formats.table.supportLevel.UNKNOWN": "Unknown",
-  
+  "admin.registries.bitstream-formats.table.supportLevel.UNKNOWN": "Onbekend",
+
   // "admin.registries.bitstream-formats.table.supportLevel.head": "Support Level",
-  // TODO New key - Add a translation
-  "admin.registries.bitstream-formats.table.supportLevel.head": "Support Level",
-  
+  "admin.registries.bitstream-formats.table.supportLevel.head": "Ondersteuningsniveau",
+
   // "admin.registries.bitstream-formats.title": "DSpace Angular :: Bitstream Format Registry",
   "admin.registries.bitstream-formats.title": "DSpace Angular :: Bitstream Formaat Register",
-  
-  
-  
+
+
+
   // "admin.registries.metadata.description": "The metadata registry maintains a list of all metadata fields available in the repository. These fields may be divided amongst multiple schemas. However, DSpace requires the qualified Dublin Core schema.",
   "admin.registries.metadata.description": "Het metadataregister omvat de lijst van alle metadatavelden die beschikbaar zijn in het systeem. Deze velden kunnen verspreid zijn over verschillende metadataschema's. Het qualified Dublin Core schema (dc) is een verplicht schema en kan niet worden verwijderd.",
-  
+
   // "admin.registries.metadata.form.create": "Create metadata schema",
-  // TODO New key - Add a translation
-  "admin.registries.metadata.form.create": "Create metadata schema",
-  
+   "admin.registries.metadata.form.create": "Maak een metadata schema aan",
+
   // "admin.registries.metadata.form.edit": "Edit metadata schema",
-  // TODO New key - Add a translation
-  "admin.registries.metadata.form.edit": "Edit metadata schema",
-  
+  "admin.registries.metadata.form.edit": "Bewerk een metadata schema",
+
   // "admin.registries.metadata.form.name": "Name",
-  // TODO New key - Add a translation
-  "admin.registries.metadata.form.name": "Name",
-  
+  "admin.registries.metadata.form.name": "Naam",
+
   // "admin.registries.metadata.form.namespace": "Namespace",
-  // TODO New key - Add a translation
   "admin.registries.metadata.form.namespace": "Namespace",
-  
+
   // "admin.registries.metadata.head": "Metadata Registry",
-  "admin.registries.metadata.head": "Metadata Register",
-  
+  "admin.registries.metadata.head": "Metadataregister",
+
   // "admin.registries.metadata.schemas.no-items": "No metadata schemas to show.",
   "admin.registries.metadata.schemas.no-items": "Er kunnen geen metadataschema's getoond worden.",
-  
+
   // "admin.registries.metadata.schemas.table.delete": "Delete selected",
-  // TODO New key - Add a translation
-  "admin.registries.metadata.schemas.table.delete": "Delete selected",
-  
+  "admin.registries.metadata.schemas.table.delete": "Verwijder geselecteerde",
+
   // "admin.registries.metadata.schemas.table.id": "ID",
   "admin.registries.metadata.schemas.table.id": "ID",
-  
+
   // "admin.registries.metadata.schemas.table.name": "Name",
   "admin.registries.metadata.schemas.table.name": "Naam",
-  
+
   // "admin.registries.metadata.schemas.table.namespace": "Namespace",
-  "admin.registries.metadata.schemas.table.namespace": "Naamruimte",
-  
+  "admin.registries.metadata.schemas.table.namespace": "Namespace",
+
   // "admin.registries.metadata.title": "DSpace Angular :: Metadata Registry",
-  "admin.registries.metadata.title": "DSpace Angular :: Metadata Register",
-  
-  
-  
+  "admin.registries.metadata.title": "DSpace Angular :: Metadataregister",
+
+
+
   // "admin.registries.schema.description": "This is the metadata schema for \"{{namespace}}\".",
   "admin.registries.schema.description": "Dit is het metadataschema voor \"{{namespace}}\".",
-  
+
   // "admin.registries.schema.fields.head": "Schema metadata fields",
   "admin.registries.schema.fields.head": "Schema metadatavelden",
-  
+
   // "admin.registries.schema.fields.no-items": "No metadata fields to show.",
   "admin.registries.schema.fields.no-items": "Er kunnen geen metadatavelden getoond worden.",
-  
+
   // "admin.registries.schema.fields.table.delete": "Delete selected",
-  // TODO New key - Add a translation
-  "admin.registries.schema.fields.table.delete": "Delete selected",
-  
+  "admin.registries.schema.fields.table.delete": "Verwijder geselecteerde",
+
   // "admin.registries.schema.fields.table.field": "Field",
   "admin.registries.schema.fields.table.field": "Veld",
-  
+
   // "admin.registries.schema.fields.table.scopenote": "Scope Note",
   "admin.registries.schema.fields.table.scopenote": "Opmerking over bereik",
-  
+
   // "admin.registries.schema.form.create": "Create metadata field",
-  // TODO New key - Add a translation
-  "admin.registries.schema.form.create": "Create metadata field",
-  
+  "admin.registries.schema.form.create": "Maak een metadataveld aan",
+
   // "admin.registries.schema.form.edit": "Edit metadata field",
-  // TODO New key - Add a translation
-  "admin.registries.schema.form.edit": "Edit metadata field",
-  
+  "admin.registries.schema.form.edit": "Bewerk metadataveld",
+
   // "admin.registries.schema.form.element": "Element",
-  // TODO New key - Add a translation
   "admin.registries.schema.form.element": "Element",
-  
+
   // "admin.registries.schema.form.qualifier": "Qualifier",
-  // TODO New key - Add a translation
   "admin.registries.schema.form.qualifier": "Qualifier",
-  
+
   // "admin.registries.schema.form.scopenote": "Scope Note",
-  // TODO New key - Add a translation
-  "admin.registries.schema.form.scopenote": "Scope Note",
-  
+  "admin.registries.schema.form.scopenote": "Opmerking over het bereik",
+
   // "admin.registries.schema.head": "Metadata Schema",
-  "admin.registries.schema.head": "Metadata Schema",
-  
+  "admin.registries.schema.head": "Metadataschema",
+
   // "admin.registries.schema.notification.created": "Successfully created metadata schema \"{{prefix}}\"",
-  // TODO New key - Add a translation
-  "admin.registries.schema.notification.created": "Successfully created metadata schema \"{{prefix}}\"",
-  
+  "admin.registries.schema.notification.created": "Metadataschema \"{{prefix}}\" is aangemaakt",
+
   // "admin.registries.schema.notification.deleted.failure": "Failed to delete {{amount}} metadata schemas",
-  // TODO New key - Add a translation
-  "admin.registries.schema.notification.deleted.failure": "Failed to delete {{amount}} metadata schemas",
-  
+  "admin.registries.schema.notification.deleted.failure": "Het verwijderen van {{amount}} metadataschemas is mislukt",
+
   // "admin.registries.schema.notification.deleted.success": "Successfully deleted {{amount}} metadata schemas",
-  // TODO New key - Add a translation
-  "admin.registries.schema.notification.deleted.success": "Successfully deleted {{amount}} metadata schemas",
-  
+  "admin.registries.schema.notification.deleted.success": "{{amount}} Metadataschemas verwijderd",
+
   // "admin.registries.schema.notification.edited": "Successfully edited metadata schema \"{{prefix}}\"",
-  // TODO New key - Add a translation
-  "admin.registries.schema.notification.edited": "Successfully edited metadata schema \"{{prefix}}\"",
-  
+  "admin.registries.schema.notification.edited": "Metadataschema \"{{prefix}}\" is bewerkt",
+
   // "admin.registries.schema.notification.failure": "Error",
-  // TODO New key - Add a translation
-  "admin.registries.schema.notification.failure": "Error",
-  
+  "admin.registries.schema.notification.failure": "Fout",
+
   // "admin.registries.schema.notification.field.created": "Successfully created metadata field \"{{field}}\"",
-  // TODO New key - Add a translation
-  "admin.registries.schema.notification.field.created": "Successfully created metadata field \"{{field}}\"",
-  
+  "admin.registries.schema.notification.field.created": "Metadataveld \"{{field}}\" is aangemaakt",
+
   // "admin.registries.schema.notification.field.deleted.failure": "Failed to delete {{amount}} metadata fields",
-  // TODO New key - Add a translation
-  "admin.registries.schema.notification.field.deleted.failure": "Failed to delete {{amount}} metadata fields",
-  
+  "admin.registries.schema.notification.field.deleted.failure": "Het verwijderen van {{amount}} metadatavelden is mislukt",
+
   // "admin.registries.schema.notification.field.deleted.success": "Successfully deleted {{amount}} metadata fields",
-  // TODO New key - Add a translation
-  "admin.registries.schema.notification.field.deleted.success": "Successfully deleted {{amount}} metadata fields",
-  
+  "admin.registries.schema.notification.field.deleted.success": "{{amount}} Metadatavelden verwijderd",
+
   // "admin.registries.schema.notification.field.edited": "Successfully edited metadata field \"{{field}}\"",
-  // TODO New key - Add a translation
-  "admin.registries.schema.notification.field.edited": "Successfully edited metadata field \"{{field}}\"",
-  
+  "admin.registries.schema.notification.field.edited": "Metadataveld \"{{field}}\" is bewerkt",
+
   // "admin.registries.schema.notification.success": "Success",
-  // TODO New key - Add a translation
-  "admin.registries.schema.notification.success": "Success",
-  
+  "admin.registries.schema.notification.success": "Succes",
+
   // "admin.registries.schema.return": "Return",
-  // TODO New key - Add a translation
-  "admin.registries.schema.return": "Return",
-  
+  "admin.registries.schema.return": "Terug",
+
   // "admin.registries.schema.title": "DSpace Angular :: Metadata Schema Registry",
   "admin.registries.schema.title": "DSpace Angular :: Metadata Schema Register",
-  
-  
-  
+
+
+
   // "auth.errors.invalid-user": "Invalid email address or password.",
   "auth.errors.invalid-user": "Ongeldig e-mailadres of wachtwoord.",
-  
+
   // "auth.messages.expired": "Your session has expired. Please log in again.",
   "auth.messages.expired": "Uw sessie is vervallen. Gelieve opnieuw aan te melden.",
-  
-  
-  
+
+
+
   // "browse.comcol.by.author": "By Author",
-  // TODO New key - Add a translation
-  "browse.comcol.by.author": "By Author",
-  
+  "browse.comcol.by.author": "Op auteur",
+
   // "browse.comcol.by.dateissued": "By Issue Date",
-  // TODO New key - Add a translation
-  "browse.comcol.by.dateissued": "By Issue Date",
-  
+  "browse.comcol.by.dateissued": "Op datum van uitgave",
+
   // "browse.comcol.by.subject": "By Subject",
-  // TODO New key - Add a translation
-  "browse.comcol.by.subject": "By Subject",
-  
+  "browse.comcol.by.subject": "Op onderwerp",
+
   // "browse.comcol.by.title": "By Title",
-  // TODO New key - Add a translation
-  "browse.comcol.by.title": "By Title",
-  
+  "browse.comcol.by.title": "Op titel",
+
   // "browse.comcol.head": "Browse",
-  // TODO New key - Add a translation
-  "browse.comcol.head": "Browse",
-  
+  "browse.comcol.head": "Blader",
+
   // "browse.empty": "No items to show.",
-  // TODO New key - Add a translation
-  "browse.empty": "No items to show.",
-  
+  "browse.empty": "Geen items om te tonen.",
+
   // "browse.metadata.author": "Author",
-  // TODO New key - Add a translation
-  "browse.metadata.author": "Author",
-  
+  "browse.metadata.author": "Auteur",
+
   // "browse.metadata.dateissued": "Issue Date",
-  // TODO New key - Add a translation
-  "browse.metadata.dateissued": "Issue Date",
-  
+  "browse.metadata.dateissued": "Datum van uitgave",
+
   // "browse.metadata.subject": "Subject",
-  // TODO New key - Add a translation
-  "browse.metadata.subject": "Subject",
-  
+  "browse.metadata.subject": "Onderwerp",
+
   // "browse.metadata.title": "Title",
-  // TODO New key - Add a translation
-  "browse.metadata.title": "Title",
-  
+  "browse.metadata.title": "Titel",
+
   // "browse.startsWith.choose_start": "(Choose start)",
-  // TODO New key - Add a translation
-  "browse.startsWith.choose_start": "(Choose start)",
-  
+  "browse.startsWith.choose_start": "(Kies begin)",
+
   // "browse.startsWith.choose_year": "(Choose year)",
-  // TODO New key - Add a translation
-  "browse.startsWith.choose_year": "(Choose year)",
-  
+  "browse.startsWith.choose_year": "(Kies jaar)",
+
   // "browse.startsWith.jump": "Jump to a point in the index:",
-  // TODO New key - Add a translation
-  "browse.startsWith.jump": "Jump to a point in the index:",
-  
+  "browse.startsWith.jump": "Ga naar een plaats in de index:",
+
   // "browse.startsWith.months.april": "April",
-  // TODO New key - Add a translation
   "browse.startsWith.months.april": "April",
-  
+
   // "browse.startsWith.months.august": "August",
-  // TODO New key - Add a translation
-  "browse.startsWith.months.august": "August",
-  
+  "browse.startsWith.months.august": "Augustus",
+
   // "browse.startsWith.months.december": "December",
-  // TODO New key - Add a translation
   "browse.startsWith.months.december": "December",
-  
+
   // "browse.startsWith.months.february": "February",
-  // TODO New key - Add a translation
-  "browse.startsWith.months.february": "February",
-  
+  "browse.startsWith.months.february": "Februari",
+
   // "browse.startsWith.months.january": "January",
-  // TODO New key - Add a translation
-  "browse.startsWith.months.january": "January",
-  
+  "browse.startsWith.months.january": "Januari",
+
   // "browse.startsWith.months.july": "July",
-  // TODO New key - Add a translation
-  "browse.startsWith.months.july": "July",
-  
+  "browse.startsWith.months.july": "Juli",
+
   // "browse.startsWith.months.june": "June",
-  // TODO New key - Add a translation
-  "browse.startsWith.months.june": "June",
-  
+  "browse.startsWith.months.june": "Juni",
+
   // "browse.startsWith.months.march": "March",
-  // TODO New key - Add a translation
-  "browse.startsWith.months.march": "March",
-  
+  "browse.startsWith.months.march": "Maart",
+
   // "browse.startsWith.months.may": "May",
-  // TODO New key - Add a translation
-  "browse.startsWith.months.may": "May",
-  
+  "browse.startsWith.months.may": "Mei",
+
   // "browse.startsWith.months.none": "(Choose month)",
-  // TODO New key - Add a translation
-  "browse.startsWith.months.none": "(Choose month)",
-  
+  "browse.startsWith.months.none": "(Kies maand)",
+
   // "browse.startsWith.months.november": "November",
-  // TODO New key - Add a translation
   "browse.startsWith.months.november": "November",
-  
+
   // "browse.startsWith.months.october": "October",
-  // TODO New key - Add a translation
-  "browse.startsWith.months.october": "October",
-  
+  "browse.startsWith.months.october": "Oktober",
+
   // "browse.startsWith.months.september": "September",
-  // TODO New key - Add a translation
   "browse.startsWith.months.september": "September",
-  
+
   // "browse.startsWith.submit": "Go",
-  // TODO New key - Add a translation
-  "browse.startsWith.submit": "Go",
-  
+  "browse.startsWith.submit": "Ga",
+
   // "browse.startsWith.type_date": "Or type in a date (year-month):",
-  // TODO New key - Add a translation
-  "browse.startsWith.type_date": "Or type in a date (year-month):",
-  
+  "browse.startsWith.type_date": "Of type een datum (jaar-maand):",
+
   // "browse.startsWith.type_text": "Or enter first few letters:",
-  // TODO New key - Add a translation
-  "browse.startsWith.type_text": "Or enter first few letters:",
-  
+  "browse.startsWith.type_text": "Or vul de eerste paar letters in:",
+
   // "browse.title": "Browsing {{ collection }} by {{ field }} {{ value }}",
   "browse.title": "Verken {{ collection }} volgens {{ field }} {{ value }}",
-  
-  
-  
+
+
+
   // "chips.remove": "Remove chip",
-  // TODO New key - Add a translation
-  "chips.remove": "Remove chip",
-  
-  
-  
+  "chips.remove": "Verwijder chip",
+
+
+
   // "collection.create.head": "Create a Collection",
-  // TODO New key - Add a translation
-  "collection.create.head": "Create a Collection",
-  
+  "collection.create.head": "Maak een collectie aan",
+
   // "collection.create.sub-head": "Create a Collection for Community {{ parent }}",
-  // TODO New key - Add a translation
-  "collection.create.sub-head": "Create a Collection for Community {{ parent }}",
-  
+  "collection.create.sub-head": "Maak een collectie voor de community {{ parent }}",
+
   // "collection.delete.cancel": "Cancel",
-  // TODO New key - Add a translation
-  "collection.delete.cancel": "Cancel",
-  
+  "collection.delete.cancel": "Annuleer",
+
   // "collection.delete.confirm": "Confirm",
-  // TODO New key - Add a translation
-  "collection.delete.confirm": "Confirm",
-  
+  "collection.delete.confirm": "Bevestig",
+
   // "collection.delete.head": "Delete Collection",
-  // TODO New key - Add a translation
-  "collection.delete.head": "Delete Collection",
-  
+  "collection.delete.head": "Verwijder Collectie",
+
   // "collection.delete.notification.fail": "Collection could not be deleted",
-  // TODO New key - Add a translation
-  "collection.delete.notification.fail": "Collection could not be deleted",
-  
+  "collection.delete.notification.fail": "De collectie kon niet verwijderd worden",
+
   // "collection.delete.notification.success": "Successfully deleted collection",
-  // TODO New key - Add a translation
-  "collection.delete.notification.success": "Successfully deleted collection",
-  
+  "collection.delete.notification.success": "De collectie is verwijderd",
+
   // "collection.delete.text": "Are you sure you want to delete collection \"{{ dso }}\"",
-  // TODO New key - Add a translation
-  "collection.delete.text": "Are you sure you want to delete collection \"{{ dso }}\"",
-  
-  
-  
+  "collection.delete.text": "Weet u zeker dat u de collectie \"{{ dso }}\" wilt verwijderen?",
+
   // "collection.edit.delete": "Delete this collection",
-  // TODO New key - Add a translation
-  "collection.edit.delete": "Delete this collection",
-  
+  "collection.edit.delete": "Verwijder deze collectie",
+
   // "collection.edit.head": "Edit Collection",
-  // TODO New key - Add a translation
-  "collection.edit.head": "Edit Collection",
-  
-  
-  
+  "collection.edit.head": "Bewerk de collectie",
+
+
+
   // "collection.edit.item-mapper.cancel": "Cancel",
-  // TODO New key - Add a translation
-  "collection.edit.item-mapper.cancel": "Cancel",
-  
+  "collection.edit.item-mapper.cancel": "Annuleer",
+
   // "collection.edit.item-mapper.collection": "Collection: \"<b>{{name}}</b>\"",
-  // TODO New key - Add a translation
-  "collection.edit.item-mapper.collection": "Collection: \"<b>{{name}}</b>\"",
-  
+   "collection.edit.item-mapper.collection": "Collectie: \"<b>{{name}}</b>\"",
+
   // "collection.edit.item-mapper.confirm": "Map selected items",
-  // TODO New key - Add a translation
-  "collection.edit.item-mapper.confirm": "Map selected items",
-  
+  "collection.edit.item-mapper.confirm": "Map de geselecteerde items",
+
   // "collection.edit.item-mapper.description": "This is the item mapper tool that allows collection administrators to map items from other collections into this collection. You can search for items from other collections and map them, or browse the list of currently mapped items.",
-  // TODO New key - Add a translation
-  "collection.edit.item-mapper.description": "This is the item mapper tool that allows collection administrators to map items from other collections into this collection. You can search for items from other collections and map them, or browse the list of currently mapped items.",
-  
+  "collection.edit.item-mapper.description": "Dit is de item mapper, waarmee collectiebeheerders items van andere collecties kunnen mappen naar deze collectie. U kunt items van andere collecties zoeken en mappen of de bladeren door de lijst met al gemapte items.",
+
   // "collection.edit.item-mapper.head": "Item Mapper - Map Items from Other Collections",
-  // TODO New key - Add a translation
-  "collection.edit.item-mapper.head": "Item Mapper - Map Items from Other Collections",
-  
+  "collection.edit.item-mapper.head": "Item mapper - Map items uit andere collecties",
+
   // "collection.edit.item-mapper.no-search": "Please enter a query to search",
-  // TODO New key - Add a translation
-  "collection.edit.item-mapper.no-search": "Please enter a query to search",
-  
+  "collection.edit.item-mapper.no-search": "Vul een zoekterm in om te zoeken",
+
   // "collection.edit.item-mapper.notifications.map.error.content": "Errors occurred for mapping of {{amount}} items.",
-  // TODO New key - Add a translation
-  "collection.edit.item-mapper.notifications.map.error.content": "Errors occurred for mapping of {{amount}} items.",
-  
+  "collection.edit.item-mapper.notifications.map.error.content": "Er is een fout opgetreden bij het mappen van {{amount}} items.",
+
   // "collection.edit.item-mapper.notifications.map.error.head": "Mapping errors",
-  // TODO New key - Add a translation
-  "collection.edit.item-mapper.notifications.map.error.head": "Mapping errors",
-  
+  "collection.edit.item-mapper.notifications.map.error.head": "Mapping fouten ",
+
   // "collection.edit.item-mapper.notifications.map.success.content": "Successfully mapped {{amount}} items.",
-  // TODO New key - Add a translation
-  "collection.edit.item-mapper.notifications.map.success.content": "Successfully mapped {{amount}} items.",
-  
+  "collection.edit.item-mapper.notifications.map.success.content": "Er zijn {{amount}} items gemapt.",
+
   // "collection.edit.item-mapper.notifications.map.success.head": "Mapping completed",
-  // TODO New key - Add a translation
-  "collection.edit.item-mapper.notifications.map.success.head": "Mapping completed",
-  
+  "collection.edit.item-mapper.notifications.map.success.head": "Mapping afgerond",
+
   // "collection.edit.item-mapper.notifications.unmap.error.content": "Errors occurred for removing the mappings of {{amount}} items.",
-  // TODO New key - Add a translation
-  "collection.edit.item-mapper.notifications.unmap.error.content": "Errors occurred for removing the mappings of {{amount}} items.",
-  
+  "collection.edit.item-mapper.notifications.unmap.error.content": "Er zijn fouten opgetreden bij het verwijderen van de mapping van {{amount}} items.",
+
   // "collection.edit.item-mapper.notifications.unmap.error.head": "Remove mapping errors",
-  // TODO New key - Add a translation
-  "collection.edit.item-mapper.notifications.unmap.error.head": "Remove mapping errors",
-  
+  "collection.edit.item-mapper.notifications.unmap.error.head": "Fouten bij het verwijderen van mappings",
+
   // "collection.edit.item-mapper.notifications.unmap.success.content": "Successfully removed the mappings of {{amount}} items.",
-  // TODO New key - Add a translation
-  "collection.edit.item-mapper.notifications.unmap.success.content": "Successfully removed the mappings of {{amount}} items.",
-  
+  "collection.edit.item-mapper.notifications.unmap.success.content": "De mappings van {{amount}} items zijn verwijderd.",
+
   // "collection.edit.item-mapper.notifications.unmap.success.head": "Remove mapping completed",
-  // TODO New key - Add a translation
-  "collection.edit.item-mapper.notifications.unmap.success.head": "Remove mapping completed",
-  
+  "collection.edit.item-mapper.notifications.unmap.success.head": "Verwijderen van mappings afgerond",
+
   // "collection.edit.item-mapper.remove": "Remove selected item mappings",
-  // TODO New key - Add a translation
-  "collection.edit.item-mapper.remove": "Remove selected item mappings",
-  
+  "collection.edit.item-mapper.remove": "Verwijder de geselecteerde item mappings",
+
   // "collection.edit.item-mapper.tabs.browse": "Browse mapped items",
-  // TODO New key - Add a translation
-  "collection.edit.item-mapper.tabs.browse": "Browse mapped items",
-  
+  "collection.edit.item-mapper.tabs.browse": "Blader door gemapte items",
+
   // "collection.edit.item-mapper.tabs.map": "Map new items",
-  // TODO New key - Add a translation
-  "collection.edit.item-mapper.tabs.map": "Map new items",
-  
-  
-  
+  "collection.edit.item-mapper.tabs.map": "Map nieuwe items",
+
+
+
   // "collection.form.abstract": "Short Description",
-  // TODO New key - Add a translation
-  "collection.form.abstract": "Short Description",
-  
+  "collection.form.abstract": "Korte beschrijving",
+
   // "collection.form.description": "Introductory text (HTML)",
-  // TODO New key - Add a translation
-  "collection.form.description": "Introductory text (HTML)",
-  
+  "collection.form.description": "Inleidende tekst (HTML)",
+
   // "collection.form.errors.title.required": "Please enter a collection name",
-  // TODO New key - Add a translation
-  "collection.form.errors.title.required": "Please enter a collection name",
-  
+  "collection.form.errors.title.required": "Vul alstublieft een collectienaam in",
+
   // "collection.form.license": "License",
-  // TODO New key - Add a translation
-  "collection.form.license": "License",
-  
+  "collection.form.license": "Licentie",
+
   // "collection.form.provenance": "Provenance",
-  // TODO New key - Add a translation
-  "collection.form.provenance": "Provenance",
-  
+  "collection.form.provenance": "Herkomst",
+
   // "collection.form.rights": "Copyright text (HTML)",
-  // TODO New key - Add a translation
-  "collection.form.rights": "Copyright text (HTML)",
-  
+  "collection.form.rights": "Auteursrechten-tekst (HTML)",
+
   // "collection.form.tableofcontents": "News (HTML)",
-  // TODO New key - Add a translation
-  "collection.form.tableofcontents": "News (HTML)",
-  
+  "collection.form.tableofcontents": "Nieuws (HTML)",
+
   // "collection.form.title": "Name",
-  // TODO New key - Add a translation
-  "collection.form.title": "Name",
-  
-  
-  
+  "collection.form.title": "Naam",
+
+
+
   // "collection.page.browse.recent.head": "Recent Submissions",
   "collection.page.browse.recent.head": "Recent toegevoegd",
-  
+
   // "collection.page.browse.recent.empty": "No items to show",
-  // TODO New key - Add a translation
-  "collection.page.browse.recent.empty": "No items to show",
-  
+  "collection.page.browse.recent.empty": "Geen items om te tonen",
+
   // "collection.page.handle": "Permanent URI for this collection",
-  // TODO New key - Add a translation
-  "collection.page.handle": "Permanent URI for this collection",
-  
+  "collection.page.handle": "Permanente URI voor deze collectie",
+
   // "collection.page.license": "License",
   "collection.page.license": "Licentie",
-  
+
   // "collection.page.news": "News",
   "collection.page.news": "Nieuws",
-  
-  
-  
+
+
+
   // "collection.select.confirm": "Confirm selected",
-  // TODO New key - Add a translation
-  "collection.select.confirm": "Confirm selected",
-  
+  "collection.select.confirm": "Bevestig uw keuze",
+
   // "collection.select.empty": "No collections to show",
-  // TODO New key - Add a translation
-  "collection.select.empty": "No collections to show",
-  
+  "collection.select.empty": "Geen collecties om te tonen",
+
   // "collection.select.table.title": "Title",
-  // TODO New key - Add a translation
-  "collection.select.table.title": "Title",
-  
-  
-  
+  "collection.select.table.title": "Titel",
+
+
+
   // "community.create.head": "Create a Community",
-  // TODO New key - Add a translation
-  "community.create.head": "Create a Community",
-  
+  "community.create.head": "Maak een community aan",
+
   // "community.create.sub-head": "Create a Sub-Community for Community {{ parent }}",
-  // TODO New key - Add a translation
-  "community.create.sub-head": "Create a Sub-Community for Community {{ parent }}",
-  
+  "community.create.sub-head": "Maak een sub-community voor community {{ parent }}",
+
   // "community.delete.cancel": "Cancel",
-  // TODO New key - Add a translation
-  "community.delete.cancel": "Cancel",
-  
+  "community.delete.cancel": "Annuleer",
+
   // "community.delete.confirm": "Confirm",
-  // TODO New key - Add a translation
-  "community.delete.confirm": "Confirm",
-  
+  "community.delete.confirm": "Bevestig",
+
   // "community.delete.head": "Delete Community",
-  // TODO New key - Add a translation
-  "community.delete.head": "Delete Community",
-  
+  "community.delete.head": "Verwijder community",
+
   // "community.delete.notification.fail": "Community could not be deleted",
-  // TODO New key - Add a translation
-  "community.delete.notification.fail": "Community could not be deleted",
-  
+  "community.delete.notification.fail": "De community kon niet verwijderd worden",
+
   // "community.delete.notification.success": "Successfully deleted community",
-  // TODO New key - Add a translation
-  "community.delete.notification.success": "Successfully deleted community",
-  
+  "community.delete.notification.success": "Community succesvol verwijderd",
+
   // "community.delete.text": "Are you sure you want to delete community \"{{ dso }}\"",
-  // TODO New key - Add a translation
-  "community.delete.text": "Are you sure you want to delete community \"{{ dso }}\"",
-  
+  "community.delete.text": "Weet u zeker dat u community \"{{ dso }}\" wilt verwijderen?",
+
   // "community.edit.delete": "Delete this community",
-  // TODO New key - Add a translation
-  "community.edit.delete": "Delete this community",
-  
+  "community.edit.delete": "Verwijder deze community",
+
   // "community.edit.head": "Edit Community",
-  // TODO New key - Add a translation
-  "community.edit.head": "Edit Community",
-  
+  "community.edit.head": "Bewerk community",
+
   // "community.form.abstract": "Short Description",
-  // TODO New key - Add a translation
-  "community.form.abstract": "Short Description",
-  
+  "community.form.abstract": "Korte beschrijving",
+
   // "community.form.description": "Introductory text (HTML)",
-  // TODO New key - Add a translation
-  "community.form.description": "Introductory text (HTML)",
-  
+  "community.form.description": "Inleidende tekst (HTML)",
+
   // "community.form.errors.title.required": "Please enter a community name",
-  // TODO New key - Add a translation
-  "community.form.errors.title.required": "Please enter a community name",
-  
+  "community.form.errors.title.required": "Vul alstublieft een communitynaam in",
+
   // "community.form.rights": "Copyright text (HTML)",
-  // TODO New key - Add a translation
-  "community.form.rights": "Copyright text (HTML)",
-  
+  "community.form.rights": "Auteursrechten-tekst (HTML)",
+
   // "community.form.tableofcontents": "News (HTML)",
-  // TODO New key - Add a translation
-  "community.form.tableofcontents": "News (HTML)",
-  
+  "community.form.tableofcontents": "Nieuws (HTML)",
+
   // "community.form.title": "Name",
-  // TODO New key - Add a translation
-  "community.form.title": "Name",
-  
+  "community.form.title": "Naam",
+
   // "community.page.handle": "Permanent URI for this community",
-  // TODO New key - Add a translation
-  "community.page.handle": "Permanent URI for this community",
-  
+  "community.page.handle": "Permanente URI voor deze community",
+
   // "community.page.license": "License",
   "community.page.license": "Licentie",
-  
+
   // "community.page.news": "News",
   "community.page.news": "Nieuws",
-  
+
   // "community.all-lists.head": "Subcommunities and Collections",
-  // TODO New key - Add a translation
-  "community.all-lists.head": "Subcommunities and Collections",
-  
+  "community.all-lists.head": "Subcommunities en collecties",
+
   // "community.sub-collection-list.head": "Collections of this Community",
-  "community.sub-collection-list.head": "Collecties in deze Community",
-  
+  "community.sub-collection-list.head": "Collecties in deze community",
+
   // "community.sub-community-list.head": "Communities of this Community",
-  // TODO New key - Add a translation
-  "community.sub-community-list.head": "Communities of this Community",
-  
-  
-  
+  "community.sub-community-list.head": "Communities in deze community",
+
+
+
   // "dso-selector.create.collection.head": "New collection",
-  // TODO New key - Add a translation
-  "dso-selector.create.collection.head": "New collection",
-  
+  "dso-selector.create.collection.head": "Nieuwe collectie",
+
   // "dso-selector.create.community.head": "New community",
-  // TODO New key - Add a translation
-  "dso-selector.create.community.head": "New community",
-  
+  "dso-selector.create.community.head": "Nieuwe community",
+
   // "dso-selector.create.community.sub-level": "Create a new community in",
-  // TODO New key - Add a translation
-  "dso-selector.create.community.sub-level": "Create a new community in",
-  
+  "dso-selector.create.community.sub-level": "Maak een nieuwe community in",
+
   // "dso-selector.create.community.top-level": "Create a new top-level community",
-  // TODO New key - Add a translation
-  "dso-selector.create.community.top-level": "Create a new top-level community",
-  
+  "dso-selector.create.community.top-level": "Maak een nieuwe community op het hoogste niveau",
+
   // "dso-selector.create.item.head": "New item",
-  // TODO New key - Add a translation
-  "dso-selector.create.item.head": "New item",
-  
+  "dso-selector.create.item.head": "Nieuw item",
+
   // "dso-selector.edit.collection.head": "Edit collection",
-  // TODO New key - Add a translation
-  "dso-selector.edit.collection.head": "Edit collection",
-  
+  "dso-selector.edit.collection.head": "Bewerk collectie",
+
   // "dso-selector.edit.community.head": "Edit community",
-  // TODO New key - Add a translation
-  "dso-selector.edit.community.head": "Edit community",
-  
+  "dso-selector.edit.community.head": "Bewerk community",
+
   // "dso-selector.edit.item.head": "Edit item",
-  // TODO New key - Add a translation
-  "dso-selector.edit.item.head": "Edit item",
-  
+  "dso-selector.edit.item.head": "Bewerk item",
+
   // "dso-selector.no-results": "No {{ type }} found",
-  // TODO New key - Add a translation
-  "dso-selector.no-results": "No {{ type }} found",
-  
+  "dso-selector.no-results": "Geen {{ type }} gevonden",
+
   // "dso-selector.placeholder": "Search for a {{ type }}",
-  // TODO New key - Add a translation
-  "dso-selector.placeholder": "Search for a {{ type }}",
-  
-  
-  
+  "dso-selector.placeholder": "Zoek een {{ type }}",
+
+
+
   // "error.browse-by": "Error fetching items",
   "error.browse-by": "Fout bij het ophalen van items",
-  
+
   // "error.collection": "Error fetching collection",
   "error.collection": "Fout bij het ophalen van een collectie",
-  
+
   // "error.collections": "Error fetching collections",
-  // TODO New key - Add a translation
-  "error.collections": "Error fetching collections",
-  
+  "error.collections": "Fout bij het ophalen van de collecties",
+
   // "error.community": "Error fetching community",
   "error.community": "Fout bij het ophalen van een community",
+
   // "error.identifier": "No item found for the identifier",
-  // TODO New key - Add a translation
-  "error.identifier": "No item found for the identifier",
-  
-  // "error.identifier": "No item found for the identifier",
-  // TODO New key - Add a translation
-  "error.identifier": "No item found for the identifier",
-  
+  "error.identifier": "Geen item gevonden voor deze identifier",
+
   // "error.default": "Error",
   "error.default": "Fout",
-  
+
   // "error.item": "Error fetching item",
-  "error.item": "Fout bij het ophalen van items",
-  
+  "error.item": "Fout bij het ophalen van het item",
+
   // "error.items": "Error fetching items",
-  // TODO New key - Add a translation
-  "error.items": "Error fetching items",
-  
+  "error.items": "Fout bij het ophalen van items",
+
   // "error.objects": "Error fetching objects",
   "error.objects": "Fout bij het ophalen van objecten",
-  
+
   // "error.recent-submissions": "Error fetching recent submissions",
   "error.recent-submissions": "Fout bij het ophalen van recent toegevoegde items",
-  
+
   // "error.search-results": "Error fetching search results",
   "error.search-results": "Fout bij het ophalen van zoekresultaten",
-  
+
   // "error.sub-collections": "Error fetching sub-collections",
   "error.sub-collections": "Fout bij het ophalen van sub-collecties",
-  
+
   // "error.sub-communities": "Error fetching sub-communities",
-  // TODO New key - Add a translation
-  "error.sub-communities": "Error fetching sub-communities",
-  
+  "error.sub-communities": "Fout bij het ophalen van sub-communities",
+
   // "error.submission.sections.init-form-error": "An error occurred during section initialize, please check your input-form configuration. Details are below : <br> <br>",
-  // TODO New key - Add a translation
-  "error.submission.sections.init-form-error": "An error occurred during section initialize, please check your input-form configuration. Details are below : <br> <br>",
-  
+  "error.submission.sections.init-form-error": "Er is een fout opgetreden bij het initialiseren van deze sectie. Controleer de configuratie van het invoerformulier. Details: <br> <br>",
+
   // "error.top-level-communities": "Error fetching top-level communities",
   "error.top-level-communities": "Fout bij het inladen van communities op het hoogste niveau",
-  
+
   // "error.validation.license.notgranted": "You must grant this license to complete your submission. If you are unable to grant this license at this time you may save your work and return later or remove the submission.",
-  "error.validation.license.notgranted": "U moet de invoerlicentie goedkeuren om de invoer af te werken. Indien u deze licentie momenteel niet kan of mag goedkeuren, kan u uw werk opslaan en de invoer later afwerken. U kunt dit nieuwe item ook verwijderen indien u niet voldoet aan de vereisten van de invoerlicentie.",
-  
+  "error.validation.license.notgranted": "U moet de invoerlicentie goedkeuren om de invoer af te werken. Indien u deze licentie momenteel niet kan of mag goedkeuren, kunt u uw werk opslaan en de invoer later afwerken. U kunt dit nieuwe item ook verwijderen indien u niet voldoet aan de vereisten van de invoerlicentie.",
+
   // "error.validation.pattern": "This input is restricted by the current pattern: {{ pattern }}.",
-  // TODO New key - Add a translation
-  "error.validation.pattern": "This input is restricted by the current pattern: {{ pattern }}.",
-  
-  
-  
+  "error.validation.pattern": "Deze invoer wordt ingeperkt door dit patroon: {{ pattern }}.",
+
+
+
   // "footer.copyright": "copyright © 2002-{{ year }}",
   "footer.copyright": "copyright © 2002-{{ year }}",
-  
+
   // "footer.link.dspace": "DSpace software",
   "footer.link.dspace": "DSpace software",
-  
+
   // "footer.link.duraspace": "DuraSpace",
   "footer.link.duraspace": "DuraSpace",
-  
-  
-  
+
+
+
   // "form.cancel": "Cancel",
   "form.cancel": "Annuleer",
-  
+
   // "form.clear": "Clear",
-  // TODO New key - Add a translation
-  "form.clear": "Clear",
-  
+  "form.clear": "Maak leeg",
+
   // "form.clear-help": "Click here to remove the selected value",
-  // TODO New key - Add a translation
-  "form.clear-help": "Click here to remove the selected value",
-  
+  "form.clear-help": "Klik hier om de geselecteerde waarde the verwijderen",
+
   // "form.edit": "Edit",
-  // TODO New key - Add a translation
-  "form.edit": "Edit",
-  
+  "form.edit": "Bewerk",
+
   // "form.edit-help": "Click here to edit the selected value",
-  // TODO New key - Add a translation
-  "form.edit-help": "Click here to edit the selected value",
-  
+  "form.edit-help": "Klik hier om de geselecteerde waarde te bewerken",
+
   // "form.first-name": "First name",
   "form.first-name": "Voornaam",
-  
+
   // "form.group-collapse": "Collapse",
   "form.group-collapse": "Inklappen",
-  
+
   // "form.group-collapse-help": "Click here to collapse",
   "form.group-collapse-help": "Klik hier op in te klappen",
-  
+
   // "form.group-expand": "Expand",
   "form.group-expand": "Uitklappen",
-  
+
   // "form.group-expand-help": "Click here to expand and add more elements",
   "form.group-expand-help": "Klik hier om uit te klappen en om meer onderdelen toe te voegen",
-  
+
   // "form.last-name": "Last name",
   "form.last-name": "Achternaam",
-  
+
   // "form.loading": "Loading...",
   "form.loading": "Inladen...",
-  
+
   // "form.no-results": "No results found",
   "form.no-results": "Geen resultaten gevonden",
-  
+
   // "form.no-value": "No value entered",
   "form.no-value": "Geen waarde ingevoerd",
-  
+
   // "form.other-information": {},
-  // TODO New key - Add a translation
   "form.other-information": {},
-  
+
   // "form.remove": "Remove",
   "form.remove": "Verwijder",
-  
+
   // "form.save": "Save",
-  // TODO New key - Add a translation
-  "form.save": "Save",
-  
+  "form.save": "Bewaar",
+
   // "form.save-help": "Save changes",
-  // TODO New key - Add a translation
-  "form.save-help": "Save changes",
-  
+  "form.save-help": "Veranderingen opslaan",
+
   // "form.search": "Search",
   "form.search": "Zoek",
-  
+
   // "form.search-help": "Click here to looking for an existing correspondence",
   // TODO New key - Add a translation
   "form.search-help": "Click here to looking for an existing correspondence",
-  
+
   // "form.submit": "Submit",
   "form.submit": "Verstuur",
-  
-  
-  
+
+
+
   // "home.description": "",
   "home.description": "",
-  
+
   // "home.title": "DSpace Angular :: Home",
   "home.title": "DSpace Angular :: Home",
-  
+
   // "home.top-level-communities.head": "Communities in DSpace",
   "home.top-level-communities.head": "Communities in DSpace",
-  
+
   // "home.top-level-communities.help": "Select a community to browse its collections.",
   "home.top-level-communities.help": "Selecteer een community om diens collecties te verkennen.",
-  
-  
-  
+
+
+
   // "item.edit.delete.cancel": "Cancel",
-  // TODO New key - Add a translation
-  "item.edit.delete.cancel": "Cancel",
-  
+  "item.edit.delete.cancel": "Annuleer",
+
   // "item.edit.delete.confirm": "Delete",
-  // TODO New key - Add a translation
-  "item.edit.delete.confirm": "Delete",
-  
+  "item.edit.delete.confirm": "Verwijder",
+
   // "item.edit.delete.description": "Are you sure this item should be completely deleted? Caution: At present, no tombstone would be left.",
-  // TODO New key - Add a translation
-  "item.edit.delete.description": "Are you sure this item should be completely deleted? Caution: At present, no tombstone would be left.",
-  
+  "item.edit.delete.description": "Weet u zeker dat dit item geheel verwijderd moet worden? Pas op: er zal geen tombstone overblijven.",
+
   // "item.edit.delete.error": "An error occurred while deleting the item",
-  // TODO New key - Add a translation
-  "item.edit.delete.error": "An error occurred while deleting the item",
-  
+  "item.edit.delete.error": "Er is een fout opgetreden bij het verwijderen van het item",
+
   // "item.edit.delete.header": "Delete item: {{ id }}",
-  // TODO New key - Add a translation
-  "item.edit.delete.header": "Delete item: {{ id }}",
-  
+  "item.edit.delete.header": "Verwijder item: {{ id }}",
+
   // "item.edit.delete.success": "The item has been deleted",
-  // TODO New key - Add a translation
-  "item.edit.delete.success": "The item has been deleted",
-  
+  "item.edit.delete.success": "Het item is verwijderd",
+
   // "item.edit.head": "Edit Item",
-  // TODO New key - Add a translation
-  "item.edit.head": "Edit Item",
-  
-  
-  
+  "item.edit.head": "Bewerk item",
+
+
+
   // "item.edit.item-mapper.buttons.add": "Map item to selected collections",
-  // TODO New key - Add a translation
-  "item.edit.item-mapper.buttons.add": "Map item to selected collections",
-  
+  "item.edit.item-mapper.buttons.add": "Map dit item naar de geselecteerde collecties",
+
   // "item.edit.item-mapper.buttons.remove": "Remove item's mapping for selected collections",
-  // TODO New key - Add a translation
-  "item.edit.item-mapper.buttons.remove": "Remove item's mapping for selected collections",
-  
+  "item.edit.item-mapper.buttons.remove": "Verwijder de mapping van de item naar de geselecteerde collecties",
+
   // "item.edit.item-mapper.cancel": "Cancel",
-  // TODO New key - Add a translation
-  "item.edit.item-mapper.cancel": "Cancel",
-  
+  "item.edit.item-mapper.cancel": "Annuleer",
+
   // "item.edit.item-mapper.description": "This is the item mapper tool that allows administrators to map this item to other collections. You can search for collections and map them, or browse the list of collections the item is currently mapped to.",
-  // TODO New key - Add a translation
-  "item.edit.item-mapper.description": "This is the item mapper tool that allows administrators to map this item to other collections. You can search for collections and map them, or browse the list of collections the item is currently mapped to.",
-  
+  "item.edit.item-mapper.description": "Dit is de item mapper, waarmee collectiebeheerders dit item kunnen mappen naar andere collecties. U kunt collecties zoeken en mappen of bladeren door de lijst waar dit item al naar is gemapt.",
+
   // "item.edit.item-mapper.head": "Item Mapper - Map Item to Collections",
-  // TODO New key - Add a translation
-  "item.edit.item-mapper.head": "Item Mapper - Map Item to Collections",
-  
+  "item.edit.item-mapper.head": "Item mapper - Map een item naar collecties",
+
   // "item.edit.item-mapper.item": "Item: \"<b>{{name}}</b>\"",
-  // TODO New key - Add a translation
   "item.edit.item-mapper.item": "Item: \"<b>{{name}}</b>\"",
-  
+
   // "item.edit.item-mapper.no-search": "Please enter a query to search",
-  // TODO New key - Add a translation
-  "item.edit.item-mapper.no-search": "Please enter a query to search",
-  
+  "item.edit.item-mapper.no-search": "Vul een zoekterm in om te zoeken",
+
   // "item.edit.item-mapper.notifications.add.error.content": "Errors occurred for mapping of item to {{amount}} collections.",
-  // TODO New key - Add a translation
-  "item.edit.item-mapper.notifications.add.error.content": "Errors occurred for mapping of item to {{amount}} collections.",
-  
+   "item.edit.item-mapper.notifications.add.error.content": "Er zijn fouten opgetreden bij het mappen van het item naar {{amount}} collecties.",
+
   // "item.edit.item-mapper.notifications.add.error.head": "Mapping errors",
-  // TODO New key - Add a translation
-  "item.edit.item-mapper.notifications.add.error.head": "Mapping errors",
-  
+   "item.edit.item-mapper.notifications.add.error.head": "Mapping fouten",
+
   // "item.edit.item-mapper.notifications.add.success.content": "Successfully mapped item to {{amount}} collections.",
-  // TODO New key - Add a translation
-  "item.edit.item-mapper.notifications.add.success.content": "Successfully mapped item to {{amount}} collections.",
-  
+  "item.edit.item-mapper.notifications.add.success.content": "Het item is naar {{amount}} collecties gemapt.",
+
   // "item.edit.item-mapper.notifications.add.success.head": "Mapping completed",
-  // TODO New key - Add a translation
-  "item.edit.item-mapper.notifications.add.success.head": "Mapping completed",
-  
+  "item.edit.item-mapper.notifications.add.success.head": "Mapping afgerond",
+
   // "item.edit.item-mapper.notifications.remove.error.content": "Errors occurred for the removal of the mapping to {{amount}} collections.",
-  // TODO New key - Add a translation
-  "item.edit.item-mapper.notifications.remove.error.content": "Errors occurred for the removal of the mapping to {{amount}} collections.",
-  
+  "item.edit.item-mapper.notifications.remove.error.content": "Er zijn fouten opgetreden bij het verwijderen van de mapping naar {{amount}} collecties.",
+
   // "item.edit.item-mapper.notifications.remove.error.head": "Removal of mapping errors",
-  // TODO New key - Add a translation
-  "item.edit.item-mapper.notifications.remove.error.head": "Removal of mapping errors",
-  
+  "item.edit.item-mapper.notifications.remove.error.head": "Fouten bij het verwijderen van mappings",
+
   // "item.edit.item-mapper.notifications.remove.success.content": "Successfully removed mapping of item to {{amount}} collections.",
-  // TODO New key - Add a translation
-  "item.edit.item-mapper.notifications.remove.success.content": "Successfully removed mapping of item to {{amount}} collections.",
-  
+  "item.edit.item-mapper.notifications.remove.success.content": "De mapping van dit item naar {{amount}} collecties is verwijderd.",
+
   // "item.edit.item-mapper.notifications.remove.success.head": "Removal of mapping completed",
-  // TODO New key - Add a translation
-  "item.edit.item-mapper.notifications.remove.success.head": "Removal of mapping completed",
-  
+  "item.edit.item-mapper.notifications.remove.success.head": "Verwijderen van mapping afgerond",
+
   // "item.edit.item-mapper.tabs.browse": "Browse mapped collections",
-  // TODO New key - Add a translation
-  "item.edit.item-mapper.tabs.browse": "Browse mapped collections",
-  
+  "item.edit.item-mapper.tabs.browse": "Blader door gemapte collecties",
+
   // "item.edit.item-mapper.tabs.map": "Map new collections",
-  // TODO New key - Add a translation
-  "item.edit.item-mapper.tabs.map": "Map new collections",
-  
-  
-  
+  "item.edit.item-mapper.tabs.map": "Map een nieuwe collectie",
+
+
+
   // "item.edit.metadata.add-button": "Add",
-  // TODO New key - Add a translation
-  "item.edit.metadata.add-button": "Add",
-  
+  "item.edit.metadata.add-button": "Voeg toe",
+
   // "item.edit.metadata.discard-button": "Discard",
-  // TODO New key - Add a translation
-  "item.edit.metadata.discard-button": "Discard",
-  
+  "item.edit.metadata.discard-button": "Annuleer",
+
   // "item.edit.metadata.edit.buttons.edit": "Edit",
-  // TODO New key - Add a translation
-  "item.edit.metadata.edit.buttons.edit": "Edit",
-  
+  "item.edit.metadata.edit.buttons.edit": "Bewerk",
+
   // "item.edit.metadata.edit.buttons.remove": "Remove",
-  // TODO New key - Add a translation
-  "item.edit.metadata.edit.buttons.remove": "Remove",
-  
+  "item.edit.metadata.edit.buttons.remove": "Verwijder",
+
   // "item.edit.metadata.edit.buttons.undo": "Undo changes",
-  // TODO New key - Add a translation
-  "item.edit.metadata.edit.buttons.undo": "Undo changes",
-  
+  "item.edit.metadata.edit.buttons.undo": "Maak wijzigingen ongedaan",
+
   // "item.edit.metadata.edit.buttons.unedit": "Stop editing",
-  // TODO New key - Add a translation
-  "item.edit.metadata.edit.buttons.unedit": "Stop editing",
-  
+  "item.edit.metadata.edit.buttons.unedit": "Stop met bewerken",
+
   // "item.edit.metadata.headers.edit": "Edit",
-  // TODO New key - Add a translation
-  "item.edit.metadata.headers.edit": "Edit",
-  
+  "item.edit.metadata.headers.edit": "Bewerk",
+
   // "item.edit.metadata.headers.field": "Field",
-  // TODO New key - Add a translation
-  "item.edit.metadata.headers.field": "Field",
-  
+  "item.edit.metadata.headers.field": "Veld",
+
   // "item.edit.metadata.headers.language": "Lang",
-  // TODO New key - Add a translation
-  "item.edit.metadata.headers.language": "Lang",
-  
+  "item.edit.metadata.headers.language": "Taal",
+
   // "item.edit.metadata.headers.value": "Value",
-  // TODO New key - Add a translation
-  "item.edit.metadata.headers.value": "Value",
-  
+  "item.edit.metadata.headers.value": "Waarde",
+
   // "item.edit.metadata.metadatafield.invalid": "Please choose a valid metadata field",
-  // TODO New key - Add a translation
-  "item.edit.metadata.metadatafield.invalid": "Please choose a valid metadata field",
-  
+  "item.edit.metadata.metadatafield.invalid": "Kies een geldig metadataveld",
+
   // "item.edit.metadata.notifications.discarded.content": "Your changes were discarded. To reinstate your changes click the 'Undo' button",
-  // TODO New key - Add a translation
-  "item.edit.metadata.notifications.discarded.content": "Your changes were discarded. To reinstate your changes click the 'Undo' button",
-  
+  "item.edit.metadata.notifications.discarded.content": "Uw wijzigingen zijn geannuleerd. Klik 'maak ongedaan' om ze terug te halen.",
+
   // "item.edit.metadata.notifications.discarded.title": "Changed discarded",
-  // TODO New key - Add a translation
-  "item.edit.metadata.notifications.discarded.title": "Changed discarded",
-  
+  "item.edit.metadata.notifications.discarded.title": "Wijzingen geannuleerd",
+
   // "item.edit.metadata.notifications.invalid.content": "Your changes were not saved. Please make sure all fields are valid before you save.",
-  // TODO New key - Add a translation
-  "item.edit.metadata.notifications.invalid.content": "Your changes were not saved. Please make sure all fields are valid before you save.",
-  
+  "item.edit.metadata.notifications.invalid.content": "Uw wijzingen zijn niet opgeslagen. Controleer of alle velden geldig zijn voor u opslaat.",
+
   // "item.edit.metadata.notifications.invalid.title": "Metadata invalid",
-  // TODO New key - Add a translation
-  "item.edit.metadata.notifications.invalid.title": "Metadata invalid",
-  
+  "item.edit.metadata.notifications.invalid.title": "Ongeldige metadata",
+
   // "item.edit.metadata.notifications.outdated.content": "The item you're currently working on has been changed by another user. Your current changes are discarded to prevent conflicts",
-  // TODO New key - Add a translation
-  "item.edit.metadata.notifications.outdated.content": "The item you're currently working on has been changed by another user. Your current changes are discarded to prevent conflicts",
-  
+  "item.edit.metadata.notifications.outdated.content": "Het item waar u aan werkt is gewijzigd door een andere gebruiker. Uw huidige wijzigingen worden geannuleerd om conflicten te voorkomen.",
+
   // "item.edit.metadata.notifications.outdated.title": "Changed outdated",
-  // TODO New key - Add a translation
-  "item.edit.metadata.notifications.outdated.title": "Changed outdated",
-  
+  "item.edit.metadata.notifications.outdated.title": "Wijzigingen verouderd",
+
   // "item.edit.metadata.notifications.saved.content": "Your changes to this item's metadata were saved.",
-  // TODO New key - Add a translation
-  "item.edit.metadata.notifications.saved.content": "Your changes to this item's metadata were saved.",
-  
+  "item.edit.metadata.notifications.saved.content": "Uw wijzingen in de metadata van dit item zijn opgeslagen.",
+
   // "item.edit.metadata.notifications.saved.title": "Metadata saved",
-  // TODO New key - Add a translation
-  "item.edit.metadata.notifications.saved.title": "Metadata saved",
-  
+  "item.edit.metadata.notifications.saved.title": "Metadata opgeslagen",
+
   // "item.edit.metadata.reinstate-button": "Undo",
-  // TODO New key - Add a translation
-  "item.edit.metadata.reinstate-button": "Undo",
-  
+  "item.edit.metadata.reinstate-button": "Maak ongedaan",
+
   // "item.edit.metadata.save-button": "Save",
-  // TODO New key - Add a translation
-  "item.edit.metadata.save-button": "Save",
-  
-  
-  
+  "item.edit.metadata.save-button": "Opslaan",
+
+
+
   // "item.edit.modify.overview.field": "Field",
-  // TODO New key - Add a translation
-  "item.edit.modify.overview.field": "Field",
-  
+  "item.edit.modify.overview.field": "Veld",
+
   // "item.edit.modify.overview.language": "Language",
-  // TODO New key - Add a translation
-  "item.edit.modify.overview.language": "Language",
-  
+  "item.edit.modify.overview.language": "Taal",
+
   // "item.edit.modify.overview.value": "Value",
-  // TODO New key - Add a translation
-  "item.edit.modify.overview.value": "Value",
-  
-  
-  
+  "item.edit.modify.overview.value": "Waarde",
+
+
+
   // "item.edit.move.cancel": "Cancel",
-  // TODO New key - Add a translation
-  "item.edit.move.cancel": "Cancel",
-  
+  "item.edit.move.cancel": "Annuleer",
+
   // "item.edit.move.description": "Select the collection you wish to move this item to. To narrow down the list of displayed collections, you can enter a search query in the box.",
-  // TODO New key - Add a translation
-  "item.edit.move.description": "Select the collection you wish to move this item to. To narrow down the list of displayed collections, you can enter a search query in the box.",
-  
+  "item.edit.move.description": "Kies de collectie waar u dit item naartoe wilt verplaatsen. Om de lijst met collecties in te perken kunt een zoekterm invullen in het zoekveld.",
+
   // "item.edit.move.error": "An error occurred when attempting to move the item",
-  // TODO New key - Add a translation
-  "item.edit.move.error": "An error occurred when attempting to move the item",
-  
+  "item.edit.move.error": "Er is een fout opgetreden bij het verplaatsen van het item",
+
   // "item.edit.move.head": "Move item: {{id}}",
-  // TODO New key - Add a translation
-  "item.edit.move.head": "Move item: {{id}}",
-  
+  "item.edit.move.head": "Verplaats item: {{id}}",
+
   // "item.edit.move.inheritpolicies.checkbox": "Inherit policies",
-  // TODO New key - Add a translation
-  "item.edit.move.inheritpolicies.checkbox": "Inherit policies",
-  
+  "item.edit.move.inheritpolicies.checkbox": "Erf policies",
+
   // "item.edit.move.inheritpolicies.description": "Inherit the default policies of the destination collection",
-  // TODO New key - Add a translation
-  "item.edit.move.inheritpolicies.description": "Inherit the default policies of the destination collection",
-  
+   "item.edit.move.inheritpolicies.description": "Neem de standaard policies van de doelcollectie over",
+
   // "item.edit.move.move": "Move",
-  // TODO New key - Add a translation
-  "item.edit.move.move": "Move",
-  
+  "item.edit.move.move": "Verplaats",
+
   // "item.edit.move.processing": "Moving...",
-  // TODO New key - Add a translation
-  "item.edit.move.processing": "Moving...",
-  
+  "item.edit.move.processing": "Bezig ...",
+
   // "item.edit.move.search.placeholder": "Enter a search query to look for collections",
-  // TODO New key - Add a translation
-  "item.edit.move.search.placeholder": "Enter a search query to look for collections",
-  
+  "item.edit.move.search.placeholder": "Vul een zoekterm in om collecties te zoeken",
+
   // "item.edit.move.success": "The item has been moved successfully",
-  // TODO New key - Add a translation
-  "item.edit.move.success": "The item has been moved successfully",
-  
+  "item.edit.move.success": "Het item is verplaatst",
+
   // "item.edit.move.title": "Move item",
-  // TODO New key - Add a translation
-  "item.edit.move.title": "Move item",
-  
-  
-  
+  "item.edit.move.title": "Verplaats item",
+
+
+
   // "item.edit.private.cancel": "Cancel",
-  // TODO New key - Add a translation
-  "item.edit.private.cancel": "Cancel",
-  
+  "item.edit.private.cancel": "Annuleer",
+
   // "item.edit.private.confirm": "Make it Private",
-  // TODO New key - Add a translation
-  "item.edit.private.confirm": "Make it Private",
-  
+   "item.edit.private.confirm": "Maak privé",
+
   // "item.edit.private.description": "Are you sure this item should be made private in the archive?",
-  // TODO New key - Add a translation
-  "item.edit.private.description": "Are you sure this item should be made private in the archive?",
-  
+  "item.edit.private.description": "Weet u zeker dat dit item privé moet worden in het archief?",
+
   // "item.edit.private.error": "An error occurred while making the item private",
-  // TODO New key - Add a translation
-  "item.edit.private.error": "An error occurred while making the item private",
-  
+  "item.edit.private.error": "Er is een fout opgetreden bij het privé maken van het item",
+
   // "item.edit.private.header": "Make item private: {{ id }}",
-  // TODO New key - Add a translation
-  "item.edit.private.header": "Make item private: {{ id }}",
-  
+  "item.edit.private.header": "Maak item privé: {{ id }}",
+
   // "item.edit.private.success": "The item is now private",
-  // TODO New key - Add a translation
-  "item.edit.private.success": "The item is now private",
-  
-  
-  
+   "item.edit.private.success": "Dit item is nu privé",
+
+
+
   // "item.edit.public.cancel": "Cancel",
-  // TODO New key - Add a translation
-  "item.edit.public.cancel": "Cancel",
-  
+  "item.edit.public.cancel": "Annuleer",
+
   // "item.edit.public.confirm": "Make it Public",
-  // TODO New key - Add a translation
-  "item.edit.public.confirm": "Make it Public",
-  
+  "item.edit.public.confirm": "Maak openbaar",
+
   // "item.edit.public.description": "Are you sure this item should be made public in the archive?",
-  // TODO New key - Add a translation
-  "item.edit.public.description": "Are you sure this item should be made public in the archive?",
-  
+  "item.edit.public.description": "Weet u zeker dat dit item openbaar moet worden in het archief?",
+
   // "item.edit.public.error": "An error occurred while making the item public",
-  // TODO New key - Add a translation
-  "item.edit.public.error": "An error occurred while making the item public",
-  
+  "item.edit.public.error": "Er is een fout opgetreden bij het openbaar maken van het item",
+
   // "item.edit.public.header": "Make item public: {{ id }}",
-  // TODO New key - Add a translation
-  "item.edit.public.header": "Make item public: {{ id }}",
-  
+  "item.edit.public.header": "Maak item openbaar: {{ id }}",
+
   // "item.edit.public.success": "The item is now public",
-  // TODO New key - Add a translation
-  "item.edit.public.success": "The item is now public",
-  
-  
-  
+  "item.edit.public.success": "Het item is nu openbaar",
+
+
+
   // "item.edit.reinstate.cancel": "Cancel",
-  // TODO New key - Add a translation
-  "item.edit.reinstate.cancel": "Cancel",
-  
+  "item.edit.reinstate.cancel": "Annuleer",
+
   // "item.edit.reinstate.confirm": "Reinstate",
-  // TODO New key - Add a translation
-  "item.edit.reinstate.confirm": "Reinstate",
-  
+   "item.edit.reinstate.confirm": "Zet terug",
+
   // "item.edit.reinstate.description": "Are you sure this item should be reinstated to the archive?",
-  // TODO New key - Add a translation
-  "item.edit.reinstate.description": "Are you sure this item should be reinstated to the archive?",
-  
+   "item.edit.reinstate.description": "Weet u zeker dat dit item weer teruggezet moet worden in het archief?",
+
   // "item.edit.reinstate.error": "An error occurred while reinstating the item",
-  // TODO New key - Add a translation
-  "item.edit.reinstate.error": "An error occurred while reinstating the item",
-  
+  "item.edit.reinstate.error": "Er is een fout opgetreden bij het terugzetten van het item",
+
   // "item.edit.reinstate.header": "Reinstate item: {{ id }}",
-  // TODO New key - Add a translation
-  "item.edit.reinstate.header": "Reinstate item: {{ id }}",
-  
+  "item.edit.reinstate.header": "Zet item terug: {{ id }}",
+
   // "item.edit.reinstate.success": "The item was reinstated successfully",
-  // TODO New key - Add a translation
-  "item.edit.reinstate.success": "The item was reinstated successfully",
-  
-  
-  
+  "item.edit.reinstate.success": "Het item is teruggezet",
+
+
+
   // "item.edit.relationships.discard-button": "Discard",
-  // TODO New key - Add a translation
-  "item.edit.relationships.discard-button": "Discard",
-  
+  "item.edit.relationships.discard-button": "Annuleer",
+
   // "item.edit.relationships.edit.buttons.remove": "Remove",
-  // TODO New key - Add a translation
-  "item.edit.relationships.edit.buttons.remove": "Remove",
-  
+  "item.edit.relationships.edit.buttons.remove": "Verwijder",
+
   // "item.edit.relationships.edit.buttons.undo": "Undo changes",
-  // TODO New key - Add a translation
-  "item.edit.relationships.edit.buttons.undo": "Undo changes",
-  
+   "item.edit.relationships.edit.buttons.undo": "Maak wijzigingen ongedaan",
+
   // "item.edit.relationships.notifications.discarded.content": "Your changes were discarded. To reinstate your changes click the 'Undo' button",
-  // TODO New key - Add a translation
-  "item.edit.relationships.notifications.discarded.content": "Your changes were discarded. To reinstate your changes click the 'Undo' button",
-  
+   "item.edit.relationships.notifications.discarded.content": "Uw wijzigingen zijn ongedaan gemaakt. Klik 'maak ongedaan' om ze weer terug te halen.",
+
   // "item.edit.relationships.notifications.discarded.title": "Changes discarded",
-  // TODO New key - Add a translation
-  "item.edit.relationships.notifications.discarded.title": "Changes discarded",
-  
+  "item.edit.relationships.notifications.discarded.title": "Wijzingen geannuleerd",
+
   // "item.edit.relationships.notifications.failed.title": "Error deleting relationship",
-  // TODO New key - Add a translation
-  "item.edit.relationships.notifications.failed.title": "Error deleting relationship",
-  
+  "item.edit.relationships.notifications.failed.title": "Er is een fout opgetreden bij het verwijderen van een relatie",
+
   // "item.edit.relationships.notifications.outdated.content": "The item you're currently working on has been changed by another user. Your current changes are discarded to prevent conflicts",
-  // TODO New key - Add a translation
-  "item.edit.relationships.notifications.outdated.content": "The item you're currently working on has been changed by another user. Your current changes are discarded to prevent conflicts",
-  
+  "item.edit.relationships.notifications.outdated.content": "Het item waar u aan werkt is gewijzigd door een andere gebruiker. Uw huidige wijzigingen zijn ongedaan gemaakt om conflicten te voorkomen.",
+
   // "item.edit.relationships.notifications.outdated.title": "Changes outdated",
-  // TODO New key - Add a translation
-  "item.edit.relationships.notifications.outdated.title": "Changes outdated",
-  
+  "item.edit.relationships.notifications.outdated.title": "Wijzingen verouderd",
+
   // "item.edit.relationships.notifications.saved.content": "Your changes to this item's relationships were saved.",
-  // TODO New key - Add a translation
-  "item.edit.relationships.notifications.saved.content": "Your changes to this item's relationships were saved.",
-  
+  "item.edit.relationships.notifications.saved.content": "Uw wijzingen in de relaties van dit item zijn opgeslagen.",
+
   // "item.edit.relationships.notifications.saved.title": "Relationships saved",
-  // TODO New key - Add a translation
-  "item.edit.relationships.notifications.saved.title": "Relationships saved",
-  
+  "item.edit.relationships.notifications.saved.title": "Relaties opgeslagen",
+
   // "item.edit.relationships.reinstate-button": "Undo",
-  // TODO New key - Add a translation
-  "item.edit.relationships.reinstate-button": "Undo",
-  
+  "item.edit.relationships.reinstate-button": "Maak ongedaan",
+
   // "item.edit.relationships.save-button": "Save",
-  // TODO New key - Add a translation
-  "item.edit.relationships.save-button": "Save",
-  
-  
-  
+  "item.edit.relationships.save-button": "Opslaan",
+
+
+
   // "item.edit.tabs.bitstreams.head": "Item Bitstreams",
-  // TODO New key - Add a translation
-  "item.edit.tabs.bitstreams.head": "Item Bitstreams",
-  
+  "item.edit.tabs.bitstreams.head": "Item bitstreams",
+
   // "item.edit.tabs.bitstreams.title": "Item Edit - Bitstreams",
-  // TODO New key - Add a translation
-  "item.edit.tabs.bitstreams.title": "Item Edit - Bitstreams",
-  
+  "item.edit.tabs.bitstreams.title": "Item bewerken - Bitstreams",
+
   // "item.edit.tabs.curate.head": "Curate",
-  // TODO New key - Add a translation
-  "item.edit.tabs.curate.head": "Curate",
-  
+  "item.edit.tabs.curate.head": "Beheer",
+
   // "item.edit.tabs.curate.title": "Item Edit - Curate",
-  // TODO New key - Add a translation
-  "item.edit.tabs.curate.title": "Item Edit - Curate",
-  
+  "item.edit.tabs.curate.title": "Item bewerken - Beheer",
+
   // "item.edit.tabs.metadata.head": "Item Metadata",
-  // TODO New key - Add a translation
-  "item.edit.tabs.metadata.head": "Item Metadata",
-  
+  "item.edit.tabs.metadata.head": "Item metadata",
+
   // "item.edit.tabs.metadata.title": "Item Edit -  Metadata",
-  // TODO New key - Add a translation
-  "item.edit.tabs.metadata.title": "Item Edit -  Metadata",
-  
+  "item.edit.tabs.metadata.title": "Item bewerken -  Metadata",
+
   // "item.edit.tabs.relationships.head": "Item Relationships",
-  // TODO New key - Add a translation
-  "item.edit.tabs.relationships.head": "Item Relationships",
-  
+  "item.edit.tabs.relationships.head": "Item relaties",
+
   // "item.edit.tabs.relationships.title": "Item Edit - Relationships",
-  // TODO New key - Add a translation
-  "item.edit.tabs.relationships.title": "Item Edit - Relationships",
-  
+  "item.edit.tabs.relationships.title": "Item bewerken - relaties",
+
   // "item.edit.tabs.status.buttons.authorizations.button": "Authorizations...",
-  // TODO New key - Add a translation
-  "item.edit.tabs.status.buttons.authorizations.button": "Authorizations...",
-  
+  "item.edit.tabs.status.buttons.authorizations.button": "Autorisaties ..",
+
   // "item.edit.tabs.status.buttons.authorizations.label": "Edit item's authorization policies",
-  // TODO New key - Add a translation
-  "item.edit.tabs.status.buttons.authorizations.label": "Edit item's authorization policies",
-  
+  "item.edit.tabs.status.buttons.authorizations.label": "Bewerk de autorisatieregels",
+
   // "item.edit.tabs.status.buttons.delete.button": "Permanently delete",
-  // TODO New key - Add a translation
-  "item.edit.tabs.status.buttons.delete.button": "Permanently delete",
-  
+  "item.edit.tabs.status.buttons.delete.button": "Permanent verwijderen",
+
   // "item.edit.tabs.status.buttons.delete.label": "Completely expunge item",
-  // TODO New key - Add a translation
-  "item.edit.tabs.status.buttons.delete.label": "Completely expunge item",
-  
+  "item.edit.tabs.status.buttons.delete.label": "Verwijderen het item geheel",
+
   // "item.edit.tabs.status.buttons.mappedCollections.button": "Mapped collections",
-  // TODO New key - Add a translation
-  "item.edit.tabs.status.buttons.mappedCollections.button": "Mapped collections",
-  
+  "item.edit.tabs.status.buttons.mappedCollections.button": "Gemapte collecties",
+
   // "item.edit.tabs.status.buttons.mappedCollections.label": "Manage mapped collections",
-  // TODO New key - Add a translation
-  "item.edit.tabs.status.buttons.mappedCollections.label": "Manage mapped collections",
-  
+  "item.edit.tabs.status.buttons.mappedCollections.label": "Beheer gemapte collecties",
+
   // "item.edit.tabs.status.buttons.move.button": "Move...",
-  // TODO New key - Add a translation
-  "item.edit.tabs.status.buttons.move.button": "Move...",
-  
+  "item.edit.tabs.status.buttons.move.button": "Verplaats ..",
+
   // "item.edit.tabs.status.buttons.move.label": "Move item to another collection",
-  // TODO New key - Add a translation
-  "item.edit.tabs.status.buttons.move.label": "Move item to another collection",
-  
+  "item.edit.tabs.status.buttons.move.label": "Verplaats het item naar een andere collectie",
+
   // "item.edit.tabs.status.buttons.private.button": "Make it private...",
-  // TODO New key - Add a translation
-  "item.edit.tabs.status.buttons.private.button": "Make it private...",
-  
+  "item.edit.tabs.status.buttons.private.button": "Maak privé ...",
+
   // "item.edit.tabs.status.buttons.private.label": "Make item private",
-  // TODO New key - Add a translation
-  "item.edit.tabs.status.buttons.private.label": "Make item private",
-  
+  "item.edit.tabs.status.buttons.private.label": "Maak het item privé",
+
   // "item.edit.tabs.status.buttons.public.button": "Make it public...",
-  // TODO New key - Add a translation
-  "item.edit.tabs.status.buttons.public.button": "Make it public...",
-  
+  "item.edit.tabs.status.buttons.public.button": "Maak openbaar ..",
+
   // "item.edit.tabs.status.buttons.public.label": "Make item public",
-  // TODO New key - Add a translation
-  "item.edit.tabs.status.buttons.public.label": "Make item public",
-  
+  "item.edit.tabs.status.buttons.public.label": "Maak het item openbaar",
+
   // "item.edit.tabs.status.buttons.reinstate.button": "Reinstate...",
-  // TODO New key - Add a translation
-  "item.edit.tabs.status.buttons.reinstate.button": "Reinstate...",
-  
+  "item.edit.tabs.status.buttons.reinstate.button": "Zet terug ...",
+
   // "item.edit.tabs.status.buttons.reinstate.label": "Reinstate item into the repository",
-  // TODO New key - Add a translation
-  "item.edit.tabs.status.buttons.reinstate.label": "Reinstate item into the repository",
-  
+  "item.edit.tabs.status.buttons.reinstate.label": "Zet het item terug in het repository",
+
   // "item.edit.tabs.status.buttons.withdraw.button": "Withdraw...",
-  // TODO New key - Add a translation
-  "item.edit.tabs.status.buttons.withdraw.button": "Withdraw...",
-  
+  "item.edit.tabs.status.buttons.withdraw.button": "Trek terug ...",
+
   // "item.edit.tabs.status.buttons.withdraw.label": "Withdraw item from the repository",
-  // TODO New key - Add a translation
-  "item.edit.tabs.status.buttons.withdraw.label": "Withdraw item from the repository",
-  
+  "item.edit.tabs.status.buttons.withdraw.label": "Trek het item terug uit het repository",
+
   // "item.edit.tabs.status.description": "Welcome to the item management page. From here you can withdraw, reinstate, move or delete the item. You may also update or add new metadata / bitstreams on the other tabs.",
-  // TODO New key - Add a translation
-  "item.edit.tabs.status.description": "Welcome to the item management page. From here you can withdraw, reinstate, move or delete the item. You may also update or add new metadata / bitstreams on the other tabs.",
-  
+  "item.edit.tabs.status.description": "Welkom op de itembeheerpagina. Hier kunt u het item terugtrekken, terugzetten, verplaatsen of verwijderen. Onder de andere tabbladen kunt u metadata / bitstreams bewerken of toevoegen.",
+
   // "item.edit.tabs.status.head": "Item Status",
-  // TODO New key - Add a translation
-  "item.edit.tabs.status.head": "Item Status",
-  
+  "item.edit.tabs.status.head": "Item status",
+
   // "item.edit.tabs.status.labels.handle": "Handle",
-  // TODO New key - Add a translation
   "item.edit.tabs.status.labels.handle": "Handle",
-  
+
   // "item.edit.tabs.status.labels.id": "Item Internal ID",
-  // TODO New key - Add a translation
-  "item.edit.tabs.status.labels.id": "Item Internal ID",
-  
+  "item.edit.tabs.status.labels.id": "Intern Item ID",
+
   // "item.edit.tabs.status.labels.itemPage": "Item Page",
-  // TODO New key - Add a translation
-  "item.edit.tabs.status.labels.itemPage": "Item Page",
-  
+  "item.edit.tabs.status.labels.itemPage": "Itempagina",
+
   // "item.edit.tabs.status.labels.lastModified": "Last Modified",
-  // TODO New key - Add a translation
-  "item.edit.tabs.status.labels.lastModified": "Last Modified",
-  
+  "item.edit.tabs.status.labels.lastModified": "Laatst gewijzigd",
+
   // "item.edit.tabs.status.title": "Item Edit -  Status",
-  // TODO New key - Add a translation
-  "item.edit.tabs.status.title": "Item Edit -  Status",
-  
+  "item.edit.tabs.status.title": "Item bewerken -  Status",
+
   // "item.edit.tabs.view.head": "View Item",
-  // TODO New key - Add a translation
-  "item.edit.tabs.view.head": "View Item",
-  
+  "item.edit.tabs.view.head": "Bekijk het item",
+
   // "item.edit.tabs.view.title": "Item Edit -  View",
-  // TODO New key - Add a translation
-  "item.edit.tabs.view.title": "Item Edit -  View",
-  
-  
-  
+  "item.edit.tabs.view.title": "Item bewerken -  Bekijk",
+
+
+
   // "item.edit.withdraw.cancel": "Cancel",
-  // TODO New key - Add a translation
-  "item.edit.withdraw.cancel": "Cancel",
-  
+  "item.edit.withdraw.cancel": "Annuleer",
+
   // "item.edit.withdraw.confirm": "Withdraw",
-  // TODO New key - Add a translation
-  "item.edit.withdraw.confirm": "Withdraw",
-  
+  "item.edit.withdraw.confirm": "Trek terug",
+
   // "item.edit.withdraw.description": "Are you sure this item should be withdrawn from the archive?",
-  // TODO New key - Add a translation
-  "item.edit.withdraw.description": "Are you sure this item should be withdrawn from the archive?",
-  
+  "item.edit.withdraw.description": "Weet u zeker dat dit item uit het archief moet worden teruggetrokken?",
+
   // "item.edit.withdraw.error": "An error occurred while withdrawing the item",
-  // TODO New key - Add a translation
-  "item.edit.withdraw.error": "An error occurred while withdrawing the item",
-  
+  "item.edit.withdraw.error": "Er is een fout opgetreden bij het terugtrekken van het item",
+
   // "item.edit.withdraw.header": "Withdraw item: {{ id }}",
-  // TODO New key - Add a translation
-  "item.edit.withdraw.header": "Withdraw item: {{ id }}",
-  
+  "item.edit.withdraw.header": "Item terugtrekken: {{ id }}",
+
   // "item.edit.withdraw.success": "The item was withdrawn successfully",
-  // TODO New key - Add a translation
-  "item.edit.withdraw.success": "The item was withdrawn successfully",
-  
-  
-  
+  "item.edit.withdraw.success": "Het item is teruggetrokken",
+
+
+
   // "item.page.abstract": "Abstract",
   "item.page.abstract": "Abstract",
-  
+
   // "item.page.author": "Authors",
   "item.page.author": "Auteur",
-  
+
   // "item.page.citation": "Citation",
-  // TODO New key - Add a translation
-  "item.page.citation": "Citation",
-  
+  "item.page.citation": "Citeren als",
+
   // "item.page.collections": "Collections",
   "item.page.collections": "Collecties",
-  
+
   // "item.page.date": "Date",
   "item.page.date": "Datum",
-  
+
   // "item.page.files": "Files",
   "item.page.files": "Bestanden",
-  
+
   // "item.page.filesection.description": "Description:",
-  // TODO New key - Add a translation
-  "item.page.filesection.description": "Description:",
-  
+  "item.page.filesection.description": "Beschrijving:",
+
   // "item.page.filesection.download": "Download",
   "item.page.filesection.download": "Download",
-  
+
   // "item.page.filesection.format": "Format:",
-  // TODO New key - Add a translation
-  "item.page.filesection.format": "Format:",
-  
+  "item.page.filesection.format": "Formaat:",
+
   // "item.page.filesection.name": "Name:",
-  // TODO New key - Add a translation
-  "item.page.filesection.name": "Name:",
-  
+  "item.page.filesection.name": "Naam:",
+
   // "item.page.filesection.size": "Size:",
-  // TODO New key - Add a translation
-  "item.page.filesection.size": "Size:",
-  
+  "item.page.filesection.size": "Grootte:",
+
   // "item.page.journal.search.title": "Articles in this journal",
-  // TODO New key - Add a translation
-  "item.page.journal.search.title": "Articles in this journal",
-  
+  "item.page.journal.search.title": "Artikelen in dit tijdschrift",
+
   // "item.page.link.full": "Full item page",
   "item.page.link.full": "Volledige itemweergave",
-  
+
   // "item.page.link.simple": "Simple item page",
   "item.page.link.simple": "Eenvoudige itemweergave",
-  
+
   // "item.page.person.search.title": "Articles by this author",
-  // TODO New key - Add a translation
-  "item.page.person.search.title": "Articles by this author",
-  
+  "item.page.person.search.title": "Artikelen van deze auteur",
+
   // "item.page.related-items.view-more": "View more",
-  // TODO New key - Add a translation
-  "item.page.related-items.view-more": "View more",
-  
+  "item.page.related-items.view-more": "Bekijk meer",
+
   // "item.page.related-items.view-less": "View less",
-  // TODO New key - Add a translation
-  "item.page.related-items.view-less": "View less",
-  
+  "item.page.related-items.view-less": "Bekijk minder",
+
   // "item.page.subject": "Keywords",
-  // TODO New key - Add a translation
-  "item.page.subject": "Keywords",
-  
+  "item.page.subject": "Trefwoorden",
+
   // "item.page.uri": "URI",
   "item.page.uri": "URI",
-  
-  
-  
+
+
+
   // "item.select.confirm": "Confirm selected",
-  // TODO New key - Add a translation
-  "item.select.confirm": "Confirm selected",
-  
+  "item.select.confirm": "Bevestig selectie",
+
   // "item.select.empty": "No items to show",
-  // TODO New key - Add a translation
-  "item.select.empty": "No items to show",
-  
+  "item.select.empty": "Geen items om te tonen",
+
   // "item.select.table.author": "Author",
-  // TODO New key - Add a translation
-  "item.select.table.author": "Author",
-  
+  "item.select.table.author": "Auteur",
+
   // "item.select.table.collection": "Collection",
-  // TODO New key - Add a translation
-  "item.select.table.collection": "Collection",
-  
+  "item.select.table.collection": "Collectie",
+
   // "item.select.table.title": "Title",
-  // TODO New key - Add a translation
-  "item.select.table.title": "Title",
-  
-  
-  
+  "item.select.table.title": "Titel",
+
+
+
   // "journal.listelement.badge": "Journal",
-  // TODO New key - Add a translation
-  "journal.listelement.badge": "Journal",
-  
+  "journal.listelement.badge": "Tijdschrift",
+
   // "journal.page.description": "Description",
-  // TODO New key - Add a translation
-  "journal.page.description": "Description",
-  
+  "journal.page.description": "Beschrijving",
+
   // "journal.page.editor": "Editor-in-Chief",
-  // TODO New key - Add a translation
-  "journal.page.editor": "Editor-in-Chief",
-  
+  "journal.page.editor": "Hoofdredacteur",
+
   // "journal.page.issn": "ISSN",
-  // TODO New key - Add a translation
   "journal.page.issn": "ISSN",
-  
+
   // "journal.page.publisher": "Publisher",
-  // TODO New key - Add a translation
-  "journal.page.publisher": "Publisher",
-  
+  "journal.page.publisher": "Uitgever",
+
   // "journal.page.titleprefix": "Journal: ",
-  // TODO New key - Add a translation
-  "journal.page.titleprefix": "Journal: ",
-  
+  "journal.page.titleprefix": "Tijdschrift: ",
+
   // "journal.search.results.head": "Journal Search Results",
-  // TODO New key - Add a translation
-  "journal.search.results.head": "Journal Search Results",
-  
+   "journal.search.results.head": "Tijdschrift zoekresultaten",
+
   // "journal.search.title": "DSpace Angular :: Journal Search",
-  // TODO New key - Add a translation
-  "journal.search.title": "DSpace Angular :: Journal Search",
-  
-  
-  
+  "journal.search.title": "DSpace Angular :: Tijdschrift zoeken",
+
+
+
   // "journalissue.listelement.badge": "Journal Issue",
-  // TODO New key - Add a translation
-  "journalissue.listelement.badge": "Journal Issue",
-  
+  "journalissue.listelement.badge": "Tijdschrift aflevering",
+
   // "journalissue.page.description": "Description",
-  // TODO New key - Add a translation
-  "journalissue.page.description": "Description",
-  
+  "journalissue.page.description": "Beschrijving",
+
   // "journalissue.page.issuedate": "Issue Date",
-  // TODO New key - Add a translation
-  "journalissue.page.issuedate": "Issue Date",
-  
+  "journalissue.page.issuedate": "Datum van uitgave",
+
   // "journalissue.page.journal-issn": "Journal ISSN",
-  // TODO New key - Add a translation
-  "journalissue.page.journal-issn": "Journal ISSN",
-  
+  "journalissue.page.journal-issn": "Tijdschrift ISSN",
+
   // "journalissue.page.journal-title": "Journal Title",
-  // TODO New key - Add a translation
-  "journalissue.page.journal-title": "Journal Title",
-  
+  "journalissue.page.journal-title": "Tijdschrifttitel",
+
   // "journalissue.page.keyword": "Keywords",
-  // TODO New key - Add a translation
-  "journalissue.page.keyword": "Keywords",
-  
+  "journalissue.page.keyword": "Trefwoorden",
+
   // "journalissue.page.number": "Number",
-  // TODO New key - Add a translation
-  "journalissue.page.number": "Number",
-  
+  "journalissue.page.number": "Nummer",
+
   // "journalissue.page.titleprefix": "Journal Issue: ",
-  // TODO New key - Add a translation
-  "journalissue.page.titleprefix": "Journal Issue: ",
-  
-  
-  
+  "journalissue.page.titleprefix": "Tijdschriftaflevering: ",
+
+
+
   // "journalvolume.listelement.badge": "Journal Volume",
-  // TODO New key - Add a translation
-  "journalvolume.listelement.badge": "Journal Volume",
-  
+  "journalvolume.listelement.badge": "Tijdschriftjaargang",
+
   // "journalvolume.page.description": "Description",
-  // TODO New key - Add a translation
-  "journalvolume.page.description": "Description",
-  
+  "journalvolume.page.description": "Beschrijving",
+
   // "journalvolume.page.issuedate": "Issue Date",
-  // TODO New key - Add a translation
-  "journalvolume.page.issuedate": "Issue Date",
-  
+  "journalvolume.page.issuedate": "Datum van uitgave",
+
   // "journalvolume.page.titleprefix": "Journal Volume: ",
-  // TODO New key - Add a translation
-  "journalvolume.page.titleprefix": "Journal Volume: ",
-  
+  "journalvolume.page.titleprefix": "Tijdschriftjaargang: ",
+
   // "journalvolume.page.volume": "Volume",
-  // TODO New key - Add a translation
-  "journalvolume.page.volume": "Volume",
-  
-  
-  
+  "journalvolume.page.volume": "Jaargang",
+
+
+
   // "loading.browse-by": "Loading items...",
   "loading.browse-by": "Items worden ingeladen...",
-  
+
   // "loading.browse-by-page": "Loading page...",
-  // TODO New key - Add a translation
-  "loading.browse-by-page": "Loading page...",
-  
+  "loading.browse-by-page": "Pagina wordt ingeladen...",
+
   // "loading.collection": "Loading collection...",
   "loading.collection": "Collectie wordt ingeladen...",
-  
+
   // "loading.collections": "Loading collections...",
-  // TODO New key - Add a translation
-  "loading.collections": "Loading collections...",
-  
+  "loading.collections": "Collecties worden ingeladen...",
+
   // "loading.community": "Loading community...",
   "loading.community": "Community wordt ingeladen...",
-  
+
   // "loading.default": "Loading...",
   "loading.default": "Laden...",
-  
+
   // "loading.item": "Loading item...",
   "loading.item": "Item wordt ingeladen...",
-  
+
   // "loading.items": "Loading items...",
-  // TODO New key - Add a translation
-  "loading.items": "Loading items...",
-  
+  "loading.items": "Items worden ingeladen...",
+
   // "loading.mydspace-results": "Loading items...",
-  // TODO New key - Add a translation
-  "loading.mydspace-results": "Loading items...",
-  
+  "loading.mydspace-results": "Items worden ingeladen...",
+
   // "loading.objects": "Loading...",
   "loading.objects": "Laden...",
-  
+
   // "loading.recent-submissions": "Loading recent submissions...",
   "loading.recent-submissions": "Recent toegevoegde items worden ingeladen...",
-  
+
   // "loading.search-results": "Loading search results...",
   "loading.search-results": "Zoekresultaten worden ingeladen...",
-  
+
   // "loading.sub-collections": "Loading sub-collections...",
   "loading.sub-collections": "De sub-collecties worden ingeladen...",
-  
+
   // "loading.sub-communities": "Loading sub-communities...",
-  // TODO New key - Add a translation
-  "loading.sub-communities": "Loading sub-communities...",
-  
+  "loading.sub-communities": "De sub-communities worden ingeladen...",
+
   // "loading.top-level-communities": "Loading top-level communities...",
-  "loading.top-level-communities": "Inladen van de Communities op het hoogste niveau...",
-  
-  
-  
+  "loading.top-level-communities": "Inladen van de communities op het hoogste niveau...",
+
+
+
   // "login.form.email": "Email address",
   "login.form.email": "Email adres",
-  
+
   // "login.form.forgot-password": "Have you forgotten your password?",
   "login.form.forgot-password": "Bent u uw wachtwoord vergeten?",
-  
+
   // "login.form.header": "Please log in to DSpace",
   "login.form.header": "Gelieve in te loggen in DSpace",
-  
+
   // "login.form.new-user": "New user? Click here to register.",
   "login.form.new-user": "Nieuwe gebruiker? Gelieve u hier te registreren",
-  
+
   // "login.form.password": "Password",
   "login.form.password": "Wachtwoord",
-  
+
   // "login.form.submit": "Log in",
   "login.form.submit": "Aanmelden",
-  
+
   // "login.title": "Login",
   "login.title": "Aanmelden",
-  
-  
-  
+
+
+
   // "logout.form.header": "Log out from DSpace",
   "logout.form.header": "Afmelden in DSpace",
-  
+
   // "logout.form.submit": "Log out",
   "logout.form.submit": "Afmelden",
-  
+
   // "logout.title": "Logout",
   "logout.title": "Afmelden",
-  
-  
-  
+
+
+
   // "menu.header.admin": "Admin",
-  // TODO New key - Add a translation
-  "menu.header.admin": "Admin",
-  
+  "menu.header.admin": "Beheer",
+
   // "menu.header.image.logo": "Repository logo",
-  // TODO New key - Add a translation
-  "menu.header.image.logo": "Repository logo",
-  
-  
-  
+   "menu.header.image.logo": "Repository logo",
+
+
+
   // "menu.section.access_control": "Access Control",
-  // TODO New key - Add a translation
-  "menu.section.access_control": "Access Control",
-  
+   "menu.section.access_control": "Toegangscontrole",
+
   // "menu.section.access_control_authorizations": "Authorizations",
-  // TODO New key - Add a translation
-  "menu.section.access_control_authorizations": "Authorizations",
-  
+  "menu.section.access_control_authorizations": "Autorisaties",
+
   // "menu.section.access_control_groups": "Groups",
-  // TODO New key - Add a translation
-  "menu.section.access_control_groups": "Groups",
-  
+  "menu.section.access_control_groups": "Groepen",
+
   // "menu.section.access_control_people": "People",
-  // TODO New key - Add a translation
-  "menu.section.access_control_people": "People",
-  
-  
-  
+  "menu.section.access_control_people": "Personen",
+
+
+
   // "menu.section.browse_community": "This Community",
-  // TODO New key - Add a translation
-  "menu.section.browse_community": "This Community",
-  
+  "menu.section.browse_community": "Deze community",
+
   // "menu.section.browse_community_by_author": "By Author",
-  // TODO New key - Add a translation
-  "menu.section.browse_community_by_author": "By Author",
-  
+  "menu.section.browse_community_by_author": "Op auteur",
+
   // "menu.section.browse_community_by_issue_date": "By Issue Date",
-  // TODO New key - Add a translation
-  "menu.section.browse_community_by_issue_date": "By Issue Date",
-  
+  "menu.section.browse_community_by_issue_date": "Op datum van uitgave",
+
   // "menu.section.browse_community_by_title": "By Title",
-  // TODO New key - Add a translation
-  "menu.section.browse_community_by_title": "By Title",
-  
+  "menu.section.browse_community_by_title": "Op titel",
+
   // "menu.section.browse_global": "All of DSpace",
-  // TODO New key - Add a translation
-  "menu.section.browse_global": "All of DSpace",
-  
+  "menu.section.browse_global": "Heel DSpace",
+
   // "menu.section.browse_global_by_author": "By Author",
-  // TODO New key - Add a translation
-  "menu.section.browse_global_by_author": "By Author",
-  
+  "menu.section.browse_global_by_author": "Op auteur",
+
   // "menu.section.browse_global_by_dateissued": "By Issue Date",
-  // TODO New key - Add a translation
-  "menu.section.browse_global_by_dateissued": "By Issue Date",
-  
+  "menu.section.browse_global_by_dateissued": "Op datum van uitgave",
+
   // "menu.section.browse_global_by_subject": "By Subject",
-  // TODO New key - Add a translation
-  "menu.section.browse_global_by_subject": "By Subject",
-  
+  "menu.section.browse_global_by_subject": "Op onderwerp",
+
   // "menu.section.browse_global_by_title": "By Title",
-  // TODO New key - Add a translation
-  "menu.section.browse_global_by_title": "By Title",
-  
+  "menu.section.browse_global_by_title": "Op titel",
+
   // "menu.section.browse_global_communities_and_collections": "Communities & Collections",
-  // TODO New key - Add a translation
-  "menu.section.browse_global_communities_and_collections": "Communities & Collections",
-  
-  
-  
+  "menu.section.browse_global_communities_and_collections": "Communities & Collecties",
+
+
+
   // "menu.section.control_panel": "Control Panel",
-  // TODO New key - Add a translation
-  "menu.section.control_panel": "Control Panel",
-  
+   "menu.section.control_panel": "Controlepaneel",
+
   // "menu.section.curation_task": "Curation Task",
-  // TODO New key - Add a translation
-  "menu.section.curation_task": "Curation Task",
-  
-  
-  
+   "menu.section.curation_task": "Beheertaak",
+
+
+
   // "menu.section.edit": "Edit",
-  // TODO New key - Add a translation
-  "menu.section.edit": "Edit",
-  
+  "menu.section.edit": "Bewerk",
+
   // "menu.section.edit_collection": "Collection",
-  // TODO New key - Add a translation
-  "menu.section.edit_collection": "Collection",
-  
+  "menu.section.edit_collection": "Collectie",
+
   // "menu.section.edit_community": "Community",
-  // TODO New key - Add a translation
   "menu.section.edit_community": "Community",
-  
+
   // "menu.section.edit_item": "Item",
-  // TODO New key - Add a translation
   "menu.section.edit_item": "Item",
-  
-  
-  
+
+
+
   // "menu.section.export": "Export",
-  // TODO New key - Add a translation
-  "menu.section.export": "Export",
-  
+  "menu.section.export": "Exporteer",
+
   // "menu.section.export_collection": "Collection",
-  // TODO New key - Add a translation
-  "menu.section.export_collection": "Collection",
-  
+  "menu.section.export_collection": "Collectie",
+
   // "menu.section.export_community": "Community",
-  // TODO New key - Add a translation
   "menu.section.export_community": "Community",
-  
+
   // "menu.section.export_item": "Item",
-  // TODO New key - Add a translation
   "menu.section.export_item": "Item",
-  
+
   // "menu.section.export_metadata": "Metadata",
-  // TODO New key - Add a translation
-  "menu.section.export_metadata": "Metadata",
-  
-  
-  
+   "menu.section.export_metadata": "Metadata",
+
+
+
   // "menu.section.find": "Find",
-  // TODO New key - Add a translation
-  "menu.section.find": "Find",
-  
+   "menu.section.find": "Vind",
+
   // "menu.section.find_items": "Items",
-  // TODO New key - Add a translation
   "menu.section.find_items": "Items",
-  
+
   // "menu.section.find_private_items": "Private Items",
-  // TODO New key - Add a translation
-  "menu.section.find_private_items": "Private Items",
-  
+  "menu.section.find_private_items": "Privé items",
+
   // "menu.section.find_withdrawn_items": "Withdrawn Items",
-  // TODO New key - Add a translation
-  "menu.section.find_withdrawn_items": "Withdrawn Items",
-  
-  
-  
+  "menu.section.find_withdrawn_items": "Teruggetrokken items",
+
+
+
   // "menu.section.icon.access_control": "Access Control menu section",
-  // TODO New key - Add a translation
-  "menu.section.icon.access_control": "Access Control menu section",
-  
+  "menu.section.icon.access_control": "Menusectie toegangscontrole",
+
   // "menu.section.icon.control_panel": "Control Panel menu section",
-  // TODO New key - Add a translation
-  "menu.section.icon.control_panel": "Control Panel menu section",
-  
+  "menu.section.icon.control_panel": "Menusectie controlepaneel",
+
   // "menu.section.icon.curation_task": "Curation Task menu section",
-  // TODO New key - Add a translation
-  "menu.section.icon.curation_task": "Curation Task menu section",
-  
+  "menu.section.icon.curation_task": "Menusectie beheertaken",
+
   // "menu.section.icon.edit": "Edit menu section",
-  // TODO New key - Add a translation
-  "menu.section.icon.edit": "Edit menu section",
-  
+  "menu.section.icon.edit": "Menusectie bewerkingen",
+
   // "menu.section.icon.export": "Export menu section",
-  // TODO New key - Add a translation
-  "menu.section.icon.export": "Export menu section",
-  
+  "menu.section.icon.export": "Menusectie export",
+
   // "menu.section.icon.find": "Find menu section",
-  // TODO New key - Add a translation
-  "menu.section.icon.find": "Find menu section",
-  
+  "menu.section.icon.find": "Menusectie vinden",
+
   // "menu.section.icon.import": "Import menu section",
-  // TODO New key - Add a translation
-  "menu.section.icon.import": "Import menu section",
-  
+  "menu.section.icon.import": "Menusectie import",
+
   // "menu.section.icon.new": "New menu section",
-  // TODO New key - Add a translation
-  "menu.section.icon.new": "New menu section",
-  
+   "menu.section.icon.new": "Menusectie nieuw",
+
   // "menu.section.icon.pin": "Pin sidebar",
-  // TODO New key - Add a translation
-  "menu.section.icon.pin": "Pin sidebar",
-  
+  "menu.section.icon.pin": "Zijbalk vastzetten",
+
   // "menu.section.icon.registries": "Registries menu section",
-  // TODO New key - Add a translation
-  "menu.section.icon.registries": "Registries menu section",
-  
+  "menu.section.icon.registries": "Menusectie registers",
+
   // "menu.section.icon.statistics_task": "Statistics Task menu section",
-  // TODO New key - Add a translation
-  "menu.section.icon.statistics_task": "Statistics Task menu section",
-  
+  "menu.section.icon.statistics_task": "Menusectie statistiektaken",
+
   // "menu.section.icon.unpin": "Unpin sidebar",
-  // TODO New key - Add a translation
-  "menu.section.icon.unpin": "Unpin sidebar",
-  
-  
-  
+  "menu.section.icon.unpin": "Zijbalk losmaken",
+
+
+
   // "menu.section.import": "Import",
-  // TODO New key - Add a translation
   "menu.section.import": "Import",
-  
+
   // "menu.section.import_batch": "Batch Import (ZIP)",
-  // TODO New key - Add a translation
-  "menu.section.import_batch": "Batch Import (ZIP)",
-  
+  "menu.section.import_batch": "Batch import (ZIP)",
+
   // "menu.section.import_metadata": "Metadata",
-  // TODO New key - Add a translation
   "menu.section.import_metadata": "Metadata",
-  
-  
-  
+
+
+
   // "menu.section.new": "New",
-  // TODO New key - Add a translation
-  "menu.section.new": "New",
-  
+  "menu.section.new": "Nieuw",
+
   // "menu.section.new_collection": "Collection",
-  // TODO New key - Add a translation
-  "menu.section.new_collection": "Collection",
-  
+  "menu.section.new_collection": "Collectie",
+
   // "menu.section.new_community": "Community",
-  // TODO New key - Add a translation
   "menu.section.new_community": "Community",
-  
+
   // "menu.section.new_item": "Item",
-  // TODO New key - Add a translation
   "menu.section.new_item": "Item",
-  
+
   // "menu.section.new_item_version": "Item Version",
-  // TODO New key - Add a translation
-  "menu.section.new_item_version": "Item Version",
-  
-  
-  
+  "menu.section.new_item_version": "Item versie",
+
+
+
   // "menu.section.pin": "Pin sidebar",
-  // TODO New key - Add a translation
-  "menu.section.pin": "Pin sidebar",
-  
+  "menu.section.pin": "Zijbalk vastzetten",
+
   // "menu.section.unpin": "Unpin sidebar",
-  // TODO New key - Add a translation
-  "menu.section.unpin": "Unpin sidebar",
-  
-  
-  
+   "menu.section.unpin": "Zijbalk losmaken",
+
+
+
   // "menu.section.registries": "Registries",
-  // TODO New key - Add a translation
-  "menu.section.registries": "Registries",
-  
+  "menu.section.registries": "Registers",
+
   // "menu.section.registries_format": "Format",
-  // TODO New key - Add a translation
-  "menu.section.registries_format": "Format",
-  
+  "menu.section.registries_format": "Formaten",
+
   // "menu.section.registries_metadata": "Metadata",
-  // TODO New key - Add a translation
   "menu.section.registries_metadata": "Metadata",
-  
-  
-  
+
+
+
   // "menu.section.statistics": "Statistics",
-  // TODO New key - Add a translation
-  "menu.section.statistics": "Statistics",
-  
+  "menu.section.statistics": "Statistieken",
+
   // "menu.section.statistics_task": "Statistics Task",
-  // TODO New key - Add a translation
-  "menu.section.statistics_task": "Statistics Task",
-  
-  
-  
+   "menu.section.statistics_task": "Statistiektaken",
+
+
+
   // "menu.section.toggle.access_control": "Toggle Access Control section",
-  // TODO New key - Add a translation
-  "menu.section.toggle.access_control": "Toggle Access Control section",
-  
+  "menu.section.toggle.access_control": "Sectie Toegangscontrole aan/uit",
+
   // "menu.section.toggle.control_panel": "Toggle Control Panel section",
-  // TODO New key - Add a translation
-  "menu.section.toggle.control_panel": "Toggle Control Panel section",
-  
+   "menu.section.toggle.control_panel": "Sectie Controlepaneel aan/uit",
+
   // "menu.section.toggle.curation_task": "Toggle Curation Task section",
-  // TODO New key - Add a translation
-  "menu.section.toggle.curation_task": "Toggle Curation Task section",
-  
+  "menu.section.toggle.curation_task": "Sectie Beheertaken aan/uit",
+
   // "menu.section.toggle.edit": "Toggle Edit section",
-  // TODO New key - Add a translation
-  "menu.section.toggle.edit": "Toggle Edit section",
-  
+  "menu.section.toggle.edit": "Sectie Bewerk aan/uit",
+
   // "menu.section.toggle.export": "Toggle Export section",
-  // TODO New key - Add a translation
-  "menu.section.toggle.export": "Toggle Export section",
-  
+   "menu.section.toggle.export": "Sectie Export aan/uit",
+
   // "menu.section.toggle.find": "Toggle Find section",
-  // TODO New key - Add a translation
-  "menu.section.toggle.find": "Toggle Find section",
-  
+  "menu.section.toggle.find": "Sectie Vind aan/uit",
+
   // "menu.section.toggle.import": "Toggle Import section",
-  // TODO New key - Add a translation
-  "menu.section.toggle.import": "Toggle Import section",
-  
+  "menu.section.toggle.import": "Sectie Import aan/uit",
+
   // "menu.section.toggle.new": "Toggle New section",
-  // TODO New key - Add a translation
-  "menu.section.toggle.new": "Toggle New section",
-  
+  "menu.section.toggle.new": "Sectie Nieuw aan/uit",
+
   // "menu.section.toggle.registries": "Toggle Registries section",
-  // TODO New key - Add a translation
-  "menu.section.toggle.registries": "Toggle Registries section",
-  
+  "menu.section.toggle.registries": "Sectie registers aan/uit",
+
   // "menu.section.toggle.statistics_task": "Toggle Statistics Task section",
-  // TODO New key - Add a translation
-  "menu.section.toggle.statistics_task": "Toggle Statistics Task section",
-  
-  
-  
+  "menu.section.toggle.statistics_task": "Sectie statistiektaken aan/uit",
+
+
+
   // "mydspace.description": "",
-  // TODO New key - Add a translation
-  "mydspace.description": "",
-  
+   "mydspace.description": "",
+
   // "mydspace.general.text-here": "HERE",
-  // TODO New key - Add a translation
-  "mydspace.general.text-here": "HERE",
-  
+  "mydspace.general.text-here": "HIER",
+
   // "mydspace.messages.controller-help": "Select this option to send a message to item's submitter.",
-  // TODO New key - Add a translation
-  "mydspace.messages.controller-help": "Select this option to send a message to item's submitter.",
-  
+  "mydspace.messages.controller-help": "Kies deze optie om een bericht te sturen naar de indiener van het item.",
+
   // "mydspace.messages.description-placeholder": "Insert your message here...",
-  // TODO New key - Add a translation
-  "mydspace.messages.description-placeholder": "Insert your message here...",
-  
+  "mydspace.messages.description-placeholder": " Vul hier uw bericht in...",
+
   // "mydspace.messages.hide-msg": "Hide message",
-  // TODO New key - Add a translation
-  "mydspace.messages.hide-msg": "Hide message",
-  
+   "mydspace.messages.hide-msg": "Verberg bericht",
+
   // "mydspace.messages.mark-as-read": "Mark as read",
-  // TODO New key - Add a translation
-  "mydspace.messages.mark-as-read": "Mark as read",
-  
+  "mydspace.messages.mark-as-read": "Markeer als gelezen",
+
   // "mydspace.messages.mark-as-unread": "Mark as unread",
-  // TODO New key - Add a translation
-  "mydspace.messages.mark-as-unread": "Mark as unread",
-  
+  "mydspace.messages.mark-as-unread": "Markeer als ongelezen",
+
   // "mydspace.messages.no-content": "No content.",
-  // TODO New key - Add a translation
-  "mydspace.messages.no-content": "No content.",
-  
+  "mydspace.messages.no-content": "Geen inhoud.",
+
   // "mydspace.messages.no-messages": "No messages yet.",
-  // TODO New key - Add a translation
-  "mydspace.messages.no-messages": "No messages yet.",
-  
+  "mydspace.messages.no-messages": "Nog geen berichten.",
+
   // "mydspace.messages.send-btn": "Send",
-  // TODO New key - Add a translation
-  "mydspace.messages.send-btn": "Send",
-  
+  "mydspace.messages.send-btn": "Verstuur",
+
   // "mydspace.messages.show-msg": "Show message",
-  // TODO New key - Add a translation
-  "mydspace.messages.show-msg": "Show message",
-  
+  "mydspace.messages.show-msg": "Toon bericht",
+
   // "mydspace.messages.subject-placeholder": "Subject...",
-  // TODO New key - Add a translation
-  "mydspace.messages.subject-placeholder": "Subject...",
-  
+  "mydspace.messages.subject-placeholder": "Onderwerp...",
+
   // "mydspace.messages.submitter-help": "Select this option to send a message to controller.",
-  // TODO New key - Add a translation
-  "mydspace.messages.submitter-help": "Select this option to send a message to controller.",
-  
+  "mydspace.messages.submitter-help": "Kies deze optie om een bericht te sturen naar de controlleur.",
+
   // "mydspace.messages.title": "Messages",
-  // TODO New key - Add a translation
-  "mydspace.messages.title": "Messages",
-  
+  "mydspace.messages.title": "Berichten",
+
   // "mydspace.messages.to": "To",
-  // TODO New key - Add a translation
-  "mydspace.messages.to": "To",
-  
+  "mydspace.messages.to": "Aan",
+
   // "mydspace.new-submission": "New submission",
-  // TODO New key - Add a translation
-  "mydspace.new-submission": "New submission",
-  
+  "mydspace.new-submission": "Nieuwe submission",
+
   // "mydspace.results.head": "Your submissions",
-  // TODO New key - Add a translation
-  "mydspace.results.head": "Your submissions",
-  
+  "mydspace.results.head": "Uw submissions",
+
   // "mydspace.results.no-abstract": "No Abstract",
-  // TODO New key - Add a translation
-  "mydspace.results.no-abstract": "No Abstract",
-  
+  "mydspace.results.no-abstract": "Geen abstract",
+
   // "mydspace.results.no-authors": "No Authors",
-  // TODO New key - Add a translation
-  "mydspace.results.no-authors": "No Authors",
-  
+   "mydspace.results.no-authors": "Geen auteurs",
+
   // "mydspace.results.no-collections": "No Collections",
-  // TODO New key - Add a translation
-  "mydspace.results.no-collections": "No Collections",
-  
+  "mydspace.results.no-collections": "Geen collecties",
+
   // "mydspace.results.no-date": "No Date",
-  // TODO New key - Add a translation
-  "mydspace.results.no-date": "No Date",
-  
+  "mydspace.results.no-date": "Geen datum",
+
   // "mydspace.results.no-files": "No Files",
-  // TODO New key - Add a translation
-  "mydspace.results.no-files": "No Files",
-  
+  "mydspace.results.no-files": "Geen bestanden",
+
   // "mydspace.results.no-results": "There were no items to show",
-  // TODO New key - Add a translation
-  "mydspace.results.no-results": "There were no items to show",
-  
+  "mydspace.results.no-results": "Er zijn geen items om getoond te worden",
+
   // "mydspace.results.no-title": "No title",
-  // TODO New key - Add a translation
-  "mydspace.results.no-title": "No title",
-  
+  "mydspace.results.no-title": "Geen titel",
+
   // "mydspace.results.no-uri": "No Uri",
-  // TODO New key - Add a translation
-  "mydspace.results.no-uri": "No Uri",
-  
+  "mydspace.results.no-uri": "Geen URI",
+
   // "mydspace.show.workflow": "All tasks",
-  // TODO New key - Add a translation
-  "mydspace.show.workflow": "All tasks",
-  
+  "mydspace.show.workflow": "Alle taken",
+
   // "mydspace.show.workspace": "Your Submissions",
-  // TODO New key - Add a translation
-  "mydspace.show.workspace": "Your Submissions",
-  
+  "mydspace.show.workspace": "Uw Submissions",
+
   // "mydspace.status.archived": "Archived",
-  // TODO New key - Add a translation
-  "mydspace.status.archived": "Archived",
-  
+  "mydspace.status.archived": "Opgeslagen",
+
   // "mydspace.status.validation": "Validation",
-  // TODO New key - Add a translation
-  "mydspace.status.validation": "Validation",
-  
+  "mydspace.status.validation": "Validatie",
+
   // "mydspace.status.waiting-for-controller": "Waiting for controller",
-  // TODO New key - Add a translation
-  "mydspace.status.waiting-for-controller": "Waiting for controller",
-  
+  "mydspace.status.waiting-for-controller": "Wachten op controlleur",
+
   // "mydspace.status.workflow": "Workflow",
-  // TODO New key - Add a translation
-  "mydspace.status.workflow": "Workflow",
-  
+   "mydspace.status.workflow": "Workflow",
+
   // "mydspace.status.workspace": "Workspace",
-  // TODO New key - Add a translation
   "mydspace.status.workspace": "Workspace",
-  
+
   // "mydspace.title": "MyDSpace",
-  // TODO New key - Add a translation
   "mydspace.title": "MyDSpace",
-  
+
   // "mydspace.upload.upload-failed": "Error creating new workspace. Please verify the content uploaded before retry.",
-  // TODO New key - Add a translation
-  "mydspace.upload.upload-failed": "Error creating new workspace. Please verify the content uploaded before retry.",
-  
+  "mydspace.upload.upload-failed": "Er is een fout opgetreden bij het aanmaken van de nieuwe workspace. Controleer alstublieft de inhoud voordat u het opnieuw probeert.",
+
   // "mydspace.upload.upload-multiple-successful": "{{qty}} new workspace items created.",
-  // TODO New key - Add a translation
-  "mydspace.upload.upload-multiple-successful": "{{qty}} new workspace items created.",
-  
+  "mydspace.upload.upload-multiple-successful": "{{qty}} nieuwe workspace items aangemaakt.",
+
   // "mydspace.upload.upload-successful": "New workspace item created. Click {{here}} for edit it.",
-  // TODO New key - Add a translation
-  "mydspace.upload.upload-successful": "New workspace item created. Click {{here}} for edit it.",
-  
+  "mydspace.upload.upload-successful": "Nieuw workspace item aangemaakt. Klik {{here}} om het te bewerken.",
+
   // "mydspace.view-btn": "View",
-  // TODO New key - Add a translation
-  "mydspace.view-btn": "View",
-  
-  
-  
+  "mydspace.view-btn": "Bekijk",
+
+
+
   // "nav.browse.header": "All of DSpace",
-  // TODO New key - Add a translation
-  "nav.browse.header": "All of DSpace",
-  
+  "nav.browse.header": "Heel DSpace",
+
   // "nav.community-browse.header": "By Community",
-  // TODO New key - Add a translation
-  "nav.community-browse.header": "By Community",
-  
+  "nav.community-browse.header": "Per community",
+
   // "nav.language": "Language switch",
-  // TODO New key - Add a translation
-  "nav.language": "Language switch",
-  
+  "nav.language": "Verander van taal",
+
   // "nav.login": "Log In",
   "nav.login": "Log In",
-  
+
   // "nav.logout": "Log Out",
   "nav.logout": "Log Uit",
-  
+
   // "nav.mydspace": "MyDSpace",
-  // TODO New key - Add a translation
   "nav.mydspace": "MyDSpace",
-  
+
   // "nav.search": "Search",
-  // TODO New key - Add a translation
-  "nav.search": "Search",
-  
+  "nav.search": "Zoek",
+
   // "nav.statistics.header": "Statistics",
-  // TODO New key - Add a translation
-  "nav.statistics.header": "Statistics",
-  
-  
-  
+  "nav.statistics.header": "Statistieken",
+
+
+
   // "orgunit.listelement.badge": "Organizational Unit",
-  // TODO New key - Add a translation
-  "orgunit.listelement.badge": "Organizational Unit",
-  
+  "orgunit.listelement.badge": "Organisatie-onderdeel",
+
   // "orgunit.page.city": "City",
-  // TODO New key - Add a translation
-  "orgunit.page.city": "City",
-  
+  "orgunit.page.city": "Plaats",
+
   // "orgunit.page.country": "Country",
-  // TODO New key - Add a translation
-  "orgunit.page.country": "Country",
-  
+  "orgunit.page.country": "Land",
+
   // "orgunit.page.dateestablished": "Date established",
-  // TODO New key - Add a translation
-  "orgunit.page.dateestablished": "Date established",
-  
+  "orgunit.page.dateestablished": "Stichtingsdatum",
+
   // "orgunit.page.description": "Description",
-  // TODO New key - Add a translation
-  "orgunit.page.description": "Description",
-  
+  "orgunit.page.description": "Beschrijving",
+
   // "orgunit.page.id": "ID",
-  // TODO New key - Add a translation
   "orgunit.page.id": "ID",
-  
+
   // "orgunit.page.titleprefix": "Organizational Unit: ",
-  // TODO New key - Add a translation
-  "orgunit.page.titleprefix": "Organizational Unit: ",
-  
-  
-  
+  "orgunit.page.titleprefix": "Organisatie-onderdeel: ",
+
+
+
   // "pagination.results-per-page": "Results Per Page",
   "pagination.results-per-page": "Resultaten per pagina",
-  
+
   // "pagination.showing.detail": "{{ range }} of {{ total }}",
   "pagination.showing.detail": "{{ range }} van {{ total }}",
-  
+
   // "pagination.showing.label": "Now showing ",
   "pagination.showing.label": "Resultaten ",
-  
+
   // "pagination.sort-direction": "Sort Options",
   "pagination.sort-direction": "Sorteermogelijkheden",
-  
-  
-  
+
+
+
   // "person.listelement.badge": "Person",
-  // TODO New key - Add a translation
-  "person.listelement.badge": "Person",
-  
+  "person.listelement.badge": "Persoon",
+
   // "person.page.birthdate": "Birth Date",
-  // TODO New key - Add a translation
-  "person.page.birthdate": "Birth Date",
-  
+  "person.page.birthdate": "Geboortedatum",
+
   // "person.page.email": "Email Address",
-  // TODO New key - Add a translation
-  "person.page.email": "Email Address",
-  
+  "person.page.email": "Emailadres",
+
   // "person.page.firstname": "First Name",
-  // TODO New key - Add a translation
-  "person.page.firstname": "First Name",
-  
+  "person.page.firstname": "Voornaam",
+
   // "person.page.jobtitle": "Job Title",
-  // TODO New key - Add a translation
-  "person.page.jobtitle": "Job Title",
-  
+  "person.page.jobtitle": "Functie",
+
   // "person.page.lastname": "Last Name",
-  // TODO New key - Add a translation
-  "person.page.lastname": "Last Name",
-  
+  "person.page.lastname": "Achternaam",
+
   // "person.page.link.full": "Show all metadata",
-  // TODO New key - Add a translation
-  "person.page.link.full": "Show all metadata",
-  
+  "person.page.link.full": "Toon alle metadata",
+
   // "person.page.orcid": "ORCID",
-  // TODO New key - Add a translation
   "person.page.orcid": "ORCID",
-  
+
   // "person.page.staffid": "Staff ID",
-  // TODO New key - Add a translation
-  "person.page.staffid": "Staff ID",
-  
+  "person.page.staffid": "Personeels-ID",
+
   // "person.page.titleprefix": "Person: ",
-  // TODO New key - Add a translation
-  "person.page.titleprefix": "Person: ",
-  
+  "person.page.titleprefix": "Persoon: ",
+
   // "person.search.results.head": "Person Search Results",
-  // TODO New key - Add a translation
-  "person.search.results.head": "Person Search Results",
-  
+  "person.search.results.head": "Zoekresultaten Persoon",
+
   // "person.search.title": "DSpace Angular :: Person Search",
-  // TODO New key - Add a translation
-  "person.search.title": "DSpace Angular :: Person Search",
-  
-  
-  
+  "person.search.title": "DSpace Angular :: Persoon zoeken",
+
+
+
   // "project.listelement.badge": "Research Project",
-  // TODO New key - Add a translation
-  "project.listelement.badge": "Research Project",
-  
+  "project.listelement.badge": "Onderzoeksproject",
+
   // "project.page.contributor": "Contributors",
-  // TODO New key - Add a translation
   "project.page.contributor": "Contributors",
-  
+
   // "project.page.description": "Description",
-  // TODO New key - Add a translation
-  "project.page.description": "Description",
-  
+  "project.page.description": "Beschrijving",
+
   // "project.page.expectedcompletion": "Expected Completion",
-  // TODO New key - Add a translation
-  "project.page.expectedcompletion": "Expected Completion",
-  
+  "project.page.expectedcompletion": "Verwachte afronding",
+
   // "project.page.funder": "Funders",
-  // TODO New key - Add a translation
   "project.page.funder": "Funders",
-  
+
   // "project.page.id": "ID",
-  // TODO New key - Add a translation
   "project.page.id": "ID",
-  
+
   // "project.page.keyword": "Keywords",
-  // TODO New key - Add a translation
-  "project.page.keyword": "Keywords",
-  
+  "project.page.keyword": "Trefwoorden",
+
   // "project.page.status": "Status",
-  // TODO New key - Add a translation
   "project.page.status": "Status",
-  
+
   // "project.page.titleprefix": "Research Project: ",
-  // TODO New key - Add a translation
-  "project.page.titleprefix": "Research Project: ",
-  
-  
-  
+  "project.page.titleprefix": "Onderzoeksproject: ",
+
+
+
   // "publication.listelement.badge": "Publication",
-  // TODO New key - Add a translation
-  "publication.listelement.badge": "Publication",
-  
+  "publication.listelement.badge": "Publicatie",
+
   // "publication.page.description": "Description",
-  // TODO New key - Add a translation
-  "publication.page.description": "Description",
-  
+  "publication.page.description": "Beschrijving",
+
   // "publication.page.journal-issn": "Journal ISSN",
-  // TODO New key - Add a translation
-  "publication.page.journal-issn": "Journal ISSN",
-  
+  "publication.page.journal-issn": "Tijdschrift ISSN",
+
   // "publication.page.journal-title": "Journal Title",
-  // TODO New key - Add a translation
-  "publication.page.journal-title": "Journal Title",
-  
+  "publication.page.journal-title": "Tijdschrifttitel",
+
   // "publication.page.publisher": "Publisher",
-  // TODO New key - Add a translation
-  "publication.page.publisher": "Publisher",
-  
+  "publication.page.publisher": "Uitgever",
+
   // "publication.page.titleprefix": "Publication: ",
-  // TODO New key - Add a translation
-  "publication.page.titleprefix": "Publication: ",
-  
+  "publication.page.titleprefix": "Publicatie: ",
+
   // "publication.page.volume-title": "Volume Title",
-  // TODO New key - Add a translation
-  "publication.page.volume-title": "Volume Title",
-  
+  "publication.page.volume-title": "Jaargangtitel",
+
   // "publication.search.results.head": "Publication Search Results",
-  // TODO New key - Add a translation
-  "publication.search.results.head": "Publication Search Results",
-  
+  "publication.search.results.head": "Publicatie zoekresultaten",
+
   // "publication.search.title": "DSpace Angular :: Publication Search",
-  // TODO New key - Add a translation
-  "publication.search.title": "DSpace Angular :: Publication Search",
-  
-  
-  
+  "publication.search.title": "DSpace Angular :: Publicatie zoeken",
+
+
+
   // "relationships.isAuthorOf": "Authors",
-  // TODO New key - Add a translation
-  "relationships.isAuthorOf": "Authors",
-  
+  "relationships.isAuthorOf": "Auteurs",
+
   // "relationships.isIssueOf": "Journal Issues",
-  // TODO New key - Add a translation
-  "relationships.isIssueOf": "Journal Issues",
-  
+  "relationships.isIssueOf": "Tijdschriftafleveringen",
+
   // "relationships.isJournalIssueOf": "Journal Issue",
-  // TODO New key - Add a translation
-  "relationships.isJournalIssueOf": "Journal Issue",
-  
+  "relationships.isJournalIssueOf": "Tijdschriftaflevering",
+
   // "relationships.isJournalOf": "Journals",
-  // TODO New key - Add a translation
-  "relationships.isJournalOf": "Journals",
-  
+  "relationships.isJournalOf": "Tijdschriften",
+
   // "relationships.isOrgUnitOf": "Organizational Units",
-  // TODO New key - Add a translation
-  "relationships.isOrgUnitOf": "Organizational Units",
-  
+  "relationships.isOrgUnitOf": "Organisatie-onderdelen",
+
   // "relationships.isPersonOf": "Authors",
-  // TODO New key - Add a translation
-  "relationships.isPersonOf": "Authors",
-  
+  "relationships.isPersonOf": "Auteurs",
+
   // "relationships.isProjectOf": "Research Projects",
-  // TODO New key - Add a translation
-  "relationships.isProjectOf": "Research Projects",
-  
+  "relationships.isProjectOf": "Onderzoeksprojecten",
+
   // "relationships.isPublicationOf": "Publications",
-  // TODO New key - Add a translation
-  "relationships.isPublicationOf": "Publications",
-  
+  "relationships.isPublicationOf": "Publicaties",
+
   // "relationships.isPublicationOfJournalIssue": "Articles",
-  // TODO New key - Add a translation
-  "relationships.isPublicationOfJournalIssue": "Articles",
-  
+  "relationships.isPublicationOfJournalIssue": "Artikelen",
+
   // "relationships.isSingleJournalOf": "Journal",
-  // TODO New key - Add a translation
-  "relationships.isSingleJournalOf": "Journal",
-  
+  "relationships.isSingleJournalOf": "Tijdschrift",
+
   // "relationships.isSingleVolumeOf": "Journal Volume",
-  // TODO New key - Add a translation
-  "relationships.isSingleVolumeOf": "Journal Volume",
-  
+  "relationships.isSingleVolumeOf": "Tijdschriftjaargang",
+
   // "relationships.isVolumeOf": "Journal Volumes",
-  // TODO New key - Add a translation
-  "relationships.isVolumeOf": "Journal Volumes",
-  
-  
-  
+  "relationships.isVolumeOf": "Tijdschriftjaargangen",
+
+
+
   // "search.description": "",
   "search.description": "",
-  
+
   // "search.switch-configuration.title": "Show",
-  // TODO New key - Add a translation
-  "search.switch-configuration.title": "Show",
-  
+  "search.switch-configuration.title": "Toon",
+
   // "search.title": "DSpace Angular :: Search",
   "search.title": "DSpace Angular :: Zoek",
-  
-  
-  
+
+
+
   // "search.filters.applied.f.author": "Author",
   "search.filters.applied.f.author": "Auteur",
-  
+
   // "search.filters.applied.f.dateIssued.max": "End date",
   "search.filters.applied.f.dateIssued.max": "Einddatum",
-  
+
   // "search.filters.applied.f.dateIssued.min": "Start date",
   "search.filters.applied.f.dateIssued.min": "Startdatum",
-  
+
   // "search.filters.applied.f.dateSubmitted": "Date submitted",
-  // TODO New key - Add a translation
-  "search.filters.applied.f.dateSubmitted": "Date submitted",
-  
+   "search.filters.applied.f.dateSubmitted": "Indiendatum",
+
   // "search.filters.applied.f.entityType": "Item Type",
-  // TODO New key - Add a translation
-  "search.filters.applied.f.entityType": "Item Type",
-  
+  "search.filters.applied.f.entityType": "Soort item",
+
   // "search.filters.applied.f.has_content_in_original_bundle": "Has files",
   "search.filters.applied.f.has_content_in_original_bundle": "Heeft bestanden",
-  
+
   // "search.filters.applied.f.itemtype": "Type",
-  // TODO New key - Add a translation
-  "search.filters.applied.f.itemtype": "Type",
-  
+   "search.filters.applied.f.itemtype": "Type",
+
   // "search.filters.applied.f.namedresourcetype": "Status",
-  // TODO New key - Add a translation
   "search.filters.applied.f.namedresourcetype": "Status",
-  
+
   // "search.filters.applied.f.subject": "Subject",
-  "search.filters.applied.f.subject": "Sleutelwoord",
-  
+  "search.filters.applied.f.subject": "Onderwerp",
+
   // "search.filters.applied.f.submitter": "Submitter",
-  // TODO New key - Add a translation
-  "search.filters.applied.f.submitter": "Submitter",
-  
-  
-  
+  "search.filters.applied.f.submitter": "Indiener",
+
+
+
   // "search.filters.filter.author.head": "Author",
   "search.filters.filter.author.head": "Auteur",
-  
+
   // "search.filters.filter.author.placeholder": "Author name",
   "search.filters.filter.author.placeholder": "Auteursnaam",
-  
+
   // "search.filters.filter.birthDate.head": "Birth Date",
-  // TODO New key - Add a translation
-  "search.filters.filter.birthDate.head": "Birth Date",
-  
+  "search.filters.filter.birthDate.head": "Geboortedatum",
+
   // "search.filters.filter.birthDate.placeholder": "Birth Date",
-  // TODO New key - Add a translation
-  "search.filters.filter.birthDate.placeholder": "Birth Date",
-  
+  "search.filters.filter.birthDate.placeholder": "Geboortedatum",
+
   // "search.filters.filter.creativeDatePublished.head": "Date Published",
-  // TODO New key - Add a translation
-  "search.filters.filter.creativeDatePublished.head": "Date Published",
-  
+  "search.filters.filter.creativeDatePublished.head": "Datum van uitgave",
+
   // "search.filters.filter.creativeDatePublished.placeholder": "Date Published",
-  // TODO New key - Add a translation
-  "search.filters.filter.creativeDatePublished.placeholder": "Date Published",
-  
+  "search.filters.filter.creativeDatePublished.placeholder": "Datum van uitgave",
+
   // "search.filters.filter.creativeWorkEditor.head": "Editor",
-  // TODO New key - Add a translation
-  "search.filters.filter.creativeWorkEditor.head": "Editor",
-  
+  "search.filters.filter.creativeWorkEditor.head": "Redacteur",
+
   // "search.filters.filter.creativeWorkEditor.placeholder": "Editor",
-  // TODO New key - Add a translation
-  "search.filters.filter.creativeWorkEditor.placeholder": "Editor",
-  
+  "search.filters.filter.creativeWorkEditor.placeholder": "Redacteur",
+
   // "search.filters.filter.creativeWorkKeywords.head": "Subject",
-  // TODO New key - Add a translation
-  "search.filters.filter.creativeWorkKeywords.head": "Subject",
-  
+  "search.filters.filter.creativeWorkKeywords.head": "Onderwerp",
+
   // "search.filters.filter.creativeWorkKeywords.placeholder": "Subject",
-  // TODO New key - Add a translation
-  "search.filters.filter.creativeWorkKeywords.placeholder": "Subject",
-  
+  "search.filters.filter.creativeWorkKeywords.placeholder": "Onderwerp",
+
   // "search.filters.filter.creativeWorkPublisher.head": "Publisher",
-  // TODO New key - Add a translation
-  "search.filters.filter.creativeWorkPublisher.head": "Publisher",
-  
+  "search.filters.filter.creativeWorkPublisher.head": "Uitgever",
+
   // "search.filters.filter.creativeWorkPublisher.placeholder": "Publisher",
-  // TODO New key - Add a translation
-  "search.filters.filter.creativeWorkPublisher.placeholder": "Publisher",
-  
+  "search.filters.filter.creativeWorkPublisher.placeholder": "Uitgever",
+
   // "search.filters.filter.dateIssued.head": "Date",
   "search.filters.filter.dateIssued.head": "Datum",
-  
+
   // "search.filters.filter.dateIssued.max.placeholder": "Minimum Date",
   "search.filters.filter.dateIssued.max.placeholder": "Vroegste Datum",
-  
+
   // "search.filters.filter.dateIssued.min.placeholder": "Maximum Date",
   "search.filters.filter.dateIssued.min.placeholder": "Laatste Datum",
-  
+
   // "search.filters.filter.dateSubmitted.head": "Date submitted",
-  // TODO New key - Add a translation
-  "search.filters.filter.dateSubmitted.head": "Date submitted",
-  
+  "search.filters.filter.dateSubmitted.head": "Indiendatum",
+
   // "search.filters.filter.dateSubmitted.placeholder": "Date submitted",
-  // TODO New key - Add a translation
-  "search.filters.filter.dateSubmitted.placeholder": "Date submitted",
-  
+  "search.filters.filter.dateSubmitted.placeholder": "Indiendatum",
+
   // "search.filters.filter.entityType.head": "Item Type",
-  // TODO New key - Add a translation
-  "search.filters.filter.entityType.head": "Item Type",
-  
+  "search.filters.filter.entityType.head": "Soort item",
+
   // "search.filters.filter.entityType.placeholder": "Item Type",
-  // TODO New key - Add a translation
-  "search.filters.filter.entityType.placeholder": "Item Type",
-  
+  "search.filters.filter.entityType.placeholder": "Soort item",
+
   // "search.filters.filter.has_content_in_original_bundle.head": "Has files",
   "search.filters.filter.has_content_in_original_bundle.head": "Heeft bestanden",
-  
+
   // "search.filters.filter.itemtype.head": "Type",
-  // TODO New key - Add a translation
   "search.filters.filter.itemtype.head": "Type",
-  
+
   // "search.filters.filter.itemtype.placeholder": "Type",
-  // TODO New key - Add a translation
   "search.filters.filter.itemtype.placeholder": "Type",
-  
+
   // "search.filters.filter.jobTitle.head": "Job Title",
-  // TODO New key - Add a translation
-  "search.filters.filter.jobTitle.head": "Job Title",
-  
+  "search.filters.filter.jobTitle.head": "Functienaam",
+
   // "search.filters.filter.jobTitle.placeholder": "Job Title",
-  // TODO New key - Add a translation
-  "search.filters.filter.jobTitle.placeholder": "Job Title",
-  
+  "search.filters.filter.jobTitle.placeholder": "Functienaam",
+
   // "search.filters.filter.knowsLanguage.head": "Known language",
-  // TODO New key - Add a translation
-  "search.filters.filter.knowsLanguage.head": "Known language",
-  
+  "search.filters.filter.knowsLanguage.head": "Kent taal",
+
   // "search.filters.filter.knowsLanguage.placeholder": "Known language",
-  // TODO New key - Add a translation
-  "search.filters.filter.knowsLanguage.placeholder": "Known language",
-  
+  "search.filters.filter.knowsLanguage.placeholder": "Kent taal",
+
   // "search.filters.filter.namedresourcetype.head": "Status",
-  // TODO New key - Add a translation
   "search.filters.filter.namedresourcetype.head": "Status",
-  
+
   // "search.filters.filter.namedresourcetype.placeholder": "Status",
-  // TODO New key - Add a translation
   "search.filters.filter.namedresourcetype.placeholder": "Status",
-  
+
   // "search.filters.filter.objectpeople.head": "People",
-  // TODO New key - Add a translation
-  "search.filters.filter.objectpeople.head": "People",
-  
+  "search.filters.filter.objectpeople.head": "Personen",
+
   // "search.filters.filter.objectpeople.placeholder": "People",
-  // TODO New key - Add a translation
-  "search.filters.filter.objectpeople.placeholder": "People",
-  
+  "search.filters.filter.objectpeople.placeholder": "Personen",
+
   // "search.filters.filter.organizationAddressCountry.head": "Country",
-  // TODO New key - Add a translation
-  "search.filters.filter.organizationAddressCountry.head": "Country",
-  
+  "search.filters.filter.organizationAddressCountry.head": "Land",
+
   // "search.filters.filter.organizationAddressCountry.placeholder": "Country",
-  // TODO New key - Add a translation
-  "search.filters.filter.organizationAddressCountry.placeholder": "Country",
-  
+  "search.filters.filter.organizationAddressCountry.placeholder": "Land",
+
   // "search.filters.filter.organizationAddressLocality.head": "City",
-  // TODO New key - Add a translation
-  "search.filters.filter.organizationAddressLocality.head": "City",
-  
+  "search.filters.filter.organizationAddressLocality.head": "Plaats",
+
   // "search.filters.filter.organizationAddressLocality.placeholder": "City",
-  // TODO New key - Add a translation
-  "search.filters.filter.organizationAddressLocality.placeholder": "City",
-  
+  "search.filters.filter.organizationAddressLocality.placeholder": "Plaats",
+
   // "search.filters.filter.organizationFoundingDate.head": "Date Founded",
-  // TODO New key - Add a translation
-  "search.filters.filter.organizationFoundingDate.head": "Date Founded",
-  
+  "search.filters.filter.organizationFoundingDate.head": "Oprichtingsdatum",
+
   // "search.filters.filter.organizationFoundingDate.placeholder": "Date Founded",
-  // TODO New key - Add a translation
-  "search.filters.filter.organizationFoundingDate.placeholder": "Date Founded",
-  
+  "search.filters.filter.organizationFoundingDate.placeholder": "Oprichtingsdatum",
+
   // "search.filters.filter.scope.head": "Scope",
   "search.filters.filter.scope.head": "Bereik",
-  
+
   // "search.filters.filter.scope.placeholder": "Scope filter",
   "search.filters.filter.scope.placeholder": "Bereikfilter",
-  
+
   // "search.filters.filter.show-less": "Collapse",
   "search.filters.filter.show-less": "Inklappen",
-  
+
   // "search.filters.filter.show-more": "Show more",
   "search.filters.filter.show-more": "Toon meer",
-  
+
   // "search.filters.filter.subject.head": "Subject",
   "search.filters.filter.subject.head": "Onderwerp",
-  
+
   // "search.filters.filter.subject.placeholder": "Subject",
   "search.filters.filter.subject.placeholder": "Onderwerp",
-  
+
   // "search.filters.filter.submitter.head": "Submitter",
-  // TODO New key - Add a translation
-  "search.filters.filter.submitter.head": "Submitter",
-  
+  "search.filters.filter.submitter.head": "Indiener",
+
   // "search.filters.filter.submitter.placeholder": "Submitter",
-  // TODO New key - Add a translation
-  "search.filters.filter.submitter.placeholder": "Submitter",
-  
-  
-  
+  "search.filters.filter.submitter.placeholder": "Indiener",
+
+
+
   // "search.filters.head": "Filters",
   "search.filters.head": "Filters",
-  
+
   // "search.filters.reset": "Reset filters",
   "search.filters.reset": "Filters verwijderen",
-  
-  
-  
+
+
+
   // "search.form.search": "Search",
   "search.form.search": "Zoek",
-  
+
   // "search.form.search_dspace": "Search DSpace",
   "search.form.search_dspace": "Zoek in DSpace",
-  
+
   // "search.form.search_mydspace": "Search MyDSpace",
-  // TODO New key - Add a translation
-  "search.form.search_mydspace": "Search MyDSpace",
-  
-  
-  
+  "search.form.search_mydspace": "Zoek in MyDSpace",
+
+
+
   // "search.results.head": "Search Results",
   "search.results.head": "Zoekresultaten",
-  
+
   // "search.results.no-results": "Your search returned no results. Having trouble finding what you're looking for? Try putting",
-  "search.results.no-results": "Er waren geen resultaten voor deze zoekopdracht",
-  
+  "search.results.no-results": "Er waren geen resultaten voor deze zoekopdracht. Kunt u niet vinden wat u zoekt? Probeer het met ",
+
   // "search.results.no-results-link": "quotes around it",
-  // TODO New key - Add a translation
-  "search.results.no-results-link": "quotes around it",
-  
-  
-  
+   "search.results.no-results-link": "aanhalingstekens om uw zoekterm",
+
+
+
   // "search.sidebar.close": "Back to results",
   "search.sidebar.close": "Terug naar de resultaten",
-  
+
   // "search.sidebar.filters.title": "Filters",
   "search.sidebar.filters.title": "Filters",
-  
+
   // "search.sidebar.open": "Search Tools",
-  "search.sidebar.open": "Zoek Tools",
-  
+  "search.sidebar.open": "Zoekmogelijkheden",
+
   // "search.sidebar.results": "results",
   "search.sidebar.results": "resultaten",
-  
+
   // "search.sidebar.settings.rpp": "Results per page",
   "search.sidebar.settings.rpp": "Resultaten per pagina",
-  
+
   // "search.sidebar.settings.sort-by": "Sort By",
   "search.sidebar.settings.sort-by": "Sorteer volgens",
-  
+
   // "search.sidebar.settings.title": "Settings",
   "search.sidebar.settings.title": "Instellingen",
-  
-  
-  
+
+
+
   // "search.view-switch.show-detail": "Show detail",
-  // TODO New key - Add a translation
-  "search.view-switch.show-detail": "Show detail",
-  
+  "search.view-switch.show-detail": "Toon detail",
+
   // "search.view-switch.show-grid": "Show as grid",
   "search.view-switch.show-grid": "Toon in raster",
-  
+
   // "search.view-switch.show-list": "Show as list",
   "search.view-switch.show-list": "Toon als lijst",
-  
-  
-  
+
+
+
   // "sorting.dc.title.ASC": "Title Ascending",
   "sorting.dc.title.ASC": "Oplopend op titel",
-  
+
   // "sorting.dc.title.DESC": "Title Descending",
   "sorting.dc.title.DESC": "Aflopend op titel",
-  
+
   // "sorting.score.DESC": "Relevance",
   "sorting.score.DESC": "Relevantie",
-  
-  
-  
+
+
+
   // "submission.edit.title": "Edit Submission",
-  // TODO New key - Add a translation
-  "submission.edit.title": "Edit Submission",
-  
+   "submission.edit.title": "Bewerk submission",
+
   // "submission.general.cannot_submit": "You have not the privilege to make a new submission.",
-  // TODO New key - Add a translation
-  "submission.general.cannot_submit": "You have not the privilege to make a new submission.",
-  
+  "submission.general.cannot_submit": "U heeft niet voldoende rechten om een nieuwe submission in te dienen.",
+
   // "submission.general.deposit": "Deposit",
-  // TODO New key - Add a translation
-  "submission.general.deposit": "Deposit",
-  
+  "submission.general.deposit": "Dien in",
+
   // "submission.general.discard.confirm.cancel": "Cancel",
-  // TODO New key - Add a translation
-  "submission.general.discard.confirm.cancel": "Cancel",
-  
+  "submission.general.discard.confirm.cancel": "Annuleer",
+
   // "submission.general.discard.confirm.info": "This operation can't be undone. Are you sure?",
-  // TODO New key - Add a translation
-  "submission.general.discard.confirm.info": "This operation can't be undone. Are you sure?",
-  
+  "submission.general.discard.confirm.info": "Deze handeling kan niet ongedaan worden gemaakt. Weet u het zeker?",
+
   // "submission.general.discard.confirm.submit": "Yes, I'm sure",
-  // TODO New key - Add a translation
-  "submission.general.discard.confirm.submit": "Yes, I'm sure",
-  
+  "submission.general.discard.confirm.submit": "Ja, ik weet het zeker",
+
   // "submission.general.discard.confirm.title": "Discard submission",
-  // TODO New key - Add a translation
-  "submission.general.discard.confirm.title": "Discard submission",
-  
+  "submission.general.discard.confirm.title": "Annuleer submission",
+
   // "submission.general.discard.submit": "Discard",
-  // TODO New key - Add a translation
-  "submission.general.discard.submit": "Discard",
-  
+   "submission.general.discard.submit": "Annuleer",
+
   // "submission.general.save": "Save",
-  // TODO New key - Add a translation
-  "submission.general.save": "Save",
-  
+  "submission.general.save": "Opslaan",
+
   // "submission.general.save-later": "Save for later",
-  // TODO New key - Add a translation
-  "submission.general.save-later": "Save for later",
-  
-  
-  
+  "submission.general.save-later": "Bewaar voor later",
+
+
+
   // "submission.sections.general.add-more": "Add more",
-  // TODO New key - Add a translation
-  "submission.sections.general.add-more": "Add more",
-  
+  "submission.sections.general.add-more": "Voeg meer toe",
+
   // "submission.sections.general.collection": "Collection",
-  // TODO New key - Add a translation
-  "submission.sections.general.collection": "Collection",
-  
+  "submission.sections.general.collection": "Collectie",
+
   // "submission.sections.general.deposit_error_notice": "There was an issue when submitting the item, please try again later.",
-  // TODO New key - Add a translation
-  "submission.sections.general.deposit_error_notice": "There was an issue when submitting the item, please try again later.",
-  
+  "submission.sections.general.deposit_error_notice": "Er is een probleem opgetreden bij het indienen van het item. Probeer het later nog eens.",
+
   // "submission.sections.general.deposit_success_notice": "Submission deposited successfully.",
-  // TODO New key - Add a translation
-  "submission.sections.general.deposit_success_notice": "Submission deposited successfully.",
-  
+  "submission.sections.general.deposit_success_notice": "Submission ingediend.",
+
   // "submission.sections.general.discard_error_notice": "There was an issue when discarding the item, please try again later.",
-  // TODO New key - Add a translation
-  "submission.sections.general.discard_error_notice": "There was an issue when discarding the item, please try again later.",
-  
+  "submission.sections.general.discard_error_notice": "Er is een probleem opgetreden bij het annuleren van de submission. Probeer het later nog eens.",
+
   // "submission.sections.general.discard_success_notice": "Submission discarded successfully.",
-  // TODO New key - Add a translation
-  "submission.sections.general.discard_success_notice": "Submission discarded successfully.",
-  
+  "submission.sections.general.discard_success_notice": "Submission geannuleerd.",
+
   // "submission.sections.general.metadata-extracted": "New metadata have been extracted and added to the <strong>{{sectionId}}</strong> section.",
-  // TODO New key - Add a translation
-  "submission.sections.general.metadata-extracted": "New metadata have been extracted and added to the <strong>{{sectionId}}</strong> section.",
-  
+  "submission.sections.general.metadata-extracted": "Er zijn nieuwe metadata gevonden en toegevoegd aan de <strong>{{sectionId}}</strong> sectie.",
+
   // "submission.sections.general.metadata-extracted-new-section": "New <strong>{{sectionId}}</strong> section has been added to submission.",
-  // TODO New key - Add a translation
-  "submission.sections.general.metadata-extracted-new-section": "New <strong>{{sectionId}}</strong> section has been added to submission.",
-  
+  "submission.sections.general.metadata-extracted-new-section": "De nieuwe sectie <strong>{{sectionId}}</strong> is toegevoegd aaan de submission.",
+
   // "submission.sections.general.no-collection": "No collection found",
-  // TODO New key - Add a translation
-  "submission.sections.general.no-collection": "No collection found",
-  
+  "submission.sections.general.no-collection": "Geen collectie gevonden",
+
   // "submission.sections.general.no-sections": "No options available",
-  // TODO New key - Add a translation
-  "submission.sections.general.no-sections": "No options available",
-  
+  "submission.sections.general.no-sections": "Geen opties beschikbaar",
+
   // "submission.sections.general.save_error_notice": "There was an issue when saving the item, please try again later.",
-  // TODO New key - Add a translation
-  "submission.sections.general.save_error_notice": "There was an issue when saving the item, please try again later.",
-  
+  "submission.sections.general.save_error_notice": "Er is een probleem opgetreden bij het bewaren van het item. Probeer het later nog eens.",
+
   // "submission.sections.general.save_success_notice": "Submission saved successfully.",
-  // TODO New key - Add a translation
-  "submission.sections.general.save_success_notice": "Submission saved successfully.",
-  
+  "submission.sections.general.save_success_notice": "Submission is opgeslagen.",
+
   // "submission.sections.general.search-collection": "Search for a collection",
-  // TODO New key - Add a translation
-  "submission.sections.general.search-collection": "Search for a collection",
-  
+  "submission.sections.general.search-collection": "Zoek een collectie",
+
   // "submission.sections.general.sections_not_valid": "There are incomplete sections.",
-  // TODO New key - Add a translation
-  "submission.sections.general.sections_not_valid": "There are incomplete sections.",
-  
-  
-  
+   "submission.sections.general.sections_not_valid": "Sommige secties zijn onvolledig.",
+
+
+
   // "submission.sections.submit.progressbar.cclicense": "Creative commons license",
-  // TODO New key - Add a translation
-  "submission.sections.submit.progressbar.cclicense": "Creative commons license",
-  
+  "submission.sections.submit.progressbar.cclicense": "Creative commons licentie",
+
   // "submission.sections.submit.progressbar.describe.recycle": "Recycle",
-  // TODO New key - Add a translation
   "submission.sections.submit.progressbar.describe.recycle": "Recycle",
-  
+
   // "submission.sections.submit.progressbar.describe.stepcustom": "Describe",
-  // TODO New key - Add a translation
-  "submission.sections.submit.progressbar.describe.stepcustom": "Describe",
-  
+   "submission.sections.submit.progressbar.describe.stepcustom": "Beschrijf",
+
   // "submission.sections.submit.progressbar.describe.stepone": "Describe",
-  // TODO New key - Add a translation
-  "submission.sections.submit.progressbar.describe.stepone": "Describe",
-  
+  "submission.sections.submit.progressbar.describe.stepone": "Beschrijf",
+
   // "submission.sections.submit.progressbar.describe.steptwo": "Describe",
-  // TODO New key - Add a translation
-  "submission.sections.submit.progressbar.describe.steptwo": "Describe",
-  
+  "submission.sections.submit.progressbar.describe.steptwo": "Beschrijf",
+
   // "submission.sections.submit.progressbar.detect-duplicate": "Potential duplicates",
-  // TODO New key - Add a translation
-  "submission.sections.submit.progressbar.detect-duplicate": "Potential duplicates",
-  
+   "submission.sections.submit.progressbar.detect-duplicate": "Mogelijke verdubbeling",
+
   // "submission.sections.submit.progressbar.license": "Deposit license",
-  // TODO New key - Add a translation
-  "submission.sections.submit.progressbar.license": "Deposit license",
-  
+   "submission.sections.submit.progressbar.license": "Deposit licentie",
+
   // "submission.sections.submit.progressbar.upload": "Upload files",
-  // TODO New key - Add a translation
-  "submission.sections.submit.progressbar.upload": "Upload files",
-  
-  
-  
+  "submission.sections.submit.progressbar.upload": "Upload bestanden",
+
+
+
   // "submission.sections.upload.delete.confirm.cancel": "Cancel",
-  // TODO New key - Add a translation
-  "submission.sections.upload.delete.confirm.cancel": "Cancel",
-  
+  "submission.sections.upload.delete.confirm.cancel": "Annuleer",
+
   // "submission.sections.upload.delete.confirm.info": "This operation can't be undone. Are you sure?",
-  // TODO New key - Add a translation
-  "submission.sections.upload.delete.confirm.info": "This operation can't be undone. Are you sure?",
-  
+  "submission.sections.upload.delete.confirm.info": "Deze handeling kan niet ongedaan worden gemaakt. Weet u het zeker?",
+
   // "submission.sections.upload.delete.confirm.submit": "Yes, I'm sure",
-  // TODO New key - Add a translation
-  "submission.sections.upload.delete.confirm.submit": "Yes, I'm sure",
-  
+  "submission.sections.upload.delete.confirm.submit": "Ja, ik weet het zeker",
+
   // "submission.sections.upload.delete.confirm.title": "Delete bitstream",
-  // TODO New key - Add a translation
-  "submission.sections.upload.delete.confirm.title": "Delete bitstream",
-  
+  "submission.sections.upload.delete.confirm.title": "Verwijder bitstream",
+
   // "submission.sections.upload.delete.submit": "Delete",
-  // TODO New key - Add a translation
-  "submission.sections.upload.delete.submit": "Delete",
-  
+  "submission.sections.upload.delete.submit": "Verwijder",
+
   // "submission.sections.upload.drop-message": "Drop files to attach them to the item",
-  // TODO New key - Add a translation
-  "submission.sections.upload.drop-message": "Drop files to attach them to the item",
-  
+  "submission.sections.upload.drop-message": "Sleep bestanden om ze toe te voegen aan het item",
+
   // "submission.sections.upload.form.access-condition-label": "Access condition type",
-  // TODO New key - Add a translation
-  "submission.sections.upload.form.access-condition-label": "Access condition type",
-  
+  "submission.sections.upload.form.access-condition-label": "Soort toegangsrecht",
+
   // "submission.sections.upload.form.date-required": "Date is required.",
-  // TODO New key - Add a translation
-  "submission.sections.upload.form.date-required": "Date is required.",
-  
+  "submission.sections.upload.form.date-required": "De datum is verplicht.",
+
   // "submission.sections.upload.form.from-label": "Access grant from",
-  // TODO New key - Add a translation
-  "submission.sections.upload.form.from-label": "Access grant from",
-  
+   "submission.sections.upload.form.from-label": "Toegang vanaf",
+
   // "submission.sections.upload.form.from-placeholder": "From",
-  // TODO New key - Add a translation
-  "submission.sections.upload.form.from-placeholder": "From",
-  
+  "submission.sections.upload.form.from-placeholder": "Van",
+
   // "submission.sections.upload.form.group-label": "Group",
-  // TODO New key - Add a translation
-  "submission.sections.upload.form.group-label": "Group",
-  
+  "submission.sections.upload.form.group-label": "Groep",
+
   // "submission.sections.upload.form.group-required": "Group is required.",
-  // TODO New key - Add a translation
-  "submission.sections.upload.form.group-required": "Group is required.",
-  
+   "submission.sections.upload.form.group-required": "Groep is verplicht.",
+
   // "submission.sections.upload.form.until-label": "Access grant until",
-  // TODO New key - Add a translation
-  "submission.sections.upload.form.until-label": "Access grant until",
-  
+   "submission.sections.upload.form.until-label": "Toegang tot",
+
   // "submission.sections.upload.form.until-placeholder": "Until",
-  // TODO New key - Add a translation
-  "submission.sections.upload.form.until-placeholder": "Until",
-  
+   "submission.sections.upload.form.until-placeholder": "Tot",
+
   // "submission.sections.upload.header.policy.default.nolist": "Uploaded files in the {{collectionName}} collection will be accessible according to the following group(s):",
-  // TODO New key - Add a translation
-  "submission.sections.upload.header.policy.default.nolist": "Uploaded files in the {{collectionName}} collection will be accessible according to the following group(s):",
-  
+  "submission.sections.upload.header.policy.default.nolist": "Bestanden in de collectie {{collectionName}} zullen toegankelijk zijn volgens deze groep(en):",
+
   // "submission.sections.upload.header.policy.default.withlist": "Please note that uploaded files in the {{collectionName}} collection will be accessible, in addition to what is explicitly decided for the single file, with the following group(s):",
-  // TODO New key - Add a translation
-  "submission.sections.upload.header.policy.default.withlist": "Please note that uploaded files in the {{collectionName}} collection will be accessible, in addition to what is explicitly decided for the single file, with the following group(s):",
-  
+   "submission.sections.upload.header.policy.default.withlist": "Let op: bestanden in de collectie {{collectionName}} zullen niet alleen toegankelijk zijn volgens de expliciet toegekende rechten per bestand, maar ook volgens de volgende groep(en):",
+
   // "submission.sections.upload.info": "Here you will find all the files currently in the item. You can update the file metadata and access conditions or <strong>upload additional files just dragging & dropping them everywhere in the page</strong>",
-  // TODO New key - Add a translation
-  "submission.sections.upload.info": "Here you will find all the files currently in the item. You can update the file metadata and access conditions or <strong>upload additional files just dragging & dropping them everywhere in the page</strong>",
-  
+   "submission.sections.upload.info": "Hier vindt u alle bestanden van het item. U kunt de metadata en toegangsrechten bewerken of <strong>meer bestanden toevoegen door ze naar deze pagina te slepen.</strong>",
+
   // "submission.sections.upload.no-entry": "No",
-  // TODO New key - Add a translation
-  "submission.sections.upload.no-entry": "No",
-  
+  "submission.sections.upload.no-entry": "Nee",
+
   // "submission.sections.upload.no-file-uploaded": "No file uploaded yet.",
-  // TODO New key - Add a translation
-  "submission.sections.upload.no-file-uploaded": "No file uploaded yet.",
-  
+  "submission.sections.upload.no-file-uploaded": "Nog geen bestand geupload.",
+
   // "submission.sections.upload.save-metadata": "Save metadata",
-  // TODO New key - Add a translation
-  "submission.sections.upload.save-metadata": "Save metadata",
-  
+   "submission.sections.upload.save-metadata": "Bewaar metadata",
+
   // "submission.sections.upload.undo": "Cancel",
-  // TODO New key - Add a translation
-  "submission.sections.upload.undo": "Cancel",
-  
+  "submission.sections.upload.undo": "Annuleer",
+
   // "submission.sections.upload.upload-failed": "Upload failed",
-  // TODO New key - Add a translation
-  "submission.sections.upload.upload-failed": "Upload failed",
-  
+   "submission.sections.upload.upload-failed": "Upload mislukt",
+
   // "submission.sections.upload.upload-successful": "Upload successful",
-  // TODO New key - Add a translation
-  "submission.sections.upload.upload-successful": "Upload successful",
-  
-  
-  
+  "submission.sections.upload.upload-successful": "Upload geslaagd",
+
+
+
   // "submission.submit.title": "Submission",
-  // TODO New key - Add a translation
   "submission.submit.title": "Submission",
-  
-  
-  
+
+
+
   // "submission.workflow.generic.delete": "Delete",
-  // TODO New key - Add a translation
-  "submission.workflow.generic.delete": "Delete",
-  
+  "submission.workflow.generic.delete": "Verwijder",
+
   // "submission.workflow.generic.delete-help": "If you would to discard this item, select \"Delete\".  You will then be asked to confirm it.",
-  // TODO New key - Add a translation
-  "submission.workflow.generic.delete-help": "If you would to discard this item, select \"Delete\".  You will then be asked to confirm it.",
-  
+  "submission.workflow.generic.delete-help": "Als u dit item wilt verwijderen, kies \"Verwijder\". Er zal gevraagd worden dit te bevestigen.",
+
   // "submission.workflow.generic.edit": "Edit",
-  // TODO New key - Add a translation
-  "submission.workflow.generic.edit": "Edit",
-  
+  "submission.workflow.generic.edit": "Bewerk",
+
   // "submission.workflow.generic.edit-help": "Select this option to change the item's metadata.",
-  // TODO New key - Add a translation
-  "submission.workflow.generic.edit-help": "Select this option to change the item's metadata.",
-  
+   "submission.workflow.generic.edit-help": "Kies deze optie om de metadata van het item te bewerken.",
+
   // "submission.workflow.generic.view": "View",
-  // TODO New key - Add a translation
-  "submission.workflow.generic.view": "View",
-  
+  "submission.workflow.generic.view": "Bekijk",
+
   // "submission.workflow.generic.view-help": "Select this option to view the item's metadata.",
-  // TODO New key - Add a translation
-  "submission.workflow.generic.view-help": "Select this option to view the item's metadata.",
-  
-  
-  
+  "submission.workflow.generic.view-help": "Kies deze optie om de metadata van het item te bekijken.",
+
+
+
   // "submission.workflow.tasks.claimed.approve": "Approve",
-  // TODO New key - Add a translation
-  "submission.workflow.tasks.claimed.approve": "Approve",
-  
+  "submission.workflow.tasks.claimed.approve": "Accepteer",
+
   // "submission.workflow.tasks.claimed.approve_help": "If you have reviewed the item and it is suitable for inclusion in the collection, select \"Approve\".",
-  // TODO New key - Add a translation
-  "submission.workflow.tasks.claimed.approve_help": "If you have reviewed the item and it is suitable for inclusion in the collection, select \"Approve\".",
-  
+  "submission.workflow.tasks.claimed.approve_help": "Als u het item gecontroleerd heeft en het geschikt is om in de collectie te worden opgenomen, kiest u \"Accepteer\".",
+
   // "submission.workflow.tasks.claimed.edit": "Edit",
-  // TODO New key - Add a translation
-  "submission.workflow.tasks.claimed.edit": "Edit",
-  
+  "submission.workflow.tasks.claimed.edit": "Bewerk",
+
   // "submission.workflow.tasks.claimed.edit_help": "Select this option to change the item's metadata.",
-  // TODO New key - Add a translation
-  "submission.workflow.tasks.claimed.edit_help": "Select this option to change the item's metadata.",
-  
+   "submission.workflow.tasks.claimed.edit_help": "Kies deze optie om de metadata van het item te bewerken.",
+
   // "submission.workflow.tasks.claimed.reject.reason.info": "Please enter your reason for rejecting the submission into the box below, indicating whether the submitter may fix a problem and resubmit.",
-  // TODO New key - Add a translation
-  "submission.workflow.tasks.claimed.reject.reason.info": "Please enter your reason for rejecting the submission into the box below, indicating whether the submitter may fix a problem and resubmit.",
-  
+  "submission.workflow.tasks.claimed.reject.reason.info": "Vul uw reden om dit item te weigeren. Geef hierbij aan of de indiener het probleem kan verhelpen en het item opnieuw kan indienen.",
+
   // "submission.workflow.tasks.claimed.reject.reason.placeholder": "Describe the reason of reject",
-  // TODO New key - Add a translation
-  "submission.workflow.tasks.claimed.reject.reason.placeholder": "Describe the reason of reject",
-  
+  "submission.workflow.tasks.claimed.reject.reason.placeholder": "Reden voor weigering",
+
   // "submission.workflow.tasks.claimed.reject.reason.submit": "Reject item",
-  // TODO New key - Add a translation
-  "submission.workflow.tasks.claimed.reject.reason.submit": "Reject item",
-  
+   "submission.workflow.tasks.claimed.reject.reason.submit": "Weiger item",
+
   // "submission.workflow.tasks.claimed.reject.reason.title": "Reason",
-  // TODO New key - Add a translation
-  "submission.workflow.tasks.claimed.reject.reason.title": "Reason",
-  
+  "submission.workflow.tasks.claimed.reject.reason.title": "Reden",
+
   // "submission.workflow.tasks.claimed.reject.submit": "Reject",
-  // TODO New key - Add a translation
-  "submission.workflow.tasks.claimed.reject.submit": "Reject",
-  
+   "submission.workflow.tasks.claimed.reject.submit": "Weiger",
+
   // "submission.workflow.tasks.claimed.reject_help": "If you have reviewed the item and found it is <strong>not</strong> suitable for inclusion in the collection, select \"Reject\".  You will then be asked to enter a message indicating why the item is unsuitable, and whether the submitter should change something and resubmit.",
-  // TODO New key - Add a translation
-  "submission.workflow.tasks.claimed.reject_help": "If you have reviewed the item and found it is <strong>not</strong> suitable for inclusion in the collection, select \"Reject\".  You will then be asked to enter a message indicating why the item is unsuitable, and whether the submitter should change something and resubmit.",
-  
+  "submission.workflow.tasks.claimed.reject_help": "Als u het item gecontroleerd heeft en heeft geconstateerd dat het <strong>niet</strong> geschikt is om opgenomen te worden, kies dan \"Weiger\". Er zal gevraagd worden om de reden van de weigering te geven. Ook kunt u aangeven of de indiener iets kan wijzigen en opnieuw indienen.",
+
   // "submission.workflow.tasks.claimed.return": "Return to pool",
-  // TODO New key - Add a translation
-  "submission.workflow.tasks.claimed.return": "Return to pool",
-  
+  "submission.workflow.tasks.claimed.return": "Terug naar pool",
+
   // "submission.workflow.tasks.claimed.return_help": "Return the task to the pool so that another user may perform the task.",
-  // TODO New key - Add a translation
-  "submission.workflow.tasks.claimed.return_help": "Return the task to the pool so that another user may perform the task.",
-  
-  
-  
+   "submission.workflow.tasks.claimed.return_help": "Stuur de taak terug naar de pool, zodat iemand anders de taak kan uitvoeren.",
+
+
+
   // "submission.workflow.tasks.generic.error": "Error occurred during operation...",
-  // TODO New key - Add a translation
-  "submission.workflow.tasks.generic.error": "Error occurred during operation...",
-  
+  "submission.workflow.tasks.generic.error": "Er is een fout opgetreden tijdens de verwerking...",
+
   // "submission.workflow.tasks.generic.processing": "Processing...",
-  // TODO New key - Add a translation
-  "submission.workflow.tasks.generic.processing": "Processing...",
-  
+  "submission.workflow.tasks.generic.processing": "Bezig met verwerken...",
+
   // "submission.workflow.tasks.generic.submitter": "Submitter",
-  // TODO New key - Add a translation
-  "submission.workflow.tasks.generic.submitter": "Submitter",
-  
+  "submission.workflow.tasks.generic.submitter": "Indiener",
+
   // "submission.workflow.tasks.generic.success": "Operation successful",
-  // TODO New key - Add a translation
-  "submission.workflow.tasks.generic.success": "Operation successful",
-  
-  
-  
+    "submission.workflow.tasks.generic.success": "Verwerking geslaagd",
+
+
+
   // "submission.workflow.tasks.pool.claim": "Claim",
-  // TODO New key - Add a translation
   "submission.workflow.tasks.pool.claim": "Claim",
-  
+
   // "submission.workflow.tasks.pool.claim_help": "Assign this task to yourself.",
-  // TODO New key - Add a translation
-  "submission.workflow.tasks.pool.claim_help": "Assign this task to yourself.",
-  
+  "submission.workflow.tasks.pool.claim_help": "Ken uzelf deze taak toe.",
+
   // "submission.workflow.tasks.pool.hide-detail": "Hide detail",
-  // TODO New key - Add a translation
-  "submission.workflow.tasks.pool.hide-detail": "Hide detail",
-  
+  "submission.workflow.tasks.pool.hide-detail": "Verberg detail",
+
   // "submission.workflow.tasks.pool.show-detail": "Show detail",
-  // TODO New key - Add a translation
-  "submission.workflow.tasks.pool.show-detail": "Show detail",
-  
-  
-  
+  "submission.workflow.tasks.pool.show-detail": "Toon detail",
+
+
+
   // "title": "DSpace",
   "title": "DSpace",
-  
-  
-  
+
+
+
   // "uploader.browse": "browse",
-  // TODO New key - Add a translation
-  "uploader.browse": "browse",
-  
+  "uploader.browse": "blader",
+
   // "uploader.drag-message": "Drag & Drop your files here",
-  // TODO New key - Add a translation
-  "uploader.drag-message": "Drag & Drop your files here",
-  
+  "uploader.drag-message": "Sleep uw bestanden hierheen",
+
   // "uploader.or": ", or",
-  // TODO New key - Add a translation
-  "uploader.or": ", or",
-  
+  "uploader.or": ", of",
+
   // "uploader.processing": "Processing",
-  // TODO New key - Add a translation
-  "uploader.processing": "Processing",
-  
+  "uploader.processing": "Bezig",
+
   // "uploader.queue-length": "Queue length",
-  // TODO New key - Add a translation
-  "uploader.queue-length": "Queue length",
-  
-  
-  
+  "uploader.queue-length": "Queue lengte",
+
+
+
 
 }
diff --git a/spec-bundle.js b/spec-bundle.js
index aa46c35d1484582ece8b198616c3bca60303c77d..d7f32eb20c3a50d68725078d6bdeeaaa2713582f 100644
--- a/spec-bundle.js
+++ b/spec-bundle.js
@@ -13,8 +13,8 @@
  */
 Error.stackTraceLimit = Infinity;
 
-require('core-js/es6');
-require('core-js/es7/reflect');
+require('core-js/es');
+require('core-js/features/reflect');
 
 // Typescript emit helpers polyfill
 require('ts-helpers');
diff --git a/src/app/+admin/admin-registries/bitstream-formats/add-bitstream-format/add-bitstream-format.component.spec.ts b/src/app/+admin/admin-registries/bitstream-formats/add-bitstream-format/add-bitstream-format.component.spec.ts
index 0a10633956ca0a9f1179bc8a36ec90707ad35bda..4ad35535230308301c2903735f93d24fd7966b38 100644
--- a/src/app/+admin/admin-registries/bitstream-formats/add-bitstream-format/add-bitstream-format.component.spec.ts
+++ b/src/app/+admin/admin-registries/bitstream-formats/add-bitstream-format/add-bitstream-format.component.spec.ts
@@ -1,19 +1,18 @@
-import { async, ComponentFixture, TestBed } from '@angular/core/testing';
 import { CommonModule } from '@angular/common';
+import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { Router } from '@angular/router';
 import { RouterTestingModule } from '@angular/router/testing';
-import { TranslateModule } from '@ngx-translate/core';
 import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
-import { Router } from '@angular/router';
-import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
-import { RouterStub } from '../../../../shared/testing/router-stub';
+import { TranslateModule } from '@ngx-translate/core';
 import { of as observableOf } from 'rxjs';
-import { NotificationsService } from '../../../../shared/notifications/notifications.service';
-import { NotificationsServiceStub } from '../../../../shared/testing/notifications-service-stub';
-import { BitstreamFormatDataService } from '../../../../core/data/bitstream-format-data.service';
 import { RestResponse } from '../../../../core/cache/response.models';
-import { BitstreamFormat } from '../../../../core/shared/bitstream-format.model';
+import { BitstreamFormatDataService } from '../../../../core/data/bitstream-format-data.service';
 import { BitstreamFormatSupportLevel } from '../../../../core/shared/bitstream-format-support-level';
-import { ResourceType } from '../../../../core/shared/resource-type';
+import { BitstreamFormat } from '../../../../core/shared/bitstream-format.model';
+import { NotificationsService } from '../../../../shared/notifications/notifications.service';
+import { NotificationsServiceStub } from '../../../../shared/testing/notifications-service-stub';
+import { RouterStub } from '../../../../shared/testing/router-stub';
 import { AddBitstreamFormatComponent } from './add-bitstream-format.component';
 
 describe('AddBitstreamFormatComponent', () => {
@@ -43,7 +42,7 @@ describe('AddBitstreamFormatComponent', () => {
     });
 
     TestBed.configureTestingModule({
-      imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule.forRoot()],
+      imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule],
       declarations: [AddBitstreamFormatComponent],
       providers: [
         {provide: Router, useValue: router},
@@ -83,7 +82,7 @@ describe('AddBitstreamFormatComponent', () => {
       });
 
       TestBed.configureTestingModule({
-        imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule.forRoot()],
+        imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule],
         declarations: [AddBitstreamFormatComponent],
         providers: [
           {provide: Router, useValue: router},
diff --git a/src/app/+admin/admin-registries/bitstream-formats/bitstream-formats.component.spec.ts b/src/app/+admin/admin-registries/bitstream-formats/bitstream-formats.component.spec.ts
index e672dc82ea5ce3ed3602eb9b249144d55edbee87..7ff15cad6df31cfa4ab3b974a9c77c0f929f0b4a 100644
--- a/src/app/+admin/admin-registries/bitstream-formats/bitstream-formats.component.spec.ts
+++ b/src/app/+admin/admin-registries/bitstream-formats/bitstream-formats.component.spec.ts
@@ -92,7 +92,7 @@ describe('BitstreamFormatsComponent', () => {
     });
 
     TestBed.configureTestingModule({
-      imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule.forRoot()],
+      imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule],
       declarations: [BitstreamFormatsComponent, PaginationComponent, EnumKeysPipe],
       providers: [
         {provide: BitstreamFormatDataService, useValue: bitstreamFormatService},
@@ -214,7 +214,7 @@ describe('BitstreamFormatsComponent', () => {
         });
 
         TestBed.configureTestingModule({
-          imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule.forRoot()],
+          imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule],
           declarations: [BitstreamFormatsComponent, PaginationComponent, EnumKeysPipe],
           providers: [
             {provide: BitstreamFormatDataService, useValue: bitstreamFormatService},
@@ -230,10 +230,10 @@ describe('BitstreamFormatsComponent', () => {
       comp.deleteFormats();
 
       expect(bitstreamFormatService.clearBitStreamFormatRequests).toHaveBeenCalled();
-      expect(bitstreamFormatService.delete).toHaveBeenCalledWith(bitstreamFormat1);
-      expect(bitstreamFormatService.delete).toHaveBeenCalledWith(bitstreamFormat2);
-      expect(bitstreamFormatService.delete).toHaveBeenCalledWith(bitstreamFormat3);
-      expect(bitstreamFormatService.delete).toHaveBeenCalledWith(bitstreamFormat4);
+      expect(bitstreamFormatService.delete).toHaveBeenCalledWith(bitstreamFormat1.id);
+      expect(bitstreamFormatService.delete).toHaveBeenCalledWith(bitstreamFormat2.id);
+      expect(bitstreamFormatService.delete).toHaveBeenCalledWith(bitstreamFormat3.id);
+      expect(bitstreamFormatService.delete).toHaveBeenCalledWith(bitstreamFormat4.id);
 
       expect(notificationsServiceStub.success).toHaveBeenCalledWith('admin.registries.bitstream-formats.delete.success.head',
         'admin.registries.bitstream-formats.delete.success.amount');
@@ -260,7 +260,7 @@ describe('BitstreamFormatsComponent', () => {
         });
 
         TestBed.configureTestingModule({
-          imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule.forRoot()],
+          imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule],
           declarations: [BitstreamFormatsComponent, PaginationComponent, EnumKeysPipe],
           providers: [
             {provide: BitstreamFormatDataService, useValue: bitstreamFormatService},
@@ -276,10 +276,10 @@ describe('BitstreamFormatsComponent', () => {
       comp.deleteFormats();
 
       expect(bitstreamFormatService.clearBitStreamFormatRequests).toHaveBeenCalled();
-      expect(bitstreamFormatService.delete).toHaveBeenCalledWith(bitstreamFormat1);
-      expect(bitstreamFormatService.delete).toHaveBeenCalledWith(bitstreamFormat2);
-      expect(bitstreamFormatService.delete).toHaveBeenCalledWith(bitstreamFormat3);
-      expect(bitstreamFormatService.delete).toHaveBeenCalledWith(bitstreamFormat4);
+      expect(bitstreamFormatService.delete).toHaveBeenCalledWith(bitstreamFormat1.id);
+      expect(bitstreamFormatService.delete).toHaveBeenCalledWith(bitstreamFormat2.id);
+      expect(bitstreamFormatService.delete).toHaveBeenCalledWith(bitstreamFormat3.id);
+      expect(bitstreamFormatService.delete).toHaveBeenCalledWith(bitstreamFormat4.id);
 
       expect(notificationsServiceStub.error).toHaveBeenCalledWith('admin.registries.bitstream-formats.delete.failure.head',
         'admin.registries.bitstream-formats.delete.failure.amount');
diff --git a/src/app/+admin/admin-registries/bitstream-formats/bitstream-formats.component.ts b/src/app/+admin/admin-registries/bitstream-formats/bitstream-formats.component.ts
index ec4003c108fb11f59a997e48cbd1f80cdf029c5b..52010e0132bf71016cdb5cac3384cced946e388b 100644
--- a/src/app/+admin/admin-registries/bitstream-formats/bitstream-formats.component.ts
+++ b/src/app/+admin/admin-registries/bitstream-formats/bitstream-formats.component.ts
@@ -64,7 +64,7 @@ export class BitstreamFormatsComponent implements OnInit {
         const tasks$ = [];
         for (const format of formats) {
           if (hasValue(format.id)) {
-            tasks$.push(this.bitstreamFormatService.delete(format));
+            tasks$.push(this.bitstreamFormatService.delete(format.id));
           }
         }
         zip(...tasks$).subscribe((results: boolean[]) => {
diff --git a/src/app/+admin/admin-registries/bitstream-formats/edit-bitstream-format/edit-bitstream-format.component.spec.ts b/src/app/+admin/admin-registries/bitstream-formats/edit-bitstream-format/edit-bitstream-format.component.spec.ts
index cfa93a15a84c80d74e26a4fb1b895e7c7c7ba58c..87e44a6fec459a1c482607b2d61f4d68882640d6 100644
--- a/src/app/+admin/admin-registries/bitstream-formats/edit-bitstream-format/edit-bitstream-format.component.spec.ts
+++ b/src/app/+admin/admin-registries/bitstream-formats/edit-bitstream-format/edit-bitstream-format.component.spec.ts
@@ -1,21 +1,20 @@
-import { async, ComponentFixture, TestBed } from '@angular/core/testing';
 import { CommonModule } from '@angular/common';
+import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { ActivatedRoute, Router } from '@angular/router';
 import { RouterTestingModule } from '@angular/router/testing';
-import { TranslateModule } from '@ngx-translate/core';
 import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
-import { ActivatedRoute, Router } from '@angular/router';
-import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
-import { RouterStub } from '../../../../shared/testing/router-stub';
+import { TranslateModule } from '@ngx-translate/core';
 import { of as observableOf } from 'rxjs';
+import { RestResponse } from '../../../../core/cache/response.models';
+import { BitstreamFormatDataService } from '../../../../core/data/bitstream-format-data.service';
 import { RemoteData } from '../../../../core/data/remote-data';
-import { EditBitstreamFormatComponent } from './edit-bitstream-format.component';
+import { BitstreamFormatSupportLevel } from '../../../../core/shared/bitstream-format-support-level';
+import { BitstreamFormat } from '../../../../core/shared/bitstream-format.model';
 import { NotificationsService } from '../../../../shared/notifications/notifications.service';
 import { NotificationsServiceStub } from '../../../../shared/testing/notifications-service-stub';
-import { BitstreamFormatDataService } from '../../../../core/data/bitstream-format-data.service';
-import { RestResponse } from '../../../../core/cache/response.models';
-import { BitstreamFormat } from '../../../../core/shared/bitstream-format.model';
-import { BitstreamFormatSupportLevel } from '../../../../core/shared/bitstream-format-support-level';
-import { ResourceType } from '../../../../core/shared/resource-type';
+import { RouterStub } from '../../../../shared/testing/router-stub';
+import { EditBitstreamFormatComponent } from './edit-bitstream-format.component';
 
 describe('EditBitstreamFormatComponent', () => {
   let comp: EditBitstreamFormatComponent;
@@ -49,7 +48,7 @@ describe('EditBitstreamFormatComponent', () => {
     });
 
     TestBed.configureTestingModule({
-      imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule.forRoot()],
+      imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule],
       declarations: [EditBitstreamFormatComponent],
       providers: [
         {provide: ActivatedRoute, useValue: routeStub},
@@ -99,7 +98,7 @@ describe('EditBitstreamFormatComponent', () => {
       });
 
       TestBed.configureTestingModule({
-        imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule.forRoot()],
+        imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule],
         declarations: [EditBitstreamFormatComponent],
         providers: [
           {provide: ActivatedRoute, useValue: routeStub},
diff --git a/src/app/+admin/admin-registries/bitstream-formats/format-form/format-form.component.spec.ts b/src/app/+admin/admin-registries/bitstream-formats/format-form/format-form.component.spec.ts
index 2870705fc8fa2b6d27e6307a434e5abca6ebd330..efc8854587ab1caa5b0aad43dc0dc68051f74f27 100644
--- a/src/app/+admin/admin-registries/bitstream-formats/format-form/format-form.component.spec.ts
+++ b/src/app/+admin/admin-registries/bitstream-formats/format-form/format-form.component.spec.ts
@@ -40,7 +40,7 @@ describe('FormatFormComponent', () => {
 
   const initAsync = () => {
     TestBed.configureTestingModule({
-      imports: [CommonModule, RouterTestingModule.withRoutes([]), ReactiveFormsModule, FormsModule, TranslateModule.forRoot(), NgbModule.forRoot()],
+      imports: [CommonModule, RouterTestingModule.withRoutes([]), ReactiveFormsModule, FormsModule, TranslateModule.forRoot(), NgbModule],
       declarations: [FormatFormComponent],
       providers: [
         {provide: Router, useValue: router},
diff --git a/src/app/+admin/admin-registries/metadata-registry/metadata-registry.actions.ts b/src/app/+admin/admin-registries/metadata-registry/metadata-registry.actions.ts
index 96f9d345f59b57ac3e4e8ff0dc5e1f09fb3335b1..9737928a13c3a3ec182db41663fe65bf7f0b92cc 100644
--- a/src/app/+admin/admin-registries/metadata-registry/metadata-registry.actions.ts
+++ b/src/app/+admin/admin-registries/metadata-registry/metadata-registry.actions.ts
@@ -148,4 +148,6 @@ export type MetadataRegistryAction
   | MetadataRegistryEditFieldAction
   | MetadataRegistryCancelFieldAction
   | MetadataRegistrySelectFieldAction
-  | MetadataRegistryDeselectFieldAction;
+  | MetadataRegistryDeselectFieldAction
+  | MetadataRegistryDeselectAllSchemaAction
+  | MetadataRegistryDeselectAllFieldAction;
diff --git a/src/app/+admin/admin-registries/metadata-registry/metadata-registry.component.spec.ts b/src/app/+admin/admin-registries/metadata-registry/metadata-registry.component.spec.ts
index 674ae739d8e6840c4a3d6eeb9a270cb092d2b4ef..409e6f988e87350c6d79fda876e42f08b099bf04 100644
--- a/src/app/+admin/admin-registries/metadata-registry/metadata-registry.component.spec.ts
+++ b/src/app/+admin/admin-registries/metadata-registry/metadata-registry.component.spec.ts
@@ -26,13 +26,21 @@ describe('MetadataRegistryComponent', () => {
   const mockSchemasList = [
     {
       id: 1,
-      self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadataschemas/1',
+      _links: {
+        self: {
+          href: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadataschemas/1'
+        },
+      },
       prefix: 'dc',
       namespace: 'http://dublincore.org/documents/dcmi-terms/'
     },
     {
       id: 2,
-      self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadataschemas/2',
+      _links: {
+        self: {
+          href: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadataschemas/2'
+        },
+      },
       prefix: 'mock',
       namespace: 'http://dspace.org/mockschema'
     }
@@ -53,7 +61,7 @@ describe('MetadataRegistryComponent', () => {
 
   beforeEach(async(() => {
     TestBed.configureTestingModule({
-      imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule.forRoot()],
+      imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule],
       declarations: [MetadataRegistryComponent, PaginationComponent, EnumKeysPipe],
       providers: [
         { provide: RegistryService, useValue: registryServiceStub },
diff --git a/src/app/+admin/admin-registries/metadata-registry/metadata-registry.reducers.spec.ts b/src/app/+admin/admin-registries/metadata-registry/metadata-registry.reducers.spec.ts
index 2f7d606c60a656c46c4ebb4d38f143d7ca100b2b..48d1b89e7c45c21075145073955db9c00fcecbf0 100644
--- a/src/app/+admin/admin-registries/metadata-registry/metadata-registry.reducers.spec.ts
+++ b/src/app/+admin/admin-registries/metadata-registry/metadata-registry.reducers.spec.ts
@@ -20,7 +20,11 @@ class NullAction extends MetadataRegistryEditSchemaAction {
 const schema: MetadataSchema = Object.assign(new MetadataSchema(),
   {
     id: 'schema-id',
-    self: 'http://rest.self/schema/dc',
+    _links: {
+      self: {
+        href: 'http://rest.self/schema/dc'
+      },
+    },
     prefix: 'dc',
     namespace: 'http://dublincore.org/documents/dcmi-terms/'
   });
@@ -28,7 +32,11 @@ const schema: MetadataSchema = Object.assign(new MetadataSchema(),
 const schema2: MetadataSchema = Object.assign(new MetadataSchema(),
   {
     id: 'another-schema-id',
-    self: 'http://rest.self/schema/dcterms',
+    _links: {
+      self: {
+        href: 'http://rest.self/schema/dcterms',
+      },
+    },
     prefix: 'dcterms',
     namespace: 'http://purl.org/dc/terms/'
   });
@@ -36,7 +44,11 @@ const schema2: MetadataSchema = Object.assign(new MetadataSchema(),
 const field: MetadataField = Object.assign(new MetadataField(),
   {
     id: 'author-field-id',
-    self: 'http://rest.self/field/author',
+    _links: {
+      self: {
+        href: 'http://rest.self/field/author',
+      },
+    },
     element: 'contributor',
     qualifier: 'author',
     scopeNote: 'Author of an item',
@@ -46,7 +58,11 @@ const field: MetadataField = Object.assign(new MetadataField(),
 const field2: MetadataField = Object.assign(new MetadataField(),
   {
     id: 'title-field-id',
-    self: 'http://rest.self/field/title',
+    _links: {
+      self: {
+        href: 'http://rest.self/field/title',
+      },
+    },
     element: 'title',
     qualifier: null,
     scopeNote: 'Title of an item',
diff --git a/src/app/+admin/admin-registries/metadata-registry/metadata-schema-form/metadata-schema-form.component.spec.ts b/src/app/+admin/admin-registries/metadata-registry/metadata-schema-form/metadata-schema-form.component.spec.ts
index fb76035d4b5349e69bc06a7293549a30b7ad4f01..db2294ab5913d1503da268971fef74ceba3f50d4 100644
--- a/src/app/+admin/admin-registries/metadata-registry/metadata-schema-form/metadata-schema-form.component.spec.ts
+++ b/src/app/+admin/admin-registries/metadata-registry/metadata-schema-form/metadata-schema-form.component.spec.ts
@@ -34,7 +34,7 @@ describe('MetadataSchemaFormComponent', () => {
 
   beforeEach(async(() => {
     TestBed.configureTestingModule({
-      imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule.forRoot()],
+      imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule],
       declarations: [ MetadataSchemaFormComponent, EnumKeysPipe ],
       providers: [
         { provide: RegistryService, useValue: registryServiceStub },
diff --git a/src/app/+admin/admin-registries/metadata-schema/metadata-field-form/metadata-field-form.component.spec.ts b/src/app/+admin/admin-registries/metadata-schema/metadata-field-form/metadata-field-form.component.spec.ts
index 3c4f858c5584fd594f976b9c0f61b7c410ea6e49..402f9c0c862d9018ce43e656170b891d1ffca429 100644
--- a/src/app/+admin/admin-registries/metadata-schema/metadata-field-form/metadata-field-form.component.spec.ts
+++ b/src/app/+admin/admin-registries/metadata-schema/metadata-field-form/metadata-field-form.component.spec.ts
@@ -42,7 +42,7 @@ describe('MetadataFieldFormComponent', () => {
 
   beforeEach(async(() => {
     TestBed.configureTestingModule({
-      imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule.forRoot()],
+      imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule],
       declarations: [ MetadataFieldFormComponent, EnumKeysPipe ],
       providers: [
         { provide: RegistryService, useValue: registryServiceStub },
diff --git a/src/app/+admin/admin-registries/metadata-schema/metadata-schema.component.spec.ts b/src/app/+admin/admin-registries/metadata-schema/metadata-schema.component.spec.ts
index e0b0ef25a5d383f36a79a411de78bfd46749ef46..f3d87bd29c9b9efd55d751430da99763cb016985 100644
--- a/src/app/+admin/admin-registries/metadata-schema/metadata-schema.component.spec.ts
+++ b/src/app/+admin/admin-registries/metadata-schema/metadata-schema.component.spec.ts
@@ -30,13 +30,21 @@ describe('MetadataSchemaComponent', () => {
   const mockSchemasList = [
     {
       id: 1,
-      self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadataschemas/1',
+      _links: {
+        self: {
+          href: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadataschemas/1',
+        },
+      },
       prefix: 'dc',
       namespace: 'http://dublincore.org/documents/dcmi-terms/'
     },
     {
       id: 2,
-      self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadataschemas/2',
+      _links: {
+        self: {
+          href: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadataschemas/2',
+        },
+      },
       prefix: 'mock',
       namespace: 'http://dspace.org/mockschema'
     }
@@ -44,7 +52,11 @@ describe('MetadataSchemaComponent', () => {
   const mockFieldsList = [
     {
       id: 1,
-      self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadatafields/8',
+      _links: {
+        self: {
+          href: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadatafields/8',
+        },
+      },
       element: 'contributor',
       qualifier: 'advisor',
       scopeNote: null,
@@ -52,7 +64,11 @@ describe('MetadataSchemaComponent', () => {
     },
     {
       id: 2,
-      self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadatafields/9',
+      _links: {
+        self: {
+          href: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadatafields/9',
+        },
+      },
       element: 'contributor',
       qualifier: 'author',
       scopeNote: null,
@@ -60,7 +76,11 @@ describe('MetadataSchemaComponent', () => {
     },
     {
       id: 3,
-      self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadatafields/10',
+      _links: {
+        self: {
+          href: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadatafields/10',
+        },
+      },
       element: 'contributor',
       qualifier: 'editor',
       scopeNote: 'test scope note',
@@ -68,7 +88,11 @@ describe('MetadataSchemaComponent', () => {
     },
     {
       id: 4,
-      self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadatafields/11',
+      _links: {
+        self: {
+          href: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadatafields/11',
+        },
+      },
       element: 'contributor',
       qualifier: 'illustrator',
       scopeNote: null,
@@ -99,7 +123,7 @@ describe('MetadataSchemaComponent', () => {
 
   beforeEach(async(() => {
     TestBed.configureTestingModule({
-      imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule.forRoot()],
+      imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule],
       declarations: [MetadataSchemaComponent, PaginationComponent, EnumKeysPipe],
       providers: [
         { provide: RegistryService, useValue: registryServiceStub },
diff --git a/src/app/+bitstream-page/edit-bitstream-page/edit-bitstream-page.component.ts b/src/app/+bitstream-page/edit-bitstream-page/edit-bitstream-page.component.ts
index 242ecc4a5625594d12e53986234e654f4f095542..58fbec75d456337f22dce56f11917d84f49537c6 100644
--- a/src/app/+bitstream-page/edit-bitstream-page/edit-bitstream-page.component.ts
+++ b/src/app/+bitstream-page/edit-bitstream-page/edit-bitstream-page.component.ts
@@ -464,7 +464,7 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy {
     bitstream$.pipe(
       switchMap(() => {
         if (isNewFormat) {
-          const operation = Object.assign({op: 'replace', path: '/format', value: selectedFormat.self});
+          const operation = Object.assign({op: 'replace', path: '/format', value: selectedFormat._links.self});
           this.bitstreamService.patch(this.bitstream.self, [operation]);
         }
 
diff --git a/src/app/+browse-by/+browse-by-date-page/browse-by-date-page.component.spec.ts b/src/app/+browse-by/+browse-by-date-page/browse-by-date-page.component.spec.ts
index a1951a6d5a0ef0b3b308c912314c7fac42eaf4cd..0c060520ce4391d50dfa26a7f636b45da0cbf116 100644
--- a/src/app/+browse-by/+browse-by-date-page/browse-by-date-page.component.spec.ts
+++ b/src/app/+browse-by/+browse-by-date-page/browse-by-date-page.component.spec.ts
@@ -68,7 +68,7 @@ describe('BrowseByDatePageComponent', () => {
 
   beforeEach(async(() => {
     TestBed.configureTestingModule({
-      imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule.forRoot()],
+      imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule],
       declarations: [BrowseByDatePageComponent, EnumKeysPipe, VarDirective],
       providers: [
         { provide: GLOBAL_CONFIG, useValue: ENV_CONFIG },
diff --git a/src/app/+browse-by/+browse-by-metadata-page/browse-by-metadata-page.component.spec.ts b/src/app/+browse-by/+browse-by-metadata-page/browse-by-metadata-page.component.spec.ts
index 553bd00f56e6389d0f50a8d7280ccd4b03d28d7c..601e7153e9ea9b92f82dc87fdd4cabf04c38da52 100644
--- a/src/app/+browse-by/+browse-by-metadata-page/browse-by-metadata-page.component.spec.ts
+++ b/src/app/+browse-by/+browse-by-metadata-page/browse-by-metadata-page.component.spec.ts
@@ -20,7 +20,6 @@ import { Item } from '../../core/shared/item.model';
 import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.service';
 import { Community } from '../../core/shared/community.model';
 import { MockRouter } from '../../shared/mocks/mock-router';
-import { ResourceType } from '../../core/shared/resource-type';
 import { createSuccessfulRemoteDataObject$ } from '../../shared/testing/utils';
 import { BrowseEntry } from '../../core/shared/browse-entry.model';
 import { VarDirective } from '../../shared/utils/var.directive';
@@ -86,7 +85,7 @@ describe('BrowseByMetadataPageComponent', () => {
 
   beforeEach(async(() => {
     TestBed.configureTestingModule({
-      imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule.forRoot()],
+      imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule],
       declarations: [BrowseByMetadataPageComponent, EnumKeysPipe, VarDirective],
       providers: [
         { provide: ActivatedRoute, useValue: activatedRouteStub },
diff --git a/src/app/+browse-by/+browse-by-title-page/browse-by-title-page.component.spec.ts b/src/app/+browse-by/+browse-by-title-page/browse-by-title-page.component.spec.ts
index 90623eb3c73ea362d0b6ebb070132de8e9b3cb83..83a3ca3030a79285b4fa9575de331702bb94202c 100644
--- a/src/app/+browse-by/+browse-by-title-page/browse-by-title-page.component.spec.ts
+++ b/src/app/+browse-by/+browse-by-title-page/browse-by-title-page.component.spec.ts
@@ -64,7 +64,7 @@ describe('BrowseByTitlePageComponent', () => {
 
   beforeEach(async(() => {
     TestBed.configureTestingModule({
-      imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule.forRoot()],
+      imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule],
       declarations: [BrowseByTitlePageComponent, EnumKeysPipe, VarDirective],
       providers: [
         { provide: ActivatedRoute, useValue: activatedRouteStub },
diff --git a/src/app/+browse-by/browse-by-dso-breadcrumb.resolver.ts b/src/app/+browse-by/browse-by-dso-breadcrumb.resolver.ts
new file mode 100644
index 0000000000000000000000000000000000000000..5759e287545ccc854a4b85039744733359758ecf
--- /dev/null
+++ b/src/app/+browse-by/browse-by-dso-breadcrumb.resolver.ts
@@ -0,0 +1,41 @@
+import { Injectable } from '@angular/core';
+import { Community } from '../core/shared/community.model';
+import { DSpaceObjectDataService } from '../core/data/dspace-object-data.service';
+import { DSOBreadcrumbsService } from '../core/breadcrumbs/dso-breadcrumbs.service';
+import { Collection } from '../core/shared/collection.model';
+import { ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
+import { BreadcrumbConfig } from '../breadcrumbs/breadcrumb/breadcrumb-config.model';
+import { Observable } from 'rxjs';
+import { getRemoteDataPayload, getSucceededRemoteData } from '../core/shared/operators';
+import { map } from 'rxjs/operators';
+import { hasValue } from '../shared/empty.util';
+import { getDSOPath } from '../app-routing.module';
+
+/**
+ * The class that resolves the BreadcrumbConfig object for a DSpaceObject on a browse by page
+ */
+@Injectable()
+export class BrowseByDSOBreadcrumbResolver {
+  constructor(protected breadcrumbService: DSOBreadcrumbsService, protected dataService: DSpaceObjectDataService) {
+  }
+
+  /**
+   * Method for resolving a breadcrumb config object
+   * @param {ActivatedRouteSnapshot} route The current ActivatedRouteSnapshot
+   * @param {RouterStateSnapshot} state The current RouterStateSnapshot
+   * @returns BreadcrumbConfig object
+   */
+  resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<BreadcrumbConfig<Community | Collection>> {
+    const uuid = route.queryParams.scope;
+    if (hasValue(uuid)) {
+      return this.dataService.findById(uuid).pipe(
+        getSucceededRemoteData(),
+        getRemoteDataPayload(),
+        map((object: Community | Collection) => {
+          return { provider: this.breadcrumbService, key: object, url: getDSOPath(object) };
+        })
+      );
+    }
+    return undefined;
+  }
+}
diff --git a/src/app/+browse-by/browse-by-guard.ts b/src/app/+browse-by/browse-by-guard.ts
index 3813f7e6567f668a00ebcfe6464f19526ebcfe35..9659a8c7b4a474339bc5d174abb1107557595907 100644
--- a/src/app/+browse-by/browse-by-guard.ts
+++ b/src/app/+browse-by/browse-by-guard.ts
@@ -37,24 +37,24 @@ export class BrowseByGuard implements CanActivate {
       return dsoAndMetadata$.pipe(
         map((dsoRD) => {
           const name = dsoRD.payload.name;
-          route.data = this.createData(title, id, metadataField, name, metadataTranslated, value);
+          route.data = this.createData(title, id, metadataField, name, metadataTranslated, value, route);
           return true;
         })
       );
     } else {
-      route.data = this.createData(title, id, metadataField, '', metadataTranslated, value);
+      route.data = this.createData(title, id, metadataField, '', metadataTranslated, value, route);
       return observableOf(true);
     }
   }
 
-  private createData(title, id, metadataField, collection, field, value) {
-    return {
+  private createData(title, id, metadataField, collection, field, value, route) {
+    return Object.assign({}, route.data, {
       title: title,
       id: id,
       metadataField: metadataField,
       collection: collection,
       field: field,
       value: hasValue(value) ? `"${value}"` : ''
-    }
+    });
   }
 }
diff --git a/src/app/+browse-by/browse-by-i18n-breadcrumb.resolver.ts b/src/app/+browse-by/browse-by-i18n-breadcrumb.resolver.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c173bd414edf306ed43d42251bc396847fd904d0
--- /dev/null
+++ b/src/app/+browse-by/browse-by-i18n-breadcrumb.resolver.ts
@@ -0,0 +1,28 @@
+import { Injectable } from '@angular/core';
+import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot } from '@angular/router';
+import { I18nBreadcrumbsService } from '../core/breadcrumbs/i18n-breadcrumbs.service';
+import { BreadcrumbConfig } from '../breadcrumbs/breadcrumb/breadcrumb-config.model';
+import { I18nBreadcrumbResolver } from '../core/breadcrumbs/i18n-breadcrumb.resolver';
+
+/**
+ * This class resolves a BreadcrumbConfig object with an i18n key string for a route
+ * It adds the metadata field of the current browse-by page
+ */
+@Injectable()
+export class BrowseByI18nBreadcrumbResolver extends I18nBreadcrumbResolver {
+  constructor(protected breadcrumbService: I18nBreadcrumbsService) {
+    super(breadcrumbService);
+  }
+
+  /**
+   * Method for resolving a browse-by i18n breadcrumb configuration object
+   * @param {ActivatedRouteSnapshot} route The current ActivatedRouteSnapshot
+   * @param {RouterStateSnapshot} state The current RouterStateSnapshot
+   * @returns BreadcrumbConfig object for a browse-by page
+   */
+  resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): BreadcrumbConfig<string> {
+    const extendedBreadcrumbKey = route.data.breadcrumbKey + '.' + route.params.id;
+    route.data = Object.assign({}, route.data, { breadcrumbKey: extendedBreadcrumbKey });
+    return super.resolve(route, state);
+  }
+}
diff --git a/src/app/+browse-by/browse-by-routing.module.ts b/src/app/+browse-by/browse-by-routing.module.ts
index e549c0f4e60353dcf3e631306de8b2e2084b2bbc..a686e7007eb49d5eeb254becc78b6dd324e8961a 100644
--- a/src/app/+browse-by/browse-by-routing.module.ts
+++ b/src/app/+browse-by/browse-by-routing.module.ts
@@ -2,12 +2,29 @@ import { RouterModule } from '@angular/router';
 import { NgModule } from '@angular/core';
 import { BrowseByGuard } from './browse-by-guard';
 import { BrowseBySwitcherComponent } from './+browse-by-switcher/browse-by-switcher.component';
+import { BrowseByDSOBreadcrumbResolver } from './browse-by-dso-breadcrumb.resolver';
+import { BrowseByI18nBreadcrumbResolver } from './browse-by-i18n-breadcrumb.resolver';
 
 @NgModule({
   imports: [
     RouterModule.forChild([
-      { path: ':id', component: BrowseBySwitcherComponent, canActivate: [BrowseByGuard], data: { title: 'browse.title' } }
-    ])
+      {
+        path: '',
+        resolve: { breadcrumb: BrowseByDSOBreadcrumbResolver },
+        children: [
+          {
+            path: ':id',
+            component: BrowseBySwitcherComponent,
+            canActivate: [BrowseByGuard],
+            resolve: { breadcrumb: BrowseByI18nBreadcrumbResolver },
+            data: { title: 'browse.title', breadcrumbKey: 'browse.metadata' }
+          }
+        ]
+      }])
+  ],
+  providers: [
+    BrowseByI18nBreadcrumbResolver,
+    BrowseByDSOBreadcrumbResolver
   ]
 })
 export class BrowseByRoutingModule {
diff --git a/src/app/+collection-page/collection-item-mapper/collection-item-mapper.component.spec.ts b/src/app/+collection-page/collection-item-mapper/collection-item-mapper.component.spec.ts
index 62a8d8dabb9ad716f93f4157a4a0ff22cc4d72e2..19bdd2951e8d4d7bfe26373db1ac857b5cb54163 100644
--- a/src/app/+collection-page/collection-item-mapper/collection-item-mapper.component.spec.ts
+++ b/src/app/+collection-page/collection-item-mapper/collection-item-mapper.component.spec.ts
@@ -1,3 +1,4 @@
+import { filter, tap } from 'rxjs/operators';
 import { CollectionItemMapperComponent } from './collection-item-mapper.component';
 import { async, ComponentFixture, TestBed } from '@angular/core/testing';
 import { RouterTestingModule } from '@angular/router/testing';
@@ -52,7 +53,12 @@ describe('CollectionItemMapperComponent', () => {
 
   const mockCollection: Collection = Object.assign(new Collection(), {
     id: 'ce41d451-97ed-4a9c-94a1-7de34f16a9f4',
-    name: 'test-collection'
+    name: 'test-collection',
+    _links: {
+      self: {
+        href: 'https://rest.api/collections/ce41d451-97ed-4a9c-94a1-7de34f16a9f4'
+      }
+    }
   });
   const mockCollectionRD: RemoteData<Collection> = new RemoteData<Collection>(false, false, true, null, mockCollection);
   const mockSearchOptions = of(new PaginatedSearchOptions({
@@ -77,7 +83,7 @@ describe('CollectionItemMapperComponent', () => {
   const itemDataServiceStub = {
     mapToCollection: () => of(new RestResponse(true, 200, 'OK'))
   };
-  const activatedRouteStub = new ActivatedRouteStub({}, { collection: mockCollectionRD });
+  const activatedRouteStub = new ActivatedRouteStub({}, { dso: mockCollectionRD });
   const translateServiceStub = {
     get: () => of('test-message of collection ' + mockCollection.name),
     onLangChange: new EventEmitter(),
@@ -116,7 +122,7 @@ describe('CollectionItemMapperComponent', () => {
 
   beforeEach(async(() => {
     TestBed.configureTestingModule({
-      imports: [CommonModule, FormsModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule.forRoot()],
+      imports: [CommonModule, FormsModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule],
       declarations: [CollectionItemMapperComponent, ItemSelectComponent, SearchFormComponent, PaginationComponent, EnumKeysPipe, VarDirective, ErrorComponent, LoadingComponent],
       providers: [
         { provide: ActivatedRoute, useValue: activatedRouteStub },
diff --git a/src/app/+collection-page/collection-item-mapper/collection-item-mapper.component.ts b/src/app/+collection-page/collection-item-mapper/collection-item-mapper.component.ts
index 5c67a78401247cf2a17b31601aa5662b0a748c97..64ad42658422ab3be974030a7804c02c4c06e6f4 100644
--- a/src/app/+collection-page/collection-item-mapper/collection-item-mapper.component.ts
+++ b/src/app/+collection-page/collection-item-mapper/collection-item-mapper.component.ts
@@ -22,6 +22,7 @@ import { SEARCH_CONFIG_SERVICE } from '../../+my-dspace-page/my-dspace-page.comp
 import { SearchConfigurationService } from '../../core/shared/search/search-configuration.service';
 import { PaginatedSearchOptions } from '../../shared/search/paginated-search-options.model';
 import { SearchService } from '../../core/shared/search/search.service';
+import { followLink } from '../../shared/utils/follow-link-config.model';
 
 @Component({
   selector: 'ds-collection-item-mapper',
@@ -48,7 +49,7 @@ export class CollectionItemMapperComponent implements OnInit {
    * A view on the tabset element
    * Used to switch tabs programmatically
    */
-  @ViewChild('tabs') tabs;
+  @ViewChild('tabs', {static: false}) tabs;
 
   /**
    * The collection to map items to
@@ -101,7 +102,7 @@ export class CollectionItemMapperComponent implements OnInit {
   }
 
   ngOnInit(): void {
-    this.collectionRD$ = this.route.data.pipe(map((data) => data.collection)).pipe(getSucceededRemoteData()) as Observable<RemoteData<Collection>>;
+    this.collectionRD$ = this.route.data.pipe(map((data) => data.dso)).pipe(getSucceededRemoteData()) as Observable<RemoteData<Collection>>;
     this.searchOptions$ = this.searchConfigService.paginatedSearchOptions;
     this.loadItemLists();
   }
@@ -122,7 +123,7 @@ export class CollectionItemMapperComponent implements OnInit {
         if (shouldUpdate) {
           return this.collectionDataService.getMappedItems(collectionRD.payload.id, Object.assign(options, {
             sort: this.defaultSortOptions
-          }))
+          }),followLink('owningCollection'))
         }
       })
     );
@@ -154,7 +155,7 @@ export class CollectionItemMapperComponent implements OnInit {
       map((collectionRD: RemoteData<Collection>) => collectionRD.payload),
       switchMap((collection: Collection) =>
         observableCombineLatest(ids.map((id: string) =>
-          remove ? this.itemDataService.removeMappingFromCollection(id, collection.id) : this.itemDataService.mapToCollection(id, collection.self)
+          remove ? this.itemDataService.removeMappingFromCollection(id, collection.id) : this.itemDataService.mapToCollection(id, collection._links.self.href)
         ))
       )
     );
diff --git a/src/app/+collection-page/collection-page-routing.module.ts b/src/app/+collection-page/collection-page-routing.module.ts
index 2df7997e1eb7cb42922f7b5af6529a7299673100..61cfda0d9e09e848bc64acf94fe3f2eac706ab70 100644
--- a/src/app/+collection-page/collection-page-routing.module.ts
+++ b/src/app/+collection-page/collection-page-routing.module.ts
@@ -10,6 +10,9 @@ import { DeleteCollectionPageComponent } from './delete-collection-page/delete-c
 import { URLCombiner } from '../core/url-combiner/url-combiner';
 import { getCollectionModulePath } from '../app-routing.module';
 import { CollectionItemMapperComponent } from './collection-item-mapper/collection-item-mapper.component';
+import { CollectionBreadcrumbResolver } from '../core/breadcrumbs/collection-breadcrumb.resolver';
+import { DSOBreadcrumbsService } from '../core/breadcrumbs/dso-breadcrumbs.service';
+import { LinkService } from '../core/cache/builders/link.service';
 
 export const COLLECTION_PARENT_PARAMETER = 'parent';
 
@@ -18,7 +21,7 @@ export function getCollectionPageRoute(collectionId: string) {
 }
 
 export function getCollectionEditPath(id: string) {
-  return new URLCombiner(getCollectionModulePath(), COLLECTION_EDIT_PATH.replace(/:id/, id)).toString()
+  return new URLCombiner(getCollectionModulePath(), id, COLLECTION_EDIT_PATH).toString()
 }
 
 export function getCollectionCreatePath() {
@@ -26,51 +29,54 @@ export function getCollectionCreatePath() {
 }
 
 const COLLECTION_CREATE_PATH = 'create';
-const COLLECTION_EDIT_PATH = ':id/edit';
+const COLLECTION_EDIT_PATH = 'edit';
 
 @NgModule({
   imports: [
     RouterModule.forChild([
-      {
-        path: COLLECTION_CREATE_PATH,
-        component: CreateCollectionPageComponent,
-        canActivate: [AuthenticatedGuard, CreateCollectionPageGuard]
-      },
-      {
-        path: COLLECTION_EDIT_PATH,
-        loadChildren: './edit-collection-page/edit-collection-page.module#EditCollectionPageModule',
-        canActivate: [AuthenticatedGuard]
-      },
-      {
-        path: ':id/delete',
-        pathMatch: 'full',
-        component: DeleteCollectionPageComponent,
-        canActivate: [AuthenticatedGuard],
-        resolve: {
-          dso: CollectionPageResolver
-        }
-      },
       {
         path: ':id',
-        component: CollectionPageComponent,
-        pathMatch: 'full',
         resolve: {
-          collection: CollectionPageResolver
-        }
+          dso: CollectionPageResolver,
+          breadcrumb: CollectionBreadcrumbResolver
+        },
+        children: [
+          {
+            path: COLLECTION_EDIT_PATH,
+            loadChildren: './edit-collection-page/edit-collection-page.module#EditCollectionPageModule',
+            canActivate: [AuthenticatedGuard]
+          },
+          {
+            path: 'delete',
+            pathMatch: 'full',
+            component: DeleteCollectionPageComponent,
+            canActivate: [AuthenticatedGuard],
+          },
+          {
+            path: '',
+            component: CollectionPageComponent,
+            pathMatch: 'full',
+          },
+          {
+            path: '/edit/mapper',
+            component: CollectionItemMapperComponent,
+            pathMatch: 'full',
+            canActivate: [AuthenticatedGuard]
+          }
+        ]
       },
       {
-        path: ':id/edit/mapper',
-        component: CollectionItemMapperComponent,
-        pathMatch: 'full',
-        resolve: {
-          collection: CollectionPageResolver
-        },
-        canActivate: [AuthenticatedGuard]
-      }
+        path: COLLECTION_CREATE_PATH,
+        component: CreateCollectionPageComponent,
+        canActivate: [AuthenticatedGuard, CreateCollectionPageGuard]
+      },
     ])
   ],
   providers: [
     CollectionPageResolver,
+    CollectionBreadcrumbResolver,
+    DSOBreadcrumbsService,
+    LinkService,
     CreateCollectionPageGuard
   ]
 })
diff --git a/src/app/+collection-page/collection-page.component.ts b/src/app/+collection-page/collection-page.component.ts
index 4866cf3b60aec1cc31568cc0e1bf804cce27e518..7f54e0f9d7854f8fc4f6542c133b4f300024e91d 100644
--- a/src/app/+collection-page/collection-page.component.ts
+++ b/src/app/+collection-page/collection-page.component.ts
@@ -62,7 +62,7 @@ export class CollectionPageComponent implements OnInit {
 
   ngOnInit(): void {
     this.collectionRD$ = this.route.data.pipe(
-      map((data) => data.collection as RemoteData<Collection>),
+      map((data) => data.dso as RemoteData<Collection>),
       redirectToPageNotFoundOn404(this.router),
       take(1)
     );
diff --git a/src/app/+collection-page/collection-page.resolver.ts b/src/app/+collection-page/collection-page.resolver.ts
index 8c6e3ad8a65d861304a399690488589ddc49989b..1c535e10aa71cd2b744c224b894d82becb5d2c37 100644
--- a/src/app/+collection-page/collection-page.resolver.ts
+++ b/src/app/+collection-page/collection-page.resolver.ts
@@ -6,6 +6,7 @@ import { CollectionDataService } from '../core/data/collection-data.service';
 import { RemoteData } from '../core/data/remote-data';
 import { find } from 'rxjs/operators';
 import { hasValue } from '../shared/empty.util';
+import { followLink } from '../shared/utils/follow-link-config.model';
 
 /**
  * This class represents a resolver that requests a specific collection before the route is activated
@@ -23,7 +24,7 @@ export class CollectionPageResolver implements Resolve<RemoteData<Collection>> {
    * or an error if something went wrong
    */
   resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<RemoteData<Collection>> {
-    return this.collectionService.findById(route.params.id).pipe(
+    return this.collectionService.findById(route.params.id, followLink('logo')).pipe(
       find((RD) => hasValue(RD.error) || RD.hasSucceeded),
     );
   }
diff --git a/src/app/+collection-page/edit-collection-page/edit-collection-page.routing.module.ts b/src/app/+collection-page/edit-collection-page/edit-collection-page.routing.module.ts
index fcfced9d810a52a2802886fcd3256f9fac51d1b8..0569de9cd9c3eaadc216cf73ca60f1351ee80e5a 100644
--- a/src/app/+collection-page/edit-collection-page/edit-collection-page.routing.module.ts
+++ b/src/app/+collection-page/edit-collection-page/edit-collection-page.routing.module.ts
@@ -1,11 +1,11 @@
 import { RouterModule } from '@angular/router';
 import { NgModule } from '@angular/core';
 import { EditCollectionPageComponent } from './edit-collection-page.component';
-import { CollectionPageResolver } from '../collection-page.resolver';
 import { CollectionMetadataComponent } from './collection-metadata/collection-metadata.component';
 import { CollectionRolesComponent } from './collection-roles/collection-roles.component';
 import { CollectionSourceComponent } from './collection-source/collection-source.component';
 import { CollectionCurateComponent } from './collection-curate/collection-curate.component';
+import { I18nBreadcrumbResolver } from '../../core/breadcrumbs/i18n-breadcrumb.resolver';
 
 /**
  * Routing module that handles the routing for the Edit Collection page administrator functionality
@@ -15,10 +15,11 @@ import { CollectionCurateComponent } from './collection-curate/collection-curate
     RouterModule.forChild([
       {
         path: '',
-        component: EditCollectionPageComponent,
         resolve: {
-          dso: CollectionPageResolver
+          breadcrumb: I18nBreadcrumbResolver
         },
+        data: { breadcrumbKey: 'collection.edit' },
+        component: EditCollectionPageComponent,
         children: [
           {
             path: '',
@@ -30,30 +31,28 @@ import { CollectionCurateComponent } from './collection-curate/collection-curate
             component: CollectionMetadataComponent,
             data: {
               title: 'collection.edit.tabs.metadata.title',
-              hideReturnButton: true
+              hideReturnButton: true,
+              showBreadcrumbs: true
             }
           },
           {
             path: 'roles',
             component: CollectionRolesComponent,
-            data: { title: 'collection.edit.tabs.roles.title' }
+            data: { title: 'collection.edit.tabs.roles.title', showBreadcrumbs: true }
           },
           {
             path: 'source',
             component: CollectionSourceComponent,
-            data: { title: 'collection.edit.tabs.source.title' }
+            data: { title: 'collection.edit.tabs.source.title', showBreadcrumbs: true }
           },
           {
             path: 'curate',
             component: CollectionCurateComponent,
-            data: { title: 'collection.edit.tabs.curate.title' }
+            data: { title: 'collection.edit.tabs.curate.title', showBreadcrumbs: true }
           }
         ]
       }
     ])
-  ],
-  providers: [
-    CollectionPageResolver,
   ]
 })
 export class EditCollectionPageRoutingModule {
diff --git a/src/app/+community-page/community-page-routing.module.ts b/src/app/+community-page/community-page-routing.module.ts
index df548e061729ce9d795855d1fa0bb286aede0b08..976a4ad0feecbaac94bb2bfb5a94eb8497cf71c3 100644
--- a/src/app/+community-page/community-page-routing.module.ts
+++ b/src/app/+community-page/community-page-routing.module.ts
@@ -9,6 +9,9 @@ import { CreateCommunityPageGuard } from './create-community-page/create-communi
 import { DeleteCommunityPageComponent } from './delete-community-page/delete-community-page.component';
 import { URLCombiner } from '../core/url-combiner/url-combiner';
 import { getCommunityModulePath } from '../app-routing.module';
+import { CommunityBreadcrumbResolver } from '../core/breadcrumbs/community-breadcrumb.resolver';
+import { DSOBreadcrumbsService } from '../core/breadcrumbs/dso-breadcrumbs.service';
+import { LinkService } from '../core/cache/builders/link.service';
 
 export const COMMUNITY_PARENT_PARAMETER = 'parent';
 
@@ -17,7 +20,7 @@ export function getCommunityPageRoute(communityId: string) {
 }
 
 export function getCommunityEditPath(id: string) {
-  return new URLCombiner(getCommunityModulePath(), COMMUNITY_EDIT_PATH.replace(/:id/, id)).toString()
+  return new URLCombiner(getCommunityModulePath(), id, COMMUNITY_EDIT_PATH).toString()
 }
 
 export function getCommunityCreatePath() {
@@ -25,42 +28,48 @@ export function getCommunityCreatePath() {
 }
 
 const COMMUNITY_CREATE_PATH = 'create';
-const COMMUNITY_EDIT_PATH = ':id/edit';
+const COMMUNITY_EDIT_PATH = 'edit';
 
 @NgModule({
   imports: [
     RouterModule.forChild([
+      {
+        path: ':id',
+        resolve: {
+          dso: CommunityPageResolver,
+          breadcrumb: CommunityBreadcrumbResolver
+        },
+        children: [
+          {
+            path: COMMUNITY_EDIT_PATH,
+            loadChildren: './edit-community-page/edit-community-page.module#EditCommunityPageModule',
+            canActivate: [AuthenticatedGuard]
+          },
+          {
+            path: 'delete',
+            pathMatch: 'full',
+            component: DeleteCommunityPageComponent,
+            canActivate: [AuthenticatedGuard],
+          },
+          {
+            path: '',
+            component: CommunityPageComponent,
+            pathMatch: 'full',
+          }
+        ]
+      },
       {
         path: COMMUNITY_CREATE_PATH,
         component: CreateCommunityPageComponent,
         canActivate: [AuthenticatedGuard, CreateCommunityPageGuard]
       },
-      {
-        path: COMMUNITY_EDIT_PATH,
-        loadChildren: './edit-community-page/edit-community-page.module#EditCommunityPageModule',
-        canActivate: [AuthenticatedGuard]
-      },
-      {
-        path: ':id/delete',
-        pathMatch: 'full',
-        component: DeleteCommunityPageComponent,
-        canActivate: [AuthenticatedGuard],
-        resolve: {
-          dso: CommunityPageResolver
-        }
-      },
-      {
-        path: ':id',
-        component: CommunityPageComponent,
-        pathMatch: 'full',
-        resolve: {
-          community: CommunityPageResolver
-        }
-      }
     ])
   ],
   providers: [
     CommunityPageResolver,
+    CommunityBreadcrumbResolver,
+    DSOBreadcrumbsService,
+    LinkService,
     CreateCommunityPageGuard
   ]
 })
diff --git a/src/app/+community-page/community-page.component.ts b/src/app/+community-page/community-page.component.ts
index f337d70250aca257c0693959b2e8037e1eec8991..36218299277904d9006cf9a800c56ad6ecb1e65c 100644
--- a/src/app/+community-page/community-page.component.ts
+++ b/src/app/+community-page/community-page.component.ts
@@ -46,7 +46,7 @@ export class CommunityPageComponent implements OnInit {
 
   ngOnInit(): void {
     this.communityRD$ = this.route.data.pipe(
-      map((data) => data.community as RemoteData<Community>),
+      map((data) => data.dso as RemoteData<Community>),
       redirectToPageNotFoundOn404(this.router)
     );
     this.logoRD$ = this.communityRD$.pipe(
diff --git a/src/app/+community-page/community-page.resolver.spec.ts b/src/app/+community-page/community-page.resolver.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..aa6e9d9c1fd3f6e69b1b88d37e35952c0bb25c5a
--- /dev/null
+++ b/src/app/+community-page/community-page.resolver.spec.ts
@@ -0,0 +1,28 @@
+import { of as observableOf } from 'rxjs';
+import { first } from 'rxjs/operators';
+import { CommunityPageResolver } from './community-page.resolver';
+
+describe('CommunityPageResolver', () => {
+  describe('resolve', () => {
+    let resolver: CommunityPageResolver;
+    let communityService: any;
+    const uuid = '1234-65487-12354-1235';
+
+    beforeEach(() => {
+      communityService = {
+        findById: (id: string) => observableOf({ payload: { id }, hasSucceeded: true })
+      };
+      resolver = new CommunityPageResolver(communityService);
+    });
+
+    it('should resolve a community with the correct id', () => {
+      resolver.resolve({ params: { id: uuid } } as any, undefined)
+        .pipe(first())
+        .subscribe(
+          (resolved) => {
+            expect(resolved.payload.id).toEqual(uuid);
+          }
+        );
+    });
+  });
+});
diff --git a/src/app/+community-page/community-page.resolver.ts b/src/app/+community-page/community-page.resolver.ts
index ffa66fa1235b68a28e3fcedd9de2d4d31e250d6c..7696f7d469549581e369120ce9e2a1486ac3c332 100644
--- a/src/app/+community-page/community-page.resolver.ts
+++ b/src/app/+community-page/community-page.resolver.ts
@@ -6,6 +6,7 @@ import { Community } from '../core/shared/community.model';
 import { CommunityDataService } from '../core/data/community-data.service';
 import { find } from 'rxjs/operators';
 import { hasValue } from '../shared/empty.util';
+import { followLink } from '../shared/utils/follow-link-config.model';
 
 /**
  * This class represents a resolver that requests a specific community before the route is activated
@@ -23,7 +24,12 @@ export class CommunityPageResolver implements Resolve<RemoteData<Community>> {
    * or an error if something went wrong
    */
   resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<RemoteData<Community>> {
-    return this.communityService.findById(route.params.id).pipe(
+    return this.communityService.findById(
+      route.params.id,
+      followLink('logo'),
+      followLink('subcommunities'),
+      followLink('collections')
+    ).pipe(
       find((RD) => hasValue(RD.error) || RD.hasSucceeded)
     );
   }
diff --git a/src/app/+community-page/delete-community-page/delete-community-page.component.spec.ts b/src/app/+community-page/delete-community-page/delete-community-page.component.spec.ts
index c23df9397686dbfae57f4b8d08183991dc2dc6c6..613be9deb3fa1f2ef4846a691a3efb7f62af0744 100644
--- a/src/app/+community-page/delete-community-page/delete-community-page.component.spec.ts
+++ b/src/app/+community-page/delete-community-page/delete-community-page.component.spec.ts
@@ -1,15 +1,14 @@
-import { async, ComponentFixture, TestBed } from '@angular/core/testing';
-import { ActivatedRoute, Router } from '@angular/router';
-import { TranslateModule } from '@ngx-translate/core';
 import { CommonModule } from '@angular/common';
-import { RouterTestingModule } from '@angular/router/testing';
 import { NO_ERRORS_SCHEMA } from '@angular/core';
-import { RouteService } from '../../core/services/route.service';
-import { SharedModule } from '../../shared/shared.module';
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { ActivatedRoute } from '@angular/router';
+import { RouterTestingModule } from '@angular/router/testing';
+import { TranslateModule } from '@ngx-translate/core';
 import { of as observableOf } from 'rxjs';
+import { CommunityDataService } from '../../core/data/community-data.service';
 import { NotificationsService } from '../../shared/notifications/notifications.service';
+import { SharedModule } from '../../shared/shared.module';
 import { DeleteCommunityPageComponent } from './delete-community-page.component';
-import { CommunityDataService } from '../../core/data/community-data.service';
 
 describe('DeleteCommunityPageComponent', () => {
   let comp: DeleteCommunityPageComponent;
diff --git a/src/app/+community-page/edit-community-page/edit-community-page.routing.module.ts b/src/app/+community-page/edit-community-page/edit-community-page.routing.module.ts
index 1182db2de1e362989a44bfd34281e6c1af4c9cc9..3197e00829e2027e07da283fc8e03b9fc31bb433 100644
--- a/src/app/+community-page/edit-community-page/edit-community-page.routing.module.ts
+++ b/src/app/+community-page/edit-community-page/edit-community-page.routing.module.ts
@@ -5,6 +5,7 @@ import { NgModule } from '@angular/core';
 import { CommunityMetadataComponent } from './community-metadata/community-metadata.component';
 import { CommunityRolesComponent } from './community-roles/community-roles.component';
 import { CommunityCurateComponent } from './community-curate/community-curate.component';
+import { I18nBreadcrumbResolver } from '../../core/breadcrumbs/i18n-breadcrumb.resolver';
 
 /**
  * Routing module that handles the routing for the Edit Community page administrator functionality
@@ -14,10 +15,11 @@ import { CommunityCurateComponent } from './community-curate/community-curate.co
     RouterModule.forChild([
       {
         path: '',
-        component: EditCommunityPageComponent,
         resolve: {
-          dso: CommunityPageResolver
+          breadcrumb: I18nBreadcrumbResolver
         },
+        data: { breadcrumbKey: 'community.edit' },
+        component: EditCommunityPageComponent,
         children: [
           {
             path: '',
@@ -29,26 +31,24 @@ import { CommunityCurateComponent } from './community-curate/community-curate.co
             component: CommunityMetadataComponent,
             data: {
               title: 'community.edit.tabs.metadata.title',
-              hideReturnButton: true
+              hideReturnButton: true,
+              showBreadcrumbs: true
             }
           },
           {
             path: 'roles',
             component: CommunityRolesComponent,
-            data: { title: 'community.edit.tabs.roles.title' }
+            data: { title: 'community.edit.tabs.roles.title', showBreadcrumbs: true }
           },
           {
             path: 'curate',
             component: CommunityCurateComponent,
-            data: { title: 'community.edit.tabs.curate.title' }
+            data: { title: 'community.edit.tabs.curate.title', showBreadcrumbs: true }
           }
         ]
       }
     ])
   ],
-  providers: [
-    CommunityPageResolver,
-  ]
 })
 export class EditCommunityPageRoutingModule {
 
diff --git a/src/app/+community-page/sub-collection-list/community-page-sub-collection-list.component.spec.ts b/src/app/+community-page/sub-collection-list/community-page-sub-collection-list.component.spec.ts
index 09332dda1694cf7c02d16ab0bf0b05cbeea733aa..79bbb2353e9c8634bca1bb6e7e24a5740302065b 100644
--- a/src/app/+community-page/sub-collection-list/community-page-sub-collection-list.component.spec.ts
+++ b/src/app/+community-page/sub-collection-list/community-page-sub-collection-list.component.spec.ts
@@ -116,7 +116,7 @@ describe('CommunityPageSubCollectionList Component', () => {
         TranslateModule.forRoot(),
         SharedModule,
         RouterTestingModule.withRoutes([]),
-        NgbModule.forRoot(),
+        NgbModule,
         NoopAnimationsModule
       ],
       declarations: [CommunityPageSubCollectionListComponent],
diff --git a/src/app/+community-page/sub-community-list/community-page-sub-community-list.component.spec.ts b/src/app/+community-page/sub-community-list/community-page-sub-community-list.component.spec.ts
index 41502e7bd44d52d1f59d602a5aac4607d9f90278..80d18274674d3a293347c4d876cf98e97a3c2bdc 100644
--- a/src/app/+community-page/sub-community-list/community-page-sub-community-list.component.spec.ts
+++ b/src/app/+community-page/sub-community-list/community-page-sub-community-list.component.spec.ts
@@ -117,7 +117,7 @@ describe('CommunityPageSubCommunityListComponent Component', () => {
         TranslateModule.forRoot(),
         SharedModule,
         RouterTestingModule.withRoutes([]),
-        NgbModule.forRoot(),
+        NgbModule,
         NoopAnimationsModule
       ],
       declarations: [CommunityPageSubCommunityListComponent],
diff --git a/src/app/+home-page/top-level-community-list/top-level-community-list.component.spec.ts b/src/app/+home-page/top-level-community-list/top-level-community-list.component.spec.ts
index fa164fe624de356b52d74c711ee9d334c4e172fb..2fbecae501fb9b2cf42a913a3beb23442a8699b6 100644
--- a/src/app/+home-page/top-level-community-list/top-level-community-list.component.spec.ts
+++ b/src/app/+home-page/top-level-community-list/top-level-community-list.component.spec.ts
@@ -107,7 +107,7 @@ describe('TopLevelCommunityList Component', () => {
         TranslateModule.forRoot(),
         SharedModule,
         RouterTestingModule.withRoutes([]),
-        NgbModule.forRoot(),
+        NgbModule,
         NoopAnimationsModule
       ],
       declarations: [TopLevelCommunityListComponent],
diff --git a/src/app/+item-page/edit-item-page/edit-item-page.routing.module.ts b/src/app/+item-page/edit-item-page/edit-item-page.routing.module.ts
index 1b386440c0f45b7c89315bdf0e1894f1bf750537..da667847f733d9356360be7c452eb5da8a2fe179 100644
--- a/src/app/+item-page/edit-item-page/edit-item-page.routing.module.ts
+++ b/src/app/+item-page/edit-item-page/edit-item-page.routing.module.ts
@@ -13,6 +13,7 @@ import { ItemBitstreamsComponent } from './item-bitstreams/item-bitstreams.compo
 import { ItemCollectionMapperComponent } from './item-collection-mapper/item-collection-mapper.component';
 import { ItemMoveComponent } from './item-move/item-move.component';
 import { ItemRelationshipsComponent } from './item-relationships/item-relationships.component';
+import { I18nBreadcrumbResolver } from '../../core/breadcrumbs/i18n-breadcrumb.resolver';
 
 const ITEM_EDIT_WITHDRAW_PATH = 'withdraw';
 const ITEM_EDIT_REINSTATE_PATH = 'reinstate';
@@ -29,104 +30,88 @@ const ITEM_EDIT_MOVE_PATH = 'move';
     RouterModule.forChild([
       {
         path: '',
-        component: EditItemPageComponent,
         resolve: {
-          item: ItemPageResolver
+          breadcrumb: I18nBreadcrumbResolver
         },
+        data: { breadcrumbKey: 'item.edit' },
         children: [
           {
             path: '',
-            redirectTo: 'status',
-            pathMatch: 'full'
+            component: EditItemPageComponent,
+            children: [
+              {
+                path: '',
+                redirectTo: 'status',
+                pathMatch: 'full'
+              },
+              {
+                path: 'status',
+                component: ItemStatusComponent,
+                data: { title: 'item.edit.tabs.status.title', showBreadcrumbs: true }
+              },
+              {
+                path: 'bitstreams',
+                component: ItemBitstreamsComponent,
+                data: { title: 'item.edit.tabs.bitstreams.title', showBreadcrumbs: true }
+              },
+              {
+                path: 'metadata',
+                component: ItemMetadataComponent,
+                data: { title: 'item.edit.tabs.metadata.title', showBreadcrumbs: true }
+              },
+              {
+                path: 'relationships',
+                component: ItemRelationshipsComponent,
+                data: { title: 'item.edit.tabs.relationships.title', showBreadcrumbs: true }
+              },
+              {
+                path: 'view',
+                /* TODO - change when view page exists */
+                component: ItemBitstreamsComponent,
+                data: { title: 'item.edit.tabs.view.title', showBreadcrumbs: true }
+              },
+              {
+                path: 'curate',
+                /* TODO - change when curate page exists */
+                component: ItemBitstreamsComponent,
+                data: { title: 'item.edit.tabs.curate.title', showBreadcrumbs: true }
+              }
+            ]
           },
           {
-            path: 'status',
-            component: ItemStatusComponent,
-            data: { title: 'item.edit.tabs.status.title' }
+            path: 'mapper',
+            component: ItemCollectionMapperComponent,
           },
           {
-            path: 'bitstreams',
-            component: ItemBitstreamsComponent,
-            data: { title: 'item.edit.tabs.bitstreams.title' }
+            path: ITEM_EDIT_WITHDRAW_PATH,
+            component: ItemWithdrawComponent,
           },
           {
-            path: 'metadata',
-            component: ItemMetadataComponent,
-            data: { title: 'item.edit.tabs.metadata.title' }
+            path: ITEM_EDIT_REINSTATE_PATH,
+            component: ItemReinstateComponent,
           },
           {
-            path: 'relationships',
-            component: ItemRelationshipsComponent,
-            data: { title: 'item.edit.tabs.relationships.title' }
+            path: ITEM_EDIT_PRIVATE_PATH,
+            component: ItemPrivateComponent,
           },
           {
-            path: 'view',
-            /* TODO - change when view page exists */
-            component: ItemBitstreamsComponent,
-            data: { title: 'item.edit.tabs.view.title' }
+            path: ITEM_EDIT_PUBLIC_PATH,
+            component: ItemPublicComponent,
           },
           {
-            path: 'curate',
-            /* TODO - change when curate page exists */
-            component: ItemBitstreamsComponent,
-            data: { title: 'item.edit.tabs.curate.title' }
+            path: ITEM_EDIT_DELETE_PATH,
+            component: ItemDeleteComponent,
           },
+          {
+            path: ITEM_EDIT_MOVE_PATH,
+            component: ItemMoveComponent,
+            data: { title: 'item.edit.move.title' },
+          }
         ]
-      },
-      {
-        path: 'mapper',
-        component: ItemCollectionMapperComponent,
-        resolve: {
-          item: ItemPageResolver
-        }
-      },
-      {
-        path: ITEM_EDIT_WITHDRAW_PATH,
-        component: ItemWithdrawComponent,
-        resolve: {
-          item: ItemPageResolver
-        }
-      },
-      {
-        path: ITEM_EDIT_REINSTATE_PATH,
-        component: ItemReinstateComponent,
-        resolve: {
-          item: ItemPageResolver
-        }
-      },
-      {
-        path: ITEM_EDIT_PRIVATE_PATH,
-        component: ItemPrivateComponent,
-        resolve: {
-          item: ItemPageResolver
-        }
-      },
-      {
-        path: ITEM_EDIT_PUBLIC_PATH,
-        component: ItemPublicComponent,
-        resolve: {
-          item: ItemPageResolver
-        }
-      },
-      {
-        path: ITEM_EDIT_DELETE_PATH,
-        component: ItemDeleteComponent,
-        resolve: {
-          item: ItemPageResolver
-        }
-      },
-      {
-        path: ITEM_EDIT_MOVE_PATH,
-        component: ItemMoveComponent,
-        data: { title: 'item.edit.move.title' },
-        resolve: {
-          item: ItemPageResolver
-        }
-      }])
+      }
+    ])
   ],
-  providers: [
-    ItemPageResolver,
-  ]
+  providers: []
 })
 export class EditItemPageRoutingModule {
 
diff --git a/src/app/+item-page/edit-item-page/item-bitstreams/item-bitstreams.component.ts b/src/app/+item-page/edit-item-page/item-bitstreams/item-bitstreams.component.ts
index ac9a2c6ed3d9d74e3255ca8bda6167ebf99dd066..43ab201bdd2374228bd3c5c3169e69d64bc26861 100644
--- a/src/app/+item-page/edit-item-page/item-bitstreams/item-bitstreams.component.ts
+++ b/src/app/+item-page/edit-item-page/item-bitstreams/item-bitstreams.component.ts
@@ -195,7 +195,7 @@ export class ItemBitstreamsComponent extends AbstractItemUpdateComponent impleme
       take(1),
       switchMap((removedBistreams: Bitstream[]) => {
         if (isNotEmpty(removedBistreams)) {
-          return observableZip(...removedBistreams.map((bitstream: Bitstream) => this.bitstreamService.deleteAndReturnResponse(bitstream)));
+          return observableZip(...removedBistreams.map((bitstream: Bitstream) => this.bitstreamService.deleteAndReturnResponse(bitstream.id)));
         } else {
           return observableOf(undefined);
         }
diff --git a/src/app/+item-page/edit-item-page/item-bitstreams/item-edit-bitstream-bundle/item-edit-bitstream-bundle.component.ts b/src/app/+item-page/edit-item-page/item-bitstreams/item-edit-bitstream-bundle/item-edit-bitstream-bundle.component.ts
index bbf896e5cdf81020da495f763b9edbf4a4f6a4fc..1aa549273000d82f26de5c5815078b65dd4775f2 100644
--- a/src/app/+item-page/edit-item-page/item-bitstreams/item-edit-bitstream-bundle/item-edit-bitstream-bundle.component.ts
+++ b/src/app/+item-page/edit-item-page/item-bitstreams/item-edit-bitstream-bundle/item-edit-bitstream-bundle.component.ts
@@ -1,21 +1,6 @@
-import { Component, EventEmitter, Input, OnInit, Output, ViewChild, ViewContainerRef } from '@angular/core';
+import { Component, Input, OnInit, ViewChild, ViewContainerRef } from '@angular/core';
 import { Bundle } from '../../../../core/shared/bundle.model';
-import { ObjectUpdatesService } from '../../../../core/data/object-updates/object-updates.service';
-import { Observable } from 'rxjs/internal/Observable';
-import { FieldUpdates } from '../../../../core/data/object-updates/object-updates.reducer';
-import { toBitstreamsArray } from '../../../../core/shared/item-bitstreams-utils';
-import { map, switchMap, take, tap } from 'rxjs/operators';
-import { Bitstream } from '../../../../core/shared/bitstream.model';
 import { Item } from '../../../../core/shared/item.model';
-import { CdkDragDrop, CdkDragStart } from '@angular/cdk/drag-drop';
-import { RemoteData } from '../../../../core/data/remote-data';
-import { PaginatedList } from '../../../../core/data/paginated-list';
-import { BundleDataService } from '../../../../core/data/bundle-data.service';
-import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject';
-import { combineLatest as observableCombineLatest } from 'rxjs';
-import { hasNoValue, isEmpty } from '../../../../shared/empty.util';
-import { PaginatedSearchOptions } from '../../../../shared/search/paginated-search-options.model';
-import { PaginationComponentOptions } from '../../../../shared/pagination/pagination-component-options.model';
 import { ResponsiveColumnSizes } from '../../../../shared/responsive-table-sizes/responsive-column-sizes';
 import { ResponsiveTableSizes } from '../../../../shared/responsive-table-sizes/responsive-table-sizes';
 
@@ -32,7 +17,7 @@ export class ItemEditBitstreamBundleComponent implements OnInit {
   /**
    * The view on the bundle information and bitstreams
    */
-  @ViewChild('bundleView') bundleView;
+  @ViewChild('bundleView', {static: false}) bundleView;
 
   /**
    * The bundle to display bitstreams for
diff --git a/src/app/+item-page/edit-item-page/item-bitstreams/item-edit-bitstream-drag-handle/item-edit-bitstream-drag-handle.component.ts b/src/app/+item-page/edit-item-page/item-bitstreams/item-edit-bitstream-drag-handle/item-edit-bitstream-drag-handle.component.ts
index 0cb91bbefa180949726bef35735d8f66cb331369..7e9ca9cebaf8a971448dcc123767bcf8c275c70c 100644
--- a/src/app/+item-page/edit-item-page/item-bitstreams/item-edit-bitstream-drag-handle/item-edit-bitstream-drag-handle.component.ts
+++ b/src/app/+item-page/edit-item-page/item-bitstreams/item-edit-bitstream-drag-handle/item-edit-bitstream-drag-handle.component.ts
@@ -9,7 +9,7 @@ export class ItemEditBitstreamDragHandleComponent implements OnInit {
   /**
    * The view on the drag-handle
    */
-  @ViewChild('handleView') handleView;
+  @ViewChild('handleView', {static: false}) handleView;
 
   constructor(private viewContainerRef: ViewContainerRef) {
   }
diff --git a/src/app/+item-page/edit-item-page/item-bitstreams/item-edit-bitstream/item-edit-bitstream.component.ts b/src/app/+item-page/edit-item-page/item-bitstreams/item-edit-bitstream/item-edit-bitstream.component.ts
index 0deaa5b2a9b727903189693eea615540c372f6a6..19f0924989c288f66af5c4005a0a9380a9402f73 100644
--- a/src/app/+item-page/edit-item-page/item-bitstreams/item-edit-bitstream/item-edit-bitstream.component.ts
+++ b/src/app/+item-page/edit-item-page/item-bitstreams/item-edit-bitstream/item-edit-bitstream.component.ts
@@ -22,7 +22,7 @@ export class ItemEditBitstreamComponent implements OnChanges, OnInit {
   /**
    * The view on the bitstream
    */
-  @ViewChild('bitstreamView') bitstreamView;
+  @ViewChild('bitstreamView', {static: false}) bitstreamView;
 
   /**
    * The current field, value and state of the bitstream
diff --git a/src/app/+item-page/edit-item-page/item-collection-mapper/item-collection-mapper.component.spec.ts b/src/app/+item-page/edit-item-page/item-collection-mapper/item-collection-mapper.component.spec.ts
index c8740c35b27cdba443513afa3bb42860c487080c..50b36c8d32ff246a66df11540c866251d075296f 100644
--- a/src/app/+item-page/edit-item-page/item-collection-mapper/item-collection-mapper.component.spec.ts
+++ b/src/app/+item-page/edit-item-page/item-collection-mapper/item-collection-mapper.component.spec.ts
@@ -1,42 +1,43 @@
+import { CommonModule } from '@angular/common';
+import { EventEmitter } from '@angular/core';
 import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { FormsModule } from '@angular/forms';
+import { By } from '@angular/platform-browser';
+import { ActivatedRoute, Router } from '@angular/router';
 import { RouterTestingModule } from '@angular/router/testing';
 import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
-import { CommonModule } from '@angular/common';
-import { ItemCollectionMapperComponent } from './item-collection-mapper.component';
-import { ActivatedRoute, Router } from '@angular/router';
-import { NotificationsService } from '../../../shared/notifications/notifications.service';
-import { ItemDataService } from '../../../core/data/item-data.service';
-import { RemoteData } from '../../../core/data/remote-data';
-import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model';
+import { TranslateModule, TranslateService } from '@ngx-translate/core';
+import { of } from 'rxjs/internal/observable/of';
 import { SortDirection, SortOptions } from '../../../core/cache/models/sort-options.model';
-import { RouterStub } from '../../../shared/testing/router-stub';
-import { ActivatedRouteStub } from '../../../shared/testing/active-router-stub';
-import { EventEmitter } from '@angular/core';
-import { SearchServiceStub } from '../../../shared/testing/search-service-stub';
+import { RestResponse } from '../../../core/cache/response.models';
+import { CollectionDataService } from '../../../core/data/collection-data.service';
+import { ItemDataService } from '../../../core/data/item-data.service';
 import { PaginatedList } from '../../../core/data/paginated-list';
+import { RemoteData } from '../../../core/data/remote-data';
+import { Collection } from '../../../core/shared/collection.model';
+import { Item } from '../../../core/shared/item.model';
 import { PageInfo } from '../../../core/shared/page-info.model';
-import { FormsModule } from '@angular/forms';
-import { TranslateModule, TranslateService } from '@ngx-translate/core';
-import { NotificationsServiceStub } from '../../../shared/testing/notifications-service-stub';
+import { SearchConfigurationService } from '../../../core/shared/search/search-configuration.service';
+import { SearchService } from '../../../core/shared/search/search.service';
+import { ErrorComponent } from '../../../shared/error/error.component';
 import { HostWindowService } from '../../../shared/host-window.service';
-import { HostWindowServiceStub } from '../../../shared/testing/host-window-service-stub';
-import { By } from '@angular/platform-browser';
-import { Item } from '../../../core/shared/item.model';
-import { ObjectSelectService } from '../../../shared/object-select/object-select.service';
-import { ObjectSelectServiceStub } from '../../../shared/testing/object-select-service-stub';
-import { of } from 'rxjs/internal/observable/of';
-import { RestResponse } from '../../../core/cache/response.models';
+import { LoadingComponent } from '../../../shared/loading/loading.component';
+import { NotificationsService } from '../../../shared/notifications/notifications.service';
 import { CollectionSelectComponent } from '../../../shared/object-select/collection-select/collection-select.component';
+import { ObjectSelectService } from '../../../shared/object-select/object-select.service';
+import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model';
 import { PaginationComponent } from '../../../shared/pagination/pagination.component';
-import { EnumKeysPipe } from '../../../shared/utils/enum-keys-pipe';
-import { VarDirective } from '../../../shared/utils/var.directive';
 import { SearchFormComponent } from '../../../shared/search-form/search-form.component';
-import { Collection } from '../../../core/shared/collection.model';
-import { ErrorComponent } from '../../../shared/error/error.component';
-import { LoadingComponent } from '../../../shared/loading/loading.component';
-import { SearchConfigurationService } from '../../../core/shared/search/search-configuration.service';
-import { SearchService } from '../../../core/shared/search/search.service';
 import { PaginatedSearchOptions } from '../../../shared/search/paginated-search-options.model';
+import { ActivatedRouteStub } from '../../../shared/testing/active-router-stub';
+import { HostWindowServiceStub } from '../../../shared/testing/host-window-service-stub';
+import { NotificationsServiceStub } from '../../../shared/testing/notifications-service-stub';
+import { ObjectSelectServiceStub } from '../../../shared/testing/object-select-service-stub';
+import { RouterStub } from '../../../shared/testing/router-stub';
+import { SearchServiceStub } from '../../../shared/testing/search-service-stub';
+import { EnumKeysPipe } from '../../../shared/utils/enum-keys-pipe';
+import { VarDirective } from '../../../shared/utils/var.directive';
+import { ItemCollectionMapperComponent } from './item-collection-mapper.component';
 
 describe('ItemCollectionMapperComponent', () => {
   let comp: ItemCollectionMapperComponent;
@@ -98,7 +99,7 @@ describe('ItemCollectionMapperComponent', () => {
 
   beforeEach(async(() => {
     TestBed.configureTestingModule({
-      imports: [CommonModule, FormsModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule.forRoot()],
+      imports: [CommonModule, FormsModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule],
       declarations: [ItemCollectionMapperComponent, CollectionSelectComponent, SearchFormComponent, PaginationComponent, EnumKeysPipe, VarDirective, ErrorComponent, LoadingComponent],
       providers: [
         { provide: ActivatedRoute, useValue: activatedRouteStub },
@@ -109,7 +110,8 @@ describe('ItemCollectionMapperComponent', () => {
         { provide: SearchService, useValue: searchServiceStub },
         { provide: ObjectSelectService, useValue: new ObjectSelectServiceStub() },
         { provide: TranslateService, useValue: translateServiceStub },
-        { provide: HostWindowService, useValue: new HostWindowServiceStub(0) }
+        { provide: HostWindowService, useValue: new HostWindowServiceStub(0) },
+        { provide: CollectionDataService, useValue: {} }
       ]
     }).compileComponents();
   }));
diff --git a/src/app/+item-page/edit-item-page/item-collection-mapper/item-collection-mapper.component.ts b/src/app/+item-page/edit-item-page/item-collection-mapper/item-collection-mapper.component.ts
index 5494d5ab5f1f6f7494a81c5e4e904bea1cdde876..8477ae5c2165e23ccc64ec4823d122ae281e78ab 100644
--- a/src/app/+item-page/edit-item-page/item-collection-mapper/item-collection-mapper.component.ts
+++ b/src/app/+item-page/edit-item-page/item-collection-mapper/item-collection-mapper.component.ts
@@ -1,12 +1,18 @@
 import { combineLatest as observableCombineLatest, Observable } from 'rxjs';
 
 import { ChangeDetectionStrategy, Component, OnInit, ViewChild } from '@angular/core';
+import { CollectionDataService } from '../../../core/data/collection-data.service';
 import { fadeIn, fadeInOut } from '../../../shared/animations/fade';
 import { RemoteData } from '../../../core/data/remote-data';
 import { PaginatedList } from '../../../core/data/paginated-list';
 import { Collection } from '../../../core/shared/collection.model';
 import { Item } from '../../../core/shared/item.model';
-import { getRemoteDataPayload, getSucceededRemoteData, toDSpaceObjectListRD } from '../../../core/shared/operators';
+import {
+  getFirstSucceededRemoteDataPayload,
+  getRemoteDataPayload,
+  getSucceededRemoteData,
+  toDSpaceObjectListRD
+} from '../../../core/shared/operators';
 import { ActivatedRoute, Router } from '@angular/router';
 import { map, startWith, switchMap, take } from 'rxjs/operators';
 import { ItemDataService } from '../../../core/data/item-data.service';
@@ -39,7 +45,7 @@ export class ItemCollectionMapperComponent implements OnInit {
    * A view on the tabset element
    * Used to switch tabs programmatically
    */
-  @ViewChild('tabs') tabs;
+  @ViewChild('tabs', {static: false}) tabs;
 
   /**
    * The item to map to collections
@@ -81,6 +87,7 @@ export class ItemCollectionMapperComponent implements OnInit {
               private searchService: SearchService,
               private notificationsService: NotificationsService,
               private itemDataService: ItemDataService,
+              private collectionDataService: CollectionDataService,
               private translateService: TranslateService) {
   }
 
@@ -106,7 +113,8 @@ export class ItemCollectionMapperComponent implements OnInit {
     );
 
     const owningCollectionRD$ = this.itemRD$.pipe(
-      switchMap((itemRD: RemoteData<Item>) => itemRD.payload.owningCollection)
+      getFirstSucceededRemoteDataPayload(),
+      switchMap((item: Item) => this.collectionDataService.findOwningCollectionFor(item))
     );
     const itemCollectionsAndOptions$ = observableCombineLatest(
       this.itemCollectionsRD$,
diff --git a/src/app/+item-page/edit-item-page/item-delete/item-delete.component.spec.ts b/src/app/+item-page/edit-item-page/item-delete/item-delete.component.spec.ts
index 00ae038dae5f8400f521f56c6ffbe10823b993e2..a22d81a5dd9933e3209204fe2604381017b7d290 100644
--- a/src/app/+item-page/edit-item-page/item-delete/item-delete.component.spec.ts
+++ b/src/app/+item-page/edit-item-page/item-delete/item-delete.component.spec.ts
@@ -182,7 +182,7 @@ describe('ItemDeleteComponent', () => {
     notificationsServiceStub = new NotificationsServiceStub();
 
     TestBed.configureTestingModule({
-      imports: [CommonModule, FormsModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule.forRoot()],
+      imports: [CommonModule, FormsModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule],
       declarations: [ItemDeleteComponent, VarDirective],
       providers: [
         { provide: ActivatedRoute, useValue: routeStub },
@@ -220,7 +220,7 @@ describe('ItemDeleteComponent', () => {
       spyOn(comp, 'notify');
       comp.performAction();
       expect(mockItemDataService.delete)
-        .toHaveBeenCalledWith(mockItem, types.filter((type) => typesSelection[type]).map((type) => type.id));
+        .toHaveBeenCalledWith(mockItem.id, types.filter((type) => typesSelection[type]).map((type) => type.id));
       expect(comp.notify).toHaveBeenCalled();
     });
   });
diff --git a/src/app/+item-page/edit-item-page/item-delete/item-delete.component.ts b/src/app/+item-page/edit-item-page/item-delete/item-delete.component.ts
index 6fe44c109bec864f28b254840788fa867daf719b..eecbdf8c6fcb87c68269e252c3aaf8788a841b98 100644
--- a/src/app/+item-page/edit-item-page/item-delete/item-delete.component.ts
+++ b/src/app/+item-page/edit-item-page/item-delete/item-delete.component.ts
@@ -312,7 +312,7 @@ export class ItemDeleteComponent
         )
       ),
     ).subscribe((types) => {
-      this.itemDataService.delete(this.item, types).pipe(first()).subscribe(
+      this.itemDataService.delete(this.item.id, types).pipe(first()).subscribe(
         (succeeded: boolean) => {
           this.notify(succeeded);
         }
@@ -322,7 +322,7 @@ export class ItemDeleteComponent
 
   /**
    * When the item is successfully delete, navigate to the homepage, otherwise navigate back to the item edit page
-   * @param response
+   * @param succeeded
    */
   notify(succeeded: boolean) {
     if (succeeded) {
diff --git a/src/app/+item-page/edit-item-page/item-metadata/edit-in-place-field/edit-in-place-field.component.spec.ts b/src/app/+item-page/edit-item-page/item-metadata/edit-in-place-field/edit-in-place-field.component.spec.ts
index e07df15651677d8c198e6d776b612f17e43378be..09a3989571c0625d1a8457153b1a93dbaed163bf 100644
--- a/src/app/+item-page/edit-item-page/item-metadata/edit-in-place-field/edit-in-place-field.component.spec.ts
+++ b/src/app/+item-page/edit-item-page/item-metadata/edit-in-place-field/edit-in-place-field.component.spec.ts
@@ -1,23 +1,22 @@
-import { async, ComponentFixture, TestBed } from '@angular/core/testing';
 import { CUSTOM_ELEMENTS_SCHEMA, DebugElement } from '@angular/core';
-import { EditInPlaceFieldComponent } from './edit-in-place-field.component';
-import { RegistryService } from '../../../../core/registry/registry.service';
-import { ObjectUpdatesService } from '../../../../core/data/object-updates/object-updates.service';
-import { of as observableOf } from 'rxjs';
-import { RemoteData } from '../../../../core/data/remote-data';
-import { PaginatedList } from '../../../../core/data/paginated-list';
-import { By } from '@angular/platform-browser';
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
 import { FormsModule } from '@angular/forms';
-import { SharedModule } from '../../../../shared/shared.module';
+import { By } from '@angular/platform-browser';
+import { TranslateModule } from '@ngx-translate/core';
 import { getTestScheduler } from 'jasmine-marbles';
+import { of as observableOf } from 'rxjs';
 import { TestScheduler } from 'rxjs/testing';
 import { FieldChangeType } from '../../../../core/data/object-updates/object-updates.actions';
-import { TranslateModule } from '@ngx-translate/core';
-import { MetadatumViewModel } from '../../../../core/shared/metadata.models';
-import { MetadataSchema } from '../../../../core/metadata/metadata-schema.model';
+import { ObjectUpdatesService } from '../../../../core/data/object-updates/object-updates.service';
+import { PaginatedList } from '../../../../core/data/paginated-list';
 import { MetadataField } from '../../../../core/metadata/metadata-field.model';
-import { createSuccessfulRemoteDataObject$ } from '../../../../shared/testing/utils';
+import { MetadataSchema } from '../../../../core/metadata/metadata-schema.model';
+import { RegistryService } from '../../../../core/registry/registry.service';
+import { MetadatumViewModel } from '../../../../core/shared/metadata.models';
 import { InputSuggestion } from '../../../../shared/input-suggestions/input-suggestions.model';
+import { SharedModule } from '../../../../shared/shared.module';
+import { createSuccessfulRemoteDataObject$ } from '../../../../shared/testing/utils';
+import { EditInPlaceFieldComponent } from './edit-in-place-field.component';
 
 let comp: EditInPlaceFieldComponent;
 let fixture: ComponentFixture<EditInPlaceFieldComponent>;
diff --git a/src/app/+item-page/edit-item-page/item-metadata/item-metadata.component.ts b/src/app/+item-page/edit-item-page/item-metadata/item-metadata.component.ts
index 01848c828352ab119daa347c54c1b8f185d68abe..3111e23589d81ee169d1bf656015bec15f56ec13 100644
--- a/src/app/+item-page/edit-item-page/item-metadata/item-metadata.component.ts
+++ b/src/app/+item-page/edit-item-page/item-metadata/item-metadata.component.ts
@@ -1,4 +1,5 @@
 import { Component, Inject } from '@angular/core';
+import { LinkService } from '../../../core/cache/builders/link.service';
 import { Item } from '../../../core/shared/item.model';
 import { ItemDataService } from '../../../core/data/item-data.service';
 import { ObjectUpdatesService } from '../../../core/data/object-updates/object-updates.service';
diff --git a/src/app/+item-page/edit-item-page/item-move/item-move.component.spec.ts b/src/app/+item-page/edit-item-page/item-move/item-move.component.spec.ts
index aa84b160a0ca6a397d2967c22203c94baee1e315..92be39ec9d26cb763e0f3108de1a337f511aeee6 100644
--- a/src/app/+item-page/edit-item-page/item-move/item-move.component.spec.ts
+++ b/src/app/+item-page/edit-item-page/item-move/item-move.component.spec.ts
@@ -1,23 +1,23 @@
-import { async, ComponentFixture, TestBed } from '@angular/core/testing';
-import { Item } from '../../../core/shared/item.model';
-import { RouterStub } from '../../../shared/testing/router-stub';
 import { CommonModule } from '@angular/common';
+import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { FormsModule } from '@angular/forms';
+import { ActivatedRoute, Router } from '@angular/router';
 import { RouterTestingModule } from '@angular/router/testing';
-import { TranslateModule } from '@ngx-translate/core';
 import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
-import { ActivatedRoute, Router } from '@angular/router';
-import { ItemMoveComponent } from './item-move.component';
-import { NotificationsServiceStub } from '../../../shared/testing/notifications-service-stub';
-import { NotificationsService } from '../../../shared/notifications/notifications.service';
+import { TranslateModule } from '@ngx-translate/core';
 import { of as observableOf } from 'rxjs';
-import { FormsModule } from '@angular/forms';
+import { RestResponse } from '../../../core/cache/response.models';
 import { ItemDataService } from '../../../core/data/item-data.service';
-import { RemoteData } from '../../../core/data/remote-data';
 import { PaginatedList } from '../../../core/data/paginated-list';
-import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
-import { RestResponse } from '../../../core/cache/response.models';
+import { RemoteData } from '../../../core/data/remote-data';
 import { Collection } from '../../../core/shared/collection.model';
+import { Item } from '../../../core/shared/item.model';
 import { SearchService } from '../../../core/shared/search/search.service';
+import { NotificationsService } from '../../../shared/notifications/notifications.service';
+import { NotificationsServiceStub } from '../../../shared/testing/notifications-service-stub';
+import { RouterStub } from '../../../shared/testing/router-stub';
+import { ItemMoveComponent } from './item-move.component';
 
 describe('ItemMoveComponent', () => {
   let comp: ItemMoveComponent;
@@ -50,16 +50,14 @@ describe('ItemMoveComponent', () => {
     })
   };
 
-  const collection1 = Object.assign(new Collection(),{
+  const collection1 = Object.assign(new Collection(), {
     uuid: 'collection-uuid-1',
-    name: 'Test collection 1',
-    self: 'self-link-1',
+    name: 'Test collection 1'
   });
 
-  const collection2 = Object.assign(new Collection(),{
+  const collection2 = Object.assign(new Collection(), {
     uuid: 'collection-uuid-2',
-    name: 'Test collection 2',
-    self: 'self-link-2',
+    name: 'Test collection 2'
   });
 
   const mockSearchService = {
@@ -80,23 +78,20 @@ describe('ItemMoveComponent', () => {
   const notificationsServiceStub = new NotificationsServiceStub();
 
   describe('ItemMoveComponent success', () => {
-    beforeEach(async(() => {
+    beforeEach(() => {
       TestBed.configureTestingModule({
-        imports: [CommonModule, FormsModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule.forRoot()],
+        imports: [CommonModule, FormsModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule],
         declarations: [ItemMoveComponent],
         providers: [
-          {provide: ActivatedRoute, useValue: routeStub},
-          {provide: Router, useValue: routerStub},
-          {provide: ItemDataService, useValue: mockItemDataService},
-          {provide: NotificationsService, useValue: notificationsServiceStub},
-          {provide: SearchService, useValue: mockSearchService},
+          { provide: ActivatedRoute, useValue: routeStub },
+          { provide: Router, useValue: routerStub },
+          { provide: ItemDataService, useValue: mockItemDataService },
+          { provide: NotificationsService, useValue: notificationsServiceStub },
+          { provide: SearchService, useValue: mockSearchService },
         ], schemas: [
           CUSTOM_ELEMENTS_SCHEMA
         ]
       }).compileComponents();
-    }));
-
-    beforeEach(() => {
       fixture = TestBed.createComponent(ItemMoveComponent);
       comp = fixture.componentInstance;
       fixture.detectChanges();
@@ -141,23 +136,20 @@ describe('ItemMoveComponent', () => {
   });
 
   describe('ItemMoveComponent fail', () => {
-    beforeEach(async(() => {
+    beforeEach(() => {
       TestBed.configureTestingModule({
-        imports: [CommonModule, FormsModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule.forRoot()],
+        imports: [CommonModule, FormsModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule],
         declarations: [ItemMoveComponent],
         providers: [
-          {provide: ActivatedRoute, useValue: routeStub},
-          {provide: Router, useValue: routerStub},
-          {provide: ItemDataService, useValue: mockItemDataServiceFail},
-          {provide: NotificationsService, useValue: notificationsServiceStub},
-          {provide: SearchService, useValue: mockSearchService},
+          { provide: ActivatedRoute, useValue: routeStub },
+          { provide: Router, useValue: routerStub },
+          { provide: ItemDataService, useValue: mockItemDataServiceFail },
+          { provide: NotificationsService, useValue: notificationsServiceStub },
+          { provide: SearchService, useValue: mockSearchService },
         ], schemas: [
           CUSTOM_ELEMENTS_SCHEMA
         ]
       }).compileComponents();
-    }));
-
-    beforeEach(() => {
       fixture = TestBed.createComponent(ItemMoveComponent);
       comp = fixture.componentInstance;
       fixture.detectChanges();
diff --git a/src/app/+item-page/edit-item-page/item-private/item-private.component.spec.ts b/src/app/+item-page/edit-item-page/item-private/item-private.component.spec.ts
index 827a4bb55ad27f532e7c9c4fd5050eca37342f9e..0bde371637c3c787c605734c14e925dc8ead7bf8 100644
--- a/src/app/+item-page/edit-item-page/item-private/item-private.component.spec.ts
+++ b/src/app/+item-page/edit-item-page/item-private/item-private.component.spec.ts
@@ -60,7 +60,7 @@ describe('ItemPrivateComponent', () => {
     notificationsServiceStub = new NotificationsServiceStub();
 
     TestBed.configureTestingModule({
-      imports: [CommonModule, FormsModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule.forRoot()],
+      imports: [CommonModule, FormsModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule],
       declarations: [ItemPrivateComponent],
       providers: [
         { provide: ActivatedRoute, useValue: routeStub },
diff --git a/src/app/+item-page/edit-item-page/item-public/item-public.component.spec.ts b/src/app/+item-page/edit-item-page/item-public/item-public.component.spec.ts
index 9cd75088684e038b6605ab48c3aa4f11c57e158e..885ced897e320ec0e067c5f15b042c046b2dda39 100644
--- a/src/app/+item-page/edit-item-page/item-public/item-public.component.spec.ts
+++ b/src/app/+item-page/edit-item-page/item-public/item-public.component.spec.ts
@@ -60,7 +60,7 @@ describe('ItemPublicComponent', () => {
     notificationsServiceStub = new NotificationsServiceStub();
 
     TestBed.configureTestingModule({
-      imports: [CommonModule, FormsModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule.forRoot()],
+      imports: [CommonModule, FormsModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule],
       declarations: [ItemPublicComponent],
       providers: [
         { provide: ActivatedRoute, useValue: routeStub },
diff --git a/src/app/+item-page/edit-item-page/item-reinstate/item-reinstate.component.spec.ts b/src/app/+item-page/edit-item-page/item-reinstate/item-reinstate.component.spec.ts
index 8dfc403bd36fd9440a26fe4f846a84e97ac9b60a..0ba451a09ba9c12009f04568ea0ce18e809384bf 100644
--- a/src/app/+item-page/edit-item-page/item-reinstate/item-reinstate.component.spec.ts
+++ b/src/app/+item-page/edit-item-page/item-reinstate/item-reinstate.component.spec.ts
@@ -60,7 +60,7 @@ describe('ItemReinstateComponent', () => {
     notificationsServiceStub = new NotificationsServiceStub();
 
     TestBed.configureTestingModule({
-      imports: [CommonModule, FormsModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule.forRoot()],
+      imports: [CommonModule, FormsModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule],
       declarations: [ItemReinstateComponent],
       providers: [
         { provide: ActivatedRoute, useValue: routeStub },
diff --git a/src/app/+item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.spec.ts b/src/app/+item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.spec.ts
index cede48e6ee40fcd373009ebad87ece857da50deb..0608eab2d87e313609e9170e8a5fdfabb6875961 100644
--- a/src/app/+item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.spec.ts
+++ b/src/app/+item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.spec.ts
@@ -1,19 +1,22 @@
-import {EditRelationshipListComponent} from './edit-relationship-list.component';
-import {async, ComponentFixture, TestBed} from '@angular/core/testing';
-import {RelationshipType} from '../../../../core/shared/item-relationships/relationship-type.model';
-import {Relationship} from '../../../../core/shared/item-relationships/relationship.model';
-import {of as observableOf} from 'rxjs/internal/observable/of';
-import {RemoteData} from '../../../../core/data/remote-data';
-import {Item} from '../../../../core/shared/item.model';
-import {PaginatedList} from '../../../../core/data/paginated-list';
-import {PageInfo} from '../../../../core/shared/page-info.model';
-import {FieldChangeType} from '../../../../core/data/object-updates/object-updates.actions';
-import {SharedModule} from '../../../../shared/shared.module';
-import {TranslateModule} from '@ngx-translate/core';
-import {ObjectUpdatesService} from '../../../../core/data/object-updates/object-updates.service';
-import {DebugElement, NO_ERRORS_SCHEMA} from '@angular/core';
-import {By} from '@angular/platform-browser';
-import {ItemType} from '../../../../core/shared/item-relationships/item-type.model';
+import { DebugElement, NO_ERRORS_SCHEMA } from '@angular/core';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { By } from '@angular/platform-browser';
+import { TranslateModule } from '@ngx-translate/core';
+import { of as observableOf } from 'rxjs/internal/observable/of';
+import { LinkService } from '../../../../core/cache/builders/link.service';
+import { FieldChangeType } from '../../../../core/data/object-updates/object-updates.actions';
+import { ObjectUpdatesService } from '../../../../core/data/object-updates/object-updates.service';
+import { PaginatedList } from '../../../../core/data/paginated-list';
+import { RelationshipTypeService } from '../../../../core/data/relationship-type.service';
+import { RemoteData } from '../../../../core/data/remote-data';
+import { ItemType } from '../../../../core/shared/item-relationships/item-type.model';
+import { RelationshipType } from '../../../../core/shared/item-relationships/relationship-type.model';
+import { Relationship } from '../../../../core/shared/item-relationships/relationship.model';
+import { Item } from '../../../../core/shared/item.model';
+import { PageInfo } from '../../../../core/shared/page-info.model';
+import { getMockLinkService } from '../../../../shared/mocks/mock-link-service';
+import { SharedModule } from '../../../../shared/shared.module';
+import { EditRelationshipListComponent } from './edit-relationship-list.component';
 
 let comp: EditRelationshipListComponent;
 let fixture: ComponentFixture<EditRelationshipListComponent>;
@@ -57,7 +60,11 @@ describe('EditRelationshipListComponent', () => {
     });
 
     relationship1 = Object.assign(new Relationship(), {
-      self: url + '/2',
+      _links: {
+        self: {
+          href: url + '/2'
+        }
+      },
       id: '2',
       uuid: '2',
       leftId: 'author1',
@@ -68,7 +75,11 @@ describe('EditRelationshipListComponent', () => {
     });
 
     relationship2 = Object.assign(new Relationship(), {
-      self: url + '/3',
+      _links: {
+        self: {
+          href: url + '/3'
+        }
+      },
       id: '3',
       uuid: '3',
       leftId: 'author2',
@@ -79,7 +90,9 @@ describe('EditRelationshipListComponent', () => {
     });
 
     item = Object.assign(new Item(), {
-      self: 'fake-item-url/publication',
+      _links: {
+        self: { href: 'fake-item-url/publication' }
+      },
       id: 'publication',
       uuid: 'publication',
       relationships: observableOf(new RemoteData(
@@ -142,6 +155,8 @@ describe('EditRelationshipListComponent', () => {
       declarations: [EditRelationshipListComponent],
       providers: [
         { provide: ObjectUpdatesService, useValue: objectUpdatesService },
+        { provide: RelationshipTypeService, useValue: {} },
+        { provide: LinkService, useValue: getMockLinkService() },
       ], schemas: [
         NO_ERRORS_SCHEMA
       ]
diff --git a/src/app/+item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.ts b/src/app/+item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.ts
index 73e3e1f8756b2aa4e1d3cdb39b95fd81e035bc2a..c17762e4a0c61b0d22fd11497e45a643912f2750 100644
--- a/src/app/+item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.ts
+++ b/src/app/+item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.ts
@@ -1,15 +1,21 @@
 import { Component, Input, OnInit } from '@angular/core';
+import { LinkService } from '../../../../core/cache/builders/link.service';
 import { ObjectUpdatesService } from '../../../../core/data/object-updates/object-updates.service';
 import { Observable } from 'rxjs/internal/Observable';
 import {FieldUpdate, FieldUpdates} from '../../../../core/data/object-updates/object-updates.reducer';
 import {Item} from '../../../../core/shared/item.model';
-import {map, switchMap} from 'rxjs/operators';
+import { map, switchMap, tap } from 'rxjs/operators';
 import {hasValue} from '../../../../shared/empty.util';
 import {Relationship} from '../../../../core/shared/item-relationships/relationship.model';
 import {RelationshipType} from '../../../../core/shared/item-relationships/relationship-type.model';
-import {getRemoteDataPayload, getSucceededRemoteData} from '../../../../core/shared/operators';
-import {combineLatest as observableCombineLatest, combineLatest} from 'rxjs';
-import {ItemType} from '../../../../core/shared/item-relationships/item-type.model';
+import {
+  getAllSucceededRemoteData,
+  getRemoteDataPayload,
+  getSucceededRemoteData
+} from '../../../../core/shared/operators';
+import { combineLatest as observableCombineLatest } from 'rxjs';
+import { ItemType } from '../../../../core/shared/item-relationships/item-type.model';
+import { followLink } from '../../../../shared/utils/follow-link-config.model';
 
 @Component({
   selector: 'ds-edit-relationship-list',
@@ -47,6 +53,7 @@ export class EditRelationshipListComponent implements OnInit {
 
   constructor(
     protected objectUpdatesService: ObjectUpdatesService,
+    protected linkService: LinkService
   ) {
   }
 
@@ -71,7 +78,7 @@ export class EditRelationshipListComponent implements OnInit {
    */
   private getLabel(): Observable<string> {
 
-    return combineLatest([
+    return observableCombineLatest([
       this.relationshipType.leftType,
       this.relationshipType.rightType,
     ].map((itemTypeRD) => itemTypeRD.pipe(
@@ -94,8 +101,20 @@ export class EditRelationshipListComponent implements OnInit {
 
   ngOnInit(): void {
     this.updates$ = this.item.relationships.pipe(
+      getAllSucceededRemoteData(),
       map((relationships) => relationships.payload.page.filter((relationship) => relationship)),
-      switchMap((itemRelationships) =>
+      map((relationships: Relationship[]) =>
+        relationships.map((relationship: Relationship) => {
+          this.linkService.resolveLinks(
+            relationship,
+            followLink('relationshipType'),
+            followLink('leftItem'),
+            followLink('rightItem'),
+          );
+          return relationship;
+        })
+      ),
+      switchMap((itemRelationships: Relationship[]) =>
         observableCombineLatest(
           itemRelationships
             .map((relationship) => relationship.relationshipType.pipe(
diff --git a/src/app/+item-page/edit-item-page/item-relationships/edit-relationship/edit-relationship.component.spec.ts b/src/app/+item-page/edit-item-page/item-relationships/edit-relationship/edit-relationship.component.spec.ts
index b3c3e773b22acf71d708955868aeb6ffd4ed5b0e..9eca3f270d72cdddf94237fc927ac0154e45df46 100644
--- a/src/app/+item-page/edit-item-page/item-relationships/edit-relationship/edit-relationship.component.spec.ts
+++ b/src/app/+item-page/edit-item-page/item-relationships/edit-relationship/edit-relationship.component.spec.ts
@@ -1,16 +1,16 @@
+import { NO_ERRORS_SCHEMA } from '@angular/core';
 import { async, TestBed } from '@angular/core/testing';
-import { of as observableOf } from 'rxjs/internal/observable/of';
 import { TranslateModule } from '@ngx-translate/core';
+import { of as observableOf } from 'rxjs/internal/observable/of';
+import { FieldChangeType } from '../../../../core/data/object-updates/object-updates.actions';
 import { ObjectUpdatesService } from '../../../../core/data/object-updates/object-updates.service';
-import { NO_ERRORS_SCHEMA } from '@angular/core';
-import { EditRelationshipComponent } from './edit-relationship.component';
+import { PaginatedList } from '../../../../core/data/paginated-list';
+import { RemoteData } from '../../../../core/data/remote-data';
 import { RelationshipType } from '../../../../core/shared/item-relationships/relationship-type.model';
 import { Relationship } from '../../../../core/shared/item-relationships/relationship.model';
-import { RemoteData } from '../../../../core/data/remote-data';
 import { Item } from '../../../../core/shared/item.model';
-import { PaginatedList } from '../../../../core/data/paginated-list';
 import { PageInfo } from '../../../../core/shared/page-info.model';
-import { FieldChangeType } from '../../../../core/data/object-updates/object-updates.actions';
+import { EditRelationshipComponent } from './edit-relationship.component';
 import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
 
 let objectUpdatesService;
@@ -42,7 +42,11 @@ describe('EditRelationshipComponent', () => {
     });
 
     item = Object.assign(new Item(), {
-      self: 'fake-item-url/publication',
+      _links: {
+        self: {
+          href: 'fake-item-url/publication'
+        }
+      },
       id: 'publication',
       uuid: 'publication',
       relationships: observableOf(new RemoteData(false, false, true, undefined, new PaginatedList(new PageInfo(), relationships)))
@@ -54,7 +58,9 @@ describe('EditRelationshipComponent', () => {
 
     relationships = [
       Object.assign(new Relationship(), {
-        self: url + '/2',
+        _links: {
+          self: { href: url + '/2' }
+        },
         id: '2',
         uuid: '2',
         leftId: 'author1',
@@ -64,7 +70,9 @@ describe('EditRelationshipComponent', () => {
         rightItem: observableOf(new RemoteData(false, false, true, undefined, item)),
       }),
       Object.assign(new Relationship(), {
-        self: url + '/3',
+        _links: {
+          self: { href: url + '/3' }
+        },
         id: '3',
         uuid: '3',
         leftId: 'author2',
diff --git a/src/app/+item-page/edit-item-page/item-relationships/item-relationships.component.spec.ts b/src/app/+item-page/edit-item-page/item-relationships/item-relationships.component.spec.ts
index aa812354b6c7accc1ba95610d98d9cf900dcbad7..c8bd577e04e7dc0f3a178c13723c867597a5266b 100644
--- a/src/app/+item-page/edit-item-page/item-relationships/item-relationships.component.spec.ts
+++ b/src/app/+item-page/edit-item-page/item-relationships/item-relationships.component.spec.ts
@@ -1,32 +1,35 @@
-import { async, ComponentFixture, TestBed } from '@angular/core/testing';
-import { ItemRelationshipsComponent } from './item-relationships.component';
 import { ChangeDetectorRef, DebugElement, NO_ERRORS_SCHEMA } from '@angular/core';
-import { INotification, Notification } from '../../../shared/notifications/models/notification.model';
-import { NotificationType } from '../../../shared/notifications/models/notification-type';
-import { RouterStub } from '../../../shared/testing/router-stub';
-import { TestScheduler } from 'rxjs/testing';
-import { SharedModule } from '../../../shared/shared.module';
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { ActivatedRoute, Router } from '@angular/router';
 import { TranslateModule } from '@ngx-translate/core';
+import { getTestScheduler } from 'jasmine-marbles';
+import { combineLatest as observableCombineLatest, of as observableOf } from 'rxjs';
+import { TestScheduler } from 'rxjs/testing';
+import { GLOBAL_CONFIG } from '../../../../config';
+import { ObjectCacheService } from '../../../core/cache/object-cache.service';
+import { RestResponse } from '../../../core/cache/response.models';
+import { EntityTypeService } from '../../../core/data/entity-type.service';
 import { ItemDataService } from '../../../core/data/item-data.service';
+import { FieldChangeType } from '../../../core/data/object-updates/object-updates.actions';
 import { ObjectUpdatesService } from '../../../core/data/object-updates/object-updates.service';
-import { ActivatedRoute, Router } from '@angular/router';
-import { NotificationsService } from '../../../shared/notifications/notifications.service';
-import { GLOBAL_CONFIG } from '../../../../config';
-import { RelationshipType } from '../../../core/shared/item-relationships/relationship-type.model';
-import { Relationship } from '../../../core/shared/item-relationships/relationship.model';
-import { combineLatest as observableCombineLatest, of as observableOf } from 'rxjs';
-import { RemoteData } from '../../../core/data/remote-data';
-import { Item } from '../../../core/shared/item.model';
 import { PaginatedList } from '../../../core/data/paginated-list';
-import { PageInfo } from '../../../core/shared/page-info.model';
-import { FieldChangeType } from '../../../core/data/object-updates/object-updates.actions';
 import { RelationshipService } from '../../../core/data/relationship.service';
-import { ObjectCacheService } from '../../../core/cache/object-cache.service';
-import { getTestScheduler } from 'jasmine-marbles';
-import { RestResponse } from '../../../core/cache/response.models';
+import { RemoteData } from '../../../core/data/remote-data';
 import { RequestService } from '../../../core/data/request.service';
-import { EntityTypeService } from '../../../core/data/entity-type.service';
 import { ItemType } from '../../../core/shared/item-relationships/item-type.model';
+import { RelationshipType } from '../../../core/shared/item-relationships/relationship-type.model';
+import { Relationship } from '../../../core/shared/item-relationships/relationship.model';
+import { Item } from '../../../core/shared/item.model';
+import { PageInfo } from '../../../core/shared/page-info.model';
+import { NotificationType } from '../../../shared/notifications/models/notification-type';
+import {
+  INotification,
+  Notification
+} from '../../../shared/notifications/models/notification.model';
+import { NotificationsService } from '../../../shared/notifications/notifications.service';
+import { SharedModule } from '../../../shared/shared.module';
+import { RouterStub } from '../../../shared/testing/router-stub';
+import { ItemRelationshipsComponent } from './item-relationships.component';
 
 let comp: any;
 let fixture: ComponentFixture<ItemRelationshipsComponent>;
@@ -77,13 +80,17 @@ describe('ItemRelationshipsComponent', () => {
 
     relationships = [
       Object.assign(new Relationship(), {
-        self: url + '/2',
+        _links: {
+          self: { href: url + '/2' }
+        },
         id: '2',
         uuid: '2',
         relationshipType: observableOf(new RemoteData(false, false, true, undefined, relationshipType))
       }),
       Object.assign(new Relationship(), {
-        self: url + '/3',
+        _links: {
+          self: { href: url + '/3' }
+        },
         id: '3',
         uuid: '3',
         relationshipType: observableOf(new RemoteData(false, false, true, undefined, relationshipType))
@@ -91,7 +98,9 @@ describe('ItemRelationshipsComponent', () => {
     ];
 
     item = Object.assign(new Item(), {
-      self: 'fake-item-url/publication',
+      _links: {
+        self: { href: 'fake-item-url/publication' }
+      },
       id: 'publication',
       uuid: 'publication',
       relationships: observableOf(new RemoteData(false, false, true, undefined, new PaginatedList(new PageInfo(), relationships))),
diff --git a/src/app/+item-page/edit-item-page/item-relationships/item-relationships.component.ts b/src/app/+item-page/edit-item-page/item-relationships/item-relationships.component.ts
index 0374e83782f4ad9a1271477eb1ffb07360cd20fd..1958dd0f88fa75d0c7507f670a9a99bb56ed4bf9 100644
--- a/src/app/+item-page/edit-item-page/item-relationships/item-relationships.component.ts
+++ b/src/app/+item-page/edit-item-page/item-relationships/item-relationships.component.ts
@@ -4,6 +4,7 @@ import { DeleteRelationship, FieldUpdate, FieldUpdates } from '../../../core/dat
 import { Observable } from 'rxjs/internal/Observable';
 import { filter, map, switchMap, take } from 'rxjs/operators';
 import { zip as observableZip } from 'rxjs';
+import { followLink } from '../../../shared/utils/follow-link-config.model';
 import { AbstractItemUpdateComponent } from '../abstract-item-update/abstract-item-update.component';
 import { ItemDataService } from '../../../core/data/item-data.service';
 import { ObjectUpdatesService } from '../../../core/data/object-updates/object-updates.service';
@@ -71,7 +72,10 @@ export class ItemRelationshipsComponent extends AbstractItemUpdateComponent impl
     super.ngOnInit();
     this.itemUpdateSubscription = this.requestService.hasByHrefObservable(this.item.self).pipe(
       filter((exists: boolean) => !exists),
-      switchMap(() => this.itemService.findById(this.item.uuid)),
+      switchMap(() => this.itemService.findById(this.item.uuid,
+        followLink('owningCollection'),
+        followLink('bundles'),
+        followLink('relationships'))),
       getSucceededRemoteData(),
     ).subscribe((itemRD: RemoteData<Item>) => {
       this.item = itemRD.payload;
@@ -94,7 +98,11 @@ export class ItemRelationshipsComponent extends AbstractItemUpdateComponent impl
 
     this.relationshipTypes$ = this.entityType$.pipe(
       switchMap((entityType) =>
-        this.entityTypeService.getEntityTypeRelationships(entityType.id).pipe(
+        this.entityTypeService.getEntityTypeRelationships(
+          entityType.id,
+          followLink('leftType'),
+          followLink('rightType'))
+        .pipe(
           getSucceededRemoteData(),
           getRemoteDataPayload(),
           map((relationshipTypes) => relationshipTypes.page),
diff --git a/src/app/+item-page/edit-item-page/item-status/item-status.component.spec.ts b/src/app/+item-page/edit-item-page/item-status/item-status.component.spec.ts
index 30f326bec4a573dd9d5196b3c7d91ecc04f8cf83..bb8fc29da21f39ae54a1917586cb227877e29c0d 100644
--- a/src/app/+item-page/edit-item-page/item-status/item-status.component.spec.ts
+++ b/src/app/+item-page/edit-item-page/item-status/item-status.component.spec.ts
@@ -33,7 +33,7 @@ describe('ItemStatusComponent', () => {
 
   beforeEach(async(() => {
     TestBed.configureTestingModule({
-      imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule.forRoot()],
+      imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule],
       declarations: [ItemStatusComponent],
       providers: [
         { provide: ActivatedRoute, useValue: routeStub },
diff --git a/src/app/+item-page/edit-item-page/item-withdraw/item-withdraw.component.spec.ts b/src/app/+item-page/edit-item-page/item-withdraw/item-withdraw.component.spec.ts
index 4c23a1d1e5ab312caaddcdc39f1edb49271f0201..ef28e8c0077c5cc6800a22fc54b0e594febb2082 100644
--- a/src/app/+item-page/edit-item-page/item-withdraw/item-withdraw.component.spec.ts
+++ b/src/app/+item-page/edit-item-page/item-withdraw/item-withdraw.component.spec.ts
@@ -60,7 +60,7 @@ describe('ItemWithdrawComponent', () => {
     notificationsServiceStub = new NotificationsServiceStub();
 
     TestBed.configureTestingModule({
-      imports: [CommonModule, FormsModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule.forRoot(),],
+      imports: [CommonModule, FormsModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule,],
       declarations: [ItemWithdrawComponent],
       providers: [
         { provide: ActivatedRoute, useValue: routeStub },
diff --git a/src/app/+item-page/edit-item-page/simple-item-action/abstract-simple-item-action.component.spec.ts b/src/app/+item-page/edit-item-page/simple-item-action/abstract-simple-item-action.component.spec.ts
index e4413e47c607c1ecd3d1170ee1ef62755bc9c09f..51c21ab4fb8bbed49b082ef4bf9b3c6a167ad9dc 100644
--- a/src/app/+item-page/edit-item-page/simple-item-action/abstract-simple-item-action.component.spec.ts
+++ b/src/app/+item-page/edit-item-page/simple-item-action/abstract-simple-item-action.component.spec.ts
@@ -83,7 +83,7 @@ describe('AbstractSimpleItemActionComponent', () => {
     notificationsServiceStub = new NotificationsServiceStub();
 
     TestBed.configureTestingModule({
-      imports: [CommonModule, FormsModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule.forRoot()],
+      imports: [CommonModule, FormsModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule],
       declarations: [MySimpleItemActionComponent],
       providers: [
         { provide: ActivatedRoute, useValue: routeStub },
diff --git a/src/app/+item-page/field-components/collections/collections.component.html b/src/app/+item-page/field-components/collections/collections.component.html
index 6e5f9a350cdba2846a0f9a20aebce38bae6baac9..e0f963b5bc65753011618620bfdf41de43883ca9 100644
--- a/src/app/+item-page/field-components/collections/collections.component.html
+++ b/src/app/+item-page/field-components/collections/collections.component.html
@@ -1,6 +1,6 @@
-<ds-metadata-field-wrapper *ngIf="hasSucceeded() | async" [label]="label | translate">
+<ds-metadata-field-wrapper *ngIf="(this.collectionsRD$ | async)?.hasSucceeded" [label]="label | translate">
     <div class="collections">
-        <a *ngFor="let collection of (collections | async); let last=last;" [routerLink]="['/collections', collection.id]">
+        <a *ngFor="let collection of (this.collectionsRD$ | async)?.payload?.page; let last=last;" [routerLink]="['/collections', collection.id]">
             <span>{{collection?.name}}</span><span *ngIf="!last" [innerHTML]="separator"></span>
         </a>
     </div>
diff --git a/src/app/+item-page/field-components/collections/collections.component.spec.ts b/src/app/+item-page/field-components/collections/collections.component.spec.ts
index b53f4998811b078ca1e7f21a8a4a1d3e939294a2..3c8529e38b3f23178828c23a435e9b56ce124b74 100644
--- a/src/app/+item-page/field-components/collections/collections.component.spec.ts
+++ b/src/app/+item-page/field-components/collections/collections.component.spec.ts
@@ -1,22 +1,20 @@
-import { CollectionsComponent } from './collections.component';
-import { async, ComponentFixture, TestBed } from '@angular/core/testing';
 import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
 import { By } from '@angular/platform-browser';
-import { Collection } from '../../../core/shared/collection.model';
+import { TranslateModule } from '@ngx-translate/core';
 import { RemoteDataBuildService } from '../../../core/cache/builders/remote-data-build.service';
-import { getMockRemoteDataBuildService } from '../../../shared/mocks/mock-remote-data-build.service';
+import { CollectionDataService } from '../../../core/data/collection-data.service';
+import { Collection } from '../../../core/shared/collection.model';
 import { Item } from '../../../core/shared/item.model';
-import { of as observableOf } from 'rxjs';
-import { RemoteData } from '../../../core/data/remote-data';
-import { TranslateModule } from '@ngx-translate/core';
-import {
-  createFailedRemoteDataObject$,
-  createSuccessfulRemoteDataObject$
-} from '../../../shared/testing/utils';
+import { getMockRemoteDataBuildService } from '../../../shared/mocks/mock-remote-data-build.service';
+import { createFailedRemoteDataObject$, createSuccessfulRemoteDataObject$ } from '../../../shared/testing/utils';
+import { CollectionsComponent } from './collections.component';
 
 let collectionsComponent: CollectionsComponent;
 let fixture: ComponentFixture<CollectionsComponent>;
 
+let collectionDataServiceStub;
+
 const mockCollection1: Collection = Object.assign(new Collection(), {
   metadata: {
     'dc.description.abstract': [
@@ -32,12 +30,22 @@ const succeededMockItem: Item = Object.assign(new Item(), {owningCollection: cre
 const failedMockItem: Item = Object.assign(new Item(), {owningCollection: createFailedRemoteDataObject$(mockCollection1)});
 
 describe('CollectionsComponent', () => {
+  collectionDataServiceStub = {
+    findOwningCollectionFor(item: Item) {
+      if (item === succeededMockItem) {
+        return createSuccessfulRemoteDataObject$(mockCollection1);
+      } else {
+        return createFailedRemoteDataObject$(mockCollection1);
+      }
+    }
+  };
   beforeEach(async(() => {
     TestBed.configureTestingModule({
       imports: [TranslateModule.forRoot()],
       declarations: [ CollectionsComponent ],
       providers: [
-        { provide: RemoteDataBuildService, useValue: getMockRemoteDataBuildService()}
+        { provide: RemoteDataBuildService, useValue: getMockRemoteDataBuildService()},
+        { provide: CollectionDataService, useValue: collectionDataServiceStub },
       ],
 
       schemas: [ NO_ERRORS_SCHEMA ]
diff --git a/src/app/+item-page/field-components/collections/collections.component.ts b/src/app/+item-page/field-components/collections/collections.component.ts
index b33c5fd41b0b39f78e24793890b736c0f939d987..0d50fcad83ad7688285511634a53902f2a7f6cc9 100644
--- a/src/app/+item-page/field-components/collections/collections.component.ts
+++ b/src/app/+item-page/field-components/collections/collections.component.ts
@@ -1,12 +1,13 @@
-
-import {map} from 'rxjs/operators';
 import { Component, Input, OnInit } from '@angular/core';
 import { Observable } from 'rxjs';
+import { map } from 'rxjs/operators';
+import { CollectionDataService } from '../../../core/data/collection-data.service';
+import { PaginatedList } from '../../../core/data/paginated-list';
+import { RemoteData } from '../../../core/data/remote-data';
 
 import { Collection } from '../../../core/shared/collection.model';
 import { Item } from '../../../core/shared/item.model';
-import { RemoteDataBuildService } from '../../../core/cache/builders/remote-data-build.service';
-import { RemoteData } from '../../../core/data/remote-data';
+import { PageInfo } from '../../../core/shared/page-info.model';
 
 /**
  * This component renders the parent collections section of the item
@@ -25,9 +26,9 @@ export class CollectionsComponent implements OnInit {
 
   separator = '<br/>';
 
-  collections: Observable<Collection[]>;
+  collectionsRD$: Observable<RemoteData<PaginatedList<Collection>>>;
 
-  constructor(private rdbs: RemoteDataBuildService) {
+  constructor(private cds: CollectionDataService) {
 
   }
 
@@ -37,11 +38,25 @@ export class CollectionsComponent implements OnInit {
     // TODO: this should use parents, but the collections
     // for an Item aren't returned by the REST API yet,
     // only the owning collection
-    this.collections = this.item.owner.pipe(map((rd: RemoteData<Collection>) => [rd.payload]));
+    this.collectionsRD$ = this.cds.findOwningCollectionFor(this.item).pipe(
+      map((rd: RemoteData<Collection>) => {
+        if (rd.hasSucceeded) {
+          return new RemoteData(
+            false,
+            false,
+            true,
+            undefined,
+            new PaginatedList({
+              elementsPerPage: 10,
+              totalPages: 1,
+              currentPage: 1,
+              totalElements: 1
+            } as PageInfo, [rd.payload])
+          );
+        } else {
+          return rd as any;
+        }
+      })
+    );
   }
-
-  hasSucceeded() {
-    return this.item.owner.pipe(map((rd: RemoteData<Collection>) => rd.hasSucceeded));
-  }
-
 }
diff --git a/src/app/+item-page/full/field-components/file-section/full-file-section.component.html b/src/app/+item-page/full/field-components/file-section/full-file-section.component.html
index a68993cd16d9d45c71b915887c422c0aa7830a70..b8ab9bdb41496932528ddcd6b97d2a3d4b2a302b 100644
--- a/src/app/+item-page/full/field-components/file-section/full-file-section.component.html
+++ b/src/app/+item-page/full/field-components/file-section/full-file-section.component.html
@@ -1,7 +1,7 @@
 <ds-metadata-field-wrapper [label]="label | translate">
-    <div class="file-section row" *ngFor="let file of (bitstreamsObs | async); let last=last;">
+    <div class="file-section row" *ngFor="let file of (bitstreams$ | async); let last=last;">
         <div class="col-3">
-            <ds-thumbnail [thumbnail]="thumbnails.get(file.id) | async"></ds-thumbnail>
+            <ds-thumbnail [thumbnail]="(file.thumbnail | async)?.payload"></ds-thumbnail>
         </div>
         <div class="col-7">
             <dl class="row">
@@ -21,7 +21,7 @@
             </dl>
         </div>
         <div class="col-2">
-            <a [href]="file.content" [download]="file.name">
+            <a [href]="file._links.content.href" [download]="file.name">
                 {{"item.page.filesection.download" | translate}}
             </a>
         </div>
diff --git a/src/app/+item-page/full/field-components/file-section/full-file-section.component.ts b/src/app/+item-page/full/field-components/file-section/full-file-section.component.ts
index 23d9ef05d0d6068c34e27b285f27ad8790a448d1..f18fccd7e9e838657d73bd448f548e3d36439a3d 100644
--- a/src/app/+item-page/full/field-components/file-section/full-file-section.component.ts
+++ b/src/app/+item-page/full/field-components/file-section/full-file-section.component.ts
@@ -1,10 +1,13 @@
+import { Component, Injector, Input, OnInit } from '@angular/core';
 import { combineLatest as observableCombineLatest, Observable } from 'rxjs';
-import { Component, Input, OnInit } from '@angular/core';
+import { map, startWith } from 'rxjs/operators';
+import { BitstreamDataService } from '../../../../core/data/bitstream-data.service';
 
 import { Bitstream } from '../../../../core/shared/bitstream.model';
 import { Item } from '../../../../core/shared/item.model';
+import { getFirstSucceededRemoteListPayload } from '../../../../core/shared/operators';
+import { followLink } from '../../../../shared/utils/follow-link-config.model';
 import { FileSectionComponent } from '../../../simple/field-components/file-section/file-section.component';
-import { map } from 'rxjs/operators';
 
 /**
  * This component renders the file section of the item
@@ -22,27 +25,49 @@ export class FullFileSectionComponent extends FileSectionComponent implements On
 
   label: string;
 
-  bitstreamsObs: Observable<Bitstream[]>;
+  bitstreams$: Observable<Bitstream[]>;
 
-  thumbnails: Map<string, Observable<Bitstream>> = new Map();
+  constructor(
+    bitstreamDataService: BitstreamDataService
+  ) {
+    super(bitstreamDataService);
+  }
 
   ngOnInit(): void {
     super.ngOnInit();
   }
 
   initialize(): void {
-    const originals = this.item.getFiles();
-    const licenses = this.item.getBitstreamsByBundleName('LICENSE');
-    this.bitstreamsObs = observableCombineLatest(originals, licenses).pipe(map(([o, l]) => [...o, ...l]));
-    this.bitstreamsObs.subscribe(
-      (files) =>
-        files.forEach(
+    // TODO pagination
+    const originals$ = this.bitstreamDataService.findAllByItemAndBundleName(
+      this.item,
+      'ORIGINAL',
+      { elementsPerPage: Number.MAX_SAFE_INTEGER },
+      followLink( 'format')
+    ).pipe(
+      getFirstSucceededRemoteListPayload(),
+      startWith([])
+    );
+    const licenses$ = this.bitstreamDataService.findAllByItemAndBundleName(
+      this.item,
+      'LICENSE',
+      { elementsPerPage: Number.MAX_SAFE_INTEGER },
+      followLink( 'format')
+    ).pipe(
+      getFirstSucceededRemoteListPayload(),
+      startWith([])
+    );
+    this.bitstreams$ = observableCombineLatest(originals$, licenses$).pipe(
+      map(([o, l]) => [...o, ...l]),
+      map((files: Bitstream[]) =>
+        files.map(
           (original) => {
-            const thumbnail: Observable<Bitstream> = this.item.getThumbnailForOriginal(original);
-            this.thumbnails.set(original.id, thumbnail);
+            original.thumbnail = this.bitstreamDataService.getMatchingThumbnail(this.item, original);
+            return original;
           }
         )
-    )
+      )
+    );
   }
 
 }
diff --git a/src/app/+item-page/item-page-routing.module.ts b/src/app/+item-page/item-page-routing.module.ts
index b95459674f95e06079486c2b8d405f4e1017d9e6..0dc3262d3487fc9f2fda0b1df79a32f2c20e0b9d 100644
--- a/src/app/+item-page/item-page-routing.module.ts
+++ b/src/app/+item-page/item-page-routing.module.ts
@@ -7,54 +7,62 @@ import { ItemPageResolver } from './item-page.resolver';
 import { URLCombiner } from '../core/url-combiner/url-combiner';
 import { getItemModulePath } from '../app-routing.module';
 import { AuthenticatedGuard } from '../core/auth/authenticated.guard';
+import { ItemBreadcrumbResolver } from '../core/breadcrumbs/item-breadcrumb.resolver';
+import { DSOBreadcrumbsService } from '../core/breadcrumbs/dso-breadcrumbs.service';
+import { LinkService } from '../core/cache/builders/link.service';
 import { UploadBitstreamComponent } from './bitstreams/upload/upload-bitstream.component';
 
 export function getItemPageRoute(itemId: string) {
   return new URLCombiner(getItemModulePath(), itemId).toString();
 }
+
 export function getItemEditPath(id: string) {
-  return new URLCombiner(getItemModulePath(),ITEM_EDIT_PATH.replace(/:id/, id)).toString()
+  return new URLCombiner(getItemModulePath(), id, ITEM_EDIT_PATH).toString()
 }
 
-const ITEM_EDIT_PATH = ':id/edit';
-const UPLOAD_BITSTREAM_PATH = ':id/bitstreams/new';
+const ITEM_EDIT_PATH = 'edit';
+const UPLOAD_BITSTREAM_PATH = 'bitstreams/new';
 
 @NgModule({
   imports: [
     RouterModule.forChild([
       {
         path: ':id',
-        component: ItemPageComponent,
-        pathMatch: 'full',
-        resolve: {
-          item: ItemPageResolver
-        }
-      },
-      {
-        path: ':id/full',
-        component: FullItemPageComponent,
         resolve: {
-          item: ItemPageResolver
-        }
-      },
-      {
-        path: ITEM_EDIT_PATH,
-        loadChildren: './edit-item-page/edit-item-page.module#EditItemPageModule',
-        canActivate: [AuthenticatedGuard]
-      },
-      {
-        path: UPLOAD_BITSTREAM_PATH,
-        component: UploadBitstreamComponent,
-        resolve: {
-          item: ItemPageResolver
+          item: ItemPageResolver,
+          breadcrumb: ItemBreadcrumbResolver
         },
-        canActivate: [AuthenticatedGuard]
+        children: [
+          {
+            path: '',
+            component: ItemPageComponent,
+            pathMatch: 'full',
+          },
+          {
+            path: 'full',
+            component: FullItemPageComponent,
+          },
+          {
+            path: ITEM_EDIT_PATH,
+            loadChildren: './edit-item-page/edit-item-page.module#EditItemPageModule',
+            canActivate: [AuthenticatedGuard]
+          },
+          {
+            path: UPLOAD_BITSTREAM_PATH,
+            component: UploadBitstreamComponent,
+            canActivate: [AuthenticatedGuard]
+          }
+        ],
       }
     ])
   ],
   providers: [
     ItemPageResolver,
+    ItemBreadcrumbResolver,
+    DSOBreadcrumbsService,
+    LinkService
   ]
+
 })
 export class ItemPageRoutingModule {
 
diff --git a/src/app/+item-page/item-page.resolver.ts b/src/app/+item-page/item-page.resolver.ts
index 4b7ef23b6991ee171095714dc49f4f1247ef17c0..0f73dc61705ad7ab3827af201c236f0cbb416e0e 100644
--- a/src/app/+item-page/item-page.resolver.ts
+++ b/src/app/+item-page/item-page.resolver.ts
@@ -6,6 +6,7 @@ import { ItemDataService } from '../core/data/item-data.service';
 import { Item } from '../core/shared/item.model';
 import { hasValue } from '../shared/empty.util';
 import { find } from 'rxjs/operators';
+import { followLink } from '../shared/utils/follow-link-config.model';
 
 /**
  * This class represents a resolver that requests a specific item before the route is activated
@@ -23,9 +24,12 @@ export class ItemPageResolver implements Resolve<RemoteData<Item>> {
    * or an error if something went wrong
    */
   resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<RemoteData<Item>> {
-    return this.itemService.findById(route.params.id)
-      .pipe(
-        find((RD) => hasValue(RD.error) || RD.hasSucceeded),
-      );
+    return this.itemService.findById(route.params.id,
+      followLink('owningCollection'),
+      followLink('bundles'),
+      followLink('relationships'),
+    ).pipe(
+      find((RD) => hasValue(RD.error) || RD.hasSucceeded),
+    );
   }
 }
diff --git a/src/app/+item-page/simple/field-components/file-section/file-section.component.html b/src/app/+item-page/simple/field-components/file-section/file-section.component.html
index 7063bac0befea1c7969cf6e41ca223ebcec145ac..6533322e036b226e76abee7e5ee7d91a0b3287cb 100644
--- a/src/app/+item-page/simple/field-components/file-section/file-section.component.html
+++ b/src/app/+item-page/simple/field-components/file-section/file-section.component.html
@@ -1,7 +1,7 @@
-<ng-container *ngVar="(bitstreamsObs | async) as bitstreams">
+<ng-container *ngVar="(bitstreams$ | async) as bitstreams">
   <ds-metadata-field-wrapper *ngIf="bitstreams?.length > 0" [label]="label | translate">
     <div class="file-section">
-      <a *ngFor="let file of bitstreams; let last=last;" [href]="file?.content" [download]="file?.name">
+      <a *ngFor="let file of bitstreams; let last=last;" [href]="file?._links.content.href" [download]="file?.name">
         <span>{{file?.name}}</span>
         <span>({{(file?.sizeBytes) | dsFileSize }})</span>
         <span *ngIf="!last" innerHTML="{{separator}}"></span>
diff --git a/src/app/+item-page/simple/field-components/file-section/file-section.component.ts b/src/app/+item-page/simple/field-components/file-section/file-section.component.ts
index 8c40d123bff65a01bf432f4d042a4513a5159369..2e09c1cd49793b95326c44a416c484461d697075 100644
--- a/src/app/+item-page/simple/field-components/file-section/file-section.component.ts
+++ b/src/app/+item-page/simple/field-components/file-section/file-section.component.ts
@@ -1,8 +1,10 @@
 import { Component, Input, OnInit } from '@angular/core';
 import { Observable } from 'rxjs';
+import { BitstreamDataService } from '../../../../core/data/bitstream-data.service';
 
 import { Bitstream } from '../../../../core/shared/bitstream.model';
 import { Item } from '../../../../core/shared/item.model';
+import { getFirstSucceededRemoteListPayload } from '../../../../core/shared/operators';
 
 /**
  * This component renders the file section of the item
@@ -20,14 +22,21 @@ export class FileSectionComponent implements OnInit {
 
   separator = '<br/>';
 
-  bitstreamsObs: Observable<Bitstream[]>;
+  bitstreams$: Observable<Bitstream[]>;
+
+  constructor(
+    protected bitstreamDataService: BitstreamDataService
+  ) {
+  }
 
   ngOnInit(): void {
     this.initialize();
   }
 
   initialize(): void {
-    this.bitstreamsObs = this.item.getFiles();
+    this.bitstreams$ = this.bitstreamDataService.findAllByItemAndBundleName(this.item, 'ORIGINAL').pipe(
+      getFirstSucceededRemoteListPayload()
+    );
   }
 
 }
diff --git a/src/app/+item-page/simple/item-types/publication/publication.component.html b/src/app/+item-page/simple/item-types/publication/publication.component.html
index c45e85668a45e31e6aa1fd7d85e2af21288654b7..9eb704b9e964824f4db951fafe201bdf91269a0e 100644
--- a/src/app/+item-page/simple/item-types/publication/publication.component.html
+++ b/src/app/+item-page/simple/item-types/publication/publication.component.html
@@ -4,7 +4,7 @@
 <div class="row">
   <div class="col-xs-12 col-md-4">
     <ds-metadata-field-wrapper>
-      <ds-thumbnail [thumbnail]="object.getThumbnail() | async"></ds-thumbnail>
+      <ds-thumbnail [thumbnail]="getThumbnail() | async"></ds-thumbnail>
     </ds-metadata-field-wrapper>
     <ds-item-page-file-section [item]="object"></ds-item-page-file-section>
     <ds-item-page-date-field [item]="object"></ds-item-page-date-field>
diff --git a/src/app/+item-page/simple/item-types/publication/publication.component.spec.ts b/src/app/+item-page/simple/item-types/publication/publication.component.spec.ts
index 9f2eb32d9979aa59e5024df109c0e9c2d185f8b5..c1aef2739f59048a3877ea02953bdfc89090780d 100644
--- a/src/app/+item-page/simple/item-types/publication/publication.component.spec.ts
+++ b/src/app/+item-page/simple/item-types/publication/publication.component.spec.ts
@@ -1,20 +1,34 @@
+import { HttpClient } from '@angular/common/http';
+import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
 import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { By } from '@angular/platform-browser';
+import { Store } from '@ngrx/store';
 import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
-import { MockTranslateLoader } from '../../../../shared/mocks/mock-translate-loader';
-import { GenericItemPageFieldComponent } from '../../field-components/specific-field/generic/generic-item-page-field.component';
-import { TruncatePipe } from '../../../../shared/utils/truncate.pipe';
+import { Observable } from 'rxjs/internal/Observable';
+import { RemoteDataBuildService } from '../../../../core/cache/builders/remote-data-build.service';
+import { ObjectCacheService } from '../../../../core/cache/object-cache.service';
+import { BitstreamDataService } from '../../../../core/data/bitstream-data.service';
+import { CommunityDataService } from '../../../../core/data/community-data.service';
+import { DefaultChangeAnalyzer } from '../../../../core/data/default-change-analyzer.service';
+import { DSOChangeAnalyzer } from '../../../../core/data/dso-change-analyzer.service';
 import { ItemDataService } from '../../../../core/data/item-data.service';
-import { TruncatableService } from '../../../../shared/truncatable/truncatable.service';
-import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
-import { Item } from '../../../../core/shared/item.model';
 import { PaginatedList } from '../../../../core/data/paginated-list';
+import { RelationshipService } from '../../../../core/data/relationship.service';
+import { RemoteData } from '../../../../core/data/remote-data';
+import { Bitstream } from '../../../../core/shared/bitstream.model';
+import { HALEndpointService } from '../../../../core/shared/hal-endpoint.service';
+import { Item } from '../../../../core/shared/item.model';
+import { MetadataMap } from '../../../../core/shared/metadata.models';
 import { PageInfo } from '../../../../core/shared/page-info.model';
-import { By } from '@angular/platform-browser';
+import { UUIDService } from '../../../../core/shared/uuid.service';
+import { MockTranslateLoader } from '../../../../shared/mocks/mock-translate-loader';
+import { NotificationsService } from '../../../../shared/notifications/notifications.service';
+import { createSuccessfulRemoteDataObject$ } from '../../../../shared/testing/utils';
+import { TruncatableService } from '../../../../shared/truncatable/truncatable.service';
+import { TruncatePipe } from '../../../../shared/utils/truncate.pipe';
+import { GenericItemPageFieldComponent } from '../../field-components/specific-field/generic/generic-item-page-field.component';
 import { createRelationshipsObservable } from '../shared/item.component.spec';
 import { PublicationComponent } from './publication.component';
-import { MetadataMap } from '../../../../core/shared/metadata.models';
-import { createSuccessfulRemoteDataObject$ } from '../../../../shared/testing/utils';
-import { RelationshipService } from '../../../../core/data/relationship.service';
 
 const mockItem: Item = Object.assign(new Item(), {
   bundles: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
@@ -27,6 +41,11 @@ describe('PublicationComponent', () => {
   let fixture: ComponentFixture<PublicationComponent>;
 
   beforeEach(async(() => {
+    const mockBitstreamDataService = {
+      getThumbnailFor(item: Item): Observable<RemoteData<Bitstream>> {
+        return createSuccessfulRemoteDataObject$(new Bitstream());
+      }
+    };
     TestBed.configureTestingModule({
       imports: [TranslateModule.forRoot({
         loader: {
@@ -36,14 +55,25 @@ describe('PublicationComponent', () => {
       })],
       declarations: [PublicationComponent, GenericItemPageFieldComponent, TruncatePipe],
       providers: [
-        {provide: ItemDataService, useValue: {}},
-        {provide: TruncatableService, useValue: {}},
-        {provide: RelationshipService, useValue: {}}
+        { provide: ItemDataService, useValue: {} },
+        { provide: TruncatableService, useValue: {} },
+        { provide: RelationshipService, useValue: {} },
+        { provide: ObjectCacheService, useValue: {} },
+        { provide: UUIDService, useValue: {} },
+        { provide: Store, useValue: {} },
+        { provide: RemoteDataBuildService, useValue: {} },
+        { provide: CommunityDataService, useValue: {} },
+        { provide: HALEndpointService, useValue: {} },
+        { provide: NotificationsService, useValue: {} },
+        { provide: HttpClient, useValue: {} },
+        { provide: DSOChangeAnalyzer, useValue: {} },
+        { provide: DefaultChangeAnalyzer, useValue: {} },
+        { provide: BitstreamDataService, useValue: mockBitstreamDataService },
       ],
 
       schemas: [NO_ERRORS_SCHEMA]
     }).overrideComponent(PublicationComponent, {
-      set: {changeDetection: ChangeDetectionStrategy.Default}
+      set: { changeDetection: ChangeDetectionStrategy.Default }
     }).compileComponents();
   }));
 
diff --git a/src/app/+item-page/simple/item-types/publication/publication.component.ts b/src/app/+item-page/simple/item-types/publication/publication.component.ts
index d926e1efdb144da6f929d92ac507899c7694c4a0..f01d0f72d3dcee7f906d4a7af68b42d08c82bd7d 100644
--- a/src/app/+item-page/simple/item-types/publication/publication.component.ts
+++ b/src/app/+item-page/simple/item-types/publication/publication.component.ts
@@ -17,4 +17,5 @@ import { listableObjectComponent } from '../../../../shared/object-collection/sh
   changeDetection: ChangeDetectionStrategy.OnPush,
 })
 export class PublicationComponent extends ItemComponent {
+
 }
diff --git a/src/app/+item-page/simple/item-types/shared/item-relationships-utils.ts b/src/app/+item-page/simple/item-types/shared/item-relationships-utils.ts
index 7baf260c61015e34c9b44e8ad8e34d684a218f85..73e02ca29df52543bd84c46cfdcb4b15b5164a45 100644
--- a/src/app/+item-page/simple/item-types/shared/item-relationships-utils.ts
+++ b/src/app/+item-page/simple/item-types/shared/item-relationships-utils.ts
@@ -1,12 +1,12 @@
-import { getSucceededRemoteData } from '../../../../core/shared/operators';
-import { hasValue } from '../../../../shared/empty.util';
+import { combineLatest as observableCombineLatest, zip as observableZip } from 'rxjs';
 import { Observable } from 'rxjs/internal/Observable';
-import { Relationship } from '../../../../core/shared/item-relationships/relationship.model';
 import { distinctUntilChanged, flatMap, map, switchMap } from 'rxjs/operators';
-import { combineLatest as observableCombineLatest, zip as observableZip } from 'rxjs';
-import { Item } from '../../../../core/shared/item.model';
 import { PaginatedList } from '../../../../core/data/paginated-list';
 import { RemoteData } from '../../../../core/data/remote-data';
+import { Relationship } from '../../../../core/shared/item-relationships/relationship.model';
+import { Item } from '../../../../core/shared/item.model';
+import { getFinishedRemoteData, getSucceededRemoteData } from '../../../../core/shared/operators';
+import { hasValue } from '../../../../shared/empty.util';
 
 /**
  * Operator for comparing arrays using a mapping function
@@ -74,8 +74,8 @@ export const paginatedRelationsToItems = (thisId: string) =>
     source.pipe(
       getSucceededRemoteData(),
       switchMap((relationshipsRD: RemoteData<PaginatedList<Relationship>>) => {
-        return observableZip(
-          ...relationshipsRD.payload.page.map((rel: Relationship) => observableCombineLatest(rel.leftItem, rel.rightItem))
+        return observableCombineLatest(
+          ...relationshipsRD.payload.page.map((rel: Relationship) => observableCombineLatest(rel.leftItem.pipe(getFinishedRemoteData()), rel.rightItem.pipe(getFinishedRemoteData())))
         ).pipe(
           map((arr) =>
             arr
diff --git a/src/app/+item-page/simple/item-types/shared/item.component.spec.ts b/src/app/+item-page/simple/item-types/shared/item.component.spec.ts
index 5a9f1c509dbb5709b946f3eed5c9975584a1bfbf..24a2f028a5cedef16b614d8d7e118bee54b72894 100644
--- a/src/app/+item-page/simple/item-types/shared/item.component.spec.ts
+++ b/src/app/+item-page/simple/item-types/shared/item.component.spec.ts
@@ -1,29 +1,36 @@
-import { Item } from '../../../../core/shared/item.model';
+import { HttpClient } from '@angular/common/http';
+import { ChangeDetectionStrategy, DebugElement, NO_ERRORS_SCHEMA } from '@angular/core';
 import { async, ComponentFixture, TestBed } from '@angular/core/testing';
 import { By } from '@angular/platform-browser';
-import { GenericItemPageFieldComponent } from '../../field-components/specific-field/generic/generic-item-page-field.component';
-import { TruncatableService } from '../../../../shared/truncatable/truncatable.service';
-import { ItemDataService } from '../../../../core/data/item-data.service';
+import { Store } from '@ngrx/store';
 import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
-import { MockTranslateLoader } from '../../../../shared/mocks/mock-translate-loader';
-import { ChangeDetectionStrategy, DebugElement, NO_ERRORS_SCHEMA } from '@angular/core';
-import { TruncatePipe } from '../../../../shared/utils/truncate.pipe';
-import { isNotEmpty } from '../../../../shared/empty.util';
-import { RelationshipType } from '../../../../core/shared/item-relationships/relationship-type.model';
+import { Observable } from 'rxjs/internal/Observable';
+import { RemoteDataBuildService } from '../../../../core/cache/builders/remote-data-build.service';
+import { ObjectCacheService } from '../../../../core/cache/object-cache.service';
+import { BitstreamDataService } from '../../../../core/data/bitstream-data.service';
+import { CommunityDataService } from '../../../../core/data/community-data.service';
+import { DefaultChangeAnalyzer } from '../../../../core/data/default-change-analyzer.service';
+import { DSOChangeAnalyzer } from '../../../../core/data/dso-change-analyzer.service';
+import { ItemDataService } from '../../../../core/data/item-data.service';
 import { PaginatedList } from '../../../../core/data/paginated-list';
+import { RelationshipService } from '../../../../core/data/relationship.service';
+import { RemoteData } from '../../../../core/data/remote-data';
+import { Bitstream } from '../../../../core/shared/bitstream.model';
+import { HALEndpointService } from '../../../../core/shared/hal-endpoint.service';
+import { RelationshipType } from '../../../../core/shared/item-relationships/relationship-type.model';
 import { Relationship } from '../../../../core/shared/item-relationships/relationship.model';
+import { Item } from '../../../../core/shared/item.model';
 import { PageInfo } from '../../../../core/shared/page-info.model';
-import { ItemComponent } from './item.component';
-import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
-import { VarDirective } from '../../../../shared/utils/var.directive';
-import { Observable } from 'rxjs/internal/Observable';
-import { MetadataRepresentation } from '../../../../core/shared/metadata-representation/metadata-representation.model';
-import { MetadatumRepresentation } from '../../../../core/shared/metadata-representation/metadatum/metadatum-representation.model';
-import { ItemMetadataRepresentation } from '../../../../core/shared/metadata-representation/item/item-metadata-representation.model';
-import { MetadataMap, MetadataValue } from '../../../../core/shared/metadata.models';
-import { compareArraysUsing, compareArraysUsingIds } from './item-relationships-utils';
+import { UUIDService } from '../../../../core/shared/uuid.service';
+import { isNotEmpty } from '../../../../shared/empty.util';
+import { MockTranslateLoader } from '../../../../shared/mocks/mock-translate-loader';
+import { NotificationsService } from '../../../../shared/notifications/notifications.service';
 import { createSuccessfulRemoteDataObject$ } from '../../../../shared/testing/utils';
-import { RelationshipService } from '../../../../core/data/relationship.service';
+import { TruncatableService } from '../../../../shared/truncatable/truncatable.service';
+import { TruncatePipe } from '../../../../shared/utils/truncate.pipe';
+import { GenericItemPageFieldComponent } from '../../field-components/specific-field/generic/generic-item-page-field.component';
+import { compareArraysUsing, compareArraysUsingIds } from './item-relationships-utils';
+import { ItemComponent } from './item.component';
 
 /**
  * Create a generic test for an item-page-fields component using a mockItem and the type of component
@@ -38,6 +45,11 @@ export function getItemPageFieldsTest(mockItem: Item, component) {
     let fixture: ComponentFixture<any>;
 
     beforeEach(async(() => {
+      const mockBitstreamDataService = {
+        getThumbnailFor(item: Item): Observable<RemoteData<Bitstream>> {
+          return createSuccessfulRemoteDataObject$(new Bitstream());
+        }
+      };
       TestBed.configureTestingModule({
         imports: [TranslateModule.forRoot({
           loader: {
@@ -47,14 +59,25 @@ export function getItemPageFieldsTest(mockItem: Item, component) {
         })],
         declarations: [component, GenericItemPageFieldComponent, TruncatePipe],
         providers: [
-          {provide: ItemDataService, useValue: {}},
-          {provide: TruncatableService, useValue: {}},
-          {provide: RelationshipService, useValue: {}}
+          { provide: ItemDataService, useValue: {} },
+          { provide: TruncatableService, useValue: {} },
+          { provide: RelationshipService, useValue: {} },
+          { provide: ObjectCacheService, useValue: {} },
+          { provide: UUIDService, useValue: {} },
+          { provide: Store, useValue: {} },
+          { provide: RemoteDataBuildService, useValue: {} },
+          { provide: CommunityDataService, useValue: {} },
+          { provide: HALEndpointService, useValue: {} },
+          { provide: HttpClient, useValue: {} },
+          { provide: DSOChangeAnalyzer, useValue: {} },
+          { provide: NotificationsService, useValue: {} },
+          { provide: DefaultChangeAnalyzer, useValue: {} },
+          { provide: BitstreamDataService, useValue: mockBitstreamDataService },
         ],
 
         schemas: [NO_ERRORS_SCHEMA]
       }).overrideComponent(component, {
-        set: {changeDetection: ChangeDetectionStrategy.Default}
+        set: { changeDetection: ChangeDetectionStrategy.Default }
       }).compileComponents();
     }));
 
@@ -102,6 +125,7 @@ export function createRelationshipsObservable() {
     })
   ]));
 }
+
 describe('ItemComponent', () => {
   const arr1 = [
     {
diff --git a/src/app/+item-page/simple/item-types/shared/item.component.ts b/src/app/+item-page/simple/item-types/shared/item.component.ts
index 64a96fdd5253490a07d258523876ff584bd5c753..abfcd243469554aa507615dd6458aa5f0b0a521e 100644
--- a/src/app/+item-page/simple/item-types/shared/item.component.ts
+++ b/src/app/+item-page/simple/item-types/shared/item.component.ts
@@ -1,5 +1,9 @@
 import { Component, Input } from '@angular/core';
+import { Observable } from 'rxjs/internal/Observable';
+import { BitstreamDataService } from '../../../../core/data/bitstream-data.service';
+import { Bitstream } from '../../../../core/shared/bitstream.model';
 import { Item } from '../../../../core/shared/item.model';
+import { getFirstSucceededRemoteDataPayload } from '../../../../core/shared/operators';
 
 @Component({
   selector: 'ds-item',
@@ -10,4 +14,14 @@ import { Item } from '../../../../core/shared/item.model';
  */
 export class ItemComponent {
   @Input() object: Item;
+
+  constructor(protected bitstreamDataService: BitstreamDataService) {
+  }
+
+  // TODO refactor to return RemoteData, and thumbnail template to deal with loading
+  getThumbnail(): Observable<Bitstream> {
+    return this.bitstreamDataService.getThumbnailFor(this.object).pipe(
+      getFirstSucceededRemoteDataPayload()
+    );
+  }
 }
diff --git a/src/app/+item-page/simple/metadata-representation-list/metadata-representation-list.component.ts b/src/app/+item-page/simple/metadata-representation-list/metadata-representation-list.component.ts
index 23484f22e06a73d5e7f45da07ea85b0d3eb04406..fc696482d0e74316859d9c0d6a604a440cd8cfa7 100644
--- a/src/app/+item-page/simple/metadata-representation-list/metadata-representation-list.component.ts
+++ b/src/app/+item-page/simple/metadata-representation-list/metadata-representation-list.component.ts
@@ -10,6 +10,7 @@ import { Relationship } from '../../../core/shared/item-relationships/relationsh
 import { Item } from '../../../core/shared/item.model';
 import { MetadatumRepresentation } from '../../../core/shared/metadata-representation/metadatum/metadatum-representation.model';
 import { ItemMetadataRepresentation } from '../../../core/shared/metadata-representation/item/item-metadata-representation.model';
+import { followLink } from '../../../shared/utils/follow-link-config.model';
 import { AbstractIncrementalListComponent } from '../abstract-incremental-list/abstract-incremental-list.component';
 
 @Component({
@@ -81,7 +82,7 @@ export class MetadataRepresentationListComponent extends AbstractIncrementalList
         .map((metadatum: any) => Object.assign(new MetadataValue(), metadatum))
         .map((metadatum: MetadataValue) => {
           if (metadatum.isVirtual) {
-            return this.relationshipService.findById(metadatum.virtualValue).pipe(
+            return this.relationshipService.findById(metadatum.virtualValue, followLink('leftItem'), followLink('rightItem')).pipe(
               getSucceededRemoteData(),
               switchMap((relRD: RemoteData<Relationship>) =>
                 observableCombineLatest(relRD.payload.leftItem, relRD.payload.rightItem).pipe(
diff --git a/src/app/+item-page/simple/related-entities/tabbed-related-entities-search/tabbed-related-entities-search.component.spec.ts b/src/app/+item-page/simple/related-entities/tabbed-related-entities-search/tabbed-related-entities-search.component.spec.ts
index 2d2e682196d0ef2ee12c44f43bf510d1bf622f3b..be4e1c1e2471482314e354f0fa492c9ed6d0477f 100644
--- a/src/app/+item-page/simple/related-entities/tabbed-related-entities-search/tabbed-related-entities-search.component.spec.ts
+++ b/src/app/+item-page/simple/related-entities/tabbed-related-entities-search/tabbed-related-entities-search.component.spec.ts
@@ -29,7 +29,7 @@ describe('TabbedRelatedEntitiesSearchComponent', () => {
 
   beforeEach(async(() => {
     TestBed.configureTestingModule({
-      imports: [TranslateModule.forRoot(), NoopAnimationsModule, NgbModule.forRoot()],
+      imports: [TranslateModule.forRoot(), NoopAnimationsModule, NgbModule],
       declarations: [TabbedRelatedEntitiesSearchComponent, VarDirective],
       providers: [
         {
diff --git a/src/app/+login-page/login-page-routing.module.ts b/src/app/+login-page/login-page-routing.module.ts
index d3c6425dd38ef4dbca569e0fb4f702347c7c75f1..cd023da55c2c7fb6210bba264838bc8ed8f9ea7f 100644
--- a/src/app/+login-page/login-page-routing.module.ts
+++ b/src/app/+login-page/login-page-routing.module.ts
@@ -2,12 +2,14 @@ import { NgModule } from '@angular/core';
 import { RouterModule } from '@angular/router';
 
 import { LoginPageComponent } from './login-page.component';
+import { I18nBreadcrumbResolver } from '../core/breadcrumbs/i18n-breadcrumb.resolver';
 
 @NgModule({
   imports: [
     RouterModule.forChild([
-      { path: '', pathMatch: 'full',  component: LoginPageComponent, data: { title: 'login.title' } }
+      { path: '', pathMatch: 'full', component: LoginPageComponent, resolve: { breadcrumb: I18nBreadcrumbResolver }, data: { breadcrumbKey: 'login', title: 'login.title' } }
     ])
   ]
 })
-export class LoginPageRoutingModule { }
+export class LoginPageRoutingModule {
+}
diff --git a/src/app/+lookup-by-id/lookup-guard.spec.ts b/src/app/+lookup-by-id/lookup-guard.spec.ts
index dce039eff3fdf775d3f7f52e36ee78ebb34f9855..dec5b57afe692353241adc44267003c74cb180a6 100644
--- a/src/app/+lookup-by-id/lookup-guard.spec.ts
+++ b/src/app/+lookup-by-id/lookup-guard.spec.ts
@@ -1,6 +1,6 @@
-import { LookupGuard } from './lookup-guard';
 import { of as observableOf } from 'rxjs';
 import { IdentifierType } from '../core/data/request.models';
+import { LookupGuard } from './lookup-guard';
 
 describe('LookupGuard', () => {
   let dsoService: any;
@@ -8,13 +8,13 @@ describe('LookupGuard', () => {
 
   beforeEach(() => {
     dsoService = {
-      findById: jasmine.createSpy('findById').and.returnValue(observableOf({ hasFailed: false,
+      findByIdAndIDType: jasmine.createSpy('findByIdAndIDType').and.returnValue(observableOf({ hasFailed: false,
         hasSucceeded: true }))
     };
     guard = new LookupGuard(dsoService);
   });
 
-  it('should call findById with handle params', () => {
+  it('should call findByIdAndIDType with handle params', () => {
     const scopedRoute = {
       params: {
         id: '1234',
@@ -22,10 +22,10 @@ describe('LookupGuard', () => {
       }
     };
     guard.canActivate(scopedRoute as any, undefined);
-    expect(dsoService.findById).toHaveBeenCalledWith('123456789/1234', IdentifierType.HANDLE)
+    expect(dsoService.findByIdAndIDType).toHaveBeenCalledWith('123456789/1234', IdentifierType.HANDLE)
   });
 
-  it('should call findById with handle params', () => {
+  it('should call findByIdAndIDType with handle params', () => {
     const scopedRoute = {
       params: {
         id: '123456789%2F1234',
@@ -33,10 +33,10 @@ describe('LookupGuard', () => {
       }
     };
     guard.canActivate(scopedRoute as any, undefined);
-    expect(dsoService.findById).toHaveBeenCalledWith('123456789%2F1234', IdentifierType.HANDLE)
+    expect(dsoService.findByIdAndIDType).toHaveBeenCalledWith('123456789%2F1234', IdentifierType.HANDLE)
   });
 
-  it('should call findById with UUID params', () => {
+  it('should call findByIdAndIDType with UUID params', () => {
     const scopedRoute = {
       params: {
         id: '34cfed7c-f597-49ef-9cbe-ea351f0023c2',
@@ -44,7 +44,7 @@ describe('LookupGuard', () => {
       }
     };
     guard.canActivate(scopedRoute as any, undefined);
-    expect(dsoService.findById).toHaveBeenCalledWith('34cfed7c-f597-49ef-9cbe-ea351f0023c2', IdentifierType.UUID)
+    expect(dsoService.findByIdAndIDType).toHaveBeenCalledWith('34cfed7c-f597-49ef-9cbe-ea351f0023c2', IdentifierType.UUID)
   });
 
 });
diff --git a/src/app/+lookup-by-id/lookup-guard.ts b/src/app/+lookup-by-id/lookup-guard.ts
index a7ddffcd4e4505d81ad4b85dfae621bec8302f1c..800332422cf68d743a786bd69defb09d702aad21 100644
--- a/src/app/+lookup-by-id/lookup-guard.ts
+++ b/src/app/+lookup-by-id/lookup-guard.ts
@@ -20,7 +20,7 @@ export class LookupGuard implements CanActivate {
 
   canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean>  {
     const params = this.getLookupParams(route);
-    return this.dsoService.findById(params.id, params.type).pipe(
+    return this.dsoService.findByIdAndIDType(params.id, params.type).pipe(
       map((response: RemoteData<FindByIDRequest>) => response.hasFailed)
     );
   }
diff --git a/src/app/+my-dspace-page/my-dspace-page.component.html b/src/app/+my-dspace-page/my-dspace-page.component.html
index e6d1a5c80dd97edad70f489cd3fa318c1880c122..21ef4e9de7a1028b5049c5003807e3205f36d168 100644
--- a/src/app/+my-dspace-page/my-dspace-page.component.html
+++ b/src/app/+my-dspace-page/my-dspace-page.component.html
@@ -19,7 +19,7 @@
           <ds-search-labels [inPlaceSearch]="inPlaceSearch"></ds-search-labels>
           <div class="row">
               <div id="search-body"
-                   class="row-offcanvas row-offcanvas-left"
+                   class="row-offcanvas row-offcanvas-left w-100"
                    [@pushInOut]="(isSidebarCollapsed() | async) ? 'collapsed' : 'expanded'">
                   <ds-search-sidebar *ngIf="(isXsOrSm$ | async)" class="col-12"
                                      id="search-sidebar-sm"
diff --git a/src/app/+my-dspace-page/my-dspace-page.component.spec.ts b/src/app/+my-dspace-page/my-dspace-page.component.spec.ts
index 9970b4b8b2b6a19c7ab09dd681fc7b7228912fed..b598258805c3df75911e9b7573f26e5ca3a57c05 100644
--- a/src/app/+my-dspace-page/my-dspace-page.component.spec.ts
+++ b/src/app/+my-dspace-page/my-dspace-page.component.spec.ts
@@ -84,7 +84,7 @@ describe('MyDSpacePageComponent', () => {
 
   beforeEach(async(() => {
     TestBed.configureTestingModule({
-      imports: [TranslateModule.forRoot(), RouterTestingModule.withRoutes([]), NoopAnimationsModule, NgbCollapseModule.forRoot()],
+      imports: [TranslateModule.forRoot(), RouterTestingModule.withRoutes([]), NoopAnimationsModule, NgbCollapseModule],
       declarations: [MyDSpacePageComponent, RoleDirective],
       providers: [
         { provide: SearchService, useValue: searchServiceStub },
diff --git a/src/app/+search-page/search-page-routing.module.ts b/src/app/+search-page/search-page-routing.module.ts
index 315e15a593b4ddaa277fb20d8e213834860d6b3e..6e3688339429a90bcdafc767fa8c243cbddfa10f 100644
--- a/src/app/+search-page/search-page-routing.module.ts
+++ b/src/app/+search-page/search-page-routing.module.ts
@@ -4,13 +4,24 @@ import { RouterModule } from '@angular/router';
 import { ConfigurationSearchPageGuard } from './configuration-search-page.guard';
 import { ConfigurationSearchPageComponent } from './configuration-search-page.component';
 import { SearchPageComponent } from './search-page.component';
+import { I18nBreadcrumbResolver } from '../core/breadcrumbs/i18n-breadcrumb.resolver';
+import { I18nBreadcrumbsService } from '../core/breadcrumbs/i18n-breadcrumbs.service';
 
 @NgModule({
   imports: [
-    RouterModule.forChild([
-      { path: '', component: SearchPageComponent, data: { title: 'search.title' } },
-      { path: ':configuration', component: ConfigurationSearchPageComponent, canActivate: [ConfigurationSearchPageGuard]}
-    ])
+    RouterModule.forChild([{
+        path: '',
+        resolve: { breadcrumb: I18nBreadcrumbResolver }, data: { title: 'search.title', breadcrumbKey: 'search' },
+        children: [
+          { path: '', component: SearchPageComponent },
+          { path: ':configuration', component: ConfigurationSearchPageComponent, canActivate: [ConfigurationSearchPageGuard] }
+        ]
+      }]
+    )
+  ],
+  providers: [
+    I18nBreadcrumbResolver,
+    I18nBreadcrumbsService
   ]
 })
 export class SearchPageRoutingModule {
diff --git a/src/app/+search-page/search.component.scss b/src/app/+search-page/search.component.scss
index 9c3da88be6a8a7aa1716100f941034c6d5d63441..44d4aabd1304b9f4a1b0ff7d5c7acf0830b6b694 100644
--- a/src/app/+search-page/search.component.scss
+++ b/src/app/+search-page/search.component.scss
@@ -5,6 +5,6 @@
   }
 }
 
-/deep/ .search-controls {
+::ng-deep .search-controls {
     margin-bottom: $spacer;
 }
diff --git a/src/app/+search-page/search.component.spec.ts b/src/app/+search-page/search.component.spec.ts
index 2fe4128ba0012034087c5fc8e93fd8db33a3330d..69d451f98bc278020bb3cb91ee1ccf4f90870af1 100644
--- a/src/app/+search-page/search.component.spec.ts
+++ b/src/app/+search-page/search.component.spec.ts
@@ -90,7 +90,7 @@ const routeServiceStub = {
 
 export function configureSearchComponentTestingModule(compType) {
   TestBed.configureTestingModule({
-    imports: [TranslateModule.forRoot(), RouterTestingModule.withRoutes([]), NoopAnimationsModule, NgbCollapseModule.forRoot()],
+    imports: [TranslateModule.forRoot(), RouterTestingModule.withRoutes([]), NoopAnimationsModule, NgbCollapseModule],
     declarations: [compType],
     providers: [
       { provide: SearchService, useValue: searchServiceStub },
diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts
index d6dbfb9345a3db0926920032e532602f30855d64..68dfd080bfb5673bcc886304957181a177dc3038 100644
--- a/src/app/app-routing.module.ts
+++ b/src/app/app-routing.module.ts
@@ -3,16 +3,30 @@ import { RouterModule } from '@angular/router';
 
 import { PageNotFoundComponent } from './pagenotfound/pagenotfound.component';
 import { AuthenticatedGuard } from './core/auth/authenticated.guard';
+import { Breadcrumb } from './breadcrumbs/breadcrumb/breadcrumb.model';
+import { DSpaceObject } from './core/shared/dspace-object.model';
+import { Community } from './core/shared/community.model';
+import { getCommunityPageRoute } from './+community-page/community-page-routing.module';
+import { Collection } from './core/shared/collection.model';
+import { Item } from './core/shared/item.model';
+import { getItemPageRoute } from './+item-page/item-page-routing.module';
+import { getCollectionPageRoute } from './+collection-page/collection-page-routing.module';
+import { BrowseByDSOBreadcrumbResolver } from './+browse-by/browse-by-dso-breadcrumb.resolver';
 
 const ITEM_MODULE_PATH = 'items';
+
 export function getItemModulePath() {
   return `/${ITEM_MODULE_PATH}`;
 }
+
 const COLLECTION_MODULE_PATH = 'collections';
+
 export function getCollectionModulePath() {
   return `/${COLLECTION_MODULE_PATH}`;
 }
+
 const COMMUNITY_MODULE_PATH = 'communities';
+
 export function getCommunityModulePath() {
   return `/${COMMUNITY_MODULE_PATH}`;
 }
@@ -21,16 +35,28 @@ export function getBitstreamModulePath() {
   return `/${BITSTREAM_MODULE_PATH}`;
 }
 
-const  ADMIN_MODULE_PATH = 'admin';
+const ADMIN_MODULE_PATH = 'admin';
+
 export function getAdminModulePath() {
   return `/${ADMIN_MODULE_PATH}`;
 }
 
+export function getDSOPath(dso: DSpaceObject): string {
+  switch ((dso as any).type) {
+    case Community.type.value:
+      return getCommunityPageRoute(dso.uuid);
+    case Collection.type.value:
+      return getCollectionPageRoute(dso.uuid);
+    case Item.type.value:
+      return getItemPageRoute(dso.uuid);
+  }
+}
+
 @NgModule({
   imports: [
     RouterModule.forRoot([
       { path: '', redirectTo: '/home', pathMatch: 'full' },
-      { path: 'home', loadChildren: './+home-page/home-page.module#HomePageModule' },
+      { path: 'home', loadChildren: './+home-page/home-page.module#HomePageModule', data: { showBreadcrumbs: false } },
       { path: 'community-list', loadChildren: './community-list-page/community-list-page.module#CommunityListPageModule' },
       { path: 'id', loadChildren: './+lookup-by-id/lookup-by-id.module#LookupIdModule' },
       { path: 'handle', loadChildren: './+lookup-by-id/lookup-by-id.module#LookupIdModule' },
@@ -40,7 +66,7 @@ export function getAdminModulePath() {
       { path: BITSTREAM_MODULE_PATH, loadChildren: './+bitstream-page/bitstream-page.module#BitstreamPageModule' },
       { path: 'mydspace', loadChildren: './+my-dspace-page/my-dspace-page.module#MyDSpacePageModule', canActivate: [AuthenticatedGuard] },
       { path: 'search', loadChildren: './+search-page/search-page.module#SearchPageModule' },
-      { path: 'browse', loadChildren: './+browse-by/browse-by.module#BrowseByModule' },
+      { path: 'browse', loadChildren: './+browse-by/browse-by.module#BrowseByModule'},
       { path: ADMIN_MODULE_PATH, loadChildren: './+admin/admin.module#AdminModule', canActivate: [AuthenticatedGuard] },
       { path: 'login', loadChildren: './+login-page/login-page.module#LoginPageModule' },
       { path: 'logout', loadChildren: './+logout-page/logout-page.module#LogoutPageModule' },
@@ -50,7 +76,7 @@ export function getAdminModulePath() {
       { path: '**', pathMatch: 'full', component: PageNotFoundComponent },
     ])
   ],
-  exports: [RouterModule]
+  exports: [RouterModule],
 })
 export class AppRoutingModule {
 
diff --git a/src/app/app.component.html b/src/app/app.component.html
index 4482cd02f8f384d8b4156e3c79acea6ba7418bbf..9aaf8050b16ebf3f2cf00d88ecf26a28b1d38011 100644
--- a/src/app/app.component.html
+++ b/src/app/app.component.html
@@ -10,7 +10,11 @@
                 [options]="config.notifications">
         </ds-notifications-board>
         <main class="main-content">
-            <div class="container" *ngIf="isLoading">
+            <div class="container">
+                <ds-breadcrumbs></ds-breadcrumbs>
+            </div>
+
+            <div class="container" *ngIf="isLoading$ | async">
                 <ds-loading message="{{'loading.default' | translate}}"></ds-loading>
             </div>
             <router-outlet></router-outlet>
diff --git a/src/app/app.component.ts b/src/app/app.component.ts
index 2141b06a77046c7557c5e38b58a382340851d388..4e029af8caca1d46efbe2c182b3643613676d39c 100644
--- a/src/app/app.component.ts
+++ b/src/app/app.component.ts
@@ -19,7 +19,7 @@ import variables from '../styles/_exposed_variables.scss';
 import { CSSVariableService } from './shared/sass-helper/sass-helper.service';
 import { MenuService } from './shared/menu/menu.service';
 import { MenuID } from './shared/menu/initial-menus-state';
-import { combineLatest as combineLatestObservable, Observable, of } from 'rxjs';
+import { BehaviorSubject, combineLatest as combineLatestObservable, Observable, of } from 'rxjs';
 import { slideSidebarPadding } from './shared/animations/slide';
 import { HostWindowService } from './shared/host-window.service';
 import { Theme } from '../config/theme.inferface';
@@ -38,7 +38,7 @@ export const LANG_COOKIE = 'language_cookie';
   animations: [slideSidebarPadding]
 })
 export class AppComponent implements OnInit, AfterViewInit {
-  isLoading = true;
+  isLoading$: BehaviorSubject<boolean> = new BehaviorSubject(true);
   sidebarVisible: Observable<boolean>;
   slideSidebarOver: Observable<boolean>;
   collapsedSidebarWidth: Observable<string>;
@@ -131,12 +131,12 @@ export class AppComponent implements OnInit, AfterViewInit {
       delay(0)
     ).subscribe((event) => {
         if (event instanceof NavigationStart) {
-          this.isLoading = true;
+          this.isLoading$.next(true);
         } else if (
           event instanceof NavigationEnd ||
           event instanceof NavigationCancel
         ) {
-          this.isLoading = false;
+          this.isLoading$.next(false);
         }
       });
   }
diff --git a/src/app/app.metareducers.ts b/src/app/app.metareducers.ts
index 4d94c899d7170f1a4e7fc1e2d03d3c7da9e95b2a..131d240b79a7fa40aa54a53c621f7db0cf6c073d 100644
--- a/src/app/app.metareducers.ts
+++ b/src/app/app.metareducers.ts
@@ -1,4 +1,3 @@
-import { isNotEmpty } from './shared/empty.util';
 import { StoreActionTypes } from './store.actions';
 
 // fallback ngrx debugger
diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index 4b803608f396fb24c00fa9cbf73e8ba7e9b035be..aaad66adf60a5855aa26d4e4b0b77a7dc774d2cc 100755
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -3,17 +3,14 @@ import { HttpClientModule } from '@angular/common/http';
 import { NgModule } from '@angular/core';
 
 import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
-
 import { EffectsModule } from '@ngrx/effects';
 import { RouterStateSerializer, StoreRouterConnectingModule } from '@ngrx/router-store';
-import { META_REDUCERS, MetaReducer, StoreModule } from '@ngrx/store';
+import { MetaReducer, StoreModule, USER_PROVIDED_META_REDUCERS } from '@ngrx/store';
 import { StoreDevtoolsModule } from '@ngrx/store-devtools';
-
+import { DYNAMIC_MATCHER_PROVIDERS } from '@ng-dynamic-forms/core';
 import { TranslateModule } from '@ngx-translate/core';
 import { ScrollToModule } from '@nicky-lenaers/ngx-scroll-to';
 
-import { storeFreeze } from 'ngrx-store-freeze';
-
 import { ENV_CONFIG, GLOBAL_CONFIG, GlobalConfig } from '../config';
 import { AdminSidebarSectionComponent } from './+admin/admin-sidebar/admin-sidebar-section/admin-sidebar-section.component';
 import { AdminSidebarComponent } from './+admin/admin-sidebar/admin-sidebar.component';
@@ -41,6 +38,7 @@ import { DSpaceRouterStateSerializer } from './shared/ngrx/dspace-router-state-s
 import { NotificationComponent } from './shared/notifications/notification/notification.component';
 import { NotificationsBoardComponent } from './shared/notifications/notifications-board/notifications-board.component';
 import { SharedModule } from './shared/shared.module';
+import { BreadcrumbsComponent } from './breadcrumbs/breadcrumbs.component';
 
 export function getConfig() {
   return ENV_CONFIG;
@@ -51,8 +49,7 @@ export function getBase() {
 }
 
 export function getMetaReducers(config: GlobalConfig): Array<MetaReducer<AppState>> {
-  const metaReducers: Array<MetaReducer<AppState>> = config.production ? appMetaReducers : [...appMetaReducers, storeFreeze];
-  return config.debug ? [...metaReducers, ...debugMetaReducers] : metaReducers;
+  return config.debug ? [...appMetaReducers, ...debugMetaReducers] : appMetaReducers;
 }
 
 const IMPORTS = [
@@ -63,11 +60,11 @@ const IMPORTS = [
   AppRoutingModule,
   CoreModule.forRoot(),
   ScrollToModule.forRoot(),
-  NgbModule.forRoot(),
+  NgbModule,
   TranslateModule.forRoot(),
   EffectsModule.forRoot(appEffects),
   StoreModule.forRoot(appReducers),
-  StoreRouterConnectingModule,
+  StoreRouterConnectingModule.forRoot(),
 ];
 
 const ENTITY_IMPORTS = [
@@ -92,7 +89,7 @@ const PROVIDERS = [
     useFactory: (getBase)
   },
   {
-    provide: META_REDUCERS,
+    provide: USER_PROVIDED_META_REDUCERS,
     useFactory: getMetaReducers,
     deps: [GLOBAL_CONFIG]
   },
@@ -100,7 +97,8 @@ const PROVIDERS = [
     provide: RouterStateSerializer,
     useClass: DSpaceRouterStateSerializer
   },
-  ClientCookieService
+  ClientCookieService,
+  ...DYNAMIC_MATCHER_PROVIDERS,
 ];
 
 const DECLARATIONS = [
@@ -131,6 +129,7 @@ const EXPORTS = [
   ],
   declarations: [
     ...DECLARATIONS,
+    BreadcrumbsComponent,
   ],
   exports: [
     ...EXPORTS
diff --git a/src/app/breadcrumbs/breadcrumb/breadcrumb-config.model.ts b/src/app/breadcrumbs/breadcrumb/breadcrumb-config.model.ts
new file mode 100644
index 0000000000000000000000000000000000000000..0ff8fc5033b11a4f7b9027480bc87bf244d0eea7
--- /dev/null
+++ b/src/app/breadcrumbs/breadcrumb/breadcrumb-config.model.ts
@@ -0,0 +1,21 @@
+import { BreadcrumbsService } from '../../core/breadcrumbs/breadcrumbs.service';
+
+/**
+ * Interface for breadcrumb configuration objects
+ */
+export interface BreadcrumbConfig<T> {
+    /**
+     * The service used to calculate the breadcrumb object
+     */
+    provider: BreadcrumbsService<T>;
+
+    /**
+     * The key that is used to calculate the breadcrumb display value
+     */
+    key: T;
+
+    /**
+     * The url of the breadcrumb
+     */
+    url?: string;
+}
diff --git a/src/app/breadcrumbs/breadcrumb/breadcrumb.model.ts b/src/app/breadcrumbs/breadcrumb/breadcrumb.model.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c6ab8491b40f2788d9fea59d52941f595995be0a
--- /dev/null
+++ b/src/app/breadcrumbs/breadcrumb/breadcrumb.model.ts
@@ -0,0 +1,15 @@
+/**
+ * Class representing a single breadcrumb
+ */
+export class Breadcrumb {
+  constructor(
+    /**
+     * The display value of the breadcrumb
+     */
+    public text: string,
+    /**
+     * The optional url of the breadcrumb
+     */
+    public url?: string) {
+  }
+}
diff --git a/src/app/breadcrumbs/breadcrumbs.component.html b/src/app/breadcrumbs/breadcrumbs.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..b773964d1e615aa28179e8f4932e13c041425aea
--- /dev/null
+++ b/src/app/breadcrumbs/breadcrumbs.component.html
@@ -0,0 +1,17 @@
+<nav *ngIf="showBreadcrumbs" aria-label="breadcrumb">
+    <ol class="breadcrumb">
+        <ng-container *ngTemplateOutlet="breadcrumbs.length > 0 ? breadcrumb : activeBreadcrumb; context: {text: 'Home', url: '/'}"></ng-container>
+        <ng-container *ngFor="let bc of breadcrumbs; let last = last;">
+            <ng-container *ngTemplateOutlet="!last ? breadcrumb : activeBreadcrumb; context: bc"></ng-container>
+        </ng-container>
+    </ol>
+</nav>
+
+<ng-template #breadcrumb let-text="text" let-url="url">
+    <li class="breadcrumb-item"><a [routerLink]="url">{{text | translate}}</a></li>
+</ng-template>
+
+<ng-template #activeBreadcrumb let-text="text" >
+    <li class="breadcrumb-item active" aria-current="page">{{text | translate}}</li>
+</ng-template>
+
diff --git a/src/app/breadcrumbs/breadcrumbs.component.scss b/src/app/breadcrumbs/breadcrumbs.component.scss
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/app/breadcrumbs/breadcrumbs.component.spec.ts b/src/app/breadcrumbs/breadcrumbs.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..0ab1fed20882bec6b145723fc700975891571f3c
--- /dev/null
+++ b/src/app/breadcrumbs/breadcrumbs.component.spec.ts
@@ -0,0 +1,111 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { BreadcrumbsComponent } from './breadcrumbs.component';
+import { ActivatedRoute, NavigationEnd, Router } from '@angular/router';
+import { Observable, of as observableOf } from 'rxjs';
+import { RouterTestingModule } from '@angular/router/testing';
+import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
+import { MockTranslateLoader } from '../shared/testing/mock-translate-loader';
+import { BreadcrumbConfig } from './breadcrumb/breadcrumb-config.model';
+import { BreadcrumbsService } from '../core/breadcrumbs/breadcrumbs.service';
+import { Breadcrumb } from './breadcrumb/breadcrumb.model';
+import { getTestScheduler } from 'jasmine-marbles';
+
+class TestBreadcrumbsService implements BreadcrumbsService<string> {
+  getBreadcrumbs(key: string, url: string): Observable<Breadcrumb[]> {
+    return observableOf([new Breadcrumb(key, url)]);
+  }
+}
+
+describe('BreadcrumbsComponent', () => {
+  let component: BreadcrumbsComponent;
+  let fixture: ComponentFixture<BreadcrumbsComponent>;
+  let router: any;
+  let route: any;
+  let breadcrumbProvider;
+  let breadcrumbConfigA: BreadcrumbConfig<string>;
+  let breadcrumbConfigB: BreadcrumbConfig<string>;
+  let expectedBreadcrumbs;
+
+  function init() {
+    breadcrumbProvider = new TestBreadcrumbsService();
+
+    breadcrumbConfigA = { provider: breadcrumbProvider, key: 'example.path', url: 'example.com' };
+    breadcrumbConfigB = { provider: breadcrumbProvider, key: 'another.path', url: 'another.com' };
+
+    route = {
+      root: {
+        snapshot: {
+          data: { breadcrumb: breadcrumbConfigA },
+          routeConfig: { resolve: { breadcrumb: {} } }
+        },
+        firstChild: {
+          snapshot: {
+            // Example without resolver should be ignored
+            data: { breadcrumb: breadcrumbConfigA },
+          },
+          firstChild: {
+            snapshot: {
+              data: { breadcrumb: breadcrumbConfigB },
+              routeConfig: { resolve: { breadcrumb: {} } }
+            }
+          }
+        }
+      }
+    };
+
+    expectedBreadcrumbs = [
+      new Breadcrumb(breadcrumbConfigA.key, breadcrumbConfigA.url),
+      new Breadcrumb(breadcrumbConfigB.key, breadcrumbConfigB.url)
+    ]
+
+  }
+
+  beforeEach(async(() => {
+    init();
+    TestBed.configureTestingModule({
+      declarations: [BreadcrumbsComponent],
+      imports: [RouterTestingModule.withRoutes([]), TranslateModule.forRoot({
+        loader: {
+          provide: TranslateLoader,
+          useClass: MockTranslateLoader
+        }
+      })],
+      providers: [
+        { provide: ActivatedRoute, useValue: route }
+
+      ]
+    })
+      .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(BreadcrumbsComponent);
+    component = fixture.componentInstance;
+    router = TestBed.get(Router);
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+
+  describe('ngOnInit', () => {
+    beforeEach(() => {
+      spyOn(component, 'resolveBreadcrumbs').and.returnValue(observableOf([]))
+    });
+
+    it('should call resolveBreadcrumb on init', () => {
+      router.events = observableOf(new NavigationEnd(0, '', ''));
+      component.ngOnInit();
+      expect(component.resolveBreadcrumbs).toHaveBeenCalledWith(route.root);
+    })
+  });
+
+  describe('resolveBreadcrumbs', () => {
+    it('should return the correct breadcrumbs', () => {
+      const breadcrumbs = component.resolveBreadcrumbs(route.root);
+      getTestScheduler().expectObservable(breadcrumbs).toBe('(a|)', { a: expectedBreadcrumbs })
+    })
+  })
+});
diff --git a/src/app/breadcrumbs/breadcrumbs.component.ts b/src/app/breadcrumbs/breadcrumbs.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..2bba3c76b6633922fd9eff12b8c78fc3a8992cbe
--- /dev/null
+++ b/src/app/breadcrumbs/breadcrumbs.component.ts
@@ -0,0 +1,100 @@
+import { Component, OnDestroy, OnInit } from '@angular/core';
+import { ActivatedRoute, NavigationEnd, Router } from '@angular/router';
+import { Breadcrumb } from './breadcrumb/breadcrumb.model';
+import { hasNoValue, hasValue, isNotUndefined, isUndefined } from '../shared/empty.util';
+import { filter, map, switchMap, tap } from 'rxjs/operators';
+import { combineLatest, Observable, Subscription, of as observableOf } from 'rxjs';
+
+/**
+ * Component representing the breadcrumbs of a page
+ */
+@Component({
+  selector: 'ds-breadcrumbs',
+  templateUrl: './breadcrumbs.component.html',
+  styleUrls: ['./breadcrumbs.component.scss']
+})
+export class BreadcrumbsComponent implements OnInit, OnDestroy {
+  /**
+   * List of breadcrumbs for this page
+   */
+  breadcrumbs: Breadcrumb[];
+
+  /**
+   * Whether or not to show breadcrumbs on this page
+   */
+  showBreadcrumbs: boolean;
+
+  /**
+   * Subscription to unsubscribe from on destroy
+   */
+  subscription: Subscription;
+
+  constructor(
+    private route: ActivatedRoute,
+    private router: Router
+  ) {
+  }
+
+  /**
+   * Sets the breadcrumbs on init for this page
+   */
+  ngOnInit(): void {
+    this.subscription = this.router.events.pipe(
+      filter((e): e is NavigationEnd => e instanceof NavigationEnd),
+      tap(() => this.reset()),
+      switchMap(() => this.resolveBreadcrumbs(this.route.root))
+    ).subscribe((breadcrumbs) => {
+        this.breadcrumbs = breadcrumbs;
+      }
+    )
+  }
+
+  /**
+   * Method that recursively resolves breadcrumbs
+   * @param route The route to get the breadcrumb from
+   */
+  resolveBreadcrumbs(route: ActivatedRoute): Observable<Breadcrumb[]> {
+    const data = route.snapshot.data;
+    const routeConfig = route.snapshot.routeConfig;
+
+    const last: boolean = hasNoValue(route.firstChild);
+    if (last) {
+      if (hasValue(data.showBreadcrumbs)) {
+        this.showBreadcrumbs = data.showBreadcrumbs;
+      } else if (isUndefined(data.breadcrumb)) {
+        this.showBreadcrumbs = false;
+      }
+    }
+
+    if (
+      hasValue(data) && hasValue(data.breadcrumb) &&
+      hasValue(routeConfig) && hasValue(routeConfig.resolve) && hasValue(routeConfig.resolve.breadcrumb)
+    ) {
+      const { provider, key, url } = data.breadcrumb;
+      if (!last) {
+        return combineLatest(provider.getBreadcrumbs(key, url), this.resolveBreadcrumbs(route.firstChild))
+          .pipe(map((crumbs) => [].concat.apply([], crumbs)));
+      } else {
+        return provider.getBreadcrumbs(key, url);
+      }
+    }
+    return !last ? this.resolveBreadcrumbs(route.firstChild) : observableOf([]);
+  }
+
+  /**
+   * Unsubscribe from subscription
+   */
+  ngOnDestroy(): void {
+    if (hasValue(this.subscription)) {
+      this.subscription.unsubscribe();
+    }
+  }
+
+  /**
+   * Resets the state of the breadcrumbs
+   */
+  reset() {
+    this.breadcrumbs = [];
+    this.showBreadcrumbs = true;
+  }
+}
diff --git a/src/app/community-list-page/community-list-service.spec.ts b/src/app/community-list-page/community-list-service.spec.ts
index a150277d200d9f90f6fd1f191aa259a519de93f2..c3cfef35a0cd51da198ca00eac22b258de2bd1c7 100644
--- a/src/app/community-list-page/community-list-service.spec.ts
+++ b/src/app/community-list-page/community-list-service.spec.ts
@@ -190,8 +190,6 @@ describe('CommunityListService', () => {
     service = new CommunityListService(communityDataServiceStub, collectionDataServiceStub, store);
   }));
 
-  afterAll(() => service = new CommunityListService(communityDataServiceStub, collectionDataServiceStub, store));
-
   it('should create', inject([CommunityListService], (serviceIn: CommunityListService) => {
     expect(serviceIn).toBeTruthy();
   }));
diff --git a/src/app/core/auth/auth-response-parsing.service.spec.ts b/src/app/core/auth/auth-response-parsing.service.spec.ts
index 112d60b8d208652509f517ee29b792a8e5319efa..3b18d925bfbc4beddff7b5e3a3935b035eb9490c 100644
--- a/src/app/core/auth/auth-response-parsing.service.spec.ts
+++ b/src/app/core/auth/auth-response-parsing.service.spec.ts
@@ -3,15 +3,16 @@ import { async, TestBed } from '@angular/core/testing';
 import { Store, StoreModule } from '@ngrx/store';
 
 import { GlobalConfig } from '../../../config/global-config.interface';
-import { AuthStatusResponse } from '../cache/response.models';
+import { MockStore } from '../../shared/testing/mock-store';
 import { ObjectCacheService } from '../cache/object-cache.service';
-import { AuthStatus } from './models/auth-status.model';
-import { AuthResponseParsingService } from './auth-response-parsing.service';
+import { AuthStatusResponse } from '../cache/response.models';
 import { AuthGetRequest, AuthPostRequest } from '../data/request.models';
-import { MockStore } from '../../shared/testing/mock-store';
+import { AuthResponseParsingService } from './auth-response-parsing.service';
+import { AuthStatus } from './models/auth-status.model';
 
 describe('AuthResponseParsingService', () => {
   let service: AuthResponseParsingService;
+  let linkServiceStub: any;
 
   const EnvConfig: GlobalConfig = { cache: { msToLive: 1000 } } as any;
   let store: any;
@@ -30,7 +31,10 @@ describe('AuthResponseParsingService', () => {
 
   beforeEach(() => {
     store = TestBed.get(Store);
-    objectCacheService = new ObjectCacheService(store as any);
+    linkServiceStub = jasmine.createSpyObj({
+      removeResolvedLinks: {}
+    });
+    objectCacheService = new ObjectCacheService(store as any, linkServiceStub);
     service = new AuthResponseParsingService(EnvConfig, objectCacheService);
   });
 
@@ -141,6 +145,7 @@ describe('AuthResponseParsingService', () => {
     it('should return a AuthStatusResponse if data contains a valid endpoint response', () => {
       const response = service.parse(validRequest2, validResponse2);
       expect(response.constructor).toBe(AuthStatusResponse);
+      expect(linkServiceStub.removeResolvedLinks).toHaveBeenCalled();
     });
 
     it('should return a AuthStatusResponse if data contains an empty 404 endpoint response', () => {
diff --git a/src/app/core/auth/auth-response-parsing.service.ts b/src/app/core/auth/auth-response-parsing.service.ts
index 8137734c49f2cee021b69a64eda3c49e5356c246..9ef523ca1407df88b121a449c09a1aacc0150020 100644
--- a/src/app/core/auth/auth-response-parsing.service.ts
+++ b/src/app/core/auth/auth-response-parsing.service.ts
@@ -10,8 +10,6 @@ import { ObjectCacheService } from '../cache/object-cache.service';
 import { ResponseParsingService } from '../data/parsing.service';
 import { RestRequest } from '../data/request.models';
 import { AuthStatus } from './models/auth-status.model';
-import { NormalizedAuthStatus } from './models/normalized-auth-status.model';
-import { NormalizedObject } from '../cache/models/normalized-object.model';
 
 @Injectable()
 export class AuthResponseParsingService extends BaseResponseParsingService implements ResponseParsingService {
@@ -25,10 +23,10 @@ export class AuthResponseParsingService extends BaseResponseParsingService imple
 
   parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse {
     if (isNotEmpty(data.payload) && isNotEmpty(data.payload._links) && (data.statusCode === 200)) {
-      const response = this.process<NormalizedObject<AuthStatus>>(data.payload, request);
+      const response = this.process<AuthStatus>(data.payload, request);
       return new AuthStatusResponse(response, data.statusCode, data.statusText);
     } else {
-      return new AuthStatusResponse(data.payload as NormalizedAuthStatus, data.statusCode, data.statusText);
+      return new AuthStatusResponse(data.payload as AuthStatus, data.statusCode, data.statusText);
     }
   }
 }
diff --git a/src/app/core/auth/auth.actions.ts b/src/app/core/auth/auth.actions.ts
index d0969d38d4099770cb549c7c395ccb200d76a902..2681ed39a233bac43f6119654c4f97fb6d05f250 100644
--- a/src/app/core/auth/auth.actions.ts
+++ b/src/app/core/auth/auth.actions.ts
@@ -1,9 +1,7 @@
 // import @ngrx
 import { Action } from '@ngrx/store';
-
 // import type function
 import { type } from '../../shared/ngrx/type';
-
 // import models
 import { EPerson } from '../eperson/models/eperson.model';
 import { AuthTokenInfo } from './models/auth-token-info.model';
@@ -31,6 +29,9 @@ export const AuthActionTypes = {
   REGISTRATION_ERROR: type('dspace/auth/REGISTRATION_ERROR'),
   REGISTRATION_SUCCESS: type('dspace/auth/REGISTRATION_SUCCESS'),
   SET_REDIRECT_URL: type('dspace/auth/SET_REDIRECT_URL'),
+  RETRIEVE_AUTHENTICATED_EPERSON: type('dspace/auth/RETRIEVE_AUTHENTICATED_EPERSON'),
+  RETRIEVE_AUTHENTICATED_EPERSON_SUCCESS: type('dspace/auth/RETRIEVE_AUTHENTICATED_EPERSON_SUCCESS'),
+  RETRIEVE_AUTHENTICATED_EPERSON_ERROR: type('dspace/auth/RETRIEVE_AUTHENTICATED_EPERSON_ERROR'),
 };
 
 /* tslint:disable:max-classes-per-file */
@@ -76,11 +77,11 @@ export class AuthenticatedSuccessAction implements Action {
   payload: {
     authenticated: boolean;
     authToken: AuthTokenInfo;
-    user: EPerson
+    userHref: string
   };
 
-  constructor(authenticated: boolean, authToken: AuthTokenInfo, user: EPerson) {
-    this.payload = { authenticated, authToken, user };
+  constructor(authenticated: boolean, authToken: AuthTokenInfo, userHref: string) {
+    this.payload = { authenticated, authToken, userHref };
   }
 }
 
@@ -322,6 +323,47 @@ export class SetRedirectUrlAction implements Action {
   }
 }
 
+/**
+ * Retrieve the authenticated eperson.
+ * @class RetrieveAuthenticatedEpersonAction
+ * @implements {Action}
+ */
+export class RetrieveAuthenticatedEpersonAction implements Action {
+  public type: string = AuthActionTypes.RETRIEVE_AUTHENTICATED_EPERSON;
+  payload: string;
+
+  constructor(user: string) {
+    this.payload = user ;
+  }
+}
+
+/**
+ * Set the authenticated eperson in the state.
+ * @class RetrieveAuthenticatedEpersonSuccessAction
+ * @implements {Action}
+ */
+export class RetrieveAuthenticatedEpersonSuccessAction implements Action {
+  public type: string = AuthActionTypes.RETRIEVE_AUTHENTICATED_EPERSON_SUCCESS;
+  payload: EPerson;
+
+  constructor(user: EPerson) {
+    this.payload = user ;
+  }
+}
+
+/**
+ * Set the authenticated eperson in the state.
+ * @class RetrieveAuthenticatedEpersonSuccessAction
+ * @implements {Action}
+ */
+export class RetrieveAuthenticatedEpersonErrorAction implements Action {
+  public type: string = AuthActionTypes.RETRIEVE_AUTHENTICATED_EPERSON_ERROR;
+  payload: Error;
+
+  constructor(payload: Error) {
+    this.payload = payload ;
+  }
+}
 /* tslint:enable:max-classes-per-file */
 
 /**
@@ -343,4 +385,8 @@ export type AuthActions
   | RegistrationErrorAction
   | RegistrationSuccessAction
   | AddAuthenticationMessageAction
-  | ResetAuthenticationMessagesAction;
+  | ResetAuthenticationMessagesAction
+  | RetrieveAuthenticatedEpersonAction
+  | RetrieveAuthenticatedEpersonErrorAction
+  | RetrieveAuthenticatedEpersonSuccessAction
+  | SetRedirectUrlAction;
diff --git a/src/app/core/auth/auth.effects.spec.ts b/src/app/core/auth/auth.effects.spec.ts
index 8c2b4026e073c2f8d7ff7e0e3ff98823529107ce..34b900fe7e087c0b23f50788928c3f9ed6d9b14f 100644
--- a/src/app/core/auth/auth.effects.spec.ts
+++ b/src/app/core/auth/auth.effects.spec.ts
@@ -18,12 +18,14 @@ import {
   LogOutErrorAction,
   LogOutSuccessAction,
   RefreshTokenErrorAction,
-  RefreshTokenSuccessAction
+  RefreshTokenSuccessAction,
+  RetrieveAuthenticatedEpersonAction,
+  RetrieveAuthenticatedEpersonErrorAction,
+  RetrieveAuthenticatedEpersonSuccessAction
 } from './auth.actions';
 import { AuthServiceStub } from '../../shared/testing/auth-service-stub';
 import { AuthService } from './auth.service';
 import { AuthState } from './auth.reducer';
-
 import { EPersonMock } from '../../shared/testing/eperson-mock';
 
 describe('AuthEffects', () => {
@@ -42,13 +44,14 @@ describe('AuthEffects', () => {
     authServiceStub = new AuthServiceStub();
     token = authServiceStub.getToken();
   }
+
   beforeEach(() => {
     init();
     TestBed.configureTestingModule({
       providers: [
         AuthEffects,
-        {provide: AuthService, useValue: authServiceStub},
-        {provide: Store, useValue: store},
+        { provide: AuthService, useValue: authServiceStub },
+        { provide: Store, useValue: store },
         provideMockActions(() => actions),
         // other providers
       ],
@@ -63,11 +66,11 @@ describe('AuthEffects', () => {
         actions = hot('--a-', {
           a: {
             type: AuthActionTypes.AUTHENTICATE,
-            payload: {email: 'user', password: 'password'}
+            payload: { email: 'user', password: 'password' }
           }
         });
 
-        const expected = cold('--b-', {b: new AuthenticationSuccessAction(token)});
+        const expected = cold('--b-', { b: new AuthenticationSuccessAction(token) });
 
         expect(authEffects.authenticate$).toBeObservable(expected);
       });
@@ -80,11 +83,11 @@ describe('AuthEffects', () => {
         actions = hot('--a-', {
           a: {
             type: AuthActionTypes.AUTHENTICATE,
-            payload: {email: 'user', password: 'wrongpassword'}
+            payload: { email: 'user', password: 'wrongpassword' }
           }
         });
 
-        const expected = cold('--b-', {b: new AuthenticationErrorAction(new Error('Message Error test'))});
+        const expected = cold('--b-', { b: new AuthenticationErrorAction(new Error('Message Error test')) });
 
         expect(authEffects.authenticate$).toBeObservable(expected);
       });
@@ -94,9 +97,9 @@ describe('AuthEffects', () => {
   describe('authenticateSuccess$', () => {
 
     it('should return a AUTHENTICATED action in response to a AUTHENTICATE_SUCCESS action', () => {
-      actions = hot('--a-', {a: {type: AuthActionTypes.AUTHENTICATE_SUCCESS, payload: token}});
+      actions = hot('--a-', { a: { type: AuthActionTypes.AUTHENTICATE_SUCCESS, payload: token } });
 
-      const expected = cold('--b-', {b: new AuthenticatedAction(token)});
+      const expected = cold('--b-', { b: new AuthenticatedAction(token) });
 
       expect(authEffects.authenticateSuccess$).toBeObservable(expected);
     });
@@ -106,9 +109,9 @@ describe('AuthEffects', () => {
 
     describe('when token is valid', () => {
       it('should return a AUTHENTICATED_SUCCESS action in response to a AUTHENTICATED action', () => {
-        actions = hot('--a-', {a: {type: AuthActionTypes.AUTHENTICATED, payload: token}});
+        actions = hot('--a-', { a: { type: AuthActionTypes.AUTHENTICATED, payload: token } });
 
-        const expected = cold('--b-', {b: new AuthenticatedSuccessAction(true, token, EPersonMock)});
+        const expected = cold('--b-', { b: new AuthenticatedSuccessAction(true, token, EPersonMock._links.self.href) });
 
         expect(authEffects.authenticated$).toBeObservable(expected);
       });
@@ -118,23 +121,42 @@ describe('AuthEffects', () => {
       it('should return a AUTHENTICATED_ERROR action in response to a AUTHENTICATED action', () => {
         spyOn((authEffects as any).authService, 'authenticatedUser').and.returnValue(observableThrow(new Error('Message Error test')));
 
-        actions = hot('--a-', {a: {type: AuthActionTypes.AUTHENTICATED, payload: token}});
+        actions = hot('--a-', { a: { type: AuthActionTypes.AUTHENTICATED, payload: token } });
 
-        const expected = cold('--b-', {b: new AuthenticatedErrorAction(new Error('Message Error test'))});
+        const expected = cold('--b-', { b: new AuthenticatedErrorAction(new Error('Message Error test')) });
 
         expect(authEffects.authenticated$).toBeObservable(expected);
       });
     });
   });
 
+  describe('authenticatedSuccess$', () => {
+
+    it('should return a RETRIEVE_AUTHENTICATED_EPERSON action in response to a AUTHENTICATED_SUCCESS action', () => {
+      actions = hot('--a-', {
+        a: {
+          type: AuthActionTypes.AUTHENTICATED_SUCCESS, payload: {
+            authenticated: true,
+            authToken: token,
+            userHref: EPersonMock._links.self.href
+          }
+        }
+      });
+
+      const expected = cold('--b-', { b: new RetrieveAuthenticatedEpersonAction(EPersonMock._links.self.href) });
+
+      expect(authEffects.authenticatedSuccess$).toBeObservable(expected);
+    });
+  });
+
   describe('checkToken$', () => {
 
     describe('when check token succeeded', () => {
       it('should return a AUTHENTICATED action in response to a CHECK_AUTHENTICATION_TOKEN action', () => {
 
-        actions = hot('--a-', {a: {type: AuthActionTypes.CHECK_AUTHENTICATION_TOKEN}});
+        actions = hot('--a-', { a: { type: AuthActionTypes.CHECK_AUTHENTICATION_TOKEN } });
 
-        const expected = cold('--b-', {b: new AuthenticatedAction(token)});
+        const expected = cold('--b-', { b: new AuthenticatedAction(token) });
 
         expect(authEffects.checkToken$).toBeObservable(expected);
       });
@@ -144,23 +166,53 @@ describe('AuthEffects', () => {
       it('should return a CHECK_AUTHENTICATION_TOKEN_ERROR action in response to a CHECK_AUTHENTICATION_TOKEN action', () => {
         spyOn((authEffects as any).authService, 'hasValidAuthenticationToken').and.returnValue(observableThrow(''));
 
-        actions = hot('--a-', {a: {type: AuthActionTypes.CHECK_AUTHENTICATION_TOKEN, payload: token}});
+        actions = hot('--a-', { a: { type: AuthActionTypes.CHECK_AUTHENTICATION_TOKEN, payload: token } });
 
-        const expected = cold('--b-', {b: new CheckAuthenticationTokenErrorAction()});
+        const expected = cold('--b-', { b: new CheckAuthenticationTokenErrorAction() });
 
         expect(authEffects.checkToken$).toBeObservable(expected);
       });
     })
   });
 
+  describe('retrieveAuthenticatedEperson$', () => {
+
+    describe('when request is successful', () => {
+      it('should return a RETRIEVE_AUTHENTICATED_EPERSON_SUCCESS action in response to a RETRIEVE_AUTHENTICATED_EPERSON action', () => {
+        actions = hot('--a-', {
+          a: {
+            type: AuthActionTypes.RETRIEVE_AUTHENTICATED_EPERSON,
+            payload: EPersonMock._links.self.href
+          }
+        });
+
+        const expected = cold('--b-', { b: new RetrieveAuthenticatedEpersonSuccessAction(EPersonMock) });
+
+        expect(authEffects.retrieveAuthenticatedEperson$).toBeObservable(expected);
+      });
+    });
+
+    describe('when request is not successful', () => {
+      it('should return a RETRIEVE_AUTHENTICATED_EPERSON_ERROR action in response to a RETRIEVE_AUTHENTICATED_EPERSON action', () => {
+        spyOn((authEffects as any).authService, 'retrieveAuthenticatedUserByHref').and.returnValue(observableThrow(new Error('Message Error test')));
+
+        actions = hot('--a-', { a: { type: AuthActionTypes.RETRIEVE_AUTHENTICATED_EPERSON, payload: token } });
+
+        const expected = cold('--b-', { b: new RetrieveAuthenticatedEpersonErrorAction(new Error('Message Error test')) });
+
+        expect(authEffects.retrieveAuthenticatedEperson$).toBeObservable(expected);
+      });
+    });
+  });
+
   describe('refreshToken$', () => {
 
     describe('when refresh token succeeded', () => {
       it('should return a REFRESH_TOKEN_SUCCESS action in response to a REFRESH_TOKEN action', () => {
 
-        actions = hot('--a-', {a: {type: AuthActionTypes.REFRESH_TOKEN}});
+        actions = hot('--a-', { a: { type: AuthActionTypes.REFRESH_TOKEN } });
 
-        const expected = cold('--b-', {b: new RefreshTokenSuccessAction(token)});
+        const expected = cold('--b-', { b: new RefreshTokenSuccessAction(token) });
 
         expect(authEffects.refreshToken$).toBeObservable(expected);
       });
@@ -170,9 +222,9 @@ describe('AuthEffects', () => {
       it('should return a REFRESH_TOKEN_ERROR action in response to a REFRESH_TOKEN action', () => {
         spyOn((authEffects as any).authService, 'refreshAuthenticationToken').and.returnValue(observableThrow(''));
 
-        actions = hot('--a-', {a: {type: AuthActionTypes.REFRESH_TOKEN, payload: token}});
+        actions = hot('--a-', { a: { type: AuthActionTypes.REFRESH_TOKEN, payload: token } });
 
-        const expected = cold('--b-', {b: new RefreshTokenErrorAction()});
+        const expected = cold('--b-', { b: new RefreshTokenErrorAction() });
 
         expect(authEffects.refreshToken$).toBeObservable(expected);
       });
@@ -184,9 +236,9 @@ describe('AuthEffects', () => {
     describe('when refresh token succeeded', () => {
       it('should return a LOG_OUT_SUCCESS action in response to a LOG_OUT action', () => {
 
-        actions = hot('--a-', {a: {type: AuthActionTypes.LOG_OUT}});
+        actions = hot('--a-', { a: { type: AuthActionTypes.LOG_OUT } });
 
-        const expected = cold('--b-', {b: new LogOutSuccessAction()});
+        const expected = cold('--b-', { b: new LogOutSuccessAction() });
 
         expect(authEffects.logOut$).toBeObservable(expected);
       });
@@ -196,9 +248,9 @@ describe('AuthEffects', () => {
       it('should return a REFRESH_TOKEN_ERROR action in response to a LOG_OUT action', () => {
         spyOn((authEffects as any).authService, 'logout').and.returnValue(observableThrow(new Error('Message Error test')));
 
-        actions = hot('--a-', {a: {type: AuthActionTypes.LOG_OUT, payload: token}});
+        actions = hot('--a-', { a: { type: AuthActionTypes.LOG_OUT, payload: token } });
 
-        const expected = cold('--b-', {b: new LogOutErrorAction(new Error('Message Error test'))});
+        const expected = cold('--b-', { b: new LogOutErrorAction(new Error('Message Error test')) });
 
         expect(authEffects.logOut$).toBeObservable(expected);
       });
diff --git a/src/app/core/auth/auth.effects.ts b/src/app/core/auth/auth.effects.ts
index 1e68802af88928796835bc19b1d78ec5b9cef390..5ee63ccd92484f60d30259b222e64f2887c898c1 100644
--- a/src/app/core/auth/auth.effects.ts
+++ b/src/app/core/auth/auth.effects.ts
@@ -26,7 +26,10 @@ import {
   RefreshTokenSuccessAction,
   RegistrationAction,
   RegistrationErrorAction,
-  RegistrationSuccessAction
+  RegistrationSuccessAction,
+  RetrieveAuthenticatedEpersonAction,
+  RetrieveAuthenticatedEpersonErrorAction,
+  RetrieveAuthenticatedEpersonSuccessAction
 } from './auth.actions';
 import { EPerson } from '../eperson/models/eperson.model';
 import { AuthStatus } from './models/auth-status.model';
@@ -66,11 +69,17 @@ export class AuthEffects {
       ofType(AuthActionTypes.AUTHENTICATED),
       switchMap((action: AuthenticatedAction) => {
         return this.authService.authenticatedUser(action.payload).pipe(
-          map((user: EPerson) => new AuthenticatedSuccessAction((user !== null), action.payload, user)),
+          map((userHref: string) => new AuthenticatedSuccessAction((userHref !== null), action.payload, userHref)),
           catchError((error) => observableOf(new AuthenticatedErrorAction(error))),);
       })
     );
 
+  @Effect()
+  public authenticatedSuccess$: Observable<Action> = this.actions$.pipe(
+      ofType(AuthActionTypes.AUTHENTICATED_SUCCESS),
+      map((action: AuthenticatedSuccessAction) => new RetrieveAuthenticatedEpersonAction(action.payload.userHref))
+    );
+
   // It means "reacts to this action but don't send another"
   @Effect({ dispatch: false })
   public authenticatedError$: Observable<Action> = this.actions$.pipe(
@@ -78,6 +87,16 @@ export class AuthEffects {
       tap((action: LogOutSuccessAction) => this.authService.removeToken())
     );
 
+  @Effect()
+  public retrieveAuthenticatedEperson$: Observable<Action> = this.actions$.pipe(
+    ofType(AuthActionTypes.RETRIEVE_AUTHENTICATED_EPERSON),
+    switchMap((action: RetrieveAuthenticatedEpersonAction) => {
+      return this.authService.retrieveAuthenticatedUserByHref(action.payload).pipe(
+        map((user: EPerson) => new RetrieveAuthenticatedEpersonSuccessAction(user)),
+        catchError((error) => observableOf(new RetrieveAuthenticatedEpersonErrorAction(error))));
+    })
+  );
+
   @Effect()
   public checkToken$: Observable<Action> = this.actions$.pipe(ofType(AuthActionTypes.CHECK_AUTHENTICATION_TOKEN),
       switchMap(() => {
diff --git a/src/app/core/auth/auth.reducer.spec.ts b/src/app/core/auth/auth.reducer.spec.ts
index ca2ba00036e5fa5f1e11e7ac744558d13715489f..f299696007827c9a4c4054b207e0655696663dbd 100644
--- a/src/app/core/auth/auth.reducer.spec.ts
+++ b/src/app/core/auth/auth.reducer.spec.ts
@@ -17,7 +17,7 @@ import {
   RefreshTokenAction,
   RefreshTokenErrorAction,
   RefreshTokenSuccessAction,
-  ResetAuthenticationMessagesAction,
+  ResetAuthenticationMessagesAction, RetrieveAuthenticatedEpersonErrorAction, RetrieveAuthenticatedEpersonSuccessAction,
   SetRedirectUrlAction
 } from './auth.actions';
 import { AuthTokenInfo } from './models/auth-token-info.model';
@@ -107,16 +107,15 @@ describe('authReducer', () => {
       loading: true,
       info: undefined
     };
-    const action = new AuthenticatedSuccessAction(true, mockTokenInfo, EPersonMock);
+    const action = new AuthenticatedSuccessAction(true, mockTokenInfo, EPersonMock._links.self.href);
     const newState = authReducer(initialState, action);
     state = {
       authenticated: true,
       authToken: mockTokenInfo,
-      loaded: true,
+      loaded: false,
       error: undefined,
-      loading: false,
-      info: undefined,
-      user: EPersonMock
+      loading: true,
+      info: undefined
     };
     expect(newState).toEqual(state);
   });
@@ -242,6 +241,50 @@ describe('authReducer', () => {
     expect(newState).toEqual(state);
   });
 
+  it('should properly set the state, in response to a RETRIEVE_AUTHENTICATED_EPERSON_SUCCESS action', () => {
+    initialState = {
+      authenticated: true,
+      authToken: mockTokenInfo,
+      loaded: false,
+      error: undefined,
+      loading: true,
+      info: undefined
+    };
+    const action = new RetrieveAuthenticatedEpersonSuccessAction(EPersonMock);
+    const newState = authReducer(initialState, action);
+    state = {
+      authenticated: true,
+      authToken: mockTokenInfo,
+      loaded: true,
+      error: undefined,
+      loading: false,
+      info: undefined,
+      user: EPersonMock
+    };
+    expect(newState).toEqual(state);
+  });
+
+  it('should properly set the state, in response to a RETRIEVE_AUTHENTICATED_EPERSON_ERROR action', () => {
+    initialState = {
+      authenticated: false,
+      loaded: false,
+      error: undefined,
+      loading: true,
+      info: undefined
+    };
+    const action = new RetrieveAuthenticatedEpersonErrorAction(mockError);
+    const newState = authReducer(initialState, action);
+    state = {
+      authenticated: false,
+      authToken: undefined,
+      error: 'Test error message',
+      loaded: true,
+      loading: false,
+      info: undefined
+    };
+    expect(newState).toEqual(state);
+  });
+
   it('should properly set the state, in response to a REFRESH_TOKEN action', () => {
     initialState = {
       authenticated: true,
diff --git a/src/app/core/auth/auth.reducer.ts b/src/app/core/auth/auth.reducer.ts
index 98827d842ef27a200146cd83bfd4f2d85e87f574..7d5e50c43209c9f17650b97dc9bc13d92851a0bc 100644
--- a/src/app/core/auth/auth.reducer.ts
+++ b/src/app/core/auth/auth.reducer.ts
@@ -8,7 +8,7 @@ import {
   LogOutErrorAction,
   RedirectWhenAuthenticationIsRequiredAction,
   RedirectWhenTokenExpiredAction,
-  RefreshTokenSuccessAction,
+  RefreshTokenSuccessAction, RetrieveAuthenticatedEpersonSuccessAction,
   SetRedirectUrlAction
 } from './auth.actions';
 // import models
@@ -80,6 +80,7 @@ export function authReducer(state: any = initialState, action: AuthActions): Aut
       });
 
     case AuthActionTypes.AUTHENTICATED_ERROR:
+    case AuthActionTypes.RETRIEVE_AUTHENTICATED_EPERSON_ERROR:
       return Object.assign({}, state, {
         authenticated: false,
         authToken: undefined,
@@ -91,12 +92,16 @@ export function authReducer(state: any = initialState, action: AuthActions): Aut
     case AuthActionTypes.AUTHENTICATED_SUCCESS:
       return Object.assign({}, state, {
         authenticated: true,
-        authToken: (action as AuthenticatedSuccessAction).payload.authToken,
+        authToken: (action as AuthenticatedSuccessAction).payload.authToken
+      });
+
+    case AuthActionTypes.RETRIEVE_AUTHENTICATED_EPERSON_SUCCESS:
+      return Object.assign({}, state, {
         loaded: true,
         error: undefined,
         loading: false,
         info: undefined,
-        user: (action as AuthenticatedSuccessAction).payload.user
+        user: (action as RetrieveAuthenticatedEpersonSuccessAction).payload
       });
 
     case AuthActionTypes.AUTHENTICATE_ERROR:
diff --git a/src/app/core/auth/auth.service.spec.ts b/src/app/core/auth/auth.service.spec.ts
index 86794f257b5fd14fd084a43ae52275a73f9d709b..31649abe32cfa8169e47e82015acd092e66808c0 100644
--- a/src/app/core/auth/auth.service.spec.ts
+++ b/src/app/core/auth/auth.service.spec.ts
@@ -11,7 +11,6 @@ import { NativeWindowRef, NativeWindowService } from '../services/window.service
 import { AuthService } from './auth.service';
 import { RouterStub } from '../../shared/testing/router-stub';
 import { ActivatedRouteStub } from '../../shared/testing/active-router-stub';
-
 import { CookieService } from '../services/cookie.service';
 import { AuthRequestServiceStub } from '../../shared/testing/auth-request-service-stub';
 import { AuthRequestService } from './auth-request.service';
@@ -22,12 +21,21 @@ import { EPersonMock } from '../../shared/testing/eperson-mock';
 import { AppState } from '../../app.reducer';
 import { ClientCookieService } from '../services/client-cookie.service';
 import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
-import { getMockRemoteDataBuildService } from '../../shared/mocks/mock-remote-data-build.service';
 import { routeServiceStub } from '../../shared/testing/route-service-stub';
 import { RouteService } from '../services/route.service';
+import { Observable } from 'rxjs/internal/Observable';
+import { RemoteData } from '../data/remote-data';
+import { createSuccessfulRemoteDataObject$ } from '../../shared/testing/utils';
+import { EPersonDataService } from '../eperson/eperson-data.service';
 
 describe('AuthService test', () => {
 
+  const mockEpersonDataService: any = {
+    findByHref(href: string): Observable<RemoteData<EPerson>> {
+      return createSuccessfulRemoteDataObject$(EPersonMock);
+    }
+  };
+
   let mockStore: Store<AuthState>;
   let authService: AuthService;
   let routeServiceMock: RouteService;
@@ -38,7 +46,7 @@ describe('AuthService test', () => {
   let storage: CookieService;
   let token: AuthTokenInfo;
   let authenticatedState;
-  let rdbService;
+  let linkService;
 
   function init() {
     mockStore = jasmine.createSpyObj('store', {
@@ -58,8 +66,10 @@ describe('AuthService test', () => {
     };
     authRequest = new AuthRequestServiceStub();
     routeStub = new ActivatedRouteStub();
-    rdbService = getMockRemoteDataBuildService();
-    spyOn(rdbService, 'build').and.returnValue({authenticated: true, eperson: observableOf({payload: {}})});
+    linkService = {
+      resolveLinks: {}
+    };
+    spyOn(linkService, 'resolveLinks').and.returnValue({ authenticated: true, eperson: observableOf({ payload: {} }) });
 
   }
 
@@ -80,7 +90,7 @@ describe('AuthService test', () => {
           { provide: RouteService, useValue: routeServiceStub },
           { provide: ActivatedRoute, useValue: routeStub },
           { provide: Store, useValue: mockStore },
-          { provide: RemoteDataBuildService, useValue: rdbService },
+          { provide: EPersonDataService, useValue: mockEpersonDataService },
           CookieService,
           AuthService
         ],
@@ -98,8 +108,14 @@ describe('AuthService test', () => {
       expect(authService.authenticate.bind(null, 'user', 'passwordwrong')).toThrow();
     });
 
-    it('should return the authenticated user object when user token is valid', () => {
-      authService.authenticatedUser(new AuthTokenInfo('test_token')).subscribe((user: EPerson) => {
+    it('should return the authenticated user href when user token is valid', () => {
+      authService.authenticatedUser(new AuthTokenInfo('test_token')).subscribe((userHref: string) => {
+        expect(userHref).toBeDefined();
+      });
+    });
+
+    it('should return the authenticated user', () => {
+      authService.retrieveAuthenticatedUserByHref(EPersonMock._links.self.href).subscribe((user: EPerson) => {
         expect(user).toBeDefined();
       });
     });
@@ -143,7 +159,7 @@ describe('AuthService test', () => {
           { provide: REQUEST, useValue: {} },
           { provide: Router, useValue: routerStub },
           { provide: RouteService, useValue: routeServiceStub },
-          { provide: RemoteDataBuildService, useValue: rdbService },
+          { provide: RemoteDataBuildService, useValue: linkService },
           CookieService,
           AuthService
         ]
@@ -156,7 +172,7 @@ describe('AuthService test', () => {
           (state as any).core = Object.create({});
           (state as any).core.auth = authenticatedState;
         });
-      authService = new AuthService({}, window, undefined, authReqService, router, routeService, cookieService, store, rdbService);
+      authService = new AuthService({}, window, undefined, authReqService, mockEpersonDataService, router, routeService, cookieService, store);
     }));
 
     it('should return true when user is logged in', () => {
@@ -195,7 +211,7 @@ describe('AuthService test', () => {
           { provide: REQUEST, useValue: {} },
           { provide: Router, useValue: routerStub },
           { provide: RouteService, useValue: routeServiceStub },
-          { provide: RemoteDataBuildService, useValue: rdbService },
+          { provide: RemoteDataBuildService, useValue: linkService },
           ClientCookieService,
           CookieService,
           AuthService
@@ -218,7 +234,7 @@ describe('AuthService test', () => {
           (state as any).core = Object.create({});
           (state as any).core.auth = authenticatedState;
         });
-      authService = new AuthService({}, window, undefined, authReqService, router, routeService, cookieService, store, rdbService);
+      authService = new AuthService({}, window, undefined, authReqService, mockEpersonDataService, router, routeService, cookieService, store);
       storage = (authService as any).storage;
       routeServiceMock = TestBed.get(RouteService);
       routerStub = TestBed.get(Router);
@@ -247,7 +263,7 @@ describe('AuthService test', () => {
       expect(storage.remove).toHaveBeenCalled();
     });
 
-    it ('should set redirect url to previous page', () => {
+    it('should set redirect url to previous page', () => {
       spyOn(routeServiceMock, 'getHistory').and.callThrough();
       spyOn(routerStub, 'navigateByUrl');
       authService.redirectAfterLoginSuccess(true);
@@ -255,7 +271,7 @@ describe('AuthService test', () => {
       expect(routerStub.navigateByUrl).toHaveBeenCalledWith('/collection/123');
     });
 
-    it ('should set redirect url to current page', () => {
+    it('should set redirect url to current page', () => {
       spyOn(routeServiceMock, 'getHistory').and.callThrough();
       spyOn(routerStub, 'navigateByUrl');
       authService.redirectAfterLoginSuccess(false);
@@ -263,7 +279,7 @@ describe('AuthService test', () => {
       expect(routerStub.navigateByUrl).toHaveBeenCalledWith('/home');
     });
 
-    it ('should redirect to / and not to /login', () => {
+    it('should redirect to / and not to /login', () => {
       spyOn(routeServiceMock, 'getHistory').and.returnValue(observableOf(['/login', '/login']));
       spyOn(routerStub, 'navigateByUrl');
       authService.redirectAfterLoginSuccess(true);
@@ -271,7 +287,7 @@ describe('AuthService test', () => {
       expect(routerStub.navigateByUrl).toHaveBeenCalledWith('/');
     });
 
-    it ('should redirect to / when no redirect url is found', () => {
+    it('should redirect to / when no redirect url is found', () => {
       spyOn(routeServiceMock, 'getHistory').and.returnValue(observableOf(['']));
       spyOn(routerStub, 'navigateByUrl');
       authService.redirectAfterLoginSuccess(true);
diff --git a/src/app/core/auth/auth.service.ts b/src/app/core/auth/auth.service.ts
index a53631352191149704521a446c8c4f3d96f76c67..fd5c98f789ced42ca8362c4d846bdaa3791d4e33 100644
--- a/src/app/core/auth/auth.service.ts
+++ b/src/app/core/auth/auth.service.ts
@@ -4,7 +4,7 @@ import { HttpHeaders } from '@angular/common/http';
 import { REQUEST, RESPONSE } from '@nguniversal/express-engine/tokens';
 
 import { Observable, of as observableOf } from 'rxjs';
-import { distinctUntilChanged, filter, map, startWith, switchMap, take, withLatestFrom } from 'rxjs/operators';
+import { distinctUntilChanged, filter, map, startWith, take, withLatestFrom } from 'rxjs/operators';
 import { RouterReducerState } from '@ngrx/router-store';
 import { select, Store } from '@ngrx/store';
 import { CookieAttributes } from 'js-cookie';
@@ -21,8 +21,9 @@ import { AppState, routerStateSelector } from '../../app.reducer';
 import { ResetAuthenticationMessagesAction, SetRedirectUrlAction } from './auth.actions';
 import { NativeWindowRef, NativeWindowService } from '../services/window.service';
 import { Base64EncodeUrl } from '../../shared/utils/encode-decode.util';
-import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
-import {RouteService} from '../services/route.service';
+import { RouteService } from '../services/route.service';
+import { EPersonDataService } from '../eperson/eperson-data.service';
+import { getFirstSucceededRemoteDataPayload } from '../shared/operators';
 
 export const LOGIN_ROUTE = '/login';
 export const LOGOUT_ROUTE = '/logout';
@@ -43,13 +44,13 @@ export class AuthService {
 
   constructor(@Inject(REQUEST) protected req: any,
               @Inject(NativeWindowService) protected _window: NativeWindowRef,
-              protected authRequestService: AuthRequestService,
               @Optional() @Inject(RESPONSE) private response: any,
+              protected authRequestService: AuthRequestService,
+              protected epersonService: EPersonDataService,
               protected router: Router,
               protected routeService: RouteService,
               protected storage: CookieService,
-              protected store: Store<AppState>,
-              protected rdbService: RemoteDataBuildService
+              protected store: Store<AppState>
   ) {
     this.store.pipe(
       select(isAuthenticated),
@@ -122,10 +123,10 @@ export class AuthService {
   }
 
   /**
-   * Returns the authenticated user
-   * @returns {User}
+   * Returns the href link to authenticated user
+   * @returns {string}
    */
-  public authenticatedUser(token: AuthTokenInfo): Observable<EPerson> {
+  public authenticatedUser(token: AuthTokenInfo): Observable<string> {
     // Determine if the user has an existing auth session on the server
     const options: HttpOptions = Object.create({});
     let headers = new HttpHeaders();
@@ -133,16 +134,25 @@ export class AuthService {
     headers = headers.append('Authorization', `Bearer ${token.accessToken}`);
     options.headers = headers;
     return this.authRequestService.getRequest('status', options).pipe(
-      map((status) => this.rdbService.build(status)),
-      switchMap((status: AuthStatus) => {
+      map((status: AuthStatus) => {
         if (status.authenticated) {
-          return status.eperson.pipe(map((eperson) => eperson.payload));
+          return status._links.eperson.href;
         } else {
           throw(new Error('Not authenticated'));
         }
       }))
   }
 
+  /**
+   * Returns the authenticated user
+   * @returns {User}
+   */
+  public retrieveAuthenticatedUserByHref(userHref: string): Observable<EPerson> {
+    return this.epersonService.findByHref(userHref).pipe(
+      getFirstSucceededRemoteDataPayload()
+    )
+  }
+
   /**
    * Checks if token is present into browser storage and is valid. (NB Check is done only on SSR)
    */
diff --git a/src/app/core/auth/models/auth-status.model.ts b/src/app/core/auth/models/auth-status.model.ts
index e0d568397a5cf1d612e1d57ac8eaffc3a744db6f..edad46a7bcc3dc1987f7b53a6f7f920ebdefcc18 100644
--- a/src/app/core/auth/models/auth-status.model.ts
+++ b/src/app/core/auth/models/auth-status.model.ts
@@ -1,54 +1,83 @@
-import { AuthError } from './auth-error.model';
-import { AuthTokenInfo } from './auth-token-info.model';
-import { EPerson } from '../../eperson/models/eperson.model';
-import { RemoteData } from '../../data/remote-data';
+import { autoserialize, deserialize, deserializeAs } from 'cerialize';
 import { Observable } from 'rxjs';
+import { link, typedObject } from '../../cache/builders/build-decorators';
+import { IDToUUIDSerializer } from '../../cache/id-to-uuid-serializer';
 import { CacheableObject } from '../../cache/object-cache.reducer';
+import { RemoteData } from '../../data/remote-data';
+import { EPerson } from '../../eperson/models/eperson.model';
+import { EPERSON } from '../../eperson/models/eperson.resource-type';
+import { HALLink } from '../../shared/hal-link.model';
 import { ResourceType } from '../../shared/resource-type';
+import { excludeFromEquals } from '../../utilities/equals.decorators';
+import { AuthError } from './auth-error.model';
+import { AUTH_STATUS } from './auth-status.resource-type';
+import { AuthTokenInfo } from './auth-token-info.model';
 
 /**
  * Object that represents the authenticated status of a user
  */
+@typedObject
 export class AuthStatus implements CacheableObject {
-  static type = new ResourceType('status');
+  static type = AUTH_STATUS;
 
   /**
    * The unique identifier of this auth status
    */
+  @autoserialize
   id: string;
 
   /**
-   * The unique uuid of this auth status
+   * The type for this AuthStatus
    */
+  @excludeFromEquals
+  @autoserialize
+  type: ResourceType;
+
+  /**
+   * The UUID of this auth status
+   * This UUID is generated client-side and isn't used by the backend.
+   * It is based on the ID, so it will be the same for each refresh.
+   */
+  @deserializeAs(new IDToUUIDSerializer('auth-status'), 'id')
   uuid: string;
 
   /**
    * True if REST API is up and running, should never return false
    */
+  @autoserialize
   okay: boolean;
 
   /**
    * If the auth status represents an authenticated state
    */
+  @autoserialize
   authenticated: boolean;
 
   /**
-   * Authentication error if there was one for this status
+   * The {@link HALLink}s for this AuthStatus
    */
-  error?: AuthError;
+  @deserialize
+  _links: {
+    self: HALLink;
+    eperson: HALLink;
+  };
 
   /**
-   * The eperson of this auth status
+   * The EPerson of this auth status
+   * Will be undefined unless the eperson {@link HALLink} has been resolved.
    */
-  eperson: Observable<RemoteData<EPerson>>;
+  @link(EPERSON)
+  eperson?: Observable<RemoteData<EPerson>>;
 
   /**
    * True if the token is valid, false if there was no token or the token wasn't valid
    */
+  @autoserialize
   token?: AuthTokenInfo;
 
   /**
-   * The self link of this auth status' REST object
+   * Authentication error if there was one for this status
    */
-  self: string;
+  // TODO should be refactored to use the RemoteData error
+  error?: AuthError;
 }
diff --git a/src/app/core/auth/models/auth-status.resource-type.ts b/src/app/core/auth/models/auth-status.resource-type.ts
new file mode 100644
index 0000000000000000000000000000000000000000..2b7c7252fc8eb6a768a6c1731a42c5b18df5d743
--- /dev/null
+++ b/src/app/core/auth/models/auth-status.resource-type.ts
@@ -0,0 +1,9 @@
+import { ResourceType } from '../../shared/resource-type';
+
+/**
+ * The resource type for AuthStatus
+ *
+ * Needs to be in a separate file to prevent circular
+ * dependencies in webpack.
+ */
+export const AUTH_STATUS = new ResourceType('status');
diff --git a/src/app/core/auth/models/normalized-auth-status.model.ts b/src/app/core/auth/models/normalized-auth-status.model.ts
deleted file mode 100644
index 3892bee408a8ed3f3bb388e7b06d7b10f26da7f6..0000000000000000000000000000000000000000
--- a/src/app/core/auth/models/normalized-auth-status.model.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-import { AuthStatus } from './auth-status.model';
-import { autoserialize, autoserializeAs, inheritSerialization } from 'cerialize';
-import { mapsTo, relationship } from '../../cache/builders/build-decorators';
-import { NormalizedObject } from '../../cache/models/normalized-object.model';
-import { IDToUUIDSerializer } from '../../cache/id-to-uuid-serializer';
-import { EPerson } from '../../eperson/models/eperson.model';
-
-@mapsTo(AuthStatus)
-@inheritSerialization(NormalizedObject)
-export class NormalizedAuthStatus extends NormalizedObject<AuthStatus> {
-  /**
-   * The unique identifier of this auth status
-   */
-  @autoserialize
-  id: string;
-
-  /**
-   * The unique generated uuid of this auth status
-   */
-  @autoserializeAs(new IDToUUIDSerializer('auth-status'), 'id')
-  uuid: string;
-
-  /**
-   * True if REST API is up and running, should never return false
-   */
-  @autoserialize
-  okay: boolean;
-
-  /**
-   * True if the token is valid, false if there was no token or the token wasn't valid
-   */
-  @autoserialize
-  authenticated: boolean;
-
-  /**
-   * The self link to the eperson of this auth status
-   */
-  @relationship(EPerson, false)
-  @autoserialize
-  eperson: string;
-}
diff --git a/src/app/core/auth/server-auth.service.ts b/src/app/core/auth/server-auth.service.ts
index cf4d4a658e8aaedc39e5f99ab765151d89c1e9c2..c8cba0206b41f6895dd8a92b914401101a24b420 100644
--- a/src/app/core/auth/server-auth.service.ts
+++ b/src/app/core/auth/server-auth.service.ts
@@ -1,15 +1,14 @@
-import { filter, map, switchMap, take } from 'rxjs/operators';
+import { HttpHeaders } from '@angular/common/http';
 import { Injectable } from '@angular/core';
 
 import { Observable } from 'rxjs';
-import { HttpHeaders } from '@angular/common/http';
+import { filter, map, take } from 'rxjs/operators';
+import { isNotEmpty } from '../../shared/empty.util';
 import { HttpOptions } from '../dspace-rest-v2/dspace-rest-v2.service';
+import { CheckAuthenticationTokenAction } from './auth.actions';
+import { AuthService } from './auth.service';
 import { AuthStatus } from './models/auth-status.model';
-import { isEmpty, isNotEmpty } from '../../shared/empty.util';
-import { AuthService, LOGIN_ROUTE } from './auth.service';
 import { AuthTokenInfo } from './models/auth-token-info.model';
-import { CheckAuthenticationTokenAction } from './auth.actions';
-import { EPerson } from '../eperson/models/eperson.model';
 
 /**
  * The auth service.
@@ -21,7 +20,7 @@ export class ServerAuthService extends AuthService {
    * Returns the authenticated user
    * @returns {User}
    */
-  public authenticatedUser(token: AuthTokenInfo): Observable<EPerson> {
+  public authenticatedUser(token: AuthTokenInfo): Observable<string> {
     // Determine if the user has an existing auth session on the server
     const options: HttpOptions = Object.create({});
     let headers = new HttpHeaders();
@@ -34,10 +33,9 @@ export class ServerAuthService extends AuthService {
 
     options.headers = headers;
     return this.authRequestService.getRequest('status', options).pipe(
-      map((status) => this.rdbService.build(status)),
-      switchMap((status: AuthStatus) => {
+      map((status: AuthStatus) => {
         if (status.authenticated) {
-          return status.eperson.pipe(map((eperson) => eperson.payload));
+          return status._links.eperson.href;
         } else {
           throw(new Error('Not authenticated'));
         }
diff --git a/src/app/core/breadcrumbs/breadcrumbs.service.ts b/src/app/core/breadcrumbs/breadcrumbs.service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f274485d5df8b69eb173ad4452ca728208c861c6
--- /dev/null
+++ b/src/app/core/breadcrumbs/breadcrumbs.service.ts
@@ -0,0 +1,15 @@
+import { Breadcrumb } from '../../breadcrumbs/breadcrumb/breadcrumb.model';
+import { Observable } from 'rxjs';
+
+/**
+ * Service to calculate breadcrumbs for a single part of the route
+ */
+export interface BreadcrumbsService<T> {
+
+  /**
+   * Method to calculate the breadcrumbs for a part of the route
+   * @param key The key used to resolve the breadcrumb
+   * @param url The url to use as a link for this breadcrumb
+   */
+  getBreadcrumbs(key: T, url: string): Observable<Breadcrumb[]>;
+}
diff --git a/src/app/core/breadcrumbs/collection-breadcrumb.resolver.ts b/src/app/core/breadcrumbs/collection-breadcrumb.resolver.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d9df7cd767ca5febe807fd2c2389f02cd2e3fe84
--- /dev/null
+++ b/src/app/core/breadcrumbs/collection-breadcrumb.resolver.ts
@@ -0,0 +1,29 @@
+import { Injectable } from '@angular/core';
+import { DSOBreadcrumbsService } from './dso-breadcrumbs.service';
+import { DSOBreadcrumbResolver } from './dso-breadcrumb.resolver';
+import { Collection } from '../shared/collection.model';
+import { CollectionDataService } from '../data/collection-data.service';
+import { followLink, FollowLinkConfig } from '../../shared/utils/follow-link-config.model';
+
+/**
+ * The class that resolves the BreadcrumbConfig object for a Collection
+ */
+@Injectable()
+export class CollectionBreadcrumbResolver extends DSOBreadcrumbResolver<Collection> {
+  constructor(protected breadcrumbService: DSOBreadcrumbsService, protected dataService: CollectionDataService) {
+    super(breadcrumbService, dataService);
+  }
+
+  /**
+   * Method that returns the follow links to already resolve
+   * The self links defined in this list are expected to be requested somewhere in the near future
+   * Requesting them as embeds will limit the number of requests
+   */
+  get followLinks(): Array<FollowLinkConfig<Collection>> {
+    return [
+      followLink('parentCommunity', undefined,
+        followLink('parentCommunity')
+      )
+    ];
+  }
+}
diff --git a/src/app/core/breadcrumbs/community-breadcrumb.resolver.ts b/src/app/core/breadcrumbs/community-breadcrumb.resolver.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d1f21455f25219685ac9ec3b0528ced4c0245b17
--- /dev/null
+++ b/src/app/core/breadcrumbs/community-breadcrumb.resolver.ts
@@ -0,0 +1,27 @@
+import { Injectable } from '@angular/core';
+import { DSOBreadcrumbsService } from './dso-breadcrumbs.service';
+import { DSOBreadcrumbResolver } from './dso-breadcrumb.resolver';
+import { CommunityDataService } from '../data/community-data.service';
+import { Community } from '../shared/community.model';
+import { followLink, FollowLinkConfig } from '../../shared/utils/follow-link-config.model';
+
+/**
+ * The class that resolves the BreadcrumbConfig object for a Community
+ */
+@Injectable()
+export class CommunityBreadcrumbResolver extends DSOBreadcrumbResolver<Community> {
+  constructor(protected breadcrumbService: DSOBreadcrumbsService, protected dataService: CommunityDataService) {
+    super(breadcrumbService, dataService);
+  }
+
+  /**
+   * Method that returns the follow links to already resolve
+   * The self links defined in this list are expected to be requested somewhere in the near future
+   * Requesting them as embeds will limit the number of requests
+   */
+  get followLinks(): Array<FollowLinkConfig<Community>> {
+    return [
+      followLink('parentCommunity')
+    ];
+  }
+}
diff --git a/src/app/core/breadcrumbs/dso-breadcrumb.resolver.spec.ts b/src/app/core/breadcrumbs/dso-breadcrumb.resolver.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..2a0005f548c76f0850c87338ae3e10309e0ab669
--- /dev/null
+++ b/src/app/core/breadcrumbs/dso-breadcrumb.resolver.spec.ts
@@ -0,0 +1,35 @@
+import { DSOBreadcrumbResolver } from './dso-breadcrumb.resolver';
+import { Collection } from '../shared/collection.model';
+import { createSuccessfulRemoteDataObject$ } from '../../shared/testing/utils';
+import { getTestScheduler } from 'jasmine-marbles';
+import { CollectionBreadcrumbResolver } from './collection-breadcrumb.resolver';
+
+describe('DSOBreadcrumbResolver', () => {
+  describe('resolve', () => {
+    let resolver: DSOBreadcrumbResolver<Collection>;
+    let collectionService: any;
+    let dsoBreadcrumbService: any;
+    let testCollection: Collection;
+    let uuid;
+    let breadcrumbUrl;
+    let currentUrl;
+
+    beforeEach(() => {
+      uuid = '1234-65487-12354-1235';
+      breadcrumbUrl = '/collections/' + uuid;
+      currentUrl = breadcrumbUrl + '/edit';
+      testCollection = Object.assign(new Collection(), { uuid });
+      dsoBreadcrumbService = {};
+      collectionService = {
+        findById: (id: string) => createSuccessfulRemoteDataObject$(testCollection)
+      };
+      resolver = new CollectionBreadcrumbResolver(dsoBreadcrumbService, collectionService);
+    });
+
+    it('should resolve a breadcrumb config for the correct DSO', () => {
+      const resolvedConfig = resolver.resolve({ params: { id: uuid } } as any, { url: currentUrl } as any);
+      const expectedConfig = { provider: dsoBreadcrumbService, key: testCollection, url: breadcrumbUrl };
+      getTestScheduler().expectObservable(resolvedConfig).toBe('(a|)', { a: expectedConfig})
+    });
+  });
+});
diff --git a/src/app/core/breadcrumbs/dso-breadcrumb.resolver.ts b/src/app/core/breadcrumbs/dso-breadcrumb.resolver.ts
new file mode 100644
index 0000000000000000000000000000000000000000..80e68a16f5c0623db5798fd256a9abdc813a8dcd
--- /dev/null
+++ b/src/app/core/breadcrumbs/dso-breadcrumb.resolver.ts
@@ -0,0 +1,46 @@
+import { BreadcrumbConfig } from '../../breadcrumbs/breadcrumb/breadcrumb-config.model';
+import { Injectable } from '@angular/core';
+import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot } from '@angular/router';
+import { DSOBreadcrumbsService } from './dso-breadcrumbs.service';
+import { DataService } from '../data/data.service';
+import { getRemoteDataPayload, getSucceededRemoteData } from '../shared/operators';
+import { map } from 'rxjs/operators';
+import { Observable } from 'rxjs';
+import { DSpaceObject } from '../shared/dspace-object.model';
+import { ChildHALResource } from '../shared/child-hal-resource.model';
+import { FollowLinkConfig } from '../../shared/utils/follow-link-config.model';
+
+/**
+ * The class that resolves the BreadcrumbConfig object for a DSpaceObject
+ */
+@Injectable()
+export abstract class DSOBreadcrumbResolver<T extends ChildHALResource & DSpaceObject> implements Resolve<BreadcrumbConfig<T>> {
+  constructor(protected breadcrumbService: DSOBreadcrumbsService, protected dataService: DataService<T>) {
+  }
+
+  /**
+   * Method for resolving a breadcrumb config object
+   * @param {ActivatedRouteSnapshot} route The current ActivatedRouteSnapshot
+   * @param {RouterStateSnapshot} state The current RouterStateSnapshot
+   * @returns BreadcrumbConfig object
+   */
+  resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<BreadcrumbConfig<T>> {
+    const uuid = route.params.id;
+    return this.dataService.findById(uuid, ...this.followLinks).pipe(
+      getSucceededRemoteData(),
+      getRemoteDataPayload(),
+      map((object: T) => {
+        const fullPath = state.url;
+        const url = fullPath.substr(0, fullPath.indexOf(uuid)) + uuid;
+        return { provider: this.breadcrumbService, key: object, url: url };
+      })
+    );
+  }
+
+  /**
+   * Method that returns the follow links to already resolve
+   * The self links defined in this list are expected to be requested somewhere in the near future
+   * Requesting them as embeds will limit the number of requests
+   */
+  abstract get followLinks(): Array<FollowLinkConfig<T>>;
+}
diff --git a/src/app/core/breadcrumbs/dso-breadcrumbs.service.spec.ts b/src/app/core/breadcrumbs/dso-breadcrumbs.service.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..101545cb141d3bebeecbd74add5a3fa43f83e234
--- /dev/null
+++ b/src/app/core/breadcrumbs/dso-breadcrumbs.service.spec.ts
@@ -0,0 +1,122 @@
+import { async, TestBed } from '@angular/core/testing';
+import { DSOBreadcrumbsService } from './dso-breadcrumbs.service';
+import { getMockLinkService } from '../../shared/mocks/mock-link-service';
+import { LinkService } from '../cache/builders/link.service';
+import { Item } from '../shared/item.model';
+import { createSuccessfulRemoteDataObject, createSuccessfulRemoteDataObject$ } from '../../shared/testing/utils';
+import { DSpaceObject } from '../shared/dspace-object.model';
+import { of as observableOf } from 'rxjs';
+import { Community } from '../shared/community.model';
+import { Collection } from '../shared/collection.model';
+import { Breadcrumb } from '../../breadcrumbs/breadcrumb/breadcrumb.model';
+import { getTestScheduler } from 'jasmine-marbles';
+import { getDSOPath } from '../../app-routing.module';
+import { DSONameService } from './dso-name.service';
+
+describe('DSOBreadcrumbsService', () => {
+  let service: DSOBreadcrumbsService;
+  let linkService: any;
+  let testItem;
+  let testCollection;
+  let testCommunity;
+
+  let itemPath;
+  let collectionPath;
+  let communityPath;
+
+  let itemUUID;
+  let collectionUUID;
+  let communityUUID;
+
+  let dsoNameService;
+
+  function init() {
+    itemPath = '/items/';
+    collectionPath = '/collection/';
+    communityPath = '/community/';
+
+    itemUUID = '04dd18fc-03f9-4b9a-9304-ed7c313686d3';
+    collectionUUID = '91dfa5b5-5440-4fb4-b869-02610342f886';
+    communityUUID = '6c0bfa6b-ce82-4bf4-a2a8-fd7682c567e8';
+
+    testCommunity = Object.assign(new Community(),
+      {
+        type: 'community',
+        metadata: {
+          'dc.title': [{value: 'community'}]
+        },
+        uuid: communityUUID,
+        parentCommunity: observableOf(Object.assign(createSuccessfulRemoteDataObject(undefined), { statusCode: 204 })),
+
+        _links: {
+          parentCommunity: 'site',
+          self: communityPath + communityUUID
+        }
+      }
+    );
+
+    testCollection = Object.assign(new Collection(),
+      {
+        type: 'collection',
+        metadata: {
+          'dc.title': [{value: 'collection'}]
+        },
+        uuid: collectionUUID,
+        parentCommunity: createSuccessfulRemoteDataObject$(testCommunity),
+        _links: {
+          parentCommunity: communityPath + communityUUID,
+          self: communityPath + collectionUUID
+        }
+      }
+    );
+
+    testItem = Object.assign(new Item(),
+      {
+        type: 'item',
+        metadata: {
+          'dc.title': [{value: 'item'}]
+        },
+        uuid: itemUUID,
+        owningCollection: createSuccessfulRemoteDataObject$(testCollection),
+        _links: {
+          owningCollection: collectionPath + collectionUUID,
+          self: itemPath + itemUUID
+        }
+      }
+    );
+
+    dsoNameService = { getName: (dso) => getName(dso) }
+  }
+
+  beforeEach(async(() => {
+    init();
+    TestBed.configureTestingModule({
+      providers: [
+        { provide: LinkService, useValue: getMockLinkService() },
+        { provide: DSONameService, useValue: dsoNameService }
+      ]
+    }).compileComponents();
+  }));
+
+  beforeEach(() => {
+    linkService = TestBed.get(LinkService);
+    linkService.resolveLink.and.callFake((object, link) => object);
+    service = new DSOBreadcrumbsService(linkService, dsoNameService);
+  });
+
+  describe('getBreadcrumbs', () => {
+    it('should return the breadcrumbs based on an Item', () => {
+      const breadcrumbs = service.getBreadcrumbs(testItem, testItem._links.self);
+      const expectedCrumbs = [
+        new Breadcrumb(getName(testCommunity), getDSOPath(testCommunity)),
+        new Breadcrumb(getName(testCollection), getDSOPath(testCollection)),
+        new Breadcrumb(getName(testItem), getDSOPath(testItem)),
+      ];
+      getTestScheduler().expectObservable(breadcrumbs).toBe('(a|)', { a: expectedCrumbs });
+    })
+  });
+
+  function getName(dso: DSpaceObject): string {
+    return dso.metadata['dc.title'][0].value
+  }
+});
diff --git a/src/app/core/breadcrumbs/dso-breadcrumbs.service.ts b/src/app/core/breadcrumbs/dso-breadcrumbs.service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..3cb73be876346a419300eaa0870b0b3de1b04f23
--- /dev/null
+++ b/src/app/core/breadcrumbs/dso-breadcrumbs.service.ts
@@ -0,0 +1,50 @@
+import { Breadcrumb } from '../../breadcrumbs/breadcrumb/breadcrumb.model';
+import { BreadcrumbsService } from './breadcrumbs.service';
+import { DSONameService } from './dso-name.service';
+import { Observable, of as observableOf } from 'rxjs';
+import { ChildHALResource } from '../shared/child-hal-resource.model';
+import { LinkService } from '../cache/builders/link.service';
+import { DSpaceObject } from '../shared/dspace-object.model';
+import { followLink } from '../../shared/utils/follow-link-config.model';
+import { find, map, switchMap } from 'rxjs/operators';
+import { getDSOPath } from '../../app-routing.module';
+import { RemoteData } from '../data/remote-data';
+import { hasValue } from '../../shared/empty.util';
+import { Injectable } from '@angular/core';
+
+/**
+ * Service to calculate DSpaceObject breadcrumbs for a single part of the route
+ */
+@Injectable()
+export class DSOBreadcrumbsService implements BreadcrumbsService<ChildHALResource & DSpaceObject> {
+  constructor(
+    private linkService: LinkService,
+    private dsoNameService: DSONameService
+  ) {
+
+  }
+
+  /**
+   * Method to recursively calculate the breadcrumbs
+   * This method returns the name and url of the key and all its parent DSO's recursively, top down
+   * @param key The key (a DSpaceObject) used to resolve the breadcrumb
+   * @param url The url to use as a link for this breadcrumb
+   */
+  getBreadcrumbs(key: ChildHALResource & DSpaceObject, url: string): Observable<Breadcrumb[]> {
+    const label = this.dsoNameService.getName(key);
+    const crumb = new Breadcrumb(label, url);
+    const propertyName = key.getParentLinkKey();
+    return this.linkService.resolveLink(key, followLink(propertyName))[propertyName].pipe(
+      find((parentRD: RemoteData<ChildHALResource & DSpaceObject>) => parentRD.hasSucceeded || parentRD.statusCode === 204),
+      switchMap((parentRD: RemoteData<ChildHALResource & DSpaceObject>) => {
+        if (hasValue(parentRD.payload)) {
+          const parent = parentRD.payload;
+          return this.getBreadcrumbs(parent, getDSOPath(parent))
+        }
+        return observableOf([]);
+
+      }),
+      map((breadcrumbs: Breadcrumb[]) => [...breadcrumbs, crumb])
+    );
+  }
+}
diff --git a/src/app/core/breadcrumbs/dso-name.service.spec.ts b/src/app/core/breadcrumbs/dso-name.service.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..aa06116ed5fcf3aff15497534a04660d83dc014f
--- /dev/null
+++ b/src/app/core/breadcrumbs/dso-name.service.spec.ts
@@ -0,0 +1,116 @@
+import { ListableObject } from '../../shared/object-collection/shared/listable-object.model';
+import { DSpaceObject } from '../shared/dspace-object.model';
+import { GenericConstructor } from '../shared/generic-constructor';
+import { Item } from '../shared/item.model';
+import { MetadataValueFilter } from '../shared/metadata.models';
+import { DSONameService } from './dso-name.service';
+
+describe(`DSONameService`, () => {
+  let service: DSONameService;
+  let mockPersonName: string;
+  let mockPerson: DSpaceObject;
+  let mockOrgUnitName: string;
+  let mockOrgUnit: DSpaceObject;
+  let mockDSOName: string;
+  let mockDSO: DSpaceObject;
+
+  beforeEach(() => {
+    mockPersonName = 'Doe, John';
+    mockPerson = Object.assign(new DSpaceObject(), {
+      firstMetadataValue(keyOrKeys: string | string[], valueFilter?: MetadataValueFilter): string {
+        return mockPersonName
+      },
+      getRenderTypes(): Array<string | GenericConstructor<ListableObject>> {
+        return ['Person', Item, DSpaceObject];
+      }
+    });
+
+    mockOrgUnitName = 'Molecular Spectroscopy';
+    mockOrgUnit = Object.assign(new DSpaceObject(), {
+      firstMetadataValue(keyOrKeys: string | string[], valueFilter?: MetadataValueFilter): string {
+        return mockOrgUnitName
+      },
+      getRenderTypes(): Array<string | GenericConstructor<ListableObject>> {
+        return ['OrgUnit', Item, DSpaceObject];
+      }
+    });
+
+    mockDSOName = 'Lorem Ipsum';
+    mockDSO = Object.assign(new DSpaceObject(), {
+      firstMetadataValue(keyOrKeys: string | string[], valueFilter?: MetadataValueFilter): string {
+        return mockDSOName
+      },
+      getRenderTypes(): Array<string | GenericConstructor<ListableObject>> {
+        return [DSpaceObject];
+      }
+    });
+
+    service = new DSONameService();
+  });
+
+  describe(`getName`, () => {
+    it(`should use the Person factory for Person entities`, () => {
+      spyOn((service as any).factories, 'Person').and.returnValue('Bingo!');
+
+      const result = service.getName(mockPerson);
+
+      expect((service as any).factories.Person).toHaveBeenCalledWith(mockPerson);
+      expect(result).toBe('Bingo!');
+    });
+
+    it(`should use the OrgUnit factory for OrgUnit entities`, () => {
+      spyOn((service as any).factories, 'OrgUnit').and.returnValue('Bingo!');
+
+      const result = service.getName(mockOrgUnit);
+
+      expect((service as any).factories.OrgUnit).toHaveBeenCalledWith(mockOrgUnit);
+      expect(result).toBe('Bingo!');
+    });
+
+    it(`should use the Default factory for regular DSpaceObjects`, () => {
+      spyOn((service as any).factories, 'Default').and.returnValue('Bingo!');
+
+      const result = service.getName(mockDSO);
+
+      expect((service as any).factories.Default).toHaveBeenCalledWith(mockDSO);
+      expect(result).toBe('Bingo!');
+    });
+  });
+
+  describe(`factories.Person`, () => {
+    beforeEach(() => {
+      spyOn(mockPerson, 'firstMetadataValue').and.returnValues(...mockPersonName.split(', '));
+    });
+
+    it(`should return 'person.familyName, person.givenName'`, () => {
+      const result = (service as any).factories.Person(mockPerson);
+      expect(result).toBe(mockPersonName);
+      expect(mockPerson.firstMetadataValue).toHaveBeenCalledWith('person.familyName');
+      expect(mockPerson.firstMetadataValue).toHaveBeenCalledWith('person.givenName');
+    });
+  });
+
+  describe(`factories.OrgUnit`, () => {
+    beforeEach(() => {
+      spyOn(mockOrgUnit, 'firstMetadataValue').and.callThrough();
+    });
+
+    it(`should return 'organization.legalName'`, () => {
+      const result = (service as any).factories.OrgUnit(mockOrgUnit);
+      expect(result).toBe(mockOrgUnitName);
+      expect(mockOrgUnit.firstMetadataValue).toHaveBeenCalledWith('organization.legalName');
+    });
+  });
+
+  describe(`factories.Default`, () => {
+    beforeEach(() => {
+      spyOn(mockDSO, 'firstMetadataValue').and.callThrough();
+    });
+
+    it(`should return 'dc.title'`, () => {
+      const result = (service as any).factories.Default(mockDSO);
+      expect(result).toBe(mockDSOName);
+      expect(mockDSO.firstMetadataValue).toHaveBeenCalledWith('dc.title');
+    });
+  });
+});
diff --git a/src/app/core/breadcrumbs/dso-name.service.ts b/src/app/core/breadcrumbs/dso-name.service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..161c4f72542a8a2f7665274093e7ff0af9d5e95b
--- /dev/null
+++ b/src/app/core/breadcrumbs/dso-name.service.ts
@@ -0,0 +1,53 @@
+import { Injectable } from '@angular/core';
+import { hasValue } from '../../shared/empty.util';
+import { DSpaceObject } from '../shared/dspace-object.model';
+
+/**
+ * Returns a name for a {@link DSpaceObject} based
+ * on its render types.
+ */
+@Injectable({
+  providedIn: 'root'
+})
+export class DSONameService {
+
+  /**
+   * Functions to generate the specific names.
+   *
+   * If this list ever expands it will probably be worth it to
+   * refactor this using decorators for specific entity types,
+   * or perhaps by using a dedicated model for each entity type
+   *
+   * With only two exceptions those solutions seem overkill for now.
+   */
+  private factories = {
+    Person: (dso: DSpaceObject): string => {
+      return `${dso.firstMetadataValue('person.familyName')}, ${dso.firstMetadataValue('person.givenName')}`;
+    },
+    OrgUnit: (dso: DSpaceObject): string => {
+      return dso.firstMetadataValue('organization.legalName');
+    },
+    Default: (dso: DSpaceObject): string => {
+      return dso.firstMetadataValue('dc.title');
+    }
+  };
+
+  /**
+   * Get the name for the given {@link DSpaceObject}
+   *
+   * @param dso  The {@link DSpaceObject} you want a name for
+   */
+  getName(dso: DSpaceObject): string {
+    const types = dso.getRenderTypes();
+    const match = types
+      .filter((type) => typeof type === 'string')
+      .find((type: string) => Object.keys(this.factories).includes(type)) as string;
+
+    if (hasValue(match)) {
+      return this.factories[match](dso);
+    } else {
+      return  this.factories.Default(dso);
+    }
+  }
+
+}
diff --git a/src/app/core/breadcrumbs/i18n-breadcrumb.resolver.spec.ts b/src/app/core/breadcrumbs/i18n-breadcrumb.resolver.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d34d6d8a9b8188bdf7127d5138aa1ca3e5aa9d28
--- /dev/null
+++ b/src/app/core/breadcrumbs/i18n-breadcrumb.resolver.spec.ts
@@ -0,0 +1,28 @@
+import { I18nBreadcrumbResolver } from './i18n-breadcrumb.resolver';
+
+describe('I18nBreadcrumbResolver', () => {
+  describe('resolve', () => {
+    let resolver: I18nBreadcrumbResolver;
+    let i18nBreadcrumbService: any;
+    let i18nKey: string;
+    let path: string;
+    beforeEach(() => {
+      i18nKey = 'example.key';
+      path = 'rest.com/path/to/breadcrumb';
+      i18nBreadcrumbService = {};
+      resolver = new I18nBreadcrumbResolver(i18nBreadcrumbService);
+    });
+
+    it('should resolve the breadcrumb config', () => {
+      const resolvedConfig = resolver.resolve({ data: { breadcrumbKey: i18nKey }, url: [path] } as any, {} as any);
+      const expectedConfig = { provider: i18nBreadcrumbService, key: i18nKey, url: path };
+      expect(resolvedConfig).toEqual(expectedConfig);
+    });
+
+    it('should resolve throw an error when no breadcrumbKey is defined', () => {
+      expect(() => {
+        resolver.resolve({ data: {} } as any, undefined)
+      }).toThrow();
+    });
+  });
+});
diff --git a/src/app/core/breadcrumbs/i18n-breadcrumb.resolver.ts b/src/app/core/breadcrumbs/i18n-breadcrumb.resolver.ts
new file mode 100644
index 0000000000000000000000000000000000000000..de7d061a3f9070b23927dca5f98d349c6426bb91
--- /dev/null
+++ b/src/app/core/breadcrumbs/i18n-breadcrumb.resolver.ts
@@ -0,0 +1,29 @@
+import { BreadcrumbConfig } from '../../breadcrumbs/breadcrumb/breadcrumb-config.model';
+import { Injectable } from '@angular/core';
+import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot } from '@angular/router';
+import { I18nBreadcrumbsService } from './i18n-breadcrumbs.service';
+import { hasNoValue } from '../../shared/empty.util';
+
+/**
+ * The class that resolves a BreadcrumbConfig object with an i18n key string for a route
+ */
+@Injectable()
+export class I18nBreadcrumbResolver implements Resolve<BreadcrumbConfig<string>> {
+  constructor(protected breadcrumbService: I18nBreadcrumbsService) {
+  }
+
+  /**
+   * Method for resolving an I18n breadcrumb configuration object
+   * @param {ActivatedRouteSnapshot} route The current ActivatedRouteSnapshot
+   * @param {RouterStateSnapshot} state The current RouterStateSnapshot
+   * @returns BreadcrumbConfig object
+   */
+  resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): BreadcrumbConfig<string> {
+    const key = route.data.breadcrumbKey;
+    if (hasNoValue(key)) {
+      throw new Error('You provided an i18nBreadcrumbResolver for url \"' + route.url + '\" but no breadcrumbKey in the route\'s data')
+    }
+    const fullPath = route.url.join('');
+    return { provider: this.breadcrumbService, key: key, url: fullPath };
+  }
+}
diff --git a/src/app/core/breadcrumbs/i18n-breadcrumbs.service.spec.ts b/src/app/core/breadcrumbs/i18n-breadcrumbs.service.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..274389db3bbe737f4a8ce7f87f5a8c7a318ece56
--- /dev/null
+++ b/src/app/core/breadcrumbs/i18n-breadcrumbs.service.spec.ts
@@ -0,0 +1,31 @@
+import { async, TestBed } from '@angular/core/testing';
+import { Breadcrumb } from '../../breadcrumbs/breadcrumb/breadcrumb.model';
+import { getTestScheduler } from 'jasmine-marbles';
+import { BREADCRUMB_MESSAGE_POSTFIX, I18nBreadcrumbsService } from './i18n-breadcrumbs.service';
+
+describe('I18nBreadcrumbsService', () => {
+  let service: I18nBreadcrumbsService;
+  let exampleString;
+  let exampleURL;
+
+  function init() {
+    exampleString = 'example.string';
+    exampleURL = 'example.com';
+  }
+
+  beforeEach(async(() => {
+    init();
+    TestBed.configureTestingModule({}).compileComponents();
+  }));
+
+  beforeEach(() => {
+    service = new I18nBreadcrumbsService();
+  });
+
+  describe('getBreadcrumbs', () => {
+    it('should return a breadcrumb based on a string by adding the postfix', () => {
+      const breadcrumbs = service.getBreadcrumbs(exampleString, exampleURL);
+      getTestScheduler().expectObservable(breadcrumbs).toBe('(a|)', { a: [new Breadcrumb(exampleString + BREADCRUMB_MESSAGE_POSTFIX, exampleURL)] });
+    })
+  });
+});
diff --git a/src/app/core/breadcrumbs/i18n-breadcrumbs.service.ts b/src/app/core/breadcrumbs/i18n-breadcrumbs.service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e07d9ed5417440476d315f5c65ebb8fd5700c86d
--- /dev/null
+++ b/src/app/core/breadcrumbs/i18n-breadcrumbs.service.ts
@@ -0,0 +1,25 @@
+import { Breadcrumb } from '../../breadcrumbs/breadcrumb/breadcrumb.model';
+import { BreadcrumbsService } from './breadcrumbs.service';
+import { Observable, of as observableOf } from 'rxjs';
+import { Injectable } from '@angular/core';
+
+/**
+ * The postfix for i18n breadcrumbs
+ */
+export const BREADCRUMB_MESSAGE_POSTFIX = '.breadcrumbs';
+
+/**
+ * Service to calculate i18n breadcrumbs for a single part of the route
+ */
+@Injectable()
+export class I18nBreadcrumbsService implements BreadcrumbsService<string> {
+
+  /**
+   * Method to calculate the breadcrumbs
+   * @param key The key used to resolve the breadcrumb
+   * @param url The url to use as a link for this breadcrumb
+   */
+  getBreadcrumbs(key: string, url: string): Observable<Breadcrumb[]> {
+    return observableOf([new Breadcrumb(key + BREADCRUMB_MESSAGE_POSTFIX, url)]);
+  }
+}
diff --git a/src/app/core/breadcrumbs/item-breadcrumb.resolver.ts b/src/app/core/breadcrumbs/item-breadcrumb.resolver.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8390c0e001d4dcbdab7b5653c3915712998cbea7
--- /dev/null
+++ b/src/app/core/breadcrumbs/item-breadcrumb.resolver.ts
@@ -0,0 +1,32 @@
+import { Injectable } from '@angular/core';
+import { DSOBreadcrumbsService } from './dso-breadcrumbs.service';
+import { ItemDataService } from '../data/item-data.service';
+import { Item } from '../shared/item.model';
+import { DSOBreadcrumbResolver } from './dso-breadcrumb.resolver';
+import { followLink, FollowLinkConfig } from '../../shared/utils/follow-link-config.model';
+
+/**
+ * The class that resolves the BreadcrumbConfig object for an Item
+ */
+@Injectable()
+export class ItemBreadcrumbResolver extends DSOBreadcrumbResolver<Item> {
+  constructor(protected breadcrumbService: DSOBreadcrumbsService, protected dataService: ItemDataService) {
+    super(breadcrumbService, dataService);
+  }
+
+  /**
+   * Method that returns the follow links to already resolve
+   * The self links defined in this list are expected to be requested somewhere in the near future
+   * Requesting them as embeds will limit the number of requests
+   */
+  get followLinks(): Array<FollowLinkConfig<Item>> {
+    return [
+      followLink('owningCollection', undefined,
+        followLink('parentCommunity', undefined,
+          followLink('parentCommunity'))
+      ),
+      followLink('bundles'),
+      followLink('relationships')
+    ];
+  }
+}
diff --git a/src/app/core/browse/browse.service.spec.ts b/src/app/core/browse/browse.service.spec.ts
index 55ff7a090ea03f8301a8e0a18a7c43b6a48e2ed5..6dafa4cf0a74ddf5eef0604ef30dda37181da65d 100644
--- a/src/app/core/browse/browse.service.spec.ts
+++ b/src/app/core/browse/browse.service.spec.ts
@@ -1,16 +1,16 @@
 import { cold, getTestScheduler, hot } from 'jasmine-marbles';
+import { of as observableOf } from 'rxjs';
 import { TestScheduler } from 'rxjs/testing';
 import { getMockRemoteDataBuildService } from '../../shared/mocks/mock-remote-data-build.service';
 import { getMockRequestService } from '../../shared/mocks/mock-request.service';
 import { HALEndpointServiceStub } from '../../shared/testing/hal-endpoint-service-stub';
 import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
 import { BrowseEndpointRequest, BrowseEntriesRequest, BrowseItemsRequest } from '../data/request.models';
+import { RequestEntry } from '../data/request.reducer';
 import { RequestService } from '../data/request.service';
 import { BrowseDefinition } from '../shared/browse-definition.model';
-import { BrowseService } from './browse.service';
 import { BrowseEntrySearchOptions } from './browse-entry-search-options.model';
-import { RequestEntry } from '../data/request.reducer';
-import { of as observableOf } from 'rxjs';
+import { BrowseService } from './browse.service';
 
 describe('BrowseService', () => {
   let scheduler: TestScheduler;
@@ -44,8 +44,8 @@ describe('BrowseService', () => {
         'dc.date.issued'
       ],
       _links: {
-        self: 'https://rest.api/discover/browses/dateissued',
-        items: 'https://rest.api/discover/browses/dateissued/items'
+        self: { href: 'https://rest.api/discover/browses/dateissued' },
+        items: { href: 'https://rest.api/discover/browses/dateissued/items' }
       }
     }),
     Object.assign(new BrowseDefinition(), {
@@ -72,9 +72,9 @@ describe('BrowseService', () => {
         'dc.creator'
       ],
       _links: {
-        self: 'https://rest.api/discover/browses/author',
-        entries: 'https://rest.api/discover/browses/author/entries',
-        items: 'https://rest.api/discover/browses/author/items'
+        self: { href: 'https://rest.api/discover/browses/author' },
+        entries: { href: 'https://rest.api/discover/browses/author/entries' },
+        items: { href: 'https://rest.api/discover/browses/author/items' }
       }
     })
   ];
@@ -125,9 +125,11 @@ describe('BrowseService', () => {
     });
 
     it('should return a RemoteData object containing the correct BrowseDefinition[]', () => {
-      const expected = cold('--a-', { a: {
-        payload: browseDefinitions
-      }});
+      const expected = cold('--a-', {
+        a: {
+          payload: browseDefinitions
+        }
+      });
 
       expect(service.getBrowseDefinitions()).toBeObservable(expected);
     });
@@ -142,15 +144,17 @@ describe('BrowseService', () => {
       rdbService = getMockRemoteDataBuildService();
       service = initTestService();
       spyOn(service, 'getBrowseDefinitions').and
-        .returnValue(hot('--a-', { a: {
+        .returnValue(hot('--a-', {
+          a: {
             payload: browseDefinitions
-          }}));
+          }
+        }));
       spyOn(rdbService, 'toRemoteDataObservable').and.callThrough();
     });
 
     describe('when getBrowseEntriesFor is called with a valid browse definition id', () => {
       it('should configure a new BrowseEntriesRequest', () => {
-        const expected = new BrowseEntriesRequest(requestService.generateRequestId(), browseDefinitions[1]._links.entries);
+        const expected = new BrowseEntriesRequest(requestService.generateRequestId(), browseDefinitions[1]._links.entries.href);
 
         scheduler.schedule(() => service.getBrowseEntriesFor(new BrowseEntrySearchOptions(browseDefinitions[1].id)).subscribe());
         scheduler.flush();
@@ -169,7 +173,7 @@ describe('BrowseService', () => {
 
     describe('when getBrowseItemsFor is called with a valid browse definition id', () => {
       it('should configure a new BrowseItemsRequest', () => {
-        const expected = new BrowseItemsRequest(requestService.generateRequestId(), browseDefinitions[1]._links.items + '?filterValue=' + mockAuthorName);
+        const expected = new BrowseItemsRequest(requestService.generateRequestId(), browseDefinitions[1]._links.items.href + '?filterValue=' + mockAuthorName);
 
         scheduler.schedule(() => service.getBrowseItemsFor(mockAuthorName, new BrowseEntrySearchOptions(browseDefinitions[1].id)).subscribe());
         scheduler.flush();
@@ -215,9 +219,11 @@ describe('BrowseService', () => {
         rdbService = getMockRemoteDataBuildService();
         service = initTestService();
         spyOn(service, 'getBrowseDefinitions').and
-          .returnValue(hot('--a-', { a: {
+          .returnValue(hot('--a-', {
+            a: {
               payload: browseDefinitions
-            }}));
+            }
+          }));
       });
 
       it('should return the URL for the given metadataKey and linkPath', () => {
@@ -288,14 +294,16 @@ describe('BrowseService', () => {
       rdbService = getMockRemoteDataBuildService();
       service = initTestService();
       spyOn(service, 'getBrowseDefinitions').and
-        .returnValue(hot('--a-', { a: {
+        .returnValue(hot('--a-', {
+          a: {
             payload: browseDefinitions
-          }}));
+          }
+        }));
       spyOn(rdbService, 'toRemoteDataObservable').and.callThrough();
     });
 
     describe('when getFirstItemFor is called with a valid browse definition id', () => {
-      const expectedURL = browseDefinitions[1]._links.items + '?page=0&size=1';
+      const expectedURL = browseDefinitions[1]._links.items.href + '?page=0&size=1';
 
       it('should configure a new BrowseItemsRequest', () => {
         const expected = new BrowseItemsRequest(requestService.generateRequestId(), expectedURL);
diff --git a/src/app/core/browse/browse.service.ts b/src/app/core/browse/browse.service.ts
index eb494d7bdb5572e6ccc4b05670a769b6cb79cc69..78e63e8540cd71ca8b1f9382fb6636c92c9c8b58 100644
--- a/src/app/core/browse/browse.service.ts
+++ b/src/app/core/browse/browse.service.ts
@@ -10,18 +10,16 @@ import {
   isNotEmptyOperator
 } from '../../shared/empty.util';
 import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
+import { GenericSuccessResponse } from '../cache/response.models';
 import { PaginatedList } from '../data/paginated-list';
 import { RemoteData } from '../data/remote-data';
-import {
-  BrowseEndpointRequest,
-  BrowseEntriesRequest,
-  BrowseItemsRequest,
-  RestRequest
-} from '../data/request.models';
+import { BrowseEndpointRequest, BrowseEntriesRequest, BrowseItemsRequest, RestRequest } from '../data/request.models';
 import { RequestService } from '../data/request.service';
 import { BrowseDefinition } from '../shared/browse-definition.model';
 import { BrowseEntry } from '../shared/browse-entry.model';
+import { DSpaceObject } from '../shared/dspace-object.model';
 import { HALEndpointService } from '../shared/hal-endpoint.service';
+import { Item } from '../shared/item.model';
 import {
   configureRequest,
   filterSuccessfulResponses,
@@ -31,10 +29,7 @@ import {
   getRequestFromRequestHref
 } from '../shared/operators';
 import { URLCombiner } from '../url-combiner/url-combiner';
-import { Item } from '../shared/item.model';
-import { DSpaceObject } from '../shared/dspace-object.model';
 import { BrowseEntrySearchOptions } from './browse-entry-search-options.model';
-import { GenericSuccessResponse } from '../cache/response.models';
 
 /**
  * The service handling all browse requests
@@ -81,10 +76,11 @@ export class BrowseService {
       map((response: GenericSuccessResponse<BrowseDefinition[]>) => response.payload),
       ensureArrayHasValue(),
       map((definitions: BrowseDefinition[]) => definitions
-        .map((definition: BrowseDefinition) => Object.assign(new BrowseDefinition(), definition))),
-      distinctUntilChanged()
+        .map((definition: BrowseDefinition) => {
+          return Object.assign(new BrowseDefinition(), definition)
+        })),
+      distinctUntilChanged(),
     );
-
     return this.rdb.toRemoteDataObservable(requestEntry$, payload$);
   }
 
@@ -96,7 +92,10 @@ export class BrowseService {
     return this.getBrowseDefinitions().pipe(
       getBrowseDefinitionLinks(options.metadataDefinition),
       hasValueOperator(),
-      map((_links: any) => _links.entries),
+      map((_links: any) => {
+        const entriesLink = _links.entries.href || _links.entries;
+        return entriesLink;
+      }),
       hasValueOperator(),
       map((href: string) => {
         // TODO nearly identical to PaginatedSearchOptions => refactor
@@ -133,7 +132,10 @@ export class BrowseService {
     return this.getBrowseDefinitions().pipe(
       getBrowseDefinitionLinks(options.metadataDefinition),
       hasValueOperator(),
-      map((_links: any) => _links.items),
+      map((_links: any) => {
+        const itemsLink = _links.items.href || _links.items;
+        return itemsLink;
+      }),
       hasValueOperator(),
       map((href: string) => {
         const args = [];
@@ -171,7 +173,10 @@ export class BrowseService {
     return this.getBrowseDefinitions().pipe(
       getBrowseDefinitionLinks(definition),
       hasValueOperator(),
-      map((_links: any) => _links.items),
+      map((_links: any) => {
+        const itemsLink = _links.items.href || _links.items;
+        return itemsLink;
+      }),
       hasValueOperator(),
       map((href: string) => {
         const args = [];
@@ -249,7 +254,7 @@ export class BrowseService {
         if (isEmpty(def) || isEmpty(def._links) || isEmpty(def._links[linkPath])) {
           throw new Error(`A browse endpoint for ${linkPath} on ${metadataKey} isn't configured`);
         } else {
-          return def._links[linkPath];
+          return def._links[linkPath] || def._links[linkPath].href;
         }
       }),
       startWith(undefined),
diff --git a/src/app/core/cache/builders/build-decorators.spec.ts b/src/app/core/cache/builders/build-decorators.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e47cf1a80ac7e18af4dbfcba86e179fe13bfaa2f
--- /dev/null
+++ b/src/app/core/cache/builders/build-decorators.spec.ts
@@ -0,0 +1,83 @@
+import { HALLink } from '../../shared/hal-link.model';
+import { HALResource } from '../../shared/hal-resource.model';
+import { ResourceType } from '../../shared/resource-type';
+import {
+  dataService,
+  getDataServiceFor,
+  getLinkDefinition,
+  link,
+} from './build-decorators';
+
+/* tslint:disable:max-classes-per-file */
+class TestService {}
+class AnotherTestService {}
+class TestHALResource implements HALResource {
+  _links: {
+    self: HALLink;
+    foo: HALLink;
+  };
+
+  bar?: any
+}
+let testType;
+
+describe('build decorators', () => {
+  beforeEach(() => {
+    testType = new ResourceType('testType-' + new Date().getTime());
+  });
+  describe('@dataService/getDataServiceFor', () => {
+
+    it('should register a resourcetype for a dataservice', () => {
+      dataService(testType)(TestService);
+      expect(getDataServiceFor(testType)).toBe(TestService);
+    });
+
+    describe(`when the resource type isn't specified`, () => {
+      it(`should throw an error`, () => {
+        expect(() => {
+          dataService(undefined)(TestService);
+        }).toThrow();
+      });
+    });
+
+    describe(`when there already is a registered dataservice for a resourcetype`, () => {
+      it(`should throw an error`, () => {
+        dataService(testType)(TestService);
+        expect(() => {
+          dataService(testType)(AnotherTestService);
+        }).toThrow();
+      });
+    });
+
+  });
+
+  describe(`@link/getLinkDefinitions`, () => {
+    it(`should register a link`, () => {
+      const target = new TestHALResource();
+      link(testType, true, 'foo')(target, 'bar');
+      const result = getLinkDefinition(TestHALResource, 'foo');
+      expect(result.resourceType).toBe(testType);
+      expect(result.isList).toBe(true);
+      expect(result.linkName).toBe('foo');
+      expect(result.propertyName).toBe('bar');
+    });
+
+    describe(`when the linkname isn't specified`, () => {
+      it(`should use the propertyname`, () => {
+        const target = new TestHALResource();
+        link(testType)(target, 'foo');
+        const result = getLinkDefinition(TestHALResource, 'foo');
+        expect(result.linkName).toBe('foo');
+        expect(result.propertyName).toBe('foo');
+      });
+    });
+
+    describe(`when there's no @link`, () => {
+      it(`should return undefined`, () => {
+        const result = getLinkDefinition(TestHALResource, 'self');
+        expect(result).toBeUndefined();
+      });
+    });
+  });
+});
+/* tslint:enable:max-classes-per-file */
diff --git a/src/app/core/cache/builders/build-decorators.ts b/src/app/core/cache/builders/build-decorators.ts
index 0bfb5f0321b6a52c39e074eac643e0702cb12016..4ba04bfa5507e2c0961e60488eb508c80bf94e49 100644
--- a/src/app/core/cache/builders/build-decorators.ts
+++ b/src/app/core/cache/builders/build-decorators.ts
@@ -1,80 +1,161 @@
 import 'reflect-metadata';
+import { hasNoValue, hasValue } from '../../../shared/empty.util';
+import { DataService } from '../../data/data.service';
 
 import { GenericConstructor } from '../../shared/generic-constructor';
-import { CacheableObject, TypedObject } from '../object-cache.reducer';
+import { HALResource } from '../../shared/hal-resource.model';
 import { ResourceType } from '../../shared/resource-type';
+import { CacheableObject, TypedObject } from '../object-cache.reducer';
 
-const mapsToMetadataKey = Symbol('mapsTo');
-const relationshipKey = Symbol('relationship');
+const resolvedLinkKey = Symbol('resolvedLink');
 
-const relationshipMap = new Map();
+const resolvedLinkMap = new Map();
 const typeMap = new Map();
+const dataServiceMap = new Map();
+const linkMap = new Map();
 
 /**
- * Decorator function to map a normalized class to it's not-normalized counter part class
- * It will also maps a type to the matching class
- * @param value The not-normalized class to map to
- */
-export function mapsTo(value: GenericConstructor<TypedObject>) {
-  return function decorator(objectConstructor: GenericConstructor<TypedObject>) {
-    Reflect.defineMetadata(mapsToMetadataKey, value, objectConstructor);
-    mapsToType((value as any).type, objectConstructor);
-  }
-}
-
-/**
- * Maps a type to the matching class
- * @param value The resourse type
- * @param objectConstructor The class to map to
- */
-function mapsToType(value: ResourceType, objectConstructor: GenericConstructor<TypedObject>) {
-  if (!objectConstructor || !value) {
-    return;
-  }
-  typeMap.set(value.value, objectConstructor);
-}
-
-/**
- * Returns the mapped class for the given normalized class
- * @param target The normalized class
+ * Decorator function to map a ResourceType to its class
+ * @param target The contructor of the typed class to map
  */
-export function getMapsTo(target: any) {
-  return Reflect.getOwnMetadata(mapsToMetadataKey, target);
+export function typedObject(target: typeof TypedObject) {
+  typeMap.set(target.type.value, target);
 }
 
 /**
  * Returns the mapped class for the given type
  * @param type The resource type
  */
-export function getMapsToType(type: string | ResourceType) {
+export function getClassForType(type: string | ResourceType) {
   if (typeof(type) === 'object') {
     type = (type as ResourceType).value;
   }
   return typeMap.get(type);
 }
 
-export function relationship<T extends CacheableObject>(value: GenericConstructor<T>, isList: boolean = false): any {
-  return function r(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
-    if (!target || !propertyKey) {
-      return;
+/**
+ * A class decorator to indicate that this class is a dataservice
+ * for a given resource type.
+ *
+ * "dataservice" in this context means that it has findByHref and
+ * findAllByHref methods.
+ *
+ * @param resourceType the resource type the class is a dataservice for
+ */
+export function dataService(resourceType: ResourceType): any {
+  return (target: any) => {
+    if (hasNoValue(resourceType)) {
+      throw new Error(`Invalid @dataService annotation on ${target}, resourceType needs to be defined`);
     }
+    const existingDataservice = dataServiceMap.get(resourceType.value);
 
-    const metaDataList: string[] = relationshipMap.get(target.constructor) || [];
-    if (metaDataList.indexOf(propertyKey) === -1) {
-      metaDataList.push(propertyKey);
+    if (hasValue(existingDataservice)) {
+      throw new Error(`Multiple dataservices for ${resourceType.value}: ${existingDataservice} and ${target}`);
     }
-    relationshipMap.set(target.constructor, metaDataList);
-    return Reflect.metadata(relationshipKey, {
-      resourceType: (value as any).type.value,
-      isList
-    }).apply(this, arguments);
+
+    dataServiceMap.set(resourceType.value, target);
   };
 }
 
-export function getRelationMetadata(target: any, propertyKey: string) {
-  return Reflect.getMetadata(relationshipKey, target, propertyKey);
+/**
+ * Return the dataservice matching the given resource type
+ *
+ * @param resourceType the resource type you want the matching dataservice for
+ */
+export function getDataServiceFor<T extends CacheableObject>(resourceType: ResourceType) {
+  return dataServiceMap.get(resourceType.value);
 }
 
-export function getRelationships(target: any) {
-  return relationshipMap.get(target);
+/**
+ * A class to represent the data that can be set by the @link decorator
+ */
+export class LinkDefinition<T extends HALResource> {
+  resourceType: ResourceType;
+  isList = false;
+  linkName: keyof T['_links'];
+  propertyName: keyof T;
+}
+
+/**
+ * A property decorator to indicate that a certain property is the placeholder
+ * where the contents of a resolved link should be stored.
+ *
+ * e.g. if an Item has an hal link for bundles, and an item.bundles property
+ * this decorator should decorate that item.bundles property.
+ *
+ * @param resourceType the resource type of the object(s) the link retrieves
+ * @param isList an optional boolean indicating whether or not it concerns a list,
+ * defaults to false
+ * @param linkName an optional string in case the {@link HALLink} name differs from the
+ * property name
+ */
+export const link = <T extends HALResource>(
+  resourceType: ResourceType,
+  isList = false,
+  linkName?: keyof T['_links'],
+  ) => {
+  return (target: T, propertyName: string) => {
+    let targetMap = linkMap.get(target.constructor);
+
+    if (hasNoValue(targetMap)) {
+      targetMap = new Map<keyof T['_links'],LinkDefinition<T>>();
+    }
+
+    if (hasNoValue(linkName)) {
+      linkName = propertyName as any;
+    }
+
+    targetMap.set(linkName, {
+      resourceType,
+      isList,
+      linkName,
+      propertyName
+    });
+
+    linkMap.set(target.constructor, targetMap);
+  }
+};
+
+/**
+ * Returns all LinkDefinitions for a model class
+ * @param source
+ */
+export const getLinkDefinitions = <T extends HALResource>(source: GenericConstructor<T>): Map<keyof T['_links'], LinkDefinition<T>> => {
+  return linkMap.get(source);
+};
+
+/**
+ * Returns a specific LinkDefinition for a model class
+ *
+ * @param source the model class
+ * @param linkName the name of the link
+ */
+export const getLinkDefinition = <T extends HALResource>(source: GenericConstructor<T>, linkName: keyof T['_links']): LinkDefinition<T> => {
+  const sourceMap = linkMap.get(source);
+  if (hasValue(sourceMap)) {
+    return sourceMap.get(linkName);
+  } else {
+    return undefined;
+  }
+};
+
+/**
+ * A class level decorator to indicate you want to inherit @link annotations
+ * from a parent class.
+ *
+ * @param parent the parent class to inherit @link annotations from
+ */
+export function inheritLinkAnnotations(parent: any): any {
+  return (child: any) => {
+    const parentMap: Map<string, LinkDefinition<any>> = linkMap.get(parent) || new Map();
+    const childMap: Map<string, LinkDefinition<any>> = linkMap.get(child) || new Map();
+
+    parentMap.forEach((value, key) => {
+      if (!childMap.has(key)) {
+        childMap.set(key, value);
+      }
+    });
+
+    linkMap.set(child, childMap);
+  }
 }
diff --git a/src/app/core/cache/builders/link.service.spec.ts b/src/app/core/cache/builders/link.service.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..dbd65eefb5eb7c07937cca193227e17c46df050b
--- /dev/null
+++ b/src/app/core/cache/builders/link.service.spec.ts
@@ -0,0 +1,269 @@
+import { Injectable } from '@angular/core';
+import { TestBed } from '@angular/core/testing';
+import { followLink, FollowLinkConfig } from '../../../shared/utils/follow-link-config.model';
+import { FindListOptions } from '../../data/request.models';
+import { HALLink } from '../../shared/hal-link.model';
+import { HALResource } from '../../shared/hal-resource.model';
+import { ResourceType } from '../../shared/resource-type';
+import * as decorators from './build-decorators';
+import { getDataServiceFor } from './build-decorators';
+import { LinkService } from './link.service';
+
+const spyOnFunction = <T>(obj: T, func: keyof T) => {
+  const spy = jasmine.createSpy(func as string);
+  spyOnProperty(obj, func, 'get').and.returnValue(spy);
+
+  return spy;
+};
+
+const TEST_MODEL = new ResourceType('testmodel');
+let result: any;
+
+/* tslint:disable:max-classes-per-file */
+class TestModel implements HALResource {
+  static type = TEST_MODEL;
+
+  type = TEST_MODEL;
+
+  value: string;
+
+  _links: {
+    self: HALLink;
+    predecessor: HALLink;
+    successor: HALLink;
+  };
+
+  predecessor?: TestModel;
+  successor?: TestModel;
+}
+
+@Injectable()
+class TestDataService {
+  findAllByHref(href: string, findListOptions: FindListOptions = {}, ...linksToFollow: Array<FollowLinkConfig<any>>) {
+    return 'findAllByHref'
+  }
+  findByHref(href: string, ...linksToFollow: Array<FollowLinkConfig<any>>) {
+    return 'findByHref'
+  }
+}
+
+let testDataService: TestDataService;
+
+let testModel: TestModel;
+
+describe('LinkService', () => {
+  let service: LinkService;
+
+  beforeEach(() => {
+    testModel = Object.assign(new TestModel(), {
+      value: 'a test value',
+      _links: {
+        self: {
+          href: 'http://self.link'
+        },
+        predecessor: {
+          href: 'http://predecessor.link'
+        },
+        successor: {
+          href: 'http://successor.link'
+        },
+      }
+    });
+    testDataService = new TestDataService();
+    spyOn(testDataService, 'findAllByHref').and.callThrough();
+    spyOn(testDataService, 'findByHref').and.callThrough();
+    TestBed.configureTestingModule({
+      providers: [LinkService, {
+        provide: TestDataService,
+        useValue: testDataService
+      }]
+    });
+    service = TestBed.get(LinkService);
+  });
+
+  describe('resolveLink', () => {
+    describe(`when the linkdefinition concerns a single object`, () => {
+      beforeEach(() => {
+        spyOnFunction(decorators, 'getLinkDefinition').and.returnValue({
+          resourceType: TEST_MODEL,
+          linkName: 'predecessor',
+          propertyName: 'predecessor'
+        });
+        spyOnFunction(decorators, 'getDataServiceFor').and.returnValue(TestDataService);
+        service.resolveLink(testModel, followLink('predecessor', {}, followLink('successor')))
+      });
+      it('should call dataservice.findByHref with the correct href and nested links', () => {
+        expect(testDataService.findByHref).toHaveBeenCalledWith(testModel._links.predecessor.href, followLink('successor'));
+      });
+    });
+    describe(`when the linkdefinition concerns a list`, () => {
+      beforeEach(() => {
+        spyOnFunction(decorators, 'getLinkDefinition').and.returnValue({
+          resourceType: TEST_MODEL,
+          linkName: 'predecessor',
+          propertyName: 'predecessor',
+          isList: true
+        });
+        spyOnFunction(decorators, 'getDataServiceFor').and.returnValue(TestDataService);
+        service.resolveLink(testModel, followLink('predecessor', { some: 'options '} as any, followLink('successor')))
+      });
+      it('should call dataservice.findAllByHref with the correct href, findListOptions,  and nested links', () => {
+        expect(testDataService.findAllByHref).toHaveBeenCalledWith(testModel._links.predecessor.href, { some: 'options '} as any, followLink('successor'));
+      });
+    });
+    describe('either way', () => {
+      beforeEach(() => {
+        spyOnFunction(decorators, 'getLinkDefinition').and.returnValue({
+          resourceType: TEST_MODEL,
+          linkName: 'predecessor',
+          propertyName: 'predecessor'
+        });
+        spyOnFunction(decorators, 'getDataServiceFor').and.returnValue(TestDataService);
+        result = service.resolveLink(testModel, followLink('predecessor', {}, followLink('successor')))
+      });
+
+      it('should call getLinkDefinition with the correct model and link', () => {
+        expect(decorators.getLinkDefinition).toHaveBeenCalledWith(testModel.constructor as any, 'predecessor');
+      });
+
+      it('should call getDataServiceFor with the correct resource type', () => {
+        expect(decorators.getDataServiceFor).toHaveBeenCalledWith(TEST_MODEL);
+      });
+
+      it('should return the model with the resolved link', () => {
+        expect(result.type).toBe(TEST_MODEL);
+        expect(result.value).toBe('a test value');
+        expect(result._links.self.href).toBe('http://self.link');
+        expect(result.predecessor).toBe('findByHref');
+      });
+    });
+
+    describe(`when the specified link doesn't exist on the model's class`, () => {
+      beforeEach(() => {
+        spyOnFunction(decorators, 'getLinkDefinition').and.returnValue(undefined);
+      });
+      it('should throw an error', () => {
+        expect(() => {
+          service.resolveLink(testModel, followLink('predecessor', {}, followLink('successor')))
+        }).toThrow();
+      });
+    });
+
+    describe(`when there is no dataservice for the resourcetype in the link`, () => {
+      beforeEach(() => {
+        spyOnFunction(decorators, 'getLinkDefinition').and.returnValue({
+          resourceType: TEST_MODEL,
+          linkName: 'predecessor',
+          propertyName: 'predecessor'
+        });
+        spyOnFunction(decorators, 'getDataServiceFor').and.returnValue(undefined);
+      });
+      it('should throw an error', () => {
+        expect(() => {
+          service.resolveLink(testModel, followLink('predecessor', {}, followLink('successor')))
+        }).toThrow();
+      });
+    });
+  });
+
+  describe('resolveLinks', () => {
+    beforeEach(() => {
+      spyOn(service, 'resolveLink');
+      service.resolveLinks(testModel, followLink('predecessor'), followLink('successor'))
+    });
+
+    it('should call resolveLink with the model for each of the provided links', () => {
+      expect(service.resolveLink).toHaveBeenCalledWith(testModel, followLink('predecessor'));
+      expect(service.resolveLink).toHaveBeenCalledWith(testModel, followLink('successor'));
+    });
+
+    it('should return the model', () => {
+      expect(result.type).toBe(TEST_MODEL);
+      expect(result.value).toBe('a test value');
+      expect(result._links.self.href).toBe('http://self.link');
+    });
+  });
+
+  describe('removeResolvedLinks', () => {
+    beforeEach(() => {
+      testModel.predecessor = 'predecessor value' as any;
+      testModel.successor = 'successor value' as any;
+      spyOnFunction(decorators, 'getLinkDefinitions').and.returnValue([
+        {
+          resourceType: TEST_MODEL,
+          linkName: 'predecessor',
+          propertyName: 'predecessor',
+        },
+        {
+          resourceType: TEST_MODEL,
+          linkName: 'successor',
+          propertyName: 'successor',
+        }
+      ])
+    });
+
+    it('should return a new version of the object without any resolved links', () => {
+      result = service.removeResolvedLinks(testModel);
+      expect(result.value).toBe(testModel.value);
+      expect(result.type).toBe(testModel.type);
+      expect(result._links).toBe(testModel._links);
+      expect(result.predecessor).toBeUndefined();
+      expect(result.successor).toBeUndefined();
+    });
+
+    it('should leave the original object untouched', () => {
+      service.removeResolvedLinks(testModel);
+      expect(testModel.predecessor as any).toBe('predecessor value');
+      expect(testModel.successor as any).toBe('successor value');
+    });
+  });
+
+  describe('when a link is missing', () => {
+    beforeEach(() => {
+      testModel = Object.assign(new TestModel(), {
+        value: 'a test value',
+        _links: {
+          self: {
+            href: 'http://self.link'
+          },
+          predecessor: {
+            href: 'http://predecessor.link'
+          }
+        }
+      });
+      spyOnFunction(decorators, 'getDataServiceFor').and.returnValue(TestDataService);
+    });
+
+    describe('resolving the available link', () => {
+      beforeEach(() => {
+        spyOnFunction(decorators, 'getLinkDefinition').and.returnValue({
+          resourceType: TEST_MODEL,
+          linkName: 'predecessor',
+          propertyName: 'predecessor'
+        });
+        result = service.resolveLinks(testModel, followLink('predecessor'));
+      });
+
+      it('should return the model with the resolved link', () => {
+        expect(result.predecessor).toBe('findByHref');
+      });
+    });
+
+    describe('resolving the missing link', () => {
+      beforeEach(() => {
+        spyOnFunction(decorators, 'getLinkDefinition').and.returnValue({
+          resourceType: TEST_MODEL,
+          linkName: 'successor',
+          propertyName: 'successor'
+        });
+        result = service.resolveLinks(testModel, followLink('successor'));
+      });
+
+      it('should return the model with no resolved link', () => {
+        expect(result.successor).toBeUndefined();
+      });
+    });
+  });
+
+});
+/* tslint:enable:max-classes-per-file */
diff --git a/src/app/core/cache/builders/link.service.ts b/src/app/core/cache/builders/link.service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..dc65eab68fd1b2d34c25ec5abcbee7c0c902b9d5
--- /dev/null
+++ b/src/app/core/cache/builders/link.service.ts
@@ -0,0 +1,93 @@
+import { Injectable, Injector } from '@angular/core';
+import { hasNoValue, hasValue, isNotEmpty } from '../../../shared/empty.util';
+import { FollowLinkConfig } from '../../../shared/utils/follow-link-config.model';
+import { GenericConstructor } from '../../shared/generic-constructor';
+import { HALResource } from '../../shared/hal-resource.model';
+import { getDataServiceFor, getLinkDefinition, getLinkDefinitions, LinkDefinition } from './build-decorators';
+
+/**
+ * A Service to handle the resolving and removing
+ * of resolved {@link HALLink}s on HALResources
+ */
+@Injectable({
+  providedIn: 'root'
+})
+export class LinkService {
+
+  constructor(
+    protected parentInjector: Injector,
+  ) {
+  }
+
+  /**
+   * Resolve the given {@link FollowLinkConfig}s for the given model
+   *
+   * @param model the {@link HALResource} to resolve the links for
+   * @param linksToFollow the {@link FollowLinkConfig}s to resolve
+   */
+  public resolveLinks<T extends HALResource>(model: T, ...linksToFollow: Array<FollowLinkConfig<T>>): T {
+    linksToFollow.forEach((linkToFollow: FollowLinkConfig<T>) => {
+      this.resolveLink(model, linkToFollow);
+    });
+    return model;
+  }
+
+  /**
+   * Resolve the given {@link FollowLinkConfig} for the given model
+   *
+   * @param model the {@link HALResource} to resolve the link for
+   * @param linkToFollow the {@link FollowLinkConfig} to resolve
+   */
+  public resolveLink<T extends HALResource>(model, linkToFollow: FollowLinkConfig<T>): T {
+    const matchingLinkDef = getLinkDefinition(model.constructor, linkToFollow.name);
+
+    if (hasNoValue(matchingLinkDef)) {
+      throw new Error(`followLink('${linkToFollow.name}') was used for a ${model.constructor.name}, but there is no property on ${model.constructor.name} models with an @link() for ${linkToFollow.name}`);
+    } else {
+      const provider = getDataServiceFor(matchingLinkDef.resourceType);
+
+      if (hasNoValue(provider)) {
+        throw new Error(`The @link() for ${linkToFollow.name} on ${model.constructor.name} models uses the resource type ${matchingLinkDef.resourceType.value.toUpperCase()}, but there is no service with an @dataService(${matchingLinkDef.resourceType.value.toUpperCase()}) annotation in order to retrieve it`);
+      }
+
+      const service = Injector.create({
+        providers: [],
+        parent: this.parentInjector
+      }).get(provider);
+
+      const link = model._links[matchingLinkDef.linkName];
+      if (hasValue(link)) {
+        const href = link.href;
+
+        try {
+          if (matchingLinkDef.isList) {
+            model[linkToFollow.name] = service.findAllByHref(href, linkToFollow.findListOptions, ...linkToFollow.linksToFollow);
+          } else {
+            model[linkToFollow.name] = service.findByHref(href, ...linkToFollow.linksToFollow);
+          }
+        } catch (e) {
+          throw new Error(`Something went wrong when using @dataService(${matchingLinkDef.resourceType.value}) ${hasValue(service) ? '' : '(undefined) '}to resolve link ${linkToFollow.name} from ${href}`);
+        }
+      }
+    }
+    return model;
+  }
+
+  /**
+   * Remove any resolved links that the model may have.
+   *
+   * @param model the {@link HALResource} to remove the links from
+   * @returns a copy of the given model, without resolved links.
+   */
+  public removeResolvedLinks<T extends HALResource>(model: T): T {
+    const result = Object.assign(new (model.constructor as GenericConstructor<T>)(), model);
+    const linkDefs = getLinkDefinitions(model.constructor as GenericConstructor<T>);
+    if (isNotEmpty(linkDefs)) {
+      linkDefs.forEach((linkDef: LinkDefinition<T>) => {
+        result[linkDef.propertyName] = undefined;
+      });
+    }
+    return result;
+  }
+
+}
diff --git a/src/app/core/cache/builders/normalized-object-build.service.ts b/src/app/core/cache/builders/normalized-object-build.service.ts
deleted file mode 100644
index 69d7454d2df0e90492c2c49fe420a08c76cd9a07..0000000000000000000000000000000000000000
--- a/src/app/core/cache/builders/normalized-object-build.service.ts
+++ /dev/null
@@ -1,48 +0,0 @@
-import { Injectable } from '@angular/core';
-import { NormalizedObject } from '../models/normalized-object.model';
-import { getMapsToType, getRelationships } from './build-decorators';
-import { hasValue, isNotEmpty } from '../../../shared/empty.util';
-import { CacheableObject, TypedObject } from '../object-cache.reducer';
-
-/**
- * Return true if halObj has a value for `_links.self`
- *
- * @param {any} halObj The object to test
- */
-export function isRestDataObject(halObj: any): boolean {
-  return isNotEmpty(halObj._links) && hasValue(halObj._links.self);
-}
-
-/**
- * Return true if halObj has a value for `page` and  `_embedded`
- *
- * @param {any} halObj The object to test
- */
-export function isRestPaginatedList(halObj: any): boolean {
-  return hasValue(halObj.page) && hasValue(halObj._embedded);
-}
-
-/**
- * A service to turn domain models in to their normalized
- * counterparts.
- */
-@Injectable()
-export class NormalizedObjectBuildService {
-
-  /**
-   * Returns the normalized model that corresponds to the given domain model
-   *
-   * @param {TDomain} domainModel a domain model
-   */
-  normalize<T extends CacheableObject>(domainModel: T): NormalizedObject<T> {
-    const normalizedConstructor = getMapsToType((domainModel as any).type);
-    const relationships = getRelationships(normalizedConstructor) || [];
-    const normalizedModel = Object.assign({}, domainModel) as any;
-    relationships.forEach((key: string) => {
-      if (hasValue(normalizedModel[key])) {
-        normalizedModel[key] = normalizedModel._links[key];
-      }
-    });
-    return normalizedModel;
-  }
-}
diff --git a/src/app/core/cache/builders/remote-data-build.service.spec.ts b/src/app/core/cache/builders/remote-data-build.service.spec.ts
index 2f0e024521d3ad61b51038cecd3bb5fb494a8354..85267d7f4cd60a941fb5728e45cd8a39726447b0 100644
--- a/src/app/core/cache/builders/remote-data-build.service.spec.ts
+++ b/src/app/core/cache/builders/remote-data-build.service.spec.ts
@@ -1,10 +1,10 @@
-import { RemoteDataBuildService } from './remote-data-build.service';
-import { Item } from '../../shared/item.model';
-import { PaginatedList } from '../../data/paginated-list';
-import { PageInfo } from '../../shared/page-info.model';
-import { RemoteData } from '../../data/remote-data';
 import { of as observableOf } from 'rxjs';
 import { createSuccessfulRemoteDataObject } from '../../../shared/testing/utils';
+import { PaginatedList } from '../../data/paginated-list';
+import { RemoteData } from '../../data/remote-data';
+import { Item } from '../../shared/item.model';
+import { PageInfo } from '../../shared/page-info.model';
+import { RemoteDataBuildService } from './remote-data-build.service';
 
 const pageInfo = new PageInfo();
 const array = [
@@ -37,7 +37,7 @@ describe('RemoteDataBuildService', () => {
   let service: RemoteDataBuildService;
 
   beforeEach(() => {
-    service = new RemoteDataBuildService(undefined, undefined);
+    service = new RemoteDataBuildService(undefined, undefined, undefined);
   });
 
   describe('when toPaginatedList is called', () => {
diff --git a/src/app/core/cache/builders/remote-data-build.service.ts b/src/app/core/cache/builders/remote-data-build.service.ts
index 403a0273bc47235eb80fe23d9a22d642796c5beb..df895e11a242a3b37a2e44bfe44e531db602e650 100644
--- a/src/app/core/cache/builders/remote-data-build.service.ts
+++ b/src/app/core/cache/builders/remote-data-build.service.ts
@@ -1,36 +1,46 @@
 import { Injectable } from '@angular/core';
-
 import { combineLatest as observableCombineLatest, Observable, of as observableOf, race as observableRace } from 'rxjs';
-import { distinctUntilChanged, flatMap, map, startWith, switchMap, tap } from 'rxjs/operators';
-
-import { hasValue, hasValueOperator, isEmpty, isNotEmpty, isNotUndefined } from '../../../shared/empty.util';
+import { distinctUntilChanged, map, startWith, switchMap } from 'rxjs/operators';
+import {
+  hasValue,
+  hasValueOperator,
+  isEmpty,
+  isNotEmpty,
+  isNotUndefined
+} from '../../../shared/empty.util';
+import { createSuccessfulRemoteDataObject$ } from '../../../shared/testing/utils';
+import { FollowLinkConfig } from '../../../shared/utils/follow-link-config.model';
 import { PaginatedList } from '../../data/paginated-list';
 import { RemoteData } from '../../data/remote-data';
 import { RemoteDataError } from '../../data/remote-data-error';
-import { GetRequest } from '../../data/request.models';
 import { RequestEntry } from '../../data/request.reducer';
 import { RequestService } from '../../data/request.service';
-import { NormalizedObject } from '../models/normalized-object.model';
-import { ObjectCacheService } from '../object-cache.service';
-import { DSOSuccessResponse, ErrorResponse } from '../response.models';
-import { getMapsTo, getRelationMetadata, getRelationships } from './build-decorators';
-import { PageInfo } from '../../shared/page-info.model';
 import {
   filterSuccessfulResponses,
   getRequestFromRequestHref,
   getRequestFromRequestUUID,
   getResourceLinksFromResponse
 } from '../../shared/operators';
-import { CacheableObject, TypedObject } from '../object-cache.reducer';
-import { createSuccessfulRemoteDataObject$ } from '../../../shared/testing/utils';
+import { PageInfo } from '../../shared/page-info.model';
+import { CacheableObject } from '../object-cache.reducer';
+import { ObjectCacheService } from '../object-cache.service';
+import { DSOSuccessResponse, ErrorResponse } from '../response.models';
+import { LinkService } from './link.service';
 
 @Injectable()
 export class RemoteDataBuildService {
   constructor(protected objectCache: ObjectCacheService,
+              protected linkService: LinkService,
               protected requestService: RequestService) {
   }
 
-  buildSingle<T extends CacheableObject>(href$: string | Observable<string>): Observable<RemoteData<T>> {
+  /**
+   * Creates a single {@link RemoteData} object based on the response of a request to the REST server, with a list of
+   * {@link FollowLinkConfig} that indicate which embedded info should be added to the object
+   * @param href$             Observable href of object we want to retrieve
+   * @param linksToFollow     List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved
+   */
+  buildSingle<T extends CacheableObject>(href$: string | Observable<string>, ...linksToFollow: Array<FollowLinkConfig<T>>): Observable<RemoteData<T>> {
     if (typeof href$ === 'string') {
       href$ = observableOf(href$);
     }
@@ -70,9 +80,9 @@ export class RemoteDataBuildService {
           }
         }),
         hasValueOperator(),
-        map((normalized: NormalizedObject<T>) => {
-          return this.build<T>(normalized);
-        }),
+        map((obj: T) =>
+          this.linkService.resolveLinks(obj, ...linksToFollow)
+        ),
         startWith(undefined),
         distinctUntilChanged()
       );
@@ -86,13 +96,14 @@ export class RemoteDataBuildService {
         const responsePending = hasValue(reqEntry) && hasValue(reqEntry.responsePending) ? reqEntry.responsePending : false;
         let isSuccessful: boolean;
         let error: RemoteDataError;
-        if (hasValue(reqEntry) && hasValue(reqEntry.response)) {
-          isSuccessful = reqEntry.response.isSuccessful;
-          const errorMessage = isSuccessful === false ? (reqEntry.response as ErrorResponse).errorMessage : undefined;
+        const response = reqEntry ? reqEntry.response : undefined;
+        if (hasValue(response)) {
+          isSuccessful = response.isSuccessful;
+          const errorMessage = isSuccessful === false ? (response as ErrorResponse).errorMessage : undefined;
           if (hasValue(errorMessage)) {
             error = new RemoteDataError(
-              (reqEntry.response as ErrorResponse).statusCode,
-              (reqEntry.response as ErrorResponse).statusText,
+              response.statusCode,
+              response.statusText,
               errorMessage
             );
           }
@@ -102,13 +113,21 @@ export class RemoteDataBuildService {
           responsePending,
           isSuccessful,
           error,
-          payload
+          payload,
+          hasValue(response) ? response.statusCode : undefined
+
         );
       })
     );
   }
 
-  buildList<T extends CacheableObject>(href$: string | Observable<string>): Observable<RemoteData<PaginatedList<T>>> {
+  /**
+   * Creates a list of {@link RemoteData} objects based on the response of a request to the REST server, with a list of
+   * {@link FollowLinkConfig} that indicate which embedded info should be added to the objects
+   * @param href$             Observable href of objects we want to retrieve
+   * @param linksToFollow     List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved
+   */
+  buildList<T extends CacheableObject>(href$: string | Observable<string>, ...linksToFollow: Array<FollowLinkConfig<T>>): Observable<RemoteData<PaginatedList<T>>> {
     if (typeof href$ === 'string') {
       href$ = observableOf(href$);
     }
@@ -118,10 +137,10 @@ export class RemoteDataBuildService {
       getResourceLinksFromResponse(),
       switchMap((resourceUUIDs: string[]) => {
         return this.objectCache.getList(resourceUUIDs).pipe(
-          map((normList: Array<NormalizedObject<T>>) => {
-            return normList.map((normalized: NormalizedObject<T>) => {
-              return this.build<T>(normalized);
-            });
+          map((objs: T[]) => {
+            return objs.map((obj: T) =>
+              this.linkService.resolveLinks(obj, ...linksToFollow)
+            );
           }));
       }),
       startWith([]),
@@ -150,60 +169,6 @@ export class RemoteDataBuildService {
     return this.toRemoteDataObservable(requestEntry$, payload$);
   }
 
-  build<T extends CacheableObject>(normalized: NormalizedObject<T>): T {
-    const links: any = {};
-    const relationships = getRelationships(normalized.constructor) || [];
-
-    relationships.forEach((relationship: string) => {
-      let result;
-      if (hasValue(normalized[relationship])) {
-        const { resourceType, isList } = getRelationMetadata(normalized, relationship);
-        const objectList = normalized[relationship].page || normalized[relationship];
-        if (typeof objectList !== 'string') {
-          objectList.forEach((href: string) => {
-            const request = new GetRequest(this.requestService.generateRequestId(), href);
-            if (!this.requestService.isCachedOrPending(request)) {
-              this.requestService.configure(request)
-            }
-          });
-
-          const rdArr = [];
-          objectList.forEach((href: string) => {
-            rdArr.push(this.buildSingle(href));
-          });
-
-          if (isList) {
-            result = this.aggregate(rdArr);
-          } else if (rdArr.length === 1) {
-            result = rdArr[0];
-          }
-        } else {
-          const request = new GetRequest(this.requestService.generateRequestId(), objectList);
-          if (!this.requestService.isCachedOrPending(request)) {
-            this.requestService.configure(request)
-          }
-
-          // The rest API can return a single URL to represent a list of resources (e.g. /items/:id/bitstreams)
-          // in that case only 1 href will be stored in the normalized obj (so the isArray above fails),
-          // but it should still be built as a list
-          if (isList) {
-            result = this.buildList(objectList);
-          } else {
-            result = this.buildSingle(objectList);
-          }
-        }
-
-        if (hasValue(normalized[relationship].page)) {
-          links[relationship] = this.toPaginatedList(result, normalized[relationship].pageInfo);
-        } else {
-          links[relationship] = result;
-        }
-      }
-    });
-    const domainModel = getMapsTo(normalized.constructor);
-    return Object.assign(new domainModel(), normalized, links);
-  }
-
   aggregate<T>(input: Array<Observable<RemoteData<T>>>): Observable<RemoteData<T[]>> {
 
     if (isEmpty(input)) {
diff --git a/src/app/core/cache/models/items/normalized-item-type.model.ts b/src/app/core/cache/models/items/normalized-item-type.model.ts
deleted file mode 100644
index fdb3b9e455547eb4efc06f650eb7f347c1fa0fd8..0000000000000000000000000000000000000000
--- a/src/app/core/cache/models/items/normalized-item-type.model.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-import { autoserialize, autoserializeAs, inheritSerialization } from 'cerialize';
-import { ItemType } from '../../../shared/item-relationships/item-type.model';
-import { mapsTo } from '../../builders/build-decorators';
-import { NormalizedObject } from '../normalized-object.model';
-import { IDToUUIDSerializer } from '../../id-to-uuid-serializer';
-
-/**
- * Normalized model class for a DSpace ItemType
- */
-@mapsTo(ItemType)
-@inheritSerialization(NormalizedObject)
-export class NormalizedItemType extends NormalizedObject<ItemType> {
-  /**
-   * The label that describes the ResourceType of the Item
-   */
-  @autoserialize
-  label: string;
-
-  /**
-   * The identifier of this ItemType
-   */
-  @autoserialize
-  id: string;
-
-  /**
-   * The universally unique identifier of this ItemType
-   */
-  @autoserializeAs(new IDToUUIDSerializer(ItemType.type.value), 'id')
-  uuid: string;
-}
diff --git a/src/app/core/cache/models/items/normalized-relationship-type.model.ts b/src/app/core/cache/models/items/normalized-relationship-type.model.ts
deleted file mode 100644
index 23c3333a9b22ccc723bb7977dfbcf83da3c77516..0000000000000000000000000000000000000000
--- a/src/app/core/cache/models/items/normalized-relationship-type.model.ts
+++ /dev/null
@@ -1,77 +0,0 @@
-import { autoserialize, autoserializeAs, inheritSerialization } from 'cerialize';
-import { RelationshipType } from '../../../shared/item-relationships/relationship-type.model';
-import { ResourceType } from '../../../shared/resource-type';
-import { mapsTo, relationship } from '../../builders/build-decorators';
-import { NormalizedDSpaceObject } from '../normalized-dspace-object.model';
-import { NormalizedObject } from '../normalized-object.model';
-import { IDToUUIDSerializer } from '../../id-to-uuid-serializer';
-import { ItemType } from '../../../shared/item-relationships/item-type.model';
-
-/**
- * Normalized model class for a DSpace RelationshipType
- */
-@mapsTo(RelationshipType)
-@inheritSerialization(NormalizedDSpaceObject)
-export class NormalizedRelationshipType extends NormalizedObject<RelationshipType> {
-  /**
-   * The identifier of this RelationshipType
-   */
-  @autoserialize
-  id: string;
-
-  /**
-   * The label that describes the Relation to the left of this RelationshipType
-   */
-  @autoserialize
-  leftwardType: string;
-
-  /**
-   * The maximum amount of Relationships allowed to the left of this RelationshipType
-   */
-  @autoserialize
-  leftMaxCardinality: number;
-
-  /**
-   * The minimum amount of Relationships allowed to the left of this RelationshipType
-   */
-  @autoserialize
-  leftMinCardinality: number;
-
-  /**
-   * The label that describes the Relation to the right of this RelationshipType
-   */
-  @autoserialize
-  rightwardType: string;
-
-  /**
-   * The maximum amount of Relationships allowed to the right of this RelationshipType
-   */
-  @autoserialize
-  rightMaxCardinality: number;
-
-  /**
-   * The minimum amount of Relationships allowed to the right of this RelationshipType
-   */
-  @autoserialize
-  rightMinCardinality: number;
-
-  /**
-   * The type of Item found to the left of this RelationshipType
-   */
-  @autoserialize
-  @relationship(ItemType, false)
-  leftType: string;
-
-  /**
-   * The type of Item found to the right of this RelationshipType
-   */
-  @autoserialize
-  @relationship(ItemType, false)
-  rightType: string;
-
-  /**
-   * The universally unique identifier of this RelationshipType
-   */
-  @autoserializeAs(new IDToUUIDSerializer(RelationshipType.type.value), 'id')
-  uuid: string;
-}
diff --git a/src/app/core/cache/models/items/normalized-relationship.model.ts b/src/app/core/cache/models/items/normalized-relationship.model.ts
deleted file mode 100644
index 1c1dcf8d5baaacf660d9b1d0bcd3625f26a5ba94..0000000000000000000000000000000000000000
--- a/src/app/core/cache/models/items/normalized-relationship.model.ts
+++ /dev/null
@@ -1,72 +0,0 @@
-import { autoserialize, deserialize, deserializeAs, inheritSerialization } from 'cerialize';
-import { Relationship } from '../../../shared/item-relationships/relationship.model';
-import { mapsTo, relationship } from '../../builders/build-decorators';
-import { NormalizedObject } from '../normalized-object.model';
-import { IDToUUIDSerializer } from '../../id-to-uuid-serializer';
-import { RelationshipType } from '../../../shared/item-relationships/relationship-type.model';
-import { Item } from '../../../shared/item.model';
-
-/**
- * Normalized model class for a DSpace Relationship
- */
-@mapsTo(Relationship)
-@inheritSerialization(NormalizedObject)
-export class NormalizedRelationship extends NormalizedObject<Relationship> {
-
-  /**
-   * The identifier of this Relationship
-   */
-  @deserialize
-  id: string;
-
-  /**
-   * The item to the left of this relationship
-   */
-  @deserialize
-  @relationship(Item, false)
-  leftItem: string;
-
-  /**
-   * The item to the right of this relationship
-   */
-  @deserialize
-  @relationship(Item, false)
-  rightItem: string;
-
-  /**
-   * The place of the Item to the left side of this Relationship
-   */
-  @autoserialize
-  leftPlace: number;
-
-  /**
-   * The place of the Item to the right side of this Relationship
-   */
-  @autoserialize
-  rightPlace: number;
-
-  /**
-   * The name variant of the Item to the left side of this Relationship
-   */
-  @autoserialize
-  leftwardValue: string;
-
-  /**
-   * The name variant of the Item to the right side of this Relationship
-   */
-  @autoserialize
-  rightwardValue: string;
-
-  /**
-   * The type of Relationship
-   */
-  @deserialize
-  @relationship(RelationshipType, false)
-  relationshipType: string;
-
-  /**
-   * The universally unique identifier of this Relationship
-   */
-  @deserializeAs(new IDToUUIDSerializer(Relationship.type.value), 'id')
-  uuid: string;
-}
diff --git a/src/app/core/cache/models/normalized-bitstream-format.model.ts b/src/app/core/cache/models/normalized-bitstream-format.model.ts
deleted file mode 100644
index 2283ecb368c47d63b8f0f3ba7f42a5b7b7ee1d42..0000000000000000000000000000000000000000
--- a/src/app/core/cache/models/normalized-bitstream-format.model.ts
+++ /dev/null
@@ -1,65 +0,0 @@
-import { autoserialize, autoserializeAs, inheritSerialization } from 'cerialize';
-import { BitstreamFormat } from '../../shared/bitstream-format.model';
-
-import { mapsTo } from '../builders/build-decorators';
-import { IDToUUIDSerializer } from '../id-to-uuid-serializer';
-import { NormalizedObject } from './normalized-object.model';
-import { BitstreamFormatSupportLevel } from '../../shared/bitstream-format-support-level';
-
-/**
- * Normalized model class for a Bitstream Format
- */
-@mapsTo(BitstreamFormat)
-@inheritSerialization(NormalizedObject)
-export class NormalizedBitstreamFormat extends NormalizedObject<BitstreamFormat> {
-  /**
-   * Short description of this Bitstream Format
-   */
-  @autoserialize
-  shortDescription: string;
-
-  /**
-   * Description of this Bitstream Format
-   */
-  @autoserialize
-  description: string;
-
-  /**
-   * String representing the MIME type of this Bitstream Format
-   */
-  @autoserialize
-  mimetype: string;
-
-  /**
-   * The level of support the system offers for this Bitstream Format
-   */
-  @autoserialize
-  supportLevel: BitstreamFormatSupportLevel;
-
-  /**
-   * True if the Bitstream Format is used to store system information, rather than the content of items in the system
-   */
-  @autoserialize
-  internal: boolean;
-
-  /**
-   * String representing this Bitstream Format's file extension
-   */
-  @autoserialize
-  extensions: string[];
-
-  /**
-   * Identifier for this Bitstream Format
-   * Note that this ID is unique for bitstream formats,
-   * but might not be unique across different object types
-   */
-  @autoserialize
-  id: string;
-
-  /**
-   * Universally unique identifier for this Bitstream Format
-   * Consist of a prefix and the id field to ensure the identifier is unique across all object types
-   */
-  @autoserializeAs(new IDToUUIDSerializer('bitstream-format'), 'id')
-  uuid: string;
-}
diff --git a/src/app/core/cache/models/normalized-bitstream.model.ts b/src/app/core/cache/models/normalized-bitstream.model.ts
deleted file mode 100644
index a9e389fd41a77d1e1d22126c74196bb86fa83673..0000000000000000000000000000000000000000
--- a/src/app/core/cache/models/normalized-bitstream.model.ts
+++ /dev/null
@@ -1,60 +0,0 @@
-import { autoserialize, inheritSerialization } from 'cerialize';
-
-import { NormalizedDSpaceObject } from './normalized-dspace-object.model';
-import { Bitstream } from '../../shared/bitstream.model';
-import { mapsTo, relationship } from '../builders/build-decorators';
-import { Item } from '../../shared/item.model';
-import { BitstreamFormat } from '../../shared/bitstream-format.model';
-
-/**
- * Normalized model class for a DSpace Bitstream
- */
-@mapsTo(Bitstream)
-@inheritSerialization(NormalizedDSpaceObject)
-export class NormalizedBitstream extends NormalizedDSpaceObject<Bitstream> {
-  /**
-   * The size of this bitstream in bytes
-   */
-  @autoserialize
-  sizeBytes: number;
-
-  /**
-   * The relative path to this Bitstream's file
-   */
-  @autoserialize
-  content: string;
-
-  /**
-   * The format of this Bitstream
-   */
-  @autoserialize
-  @relationship(BitstreamFormat, false)
-  format: string;
-
-  /**
-   * The description of this Bitstream
-   */
-  @autoserialize
-  description: string;
-
-  /**
-   * An array of Bundles that are direct parents of this Bitstream
-   */
-  @autoserialize
-  @relationship(Item, true)
-  parents: string[];
-
-  /**
-   * The Bundle that owns this Bitstream
-   */
-  @autoserialize
-  @relationship(Item, false)
-  owner: string;
-
-  /**
-   * The name of the Bundle this Bitstream is part of
-   */
-  @autoserialize
-  bundleName: string;
-
-}
diff --git a/src/app/core/cache/models/normalized-bundle.model.ts b/src/app/core/cache/models/normalized-bundle.model.ts
deleted file mode 100644
index 9582643efb95706c701629f9a977082b5ea88fa3..0000000000000000000000000000000000000000
--- a/src/app/core/cache/models/normalized-bundle.model.ts
+++ /dev/null
@@ -1,45 +0,0 @@
-import { autoserialize, inheritSerialization } from 'cerialize';
-
-import { NormalizedDSpaceObject } from './normalized-dspace-object.model';
-import { Bundle } from '../../shared/bundle.model';
-import { mapsTo, relationship } from '../builders/build-decorators';
-import { Bitstream } from '../../shared/bitstream.model';
-
-/**
- * Normalized model class for a DSpace Bundle
- */
-@mapsTo(Bundle)
-@inheritSerialization(NormalizedDSpaceObject)
-export class NormalizedBundle extends NormalizedDSpaceObject<Bundle> {
-
-  /**
-   * The bundle's name
-   */
-  @autoserialize
-  name: string;
-
-  /**
-   * The primary bitstream of this Bundle
-   */
-  @autoserialize
-  @relationship(Bitstream, false)
-  primaryBitstream: string;
-
-  /**
-   * An array of Items that are direct parents of this Bundle
-   */
-  parents: string[];
-
-  /**
-   * The Item that owns this Bundle
-   */
-  owner: string;
-
-  /**
-   * List of Bitstreams that are part of this Bundle
-   */
-  @autoserialize
-  @relationship(Bitstream, true)
-  bitstreams: string[];
-
-}
diff --git a/src/app/core/cache/models/normalized-collection.model.ts b/src/app/core/cache/models/normalized-collection.model.ts
deleted file mode 100644
index 9b3419675a3c2266c0f6f70eb4ad708abd3ed54c..0000000000000000000000000000000000000000
--- a/src/app/core/cache/models/normalized-collection.model.ts
+++ /dev/null
@@ -1,71 +0,0 @@
-import { autoserialize, deserialize, inheritSerialization } from 'cerialize';
-
-import { NormalizedDSpaceObject } from './normalized-dspace-object.model';
-import { Collection } from '../../shared/collection.model';
-import { mapsTo, relationship } from '../builders/build-decorators';
-import { NormalizedResourcePolicy } from './normalized-resource-policy.model';
-import { NormalizedBitstream } from './normalized-bitstream.model';
-import { NormalizedCommunity } from './normalized-community.model';
-import { NormalizedItem } from './normalized-item.model';
-import { License } from '../../shared/license.model';
-import { ResourcePolicy } from '../../shared/resource-policy.model';
-import { Bitstream } from '../../shared/bitstream.model';
-import { Community } from '../../shared/community.model';
-import { Item } from '../../shared/item.model';
-
-/**
- * Normalized model class for a DSpace Collection
- */
-@mapsTo(Collection)
-@inheritSerialization(NormalizedDSpaceObject)
-export class NormalizedCollection extends NormalizedDSpaceObject<Collection> {
-
-  /**
-   * A string representing the unique handle of this Collection
-   */
-  @autoserialize
-  handle: string;
-
-  /**
-   * The Bitstream that represents the license of this Collection
-   */
-  @autoserialize
-  @relationship(License, false)
-  license: string;
-
-  /**
-   * The Bitstream that represents the default Access Conditions of this Collection
-   */
-  @autoserialize
-  @relationship(ResourcePolicy, false)
-  defaultAccessConditions: string;
-
-  /**
-   * The Bitstream that represents the logo of this Collection
-   */
-  @deserialize
-  @relationship(Bitstream, false)
-  logo: string;
-
-  /**
-   * An array of Communities that are direct parents of this Collection
-   */
-  @deserialize
-  @relationship(Community, true)
-  parents: string[];
-
-  /**
-   * The Community that owns this Collection
-   */
-  @deserialize
-  @relationship(Community, false)
-  owner: string;
-
-  /**
-   * List of Items that are part of (not necessarily owned by) this Collection
-   */
-  @deserialize
-  @relationship(Item, true)
-  items: string[];
-
-}
diff --git a/src/app/core/cache/models/normalized-community.model.ts b/src/app/core/cache/models/normalized-community.model.ts
deleted file mode 100644
index 173760ca720607fbd6d471e89cf704af536a7e37..0000000000000000000000000000000000000000
--- a/src/app/core/cache/models/normalized-community.model.ts
+++ /dev/null
@@ -1,56 +0,0 @@
-import { autoserialize, deserialize, inheritSerialization } from 'cerialize';
-
-import { NormalizedDSpaceObject } from './normalized-dspace-object.model';
-import { Community } from '../../shared/community.model';
-import { mapsTo, relationship } from '../builders/build-decorators';
-import { ResourceType } from '../../shared/resource-type';
-import { NormalizedBitstream } from './normalized-bitstream.model';
-import { NormalizedCollection } from './normalized-collection.model';
-import { Bitstream } from '../../shared/bitstream.model';
-import { Collection } from '../../shared/collection.model';
-
-/**
- * Normalized model class for a DSpace Community
- */
-@mapsTo(Community)
-@inheritSerialization(NormalizedDSpaceObject)
-export class NormalizedCommunity extends NormalizedDSpaceObject<Community> {
-  /**
-   * A string representing the unique handle of this Community
-   */
-  @autoserialize
-  handle: string;
-
-  /**
-   * The Bitstream that represents the logo of this Community
-   */
-  @deserialize
-  @relationship(Bitstream, false)
-  logo: string;
-
-  /**
-   * An array of Communities that are direct parents of this Community
-   */
-  @deserialize
-  @relationship(Community, true)
-  parents: string[];
-
-  /**
-   * The Community that owns this Community
-   */
-  @deserialize
-  @relationship(Community, false)
-  owner: string;
-
-  /**
-   * List of Collections that are owned by this Community
-   */
-  @deserialize
-  @relationship(Collection, true)
-  collections: string[];
-
-  @deserialize
-  @relationship(Community, true)
-  subcommunities: string[];
-
-}
diff --git a/src/app/core/cache/models/normalized-dspace-object.model.ts b/src/app/core/cache/models/normalized-dspace-object.model.ts
deleted file mode 100644
index 3c43dd85dc8579974d041bcaabb5c253f401a4ef..0000000000000000000000000000000000000000
--- a/src/app/core/cache/models/normalized-dspace-object.model.ts
+++ /dev/null
@@ -1,72 +0,0 @@
-import { autoserializeAs, deserializeAs, autoserialize } from 'cerialize';
-import { DSpaceObject } from '../../shared/dspace-object.model';
-import { MetadataMap, MetadataMapSerializer } from '../../shared/metadata.models';
-import { mapsTo } from '../builders/build-decorators';
-import { NormalizedObject } from './normalized-object.model';
-import { TypedObject } from '../object-cache.reducer';
-
-/**
- * An model class for a DSpaceObject.
- */
-@mapsTo(DSpaceObject)
-export class NormalizedDSpaceObject<T extends DSpaceObject> extends NormalizedObject<T> implements TypedObject {
-
-  /**
-   * The link to the rest endpoint where this object can be found
-   *
-   * Repeated here to make the serialization work,
-   * inheritSerialization doesn't seem to work for more than one level
-   */
-  @deserializeAs(String)
-  self: string;
-
-  /**
-   * The human-readable identifier of this DSpaceObject
-   *
-   * Currently mapped to uuid but left in to leave room
-   * for a shorter, more user friendly type of id
-   */
-  @autoserializeAs(String, 'uuid')
-  id: string;
-
-  /**
-   * The universally unique identifier of this DSpaceObject
-   */
-  @autoserializeAs(String)
-  uuid: string;
-
-  /**
-   * A string representing the kind of DSpaceObject, e.g. community, item, …
-   */
-  @autoserialize
-  type: string;
-
-  /**
-   * All metadata of this DSpaceObject
-   */
-  @autoserializeAs(MetadataMapSerializer)
-  metadata: MetadataMap;
-
-  /**
-   * An array of DSpaceObjects that are direct parents of this DSpaceObject
-   */
-  @deserializeAs(String)
-  parents: string[];
-
-  /**
-   * The DSpaceObject that owns this DSpaceObject
-   */
-  @deserializeAs(String)
-  owner: string;
-
-  /**
-   * The links to all related resources returned by the rest api.
-   *
-   * Repeated here to make the serialization work,
-   * inheritSerialization doesn't seem to work for more than one level
-   */
-  @deserializeAs(Object)
-  _links: {
-    [name: string]: string
-  }
-}
diff --git a/src/app/core/cache/models/normalized-external-source-entry.model.ts b/src/app/core/cache/models/normalized-external-source-entry.model.ts
deleted file mode 100644
index de262949e70ef6770e60743e77a903dc0b43f2bb..0000000000000000000000000000000000000000
--- a/src/app/core/cache/models/normalized-external-source-entry.model.ts
+++ /dev/null
@@ -1,42 +0,0 @@
-import { autoserialize, autoserializeAs, inheritSerialization } from 'cerialize';
-import { NormalizedObject } from './normalized-object.model';
-import { ExternalSourceEntry } from '../../shared/external-source-entry.model';
-import { mapsTo } from '../builders/build-decorators';
-import { MetadataMap, MetadataMapSerializer } from '../../shared/metadata.models';
-
-/**
- * Normalized model class for an external source entry
- */
-@mapsTo(ExternalSourceEntry)
-@inheritSerialization(NormalizedObject)
-export class NormalizedExternalSourceEntry extends NormalizedObject<ExternalSourceEntry> {
-  /**
-   * Unique identifier
-   */
-  @autoserialize
-  id: string;
-
-  /**
-   * The value to display
-   */
-  @autoserialize
-  display: string;
-
-  /**
-   * The value to store the entry with
-   */
-  @autoserialize
-  value: string;
-
-  /**
-   * The ID of the external source this entry originates from
-   */
-  @autoserialize
-  externalSource: string;
-
-  /**
-   * Metadata of the entry
-   */
-  @autoserializeAs(MetadataMapSerializer)
-  metadata: MetadataMap;
-}
diff --git a/src/app/core/cache/models/normalized-external-source.model.ts b/src/app/core/cache/models/normalized-external-source.model.ts
deleted file mode 100644
index fd9a42fb721182eec336e0f0adde35ea6f0705e4..0000000000000000000000000000000000000000
--- a/src/app/core/cache/models/normalized-external-source.model.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-import { autoserialize, inheritSerialization } from 'cerialize';
-import { NormalizedObject } from './normalized-object.model';
-import { ExternalSource } from '../../shared/external-source.model';
-import { mapsTo } from '../builders/build-decorators';
-
-/**
- * Normalized model class for an external source
- */
-@mapsTo(ExternalSource)
-@inheritSerialization(NormalizedObject)
-export class NormalizedExternalSource extends NormalizedObject<ExternalSource> {
-  /**
-   * Unique identifier
-   */
-  @autoserialize
-  id: string;
-
-  /**
-   * The name of this external source
-   */
-  @autoserialize
-  name: string;
-
-  /**
-   * Is the source hierarchical?
-   */
-  @autoserialize
-  hierarchical: boolean;
-}
diff --git a/src/app/core/cache/models/normalized-item.model.ts b/src/app/core/cache/models/normalized-item.model.ts
deleted file mode 100644
index 9b7edf70c060c7767139ac254c375f318e80cb54..0000000000000000000000000000000000000000
--- a/src/app/core/cache/models/normalized-item.model.ts
+++ /dev/null
@@ -1,72 +0,0 @@
-import { inheritSerialization, deserialize, autoserialize, autoserializeAs } from 'cerialize';
-
-import { NormalizedDSpaceObject } from './normalized-dspace-object.model';
-import { Item } from '../../shared/item.model';
-import { mapsTo, relationship } from '../builders/build-decorators';
-import { Collection } from '../../shared/collection.model';
-import { Relationship } from '../../shared/item-relationships/relationship.model';
-import { Bundle } from '../../shared/bundle.model';
-
-/**
- * Normalized model class for a DSpace Item
- */
-@mapsTo(Item)
-@inheritSerialization(NormalizedDSpaceObject)
-export class NormalizedItem extends NormalizedDSpaceObject<Item> {
-
-  /**
-   * A string representing the unique handle of this Item
-   */
-  @autoserialize
-  handle: string;
-
-  /**
-   * The Date of the last modification of this Item
-   */
-  @deserialize
-  lastModified: Date;
-
-  /**
-   * A boolean representing if this Item is currently archived or not
-   */
-  @autoserializeAs(Boolean, 'inArchive')
-  isArchived: boolean;
-
-  /**
-   * A boolean representing if this Item is currently discoverable or not
-   */
-  @autoserializeAs(Boolean, 'discoverable')
-  isDiscoverable: boolean;
-
-  /**
-   * A boolean representing if this Item is currently withdrawn or not
-   */
-  @autoserializeAs(Boolean, 'withdrawn')
-  isWithdrawn: boolean;
-
-  /**
-   * An array of Collections that are direct parents of this Item
-   */
-  @deserialize
-  @relationship(Collection, true)
-  parents: string[];
-
-  /**
-   * The Collection that owns this Item
-   */
-  @deserialize
-  @relationship(Collection, false)
-  owningCollection: string;
-
-  /**
-   * List of Bitstreams that are owned by this Item
-   */
-  @deserialize
-  @relationship(Bundle, true)
-  bundles: string[];
-
-  @deserialize
-  @relationship(Relationship, true)
-  relationships: string[];
-
-}
diff --git a/src/app/core/cache/models/normalized-license.model.ts b/src/app/core/cache/models/normalized-license.model.ts
deleted file mode 100644
index 02bd1808c88ad098d5814cdc2653509a7321b604..0000000000000000000000000000000000000000
--- a/src/app/core/cache/models/normalized-license.model.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-import { autoserialize, inheritSerialization } from 'cerialize';
-import { mapsTo } from '../builders/build-decorators';
-import { NormalizedDSpaceObject } from './normalized-dspace-object.model';
-import { License } from '../../shared/license.model';
-
-/**
- * Normalized model class for a Collection License
- */
-@mapsTo(License)
-@inheritSerialization(NormalizedDSpaceObject)
-export class NormalizedLicense extends NormalizedDSpaceObject<License> {
-
-  /**
-   * A boolean representing if this License is custom or not
-   */
-  @autoserialize
-  custom: boolean;
-
-  /**
-   * The text of the license
-   */
-  @autoserialize
-  text: string;
-}
diff --git a/src/app/core/cache/models/normalized-object.model.ts b/src/app/core/cache/models/normalized-object.model.ts
deleted file mode 100644
index 8a3aed32c9e347e2db731029c6e3250100d87ad3..0000000000000000000000000000000000000000
--- a/src/app/core/cache/models/normalized-object.model.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-import { CacheableObject, TypedObject } from '../object-cache.reducer';
-import { autoserialize, deserialize } from 'cerialize';
-import { ResourceType } from '../../shared/resource-type';
-/**
- * An abstract model class for a NormalizedObject.
- */
-export abstract class NormalizedObject<T extends TypedObject> implements CacheableObject {
-  /**
-   * The link to the rest endpoint where this object can be found
-   */
-  @deserialize
-  self: string;
-
-  @deserialize
-  _links: {
-    [name: string]: string
-  };
-
-  /**
-   * A string representing the kind of object
-   */
-  @deserialize
-  type: string;
-}
diff --git a/src/app/core/cache/models/normalized-resource-policy.model.ts b/src/app/core/cache/models/normalized-resource-policy.model.ts
deleted file mode 100644
index cd25a0af056c223324c037c74de15f629b9bd19b..0000000000000000000000000000000000000000
--- a/src/app/core/cache/models/normalized-resource-policy.model.ts
+++ /dev/null
@@ -1,48 +0,0 @@
-import { autoserialize, autoserializeAs, inheritSerialization } from 'cerialize';
-import { ResourcePolicy } from '../../shared/resource-policy.model';
-
-import { mapsTo } from '../builders/build-decorators';
-import { NormalizedObject } from './normalized-object.model';
-import { IDToUUIDSerializer } from '../id-to-uuid-serializer';
-import { ActionType } from './action-type.model';
-
-/**
- * Normalized model class for a Resource Policy
- */
-@mapsTo(ResourcePolicy)
-@inheritSerialization(NormalizedObject)
-export class NormalizedResourcePolicy extends NormalizedObject<ResourcePolicy> {
-  /**
-   * The action that is allowed by this Resource Policy
-   */
-  @autoserialize
-  action: ActionType;
-
-  /**
-   * The name for this Resource Policy
-   */
-  @autoserialize
-  name: string;
-
-  /**
-   * The uuid of the Group this Resource Policy applies to
-   */
-  @autoserialize
-  groupUUID: string;
-
-  /**
-   * Identifier for this Resource Policy
-   * Note that this ID is unique for resource policies,
-   * but might not be unique across different object types
-   */
-  @autoserialize
-  id: string;
-
-  /**
-   * The universally unique identifier for this Resource Policy
-   * Consist of a prefix and the id field to ensure the identifier is unique across all object types
-   */
-  @autoserializeAs(new IDToUUIDSerializer('resource-policy'), 'id')
-  uuid: string;
-
-}
diff --git a/src/app/core/cache/models/normalized-site.model.ts b/src/app/core/cache/models/normalized-site.model.ts
deleted file mode 100644
index 68a7e0a48053ef34258827d59d1be039d4d6b6d2..0000000000000000000000000000000000000000
--- a/src/app/core/cache/models/normalized-site.model.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import { inheritSerialization } from 'cerialize';
-import { NormalizedDSpaceObject } from './normalized-dspace-object.model';
-import { mapsTo } from '../builders/build-decorators';
-import { Site } from '../../shared/site.model';
-
-/**
- * Normalized model class for a Site object
- */
-@mapsTo(Site)
-@inheritSerialization(NormalizedDSpaceObject)
-export class NormalizedSite extends NormalizedDSpaceObject<Site> {
-
-}
diff --git a/src/app/core/cache/object-cache.reducer.spec.ts b/src/app/core/cache/object-cache.reducer.spec.ts
index a65e63ab8624e07af0c07afde8fb822c32240e34..6519e887c91a7ae14b5a92580b9c73dddc07e154 100644
--- a/src/app/core/cache/object-cache.reducer.spec.ts
+++ b/src/app/core/cache/object-cache.reducer.spec.ts
@@ -1,6 +1,6 @@
 import * as deepFreeze from 'deep-freeze';
-
-import { objectCacheReducer } from './object-cache.reducer';
+import { Operation } from 'fast-json-patch';
+import { Item } from '../shared/item.model';
 import {
   AddPatchObjectCacheAction,
   AddToObjectCacheAction,
@@ -8,8 +8,8 @@ import {
   RemoveFromObjectCacheAction,
   ResetObjectCacheTimestampsAction
 } from './object-cache.actions';
-import { Operation } from 'fast-json-patch';
-import { Item } from '../shared/item.model';
+
+import { objectCacheReducer } from './object-cache.reducer';
 
 class NullAction extends RemoveFromObjectCacheAction {
   type = null;
@@ -31,19 +31,21 @@ describe('objectCacheReducer', () => {
       data: {
         type: Item.type,
         self: selfLink1,
-        foo: 'bar'
+        foo: 'bar',
+        _links: { self: { href: selfLink1 } }
       },
       timeAdded: new Date().getTime(),
       msToLive: 900000,
       requestUUID: requestUUID1,
       patches: [],
-      isDirty: false
+      isDirty: false,
     },
     [selfLink2]: {
       data: {
         type: Item.type,
         self: requestUUID2,
-        foo: 'baz'
+        foo: 'baz',
+        _links: { self: { href: requestUUID2 } }
       },
       timeAdded: new Date().getTime(),
       msToLive: 900000,
@@ -70,7 +72,7 @@ describe('objectCacheReducer', () => {
 
   it('should add the payload to the cache in response to an ADD action', () => {
     const state = Object.create(null);
-    const objectToCache = { self: selfLink1, type: Item.type };
+    const objectToCache = { self: selfLink1, type: Item.type, _links: { self: { href: selfLink1 } } };
     const timeAdded = new Date().getTime();
     const msToLive = 900000;
     const requestUUID = requestUUID1;
@@ -87,7 +89,8 @@ describe('objectCacheReducer', () => {
       self: selfLink1,
       foo: 'baz',
       somethingElse: true,
-      type: Item.type
+      type: Item.type,
+      _links: { self: { href: selfLink1 } }
     };
     const timeAdded = new Date().getTime();
     const msToLive = 900000;
@@ -103,7 +106,7 @@ describe('objectCacheReducer', () => {
 
   it('should perform the ADD action without affecting the previous state', () => {
     const state = Object.create(null);
-    const objectToCache = { self: selfLink1, type: Item.type };
+    const objectToCache = { self: selfLink1, type: Item.type, _links: { self: { href: selfLink1 } } };
     const timeAdded = new Date().getTime();
     const msToLive = 900000;
     const requestUUID = requestUUID1;
@@ -121,8 +124,8 @@ describe('objectCacheReducer', () => {
     expect(newState[selfLink1]).toBeUndefined();
   });
 
-  it("shouldn't do anything in response to the REMOVE action for an object that isn't cached", () => {
-    const wrongKey = "this isn't cached";
+  it('shouldn\'t do anything in response to the REMOVE action for an object that isn\'t cached', () => {
+    const wrongKey = 'this isn\'t cached';
     const action = new RemoveFromObjectCacheAction(wrongKey);
     const newState = objectCacheReducer(testState, action);
 
diff --git a/src/app/core/cache/object-cache.reducer.ts b/src/app/core/cache/object-cache.reducer.ts
index afc040bf5973867ea5ac3865347f6b8911c12053..a39ceb4e167480b0ca78bd775d3bcf06dcd26b16 100644
--- a/src/app/core/cache/object-cache.reducer.ts
+++ b/src/app/core/cache/object-cache.reducer.ts
@@ -1,3 +1,7 @@
+import { autoserialize, deserialize } from 'cerialize';
+import { HALLink } from '../shared/hal-link.model';
+import { HALResource } from '../shared/hal-resource.model';
+import { excludeFromEquals } from '../utilities/equals.decorators';
 import {
   ObjectCacheAction,
   ObjectCacheActionTypes,
@@ -34,6 +38,7 @@ export interface Patch {
 
 export abstract class TypedObject {
   static type: ResourceType;
+  type: ResourceType;
 }
 
 /* tslint:disable:max-classes-per-file */
@@ -42,10 +47,13 @@ export abstract class TypedObject {
  *
  * A cacheable object should have a self link
  */
-export class CacheableObject extends TypedObject {
+export class CacheableObject extends TypedObject implements HALResource {
   uuid?: string;
   handle?: string;
-  self: string;
+
+  _links: {
+    self: HALLink;
+  }
   // isNew: boolean;
   // dirtyType: DirtyType;
   // hasDirtyAttributes: boolean;
@@ -129,9 +137,9 @@ export function objectCacheReducer(state = initialState, action: ObjectCacheActi
  *    the new state, with the object added, or overwritten.
  */
 function addToObjectCache(state: ObjectCacheState, action: AddToObjectCacheAction): ObjectCacheState {
-  const existing = state[action.payload.objectToCache.self];
+  const existing = state[action.payload.objectToCache._links.self.href];
   return Object.assign({}, state, {
-    [action.payload.objectToCache.self]: {
+    [action.payload.objectToCache._links.self.href]: {
       data: action.payload.objectToCache,
       timeAdded: action.payload.timeAdded,
       msToLive: action.payload.msToLive,
diff --git a/src/app/core/cache/object-cache.service.spec.ts b/src/app/core/cache/object-cache.service.spec.ts
index 39dc10de2cf26047a520e6ecc9ea5f69299cafc8..e7c208e095ad98f67b2169290ec1c3f76bc1bc89 100644
--- a/src/app/core/cache/object-cache.service.spec.ts
+++ b/src/app/core/cache/object-cache.service.spec.ts
@@ -1,34 +1,36 @@
 import * as ngrx from '@ngrx/store';
 import { Store } from '@ngrx/store';
+import { Operation } from 'fast-json-patch';
 import { of as observableOf } from 'rxjs';
-
-import { ObjectCacheService } from './object-cache.service';
+import { first } from 'rxjs/operators';
+import { CoreState } from '../core.reducers';
+import { RestRequestMethod } from '../data/rest-request-method';
+import { Item } from '../shared/item.model';
 import {
   AddPatchObjectCacheAction,
   AddToObjectCacheAction,
   ApplyPatchObjectCacheAction,
   RemoveFromObjectCacheAction
 } from './object-cache.actions';
-import { CoreState } from '../core.reducers';
-import { NormalizedItem } from './models/normalized-item.model';
-import { first } from 'rxjs/operators';
-import { Operation } from 'fast-json-patch';
-import { RestRequestMethod } from '../data/rest-request-method';
-import { AddToSSBAction } from './server-sync-buffer.actions';
 import { Patch } from './object-cache.reducer';
-import { Item } from '../shared/item.model';
+
+import { ObjectCacheService } from './object-cache.service';
+import { AddToSSBAction } from './server-sync-buffer.actions';
 
 describe('ObjectCacheService', () => {
   let service: ObjectCacheService;
   let store: Store<CoreState>;
+  let linkServiceStub;
 
   const selfLink = 'https://rest.api/endpoint/1698f1d3-be98-4c51-9fd8-6bfedcbd59b7';
   const requestUUID = '4d3a4ce8-a375-4b98-859b-39f0a014d736';
   const timestamp = new Date().getTime();
   const msToLive = 900000;
   let objectToCache = {
-    self: selfLink,
-    type: Item.type
+    type: Item.type,
+    _links: {
+      self: { href: selfLink }
+    }
   };
   let cacheEntry;
   let invalidCacheEntry;
@@ -36,8 +38,10 @@ describe('ObjectCacheService', () => {
 
   function init() {
     objectToCache = {
-      self: selfLink,
-      type: Item.type
+      type: Item.type,
+      _links: {
+        self: { href: selfLink }
+      }
     };
     cacheEntry = {
       data: objectToCache,
@@ -50,8 +54,12 @@ describe('ObjectCacheService', () => {
   beforeEach(() => {
     init();
     store = new Store<CoreState>(undefined, undefined, undefined);
+    linkServiceStub = {
+      removeResolvedLinks: (a) => a
+    };
+    spyOn(linkServiceStub, 'removeResolvedLinks').and.callThrough();
     spyOn(store, 'dispatch');
-    service = new ObjectCacheService(store);
+    service = new ObjectCacheService(store, linkServiceStub);
 
     spyOn(Date.prototype, 'getTime').and.callFake(() => {
       return timestamp;
@@ -62,6 +70,7 @@ describe('ObjectCacheService', () => {
     it('should dispatch an ADD action with the object to add, the time to live, and the current timestamp', () => {
       service.add(objectToCache, msToLive, requestUUID);
       expect(store.dispatch).toHaveBeenCalledWith(new AddToObjectCacheAction(objectToCache, timestamp, msToLive, requestUUID));
+      expect(linkServiceStub.removeResolvedLinks).toHaveBeenCalledWith(objectToCache);
     });
   });
 
@@ -82,9 +91,9 @@ describe('ObjectCacheService', () => {
 
       // due to the implementation of spyOn above, this subscribe will be synchronous
       service.getObjectBySelfLink(selfLink).pipe(first()).subscribe((o) => {
-          expect(o.self).toBe(selfLink);
+          expect(o._links.self.href).toBe(selfLink);
           // this only works if testObj is an instance of TestClass
-          expect(o instanceof NormalizedItem).toBeTruthy();
+          expect(o instanceof Item).toBeTruthy();
         }
       );
     });
@@ -105,13 +114,14 @@ describe('ObjectCacheService', () => {
 
   describe('getList', () => {
     it('should return an observable of the array of cached objects with the specified self link and type', () => {
-      const item = new NormalizedItem();
-      item.self = selfLink;
+      const item = Object.assign(new Item(), {
+        _links: { self: { href: selfLink } }
+      });
       spyOn(service, 'getObjectBySelfLink').and.returnValue(observableOf(item));
 
       service.getList([selfLink, selfLink]).pipe(first()).subscribe((arr) => {
-        expect(arr[0].self).toBe(selfLink);
-        expect(arr[0] instanceof NormalizedItem).toBeTruthy();
+        expect(arr[0]._links.self.href).toBe(selfLink);
+        expect(arr[0] instanceof Item).toBeTruthy();
       });
     });
   });
@@ -127,7 +137,7 @@ describe('ObjectCacheService', () => {
       expect(service.hasBySelfLink(selfLink)).toBe(true);
     });
 
-    it("should return false if the object with the supplied self link isn't cached", () => {
+    it('should return false if the object with the supplied self link isn\'t cached', () => {
       spyOnProperty(ngrx, 'select').and.callFake(() => {
         return () => {
           return () => observableOf(undefined);
diff --git a/src/app/core/cache/object-cache.service.ts b/src/app/core/cache/object-cache.service.ts
index 8d4e910471439f4f2f772fb3b3a25904c87d5d0b..53894df5f1df61243a4357ceb20d7a19caa46b2e 100644
--- a/src/app/core/cache/object-cache.service.ts
+++ b/src/app/core/cache/object-cache.service.ts
@@ -10,7 +10,7 @@ import { coreSelector } from '../core.selectors';
 import { RestRequestMethod } from '../data/rest-request-method';
 import { selfLinkFromUuidSelector } from '../index/index.selectors';
 import { GenericConstructor } from '../shared/generic-constructor';
-import { NormalizedObject } from './models/normalized-object.model';
+import { LinkService } from './builders/link.service';
 import {
   AddPatchObjectCacheAction,
   AddToObjectCacheAction,
@@ -20,7 +20,7 @@ import {
 
 import { CacheableObject, ObjectCacheEntry, ObjectCacheState } from './object-cache.reducer';
 import { AddToSSBAction } from './server-sync-buffer.actions';
-import { getMapsToType } from './builders/build-decorators';
+import { getClassForType } from './builders/build-decorators';
 
 /**
  * The base selector function to select the object cache in the store
@@ -45,21 +45,25 @@ const entryFromSelfLinkSelector =
  */
 @Injectable()
 export class ObjectCacheService {
-  constructor(private store: Store<CoreState>) {
+  constructor(
+    private store: Store<CoreState>,
+    private linkService: LinkService
+    ) {
   }
 
   /**
    * Add an object to the cache
    *
-   * @param objectToCache
+   * @param object
    *    The object to add
    * @param msToLive
    *    The number of milliseconds it should be cached for
    * @param requestUUID
    *    The UUID of the request that resulted in this object
    */
-  add(objectToCache: CacheableObject, msToLive: number, requestUUID: string): void {
-    this.store.dispatch(new AddToObjectCacheAction(objectToCache, new Date().getTime(), msToLive, requestUUID));
+  add(object: CacheableObject, msToLive: number, requestUUID: string): void {
+    object = this.linkService.removeResolvedLinks(object); // Ensure the object we're storing has no resolved links
+    this.store.dispatch(new AddToObjectCacheAction(object, new Date().getTime(), msToLive, requestUUID));
   }
 
   /**
@@ -77,14 +81,14 @@ export class ObjectCacheService {
    *
    * @param uuid
    *    The UUID of the object to get
-   * @return Observable<NormalizedObject<T>>
-   *    An observable of the requested object in normalized form
+   * @return Observable<T>
+   *    An observable of the requested object
    */
   getObjectByUUID<T extends CacheableObject>(uuid: string):
-    Observable<NormalizedObject<T>> {
+    Observable<T> {
     return this.store.pipe(
       select(selfLinkFromUuidSelector(uuid)),
-      mergeMap((selfLink: string) => this.getObjectBySelfLink(selfLink)
+      mergeMap((selfLink: string) => this.getObjectBySelfLink<T>(selfLink)
       )
     )
   }
@@ -94,10 +98,10 @@ export class ObjectCacheService {
    *
    * @param selfLink
    *    The selfLink of the object to get
-   * @return Observable<NormalizedObject<T>>
-   *    An observable of the requested object in normalized form
+   * @return Observable<T>
+   *    An observable of the requested object
    */
-  getObjectBySelfLink<T extends CacheableObject>(selfLink: string): Observable<NormalizedObject<T>> {
+  getObjectBySelfLink<T extends CacheableObject>(selfLink: string): Observable<T> {
     return this.getBySelfLink(selfLink).pipe(
       map((entry: ObjectCacheEntry) => {
           if (isNotEmpty(entry.patches)) {
@@ -110,8 +114,11 @@ export class ObjectCacheService {
         }
       ),
       map((entry: ObjectCacheEntry) => {
-        const type: GenericConstructor<NormalizedObject<T>> = getMapsToType((entry.data as any).type);
-        return Object.assign(new type(), entry.data) as NormalizedObject<T>
+        const type: GenericConstructor<T> = getClassForType((entry.data as any).type);
+        if (typeof type !== 'function') {
+          throw new Error(`${type} is not a valid constructor for ${JSON.stringify(entry.data)}`);
+        }
+        return Object.assign(new type(), entry.data) as T
       })
     );
   }
@@ -180,7 +187,7 @@ export class ObjectCacheService {
    *    The type of the objects to get
    * @return Observable<Array<T>>
    */
-  getList<T extends CacheableObject>(selfLinks: string[]): Observable<Array<NormalizedObject<T>>> {
+  getList<T extends CacheableObject>(selfLinks: string[]): Observable<T[]> {
     return observableCombineLatest(
       selfLinks.map((selfLink: string) => this.getObjectBySelfLink<T>(selfLink))
     );
@@ -254,7 +261,7 @@ export class ObjectCacheService {
       const timeOutdated = entry.timeAdded + entry.msToLive;
       const isOutDated = new Date().getTime() > timeOutdated;
       if (isOutDated) {
-        this.store.dispatch(new RemoveFromObjectCacheAction(entry.data.self));
+        this.store.dispatch(new RemoveFromObjectCacheAction(entry.data._links.self.href));
       }
       return !isOutDated;
     }
diff --git a/src/app/core/cache/response.models.ts b/src/app/core/cache/response.models.ts
index 5f4e15e13820ef0174b571884578faf0fddd08a3..3f46ecf64781a0e05ec114db4c14d62f7d4248a9 100644
--- a/src/app/core/cache/response.models.ts
+++ b/src/app/core/cache/response.models.ts
@@ -1,4 +1,5 @@
 import { SearchQueryResponse } from '../../shared/search/search-query-response.model';
+import { AuthStatus } from '../auth/models/auth-status.model';
 import { RequestError } from '../data/request.models';
 import { PageInfo } from '../shared/page-info.model';
 import { ConfigObject } from '../config/models/config.model';
@@ -11,7 +12,6 @@ import { RegistryBitstreamformatsResponse } from '../registry/registry-bitstream
 import { PaginatedList } from '../data/paginated-list';
 import { SubmissionObject } from '../submission/models/submission-object.model';
 import { DSpaceObject } from '../shared/dspace-object.model';
-import { NormalizedAuthStatus } from '../auth/models/normalized-auth-status.model';
 import { MetadataSchema } from '../metadata/metadata-schema.model';
 import { MetadataField } from '../metadata/metadata-field.model';
 import { ContentSource } from '../shared/content-source.model';
@@ -203,7 +203,7 @@ export class AuthStatusResponse extends RestResponse {
   public toCache = false;
 
   constructor(
-    public response: NormalizedAuthStatus,
+    public response: AuthStatus,
     public statusCode: number,
     public statusText: string,
   ) {
diff --git a/src/app/core/cache/server-sync-buffer.effects.spec.ts b/src/app/core/cache/server-sync-buffer.effects.spec.ts
index 66477adc20d5a2ebb95f354e295ba71742638895..3cdde3c2c61579100b098e3826c65ff6e5e4ebb9 100644
--- a/src/app/core/cache/server-sync-buffer.effects.spec.ts
+++ b/src/app/core/cache/server-sync-buffer.effects.spec.ts
@@ -1,22 +1,22 @@
 import { TestBed } from '@angular/core/testing';
-
-import { Observable, of as observableOf } from 'rxjs';
 import { provideMockActions } from '@ngrx/effects/testing';
+import { Store, StoreModule } from '@ngrx/store';
 import { cold, hot } from 'jasmine-marbles';
 
-import { ServerSyncBufferEffects } from './server-sync-buffer.effects';
+import { Observable, of as observableOf } from 'rxjs';
+import * as operators from 'rxjs/operators';
 import { GLOBAL_CONFIG } from '../../../config';
-import { CommitSSBAction, EmptySSBAction, ServerSyncBufferActionTypes } from './server-sync-buffer.actions';
-import { RestRequestMethod } from '../data/rest-request-method';
-import { Store, StoreModule } from '@ngrx/store';
-import { RequestService } from '../data/request.service';
-import { ObjectCacheService } from './object-cache.service';
+import { getMockRequestService } from '../../shared/mocks/mock-request.service';
 import { MockStore } from '../../shared/testing/mock-store';
-import * as operators from 'rxjs/operators';
 import { spyOnOperator } from '../../shared/testing/utils';
+import { RequestService } from '../data/request.service';
+import { RestRequestMethod } from '../data/rest-request-method';
 import { DSpaceObject } from '../shared/dspace-object.model';
-import { getMockRequestService } from '../../shared/mocks/mock-request.service';
 import { ApplyPatchObjectCacheAction } from './object-cache.actions';
+import { ObjectCacheService } from './object-cache.service';
+import { CommitSSBAction, EmptySSBAction, ServerSyncBufferActionTypes } from './server-sync-buffer.actions';
+
+import { ServerSyncBufferEffects } from './server-sync-buffer.effects';
 
 describe('ServerSyncBufferEffects', () => {
   let ssbEffects: ServerSyncBufferEffects;
@@ -47,8 +47,9 @@ describe('ServerSyncBufferEffects', () => {
         {
           provide: ObjectCacheService, useValue: {
             getObjectBySelfLink: (link) => {
-              const object = new DSpaceObject();
-              object.self = link;
+              const object = Object.assign(new DSpaceObject(), {
+                _links: { self: { href: link } }
+              });
               return observableOf(object);
             },
             getBySelfLink: (link) => {
diff --git a/src/app/core/cache/server-sync-buffer.effects.ts b/src/app/core/cache/server-sync-buffer.effects.ts
index dae1ab6f4fc3ffa6e0a64d027adefeadfa76b6a3..ed9340b148c0ea5da700a42f10fdf6b3e2e56e24 100644
--- a/src/app/core/cache/server-sync-buffer.effects.ts
+++ b/src/app/core/cache/server-sync-buffer.effects.ts
@@ -15,11 +15,9 @@ import { Action, createSelector, MemoizedSelector, select, Store } from '@ngrx/s
 import { ServerSyncBufferEntry, ServerSyncBufferState } from './server-sync-buffer.reducer';
 import { combineLatest as observableCombineLatest, of as observableOf } from 'rxjs';
 import { RequestService } from '../data/request.service';
-import { PatchRequest, PutRequest } from '../data/request.models';
+import { PatchRequest } from '../data/request.models';
 import { ObjectCacheService } from './object-cache.service';
 import { ApplyPatchObjectCacheAction } from './object-cache.actions';
-import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer';
-import { GenericConstructor } from '../shared/generic-constructor';
 import { hasValue, isNotEmpty, isNotUndefined } from '../../shared/empty.util';
 import { Observable } from 'rxjs/internal/Observable';
 import { RestRequestMethod } from '../data/rest-request-method';
diff --git a/src/app/core/config/config-response-parsing.service.spec.ts b/src/app/core/config/config-response-parsing.service.spec.ts
index 90dd1670b8c225ad83e25ad9c285759bbc3de27c..87a7057078ffd24fdfae8b8c4dbf3c0dcad03a44 100644
--- a/src/app/core/config/config-response-parsing.service.spec.ts
+++ b/src/app/core/config/config-response-parsing.service.spec.ts
@@ -1,22 +1,21 @@
-import { ConfigSuccessResponse, ErrorResponse } from '../cache/response.models';
-import { ConfigResponseParsingService } from './config-response-parsing.service';
-import { ObjectCacheService } from '../cache/object-cache.service';
-import { GlobalConfig } from '../../../config/global-config.interface';
-import { ConfigRequest } from '../data/request.models';
-
 import { Store } from '@ngrx/store';
+import { GlobalConfig } from '../../../config/global-config.interface';
+import { ObjectCacheService } from '../cache/object-cache.service';
+import { ConfigSuccessResponse, ErrorResponse } from '../cache/response.models';
 import { CoreState } from '../core.reducers';
 import { PaginatedList } from '../data/paginated-list';
+import { ConfigRequest } from '../data/request.models';
 import { PageInfo } from '../shared/page-info.model';
-import { NormalizedSubmissionSectionModel } from './models/normalized-config-submission-section.model';
-import { NormalizedSubmissionDefinitionModel } from './models/normalized-config-submission-definition.model';
+import { ConfigResponseParsingService } from './config-response-parsing.service';
+import { SubmissionDefinitionModel } from './models/config-submission-definition.model';
+import { SubmissionSectionModel } from './models/config-submission-section.model';
 
 describe('ConfigResponseParsingService', () => {
   let service: ConfigResponseParsingService;
 
   const EnvConfig = {} as GlobalConfig;
   const store = {} as Store<CoreState>;
-  const objectCacheService = new ObjectCacheService(store);
+  const objectCacheService = new ObjectCacheService(store, undefined);
   let validResponse;
   beforeEach(() => {
     service = new ConfigResponseParsingService(EnvConfig, objectCacheService);
@@ -150,7 +149,7 @@ describe('ConfigResponseParsingService', () => {
             },
             _embedded: [{}, {}],
             _links: {
-              self: 'https://rest.api/config/submissiondefinitions/traditional/sections'
+              self: { href: 'https://rest.api/config/submissiondefinitions/traditional/sections' }
             }
           }
         }
@@ -170,77 +169,76 @@ describe('ConfigResponseParsingService', () => {
       totalElements: 4,
       totalPages: 1,
       currentPage: 1,
-      self: 'https://rest.api/config/submissiondefinitions/traditional/sections'
+      _links: {
+        self: {
+          href: 'https://rest.api/config/submissiondefinitions/traditional/sections'
+        },
+      },
     });
     const definitions =
-      Object.assign(new NormalizedSubmissionDefinitionModel(), {
+      Object.assign(new SubmissionDefinitionModel(), {
         isDefault: true,
         name: 'traditional',
         type: 'submissiondefinition',
         _links: {
-          sections: 'https://rest.api/config/submissiondefinitions/traditional/sections',
-          self: 'https://rest.api/config/submissiondefinitions/traditional'
+          sections: { href: 'https://rest.api/config/submissiondefinitions/traditional/sections' },
+          self: { href: 'https://rest.api/config/submissiondefinitions/traditional' }
         },
-        self: 'https://rest.api/config/submissiondefinitions/traditional',
         sections: new PaginatedList(pageinfo, [
-          Object.assign(new NormalizedSubmissionSectionModel(), {
+          Object.assign(new SubmissionSectionModel(), {
             header: 'submit.progressbar.describe.stepone',
             mandatory: true,
             sectionType: 'submission-form',
-            visibility:{
-              main:null,
-              other:'READONLY'
+            visibility: {
+              main: null,
+              other: 'READONLY'
             },
             type: 'submissionsection',
             _links: {
-              self: 'https://rest.api/config/submissionsections/traditionalpageone',
-              config: 'https://rest.api/config/submissionforms/traditionalpageone'
+              self: { href: 'https://rest.api/config/submissionsections/traditionalpageone' },
+              config: { href: 'https://rest.api/config/submissionforms/traditionalpageone' }
             },
-            self: 'https://rest.api/config/submissionsections/traditionalpageone',
           }),
-          Object.assign(new NormalizedSubmissionSectionModel(), {
+          Object.assign(new SubmissionSectionModel(), {
             header: 'submit.progressbar.describe.steptwo',
             mandatory: true,
             sectionType: 'submission-form',
-            visibility:{
-              main:null,
-              other:'READONLY'
+            visibility: {
+              main: null,
+              other: 'READONLY'
             },
             type: 'submissionsection',
             _links: {
-              self: 'https://rest.api/config/submissionsections/traditionalpagetwo',
-              config: 'https://rest.api/config/submissionforms/traditionalpagetwo'
+              self: { href: 'https://rest.api/config/submissionsections/traditionalpagetwo' },
+              config: { href: 'https://rest.api/config/submissionforms/traditionalpagetwo' }
             },
-            self: 'https://rest.api/config/submissionsections/traditionalpagetwo',
           }),
-          Object.assign(new NormalizedSubmissionSectionModel(), {
+          Object.assign(new SubmissionSectionModel(), {
             header: 'submit.progressbar.upload',
             mandatory: false,
             sectionType: 'upload',
-            visibility:{
-              main:null,
-              other:'READONLY'
+            visibility: {
+              main: null,
+              other: 'READONLY'
             },
             type: 'submissionsection',
             _links: {
-              self: 'https://rest.api/config/submissionsections/upload',
-              config: 'https://rest.api/config/submissionuploads/upload'
+              self: { href: 'https://rest.api/config/submissionsections/upload' },
+              config: { href: 'https://rest.api/config/submissionuploads/upload' }
             },
-            self: 'https://rest.api/config/submissionsections/upload',
           }),
-          Object.assign(new NormalizedSubmissionSectionModel(), {
+          Object.assign(new SubmissionSectionModel(), {
             header: 'submit.progressbar.license',
             mandatory: true,
             sectionType: 'license',
-            visibility:{
-              main:null,
-              other:'READONLY'
+            visibility: {
+              main: null,
+              other: 'READONLY'
             },
             type: 'submissionsection',
             _links: {
-              self: 'https://rest.api/config/submissionsections/license'
+              self: { href: 'https://rest.api/config/submissionsections/license' }
             },
-            self: 'https://rest.api/config/submissionsections/license',
           })
         ])
       });
diff --git a/src/app/core/config/config-response-parsing.service.ts b/src/app/core/config/config-response-parsing.service.ts
index d1f49710d3654bada4089f7e1cfc7624261efb8c..d674445d544b225504ad574abffd10f5d786ab87 100644
--- a/src/app/core/config/config-response-parsing.service.ts
+++ b/src/app/core/config/config-response-parsing.service.ts
@@ -15,6 +15,7 @@ import { ObjectCacheService } from '../cache/object-cache.service';
 @Injectable()
 export class ConfigResponseParsingService extends BaseResponseParsingService implements ResponseParsingService {
   protected toCache = false;
+  protected shouldDirectlyAttachEmbeds = true;
 
   constructor(
     @Inject(GLOBAL_CONFIG) protected EnvConfig: GlobalConfig,
diff --git a/src/app/core/config/models/config-submission-definition.model.ts b/src/app/core/config/models/config-submission-definition.model.ts
index 0449e6a964c3f0c21b0ad50c9a26f35ca91b1004..f3e888d5138b583e3fe4b409fb894f0c588a2432 100644
--- a/src/app/core/config/models/config-submission-definition.model.ts
+++ b/src/app/core/config/models/config-submission-definition.model.ts
@@ -1,22 +1,40 @@
-import { ConfigObject } from './config.model';
-import { SubmissionSectionModel } from './config-submission-section.model';
+import { autoserialize, deserialize, inheritSerialization } from 'cerialize';
+import { typedObject } from '../../cache/builders/build-decorators';
 import { PaginatedList } from '../../data/paginated-list';
+import { HALLink } from '../../shared/hal-link.model';
 import { ResourceType } from '../../shared/resource-type';
+import { SubmissionSectionModel } from './config-submission-section.model';
+import { ConfigObject } from './config.model';
 
 /**
  * Class for the configuration describing the submission
  */
+@typedObject
+@inheritSerialization(ConfigObject)
 export class SubmissionDefinitionModel extends ConfigObject {
   static type = new ResourceType('submissiondefinition');
 
   /**
    * A boolean representing if this submission definition is the default or not
    */
+  @autoserialize
   isDefault: boolean;
 
   /**
    * A list of SubmissionSectionModel that are present in this submission definition
    */
+  // TODO refactor using remotedata
+  @deserialize
   sections: PaginatedList<SubmissionSectionModel>;
 
+  /**
+   * The links to all related resources returned by the rest api.
+   */
+  @deserialize
+  _links: {
+    self: HALLink,
+    collections: HALLink,
+    sections: HALLink
+  };
+
 }
diff --git a/src/app/core/config/models/config-submission-definitions.model.ts b/src/app/core/config/models/config-submission-definitions.model.ts
index d9892f542f3d703116017e813add318d5a290880..1fdf57180694c761401e8b230c25e0d946b111c7 100644
--- a/src/app/core/config/models/config-submission-definitions.model.ts
+++ b/src/app/core/config/models/config-submission-definitions.model.ts
@@ -1,6 +1,10 @@
+import { inheritSerialization } from 'cerialize';
+import { typedObject } from '../../cache/builders/build-decorators';
 import { SubmissionDefinitionModel } from './config-submission-definition.model';
 import { ResourceType } from '../../shared/resource-type';
 
+@typedObject
+@inheritSerialization(SubmissionDefinitionModel)
 export class SubmissionDefinitionsModel extends SubmissionDefinitionModel {
   static type = new ResourceType('submissiondefinitions');
 
diff --git a/src/app/core/config/models/config-submission-form.model.ts b/src/app/core/config/models/config-submission-form.model.ts
index a65d285c95e9eae45c4a7a34dc3ba4ccc8ab5f88..d3fcfa973898948b0852b75e7ff175b411139499 100644
--- a/src/app/core/config/models/config-submission-form.model.ts
+++ b/src/app/core/config/models/config-submission-form.model.ts
@@ -1,3 +1,5 @@
+import { autoserialize, inheritSerialization } from 'cerialize';
+import { typedObject } from '../../cache/builders/build-decorators';
 import { ConfigObject } from './config.model';
 import { FormFieldModel } from '../../../shared/form/builder/models/form-field.model';
 import { ResourceType } from '../../shared/resource-type';
@@ -12,11 +14,14 @@ export interface FormRowModel {
 /**
  * A model class for a NormalizedObject.
  */
+@typedObject
+@inheritSerialization(ConfigObject)
 export class SubmissionFormModel extends ConfigObject {
   static type = new ResourceType('submissionform');
 
   /**
    * An array of [FormRowModel] that are present in this form
    */
+  @autoserialize
   rows: FormRowModel[];
 }
diff --git a/src/app/core/config/models/config-submission-forms.model.ts b/src/app/core/config/models/config-submission-forms.model.ts
index 017d7d68cc1f813bd1ec68c95727865956c44f6c..8130bf32647c34946ccef136b54a95170710d5ad 100644
--- a/src/app/core/config/models/config-submission-forms.model.ts
+++ b/src/app/core/config/models/config-submission-forms.model.ts
@@ -1,9 +1,13 @@
+import { inheritSerialization } from 'cerialize';
+import { typedObject } from '../../cache/builders/build-decorators';
 import { SubmissionFormModel } from './config-submission-form.model';
 import { ResourceType } from '../../shared/resource-type';
 
 /**
  * A model class for a NormalizedObject.
  */
+@typedObject
+@inheritSerialization(SubmissionFormModel)
 export class SubmissionFormsModel extends SubmissionFormModel {
   static type = new ResourceType('submissionforms');
 }
diff --git a/src/app/core/config/models/config-submission-section.model.ts b/src/app/core/config/models/config-submission-section.model.ts
index 4c560fa631b9e2ccf24c0a434c4a1c2b465e77db..d8249297b1a17ae3107e3299cab5dbdfed323f15 100644
--- a/src/app/core/config/models/config-submission-section.model.ts
+++ b/src/app/core/config/models/config-submission-section.model.ts
@@ -1,6 +1,9 @@
-import { ConfigObject } from './config.model';
+import { autoserialize, deserialize, inheritSerialization } from 'cerialize';
 import { SectionsType } from '../../../submission/sections/sections-type';
+import { typedObject } from '../../cache/builders/build-decorators';
+import { HALLink } from '../../shared/hal-link.model';
 import { ResourceType } from '../../shared/resource-type';
+import { ConfigObject } from './config.model';
 
 /**
  * An interface that define section visibility and its properties.
@@ -10,27 +13,42 @@ export interface SubmissionSectionVisibility {
   other: any
 }
 
+@typedObject
+@inheritSerialization(ConfigObject)
 export class SubmissionSectionModel extends ConfigObject {
   static type = new ResourceType('submissionsection');
 
   /**
    * The header for this section
    */
+  @autoserialize
   header: string;
 
   /**
    * A boolean representing if this submission section is the mandatory or not
    */
+  @autoserialize
   mandatory: boolean;
 
   /**
    * A string representing the kind of section object
    */
+  @autoserialize
   sectionType: SectionsType;
 
   /**
    * The [SubmissionSectionVisibility] object for this section
    */
-  visibility: SubmissionSectionVisibility
+  @autoserialize
+  visibility: SubmissionSectionVisibility;
+
+  /**
+   * The {@link HALLink}s for this SubmissionSectionModel
+   */
+  @deserialize
+  _links: {
+    self: HALLink;
+    config: HALLink;
+  }
 
 }
diff --git a/src/app/core/config/models/config-submission-sections.model.ts b/src/app/core/config/models/config-submission-sections.model.ts
index ae7b1333916fab1c931f368b18ff8b7d7a116845..7f787122731e5df47850b2dc440e47b02f5c3501 100644
--- a/src/app/core/config/models/config-submission-sections.model.ts
+++ b/src/app/core/config/models/config-submission-sections.model.ts
@@ -1,6 +1,10 @@
+import { inheritSerialization } from 'cerialize';
+import { typedObject } from '../../cache/builders/build-decorators';
 import { SubmissionSectionModel } from './config-submission-section.model';
 import { ResourceType } from '../../shared/resource-type';
 
+@typedObject
+@inheritSerialization(SubmissionSectionModel)
 export class SubmissionSectionsModel extends SubmissionSectionModel {
   static type = new ResourceType('submissionsections');
 }
diff --git a/src/app/core/config/models/config-submission-uploads.model.ts b/src/app/core/config/models/config-submission-uploads.model.ts
index 812a59004144ce349ced902e0b88dddd3941079e..b7733ee25d3e61c117ca3208bda2b7da022ac62a 100644
--- a/src/app/core/config/models/config-submission-uploads.model.ts
+++ b/src/app/core/config/models/config-submission-uploads.model.ts
@@ -1,22 +1,30 @@
+import { autoserialize, inheritSerialization } from 'cerialize';
+import { typedObject } from '../../cache/builders/build-decorators';
 import { ConfigObject } from './config.model';
 import { AccessConditionOption } from './config-access-condition-option.model';
 import { SubmissionFormsModel } from './config-submission-forms.model';
 import { ResourceType } from '../../shared/resource-type';
 
+@typedObject
+@inheritSerialization(ConfigObject)
 export class SubmissionUploadsModel extends ConfigObject {
   static type =  new ResourceType('submissionupload');
   /**
    * A list of available bitstream access conditions
    */
+  @autoserialize
   accessConditionOptions: AccessConditionOption[];
 
   /**
    * An object representing the configuration describing the bistream metadata form
    */
+  @autoserialize
   metadata: SubmissionFormsModel;
 
+  @autoserialize
   required: boolean;
 
+  @autoserialize
   maxSize: number;
 
 }
diff --git a/src/app/core/config/models/config.model.ts b/src/app/core/config/models/config.model.ts
index 20d67ec69d3d16691971742bd1ee266929275de9..fabb16eb233787004d7f16d23d60835b1c47eb16 100644
--- a/src/app/core/config/models/config.model.ts
+++ b/src/app/core/config/models/config.model.ts
@@ -1,22 +1,30 @@
+import { autoserialize, deserialize } from 'cerialize';
 import { CacheableObject } from '../../cache/object-cache.reducer';
+import { HALLink } from '../../shared/hal-link.model';
 import { ResourceType } from '../../shared/resource-type';
+import { excludeFromEquals } from '../../utilities/equals.decorators';
 
 export abstract class ConfigObject implements CacheableObject {
 
   /**
    * The name for this configuration
    */
+  @autoserialize
   public name: string;
 
   /**
-   * The links to all related resources returned by the rest api.
+   * The type of this ConfigObject
    */
-  public _links: {
-    [name: string]: string
-  };
+  @excludeFromEquals
+  @autoserialize
+  type: ResourceType;
 
   /**
-   * The link to the rest endpoint where this config object can be found
+   * The links to all related resources returned by the rest api.
    */
-  self: string;
+  @deserialize
+  _links: {
+    self: HALLink,
+    [name: string]: HALLink
+  };
 }
diff --git a/src/app/core/config/models/normalized-config-submission-definition.model.ts b/src/app/core/config/models/normalized-config-submission-definition.model.ts
deleted file mode 100644
index cb56e01acf4a820e3339f8f88e1a8ba8b189bba0..0000000000000000000000000000000000000000
--- a/src/app/core/config/models/normalized-config-submission-definition.model.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-import { autoserialize, autoserializeAs, inheritSerialization } from 'cerialize';
-import { SubmissionSectionModel } from './config-submission-section.model';
-import { PaginatedList } from '../../data/paginated-list';
-import { NormalizedConfigObject } from './normalized-config.model';
-import { SubmissionDefinitionsModel } from './config-submission-definitions.model';
-import { mapsTo } from '../../cache/builders/build-decorators';
-import { SubmissionDefinitionModel } from './config-submission-definition.model';
-
-/**
- * Normalized class for the configuration describing the submission
- */
-@mapsTo(SubmissionDefinitionModel)
-@inheritSerialization(NormalizedConfigObject)
-export class NormalizedSubmissionDefinitionModel extends NormalizedConfigObject<SubmissionDefinitionModel> {
-
-  /**
-   * A boolean representing if this submission definition is the default or not
-   */
-  @autoserialize
-  isDefault: boolean;
-
-  /**
-   * A list of SubmissionSectionModel that are present in this submission definition
-   */
-  @autoserializeAs(SubmissionSectionModel)
-  sections: PaginatedList<SubmissionSectionModel>;
-
-}
diff --git a/src/app/core/config/models/normalized-config-submission-definitions.model.ts b/src/app/core/config/models/normalized-config-submission-definitions.model.ts
deleted file mode 100644
index 4c52d96458d3dbf7039450386fea36319f07fb08..0000000000000000000000000000000000000000
--- a/src/app/core/config/models/normalized-config-submission-definitions.model.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import { inheritSerialization } from 'cerialize';
-import { NormalizedConfigObject } from './normalized-config.model';
-import { SubmissionDefinitionsModel } from './config-submission-definitions.model';
-import { mapsTo } from '../../cache/builders/build-decorators';
-import { NormalizedSubmissionDefinitionModel } from './normalized-config-submission-definition.model';
-
-/**
- * Normalized class for the configuration describing the submission
- */
-@mapsTo(SubmissionDefinitionsModel)
-@inheritSerialization(NormalizedConfigObject)
-export class NormalizedSubmissionDefinitionsModel extends NormalizedSubmissionDefinitionModel {
-}
diff --git a/src/app/core/config/models/normalized-config-submission-form.model.ts b/src/app/core/config/models/normalized-config-submission-form.model.ts
deleted file mode 100644
index afdfef481854b6015e284aee84326ab9dc4e0f67..0000000000000000000000000000000000000000
--- a/src/app/core/config/models/normalized-config-submission-form.model.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-import { autoserialize, inheritSerialization } from 'cerialize';
-import { NormalizedConfigObject } from './normalized-config.model';
-import { mapsTo } from '../../cache/builders/build-decorators';
-import { FormRowModel, SubmissionFormModel } from './config-submission-form.model';
-
-/**
- * Normalized class for the configuration describing the submission form
- */
-@mapsTo(SubmissionFormModel)
-@inheritSerialization(NormalizedConfigObject)
-export class NormalizedSubmissionFormModel extends NormalizedConfigObject<SubmissionFormModel> {
-
-  /**
-   * An array of [FormRowModel] that are present in this form
-   */
-  @autoserialize
-  rows: FormRowModel[];
-}
diff --git a/src/app/core/config/models/normalized-config-submission-forms.model.ts b/src/app/core/config/models/normalized-config-submission-forms.model.ts
deleted file mode 100644
index c040a945874451aa5e2483a56907d8a6de064471..0000000000000000000000000000000000000000
--- a/src/app/core/config/models/normalized-config-submission-forms.model.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import { inheritSerialization } from 'cerialize';
-import { mapsTo } from '../../cache/builders/build-decorators';
-import { SubmissionFormsModel } from './config-submission-forms.model';
-import { NormalizedSubmissionFormModel } from './normalized-config-submission-form.model';
-
-/**
- * Normalized class for the configuration describing the submission form
- */
-@mapsTo(SubmissionFormsModel)
-@inheritSerialization(NormalizedSubmissionFormModel)
-export class NormalizedSubmissionFormsModel extends NormalizedSubmissionFormModel {
-}
diff --git a/src/app/core/config/models/normalized-config-submission-section.model.ts b/src/app/core/config/models/normalized-config-submission-section.model.ts
deleted file mode 100644
index 364a981060584192a18df26211b7549b03064abd..0000000000000000000000000000000000000000
--- a/src/app/core/config/models/normalized-config-submission-section.model.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-import { autoserialize, inheritSerialization } from 'cerialize';
-import { SectionsType } from '../../../submission/sections/sections-type';
-import { NormalizedConfigObject } from './normalized-config.model';
-import {
-  SubmissionSectionModel,
-  SubmissionSectionVisibility
-} from './config-submission-section.model';
-import { mapsTo } from '../../cache/builders/build-decorators';
-
-/**
- * Normalized class for the configuration describing the submission section
- */
-@mapsTo(SubmissionSectionModel)
-@inheritSerialization(NormalizedConfigObject)
-export class NormalizedSubmissionSectionModel extends NormalizedConfigObject<SubmissionSectionModel> {
-
-  /**
-   * The header for this section
-   */
-  @autoserialize
-  header: string;
-
-  /**
-   * A boolean representing if this submission section is the mandatory or not
-   */
-  @autoserialize
-  mandatory: boolean;
-
-  /**
-   * A string representing the kind of section object
-   */
-  @autoserialize
-  sectionType: SectionsType;
-
-  /**
-   * The [SubmissionSectionVisibility] object for this section
-   */
-  @autoserialize
-  visibility: SubmissionSectionVisibility
-
-}
diff --git a/src/app/core/config/models/normalized-config-submission-sections.model.ts b/src/app/core/config/models/normalized-config-submission-sections.model.ts
deleted file mode 100644
index fb1e4c671ab2e56b4ac75131508b2d0306450b04..0000000000000000000000000000000000000000
--- a/src/app/core/config/models/normalized-config-submission-sections.model.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-import { autoserialize, inheritSerialization } from 'cerialize';
-import { SectionsType } from '../../../submission/sections/sections-type';
-import { NormalizedConfigObject } from './normalized-config.model';
-import {
-  SubmissionSectionModel,
-  SubmissionSectionVisibility
-} from './config-submission-section.model';
-import { mapsTo } from '../../cache/builders/build-decorators';
-import { SubmissionSectionsModel } from './config-submission-sections.model';
-import { NormalizedSubmissionSectionModel } from './normalized-config-submission-section.model';
-
-/**
- * Normalized class for the configuration describing the submission section
- */
-@mapsTo(SubmissionSectionsModel)
-@inheritSerialization(NormalizedSubmissionSectionModel)
-export class NormalizedSubmissionSectionsModel extends NormalizedSubmissionSectionModel {
-}
diff --git a/src/app/core/config/models/normalized-config-submission-uploads.model.ts b/src/app/core/config/models/normalized-config-submission-uploads.model.ts
deleted file mode 100644
index 7a21c15912694fccb583e9c7af604a5e401fc9fa..0000000000000000000000000000000000000000
--- a/src/app/core/config/models/normalized-config-submission-uploads.model.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-import { autoserialize, autoserializeAs, inheritSerialization } from 'cerialize';
-import { AccessConditionOption } from './config-access-condition-option.model';
-import { SubmissionFormsModel } from './config-submission-forms.model';
-import { NormalizedConfigObject } from './normalized-config.model';
-import { SubmissionUploadsModel } from './config-submission-uploads.model';
-import { mapsTo } from '../../cache/builders/build-decorators';
-
-/**
- * Normalized class for the configuration describing the submission upload section
- */
-@mapsTo(SubmissionUploadsModel)
-@inheritSerialization(NormalizedConfigObject)
-export class NormalizedSubmissionUploadsModel extends NormalizedConfigObject<SubmissionUploadsModel> {
-
-  /**
-   * A list of available bitstream access conditions
-   */
-  @autoserialize
-  accessConditionOptions: AccessConditionOption[];
-
-  /**
-   * An object representing the configuration describing the bistream metadata form
-   */
-  @autoserializeAs(SubmissionFormsModel)
-  metadata: SubmissionFormsModel;
-
-  @autoserialize
-  required: boolean;
-
-  @autoserialize
-  maxSize: number;
-
-}
diff --git a/src/app/core/config/models/normalized-config.model.ts b/src/app/core/config/models/normalized-config.model.ts
deleted file mode 100644
index 1bf4ffb826c17dd9f90420e5ba44916f069f4af8..0000000000000000000000000000000000000000
--- a/src/app/core/config/models/normalized-config.model.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-import { autoserialize, inheritSerialization } from 'cerialize';
-import { NormalizedObject } from '../../cache/models/normalized-object.model';
-import { CacheableObject, TypedObject } from '../../cache/object-cache.reducer';
-import { ResourceType } from '../../shared/resource-type';
-
-/**
- * Normalized abstract class for a configuration object
- */
-@inheritSerialization(NormalizedObject)
-export abstract class NormalizedConfigObject<T extends CacheableObject> implements CacheableObject {
-
-  /**
-   * The name for this configuration
-   */
-  @autoserialize
-  public name: string;
-
-  /**
-   * The links to all related resources returned by the rest api.
-   */
-  @autoserialize
-  public _links: {
-    [name: string]: string
-  };
-
-  /**
-   * The link to the rest endpoint where this config object can be found
-   */
-  @autoserialize
-  self: string;
-
-}
diff --git a/src/app/core/core.module.ts b/src/app/core/core.module.ts
index e2c8e1a3b542a8f1bf8386fc4ae257e9f16a1eaf..9180b0882a05c680bc799e7b09330e9863700766 100644
--- a/src/app/core/core.module.ts
+++ b/src/app/core/core.module.ts
@@ -1,149 +1,149 @@
-import { ModuleWithProviders, NgModule, Optional, SkipSelf } from '@angular/core';
 import { CommonModule } from '@angular/common';
-
-import { StoreModule } from '@ngrx/store';
-import { EffectsModule } from '@ngrx/effects';
+import { HTTP_INTERCEPTORS, HttpClient } from '@angular/common/http';
+import { ModuleWithProviders, NgModule, Optional, SkipSelf } from '@angular/core';
 import {
   DynamicFormLayoutService,
   DynamicFormService,
   DynamicFormValidationService
 } from '@ng-dynamic-forms/core';
+import { EffectsModule } from '@ngrx/effects';
 
-import { coreEffects } from './core.effects';
-import { coreReducers } from './core.reducers';
+import { StoreModule } from '@ngrx/store';
+import { MyDSpaceGuard } from '../+my-dspace-page/my-dspace.guard';
+import { ENV_CONFIG, GLOBAL_CONFIG, GlobalConfig } from '../../config';
 
 import { isNotEmpty } from '../shared/empty.util';
-
-import { ApiService } from './services/api.service';
-import { BrowseEntriesResponseParsingService } from './data/browse-entries-response-parsing.service';
-import { CollectionDataService } from './data/collection-data.service';
-import { CommunityDataService } from './data/community-data.service';
-import { DebugResponseParsingService } from './data/debug-response-parsing.service';
-import { DSOResponseParsingService } from './data/dso-response-parsing.service';
-import { SearchResponseParsingService } from './data/search-response-parsing.service';
-import { DSpaceRESTv2Service } from './dspace-rest-v2/dspace-rest-v2.service';
 import { FormBuilderService } from '../shared/form/builder/form-builder.service';
-import { SectionFormOperationsService } from '../submission/sections/form/section-form-operations.service';
 import { FormService } from '../shared/form/form.service';
-import { GroupEpersonService } from './eperson/group-eperson.service';
 import { HostWindowService } from '../shared/host-window.service';
-import { ItemDataService } from './data/item-data.service';
-import { MetadataService } from './metadata/metadata.service';
-import { ObjectCacheService } from './cache/object-cache.service';
+import { MenuService } from '../shared/menu/menu.service';
+import { EndpointMockingRestService } from '../shared/mocks/dspace-rest-v2/endpoint-mocking-rest.service';
+
+import {
+  MOCK_RESPONSE_MAP,
+  MockResponseMap,
+  mockResponseMap
+} from '../shared/mocks/dspace-rest-v2/mocks/mock-response-map';
+import { NotificationsService } from '../shared/notifications/notifications.service';
+import { SelectableListService } from '../shared/object-list/selectable-list/selectable-list.service';
+import { ObjectSelectService } from '../shared/object-select/object-select.service';
 import { PaginationComponentOptions } from '../shared/pagination/pagination-component-options.model';
-import { RemoteDataBuildService } from './cache/builders/remote-data-build.service';
-import { RequestService } from './data/request.service';
-import { EndpointMapResponseParsingService } from './data/endpoint-map-response-parsing.service';
-import { ServerResponseService } from './services/server-response.service';
-import { NativeWindowFactory, NativeWindowService } from './services/window.service';
+import { CSSVariableService } from '../shared/sass-helper/sass-helper.service';
+import { SidebarService } from '../shared/sidebar/sidebar.service';
+import { UploaderService } from '../shared/uploader/uploader.service';
+import { SectionFormOperationsService } from '../submission/sections/form/section-form-operations.service';
+import { AuthRequestService } from './auth/auth-request.service';
+import { AuthResponseParsingService } from './auth/auth-response-parsing.service';
+import { AuthInterceptor } from './auth/auth.interceptor';
+import { AuthenticatedGuard } from './auth/authenticated.guard';
+import { AuthStatus } from './auth/models/auth-status.model';
 import { BrowseService } from './browse/browse.service';
-import { BrowseResponseParsingService } from './data/browse-response-parsing.service';
+import { RemoteDataBuildService } from './cache/builders/remote-data-build.service';
+import { ObjectCacheService } from './cache/object-cache.service';
 import { ConfigResponseParsingService } from './config/config-response-parsing.service';
-import { RouteService } from './services/route.service';
+import { SubmissionDefinitionsModel } from './config/models/config-submission-definitions.model';
+import { SubmissionFormsModel } from './config/models/config-submission-forms.model';
+import { SubmissionSectionModel } from './config/models/config-submission-section.model';
+import { SubmissionUploadsModel } from './config/models/config-submission-uploads.model';
 import { SubmissionDefinitionsConfigService } from './config/submission-definitions-config.service';
 import { SubmissionFormsConfigService } from './config/submission-forms-config.service';
 import { SubmissionSectionsConfigService } from './config/submission-sections-config.service';
-import { SubmissionResponseParsingService } from './submission/submission-response-parsing.service';
-import { EpersonResponseParsingService } from './eperson/eperson-response-parsing.service';
-import { JsonPatchOperationsBuilder } from './json-patch/builder/json-patch-operations-builder';
-import { AuthorityService } from './integration/authority.service';
-import { IntegrationResponseParsingService } from './integration/integration-response-parsing.service';
-import { WorkspaceitemDataService } from './submission/workspaceitem-data.service';
-import { UUIDService } from './shared/uuid.service';
-import { AuthenticatedGuard } from './auth/authenticated.guard';
-import { AuthRequestService } from './auth/auth-request.service';
-import { AuthResponseParsingService } from './auth/auth-response-parsing.service';
-import { HTTP_INTERCEPTORS, HttpClient } from '@angular/common/http';
-import { AuthInterceptor } from './auth/auth.interceptor';
-import { HALEndpointService } from './shared/hal-endpoint.service';
-import { FacetValueResponseParsingService } from './data/facet-value-response-parsing.service';
-import { FacetValueMapResponseParsingService } from './data/facet-value-map-response-parsing.service';
-import { FacetConfigResponseParsingService } from './data/facet-config-response-parsing.service';
-import { ResourcePolicyService } from './data/resource-policy.service';
-import { RegistryService } from './registry/registry.service';
-import { RegistryMetadataschemasResponseParsingService } from './data/registry-metadataschemas-response-parsing.service';
-import { RegistryMetadatafieldsResponseParsingService } from './data/registry-metadatafields-response-parsing.service';
-import { RegistryBitstreamformatsResponseParsingService } from './data/registry-bitstreamformats-response-parsing.service';
-import { WorkflowItemDataService } from './submission/workflowitem-data.service';
-import { NotificationsService } from '../shared/notifications/notifications.service';
-import { UploaderService } from '../shared/uploader/uploader.service';
-import { FileService } from './shared/file.service';
-import { SubmissionRestService } from './submission/submission-rest.service';
+
+import { coreEffects } from './core.effects';
+import { coreReducers } from './core.reducers';
+import { BitstreamFormatDataService } from './data/bitstream-format-data.service';
+import { BrowseEntriesResponseParsingService } from './data/browse-entries-response-parsing.service';
 import { BrowseItemsResponseParsingService } from './data/browse-items-response-parsing-service';
+import { BrowseResponseParsingService } from './data/browse-response-parsing.service';
+import { CollectionDataService } from './data/collection-data.service';
+import { CommunityDataService } from './data/community-data.service';
+import { ContentSourceResponseParsingService } from './data/content-source-response-parsing.service';
+import { DebugResponseParsingService } from './data/debug-response-parsing.service';
+import { DefaultChangeAnalyzer } from './data/default-change-analyzer.service';
+import { DSOChangeAnalyzer } from './data/dso-change-analyzer.service';
+import { DSOResponseParsingService } from './data/dso-response-parsing.service';
 import { DSpaceObjectDataService } from './data/dspace-object-data.service';
-import { MetadataschemaParsingService } from './data/metadataschema-parsing.service';
+import { EndpointMapResponseParsingService } from './data/endpoint-map-response-parsing.service';
+import { ItemTypeDataService } from './data/entity-type-data.service';
+import { EntityTypeService } from './data/entity-type.service';
+import { ExternalSourceService } from './data/external-source.service';
+import { FacetConfigResponseParsingService } from './data/facet-config-response-parsing.service';
+import { FacetValueMapResponseParsingService } from './data/facet-value-map-response-parsing.service';
+import { FacetValueResponseParsingService } from './data/facet-value-response-parsing.service';
 import { FilteredDiscoveryPageResponseParsingService } from './data/filtered-discovery-page-response-parsing.service';
-import { CSSVariableService } from '../shared/sass-helper/sass-helper.service';
-import { MenuService } from '../shared/menu/menu.service';
-import { SubmissionJsonPatchOperationsService } from './submission/submission-json-patch-operations.service';
-import { NormalizedObjectBuildService } from './cache/builders/normalized-object-build.service';
-import { DSOChangeAnalyzer } from './data/dso-change-analyzer.service';
+import { ItemDataService } from './data/item-data.service';
+import { LicenseDataService } from './data/license-data.service';
+import { LookupRelationService } from './data/lookup-relation.service';
+import { MappedCollectionsReponseParsingService } from './data/mapped-collections-reponse-parsing.service';
+import { MetadatafieldParsingService } from './data/metadatafield-parsing.service';
+import { MetadataschemaParsingService } from './data/metadataschema-parsing.service';
+import { MyDSpaceResponseParsingService } from './data/mydspace-response-parsing.service';
 import { ObjectUpdatesService } from './data/object-updates/object-updates.service';
-import { DefaultChangeAnalyzer } from './data/default-change-analyzer.service';
-import { SearchService } from './shared/search/search.service';
+import { RegistryBitstreamformatsResponseParsingService } from './data/registry-bitstreamformats-response-parsing.service';
+import { RegistryMetadatafieldsResponseParsingService } from './data/registry-metadatafields-response-parsing.service';
+import { RegistryMetadataschemasResponseParsingService } from './data/registry-metadataschemas-response-parsing.service';
+import { RelationshipTypeService } from './data/relationship-type.service';
 import { RelationshipService } from './data/relationship.service';
-import { NormalizedCollection } from './cache/models/normalized-collection.model';
-import { NormalizedCommunity } from './cache/models/normalized-community.model';
-import { NormalizedDSpaceObject } from './cache/models/normalized-dspace-object.model';
-import { NormalizedBitstream } from './cache/models/normalized-bitstream.model';
-import { NormalizedBundle } from './cache/models/normalized-bundle.model';
-import { NormalizedBitstreamFormat } from './cache/models/normalized-bitstream-format.model';
-import { NormalizedItem } from './cache/models/normalized-item.model';
-import { NormalizedEPerson } from './eperson/models/normalized-eperson.model';
-import { NormalizedGroup } from './eperson/models/normalized-group.model';
-import { NormalizedResourcePolicy } from './cache/models/normalized-resource-policy.model';
-import { NormalizedMetadataSchema } from './metadata/normalized-metadata-schema.model';
-import { NormalizedMetadataField } from './metadata/normalized-metadata-field.model';
-import { NormalizedLicense } from './cache/models/normalized-license.model';
-import { NormalizedWorkflowItem } from './submission/models/normalized-workflowitem.model';
-import { NormalizedWorkspaceItem } from './submission/models/normalized-workspaceitem.model';
-import { NormalizedSubmissionDefinitionsModel } from './config/models/normalized-config-submission-definitions.model';
-import { NormalizedSubmissionFormsModel } from './config/models/normalized-config-submission-forms.model';
-import { NormalizedSubmissionSectionModel } from './config/models/normalized-config-submission-section.model';
-import { NormalizedAuthStatus } from './auth/models/normalized-auth-status.model';
-import { NormalizedAuthorityValue } from './integration/models/normalized-authority-value.model';
+import { ResourcePolicyService } from './data/resource-policy.service';
+import { SearchResponseParsingService } from './data/search-response-parsing.service';
+import { SiteDataService } from './data/site-data.service';
+import { DSpaceRESTv2Service } from './dspace-rest-v2/dspace-rest-v2.service';
+import { EPersonDataService } from './eperson/eperson-data.service';
+import { EpersonResponseParsingService } from './eperson/eperson-response-parsing.service';
+import { EPerson } from './eperson/models/eperson.model';
+import { Group } from './eperson/models/group.model';
+import { AuthorityService } from './integration/authority.service';
+import { IntegrationResponseParsingService } from './integration/integration-response-parsing.service';
+import { AuthorityValue } from './integration/models/authority.value';
+import { JsonPatchOperationsBuilder } from './json-patch/builder/json-patch-operations-builder';
+import { MetadataField } from './metadata/metadata-field.model';
+import { MetadataSchema } from './metadata/metadata-schema.model';
+import { MetadataService } from './metadata/metadata.service';
+import { RegistryService } from './registry/registry.service';
 import { RoleService } from './roles/role.service';
-import { MyDSpaceGuard } from '../+my-dspace-page/my-dspace.guard';
-import { MyDSpaceResponseParsingService } from './data/mydspace-response-parsing.service';
+
+import { ApiService } from './services/api.service';
+import { RouteService } from './services/route.service';
+import { ServerResponseService } from './services/server-response.service';
+import { NativeWindowFactory, NativeWindowService } from './services/window.service';
+import { BitstreamFormat } from './shared/bitstream-format.model';
+import { Bitstream } from './shared/bitstream.model';
+import { BrowseDefinition } from './shared/browse-definition.model';
+import { BrowseEntry } from './shared/browse-entry.model';
+import { Bundle } from './shared/bundle.model';
+import { Collection } from './shared/collection.model';
+import { Community } from './shared/community.model';
+import { DSpaceObject } from './shared/dspace-object.model';
+import { ExternalSourceEntry } from './shared/external-source-entry.model';
+import { ExternalSource } from './shared/external-source.model';
+import { FileService } from './shared/file.service';
+import { HALEndpointService } from './shared/hal-endpoint.service';
+import { ItemType } from './shared/item-relationships/item-type.model';
+import { RelationshipType } from './shared/item-relationships/relationship-type.model';
+import { Relationship } from './shared/item-relationships/relationship.model';
+import { Item } from './shared/item.model';
+import { License } from './shared/license.model';
+import { ResourcePolicy } from './shared/resource-policy.model';
+import { SearchConfigurationService } from './shared/search/search-configuration.service';
+import { SearchFilterService } from './shared/search/search-filter.service';
+import { SearchService } from './shared/search/search.service';
+import { Site } from './shared/site.model';
+import { UUIDService } from './shared/uuid.service';
+import { WorkflowItem } from './submission/models/workflowitem.model';
+import { WorkspaceItem } from './submission/models/workspaceitem.model';
+import { SubmissionJsonPatchOperationsService } from './submission/submission-json-patch-operations.service';
+import { SubmissionResponseParsingService } from './submission/submission-response-parsing.service';
+import { SubmissionRestService } from './submission/submission-rest.service';
+import { WorkflowItemDataService } from './submission/workflowitem-data.service';
+import { WorkspaceitemDataService } from './submission/workspaceitem-data.service';
 import { ClaimedTaskDataService } from './tasks/claimed-task-data.service';
+import { ClaimedTask } from './tasks/models/claimed-task-object.model';
+import { PoolTask } from './tasks/models/pool-task-object.model';
+import { TaskObject } from './tasks/models/task-object.model';
 import { PoolTaskDataService } from './tasks/pool-task-data.service';
 import { TaskResponseParsingService } from './tasks/task-response-parsing.service';
-import { BitstreamFormatDataService } from './data/bitstream-format-data.service';
-import { NormalizedClaimedTask } from './tasks/models/normalized-claimed-task-object.model';
-import { NormalizedTaskObject } from './tasks/models/normalized-task-object.model';
-import { NormalizedPoolTask } from './tasks/models/normalized-pool-task-object.model';
-import { NormalizedRelationship } from './cache/models/items/normalized-relationship.model';
-import { NormalizedRelationshipType } from './cache/models/items/normalized-relationship-type.model';
-import { NormalizedItemType } from './cache/models/items/normalized-item-type.model';
-import { MetadatafieldParsingService } from './data/metadatafield-parsing.service';
-import { NormalizedSubmissionUploadsModel } from './config/models/normalized-config-submission-uploads.model';
-import { NormalizedBrowseEntry } from './shared/normalized-browse-entry.model';
-import { BrowseDefinition } from './shared/browse-definition.model';
-import { BitstreamDataService } from './data/bitstream-data.service';
-import { ContentSourceResponseParsingService } from './data/content-source-response-parsing.service';
-import { MappedCollectionsReponseParsingService } from './data/mapped-collections-reponse-parsing.service';
-import { ObjectSelectService } from '../shared/object-select/object-select.service';
 import { ArrayMoveChangeAnalyzer } from './data/array-move-change-analyzer.service';
-import { EntityTypeService } from './data/entity-type.service';
-import { SiteDataService } from './data/site-data.service';
-import { NormalizedSite } from './cache/models/normalized-site.model';
-
-import {
-  MOCK_RESPONSE_MAP,
-  MockResponseMap,
-  mockResponseMap
-} from '../shared/mocks/dspace-rest-v2/mocks/mock-response-map';
-import { EndpointMockingRestService } from '../shared/mocks/dspace-rest-v2/endpoint-mocking-rest.service';
-import { ENV_CONFIG, GLOBAL_CONFIG, GlobalConfig } from '../../config';
-import { SearchFilterService } from './shared/search/search-filter.service';
-import { SearchConfigurationService } from './shared/search/search-configuration.service';
-import { SelectableListService } from '../shared/object-list/selectable-list/selectable-list.service';
-import { RelationshipTypeService } from './data/relationship-type.service';
-import { SidebarService } from '../shared/sidebar/sidebar.service';
-import { NormalizedExternalSource } from './cache/models/normalized-external-source.model';
-import { NormalizedExternalSourceEntry } from './cache/models/normalized-external-source-entry.model';
-import { ExternalSourceService } from './data/external-source.service';
-import { LookupRelationService } from './data/lookup-relation.service';
+import { BitstreamDataService } from './data/bitstream-data.service';
 
 /**
  * When not in production, endpoint responses can be mocked for testing purposes
@@ -185,7 +185,7 @@ const PROVIDERS = [
   SectionFormOperationsService,
   FormService,
   EpersonResponseParsingService,
-  GroupEpersonService,
+  EPersonDataService,
   HALEndpointService,
   HostWindowService,
   ItemDataService,
@@ -195,9 +195,7 @@ const PROVIDERS = [
   ResourcePolicyService,
   RegistryService,
   BitstreamFormatDataService,
-  NormalizedObjectBuildService,
   RemoteDataBuildService,
-  RequestService,
   EndpointMapResponseParsingService,
   FacetValueResponseParsingService,
   FacetValueMapResponseParsingService,
@@ -261,6 +259,8 @@ const PROVIDERS = [
   RelationshipTypeService,
   ExternalSourceService,
   LookupRelationService,
+  LicenseDataService,
+  ItemTypeDataService,
   // register AuthInterceptor as HttpInterceptor
   {
     provide: HTTP_INTERCEPTORS,
@@ -275,40 +275,40 @@ const PROVIDERS = [
 /**
  * Declaration needed to make sure all decorator functions are called in time
  */
-export const normalizedModels =
+export const models =
   [
-    NormalizedDSpaceObject,
-    NormalizedBundle,
-    NormalizedBitstream,
-    NormalizedBitstreamFormat,
-    NormalizedItem,
-    NormalizedSite,
-    NormalizedCollection,
-    NormalizedCommunity,
-    NormalizedEPerson,
-    NormalizedGroup,
-    NormalizedResourcePolicy,
-    NormalizedMetadataSchema,
-    NormalizedMetadataField,
-    NormalizedLicense,
-    NormalizedWorkflowItem,
-    NormalizedWorkspaceItem,
-    NormalizedSubmissionDefinitionsModel,
-    NormalizedSubmissionFormsModel,
-    NormalizedSubmissionSectionModel,
-    NormalizedSubmissionUploadsModel,
-    NormalizedAuthStatus,
-    NormalizedAuthorityValue,
-    NormalizedBrowseEntry,
+    DSpaceObject,
+    Bundle,
+    Bitstream,
+    BitstreamFormat,
+    Item,
+    Site,
+    Collection,
+    Community,
+    EPerson,
+    Group,
+    ResourcePolicy,
+    MetadataSchema,
+    MetadataField,
+    License,
+    WorkflowItem,
+    WorkspaceItem,
+    SubmissionDefinitionsModel,
+    SubmissionFormsModel,
+    SubmissionSectionModel,
+    SubmissionUploadsModel,
+    AuthStatus,
+    AuthorityValue,
+    BrowseEntry,
     BrowseDefinition,
-    NormalizedClaimedTask,
-    NormalizedTaskObject,
-    NormalizedPoolTask,
-    NormalizedRelationship,
-    NormalizedRelationshipType,
-    NormalizedItemType,
-    NormalizedExternalSource,
-    NormalizedExternalSourceEntry
+    ClaimedTask,
+    TaskObject,
+    PoolTask,
+    Relationship,
+    RelationshipType,
+    ItemType,
+    ExternalSource,
+    ExternalSourceEntry,
   ];
 
 @NgModule({
diff --git a/src/app/core/data/array-move-change-analyzer.service.ts b/src/app/core/data/array-move-change-analyzer.service.ts
index 91dd7809e0e8fa7b062ee6dae8ac777b4bd120f9..39d22fc46324e98223a4eacb5a4565d06ef2eea8 100644
--- a/src/app/core/data/array-move-change-analyzer.service.ts
+++ b/src/app/core/data/array-move-change-analyzer.service.ts
@@ -1,9 +1,5 @@
-import { MoveOperation, Operation } from 'fast-json-patch/lib/core';
-import { compare } from 'fast-json-patch';
-import { ChangeAnalyzer } from './change-analyzer';
+import { MoveOperation } from 'fast-json-patch/lib/core';
 import { Injectable } from '@angular/core';
-import { CacheableObject } from '../cache/object-cache.reducer';
-import { NormalizedObject } from '../cache/models/normalized-object.model';
 import { moveItemInArray } from '@angular/cdk/drag-drop';
 import { hasValue } from '../../shared/empty.util';
 
diff --git a/src/app/core/data/base-response-parsing.service.ts b/src/app/core/data/base-response-parsing.service.ts
index ea2d71faa78bd9f4c43317301641445ae361dddf..3615ab402302f20de3e2ad16c4ec573b60850a2e 100644
--- a/src/app/core/data/base-response-parsing.service.ts
+++ b/src/app/core/data/base-response-parsing.service.ts
@@ -1,21 +1,45 @@
 import { hasNoValue, hasValue, isNotEmpty } from '../../shared/empty.util';
-import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer';
+import { DSpaceSerializer } from '../dspace-rest-v2/dspace.serializer';
 import { CacheableObject } from '../cache/object-cache.reducer';
+import { Serializer } from '../serializer';
 import { PageInfo } from '../shared/page-info.model';
 import { ObjectCacheService } from '../cache/object-cache.service';
 import { GlobalConfig } from '../../../config/global-config.interface';
 import { GenericConstructor } from '../shared/generic-constructor';
 import { PaginatedList } from './paginated-list';
-import { isRestDataObject, isRestPaginatedList } from '../cache/builders/normalized-object-build.service';
-import { ResourceType } from '../shared/resource-type';
-import { getMapsToType } from '../cache/builders/build-decorators';
+import { getClassForType } from '../cache/builders/build-decorators';
 import { RestRequest } from './request.models';
 /* tslint:disable:max-classes-per-file */
 
+/**
+ * Return true if halObj has a value for `_links.self`
+ *
+ * @param {any} halObj The object to test
+ */
+export function isRestDataObject(halObj: any): boolean {
+  return isNotEmpty(halObj._links) && hasValue(halObj._links.self);
+}
+
+/**
+ * Return true if halObj has a value for `page` with properties
+ * `size`, `totalElements`, `totalPages`, `number`
+ *
+ * @param {any} halObj The object to test
+ */
+export function isRestPaginatedList(halObj: any): boolean {
+  return hasValue(halObj.page) &&
+          hasValue(halObj.page.size) &&
+          hasValue(halObj.page.totalElements) &&
+          hasValue(halObj.page.totalPages) &&
+          hasValue(halObj.page.number);
+}
+
 export abstract class BaseResponseParsingService {
   protected abstract EnvConfig: GlobalConfig;
   protected abstract objectCache: ObjectCacheService;
   protected abstract toCache: boolean;
+  protected shouldDirectlyAttachEmbeds = false;
+  protected serializerConstructor: GenericConstructor<Serializer<any>> = DSpaceSerializer;
 
   protected process<ObjectDomain>(data: any, request: RestRequest): any {
     if (isNotEmpty(data)) {
@@ -33,20 +57,20 @@ export abstract class BaseResponseParsingService {
             .filter((property) => data._embedded.hasOwnProperty(property))
             .forEach((property) => {
               const parsedObj = this.process<ObjectDomain>(data._embedded[property], request);
-              if (isNotEmpty(parsedObj)) {
-                if (isRestPaginatedList(data._embedded[property])) {
-                  object[property] = parsedObj;
-                  object[property].page = parsedObj.page.map((obj) => this.retrieveObjectOrUrl(obj));
-                } else if (isRestDataObject(data._embedded[property])) {
-                  object[property] = this.retrieveObjectOrUrl(parsedObj);
-                } else if (Array.isArray(parsedObj)) {
-                  object[property] = parsedObj.map((obj) => this.retrieveObjectOrUrl(obj))
-                }
+              if (this.shouldDirectlyAttachEmbeds && isNotEmpty(parsedObj)) {
+                  if (isRestPaginatedList(data._embedded[property])) {
+                    object[property] = parsedObj;
+                    object[property].page = parsedObj.page.map((obj) => this.retrieveObjectOrUrl(obj));
+                  } else if (isRestDataObject(data._embedded[property])) {
+                    object[property] = this.retrieveObjectOrUrl(parsedObj);
+                  } else if (Array.isArray(parsedObj)) {
+                    object[property] = parsedObj.map((obj) => this.retrieveObjectOrUrl(obj))
+                  }
               }
             });
         }
 
-        this.cache(object, request);
+        this.cache(object, request, data);
         return object;
       }
       const result = {};
@@ -87,33 +111,38 @@ export abstract class BaseResponseParsingService {
   protected deserialize<ObjectDomain>(obj): any {
     const type: string = obj.type;
     if (hasValue(type)) {
-      const normObjConstructor = getMapsToType(type) as GenericConstructor<ObjectDomain>;
+      const objConstructor = getClassForType(type) as GenericConstructor<ObjectDomain>;
 
-      if (hasValue(normObjConstructor)) {
-        const serializer = new DSpaceRESTv2Serializer(normObjConstructor);
+      if (hasValue(objConstructor)) {
+        const serializer = new this.serializerConstructor(objConstructor);
         return serializer.deserialize(obj);
       } else {
-        // TODO: move check to Validator?
-        // throw new Error(`The server returned an object with an unknown a known type: ${type}`);
         return null;
       }
 
     } else {
-      // TODO: move check to Validator
-      // throw new Error(`The server returned an object without a type: ${JSON.stringify(obj)}`);
       return null;
     }
   }
 
-  protected cache<ObjectDomain>(obj, request: RestRequest) {
+  protected cache<ObjectDomain>(obj, request: RestRequest, data: any) {
     if (this.toCache) {
-      this.addToObjectCache(obj, request);
+      this.addToObjectCache(obj, request, data);
     }
   }
 
-  protected addToObjectCache(co: CacheableObject, request: RestRequest): void {
-    if (hasNoValue(co) || hasNoValue(co.self)) {
-      throw new Error('The server returned an invalid object');
+  protected addToObjectCache(co: CacheableObject, request: RestRequest, data: any): void {
+    if (hasNoValue(co) || hasNoValue(co._links) || hasNoValue(co._links.self) || hasNoValue(co._links.self.href)) {
+      const type = hasValue(data) && hasValue(data.type) ? data.type : 'object';
+      let dataJSON: string;
+      if (hasValue(data._embedded)) {
+        dataJSON = JSON.stringify(Object.assign({}, data, {
+          _embedded: '...'
+        }));
+      } else {
+        dataJSON = JSON.stringify(data);
+      }
+      throw new Error(`Can't cache incomplete ${type}: ${JSON.stringify(co)}, parsed from (partial) response: ${dataJSON}`);
     }
     this.objectCache.add(co, hasValue(request.responseMsToLive) ? request.responseMsToLive : this.EnvConfig.cache.msToLive.default, request.uuid);
   }
@@ -121,7 +150,7 @@ export abstract class BaseResponseParsingService {
   processPageInfo(payload: any): PageInfo {
     if (hasValue(payload.page)) {
       const pageObj = Object.assign({}, payload.page, { _links: payload._links });
-      const pageInfoObject = new DSpaceRESTv2Serializer(PageInfo).deserialize(pageObj);
+      const pageInfoObject = new DSpaceSerializer(PageInfo).deserialize(pageObj);
       if (pageInfoObject.currentPage >= 0) {
         Object.assign(pageInfoObject, { currentPage: pageInfoObject.currentPage + 1 });
       }
@@ -140,7 +169,7 @@ export abstract class BaseResponseParsingService {
   }
 
   protected retrieveObjectOrUrl(obj: any): any {
-    return this.toCache ? obj.self : obj;
+    return this.toCache ? obj._links.self.href : obj;
   }
 
   protected isSuccessStatus(statusCode: number) {
diff --git a/src/app/core/data/bitstream-data.service.ts b/src/app/core/data/bitstream-data.service.ts
index 39d30c9e08553ebadd52655c6e835d0ba9ce51e8..ca402f6f957deb790d540da4299e8a0e0847631d 100644
--- a/src/app/core/data/bitstream-data.service.ts
+++ b/src/app/core/data/bitstream-data.service.ts
@@ -1,61 +1,177 @@
+import { HttpClient, HttpHeaders } from '@angular/common/http';
 import { Injectable } from '@angular/core';
-import { DataService } from './data.service';
-import { Bitstream } from '../shared/bitstream.model';
-import { RequestService } from './request.service';
-import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
-import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service';
 import { Store } from '@ngrx/store';
-import { CoreState } from '../core.reducers';
-import { BrowseService } from '../browse/browse.service';
+import { Observable } from 'rxjs/internal/Observable';
+import { map, switchMap } from 'rxjs/operators';
+import { hasValue, isNotEmpty } from '../../shared/empty.util';
+import { NotificationsService } from '../../shared/notifications/notifications.service';
+import { FollowLinkConfig } from '../../shared/utils/follow-link-config.model';
+import { dataService } from '../cache/builders/build-decorators';
+import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
 import { ObjectCacheService } from '../cache/object-cache.service';
+import { CoreState } from '../core.reducers';
+import { Bitstream } from '../shared/bitstream.model';
+import { BITSTREAM } from '../shared/bitstream.resource-type';
+import { Bundle } from '../shared/bundle.model';
 import { HALEndpointService } from '../shared/hal-endpoint.service';
-import { NotificationsService } from '../../shared/notifications/notifications.service';
-import { HttpClient, HttpHeaders } from '@angular/common/http';
+import { Item } from '../shared/item.model';
+import { BundleDataService } from './bundle-data.service';
+import { CommunityDataService } from './community-data.service';
+import { DataService } from './data.service';
 import { DSOChangeAnalyzer } from './dso-change-analyzer.service';
+import { PaginatedList } from './paginated-list';
+import { RemoteData } from './remote-data';
+import { RemoteDataError } from './remote-data-error';
 import { FindListOptions, PutRequest } from './request.models';
-import { Observable } from 'rxjs/internal/Observable';
-import { RestResponse } from '../cache/response.models';
+import { RequestService } from './request.service';
 import { BitstreamFormatDataService } from './bitstream-format-data.service';
-import { map, switchMap } from 'rxjs/operators';
-import { combineLatest as observableCombineLatest } from 'rxjs';
-import { HttpOptions } from '../dspace-rest-v2/dspace-rest-v2.service';
-import {
-  configureRequest,
-  getResponseFromEntry,
-} from '../shared/operators';
 import { BitstreamFormat } from '../shared/bitstream-format.model';
+import { RestResponse } from '../cache/response.models';
+import { HttpOptions } from '../dspace-rest-v2/dspace-rest-v2.service';
+import { configureRequest, getResponseFromEntry } from '../shared/operators';
+import { combineLatest as observableCombineLatest } from 'rxjs';
 
 /**
- * A service responsible for fetching/sending data from/to the REST API on the bitstreams endpoint
+ * A service to retrieve {@link Bitstream}s from the REST API
  */
-@Injectable()
+@Injectable({
+  providedIn: 'root'
+})
+@dataService(BITSTREAM)
 export class BitstreamDataService extends DataService<Bitstream> {
+
+  /**
+   * The HAL path to the bitstream endpoint
+   */
   protected linkPath = 'bitstreams';
-  protected forceBypassCache = false;
 
   constructor(
     protected requestService: RequestService,
     protected rdbService: RemoteDataBuildService,
-    protected dataBuildService: NormalizedObjectBuildService,
     protected store: Store<CoreState>,
-    protected bs: BrowseService,
+    protected cds: CommunityDataService,
     protected objectCache: ObjectCacheService,
     protected halService: HALEndpointService,
     protected notificationsService: NotificationsService,
     protected http: HttpClient,
     protected comparator: DSOChangeAnalyzer<Bitstream>,
-    protected bitstreamFormatService: BitstreamFormatDataService) {
+    protected bundleService: BundleDataService,
+    protected bitstreamFormatService: BitstreamFormatDataService
+  ) {
     super();
   }
 
   /**
-   * Get the endpoint for browsing bitstreams
-   * @param {FindListOptions} options
-   * @param linkPath
-   * @returns {Observable<string>}
+   * Retrieves the {@link Bitstream}s in a given bundle
+   *
+   * @param bundle the bundle to retrieve bitstreams from
+   * @param options options for the find all request
    */
-  getBrowseEndpoint(options: FindListOptions = {}, linkPath: string = this.linkPath): Observable<string> {
-    return this.halService.getEndpoint(linkPath);
+  findAllByBundle(bundle: Bundle, options?: FindListOptions, ...linksToFollow: Array<FollowLinkConfig<Bitstream>>): Observable<RemoteData<PaginatedList<Bitstream>>> {
+    return this.findAllByHref(bundle._links.bitstreams.href, options, ...linksToFollow);
+  }
+
+  /**
+   * Retrieves the thumbnail for the given item
+   * @returns {Observable<RemoteData<{@link Bitstream}>>} the first bitstream in the THUMBNAIL bundle
+   */
+  // TODO should be implemented rest side. {@link Item} should get a thumbnail link
+  public getThumbnailFor(item: Item): Observable<RemoteData<Bitstream>> {
+    return this.bundleService.findByItemAndName(item, 'THUMBNAIL').pipe(
+      switchMap((bundleRD: RemoteData<Bundle>) => {
+        if (isNotEmpty(bundleRD.payload)) {
+          return this.findAllByBundle(bundleRD.payload, { elementsPerPage: 1 }).pipe(
+            map((bitstreamRD: RemoteData<PaginatedList<Bitstream>>) => {
+              if (hasValue(bitstreamRD.payload) && hasValue(bitstreamRD.payload.page)) {
+                return new RemoteData(
+                  false,
+                  false,
+                  true,
+                  undefined,
+                  bitstreamRD.payload.page[0]
+                );
+              } else {
+                return bitstreamRD as any;
+              }
+            })
+          );
+        } else {
+          return [bundleRD as any];
+        }
+      })
+    );
+  }
+
+  /**
+   * Retrieve the matching thumbnail for a {@link Bitstream}.
+   *
+   * The {@link Item} is technically redundant, but is available
+   * in all current use cases, and having it simplifies this method
+   *
+   * @param item The {@link Item} the {@link Bitstream} and its thumbnail are a part of
+   * @param bitstreamInOriginal The original {@link Bitstream} to find the thumbnail for
+   */
+  // TODO should be implemented rest side
+  public getMatchingThumbnail(item: Item, bitstreamInOriginal: Bitstream): Observable<RemoteData<Bitstream>> {
+    return this.bundleService.findByItemAndName(item, 'THUMBNAIL').pipe(
+      switchMap((bundleRD: RemoteData<Bundle>) => {
+        if (isNotEmpty(bundleRD.payload)) {
+          return this.findAllByBundle(bundleRD.payload, { elementsPerPage: Number.MAX_SAFE_INTEGER }).pipe(
+            map((bitstreamRD: RemoteData<PaginatedList<Bitstream>>) => {
+              if (hasValue(bitstreamRD.payload) && hasValue(bitstreamRD.payload.page)) {
+                const matchingThumbnail = bitstreamRD.payload.page.find((thumbnail: Bitstream) =>
+                  thumbnail.name.startsWith(bitstreamInOriginal.name)
+                );
+                if (hasValue(matchingThumbnail)) {
+                  return new RemoteData(
+                    false,
+                    false,
+                    true,
+                    undefined,
+                    matchingThumbnail
+                  );
+                } else {
+                  return new RemoteData(
+                    false,
+                    false,
+                    false,
+                    new RemoteDataError(404, '404', 'No matching thumbnail found'),
+                    undefined
+                  );
+                }
+              } else {
+                return bitstreamRD as any;
+              }
+            })
+          );
+        } else {
+          return [bundleRD as any];
+        }
+      })
+    );
+  }
+
+  /**
+   * Retrieve all {@link Bitstream}s in a certain {@link Bundle}.
+   *
+   * The {@link Item} is technically redundant, but is available
+   * in all current use cases, and having it simplifies this method
+   *
+   * @param item the {@link Item} the {@link Bundle} is a part of
+   * @param bundleName the name of the {@link Bundle} we want to find {@link Bitstream}s for
+   * @param options the {@link FindListOptions} for the request
+   * @param linksToFollow the {@link FollowLinkConfig}s for the request
+   */
+  public findAllByItemAndBundleName(item: Item, bundleName: string, options?: FindListOptions, ...linksToFollow: Array<FollowLinkConfig<Bitstream>>): Observable<RemoteData<PaginatedList<Bitstream>>> {
+    return this.bundleService.findByItemAndName(item, bundleName).pipe(
+      switchMap((bundleRD: RemoteData<Bundle>) => {
+        if (hasValue(bundleRD.payload)) {
+          return this.findAllByBundle(bundleRD.payload, options, ...linksToFollow);
+        } else {
+          return [bundleRD as any];
+        }
+      })
+    );
   }
 
   /**
@@ -87,4 +203,5 @@ export class BitstreamDataService extends DataService<Bitstream> {
       getResponseFromEntry()
     );
   }
+
 }
diff --git a/src/app/core/data/bitstream-format-data.service.spec.ts b/src/app/core/data/bitstream-format-data.service.spec.ts
index c626fcd6e2d417f80d38d502a6c88fdb95f8ae7a..795441601065a0a93d1aa0c263f9f823f3b24a06 100644
--- a/src/app/core/data/bitstream-format-data.service.spec.ts
+++ b/src/app/core/data/bitstream-format-data.service.spec.ts
@@ -8,7 +8,6 @@ import { cold, getTestScheduler, hot } from 'jasmine-marbles';
 import { HALEndpointService } from '../shared/hal-endpoint.service';
 import { NotificationsService } from '../../shared/notifications/notifications.service';
 import { HttpClient } from '@angular/common/http';
-import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service';
 import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
 import { BitstreamFormat } from '../shared/bitstream-format.model';
 import { async } from '@angular/core/testing';
@@ -48,14 +47,12 @@ describe('BitstreamFormatDataService', () => {
   const notificationsService = {} as NotificationsService;
   const http = {} as HttpClient;
   const comparator = {} as any;
-  const dataBuildService = {} as NormalizedObjectBuildService;
   const rdbService = {} as RemoteDataBuildService;
 
   function initTestService(halService) {
     return new BitstreamFormatDataService(
       requestService,
       rdbService,
-      dataBuildService,
       store,
       objectCache,
       halService,
@@ -285,7 +282,7 @@ describe('BitstreamFormatDataService', () => {
       format.id = 'format-id';
 
       const expected = cold('(b|)', {b: true});
-      const result = service.delete(format);
+      const result = service.delete(format.id);
 
       expect(result).toBeObservable(expected);
     });
diff --git a/src/app/core/data/bitstream-format-data.service.ts b/src/app/core/data/bitstream-format-data.service.ts
index c30330a0a30fee9cbe910f64caaa21934d2aaf24..e8cf030a528081746d015ebb07db9c4714b3e203 100644
--- a/src/app/core/data/bitstream-format-data.service.ts
+++ b/src/app/core/data/bitstream-format-data.service.ts
@@ -1,31 +1,34 @@
+import { HttpClient } from '@angular/common/http';
 import { Injectable } from '@angular/core';
-import { DataService } from './data.service';
-import { BitstreamFormat } from '../shared/bitstream-format.model';
-import { RequestService } from './request.service';
-import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
-import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service';
 import { createSelector, select, Store } from '@ngrx/store';
-import { ObjectCacheService } from '../cache/object-cache.service';
-import { HALEndpointService } from '../shared/hal-endpoint.service';
-import { NotificationsService } from '../../shared/notifications/notifications.service';
-import { HttpClient } from '@angular/common/http';
-import { DefaultChangeAnalyzer } from './default-change-analyzer.service';
-import { DeleteByIDRequest, FindListOptions, PostRequest, PutRequest } from './request.models';
 import { Observable } from 'rxjs';
-import { find, map, tap } from 'rxjs/operators';
-import { configureRequest, getResponseFromEntry } from '../shared/operators';
 import { distinctUntilChanged } from 'rxjs/internal/operators/distinctUntilChanged';
-import { RestResponse } from '../cache/response.models';
-import { BitstreamFormatRegistryState } from '../../+admin/admin-registries/bitstream-formats/bitstream-format.reducers';
+import { find, map, tap } from 'rxjs/operators';
 import {
   BitstreamFormatsRegistryDeselectAction,
   BitstreamFormatsRegistryDeselectAllAction,
   BitstreamFormatsRegistrySelectAction
 } from '../../+admin/admin-registries/bitstream-formats/bitstream-format.actions';
+import { BitstreamFormatRegistryState } from '../../+admin/admin-registries/bitstream-formats/bitstream-format.reducers';
 import { hasValue } from '../../shared/empty.util';
-import { RequestEntry } from './request.reducer';
+import { NotificationsService } from '../../shared/notifications/notifications.service';
+import { dataService } from '../cache/builders/build-decorators';
+import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
+import { ObjectCacheService } from '../cache/object-cache.service';
+import { RestResponse } from '../cache/response.models';
 import { CoreState } from '../core.reducers';
 import { coreSelector } from '../core.selectors';
+import { BitstreamFormat } from '../shared/bitstream-format.model';
+import { BITSTREAM_FORMAT } from '../shared/bitstream-format.resource-type';
+import { Bitstream } from '../shared/bitstream.model';
+import { HALEndpointService } from '../shared/hal-endpoint.service';
+import { configureRequest, getResponseFromEntry } from '../shared/operators';
+import { DataService } from './data.service';
+import { DefaultChangeAnalyzer } from './default-change-analyzer.service';
+import { RemoteData } from './remote-data';
+import { DeleteByIDRequest, PostRequest, PutRequest } from './request.models';
+import { RequestEntry } from './request.reducer';
+import { RequestService } from './request.service';
 
 const bitstreamFormatsStateSelector = createSelector(
   coreSelector,
@@ -38,6 +41,7 @@ const selectedBitstreamFormatSelector = createSelector(bitstreamFormatsStateSele
  * A service responsible for fetching/sending data from/to the REST API on the bitstreamformats endpoint
  */
 @Injectable()
+@dataService(BITSTREAM_FORMAT)
 export class BitstreamFormatDataService extends DataService<BitstreamFormat> {
 
   protected linkPath = 'bitstreamformats';
@@ -45,7 +49,6 @@ export class BitstreamFormatDataService extends DataService<BitstreamFormat> {
   constructor(
     protected requestService: RequestService,
     protected rdbService: RemoteDataBuildService,
-    protected dataBuildService: NormalizedObjectBuildService,
     protected store: Store<CoreState>,
     protected objectCache: ObjectCacheService,
     protected halService: HALEndpointService,
@@ -55,16 +58,6 @@ export class BitstreamFormatDataService extends DataService<BitstreamFormat> {
     super();
   }
 
-  /**
-   * Get the endpoint for browsing bitstream formats
-   * @param {FindListOptions} options
-   * @param {string} linkPath
-   * @returns {Observable<string>}
-   */
-  getBrowseEndpoint(options: FindListOptions = {}, linkPath?: string): Observable<string> {
-    return this.halService.getEndpoint(this.linkPath);
-  }
-
   /**
    * Get the endpoint to update an existing bitstream format
    * @param formatId
@@ -161,19 +154,19 @@ export class BitstreamFormatDataService extends DataService<BitstreamFormat> {
 
   /**
    * Delete an existing DSpace Object on the server
-   * @param format The DSpace Object to be removed
+   * @param formatID The DSpace Object'id to be removed
    * Return an observable that emits true when the deletion was successful, false when it failed
    */
-  delete(format: BitstreamFormat): Observable<boolean> {
+  delete(formatID: string): Observable<boolean> {
     const requestId = this.requestService.generateRequestId();
 
     const hrefObs = this.halService.getEndpoint(this.linkPath).pipe(
-      map((endpoint: string) => this.getIDHref(endpoint, format.id)));
+      map((endpoint: string) => this.getIDHref(endpoint, formatID)));
 
     hrefObs.pipe(
       find((href: string) => hasValue(href)),
       map((href: string) => {
-        const request = new DeleteByIDRequest(requestId, href, format.id);
+        const request = new DeleteByIDRequest(requestId, href, formatID);
         this.requestService.configure(request);
       })
     ).subscribe();
@@ -183,4 +176,8 @@ export class BitstreamFormatDataService extends DataService<BitstreamFormat> {
       map((request: RequestEntry) => request.response.isSuccessful)
     );
   }
+
+  findByBitstream(bitstream: Bitstream): Observable<RemoteData<BitstreamFormat>> {
+    return this.findByHref(bitstream._links.format.href);
+  }
 }
diff --git a/src/app/core/data/browse-entries-response-parsing.service.ts b/src/app/core/data/browse-entries-response-parsing.service.ts
index a2f5f213123fdecca3a5557c32284ebc51597974..ec35b8cc756583110c816ec9945d0de4bfb22572 100644
--- a/src/app/core/data/browse-entries-response-parsing.service.ts
+++ b/src/app/core/data/browse-entries-response-parsing.service.ts
@@ -5,11 +5,11 @@ import { isNotEmpty } from '../../shared/empty.util';
 import { ObjectCacheService } from '../cache/object-cache.service';
 import { ErrorResponse, GenericSuccessResponse, RestResponse } from '../cache/response.models';
 import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
-import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer';
+import { DSpaceSerializer } from '../dspace-rest-v2/dspace.serializer';
+import { BrowseEntry } from '../shared/browse-entry.model';
 import { BaseResponseParsingService } from './base-response-parsing.service';
 import { ResponseParsingService } from './parsing.service';
 import { RestRequest } from './request.models';
-import { NormalizedBrowseEntry } from '../shared/normalized-browse-entry.model';
 
 @Injectable()
 export class BrowseEntriesResponseParsingService extends BaseResponseParsingService implements ResponseParsingService {
@@ -26,7 +26,7 @@ export class BrowseEntriesResponseParsingService extends BaseResponseParsingServ
     if (isNotEmpty(data.payload)) {
       let browseEntries = [];
       if (isNotEmpty(data.payload._embedded) && Array.isArray(data.payload._embedded[Object.keys(data.payload._embedded)[0]])) {
-        const serializer = new DSpaceRESTv2Serializer(NormalizedBrowseEntry);
+        const serializer = new DSpaceSerializer(BrowseEntry);
         browseEntries = serializer.deserializeArray(data.payload._embedded[Object.keys(data.payload._embedded)[0]]);
       }
       return new GenericSuccessResponse(browseEntries, data.statusCode, data.statusText, this.processPageInfo(data.payload));
diff --git a/src/app/core/data/browse-items-response-parsing-service.ts b/src/app/core/data/browse-items-response-parsing-service.ts
index 324b36199abad6a765be423921d75fdcfb13cd44..08ade5772dfa1527b8c33cc63b0b7bc416c390d6 100644
--- a/src/app/core/data/browse-items-response-parsing-service.ts
+++ b/src/app/core/data/browse-items-response-parsing-service.ts
@@ -6,12 +6,11 @@ import { hasValue, isNotEmpty } from '../../shared/empty.util';
 import { ObjectCacheService } from '../cache/object-cache.service';
 import { ErrorResponse, GenericSuccessResponse, RestResponse } from '../cache/response.models';
 import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
-import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer';
+import { DSpaceSerializer } from '../dspace-rest-v2/dspace.serializer';
+import { DSpaceObject } from '../shared/dspace-object.model';
 import { BaseResponseParsingService } from './base-response-parsing.service';
 import { ResponseParsingService } from './parsing.service';
 import { RestRequest } from './request.models';
-import { DSpaceObject } from '../shared/dspace-object.model';
-import { NormalizedDSpaceObject } from '../cache/models/normalized-dspace-object.model';
 
 /**
  * A ResponseParsingService used to parse DSpaceRESTV2Response coming from the REST API to Browse Items (DSpaceObject[])
@@ -35,7 +34,7 @@ export class BrowseItemsResponseParsingService extends BaseResponseParsingServic
   parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse {
     if (isNotEmpty(data.payload) && isNotEmpty(data.payload._embedded)
       && Array.isArray(data.payload._embedded[Object.keys(data.payload._embedded)[0]])) {
-      const serializer = new DSpaceRESTv2Serializer(NormalizedDSpaceObject);
+      const serializer = new DSpaceSerializer(DSpaceObject);
       const items = serializer.deserializeArray(data.payload._embedded[Object.keys(data.payload._embedded)[0]]);
       return new GenericSuccessResponse(items, data.statusCode, data.statusText, this.processPageInfo(data.payload));
     } else if (hasValue(data.payload) && hasValue(data.payload.page)) {
diff --git a/src/app/core/data/browse-response-parsing.service.spec.ts b/src/app/core/data/browse-response-parsing.service.spec.ts
index 8d0fe7cd41353f590f0828f98d75239092abc425..fedfea130903f523b2b66c4c8e5297361582bc89 100644
--- a/src/app/core/data/browse-response-parsing.service.spec.ts
+++ b/src/app/core/data/browse-response-parsing.service.spec.ts
@@ -1,8 +1,8 @@
+import { ErrorResponse, GenericSuccessResponse } from '../cache/response.models';
+import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
+import { BrowseDefinition } from '../shared/browse-definition.model';
 import { BrowseResponseParsingService } from './browse-response-parsing.service';
 import { BrowseEndpointRequest } from './request.models';
-import { GenericSuccessResponse, ErrorResponse } from '../cache/response.models';
-import { BrowseDefinition } from '../shared/browse-definition.model';
-import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
 
 describe('BrowseResponseParsingService', () => {
   let service: BrowseResponseParsingService;
@@ -31,7 +31,6 @@ describe('BrowseResponseParsingService', () => {
                 metadata: 'dc.date.issued'
               }, { name: 'dateaccessioned', metadata: 'dc.date.accessioned' }],
               order: 'ASC',
-              type: 'browse',
               metadata: ['dc.date.issued'],
               _links: {
                 self: { href: 'https://rest.api/discover/browses/dateissued' },
@@ -44,7 +43,6 @@ describe('BrowseResponseParsingService', () => {
                 metadata: 'dc.date.issued'
               }, { name: 'dateaccessioned', metadata: 'dc.date.accessioned' }],
               order: 'ASC',
-              type: 'browse',
               metadata: ['dc.contributor.*', 'dc.creator'],
               _links: {
                 self: { href: 'https://rest.api/discover/browses/author' },
@@ -68,7 +66,6 @@ describe('BrowseResponseParsingService', () => {
                 metadata: 'dc.date.issued'
               }, { name: 'dateaccessioned', metadata: 'dc.date.accessioned' }],
               order: 'ASC',
-              type: 'browse',
               metadata: ['dc.date.issued'],
               _links: {
                 self: { href: 'https://rest.api/discover/browses/dateissued' },
@@ -117,8 +114,8 @@ describe('BrowseResponseParsingService', () => {
             'dc.date.issued'
           ],
           _links: {
-            self: 'https://rest.api/discover/browses/dateissued',
-            items: 'https://rest.api/discover/browses/dateissued/items'
+            self: { href: 'https://rest.api/discover/browses/dateissued' },
+            items: { href: 'https://rest.api/discover/browses/dateissued/items' }
           }
         }),
         Object.assign(new BrowseDefinition(), {
@@ -143,9 +140,9 @@ describe('BrowseResponseParsingService', () => {
             'dc.creator'
           ],
           _links: {
-            self: 'https://rest.api/discover/browses/author',
-            entries: 'https://rest.api/discover/browses/author/entries',
-            items: 'https://rest.api/discover/browses/author/items'
+            self: { href: 'https://rest.api/discover/browses/author' },
+            entries: { href: 'https://rest.api/discover/browses/author/entries' },
+            items: { href: 'https://rest.api/discover/browses/author/items' }
           }
         })
       ];
diff --git a/src/app/core/data/browse-response-parsing.service.ts b/src/app/core/data/browse-response-parsing.service.ts
index 3c67b2b3eb2a1ec0d69c9d8221e1099cf13c897b..d1b9c2f15c66b3a172fae51d1aca1a169552ca06 100644
--- a/src/app/core/data/browse-response-parsing.service.ts
+++ b/src/app/core/data/browse-response-parsing.service.ts
@@ -1,11 +1,11 @@
 import { Injectable } from '@angular/core';
-import { ResponseParsingService } from './parsing.service';
-import { RestRequest } from './request.models';
-import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
-import { GenericSuccessResponse, ErrorResponse, RestResponse } from '../cache/response.models';
 import { isNotEmpty } from '../../shared/empty.util';
-import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer';
+import { ErrorResponse, GenericSuccessResponse, RestResponse } from '../cache/response.models';
+import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
+import { DSpaceSerializer } from '../dspace-rest-v2/dspace.serializer';
 import { BrowseDefinition } from '../shared/browse-definition.model';
+import { ResponseParsingService } from './parsing.service';
+import { RestRequest } from './request.models';
 
 @Injectable()
 export class BrowseResponseParsingService implements ResponseParsingService {
@@ -13,7 +13,7 @@ export class BrowseResponseParsingService implements ResponseParsingService {
   parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse {
     if (isNotEmpty(data.payload) && isNotEmpty(data.payload._embedded)
       && Array.isArray(data.payload._embedded[Object.keys(data.payload._embedded)[0]])) {
-      const serializer = new DSpaceRESTv2Serializer(BrowseDefinition);
+      const serializer = new DSpaceSerializer(BrowseDefinition);
       const browseDefinitions = serializer.deserializeArray(data.payload._embedded[Object.keys(data.payload._embedded)[0]]);
       return new GenericSuccessResponse(browseDefinitions, data.statusCode, data.statusText);
     } else {
diff --git a/src/app/core/data/bundle-data.service.ts b/src/app/core/data/bundle-data.service.ts
index cafcab04d229cb7bda37281be01c8eddb9fc0f8d..498c3d48ff4de37bfdc0e3f11689de0bedad60d3 100644
--- a/src/app/core/data/bundle-data.service.ts
+++ b/src/app/core/data/bundle-data.service.ts
@@ -1,37 +1,42 @@
+import { HttpClient } from '@angular/common/http';
 import { Injectable } from '@angular/core';
-import { DataService } from './data.service';
-import { Bundle } from '../shared/bundle.model';
-import { RequestService } from './request.service';
-import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
-import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service';
 import { Store } from '@ngrx/store';
-import { CoreState } from '../core.reducers';
+import { Observable } from 'rxjs/internal/Observable';
+import { map, switchMap, take } from 'rxjs/operators';
+import { hasValue } from '../../shared/empty.util';
+import { NotificationsService } from '../../shared/notifications/notifications.service';
+import { FollowLinkConfig } from '../../shared/utils/follow-link-config.model';
+import { dataService } from '../cache/builders/build-decorators';
+import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
 import { ObjectCacheService } from '../cache/object-cache.service';
+import { CoreState } from '../core.reducers';
+import { Bundle } from '../shared/bundle.model';
+import { BUNDLE } from '../shared/bundle.resource-type';
 import { HALEndpointService } from '../shared/hal-endpoint.service';
-import { NotificationsService } from '../../shared/notifications/notifications.service';
-import { HttpClient } from '@angular/common/http';
+import { Item } from '../shared/item.model';
+import { DataService } from './data.service';
 import { DefaultChangeAnalyzer } from './default-change-analyzer.service';
-import { FindListOptions, GetRequest } from './request.models';
-import { Observable } from 'rxjs/internal/Observable';
-import { map, switchMap, take } from 'rxjs/operators';
-import { RemoteData } from './remote-data';
 import { PaginatedList } from './paginated-list';
-import { Bitstream } from '../shared/bitstream.model';
+import { RemoteData } from './remote-data';
+import { FindListOptions, GetRequest } from './request.models';
+import { RequestService } from './request.service';
 import { PaginatedSearchOptions } from '../../shared/search/paginated-search-options.model';
+import { Bitstream } from '../shared/bitstream.model';
 
 /**
- * A service responsible for fetching/sending data from/to the REST API on the bundles endpoint
+ * A service to retrieve {@link Bundle}s from the REST API
  */
-@Injectable()
+@Injectable(
+  {providedIn: 'root'}
+)
+@dataService(BUNDLE)
 export class BundleDataService extends DataService<Bundle> {
   protected linkPath = 'bundles';
   protected bitstreamsEndpoint = 'bitstreams';
-  protected forceBypassCache = false;
 
   constructor(
     protected requestService: RequestService,
     protected rdbService: RemoteDataBuildService,
-    protected dataBuildService: NormalizedObjectBuildService,
     protected store: Store<CoreState>,
     protected objectCache: ObjectCacheService,
     protected halService: HALEndpointService,
@@ -42,12 +47,42 @@ export class BundleDataService extends DataService<Bundle> {
   }
 
   /**
-   * Get the endpoint for browsing bundles
-   * @param {FindListOptions} options
-   * @returns {Observable<string>}
+   * Retrieve all {@link Bundle}s in the given {@link Item}
+   *
+   * @param item the {@link Item} the {@link Bundle}s are a part of
+   * @param options the {@link FindListOptions} for the request
+   * @param linksToFollow the {@link FollowLinkConfig}s for the request
    */
-  getBrowseEndpoint(options: FindListOptions = {}, linkPath?: string): Observable<string> {
-    return this.halService.getEndpoint(this.linkPath);
+  findAllByItem(item: Item, options?: FindListOptions, ...linksToFollow: Array<FollowLinkConfig<Bundle>>): Observable<RemoteData<PaginatedList<Bundle>>> {
+    return this.findAllByHref(item._links.bundles.href, options,  ...linksToFollow);
+  }
+
+  /**
+   * Retrieve a {@link Bundle} in the given {@link Item} by name
+   *
+   * @param item the {@link Item} the {@link Bundle}s are a part of
+   * @param bundleName the name of the {@link Bundle} to retrieve
+   * @param linksToFollow the {@link FollowLinkConfig}s for the request
+   */
+  // TODO should be implemented rest side
+  findByItemAndName(item: Item, bundleName: string, ...linksToFollow: Array<FollowLinkConfig<Bundle>>): Observable<RemoteData<Bundle>> {
+    return this.findAllByItem(item, { elementsPerPage: Number.MAX_SAFE_INTEGER }, ...linksToFollow).pipe(
+      map((rd: RemoteData<PaginatedList<Bundle>>) => {
+        if (hasValue(rd.payload) && hasValue(rd.payload.page)) {
+          const matchingBundle = rd.payload.page.find((bundle: Bundle) =>
+            bundle.name === bundleName);
+          return new RemoteData(
+            false,
+            false,
+            true,
+            undefined,
+            matchingBundle
+          );
+        } else {
+          return rd as any;
+        }
+      }),
+    );
   }
 
   /**
diff --git a/src/app/core/data/change-analyzer.ts b/src/app/core/data/change-analyzer.ts
index c45c9e55b77b3a548960ba997467b42f6f9271a1..395af4a68c58bfba980a2828390eae8a87067d09 100644
--- a/src/app/core/data/change-analyzer.ts
+++ b/src/app/core/data/change-analyzer.ts
@@ -1,4 +1,3 @@
-import { NormalizedObject } from '../cache/models/normalized-object.model';
 import { Operation } from 'fast-json-patch/lib/core';
 import { CacheableObject } from '../cache/object-cache.reducer';
 
@@ -12,10 +11,10 @@ export interface ChangeAnalyzer<T extends CacheableObject> {
    * Compare two objects and return their differences as a
    * JsonPatch Operation Array
    *
-   * @param {NormalizedObject} object1
+   * @param {CacheableObject} object1
    *    The first object to compare
-   * @param {NormalizedObject} object2
+   * @param {CacheableObject} object2
    *    The second object to compare
    */
-  diff(object1: T | NormalizedObject<T>, object2: T | NormalizedObject<T>): Operation[];
+  diff(object1: T, object2: T): Operation[];
 }
diff --git a/src/app/core/data/collection-data.service.spec.ts b/src/app/core/data/collection-data.service.spec.ts
index c8f056bf19111611413248c3ef4241c54447d05a..96141d6a8ac46bd5212ad1f462bf6e82b3a2fa9f 100644
--- a/src/app/core/data/collection-data.service.spec.ts
+++ b/src/app/core/data/collection-data.service.spec.ts
@@ -126,7 +126,7 @@ describe('CollectionDataService', () => {
     notificationsService = new NotificationsServiceStub();
     translate = getMockTranslateService();
 
-    service = new CollectionDataService(requestService, rdbService, null, null, null, objectCache, halService, notificationsService, null, null, translate);
+    service = new CollectionDataService(requestService, rdbService, null, null, objectCache, halService, notificationsService, null, null, translate);
   }
 
 });
diff --git a/src/app/core/data/collection-data.service.ts b/src/app/core/data/collection-data.service.ts
index ed05c99e279c203c273074a3a35915fcb860eaba..6ae40f4ca9bc206fc52ea25bbb26b40d0f55c62a 100644
--- a/src/app/core/data/collection-data.service.ts
+++ b/src/app/core/data/collection-data.service.ts
@@ -1,52 +1,54 @@
+import { HttpClient, HttpHeaders } from '@angular/common/http';
 import { Injectable } from '@angular/core';
-
-import { distinctUntilChanged, filter, map, switchMap, take } from 'rxjs/operators';
 import { Store } from '@ngrx/store';
-
+import { TranslateService } from '@ngx-translate/core';
+import { Observable } from 'rxjs/internal/Observable';
+import { distinctUntilChanged, filter, map, switchMap, take } from 'rxjs/operators';
+import { hasValue, isNotEmpty, isNotEmptyOperator } from '../../shared/empty.util';
+import { NotificationOptions } from '../../shared/notifications/models/notification-options.model';
+import { INotification } from '../../shared/notifications/models/notification.model';
+import { NotificationsService } from '../../shared/notifications/notifications.service';
+import { PaginatedSearchOptions } from '../../shared/search/paginated-search-options.model';
+import { FollowLinkConfig } from '../../shared/utils/follow-link-config.model';
+import { dataService } from '../cache/builders/build-decorators';
 import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
+import { SearchParam } from '../cache/models/search-param.model';
 import { ObjectCacheService } from '../cache/object-cache.service';
+import { ContentSourceSuccessResponse, RestResponse } from '../cache/response.models';
 import { CoreState } from '../core.reducers';
+import { HttpOptions } from '../dspace-rest-v2/dspace-rest-v2.service';
+import { DSpaceSerializer } from '../dspace-rest-v2/dspace.serializer';
 import { Collection } from '../shared/collection.model';
-import { ComColDataService } from './comcol-data.service';
-import { CommunityDataService } from './community-data.service';
-import { RequestService } from './request.service';
-import { HALEndpointService } from '../shared/hal-endpoint.service';
-import { NotificationsService } from '../../shared/notifications/notifications.service';
-import { HttpClient, HttpHeaders } from '@angular/common/http';
-import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service';
-import { DSOChangeAnalyzer } from './dso-change-analyzer.service';
-import { Observable } from 'rxjs/internal/Observable';
-import {
-  ContentSourceRequest,
-  RestRequest,
-  UpdateContentSourceRequest,
-  GetRequest,
-  FindListOptions
-} from './request.models';
-import { RemoteData } from './remote-data';
-import { PaginatedList } from './paginated-list';
+import { COLLECTION } from '../shared/collection.resource-type';
 import { ContentSource } from '../shared/content-source.model';
+import { DSpaceObject } from '../shared/dspace-object.model';
+import { GenericConstructor } from '../shared/generic-constructor';
+import { HALEndpointService } from '../shared/hal-endpoint.service';
+import { Item } from '../shared/item.model';
 import {
   configureRequest,
   filterSuccessfulResponses,
   getRequestFromRequestHref,
   getResponseFromEntry
 } from '../shared/operators';
-import { ContentSourceSuccessResponse, RestResponse } from '../cache/response.models';
-import { HttpOptions } from '../dspace-rest-v2/dspace-rest-v2.service';
-import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer';
-import { hasValue, isNotEmpty, isNotEmptyOperator } from '../../shared/empty.util';
-import { NotificationOptions } from '../../shared/notifications/models/notification-options.model';
-import { TranslateService } from '@ngx-translate/core';
-import { SearchParam } from '../cache/models/search-param.model';
+import { ComColDataService } from './comcol-data.service';
+import { CommunityDataService } from './community-data.service';
+import { DSOChangeAnalyzer } from './dso-change-analyzer.service';
 import { DSOResponseParsingService } from './dso-response-parsing.service';
+import { PaginatedList } from './paginated-list';
 import { ResponseParsingService } from './parsing.service';
-import { GenericConstructor } from '../shared/generic-constructor';
-import { DSpaceObject } from '../shared/dspace-object.model';
-import { INotification } from '../../shared/notifications/models/notification.model';
-import { PaginatedSearchOptions } from '../../shared/search/paginated-search-options.model';
+import { RemoteData } from './remote-data';
+import {
+  ContentSourceRequest,
+  FindListOptions,
+  GetRequest,
+  RestRequest,
+  UpdateContentSourceRequest
+} from './request.models';
+import { RequestService } from './request.service';
 
 @Injectable()
+@dataService(COLLECTION)
 export class CollectionDataService extends ComColDataService<Collection> {
   protected linkPath = 'collections';
   protected errorTitle = 'collection.source.update.notifications.error.title';
@@ -55,7 +57,6 @@ export class CollectionDataService extends ComColDataService<Collection> {
   constructor(
     protected requestService: RequestService,
     protected rdbService: RemoteDataBuildService,
-    protected dataBuildService: NormalizedObjectBuildService,
     protected store: Store<CoreState>,
     protected cds: CommunityDataService,
     protected objectCache: ObjectCacheService,
@@ -150,7 +151,7 @@ export class CollectionDataService extends ComColDataService<Collection> {
    */
   updateContentSource(collectionId: string, contentSource: ContentSource): Observable<ContentSource | INotification> {
     const requestId = this.requestService.generateRequestId();
-    const serializedContentSource = new DSpaceRESTv2Serializer(ContentSource).serialize(contentSource);
+    const serializedContentSource = new DSpaceSerializer(ContentSource).serialize(contentSource);
     const request$ = this.getHarvesterEndpoint(collectionId).pipe(
       take(1),
       map((href: string) => {
@@ -208,8 +209,9 @@ export class CollectionDataService extends ComColDataService<Collection> {
    * Fetches a list of items that are mapped to a collection
    * @param collectionId    The id of the collection
    * @param searchOptions   Search options to sort or filter out items
+   * @param linksToFollow   List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved
    */
-  getMappedItems(collectionId: string, searchOptions?: PaginatedSearchOptions): Observable<RemoteData<PaginatedList<DSpaceObject>>> {
+  getMappedItems(collectionId: string, searchOptions?: PaginatedSearchOptions, ...linksToFollow: Array<FollowLinkConfig<Item>>): Observable<RemoteData<PaginatedList<DSpaceObject>>> {
     const requestUuid = this.requestService.generateRequestId();
 
     const href$ = this.getMappedItemsEndpoint(collectionId).pipe(
@@ -231,7 +233,7 @@ export class CollectionDataService extends ComColDataService<Collection> {
       configureRequest(this.requestService)
     ).subscribe();
 
-    return this.rdbService.buildList(href$);
+    return this.rdbService.buildList(href$, ...linksToFollow);
   }
 
   protected getFindByParentHref(parentUUID: string): Observable<string> {
@@ -240,4 +242,13 @@ export class CollectionDataService extends ComColDataService<Collection> {
         this.halService.getEndpoint('collections', `${communityEndpointHref}/${parentUUID}`)),
     );
   }
+
+  /**
+   * Returns {@link RemoteData} of {@link Collection} that is the owing collection of the given item
+   * @param item  Item we want the owning collection of
+   */
+  findOwningCollectionFor(item: Item): Observable<RemoteData<Collection>> {
+    return this.findByHref(item._links.owningCollection.href);
+  }
+
 }
diff --git a/src/app/core/data/comcol-data.service.spec.ts b/src/app/core/data/comcol-data.service.spec.ts
index a7fcd205d4ace43ddbbbb61f80e21dc4f6addd48..fc487527b976a8c295a79645a5e01395a66f468a 100644
--- a/src/app/core/data/comcol-data.service.spec.ts
+++ b/src/app/core/data/comcol-data.service.spec.ts
@@ -1,38 +1,31 @@
+import { HttpClient } from '@angular/common/http';
 import { Store } from '@ngrx/store';
 import { cold, getTestScheduler, hot } from 'jasmine-marbles';
+import { Observable, of as observableOf } from 'rxjs';
 import { TestScheduler } from 'rxjs/testing';
 import { GlobalConfig } from '../../../config';
 import { getMockRequestService } from '../../shared/mocks/mock-request.service';
+import { NotificationsService } from '../../shared/notifications/notifications.service';
 import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
 import { ObjectCacheService } from '../cache/object-cache.service';
 import { CoreState } from '../core.reducers';
+import { Community } from '../shared/community.model';
+import { HALEndpointService } from '../shared/hal-endpoint.service';
+import { Item } from '../shared/item.model';
 import { ComColDataService } from './comcol-data.service';
 import { CommunityDataService } from './community-data.service';
-import { FindListOptions, FindByIDRequest } from './request.models';
-import { RequestService } from './request.service';
-import { NormalizedObject } from '../cache/models/normalized-object.model';
-import { HALEndpointService } from '../shared/hal-endpoint.service';
-import { RequestEntry } from './request.reducer';
-import {Observable, of as observableOf} from 'rxjs';
-import { NotificationsService } from '../../shared/notifications/notifications.service';
-import { HttpClient } from '@angular/common/http';
-import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service';
 import { DSOChangeAnalyzer } from './dso-change-analyzer.service';
-import { Item } from '../shared/item.model';
-import { Community } from '../shared/community.model';
+import { FindByIDRequest, FindListOptions } from './request.models';
+import { RequestEntry } from './request.reducer';
+import { RequestService } from './request.service';
 
 const LINK_NAME = 'test';
 
-/* tslint:disable:max-classes-per-file */
-class NormalizedTestObject extends NormalizedObject<Item> {
-}
-
 class TestService extends ComColDataService<any> {
 
   constructor(
     protected requestService: RequestService,
     protected rdbService: RemoteDataBuildService,
-    protected dataBuildService: NormalizedObjectBuildService,
     protected store: Store<CoreState>,
     protected EnvConfig: GlobalConfig,
     protected cds: CommunityDataService,
@@ -52,8 +45,6 @@ class TestService extends ComColDataService<any> {
   }
 }
 
-/* tslint:enable:max-classes-per-file */
-
 describe('ComColDataService', () => {
   let scheduler: TestScheduler;
   let service: TestService;
@@ -68,7 +59,6 @@ describe('ComColDataService', () => {
   const notificationsService = {} as NotificationsService;
   const http = {} as HttpClient;
   const comparator = {} as any;
-  const dataBuildService = {} as NormalizedObjectBuildService;
 
   const scopeID = 'd9d30c0c-69b7-4369-8397-ca67c888974d';
   const options = Object.assign(new FindListOptions(), {
@@ -102,7 +92,9 @@ describe('ComColDataService', () => {
       getObjectByUUID: cold('d-', {
         d: {
           _links: {
-            [LINK_NAME]: scopedEndpoint
+            [LINK_NAME]: {
+              href: scopedEndpoint
+            }
           }
         }
       })
@@ -113,7 +105,6 @@ describe('ComColDataService', () => {
     return new TestService(
       requestService,
       rdbService,
-      dataBuildService,
       store,
       EnvConfig,
       cds,
diff --git a/src/app/core/data/comcol-data.service.ts b/src/app/core/data/comcol-data.service.ts
index 2ce0362a4e85e69c09b0f38e84e285fdddcc7c61..d83518a3b0d78afbec62ba54c63e52a6d7fb859f 100644
--- a/src/app/core/data/comcol-data.service.ts
+++ b/src/app/core/data/comcol-data.service.ts
@@ -6,8 +6,10 @@ import {
 } from 'rxjs/operators';
 import { merge as observableMerge, Observable, throwError as observableThrowError, combineLatest as observableCombineLatest } from 'rxjs';
 import { hasValue, isEmpty, isNotEmpty } from '../../shared/empty.util';
-import { NormalizedCommunity } from '../cache/models/normalized-community.model';
 import { ObjectCacheService } from '../cache/object-cache.service';
+import { Community } from '../shared/community.model';
+import { HALLink } from '../shared/hal-link.model';
+import { HALResource } from '../shared/hal-resource.model';
 import { CommunityDataService } from './community-data.service';
 
 import { DataService } from './data.service';
@@ -70,8 +72,9 @@ export abstract class ComColDataService<T extends CacheableObject> extends DataS
       const successResponses = responses.pipe(
         filter((response) => response.isSuccessful),
         mergeMap(() => this.objectCache.getObjectByUUID(options.scopeID)),
-        map((nc: NormalizedCommunity) => nc._links[linkPath]),
-        filter((href) => isNotEmpty(href))
+        map((hr: HALResource) => hr._links[linkPath]),
+        filter((halLink: HALLink) => isNotEmpty(halLink)),
+        map((halLink: HALLink) => halLink.href)
       );
 
       return observableMerge(errorResponses, successResponses).pipe(distinctUntilChanged(), share());
@@ -81,7 +84,9 @@ export abstract class ComColDataService<T extends CacheableObject> extends DataS
   protected abstract getFindByParentHref(parentUUID: string): Observable<string>;
 
   public findByParent(parentUUID: string, options: FindListOptions = {}): Observable<RemoteData<PaginatedList<T>>> {
-    const href$ = this.buildHrefFromFindOptions(this.getFindByParentHref(parentUUID), [], options);
+    const href$ = this.getFindByParentHref(parentUUID).pipe(
+      map((href: string) => this.buildHrefFromFindOptions(href, options))
+    );
     return this.findList(href$, options);
   }
 
diff --git a/src/app/core/data/community-data.service.ts b/src/app/core/data/community-data.service.ts
index 57bf64678f727427e51edf94311a5fec79e2b147..123c3eccd174705e5bbe685705f3dd8d40c7f93d 100644
--- a/src/app/core/data/community-data.service.ts
+++ b/src/app/core/data/community-data.service.ts
@@ -1,25 +1,27 @@
-import { filter, switchMap, take } from 'rxjs/operators';
+import { HttpClient } from '@angular/common/http';
 import { Injectable } from '@angular/core';
 
 import { Store } from '@ngrx/store';
+import { Observable } from 'rxjs';
+import { filter, switchMap, take } from 'rxjs/operators';
+import { hasValue } from '../../shared/empty.util';
+import { NotificationsService } from '../../shared/notifications/notifications.service';
+import { dataService } from '../cache/builders/build-decorators';
 import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
 import { ObjectCacheService } from '../cache/object-cache.service';
 import { CoreState } from '../core.reducers';
 import { Community } from '../shared/community.model';
-import { ComColDataService } from './comcol-data.service';
-import { RequestService } from './request.service';
+import { COMMUNITY } from '../shared/community.resource-type';
 import { HALEndpointService } from '../shared/hal-endpoint.service';
-import { FindListOptions, FindListRequest } from './request.models';
-import { RemoteData } from './remote-data';
-import { hasValue } from '../../shared/empty.util';
-import { Observable } from 'rxjs';
-import { PaginatedList } from './paginated-list';
-import { NotificationsService } from '../../shared/notifications/notifications.service';
-import { HttpClient } from '@angular/common/http';
-import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service';
+import { ComColDataService } from './comcol-data.service';
 import { DSOChangeAnalyzer } from './dso-change-analyzer.service';
+import { PaginatedList } from './paginated-list';
+import { RemoteData } from './remote-data';
+import { FindListOptions, FindListRequest } from './request.models';
+import { RequestService } from './request.service';
 
 @Injectable()
+@dataService(COMMUNITY)
 export class CommunityDataService extends ComColDataService<Community> {
   protected linkPath = 'communities';
   protected topLinkPath = 'communities/search/top';
@@ -28,7 +30,6 @@ export class CommunityDataService extends ComColDataService<Community> {
   constructor(
     protected requestService: RequestService,
     protected rdbService: RemoteDataBuildService,
-    protected dataBuildService: NormalizedObjectBuildService,
     protected store: Store<CoreState>,
     protected objectCache: ObjectCacheService,
     protected halService: HALEndpointService,
diff --git a/src/app/core/data/content-source-response-parsing.service.ts b/src/app/core/data/content-source-response-parsing.service.ts
index 4e0490148b3b4064d8ef186aea023feb7060f4ba..95e25db613369c9b6e4bd0f0479c6e49acdbd83b 100644
--- a/src/app/core/data/content-source-response-parsing.service.ts
+++ b/src/app/core/data/content-source-response-parsing.service.ts
@@ -1,11 +1,11 @@
 import { Injectable } from '@angular/core';
-import { ResponseParsingService } from './parsing.service';
-import { RestRequest } from './request.models';
-import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
 import { ContentSourceSuccessResponse, RestResponse } from '../cache/response.models';
-import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer';
+import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
+import { DSpaceSerializer } from '../dspace-rest-v2/dspace.serializer';
 import { ContentSource } from '../shared/content-source.model';
 import { MetadataConfig } from '../shared/metadata-config.model';
+import { ResponseParsingService } from './parsing.service';
+import { RestRequest } from './request.models';
 
 @Injectable()
 /**
@@ -17,11 +17,11 @@ export class ContentSourceResponseParsingService implements ResponseParsingServi
   parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse {
     const payload = data.payload;
 
-    const deserialized = new DSpaceRESTv2Serializer(ContentSource).deserialize(payload);
+    const deserialized = new DSpaceSerializer(ContentSource).deserialize(payload);
 
     let metadataConfigs = [];
     if (payload._embedded && payload._embedded.harvestermetadata && payload._embedded.harvestermetadata.configs) {
-      metadataConfigs = new DSpaceRESTv2Serializer(MetadataConfig).serializeArray(payload._embedded.harvestermetadata.configs);
+      metadataConfigs = new DSpaceSerializer(MetadataConfig).serializeArray(payload._embedded.harvestermetadata.configs);
     }
     deserialized.metadataConfigs = metadataConfigs;
 
diff --git a/src/app/core/data/data.service.spec.ts b/src/app/core/data/data.service.spec.ts
index 16d5933152a8496b110c12969e3b33c871197ae4..ce74b7af04ae87cfbb430d295753ba6eb85f0e7b 100644
--- a/src/app/core/data/data.service.spec.ts
+++ b/src/app/core/data/data.service.spec.ts
@@ -1,5 +1,4 @@
 import { DataService } from './data.service';
-import { NormalizedObject } from '../cache/models/normalized-object.model';
 import { RequestService } from './request.service';
 import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
 import { CoreState } from '../core.reducers';
@@ -13,7 +12,6 @@ import { compare, Operation } from 'fast-json-patch';
 import { DSpaceObject } from '../shared/dspace-object.model';
 import { ChangeAnalyzer } from './change-analyzer';
 import { HttpClient } from '@angular/common/http';
-import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service';
 import { NotificationsService } from '../../shared/notifications/notifications.service';
 import { Item } from '../shared/item.model';
 import { getMockRequestService } from '../../shared/mocks/mock-request.service';
@@ -23,23 +21,19 @@ import { createSuccessfulRemoteDataObject$ } from '../../shared/testing/utils';
 
 const endpoint = 'https://rest.api/core';
 
-// tslint:disable:max-classes-per-file
-class NormalizedTestObject extends NormalizedObject<Item> {
-}
-
+/* tslint:disable:max-classes-per-file */
 class TestService extends DataService<any> {
 
   constructor(
     protected requestService: RequestService,
     protected rdbService: RemoteDataBuildService,
-    protected dataBuildService: NormalizedObjectBuildService,
     protected store: Store<CoreState>,
     protected linkPath: string,
     protected halService: HALEndpointService,
     protected objectCache: ObjectCacheService,
     protected notificationsService: NotificationsService,
     protected http: HttpClient,
-    protected comparator: ChangeAnalyzer<NormalizedTestObject>
+    protected comparator: ChangeAnalyzer<Item>
   ) {
     super();
   }
@@ -48,9 +42,8 @@ class TestService extends DataService<any> {
     return observableOf(endpoint);
   }
 }
-
-class DummyChangeAnalyzer implements ChangeAnalyzer<NormalizedTestObject> {
-  diff(object1: NormalizedTestObject, object2: NormalizedTestObject): Operation[] {
+class DummyChangeAnalyzer implements ChangeAnalyzer<Item> {
+  diff(object1: Item, object2: Item): Operation[] {
     return compare((object1 as any).metadata, (object2 as any).metadata);
   }
 
@@ -65,9 +58,6 @@ describe('DataService', () => {
   const notificationsService = {} as NotificationsService;
   const http = {} as HttpClient;
   const comparator = new DummyChangeAnalyzer() as any;
-  const dataBuildService = {
-    normalize: (object) => object
-  } as NormalizedObjectBuildService;
   const objectCache = {
     addPatch: () => {
       /* empty */
@@ -82,7 +72,6 @@ describe('DataService', () => {
     return new TestService(
       requestService,
       rdbService,
-      dataBuildService,
       store,
       endpoint,
       halService,
@@ -207,13 +196,15 @@ describe('DataService', () => {
       operations = [{ op: 'replace', path: '/0/value', value: name2 } as Operation];
       selfLink = 'https://rest.api/endpoint/1698f1d3-be98-4c51-9fd8-6bfedcbd59b7';
 
-      dso = new DSpaceObject();
-      dso.self = selfLink;
-      dso.metadata = [{ key: 'dc.title', value: name1 }];
+      dso = Object.assign(new DSpaceObject(), {
+        _links: { self: { href: selfLink } },
+        metadata: [{ key: 'dc.title', value: name1 }]
+      });
 
-      dso2 = new DSpaceObject();
-      dso2.self = selfLink;
-      dso2.metadata = [{ key: 'dc.title', value: name2 }];
+      dso2 = Object.assign(new DSpaceObject(), {
+        _links: { self: { href: selfLink } },
+        metadata: [{ key: 'dc.title', value: name2 }]
+      });
 
       spyOn(service, 'findByHref').and.returnValue(createSuccessfulRemoteDataObject$(dso));
       spyOn(objectCache, 'addPatch');
@@ -230,3 +221,4 @@ describe('DataService', () => {
     });
   });
 });
+/* tslint:enable:max-classes-per-file */
diff --git a/src/app/core/data/data.service.ts b/src/app/core/data/data.service.ts
index e065e79e5b4856befd35626d3f9745abe91785ac..4a3bb3eb08585e3ce3c77376248d634485bf7d39 100644
--- a/src/app/core/data/data.service.ts
+++ b/src/app/core/data/data.service.ts
@@ -1,5 +1,6 @@
 import { HttpClient } from '@angular/common/http';
-
+import { Store } from '@ngrx/store';
+import { Operation } from 'fast-json-patch';
 import { Observable } from 'rxjs';
 import {
   distinctUntilChanged,
@@ -13,12 +14,28 @@ import {
   take,
   tap
 } from 'rxjs/operators';
-import { Store } from '@ngrx/store';
-
 import { hasValue, hasValueOperator, isNotEmpty, isNotEmptyOperator } from '../../shared/empty.util';
+import { NotificationOptions } from '../../shared/notifications/models/notification-options.model';
+import { NotificationsService } from '../../shared/notifications/notifications.service';
+import { FollowLinkConfig } from '../../shared/utils/follow-link-config.model';
+import { getClassForType } from '../cache/builders/build-decorators';
 import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
+import { SearchParam } from '../cache/models/search-param.model';
+import { CacheableObject } from '../cache/object-cache.reducer';
+import { ObjectCacheService } from '../cache/object-cache.service';
+import { ErrorResponse, RestResponse } from '../cache/response.models';
+import { CoreState } from '../core.reducers';
+import { DSpaceSerializer } from '../dspace-rest-v2/dspace.serializer';
+import { DSpaceObject } from '../shared/dspace-object.model';
 import { HALEndpointService } from '../shared/hal-endpoint.service';
+import {
+  configureRequest,
+  getRemoteDataPayload,
+  getResponseFromEntry,
+  getSucceededRemoteData
+} from '../shared/operators';
 import { URLCombiner } from '../url-combiner/url-combiner';
+import { ChangeAnalyzer } from './change-analyzer';
 import { PaginatedList } from './paginated-list';
 import { RemoteData } from './remote-data';
 import {
@@ -30,30 +47,13 @@ import {
   GetRequest,
   PatchRequest
 } from './request.models';
-import { RequestService } from './request.service';
-import { HttpOptions } from '../dspace-rest-v2/dspace-rest-v2.service';
-import { NormalizedObject } from '../cache/models/normalized-object.model';
-import { SearchParam } from '../cache/models/search-param.model';
-import { Operation } from 'fast-json-patch';
-import { ObjectCacheService } from '../cache/object-cache.service';
-import { DSpaceObject } from '../shared/dspace-object.model';
-import { NotificationsService } from '../../shared/notifications/notifications.service';
-import { configureRequest, getRemoteDataPayload, getResponseFromEntry, getSucceededRemoteData } from '../shared/operators';
-import { ErrorResponse, RestResponse } from '../cache/response.models';
-import { NotificationOptions } from '../../shared/notifications/models/notification-options.model';
-import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer';
-import { CacheableObject } from '../cache/object-cache.reducer';
 import { RequestEntry } from './request.reducer';
-import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service';
-import { ChangeAnalyzer } from './change-analyzer';
+import { RequestService } from './request.service';
 import { RestRequestMethod } from './rest-request-method';
-import { getMapsToType } from '../cache/builders/build-decorators';
-import { CoreState } from '../core.reducers';
 
 export abstract class DataService<T extends CacheableObject> {
   protected abstract requestService: RequestService;
   protected abstract rdbService: RemoteDataBuildService;
-  protected abstract dataBuildService: NormalizedObjectBuildService;
   protected abstract store: Store<CoreState>;
   protected abstract linkPath: string;
   protected abstract halService: HALEndpointService;
@@ -61,12 +61,21 @@ export abstract class DataService<T extends CacheableObject> {
   protected abstract notificationsService: NotificationsService;
   protected abstract http: HttpClient;
   protected abstract comparator: ChangeAnalyzer<T>;
+
   /**
    * Allows subclasses to reset the response cache time.
    */
   protected responseMsToLive: number;
 
-  public abstract getBrowseEndpoint(options: FindListOptions, linkPath?: string): Observable<string>
+  /**
+   * Get the endpoint for browsing
+   * @param options The [[FindListOptions]] object
+   * @param linkPath The link path for the object
+   * @returns {Observable<string>}
+   */
+  getBrowseEndpoint(options: FindListOptions = {}, linkPath?: string): Observable<string> {
+    return this.halService.getEndpoint(this.linkPath);
+  }
 
   /**
    * Create the HREF with given options object
@@ -77,12 +86,12 @@ export abstract class DataService<T extends CacheableObject> {
    *    Return an observable that emits created HREF
    */
   protected getFindAllHref(options: FindListOptions = {}, linkPath?: string): Observable<string> {
-    let result: Observable<string>;
+    let result$: Observable<string>;
     const args = [];
 
-    result = this.getBrowseEndpoint(options, linkPath).pipe(distinctUntilChanged());
+    result$ = this.getBrowseEndpoint(options, linkPath).pipe(distinctUntilChanged());
 
-    return this.buildHrefFromFindOptions(result, args, options);
+    return result$.pipe(map((result: string) => this.buildHrefFromFindOptions(result, options, args)));
   }
 
   /**
@@ -94,10 +103,10 @@ export abstract class DataService<T extends CacheableObject> {
    *    Return an observable that emits created HREF
    */
   protected getSearchByHref(searchMethod: string, options: FindListOptions = {}): Observable<string> {
-    let result: Observable<string>;
+    let result$: Observable<string>;
     const args = [];
 
-    result = this.getSearchEndpoint(searchMethod);
+    result$ = this.getSearchEndpoint(searchMethod);
 
     if (hasValue(options.searchParams)) {
       options.searchParams.forEach((param: SearchParam) => {
@@ -105,45 +114,63 @@ export abstract class DataService<T extends CacheableObject> {
       })
     }
 
-    return this.buildHrefFromFindOptions(result, args, options);
+    return result$.pipe(map((result: string) => this.buildHrefFromFindOptions(result, options, args)));
   }
 
   /**
    * Turn an options object into a query string and combine it with the given HREF
    *
-   * @param href$ The HREF to which the query string should be appended
-   * @param args Array with additional params to combine with query string
+   * @param href The HREF to which the query string should be appended
    * @param options The [[FindListOptions]] object
+   * @param extraArgs Array with additional params to combine with query string
    * @return {Observable<string>}
    *    Return an observable that emits created HREF
    */
-  protected buildHrefFromFindOptions(href$: Observable<string>, args: string[], options: FindListOptions): Observable<string> {
+  protected buildHrefFromFindOptions(href: string, options: FindListOptions, extraArgs: string[] = []): string {
+
+    let args = [...extraArgs];
 
     if (hasValue(options.currentPage) && typeof options.currentPage === 'number') {
       /* TODO: this is a temporary fix for the pagination start index (0 or 1) discrepancy between the rest and the frontend respectively */
-      args.push(`page=${options.currentPage - 1}`);
+      args = [...args, `page=${options.currentPage - 1}`];
     }
     if (hasValue(options.elementsPerPage)) {
-      args.push(`size=${options.elementsPerPage}`);
+      args = [...args, `size=${options.elementsPerPage}`];
     }
     if (hasValue(options.sort)) {
-      args.push(`sort=${options.sort.field},${options.sort.direction}`);
+      args = [...args, `sort=${options.sort.field},${options.sort.direction}`];
     }
     if (hasValue(options.startsWith)) {
-      args.push(`startsWith=${options.startsWith}`);
+      args = [...args, `startsWith=${options.startsWith}`];
     }
     if (isNotEmpty(args)) {
-      return href$.pipe(map((href: string) => new URLCombiner(href, `?${args.join('&')}`).toString()));
+      return new URLCombiner(href, `?${args.join('&')}`).toString();
     } else {
-      return href$;
+      return href;
     }
   }
 
-  findAll(options: FindListOptions = {}): Observable<RemoteData<PaginatedList<T>>> {
-    return this.findList(this.getFindAllHref(options), options);
+  /**
+   * Returns {@link RemoteData} of all object with a list of {@link FollowLinkConfig}, to indicate which embedded
+   * info should be added to the objects
+   *
+   * @param options         Find list options object
+   * @param linksToFollow   List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved
+   * @return {Observable<RemoteData<PaginatedList<T>>>}
+   *    Return an observable that emits object list
+   */
+  findAll(options: FindListOptions = {}, ...linksToFollow: Array<FollowLinkConfig<T>>): Observable<RemoteData<PaginatedList<T>>> {
+    return this.findList(this.getFindAllHref(options), options, ...linksToFollow);
   }
 
-  protected findList(href$, options: FindListOptions) {
+  /**
+   * Returns an observable of {@link RemoteData} of an object, based on href observable,
+   * with a list of {@link FollowLinkConfig}, to automatically resolve {@link HALLink}s of the object
+   * @param href$           Observable of href of object we want to retrieve
+   * @param options         Find list options object
+   * @param linksToFollow   List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved
+   */
+  protected findList(href$, options: FindListOptions, ...linksToFollow: Array<FollowLinkConfig<T>>) {
     href$.pipe(
       first((href: string) => hasValue(href)))
       .subscribe((href: string) => {
@@ -154,7 +181,7 @@ export abstract class DataService<T extends CacheableObject> {
         this.requestService.configure(request);
       });
 
-    return this.rdbService.buildList<T>(href$) as Observable<RemoteData<PaginatedList<T>>>;
+    return this.rdbService.buildList<T>(href$, ...linksToFollow) as Observable<RemoteData<PaginatedList<T>>>;
   }
 
   /**
@@ -166,7 +193,13 @@ export abstract class DataService<T extends CacheableObject> {
     return `${endpoint}/${resourceID}`;
   }
 
-  findById(id: string): Observable<RemoteData<T>> {
+  /**
+   * Returns an observable of {@link RemoteData} of an object, based on its ID, with a list of {@link FollowLinkConfig},
+   * to automatically resolve {@link HALLink}s of the object
+   * @param id              ID of object we want to retrieve
+   * @param linksToFollow   List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved
+   */
+  findById(id: string, ...linksToFollow: Array<FollowLinkConfig<T>>): Observable<RemoteData<T>> {
 
     const hrefObs = this.halService.getEndpoint(this.linkPath).pipe(
       map((endpoint: string) => this.getIDHref(endpoint, encodeURIComponent(id))));
@@ -181,16 +214,40 @@ export abstract class DataService<T extends CacheableObject> {
         this.requestService.configure(request);
       });
 
-    return this.rdbService.buildSingle<T>(hrefObs);
+    return this.rdbService.buildSingle<T>(hrefObs, ...linksToFollow);
   }
 
-  findByHref(href: string, options?: HttpOptions): Observable<RemoteData<T>> {
-    const request = new GetRequest(this.requestService.generateRequestId(), href, null, options);
+  /**
+   * Returns an observable of {@link RemoteData} of an object, based on an href, with a list of {@link FollowLinkConfig},
+   * to automatically resolve {@link HALLink}s of the object
+   * @param href            The url of object we want to retrieve
+   * @param linksToFollow   List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved
+   */
+  findByHref(href: string, ...linksToFollow: Array<FollowLinkConfig<T>>): Observable<RemoteData<T>> {
+    const requestHref = this.buildHrefFromFindOptions(href, {}, []);
+    const request = new GetRequest(this.requestService.generateRequestId(), requestHref);
     if (hasValue(this.responseMsToLive)) {
       request.responseMsToLive = this.responseMsToLive;
     }
     this.requestService.configure(request);
-    return this.rdbService.buildSingle<T>(href);
+    return this.rdbService.buildSingle<T>(href, ...linksToFollow);
+  }
+
+  /**
+   * Returns a list of observables of {@link RemoteData} of objects, based on an href, with a list of {@link FollowLinkConfig},
+   * to automatically resolve {@link HALLink}s of the object
+   * @param href            The url of object we want to retrieve
+   * @param findListOptions Find list options object
+   * @param linksToFollow   List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved
+   */
+  findAllByHref(href: string, findListOptions: FindListOptions = {}, ...linksToFollow: Array<FollowLinkConfig<T>>): Observable<RemoteData<PaginatedList<T>>> {
+    const requestHref = this.buildHrefFromFindOptions(href, findListOptions, []);
+    const request = new GetRequest(this.requestService.generateRequestId(), requestHref);
+    if (hasValue(this.responseMsToLive)) {
+      request.responseMsToLive = this.responseMsToLive;
+    }
+    this.requestService.configure(request);
+    return this.rdbService.buildList<T>(requestHref, ...linksToFollow);
   }
 
   /**
@@ -209,10 +266,11 @@ export abstract class DataService<T extends CacheableObject> {
    *
    * @param searchMethod The search method for the object
    * @param options The [[FindListOptions]] object
+   * @param linksToFollow The array of [[FollowLinkConfig]]
    * @return {Observable<RemoteData<PaginatedList<T>>}
    *    Return an observable that emits response from the server
    */
-  protected searchBy(searchMethod: string, options: FindListOptions = {}): Observable<RemoteData<PaginatedList<T>>> {
+  protected searchBy(searchMethod: string, options: FindListOptions = {}, ...linksToFollow: Array<FollowLinkConfig<T>>): Observable<RemoteData<PaginatedList<T>>> {
 
     const hrefObs = this.getSearchByHref(searchMethod, options);
 
@@ -229,7 +287,7 @@ export abstract class DataService<T extends CacheableObject> {
       switchMap((href) => this.requestService.getByHref(href)),
       skipWhile((requestEntry) => hasValue(requestEntry) && requestEntry.completed),
       switchMap((href) =>
-        this.rdbService.buildList<T>(hrefObs) as Observable<RemoteData<PaginatedList<T>>>
+        this.rdbService.buildList<T>(hrefObs, ...linksToFollow) as Observable<RemoteData<PaginatedList<T>>>
       )
     );
   }
@@ -275,18 +333,18 @@ export abstract class DataService<T extends CacheableObject> {
    * @param {DSpaceObject} object The given object
    */
   update(object: T): Observable<RemoteData<T>> {
-    const oldVersion$ = this.findByHref(object.self);
+    const oldVersion$ = this.findByHref(object._links.self.href);
     return oldVersion$.pipe(
       getSucceededRemoteData(),
       getRemoteDataPayload(),
       mergeMap((oldVersion: T) => {
-        const operations = this.comparator.diff(oldVersion, object);
-        if (isNotEmpty(operations)) {
-          this.objectCache.addPatch(object.self, operations);
+          const operations = this.comparator.diff(oldVersion, object);
+          if (isNotEmpty(operations)) {
+            this.objectCache.addPatch(object._links.self.href, operations);
+          }
+          return this.findByHref(object._links.self.href);
         }
-        return this.findByHref(object.self);
-      }
-    ));
+      ));
   }
 
   /**
@@ -306,8 +364,7 @@ export abstract class DataService<T extends CacheableObject> {
       map((endpoint: string) => parentUUID ? `${endpoint}?parent=${parentUUID}` : endpoint)
     );
 
-    const normalizedObject: NormalizedObject<T> = this.dataBuildService.normalize<T>(dso);
-    const serializedDso = new DSpaceRESTv2Serializer(getMapsToType((dso as any).type)).serialize(normalizedObject);
+    const serializedDso = new DSpaceSerializer(getClassForType((dso as any).type)).serialize(dso);
 
     const request$ = endpoint$.pipe(
       take(1),
@@ -344,13 +401,13 @@ export abstract class DataService<T extends CacheableObject> {
 
   /**
    * Delete an existing DSpace Object on the server
-   * @param dso The DSpace Object to be removed
+   * @param dsoID The DSpace Object' id to be removed
    * @param copyVirtualMetadata (optional parameter) the identifiers of the relationship types for which the virtual
    *                            metadata should be saved as real metadata
    * @return an observable that emits true when the deletion was successful, false when it failed
    */
-  delete(dso: T, copyVirtualMetadata?: string[]): Observable<boolean> {
-    const requestId = this.deleteAndReturnRequestId(dso, copyVirtualMetadata);
+  delete(dsoID: string, copyVirtualMetadata?: string[]): Observable<boolean> {
+    const requestId = this.deleteAndReturnRequestId(dsoID, copyVirtualMetadata);
 
     return this.requestService.getByUUID(requestId).pipe(
       find((request: RequestEntry) => request.completed),
@@ -360,13 +417,13 @@ export abstract class DataService<T extends CacheableObject> {
 
   /**
    * Delete an existing DSpace Object on the server
-   * @param dso The DSpace Object to be removed
+   * @param dsoID The DSpace Object' id to be removed
    * @param copyVirtualMetadata (optional parameter) the identifiers of the relationship types for which the virtual
    *                            metadata should be saved as real metadata
    * Return an observable of the completed response
    */
-  deleteAndReturnResponse(dso: T, copyVirtualMetadata?: string[]): Observable<RestResponse> {
-    const requestId = this.deleteAndReturnRequestId(dso, copyVirtualMetadata);
+  deleteAndReturnResponse(dsoID: string, copyVirtualMetadata?: string[]): Observable<RestResponse> {
+    const requestId = this.deleteAndReturnRequestId(dsoID, copyVirtualMetadata);
 
     return this.requestService.getByUUID(requestId).pipe(
       hasValueOperator(),
@@ -377,16 +434,16 @@ export abstract class DataService<T extends CacheableObject> {
 
   /**
    * Delete an existing DSpace Object on the server
-   * @param dso The DSpace Object to be removed
+   * @param dsoID The DSpace Object' id to be removed
    * @param copyVirtualMetadata (optional parameter) the identifiers of the relationship types for which the virtual
    *                            metadata should be saved as real metadata
    * Return the delete request's ID
    */
-  private deleteAndReturnRequestId(dso: T, copyVirtualMetadata?: string[]): string {
+  private deleteAndReturnRequestId(dsoID: string, copyVirtualMetadata?: string[]): string {
     const requestId = this.requestService.generateRequestId();
 
     const hrefObs = this.halService.getEndpoint(this.linkPath).pipe(
-      map((endpoint: string) => this.getIDHref(endpoint, dso.uuid)));
+      map((endpoint: string) => this.getIDHref(endpoint, dsoID)));
 
     hrefObs.pipe(
       find((href: string) => hasValue(href)),
@@ -398,7 +455,7 @@ export abstract class DataService<T extends CacheableObject> {
               + id
           );
         }
-        const request = new DeleteByIDRequest(requestId, href, dso.uuid);
+        const request = new DeleteByIDRequest(requestId, href, dsoID);
         this.requestService.configure(request);
       })
     ).subscribe();
diff --git a/src/app/core/data/default-change-analyzer.service.ts b/src/app/core/data/default-change-analyzer.service.ts
index 862c0e5b85c47bc8afa3bb86d0a7574b1ca7662b..20218925fb9eba2e190170f3a7e8061c77068986 100644
--- a/src/app/core/data/default-change-analyzer.service.ts
+++ b/src/app/core/data/default-change-analyzer.service.ts
@@ -1,10 +1,10 @@
-import { Operation } from 'fast-json-patch/lib/core';
-import { compare } from 'fast-json-patch';
-import { ChangeAnalyzer } from './change-analyzer';
 import { Injectable } from '@angular/core';
+import { compare } from 'fast-json-patch';
+import { Operation } from 'fast-json-patch/lib/core';
+import { getClassForType } from '../cache/builders/build-decorators';
 import { CacheableObject } from '../cache/object-cache.reducer';
-import { NormalizedObject } from '../cache/models/normalized-object.model';
-import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service';
+import { DSpaceSerializer } from '../dspace-rest-v2/dspace.serializer';
+import { ChangeAnalyzer } from './change-analyzer';
 
 /**
  * A class to determine what differs between two
@@ -12,19 +12,18 @@ import { NormalizedObjectBuildService } from '../cache/builders/normalized-objec
  */
 @Injectable()
 export class DefaultChangeAnalyzer<T extends CacheableObject> implements ChangeAnalyzer<T> {
-  constructor(private normalizeService: NormalizedObjectBuildService) {
-  }
-
   /**
    * Compare the metadata of two CacheableObject and return the differences as
    * a JsonPatch Operation Array
    *
-   * @param {NormalizedObject} object1
+   * @param {CacheableObject} object1
    *    The first object to compare
-   * @param {NormalizedObject} object2
+   * @param {CacheableObject} object2
    *    The second object to compare
    */
-  diff(object1: T | NormalizedObject<T>, object2: T | NormalizedObject<T>): Operation[] {
-    return compare(this.normalizeService.normalize(object1), this.normalizeService.normalize(object2));
+  diff(object1: T, object2: T): Operation[] {
+    const serializer1 = new DSpaceSerializer(getClassForType(object1.type));
+    const serializer2 = new DSpaceSerializer(getClassForType(object2.type));
+    return compare(serializer1.serialize(object1), serializer2.serialize(object2));
   }
 }
diff --git a/src/app/core/data/dso-change-analyzer.service.ts b/src/app/core/data/dso-change-analyzer.service.ts
index ce3ed2452ec034a62298cf48025998d717d3fd39..af0b95234b0d2fd13d7066e862cc213ba1c11d40 100644
--- a/src/app/core/data/dso-change-analyzer.service.ts
+++ b/src/app/core/data/dso-change-analyzer.service.ts
@@ -1,7 +1,6 @@
 import { Operation } from 'fast-json-patch/lib/core';
 import { compare } from 'fast-json-patch';
 import { ChangeAnalyzer } from './change-analyzer';
-import { NormalizedDSpaceObject } from '../cache/models/normalized-dspace-object.model';
 import { Injectable } from '@angular/core';
 import { DSpaceObject } from '../shared/dspace-object.model';
 import { MetadataMap } from '../shared/metadata.models';
@@ -18,12 +17,12 @@ export class DSOChangeAnalyzer<T extends DSpaceObject> implements ChangeAnalyzer
    * Compare the metadata of two DSpaceObjects and return the differences as
    * a JsonPatch Operation Array
    *
-   * @param {NormalizedDSpaceObject} object1
+   * @param {DSpaceObject} object1
    *    The first object to compare
-   * @param {NormalizedDSpaceObject} object2
+   * @param {DSpaceObject} object2
    *    The second object to compare
    */
-  diff(object1: T | NormalizedDSpaceObject<T>, object2: T | NormalizedDSpaceObject<T>): Operation[] {
+  diff(object1: DSpaceObject, object2: DSpaceObject): Operation[] {
     return compare(this.filterUUIDsFromMetadata(object1.metadata), this.filterUUIDsFromMetadata(object2.metadata))
       .map((operation: Operation) => Object.assign({}, operation, { path: '/metadata' + operation.path }));
   }
diff --git a/src/app/core/data/dso-redirect-data.service.spec.ts b/src/app/core/data/dso-redirect-data.service.spec.ts
index 80507c4492a91e4c18de9605e304a9470bff6217..25a148d92be562ac7cad6159c562addf2081d2b4 100644
--- a/src/app/core/data/dso-redirect-data.service.spec.ts
+++ b/src/app/core/data/dso-redirect-data.service.spec.ts
@@ -7,7 +7,6 @@ import { RequestService } from './request.service';
 import { ObjectCacheService } from '../cache/object-cache.service';
 import { NotificationsService } from '../../shared/notifications/notifications.service';
 import { HttpClient } from '@angular/common/http';
-import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service';
 import { DsoRedirectDataService } from './dso-redirect-data.service';
 import { Store } from '@ngrx/store';
 import { CoreState } from '../core.reducers';
@@ -31,7 +30,6 @@ describe('DsoRedirectDataService', () => {
   const notificationsService = {} as NotificationsService;
   const http = {} as HttpClient;
   const comparator = {} as any;
-  const dataBuildService = {} as NormalizedObjectBuildService;
   const objectCache = {} as ObjectCacheService;
   let setup;
   beforeEach(() => {
@@ -68,7 +66,6 @@ describe('DsoRedirectDataService', () => {
       service = new DsoRedirectDataService(
         requestService,
         rdbService,
-        dataBuildService,
         store,
         objectCache,
         halService,
@@ -83,7 +80,7 @@ describe('DsoRedirectDataService', () => {
   describe('findById', () => {
     it('should call HALEndpointService with the path to the pid endpoint', () => {
       setup();
-      scheduler.schedule(() => service.findById(dsoHandle, IdentifierType.HANDLE));
+      scheduler.schedule(() => service.findByIdAndIDType(dsoHandle, IdentifierType.HANDLE));
       scheduler.flush();
 
       expect(halService.getEndpoint).toHaveBeenCalledWith('pid');
@@ -91,7 +88,7 @@ describe('DsoRedirectDataService', () => {
 
     it('should call HALEndpointService with the path to the dso endpoint', () => {
       setup();
-      scheduler.schedule(() => service.findById(dsoUUID, IdentifierType.UUID));
+      scheduler.schedule(() => service.findByIdAndIDType(dsoUUID, IdentifierType.UUID));
       scheduler.flush();
 
       expect(halService.getEndpoint).toHaveBeenCalledWith('dso');
@@ -99,7 +96,7 @@ describe('DsoRedirectDataService', () => {
 
     it('should call HALEndpointService with the path to the dso endpoint when identifier type not specified', () => {
       setup();
-      scheduler.schedule(() => service.findById(dsoUUID));
+      scheduler.schedule(() => service.findByIdAndIDType(dsoUUID));
       scheduler.flush();
 
       expect(halService.getEndpoint).toHaveBeenCalledWith('dso');
@@ -107,7 +104,7 @@ describe('DsoRedirectDataService', () => {
 
     it('should configure the proper FindByIDRequest for uuid', () => {
       setup();
-      scheduler.schedule(() => service.findById(dsoUUID, IdentifierType.UUID));
+      scheduler.schedule(() => service.findByIdAndIDType(dsoUUID, IdentifierType.UUID));
       scheduler.flush();
 
       expect(requestService.configure).toHaveBeenCalledWith(new FindByIDRequest(requestUUID, requestUUIDURL, dsoUUID));
@@ -115,7 +112,7 @@ describe('DsoRedirectDataService', () => {
 
     it('should configure the proper FindByIDRequest for handle', () => {
       setup();
-      scheduler.schedule(() => service.findById(dsoHandle, IdentifierType.HANDLE));
+      scheduler.schedule(() => service.findByIdAndIDType(dsoHandle, IdentifierType.HANDLE));
       scheduler.flush();
 
       expect(requestService.configure).toHaveBeenCalledWith(new FindByIDRequest(requestUUID, requestHandleURL, dsoHandle));
@@ -124,7 +121,7 @@ describe('DsoRedirectDataService', () => {
     it('should navigate to item route', () => {
       remoteData.payload.type = 'item';
       setup();
-      const redir = service.findById(dsoHandle, IdentifierType.HANDLE);
+      const redir = service.findByIdAndIDType(dsoHandle, IdentifierType.HANDLE);
       // The framework would normally subscribe but do it here so we can test navigation.
       redir.subscribe();
       scheduler.schedule(() => redir);
@@ -135,7 +132,7 @@ describe('DsoRedirectDataService', () => {
     it('should navigate to collections route', () => {
       remoteData.payload.type = 'collection';
       setup();
-      const redir = service.findById(dsoHandle, IdentifierType.HANDLE);
+      const redir = service.findByIdAndIDType(dsoHandle, IdentifierType.HANDLE);
       redir.subscribe();
       scheduler.schedule(() => redir);
       scheduler.flush();
@@ -145,7 +142,7 @@ describe('DsoRedirectDataService', () => {
     it('should navigate to communities route', () => {
       remoteData.payload.type = 'community';
       setup();
-      const redir = service.findById(dsoHandle, IdentifierType.HANDLE);
+      const redir = service.findByIdAndIDType(dsoHandle, IdentifierType.HANDLE);
       redir.subscribe();
       scheduler.schedule(() => redir);
       scheduler.flush();
diff --git a/src/app/core/data/dso-redirect-data.service.ts b/src/app/core/data/dso-redirect-data.service.ts
index f4999637b344e45c74b1cb3de838fa9080394408..232fde65d0eed5761abd42e4a3d76e7f6bf6044a 100644
--- a/src/app/core/data/dso-redirect-data.service.ts
+++ b/src/app/core/data/dso-redirect-data.service.ts
@@ -1,35 +1,32 @@
-import { DataService } from './data.service';
-import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service';
-import { HALEndpointService } from '../shared/hal-endpoint.service';
 import { HttpClient } from '@angular/common/http';
-import { NotificationsService } from '../../shared/notifications/notifications.service';
-import { ObjectCacheService } from '../cache/object-cache.service';
-import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
-import { RequestService } from './request.service';
+import { Injectable } from '@angular/core';
+import { Router } from '@angular/router';
 import { Store } from '@ngrx/store';
-import { CoreState } from '../core.reducers';
-import { FindListOptions, FindByIDRequest, IdentifierType } from './request.models';
 import { Observable } from 'rxjs';
-import { RemoteData } from './remote-data';
-import { DSOChangeAnalyzer } from './dso-change-analyzer.service';
-import { Injectable } from '@angular/core';
-import { filter, take, tap } from 'rxjs/operators';
+import { take, tap } from 'rxjs/operators';
 import { hasValue } from '../../shared/empty.util';
+import { NotificationsService } from '../../shared/notifications/notifications.service';
+import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
+import { ObjectCacheService } from '../cache/object-cache.service';
+import { CoreState } from '../core.reducers';
+import { HALEndpointService } from '../shared/hal-endpoint.service';
 import { getFinishedRemoteData } from '../shared/operators';
-import { Router } from '@angular/router';
+import { DataService } from './data.service';
+import { DSOChangeAnalyzer } from './dso-change-analyzer.service';
+import { RemoteData } from './remote-data';
+import { FindByIDRequest, IdentifierType } from './request.models';
+import { RequestService } from './request.service';
 
 @Injectable()
 export class DsoRedirectDataService extends DataService<any> {
 
   // Set the default link path to the identifier lookup endpoint.
   protected linkPath = 'pid';
-  protected forceBypassCache = false;
   private uuidEndpoint = 'dso';
 
   constructor(
     protected requestService: RequestService,
     protected rdbService: RemoteDataBuildService,
-    protected dataBuildService: NormalizedObjectBuildService,
     protected store: Store<CoreState>,
     protected objectCache: ObjectCacheService,
     protected halService: HALEndpointService,
@@ -40,10 +37,6 @@ export class DsoRedirectDataService extends DataService<any> {
     super();
   }
 
-  getBrowseEndpoint(options: FindListOptions = {}, linkPath: string = this.linkPath): Observable<string> {
-    return this.halService.getEndpoint(linkPath);
-  }
-
   setLinkPath(identifierType: IdentifierType) {
     // The default 'pid' endpoint for identifiers does not support uuid lookups.
     // For uuid lookups we need to change the linkPath.
@@ -58,9 +51,9 @@ export class DsoRedirectDataService extends DataService<any> {
       .replace(/\{\?uuid\}/, `?uuid=${resourceID}`);
   }
 
-  findById(id: string, identifierType = IdentifierType.UUID): Observable<RemoteData<FindByIDRequest>> {
+  findByIdAndIDType(id: string, identifierType = IdentifierType.UUID): Observable<RemoteData<FindByIDRequest>> {
     this.setLinkPath(identifierType);
-    return super.findById(id).pipe(
+    return this.findById(id).pipe(
       getFinishedRemoteData(),
       take(1),
       tap((response) => {
diff --git a/src/app/core/data/dso-response-parsing.service.ts b/src/app/core/data/dso-response-parsing.service.ts
index d2c21825cc5380319163c2674e5a2160f9020008..83676ce1051e0b8410283a74b25be9f0c35dabac 100644
--- a/src/app/core/data/dso-response-parsing.service.ts
+++ b/src/app/core/data/dso-response-parsing.service.ts
@@ -3,7 +3,6 @@ import { Inject, Injectable } from '@angular/core';
 import { ObjectCacheService } from '../cache/object-cache.service';
 import { GlobalConfig } from '../../../config/global-config.interface';
 import { GLOBAL_CONFIG } from '../../../config';
-import { NormalizedObject } from '../cache/models/normalized-object.model';
 import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
 import { RestResponse, DSOSuccessResponse } from '../cache/response.models';
 import { RestRequest } from './request.models';
@@ -30,7 +29,7 @@ export class DSOResponseParsingService extends BaseResponseParsingService implem
     if (hasValue(data.payload) && hasValue(data.payload.page) && data.payload.page.totalElements === 0) {
       processRequestDTO = { page: [] };
     } else {
-      processRequestDTO = this.process<NormalizedObject<DSpaceObject>>(data.payload, request);
+      processRequestDTO = this.process<DSpaceObject>(data.payload, request);
     }
     let objectList = processRequestDTO;
 
@@ -42,7 +41,7 @@ export class DSOResponseParsingService extends BaseResponseParsingService implem
     } else if (!Array.isArray(processRequestDTO)) {
       objectList = [processRequestDTO];
     }
-    const selfLinks = objectList.map((no) => no.self);
+    const selfLinks = objectList.map((no) => no._links.self.href);
     return new DSOSuccessResponse(selfLinks, data.statusCode, data.statusText, this.processPageInfo(data.payload))
   }
 
diff --git a/src/app/core/data/dspace-object-data.service.spec.ts b/src/app/core/data/dspace-object-data.service.spec.ts
index 7047db606549f7fb5d513f7f77e3d129506f9487..b7c8c3fe9d6b5f6d734a546d9064bff40882913c 100644
--- a/src/app/core/data/dspace-object-data.service.spec.ts
+++ b/src/app/core/data/dspace-object-data.service.spec.ts
@@ -9,8 +9,6 @@ import { DSpaceObjectDataService } from './dspace-object-data.service';
 import { ObjectCacheService } from '../cache/object-cache.service';
 import { NotificationsService } from '../../shared/notifications/notifications.service';
 import { HttpClient } from '@angular/common/http';
-import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service';
-
 describe('DSpaceObjectDataService', () => {
   let scheduler: TestScheduler;
   let service: DSpaceObjectDataService;
@@ -46,12 +44,10 @@ describe('DSpaceObjectDataService', () => {
     const notificationsService = {} as NotificationsService;
     const http = {} as HttpClient;
     const comparator = {} as any;
-    const dataBuildService = {} as NormalizedObjectBuildService;
 
     service = new DSpaceObjectDataService(
       requestService,
       rdbService,
-      dataBuildService,
       objectCache,
       halService,
       notificationsService,
diff --git a/src/app/core/data/dspace-object-data.service.ts b/src/app/core/data/dspace-object-data.service.ts
index 002ac3cdbc90835e791b1e2924d213825b94a1ba..38e9f8d8883e7863faa3f933fc8182d70e1f8e64 100644
--- a/src/app/core/data/dspace-object-data.service.ts
+++ b/src/app/core/data/dspace-object-data.service.ts
@@ -1,19 +1,19 @@
+import { HttpClient } from '@angular/common/http';
 import { Injectable } from '@angular/core';
 import { Store } from '@ngrx/store';
 import { Observable } from 'rxjs';
+import { NotificationsService } from '../../shared/notifications/notifications.service';
+import { dataService } from '../cache/builders/build-decorators';
 import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
+import { ObjectCacheService } from '../cache/object-cache.service';
 import { CoreState } from '../core.reducers';
 import { DSpaceObject } from '../shared/dspace-object.model';
+import { DSPACE_OBJECT } from '../shared/dspace-object.resource-type';
 import { HALEndpointService } from '../shared/hal-endpoint.service';
 import { DataService } from './data.service';
+import { DSOChangeAnalyzer } from './dso-change-analyzer.service';
 import { RemoteData } from './remote-data';
 import { RequestService } from './request.service';
-import { FindListOptions } from './request.models';
-import { ObjectCacheService } from '../cache/object-cache.service';
-import { NotificationsService } from '../../shared/notifications/notifications.service';
-import { HttpClient } from '@angular/common/http';
-import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service';
-import { DSOChangeAnalyzer } from './dso-change-analyzer.service';
 
 /* tslint:disable:max-classes-per-file */
 class DataServiceImpl extends DataService<DSpaceObject> {
@@ -22,7 +22,6 @@ class DataServiceImpl extends DataService<DSpaceObject> {
   constructor(
     protected requestService: RequestService,
     protected rdbService: RemoteDataBuildService,
-    protected dataBuildService: NormalizedObjectBuildService,
     protected store: Store<CoreState>,
     protected objectCache: ObjectCacheService,
     protected halService: HALEndpointService,
@@ -32,16 +31,13 @@ class DataServiceImpl extends DataService<DSpaceObject> {
     super();
   }
 
-  getBrowseEndpoint(options: FindListOptions = {}, linkPath: string = this.linkPath): Observable<string> {
-    return this.halService.getEndpoint(linkPath);
-  }
-
   getIDHref(endpoint, resourceID): string {
-    return endpoint.replace(/\{\?uuid\}/,`?uuid=${resourceID}`);
+    return endpoint.replace(/\{\?uuid\}/, `?uuid=${resourceID}`);
   }
 }
 
 @Injectable()
+@dataService(DSPACE_OBJECT)
 export class DSpaceObjectDataService {
   protected linkPath = 'dso';
   private dataService: DataServiceImpl;
@@ -49,13 +45,12 @@ export class DSpaceObjectDataService {
   constructor(
     protected requestService: RequestService,
     protected rdbService: RemoteDataBuildService,
-    protected dataBuildService: NormalizedObjectBuildService,
     protected objectCache: ObjectCacheService,
     protected halService: HALEndpointService,
     protected notificationsService: NotificationsService,
     protected http: HttpClient,
     protected comparator: DSOChangeAnalyzer<DSpaceObject>) {
-    this.dataService = new DataServiceImpl(requestService, rdbService, dataBuildService, null, objectCache, halService, notificationsService, http, comparator);
+    this.dataService = new DataServiceImpl(requestService, rdbService, null, objectCache, halService, notificationsService, http, comparator);
   }
 
   findById(uuid: string): Observable<RemoteData<DSpaceObject>> {
diff --git a/src/app/core/data/entity-type-data.service.ts b/src/app/core/data/entity-type-data.service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..87de69b9357768d2a21fc2faaf0e036333e3b7c9
--- /dev/null
+++ b/src/app/core/data/entity-type-data.service.ts
@@ -0,0 +1,85 @@
+import { HttpClient } from '@angular/common/http';
+import { Injectable } from '@angular/core';
+import { Store } from '@ngrx/store';
+import { Observable } from 'rxjs';
+import { NotificationsService } from '../../shared/notifications/notifications.service';
+import { FollowLinkConfig } from '../../shared/utils/follow-link-config.model';
+import { dataService } from '../cache/builders/build-decorators';
+import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
+import { ObjectCacheService } from '../cache/object-cache.service';
+import { CoreState } from '../core.reducers';
+import { HALEndpointService } from '../shared/hal-endpoint.service';
+import { ItemType } from '../shared/item-relationships/item-type.model';
+import { ITEM_TYPE } from '../shared/item-relationships/item-type.resource-type';
+import { DataService } from './data.service';
+import { DefaultChangeAnalyzer } from './default-change-analyzer.service';
+import { PaginatedList } from './paginated-list';
+import { RemoteData } from './remote-data';
+import { FindListOptions } from './request.models';
+import { RequestService } from './request.service';
+
+/* tslint:disable:max-classes-per-file */
+
+/**
+ * A private DataService implementation to delegate specific methods to.
+ */
+class DataServiceImpl extends DataService<ItemType> {
+  protected linkPath = 'entitytypes';
+
+  constructor(
+    protected requestService: RequestService,
+    protected rdbService: RemoteDataBuildService,
+    protected store: Store<CoreState>,
+    protected objectCache: ObjectCacheService,
+    protected halService: HALEndpointService,
+    protected notificationsService: NotificationsService,
+    protected http: HttpClient,
+    protected comparator: DefaultChangeAnalyzer<ItemType>) {
+    super();
+  }
+}
+
+/**
+ * A service to retrieve {@link ItemType}s from the REST API.
+ */
+@Injectable()
+@dataService(ITEM_TYPE)
+export class ItemTypeDataService {
+  /**
+   * A private DataService instance to delegate specific methods to.
+   */
+  private dataService: DataServiceImpl;
+
+  constructor(
+    protected requestService: RequestService,
+    protected rdbService: RemoteDataBuildService,
+    protected store: Store<CoreState>,
+    protected objectCache: ObjectCacheService,
+    protected halService: HALEndpointService,
+    protected notificationsService: NotificationsService,
+    protected http: HttpClient,
+    protected comparator: DefaultChangeAnalyzer<ItemType>) {
+    this.dataService = new DataServiceImpl(requestService, rdbService, null, objectCache, halService, notificationsService, http, comparator);
+  }
+
+  /**
+   * Returns an observable of {@link RemoteData} of an {@link ItemType}, based on an href, with a list of {@link FollowLinkConfig},
+   * to automatically resolve {@link HALLink}s of the {@link ItemType}
+   * @param href            The url of {@link ItemType} we want to retrieve
+   * @param linksToFollow   List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved
+   */
+  findByHref(href: string, ...linksToFollow: Array<FollowLinkConfig<ItemType>>): Observable<RemoteData<ItemType>> {
+    return this.dataService.findByHref(href, ...linksToFollow);
+  }
+
+  /**
+   * Returns a list of observables of {@link RemoteData} of {@link ItemType}s, based on an href, with a list of {@link FollowLinkConfig},
+   * to automatically resolve {@link HALLink}s of the {@link ItemType}
+   * @param href            The url of the {@link ItemType} we want to retrieve
+   * @param linksToFollow   List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved
+   */
+  findByAllHref(href: string, findListOptions: FindListOptions = {}, ...linksToFollow: Array<FollowLinkConfig<ItemType>>): Observable<RemoteData<PaginatedList<ItemType>>> {
+    return this.dataService.findAllByHref(href, findListOptions, ...linksToFollow);
+  }
+}
+/* tslint:enable:max-classes-per-file */
diff --git a/src/app/core/data/entity-type.service.ts b/src/app/core/data/entity-type.service.ts
index 583601d898d4f771cb10a53c00409986409ff93d..b8e8b7cd9a3f1ad63e59369307ef3af9fd0d13f3 100644
--- a/src/app/core/data/entity-type.service.ts
+++ b/src/app/core/data/entity-type.service.ts
@@ -1,7 +1,7 @@
+import { FollowLinkConfig } from '../../shared/utils/follow-link-config.model';
 import { DataService } from './data.service';
 import { RequestService } from './request.service';
 import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
-import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service';
 import { Store } from '@ngrx/store';
 import { CoreState } from '../core.reducers';
 import { HALEndpointService } from '../shared/hal-endpoint.service';
@@ -25,11 +25,9 @@ import {ItemType} from '../shared/item-relationships/item-type.model';
 export class EntityTypeService extends DataService<ItemType> {
 
   protected linkPath = 'entitytypes';
-  protected forceBypassCache = false;
 
   constructor(protected requestService: RequestService,
               protected rdbService: RemoteDataBuildService,
-              protected dataBuildService: NormalizedObjectBuildService,
               protected store: Store<CoreState>,
               protected halService: HALEndpointService,
               protected objectCache: ObjectCacheService,
@@ -56,8 +54,9 @@ export class EntityTypeService extends DataService<ItemType> {
   /**
    * Get the allowed relationship types for an entity type
    * @param entityTypeId
+   * @param linksToFollow     List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved
    */
-  getEntityTypeRelationships(entityTypeId: string): Observable<RemoteData<PaginatedList<RelationshipType>>> {
+  getEntityTypeRelationships(entityTypeId: string, ...linksToFollow: Array<FollowLinkConfig<RelationshipType>>): Observable<RemoteData<PaginatedList<RelationshipType>>> {
 
     const href$ = this.getRelationshipTypesEndpoint(entityTypeId);
 
@@ -66,7 +65,7 @@ export class EntityTypeService extends DataService<ItemType> {
       this.requestService.configure(request);
     });
 
-    return this.rdbService.buildList(href$);
+    return this.rdbService.buildList(href$, ...linksToFollow);
   }
 
   /**
diff --git a/src/app/core/data/external-source.service.spec.ts b/src/app/core/data/external-source.service.spec.ts
index 77a2a85dfd4f548619327275eceb01907172799e..f891b46883e49fa268fe5188d361363f93a4ba47 100644
--- a/src/app/core/data/external-source.service.spec.ts
+++ b/src/app/core/data/external-source.service.spec.ts
@@ -49,7 +49,7 @@ describe('ExternalSourceService', () => {
     halService = jasmine.createSpyObj('halService', {
       getEndpoint: observableOf('external-sources-REST-endpoint')
     });
-    service = new ExternalSourceService(requestService, rdbService, undefined, undefined, undefined, halService, undefined, undefined, undefined);
+    service = new ExternalSourceService(requestService, rdbService, undefined, undefined, halService, undefined, undefined, undefined);
   }
 
   beforeEach(() => {
diff --git a/src/app/core/data/external-source.service.ts b/src/app/core/data/external-source.service.ts
index c32c13a20fdbe39a0ab853fbcfc534dacb902480..0c1a8d255c385337893d7f64d150f1fbb68f6174 100644
--- a/src/app/core/data/external-source.service.ts
+++ b/src/app/core/data/external-source.service.ts
@@ -3,7 +3,6 @@ import { DataService } from './data.service';
 import { ExternalSource } from '../shared/external-source.model';
 import { RequestService } from './request.service';
 import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
-import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service';
 import { Store } from '@ngrx/store';
 import { CoreState } from '../core.reducers';
 import { ObjectCacheService } from '../cache/object-cache.service';
@@ -31,7 +30,6 @@ export class ExternalSourceService extends DataService<ExternalSource> {
   constructor(
     protected requestService: RequestService,
     protected rdbService: RemoteDataBuildService,
-    protected dataBuildService: NormalizedObjectBuildService,
     protected store: Store<CoreState>,
     protected objectCache: ObjectCacheService,
     protected halService: HALEndpointService,
diff --git a/src/app/core/data/facet-config-response-parsing.service.ts b/src/app/core/data/facet-config-response-parsing.service.ts
index 19b37f8b5d0acd9ab44393036b25bfc4f487937a..3fc14b6495dad4ce121ac96745babdab4aa6abcd 100644
--- a/src/app/core/data/facet-config-response-parsing.service.ts
+++ b/src/app/core/data/facet-config-response-parsing.service.ts
@@ -1,17 +1,14 @@
 import { Inject, Injectable } from '@angular/core';
-import {
-  FacetConfigSuccessResponse,
-  RestResponse
-} from '../cache/response.models';
-import { ResponseParsingService } from './parsing.service';
-import { RestRequest } from './request.models';
-import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
-import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer';
+import { GLOBAL_CONFIG } from '../../../config';
+import { GlobalConfig } from '../../../config/global-config.interface';
 import { SearchFilterConfig } from '../../shared/search/search-filter-config.model';
-import { BaseResponseParsingService } from './base-response-parsing.service';
 import { ObjectCacheService } from '../cache/object-cache.service';
-import { GlobalConfig } from '../../../config/global-config.interface';
-import { GLOBAL_CONFIG } from '../../../config';
+import { FacetConfigSuccessResponse, RestResponse } from '../cache/response.models';
+import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
+import { DSpaceSerializer } from '../dspace-rest-v2/dspace.serializer';
+import { BaseResponseParsingService } from './base-response-parsing.service';
+import { ResponseParsingService } from './parsing.service';
+import { RestRequest } from './request.models';
 
 @Injectable()
 export class FacetConfigResponseParsingService extends BaseResponseParsingService implements ResponseParsingService {
@@ -24,7 +21,7 @@ export class FacetConfigResponseParsingService extends BaseResponseParsingServic
   parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse {
 
     const config = data.payload._embedded.facets;
-    const serializer = new DSpaceRESTv2Serializer(SearchFilterConfig);
+    const serializer = new DSpaceSerializer(SearchFilterConfig);
     const facetConfig = serializer.deserializeArray(config);
     return new FacetConfigSuccessResponse(facetConfig, data.statusCode, data.statusText);
   }
diff --git a/src/app/core/data/facet-value-map-response-parsing.service.ts b/src/app/core/data/facet-value-map-response-parsing.service.ts
index 64c8e87e7dc8046fb3305e94564622acf992bd8a..8c8c12dff76eefa3f759023769bd546f0c524ba2 100644
--- a/src/app/core/data/facet-value-map-response-parsing.service.ts
+++ b/src/app/core/data/facet-value-map-response-parsing.service.ts
@@ -1,19 +1,19 @@
 import { Inject, Injectable } from '@angular/core';
+import { GLOBAL_CONFIG } from '../../../config';
+import { GlobalConfig } from '../../../config/global-config.interface';
+import { FacetValue } from '../../shared/search/facet-value.model';
+import { ObjectCacheService } from '../cache/object-cache.service';
 import {
   FacetValueMap,
   FacetValueMapSuccessResponse,
   FacetValueSuccessResponse,
   RestResponse
 } from '../cache/response.models';
-import { ResponseParsingService } from './parsing.service';
-import { RestRequest } from './request.models';
 import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
-import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer';
-import { FacetValue } from '../../shared/search/facet-value.model';
+import { DSpaceSerializer } from '../dspace-rest-v2/dspace.serializer';
 import { BaseResponseParsingService } from './base-response-parsing.service';
-import { ObjectCacheService } from '../cache/object-cache.service';
-import { GlobalConfig } from '../../../config/global-config.interface';
-import { GLOBAL_CONFIG } from '../../../config';
+import { ResponseParsingService } from './parsing.service';
+import { RestRequest } from './request.models';
 
 @Injectable()
 export class FacetValueMapResponseParsingService extends BaseResponseParsingService implements ResponseParsingService {
@@ -30,7 +30,7 @@ export class FacetValueMapResponseParsingService extends BaseResponseParsingServ
     const payload = data.payload;
     const facetMap: FacetValueMap = new FacetValueMap();
 
-    const serializer = new DSpaceRESTv2Serializer(FacetValue);
+    const serializer = new DSpaceSerializer(FacetValue);
     payload._embedded.facets.map((facet) => {
       const values = facet._embedded.values.map((value) => {value.search = value._links.search.href; return value;});
       const facetValues = serializer.deserializeArray(values);
diff --git a/src/app/core/data/facet-value-response-parsing.service.ts b/src/app/core/data/facet-value-response-parsing.service.ts
index 7fedc17545f3441428ec3c3d88ed449b84c99b53..c9ff93a1ae00af5208472d27bfe1f4095a012e61 100644
--- a/src/app/core/data/facet-value-response-parsing.service.ts
+++ b/src/app/core/data/facet-value-response-parsing.service.ts
@@ -1,14 +1,14 @@
 import { Inject, Injectable } from '@angular/core';
+import { GLOBAL_CONFIG } from '../../../config';
+import { GlobalConfig } from '../../../config/global-config.interface';
+import { FacetValue } from '../../shared/search/facet-value.model';
+import { ObjectCacheService } from '../cache/object-cache.service';
 import { FacetValueSuccessResponse, RestResponse } from '../cache/response.models';
-import { ResponseParsingService } from './parsing.service';
-import { RestRequest } from './request.models';
 import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
-import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer';
-import {FacetValue} from '../../shared/search/facet-value.model';
+import { DSpaceSerializer } from '../dspace-rest-v2/dspace.serializer';
 import { BaseResponseParsingService } from './base-response-parsing.service';
-import { ObjectCacheService } from '../cache/object-cache.service';
-import { GLOBAL_CONFIG } from '../../../config';
-import { GlobalConfig } from '../../../config/global-config.interface';
+import { ResponseParsingService } from './parsing.service';
+import { RestRequest } from './request.models';
 
 @Injectable()
 export class FacetValueResponseParsingService extends BaseResponseParsingService implements ResponseParsingService {
@@ -21,7 +21,7 @@ export class FacetValueResponseParsingService extends BaseResponseParsingService
   parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse {
     const payload = data.payload;
 
-    const serializer = new DSpaceRESTv2Serializer(FacetValue);
+    const serializer = new DSpaceSerializer(FacetValue);
     // const values = payload._embedded.values.map((value) => {value.search = value._links.search.href; return value;});
 
     const facetValues = serializer.deserializeArray(payload._embedded.values);
diff --git a/src/app/core/data/item-data.service.spec.ts b/src/app/core/data/item-data.service.spec.ts
index 8263601e28fd480a85940f930e6c24b8ed0e60c7..06adfd51433862105b57611add7f9ec79038fc0c 100644
--- a/src/app/core/data/item-data.service.spec.ts
+++ b/src/app/core/data/item-data.service.spec.ts
@@ -1,21 +1,20 @@
+import { HttpClient } from '@angular/common/http';
 import { Store } from '@ngrx/store';
 import { cold, getTestScheduler } from 'jasmine-marbles';
+import { Observable, of as observableOf } from 'rxjs';
 import { TestScheduler } from 'rxjs/testing';
+import { getMockRequestService } from '../../shared/mocks/mock-request.service';
+import { NotificationsService } from '../../shared/notifications/notifications.service';
 import { BrowseService } from '../browse/browse.service';
+import { ObjectCacheService } from '../cache/object-cache.service';
+import { RestResponse } from '../cache/response.models';
 import { CoreState } from '../core.reducers';
-import { ItemDataService } from './item-data.service';
-import { RequestService } from './request.service';
+import { ExternalSourceEntry } from '../shared/external-source-entry.model';
 import { HALEndpointService } from '../shared/hal-endpoint.service';
+import { ItemDataService } from './item-data.service';
 import { DeleteRequest, FindListOptions, PostRequest, RestRequest } from './request.models';
-import { ObjectCacheService } from '../cache/object-cache.service';
-import { Observable, of as observableOf } from 'rxjs';
-import { RestResponse } from '../cache/response.models';
-import { NotificationsService } from '../../shared/notifications/notifications.service';
-import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service';
-import { HttpClient } from '@angular/common/http';
 import { RequestEntry } from './request.reducer';
-import { getMockRequestService } from '../../shared/mocks/mock-request.service';
-import { ExternalSourceEntry } from '../shared/external-source-entry.model';
+import { RequestService } from './request.service';
 
 describe('ItemDataService', () => {
   let scheduler: TestScheduler;
@@ -45,7 +44,7 @@ describe('ItemDataService', () => {
   const objectCache = {} as ObjectCacheService;
   const halEndpointService = {
     getEndpoint(linkPath: string): Observable<string> {
-      return cold('a', {a: itemEndpoint});
+      return cold('a', { a: itemEndpoint });
     }
   } as HALEndpointService;
 
@@ -66,7 +65,6 @@ describe('ItemDataService', () => {
   const notificationsService = {} as NotificationsService;
   const http = {} as HttpClient;
   const comparator = {} as any;
-  const dataBuildService = {} as NormalizedObjectBuildService;
   const itemEndpoint = 'https://rest.api/core/items';
   const ScopedItemEndpoint = `https://rest.api/core/items/${scopeID}`;
 
@@ -83,7 +81,6 @@ describe('ItemDataService', () => {
     return new ItemDataService(
       requestService,
       rdbService,
-      dataBuildService,
       store,
       bs,
       objectCache,
@@ -132,7 +129,7 @@ describe('ItemDataService', () => {
 
     it('should return the endpoint to withdraw and reinstate items', () => {
       const result = service.getItemWithdrawEndpoint(scopeID);
-      const expected = cold('a', {a: ScopedItemEndpoint});
+      const expected = cold('a', { a: ScopedItemEndpoint });
 
       expect(result).toBeObservable(expected);
     });
@@ -154,7 +151,7 @@ describe('ItemDataService', () => {
 
     it('should return the endpoint to make an item private or public', () => {
       const result = service.getItemDiscoverableEndpoint(scopeID);
-      const expected = cold('a', {a: ScopedItemEndpoint});
+      const expected = cold('a', { a: ScopedItemEndpoint });
 
       expect(result).toBeObservable(expected);
     });
@@ -201,7 +198,7 @@ describe('ItemDataService', () => {
     const externalSourceEntry = Object.assign(new ExternalSourceEntry(), {
       display: 'John, Doe',
       value: 'John, Doe',
-      self: 'http://test-rest.com/server/api/integration/externalSources/orcidV2/entryValues/0000-0003-4851-8004'
+      _links: { self: { href: 'http://test-rest.com/server/api/integration/externalSources/orcidV2/entryValues/0000-0003-4851-8004' } }
     });
 
     beforeEach(() => {
diff --git a/src/app/core/data/item-data.service.ts b/src/app/core/data/item-data.service.ts
index 8e48bc62f9ce8bd1938d4dc338f988a6930059a8..c9fb378bc633fa2aa81be67698e0dc6bd20d19d7 100644
--- a/src/app/core/data/item-data.service.ts
+++ b/src/app/core/data/item-data.service.ts
@@ -1,17 +1,34 @@
-import { distinctUntilChanged, filter, find, map, switchMap, take } from 'rxjs/operators';
+import { HttpClient, HttpHeaders } from '@angular/common/http';
 import { Injectable } from '@angular/core';
 import { Store } from '@ngrx/store';
 import { Observable } from 'rxjs';
+import { distinctUntilChanged, filter, find, map, switchMap, take } from 'rxjs/operators';
 import { hasValue, isNotEmpty, isNotEmptyOperator } from '../../shared/empty.util';
+import { NotificationsService } from '../../shared/notifications/notifications.service';
 import { BrowseService } from '../browse/browse.service';
+import { dataService } from '../cache/builders/build-decorators';
 import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
+import { ObjectCacheService } from '../cache/object-cache.service';
+import { GenericSuccessResponse, RestResponse } from '../cache/response.models';
 import { CoreState } from '../core.reducers';
+import { HttpOptions } from '../dspace-rest-v2/dspace-rest-v2.service';
+import { Collection } from '../shared/collection.model';
+import { ExternalSourceEntry } from '../shared/external-source-entry.model';
+import { HALEndpointService } from '../shared/hal-endpoint.service';
 import { Item } from '../shared/item.model';
+import { ITEM } from '../shared/item.resource-type';
+import {
+  configureRequest,
+  filterSuccessfulResponses,
+  getRequestFromRequestHref,
+  getResponseFromEntry
+} from '../shared/operators';
 import { URLCombiner } from '../url-combiner/url-combiner';
 
 import { DataService } from './data.service';
-import { RequestService } from './request.service';
-import { HALEndpointService } from '../shared/hal-endpoint.service';
+import { DSOChangeAnalyzer } from './dso-change-analyzer.service';
+import { PaginatedList } from './paginated-list';
+import { RemoteData } from './remote-data';
 import {
   DeleteRequest,
   FindListOptions,
@@ -22,43 +39,27 @@ import {
   PutRequest,
   RestRequest
 } from './request.models';
-import { ObjectCacheService } from '../cache/object-cache.service';
-import { NotificationsService } from '../../shared/notifications/notifications.service';
-import { DSOChangeAnalyzer } from './dso-change-analyzer.service';
-import { HttpClient, HttpHeaders } from '@angular/common/http';
-import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service';
-import {
-  configureRequest,
-  filterSuccessfulResponses,
-  getRequestFromRequestHref,
-  getResponseFromEntry
-} from '../shared/operators';
 import { RequestEntry } from './request.reducer';
-import { GenericSuccessResponse, RestResponse } from '../cache/response.models';
-import { HttpOptions } from '../dspace-rest-v2/dspace-rest-v2.service';
-import { Collection } from '../shared/collection.model';
-import { RemoteData } from './remote-data';
-import { PaginatedList } from './paginated-list';
-import { Bitstream } from '../shared/bitstream.model';
-import { Bundle } from '../shared/bundle.model';
-import { ExternalSourceEntry } from '../shared/external-source-entry.model';
+import { RequestService } from './request.service';
 import { PaginatedSearchOptions } from '../../shared/search/paginated-search-options.model';
+import { Bundle } from '../shared/bundle.model';
 
 @Injectable()
+@dataService(ITEM)
 export class ItemDataService extends DataService<Item> {
   protected linkPath = 'items';
 
   constructor(
     protected requestService: RequestService,
     protected rdbService: RemoteDataBuildService,
-    protected dataBuildService: NormalizedObjectBuildService,
     protected store: Store<CoreState>,
     private bs: BrowseService,
     protected objectCache: ObjectCacheService,
     protected halService: HALEndpointService,
     protected notificationsService: NotificationsService,
     protected http: HttpClient,
-    protected comparator: DSOChangeAnalyzer<Item>) {
+    protected comparator: DSOChangeAnalyzer<Item>,
+  ) {
     super();
   }
 
@@ -272,7 +273,7 @@ export class ItemDataService extends DataService<Item> {
     hrefObs.pipe(
       find((href: string) => hasValue(href)),
       map((href: string) => {
-        const request = new PutRequest(requestId, href, collection.self, options);
+        const request = new PutRequest(requestId, href, collection._links.self.href, options);
         this.requestService.configure(request);
       })
     ).subscribe();
@@ -300,7 +301,7 @@ export class ItemDataService extends DataService<Item> {
     href$.pipe(
       find((href: string) => hasValue(href)),
       map((href: string) => {
-        const request = new PostRequest(requestId, href, externalSourceEntry.self, options);
+        const request = new PostRequest(requestId, href, externalSourceEntry._links.self.href, options);
         this.requestService.configure(request);
       })
     ).subscribe();
diff --git a/src/app/core/data/license-data.service.ts b/src/app/core/data/license-data.service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..23637be596803f856f7cc84ad058af03cd0807d3
--- /dev/null
+++ b/src/app/core/data/license-data.service.ts
@@ -0,0 +1,85 @@
+import { HttpClient } from '@angular/common/http';
+import { Injectable } from '@angular/core';
+import { Store } from '@ngrx/store';
+import { Observable } from 'rxjs';
+import { NotificationsService } from '../../shared/notifications/notifications.service';
+import { FollowLinkConfig } from '../../shared/utils/follow-link-config.model';
+import { dataService } from '../cache/builders/build-decorators';
+import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
+import { ObjectCacheService } from '../cache/object-cache.service';
+import { CoreState } from '../core.reducers';
+import { HALEndpointService } from '../shared/hal-endpoint.service';
+import { License } from '../shared/license.model';
+import { LICENSE } from '../shared/license.resource-type';
+import { DataService } from './data.service';
+import { DefaultChangeAnalyzer } from './default-change-analyzer.service';
+import { PaginatedList } from './paginated-list';
+import { RemoteData } from './remote-data';
+import { FindListOptions } from './request.models';
+import { RequestService } from './request.service';
+
+/* tslint:disable:max-classes-per-file */
+
+/**
+ * A private DataService implementation to delegate specific methods to.
+ */
+class DataServiceImpl extends DataService<License> {
+  protected linkPath = '';
+
+  constructor(
+    protected requestService: RequestService,
+    protected rdbService: RemoteDataBuildService,
+    protected store: Store<CoreState>,
+    protected objectCache: ObjectCacheService,
+    protected halService: HALEndpointService,
+    protected notificationsService: NotificationsService,
+    protected http: HttpClient,
+    protected comparator: DefaultChangeAnalyzer<License>) {
+    super();
+  }
+}
+
+/**
+ * A service to retrieve {@link License}s from the REST API.
+ */
+@Injectable()
+@dataService(LICENSE)
+export class LicenseDataService {
+  /**
+   * A private DataService instance to delegate specific methods to.
+   */
+  private dataService: DataServiceImpl;
+
+  constructor(
+    protected requestService: RequestService,
+    protected rdbService: RemoteDataBuildService,
+    protected store: Store<CoreState>,
+    protected objectCache: ObjectCacheService,
+    protected halService: HALEndpointService,
+    protected notificationsService: NotificationsService,
+    protected http: HttpClient,
+    protected comparator: DefaultChangeAnalyzer<License>) {
+    this.dataService = new DataServiceImpl(requestService, rdbService, null, objectCache, halService, notificationsService, http, comparator);
+  }
+
+  /**
+   * Returns an observable of {@link RemoteData} of a {@link License}, based on an href, with a list of {@link FollowLinkConfig},
+   * to automatically resolve {@link HALLink}s of the {@link License}
+   * @param href            The URL of object we want to retrieve
+   * @param linksToFollow   List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved
+   */
+  findByHref(href: string, ...linksToFollow: Array<FollowLinkConfig<License>>): Observable<RemoteData<License>> {
+    return this.dataService.findByHref(href, ...linksToFollow);
+  }
+
+  /**
+   * Returns a list of observables of {@link RemoteData} of {@link License}s, based on an href, with a list of {@link FollowLinkConfig},
+   * to automatically resolve {@link HALLink}s of the {@link License}
+   * @param href            The URL of object we want to retrieve
+   * @param linksToFollow   List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved
+   */
+  findByAllHref(href: string, findListOptions: FindListOptions = {}, ...linksToFollow: Array<FollowLinkConfig<License>>): Observable<RemoteData<PaginatedList<License>>> {
+    return this.dataService.findAllByHref(href, findListOptions, ...linksToFollow);
+  }
+}
+/* tslint:enable:max-classes-per-file */
diff --git a/src/app/core/data/metadata-schema-data.service.ts b/src/app/core/data/metadata-schema-data.service.ts
index 662eaa6c7c31e23f04c5bc4a798b36a20bd78dd5..915f5883799fcf55942ba77433d4c8a4e0e15748 100644
--- a/src/app/core/data/metadata-schema-data.service.ts
+++ b/src/app/core/data/metadata-schema-data.service.ts
@@ -1,20 +1,19 @@
+import { HttpClient } from '@angular/common/http';
 import { Injectable } from '@angular/core';
 import { Store } from '@ngrx/store';
-import { Observable } from 'rxjs';
+import { NotificationsService } from '../../shared/notifications/notifications.service';
+import { dataService } from '../cache/builders/build-decorators';
 import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
+import { ObjectCacheService } from '../cache/object-cache.service';
 import { CoreState } from '../core.reducers';
-
-import { DataService } from './data.service';
-import { RequestService } from './request.service';
+import { MetadataSchema } from '../metadata/metadata-schema.model';
+import { METADATA_SCHEMA } from '../metadata/metadata-schema.resource-type';
 import { HALEndpointService } from '../shared/hal-endpoint.service';
-import { FindListOptions } from './request.models';
-import { ObjectCacheService } from '../cache/object-cache.service';
-import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service';
-import { HttpClient } from '@angular/common/http';
-import { NotificationsService } from '../../shared/notifications/notifications.service';
 import { ChangeAnalyzer } from './change-analyzer';
+
+import { DataService } from './data.service';
 import { DefaultChangeAnalyzer } from './default-change-analyzer.service';
-import { MetadataSchema } from '../metadata/metadata-schema.model';
+import { RequestService } from './request.service';
 
 /* tslint:disable:max-classes-per-file */
 class DataServiceImpl extends DataService<MetadataSchema> {
@@ -23,7 +22,6 @@ class DataServiceImpl extends DataService<MetadataSchema> {
   constructor(
     protected requestService: RequestService,
     protected rdbService: RemoteDataBuildService,
-    protected dataBuildService: NormalizedObjectBuildService,
     protected store: Store<CoreState>,
     protected objectCache: ObjectCacheService,
     protected halService: HALEndpointService,
@@ -33,15 +31,13 @@ class DataServiceImpl extends DataService<MetadataSchema> {
     super();
   }
 
-  getBrowseEndpoint(options: FindListOptions = {}, linkPath: string = this.linkPath): Observable<string> {
-    return this.halService.getEndpoint(linkPath);
-  }
 }
 
 /**
  * A service responsible for fetching/sending data from/to the REST API on the metadataschemas endpoint
  */
 @Injectable()
+@dataService(METADATA_SCHEMA)
 export class MetadataSchemaDataService {
   private dataService: DataServiceImpl;
 
@@ -52,9 +48,8 @@ export class MetadataSchemaDataService {
     protected halService: HALEndpointService,
     protected objectCache: ObjectCacheService,
     protected comparator: DefaultChangeAnalyzer<MetadataSchema>,
-    protected dataBuildService: NormalizedObjectBuildService,
     protected http: HttpClient,
     protected notificationsService: NotificationsService) {
-    this.dataService = new DataServiceImpl(requestService, rdbService, dataBuildService, null, objectCache, halService, notificationsService, http, comparator);
+    this.dataService = new DataServiceImpl(requestService, rdbService, null, objectCache, halService, notificationsService, http, comparator);
   }
 }
diff --git a/src/app/core/data/metadatafield-parsing.service.ts b/src/app/core/data/metadatafield-parsing.service.ts
index 092285e9c502e722d820377411e7d24304e9ee44..08f7892ac75a6ec4be4f1594395ca2e436c51304 100644
--- a/src/app/core/data/metadatafield-parsing.service.ts
+++ b/src/app/core/data/metadatafield-parsing.service.ts
@@ -1,10 +1,10 @@
-import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer';
-import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
-import { RestRequest } from './request.models';
-import { ResponseParsingService } from './parsing.service';
 import { Injectable } from '@angular/core';
 import { MetadatafieldSuccessResponse, RestResponse } from '../cache/response.models';
+import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
+import { DSpaceSerializer } from '../dspace-rest-v2/dspace.serializer';
 import { MetadataField } from '../metadata/metadata-field.model';
+import { ResponseParsingService } from './parsing.service';
+import { RestRequest } from './request.models';
 
 /**
  * A service responsible for parsing DSpaceRESTV2Response data related to a single MetadataField to a valid RestResponse
@@ -15,7 +15,7 @@ export class MetadatafieldParsingService implements ResponseParsingService {
   parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse {
     const payload = data.payload;
 
-    const deserialized = new DSpaceRESTv2Serializer(MetadataField).deserialize(payload);
+    const deserialized = new DSpaceSerializer(MetadataField).deserialize(payload);
     return new MetadatafieldSuccessResponse(deserialized, data.statusCode, data.statusText);
   }
 
diff --git a/src/app/core/data/metadataschema-parsing.service.ts b/src/app/core/data/metadataschema-parsing.service.ts
index 3e9fd257bb03579326baf206dfbddc7d84fb22d1..f4b90e5dcde5d623a60c45ce3895397b55cf6ccd 100644
--- a/src/app/core/data/metadataschema-parsing.service.ts
+++ b/src/app/core/data/metadataschema-parsing.service.ts
@@ -1,10 +1,10 @@
-import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer';
-import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
-import { RestRequest } from './request.models';
-import { ResponseParsingService } from './parsing.service';
 import { Injectable } from '@angular/core';
 import { MetadataschemaSuccessResponse, RestResponse } from '../cache/response.models';
+import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
+import { DSpaceSerializer } from '../dspace-rest-v2/dspace.serializer';
 import { MetadataSchema } from '../metadata/metadata-schema.model';
+import { ResponseParsingService } from './parsing.service';
+import { RestRequest } from './request.models';
 
 @Injectable()
 export class MetadataschemaParsingService implements ResponseParsingService {
@@ -12,7 +12,7 @@ export class MetadataschemaParsingService implements ResponseParsingService {
   parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse {
     const payload = data.payload;
 
-    const deserialized = new DSpaceRESTv2Serializer(MetadataSchema).deserialize(payload);
+    const deserialized = new DSpaceSerializer(MetadataSchema).deserialize(payload);
     return new MetadataschemaSuccessResponse(deserialized, data.statusCode, data.statusText);
   }
 
diff --git a/src/app/core/data/mydspace-response-parsing.service.ts b/src/app/core/data/mydspace-response-parsing.service.ts
index bd5d5b1083ea32f81ae9e32899c26a3e329899aa..062bafab46a567a883e77db2d4ff99df720ef259 100644
--- a/src/app/core/data/mydspace-response-parsing.service.ts
+++ b/src/app/core/data/mydspace-response-parsing.service.ts
@@ -1,10 +1,10 @@
 import { Injectable } from '@angular/core';
 import { RestResponse, SearchSuccessResponse } from '../cache/response.models';
+import { DSpaceSerializer } from '../dspace-rest-v2/dspace.serializer';
 import { DSOResponseParsingService } from './dso-response-parsing.service';
 import { ResponseParsingService } from './parsing.service';
 import { RestRequest } from './request.models';
 import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
-import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer';
 import { hasValue } from '../../shared/empty.util';
 import { SearchQueryResponse } from '../../shared/search/search-query-response.model';
 import { MetadataMap, MetadataValue } from '../shared/metadata.models';
@@ -57,7 +57,7 @@ export class MyDSpaceResponseParsingService implements ResponseParsingService {
         _embedded: this.filterEmbeddedObjects(object)
       }));
     payload.objects = objects;
-    const deserialized = new DSpaceRESTv2Serializer(SearchQueryResponse).deserialize(payload);
+    const deserialized = new DSpaceSerializer(SearchQueryResponse).deserialize(payload);
     return new SearchSuccessResponse(deserialized, data.statusCode, data.statusText, this.dsoParser.processPageInfo(payload));
   }
 
diff --git a/src/app/core/data/object-updates/object-updates.actions.ts b/src/app/core/data/object-updates/object-updates.actions.ts
index 868496b0794ea93ce48e33f84d204d091e2407a7..94918157eecfccf0dc8862ec05a8900e61b97fc8 100644
--- a/src/app/core/data/object-updates/object-updates.actions.ts
+++ b/src/app/core/data/object-updates/object-updates.actions.ts
@@ -371,4 +371,7 @@ export type ObjectUpdatesAction
   | RemoveFieldUpdateAction
   | MoveFieldUpdateAction
   | AddPageToCustomOrderAction
-  | SelectVirtualMetadataAction;
+  | RemoveAllObjectUpdatesAction
+  | SelectVirtualMetadataAction
+  | SetEditableFieldUpdateAction
+  | SetValidFieldUpdateAction;
diff --git a/src/app/core/data/object-updates/object-updates.effects.ts b/src/app/core/data/object-updates/object-updates.effects.ts
index c115939576fa724274818f9dd3d7668b48242ed7..239fee9477468eec37cb387d7bc48e9c30c937a6 100644
--- a/src/app/core/data/object-updates/object-updates.effects.ts
+++ b/src/app/core/data/object-updates/object-updates.effects.ts
@@ -54,8 +54,8 @@ export class ObjectUpdatesEffects {
     .pipe(
       ofType(...Object.values(ObjectUpdatesActionTypes)),
       map((action: ObjectUpdatesAction) => {
-        if (hasValue(action.payload)) {
-          const url: string = action.payload.url;
+        if (hasValue((action as any).payload)) {
+          const url: string = (action as any).payload.url;
           if (hasNoValue(this.actionMap$[url])) {
             this.actionMap$[url] = new Subject<ObjectUpdatesAction>();
           }
diff --git a/src/app/core/data/paginated-list.ts b/src/app/core/data/paginated-list.ts
index b9de67a34d90d04697830d30d1fa1996ff03a979..9f05ca78890e8e86b7a6a141980e12cacb5eaa11 100644
--- a/src/app/core/data/paginated-list.ts
+++ b/src/app/core/data/paginated-list.ts
@@ -56,14 +56,14 @@ export class PaginatedList<T> {
   }
 
   set first(first: string) {
-    this.pageInfo.first = first;
+    this.pageInfo._links.first = { href: first };
   }
 
   get prev(): string {
     return this.pageInfo.prev;
   }
   set prev(prev: string) {
-    this.pageInfo.prev = prev;
+    this.pageInfo._links.prev = { href: prev };
   }
 
   get next(): string {
@@ -71,7 +71,7 @@ export class PaginatedList<T> {
   }
 
   set next(next: string) {
-    this.pageInfo.next = next;
+    this.pageInfo._links.next = { href: next };
   }
 
   get last(): string {
@@ -79,7 +79,7 @@ export class PaginatedList<T> {
   }
 
   set last(last: string) {
-    this.pageInfo.last = last;
+    this.pageInfo._links.last = { href: last };
   }
 
   get self(): string {
@@ -87,7 +87,7 @@ export class PaginatedList<T> {
   }
 
   set self(self: string) {
-    this.pageInfo.self = self;
+    this.pageInfo._links.self = { href: self };
   }
 
   protected getPageLength() {
diff --git a/src/app/core/data/registry-bitstreamformats-response-parsing.service.ts b/src/app/core/data/registry-bitstreamformats-response-parsing.service.ts
index 899fee4d1e166d07319c56653d8f66a5c4620320..1cbcf358e3466488023cf1301dea03e72eef710a 100644
--- a/src/app/core/data/registry-bitstreamformats-response-parsing.service.ts
+++ b/src/app/core/data/registry-bitstreamformats-response-parsing.service.ts
@@ -1,11 +1,11 @@
+import { Injectable } from '@angular/core';
 import { RegistryBitstreamformatsSuccessResponse, RestResponse } from '../cache/response.models';
-import { RegistryBitstreamformatsResponse } from '../registry/registry-bitstreamformats-response.model';
-import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer';
 import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
-import { RestRequest } from './request.models';
+import { DSpaceSerializer } from '../dspace-rest-v2/dspace.serializer';
+import { RegistryBitstreamformatsResponse } from '../registry/registry-bitstreamformats-response.model';
 import { DSOResponseParsingService } from './dso-response-parsing.service';
 import { ResponseParsingService } from './parsing.service';
-import { Injectable } from '@angular/core';
+import { RestRequest } from './request.models';
 
 @Injectable()
 export class RegistryBitstreamformatsResponseParsingService implements ResponseParsingService {
@@ -18,7 +18,7 @@ export class RegistryBitstreamformatsResponseParsingService implements ResponseP
     const bitstreamformats = payload._embedded.bitstreamformats;
     payload.bitstreamformats = bitstreamformats;
 
-    const deserialized = new DSpaceRESTv2Serializer(RegistryBitstreamformatsResponse).deserialize(payload);
+    const deserialized = new DSpaceSerializer(RegistryBitstreamformatsResponse).deserialize(payload);
     return new RegistryBitstreamformatsSuccessResponse(deserialized, data.statusCode, data.statusText, this.dsoParser.processPageInfo(data.payload.page));
   }
 
diff --git a/src/app/core/data/registry-metadatafields-response-parsing.service.ts b/src/app/core/data/registry-metadatafields-response-parsing.service.ts
index a4bed3240e8af03b5973a8f45167b75605c406c4..cf9484c4c4a76023b82aee84b47b856f42ce8d5f 100644
--- a/src/app/core/data/registry-metadatafields-response-parsing.service.ts
+++ b/src/app/core/data/registry-metadatafields-response-parsing.service.ts
@@ -1,15 +1,12 @@
-import {
-  RegistryMetadatafieldsSuccessResponse,
-  RestResponse
-} from '../cache/response.models';
-import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
-import { RestRequest } from './request.models';
-import { ResponseParsingService } from './parsing.service';
-import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer';
-import { DSOResponseParsingService } from './dso-response-parsing.service';
 import { Injectable } from '@angular/core';
-import { RegistryMetadatafieldsResponse } from '../registry/registry-metadatafields-response.model';
 import { hasValue } from '../../shared/empty.util';
+import { RegistryMetadatafieldsSuccessResponse, RestResponse } from '../cache/response.models';
+import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
+import { DSpaceSerializer } from '../dspace-rest-v2/dspace.serializer';
+import { RegistryMetadatafieldsResponse } from '../registry/registry-metadatafields-response.model';
+import { DSOResponseParsingService } from './dso-response-parsing.service';
+import { ResponseParsingService } from './parsing.service';
+import { RestRequest } from './request.models';
 
 @Injectable()
 export class RegistryMetadatafieldsResponseParsingService implements ResponseParsingService {
@@ -30,7 +27,7 @@ export class RegistryMetadatafieldsResponseParsingService implements ResponsePar
 
     payload.metadatafields = metadatafields;
 
-    const deserialized = new DSpaceRESTv2Serializer(RegistryMetadatafieldsResponse).deserialize(payload);
+    const deserialized = new DSpaceSerializer(RegistryMetadatafieldsResponse).deserialize(payload);
     return new RegistryMetadatafieldsSuccessResponse(deserialized, data.statusCode, data.statusText, this.dsoParser.processPageInfo(data.payload));
   }
 
diff --git a/src/app/core/data/registry-metadataschemas-response-parsing.service.ts b/src/app/core/data/registry-metadataschemas-response-parsing.service.ts
index d19b334131a9eb73c9f903a68ccae2299d948456..416ed19dc26c78664bec0ead0fd84c9955fa3739 100644
--- a/src/app/core/data/registry-metadataschemas-response-parsing.service.ts
+++ b/src/app/core/data/registry-metadataschemas-response-parsing.service.ts
@@ -1,12 +1,12 @@
+import { Injectable } from '@angular/core';
+import { hasValue } from '../../shared/empty.util';
 import { RegistryMetadataschemasSuccessResponse, RestResponse } from '../cache/response.models';
 import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
-import { RestRequest } from './request.models';
-import { ResponseParsingService } from './parsing.service';
+import { DSpaceSerializer } from '../dspace-rest-v2/dspace.serializer';
 import { RegistryMetadataschemasResponse } from '../registry/registry-metadataschemas-response.model';
-import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer';
 import { DSOResponseParsingService } from './dso-response-parsing.service';
-import { Injectable } from '@angular/core';
-import { hasValue } from '../../shared/empty.util';
+import { ResponseParsingService } from './parsing.service';
+import { RestRequest } from './request.models';
 
 @Injectable()
 export class RegistryMetadataschemasResponseParsingService implements ResponseParsingService {
@@ -22,7 +22,7 @@ export class RegistryMetadataschemasResponseParsingService implements ResponsePa
     }
     payload.metadataschemas = metadataschemas;
 
-    const deserialized = new DSpaceRESTv2Serializer(RegistryMetadataschemasResponse).deserialize(payload);
+    const deserialized = new DSpaceSerializer(RegistryMetadataschemasResponse).deserialize(payload);
     return new RegistryMetadataschemasSuccessResponse(deserialized, data.statusCode, data.statusText, this.dsoParser.processPageInfo(data.payload));
   }
 
diff --git a/src/app/core/data/relationship-type.service.spec.ts b/src/app/core/data/relationship-type.service.spec.ts
index 118baf87382f14492276b39d2f54c8ae70f24213..0a86b4bc61c5ee0b50fc78a20d20bbb8d33cf8af 100644
--- a/src/app/core/data/relationship-type.service.spec.ts
+++ b/src/app/core/data/relationship-type.service.spec.ts
@@ -1,14 +1,15 @@
-import { RequestService } from './request.service';
-import { HALEndpointServiceStub } from '../../shared/testing/hal-endpoint-service-stub';
+import { of as observableOf } from 'rxjs';
 import { getMockRemoteDataBuildService } from '../../shared/mocks/mock-remote-data-build.service';
-import { RelationshipType } from '../shared/item-relationships/relationship-type.model';
 import { getMockRequestService } from '../../shared/mocks/mock-request.service';
-import { PaginatedList } from './paginated-list';
-import { PageInfo } from '../shared/page-info.model';
+import { HALEndpointServiceStub } from '../../shared/testing/hal-endpoint-service-stub';
 import { createSuccessfulRemoteDataObject, createSuccessfulRemoteDataObject$ } from '../../shared/testing/utils';
-import { RelationshipTypeService } from './relationship-type.service';
-import { of as observableOf } from 'rxjs';
+import { ObjectCacheService } from '../cache/object-cache.service';
 import { ItemType } from '../shared/item-relationships/item-type.model';
+import { RelationshipType } from '../shared/item-relationships/relationship-type.model';
+import { PageInfo } from '../shared/page-info.model';
+import { PaginatedList } from './paginated-list';
+import { RelationshipTypeService } from './relationship-type.service';
+import { RequestService } from './request.service';
 
 describe('RelationshipTypeService', () => {
   let service: RelationshipTypeService;
@@ -25,8 +26,10 @@ describe('RelationshipTypeService', () => {
   let relationshipType1;
   let relationshipType2;
 
+  let itemService;
   let buildList;
   let rdbService;
+  let objectCache;
 
   function init() {
     restEndpointURL = 'https://rest.api/relationshiptypes';
@@ -58,13 +61,29 @@ describe('RelationshipTypeService', () => {
 
     buildList = createSuccessfulRemoteDataObject(new PaginatedList(new PageInfo(), [relationshipType1, relationshipType2]));
     rdbService = getMockRemoteDataBuildService(undefined, observableOf(buildList));
+    objectCache = Object.assign({
+      /* tslint:disable:no-empty */
+      remove: () => {
+      },
+      hasBySelfLinkObservable: () => observableOf(false)
+      /* tslint:enable:no-empty */
+    }) as ObjectCacheService;
+
+    itemService = undefined;
 
   }
   function initTestService() {
     return new RelationshipTypeService(
+      itemService,
       requestService,
+      rdbService,
+      null,
       halService,
-      rdbService
+      objectCache,
+      null,
+      null,
+      null,
+      null
     );
   }
 
diff --git a/src/app/core/data/relationship-type.service.ts b/src/app/core/data/relationship-type.service.ts
index 7978373b082998463bf1a0cdd2ddd91d29300e31..eefe663209b5d7c41e28f7e8131e4a65cec8f406 100644
--- a/src/app/core/data/relationship-type.service.ts
+++ b/src/app/core/data/relationship-type.service.ts
@@ -1,28 +1,49 @@
+import { HttpClient } from '@angular/common/http';
 import { Injectable } from '@angular/core';
-import { RequestService } from './request.service';
-import { HALEndpointService } from '../shared/hal-endpoint.service';
-import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
-import { filter, find, map, switchMap } from 'rxjs/operators';
-import { configureRequest, getSucceededRemoteData } from '../shared/operators';
+import { Store } from '@ngrx/store';
+import { combineLatest as observableCombineLatest } from 'rxjs';
 import { Observable } from 'rxjs/internal/Observable';
+import { filter, find, map, switchMap } from 'rxjs/operators';
+import { AppState } from '../../app.reducer';
+import { isNotUndefined } from '../../shared/empty.util';
+import { NotificationsService } from '../../shared/notifications/notifications.service';
+import { followLink } from '../../shared/utils/follow-link-config.model';
+import { dataService } from '../cache/builders/build-decorators';
+import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
+import { ObjectCacheService } from '../cache/object-cache.service';
+import { CoreState } from '../core.reducers';
+import { HALEndpointService } from '../shared/hal-endpoint.service';
+import { ItemType } from '../shared/item-relationships/item-type.model';
 import { RelationshipType } from '../shared/item-relationships/relationship-type.model';
-import { RemoteData } from './remote-data';
+import { RELATIONSHIP_TYPE } from '../shared/item-relationships/relationship-type.resource-type';
+import { configureRequest, getSucceededRemoteData } from '../shared/operators';
+import { DataService } from './data.service';
+import { DefaultChangeAnalyzer } from './default-change-analyzer.service';
+import { ItemDataService } from './item-data.service';
 import { PaginatedList } from './paginated-list';
-import { combineLatest as observableCombineLatest } from 'rxjs';
-import { ItemType } from '../shared/item-relationships/item-type.model';
-import { isNotUndefined } from '../../shared/empty.util';
+import { RemoteData } from './remote-data';
 import { FindListOptions, FindListRequest } from './request.models';
+import { RequestService } from './request.service';
 
 /**
- * The service handling all relationship requests
+ * The service handling all relationship type requests
  */
 @Injectable()
-export class RelationshipTypeService {
+@dataService(RELATIONSHIP_TYPE)
+export class RelationshipTypeService extends DataService<RelationshipType> {
   protected linkPath = 'relationshiptypes';
 
-  constructor(protected requestService: RequestService,
+  constructor(protected itemService: ItemDataService,
+              protected requestService: RequestService,
+              protected rdbService: RemoteDataBuildService,
+              protected store: Store<CoreState>,
               protected halService: HALEndpointService,
-              protected rdbService: RemoteDataBuildService) {
+              protected objectCache: ObjectCacheService,
+              protected notificationsService: NotificationsService,
+              protected http: HttpClient,
+              protected comparator: DefaultChangeAnalyzer<RelationshipType>,
+              protected appStore: Store<AppState>) {
+    super()
   }
 
   /**
@@ -41,7 +62,7 @@ export class RelationshipTypeService {
       .pipe(
         map((endpointURL: string) => new FindListRequest(this.requestService.generateRequestId(), endpointURL, options)),
         configureRequest(this.requestService),
-        switchMap(() => this.rdbService.buildList(link$))
+        switchMap(() => this.rdbService.buildList<RelationshipType>(link$, followLink('leftType'), followLink('rightType')))
       ) as Observable<RemoteData<PaginatedList<RelationshipType>>>;
   }
 
diff --git a/src/app/core/data/relationship.service.spec.ts b/src/app/core/data/relationship.service.spec.ts
index 99442da58d04dd47e99b49f31ad7d33224783ca3..247dce1619e8c4111557fbe22c312c8d376a77ec 100644
--- a/src/app/core/data/relationship.service.spec.ts
+++ b/src/app/core/data/relationship.service.spec.ts
@@ -1,26 +1,28 @@
-import { RelationshipService } from './relationship.service';
-import { RequestService } from './request.service';
-import { HALEndpointServiceStub } from '../../shared/testing/hal-endpoint-service-stub';
-import { getMockRemoteDataBuildService } from '../../shared/mocks/mock-remote-data-build.service';
+import { Observable } from 'rxjs/internal/Observable';
 import { of as observableOf } from 'rxjs/internal/observable/of';
-import { RequestEntry } from './request.reducer';
+import * as ItemRelationshipsUtils from '../../+item-page/simple/item-types/shared/item-relationships-utils';
+import { getMockRemoteDataBuildServiceHrefMap } from '../../shared/mocks/mock-remote-data-build.service';
+import { getMockRequestService } from '../../shared/mocks/mock-request.service';
+import { HALEndpointServiceStub } from '../../shared/testing/hal-endpoint-service-stub';
+import { createSuccessfulRemoteDataObject$, spyOnOperator } from '../../shared/testing/utils';
+import { followLink } from '../../shared/utils/follow-link-config.model';
+import { ObjectCacheService } from '../cache/object-cache.service';
 import { RelationshipType } from '../shared/item-relationships/relationship-type.model';
 import { Relationship } from '../shared/item-relationships/relationship.model';
-import { RemoteData } from './remote-data';
-import { getMockRequestService } from '../../shared/mocks/mock-request.service';
 import { Item } from '../shared/item.model';
-import { PaginatedList } from './paginated-list';
 import { PageInfo } from '../shared/page-info.model';
-import { DeleteRequest } from './request.models';
-import { ObjectCacheService } from '../cache/object-cache.service';
-import { Observable } from 'rxjs/internal/Observable';
-import { createSuccessfulRemoteDataObject$ } from '../../shared/testing/utils';
+import { PaginatedList } from './paginated-list';
+import { RelationshipService } from './relationship.service';
+import { RemoteData } from './remote-data';
+import { DeleteRequest, FindListOptions } from './request.models';
+import { RequestEntry } from './request.reducer';
+import { RequestService } from './request.service';
 
 describe('RelationshipService', () => {
   let service: RelationshipService;
   let requestService: RequestService;
 
-  const restEndpointURL = 'https://rest.api/';
+  const restEndpointURL = 'https://rest.api/core';
   const relationshipsEndpointURL = `${restEndpointURL}/relationships`;
   const halService: any = new HALEndpointServiceStub(restEndpointURL);
 
@@ -31,38 +33,68 @@ describe('RelationshipService', () => {
     rightwardType: 'isPublicationOfAuthor'
   });
 
+  const ri1SelfLink = restEndpointURL + '/author1';
+  const ri2SelfLink = restEndpointURL + '/author2';
+  const itemSelfLink = restEndpointURL + '/publication';
+
   const relationship1 = Object.assign(new Relationship(), {
-    self: relationshipsEndpointURL + '/2',
+    _links: {
+      self: {
+        href: relationshipsEndpointURL + '/2'
+      },
+      leftItem: {
+        href: ri1SelfLink
+      },
+      rightItem: {
+        href: itemSelfLink
+      }
+    },
     id: '2',
     uuid: '2',
     relationshipType: observableOf(new RemoteData(false, false, true, undefined, relationshipType))
   });
   const relationship2 = Object.assign(new Relationship(), {
-    self: relationshipsEndpointURL + '/3',
+    _links: {
+      self: {
+        href: relationshipsEndpointURL + '/3'
+      },
+      leftItem: {
+        href: ri2SelfLink
+      },
+      rightItem: {
+        href: itemSelfLink
+      },
+    },
     id: '3',
     uuid: '3',
     relationshipType: observableOf(new RemoteData(false, false, true, undefined, relationshipType))
   });
 
-  const relationships = [ relationship1, relationship2 ];
-
-  const item = Object.assign(new Item(), {
-    self: 'fake-item-url/publication',
+  const relationships = [relationship1, relationship2];  const item = Object.assign(new Item(), {
     id: 'publication',
     uuid: 'publication',
-    relationships: observableOf(new RemoteData(false, false, true, undefined, new PaginatedList(new PageInfo(), relationships)))
+    relationships: observableOf(new RemoteData(false, false, true, undefined, new PaginatedList(new PageInfo(), relationships))),
+    _links: {
+      relationships: { href: restEndpointURL + '/publication/relationships' },
+      self: { href: itemSelfLink }
+    }
   });
 
   const relatedItem1 = Object.assign(new Item(), {
-    self: 'fake-item-url/author1',
     id: 'author1',
-    uuid: 'author1'
+    uuid: 'author1',
+    _links: {
+      self: { href: ri1SelfLink }
+    }
   });
   const relatedItem2 = Object.assign(new Item(), {
-    self: 'fake-item-url/author2',
     id: 'author2',
-    uuid: 'author2'
+    uuid: 'author2',
+    _links: {
+      self: { href: ri2SelfLink }
+    }
   });
+
   relationship1.leftItem = getRemotedataObservable(relatedItem1);
   relationship1.rightItem = getRemotedataObservable(item);
   relationship2.leftItem = getRemotedataObservable(relatedItem2);
@@ -70,10 +102,12 @@ describe('RelationshipService', () => {
   const relatedItems = [relatedItem1, relatedItem2];
 
   const buildList$ = createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [relatedItems]));
-  const rdbService = getMockRemoteDataBuildService(undefined, buildList$);
+  const relationships$ = createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [relationships]));
+  const rdbService = getMockRemoteDataBuildServiceHrefMap(undefined, {'href': buildList$, 'https://rest.api/core/publication/relationships': relationships$});
   const objectCache = Object.assign({
     /* tslint:disable:no-empty */
-    remove: () => {},
+    remove: () => {
+    },
     hasBySelfLinkObservable: () => observableOf(false)
     /* tslint:enable:no-empty */
   }) as ObjectCacheService;
@@ -89,7 +123,6 @@ describe('RelationshipService', () => {
       requestService,
       rdbService,
       null,
-      null,
       halService,
       objectCache,
       null,
@@ -123,33 +156,104 @@ describe('RelationshipService', () => {
     });
 
     it('should clear the cache of the related items', () => {
-      expect(objectCache.remove).toHaveBeenCalledWith(relatedItem1.self);
-      expect(objectCache.remove).toHaveBeenCalledWith(item.self);
+      expect(objectCache.remove).toHaveBeenCalledWith(relatedItem1._links.self.href);
+      expect(objectCache.remove).toHaveBeenCalledWith(item._links.self.href);
       expect(requestService.removeByHrefSubstring).toHaveBeenCalledWith(relatedItem1.self);
       expect(requestService.removeByHrefSubstring).toHaveBeenCalledWith(item.self);
     });
   });
 
   describe('getItemRelationshipsArray', () => {
-    it('should return the item\'s relationships in the form of an array', () => {
+    it('should return the item\'s relationships in the form of an array', (done) => {
       service.getItemRelationshipsArray(item).subscribe((result) => {
-        expect(result).toEqual(relationships);
+        result.forEach((relResult: any) => {
+          expect(relResult).toEqual(relationships);
+        });
+        done();
       });
     });
   });
 
   describe('getRelatedItems', () => {
-    it('should return the related items', () => {
-      service.getRelatedItems(item).subscribe((result) => {
-        expect(result).toEqual(relatedItems);
+    let mockItem;
+
+    beforeEach(() => {
+      mockItem = { uuid: 'someid' } as Item;
+
+      spyOn(service, 'getItemRelationshipsArray').and.returnValue(observableOf(relationships));
+
+      spyOnOperator(ItemRelationshipsUtils, 'relationsToItems').and.returnValue((v) => v);
+    });
+
+    it('should call getItemRelationshipsArray with the correct params', (done) => {
+      service.getRelatedItems(mockItem).subscribe(() => {
+        expect(service.getItemRelationshipsArray).toHaveBeenCalledWith(
+          mockItem,
+          followLink('leftItem'),
+          followLink('rightItem'),
+          followLink('relationshipType')
+        );
+        done();
+      });
+    });
+
+    it('should use the relationsToItems operator', (done) => {
+      service.getRelatedItems(mockItem).subscribe(() => {
+        expect(ItemRelationshipsUtils.relationsToItems).toHaveBeenCalledWith(mockItem.uuid);
+        done();
       });
     });
   });
 
   describe('getRelatedItemsByLabel', () => {
-    it('should return the related items by label', () => {
-      service.getRelatedItemsByLabel(item, relationshipType.rightwardType).subscribe((result) => {
-        expect(result.payload.page).toEqual(relatedItems);
+    let relationsList;
+    let mockItem;
+    let mockLabel;
+    let mockOptions;
+
+    beforeEach(() => {
+      relationsList = new PaginatedList(new PageInfo({
+        elementsPerPage: relationships.length,
+        totalElements: relationships.length,
+        currentPage: 1,
+        totalPages: 1
+      }), relationships);
+      mockItem = { uuid: 'someid' } as Item;
+      mockLabel = 'label';
+      mockOptions = { label: 'options' } as FindListOptions;
+
+      const rd$ = createSuccessfulRemoteDataObject$(relationsList);
+      spyOn(service, 'getItemRelationshipsByLabel').and.returnValue(rd$);
+
+      spyOnOperator(ItemRelationshipsUtils, 'paginatedRelationsToItems').and.returnValue((v) => v);
+    });
+
+    it('should call getItemRelationshipsByLabel with the correct params', (done) => {
+      service.getRelatedItemsByLabel(
+        mockItem,
+        mockLabel,
+        mockOptions
+      ).subscribe((result) => {
+        expect(service.getItemRelationshipsByLabel).toHaveBeenCalledWith(
+          mockItem,
+          mockLabel,
+          mockOptions,
+          followLink('leftItem'),
+          followLink('rightItem'),
+          followLink('relationshipType')
+        );
+        done();
+      });
+    });
+
+    it('should use the paginatedRelationsToItems operator', (done) => {
+      service.getRelatedItemsByLabel(
+        mockItem,
+        mockLabel,
+        mockOptions
+      ).subscribe((result) => {
+        expect(ItemRelationshipsUtils.paginatedRelationsToItems).toHaveBeenCalledWith(mockItem.uuid);
+        done();
       });
     });
   })
diff --git a/src/app/core/data/relationship.service.ts b/src/app/core/data/relationship.service.ts
index 0448c18ec6238aa8b05130116913a6c43705bf13..4dde567c99d468e259d38503726dc12682369350 100644
--- a/src/app/core/data/relationship.service.ts
+++ b/src/app/core/data/relationship.service.ts
@@ -1,47 +1,49 @@
+import { HttpClient, HttpHeaders } from '@angular/common/http';
 import { Injectable } from '@angular/core';
-import { ReorderableRelationship } from '../../shared/form/builder/ds-dynamic-form-ui/existing-metadata-list-element/existing-metadata-list-element.component';
-import { RequestService } from './request.service';
-import { HALEndpointService } from '../shared/hal-endpoint.service';
-import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
-import { hasValue, hasValueOperator, isNotEmpty, isNotEmptyOperator } from '../../shared/empty.util';
-import { distinctUntilChanged, filter, map, mergeMap, startWith, switchMap, take, tap } from 'rxjs/operators';
-import {
-  configureRequest,
-  getRemoteDataPayload,
-  getResponseFromEntry,
-  getSucceededRemoteData
-} from '../shared/operators';
-import { DeleteRequest, FindListOptions, PostRequest, RestRequest } from './request.models';
-import { Observable } from 'rxjs/internal/Observable';
-import { RestResponse } from '../cache/response.models';
-import { Item } from '../shared/item.model';
-import { Relationship } from '../shared/item-relationships/relationship.model';
-import { RelationshipType } from '../shared/item-relationships/relationship-type.model';
-import { RemoteData, RemoteDataState } from './remote-data';
+import { MemoizedSelector, select, Store } from '@ngrx/store';
 import { combineLatest, combineLatest as observableCombineLatest } from 'rxjs';
-import { PaginatedList } from './paginated-list';
-import { ItemDataService } from './item-data.service';
+import { Observable } from 'rxjs/internal/Observable';
+import { distinctUntilChanged, filter, map, mergeMap, startWith, switchMap, take, tap } from 'rxjs/operators';
 import {
   compareArraysUsingIds,
   paginatedRelationsToItems,
   relationsToItems
 } from '../../+item-page/simple/item-types/shared/item-relationships-utils';
-import { ObjectCacheService } from '../cache/object-cache.service';
-import { DataService } from './data.service';
-import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service';
-import { MemoizedSelector, select, Store } from '@ngrx/store';
-import { CoreState } from '../core.reducers';
-import { NotificationsService } from '../../shared/notifications/notifications.service';
-import { HttpClient, HttpHeaders } from '@angular/common/http';
-import { DefaultChangeAnalyzer } from './default-change-analyzer.service';
-import { SearchParam } from '../cache/models/search-param.model';
-import { HttpOptions } from '../dspace-rest-v2/dspace-rest-v2.service';
 import { AppState, keySelector } from '../../app.reducer';
-import { NameVariantListState } from '../../shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/name-variant.reducer';
+import { hasValue, hasValueOperator, isNotEmpty, isNotEmptyOperator } from '../../shared/empty.util';
+import { ReorderableRelationship } from '../../shared/form/builder/ds-dynamic-form-ui/existing-metadata-list-element/existing-metadata-list-element.component';
 import {
   RemoveNameVariantAction,
   SetNameVariantAction
 } from '../../shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/name-variant.actions';
+import { NameVariantListState } from '../../shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/name-variant.reducer';
+import { NotificationsService } from '../../shared/notifications/notifications.service';
+import { followLink, FollowLinkConfig } from '../../shared/utils/follow-link-config.model';
+import { dataService } from '../cache/builders/build-decorators';
+import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
+import { SearchParam } from '../cache/models/search-param.model';
+import { ObjectCacheService } from '../cache/object-cache.service';
+import { RestResponse } from '../cache/response.models';
+import { CoreState } from '../core.reducers';
+import { HttpOptions } from '../dspace-rest-v2/dspace-rest-v2.service';
+import { HALEndpointService } from '../shared/hal-endpoint.service';
+import { RelationshipType } from '../shared/item-relationships/relationship-type.model';
+import { Relationship } from '../shared/item-relationships/relationship.model';
+import { RELATIONSHIP } from '../shared/item-relationships/relationship.resource-type';
+import { Item } from '../shared/item.model';
+import {
+  configureRequest,
+  getRemoteDataPayload,
+  getResponseFromEntry,
+  getSucceededRemoteData
+} from '../shared/operators';
+import { DataService } from './data.service';
+import { DefaultChangeAnalyzer } from './default-change-analyzer.service';
+import { ItemDataService } from './item-data.service';
+import { PaginatedList } from './paginated-list';
+import { RemoteData, RemoteDataState } from './remote-data';
+import { DeleteRequest, FindListOptions, PostRequest, RestRequest } from './request.models';
+import { RequestService } from './request.service';
 
 const relationshipListsStateSelector = (state: AppState) => state.relationshipLists;
 
@@ -57,14 +59,13 @@ const relationshipStateSelector = (listID: string, itemID: string): MemoizedSele
  * The service handling all relationship requests
  */
 @Injectable()
+@dataService(RELATIONSHIP)
 export class RelationshipService extends DataService<Relationship> {
   protected linkPath = 'relationships';
-  protected forceBypassCache = false;
 
   constructor(protected itemService: ItemDataService,
               protected requestService: RequestService,
               protected rdbService: RemoteDataBuildService,
-              protected dataBuildService: NormalizedObjectBuildService,
               protected store: Store<CoreState>,
               protected halService: HALEndpointService,
               protected objectCache: ObjectCacheService,
@@ -75,10 +76,6 @@ export class RelationshipService extends DataService<Relationship> {
     super();
   }
 
-  getBrowseEndpoint(options: FindListOptions = {}, linkPath: string = this.linkPath): Observable<string> {
-    return this.halService.getEndpoint(linkPath);
-  }
-
   /**
    * Get the endpoint for a relationship by ID
    * @param uuid
@@ -165,29 +162,29 @@ export class RelationshipService extends DataService<Relationship> {
    * @param item The item to remove from the cache
    */
   private removeRelationshipItemsFromCache(item) {
-    this.objectCache.remove(item.self);
+    this.objectCache.remove(item._links.self.href);
     this.requestService.removeByHrefSubstring(item.uuid);
     combineLatest(
-      this.objectCache.hasBySelfLinkObservable(item.self),
+      this.objectCache.hasBySelfLinkObservable(item._links.self.href),
       this.requestService.hasByHrefObservable(item.uuid)
     ).pipe(
       filter(([existsInOC, existsInRC]) => !existsInOC && !existsInRC),
       take(1),
-      switchMap(() => this.itemService.findByHref(item.self).pipe(take(1)))
+      switchMap(() => this.itemService.findByHref(item._links.self.href).pipe(take(1)))
     ).subscribe();
   }
 
   /**
-   * Get an item its relationships in the form of an array
+   * Get an item's relationships in the form of an array
    * @param item
    */
-  getItemRelationshipsArray(item: Item): Observable<Relationship[]> {
-    return item.relationships.pipe(
+  getItemRelationshipsArray(item: Item, ...linksToFollow: Array<FollowLinkConfig<Relationship>>): Observable<Relationship[]> {
+    return this.findAllByHref(item._links.relationships.href, undefined, ...linksToFollow).pipe(
       getSucceededRemoteData(),
       getRemoteDataPayload(),
       map((rels: PaginatedList<Relationship>) => rels.page),
       hasValueOperator(),
-      distinctUntilChanged(compareArraysUsingIds())
+      distinctUntilChanged(compareArraysUsingIds()),
     );
   }
 
@@ -197,7 +194,7 @@ export class RelationshipService extends DataService<Relationship> {
    * @param item
    */
   getRelationshipTypeLabelsByItem(item: Item): Observable<string[]> {
-    return this.getItemRelationshipsArray(item).pipe(
+    return this.getItemRelationshipsArray(item, followLink('leftItem'), followLink('rightItem'), followLink('relationshipType')).pipe(
       switchMap((relationships: Relationship[]) => observableCombineLatest(relationships.map((relationship: Relationship) => this.getRelationshipTypeLabelByRelationshipAndItem(relationship, item)))),
       map((labels: string[]) => Array.from(new Set(labels)))
     );
@@ -226,7 +223,12 @@ export class RelationshipService extends DataService<Relationship> {
    * @param item
    */
   getRelatedItems(item: Item): Observable<Item[]> {
-    return this.getItemRelationshipsArray(item).pipe(
+    return this.getItemRelationshipsArray(
+      item,
+      followLink('leftItem'),
+      followLink('rightItem'),
+      followLink('relationshipType')
+    ).pipe(
       relationsToItems(item.uuid)
     );
   }
@@ -239,17 +241,18 @@ export class RelationshipService extends DataService<Relationship> {
    * @param options
    */
   getRelatedItemsByLabel(item: Item, label: string, options?: FindListOptions): Observable<RemoteData<PaginatedList<Item>>> {
-    return this.getItemRelationshipsByLabel(item, label, options).pipe(paginatedRelationsToItems(item.uuid));
+    return this.getItemRelationshipsByLabel(item, label, options, followLink('leftItem'), followLink('rightItem'), followLink('relationshipType')).pipe(paginatedRelationsToItems(item.uuid));
   }
 
   /**
-   * Resolve a given item's relationships into related items, filtered by a relationship label
-   * and return the items as an array
+   * Resolve a given item's relationships by label
+   * This should move to the REST API.
+   *
    * @param item
    * @param label
    * @param options
    */
-  getItemRelationshipsByLabel(item: Item, label: string, options?: FindListOptions): Observable<RemoteData<PaginatedList<Relationship>>> {
+  getItemRelationshipsByLabel(item: Item, label: string, options?: FindListOptions, ...linksToFollow: Array<FollowLinkConfig<Relationship>>): Observable<RemoteData<PaginatedList<Relationship>>> {
     let findListOptions = new FindListOptions();
     if (options) {
       findListOptions = Object.assign(new FindListOptions(), options);
@@ -260,7 +263,7 @@ export class RelationshipService extends DataService<Relationship> {
     } else {
       findListOptions.searchParams = searchParams;
     }
-    return this.searchBy('byLabel', findListOptions);
+    return this.searchBy('byLabel', findListOptions, ...linksToFollow);
   }
 
   /**
@@ -270,7 +273,7 @@ export class RelationshipService extends DataService<Relationship> {
    * @param uuids
    */
   getRelationshipsByRelatedItemIds(item: Item, uuids: string[]): Observable<Relationship[]> {
-    return this.getItemRelationshipsArray(item).pipe(
+    return this.getItemRelationshipsArray(item, followLink('leftItem'), followLink('rightItem')).pipe(
       switchMap((relationships: Relationship[]) => {
         return observableCombineLatest(...relationships.map((relationship: Relationship) => {
           const isLeftItem$ = this.isItemInUUIDArray(relationship.leftItem, uuids);
@@ -300,8 +303,8 @@ export class RelationshipService extends DataService<Relationship> {
    * @param item2 The second item in the relationship
    * @param label The rightward or leftward type of the relationship
    */
-  getRelationshipByItemsAndLabel(item1: Item, item2: Item, label: string): Observable<Relationship> {
-    return this.getItemRelationshipsByLabel(item1, label)
+  getRelationshipByItemsAndLabel(item1: Item, item2: Item, label: string, options?: FindListOptions): Observable<Relationship> {
+    return this.getItemRelationshipsByLabel(item1, label, options, followLink('relationshipType'), followLink('leftItem'), followLink('rightItem'))
       .pipe(
         getSucceededRemoteData(),
         isNotEmptyOperator(),
@@ -443,19 +446,12 @@ export class RelationshipService extends DataService<Relationship> {
   clearRelatedCache(uuid: string): Observable<void> {
     return this.findById(uuid).pipe(
       getSucceededRemoteData(),
-      switchMap((rd: RemoteData<Relationship>) =>
-        observableCombineLatest(
-          rd.payload.leftItem.pipe(getSucceededRemoteData()),
-          rd.payload.rightItem.pipe(getSucceededRemoteData())
-        )
-      ),
-      take(1),
-      map(([leftItem, rightItem]) => {
-        this.objectCache.remove(leftItem.payload.self);
-        this.objectCache.remove(rightItem.payload.self);
-        this.requestService.removeByHrefSubstring(leftItem.payload.self);
-        this.requestService.removeByHrefSubstring(rightItem.payload.self);
-      }),
+      map((rd: RemoteData<Relationship>) => {
+        this.objectCache.remove(rd.payload._links.leftItem.href);
+        this.objectCache.remove(rd.payload._links.rightItem.href);
+        this.requestService.removeByHrefSubstring(rd.payload._links.leftItem.href);
+        this.requestService.removeByHrefSubstring(rd.payload._links.rightItem.href);
+      })
     );
   }
 }
diff --git a/src/app/core/data/remote-data.ts b/src/app/core/data/remote-data.ts
index 3be92489071bd79f372977dee65149e1187cb493..8502c8ba1da78c0d0b8c238e210cebc60c170879 100644
--- a/src/app/core/data/remote-data.ts
+++ b/src/app/core/data/remote-data.ts
@@ -17,7 +17,8 @@ export class RemoteData<T> {
     private responsePending?: boolean,
     private isSuccessful?: boolean,
     public error?: RemoteDataError,
-    public payload?: T
+    public payload?: T,
+    public statusCode?: number,
   ) {
   }
 
diff --git a/src/app/core/data/request.effects.ts b/src/app/core/data/request.effects.ts
index 9ef85bfe8b26cd1f76eb75b91e5f43ecd2b740dd..a9052aa8dca29d5a978abd06d1b7cb473bfb064c 100644
--- a/src/app/core/data/request.effects.ts
+++ b/src/app/core/data/request.effects.ts
@@ -1,12 +1,17 @@
-import { Observable, of as observableOf } from 'rxjs';
 import { Inject, Injectable, Injector } from '@angular/core';
 import { Actions, Effect, ofType } from '@ngrx/effects';
+import { Observable, of as observableOf } from 'rxjs';
+import { catchError, filter, flatMap, map, take } from 'rxjs/operators';
 
 import { GLOBAL_CONFIG, GlobalConfig } from '../../../config';
 import { hasValue, isNotEmpty } from '../../shared/empty.util';
+import { StoreActionTypes } from '../../store.actions';
+import { getClassForType } from '../cache/builders/build-decorators';
+import { ErrorResponse, RestResponse } from '../cache/response.models';
 import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
 
 import { DSpaceRESTv2Service } from '../dspace-rest-v2/dspace-rest-v2.service';
+import { DSpaceSerializer } from '../dspace-rest-v2/dspace.serializer';
 import {
   RequestActionTypes,
   RequestCompleteAction,
@@ -16,11 +21,6 @@ import {
 import { RequestError, RestRequest } from './request.models';
 import { RequestEntry } from './request.reducer';
 import { RequestService } from './request.service';
-import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer';
-import { catchError, filter, flatMap, map, take, tap } from 'rxjs/operators';
-import { ErrorResponse, RestResponse } from '../cache/response.models';
-import { StoreActionTypes } from '../../store.actions';
-import { getMapsToType } from '../cache/builders/build-decorators';
 
 export const addToResponseCacheAndCompleteAction = (request: RestRequest, envConfig: GlobalConfig) =>
   (source: Observable<RestResponse>): Observable<RequestCompleteAction> =>
@@ -45,7 +45,7 @@ export class RequestEffects {
     flatMap((request: RestRequest) => {
       let body;
       if (isNotEmpty(request.body)) {
-        const serializer = new DSpaceRESTv2Serializer(getMapsToType(request.body.type));
+        const serializer = new DSpaceSerializer(getClassForType(request.body.type));
         body = serializer.serialize(request.body);
       }
       return this.restApi.request(request.method, request.href, body, request.options).pipe(
diff --git a/src/app/core/data/request.reducer.spec.ts b/src/app/core/data/request.reducer.spec.ts
index 65a4ddba170d0f7a350ba6ca772ff6b73b2ebdaf..d32fe348b53a84f29c9104d5520d5e7b56de21b1 100644
--- a/src/app/core/data/request.reducer.spec.ts
+++ b/src/app/core/data/request.reducer.spec.ts
@@ -1,13 +1,15 @@
 import * as deepFreeze from 'deep-freeze';
-
-import { requestReducer, RequestState } from './request.reducer';
+import { RestResponse } from '../cache/response.models';
 import {
   RequestCompleteAction,
   RequestConfigureAction,
-  RequestExecuteAction, RequestRemoveAction, ResetResponseTimestampsAction
+  RequestExecuteAction,
+  RequestRemoveAction,
+  ResetResponseTimestampsAction
 } from './request.actions';
 import { GetRequest } from './request.models';
-import { RestResponse } from '../cache/response.models';
+
+import { requestReducer, RequestState } from './request.reducer';
 
 const response =  new RestResponse(true, 200, 'OK');
 class NullAction extends RequestCompleteAction {
diff --git a/src/app/core/data/request.service.spec.ts b/src/app/core/data/request.service.spec.ts
index 01560380c221a540598b0c78f514777b30afa0e7..017721fdf9a5e65efb2d92051ea6996e268d9d8c 100644
--- a/src/app/core/data/request.service.spec.ts
+++ b/src/app/core/data/request.service.spec.ts
@@ -2,6 +2,7 @@ import * as ngrx from '@ngrx/store';
 import { ActionsSubject, Store } from '@ngrx/store';
 import { cold, getTestScheduler, hot } from 'jasmine-marbles';
 import { BehaviorSubject, EMPTY, of as observableOf } from 'rxjs';
+import { TestScheduler } from 'rxjs/testing';
 
 import { getMockObjectCacheService } from '../../shared/mocks/mock-object-cache.service';
 import { defaultUUID, getMockUUIDService } from '../../shared/mocks/mock-uuid.service';
@@ -19,9 +20,8 @@ import {
   PutRequest,
   RestRequest
 } from './request.models';
-import { RequestService } from './request.service';
-import { TestScheduler } from 'rxjs/testing';
 import { RequestEntry } from './request.reducer';
+import { RequestService } from './request.service';
 
 describe('RequestService', () => {
   let scheduler: TestScheduler;
diff --git a/src/app/core/data/request.service.ts b/src/app/core/data/request.service.ts
index fa10a36ce963208a0e288cb1a901d300e2acdd56..1101c851ac91c3a2f122290ec01a89e62a6b270f 100644
--- a/src/app/core/data/request.service.ts
+++ b/src/app/core/data/request.service.ts
@@ -71,7 +71,9 @@ const getUuidsFromHrefSubstring = (state: IndexState, href: string): string[] =>
 /**
  * A service to interact with the request state in the store
  */
-@Injectable()
+@Injectable({
+  providedIn: 'root'
+})
 export class RequestService {
   private requestsOnTheirWayToTheStore: string[] = [];
 
diff --git a/src/app/core/data/resource-policy.service.spec.ts b/src/app/core/data/resource-policy.service.spec.ts
index 1a02171be39e44c2ec90d0c451b878ff87d9e70b..abed805ca3e68559b893873322c6aab83985d8bc 100644
--- a/src/app/core/data/resource-policy.service.spec.ts
+++ b/src/app/core/data/resource-policy.service.spec.ts
@@ -1,15 +1,13 @@
+import { HttpClient } from '@angular/common/http';
 import { cold, getTestScheduler } from 'jasmine-marbles';
 import { TestScheduler } from 'rxjs/testing';
+import { NotificationsService } from '../../shared/notifications/notifications.service';
 import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
-import { ResourcePolicy } from '../shared/resource-policy.model';
+import { ObjectCacheService } from '../cache/object-cache.service';
 import { HALEndpointService } from '../shared/hal-endpoint.service';
-import { GetRequest } from './request.models';
+import { ResourcePolicy } from '../shared/resource-policy.model';
 import { RequestService } from './request.service';
 import { ResourcePolicyService } from './resource-policy.service';
-import { ObjectCacheService } from '../cache/object-cache.service';
-import { NotificationsService } from '../../shared/notifications/notifications.service';
-import { HttpClient } from '@angular/common/http';
-import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service';
 
 describe('ResourcePolicyService', () => {
   let scheduler: TestScheduler;
@@ -42,26 +40,26 @@ describe('ResourcePolicyService', () => {
     const notificationsService = {} as NotificationsService;
     const http = {} as HttpClient;
     const comparator = {} as any;
-    const dataBuildService = {} as NormalizedObjectBuildService;
 
     service = new ResourcePolicyService(
       requestService,
       rdbService,
-      dataBuildService,
       objectCache,
       halService,
       notificationsService,
       http,
       comparator
-    )
+    );
+
+    spyOn((service as any).dataService, 'findByHref').and.callThrough();
   });
 
   describe('findByHref', () => {
-    it('should configure the proper GetRequest', () => {
+    it('should proxy the call to dataservice.findByHref', () => {
       scheduler.schedule(() => service.findByHref(requestURL));
       scheduler.flush();
 
-      expect(requestService.configure).toHaveBeenCalledWith(new GetRequest(requestUUID, requestURL, null));
+      expect((service as any).dataService.findByHref).toHaveBeenCalledWith(requestURL);
     });
 
     it('should return a RemoteData<ResourcePolicy> for the object with the given URL', () => {
diff --git a/src/app/core/data/resource-policy.service.ts b/src/app/core/data/resource-policy.service.ts
index 017e5cf5ee1b02652d99b9c998d26c194e34c2e2..f66032925e185e126c4ccb9ad8a08f99f759447c 100644
--- a/src/app/core/data/resource-policy.service.ts
+++ b/src/app/core/data/resource-policy.service.ts
@@ -3,10 +3,13 @@ import { HttpClient } from '@angular/common/http';
 
 import { Store } from '@ngrx/store';
 import { Observable } from 'rxjs';
+import { FollowLinkConfig } from '../../shared/utils/follow-link-config.model';
+import { dataService } from '../cache/builders/build-decorators';
 
 import { DataService } from '../data/data.service';
 import { RequestService } from '../data/request.service';
 import { FindListOptions } from '../data/request.models';
+import { Collection } from '../shared/collection.model';
 import { HALEndpointService } from '../shared/hal-endpoint.service';
 import { ResourcePolicy } from '../shared/resource-policy.model';
 import { RemoteData } from '../data/remote-data';
@@ -14,19 +17,22 @@ import { RemoteDataBuildService } from '../cache/builders/remote-data-build.serv
 import { CoreState } from '../core.reducers';
 import { ObjectCacheService } from '../cache/object-cache.service';
 import { NotificationsService } from '../../shared/notifications/notifications.service';
-import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service';
+import { RESOURCE_POLICY } from '../shared/resource-policy.resource-type';
 import { ChangeAnalyzer } from './change-analyzer';
 import { DefaultChangeAnalyzer } from '../data/default-change-analyzer.service';
-import { HttpOptions } from '../dspace-rest-v2/dspace-rest-v2.service';
+import { PaginatedList } from './paginated-list';
 
 /* tslint:disable:max-classes-per-file */
+
+/**
+ * A private DataService implementation to delegate specific methods to.
+ */
 class DataServiceImpl extends DataService<ResourcePolicy> {
   protected linkPath = 'resourcepolicies';
 
   constructor(
     protected requestService: RequestService,
     protected rdbService: RemoteDataBuildService,
-    protected dataBuildService: NormalizedObjectBuildService,
     protected store: Store<CoreState>,
     protected objectCache: ObjectCacheService,
     protected halService: HALEndpointService,
@@ -36,31 +42,54 @@ class DataServiceImpl extends DataService<ResourcePolicy> {
     super();
   }
 
-  getBrowseEndpoint(options: FindListOptions = {}, linkPath: string = this.linkPath): Observable<string> {
-    return this.halService.getEndpoint(linkPath);
-  }
 }
 
 /**
  * A service responsible for fetching/sending data from/to the REST API on the resourcepolicies endpoint
  */
 @Injectable()
+@dataService(RESOURCE_POLICY)
 export class ResourcePolicyService {
   private dataService: DataServiceImpl;
 
   constructor(
     protected requestService: RequestService,
     protected rdbService: RemoteDataBuildService,
-    protected dataBuildService: NormalizedObjectBuildService,
     protected objectCache: ObjectCacheService,
     protected halService: HALEndpointService,
     protected notificationsService: NotificationsService,
     protected http: HttpClient,
     protected comparator: DefaultChangeAnalyzer<ResourcePolicy>) {
-    this.dataService = new DataServiceImpl(requestService, rdbService, dataBuildService, null, objectCache, halService, notificationsService, http, comparator);
+    this.dataService = new DataServiceImpl(requestService, rdbService, null, objectCache, halService, notificationsService, http, comparator);
+  }
+
+  /**
+   * Returns an observable of {@link RemoteData} of a {@link ResourcePolicy}, based on an href, with a list of {@link FollowLinkConfig},
+   * to automatically resolve {@link HALLink}s of the {@link ResourcePolicy}
+   * @param href            The url of {@link ResourcePolicy} we want to retrieve
+   * @param linksToFollow   List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved
+   */
+  findByHref(href: string, ...linksToFollow: Array<FollowLinkConfig<ResourcePolicy>>): Observable<RemoteData<ResourcePolicy>> {
+    return this.dataService.findByHref(href, ...linksToFollow);
+  }
+
+  /**
+   * Returns a list of observables of {@link RemoteData} of {@link ResourcePolicy}s, based on an href, with a list of {@link FollowLinkConfig},
+   * to automatically resolve {@link HALLink}s of the {@link ResourcePolicy}
+   * @param href            The url of the {@link ResourcePolicy} we want to retrieve
+   * @param linksToFollow   List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved
+   */
+  findAllByHref(href: string, findListOptions: FindListOptions = {}, ...linksToFollow: Array<FollowLinkConfig<ResourcePolicy>>): Observable<RemoteData<PaginatedList<ResourcePolicy>>> {
+    return this.dataService.findAllByHref(href, findListOptions, ...linksToFollow);
   }
 
-  findByHref(href: string, options?: HttpOptions): Observable<RemoteData<ResourcePolicy>> {
-    return this.dataService.findByHref(href, options);
+  /**
+   * Return the defaultAccessConditions {@link ResourcePolicy} list for a given {@link Collection}
+   *
+   * @param collection the {@link Collection} to retrieve the defaultAccessConditions for
+   * @param findListOptions the {@link FindListOptions} for the request
+   */
+  getDefaultAccessConditionsFor(collection: Collection, findListOptions?: FindListOptions): Observable<RemoteData<PaginatedList<ResourcePolicy>>> {
+    return this.dataService.findAllByHref(collection._links.defaultAccessConditions.href, findListOptions);
   }
 }
diff --git a/src/app/core/data/search-response-parsing.service.ts b/src/app/core/data/search-response-parsing.service.ts
index c449fa872f3b4f0f307ccb855ffbc650de620565..ed472509225b1c0f5996325c088b5109e0bd1dfa 100644
--- a/src/app/core/data/search-response-parsing.service.ts
+++ b/src/app/core/data/search-response-parsing.service.ts
@@ -1,13 +1,13 @@
 import { Injectable } from '@angular/core';
+import { hasValue } from '../../shared/empty.util';
+import { SearchQueryResponse } from '../../shared/search/search-query-response.model';
 import { RestResponse, SearchSuccessResponse } from '../cache/response.models';
+import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
+import { DSpaceSerializer } from '../dspace-rest-v2/dspace.serializer';
+import { MetadataMap, MetadataValue } from '../shared/metadata.models';
 import { DSOResponseParsingService } from './dso-response-parsing.service';
 import { ResponseParsingService } from './parsing.service';
 import { RestRequest } from './request.models';
-import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
-import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer';
-import { hasValue } from '../../shared/empty.util';
-import { SearchQueryResponse } from '../../shared/search/search-query-response.model';
-import { MetadataMap, MetadataValue } from '../shared/metadata.models';
 
 @Injectable()
 export class SearchResponseParsingService implements ResponseParsingService {
@@ -42,10 +42,6 @@ export class SearchResponseParsingService implements ResponseParsingService {
     const dsoSelfLinks = payload._embedded.objects
       .filter((object) => hasValue(object._embedded))
       .map((object) => object._embedded.indexableObject)
-      // we don't need embedded collections, bitstreamformats, etc for search results.
-      // And parsing them all takes up a lot of time. Throw them away to improve performance
-      // until objs until partial results are supported by the rest api
-      .map((dso) => Object.assign({}, dso, { _embedded: undefined }))
       .map((dso) => this.dsoParser.parse(request, {
         payload: dso,
         statusCode: data.statusCode,
@@ -59,13 +55,9 @@ export class SearchResponseParsingService implements ResponseParsingService {
       .map((object, index) => Object.assign({}, object, {
         indexableObject: dsoSelfLinks[index],
         hitHighlights: hitHighlights[index],
-        // we don't need embedded collections, bitstreamformats, etc for search results.
-        // And parsing them all takes up a lot of time. Throw them away to improve performance
-        // until objs until partial results are supported by the rest api
-        _embedded: undefined
       }));
     payload.objects = objects;
-    const deserialized = new DSpaceRESTv2Serializer(SearchQueryResponse).deserialize(payload);
+    const deserialized = new DSpaceSerializer(SearchQueryResponse).deserialize(payload);
     return new SearchSuccessResponse(deserialized, data.statusCode, data.statusText, this.dsoParser.processPageInfo(payload));
   }
 }
diff --git a/src/app/core/data/site-data.service.spec.ts b/src/app/core/data/site-data.service.spec.ts
index 6148135f50ab269183f9bae94942c8840172a3ab..6938cd65a97e6eb8e8ccad957ac834eed48e4822 100644
--- a/src/app/core/data/site-data.service.spec.ts
+++ b/src/app/core/data/site-data.service.spec.ts
@@ -8,7 +8,6 @@ import { Store } from '@ngrx/store';
 import { CoreState } from '../core.reducers';
 import { NotificationsService } from '../../shared/notifications/notifications.service';
 import { HttpClient } from '@angular/common/http';
-import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service';
 import { HALEndpointService } from '../shared/hal-endpoint.service';
 import { of as observableOf } from 'rxjs';
 import { RestResponse } from '../cache/response.models';
@@ -63,12 +62,10 @@ describe('SiteDataService', () => {
     const notificationsService = {} as NotificationsService;
     const http = {} as HttpClient;
     const comparator = {} as any;
-    const dataBuildService = {} as NormalizedObjectBuildService;
 
     service = new SiteDataService(
       requestService,
       rdbService,
-      dataBuildService,
       store,
       objectCache,
       halService,
diff --git a/src/app/core/data/site-data.service.ts b/src/app/core/data/site-data.service.ts
index c1a1b2069bdef7ffbc701f6dfaedb8526a578341..7b2bfdb543ea6ae00a774ce3ff5e7c6555193d89 100644
--- a/src/app/core/data/site-data.service.ts
+++ b/src/app/core/data/site-data.service.ts
@@ -1,35 +1,34 @@
-import { DataService } from './data.service';
-import { Site } from '../shared/site.model';
-import { RequestService } from './request.service';
-import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
-import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service';
+import { HttpClient } from '@angular/common/http';
+import { Injectable } from '@angular/core';
 import { Store } from '@ngrx/store';
-import { CoreState } from '../core.reducers';
+import { Observable } from 'rxjs';
+import { map } from 'rxjs/operators';
+import { NotificationsService } from '../../shared/notifications/notifications.service';
+import { dataService } from '../cache/builders/build-decorators';
+import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
 import { ObjectCacheService } from '../cache/object-cache.service';
+import { CoreState } from '../core.reducers';
 import { HALEndpointService } from '../shared/hal-endpoint.service';
-import { NotificationsService } from '../../shared/notifications/notifications.service';
-import { HttpClient } from '@angular/common/http';
+import { getSucceededRemoteData } from '../shared/operators';
+import { Site } from '../shared/site.model';
+import { SITE } from '../shared/site.resource-type';
+import { DataService } from './data.service';
 import { DSOChangeAnalyzer } from './dso-change-analyzer.service';
-import { FindListOptions } from './request.models';
-import { Observable } from 'rxjs';
-import { map } from 'rxjs/operators';
-import { RemoteData } from './remote-data';
 import { PaginatedList } from './paginated-list';
-import { Injectable } from '@angular/core';
-import { getSucceededRemoteData } from '../shared/operators';
+import { RemoteData } from './remote-data';
+import { RequestService } from './request.service';
 
 /**
  * Service responsible for handling requests related to the Site object
  */
 @Injectable()
+@dataService(SITE)
 export class SiteDataService extends DataService<Site> {​
   protected linkPath = 'sites';
-  protected forceBypassCache = false;
 
   constructor(
     protected requestService: RequestService,
     protected rdbService: RemoteDataBuildService,
-    protected dataBuildService: NormalizedObjectBuildService,
     protected store: Store<CoreState>,
     protected objectCache: ObjectCacheService,
     protected halService: HALEndpointService,
@@ -40,15 +39,6 @@ export class SiteDataService extends DataService<Site> {​
     super();
   }
 
-  /**
-   * Get the endpoint for browsing the site object
-   * @param {FindListOptions} options
-   * @param {Observable<string>} linkPath
-   */
-  getBrowseEndpoint(options: FindListOptions, linkPath?: string): Observable<string> {
-    return this.halService.getEndpoint(this.linkPath);
-  }
-
   /**
    * Retrieve the Site Object
    */
diff --git a/src/app/core/dspace-rest-v2/dspace-rest-v2.serializer.spec.ts b/src/app/core/dspace-rest-v2/dspace-rest-v2.serializer.spec.ts
deleted file mode 100644
index 8431d6f8b3dc353d98d1be617a4510e36b72626c..0000000000000000000000000000000000000000
--- a/src/app/core/dspace-rest-v2/dspace-rest-v2.serializer.spec.ts
+++ /dev/null
@@ -1,194 +0,0 @@
-import { autoserialize, autoserializeAs } from 'cerialize';
-
-import { DSpaceRESTv2Serializer } from './dspace-rest-v2.serializer';
-
-class TestModel {
-  @autoserialize
-  id: string;
-
-  @autoserialize
-  name: string;
-
-  @autoserializeAs(TestModel)
-  parents?: TestModel[];
-}
-
-const testModels = [
-  {
-    id: 'd4466d54-d73b-4d8f-b73f-c702020baa14',
-    name: 'Model 1',
-  },
-  {
-    id: '752a1250-949a-46ad-9bea-fbc45f0b656d',
-    name: 'Model 2',
-  }
-];
-
-const testResponses = [
-  {
-    _links: {
-      self: '/testmodels/9e32a2e2-6b91-4236-a361-995ccdc14c60',
-      parents: [
-        { href: '/testmodels/21539b1d-9ef1-4eda-9c77-49565b5bfb78' },
-        { href: '/testmodels/be8325f7-243b-49f4-8a4b-df2b793ff3b5' }
-      ]
-    },
-    id: '9e32a2e2-6b91-4236-a361-995ccdc14c60',
-    type: 'testModels',
-    name: 'A Test Model'
-  },
-  {
-    _links: {
-      self: '/testmodels/598ce822-c357-46f3-ab70-63724d02d6ad',
-      parents: [
-        { href: '/testmodels/be8325f7-243b-49f4-8a4b-df2b793ff3b5' },
-        { href: '/testmodels/21539b1d-9ef1-4eda-9c77-49565b5bfb78' }
-      ]
-    },
-    id: '598ce822-c357-46f3-ab70-63724d02d6ad',
-    type: 'testModels',
-    name: 'Another Test Model'
-  }
-];
-
-const parentHrefRegex = /^\/testmodels\/(.+)$/g;
-
-describe('DSpaceRESTv2Serializer', () => {
-
-  describe('serialize', () => {
-
-    it('should turn a model in to a valid document', () => {
-      const serializer = new DSpaceRESTv2Serializer(TestModel);
-      const doc = serializer.serialize(testModels[0]);
-      expect(testModels[0].id).toBe(doc.id);
-      expect(testModels[0].name).toBe(doc.name);
-    });
-
-  });
-
-  describe('serializeArray', () => {
-
-    it('should turn an array of models in to a valid document', () => {
-      const serializer = new DSpaceRESTv2Serializer(TestModel);
-      const doc = serializer.serializeArray(testModels);
-
-      expect(testModels[0].id).toBe(doc[0].id);
-      expect(testModels[0].name).toBe(doc[0].name);
-      expect(testModels[1].id).toBe(doc[1].id);
-      expect(testModels[1].name).toBe(doc[1].name);
-    });
-
-  });
-
-  describe('deserialize', () => {
-
-    it('should turn a valid document describing a single entity in to a valid model', () => {
-      const serializer = new DSpaceRESTv2Serializer(TestModel);
-      const model = serializer.deserialize(testResponses[0]);
-
-      expect(model.id).toBe(testResponses[0].id);
-      expect(model.name).toBe(testResponses[0].name);
-    });
-
-    // TODO: cant implement/test this yet - depends on how relationships
-    // will be handled in the rest api
-    // it('should retain relationship information', () => {
-    //   const serializer = new DSpaceRESTv2Serializer(TestModel);
-    //   const doc = {
-    //     '_embedded': testResponses[0],
-    //   };
-    //
-    //   const model = serializer.deserialize(doc);
-    //
-    //   console.log(model);
-    //
-    //   const modelParentIds = model.parents.map(parent => parent.id).sort();
-    //   const responseParentIds = doc._embedded._links.parents
-    //     .map(parent => parent.href)
-    //     .map(href => href.replace(parentHrefRegex, '$1'))
-    //     .sort();
-    //
-    //   expect(modelParentIds).toEqual(responseParentIds);
-    // });
-
-    // TODO enable once validation is enabled in the serializer
-    // it('should throw an error when dealing with an invalid document', () => {
-    //   const serializer = new DSpaceRESTv2Serializer(TestModel);
-    //   const doc = testResponses[0];
-    //
-    //   expect(() => {
-    //     serializer.deserialize(doc);
-    //   }).toThrow();
-    // });
-
-    it('should throw an error when dealing with a document describing an array', () => {
-      const serializer = new DSpaceRESTv2Serializer(TestModel);
-      expect(() => {
-        serializer.deserialize(testResponses);
-      }).toThrow();
-    });
-
-  });
-
-  describe('deserializeArray', () => {
-
-    // TODO: rewrite to incorporate normalisation.
-    // it('should turn a valid document describing a collection of objects in to an array of valid models', () => {
-    //   const serializer = new DSpaceRESTv2Serializer(TestModel);
-    //   const doc = {
-    //     '_embedded': testResponses
-    //   };
-    //
-    //   const models = serializer.deserializeArray(doc);
-    //
-    //   expect(models[0].id).toBe(doc._embedded[0].id);
-    //   expect(models[0].name).toBe(doc._embedded[0].name);
-    //   expect(models[1].id).toBe(doc._embedded[1].id);
-    //   expect(models[1].name).toBe(doc._embedded[1].name);
-    // });
-
-    // TODO: cant implement/test this yet - depends on how relationships
-    // will be handled in the rest api
-    // it('should retain relationship information', () => {
-    //   const serializer = new DSpaceRESTv2Serializer(TestModel);
-    //   const doc = {
-    //     '_embedded': testResponses,
-    //   };
-    //
-    //   const models = serializer.deserializeArray(doc);
-    //
-    //   models.forEach((model, i) => {
-    //     const modelParentIds = model.parents.map(parent => parent.id).sort();
-    //     const responseParentIds = doc._embedded[i]._links.parents
-    //       .map(parent => parent.href)
-    //       .map(href => href.replace(parentHrefRegex, '$1'))
-    //       .sort();
-    //
-    //     expect(modelParentIds).toEqual(responseParentIds);
-    //   });
-    // });
-
-    // TODO enable once validation is enabled in the serializer
-    // it('should throw an error when dealing with an invalid document', () => {
-    //   const serializer = new DSpaceRESTv2Serializer(TestModel);
-    //   const doc = testResponses[0];
-    //
-    //   expect(() => {
-    //     serializer.deserializeArray(doc);
-    //   }).toThrow();
-    // });
-
-    it('should throw an error when dealing with a document describing a single model', () => {
-      const serializer = new DSpaceRESTv2Serializer(TestModel);
-      const doc = {
-        _embedded: testResponses[0]
-      };
-
-      expect(() => {
-        serializer.deserializeArray(doc);
-      }).toThrow();
-    });
-
-  });
-
-});
diff --git a/src/app/core/dspace-rest-v2/dspace-rest-v2.service.ts b/src/app/core/dspace-rest-v2/dspace-rest-v2.service.ts
index cf9b1067c152e68a3c026f554e74b26e95b03a9b..91756d412cb6378a3f8cf449438c102ae806c09f 100644
--- a/src/app/core/dspace-rest-v2/dspace-rest-v2.service.ts
+++ b/src/app/core/dspace-rest-v2/dspace-rest-v2.service.ts
@@ -4,7 +4,6 @@ import { Injectable } from '@angular/core';
 import { HttpClient, HttpHeaders, HttpParams, HttpResponse } from '@angular/common/http'
 
 import { DSpaceRESTV2Response } from './dspace-rest-v2-response.model';
-import { HttpObserve } from '@angular/common/http/src/client';
 import { RestRequestMethod } from '../data/rest-request-method';
 import { hasNoValue, isNotEmpty } from '../../shared/empty.util';
 import { DSpaceObject } from '../shared/dspace-object.model';
@@ -14,7 +13,7 @@ export interface HttpOptions {
   body?: any;
   headers?: HttpHeaders;
   params?: HttpParams;
-  observe?: HttpObserve;
+  observe?: 'body' | 'events' | 'response';
   reportProgress?: boolean;
   responseType?: 'arraybuffer' | 'blob' | 'json' | 'text';
   withCredentials?: boolean;
diff --git a/src/app/core/dspace-rest-v2/dspace.serializer.spec.ts b/src/app/core/dspace-rest-v2/dspace.serializer.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b07a4f97d11cea9d60208b5be75627728d2eacb5
--- /dev/null
+++ b/src/app/core/dspace-rest-v2/dspace.serializer.spec.ts
@@ -0,0 +1,154 @@
+import { autoserialize, autoserializeAs, deserialize } from 'cerialize';
+import { HALLink } from '../shared/hal-link.model';
+import { HALResource } from '../shared/hal-resource.model';
+import { DSpaceSerializer } from './dspace.serializer';
+
+class TestModel implements HALResource {
+  @autoserialize
+  id: string;
+
+  @autoserialize
+  name: string;
+
+  @deserialize
+  _links: {
+    self: HALLink;
+    parents: HALLink;
+  }
+}
+
+const testModels = [
+  {
+    id: 'd4466d54-d73b-4d8f-b73f-c702020baa14',
+    name: 'Model 1',
+    _links: {
+      self: {
+        href: '/testmodels/9e32a2e2-6b91-4236-a361-995ccdc14c60'
+      },
+      parents: {
+        href: '/testmodels/9e32a2e2-6b91-4236-a361-995ccdc14c60/parents'
+      }
+    }
+  },
+  {
+    id: '752a1250-949a-46ad-9bea-fbc45f0b656d',
+    name: 'Model 2',
+    _links: {
+      self: {
+        href: '/testmodels/598ce822-c357-46f3-ab70-63724d02d6ad'
+      },
+      parents: {
+        href: '/testmodels/598ce822-c357-46f3-ab70-63724d02d6ad/parents'
+      }
+    }
+  }
+];
+
+const testResponses = [
+  {
+    _links: {
+      self: {
+        href: '/testmodels/9e32a2e2-6b91-4236-a361-995ccdc14c60'
+      },
+      parents: {
+        href: '/testmodels/9e32a2e2-6b91-4236-a361-995ccdc14c60/parents'
+      }
+    },
+    id: '9e32a2e2-6b91-4236-a361-995ccdc14c60',
+    type: 'testModels',
+    name: 'A Test Model'
+  },
+  {
+    _links: {
+      self: {
+        href: '/testmodels/598ce822-c357-46f3-ab70-63724d02d6ad'
+      },
+      parents: {
+        href: '/testmodels/598ce822-c357-46f3-ab70-63724d02d6ad/parents'
+      }
+    },
+    id: '598ce822-c357-46f3-ab70-63724d02d6ad',
+    type: 'testModels',
+    name: 'Another Test Model'
+  }
+];
+
+describe('DSpaceSerializer', () => {
+
+  describe('serialize', () => {
+
+    it('should turn a model in to a valid document', () => {
+      const serializer = new DSpaceSerializer(TestModel);
+      const doc = serializer.serialize(testModels[0]);
+      expect(doc.id).toBe(testModels[0].id);
+      expect(doc.name).toBe(testModels[0].name);
+      expect(doc._links).toBeUndefined();
+    });
+
+  });
+
+  describe('serializeArray', () => {
+
+    it('should turn an array of models in to a valid document', () => {
+      const serializer = new DSpaceSerializer(TestModel);
+      const doc = serializer.serializeArray(testModels);
+
+      expect(doc[0].id).toBe(testModels[0].id);
+      expect(doc[0].name).toBe(testModels[0].name);
+      expect(doc[0]._links).toBeUndefined();
+      expect(doc[1].id).toBe(testModels[1].id);
+      expect(doc[1].name).toBe(testModels[1].name);
+      expect(doc[1]._links).toBeUndefined();
+    });
+
+  });
+
+  describe('deserialize', () => {
+
+    it('should turn a valid document describing a single entity in to a valid model', () => {
+      const serializer = new DSpaceSerializer(TestModel);
+      const model = serializer.deserialize(testResponses[0]);
+
+      expect(model.id).toBe(testResponses[0].id);
+      expect(model.name).toBe(testResponses[0].name);
+    });
+
+    it('should throw an error when dealing with a document describing an array', () => {
+      const serializer = new DSpaceSerializer(TestModel);
+      expect(() => {
+        serializer.deserialize(testResponses);
+      }).toThrow();
+    });
+
+  });
+
+  describe('deserializeArray', () => {
+
+    it('should throw an error when dealing with a document describing a single model', () => {
+      const serializer = new DSpaceSerializer(TestModel);
+      const doc = {
+        _embedded: testResponses[0]
+      };
+
+      expect(() => {
+        serializer.deserializeArray(doc);
+      }).toThrow();
+    });
+
+    it('should turn an array of responses in to valid models', () => {
+      const serializer = new DSpaceSerializer(TestModel);
+      const output = serializer.deserializeArray(testResponses);
+
+      expect(testResponses[0].id).toBe(output[0].id);
+      expect(testResponses[0].name).toBe(output[0].name);
+      expect(testResponses[0]._links.self.href).toBe(output[0]._links.self.href);
+      expect(testResponses[0]._links.parents.href).toBe(output[0]._links.parents.href);
+      expect(testResponses[1].id).toBe(output[1].id);
+      expect(testResponses[1].name).toBe(output[1].name);
+      expect(testResponses[1]._links.self.href).toBe(output[1]._links.self.href);
+      expect(testResponses[1]._links.parents.href).toBe(output[1]._links.parents.href);
+    });
+
+  });
+
+});
diff --git a/src/app/core/dspace-rest-v2/dspace-rest-v2.serializer.ts b/src/app/core/dspace-rest-v2/dspace.serializer.ts
similarity index 53%
rename from src/app/core/dspace-rest-v2/dspace-rest-v2.serializer.ts
rename to src/app/core/dspace-rest-v2/dspace.serializer.ts
index 258edb116d232ce4f0ee3e76e8f9dac65058382b..e16094a040c2da8821d3e1b3dad3873d7bc6fcf9 100644
--- a/src/app/core/dspace-rest-v2/dspace-rest-v2.serializer.ts
+++ b/src/app/core/dspace-rest-v2/dspace.serializer.ts
@@ -1,19 +1,16 @@
-import { Serialize, Deserialize } from 'cerialize';
+import { Deserialize, Serialize } from 'cerialize';
 
 import { Serializer } from '../serializer';
-import { DSpaceRESTV2Response } from './dspace-rest-v2-response.model';
-import { DSpaceRESTv2Validator } from './dspace-rest-v2.validator';
 import { GenericConstructor } from '../shared/generic-constructor';
-import { hasNoValue, hasValue } from '../../shared/empty.util';
 
 /**
  * This Serializer turns responses from v2 of DSpace's REST API
  * to models and vice versa
  */
-export class DSpaceRESTv2Serializer<T> implements Serializer<T> {
+export class DSpaceSerializer<T> implements Serializer<T> {
 
   /**
-   * Create a new DSpaceRESTv2Serializer instance
+   * Create a new DSpaceSerializer instance
    *
    * @param modelType a class or interface to indicate
    * the kind of model this serializer should work with
@@ -48,13 +45,10 @@ export class DSpaceRESTv2Serializer<T> implements Serializer<T> {
    * @returns a model of type T
    */
   deserialize(response: any): T {
-    // TODO enable validation, once rest data stabilizes
-    // new DSpaceRESTv2Validator(response).validate();
     if (Array.isArray(response)) {
       throw new Error('Expected a single model, use deserializeArray() instead');
     }
-    const normalized = Object.assign({}, response, this.normalizeLinks(response._links));
-    return Deserialize(normalized, this.modelType) as T;
+    return Deserialize(response, this.modelType) as T;
   }
 
   /**
@@ -64,30 +58,9 @@ export class DSpaceRESTv2Serializer<T> implements Serializer<T> {
    * @returns an array of models of type T
    */
   deserializeArray(response: any): T[] {
-    // TODO: enable validation, once rest data stabilizes
-    // new DSpaceRESTv2Validator(response).validate();
     if (!Array.isArray(response)) {
       throw new Error('Expected an Array, use deserialize() instead');
     }
-    const normalized = response.map((resource) => {
-      return Object.assign({}, resource, this.normalizeLinks(resource._links));
-    });
-
-    return Deserialize(normalized, this.modelType) as T[];
+    return Deserialize(response, this.modelType) as T[];
   }
-
-  private normalizeLinks(links: any): any {
-    const normalizedLinks = links;
-    for (const link in normalizedLinks) {
-      if (Array.isArray(normalizedLinks[link])) {
-        normalizedLinks[link] = normalizedLinks[link].map((linkedResource) => {
-          return linkedResource.href;
-        });
-      } else {
-        normalizedLinks[link] = normalizedLinks[link].href;
-      }
-    }
-    return normalizedLinks;
-  }
-
 }
diff --git a/src/app/core/eperson/eperson-data.service.ts b/src/app/core/eperson/eperson-data.service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ef2e76c7c60a9933af3e040fca5029b1eb04abb5
--- /dev/null
+++ b/src/app/core/eperson/eperson-data.service.ts
@@ -0,0 +1,38 @@
+import { HttpClient } from '@angular/common/http';
+import { Injectable } from '@angular/core';
+import { Store } from '@ngrx/store';
+import { NotificationsService } from '../../shared/notifications/notifications.service';
+import { dataService } from '../cache/builders/build-decorators';
+import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
+import { ObjectCacheService } from '../cache/object-cache.service';
+import { CoreState } from '../core.reducers';
+import { DataService } from '../data/data.service';
+import { DSOChangeAnalyzer } from '../data/dso-change-analyzer.service';
+import { RequestService } from '../data/request.service';
+import { HALEndpointService } from '../shared/hal-endpoint.service';
+import { EPerson } from './models/eperson.model';
+import { EPERSON } from './models/eperson.resource-type';
+
+/**
+ * A service to retrieve {@link EPerson}s from the REST API
+ */
+@Injectable()
+@dataService(EPERSON)
+export class EPersonDataService extends DataService<EPerson> {
+
+  protected linkPath: 'epersons';
+
+  constructor(
+    protected requestService: RequestService,
+    protected rdbService: RemoteDataBuildService,
+    protected store: Store<CoreState>,
+    protected objectCache: ObjectCacheService,
+    protected halService: HALEndpointService,
+    protected notificationsService: NotificationsService,
+    protected http: HttpClient,
+    protected comparator: DSOChangeAnalyzer<EPerson>
+  ) {
+    super();
+  }
+
+}
diff --git a/src/app/core/eperson/eperson.service.ts b/src/app/core/eperson/eperson.service.ts
deleted file mode 100644
index 81ae532e3b536bea8501805201036050963043fb..0000000000000000000000000000000000000000
--- a/src/app/core/eperson/eperson.service.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-import { Observable } from 'rxjs';
-import { FindListOptions } from '../data/request.models';
-import { DataService } from '../data/data.service';
-import { CacheableObject } from '../cache/object-cache.reducer';
-
-/**
- * An abstract class that provides methods to make HTTP request to eperson endpoint.
- */
-export abstract class EpersonService<TDomain extends CacheableObject> extends DataService<TDomain> {
-
-  public getBrowseEndpoint(options: FindListOptions): Observable<string> {
-    return this.halService.getEndpoint(this.linkPath);
-  }
-}
diff --git a/src/app/core/eperson/group-eperson.service.ts b/src/app/core/eperson/group-data.service.ts
similarity index 88%
rename from src/app/core/eperson/group-eperson.service.ts
rename to src/app/core/eperson/group-data.service.ts
index c8a2a78917198ab325ce699746551d21328085a9..532f42323a81615486daeef4a4b097cc61190449 100644
--- a/src/app/core/eperson/group-eperson.service.ts
+++ b/src/app/core/eperson/group-data.service.ts
@@ -4,8 +4,8 @@ import { HttpClient } from '@angular/common/http';
 import { Store } from '@ngrx/store';
 import { Observable } from 'rxjs';
 import { filter, map, take } from 'rxjs/operators';
+import { DataService } from '../data/data.service';
 
-import { EpersonService } from './eperson.service';
 import { RequestService } from '../data/request.service';
 import { FindListOptions } from '../data/request.models';
 import { HALEndpointService } from '../shared/hal-endpoint.service';
@@ -17,20 +17,23 @@ import { SearchParam } from '../cache/models/search-param.model';
 import { RemoteData } from '../data/remote-data';
 import { PaginatedList } from '../data/paginated-list';
 import { NotificationsService } from '../../shared/notifications/notifications.service';
-import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service';
 import { DSOChangeAnalyzer } from '../data/dso-change-analyzer.service';
+import { dataService } from '../cache/builders/build-decorators';
+import { GROUP } from './models/group.resource-type';
 
 /**
  * Provides methods to retrieve eperson group resources.
  */
-@Injectable()
-export class GroupEpersonService extends EpersonService<Group> {
+@Injectable({
+  providedIn: 'root'
+})
+@dataService(GROUP)
+export class GroupDataService extends DataService<Group> {
   protected linkPath = 'groups';
   protected browseEndpoint = '';
 
   constructor(
     protected comparator: DSOChangeAnalyzer<Group>,
-    protected dataBuildService: NormalizedObjectBuildService,
     protected http: HttpClient,
     protected notificationsService: NotificationsService,
     protected requestService: RequestService,
diff --git a/src/app/core/eperson/models/eperson.model.ts b/src/app/core/eperson/models/eperson.model.ts
index d99a059e8b873ed7c0e230e598a04c710388e306..bb990221121d9a963c788d00054d832c46add14f 100644
--- a/src/app/core/eperson/models/eperson.model.ts
+++ b/src/app/core/eperson/models/eperson.model.ts
@@ -1,52 +1,60 @@
+import { autoserialize, deserialize, inheritSerialization } from 'cerialize';
 import { Observable } from 'rxjs';
+import { link, typedObject } from '../../cache/builders/build-decorators';
+import { PaginatedList } from '../../data/paginated-list';
+import { RemoteData } from '../../data/remote-data';
 
 import { DSpaceObject } from '../../shared/dspace-object.model';
+import { HALLink } from '../../shared/hal-link.model';
+import { EPERSON } from './eperson.resource-type';
 import { Group } from './group.model';
-import { RemoteData } from '../../data/remote-data';
-import { PaginatedList } from '../../data/paginated-list';
-import { ResourceType } from '../../shared/resource-type';
+import { GROUP } from './group.resource-type';
 
+@typedObject
+@inheritSerialization(DSpaceObject)
 export class EPerson extends DSpaceObject {
-  static type = new ResourceType('eperson');
+  static type = EPERSON;
 
   /**
    * A string representing the unique handle of this Collection
    */
+  @autoserialize
   public handle: string;
 
-  /**
-   * List of Groups that this EPerson belong to
-   */
-  public groups: Observable<RemoteData<PaginatedList<Group>>>;
-
   /**
    * A string representing the netid of this EPerson
    */
+  @autoserialize
   public netid: string;
 
   /**
    * A string representing the last active date for this EPerson
    */
+  @autoserialize
   public lastActive: string;
 
   /**
    * A boolean representing if this EPerson can log in
    */
+  @autoserialize
   public canLogIn: boolean;
 
   /**
    * The EPerson email address
    */
+  @autoserialize
   public email: string;
 
   /**
    * A boolean representing if this EPerson require certificate
    */
+  @autoserialize
   public requireCertificate: boolean;
 
   /**
    * A boolean representing if this EPerson registered itself
    */
+  @autoserialize
   public selfRegistered: boolean;
 
   /**
@@ -55,4 +63,17 @@ export class EPerson extends DSpaceObject {
   get name(): string {
     return this.firstMetadataValue('eperson.firstname') + ' ' + this.firstMetadataValue('eperson.lastname');
   }
+
+  _links: {
+    self: HALLink;
+    groups: HALLink;
+  };
+
+  /**
+   * The list of Groups this EPerson is part of
+   * Will be undefined unless the groups {@link HALLink} has been resolved.
+   */
+  @link(GROUP, true)
+  public groups?: Observable<RemoteData<PaginatedList<Group>>>;
+
 }
diff --git a/src/app/core/eperson/models/eperson.resource-type.ts b/src/app/core/eperson/models/eperson.resource-type.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8c91b3bca648855a2d7eca3dd4dcd0e46c66817a
--- /dev/null
+++ b/src/app/core/eperson/models/eperson.resource-type.ts
@@ -0,0 +1,10 @@
+import { ResourceType } from '../../shared/resource-type';
+
+/**
+ * The resource type for EPerson
+ *
+ * Needs to be in a separate file to prevent circular
+ * dependencies in webpack.
+ */
+
+export const EPERSON = new ResourceType('eperson');
diff --git a/src/app/core/eperson/models/group.model.ts b/src/app/core/eperson/models/group.model.ts
index 9c14c20de77274b6d2846584d868882b7e490d34..5d531800b86e70b5a2024ac9e389ede0b77dc67d 100644
--- a/src/app/core/eperson/models/group.model.ts
+++ b/src/app/core/eperson/models/group.model.ts
@@ -1,30 +1,44 @@
+import { autoserialize, deserialize, inheritSerialization } from 'cerialize';
 import { Observable } from 'rxjs';
-
-import { DSpaceObject } from '../../shared/dspace-object.model';
+import { link, typedObject } from '../../cache/builders/build-decorators';
 import { PaginatedList } from '../../data/paginated-list';
 import { RemoteData } from '../../data/remote-data';
-import { ResourceType } from '../../shared/resource-type';
 
+import { DSpaceObject } from '../../shared/dspace-object.model';
+import { HALLink } from '../../shared/hal-link.model';
+import { GROUP } from './group.resource-type';
+
+@typedObject
+@inheritSerialization(DSpaceObject)
 export class Group extends DSpaceObject {
-  static type = new ResourceType('group');
+  static type = GROUP;
 
   /**
-   * List of Groups that this Group belong to
+   * A string representing the unique handle of this Group
    */
-  public groups: Observable<RemoteData<PaginatedList<Group>>>;
+  @autoserialize
+  public handle: string;
 
   /**
-   * A string representing the unique handle of this Group
+   * A boolean denoting whether this Group is permanent
    */
-  public handle: string;
+  @autoserialize
+  public permanent: boolean;
 
   /**
-   * A string representing the name of this Group
+   * The {@link HALLink}s for this Group
    */
-  public name: string;
+  @deserialize
+  _links: {
+    self: HALLink;
+    groups: HALLink;
+  };
 
   /**
-   * A string representing the name of this Group is permanent
+   * The list of Groups this Group is part of
+   * Will be undefined unless the groups {@link HALLink} has been resolved.
    */
-  public permanent: boolean;
+  @link(GROUP, true)
+  public groups?: Observable<RemoteData<PaginatedList<Group>>>;
+
 }
diff --git a/src/app/core/eperson/models/group.resource-type.ts b/src/app/core/eperson/models/group.resource-type.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ad4a8bbccb2591283f8d05c2187a7b3b171b3be3
--- /dev/null
+++ b/src/app/core/eperson/models/group.resource-type.ts
@@ -0,0 +1,10 @@
+import { ResourceType } from '../../shared/resource-type';
+
+/**
+ * The resource type for Group
+ *
+ * Needs to be in a separate file to prevent circular
+ * dependencies in webpack.
+ */
+
+export const GROUP = new ResourceType('group');
diff --git a/src/app/core/eperson/models/normalized-eperson.model.ts b/src/app/core/eperson/models/normalized-eperson.model.ts
deleted file mode 100644
index 489bf259c6e33b348dec73ccfabb4624010f7989..0000000000000000000000000000000000000000
--- a/src/app/core/eperson/models/normalized-eperson.model.ts
+++ /dev/null
@@ -1,61 +0,0 @@
-import { autoserialize, deserialize, inheritSerialization } from 'cerialize';
-
-import { CacheableObject } from '../../cache/object-cache.reducer';
-import { NormalizedDSpaceObject } from '../../cache/models/normalized-dspace-object.model';
-import { EPerson } from './eperson.model';
-import { mapsTo, relationship } from '../../cache/builders/build-decorators';
-import { Group } from './group.model';
-
-@mapsTo(EPerson)
-@inheritSerialization(NormalizedDSpaceObject)
-export class NormalizedEPerson extends NormalizedDSpaceObject<EPerson> implements CacheableObject {
-
-  /**
-   * A string representing the unique handle of this EPerson
-   */
-  @autoserialize
-  public handle: string;
-
-  /**
-   * List of Groups that this EPerson belong to
-   */
-  @deserialize
-  @relationship(Group, true)
-  groups: string[];
-
-  /**
-   * A string representing the netid of this EPerson
-   */
-  @autoserialize
-  public netid: string;
-
-  /**
-   * A string representing the last active date for this EPerson
-   */
-  @autoserialize
-  public lastActive: string;
-
-  /**
-   * A boolean representing if this EPerson can log in
-   */
-  @autoserialize
-  public canLogIn: boolean;
-
-  /**
-   * The EPerson email address
-   */
-  @autoserialize
-  public email: string;
-
-  /**
-   * A boolean representing if this EPerson require certificate
-   */
-  @autoserialize
-  public requireCertificate: boolean;
-
-  /**
-   * A boolean representing if this EPerson registered itself
-   */
-  @autoserialize
-  public selfRegistered: boolean;
-}
diff --git a/src/app/core/eperson/models/normalized-group.model.ts b/src/app/core/eperson/models/normalized-group.model.ts
deleted file mode 100644
index 72b4e7b1a4429c9f5b5f7d0cd6ee5cd9098f31d5..0000000000000000000000000000000000000000
--- a/src/app/core/eperson/models/normalized-group.model.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-import { autoserialize, deserialize, inheritSerialization } from 'cerialize';
-
-import { CacheableObject } from '../../cache/object-cache.reducer';
-import { NormalizedDSpaceObject } from '../../cache/models/normalized-dspace-object.model';
-import { mapsTo, relationship } from '../../cache/builders/build-decorators';
-import { Group } from './group.model';
-
-@mapsTo(Group)
-@inheritSerialization(NormalizedDSpaceObject)
-export class NormalizedGroup extends NormalizedDSpaceObject<Group> implements CacheableObject {
-
-  /**
-   * List of Groups that this Group belong to
-   */
-  @deserialize
-  @relationship(Group, true)
-  groups: string[];
-
-  /**
-   * A string representing the unique handle of this Group
-   */
-  @autoserialize
-  public handle: string;
-
-  /**
-   * A string representing the name of this Group
-   */
-  @autoserialize
-  public name: string;
-
-  /**
-   * A string representing the name of this Group is permanent
-   */
-  @autoserialize
-  public permanent: boolean;
-}
diff --git a/src/app/core/eperson/models/workflowitem.resource-type.ts b/src/app/core/eperson/models/workflowitem.resource-type.ts
new file mode 100644
index 0000000000000000000000000000000000000000..001b6b3f33420d5f1bfaa72ca0487787c980a635
--- /dev/null
+++ b/src/app/core/eperson/models/workflowitem.resource-type.ts
@@ -0,0 +1,3 @@
+import { ResourceType } from '../../shared/resource-type';
+
+export const WORKFLOWITEM = new ResourceType('workflowitem');
diff --git a/src/app/core/index/index.actions.ts b/src/app/core/index/index.actions.ts
index 42804dbe26a93814cf6435c100324fba86f1ce6c..d31f6ee2bd4e203413dbd2597cbae8573180d5d4 100644
--- a/src/app/core/index/index.actions.ts
+++ b/src/app/core/index/index.actions.ts
@@ -91,4 +91,4 @@ export class RemoveFromIndexBySubstringAction implements Action {
 /**
  * A type to encompass all HrefIndexActions
  */
-export type IndexAction = AddToIndexAction | RemoveFromIndexByValueAction;
+export type IndexAction = AddToIndexAction | RemoveFromIndexByValueAction | RemoveFromIndexBySubstringAction;
diff --git a/src/app/core/index/index.effects.ts b/src/app/core/index/index.effects.ts
index 61cf313ab1a8fc785b582406ec0ef405b6f2b56a..c9f6eace8f9ebb7bcbc54a9285ba3245942c63b3 100644
--- a/src/app/core/index/index.effects.ts
+++ b/src/app/core/index/index.effects.ts
@@ -24,7 +24,7 @@ export class UUIDIndexEffects {
         return new AddToIndexAction(
           IndexName.OBJECT,
           action.payload.objectToCache.uuid,
-          action.payload.objectToCache.self
+          action.payload.objectToCache._links.self.href
         );
       })
     );
diff --git a/src/app/core/index/index.reducer.ts b/src/app/core/index/index.reducer.ts
index b4cd8aa84b7425d6c76829f0a5c227983d1911fb..616363ff7ae748b1936a1f8dad81fd5146848ec9 100644
--- a/src/app/core/index/index.reducer.ts
+++ b/src/app/core/index/index.reducer.ts
@@ -126,7 +126,7 @@ function removeFromIndexByValue(state: MetaIndexState, action: RemoveFromIndexBy
  * @return MetaIndexState
  *    the new state
  */
-function removeFromIndexBySubstring(state: MetaIndexState, action: RemoveFromIndexByValueAction): MetaIndexState {
+function removeFromIndexBySubstring(state: MetaIndexState, action: RemoveFromIndexByValueAction | RemoveFromIndexBySubstringAction): MetaIndexState {
   const subState = state[action.payload.name];
   const newSubState = Object.create(null);
   for (const value in subState) {
diff --git a/src/app/core/integration/integration-response-parsing.service.spec.ts b/src/app/core/integration/integration-response-parsing.service.spec.ts
index 4187606265e9e70cfaf547317aeea38f65894ec8..8cc139744c9dbb202e59cc20bf0102b837b6ef1c 100644
--- a/src/app/core/integration/integration-response-parsing.service.spec.ts
+++ b/src/app/core/integration/integration-response-parsing.service.spec.ts
@@ -1,22 +1,21 @@
-import { ErrorResponse, IntegrationSuccessResponse } from '../cache/response.models';
-
-import { ObjectCacheService } from '../cache/object-cache.service';
+import { Store } from '@ngrx/store';
 import { GlobalConfig } from '../../../config/global-config.interface';
 
-import { Store } from '@ngrx/store';
+import { ObjectCacheService } from '../cache/object-cache.service';
+import { ErrorResponse, IntegrationSuccessResponse } from '../cache/response.models';
 import { CoreState } from '../core.reducers';
-import { IntegrationResponseParsingService } from './integration-response-parsing.service';
+import { PaginatedList } from '../data/paginated-list';
 import { IntegrationRequest } from '../data/request.models';
-import { AuthorityValue } from './models/authority.value';
 import { PageInfo } from '../shared/page-info.model';
-import { PaginatedList } from '../data/paginated-list';
+import { IntegrationResponseParsingService } from './integration-response-parsing.service';
+import { AuthorityValue } from './models/authority.value';
 
 describe('IntegrationResponseParsingService', () => {
   let service: IntegrationResponseParsingService;
 
   const EnvConfig = {} as GlobalConfig;
   const store = {} as Store<CoreState>;
-  const objectCacheService = new ObjectCacheService(store);
+  const objectCacheService = new ObjectCacheService(store, undefined);
   const name = 'type';
   const metadata = 'dc.type';
   const query = '';
@@ -33,8 +32,16 @@ describe('IntegrationResponseParsingService', () => {
   let definitions;
 
   function initVars() {
-    pageInfo = Object.assign(new PageInfo(), { elementsPerPage: 5, totalElements: 5, totalPages: 1, currentPage: 1, self: 'https://rest.api/integration/authorities/type/entries'});
-    definitions = new PaginatedList(pageInfo,[
+    pageInfo = Object.assign(new PageInfo(), {
+      elementsPerPage: 5,
+      totalElements: 5,
+      totalPages: 1,
+      currentPage: 1,
+      _links: {
+        self: { href: 'https://rest.api/integration/authorities/type/entries' }
+      }
+    });
+    definitions = new PaginatedList(pageInfo, [
       Object.assign(new AuthorityValue(), {
         type: 'authority',
         display: 'One',
diff --git a/src/app/core/integration/models/authority.resource-type.ts b/src/app/core/integration/models/authority.resource-type.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ec87ddc85f98e537241bb0ce4e8b43eef02774b6
--- /dev/null
+++ b/src/app/core/integration/models/authority.resource-type.ts
@@ -0,0 +1,10 @@
+import { ResourceType } from '../../shared/resource-type';
+
+/**
+ * The resource type for AuthorityValue
+ *
+ * Needs to be in a separate file to prevent circular
+ * dependencies in webpack.
+ */
+
+export const AUTHORITY_VALUE = new ResourceType('authority');
diff --git a/src/app/core/integration/models/authority.value.ts b/src/app/core/integration/models/authority.value.ts
index 4c6a7c01cb0a9ad9f14afe5e217dffc0aeedfc48..4e0183603b35314f51e145f2cc2e1f5fb8bec45b 100644
--- a/src/app/core/integration/models/authority.value.ts
+++ b/src/app/core/integration/models/authority.value.ts
@@ -1,41 +1,59 @@
-import { IntegrationModel } from './integration.model';
+import { autoserialize, deserialize, inheritSerialization } from 'cerialize';
 import { isNotEmpty } from '../../../shared/empty.util';
 import { PLACEHOLDER_PARENT_METADATA } from '../../../shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.model';
 import { OtherInformation } from '../../../shared/form/builder/models/form-field-metadata-value.model';
+import { typedObject } from '../../cache/builders/build-decorators';
+import { HALLink } from '../../shared/hal-link.model';
 import { MetadataValueInterface } from '../../shared/metadata.models';
-import { ResourceType } from '../../shared/resource-type';
+import { AUTHORITY_VALUE } from './authority.resource-type';
+import { IntegrationModel } from './integration.model';
 
 /**
  * Class representing an authority object
  */
+@typedObject
+@inheritSerialization(IntegrationModel)
 export class AuthorityValue extends IntegrationModel implements MetadataValueInterface {
-  static type = new ResourceType('authority');
+  static type = AUTHORITY_VALUE;
 
   /**
    * The identifier of this authority
    */
+  @autoserialize
   id: string;
 
   /**
    * The display value of this authority
    */
+  @autoserialize
   display: string;
 
   /**
    * The value of this authority
    */
+  @autoserialize
   value: string;
 
   /**
    * An object containing additional information related to this authority
    */
+  @autoserialize
   otherInformation: OtherInformation;
 
   /**
    * The language code of this authority value
    */
+  @autoserialize
   language: string;
 
+  /**
+   * The {@link HALLink}s for this AuthorityValue
+   */
+  @deserialize
+  _links: {
+    self: HALLink,
+  };
+
   /**
    * This method checks if authority has an identifier value
    *
diff --git a/src/app/core/integration/models/integration.model.ts b/src/app/core/integration/models/integration.model.ts
index 3158abc7eb3883d28b441ec761680e24969b14b7..d2f21a70c0530c4c52cf9e1ce39fd326259bc168 100644
--- a/src/app/core/integration/models/integration.model.ts
+++ b/src/app/core/integration/models/integration.model.ts
@@ -1,5 +1,6 @@
-import { autoserialize } from 'cerialize';
+import { autoserialize, deserialize } from 'cerialize';
 import { CacheableObject } from '../../cache/object-cache.reducer';
+import { HALLink } from '../../shared/hal-link.model';
 
 export abstract class IntegrationModel implements CacheableObject {
 
@@ -12,9 +13,10 @@ export abstract class IntegrationModel implements CacheableObject {
   @autoserialize
   public type: any;
 
-  @autoserialize
+  @deserialize
   public _links: {
-    [name: string]: string
+    self: HALLink,
+    [name: string]: HALLink
   }
 
 }
diff --git a/src/app/core/integration/models/normalized-authority-value.model.ts b/src/app/core/integration/models/normalized-authority-value.model.ts
deleted file mode 100644
index 5ebb61281d1b3509e5614c7e582dfffddbb131af..0000000000000000000000000000000000000000
--- a/src/app/core/integration/models/normalized-authority-value.model.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-import { autoserialize, inheritSerialization } from 'cerialize';
-import { IntegrationModel } from './integration.model';
-import { mapsTo } from '../../cache/builders/build-decorators';
-import { AuthorityValue } from './authority.value';
-
-/**
- * Normalized model class for an Authority Value
- */
-@mapsTo(AuthorityValue)
-@inheritSerialization(IntegrationModel)
-export class NormalizedAuthorityValue extends IntegrationModel {
-
-  @autoserialize
-  id: string;
-
-  @autoserialize
-  display: string;
-
-  @autoserialize
-  value: string;
-
-  @autoserialize
-  otherInformation: any;
-
-  @autoserialize
-  language: string;
-
-}
diff --git a/src/app/core/metadata/metadata-field.model.ts b/src/app/core/metadata/metadata-field.model.ts
index 45ac4b20516b5b2c167fcf31dd3b755ac471c068..ad7ec59b25ff642e236b61e00778197098afaeb1 100644
--- a/src/app/core/metadata/metadata-field.model.ts
+++ b/src/app/core/metadata/metadata-field.model.ts
@@ -1,44 +1,69 @@
-import { ListableObject } from '../../shared/object-collection/shared/listable-object.model';
+import { autoserialize, deserialize } from 'cerialize';
 import { isNotEmpty } from '../../shared/empty.util';
-import { MetadataSchema } from './metadata-schema.model';
-import { ResourceType } from '../shared/resource-type';
+import { ListableObject } from '../../shared/object-collection/shared/listable-object.model';
+import { link, typedObject } from '../cache/builders/build-decorators';
 import { GenericConstructor } from '../shared/generic-constructor';
+import { HALLink } from '../shared/hal-link.model';
+import { HALResource } from '../shared/hal-resource.model';
+import { ResourceType } from '../shared/resource-type';
+import { excludeFromEquals } from '../utilities/equals.decorators';
+import { METADATA_FIELD } from './metadata-field.resource-type';
+import { MetadataSchema } from './metadata-schema.model';
 
 /**
  * Class the represents a metadata field
  */
-export class MetadataField extends ListableObject {
-  static type = new ResourceType('metadatafield');
+@typedObject
+export class MetadataField extends ListableObject implements HALResource {
+  static type = METADATA_FIELD;
 
   /**
-   * The identifier of this metadata field
+   * The object type
    */
-  id: number;
+  @excludeFromEquals
+  @autoserialize
+  type: ResourceType;
 
   /**
-   * The self link of this metadata field
+   * The identifier of this metadata field
    */
-  self: string;
+  @autoserialize
+  id: number;
 
   /**
    * The element of this metadata field
    */
+  @autoserialize
   element: string;
 
   /**
    * The qualifier of this metadata field
    */
+  @autoserialize
   qualifier: string;
 
   /**
    * The scope note of this metadata field
    */
+  @autoserialize
   scopeNote: string;
 
   /**
-   * The metadata schema object of this metadata field
+   * The {@link HALLink}s for this MetadataField
+   */
+  @deserialize
+  _links: {
+    self: HALLink,
+    schema: HALLink
+  };
+
+  /**
+   * The MetadataSchema for this MetadataField
+   * Will be undefined unless the schema {@link HALLink} has been resolved.
    */
-  schema: MetadataSchema;
+  // TODO the responseparsingservice assumes schemas are always embedded. This should use remotedata, and be a link instead.
+  // @link(METADATA_SCHEMA)
+  schema?: MetadataSchema;
 
   /**
    * Method to print this metadata field as a string
diff --git a/src/app/core/metadata/metadata-field.resource-type.ts b/src/app/core/metadata/metadata-field.resource-type.ts
new file mode 100644
index 0000000000000000000000000000000000000000..53cbedb1eb2f27e622428c18f3b2a44bc0327ca4
--- /dev/null
+++ b/src/app/core/metadata/metadata-field.resource-type.ts
@@ -0,0 +1,10 @@
+import { ResourceType } from '../shared/resource-type';
+
+/**
+ * The resource type for MetadataField
+ *
+ * Needs to be in a separate file to prevent circular
+ * dependencies in webpack.
+ */
+
+export const METADATA_FIELD = new ResourceType('metadatafield');
diff --git a/src/app/core/metadata/metadata-schema.model.ts b/src/app/core/metadata/metadata-schema.model.ts
index 2059b210944b3c84bf7f2dd76bb85bf56c2f67dc..d4d94b878093a3e1435db06d32e4d3c58a47f935 100644
--- a/src/app/core/metadata/metadata-schema.model.ts
+++ b/src/app/core/metadata/metadata-schema.model.ts
@@ -1,33 +1,50 @@
+import { autoserialize, deserialize } from 'cerialize';
 import { ListableObject } from '../../shared/object-collection/shared/listable-object.model';
-import { ResourceType } from '../shared/resource-type';
+import { typedObject } from '../cache/builders/build-decorators';
 import { GenericConstructor } from '../shared/generic-constructor';
+import { HALLink } from '../shared/hal-link.model';
+import { HALResource } from '../shared/hal-resource.model';
+import { ResourceType } from '../shared/resource-type';
+import { excludeFromEquals } from '../utilities/equals.decorators';
+import { METADATA_SCHEMA } from './metadata-schema.resource-type';
 
 /**
  * Class that represents a metadata schema
  */
-export class MetadataSchema extends ListableObject {
-  static type = new ResourceType('metadataschema');
+@typedObject
+export class MetadataSchema extends ListableObject implements HALResource {
+  static type = METADATA_SCHEMA;
 
   /**
    * The unique identifier for this metadata schema
    */
+  @autoserialize
   id: number;
 
   /**
-   * The REST link to itself
+   * The object type
    */
-  self: string;
+  @excludeFromEquals
+  @autoserialize
+  type: ResourceType;
 
   /**
    * A unique prefix that defines this schema
    */
+  @autoserialize
   prefix: string;
 
   /**
    * The namespace of this metadata schema
    */
+  @autoserialize
   namespace: string;
 
+  @deserialize
+  _links: {
+    self: HALLink,
+  };
+
   /**
    * Method that returns as which type of object this object should be rendered
    */
diff --git a/src/app/core/metadata/metadata-schema.resource-type.ts b/src/app/core/metadata/metadata-schema.resource-type.ts
new file mode 100644
index 0000000000000000000000000000000000000000..462c9957c7f55cc6e58d51b1d603f7ad1a784c02
--- /dev/null
+++ b/src/app/core/metadata/metadata-schema.resource-type.ts
@@ -0,0 +1,10 @@
+import { ResourceType } from '../shared/resource-type';
+
+/**
+ * The resource type for MetadataSchema
+ *
+ * Needs to be in a separate file to prevent circular
+ * dependencies in webpack.
+ */
+
+export const METADATA_SCHEMA = new ResourceType('metadataschema');
diff --git a/src/app/core/metadata/metadata.service.spec.ts b/src/app/core/metadata/metadata.service.spec.ts
index 80ce33b370f7837c22d94c58aed4202fc0a9d75f..e3f6c3401c8de6aeb5f5e6304f7c2c61284971f7 100644
--- a/src/app/core/metadata/metadata.service.spec.ts
+++ b/src/app/core/metadata/metadata.service.spec.ts
@@ -1,44 +1,58 @@
-import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
-import { RouterTestingModule } from '@angular/router/testing';
-
 import { CommonModule, Location } from '@angular/common';
+import { HttpClient } from '@angular/common/http';
 import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
+import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
 import { Meta, MetaDefinition, Title } from '@angular/platform-browser';
 import { ActivatedRoute, Router } from '@angular/router';
-
-import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
+import { RouterTestingModule } from '@angular/router/testing';
 
 import { Store, StoreModule } from '@ngrx/store';
-import { Observable, of as observableOf } from 'rxjs';
-import { UUIDService } from '../shared/uuid.service';
-
-import { MetadataService } from './metadata.service';
 
-import { CoreState } from '../core.reducers';
-
-import { GlobalConfig } from '../../../config/global-config.interface';
+import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
+import { Observable } from 'rxjs';
+import { EmptyError } from 'rxjs/internal-compatibility';
 import { ENV_CONFIG, GLOBAL_CONFIG } from '../../../config';
 
-import { ItemDataService } from '../data/item-data.service';
-import { ObjectCacheService } from '../cache/object-cache.service';
-import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
-import { RequestService } from '../data/request.service';
+import { GlobalConfig } from '../../../config/global-config.interface';
 
 import { RemoteData } from '../../core/data/remote-data';
 import { Item } from '../../core/shared/item.model';
 
-import { MockItem } from '../../shared/mocks/mock-item';
+import {
+  MockBitstream1,
+  MockBitstream2,
+  MockBitstreamFormat1,
+  MockBitstreamFormat2,
+  MockItem
+} from '../../shared/mocks/mock-item';
 import { MockTranslateLoader } from '../../shared/mocks/mock-translate-loader';
-import { BrowseService } from '../browse/browse.service';
-import { HALEndpointService } from '../shared/hal-endpoint.service';
-import { AuthService } from '../auth/auth.service';
 import { NotificationsService } from '../../shared/notifications/notifications.service';
-import { HttpClient } from '@angular/common/http';
-import { EmptyError } from 'rxjs/internal-compatibility';
-import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service';
+import { createSuccessfulRemoteDataObject$ } from '../../shared/testing/utils';
+import { FollowLinkConfig } from '../../shared/utils/follow-link-config.model';
+import { AuthService } from '../auth/auth.service';
+import { BrowseService } from '../browse/browse.service';
+import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
+import { ObjectCacheService } from '../cache/object-cache.service';
+
+import { CoreState } from '../core.reducers';
+import { BitstreamDataService } from '../data/bitstream-data.service';
+import { BitstreamFormatDataService } from '../data/bitstream-format-data.service';
+import { CommunityDataService } from '../data/community-data.service';
+import { DefaultChangeAnalyzer } from '../data/default-change-analyzer.service';
 import { DSOChangeAnalyzer } from '../data/dso-change-analyzer.service';
+
+import { ItemDataService } from '../data/item-data.service';
+import { PaginatedList } from '../data/paginated-list';
+import { FindListOptions } from '../data/request.models';
+import { RequestService } from '../data/request.service';
+import { BitstreamFormat } from '../shared/bitstream-format.model';
+import { Bitstream } from '../shared/bitstream.model';
+import { HALEndpointService } from '../shared/hal-endpoint.service';
 import { MetadataValue } from '../shared/metadata.models';
-import { createSuccessfulRemoteDataObject$ } from '../../shared/testing/utils';
+import { PageInfo } from '../shared/page-info.model';
+import { UUIDService } from '../shared/uuid.service';
+
+import { MetadataService } from './metadata.service';
 
 /* tslint:disable:max-classes-per-file */
 @Component({
@@ -50,13 +64,15 @@ class TestComponent {
   }
 }
 
-@Component({ template: '' }) class DummyItemComponent {
+@Component({ template: '' })
+class DummyItemComponent {
   constructor(private route: ActivatedRoute, private items: ItemDataService, private metadata: MetadataService) {
     this.route.params.subscribe((params) => {
       this.metadata.processRemoteData(this.items.findById(params.id));
     });
   }
 }
+
 /* tslint:enable:max-classes-per-file */
 
 describe('MetadataService', () => {
@@ -88,10 +104,33 @@ describe('MetadataService', () => {
     store = new Store<CoreState>(undefined, undefined, undefined);
     spyOn(store, 'dispatch');
 
-    objectCacheService = new ObjectCacheService(store);
+    objectCacheService = new ObjectCacheService(store, undefined);
     uuidService = new UUIDService();
     requestService = new RequestService(objectCacheService, uuidService, store, undefined);
-    remoteDataBuildService = new RemoteDataBuildService(objectCacheService, requestService);
+    remoteDataBuildService = new RemoteDataBuildService(objectCacheService, undefined, requestService);
+    const mockBitstreamDataService = {
+      findAllByItemAndBundleName(item: Item, bundleName: string, options?: FindListOptions, ...linksToFollow: Array<FollowLinkConfig<Bitstream>>): Observable<RemoteData<PaginatedList<Bitstream>>> {
+        if (item.equals(MockItem)) {
+          return createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [MockBitstream1, MockBitstream2]));
+        } else {
+          return createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), []));
+        }
+      },
+    };
+    const mockBitstreamFormatDataService = {
+      findByBitstream(bitstream: Bitstream): Observable<RemoteData<BitstreamFormat>> {
+        switch (bitstream) {
+          case MockBitstream1:
+            return createSuccessfulRemoteDataObject$(MockBitstreamFormat1);
+            break;
+          case MockBitstream2:
+            return createSuccessfulRemoteDataObject$(MockBitstreamFormat2);
+            break;
+          default:
+            return createSuccessfulRemoteDataObject$(new BitstreamFormat());
+        }
+      }
+    };
 
     TestBed.configureTestingModule({
       imports: [
@@ -105,7 +144,12 @@ describe('MetadataService', () => {
         }),
         RouterTestingModule.withRoutes([
           { path: 'items/:id', component: DummyItemComponent, pathMatch: 'full' },
-          { path: 'other', component: DummyItemComponent, pathMatch: 'full', data: { title: 'Dummy Title', description: 'This is a dummy item component for testing!' } }
+          {
+            path: 'other',
+            component: DummyItemComponent,
+            pathMatch: 'full',
+            data: { title: 'Dummy Title', description: 'This is a dummy item component for testing!' }
+          }
         ])
       ],
       declarations: [
@@ -121,8 +165,11 @@ describe('MetadataService', () => {
         { provide: AuthService, useValue: {} },
         { provide: NotificationsService, useValue: {} },
         { provide: HttpClient, useValue: {} },
-        { provide: NormalizedObjectBuildService, useValue: {} },
         { provide: DSOChangeAnalyzer, useValue: {} },
+        { provide: CommunityDataService, useValue: {} },
+        { provide: DefaultChangeAnalyzer, useValue: {} },
+        { provide: BitstreamFormatDataService, useValue: mockBitstreamFormatDataService },
+        { provide: BitstreamDataService, useValue: mockBitstreamDataService },
         Meta,
         Title,
         ItemDataService,
@@ -193,7 +240,8 @@ describe('MetadataService', () => {
   describe('when the item has no bitstreams', () => {
 
     beforeEach(() => {
-      spyOn(MockItem, 'getFiles').and.returnValue(observableOf([]));
+      // this.bitstreamDataService.findAllByItemAndBundleName(this.item, 'ORIGINAL')
+      // spyOn(MockItem, 'getFiles').and.returnValue(observableOf([]));
     });
 
     it('processRemoteData should not produce an EmptyError', fakeAsync(() => {
@@ -212,7 +260,7 @@ describe('MetadataService', () => {
 
   const mockType = (mockItem: Item, type: string): Item => {
     const typedMockItem = Object.assign(new Item(), mockItem) as Item;
-    typedMockItem.metadata['dc.type'] = [ { value: type } ] as MetadataValue[];
+    typedMockItem.metadata['dc.type'] = [{ value: type }] as MetadataValue[];
     return typedMockItem;
   };
 
diff --git a/src/app/core/metadata/metadata.service.ts b/src/app/core/metadata/metadata.service.ts
index 2b1cf4ffc158b97ae3521073f93f13ee47c8d53a..dbba9d83f6797aad1debe51837754a28b7672e02 100644
--- a/src/app/core/metadata/metadata.service.ts
+++ b/src/app/core/metadata/metadata.service.ts
@@ -1,29 +1,26 @@
-import {
-  catchError,
-  distinctUntilKeyChanged,
-  filter,
-  first,
-  map,
-  take
-} from 'rxjs/operators';
 import { Inject, Injectable } from '@angular/core';
-import { ActivatedRoute, NavigationEnd, Router } from '@angular/router';
 
 import { Meta, MetaDefinition, Title } from '@angular/platform-browser';
+import { ActivatedRoute, NavigationEnd, Router } from '@angular/router';
 
 import { TranslateService } from '@ngx-translate/core';
 
 import { BehaviorSubject, Observable } from 'rxjs';
+import { catchError, distinctUntilKeyChanged, filter, first, map, take } from 'rxjs/operators';
+
+import { GLOBAL_CONFIG, GlobalConfig } from '../../../config';
+import { hasValue, isNotEmpty } from '../../shared/empty.util';
+import { DSONameService } from '../breadcrumbs/dso-name.service';
+import { CacheableObject } from '../cache/object-cache.reducer';
+import { BitstreamDataService } from '../data/bitstream-data.service';
+import { BitstreamFormatDataService } from '../data/bitstream-format-data.service';
 
 import { RemoteData } from '../data/remote-data';
+import { BitstreamFormat } from '../shared/bitstream-format.model';
 import { Bitstream } from '../shared/bitstream.model';
-import { CacheableObject } from '../cache/object-cache.reducer';
 import { DSpaceObject } from '../shared/dspace-object.model';
 import { Item } from '../shared/item.model';
-
-import { GLOBAL_CONFIG, GlobalConfig } from '../../../config';
-import { BitstreamFormat } from '../shared/bitstream-format.model';
-import { hasValue, isNotEmpty } from '../../shared/empty.util';
+import { getFirstSucceededRemoteDataPayload, getFirstSucceededRemoteListPayload } from '../shared/operators';
 
 @Injectable()
 export class MetadataService {
@@ -39,6 +36,9 @@ export class MetadataService {
     private translate: TranslateService,
     private meta: Meta,
     private title: Title,
+    private dsoNameService: DSONameService,
+    private bitstreamDataService: BitstreamDataService,
+    private bitstreamFormatDataService: BitstreamFormatDataService,
     @Inject(GLOBAL_CONFIG) private envConfig: GlobalConfig
   ) {
     // TODO: determine what open graph meta tags are needed and whether
@@ -156,7 +156,7 @@ export class MetadataService {
    * Add <meta name="title" ... >  to the <head>
    */
   private setTitleTag(): void {
-    const value = this.getMetaTagValue('dc.title');
+    const value = this.dsoNameService.getName(this.currentObject.getValue());
     this.addMetaTag('title', value);
     this.title.setTitle(value);
   }
@@ -266,8 +266,9 @@ export class MetadataService {
   private setCitationPdfUrlTag(): void {
     if (this.currentObject.value instanceof Item) {
       const item = this.currentObject.value as Item;
-      item.getFiles()
+      this.bitstreamDataService.findAllByItemAndBundleName(item, 'ORIGINAL')
         .pipe(
+          getFirstSucceededRemoteListPayload(),
           first((files) => isNotEmpty(files)),
           catchError((error) => {
             console.debug(error.message);
@@ -275,19 +276,13 @@ export class MetadataService {
           }))
         .subscribe((bitstreams: Bitstream[]) => {
           for (const bitstream of bitstreams) {
-            bitstream.format.pipe(
-              first(),
-              catchError((error: Error) => {
-                console.debug(error.message);
-                return []
-              }),
-              map((rd: RemoteData<BitstreamFormat>) => rd.payload),
-              filter((format: BitstreamFormat) => hasValue(format)))
-              .subscribe((format: BitstreamFormat) => {
-                if (format.mimetype === 'application/pdf') {
-                  this.addMetaTag('citation_pdf_url', bitstream.content);
-                }
-              });
+            this.bitstreamFormatDataService.findByBitstream(bitstream).pipe(
+              getFirstSucceededRemoteDataPayload()
+            ).subscribe((format: BitstreamFormat) => {
+              if (format.mimetype === 'application/pdf') {
+                this.addMetaTag('citation_pdf_url', bitstream._links.content.href);
+              }
+            });
           }
         });
     }
@@ -367,7 +362,7 @@ export class MetadataService {
 
   public clearMetaTags() {
     this.tagStore.forEach((tags: MetaDefinition[], property: string) => {
-      this.meta.removeTag("property='" + property + "'");
+      this.meta.removeTag('property=\'' + property + '\'');
     });
     this.tagStore.clear();
   }
diff --git a/src/app/core/metadata/normalized-metadata-field.model.ts b/src/app/core/metadata/normalized-metadata-field.model.ts
deleted file mode 100644
index 3d8750778d30eabd4a1d628e1064704b2a95bd16..0000000000000000000000000000000000000000
--- a/src/app/core/metadata/normalized-metadata-field.model.ts
+++ /dev/null
@@ -1,50 +0,0 @@
-import { autoserialize, deserialize, inheritSerialization } from 'cerialize';
-import { mapsTo, relationship } from '../cache/builders/build-decorators';
-import { MetadataField } from './metadata-field.model';
-import { NormalizedObject } from '../cache/models/normalized-object.model';
-import { MetadataSchema } from './metadata-schema.model';
-
-/**
- * Class the represents a normalized metadata field
- */
-@mapsTo(MetadataField)
-@inheritSerialization(NormalizedObject)
-export class NormalizedMetadataField extends NormalizedObject<MetadataField> {
-
-  /**
-   * The identifier of this normalized metadata field
-   */
-  @autoserialize
-  id: number;
-
-  /**
-   * The self link of this normalized metadata field
-   */
-  @autoserialize
-  self: string;
-
-  /**
-   * The element of this normalized metadata field
-   */
-  @autoserialize
-  element: string;
-
-  /**
-   * The qualifier of this normalized metadata field
-   */
-  @autoserialize
-  qualifier: string;
-
-  /**
-   * The scope note of this normalized metadata field
-   */
-  @autoserialize
-  scopeNote: string;
-
-  /**
-   * The link to the metadata schema of this normalized metadata field
-   */
-  @deserialize
-  @relationship(MetadataSchema)
-  schema: string;
-}
diff --git a/src/app/core/metadata/normalized-metadata-schema.model.ts b/src/app/core/metadata/normalized-metadata-schema.model.ts
deleted file mode 100644
index 4b534725f40fdaf936c94b050dacae01f04963d1..0000000000000000000000000000000000000000
--- a/src/app/core/metadata/normalized-metadata-schema.model.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-import { autoserialize, inheritSerialization } from 'cerialize';
-import { NormalizedObject } from '../cache/models/normalized-object.model';
-import { mapsTo } from '../cache/builders/build-decorators';
-import { MetadataSchema } from './metadata-schema.model';
-
-/**
- * Normalized class for a DSpace MetadataSchema
- */
-@mapsTo(MetadataSchema)
-@inheritSerialization(NormalizedObject)
-export class NormalizedMetadataSchema extends NormalizedObject<MetadataSchema> {
-  /**
-   * The unique identifier for this schema
-   */
-  @autoserialize
-  id: number;
-
-  /**
-   * The REST link to itself
-   */
-  @autoserialize
-  self: string;
-
-  /**
-   * A unique prefix that defines this schema
-   */
-  @autoserialize
-  prefix: string;
-
-  /**
-   * The namespace for this schema
-   */
-  @autoserialize
-  namespace: string;
-
-}
diff --git a/src/app/core/registry/registry-bitstreamformats-response.model.ts b/src/app/core/registry/registry-bitstreamformats-response.model.ts
index ddf926f3be81458156f6c18f6c55c20dfe52bc28..4da30b4ffc912547dfafaf6b506d452c77e6d82f 100644
--- a/src/app/core/registry/registry-bitstreamformats-response.model.ts
+++ b/src/app/core/registry/registry-bitstreamformats-response.model.ts
@@ -1,16 +1,24 @@
 import { autoserialize, deserialize } from 'cerialize';
+import { BITSTREAM_FORMAT } from '../shared/bitstream-format.resource-type';
+import { HALLink } from '../shared/hal-link.model';
 import { PageInfo } from '../shared/page-info.model';
 import { BitstreamFormat } from '../shared/bitstream-format.model';
-import { relationship } from '../cache/builders/build-decorators';
+import { link } from '../cache/builders/build-decorators';
 
 export class RegistryBitstreamformatsResponse {
-  @deserialize
-  @relationship(BitstreamFormat, true)
-  bitstreamformats: BitstreamFormat[];
-
   @autoserialize
   page: PageInfo;
 
-  @autoserialize
-  self: string;
+  /**
+   * The {@link HALLink}s for this RegistryBitstreamformatsResponse
+   */
+  @deserialize
+  _links: {
+    self: HALLink;
+    bitstreamformats: HALLink;
+  };
+
+  @link(BITSTREAM_FORMAT)
+  bitstreamformats?: BitstreamFormat[];
+
 }
diff --git a/src/app/core/registry/registry-metadatafields-response.model.ts b/src/app/core/registry/registry-metadatafields-response.model.ts
index 984603e42ed63de37ae9f65d298006a5ad26bdbb..5dc492ab0f53f1e1b8b0885dafaa071e24ba5a61 100644
--- a/src/app/core/registry/registry-metadatafields-response.model.ts
+++ b/src/app/core/registry/registry-metadatafields-response.model.ts
@@ -1,20 +1,30 @@
-import { PageInfo } from '../shared/page-info.model';
 import { autoserialize, deserialize } from 'cerialize';
-import { ResourceType } from '../shared/resource-type';
-import { relationship } from '../cache/builders/build-decorators';
-import { NormalizedMetadataField } from '../metadata/normalized-metadata-field.model';
+import { typedObject } from '../cache/builders/build-decorators';
 import { MetadataField } from '../metadata/metadata-field.model';
+import { METADATA_FIELD } from '../metadata/metadata-field.resource-type';
+import { HALLink } from '../shared/hal-link.model';
+import { PageInfo } from '../shared/page-info.model';
+import { ResourceType } from '../shared/resource-type';
+import { excludeFromEquals } from '../utilities/equals.decorators';
 
 /**
  * Class that represents a response with a registry's metadata fields
  */
+@typedObject
 export class RegistryMetadatafieldsResponse {
-  static type = new ResourceType('metadatafield');
+  static type = METADATA_FIELD;
+
+  /**
+   * The object type
+   */
+  @excludeFromEquals
+  @autoserialize
+  type: ResourceType;
+
   /**
    * List of metadata fields in the response
    */
   @deserialize
-  @relationship(MetadataField, true)
   metadatafields: MetadataField[];
 
   /**
@@ -28,4 +38,9 @@ export class RegistryMetadatafieldsResponse {
    */
   @autoserialize
   self: string;
+
+  @deserialize
+  _links: {
+    self: HALLink,
+  }
 }
diff --git a/src/app/core/registry/registry-metadataschemas-response.model.ts b/src/app/core/registry/registry-metadataschemas-response.model.ts
index fc53b354a59e3b7f2f825ce3c39ea40e716e7e14..7a485d8849b05f8868edccf5c896781cc16c9515 100644
--- a/src/app/core/registry/registry-metadataschemas-response.model.ts
+++ b/src/app/core/registry/registry-metadataschemas-response.model.ts
@@ -1,11 +1,9 @@
 import { PageInfo } from '../shared/page-info.model';
 import { autoserialize, deserialize } from 'cerialize';
 import { MetadataSchema } from '../metadata/metadata-schema.model';
-import { relationship } from '../cache/builders/build-decorators';
 
 export class RegistryMetadataschemasResponse {
   @deserialize
-  @relationship(MetadataSchema, true)
   metadataschemas: MetadataSchema[];
 
   @autoserialize
diff --git a/src/app/core/registry/registry.service.spec.ts b/src/app/core/registry/registry.service.spec.ts
index 03a7c132deefb24d49e2f8fd0bafa33ee0311e19..b466693649971968ea6b1c8873fa89f18639e635 100644
--- a/src/app/core/registry/registry.service.spec.ts
+++ b/src/app/core/registry/registry.service.spec.ts
@@ -1,30 +1,10 @@
-import { TestBed } from '@angular/core/testing';
-import { RegistryService } from './registry.service';
 import { CommonModule } from '@angular/common';
-import { RequestService } from '../data/request.service';
-import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
-import { HALEndpointService } from '../shared/hal-endpoint.service';
-import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model';
-import { combineLatest as observableCombineLatest, Observable, of as observableOf } from 'rxjs';
-import { RequestEntry } from '../data/request.reducer';
-import { RemoteData } from '../data/remote-data';
-import { PageInfo } from '../shared/page-info.model';
-import { getMockRequestService } from '../../shared/mocks/mock-request.service';
-
-import {
-  RegistryMetadatafieldsSuccessResponse,
-  RegistryMetadataschemasSuccessResponse,
-  RestResponse
-} from '../cache/response.models';
 import { Component } from '@angular/core';
-import { RegistryMetadataschemasResponse } from './registry-metadataschemas-response.model';
-import { RegistryMetadatafieldsResponse } from './registry-metadatafields-response.model';
-import { map } from 'rxjs/operators';
+import { TestBed } from '@angular/core/testing';
 import { Store, StoreModule } from '@ngrx/store';
-import { MockStore } from '../../shared/testing/mock-store';
-import { NotificationsService } from '../../shared/notifications/notifications.service';
-import { NotificationsServiceStub } from '../../shared/testing/notifications-service-stub';
 import { TranslateModule } from '@ngx-translate/core';
+import { combineLatest as observableCombineLatest, Observable, of as observableOf } from 'rxjs';
+import { map } from 'rxjs/operators';
 import {
   MetadataRegistryCancelFieldAction,
   MetadataRegistryCancelSchemaAction,
@@ -37,12 +17,31 @@ import {
   MetadataRegistrySelectFieldAction,
   MetadataRegistrySelectSchemaAction
 } from '../../+admin/admin-registries/metadata-registry/metadata-registry.actions';
-import { ResourceType } from '../shared/resource-type';
-import { MetadataSchema } from '../metadata/metadata-schema.model';
-import { MetadataField } from '../metadata/metadata-field.model';
+import { getMockRequestService } from '../../shared/mocks/mock-request.service';
+import { NotificationsService } from '../../shared/notifications/notifications.service';
+import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model';
+import { MockStore } from '../../shared/testing/mock-store';
+import { NotificationsServiceStub } from '../../shared/testing/notifications-service-stub';
 import { createSuccessfulRemoteDataObject$ } from '../../shared/testing/utils';
+import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
 
-@Component({template: ''})
+import {
+  RegistryMetadatafieldsSuccessResponse,
+  RegistryMetadataschemasSuccessResponse,
+  RestResponse
+} from '../cache/response.models';
+import { RemoteData } from '../data/remote-data';
+import { RequestEntry } from '../data/request.reducer';
+import { RequestService } from '../data/request.service';
+import { MetadataField } from '../metadata/metadata-field.model';
+import { MetadataSchema } from '../metadata/metadata-schema.model';
+import { HALEndpointService } from '../shared/hal-endpoint.service';
+import { PageInfo } from '../shared/page-info.model';
+import { RegistryMetadatafieldsResponse } from './registry-metadatafields-response.model';
+import { RegistryMetadataschemasResponse } from './registry-metadataschemas-response.model';
+import { RegistryService } from './registry.service';
+
+@Component({ template: '' })
 class DummyComponent {
 }
 
@@ -57,15 +56,18 @@ describe('RegistryService', () => {
   const mockSchemasList = [
     Object.assign(new MetadataSchema(), {
       id: 1,
-      self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadataschemas/1',
+      _links: {
+        self: { href: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadataschemas/1' }
+      },
       prefix: 'dc',
       namespace: 'http://dublincore.org/documents/dcmi-terms/',
       type: MetadataSchema.type
-}),
+    }),
     Object.assign(new MetadataSchema(), {
-
       id: 2,
-      self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadataschemas/2',
+      _links: {
+        self: { href: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadataschemas/2' }
+      },
       prefix: 'mock',
       namespace: 'http://dspace.org/mockschema',
       type: MetadataSchema.type
@@ -73,45 +75,53 @@ describe('RegistryService', () => {
   ];
   const mockFieldsList = [
     Object.assign(new MetadataField(),
-    {
-      id: 1,
-      self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadatafields/8',
-      element: 'contributor',
-      qualifier: 'advisor',
-      scopeNote: null,
-      schema: mockSchemasList[0],
-      type: MetadataField.type
-    }),
+      {
+        id: 1,
+        _links: {
+          self: { href: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadatafields/8' }
+        },
+        element: 'contributor',
+        qualifier: 'advisor',
+        scopeNote: null,
+        schema: mockSchemasList[0],
+        type: MetadataField.type
+      }),
     Object.assign(new MetadataField(),
       {
-      id: 2,
-      self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadatafields/9',
-      element: 'contributor',
-      qualifier: 'author',
-      scopeNote: null,
-      schema: mockSchemasList[0],
-      type: MetadataField.type
-    }),
+        id: 2,
+        _links: {
+          self: { href: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadatafields/9' }
+        },
+        element: 'contributor',
+        qualifier: 'author',
+        scopeNote: null,
+        schema: mockSchemasList[0],
+        type: MetadataField.type
+      }),
     Object.assign(new MetadataField(),
       {
-      id: 3,
-      self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadatafields/10',
-      element: 'contributor',
-      qualifier: 'editor',
-      scopeNote: 'test scope note',
-      schema: mockSchemasList[1],
-      type: MetadataField.type
-    }),
+        id: 3,
+        _links: {
+          self: { href: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadatafields/10' }
+        },
+        element: 'contributor',
+        qualifier: 'editor',
+        scopeNote: 'test scope note',
+        schema: mockSchemasList[1],
+        type: MetadataField.type
+      }),
     Object.assign(new MetadataField(),
       {
-      id: 4,
-      self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadatafields/11',
-      element: 'contributor',
-      qualifier: 'illustrator',
-      scopeNote: null,
-      schema: mockSchemasList[1],
-      type: MetadataField.type
-    })
+        id: 4,
+        _links: {
+          self: { href: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadatafields/11' }
+        },
+        element: 'contributor',
+        qualifier: 'illustrator',
+        scopeNote: null,
+        schema: mockSchemasList[1],
+        type: MetadataField.type
+      })
   ];
 
   const pageInfo = new PageInfo();
@@ -130,7 +140,7 @@ describe('RegistryService', () => {
     toRemoteDataObservable: (requestEntryObs: Observable<RequestEntry>, payloadObs: Observable<any>) => {
       return observableCombineLatest(requestEntryObs,
         payloadObs).pipe(map(([req, pay]) => {
-          return {req, pay};
+          return { req, pay };
         })
       );
     },
@@ -146,11 +156,11 @@ describe('RegistryService', () => {
         DummyComponent
       ],
       providers: [
-        {provide: RequestService, useValue: getMockRequestService()},
-        {provide: RemoteDataBuildService, useValue: rdbStub},
-        {provide: HALEndpointService, useValue: halServiceStub},
-        {provide: Store, useClass: MockStore},
-        {provide: NotificationsService, useValue: new NotificationsServiceStub()},
+        { provide: RequestService, useValue: getMockRequestService() },
+        { provide: RemoteDataBuildService, useValue: rdbStub },
+        { provide: HALEndpointService, useValue: halServiceStub },
+        { provide: Store, useClass: MockStore },
+        { provide: NotificationsService, useValue: new NotificationsServiceStub() },
         RegistryService
       ]
     });
@@ -165,7 +175,7 @@ describe('RegistryService', () => {
       page: pageInfo
     });
     const response = new RegistryMetadataschemasSuccessResponse(queryResponse, 200, 'OK', pageInfo);
-    const responseEntry = Object.assign(new RequestEntry(), {response: response});
+    const responseEntry = Object.assign(new RequestEntry(), { response: response });
 
     beforeEach(() => {
       (registryService as any).requestService.getByHref.and.returnValue(observableOf(responseEntry));
@@ -194,7 +204,7 @@ describe('RegistryService', () => {
       page: pageInfo
     });
     const response = new RegistryMetadataschemasSuccessResponse(queryResponse, 200, 'OK', pageInfo);
-    const responseEntry = Object.assign(new RequestEntry(), {response: response});
+    const responseEntry = Object.assign(new RequestEntry(), { response: response });
 
     beforeEach(() => {
       (registryService as any).requestService.getByHref.and.returnValue(observableOf(responseEntry));
@@ -223,7 +233,7 @@ describe('RegistryService', () => {
       page: pageInfo
     });
     const response = new RegistryMetadatafieldsSuccessResponse(queryResponse, 200, 'OK', pageInfo);
-    const responseEntry = Object.assign(new RequestEntry(), {response: response});
+    const responseEntry = Object.assign(new RequestEntry(), { response: response });
 
     beforeEach(() => {
       (registryService as any).requestService.getByHref.and.returnValue(observableOf(responseEntry));
diff --git a/src/app/core/registry/registry.service.ts b/src/app/core/registry/registry.service.ts
index 3c6de364923a4456c991f2d31327a7361f0989c6..fbc42b26f4a2cbd745c21abf891af37aed1d6384 100644
--- a/src/app/core/registry/registry.service.ts
+++ b/src/app/core/registry/registry.service.ts
@@ -2,6 +2,7 @@ import { combineLatest as observableCombineLatest, Observable } from 'rxjs';
 import { Injectable } from '@angular/core';
 import { RemoteData } from '../data/remote-data';
 import { PaginatedList } from '../data/paginated-list';
+import { DSpaceSerializer } from '../dspace-rest-v2/dspace.serializer';
 import { PageInfo } from '../shared/page-info.model';
 import {
   CreateMetadataFieldRequest,
@@ -48,8 +49,6 @@ import {
   MetadataRegistrySelectSchemaAction
 } from '../../+admin/admin-registries/metadata-registry/metadata-registry.actions';
 import { distinctUntilChanged, flatMap, map, take, tap } from 'rxjs/operators';
-import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer';
-import { NormalizedMetadataSchema } from '../metadata/normalized-metadata-schema.model';
 import { NotificationsService } from '../../shared/notifications/notifications.service';
 import { NotificationOptions } from '../../shared/notifications/models/notification-options.model';
 import { HttpOptions } from '../dspace-rest-v2/dspace-rest-v2.service';
@@ -57,7 +56,7 @@ import { HttpHeaders } from '@angular/common/http';
 import { TranslateService } from '@ngx-translate/core';
 import { MetadataSchema } from '../metadata/metadata-schema.model';
 import { MetadataField } from '../metadata/metadata-field.model';
-import { getMapsToType } from '../cache/builders/build-decorators';
+import { getClassForType } from '../cache/builders/build-decorators';
 
 const metadataRegistryStateSelector = (state: AppState) => state.metadataRegistry;
 const editMetadataSchemaSelector = createSelector(metadataRegistryStateSelector, (metadataState: MetadataRegistryState) => metadataState.editSchema);
@@ -400,7 +399,7 @@ export class RegistryService {
       distinctUntilChanged()
     );
 
-    const serializedSchema = new DSpaceRESTv2Serializer(getMapsToType(MetadataSchema.type)).serialize(schema);
+    const serializedSchema = new DSpaceSerializer(getClassForType(MetadataSchema.type)).serialize(schema);
 
     const request$ = endpoint$.pipe(
       take(1),
diff --git a/src/app/core/services/route.actions.ts b/src/app/core/services/route.actions.ts
index 1f6381d2c67ac06e4b037e2a0ac2536939234e40..1d3381e2ec7a05f44d5422a6546fbd2c47fd0963 100644
--- a/src/app/core/services/route.actions.ts
+++ b/src/app/core/services/route.actions.ts
@@ -162,4 +162,5 @@ export type RouteActions =
   | AddQueryParameterAction
   | AddParameterAction
   | ResetRouteStateAction
-  | SetParameterAction;
+  | SetParameterAction
+  | SetQueryParameterAction;
diff --git a/src/app/core/shared/bitstream-format.model.ts b/src/app/core/shared/bitstream-format.model.ts
index 0e1279e97844bed638ff6b677cf9bbb6ce783c9f..8aeba1e3cd1e07ea47c10bfca07e0d1cf383973f 100644
--- a/src/app/core/shared/bitstream-format.model.ts
+++ b/src/app/core/shared/bitstream-format.model.ts
@@ -1,52 +1,69 @@
-import { CacheableObject, TypedObject } from '../cache/object-cache.reducer';
-import { ResourceType } from './resource-type';
+import { autoserialize, deserialize, deserializeAs } from 'cerialize';
+import { typedObject } from '../cache/builders/build-decorators';
+import { IDToUUIDSerializer } from '../cache/id-to-uuid-serializer';
+import { CacheableObject } from '../cache/object-cache.reducer';
+import { excludeFromEquals } from '../utilities/equals.decorators';
 import { BitstreamFormatSupportLevel } from './bitstream-format-support-level';
+import { BITSTREAM_FORMAT } from './bitstream-format.resource-type';
+import { HALLink } from './hal-link.model';
+import { ResourceType } from './resource-type';
 
 /**
  * Model class for a Bitstream Format
  */
+@typedObject
 export class BitstreamFormat implements CacheableObject {
-  static type = new ResourceType('bitstreamformat');
+  static type = BITSTREAM_FORMAT;
+
+  /**
+   * The object type
+   */
+  @excludeFromEquals
+  @autoserialize
+  type: ResourceType;
 
-  bitstreamformat
   /**
    * Short description of this Bitstream Format
    */
+  @autoserialize
   shortDescription: string;
 
   /**
    * Description of this Bitstream Format
    */
+  @autoserialize
   description: string;
 
   /**
    * String representing the MIME type of this Bitstream Format
    */
+  @autoserialize
   mimetype: string;
 
   /**
    * The level of support the system offers for this Bitstream Format
    */
+  @autoserialize
   supportLevel: BitstreamFormatSupportLevel;
 
   /**
    * True if the Bitstream Format is used to store system information, rather than the content of items in the system
    */
+  @autoserialize
   internal: boolean;
 
   /**
    * String representing this Bitstream Format's file extension
    */
+  @autoserialize
   extensions: string[];
 
-  /**
-   * The link to the rest endpoint where this Bitstream Format can be found
-   */
-  self: string;
-
   /**
    * Universally unique identifier for this Bitstream Format
+   * This UUID is generated client-side and isn't used by the backend.
+   * It is based on the ID, so it will be the same for each refresh.
    */
+  @deserializeAs(new IDToUUIDSerializer('bitstream-format'), 'id')
   uuid: string;
 
   /**
@@ -54,6 +71,14 @@ export class BitstreamFormat implements CacheableObject {
    * Note that this ID is unique for bitstream formats,
    * but might not be unique across different object types
    */
+  @autoserialize
   id: string;
 
+  /**
+   * The {@link HALLink}s for this BitstreamFormat
+   */
+  @deserialize
+  _links: {
+    self: HALLink;
+  }
 }
diff --git a/src/app/core/shared/bitstream-format.resource-type.ts b/src/app/core/shared/bitstream-format.resource-type.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b1184e2665c93f4f87a87e91b9463fffffa54c04
--- /dev/null
+++ b/src/app/core/shared/bitstream-format.resource-type.ts
@@ -0,0 +1,9 @@
+import { ResourceType } from './resource-type';
+
+/**
+ * The resource type for BitstreamFormat
+ *
+ * Needs to be in a separate file to prevent circular
+ * dependencies in webpack.
+ */
+export const BITSTREAM_FORMAT = new ResourceType('bitstreamformat');
diff --git a/src/app/core/shared/bitstream.model.ts b/src/app/core/shared/bitstream.model.ts
index bbd318c144206210d5f3cc6bdb3e80cfe1178131..231d44eeffc2a13fda74ca93074dca969df358da 100644
--- a/src/app/core/shared/bitstream.model.ts
+++ b/src/app/core/shared/bitstream.model.ts
@@ -1,60 +1,60 @@
-import { DSpaceObject } from './dspace-object.model';
+import { autoserialize, deserialize, inheritSerialization } from 'cerialize';
+import { Observable } from 'rxjs';
+import { link, typedObject } from '../cache/builders/build-decorators';
 import { RemoteData } from '../data/remote-data';
-import { Item } from './item.model';
 import { BitstreamFormat } from './bitstream-format.model';
-import { Observable } from 'rxjs';
-import { ResourceType } from './resource-type';
-import { hasValue, isUndefined } from '../../shared/empty.util';
-
-export class Bitstream extends DSpaceObject {
-  static type = new ResourceType('bitstream');
+import { BITSTREAM_FORMAT } from './bitstream-format.resource-type';
+import { BITSTREAM } from './bitstream.resource-type';
+import { DSpaceObject } from './dspace-object.model';
+import { HALLink } from './hal-link.model';
+import { HALResource } from './hal-resource.model';
 
-  private _description: string;
+@typedObject
+@inheritSerialization(DSpaceObject)
+export class Bitstream extends DSpaceObject implements HALResource {
+  static type = BITSTREAM;
 
   /**
    * The size of this bitstream in bytes
    */
+  @autoserialize
   sizeBytes: number;
 
   /**
-   * Get the description of this Bitstream
+   * The description of this Bitstream
    */
-  get description(): string {
-    return (isUndefined(this._description)) ? this.firstMetadataValue('dc.description') : this._description;
-  }
-
-  /**
-   * Set the description of this Bitstream
-   */
-  set description(description) {
-    if (hasValue(this.firstMetadata('dc.description'))) {
-      this.firstMetadata('dc.description').value = description;
-    }
-    this._description = description;
-  }
+  @autoserialize
+  description: string;
 
   /**
    * The name of the Bundle this Bitstream is part of
    */
+  @autoserialize
   bundleName: string;
 
   /**
-   * An array of Bitstream Format of this Bitstream
+   * The {@link HALLink}s for this Bitstream
    */
-  format: Observable<RemoteData<BitstreamFormat>>;
+  @deserialize
+  _links: {
+    self: HALLink;
+    bundle: HALLink;
+    format: HALLink;
+    content: HALLink;
+  };
 
   /**
-   * An array of Items that are direct parents of this Bitstream
+   * The thumbnail for this Bitstream
+   * Needs to be resolved first, but isn't available as a {@link HALLink} yet
+   * Use BitstreamDataService.getThumbnailFor(…) for now.
    */
-  parents: Observable<RemoteData<Item[]>>;
+  thumbnail?: Observable<RemoteData<Bitstream>>;
 
   /**
-   * The Bundle that owns this Bitstream
+   * The BitstreamFormat of this Bitstream
+   * Will be undefined unless the format {@link HALLink} has been resolved.
    */
-  owner: Observable<RemoteData<Item>>;
+  @link(BITSTREAM_FORMAT)
+  format?: Observable<RemoteData<BitstreamFormat>>;
 
-  /**
-   * The URL to retrieve this Bitstream's file
-   */
-  content: string;
 }
diff --git a/src/app/core/shared/bitstream.resource-type.ts b/src/app/core/shared/bitstream.resource-type.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d2ff21ae60d5bf3fe10febdb21db6ddbc02217e1
--- /dev/null
+++ b/src/app/core/shared/bitstream.resource-type.ts
@@ -0,0 +1,9 @@
+import { ResourceType } from './resource-type';
+
+/**
+ * The resource type for Bitstream
+ *
+ * Needs to be in a separate file to prevent circular
+ * dependencies in webpack.
+ */
+export const BITSTREAM = new ResourceType('bitstream');
diff --git a/src/app/core/shared/browse-definition.model.ts b/src/app/core/shared/browse-definition.model.ts
index 9fafe7e3214ba833efe912e0184f8fc57a940487..e1d0e0bf013be63c6707af9edc84d7ea0bf3b2e5 100644
--- a/src/app/core/shared/browse-definition.model.ts
+++ b/src/app/core/shared/browse-definition.model.ts
@@ -1,10 +1,22 @@
-import { autoserialize, autoserializeAs } from 'cerialize';
-import { SortOption } from './sort-option.model';
-import { ResourceType } from './resource-type';
+import { autoserialize, autoserializeAs, deserialize } from 'cerialize';
+import { typedObject } from '../cache/builders/build-decorators';
 import { TypedObject } from '../cache/object-cache.reducer';
+import { excludeFromEquals } from '../utilities/equals.decorators';
+import { BROWSE_DEFINITION } from './browse-definition.resource-type';
+import { HALLink } from './hal-link.model';
+import { ResourceType } from './resource-type';
+import { SortOption } from './sort-option.model';
 
+@typedObject
 export class BrowseDefinition implements TypedObject {
-  static type = new ResourceType('browse');
+  static type = BROWSE_DEFINITION;
+
+  /**
+   * The object type
+   */
+  @excludeFromEquals
+  @autoserialize
+  type: ResourceType;
 
   @autoserialize
   id: string;
@@ -21,8 +33,14 @@ export class BrowseDefinition implements TypedObject {
   @autoserializeAs('metadata')
   metadataKeys: string[];
 
-  @autoserialize
-  _links: {
-    [name: string]: string
+  get self(): string {
+    return this._links.self.href;
   }
+
+  @deserialize
+  _links: {
+    self: HALLink;
+    entries: HALLink;
+    items: HALLink;
+  };
 }
diff --git a/src/app/core/shared/browse-definition.resource-type.ts b/src/app/core/shared/browse-definition.resource-type.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f79ee1f020e2410aed577913ab9065e16bba303d
--- /dev/null
+++ b/src/app/core/shared/browse-definition.resource-type.ts
@@ -0,0 +1,9 @@
+import { ResourceType } from './resource-type';
+
+/**
+ * The resource type for BrowseDefinition
+ *
+ * Needs to be in a separate file to prevent circular
+ * dependencies in webpack.
+ */
+export const BROWSE_DEFINITION = new ResourceType('browse');
diff --git a/src/app/core/shared/browse-entry.model.ts b/src/app/core/shared/browse-entry.model.ts
index d6074de3f577ede8efa1dafa876df85da997377b..b5e971d06981ff4d889e2a75705fffc82c8a999e 100644
--- a/src/app/core/shared/browse-entry.model.ts
+++ b/src/app/core/shared/browse-entry.model.ts
@@ -1,37 +1,58 @@
+import { autoserialize, autoserializeAs, deserialize } from 'cerialize';
 import { ListableObject } from '../../shared/object-collection/shared/listable-object.model';
+import { typedObject } from '../cache/builders/build-decorators';
 import { TypedObject } from '../cache/object-cache.reducer';
-import { ResourceType } from './resource-type';
-import { GenericConstructor } from './generic-constructor';
 import { excludeFromEquals } from '../utilities/equals.decorators';
+import { BROWSE_ENTRY } from './browse-entry.resource-type';
+import { GenericConstructor } from './generic-constructor';
+import { HALLink } from './hal-link.model';
+import { ResourceType } from './resource-type';
 
 /**
  * Class object representing a browse entry
- * This class is not normalized because browse entries do not have self links
  */
+@typedObject
 export class BrowseEntry extends ListableObject implements TypedObject {
-  static type = new ResourceType('browseEntry');
+  static type = BROWSE_ENTRY;
+
+  /**
+   * The object type
+   */
+  @excludeFromEquals
+  @autoserialize
+  type: ResourceType;
 
   /**
    * The authority string of this browse entry
    */
+  @autoserialize
   authority: string;
 
   /**
    * The value of this browse entry
    */
+  @autoserialize
   value: string;
 
   /**
    * The language of the value of this browse entry
    */
+  @autoserializeAs('valueLang')
   language: string;
 
   /**
    * The count of this browse entry
    */
   @excludeFromEquals
+  @autoserialize
   count: number;
 
+  @deserialize
+  _links: {
+    self: HALLink;
+    entries: HALLink;
+  };
+
   /**
    * Method that returns as which type of object this object should be rendered
    */
diff --git a/src/app/core/shared/browse-entry.resource-type.ts b/src/app/core/shared/browse-entry.resource-type.ts
new file mode 100644
index 0000000000000000000000000000000000000000..648f7ee31f452e04bf5e4ca95844d0fdedb0a68e
--- /dev/null
+++ b/src/app/core/shared/browse-entry.resource-type.ts
@@ -0,0 +1,9 @@
+import { ResourceType } from './resource-type';
+
+/**
+ * The resource type for BrowseEntry
+ *
+ * Needs to be in a separate file to prevent circular
+ * dependencies in webpack.
+ */
+export const BROWSE_ENTRY = new ResourceType('browseEntry');
diff --git a/src/app/core/shared/bundle.model.ts b/src/app/core/shared/bundle.model.ts
index dade7d12beb9b53ef4cd5f959f7fb5bc0c6fffe9..c1164f0fc494ca52351d154014001a5cabd8ba3d 100644
--- a/src/app/core/shared/bundle.model.ts
+++ b/src/app/core/shared/bundle.model.ts
@@ -1,37 +1,21 @@
+import { deserialize, inheritSerialization } from 'cerialize';
+import { typedObject } from '../cache/builders/build-decorators';
+import { BUNDLE } from './bundle.resource-type';
 import { DSpaceObject } from './dspace-object.model';
-import { Bitstream } from './bitstream.model';
-import { Item } from './item.model';
-import { RemoteData } from '../data/remote-data';
-import { Observable } from 'rxjs';
-import { ResourceType } from './resource-type';
-import { PaginatedList } from '../data/paginated-list';
+import { HALLink } from './hal-link.model';
 
+@typedObject
+@inheritSerialization(DSpaceObject)
 export class Bundle extends DSpaceObject {
-  static type = new ResourceType('bundle');
+  static type = BUNDLE;
 
   /**
-   * The bundle's name
+   * The {@link HALLink}s for this Bundle
    */
-  name: string;
-
-  /**
-   * The primary bitstream of this Bundle
-   */
-  primaryBitstream: Observable<RemoteData<Bitstream>>;
-
-  /**
-   * An array of Items that are direct parents of this Bundle
-   */
-  parents: Observable<RemoteData<Item[]>>;
-
-  /**
-   * The Item that owns this Bundle
-   */
-  owner: Observable<RemoteData<Item>>;
-
-  /**
-   * List of Bitstreams that are part of this Bundle
-   */
-  bitstreams: Observable<RemoteData<PaginatedList<Bitstream>>>;
-
+  @deserialize
+  _links: {
+    self: HALLink;
+    primaryBitstream: HALLink;
+    bitstreams: HALLink;
+  }
 }
diff --git a/src/app/core/shared/bundle.resource-type.ts b/src/app/core/shared/bundle.resource-type.ts
new file mode 100644
index 0000000000000000000000000000000000000000..18c2f1c1b94a58dcc50c86fe49965734f4ff577f
--- /dev/null
+++ b/src/app/core/shared/bundle.resource-type.ts
@@ -0,0 +1,9 @@
+import { ResourceType } from './resource-type';
+
+/**
+ * The resource type for Bundle
+ *
+ * Needs to be in a separate file to prevent circular
+ * dependencies in webpack.
+ */
+export const BUNDLE = new ResourceType('bundle');
diff --git a/src/app/core/shared/child-hal-resource.model.ts b/src/app/core/shared/child-hal-resource.model.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ee022942bbe452e0a08fc7e449c719f6e3f3bcbc
--- /dev/null
+++ b/src/app/core/shared/child-hal-resource.model.ts
@@ -0,0 +1,12 @@
+import { HALResource } from './hal-resource.model';
+
+/**
+ * Interface for HALResources with a parent object link
+ */
+export interface ChildHALResource extends HALResource {
+
+  /**
+   * Returns the key of the parent link
+   */
+  getParentLinkKey(): keyof this['_links'];
+}
diff --git a/src/app/core/shared/collection.model.ts b/src/app/core/shared/collection.model.ts
index 642fe5073642ea1bafe214a9de0dd481d00c1ef1..ba2f448bba9fd6c4a74d96627e7bae237e9310d3 100644
--- a/src/app/core/shared/collection.model.ts
+++ b/src/app/core/shared/collection.model.ts
@@ -1,21 +1,75 @@
-import { DSpaceObject } from './dspace-object.model';
-import { Bitstream } from './bitstream.model';
-import { Item } from './item.model';
-import { RemoteData } from '../data/remote-data';
+import { autoserialize, deserialize, inheritSerialization } from 'cerialize';
 import { Observable } from 'rxjs';
+import { link, typedObject } from '../cache/builders/build-decorators';
+import { PaginatedList } from '../data/paginated-list';
+import { RemoteData } from '../data/remote-data';
+import { Bitstream } from './bitstream.model';
+import { BITSTREAM } from './bitstream.resource-type';
+import { COLLECTION } from './collection.resource-type';
+import { DSpaceObject } from './dspace-object.model';
+import { HALLink } from './hal-link.model';
 import { License } from './license.model';
+import { LICENSE } from './license.resource-type';
 import { ResourcePolicy } from './resource-policy.model';
-import { PaginatedList } from '../data/paginated-list';
-import { ResourceType } from './resource-type';
+import { RESOURCE_POLICY } from './resource-policy.resource-type';
+import { COMMUNITY } from './community.resource-type';
+import { Community } from './community.model';
+import { ChildHALResource } from './child-hal-resource.model';
 
-export class Collection extends DSpaceObject {
-  static type = new ResourceType('collection');
+@typedObject
+@inheritSerialization(DSpaceObject)
+export class Collection extends DSpaceObject implements ChildHALResource {
+  static type = COLLECTION;
 
   /**
    * A string representing the unique handle of this Collection
    */
+  @autoserialize
   handle: string;
 
+  /**
+   * The {@link HALLink}s for this Collection
+   */
+  @deserialize
+  _links: {
+    license: HALLink;
+    harvester: HALLink;
+    mappedItems: HALLink;
+    itemtemplate: HALLink;
+    defaultAccessConditions: HALLink;
+    logo: HALLink;
+    parentCommunity: HALLink;
+    self: HALLink;
+  };
+
+  /**
+   * The license for this Collection
+   * Will be undefined unless the license {@link HALLink} has been resolved.
+   */
+  @link(LICENSE)
+  license?: Observable<RemoteData<License>>;
+
+  /**
+   * The logo for this Collection
+   * Will be undefined unless the logo {@link HALLink} has been resolved.
+   */
+  @link(BITSTREAM)
+  logo?: Observable<RemoteData<Bitstream>>;
+
+  /**
+   * The default access conditions for this Collection
+   * Will be undefined unless the defaultAccessConditions {@link HALLink} has been resolved.
+   */
+  @link(RESOURCE_POLICY, true)
+  defaultAccessConditions?: Observable<RemoteData<PaginatedList<ResourcePolicy>>>;
+
+  /**
+   * The Community that is a direct parent of this Collection
+   * Will be undefined unless the parent community HALLink has been resolved.
+   */
+  @link(COMMUNITY, false)
+  parentCommunity?: Observable<RemoteData<Community>>;
+
   /**
    * The introductory text of this Collection
    * Corresponds to the metadata field dc.description
@@ -56,30 +110,7 @@ export class Collection extends DSpaceObject {
     return this.firstMetadataValue('dc.description.tableofcontents');
   }
 
-  /**
-   * The deposit license of this Collection
-   */
-  license: Observable<RemoteData<License>>;
-
-  /**
-   * The Bitstream that represents the logo of this Collection
-   */
-  logo: Observable<RemoteData<Bitstream>>;
-
-  /**
-   * The default access conditions of this Collection
-   */
-  defaultAccessConditions: Observable<RemoteData<PaginatedList<ResourcePolicy>>>;
-
-  /**
-   * An array of Collections that are direct parents of this Collection
-   */
-  parents: Observable<RemoteData<Collection[]>>;
-
-  /**
-   * The Collection that owns this Collection
-   */
-  owner: Observable<RemoteData<Collection>>;
-
-  items: Observable<RemoteData<Item[]>>;
+  getParentLinkKey(): keyof this['_links'] {
+    return 'parentCommunity';
+  }
 }
diff --git a/src/app/core/shared/collection.resource-type.ts b/src/app/core/shared/collection.resource-type.ts
new file mode 100644
index 0000000000000000000000000000000000000000..899b33f7d2de7509746b181cdd41822760edd4a3
--- /dev/null
+++ b/src/app/core/shared/collection.resource-type.ts
@@ -0,0 +1,9 @@
+import { ResourceType } from './resource-type';
+
+/**
+ * The resource type for Collection
+ *
+ * Needs to be in a separate file to prevent circular
+ * dependencies in webpack.
+ */
+export const COLLECTION = new ResourceType('collection');
diff --git a/src/app/core/shared/community.model.ts b/src/app/core/shared/community.model.ts
index b61ddfd7f9927e27146b2b7cf0337a5296ebf7e4..e18ec743e8e5fac4cd01a88d143e44d339038de8 100644
--- a/src/app/core/shared/community.model.ts
+++ b/src/app/core/shared/community.model.ts
@@ -1,19 +1,68 @@
-import { DSpaceObject } from './dspace-object.model';
-import { Bitstream } from './bitstream.model';
-import { Collection } from './collection.model';
-import { RemoteData } from '../data/remote-data';
+import { autoserialize, deserialize, inheritSerialization } from 'cerialize';
 import { Observable } from 'rxjs';
+import { link, typedObject } from '../cache/builders/build-decorators';
 import { PaginatedList } from '../data/paginated-list';
-import { ResourceType } from './resource-type';
+import { RemoteData } from '../data/remote-data';
+import { Bitstream } from './bitstream.model';
+import { BITSTREAM } from './bitstream.resource-type';
+import { Collection } from './collection.model';
+import { COLLECTION } from './collection.resource-type';
+import { COMMUNITY } from './community.resource-type';
+import { DSpaceObject } from './dspace-object.model';
+import { HALLink } from './hal-link.model';
+import { ChildHALResource } from './child-hal-resource.model';
 
-export class Community extends DSpaceObject {
-  static type = new ResourceType('community');
+@typedObject
+@inheritSerialization(DSpaceObject)
+export class Community extends DSpaceObject implements ChildHALResource {
+  static type = COMMUNITY;
 
   /**
    * A string representing the unique handle of this Community
    */
+  @autoserialize
   handle: string;
 
+  /**
+   * The {@link HALLink}s for this Community
+   */
+  @deserialize
+  _links: {
+    collections: HALLink;
+    logo: HALLink;
+    subcommunities: HALLink;
+    parentCommunity: HALLink;
+    self: HALLink;
+  };
+
+  /**
+   * The logo for this Community
+   * Will be undefined unless the logo {@link HALLink} has been resolved.
+   */
+  @link(BITSTREAM)
+  logo?: Observable<RemoteData<Bitstream>>;
+
+  /**
+   * The list of Collections that are direct children of this Community
+   * Will be undefined unless the collections {@link HALLink} has been resolved.
+   */
+  @link(COLLECTION, true)
+  collections?: Observable<RemoteData<PaginatedList<Collection>>>;
+
+  /**
+   * The list of Communities that are direct children of this Community
+   * Will be undefined unless the subcommunities {@link HALLink} has been resolved.
+   */
+  @link(COMMUNITY, true)
+  subcommunities?: Observable<RemoteData<PaginatedList<Community>>>;
+
+  /**
+   * The Community that is a direct parent of this Community
+   * Will be undefined unless the parent community HALLink has been resolved.
+   */
+  @link(COMMUNITY, false)
+  parentCommunity?: Observable<RemoteData<Community>>;
+
   /**
    * The introductory text of this Community
    * Corresponds to the metadata field dc.description
@@ -46,23 +95,7 @@ export class Community extends DSpaceObject {
     return this.firstMetadataValue('dc.description.tableofcontents');
   }
 
-  /**
-   * The Bitstream that represents the logo of this Community
-   */
-  logo: Observable<RemoteData<Bitstream>>;
-
-  /**
-   * An array of Communities that are direct parents of this Community
-   */
-  parents: Observable<RemoteData<DSpaceObject[]>>;
-
-  /**
-   * The Community that owns this Community
-   */
-  owner: Observable<RemoteData<Community>>;
-
-  collections: Observable<RemoteData<PaginatedList<Collection>>>;
-
-  subcommunities: Observable<RemoteData<PaginatedList<Community>>>;
-
+  getParentLinkKey(): keyof this['_links'] {
+    return 'parentCommunity';
+  }
 }
diff --git a/src/app/core/shared/community.resource-type.ts b/src/app/core/shared/community.resource-type.ts
new file mode 100644
index 0000000000000000000000000000000000000000..2d5f74cafc53fb138009c32132d35e091d119fb1
--- /dev/null
+++ b/src/app/core/shared/community.resource-type.ts
@@ -0,0 +1,9 @@
+import { ResourceType } from './resource-type';
+
+/**
+ * The resource type for Community
+ *
+ * Needs to be in a separate file to prevent circular
+ * dependencies in webpack.
+ */
+export const COMMUNITY = new ResourceType('community');
diff --git a/src/app/core/shared/content-source.model.ts b/src/app/core/shared/content-source.model.ts
index cd53c2d81e62d51b652b833ba9bcc83305de05a6..3e530b6a3abf6d84a8cbd14dea561039548437dd 100644
--- a/src/app/core/shared/content-source.model.ts
+++ b/src/app/core/shared/content-source.model.ts
@@ -1,4 +1,6 @@
 import { autoserialize, autoserializeAs, deserializeAs, deserialize } from 'cerialize';
+import { HALLink } from './hal-link.model';
+import { HALResource } from './hal-resource.model';
 import { MetadataConfig } from './metadata-config.model';
 
 /**
@@ -14,7 +16,7 @@ export enum ContentSourceHarvestType {
 /**
  * A model class that holds information about the Content Source of a Collection
  */
-export class ContentSource {
+export class ContentSource implements HALResource {
   /**
    * Unique identifier, this is necessary to store the ContentSource in FieldUpdates
    * Because the ContentSource coming from the REST API doesn't have a UUID, we're using the selflink
@@ -53,8 +55,10 @@ export class ContentSource {
   metadataConfigs: MetadataConfig[];
 
   /**
-   * The REST link to itself
+   * The {@link HALLink}s for this ContentSource
    */
   @deserialize
-  self: string;
+  _links: {
+    self: HALLink
+  }
 }
diff --git a/src/app/core/shared/dspace-object.model.ts b/src/app/core/shared/dspace-object.model.ts
index 32242548847ed162123dc522f2cf087d16757108..a9256fbb7f4dfe689ee188edfc03ab1f88fac1de 100644
--- a/src/app/core/shared/dspace-object.model.ts
+++ b/src/app/core/shared/dspace-object.model.ts
@@ -1,54 +1,75 @@
-import { Observable } from 'rxjs';
-
+import { autoserialize, autoserializeAs, deserialize, deserializeAs } from 'cerialize';
+import { hasNoValue, hasValue, isUndefined } from '../../shared/empty.util';
+import { ListableObject } from '../../shared/object-collection/shared/listable-object.model';
+import { typedObject } from '../cache/builders/build-decorators';
+import { CacheableObject } from '../cache/object-cache.reducer';
+import { excludeFromEquals } from '../utilities/equals.decorators';
+import { DSPACE_OBJECT } from './dspace-object.resource-type';
+import { GenericConstructor } from './generic-constructor';
+import { HALLink } from './hal-link.model';
 import {
   MetadataMap,
+  MetadataMapSerializer,
   MetadataValue,
   MetadataValueFilter,
   MetadatumViewModel
 } from './metadata.models';
 import { Metadata } from './metadata.utils';
-import { hasNoValue, hasValue, isUndefined } from '../../shared/empty.util';
-import { CacheableObject } from '../cache/object-cache.reducer';
-import { RemoteData } from '../data/remote-data';
-import { ListableObject } from '../../shared/object-collection/shared/listable-object.model';
-import { excludeFromEquals } from '../utilities/equals.decorators';
 import { ResourceType } from './resource-type';
-import { GenericConstructor } from './generic-constructor';
 
 /**
  * An abstract model class for a DSpaceObject.
  */
+@typedObject
 export class DSpaceObject extends ListableObject implements CacheableObject {
   /**
    * A string representing the kind of DSpaceObject, e.g. community, item, …
    */
-  static type = new ResourceType('dspaceobject');
+  static type = DSPACE_OBJECT;
 
   @excludeFromEquals
+  @deserializeAs('name')
   private _name: string;
 
-  @excludeFromEquals
-  self: string;
-
   /**
    * The human-readable identifier of this DSpaceObject
    */
   @excludeFromEquals
+  @autoserializeAs(String, 'uuid')
   id: string;
 
   /**
    * The universally unique identifier of this DSpaceObject
    */
+  @autoserializeAs(String)
   uuid: string;
 
   /**
    * A string representing the kind of DSpaceObject, e.g. community, item, …
    */
   @excludeFromEquals
+  @autoserialize
   type: ResourceType;
 
+  /**
+   * A shorthand to get this DSpaceObject's self link
+   */
+  get self(): string {
+    return this._links.self.href;
+  }
+
+  /**
+   * A shorthand to set this DSpaceObject's self link
+   */
+  set self(v: string) {
+    this._links.self = {
+      href: v
+    };
+  }
+
   /**
    * The name for this DSpaceObject
+   * @deprecated use {@link DSONameService} instead
    */
   get name(): string {
     return (isUndefined(this._name)) ? this.firstMetadataValue('dc.title') : this._name;
@@ -68,8 +89,14 @@ export class DSpaceObject extends ListableObject implements CacheableObject {
    * All metadata of this DSpaceObject
    */
   @excludeFromEquals
+  @autoserializeAs(MetadataMapSerializer)
   metadata: MetadataMap;
 
+  @deserialize
+  _links: {
+    self: HALLink;
+  };
+
   /**
    * Retrieve the current metadata as a list of MetadatumViewModels
    */
@@ -77,18 +104,6 @@ export class DSpaceObject extends ListableObject implements CacheableObject {
     return Metadata.toViewModelList(this.metadata);
   }
 
-  /**
-   * An array of DSpaceObjects that are direct parents of this DSpaceObject
-   */
-  @excludeFromEquals
-  parents: Observable<RemoteData<DSpaceObject[]>>;
-
-  /**
-   * The DSpaceObject that owns this DSpaceObject
-   */
-  @excludeFromEquals
-  owner: Observable<RemoteData<DSpaceObject>>;
-
   /**
    * Gets all matching metadata in this DSpaceObject.
    *
diff --git a/src/app/core/shared/dspace-object.resource-type.ts b/src/app/core/shared/dspace-object.resource-type.ts
new file mode 100644
index 0000000000000000000000000000000000000000..7d2b4450709fbc1372736ba0e85e9561da628fb7
--- /dev/null
+++ b/src/app/core/shared/dspace-object.resource-type.ts
@@ -0,0 +1,9 @@
+import { ResourceType } from './resource-type';
+
+/**
+ * The resource type for DSpaceObject
+ *
+ * Needs to be in a separate file to prevent circular
+ * dependencies in webpack.
+ */
+export const DSPACE_OBJECT = new ResourceType('dspaceobject');
diff --git a/src/app/core/shared/external-source-entry.model.ts b/src/app/core/shared/external-source-entry.model.ts
index 2451aa4d24afedce050ce252e5f93cbac885643c..5836a01138102af4906b06aec35bc042bd8fbb39 100644
--- a/src/app/core/shared/external-source-entry.model.ts
+++ b/src/app/core/shared/external-source-entry.model.ts
@@ -1,43 +1,64 @@
-import { MetadataMap } from './metadata.models';
-import { ResourceType } from './resource-type';
+import { autoserialize, autoserializeAs, deserialize } from 'cerialize';
 import { ListableObject } from '../../shared/object-collection/shared/listable-object.model';
+import { typedObject } from '../cache/builders/build-decorators';
+import { excludeFromEquals } from '../utilities/equals.decorators';
+import { EXTERNAL_SOURCE_ENTRY } from './external-source-entry.resource-type';
 import { GenericConstructor } from './generic-constructor';
+import { HALLink } from './hal-link.model';
+import { MetadataMap, MetadataMapSerializer } from './metadata.models';
+import { ResourceType } from './resource-type';
 
 /**
  * Model class for a single entry from an external source
  */
+@typedObject
 export class ExternalSourceEntry extends ListableObject {
-  static type = new ResourceType('externalSourceEntry');
+  static type = EXTERNAL_SOURCE_ENTRY;
 
   /**
    * Unique identifier
    */
+  @autoserialize
   id: string;
 
+  /**
+   * The object type
+   */
+  @excludeFromEquals
+  @autoserialize
+  type: ResourceType;
+
   /**
    * The value to display
    */
+  @autoserialize
   display: string;
 
   /**
    * The value to store the entry with
    */
+  @autoserialize
   value: string;
 
   /**
    * The ID of the external source this entry originates from
    */
+  @autoserialize
   externalSource: string;
 
   /**
    * Metadata of the entry
    */
+  @autoserializeAs(MetadataMapSerializer)
   metadata: MetadataMap;
 
   /**
-   * The link to the rest endpoint where this External Source Entry can be found
+   * The {@link HALLink}s for this ExternalSourceEntry
    */
-  self: string;
+  @deserialize
+  _links: {
+    self: HALLink;
+  };
 
   /**
    * Method that returns as which type of object this object should be rendered
diff --git a/src/app/core/shared/external-source-entry.resource-type.ts b/src/app/core/shared/external-source-entry.resource-type.ts
new file mode 100644
index 0000000000000000000000000000000000000000..0fc25a5e3ff567d46ef5585c47a171b312ef5f09
--- /dev/null
+++ b/src/app/core/shared/external-source-entry.resource-type.ts
@@ -0,0 +1,9 @@
+import { ResourceType } from './resource-type';
+
+/**
+ * The resource type for ResourceType
+ *
+ * Needs to be in a separate file to prevent circular
+ * dependencies in webpack.
+ */
+export const EXTERNAL_SOURCE_ENTRY = new ResourceType('externalSourceEntry');
diff --git a/src/app/core/shared/external-source.model.ts b/src/app/core/shared/external-source.model.ts
index a158f18f5d6fefdc65a0ed15ff93f614d7992e46..5005fbcd3611f77ab39c51bda282d8f46e047b73 100644
--- a/src/app/core/shared/external-source.model.ts
+++ b/src/app/core/shared/external-source.model.ts
@@ -1,29 +1,49 @@
-import { ResourceType } from './resource-type';
+import { autoserialize, deserialize, inheritSerialization } from 'cerialize';
+import { typedObject } from '../cache/builders/build-decorators';
 import { CacheableObject } from '../cache/object-cache.reducer';
+import { excludeFromEquals } from '../utilities/equals.decorators';
+import { EXTERNAL_SOURCE } from './external-source.resource-type';
+import { HALLink } from './hal-link.model';
+import { ResourceType } from './resource-type';
 
 /**
  * Model class for an external source
  */
+@typedObject
 export class ExternalSource extends CacheableObject {
-  static type = new ResourceType('externalsource');
+  static type = EXTERNAL_SOURCE;
+
+  /**
+   * The object type
+   */
+  @excludeFromEquals
+  @autoserialize
+  type: ResourceType;
 
   /**
    * Unique identifier
    */
+  @autoserialize
   id: string;
 
   /**
    * The name of this external source
    */
+  @autoserialize
   name: string;
 
   /**
    * Is the source hierarchical?
    */
+  @autoserialize
   hierarchical: boolean;
 
   /**
-   * The link to the rest endpoint where this External Source can be found
+   * The {@link HALLink}s for this ExternalSource
    */
-  self: string;
+  @deserialize
+  _links: {
+    self: HALLink;
+    entries: HALLink;
+  }
 }
diff --git a/src/app/core/shared/external-source.resource-type.ts b/src/app/core/shared/external-source.resource-type.ts
new file mode 100644
index 0000000000000000000000000000000000000000..2cf07bd5fcdd6987ec2c6c58821a8d1036cecc3f
--- /dev/null
+++ b/src/app/core/shared/external-source.resource-type.ts
@@ -0,0 +1,9 @@
+import { ResourceType } from './resource-type';
+
+/**
+ * The resource type for ExternalSource
+ *
+ * Needs to be in a separate file to prevent circular
+ * dependencies in webpack.
+ */
+export const EXTERNAL_SOURCE = new ResourceType('externalsource');
diff --git a/src/app/core/shared/hal-link.model.ts b/src/app/core/shared/hal-link.model.ts
new file mode 100644
index 0000000000000000000000000000000000000000..88a136a4b2f2c897b6f60a7326227208cfc5e0dc
--- /dev/null
+++ b/src/app/core/shared/hal-link.model.ts
@@ -0,0 +1,23 @@
+/**
+ * A single link in the _links section of a {@link HALResource}
+ */
+export class HALLink {
+
+  /**
+   * The url of the {@link HALLink}'s target
+   */
+  href: string;
+
+  /**
+   * The name of the {@link HALLink}
+   */
+  name?: string;
+
+  /**
+   * A boolean indicating whether the href contains a template.
+   *
+   * e.g. if href is "http://haltalk.herokuapp.com/docs/{rel}"
+   * {rel} would be the template
+   */
+  templated?: boolean
+}
diff --git a/src/app/core/shared/hal-resource.model.ts b/src/app/core/shared/hal-resource.model.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b6ef822a23f5b9d8415ee1b983cf300b0b0a9751
--- /dev/null
+++ b/src/app/core/shared/hal-resource.model.ts
@@ -0,0 +1,23 @@
+import { HALLink } from './hal-link.model';
+
+/**
+ * Represents HAL resources.
+ *
+ * A HAL resource has a _links section with at least a self link.
+ */
+export class HALResource {
+  /**
+   * The {@link HALLink}s for this {@link HALResource}
+   */
+  _links: {
+    /**
+     * The {@link HALLink} that refers to this {@link HALResource}
+     */
+    self: HALLink
+
+    /**
+     * {@link HALLink}s to related {@link HALResource}s
+     */
+    [k: string]: HALLink;
+  };
+}
diff --git a/src/app/core/shared/item-relationships/item-type.model.ts b/src/app/core/shared/item-relationships/item-type.model.ts
index 0fc52b00a575b59b5cc13bf9e966d00ea03711d2..d41024cdaa06385a44c22d4329f6f1a17da1e0dd 100644
--- a/src/app/core/shared/item-relationships/item-type.model.ts
+++ b/src/app/core/shared/item-relationships/item-type.model.ts
@@ -1,26 +1,48 @@
+import { autoserialize, deserialize, deserializeAs } from 'cerialize';
+import { typedObject } from '../../cache/builders/build-decorators';
+import { IDToUUIDSerializer } from '../../cache/id-to-uuid-serializer';
 import { CacheableObject } from '../../cache/object-cache.reducer';
+import { excludeFromEquals } from '../../utilities/equals.decorators';
+import { HALLink } from '../hal-link.model';
 import { ResourceType } from '../resource-type';
+import { ITEM_TYPE } from './item-type.resource-type';
 
 /**
  * Describes a type of Item
  */
+@typedObject
 export class ItemType implements CacheableObject {
-  static type = new ResourceType('entitytype');
+  static type = ITEM_TYPE;
+
+  /**
+   * The object type
+   */
+  @excludeFromEquals
+  @autoserialize
+  type: ResourceType;
 
   /**
    * The identifier of this ItemType
    */
+  @autoserialize
   id: string;
 
+  @autoserialize
   label: string;
 
   /**
-   * The link to the rest endpoint where this object can be found
+   * The universally unique identifier of this ItemType
+   * This UUID is generated client-side and isn't used by the backend.
+   * It is based on the ID, so it will be the same for each refresh.
    */
-  self: string;
+  @deserializeAs(new IDToUUIDSerializer(ItemType.type.value), 'id')
+  uuid: string;
 
   /**
-   * The universally unique identifier of this ItemType
+   * The {@link HALLink}s for this ItemType
    */
-  uuid: string;
+  @deserialize
+  _links: {
+    self: HALLink,
+  };
 }
diff --git a/src/app/core/shared/item-relationships/item-type.resource-type.ts b/src/app/core/shared/item-relationships/item-type.resource-type.ts
new file mode 100644
index 0000000000000000000000000000000000000000..616dc23b73a46315348dbd32b2dc811b1022fe40
--- /dev/null
+++ b/src/app/core/shared/item-relationships/item-type.resource-type.ts
@@ -0,0 +1,10 @@
+import { ResourceType } from '../resource-type';
+
+/**
+ * The resource type for ItemType
+ *
+ * Needs to be in a separate file to prevent circular
+ * dependencies in webpack.
+ */
+
+export const ITEM_TYPE = new ResourceType('entitytype');
diff --git a/src/app/core/shared/item-relationships/relationship-type.model.ts b/src/app/core/shared/item-relationships/relationship-type.model.ts
index 06ac94b04149c734ed73fc5112f60a2af997b655..fb62f685dd12a4cae03f89edd86ec46da5deb844 100644
--- a/src/app/core/shared/item-relationships/relationship-type.model.ts
+++ b/src/app/core/shared/item-relationships/relationship-type.model.ts
@@ -1,72 +1,107 @@
+import { autoserialize, deserialize, deserializeAs } from 'cerialize';
 import { Observable } from 'rxjs';
+import { link, typedObject } from '../../cache/builders/build-decorators';
+import { IDToUUIDSerializer } from '../../cache/id-to-uuid-serializer';
 import { CacheableObject } from '../../cache/object-cache.reducer';
 import { RemoteData } from '../../data/remote-data';
+import { excludeFromEquals } from '../../utilities/equals.decorators';
+import { HALLink } from '../hal-link.model';
 import { ResourceType } from '../resource-type';
 import { ItemType } from './item-type.model';
+import { ITEM_TYPE } from './item-type.resource-type';
+import { RELATIONSHIP_TYPE } from './relationship-type.resource-type';
 
 /**
  * Describes a type of Relationship between multiple possible Items
  */
+@typedObject
 export class RelationshipType implements CacheableObject {
-  static type = new ResourceType('relationshiptype');
+  static type = RELATIONSHIP_TYPE;
 
   /**
-   * The link to the rest endpoint where this object can be found
+   * The object type
    */
-  self: string;
+  @excludeFromEquals
+  @autoserialize
+  type: ResourceType;
 
   /**
    * The label that describes this RelationshipType
    */
+  @autoserialize
   label: string;
 
   /**
    * The identifier of this RelationshipType
    */
+  @autoserialize
   id: string;
 
   /**
    * The universally unique identifier of this RelationshipType
+   * This UUID is generated client-side and isn't used by the backend.
+   * It is based on the ID, so it will be the same for each refresh.
    */
+  @deserializeAs(new IDToUUIDSerializer(RelationshipType.type.value), 'id')
   uuid: string;
 
   /**
    * The label that describes the Relation to the left of this RelationshipType
    */
+  @autoserialize
   leftwardType: string;
 
   /**
    * The maximum amount of Relationships allowed to the left of this RelationshipType
    */
+  @autoserialize
   leftMaxCardinality: number;
 
   /**
    * The minimum amount of Relationships allowed to the left of this RelationshipType
    */
+  @autoserialize
   leftMinCardinality: number;
 
   /**
    * The label that describes the Relation to the right of this RelationshipType
    */
+  @autoserialize
   rightwardType: string;
 
   /**
    * The maximum amount of Relationships allowed to the right of this RelationshipType
    */
+  @autoserialize
   rightMaxCardinality: number;
 
   /**
    * The minimum amount of Relationships allowed to the right of this RelationshipType
    */
+  @autoserialize
   rightMinCardinality: number;
 
   /**
-   * The type of Item found to the left of this RelationshipType
+   * The {@link HALLink}s for this RelationshipType
    */
-  leftType: Observable<RemoteData<ItemType>>;
+  @deserialize
+  _links: {
+    self: HALLink;
+    leftType: HALLink;
+    rightType: HALLink;
+  };
 
   /**
-   * The type of Item found to the right of this RelationshipType
+   * The type of Item found on the left side of this RelationshipType
+   * Will be undefined unless the leftType {@link HALLink} has been resolved.
    */
-  rightType: Observable<RemoteData<ItemType>>;
+  @link(ITEM_TYPE)
+  leftType?: Observable<RemoteData<ItemType>>;
+
+  /**
+   * The type of Item found on the right side of this RelationshipType
+   * Will be undefined unless the rightType {@link HALLink} has been resolved.
+   */
+  @link(ITEM_TYPE)
+  rightType?: Observable<RemoteData<ItemType>>;
 }
diff --git a/src/app/core/shared/item-relationships/relationship-type.resource-type.ts b/src/app/core/shared/item-relationships/relationship-type.resource-type.ts
new file mode 100644
index 0000000000000000000000000000000000000000..6f6300c38eb253c258962e2bae328fa4005e27ee
--- /dev/null
+++ b/src/app/core/shared/item-relationships/relationship-type.resource-type.ts
@@ -0,0 +1,10 @@
+import { ResourceType } from '../resource-type';
+
+/**
+ * The resource type for RelationshipType
+ *
+ * Needs to be in a separate file to prevent circular
+ * dependencies in webpack.
+ */
+
+export const RELATIONSHIP_TYPE = new ResourceType('relationshiptype');
diff --git a/src/app/core/shared/item-relationships/relationship.model.ts b/src/app/core/shared/item-relationships/relationship.model.ts
index 2adcf42c04b922e5a0c20003c9194e0a07fbe08f..97a5db9e37718e208389689aef97ee47d3f39cc8 100644
--- a/src/app/core/shared/item-relationships/relationship.model.ts
+++ b/src/app/core/shared/item-relationships/relationship.model.ts
@@ -1,63 +1,100 @@
+import { autoserialize, deserialize, serialize, deserializeAs } from 'cerialize';
 import { Observable } from 'rxjs';
+import { link, typedObject } from '../../cache/builders/build-decorators';
+import { IDToUUIDSerializer } from '../../cache/id-to-uuid-serializer';
 import { CacheableObject } from '../../cache/object-cache.reducer';
 import { RemoteData } from '../../data/remote-data';
+import { excludeFromEquals } from '../../utilities/equals.decorators';
+import { HALLink } from '../hal-link.model';
+import { Item } from '../item.model';
+import { ITEM } from '../item.resource-type';
 import { ResourceType } from '../resource-type';
 import { RelationshipType } from './relationship-type.model';
-import { Item } from '../item.model';
+import { RELATIONSHIP_TYPE } from './relationship-type.resource-type';
+import { RELATIONSHIP } from './relationship.resource-type';
 
 /**
  * Describes a Relationship between two Items
  */
+@typedObject
 export class Relationship implements CacheableObject {
-  static type = new ResourceType('relationship');
+  static type = RELATIONSHIP;
 
   /**
-   * The link to the rest endpoint where this object can be found
+   * The object type
    */
-  self: string;
+  @excludeFromEquals
+  @autoserialize
+  type: ResourceType;
 
   /**
    * The universally unique identifier of this Relationship
+   * This UUID is generated client-side and isn't used by the backend.
+   * It is based on the ID, so it will be the same for each refresh.
    */
+  @deserializeAs(new IDToUUIDSerializer(Relationship.type.value), 'id')
   uuid: string;
 
   /**
    * The identifier of this Relationship
    */
+  @autoserialize
   id: string;
 
-  /**
-   * The item to the left of this relationship
-   */
-  leftItem: Observable<RemoteData<Item>>;
-
-  /**
-   * The item to the right of this relationship
-   */
-  rightItem: Observable<RemoteData<Item>>;
-
   /**
    * The place of the Item to the left side of this Relationship
    */
+  @autoserialize
   leftPlace: number;
 
   /**
    * The place of the Item to the right side of this Relationship
    */
+  @autoserialize
   rightPlace: number;
 
   /**
    * The name variant of the Item to the left side of this Relationship
    */
+  @autoserialize
   leftwardValue: string;
 
   /**
    * The name variant of the Item to the right side of this Relationship
    */
+  @autoserialize
   rightwardValue: string;
 
   /**
-   * The type of Relationship
+   * The {@link HALLink}s for this Relationship
+   */
+  @deserialize
+  _links: {
+    self: HALLink;
+    leftItem: HALLink;
+    rightItem: HALLink;
+    relationshipType: HALLink;
+  };
+
+  /**
+   * The item on the left side of this relationship
+   * Will be undefined unless the leftItem {@link HALLink} has been resolved.
+   */
+  @link(ITEM)
+  leftItem?: Observable<RemoteData<Item>>;
+
+  /**
+   * The item on the right side of this relationship
+   * Will be undefined unless the rightItem {@link HALLink} has been resolved.
    */
-  relationshipType: Observable<RemoteData<RelationshipType>>;
+  @link(ITEM)
+  rightItem?: Observable<RemoteData<Item>>;
+
+  /**
+   * The RelationshipType for this Relationship
+   * Will be undefined unless the relationshipType {@link HALLink} has been resolved.
+   */
+  @link(RELATIONSHIP_TYPE)
+  relationshipType?: Observable<RemoteData<RelationshipType>>;
+
 }
diff --git a/src/app/core/shared/item-relationships/relationship.resource-type.ts b/src/app/core/shared/item-relationships/relationship.resource-type.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f65f218d708ee7f58eb73526c4c8255395ee5d31
--- /dev/null
+++ b/src/app/core/shared/item-relationships/relationship.resource-type.ts
@@ -0,0 +1,9 @@
+import { ResourceType } from '../resource-type';
+
+/**
+ * The resource type for Relationship.
+ *
+ * Needs to be in a separate file to prevent circular
+ * dependencies in webpack.
+ */
+export const RELATIONSHIP = new ResourceType('relationship');
diff --git a/src/app/core/shared/item.model.spec.ts b/src/app/core/shared/item.model.spec.ts
index 1cffcf568a61ea0d2705d342d45d3ca005519847..9a4e11e6fd5c58c484bc10677b74c431ba2011ea 100644
--- a/src/app/core/shared/item.model.spec.ts
+++ b/src/app/core/shared/item.model.spec.ts
@@ -1,10 +1,6 @@
-import { Observable, of as observableOf } from 'rxjs';
+import { createPaginatedList, createSuccessfulRemoteDataObject$ } from '../../shared/testing/utils';
 
 import { Item } from './item.model';
-import { Bitstream } from './bitstream.model';
-import { isEmpty } from '../../shared/empty.util';
-import { first, map } from 'rxjs/operators';
-import { createPaginatedList, createSuccessfulRemoteDataObject$ } from '../../shared/testing/utils';
 
 describe('Item', () => {
 
@@ -55,50 +51,4 @@ describe('Item', () => {
 
     item = Object.assign(new Item(), { bundles: remoteDataBundles });
   });
-
-  it('should return the bitstreams related to this item with the specified bundle name', () => {
-    const bitObs: Observable<Bitstream[]> = item.getBitstreamsByBundleName(thumbnailBundleName);
-    bitObs.pipe(first()).subscribe((bs) =>
-      expect(bs.every((b) => b.name === thumbnailBundleName)).toBeTruthy());
-  });
-
-  it('should return an empty array when no bitstreams with this bundleName exist for this item', () => {
-    const bs: Observable<Bitstream[]> = item.getBitstreamsByBundleName(nonExistingBundleName);
-    bs.pipe(first()).subscribe((b) => expect(isEmpty(b)).toBeTruthy());
-  });
-
-  describe('get thumbnail', () => {
-    beforeEach(() => {
-      spyOn(item, 'getBitstreamsByBundleName').and.returnValue(observableOf([remoteDataThumbnail]));
-    });
-
-    it('should return the thumbnail of this item', () => {
-      const path: string = thumbnailPath;
-      const bitstream: Observable<Bitstream> = item.getThumbnail();
-      bitstream.pipe(map((b) => expect(b.content).toBe(path)));
-    });
-  });
-
-  describe('get files', () => {
-    beforeEach(() => {
-      spyOn(item, 'getBitstreamsByBundleName').and.returnValue(observableOf(bitstreams));
-    });
-
-    it("should return all bitstreams with 'ORIGINAL' as bundleName", () => {
-      const paths = [bitstream1Path, bitstream2Path];
-
-      const files: Observable<Bitstream[]> = item.getFiles();
-      let index = 0;
-      files.pipe(map((f) => expect(f.length).toBe(2)));
-      files.subscribe(
-        (array) => array.forEach(
-          (file) => {
-            expect(file.content).toBe(paths[index]);
-            index++;
-          }
-        )
-      )
-    });
-
-  });
 });
diff --git a/src/app/core/shared/item.model.ts b/src/app/core/shared/item.model.ts
index bd304274abf0e8ba5207f9e2f28d671e1a028097..e7f0ae9e1030f457289306014c4b6603aeb46515 100644
--- a/src/app/core/shared/item.model.ts
+++ b/src/app/core/shared/item.model.ts
@@ -1,122 +1,95 @@
-import { map, startWith, filter, switchMap } from 'rxjs/operators';
-import { Observable } from 'rxjs';
-
-import { DSpaceObject } from './dspace-object.model';
-import { Collection } from './collection.model';
-import { RemoteData } from '../data/remote-data';
-import { Bitstream } from './bitstream.model';
-import { hasValueOperator, isNotEmpty, isEmpty } from '../../shared/empty.util';
+import { autoserialize, autoserializeAs, deserialize, inheritSerialization } from 'cerialize';
+import { Observable } from 'rxjs/internal/Observable';
+import { isEmpty } from '../../shared/empty.util';
+import { DEFAULT_ENTITY_TYPE } from '../../shared/metadata-representation/metadata-representation.decorator';
+import { ListableObject } from '../../shared/object-collection/shared/listable-object.model';
+import { link, typedObject } from '../cache/builders/build-decorators';
 import { PaginatedList } from '../data/paginated-list';
-import { Relationship } from './item-relationships/relationship.model';
-import { ResourceType } from './resource-type';
-import { getAllSucceededRemoteData, getSucceededRemoteData } from './operators';
+import { RemoteData } from '../data/remote-data';
 import { Bundle } from './bundle.model';
+import { BUNDLE } from './bundle.resource-type';
+import { Collection } from './collection.model';
+import { COLLECTION } from './collection.resource-type';
+
+import { DSpaceObject } from './dspace-object.model';
 import { GenericConstructor } from './generic-constructor';
-import { ListableObject } from '../../shared/object-collection/shared/listable-object.model';
-import { DEFAULT_ENTITY_TYPE } from '../../shared/metadata-representation/metadata-representation.decorator';
+import { HALLink } from './hal-link.model';
+import { Relationship } from './item-relationships/relationship.model';
+import { RELATIONSHIP } from './item-relationships/relationship.resource-type';
+import { ITEM } from './item.resource-type';
+import { ChildHALResource } from './child-hal-resource.model';
 
 /**
  * Class representing a DSpace Item
  */
-export class Item extends DSpaceObject {
-  static type = new ResourceType('item');
+@typedObject
+@inheritSerialization(DSpaceObject)
+export class Item extends DSpaceObject implements ChildHALResource {
+  static type = ITEM;
 
   /**
    * A string representing the unique handle of this Item
    */
+  @autoserialize
   handle: string;
 
   /**
    * The Date of the last modification of this Item
    */
+  @deserialize
   lastModified: Date;
 
   /**
    * A boolean representing if this Item is currently archived or not
    */
+  @autoserializeAs(Boolean, 'inArchive')
   isArchived: boolean;
 
   /**
    * A boolean representing if this Item is currently discoverable or not
    */
+  @autoserializeAs(Boolean, 'discoverable')
   isDiscoverable: boolean;
 
   /**
    * A boolean representing if this Item is currently withdrawn or not
    */
+  @autoserializeAs(Boolean, 'withdrawn')
   isWithdrawn: boolean;
 
   /**
-   * An array of Collections that are direct parents of this Item
-   */
-  parents: Observable<RemoteData<Collection[]>>;
-
-  /**
-   * The Collection that owns this Item
-   */
-  owningCollection: Observable<RemoteData<Collection>>;
-
-  get owner(): Observable<RemoteData<Collection>> {
-    return this.owningCollection;
-  }
-
-  /**
-   * Bitstream bundles within this item
-   */
-  bundles: Observable<RemoteData<PaginatedList<Bundle>>>;
-
-  relationships: Observable<RemoteData<PaginatedList<Relationship>>>;
-
-  /**
-   * Retrieves the thumbnail of this item
-   * @returns {Observable<Bitstream>} the primaryBitstream of the 'THUMBNAIL' bundle
+   * The {@link HALLink}s for this Item
    */
-  getThumbnail(): Observable<Bitstream> {
-    // TODO: currently this just picks the first thumbnail
-    // should be adjusted when we have a way to determine
-    // the primary thumbnail from rest
-    return this.getBitstreamsByBundleName('THUMBNAIL').pipe(
-      filter((thumbnails) => isNotEmpty(thumbnails)),
-      map((thumbnails) => thumbnails[0]),)
-  }
+  @deserialize
+  _links: {
+    mappedCollections: HALLink;
+    relationships: HALLink;
+    bundles: HALLink;
+    owningCollection: HALLink;
+    templateItemOf: HALLink;
+    self: HALLink;
+  };
 
   /**
-   * Retrieves the thumbnail for the given original of this item
-   * @returns {Observable<Bitstream>} the primaryBitstream of the 'THUMBNAIL' bundle
+   * The owning Collection for this Item
+   * Will be undefined unless the owningCollection {@link HALLink} has been resolved.
    */
-  getThumbnailForOriginal(original: Bitstream): Observable<Bitstream> {
-    return this.getBitstreamsByBundleName('THUMBNAIL').pipe(
-      map((files) => {
-        return files.find((thumbnail) => thumbnail.name.startsWith(original.name))
-      }),startWith(undefined),);
-  }
+  @link(COLLECTION)
+  owningCollection?: Observable<RemoteData<Collection>>;
 
   /**
-   * Retrieves all files that should be displayed on the item page of this item
-   * @returns {Observable<Array<Observable<Bitstream>>>} an array of all Bitstreams in the 'ORIGINAL' bundle
+   * The list of Bundles inside this Item
+   * Will be undefined unless the bundles {@link HALLink} has been resolved.
    */
-  getFiles(): Observable<Bitstream[]> {
-    return this.getBitstreamsByBundleName('ORIGINAL');
-  }
+  @link(BUNDLE, true)
+  bundles?: Observable<RemoteData<PaginatedList<Bundle>>>;
 
   /**
-   * Retrieves bitstreams by bundle name
-   * @param bundleName The name of the Bundle that should be returned
-   * @returns {Observable<Bitstream[]>} the bitstreams with the given bundleName
-   * TODO now that bitstreams can be paginated this should move to the server
-   * see https://github.com/DSpace/dspace-angular/issues/332
+   * The list of Relationships this Item has with others
+   * Will be undefined unless the relationships {@link HALLink} has been resolved.
    */
-  getBitstreamsByBundleName(bundleName: string): Observable<Bitstream[]> {
-    return this.bundles.pipe(
-      getSucceededRemoteData(),
-      map((rd: RemoteData<PaginatedList<Bundle>>) => rd.payload.page.find((bundle: Bundle) => bundle.name === bundleName)),
-      hasValueOperator(),
-      switchMap((bundle: Bundle) => bundle.bitstreams),
-      getAllSucceededRemoteData(),
-      map((rd: RemoteData<PaginatedList<Bitstream>>) => rd.payload.page),
-      startWith([])
-    );
-  }
+  @link(RELATIONSHIP, true)
+  relationships?: Observable<RemoteData<PaginatedList<Relationship>>>;
 
   /**
    * Method that returns as which type of object this object should be rendered
@@ -128,4 +101,8 @@ export class Item extends DSpaceObject {
     }
     return [entityType, ...super.getRenderTypes()];
   }
+
+  getParentLinkKey(): keyof this['_links'] {
+    return 'owningCollection';
+  }
 }
diff --git a/src/app/core/shared/item.resource-type.ts b/src/app/core/shared/item.resource-type.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8371f6b9b5bacf7e932ae29fb2b060e778144bce
--- /dev/null
+++ b/src/app/core/shared/item.resource-type.ts
@@ -0,0 +1,9 @@
+import { ResourceType } from './resource-type';
+
+/**
+ * The resource type for Item.
+ *
+ * Needs to be in a separate file to prevent circular
+ * dependencies in webpack.
+ */
+export const ITEM = new ResourceType('item');
diff --git a/src/app/core/shared/license.model.ts b/src/app/core/shared/license.model.ts
index fa49e1f430f9ee8cdac6e4dfce262b754d0cc560..2b2477c1f8f2e9be613597575420913bbdb7dfb9 100644
--- a/src/app/core/shared/license.model.ts
+++ b/src/app/core/shared/license.model.ts
@@ -1,16 +1,22 @@
+import { autoserialize, inheritSerialization } from 'cerialize';
+import { typedObject } from '../cache/builders/build-decorators';
 import { DSpaceObject } from './dspace-object.model';
-import { ResourceType } from './resource-type';
+import { LICENSE } from './license.resource-type';
 
+@typedObject
+@inheritSerialization(DSpaceObject)
 export class License extends DSpaceObject {
-  static type = new ResourceType('license');
+  static type = LICENSE;
 
   /**
    * Is the license custom?
    */
+  @autoserialize
   custom: boolean;
 
   /**
    * The text of the license
    */
+  @autoserialize
   text: string;
 }
diff --git a/src/app/core/shared/license.resource-type.ts b/src/app/core/shared/license.resource-type.ts
new file mode 100644
index 0000000000000000000000000000000000000000..0e53525ac5cd31080106b3cef5c3cc0602027149
--- /dev/null
+++ b/src/app/core/shared/license.resource-type.ts
@@ -0,0 +1,9 @@
+import { ResourceType } from './resource-type';
+
+/**
+ * The resource type for License
+ *
+ * Needs to be in a separate file to prevent circular
+ * dependencies in webpack.
+ */
+export const LICENSE = new ResourceType('license');
diff --git a/src/app/core/shared/normalized-browse-entry.model.ts b/src/app/core/shared/normalized-browse-entry.model.ts
deleted file mode 100644
index 949758cb673354d1240a733de32b86aba9953188..0000000000000000000000000000000000000000
--- a/src/app/core/shared/normalized-browse-entry.model.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-import { autoserialize, autoserializeAs, inheritSerialization } from 'cerialize';
-import { BrowseEntry } from './browse-entry.model';
-import { NormalizedObject } from '../cache/models/normalized-object.model';
-import { mapsTo } from '../cache/builders/build-decorators';
-
-/**
- * Class object representing a browse entry
- * This class is not normalized because browse entries do not have self links
- */
-@mapsTo(BrowseEntry)
-@inheritSerialization(NormalizedObject)
-export class NormalizedBrowseEntry extends NormalizedObject<BrowseEntry> {
-  /**
-   * The authority string of this browse entry
-   */
-  @autoserialize
-  authority: string;
-
-  /**
-   * The value of this browse entry
-   */
-  @autoserialize
-  value: string;
-
-  /**
-   * The language of the value of this browse entry
-   */
-  @autoserializeAs('valueLang')
-  language: string;
-
-  /**
-   * The count of this browse entry
-   */
-  @autoserialize
-  count: number;
-}
diff --git a/src/app/core/shared/operators.ts b/src/app/core/shared/operators.ts
index af927c3d469932dbcb699b43c094ed51142d508a..a51e711d2659bb729fe6dc21bdcb7d7b16daa43d 100644
--- a/src/app/core/shared/operators.ts
+++ b/src/app/core/shared/operators.ts
@@ -1,16 +1,16 @@
+import { Router } from '@angular/router';
 import { Observable } from 'rxjs';
 import { filter, find, flatMap, map, take, tap } from 'rxjs/operators';
 import { hasValue, hasValueOperator, isNotEmpty } from '../../shared/empty.util';
+import { SearchResult } from '../../shared/search/search-result.model';
 import { DSOSuccessResponse, RestResponse } from '../cache/response.models';
+import { PaginatedList } from '../data/paginated-list';
 import { RemoteData } from '../data/remote-data';
 import { RestRequest } from '../data/request.models';
 import { RequestEntry } from '../data/request.reducer';
 import { RequestService } from '../data/request.service';
 import { BrowseDefinition } from './browse-definition.model';
 import { DSpaceObject } from './dspace-object.model';
-import { PaginatedList } from '../data/paginated-list';
-import { SearchResult } from '../../shared/search/search-result.model';
-import { Router } from '@angular/router';
 
 /**
  * This file contains custom RxJS operators that can be used in multiple places
@@ -59,10 +59,92 @@ export const getRemoteDataPayload = () =>
   <T>(source: Observable<RemoteData<T>>): Observable<T> =>
     source.pipe(map((remoteData: RemoteData<T>) => remoteData.payload));
 
+export const getPaginatedListPayload = () =>
+  <T>(source: Observable<PaginatedList<T>>): Observable<T[]> =>
+    source.pipe(map((list: PaginatedList<T>) => list.page));
+
 export const getSucceededRemoteData = () =>
   <T>(source: Observable<RemoteData<T>>): Observable<RemoteData<T>> =>
     source.pipe(find((rd: RemoteData<T>) => rd.hasSucceeded));
 
+/**
+ * Get the first successful remotely retrieved object
+ *
+ * You usually don't want to use this, it is a code smell.
+ * Work with the RemoteData object instead, that way you can
+ * handle loading and errors correctly.
+ *
+ * These operators were created as a first step in refactoring
+ * out all the instances where this is used incorrectly.
+ */
+export const getFirstSucceededRemoteDataPayload = () =>
+  <T>(source: Observable<RemoteData<T>>): Observable<T> =>
+    source.pipe(
+      getSucceededRemoteData(),
+      getRemoteDataPayload()
+    );
+
+/**
+ * Get the all successful remotely retrieved objects
+ *
+ * You usually don't want to use this, it is a code smell.
+ * Work with the RemoteData object instead, that way you can
+ * handle loading and errors correctly.
+ *
+ * These operators were created as a first step in refactoring
+ * out all the instances where this is used incorrectly.
+ */
+export const getAllSucceededRemoteDataPayload = () =>
+  <T>(source: Observable<RemoteData<T>>): Observable<T> =>
+    source.pipe(
+      getAllSucceededRemoteData(),
+      getRemoteDataPayload()
+    );
+
+/**
+ * Get the first successful remotely retrieved paginated list
+ * as an array
+ *
+ * You usually don't want to use this, it is a code smell.
+ * Work with the RemoteData object instead, that way you can
+ * handle loading and errors correctly.
+ *
+ * You also don't want to ignore pagination and simply use the
+ * page as an array.
+ *
+ * These operators were created as a first step in refactoring
+ * out all the instances where this is used incorrectly.
+ */
+export const getFirstSucceededRemoteListPayload = () =>
+  <T>(source: Observable<RemoteData<PaginatedList<T>>>): Observable<T[]> =>
+    source.pipe(
+      getSucceededRemoteData(),
+      getRemoteDataPayload(),
+      getPaginatedListPayload()
+    );
+
+/**
+ * Get all successful remotely retrieved paginated lists
+ * as arrays
+ *
+ * You usually don't want to use this, it is a code smell.
+ * Work with the RemoteData object instead, that way you can
+ * handle loading and errors correctly.
+ *
+ * You also don't want to ignore pagination and simply use the
+ * page as an array.
+ *
+ * These operators were created as a first step in refactoring
+ * out all the instances where this is used incorrectly.
+ */
+export const getAllSucceededRemoteListPayload = () =>
+  <T>(source: Observable<RemoteData<PaginatedList<T>>>): Observable<T[]> =>
+    source.pipe(
+      getAllSucceededRemoteData(),
+      getRemoteDataPayload(),
+      getPaginatedListPayload()
+    );
+
 /**
  * Operator that checks if a remote data object contains a page not found error
  * When it does contain such an error, it will redirect the user to a page not found, without altering the current URL
@@ -126,18 +208,6 @@ export const getFirstOccurrence = () =>
       map((rd) => Object.assign(rd, { payload: rd.payload.page.length > 0 ? rd.payload.page[0] : undefined }))
     );
 
-/**
- * Get the first succeeded RemoteData's payload
- */
-export const getFirstSucceededRemoteDataPayload = () =>
-  <T>(source: Observable<RemoteData<T>>): Observable<T> =>
-    source.pipe(
-      getSucceededRemoteData(),
-      getRemoteDataPayload(),
-      hasValueOperator(),
-      take(1)
-    );
-
 /**
  * Operator for turning the current page of bitstreams into an array
  */
diff --git a/src/app/core/shared/page-info.model.ts b/src/app/core/shared/page-info.model.ts
index 273510da60b31c5ad47e6a7a773c1b9e34b7d619..ccb0aae4718acd5149682142904a3502d2602a95 100644
--- a/src/app/core/shared/page-info.model.ts
+++ b/src/app/core/shared/page-info.model.ts
@@ -1,10 +1,12 @@
-import { autoserialize, autoserializeAs } from 'cerialize';
+import { autoserialize, autoserializeAs, deserialize } from 'cerialize';
 import { hasValue } from '../../shared/empty.util';
+import { HALLink } from './hal-link.model';
+import { HALResource } from './hal-resource.model';
 
 /**
  * Represents the state of a paginated response
  */
-export class PageInfo {
+export class PageInfo implements HALResource {
 
   /**
    * The number of elements on a page
@@ -30,20 +32,17 @@ export class PageInfo {
   @autoserializeAs(Number, 'number')
   currentPage: number;
 
-  @autoserialize
-  last: string;
-
-  @autoserialize
-  next: string;
-
-  @autoserialize
-  prev: string;
-
-  @autoserialize
-  first: string;
-
-  @autoserialize
-  self: string;
+  /**
+   * The {@link HALLink}s for this PageInfo
+   */
+  @deserialize
+  _links: {
+    first: HALLink;
+    prev: HALLink;
+    next: HALLink;
+    last: HALLink;
+    self: HALLink;
+  };
 
   constructor(
     options?: {
@@ -60,4 +59,41 @@ export class PageInfo {
       this.currentPage = options.currentPage;
     }
   }
+
+  get self() {
+    return this._links.self.href;
+  }
+
+  get last(): string {
+    if (hasValue(this._links) && hasValue(this._links.last)) {
+      return this._links.last.href;
+    } else {
+      return undefined;
+    }
+  }
+
+  get next(): string {
+    if (hasValue(this._links) && hasValue(this._links.next)) {
+      return this._links.next.href;
+    } else {
+      return undefined;
+    }
+  }
+
+  get prev(): string {
+    if (hasValue(this._links) && hasValue(this._links.prev)) {
+      return this._links.prev.href;
+    } else {
+      return undefined;
+    }
+  }
+
+  get first(): string {
+    if (hasValue(this._links) && hasValue(this._links.first)) {
+      return this._links.first.href;
+    } else {
+      return undefined;
+    }
+  }
+
 }
diff --git a/src/app/core/shared/resource-policy.model.ts b/src/app/core/shared/resource-policy.model.ts
index a80446a369eb2e689d47484282be1d79f5da5f80..dd00a16e9732a2a1bd9b7ad244a959b3f68e6a19 100644
--- a/src/app/core/shared/resource-policy.model.ts
+++ b/src/app/core/shared/resource-policy.model.ts
@@ -1,36 +1,58 @@
+import { autoserialize, deserialize, deserializeAs } from 'cerialize';
+import { typedObject } from '../cache/builders/build-decorators';
+import { IDToUUIDSerializer } from '../cache/id-to-uuid-serializer';
+import { ActionType } from '../cache/models/action-type.model';
 import { CacheableObject } from '../cache/object-cache.reducer';
+import { excludeFromEquals } from '../utilities/equals.decorators';
+import { HALLink } from './hal-link.model';
+import { RESOURCE_POLICY } from './resource-policy.resource-type';
 import { ResourceType } from './resource-type';
-import { ActionType } from '../cache/models/action-type.model';
 
 /**
  * Model class for a Resource Policy
  */
+@typedObject
 export class ResourcePolicy implements CacheableObject {
-  static type = new ResourceType('resourcePolicy');
+  static type = RESOURCE_POLICY;
+
+  /**
+   * The object type
+   */
+  @excludeFromEquals
+  @autoserialize
+  type: ResourceType;
 
   /**
    * The action that is allowed by this Resource Policy
    */
+  @autoserialize
   action: ActionType;
 
   /**
    * The name for this Resource Policy
    */
+  @autoserialize
   name: string;
 
   /**
    * The uuid of the Group this Resource Policy applies to
    */
+  @autoserialize
   groupUUID: string;
 
-  /**
-   * The link to the rest endpoint where this Resource Policy can be found
-   */
-  self: string;
-
   /**
    * The universally unique identifier for this Resource Policy
+   * This UUID is generated client-side and isn't used by the backend.
+   * It is based on the ID, so it will be the same for each refresh.
    */
+  @deserializeAs(new IDToUUIDSerializer('resource-policy'), 'id')
   uuid: string;
 
+  /**
+   * The {@link HALLink}s for this ResourcePolicy
+   */
+  @deserialize
+  _links: {
+    self: HALLink,
+  }
 }
diff --git a/src/app/core/shared/resource-policy.resource-type.ts b/src/app/core/shared/resource-policy.resource-type.ts
new file mode 100644
index 0000000000000000000000000000000000000000..1811a3a0d130dab47a7f7256898da50cb0a84a31
--- /dev/null
+++ b/src/app/core/shared/resource-policy.resource-type.ts
@@ -0,0 +1,9 @@
+import { ResourceType } from './resource-type';
+
+/**
+ * The resource type for ResourcePolicy
+ *
+ * Needs to be in a separate file to prevent circular
+ * dependencies in webpack.
+ */
+export const RESOURCE_POLICY = new ResourceType('resourcePolicy');
diff --git a/src/app/core/shared/search/search.service.ts b/src/app/core/shared/search/search.service.ts
index 141f261990f2cd7316fa1266aeae44a5efc147bd..06dfd6dba0b3da1f99412be286204d4c8e95d422 100644
--- a/src/app/core/shared/search/search.service.ts
+++ b/src/app/core/shared/search/search.service.ts
@@ -2,6 +2,8 @@ import { combineLatest as observableCombineLatest, Observable, of as observableO
 import { Injectable, OnDestroy } from '@angular/core';
 import { NavigationExtras, Router } from '@angular/router';
 import { first, map, switchMap, tap } from 'rxjs/operators';
+import { followLink, FollowLinkConfig } from '../../../shared/utils/follow-link-config.model';
+import { LinkService } from '../../cache/builders/link.service';
 import { FacetConfigSuccessResponse, FacetValueSuccessResponse, SearchSuccessResponse } from '../../cache/response.models';
 import { PaginatedList } from '../../data/paginated-list';
 import { ResponseParsingService } from '../../data/parsing.service';
@@ -13,7 +15,6 @@ import { GenericConstructor } from '../generic-constructor';
 import { HALEndpointService } from '../hal-endpoint.service';
 import { URLCombiner } from '../../url-combiner/url-combiner';
 import { hasValue, isEmpty, isNotEmpty, isNotUndefined } from '../../../shared/empty.util';
-import { NormalizedSearchResult } from '../../../shared/search/normalized-search-result.model';
 import { SearchOptions } from '../../../shared/search/search-options.model';
 import { SearchResult } from '../../../shared/search/search-result.model';
 import { FacetValue } from '../../../shared/search/facet-value.model';
@@ -69,6 +70,7 @@ export class SearchService implements OnDestroy {
               private routeService: RouteService,
               protected requestService: RequestService,
               private rdb: RemoteDataBuildService,
+              private linkService: LinkService,
               private halService: HALEndpointService,
               private communityService: CommunityDataService,
               private dspaceObjectService: DSpaceObjectDataService
@@ -105,10 +107,11 @@ export class SearchService implements OnDestroy {
    * Method to retrieve a paginated list of search results from the server
    * @param {PaginatedSearchOptions} searchOptions The configuration necessary to perform this search
    * @param responseMsToLive The amount of milliseconds for the response to live in cache
+   * @param linksToFollow List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved
    * @returns {Observable<RemoteData<PaginatedList<SearchResult<DSpaceObject>>>>} Emits a paginated list with all search results found
    */
-  search(searchOptions?: PaginatedSearchOptions, responseMsToLive?: number): Observable<RemoteData<PaginatedList<SearchResult<DSpaceObject>>>> {
-    return this.getPaginatedResults(this.searchEntries(searchOptions));
+  search<T extends DSpaceObject>(searchOptions?: PaginatedSearchOptions, responseMsToLive?: number, ...linksToFollow: Array<FollowLinkConfig<T>>): Observable<RemoteData<PaginatedList<SearchResult<DSpaceObject>>>> {
+    return this.getPaginatedResults<T>(this.searchEntries(searchOptions), ...linksToFollow);
   }
 
   /**
@@ -149,9 +152,10 @@ export class SearchService implements OnDestroy {
   /**
    * Method to convert the parsed responses into a paginated list of search results
    * @param searchEntries: The request entries from the search method
+   * @param linksToFollow List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved
    * @returns {Observable<RemoteData<PaginatedList<SearchResult<DSpaceObject>>>>} Emits a paginated list with all search results found
    */
-  getPaginatedResults(searchEntries: Observable<{ searchOptions: PaginatedSearchOptions, requestEntry: RequestEntry }>): Observable<RemoteData<PaginatedList<SearchResult<DSpaceObject>>>> {
+  getPaginatedResults<T extends DSpaceObject>(searchEntries: Observable<{ searchOptions: PaginatedSearchOptions, requestEntry: RequestEntry }>, ...linksToFollow: Array<FollowLinkConfig<T>>): Observable<RemoteData<PaginatedList<SearchResult<DSpaceObject>>>> {
     const requestEntryObs: Observable<RequestEntry> = searchEntries.pipe(
       map((entry) => entry.requestEntry),
     );
@@ -167,19 +171,19 @@ export class SearchService implements OnDestroy {
     const dsoObs: Observable<RemoteData<DSpaceObject[]>> = sqrObs.pipe(
       map((sqr: SearchQueryResponse) => {
         return sqr.objects
-          .filter((nsr: NormalizedSearchResult) => isNotUndefined(nsr.indexableObject))
-          .map((nsr: NormalizedSearchResult) => new GetRequest(this.requestService.generateRequestId(), nsr.indexableObject))
+          .filter((sr: SearchResult<DSpaceObject>) => isNotUndefined(sr._links.indexableObject))
+          .map((sr: SearchResult<DSpaceObject>) => new GetRequest(this.requestService.generateRequestId(), sr._links.indexableObject.href))
       }),
       // Send a request for each item to ensure fresh cache
       tap((reqs: RestRequest[]) => reqs.forEach((req: RestRequest) => this.requestService.configure(req))),
-      map((reqs: RestRequest[]) => reqs.map((req: RestRequest) => this.rdb.buildSingle(req.href))),
+      map((reqs: RestRequest[]) => reqs.map((req: RestRequest) => this.rdb.buildSingle(req.href, ...linksToFollow))),
       switchMap((input: Array<Observable<RemoteData<DSpaceObject>>>) => this.rdb.aggregate(input)),
     );
 
     // Create search results again with the correct dso objects linked to each result
     const tDomainListObs = observableCombineLatest(sqrObs, dsoObs).pipe(
       map(([sqr, dsos]) => {
-        return sqr.objects.map((object: NormalizedSearchResult, index: number) => {
+        return sqr.objects.map((object: SearchResult<DSpaceObject>, index: number) => {
           let co = DSpaceObject;
           if (dsos.payload[index]) {
             const constructor: GenericConstructor<ListableObject> = dsos.payload[index].constructor as GenericConstructor<ListableObject>;
@@ -340,6 +344,7 @@ export class SearchService implements OnDestroy {
       switchMap((dsoRD: RemoteData<DSpaceObject>) => {
           if ((dsoRD.payload as any).type === Community.type.value) {
             const community: Community = dsoRD.payload as Community;
+            this.linkService.resolveLinks(community, followLink('subcommunities'), followLink('collections'));
             return observableCombineLatest(community.subcommunities, community.collections).pipe(
               map(([subCommunities, collections]) => {
                 /*if this is a community, we also need to show the direct children*/
diff --git a/src/app/core/shared/site.model.ts b/src/app/core/shared/site.model.ts
index a191b2143fe1945ffc30ffabfd4e03168fad56d2..befd4c1ae3435f10a235ca45cf330e6c72027a41 100644
--- a/src/app/core/shared/site.model.ts
+++ b/src/app/core/shared/site.model.ts
@@ -1,11 +1,15 @@
+import { inheritSerialization } from 'cerialize';
+import { typedObject } from '../cache/builders/build-decorators';
 import { DSpaceObject } from './dspace-object.model';
-import { ResourceType } from './resource-type';
+import { SITE } from './site.resource-type';
 
 /**
  * Model class for the Site object
  */
+@typedObject
+@inheritSerialization(DSpaceObject)
 export class Site extends DSpaceObject {
 ​
-  static type = new ResourceType('site');
+  static type = SITE;
 ​
 }
diff --git a/src/app/core/shared/site.resource-type.ts b/src/app/core/shared/site.resource-type.ts
new file mode 100644
index 0000000000000000000000000000000000000000..570697833fc17d724831ead6160ea3caff09fa34
--- /dev/null
+++ b/src/app/core/shared/site.resource-type.ts
@@ -0,0 +1,9 @@
+import { ResourceType } from './resource-type';
+
+/**
+ * The resource type for Site
+ *
+ * Needs to be in a separate file to prevent circular
+ * dependencies in webpack.
+ */
+export const SITE = new ResourceType('site');
diff --git a/src/app/core/submission/models/normalized-submission-object.model.ts b/src/app/core/submission/models/normalized-submission-object.model.ts
deleted file mode 100644
index f674ebdf72dd96dfe15275c415b179461b30c69d..0000000000000000000000000000000000000000
--- a/src/app/core/submission/models/normalized-submission-object.model.ts
+++ /dev/null
@@ -1,43 +0,0 @@
-import { autoserialize, autoserializeAs, inheritSerialization } from 'cerialize';
-
-import { NormalizedDSpaceObject } from '../../cache/models/normalized-dspace-object.model';
-import { WorkspaceitemSectionsObject } from './workspaceitem-sections.model';
-import { SubmissionObjectError } from './submission-object.model';
-import { DSpaceObject } from '../../shared/dspace-object.model';
-
-/**
- * An abstract model class for a NormalizedSubmissionObject.
- */
-@inheritSerialization(NormalizedDSpaceObject)
-export class NormalizedSubmissionObject<T extends DSpaceObject> extends NormalizedDSpaceObject<T> {
-
-  /**
-   * The workspaceitem/workflowitem identifier
-   */
-  @autoserialize
-  id: string;
-
-  /**
-   * The workspaceitem/workflowitem identifier
-   */
-  @autoserializeAs(String, 'id')
-  uuid: string;
-
-  /**
-   * The workspaceitem/workflowitem last modified date
-   */
-  @autoserialize
-  lastModified: Date;
-
-  /**
-   * The workspaceitem/workflowitem last sections data
-   */
-  @autoserialize
-  sections: WorkspaceitemSectionsObject;
-
-  /**
-   * The workspaceitem/workflowitem last sections errors
-   */
-  @autoserialize
-  errors: SubmissionObjectError[];
-}
diff --git a/src/app/core/submission/models/normalized-workflowitem.model.ts b/src/app/core/submission/models/normalized-workflowitem.model.ts
deleted file mode 100644
index e96024b4aefbb4a1cbb9c2b24a8f11795b7210b0..0000000000000000000000000000000000000000
--- a/src/app/core/submission/models/normalized-workflowitem.model.ts
+++ /dev/null
@@ -1,46 +0,0 @@
-import { autoserialize, inheritSerialization } from 'cerialize';
-
-import { mapsTo, relationship } from '../../cache/builders/build-decorators';
-import { WorkflowItem } from './workflowitem.model';
-import { NormalizedSubmissionObject } from './normalized-submission-object.model';
-import { Collection } from '../../shared/collection.model';
-import { Item } from '../../shared/item.model';
-import { SubmissionDefinitionsModel } from '../../config/models/config-submission-definitions.model';
-import { EPerson } from '../../eperson/models/eperson.model';
-
-/**
- * An model class for a NormalizedWorkflowItem.
- */
-@mapsTo(WorkflowItem)
-@inheritSerialization(NormalizedSubmissionObject)
-export class NormalizedWorkflowItem extends NormalizedSubmissionObject<WorkflowItem> {
-
-  /**
-   * The collection this workflowitem belonging to
-   */
-  @autoserialize
-  @relationship(Collection, false)
-  collection: string;
-
-  /**
-   * The item created with this workflowitem
-   */
-  @autoserialize
-  @relationship(Item, false)
-  item: string;
-
-  /**
-   * The configuration object that define this workflowitem
-   */
-  @autoserialize
-  @relationship(SubmissionDefinitionsModel, false)
-  submissionDefinition: string;
-
-  /**
-   * The EPerson who submit this workflowitem
-   */
-  @autoserialize
-  @relationship(EPerson, false)
-  submitter: string;
-
-}
diff --git a/src/app/core/submission/models/normalized-workspaceitem.model.ts b/src/app/core/submission/models/normalized-workspaceitem.model.ts
deleted file mode 100644
index 427542019146a20a7d13551001250815acf47a47..0000000000000000000000000000000000000000
--- a/src/app/core/submission/models/normalized-workspaceitem.model.ts
+++ /dev/null
@@ -1,47 +0,0 @@
-import { autoserialize, inheritSerialization } from 'cerialize';
-
-import { WorkspaceItem } from './workspaceitem.model';
-import { NormalizedSubmissionObject } from './normalized-submission-object.model';
-import { mapsTo, relationship } from '../../cache/builders/build-decorators';
-import { NormalizedDSpaceObject } from '../../cache/models/normalized-dspace-object.model';
-import { Item } from '../../shared/item.model';
-import { Collection } from '../../shared/collection.model';
-import { SubmissionDefinitionModel } from '../../config/models/config-submission-definition.model';
-import { EPerson } from '../../eperson/models/eperson.model';
-
-/**
- * An model class for a NormalizedWorkspaceItem.
- */
-@mapsTo(WorkspaceItem)
-@inheritSerialization(NormalizedDSpaceObject)
-@inheritSerialization(NormalizedSubmissionObject)
-export class NormalizedWorkspaceItem extends NormalizedSubmissionObject<WorkspaceItem> {
-
-  /**
-   * The collection this workspaceitem belonging to
-   */
-  @autoserialize
-  @relationship(Collection, false)
-  collection: string;
-
-  /**
-   * The item created with this workspaceitem
-   */
-  @autoserialize
-  @relationship(Item, false)
-  item: string;
-
-  /**
-   * The configuration object that define this workspaceitem
-   */
-  @autoserialize
-  @relationship(SubmissionDefinitionModel, false)
-  submissionDefinition: string;
-
-  /**
-   * The EPerson who submit this workspaceitem
-   */
-  @autoserialize
-  @relationship(EPerson, false)
-  submitter: string;
-}
diff --git a/src/app/core/submission/models/submission-object.model.ts b/src/app/core/submission/models/submission-object.model.ts
index 0b1110fa24dd18e9b1caac1d9ab89a8c6f5cb149..87ea19653dd78246356aa16799b0046b6ed98c39 100644
--- a/src/app/core/submission/models/submission-object.model.ts
+++ b/src/app/core/submission/models/submission-object.model.ts
@@ -1,12 +1,19 @@
+import { autoserialize, deserialize, inheritSerialization } from 'cerialize';
 import { Observable } from 'rxjs';
+import { link } from '../../cache/builders/build-decorators';
 
 import { CacheableObject } from '../../cache/object-cache.reducer';
-import { DSpaceObject } from '../../shared/dspace-object.model';
-import { EPerson } from '../../eperson/models/eperson.model';
+import { SubmissionDefinitionsModel } from '../../config/models/config-submission-definitions.model';
 import { RemoteData } from '../../data/remote-data';
+import { EPerson } from '../../eperson/models/eperson.model';
+import { EPERSON } from '../../eperson/models/eperson.resource-type';
 import { Collection } from '../../shared/collection.model';
+import { COLLECTION } from '../../shared/collection.resource-type';
+import { DSpaceObject } from '../../shared/dspace-object.model';
+import { HALLink } from '../../shared/hal-link.model';
 import { Item } from '../../shared/item.model';
-import { SubmissionDefinitionsModel } from '../../config/models/config-submission-definitions.model';
+import { ITEM } from '../../shared/item.resource-type';
+import { excludeFromEquals } from '../../utilities/equals.decorators';
 import { WorkspaceitemSectionsObject } from './workspaceitem-sections.model';
 
 export interface SubmissionObjectError {
@@ -17,50 +24,72 @@ export interface SubmissionObjectError {
 /**
  * An abstract model class for a SubmissionObject.
  */
+@inheritSerialization(DSpaceObject)
 export abstract class SubmissionObject extends DSpaceObject implements CacheableObject {
 
-  /**
-   * The workspaceitem/workflowitem identifier
-   */
+  @excludeFromEquals
+  @autoserialize
   id: string;
 
   /**
-   * The workspaceitem/workflowitem identifier
-   */
-  uuid: string;
-
-  /**
-   * The workspaceitem/workflowitem last modified date
+   * The SubmissionObject last modified date
    */
+  @autoserialize
   lastModified: Date;
 
   /**
    * The collection this submission applies to
+   * Will be undefined unless the collection {@link HALLink} has been resolved.
    */
-  collection: Observable<RemoteData<Collection>> | Collection;
+  @link(COLLECTION)
+  collection?: Observable<RemoteData<Collection>> | Collection;
 
   /**
-   * The submission item
+   * The SubmissionObject's last section's data
    */
-  item: Observable<RemoteData<Item>> | Item;
+  @autoserialize
+  sections: WorkspaceitemSectionsObject;
 
   /**
-   * The workspaceitem/workflowitem last sections data
+   * The SubmissionObject's last section's errors
    */
-  sections: WorkspaceitemSectionsObject;
+  @autoserialize
+  errors: SubmissionObjectError[];
 
   /**
-   * The configuration object that define this submission
+   * The {@link HALLink}s for this SubmissionObject
    */
-  submissionDefinition: Observable<RemoteData<SubmissionDefinitionsModel>> | SubmissionDefinitionsModel;
+  @deserialize
+  _links: {
+    self: HALLink;
+    collection: HALLink;
+    item: HALLink;
+    submissionDefinition: HALLink;
+    submitter: HALLink;
+  };
+
+  get self(): string {
+    return this._links.self.href;
+  }
 
   /**
-   * The workspaceitem submitter
+   * The submission item
+   * Will be undefined unless the item {@link HALLink} has been resolved.
    */
-  submitter: Observable<RemoteData<EPerson>> | EPerson;
+  @link(ITEM)
+  item?: Observable<RemoteData<Item>> | Item;
+  /**
+   * The configuration object that define this submission
+   * Will be undefined unless the submissionDefinition {@link HALLink} has been resolved.
+   */
+  @link(SubmissionDefinitionsModel.type)
+  submissionDefinition?: Observable<RemoteData<SubmissionDefinitionsModel>> | SubmissionDefinitionsModel;
 
   /**
-   * The workspaceitem/workflowitem last sections errors
+   * The submitter for this SubmissionObject
+   * Will be undefined unless the submitter {@link HALLink} has been resolved.
    */
-  errors: SubmissionObjectError[];
+  @link(EPERSON)
+  submitter?: Observable<RemoteData<EPerson>> | EPerson;
+
 }
diff --git a/src/app/core/submission/models/workflowitem.model.ts b/src/app/core/submission/models/workflowitem.model.ts
index 4cfc4d7fa13473a7af0791d10502b2fd9121ce7c..b8054a66d03977ed94199b7a30a47a91405a815b 100644
--- a/src/app/core/submission/models/workflowitem.model.ts
+++ b/src/app/core/submission/models/workflowitem.model.ts
@@ -1,9 +1,23 @@
-import { WorkspaceItem } from './workspaceitem.model';
-import { ResourceType } from '../../shared/resource-type';
+import { deserializeAs, inheritSerialization } from 'cerialize';
+import { inheritLinkAnnotations, typedObject } from '../../cache/builders/build-decorators';
+import { IDToUUIDSerializer } from '../../cache/id-to-uuid-serializer';
+import { WORKFLOWITEM } from '../../eperson/models/workflowitem.resource-type';
+import { SubmissionObject } from './submission-object.model';
 
 /**
  * A model class for a WorkflowItem.
  */
-export class WorkflowItem extends WorkspaceItem {
-  static type = new ResourceType('workflowitem');
+@typedObject
+@inheritSerialization(SubmissionObject)
+@inheritLinkAnnotations(SubmissionObject)
+export class WorkflowItem extends SubmissionObject {
+  static type = WORKFLOWITEM;
+
+  /**
+   * The universally unique identifier of this WorkflowItem
+   * This UUID is generated client-side and isn't used by the backend.
+   * It is based on the ID, so it will be the same for each refresh.
+   */
+  @deserializeAs(new IDToUUIDSerializer(WorkflowItem.type.value), 'id')
+  uuid: string;
 }
diff --git a/src/app/core/submission/models/workspaceitem.model.ts b/src/app/core/submission/models/workspaceitem.model.ts
index c4bb5b75201589274d932f53e6d298f34f53ad1a..b29d8c0efa02dd35e1bd13c13652390f988b771b 100644
--- a/src/app/core/submission/models/workspaceitem.model.ts
+++ b/src/app/core/submission/models/workspaceitem.model.ts
@@ -1,10 +1,24 @@
+import { deserializeAs, inheritSerialization } from 'cerialize';
+import { inheritLinkAnnotations, typedObject } from '../../cache/builders/build-decorators';
+import { IDToUUIDSerializer } from '../../cache/id-to-uuid-serializer';
+import { DSpaceObject } from '../../shared/dspace-object.model';
 import { SubmissionObject } from './submission-object.model';
 import { ResourceType } from '../../shared/resource-type';
 
 /**
  * A model class for a WorkspaceItem.
  */
+@typedObject
+@inheritSerialization(SubmissionObject)
+@inheritLinkAnnotations(SubmissionObject)
 export class WorkspaceItem extends SubmissionObject {
   static type = new ResourceType('workspaceitem');
 
+  /**
+   * The universally unique identifier of this WorkspaceItem
+   * This UUID is generated client-side and isn't used by the backend.
+   * It is based on the ID, so it will be the same for each refresh.
+   */
+  @deserializeAs(new IDToUUIDSerializer(WorkspaceItem.type.value), 'id')
+  uuid: string;
 }
diff --git a/src/app/core/submission/submission-object-data.service.spec.ts b/src/app/core/submission/submission-object-data.service.spec.ts
index b7c06272e68332c725d81ae3cad78ffd6a3c68e8..f46a465edbf134c8d86b8b880d3ba2e41515461b 100644
--- a/src/app/core/submission/submission-object-data.service.spec.ts
+++ b/src/app/core/submission/submission-object-data.service.spec.ts
@@ -45,7 +45,7 @@ describe('SubmissionObjectDataService', () => {
         service = new SubmissionObjectDataService(workspaceitemDataService, workflowItemDataService, submissionService);
       });
 
-      it('should forward the result of WorkspaceitemDataService.findById()', () => {
+      it('should forward the result of WorkspaceitemDataService.findByIdAndIDType()', () => {
         const result = service.findById(submissionId);
         expect(workspaceitemDataService.findById).toHaveBeenCalledWith(submissionId);
         expect(result).toBe(wsiResult);
@@ -60,7 +60,7 @@ describe('SubmissionObjectDataService', () => {
         service = new SubmissionObjectDataService(workspaceitemDataService, workflowItemDataService, submissionService);
       });
 
-      it('should forward the result of WorkflowItemDataService.findById()', () => {
+      it('should forward the result of WorkflowItemDataService.findByIdAndIDType()', () => {
         const result = service.findById(submissionId);
         expect(workflowItemDataService.findById).toHaveBeenCalledWith(submissionId);
         expect(result).toBe(wfiResult);
diff --git a/src/app/core/submission/submission-object-data.service.ts b/src/app/core/submission/submission-object-data.service.ts
index 15ede18cb83ff9f8e769aac47bb2995a4472ba29..0b6d65c7580807279d0620c066c4d919c152ac3a 100644
--- a/src/app/core/submission/submission-object-data.service.ts
+++ b/src/app/core/submission/submission-object-data.service.ts
@@ -1,5 +1,6 @@
 import { Injectable } from '@angular/core';
 import { of as observableOf, Observable } from 'rxjs';
+import { FollowLinkConfig } from '../../shared/utils/follow-link-config.model';
 import { SubmissionService } from '../../submission/submission.service';
 import { RemoteData } from '../data/remote-data';
 import { RemoteDataError } from '../data/remote-data-error';
@@ -27,13 +28,14 @@ export class SubmissionObjectDataService {
    * Retrieve a submission object based on its ID.
    *
    * @param id The identifier of a submission object
+   * @param linksToFollow   List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved
    */
-  findById(id: string): Observable<RemoteData<SubmissionObject>> {
+  findById(id: string, ...linksToFollow: Array<FollowLinkConfig<SubmissionObject>>): Observable<RemoteData<SubmissionObject>> {
     switch (this.submissionService.getSubmissionScope()) {
       case SubmissionScopeType.WorkspaceItem:
-        return this.workspaceitemDataService.findById(id);
+        return this.workspaceitemDataService.findById(id,...linksToFollow);
       case SubmissionScopeType.WorkflowItem:
-        return this.workflowItemDataService.findById(id);
+        return this.workflowItemDataService.findById(id,...linksToFollow);
       default:
         const error = new RemoteDataError(
           undefined,
diff --git a/src/app/core/submission/submission-response-parsing.service.ts b/src/app/core/submission/submission-response-parsing.service.ts
index 8bc29719224f351ae2f2cfe8f9f4a6b0ad13d11e..27a7e43c4646808ff1e124f85291817913a57556 100644
--- a/src/app/core/submission/submission-response-parsing.service.ts
+++ b/src/app/core/submission/submission-response-parsing.service.ts
@@ -12,10 +12,10 @@ import { BaseResponseParsingService } from '../data/base-response-parsing.servic
 import { GLOBAL_CONFIG } from '../../../config';
 import { GlobalConfig } from '../../../config/global-config.interface';
 import { ObjectCacheService } from '../cache/object-cache.service';
-import { NormalizedWorkspaceItem } from './models/normalized-workspaceitem.model';
-import { NormalizedWorkflowItem } from './models/normalized-workflowitem.model';
 import { FormFieldMetadataValueObject } from '../../shared/form/builder/models/form-field-metadata-value.model';
 import { SubmissionObject } from './models/submission-object.model';
+import { WorkflowItem } from './models/workflowitem.model';
+import { WorkspaceItem } from './models/workspaceitem.model';
 
 /**
  * Export a function to check if object has same properties of FormFieldMetadataValueObject
@@ -77,6 +77,18 @@ export class SubmissionResponseParsingService extends BaseResponseParsingService
 
   protected toCache = false;
 
+  /**
+   * The submission assumes certain related HALResources will always be embedded.
+   * It only works if the responseparser finds these embedded resources, and directly
+   * attaches them to the requested object, instead of putting them in the cache and
+   * treating them as separate objects. This boolean was added to allow us to disable
+   * that behavior for the rest of the application, while keeping it for the submission.
+   *
+   * It should be removed after the submission has been refactored to treat embeds as
+   * resources that may need to be retrieved separately.
+   */
+  protected shouldDirectlyAttachEmbeds = true;
+
   constructor(@Inject(GLOBAL_CONFIG) protected EnvConfig: GlobalConfig,
               protected objectCache: ObjectCacheService,
               protected dsoParser: DSOResponseParsingService
@@ -119,15 +131,15 @@ export class SubmissionResponseParsingService extends BaseResponseParsingService
    */
   protected processResponse<ObjectDomain>(data: any, request: RestRequest): any[] {
     const dataDefinition = this.process<ObjectDomain>(data, request);
-    const normalizedDefinition = Array.of();
+    const definition = Array.of();
     const processedList = Array.isArray(dataDefinition) ? dataDefinition : Array.of(dataDefinition);
 
     processedList.forEach((item) => {
 
-      let normalizedItem = Object.assign({}, item);
-      // In case data is an Instance of NormalizedWorkspaceItem normalize field value of all the section of type form
-      if (item instanceof NormalizedWorkspaceItem
-        || item instanceof NormalizedWorkflowItem) {
+      item = Object.assign({}, item);
+      // In case data is an Instance of WorkspaceItem normalize field value of all the section of type form
+      if (item instanceof WorkspaceItem
+        || item instanceof WorkflowItem) {
         if (item.sections) {
           const precessedSection = Object.create({});
           // Iterate over all workspaceitem's sections
@@ -137,35 +149,35 @@ export class SubmissionResponseParsingService extends BaseResponseParsingService
                 // When Upload section is disabled, add to submission only if there are files
                 (!item.sections[sectionId].hasOwnProperty('files') || isNotEmpty((item.sections[sectionId] as any).files)))) {
 
-                const normalizedSectionData = Object.create({});
+                const sectiondata = Object.create({});
                 // Iterate over all sections property
                 Object.keys(item.sections[sectionId])
                   .forEach((metdadataId) => {
                     const entry = item.sections[sectionId][metdadataId];
                     // If entry is not an array, for sure is not a section of type form
                     if (Array.isArray(entry)) {
-                      normalizedSectionData[metdadataId] = [];
+                      sectiondata[metdadataId] = [];
                       entry.forEach((valueItem, index) => {
                         // Parse value and normalize it
                         const normValue = normalizeSectionData(valueItem, index);
                         if (isNotEmpty(normValue)) {
-                          normalizedSectionData[metdadataId].push(normValue);
+                          sectiondata[metdadataId].push(normValue);
                         }
                       });
                     } else {
-                      normalizedSectionData[metdadataId] = entry;
+                      sectiondata[metdadataId] = entry;
                     }
                   });
-                precessedSection[sectionId] = normalizedSectionData;
+                precessedSection[sectionId] = sectiondata;
               }
             });
-          normalizedItem = Object.assign({}, item, { sections: precessedSection });
+          item = Object.assign({}, item, { sections: precessedSection });
         }
       }
-      normalizedDefinition.push(normalizedItem);
+      definition.push(item);
     });
 
-    return normalizedDefinition;
+    return definition;
   }
 
 }
diff --git a/src/app/core/submission/submission-rest.service.spec.ts b/src/app/core/submission/submission-rest.service.spec.ts
index eefc815435ffac9e0cf36a1e827e6010045e3db2..68d7ff13f4f4d91b6b19e1c1ea4f312f87c0ee94 100644
--- a/src/app/core/submission/submission-rest.service.spec.ts
+++ b/src/app/core/submission/submission-rest.service.spec.ts
@@ -26,7 +26,7 @@ describe('SubmissionRestService test suite', () => {
   const resourceEndpoint = 'workspaceitems';
   const resourceScope = '260';
   const body = { test: new FormFieldMetadataValueObject('test')};
-  const resourceHref = resourceEndpointURL + '/' + resourceEndpoint + '/' + resourceScope;
+  const resourceHref = resourceEndpointURL + '/' + resourceEndpoint + '/' + resourceScope + '?projection=full';
   const timestampResponse = 1545994811992;
 
   function initTestService() {
diff --git a/src/app/core/submission/submission-rest.service.ts b/src/app/core/submission/submission-rest.service.ts
index 32ba0700020aa69c47e2cb4fc8e50abf8f408da6..350874bc5033b65fdf6b748d7a3fbffa0172a013 100644
--- a/src/app/core/submission/submission-rest.service.ts
+++ b/src/app/core/submission/submission-rest.service.ts
@@ -71,8 +71,9 @@ export class SubmissionRestService {
    */
   protected getEndpointByIDHref(endpoint, resourceID, collectionId?: string): string {
     let url = isNotEmpty(resourceID) ? `${endpoint}/${resourceID}` : `${endpoint}`;
+    url = new URLCombiner(url, '?projection=full').toString();
     if (collectionId) {
-      url = new URLCombiner(url, `?owningCollection=${collectionId}`).toString();
+      url = new URLCombiner(url, `&owningCollection=${collectionId}`).toString();
     }
     return url;
   }
diff --git a/src/app/core/submission/workflowitem-data.service.ts b/src/app/core/submission/workflowitem-data.service.ts
index 47195ed0a11ef682f057930ca77ba739fb3caff7..a2dfca5eb315169711902ba1ab79da3621e04b4d 100644
--- a/src/app/core/submission/workflowitem-data.service.ts
+++ b/src/app/core/submission/workflowitem-data.service.ts
@@ -2,6 +2,7 @@ import { Injectable } from '@angular/core';
 import { HttpClient } from '@angular/common/http';
 
 import { Store } from '@ngrx/store';
+import { dataService } from '../cache/builders/build-decorators';
 import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
 import { CoreState } from '../core.reducers';
 import { DataService } from '../data/data.service';
@@ -9,7 +10,6 @@ import { RequestService } from '../data/request.service';
 import { WorkflowItem } from './models/workflowitem.model';
 import { HALEndpointService } from '../shared/hal-endpoint.service';
 import { FindListOptions } from '../data/request.models';
-import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service';
 import { NotificationsService } from '../../shared/notifications/notifications.service';
 import { ObjectCacheService } from '../cache/object-cache.service';
 import { DSOChangeAnalyzer } from '../data/dso-change-analyzer.service';
@@ -18,13 +18,13 @@ import { DSOChangeAnalyzer } from '../data/dso-change-analyzer.service';
  * A service that provides methods to make REST requests with workflowitems endpoint.
  */
 @Injectable()
+@dataService(WorkflowItem.type)
 export class WorkflowItemDataService extends DataService<WorkflowItem> {
   protected linkPath = 'workflowitems';
   protected responseMsToLive = 10 * 1000;
 
   constructor(
     protected comparator: DSOChangeAnalyzer<WorkflowItem>,
-    protected dataBuildService: NormalizedObjectBuildService,
     protected halService: HALEndpointService,
     protected http: HttpClient,
     protected notificationsService: NotificationsService,
@@ -35,8 +35,4 @@ export class WorkflowItemDataService extends DataService<WorkflowItem> {
     super();
   }
 
-  public getBrowseEndpoint(options: FindListOptions) {
-    return this.halService.getEndpoint(this.linkPath);
-  }
-
 }
diff --git a/src/app/core/submission/workspaceitem-data.service.ts b/src/app/core/submission/workspaceitem-data.service.ts
index 3f782b74a2fd3813c5b7ab117e12a50ea5e993b6..fcb85cc8b4bc1d2830e3f1d6dcff39f2dad9c9de 100644
--- a/src/app/core/submission/workspaceitem-data.service.ts
+++ b/src/app/core/submission/workspaceitem-data.service.ts
@@ -2,13 +2,13 @@ import { Injectable } from '@angular/core';
 import { HttpClient } from '@angular/common/http';
 
 import { Store } from '@ngrx/store';
+import { dataService } from '../cache/builders/build-decorators';
 import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
 import { CoreState } from '../core.reducers';
 import { DataService } from '../data/data.service';
 import { RequestService } from '../data/request.service';
 import { HALEndpointService } from '../shared/hal-endpoint.service';
 import { FindListOptions } from '../data/request.models';
-import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service';
 import { NotificationsService } from '../../shared/notifications/notifications.service';
 import { ObjectCacheService } from '../cache/object-cache.service';
 import { DSOChangeAnalyzer } from '../data/dso-change-analyzer.service';
@@ -18,13 +18,13 @@ import { WorkspaceItem } from './models/workspaceitem.model';
  * A service that provides methods to make REST requests with workspaceitems endpoint.
  */
 @Injectable()
+@dataService(WorkspaceItem.type)
 export class WorkspaceitemDataService extends DataService<WorkspaceItem> {
   protected linkPath = 'workspaceitems';
   protected responseMsToLive = 10 * 1000;
 
   constructor(
     protected comparator: DSOChangeAnalyzer<WorkspaceItem>,
-    protected dataBuildService: NormalizedObjectBuildService,
     protected halService: HALEndpointService,
     protected http: HttpClient,
     protected notificationsService: NotificationsService,
@@ -35,8 +35,4 @@ export class WorkspaceitemDataService extends DataService<WorkspaceItem> {
     super();
   }
 
-  public getBrowseEndpoint(options: FindListOptions) {
-    return this.halService.getEndpoint(this.linkPath);
-  }
-
 }
diff --git a/src/app/core/tasks/claimed-task-data.service.spec.ts b/src/app/core/tasks/claimed-task-data.service.spec.ts
index a7be0830ec17a890c7edb0d229a5043c5751126e..90d449b22ba21e0c7f5a86ffdf74241912c4592d 100644
--- a/src/app/core/tasks/claimed-task-data.service.spec.ts
+++ b/src/app/core/tasks/claimed-task-data.service.spec.ts
@@ -6,7 +6,6 @@ import { getMockRequestService } from '../../shared/mocks/mock-request.service';
 import { HALEndpointServiceStub } from '../../shared/testing/hal-endpoint-service-stub';
 import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
 import { NotificationsService } from '../../shared/notifications/notifications.service';
-import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service';
 import { CoreState } from '../core.reducers';
 import { ClaimedTaskDataService } from './claimed-task-data.service';
 import { HttpOptions } from '../dspace-rest-v2/dspace-rest-v2.service';
@@ -22,9 +21,6 @@ describe('ClaimedTaskDataService', () => {
   const notificationsService = {} as NotificationsService;
   const http = {} as HttpClient;
   const comparator = {} as any;
-  const dataBuildService = {
-    normalize: (object) => object
-  } as NormalizedObjectBuildService;
   const objectCache = {
     addPatch: () => {
       /* empty */
@@ -39,7 +35,6 @@ describe('ClaimedTaskDataService', () => {
     return new ClaimedTaskDataService(
       requestService,
       rdbService,
-      dataBuildService,
       store,
       objectCache,
       halService,
diff --git a/src/app/core/tasks/claimed-task-data.service.ts b/src/app/core/tasks/claimed-task-data.service.ts
index 76e5e769d7b3e22f2bcabc4603917c7dc15bafc7..0a9de2053026a650d1ef9de5f796369bb9cea4f7 100644
--- a/src/app/core/tasks/claimed-task-data.service.ts
+++ b/src/app/core/tasks/claimed-task-data.service.ts
@@ -1,25 +1,26 @@
-import { Injectable } from '@angular/core';
 import { HttpClient } from '@angular/common/http';
+import { Injectable } from '@angular/core';
 
 import { Store } from '@ngrx/store';
 import { Observable } from 'rxjs';
-
+import { NotificationsService } from '../../shared/notifications/notifications.service';
+import { dataService } from '../cache/builders/build-decorators';
 import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
+import { ObjectCacheService } from '../cache/object-cache.service';
 import { CoreState } from '../core.reducers';
+import { DSOChangeAnalyzer } from '../data/dso-change-analyzer.service';
 import { RequestService } from '../data/request.service';
-import { ClaimedTask } from './models/claimed-task-object.model';
-import { TasksService } from './tasks.service';
 import { HALEndpointService } from '../shared/hal-endpoint.service';
-import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service';
-import { ObjectCacheService } from '../cache/object-cache.service';
-import { NotificationsService } from '../../shared/notifications/notifications.service';
-import { DSOChangeAnalyzer } from '../data/dso-change-analyzer.service';
+import { ClaimedTask } from './models/claimed-task-object.model';
+import { CLAIMED_TASK } from './models/claimed-task-object.resource-type';
 import { ProcessTaskResponse } from './models/process-task-response';
+import { TasksService } from './tasks.service';
 
 /**
  * The service handling all REST requests for ClaimedTask
  */
 @Injectable()
+@dataService(CLAIMED_TASK)
 export class ClaimedTaskDataService extends TasksService<ClaimedTask> {
 
   protected responseMsToLive = 10 * 1000;
@@ -34,7 +35,7 @@ export class ClaimedTaskDataService extends TasksService<ClaimedTask> {
    *
    * @param {RequestService} requestService
    * @param {RemoteDataBuildService} rdbService
-   * @param {NormalizedObjectBuildService} dataBuildService
+   * @param {NormalizedObjectBuildService} linkService
    * @param {Store<CoreState>} store
    * @param {ObjectCacheService} objectCache
    * @param {HALEndpointService} halService
@@ -45,7 +46,6 @@ export class ClaimedTaskDataService extends TasksService<ClaimedTask> {
   constructor(
     protected requestService: RequestService,
     protected rdbService: RemoteDataBuildService,
-    protected dataBuildService: NormalizedObjectBuildService,
     protected store: Store<CoreState>,
     protected objectCache: ObjectCacheService,
     protected halService: HALEndpointService,
diff --git a/src/app/core/tasks/models/claimed-task-object.model.ts b/src/app/core/tasks/models/claimed-task-object.model.ts
index 2f427f586f46c5be11a33057efa2405cece1bf80..3ea78595f26aca6e370027cb30bee1f1f11d36ea 100644
--- a/src/app/core/tasks/models/claimed-task-object.model.ts
+++ b/src/app/core/tasks/models/claimed-task-object.model.ts
@@ -1,9 +1,14 @@
+import { inheritSerialization } from 'cerialize';
+import { inheritLinkAnnotations, typedObject } from '../../cache/builders/build-decorators';
+import { CLAIMED_TASK } from './claimed-task-object.resource-type';
 import { TaskObject } from './task-object.model';
-import { ResourceType } from '../../shared/resource-type';
 
 /**
  * A model class for a ClaimedTask.
  */
+@typedObject
+@inheritSerialization(TaskObject)
+@inheritLinkAnnotations(TaskObject)
 export class ClaimedTask extends TaskObject {
-  static type = new ResourceType('claimedtask');
+  static type = CLAIMED_TASK;
 }
diff --git a/src/app/core/tasks/models/claimed-task-object.resource-type.ts b/src/app/core/tasks/models/claimed-task-object.resource-type.ts
new file mode 100644
index 0000000000000000000000000000000000000000..9ad48fb2299b29f0de19f1ca7c1a7e7381e3c119
--- /dev/null
+++ b/src/app/core/tasks/models/claimed-task-object.resource-type.ts
@@ -0,0 +1,9 @@
+import { ResourceType } from '../../shared/resource-type';
+
+/**
+ * The resource type for ClaimedTask
+ *
+ * Needs to be in a separate file to prevent circular
+ * dependencies in webpack.
+ */
+export const CLAIMED_TASK = new ResourceType('claimedtask');
diff --git a/src/app/core/tasks/models/normalized-claimed-task-object.model.ts b/src/app/core/tasks/models/normalized-claimed-task-object.model.ts
deleted file mode 100644
index d43a277f028ba7eb0c5a0e497aba10eb74bca7b8..0000000000000000000000000000000000000000
--- a/src/app/core/tasks/models/normalized-claimed-task-object.model.ts
+++ /dev/null
@@ -1,54 +0,0 @@
-import { NormalizedTaskObject } from './normalized-task-object.model';
-import { mapsTo, relationship } from '../../cache/builders/build-decorators';
-import { autoserialize, inheritSerialization } from 'cerialize';
-import { ClaimedTask } from './claimed-task-object.model';
-import { EPerson } from '../../eperson/models/eperson.model';
-import { Group } from '../../eperson/models/group.model';
-import { WorkflowItem } from '../../submission/models/workflowitem.model';
-
-/**
- * A normalized model class for a ClaimedTask.
- */
-@mapsTo(ClaimedTask)
-@inheritSerialization(NormalizedTaskObject)
-export class NormalizedClaimedTask extends NormalizedTaskObject<ClaimedTask> {
-  /**
-   * The task identifier
-   */
-  @autoserialize
-  id: string;
-
-  /**
-   * The workflow step
-   */
-  @autoserialize
-  step: string;
-
-  /**
-   * The task action type
-   */
-  @autoserialize
-  action: string;
-
-  /**
-   * The eperson object for this task
-   */
-  @autoserialize
-  @relationship(EPerson, false)
-  eperson: string;
-
-  /**
-   * The group object for this task
-   */
-  @autoserialize
-  @relationship(Group, false)
-  group: string;
-
-  /**
-   * The workflowitem object whom this task is related
-   */
-  @autoserialize
-  @relationship(WorkflowItem, false)
-  workflowitem: string;
-
-}
diff --git a/src/app/core/tasks/models/normalized-pool-task-object.model.ts b/src/app/core/tasks/models/normalized-pool-task-object.model.ts
deleted file mode 100644
index bfc782f182f2d7728e1c6213082dccb308d933a7..0000000000000000000000000000000000000000
--- a/src/app/core/tasks/models/normalized-pool-task-object.model.ts
+++ /dev/null
@@ -1,45 +0,0 @@
-import { NormalizedTaskObject } from './normalized-task-object.model';
-import { PoolTask } from './pool-task-object.model';
-import { autoserialize, inheritSerialization } from 'cerialize';
-import { mapsTo, relationship } from '../../cache/builders/build-decorators';
-import { Group } from '../../eperson/models/group.model';
-import { WorkflowItem } from '../../submission/models/workflowitem.model';
-
-/**
- * A normalized model class for a PoolTask.
- */
-@mapsTo(PoolTask)
-@inheritSerialization(NormalizedTaskObject)
-export class NormalizedPoolTask extends NormalizedTaskObject<PoolTask> {
-  /**
-   * The task identifier
-   */
-  @autoserialize
-  id: string;
-
-  /**
-   * The workflow step
-   */
-  @autoserialize
-  step: string;
-
-  /**
-   * The task action type
-   */
-  @autoserialize
-  action: string;
-
-  /**
-   * The group object for this task
-   */
-  @autoserialize
-  @relationship(Group, false)
-  group: string;
-
-  /**
-   * The workflowitem object whom this task is related
-   */
-  @autoserialize
-  @relationship(WorkflowItem, false)
-  workflowitem: string;
-}
diff --git a/src/app/core/tasks/models/normalized-task-object.model.ts b/src/app/core/tasks/models/normalized-task-object.model.ts
deleted file mode 100644
index 2c96b9539300df3f3295c291a162ae264e699249..0000000000000000000000000000000000000000
--- a/src/app/core/tasks/models/normalized-task-object.model.ts
+++ /dev/null
@@ -1,55 +0,0 @@
-import { autoserialize, inheritSerialization } from 'cerialize';
-import { mapsTo, relationship } from '../../cache/builders/build-decorators';
-import { NormalizedDSpaceObject } from '../../cache/models/normalized-dspace-object.model';
-import { TaskObject } from './task-object.model';
-import { DSpaceObject } from '../../shared/dspace-object.model';
-import { Group } from '../../eperson/models/group.model';
-import { EPerson } from '../../eperson/models/eperson.model';
-import { WorkflowItem } from '../../submission/models/workflowitem.model';
-
-/**
- * An abstract normalized model class for a TaskObject.
- */
-@mapsTo(TaskObject)
-@inheritSerialization(NormalizedDSpaceObject)
-export class NormalizedTaskObject<T extends DSpaceObject> extends NormalizedDSpaceObject<T> {
-
-  /**
-   * The task identifier
-   */
-  @autoserialize
-  id: string;
-
-  /**
-   * The workflow step
-   */
-  @autoserialize
-  step: string;
-
-  /**
-   * The task action type
-   */
-  @autoserialize
-  action: string;
-
-  /**
-   * The eperson object for this task
-   */
-  @autoserialize
-  @relationship(EPerson, false)
-  eperson: string;
-
-  /**
-   * The group object for this task
-   */
-  @autoserialize
-  @relationship(Group, false)
-  group: string;
-
-  /**
-   * The workflowitem object whom this task is related
-   */
-  @autoserialize
-  @relationship(WorkflowItem, false)
-  workflowitem: string;
-}
diff --git a/src/app/core/tasks/models/pool-task-object.model.ts b/src/app/core/tasks/models/pool-task-object.model.ts
index 876b62373df32c413fc2e6b250b1ff91c40c697e..501849e8ec749a1c5d401ec67f0a20ff403dc21e 100644
--- a/src/app/core/tasks/models/pool-task-object.model.ts
+++ b/src/app/core/tasks/models/pool-task-object.model.ts
@@ -1,9 +1,14 @@
+import { inheritSerialization } from 'cerialize';
+import { inheritLinkAnnotations, typedObject } from '../../cache/builders/build-decorators';
+import { POOL_TASK } from './pool-task-object.resource-type';
 import { TaskObject } from './task-object.model';
-import { ResourceType } from '../../shared/resource-type';
 
 /**
  * A model class for a PoolTask.
  */
+@typedObject
+@inheritSerialization(TaskObject)
+@inheritLinkAnnotations(TaskObject)
 export class PoolTask extends TaskObject {
-  static type = new ResourceType('pooltask');
+  static type = POOL_TASK;
 }
diff --git a/src/app/core/tasks/models/pool-task-object.resource-type.ts b/src/app/core/tasks/models/pool-task-object.resource-type.ts
new file mode 100644
index 0000000000000000000000000000000000000000..cab8ec16078ca9236f8763142cfafd5bfe458d11
--- /dev/null
+++ b/src/app/core/tasks/models/pool-task-object.resource-type.ts
@@ -0,0 +1,9 @@
+import { ResourceType } from '../../shared/resource-type';
+
+/**
+ * The resource type for PoolTask
+ *
+ * Needs to be in a separate file to prevent circular
+ * dependencies in webpack.
+ */
+export const POOL_TASK = new ResourceType('pooltask');
diff --git a/src/app/core/tasks/models/task-object.model.ts b/src/app/core/tasks/models/task-object.model.ts
index 1f37548b0484b72b43d7e47472fe44365559bbe3..b56cec3a7ebcbc6df166c211412cfb34d43b6f2b 100644
--- a/src/app/core/tasks/models/task-object.model.ts
+++ b/src/app/core/tasks/models/task-object.model.ts
@@ -1,46 +1,75 @@
+import { autoserialize, deserialize, inheritSerialization } from 'cerialize';
 import { Observable } from 'rxjs';
+import { link, typedObject } from '../../cache/builders/build-decorators';
 
 import { CacheableObject } from '../../cache/object-cache.reducer';
-import { DSpaceObject } from '../../shared/dspace-object.model';
 import { RemoteData } from '../../data/remote-data';
-import { WorkflowItem } from '../../submission/models/workflowitem.model';
-import { ResourceType } from '../../shared/resource-type';
 import { EPerson } from '../../eperson/models/eperson.model';
+import { EPERSON } from '../../eperson/models/eperson.resource-type';
 import { Group } from '../../eperson/models/group.model';
+import { GROUP } from '../../eperson/models/group.resource-type';
+import { DSpaceObject } from '../../shared/dspace-object.model';
+import { HALLink } from '../../shared/hal-link.model';
+import { WorkflowItem } from '../../submission/models/workflowitem.model';
+import { TASK_OBJECT } from './task-object.resource-type';
+import { WORKFLOWITEM } from '../../eperson/models/workflowitem.resource-type';
 
 /**
  * An abstract model class for a TaskObject.
  */
+@typedObject
+@inheritSerialization(DSpaceObject)
 export class TaskObject extends DSpaceObject implements CacheableObject {
-  static type = new ResourceType('taskobject');
+  static type = TASK_OBJECT;
 
   /**
    * The task identifier
    */
+  @autoserialize
   id: string;
 
   /**
    * The workflow step
    */
+  @autoserialize
   step: string;
 
   /**
    * The task action type
    */
+  @autoserialize
   action: string;
 
   /**
-   * The group of this task
+   * The {@link HALLink}s for this TaskObject
    */
-  eperson: Observable<RemoteData<EPerson>>;
+  @deserialize
+  _links: {
+    self: HALLink;
+    owner: HALLink;
+    group: HALLink;
+    workflowitem: HALLink;
+  };
 
   /**
-   * The group of this task
+   * The EPerson for this task
+   * Will be undefined unless the eperson {@link HALLink} has been resolved.
    */
-  group: Observable<RemoteData<Group>>;
+  @link(EPERSON, false, 'owner')
+  eperson?: Observable<RemoteData<EPerson>>;
 
   /**
-   * The workflowitem object whom this task is related
+   * The Group for this task
+   * Will be undefined unless the group {@link HALLink} has been resolved.
    */
-  workflowitem: Observable<RemoteData<WorkflowItem>> | WorkflowItem;
+  @link(GROUP)
+  group?: Observable<RemoteData<Group>>;
+
+  /**
+   * The WorkflowItem for this task
+   * Will be undefined unless the workflowitem {@link HALLink} has been resolved.
+   */
+  @link(WORKFLOWITEM)
+  workflowitem?: Observable<RemoteData<WorkflowItem>> | WorkflowItem;
+
 }
diff --git a/src/app/core/tasks/models/task-object.resource-type.ts b/src/app/core/tasks/models/task-object.resource-type.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d25e27ee94936073e19c0218a865e7567821ccaa
--- /dev/null
+++ b/src/app/core/tasks/models/task-object.resource-type.ts
@@ -0,0 +1,9 @@
+import { ResourceType } from '../../shared/resource-type';
+
+/**
+ * The resource type for TaskObject
+ *
+ * Needs to be in a separate file to prevent circular
+ * dependencies in webpack.
+ */
+export const TASK_OBJECT = new ResourceType('taskobject');
diff --git a/src/app/core/tasks/pool-task-data.service.spec.ts b/src/app/core/tasks/pool-task-data.service.spec.ts
index 7f40c6e89c17be4d3b596db4cda75962ca965743..70ae4c7a91365039464086cd3e8b54fae47e4280 100644
--- a/src/app/core/tasks/pool-task-data.service.spec.ts
+++ b/src/app/core/tasks/pool-task-data.service.spec.ts
@@ -6,7 +6,6 @@ import { getMockRequestService } from '../../shared/mocks/mock-request.service';
 import { HALEndpointServiceStub } from '../../shared/testing/hal-endpoint-service-stub';
 import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
 import { NotificationsService } from '../../shared/notifications/notifications.service';
-import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service';
 import { CoreState } from '../core.reducers';
 import { PoolTaskDataService } from './pool-task-data.service';
 import { HttpOptions } from '../dspace-rest-v2/dspace-rest-v2.service';
@@ -22,9 +21,6 @@ describe('PoolTaskDataService', () => {
   const notificationsService = {} as NotificationsService;
   const http = {} as HttpClient;
   const comparator = {} as any;
-  const dataBuildService = {
-    normalize: (object) => object
-  } as NormalizedObjectBuildService;
   const objectCache = {
     addPatch: () => {
       /* empty */
@@ -39,7 +35,6 @@ describe('PoolTaskDataService', () => {
     return new PoolTaskDataService(
       requestService,
       rdbService,
-      dataBuildService,
       store,
       objectCache,
       halService,
diff --git a/src/app/core/tasks/pool-task-data.service.ts b/src/app/core/tasks/pool-task-data.service.ts
index 0e7704336dd6577bfc6fd66144334c695362bdcb..f08274b5f17dcf507eb8128d9df975f8c70992b8 100644
--- a/src/app/core/tasks/pool-task-data.service.ts
+++ b/src/app/core/tasks/pool-task-data.service.ts
@@ -1,25 +1,26 @@
-import { Injectable } from '@angular/core';
 import { HttpClient } from '@angular/common/http';
-
-import { Observable } from 'rxjs';
+import { Injectable } from '@angular/core';
 import { Store } from '@ngrx/store';
 
+import { Observable } from 'rxjs';
+import { NotificationsService } from '../../shared/notifications/notifications.service';
+import { dataService } from '../cache/builders/build-decorators';
 import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
+import { ObjectCacheService } from '../cache/object-cache.service';
 import { CoreState } from '../core.reducers';
+import { DSOChangeAnalyzer } from '../data/dso-change-analyzer.service';
 import { RequestService } from '../data/request.service';
-import { PoolTask } from './models/pool-task-object.model';
-import { TasksService } from './tasks.service';
 import { HALEndpointService } from '../shared/hal-endpoint.service';
-import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service';
-import { ObjectCacheService } from '../cache/object-cache.service';
-import { NotificationsService } from '../../shared/notifications/notifications.service';
-import { DSOChangeAnalyzer } from '../data/dso-change-analyzer.service';
+import { PoolTask } from './models/pool-task-object.model';
+import { POOL_TASK } from './models/pool-task-object.resource-type';
 import { ProcessTaskResponse } from './models/process-task-response';
+import { TasksService } from './tasks.service';
 
 /**
  * The service handling all REST requests for PoolTask
  */
 @Injectable()
+@dataService(POOL_TASK)
 export class PoolTaskDataService extends TasksService<PoolTask> {
 
   /**
@@ -34,7 +35,7 @@ export class PoolTaskDataService extends TasksService<PoolTask> {
    *
    * @param {RequestService} requestService
    * @param {RemoteDataBuildService} rdbService
-   * @param {NormalizedObjectBuildService} dataBuildService
+   * @param {NormalizedObjectBuildService} linkService
    * @param {Store<CoreState>} store
    * @param {ObjectCacheService} objectCache
    * @param {HALEndpointService} halService
@@ -45,7 +46,6 @@ export class PoolTaskDataService extends TasksService<PoolTask> {
   constructor(
     protected requestService: RequestService,
     protected rdbService: RemoteDataBuildService,
-    protected dataBuildService: NormalizedObjectBuildService,
     protected store: Store<CoreState>,
     protected objectCache: ObjectCacheService,
     protected halService: HALEndpointService,
diff --git a/src/app/core/tasks/tasks.service.spec.ts b/src/app/core/tasks/tasks.service.spec.ts
index 3ca9b8ea8f428ba6b0b7b2375040ef45e9ae8b1a..782a950b2d07122ce7b85d4734b9c9a1461bc108 100644
--- a/src/app/core/tasks/tasks.service.spec.ts
+++ b/src/app/core/tasks/tasks.service.spec.ts
@@ -9,7 +9,6 @@ import { HALEndpointService } from '../shared/hal-endpoint.service';
 import { HALEndpointServiceStub } from '../../shared/testing/hal-endpoint-service-stub';
 import { TaskObject } from './models/task-object.model';
 import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
-import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service';
 import { Store } from '@ngrx/store';
 import { CoreState } from '../core.reducers';
 import { ObjectCacheService } from '../cache/object-cache.service';
@@ -18,7 +17,6 @@ import { HttpClient, HttpHeaders } from '@angular/common/http';
 import { DSOChangeAnalyzer } from '../data/dso-change-analyzer.service';
 import { ChangeAnalyzer } from '../data/change-analyzer';
 import { compare, Operation } from 'fast-json-patch';
-import { NormalizedTaskObject } from './models/normalized-task-object.model';
 import { HttpOptions } from '../dspace-rest-v2/dspace-rest-v2.service';
 
 const LINK_NAME = 'test';
@@ -33,7 +31,6 @@ class TestService extends TasksService<TestTask> {
   constructor(
     protected requestService: RequestService,
     protected rdbService: RemoteDataBuildService,
-    protected dataBuildService: NormalizedObjectBuildService,
     protected store: Store<CoreState>,
     protected objectCache: ObjectCacheService,
     protected halService: HALEndpointService,
@@ -44,11 +41,8 @@ class TestService extends TasksService<TestTask> {
   }
 }
 
-class NormalizedTestTaskObject extends NormalizedTaskObject<TestTask> {
-}
-
-class DummyChangeAnalyzer implements ChangeAnalyzer<NormalizedTestTaskObject> {
-  diff(object1: NormalizedTestTaskObject, object2: NormalizedTestTaskObject): Operation[] {
+class DummyChangeAnalyzer implements ChangeAnalyzer<TestTask> {
+  diff(object1: TestTask, object2: TestTask): Operation[] {
     return compare((object1 as any).metadata, (object2 as any).metadata);
   }
 
@@ -66,9 +60,6 @@ describe('TasksService', () => {
   const notificationsService = {} as NotificationsService;
   const http = {} as HttpClient;
   const comparator = new DummyChangeAnalyzer() as any;
-  const dataBuildService = {
-    normalize: (object) => object
-  } as NormalizedObjectBuildService;
   const objectCache = {
     addPatch: () => {
       /* empty */
@@ -83,7 +74,6 @@ describe('TasksService', () => {
     return new TestService(
       requestService,
       rdbService,
-      dataBuildService,
       store,
       objectCache,
       halService,
diff --git a/src/app/core/tasks/tasks.service.ts b/src/app/core/tasks/tasks.service.ts
index cf23bfd74b88c32ff4515e063e1cb9fc5185a3ce..0eae88e96c1e310521ec9f57614f876b308e7ab7 100644
--- a/src/app/core/tasks/tasks.service.ts
+++ b/src/app/core/tasks/tasks.service.ts
@@ -18,10 +18,6 @@ import { CacheableObject } from '../cache/object-cache.reducer';
  */
 export abstract class TasksService<T extends CacheableObject> extends DataService<T> {
 
-  public getBrowseEndpoint(options: FindListOptions): Observable<string> {
-    return this.halService.getEndpoint(this.linkPath);
-  }
-
   /**
    * Fetch a RestRequest
    *
diff --git a/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-issue/journal-issue-search-result-grid-element.component.html b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-issue/journal-issue-search-result-grid-element.component.html
index 18ff77bf2397946e8f13b4885ef6ea07f6cbbe09..af339109c6d0a3cadefe5ab9e359606e3edfbe94 100644
--- a/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-issue/journal-issue-search-result-grid-element.component.html
+++ b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-issue/journal-issue-search-result-grid-element.component.html
@@ -2,13 +2,13 @@
     <div class="card" [@focusShadow]="(isCollapsed$ | async)?'blur':'focus'">
         <a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer" [routerLink]="['/items/' + dso.id]" class="card-img-top full-width">
             <div>
-                <ds-grid-thumbnail [thumbnail]="dso.getThumbnail() | async">
+                <ds-grid-thumbnail [thumbnail]="getThumbnail() | async">
                 </ds-grid-thumbnail>
             </div>
         </a>
         <span *ngIf="linkType == linkTypes.None" class="card-img-top full-width">
             <div>
-                <ds-grid-thumbnail [thumbnail]="dso.getThumbnail() | async">
+                <ds-grid-thumbnail [thumbnail]="getThumbnail() | async">
                 </ds-grid-thumbnail>
             </div>
         </span>
diff --git a/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-volume/journal-volume-search-result-grid-element.component.html b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-volume/journal-volume-search-result-grid-element.component.html
index 07e50eb6fbab18c6d040f6aba943ef939d89fab4..2c7f24662a347fdd2611dace17883775a2792fdd 100644
--- a/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-volume/journal-volume-search-result-grid-element.component.html
+++ b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-volume/journal-volume-search-result-grid-element.component.html
@@ -2,13 +2,13 @@
         <div class="card" [@focusShadow]="(isCollapsed$ | async)?'blur':'focus'">
             <a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer" [routerLink]="['/items/' + dso.id]" class="card-img-top full-width">
                 <div>
-                    <ds-grid-thumbnail [thumbnail]="dso.getThumbnail() | async">
+                    <ds-grid-thumbnail [thumbnail]="getThumbnail() | async">
                     </ds-grid-thumbnail>
                 </div>
             </a>
             <span *ngIf="linkType == linkTypes.None" class="card-img-top full-width">
                 <div>
-                    <ds-grid-thumbnail [thumbnail]="dso.getThumbnail() | async">
+                    <ds-grid-thumbnail [thumbnail]="getThumbnail() | async">
                     </ds-grid-thumbnail>
                 </div>
             </span>
diff --git a/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal/journal-search-result-grid-element.component.html b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal/journal-search-result-grid-element.component.html
index 394e5241e153092bd7bb2031fd8bf5122ce78c44..d6b9c4a62e0f01bab2ec5e3a26027f541c71fbbe 100644
--- a/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal/journal-search-result-grid-element.component.html
+++ b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal/journal-search-result-grid-element.component.html
@@ -2,13 +2,13 @@
     <div class="card" [@focusShadow]="(isCollapsed$ | async)?'blur':'focus'">
         <a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer" [routerLink]="['/items/' + dso.id]" class="card-img-top full-width">
             <div>
-                <ds-grid-thumbnail [thumbnail]="dso.getThumbnail() | async">
+                <ds-grid-thumbnail [thumbnail]="getThumbnail() | async">
                 </ds-grid-thumbnail>
             </div>
         </a>
         <span *ngIf="linkType == linkTypes.None" class="card-img-top full-width">
             <div>
-                <ds-grid-thumbnail [thumbnail]="dso.getThumbnail() | async">
+                <ds-grid-thumbnail [thumbnail]="getThumbnail() | async">
                 </ds-grid-thumbnail>
             </div>
         </span>
diff --git a/src/app/entity-groups/journal-entities/item-pages/journal-issue/journal-issue.component.html b/src/app/entity-groups/journal-entities/item-pages/journal-issue/journal-issue.component.html
index 87312f87846e4ab9649d0df24f9492bde14396c8..cdfa6293c406fc1aa04c49f1258716a429c5a4a1 100644
--- a/src/app/entity-groups/journal-entities/item-pages/journal-issue/journal-issue.component.html
+++ b/src/app/entity-groups/journal-entities/item-pages/journal-issue/journal-issue.component.html
@@ -4,7 +4,7 @@
 <div class="row">
   <div class="col-xs-12 col-md-4">
     <ds-metadata-field-wrapper>
-      <ds-thumbnail [thumbnail]="object.getThumbnail() | async"></ds-thumbnail>
+      <ds-thumbnail [thumbnail]="getThumbnail() | async"></ds-thumbnail>
     </ds-metadata-field-wrapper>
     <ds-generic-item-page-field [item]="object"
       [fields]="['publicationvolume.volumeNumber']"
diff --git a/src/app/entity-groups/journal-entities/item-pages/journal-volume/journal-volume.component.html b/src/app/entity-groups/journal-entities/item-pages/journal-volume/journal-volume.component.html
index e77b24a98bfda748b5af1312d8c93d21d333add3..5df1997f0bfa52fe595114f50a5a4dced0fc35f1 100644
--- a/src/app/entity-groups/journal-entities/item-pages/journal-volume/journal-volume.component.html
+++ b/src/app/entity-groups/journal-entities/item-pages/journal-volume/journal-volume.component.html
@@ -4,7 +4,7 @@
 <div class="row">
   <div class="col-xs-12 col-md-4">
     <ds-metadata-field-wrapper>
-      <ds-thumbnail [thumbnail]="object.getThumbnail() | async"></ds-thumbnail>
+      <ds-thumbnail [thumbnail]="getThumbnail() | async"></ds-thumbnail>
     </ds-metadata-field-wrapper>
     <ds-generic-item-page-field [item]="object"
       [fields]="['publicationvolume.volumeNumber']"
diff --git a/src/app/entity-groups/journal-entities/item-pages/journal/journal.component.html b/src/app/entity-groups/journal-entities/item-pages/journal/journal.component.html
index e86ab35e0ee62235de5199e3790518da3b936119..d8d32df04a597e2c05b538e2cebde4dcdd3a3554 100644
--- a/src/app/entity-groups/journal-entities/item-pages/journal/journal.component.html
+++ b/src/app/entity-groups/journal-entities/item-pages/journal/journal.component.html
@@ -4,7 +4,7 @@
 <div class="row">
   <div class="col-xs-12 col-md-4">
     <ds-metadata-field-wrapper>
-      <ds-thumbnail [thumbnail]="object.getThumbnail() | async"></ds-thumbnail>
+      <ds-thumbnail [thumbnail]="getThumbnail() | async"></ds-thumbnail>
     </ds-metadata-field-wrapper>
     <ds-generic-item-page-field class="item-page-fields" [item]="object"
       [fields]="['creativeworkseries.issn']"
diff --git a/src/app/entity-groups/journal-entities/item-pages/journal/journal.component.spec.ts b/src/app/entity-groups/journal-entities/item-pages/journal/journal.component.spec.ts
index 39d7d9ccce90d36b05e9e2bdcfeb9af492154f51..3cd2ac1cce27558bea4be196f681a88e083e3e49 100644
--- a/src/app/entity-groups/journal-entities/item-pages/journal/journal.component.spec.ts
+++ b/src/app/entity-groups/journal-entities/item-pages/journal/journal.component.spec.ts
@@ -1,19 +1,33 @@
+import { HttpClient } from '@angular/common/http';
 import { ChangeDetectionStrategy, DebugElement, NO_ERRORS_SCHEMA } from '@angular/core';
 import { async, ComponentFixture, TestBed } from '@angular/core/testing';
-import { TruncatableService } from '../../../../shared/truncatable/truncatable.service';
-import { TruncatePipe } from '../../../../shared/utils/truncate.pipe';
-import { ItemDataService } from '../../../../core/data/item-data.service';
-import { Item } from '../../../../core/shared/item.model';
 import { By } from '@angular/platform-browser';
+import { Store } from '@ngrx/store';
 import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
-import { MockTranslateLoader } from '../../../../shared/mocks/mock-translate-loader';
+import { Observable } from 'rxjs/internal/Observable';
+import { GenericItemPageFieldComponent } from '../../../../+item-page/simple/field-components/specific-field/generic/generic-item-page-field.component';
+import { RemoteDataBuildService } from '../../../../core/cache/builders/remote-data-build.service';
+import { ObjectCacheService } from '../../../../core/cache/object-cache.service';
+import { BitstreamDataService } from '../../../../core/data/bitstream-data.service';
+import { CommunityDataService } from '../../../../core/data/community-data.service';
+import { DefaultChangeAnalyzer } from '../../../../core/data/default-change-analyzer.service';
+import { DSOChangeAnalyzer } from '../../../../core/data/dso-change-analyzer.service';
+import { ItemDataService } from '../../../../core/data/item-data.service';
 import { PaginatedList } from '../../../../core/data/paginated-list';
+import { RelationshipService } from '../../../../core/data/relationship.service';
+import { RemoteData } from '../../../../core/data/remote-data';
+import { Bitstream } from '../../../../core/shared/bitstream.model';
+import { HALEndpointService } from '../../../../core/shared/hal-endpoint.service';
+import { Item } from '../../../../core/shared/item.model';
 import { PageInfo } from '../../../../core/shared/page-info.model';
+import { UUIDService } from '../../../../core/shared/uuid.service';
 import { isNotEmpty } from '../../../../shared/empty.util';
-import { JournalComponent } from './journal.component';
-import { GenericItemPageFieldComponent } from '../../../../+item-page/simple/field-components/specific-field/generic/generic-item-page-field.component';
+import { MockTranslateLoader } from '../../../../shared/mocks/mock-translate-loader';
+import { NotificationsService } from '../../../../shared/notifications/notifications.service';
 import { createSuccessfulRemoteDataObject$ } from '../../../../shared/testing/utils';
-import { RelationshipService } from '../../../../core/data/relationship.service';
+import { TruncatableService } from '../../../../shared/truncatable/truncatable.service';
+import { TruncatePipe } from '../../../../shared/utils/truncate.pipe';
+import { JournalComponent } from './journal.component';
 
 let comp: JournalComponent;
 let fixture: ComponentFixture<JournalComponent>;
@@ -43,6 +57,11 @@ const mockItem: Item = Object.assign(new Item(), {
 });
 
 describe('JournalComponent', () => {
+  const mockBitstreamDataService = {
+    getThumbnailFor(item: Item): Observable<RemoteData<Bitstream>> {
+      return createSuccessfulRemoteDataObject$(new Bitstream());
+    }
+  };
   beforeEach(async(() => {
     TestBed.configureTestingModule({
       imports: [TranslateModule.forRoot({
@@ -53,14 +72,25 @@ describe('JournalComponent', () => {
       })],
       declarations: [JournalComponent, GenericItemPageFieldComponent, TruncatePipe],
       providers: [
-        {provide: ItemDataService, useValue: {}},
-        {provide: TruncatableService, useValue: {}},
-        {provide: RelationshipService, useValue: {}}
+        { provide: ItemDataService, useValue: {} },
+        { provide: TruncatableService, useValue: {} },
+        { provide: RelationshipService, useValue: {} },
+        { provide: ObjectCacheService, useValue: {} },
+        { provide: UUIDService, useValue: {} },
+        { provide: Store, useValue: {} },
+        { provide: RemoteDataBuildService, useValue: {} },
+        { provide: CommunityDataService, useValue: {} },
+        { provide: HALEndpointService, useValue: {} },
+        { provide: HttpClient, useValue: {} },
+        { provide: DSOChangeAnalyzer, useValue: {} },
+        { provide: NotificationsService, useValue: {} },
+        { provide: DefaultChangeAnalyzer, useValue: {} },
+        { provide: BitstreamDataService, useValue: mockBitstreamDataService },
       ],
 
       schemas: [NO_ERRORS_SCHEMA]
     }).overrideComponent(JournalComponent, {
-      set: {changeDetection: ChangeDetectionStrategy.Default}
+      set: { changeDetection: ChangeDetectionStrategy.Default }
     }).compileComponents();
   }));
 
diff --git a/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/org-unit/org-unit-search-result-grid-element.component.html b/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/org-unit/org-unit-search-result-grid-element.component.html
index 5c42be2b246bb7778b3398bd42640c8a82e46a43..0fb1ec02f865dcf9d844cb488fd7aca54c38613f 100644
--- a/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/org-unit/org-unit-search-result-grid-element.component.html
+++ b/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/org-unit/org-unit-search-result-grid-element.component.html
@@ -2,13 +2,13 @@
     <div class="card" [@focusShadow]="(isCollapsed$ | async)?'blur':'focus'">
         <a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer" [routerLink]="['/items/' + dso.id]" class="card-img-top full-width">
             <div>
-                <ds-grid-thumbnail [thumbnail]="dso.getThumbnail() | async">
+                <ds-grid-thumbnail [thumbnail]="getThumbnail() | async">
                 </ds-grid-thumbnail>
             </div>
         </a>
         <span *ngIf="linkType == linkTypes.None" class="card-img-top full-width">
             <div>
-                <ds-grid-thumbnail [thumbnail]="dso.getThumbnail() | async">
+                <ds-grid-thumbnail [thumbnail]="getThumbnail() | async">
                 </ds-grid-thumbnail>
             </div>
         </span>
diff --git a/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/person/person-search-result-grid-element.component.html b/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/person/person-search-result-grid-element.component.html
index b7eed7c8b406a00802b4206451f78552cfe51d02..321ecd4a47c78a3b446b78ddf1e7c230d3bc5dd9 100644
--- a/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/person/person-search-result-grid-element.component.html
+++ b/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/person/person-search-result-grid-element.component.html
@@ -3,13 +3,13 @@
         <a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer" [routerLink]="['/items/' + dso.id]"
            class="card-img-top full-width">
             <div>
-                <ds-grid-thumbnail [thumbnail]="dso.getThumbnail() | async">
+                <ds-grid-thumbnail [thumbnail]="getThumbnail() | async">
                 </ds-grid-thumbnail>
             </div>
         </a>
         <span *ngIf="linkType == linkTypes.None" class="card-img-top full-width">
             <div>
-                <ds-grid-thumbnail [thumbnail]="dso.getThumbnail() | async">
+                <ds-grid-thumbnail [thumbnail]="getThumbnail() | async">
                 </ds-grid-thumbnail>
             </div>
         </span>
diff --git a/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/project/project-search-result-grid-element.component.html b/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/project/project-search-result-grid-element.component.html
index f3a0dea81fb772d81f001aeea02043354b48b21f..c39de6bc2a38f742453b46ebf5557e606c5c0ae1 100644
--- a/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/project/project-search-result-grid-element.component.html
+++ b/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/project/project-search-result-grid-element.component.html
@@ -2,13 +2,13 @@
     <div class="card" [@focusShadow]="(isCollapsed$ | async)?'blur':'focus'">
         <a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer" [routerLink]="['/items/' + dso.id]" class="card-img-top full-width">
             <div>
-                <ds-grid-thumbnail [thumbnail]="dso.getThumbnail() | async">
+                <ds-grid-thumbnail [thumbnail]="getThumbnail() | async">
                 </ds-grid-thumbnail>
             </div>
         </a>
         <span *ngIf="linkType == linkTypes.None" class="card-img-top full-width">
       <div>
-        <ds-grid-thumbnail [thumbnail]="dso.getThumbnail() | async">
+        <ds-grid-thumbnail [thumbnail]="getThumbnail() | async">
         </ds-grid-thumbnail>
       </div>
     </span>
diff --git a/src/app/entity-groups/research-entities/item-pages/org-unit/org-unit.component.html b/src/app/entity-groups/research-entities/item-pages/org-unit/org-unit.component.html
index 1b23d567f529ba3c5bbe756edc6d6acfd5bcb26d..784000b44685570c1aa87776daa58df135b66a2e 100644
--- a/src/app/entity-groups/research-entities/item-pages/org-unit/org-unit.component.html
+++ b/src/app/entity-groups/research-entities/item-pages/org-unit/org-unit.component.html
@@ -4,7 +4,7 @@
 <div class="row">
   <div class="col-xs-12 col-md-4">
     <ds-metadata-field-wrapper>
-      <ds-thumbnail [thumbnail]="object.getThumbnail() | async" [defaultImage]="'assets/images/orgunit-placeholder.svg'"></ds-thumbnail>
+      <ds-thumbnail [thumbnail]="getThumbnail() | async" [defaultImage]="'assets/images/orgunit-placeholder.svg'"></ds-thumbnail>
     </ds-metadata-field-wrapper>
     <ds-generic-item-page-field [item]="object"
       [fields]="['organization.foundingDate']"
diff --git a/src/app/entity-groups/research-entities/item-pages/person/person.component.html b/src/app/entity-groups/research-entities/item-pages/person/person.component.html
index 97a3cf416ef252ac26d86c5492b4adc9ef93afad..af71d5a1c6258dfc56604d0da8d288294e330bbd 100644
--- a/src/app/entity-groups/research-entities/item-pages/person/person.component.html
+++ b/src/app/entity-groups/research-entities/item-pages/person/person.component.html
@@ -4,7 +4,7 @@
 <div class="row">
   <div class="col-xs-12 col-md-4">
     <ds-metadata-field-wrapper>
-      <ds-thumbnail [thumbnail]="this.object.getThumbnail() | async" [defaultImage]="'assets/images/person-placeholder.svg'"></ds-thumbnail>
+      <ds-thumbnail [thumbnail]="getThumbnail() | async" [defaultImage]="'assets/images/person-placeholder.svg'"></ds-thumbnail>
     </ds-metadata-field-wrapper>
     <ds-generic-item-page-field [item]="object"
       [fields]="['person.email']"
diff --git a/src/app/entity-groups/research-entities/item-pages/person/person.component.spec.ts b/src/app/entity-groups/research-entities/item-pages/person/person.component.spec.ts
index 302b6f1f605f9f2d57338aacf9b24aa6cea4a86e..8954d27de862d85e4cf69b874202e60e959c7116 100644
--- a/src/app/entity-groups/research-entities/item-pages/person/person.component.spec.ts
+++ b/src/app/entity-groups/research-entities/item-pages/person/person.component.spec.ts
@@ -1,14 +1,12 @@
-import { Item } from '../../../../core/shared/item.model';
-import { RemoteData } from '../../../../core/data/remote-data';
-import { PaginatedList } from '../../../../core/data/paginated-list';
-import { PageInfo } from '../../../../core/shared/page-info.model';
-import { PersonComponent } from './person.component';
-import { of as observableOf } from 'rxjs';
 import {
   createRelationshipsObservable,
   getItemPageFieldsTest
 } from '../../../../+item-page/simple/item-types/shared/item.component.spec';
+import { PaginatedList } from '../../../../core/data/paginated-list';
+import { Item } from '../../../../core/shared/item.model';
+import { PageInfo } from '../../../../core/shared/page-info.model';
 import { createSuccessfulRemoteDataObject$ } from '../../../../shared/testing/utils';
+import { PersonComponent } from './person.component';
 
 const mockItem: Item = Object.assign(new Item(), {
   bundles: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
diff --git a/src/app/entity-groups/research-entities/item-pages/project/project.component.html b/src/app/entity-groups/research-entities/item-pages/project/project.component.html
index bb6ce21cd1f518c5a3b203db2a4e08083140b498..6c4a0bab01d040d5d86c75a2d82ac85e8a793e65 100644
--- a/src/app/entity-groups/research-entities/item-pages/project/project.component.html
+++ b/src/app/entity-groups/research-entities/item-pages/project/project.component.html
@@ -4,7 +4,7 @@
 <div class="row">
   <div class="col-xs-12 col-md-4">
     <ds-metadata-field-wrapper>
-      <ds-thumbnail [thumbnail]="object.getThumbnail() | async" [defaultImage]="'assets/images/project-placeholder.svg'"></ds-thumbnail>
+      <ds-thumbnail [thumbnail]="getThumbnail() | async" [defaultImage]="'assets/images/project-placeholder.svg'"></ds-thumbnail>
     </ds-metadata-field-wrapper>
     <!--<ds-generic-item-page-field [item]="object"-->
       <!--[fields]="['project.identifier.status']"-->
diff --git a/src/app/entity-groups/research-entities/item-pages/project/project.component.spec.ts b/src/app/entity-groups/research-entities/item-pages/project/project.component.spec.ts
index 6792000fd030e13ccc1fd39e0009ae3a51648436..72857654ce4f253d7c3f7029fbbc3b96025d8ce2 100644
--- a/src/app/entity-groups/research-entities/item-pages/project/project.component.spec.ts
+++ b/src/app/entity-groups/research-entities/item-pages/project/project.component.spec.ts
@@ -1,14 +1,12 @@
-import { Item } from '../../../../core/shared/item.model';
-import { RemoteData } from '../../../../core/data/remote-data';
-import { PaginatedList } from '../../../../core/data/paginated-list';
-import { PageInfo } from '../../../../core/shared/page-info.model';
-import { ProjectComponent } from './project.component';
-import { of as observableOf } from 'rxjs';
 import {
   createRelationshipsObservable,
   getItemPageFieldsTest
 } from '../../../../+item-page/simple/item-types/shared/item.component.spec';
+import { PaginatedList } from '../../../../core/data/paginated-list';
+import { Item } from '../../../../core/shared/item.model';
+import { PageInfo } from '../../../../core/shared/page-info.model';
 import { createSuccessfulRemoteDataObject$ } from '../../../../shared/testing/utils';
+import { ProjectComponent } from './project.component';
 
 const mockItem: Item = Object.assign(new Item(), {
   bundles: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
diff --git a/src/app/entity-groups/research-entities/metadata-representations/org-unit/org-unit-item-metadata-list-element.component.html b/src/app/entity-groups/research-entities/metadata-representations/org-unit/org-unit-item-metadata-list-element.component.html
index 09774137222f56ac71bcda674d5b7c41eee05bec..d8a4e744e4e44ca7c6dd49356665e49c67767ea3 100644
--- a/src/app/entity-groups/research-entities/metadata-representations/org-unit/org-unit-item-metadata-list-element.component.html
+++ b/src/app/entity-groups/research-entities/metadata-representations/org-unit/org-unit-item-metadata-list-element.component.html
@@ -9,5 +9,5 @@
 <ds-truncatable [id]="metadataRepresentation.id">
   <a [routerLink]="['/items/' + metadataRepresentation.id]"
      [innerHTML]="metadataRepresentation.getValue()"
-     [tooltip]="metadataRepresentation.allMetadata(['dc.description']).length > 0 ? descTemplate : null"></a>
+     [tooltip]="metadataRepresentation.allMetadata(['organization.legalName']).length > 0 ? descTemplate : null"></a>
 </ds-truncatable>
diff --git a/src/app/entity-groups/research-entities/metadata-representations/org-unit/org-unit-item-metadata-list-element.component.spec.ts b/src/app/entity-groups/research-entities/metadata-representations/org-unit/org-unit-item-metadata-list-element.component.spec.ts
index 7d27b605ece6a45512985597fa3c703f24d51d20..2d288217380a1252026aefc4955baa55b1f53ca7 100644
--- a/src/app/entity-groups/research-entities/metadata-representations/org-unit/org-unit-item-metadata-list-element.component.spec.ts
+++ b/src/app/entity-groups/research-entities/metadata-representations/org-unit/org-unit-item-metadata-list-element.component.spec.ts
@@ -27,12 +27,12 @@ describe('OrgUnitItemMetadataListElementComponent', () => {
     }).compileComponents();
   }));
 
-  beforeEach(async(() => {
+  beforeEach(() => {
     fixture = TestBed.createComponent(OrgUnitItemMetadataListElementComponent);
     comp = fixture.componentInstance;
     comp.metadataRepresentation = mockItemMetadataRepresentation;
     fixture.detectChanges();
-  }));
+  });
 
   it('should show the name of the organisation as a link', () => {
     const linkText = fixture.debugElement.query(By.css('a')).nativeElement.textContent;
diff --git a/src/app/entity-groups/research-entities/metadata-representations/person/person-item-metadata-list-element.component.spec.ts b/src/app/entity-groups/research-entities/metadata-representations/person/person-item-metadata-list-element.component.spec.ts
index 1081e458840dd2821a21afd04a2241aefbf3eb79..97087728f8d07ceae856e32a4e1d5b417fb446f3 100644
--- a/src/app/entity-groups/research-entities/metadata-representations/person/person-item-metadata-list-element.component.spec.ts
+++ b/src/app/entity-groups/research-entities/metadata-representations/person/person-item-metadata-list-element.component.spec.ts
@@ -29,12 +29,12 @@ describe('PersonItemMetadataListElementComponent', () => {
     }).compileComponents();
   }));
 
-  beforeEach(async(() => {
+  beforeEach(() => {
     fixture = TestBed.createComponent(PersonItemMetadataListElementComponent);
     comp = fixture.componentInstance;
     comp.metadataRepresentation = mockItemMetadataRepresentation;
     fixture.detectChanges();
-  }));
+  });
 
   it('should show the person\'s name as a link', () => {
     const linkText = fixture.debugElement.query(By.css('a')).nativeElement.textContent;
diff --git a/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-search-result-list-submission-element.component.html b/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-search-result-list-submission-element.component.html
index b0fa714371958c14248ecef0718e682608d5c8b6..93165c24cd6471ad9fcc551fe8dcb1378b34268c 100644
--- a/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-search-result-list-submission-element.component.html
+++ b/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-search-result-list-submission-element.component.html
@@ -1,6 +1,6 @@
 <div class="d-flex">
     <div class="person-thumbnail pr-2">
-        <ds-thumbnail [thumbnail]="dso.getThumbnail() | async" [defaultImage]="'assets/images/orgunit-placeholder.svg'"></ds-thumbnail>
+        <ds-thumbnail [thumbnail]="getThumbnail() | async" [defaultImage]="'assets/images/orgunit-placeholder.svg'"></ds-thumbnail>
     </div>
     <div class="flex-grow-1">
         <ds-org-unit-input-suggestions [suggestions]="allSuggestions" [(ngModel)]="selectedName" (clickSuggestion)="select($event)"
diff --git a/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-search-result-list-submission-element.component.spec.ts b/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-search-result-list-submission-element.component.spec.ts
index 2a77b64f43ffa49707e05cb0ca20dfe249cb596a..e1520d9eddc732aaf16a95889aac6edc96db6f18 100644
--- a/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-search-result-list-submission-element.component.spec.ts
+++ b/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-search-result-list-submission-element.component.spec.ts
@@ -1,21 +1,33 @@
-import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { HttpClient } from '@angular/common/http';
 import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
 import { By } from '@angular/platform-browser';
+import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
+import { Store } from '@ngrx/store';
+import { TranslateService } from '@ngx-translate/core';
 import { of as observableOf } from 'rxjs';
-import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model';
-import { OrgUnitSearchResultListSubmissionElementComponent } from './org-unit-search-result-list-submission-element.component';
-import { Item } from '../../../../../core/shared/item.model';
-import { TruncatePipe } from '../../../../../shared/utils/truncate.pipe';
-import { TruncatableService } from '../../../../../shared/truncatable/truncatable.service';
+import { Observable } from 'rxjs/internal/Observable';
+import { RemoteDataBuildService } from '../../../../../core/cache/builders/remote-data-build.service';
+import { ObjectCacheService } from '../../../../../core/cache/object-cache.service';
+import { BitstreamDataService } from '../../../../../core/data/bitstream-data.service';
+import { CommunityDataService } from '../../../../../core/data/community-data.service';
+import { DefaultChangeAnalyzer } from '../../../../../core/data/default-change-analyzer.service';
+import { DSOChangeAnalyzer } from '../../../../../core/data/dso-change-analyzer.service';
+import { ItemDataService } from '../../../../../core/data/item-data.service';
+import { PaginatedList } from '../../../../../core/data/paginated-list';
 import { RelationshipService } from '../../../../../core/data/relationship.service';
+import { RemoteData } from '../../../../../core/data/remote-data';
+import { Bitstream } from '../../../../../core/shared/bitstream.model';
+import { HALEndpointService } from '../../../../../core/shared/hal-endpoint.service';
+import { Item } from '../../../../../core/shared/item.model';
+import { UUIDService } from '../../../../../core/shared/uuid.service';
 import { NotificationsService } from '../../../../../shared/notifications/notifications.service';
-import { TranslateService } from '@ngx-translate/core';
-import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
-import { ItemDataService } from '../../../../../core/data/item-data.service';
+import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model';
 import { SelectableListService } from '../../../../../shared/object-list/selectable-list/selectable-list.service';
-import { Store } from '@ngrx/store';
 import { createSuccessfulRemoteDataObject$ } from '../../../../../shared/testing/utils';
-import { PaginatedList } from '../../../../../core/data/paginated-list';
+import { TruncatableService } from '../../../../../shared/truncatable/truncatable.service';
+import { TruncatePipe } from '../../../../../shared/utils/truncate.pipe';
+import { OrgUnitSearchResultListSubmissionElementComponent } from './org-unit-search-result-list-submission-element.component';
 
 let personListElementComponent: OrgUnitSearchResultListSubmissionElementComponent;
 let fixture: ComponentFixture<OrgUnitSearchResultListSubmissionElementComponent>;
@@ -79,6 +91,11 @@ function init() {
 describe('OrgUnitSearchResultListSubmissionElementComponent', () => {
   beforeEach(async(() => {
     init();
+    const mockBitstreamDataService = {
+      getThumbnailFor(item: Item): Observable<RemoteData<Bitstream>> {
+        return createSuccessfulRemoteDataObject$(new Bitstream());
+      }
+    };
     TestBed.configureTestingModule({
       declarations: [OrgUnitSearchResultListSubmissionElementComponent, TruncatePipe],
       providers: [
@@ -89,7 +106,16 @@ describe('OrgUnitSearchResultListSubmissionElementComponent', () => {
         { provide: NgbModal, useValue: {} },
         { provide: ItemDataService, useValue: {} },
         { provide: SelectableListService, useValue: {} },
-        { provide: Store, useValue: {} }
+        { provide: Store, useValue: {} },
+        { provide: ObjectCacheService, useValue: {} },
+        { provide: UUIDService, useValue: {} },
+        { provide: RemoteDataBuildService, useValue: {} },
+        { provide: CommunityDataService, useValue: {} },
+        { provide: HALEndpointService, useValue: {} },
+        { provide: HttpClient, useValue: {} },
+        { provide: DSOChangeAnalyzer, useValue: {} },
+        { provide: DefaultChangeAnalyzer, useValue: {} },
+        { provide: BitstreamDataService, useValue: mockBitstreamDataService },
       ],
 
       schemas: [NO_ERRORS_SCHEMA]
diff --git a/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-search-result-list-submission-element.component.ts b/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-search-result-list-submission-element.component.ts
index cbddb8d6f9c535f37c5178881ef0e5c49d72333c..96f28a799bbde0bea95ec6ddde6aaec879f635e6 100644
--- a/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-search-result-list-submission-element.component.ts
+++ b/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-search-result-list-submission-element.component.ts
@@ -1,4 +1,8 @@
 import { Component, OnInit } from '@angular/core';
+import { Observable } from 'rxjs/internal/Observable';
+import { BitstreamDataService } from '../../../../../core/data/bitstream-data.service';
+import { Bitstream } from '../../../../../core/shared/bitstream.model';
+import { getFirstSucceededRemoteDataPayload } from '../../../../../core/shared/operators';
 import { SearchResultListElementComponent } from '../../../../../shared/object-list/search-result-list-element/search-result-list-element.component';
 import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model';
 import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator';
@@ -37,6 +41,7 @@ export class OrgUnitSearchResultListSubmissionElementComponent extends SearchRes
               private translateService: TranslateService,
               private modalService: NgbModal,
               private itemDataService: ItemDataService,
+              private bitstreamDataService: BitstreamDataService,
               private selectableListService: SelectableListService) {
     super(truncatableService);
   }
@@ -95,4 +100,11 @@ export class OrgUnitSearchResultListSubmissionElementComponent extends SearchRes
     modalComp.value = value;
     return modalRef.result;
   }
+
+  // TODO refactor to return RemoteData, and thumbnail template to deal with loading
+  getThumbnail(): Observable<Bitstream> {
+    return this.bitstreamDataService.getThumbnailFor(this.dso).pipe(
+      getFirstSucceededRemoteDataPayload()
+    );
+  }
 }
diff --git a/src/app/entity-groups/research-entities/submission/item-list-elements/person/person-search-result-list-submission-element.component.html b/src/app/entity-groups/research-entities/submission/item-list-elements/person/person-search-result-list-submission-element.component.html
index df93c2f4f34a225c4357640da9dd2e8c6497b1c0..25c091d386140fc2da226671bba3b94e6c875a40 100644
--- a/src/app/entity-groups/research-entities/submission/item-list-elements/person/person-search-result-list-submission-element.component.html
+++ b/src/app/entity-groups/research-entities/submission/item-list-elements/person/person-search-result-list-submission-element.component.html
@@ -1,6 +1,6 @@
 <div class="d-flex">
     <div class="person-thumbnail pr-2">
-        <ds-thumbnail [thumbnail]="dso.getThumbnail() | async" [defaultImage]="'assets/images/person-placeholder.svg'"></ds-thumbnail>
+        <ds-thumbnail [thumbnail]="getThumbnail() | async" [defaultImage]="'assets/images/person-placeholder.svg'"></ds-thumbnail>
     </div>
     <div class="flex-grow-1">
         <ds-person-input-suggestions [suggestions]="allSuggestions" [(ngModel)]="selectedName" (clickSuggestion)="select($event)" (submitSuggestion)="selectCustom($event)"></ds-person-input-suggestions>
diff --git a/src/app/entity-groups/research-entities/submission/item-list-elements/person/person-search-result-list-submission-element.component.spec.ts b/src/app/entity-groups/research-entities/submission/item-list-elements/person/person-search-result-list-submission-element.component.spec.ts
index a21f0ec0756060ece41e5020f3ea4cabba3b1e94..0949ebea7e4e700544aafb13ca634cd0850896e9 100644
--- a/src/app/entity-groups/research-entities/submission/item-list-elements/person/person-search-result-list-submission-element.component.spec.ts
+++ b/src/app/entity-groups/research-entities/submission/item-list-elements/person/person-search-result-list-submission-element.component.spec.ts
@@ -1,21 +1,33 @@
-import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { HttpClient } from '@angular/common/http';
 import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
 import { By } from '@angular/platform-browser';
+import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
+import { Store } from '@ngrx/store';
+import { TranslateService } from '@ngx-translate/core';
 import { of as observableOf } from 'rxjs';
-import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model';
-import { PersonSearchResultListSubmissionElementComponent } from './person-search-result-list-submission-element.component';
-import { Item } from '../../../../../core/shared/item.model';
-import { TruncatePipe } from '../../../../../shared/utils/truncate.pipe';
-import { TruncatableService } from '../../../../../shared/truncatable/truncatable.service';
+import { Observable } from 'rxjs/internal/Observable';
+import { RemoteDataBuildService } from '../../../../../core/cache/builders/remote-data-build.service';
+import { ObjectCacheService } from '../../../../../core/cache/object-cache.service';
+import { BitstreamDataService } from '../../../../../core/data/bitstream-data.service';
+import { CommunityDataService } from '../../../../../core/data/community-data.service';
+import { DefaultChangeAnalyzer } from '../../../../../core/data/default-change-analyzer.service';
+import { DSOChangeAnalyzer } from '../../../../../core/data/dso-change-analyzer.service';
+import { ItemDataService } from '../../../../../core/data/item-data.service';
+import { PaginatedList } from '../../../../../core/data/paginated-list';
 import { RelationshipService } from '../../../../../core/data/relationship.service';
+import { RemoteData } from '../../../../../core/data/remote-data';
+import { Bitstream } from '../../../../../core/shared/bitstream.model';
+import { HALEndpointService } from '../../../../../core/shared/hal-endpoint.service';
+import { Item } from '../../../../../core/shared/item.model';
+import { UUIDService } from '../../../../../core/shared/uuid.service';
 import { NotificationsService } from '../../../../../shared/notifications/notifications.service';
-import { TranslateService } from '@ngx-translate/core';
-import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
-import { ItemDataService } from '../../../../../core/data/item-data.service';
+import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model';
 import { SelectableListService } from '../../../../../shared/object-list/selectable-list/selectable-list.service';
-import { Store } from '@ngrx/store';
 import { createSuccessfulRemoteDataObject$ } from '../../../../../shared/testing/utils';
-import { PaginatedList } from '../../../../../core/data/paginated-list';
+import { TruncatableService } from '../../../../../shared/truncatable/truncatable.service';
+import { TruncatePipe } from '../../../../../shared/utils/truncate.pipe';
+import { PersonSearchResultListSubmissionElementComponent } from './person-search-result-list-submission-element.component';
 
 let personListElementComponent: PersonSearchResultListSubmissionElementComponent;
 let fixture: ComponentFixture<PersonSearchResultListSubmissionElementComponent>;
@@ -71,6 +83,11 @@ function init() {
 }
 
 describe('PersonSearchResultListElementSubmissionComponent', () => {
+  const mockBitstreamDataService = {
+    getThumbnailFor(item: Item): Observable<RemoteData<Bitstream>> {
+      return createSuccessfulRemoteDataObject$(new Bitstream());
+    }
+  };
   beforeEach(async(() => {
     init();
     TestBed.configureTestingModule({
@@ -83,7 +100,16 @@ describe('PersonSearchResultListElementSubmissionComponent', () => {
         { provide: NgbModal, useValue: {} },
         { provide: ItemDataService, useValue: {} },
         { provide: SelectableListService, useValue: {} },
-        { provide: Store, useValue: {}}
+        { provide: Store, useValue: {}},
+        { provide: ObjectCacheService, useValue: {} },
+        { provide: UUIDService, useValue: {} },
+        { provide: RemoteDataBuildService, useValue: {} },
+        { provide: CommunityDataService, useValue: {} },
+        { provide: HALEndpointService, useValue: {} },
+        { provide: HttpClient, useValue: {} },
+        { provide: DSOChangeAnalyzer, useValue: {} },
+        { provide: DefaultChangeAnalyzer, useValue: {} },
+        { provide: BitstreamDataService, useValue: mockBitstreamDataService },
       ],
 
       schemas: [NO_ERRORS_SCHEMA]
diff --git a/src/app/entity-groups/research-entities/submission/item-list-elements/person/person-search-result-list-submission-element.component.ts b/src/app/entity-groups/research-entities/submission/item-list-elements/person/person-search-result-list-submission-element.component.ts
index 37fd77649ba93815bf5bdaa734114a0072616564..83761c6c2097b24b126ea3f8b748cc09b465ff33 100644
--- a/src/app/entity-groups/research-entities/submission/item-list-elements/person/person-search-result-list-submission-element.component.ts
+++ b/src/app/entity-groups/research-entities/submission/item-list-elements/person/person-search-result-list-submission-element.component.ts
@@ -1,4 +1,8 @@
 import { Component, OnInit } from '@angular/core';
+import { Observable } from 'rxjs/internal/Observable';
+import { BitstreamDataService } from '../../../../../core/data/bitstream-data.service';
+import { Bitstream } from '../../../../../core/shared/bitstream.model';
+import { getFirstSucceededRemoteDataPayload } from '../../../../../core/shared/operators';
 import { SearchResultListElementComponent } from '../../../../../shared/object-list/search-result-list-element/search-result-list-element.component';
 import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model';
 import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator';
@@ -37,6 +41,7 @@ export class PersonSearchResultListSubmissionElementComponent extends SearchResu
               private translateService: TranslateService,
               private modalService: NgbModal,
               private itemDataService: ItemDataService,
+              private bitstreamDataService: BitstreamDataService,
               private selectableListService: SelectableListService) {
     super(truncatableService);
   }
@@ -95,4 +100,11 @@ export class PersonSearchResultListSubmissionElementComponent extends SearchResu
     modalComp.value = value;
     return modalRef.result;
   }
+
+  // TODO refactor to return RemoteData, and thumbnail template to deal with loading
+  getThumbnail(): Observable<Bitstream> {
+    return this.bitstreamDataService.getThumbnailFor(this.dso).pipe(
+      getFirstSucceededRemoteDataPayload()
+    );
+  }
 }
diff --git a/src/app/entity-groups/research-entities/submission/name-variant-modal/name-variant-modal.component.spec.ts b/src/app/entity-groups/research-entities/submission/name-variant-modal/name-variant-modal.component.spec.ts
index b5043ea2d67e2b37f18a06f9cc46c4a15417bbc5..e3c73617f100ec39e045ee2de2c1eb8cec3c1e5b 100644
--- a/src/app/entity-groups/research-entities/submission/name-variant-modal/name-variant-modal.component.spec.ts
+++ b/src/app/entity-groups/research-entities/submission/name-variant-modal/name-variant-modal.component.spec.ts
@@ -18,7 +18,7 @@ describe('NameVariantModalComponent', () => {
     init();
     TestBed.configureTestingModule({
       declarations: [NameVariantModalComponent],
-      imports: [NgbModule.forRoot(), TranslateModule.forRoot()],
+      imports: [NgbModule, TranslateModule.forRoot()],
       providers: [{ provide: NgbActiveModal, useValue: modal }]
     })
       .compileComponents();
diff --git a/src/app/search-navbar/search-navbar.component.ts b/src/app/search-navbar/search-navbar.component.ts
index 1bedfb73ef2296f5167430abe2e3756b921a4a59..01329c1cbe4a3b631a7ed2aa96b5837f623ac0ac 100644
--- a/src/app/search-navbar/search-navbar.component.ts
+++ b/src/app/search-navbar/search-navbar.component.ts
@@ -22,7 +22,7 @@ export class SearchNavbarComponent {
   isExpanded = 'collapsed';
 
   // Search input field
-  @ViewChild('searchInput') searchField: ElementRef;
+  @ViewChild('searchInput', {static: false}) searchField: ElementRef;
 
   constructor(private formBuilder: FormBuilder, private router: Router, private searchService: SearchService) {
     this.searchForm = this.formBuilder.group(({
diff --git a/src/app/shared/browse-by/browse-by.component.spec.ts b/src/app/shared/browse-by/browse-by.component.spec.ts
index 5592b88c86481c88b5ccd5eb82ff2f4a7a47cbe1..51db888c4b7873c30af6ecbfce75b493e0e7e6c1 100644
--- a/src/app/shared/browse-by/browse-by.component.spec.ts
+++ b/src/app/shared/browse-by/browse-by.component.spec.ts
@@ -51,7 +51,7 @@ describe('BrowseByComponent', () => {
         CommonModule,
         TranslateModule.forRoot(),
         SharedModule,
-        NgbModule.forRoot(),
+        NgbModule,
         StoreModule.forRoot({}),
         TranslateModule.forRoot({
           loader: {
diff --git a/src/app/shared/chips/chips.component.spec.ts b/src/app/shared/chips/chips.component.spec.ts
index 6dbecf51655782626b4d45df639ad5250a527a85..facfc8061b83670bbbb78438b6b11aa66a58f79d 100644
--- a/src/app/shared/chips/chips.component.spec.ts
+++ b/src/app/shared/chips/chips.component.spec.ts
@@ -6,16 +6,16 @@ import { Chips } from './models/chips.model';
 import { UploaderService } from '../uploader/uploader.service';
 import { ChipsComponent } from './chips.component';
 import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
-import { SortablejsModule } from 'angular-sortablejs';
 import { By } from '@angular/platform-browser';
 import { FormFieldMetadataValueObject } from '../form/builder/models/form-field-metadata-value.model';
-import { createTestComponent, hasClass } from '../testing/utils';
+import { createTestComponent } from '../testing/utils';
 import { AuthorityConfidenceStateDirective } from '../authority-confidence/authority-confidence-state.directive';
 import { TranslateModule } from '@ngx-translate/core';
 import { GlobalConfig } from '../../../config/global-config.interface';
 import { GLOBAL_CONFIG } from '../../../config';
 import { MOCK_SUBMISSION_CONFIG } from '../testing/mock-submission-config';
 import { ConfidenceType } from '../../core/integration/models/confidence-type';
+import { SortablejsModule } from 'ngx-sortablejs';
 
 describe('ChipsComponent test suite', () => {
 
@@ -32,7 +32,7 @@ describe('ChipsComponent test suite', () => {
 
     TestBed.configureTestingModule({
       imports: [
-        NgbModule.forRoot(),
+        NgbModule,
         SortablejsModule.forRoot({animation: 150}),
         TranslateModule.forRoot()
       ],
diff --git a/src/app/shared/chips/chips.component.ts b/src/app/shared/chips/chips.component.ts
index 1283decc9f3ed0aaefec87070c706aa11198414e..82bb8f0f726638757db0f664b1ae51dba7e70f8e 100644
--- a/src/app/shared/chips/chips.component.ts
+++ b/src/app/shared/chips/chips.component.ts
@@ -1,13 +1,13 @@
 import { ChangeDetectorRef, Component, EventEmitter, Input, OnChanges, Output, SimpleChanges, } from '@angular/core';
 
 import { NgbTooltip } from '@ng-bootstrap/ng-bootstrap';
-import { SortablejsOptions } from 'angular-sortablejs';
 import { isObject } from 'lodash';
 
 import { Chips } from './models/chips.model';
 import { ChipsItem } from './models/chips-item.model';
 import { UploaderService } from '../uploader/uploader.service';
 import { TranslateService } from '@ngx-translate/core';
+import { Options } from 'sortablejs';
 
 @Component({
   selector: 'ds-chips',
@@ -25,7 +25,7 @@ export class ChipsComponent implements OnChanges {
   @Output() remove: EventEmitter<number> = new EventEmitter<number>();
   @Output() change: EventEmitter<any> = new EventEmitter<any>();
 
-  options: SortablejsOptions;
+  options: Options;
   dragged = -1;
   tipText: string[];
 
diff --git a/src/app/shared/comcol-forms/comcol-form/comcol-form.component.spec.ts b/src/app/shared/comcol-forms/comcol-form/comcol-form.component.spec.ts
index 58488f721a1bbf99d018b35b33eee6ea0474ac32..06f9843c6df6e401be51d1cc542b02655717c96f 100644
--- a/src/app/shared/comcol-forms/comcol-form/comcol-form.component.spec.ts
+++ b/src/app/shared/comcol-forms/comcol-form/comcol-form.component.spec.ts
@@ -1,27 +1,27 @@
-import { async, ComponentFixture, TestBed } from '@angular/core/testing';
-import { TranslateModule } from '@ngx-translate/core';
 import { Location } from '@angular/common';
-import { RouterTestingModule } from '@angular/router/testing';
 import { NO_ERRORS_SCHEMA } from '@angular/core';
-import { DynamicFormControlModel, DynamicFormService, DynamicInputModel } from '@ng-dynamic-forms/core';
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
 import { FormControl, FormGroup } from '@angular/forms';
+import { By } from '@angular/platform-browser';
+import { RouterTestingModule } from '@angular/router/testing';
+import { DynamicFormControlModel, DynamicFormService, DynamicInputModel } from '@ng-dynamic-forms/core';
+import { TranslateModule } from '@ngx-translate/core';
+import { of as observableOf } from 'rxjs';
+import { AuthService } from '../../../core/auth/auth.service';
+import { ObjectCacheService } from '../../../core/cache/object-cache.service';
+import { ErrorResponse, RestResponse } from '../../../core/cache/response.models';
+import { RemoteData } from '../../../core/data/remote-data';
+import { RequestError } from '../../../core/data/request.models';
+import { RequestService } from '../../../core/data/request.service';
+import { RestRequestMethod } from '../../../core/data/rest-request-method';
 import { Community } from '../../../core/shared/community.model';
-import { ComColFormComponent } from './comcol-form.component';
 import { DSpaceObject } from '../../../core/shared/dspace-object.model';
 import { hasValue } from '../../empty.util';
-import { VarDirective } from '../../utils/var.directive';
+import { AuthServiceMock } from '../../mocks/mock-auth.service';
 import { NotificationsService } from '../../notifications/notifications.service';
 import { NotificationsServiceStub } from '../../testing/notifications-service-stub';
-import { AuthService } from '../../../core/auth/auth.service';
-import { AuthServiceMock } from '../../mocks/mock-auth.service';
-import { of as observableOf } from 'rxjs';
-import { RemoteData } from '../../../core/data/remote-data';
-import { RestRequestMethod } from '../../../core/data/rest-request-method';
-import { ErrorResponse, RestResponse } from '../../../core/cache/response.models';
-import { RequestError } from '../../../core/data/request.models';
-import { RequestService } from '../../../core/data/request.service';
-import { ObjectCacheService } from '../../../core/cache/object-cache.service';
-import { By } from '@angular/platform-browser';
+import { VarDirective } from '../../utils/var.directive';
+import { ComColFormComponent } from './comcol-form.component';
 
 describe('ComColFormComponent', () => {
   let comp: ComColFormComponent<DSpaceObject>;
@@ -43,10 +43,10 @@ describe('ComColFormComponent', () => {
   const dcRandom = 'dc.random';
   const dcAbstract = 'dc.description.abstract';
 
-  const titleMD = { [dcTitle]: [ { value: 'Community Title', language: null } ] };
-  const randomMD = { [dcRandom]: [ { value: 'Random metadata excluded from form', language: null } ] };
-  const abstractMD = { [dcAbstract]: [ { value: 'Community description', language: null } ] };
-  const newTitleMD = { [dcTitle]: [ { value: 'New Community Title', language: null } ] };
+  const titleMD = { [dcTitle]: [{ value: 'Community Title', language: null }] };
+  const randomMD = { [dcRandom]: [{ value: 'Random metadata excluded from form', language: null }] };
+  const abstractMD = { [dcAbstract]: [{ value: 'Community description', language: null }] };
+  const newTitleMD = { [dcTitle]: [{ value: 'New Community Title', language: null }] };
   const formModel = [
     new DynamicInputModel({
       id: 'title',
@@ -96,7 +96,9 @@ describe('ComColFormComponent', () => {
 
   describe('when the dso doesn\'t contain an ID (newly created)', () => {
     beforeEach(() => {
-      initComponent(new Community());
+      initComponent(Object.assign(new Community(), {
+        _links: { self: { href: 'community-self' } }
+      }));
     });
 
     it('should initialize the uploadFilesOptions with a placeholder url', () => {
@@ -119,7 +121,6 @@ describe('ComColFormComponent', () => {
             }
           }
         );
-
         comp.onSubmit();
 
         expect(comp.submitForm.emit).toHaveBeenCalledWith(
@@ -191,7 +192,8 @@ describe('ComColFormComponent', () => {
       beforeEach(() => {
         initComponent(Object.assign(new Community(), {
           id: 'community-id',
-          logo: observableOf(new RemoteData(false, false, true, null, undefined))
+          logo: observableOf(new RemoteData(false, false, true, null, undefined)),
+          _links: { self: { href: 'community-self' } }
         }));
       });
 
@@ -208,7 +210,8 @@ describe('ComColFormComponent', () => {
       beforeEach(() => {
         initComponent(Object.assign(new Community(), {
           id: 'community-id',
-          logo: observableOf(new RemoteData(false, false, true, null, {}))
+          logo: observableOf(new RemoteData(false, false, true, null, {})),
+          _links: { self: { href: 'community-self' } }
         }));
       });
 
@@ -239,7 +242,7 @@ describe('ComColFormComponent', () => {
         });
 
         describe('when dsoService.deleteLogo returns an error response', () => {
-          const response = new ErrorResponse(new RequestError('errorMessage'));
+          const response = new ErrorResponse(new RequestError('this error was purposely thrown, to test error notifications'));
 
           beforeEach(() => {
             spyOn(dsoService, 'deleteLogo').and.returnValue(observableOf(response));
@@ -313,9 +316,9 @@ describe('ComColFormComponent', () => {
     comp.formModel = [];
     comp.dso = dso;
     (comp as any).type = Community.type;
-    comp.uploaderComponent = Object.assign({
-      uploader: {}
-    });
+    comp.uploaderComponent = {uploader: {}} as any;
+
+    console.log(comp);
     (comp as any).dsoService = dsoService;
     fixture.detectChanges();
     location = (comp as any).location;
diff --git a/src/app/shared/comcol-forms/comcol-form/comcol-form.component.ts b/src/app/shared/comcol-forms/comcol-form/comcol-form.component.ts
index 435ef61d723a22dcaa595c5af47159f6fae4d376..35c6f5096989f275320b6846e1b95a3543a46aab 100644
--- a/src/app/shared/comcol-forms/comcol-form/comcol-form.component.ts
+++ b/src/app/shared/comcol-forms/comcol-form/comcol-form.component.ts
@@ -1,34 +1,30 @@
-import { Component, EventEmitter, Input, OnDestroy, OnInit, Output, ViewChild } from '@angular/core';
 import { Location } from '@angular/common';
-import {
-  DynamicFormControlModel,
-  DynamicFormService,
-  DynamicInputModel
-} from '@ng-dynamic-forms/core';
+import { Component, EventEmitter, Input, OnDestroy, OnInit, Output, ViewChild } from '@angular/core';
 import { FormGroup } from '@angular/forms';
+import { DynamicFormControlModel, DynamicFormService, DynamicInputModel } from '@ng-dynamic-forms/core';
 import { TranslateService } from '@ngx-translate/core';
+import { FileUploader } from 'ng2-file-upload';
+import { combineLatest as observableCombineLatest } from 'rxjs';
+import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject';
+import { Subscription } from 'rxjs/internal/Subscription';
+import { AuthService } from '../../../core/auth/auth.service';
+import { ObjectCacheService } from '../../../core/cache/object-cache.service';
+import { ErrorResponse, RestResponse } from '../../../core/cache/response.models';
+import { ComColDataService } from '../../../core/data/comcol-data.service';
+import { RemoteData } from '../../../core/data/remote-data';
+import { RequestService } from '../../../core/data/request.service';
+import { RestRequestMethod } from '../../../core/data/rest-request-method';
+import { Bitstream } from '../../../core/shared/bitstream.model';
+import { Collection } from '../../../core/shared/collection.model';
+import { Community } from '../../../core/shared/community.model';
 
 import { DSpaceObject } from '../../../core/shared/dspace-object.model';
 import { MetadataMap, MetadataValue } from '../../../core/shared/metadata.models';
 import { ResourceType } from '../../../core/shared/resource-type';
 import { hasValue, isNotEmpty } from '../../empty.util';
-import { UploaderOptions } from '../../uploader/uploader-options.model';
 import { NotificationsService } from '../../notifications/notifications.service';
-import { ComColDataService } from '../../../core/data/comcol-data.service';
-import { Subscription } from 'rxjs/internal/Subscription';
-import { AuthService } from '../../../core/auth/auth.service';
-import { Community } from '../../../core/shared/community.model';
-import { Collection } from '../../../core/shared/collection.model';
+import { UploaderOptions } from '../../uploader/uploader-options.model';
 import { UploaderComponent } from '../../uploader/uploader.component';
-import { FileUploader } from 'ng2-file-upload';
-import { ErrorResponse, RestResponse } from '../../../core/cache/response.models';
-import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject';
-import { RemoteData } from '../../../core/data/remote-data';
-import { Bitstream } from '../../../core/shared/bitstream.model';
-import { combineLatest as observableCombineLatest } from 'rxjs';
-import { RestRequestMethod } from '../../../core/data/rest-request-method';
-import { RequestService } from '../../../core/data/request.service';
-import { ObjectCacheService } from '../../../core/cache/object-cache.service';
 
 /**
  * A form for creating and editing Communities or Collections
@@ -43,7 +39,7 @@ export class ComColFormComponent<T extends DSpaceObject> implements OnInit, OnDe
   /**
    * The logo uploader component
    */
-  @ViewChild(UploaderComponent) uploaderComponent: UploaderComponent;
+  @ViewChild(UploaderComponent, {static: true}) uploaderComponent: UploaderComponent;
 
   /**
    * DSpaceObject that the form represents
@@ -253,8 +249,8 @@ export class ComColFormComponent<T extends DSpaceObject> implements OnInit, OnDe
    * Refresh the object's cache to ensure the latest version
    */
   private refreshCache() {
-    this.requestService.removeByHrefSubstring(this.dso.self);
-    this.objectCache.remove(this.dso.self);
+    this.requestService.removeByHrefSubstring(this.dso._links.self.href);
+    this.objectCache.remove(this.dso._links.self.href);
   }
 
   /**
diff --git a/src/app/shared/comcol-forms/create-comcol-page/create-comcol-page.component.ts b/src/app/shared/comcol-forms/create-comcol-page/create-comcol-page.component.ts
index 7b23c5949872649694d13bf4452d2e0ef70a90d0..e9373aff47378c10b2f15e8a91a269fab95e11b6 100644
--- a/src/app/shared/comcol-forms/create-comcol-page/create-comcol-page.component.ts
+++ b/src/app/shared/comcol-forms/create-comcol-page/create-comcol-page.component.ts
@@ -1,19 +1,18 @@
 import { Component, OnInit } from '@angular/core';
-import { Community } from '../../../core/shared/community.model';
-import { CommunityDataService } from '../../../core/data/community-data.service';
+import { Router } from '@angular/router';
+import { TranslateService } from '@ngx-translate/core';
 import { Observable } from 'rxjs';
-import { RouteService } from '../../../core/services/route.service';
-import { ActivatedRoute, Router } from '@angular/router';
-import { RemoteData } from '../../../core/data/remote-data';
-import { hasValue, isNotEmpty, isNotUndefined } from '../../empty.util';
 import { take } from 'rxjs/operators';
-import { getSucceededRemoteData } from '../../../core/shared/operators';
-import { DSpaceObject } from '../../../core/shared/dspace-object.model';
-import { DataService } from '../../../core/data/data.service';
 import { ComColDataService } from '../../../core/data/comcol-data.service';
-import { NotificationsService } from '../../notifications/notifications.service';
-import { TranslateService } from '@ngx-translate/core';
+import { CommunityDataService } from '../../../core/data/community-data.service';
+import { RemoteData } from '../../../core/data/remote-data';
+import { RouteService } from '../../../core/services/route.service';
+import { Community } from '../../../core/shared/community.model';
+import { DSpaceObject } from '../../../core/shared/dspace-object.model';
+import { getSucceededRemoteData } from '../../../core/shared/operators';
 import { ResourceType } from '../../../core/shared/resource-type';
+import { hasValue, isNotEmpty, isNotUndefined } from '../../empty.util';
+import { NotificationsService } from '../../notifications/notifications.service';
 
 /**
  * Component representing the create page for communities and collections
diff --git a/src/app/shared/comcol-forms/delete-comcol-page/delete-comcol-page.component.spec.ts b/src/app/shared/comcol-forms/delete-comcol-page/delete-comcol-page.component.spec.ts
index 3b39d36008072d5e45d16ed2c72dc8025ae7f3ea..dbbeea5bc6b331da93be8740bab08b948d32ce55 100644
--- a/src/app/shared/comcol-forms/delete-comcol-page/delete-comcol-page.component.spec.ts
+++ b/src/app/shared/comcol-forms/delete-comcol-page/delete-comcol-page.component.spec.ts
@@ -125,7 +125,7 @@ describe('DeleteComColPageComponent', () => {
     it('should call delete on the data service', () => {
       comp.onConfirm(data1);
       fixture.detectChanges();
-      expect(dsoDataService.delete).toHaveBeenCalledWith(data1);
+      expect(dsoDataService.delete).toHaveBeenCalledWith(data1.id);
     });
   });
 
diff --git a/src/app/shared/comcol-forms/delete-comcol-page/delete-comcol-page.component.ts b/src/app/shared/comcol-forms/delete-comcol-page/delete-comcol-page.component.ts
index 57c860e04fa65e9068bc037fb56feb82c879a4d2..f5a1a84af5da2ecd0e9aa62263f1530d3bbd48a8 100644
--- a/src/app/shared/comcol-forms/delete-comcol-page/delete-comcol-page.component.ts
+++ b/src/app/shared/comcol-forms/delete-comcol-page/delete-comcol-page.component.ts
@@ -43,7 +43,7 @@ export class DeleteComColPageComponent<TDomain extends DSpaceObject> implements
    * Deletes an existing DSO and redirects to the home page afterwards, showing a notification that states whether or not the deletion was successful
    */
   onConfirm(dso: TDomain) {
-    this.dsoDataService.delete(dso)
+    this.dsoDataService.delete(dso.id)
       .pipe(first())
       .subscribe((success: boolean) => {
         if (success) {
diff --git a/src/app/shared/comcol-forms/edit-comcol-page/comcol-metadata/comcol-metadata.component.spec.ts b/src/app/shared/comcol-forms/edit-comcol-page/comcol-metadata/comcol-metadata.component.spec.ts
index 5711aa4e701433c6656479a3e6306e906cc471f3..84454c42506a03df14b1b3209938c888238c069b 100644
--- a/src/app/shared/comcol-forms/edit-comcol-page/comcol-metadata/comcol-metadata.component.spec.ts
+++ b/src/app/shared/comcol-forms/edit-comcol-page/comcol-metadata/comcol-metadata.component.spec.ts
@@ -1,21 +1,20 @@
-import { DSpaceObject } from '../../../../core/shared/dspace-object.model';
+import { CommonModule } from '@angular/common';
+import { NO_ERRORS_SCHEMA } from '@angular/core';
 import { async, ComponentFixture, TestBed } from '@angular/core/testing';
-import { CommunityDataService } from '../../../../core/data/community-data.service';
 import { ActivatedRoute, Router } from '@angular/router';
-import { Community } from '../../../../core/shared/community.model';
+import { RouterTestingModule } from '@angular/router/testing';
+import { TranslateModule } from '@ngx-translate/core';
 import { of as observableOf } from 'rxjs/internal/observable/of';
+import { ComColDataService } from '../../../../core/data/comcol-data.service';
+import { CommunityDataService } from '../../../../core/data/community-data.service';
 import { RemoteData } from '../../../../core/data/remote-data';
-import { TranslateModule } from '@ngx-translate/core';
+import { Community } from '../../../../core/shared/community.model';
+import { DSpaceObject } from '../../../../core/shared/dspace-object.model';
+import { NotificationsService } from '../../../notifications/notifications.service';
 import { SharedModule } from '../../../shared.module';
-import { CommonModule } from '@angular/common';
-import { RouterTestingModule } from '@angular/router/testing';
-import { DataService } from '../../../../core/data/data.service';
-import { NO_ERRORS_SCHEMA } from '@angular/core';
-import { ComcolMetadataComponent } from './comcol-metadata.component';
-import { createFailedRemoteDataObject$, createSuccessfulRemoteDataObject$ } from '../../../testing/utils';
-import { ComColDataService } from '../../../../core/data/comcol-data.service';
 import { NotificationsServiceStub } from '../../../testing/notifications-service-stub';
-import { NotificationsService } from '../../../notifications/notifications.service';
+import { createFailedRemoteDataObject$, createSuccessfulRemoteDataObject$ } from '../../../testing/utils';
+import { ComcolMetadataComponent } from './comcol-metadata.component';
 
 describe('ComColMetadataComponent', () => {
   let comp: ComcolMetadataComponent<DSpaceObject>;
diff --git a/src/app/shared/comcol-page-browse-by/comcol-page-browse-by.component.ts b/src/app/shared/comcol-page-browse-by/comcol-page-browse-by.component.ts
index 1bc83d74a55f0508c45f9efa1dbecef683165e79..091e02723f3a00269a027f83aef8e16c30fe1003 100644
--- a/src/app/shared/comcol-page-browse-by/comcol-page-browse-by.component.ts
+++ b/src/app/shared/comcol-page-browse-by/comcol-page-browse-by.component.ts
@@ -12,7 +12,7 @@ import { filter, map, startWith, tap } from 'rxjs/operators';
 import { getCollectionPageRoute } from '../../+collection-page/collection-page-routing.module';
 import { getCommunityPageRoute } from '../../+community-page/community-page-routing.module';
 import { GLOBAL_CONFIG, GlobalConfig } from '../../../config';
-import { Router, ActivatedRoute, RouterModule, UrlSegment } from '@angular/router';
+import { Router, ActivatedRoute, RouterModule, UrlSegment, Params } from '@angular/router';
 import { BrowseByTypeConfig } from '../../../config/browse-by-type-config.interface';
 import { hasValue } from '../empty.util';
 
@@ -76,9 +76,8 @@ export class ComcolPageBrowseByComponent implements OnInit {
         }, ...this.allOptions ];
     }
 
-    this.currentOptionId$ = this.route.url.pipe(
-      filter((urlSegments: UrlSegment[]) => hasValue(urlSegments)),
-      map((urlSegments: UrlSegment[]) => urlSegments[urlSegments.length - 1].path)
+    this.currentOptionId$ = this.route.params.pipe(
+      map((params: Params) => params.id)
     );
   }
 
diff --git a/src/app/shared/comcol-page-logo/comcol-page-logo.component.html b/src/app/shared/comcol-page-logo/comcol-page-logo.component.html
index 4bd7369f06e67b648872bad15267c337bdcb1c8b..057c358223942eaf0a5bd96d4f1217f59ee27e66 100644
--- a/src/app/shared/comcol-page-logo/comcol-page-logo.component.html
+++ b/src/app/shared/comcol-page-logo/comcol-page-logo.component.html
@@ -1,3 +1,3 @@
 <div *ngIf="logo" class="dso-logo mb-3">
-    <img [src]="logo.content" class="img-fluid" [attr.alt]="alternateText ? alternateText : null" (error)="errorHandler($event)"/>
+    <img [src]="logo._links.content.href" class="img-fluid" [attr.alt]="alternateText ? alternateText : null" (error)="errorHandler($event)"/>
 </div>
diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.scss b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.scss
index 5b808b9cfd4c377c05c99b5b0846e9c33b7871b9..4e58759f4e7884348c0a0930e1ae363ff0873777 100644
--- a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.scss
+++ b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.scss
@@ -9,7 +9,7 @@
   justify-content: center;
 }
 
-:host /deep/ .custom-select {
+:host ::ng-deep .custom-select {
   -webkit-appearance: none;
   -moz-appearance: none;
   appearance: none;
diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.spec.ts
index 91c1dbc085971fb1dd0a5d49414fc64cee99150f..75ea88735f2b3e0631e67912b215ff3204e4e2cf 100644
--- a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.spec.ts
+++ b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.spec.ts
@@ -160,7 +160,7 @@ describe('DsDynamicFormControlContainerComponent test suite', () => {
       imports: [
         FormsModule,
         ReactiveFormsModule,
-        NgbModule.forRoot(),
+        NgbModule,
         DynamicFormsCoreModule.forRoot(),
         SharedModule,
         TranslateModule.forRoot(),
diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.ts
index d916486452f9a40a6be6d64e561cbac5ce1baea3..2089ce8bcaca578a816cbb3dc06709aca0efb838 100644
--- a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.ts
+++ b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.ts
@@ -29,13 +29,13 @@ import {
   DYNAMIC_FORM_CONTROL_TYPE_SELECT,
   DYNAMIC_FORM_CONTROL_TYPE_TEXTAREA,
   DYNAMIC_FORM_CONTROL_TYPE_TIMEPICKER,
-  DynamicDatePickerModel,
+  DynamicDatePickerModel, DynamicFormComponentService,
   DynamicFormControl,
   DynamicFormControlContainerComponent,
   DynamicFormControlEvent,
-  DynamicFormControlModel, DynamicFormInstancesService,
+  DynamicFormControlModel,
   DynamicFormLayout,
-  DynamicFormLayoutService,
+  DynamicFormLayoutService, DynamicFormRelationService,
   DynamicFormValidationService,
   DynamicTemplateDirective,
 } from '@ng-dynamic-forms/core';
@@ -50,6 +50,7 @@ import {
   DynamicNGBootstrapTimePickerComponent
 } from '@ng-dynamic-forms/ui-ng-bootstrap';
 import { TranslateService } from '@ngx-translate/core';
+import { followLink } from '../../../utils/follow-link-config.model';
 import {
   Reorderable,
   ReorderableRelationship
@@ -206,32 +207,32 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo
   @Output('dfFocus') focus: EventEmitter<DynamicFormControlEvent> = new EventEmitter<DynamicFormControlEvent>();
   @Output('ngbEvent') customEvent: EventEmitter<DynamicFormControlEvent> = new EventEmitter<DynamicFormControlEvent>();
   /* tslint:enable:no-output-rename */
-  @ViewChild('componentViewContainer', { read: ViewContainerRef }) componentViewContainerRef: ViewContainerRef;
+  @ViewChild('componentViewContainer', { read: ViewContainerRef, static: true}) componentViewContainerRef: ViewContainerRef;
 
   private showErrorMessagesPreviousStage: boolean;
 
   get componentType(): Type<DynamicFormControl> | null {
-    return this.layoutService.getCustomComponentType(this.model) || dsDynamicFormControlMapFn(this.model);
+    return dsDynamicFormControlMapFn(this.model);
   }
 
   constructor(
     protected componentFactoryResolver: ComponentFactoryResolver,
-    protected dynamicFormInstanceService: DynamicFormInstancesService,
+    protected dynamicFormComponentService: DynamicFormComponentService,
     protected layoutService: DynamicFormLayoutService,
     protected validationService: DynamicFormValidationService,
     protected translateService: TranslateService,
+    protected relationService: DynamicFormRelationService,
     private modalService: NgbModal,
-    private relationService: RelationshipService,
+    private relationshipService: RelationshipService,
     private selectableListService: SelectableListService,
     private itemService: ItemDataService,
-    private relationshipService: RelationshipService,
     private zone: NgZone,
     private store: Store<AppState>,
     private submissionObjectService: SubmissionObjectDataService,
     private ref: ChangeDetectorRef
   ) {
 
-    super(componentFactoryResolver, layoutService, validationService, dynamicFormInstanceService);
+    super(componentFactoryResolver, layoutService, validationService, dynamicFormComponentService, relationService);
   }
 
   /**
@@ -245,7 +246,7 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo
       this.listId = 'list-' + this.model.relationship.relationshipType;
 
       const submissionObject$ = this.submissionObjectService
-        .findById(this.model.submissionId).pipe(
+        .findById(this.model.submissionId, followLink('item'), followLink('collection')).pipe(
           getAllSucceededRemoteData(),
           getRemoteDataPayload()
         );
@@ -256,7 +257,7 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo
       this.subs.push(item$.subscribe((item) => this.item = item));
       this.subs.push(collection$.subscribe((collection) => this.collection = collection));
       this.reorderables$ = item$.pipe(
-        switchMap((item) => this.relationService.getItemRelationshipsByLabel(item, this.model.relationship.relationshipType)
+        switchMap((item) => this.relationshipService.getItemRelationshipsByLabel(item, this.model.relationship.relationshipType, undefined, followLink('leftItem'), followLink('rightItem'), followLink('relationshipType'))
           .pipe(
             getAllSucceededRemoteData(),
             getRemoteDataPayload(),
@@ -288,9 +289,12 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo
         this.ref.detectChanges();
       }));
 
-      this.relationService.getRelatedItemsByLabel(this.item, this.model.relationship.relationshipType).pipe(
+      item$.pipe(
+        switchMap((item) => this.relationshipService.getRelatedItemsByLabel(item, this.model.relationship.relationshipType)),
         map((items: RemoteData<PaginatedList<Item>>) => items.payload.page.map((item) => Object.assign(new ItemSearchResult(), { indexableObject: item }))),
-      ).subscribe((relatedItems: Array<SearchResult<Item>>) => this.selectableListService.select(this.listId, relatedItems));
+      ).subscribe((relatedItems: Array<SearchResult<Item>>) => {
+        this.selectableListService.select(this.listId, relatedItems)
+      });
     }
   }
 
diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker-inline/dynamic-date-picker-inline.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker-inline/dynamic-date-picker-inline.component.spec.ts
index da7f5637dda0e689f6b1d9d01deceb66d20ae091..327859e0ead8fdf2464a98a8108348dc0632abcd 100644
--- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker-inline/dynamic-date-picker-inline.component.spec.ts
+++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker-inline/dynamic-date-picker-inline.component.spec.ts
@@ -26,7 +26,7 @@ describe('DsDatePickerInlineComponent test suite', () => {
                 ReactiveFormsModule,
                 NoopAnimationsModule,
                 TextMaskModule,
-                NgbDatepickerModule.forRoot(),
+                NgbDatepickerModule,
                 DynamicFormsCoreModule.forRoot()
             ],
             declarations: [DsDatePickerInlineComponent]
diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker-inline/dynamic-date-picker-inline.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker-inline/dynamic-date-picker-inline.component.ts
index f51c2f78f4bf4d0c04e71fb2158d788a3918fe9a..73375a85a22c34f77015444c67fa2ebbc7b37618 100644
--- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker-inline/dynamic-date-picker-inline.component.ts
+++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker-inline/dynamic-date-picker-inline.component.ts
@@ -24,7 +24,7 @@ export class DsDatePickerInlineComponent extends DynamicFormControlComponent {
   @Output() change: EventEmitter<any> = new EventEmitter();
   @Output() focus: EventEmitter<any> = new EventEmitter();
 
-  @ViewChild(NgbDatepicker) ngbDatePicker: NgbDatepicker;
+  @ViewChild(NgbDatepicker, {static: false}) ngbDatePicker: NgbDatepicker;
 
   constructor(protected layoutService: DynamicFormLayoutService,
               protected validationService: DynamicFormValidationService,
diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.spec.ts
index 8f40c4f85f9af141b770dc3f972e847e907024b1..ad5492588072de358de765575380805a07f5de8d 100644
--- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.spec.ts
+++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.spec.ts
@@ -43,7 +43,7 @@ describe('DsDatePickerComponent test suite', () => {
 
     TestBed.configureTestingModule({
       imports: [
-        NgbModule.forRoot()
+        NgbModule
       ],
       declarations: [
         DsDatePickerComponent,
diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/list/dynamic-list.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/list/dynamic-list.component.spec.ts
index 1b3bcb5a598194d8b052295c4d0ec7579f0a5265..e3124446253f01f51226faaef58009bbc1bf1b7b 100644
--- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/list/dynamic-list.component.spec.ts
+++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/list/dynamic-list.component.spec.ts
@@ -88,7 +88,7 @@ describe('DsDynamicListComponent test suite', () => {
         DynamicFormsNGBootstrapUIModule,
         FormsModule,
         ReactiveFormsModule,
-        NgbModule.forRoot()
+        NgbModule
       ],
       declarations: [
         DsDynamicListComponent,
diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.scss b/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.scss
index 3af258db797ca23c23ac9ed1c1d38a0fc9a38643..e1ba2442e55d013d1f691056dc53e18a1ca4127d 100644
--- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.scss
+++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.scss
@@ -2,7 +2,7 @@
   display:none
 }
 
-:host /deep/ .dropdown-menu {
+:host ::ng-deep .dropdown-menu {
   left: 0 !important;
   width: 100% !important;
   max-height: $dropdown-menu-max-height;
@@ -10,10 +10,10 @@
   overflow-x: hidden;
 }
 
-:host /deep/ .dropdown-item.active,
-:host /deep/ .dropdown-item:active,
-:host /deep/ .dropdown-item:focus,
-:host /deep/ .dropdown-item:hover {
+:host ::ng-deep .dropdown-item.active,
+:host ::ng-deep .dropdown-item:active,
+:host ::ng-deep .dropdown-item:focus,
+:host ::ng-deep .dropdown-item:hover {
   color: $dropdown-link-hover-color !important;
   background-color: $dropdown-link-hover-bg !important;
 }
diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.spec.ts
index b0ed3a1dc21766864b020813b4c46b1aeb8e3b1f..c1f8ad69baa750f02487644061c3cbed9d33a8c1 100644
--- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.spec.ts
+++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.spec.ts
@@ -160,7 +160,7 @@ describe('Dynamic Lookup component', () => {
         FormsModule,
         InfiniteScrollModule,
         ReactiveFormsModule,
-        NgbModule.forRoot(),
+        NgbModule,
         TranslateModule.forRoot()
       ],
       declarations: [
diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.component.spec.ts
index 75d30d9d79840c48cbdbf0aa0d090d74c9415e07..eb0f8f76f94c5f0c2ce82df0c6ffe0c6386dd15d 100644
--- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.component.spec.ts
+++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.component.spec.ts
@@ -113,7 +113,7 @@ describe('DsDynamicRelationGroupComponent test suite', () => {
         BrowserAnimationsModule,
         FormsModule,
         ReactiveFormsModule,
-        NgbModule.forRoot(),
+        NgbModule,
         StoreModule.forRoot({}),
         TranslateModule.forRoot()
       ],
diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.components.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.components.ts
index ea62eeb4ce78bbf6d42380d33c9603210818e055..5f96e957ac2217fade3a4c1a8567730cde32f46f 100644
--- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.components.ts
+++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.components.ts
@@ -65,7 +65,7 @@ export class DsDynamicRelationGroupComponent extends DynamicFormControlComponent
   private selectedChipItem: ChipsItem;
   private subs: Subscription[] = [];
 
-  @ViewChild('formRef') private formRef: FormComponent;
+  @ViewChild('formRef', {static: false}) private formRef: FormComponent;
 
   constructor(@Inject(GLOBAL_CONFIG) protected EnvConfig: GlobalConfig,
               private authorityService: AuthorityService,
diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.spec.ts
index ab923a58fa7219ca1af610ab5b91a33f27ae2e91..16446e624e24957bdf0c2fc0e48f42fea6cb67b1 100644
--- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.spec.ts
+++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.spec.ts
@@ -64,7 +64,7 @@ describe('Dynamic Dynamic Scrollable Dropdown component', () => {
         FormsModule,
         InfiniteScrollModule,
         ReactiveFormsModule,
-        NgbModule.forRoot(),
+        NgbModule,
         TranslateModule.forRoot()
       ],
       declarations: [
diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/tag/dynamic-tag.component.scss b/src/app/shared/form/builder/ds-dynamic-form-ui/models/tag/dynamic-tag.component.scss
index a657d3eeb6cf012127aea1970f4002ec867bead9..032596207a62988bfc6a1d83420b47af3fcc4815 100644
--- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/tag/dynamic-tag.component.scss
+++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/tag/dynamic-tag.component.scss
@@ -8,7 +8,7 @@
   padding-right: 100%;
 }
 
-:host /deep/ .dropdown-menu {
+:host ::ng-deep .dropdown-menu {
   width: 100% !important;
   max-height: $dropdown-menu-max-height;
   overflow-y: scroll;
@@ -17,10 +17,10 @@
   margin-top: $spacer !important;
 }
 
-:host /deep/ .dropdown-item.active,
-:host /deep/ .dropdown-item:active,
-:host /deep/ .dropdown-item:focus,
-:host /deep/ .dropdown-item:hover {
+:host ::ng-deep .dropdown-item.active,
+:host ::ng-deep .dropdown-item:active,
+:host ::ng-deep .dropdown-item:focus,
+:host ::ng-deep .dropdown-item:hover {
   color: $dropdown-link-hover-color !important;
   background-color: $dropdown-link-hover-bg !important;
 }
diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/tag/dynamic-tag.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/tag/dynamic-tag.component.spec.ts
index 9aeada5032a2e23adb21794c106797ea783ac492..dcc4eaf9c9c9bc77ba3c1e1a4e6b07eff0b2c2e1 100644
--- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/tag/dynamic-tag.component.spec.ts
+++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/tag/dynamic-tag.component.spec.ts
@@ -85,7 +85,7 @@ describe('DsDynamicTagComponent test suite', () => {
         DynamicFormsCoreModule,
         DynamicFormsNGBootstrapUIModule,
         FormsModule,
-        NgbModule.forRoot(),
+        NgbModule,
         ReactiveFormsModule,
       ],
       declarations: [
diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/tag/dynamic-tag.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/tag/dynamic-tag.component.ts
index a44a20d4bd6fad264b6db0a0266d474e41fe2415..c976454dd9c6f7949e4a14cdedb647b2650450d8 100644
--- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/tag/dynamic-tag.component.ts
+++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/tag/dynamic-tag.component.ts
@@ -33,7 +33,7 @@ export class DsDynamicTagComponent extends DynamicFormControlComponent implement
   @Output() change: EventEmitter<any> = new EventEmitter<any>();
   @Output() focus: EventEmitter<any> = new EventEmitter<any>();
 
-  @ViewChild('instance') instance: NgbTypeahead;
+  @ViewChild('instance', {static: false}) instance: NgbTypeahead;
 
   chips: Chips;
   hasAuthority: boolean;
diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/typeahead/dynamic-typeahead.component.scss b/src/app/shared/form/builder/ds-dynamic-form-ui/models/typeahead/dynamic-typeahead.component.scss
index fe20afe1ce5a3e565220bf27230ca12da019e341..3857d96e78e46192097565439e318072564a5cd6 100644
--- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/typeahead/dynamic-typeahead.component.scss
+++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/typeahead/dynamic-typeahead.component.scss
@@ -1,18 +1,18 @@
-:host /deep/ .dropdown-menu {
+:host ::ng-deep .dropdown-menu {
   width: 100% !important;
   max-height: $dropdown-menu-max-height;
   overflow-y: auto !important;
   overflow-x: hidden;
 }
 
-:host /deep/ .dropdown-item {
+:host ::ng-deep .dropdown-item {
   border-bottom: $dropdown-border-width solid $dropdown-border-color;
 }
 
-:host /deep/ .dropdown-item.active,
-:host /deep/ .dropdown-item:active,
-:host /deep/ .dropdown-item:focus,
-:host /deep/ .dropdown-item:hover {
+:host ::ng-deep .dropdown-item.active,
+:host ::ng-deep .dropdown-item:active,
+:host ::ng-deep .dropdown-item:focus,
+:host ::ng-deep .dropdown-item:hover {
   color: $dropdown-link-hover-color !important;
   background-color: $dropdown-link-hover-bg !important;
 }
diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/typeahead/dynamic-typeahead.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/typeahead/dynamic-typeahead.component.spec.ts
index 47b83ed2f923b606b7f0a3c3174f47b8cadaabbd..4b1e2d8703be18909789a2ea708dd034a3860f99 100644
--- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/typeahead/dynamic-typeahead.component.spec.ts
+++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/typeahead/dynamic-typeahead.component.spec.ts
@@ -70,7 +70,7 @@ describe('DsDynamicTypeaheadComponent test suite', () => {
         DynamicFormsCoreModule,
         DynamicFormsNGBootstrapUIModule,
         FormsModule,
-        NgbModule.forRoot(),
+        NgbModule,
         ReactiveFormsModule,
         TranslateModule.forRoot()
       ],
diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/typeahead/dynamic-typeahead.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/typeahead/dynamic-typeahead.component.ts
index 136d1db1c2b4f45940987dd6d1513970a44aaa92..791704a7ca7e34eba48afe7065c126165335d2e4 100644
--- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/typeahead/dynamic-typeahead.component.ts
+++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/typeahead/dynamic-typeahead.component.ts
@@ -31,7 +31,7 @@ export class DsDynamicTypeaheadComponent extends DynamicFormControlComponent imp
   @Output() change: EventEmitter<any> = new EventEmitter<any>();
   @Output() focus: EventEmitter<any> = new EventEmitter<any>();
 
-  @ViewChild('instance') instance: NgbTypeahead;
+  @ViewChild('instance', {static: false}) instance: NgbTypeahead;
 
   searching = false;
   searchOptions: IntegrationSearchOptions;
diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component.spec.ts
index d1b289bf113eb85c3e8589506d95db62be6354de..3fbe372699abb512ba026e2ac6585be5c5e192c8 100644
--- a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component.spec.ts
+++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component.spec.ts
@@ -79,7 +79,7 @@ describe('DsDynamicLookupRelationModalComponent', () => {
     init();
     TestBed.configureTestingModule({
       declarations: [DsDynamicLookupRelationModalComponent],
-      imports: [TranslateModule.forRoot(), RouterTestingModule.withRoutes([]), NgbModule.forRoot()],
+      imports: [TranslateModule.forRoot(), RouterTestingModule.withRoutes([]), NgbModule],
       providers: [
         {
           provide: SearchConfigurationService, useValue: {
diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/dynamic-lookup-relation-external-source-tab.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/dynamic-lookup-relation-external-source-tab.component.spec.ts
index 00242ad9cea0dfdfacb93d7d469da2c02171d983..06a0cf2ac71410e539ff9ebb172d4c06b869e0b8 100644
--- a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/dynamic-lookup-relation-external-source-tab.component.spec.ts
+++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/dynamic-lookup-relation-external-source-tab.component.spec.ts
@@ -95,7 +95,7 @@ describe('DsDynamicLookupRelationExternalSourceTabComponent', () => {
     init();
     TestBed.configureTestingModule({
       declarations: [DsDynamicLookupRelationExternalSourceTabComponent, VarDirective],
-      imports: [TranslateModule.forRoot(), RouterTestingModule.withRoutes([]), NgbModule.forRoot(), BrowserAnimationsModule],
+      imports: [TranslateModule.forRoot(), RouterTestingModule.withRoutes([]), NgbModule, BrowserAnimationsModule],
       providers: [
         {
           provide: SearchConfigurationService, useValue: {
diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/external-source-entry-import-modal/external-source-entry-import-modal.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/external-source-entry-import-modal/external-source-entry-import-modal.component.spec.ts
index 5248f955737b83ca565cb2884aed2148f5ead829..264b3f945aaee542c014e13a1292668df55ef05c 100644
--- a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/external-source-entry-import-modal/external-source-entry-import-modal.component.spec.ts
+++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/external-source-entry-import-modal/external-source-entry-import-modal.component.spec.ts
@@ -67,7 +67,7 @@ describe('DsDynamicLookupRelationExternalSourceTabComponent', () => {
     init();
     TestBed.configureTestingModule({
       declarations: [ExternalSourceEntryImportModalComponent],
-      imports: [TranslateModule.forRoot(), RouterTestingModule.withRoutes([]), NgbModule.forRoot()],
+      imports: [TranslateModule.forRoot(), RouterTestingModule.withRoutes([]), NgbModule],
       providers: [
         { provide: LookupRelationService, useValue: lookupRelationService },
         { provide: SelectableListService, useValue: selectService },
diff --git a/src/app/shared/form/builder/form-builder.service.spec.ts b/src/app/shared/form/builder/form-builder.service.spec.ts
index ea0957f6893506fdae4921ec264f02cd20779dd3..972abb68b550d7db53c0c762917bf9f5b7e1249e 100644
--- a/src/app/shared/form/builder/form-builder.service.spec.ts
+++ b/src/app/shared/form/builder/form-builder.service.spec.ts
@@ -276,7 +276,7 @@ describe('FormBuilderService test suite', () => {
         {
           fields: [
             {
-              input: {type: 'lookup'},
+              input: { type: 'lookup' },
               label: 'Journal',
               mandatory: 'false',
               repeatable: false,
@@ -291,7 +291,7 @@ describe('FormBuilderService test suite', () => {
               languageCodes: []
             } as FormFieldModel,
             {
-              input: {type: 'onebox'},
+              input: { type: 'onebox' },
               label: 'Issue',
               mandatory: 'false',
               repeatable: false,
@@ -304,7 +304,7 @@ describe('FormBuilderService test suite', () => {
               languageCodes: []
             } as FormFieldModel,
             {
-              input: {type: 'name'},
+              input: { type: 'name' },
               label: 'Name',
               mandatory: 'false',
               repeatable: false,
@@ -322,24 +322,24 @@ describe('FormBuilderService test suite', () => {
           fields: [
             {
               hints: 'If the item has any identification numbers or codes associated with↵	it, please enter the types and the actual numbers or codes.',
-              input: {type: 'onebox'},
+              input: { type: 'onebox' },
               label: 'Identifiers',
               languageCodes: [],
               mandatory: 'false',
               repeatable: false,
               selectableMetadata: [
-                {metadata: 'dc.identifier.issn', label: 'ISSN'},
-                {metadata: 'dc.identifier.other', label: 'Other'},
-                {metadata: 'dc.identifier.ismn', label: 'ISMN'},
-                {metadata: 'dc.identifier.govdoc', label: 'Gov\'t Doc #'},
-                {metadata: 'dc.identifier.uri', label: 'URI'},
-                {metadata: 'dc.identifier.isbn', label: 'ISBN'},
-                {metadata: 'dc.identifier.doi', label: 'DOI'},
-                {metadata: 'dc.identifier.pmid', label: 'PubMed ID'},
-                {metadata: 'dc.identifier.arxiv', label: 'arXiv'}
+                { metadata: 'dc.identifier.issn', label: 'ISSN' },
+                { metadata: 'dc.identifier.other', label: 'Other' },
+                { metadata: 'dc.identifier.ismn', label: 'ISMN' },
+                { metadata: 'dc.identifier.govdoc', label: 'Gov\'t Doc #' },
+                { metadata: 'dc.identifier.uri', label: 'URI' },
+                { metadata: 'dc.identifier.isbn', label: 'ISBN' },
+                { metadata: 'dc.identifier.doi', label: 'DOI' },
+                { metadata: 'dc.identifier.pmid', label: 'PubMed ID' },
+                { metadata: 'dc.identifier.arxiv', label: 'arXiv' }
               ]
             }, {
-              input: {type: 'onebox'},
+              input: { type: 'onebox' },
               label: 'Publisher',
               mandatory: 'false',
               repeatable: false,
@@ -356,7 +356,7 @@ describe('FormBuilderService test suite', () => {
         {
           fields: [
             {
-              input: {type: 'onebox'},
+              input: { type: 'onebox' },
               label: 'Conference',
               mandatory: 'false',
               repeatable: false,
@@ -373,10 +373,14 @@ describe('FormBuilderService test suite', () => {
           ]
         } as FormRowModel
       ],
-      self: 'testFormConfiguration.url',
+      self: {
+        href: 'testFormConfiguration.url'
+      },
       type: 'submissionform',
       _links: {
-        self: 'testFormConfiguration.url'
+        self: {
+          href: 'testFormConfiguration.url'
+        }
       }
     } as any;
   });
diff --git a/src/app/shared/form/builder/models/form-field-previous-value-object.ts b/src/app/shared/form/builder/models/form-field-previous-value-object.ts
index f0ead99f91048083edb6edcc708fbf1ff51a9dd9..ca4a47c089d2282ae7fa89f5ebc15e5700db88f1 100644
--- a/src/app/shared/form/builder/models/form-field-previous-value-object.ts
+++ b/src/app/shared/form/builder/models/form-field-previous-value-object.ts
@@ -14,7 +14,7 @@ export class FormFieldPreviousValueObject {
     return this._path;
   }
 
-  set path(path: any[]) {
+  set path(path: string | string[]) {
     this._path = path;
   }
 
diff --git a/src/app/shared/form/builder/parsers/field-parser.ts b/src/app/shared/form/builder/parsers/field-parser.ts
index f7bf12353c673a54fd2bbcff344daaaf07dac442..f218d442e1ba9f50014284e2a7dd5ec3fe33cbe4 100644
--- a/src/app/shared/form/builder/parsers/field-parser.ts
+++ b/src/app/shared/form/builder/parsers/field-parser.ts
@@ -49,7 +49,7 @@ export abstract class FieldParser {
         label: this.configData.label,
         initialCount: this.getInitArrayIndex(),
         notRepeatable: !this.configData.repeatable,
-        required: isNotEmpty(this.configData.mandatory),
+        required: JSON.parse( this.configData.mandatory),
         groupFactory: () => {
           let model;
           if ((arrayCounter === 0)) {
diff --git a/src/app/shared/form/form.component.spec.ts b/src/app/shared/form/form.component.spec.ts
index 3342db37ae1c3c3dde464d69b78c2ffae0ab7d1e..f0617c5c0ac6760c9362d2448fc672540f947cd5 100644
--- a/src/app/shared/form/form.component.spec.ts
+++ b/src/app/shared/form/form.component.spec.ts
@@ -142,7 +142,7 @@ describe('FormComponent test suite', () => {
         CommonModule,
         FormsModule,
         ReactiveFormsModule,
-        NgbModule.forRoot(),
+        NgbModule,
         StoreModule.forRoot({}),
         TranslateModule.forRoot()
       ],
diff --git a/src/app/shared/input-suggestions/input-suggestions.component.ts b/src/app/shared/input-suggestions/input-suggestions.component.ts
index 7f8d0741ded667b304f4e4be6693733349f10e0f..ad052672c81f509721c70c4b5a3738aa9e94e9e1 100644
--- a/src/app/shared/input-suggestions/input-suggestions.component.ts
+++ b/src/app/shared/input-suggestions/input-suggestions.component.ts
@@ -92,7 +92,7 @@ export class InputSuggestionsComponent implements ControlValueAccessor, OnChange
   /**
    * Reference to the input field component
    */
-  @ViewChild('inputField') queryInput: ElementRef;
+  @ViewChild('inputField', {static: false}) queryInput: ElementRef;
   /**
    * Reference to the suggestion components
    */
diff --git a/src/app/shared/loading/loading.component.scss b/src/app/shared/loading/loading.component.scss
index c9ccb5b2fab3eb9b4d41213d3c3dee0c32331070..e2287cdc8b682ad0eb8920e2bab647cc17b22b57 100644
--- a/src/app/shared/loading/loading.component.scss
+++ b/src/app/shared/loading/loading.component.scss
@@ -58,10 +58,10 @@ span.l-10 {-webkit-animation-delay: 0s;animation-delay: 0s;-ms-animation-delay:
 	100% {opacity: 0;}
 }
 
-@-keyframes loader {
-	0% {-transform: translateX(-30px); opacity: 0;}
+@keyframes loader {
+	0% {transform: translateX(-30px); opacity: 0;}
 	25% {opacity: 1;}
-	50% {-transform: translateX(30px); opacity: 0;}
+	50% {transform: translateX(30px); opacity: 0;}
 	100% {opacity: 0;}
 }
 
@@ -70,4 +70,4 @@ span.l-10 {-webkit-animation-delay: 0s;animation-delay: 0s;-ms-animation-delay:
 	25% {opacity: 1;}
 	50% {-ms-transform: translateX(30px); opacity: 0;}
 	100% {opacity: 0;}
-}
\ No newline at end of file
+}
diff --git a/src/app/shared/menu/menu.actions.ts b/src/app/shared/menu/menu.actions.ts
index 0c1533ed3b0411c2de34a5431f1bb5c3d9dba507..00275441d63d09189cf47f1524805cc9b3ae61cd 100644
--- a/src/app/shared/menu/menu.actions.ts
+++ b/src/app/shared/menu/menu.actions.ts
@@ -223,4 +223,6 @@ export type MenuAction =
   | ActivateMenuSectionAction
   | DeactivateMenuSectionAction
   | ToggleActiveMenuSectionAction
+  | CollapseMenuPreviewAction
+  | ExpandMenuPreviewAction
 /* tslint:enable:max-classes-per-file */
diff --git a/src/app/shared/metadata-representation/metadata-representation-loader.component.ts b/src/app/shared/metadata-representation/metadata-representation-loader.component.ts
index eb385b5afde2dfc3695707a4877a6347bd15d502..86bede67896991d94bc89f64e85b28b62329b410 100644
--- a/src/app/shared/metadata-representation/metadata-representation-loader.component.ts
+++ b/src/app/shared/metadata-representation/metadata-representation-loader.component.ts
@@ -28,7 +28,7 @@ export class MetadataRepresentationLoaderComponent implements OnInit {
   /**
    * Directive to determine where the dynamic child component is located
    */
-  @ViewChild(MetadataRepresentationDirective) mdRepDirective: MetadataRepresentationDirective;
+  @ViewChild(MetadataRepresentationDirective, {static: true}) mdRepDirective: MetadataRepresentationDirective;
 
   constructor(private componentFactoryResolver: ComponentFactoryResolver) {
   }
diff --git a/src/app/shared/mocks/mock-item.ts b/src/app/shared/mocks/mock-item.ts
index 3b77b630c51fed48318a9bcdd66a9304dc753e2a..a5b6a45d4a08150422b2ce54ffd5dcdda1d4f04d 100644
--- a/src/app/shared/mocks/mock-item.ts
+++ b/src/app/shared/mocks/mock-item.ts
@@ -1,11 +1,86 @@
-import {of as observableOf,  Observable } from 'rxjs';
+import { of as observableOf } from 'rxjs';
+import { BitstreamFormat } from '../../core/shared/bitstream-format.model';
+import { Bitstream } from '../../core/shared/bitstream.model';
 
 import { Item } from '../../core/shared/item.model';
-import { RemoteData } from '../../core/data/remote-data';
-import { Bitstream } from '../../core/shared/bitstream.model';
-import { PaginatedList } from '../../core/data/paginated-list';
 import { createPaginatedList, createSuccessfulRemoteDataObject$ } from '../testing/utils';
 
+export const MockBitstreamFormat1: BitstreamFormat = Object.assign(new BitstreamFormat(), {
+  shortDescription: 'Microsoft Word XML',
+    description: 'Microsoft Word XML',
+    mimetype: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
+    supportLevel: 0,
+    internal: false,
+    extensions: null,
+    _links:{
+    self: {
+      href: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreamformats/10'
+    }
+    }
+});
+
+export const MockBitstreamFormat2: BitstreamFormat = Object.assign(new BitstreamFormat(), {
+    shortDescription: 'Adobe PDF',
+    description: 'Adobe Portable Document Format',
+    mimetype: 'application/pdf',
+    supportLevel: 0,
+    internal: false,
+    extensions: null,
+    _links:{
+      self: {
+        href: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreamformats/4'
+      }
+    }
+});
+
+export const MockBitstream1: Bitstream = Object.assign(new Bitstream(),
+  {
+    sizeBytes: 10201,
+    content: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreams/cf9b0c8e-a1eb-4b65-afd0-567366448713/content',
+    format: observableOf(MockBitstreamFormat1),
+    bundleName: 'ORIGINAL',
+    _links:{
+      self: {
+        href: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreams/cf9b0c8e-a1eb-4b65-afd0-567366448713'
+      }
+    },
+    id: 'cf9b0c8e-a1eb-4b65-afd0-567366448713',
+    uuid: 'cf9b0c8e-a1eb-4b65-afd0-567366448713',
+    type: 'bitstream',
+    metadata: {
+      'dc.title': [
+        {
+          language: null,
+          value: 'test_word.docx'
+        }
+      ]
+    }
+  });
+
+export const MockBitstream2: Bitstream = Object.assign(new Bitstream(), {
+  sizeBytes: 31302,
+  content: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreams/99b00f3c-1cc6-4689-8158-91965bee6b28/content',
+  format: observableOf(MockBitstreamFormat2),
+  bundleName: 'ORIGINAL',
+  id: '99b00f3c-1cc6-4689-8158-91965bee6b28',
+  uuid: '99b00f3c-1cc6-4689-8158-91965bee6b28',
+  type: 'bitstream',
+  _links: {
+    self: { href: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreams/99b00f3c-1cc6-4689-8158-91965bee6b28' },
+    content: { href: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreams/99b00f3c-1cc6-4689-8158-91965bee6b28/content' },
+    format: { href: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreamformats/4' },
+    bundle: { href: '' }
+  },
+  metadata: {
+    'dc.title': [
+      {
+        language: null,
+        value: 'test_pdf.pdf'
+      }
+    ]
+  }
+});
+
 /* tslint:disable:no-shadowed-variable */
 export const MockItem: Item = Object.assign(new Item(), {
   handle: '10673/6',
@@ -17,7 +92,11 @@ export const MockItem: Item = Object.assign(new Item(), {
     {
       name: 'ORIGINAL',
       bitstreams: observableOf(Object.assign({
-        self: 'dspace-angular://aggregated/object/1507836003548',
+        _links: {
+          self: {
+            href: 'dspace-angular://aggregated/object/1507836003548',
+          }
+        },
         requestPending: false,
         responsePending: false,
         isSuccessful: true,
@@ -39,82 +118,18 @@ export const MockItem: Item = Object.assign(new Item(), {
             currentPage: 2
           },
           page: [
-            {
-              sizeBytes: 10201,
-              content: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreams/cf9b0c8e-a1eb-4b65-afd0-567366448713/content',
-              format: observableOf({
-                self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreamformats/10',
-                requestPending: false,
-                responsePending: false,
-                isSuccessful: true,
-                errorMessage: '',
-                statusCode: '202',
-                pageInfo: {},
-                payload: {
-                  shortDescription: 'Microsoft Word XML',
-                  description: 'Microsoft Word XML',
-                  mimetype: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
-                  supportLevel: 0,
-                  internal: false,
-                  extensions: null,
-                  self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreamformats/10'
-                }
-              }),
-              bundleName: 'ORIGINAL',
-              self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreams/cf9b0c8e-a1eb-4b65-afd0-567366448713',
-              id: 'cf9b0c8e-a1eb-4b65-afd0-567366448713',
-              uuid: 'cf9b0c8e-a1eb-4b65-afd0-567366448713',
-              type: 'bitstream',
-              metadata: {
-                'dc.title': [
-                  {
-                    language: null,
-                    value: 'test_word.docx'
-                  }
-                ]
-              }
-            },
-            {
-              sizeBytes: 31302,
-              content: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreams/99b00f3c-1cc6-4689-8158-91965bee6b28/content',
-              format: observableOf({
-                self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreamformats/4',
-                requestPending: false,
-                responsePending: false,
-                isSuccessful: true,
-                errorMessage: '',
-                statusCode: '202',
-                pageInfo: {},
-                payload: {
-                  shortDescription: 'Adobe PDF',
-                  description: 'Adobe Portable Document Format',
-                  mimetype: 'application/pdf',
-                  supportLevel: 0,
-                  internal: false,
-                  extensions: null,
-                  self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreamformats/4'
-                }
-              }),
-              bundleName: 'ORIGINAL',
-              self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreams/99b00f3c-1cc6-4689-8158-91965bee6b28',
-              id: '99b00f3c-1cc6-4689-8158-91965bee6b28',
-              uuid: '99b00f3c-1cc6-4689-8158-91965bee6b28',
-              type: 'bitstream',
-              metadata: {
-                'dc.title': [
-                  {
-                    language: null,
-                    value: 'test_pdf.pdf'
-                  }
-                ]
-              }
-            }
+            MockBitstream1,
+            MockBitstream2
           ]
         }
       }))
     }
   ])),
-  self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/items/0ec7ff22-f211-40ab-a69e-c819b0b1f357',
+  _links:{
+    self: {
+      href: 'https://dspace7.4science.it/dspace-spring-rest/api/core/items/0ec7ff22-f211-40ab-a69e-c819b0b1f357'
+    }
+  },
   id: '0ec7ff22-f211-40ab-a69e-c819b0b1f357',
   uuid: '0ec7ff22-f211-40ab-a69e-c819b0b1f357',
   type: 'item',
@@ -219,7 +234,11 @@ export const MockItem: Item = Object.assign(new Item(), {
     ]
   },
   owningCollection: observableOf({
-      self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/collections/1c11f3f1-ba1f-4f36-908a-3f1ea9a557eb',
+      _links: {
+        self: {
+          href: 'https://dspace7.4science.it/dspace-spring-rest/api/core/collections/1c11f3f1-ba1f-4f36-908a-3f1ea9a557eb'
+        }
+      },
       requestPending: false,
       responsePending: false,
       isSuccessful: true,
@@ -228,5 +247,6 @@ export const MockItem: Item = Object.assign(new Item(), {
       pageInfo: {},
       payload: []
     }
-  )});
+  )
+});
 /* tslint:enable:no-shadowed-variable */
diff --git a/src/app/shared/mocks/mock-link-service.ts b/src/app/shared/mocks/mock-link-service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d50640a6295c4405ea03253d2c0d4a48b6133268
--- /dev/null
+++ b/src/app/shared/mocks/mock-link-service.ts
@@ -0,0 +1,9 @@
+import { LinkService } from '../../core/cache/builders/link.service';
+
+export function getMockLinkService(): LinkService {
+  return jasmine.createSpyObj('linkService', {
+    resolveLinks: jasmine.createSpy('resolveLinks'),
+    resolveLink: jasmine.createSpy('resolveLink'),
+    removeResolvedLinks: jasmine.createSpy('removeResolvedLinks')
+  });
+}
diff --git a/src/app/shared/mocks/mock-remote-data-build.service.ts b/src/app/shared/mocks/mock-remote-data-build.service.ts
index 2e492daf144a338e1b5bf87509c62f4ffefa8de8..2dff033a2673b640dec6cca40e6fc62148a123e2 100644
--- a/src/app/shared/mocks/mock-remote-data-build.service.ts
+++ b/src/app/shared/mocks/mock-remote-data-build.service.ts
@@ -1,13 +1,12 @@
-import { Observable, of as observableOf } from 'rxjs';
+import { Observable } from 'rxjs';
 import { map } from 'rxjs/operators';
 import { RemoteDataBuildService } from '../../core/cache/builders/remote-data-build.service';
+import { PaginatedList } from '../../core/data/paginated-list';
 import { RemoteData } from '../../core/data/remote-data';
 import { RequestEntry } from '../../core/data/request.reducer';
+import { PageInfo } from '../../core/shared/page-info.model';
 import { hasValue } from '../empty.util';
-import { NormalizedObject } from '../../core/cache/models/normalized-object.model';
 import { createSuccessfulRemoteDataObject$ } from '../testing/utils';
-import { PaginatedList } from '../../core/data/paginated-list';
-import { PageInfo } from '../../core/shared/page-info.model';
 
 export function getMockRemoteDataBuildService(toRemoteDataObservable$?: Observable<RemoteData<any>>, buildList$?: Observable<RemoteData<PaginatedList<any>>>): RemoteDataBuildService {
   return {
@@ -22,7 +21,6 @@ export function getMockRemoteDataBuildService(toRemoteDataObservable$?: Observab
       }
     },
     buildSingle: (href$: string | Observable<string>) => createSuccessfulRemoteDataObject$({}),
-    build: (normalized: NormalizedObject<any>) => Object.create({}),
     buildList: (href$: string | Observable<string>) => {
       if (hasValue(buildList$)) {
         return buildList$;
@@ -33,3 +31,38 @@ export function getMockRemoteDataBuildService(toRemoteDataObservable$?: Observab
   } as RemoteDataBuildService;
 
 }
+
+export function getMockRemoteDataBuildServiceHrefMap(toRemoteDataObservable$?: Observable<RemoteData<any>>, buildListHrefMap$?: { [href: string]: Observable<RemoteData<PaginatedList<any>>>; }): RemoteDataBuildService {
+  return {
+    toRemoteDataObservable: (requestEntry$: Observable<RequestEntry>, payload$: Observable<any>) => {
+
+      if (hasValue(toRemoteDataObservable$)) {
+        return toRemoteDataObservable$;
+      } else {
+        return payload$.pipe(map((payload) => ({
+          payload
+        } as RemoteData<any>)))
+      }
+    },
+    buildSingle: (href$: string | Observable<string>) => createSuccessfulRemoteDataObject$({}),
+    buildList: (href$: string | Observable<string>) => {
+      if (typeof href$ === 'string') {
+        if (hasValue(buildListHrefMap$[href$])) {
+          return buildListHrefMap$[href$];
+        } else {
+          return createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), []))
+        }
+      }
+      href$.pipe(
+        map((href: string) => {
+          if (hasValue(buildListHrefMap$[href])) {
+            return buildListHrefMap$[href];
+          } else {
+            return createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), []))
+          }
+        })
+      );
+    }
+  } as RemoteDataBuildService;
+
+}
diff --git a/src/app/shared/mocks/mock-submission.ts b/src/app/shared/mocks/mock-submission.ts
index a97d2fb31a342ed9e51cf7a01c2ff108af48e5fe..082eec4c711417b70dc08ec62fd067931fb782e4 100644
--- a/src/app/shared/mocks/mock-submission.ts
+++ b/src/app/shared/mocks/mock-submission.ts
@@ -1,15 +1,16 @@
-import { SubmissionObjectState } from '../../submission/objects/submission-objects.reducer';
 import { SubmissionDefinitionsModel } from '../../core/config/models/config-submission-definitions.model';
 import { PaginatedList } from '../../core/data/paginated-list';
+import { Group } from '../../core/eperson/models/group.model';
 import { PageInfo } from '../../core/shared/page-info.model';
+import { SubmissionObjectState } from '../../submission/objects/submission-objects.reducer';
 import { FormFieldMetadataValueObject } from '../form/builder/models/form-field-metadata-value.model';
-import { Group } from '../../core/eperson/models/group.model';
 
 export const mockSectionsData = {
-  traditionalpageone:{
+  traditionalpageone: {
     'dc.title': [
-      new FormFieldMetadataValueObject('test', null, null, 'test' )
-    ]},
+      new FormFieldMetadataValueObject('test', null, null, 'test')
+    ]
+  },
   license: {
     url: null,
     acceptanceDate: null,
@@ -21,14 +22,16 @@ export const mockSectionsData = {
 };
 
 export const mockSectionsDataTwo = {
-  traditionalpageone:{
+  traditionalpageone: {
     'dc.title': [
-      new FormFieldMetadataValueObject('test', null, null, 'test' )
-    ]},
-  traditionalpagetwo:{
+      new FormFieldMetadataValueObject('test', null, null, 'test')
+    ]
+  },
+  traditionalpagetwo: {
     'dc.relation': [
-      new FormFieldMetadataValueObject('test', null, null, 'test' )
-    ]},
+      new FormFieldMetadataValueObject('test', null, null, 'test')
+    ]
+  },
   license: {
     url: null,
     acceptanceDate: null,
@@ -68,14 +71,14 @@ export const mockUploadResponse1Errors = {
   ]
 };
 
-export const mockUploadResponse1ParsedErrors: any =  {
+export const mockUploadResponse1ParsedErrors: any = {
   traditionalpageone: [
     { path: '/sections/traditionalpageone/dc.title', message: 'error.validation.required' },
     { path: '/sections/traditionalpageone/dc.date.issued', message: 'error.validation.required' }
   ]
 };
 
-export const mockLicenseParsedErrors: any =  {
+export const mockLicenseParsedErrors: any = {
   license: [
     { path: '/sections/license', message: 'error.validation.license.notgranted' }
   ]
@@ -124,20 +127,18 @@ export const mockSubmissionRestResponse = [
             content: 'https://rest.api/dspace-spring-rest/api/core/bitstreams/3f859425-ffbd-4b0e-bf91-bfeb458a7425/content',
             format: [],
             bundleName: null,
-            self: 'https://rest.api/dspace-spring-rest/api/core/bitstreams/3f859425-ffbd-4b0e-bf91-bfeb458a7425',
             id: '3f859425-ffbd-4b0e-bf91-bfeb458a7425',
             uuid: '3f859425-ffbd-4b0e-bf91-bfeb458a7425',
             type: 'bitstream',
             name: null,
             metadata: [],
             _links: {
-              content: 'https://rest.api/dspace-spring-rest/api/core/bitstreams/3f859425-ffbd-4b0e-bf91-bfeb458a7425/content',
-              format: 'https://rest.api/dspace-spring-rest/api/core/bitstreams/3f859425-ffbd-4b0e-bf91-bfeb458a7425/format',
-              self: 'https://rest.api/dspace-spring-rest/api/core/bitstreams/3f859425-ffbd-4b0e-bf91-bfeb458a7425'
+              content: { href: 'https://rest.api/dspace-spring-rest/api/core/bitstreams/3f859425-ffbd-4b0e-bf91-bfeb458a7425/content' },
+              format: { href: 'https://rest.api/dspace-spring-rest/api/core/bitstreams/3f859425-ffbd-4b0e-bf91-bfeb458a7425/format' },
+              self: { href: 'https://rest.api/dspace-spring-rest/api/core/bitstreams/3f859425-ffbd-4b0e-bf91-bfeb458a7425' }
             }
           }
         ],
-        self: 'https://rest.api/dspace-spring-rest/api/core/collections/1c11f3f1-ba1f-4f36-908a-3f1ea9a557eb',
         id: '1c11f3f1-ba1f-4f36-908a-3f1ea9a557eb',
         uuid: '1c11f3f1-ba1f-4f36-908a-3f1ea9a557eb',
         type: 'collection',
@@ -180,10 +181,10 @@ export const mockSubmissionRestResponse = [
           }
         ],
         _links: {
-          license: 'https://rest.api/dspace-spring-rest/api/core/collections/1c11f3f1-ba1f-4f36-908a-3f1ea9a557eb/license',
-          defaultAccessConditions: 'https://rest.api/dspace-spring-rest/api/core/collections/1c11f3f1-ba1f-4f36-908a-3f1ea9a557eb/defaultAccessConditions',
-          logo: 'https://rest.api/dspace-spring-rest/api/core/collections/1c11f3f1-ba1f-4f36-908a-3f1ea9a557eb/logo',
-          self: 'https://rest.api/dspace-spring-rest/api/core/collections/1c11f3f1-ba1f-4f36-908a-3f1ea9a557eb'
+          license: { href: 'https://rest.api/dspace-spring-rest/api/core/collections/1c11f3f1-ba1f-4f36-908a-3f1ea9a557eb/license' },
+          defaultAccessConditions: { href: 'https://rest.api/dspace-spring-rest/api/core/collections/1c11f3f1-ba1f-4f36-908a-3f1ea9a557eb/defaultAccessConditions' },
+          logo: { href: 'https://rest.api/dspace-spring-rest/api/core/collections/1c11f3f1-ba1f-4f36-908a-3f1ea9a557eb/logo' },
+          self: { href: 'https://rest.api/dspace-spring-rest/api/core/collections/1c11f3f1-ba1f-4f36-908a-3f1ea9a557eb' }
         }
       }
     ],
@@ -195,17 +196,16 @@ export const mockSubmissionRestResponse = [
         isDiscoverable: true,
         isWithdrawn: false,
         bitstreams: 'https://rest.api/dspace-spring-rest/api/core/items/6f344222-6980-4738-8192-b808d79af8a5/bitstreams',
-        self: 'https://rest.api/dspace-spring-rest/api/core/items/6f344222-6980-4738-8192-b808d79af8a5',
         id: '6f344222-6980-4738-8192-b808d79af8a5',
         uuid: '6f344222-6980-4738-8192-b808d79af8a5',
         type: 'item',
         name: null,
         metadata: [],
         _links: {
-          bitstreams: 'https://rest.api/dspace-spring-rest/api/core/items/6f344222-6980-4738-8192-b808d79af8a5/bitstreams',
-          owningCollection: 'https://rest.api/dspace-spring-rest/api/core/items/6f344222-6980-4738-8192-b808d79af8a5/owningCollection',
-          templateItemOf: 'https://rest.api/dspace-spring-rest/api/core/items/6f344222-6980-4738-8192-b808d79af8a5/templateItemOf',
-          self: 'https://rest.api/dspace-spring-rest/api/core/items/6f344222-6980-4738-8192-b808d79af8a5'
+          bitstreams: { href: 'https://rest.api/dspace-spring-rest/api/core/items/6f344222-6980-4738-8192-b808d79af8a5/bitstreams' },
+          owningCollection: { href: 'https://rest.api/dspace-spring-rest/api/core/items/6f344222-6980-4738-8192-b808d79af8a5/owningCollection' },
+          templateItemOf: { href: 'https://rest.api/dspace-spring-rest/api/core/items/6f344222-6980-4738-8192-b808d79af8a5/templateItemOf' },
+          self: { href: 'https://rest.api/dspace-spring-rest/api/core/items/6f344222-6980-4738-8192-b808d79af8a5' }
         }
       }
     ],
@@ -223,9 +223,9 @@ export const mockSubmissionRestResponse = [
             },
             type: 'submissionsection',
             _links: {
-              self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/extraction'
+              self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/extraction' },
+              config: ''
             },
-            self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/extraction'
           },
           {
             mandatory: true,
@@ -236,9 +236,9 @@ export const mockSubmissionRestResponse = [
             },
             type: 'submissionsection',
             _links: {
-              self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/collection'
+              self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/collection' },
+              config: ''
             },
-            self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/collection'
           },
           {
             header: 'submit.progressbar.describe.stepone',
@@ -246,10 +246,9 @@ export const mockSubmissionRestResponse = [
             sectionType: 'submission-form',
             type: 'submissionsection',
             _links: {
-              self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpageone',
-              config: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/traditionalpageone'
+              self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpageone' },
+              config: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/traditionalpageone' }
             },
-            self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpageone'
           },
           {
             header: 'submit.progressbar.describe.steptwo',
@@ -257,10 +256,9 @@ export const mockSubmissionRestResponse = [
             sectionType: 'submission-form',
             type: 'submissionsection',
             _links: {
-              self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpagetwo',
-              config: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/traditionalpagetwo'
+              self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpagetwo' },
+              config: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/traditionalpagetwo' }
             },
-            self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpagetwo'
           },
           {
             header: 'submit.progressbar.upload',
@@ -268,10 +266,9 @@ export const mockSubmissionRestResponse = [
             sectionType: 'upload',
             type: 'submissionsection',
             _links: {
-              self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/upload',
-              config: 'https://rest.api/dspace-spring-rest/api/config/submissionuploads/upload'
+              self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/upload' },
+              config: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionuploads/upload' }
             },
-            self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/upload'
           },
           {
             header: 'submit.progressbar.license',
@@ -283,31 +280,29 @@ export const mockSubmissionRestResponse = [
             },
             type: 'submissionsection',
             _links: {
-              self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/license'
+              self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/license' },
+              config: ''
             },
-            self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/license'
           }
         ],
         name: 'traditional',
         type: 'submissiondefinition',
         _links: {
-          collections: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional/collections',
-          sections: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional/sections',
-          self: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional'
+          collections: { href: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional/collections' },
+          sections: { href: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional/sections' },
+          self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional' }
         },
-        self: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional'
       }
     ],
     submitter: [],
     errors: [],
-    self: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826',
     type: 'workspaceitem',
     _links: {
-      collection: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826/collection',
-      item: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826/item',
-      submissionDefinition: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826/submissionDefinition',
-      submitter: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826/submitter',
-      self: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826'
+      collection: { href: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826/collection' },
+      item: { href: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826/item' },
+      submissionDefinition: { href: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826/submissionDefinition' },
+      submitter: { href: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826/submitter' },
+      self: { href: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826' }
     }
   }
 ];
@@ -329,10 +324,9 @@ export const mockSubmissionObject = {
           groupUUID: '11cc35e5-a11d-4b64-b5b9-0052a5d15509',
           id: 20,
           uuid: 'resource-policy-20',
-          self: 'https://rest.api/dspace-spring-rest/api/authz/resourcePolicies/20',
           type: 'resourcePolicy',
           _links: {
-            self: 'https://rest.api/dspace-spring-rest/api/authz/resourcePolicies/20'
+            self: { href: 'https://rest.api/dspace-spring-rest/api/authz/resourcePolicies/20' }
           }
         }
       ]
@@ -342,19 +336,17 @@ export const mockSubmissionObject = {
       content: 'https://rest.api/dspace-spring-rest/api/core/bitstreams/3f859425-ffbd-4b0e-bf91-bfeb458a7425/content',
       format: 'https://rest.api/dspace-spring-rest/api/core/bitstreams/3f859425-ffbd-4b0e-bf91-bfeb458a7425/format',
       bundleName: null,
-      self: 'https://rest.api/dspace-spring-rest/api/core/bitstreams/3f859425-ffbd-4b0e-bf91-bfeb458a7425',
       id: '3f859425-ffbd-4b0e-bf91-bfeb458a7425',
       uuid: '3f859425-ffbd-4b0e-bf91-bfeb458a7425',
       type: 'bitstream',
       name: null,
       metadata: [],
       _links: {
-        content: 'https://rest.api/dspace-spring-rest/api/core/bitstreams/3f859425-ffbd-4b0e-bf91-bfeb458a7425/content',
-        format: 'https://rest.api/dspace-spring-rest/api/core/bitstreams/3f859425-ffbd-4b0e-bf91-bfeb458a7425/format',
-        self: 'https://rest.api/dspace-spring-rest/api/core/bitstreams/3f859425-ffbd-4b0e-bf91-bfeb458a7425'
+        content: { href: 'https://rest.api/dspace-spring-rest/api/core/bitstreams/3f859425-ffbd-4b0e-bf91-bfeb458a7425/content' },
+        format: { href: 'https://rest.api/dspace-spring-rest/api/core/bitstreams/3f859425-ffbd-4b0e-bf91-bfeb458a7425/format' },
+        self: { href: 'https://rest.api/dspace-spring-rest/api/core/bitstreams/3f859425-ffbd-4b0e-bf91-bfeb458a7425' }
       }
     },
-    self: 'https://rest.api/dspace-spring-rest/api/core/collections/1c11f3f1-ba1f-4f36-908a-3f1ea9a557eb',
     id: '1c11f3f1-ba1f-4f36-908a-3f1ea9a557eb',
     uuid: '1c11f3f1-ba1f-4f36-908a-3f1ea9a557eb',
     type: 'collection',
@@ -397,10 +389,10 @@ export const mockSubmissionObject = {
       }
     ],
     _links: {
-      license: 'https://rest.api/dspace-spring-rest/api/core/collections/1c11f3f1-ba1f-4f36-908a-3f1ea9a557eb/license',
-      defaultAccessConditions: 'https://rest.api/dspace-spring-rest/api/core/collections/1c11f3f1-ba1f-4f36-908a-3f1ea9a557eb/defaultAccessConditions',
-      logo: 'https://rest.api/dspace-spring-rest/api/core/collections/1c11f3f1-ba1f-4f36-908a-3f1ea9a557eb/logo',
-      self: 'https://rest.api/dspace-spring-rest/api/core/collections/1c11f3f1-ba1f-4f36-908a-3f1ea9a557eb'
+      license: { href: 'https://rest.api/dspace-spring-rest/api/core/collections/1c11f3f1-ba1f-4f36-908a-3f1ea9a557eb/license' },
+      defaultAccessConditions: { href: 'https://rest.api/dspace-spring-rest/api/core/collections/1c11f3f1-ba1f-4f36-908a-3f1ea9a557eb/defaultAccessConditions' },
+      logo: { href: 'https://rest.api/dspace-spring-rest/api/core/collections/1c11f3f1-ba1f-4f36-908a-3f1ea9a557eb/logo' },
+      self: { href: 'https://rest.api/dspace-spring-rest/api/core/collections/1c11f3f1-ba1f-4f36-908a-3f1ea9a557eb' }
     }
   },
   item: {
@@ -419,17 +411,16 @@ export const mockSubmissionObject = {
       },
       page: []
     },
-    self: 'https://rest.api/dspace-spring-rest/api/core/items/cae8af78-c874-4468-af79-e6c996aa8270',
     id: 'cae8af78-c874-4468-af79-e6c996aa8270',
     uuid: 'cae8af78-c874-4468-af79-e6c996aa8270',
     type: 'item',
     name: null,
     metadata: [],
     _links: {
-      bitstreams: 'https://rest.api/dspace-spring-rest/api/core/items/cae8af78-c874-4468-af79-e6c996aa8270/bitstreams',
-      owningCollection: 'https://rest.api/dspace-spring-rest/api/core/items/cae8af78-c874-4468-af79-e6c996aa8270/owningCollection',
-      templateItemOf: 'https://rest.api/dspace-spring-rest/api/core/items/cae8af78-c874-4468-af79-e6c996aa8270/templateItemOf',
-      self: 'https://rest.api/dspace-spring-rest/api/core/items/cae8af78-c874-4468-af79-e6c996aa8270'
+      bitstreams: { href: 'https://rest.api/dspace-spring-rest/api/core/items/cae8af78-c874-4468-af79-e6c996aa8270/bitstreams' },
+      owningCollection: { href: 'https://rest.api/dspace-spring-rest/api/core/items/cae8af78-c874-4468-af79-e6c996aa8270/owningCollection' },
+      templateItemOf: { href: 'https://rest.api/dspace-spring-rest/api/core/items/cae8af78-c874-4468-af79-e6c996aa8270/templateItemOf' },
+      self: { href: 'https://rest.api/dspace-spring-rest/api/core/items/cae8af78-c874-4468-af79-e6c996aa8270' }
     }
   },
   submissionDefinition: {
@@ -451,9 +442,9 @@ export const mockSubmissionObject = {
           },
           type: 'submissionsection',
           _links: {
-            self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/collection'
+            self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/collection' },
+            config: ''
           },
-          self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/collection'
         },
         {
           header: 'submit.progressbar.describe.stepone',
@@ -461,10 +452,9 @@ export const mockSubmissionObject = {
           sectionType: 'submission-form',
           type: 'submissionsection',
           _links: {
-            self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpageone',
-            config: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/traditionalpageone'
+            self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpageone' },
+            config: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/traditionalpageone' }
           },
-          self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpageone'
         },
         {
           header: 'submit.progressbar.describe.steptwo',
@@ -472,10 +462,9 @@ export const mockSubmissionObject = {
           sectionType: 'submission-form',
           type: 'submissionsection',
           _links: {
-            self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpagetwo',
-            config: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/traditionalpagetwo'
+            self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpagetwo' },
+            config: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/traditionalpagetwo' }
           },
-          self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpagetwo'
         },
         {
           header: 'submit.progressbar.upload',
@@ -483,10 +472,9 @@ export const mockSubmissionObject = {
           sectionType: 'upload',
           type: 'submissionsection',
           _links: {
-            self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/upload',
-            config: 'https://rest.api/dspace-spring-rest/api/config/submissionuploads/upload'
+            self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/upload' },
+            config: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionuploads/upload' }
           },
-          self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/upload'
         },
         {
           header: 'submit.progressbar.license',
@@ -498,20 +486,19 @@ export const mockSubmissionObject = {
           },
           type: 'submissionsection',
           _links: {
-            self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/license'
+            self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/license' },
+            config: ''
           },
-          self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/license'
         }
       ]
     },
     name: 'traditional',
     type: 'submissiondefinition',
     _links: {
-      collections: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional/collections',
-      sections: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional/sections',
-      self: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional'
+      collections: { href: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional/collections' },
+      sections: { href: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional/sections' },
+      self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional' }
     },
-    self: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional',
     collections: {
       pageInfo: {
         elementsPerPage: 0,
@@ -531,7 +518,6 @@ export const mockSubmissionObject = {
     email: 'dspacedemo+submit@gmail.com',
     requireCertificate: false,
     selfRegistered: false,
-    self: 'https://rest.api/dspace-spring-rest/api/eperson/epersons/99423c27-b642-5tg6-a9cd-6d910e68dca5',
     id: '99423c27-b642-5tg6-a9cd-6d910e68dca5',
     uuid: '99423c27-b642-5tg6-a9cd-6d910e68dca5',
     type: 'eperson',
@@ -549,7 +535,7 @@ export const mockSubmissionObject = {
       }
     ],
     _links: {
-      self: 'https://rest.api/dspace-spring-rest/api/eperson/epersons/99423c27-b642-5tg6-a9cd-6d910e68dca5'
+      self: { href: 'https://rest.api/dspace-spring-rest/api/eperson/epersons/99423c27-b642-5tg6-a9cd-6d910e68dca5' }
     }
   },
   id: 826,
@@ -573,14 +559,13 @@ export const mockSubmissionObject = {
       ]
     }
   ],
-  self: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826',
   type: 'workspaceitem',
   _links: {
-    collection: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826/collection',
-    item: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826/item',
-    submissionDefinition: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826/submissionDefinition',
-    submitter: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826/submitter',
-    self: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826'
+    collection: { href: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826/collection' },
+    item: { href: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826/item' },
+    submissionDefinition: { href: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826/submissionDefinition' },
+    submitter: { href: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826/submitter' },
+    self: { href: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826' }
   }
 };
 
@@ -601,10 +586,9 @@ export const mockSubmissionObjectNew = {
           groupUUID: '11cc35e5-a11d-4b64-b5b9-0052a5d15509',
           id: 20,
           uuid: 'resource-policy-20',
-          self: 'https://rest.api/dspace-spring-rest/api/authz/resourcePolicies/20',
           type: 'resourcePolicy',
           _links: {
-            self: 'https://rest.api/dspace-spring-rest/api/authz/resourcePolicies/20'
+            self: { href: 'https://rest.api/dspace-spring-rest/api/authz/resourcePolicies/20' }
           }
         }
       ]
@@ -614,19 +598,17 @@ export const mockSubmissionObjectNew = {
       content: 'https://rest.api/dspace-spring-rest/api/core/bitstreams/3f859425-ffbd-4b0e-bf91-bfeb458a7425/content',
       format: 'https://rest.api/dspace-spring-rest/api/core/bitstreams/3f859425-ffbd-4b0e-bf91-bfeb458a7425/format',
       bundleName: null,
-      self: 'https://rest.api/dspace-spring-rest/api/core/bitstreams/3f859425-ffbd-4b0e-bf91-bfeb458a7425',
       id: '3f859425-ffbd-4b0e-bf91-bfeb458a7425',
       uuid: '3f859425-ffbd-4b0e-bf91-bfeb458a7425',
       type: 'bitstream',
       name: null,
       metadata: [],
       _links: {
-        content: 'https://rest.api/dspace-spring-rest/api/core/bitstreams/3f859425-ffbd-4b0e-bf91-bfeb458a7425/content',
-        format: 'https://rest.api/dspace-spring-rest/api/core/bitstreams/3f859425-ffbd-4b0e-bf91-bfeb458a7425/format',
-        self: 'https://rest.api/dspace-spring-rest/api/core/bitstreams/3f859425-ffbd-4b0e-bf91-bfeb458a7425'
+        content: { href: 'https://rest.api/dspace-spring-rest/api/core/bitstreams/3f859425-ffbd-4b0e-bf91-bfeb458a7425/content' },
+        format: { href: 'https://rest.api/dspace-spring-rest/api/core/bitstreams/3f859425-ffbd-4b0e-bf91-bfeb458a7425/format' },
+        self: { href: 'https://rest.api/dspace-spring-rest/api/core/bitstreams/3f859425-ffbd-4b0e-bf91-bfeb458a7425' }
       }
     },
-    self: 'https://rest.api/dspace-spring-rest/api/core/collections/45f2f3f1-ba1f-4f36-908a-3f1ea9a557eb',
     id: '45f2f3f1-ba1f-4f36-908a-3f1ea9a557eb',
     uuid: '45f2f3f1-ba1f-4f36-908a-3f1ea9a557eb',
     type: 'collection',
@@ -669,10 +651,10 @@ export const mockSubmissionObjectNew = {
       }
     ],
     _links: {
-      license: 'https://rest.api/dspace-spring-rest/api/core/collections/45f2f3f1-ba1f-4f36-908a-3f1ea9a557eb/license',
-      defaultAccessConditions: 'https://rest.api/dspace-spring-rest/api/core/collections/45f2f3f1-ba1f-4f36-908a-3f1ea9a557eb/defaultAccessConditions',
-      logo: 'https://rest.api/dspace-spring-rest/api/core/collections/45f2f3f1-ba1f-4f36-908a-3f1ea9a557eb/logo',
-      self: 'https://rest.api/dspace-spring-rest/api/core/collections/45f2f3f1-ba1f-4f36-908a-3f1ea9a557eb'
+      license: { href: 'https://rest.api/dspace-spring-rest/api/core/collections/45f2f3f1-ba1f-4f36-908a-3f1ea9a557eb/license' },
+      defaultAccessConditions: { href: 'https://rest.api/dspace-spring-rest/api/core/collections/45f2f3f1-ba1f-4f36-908a-3f1ea9a557eb/defaultAccessConditions' },
+      logo: { href: 'https://rest.api/dspace-spring-rest/api/core/collections/45f2f3f1-ba1f-4f36-908a-3f1ea9a557eb/logo' },
+      self: { href: 'https://rest.api/dspace-spring-rest/api/core/collections/45f2f3f1-ba1f-4f36-908a-3f1ea9a557eb' }
     }
   },
   item: {
@@ -691,17 +673,16 @@ export const mockSubmissionObjectNew = {
       },
       page: []
     },
-    self: 'https://rest.api/dspace-spring-rest/api/core/items/cae8af78-c874-4468-af79-e6c996aa8270',
     id: 'cae8af78-c874-4468-af79-e6c996aa8270',
     uuid: 'cae8af78-c874-4468-af79-e6c996aa8270',
     type: 'item',
     name: null,
     metadata: [],
     _links: {
-      bitstreams: 'https://rest.api/dspace-spring-rest/api/core/items/cae8af78-c874-4468-af79-e6c996aa8270/bitstreams',
-      owningCollection: 'https://rest.api/dspace-spring-rest/api/core/items/cae8af78-c874-4468-af79-e6c996aa8270/owningCollection',
-      templateItemOf: 'https://rest.api/dspace-spring-rest/api/core/items/cae8af78-c874-4468-af79-e6c996aa8270/templateItemOf',
-      self: 'https://rest.api/dspace-spring-rest/api/core/items/cae8af78-c874-4468-af79-e6c996aa8270'
+      bitstreams: { href: 'https://rest.api/dspace-spring-rest/api/core/items/cae8af78-c874-4468-af79-e6c996aa8270/bitstreams' },
+      owningCollection: { href: 'https://rest.api/dspace-spring-rest/api/core/items/cae8af78-c874-4468-af79-e6c996aa8270/owningCollection' },
+      templateItemOf: { href: 'https://rest.api/dspace-spring-rest/api/core/items/cae8af78-c874-4468-af79-e6c996aa8270/templateItemOf' },
+      self: { href: 'https://rest.api/dspace-spring-rest/api/core/items/cae8af78-c874-4468-af79-e6c996aa8270' }
     }
   },
   submissionDefinition: {
@@ -723,9 +704,9 @@ export const mockSubmissionObjectNew = {
           },
           type: 'submissionsection',
           _links: {
-            self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/collection'
+            self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/collection' },
+            config: ''
           },
-          self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/collection'
         },
         {
           header: 'submit.progressbar.describe.stepone',
@@ -733,10 +714,9 @@ export const mockSubmissionObjectNew = {
           sectionType: 'submission-form',
           type: 'submissionsection',
           _links: {
-            self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpageone',
-            config: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/traditionalpageone'
+            self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpageone' },
+            config: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/traditionalpageone' }
           },
-          self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpageone'
         },
         {
           header: 'submit.progressbar.describe.steptwo',
@@ -744,10 +724,9 @@ export const mockSubmissionObjectNew = {
           sectionType: 'submission-form',
           type: 'submissionsection',
           _links: {
-            self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpagetwo',
-            config: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/traditionalpagetwo'
+            self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpagetwo' },
+            config: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/traditionalpagetwo' }
           },
-          self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpagetwo'
         },
         {
           header: 'submit.progressbar.upload',
@@ -755,10 +734,9 @@ export const mockSubmissionObjectNew = {
           sectionType: 'upload',
           type: 'submissionsection',
           _links: {
-            self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/upload',
-            config: 'https://rest.api/dspace-spring-rest/api/config/submissionuploads/upload'
+            self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/upload' },
+            config: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionuploads/upload' }
           },
-          self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/upload'
         },
         {
           header: 'submit.progressbar.license',
@@ -770,20 +748,19 @@ export const mockSubmissionObjectNew = {
           },
           type: 'submissionsection',
           _links: {
-            self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/license'
+            self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/license' },
+            config: ''
           },
-          self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/license'
         }
       ]
     },
     name: 'traditionaltwo',
     type: 'submissiondefinition',
     _links: {
-      collections: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional/collections',
-      sections: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional/sections',
-      self: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional'
+      collections: { href: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional/collections' },
+      sections: { href: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional/sections' },
+      self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional' }
     },
-    self: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional',
     collections: {
       pageInfo: {
         elementsPerPage: 0,
@@ -803,7 +780,6 @@ export const mockSubmissionObjectNew = {
     email: 'dspacedemo+submit@gmail.com',
     requireCertificate: false,
     selfRegistered: false,
-    self: 'https://rest.api/dspace-spring-rest/api/eperson/epersons/99423c27-b642-4bb9-a9cd-45gh23e68dca5',
     id: '99423c27-b642-4bb9-a9cd-45gh23e68dca5',
     uuid: '99423c27-b642-4bb9-a9cd-45gh23e68dca5',
     type: 'eperson',
@@ -821,21 +797,20 @@ export const mockSubmissionObjectNew = {
       }
     ],
     _links: {
-      self: 'https://rest.api/dspace-spring-rest/api/eperson/epersons/99423c27-b642-4bb9-a9cd-45gh23e68dca5'
+      self: { href: 'https://rest.api/dspace-spring-rest/api/eperson/epersons/99423c27-b642-4bb9-a9cd-45gh23e68dca5' }
     }
   },
   id: 826,
   lastModified: '2019-01-09T10:17:33.738+0000',
   sections: {},
   errors: [],
-  self: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826',
   type: 'workspaceitem',
   _links: {
-    collection: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826/collection',
-    item: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826/item',
-    submissionDefinition: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826/submissionDefinition',
-    submitter: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826/submitter',
-    self: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826'
+    collection: { href: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826/collection' },
+    item: { href: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826/item' },
+    submissionDefinition: { href: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826/submissionDefinition' },
+    submitter: { href: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826/submitter' },
+    self: { href: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826' }
   }
 };
 
@@ -857,9 +832,9 @@ export const mockSubmissionDefinitionResponse = {
       },
       type: 'submissionsection',
       _links: {
-        self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/extraction'
+        self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/extraction' },
+        config: ''
       },
-      self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/extraction'
     },
     {
       mandatory: true,
@@ -870,9 +845,9 @@ export const mockSubmissionDefinitionResponse = {
       },
       type: 'submissionsection',
       _links: {
-        self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/collection'
+        self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/collection' },
+        config: ''
       },
-      self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/collection'
     },
     {
       header: 'submit.progressbar.describe.stepone',
@@ -880,10 +855,9 @@ export const mockSubmissionDefinitionResponse = {
       sectionType: 'submission-form',
       type: 'submissionsection',
       _links: {
-        self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpageone',
-        config: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/traditionalpageone'
+        self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpageone' },
+        config: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/traditionalpageone' }
       },
-      self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpageone'
     },
     {
       header: 'submit.progressbar.describe.steptwo',
@@ -891,10 +865,9 @@ export const mockSubmissionDefinitionResponse = {
       sectionType: 'submission-form',
       type: 'submissionsection',
       _links: {
-        self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpagetwo',
-        config: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/traditionalpagetwo'
+        self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpagetwo' },
+        config: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/traditionalpagetwo' }
       },
-      self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpagetwo'
     },
     {
       header: 'submit.progressbar.upload',
@@ -902,10 +875,9 @@ export const mockSubmissionDefinitionResponse = {
       sectionType: 'upload',
       type: 'submissionsection',
       _links: {
-        self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/upload',
-        config: 'https://rest.api/dspace-spring-rest/api/config/submissionuploads/upload'
+        self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/upload' },
+        config: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionuploads/upload' }
       },
-      self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/upload'
     },
     {
       header: 'submit.progressbar.license',
@@ -917,24 +889,23 @@ export const mockSubmissionDefinitionResponse = {
       },
       type: 'submissionsection',
       _links: {
-        self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/license'
+        self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/license' },
+        config: ''
       },
-      self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/license'
     }
   ],
   name: 'traditional',
   type: 'submissiondefinition',
   _links: {
-    collections: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional/collections',
-    sections: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional/sections',
-    self: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional'
+    collections: { href: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional/collections' },
+    sections: { href: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional/sections' },
+    self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional' }
   },
-  self: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional'
 } as any;
 
 export const mockSubmissionDefinition: SubmissionDefinitionsModel = {
   isDefault: true,
-  sections: new PaginatedList(new PageInfo(),[
+  sections: new PaginatedList(new PageInfo(), [
     {
       mandatory: true,
       sectionType: 'utils',
@@ -944,9 +915,9 @@ export const mockSubmissionDefinition: SubmissionDefinitionsModel = {
       },
       type: 'submissionsection',
       _links: {
-        self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/extraction'
+        self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/extraction' },
+        config: ''
       },
-      self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/extraction'
     },
     {
       mandatory: true,
@@ -957,9 +928,9 @@ export const mockSubmissionDefinition: SubmissionDefinitionsModel = {
       },
       type: 'submissionsection',
       _links: {
-        self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/collection'
+        self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/collection' },
+        config: ''
       },
-      self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/collection'
     },
     {
       header: 'submit.progressbar.describe.stepone',
@@ -967,10 +938,9 @@ export const mockSubmissionDefinition: SubmissionDefinitionsModel = {
       sectionType: 'submission-form',
       type: 'submissionsection',
       _links: {
-        self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpageone',
-        config: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/traditionalpageone'
+        self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpageone' },
+        config: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/traditionalpageone' }
       },
-      self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpageone'
     },
     {
       header: 'submit.progressbar.describe.steptwo',
@@ -978,10 +948,9 @@ export const mockSubmissionDefinition: SubmissionDefinitionsModel = {
       sectionType: 'submission-form',
       type: 'submissionsection',
       _links: {
-        self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpagetwo',
-        config: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/traditionalpagetwo'
+        self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpagetwo' },
+        config: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/traditionalpagetwo' }
       },
-      self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpagetwo'
     },
     {
       header: 'submit.progressbar.upload',
@@ -989,10 +958,9 @@ export const mockSubmissionDefinition: SubmissionDefinitionsModel = {
       sectionType: 'upload',
       type: 'submissionsection',
       _links: {
-        self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/upload',
-        config: 'https://rest.api/dspace-spring-rest/api/config/submissionuploads/upload'
+        self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/upload' },
+        config: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionuploads/upload' }
       },
-      self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/upload'
     },
     {
       header: 'submit.progressbar.license',
@@ -1004,19 +972,18 @@ export const mockSubmissionDefinition: SubmissionDefinitionsModel = {
       },
       type: 'submissionsection',
       _links: {
-        self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/license'
+        self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/license' },
+        config: ''
       },
-      self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/license'
     }
   ]),
   name: 'traditional',
   type: 'submissiondefinition',
   _links: {
-    collections: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional/collections',
-    sections: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional/sections',
-    self: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional'
+    collections: { href: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional/collections' },
+    sections: { href: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional/sections' },
+    self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional' }
   },
-  self: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional'
 } as any;
 
 export const mockSubmissionState: SubmissionObjectState = Object.assign({}, {
@@ -1321,19 +1288,17 @@ export const mockUploadConfigResponse = {
     name: 'bitstream-metadata',
     type: 'submissionform',
     _links: {
-      self: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/bitstream-metadata'
+      self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/bitstream-metadata' }
     },
-    self: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/bitstream-metadata'
   },
   required: true,
   maxSize: 536870912,
   name: 'upload',
   type: 'submissionupload',
   _links: {
-    metadata: 'https://rest.api/dspace-spring-rest/api/config/submissionuploads/upload/metadata',
-    self: 'https://rest.api/dspace-spring-rest/api/config/submissionuploads/upload'
+    metadata: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionuploads/upload/metadata' },
+    self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionuploads/upload' }
   },
-  self: 'https://rest.api/dspace-spring-rest/api/config/submissionuploads/upload'
 };
 
 // Clone the object and change one property
@@ -1372,15 +1337,14 @@ export const mockAccessConditionOptions = [
 export const mockGroup = Object.assign(new Group(), {
   handle: null,
   permanent: true,
-  self: 'https://rest.api/dspace-spring-rest/api/eperson/groups/123456-g1',
   id: '123456-g',
   uuid: '123456-g',
   type: 'group',
   name: 'Anonymous',
   metadata: [],
   _links: {
-    groups: 'https://rest.api/dspace-spring-rest/api/eperson/groups/123456-g1/groups',
-    self: 'https://rest.api/dspace-spring-rest/api/eperson/groups/123456-g1'
+    groups: { href: 'https://rest.api/dspace-spring-rest/api/eperson/groups/123456-g1/groups' },
+    self: { href: 'https://rest.api/dspace-spring-rest/api/eperson/groups/123456-g1' }
   },
   groups: {
     pageInfo: {
diff --git a/src/app/shared/mydspace-actions/claimed-task/claimed-task-actions.component.html b/src/app/shared/mydspace-actions/claimed-task/claimed-task-actions.component.html
index 3a8cb0cded39dbce23408427347b530e521f8bbd..df8fb0eae7a342f1d6268753b8d350150c7037cc 100644
--- a/src/app/shared/mydspace-actions/claimed-task/claimed-task-actions.component.html
+++ b/src/app/shared/mydspace-actions/claimed-task/claimed-task-actions.component.html
@@ -2,7 +2,7 @@
   <a [class.disabled]="!(object.workflowitem | async)?.hasSucceeded"
      class="btn btn-primary mt-1 mb-3"
      ngbTooltip="{{'submission.workflow.tasks.claimed.edit_help' | translate}}"
-     [routerLink]="['/workflowitems/' + (object.workflowitem | async)?.payload.id + '/edit']"
+     [routerLink]="['/workflowitems/' + (object?.workflowitem | async)?.payload?.id + '/edit']"
      role="button">
     <i class="fa fa-edit"></i> {{'submission.workflow.tasks.claimed.edit' | translate}}
   </a>
diff --git a/src/app/shared/mydspace-actions/claimed-task/reject/claimed-task-actions-reject.component.spec.ts b/src/app/shared/mydspace-actions/claimed-task/reject/claimed-task-actions-reject.component.spec.ts
index d7e0b53748bd3ff5ce6e3dd3ccc77b54e9522c89..0e5102d53891d149ef219536eab34d2b06f26cc5 100644
--- a/src/app/shared/mydspace-actions/claimed-task/reject/claimed-task-actions-reject.component.spec.ts
+++ b/src/app/shared/mydspace-actions/claimed-task/reject/claimed-task-actions-reject.component.spec.ts
@@ -18,7 +18,7 @@ describe('ClaimedTaskActionsRejectComponent', () => {
   beforeEach(async(() => {
     TestBed.configureTestingModule({
       imports: [
-        NgbModule.forRoot(),
+        NgbModule,
         ReactiveFormsModule,
         TranslateModule.forRoot({
           loader: {
@@ -75,7 +75,7 @@ describe('ClaimedTaskActionsRejectComponent', () => {
     expect(span).toBeDefined();
   });
 
-  it('should call openRejectModal on reject button click', fakeAsync(() => {
+  it('should call openRejectModal on reject button click', () => {
     spyOn(component.rejectForm, 'reset');
     const btn = fixture.debugElement.query(By.css('.btn-danger'));
     btn.nativeElement.click();
@@ -85,9 +85,9 @@ describe('ClaimedTaskActionsRejectComponent', () => {
     expect(component.modalRef).toBeDefined();
 
     component.modalRef.close()
-  }));
+  });
 
-  it('should call confirmReject on form submit', fakeAsync(() => {
+  it('should call confirmReject on form submit', () => {
     spyOn(component.reject, 'emit');
 
     const btn = fixture.debugElement.query(By.css('.btn-danger'));
@@ -104,5 +104,5 @@ describe('ClaimedTaskActionsRejectComponent', () => {
       expect(component.reject.emit).toHaveBeenCalled();
     });
 
-  }));
+  });
 });
diff --git a/src/app/shared/mydspace-actions/workspaceitem/workspaceitem-actions.component.spec.ts b/src/app/shared/mydspace-actions/workspaceitem/workspaceitem-actions.component.spec.ts
index ac2d911a2cb0332f7ac7a9c7e771a0b72536fe32..00f5422b27d457c3cd726f797ec4821ab830e285 100644
--- a/src/app/shared/mydspace-actions/workspaceitem/workspaceitem-actions.component.spec.ts
+++ b/src/app/shared/mydspace-actions/workspaceitem/workspaceitem-actions.component.spec.ts
@@ -1,5 +1,5 @@
 import { ChangeDetectionStrategy, Injector, NO_ERRORS_SCHEMA } from '@angular/core';
-import { async, ComponentFixture, fakeAsync, TestBed } from '@angular/core/testing';
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
 import { Router } from '@angular/router';
 import { By } from '@angular/platform-browser';
 
@@ -72,7 +72,7 @@ describe('WorkspaceitemActionsComponent', () => {
 
     TestBed.configureTestingModule({
       imports: [
-        NgbModule.forRoot(),
+        NgbModule,
         TranslateModule.forRoot({
           loader: {
             provide: TranslateLoader,
@@ -128,7 +128,7 @@ describe('WorkspaceitemActionsComponent', () => {
     expect(btn).toBeDefined();
   });
 
-  it('should call confirmDiscard on discard confirmation', fakeAsync(() => {
+  it('should call confirmDiscard on discard confirmation', () => {
     mockDataService.delete.and.returnValue(observableOf(true));
     spyOn(component, 'reload');
     const btn = fixture.debugElement.query(By.css('.btn-danger'));
@@ -141,10 +141,10 @@ describe('WorkspaceitemActionsComponent', () => {
     fixture.detectChanges();
 
     fixture.whenStable().then(() => {
-      expect(mockDataService.delete).toHaveBeenCalledWith(mockObject);
+      expect(mockDataService.delete).toHaveBeenCalledWith(mockObject.id);
     });
 
-  }));
+  });
 
   it('should display a success notification on delete success', async(() => {
     spyOn((component as any).modalService, 'open').and.returnValue({result: Promise.resolve('ok')});
diff --git a/src/app/shared/mydspace-actions/workspaceitem/workspaceitem-actions.component.ts b/src/app/shared/mydspace-actions/workspaceitem/workspaceitem-actions.component.ts
index 2378c8e251f8f119a0a1dbe23267ceb160039c2a..27512d899e0d2fa4969bc433faf6672334e82122 100644
--- a/src/app/shared/mydspace-actions/workspaceitem/workspaceitem-actions.component.ts
+++ b/src/app/shared/mydspace-actions/workspaceitem/workspaceitem-actions.component.ts
@@ -1,4 +1,4 @@
-import { Component, Injector, Input, OnDestroy } from '@angular/core';
+import { Component, Injector, Input } from '@angular/core';
 import { Router } from '@angular/router';
 
 import { BehaviorSubject } from 'rxjs';
@@ -62,7 +62,7 @@ export class WorkspaceitemActionsComponent extends MyDSpaceActionsComponent<Work
       (result) => {
         if (result === 'ok') {
           this.processingDelete$.next(true);
-          this.objectDataService.delete(this.object)
+          this.objectDataService.delete(this.object.id)
             .subscribe((response: boolean) => {
               this.processingDelete$.next(false);
               this.handleActionResponse(response);
diff --git a/src/app/shared/number-picker/number-picker.component.spec.ts b/src/app/shared/number-picker/number-picker.component.spec.ts
index 3703be97df3a046de1dd0cb85206baca59184d8f..82d4329bec436704fb945a0db26027fe449a1807 100644
--- a/src/app/shared/number-picker/number-picker.component.spec.ts
+++ b/src/app/shared/number-picker/number-picker.component.spec.ts
@@ -24,7 +24,7 @@ describe('NumberPickerComponent test suite', () => {
       imports: [
         FormsModule,
         ReactiveFormsModule,
-        NgbModule.forRoot()
+        NgbModule
       ],
       declarations: [
         NumberPickerComponent,
diff --git a/src/app/shared/object-collection/shared/listable-object/listable-object-component-loader.component.ts b/src/app/shared/object-collection/shared/listable-object/listable-object-component-loader.component.ts
index 25232efa1dad0637a0b6e4e227eaef1bd9c9653d..4e6e206ddd5587363c4ee0ef738f9e573265bdfd 100644
--- a/src/app/shared/object-collection/shared/listable-object/listable-object-component-loader.component.ts
+++ b/src/app/shared/object-collection/shared/listable-object/listable-object-component-loader.component.ts
@@ -1,4 +1,4 @@
-import { Component, ComponentFactoryResolver, Input, OnInit, ViewChild } from '@angular/core';
+import { Component, ComponentFactoryResolver, ContentChild, ElementRef, Input, OnInit, ViewChild } from '@angular/core';
 import { ListableObject } from '../listable-object.model';
 import { ViewMode } from '../../../../core/shared/view-mode.model';
 import { Context } from '../../../../core/shared/context.model';
@@ -49,7 +49,7 @@ export class ListableObjectComponentLoaderComponent implements OnInit {
   /**
    * Directive hook used to place the dynamic child component
    */
-  @ViewChild(ListableObjectDirective) listableObjectDirective: ListableObjectDirective;
+  @ViewChild(ListableObjectDirective, {static: true}) listableObjectDirective: ListableObjectDirective;
 
   constructor(private componentFactoryResolver: ComponentFactoryResolver) {
   }
diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/claimed-task-search-result/claimed-task-search-result-detail-element.component.html b/src/app/shared/object-detail/my-dspace-result-detail-element/claimed-task-search-result/claimed-task-search-result-detail-element.component.html
index d4ecaaa33296ef5d648788ac8a9646aabf827cc1..a03d8c96fe5f51c05257b9796106006a0505fe65 100644
--- a/src/app/shared/object-detail/my-dspace-result-detail-element/claimed-task-search-result/claimed-task-search-result-detail-element.component.html
+++ b/src/app/shared/object-detail/my-dspace-result-detail-element/claimed-task-search-result/claimed-task-search-result-detail-element.component.html
@@ -1,8 +1,10 @@
-<ds-item-detail-preview *ngIf="workflowitem"
-                        [item]="(workflowitem.item | async)?.payload"
-                        [object]="object"
-                        [showSubmitter]="showSubmitter"
-                        [status]="status">
-</ds-item-detail-preview>
+<ng-container *ngVar="(workflowitemRD$ | async)?.payload as workflowitem">
+  <ds-item-detail-preview *ngIf="workflowitem"
+                          [item]="(workflowitem.item | async)?.payload"
+                          [object]="object"
+                          [showSubmitter]="showSubmitter"
+                          [status]="status">
+  </ds-item-detail-preview>
 
-<ds-claimed-task-actions *ngIf="workflowitem" [object]="dso"></ds-claimed-task-actions>
+  <ds-claimed-task-actions *ngIf="workflowitem" [object]="dso"></ds-claimed-task-actions>
+</ng-container>
diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/claimed-task-search-result/claimed-task-search-result-detail-element.component.spec.ts b/src/app/shared/object-detail/my-dspace-result-detail-element/claimed-task-search-result/claimed-task-search-result-detail-element.component.spec.ts
index 074ce56f92854ef9354361f4cef19b32f980d36f..bdeba1a89467497885f42cf898e7e955104cc20f 100644
--- a/src/app/shared/object-detail/my-dspace-result-detail-element/claimed-task-search-result/claimed-task-search-result-detail-element.component.spec.ts
+++ b/src/app/shared/object-detail/my-dspace-result-detail-element/claimed-task-search-result/claimed-task-search-result-detail-element.component.spec.ts
@@ -11,6 +11,9 @@ import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspa
 import { WorkflowItem } from '../../../../core/submission/models/workflowitem.model';
 import { createSuccessfulRemoteDataObject } from '../../../testing/utils';
 import { ClaimedTaskSearchResult } from '../../../object-collection/shared/claimed-task-search-result.model';
+import { VarDirective } from '../../../utils/var.directive';
+import { getMockLinkService } from '../../../mocks/mock-link-service';
+import { LinkService } from '../../../../core/cache/builders/link.service';
 
 let component: ClaimedTaskSearchResultDetailElementComponent;
 let fixture: ComponentFixture<ClaimedTaskSearchResultDetailElementComponent>;
@@ -53,12 +56,16 @@ const rdItem = createSuccessfulRemoteDataObject(item);
 const workflowitem = Object.assign(new WorkflowItem(), { item: observableOf(rdItem) });
 const rdWorkflowitem = createSuccessfulRemoteDataObject(workflowitem);
 mockResultObject.indexableObject = Object.assign(new ClaimedTask(), { workflowitem: observableOf(rdWorkflowitem) });
+const linkService = getMockLinkService();
 
 describe('ClaimedTaskSearchResultDetailElementComponent', () => {
   beforeEach(async(() => {
     TestBed.configureTestingModule({
       imports: [NoopAnimationsModule],
-      declarations: [ClaimedTaskSearchResultDetailElementComponent],
+      declarations: [ClaimedTaskSearchResultDetailElementComponent, VarDirective],
+      providers: [
+        { provide: LinkService, useValue: linkService }
+      ],
       schemas: [NO_ERRORS_SCHEMA]
     }).overrideComponent(ClaimedTaskSearchResultDetailElementComponent, {
       set: { changeDetection: ChangeDetectionStrategy.Default }
@@ -75,8 +82,12 @@ describe('ClaimedTaskSearchResultDetailElementComponent', () => {
     fixture.detectChanges();
   });
 
-  it('should init item properly', () => {
-    expect(component.workflowitem).toEqual(workflowitem);
+  it('should init workflowitem properly', (done) => {
+    component.workflowitemRD$.subscribe((workflowitemRD) => {
+      expect(linkService.resolveLink).toHaveBeenCalled();
+      expect(workflowitemRD.payload).toEqual(workflowitem);
+      done();
+    });
   });
 
   it('should have properly status', () => {
diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/claimed-task-search-result/claimed-task-search-result-detail-element.component.ts b/src/app/shared/object-detail/my-dspace-result-detail-element/claimed-task-search-result/claimed-task-search-result-detail-element.component.ts
index 72ffca4b98a4775e5cf97e745990fc46bbb2b500..f6abb444d5512eed8d913d9b103fba2af397fdcb 100644
--- a/src/app/shared/object-detail/my-dspace-result-detail-element/claimed-task-search-result/claimed-task-search-result-detail-element.component.ts
+++ b/src/app/shared/object-detail/my-dspace-result-detail-element/claimed-task-search-result/claimed-task-search-result-detail-element.component.ts
@@ -1,17 +1,17 @@
 import { Component } from '@angular/core';
 
 import { Observable } from 'rxjs';
-import { find } from 'rxjs/operators';
 
 import { RemoteData } from '../../../../core/data/remote-data';
 import { ViewMode } from '../../../../core/shared/view-mode.model';
-import { isNotUndefined } from '../../../empty.util';
 import { WorkflowItem } from '../../../../core/submission/models/workflowitem.model';
 import { ClaimedTask } from '../../../../core/tasks/models/claimed-task-object.model';
 import { SearchResultDetailElementComponent } from '../search-result-detail-element.component';
 import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type';
 import { listableObjectComponent } from '../../../object-collection/shared/listable-object/listable-object.decorator';
 import { ClaimedTaskSearchResult } from '../../../object-collection/shared/claimed-task-search-result.model';
+import { followLink } from '../../../utils/follow-link-config.model';
+import { LinkService } from '../../../../core/cache/builders/link.service';
 
 /**
  * This component renders claimed task object for the search result in the detail view.
@@ -38,25 +38,24 @@ export class ClaimedTaskSearchResultDetailElementComponent extends SearchResultD
   /**
    * The workflowitem object that belonging to the result object
    */
-  public workflowitem: WorkflowItem;
+  public workflowitemRD$: Observable<RemoteData<WorkflowItem>>;
+
+  constructor(protected linkService: LinkService) {
+    super();
+  }
 
   /**
    * Initialize all instance variables
    */
   ngOnInit() {
     super.ngOnInit();
-    this.initWorkflowItem(this.dso.workflowitem as Observable<RemoteData<WorkflowItem>>);
-  }
-
-  /**
-   * Retrieve workflow item from result object
-   */
-  initWorkflowItem(wfi$: Observable<RemoteData<WorkflowItem>>) {
-    wfi$.pipe(
-      find((rd: RemoteData<WorkflowItem>) => (rd.hasSucceeded && isNotUndefined(rd.payload)))
-    ).subscribe((rd: RemoteData<WorkflowItem>) => {
-      this.workflowitem = rd.payload;
-    });
+    this.linkService.resolveLink(this.dso, followLink(
+      'workflowitem',
+      null,
+      followLink('item', null, followLink('bundles')),
+      followLink('submitter')
+    ));
+    this.workflowitemRD$ = this.dso.workflowitem as Observable<RemoteData<WorkflowItem>>;
   }
 
 }
diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component.html b/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component.html
index ab2c24c4351ceffa05319556b9d8654adc53cdd6..cbc3f9ccfb68aabc3ce31a5ab34405d7513fb20d 100644
--- a/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component.html
+++ b/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component.html
@@ -10,9 +10,9 @@
     <div class="row mb-1">
       <div class="col-xs-12 col-md-4">
         <ds-metadata-field-wrapper>
-          <ds-thumbnail [thumbnail]="thumbnail$ | async"></ds-thumbnail>
+          <ds-thumbnail [thumbnail]="getThumbnail() | async"></ds-thumbnail>
         </ds-metadata-field-wrapper>
-        <ng-container *ngVar="(bitstreams$ | async) as bitstreams">
+        <ng-container *ngVar="(getFiles() | async) as bitstreams">
           <ds-metadata-field-wrapper [label]="('item.page.files' | translate)">
             <div *ngIf="bitstreams?.length > 0" class="file-section">
               <button class="btn btn-link" *ngFor="let file of bitstreams; let last=last;" (click)="downloadBitstreamFile(file?.uuid)">
diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component.spec.ts b/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component.spec.ts
index 84be0c1b0564a6ef43c3b5dcd3f811cbc928c420..5e3793b71b6612b53ddaea7cce5cfbd7fac13cc6 100644
--- a/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component.spec.ts
+++ b/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component.spec.ts
@@ -1,23 +1,37 @@
-import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { HttpClient } from '@angular/common/http';
 import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
 import { NoopAnimationsModule } from '@angular/platform-browser/animations';
-
-import { of as observableOf } from 'rxjs';
+import { Store } from '@ngrx/store';
 import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
 
-import { TruncatePipe } from '../../../utils/truncate.pipe';
+import { Observable, of as observableOf } from 'rxjs';
+
+import { RemoteDataBuildService } from '../../../../core/cache/builders/remote-data-build.service';
+import { ObjectCacheService } from '../../../../core/cache/object-cache.service';
+import { BitstreamDataService } from '../../../../core/data/bitstream-data.service';
+import { CommunityDataService } from '../../../../core/data/community-data.service';
+import { DefaultChangeAnalyzer } from '../../../../core/data/default-change-analyzer.service';
+import { DSOChangeAnalyzer } from '../../../../core/data/dso-change-analyzer.service';
+import { PaginatedList } from '../../../../core/data/paginated-list';
+import { RemoteData } from '../../../../core/data/remote-data';
+import { FindListOptions } from '../../../../core/data/request.models';
+import { Bitstream } from '../../../../core/shared/bitstream.model';
+import { FileService } from '../../../../core/shared/file.service';
+import { HALEndpointService } from '../../../../core/shared/hal-endpoint.service';
 import { Item } from '../../../../core/shared/item.model';
-import { ItemDetailPreviewComponent } from './item-detail-preview.component';
+import { PageInfo } from '../../../../core/shared/page-info.model';
+import { UUIDService } from '../../../../core/shared/uuid.service';
 import { MockTranslateLoader } from '../../../mocks/mock-translate-loader';
-import { ItemDetailPreviewFieldComponent } from './item-detail-preview-field/item-detail-preview-field.component';
+import { NotificationsService } from '../../../notifications/notifications.service';
+import { HALEndpointServiceStub } from '../../../testing/hal-endpoint-service-stub';
+import { createSuccessfulRemoteDataObject$ } from '../../../testing/utils';
 import { FileSizePipe } from '../../../utils/file-size-pipe';
+import { FollowLinkConfig } from '../../../utils/follow-link-config.model';
+import { TruncatePipe } from '../../../utils/truncate.pipe';
 import { VarDirective } from '../../../utils/var.directive';
-import { FileService } from '../../../../core/shared/file.service';
-import { HALEndpointService } from '../../../../core/shared/hal-endpoint.service';
-import { HALEndpointServiceStub } from '../../../testing/hal-endpoint-service-stub';
-import { RemoteData } from '../../../../core/data/remote-data';
-import { PaginatedList } from '../../../../core/data/paginated-list';
-import { PageInfo } from '../../../../core/shared/page-info.model';
+import { ItemDetailPreviewFieldComponent } from './item-detail-preview-field/item-detail-preview-field.component';
+import { ItemDetailPreviewComponent } from './item-detail-preview.component';
 
 function getMockFileService(): FileService {
   return jasmine.createSpyObj('FileService', {
@@ -60,6 +74,14 @@ const mockItem: Item = Object.assign(new Item(), {
 });
 
 describe('ItemDetailPreviewComponent', () => {
+  const mockBitstreamDataService = {
+    getThumbnailFor(item: Item): Observable<RemoteData<Bitstream>> {
+      return createSuccessfulRemoteDataObject$(new Bitstream());
+    },
+    findAllByItemAndBundleName(item: Item, bundleName: string, options?: FindListOptions, ...linksToFollow: Array<FollowLinkConfig<Bitstream>>): Observable<RemoteData<PaginatedList<Bitstream>>> {
+      return createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), []));
+    },
+  };
   beforeEach(async(() => {
     TestBed.configureTestingModule({
       imports: [
@@ -74,7 +96,18 @@ describe('ItemDetailPreviewComponent', () => {
       declarations: [ItemDetailPreviewComponent, ItemDetailPreviewFieldComponent, TruncatePipe, FileSizePipe, VarDirective],
       providers: [
         { provide: FileService, useValue: getMockFileService() },
-        { provide: HALEndpointService, useValue: new HALEndpointServiceStub('workspaceitems') }
+        { provide: HALEndpointService, useValue: new HALEndpointServiceStub('workspaceitems') },
+        { provide: ObjectCacheService, useValue: {} },
+        { provide: UUIDService, useValue: {} },
+        { provide: Store, useValue: {} },
+        { provide: RemoteDataBuildService, useValue: {} },
+        { provide: CommunityDataService, useValue: {} },
+        { provide: HALEndpointService, useValue: {} },
+        { provide: NotificationsService, useValue: {} },
+        { provide: HttpClient, useValue: {} },
+        { provide: DSOChangeAnalyzer, useValue: {} },
+        { provide: DefaultChangeAnalyzer, useValue: {} },
+        { provide: BitstreamDataService, useValue: mockBitstreamDataService },
       ],
       schemas: [NO_ERRORS_SCHEMA]
     }).overrideComponent(ItemDetailPreviewComponent, {
@@ -88,13 +121,22 @@ describe('ItemDetailPreviewComponent', () => {
     component.object = { hitHighlights: {} } as any;
     component.item = mockItem;
     component.separator = ', ';
-    spyOn(component.item, 'getFiles').and.returnValue(mockItem.bundles as any);
+    // spyOn(component.item, 'getFiles').and.returnValue(mockItem.bundles as any);
     fixture.detectChanges();
 
   }));
 
-  it('should init thumbnail and bitstreams on init', () => {
-    expect(component.thumbnail$).toBeDefined();
-    expect(component.bitstreams$).toBeDefined();
+  it('should get item thumbnail', (done) => {
+    component.getThumbnail().subscribe((thumbnail) => {
+      expect(thumbnail).toBeDefined();
+      done();
+    });
+  });
+
+  it('should get item bitstreams', (done) => {
+    component.getFiles().subscribe((bitstreams) => {
+      expect(bitstreams).toBeDefined();
+      done();
+    })
   });
 });
diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component.ts b/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component.ts
index 9a8f5ebeec796f5afc364d4678cf277b38e0d5a8..b7e67ff2ec6deff0bbf78977d0d6197fc874a37d 100644
--- a/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component.ts
+++ b/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component.ts
@@ -2,8 +2,13 @@ import { Component, Input } from '@angular/core';
 
 import { Observable } from 'rxjs';
 import { first } from 'rxjs/operators';
+import { BitstreamDataService } from '../../../../core/data/bitstream-data.service';
 
 import { Item } from '../../../../core/shared/item.model';
+import {
+  getFirstSucceededRemoteDataPayload,
+  getFirstSucceededRemoteListPayload
+} from '../../../../core/shared/operators';
 import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type';
 import { fadeInOut } from '../../../animations/fade';
 import { Bitstream } from '../../../../core/shared/bitstream.model';
@@ -62,17 +67,11 @@ export class ItemDetailPreviewComponent {
    *
    * @param {FileService} fileService
    * @param {HALEndpointService} halService
+   * @param {BitstreamDataService} bitstreamDataService
    */
   constructor(private fileService: FileService,
-              private halService: HALEndpointService) {
-  }
-
-  /**
-   * Initialize all instance variables
-   */
-  ngOnInit() {
-    this.thumbnail$ = this.item.getThumbnail();
-    this.bitstreams$ = this.item.getFiles();
+              private halService: HALEndpointService,
+              private bitstreamDataService: BitstreamDataService) {
   }
 
   /**
@@ -86,4 +85,20 @@ export class ItemDetailPreviewComponent {
         this.fileService.downloadFile(fileUrl);
       });
   }
+
+  // TODO refactor this method to return RemoteData, and the template to deal with loading and errors
+  public getThumbnail(): Observable<Bitstream> {
+    return this.bitstreamDataService.getThumbnailFor(this.item).pipe(
+      getFirstSucceededRemoteDataPayload()
+    );
+  }
+
+  // TODO refactor this method to return RemoteData, and the template to deal with loading and errors
+  public getFiles(): Observable<Bitstream[]> {
+    return this.bitstreamDataService
+      .findAllByItemAndBundleName(this.item, 'ORIGINAL', { elementsPerPage: Number.MAX_SAFE_INTEGER })
+      .pipe(
+        getFirstSucceededRemoteListPayload()
+      );
+  }
 }
diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/pool-search-result/pool-search-result-detail-element.component.html b/src/app/shared/object-detail/my-dspace-result-detail-element/pool-search-result/pool-search-result-detail-element.component.html
index 96ef68e3f87fa1bfbf37e679100663e0c0b2fda7..61c897e8d5d18b078cd15c57ecc5e6af6be2f56e 100644
--- a/src/app/shared/object-detail/my-dspace-result-detail-element/pool-search-result/pool-search-result-detail-element.component.html
+++ b/src/app/shared/object-detail/my-dspace-result-detail-element/pool-search-result/pool-search-result-detail-element.component.html
@@ -1,7 +1,9 @@
-<ds-item-detail-preview *ngIf="workflowitem"
-                        [item]="(workflowitem.item | async)?.payload"
-                        [object]="object"
-                        [showSubmitter]="showSubmitter"
-                        [status]="status"></ds-item-detail-preview>
+<ng-container *ngVar="(workflowitemRD$ | async)?.payload as workflowitem">
+  <ds-item-detail-preview *ngIf="workflowitem"
+                          [item]="(workflowitem?.item | async)?.payload"
+                          [object]="object"
+                          [showSubmitter]="showSubmitter"
+                          [status]="status"></ds-item-detail-preview>
 
-<ds-pool-task-actions *ngIf="workflowitem" [object]="dso"></ds-pool-task-actions>
+  <ds-pool-task-actions *ngIf="workflowitem" [object]="dso"></ds-pool-task-actions>
+</ng-container>
diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/pool-search-result/pool-search-result-detail-element.component.spec.ts b/src/app/shared/object-detail/my-dspace-result-detail-element/pool-search-result/pool-search-result-detail-element.component.spec.ts
index f6e48cd2a5033e230092e489882d10bf5f488adb..f60cc4441097287afc70a17ee8156d2da917927d 100644
--- a/src/app/shared/object-detail/my-dspace-result-detail-element/pool-search-result/pool-search-result-detail-element.component.spec.ts
+++ b/src/app/shared/object-detail/my-dspace-result-detail-element/pool-search-result/pool-search-result-detail-element.component.spec.ts
@@ -11,6 +11,9 @@ import { WorkflowItem } from '../../../../core/submission/models/workflowitem.mo
 import { createSuccessfulRemoteDataObject } from '../../../testing/utils';
 import { PoolSearchResultDetailElementComponent } from './pool-search-result-detail-element.component';
 import { PoolTaskSearchResult } from '../../../object-collection/shared/pool-task-search-result.model';
+import { VarDirective } from '../../../utils/var.directive';
+import { LinkService } from '../../../../core/cache/builders/link.service';
+import { getMockLinkService } from '../../../mocks/mock-link-service';
 
 let component: PoolSearchResultDetailElementComponent;
 let fixture: ComponentFixture<PoolSearchResultDetailElementComponent>;
@@ -53,15 +56,17 @@ const rdItem = createSuccessfulRemoteDataObject(item);
 const workflowitem = Object.assign(new WorkflowItem(), { item: observableOf(rdItem) });
 const rdWorkflowitem = createSuccessfulRemoteDataObject(workflowitem);
 mockResultObject.indexableObject = Object.assign(new PoolTask(), { workflowitem: observableOf(rdWorkflowitem) });
+const linkService = getMockLinkService();
 
 describe('PoolSearchResultDetailElementComponent', () => {
   beforeEach(async(() => {
     TestBed.configureTestingModule({
       imports: [NoopAnimationsModule],
-      declarations: [PoolSearchResultDetailElementComponent],
+      declarations: [PoolSearchResultDetailElementComponent, VarDirective],
       providers: [
         { provide: 'objectElementProvider', useValue: (mockResultObject) },
-        { provide: 'indexElementProvider', useValue: (compIndex) }
+        { provide: 'indexElementProvider', useValue: (compIndex) },
+        { provide: LinkService, useValue: linkService }
       ],
       schemas: [NO_ERRORS_SCHEMA]
     }).overrideComponent(PoolSearchResultDetailElementComponent, {
@@ -79,8 +84,12 @@ describe('PoolSearchResultDetailElementComponent', () => {
     fixture.detectChanges();
   });
 
-  it('should init item properly', () => {
-    expect(component.workflowitem).toEqual(workflowitem);
+  it('should init workflowitem properly', (done) => {
+    component.workflowitemRD$.subscribe((workflowitemRD) => {
+      expect(linkService.resolveLink).toHaveBeenCalled();
+      expect(workflowitemRD.payload).toEqual(workflowitem);
+      done();
+    });
   });
 
   it('should have properly status', () => {
diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/pool-search-result/pool-search-result-detail-element.component.ts b/src/app/shared/object-detail/my-dspace-result-detail-element/pool-search-result/pool-search-result-detail-element.component.ts
index 95de37271385caff2bc2ee10d99c574eda569ab0..afa4f57d78bca9708c871c050537ea6573dab2c6 100644
--- a/src/app/shared/object-detail/my-dspace-result-detail-element/pool-search-result/pool-search-result-detail-element.component.ts
+++ b/src/app/shared/object-detail/my-dspace-result-detail-element/pool-search-result/pool-search-result-detail-element.component.ts
@@ -1,9 +1,7 @@
 import { Component } from '@angular/core';
 
 import { Observable } from 'rxjs';
-import { find } from 'rxjs/operators';
 import { RemoteData } from '../../../../core/data/remote-data';
-import { isNotUndefined } from '../../../empty.util';
 import { PoolTask } from '../../../../core/tasks/models/pool-task-object.model';
 import { SearchResultDetailElementComponent } from '../search-result-detail-element.component';
 import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type';
@@ -11,6 +9,8 @@ import { WorkflowItem } from '../../../../core/submission/models/workflowitem.mo
 import { ViewMode } from '../../../../core/shared/view-mode.model';
 import { listableObjectComponent } from '../../../object-collection/shared/listable-object/listable-object.decorator';
 import { PoolTaskSearchResult } from '../../../object-collection/shared/pool-task-search-result.model';
+import { followLink } from '../../../utils/follow-link-config.model';
+import { LinkService } from '../../../../core/cache/builders/link.service';
 
 /**
  * This component renders pool task object for the search result in the detail view.
@@ -37,25 +37,24 @@ export class PoolSearchResultDetailElementComponent extends SearchResultDetailEl
   /**
    * The workflowitem object that belonging to the result object
    */
-  public workflowitem: WorkflowItem;
+  public workflowitemRD$: Observable<RemoteData<WorkflowItem>>;
+
+  constructor(protected linkService: LinkService) {
+    super();
+  }
 
   /**
    * Initialize all instance variables
    */
   ngOnInit() {
     super.ngOnInit();
-    this.initWorkflowItem(this.dso.workflowitem as Observable<RemoteData<WorkflowItem>>);
-  }
-
-  /**
-   * Retrieve workflowitem from result object
-   */
-  initWorkflowItem(wfi$: Observable<RemoteData<WorkflowItem>>) {
-    wfi$.pipe(
-      find((rd: RemoteData<WorkflowItem>) => (rd.hasSucceeded && isNotUndefined(rd.payload)))
-    ).subscribe((rd: RemoteData<WorkflowItem>) => {
-      this.workflowitem = rd.payload;
-    });
+    this.linkService.resolveLink(this.dso, followLink(
+      'workflowitem',
+      null,
+      followLink('item', null, followLink('bundles')),
+      followLink('submitter')
+    ));
+    this.workflowitemRD$ = this.dso.workflowitem as Observable<RemoteData<WorkflowItem>>;
   }
 
 }
diff --git a/src/app/shared/object-grid/grid-thumbnail/grid-thumbnail.component.spec.ts b/src/app/shared/object-grid/grid-thumbnail/grid-thumbnail.component.spec.ts
index 170ca34b42ed206a0b14fe766607264e8acbe632..719341a286fd172a9830a038e29e7f6ebabf1fa2 100644
--- a/src/app/shared/object-grid/grid-thumbnail/grid-thumbnail.component.spec.ts
+++ b/src/app/shared/object-grid/grid-thumbnail/grid-thumbnail.component.spec.ts
@@ -1,11 +1,11 @@
-import { ComponentFixture, TestBed, async } from '@angular/core/testing';
-import { By } from '@angular/platform-browser';
 import { DebugElement } from '@angular/core';
-
-import { GridThumbnailComponent } from './grid-thumbnail.component';
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { By } from '@angular/platform-browser';
 import { Bitstream } from '../../../core/shared/bitstream.model';
 import { SafeUrlPipe } from '../../utils/safe-url-pipe';
 
+import { GridThumbnailComponent } from './grid-thumbnail.component';
+
 describe('GridThumbnailComponent', () => {
   let comp: GridThumbnailComponent;
   let fixture: ComponentFixture<GridThumbnailComponent>;
@@ -26,14 +26,22 @@ describe('GridThumbnailComponent', () => {
   });
 
   it('should display image', () => {
-    comp.thumbnail = new Bitstream();
-    comp.thumbnail.content = 'test.url';
+    const thumbnail = new Bitstream();
+    thumbnail._links = {
+      self: { href: 'self.url' },
+      bundle: { href: 'bundle.url' },
+      format: { href: 'format.url' },
+      content: { href: 'content.url' },
+    };
+    comp.thumbnail = thumbnail;
     fixture.detectChanges();
     const image: HTMLElement = de.query(By.css('img')).nativeElement;
-    expect(image.getAttribute('src')).toBe(comp.thumbnail.content);
+    expect(image.getAttribute('src')).toBe(comp.thumbnail._links.content.href);
   });
 
   it('should display placeholder', () => {
+    const thumbnail = new Bitstream();
+    comp.thumbnail = thumbnail;
     fixture.detectChanges();
     const image: HTMLElement = de.query(By.css('img')).nativeElement;
     expect(image.getAttribute('src')).toBe(comp.defaultImage);
diff --git a/src/app/shared/object-grid/grid-thumbnail/grid-thumbnail.component.ts b/src/app/shared/object-grid/grid-thumbnail/grid-thumbnail.component.ts
index 6ae0c2d37eb414ff220252d4fe9d21e6c857e5e7..4622483f2f828cb2404598d123981058732247fa 100644
--- a/src/app/shared/object-grid/grid-thumbnail/grid-thumbnail.component.ts
+++ b/src/app/shared/object-grid/grid-thumbnail/grid-thumbnail.component.ts
@@ -30,8 +30,8 @@ export class GridThumbnailComponent implements OnInit {
   }
 
   ngOnInit(): void {
-    if (hasValue(this.thumbnail) && this.thumbnail.content) {
-      this.src = this.thumbnail.content;
+    if (hasValue(this.thumbnail) && hasValue(this.thumbnail._links) && this.thumbnail._links.content.href) {
+      this.src = this.thumbnail._links.content.href;
     } else {
       this.src = this.defaultImage
     }
diff --git a/src/app/shared/object-grid/search-result-grid-element/collection-search-result/collection-search-result-grid-element.component.spec.ts b/src/app/shared/object-grid/search-result-grid-element/collection-search-result/collection-search-result-grid-element.component.spec.ts
index 07f3960d556d07013b4ae00efcb19ab872dcfd3e..c14e3f6df1dcc47e742e44b2f73fbaedfef1c0d1 100644
--- a/src/app/shared/object-grid/search-result-grid-element/collection-search-result/collection-search-result-grid-element.component.spec.ts
+++ b/src/app/shared/object-grid/search-result-grid-element/collection-search-result/collection-search-result-grid-element.component.spec.ts
@@ -1,12 +1,22 @@
-import { CollectionSearchResultGridElementComponent } from './collection-search-result-grid-element.component';
-import { async, ComponentFixture, TestBed } from '@angular/core/testing';
-import { of as observableOf } from 'rxjs';
+import { HttpClient } from '@angular/common/http';
 import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
 import { By } from '@angular/platform-browser';
-import { TruncatePipe } from '../../../utils/truncate.pipe';
+import { Store } from '@ngrx/store';
+import { of as observableOf } from 'rxjs';
+import { RemoteDataBuildService } from '../../../../core/cache/builders/remote-data-build.service';
+import { ObjectCacheService } from '../../../../core/cache/object-cache.service';
+import { CommunityDataService } from '../../../../core/data/community-data.service';
+import { DefaultChangeAnalyzer } from '../../../../core/data/default-change-analyzer.service';
+import { DSOChangeAnalyzer } from '../../../../core/data/dso-change-analyzer.service';
 import { Collection } from '../../../../core/shared/collection.model';
-import { TruncatableService } from '../../../truncatable/truncatable.service';
+import { HALEndpointService } from '../../../../core/shared/hal-endpoint.service';
+import { UUIDService } from '../../../../core/shared/uuid.service';
+import { NotificationsService } from '../../../notifications/notifications.service';
 import { CollectionSearchResult } from '../../../object-collection/shared/collection-search-result.model';
+import { TruncatableService } from '../../../truncatable/truncatable.service';
+import { TruncatePipe } from '../../../utils/truncate.pipe';
+import { CollectionSearchResultGridElementComponent } from './collection-search-result-grid-element.component';
 
 let collectionSearchResultGridElementComponent: CollectionSearchResultGridElementComponent;
 let fixture: ComponentFixture<CollectionSearchResultGridElementComponent>;
@@ -47,7 +57,17 @@ describe('CollectionSearchResultGridElementComponent', () => {
       declarations: [ CollectionSearchResultGridElementComponent, TruncatePipe ],
       providers: [
         { provide: TruncatableService, useValue: truncatableServiceStub },
-        { provide: 'objectElementProvider', useValue: (mockCollectionWithAbstract) }
+        { provide: 'objectElementProvider', useValue: (mockCollectionWithAbstract) },
+        { provide: ObjectCacheService, useValue: {} },
+        { provide: UUIDService, useValue: {} },
+        { provide: Store, useValue: {} },
+        { provide: RemoteDataBuildService, useValue: {} },
+        { provide: CommunityDataService, useValue: {} },
+        { provide: HALEndpointService, useValue: {} },
+        { provide: NotificationsService, useValue: {} },
+        { provide: HttpClient, useValue: {} },
+        { provide: DSOChangeAnalyzer, useValue: {} },
+        { provide: DefaultChangeAnalyzer, useValue: {} },
       ],
 
       schemas: [ NO_ERRORS_SCHEMA ]
diff --git a/src/app/shared/object-grid/search-result-grid-element/community-search-result/community-search-result-grid-element.component.spec.ts b/src/app/shared/object-grid/search-result-grid-element/community-search-result/community-search-result-grid-element.component.spec.ts
index 567b2e1d0e045d9aa5b3b3d68e2b171b8bc088e8..0ea72b52d53dcf2140a1e7d3ca906f02439da3d6 100644
--- a/src/app/shared/object-grid/search-result-grid-element/community-search-result/community-search-result-grid-element.component.spec.ts
+++ b/src/app/shared/object-grid/search-result-grid-element/community-search-result/community-search-result-grid-element.component.spec.ts
@@ -1,12 +1,22 @@
-import { CommunitySearchResultGridElementComponent } from './community-search-result-grid-element.component';
-import { async, ComponentFixture, TestBed } from '@angular/core/testing';
-import { of as observableOf } from 'rxjs';
+import { HttpClient } from '@angular/common/http';
 import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
 import { By } from '@angular/platform-browser';
-import { TruncatePipe } from '../../../utils/truncate.pipe';
+import { Store } from '@ngrx/store';
+import { of as observableOf } from 'rxjs';
+import { RemoteDataBuildService } from '../../../../core/cache/builders/remote-data-build.service';
+import { ObjectCacheService } from '../../../../core/cache/object-cache.service';
+import { CommunityDataService } from '../../../../core/data/community-data.service';
+import { DefaultChangeAnalyzer } from '../../../../core/data/default-change-analyzer.service';
+import { DSOChangeAnalyzer } from '../../../../core/data/dso-change-analyzer.service';
 import { Community } from '../../../../core/shared/community.model';
-import { TruncatableService } from '../../../truncatable/truncatable.service';
+import { HALEndpointService } from '../../../../core/shared/hal-endpoint.service';
+import { UUIDService } from '../../../../core/shared/uuid.service';
+import { NotificationsService } from '../../../notifications/notifications.service';
 import { CommunitySearchResult } from '../../../object-collection/shared/community-search-result.model';
+import { TruncatableService } from '../../../truncatable/truncatable.service';
+import { TruncatePipe } from '../../../utils/truncate.pipe';
+import { CommunitySearchResultGridElementComponent } from './community-search-result-grid-element.component';
 
 let communitySearchResultGridElementComponent: CommunitySearchResultGridElementComponent;
 let fixture: ComponentFixture<CommunitySearchResultGridElementComponent>;
@@ -47,7 +57,17 @@ describe('CommunitySearchResultGridElementComponent', () => {
       declarations: [ CommunitySearchResultGridElementComponent, TruncatePipe ],
       providers: [
         { provide: TruncatableService, useValue: truncatableServiceStub },
-        { provide: 'objectElementProvider', useValue: (mockCommunityWithAbstract) }
+        { provide: 'objectElementProvider', useValue: (mockCommunityWithAbstract) },
+        { provide: ObjectCacheService, useValue: {} },
+        { provide: UUIDService, useValue: {} },
+        { provide: Store, useValue: {} },
+        { provide: RemoteDataBuildService, useValue: {} },
+        { provide: CommunityDataService, useValue: {} },
+        { provide: HALEndpointService, useValue: {} },
+        { provide: NotificationsService, useValue: {} },
+        { provide: HttpClient, useValue: {} },
+        { provide: DSOChangeAnalyzer, useValue: {} },
+        { provide: DefaultChangeAnalyzer, useValue: {} },
       ],
 
       schemas: [ NO_ERRORS_SCHEMA ]
diff --git a/src/app/shared/object-grid/search-result-grid-element/item-search-result/publication/publication-search-result-grid-element.component.html b/src/app/shared/object-grid/search-result-grid-element/item-search-result/publication/publication-search-result-grid-element.component.html
index a00e30cbcd5591a8cc65e3810ea9f38ed4af46e1..41c16c6eabfcb3e8b4d3512e2e6bd95c063c0f16 100644
--- a/src/app/shared/object-grid/search-result-grid-element/item-search-result/publication/publication-search-result-grid-element.component.html
+++ b/src/app/shared/object-grid/search-result-grid-element/item-search-result/publication/publication-search-result-grid-element.component.html
@@ -3,13 +3,13 @@
         <a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer" [routerLink]="['/items/' + dso.id]"
            class="card-img-top full-width">
             <div>
-                <ds-grid-thumbnail [thumbnail]="this.dso.getThumbnail() | async">
+                <ds-grid-thumbnail [thumbnail]="getThumbnail() | async">
                 </ds-grid-thumbnail>
             </div>
         </a>
         <span *ngIf="linkType == linkTypes.None" class="card-img-top full-width">
             <div>
-                <ds-grid-thumbnail [thumbnail]="dso.getThumbnail() | async">
+                <ds-grid-thumbnail [thumbnail]="getThumbnail() | async">
                 </ds-grid-thumbnail>
             </div>
         </span>
diff --git a/src/app/shared/object-grid/search-result-grid-element/item-search-result/publication/publication-search-result-grid-element.component.spec.ts b/src/app/shared/object-grid/search-result-grid-element/item-search-result/publication/publication-search-result-grid-element.component.spec.ts
index 69e50c7300b90f65a431d18118a0b1910d67b912..47531e044c810a13e1d36a0a6a76590f539c44d8 100644
--- a/src/app/shared/object-grid/search-result-grid-element/item-search-result/publication/publication-search-result-grid-element.component.spec.ts
+++ b/src/app/shared/object-grid/search-result-grid-element/item-search-result/publication/publication-search-result-grid-element.component.spec.ts
@@ -1,15 +1,29 @@
-import { async, ComponentFixture, TestBed } from '@angular/core/testing';
-import { NoopAnimationsModule } from '@angular/platform-browser/animations';
-import { TruncatePipe } from '../../../../utils/truncate.pipe';
-import { TruncatableService } from '../../../../truncatable/truncatable.service';
+import { HttpClient } from '@angular/common/http';
 import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
+import { async, TestBed } from '@angular/core/testing';
 import { By } from '@angular/platform-browser';
+import { NoopAnimationsModule } from '@angular/platform-browser/animations';
+import { Store } from '@ngrx/store';
+import { Observable } from 'rxjs/internal/Observable';
 import { of as observableOf } from 'rxjs/internal/observable/of';
-import { ItemSearchResult } from '../../../../object-collection/shared/item-search-result.model';
-import { Item } from '../../../../../core/shared/item.model';
-import { createSuccessfulRemoteDataObject$ } from '../../../../testing/utils';
+import { RemoteDataBuildService } from '../../../../../core/cache/builders/remote-data-build.service';
+import { ObjectCacheService } from '../../../../../core/cache/object-cache.service';
+import { BitstreamDataService } from '../../../../../core/data/bitstream-data.service';
+import { CommunityDataService } from '../../../../../core/data/community-data.service';
+import { DefaultChangeAnalyzer } from '../../../../../core/data/default-change-analyzer.service';
+import { DSOChangeAnalyzer } from '../../../../../core/data/dso-change-analyzer.service';
 import { PaginatedList } from '../../../../../core/data/paginated-list';
+import { RemoteData } from '../../../../../core/data/remote-data';
+import { Bitstream } from '../../../../../core/shared/bitstream.model';
+import { HALEndpointService } from '../../../../../core/shared/hal-endpoint.service';
+import { Item } from '../../../../../core/shared/item.model';
 import { PageInfo } from '../../../../../core/shared/page-info.model';
+import { UUIDService } from '../../../../../core/shared/uuid.service';
+import { NotificationsService } from '../../../../notifications/notifications.service';
+import { ItemSearchResult } from '../../../../object-collection/shared/item-search-result.model';
+import { createSuccessfulRemoteDataObject$ } from '../../../../testing/utils';
+import { TruncatableService } from '../../../../truncatable/truncatable.service';
+import { TruncatePipe } from '../../../../utils/truncate.pipe';
 import { PublicationSearchResultGridElementComponent } from './publication-search-result-grid-element.component';
 
 const mockItemWithMetadata: ItemSearchResult = new ItemSearchResult();
@@ -78,12 +92,29 @@ export function getEntityGridElementTestComponent(component, searchResultWithMet
       isCollapsed: (id: number) => observableOf(true),
     };
 
+    const mockBitstreamDataService = {
+      getThumbnailFor(item: Item): Observable<RemoteData<Bitstream>> {
+        return createSuccessfulRemoteDataObject$(new Bitstream());
+      }
+    };
+
     beforeEach(async(() => {
       TestBed.configureTestingModule({
         imports: [NoopAnimationsModule],
         declarations: [component, TruncatePipe],
         providers: [
           { provide: TruncatableService, useValue: truncatableServiceStub },
+          { provide: ObjectCacheService, useValue: {} },
+          { provide: UUIDService, useValue: {} },
+          { provide: Store, useValue: {} },
+          { provide: RemoteDataBuildService, useValue: {} },
+          { provide: CommunityDataService, useValue: {} },
+          { provide: HALEndpointService, useValue: {} },
+          { provide: HttpClient, useValue: {} },
+          { provide: DSOChangeAnalyzer, useValue: {} },
+          { provide: NotificationsService, useValue: {} },
+          { provide: DefaultChangeAnalyzer, useValue: {} },
+          { provide: BitstreamDataService, useValue: mockBitstreamDataService },
         ],
         schemas: [NO_ERRORS_SCHEMA]
       }).overrideComponent(component, {
diff --git a/src/app/shared/object-grid/search-result-grid-element/search-result-grid-element.component.scss b/src/app/shared/object-grid/search-result-grid-element/search-result-grid-element.component.scss
index dc9f9b39698756ab16e154621fb9a6156e7b31db..efc4d3c4149d6770bbb06a33e3194b898b1ca936 100644
--- a/src/app/shared/object-grid/search-result-grid-element/search-result-grid-element.component.scss
+++ b/src/app/shared/object-grid/search-result-grid-element/search-result-grid-element.component.scss
@@ -1,5 +1,5 @@
 :host {
-    /deep/ em {
+    ::ng-deep em {
         font-weight: bold;
         font-style: normal;
     }
diff --git a/src/app/shared/object-grid/search-result-grid-element/search-result-grid-element.component.ts b/src/app/shared/object-grid/search-result-grid-element/search-result-grid-element.component.ts
index 8587e91302ceaebc1e40ee9d2fdd9b1854ef5c89..dc05f78e408f491015fb17d62e05b008277d87eb 100644
--- a/src/app/shared/object-grid/search-result-grid-element/search-result-grid-element.component.ts
+++ b/src/app/shared/object-grid/search-result-grid-element/search-result-grid-element.component.ts
@@ -1,12 +1,15 @@
-import { Component, Inject, OnInit } from '@angular/core';
+import { Component, OnInit } from '@angular/core';
+import { Observable } from 'rxjs';
 
 import { SearchResult } from '../../search/search-result.model';
+import { BitstreamDataService } from '../../../core/data/bitstream-data.service';
+import { Bitstream } from '../../../core/shared/bitstream.model';
 import { DSpaceObject } from '../../../core/shared/dspace-object.model';
-import { AbstractListableElementComponent } from '../../object-collection/shared/object-collection-element/abstract-listable-element.component';
-import { TruncatableService } from '../../truncatable/truncatable.service';
-import { Observable } from 'rxjs';
 import { Metadata } from '../../../core/shared/metadata.utils';
+import { getFirstSucceededRemoteDataPayload } from '../../../core/shared/operators';
 import { hasValue } from '../../empty.util';
+import { AbstractListableElementComponent } from '../../object-collection/shared/object-collection-element/abstract-listable-element.component';
+import { TruncatableService } from '../../truncatable/truncatable.service';
 
 @Component({
   selector: 'ds-search-result-grid-element',
@@ -24,7 +27,10 @@ export class SearchResultGridElementComponent<T extends SearchResult<K>, K exten
    */
   isCollapsed$: Observable<boolean>;
 
-  public constructor(protected truncatableService: TruncatableService) {
+  public constructor(
+    protected truncatableService: TruncatableService,
+    protected bitstreamDataService: BitstreamDataService
+  ) {
     super();
     if (hasValue(this.object)) {
       this.isCollapsed$ = this.isCollapsed();
@@ -63,4 +69,11 @@ export class SearchResultGridElementComponent<T extends SearchResult<K>, K exten
   private isCollapsed(): Observable<boolean> {
     return this.truncatableService.isCollapsed(this.dso.id);
   }
+
+  // TODO refactor to return RemoteData, and thumbnail template to deal with loading
+  getThumbnail(): Observable<Bitstream> {
+    return this.bitstreamDataService.getThumbnailFor(this.dso as any).pipe(
+      getFirstSucceededRemoteDataPayload()
+    );
+  }
 }
diff --git a/src/app/shared/object-list/my-dspace-result-list-element/claimed-search-result/claimed-search-result-list-element.component.html b/src/app/shared/object-list/my-dspace-result-list-element/claimed-search-result/claimed-search-result-list-element.component.html
index 5ec4c9a5b5f6ff20ffbd6bc25cd1a58c1d25df7e..b35a4f87411c71b735fab393eb32bc64ecb936de 100644
--- a/src/app/shared/object-list/my-dspace-result-list-element/claimed-search-result/claimed-search-result-list-element.component.html
+++ b/src/app/shared/object-list/my-dspace-result-list-element/claimed-search-result/claimed-search-result-list-element.component.html
@@ -1,7 +1,10 @@
-<ds-item-list-preview *ngIf="workflowitem"
-                      [item]="(workflowitem.item | async)?.payload"
-                      [object]="object"
-                      [showSubmitter]="showSubmitter"
-                      [status]="status"></ds-item-list-preview>
+<ng-container *ngVar="(workflowitemRD$ | async)?.payload as workflowitem">
+  <ds-item-list-preview *ngIf="workflowitem"
+                        [item]="(workflowitem?.item | async)?.payload"
+                        [object]="object"
+                        [showSubmitter]="showSubmitter"
+                        [status]="status"></ds-item-list-preview>
+
+  <ds-claimed-task-actions *ngIf="workflowitem" [object]="dso"></ds-claimed-task-actions>
+</ng-container>
 
-<ds-claimed-task-actions *ngIf="workflowitem" [object]="dso"></ds-claimed-task-actions>
diff --git a/src/app/shared/object-list/my-dspace-result-list-element/claimed-search-result/claimed-search-result-list-element.component.spec.ts b/src/app/shared/object-list/my-dspace-result-list-element/claimed-search-result/claimed-search-result-list-element.component.spec.ts
index cce134f806be1da49c0bb60d62b1580f211d478b..03cc46725bac2283b0bd987ad16a3499912e5443 100644
--- a/src/app/shared/object-list/my-dspace-result-list-element/claimed-search-result/claimed-search-result-list-element.component.spec.ts
+++ b/src/app/shared/object-list/my-dspace-result-list-element/claimed-search-result/claimed-search-result-list-element.component.spec.ts
@@ -12,6 +12,9 @@ import { WorkflowItem } from '../../../../core/submission/models/workflowitem.mo
 import { createSuccessfulRemoteDataObject } from '../../../testing/utils';
 import { ClaimedTaskSearchResult } from '../../../object-collection/shared/claimed-task-search-result.model';
 import { TruncatableService } from '../../../truncatable/truncatable.service';
+import { VarDirective } from '../../../utils/var.directive';
+import { LinkService } from '../../../../core/cache/builders/link.service';
+import { getMockLinkService } from '../../../mocks/mock-link-service';
 
 let component: ClaimedSearchResultListElementComponent;
 let fixture: ComponentFixture<ClaimedSearchResultListElementComponent>;
@@ -54,14 +57,16 @@ const rdItem = createSuccessfulRemoteDataObject(item);
 const workflowitem = Object.assign(new WorkflowItem(), { item: observableOf(rdItem) });
 const rdWorkflowitem = createSuccessfulRemoteDataObject(workflowitem);
 mockResultObject.indexableObject = Object.assign(new ClaimedTask(), { workflowitem: observableOf(rdWorkflowitem) });
+const linkService = getMockLinkService();
 
 describe('ClaimedSearchResultListElementComponent', () => {
   beforeEach(async(() => {
     TestBed.configureTestingModule({
       imports: [NoopAnimationsModule],
-      declarations: [ClaimedSearchResultListElementComponent],
+      declarations: [ClaimedSearchResultListElementComponent, VarDirective],
       providers: [
         { provide: TruncatableService, useValue: {} },
+        { provide: LinkService, useValue: linkService }
       ],
       schemas: [NO_ERRORS_SCHEMA]
     }).overrideComponent(ClaimedSearchResultListElementComponent, {
@@ -79,8 +84,12 @@ describe('ClaimedSearchResultListElementComponent', () => {
     fixture.detectChanges();
   });
 
-  it('should init item properly', () => {
-    expect(component.workflowitem).toEqual(workflowitem);
+  it('should init workflowitem properly', (done) => {
+    component.workflowitemRD$.subscribe((workflowitemRD) => {
+      expect(linkService.resolveLink).toHaveBeenCalled();
+      expect(workflowitemRD.payload).toEqual(workflowitem);
+      done();
+    });
   });
 
   it('should have properly status', () => {
diff --git a/src/app/shared/object-list/my-dspace-result-list-element/claimed-search-result/claimed-search-result-list-element.component.ts b/src/app/shared/object-list/my-dspace-result-list-element/claimed-search-result/claimed-search-result-list-element.component.ts
index 35371f40aad147d02b8c719acfb06d5ce1dd53f2..1648a16d59efe1ba8f8548e9a853f1dbddefb11c 100644
--- a/src/app/shared/object-list/my-dspace-result-list-element/claimed-search-result/claimed-search-result-list-element.component.ts
+++ b/src/app/shared/object-list/my-dspace-result-list-element/claimed-search-result/claimed-search-result-list-element.component.ts
@@ -2,17 +2,18 @@ import { Component } from '@angular/core';
 import { Location, LocationStrategy, PathLocationStrategy } from '@angular/common';
 
 import { Observable } from 'rxjs';
-import { find } from 'rxjs/operators';
 
 import { ViewMode } from '../../../../core/shared/view-mode.model';
 import { RemoteData } from '../../../../core/data/remote-data';
-import { isNotUndefined } from '../../../empty.util';
 import { WorkflowItem } from '../../../../core/submission/models/workflowitem.model';
 import { ClaimedTask } from '../../../../core/tasks/models/claimed-task-object.model';
 import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type';
 import { listableObjectComponent } from '../../../object-collection/shared/listable-object/listable-object.decorator';
 import { ClaimedTaskSearchResult } from '../../../object-collection/shared/claimed-task-search-result.model';
 import { SearchResultListElementComponent } from '../../search-result-list-element/search-result-list-element.component';
+import { followLink } from '../../../utils/follow-link-config.model';
+import { LinkService } from '../../../../core/cache/builders/link.service';
+import { TruncatableService } from '../../../truncatable/truncatable.service';
 
 /**
  * This component renders claimed task object for the search result in the list view.
@@ -40,24 +41,26 @@ export class ClaimedSearchResultListElementComponent extends SearchResultListEle
   /**
    * The workflowitem object that belonging to the result object
    */
-  public workflowitem: WorkflowItem;
+  public workflowitemRD$: Observable<RemoteData<WorkflowItem>>;
+
+  constructor(
+    protected linkService: LinkService,
+    protected truncatableService: TruncatableService
+  ) {
+    super(truncatableService);
+  }
 
   /**
    * Initialize all instance variables
    */
   ngOnInit() {
     super.ngOnInit();
-    this.initWorkflowItem(this.dso.workflowitem as Observable<RemoteData<WorkflowItem>>);
-  }
-
-  /**
-   * Retrieve workflowitem from result object
-   */
-  initWorkflowItem(wfi$: Observable<RemoteData<WorkflowItem>>) {
-    wfi$.pipe(
-      find((rd: RemoteData<WorkflowItem>) => (rd.hasSucceeded && isNotUndefined(rd.payload)))
-    ).subscribe((rd: RemoteData<WorkflowItem>) => {
-      this.workflowitem = rd.payload;
-    });
+    this.linkService.resolveLink(this.dso, followLink(
+      'workflowitem',
+      null,
+      followLink('item'),
+      followLink('submitter')
+    ));
+    this.workflowitemRD$ = this.dso.workflowitem as Observable<RemoteData<WorkflowItem>>;
   }
 }
diff --git a/src/app/shared/object-list/my-dspace-result-list-element/pool-search-result/pool-search-result-list-element.component.html b/src/app/shared/object-list/my-dspace-result-list-element/pool-search-result/pool-search-result-list-element.component.html
index 5f0f1bb6d4845cc932afdb9427cd047c79efa4a3..9358e35bed18fa996596affe65045c5f84173d74 100644
--- a/src/app/shared/object-list/my-dspace-result-list-element/pool-search-result/pool-search-result-list-element.component.html
+++ b/src/app/shared/object-list/my-dspace-result-list-element/pool-search-result/pool-search-result-list-element.component.html
@@ -1,7 +1,9 @@
-<ds-item-list-preview *ngIf="workflowitem"
-                      [item]="(workflowitem.item | async)?.payload"
-                      [object]="object"
-                      [showSubmitter]="showSubmitter"
-                      [status]="status"></ds-item-list-preview>
+<ng-container *ngVar="(workflowitemRD$ | async)?.payload as workflowitem">
+  <ds-item-list-preview *ngIf="workflowitem"
+                        [item]="(workflowitem?.item | async)?.payload"
+                        [object]="object"
+                        [showSubmitter]="showSubmitter"
+                        [status]="status"></ds-item-list-preview>
 
-<ds-pool-task-actions [object]="dso"></ds-pool-task-actions>
+  <ds-pool-task-actions *ngIf="workflowitem" [object]="dso"></ds-pool-task-actions>
+</ng-container>
diff --git a/src/app/shared/object-list/my-dspace-result-list-element/pool-search-result/pool-search-result-list-element.component.spec.ts b/src/app/shared/object-list/my-dspace-result-list-element/pool-search-result/pool-search-result-list-element.component.spec.ts
index 119870cf9ca97c2b5f7662137ecf7c34c13e61f9..39f567bb2ecc326f7a1a328abb2817b0e4e9ec21 100644
--- a/src/app/shared/object-list/my-dspace-result-list-element/pool-search-result/pool-search-result-list-element.component.spec.ts
+++ b/src/app/shared/object-list/my-dspace-result-list-element/pool-search-result/pool-search-result-list-element.component.spec.ts
@@ -12,6 +12,9 @@ import { WorkflowItem } from '../../../../core/submission/models/workflowitem.mo
 import { createSuccessfulRemoteDataObject } from '../../../testing/utils';
 import { PoolTaskSearchResult } from '../../../object-collection/shared/pool-task-search-result.model';
 import { TruncatableService } from '../../../truncatable/truncatable.service';
+import { VarDirective } from '../../../utils/var.directive';
+import { LinkService } from '../../../../core/cache/builders/link.service';
+import { getMockLinkService } from '../../../mocks/mock-link-service';
 
 let component: PoolSearchResultListElementComponent;
 let fixture: ComponentFixture<PoolSearchResultListElementComponent>;
@@ -54,14 +57,16 @@ const rdItem = createSuccessfulRemoteDataObject(item);
 const workflowitem = Object.assign(new WorkflowItem(), { item: observableOf(rdItem) });
 const rdWorkflowitem = createSuccessfulRemoteDataObject(workflowitem);
 mockResultObject.indexableObject = Object.assign(new PoolTask(), { workflowitem: observableOf(rdWorkflowitem) });
+const linkService = getMockLinkService();
 
 describe('PoolSearchResultListElementComponent', () => {
   beforeEach(async(() => {
     TestBed.configureTestingModule({
       imports: [NoopAnimationsModule],
-      declarations: [PoolSearchResultListElementComponent],
+      declarations: [PoolSearchResultListElementComponent, VarDirective],
       providers: [
         { provide: TruncatableService, useValue: {} },
+        { provide: LinkService, useValue: linkService }
       ],
       schemas: [NO_ERRORS_SCHEMA]
     }).overrideComponent(PoolSearchResultListElementComponent, {
@@ -79,8 +84,12 @@ describe('PoolSearchResultListElementComponent', () => {
     fixture.detectChanges();
   });
 
-  it('should init item properly', () => {
-    expect(component.workflowitem).toEqual(workflowitem);
+  it('should init workflowitem properly', (done) => {
+    component.workflowitemRD$.subscribe((workflowitemRD) => {
+      expect(linkService.resolveLink).toHaveBeenCalled();
+      expect(workflowitemRD.payload).toEqual(workflowitem);
+      done();
+    });
   });
 
   it('should have properly status', () => {
diff --git a/src/app/shared/object-list/my-dspace-result-list-element/pool-search-result/pool-search-result-list-element.component.ts b/src/app/shared/object-list/my-dspace-result-list-element/pool-search-result/pool-search-result-list-element.component.ts
index b34e23c3e629c5dcfb5085968f1469ccbdccd8b0..f3368cf64cb0f3b65508877691a8f46e67ada82a 100644
--- a/src/app/shared/object-list/my-dspace-result-list-element/pool-search-result/pool-search-result-list-element.component.ts
+++ b/src/app/shared/object-list/my-dspace-result-list-element/pool-search-result/pool-search-result-list-element.component.ts
@@ -1,11 +1,9 @@
 import { Component, OnInit } from '@angular/core';
 
 import { Observable } from 'rxjs';
-import { find } from 'rxjs/operators';
 
 import { ViewMode } from '../../../../core/shared/view-mode.model';
 import { RemoteData } from '../../../../core/data/remote-data';
-import { isNotUndefined } from '../../../empty.util';
 import { WorkflowItem } from '../../../../core/submission/models/workflowitem.model';
 import { PoolTask } from '../../../../core/tasks/models/pool-task-object.model';
 import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type';
@@ -13,6 +11,8 @@ import { listableObjectComponent } from '../../../object-collection/shared/lista
 import { PoolTaskSearchResult } from '../../../object-collection/shared/pool-task-search-result.model';
 import { SearchResultListElementComponent } from '../../search-result-list-element/search-result-list-element.component';
 import { TruncatableService } from '../../../truncatable/truncatable.service';
+import { followLink } from '../../../utils/follow-link-config.model';
+import { LinkService } from '../../../../core/cache/builders/link.service';
 
 /**
  * This component renders pool task object for the search result in the list view.
@@ -39,14 +39,17 @@ export class PoolSearchResultListElementComponent extends SearchResultListElemen
   /**
    * The workflowitem object that belonging to the result object
    */
-  public workflowitem: WorkflowItem;
+  public workflowitemRD$: Observable<RemoteData<WorkflowItem>>;
 
   /**
    * The index of this list element
    */
   public index: number;
 
-  constructor(protected truncatableService: TruncatableService) {
+  constructor(
+    protected linkService: LinkService,
+    protected truncatableService: TruncatableService
+  ) {
     super(truncatableService);
   }
 
@@ -55,17 +58,12 @@ export class PoolSearchResultListElementComponent extends SearchResultListElemen
    */
   ngOnInit() {
     super.ngOnInit();
-    this.initWorkflowItem(this.dso.workflowitem as Observable<RemoteData<WorkflowItem>>);
-  }
-
-  /**
-   * Retrieve workflowitem from result object
-   */
-  initWorkflowItem(wfi$: Observable<RemoteData<WorkflowItem>>) {
-    wfi$.pipe(
-      find((rd: RemoteData<WorkflowItem>) => (rd.hasSucceeded && isNotUndefined(rd.payload)))
-    ).subscribe((rd: RemoteData<WorkflowItem>) => {
-      this.workflowitem = rd.payload;
-    });
+    this.linkService.resolveLink(this.dso, followLink(
+      'workflowitem',
+      null,
+      followLink('item'),
+      followLink('submitter')
+    ));
+    this.workflowitemRD$ = this.dso.workflowitem as Observable<RemoteData<WorkflowItem>>;
   }
 }
diff --git a/src/app/shared/object-list/my-dspace-result-list-element/workflow-item-search-result/workflow-item-search-result-list-element.component.html b/src/app/shared/object-list/my-dspace-result-list-element/workflow-item-search-result/workflow-item-search-result-list-element.component.html
index 782c5f9e56dd70db3a93262d7e92a958f5b212c6..ced2846b4b45580cd728b764010864eccb26cf28 100644
--- a/src/app/shared/object-list/my-dspace-result-list-element/workflow-item-search-result/workflow-item-search-result-list-element.component.html
+++ b/src/app/shared/object-list/my-dspace-result-list-element/workflow-item-search-result/workflow-item-search-result-list-element.component.html
@@ -1,6 +1,11 @@
-<ds-item-list-preview [item]="item"
-                      [object]="object"
-                      [status]="status"></ds-item-list-preview>
-
-<ds-workflowitem-actions [object]="dso"></ds-workflowitem-actions>
+<ng-container *ngIf="item$ | async">
+  <ds-item-list-preview
+    [item]="item$ | async"
+    [object]="object"
+    [status]="status"></ds-item-list-preview>
 
+  <ds-workflowitem-actions [object]="dso"></ds-workflowitem-actions>
+</ng-container>
+<ds-loading
+  *ngIf="!(item$ | async)"
+  [showMessage]="false"></ds-loading>
diff --git a/src/app/shared/object-list/my-dspace-result-list-element/workflow-item-search-result/workflow-item-search-result-list-element.component.spec.ts b/src/app/shared/object-list/my-dspace-result-list-element/workflow-item-search-result/workflow-item-search-result-list-element.component.spec.ts
index f5521001ffbfc6b6f66332a9a428020319497aa5..9cbbd666cd362d2a678a0c8dd6e5d3595d73c02c 100644
--- a/src/app/shared/object-list/my-dspace-result-list-element/workflow-item-search-result/workflow-item-search-result-list-element.component.spec.ts
+++ b/src/app/shared/object-list/my-dspace-result-list-element/workflow-item-search-result/workflow-item-search-result-list-element.component.spec.ts
@@ -3,14 +3,18 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing';
 import { NoopAnimationsModule } from '@angular/platform-browser/animations';
 
 import { of as observableOf } from 'rxjs';
+import { take } from 'rxjs/operators';
+import { LinkService } from '../../../../core/cache/builders/link.service';
+import { ItemDataService } from '../../../../core/data/item-data.service';
 
 import { Item } from '../../../../core/shared/item.model';
 import { WorkflowItem } from '../../../../core/submission/models/workflowitem.model';
+import { getMockLinkService } from '../../../mocks/mock-link-service';
 import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type';
-import { createSuccessfulRemoteDataObject } from '../../../testing/utils';
-import { WorkflowItemSearchResultListElementComponent } from './workflow-item-search-result-list-element.component';
 import { WorkflowItemSearchResult } from '../../../object-collection/shared/workflow-item-search-result.model';
+import { createSuccessfulRemoteDataObject } from '../../../testing/utils';
 import { TruncatableService } from '../../../truncatable/truncatable.service';
+import { WorkflowItemSearchResultListElementComponent } from './workflow-item-search-result-list-element.component';
 
 let component: WorkflowItemSearchResultListElementComponent;
 let fixture: ComponentFixture<WorkflowItemSearchResultListElementComponent>;
@@ -52,13 +56,18 @@ const item = Object.assign(new Item(), {
 const rd = createSuccessfulRemoteDataObject(item);
 mockResultObject.indexableObject = Object.assign(new WorkflowItem(), { item: observableOf(rd) });
 
+let linkService;
+
 describe('WorkflowItemSearchResultListElementComponent', () => {
   beforeEach(async(() => {
+    linkService = getMockLinkService();
     TestBed.configureTestingModule({
       imports: [NoopAnimationsModule],
       declarations: [WorkflowItemSearchResultListElementComponent],
       providers: [
         { provide: TruncatableService, useValue: {} },
+        { provide: ItemDataService, useValue: {} },
+        { provide: LinkService, useValue: linkService },
       ],
       schemas: [NO_ERRORS_SCHEMA]
     }).overrideComponent(WorkflowItemSearchResultListElementComponent, {
@@ -76,8 +85,12 @@ describe('WorkflowItemSearchResultListElementComponent', () => {
     fixture.detectChanges();
   });
 
-  it('should init item properly', () => {
-    expect(component.item).toEqual(item);
+  it('should init item properly', (done) => {
+    component.item$.pipe(take(1)).subscribe((i) => {
+      expect(linkService.resolveLink).toHaveBeenCalled();
+      expect(i).toBe(item);
+      done();
+    });
   });
 
   it('should have properly status', () => {
diff --git a/src/app/shared/object-list/my-dspace-result-list-element/workflow-item-search-result/workflow-item-search-result-list-element.component.ts b/src/app/shared/object-list/my-dspace-result-list-element/workflow-item-search-result/workflow-item-search-result-list-element.component.ts
index faf03425f0fca67c7874987e538183aa8c387563..432f69f28caf7f39d79e4e7d6609a5403ed0f26e 100644
--- a/src/app/shared/object-list/my-dspace-result-list-element/workflow-item-search-result/workflow-item-search-result-list-element.component.ts
+++ b/src/app/shared/object-list/my-dspace-result-list-element/workflow-item-search-result/workflow-item-search-result-list-element.component.ts
@@ -1,16 +1,19 @@
 import { Component } from '@angular/core';
 
 import { Observable } from 'rxjs';
-import { find } from 'rxjs/operators';
+import { find, map } from 'rxjs/operators';
+import { LinkService } from '../../../../core/cache/builders/link.service';
+import { RemoteData } from '../../../../core/data/remote-data';
+import { Item } from '../../../../core/shared/item.model';
 
 import { ViewMode } from '../../../../core/shared/view-mode.model';
-import { RemoteData } from '../../../../core/data/remote-data';
-import { isNotUndefined } from '../../../empty.util';
 import { WorkflowItem } from '../../../../core/submission/models/workflowitem.model';
-import { Item } from '../../../../core/shared/item.model';
-import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type';
+import { isNotUndefined } from '../../../empty.util';
 import { listableObjectComponent } from '../../../object-collection/shared/listable-object/listable-object.decorator';
+import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type';
 import { WorkflowItemSearchResult } from '../../../object-collection/shared/workflow-item-search-result.model';
+import { TruncatableService } from '../../../truncatable/truncatable.service';
+import { followLink } from '../../../utils/follow-link-config.model';
 import { SearchResultListElementComponent } from '../../search-result-list-element/search-result-list-element.component';
 
 /**
@@ -28,18 +31,26 @@ export class WorkflowItemSearchResultListElementComponent extends SearchResultLi
   /**
    * The item object that belonging to the result object
    */
-  public item: Item;
+  public item$: Observable<Item>;
 
   /**
    * Represent item's status
    */
   public status = MyDspaceItemStatusType.WORKFLOW;
 
+  constructor(
+    protected truncatableService: TruncatableService,
+    protected linkService: LinkService
+  ) {
+    super(truncatableService);
+  }
+
   /**
    * Initialize all instance variables
    */
   ngOnInit() {
     super.ngOnInit();
+    this.linkService.resolveLink(this.dso, followLink('item'));
     this.initItem(this.dso.item as Observable<RemoteData<Item>> );
   }
 
@@ -47,11 +58,10 @@ export class WorkflowItemSearchResultListElementComponent extends SearchResultLi
    * Retrieve item from result object
    */
   initItem(item$: Observable<RemoteData<Item>>) {
-    item$.pipe(
-      find((rd: RemoteData<Item>) => rd.hasSucceeded && isNotUndefined(rd.payload))
-    ).subscribe((rd: RemoteData<Item>) => {
-      this.item = rd.payload;
-    });
+    this.item$ = item$.pipe(
+      find((rd: RemoteData<Item>) => rd.hasSucceeded && isNotUndefined(rd.payload)),
+      map((rd: RemoteData<Item>) => rd.payload)
+    );
   }
 
 }
diff --git a/src/app/shared/object-list/my-dspace-result-list-element/workspace-item-search-result/workspace-item-search-result-list-element.component.html b/src/app/shared/object-list/my-dspace-result-list-element/workspace-item-search-result/workspace-item-search-result-list-element.component.html
index 79a31770d6a6d2f2df3dbc242063bc802d84d2bb..8966b4b1d8d750117d734d455ee25f3b7c1a3979 100644
--- a/src/app/shared/object-list/my-dspace-result-list-element/workspace-item-search-result/workspace-item-search-result-list-element.component.html
+++ b/src/app/shared/object-list/my-dspace-result-list-element/workspace-item-search-result/workspace-item-search-result-list-element.component.html
@@ -1,7 +1,11 @@
-<ds-item-list-preview
-  *ngIf="status && item"
-  [item]="item"
-  [object]="object"
-  [status]="status"></ds-item-list-preview>
+<ng-container *ngIf="item$ | async">
+  <ds-item-list-preview
+    [item]="item$ | async"
+    [object]="object"
+    [status]="status"></ds-item-list-preview>
 
-<ds-workspaceitem-actions [object]="dso"></ds-workspaceitem-actions>
+  <ds-workspaceitem-actions [object]="dso"></ds-workspaceitem-actions>
+</ng-container>
+<ds-loading
+  *ngIf="!(item$ | async)"
+  [showMessage]="false"></ds-loading>
diff --git a/src/app/shared/object-list/my-dspace-result-list-element/workspace-item-search-result/workspace-item-search-result-list-element.component.spec.ts b/src/app/shared/object-list/my-dspace-result-list-element/workspace-item-search-result/workspace-item-search-result-list-element.component.spec.ts
index faf4a3b1be98ac4ae327461dd836be7e936c085f..441800c8db777dcbc5fd8c0b071cdec94dbffb20 100644
--- a/src/app/shared/object-list/my-dspace-result-list-element/workspace-item-search-result/workspace-item-search-result-list-element.component.spec.ts
+++ b/src/app/shared/object-list/my-dspace-result-list-element/workspace-item-search-result/workspace-item-search-result-list-element.component.spec.ts
@@ -3,14 +3,18 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing';
 import { NoopAnimationsModule } from '@angular/platform-browser/animations';
 
 import { of as observableOf } from 'rxjs';
+import { take } from 'rxjs/operators';
+import { LinkService } from '../../../../core/cache/builders/link.service';
+import { ItemDataService } from '../../../../core/data/item-data.service';
 
 import { Item } from '../../../../core/shared/item.model';
-import { WorkspaceItemSearchResultListElementComponent } from './workspace-item-search-result-list-element.component';
 import { WorkspaceItem } from '../../../../core/submission/models/workspaceitem.model';
+import { getMockLinkService } from '../../../mocks/mock-link-service';
 import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type';
-import { createSuccessfulRemoteDataObject } from '../../../testing/utils';
 import { WorkflowItemSearchResult } from '../../../object-collection/shared/workflow-item-search-result.model';
+import { createSuccessfulRemoteDataObject } from '../../../testing/utils';
 import { TruncatableService } from '../../../truncatable/truncatable.service';
+import { WorkspaceItemSearchResultListElementComponent } from './workspace-item-search-result-list-element.component';
 
 let component: WorkspaceItemSearchResultListElementComponent;
 let fixture: ComponentFixture<WorkspaceItemSearchResultListElementComponent>;
@@ -51,14 +55,18 @@ const item = Object.assign(new Item(), {
 });
 const rd = createSuccessfulRemoteDataObject(item);
 mockResultObject.indexableObject = Object.assign(new WorkspaceItem(), { item: observableOf(rd) });
+let linkService;
 
 describe('WorkspaceItemSearchResultListElementComponent', () => {
   beforeEach(async(() => {
+    linkService = getMockLinkService();
     TestBed.configureTestingModule({
       imports: [NoopAnimationsModule],
       declarations: [WorkspaceItemSearchResultListElementComponent],
       providers: [
         { provide: TruncatableService, useValue: {} },
+        { provide: ItemDataService, useValue: {} },
+        { provide: LinkService, useValue: linkService },
       ],
       schemas: [NO_ERRORS_SCHEMA]
     }).overrideComponent(WorkspaceItemSearchResultListElementComponent, {
@@ -76,8 +84,12 @@ describe('WorkspaceItemSearchResultListElementComponent', () => {
     fixture.detectChanges();
   });
 
-  it('should init item properly', () => {
-    expect(component.item).toEqual(item);
+  it('should init item properly', (done) => {
+    component.item$.pipe(take(1)).subscribe((i) => {
+      expect(linkService.resolveLink).toHaveBeenCalled();
+      expect(i).toBe(item);
+      done();
+    });
   });
 
   it('should have properly status', () => {
diff --git a/src/app/shared/object-list/my-dspace-result-list-element/workspace-item-search-result/workspace-item-search-result-list-element.component.ts b/src/app/shared/object-list/my-dspace-result-list-element/workspace-item-search-result/workspace-item-search-result-list-element.component.ts
index 830726c6770885a16a641aadaacc5d89bb395a42..b9d89ef6ab95725bfad5155b640a3f004c56e550 100644
--- a/src/app/shared/object-list/my-dspace-result-list-element/workspace-item-search-result/workspace-item-search-result-list-element.component.ts
+++ b/src/app/shared/object-list/my-dspace-result-list-element/workspace-item-search-result/workspace-item-search-result-list-element.component.ts
@@ -1,16 +1,19 @@
 import { Component } from '@angular/core';
 
 import { Observable } from 'rxjs';
-import { find } from 'rxjs/operators';
+import { find, map } from 'rxjs/operators';
+import { LinkService } from '../../../../core/cache/builders/link.service';
+import { RemoteData } from '../../../../core/data/remote-data';
+import { Item } from '../../../../core/shared/item.model';
 
 import { ViewMode } from '../../../../core/shared/view-mode.model';
 import { WorkspaceItem } from '../../../../core/submission/models/workspaceitem.model';
-import { RemoteData } from '../../../../core/data/remote-data';
 import { isNotUndefined } from '../../../empty.util';
-import { Item } from '../../../../core/shared/item.model';
-import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type';
 import { listableObjectComponent } from '../../../object-collection/shared/listable-object/listable-object.decorator';
+import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type';
 import { WorkspaceItemSearchResult } from '../../../object-collection/shared/workspace-item-search-result.model';
+import { TruncatableService } from '../../../truncatable/truncatable.service';
+import { followLink } from '../../../utils/follow-link-config.model';
 import { SearchResultListElementComponent } from '../../search-result-list-element/search-result-list-element.component';
 
 /**
@@ -28,18 +31,26 @@ export class WorkspaceItemSearchResultListElementComponent extends SearchResultL
   /**
    * The item object that belonging to the result object
    */
-  item: Item;
+  item$: Observable<Item>;
 
   /**
    * Represent item's status
    */
   status = MyDspaceItemStatusType.WORKSPACE;
 
+  constructor(
+    protected truncatableService: TruncatableService,
+    protected linkService: LinkService
+  ) {
+    super(truncatableService);
+  }
+
   /**
    * Initialize all instance variables
    */
   ngOnInit() {
     super.ngOnInit();
+    this.linkService.resolveLink(this.dso, followLink('item'));
     this.initItem(this.dso.item as Observable<RemoteData<Item>>);
   }
 
@@ -47,10 +58,9 @@ export class WorkspaceItemSearchResultListElementComponent extends SearchResultL
    * Retrieve item from result object
    */
   initItem(item$: Observable<RemoteData<Item>>) {
-    item$.pipe(
-      find((rd: RemoteData<Item>) => rd.hasSucceeded && isNotUndefined(rd.payload))
-    ).subscribe((rd: RemoteData<Item>) => {
-      this.item = rd.payload;
-    });
+    this.item$ = item$.pipe(
+      find((rd: RemoteData<Item>) => rd.hasSucceeded && isNotUndefined(rd.payload)),
+      map((rd: RemoteData<Item>) => rd.payload)
+    );
   }
 }
diff --git a/src/app/shared/object.util.ts b/src/app/shared/object.util.ts
index 60ed71096a4170ae5cc63ee4e01d12f983d4a130..02f7c54e1d40f1848dea5968ee3f8e735522364f 100644
--- a/src/app/shared/object.util.ts
+++ b/src/app/shared/object.util.ts
@@ -5,7 +5,7 @@ import { isEqual, isObject, transform } from 'lodash';
  * Returns passed object without specified property
  */
 export function deleteProperty(object: object, key: string): object {
-  const {[key]: deletedKey, ...otherKeys} = object;
+  const { [key]: deletedKey, ...otherKeys } = object as { [key: string]: any };
   return otherKeys;
 }
 
@@ -47,7 +47,7 @@ export function difference(object: object, base: object) {
   const changes = (o, b) => {
     return transform(o, (result, value, key) => {
       if (!isEqual(value, b[key]) && isNotEmpty(value)) {
-        const resultValue = (isObject(value) && isObject(b[key])) ? changes(value, b[key]) : value;
+        const resultValue = (isObject(value) && isObject(b[key])) ? changes(value, b[key]) : value as object;
         if (!hasOnlyEmptyProperties(resultValue)) {
           result[key] = resultValue;
         }
diff --git a/src/app/shared/pagination-drag-and-drop/abstract-paginated-drag-and-drop-list.component.ts b/src/app/shared/pagination-drag-and-drop/abstract-paginated-drag-and-drop-list.component.ts
index 7e1ba47687a92c6b44e7d90cd9183725d5ab24d4..a34b5d5bc0c2a088db93bebaf3f037a8da32669d 100644
--- a/src/app/shared/pagination-drag-and-drop/abstract-paginated-drag-and-drop-list.component.ts
+++ b/src/app/shared/pagination-drag-and-drop/abstract-paginated-drag-and-drop-list.component.ts
@@ -32,7 +32,7 @@ export abstract class AbstractPaginatedDragAndDropListComponent<T extends DSpace
   /**
    * A view on the child pagination component
    */
-  @ViewChild(PaginationComponent) paginationComponent: PaginationComponent;
+  @ViewChild(PaginationComponent, {static: false}) paginationComponent: PaginationComponent;
 
   /**
    * The URL to use for accessing the object updates from this list
diff --git a/src/app/shared/pagination/pagination.component.spec.ts b/src/app/shared/pagination/pagination.component.spec.ts
index dfbef9123ab3b63dd707f63a6301068cf3966b82..949ebc85d3f0d72db882cbd47ec25b9372d8873b 100644
--- a/src/app/shared/pagination/pagination.component.spec.ts
+++ b/src/app/shared/pagination/pagination.component.spec.ts
@@ -139,7 +139,7 @@ describe('Pagination component', () => {
           }
         }),
         NgxPaginationModule,
-        NgbModule.forRoot(),
+        NgbModule,
         RouterTestingModule.withRoutes([
           { path: 'home', component: TestComponent }
         ])],
diff --git a/src/app/shared/search-form/search-form.component.spec.ts b/src/app/shared/search-form/search-form.component.spec.ts
index 74ed4bb913e7179523e2d64401ed387468dceab2..ffd8dd87a257c695fe2ff90fdaf904febd46d60e 100644
--- a/src/app/shared/search-form/search-form.component.spec.ts
+++ b/src/app/shared/search-form/search-form.component.spec.ts
@@ -124,7 +124,11 @@ export const objects: DSpaceObject[] = [
         scheduler: null
       }
     },
-    self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/communities/7669c72a-3f2a-451f-a3b9-9210e7a4c02f',
+    _links: {
+      self: {
+        href: 'https://dspace7.4science.it/dspace-spring-rest/api/core/communities/7669c72a-3f2a-451f-a3b9-9210e7a4c02f',
+      },
+    },
     id: '7669c72a-3f2a-451f-a3b9-9210e7a4c02f',
     uuid: '7669c72a-3f2a-451f-a3b9-9210e7a4c02f',
     type: Community.type,
@@ -178,7 +182,11 @@ export const objects: DSpaceObject[] = [
           scheduler: null
         }
       },
-      self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/communities/9076bd16-e69a-48d6-9e41-0238cb40d863',
+      _links: {
+        self: {
+          href: 'https://dspace7.4science.it/dspace-spring-rest/api/core/communities/9076bd16-e69a-48d6-9e41-0238cb40d863',
+        },
+      },
       id: '9076bd16-e69a-48d6-9e41-0238cb40d863',
       uuid: '9076bd16-e69a-48d6-9e41-0238cb40d863',
       type: Community.type,
diff --git a/src/app/shared/search-form/search-form.component.ts b/src/app/shared/search-form/search-form.component.ts
index c49353deb3f571bd2d1a5cef5bb5e392d1f447d2..97541c478619669d35f28c0c149683f0da779f40 100644
--- a/src/app/shared/search-form/search-form.component.ts
+++ b/src/app/shared/search-form/search-form.component.ts
@@ -1,9 +1,7 @@
 import { Component, EventEmitter, Input, Output } from '@angular/core';
 import { DSpaceObject } from '../../core/shared/dspace-object.model';
 import { Router } from '@angular/router';
-import { hasValue, isNotEmpty } from '../empty.util';
-import { QueryParamsHandling } from '@angular/router/src/config';
-import { MYDSPACE_ROUTE } from '../../+my-dspace-page/my-dspace-page.component';
+import { isNotEmpty } from '../empty.util';
 import { SearchService } from '../../core/shared/search/search.service';
 import { currentPath } from '../utils/route.utils';
 
diff --git a/src/app/shared/search/facet-value.model.ts b/src/app/shared/search/facet-value.model.ts
index d2cc521356fa5be8ba9465f5fec75581a0a63cce..032f9c9b2a223b88c5bc2ab79e6bcb62bd569e9d 100644
--- a/src/app/shared/search/facet-value.model.ts
+++ b/src/app/shared/search/facet-value.model.ts
@@ -1,9 +1,11 @@
-import { autoserialize, autoserializeAs } from 'cerialize';
+import { autoserialize, autoserializeAs, deserialize } from 'cerialize';
+import { HALLink } from '../../core/shared/hal-link.model';
+import { HALResource } from '../../core/shared/hal-resource.model';
 
 /**
  * Class representing possible values for a certain filter
  */
-export class FacetValue {
+export class FacetValue implements HALResource {
   /**
    * The display label of the facet value
    */
@@ -23,8 +25,11 @@ export class FacetValue {
   count: number;
 
   /**
-   * The REST url to add this filter value
+   * The {@link HALLink}s for this FacetValue
    */
-  @autoserialize
-  search: string;
+  @deserialize
+  _links: {
+    self: HALLink
+    search: HALLink
+  }
 }
diff --git a/src/app/shared/search/normalized-search-result.model.ts b/src/app/shared/search/normalized-search-result.model.ts
deleted file mode 100644
index 3904b4a49459b29299dd06dbef6429081816f9d0..0000000000000000000000000000000000000000
--- a/src/app/shared/search/normalized-search-result.model.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-import { autoserialize, inheritSerialization } from 'cerialize';
-import { MetadataMap } from '../../core/shared/metadata.models';
-import { NormalizedObject } from '../../core/cache/models/normalized-object.model';
-
-/**
- * Represents a normalized version of a search result object of a certain DSpaceObject
- */
-@inheritSerialization(NormalizedObject)
-export class NormalizedSearchResult {
-  /**
-   * The UUID of the DSpaceObject that was found
-   */
-  @autoserialize
-  indexableObject: string;
-
-  /**
-   * The metadata that was used to find this item, hithighlighted
-   */
-  @autoserialize
-  hitHighlights: MetadataMap;
-}
diff --git a/src/app/shared/search/search-filters/search-filter/search-authority-filter/search-authority-filter.component.ts b/src/app/shared/search/search-filters/search-filter/search-authority-filter/search-authority-filter.component.ts
index 99e9bfac2e29339ae749ea4bb5bad827ae20476e..5dc930f67fc2cccf6c1c202b7c0516f31b3e653f 100644
--- a/src/app/shared/search/search-filters/search-filter/search-authority-filter/search-authority-filter.component.ts
+++ b/src/app/shared/search/search-filters/search-filter/search-authority-filter/search-authority-filter.component.ts
@@ -23,7 +23,7 @@ export class SearchAuthorityFilterComponent extends SearchFacetFilterComponent i
    * Retrieve facet value from search link
    */
   protected getFacetValue(facet: FacetValue): string {
-    const search = facet.search;
+    const search = facet._links.search.href;
     const hashes = search.slice(search.indexOf('?') + 1).split('&');
     const params = {};
     hashes.map((hash) => {
diff --git a/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.spec.ts b/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.spec.ts
index ff5db664dbc01cdbf92eb1ee670d8ce5524fee3a..43f47cc2b9153fb5f5bcfae1c36c65dbca135eb3 100644
--- a/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.spec.ts
+++ b/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.spec.ts
@@ -1,20 +1,20 @@
 import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
 import { async, ComponentFixture, TestBed } from '@angular/core/testing';
-import { TranslateModule } from '@ngx-translate/core';
-import { NoopAnimationsModule } from '@angular/platform-browser/animations';
-import { SearchFacetOptionComponent } from './search-facet-option.component';
-import { SearchFilterConfig } from '../../../../search-filter-config.model';
-import { FilterType } from '../../../../filter-type.model';
-import { FacetValue } from '../../../../facet-value.model';
 import { FormsModule } from '@angular/forms';
-import { of as observableOf } from 'rxjs';
-import { SearchService } from '../../../../../../core/shared/search/search.service';
-import { SearchServiceStub } from '../../../../../testing/search-service-stub';
+import { By } from '@angular/platform-browser';
+import { NoopAnimationsModule } from '@angular/platform-browser/animations';
 import { Router } from '@angular/router';
-import { RouterStub } from '../../../../../testing/router-stub';
+import { TranslateModule } from '@ngx-translate/core';
+import { of as observableOf } from 'rxjs';
 import { SearchConfigurationService } from '../../../../../../core/shared/search/search-configuration.service';
 import { SearchFilterService } from '../../../../../../core/shared/search/search-filter.service';
-import { By } from '@angular/platform-browser';
+import { SearchService } from '../../../../../../core/shared/search/search.service';
+import { RouterStub } from '../../../../../testing/router-stub';
+import { SearchServiceStub } from '../../../../../testing/search-service-stub';
+import { FacetValue } from '../../../../facet-value.model';
+import { FilterType } from '../../../../filter-type.model';
+import { SearchFilterConfig } from '../../../../search-filter-config.model';
+import { SearchFacetOptionComponent } from './search-facet-option.component';
 
 describe('SearchFacetOptionComponent', () => {
   let comp: SearchFacetOptionComponent;
@@ -47,21 +47,30 @@ describe('SearchFacetOptionComponent', () => {
     label: value2,
     value: value2,
     count: 20,
-    search: ``
+    _links: {
+      self: { href: 'selectedValue-self-link2' },
+      search: { href: `` }
+    }
   };
 
   const selectedValue: FacetValue = {
     label: value1,
     value: value1,
     count: 20,
-    search: `http://test.org/api/discover/search/objects?f.${filterName1}=${value1},${operator}`
+    _links: {
+      self: { href: 'selectedValue-self-link1' },
+      search: { href: `http://test.org/api/discover/search/objects?f.${filterName1}=${value1},${operator}` }
+    }
   };
 
   const authorityValue: FacetValue = {
     label: value2,
     value: value2,
     count: 20,
-    search: `http://test.org/api/discover/search/objects?f.${filterName2}=${value2},${operator}`
+    _links: {
+      self: { href: 'authorityValue-self-link2' },
+      search: { href: `http://test.org/api/discover/search/objects?f.${filterName2}=${value2},${operator}` }
+    }
   };
 
   const searchLink = '/search';
diff --git a/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.ts b/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.ts
index 512cd5501ca32d8846e652a8a6f50fd84a8562fc..04e810eddaf761e35b6a7e1a14229cfa1731fc65 100644
--- a/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.ts
+++ b/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.ts
@@ -113,7 +113,7 @@ export class SearchFacetOptionComponent implements OnInit, OnDestroy {
    */
   private getFacetValue(): string {
     if (this.filterConfig.type === FilterType.authority) {
-      const search = this.filterValue.search;
+      const search = this.filterValue._links.search.href;
       const hashes = search.slice(search.indexOf('?') + 1).split('&');
       const params = {};
       hashes.map((hash) => {
diff --git a/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component.spec.ts b/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component.spec.ts
index e6878dadd1cd2d76a597aa221a79c34c40baf4f7..34fb64040c9df7f7ab5f3814b3fb70d540b6fbea 100644
--- a/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component.spec.ts
+++ b/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component.spec.ts
@@ -38,7 +38,14 @@ describe('SearchFacetRangeOptionComponent', () => {
     label: value2,
     value: value2,
     count: 20,
-    search: ''
+    _links: {
+      self: {
+        href: ''
+      },
+      search: {
+        href: ''
+      }
+    }
   };
 
   const searchLink = '/search';
@@ -96,7 +103,14 @@ describe('SearchFacetRangeOptionComponent', () => {
         label: '50-60',
         value: '50-60',
         count: 20,
-        search: ''
+        _links: {
+          self: {
+            href: ''
+          },
+          search: {
+            href: ''
+          }
+        }
       };
       (comp as any).updateChangeParams();
       expect(comp.changeQueryParams).toEqual({
diff --git a/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.spec.ts b/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.spec.ts
index 4ea6571a872daaf782626b9f11e8447c31bad4b3..cfeda7d51c6ae378747a9366dc3b8da134996e93 100644
--- a/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.spec.ts
+++ b/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.spec.ts
@@ -1,19 +1,19 @@
 import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
 import { async, ComponentFixture, TestBed } from '@angular/core/testing';
-import { TranslateModule } from '@ngx-translate/core';
-import { NoopAnimationsModule } from '@angular/platform-browser/animations';
-import { SearchFilterConfig } from '../../../../search-filter-config.model';
-import { FilterType } from '../../../../filter-type.model';
 import { FormsModule } from '@angular/forms';
-import { of as observableOf } from 'rxjs';
-import { SearchService } from '../../../../../../core/shared/search/search.service';
-import { SearchServiceStub } from '../../../../../testing/search-service-stub';
+import { NoopAnimationsModule } from '@angular/platform-browser/animations';
 import { Router } from '@angular/router';
-import { RouterStub } from '../../../../../testing/router-stub';
+import { TranslateModule } from '@ngx-translate/core';
+import { of as observableOf } from 'rxjs';
 import { SearchConfigurationService } from '../../../../../../core/shared/search/search-configuration.service';
 import { SearchFilterService } from '../../../../../../core/shared/search/search-filter.service';
-import { SearchFacetSelectedOptionComponent } from './search-facet-selected-option.component';
+import { SearchService } from '../../../../../../core/shared/search/search.service';
+import { RouterStub } from '../../../../../testing/router-stub';
+import { SearchServiceStub } from '../../../../../testing/search-service-stub';
 import { FacetValue } from '../../../../facet-value.model';
+import { FilterType } from '../../../../filter-type.model';
+import { SearchFilterConfig } from '../../../../search-filter-config.model';
+import { SearchFacetSelectedOptionComponent } from './search-facet-selected-option.component';
 
 describe('SearchFacetSelectedOptionComponent', () => {
   let comp: SearchFacetSelectedOptionComponent;
@@ -47,25 +47,37 @@ describe('SearchFacetSelectedOptionComponent', () => {
     label: value1,
     value: value1,
     count: 20,
-    search: `http://test.org/api/discover/search/objects?f.${filterName1}=${value1}`
+    _links: {
+      self: { href: 'selectedValue-self-link1' },
+      search: { href: `http://test.org/api/discover/search/objects?f.${filterName1}=${value1}` }
+    }
   };
   const selectedValue2: FacetValue = {
     label: value2,
     value: value2,
     count: 20,
-    search: `http://test.org/api/discover/search/objects?f.${filterName1}=${value2}`
+    _links: {
+      self: { href: 'selectedValue-self-link2' },
+      search: { href: `http://test.org/api/discover/search/objects?f.${filterName1}=${value2}` }
+    }
   };
   const selectedAuthorityValue: FacetValue = {
     label: label1,
     value: value1,
     count: 20,
-    search: `http://test.org/api/discover/search/objects?f.${filterName2}=${value1},${operator}`
+    _links: {
+      self: { href: 'selectedAuthorityValue-self-link1' },
+      search: { href: `http://test.org/api/discover/search/objects?f.${filterName2}=${value1},${operator}` }
+    }
   };
   const selectedAuthorityValue2: FacetValue = {
     label: label2,
     value: value2,
     count: 20,
-    search: `http://test.org/api/discover/search/objects?f.${filterName2}=${value2},${operator}`
+    _links: {
+      self: { href: 'selectedAuthorityValue-self-link2' },
+      search: { href: `http://test.org/api/discover/search/objects?f.${filterName2}=${value2},${operator}` }
+    }
   };
   const selectedValues = [selectedValue, selectedValue2];
   const selectedAuthorityValues = [selectedAuthorityValue, selectedAuthorityValue2];
@@ -73,13 +85,19 @@ describe('SearchFacetSelectedOptionComponent', () => {
     label: value2,
     value: value2,
     count: 1,
-    search: ''
+    _links: {
+      self: { href: 'facetValue-self-link2' },
+      search: { href: `` }
+    }
   };
   const authorityValue: FacetValue = {
     label: label2,
     value: value2,
     count: 20,
-    search: `http://test.org/api/discover/search/objects?f.${filterName2}=${value2},${operator}`
+    _links: {
+      self: { href: 'authorityValue-self-link2' },
+      search: { href: `http://test.org/api/discover/search/objects?f.${filterName2}=${value2},${operator}` }
+    }
   };
   const selectedValues$ = observableOf(selectedValues);
   const selectedAuthorityValues$ = observableOf(selectedAuthorityValues);
diff --git a/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.ts b/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.ts
index 0cf54d88f5b5e15429c8cd0d90d1d2e4399dece2..f58a903b0cd2ed814e72ab583769003216320d82 100644
--- a/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.ts
+++ b/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.ts
@@ -102,7 +102,7 @@ export class SearchFacetSelectedOptionComponent implements OnInit, OnDestroy {
    */
   private getFacetValue(facetValue: FacetValue): string {
     if (this.filterConfig.type === FilterType.authority) {
-      const search = facetValue.search;
+      const search = facetValue._links.search.href;
       const hashes = search.slice(search.indexOf('?') + 1).split('&');
       const params = {};
       hashes.map((hash) => {
diff --git a/src/app/shared/search/search-filters/search-filter/search-facet-filter/search-facet-filter.component.spec.ts b/src/app/shared/search/search-filters/search-filter/search-facet-filter/search-facet-filter.component.spec.ts
index 1b66e292460ed9cff7cd3cad140120128a07eead..769549775004f9c094007eaa7dce031cfc900e6c 100644
--- a/src/app/shared/search/search-filters/search-filter/search-facet-filter/search-facet-filter.component.spec.ts
+++ b/src/app/shared/search/search-filters/search-filter/search-facet-filter/search-facet-filter.component.spec.ts
@@ -39,17 +39,38 @@ describe('SearchFacetFilterComponent', () => {
       label: value1,
       value: value1,
       count: 52,
-      search: ''
+      _links: {
+        self: {
+          href: ''
+        },
+        search: {
+          href: ''
+        }
+      }
     }, {
       label: value2,
       value: value2,
       count: 20,
-      search: ''
+      _links: {
+        self: {
+          href: ''
+        },
+        search: {
+          href: ''
+        }
+      }
     }, {
       label: value3,
       value: value3,
       count: 5,
-      search: ''
+      _links: {
+        self: {
+          href: ''
+        },
+        search: {
+          href: ''
+        }
+      }
     }
   ];
 
diff --git a/src/app/shared/search/search-filters/search-filter/search-facet-filter/search-facet-filter.component.ts b/src/app/shared/search/search-filters/search-filter/search-facet-filter/search-facet-filter.component.ts
index 1d6a85b95b12319e48fec1ca3a67a83eacc81ff9..df0c53f54314494e67a3d51334667f5a28fa6b00 100644
--- a/src/app/shared/search/search-filters/search-filter/search-facet-filter/search-facet-filter.component.ts
+++ b/src/app/shared/search/search-filters/search-filter/search-facet-filter/search-facet-filter.component.ts
@@ -320,7 +320,7 @@ export class SearchFacetFilterComponent implements OnInit, OnDestroy {
    * Prevent unnecessary rerendering
    */
   trackUpdate(index, value: FacetValue) {
-    return value ? value.search : undefined;
+    return value ? value._links.search.href : undefined;
   }
 }
 
diff --git a/src/app/shared/search/search-filters/search-filter/search-range-filter/search-range-filter.component.spec.ts b/src/app/shared/search/search-filters/search-filter/search-range-filter/search-range-filter.component.spec.ts
index 530b4e6b712ce5d875a3e40766faeab5151c6488..72840b3ffe7628bc6740fd8d2a3a1488181adddb 100644
--- a/src/app/shared/search/search-filters/search-filter/search-range-filter/search-range-filter.component.spec.ts
+++ b/src/app/shared/search/search-filters/search-filter/search-range-filter/search-range-filter.component.spec.ts
@@ -45,17 +45,38 @@ describe('SearchRangeFilterComponent', () => {
       label: value1,
       value: value1,
       count: 52,
-      search: ''
+      _links: {
+        self: {
+          href:''
+        },
+        search: {
+          href: ''
+        }
+      }
     }, {
       label: value2,
       value: value2,
       count: 20,
-      search: ''
+      _links: {
+        self: {
+          href:''
+        },
+        search: {
+          href: ''
+        }
+      }
     }, {
       label: value3,
       value: value3,
       count: 5,
-      search: ''
+      _links: {
+        self: {
+          href:''
+        },
+        search: {
+          href: ''
+        }
+      }
     }
   ];
 
diff --git a/src/app/shared/search/search-options.model.ts b/src/app/shared/search/search-options.model.ts
index 4dc92c32f4ccf313c420a6077dba281a0911bd32..a8b115abd31ba4bb04968db572c64d4c56d8179e 100644
--- a/src/app/shared/search/search-options.model.ts
+++ b/src/app/shared/search/search-options.model.ts
@@ -1,6 +1,5 @@
 import { isNotEmpty } from '../empty.util';
 import { URLCombiner } from '../../core/url-combiner/url-combiner';
-import 'core-js/library/fn/object/entries';
 import { SearchFilter } from './search-filter.model';
 import { DSpaceObjectType } from '../../core/shared/dspace-object-type.model';
 import { ViewMode } from '../../core/shared/view-mode.model';
diff --git a/src/app/shared/search/search-query-response.model.ts b/src/app/shared/search/search-query-response.model.ts
index da15a60631ca9724663af6df51084288e2e958d2..2c9d11e2b3e0ed92be2b6022cc86d9ba48aae585 100644
--- a/src/app/shared/search/search-query-response.model.ts
+++ b/src/app/shared/search/search-query-response.model.ts
@@ -1,6 +1,7 @@
 import { autoserialize, autoserializeAs } from 'cerialize';
+import { DSpaceObject } from '../../core/shared/dspace-object.model';
 import { PageInfo } from '../../core/shared/page-info.model';
-import { NormalizedSearchResult } from './normalized-search-result.model';
+import { SearchResult } from './search-result.model';
 
 /**
  * Class representing the response returned by the server when performing a search request
@@ -51,8 +52,8 @@ export class SearchQueryResponse {
   /**
    * The results for this query
    */
-  @autoserializeAs(NormalizedSearchResult)
-  objects: NormalizedSearchResult[];
+  @autoserializeAs(SearchResult)
+  objects: Array<SearchResult<DSpaceObject>>;
 
   @autoserialize
   facets: any; // TODO
diff --git a/src/app/shared/search/search-result.model.ts b/src/app/shared/search/search-result.model.ts
index 8d263950214505e6f56ab489f9b696c7d1287a8f..2f14a60c9707eb549e236b582f548b27f0b52aaf 100644
--- a/src/app/shared/search/search-result.model.ts
+++ b/src/app/shared/search/search-result.model.ts
@@ -1,25 +1,40 @@
+import { autoserialize, deserialize } from 'cerialize';
+import { link } from '../../core/cache/builders/build-decorators';
 import { DSpaceObject } from '../../core/shared/dspace-object.model';
+import { DSPACE_OBJECT } from '../../core/shared/dspace-object.resource-type';
+import { GenericConstructor } from '../../core/shared/generic-constructor';
+import { HALLink } from '../../core/shared/hal-link.model';
 import { MetadataMap } from '../../core/shared/metadata.models';
-import { ListableObject } from '../object-collection/shared/listable-object.model';
 import { excludeFromEquals, fieldsForEquals } from '../../core/utilities/equals.decorators';
-import { GenericConstructor } from '../../core/shared/generic-constructor';
+import { ListableObject } from '../object-collection/shared/listable-object.model';
 
 /**
  * Represents a search result object of a certain (<T>) DSpaceObject
  */
 export class SearchResult<T extends DSpaceObject> extends ListableObject {
-  /**
-   * The DSpaceObject that was found
-   */
-  @fieldsForEquals('uuid')
-  indexableObject: T;
-
   /**
    * The metadata that was used to find this item, hithighlighted
    */
   @excludeFromEquals
+  @autoserialize
   hitHighlights: MetadataMap;
 
+  /**
+   * The {@link HALLink}s for this SearchResult
+   */
+  @deserialize
+  _links: {
+    self: HALLink;
+    indexableObject: HALLink;
+  };
+
+  /**
+   * The DSpaceObject that was found
+   */
+  @fieldsForEquals('uuid')
+  @link(DSPACE_OBJECT)
+  indexableObject: T;
+
   /**
    * Method that returns as which type of object this object should be rendered
    */
diff --git a/src/app/shared/search/search-results/search-results.component.spec.ts b/src/app/shared/search/search-results/search-results.component.spec.ts
index d2c02717c94d4454eab6eb39cc1da70f5f41fb99..60e91d6fc1e347f88b29937cd2ef14532592c100 100644
--- a/src/app/shared/search/search-results/search-results.component.spec.ts
+++ b/src/app/shared/search/search-results/search-results.component.spec.ts
@@ -111,7 +111,11 @@ export const objects = [
         scheduler: null
       }
     },
-    self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/communities/7669c72a-3f2a-451f-a3b9-9210e7a4c02f',
+    _links: {
+      self: {
+        href: 'https://dspace7.4science.it/dspace-spring-rest/api/core/communities/7669c72a-3f2a-451f-a3b9-9210e7a4c02f',
+      },
+    },
     id: '7669c72a-3f2a-451f-a3b9-9210e7a4c02f',
     uuid: '7669c72a-3f2a-451f-a3b9-9210e7a4c02f',
     type: Community.type,
@@ -165,7 +169,11 @@ export const objects = [
           scheduler: null
         }
       },
-      self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/communities/9076bd16-e69a-48d6-9e41-0238cb40d863',
+      _links: {
+        self: {
+          href: 'https://dspace7.4science.it/dspace-spring-rest/api/core/communities/9076bd16-e69a-48d6-9e41-0238cb40d863',
+        },
+      },
       id: '9076bd16-e69a-48d6-9e41-0238cb40d863',
       uuid: '9076bd16-e69a-48d6-9e41-0238cb40d863',
       type: Community.type,
diff --git a/src/app/shared/search/search-sidebar/search-sidebar.component.spec.ts b/src/app/shared/search/search-sidebar/search-sidebar.component.spec.ts
index 6586254227006b0fc6df72c7d72de2312d11ec10..f05b33ff88ab1b34e700f74fe345e94a6272c34f 100644
--- a/src/app/shared/search/search-sidebar/search-sidebar.component.spec.ts
+++ b/src/app/shared/search/search-sidebar/search-sidebar.component.spec.ts
@@ -12,7 +12,7 @@ describe('SearchSidebarComponent', () => {
   // async beforeEach
   beforeEach(async(() => {
     TestBed.configureTestingModule({
-      imports: [TranslateModule.forRoot(), NgbCollapseModule.forRoot()],
+      imports: [TranslateModule.forRoot(), NgbCollapseModule],
       declarations: [SearchSidebarComponent],
       schemas: [NO_ERRORS_SCHEMA],
     })
diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts
index cd6417d964fd4420bf58319c5d57da9c2215e382..1f2f87576c80d66bd284631a301c21e236780712 100644
--- a/src/app/shared/shared.module.ts
+++ b/src/app/shared/shared.module.ts
@@ -66,7 +66,6 @@ import { DsDynamicFormGroupComponent } from './form/builder/ds-dynamic-form-ui/m
 import { DsDynamicFormArrayComponent } from './form/builder/ds-dynamic-form-ui/models/array-group/dynamic-form-array.component';
 import { DsDynamicRelationGroupComponent } from './form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.components';
 import { DsDatePickerInlineComponent } from './form/builder/ds-dynamic-form-ui/models/date-picker-inline/dynamic-date-picker-inline.component';
-import { SortablejsModule } from 'angular-sortablejs';
 import { NumberPickerComponent } from './number-picker/number-picker.component';
 import { DsDatePickerComponent } from './form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component';
 import { DsDynamicLookupComponent } from './form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component';
@@ -177,6 +176,7 @@ import { ExternalSourceEntryImportModalComponent } from './form/builder/ds-dynam
 import { ImportableListItemControlComponent } from './object-collection/shared/importable-list-item-control/importable-list-item-control.component';
 import { DragDropModule } from '@angular/cdk/drag-drop';
 import { ExistingMetadataListElementComponent } from './form/builder/ds-dynamic-form-ui/existing-metadata-list-element/existing-metadata-list-element.component';
+import { SortablejsModule } from 'ngx-sortablejs';
 import { CustomSwitchComponent } from './form/builder/ds-dynamic-form-ui/models/custom-switch/custom-switch.component';
 
 const MODULES = [
diff --git a/src/app/shared/starts-with/date/starts-with-date.component.spec.ts b/src/app/shared/starts-with/date/starts-with-date.component.spec.ts
index 88a10990726dd209353537c7f69cf6a75bdadcdd..533724f5cb6045db2495bba8d30d121072585d41 100644
--- a/src/app/shared/starts-with/date/starts-with-date.component.spec.ts
+++ b/src/app/shared/starts-with/date/starts-with-date.component.spec.ts
@@ -27,7 +27,7 @@ describe('StartsWithDateComponent', () => {
 
   beforeEach(async(() => {
     TestBed.configureTestingModule({
-      imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule.forRoot()],
+      imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule],
       declarations: [StartsWithDateComponent, EnumKeysPipe],
       providers: [
         { provide: 'startsWithOptions', useValue: options },
diff --git a/src/app/shared/starts-with/text/starts-with-text.component.spec.ts b/src/app/shared/starts-with/text/starts-with-text.component.spec.ts
index 590b46f6dee6980fbfe86b4874327f7c0a201d0a..bc9c21aab82a772f2d6fc3e9bfde6710eb1728c8 100644
--- a/src/app/shared/starts-with/text/starts-with-text.component.spec.ts
+++ b/src/app/shared/starts-with/text/starts-with-text.component.spec.ts
@@ -19,7 +19,7 @@ describe('StartsWithTextComponent', () => {
 
   beforeEach(async(() => {
     TestBed.configureTestingModule({
-      imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule.forRoot()],
+      imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule],
       declarations: [StartsWithTextComponent, EnumKeysPipe],
       providers: [
         { provide: 'startsWithOptions', useValue: options }
diff --git a/src/app/shared/testing/auth-request-service-stub.ts b/src/app/shared/testing/auth-request-service-stub.ts
index 82ce682a9b427d11db5cc67116f8fa18f90eb1b0..b32b5395baee1f122f8dbeb90dccf0f2800371ae 100644
--- a/src/app/shared/testing/auth-request-service-stub.ts
+++ b/src/app/shared/testing/auth-request-service-stub.ts
@@ -5,8 +5,6 @@ import { AuthTokenInfo } from '../../core/auth/models/auth-token-info.model';
 import { EPerson } from '../../core/eperson/models/eperson.model';
 import { isNotEmpty } from '../empty.util';
 import { EPersonMock } from './eperson-mock';
-import { RemoteData } from '../../core/data/remote-data';
-import { createSuccessfulRemoteDataObject$ } from './utils';
 
 export class AuthRequestServiceStub {
   protected mockUser: EPerson = EPersonMock;
@@ -28,7 +26,14 @@ export class AuthRequestServiceStub {
       if (this.validateToken(token)) {
         authStatusStub.authenticated = true;
         authStatusStub.token = this.mockTokenInfo;
-        authStatusStub.eperson = createSuccessfulRemoteDataObject$(this.mockUser);
+        authStatusStub._links = {
+          self: {
+            href: 'dspace.org/api/status',
+          },
+          eperson: {
+            href: this.mockUser._links.self.href
+          }
+        };
       } else {
         authStatusStub.authenticated = false;
       }
@@ -47,7 +52,14 @@ export class AuthRequestServiceStub {
         if (this.validateToken(token)) {
           authStatusStub.authenticated = true;
           authStatusStub.token = this.mockTokenInfo;
-          authStatusStub.eperson = createSuccessfulRemoteDataObject$(this.mockUser);
+          authStatusStub._links = {
+            self: {
+              href: 'dspace.org/api/status',
+            },
+            eperson: {
+              href: this.mockUser._links.self.href
+            }
+          };
         } else {
           authStatusStub.authenticated = false;
         }
diff --git a/src/app/shared/testing/auth-service-stub.ts b/src/app/shared/testing/auth-service-stub.ts
index a6d24d5c8b2aec41f3d6fdecf43d914368cb3a56..a3c6351ccde8ae13205049a751e7f80c5759d515 100644
--- a/src/app/shared/testing/auth-service-stub.ts
+++ b/src/app/shared/testing/auth-service-stub.ts
@@ -3,7 +3,6 @@ import { AuthStatus } from '../../core/auth/models/auth-status.model';
 import { AuthTokenInfo } from '../../core/auth/models/auth-token-info.model';
 import { EPersonMock } from './eperson-mock';
 import { EPerson } from '../../core/eperson/models/eperson.model';
-import { RemoteData } from '../../core/data/remote-data';
 import { createSuccessfulRemoteDataObject$ } from './utils';
 
 export class AuthServiceStub {
@@ -30,14 +29,18 @@ export class AuthServiceStub {
     }
   }
 
-  public authenticatedUser(token: AuthTokenInfo): Observable<EPerson> {
+  public authenticatedUser(token: AuthTokenInfo): Observable<string> {
     if (token.accessToken === 'token_test') {
-      return observableOf(EPersonMock);
+      return observableOf(EPersonMock._links.self.href);
     } else {
       throw(new Error('Message Error test'));
     }
   }
 
+  public retrieveAuthenticatedUserByHref(href: string): Observable<EPerson> {
+    return observableOf(EPersonMock);
+  }
+
   public buildAuthHeader(token?: AuthTokenInfo): string {
     return `Bearer ${token.accessToken}`;
   }
diff --git a/src/app/shared/testing/eperson-mock.ts b/src/app/shared/testing/eperson-mock.ts
index c822fc15d68b10d56dccc27f77121b53ffbf7d43..44585f278f26c136b46a816c6872fe452a4d6067 100644
--- a/src/app/shared/testing/eperson-mock.ts
+++ b/src/app/shared/testing/eperson-mock.ts
@@ -9,7 +9,11 @@ export const EPersonMock: EPerson = Object.assign(new EPerson(),{
   email: 'test@test.com',
   requireCertificate: false,
   selfRegistered: false,
-  self: 'https://dspace.4science.it/dspace-spring-rest/api/eperson/epersons/testid',
+  _links: {
+    self: {
+      href: 'https://dspace.4science.it/dspace-spring-rest/api/eperson/epersons/testid',
+    }
+  },
   id: 'testid',
   uuid: 'testid',
   type: 'eperson',
diff --git a/src/app/shared/testing/test-module.ts b/src/app/shared/testing/test-module.ts
index 8f59d76c875ea69faed3fdec840b613f43ae17bf..f25fda8d723b05b01a2b65894c2ed03a0404e152 100644
--- a/src/app/shared/testing/test-module.ts
+++ b/src/app/shared/testing/test-module.ts
@@ -1,10 +1,10 @@
-import {CUSTOM_ELEMENTS_SCHEMA, NgModule} from '@angular/core';
-import { QueryParamsDirectiveStub } from './query-params-directive-stub';
+import { CommonModule } from '@angular/common';
+import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
 import { MySimpleItemActionComponent } from '../../+item-page/edit-item-page/simple-item-action/abstract-simple-item-action.component.spec';
-import {CommonModule} from '@angular/common';
-import {SharedModule} from '../shared.module';
-import { RouterLinkDirectiveStub } from './router-link-directive-stub';
+import { SharedModule } from '../shared.module';
 import { NgComponentOutletDirectiveStub } from './ng-component-outlet-directive-stub';
+import { QueryParamsDirectiveStub } from './query-params-directive-stub';
+import { RouterLinkDirectiveStub } from './router-link-directive-stub';
 
 /**
  * This module isn't used. It serves to prevent the AoT compiler
@@ -26,4 +26,5 @@ import { NgComponentOutletDirectiveStub } from './ng-component-outlet-directive-
     CUSTOM_ELEMENTS_SCHEMA
   ]
 })
-export class TestModule {}
+export class TestModule {
+}
diff --git a/src/app/shared/utils/follow-link-config.model.ts b/src/app/shared/utils/follow-link-config.model.ts
new file mode 100644
index 0000000000000000000000000000000000000000..21df288690262d4b2f301fe14a2149722a7398a1
--- /dev/null
+++ b/src/app/shared/utils/follow-link-config.model.ts
@@ -0,0 +1,50 @@
+import { FindListOptions } from '../../core/data/request.models';
+import { HALResource } from '../../core/shared/hal-resource.model';
+
+/**
+ * A class to configure the retrieval of a {@link HALLink}
+ */
+export class FollowLinkConfig<R extends HALResource> {
+  /**
+   * The name of the link to fetch.
+   * Can only be a {@link HALLink} of the object you're working with
+   */
+  name: keyof R['_links'];
+
+  /**
+   * {@link FindListOptions} for the query,
+   * allows you to resolve the link using a certain page, or sorted
+   * in a certain way
+   */
+  findListOptions?: FindListOptions;
+
+  /**
+   * A list of {@link FollowLinkConfig}s to
+   * use on the retrieved object.
+   */
+  linksToFollow?: Array<FollowLinkConfig<any>>;
+}
+
+/**
+ * A factory function for {@link FollowLinkConfig}s,
+ * in order to create them in a less verbose way.
+ *
+ * @param linkName: the name of the link to fetch.
+ * Can only be a {@link HALLink} of the object you're working with
+ * @param findListOptions: {@link FindListOptions} for the query,
+ * allows you to resolve the link using a certain page, or sorted
+ * in a certain way
+ * @param linksToFollow: a list of {@link FollowLinkConfig}s to
+ * use on the retrieved object.
+ */
+export const followLink = <R extends HALResource>(
+  linkName: keyof R['_links'],
+  findListOptions?: FindListOptions,
+  ...linksToFollow: Array<FollowLinkConfig<any>>
+): FollowLinkConfig<R> => {
+  return {
+    name: linkName,
+    findListOptions,
+    linksToFollow
+  }
+};
diff --git a/src/app/submission/edit/submission-edit.component.spec.ts b/src/app/submission/edit/submission-edit.component.spec.ts
index 115016d2feb89f8d6505213a8d830fc01de55c48..3b8695b0233219b9c61ce694e0befdb7290abcb4 100644
--- a/src/app/submission/edit/submission-edit.component.spec.ts
+++ b/src/app/submission/edit/submission-edit.component.spec.ts
@@ -74,7 +74,7 @@ describe('SubmissionEditComponent Component', () => {
 
     expect(comp.submissionId).toBe(submissionId);
     expect(comp.collectionId).toBe(submissionObject.collection.id);
-    expect(comp.selfUrl).toBe(submissionObject.self);
+    expect(comp.selfUrl).toBe(submissionObject._links.self.href);
     expect(comp.sections).toBe(submissionObject.sections);
     expect(comp.submissionDefinition).toBe(submissionObject.submissionDefinition);
 
diff --git a/src/app/submission/edit/submission-edit.component.ts b/src/app/submission/edit/submission-edit.component.ts
index 60c8b9a7a398c2e78f845ee23ed5ffbf90589cc3..908f473136b2c042f0d0707cd0a6d9fc1a7e6074 100644
--- a/src/app/submission/edit/submission-edit.component.ts
+++ b/src/app/submission/edit/submission-edit.component.ts
@@ -94,7 +94,7 @@ export class SubmissionEditComponent implements OnDestroy, OnInit {
         } else {
           this.submissionId = submissionObjectRD.payload.id.toString();
           this.collectionId = (submissionObjectRD.payload.collection as Collection).id;
-          this.selfUrl = submissionObjectRD.payload.self;
+          this.selfUrl = submissionObjectRD.payload._links.self.href;
           this.sections = submissionObjectRD.payload.sections;
           this.submissionDefinition = (submissionObjectRD.payload.submissionDefinition as SubmissionDefinitionsModel);
           this.changeDetectorRef.detectChanges();
diff --git a/src/app/submission/form/collection/submission-form-collection.component.spec.ts b/src/app/submission/form/collection/submission-form-collection.component.spec.ts
index 8539560d26b7143be63a50e6d46e68e9e14993c2..ff91d86736b7396c0b733b2fa9c5e7c99cf6ae44 100644
--- a/src/app/submission/form/collection/submission-form-collection.component.spec.ts
+++ b/src/app/submission/form/collection/submission-form-collection.component.spec.ts
@@ -222,7 +222,7 @@ describe('SubmissionFormCollectionComponent Component', () => {
       imports: [
         FormsModule,
         ReactiveFormsModule,
-        NgbModule.forRoot(),
+        NgbModule,
         TranslateModule.forRoot()
       ],
       declarations: [
diff --git a/src/app/submission/form/footer/submission-form-footer.component.spec.ts b/src/app/submission/form/footer/submission-form-footer.component.spec.ts
index 5fbfd84cb89c4c91ac1fd97d2c405a2e8ba0e1a2..d786faeee8cbebad7b5812ad8616d8627c7888e4 100644
--- a/src/app/submission/form/footer/submission-form-footer.component.spec.ts
+++ b/src/app/submission/form/footer/submission-form-footer.component.spec.ts
@@ -34,7 +34,7 @@ describe('SubmissionFormFooterComponent Component', () => {
   beforeEach(async(() => {
     TestBed.configureTestingModule({
       imports: [
-        NgbModule.forRoot(),
+        NgbModule,
         TranslateModule.forRoot()
       ],
       declarations: [
@@ -188,7 +188,7 @@ describe('SubmissionFormFooterComponent Component', () => {
       expect(submissionServiceStub.dispatchDeposit).toHaveBeenCalledWith(submissionId);
     });
 
-    it('should call dispatchDiscard on discard confirmation', fakeAsync(() => {
+    it('should call dispatchDiscard on discard confirmation', () => {
       comp.showDepositAndDiscard = observableOf(true);
       fixture.detectChanges();
       const modalBtn = fixture.debugElement.query(By.css('.btn-danger'));
@@ -204,7 +204,7 @@ describe('SubmissionFormFooterComponent Component', () => {
       fixture.whenStable().then(() => {
         expect(submissionServiceStub.dispatchDiscard).toHaveBeenCalledWith(submissionId);
       });
-    }));
+    });
 
     it('should have deposit button disabled when submission is not valid', () => {
       comp.showDepositAndDiscard = observableOf(true);
diff --git a/src/app/submission/form/section-add/submission-form-section-add.component.spec.ts b/src/app/submission/form/section-add/submission-form-section-add.component.spec.ts
index 236bd6de9b4cd44e46bfb3e879e238f9a224a275..5a2978b17c0fd38ab7f227c7c63aa60ca0b8f30b 100644
--- a/src/app/submission/form/section-add/submission-form-section-add.component.spec.ts
+++ b/src/app/submission/form/section-add/submission-form-section-add.component.spec.ts
@@ -59,7 +59,7 @@ describe('SubmissionFormSectionAddComponent Component', () => {
   beforeEach(async(() => {
     TestBed.configureTestingModule({
       imports: [
-        NgbModule.forRoot(),
+        NgbModule,
         TranslateModule.forRoot()
       ],
       declarations: [
diff --git a/src/app/submission/form/submission-form.component.ts b/src/app/submission/form/submission-form.component.ts
index 3ea07f9ae76220218e9235e79be5675c47eae650..0b8cfce6191540b85723c480e1589f0a3638e357 100644
--- a/src/app/submission/form/submission-form.component.ts
+++ b/src/app/submission/form/submission-form.component.ts
@@ -1,19 +1,19 @@
 import { ChangeDetectorRef, Component, Input, OnChanges, OnDestroy, SimpleChanges } from '@angular/core';
 
-import { of as observableOf, Observable, Subscription } from 'rxjs';
-import { distinctUntilChanged, filter, flatMap, map, switchMap } from 'rxjs/operators';
+import { Observable, of as observableOf, Subscription } from 'rxjs';
+import { distinctUntilChanged, filter, map, switchMap } from 'rxjs/operators';
+import { AuthService } from '../../core/auth/auth.service';
+import { SubmissionDefinitionsModel } from '../../core/config/models/config-submission-definitions.model';
+import { Collection } from '../../core/shared/collection.model';
+import { HALEndpointService } from '../../core/shared/hal-endpoint.service';
+import { SubmissionObject } from '../../core/submission/models/submission-object.model';
+import { WorkspaceitemSectionsObject } from '../../core/submission/models/workspaceitem-sections.model';
 
 import { hasValue, isNotEmpty } from '../../shared/empty.util';
+import { UploaderOptions } from '../../shared/uploader/uploader-options.model';
 import { SubmissionObjectEntry } from '../objects/submission-objects.reducer';
-import { WorkspaceitemSectionsObject } from '../../core/submission/models/workspaceitem-sections.model';
-import { SubmissionDefinitionsModel } from '../../core/config/models/config-submission-definitions.model';
-import { SubmissionService } from '../submission.service';
-import { AuthService } from '../../core/auth/auth.service';
 import { SectionDataObject } from '../sections/models/section-data.model';
-import { UploaderOptions } from '../../shared/uploader/uploader-options.model';
-import { HALEndpointService } from '../../core/shared/hal-endpoint.service';
-import { Collection } from '../../core/shared/collection.model';
-import { SubmissionObject } from '../../core/submission/models/submission-object.model';
+import { SubmissionService } from '../submission.service';
 
 /**
  * This component represents the submission form.
@@ -189,7 +189,7 @@ export class SubmissionFormComponent implements OnChanges, OnDestroy {
       this.submissionService.resetSubmissionObject(
         this.collectionId,
         this.submissionId,
-        submissionObject.self,
+        submissionObject._links.self.href,
         this.submissionDefinition,
         this.sections);
     } else {
diff --git a/src/app/submission/objects/submission-objects.actions.ts b/src/app/submission/objects/submission-objects.actions.ts
index 9bd88f035a50dcf65952779df4e18fa4eba4ba7e..57226fc531a5403835fbf42b906f06342ff6327e 100644
--- a/src/app/submission/objects/submission-objects.actions.ts
+++ b/src/app/submission/objects/submission-objects.actions.ts
@@ -796,4 +796,5 @@ export type SubmissionObjectAction = DisableSectionAction
   | SaveSubmissionSectionFormAction
   | SaveSubmissionSectionFormSuccessAction
   | SaveSubmissionSectionFormErrorAction
-  | SetActiveSectionAction;
+  | SetActiveSectionAction
+  | DepositSubmissionAction;
diff --git a/src/app/submission/objects/submission-objects.effects.spec.ts b/src/app/submission/objects/submission-objects.effects.spec.ts
index 8bbdd4e0eeff1c6e79520345e5849e2f1c2fa748..40c5cc9dd0ba20196d981633dc09474924f055ab 100644
--- a/src/app/submission/objects/submission-objects.effects.spec.ts
+++ b/src/app/submission/objects/submission-objects.effects.spec.ts
@@ -109,8 +109,8 @@ describe('SubmissionObjectEffects test suite', () => {
       const mappedActions = [];
       (submissionDefinitionResponse.sections as SubmissionSectionModel[])
         .forEach((sectionDefinition: SubmissionSectionModel) => {
-          const sectionId = sectionDefinition._links.self.substr(sectionDefinition._links.self.lastIndexOf('/') + 1);
-          const config = sectionDefinition._links.config || '';
+          const sectionId = sectionDefinition._links.self.href.substr(sectionDefinition._links.self.href.lastIndexOf('/') + 1);
+          const config = sectionDefinition._links.config.href || '';
           const enabled = (sectionDefinition.mandatory);
           const sectionData = {};
           const sectionErrors = null;
diff --git a/src/app/submission/objects/submission-objects.effects.ts b/src/app/submission/objects/submission-objects.effects.ts
index ba82fe1e650c1a5aa757218e3c22b8f778123aa8..a2a3350c6a3055fbcda0c1ffc30f5f8593cad311 100644
--- a/src/app/submission/objects/submission-objects.effects.ts
+++ b/src/app/submission/objects/submission-objects.effects.ts
@@ -1,10 +1,24 @@
 import { Injectable } from '@angular/core';
 import { Actions, Effect, ofType } from '@ngrx/effects';
+import { Store } from '@ngrx/store';
+import { TranslateService } from '@ngx-translate/core';
+import { union } from 'lodash';
 
 import { from as observableFrom, of as observableOf } from 'rxjs';
 import { catchError, map, mergeMap, switchMap, tap, withLatestFrom } from 'rxjs/operators';
-import { Store } from '@ngrx/store';
-import { union } from 'lodash';
+import { SubmissionObject } from '../../core/submission/models/submission-object.model';
+import { WorkflowItem } from '../../core/submission/models/workflowitem.model';
+import { WorkspaceitemSectionUploadObject } from '../../core/submission/models/workspaceitem-section-upload.model';
+import { WorkspaceitemSectionsObject } from '../../core/submission/models/workspaceitem-sections.model';
+import { WorkspaceItem } from '../../core/submission/models/workspaceitem.model';
+import { SubmissionJsonPatchOperationsService } from '../../core/submission/submission-json-patch-operations.service';
+import { isEmpty, isNotEmpty, isNotUndefined } from '../../shared/empty.util';
+import { NotificationsService } from '../../shared/notifications/notifications.service';
+import { SectionsType } from '../sections/sections-type';
+import { SectionsService } from '../sections/sections.service';
+import { SubmissionState } from '../submission.reducers';
+import { SubmissionService } from '../submission.service';
+import parseSectionErrors from '../utils/parseSectionErrors';
 
 import {
   CompleteInitSubmissionFormAction,
@@ -24,26 +38,12 @@ import {
   SaveSubmissionFormSuccessAction,
   SaveSubmissionSectionFormAction,
   SaveSubmissionSectionFormErrorAction,
-  SaveSubmissionSectionFormSuccessAction, SubmissionObjectAction,
+  SaveSubmissionSectionFormSuccessAction,
+  SubmissionObjectAction,
   SubmissionObjectActionTypes,
   UpdateSectionDataAction
 } from './submission-objects.actions';
-import { SectionsService } from '../sections/sections.service';
-import { isEmpty, isNotEmpty, isNotUndefined } from '../../shared/empty.util';
-import { WorkspaceItem } from '../../core/submission/models/workspaceitem.model';
-import { SubmissionService } from '../submission.service';
-import { WorkflowItem } from '../../core/submission/models/workflowitem.model';
-import { NotificationsService } from '../../shared/notifications/notifications.service';
-import { SubmissionObject } from '../../core/submission/models/submission-object.model';
-import { TranslateService } from '@ngx-translate/core';
-import { SubmissionState } from '../submission.reducers';
 import { SubmissionObjectEntry } from './submission-objects.reducer';
-import { SubmissionSectionModel } from '../../core/config/models/config-submission-section.model';
-import parseSectionErrors from '../utils/parseSectionErrors';
-import { WorkspaceitemSectionsObject } from '../../core/submission/models/workspaceitem-sections.model';
-import { WorkspaceitemSectionUploadObject } from '../../core/submission/models/workspaceitem-section-upload.model';
-import { SectionsType } from '../sections/sections-type';
-import { SubmissionJsonPatchOperationsService } from '../../core/submission/submission-json-patch-operations.service';
 
 @Injectable()
 export class SubmissionObjectEffects {
@@ -56,9 +56,10 @@ export class SubmissionObjectEffects {
     map((action: InitSubmissionFormAction) => {
       const definition = action.payload.submissionDefinition;
       const mappedActions = [];
-      definition.sections.page.forEach((sectionDefinition: SubmissionSectionModel) => {
-        const sectionId = sectionDefinition._links.self.substr(sectionDefinition._links.self.lastIndexOf('/') + 1);
-        const config = sectionDefinition._links.config || '';
+      definition.sections.page.forEach((sectionDefinition: any) => {
+        const selfLink = sectionDefinition._links.self.href || sectionDefinition._links.self;
+        const sectionId = selfLink.substr(selfLink.lastIndexOf('/') + 1);
+        const config = sectionDefinition._links.config ? (sectionDefinition._links.config.href || sectionDefinition._links.config) : '';
         const enabled = (sectionDefinition.mandatory) || (isNotEmpty(action.payload.sections) && action.payload.sections.hasOwnProperty(sectionId));
         const sectionData = (isNotUndefined(action.payload.sections) && isNotUndefined(action.payload.sections[sectionId])) ? action.payload.sections[sectionId] : Object.create(null);
         const sectionErrors = null;
diff --git a/src/app/submission/objects/submission-objects.reducer.spec.ts b/src/app/submission/objects/submission-objects.reducer.spec.ts
index a5e0be451b21b5023dcb26f89194051c1f006e67..7fdccf3ebb87a908b6606809a856332a604a10fb 100644
--- a/src/app/submission/objects/submission-objects.reducer.spec.ts
+++ b/src/app/submission/objects/submission-objects.reducer.spec.ts
@@ -22,14 +22,13 @@ import {
   SaveAndDepositSubmissionAction,
   SaveForLaterSubmissionFormAction,
   SaveForLaterSubmissionFormErrorAction,
-  SaveForLaterSubmissionFormSuccessAction,
   SaveSubmissionFormAction,
   SaveSubmissionFormErrorAction,
   SaveSubmissionFormSuccessAction,
   SaveSubmissionSectionFormAction,
   SaveSubmissionSectionFormErrorAction,
   SaveSubmissionSectionFormSuccessAction,
-  SectionStatusChangeAction,
+  SectionStatusChangeAction, SubmissionObjectAction,
   UpdateSectionDataAction
 } from './submission-objects.actions';
 import { SectionsType } from '../sections/sections-type';
@@ -117,7 +116,7 @@ describe('submissionReducer test suite', () => {
   });
 
   it('should set to true savePendig flag on save', () => {
-    let action = new SaveSubmissionFormAction(submissionId);
+    let action: SubmissionObjectAction = new SaveSubmissionFormAction(submissionId);
     let newState = submissionObjectReducer(initState, action);
 
     expect(newState[826].savePending).toBeTruthy();
@@ -273,7 +272,7 @@ describe('submissionReducer test suite', () => {
 
   it('should enable submission section properly', () => {
 
-    let action = new EnableSectionAction(submissionId, 'traditionalpagetwo');
+    let action: SubmissionObjectAction = new EnableSectionAction(submissionId, 'traditionalpagetwo');
     let newState = submissionObjectReducer(initState, action);
 
     action = new DisableSectionAction(submissionId, 'traditionalpagetwo');
diff --git a/src/app/submission/objects/submission-objects.reducer.ts b/src/app/submission/objects/submission-objects.reducer.ts
index 8c111dde671be341e027c27fa334411cc421180f..e0aeefd7b61045edae30edc8e3b274fab48e3dc2 100644
--- a/src/app/submission/objects/submission-objects.reducer.ts
+++ b/src/app/submission/objects/submission-objects.reducer.ts
@@ -548,7 +548,7 @@ function startDeposit(state: SubmissionObjectState, action: DepositSubmissionAct
  * @return SubmissionObjectState
  *    the new state, with the deposit flag changed.
  */
-function endDeposit(state: SubmissionObjectState, action: DepositSubmissionSuccessAction | DepositSubmissionErrorAction): SubmissionObjectState {
+function endDeposit(state: SubmissionObjectState, action: DepositSubmissionSuccessAction | DepositSubmissionErrorAction | DepositSubmissionAction): SubmissionObjectState {
   if (hasValue(state[ action.payload.submissionId ])) {
     return Object.assign({}, state, {
       [ action.payload.submissionId ]: Object.assign({}, state[ action.payload.submissionId ], {
diff --git a/src/app/submission/sections/container/section-container.component.scss b/src/app/submission/sections/container/section-container.component.scss
index 3917280f8cad54427cf321ffff727d169d744539..0255b71dac93c42634ac81ea4ce395e8de51bb68 100644
--- a/src/app/submission/sections/container/section-container.component.scss
+++ b/src/app/submission/sections/container/section-container.component.scss
@@ -1,4 +1,4 @@
-:host /deep/ .card {
+:host ::ng-deep .card {
   margin-bottom: $submission-sections-margin-bottom;
   overflow: unset;
 }
@@ -9,13 +9,13 @@
 }
 
 // TODO to remove the following when upgrading @ng-bootstrap
-:host /deep/ .card:first-of-type {
+:host ::ng-deep .card:first-of-type {
   border-bottom: $card-border-width solid  $card-border-color !important;
   border-bottom-left-radius: $card-border-radius !important;
   border-bottom-right-radius: $card-border-radius !important;
 }
 
-:host /deep/ .card-header button {
+:host ::ng-deep .card-header button {
   box-shadow: none !important;
   width: 100%;
 }
diff --git a/src/app/submission/sections/container/section-container.component.spec.ts b/src/app/submission/sections/container/section-container.component.spec.ts
index 778aa4ab8414cbde3f88ba3a4d77f6395bfbcf03..38b8572d0cc474e716173819a73716336b33ad64 100644
--- a/src/app/submission/sections/container/section-container.component.spec.ts
+++ b/src/app/submission/sections/container/section-container.component.spec.ts
@@ -67,7 +67,7 @@ describe('SubmissionSectionContainerComponent test suite', () => {
 
     TestBed.configureTestingModule({
       imports: [
-        NgbModule.forRoot(),
+        NgbModule,
         TranslateModule.forRoot()
       ],
       declarations: [
diff --git a/src/app/submission/sections/container/section-container.component.ts b/src/app/submission/sections/container/section-container.component.ts
index f040288667c0af33ecd0fd5985e1fa8d54ab0f98..a48bf8cb923734c2020629d175180d26d3d921a0 100644
--- a/src/app/submission/sections/container/section-container.component.ts
+++ b/src/app/submission/sections/container/section-container.component.ts
@@ -48,7 +48,7 @@ export class SubmissionSectionContainerComponent implements OnInit {
   /**
    * The SectionsDirective reference
    */
-  @ViewChild('sectionRef') sectionRef: SectionsDirective;
+  @ViewChild('sectionRef', {static: false}) sectionRef: SectionsDirective;
 
   /**
    * Initialize instance variables
diff --git a/src/app/submission/sections/form/section-form.component.spec.ts b/src/app/submission/sections/form/section-form.component.spec.ts
index be13c1494128882442a8652f087f52b85c9cd9ee..10f6655ce199d770079e1edd5235fcf91363f873 100644
--- a/src/app/submission/sections/form/section-form.component.spec.ts
+++ b/src/app/submission/sections/form/section-form.component.spec.ts
@@ -43,9 +43,6 @@ import { SubmissionSectionError } from '../../objects/submission-objects.reducer
 import { DynamicFormControlEvent, DynamicFormControlEventType } from '@ng-dynamic-forms/core';
 import { JsonPatchOperationPathCombiner } from '../../../core/json-patch/builder/json-patch-operation-path-combiner';
 import { FormRowModel } from '../../../core/config/models/config-submission-form.model';
-import { WorkspaceitemDataService } from '../../../core/submission/workspaceitem-data.service';
-import { RemoteData } from '../../../core/data/remote-data';
-import { WorkspaceItem } from '../../../core/submission/models/workspaceitem.model';
 
 function getMockSubmissionFormsConfigService(): SubmissionFormsConfigService {
   return jasmine.createSpyObj('FormOperationsService', {
@@ -108,10 +105,11 @@ const testFormConfiguration = {
       ]
     } as FormRowModel,
   ],
-  self: 'testFormConfiguration.url',
   type: 'submissionform',
   _links: {
-    self: 'testFormConfiguration.url'
+    self: {
+      href: 'testFormConfiguration.url'
+    }
   }
 } as any;
 
@@ -182,7 +180,6 @@ describe('SubmissionSectionformComponent test suite', () => {
         { provide: 'collectionIdProvider', useValue: collectionId },
         { provide: 'sectionDataProvider', useValue: sectionObject },
         { provide: 'submissionIdProvider', useValue: submissionId },
-        { provide: WorkspaceitemDataService, useValue: {findById: () => observableOf(new RemoteData(false, false, true, null, new WorkspaceItem()))}},
         ChangeDetectorRef,
         SubmissionSectionformComponent
       ],
diff --git a/src/app/submission/sections/form/section-form.component.ts b/src/app/submission/sections/form/section-form.component.ts
index 49dbaea807ccb8e9bbafeed70a6b240d684b1776..76e7339f1765572e615cd47705ea1dc2a79813d6 100644
--- a/src/app/submission/sections/form/section-form.component.ts
+++ b/src/app/submission/sections/form/section-form.component.ts
@@ -15,10 +15,7 @@ import { hasValue, isNotEmpty, isUndefined } from '../../../shared/empty.util';
 import { ConfigData } from '../../../core/config/config-data';
 import { JsonPatchOperationPathCombiner } from '../../../core/json-patch/builder/json-patch-operation-path-combiner';
 import { SubmissionFormsModel } from '../../../core/config/models/config-submission-forms.model';
-import {
-  SubmissionSectionError,
-  SubmissionSectionObject
-} from '../../objects/submission-objects.reducer';
+import { SubmissionSectionError, SubmissionSectionObject } from '../../objects/submission-objects.reducer';
 import { FormFieldPreviousValueObject } from '../../../shared/form/builder/models/form-field-previous-value-object';
 import { GLOBAL_CONFIG } from '../../../../config';
 import { GlobalConfig } from '../../../../config/global-config.interface';
@@ -31,11 +28,7 @@ import { NotificationsService } from '../../../shared/notifications/notification
 import { SectionsService } from '../sections.service';
 import { difference } from '../../../shared/object.util';
 import { WorkspaceitemSectionFormObject } from '../../../core/submission/models/workspaceitem-section-form.model';
-import { WorkspaceItem } from '../../../core/submission/models/workspaceitem.model';
 import { WorkspaceitemDataService } from '../../../core/submission/workspaceitem-data.service';
-import { combineLatest as combineLatestObservable } from 'rxjs';
-import { getSucceededRemoteData } from '../../../core/shared/operators';
-import { RemoteData } from '../../../core/data/remote-data';
 
 /**
  * This component represents a section that contains a Form.
@@ -108,11 +101,10 @@ export class SubmissionSectionformComponent extends SectionModelComponent {
    */
   protected subs: Subscription[] = [];
 
-  protected workspaceItem: WorkspaceItem;
   /**
    * The FormComponent reference
    */
-  @ViewChild('formRef') private formRef: FormComponent;
+  @ViewChild('formRef', {static: false}) private formRef: FormComponent;
 
   /**
    * Initialize instance variables
@@ -140,7 +132,6 @@ export class SubmissionSectionformComponent extends SectionModelComponent {
               protected sectionService: SectionsService,
               protected submissionService: SubmissionService,
               protected translate: TranslateService,
-              protected workspaceItemDataService: WorkspaceitemDataService,
               @Inject(GLOBAL_CONFIG) protected EnvConfig: GlobalConfig,
               @Inject('collectionIdProvider') public injectedCollectionId: string,
               @Inject('sectionDataProvider') public injectedSectionData: SectionDataObject,
@@ -157,16 +148,11 @@ export class SubmissionSectionformComponent extends SectionModelComponent {
     this.formConfigService.getConfigByHref(this.sectionData.config).pipe(
       map((configData: ConfigData) => configData.payload),
       tap((config: SubmissionFormsModel) => this.formConfig = config),
-      flatMap(() =>
-        combineLatestObservable(
-          this.sectionService.getSectionData(this.submissionId, this.sectionData.id),
-          this.workspaceItemDataService.findById(this.submissionId).pipe(getSucceededRemoteData(), map((wsiRD: RemoteData<WorkspaceItem>) => wsiRD.payload))
-        )),
+      flatMap(() => this.sectionService.getSectionData(this.submissionId, this.sectionData.id)),
       take(1))
-      .subscribe(([sectionData, workspaceItem]: [WorkspaceitemSectionFormObject, WorkspaceItem]) => {
+      .subscribe((sectionData: WorkspaceitemSectionFormObject) => {
         if (isUndefined(this.formModel)) {
           this.sectionData.errors = [];
-          this.workspaceItem = workspaceItem;
           // Is the first loading so init form
           this.initForm(sectionData);
           this.sectionData.data = sectionData;
diff --git a/src/app/submission/sections/license/section-license.component.ts b/src/app/submission/sections/license/section-license.component.ts
index 940460c83d4fe1dd517152fa89e601e08650234c..e6915112e5fb76f2c6ed6df8a85075b838df31d4 100644
--- a/src/app/submission/sections/license/section-license.component.ts
+++ b/src/app/submission/sections/license/section-license.component.ts
@@ -1,7 +1,4 @@
 import { ChangeDetectorRef, Component, Inject, ViewChild } from '@angular/core';
-
-import { Observable, Subscription } from 'rxjs';
-import { distinctUntilChanged, filter, find, flatMap, map, startWith, take } from 'rxjs/operators';
 import {
   DynamicCheckboxModel,
   DynamicFormControlEvent,
@@ -9,25 +6,29 @@ import {
   DynamicFormLayout
 } from '@ng-dynamic-forms/core';
 
-import { SectionModelComponent } from '../models/section.model';
-import { JsonPatchOperationsBuilder } from '../../../core/json-patch/builder/json-patch-operations-builder';
+import { Observable, Subscription } from 'rxjs';
+import { distinctUntilChanged, filter, find, flatMap, map, startWith, take } from 'rxjs/operators';
 import { CollectionDataService } from '../../../core/data/collection-data.service';
-import { hasValue, isNotEmpty, isNotNull, isNotUndefined } from '../../../shared/empty.util';
-import { License } from '../../../core/shared/license.model';
 import { RemoteData } from '../../../core/data/remote-data';
+import { JsonPatchOperationPathCombiner } from '../../../core/json-patch/builder/json-patch-operation-path-combiner';
+import { JsonPatchOperationsBuilder } from '../../../core/json-patch/builder/json-patch-operations-builder';
 import { Collection } from '../../../core/shared/collection.model';
-import { SECTION_LICENSE_FORM_LAYOUT, SECTION_LICENSE_FORM_MODEL } from './section-license.model';
+import { License } from '../../../core/shared/license.model';
+import { WorkspaceitemSectionLicenseObject } from '../../../core/submission/models/workspaceitem-section-license.model';
+import { hasValue, isNotEmpty, isNotNull, isNotUndefined } from '../../../shared/empty.util';
 import { FormBuilderService } from '../../../shared/form/builder/form-builder.service';
+import { FormComponent } from '../../../shared/form/form.component';
 import { FormService } from '../../../shared/form/form.service';
-import { JsonPatchOperationPathCombiner } from '../../../core/json-patch/builder/json-patch-operation-path-combiner';
-import { SectionsType } from '../sections-type';
-import { renderSectionFor } from '../sections-decorator';
-import { SectionDataObject } from '../models/section-data.model';
-import { WorkspaceitemSectionLicenseObject } from '../../../core/submission/models/workspaceitem-section-license.model';
+import { followLink } from '../../../shared/utils/follow-link-config.model';
 import { SubmissionService } from '../../submission.service';
-import { SectionsService } from '../sections.service';
 import { SectionFormOperationsService } from '../form/section-form-operations.service';
-import { FormComponent } from '../../../shared/form/form.component';
+import { SectionDataObject } from '../models/section-data.model';
+
+import { SectionModelComponent } from '../models/section.model';
+import { renderSectionFor } from '../sections-decorator';
+import { SectionsType } from '../sections-type';
+import { SectionsService } from '../sections.service';
+import { SECTION_LICENSE_FORM_LAYOUT, SECTION_LICENSE_FORM_MODEL } from './section-license.model';
 
 /**
  * This component represents a section that contains the submission license form.
@@ -85,7 +86,7 @@ export class SubmissionSectionLicenseComponent extends SectionModelComponent {
   /**
    * The FormComponent reference
    */
-  @ViewChild('formRef') private formRef: FormComponent;
+  @ViewChild('formRef', {static: false}) private formRef: FormComponent;
 
   /**
    * Initialize instance variables
@@ -132,9 +133,9 @@ export class SubmissionSectionLicenseComponent extends SectionModelComponent {
       (model as DynamicCheckboxModel).valueUpdates.next(false);
     }
 
-    this.licenseText$ = this.collectionDataService.findById(this.collectionId).pipe(
+    this.licenseText$ = this.collectionDataService.findById(this.collectionId, followLink('license')).pipe(
       filter((collectionData: RemoteData<Collection>) => isNotUndefined((collectionData.payload))),
-      flatMap((collectionData: RemoteData<Collection>) => collectionData.payload.license),
+      flatMap((collectionData: RemoteData<Collection>) => (collectionData.payload as any).license),
       find((licenseData: RemoteData<License>) => isNotUndefined((licenseData.payload))),
       map((licenseData: RemoteData<License>) => licenseData.payload.text),
       startWith(''));
diff --git a/src/app/submission/sections/upload/accessConditions/submission-section-upload-access-conditions.component.ts b/src/app/submission/sections/upload/accessConditions/submission-section-upload-access-conditions.component.ts
index 43b0a7da3f8d075a276b1375d30b0ec6b1ad8e58..04852cc0144f0fdb457877e3378ed355707f3412 100644
--- a/src/app/submission/sections/upload/accessConditions/submission-section-upload-access-conditions.component.ts
+++ b/src/app/submission/sections/upload/accessConditions/submission-section-upload-access-conditions.component.ts
@@ -2,7 +2,7 @@ import { Component, Input, OnInit } from '@angular/core';
 
 import { find } from 'rxjs/operators';
 
-import { GroupEpersonService } from '../../../../core/eperson/group-eperson.service';
+import { GroupDataService } from '../../../../core/eperson/group-data.service';
 import { ResourcePolicy } from '../../../../core/shared/resource-policy.model';
 import { isEmpty } from '../../../../shared/empty.util';
 import { Group } from '../../../../core/eperson/models/group.model';
@@ -32,9 +32,9 @@ export class SubmissionSectionUploadAccessConditionsComponent implements OnInit
   /**
    * Initialize instance variables
    *
-   * @param {GroupEpersonService} groupService
+   * @param {GroupDataService} groupService
    */
-  constructor(private groupService: GroupEpersonService) {}
+  constructor(private groupService: GroupDataService) {}
 
   /**
    * Retrieve access conditions list
diff --git a/src/app/submission/sections/upload/file/edit/section-upload-file-edit.component.ts b/src/app/submission/sections/upload/file/edit/section-upload-file-edit.component.ts
index 8cf0d22d2072d2a7a36db3949b010ac7510033f3..217754b42e125a8b598dd45d7eaff15d47a7680d 100644
--- a/src/app/submission/sections/upload/file/edit/section-upload-file-edit.component.ts
+++ b/src/app/submission/sections/upload/file/edit/section-upload-file-edit.component.ts
@@ -10,7 +10,9 @@ import {
   DynamicFormControlEvent,
   DynamicFormControlModel,
   DynamicFormGroupModel,
-  DynamicSelectModel
+  DynamicSelectModel,
+  MATCH_ENABLED,
+  OR_OPERATOR
 } from '@ng-dynamic-forms/core';
 
 import { WorkspaceitemSectionUploadFileObject } from '../../../../../core/submission/models/workspaceitem-section-upload-file.model';
@@ -125,7 +127,7 @@ export class SubmissionSectionUploadFileEditComponent implements OnChanges {
   /**
    * The FormComponent reference
    */
-  @ViewChild('formRef') public formRef: FormComponent;
+  @ViewChild('formRef', {static: false}) public formRef: FormComponent;
 
   /**
    * Initialize instance variables
@@ -206,9 +208,9 @@ export class SubmissionSectionUploadFileEditComponent implements OnChanges {
           hasGroups.push({ id: 'name', value: condition.name });
         }
       });
-      const confStart = { relation: [{ action: 'ENABLE', connective: 'OR', when: hasStart }] };
-      const confEnd = { relation: [{ action: 'ENABLE', connective: 'OR', when: hasEnd }] };
-      const confGroup = { relation: [{ action: 'ENABLE', connective: 'OR', when: hasGroups }] };
+      const confStart = { relations: [{ match: MATCH_ENABLED, operator: OR_OPERATOR, when: hasStart }] };
+      const confEnd = { relations: [{ match: MATCH_ENABLED, operator: OR_OPERATOR, when: hasEnd }] };
+      const confGroup = { relations: [{ match: MATCH_ENABLED, operator: OR_OPERATOR, when: hasGroups }] };
 
       accessConditionsArrayConfig.groupFactory = () => {
         const type = new DynamicSelectModel(accessConditionTypeModelConfig, BITSTREAM_FORM_ACCESS_CONDITION_TYPE_LAYOUT);
@@ -334,7 +336,7 @@ export class SubmissionSectionUploadFileEditComponent implements OnChanges {
             });
 
             // Due to a bug can't dynamically change the select options, so replace the model with a new one
-            const confGroup = { relation: groupModel.relation };
+            const confGroup = { relation: groupModel.relations };
             const groupsConfig = Object.assign({}, BITSTREAM_FORM_ACCESS_CONDITION_GROUPS_CONFIG, confGroup);
             groupsConfig.options = groupOptions;
             (model.parent as DynamicFormGroupModel).group.pop();
diff --git a/src/app/submission/sections/upload/file/edit/section-upload-file-edit.model.ts b/src/app/submission/sections/upload/file/edit/section-upload-file-edit.model.ts
index ec72adf7864ed7ff9ace1fc4d8bcd9840f73462a..dd2ac7a2a74d56c4814cf870abe460a9db81bd57 100644
--- a/src/app/submission/sections/upload/file/edit/section-upload-file-edit.model.ts
+++ b/src/app/submission/sections/upload/file/edit/section-upload-file-edit.model.ts
@@ -1,8 +1,11 @@
 import {
   DynamicDatePickerModelConfig,
   DynamicFormArrayModelConfig,
+  DynamicFormControlLayout,
+  DynamicFormGroupModelConfig,
   DynamicSelectModelConfig,
-  DynamicFormGroupModelConfig, DynamicFormControlLayout,
+  MATCH_ENABLED,
+  OR_OPERATOR,
 } from '@ng-dynamic-forms/core';
 
 export const BITSTREAM_METADATA_FORM_GROUP_CONFIG: DynamicFormGroupModelConfig = {
@@ -15,7 +18,7 @@ export const BITSTREAM_METADATA_FORM_GROUP_LAYOUT: DynamicFormControlLayout = {
       label: 'col-form-label'
   },
   grid: {
-      label: 'col-sm-3'
+    label: 'col-sm-3'
   }
 };
 
@@ -50,10 +53,10 @@ export const BITSTREAM_FORM_ACCESS_CONDITION_START_DATE_CONFIG: DynamicDatePicke
   placeholder: 'submission.sections.upload.form.from-placeholder',
   inline: false,
   toggleIcon: 'far fa-calendar-alt',
-  relation: [
+  relations: [
     {
-      action: 'ENABLE',
-      connective: 'OR',
+      match: MATCH_ENABLED,
+      operator: OR_OPERATOR,
       when: []
     }
   ],
@@ -81,10 +84,10 @@ export const BITSTREAM_FORM_ACCESS_CONDITION_END_DATE_CONFIG: DynamicDatePickerM
   placeholder: 'submission.sections.upload.form.until-placeholder',
   inline: false,
   toggleIcon: 'far fa-calendar-alt',
-  relation: [
+  relations: [
     {
-      action: 'ENABLE',
-      connective: 'OR',
+      match: MATCH_ENABLED,
+      operator: OR_OPERATOR,
       when: []
     }
   ],
@@ -110,10 +113,10 @@ export const BITSTREAM_FORM_ACCESS_CONDITION_GROUPS_CONFIG: DynamicSelectModelCo
   id: 'groupUUID',
   label: 'submission.sections.upload.form.group-label',
   options: [],
-  relation: [
+  relations: [
     {
-      action: 'ENABLE',
-      connective: 'OR',
+      match: MATCH_ENABLED,
+      operator: OR_OPERATOR,
       when: []
     }
   ],
diff --git a/src/app/submission/sections/upload/file/section-upload-file.component.spec.ts b/src/app/submission/sections/upload/file/section-upload-file.component.spec.ts
index 54b51e7afc86911a17121f8f50d8989a03fb099e..4e0badb76d36f52c4de80d171bac6606fc152c2a 100644
--- a/src/app/submission/sections/upload/file/section-upload-file.component.spec.ts
+++ b/src/app/submission/sections/upload/file/section-upload-file.component.spec.ts
@@ -86,7 +86,7 @@ describe('SubmissionSectionUploadFileComponent test suite', () => {
       imports: [
         BrowserModule,
         CommonModule,
-        NgbModule.forRoot(),
+        NgbModule,
         TranslateModule.forRoot()
       ],
       declarations: [
@@ -190,7 +190,7 @@ describe('SubmissionSectionUploadFileComponent test suite', () => {
       expect(comp.fileData).toEqual(fileData);
     });
 
-    it('should call deleteFile on delete confirmation', fakeAsync(() => {
+    it('should call deleteFile on delete confirmation', () => {
       spyOn(compAsAny, 'deleteFile');
       comp.fileData = fileData;
 
@@ -209,7 +209,7 @@ describe('SubmissionSectionUploadFileComponent test suite', () => {
       fixture.whenStable().then(() => {
         expect(compAsAny.deleteFile).toHaveBeenCalled();
       });
-    }));
+    });
 
     it('should delete file properly', () => {
       compAsAny.pathCombiner = pathCombiner;
diff --git a/src/app/submission/sections/upload/file/section-upload-file.component.ts b/src/app/submission/sections/upload/file/section-upload-file.component.ts
index 9923c358e7f31d7c1bfc6f1b99f8626be5349ff1..c0ad31165b116ee99beef97bbb6e89e30b85ad81 100644
--- a/src/app/submission/sections/upload/file/section-upload-file.component.ts
+++ b/src/app/submission/sections/upload/file/section-upload-file.component.ts
@@ -141,7 +141,7 @@ export class SubmissionSectionUploadFileComponent implements OnChanges, OnInit {
    * The [[SubmissionSectionUploadFileEditComponent]] reference
    * @type {SubmissionSectionUploadFileEditComponent}
    */
-  @ViewChild(SubmissionSectionUploadFileEditComponent) fileEditComp: SubmissionSectionUploadFileEditComponent;
+  @ViewChild(SubmissionSectionUploadFileEditComponent, {static: false}) fileEditComp: SubmissionSectionUploadFileEditComponent;
 
   /**
    * Initialize instance variables
diff --git a/src/app/submission/sections/upload/section-upload.component.spec.ts b/src/app/submission/sections/upload/section-upload.component.spec.ts
index a58de09b8d0b6ed73d1ced48d63ef8e80ba8e538..af865b81ebd14a1dd8123ee9896939c0a5b5b9fb 100644
--- a/src/app/submission/sections/upload/section-upload.component.spec.ts
+++ b/src/app/submission/sections/upload/section-upload.component.spec.ts
@@ -27,7 +27,7 @@ import { SubmissionUploadsConfigService } from '../../../core/config/submission-
 import { SectionUploadService } from './section-upload.service';
 import { SubmissionSectionUploadComponent } from './section-upload.component';
 import { CollectionDataService } from '../../../core/data/collection-data.service';
-import { GroupEpersonService } from '../../../core/eperson/group-eperson.service';
+import { GroupDataService } from '../../../core/eperson/group-data.service';
 import { cold, hot } from 'jasmine-marbles';
 import { Collection } from '../../../core/shared/collection.model';
 import { ResourcePolicy } from '../../../core/shared/resource-policy.model';
@@ -52,8 +52,8 @@ function getMockCollectionDataService(): CollectionDataService {
   });
 }
 
-function getMockGroupEpersonService(): GroupEpersonService {
-  return jasmine.createSpyObj('GroupEpersonService', {
+function getMockGroupEpersonService(): GroupDataService {
+  return jasmine.createSpyObj('GroupDataService', {
     findById: jasmine.createSpy('findById'),
 
   });
@@ -134,7 +134,7 @@ describe('SubmissionSectionUploadComponent test suite', () => {
       ],
       providers: [
         { provide: CollectionDataService, useValue: getMockCollectionDataService() },
-        { provide: GroupEpersonService, useValue: getMockGroupEpersonService() },
+        { provide: GroupDataService, useValue: getMockGroupEpersonService() },
         { provide: ResourcePolicyService, useValue: getMockResourcePolicyService() },
         { provide: SubmissionUploadsConfigService, useValue: getMockSubmissionUploadsConfigService() },
         { provide: SectionsService, useClass: SectionsServiceStub },
@@ -181,7 +181,7 @@ describe('SubmissionSectionUploadComponent test suite', () => {
       submissionServiceStub = TestBed.get(SubmissionService);
       sectionsServiceStub = TestBed.get(SectionsService);
       collectionDataService = TestBed.get(CollectionDataService);
-      groupService = TestBed.get(GroupEpersonService);
+      groupService = TestBed.get(GroupDataService);
       resourcePolicyService = TestBed.get(ResourcePolicyService);
       uploadsConfigService = TestBed.get(SubmissionUploadsConfigService);
       bitstreamService = TestBed.get(SectionUploadService);
@@ -197,7 +197,9 @@ describe('SubmissionSectionUploadComponent test suite', () => {
 
       submissionServiceStub.getSubmissionObject.and.returnValue(observableOf(submissionState));
 
-      collectionDataService.findById.and.returnValue(createSuccessfulRemoteDataObject$(mockCollection));
+      collectionDataService.findById.and.returnValue(createSuccessfulRemoteDataObject$(Object.assign(new Collection(), mockCollection, {
+        defaultAccessConditions: createSuccessfulRemoteDataObject$(mockDefaultAccessCondition)
+      })));
 
       resourcePolicyService.findByHref.and.returnValue(createSuccessfulRemoteDataObject$(mockDefaultAccessCondition));
 
diff --git a/src/app/submission/sections/upload/section-upload.component.ts b/src/app/submission/sections/upload/section-upload.component.ts
index 6c2506b773111f8c0413dd7435ff921fc2305805..f8f096d4bd449773f8ebdca922e6215b6f0861a8 100644
--- a/src/app/submission/sections/upload/section-upload.component.ts
+++ b/src/app/submission/sections/upload/section-upload.component.ts
@@ -2,12 +2,13 @@ import { ChangeDetectorRef, Component, Inject } from '@angular/core';
 
 import { BehaviorSubject, combineLatest as observableCombineLatest, Observable, Subscription} from 'rxjs';
 import { distinctUntilChanged, filter, find, flatMap, map, reduce, take, tap } from 'rxjs/operators';
+import { followLink } from '../../../shared/utils/follow-link-config.model';
 
 import { SectionModelComponent } from '../models/section.model';
 import { hasValue, isNotEmpty, isNotUndefined, isUndefined } from '../../../shared/empty.util';
 import { SectionUploadService } from './section-upload.service';
 import { CollectionDataService } from '../../../core/data/collection-data.service';
-import { GroupEpersonService } from '../../../core/eperson/group-eperson.service';
+import { GroupDataService } from '../../../core/eperson/group-data.service';
 import { ResourcePolicyService } from '../../../core/data/resource-policy.service';
 import { SubmissionUploadsConfigService } from '../../../core/config/submission-uploads-config.service';
 import { SubmissionUploadsModel } from '../../../core/config/models/config-submission-uploads.model';
@@ -95,7 +96,7 @@ export class SubmissionSectionUploadComponent extends SectionModelComponent {
   public configMetadataForm$: Observable<SubmissionFormsModel>;
 
   /**
-   * List of available access conditions that could be setted to files
+   * List of available access conditions that could be set to files
    */
   public availableAccessConditionOptions: AccessConditionOption[];  // List of accessConditions that an user can select
 
@@ -122,7 +123,7 @@ export class SubmissionSectionUploadComponent extends SectionModelComponent {
    * @param {SectionUploadService} bitstreamService
    * @param {ChangeDetectorRef} changeDetectorRef
    * @param {CollectionDataService} collectionDataService
-   * @param {GroupEpersonService} groupService
+   * @param {GroupDataService} groupService
    * @param {ResourcePolicyService} resourcePolicyService
    * @param {SectionsService} sectionService
    * @param {SubmissionService} submissionService
@@ -133,7 +134,7 @@ export class SubmissionSectionUploadComponent extends SectionModelComponent {
   constructor(private bitstreamService: SectionUploadService,
               private changeDetectorRef: ChangeDetectorRef,
               private collectionDataService: CollectionDataService,
-              private groupService: GroupEpersonService,
+              private groupService: GroupDataService,
               private resourcePolicyService: ResourcePolicyService,
               protected sectionService: SectionsService,
               private submissionService: SubmissionService,
@@ -163,9 +164,10 @@ export class SubmissionSectionUploadComponent extends SectionModelComponent {
         flatMap((submissionObject: SubmissionObjectEntry) => this.collectionDataService.findById(submissionObject.collection)),
         filter((rd: RemoteData<Collection>) => isNotUndefined((rd.payload))),
         tap((collectionRemoteData: RemoteData<Collection>) => this.collectionName = collectionRemoteData.payload.name),
-        flatMap((collectionRemoteData: RemoteData<Collection>) => {
+        // TODO review this part when https://github.com/DSpace/dspace-angular/issues/575 is resolved
+/*        flatMap((collectionRemoteData: RemoteData<Collection>) => {
           return this.resourcePolicyService.findByHref(
-            (collectionRemoteData.payload as any)._links.defaultAccessConditions
+            (collectionRemoteData.payload as any)._links.defaultAccessConditions.href
           );
         }),
         filter((defaultAccessConditionsRemoteData: RemoteData<ResourcePolicy>) =>
@@ -175,7 +177,7 @@ export class SubmissionSectionUploadComponent extends SectionModelComponent {
             this.collectionDefaultAccessConditions = Array.isArray(defaultAccessConditionsRemoteData.payload)
               ? defaultAccessConditionsRemoteData.payload : [defaultAccessConditionsRemoteData.payload];
           }
-        }),
+        }),*/
         flatMap(() => config$),
         flatMap((config: SubmissionUploadsModel) => {
           this.required$.next(config.required);
diff --git a/src/app/submission/submit/submission-submit.component.spec.ts b/src/app/submission/submit/submission-submit.component.spec.ts
index ca3316669f54b8a43935e2694a38bd31be735546..809a4dd6273e131b3e62803265f118a4a479cf4c 100644
--- a/src/app/submission/submit/submission-submit.component.spec.ts
+++ b/src/app/submission/submit/submission-submit.component.spec.ts
@@ -68,7 +68,7 @@ describe('SubmissionSubmitComponent Component', () => {
 
     expect(comp.submissionId.toString()).toEqual(submissionId);
     expect(comp.collectionId).toBe(submissionObject.collection.id);
-    expect(comp.selfUrl).toBe(submissionObject.self);
+    expect(comp.selfUrl).toBe(submissionObject._links.self.href);
     expect(comp.submissionDefinition).toBe(submissionObject.submissionDefinition);
 
   }));
diff --git a/src/app/submission/submit/submission-submit.component.ts b/src/app/submission/submit/submission-submit.component.ts
index 0aa0380a251e32a22d84ce286f59e5a186b32686..d3d3ca4e66ee1984f3288916ebb2da27879095c7 100644
--- a/src/app/submission/submit/submission-submit.component.ts
+++ b/src/app/submission/submit/submission-submit.component.ts
@@ -95,7 +95,7 @@ export class SubmissionSubmitComponent implements OnDestroy, OnInit {
               this.router.navigate(['/mydspace']);
             } else {
               this.collectionId = (submissionObject.collection as Collection).id;
-              this.selfUrl = submissionObject.self;
+              this.selfUrl = submissionObject._links.self.href;
               this.submissionDefinition = (submissionObject.submissionDefinition as SubmissionDefinitionsModel);
               this.submissionId = submissionObject.id;
               this.changeDetectorRef.detectChanges();
diff --git a/src/app/thumbnail/thumbnail.component.html b/src/app/thumbnail/thumbnail.component.html
index 87fd0251f55c45eea112c7db1210acbd32aa72b7..dbf8f6732cf482d3ef6f2bbdf830df31f4b3a2ec 100644
--- a/src/app/thumbnail/thumbnail.component.html
+++ b/src/app/thumbnail/thumbnail.component.html
@@ -1,4 +1,4 @@
 <div class="thumbnail">
-  <img [src]="src | dsSafeUrl" (error)="errorHandler($event)" class="img-fluid"/>
+  <img [src]="src | dsSafeUrl" (error)="errorHandler()" class="img-fluid"/>
 </div>
 
diff --git a/src/app/thumbnail/thumbnail.component.spec.ts b/src/app/thumbnail/thumbnail.component.spec.ts
index f2be55d52cb5a32d370b75bada24e628b32af394..c4258aceb996c19c5b62e6f96e5c633a4ca91d90 100644
--- a/src/app/thumbnail/thumbnail.component.spec.ts
+++ b/src/app/thumbnail/thumbnail.component.spec.ts
@@ -1,11 +1,11 @@
-import { ComponentFixture, TestBed, async } from '@angular/core/testing';
-import { By } from '@angular/platform-browser';
 import { DebugElement } from '@angular/core';
-
-import { ThumbnailComponent } from './thumbnail.component';
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { By } from '@angular/platform-browser';
 import { Bitstream } from '../core/shared/bitstream.model';
 import { SafeUrlPipe } from '../shared/utils/safe-url-pipe';
 
+import { THUMBNAIL_PLACEHOLDER, ThumbnailComponent } from './thumbnail.component';
+
 describe('ThumbnailComponent', () => {
   let comp: ThumbnailComponent;
   let fixture: ComponentFixture<ThumbnailComponent>;
@@ -25,18 +25,37 @@ describe('ThumbnailComponent', () => {
     el = de.nativeElement;
   });
 
-  it('should display image', () => {
-    comp.thumbnail = new Bitstream();
-    comp.thumbnail.content = 'test.url';
-    fixture.detectChanges();
-    const image: HTMLElement = de.query(By.css('img')).nativeElement;
-    expect(image.getAttribute('src')).toBe(comp.thumbnail.content);
+  describe('when the thumbnail exists', () => {
+    it('should display an image', () => {
+      const thumbnail = new Bitstream();
+      thumbnail._links = {
+        self: { href: 'self.url' },
+        bundle: { href: 'bundle.url' },
+        format: { href: 'format.url' },
+        content: { href: 'content.url' },
+      };
+      comp.thumbnail = thumbnail;
+      fixture.detectChanges();
+      const image: HTMLElement = de.query(By.css('img')).nativeElement;
+      expect(image.getAttribute('src')).toBe(comp.thumbnail._links.content.href);
+    });
   });
-
-  it('should display placeholder', () => {
-    fixture.detectChanges();
-    const image: HTMLElement = de.query(By.css('img')).nativeElement;
-    expect(image.getAttribute('src')).toBe(comp.defaultImage);
+  describe(`when the thumbnail doesn't exist`, () => {
+    describe('and there is a default image', () => {
+      it('should display the default image', () => {
+        comp.src = 'http://bit.stream';
+        comp.defaultImage = 'http://default.img';
+        comp.errorHandler();
+        expect(comp.src).toBe(comp.defaultImage);
+      });
+    });
+    describe('and there is no default image', () => {
+      it('should display the placeholder', () => {
+        comp.src = 'http://default.img';
+        comp.defaultImage = 'http://default.img';
+        comp.errorHandler();
+        expect(comp.src).toBe(THUMBNAIL_PLACEHOLDER);
+      })
+    });
   });
-
 });
diff --git a/src/app/thumbnail/thumbnail.component.ts b/src/app/thumbnail/thumbnail.component.ts
index e31e907b47b1069161450c739562cdc8848b02ef..2bbd2bb2dafd6b57dc66e327f9503960a62dedb2 100644
--- a/src/app/thumbnail/thumbnail.component.ts
+++ b/src/app/thumbnail/thumbnail.component.ts
@@ -2,12 +2,16 @@ import { Component, Input, OnInit } from '@angular/core';
 import { Bitstream } from '../core/shared/bitstream.model';
 import { hasValue } from '../shared/empty.util';
 
+/**
+ * A fallback placeholder image as a base64 string
+ */
+export const THUMBNAIL_PLACEHOLDER = 'data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2293%22%20height%3D%22120%22%20viewBox%3D%220%200%2093%20120%22%20preserveAspectRatio%3D%22none%22%3E%3C!--%0ASource%20URL%3A%20holder.js%2F93x120%3Ftext%3DNo%20Thumbnail%0ACreated%20with%20Holder.js%202.8.2.%0ALearn%20more%20at%20http%3A%2F%2Fholderjs.com%0A(c)%202012-2015%20Ivan%20Malopinsky%20-%20http%3A%2F%2Fimsky.co%0A--%3E%3Cdefs%3E%3Cstyle%20type%3D%22text%2Fcss%22%3E%3C!%5BCDATA%5B%23holder_1543e460b05%20text%20%7B%20fill%3A%23AAAAAA%3Bfont-weight%3Abold%3Bfont-family%3AArial%2C%20Helvetica%2C%20Open%20Sans%2C%20sans-serif%2C%20monospace%3Bfont-size%3A10pt%20%7D%20%5D%5D%3E%3C%2Fstyle%3E%3C%2Fdefs%3E%3Cg%20id%3D%22holder_1543e460b05%22%3E%3Crect%20width%3D%2293%22%20height%3D%22120%22%20fill%3D%22%23FFFFFF%22%2F%3E%3Cg%3E%3Ctext%20x%3D%2235.6171875%22%20y%3D%2257%22%3ENo%3C%2Ftext%3E%3Ctext%20x%3D%2210.8125%22%20y%3D%2272%22%3EThumbnail%3C%2Ftext%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E';
+
 /**
  * This component renders a given Bitstream as a thumbnail.
  * One input parameter of type Bitstream is expected.
  * If no Bitstream is provided, a holderjs image will be rendered instead.
  */
-
 @Component({
   selector: 'ds-thumbnail',
   styleUrls: ['./thumbnail.component.scss'],
@@ -15,24 +19,43 @@ import { hasValue } from '../shared/empty.util';
 })
 export class ThumbnailComponent implements OnInit {
 
+  /**
+   * The thumbnail Bitstream
+   */
   @Input() thumbnail: Bitstream;
 
   /**
-   * The default 'holder.js' image
+   * The default image, used if the thumbnail isn't set or can't be downloaded
    */
-  @Input() defaultImage? = 'data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2293%22%20height%3D%22120%22%20viewBox%3D%220%200%2093%20120%22%20preserveAspectRatio%3D%22none%22%3E%3C!--%0ASource%20URL%3A%20holder.js%2F93x120%3Ftext%3DNo%20Thumbnail%0ACreated%20with%20Holder.js%202.8.2.%0ALearn%20more%20at%20http%3A%2F%2Fholderjs.com%0A(c)%202012-2015%20Ivan%20Malopinsky%20-%20http%3A%2F%2Fimsky.co%0A--%3E%3Cdefs%3E%3Cstyle%20type%3D%22text%2Fcss%22%3E%3C!%5BCDATA%5B%23holder_1543e460b05%20text%20%7B%20fill%3A%23AAAAAA%3Bfont-weight%3Abold%3Bfont-family%3AArial%2C%20Helvetica%2C%20Open%20Sans%2C%20sans-serif%2C%20monospace%3Bfont-size%3A10pt%20%7D%20%5D%5D%3E%3C%2Fstyle%3E%3C%2Fdefs%3E%3Cg%20id%3D%22holder_1543e460b05%22%3E%3Crect%20width%3D%2293%22%20height%3D%22120%22%20fill%3D%22%23FFFFFF%22%2F%3E%3Cg%3E%3Ctext%20x%3D%2235.6171875%22%20y%3D%2257%22%3ENo%3C%2Ftext%3E%3Ctext%20x%3D%2210.8125%22%20y%3D%2272%22%3EThumbnail%3C%2Ftext%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E';
+  @Input() defaultImage? = THUMBNAIL_PLACEHOLDER;
 
+  /**
+   * The src attribute used in the template to render the image.
+   */
   src: string;
-  errorHandler(event) {
-    event.currentTarget.src = this.defaultImage;
-  }
 
+  /**
+   * Initialize the thumbnail.
+   * Use a default image if no actual image is available.
+   */
   ngOnInit(): void {
-      if (hasValue(this.thumbnail) && this.thumbnail.content) {
-        this.src = this.thumbnail.content;
-      } else {
-        this.src = this.defaultImage
-      }
+    if (hasValue(this.thumbnail) && hasValue(this.thumbnail._links) && hasValue(this.thumbnail._links.content) && this.thumbnail._links.content.href) {
+      this.src = this.thumbnail._links.content.href;
+    } else {
+      this.src = this.defaultImage
+    }
   }
 
+  /**
+   * Handle image download errors.
+   * If the image can't be found, use the defaultImage instead.
+   * If that also can't be found, use the base64 placeholder.
+   */
+  errorHandler() {
+    if (this.src !== this.defaultImage) {
+      this.src = this.defaultImage;
+    } else {
+      this.src = THUMBNAIL_PLACEHOLDER;
+    }
+  }
 }
diff --git a/src/modules/app/browser-app.module.ts b/src/modules/app/browser-app.module.ts
index 0dbe4f58fed7da8c03a1f2a37238abe14cf6aa3f..34d8fb18a736ab4e9d99543a1651b54799d3e980 100644
--- a/src/modules/app/browser-app.module.ts
+++ b/src/modules/app/browser-app.module.ts
@@ -18,7 +18,7 @@ import { DSpaceTransferState } from '../transfer-state/dspace-transfer-state.ser
 import { ClientCookieService } from '../../app/core/services/client-cookie.service';
 import { CookieService } from '../../app/core/services/cookie.service';
 import { AuthService } from '../../app/core/auth/auth.service';
-import { Angulartics2Module } from 'angulartics2';
+import { Angulartics2RouterlessModule } from 'angulartics2/routerlessmodule';
 import { SubmissionService } from '../../app/submission/submission.service';
 import { StatisticsModule } from '../../app/statistics/statistics.module';
 
@@ -48,7 +48,7 @@ export function getRequest(transferState: TransferState): any {
       IdlePreload
     }),
     StatisticsModule.forRoot(),
-    Angulartics2Module.forRoot(),
+    Angulartics2RouterlessModule.forRoot(),
     BrowserAnimationsModule,
     DSpaceBrowserTransferStateModule,
     TranslateModule.forRoot({
diff --git a/src/modules/app/server-app.module.ts b/src/modules/app/server-app.module.ts
index 286e878d9b22c507cd153397bafb885f5a8aedf0..4011bb8d370a766c49edb67f587fa2ffbcd4fb90 100644
--- a/src/modules/app/server-app.module.ts
+++ b/src/modules/app/server-app.module.ts
@@ -23,7 +23,7 @@ import { AngularticsMock } from '../../app/shared/mocks/mock-angulartics.service
 import { SubmissionService } from '../../app/submission/submission.service';
 import { ServerSubmissionService } from '../../app/submission/server-submission.service';
 import { Angulartics2DSpace } from '../../app/statistics/angulartics/dspace-provider';
-import { Angulartics2Module } from 'angulartics2';
+import { Angulartics2RouterlessModule } from 'angulartics2/routerlessmodule';
 
 export function createTranslateLoader() {
   return new TranslateJson5UniversalLoader('dist/assets/i18n/', '.json5');
@@ -47,7 +47,7 @@ export function createTranslateLoader() {
         deps: []
       }
     }),
-    Angulartics2Module.forRoot(),
+    Angulartics2RouterlessModule.forRoot(),
     ServerModule,
     AppModule
   ],
diff --git a/themes/mantis/app/+item-page/simple/item-types/publication/publication.component.html b/themes/mantis/app/+item-page/simple/item-types/publication/publication.component.html
index 50b5fed9d39025d3962e3874bfcb32d349393337..adecd9e1afafdb525998dc2264675a38a15ac3ba 100644
--- a/themes/mantis/app/+item-page/simple/item-types/publication/publication.component.html
+++ b/themes/mantis/app/+item-page/simple/item-types/publication/publication.component.html
@@ -4,7 +4,7 @@ a<div class="top-item-page">
 
             <div class="col-12 col-md-2 d-flex flex-md-column justify-content-between">
                 <ds-metadata-field-wrapper>
-                    <ds-thumbnail [thumbnail]="object.getThumbnail() | async"></ds-thumbnail>
+                    <ds-thumbnail [thumbnail]="getThumbnail() | async"></ds-thumbnail>
                 </ds-metadata-field-wrapper>
                 <div>
                     <a class="btn btn-secondary"
diff --git a/themes/mantis/app/entity-groups/journal-entities/item-pages/journal-issue/journal-issue.component.html b/themes/mantis/app/entity-groups/journal-entities/item-pages/journal-issue/journal-issue.component.html
index 9fa80d9c3cd03f3d29c1864bc1e427d63c2642e9..78a0eba13e6405fe6d5183c8a51f718a9f596951 100644
--- a/themes/mantis/app/entity-groups/journal-entities/item-pages/journal-issue/journal-issue.component.html
+++ b/themes/mantis/app/entity-groups/journal-entities/item-pages/journal-issue/journal-issue.component.html
@@ -4,7 +4,7 @@
 
             <div class="col-12 col-md-2 d-flex flex-md-column justify-content-between">
                 <ds-metadata-field-wrapper>
-                    <ds-thumbnail [thumbnail]="object.getThumbnail() | async"></ds-thumbnail>
+                    <ds-thumbnail [thumbnail]="getThumbnail() | async"></ds-thumbnail>
                 </ds-metadata-field-wrapper>
                 <div>
                     <a class="btn btn-secondary"
diff --git a/themes/mantis/app/entity-groups/journal-entities/item-pages/journal-volume/journal-volume.component.html b/themes/mantis/app/entity-groups/journal-entities/item-pages/journal-volume/journal-volume.component.html
index 907f70b9411ac6feac7cafb58b47f93c0fad5c6c..3dca7dfbbad0ee846f79d47581f6343a14011b62 100644
--- a/themes/mantis/app/entity-groups/journal-entities/item-pages/journal-volume/journal-volume.component.html
+++ b/themes/mantis/app/entity-groups/journal-entities/item-pages/journal-volume/journal-volume.component.html
@@ -4,7 +4,7 @@
 
             <div class="col-12 col-md-2 d-flex flex-md-column justify-content-between">
                 <ds-metadata-field-wrapper>
-                    <ds-thumbnail [thumbnail]="object.getThumbnail() | async"></ds-thumbnail>
+                    <ds-thumbnail [thumbnail]="getThumbnail() | async"></ds-thumbnail>
                 </ds-metadata-field-wrapper>
                 <div>
                     <a class="btn btn-secondary"
diff --git a/themes/mantis/app/entity-groups/journal-entities/item-pages/journal/journal.component.html b/themes/mantis/app/entity-groups/journal-entities/item-pages/journal/journal.component.html
index 089511804edad61a39a36d2b8ed8d14335c3e411..ed542c7840b753b000ac514ece65f6d81686cc8a 100644
--- a/themes/mantis/app/entity-groups/journal-entities/item-pages/journal/journal.component.html
+++ b/themes/mantis/app/entity-groups/journal-entities/item-pages/journal/journal.component.html
@@ -3,7 +3,7 @@
         <div class="row">
             <div class="col-12 col-md-2 d-flex flex-md-column justify-content-between">
                 <ds-metadata-field-wrapper>
-                    <ds-thumbnail [thumbnail]="object.getThumbnail() | async"></ds-thumbnail>
+                    <ds-thumbnail [thumbnail]="getThumbnail() | async"></ds-thumbnail>
                 </ds-metadata-field-wrapper>
                 <div>
                     <a class="btn btn-secondary"
diff --git a/themes/mantis/app/entity-groups/research-entities/item-pages/org-unit/org-unit.component.html b/themes/mantis/app/entity-groups/research-entities/item-pages/org-unit/org-unit.component.html
index ee78d9c653696608464157ec202e26e49366faf2..ae003e31a8d5012f26d179033be2491f01f7a613 100644
--- a/themes/mantis/app/entity-groups/research-entities/item-pages/org-unit/org-unit.component.html
+++ b/themes/mantis/app/entity-groups/research-entities/item-pages/org-unit/org-unit.component.html
@@ -4,7 +4,7 @@
 
             <div class="col-12 col-md-2 d-flex flex-md-column justify-content-between">
                 <ds-metadata-field-wrapper>
-                    <ds-thumbnail [thumbnail]="object.getThumbnail() | async"
+                    <ds-thumbnail [thumbnail]="getThumbnail() | async"
                                   [defaultImage]="'assets/images/orgunit-placeholder.svg'"></ds-thumbnail>
                 </ds-metadata-field-wrapper>
                 <div>
diff --git a/themes/mantis/app/entity-groups/research-entities/item-pages/person/person.component.html b/themes/mantis/app/entity-groups/research-entities/item-pages/person/person.component.html
index 1679f9354da9a1b8488a57c8b0c08df4ab4b5f17..dbcb76a2929276a09b2d7d7665f0dd1671519f7b 100644
--- a/themes/mantis/app/entity-groups/research-entities/item-pages/person/person.component.html
+++ b/themes/mantis/app/entity-groups/research-entities/item-pages/person/person.component.html
@@ -4,7 +4,7 @@
 
             <div class="col-12 col-md-2 d-flex flex-md-column justify-content-between">
                 <ds-metadata-field-wrapper>
-                    <ds-thumbnail [thumbnail]="object.getThumbnail() | async"
+                    <ds-thumbnail [thumbnail]="getThumbnail() | async"
                                   [defaultImage]="'assets/images/person-placeholder.svg'"></ds-thumbnail>
                 </ds-metadata-field-wrapper>
                 <div>
diff --git a/themes/mantis/app/entity-groups/research-entities/item-pages/project/project.component.html b/themes/mantis/app/entity-groups/research-entities/item-pages/project/project.component.html
index 31ba79a1588a5d1acd327f45d81832fb9f94cc1c..b31353ef76f56eddf7934a03295727aaa5d4b81f 100644
--- a/themes/mantis/app/entity-groups/research-entities/item-pages/project/project.component.html
+++ b/themes/mantis/app/entity-groups/research-entities/item-pages/project/project.component.html
@@ -4,7 +4,7 @@
 
             <div class="col-12 col-md-2 d-flex flex-md-column justify-content-between">
                 <ds-metadata-field-wrapper>
-                    <ds-thumbnail [thumbnail]="object.getThumbnail() | async"
+                    <ds-thumbnail [thumbnail]="getThumbnail() | async"
                                   [defaultImage]="'assets/images/project-placeholder.svg'"></ds-thumbnail>
                 </ds-metadata-field-wrapper>
                 <div>
diff --git a/webpack/webpack.server.js b/webpack/webpack.server.js
index 5e80a286a0399edb2326c37aca33568cd523f3b1..6f529ed79100791546f1a42b4e291245bb7a7096 100644
--- a/webpack/webpack.server.js
+++ b/webpack/webpack.server.js
@@ -20,7 +20,7 @@ module.exports = (env) => {
             /@ng/,
             /angular2-text-mask/,
             /ng2-file-upload/,
-            /angular-sortablejs/,
+            /ngx-sortablejs/,
             /sortablejs/,
             /ngx/]
         })],
diff --git a/yarn.lock b/yarn.lock
index 3d0880bdb40795fb922c051e772af3d7d284c77f..7035bb60c4b1ddf44edcc047da02a989fd4339c7 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2,84 +2,95 @@
 # yarn lockfile v1
 
 
-"@angular-devkit/architect@0.13.9":
-  version "0.13.9"
-  resolved "https://registry.yarnpkg.com/@angular-devkit/architect/-/architect-0.13.9.tgz#8bbca4b968fccbf88fc2f86542cbee09e1256e1f"
-  integrity sha512-EAFtCs9dsGhpMRC45PoYsrkiExpWz9Ax15qXfzwdDRacz5DmdOVt+QpkLW1beUOwiyj/bhFyj23eaONK2RTn/w==
-  dependencies:
-    "@angular-devkit/core" "7.3.9"
-    rxjs "6.3.3"
-
-"@angular-devkit/build-angular@^0.13.5":
-  version "0.13.9"
-  resolved "https://registry.yarnpkg.com/@angular-devkit/build-angular/-/build-angular-0.13.9.tgz#92ef7b55a1aa055b2f5c8ffed4bdb04df86db678"
-  integrity sha512-onh07LhdxotDFjja0KKsDWNCwgpM/ymuRr5h0e+vT4AgklP2Uioz1CpzVOgxPIKkdVdGR9QgDinVsWAmY90J8g==
-  dependencies:
-    "@angular-devkit/architect" "0.13.9"
-    "@angular-devkit/build-optimizer" "0.13.9"
-    "@angular-devkit/build-webpack" "0.13.9"
-    "@angular-devkit/core" "7.3.9"
-    "@ngtools/webpack" "7.3.9"
-    ajv "6.9.1"
-    autoprefixer "9.4.6"
-    circular-dependency-plugin "5.0.2"
+"@angular-devkit/architect@0.803.25":
+  version "0.803.25"
+  resolved "https://registry.yarnpkg.com/@angular-devkit/architect/-/architect-0.803.25.tgz#06d109b3b24a080f0bac7374c5328b6a7b886f06"
+  integrity sha512-usV/zEncKCKQuF6AD3pRU6N5i5fbaAux/qZb+nbOz9/2G5jrXwe5sH+y3vxbgqB83e3LqusEQCTu7/tfg6LwZg==
+  dependencies:
+    "@angular-devkit/core" "8.3.25"
+    rxjs "6.4.0"
+
+"@angular-devkit/build-angular@^0.803.25":
+  version "0.803.25"
+  resolved "https://registry.yarnpkg.com/@angular-devkit/build-angular/-/build-angular-0.803.25.tgz#c630fda1d85b720a0f76211edbd475a8399fbbbb"
+  integrity sha512-WY0E7NgXuog3phhz5ZdutZPWQ9nbOr+omGN5KI1e8MZs1sJO4xkyaGRT8zOulkogkqJ2NboTBq3j9uSbZkcYeg==
+  dependencies:
+    "@angular-devkit/architect" "0.803.25"
+    "@angular-devkit/build-optimizer" "0.803.25"
+    "@angular-devkit/build-webpack" "0.803.25"
+    "@angular-devkit/core" "8.3.25"
+    "@babel/core" "7.8.3"
+    "@babel/preset-env" "7.8.3"
+    "@ngtools/webpack" "8.3.25"
+    ajv "6.10.2"
+    autoprefixer "9.6.1"
+    browserslist "4.8.6"
+    cacache "12.0.2"
+    caniuse-lite "1.0.30001024"
+    circular-dependency-plugin "5.2.0"
     clean-css "4.2.1"
-    copy-webpack-plugin "4.6.0"
-    file-loader "3.0.1"
-    glob "7.1.3"
-    istanbul-instrumenter-loader "3.0.1"
-    karma-source-map-support "1.3.0"
+    copy-webpack-plugin "5.1.1"
+    core-js "3.6.4"
+    coverage-istanbul-loader "2.0.3"
+    file-loader "4.2.0"
+    find-cache-dir "3.0.0"
+    glob "7.1.4"
+    jest-worker "24.9.0"
+    karma-source-map-support "1.4.0"
     less "3.9.0"
-    less-loader "4.1.0"
-    license-webpack-plugin "2.1.0"
+    less-loader "5.0.0"
+    license-webpack-plugin "2.1.2"
     loader-utils "1.2.3"
-    mini-css-extract-plugin "0.5.0"
+    mini-css-extract-plugin "0.8.0"
     minimatch "3.0.4"
-    open "6.0.0"
+    open "6.4.0"
     parse5 "4.0.0"
-    postcss "7.0.14"
+    postcss "7.0.17"
     postcss-import "12.0.1"
     postcss-loader "3.0.0"
-    raw-loader "1.0.0"
-    rxjs "6.3.3"
-    sass-loader "7.1.0"
-    semver "5.6.0"
+    raw-loader "3.1.0"
+    regenerator-runtime "0.13.3"
+    rxjs "6.4.0"
+    sass "1.22.9"
+    sass-loader "7.2.0"
+    semver "6.3.0"
+    source-map "0.7.3"
     source-map-loader "0.2.4"
-    source-map-support "0.5.10"
+    source-map-support "0.5.13"
     speed-measure-webpack-plugin "1.3.1"
-    stats-webpack-plugin "0.7.0"
-    style-loader "0.23.1"
+    style-loader "1.0.0"
     stylus "0.54.5"
     stylus-loader "3.0.2"
-    terser-webpack-plugin "1.2.2"
-    tree-kill "1.2.1"
-    webpack "4.29.0"
-    webpack-dev-middleware "3.5.1"
-    webpack-dev-server "3.1.14"
+    terser "4.6.3"
+    terser-webpack-plugin "1.4.3"
+    tree-kill "1.2.2"
+    webpack "4.39.2"
+    webpack-dev-middleware "3.7.2"
+    webpack-dev-server "3.9.0"
     webpack-merge "4.2.1"
-    webpack-sources "1.3.0"
+    webpack-sources "1.4.3"
     webpack-subresource-integrity "1.1.0-rc.6"
-  optionalDependencies:
-    node-sass "4.12.0"
+    worker-plugin "3.2.0"
 
-"@angular-devkit/build-optimizer@0.13.9":
-  version "0.13.9"
-  resolved "https://registry.yarnpkg.com/@angular-devkit/build-optimizer/-/build-optimizer-0.13.9.tgz#05a25ca7743876987158881585c55dfc478b95bd"
-  integrity sha512-GQtCntthQHSBv5l1ZY5p00JOECb/WcE1qUBo5kFjp84z0fszDkhOy52M1kcWCX4PFzJaY4DKk58hbUE/2UN0jw==
+"@angular-devkit/build-optimizer@0.803.25":
+  version "0.803.25"
+  resolved "https://registry.yarnpkg.com/@angular-devkit/build-optimizer/-/build-optimizer-0.803.25.tgz#83aedee3cbe15f4ec7f777dc028f2669e0ff4439"
+  integrity sha512-MiQimuEs8QeM3xo7bR3Yk1OWHHlp2pGCc2GLUMIcWhKqM+QjoRky0HoGoBazbznx292l+xjFjANvPEKbqJ2v7Q==
   dependencies:
     loader-utils "1.2.3"
-    source-map "0.5.6"
-    typescript "3.2.4"
-    webpack-sources "1.3.0"
+    source-map "0.7.3"
+    tslib "1.10.0"
+    typescript "3.5.3"
+    webpack-sources "1.4.3"
 
-"@angular-devkit/build-webpack@0.13.9":
-  version "0.13.9"
-  resolved "https://registry.yarnpkg.com/@angular-devkit/build-webpack/-/build-webpack-0.13.9.tgz#9fa091d778db752c539e1c585e21ba47d7054672"
-  integrity sha512-6ypu6pzNmQxzATF4rTWEhGSl5hyGQ8a/3aCZF/ux+XGc3d4hi2HW+NWlDm1UEna6ZjNtgEPlgfP4q8BKrjRmfA==
+"@angular-devkit/build-webpack@0.803.25":
+  version "0.803.25"
+  resolved "https://registry.yarnpkg.com/@angular-devkit/build-webpack/-/build-webpack-0.803.25.tgz#7a0648920de1c51d30447cf369929d491e267f9c"
+  integrity sha512-WR7HWJIWL6TB3WHG7ZFn8s0z3WlojeQlod75UIKl5i+f4OU90kp8kxcoH5G6OCXu56x5w40oIi1ve5ljjWSJkw==
   dependencies:
-    "@angular-devkit/architect" "0.13.9"
-    "@angular-devkit/core" "7.3.9"
-    rxjs "6.3.3"
+    "@angular-devkit/architect" "0.803.25"
+    "@angular-devkit/core" "8.3.25"
+    rxjs "6.4.0"
 
 "@angular-devkit/core@0.7.5":
   version "0.7.5"
@@ -91,15 +102,15 @@
     rxjs "^6.0.0"
     source-map "^0.5.6"
 
-"@angular-devkit/core@7.3.9":
-  version "7.3.9"
-  resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-7.3.9.tgz#bef2aaa0be7219c546fb99ea0ba9dd3a6dcd288a"
-  integrity sha512-SaxD+nKFW3iCBKsxNR7+66J30EexW/y7tm8m5AvUH+GwSAgIj0ZYmRUzFEPggcaLVA4WnE/YWqIXZMJW5dT7gw==
+"@angular-devkit/core@8.3.25":
+  version "8.3.25"
+  resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-8.3.25.tgz#8133a18be811424f10a10f37c712165b0f69f3fc"
+  integrity sha512-l7Gqy1tMrTpRmPVlovcFX8UA3mtXRlgO8kcSsbJ9MKRKNTCcxlfsWEYY5igyDBUVh6ADkgSIu0nuk31ZGTe0lw==
   dependencies:
-    ajv "6.9.1"
-    chokidar "2.0.4"
+    ajv "6.10.2"
     fast-json-stable-stringify "2.0.0"
-    rxjs "6.3.3"
+    magic-string "0.25.3"
+    rxjs "6.4.0"
     source-map "0.7.3"
 
 "@angular-devkit/schematics@0.7.5":
@@ -110,60 +121,67 @@
     "@angular-devkit/core" "0.7.5"
     rxjs "^6.0.0"
 
-"@angular-devkit/schematics@7.3.9":
-  version "7.3.9"
-  resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-7.3.9.tgz#4fe7bc878b116b157a3adf00583c28c951215877"
-  integrity sha512-xzROGCYp7aQbeJ3V6YC0MND7wKEAdWqmm/GaCufEk0dDS8ZGe0sQhcM2oBRa2nQqGQNeThFIH51kx+FayrJP0w==
+"@angular-devkit/schematics@8.3.25":
+  version "8.3.25"
+  resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-8.3.25.tgz#692eaa0fc14bc09c315d93966c781a97ca524f77"
+  integrity sha512-/p1MkfursfLy+JRGXlJGPEmX55lrFCsR/2khWAVXZcMaFR3QlR/b6/zvB8I2pHFfr0/XWnYTT/BsF7rJjO3RmA==
   dependencies:
-    "@angular-devkit/core" "7.3.9"
-    rxjs "6.3.3"
+    "@angular-devkit/core" "8.3.25"
+    rxjs "6.4.0"
 
-"@angular/animations@^7.2.15":
-  version "7.2.15"
-  resolved "https://registry.yarnpkg.com/@angular/animations/-/animations-7.2.15.tgz#980c1f523a79d4b7cb44508f57fba06f2e0872fa"
-  integrity sha512-8oBt3HLgd2+kyJHUgsd7OzKCCss67t2sch15XNoIWlOLfxclqU+EfFE6t/vCzpT8/+lpZS6LU9ZrTnb+UBj5jg==
+"@angular/animations@^8.2.14":
+  version "8.2.14"
+  resolved "https://registry.yarnpkg.com/@angular/animations/-/animations-8.2.14.tgz#76736b21e56165e6ca4925fb69605bdcc56aba7d"
+  integrity sha512-3Vc9TnNpKdtvKIXcWDFINSsnwgEMiDmLzjceWg1iYKwpeZGQahUXPoesLwQazBMmxJzQiA4HOMj0TTXKZ+Jzkg==
   dependencies:
     tslib "^1.9.0"
 
-"@angular/cdk@^7.3.7":
-  version "7.3.7"
-  resolved "https://registry.yarnpkg.com/@angular/cdk/-/cdk-7.3.7.tgz#ce1ad53ba04beb9c8e950acc5691ea0143753764"
-  integrity sha512-xbXxhHHKGkVuW6K7pzPmvpJXIwpl0ykBnvA2g+/7Sgy5Pd35wCC+UtHD9RYczDM/mkygNxMQtagyCErwFnDtQA==
+"@angular/cdk@8.2.3":
+  version "8.2.3"
+  resolved "https://registry.yarnpkg.com/@angular/cdk/-/cdk-8.2.3.tgz#16b96ffa935cbf5a646757ecaf2b19c434678f72"
+  integrity sha512-ZwO5Sn720RA2YvBqud0JAHkZXjmjxM0yNzCO8RVtRE9i8Gl26Wk0j0nQeJkVm4zwv2QO8MwbKUKGTMt8evsokA==
   dependencies:
     tslib "^1.7.1"
   optionalDependencies:
     parse5 "^5.0.0"
 
-"@angular/cli@^7.3.5":
-  version "7.3.9"
-  resolved "https://registry.yarnpkg.com/@angular/cli/-/cli-7.3.9.tgz#0366b5a66654c1f02ab2f3a9f15ebde446d506a4"
-  integrity sha512-7oJj7CKDlFUbQav1x1CV4xKKcbt0pnxY4unKcm7Q1tVXhu8bU2bc3cDA0aJnbofcYb6TJcd/C2qHgCt78q7edA==
+"@angular/cli@^8.3.25":
+  version "8.3.25"
+  resolved "https://registry.yarnpkg.com/@angular/cli/-/cli-8.3.25.tgz#2802291f83a88f334336a1482c8ee63a69cabad7"
+  integrity sha512-CPJI5nnbBvvyBUFwOHfRXy/KVwsiYlcbDAeIk1klcjQjbVFYZbnY0iAhNupy9j7rPQhb7jle5oslU3TLfbqOTQ==
   dependencies:
-    "@angular-devkit/architect" "0.13.9"
-    "@angular-devkit/core" "7.3.9"
-    "@angular-devkit/schematics" "7.3.9"
-    "@schematics/angular" "7.3.9"
-    "@schematics/update" "0.13.9"
+    "@angular-devkit/architect" "0.803.25"
+    "@angular-devkit/core" "8.3.25"
+    "@angular-devkit/schematics" "8.3.25"
+    "@schematics/angular" "8.3.25"
+    "@schematics/update" "0.803.25"
     "@yarnpkg/lockfile" "1.1.0"
+    ansi-colors "4.1.1"
+    debug "^4.1.1"
     ini "1.3.5"
-    inquirer "6.2.1"
+    inquirer "6.5.1"
     npm-package-arg "6.1.0"
-    open "6.0.0"
-    pacote "9.4.0"
-    semver "5.6.0"
+    npm-pick-manifest "3.0.2"
+    open "6.4.0"
+    pacote "9.5.5"
+    read-package-tree "5.3.1"
+    rimraf "3.0.0"
+    semver "6.3.0"
     symbol-observable "1.2.0"
+    universal-analytics "^0.4.20"
+    uuid "^3.3.2"
 
-"@angular/common@^7.2.15":
-  version "7.2.15"
-  resolved "https://registry.yarnpkg.com/@angular/common/-/common-7.2.15.tgz#e6c2f6913cdc49f87adcaabc30604e721561374b"
-  integrity sha512-2b5JY2HWVHCf3D1GZjmde7jdAXSTXkYtmjLtA9tQkjOOTr80eHpNSujQqnzb97dk9VT9OjfjqTQd7K3pxZz8jw==
+"@angular/common@^8.2.14":
+  version "8.2.14"
+  resolved "https://registry.yarnpkg.com/@angular/common/-/common-8.2.14.tgz#027e52b2951c14082d6e3af1a4ffa1356220e439"
+  integrity sha512-Qmt+aX2quUW54kaNT7QH7WGXnFxr/cC2C6sf5SW5SdkZfDQSiz8IaItvieZfXVQUbBOQKFRJ7TlSkt0jI/yjvw==
   dependencies:
     tslib "^1.9.0"
 
-"@angular/compiler-cli@^7.2.15":
-  version "7.2.15"
-  resolved "https://registry.yarnpkg.com/@angular/compiler-cli/-/compiler-cli-7.2.15.tgz#25cc3a6556ba726d00c4992ad894f8db203f4fbc"
-  integrity sha512-+AsfyKawmj/sa+m4Pz8VSRFbCfx/3IOjAuuEjhopbyr154YpPDSu8NTbcwzq3yfbVcPwK4/4exmbQzpsndaCTg==
+"@angular/compiler-cli@^8.2.14":
+  version "8.2.14"
+  resolved "https://registry.yarnpkg.com/@angular/compiler-cli/-/compiler-cli-8.2.14.tgz#1997bec04a6b9d022954e5747505fe8906994594"
+  integrity sha512-XDrTyrlIZM+0NquVT+Kbg5bn48AaWFT+B3bAT288PENrTdkuxuF9AhjFRZj8jnMdmaE4O2rioEkXBtl6z3zptA==
   dependencies:
     canonical-path "1.0.0"
     chokidar "^2.1.1"
@@ -172,66 +190,58 @@
     magic-string "^0.25.0"
     minimist "^1.2.0"
     reflect-metadata "^0.1.2"
-    shelljs "^0.8.1"
     source-map "^0.6.1"
     tslib "^1.9.0"
-    yargs "9.0.1"
-
-"@angular/compiler@^7.2.15":
-  version "7.2.15"
-  resolved "https://registry.yarnpkg.com/@angular/compiler/-/compiler-7.2.15.tgz#9698dac49dbb46956f0b8a6280580025ea7ab04e"
-  integrity sha512-5yb4NcLk8GuXkYf7Dcor4XkGueYp4dgihzDmMjYDUrV0NPhubKlr+SwGtLOtzgRBWJ1I2bO0S3zwa0q0OgIPOw==
-  dependencies:
-    tslib "^1.9.0"
+    yargs "13.1.0"
 
-"@angular/core@^7.2.15":
-  version "7.2.15"
-  resolved "https://registry.yarnpkg.com/@angular/core/-/core-7.2.15.tgz#c00d4be0ebe95b70f7631154169509cc97934e9a"
-  integrity sha512-XsuYm0jEU/mOqwDOk2utThv8J9kESkAerfuCHClE9rB2TtHUOGCfekF7lJWqjjypu6/J9ygoPFo7hdAE058ZGg==
+"@angular/compiler@^8.2.14":
+  version "8.2.14"
+  resolved "https://registry.yarnpkg.com/@angular/compiler/-/compiler-8.2.14.tgz#46db7a9d1c17f236126518ff26480c160d5a6183"
+  integrity sha512-ABZO4E7eeFA1QyJ2trDezxeQM5ZFa1dXw1Mpl/+1vuXDKNjJgNyWYwKp/NwRkLmrsuV0yv4UDCDe4kJOGbPKnw==
   dependencies:
     tslib "^1.9.0"
 
-"@angular/forms@^7.2.15":
-  version "7.2.15"
-  resolved "https://registry.yarnpkg.com/@angular/forms/-/forms-7.2.15.tgz#6b6e10b5f4687b6be3081abcc02a055b3ceeb6d8"
-  integrity sha512-p0kcIQLtBBC1qeTA6M3nOuXf/k91E80FKquVM9zEsO2kDjI0oZJVfFYL2UMov5samlJOPN+t6lRHEIUa7ApPsw==
+"@angular/core@^8.2.14":
+  version "8.2.14"
+  resolved "https://registry.yarnpkg.com/@angular/core/-/core-8.2.14.tgz#35566f5b19480369229477e7e0e0fde740bd5204"
+  integrity sha512-zeePkigi+hPh3rN7yoNENG/YUBUsIvUXdxx+AZq+QPaFeKEA2FBSrKn36ojHFrdJUjKzl0lPMEiGC2b6a6bo6g==
   dependencies:
     tslib "^1.9.0"
 
-"@angular/http@^7.2.15":
-  version "7.2.15"
-  resolved "https://registry.yarnpkg.com/@angular/http/-/http-7.2.15.tgz#a32bea9e67e99eef88150085aeebbe7aeecd39eb"
-  integrity sha512-TR7PEdmLWNIre3Zn8lvyb4lSrvPUJhKLystLnp4hBMcWsJqq5iK8S3bnlR4viZ9HMlf7bW7+Hm4SI6aB3tdUtw==
+"@angular/forms@^8.2.14":
+  version "8.2.14"
+  resolved "https://registry.yarnpkg.com/@angular/forms/-/forms-8.2.14.tgz#7d357c346a3884881beb044c50ec4a09d3d7ee8e"
+  integrity sha512-zhyKL3CFIqcyHJ/TQF/h1OZztK611a6rxuPHCrt/5Sn1SuBTJJQ1pPTkOYIDy6IrCrtyANc8qB6P17Mao71DNQ==
   dependencies:
     tslib "^1.9.0"
 
-"@angular/platform-browser-dynamic@^7.2.15":
-  version "7.2.15"
-  resolved "https://registry.yarnpkg.com/@angular/platform-browser-dynamic/-/platform-browser-dynamic-7.2.15.tgz#e697159b565ef78bd7d276fa876d099172ad8735"
-  integrity sha512-UL2PqhzXMD769NQ6Lh6pxlBDKvN9Qol3XLRFil80lwJ1GRW16ITeYbCamcafIH2GOyd88IhmYcbMfUQ/6q4MMQ==
+"@angular/platform-browser-dynamic@^8.2.14":
+  version "8.2.14"
+  resolved "https://registry.yarnpkg.com/@angular/platform-browser-dynamic/-/platform-browser-dynamic-8.2.14.tgz#4439a79fe10ec45170e6940a28835e9ff0918950"
+  integrity sha512-mO2JPR5kLU/A3AQngy9+R/Q5gaF9csMStBQjwsCRI0wNtlItOIGL6+wTYpiTuh/ux+WVN1F2sLcEYU4Zf1ud9A==
   dependencies:
     tslib "^1.9.0"
 
-"@angular/platform-browser@^7.2.15":
-  version "7.2.15"
-  resolved "https://registry.yarnpkg.com/@angular/platform-browser/-/platform-browser-7.2.15.tgz#d6df74c427453e563c12bc2ec03a83bf10bb3805"
-  integrity sha512-aYgmPsbC9Tvp9vmKWD8voeAp4crwCay7/D6lM3ClEe2EeK934LuEXq3/uczMrFVbnIX7BBIo8fh03Tl7wbiGPw==
+"@angular/platform-browser@^8.2.14":
+  version "8.2.14"
+  resolved "https://registry.yarnpkg.com/@angular/platform-browser/-/platform-browser-8.2.14.tgz#31f082e8ba977f9b89964d721c38cbc32ce0e433"
+  integrity sha512-MtJptptyKzsE37JZ2VB/tI4cvMrdAH+cT9pMBYZd66YSZfKjIj5s+AZo7z8ncoskQSB1o3HMfDjSK7QXGx1mLQ==
   dependencies:
     tslib "^1.9.0"
 
-"@angular/platform-server@^7.2.15":
-  version "7.2.15"
-  resolved "https://registry.yarnpkg.com/@angular/platform-server/-/platform-server-7.2.15.tgz#06c8a4c1850da6289f643bd690fc7e1e8bdd6376"
-  integrity sha512-a7XhYlbmQ7pN6liFq8WqdX4GNoxCIXhlZqotZkfwJDsDy2E2yyvVx6BYCEOnSRvO9xXwfyBXiLfZ4Y2A7xeCoQ==
+"@angular/platform-server@^8.2.14":
+  version "8.2.14"
+  resolved "https://registry.yarnpkg.com/@angular/platform-server/-/platform-server-8.2.14.tgz#393e42d82022ad072b652999696bd5fa0b5c6928"
+  integrity sha512-gGAgxMmac5CyLcwgB+qCD1o75An0NmpREh/lxPgz6n6Zs9JqdqpZROLSIHqGBaU6MWo1qiOfS6L08HwYPx7ipQ==
   dependencies:
-    domino "^2.1.0"
+    domino "^2.1.2"
     tslib "^1.9.0"
     xhr2 "^0.1.4"
 
-"@angular/router@^7.2.15":
-  version "7.2.15"
-  resolved "https://registry.yarnpkg.com/@angular/router/-/router-7.2.15.tgz#b2acbd07c17158801006cdd7e93113d6ec1f116e"
-  integrity sha512-qAubRJRQanguUqJQ76J9GSZ4JFtoyhJKRmX5P23ANZJXpB6YLzF2fJmOGi+E6cV8F0tKBMEq1pjxFTisx0MXwQ==
+"@angular/router@^8.2.14":
+  version "8.2.14"
+  resolved "https://registry.yarnpkg.com/@angular/router/-/router-8.2.14.tgz#5f9f9707710983c2143aead79dcd2da520ae3eb8"
+  integrity sha512-DHA2BhODqV7F0g6ZKgFaZgbsqzHHWRcfWchCOrOVKu2rYiKUTwwHVLBgZAhrpNeinq2pWanVYSIhMr7wy+LfEA==
   dependencies:
     tslib "^1.9.0"
 
@@ -247,6 +257,257 @@
   dependencies:
     "@babel/highlight" "^7.0.0"
 
+"@babel/code-frame@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.8.3.tgz#33e25903d7481181534e12ec0a25f16b6fcf419e"
+  integrity sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==
+  dependencies:
+    "@babel/highlight" "^7.8.3"
+
+"@babel/compat-data@^7.8.0", "@babel/compat-data@^7.8.4":
+  version "7.8.5"
+  resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.8.5.tgz#d28ce872778c23551cbb9432fc68d28495b613b9"
+  integrity sha512-jWYUqQX/ObOhG1UiEkbH5SANsE/8oKXiQWjj7p7xgj9Zmnt//aUvyz4dBkK0HNsS8/cbyC5NmmH87VekW+mXFg==
+  dependencies:
+    browserslist "^4.8.5"
+    invariant "^2.2.4"
+    semver "^5.5.0"
+
+"@babel/core@7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.8.3.tgz#30b0ebb4dd1585de6923a0b4d179e0b9f5d82941"
+  integrity sha512-4XFkf8AwyrEG7Ziu3L2L0Cv+WyY47Tcsp70JFmpftbAA1K7YL/sgE9jh9HyNj08Y/U50ItUchpN0w6HxAoX1rA==
+  dependencies:
+    "@babel/code-frame" "^7.8.3"
+    "@babel/generator" "^7.8.3"
+    "@babel/helpers" "^7.8.3"
+    "@babel/parser" "^7.8.3"
+    "@babel/template" "^7.8.3"
+    "@babel/traverse" "^7.8.3"
+    "@babel/types" "^7.8.3"
+    convert-source-map "^1.7.0"
+    debug "^4.1.0"
+    gensync "^1.0.0-beta.1"
+    json5 "^2.1.0"
+    lodash "^4.17.13"
+    resolve "^1.3.2"
+    semver "^5.4.1"
+    source-map "^0.5.0"
+
+"@babel/core@^7.7.5":
+  version "7.8.4"
+  resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.8.4.tgz#d496799e5c12195b3602d0fddd77294e3e38e80e"
+  integrity sha512-0LiLrB2PwrVI+a2/IEskBopDYSd8BCb3rOvH7D5tzoWd696TBEduBvuLVm4Nx6rltrLZqvI3MCalB2K2aVzQjA==
+  dependencies:
+    "@babel/code-frame" "^7.8.3"
+    "@babel/generator" "^7.8.4"
+    "@babel/helpers" "^7.8.4"
+    "@babel/parser" "^7.8.4"
+    "@babel/template" "^7.8.3"
+    "@babel/traverse" "^7.8.4"
+    "@babel/types" "^7.8.3"
+    convert-source-map "^1.7.0"
+    debug "^4.1.0"
+    gensync "^1.0.0-beta.1"
+    json5 "^2.1.0"
+    lodash "^4.17.13"
+    resolve "^1.3.2"
+    semver "^5.4.1"
+    source-map "^0.5.0"
+
+"@babel/generator@^7.8.3", "@babel/generator@^7.8.4":
+  version "7.8.4"
+  resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.8.4.tgz#35bbc74486956fe4251829f9f6c48330e8d0985e"
+  integrity sha512-PwhclGdRpNAf3IxZb0YVuITPZmmrXz9zf6fH8lT4XbrmfQKr6ryBzhv593P5C6poJRciFCL/eHGW2NuGrgEyxA==
+  dependencies:
+    "@babel/types" "^7.8.3"
+    jsesc "^2.5.1"
+    lodash "^4.17.13"
+    source-map "^0.5.0"
+
+"@babel/helper-annotate-as-pure@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.8.3.tgz#60bc0bc657f63a0924ff9a4b4a0b24a13cf4deee"
+  integrity sha512-6o+mJrZBxOoEX77Ezv9zwW7WV8DdluouRKNY/IR5u/YTMuKHgugHOzYWlYvYLpLA9nPsQCAAASpCIbjI9Mv+Uw==
+  dependencies:
+    "@babel/types" "^7.8.3"
+
+"@babel/helper-builder-binary-assignment-operator-visitor@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.8.3.tgz#c84097a427a061ac56a1c30ebf54b7b22d241503"
+  integrity sha512-5eFOm2SyFPK4Rh3XMMRDjN7lBH0orh3ss0g3rTYZnBQ+r6YPj7lgDyCvPphynHvUrobJmeMignBr6Acw9mAPlw==
+  dependencies:
+    "@babel/helper-explode-assignable-expression" "^7.8.3"
+    "@babel/types" "^7.8.3"
+
+"@babel/helper-call-delegate@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-call-delegate/-/helper-call-delegate-7.8.3.tgz#de82619898aa605d409c42be6ffb8d7204579692"
+  integrity sha512-6Q05px0Eb+N4/GTyKPPvnkig7Lylw+QzihMpws9iiZQv7ZImf84ZsZpQH7QoWN4n4tm81SnSzPgHw2qtO0Zf3A==
+  dependencies:
+    "@babel/helper-hoist-variables" "^7.8.3"
+    "@babel/traverse" "^7.8.3"
+    "@babel/types" "^7.8.3"
+
+"@babel/helper-compilation-targets@^7.8.3":
+  version "7.8.4"
+  resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.8.4.tgz#03d7ecd454b7ebe19a254f76617e61770aed2c88"
+  integrity sha512-3k3BsKMvPp5bjxgMdrFyq0UaEO48HciVrOVF0+lon8pp95cyJ2ujAh0TrBHNMnJGT2rr0iKOJPFFbSqjDyf/Pg==
+  dependencies:
+    "@babel/compat-data" "^7.8.4"
+    browserslist "^4.8.5"
+    invariant "^2.2.4"
+    levenary "^1.1.1"
+    semver "^5.5.0"
+
+"@babel/helper-create-regexp-features-plugin@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.8.3.tgz#c774268c95ec07ee92476a3862b75cc2839beb79"
+  integrity sha512-Gcsm1OHCUr9o9TcJln57xhWHtdXbA2pgQ58S0Lxlks0WMGNXuki4+GLfX0p+L2ZkINUGZvfkz8rzoqJQSthI+Q==
+  dependencies:
+    "@babel/helper-regex" "^7.8.3"
+    regexpu-core "^4.6.0"
+
+"@babel/helper-define-map@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.8.3.tgz#a0655cad5451c3760b726eba875f1cd8faa02c15"
+  integrity sha512-PoeBYtxoZGtct3md6xZOCWPcKuMuk3IHhgxsRRNtnNShebf4C8YonTSblsK4tvDbm+eJAw2HAPOfCr+Q/YRG/g==
+  dependencies:
+    "@babel/helper-function-name" "^7.8.3"
+    "@babel/types" "^7.8.3"
+    lodash "^4.17.13"
+
+"@babel/helper-explode-assignable-expression@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.8.3.tgz#a728dc5b4e89e30fc2dfc7d04fa28a930653f982"
+  integrity sha512-N+8eW86/Kj147bO9G2uclsg5pwfs/fqqY5rwgIL7eTBklgXjcOJ3btzS5iM6AitJcftnY7pm2lGsrJVYLGjzIw==
+  dependencies:
+    "@babel/traverse" "^7.8.3"
+    "@babel/types" "^7.8.3"
+
+"@babel/helper-function-name@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz#eeeb665a01b1f11068e9fb86ad56a1cb1a824cca"
+  integrity sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA==
+  dependencies:
+    "@babel/helper-get-function-arity" "^7.8.3"
+    "@babel/template" "^7.8.3"
+    "@babel/types" "^7.8.3"
+
+"@babel/helper-get-function-arity@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz#b894b947bd004381ce63ea1db9f08547e920abd5"
+  integrity sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==
+  dependencies:
+    "@babel/types" "^7.8.3"
+
+"@babel/helper-hoist-variables@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.8.3.tgz#1dbe9b6b55d78c9b4183fc8cdc6e30ceb83b7134"
+  integrity sha512-ky1JLOjcDUtSc+xkt0xhYff7Z6ILTAHKmZLHPxAhOP0Nd77O+3nCsd6uSVYur6nJnCI029CrNbYlc0LoPfAPQg==
+  dependencies:
+    "@babel/types" "^7.8.3"
+
+"@babel/helper-member-expression-to-functions@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.8.3.tgz#659b710498ea6c1d9907e0c73f206eee7dadc24c"
+  integrity sha512-fO4Egq88utkQFjbPrSHGmGLFqmrshs11d46WI+WZDESt7Wu7wN2G2Iu+NMMZJFDOVRHAMIkB5SNh30NtwCA7RA==
+  dependencies:
+    "@babel/types" "^7.8.3"
+
+"@babel/helper-module-imports@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.8.3.tgz#7fe39589b39c016331b6b8c3f441e8f0b1419498"
+  integrity sha512-R0Bx3jippsbAEtzkpZ/6FIiuzOURPcMjHp+Z6xPe6DtApDJx+w7UYyOLanZqO8+wKR9G10s/FmHXvxaMd9s6Kg==
+  dependencies:
+    "@babel/types" "^7.8.3"
+
+"@babel/helper-module-transforms@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.8.3.tgz#d305e35d02bee720fbc2c3c3623aa0c316c01590"
+  integrity sha512-C7NG6B7vfBa/pwCOshpMbOYUmrYQDfCpVL/JCRu0ek8B5p8kue1+BCXpg2vOYs7w5ACB9GTOBYQ5U6NwrMg+3Q==
+  dependencies:
+    "@babel/helper-module-imports" "^7.8.3"
+    "@babel/helper-simple-access" "^7.8.3"
+    "@babel/helper-split-export-declaration" "^7.8.3"
+    "@babel/template" "^7.8.3"
+    "@babel/types" "^7.8.3"
+    lodash "^4.17.13"
+
+"@babel/helper-optimise-call-expression@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.8.3.tgz#7ed071813d09c75298ef4f208956006b6111ecb9"
+  integrity sha512-Kag20n86cbO2AvHca6EJsvqAd82gc6VMGule4HwebwMlwkpXuVqrNRj6CkCV2sKxgi9MyAUnZVnZ6lJ1/vKhHQ==
+  dependencies:
+    "@babel/types" "^7.8.3"
+
+"@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz#9ea293be19babc0f52ff8ca88b34c3611b208670"
+  integrity sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==
+
+"@babel/helper-regex@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.8.3.tgz#139772607d51b93f23effe72105b319d2a4c6965"
+  integrity sha512-BWt0QtYv/cg/NecOAZMdcn/waj/5P26DR4mVLXfFtDokSR6fyuG0Pj+e2FqtSME+MqED1khnSMulkmGl8qWiUQ==
+  dependencies:
+    lodash "^4.17.13"
+
+"@babel/helper-remap-async-to-generator@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.8.3.tgz#273c600d8b9bf5006142c1e35887d555c12edd86"
+  integrity sha512-kgwDmw4fCg7AVgS4DukQR/roGp+jP+XluJE5hsRZwxCYGg+Rv9wSGErDWhlI90FODdYfd4xG4AQRiMDjjN0GzA==
+  dependencies:
+    "@babel/helper-annotate-as-pure" "^7.8.3"
+    "@babel/helper-wrap-function" "^7.8.3"
+    "@babel/template" "^7.8.3"
+    "@babel/traverse" "^7.8.3"
+    "@babel/types" "^7.8.3"
+
+"@babel/helper-replace-supers@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.8.3.tgz#91192d25f6abbcd41da8a989d4492574fb1530bc"
+  integrity sha512-xOUssL6ho41U81etpLoT2RTdvdus4VfHamCuAm4AHxGr+0it5fnwoVdwUJ7GFEqCsQYzJUhcbsN9wB9apcYKFA==
+  dependencies:
+    "@babel/helper-member-expression-to-functions" "^7.8.3"
+    "@babel/helper-optimise-call-expression" "^7.8.3"
+    "@babel/traverse" "^7.8.3"
+    "@babel/types" "^7.8.3"
+
+"@babel/helper-simple-access@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.8.3.tgz#7f8109928b4dab4654076986af575231deb639ae"
+  integrity sha512-VNGUDjx5cCWg4vvCTR8qQ7YJYZ+HBjxOgXEl7ounz+4Sn7+LMD3CFrCTEU6/qXKbA2nKg21CwhhBzO0RpRbdCw==
+  dependencies:
+    "@babel/template" "^7.8.3"
+    "@babel/types" "^7.8.3"
+
+"@babel/helper-split-export-declaration@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz#31a9f30070f91368a7182cf05f831781065fc7a9"
+  integrity sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==
+  dependencies:
+    "@babel/types" "^7.8.3"
+
+"@babel/helper-wrap-function@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.8.3.tgz#9dbdb2bb55ef14aaa01fe8c99b629bd5352d8610"
+  integrity sha512-LACJrbUET9cQDzb6kG7EeD7+7doC3JNvUgTEQOx2qaO1fKlzE/Bf05qs9w1oXQMmXlPO65lC3Tq9S6gZpTErEQ==
+  dependencies:
+    "@babel/helper-function-name" "^7.8.3"
+    "@babel/template" "^7.8.3"
+    "@babel/traverse" "^7.8.3"
+    "@babel/types" "^7.8.3"
+
+"@babel/helpers@^7.8.3", "@babel/helpers@^7.8.4":
+  version "7.8.4"
+  resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.8.4.tgz#754eb3ee727c165e0a240d6c207de7c455f36f73"
+  integrity sha512-VPbe7wcQ4chu4TDQjimHv/5tj73qz88o12EPkO2ValS2QiQS/1F2SsjyIGNnAD0vF/nZS6Cf9i+vW6HIlnaR8w==
+  dependencies:
+    "@babel/template" "^7.8.3"
+    "@babel/traverse" "^7.8.4"
+    "@babel/types" "^7.8.3"
+
 "@babel/highlight@^7.0.0":
   version "7.0.0"
   resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0.tgz#f710c38c8d458e6dd9a201afb637fcb781ce99e4"
@@ -256,6 +517,449 @@
     esutils "^2.0.2"
     js-tokens "^4.0.0"
 
+"@babel/highlight@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.8.3.tgz#28f173d04223eaaa59bc1d439a3836e6d1265797"
+  integrity sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==
+  dependencies:
+    chalk "^2.0.0"
+    esutils "^2.0.2"
+    js-tokens "^4.0.0"
+
+"@babel/parser@^7.7.5", "@babel/parser@^7.8.3", "@babel/parser@^7.8.4":
+  version "7.8.4"
+  resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.8.4.tgz#d1dbe64691d60358a974295fa53da074dd2ce8e8"
+  integrity sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw==
+
+"@babel/plugin-proposal-async-generator-functions@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.8.3.tgz#bad329c670b382589721b27540c7d288601c6e6f"
+  integrity sha512-NZ9zLv848JsV3hs8ryEh7Uaz/0KsmPLqv0+PdkDJL1cJy0K4kOCFa8zc1E3mp+RHPQcpdfb/6GovEsW4VDrOMw==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+    "@babel/helper-remap-async-to-generator" "^7.8.3"
+    "@babel/plugin-syntax-async-generators" "^7.8.0"
+
+"@babel/plugin-proposal-dynamic-import@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.8.3.tgz#38c4fe555744826e97e2ae930b0fb4cc07e66054"
+  integrity sha512-NyaBbyLFXFLT9FP+zk0kYlUlA8XtCUbehs67F0nnEg7KICgMc2mNkIeu9TYhKzyXMkrapZFwAhXLdnt4IYHy1w==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+    "@babel/plugin-syntax-dynamic-import" "^7.8.0"
+
+"@babel/plugin-proposal-json-strings@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.8.3.tgz#da5216b238a98b58a1e05d6852104b10f9a70d6b"
+  integrity sha512-KGhQNZ3TVCQG/MjRbAUwuH+14y9q0tpxs1nWWs3pbSleRdDro9SAMMDyye8HhY1gqZ7/NqIc8SKhya0wRDgP1Q==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+    "@babel/plugin-syntax-json-strings" "^7.8.0"
+
+"@babel/plugin-proposal-nullish-coalescing-operator@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.8.3.tgz#e4572253fdeed65cddeecfdab3f928afeb2fd5d2"
+  integrity sha512-TS9MlfzXpXKt6YYomudb/KU7nQI6/xnapG6in1uZxoxDghuSMZsPb6D2fyUwNYSAp4l1iR7QtFOjkqcRYcUsfw==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+    "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0"
+
+"@babel/plugin-proposal-object-rest-spread@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.8.3.tgz#eb5ae366118ddca67bed583b53d7554cad9951bb"
+  integrity sha512-8qvuPwU/xxUCt78HocNlv0mXXo0wdh9VT1R04WU8HGOfaOob26pF+9P5/lYjN/q7DHOX1bvX60hnhOvuQUJdbA==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+    "@babel/plugin-syntax-object-rest-spread" "^7.8.0"
+
+"@babel/plugin-proposal-optional-catch-binding@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.8.3.tgz#9dee96ab1650eed88646ae9734ca167ac4a9c5c9"
+  integrity sha512-0gkX7J7E+AtAw9fcwlVQj8peP61qhdg/89D5swOkjYbkboA2CVckn3kiyum1DE0wskGb7KJJxBdyEBApDLLVdw==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+    "@babel/plugin-syntax-optional-catch-binding" "^7.8.0"
+
+"@babel/plugin-proposal-optional-chaining@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.8.3.tgz#ae10b3214cb25f7adb1f3bc87ba42ca10b7e2543"
+  integrity sha512-QIoIR9abkVn+seDE3OjA08jWcs3eZ9+wJCKSRgo3WdEU2csFYgdScb+8qHB3+WXsGJD55u+5hWCISI7ejXS+kg==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+    "@babel/plugin-syntax-optional-chaining" "^7.8.0"
+
+"@babel/plugin-proposal-unicode-property-regex@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.8.3.tgz#b646c3adea5f98800c9ab45105ac34d06cd4a47f"
+  integrity sha512-1/1/rEZv2XGweRwwSkLpY+s60za9OZ1hJs4YDqFHCw0kYWYwL5IFljVY1MYBL+weT1l9pokDO2uhSTLVxzoHkQ==
+  dependencies:
+    "@babel/helper-create-regexp-features-plugin" "^7.8.3"
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-syntax-async-generators@^7.8.0":
+  version "7.8.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d"
+  integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.0"
+
+"@babel/plugin-syntax-dynamic-import@^7.8.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3"
+  integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.0"
+
+"@babel/plugin-syntax-json-strings@^7.8.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a"
+  integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.0"
+
+"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9"
+  integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.0"
+
+"@babel/plugin-syntax-object-rest-spread@^7.8.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871"
+  integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.0"
+
+"@babel/plugin-syntax-optional-catch-binding@^7.8.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1"
+  integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.0"
+
+"@babel/plugin-syntax-optional-chaining@^7.8.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a"
+  integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.0"
+
+"@babel/plugin-syntax-top-level-await@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.8.3.tgz#3acdece695e6b13aaf57fc291d1a800950c71391"
+  integrity sha512-kwj1j9lL/6Wd0hROD3b/OZZ7MSrZLqqn9RAZ5+cYYsflQ9HZBIKCUkr3+uL1MEJ1NePiUbf98jjiMQSv0NMR9g==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-arrow-functions@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.8.3.tgz#82776c2ed0cd9e1a49956daeb896024c9473b8b6"
+  integrity sha512-0MRF+KC8EqH4dbuITCWwPSzsyO3HIWWlm30v8BbbpOrS1B++isGxPnnuq/IZvOX5J2D/p7DQalQm+/2PnlKGxg==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-async-to-generator@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.8.3.tgz#4308fad0d9409d71eafb9b1a6ee35f9d64b64086"
+  integrity sha512-imt9tFLD9ogt56Dd5CI/6XgpukMwd/fLGSrix2httihVe7LOGVPhyhMh1BU5kDM7iHD08i8uUtmV2sWaBFlHVQ==
+  dependencies:
+    "@babel/helper-module-imports" "^7.8.3"
+    "@babel/helper-plugin-utils" "^7.8.3"
+    "@babel/helper-remap-async-to-generator" "^7.8.3"
+
+"@babel/plugin-transform-block-scoped-functions@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.8.3.tgz#437eec5b799b5852072084b3ae5ef66e8349e8a3"
+  integrity sha512-vo4F2OewqjbB1+yaJ7k2EJFHlTP3jR634Z9Cj9itpqNjuLXvhlVxgnjsHsdRgASR8xYDrx6onw4vW5H6We0Jmg==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-block-scoping@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.8.3.tgz#97d35dab66857a437c166358b91d09050c868f3a"
+  integrity sha512-pGnYfm7RNRgYRi7bids5bHluENHqJhrV4bCZRwc5GamaWIIs07N4rZECcmJL6ZClwjDz1GbdMZFtPs27hTB06w==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+    lodash "^4.17.13"
+
+"@babel/plugin-transform-classes@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.8.3.tgz#46fd7a9d2bb9ea89ce88720477979fe0d71b21b8"
+  integrity sha512-SjT0cwFJ+7Rbr1vQsvphAHwUHvSUPmMjMU/0P59G8U2HLFqSa082JO7zkbDNWs9kH/IUqpHI6xWNesGf8haF1w==
+  dependencies:
+    "@babel/helper-annotate-as-pure" "^7.8.3"
+    "@babel/helper-define-map" "^7.8.3"
+    "@babel/helper-function-name" "^7.8.3"
+    "@babel/helper-optimise-call-expression" "^7.8.3"
+    "@babel/helper-plugin-utils" "^7.8.3"
+    "@babel/helper-replace-supers" "^7.8.3"
+    "@babel/helper-split-export-declaration" "^7.8.3"
+    globals "^11.1.0"
+
+"@babel/plugin-transform-computed-properties@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.8.3.tgz#96d0d28b7f7ce4eb5b120bb2e0e943343c86f81b"
+  integrity sha512-O5hiIpSyOGdrQZRQ2ccwtTVkgUDBBiCuK//4RJ6UfePllUTCENOzKxfh6ulckXKc0DixTFLCfb2HVkNA7aDpzA==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-destructuring@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.8.3.tgz#20ddfbd9e4676906b1056ee60af88590cc7aaa0b"
+  integrity sha512-H4X646nCkiEcHZUZaRkhE2XVsoz0J/1x3VVujnn96pSoGCtKPA99ZZA+va+gK+92Zycd6OBKCD8tDb/731bhgQ==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-dotall-regex@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.8.3.tgz#c3c6ec5ee6125c6993c5cbca20dc8621a9ea7a6e"
+  integrity sha512-kLs1j9Nn4MQoBYdRXH6AeaXMbEJFaFu/v1nQkvib6QzTj8MZI5OQzqmD83/2jEM1z0DLilra5aWO5YpyC0ALIw==
+  dependencies:
+    "@babel/helper-create-regexp-features-plugin" "^7.8.3"
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-duplicate-keys@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.8.3.tgz#8d12df309aa537f272899c565ea1768e286e21f1"
+  integrity sha512-s8dHiBUbcbSgipS4SMFuWGqCvyge5V2ZeAWzR6INTVC3Ltjig/Vw1G2Gztv0vU/hRG9X8IvKvYdoksnUfgXOEQ==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-exponentiation-operator@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.8.3.tgz#581a6d7f56970e06bf51560cd64f5e947b70d7b7"
+  integrity sha512-zwIpuIymb3ACcInbksHaNcR12S++0MDLKkiqXHl3AzpgdKlFNhog+z/K0+TGW+b0w5pgTq4H6IwV/WhxbGYSjQ==
+  dependencies:
+    "@babel/helper-builder-binary-assignment-operator-visitor" "^7.8.3"
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-for-of@^7.8.3":
+  version "7.8.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.8.4.tgz#6fe8eae5d6875086ee185dd0b098a8513783b47d"
+  integrity sha512-iAXNlOWvcYUYoV8YIxwS7TxGRJcxyl8eQCfT+A5j8sKUzRFvJdcyjp97jL2IghWSRDaL2PU2O2tX8Cu9dTBq5A==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-function-name@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.8.3.tgz#279373cb27322aaad67c2683e776dfc47196ed8b"
+  integrity sha512-rO/OnDS78Eifbjn5Py9v8y0aR+aSYhDhqAwVfsTl0ERuMZyr05L1aFSCJnbv2mmsLkit/4ReeQ9N2BgLnOcPCQ==
+  dependencies:
+    "@babel/helper-function-name" "^7.8.3"
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-literals@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.8.3.tgz#aef239823d91994ec7b68e55193525d76dbd5dc1"
+  integrity sha512-3Tqf8JJ/qB7TeldGl+TT55+uQei9JfYaregDcEAyBZ7akutriFrt6C/wLYIer6OYhleVQvH/ntEhjE/xMmy10A==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-member-expression-literals@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.8.3.tgz#963fed4b620ac7cbf6029c755424029fa3a40410"
+  integrity sha512-3Wk2EXhnw+rP+IDkK6BdtPKsUE5IeZ6QOGrPYvw52NwBStw9V1ZVzxgK6fSKSxqUvH9eQPR3tm3cOq79HlsKYA==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-modules-amd@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.8.3.tgz#65606d44616b50225e76f5578f33c568a0b876a5"
+  integrity sha512-MadJiU3rLKclzT5kBH4yxdry96odTUwuqrZM+GllFI/VhxfPz+k9MshJM+MwhfkCdxxclSbSBbUGciBngR+kEQ==
+  dependencies:
+    "@babel/helper-module-transforms" "^7.8.3"
+    "@babel/helper-plugin-utils" "^7.8.3"
+    babel-plugin-dynamic-import-node "^2.3.0"
+
+"@babel/plugin-transform-modules-commonjs@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.8.3.tgz#df251706ec331bd058a34bdd72613915f82928a5"
+  integrity sha512-JpdMEfA15HZ/1gNuB9XEDlZM1h/gF/YOH7zaZzQu2xCFRfwc01NXBMHHSTT6hRjlXJJs5x/bfODM3LiCk94Sxg==
+  dependencies:
+    "@babel/helper-module-transforms" "^7.8.3"
+    "@babel/helper-plugin-utils" "^7.8.3"
+    "@babel/helper-simple-access" "^7.8.3"
+    babel-plugin-dynamic-import-node "^2.3.0"
+
+"@babel/plugin-transform-modules-systemjs@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.8.3.tgz#d8bbf222c1dbe3661f440f2f00c16e9bb7d0d420"
+  integrity sha512-8cESMCJjmArMYqa9AO5YuMEkE4ds28tMpZcGZB/jl3n0ZzlsxOAi3mC+SKypTfT8gjMupCnd3YiXCkMjj2jfOg==
+  dependencies:
+    "@babel/helper-hoist-variables" "^7.8.3"
+    "@babel/helper-module-transforms" "^7.8.3"
+    "@babel/helper-plugin-utils" "^7.8.3"
+    babel-plugin-dynamic-import-node "^2.3.0"
+
+"@babel/plugin-transform-modules-umd@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.8.3.tgz#592d578ce06c52f5b98b02f913d653ffe972661a"
+  integrity sha512-evhTyWhbwbI3/U6dZAnx/ePoV7H6OUG+OjiJFHmhr9FPn0VShjwC2kdxqIuQ/+1P50TMrneGzMeyMTFOjKSnAw==
+  dependencies:
+    "@babel/helper-module-transforms" "^7.8.3"
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-named-capturing-groups-regex@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.8.3.tgz#a2a72bffa202ac0e2d0506afd0939c5ecbc48c6c"
+  integrity sha512-f+tF/8UVPU86TrCb06JoPWIdDpTNSGGcAtaD9mLP0aYGA0OS0j7j7DHJR0GTFrUZPUU6loZhbsVZgTh0N+Qdnw==
+  dependencies:
+    "@babel/helper-create-regexp-features-plugin" "^7.8.3"
+
+"@babel/plugin-transform-new-target@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.8.3.tgz#60cc2ae66d85c95ab540eb34babb6434d4c70c43"
+  integrity sha512-QuSGysibQpyxexRyui2vca+Cmbljo8bcRckgzYV4kRIsHpVeyeC3JDO63pY+xFZ6bWOBn7pfKZTqV4o/ix9sFw==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-object-super@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.8.3.tgz#ebb6a1e7a86ffa96858bd6ac0102d65944261725"
+  integrity sha512-57FXk+gItG/GejofIyLIgBKTas4+pEU47IXKDBWFTxdPd7F80H8zybyAY7UoblVfBhBGs2EKM+bJUu2+iUYPDQ==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+    "@babel/helper-replace-supers" "^7.8.3"
+
+"@babel/plugin-transform-parameters@^7.8.3":
+  version "7.8.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.8.4.tgz#1d5155de0b65db0ccf9971165745d3bb990d77d3"
+  integrity sha512-IsS3oTxeTsZlE5KqzTbcC2sV0P9pXdec53SU+Yxv7o/6dvGM5AkTotQKhoSffhNgZ/dftsSiOoxy7evCYJXzVA==
+  dependencies:
+    "@babel/helper-call-delegate" "^7.8.3"
+    "@babel/helper-get-function-arity" "^7.8.3"
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-property-literals@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.8.3.tgz#33194300d8539c1ed28c62ad5087ba3807b98263"
+  integrity sha512-uGiiXAZMqEoQhRWMK17VospMZh5sXWg+dlh2soffpkAl96KAm+WZuJfa6lcELotSRmooLqg0MWdH6UUq85nmmg==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-regenerator@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.8.3.tgz#b31031e8059c07495bf23614c97f3d9698bc6ec8"
+  integrity sha512-qt/kcur/FxrQrzFR432FGZznkVAjiyFtCOANjkAKwCbt465L6ZCiUQh2oMYGU3Wo8LRFJxNDFwWn106S5wVUNA==
+  dependencies:
+    regenerator-transform "^0.14.0"
+
+"@babel/plugin-transform-reserved-words@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.8.3.tgz#9a0635ac4e665d29b162837dd3cc50745dfdf1f5"
+  integrity sha512-mwMxcycN3omKFDjDQUl+8zyMsBfjRFr0Zn/64I41pmjv4NJuqcYlEtezwYtw9TFd9WR1vN5kiM+O0gMZzO6L0A==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-shorthand-properties@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.8.3.tgz#28545216e023a832d4d3a1185ed492bcfeac08c8"
+  integrity sha512-I9DI6Odg0JJwxCHzbzW08ggMdCezoWcuQRz3ptdudgwaHxTjxw5HgdFJmZIkIMlRymL6YiZcped4TTCB0JcC8w==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-spread@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.8.3.tgz#9c8ffe8170fdfb88b114ecb920b82fb6e95fe5e8"
+  integrity sha512-CkuTU9mbmAoFOI1tklFWYYbzX5qCIZVXPVy0jpXgGwkplCndQAa58s2jr66fTeQnA64bDox0HL4U56CFYoyC7g==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-sticky-regex@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.8.3.tgz#be7a1290f81dae767475452199e1f76d6175b100"
+  integrity sha512-9Spq0vGCD5Bb4Z/ZXXSK5wbbLFMG085qd2vhL1JYu1WcQ5bXqZBAYRzU1d+p79GcHs2szYv5pVQCX13QgldaWw==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+    "@babel/helper-regex" "^7.8.3"
+
+"@babel/plugin-transform-template-literals@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.8.3.tgz#7bfa4732b455ea6a43130adc0ba767ec0e402a80"
+  integrity sha512-820QBtykIQOLFT8NZOcTRJ1UNuztIELe4p9DCgvj4NK+PwluSJ49we7s9FB1HIGNIYT7wFUJ0ar2QpCDj0escQ==
+  dependencies:
+    "@babel/helper-annotate-as-pure" "^7.8.3"
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-typeof-symbol@^7.8.3":
+  version "7.8.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.8.4.tgz#ede4062315ce0aaf8a657a920858f1a2f35fc412"
+  integrity sha512-2QKyfjGdvuNfHsb7qnBBlKclbD4CfshH2KvDabiijLMGXPHJXGxtDzwIF7bQP+T0ysw8fYTtxPafgfs/c1Lrqg==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-unicode-regex@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.8.3.tgz#0cef36e3ba73e5c57273effb182f46b91a1ecaad"
+  integrity sha512-+ufgJjYdmWfSQ+6NS9VGUR2ns8cjJjYbrbi11mZBTaWm+Fui/ncTLFF28Ei1okavY+xkojGr1eJxNsWYeA5aZw==
+  dependencies:
+    "@babel/helper-create-regexp-features-plugin" "^7.8.3"
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/preset-env@7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.8.3.tgz#dc0fb2938f52bbddd79b3c861a4b3427dd3a6c54"
+  integrity sha512-Rs4RPL2KjSLSE2mWAx5/iCH+GC1ikKdxPrhnRS6PfFVaiZeom22VFKN4X8ZthyN61kAaR05tfXTbCvatl9WIQg==
+  dependencies:
+    "@babel/compat-data" "^7.8.0"
+    "@babel/helper-compilation-targets" "^7.8.3"
+    "@babel/helper-module-imports" "^7.8.3"
+    "@babel/helper-plugin-utils" "^7.8.3"
+    "@babel/plugin-proposal-async-generator-functions" "^7.8.3"
+    "@babel/plugin-proposal-dynamic-import" "^7.8.3"
+    "@babel/plugin-proposal-json-strings" "^7.8.3"
+    "@babel/plugin-proposal-nullish-coalescing-operator" "^7.8.3"
+    "@babel/plugin-proposal-object-rest-spread" "^7.8.3"
+    "@babel/plugin-proposal-optional-catch-binding" "^7.8.3"
+    "@babel/plugin-proposal-optional-chaining" "^7.8.3"
+    "@babel/plugin-proposal-unicode-property-regex" "^7.8.3"
+    "@babel/plugin-syntax-async-generators" "^7.8.0"
+    "@babel/plugin-syntax-dynamic-import" "^7.8.0"
+    "@babel/plugin-syntax-json-strings" "^7.8.0"
+    "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0"
+    "@babel/plugin-syntax-object-rest-spread" "^7.8.0"
+    "@babel/plugin-syntax-optional-catch-binding" "^7.8.0"
+    "@babel/plugin-syntax-optional-chaining" "^7.8.0"
+    "@babel/plugin-syntax-top-level-await" "^7.8.3"
+    "@babel/plugin-transform-arrow-functions" "^7.8.3"
+    "@babel/plugin-transform-async-to-generator" "^7.8.3"
+    "@babel/plugin-transform-block-scoped-functions" "^7.8.3"
+    "@babel/plugin-transform-block-scoping" "^7.8.3"
+    "@babel/plugin-transform-classes" "^7.8.3"
+    "@babel/plugin-transform-computed-properties" "^7.8.3"
+    "@babel/plugin-transform-destructuring" "^7.8.3"
+    "@babel/plugin-transform-dotall-regex" "^7.8.3"
+    "@babel/plugin-transform-duplicate-keys" "^7.8.3"
+    "@babel/plugin-transform-exponentiation-operator" "^7.8.3"
+    "@babel/plugin-transform-for-of" "^7.8.3"
+    "@babel/plugin-transform-function-name" "^7.8.3"
+    "@babel/plugin-transform-literals" "^7.8.3"
+    "@babel/plugin-transform-member-expression-literals" "^7.8.3"
+    "@babel/plugin-transform-modules-amd" "^7.8.3"
+    "@babel/plugin-transform-modules-commonjs" "^7.8.3"
+    "@babel/plugin-transform-modules-systemjs" "^7.8.3"
+    "@babel/plugin-transform-modules-umd" "^7.8.3"
+    "@babel/plugin-transform-named-capturing-groups-regex" "^7.8.3"
+    "@babel/plugin-transform-new-target" "^7.8.3"
+    "@babel/plugin-transform-object-super" "^7.8.3"
+    "@babel/plugin-transform-parameters" "^7.8.3"
+    "@babel/plugin-transform-property-literals" "^7.8.3"
+    "@babel/plugin-transform-regenerator" "^7.8.3"
+    "@babel/plugin-transform-reserved-words" "^7.8.3"
+    "@babel/plugin-transform-shorthand-properties" "^7.8.3"
+    "@babel/plugin-transform-spread" "^7.8.3"
+    "@babel/plugin-transform-sticky-regex" "^7.8.3"
+    "@babel/plugin-transform-template-literals" "^7.8.3"
+    "@babel/plugin-transform-typeof-symbol" "^7.8.3"
+    "@babel/plugin-transform-unicode-regex" "^7.8.3"
+    "@babel/types" "^7.8.3"
+    browserslist "^4.8.2"
+    core-js-compat "^3.6.2"
+    invariant "^2.2.2"
+    levenary "^1.1.0"
+    semver "^5.5.0"
+
 "@babel/runtime-corejs3@^7.7.4":
   version "7.7.6"
   resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.7.6.tgz#5b1044ea11b659d288f77190e19c62da959ed9a3"
@@ -271,11 +975,49 @@
   dependencies:
     regenerator-runtime "^0.13.2"
 
+"@babel/template@^7.7.4", "@babel/template@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.8.3.tgz#e02ad04fe262a657809327f578056ca15fd4d1b8"
+  integrity sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==
+  dependencies:
+    "@babel/code-frame" "^7.8.3"
+    "@babel/parser" "^7.8.3"
+    "@babel/types" "^7.8.3"
+
+"@babel/traverse@^7.7.4", "@babel/traverse@^7.8.3", "@babel/traverse@^7.8.4":
+  version "7.8.4"
+  resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.8.4.tgz#f0845822365f9d5b0e312ed3959d3f827f869e3c"
+  integrity sha512-NGLJPZwnVEyBPLI+bl9y9aSnxMhsKz42so7ApAv9D+b4vAFPpY013FTS9LdKxcABoIYFU52HcYga1pPlx454mg==
+  dependencies:
+    "@babel/code-frame" "^7.8.3"
+    "@babel/generator" "^7.8.4"
+    "@babel/helper-function-name" "^7.8.3"
+    "@babel/helper-split-export-declaration" "^7.8.3"
+    "@babel/parser" "^7.8.4"
+    "@babel/types" "^7.8.3"
+    debug "^4.1.0"
+    globals "^11.1.0"
+    lodash "^4.17.13"
+
+"@babel/types@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.8.3.tgz#5a383dffa5416db1b73dedffd311ffd0788fb31c"
+  integrity sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==
+  dependencies:
+    esutils "^2.0.2"
+    lodash "^4.17.13"
+    to-fast-properties "^2.0.0"
+
 "@fortawesome/fontawesome-free@^5.5.0":
   version "5.5.0"
   resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-free/-/fontawesome-free-5.5.0.tgz#0c6c53823d04457ae669cd19567b8a21dbb4fcfd"
   integrity sha512-p4lu0jfj5QN013ddArh99r3OXZ/fp9rbovs62LfaO70OMBsAXxtNd0lAq/97fitrscR0fqfd+/a5KNcp6Sh/0A==
 
+"@istanbuljs/schema@^0.1.2":
+  version "0.1.2"
+  resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.2.tgz#26520bf09abe4a5644cd5414e37125a8954241dd"
+  integrity sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==
+
 "@mrmlnc/readdir-enhanced@^2.2.1":
   version "2.2.1"
   resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde"
@@ -284,72 +1026,72 @@
     call-me-maybe "^1.0.1"
     glob-to-regexp "^0.3.0"
 
-"@ng-bootstrap/ng-bootstrap@^4.1.0":
-  version "4.2.2"
-  resolved "https://registry.yarnpkg.com/@ng-bootstrap/ng-bootstrap/-/ng-bootstrap-4.2.2.tgz#a1c3a9576656cb4f793bbc3df56dfbdeb098f2fb"
-  integrity sha512-v8QmC17bv9he5Ep6zutaI9aQ2w/2NqySP0fejOKe7cacKpGUqsLIakpyd2FD7mfZu7pSCCtHYpRWR+h6yq+Ngg==
+"@ng-bootstrap/ng-bootstrap@^5.2.1":
+  version "5.2.1"
+  resolved "https://registry.yarnpkg.com/@ng-bootstrap/ng-bootstrap/-/ng-bootstrap-5.2.1.tgz#4fea4b561a8fa2422d31d492ffa3843b22669cfd"
+  integrity sha512-73/FX3wkDCQgdTBIa/pAOUB+DQLbag2vET3NIaqNz8Zno6cilkefY1zdlQ2zbwONcGzCyoTPFAUPivHgvoy9/w==
   dependencies:
     tslib "^1.9.0"
 
-"@ng-dynamic-forms/core@^7.1.0":
-  version "7.2.0"
-  resolved "https://registry.yarnpkg.com/@ng-dynamic-forms/core/-/core-7.2.0.tgz#788253da5f0bc44ea69cd1eb0071b78f091ea389"
-  integrity sha512-eRb26jDNIXiBla0hzgEpdL1Za9e6RD9phbV9PxzIkNlYKY2+FQowQBPmGBuck21E9okfVkEle2RJ4lUmozV5jw==
+"@ng-dynamic-forms/core@8.1.1":
+  version "8.1.1"
+  resolved "https://registry.yarnpkg.com/@ng-dynamic-forms/core/-/core-8.1.1.tgz#41af2d95f6b0e426030aa993be5d4937c81a8e10"
+  integrity sha512-x0wUAv2r929CqTbRnAutAWmrSKd0pbbk4hwqguMl3D4Xk2/Qc565LYWWFRnq+Xr9NgyCONXKBu9unxspfG4g0A==
   dependencies:
     tslib "^1.9.0"
 
-"@ng-dynamic-forms/ui-ng-bootstrap@^7.1.0":
-  version "7.2.0"
-  resolved "https://registry.yarnpkg.com/@ng-dynamic-forms/ui-ng-bootstrap/-/ui-ng-bootstrap-7.2.0.tgz#b01da1f0a149108218eb0a1e6f26700a6a5bdbb9"
-  integrity sha512-iX6/7p5FK7yCEDxbKRs//JwsklQGx//0LyB4FkzPil7LNjXqJCabA7WS3+lUFZQdYXM0fAcyve+UZJCM7yTZiA==
+"@ng-dynamic-forms/ui-ng-bootstrap@8.1.1":
+  version "8.1.1"
+  resolved "https://registry.yarnpkg.com/@ng-dynamic-forms/ui-ng-bootstrap/-/ui-ng-bootstrap-8.1.1.tgz#a2444ec68c3416533b625b74ce861ea06dcaa74b"
+  integrity sha512-LJEbJatev6Lg+Fs6/+xxXJ2DydUO/5sEC2hwTET8BRZmeThL7//4cLbOTKihY2X/JL16cEsIFB8mxgfBeJ2c3Q==
   dependencies:
     tslib "^1.9.0"
 
-"@ngrx/effects@^7.3.0":
-  version "7.4.0"
-  resolved "https://registry.yarnpkg.com/@ngrx/effects/-/effects-7.4.0.tgz#7d1977538cf85e42ab48fd648acdfbc8b52f93d3"
-  integrity sha512-YjgB17WnLCBDPjAkHduKWsLFSGLZryPaTjY3EIvMF+WTRPDlgC5SAv2n7p3YIei6g6IYcEvOwLWBqZHFUXTgBw==
-
-"@ngrx/entity@^7.3.0":
-  version "7.4.0"
-  resolved "https://registry.yarnpkg.com/@ngrx/entity/-/entity-7.4.0.tgz#634cdff1db9629ca0e64c1d6b1e43dc15f4e2ca6"
-  integrity sha512-aFRDTNp6IFkYFlP9gV6hgNgtDYot9KYF8WVbaQTao9ihmdPumMBOCeRttPPiHS/cU41w9nW3xF53NgxQPnEiQA==
-
-"@ngrx/router-store@^7.3.0":
-  version "7.4.0"
-  resolved "https://registry.yarnpkg.com/@ngrx/router-store/-/router-store-7.4.0.tgz#69c085bda3022117169f87ed5753b951de7d376d"
-  integrity sha512-ZpwTO1/ha3pxO7NV3jIfnwipBN1A719IjAOgrcmI8Ut06VH3HY/7JVFTkwLN/FyuHvl4EOlAVYmMAblmrymUWA==
-
-"@ngrx/schematics@^7.3.0":
-  version "7.4.0"
-  resolved "https://registry.yarnpkg.com/@ngrx/schematics/-/schematics-7.4.0.tgz#c430e11e60b4ef9cd60d92569da65b29847bce89"
-  integrity sha512-H0endOV7nYWDaFH7mOJAWFGVymlOYynwjEHZPWeLQFZIFUaekKOrgrHpc+rygu1Hov5ww8lNXHgAunm4vpvwMA==
-
-"@ngrx/store-devtools@^7.3.0":
-  version "7.4.0"
-  resolved "https://registry.yarnpkg.com/@ngrx/store-devtools/-/store-devtools-7.4.0.tgz#5a73469c70322351c4224f4529c5123f587a5997"
-  integrity sha512-ZmPpquprBYUozbLuLMLZzUhI+LnMNGMNg8x1ij9yDxXWQADcJm1Zu7kouYE1r5SoCYxKfwJ3Ia1VQfS3A5S8dw==
-
-"@ngrx/store@^7.3.0":
-  version "7.4.0"
-  resolved "https://registry.yarnpkg.com/@ngrx/store/-/store-7.4.0.tgz#525a343aa45d7f6ca60f3301a23a27669c14bbce"
-  integrity sha512-kwTUHgfgBeAL4RQBjZO46z9v4Xzg8PXAgY4WwXdt3zUk1tF4ZvijMleFvFRUoiJJfxF/UM6jgIZ/yGrX2dXQuA==
-
-"@ngtools/webpack@7.3.9", "@ngtools/webpack@^7.3.9":
-  version "7.3.9"
-  resolved "https://registry.yarnpkg.com/@ngtools/webpack/-/webpack-7.3.9.tgz#db115dba8cc0886d8d822723be4119d3849fb4e3"
-  integrity sha512-+ROpqfCXLdQwfP+UNDLk4p959ZrocpStkdd2Iy9CeOJ8yDkityqpstTwQC3oHzzu/95BiyZ0hrHbM6AsPPIvJg==
-  dependencies:
-    "@angular-devkit/core" "7.3.9"
+"@ngrx/effects@^8.6.0":
+  version "8.6.0"
+  resolved "https://registry.yarnpkg.com/@ngrx/effects/-/effects-8.6.0.tgz#a0d7339597a5128c5cf896ddcf93f73406a45860"
+  integrity sha512-JdyJLQbv/wnE0ZPY9DcDOtF9PzJuzsKWmIWgIGunHF18wdjk5O8Zpkcrxq18wDRL6geg5UTtNJRMvTQhpDbzow==
+
+"@ngrx/entity@^8.6.0":
+  version "8.6.0"
+  resolved "https://registry.yarnpkg.com/@ngrx/entity/-/entity-8.6.0.tgz#63e7875d0e83e552249b8b75bb9b6aba248cae2a"
+  integrity sha512-Qq+ANgsHd2/i7gam1j05hxA8kPWQyf5ewtCLlbtMJI/qLmvA6ruSE8PYNNwrt90wm4BWdks2zKE5ERzvPzto0w==
+
+"@ngrx/router-store@^8.6.0":
+  version "8.6.0"
+  resolved "https://registry.yarnpkg.com/@ngrx/router-store/-/router-store-8.6.0.tgz#3bda275722e476e8604fd57af81f37687662d673"
+  integrity sha512-4Dvl6dfOj15lNZ63wucRNcTEHUi0hEqapOBVRslfAsnaSRo2t1lOvfX7b68IbxPiqzabTBdIeEkJwAC2q/rZZg==
+
+"@ngrx/schematics@^8.6.0":
+  version "8.6.0"
+  resolved "https://registry.yarnpkg.com/@ngrx/schematics/-/schematics-8.6.0.tgz#5387c0abc438768e4cb56c0b617082e0db2f00d7"
+  integrity sha512-d28FVsLWFJYxpMFnqzWvdbFSSPNlLUIezd0c4zlyf4CyNS/C8aw6Lio9xjOJHhgZuHvFuO9GwRrYV/GaS6wC7A==
+
+"@ngrx/store-devtools@^8.6.0":
+  version "8.6.0"
+  resolved "https://registry.yarnpkg.com/@ngrx/store-devtools/-/store-devtools-8.6.0.tgz#ac287e4b094d099781cdc9f3281039c0e988296c"
+  integrity sha512-PWZmiOZE0J56GFfZpuzKLb7w0K2c6OXZSp/eWDeAvtdHFD4/Nas1i4TXtiWWMWWnSZeNs0hNIg4nFJXi2EddJQ==
+
+"@ngrx/store@^8.6.0":
+  version "8.6.0"
+  resolved "https://registry.yarnpkg.com/@ngrx/store/-/store-8.6.0.tgz#8540c5bd40b33fc2f443e7e86f47c0d801b8f413"
+  integrity sha512-K4cvCEa+5hw9qrETQWO+Cha3YbVCAT8yaIKJr/N35KntTL9mQMjoL+51JWLZfBwPV0e19CFgJIyrBnVUTxwr2A==
+
+"@ngtools/webpack@8.3.25", "@ngtools/webpack@^8.3.25":
+  version "8.3.25"
+  resolved "https://registry.yarnpkg.com/@ngtools/webpack/-/webpack-8.3.25.tgz#f33dfb114463662b16b719031fd99ebf21354cf1"
+  integrity sha512-yHvgxXUXlgdWijtzcRjTaUqzK+6TVK/8p7PreBR00GsLxhl4U1jQSC6yDaZUCjOaEkiczFWl4hEuC4wTU/hLdg==
+  dependencies:
+    "@angular-devkit/core" "8.3.25"
     enhanced-resolve "4.1.0"
-    rxjs "6.3.3"
-    tree-kill "1.2.1"
-    webpack-sources "1.3.0"
+    rxjs "6.4.0"
+    tree-kill "1.2.2"
+    webpack-sources "1.4.3"
 
-"@nguniversal/express-engine@^7.1.1":
-  version "7.1.1"
-  resolved "https://registry.yarnpkg.com/@nguniversal/express-engine/-/express-engine-7.1.1.tgz#9445ccb374dabdadccc8de98ca8a79b536ae14de"
-  integrity sha512-RJ2VATA6s48bYNrAfjnkjUCohpR7ehiOySwGA2vuUIWCWXKDIIPxgmET5ffVHy1a2XdMsOgrQ9Whth7+CxnUgw==
+"@nguniversal/express-engine@^8.2.6":
+  version "8.2.6"
+  resolved "https://registry.yarnpkg.com/@nguniversal/express-engine/-/express-engine-8.2.6.tgz#3930551727b5be1256f0aefa1ffd3c37cb420f9f"
+  integrity sha512-IKUKTpesgjYyB0Xg+fFhSbwbGBJhG0Wfn8MkQAi9RgSi8QsrSMkI3oUXc86Z7fpQL55D/ZIH7PekoC0Fmh/kxA==
 
 "@ngx-translate/core@11.0.1":
   version "11.0.1"
@@ -365,10 +1107,10 @@
   dependencies:
     tslib "^1.9.0"
 
-"@nicky-lenaers/ngx-scroll-to@^1.0.0":
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/@nicky-lenaers/ngx-scroll-to/-/ngx-scroll-to-1.0.0.tgz#2afdc03e5b3218bbb5e19ec69fb1e7f7c8eb83dc"
-  integrity sha512-IBKmt9D8gkntSwwQyAWCtOY552JLWcwTDlKOduEF6h8SYfpc1eSJu65rz8zHpur2MRZeLCGaIV+woBLpGYk8YQ==
+"@nicky-lenaers/ngx-scroll-to@^3.0.1":
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/@nicky-lenaers/ngx-scroll-to/-/ngx-scroll-to-3.0.1.tgz#e690e2ce7c6195373ad223cee411daaab3831b12"
+  integrity sha512-n7kwFUfV7B2UyRDQPegziXPp9zmRdEZiIgk2jJSirLrZf2jW96r25DNOvoahjQnK4PS3at+JD9LIWF+WyI0Lhg==
   dependencies:
     tslib "^1.9.0"
 
@@ -377,14 +1119,13 @@
   resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.1.tgz#53f349bb986ab273d601175aa1b25a655ab90ee3"
   integrity sha512-KU/VDjC5RwtDUZiz3d+DHXJF2lp5hB9dn552TXIyptj8SH1vXmR40mG0JgGq03IlYsOgGfcv8xrLpSQ0YUMQdA==
 
-"@schematics/angular@7.3.9":
-  version "7.3.9"
-  resolved "https://registry.yarnpkg.com/@schematics/angular/-/angular-7.3.9.tgz#f57baf1cd9588d4f1035974d06fd8f3d54df021a"
-  integrity sha512-B3lytFtFeYNLfWdlrIzvy3ulFRccD2/zkoL0734J+DAGfUz7vbysJ50RwYL46sQUcKdZdvb48ktfu1S8yooP6Q==
+"@schematics/angular@8.3.25":
+  version "8.3.25"
+  resolved "https://registry.yarnpkg.com/@schematics/angular/-/angular-8.3.25.tgz#11252399e30e2ddb94323e5e438bb69839fb9464"
+  integrity sha512-/vEPtE+fvgsWPml/MVqzmlGPBujadPPNwaTuuj5Uz1aVcKeEYzLkbN8YQOpml4vxZHCF8RDwNdGiU4SZg63Jfg==
   dependencies:
-    "@angular-devkit/core" "7.3.9"
-    "@angular-devkit/schematics" "7.3.9"
-    typescript "3.2.4"
+    "@angular-devkit/core" "8.3.25"
+    "@angular-devkit/schematics" "8.3.25"
 
 "@schematics/angular@^0.7.5":
   version "0.7.5"
@@ -395,18 +1136,18 @@
     "@angular-devkit/schematics" "0.7.5"
     typescript ">=2.6.2 <2.10"
 
-"@schematics/update@0.13.9":
-  version "0.13.9"
-  resolved "https://registry.yarnpkg.com/@schematics/update/-/update-0.13.9.tgz#60d338676d10d24d1b12812a0624f6e7c3dbcd06"
-  integrity sha512-4MQcaKFxhMzZyE//+DknDh3h3duy3avg2oxSHxdwXlCZ8Q92+4lpegjJcSRiqlEwO4qeJ5XnrjrvzfIiaIZOmA==
+"@schematics/update@0.803.25":
+  version "0.803.25"
+  resolved "https://registry.yarnpkg.com/@schematics/update/-/update-0.803.25.tgz#d424dfb4eaa06215ea447993613da2730327097b"
+  integrity sha512-VIlqhJsCStA3aO4llxZ7lAOvQUqppyZdrEO7f/ApIJmuofPQTkO5Hx21tnv0dyExwoqPCSIHzEu4Tmc0/TWM1A==
   dependencies:
-    "@angular-devkit/core" "7.3.9"
-    "@angular-devkit/schematics" "7.3.9"
+    "@angular-devkit/core" "8.3.25"
+    "@angular-devkit/schematics" "8.3.25"
     "@yarnpkg/lockfile" "1.1.0"
     ini "1.3.5"
-    pacote "9.4.0"
-    rxjs "6.3.3"
-    semver "5.6.0"
+    pacote "9.5.5"
+    rxjs "6.4.0"
+    semver "6.3.0"
     semver-intersect "1.4.0"
 
 "@types/acorn@^4.0.3":
@@ -701,15 +1442,6 @@
     semver "^6.3.0"
     tsutils "^3.17.1"
 
-"@webassemblyjs/ast@1.7.11":
-  version "1.7.11"
-  resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.7.11.tgz#b988582cafbb2b095e8b556526f30c90d057cace"
-  integrity sha512-ZEzy4vjvTzScC+SH8RBssQUawpaInUdMTYwYYLh54/s8TuT0gBLuyUnppKsVyZEi876VmmStKsUs28UxPgdvrA==
-  dependencies:
-    "@webassemblyjs/helper-module-context" "1.7.11"
-    "@webassemblyjs/helper-wasm-bytecode" "1.7.11"
-    "@webassemblyjs/wast-parser" "1.7.11"
-
 "@webassemblyjs/ast@1.8.5":
   version "1.8.5"
   resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.8.5.tgz#51b1c5fe6576a34953bf4b253df9f0d490d9e359"
@@ -719,43 +1451,21 @@
     "@webassemblyjs/helper-wasm-bytecode" "1.8.5"
     "@webassemblyjs/wast-parser" "1.8.5"
 
-"@webassemblyjs/floating-point-hex-parser@1.7.11":
-  version "1.7.11"
-  resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.7.11.tgz#a69f0af6502eb9a3c045555b1a6129d3d3f2e313"
-  integrity sha512-zY8dSNyYcgzNRNT666/zOoAyImshm3ycKdoLsyDw/Bwo6+/uktb7p4xyApuef1dwEBo/U/SYQzbGBvV+nru2Xg==
-
 "@webassemblyjs/floating-point-hex-parser@1.8.5":
   version "1.8.5"
   resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.8.5.tgz#1ba926a2923613edce496fd5b02e8ce8a5f49721"
   integrity sha512-9p+79WHru1oqBh9ewP9zW95E3XAo+90oth7S5Re3eQnECGq59ly1Ri5tsIipKGpiStHsUYmY3zMLqtk3gTcOtQ==
 
-"@webassemblyjs/helper-api-error@1.7.11":
-  version "1.7.11"
-  resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.7.11.tgz#c7b6bb8105f84039511a2b39ce494f193818a32a"
-  integrity sha512-7r1qXLmiglC+wPNkGuXCvkmalyEstKVwcueZRP2GNC2PAvxbLYwLLPr14rcdJaE4UtHxQKfFkuDFuv91ipqvXg==
-
 "@webassemblyjs/helper-api-error@1.8.5":
   version "1.8.5"
   resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.8.5.tgz#c49dad22f645227c5edb610bdb9697f1aab721f7"
   integrity sha512-Za/tnzsvnqdaSPOUXHyKJ2XI7PDX64kWtURyGiJJZKVEdFOsdKUCPTNEVFZq3zJ2R0G5wc2PZ5gvdTRFgm81zA==
 
-"@webassemblyjs/helper-buffer@1.7.11":
-  version "1.7.11"
-  resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.7.11.tgz#3122d48dcc6c9456ed982debe16c8f37101df39b"
-  integrity sha512-MynuervdylPPh3ix+mKZloTcL06P8tenNH3sx6s0qE8SLR6DdwnfgA7Hc9NSYeob2jrW5Vql6GVlsQzKQCa13w==
-
 "@webassemblyjs/helper-buffer@1.8.5":
   version "1.8.5"
   resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.8.5.tgz#fea93e429863dd5e4338555f42292385a653f204"
   integrity sha512-Ri2R8nOS0U6G49Q86goFIPNgjyl6+oE1abW1pS84BuhP1Qcr5JqMwRFT3Ah3ADDDYGEgGs1iyb1DGX+kAi/c/Q==
 
-"@webassemblyjs/helper-code-frame@1.7.11":
-  version "1.7.11"
-  resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.7.11.tgz#cf8f106e746662a0da29bdef635fcd3d1248364b"
-  integrity sha512-T8ESC9KMXFTXA5urJcyor5cn6qWeZ4/zLPyWeEXZ03hj/x9weSokGNkVCdnhSabKGYWxElSdgJ+sFa9G/RdHNw==
-  dependencies:
-    "@webassemblyjs/wast-printer" "1.7.11"
-
 "@webassemblyjs/helper-code-frame@1.8.5":
   version "1.8.5"
   resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.8.5.tgz#9a740ff48e3faa3022b1dff54423df9aa293c25e"
@@ -763,21 +1473,11 @@
   dependencies:
     "@webassemblyjs/wast-printer" "1.8.5"
 
-"@webassemblyjs/helper-fsm@1.7.11":
-  version "1.7.11"
-  resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.7.11.tgz#df38882a624080d03f7503f93e3f17ac5ac01181"
-  integrity sha512-nsAQWNP1+8Z6tkzdYlXT0kxfa2Z1tRTARd8wYnc/e3Zv3VydVVnaeePgqUzFrpkGUyhUUxOl5ML7f1NuT+gC0A==
-
 "@webassemblyjs/helper-fsm@1.8.5":
   version "1.8.5"
   resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.8.5.tgz#ba0b7d3b3f7e4733da6059c9332275d860702452"
   integrity sha512-kRuX/saORcg8se/ft6Q2UbRpZwP4y7YrWsLXPbbmtepKr22i8Z4O3V5QE9DbZK908dh5Xya4Un57SDIKwB9eow==
 
-"@webassemblyjs/helper-module-context@1.7.11":
-  version "1.7.11"
-  resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.7.11.tgz#d874d722e51e62ac202476935d649c802fa0e209"
-  integrity sha512-JxfD5DX8Ygq4PvXDucq0M+sbUFA7BJAv/GGl9ITovqE+idGX+J3QSzJYz+LwQmL7fC3Rs+utvWoJxDb6pmC0qg==
-
 "@webassemblyjs/helper-module-context@1.8.5":
   version "1.8.5"
   resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.8.5.tgz#def4b9927b0101dc8cbbd8d1edb5b7b9c82eb245"
@@ -786,26 +1486,11 @@
     "@webassemblyjs/ast" "1.8.5"
     mamacro "^0.0.3"
 
-"@webassemblyjs/helper-wasm-bytecode@1.7.11":
-  version "1.7.11"
-  resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.7.11.tgz#dd9a1e817f1c2eb105b4cf1013093cb9f3c9cb06"
-  integrity sha512-cMXeVS9rhoXsI9LLL4tJxBgVD/KMOKXuFqYb5oCJ/opScWpkCMEz9EJtkonaNcnLv2R3K5jIeS4TRj/drde1JQ==
-
 "@webassemblyjs/helper-wasm-bytecode@1.8.5":
   version "1.8.5"
   resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.8.5.tgz#537a750eddf5c1e932f3744206551c91c1b93e61"
   integrity sha512-Cu4YMYG3Ddl72CbmpjU/wbP6SACcOPVbHN1dI4VJNJVgFwaKf1ppeFJrwydOG3NDHxVGuCfPlLZNyEdIYlQ6QQ==
 
-"@webassemblyjs/helper-wasm-section@1.7.11":
-  version "1.7.11"
-  resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.7.11.tgz#9c9ac41ecf9fbcfffc96f6d2675e2de33811e68a"
-  integrity sha512-8ZRY5iZbZdtNFE5UFunB8mmBEAbSI3guwbrsCl4fWdfRiAcvqQpeqd5KHhSWLL5wuxo53zcaGZDBU64qgn4I4Q==
-  dependencies:
-    "@webassemblyjs/ast" "1.7.11"
-    "@webassemblyjs/helper-buffer" "1.7.11"
-    "@webassemblyjs/helper-wasm-bytecode" "1.7.11"
-    "@webassemblyjs/wasm-gen" "1.7.11"
-
 "@webassemblyjs/helper-wasm-section@1.8.5":
   version "1.8.5"
   resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.8.5.tgz#74ca6a6bcbe19e50a3b6b462847e69503e6bfcbf"
@@ -816,13 +1501,6 @@
     "@webassemblyjs/helper-wasm-bytecode" "1.8.5"
     "@webassemblyjs/wasm-gen" "1.8.5"
 
-"@webassemblyjs/ieee754@1.7.11":
-  version "1.7.11"
-  resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.7.11.tgz#c95839eb63757a31880aaec7b6512d4191ac640b"
-  integrity sha512-Mmqx/cS68K1tSrvRLtaV/Lp3NZWzXtOHUW2IvDvl2sihAwJh4ACE0eL6A8FvMyDG9abes3saB6dMimLOs+HMoQ==
-  dependencies:
-    "@xtuc/ieee754" "^1.2.0"
-
 "@webassemblyjs/ieee754@1.8.5":
   version "1.8.5"
   resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.8.5.tgz#712329dbef240f36bf57bd2f7b8fb9bf4154421e"
@@ -830,13 +1508,6 @@
   dependencies:
     "@xtuc/ieee754" "^1.2.0"
 
-"@webassemblyjs/leb128@1.7.11":
-  version "1.7.11"
-  resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.7.11.tgz#d7267a1ee9c4594fd3f7e37298818ec65687db63"
-  integrity sha512-vuGmgZjjp3zjcerQg+JA+tGOncOnJLWVkt8Aze5eWQLwTQGNgVLcyOTqgSCxWTR4J42ijHbBxnuRaL1Rv7XMdw==
-  dependencies:
-    "@xtuc/long" "4.2.1"
-
 "@webassemblyjs/leb128@1.8.5":
   version "1.8.5"
   resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.8.5.tgz#044edeb34ea679f3e04cd4fd9824d5e35767ae10"
@@ -844,30 +1515,11 @@
   dependencies:
     "@xtuc/long" "4.2.2"
 
-"@webassemblyjs/utf8@1.7.11":
-  version "1.7.11"
-  resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.7.11.tgz#06d7218ea9fdc94a6793aa92208160db3d26ee82"
-  integrity sha512-C6GFkc7aErQIAH+BMrIdVSmW+6HSe20wg57HEC1uqJP8E/xpMjXqQUxkQw07MhNDSDcGpxI9G5JSNOQCqJk4sA==
-
 "@webassemblyjs/utf8@1.8.5":
   version "1.8.5"
   resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.8.5.tgz#a8bf3b5d8ffe986c7c1e373ccbdc2a0915f0cedc"
   integrity sha512-U7zgftmQriw37tfD934UNInokz6yTmn29inT2cAetAsaU9YeVCveWEwhKL1Mg4yS7q//NGdzy79nlXh3bT8Kjw==
 
-"@webassemblyjs/wasm-edit@1.7.11":
-  version "1.7.11"
-  resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.7.11.tgz#8c74ca474d4f951d01dbae9bd70814ee22a82005"
-  integrity sha512-FUd97guNGsCZQgeTPKdgxJhBXkUbMTY6hFPf2Y4OedXd48H97J+sOY2Ltaq6WGVpIH8o/TGOVNiVz/SbpEMJGg==
-  dependencies:
-    "@webassemblyjs/ast" "1.7.11"
-    "@webassemblyjs/helper-buffer" "1.7.11"
-    "@webassemblyjs/helper-wasm-bytecode" "1.7.11"
-    "@webassemblyjs/helper-wasm-section" "1.7.11"
-    "@webassemblyjs/wasm-gen" "1.7.11"
-    "@webassemblyjs/wasm-opt" "1.7.11"
-    "@webassemblyjs/wasm-parser" "1.7.11"
-    "@webassemblyjs/wast-printer" "1.7.11"
-
 "@webassemblyjs/wasm-edit@1.8.5":
   version "1.8.5"
   resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.8.5.tgz#962da12aa5acc1c131c81c4232991c82ce56e01a"
@@ -882,17 +1534,6 @@
     "@webassemblyjs/wasm-parser" "1.8.5"
     "@webassemblyjs/wast-printer" "1.8.5"
 
-"@webassemblyjs/wasm-gen@1.7.11":
-  version "1.7.11"
-  resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.7.11.tgz#9bbba942f22375686a6fb759afcd7ac9c45da1a8"
-  integrity sha512-U/KDYp7fgAZX5KPfq4NOupK/BmhDc5Kjy2GIqstMhvvdJRcER/kUsMThpWeRP8BMn4LXaKhSTggIJPOeYHwISA==
-  dependencies:
-    "@webassemblyjs/ast" "1.7.11"
-    "@webassemblyjs/helper-wasm-bytecode" "1.7.11"
-    "@webassemblyjs/ieee754" "1.7.11"
-    "@webassemblyjs/leb128" "1.7.11"
-    "@webassemblyjs/utf8" "1.7.11"
-
 "@webassemblyjs/wasm-gen@1.8.5":
   version "1.8.5"
   resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.8.5.tgz#54840766c2c1002eb64ed1abe720aded714f98bc"
@@ -904,16 +1545,6 @@
     "@webassemblyjs/leb128" "1.8.5"
     "@webassemblyjs/utf8" "1.8.5"
 
-"@webassemblyjs/wasm-opt@1.7.11":
-  version "1.7.11"
-  resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.7.11.tgz#b331e8e7cef8f8e2f007d42c3a36a0580a7d6ca7"
-  integrity sha512-XynkOwQyiRidh0GLua7SkeHvAPXQV/RxsUeERILmAInZegApOUAIJfRuPYe2F7RcjOC9tW3Cb9juPvAC/sCqvg==
-  dependencies:
-    "@webassemblyjs/ast" "1.7.11"
-    "@webassemblyjs/helper-buffer" "1.7.11"
-    "@webassemblyjs/wasm-gen" "1.7.11"
-    "@webassemblyjs/wasm-parser" "1.7.11"
-
 "@webassemblyjs/wasm-opt@1.8.5":
   version "1.8.5"
   resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.8.5.tgz#b24d9f6ba50394af1349f510afa8ffcb8a63d264"
@@ -924,18 +1555,6 @@
     "@webassemblyjs/wasm-gen" "1.8.5"
     "@webassemblyjs/wasm-parser" "1.8.5"
 
-"@webassemblyjs/wasm-parser@1.7.11":
-  version "1.7.11"
-  resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.7.11.tgz#6e3d20fa6a3519f6b084ef9391ad58211efb0a1a"
-  integrity sha512-6lmXRTrrZjYD8Ng8xRyvyXQJYUQKYSXhJqXOBLw24rdiXsHAOlvw5PhesjdcaMadU/pyPQOJ5dHreMjBxwnQKg==
-  dependencies:
-    "@webassemblyjs/ast" "1.7.11"
-    "@webassemblyjs/helper-api-error" "1.7.11"
-    "@webassemblyjs/helper-wasm-bytecode" "1.7.11"
-    "@webassemblyjs/ieee754" "1.7.11"
-    "@webassemblyjs/leb128" "1.7.11"
-    "@webassemblyjs/utf8" "1.7.11"
-
 "@webassemblyjs/wasm-parser@1.8.5":
   version "1.8.5"
   resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.8.5.tgz#21576f0ec88b91427357b8536383668ef7c66b8d"
@@ -948,18 +1567,6 @@
     "@webassemblyjs/leb128" "1.8.5"
     "@webassemblyjs/utf8" "1.8.5"
 
-"@webassemblyjs/wast-parser@1.7.11":
-  version "1.7.11"
-  resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.7.11.tgz#25bd117562ca8c002720ff8116ef9072d9ca869c"
-  integrity sha512-lEyVCg2np15tS+dm7+JJTNhNWq9yTZvi3qEhAIIOaofcYlUp0UR5/tVqOwa/gXYr3gjwSZqw+/lS9dscyLelbQ==
-  dependencies:
-    "@webassemblyjs/ast" "1.7.11"
-    "@webassemblyjs/floating-point-hex-parser" "1.7.11"
-    "@webassemblyjs/helper-api-error" "1.7.11"
-    "@webassemblyjs/helper-code-frame" "1.7.11"
-    "@webassemblyjs/helper-fsm" "1.7.11"
-    "@xtuc/long" "4.2.1"
-
 "@webassemblyjs/wast-parser@1.8.5":
   version "1.8.5"
   resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.8.5.tgz#e10eecd542d0e7bd394f6827c49f3df6d4eefb8c"
@@ -972,15 +1579,6 @@
     "@webassemblyjs/helper-fsm" "1.8.5"
     "@xtuc/long" "4.2.2"
 
-"@webassemblyjs/wast-printer@1.7.11":
-  version "1.7.11"
-  resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.7.11.tgz#c4245b6de242cb50a2cc950174fdbf65c78d7813"
-  integrity sha512-m5vkAsuJ32QpkdkDOUPGSltrg8Cuk3KBx4YrmAGQwCZPRdUHXxG4phIOuuycLemHFr74sWL9Wthqss4fzdzSwg==
-  dependencies:
-    "@webassemblyjs/ast" "1.7.11"
-    "@webassemblyjs/wast-parser" "1.7.11"
-    "@xtuc/long" "4.2.1"
-
 "@webassemblyjs/wast-printer@1.8.5":
   version "1.8.5"
   resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.8.5.tgz#114bbc481fd10ca0e23b3560fa812748b0bae5bc"
@@ -995,11 +1593,6 @@
   resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790"
   integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==
 
-"@xtuc/long@4.2.1":
-  version "4.2.1"
-  resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.1.tgz#5c85d662f76fa1d34575766c5dcd6615abcd30d8"
-  integrity sha512-FZdkNBDqBRHKQ2MEbSC17xnPFOhZxeJ2YGSfr2BKf3sujG49Qe3bB+rGCwQfIaA7WHnGeGkSijX4FuBCdrzW/g==
-
 "@xtuc/long@4.2.2":
   version "4.2.2"
   resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d"
@@ -1044,11 +1637,6 @@ accepts@~1.3.7:
     mime-types "~2.1.24"
     negotiator "0.6.2"
 
-acorn-dynamic-import@^4.0.0:
-  version "4.0.0"
-  resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-4.0.0.tgz#482210140582a36b83c3e342e1cfebcaa9240948"
-  integrity sha512-d3OEjQV4ROpoflsnUA8HozoIR504TFxNivYEUi6uwz0IYhBkTDXGuWlNdMtybRt3nqVx/L6XqMt0FxkXuWKZhw==
-
 acorn-jsx@^5.1.0:
   version "5.1.0"
   resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.1.0.tgz#294adb71b57398b0680015f0a38c563ee1db5384"
@@ -1064,16 +1652,16 @@ acorn@^5.5.0:
   resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.2.tgz#91fa871883485d06708800318404e72bfb26dcc5"
   integrity sha512-cJrKCNcr2kv8dlDnbw+JPUGjHZzo4myaxOLmpOX8a+rgX94YeTcTMv/LFJUSByRpc+i4GgVnnhLxvMu/2Y+rqw==
 
-acorn@^6.0.5, acorn@^6.2.1:
-  version "6.4.0"
-  resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.0.tgz#b659d2ffbafa24baf5db1cdbb2c94a983ecd2784"
-  integrity sha512-gac8OEcQ2Li1dxIEWGZzsp2BitJxwkwcOm0zHAJLcPJaVvm58FRnk6RkuLRpU1EujipU2ZFODv2P9DLMfnV8mw==
-
 acorn@^6.0.7:
   version "6.1.1"
   resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.1.1.tgz#7d25ae05bb8ad1f9b699108e1094ecd7884adc1f"
   integrity sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA==
 
+acorn@^6.2.1:
+  version "6.4.0"
+  resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.0.tgz#b659d2ffbafa24baf5db1cdbb2c94a983ecd2784"
+  integrity sha512-gac8OEcQ2Li1dxIEWGZzsp2BitJxwkwcOm0zHAJLcPJaVvm58FRnk6RkuLRpU1EujipU2ZFODv2P9DLMfnV8mw==
+
 acorn@^7.1.0:
   version "7.1.0"
   resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.1.0.tgz#949d36f2c292535da602283586c2477c57eb2d6c"
@@ -1089,7 +1677,7 @@ after@0.8.2:
   resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f"
   integrity sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=
 
-agent-base@4:
+agent-base@4, agent-base@^4.3.0:
   version "4.3.0"
   resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.3.0.tgz#8165f01c436009bccad0b1d122f05ed770efc6ee"
   integrity sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==
@@ -1133,10 +1721,10 @@ ajv-keywords@^3.4.1:
   resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.4.1.tgz#ef916e271c64ac12171fd8384eaae6b2345854da"
   integrity sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ==
 
-ajv@6.9.1:
-  version "6.9.1"
-  resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.9.1.tgz#a4d3683d74abc5670e75f0b16520f70a20ea8dc1"
-  integrity sha512-XDN92U311aINL77ieWHmqCcNlwjoP5cHXDxIxbf2MaPYuCXOHS7gHH8jktxeK5omgd52XbSTX6a4Piwd1pQmzA==
+ajv@6.10.2, ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2:
+  version "6.10.2"
+  resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.2.tgz#d3cea04d6b017b2894ad69040fec8b623eb4bd52"
+  integrity sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==
   dependencies:
     fast-deep-equal "^2.0.1"
     fast-json-stable-stringify "^2.0.0"
@@ -1153,16 +1741,6 @@ ajv@^5.0.0, ajv@^5.3.0:
     fast-json-stable-stringify "^2.0.0"
     json-schema-traverse "^0.3.0"
 
-ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2:
-  version "6.10.2"
-  resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.2.tgz#d3cea04d6b017b2894ad69040fec8b623eb4bd52"
-  integrity sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==
-  dependencies:
-    fast-deep-equal "^2.0.1"
-    fast-json-stable-stringify "^2.0.0"
-    json-schema-traverse "^0.4.1"
-    uri-js "^4.2.2"
-
 ajv@^6.1.1:
   version "6.5.3"
   resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.5.3.tgz#71a569d189ecf4f4f321224fecb166f071dd90f9"
@@ -1198,11 +1776,6 @@ angular-idle-preload@3.0.0:
   resolved "https://registry.yarnpkg.com/angular-idle-preload/-/angular-idle-preload-3.0.0.tgz#decace34d9fac1cb00000727a6dc5caafdb84e4d"
   integrity sha512-W3P2m2B6MHdt1DVunH6H3VWkAZrG3ZwxGcPjedVvIyRhg/LmMtILoizHSxTXw3fsKIEdAPwGObXGpML9WD1jJA==
 
-angular-sortablejs@^2.5.0:
-  version "2.6.0"
-  resolved "https://registry.yarnpkg.com/angular-sortablejs/-/angular-sortablejs-2.6.0.tgz#d41a5dcaf1dd08bcd79677b1fc0c64fb872fe2d3"
-  integrity sha512-f/W5WUeySMLhMqUHpAqzHCi3+yj6uwPcwr5FcKRRF+o5nzuYR5ppW1GJJk/Px1Q0HhL2//z9O3QZpEVMlvHf5w==
-
 angular2-template-loader@0.6.2:
   version "0.6.2"
   resolved "https://registry.yarnpkg.com/angular2-template-loader/-/angular2-template-loader-0.6.2.tgz#c0d44e90fff0fac95e8b23f043acda7fd1c51d7c"
@@ -1231,6 +1804,11 @@ ansi-align@^2.0.0:
   dependencies:
     string-width "^2.0.0"
 
+ansi-colors@4.1.1:
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348"
+  integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==
+
 ansi-colors@^1.0.1:
   version "1.1.0"
   resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-1.1.0.tgz#6374b4dd5d4718ff3ce27a671a3b1cad077132a9"
@@ -1255,11 +1833,6 @@ ansi-escapes@^1.1.0:
   resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e"
   integrity sha1-06ioOzGapneTZisT52HHkRQiMG4=
 
-ansi-escapes@^3.0.0:
-  version "3.1.0"
-  resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.1.0.tgz#f73207bb81207d75fd6c83f125af26eea378ca30"
-  integrity sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw==
-
 ansi-escapes@^4.2.1:
   version "4.3.0"
   resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.0.tgz#a4ce2b33d6b214b7950d8595c212f12ac9cc569d"
@@ -1336,12 +1909,20 @@ anymatch@^2.0.0:
     micromatch "^3.1.4"
     normalize-path "^2.1.1"
 
+anymatch@~3.1.1:
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142"
+  integrity sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==
+  dependencies:
+    normalize-path "^3.0.0"
+    picomatch "^2.0.4"
+
 app-root-path@^2.2.1:
   version "2.2.1"
   resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-2.2.1.tgz#d0df4a682ee408273583d43f6f79e9892624bc9a"
   integrity sha512-91IFKeKk7FjfmezPKkwtaRvSpnUc4gDwPAjA1YZ9Gn0q0PPeW+vbeUsZuyDwjI7+QTHhcLen2v25fi/AmhvbJA==
 
-aproba@^1.0.3, aproba@^1.1.1:
+aproba@^1.1.1:
   version "1.2.0"
   resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a"
   integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==
@@ -1375,14 +1956,6 @@ archiver@^3.0.0:
     tar-stream "^2.1.0"
     zip-stream "^2.1.2"
 
-are-we-there-yet@~1.1.2:
-  version "1.1.5"
-  resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21"
-  integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==
-  dependencies:
-    delegates "^1.0.0"
-    readable-stream "^2.0.6"
-
 argparse@^1.0.7:
   version "1.0.10"
   resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
@@ -1505,7 +2078,7 @@ arrify@^1.0.0, arrify@^1.0.1:
   resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
   integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=
 
-asap@~2.0.3:
+asap@^2.0.0, asap@~2.0.3:
   version "2.0.6"
   resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
   integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=
@@ -1563,11 +2136,6 @@ async-each@^1.0.1:
   resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf"
   integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==
 
-async-foreach@^0.1.3:
-  version "0.1.3"
-  resolved "https://registry.yarnpkg.com/async-foreach/-/async-foreach-0.1.3.tgz#36121f845c0578172de419a97dbeb1d16ec34542"
-  integrity sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI=
-
 async-limiter@~1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8"
@@ -1609,17 +2177,18 @@ atob@^2.1.1:
   resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
   integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==
 
-autoprefixer@9.4.6:
-  version "9.4.6"
-  resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.4.6.tgz#0ace275e33b37de16b09a5547dbfe73a98c1d446"
-  integrity sha512-Yp51mevbOEdxDUy5WjiKtpQaecqYq9OqZSL04rSoCiry7Tc5I9FEyo3bfxiTJc1DfHeKwSFCUYbBAiOQ2VGfiw==
+autoprefixer@9.6.1:
+  version "9.6.1"
+  resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.6.1.tgz#51967a02d2d2300bb01866c1611ec8348d355a47"
+  integrity sha512-aVo5WxR3VyvyJxcJC3h4FKfwCQvQWb1tSI5VHNibddCVWrcD1NvlxEweg3TSgiPztMnWfjpy2FURKA2kvDE+Tw==
   dependencies:
-    browserslist "^4.4.1"
-    caniuse-lite "^1.0.30000929"
+    browserslist "^4.6.3"
+    caniuse-lite "^1.0.30000980"
+    chalk "^2.4.2"
     normalize-range "^0.1.2"
     num2fraction "^1.2.2"
-    postcss "^7.0.13"
-    postcss-value-parser "^3.3.1"
+    postcss "^7.0.17"
+    postcss-value-parser "^4.0.0"
 
 autoprefixer@^7.1.1:
   version "7.2.6"
@@ -1693,6 +2262,13 @@ babel-messages@^6.23.0:
   dependencies:
     babel-runtime "^6.22.0"
 
+babel-plugin-dynamic-import-node@^2.3.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.0.tgz#f00f507bdaa3c3e3ff6e7e5e98d90a7acab96f7f"
+  integrity sha512-o6qFkpeQEBxcqt0XYlWzAVxNCSCZdUgcR8IRlhD/8DylxjjO4foPcvTW0GGKa/cVt3rvxZ7o5ippJ+/0nvLhlQ==
+  dependencies:
+    object.assign "^4.1.0"
+
 babel-polyfill@6.23.0:
   version "6.23.0"
   resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.23.0.tgz#8364ca62df8eafb830499f699177466c3b03499d"
@@ -1855,6 +2431,18 @@ binary-extensions@^1.0.0:
   resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.11.0.tgz#46aa1751fb6a2f93ee5e689bb1087d4b14c6c205"
   integrity sha1-RqoXUftqL5PuXmibsQh9SxTGwgU=
 
+binary-extensions@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.0.0.tgz#23c0df14f6a88077f5f986c0d167ec03c3d5537c"
+  integrity sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==
+
+bindings@^1.5.0:
+  version "1.5.0"
+  resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df"
+  integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==
+  dependencies:
+    file-uri-to-path "1.0.0"
+
 bl@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/bl/-/bl-3.0.0.tgz#3611ec00579fd18561754360b21e9f784500ff88"
@@ -1867,13 +2455,6 @@ blob@0.0.4:
   resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.4.tgz#bcf13052ca54463f30f9fc7e95b9a47630a94921"
   integrity sha1-vPEwUspURj8w+fx+lbmkdjCpSSE=
 
-block-stream@*:
-  version "0.0.9"
-  resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a"
-  integrity sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=
-  dependencies:
-    inherits "~2.0.0"
-
 blocking-proxy@^1.0.0:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/blocking-proxy/-/blocking-proxy-1.0.1.tgz#81d6fd1fe13a4c0d6957df7f91b75e98dac40cb2"
@@ -2012,6 +2593,13 @@ braces@^2.3.0, braces@^2.3.1, braces@^2.3.2:
     split-string "^3.0.2"
     to-regex "^3.0.1"
 
+braces@~3.0.2:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
+  integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
+  dependencies:
+    fill-range "^7.0.1"
+
 brorand@^1.0.1:
   version "1.1.0"
   resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f"
@@ -2081,6 +2669,15 @@ browserify-zlib@^0.2.0:
   dependencies:
     pako "~1.0.5"
 
+browserslist@4.8.6, browserslist@^4.6.3, browserslist@^4.8.2, browserslist@^4.8.3, browserslist@^4.8.5:
+  version "4.8.6"
+  resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.8.6.tgz#96406f3f5f0755d272e27a66f4163ca821590a7e"
+  integrity sha512-ZHao85gf0eZ0ESxLfCp73GG9O/VTytYDIkIiZDlURppLTI9wErSM/5yAKEq6rcUdxBLjMELmrYUJGg5sxGKMHg==
+  dependencies:
+    caniuse-lite "^1.0.30001023"
+    electron-to-chromium "^1.3.341"
+    node-releases "^1.1.47"
+
 browserslist@^2.0.0, browserslist@^2.11.3:
   version "2.11.3"
   resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-2.11.3.tgz#fe36167aed1bbcde4827ebfe71347a2cc70b99b2"
@@ -2107,15 +2704,6 @@ browserslist@^4.0.2:
     electron-to-chromium "^1.3.61"
     node-releases "^1.0.0-alpha.11"
 
-browserslist@^4.4.1:
-  version "4.8.2"
-  resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.8.2.tgz#b45720ad5fbc8713b7253c20766f701c9a694289"
-  integrity sha512-+M4oeaTplPm/f1pXDw84YohEv7B1i/2Aisei8s4s6k3QsoSHa7i5sz8u/cGQkkatCPxMASKxPualR4wwYgVboA==
-  dependencies:
-    caniuse-lite "^1.0.30001015"
-    electron-to-chromium "^1.3.322"
-    node-releases "^1.1.42"
-
 browserstack@^1.5.1:
   version "1.5.1"
   resolved "https://registry.yarnpkg.com/browserstack/-/browserstack-1.5.1.tgz#e2dfa66ffee940ebad0a07f7e00fd4687c455d66"
@@ -2213,35 +2801,17 @@ bytes@3.1.0:
   resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6"
   integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==
 
-cacache@^10.0.4:
-  version "10.0.4"
-  resolved "https://registry.yarnpkg.com/cacache/-/cacache-10.0.4.tgz#6452367999eff9d4188aefd9a14e9d7c6a263460"
-  integrity sha512-Dph0MzuH+rTQzGPNT9fAnrPmMmjKfST6trxJeK7NQuHRaVw24VzPRWTmg9MpcwOVQZO0E1FBICUlFeNaKPIfHA==
-  dependencies:
-    bluebird "^3.5.1"
-    chownr "^1.0.1"
-    glob "^7.1.2"
-    graceful-fs "^4.1.11"
-    lru-cache "^4.1.1"
-    mississippi "^2.0.0"
-    mkdirp "^0.5.1"
-    move-concurrently "^1.0.1"
-    promise-inflight "^1.0.1"
-    rimraf "^2.6.2"
-    ssri "^5.2.4"
-    unique-filename "^1.1.0"
-    y18n "^4.0.0"
-
-cacache@^11.0.2, cacache@^11.3.2, cacache@^11.3.3:
-  version "11.3.3"
-  resolved "https://registry.yarnpkg.com/cacache/-/cacache-11.3.3.tgz#8bd29df8c6a718a6ebd2d010da4d7972ae3bbadc"
-  integrity sha512-p8WcneCytvzPxhDvYp31PD039vi77I12W+/KfR9S8AZbaiARFBCpsPJS+9uhWfeBfeAtW7o/4vt3MUqLkbY6nA==
+cacache@12.0.2:
+  version "12.0.2"
+  resolved "https://registry.yarnpkg.com/cacache/-/cacache-12.0.2.tgz#8db03205e36089a3df6954c66ce92541441ac46c"
+  integrity sha512-ifKgxH2CKhJEg6tNdAwziu6Q33EvuG26tYcda6PT3WKisZcYDXsnEdnRv67Po3yCzFfaSoMjGZzJyD2c3DT1dg==
   dependencies:
     bluebird "^3.5.5"
     chownr "^1.1.1"
     figgy-pudding "^3.5.1"
     glob "^7.1.4"
     graceful-fs "^4.1.15"
+    infer-owner "^1.0.3"
     lru-cache "^5.1.1"
     mississippi "^3.0.0"
     mkdirp "^0.5.1"
@@ -2252,7 +2822,7 @@ cacache@^11.0.2, cacache@^11.3.2, cacache@^11.3.3:
     unique-filename "^1.1.1"
     y18n "^4.0.0"
 
-cacache@^12.0.2, cacache@^12.0.3:
+cacache@^12.0.0, cacache@^12.0.2, cacache@^12.0.3:
   version "12.0.3"
   resolved "https://registry.yarnpkg.com/cacache/-/cacache-12.0.3.tgz#be99abba4e1bf5df461cd5a2c1071fc432573390"
   integrity sha512-kqdmfXEGFepesTuROHMs3MpFLWrPkSSpRqOw80RCflZXy/khxaArvFrQ7uJxSUduzAufc6G0g1VUCOZXxWavPw==
@@ -2367,12 +2937,7 @@ camelcase@^2.0.0:
   resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f"
   integrity sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=
 
-camelcase@^3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a"
-  integrity sha1-MvxLn82vhF/N9+c7uXysImHwqwo=
-
-camelcase@^4.0.0, camelcase@^4.1.0:
+camelcase@^4.0.0:
   version "4.1.0"
   resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd"
   integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=
@@ -2402,21 +2967,26 @@ caniuse-api@^3.0.0:
     lodash.memoize "^4.1.2"
     lodash.uniq "^4.5.0"
 
+caniuse-lite@1.0.30001024:
+  version "1.0.30001024"
+  resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001024.tgz#7feb6793fd5c9d7e0d4c01c80321855592a46b73"
+  integrity sha512-LubRSEPpOlKlhZw9wGlLHo8ZVj6ugGU3xGUfLPneNBledSd9lIM5cCGZ9Mz/mMCJUhEt4jZpYteZNVRdJw5FRA==
+
 caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000697, caniuse-lite@^1.0.30000792, caniuse-lite@^1.0.30000805, caniuse-lite@^1.0.30000878:
   version "1.0.30000883"
   resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000883.tgz#597c1eabfb379bd9fbeaa778632762eb574706ac"
   integrity sha512-ovvb0uya4cKJct8Rj9Olstz0LaWmyJhCp3NawRG5fVigka8pEhIIwipF7zyYd2Q58UZb5YfIt52pVF444uj2kQ==
 
-caniuse-lite@^1.0.30000929, caniuse-lite@^1.0.30001015:
-  version "1.0.30001016"
-  resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001016.tgz#16ea48d7d6e8caf3cad3295c2d746fe38c4e7f66"
-  integrity sha512-yYQ2QfotceRiH4U+h1Us86WJXtVHDmy3nEKIdYPsZCYnOV5/tMgGbmoIlrMzmh2VXlproqYtVaKeGDBkMZifFA==
-
 caniuse-lite@^1.0.30000939:
   version "1.0.30000948"
   resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000948.tgz#793ed7c28fe664856beb92b43fc013fc22b81633"
   integrity sha512-Lw4y7oz1X5MOMZm+2IFaSISqVVQvUuD+ZUSfeYK/SlYiMjkHN/eJ2PDfJehW5NA6JjrxYSSnIWfwjeObQMEjFQ==
 
+caniuse-lite@^1.0.30000980, caniuse-lite@^1.0.30001023:
+  version "1.0.30001025"
+  resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001025.tgz#30336a8aca7f98618eb3cf38e35184e13d4e5fe6"
+  integrity sha512-SKyFdHYfXUZf5V85+PJgLYyit27q4wgvZuf8QTOk1osbypcROihMBlx9GRar2/pIcKH2r4OehdlBr9x6PXetAQ==
+
 canonical-path@1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/canonical-path/-/canonical-path-1.0.0.tgz#fcb470c23958def85081856be7a86e904f180d1d"
@@ -2479,7 +3049,22 @@ check-types@^7.3.0:
   resolved "https://registry.yarnpkg.com/check-types/-/check-types-7.4.0.tgz#0378ec1b9616ec71f774931a3c6516fad8c152f4"
   integrity sha512-YbulWHdfP99UfZ73NcUDlNJhEIDgm9Doq9GhpyXbF+7Aegi3CVV7qqMCKTTqJxlvEvnQBp9IA+dxsGN6xK/nSg==
 
-chokidar@2.0.4, chokidar@^2.0.0, chokidar@^2.0.2, chokidar@^2.0.3, chokidar@^2.0.4:
+"chokidar@>=2.0.0 <4.0.0":
+  version "3.3.1"
+  resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.3.1.tgz#c84e5b3d18d9a4d77558fef466b1bf16bbeb3450"
+  integrity sha512-4QYCEWOcK3OJrxwvyyAOxFuhpvOVCYkr33LPfFNBjAD/w3sEzWsp2BUOkI4l9bHvWioAd0rc6NlHUOEaWkTeqg==
+  dependencies:
+    anymatch "~3.1.1"
+    braces "~3.0.2"
+    glob-parent "~5.1.0"
+    is-binary-path "~2.1.0"
+    is-glob "~4.0.1"
+    normalize-path "~3.0.0"
+    readdirp "~3.3.0"
+  optionalDependencies:
+    fsevents "~2.1.2"
+
+chokidar@^2.0.0, chokidar@^2.0.2, chokidar@^2.0.3, chokidar@^2.0.4:
   version "2.0.4"
   resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.4.tgz#356ff4e2b0e8e43e322d18a372460bbcf3accd26"
   integrity sha512-z9n7yt9rOvIJrMhvDtDictKrkFHeihkNl6uWMmZlmL6tJtX9Cs+87oK+teBx+JIgzvbX3yZHT3eF8vpbDxHJXQ==
@@ -2499,7 +3084,7 @@ chokidar@2.0.4, chokidar@^2.0.0, chokidar@^2.0.2, chokidar@^2.0.3, chokidar@^2.0
   optionalDependencies:
     fsevents "^1.2.2"
 
-chokidar@^2.1.1:
+chokidar@^2.1.1, chokidar@^2.1.8:
   version "2.1.8"
   resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917"
   integrity sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==
@@ -2537,23 +3122,11 @@ chokidar@^2.1.6:
   optionalDependencies:
     fsevents "^1.2.7"
 
-chownr@^1.0.1:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181"
-  integrity sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE=
-
 chownr@^1.1.1, chownr@^1.1.2:
   version "1.1.3"
   resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.3.tgz#42d837d5239688d55f303003a508230fa6727142"
   integrity sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw==
 
-chrome-trace-event@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.0.tgz#45a91bd2c20c9411f0963b5aaeb9a1b95e09cc48"
-  integrity sha512-xDbVgyfDTT2piup/h8dK/y4QZfJRSa73bw1WZ8b4XM1o7fsFubUVGYcE+1ANtOzJJELGpYoG2961z0Z6OAld9A==
-  dependencies:
-    tslib "^1.9.0"
-
 chrome-trace-event@^1.0.2:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz#234090ee97c7d4ad1a2c4beae27505deffc608a4"
@@ -2574,10 +3147,10 @@ cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3:
     inherits "^2.0.1"
     safe-buffer "^5.0.1"
 
-circular-dependency-plugin@5.0.2:
-  version "5.0.2"
-  resolved "https://registry.yarnpkg.com/circular-dependency-plugin/-/circular-dependency-plugin-5.0.2.tgz#da168c0b37e7b43563fb9f912c1c007c213389ef"
-  integrity sha512-oC7/DVAyfcY3UWKm0sN/oVoDedQDQiw/vIiAnuTWTpE5s0zWf7l3WY417Xw/Fbi/QbAjctAkxgMiS9P0s3zkmA==
+circular-dependency-plugin@5.2.0:
+  version "5.2.0"
+  resolved "https://registry.yarnpkg.com/circular-dependency-plugin/-/circular-dependency-plugin-5.2.0.tgz#e09dbc2dd3e2928442403e2d45b41cea06bc0a93"
+  integrity sha512-7p4Kn/gffhQaavNfyDFg7LS5S/UT1JAjyGd4UqR2+jzoYF02eDkj0Ec3+48TsIa4zghjLY87nQHIh/ecK9qLdw==
 
 circular-json@^0.5.0:
   version "0.5.9"
@@ -2638,15 +3211,6 @@ cli-width@^2.0.0:
   resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639"
   integrity sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=
 
-cliui@^3.2.0:
-  version "3.2.0"
-  resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d"
-  integrity sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=
-  dependencies:
-    string-width "^1.0.1"
-    strip-ansi "^3.0.1"
-    wrap-ansi "^2.0.0"
-
 cliui@^4.0.0:
   version "4.1.0"
   resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49"
@@ -2665,16 +3229,6 @@ cliui@^5.0.0:
     strip-ansi "^5.2.0"
     wrap-ansi "^5.1.0"
 
-clone-deep@^2.0.1:
-  version "2.0.2"
-  resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-2.0.2.tgz#00db3a1e173656730d1188c3d6aced6d7ea97713"
-  integrity sha512-SZegPTKjCgpQH63E+eN6mVEEPdQBOUzjyJm5Pora4lrwWRFS8I0QAxV/KD6vV/i0WuijHZWQC1fMsPEdxfdVCQ==
-  dependencies:
-    for-own "^1.0.0"
-    is-plain-object "^2.0.4"
-    kind-of "^6.0.0"
-    shallow-clone "^1.0.0"
-
 clone-deep@^4.0.1:
   version "4.0.1"
   resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387"
@@ -2843,7 +3397,7 @@ commander@2.17.x, commander@~2.17.1:
   resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf"
   integrity sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==
 
-commander@^2.11.0, commander@^2.19.0, commander@^2.20.0, commander@~2.20.3:
+commander@^2.11.0, commander@^2.20.0, commander@~2.20.3:
   version "2.20.3"
   resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
   integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
@@ -2932,7 +3486,7 @@ compression@1.7.1:
     safe-buffer "5.1.1"
     vary "~1.1.2"
 
-compression@^1.5.2, compression@^1.7.4:
+compression@^1.7.4:
   version "1.7.4"
   resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f"
   integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==
@@ -2972,7 +3526,7 @@ configstore@^3.0.0:
     write-file-atomic "^2.0.0"
     xdg-basedir "^3.0.0"
 
-connect-history-api-fallback@^1.3.0, connect-history-api-fallback@^1.6.0:
+connect-history-api-fallback@^1.6.0:
   version "1.6.0"
   resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz#8b32089359308d111115d81cad3fceab888f97bc"
   integrity sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==
@@ -2994,11 +3548,6 @@ console-browserify@^1.1.0:
   dependencies:
     date-now "^0.1.4"
 
-console-control-strings@^1.0.0, console-control-strings@~1.1.0:
-  version "1.1.0"
-  resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
-  integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=
-
 constants-browserify@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75"
@@ -3026,6 +3575,13 @@ convert-source-map@^1.5.0, convert-source-map@^1.5.1:
   resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5"
   integrity sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU=
 
+convert-source-map@^1.7.0:
+  version "1.7.0"
+  resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442"
+  integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==
+  dependencies:
+    safe-buffer "~5.1.1"
+
 cookie-parser@1.4.3:
   version "1.4.3"
   resolved "https://registry.yarnpkg.com/cookie-parser/-/cookie-parser-1.4.3.tgz#0fe31fa19d000b95f4aadf1f53fdc2b8a203baa5"
@@ -3066,21 +3622,7 @@ copy-descriptor@^0.1.0:
   resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
   integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=
 
-copy-webpack-plugin@4.6.0:
-  version "4.6.0"
-  resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-4.6.0.tgz#e7f40dd8a68477d405dd1b7a854aae324b158bae"
-  integrity sha512-Y+SQCF+0NoWQryez2zXn5J5knmr9z/9qSQt7fbL78u83rxmigOy8X5+BFn8CFSuX+nKT8gpYwJX68ekqtQt6ZA==
-  dependencies:
-    cacache "^10.0.4"
-    find-cache-dir "^1.0.0"
-    globby "^7.1.1"
-    is-glob "^4.0.0"
-    loader-utils "^1.1.0"
-    minimatch "^3.0.4"
-    p-limit "^1.0.0"
-    serialize-javascript "^1.4.0"
-
-copy-webpack-plugin@^5.1.1:
+copy-webpack-plugin@5.1.1, copy-webpack-plugin@^5.1.1:
   version "5.1.1"
   resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-5.1.1.tgz#5481a03dea1123d88a988c6ff8b78247214f0b88"
   integrity sha512-P15M5ZC8dyCjQHWwd4Ia/dm0SgVvZJMYeykVIVYXbGyqO4dWB5oyPHp9i7wjwo5LhtlhKbiBCdS2NvM07Wlybg==
@@ -3110,21 +3652,29 @@ copyfiles@^2.1.1:
     through2 "^2.0.1"
     yargs "^13.2.4"
 
+core-js-compat@^3.6.2:
+  version "3.6.4"
+  resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.6.4.tgz#938476569ebb6cda80d339bcf199fae4f16fff17"
+  integrity sha512-zAa3IZPvsJ0slViBQ2z+vgyyTuhd3MFn1rBQjZSKVEgB0UMYhUkCj9jJUVPgGTGqWvsBVmfnruXgTcNyTlEiSA==
+  dependencies:
+    browserslist "^4.8.3"
+    semver "7.0.0"
+
 core-js-pure@^3.0.0:
   version "3.5.0"
   resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.5.0.tgz#f63c7f2b245e7d678e73f87ad28505480554d70e"
   integrity sha512-wB0QtKAofWigiISuT1Tej3hKgq932fB//Lf1VoPbiLpTYlHY0nIDhgF+q1na0DAKFHH5wGCirkAknOmDN8ijXA==
 
+core-js@3.6.4, core-js@^3.6.4:
+  version "3.6.4"
+  resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.6.4.tgz#440a83536b458114b9cb2ac1580ba377dc470647"
+  integrity sha512-4paDGScNgZP2IXXilaffL9X7968RuvwlkK3xWtZRVqgd8SYNiVKRJvkFd1aqqEuPfN7E68ZHEp9hDj6lHj4Hyw==
+
 core-js@^2.2.0, core-js@^2.4.0:
   version "2.5.7"
   resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.7.tgz#f972608ff0cead68b841a16a932d0b183791814e"
   integrity sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==
 
-core-js@^2.6.5:
-  version "2.6.11"
-  resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.11.tgz#38831469f9922bded8ee21c9dc46985e0399308c"
-  integrity sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==
-
 core-js@~2.3.0:
   version "2.3.0"
   resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.3.0.tgz#fab83fbb0b2d8dc85fa636c4b9d34c75420c6d65"
@@ -3150,6 +3700,17 @@ cosmiconfig@^5.0.0:
     js-yaml "^3.13.1"
     parse-json "^4.0.0"
 
+coverage-istanbul-loader@2.0.3:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/coverage-istanbul-loader/-/coverage-istanbul-loader-2.0.3.tgz#87d42f03fa0fd3fa8743ec76945d9d67f105722a"
+  integrity sha512-LiGRvyIuzVYs3M1ZYK1tF0HekjH0DJ8zFdUwAZq378EJzqOgToyb1690dp3TAUlP6Y+82uu42LRjuROVeJ54CA==
+  dependencies:
+    convert-source-map "^1.7.0"
+    istanbul-lib-instrument "^4.0.0"
+    loader-utils "^1.2.3"
+    merge-source-map "^1.1.0"
+    schema-utils "^2.6.1"
+
 coveralls@3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/coveralls/-/coveralls-3.0.0.tgz#22ef730330538080d29b8c151dc9146afde88a99"
@@ -3230,14 +3791,6 @@ cross-spawn@6.0.5, cross-spawn@^6.0.0, cross-spawn@^6.0.4, cross-spawn@^6.0.5:
     shebang-command "^1.2.0"
     which "^1.2.9"
 
-cross-spawn@^3.0.0:
-  version "3.0.1"
-  resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-3.0.1.tgz#1256037ecb9f0c5f79e3d6ef135e30770184b982"
-  integrity sha1-ElYDfsufDF9549bvE14wdwGEuYI=
-  dependencies:
-    lru-cache "^4.0.1"
-    which "^1.2.9"
-
 cross-spawn@^5.0.1:
   version "5.1.0"
   resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449"
@@ -3561,7 +4114,7 @@ debug@*, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1:
   dependencies:
     ms "^2.1.1"
 
-debug@2.6.9, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8:
+debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8:
   version "2.6.9"
   resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
   integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
@@ -3575,25 +4128,23 @@ debug@3.1.0, debug@^3.1.0, debug@~3.1.0:
   dependencies:
     ms "2.0.0"
 
-debug@^3.1.1, debug@^3.2.5, debug@^3.2.6:
+debug@^3.0.0, debug@^3.1.1, debug@^3.2.5, debug@^3.2.6:
   version "3.2.6"
   resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
   integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==
   dependencies:
     ms "^2.1.1"
 
-decamelize@^1.1.1, decamelize@^1.1.2, decamelize@^1.2.0:
+debuglog@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492"
+  integrity sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=
+
+decamelize@^1.1.2, decamelize@^1.2.0:
   version "1.2.0"
   resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
   integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=
 
-decamelize@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-2.0.0.tgz#656d7bbc8094c4c788ea53c5840908c9c7d063c7"
-  integrity sha512-Ikpp5scV3MSYxY39ymh45ZLEecsTdv/Xj2CaQfI8RLMuwi7XvjX9H/fhraiSuU+C5w5NTDu4ZU72xNiZnurBPg==
-  dependencies:
-    xregexp "4.0.0"
-
 decode-uri-component@^0.2.0:
   version "0.2.0"
   resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545"
@@ -3609,11 +4160,6 @@ deep-extend@^0.6.0:
   resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
   integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==
 
-deep-freeze-strict@^1.1.1:
-  version "1.1.1"
-  resolved "https://registry.yarnpkg.com/deep-freeze-strict/-/deep-freeze-strict-1.1.1.tgz#77d0583ca24a69be4bbd9ac2fae415d55523e5b0"
-  integrity sha1-d9BYPKJKab5LvZrC+uQV1VUj5bA=
-
 deep-freeze@0.0.1:
   version "0.0.1"
   resolved "https://registry.yarnpkg.com/deep-freeze/-/deep-freeze-0.0.1.tgz#3a0b0005de18672819dfd38cd31f91179c893e84"
@@ -3624,14 +4170,6 @@ deep-is@~0.1.3:
   resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
   integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=
 
-default-gateway@^2.6.0:
-  version "2.7.2"
-  resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-2.7.2.tgz#b7ef339e5e024b045467af403d50348db4642d0f"
-  integrity sha512-lAc4i9QJR0YHSDFdzeBQKfZ1SRDG3hsJNEkrpcZa8QhBfidLAilT60BDEIVUUGqosFp425KOgB3uYqcnQrWafQ==
-  dependencies:
-    execa "^0.10.0"
-    ip-regex "^2.1.0"
-
 default-gateway@^4.2.0:
   version "4.2.0"
   resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-4.2.0.tgz#167104c7500c2115f6dd69b0a536bb8ed720552b"
@@ -3682,18 +4220,6 @@ del@^2.2.0:
     pinkie-promise "^2.0.0"
     rimraf "^2.2.8"
 
-del@^3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/del/-/del-3.0.0.tgz#53ecf699ffcbcb39637691ab13baf160819766e5"
-  integrity sha1-U+z2mf/LyzljdpGrE7rxYIGXZuU=
-  dependencies:
-    globby "^6.1.0"
-    is-path-cwd "^1.0.0"
-    is-path-in-cwd "^1.0.0"
-    p-map "^1.1.1"
-    pify "^3.0.0"
-    rimraf "^2.2.8"
-
 del@^4.1.1:
   version "4.1.1"
   resolved "https://registry.yarnpkg.com/del/-/del-4.1.1.tgz#9e8f117222ea44a31ff3a156c049b99052a9f0b4"
@@ -3712,11 +4238,6 @@ delayed-stream@~1.0.0:
   resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
   integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk=
 
-delegates@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
-  integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=
-
 depd@1.1.1:
   version "1.1.1"
   resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.1.tgz#5783b4e1c459f06fa5ca27f991f3d06e7a310359"
@@ -3762,16 +4283,19 @@ detect-indent@^4.0.0:
   dependencies:
     repeating "^2.0.0"
 
-detect-libc@^1.0.2:
-  version "1.0.3"
-  resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
-  integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=
-
 detect-node@^2.0.4:
   version "2.0.4"
   resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c"
   integrity sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==
 
+dezalgo@^1.0.0:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.3.tgz#7f742de066fc748bc8db820569dddce49bf0d456"
+  integrity sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY=
+  dependencies:
+    asap "^2.0.0"
+    wrappy "1"
+
 di@^0.0.1:
   version "0.0.1"
   resolved "https://registry.yarnpkg.com/di/-/di-0.0.1.tgz#806649326ceaa7caa3306d75d985ea2748ba913c"
@@ -3873,7 +4397,7 @@ domhandler@2.1:
   dependencies:
     domelementtype "1"
 
-domino@^2.1.0:
+domino@^2.1.2:
   version "2.1.4"
   resolved "https://registry.yarnpkg.com/domino/-/domino-2.1.4.tgz#78922e7fab7c610f35792b6c745b7962d342e9c4"
   integrity sha512-l70mlQ7IjPKC8kT7GljQXJZmt5OqFL+RE91ik5y5WWQtsd9wP8R7gpFnNu96fK5MqAAZRXfLLsnzKtkty5fWGQ==
@@ -3973,10 +4497,10 @@ electron-to-chromium@^1.3.30, electron-to-chromium@^1.3.61:
   resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.62.tgz#2e8e2dc070c800ec8ce23ff9dfcceb585d6f9ed8"
   integrity sha512-x09ndL/Gjnuk3unlAyoGyUg3wbs4w/bXurgL7wL913vXHAOWmMhrLf1VNGRaMLngmadd5Q8gsV9BFuIr6rP+Xg==
 
-electron-to-chromium@^1.3.322:
-  version "1.3.322"
-  resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.322.tgz#a6f7e1c79025c2b05838e8e344f6e89eb83213a8"
-  integrity sha512-Tc8JQEfGQ1MzfSzI/bTlSr7btJv/FFO7Yh6tanqVmIWOuNCu6/D1MilIEgLtmWqIrsv+o4IjpLAhgMBr/ncNAA==
+electron-to-chromium@^1.3.341:
+  version "1.3.345"
+  resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.345.tgz#2569d0d54a64ef0f32a4b7e8c80afa5fe57c5d98"
+  integrity sha512-f8nx53+Z9Y+SPWGg3YdHrbYYfIJAtbUjpFfW4X1RwTZ94iUG7geg9tV8HqzAXX7XTNgyWgAFvce4yce8ZKxKmg==
 
 elliptic@^6.0.0:
   version "6.4.1"
@@ -4221,14 +4745,6 @@ escodegen@1.8.x:
   optionalDependencies:
     source-map "~0.2.0"
 
-eslint-scope@^4.0.0:
-  version "4.0.0"
-  resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.0.tgz#50bf3071e9338bcdc43331794a0cb533f0136172"
-  integrity sha512-1G6UTDi7Jc1ELFwnR58HV4fK9OQK4S6N985f166xqXxpjU6plxFISJa2Ba9KCQuFa8RCnj/lSFJbHo7UFDBnUA==
-  dependencies:
-    esrecurse "^4.1.0"
-    estraverse "^4.1.1"
-
 eslint-scope@^4.0.3:
   version "4.0.3"
   resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848"
@@ -4381,16 +4897,6 @@ eventemitter3@^3.0.0:
   resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.0.tgz#090b4d6cdbd645ed10bf750d4b5407942d7ba163"
   integrity sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA==
 
-eventemitter3@^4.0.0:
-  version "4.0.0"
-  resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.0.tgz#d65176163887ee59f386d64c82610b696a4a74eb"
-  integrity sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg==
-
-events@^1.0.0:
-  version "1.1.1"
-  resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924"
-  integrity sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=
-
 events@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/events/-/events-3.0.0.tgz#9a0a0dfaf62893d92b875b8f2698ca4114973e88"
@@ -4548,7 +5054,7 @@ express@4.16.2:
     utils-merge "1.0.1"
     vary "~1.1.2"
 
-express@^4.16.2, express@^4.16.3, express@^4.17.1:
+express@^4.16.3, express@^4.17.1:
   version "4.17.1"
   resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134"
   integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==
@@ -4627,15 +5133,6 @@ external-editor@^2.0.1:
     iconv-lite "^0.4.17"
     tmp "^0.0.33"
 
-external-editor@^3.0.0:
-  version "3.0.3"
-  resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.0.3.tgz#5866db29a97826dbe4bf3afd24070ead9ea43a27"
-  integrity sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA==
-  dependencies:
-    chardet "^0.7.0"
-    iconv-lite "^0.4.24"
-    tmp "^0.0.33"
-
 external-editor@^3.0.3:
   version "3.1.0"
   resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495"
@@ -4801,19 +5298,24 @@ file-entry-cache@^5.0.1:
   dependencies:
     flat-cache "^2.0.1"
 
-file-loader@3.0.1:
-  version "3.0.1"
-  resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-3.0.1.tgz#f8e0ba0b599918b51adfe45d66d1e771ad560faa"
-  integrity sha512-4sNIOXgtH/9WZq4NvlfU3Opn5ynUsqBwSLyM+I7UOwdGigTBYfVVQEwe/msZNX/j4pCJTIM14Fsw66Svo1oVrw==
+file-loader@4.2.0:
+  version "4.2.0"
+  resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-4.2.0.tgz#5fb124d2369d7075d70a9a5abecd12e60a95215e"
+  integrity sha512-+xZnaK5R8kBJrHK0/6HRlrKNamvVS5rjyuju+rnyxRGuwUJwpAMsVzUl5dz6rK8brkzjV6JpcFNjp6NqV0g1OQ==
   dependencies:
-    loader-utils "^1.0.2"
-    schema-utils "^1.0.0"
+    loader-utils "^1.2.3"
+    schema-utils "^2.0.0"
 
 file-saver@^1.3.8:
   version "1.3.8"
   resolved "https://registry.yarnpkg.com/file-saver/-/file-saver-1.3.8.tgz#e68a30c7cb044e2fb362b428469feb291c2e09d8"
   integrity sha512-spKHSBQIxxS81N/O21WmuXA2F6wppUCsutpzenOeZzOCCJ5gEfcbqJP983IrpLXzYmXnMUa6J03SubcNPdKrlg==
 
+file-uri-to-path@1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd"
+  integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==
+
 filename-regex@^2.0.0:
   version "2.0.1"
   resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26"
@@ -4845,6 +5347,13 @@ fill-range@^4.0.0:
     repeat-string "^1.6.1"
     to-regex-range "^2.1.0"
 
+fill-range@^7.0.1:
+  version "7.0.1"
+  resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
+  integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
+  dependencies:
+    to-regex-range "^5.0.1"
+
 finalhandler@1.1.0:
   version "1.1.0"
   resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.0.tgz#ce0b6855b45853e791b2fcc680046d88253dd7f5"
@@ -4871,16 +5380,16 @@ finalhandler@~1.1.2:
     statuses "~1.5.0"
     unpipe "~1.0.0"
 
-find-cache-dir@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-1.0.0.tgz#9288e3e9e3cc3748717d39eade17cf71fc30ee6f"
-  integrity sha1-kojj6ePMN0hxfTnq3hfPcfww7m8=
+find-cache-dir@3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.0.0.tgz#cd4b7dd97b7185b7e17dbfe2d6e4115ee3eeb8fc"
+  integrity sha512-t7ulV1fmbxh5G9l/492O1p5+EBbr3uwpt6odhFTMc+nWyhmbloe+ja9BZ8pIBtqFWhOmCWVjx+pTW4zDkFoclw==
   dependencies:
     commondir "^1.0.1"
-    make-dir "^1.0.0"
-    pkg-dir "^2.0.0"
+    make-dir "^3.0.0"
+    pkg-dir "^4.1.0"
 
-find-cache-dir@^2.0.0, find-cache-dir@^2.1.0:
+find-cache-dir@^2.1.0:
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7"
   integrity sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==
@@ -4906,13 +5415,6 @@ find-up@^1.0.0:
     path-exists "^2.0.0"
     pinkie-promise "^2.0.0"
 
-find-up@^2.0.0, find-up@^2.1.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7"
-  integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c=
-  dependencies:
-    locate-path "^2.0.0"
-
 find-up@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73"
@@ -4977,11 +5479,6 @@ font-awesome@4.7.0:
   resolved "https://registry.yarnpkg.com/font-awesome/-/font-awesome-4.7.0.tgz#8fa8cf0411a1a31afd07b06d2902bb9fc815a133"
   integrity sha1-j6jPBBGhoxr9B7BtKQK7n8gVoTM=
 
-for-in@^0.1.3:
-  version "0.1.8"
-  resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.8.tgz#d8773908e31256109952b1fdb9b3fa867d2775e1"
-  integrity sha1-2Hc5COMSVhCZUrH9ubP6hn0ndeE=
-
 for-in@^1.0.1, for-in@^1.0.2:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
@@ -4994,13 +5491,6 @@ for-own@^0.1.4:
   dependencies:
     for-in "^1.0.1"
 
-for-own@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/for-own/-/for-own-1.0.0.tgz#c63332f415cedc4b04dbfe70cf836494c53cb44b"
-  integrity sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=
-  dependencies:
-    for-in "^1.0.1"
-
 forever-agent@~0.6.1:
   version "0.6.1"
   resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
@@ -5147,31 +5637,18 @@ fs.realpath@^1.0.0:
   resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
   integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
 
-fsevents@^1.2.2:
-  version "1.2.4"
-  resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.4.tgz#f41dcb1af2582af3692da36fc55cbd8e1041c426"
-  integrity sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg==
-  dependencies:
-    nan "^2.9.2"
-    node-pre-gyp "^0.10.0"
-
-fsevents@^1.2.7:
-  version "1.2.9"
-  resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.9.tgz#3f5ed66583ccd6f400b5a00db6f7e861363e388f"
-  integrity sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==
+fsevents@^1.2.2, fsevents@^1.2.7:
+  version "1.2.11"
+  resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.11.tgz#67bf57f4758f02ede88fb2a1712fef4d15358be3"
+  integrity sha512-+ux3lx6peh0BpvY0JebGyZoiR4D+oYzdPZMKJwkZ+sFkNJzpL7tXc/wehS49gUAxg3tmMHPHZkA8JU2rhhgDHw==
   dependencies:
+    bindings "^1.5.0"
     nan "^2.12.1"
-    node-pre-gyp "^0.12.0"
 
-fstream@^1.0.0, fstream@^1.0.2:
-  version "1.0.12"
-  resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.12.tgz#4e8ba8ee2d48be4f7d0de505455548eae5932045"
-  integrity sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==
-  dependencies:
-    graceful-fs "^4.1.2"
-    inherits "~2.0.0"
-    mkdirp ">=0.5 0"
-    rimraf "2"
+fsevents@~2.1.2:
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.2.tgz#4c0a1fb34bc68e543b4b82a9ec392bfbda840805"
+  integrity sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA==
 
 function-bind@^1.0.2, function-bind@^1.1.1:
   version "1.1.1"
@@ -5183,32 +5660,16 @@ functional-red-black-tree@^1.0.1:
   resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327"
   integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=
 
-gauge@~2.7.3:
-  version "2.7.4"
-  resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7"
-  integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=
-  dependencies:
-    aproba "^1.0.3"
-    console-control-strings "^1.0.0"
-    has-unicode "^2.0.0"
-    object-assign "^4.1.0"
-    signal-exit "^3.0.0"
-    string-width "^1.0.1"
-    strip-ansi "^3.0.1"
-    wide-align "^1.1.0"
-
-gaze@^1.0.0:
-  version "1.1.3"
-  resolved "https://registry.yarnpkg.com/gaze/-/gaze-1.1.3.tgz#c441733e13b927ac8c0ff0b4c3b033f28812924a"
-  integrity sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==
-  dependencies:
-    globule "^1.0.0"
-
 genfun@^5.0.0:
   version "5.0.0"
   resolved "https://registry.yarnpkg.com/genfun/-/genfun-5.0.0.tgz#9dd9710a06900a5c4a5bf57aca5da4e52fe76537"
   integrity sha512-KGDOARWVga7+rnB3z9Sd2Letx515owfk0hSxHGuqjANb1M+x2bGZGqHLiozPsYMdM2OubeMni/Hpwmjq6qIUhA==
 
+gensync@^1.0.0-beta.1:
+  version "1.0.0-beta.1"
+  resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269"
+  integrity sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==
+
 get-caller-file@^1.0.1:
   version "1.0.3"
   resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a"
@@ -5276,7 +5737,7 @@ glob-parent@^3.1.0:
     is-glob "^3.1.0"
     path-dirname "^1.0.0"
 
-glob-parent@^5.0.0:
+glob-parent@^5.0.0, glob-parent@~5.1.0:
   version "5.1.0"
   resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.0.tgz#5f4c1d1e748d30cd73ad2944b3577a81b081e8c2"
   integrity sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==
@@ -5312,10 +5773,10 @@ glob@7.1.2:
     once "^1.3.0"
     path-is-absolute "^1.0.0"
 
-glob@7.1.3, glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.0.6, glob@^7.1.1, glob@^7.1.2, glob@~7.1.1:
-  version "7.1.3"
-  resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1"
-  integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==
+glob@7.1.4, glob@^7.1.3, glob@^7.1.4:
+  version "7.1.4"
+  resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255"
+  integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==
   dependencies:
     fs.realpath "^1.0.0"
     inflight "^1.0.4"
@@ -5335,10 +5796,10 @@ glob@^5.0.15:
     once "^1.3.0"
     path-is-absolute "^1.0.0"
 
-glob@^7.1.3, glob@^7.1.4:
-  version "7.1.4"
-  resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255"
-  integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==
+glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.0.6, glob@^7.1.1, glob@^7.1.2:
+  version "7.1.3"
+  resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1"
+  integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==
   dependencies:
     fs.realpath "^1.0.0"
     inflight "^1.0.4"
@@ -5402,6 +5863,11 @@ global-prefix@^3.0.0:
     kind-of "^6.0.2"
     which "^1.3.1"
 
+globals@^11.1.0:
+  version "11.12.0"
+  resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
+  integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
+
 globals@^12.1.0:
   version "12.3.0"
   resolved "https://registry.yarnpkg.com/globals/-/globals-12.3.0.tgz#1e564ee5c4dded2ab098b0f88f24702a3c56be13"
@@ -5462,15 +5928,6 @@ globby@^8.0.0:
     pify "^3.0.0"
     slash "^1.0.0"
 
-globule@^1.0.0:
-  version "1.2.1"
-  resolved "https://registry.yarnpkg.com/globule/-/globule-1.2.1.tgz#5dffb1b191f22d20797a9369b49eab4e9839696d"
-  integrity sha512-g7QtgWF4uYSL5/dn71WxubOrS7JVGCnFPEnoeChJmBnyR9Mw8nGoEwOgJL/RC2Te0WhbsEUCejfH8SZNJ+adYQ==
-  dependencies:
-    glob "~7.1.1"
-    lodash "~4.17.10"
-    minimatch "~3.0.2"
-
 glogg@^1.0.0:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/glogg/-/glogg-1.0.1.tgz#dcf758e44789cc3f3d32c1f3562a3676e6a34810"
@@ -5649,11 +6106,6 @@ has-symbols@^1.0.0:
   resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44"
   integrity sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=
 
-has-unicode@^2.0.0:
-  version "2.0.1"
-  resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
-  integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=
-
 has-value@^0.3.1:
   version "0.3.1"
   resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f"
@@ -5792,7 +6244,7 @@ html-comment-regex@^1.1.0:
   resolved "https://registry.yarnpkg.com/html-comment-regex/-/html-comment-regex-1.1.2.tgz#97d4688aeb5c81886a364faa0cad1dda14d433a7"
   integrity sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ==
 
-html-entities@^1.2.0, html-entities@^1.2.1:
+html-entities@^1.2.1:
   version "1.2.1"
   resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.1.tgz#0df29351f0721163515dfb9e5543e5f6eed5162f"
   integrity sha1-DfKTUfByEWNRXfueVUPl9u7VFi8=
@@ -5887,7 +6339,7 @@ http-proxy-agent@^2.1.0:
     agent-base "4"
     debug "3.1.0"
 
-http-proxy-middleware@^0.19.1:
+http-proxy-middleware@0.19.1, http-proxy-middleware@^0.19.1:
   version "0.19.1"
   resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz#183c7dc4aa1479150306498c210cdaf96080a43a"
   integrity sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q==
@@ -5897,16 +6349,6 @@ http-proxy-middleware@^0.19.1:
     lodash "^4.17.11"
     micromatch "^3.1.10"
 
-http-proxy-middleware@~0.18.0:
-  version "0.18.0"
-  resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-0.18.0.tgz#0987e6bb5a5606e5a69168d8f967a87f15dd8aab"
-  integrity sha512-Fs25KVMPAIIcgjMZkVHJoKg9VcXcC1C8yb9JUgeDvVXY0S/zgVIhMb+qVswDIgtJe2DfckMSY2d6TuTEutlk6Q==
-  dependencies:
-    http-proxy "^1.16.2"
-    is-glob "^4.0.0"
-    lodash "^4.17.5"
-    micromatch "^3.1.9"
-
 http-proxy@^1.13.0, http-proxy@^1.17.0, http-proxy@^1.8.1:
   version "1.17.0"
   resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.17.0.tgz#7ad38494658f84605e2f6db4436df410f4e5be9a"
@@ -5916,15 +6358,6 @@ http-proxy@^1.13.0, http-proxy@^1.17.0, http-proxy@^1.8.1:
     follow-redirects "^1.0.0"
     requires-port "^1.0.0"
 
-http-proxy@^1.16.2:
-  version "1.18.0"
-  resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.0.tgz#dbe55f63e75a347db7f3d99974f2692a314a6a3a"
-  integrity sha512-84I2iJM/n1d4Hdgc6y2+qY5mDaz2PUVjlg9znE9byl+q0uC3DeByqBGReQu5tpLK0TAqTIXScRUV+dg7+bUPpQ==
-  dependencies:
-    eventemitter3 "^4.0.0"
-    follow-redirects "^1.0.0"
-    requires-port "^1.0.0"
-
 http-server@0.11.1:
   version "0.11.1"
   resolved "https://registry.yarnpkg.com/http-server/-/http-server-0.11.1.tgz#2302a56a6ffef7f9abea0147d838a5e9b6b6a79b"
@@ -5961,6 +6394,14 @@ https-proxy-agent@^2.2.1:
     agent-base "^4.1.0"
     debug "^3.1.0"
 
+https-proxy-agent@^2.2.3:
+  version "2.2.4"
+  resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz#4ee7a737abd92678a293d9b34a1af4d0d08c787b"
+  integrity sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==
+  dependencies:
+    agent-base "^4.3.0"
+    debug "^3.1.0"
+
 https@1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/https/-/https-1.0.0.tgz#3c37c7ae1a8eeb966904a2ad1e975a194b7ed3a4"
@@ -5985,7 +6426,7 @@ iconv-lite@0.4.23:
   dependencies:
     safer-buffer ">= 2.1.2 < 3"
 
-iconv-lite@0.4.24, iconv-lite@^0.4.17, iconv-lite@^0.4.24, iconv-lite@^0.4.4, iconv-lite@~0.4.13:
+iconv-lite@0.4.24, iconv-lite@^0.4.17, iconv-lite@^0.4.24, iconv-lite@~0.4.13:
   version "0.4.24"
   resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
   integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
@@ -6097,11 +6538,6 @@ imurmurhash@^0.1.4:
   resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
   integrity sha1-khi5srkoojixPcT7a21XbyMUU+o=
 
-in-publish@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/in-publish/-/in-publish-2.0.0.tgz#e20ff5e3a2afc2690320b6dc552682a9c7fadf51"
-  integrity sha1-4g/146KvwmkDILbcVSaCqcf631E=
-
 indent-string@^2.1.0:
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80"
@@ -6137,7 +6573,7 @@ inflight@^1.0.4:
     once "^1.3.0"
     wrappy "1"
 
-inherits@2, inherits@2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3:
+inherits@2, inherits@2.0.3, inherits@~2.0.1, inherits@~2.0.3:
   version "2.0.3"
   resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
   integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
@@ -6176,23 +6612,23 @@ inquirer@3.0.6:
     strip-ansi "^3.0.0"
     through "^2.3.6"
 
-inquirer@6.2.1:
-  version "6.2.1"
-  resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.2.1.tgz#9943fc4882161bdb0b0c9276769c75b32dbfcd52"
-  integrity sha512-088kl3DRT2dLU5riVMKKr1DlImd6X7smDhpXUCkJDCKvTEJeRiXh0G132HG9u5a+6Ylw9plFRY7RuTnwohYSpg==
+inquirer@6.5.1:
+  version "6.5.1"
+  resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.5.1.tgz#8bfb7a5ac02dac6ff641ac4c5ff17da112fcdb42"
+  integrity sha512-uxNHBeQhRXIoHWTSNYUFhQVrHYFThIt6IVo2fFmSe8aBwdR3/w6b58hJpiL/fMukFkvGzjg+hSxFtwvVmKZmXw==
   dependencies:
-    ansi-escapes "^3.0.0"
-    chalk "^2.0.0"
-    cli-cursor "^2.1.0"
+    ansi-escapes "^4.2.1"
+    chalk "^2.4.2"
+    cli-cursor "^3.1.0"
     cli-width "^2.0.0"
-    external-editor "^3.0.0"
-    figures "^2.0.0"
-    lodash "^4.17.10"
-    mute-stream "0.0.7"
+    external-editor "^3.0.3"
+    figures "^3.0.0"
+    lodash "^4.17.15"
+    mute-stream "0.0.8"
     run-async "^2.2.0"
-    rxjs "^6.1.0"
-    string-width "^2.1.0"
-    strip-ansi "^5.0.0"
+    rxjs "^6.4.0"
+    string-width "^4.1.0"
+    strip-ansi "^5.1.0"
     through "^2.3.6"
 
 inquirer@^7.0.0:
@@ -6214,14 +6650,6 @@ inquirer@^7.0.0:
     strip-ansi "^5.1.0"
     through "^2.3.6"
 
-internal-ip@^3.0.1:
-  version "3.0.1"
-  resolved "https://registry.yarnpkg.com/internal-ip/-/internal-ip-3.0.1.tgz#df5c99876e1d2eb2ea2d74f520e3f669a00ece27"
-  integrity sha512-NXXgESC2nNVtU+pqmC9e6R8B1GpKxzsAQhffvh5AL79qKnodd+L7tnEQmTiUAVngqLalPbSqRA7XGIEL5nCd0Q==
-  dependencies:
-    default-gateway "^2.6.0"
-    ipaddr.js "^1.5.2"
-
 internal-ip@^4.3.0:
   version "4.3.0"
   resolved "https://registry.yarnpkg.com/internal-ip/-/internal-ip-4.3.0.tgz#845452baad9d2ca3b69c635a137acb9a0dad0907"
@@ -6240,18 +6668,13 @@ interpret@^1.0.0:
   resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.1.0.tgz#7ed1b1410c6a0e0f78cf95d3b8440c63f78b8614"
   integrity sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=
 
-invariant@^2.2.2:
+invariant@^2.2.2, invariant@^2.2.4:
   version "2.2.4"
   resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
   integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==
   dependencies:
     loose-envify "^1.0.0"
 
-invert-kv@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6"
-  integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY=
-
 invert-kv@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02"
@@ -6277,7 +6700,7 @@ ipaddr.js@1.9.0:
   resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.0.tgz#37df74e430a0e47550fe54a2defe30d8acd95f65"
   integrity sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA==
 
-ipaddr.js@^1.5.2, ipaddr.js@^1.9.0:
+ipaddr.js@^1.9.0:
   version "1.9.1"
   resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3"
   integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==
@@ -6287,6 +6710,11 @@ is-absolute-url@^2.0.0:
   resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-2.1.0.tgz#50530dfb84fcc9aa7dbe7852e83a37b93b9f2aa6"
   integrity sha1-UFMN+4T8yap9vnhS6Do3uTufKqY=
 
+is-absolute-url@^3.0.3:
+  version "3.0.3"
+  resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-3.0.3.tgz#96c6a22b6a23929b11ea0afb1836c36ad4a5d698"
+  integrity sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q==
+
 is-accessor-descriptor@^0.1.6:
   version "0.1.6"
   resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6"
@@ -6318,6 +6746,13 @@ is-binary-path@^1.0.0:
   dependencies:
     binary-extensions "^1.0.0"
 
+is-binary-path@~2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09"
+  integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==
+  dependencies:
+    binary-extensions "^2.0.0"
+
 is-buffer@^1.1.5, is-buffer@~1.1.1:
   version "1.1.6"
   resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
@@ -6475,7 +6910,7 @@ is-glob@^4.0.0:
   dependencies:
     is-extglob "^2.1.1"
 
-is-glob@^4.0.1:
+is-glob@^4.0.1, is-glob@~4.0.1:
   version "4.0.1"
   resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc"
   integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==
@@ -6519,6 +6954,11 @@ is-number@^4.0.0:
   resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff"
   integrity sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==
 
+is-number@^7.0.0:
+  version "7.0.0"
+  resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
+  integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
+
 is-obj@^1.0.0:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f"
@@ -6562,6 +7002,11 @@ is-path-inside@^2.1.0:
   dependencies:
     path-is-inside "^1.0.2"
 
+is-plain-obj@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e"
+  integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4=
+
 is-plain-object@^2.0.4:
   version "2.0.4"
   resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677"
@@ -6714,6 +7159,11 @@ istanbul-lib-coverage@^1.2.0:
   resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-1.2.0.tgz#f7d8f2e42b97e37fe796114cb0f9d68b5e3a4341"
   integrity sha512-GvgM/uXRwm+gLlvkWHTjDAvwynZkL9ns15calTrmhGgowlwJBbWMYzWbKqE2DT6JDP1AFXKa+Zi0EkqNCUqY0A==
 
+istanbul-lib-coverage@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz#f5944a37c70b550b02a78a5c3b2055b280cec8ec"
+  integrity sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==
+
 istanbul-lib-instrument@^1.7.3:
   version "1.10.1"
   resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-1.10.1.tgz#724b4b6caceba8692d3f1f9d0727e279c401af7b"
@@ -6727,6 +7177,19 @@ istanbul-lib-instrument@^1.7.3:
     istanbul-lib-coverage "^1.2.0"
     semver "^5.3.0"
 
+istanbul-lib-instrument@^4.0.0:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.1.tgz#61f13ac2c96cfefb076fe7131156cc05907874e6"
+  integrity sha512-imIchxnodll7pvQBYOqUu88EufLCU56LMeFPZZM/fJZ1irYcYdqroaV+ACK1Ila8ls09iEYArp+nqyC6lW1Vfg==
+  dependencies:
+    "@babel/core" "^7.7.5"
+    "@babel/parser" "^7.7.5"
+    "@babel/template" "^7.7.4"
+    "@babel/traverse" "^7.7.4"
+    "@istanbuljs/schema" "^0.1.2"
+    istanbul-lib-coverage "^3.0.0"
+    semver "^6.3.0"
+
 istanbul@0.4.5, istanbul@^0.4.0, istanbul@^0.4.3:
   version "0.4.5"
   resolved "https://registry.yarnpkg.com/istanbul/-/istanbul-0.4.5.tgz#65c7d73d4c4da84d4f3ac310b918fb0b8033733b"
@@ -6785,14 +7248,7 @@ jasminewd2@^2.1.0:
   resolved "https://registry.yarnpkg.com/jasminewd2/-/jasminewd2-2.2.0.tgz#e37cf0b17f199cce23bea71b2039395246b4ec4e"
   integrity sha1-43zwsX8ZnM4jvqcbIDk5Uka07E4=
 
-jest-worker@^23.2.0:
-  version "23.2.0"
-  resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-23.2.0.tgz#faf706a8da36fae60eb26957257fa7b5d8ea02b9"
-  integrity sha1-+vcGqNo2+uYOsmlXJX+ntdjqArk=
-  dependencies:
-    merge-stream "^1.0.1"
-
-jest-worker@^24.9.0:
+jest-worker@24.9.0, jest-worker@^24.9.0:
   version "24.9.0"
   resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-24.9.0.tgz#5dbfdb5b2d322e98567898238a9697bcce67b3e5"
   integrity sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw==
@@ -6800,10 +7256,12 @@ jest-worker@^24.9.0:
     merge-stream "^2.0.0"
     supports-color "^6.1.0"
 
-js-base64@^2.1.8:
-  version "2.4.9"
-  resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.4.9.tgz#748911fb04f48a60c4771b375cac45a80df11c03"
-  integrity sha512-xcinL3AuDJk7VSzsHgb9DvvIXayBbadtMZ4HFPx8rUszbW1MuNMlwYVC4zzCZ6e1sqZpnNS5ZFYOhXqA39T7LQ==
+jest-worker@^23.2.0:
+  version "23.2.0"
+  resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-23.2.0.tgz#faf706a8da36fae60eb26957257fa7b5d8ea02b9"
+  integrity sha1-+vcGqNo2+uYOsmlXJX+ntdjqArk=
+  dependencies:
+    merge-stream "^1.0.1"
 
 js-cookie@2.2.0:
   version "2.2.0"
@@ -6843,6 +7301,11 @@ jsesc@^1.3.0:
   resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b"
   integrity sha1-RsP+yMGJKxKwgz25vHYiF226s0s=
 
+jsesc@^2.5.1:
+  version "2.5.2"
+  resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4"
+  integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==
+
 jsesc@~0.5.0:
   version "0.5.0"
   resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d"
@@ -7029,10 +7492,10 @@ karma-remap-istanbul@0.6.0:
     istanbul "^0.4.3"
     remap-istanbul "^0.9.0"
 
-karma-source-map-support@1.3.0:
-  version "1.3.0"
-  resolved "https://registry.yarnpkg.com/karma-source-map-support/-/karma-source-map-support-1.3.0.tgz#36dd4d8ca154b62ace95696236fae37caf0a7dde"
-  integrity sha512-HcPqdAusNez/ywa+biN4EphGz62MmQyPggUsDfsHqa7tSe4jdsxgvTKuDfIazjL+IOxpVWyT7Pr4dhAV+sxX5Q==
+karma-source-map-support@1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/karma-source-map-support/-/karma-source-map-support-1.4.0.tgz#58526ceccf7e8730e56effd97a4de8d712ac0d6b"
+  integrity sha512-RsBECncGO17KAoJCYXjv+ckIz+Ii9NCi+9enk+rq6XC81ezYkb4/RHE6CTXdA7IOJqoF3wcaLfVG0CPmE5ca6A==
   dependencies:
     source-map-support "^0.5.5"
 
@@ -7100,7 +7563,7 @@ kew@^0.7.0:
   resolved "https://registry.yarnpkg.com/kew/-/kew-0.7.0.tgz#79d93d2d33363d6fdd2970b335d9141ad591d79b"
   integrity sha1-edk9LTM2PW/dKXCzNdkUGtWR15s=
 
-killable@^1.0.0, killable@^1.0.1:
+killable@^1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.1.tgz#4c8ce441187a061c7474fb87ca08e2a638194892"
   integrity sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg==
@@ -7163,13 +7626,6 @@ lazystream@^1.0.0:
   dependencies:
     readable-stream "^2.0.5"
 
-lcid@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835"
-  integrity sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=
-  dependencies:
-    invert-kv "^1.0.0"
-
 lcid@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf"
@@ -7182,14 +7638,14 @@ lcov-parse@^0.0.10:
   resolved "https://registry.yarnpkg.com/lcov-parse/-/lcov-parse-0.0.10.tgz#1b0b8ff9ac9c7889250582b70b71315d9da6d9a3"
   integrity sha1-GwuP+ayceIklBYK3C3ExXZ2m2aM=
 
-less-loader@4.1.0:
-  version "4.1.0"
-  resolved "https://registry.yarnpkg.com/less-loader/-/less-loader-4.1.0.tgz#2c1352c5b09a4f84101490274fd51674de41363e"
-  integrity sha512-KNTsgCE9tMOM70+ddxp9yyt9iHqgmSs0yTZc5XH5Wo+g80RWRIYNqE58QJKm/yMud5wZEvz50ugRDuzVIkyahg==
+less-loader@5.0.0:
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/less-loader/-/less-loader-5.0.0.tgz#498dde3a6c6c4f887458ee9ed3f086a12ad1b466"
+  integrity sha512-bquCU89mO/yWLaUq0Clk7qCsKhsF/TZpJUzETRvJa9KSVEL9SO3ovCvdEHISBhrC81OwC8QSVX7E0bzElZj9cg==
   dependencies:
     clone "^2.1.1"
     loader-utils "^1.1.0"
-    pify "^3.0.0"
+    pify "^4.0.1"
 
 less@3.9.0:
   version "3.9.0"
@@ -7207,6 +7663,18 @@ less@3.9.0:
     request "^2.83.0"
     source-map "~0.6.0"
 
+leven@^3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2"
+  integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==
+
+levenary@^1.1.0, levenary@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/levenary/-/levenary-1.1.1.tgz#842a9ee98d2075aa7faeedbe32679e9205f46f77"
+  integrity sha512-mkAdOIt79FD6irqjYSs4rdbnlT5vRonMEvBVPVb3XmevfS8kgRXwfes0dhPdEtzTWD/1eNE/Bm/G1iRt6DcnQQ==
+  dependencies:
+    leven "^3.1.0"
+
 levn@^0.3.0, levn@~0.3.0:
   version "0.3.0"
   resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee"
@@ -7215,10 +7683,10 @@ levn@^0.3.0, levn@~0.3.0:
     prelude-ls "~1.1.2"
     type-check "~0.3.2"
 
-license-webpack-plugin@2.1.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/license-webpack-plugin/-/license-webpack-plugin-2.1.0.tgz#83acaa6e89c3c5316effdd80cb4ec9c5cd8efc2f"
-  integrity sha512-vDiBeMWxjE9n6TabQ9J4FH8urFdsRK0Nvxn1cit9biCiR9aq1zBR0X2BlAkEiIG6qPamLeU0GzvIgLkrFc398A==
+license-webpack-plugin@2.1.2:
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/license-webpack-plugin/-/license-webpack-plugin-2.1.2.tgz#63f7c571537a450ec47dc98f5d5ffdbca7b3b14f"
+  integrity sha512-7poZHRla+ae0eEButlwMrPpkXyhNVBf2EHePYWT0jyLnI6311/OXJkTI2sOIRungRpQgU2oDMpro5bSFPT5F0A==
   dependencies:
     "@types/webpack-sources" "^0.1.5"
     webpack-sources "^1.2.0"
@@ -7241,16 +7709,6 @@ load-json-file@^1.0.0:
     pinkie-promise "^2.0.0"
     strip-bom "^2.0.0"
 
-load-json-file@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8"
-  integrity sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=
-  dependencies:
-    graceful-fs "^4.1.2"
-    parse-json "^2.2.0"
-    pify "^2.0.0"
-    strip-bom "^3.0.0"
-
 load-json-file@^4.0.0:
   version "4.0.0"
   resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b"
@@ -7261,11 +7719,6 @@ load-json-file@^4.0.0:
     pify "^3.0.0"
     strip-bom "^3.0.0"
 
-loader-runner@^2.3.0:
-  version "2.3.0"
-  resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.3.0.tgz#f482aea82d543e07921700d5a46ef26fdac6b8a2"
-  integrity sha1-9IKuqC1UPgeSFwDVpG7yb9rGuKI=
-
 loader-runner@^2.4.0:
   version "2.4.0"
   resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357"
@@ -7299,14 +7752,6 @@ loader-utils@^1.0.0:
     emojis-list "^2.0.0"
     json5 "^0.5.0"
 
-locate-path@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e"
-  integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=
-  dependencies:
-    p-locate "^2.0.0"
-    path-exists "^3.0.0"
-
 locate-path@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e"
@@ -7367,12 +7812,7 @@ lodash._root@^3.0.0:
   resolved "https://registry.yarnpkg.com/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692"
   integrity sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI=
 
-lodash.assign@^4.2.0:
-  version "4.2.0"
-  resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7"
-  integrity sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=
-
-lodash.clonedeep@^4.3.2, lodash.clonedeep@^4.5.0:
+lodash.clonedeep@^4.5.0:
   version "4.5.0"
   resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
   integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=
@@ -7448,11 +7888,6 @@ lodash.memoize@^4.1.2:
   resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
   integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=
 
-lodash.mergewith@^4.6.0:
-  version "4.6.2"
-  resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz#617121f89ac55f59047c7aec1ccd6654c6590f55"
-  integrity sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==
-
 lodash.restparam@^3.0.0:
   version "3.6.1"
   resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805"
@@ -7463,11 +7898,6 @@ lodash.startswith@^4.2.1:
   resolved "https://registry.yarnpkg.com/lodash.startswith/-/lodash.startswith-4.2.1.tgz#c598c4adce188a27e53145731cdc6c0e7177600c"
   integrity sha1-xZjErc4YiiflMUVzHNxsDnF3YAw=
 
-lodash.tail@^4.1.1:
-  version "4.1.1"
-  resolved "https://registry.yarnpkg.com/lodash.tail/-/lodash.tail-4.1.1.tgz#d2333a36d9e7717c8ad2f7cacafec7c32b444664"
-  integrity sha1-0jM6NtnncXyK0vfKyv7HwytERmQ=
-
 lodash.template@^3.0.0:
   version "3.6.2"
   resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-3.6.2.tgz#f8cdecc6169a255be9098ae8b0c53d378931d14f"
@@ -7521,7 +7951,7 @@ lodash.uniq@^4.5.0:
   resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
   integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
 
-lodash@^4.0.0, lodash@^4.0.1, lodash@^4.13.1, lodash@^4.17.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.3.0, lodash@^4.5.0, lodash@~4.17.10:
+lodash@^4.0.0, lodash@^4.0.1, lodash@^4.13.1, lodash@^4.17.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.3.0, lodash@^4.5.0:
   version "4.17.15"
   resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
   integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
@@ -7549,16 +7979,16 @@ log4js@^4.0.0:
     rfdc "^1.1.4"
     streamroller "^1.0.6"
 
-loglevel@^1.4.1:
-  version "1.6.6"
-  resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.6.tgz#0ee6300cc058db6b3551fa1c4bf73b83bb771312"
-  integrity sha512-Sgr5lbboAUBo3eXCSPL4/KoVz3ROKquOjcctxmHIt+vol2DrqTQe3SwkKKuYhEiWB5kYa13YyopJ69deJ1irzQ==
-
 loglevel@^1.6.3:
   version "1.6.3"
   resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.3.tgz#77f2eb64be55a404c9fd04ad16d57c1d6d6b1280"
   integrity sha512-LoEDv5pgpvWgPF4kNYuIp0qqSJVWak/dML0RY74xlzMZiT9w77teNAwKYKWBTYjlokMirg+o3jBwp+vlLrcfAA==
 
+loglevel@^1.6.4:
+  version "1.6.6"
+  resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.6.tgz#0ee6300cc058db6b3551fa1c4bf73b83bb771312"
+  integrity sha512-Sgr5lbboAUBo3eXCSPL4/KoVz3ROKquOjcctxmHIt+vol2DrqTQe3SwkKKuYhEiWB5kYa13YyopJ69deJ1irzQ==
+
 loglevelnext@^1.0.1:
   version "1.0.5"
   resolved "https://registry.yarnpkg.com/loglevelnext/-/loglevelnext-1.0.5.tgz#36fc4f5996d6640f539ff203ba819641680d75a2"
@@ -7600,7 +8030,7 @@ lru-cache@4.1.x:
     pseudomap "^1.0.2"
     yallist "^2.1.2"
 
-lru-cache@^4.0.1, lru-cache@^4.1.1:
+lru-cache@^4.0.1:
   version "4.1.3"
   resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.3.tgz#a1175cf3496dfc8436c156c334b4955992bce69c"
   integrity sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA==
@@ -7615,6 +8045,13 @@ lru-cache@^5.1.1:
   dependencies:
     yallist "^3.0.2"
 
+magic-string@0.25.3:
+  version "0.25.3"
+  resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.3.tgz#34b8d2a2c7fec9d9bdf9929a3fd81d271ef35be9"
+  integrity sha512-6QK0OpF/phMz0Q2AxILkX2mFhi7m+WMwTRg0LQKq/WBB0cDP4rYH3Wp4/d3OTXlrPLVJT/RFqj8tFeAR4nk8AA==
+  dependencies:
+    sourcemap-codec "^1.4.4"
+
 magic-string@^0.22.4:
   version "0.22.5"
   resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.22.5.tgz#8e9cf5afddf44385c1da5bc2a6a0dbd10b03657e"
@@ -7656,16 +8093,16 @@ make-error@^1.1.1:
   resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.4.tgz#19978ed575f9e9545d2ff8c13e33b5d18a67d535"
   integrity sha512-0Dab5btKVPhibSalc9QGXb559ED7G7iLjFXBaj9Wq8O3vorueR5K5jaE3hkG6ZQINyhA/JgG6Qk4qdFQjsYV6g==
 
-make-fetch-happen@^4.0.1, make-fetch-happen@^4.0.2:
-  version "4.0.2"
-  resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-4.0.2.tgz#2d156b11696fb32bffbafe1ac1bc085dd6c78a79"
-  integrity sha512-YMJrAjHSb/BordlsDEcVcPyTbiJKkzqMf48N8dAJZT9Zjctrkb6Yg4TY9Sq2AwSIQJFn5qBBKVTYt3vP5FMIHA==
+make-fetch-happen@^5.0.0:
+  version "5.0.2"
+  resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-5.0.2.tgz#aa8387104f2687edca01c8687ee45013d02d19bd"
+  integrity sha512-07JHC0r1ykIoruKO8ifMXu+xEU8qOXDFETylktdug6vJDACnP+HKevOu3PXyNPzFyTSlz8vrBYlBO1JZRe8Cag==
   dependencies:
     agentkeepalive "^3.4.1"
-    cacache "^11.3.3"
+    cacache "^12.0.0"
     http-cache-semantics "^3.8.1"
     http-proxy-agent "^2.1.0"
-    https-proxy-agent "^2.2.1"
+    https-proxy-agent "^2.2.3"
     lru-cache "^5.1.1"
     mississippi "^3.0.0"
     node-fetch-npm "^2.0.2"
@@ -7749,13 +8186,6 @@ media-typer@0.3.0:
   resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
   integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=
 
-mem@^1.1.0:
-  version "1.1.0"
-  resolved "https://registry.yarnpkg.com/mem/-/mem-1.1.0.tgz#5edd52b485ca1d900fe64895505399a0dfa45f76"
-  integrity sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=
-  dependencies:
-    mimic-fn "^1.0.0"
-
 mem@^4.0.0:
   version "4.3.0"
   resolved "https://registry.yarnpkg.com/mem/-/mem-4.3.0.tgz#461af497bc4ae09608cdb2e60eefb69bff744178"
@@ -7778,7 +8208,7 @@ memorystream@^0.3.1:
   resolved "https://registry.yarnpkg.com/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2"
   integrity sha1-htcJCzDORV1j+64S3aUaR93K+bI=
 
-meow@^3.3.0, meow@^3.7.0:
+meow@^3.3.0:
   version "3.7.0"
   resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb"
   integrity sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=
@@ -7799,6 +8229,13 @@ merge-descriptors@1.0.1:
   resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
   integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=
 
+merge-source-map@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/merge-source-map/-/merge-source-map-1.1.0.tgz#2fdde7e6020939f70906a68f2d7ae685e4c8c646"
+  integrity sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==
+  dependencies:
+    source-map "^0.6.1"
+
 merge-stream@^1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-1.0.1.tgz#4041202d508a342ba00174008df0c251b8c135e1"
@@ -7845,7 +8282,7 @@ micromatch@^2.3.11:
     parse-glob "^3.0.4"
     regex-cache "^0.4.2"
 
-micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4, micromatch@^3.1.8, micromatch@^3.1.9:
+micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4:
   version "3.1.10"
   resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23"
   integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==
@@ -7911,7 +8348,7 @@ mime@^2.1.0, mime@^2.3.1:
   resolved "https://registry.yarnpkg.com/mime/-/mime-2.3.1.tgz#b1621c54d63b97c47d3cfe7f7215f7d64517c369"
   integrity sha512-OEUllcVoydBHGN1z84yfQDimn58pZNNNXgZlHXSboxMlFvgI6MXSWpWKpFRra7H1HxpVhHTkrghfRW49k6yjeg==
 
-mime@^2.4.2:
+mime@^2.4.2, mime@^2.4.4:
   version "2.4.4"
   resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.4.tgz#bd7b91135fc6b01cde3e9bae33d659b63d8857e5"
   integrity sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==
@@ -7926,12 +8363,13 @@ mimic-fn@^2.0.0, mimic-fn@^2.1.0:
   resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
   integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
 
-mini-css-extract-plugin@0.5.0:
-  version "0.5.0"
-  resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.5.0.tgz#ac0059b02b9692515a637115b0cc9fed3a35c7b0"
-  integrity sha512-IuaLjruM0vMKhUUT51fQdQzBYTX49dLj8w68ALEAe2A4iYNpIC4eMac67mt3NzycvjOlf07/kYxJDc0RTl1Wqw==
+mini-css-extract-plugin@0.8.0:
+  version "0.8.0"
+  resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.8.0.tgz#81d41ec4fe58c713a96ad7c723cdb2d0bd4d70e1"
+  integrity sha512-MNpRGbNA52q6U92i0qbVpQNsgk7LExy41MdAlG84FeytfDOtRIf/mCHdEgG8rpTKOaNKiqUnZdlptF469hxqOw==
   dependencies:
     loader-utils "^1.1.0"
+    normalize-url "1.9.1"
     schema-utils "^1.0.0"
     webpack-sources "^1.1.0"
 
@@ -7945,7 +8383,7 @@ minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1:
   resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a"
   integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=
 
-"minimatch@2 || 3", minimatch@3.0.4, minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4, minimatch@~3.0.2:
+"minimatch@2 || 3", minimatch@3.0.4, minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4:
   version "3.0.4"
   resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
   integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
@@ -7993,7 +8431,7 @@ minipass-pipeline@^1.2.2:
   dependencies:
     minipass "^3.0.0"
 
-minipass@^2.2.1, minipass@^2.3.3:
+minipass@^2.2.1:
   version "2.3.4"
   resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.4.tgz#4768d7605ed6194d6d576169b9e12ef71e9d9957"
   integrity sha512-mlouk1OHlaUE8Odt1drMtG1bAJA4ZA6B/ehysgV0LUIrDHdKgo1KorZq3pK0b/7Z7LJIQ12MNM6aC+Tn6lUZ5w==
@@ -8016,35 +8454,12 @@ minipass@^3.0.0, minipass@^3.1.1:
   dependencies:
     yallist "^4.0.0"
 
-minizlib@^1.1.0:
-  version "1.1.0"
-  resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.1.0.tgz#11e13658ce46bc3a70a267aac58359d1e0c29ceb"
-  integrity sha512-4T6Ur/GctZ27nHfpt9THOdRZNgyJ9FZchYO1ceg5S8Q3DNLCKYy44nCZzgCJgcvx2UM8czmqak5BCxJMrq37lA==
-  dependencies:
-    minipass "^2.2.1"
-
 minizlib@^1.2.1:
   version "1.3.3"
   resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d"
   integrity sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==
   dependencies:
-    minipass "^2.9.0"
-
-mississippi@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-2.0.0.tgz#3442a508fafc28500486feea99409676e4ee5a6f"
-  integrity sha512-zHo8v+otD1J10j/tC+VNoGK9keCuByhKovAvdn74dmxJl9+mWHnx6EMsDN4lgRoMI/eYo2nchAxniIbUPb5onw==
-  dependencies:
-    concat-stream "^1.5.0"
-    duplexify "^3.4.2"
-    end-of-stream "^1.1.0"
-    flush-write-stream "^1.0.0"
-    from2 "^2.1.0"
-    parallel-transform "^1.1.0"
-    pump "^2.0.1"
-    pumpify "^1.3.3"
-    stream-each "^1.1.0"
-    through2 "^2.0.0"
+    minipass "^2.9.0"
 
 mississippi@^3.0.0:
   version "3.0.0"
@@ -8070,15 +8485,7 @@ mixin-deep@^1.2.0:
     for-in "^1.0.2"
     is-extendable "^1.0.1"
 
-mixin-object@^2.0.1:
-  version "2.0.1"
-  resolved "https://registry.yarnpkg.com/mixin-object/-/mixin-object-2.0.1.tgz#4fb949441dab182540f1fe035ba60e1947a5e57e"
-  integrity sha1-T7lJRB2rGCVA8f4DW6YOGUel5X4=
-  dependencies:
-    for-in "^0.1.3"
-    is-extendable "^0.1.1"
-
-mkdirp@0.5.1, mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1:
+mkdirp@0.5.1, mkdirp@0.5.x, mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.1:
   version "0.5.1"
   resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
   integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=
@@ -8182,12 +8589,7 @@ mute-stream@0.0.8:
   resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d"
   integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==
 
-nan@^2.10.0, nan@^2.9.2:
-  version "2.11.0"
-  resolved "https://registry.yarnpkg.com/nan/-/nan-2.11.0.tgz#574e360e4d954ab16966ec102c0c049fd961a099"
-  integrity sha512-F4miItu2rGnV2ySkXOQoA8FKz/SR2Q2sWP0sbTxNxz/tuokeC8WxOhPMcwi0qIyGtVn/rrSeLbvVkznqCdwYnw==
-
-nan@^2.12.1, nan@^2.13.2:
+nan@^2.12.1:
   version "2.14.0"
   resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c"
   integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==
@@ -8219,15 +8621,6 @@ ncp@^2.0.0:
   resolved "https://registry.yarnpkg.com/ncp/-/ncp-2.0.0.tgz#195a21d6c46e361d2fb1281ba38b91e9df7bdbb3"
   integrity sha1-GVoh1sRuNh0vsSgbo4uR6d9727M=
 
-needle@^2.2.1:
-  version "2.2.2"
-  resolved "https://registry.yarnpkg.com/needle/-/needle-2.2.2.tgz#1120ca4c41f2fcc6976fd28a8968afe239929418"
-  integrity sha512-mW7W8dKuVYefCpNzE3Z7xUmPI9wSrSL/1qH31YGMxmSOAnjatS3S9Zv3cmiHrhx3Jkp1SrWWBdOFXjfF48Uq3A==
-  dependencies:
-    debug "^2.1.2"
-    iconv-lite "^0.4.4"
-    sax "^1.2.4"
-
 negotiator@0.6.1:
   version "0.6.1"
   resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9"
@@ -8248,10 +8641,10 @@ next-tick@~1.0.0:
   resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c"
   integrity sha1-yobR/ogoFpsBICCOPchCS524NCw=
 
-ng-mocks@^7.6.0:
-  version "7.8.0"
-  resolved "https://registry.yarnpkg.com/ng-mocks/-/ng-mocks-7.8.0.tgz#05b9f46164ca8d22b72ee9ac2369f37b2434ceb2"
-  integrity sha512-QopwqQUeEoUmHZdJeEDG3koJ5woHYeVe3TEfRjVHwLyLfJ/wdcNcepdei6j9n9Ne42SpS2bOETgKBqUT5NUsng==
+ng-mocks@^8.1.0:
+  version "8.1.0"
+  resolved "https://registry.yarnpkg.com/ng-mocks/-/ng-mocks-8.1.0.tgz#d00a5e53ae53587f35c68147826590fab71a1658"
+  integrity sha512-/314nyU6UrONCUKfvFRuJPLpNBxqocwJmQBlPy4he5Vueu6gObXjy+KLUlbbENuA7zTeBjp//RA6w/Fa1yQ4Fw==
 
 ng2-file-upload@1.2.1:
   version "1.2.1"
@@ -8263,17 +8656,10 @@ ng2-nouislider@^1.8.2:
   resolved "https://registry.yarnpkg.com/ng2-nouislider/-/ng2-nouislider-1.8.2.tgz#4d4aab402d307020415da1714a5e9f46817fe97c"
   integrity sha512-apCpRxwX/3VapLuPozZkUfM3HAE1unuCm2UdRMDvAHbbY6CLobaZcsWUYQ6b02VzxccyV4G1z0xsq2un8J2Lqw==
 
-ngrx-store-freeze@^0.2.4:
-  version "0.2.4"
-  resolved "https://registry.yarnpkg.com/ngrx-store-freeze/-/ngrx-store-freeze-0.2.4.tgz#146687cdf7e21244eb9003c7e883f2125847076c"
-  integrity sha512-90awpbbMa/x2H81eWWYniyli3LJ1PZU/FaztL10d9Rp/4kw2+97pqyLjdxSPxcOv9St//m9kfuWZ7gyoVDjgcg==
-  dependencies:
-    deep-freeze-strict "^1.1.1"
-
-ngx-bootstrap@^3.2.0:
-  version "3.2.0"
-  resolved "https://registry.yarnpkg.com/ngx-bootstrap/-/ngx-bootstrap-3.2.0.tgz#ece7c48af0bc260462c3f77de14f22d4b3dde149"
-  integrity sha512-oLSLIWZgRiIfcuxyXLMZUOhX3wZtg6lpuMbdo/0UzMDg2bSOe1XPskcKZ/iuOa3FOlU9rjuYMzswHYYV5f/QCA==
+ngx-bootstrap@^5.3.2:
+  version "5.3.2"
+  resolved "https://registry.yarnpkg.com/ngx-bootstrap/-/ngx-bootstrap-5.3.2.tgz#0668b01202610657e998b3ca87669645e0b31dc9"
+  integrity sha512-gSMf8EXYl99Q3gqkq4RVhoTNSTYHz2Or6Cig2BJRbLJyqk15ZQE5qcq/ldHS8zzx/wgCA3HQeI63t2j2mEU9PA==
 
 ngx-infinite-scroll@6.0.1:
   version "6.0.1"
@@ -8294,6 +8680,13 @@ ngx-pagination@3.0.3:
   resolved "https://registry.yarnpkg.com/ngx-pagination/-/ngx-pagination-3.0.3.tgz#314145263613738d8c544da36cd8dacc5aa89a6f"
   integrity sha1-MUFFJjYTc42MVE2jbNjazFqomm8=
 
+ngx-sortablejs@^3.1.4:
+  version "3.1.4"
+  resolved "https://registry.yarnpkg.com/ngx-sortablejs/-/ngx-sortablejs-3.1.4.tgz#8c2e29f8f6c0ea6cdf8298ae1438b522d0ed70b9"
+  integrity sha512-jrEC4loWf01JxBcPiOHiyHbXwNrs4acIus1c9NVv7hiK574dywoqOnL5/OVQFnluqItWC7llqCUXfDr3Kmyqfg==
+  dependencies:
+    tslib "^1.9.0"
+
 nice-try@^1.0.4:
   version "1.0.5"
   resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
@@ -8333,53 +8726,6 @@ node-forge@0.9.0:
   resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.9.0.tgz#d624050edbb44874adca12bb9a52ec63cb782579"
   integrity sha512-7ASaDa3pD+lJ3WvXFsxekJQelBKRpne+GOVbLbtHYdd7pFspyeuJHnWfLplGf3SwKGbfs/aYl5V/JCIaHVUKKQ==
 
-node-gyp@^3.8.0:
-  version "3.8.0"
-  resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.8.0.tgz#540304261c330e80d0d5edce253a68cb3964218c"
-  integrity sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA==
-  dependencies:
-    fstream "^1.0.0"
-    glob "^7.0.3"
-    graceful-fs "^4.1.2"
-    mkdirp "^0.5.0"
-    nopt "2 || 3"
-    npmlog "0 || 1 || 2 || 3 || 4"
-    osenv "0"
-    request "^2.87.0"
-    rimraf "2"
-    semver "~5.3.0"
-    tar "^2.0.0"
-    which "1"
-
-node-libs-browser@^2.0.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.1.0.tgz#5f94263d404f6e44767d726901fff05478d600df"
-  integrity sha512-5AzFzdoIMb89hBGMZglEegffzgRg+ZFoUmisQ8HI4j1KDdpx13J0taNp2y9xPbur6W61gepGDDotGBVQ7mfUCg==
-  dependencies:
-    assert "^1.1.1"
-    browserify-zlib "^0.2.0"
-    buffer "^4.3.0"
-    console-browserify "^1.1.0"
-    constants-browserify "^1.0.0"
-    crypto-browserify "^3.11.0"
-    domain-browser "^1.1.1"
-    events "^1.0.0"
-    https-browserify "^1.0.0"
-    os-browserify "^0.3.0"
-    path-browserify "0.0.0"
-    process "^0.11.10"
-    punycode "^1.2.4"
-    querystring-es3 "^0.2.0"
-    readable-stream "^2.3.3"
-    stream-browserify "^2.0.1"
-    stream-http "^2.7.2"
-    string_decoder "^1.0.0"
-    timers-browserify "^2.0.4"
-    tty-browserify "0.0.0"
-    url "^0.11.0"
-    util "^0.10.3"
-    vm-browserify "0.0.4"
-
 node-libs-browser@^2.2.1:
   version "2.2.1"
   resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425"
@@ -8409,38 +8755,6 @@ node-libs-browser@^2.2.1:
     util "^0.11.0"
     vm-browserify "^1.0.1"
 
-node-pre-gyp@^0.10.0:
-  version "0.10.3"
-  resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz#3070040716afdc778747b61b6887bf78880b80fc"
-  integrity sha512-d1xFs+C/IPS8Id0qPTZ4bUT8wWryfR/OzzAFxweG+uLN85oPzyo2Iw6bVlLQ/JOdgNonXLCoRyqDzDWq4iw72A==
-  dependencies:
-    detect-libc "^1.0.2"
-    mkdirp "^0.5.1"
-    needle "^2.2.1"
-    nopt "^4.0.1"
-    npm-packlist "^1.1.6"
-    npmlog "^4.0.2"
-    rc "^1.2.7"
-    rimraf "^2.6.1"
-    semver "^5.3.0"
-    tar "^4"
-
-node-pre-gyp@^0.12.0:
-  version "0.12.0"
-  resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.12.0.tgz#39ba4bb1439da030295f899e3b520b7785766149"
-  integrity sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A==
-  dependencies:
-    detect-libc "^1.0.2"
-    mkdirp "^0.5.1"
-    needle "^2.2.1"
-    nopt "^4.0.1"
-    npm-packlist "^1.1.6"
-    npmlog "^4.0.2"
-    rc "^1.2.7"
-    rimraf "^2.6.1"
-    semver "^5.3.0"
-    tar "^4"
-
 node-releases@^1.0.0-alpha.11:
   version "1.0.0-alpha.11"
   resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.0.0-alpha.11.tgz#73c810acc2e5b741a17ddfbb39dfca9ab9359d8a"
@@ -8448,10 +8762,10 @@ node-releases@^1.0.0-alpha.11:
   dependencies:
     semver "^5.3.0"
 
-node-releases@^1.1.42:
-  version "1.1.42"
-  resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.42.tgz#a999f6a62f8746981f6da90627a8d2fc090bbad7"
-  integrity sha512-OQ/ESmUqGawI2PRX+XIRao44qWYBBfN54ImQYdWVTQqUckuejOg76ysSqDBK8NG3zwySRVnX36JwDQ6x+9GxzA==
+node-releases@^1.1.47:
+  version "1.1.47"
+  resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.47.tgz#c59ef739a1fd7ecbd9f0b7cf5b7871e8a8b591e4"
+  integrity sha512-k4xjVPx5FpwBUj0Gw7uvFOTF4Ep8Hok1I6qjwL3pLfwe7Y0REQSAqOwwv9TWBCUtMHxcXfY4PgRLRozcChvTcA==
   dependencies:
     semver "^6.3.0"
 
@@ -8462,54 +8776,6 @@ node-releases@^1.1.8:
   dependencies:
     semver "^5.3.0"
 
-node-sass@4.12.0:
-  version "4.12.0"
-  resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.12.0.tgz#0914f531932380114a30cc5fa4fa63233a25f017"
-  integrity sha512-A1Iv4oN+Iel6EPv77/HddXErL2a+gZ4uBeZUy+a8O35CFYTXhgA8MgLCWBtwpGZdCvTvQ9d+bQxX/QC36GDPpQ==
-  dependencies:
-    async-foreach "^0.1.3"
-    chalk "^1.1.1"
-    cross-spawn "^3.0.0"
-    gaze "^1.0.0"
-    get-stdin "^4.0.1"
-    glob "^7.0.3"
-    in-publish "^2.0.0"
-    lodash "^4.17.11"
-    meow "^3.7.0"
-    mkdirp "^0.5.1"
-    nan "^2.13.2"
-    node-gyp "^3.8.0"
-    npmlog "^4.0.0"
-    request "^2.88.0"
-    sass-graph "^2.2.4"
-    stdout-stream "^1.4.0"
-    "true-case-path" "^1.0.2"
-
-node-sass@^4.11.0:
-  version "4.11.0"
-  resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.11.0.tgz#183faec398e9cbe93ba43362e2768ca988a6369a"
-  integrity sha512-bHUdHTphgQJZaF1LASx0kAviPH7sGlcyNhWade4eVIpFp6tsn7SV8xNMTbsQFpEV9VXpnwTTnNYlfsZXgGgmkA==
-  dependencies:
-    async-foreach "^0.1.3"
-    chalk "^1.1.1"
-    cross-spawn "^3.0.0"
-    gaze "^1.0.0"
-    get-stdin "^4.0.1"
-    glob "^7.0.3"
-    in-publish "^2.0.0"
-    lodash.assign "^4.2.0"
-    lodash.clonedeep "^4.3.2"
-    lodash.mergewith "^4.6.0"
-    meow "^3.7.0"
-    mkdirp "^0.5.1"
-    nan "^2.10.0"
-    node-gyp "^3.8.0"
-    npmlog "^4.0.0"
-    request "^2.88.0"
-    sass-graph "^2.2.4"
-    stdout-stream "^1.4.0"
-    "true-case-path" "^1.0.2"
-
 nodemon@^1.15.0:
   version "1.18.4"
   resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-1.18.4.tgz#873f65fdb53220eb166180cf106b1354ac5d714d"
@@ -8534,21 +8800,13 @@ noms@0.0.0:
     inherits "^2.0.1"
     readable-stream "~1.0.31"
 
-"nopt@2 || 3", nopt@3.x:
+nopt@3.x:
   version "3.0.6"
   resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9"
   integrity sha1-xkZdvwirzU2zWTF/eaxopkayj/k=
   dependencies:
     abbrev "1"
 
-nopt@^4.0.1:
-  version "4.0.1"
-  resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d"
-  integrity sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=
-  dependencies:
-    abbrev "1"
-    osenv "^0.1.4"
-
 nopt@~1.0.10:
   version "1.0.10"
   resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee"
@@ -8556,23 +8814,23 @@ nopt@~1.0.10:
   dependencies:
     abbrev "1"
 
-normalize-package-data@^2.3.2, normalize-package-data@^2.3.4:
-  version "2.4.0"
-  resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f"
-  integrity sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==
+normalize-package-data@^2.0.0, normalize-package-data@^2.4.0:
+  version "2.5.0"
+  resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8"
+  integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==
   dependencies:
     hosted-git-info "^2.1.4"
-    is-builtin-module "^1.0.0"
+    resolve "^1.10.0"
     semver "2 || 3 || 4 || 5"
     validate-npm-package-license "^3.0.1"
 
-normalize-package-data@^2.4.0:
-  version "2.5.0"
-  resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8"
-  integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==
+normalize-package-data@^2.3.2, normalize-package-data@^2.3.4:
+  version "2.4.0"
+  resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f"
+  integrity sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==
   dependencies:
     hosted-git-info "^2.1.4"
-    resolve "^1.10.0"
+    is-builtin-module "^1.0.0"
     semver "2 || 3 || 4 || 5"
     validate-npm-package-license "^3.0.1"
 
@@ -8583,7 +8841,7 @@ normalize-path@^2.0.1, normalize-path@^2.1.1:
   dependencies:
     remove-trailing-separator "^1.0.1"
 
-normalize-path@^3.0.0:
+normalize-path@^3.0.0, normalize-path@~3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
   integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
@@ -8593,6 +8851,16 @@ normalize-range@^0.1.2:
   resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942"
   integrity sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=
 
+normalize-url@1.9.1:
+  version "1.9.1"
+  resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-1.9.1.tgz#2cc0d66b31ea23036458436e3620d85954c66c3c"
+  integrity sha1-LMDWazHqIwNkWENuNiDYWVTGbDw=
+  dependencies:
+    object-assign "^4.0.1"
+    prepend-http "^1.0.0"
+    query-string "^4.1.0"
+    sort-keys "^1.0.0"
+
 normalize-url@^3.0.0:
   version "3.3.0"
   resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-3.3.0.tgz#b2e1c4dc4f7c6d57743df733a4f5978d18650559"
@@ -8608,6 +8876,11 @@ npm-bundled@^1.0.1:
   resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.5.tgz#3c1732b7ba936b3a10325aef616467c0ccbcc979"
   integrity sha512-m/e6jgWu8/v5niCUKQi9qQl8QdeEduFA96xHDDzFGqly0OOjI7c+60KM/2sppfnUU9JJagf+zs+yGhqSOFj71g==
 
+npm-normalize-package-bin@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz#6e79a41f23fd235c0623218228da7d9c23b8f6e2"
+  integrity sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==
+
 npm-package-arg@6.1.0:
   version "6.1.0"
   resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-6.1.0.tgz#15ae1e2758a5027efb4c250554b85a737db7fcc1"
@@ -8636,13 +8909,14 @@ npm-packlist@^1.1.12:
     ignore-walk "^3.0.1"
     npm-bundled "^1.0.1"
 
-npm-packlist@^1.1.6:
-  version "1.1.11"
-  resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.1.11.tgz#84e8c683cbe7867d34b1d357d893ce29e28a02de"
-  integrity sha512-CxKlZ24urLkJk+9kCm48RTQ7L4hsmgSVzEk0TLGPzzyuFxD7VNgy5Sl24tOLMzQv773a/NeJ1ce1DKeacqffEA==
+npm-pick-manifest@3.0.2:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/npm-pick-manifest/-/npm-pick-manifest-3.0.2.tgz#f4d9e5fd4be2153e5f4e5f9b7be8dc419a99abb7"
+  integrity sha512-wNprTNg+X5nf+tDi+hbjdHhM4bX+mKqv6XmPh7B5eG+QY9VARfQPfCEH013H5GqfNj6ee8Ij2fg8yk0mzps1Vw==
   dependencies:
-    ignore-walk "^3.0.1"
-    npm-bundled "^1.0.1"
+    figgy-pudding "^3.5.1"
+    npm-package-arg "^6.0.0"
+    semver "^5.4.1"
 
 npm-pick-manifest@^2.2.3:
   version "2.2.3"
@@ -8653,17 +8927,18 @@ npm-pick-manifest@^2.2.3:
     npm-package-arg "^6.0.0"
     semver "^5.4.1"
 
-npm-registry-fetch@^3.8.0:
-  version "3.9.1"
-  resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-3.9.1.tgz#00ff6e4e35d3f75a172b332440b53e93f4cb67de"
-  integrity sha512-VQCEZlydXw4AwLROAXWUR7QDfe2Y8Id/vpAgp6TI1/H78a4SiQ1kQrKZALm5/zxM5n4HIi+aYb+idUAV/RuY0Q==
+npm-registry-fetch@^4.0.0:
+  version "4.0.2"
+  resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-4.0.2.tgz#2b1434f93ccbe6b6385f8e45f45db93e16921d7a"
+  integrity sha512-Z0IFtPEozNdeZRPh3aHHxdG+ZRpzcbQaJLthsm3VhNf6DScicTFRHZzK82u8RsJUsUHkX+QH/zcB/5pmd20H4A==
   dependencies:
     JSONStream "^1.3.4"
     bluebird "^3.5.1"
     figgy-pudding "^3.4.1"
     lru-cache "^5.1.1"
-    make-fetch-happen "^4.0.2"
+    make-fetch-happen "^5.0.0"
     npm-package-arg "^6.1.0"
+    safe-buffer "^5.2.0"
 
 npm-run-all@4.1.3:
   version "4.1.3"
@@ -8687,16 +8962,6 @@ npm-run-path@^2.0.0, npm-run-path@^2.0.2:
   dependencies:
     path-key "^2.0.0"
 
-"npmlog@0 || 1 || 2 || 3 || 4", npmlog@^4.0.0, npmlog@^4.0.2:
-  version "4.1.2"
-  resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b"
-  integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==
-  dependencies:
-    are-we-there-yet "~1.1.2"
-    console-control-strings "~1.1.0"
-    gauge "~2.7.3"
-    set-blocking "~2.0.0"
-
 nth-check@^1.0.2:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.2.tgz#b2bd295c37e3dd58a3bf0700376663ba4d9cf05c"
@@ -8858,10 +9123,10 @@ onetime@^5.1.0:
   dependencies:
     mimic-fn "^2.1.0"
 
-open@6.0.0:
-  version "6.0.0"
-  resolved "https://registry.yarnpkg.com/open/-/open-6.0.0.tgz#cae5e2c1a3a1bfaee0d0acc8c4b7609374750346"
-  integrity sha512-/yb5mVZBz7mHLySMiSj2DcLtMBbFPJk5JBKEkHVZFxZAPzeg3L026O0T+lbdz1B2nyDnkClRSwRQJdeVUIF7zw==
+open@6.4.0:
+  version "6.4.0"
+  resolved "https://registry.yarnpkg.com/open/-/open-6.4.0.tgz#5c13e96d0dc894686164f18965ecfe889ecfc8a9"
+  integrity sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg==
   dependencies:
     is-wsl "^1.1.0"
 
@@ -8895,7 +9160,7 @@ opn@4.0.2:
     object-assign "^4.0.1"
     pinkie-promise "^2.0.0"
 
-opn@^5.1.0, opn@^5.5.0:
+opn@^5.5.0:
   version "5.5.0"
   resolved "https://registry.yarnpkg.com/opn/-/opn-5.5.0.tgz#fc7164fab56d235904c51c3b27da6758ca3b9bfc"
   integrity sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==
@@ -8959,22 +9224,6 @@ os-homedir@^1.0.0:
   resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
   integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M=
 
-os-locale@^1.4.0:
-  version "1.4.0"
-  resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9"
-  integrity sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=
-  dependencies:
-    lcid "^1.0.0"
-
-os-locale@^2.0.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-2.1.0.tgz#42bc2900a6b5b8bd17376c8e882b65afccf24bf2"
-  integrity sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==
-  dependencies:
-    execa "^0.7.0"
-    lcid "^1.0.0"
-    mem "^1.1.0"
-
 os-locale@^3.0.0, os-locale@^3.1.0:
   version "3.1.0"
   resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a"
@@ -8989,7 +9238,7 @@ os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.1, os-tmpdir@~1.0.2:
   resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
   integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=
 
-osenv@0, osenv@^0.1.4, osenv@^0.1.5:
+osenv@^0.1.5:
   version "0.1.5"
   resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410"
   integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==
@@ -9012,13 +9261,6 @@ p-is-promise@^2.0.0:
   resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.1.0.tgz#918cebaea248a62cf7ffab8e3bca8c5f882fc42e"
   integrity sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==
 
-p-limit@^1.0.0, p-limit@^1.1.0:
-  version "1.3.0"
-  resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8"
-  integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==
-  dependencies:
-    p-try "^1.0.0"
-
 p-limit@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.0.0.tgz#e624ed54ee8c460a778b3c9f3670496ff8a57aec"
@@ -9033,13 +9275,6 @@ p-limit@^2.2.0, p-limit@^2.2.1:
   dependencies:
     p-try "^2.0.0"
 
-p-locate@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43"
-  integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=
-  dependencies:
-    p-limit "^1.1.0"
-
 p-locate@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4"
@@ -9054,11 +9289,6 @@ p-locate@^4.1.0:
   dependencies:
     p-limit "^2.2.0"
 
-p-map@^1.1.1:
-  version "1.2.0"
-  resolved "https://registry.yarnpkg.com/p-map/-/p-map-1.2.0.tgz#e4e94f311eabbc8633a1e79908165fca26241b6b"
-  integrity sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==
-
 p-map@^2.0.0:
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175"
@@ -9078,11 +9308,6 @@ p-retry@^3.0.1:
   dependencies:
     retry "^0.12.0"
 
-p-try@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3"
-  integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=
-
 p-try@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.0.0.tgz#85080bb87c64688fa47996fe8f7dfbe8211760b1"
@@ -9098,18 +9323,19 @@ package-json@^4.0.0:
     registry-url "^3.0.3"
     semver "^5.1.0"
 
-pacote@9.4.0:
-  version "9.4.0"
-  resolved "https://registry.yarnpkg.com/pacote/-/pacote-9.4.0.tgz#af979abdeb175cd347c3e33be3241af1ed254807"
-  integrity sha512-WQ1KL/phGMkedYEQx9ODsjj7xvwLSpdFJJdEXrLyw5SILMxcTNt5DTxT2Z93fXuLFYJBlZJdnwdalrQdB/rX5w==
+pacote@9.5.5:
+  version "9.5.5"
+  resolved "https://registry.yarnpkg.com/pacote/-/pacote-9.5.5.tgz#63355a393614c3424e735820c3731e2cbbedaeeb"
+  integrity sha512-jAEP+Nqj4kyMWyNpfTU/Whx1jA7jEc5cCOlurm0/0oL+v8TAp1QSsK83N7bYe+2bEdFzMAtPG5TBebjzzGV0cA==
   dependencies:
     bluebird "^3.5.3"
-    cacache "^11.3.2"
+    cacache "^12.0.2"
     figgy-pudding "^3.5.1"
     get-stream "^4.1.0"
     glob "^7.1.3"
+    infer-owner "^1.0.4"
     lru-cache "^5.1.1"
-    make-fetch-happen "^4.0.1"
+    make-fetch-happen "^5.0.0"
     minimatch "^3.0.4"
     minipass "^2.3.5"
     mississippi "^3.0.0"
@@ -9118,7 +9344,7 @@ pacote@9.4.0:
     npm-package-arg "^6.1.0"
     npm-packlist "^1.1.12"
     npm-pick-manifest "^2.2.3"
-    npm-registry-fetch "^3.8.0"
+    npm-registry-fetch "^4.0.0"
     osenv "^0.1.5"
     promise-inflight "^1.0.1"
     promise-retry "^1.1.1"
@@ -9244,11 +9470,6 @@ pascalcase@^0.1.1:
   resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14"
   integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=
 
-path-browserify@0.0.0:
-  version "0.0.0"
-  resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a"
-  integrity sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo=
-
 path-browserify@0.0.1:
   version "0.0.1"
   resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.1.tgz#e6c4ddd7ed3aa27c68a20cc4e50e1a4ee83bbc4a"
@@ -9310,13 +9531,6 @@ path-type@^1.0.0:
     pify "^2.0.0"
     pinkie-promise "^2.0.0"
 
-path-type@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73"
-  integrity sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=
-  dependencies:
-    pify "^2.0.0"
-
 path-type@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f"
@@ -9377,6 +9591,11 @@ phantomjs-prebuilt@^2.1.7:
     request-progress "^2.0.1"
     which "^1.2.10"
 
+picomatch@^2.0.4, picomatch@^2.0.7:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.1.tgz#21bac888b6ed8601f831ce7816e335bc779f0a4a"
+  integrity sha512-ISBaA8xQNmwELC7eOjqFKMESB2VIqt4PPDD0nsS95b/9dZXvVKOlz9keMSnoGGKcOHXfTvDD6WMaRoSc9UuhRA==
+
 pify@^2.0.0, pify@^2.3.0:
   version "2.3.0"
   resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
@@ -9413,13 +9632,6 @@ pixrem@^4.0.0:
     postcss "^6.0.0"
     reduce-css-calc "^1.2.7"
 
-pkg-dir@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b"
-  integrity sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=
-  dependencies:
-    find-up "^2.1.0"
-
 pkg-dir@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3"
@@ -9481,7 +9693,7 @@ portfinder@^1.0.20:
     debug "^2.2.0"
     mkdirp "0.5.x"
 
-portfinder@^1.0.9:
+portfinder@^1.0.25:
   version "1.0.25"
   resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.25.tgz#254fd337ffba869f4b9d37edc298059cb4d35eca"
   integrity sha512-6ElJnHBbxVA1XSLgBp7G1FiCkQdlqGzuF7DswL5tcea+E8UpuvPU7beVAjjRwCioTS9ZluNbu+ZyRvgTsmqEBg==
@@ -10192,10 +10404,10 @@ postcss-values-parser@^1.5.0:
     indexes-of "^1.0.1"
     uniq "^1.0.1"
 
-postcss@7.0.14, postcss@^7.0.1, postcss@^7.0.5:
-  version "7.0.14"
-  resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.14.tgz#4527ed6b1ca0d82c53ce5ec1a2041c2346bbd6e5"
-  integrity sha512-NsbD6XUUMZvBxtQAJuWDJeeC4QFsmWsfozWxCJPWf3M55K9iu2iMDaKqyoOdTJ1R4usBXuxlVFAIo8rZPQD4Bg==
+postcss@7.0.17:
+  version "7.0.17"
+  resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.17.tgz#4da1bdff5322d4a0acaab4d87f3e782436bad31f"
+  integrity sha512-546ZowA+KZ3OasvQZHsbuEpysvwTZNGJv9EfyCQdsIDltPSWHAeTQ5fQy/Npi2ZDtLI3zs7Ps/p6wThErhm9fQ==
   dependencies:
     chalk "^2.4.2"
     source-map "^0.6.1"
@@ -10210,7 +10422,7 @@ postcss@^6.0, postcss@^6.0.0, postcss@^6.0.1, postcss@^6.0.11, postcss@^6.0.14,
     source-map "^0.6.1"
     supports-color "^5.4.0"
 
-postcss@^7.0.0, postcss@^7.0.13, postcss@^7.0.14, postcss@^7.0.16, postcss@^7.0.23, postcss@^7.0.6:
+postcss@^7.0.0, postcss@^7.0.14, postcss@^7.0.16, postcss@^7.0.23, postcss@^7.0.6:
   version "7.0.25"
   resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.25.tgz#dd2a2a753d50b13bed7a2009b4a18ac14d9db21e"
   integrity sha512-NXXVvWq9icrm/TgQC0O6YVFi4StfJz46M1iNd/h6B26Nvh/HKI+q4YZtFN/EjcInZliEscO/WL10BXnc1E5nwg==
@@ -10219,6 +10431,24 @@ postcss@^7.0.0, postcss@^7.0.13, postcss@^7.0.14, postcss@^7.0.16, postcss@^7.0.
     source-map "^0.6.1"
     supports-color "^6.1.0"
 
+postcss@^7.0.1, postcss@^7.0.5:
+  version "7.0.14"
+  resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.14.tgz#4527ed6b1ca0d82c53ce5ec1a2041c2346bbd6e5"
+  integrity sha512-NsbD6XUUMZvBxtQAJuWDJeeC4QFsmWsfozWxCJPWf3M55K9iu2iMDaKqyoOdTJ1R4usBXuxlVFAIo8rZPQD4Bg==
+  dependencies:
+    chalk "^2.4.2"
+    source-map "^0.6.1"
+    supports-color "^6.1.0"
+
+postcss@^7.0.17:
+  version "7.0.26"
+  resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.26.tgz#5ed615cfcab35ba9bbb82414a4fa88ea10429587"
+  integrity sha512-IY4oRjpXWYshuTDFxMVkJDtWIk2LhsTlu8bZnbEJA4+bYT16Lvpo8Qv6EvDumhYRgzjZl489pmsY3qVgJQ08nA==
+  dependencies:
+    chalk "^2.4.2"
+    source-map "^0.6.1"
+    supports-color "^6.1.0"
+
 postcss@^7.0.2:
   version "7.0.2"
   resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.2.tgz#7b5a109de356804e27f95a960bef0e4d5bc9bb18"
@@ -10233,7 +10463,7 @@ prelude-ls@~1.1.2:
   resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
   integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=
 
-prepend-http@^1.0.1:
+prepend-http@^1.0.0, prepend-http@^1.0.1:
   version "1.0.4"
   resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc"
   integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=
@@ -10256,6 +10486,11 @@ pretty-hrtime@^1.0.3:
   resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1"
   integrity sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=
 
+private@^0.1.6:
+  version "0.1.8"
+  resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff"
+  integrity sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==
+
 process-es6@^0.11.6:
   version "0.11.6"
   resolved "https://registry.yarnpkg.com/process-es6/-/process-es6-0.11.6.tgz#c6bb389f9a951f82bd4eb169600105bd2ff9c778"
@@ -10407,7 +10642,7 @@ public-encrypt@^4.0.0:
     parse-asn1 "^5.0.0"
     randombytes "^2.0.1"
 
-pump@^2.0.0, pump@^2.0.1:
+pump@^2.0.0:
   version "2.0.1"
   resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909"
   integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==
@@ -10482,6 +10717,14 @@ qs@~2.3.3:
   resolved "https://registry.yarnpkg.com/qs/-/qs-2.3.3.tgz#e9e85adbe75da0bbe4c8e0476a086290f863b404"
   integrity sha1-6eha2+ddoLvkyOBHaghikPhjtAQ=
 
+query-string@^4.1.0:
+  version "4.3.4"
+  resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.3.4.tgz#bbb693b9ca915c232515b228b1a02b609043dbeb"
+  integrity sha1-u7aTucqRXCMlFbIosaArYJBD2+s=
+  dependencies:
+    object-assign "^4.1.0"
+    strict-uri-encode "^1.0.0"
+
 querystring-es3@^0.2.0:
   version "0.2.1"
   resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73"
@@ -10576,15 +10819,15 @@ raw-loader@0.5.1:
   resolved "https://registry.yarnpkg.com/raw-loader/-/raw-loader-0.5.1.tgz#0c3d0beaed8a01c966d9787bf778281252a979aa"
   integrity sha1-DD0L6u2KAclm2Xh793goElKpeao=
 
-raw-loader@1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/raw-loader/-/raw-loader-1.0.0.tgz#3f9889e73dadbda9a424bce79809b4133ad46405"
-  integrity sha512-Uqy5AqELpytJTRxYT4fhltcKPj0TyaEpzJDcGz7DFJi+pQOOi3GjR/DOdxTkTsF+NzhnldIoG6TORaBlInUuqA==
+raw-loader@3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/raw-loader/-/raw-loader-3.1.0.tgz#5e9d399a5a222cc0de18f42c3bc5e49677532b3f"
+  integrity sha512-lzUVMuJ06HF4rYveaz9Tv0WRlUMxJ0Y1hgSkkgg+50iEdaI0TthyEDe08KIHb0XsF6rn8WYTqPCaGTZg3sX+qA==
   dependencies:
     loader-utils "^1.1.0"
-    schema-utils "^1.0.0"
+    schema-utils "^2.0.1"
 
-rc@^1.0.1, rc@^1.1.6, rc@^1.2.7:
+rc@^1.0.1, rc@^1.1.6:
   version "1.2.8"
   resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"
   integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==
@@ -10601,6 +10844,27 @@ read-cache@^1.0.0:
   dependencies:
     pify "^2.3.0"
 
+read-package-json@^2.0.0:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/read-package-json/-/read-package-json-2.1.1.tgz#16aa66c59e7d4dad6288f179dd9295fd59bb98f1"
+  integrity sha512-dAiqGtVc/q5doFz6096CcnXhpYk0ZN8dEKVkGLU0CsASt8SrgF6SF7OTKAYubfvFhWaqofl+Y8HK19GR8jwW+A==
+  dependencies:
+    glob "^7.1.1"
+    json-parse-better-errors "^1.0.1"
+    normalize-package-data "^2.0.0"
+    npm-normalize-package-bin "^1.0.0"
+  optionalDependencies:
+    graceful-fs "^4.1.2"
+
+read-package-tree@5.3.1:
+  version "5.3.1"
+  resolved "https://registry.yarnpkg.com/read-package-tree/-/read-package-tree-5.3.1.tgz#a32cb64c7f31eb8a6f31ef06f9cedf74068fe636"
+  integrity sha512-mLUDsD5JVtlZxjSlPPx1RETkNjjvQYuweKwNVt1Sn8kP5Jh44pvYuUHCp6xSVDZWbNxVxG5lyZJ921aJH61sTw==
+  dependencies:
+    read-package-json "^2.0.0"
+    readdir-scoped-modules "^1.0.0"
+    util-promisify "^2.1.0"
+
 read-pkg-up@^1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02"
@@ -10609,14 +10873,6 @@ read-pkg-up@^1.0.1:
     find-up "^1.0.0"
     read-pkg "^1.0.0"
 
-read-pkg-up@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be"
-  integrity sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=
-  dependencies:
-    find-up "^2.0.0"
-    read-pkg "^2.0.0"
-
 read-pkg@^1.0.0:
   version "1.1.0"
   resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28"
@@ -10626,15 +10882,6 @@ read-pkg@^1.0.0:
     normalize-package-data "^2.3.2"
     path-type "^1.0.0"
 
-read-pkg@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8"
-  integrity sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=
-  dependencies:
-    load-json-file "^2.0.0"
-    normalize-package-data "^2.3.2"
-    path-type "^2.0.0"
-
 read-pkg@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389"
@@ -10644,7 +10891,7 @@ read-pkg@^3.0.0:
     normalize-package-data "^2.3.2"
     path-type "^3.0.0"
 
-"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6:
+"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.5, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6:
   version "2.3.6"
   resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf"
   integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==
@@ -10698,6 +10945,16 @@ readable-stream@~2.0.0, readable-stream@~2.0.6:
     string_decoder "~0.10.x"
     util-deprecate "~1.0.1"
 
+readdir-scoped-modules@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz#8d45407b4f870a0dcaebc0e28670d18e74514309"
+  integrity sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw==
+  dependencies:
+    debuglog "^1.0.1"
+    dezalgo "^1.0.0"
+    graceful-fs "^4.1.2"
+    once "^1.3.0"
+
 readdirp@^2.0.0:
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78"
@@ -10717,6 +10974,13 @@ readdirp@^2.2.1:
     micromatch "^3.1.10"
     readable-stream "^2.0.2"
 
+readdirp@~3.3.0:
+  version "3.3.0"
+  resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.3.0.tgz#984458d13a1e42e2e9f5841b129e162f369aff17"
+  integrity sha512-zz0pAkSPOXXm1viEwygWIPSPkcBYjW1xU5j/JBh5t9bGCJwa6f9+BJa6VaB2g+b55yVrmXzqkyLf4xaWYM0IkQ==
+  dependencies:
+    picomatch "^2.0.7"
+
 rechoir@^0.6.2:
   version "0.6.2"
   resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384"
@@ -10756,16 +11020,33 @@ reduce-function-call@^1.0.1, reduce-function-call@^1.0.2:
   dependencies:
     balanced-match "^0.4.2"
 
-reflect-metadata@0.1.12, reflect-metadata@^0.1.2:
+reflect-metadata@^0.1.13:
+  version "0.1.13"
+  resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08"
+  integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==
+
+reflect-metadata@^0.1.2:
   version "0.1.12"
   resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.12.tgz#311bf0c6b63cd782f228a81abe146a2bfa9c56f2"
   integrity sha512-n+IyV+nGz3+0q3/Yf1ra12KpCyi001bi4XFxSjbiWWjfqb52iTTtpGXmCCAOWWIAn9KEuFZKGqBERHmrtScZ3A==
 
-regenerate@^1.2.1:
+regenerate-unicode-properties@^8.1.0:
+  version "8.1.0"
+  resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.1.0.tgz#ef51e0f0ea4ad424b77bf7cb41f3e015c70a3f0e"
+  integrity sha512-LGZzkgtLY79GeXLm8Dp0BVLdQlWICzBnJz/ipWUgo59qBaZ+BHtq51P2q1uVZlppMuUAT37SDk39qUbjTWB7bA==
+  dependencies:
+    regenerate "^1.4.0"
+
+regenerate@^1.2.1, regenerate@^1.4.0:
   version "1.4.0"
   resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11"
   integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==
 
+regenerator-runtime@0.13.3, regenerator-runtime@^0.13.2:
+  version "0.13.3"
+  resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz#7cf6a77d8f5c6f60eb73c5fc1955b2ceb01e6bf5"
+  integrity sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw==
+
 regenerator-runtime@^0.10.0:
   version "0.10.5"
   resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658"
@@ -10776,10 +11057,12 @@ regenerator-runtime@^0.11.0:
   resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
   integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==
 
-regenerator-runtime@^0.13.2:
-  version "0.13.3"
-  resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz#7cf6a77d8f5c6f60eb73c5fc1955b2ceb01e6bf5"
-  integrity sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw==
+regenerator-transform@^0.14.0:
+  version "0.14.1"
+  resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.1.tgz#3b2fce4e1ab7732c08f665dfdb314749c7ddd2fb"
+  integrity sha512-flVuee02C3FKRISbxhXl9mGzdbWUVHubl1SMaknjxkFB1/iqpJhArQUvRxOOPEc/9tAiX0BaQ28FJH10E4isSQ==
+  dependencies:
+    private "^0.1.6"
 
 regex-cache@^0.4.2:
   version "0.4.4"
@@ -10815,6 +11098,18 @@ regexpu-core@^1.0.0:
     regjsgen "^0.2.0"
     regjsparser "^0.1.4"
 
+regexpu-core@^4.6.0:
+  version "4.6.0"
+  resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.6.0.tgz#2037c18b327cfce8a6fea2a4ec441f2432afb8b6"
+  integrity sha512-YlVaefl8P5BnFYOITTNzDvan1ulLOiXJzCNZxduTIosN17b87h3bvG9yHMoHaRuo88H4mQ06Aodj5VtYGGGiTg==
+  dependencies:
+    regenerate "^1.4.0"
+    regenerate-unicode-properties "^8.1.0"
+    regjsgen "^0.5.0"
+    regjsparser "^0.6.0"
+    unicode-match-property-ecmascript "^1.0.4"
+    unicode-match-property-value-ecmascript "^1.1.0"
+
 registry-auth-token@^3.0.1:
   version "3.3.2"
   resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-3.3.2.tgz#851fd49038eecb586911115af845260eec983f20"
@@ -10835,6 +11130,11 @@ regjsgen@^0.2.0:
   resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7"
   integrity sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=
 
+regjsgen@^0.5.0:
+  version "0.5.1"
+  resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.1.tgz#48f0bf1a5ea205196929c0d9798b42d1ed98443c"
+  integrity sha512-5qxzGZjDs9w4tzT3TPhCJqWdCc3RLYwy9J2NB0nm5Lz+S273lvWcpjaTGHsT1dc6Hhfq41uSEOw8wBmxrKOuyg==
+
 regjsparser@^0.1.4:
   version "0.1.5"
   resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c"
@@ -10842,6 +11142,13 @@ regjsparser@^0.1.4:
   dependencies:
     jsesc "~0.5.0"
 
+regjsparser@^0.6.0:
+  version "0.6.2"
+  resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.2.tgz#fd62c753991467d9d1ffe0a9f67f27a529024b96"
+  integrity sha512-E9ghzUtoLwDekPT0DYCp+c4h+bvuUpe6rRHCTYn6eGoqj1LgKXxT6I0Il4WbjhQkOghzi/V+y03bPKvbllL93Q==
+  dependencies:
+    jsesc "~0.5.0"
+
 relateurl@0.2.x:
   version "0.2.7"
   resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9"
@@ -11067,7 +11374,7 @@ rgba-regex@^1.0.0:
   resolved "https://registry.yarnpkg.com/rgba-regex/-/rgba-regex-1.0.0.tgz#43374e2e2ca0968b0ef1523460b7d730ff22eeb3"
   integrity sha1-QzdOLiyglosO8VI0YLfXMP8i7rM=
 
-rimraf@2, rimraf@2.6.2, rimraf@^2.2.8, rimraf@^2.5.2, rimraf@^2.5.4, rimraf@^2.6.0, rimraf@^2.6.1, rimraf@^2.6.2:
+rimraf@2.6.2, rimraf@^2.2.8, rimraf@^2.5.2, rimraf@^2.5.4, rimraf@^2.6.0, rimraf@^2.6.2:
   version "2.6.2"
   resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36"
   integrity sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==
@@ -11081,6 +11388,13 @@ rimraf@2.6.3, rimraf@^2.6.3:
   dependencies:
     glob "^7.1.3"
 
+rimraf@3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.0.tgz#614176d4b3010b75e5c390eb0ee96f6dc0cebb9b"
+  integrity sha512-NDGVxTsjqfunkds7CqsOiEnxln4Bo7Nddl3XhS4pXg5OzwkLqJ971ZVAAnB+DDLnF76N+VnDEiBHaVV8I06SUg==
+  dependencies:
+    glob "^7.1.3"
+
 rimraf@^2.7.1:
   version "2.7.1"
   resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec"
@@ -11182,13 +11496,6 @@ rxjs-spy@^7.5.1:
     error-stack-parser "^2.0.1"
     stacktrace-gps "^3.0.2"
 
-rxjs@6.3.3:
-  version "6.3.3"
-  resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.3.3.tgz#3c6a7fa420e844a81390fb1158a9ec614f4bad55"
-  integrity sha512-JTWmoY9tWCs7zvIk/CvRjhjGaOd+OVBM987mxFo+OW66cGpdKjZcpmc74ES1sB//7Kl/PAe8+wEakuhG4pcgOw==
-  dependencies:
-    tslib "^1.9.0"
-
 rxjs@6.4.0:
   version "6.4.0"
   resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.4.0.tgz#f3bb0fe7bda7fb69deac0c16f17b50b0b8790504"
@@ -11196,7 +11503,14 @@ rxjs@6.4.0:
   dependencies:
     tslib "^1.9.0"
 
-rxjs@^6.0.0, rxjs@^6.1.0:
+rxjs@6.5.4, rxjs@^6.4.0:
+  version "6.5.4"
+  resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.4.tgz#e0777fe0d184cec7872df147f303572d414e211c"
+  integrity sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q==
+  dependencies:
+    tslib "^1.9.0"
+
+rxjs@^6.0.0:
   version "6.2.2"
   resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.2.2.tgz#eb75fa3c186ff5289907d06483a77884586e1cf9"
   integrity sha512-0MI8+mkKAXZUF9vMrEoPnaoHkfzBPP4IGwUYRJhIRJF6/w3uByO1e91bEHn8zd43RdkTMKiooYKmwz7RH6zfOQ==
@@ -11220,6 +11534,11 @@ safe-buffer@5.1.2, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, s
   resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
   integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
 
+safe-buffer@^5.2.0:
+  version "5.2.0"
+  resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519"
+  integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==
+
 safe-regex@^1.1.0:
   version "1.1.0"
   resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e"
@@ -11232,26 +11551,15 @@ safe-regex@^1.1.0:
   resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
   integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
 
-sass-graph@^2.2.4:
-  version "2.2.4"
-  resolved "https://registry.yarnpkg.com/sass-graph/-/sass-graph-2.2.4.tgz#13fbd63cd1caf0908b9fd93476ad43a51d1e0b49"
-  integrity sha1-E/vWPNHK8JCLn9k0dq1DpR0eC0k=
-  dependencies:
-    glob "^7.0.0"
-    lodash "^4.0.0"
-    scss-tokenizer "^0.2.3"
-    yargs "^7.0.0"
-
-sass-loader@7.1.0:
-  version "7.1.0"
-  resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-7.1.0.tgz#16fd5138cb8b424bf8a759528a1972d72aad069d"
-  integrity sha512-+G+BKGglmZM2GUSfT9TLuEp6tzehHPjAMoRRItOojWIqIGPloVCMhNIQuG639eJ+y033PaGTSjLaTHts8Kw79w==
+sass-loader@7.2.0:
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-7.2.0.tgz#e34115239309d15b2527cb62b5dfefb62a96ff7f"
+  integrity sha512-h8yUWaWtsbuIiOCgR9fd9c2lRXZ2uG+h8Dzg/AGNj+Hg/3TO8+BBAW9mEP+mh8ei+qBKqSJ0F1FLlYjNBc61OA==
   dependencies:
-    clone-deep "^2.0.1"
+    clone-deep "^4.0.1"
     loader-utils "^1.0.1"
-    lodash.tail "^4.1.1"
     neo-async "^2.5.0"
-    pify "^3.0.0"
+    pify "^4.0.1"
     semver "^5.5.0"
 
 sass-loader@7.3.1:
@@ -11275,6 +11583,13 @@ sass-resources-loader@^2.0.0:
     glob "^7.1.1"
     loader-utils "^1.0.4"
 
+sass@1.22.9:
+  version "1.22.9"
+  resolved "https://registry.yarnpkg.com/sass/-/sass-1.22.9.tgz#41a2ed6038027f58be2bd5041293452a29c2cb84"
+  integrity sha512-FzU1X2V8DlnqabrL4u7OBwD2vcOzNMongEJEx3xMEhWY/v26FFR3aG0hyeu2T965sfR0E9ufJwmG+Qjz78vFPQ==
+  dependencies:
+    chokidar ">=2.0.0 <4.0.0"
+
 saucelabs@^1.5.0:
   version "1.5.0"
   resolved "https://registry.yarnpkg.com/saucelabs/-/saucelabs-1.5.0.tgz#9405a73c360d449b232839919a86c396d379fd9d"
@@ -11287,7 +11602,7 @@ sax@0.5.x:
   resolved "https://registry.yarnpkg.com/sax/-/sax-0.5.8.tgz#d472db228eb331c2506b0e8c15524adb939d12c1"
   integrity sha1-1HLbIo6zMcJQaw6MFVJK25OdEsE=
 
-sax@>=0.6.0, sax@^1.2.4, sax@~1.2.4:
+sax@>=0.6.0, sax@~1.2.4:
   version "1.2.4"
   resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
   integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
@@ -11299,7 +11614,7 @@ schema-utils@^0.3.0:
   dependencies:
     ajv "^5.0.0"
 
-schema-utils@^0.4.4, schema-utils@^0.4.5:
+schema-utils@^0.4.5:
   version "0.4.7"
   resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.4.7.tgz#ba74f597d2be2ea880131746ee17d0a093c68187"
   integrity sha512-v/iwU6wvwGK8HbU9yi3/nhGzP0yGSuhQMzL6ySiec1FSrZZDkhm4noOSWzrNFo/jEc+SJY6jRTwuwbSXJPDUnQ==
@@ -11316,6 +11631,14 @@ schema-utils@^1.0.0:
     ajv-errors "^1.0.0"
     ajv-keywords "^3.1.0"
 
+schema-utils@^2.0.0, schema-utils@^2.0.1:
+  version "2.6.4"
+  resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.6.4.tgz#a27efbf6e4e78689d91872ee3ccfa57d7bdd0f53"
+  integrity sha512-VNjcaUxVnEeun6B2fiiUDjXXBtD4ZSH7pdbfIu1pOFwgptDPLMo/z9jr4sUfsjFVPqDCEin/F7IYlq7/E6yDbQ==
+  dependencies:
+    ajv "^6.10.2"
+    ajv-keywords "^3.4.1"
+
 schema-utils@^2.6.0, schema-utils@^2.6.1:
   version "2.6.1"
   resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.6.1.tgz#eb78f0b945c7bcfa2082b3565e8db3548011dc4f"
@@ -11331,14 +11654,6 @@ script-ext-html-webpack-plugin@2.1.4:
   dependencies:
     debug "^4.1.1"
 
-scss-tokenizer@^0.2.3:
-  version "0.2.3"
-  resolved "https://registry.yarnpkg.com/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz#8eb06db9a9723333824d3f5530641149847ce5d1"
-  integrity sha1-jrBtualyMzOCTT9VMGQRSYR85dE=
-  dependencies:
-    js-base64 "^2.1.8"
-    source-map "^0.4.2"
-
 select-hose@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca"
@@ -11361,7 +11676,7 @@ selfsigned@^1.10.4:
   dependencies:
     node-forge "0.7.5"
 
-selfsigned@^1.9.1:
+selfsigned@^1.10.7:
   version "1.10.7"
   resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-1.10.7.tgz#da5819fd049d5574f28e88a9bcc6dbc6e6f3906b"
   integrity sha512-8M3wBCzeWIJnQfl43IKwOmC4H/RAp50S8DF60znzjW5GVqTcSe2vWclt7hmYVPkKPlHWOu5EaWOMZ2Y6W8ZXTA==
@@ -11394,25 +11709,25 @@ semver-intersect@1.4.0:
   resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.1.tgz#7dfdd8814bdb7cabc7be0fb1d734cfb66c940477"
   integrity sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw==
 
-semver@5.6.0, semver@^5.0.1:
+semver@6.3.0, semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0:
+  version "6.3.0"
+  resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
+  integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
+
+semver@7.0.0:
+  version "7.0.0"
+  resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e"
+  integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==
+
+semver@^5.0.1:
   version "5.6.0"
   resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004"
   integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==
 
 semver@^5.4.1, semver@^5.5.0, semver@^5.6.0:
-  version "5.7.1"
-  resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
-  integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
-
-semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0:
-  version "6.3.0"
-  resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
-  integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
-
-semver@~5.3.0:
-  version "5.3.0"
-  resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"
-  integrity sha1-myzl094C0XxgEq0yaqa00M9U+U8=
+  version "5.7.1"
+  resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
+  integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
 
 send@0.16.1:
   version "0.16.1"
@@ -11452,12 +11767,12 @@ send@0.17.1:
     range-parser "~1.2.1"
     statuses "~1.5.0"
 
-"serialize-javascript@>= 2.1.2", serialize-javascript@^1.4.0, serialize-javascript@^2.1.2:
+"serialize-javascript@>= 2.1.2", serialize-javascript@^2.1.2:
   version "2.1.2"
   resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-2.1.2.tgz#ecec53b0e0317bdc95ef76ab7074b7384785fa61"
   integrity sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ==
 
-serve-index@^1.7.2, serve-index@^1.9.1:
+serve-index@^1.9.1:
   version "1.9.1"
   resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239"
   integrity sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=
@@ -11490,7 +11805,7 @@ serve-static@1.14.1:
     parseurl "~1.3.3"
     send "0.17.1"
 
-set-blocking@^2.0.0, set-blocking@~2.0.0:
+set-blocking@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
   integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
@@ -11535,15 +11850,6 @@ sha.js@^2.4.0, sha.js@^2.4.8:
     inherits "^2.0.1"
     safe-buffer "^5.0.1"
 
-shallow-clone@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-1.0.0.tgz#4480cd06e882ef68b2ad88a3ea54832e2c48b571"
-  integrity sha512-oeXreoKR/SyNJtRJMAKPDSvd28OqEwG4eR/xc856cRGBII7gX9lvAqDxusPm0846z/w/hWYjI1NpKwJ00NHzRA==
-  dependencies:
-    is-extendable "^0.1.1"
-    kind-of "^5.0.0"
-    mixin-object "^2.0.1"
-
 shallow-clone@^3.0.0:
   version "3.0.1"
   resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3"
@@ -11582,15 +11888,6 @@ shelljs@^0.7.0:
     interpret "^1.0.0"
     rechoir "^0.6.2"
 
-shelljs@^0.8.1:
-  version "0.8.3"
-  resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.3.tgz#a7f3319520ebf09ee81275b2368adb286659b097"
-  integrity sha512-fc0BKlAWiLpwZljmOvAOTE/gXawtCoNrP5oaY7KIaQbbyHeQVg01pSEuEGvGh3HEdBU4baCD7wQBwADmM/7f7A==
-  dependencies:
-    glob "^7.0.0"
-    interpret "^1.0.0"
-    rechoir "^0.6.2"
-
 signal-exit@^3.0.0, signal-exit@^3.0.2:
   version "3.0.2"
   resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
@@ -11710,6 +12007,18 @@ sockjs-client@1.3.0:
     json3 "^3.3.2"
     url-parse "^1.4.3"
 
+sockjs-client@1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.4.0.tgz#c9f2568e19c8fd8173b4997ea3420e0bb306c7d5"
+  integrity sha512-5zaLyO8/nri5cua0VtOrFXBPK1jbL4+1cebT/mmKA1E1ZXOvJrII75bPu0l0k843G/+iAbhEqzyKr0w/eCCj7g==
+  dependencies:
+    debug "^3.2.5"
+    eventsource "^1.0.7"
+    faye-websocket "~0.11.1"
+    inherits "^2.0.3"
+    json3 "^3.3.2"
+    url-parse "^1.4.3"
+
 sockjs@0.3.19:
   version "0.3.19"
   resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.19.tgz#d976bbe800af7bd20ae08598d582393508993c0d"
@@ -11734,6 +12043,13 @@ socks@~2.3.2:
     ip "1.1.5"
     smart-buffer "^4.1.0"
 
+sort-keys@^1.0.0:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-1.1.2.tgz#441b6d4d346798f1b4e49e8920adfba0e543f9ad"
+  integrity sha1-RBttTTRnmPG05J6JIK37oOVD+a0=
+  dependencies:
+    is-plain-obj "^1.0.0"
+
 sortablejs@1.7.0:
   version "1.7.0"
   resolved "https://registry.yarnpkg.com/sortablejs/-/sortablejs-1.7.0.tgz#80a2b2370abd568e1cec8c271131ef30a904fa28"
@@ -11768,10 +12084,10 @@ source-map-resolve@^0.5.0:
     source-map-url "^0.4.0"
     urix "^0.1.0"
 
-source-map-support@0.5.10:
-  version "0.5.10"
-  resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.10.tgz#2214080bc9d51832511ee2bab96e3c2f9353120c"
-  integrity sha512-YfQ3tQFTK/yzlGJuX8pTwa4tifQj4QS2Mj7UegOu8jAz59MqIiMGPXxQhVQiIMNzayuUSF/jEuVnfFF5JqybmQ==
+source-map-support@0.5.13:
+  version "0.5.13"
+  resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932"
+  integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==
   dependencies:
     buffer-from "^1.0.0"
     source-map "^0.6.0"
@@ -11784,7 +12100,7 @@ source-map-support@^0.5.0, source-map-support@~0.5.6:
     buffer-from "^1.0.0"
     source-map "^0.6.0"
 
-source-map-support@^0.5.5, source-map-support@~0.5.10, source-map-support@~0.5.12:
+source-map-support@^0.5.5, source-map-support@~0.5.12:
   version "0.5.16"
   resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.16.tgz#0ae069e7fe3ba7538c64c98515e35339eac5a042"
   integrity sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==
@@ -11826,14 +12142,7 @@ source-map@0.7.3:
   resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383"
   integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==
 
-source-map@^0.4.2, source-map@~0.4.1:
-  version "0.4.4"
-  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b"
-  integrity sha1-66T12pwNyZneaAMti092FzZSA2s=
-  dependencies:
-    amdefine ">=0.0.4"
-
-source-map@^0.5.1, source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7:
+source-map@^0.5.0, source-map@^0.5.1, source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7:
   version "0.5.7"
   resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
   integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=
@@ -11850,6 +12159,13 @@ source-map@~0.2.0:
   dependencies:
     amdefine ">=0.0.4"
 
+source-map@~0.4.1:
+  version "0.4.4"
+  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b"
+  integrity sha1-66T12pwNyZneaAMti092FzZSA2s=
+  dependencies:
+    amdefine ">=0.0.4"
+
 sourcemap-codec@^1.4.4:
   version "1.4.6"
   resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.6.tgz#e30a74f0402bad09807640d39e971090a08ce1e9"
@@ -11898,7 +12214,7 @@ spdy-transport@^3.0.0:
     readable-stream "^3.0.6"
     wbuf "^1.7.3"
 
-spdy@^4.0.0:
+spdy@^4.0.0, spdy@^4.0.1:
   version "4.0.1"
   resolved "https://registry.yarnpkg.com/spdy/-/spdy-4.0.1.tgz#6f12ed1c5db7ea4f24ebb8b89ba58c87c08257f2"
   integrity sha512-HeZS3PBdMA+sZSu0qwpCxl3DeALD5ASx8pAX0jZdKXSpPWbQ6SYGnlg3BBmYLx5LtiZrmkAZfErCm2oECBcioA==
@@ -11956,13 +12272,6 @@ sshpk@^1.7.0:
     jsbn "~0.1.0"
     tweetnacl "~0.14.0"
 
-ssri@^5.2.4:
-  version "5.3.0"
-  resolved "https://registry.yarnpkg.com/ssri/-/ssri-5.3.0.tgz#ba3872c9c6d33a0704a7d71ff045e5ec48999d06"
-  integrity sha512-XRSIPqLij52MtgoQavH/x/dU1qVKtWUAAZeOHsR9c2Ddi4XerFy3mc1alf+dLJKl9EUIm/Ht+EowFkTUOA6GAQ==
-  dependencies:
-    safe-buffer "^5.1.1"
-
 ssri@^6.0.0, ssri@^6.0.1:
   version "6.0.1"
   resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.1.tgz#2a3c41b28dd45b62b63676ecb74001265ae9edd8"
@@ -12004,13 +12313,6 @@ static-extend@^0.1.1:
     define-property "^0.2.5"
     object-copy "^0.1.0"
 
-stats-webpack-plugin@0.7.0:
-  version "0.7.0"
-  resolved "https://registry.yarnpkg.com/stats-webpack-plugin/-/stats-webpack-plugin-0.7.0.tgz#ccffe9b745de8bbb155571e063f8263fc0e2bc06"
-  integrity sha512-NT0YGhwuQ0EOX+uPhhUcI6/+1Sq/pMzNuSCBVT4GbFl/ac6I/JZefBcjlECNfAb1t3GOx5dEj1Z7x0cAxeeVLQ==
-  dependencies:
-    lodash "^4.17.4"
-
 "statuses@>= 1.3.1 < 2", "statuses@>= 1.4.0 < 2", "statuses@>= 1.5.0 < 2", statuses@~1.5.0:
   version "1.5.0"
   resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
@@ -12021,13 +12323,6 @@ statuses@~1.3.1:
   resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e"
   integrity sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=
 
-stdout-stream@^1.4.0:
-  version "1.4.1"
-  resolved "https://registry.yarnpkg.com/stdout-stream/-/stdout-stream-1.4.1.tgz#5ac174cdd5cd726104aa0c0b2bd83815d8d535de"
-  integrity sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA==
-  dependencies:
-    readable-stream "^2.0.1"
-
 stream-browserify@^2.0.1:
   version "2.0.1"
   resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db"
@@ -12078,6 +12373,11 @@ streamroller@^1.0.6:
     fs-extra "^7.0.1"
     lodash "^4.17.14"
 
+strict-uri-encode@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713"
+  integrity sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=
+
 string-replace-loader@^2.1.1:
   version "2.1.1"
   resolved "https://registry.yarnpkg.com/string-replace-loader/-/string-replace-loader-2.1.1.tgz#b72e7b57b6ef04efe615aff0ad989b5c14ca63d1"
@@ -12086,7 +12386,7 @@ string-replace-loader@^2.1.1:
     loader-utils "^1.1.0"
     schema-utils "^0.4.5"
 
-string-width@^1.0.1, string-width@^1.0.2:
+string-width@^1.0.1:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
   integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=
@@ -12095,7 +12395,7 @@ string-width@^1.0.1, string-width@^1.0.2:
     is-fullwidth-code-point "^1.0.0"
     strip-ansi "^3.0.0"
 
-"string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1:
+string-width@^2.0.0, string-width@^2.1.1:
   version "2.1.1"
   resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e"
   integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==
@@ -12211,13 +12511,13 @@ strip-json-comments@^3.0.1:
   resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.0.1.tgz#85713975a91fb87bf1b305cca77395e40d2a64a7"
   integrity sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==
 
-style-loader@0.23.1:
-  version "0.23.1"
-  resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.23.1.tgz#cb9154606f3e771ab6c4ab637026a1049174d925"
-  integrity sha512-XK+uv9kWwhZMZ1y7mysB+zoihsEj4wneFWAS5qoiLwzW0WzSqMrrsIy+a3zkQJq0ipFtBpX5W3MqyRIBF/WFGg==
+style-loader@1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-1.0.0.tgz#1d5296f9165e8e2c85d24eee0b7caf9ec8ca1f82"
+  integrity sha512-B0dOCFwv7/eY31a5PCieNwMgMhVGFe9w+rh7s/Bx8kfFkrth9zfTZquoYvdw8URgiqxObQKcpW51Ugz1HjfdZw==
   dependencies:
-    loader-utils "^1.1.0"
-    schema-utils "^1.0.0"
+    loader-utils "^1.2.3"
+    schema-utils "^2.0.1"
 
 stylehacks@^4.0.0:
   version "4.0.3"
@@ -12282,7 +12582,7 @@ supports-color@^3.1.0:
   dependencies:
     has-flag "^1.0.0"
 
-supports-color@^5.1.0, supports-color@^5.2.0, supports-color@^5.3.0, supports-color@^5.4.0:
+supports-color@^5.2.0, supports-color@^5.3.0, supports-color@^5.4.0:
   version "5.5.0"
   resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
   integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
@@ -12329,7 +12629,7 @@ tapable@^1.0.0:
   resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.0.0.tgz#cbb639d9002eed9c6b5975eb20598d7936f1f9f2"
   integrity sha512-dQRhbNQkRnaqauC7WqSJ21EEksgT0fYZX2lqXzGkpo8JNig9zGZTYoMGvyI2nWmXlE2VSVXVDu7wLVGu/mQEsg==
 
-tapable@^1.1.0, tapable@^1.1.3:
+tapable@^1.1.3:
   version "1.1.3"
   resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2"
   integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==
@@ -12345,28 +12645,6 @@ tar-stream@^2.1.0:
     inherits "^2.0.3"
     readable-stream "^3.1.1"
 
-tar@^2.0.0:
-  version "2.2.1"
-  resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1"
-  integrity sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=
-  dependencies:
-    block-stream "*"
-    fstream "^1.0.2"
-    inherits "2"
-
-tar@^4:
-  version "4.4.6"
-  resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.6.tgz#63110f09c00b4e60ac8bcfe1bf3c8660235fbc9b"
-  integrity sha512-tMkTnh9EdzxyfW+6GK6fCahagXsnYk6kE6S9Gr9pjVdys769+laCTbodXDhPAjzVtEBazRgP0gYqOjnk9dQzLg==
-  dependencies:
-    chownr "^1.0.1"
-    fs-minipass "^1.2.5"
-    minipass "^2.3.3"
-    minizlib "^1.1.0"
-    mkdirp "^0.5.0"
-    safe-buffer "^5.1.2"
-    yallist "^3.0.2"
-
 tar@^4.4.8:
   version "4.4.13"
   resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.13.tgz#43b364bc52888d555298637b10d60790254ab525"
@@ -12387,21 +12665,7 @@ term-size@^1.2.0:
   dependencies:
     execa "^0.7.0"
 
-terser-webpack-plugin@1.2.2:
-  version "1.2.2"
-  resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.2.2.tgz#9bff3a891ad614855a7dde0d707f7db5a927e3d9"
-  integrity sha512-1DMkTk286BzmfylAvLXwpJrI7dWa5BnFmscV/2dCr8+c56egFcbaeFAl7+sujAjdmpLam21XRdhA4oifLyiWWg==
-  dependencies:
-    cacache "^11.0.2"
-    find-cache-dir "^2.0.0"
-    schema-utils "^1.0.0"
-    serialize-javascript "^1.4.0"
-    source-map "^0.6.1"
-    terser "^3.16.1"
-    webpack-sources "^1.1.0"
-    worker-farm "^1.5.2"
-
-terser-webpack-plugin@^1.1.0, terser-webpack-plugin@^1.4.3:
+terser-webpack-plugin@1.4.3, terser-webpack-plugin@^1.4.1, terser-webpack-plugin@^1.4.3:
   version "1.4.3"
   resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.4.3.tgz#5ecaf2dbdc5fb99745fd06791f46fc9ddb1c9a7c"
   integrity sha512-QMxecFz/gHQwteWwSo5nTc6UaICqN1bMedC5sMtUc7y3Ha3Q8y6ZO0iCR8pq4RJC8Hjf0FEPEHZqcMB/+DFCrA==
@@ -12430,14 +12694,14 @@ terser-webpack-plugin@^2.3.1:
     terser "^4.4.3"
     webpack-sources "^1.4.3"
 
-terser@^3.16.1:
-  version "3.17.0"
-  resolved "https://registry.yarnpkg.com/terser/-/terser-3.17.0.tgz#f88ffbeda0deb5637f9d24b0da66f4e15ab10cb2"
-  integrity sha512-/FQzzPJmCpjAH9Xvk2paiWrFq+5M6aVOf+2KRbwhByISDX/EujxsK+BAvrhb6H+2rtrLCHK9N01wO014vrIwVQ==
+terser@4.6.3:
+  version "4.6.3"
+  resolved "https://registry.yarnpkg.com/terser/-/terser-4.6.3.tgz#e33aa42461ced5238d352d2df2a67f21921f8d87"
+  integrity sha512-Lw+ieAXmY69d09IIc/yqeBqXpEQIpDGZqT34ui1QWXIUpR2RjbqEkT8X7Lgex19hslSqcWM5iMN2kM11eMsESQ==
   dependencies:
-    commander "^2.19.0"
+    commander "^2.20.0"
     source-map "~0.6.1"
-    source-map-support "~0.5.10"
+    source-map-support "~0.5.12"
 
 terser@^3.8.2:
   version "3.8.2"
@@ -12562,6 +12826,11 @@ to-fast-properties@^1.0.3:
   resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47"
   integrity sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=
 
+to-fast-properties@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
+  integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=
+
 to-object-path@^0.3.0:
   version "0.3.0"
   resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af"
@@ -12577,6 +12846,13 @@ to-regex-range@^2.1.0:
     is-number "^3.0.0"
     repeat-string "^1.6.1"
 
+to-regex-range@^5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
+  integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
+  dependencies:
+    is-number "^7.0.0"
+
 to-regex@^3.0.1, to-regex@^3.0.2:
   version "3.0.2"
   resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce"
@@ -12619,10 +12895,10 @@ tough-cookie@~2.4.3:
     psl "^1.1.24"
     punycode "^1.4.1"
 
-tree-kill@1.2.1:
-  version "1.2.1"
-  resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.1.tgz#5398f374e2f292b9dcc7b2e71e30a5c3bb6c743a"
-  integrity sha512-4hjqbObwlh2dLyW4tcz0Ymw0ggoaVDMveUB9w8kFSQScdRLo0gxO9J7WFcUBo+W3C1TLdFIEwNOWebgZZ0RH9Q==
+tree-kill@1.2.2:
+  version "1.2.2"
+  resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc"
+  integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==
 
 trim-newlines@^1.0.0:
   version "1.0.0"
@@ -12634,13 +12910,6 @@ trim-right@^1.0.1:
   resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003"
   integrity sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=
 
-"true-case-path@^1.0.2":
-  version "1.0.3"
-  resolved "https://registry.yarnpkg.com/true-case-path/-/true-case-path-1.0.3.tgz#f813b5a8c86b40da59606722b144e3225799f47d"
-  integrity sha512-m6s2OdQe5wgpFMC+pAJ+q9djG82O2jcHPOI6RNg1yy9rCYR+WD6Nbpl32fDpfC56nirdRy+opFa/Vk7HYhqaew==
-  dependencies:
-    glob "^7.1.2"
-
 tryer@^1.0.0:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/tryer/-/tryer-1.0.1.tgz#f2c85406800b9b0f74c9f7465b81eaad241252f8"
@@ -12693,17 +12962,12 @@ tsconfig@^7.0.0:
     strip-bom "^3.0.0"
     strip-json-comments "^2.0.0"
 
-tslib@^1.7.1:
-  version "1.10.0"
-  resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a"
-  integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==
-
-tslib@^1.7.1:
+tslib@1.10.0, tslib@^1.7.1, tslib@^1.9.0:
   version "1.10.0"
   resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a"
   integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==
 
-tslib@^1.8.0, tslib@^1.8.1, tslib@^1.9.0:
+tslib@^1.8.0, tslib@^1.8.1:
   version "1.9.3"
   resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286"
   integrity sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==
@@ -12833,15 +13097,10 @@ typescript@2.4.1:
   resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.4.1.tgz#c3ccb16ddaa0b2314de031e7e6fee89e5ba346bc"
   integrity sha1-w8yxbdqgsjFN4DHn5v7onlujRrw=
 
-typescript@3.1.6:
-  version "3.1.6"
-  resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.1.6.tgz#b6543a83cfc8c2befb3f4c8fba6896f5b0c9be68"
-  integrity sha512-tDMYfVtvpb96msS1lDX9MEdHrW4yOuZ4Kdc4Him9oU796XldPYF/t2+uKoX0BBa0hXXwDlqYQbXY5Rzjzc5hBA==
-
-typescript@3.2.4:
-  version "3.2.4"
-  resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.2.4.tgz#c585cb952912263d915b462726ce244ba510ef3d"
-  integrity sha512-0RNDbSdEokBeEAkgNbxJ+BLwSManFy9TeXz8uW+48j/xhEXv1ePME60olyzw2XzUqUBNAYFeJadIqAgNqIACwg==
+typescript@3.5.3:
+  version "3.5.3"
+  resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.3.tgz#c830f657f93f1ea846819e929092f5fe5983e977"
+  integrity sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==
 
 "typescript@>=2.6.2 <2.10", typescript@^2.5.0:
   version "2.9.2"
@@ -12883,6 +13142,29 @@ undefsafe@^2.0.2:
   dependencies:
     debug "^2.2.0"
 
+unicode-canonical-property-names-ecmascript@^1.0.4:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818"
+  integrity sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==
+
+unicode-match-property-ecmascript@^1.0.4:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz#8ed2a32569961bce9227d09cd3ffbb8fed5f020c"
+  integrity sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==
+  dependencies:
+    unicode-canonical-property-names-ecmascript "^1.0.4"
+    unicode-property-aliases-ecmascript "^1.0.4"
+
+unicode-match-property-value-ecmascript@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.1.0.tgz#5b4b426e08d13a80365e0d657ac7a6c1ec46a277"
+  integrity sha512-hDTHvaBk3RmFzvSl0UVrUmC3PuW9wKVnpoUDYH0JDkSIovzw+J5viQmeYHxVSBptubnr7PbH2e0fnpDRQnQl5g==
+
+unicode-property-aliases-ecmascript@^1.0.4:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.5.tgz#a9cc6cc7ce63a0a3023fc99e341b94431d405a57"
+  integrity sha512-L5RAqCfXqAwR3RriF8pM0lU0w4Ryf/GgzONwi6KnL1taJQa7x1TCxdJnILX59WIGOwR57IVxn7Nej0fz1Ny6fw==
+
 union-value@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4"
@@ -12910,13 +13192,6 @@ uniqs@^2.0.0:
   resolved "https://registry.yarnpkg.com/uniqs/-/uniqs-2.0.0.tgz#ffede4b36b25290696e6e165d4a59edb998e6b02"
   integrity sha1-/+3ks2slKQaW5uFl1KWe25mOawI=
 
-unique-filename@^1.1.0:
-  version "1.1.0"
-  resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.0.tgz#d05f2fe4032560871f30e93cbe735eea201514f3"
-  integrity sha1-0F8v5AMlYIcfMOk8vnNe6iAVFPM=
-  dependencies:
-    unique-slug "^2.0.0"
-
 unique-filename@^1.1.1:
   version "1.1.1"
   resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230"
@@ -12946,6 +13221,15 @@ units-css@^0.4.0:
     isnumeric "^0.2.0"
     viewport-dimensions "^0.2.0"
 
+universal-analytics@^0.4.20:
+  version "0.4.20"
+  resolved "https://registry.yarnpkg.com/universal-analytics/-/universal-analytics-0.4.20.tgz#d6b64e5312bf74f7c368e3024a922135dbf24b03"
+  integrity sha512-gE91dtMvNkjO+kWsPstHRtSwHXz0l2axqptGYp5ceg4MsuurloM0PU3pdOfpb5zBXUvyjT4PwhWK2m39uczZuw==
+  dependencies:
+    debug "^3.0.0"
+    request "^2.88.0"
+    uuid "^3.0.0"
+
 universalify@^0.1.0:
   version "0.1.2"
   resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
@@ -13083,6 +13367,13 @@ util-deprecate@^1.0.1, util-deprecate@~1.0.1:
   resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
   integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
 
+util-promisify@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/util-promisify/-/util-promisify-2.1.0.tgz#3c2236476c4d32c5ff3c47002add7c13b9a82a53"
+  integrity sha1-PCI2R2xNMsX/PEcAKt18E7moKlM=
+  dependencies:
+    object.getownpropertydescriptors "^2.0.3"
+
 util.promisify@1.0.0, util.promisify@~1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.0.tgz#440f7165a459c9a16dc145eb8e72f35687097030"
@@ -13098,13 +13389,6 @@ util@0.10.3:
   dependencies:
     inherits "2.0.1"
 
-util@^0.10.3:
-  version "0.10.4"
-  resolved "https://registry.yarnpkg.com/util/-/util-0.10.4.tgz#3aa0125bfe668a4672de58857d3ace27ecb76901"
-  integrity sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==
-  dependencies:
-    inherits "2.0.3"
-
 util@^0.11.0:
   version "0.11.1"
   resolved "https://registry.yarnpkg.com/util/-/util-0.11.1.tgz#3236733720ec64bb27f6e26f421aaa2e1b588d61"
@@ -13132,6 +13416,11 @@ uuid@^2.0.1:
   resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a"
   integrity sha1-Z+LoY3lyFVMN/zGOW/nc6/1Hsho=
 
+uuid@^3.0.0:
+  version "3.4.0"
+  resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
+  integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
+
 uuid@^3.0.1, uuid@^3.1.0, uuid@^3.2.1, uuid@^3.3.2:
   version "3.3.2"
   resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131"
@@ -13212,13 +13501,6 @@ vlq@^0.2.2:
   resolved "https://registry.yarnpkg.com/vlq/-/vlq-0.2.3.tgz#8f3e4328cf63b1540c0d67e1b2778386f8975b26"
   integrity sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow==
 
-vm-browserify@0.0.4:
-  version "0.0.4"
-  resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-0.0.4.tgz#5d7ea45bbef9e4a6ff65f95438e0a87c357d5a73"
-  integrity sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=
-  dependencies:
-    indexof "0.0.1"
-
 vm-browserify@^1.0.1:
   version "1.1.2"
   resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0"
@@ -13229,7 +13511,7 @@ void-elements@^2.0.0:
   resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec"
   integrity sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=
 
-watchpack@^1.5.0, watchpack@^1.6.0:
+watchpack@^1.6.0:
   version "1.6.0"
   resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.6.0.tgz#4bc12c2ebe8aa277a71f1d3f14d685c7b446cd00"
   integrity sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA==
@@ -13364,24 +13646,15 @@ webpack-dev-middleware@3.2.0:
     url-join "^4.0.0"
     webpack-log "^2.0.0"
 
-webpack-dev-middleware@3.4.0:
-  version "3.4.0"
-  resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.4.0.tgz#1132fecc9026fd90f0ecedac5cbff75d1fb45890"
-  integrity sha512-Q9Iyc0X9dP9bAsYskAVJ/hmIZZQwf/3Sy4xCAZgL5cUkjZmUZLt4l5HpbST/Pdgjn3u6pE7u5OdGd1apgzRujA==
-  dependencies:
-    memory-fs "~0.4.1"
-    mime "^2.3.1"
-    range-parser "^1.0.3"
-    webpack-log "^2.0.0"
-
-webpack-dev-middleware@3.5.1:
-  version "3.5.1"
-  resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.5.1.tgz#9265b7742ef50f54f54c1d9af022fc17c1be9b88"
-  integrity sha512-4dwCh/AyMOYAybggUr8fiCkRnjVDp+Cqlr9c+aaNB3GJYgRGYQWJ1YX/WAKUNA9dPNHZ6QSN2lYDKqjKSI8Vqw==
+webpack-dev-middleware@3.7.2, webpack-dev-middleware@^3.7.2:
+  version "3.7.2"
+  resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.7.2.tgz#0019c3db716e3fa5cecbf64f2ab88a74bab331f3"
+  integrity sha512-1xC42LxbYoqLNAhV6YzTYacicgMZQTqRd27Sim9wn5hJrX3I5nxYy1SxSd4+gjUFsz1dQFj+yEe6zEVmSkeJjw==
   dependencies:
-    memory-fs "~0.4.1"
-    mime "^2.3.1"
-    range-parser "^1.0.3"
+    memory-fs "^0.4.1"
+    mime "^2.4.4"
+    mkdirp "^0.5.1"
+    range-parser "^1.2.1"
     webpack-log "^2.0.0"
 
 webpack-dev-middleware@^2.0.6:
@@ -13407,41 +13680,44 @@ webpack-dev-middleware@^3.7.0:
     range-parser "^1.2.1"
     webpack-log "^2.0.0"
 
-webpack-dev-server@3.1.14:
-  version "3.1.14"
-  resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.1.14.tgz#60fb229b997fc5a0a1fc6237421030180959d469"
-  integrity sha512-mGXDgz5SlTxcF3hUpfC8hrQ11yhAttuUQWf1Wmb+6zo3x6rb7b9mIfuQvAPLdfDRCGRGvakBWHdHOa0I9p/EVQ==
+webpack-dev-server@3.9.0:
+  version "3.9.0"
+  resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.9.0.tgz#27c3b5d0f6b6677c4304465ac817623c8b27b89c"
+  integrity sha512-E6uQ4kRrTX9URN9s/lIbqTAztwEPdvzVrcmHE8EQ9YnuT9J8Es5Wrd8n9BKg1a0oZ5EgEke/EQFgUsp18dSTBw==
   dependencies:
     ansi-html "0.0.7"
     bonjour "^3.5.0"
-    chokidar "^2.0.0"
-    compression "^1.5.2"
-    connect-history-api-fallback "^1.3.0"
-    debug "^3.1.0"
-    del "^3.0.0"
-    express "^4.16.2"
-    html-entities "^1.2.0"
-    http-proxy-middleware "~0.18.0"
+    chokidar "^2.1.8"
+    compression "^1.7.4"
+    connect-history-api-fallback "^1.6.0"
+    debug "^4.1.1"
+    del "^4.1.1"
+    express "^4.17.1"
+    html-entities "^1.2.1"
+    http-proxy-middleware "0.19.1"
     import-local "^2.0.0"
-    internal-ip "^3.0.1"
+    internal-ip "^4.3.0"
     ip "^1.1.5"
-    killable "^1.0.0"
-    loglevel "^1.4.1"
-    opn "^5.1.0"
-    portfinder "^1.0.9"
+    is-absolute-url "^3.0.3"
+    killable "^1.0.1"
+    loglevel "^1.6.4"
+    opn "^5.5.0"
+    p-retry "^3.0.1"
+    portfinder "^1.0.25"
     schema-utils "^1.0.0"
-    selfsigned "^1.9.1"
-    semver "^5.6.0"
-    serve-index "^1.7.2"
+    selfsigned "^1.10.7"
+    semver "^6.3.0"
+    serve-index "^1.9.1"
     sockjs "0.3.19"
-    sockjs-client "1.3.0"
-    spdy "^4.0.0"
-    strip-ansi "^3.0.0"
-    supports-color "^5.1.0"
+    sockjs-client "1.4.0"
+    spdy "^4.0.1"
+    strip-ansi "^3.0.1"
+    supports-color "^6.1.0"
     url "^0.11.0"
-    webpack-dev-middleware "3.4.0"
+    webpack-dev-middleware "^3.7.2"
     webpack-log "^2.0.0"
-    yargs "12.0.2"
+    ws "^6.2.1"
+    yargs "12.0.5"
 
 webpack-dev-server@^3.1.11:
   version "3.7.2"
@@ -13524,10 +13800,10 @@ webpack-node-externals@1.7.2:
   resolved "https://registry.yarnpkg.com/webpack-node-externals/-/webpack-node-externals-1.7.2.tgz#6e1ee79ac67c070402ba700ef033a9b8d52ac4e3"
   integrity sha512-ajerHZ+BJKeCLviLUUmnyd5B4RavLF76uv3cs6KNuO8W+HuQaEs0y0L7o40NQxdPy5w0pcv8Ew7yPUAQG0UdCg==
 
-webpack-sources@1.3.0:
-  version "1.3.0"
-  resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.3.0.tgz#2a28dcb9f1f45fe960d8f1493252b5ee6530fa85"
-  integrity sha512-OiVgSrbGu7NEnEvQJJgdSFPl2qWKkWq5lHMhgiToIiN9w34EBnjYzSYs+VbL5KoYiLNtFFa7BZIKxRED3I32pA==
+webpack-sources@1.4.3, webpack-sources@^1.2.0, webpack-sources@^1.4.0, webpack-sources@^1.4.1, webpack-sources@^1.4.3:
+  version "1.4.3"
+  resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933"
+  integrity sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==
   dependencies:
     source-list-map "^2.0.0"
     source-map "~0.6.1"
@@ -13540,14 +13816,6 @@ webpack-sources@^1.0.1, webpack-sources@^1.1.0:
     source-list-map "^2.0.0"
     source-map "~0.6.1"
 
-webpack-sources@^1.2.0, webpack-sources@^1.3.0, webpack-sources@^1.4.0, webpack-sources@^1.4.1, webpack-sources@^1.4.3:
-  version "1.4.3"
-  resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933"
-  integrity sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==
-  dependencies:
-    source-list-map "^2.0.0"
-    source-map "~0.6.1"
-
 webpack-subresource-integrity@1.1.0-rc.6:
   version "1.1.0-rc.6"
   resolved "https://registry.yarnpkg.com/webpack-subresource-integrity/-/webpack-subresource-integrity-1.1.0-rc.6.tgz#37f6f1264e1eb378e41465a98da80fad76ab8886"
@@ -13555,35 +13823,34 @@ webpack-subresource-integrity@1.1.0-rc.6:
   dependencies:
     webpack-core "^0.6.8"
 
-webpack@4.29.0:
-  version "4.29.0"
-  resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.29.0.tgz#f2cfef83f7ae404ba889ff5d43efd285ca26e750"
-  integrity sha512-pxdGG0keDBtamE1mNvT5zyBdx+7wkh6mh7uzMOo/uRQ/fhsdj5FXkh/j5mapzs060forql1oXqXN9HJGju+y7w==
-  dependencies:
-    "@webassemblyjs/ast" "1.7.11"
-    "@webassemblyjs/helper-module-context" "1.7.11"
-    "@webassemblyjs/wasm-edit" "1.7.11"
-    "@webassemblyjs/wasm-parser" "1.7.11"
-    acorn "^6.0.5"
-    acorn-dynamic-import "^4.0.0"
-    ajv "^6.1.0"
-    ajv-keywords "^3.1.0"
-    chrome-trace-event "^1.0.0"
+webpack@4.39.2:
+  version "4.39.2"
+  resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.39.2.tgz#c9aa5c1776d7c309d1b3911764f0288c8c2816aa"
+  integrity sha512-AKgTfz3xPSsEibH00JfZ9sHXGUwIQ6eZ9tLN8+VLzachk1Cw2LVmy+4R7ZiwTa9cZZ15tzySjeMui/UnSCAZhA==
+  dependencies:
+    "@webassemblyjs/ast" "1.8.5"
+    "@webassemblyjs/helper-module-context" "1.8.5"
+    "@webassemblyjs/wasm-edit" "1.8.5"
+    "@webassemblyjs/wasm-parser" "1.8.5"
+    acorn "^6.2.1"
+    ajv "^6.10.2"
+    ajv-keywords "^3.4.1"
+    chrome-trace-event "^1.0.2"
     enhanced-resolve "^4.1.0"
-    eslint-scope "^4.0.0"
+    eslint-scope "^4.0.3"
     json-parse-better-errors "^1.0.2"
-    loader-runner "^2.3.0"
-    loader-utils "^1.1.0"
-    memory-fs "~0.4.1"
-    micromatch "^3.1.8"
-    mkdirp "~0.5.0"
-    neo-async "^2.5.0"
-    node-libs-browser "^2.0.0"
-    schema-utils "^0.4.4"
-    tapable "^1.1.0"
-    terser-webpack-plugin "^1.1.0"
-    watchpack "^1.5.0"
-    webpack-sources "^1.3.0"
+    loader-runner "^2.4.0"
+    loader-utils "^1.2.3"
+    memory-fs "^0.4.1"
+    micromatch "^3.1.10"
+    mkdirp "^0.5.1"
+    neo-async "^2.6.1"
+    node-libs-browser "^2.2.1"
+    schema-utils "^1.0.0"
+    tapable "^1.1.3"
+    terser-webpack-plugin "^1.4.1"
+    watchpack "^1.6.0"
+    webpack-sources "^1.4.1"
 
 webpack@^4.29.6:
   version "4.41.3"
@@ -13632,30 +13899,18 @@ when@~3.6.x:
   resolved "https://registry.yarnpkg.com/when/-/when-3.6.4.tgz#473b517ec159e2b85005497a13983f095412e34e"
   integrity sha1-RztRfsFZ4rhQBUl6E5g/CVQS404=
 
-which-module@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f"
-  integrity sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=
-
 which-module@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a"
   integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=
 
-which@1, which@^1.1.1, which@^1.2.1, which@^1.2.10, which@^1.2.14, which@^1.2.9, which@^1.3.1:
+which@^1.1.1, which@^1.2.1, which@^1.2.10, which@^1.2.14, which@^1.2.9, which@^1.3.1:
   version "1.3.1"
   resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
   integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
   dependencies:
     isexe "^2.0.0"
 
-wide-align@^1.1.0:
-  version "1.1.3"
-  resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457"
-  integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==
-  dependencies:
-    string-width "^1.0.2 || 2"
-
 widest-line@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-2.0.0.tgz#0142a4e8a243f8882c0233aa0e0281aa76152273"
@@ -13678,13 +13933,6 @@ wordwrap@~0.0.2:
   resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107"
   integrity sha1-o9XabNXAvAAI03I0u68b7WMFkQc=
 
-worker-farm@^1.5.2:
-  version "1.6.0"
-  resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.6.0.tgz#aecc405976fab5a95526180846f0dba288f3a4a0"
-  integrity sha512-6w+3tHbM87WnSWnENBUvA2pxJPLhQUg5LKwUQHq3r+XPhIM+Gh2R5ycbwPCyuGbNg+lPgdcnQUhuC02kJCvffQ==
-  dependencies:
-    errno "~0.1.7"
-
 worker-farm@^1.7.0:
   version "1.7.0"
   resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.7.0.tgz#26a94c5391bbca926152002f69b84a4bf772e5a8"
@@ -13692,6 +13940,13 @@ worker-farm@^1.7.0:
   dependencies:
     errno "~0.1.7"
 
+worker-plugin@3.2.0:
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/worker-plugin/-/worker-plugin-3.2.0.tgz#ddae9f161b76fcbaacf8f54ecd037844584e43e7"
+  integrity sha512-W5nRkw7+HlbsEt3qRP6MczwDDISjiRj2GYt9+bpe8A2La00TmJdwzG5bpdMXhRt1qcWmwAvl1TiKaHRa+XDS9Q==
+  dependencies:
+    loader-utils "^1.1.0"
+
 wrap-ansi@^2.0.0:
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85"
@@ -13730,7 +13985,7 @@ write@1.0.3:
   dependencies:
     mkdirp "^0.5.1"
 
-ws@^6.0.0:
+ws@^6.0.0, ws@^6.2.1:
   version "6.2.1"
   resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.1.tgz#442fdf0a47ed64f59b6a5d8ff130f4748ed524fb"
   integrity sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==
@@ -13774,21 +14029,11 @@ xmlhttprequest-ssl@~1.5.4:
   resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz#c2876b06168aadc40e57d97e81191ac8f4398b3e"
   integrity sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=
 
-xregexp@4.0.0:
-  version "4.0.0"
-  resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-4.0.0.tgz#e698189de49dd2a18cc5687b05e17c8e43943020"
-  integrity sha512-PHyM+sQouu7xspQQwELlGwwd05mXUFqwFYfqPO0cC7x4fxyHnnuetmQr6CjJiafIDoH4MogHb9dOoJzR/Y4rFg==
-
 xtend@^4.0.0, xtend@~4.0.0, xtend@~4.0.1:
   version "4.0.1"
   resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
   integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68=
 
-y18n@^3.2.1:
-  version "3.2.1"
-  resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41"
-  integrity sha1-bRX7qITAhnnA136I53WegR4H+kE=
-
 "y18n@^3.2.1 || ^4.0.0", y18n@^4.0.0:
   version "4.0.0"
   resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b"
@@ -13814,13 +14059,6 @@ yallist@^4.0.0:
   resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
   integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
 
-yargs-parser@^10.1.0:
-  version "10.1.0"
-  resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-10.1.0.tgz#7202265b89f7e9e9f2e5765e0fe735a905edbaa8"
-  integrity sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==
-  dependencies:
-    camelcase "^4.1.0"
-
 yargs-parser@^11.1.1:
   version "11.1.1"
   resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-11.1.1.tgz#879a0865973bca9f6bab5cbdf3b1c67ec7d3bcf4"
@@ -13829,7 +14067,7 @@ yargs-parser@^11.1.1:
     camelcase "^5.0.0"
     decamelize "^1.2.0"
 
-yargs-parser@^13.1.0, yargs-parser@^13.1.1:
+yargs-parser@^13.0.0, yargs-parser@^13.1.0, yargs-parser@^13.1.1:
   version "13.1.1"
   resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.1.tgz#d26058532aa06d365fe091f6a1fc06b2f7e5eca0"
   integrity sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==
@@ -13837,27 +14075,13 @@ yargs-parser@^13.1.0, yargs-parser@^13.1.1:
     camelcase "^5.0.0"
     decamelize "^1.2.0"
 
-yargs-parser@^5.0.0:
-  version "5.0.0"
-  resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-5.0.0.tgz#275ecf0d7ffe05c77e64e7c86e4cd94bf0e1228a"
-  integrity sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo=
-  dependencies:
-    camelcase "^3.0.0"
-
-yargs-parser@^7.0.0:
-  version "7.0.0"
-  resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-7.0.0.tgz#8d0ac42f16ea55debd332caf4c4038b3e3f5dfd9"
-  integrity sha1-jQrELxbqVd69MyyvTEA4s+P139k=
-  dependencies:
-    camelcase "^4.1.0"
-
-yargs@12.0.2:
-  version "12.0.2"
-  resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.2.tgz#fe58234369392af33ecbef53819171eff0f5aadc"
-  integrity sha512-e7SkEx6N6SIZ5c5H22RTZae61qtn3PYUE8JYbBFlK9sYmh3DMQ6E5ygtaG/2BW0JZi4WGgTR2IV5ChqlqrDGVQ==
+yargs@12.0.5, yargs@^12.0.1:
+  version "12.0.5"
+  resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.5.tgz#05f5997b609647b64f66b81e3b4b10a368e7ad13"
+  integrity sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==
   dependencies:
     cliui "^4.0.0"
-    decamelize "^2.0.0"
+    decamelize "^1.2.0"
     find-up "^3.0.0"
     get-caller-file "^1.0.1"
     os-locale "^3.0.0"
@@ -13867,25 +14091,24 @@ yargs@12.0.2:
     string-width "^2.0.0"
     which-module "^2.0.0"
     y18n "^3.2.1 || ^4.0.0"
-    yargs-parser "^10.1.0"
+    yargs-parser "^11.1.1"
 
-yargs@12.0.5, yargs@^12.0.1:
-  version "12.0.5"
-  resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.5.tgz#05f5997b609647b64f66b81e3b4b10a368e7ad13"
-  integrity sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==
+yargs@13.1.0:
+  version "13.1.0"
+  resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.1.0.tgz#b2729ce4bfc0c584939719514099d8a916ad2301"
+  integrity sha512-1UhJbXfzHiPqkfXNHYhiz79qM/kZqjTE8yGlEjZa85Q+3+OwcV6NRkV7XOV1W2Eom2bzILeUn55pQYffjVOLAg==
   dependencies:
     cliui "^4.0.0"
-    decamelize "^1.2.0"
     find-up "^3.0.0"
-    get-caller-file "^1.0.1"
-    os-locale "^3.0.0"
+    get-caller-file "^2.0.1"
+    os-locale "^3.1.0"
     require-directory "^2.1.1"
-    require-main-filename "^1.0.1"
+    require-main-filename "^2.0.0"
     set-blocking "^2.0.0"
-    string-width "^2.0.0"
+    string-width "^3.0.0"
     which-module "^2.0.0"
-    y18n "^3.2.1 || ^4.0.0"
-    yargs-parser "^11.1.1"
+    y18n "^4.0.0"
+    yargs-parser "^13.0.0"
 
 yargs@13.2.4:
   version "13.2.4"
@@ -13904,25 +14127,6 @@ yargs@13.2.4:
     y18n "^4.0.0"
     yargs-parser "^13.1.0"
 
-yargs@9.0.1:
-  version "9.0.1"
-  resolved "https://registry.yarnpkg.com/yargs/-/yargs-9.0.1.tgz#52acc23feecac34042078ee78c0c007f5085db4c"
-  integrity sha1-UqzCP+7Kw0BCB47njAwAf1CF20w=
-  dependencies:
-    camelcase "^4.1.0"
-    cliui "^3.2.0"
-    decamelize "^1.1.1"
-    get-caller-file "^1.0.1"
-    os-locale "^2.0.0"
-    read-pkg-up "^2.0.0"
-    require-directory "^2.1.1"
-    require-main-filename "^1.0.1"
-    set-blocking "^2.0.0"
-    string-width "^2.0.0"
-    which-module "^2.0.0"
-    y18n "^3.2.1"
-    yargs-parser "^7.0.0"
-
 yargs@^13.2.4:
   version "13.3.0"
   resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.0.tgz#4c657a55e07e5f2cf947f8a366567c04a0dedc83"
@@ -13939,25 +14143,6 @@ yargs@^13.2.4:
     y18n "^4.0.0"
     yargs-parser "^13.1.1"
 
-yargs@^7.0.0:
-  version "7.1.0"
-  resolved "https://registry.yarnpkg.com/yargs/-/yargs-7.1.0.tgz#6ba318eb16961727f5d284f8ea003e8d6154d0c8"
-  integrity sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=
-  dependencies:
-    camelcase "^3.0.0"
-    cliui "^3.2.0"
-    decamelize "^1.1.1"
-    get-caller-file "^1.0.1"
-    os-locale "^1.4.0"
-    read-pkg-up "^1.0.1"
-    require-directory "^2.1.1"
-    require-main-filename "^1.0.1"
-    set-blocking "^2.0.0"
-    string-width "^1.0.2"
-    which-module "^1.0.0"
-    y18n "^3.2.1"
-    yargs-parser "^5.0.0"
-
 yauzl@2.4.1:
   version "2.4.1"
   resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.4.1.tgz#9528f442dab1b2284e58b4379bb194e22e0c4005"
@@ -13984,7 +14169,7 @@ zip-stream@^2.1.2:
     compress-commons "^2.1.1"
     readable-stream "^3.4.0"
 
-zone.js@^0.8.29:
-  version "0.8.29"
-  resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.8.29.tgz#8dce92aa0dd553b50bc5bfbb90af9986ad845a12"
-  integrity sha512-mla2acNCMkWXBD+c+yeUrBUrzOxYMNFdQ6FGfigGGtEVBPJx07BQeJekjt9DmH1FtZek4E9rE1eRR9qQpxACOQ==
+zone.js@^0.9.1:
+  version "0.9.1"
+  resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.9.1.tgz#e37c6e5c54c13fae4de26b5ffe8d8e9212da6d9b"
+  integrity sha512-GkPiJL8jifSrKReKaTZ5jkhrMEgXbXYC+IPo1iquBjayRa0q86w3Dipjn8b415jpitMExe9lV8iTsv8tk3DGag==