diff --git a/.gitignore b/.gitignore
index 1f84d74fa6c7792dccc281707ac555755aaac259..0261a90deccd65899998610b512a0de5128f65b0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,6 +17,7 @@
 .settings/
 *.sublime-workspace
 
+
 # IDE - VSCode
 .vscode/*
 !.vscode/settings.json
@@ -41,3 +42,4 @@ Thumbs.db
 
 src/environments/environment.ts
 .gitignore
+
diff --git a/README.md b/README.md
index 5cffeb7bfc8192bdf63ebcd2f263402cb6b0b73b..0741b6fcdaed73fe7037d31fbd0154d59cbc8134 100644
--- a/README.md
+++ b/README.md
@@ -1,9 +1,3 @@
 # IQB Testcenter
 
 Diese Angular-Programmierung ist die clientseitige Web-Anwendung für das Online-Testen des IQB. Über diesen Weg wird die Programmierung allen Interessierten zur Verfügung gestellt. Eine Anleitung zum Installieren und Konfigurieren wird schrittweise an dieser Stelle folgen.
-
-# Testing
-
-The following technology is / will be used in the development of this project:
-
-![Browserstack logo](https://ocba2.iqb.hu-berlin.de/browserstack/logo-smaller.png)
diff --git a/browserslist b/browserslist
new file mode 100644
index 0000000000000000000000000000000000000000..80848532e47d58cc7a4b618f600b438960f9f045
--- /dev/null
+++ b/browserslist
@@ -0,0 +1,12 @@
+# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
+# For additional information regarding the format and rule options, please see:
+# https://github.com/browserslist/browserslist#queries
+
+# You can see what browsers were selected by your queries by running:
+#   npx browserslist
+
+> 0.5%
+last 2 versions
+Firefox ESR
+not dead
+not IE 9-11 # For IE 9-11 support, remove 'not'.
\ No newline at end of file
diff --git a/e2e/src/app.e2e-spec.ts.ADMIN b/e2e/src/app.e2e-spec.ts.ADMIN
new file mode 100644
index 0000000000000000000000000000000000000000..ec39f304e42ab70fc2f1ff05a9e565a7dfe54cfa
--- /dev/null
+++ b/e2e/src/app.e2e-spec.ts.ADMIN
@@ -0,0 +1,14 @@
+import { AppPage } from './app.po';
+
+describe('workspace-project App', () => {
+  let page: AppPage;
+
+  beforeEach(() => {
+    page = new AppPage();
+  });
+
+  it('should display welcome message', () => {
+    page.navigateTo();
+    expect(page.getParagraphText()).toEqual('Welcome to itc-ng-admin!');
+  });
+});
diff --git a/e2e/src/app.e2e-spec.ts b/e2e/src/app.e2e-spec.ts.TC
similarity index 100%
rename from e2e/src/app.e2e-spec.ts
rename to e2e/src/app.e2e-spec.ts.TC
diff --git a/package-lock.json b/package-lock.json
index e41c1dbff816cd0112c294e538f3d8a51d674c45..b665eda4a42200929444dece64844ac4db0ac7c1 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
 {
   "name": "itc-ng",
-  "version": "1.5.3",
+  "version": "2.0.0-alpha",
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
@@ -12,6 +12,17 @@
       "requires": {
         "@angular-devkit/core": "8.3.25",
         "rxjs": "6.4.0"
+      },
+      "dependencies": {
+        "rxjs": {
+          "version": "6.4.0",
+          "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz",
+          "integrity": "sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw==",
+          "dev": true,
+          "requires": {
+            "tslib": "^1.9.0"
+          }
+        }
       }
     },
     "@angular-devkit/build-angular": {
@@ -78,37 +89,20 @@
         "worker-plugin": "3.2.0"
       },
       "dependencies": {
-        "caniuse-lite": {
-          "version": "1.0.30001024",
-          "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001024.tgz",
-          "integrity": "sha512-LubRSEPpOlKlhZw9wGlLHo8ZVj6ugGU3xGUfLPneNBledSd9lIM5cCGZ9Mz/mMCJUhEt4jZpYteZNVRdJw5FRA==",
-          "dev": true
-        },
-        "core-js": {
-          "version": "3.6.4",
-          "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.6.4.tgz",
-          "integrity": "sha512-4paDGScNgZP2IXXilaffL9X7968RuvwlkK3xWtZRVqgd8SYNiVKRJvkFd1aqqEuPfN7E68ZHEp9hDj6lHj4Hyw==",
-          "dev": true
-        },
-        "glob": {
-          "version": "7.1.4",
-          "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz",
-          "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==",
-          "dev": true,
-          "requires": {
-            "fs.realpath": "^1.0.0",
-            "inflight": "^1.0.4",
-            "inherits": "2",
-            "minimatch": "^3.0.4",
-            "once": "^1.3.0",
-            "path-is-absolute": "^1.0.0"
-          }
-        },
         "parse5": {
           "version": "4.0.0",
           "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz",
           "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==",
           "dev": true
+        },
+        "rxjs": {
+          "version": "6.4.0",
+          "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz",
+          "integrity": "sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw==",
+          "dev": true,
+          "requires": {
+            "tslib": "^1.9.0"
+          }
         }
       }
     },
@@ -130,12 +124,6 @@
           "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz",
           "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==",
           "dev": true
-        },
-        "typescript": {
-          "version": "3.5.3",
-          "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.5.3.tgz",
-          "integrity": "sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==",
-          "dev": true
         }
       }
     },
@@ -148,6 +136,17 @@
         "@angular-devkit/architect": "0.803.25",
         "@angular-devkit/core": "8.3.25",
         "rxjs": "6.4.0"
+      },
+      "dependencies": {
+        "rxjs": {
+          "version": "6.4.0",
+          "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz",
+          "integrity": "sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw==",
+          "dev": true,
+          "requires": {
+            "tslib": "^1.9.0"
+          }
+        }
       }
     },
     "@angular-devkit/core": {
@@ -161,6 +160,17 @@
         "magic-string": "0.25.3",
         "rxjs": "6.4.0",
         "source-map": "0.7.3"
+      },
+      "dependencies": {
+        "rxjs": {
+          "version": "6.4.0",
+          "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz",
+          "integrity": "sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw==",
+          "dev": true,
+          "requires": {
+            "tslib": "^1.9.0"
+          }
+        }
       }
     },
     "@angular-devkit/schematics": {
@@ -171,6 +181,17 @@
       "requires": {
         "@angular-devkit/core": "8.3.25",
         "rxjs": "6.4.0"
+      },
+      "dependencies": {
+        "rxjs": {
+          "version": "6.4.0",
+          "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz",
+          "integrity": "sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw==",
+          "dev": true,
+          "requires": {
+            "tslib": "^1.9.0"
+          }
+        }
       }
     },
     "@angular/animations": {
@@ -182,9 +203,9 @@
       }
     },
     "@angular/cdk": {
-      "version": "8.0.2",
-      "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-8.0.2.tgz",
-      "integrity": "sha512-Tv9M0vuTp7Ogk7mRiEpzBG9x5289FXe+WH0VKqN4zTzF/taTgGEuJBLDcFrwQMW0mFpGP7acVOiopgH+nClytg==",
+      "version": "8.2.3",
+      "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-8.2.3.tgz",
+      "integrity": "sha512-ZwO5Sn720RA2YvBqud0JAHkZXjmjxM0yNzCO8RVtRE9i8Gl26Wk0j0nQeJkVm4zwv2QO8MwbKUKGTMt8evsokA==",
       "requires": {
         "parse5": "^5.0.0",
         "tslib": "^1.7.1"
@@ -224,21 +245,6 @@
           "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==",
           "dev": true
         },
-        "debug": {
-          "version": "4.1.1",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
-          "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
-          "dev": true,
-          "requires": {
-            "ms": "^2.1.1"
-          }
-        },
-        "ms": {
-          "version": "2.1.2",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-          "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
-          "dev": true
-        },
         "rimraf": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.0.tgz",
@@ -973,12 +979,6 @@
             "is-buffer": "^1.1.5"
           }
         },
-        "minimist": {
-          "version": "1.2.0",
-          "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
-          "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
-          "dev": true
-        },
         "readdirp": {
           "version": "2.2.1",
           "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz",
@@ -1052,9 +1052,9 @@
           }
         },
         "yargs-parser": {
-          "version": "13.1.1",
-          "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz",
-          "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==",
+          "version": "13.1.2",
+          "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz",
+          "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==",
           "dev": true,
           "requires": {
             "camelcase": "^5.0.0",
@@ -1094,9 +1094,9 @@
       "dev": true
     },
     "@angular/material": {
-      "version": "8.0.2",
-      "resolved": "https://registry.npmjs.org/@angular/material/-/material-8.0.2.tgz",
-      "integrity": "sha512-Q6YxX7zLsfI1kv0dSJSENSyCuwq7GdHjHzOGeogGfjQRvX3N/ty/z8YfwhQFzZ3XtIysbhuGcpAUWazgWeIKgw==",
+      "version": "8.2.3",
+      "resolved": "https://registry.npmjs.org/@angular/material/-/material-8.2.3.tgz",
+      "integrity": "sha512-SOczkIaqes+r+9XF/UUiokidfFKBpHkOPIaFK857sFD0FBNPvPEpOr5oHKCG3feERRwAFqHS7Wo2ohVEWypb5A==",
       "requires": {
         "tslib": "^1.7.1"
       }
@@ -1135,9 +1135,9 @@
       }
     },
     "@babel/compat-data": {
-      "version": "7.8.5",
-      "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.8.5.tgz",
-      "integrity": "sha512-jWYUqQX/ObOhG1UiEkbH5SANsE/8oKXiQWjj7p7xgj9Zmnt//aUvyz4dBkK0HNsS8/cbyC5NmmH87VekW+mXFg==",
+      "version": "7.8.6",
+      "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.8.6.tgz",
+      "integrity": "sha512-CurCIKPTkS25Mb8mz267vU95vy+TyUpnctEX2lV33xWNmHAfjruztgiPBbXZRh3xZZy1CYvGx6XfxyTVS+sk7Q==",
       "dev": true,
       "requires": {
         "browserslist": "^4.8.5",
@@ -1176,36 +1176,15 @@
         "source-map": "^0.5.0"
       },
       "dependencies": {
-        "debug": {
-          "version": "4.1.1",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
-          "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
-          "dev": true,
-          "requires": {
-            "ms": "^2.1.1"
-          }
-        },
         "json5": {
-          "version": "2.1.1",
-          "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.1.tgz",
-          "integrity": "sha512-l+3HXD0GEI3huGq1njuqtzYK8OYJyXMkOLtQ53pjWh89tvWS2h6l+1zMkYWqlb57+SiQodKZyvMEFb2X+KrFhQ==",
+          "version": "2.1.2",
+          "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.2.tgz",
+          "integrity": "sha512-MoUOQ4WdiN3yxhm7NEVJSJrieAo5hNSLQ5sj05OTRHPL9HOBy8u4Bu88jsC1jvqAdN+E1bJmsUcZH+1HQxliqQ==",
           "dev": true,
           "requires": {
-            "minimist": "^1.2.0"
+            "minimist": "^1.2.5"
           }
         },
-        "minimist": {
-          "version": "1.2.0",
-          "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
-          "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
-          "dev": true
-        },
-        "ms": {
-          "version": "2.1.2",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-          "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
-          "dev": true
-        },
         "semver": {
           "version": "5.7.1",
           "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
@@ -1221,12 +1200,12 @@
       }
     },
     "@babel/generator": {
-      "version": "7.8.3",
-      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.8.3.tgz",
-      "integrity": "sha512-WjoPk8hRpDRqqzRpvaR8/gDUPkrnOOeuT2m8cNICJtZH6mwaCo3v0OKMI7Y6SM1pBtyijnLtAL0HDi41pf41ug==",
+      "version": "7.8.8",
+      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.8.8.tgz",
+      "integrity": "sha512-HKyUVu69cZoclptr8t8U5b6sx6zoWjh8jiUhnuj3MpZuKT2dJ8zPTuiy31luq32swhI0SpwItCIlU8XW7BZeJg==",
       "dev": true,
       "requires": {
-        "@babel/types": "^7.8.3",
+        "@babel/types": "^7.8.7",
         "jsesc": "^2.5.1",
         "lodash": "^4.17.13",
         "source-map": "^0.5.0"
@@ -1260,29 +1239,46 @@
       }
     },
     "@babel/helper-call-delegate": {
-      "version": "7.8.3",
-      "resolved": "https://registry.npmjs.org/@babel/helper-call-delegate/-/helper-call-delegate-7.8.3.tgz",
-      "integrity": "sha512-6Q05px0Eb+N4/GTyKPPvnkig7Lylw+QzihMpws9iiZQv7ZImf84ZsZpQH7QoWN4n4tm81SnSzPgHw2qtO0Zf3A==",
+      "version": "7.8.7",
+      "resolved": "https://registry.npmjs.org/@babel/helper-call-delegate/-/helper-call-delegate-7.8.7.tgz",
+      "integrity": "sha512-doAA5LAKhsFCR0LAFIf+r2RSMmC+m8f/oQ+URnUET/rWeEzC0yTRmAGyWkD4sSu3xwbS7MYQ2u+xlt1V5R56KQ==",
       "dev": true,
       "requires": {
         "@babel/helper-hoist-variables": "^7.8.3",
         "@babel/traverse": "^7.8.3",
-        "@babel/types": "^7.8.3"
+        "@babel/types": "^7.8.7"
       }
     },
     "@babel/helper-compilation-targets": {
-      "version": "7.8.4",
-      "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.8.4.tgz",
-      "integrity": "sha512-3k3BsKMvPp5bjxgMdrFyq0UaEO48HciVrOVF0+lon8pp95cyJ2ujAh0TrBHNMnJGT2rr0iKOJPFFbSqjDyf/Pg==",
+      "version": "7.8.7",
+      "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.8.7.tgz",
+      "integrity": "sha512-4mWm8DCK2LugIS+p1yArqvG1Pf162upsIsjE7cNBjez+NjliQpVhj20obE520nao0o14DaTnFJv+Fw5a0JpoUw==",
       "dev": true,
       "requires": {
-        "@babel/compat-data": "^7.8.4",
-        "browserslist": "^4.8.5",
+        "@babel/compat-data": "^7.8.6",
+        "browserslist": "^4.9.1",
         "invariant": "^2.2.4",
         "levenary": "^1.1.1",
         "semver": "^5.5.0"
       },
       "dependencies": {
+        "browserslist": {
+          "version": "4.9.1",
+          "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.9.1.tgz",
+          "integrity": "sha512-Q0DnKq20End3raFulq6Vfp1ecB9fh8yUNV55s8sekaDDeqBaCtWlRHCUdaWyUeSSBJM7IbM6HcsyaeYqgeDhnw==",
+          "dev": true,
+          "requires": {
+            "caniuse-lite": "^1.0.30001030",
+            "electron-to-chromium": "^1.3.363",
+            "node-releases": "^1.1.50"
+          }
+        },
+        "caniuse-lite": {
+          "version": "1.0.30001035",
+          "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001035.tgz",
+          "integrity": "sha512-C1ZxgkuA4/bUEdMbU5WrGY4+UhMFFiXrgNAfxiMIqWgFTWfv/xsZCS2xEHT2LMq7xAZfuAnu6mcqyDl0ZR6wLQ==",
+          "dev": true
+        },
         "semver": {
           "version": "5.7.1",
           "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
@@ -1292,13 +1288,14 @@
       }
     },
     "@babel/helper-create-regexp-features-plugin": {
-      "version": "7.8.3",
-      "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.8.3.tgz",
-      "integrity": "sha512-Gcsm1OHCUr9o9TcJln57xhWHtdXbA2pgQ58S0Lxlks0WMGNXuki4+GLfX0p+L2ZkINUGZvfkz8rzoqJQSthI+Q==",
+      "version": "7.8.8",
+      "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.8.8.tgz",
+      "integrity": "sha512-LYVPdwkrQEiX9+1R29Ld/wTrmQu1SSKYnuOk3g0CkcZMA1p0gsNxJFj/3gBdaJ7Cg0Fnek5z0DsMULePP7Lrqg==",
       "dev": true,
       "requires": {
+        "@babel/helper-annotate-as-pure": "^7.8.3",
         "@babel/helper-regex": "^7.8.3",
-        "regexpu-core": "^4.6.0"
+        "regexpu-core": "^4.7.0"
       }
     },
     "@babel/helper-define-map": {
@@ -1370,16 +1367,17 @@
       }
     },
     "@babel/helper-module-transforms": {
-      "version": "7.8.3",
-      "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.8.3.tgz",
-      "integrity": "sha512-C7NG6B7vfBa/pwCOshpMbOYUmrYQDfCpVL/JCRu0ek8B5p8kue1+BCXpg2vOYs7w5ACB9GTOBYQ5U6NwrMg+3Q==",
+      "version": "7.8.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.8.6.tgz",
+      "integrity": "sha512-RDnGJSR5EFBJjG3deY0NiL0K9TO8SXxS9n/MPsbPK/s9LbQymuLNtlzvDiNS7IpecuL45cMeLVkA+HfmlrnkRg==",
       "dev": true,
       "requires": {
         "@babel/helper-module-imports": "^7.8.3",
+        "@babel/helper-replace-supers": "^7.8.6",
         "@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",
+        "@babel/template": "^7.8.6",
+        "@babel/types": "^7.8.6",
         "lodash": "^4.17.13"
       }
     },
@@ -1421,15 +1419,15 @@
       }
     },
     "@babel/helper-replace-supers": {
-      "version": "7.8.3",
-      "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.8.3.tgz",
-      "integrity": "sha512-xOUssL6ho41U81etpLoT2RTdvdus4VfHamCuAm4AHxGr+0it5fnwoVdwUJ7GFEqCsQYzJUhcbsN9wB9apcYKFA==",
+      "version": "7.8.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.8.6.tgz",
+      "integrity": "sha512-PeMArdA4Sv/Wf4zXwBKPqVj7n9UF/xg6slNRtZW84FM7JpE1CbG8B612FyM4cxrf4fMAMGO0kR7voy1ForHHFA==",
       "dev": true,
       "requires": {
         "@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/traverse": "^7.8.6",
+        "@babel/types": "^7.8.6"
       }
     },
     "@babel/helper-simple-access": {
@@ -1472,64 +1470,6 @@
         "@babel/template": "^7.8.3",
         "@babel/traverse": "^7.8.4",
         "@babel/types": "^7.8.3"
-      },
-      "dependencies": {
-        "@babel/generator": {
-          "version": "7.8.4",
-          "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.8.4.tgz",
-          "integrity": "sha512-PwhclGdRpNAf3IxZb0YVuITPZmmrXz9zf6fH8lT4XbrmfQKr6ryBzhv593P5C6poJRciFCL/eHGW2NuGrgEyxA==",
-          "dev": true,
-          "requires": {
-            "@babel/types": "^7.8.3",
-            "jsesc": "^2.5.1",
-            "lodash": "^4.17.13",
-            "source-map": "^0.5.0"
-          }
-        },
-        "@babel/parser": {
-          "version": "7.8.4",
-          "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.4.tgz",
-          "integrity": "sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw==",
-          "dev": true
-        },
-        "@babel/traverse": {
-          "version": "7.8.4",
-          "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.8.4.tgz",
-          "integrity": "sha512-NGLJPZwnVEyBPLI+bl9y9aSnxMhsKz42so7ApAv9D+b4vAFPpY013FTS9LdKxcABoIYFU52HcYga1pPlx454mg==",
-          "dev": true,
-          "requires": {
-            "@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"
-          }
-        },
-        "debug": {
-          "version": "4.1.1",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
-          "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
-          "dev": true,
-          "requires": {
-            "ms": "^2.1.1"
-          }
-        },
-        "ms": {
-          "version": "2.1.2",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-          "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
-          "dev": true
-        },
-        "source-map": {
-          "version": "0.5.7",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
-          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
-          "dev": true
-        }
       }
     },
     "@babel/highlight": {
@@ -1544,9 +1484,9 @@
       }
     },
     "@babel/parser": {
-      "version": "7.8.3",
-      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.3.tgz",
-      "integrity": "sha512-/V72F4Yp/qmHaTALizEm9Gf2eQHV3QyTL3K0cNfijwnMnb1L+LDlAubb/ZnSdGAVzVSWakujHYs1I26x66sMeQ==",
+      "version": "7.8.8",
+      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.8.tgz",
+      "integrity": "sha512-mO5GWzBPsPf6865iIbzNE0AvkKF3NE+2S3eRUpE+FE07BOAkXh6G+GW/Pj01hhXjve1WScbaIO4UlY1JKeqCcA==",
       "dev": true
     },
     "@babel/plugin-proposal-async-generator-functions": {
@@ -1621,12 +1561,12 @@
       }
     },
     "@babel/plugin-proposal-unicode-property-regex": {
-      "version": "7.8.3",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.8.3.tgz",
-      "integrity": "sha512-1/1/rEZv2XGweRwwSkLpY+s60za9OZ1hJs4YDqFHCw0kYWYwL5IFljVY1MYBL+weT1l9pokDO2uhSTLVxzoHkQ==",
+      "version": "7.8.8",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.8.8.tgz",
+      "integrity": "sha512-EVhjVsMpbhLw9ZfHWSx2iy13Q8Z/eg8e8ccVWt23sWQK5l1UdkoLJPN5w69UA4uITGBnEZD2JOe4QOHycYKv8A==",
       "dev": true,
       "requires": {
-        "@babel/helper-create-regexp-features-plugin": "^7.8.3",
+        "@babel/helper-create-regexp-features-plugin": "^7.8.8",
         "@babel/helper-plugin-utils": "^7.8.3"
       }
     },
@@ -1742,9 +1682,9 @@
       }
     },
     "@babel/plugin-transform-classes": {
-      "version": "7.8.3",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.8.3.tgz",
-      "integrity": "sha512-SjT0cwFJ+7Rbr1vQsvphAHwUHvSUPmMjMU/0P59G8U2HLFqSa082JO7zkbDNWs9kH/IUqpHI6xWNesGf8haF1w==",
+      "version": "7.8.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.8.6.tgz",
+      "integrity": "sha512-k9r8qRay/R6v5aWZkrEclEhKO6mc1CCQr2dLsVHBmOQiMpN6I2bpjX3vgnldUWeEI1GHVNByULVxZ4BdP4Hmdg==",
       "dev": true,
       "requires": {
         "@babel/helper-annotate-as-pure": "^7.8.3",
@@ -1752,7 +1692,7 @@
         "@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-replace-supers": "^7.8.6",
         "@babel/helper-split-export-declaration": "^7.8.3",
         "globals": "^11.1.0"
       }
@@ -1767,9 +1707,9 @@
       }
     },
     "@babel/plugin-transform-destructuring": {
-      "version": "7.8.3",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.8.3.tgz",
-      "integrity": "sha512-H4X646nCkiEcHZUZaRkhE2XVsoz0J/1x3VVujnn96pSoGCtKPA99ZZA+va+gK+92Zycd6OBKCD8tDb/731bhgQ==",
+      "version": "7.8.8",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.8.8.tgz",
+      "integrity": "sha512-eRJu4Vs2rmttFCdhPUM3bV0Yo/xPSdPw6ML9KHs/bjB4bLA5HXlbvYXPOD5yASodGod+krjYx21xm1QmL8dCJQ==",
       "dev": true,
       "requires": {
         "@babel/helper-plugin-utils": "^7.8.3"
@@ -1805,9 +1745,9 @@
       }
     },
     "@babel/plugin-transform-for-of": {
-      "version": "7.8.4",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.8.4.tgz",
-      "integrity": "sha512-iAXNlOWvcYUYoV8YIxwS7TxGRJcxyl8eQCfT+A5j8sKUzRFvJdcyjp97jL2IghWSRDaL2PU2O2tX8Cu9dTBq5A==",
+      "version": "7.8.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.8.6.tgz",
+      "integrity": "sha512-M0pw4/1/KI5WAxPsdcUL/w2LJ7o89YHN3yLkzNjg7Yl15GlVGgzHyCU+FMeAxevHGsLVmUqbirlUIKTafPmzdw==",
       "dev": true,
       "requires": {
         "@babel/helper-plugin-utils": "^7.8.3"
@@ -1915,12 +1855,12 @@
       }
     },
     "@babel/plugin-transform-parameters": {
-      "version": "7.8.4",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.8.4.tgz",
-      "integrity": "sha512-IsS3oTxeTsZlE5KqzTbcC2sV0P9pXdec53SU+Yxv7o/6dvGM5AkTotQKhoSffhNgZ/dftsSiOoxy7evCYJXzVA==",
+      "version": "7.8.8",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.8.8.tgz",
+      "integrity": "sha512-hC4Ld/Ulpf1psQciWWwdnUspQoQco2bMzSrwU6TmzRlvoYQe4rQFy9vnCZDTlVeCQj0JPfL+1RX0V8hCJvkgBA==",
       "dev": true,
       "requires": {
-        "@babel/helper-call-delegate": "^7.8.3",
+        "@babel/helper-call-delegate": "^7.8.7",
         "@babel/helper-get-function-arity": "^7.8.3",
         "@babel/helper-plugin-utils": "^7.8.3"
       }
@@ -1935,12 +1875,12 @@
       }
     },
     "@babel/plugin-transform-regenerator": {
-      "version": "7.8.3",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.8.3.tgz",
-      "integrity": "sha512-qt/kcur/FxrQrzFR432FGZznkVAjiyFtCOANjkAKwCbt465L6ZCiUQh2oMYGU3Wo8LRFJxNDFwWn106S5wVUNA==",
+      "version": "7.8.7",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.8.7.tgz",
+      "integrity": "sha512-TIg+gAl4Z0a3WmD3mbYSk+J9ZUH6n/Yc57rtKRnlA/7rcCvpekHXe0CMZHP1gYp7/KLe9GHTuIba0vXmls6drA==",
       "dev": true,
       "requires": {
-        "regenerator-transform": "^0.14.0"
+        "regenerator-transform": "^0.14.2"
       }
     },
     "@babel/plugin-transform-reserved-words": {
@@ -2082,55 +2022,55 @@
         }
       }
     },
+    "@babel/runtime": {
+      "version": "7.8.7",
+      "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.8.7.tgz",
+      "integrity": "sha512-+AATMUFppJDw6aiR5NVPHqIQBlV/Pj8wY/EZH+lmvRdUo9xBaz/rF3alAwFJQavvKfeOlPE7oaaDHVbcySbCsg==",
+      "dev": true,
+      "requires": {
+        "regenerator-runtime": "^0.13.4"
+      },
+      "dependencies": {
+        "regenerator-runtime": {
+          "version": "0.13.5",
+          "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz",
+          "integrity": "sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA==",
+          "dev": true
+        }
+      }
+    },
     "@babel/template": {
-      "version": "7.8.3",
-      "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz",
-      "integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==",
+      "version": "7.8.6",
+      "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.6.tgz",
+      "integrity": "sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg==",
       "dev": true,
       "requires": {
         "@babel/code-frame": "^7.8.3",
-        "@babel/parser": "^7.8.3",
-        "@babel/types": "^7.8.3"
+        "@babel/parser": "^7.8.6",
+        "@babel/types": "^7.8.6"
       }
     },
     "@babel/traverse": {
-      "version": "7.8.3",
-      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.8.3.tgz",
-      "integrity": "sha512-we+a2lti+eEImHmEXp7bM9cTxGzxPmBiVJlLVD+FuuQMeeO7RaDbutbgeheDkw+Xe3mCfJHnGOWLswT74m2IPg==",
+      "version": "7.8.6",
+      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.8.6.tgz",
+      "integrity": "sha512-2B8l0db/DPi8iinITKuo7cbPznLCEk0kCxDoB9/N6gGNg/gxOXiR/IcymAFPiBwk5w6TtQ27w4wpElgp9btR9A==",
       "dev": true,
       "requires": {
         "@babel/code-frame": "^7.8.3",
-        "@babel/generator": "^7.8.3",
+        "@babel/generator": "^7.8.6",
         "@babel/helper-function-name": "^7.8.3",
         "@babel/helper-split-export-declaration": "^7.8.3",
-        "@babel/parser": "^7.8.3",
-        "@babel/types": "^7.8.3",
+        "@babel/parser": "^7.8.6",
+        "@babel/types": "^7.8.6",
         "debug": "^4.1.0",
         "globals": "^11.1.0",
         "lodash": "^4.17.13"
-      },
-      "dependencies": {
-        "debug": {
-          "version": "4.1.1",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
-          "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
-          "dev": true,
-          "requires": {
-            "ms": "^2.1.1"
-          }
-        },
-        "ms": {
-          "version": "2.1.2",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-          "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
-          "dev": true
-        }
       }
     },
     "@babel/types": {
-      "version": "7.8.3",
-      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz",
-      "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==",
+      "version": "7.8.7",
+      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.7.tgz",
+      "integrity": "sha512-k2TreEHxFA4CjGkL+GYjRyx35W0Mr7DP5+9q6WMkyKXB+904bYmG40syjMFV0oLlhhFCwWl0vA0DyzTDkwAiJw==",
       "dev": true,
       "requires": {
         "esutils": "^2.0.2",
@@ -2155,6 +2095,17 @@
         "rxjs": "6.4.0",
         "tree-kill": "1.2.2",
         "webpack-sources": "1.4.3"
+      },
+      "dependencies": {
+        "rxjs": {
+          "version": "6.4.0",
+          "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz",
+          "integrity": "sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw==",
+          "dev": true,
+          "requires": {
+            "tslib": "^1.9.0"
+          }
+        }
       }
     },
     "@schematics/angular": {
@@ -2181,22 +2132,35 @@
         "rxjs": "6.4.0",
         "semver": "6.3.0",
         "semver-intersect": "1.4.0"
+      },
+      "dependencies": {
+        "rxjs": {
+          "version": "6.4.0",
+          "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz",
+          "integrity": "sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw==",
+          "dev": true,
+          "requires": {
+            "tslib": "^1.9.0"
+          }
+        }
       }
     },
-    "@testim/chrome-version": {
-      "version": "1.0.7",
-      "resolved": "https://registry.npmjs.org/@testim/chrome-version/-/chrome-version-1.0.7.tgz",
-      "integrity": "sha512-8UT/J+xqCYfn3fKtOznAibsHpiuDshCb0fwgWxRazTT19Igp9ovoXMPhXyLD6m3CKQGTMHgqoxaFfMWaL40Rnw=="
-    },
     "@types/events": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz",
-      "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g=="
+      "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==",
+      "dev": true
+    },
+    "@types/file-saver": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/@types/file-saver/-/file-saver-2.0.1.tgz",
+      "integrity": "sha512-g1QUuhYVVAamfCifK7oB7G3aIl4BbOyzDOqVyUfEr4tfBKrXfeH+M+Tg7HKCXSrbzxYdhyCP7z9WbKo0R2hBCw=="
     },
     "@types/glob": {
       "version": "7.1.1",
       "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz",
       "integrity": "sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==",
+      "dev": true,
       "requires": {
         "@types/events": "*",
         "@types/minimatch": "*",
@@ -2204,9 +2168,9 @@
       }
     },
     "@types/jasmine": {
-      "version": "2.8.16",
-      "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-2.8.16.tgz",
-      "integrity": "sha512-056oRlBBp7MDzr+HoU5su099s/s7wjZ3KcHxLfv+Byqb9MwdLUvsfLgw1VS97hsh3ddxSPyQu+olHMnoVTUY6g==",
+      "version": "3.5.9",
+      "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-3.5.9.tgz",
+      "integrity": "sha512-KNL2Fq6GRmty2j6+ZmueT/Z/dkctLNH+5DFoGHNDtcgt7yME9NZd8x2p81Yuea1Xux/qAryDd3zVLUoKpDz1TA==",
       "dev": true
     },
     "@types/jasminewd2": {
@@ -2221,12 +2185,14 @@
     "@types/minimatch": {
       "version": "3.0.3",
       "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz",
-      "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA=="
+      "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==",
+      "dev": true
     },
     "@types/node": {
-      "version": "8.9.5",
-      "resolved": "https://registry.npmjs.org/@types/node/-/node-8.9.5.tgz",
-      "integrity": "sha512-jRHfWsvyMtXdbhnz5CVHxaBgnV6duZnPlQuRSo/dm/GnmikNcmZhxIES4E9OZjUmQ8C+HCl4KJux+cXN/ErGDQ=="
+      "version": "13.9.1",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-13.9.1.tgz",
+      "integrity": "sha512-E6M6N0blf/jiZx8Q3nb0vNaswQeEyn0XlupO+xN6DtJ6r6IT4nXrTry7zhIfYvFCl3/8Cu6WIysmUBKiqV0bqQ==",
+      "dev": true
     },
     "@types/q": {
       "version": "0.0.32",
@@ -2235,9 +2201,9 @@
       "dev": true
     },
     "@types/selenium-webdriver": {
-      "version": "3.0.16",
-      "resolved": "https://registry.npmjs.org/@types/selenium-webdriver/-/selenium-webdriver-3.0.16.tgz",
-      "integrity": "sha512-lMC2G0ItF2xv4UCiwbJGbnJlIuUixHrioOhNGHSCsYCJ8l4t9hMCUimCytvFv7qy6AfSzRxhRHoGa+UqaqwyeA==",
+      "version": "3.0.17",
+      "resolved": "https://registry.npmjs.org/@types/selenium-webdriver/-/selenium-webdriver-3.0.17.tgz",
+      "integrity": "sha512-tGomyEuzSC1H28y2zlW6XPCaDaXFaD6soTdb4GNdmte2qfHtrKqhy0ZFs4r/1hpazCfEZqeTSRLvSasmEx89uw==",
       "dev": true
     },
     "@types/source-list-map": {
@@ -2480,9 +2446,9 @@
       }
     },
     "acorn": {
-      "version": "6.4.0",
-      "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.0.tgz",
-      "integrity": "sha512-gac8OEcQ2Li1dxIEWGZzsp2BitJxwkwcOm0zHAJLcPJaVvm58FRnk6RkuLRpU1EujipU2ZFODv2P9DLMfnV8mw==",
+      "version": "6.4.1",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz",
+      "integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==",
       "dev": true
     },
     "adm-zip": {
@@ -2519,6 +2485,7 @@
       "version": "6.10.2",
       "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz",
       "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==",
+      "dev": true,
       "requires": {
         "fast-deep-equal": "^2.0.1",
         "fast-json-stable-stringify": "^2.0.0",
@@ -2551,12 +2518,12 @@
       "dev": true
     },
     "ansi-escapes": {
-      "version": "4.3.0",
-      "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.0.tgz",
-      "integrity": "sha512-EiYhwo0v255HUL6eDyuLrXEkTi7WwVCLAw+SeOQ7M7qdun1z1pum4DEm/nuqIVbPvi9RPPc9k9LbyBv6H0DwVg==",
+      "version": "4.3.1",
+      "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz",
+      "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==",
       "dev": true,
       "requires": {
-        "type-fest": "^0.8.1"
+        "type-fest": "^0.11.0"
       }
     },
     "ansi-html": {
@@ -2611,6 +2578,12 @@
       "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==",
       "dev": true
     },
+    "arg": {
+      "version": "4.1.3",
+      "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
+      "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
+      "dev": true
+    },
     "argparse": {
       "version": "1.0.10",
       "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
@@ -2658,6 +2631,7 @@
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
       "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=",
+      "dev": true,
       "requires": {
         "array-uniq": "^1.0.1"
       }
@@ -2665,7 +2639,8 @@
     "array-uniq": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz",
-      "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY="
+      "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=",
+      "dev": true
     },
     "array-unique": {
       "version": "0.3.2",
@@ -2695,6 +2670,7 @@
       "version": "0.2.4",
       "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
       "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
+      "dev": true,
       "requires": {
         "safer-buffer": "~2.1.0"
       }
@@ -2740,7 +2716,8 @@
     "assert-plus": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
-      "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
+      "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
+      "dev": true
     },
     "assign-symbols": {
       "version": "1.0.0",
@@ -2778,7 +2755,8 @@
     "asynckit": {
       "version": "0.4.0",
       "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
-      "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
+      "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
+      "dev": true
     },
     "atob": {
       "version": "2.1.2",
@@ -2804,12 +2782,14 @@
     "aws-sign2": {
       "version": "0.7.0",
       "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
-      "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg="
+      "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=",
+      "dev": true
     },
     "aws4": {
       "version": "1.9.1",
       "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.1.tgz",
-      "integrity": "sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug=="
+      "integrity": "sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug==",
+      "dev": true
     },
     "axobject-query": {
       "version": "2.0.2",
@@ -2820,50 +2800,6 @@
         "ast-types-flow": "0.0.7"
       }
     },
-    "babel-code-frame": {
-      "version": "6.26.0",
-      "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
-      "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=",
-      "dev": true,
-      "requires": {
-        "chalk": "^1.1.3",
-        "esutils": "^2.0.2",
-        "js-tokens": "^3.0.2"
-      },
-      "dependencies": {
-        "ansi-styles": {
-          "version": "2.2.1",
-          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
-          "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
-          "dev": true
-        },
-        "chalk": {
-          "version": "1.1.3",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
-          "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
-          "dev": true,
-          "requires": {
-            "ansi-styles": "^2.2.1",
-            "escape-string-regexp": "^1.0.2",
-            "has-ansi": "^2.0.0",
-            "strip-ansi": "^3.0.0",
-            "supports-color": "^2.0.0"
-          }
-        },
-        "js-tokens": {
-          "version": "3.0.2",
-          "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
-          "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=",
-          "dev": true
-        },
-        "supports-color": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
-          "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
-          "dev": true
-        }
-      }
-    },
     "babel-plugin-dynamic-import-node": {
       "version": "2.3.0",
       "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.0.tgz",
@@ -2882,7 +2818,8 @@
     "balanced-match": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
-      "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
+      "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
+      "dev": true
     },
     "base": {
       "version": "0.11.2",
@@ -2967,6 +2904,7 @@
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
       "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
+      "dev": true,
       "requires": {
         "tweetnacl": "^0.14.3"
       }
@@ -3015,14 +2953,6 @@
       "dev": true,
       "requires": {
         "minimist": "^1.2.0"
-      },
-      "dependencies": {
-        "minimist": {
-          "version": "1.2.0",
-          "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
-          "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
-          "dev": true
-        }
       }
     },
     "bluebird": {
@@ -3061,6 +2991,21 @@
           "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==",
           "dev": true
         },
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+          "dev": true,
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+          "dev": true
+        },
         "qs": {
           "version": "6.7.0",
           "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
@@ -3087,6 +3032,7 @@
       "version": "1.1.11",
       "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
       "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+      "dev": true,
       "requires": {
         "balanced-match": "^1.0.0",
         "concat-map": "0.0.1"
@@ -3182,6 +3128,7 @@
       "version": "4.8.6",
       "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.8.6.tgz",
       "integrity": "sha512-ZHao85gf0eZ0ESxLfCp73GG9O/VTytYDIkIiZDlURppLTI9wErSM/5yAKEq6rcUdxBLjMELmrYUJGg5sxGKMHg==",
+      "dev": true,
       "requires": {
         "caniuse-lite": "^1.0.30001023",
         "electron-to-chromium": "^1.3.341",
@@ -3233,7 +3180,8 @@
     "buffer-from": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
-      "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A=="
+      "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
+      "dev": true
     },
     "buffer-indexof": {
       "version": "1.1.1",
@@ -3348,9 +3296,10 @@
       "dev": true
     },
     "caniuse-lite": {
-      "version": "1.0.30001027",
-      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001027.tgz",
-      "integrity": "sha512-7xvKeErvXZFtUItTHgNtLgS9RJpVnwBlWX8jSo/BO8VsF6deszemZSkJJJA1KOKrXuzZH4WALpAJdq5EyfgMLg=="
+      "version": "1.0.30001024",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001024.tgz",
+      "integrity": "sha512-LubRSEPpOlKlhZw9wGlLHo8ZVj6ugGU3xGUfLPneNBledSd9lIM5cCGZ9Mz/mMCJUhEt4jZpYteZNVRdJw5FRA==",
+      "dev": true
     },
     "canonical-path": {
       "version": "1.0.0",
@@ -3361,7 +3310,8 @@
     "caseless": {
       "version": "0.12.0",
       "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
-      "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
+      "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=",
+      "dev": true
     },
     "chalk": {
       "version": "2.4.2",
@@ -3408,9 +3358,9 @@
       }
     },
     "chownr": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.3.tgz",
-      "integrity": "sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw==",
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
+      "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
       "dev": true
     },
     "chrome-trace-event": {
@@ -3422,19 +3372,6 @@
         "tslib": "^1.9.0"
       }
     },
-    "chromedriver": {
-      "version": "79.0.3",
-      "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-79.0.3.tgz",
-      "integrity": "sha512-XkgXrYF+M1oAT02aIIEjaM4x0oaUXTBoB+PvCNdh3rKUhn596byCc6Jy3USutZj4/0R/K+Bqf4I+4RESvfjehg==",
-      "requires": {
-        "@testim/chrome-version": "^1.0.7",
-        "del": "^4.1.1",
-        "extract-zip": "^1.6.7",
-        "mkdirp": "^0.5.1",
-        "request": "^2.88.0",
-        "tcp-port-used": "^1.0.1"
-      }
-    },
     "cipher-base": {
       "version": "1.0.4",
       "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
@@ -3474,11 +3411,6 @@
         }
       }
     },
-    "classlist.js": {
-      "version": "1.1.20150312",
-      "resolved": "https://registry.npmjs.org/classlist.js/-/classlist.js-1.1.20150312.tgz",
-      "integrity": "sha1-HXCEL3Ai8I2awIbOaeWyUPLFd4k="
-    },
     "clean-css": {
       "version": "4.2.1",
       "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.1.tgz",
@@ -3628,6 +3560,7 @@
       "version": "1.0.8",
       "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
       "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+      "dev": true,
       "requires": {
         "delayed-stream": "~1.0.0"
       }
@@ -3645,9 +3578,9 @@
       "dev": true
     },
     "compare-versions": {
-      "version": "3.5.1",
-      "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.5.1.tgz",
-      "integrity": "sha512-9fGPIB7C6AyM18CJJBHt5EnCZDG3oiTJYy0NjfIAGjKpzv0tkxWko7TNQHF5ymqm7IH03tqmeuBxtvD+Izh6mg==",
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.6.0.tgz",
+      "integrity": "sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA==",
       "dev": true
     },
     "component-bind": {
@@ -3690,17 +3623,36 @@
         "on-headers": "~1.0.2",
         "safe-buffer": "5.1.2",
         "vary": "~1.1.2"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+          "dev": true,
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+          "dev": true
+        }
       }
     },
     "concat-map": {
       "version": "0.0.1",
       "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
-      "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
+      "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
+      "dev": true
     },
     "concat-stream": {
       "version": "1.6.2",
       "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
       "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
+      "dev": true,
       "requires": {
         "buffer-from": "^1.0.0",
         "inherits": "^2.0.3",
@@ -3718,6 +3670,23 @@
         "finalhandler": "1.1.2",
         "parseurl": "~1.3.3",
         "utils-merge": "1.0.1"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+          "dev": true,
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+          "dev": true
+        }
       }
     },
     "connect-history-api-fallback": {
@@ -3851,9 +3820,9 @@
       }
     },
     "core-js": {
-      "version": "2.6.11",
-      "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz",
-      "integrity": "sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg=="
+      "version": "3.6.4",
+      "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.6.4.tgz",
+      "integrity": "sha512-4paDGScNgZP2IXXilaffL9X7968RuvwlkK3xWtZRVqgd8SYNiVKRJvkFd1aqqEuPfN7E68ZHEp9hDj6lHj4Hyw=="
     },
     "core-js-compat": {
       "version": "3.6.4",
@@ -3876,7 +3845,8 @@
     "core-util-is": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
-      "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
+      "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
+      "dev": true
     },
     "cosmiconfig": {
       "version": "5.2.1",
@@ -3903,13 +3873,31 @@
         "schema-utils": "^2.6.1"
       },
       "dependencies": {
+        "ajv": {
+          "version": "6.12.0",
+          "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.0.tgz",
+          "integrity": "sha512-D6gFiFA0RRLyUbvijN74DWAjXSFxWKaWP7mldxkVhyhAV3+SWA9HEJPHQ2c9soIeTFJqcSdFDGFgdqs1iUU2Hw==",
+          "dev": true,
+          "requires": {
+            "fast-deep-equal": "^3.1.1",
+            "fast-json-stable-stringify": "^2.0.0",
+            "json-schema-traverse": "^0.4.1",
+            "uri-js": "^4.2.2"
+          }
+        },
+        "fast-deep-equal": {
+          "version": "3.1.1",
+          "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz",
+          "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==",
+          "dev": true
+        },
         "schema-utils": {
-          "version": "2.6.4",
-          "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.6.4.tgz",
-          "integrity": "sha512-VNjcaUxVnEeun6B2fiiUDjXXBtD4ZSH7pdbfIu1pOFwgptDPLMo/z9jr4sUfsjFVPqDCEin/F7IYlq7/E6yDbQ==",
+          "version": "2.6.5",
+          "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.6.5.tgz",
+          "integrity": "sha512-5KXuwKziQrTVHh8j/Uxz+QUbxkaLW9X/86NBlx/gnKgtsZA2GIVMUn17qWhRFwF8jdYb3Dig5hRO/W5mZqy6SQ==",
           "dev": true,
           "requires": {
-            "ajv": "^6.10.2",
+            "ajv": "^6.12.0",
             "ajv-keywords": "^3.4.1"
           }
         }
@@ -3999,48 +3987,14 @@
       "dev": true
     },
     "css-selector-tokenizer": {
-      "version": "0.7.1",
-      "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.1.tgz",
-      "integrity": "sha512-xYL0AMZJ4gFzJQsHUKa5jiWWi2vH77WVNg7JYRyewwj6oPh4yb/y6Y9ZCw9dsj/9UauMhtuxR+ogQd//EdEVNA==",
+      "version": "0.7.2",
+      "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.2.tgz",
+      "integrity": "sha512-yj856NGuAymN6r8bn8/Jl46pR+OC3eEvAhfGYDUe7YPtTPAYrSSw4oAniZ9Y8T5B92hjhwTBLUen0/vKPxf6pw==",
       "dev": true,
       "requires": {
-        "cssesc": "^0.1.0",
-        "fastparse": "^1.1.1",
-        "regexpu-core": "^1.0.0"
-      },
-      "dependencies": {
-        "jsesc": {
-          "version": "0.5.0",
-          "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz",
-          "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=",
-          "dev": true
-        },
-        "regexpu-core": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-1.0.0.tgz",
-          "integrity": "sha1-hqdj9Y7k18L2sQLkdkBQ3n7ZDGs=",
-          "dev": true,
-          "requires": {
-            "regenerate": "^1.2.1",
-            "regjsgen": "^0.2.0",
-            "regjsparser": "^0.1.4"
-          }
-        },
-        "regjsgen": {
-          "version": "0.2.0",
-          "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz",
-          "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=",
-          "dev": true
-        },
-        "regjsparser": {
-          "version": "0.1.5",
-          "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz",
-          "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=",
-          "dev": true,
-          "requires": {
-            "jsesc": "~0.5.0"
-          }
-        }
+        "cssesc": "^3.0.0",
+        "fastparse": "^1.1.2",
+        "regexpu-core": "^4.6.0"
       }
     },
     "cssauron": {
@@ -4053,9 +4007,9 @@
       }
     },
     "cssesc": {
-      "version": "0.1.0",
-      "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-0.1.0.tgz",
-      "integrity": "sha1-yBSQPkViM3GgR3tAEJqq++6t27Q=",
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
+      "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
       "dev": true
     },
     "custom-event": {
@@ -4071,15 +4025,16 @@
       "dev": true
     },
     "damerau-levenshtein": {
-      "version": "1.0.5",
-      "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.5.tgz",
-      "integrity": "sha512-CBCRqFnpu715iPmw1KrdOrzRqbdFwQTwAWyyyYS42+iAgHCuXZ+/TdMgQkUENPomxEz9z1BEzuQU2Xw0kUuAgA==",
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.6.tgz",
+      "integrity": "sha512-JVrozIeElnj3QzfUIt8tB8YMluBJom4Vw9qTPpjGYQ9fYlB3D/rb6OordUxf3xeFB35LKWs0xqcO5U6ySvBtug==",
       "dev": true
     },
     "dashdash": {
       "version": "1.14.1",
       "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
       "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
+      "dev": true,
       "requires": {
         "assert-plus": "^1.0.0"
       }
@@ -4091,11 +4046,12 @@
       "dev": true
     },
     "debug": {
-      "version": "2.6.9",
-      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
-      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
+      "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
+      "dev": true,
       "requires": {
-        "ms": "2.0.0"
+        "ms": "^2.1.1"
       }
     },
     "debuglog": {
@@ -4130,11 +4086,6 @@
         "regexp.prototype.flags": "^1.2.0"
       }
     },
-    "deep-is": {
-      "version": "0.1.3",
-      "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
-      "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ="
-    },
     "default-gateway": {
       "version": "4.2.0",
       "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-4.2.0.tgz",
@@ -4208,6 +4159,7 @@
       "version": "4.1.1",
       "resolved": "https://registry.npmjs.org/del/-/del-4.1.1.tgz",
       "integrity": "sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==",
+      "dev": true,
       "requires": {
         "@types/glob": "^7.1.1",
         "globby": "^6.1.0",
@@ -4222,6 +4174,7 @@
           "version": "6.1.0",
           "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz",
           "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=",
+          "dev": true,
           "requires": {
             "array-union": "^1.0.1",
             "glob": "^7.0.3",
@@ -4233,7 +4186,8 @@
             "pify": {
               "version": "2.3.0",
               "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
-              "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw="
+              "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
+              "dev": true
             }
           }
         }
@@ -4242,7 +4196,8 @@
     "delayed-stream": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
-      "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
+      "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
+      "dev": true
     },
     "depd": {
       "version": "1.1.2",
@@ -4295,9 +4250,9 @@
       "dev": true
     },
     "diff": {
-      "version": "3.5.0",
-      "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz",
-      "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==",
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
+      "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
       "dev": true
     },
     "diffie-hellman": {
@@ -4379,6 +4334,7 @@
       "version": "0.1.2",
       "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
       "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
+      "dev": true,
       "requires": {
         "jsbn": "~0.1.0",
         "safer-buffer": "^2.1.0"
@@ -4391,9 +4347,10 @@
       "dev": true
     },
     "electron-to-chromium": {
-      "version": "1.3.348",
-      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.348.tgz",
-      "integrity": "sha512-6O0IInybavGdYtcbI4ryF/9e3Qi8/soi6C68ELRseJuTwQPKq39uGgVVeQHG28t69Sgsky09nXBRhUiFXsZyFQ=="
+      "version": "1.3.377",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.377.tgz",
+      "integrity": "sha512-cm2WzMKf/3dW5+hNANKm8GAW6SwIWOqLTJ6GPCD0Bbw1qJ9Wzm9nmx9M+byzSsgw8CdCv5fb/wzLFqVS5h6QrA==",
+      "dev": true
     },
     "elliptic": {
       "version": "6.5.2",
@@ -4475,6 +4432,12 @@
             "ms": "2.0.0"
           }
         },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+          "dev": true
+        },
         "ws": {
           "version": "3.3.3",
           "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz",
@@ -4522,6 +4485,12 @@
             "ms": "2.0.0"
           }
         },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+          "dev": true
+        },
         "ws": {
           "version": "3.3.3",
           "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz",
@@ -4756,6 +4725,15 @@
         "to-regex": "^3.0.1"
       },
       "dependencies": {
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+          "dev": true,
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
         "define-property": {
           "version": "0.2.5",
           "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
@@ -4773,6 +4751,12 @@
           "requires": {
             "is-extendable": "^0.1.0"
           }
+        },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+          "dev": true
         }
       }
     },
@@ -4820,6 +4804,21 @@
           "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=",
           "dev": true
         },
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+          "dev": true,
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+          "dev": true
+        },
         "qs": {
           "version": "6.7.0",
           "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
@@ -4831,7 +4830,8 @@
     "extend": {
       "version": "3.0.2",
       "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
-      "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
+      "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
+      "dev": true
     },
     "extend-shallow": {
       "version": "3.0.2",
@@ -4930,31 +4930,23 @@
         }
       }
     },
-    "extract-zip": {
-      "version": "1.6.7",
-      "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.6.7.tgz",
-      "integrity": "sha1-qEC0uK9kAyZMjbV/Txp0Mz74H+k=",
-      "requires": {
-        "concat-stream": "1.6.2",
-        "debug": "2.6.9",
-        "mkdirp": "0.5.1",
-        "yauzl": "2.4.1"
-      }
-    },
     "extsprintf": {
       "version": "1.3.0",
       "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
-      "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
+      "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=",
+      "dev": true
     },
     "fast-deep-equal": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
-      "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk="
+      "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=",
+      "dev": true
     },
     "fast-json-stable-stringify": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
-      "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I="
+      "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=",
+      "dev": true
     },
     "fastparse": {
       "version": "1.1.2",
@@ -4971,14 +4963,6 @@
         "websocket-driver": ">=0.5.1"
       }
     },
-    "fd-slicer": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz",
-      "integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=",
-      "requires": {
-        "pend": "~1.2.0"
-      }
-    },
     "figgy-pudding": {
       "version": "3.5.1",
       "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.1.tgz",
@@ -4986,9 +4970,9 @@
       "dev": true
     },
     "figures": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/figures/-/figures-3.1.0.tgz",
-      "integrity": "sha512-ravh8VRXqHuMvZt/d8GblBeqDMkdJMBdv/2KntFH+ra5MXkO7nxNKpzQ3n6QD/2da1kH0aWmNISdvhM7gl2gVg==",
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
+      "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==",
       "dev": true,
       "requires": {
         "escape-string-regexp": "^1.0.5"
@@ -5004,18 +4988,41 @@
         "schema-utils": "^2.0.0"
       },
       "dependencies": {
+        "ajv": {
+          "version": "6.12.0",
+          "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.0.tgz",
+          "integrity": "sha512-D6gFiFA0RRLyUbvijN74DWAjXSFxWKaWP7mldxkVhyhAV3+SWA9HEJPHQ2c9soIeTFJqcSdFDGFgdqs1iUU2Hw==",
+          "dev": true,
+          "requires": {
+            "fast-deep-equal": "^3.1.1",
+            "fast-json-stable-stringify": "^2.0.0",
+            "json-schema-traverse": "^0.4.1",
+            "uri-js": "^4.2.2"
+          }
+        },
+        "fast-deep-equal": {
+          "version": "3.1.1",
+          "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz",
+          "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==",
+          "dev": true
+        },
         "schema-utils": {
-          "version": "2.6.4",
-          "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.6.4.tgz",
-          "integrity": "sha512-VNjcaUxVnEeun6B2fiiUDjXXBtD4ZSH7pdbfIu1pOFwgptDPLMo/z9jr4sUfsjFVPqDCEin/F7IYlq7/E6yDbQ==",
+          "version": "2.6.5",
+          "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.6.5.tgz",
+          "integrity": "sha512-5KXuwKziQrTVHh8j/Uxz+QUbxkaLW9X/86NBlx/gnKgtsZA2GIVMUn17qWhRFwF8jdYb3Dig5hRO/W5mZqy6SQ==",
           "dev": true,
           "requires": {
-            "ajv": "^6.10.2",
+            "ajv": "^6.12.0",
             "ajv-keywords": "^3.4.1"
           }
         }
       }
     },
+    "file-saver": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.2.tgz",
+      "integrity": "sha512-Wz3c3XQ5xroCxd1G8b7yL0Ehkf0TC9oYC6buPFkNnU9EnaPlifeAFCyCh+iewXTyFRcg0a6j3J7FmJsIhlhBdw=="
+    },
     "file-uri-to-path": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
@@ -5055,6 +5062,23 @@
         "parseurl": "~1.3.3",
         "statuses": "~1.5.0",
         "unpipe": "~1.0.0"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+          "dev": true,
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+          "dev": true
+        }
       }
     },
     "find-cache-dir": {
@@ -5088,9 +5112,9 @@
           }
         },
         "make-dir": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.0.0.tgz",
-          "integrity": "sha512-grNJDhb8b1Jm1qeqW5R/O63wUo4UXo2v2HMic6YT9i/HBlF93S8jkMgH7yugvY9ABDShH4VZMn8I+U8+fCNegw==",
+          "version": "3.0.2",
+          "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.0.2.tgz",
+          "integrity": "sha512-rYKABKutXa6vXTXhoV18cBE7PaewPXHe/Bdq4v+ZLMhxbWApkFFplT0LcbMW+6BbjnQXzZ/sAvSE/JdguApG5w==",
           "dev": true,
           "requires": {
             "semver": "^6.0.0"
@@ -5148,9 +5172,9 @@
       }
     },
     "follow-redirects": {
-      "version": "1.9.0",
-      "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.9.0.tgz",
-      "integrity": "sha512-CRcPzsSIbXyVDl0QI01muNDu69S8trU4jArW9LpOt2WtC6LyUJetcIrmfHsRBx7/Jb6GHJUiuqyYxPooFfNt6A==",
+      "version": "1.10.0",
+      "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.10.0.tgz",
+      "integrity": "sha512-4eyLK6s6lH32nOvLLwlIOnr9zrL8Sm+OvW4pVTJNoXeGzYIkHVf+pADQi+OJ0E67hiuSLezPVPyBcIZO50TmmQ==",
       "dev": true,
       "requires": {
         "debug": "^3.0.0"
@@ -5164,12 +5188,6 @@
           "requires": {
             "ms": "^2.1.1"
           }
-        },
-        "ms": {
-          "version": "2.1.2",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-          "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
-          "dev": true
         }
       }
     },
@@ -5182,12 +5200,14 @@
     "forever-agent": {
       "version": "0.6.1",
       "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
-      "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE="
+      "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=",
+      "dev": true
     },
     "form-data": {
       "version": "2.3.3",
       "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
       "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
+      "dev": true,
       "requires": {
         "asynckit": "^0.4.0",
         "combined-stream": "^1.0.6",
@@ -5225,15 +5245,6 @@
         "readable-stream": "^2.0.0"
       }
     },
-    "fs-access": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/fs-access/-/fs-access-1.0.1.tgz",
-      "integrity": "sha1-1qh/JiJxzv6+wwxVNAf7mV2od3o=",
-      "dev": true,
-      "requires": {
-        "null-check": "^1.0.0"
-      }
-    },
     "fs-extra": {
       "version": "7.0.1",
       "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz",
@@ -5269,7 +5280,8 @@
     "fs.realpath": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
-      "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
+      "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
+      "dev": true
     },
     "fsevents": {
       "version": "2.1.2",
@@ -5321,14 +5333,16 @@
       "version": "0.1.7",
       "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
       "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
+      "dev": true,
       "requires": {
         "assert-plus": "^1.0.0"
       }
     },
     "glob": {
-      "version": "7.1.6",
-      "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
-      "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+      "version": "7.1.4",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz",
+      "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==",
+      "dev": true,
       "requires": {
         "fs.realpath": "^1.0.0",
         "inflight": "^1.0.4",
@@ -5393,6 +5407,11 @@
       "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==",
       "dev": true
     },
+    "hammerjs": {
+      "version": "2.0.8",
+      "resolved": "https://registry.npmjs.org/hammerjs/-/hammerjs-2.0.8.tgz",
+      "integrity": "sha1-BO93hiz/K7edMPdpIJWTAiK/YPE="
+    },
     "handle-thing": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.0.tgz",
@@ -5402,12 +5421,14 @@
     "har-schema": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
-      "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI="
+      "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=",
+      "dev": true
     },
     "har-validator": {
       "version": "5.1.3",
       "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz",
       "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==",
+      "dev": true,
       "requires": {
         "ajv": "^6.5.5",
         "har-schema": "^2.0.0"
@@ -5550,9 +5571,9 @@
       }
     },
     "hosted-git-info": {
-      "version": "2.8.5",
-      "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.5.tgz",
-      "integrity": "sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg==",
+      "version": "2.8.8",
+      "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz",
+      "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==",
       "dev": true
     },
     "hpack.js": {
@@ -5647,6 +5668,12 @@
           "requires": {
             "ms": "2.0.0"
           }
+        },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+          "dev": true
         }
       }
     },
@@ -5666,6 +5693,7 @@
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
       "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
+      "dev": true,
       "requires": {
         "assert-plus": "^1.0.0",
         "jsprim": "^1.2.2",
@@ -5696,12 +5724,6 @@
           "requires": {
             "ms": "^2.1.1"
           }
-        },
-        "ms": {
-          "version": "2.1.2",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-          "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
-          "dev": true
         }
       }
     },
@@ -5823,6 +5845,7 @@
       "version": "1.0.6",
       "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
       "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+      "dev": true,
       "requires": {
         "once": "^1.3.0",
         "wrappy": "1"
@@ -5831,7 +5854,8 @@
     "inherits": {
       "version": "2.0.4",
       "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
-      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+      "dev": true
     },
     "ini": {
       "version": "1.3.5",
@@ -5947,12 +5971,13 @@
     "ip-regex": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz",
-      "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk="
+      "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=",
+      "dev": true
     },
     "ipaddr.js": {
-      "version": "1.9.0",
-      "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz",
-      "integrity": "sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA==",
+      "version": "1.9.1",
+      "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
+      "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
       "dev": true
     },
     "iqb-components": {
@@ -6109,12 +6134,14 @@
     "is-path-cwd": {
       "version": "2.2.0",
       "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz",
-      "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ=="
+      "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==",
+      "dev": true
     },
     "is-path-in-cwd": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz",
       "integrity": "sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ==",
+      "dev": true,
       "requires": {
         "is-path-inside": "^2.1.0"
       }
@@ -6123,6 +6150,7 @@
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-2.1.0.tgz",
       "integrity": "sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==",
+      "dev": true,
       "requires": {
         "path-is-inside": "^1.0.2"
       }
@@ -6175,12 +6203,8 @@
     "is-typedarray": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
-      "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
-    },
-    "is-url": {
-      "version": "1.2.4",
-      "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz",
-      "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww=="
+      "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=",
+      "dev": true
     },
     "is-windows": {
       "version": "1.0.2",
@@ -6194,20 +6218,11 @@
       "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=",
       "dev": true
     },
-    "is2": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/is2/-/is2-2.0.1.tgz",
-      "integrity": "sha512-+WaJvnaA7aJySz2q/8sLjMb2Mw14KTplHmSwcSpZ/fWJPkUmqw3YTzSWbPJ7OAwRvdYTWF2Wg+yYJ1AdP5Z8CA==",
-      "requires": {
-        "deep-is": "^0.1.3",
-        "ip-regex": "^2.1.0",
-        "is-url": "^1.2.2"
-      }
-    },
     "isarray": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
-      "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
+      "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+      "dev": true
     },
     "isbinaryfile": {
       "version": "3.0.3",
@@ -6233,7 +6248,8 @@
     "isstream": {
       "version": "0.1.2",
       "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
-      "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
+      "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=",
+      "dev": true
     },
     "istanbul-api": {
       "version": "2.1.6",
@@ -6350,27 +6366,12 @@
         "source-map": "^0.6.1"
       },
       "dependencies": {
-        "debug": {
-          "version": "4.1.1",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
-          "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
-          "dev": true,
-          "requires": {
-            "ms": "^2.1.1"
-          }
-        },
         "istanbul-lib-coverage": {
           "version": "2.0.5",
           "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz",
           "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==",
           "dev": true
         },
-        "ms": {
-          "version": "2.1.2",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-          "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
-          "dev": true
-        },
         "source-map": {
           "version": "0.6.1",
           "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
@@ -6408,9 +6409,9 @@
       }
     },
     "jasmine-core": {
-      "version": "3.3.0",
-      "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-3.3.0.tgz",
-      "integrity": "sha512-3/xSmG/d35hf80BEN66Y6g9Ca5l/Isdeg/j6zvbTYlTzeKinzmaTM4p9am5kYqOmE05D7s1t8FGjzdSnbUbceA==",
+      "version": "3.5.0",
+      "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-3.5.0.tgz",
+      "integrity": "sha512-nCeAiw37MIMA9w9IXso7bRaLl+c/ef3wnxsoSAlYrzS+Ot0zTG6nU8G/cIfGkqpkjX2wNaIW9RFG0TwIFnG6bA==",
       "dev": true
     },
     "jasmine-spec-reporter": {
@@ -6468,7 +6469,8 @@
     "jsbn": {
       "version": "0.1.1",
       "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
-      "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM="
+      "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
+      "dev": true
     },
     "jsesc": {
       "version": "2.5.2",
@@ -6485,17 +6487,20 @@
     "json-schema": {
       "version": "0.2.3",
       "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
-      "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM="
+      "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=",
+      "dev": true
     },
     "json-schema-traverse": {
       "version": "0.4.1",
       "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
-      "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
+      "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+      "dev": true
     },
     "json-stringify-safe": {
       "version": "5.0.1",
       "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
-      "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
+      "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=",
+      "dev": true
     },
     "json3": {
       "version": "3.3.3",
@@ -6510,14 +6515,6 @@
       "dev": true,
       "requires": {
         "minimist": "^1.2.0"
-      },
-      "dependencies": {
-        "minimist": {
-          "version": "1.2.0",
-          "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
-          "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
-          "dev": true
-        }
       }
     },
     "jsonfile": {
@@ -6539,6 +6536,7 @@
       "version": "1.4.1",
       "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
       "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
+      "dev": true,
       "requires": {
         "assert-plus": "1.0.0",
         "extsprintf": "1.3.0",
@@ -6607,12 +6605,11 @@
       }
     },
     "karma-chrome-launcher": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-2.2.0.tgz",
-      "integrity": "sha512-uf/ZVpAabDBPvdPdveyk1EPgbnloPvFFGgmRhYLTDH7gEB4nZdSBk8yTU47w1g/drLSx5uMOkjKk7IWKfWg/+w==",
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.1.0.tgz",
+      "integrity": "sha512-3dPs/n7vgz1rxxtynpzZTvb9y/GIaW8xjAwcIGttLbycqoFtI7yo1NGnQi6oFTherRE+GIhCAHZC4vEqWGhNvg==",
       "dev": true,
       "requires": {
-        "fs-access": "^1.0.0",
         "which": "^1.2.1"
       }
     },
@@ -6627,26 +6624,18 @@
       }
     },
     "karma-jasmine": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-2.0.1.tgz",
-      "integrity": "sha512-iuC0hmr9b+SNn1DaUD2QEYtUxkS1J+bSJSn7ejdEexs7P8EYvA1CWkEdrDQ+8jVH3AgWlCNwjYsT1chjcNW9lA==",
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-3.1.1.tgz",
+      "integrity": "sha512-pxBmv5K7IkBRLsFSTOpgiK/HzicQT3mfFF+oHAC7nxMfYKhaYFgxOa5qjnHW4sL5rUnmdkSajoudOnnOdPyW4Q==",
       "dev": true,
       "requires": {
-        "jasmine-core": "^3.3"
-      },
-      "dependencies": {
-        "jasmine-core": {
-          "version": "3.5.0",
-          "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-3.5.0.tgz",
-          "integrity": "sha512-nCeAiw37MIMA9w9IXso7bRaLl+c/ef3wnxsoSAlYrzS+Ot0zTG6nU8G/cIfGkqpkjX2wNaIW9RFG0TwIFnG6bA==",
-          "dev": true
-        }
+        "jasmine-core": "^3.5.0"
       }
     },
     "karma-jasmine-html-reporter": {
-      "version": "1.4.2",
-      "resolved": "https://registry.npmjs.org/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-1.4.2.tgz",
-      "integrity": "sha512-7g0gPj8+9JepCNJR9WjDyQ2RkZ375jpdurYQyAYv8PorUCadepl8vrD6LmMqOGcM17cnrynBawQYZHaumgDjBw==",
+      "version": "1.5.2",
+      "resolved": "https://registry.npmjs.org/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-1.5.2.tgz",
+      "integrity": "sha512-ILBPsXqQ3eomq+oaQsM311/jxsypw5/d0LnZXj26XkfThwq7jZ55A2CFSKJVA5VekbbOGvMyv7d3juZj0SeTxA==",
       "dev": true
     },
     "karma-source-map-support": {
@@ -6665,9 +6654,9 @@
       "dev": true
     },
     "kind-of": {
-      "version": "6.0.2",
-      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
-      "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+      "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
       "dev": true
     },
     "lcid": {
@@ -6800,23 +6789,6 @@
         "flatted": "^2.0.0",
         "rfdc": "^1.1.4",
         "streamroller": "^1.0.6"
-      },
-      "dependencies": {
-        "debug": {
-          "version": "4.1.1",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
-          "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
-          "dev": true,
-          "requires": {
-            "ms": "^2.1.1"
-          }
-        },
-        "ms": {
-          "version": "2.1.2",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-          "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
-          "dev": true
-        }
       }
     },
     "loglevel": {
@@ -6871,9 +6843,9 @@
       }
     },
     "make-error": {
-      "version": "1.3.5",
-      "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.5.tgz",
-      "integrity": "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==",
+      "version": "1.3.6",
+      "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
+      "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
       "dev": true
     },
     "make-fetch-happen": {
@@ -6925,11 +6897,6 @@
         "object-visit": "^1.0.0"
       }
     },
-    "material-design-icons": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/material-design-icons/-/material-design-icons-3.0.1.tgz",
-      "integrity": "sha1-mnHEh0chjrylHlGmbaaCA4zct78="
-    },
     "md5.js": {
       "version": "1.3.5",
       "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
@@ -7127,12 +7094,14 @@
     "mime-db": {
       "version": "1.43.0",
       "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz",
-      "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ=="
+      "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==",
+      "dev": true
     },
     "mime-types": {
       "version": "2.1.26",
       "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz",
       "integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==",
+      "dev": true,
       "requires": {
         "mime-db": "1.43.0"
       }
@@ -7171,14 +7140,16 @@
       "version": "3.0.4",
       "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
       "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+      "dev": true,
       "requires": {
         "brace-expansion": "^1.1.7"
       }
     },
     "minimist": {
-      "version": "0.0.8",
-      "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
-      "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
+      "version": "1.2.5",
+      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
+      "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
+      "dev": true
     },
     "minipass": {
       "version": "2.9.0",
@@ -7242,8 +7213,17 @@
       "version": "0.5.1",
       "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
       "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
+      "dev": true,
       "requires": {
         "minimist": "0.0.8"
+      },
+      "dependencies": {
+        "minimist": {
+          "version": "0.0.8",
+          "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
+          "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
+          "dev": true
+        }
       }
     },
     "move-concurrently": {
@@ -7261,9 +7241,10 @@
       }
     },
     "ms": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-      "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+      "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+      "dev": true
     },
     "multicast-dns": {
       "version": "6.2.3",
@@ -7332,9 +7313,9 @@
       "dev": true
     },
     "node-fetch-npm": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/node-fetch-npm/-/node-fetch-npm-2.0.2.tgz",
-      "integrity": "sha512-nJIxm1QmAj4v3nfCvEeCrYSoVwXyxLnaPBK5W1W5DGEJwjlKuC2VEUycGw5oxk+4zZahRrB84PUJJgEmhFTDFw==",
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/node-fetch-npm/-/node-fetch-npm-2.0.3.tgz",
+      "integrity": "sha512-DgwoKEsqLnFZtk3ap7GWBHcHwnUhsNmQqEDcdjfQ8GofLEFJ081NAd4Uin3R7RFZBWVJCwHISw1oaEqPgSLloA==",
       "dev": true,
       "requires": {
         "encoding": "^0.1.11",
@@ -7388,9 +7369,10 @@
       }
     },
     "node-releases": {
-      "version": "1.1.48",
-      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.48.tgz",
-      "integrity": "sha512-Hr8BbmUl1ujAST0K0snItzEA5zkJTQup8VNTKNfT6Zw8vTJkIiagUPNfxHmgDOyfFYNfKAul40sD0UEYTvwebw==",
+      "version": "1.1.52",
+      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.52.tgz",
+      "integrity": "sha512-snSiT1UypkgGt2wxPqS6ImEUICbNCMb31yaxWrOLXjhlt2z2/IBpaOxzONExqSm4y5oLnAqjjRWu+wsDzK5yNQ==",
+      "dev": true,
       "requires": {
         "semver": "^6.3.0"
       }
@@ -7505,9 +7487,9 @@
       }
     },
     "npm-registry-fetch": {
-      "version": "4.0.2",
-      "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-4.0.2.tgz",
-      "integrity": "sha512-Z0IFtPEozNdeZRPh3aHHxdG+ZRpzcbQaJLthsm3VhNf6DScicTFRHZzK82u8RsJUsUHkX+QH/zcB/5pmd20H4A==",
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-4.0.3.tgz",
+      "integrity": "sha512-WGvUx0lkKFhu9MbiGFuT9nG2NpfQ+4dCJwRwwtK2HK5izJEvwDxMeUyqbuMS7N/OkpVCqDorV6rO5E4V9F8lJw==",
       "dev": true,
       "requires": {
         "JSONStream": "^1.3.4",
@@ -7536,12 +7518,6 @@
         "path-key": "^2.0.0"
       }
     },
-    "null-check": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/null-check/-/null-check-1.0.0.tgz",
-      "integrity": "sha1-l33/1xdgErnsMNKjnbXPcqBDnt0=",
-      "dev": true
-    },
     "num2fraction": {
       "version": "1.2.2",
       "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz",
@@ -7557,12 +7533,14 @@
     "oauth-sign": {
       "version": "0.9.0",
       "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
-      "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ=="
+      "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==",
+      "dev": true
     },
     "object-assign": {
       "version": "4.1.1",
       "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
-      "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
+      "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
+      "dev": true
     },
     "object-component": {
       "version": "0.0.3",
@@ -7684,6 +7662,7 @@
       "version": "1.4.0",
       "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
       "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+      "dev": true,
       "requires": {
         "wrappy": "1"
       }
@@ -7723,6 +7702,14 @@
       "requires": {
         "minimist": "~0.0.1",
         "wordwrap": "~0.0.2"
+      },
+      "dependencies": {
+        "minimist": {
+          "version": "0.0.10",
+          "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
+          "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=",
+          "dev": true
+        }
       }
     },
     "original": {
@@ -7812,7 +7799,8 @@
     "p-map": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz",
-      "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw=="
+      "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==",
+      "dev": true
     },
     "p-retry": {
       "version": "3.0.1",
@@ -7982,12 +7970,14 @@
     "path-is-absolute": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
-      "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
+      "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
+      "dev": true
     },
     "path-is-inside": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz",
-      "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM="
+      "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=",
+      "dev": true
     },
     "path-key": {
       "version": "2.0.1",
@@ -8037,15 +8027,11 @@
         "sha.js": "^2.4.8"
       }
     },
-    "pend": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
-      "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA="
-    },
     "performance-now": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
-      "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
+      "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=",
+      "dev": true
     },
     "picomatch": {
       "version": "2.2.1",
@@ -8056,17 +8042,20 @@
     "pify": {
       "version": "4.0.1",
       "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
-      "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g=="
+      "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==",
+      "dev": true
     },
     "pinkie": {
       "version": "2.0.4",
       "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
-      "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA="
+      "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=",
+      "dev": true
     },
     "pinkie-promise": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
       "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
+      "dev": true,
       "requires": {
         "pinkie": "^2.0.0"
       }
@@ -8099,12 +8088,6 @@
           "requires": {
             "ms": "^2.1.1"
           }
-        },
-        "ms": {
-          "version": "2.1.2",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-          "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
-          "dev": true
         }
       }
     },
@@ -8185,9 +8168,9 @@
       }
     },
     "postcss-value-parser": {
-      "version": "4.0.2",
-      "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.0.2.tgz",
-      "integrity": "sha512-LmeoohTpp/K4UiyQCwuGWlONxXamGzCMtFxLq4W1nZVGIQLYvMCJx3yAF9qyyuFpflABI9yVdtJAqbihOsCsJQ==",
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.0.3.tgz",
+      "integrity": "sha512-N7h4pG+Nnu5BEIzyeaaIYWs0LI5XC40OrRh5L60z0QjFsqGWcHcbkBvpe1WYpcIS9yQ8sOi/vIPt1ejQCrMVrg==",
       "dev": true
     },
     "prepend-http": {
@@ -8211,7 +8194,8 @@
     "process-nextick-args": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
-      "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
+      "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
+      "dev": true
     },
     "promise": {
       "version": "7.3.1",
@@ -8351,12 +8335,6 @@
             "path-is-inside": "^1.0.1"
           }
         },
-        "minimist": {
-          "version": "1.2.0",
-          "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
-          "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
-          "dev": true
-        },
         "pify": {
           "version": "2.3.0",
           "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
@@ -8412,13 +8390,13 @@
       }
     },
     "proxy-addr": {
-      "version": "2.0.5",
-      "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.5.tgz",
-      "integrity": "sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==",
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz",
+      "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==",
       "dev": true,
       "requires": {
         "forwarded": "~0.1.2",
-        "ipaddr.js": "1.9.0"
+        "ipaddr.js": "1.9.1"
       }
     },
     "prr": {
@@ -8436,7 +8414,8 @@
     "psl": {
       "version": "1.7.0",
       "resolved": "https://registry.npmjs.org/psl/-/psl-1.7.0.tgz",
-      "integrity": "sha512-5NsSEDv8zY70ScRnOTn7bK7eanl2MvFrOrS/R6x+dBt5g1ghnj9Zv90kO8GwT8gxcu2ANyFprnFYB85IogIJOQ=="
+      "integrity": "sha512-5NsSEDv8zY70ScRnOTn7bK7eanl2MvFrOrS/R6x+dBt5g1ghnj9Zv90kO8GwT8gxcu2ANyFprnFYB85IogIJOQ==",
+      "dev": true
     },
     "public-encrypt": {
       "version": "4.0.3",
@@ -8488,7 +8467,8 @@
     "punycode": {
       "version": "2.1.1",
       "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
-      "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
+      "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
+      "dev": true
     },
     "q": {
       "version": "1.4.1",
@@ -8505,7 +8485,8 @@
     "qs": {
       "version": "6.5.2",
       "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
-      "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
+      "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==",
+      "dev": true
     },
     "query-string": {
       "version": "4.3.4",
@@ -8590,13 +8571,31 @@
         "schema-utils": "^2.0.1"
       },
       "dependencies": {
+        "ajv": {
+          "version": "6.12.0",
+          "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.0.tgz",
+          "integrity": "sha512-D6gFiFA0RRLyUbvijN74DWAjXSFxWKaWP7mldxkVhyhAV3+SWA9HEJPHQ2c9soIeTFJqcSdFDGFgdqs1iUU2Hw==",
+          "dev": true,
+          "requires": {
+            "fast-deep-equal": "^3.1.1",
+            "fast-json-stable-stringify": "^2.0.0",
+            "json-schema-traverse": "^0.4.1",
+            "uri-js": "^4.2.2"
+          }
+        },
+        "fast-deep-equal": {
+          "version": "3.1.1",
+          "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz",
+          "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==",
+          "dev": true
+        },
         "schema-utils": {
-          "version": "2.6.4",
-          "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.6.4.tgz",
-          "integrity": "sha512-VNjcaUxVnEeun6B2fiiUDjXXBtD4ZSH7pdbfIu1pOFwgptDPLMo/z9jr4sUfsjFVPqDCEin/F7IYlq7/E6yDbQ==",
+          "version": "2.6.5",
+          "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.6.5.tgz",
+          "integrity": "sha512-5KXuwKziQrTVHh8j/Uxz+QUbxkaLW9X/86NBlx/gnKgtsZA2GIVMUn17qWhRFwF8jdYb3Dig5hRO/W5mZqy6SQ==",
           "dev": true,
           "requires": {
-            "ajv": "^6.10.2",
+            "ajv": "^6.12.0",
             "ajv-keywords": "^3.4.1"
           }
         }
@@ -8647,6 +8646,7 @@
       "version": "2.3.7",
       "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
       "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
+      "dev": true,
       "requires": {
         "core-util-is": "~1.0.0",
         "inherits": "~2.0.3",
@@ -8691,9 +8691,9 @@
       "dev": true
     },
     "regenerate-unicode-properties": {
-      "version": "8.1.0",
-      "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.1.0.tgz",
-      "integrity": "sha512-LGZzkgtLY79GeXLm8Dp0BVLdQlWICzBnJz/ipWUgo59qBaZ+BHtq51P2q1uVZlppMuUAT37SDk39qUbjTWB7bA==",
+      "version": "8.2.0",
+      "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz",
+      "integrity": "sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA==",
       "dev": true,
       "requires": {
         "regenerate": "^1.4.0"
@@ -8706,12 +8706,13 @@
       "dev": true
     },
     "regenerator-transform": {
-      "version": "0.14.1",
-      "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.1.tgz",
-      "integrity": "sha512-flVuee02C3FKRISbxhXl9mGzdbWUVHubl1SMaknjxkFB1/iqpJhArQUvRxOOPEc/9tAiX0BaQ28FJH10E4isSQ==",
+      "version": "0.14.3",
+      "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.3.tgz",
+      "integrity": "sha512-zXHNKJspmONxBViAb3ZUmFoFPnTBs3zFhCEZJiwp/gkNzxVbTqNJVjYKx6Qk1tQ1P4XLf4TbH9+KBB7wGoAaUw==",
       "dev": true,
       "requires": {
-        "private": "^0.1.6"
+        "@babel/runtime": "^7.8.4",
+        "private": "^0.1.8"
       }
     },
     "regex-not": {
@@ -8735,17 +8736,17 @@
       }
     },
     "regexpu-core": {
-      "version": "4.6.0",
-      "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.6.0.tgz",
-      "integrity": "sha512-YlVaefl8P5BnFYOITTNzDvan1ulLOiXJzCNZxduTIosN17b87h3bvG9yHMoHaRuo88H4mQ06Aodj5VtYGGGiTg==",
+      "version": "4.7.0",
+      "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.7.0.tgz",
+      "integrity": "sha512-TQ4KXRnIn6tz6tjnrXEkD/sshygKH/j5KzK86X8MkeHyZ8qst/LZ89j3X4/8HEIfHANTFIP/AbXakeRhWIl5YQ==",
       "dev": true,
       "requires": {
         "regenerate": "^1.4.0",
-        "regenerate-unicode-properties": "^8.1.0",
-        "regjsgen": "^0.5.0",
-        "regjsparser": "^0.6.0",
+        "regenerate-unicode-properties": "^8.2.0",
+        "regjsgen": "^0.5.1",
+        "regjsparser": "^0.6.4",
         "unicode-match-property-ecmascript": "^1.0.4",
-        "unicode-match-property-value-ecmascript": "^1.1.0"
+        "unicode-match-property-value-ecmascript": "^1.2.0"
       }
     },
     "regjsgen": {
@@ -8755,9 +8756,9 @@
       "dev": true
     },
     "regjsparser": {
-      "version": "0.6.2",
-      "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.2.tgz",
-      "integrity": "sha512-E9ghzUtoLwDekPT0DYCp+c4h+bvuUpe6rRHCTYn6eGoqj1LgKXxT6I0Il4WbjhQkOghzi/V+y03bPKvbllL93Q==",
+      "version": "0.6.4",
+      "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.4.tgz",
+      "integrity": "sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw==",
       "dev": true,
       "requires": {
         "jsesc": "~0.5.0"
@@ -8790,9 +8791,10 @@
       "dev": true
     },
     "request": {
-      "version": "2.88.0",
-      "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz",
-      "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==",
+      "version": "2.88.2",
+      "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
+      "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==",
+      "dev": true,
       "requires": {
         "aws-sign2": "~0.7.0",
         "aws4": "^1.8.0",
@@ -8801,7 +8803,7 @@
         "extend": "~3.0.2",
         "forever-agent": "~0.6.1",
         "form-data": "~2.3.2",
-        "har-validator": "~5.1.0",
+        "har-validator": "~5.1.3",
         "http-signature": "~1.2.0",
         "is-typedarray": "~1.0.0",
         "isstream": "~0.1.2",
@@ -8811,7 +8813,7 @@
         "performance-now": "^2.1.0",
         "qs": "~6.5.2",
         "safe-buffer": "^5.1.2",
-        "tough-cookie": "~2.4.3",
+        "tough-cookie": "~2.5.0",
         "tunnel-agent": "^0.6.0",
         "uuid": "^3.3.2"
       }
@@ -8835,9 +8837,9 @@
       "dev": true
     },
     "resolve": {
-      "version": "1.14.2",
-      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.14.2.tgz",
-      "integrity": "sha512-EjlOBLBO1kxsUxsKjLt7TAECyKW6fOh1VRkykQkKGzcBbjjPIxBqGh0jf7GJ3k/f5mxMqW3htMD3WdTUVtW8HQ==",
+      "version": "1.15.1",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.1.tgz",
+      "integrity": "sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w==",
       "dev": true,
       "requires": {
         "path-parse": "^1.0.6"
@@ -8896,6 +8898,7 @@
       "version": "2.7.1",
       "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
       "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
+      "dev": true,
       "requires": {
         "glob": "^7.1.3"
       }
@@ -8911,9 +8914,9 @@
       }
     },
     "run-async": {
-      "version": "2.3.0",
-      "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz",
-      "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=",
+      "version": "2.4.0",
+      "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.0.tgz",
+      "integrity": "sha512-xJTbh/d7Lm7SBhc1tNvTpeCHaEzoyxPrqNlvSdMfBTYwaY++UJFyXUOxAtsRUXjlqOfj8luNaR9vjCh4KeV+pg==",
       "dev": true,
       "requires": {
         "is-promise": "^2.1.0"
@@ -8929,9 +8932,9 @@
       }
     },
     "rxjs": {
-      "version": "6.4.0",
-      "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz",
-      "integrity": "sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw==",
+      "version": "6.5.4",
+      "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.4.tgz",
+      "integrity": "sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q==",
       "requires": {
         "tslib": "^1.9.0"
       }
@@ -8939,7 +8942,8 @@
     "safe-buffer": {
       "version": "5.1.2",
       "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
-      "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+      "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+      "dev": true
     },
     "safe-regex": {
       "version": "1.1.0",
@@ -8953,7 +8957,8 @@
     "safer-buffer": {
       "version": "2.1.2",
       "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
-      "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+      "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+      "dev": true
     },
     "sass": {
       "version": "1.22.9",
@@ -9052,7 +9057,8 @@
     "semver": {
       "version": "6.3.0",
       "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
-      "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
+      "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+      "dev": true
     },
     "semver-dsl": {
       "version": "1.0.1",
@@ -9109,6 +9115,23 @@
         "statuses": "~1.5.0"
       },
       "dependencies": {
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+          "dev": true,
+          "requires": {
+            "ms": "2.0.0"
+          },
+          "dependencies": {
+            "ms": {
+              "version": "2.0.0",
+              "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+              "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+              "dev": true
+            }
+          }
+        },
         "ms": {
           "version": "2.1.1",
           "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
@@ -9138,6 +9161,15 @@
         "parseurl": "~1.3.2"
       },
       "dependencies": {
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+          "dev": true,
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
         "http-errors": {
           "version": "1.6.3",
           "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz",
@@ -9156,6 +9188,12 @@
           "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
           "dev": true
         },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+          "dev": true
+        },
         "setprototypeof": {
           "version": "1.1.0",
           "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz",
@@ -9291,6 +9329,15 @@
         "use": "^3.1.0"
       },
       "dependencies": {
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+          "dev": true,
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
         "define-property": {
           "version": "0.2.5",
           "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
@@ -9309,6 +9356,12 @@
             "is-extendable": "^0.1.0"
           }
         },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+          "dev": true
+        },
         "source-map": {
           "version": "0.5.7",
           "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
@@ -9410,6 +9463,12 @@
           "requires": {
             "ms": "2.0.0"
           }
+        },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+          "dev": true
         }
       }
     },
@@ -9455,6 +9514,12 @@
           "requires": {
             "ms": "2.0.0"
           }
+        },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+          "dev": true
         }
       }
     },
@@ -9489,6 +9554,12 @@
           "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz",
           "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=",
           "dev": true
+        },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+          "dev": true
         }
       }
     },
@@ -9533,12 +9604,6 @@
           "requires": {
             "websocket-driver": ">=0.5.1"
           }
-        },
-        "ms": {
-          "version": "2.1.2",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-          "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
-          "dev": true
         }
       }
     },
@@ -9642,9 +9707,9 @@
       "dev": true
     },
     "sourcemap-codec": {
-      "version": "1.4.7",
-      "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.7.tgz",
-      "integrity": "sha512-RuN23NzhAOuUtaivhcrjXx1OPXsFeH9m5sI373/U7+tGLKihjUyboZAzOadytMjnqHp1f45RGk1IzDKCpDpSYA==",
+      "version": "1.4.8",
+      "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
+      "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==",
       "dev": true
     },
     "spdx-correct": {
@@ -9690,23 +9755,6 @@
         "http-deceiver": "^1.2.7",
         "select-hose": "^2.0.0",
         "spdy-transport": "^3.0.0"
-      },
-      "dependencies": {
-        "debug": {
-          "version": "4.1.1",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
-          "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
-          "dev": true,
-          "requires": {
-            "ms": "^2.1.1"
-          }
-        },
-        "ms": {
-          "version": "2.1.2",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-          "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
-          "dev": true
-        }
       }
     },
     "spdy-transport": {
@@ -9723,25 +9771,10 @@
         "wbuf": "^1.7.3"
       },
       "dependencies": {
-        "debug": {
-          "version": "4.1.1",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
-          "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
-          "dev": true,
-          "requires": {
-            "ms": "^2.1.1"
-          }
-        },
-        "ms": {
-          "version": "2.1.2",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-          "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
-          "dev": true
-        },
         "readable-stream": {
-          "version": "3.5.0",
-          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.5.0.tgz",
-          "integrity": "sha512-gSz026xs2LfxBPudDuI41V1lka8cxg64E66SGe78zJlsUofOg/yqwezdIcdfwik6B4h8LFmWPA9ef9X3FiNFLA==",
+          "version": "3.6.0",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+          "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
           "dev": true,
           "requires": {
             "inherits": "^2.0.3",
@@ -9779,6 +9812,7 @@
       "version": "1.16.1",
       "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz",
       "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==",
+      "dev": true,
       "requires": {
         "asn1": "~0.2.3",
         "assert-plus": "^1.0.0",
@@ -9887,12 +9921,6 @@
           "requires": {
             "ms": "^2.1.1"
           }
-        },
-        "ms": {
-          "version": "2.1.2",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-          "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
-          "dev": true
         }
       }
     },
@@ -9953,6 +9981,7 @@
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
       "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+      "dev": true,
       "requires": {
         "safe-buffer": "~5.1.0"
       }
@@ -9988,13 +10017,31 @@
         "schema-utils": "^2.0.1"
       },
       "dependencies": {
+        "ajv": {
+          "version": "6.12.0",
+          "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.0.tgz",
+          "integrity": "sha512-D6gFiFA0RRLyUbvijN74DWAjXSFxWKaWP7mldxkVhyhAV3+SWA9HEJPHQ2c9soIeTFJqcSdFDGFgdqs1iUU2Hw==",
+          "dev": true,
+          "requires": {
+            "fast-deep-equal": "^3.1.1",
+            "fast-json-stable-stringify": "^2.0.0",
+            "json-schema-traverse": "^0.4.1",
+            "uri-js": "^4.2.2"
+          }
+        },
+        "fast-deep-equal": {
+          "version": "3.1.1",
+          "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz",
+          "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==",
+          "dev": true
+        },
         "schema-utils": {
-          "version": "2.6.4",
-          "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.6.4.tgz",
-          "integrity": "sha512-VNjcaUxVnEeun6B2fiiUDjXXBtD4ZSH7pdbfIu1pOFwgptDPLMo/z9jr4sUfsjFVPqDCEin/F7IYlq7/E6yDbQ==",
+          "version": "2.6.5",
+          "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.6.5.tgz",
+          "integrity": "sha512-5KXuwKziQrTVHh8j/Uxz+QUbxkaLW9X/86NBlx/gnKgtsZA2GIVMUn17qWhRFwF8jdYb3Dig5hRO/W5mZqy6SQ==",
           "dev": true,
           "requires": {
-            "ajv": "^6.10.2",
+            "ajv": "^6.12.0",
             "ajv-keywords": "^3.4.1"
           }
         }
@@ -10086,30 +10133,6 @@
         "yallist": "^3.0.3"
       }
     },
-    "tcp-port-used": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/tcp-port-used/-/tcp-port-used-1.0.1.tgz",
-      "integrity": "sha512-rwi5xJeU6utXoEIiMvVBMc9eJ2/ofzB+7nLOdnZuFTmNCLqRiQh2sMG9MqCxHU/69VC/Fwp5dV9306Qd54ll1Q==",
-      "requires": {
-        "debug": "4.1.0",
-        "is2": "2.0.1"
-      },
-      "dependencies": {
-        "debug": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.0.tgz",
-          "integrity": "sha512-heNPJUJIqC+xB6ayLAMHaIrmN9HKa7aQO8MGqKpvCA+uJYVcvR6l5kgdrhRuwPFHU7P5/A1w0BjByPHwpfTDKg==",
-          "requires": {
-            "ms": "^2.1.1"
-          }
-        },
-        "ms": {
-          "version": "2.1.2",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-          "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
-        }
-      }
-    },
     "terser": {
       "version": "4.6.3",
       "resolved": "https://registry.npmjs.org/terser/-/terser-4.6.3.tgz",
@@ -10271,19 +10294,13 @@
       "dev": true
     },
     "tough-cookie": {
-      "version": "2.4.3",
-      "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz",
-      "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==",
+      "version": "2.5.0",
+      "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
+      "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
+      "dev": true,
       "requires": {
-        "psl": "^1.1.24",
-        "punycode": "^1.4.1"
-      },
-      "dependencies": {
-        "punycode": {
-          "version": "1.4.1",
-          "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
-          "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4="
-        }
+        "psl": "^1.1.28",
+        "punycode": "^2.1.1"
       }
     },
     "tree-kill": {
@@ -10293,52 +10310,42 @@
       "dev": true
     },
     "ts-node": {
-      "version": "7.0.1",
-      "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-7.0.1.tgz",
-      "integrity": "sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw==",
+      "version": "8.6.2",
+      "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.6.2.tgz",
+      "integrity": "sha512-4mZEbofxGqLL2RImpe3zMJukvEvcO1XP8bj8ozBPySdCUXEcU5cIRwR0aM3R+VoZq7iXc8N86NC0FspGRqP4gg==",
       "dev": true,
       "requires": {
-        "arrify": "^1.0.0",
-        "buffer-from": "^1.1.0",
-        "diff": "^3.1.0",
+        "arg": "^4.1.0",
+        "diff": "^4.0.1",
         "make-error": "^1.1.1",
-        "minimist": "^1.2.0",
-        "mkdirp": "^0.5.1",
         "source-map-support": "^0.5.6",
-        "yn": "^2.0.0"
-      },
-      "dependencies": {
-        "minimist": {
-          "version": "1.2.0",
-          "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
-          "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
-          "dev": true
-        }
+        "yn": "3.1.1"
       }
     },
     "tslib": {
-      "version": "1.9.3",
-      "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz",
-      "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ=="
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.1.tgz",
+      "integrity": "sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA=="
     },
     "tslint": {
-      "version": "5.11.0",
-      "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.11.0.tgz",
-      "integrity": "sha1-mPMMAurjzecAYgHkwzywi0hYHu0=",
+      "version": "5.20.1",
+      "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.20.1.tgz",
+      "integrity": "sha512-EcMxhzCFt8k+/UP5r8waCf/lzmeSyVlqxqMEDQE7rWYiQky8KpIBz1JAoYXfROHrPZ1XXd43q8yQnULOLiBRQg==",
       "dev": true,
       "requires": {
-        "babel-code-frame": "^6.22.0",
+        "@babel/code-frame": "^7.0.0",
         "builtin-modules": "^1.1.1",
         "chalk": "^2.3.0",
         "commander": "^2.12.1",
-        "diff": "^3.2.0",
+        "diff": "^4.0.1",
         "glob": "^7.1.1",
-        "js-yaml": "^3.7.0",
+        "js-yaml": "^3.13.1",
         "minimatch": "^3.0.4",
+        "mkdirp": "^0.5.1",
         "resolve": "^1.3.2",
         "semver": "^5.3.0",
         "tslib": "^1.8.0",
-        "tsutils": "^2.27.2"
+        "tsutils": "^2.29.0"
       },
       "dependencies": {
         "semver": {
@@ -10368,6 +10375,7 @@
       "version": "0.6.0",
       "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
       "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
+      "dev": true,
       "requires": {
         "safe-buffer": "^5.0.1"
       }
@@ -10375,12 +10383,13 @@
     "tweetnacl": {
       "version": "0.14.5",
       "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
-      "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q="
+      "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
+      "dev": true
     },
     "type-fest": {
-      "version": "0.8.1",
-      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
-      "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
+      "version": "0.11.0",
+      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz",
+      "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==",
       "dev": true
     },
     "type-is": {
@@ -10396,19 +10405,15 @@
     "typedarray": {
       "version": "0.0.6",
       "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
-      "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
+      "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
+      "dev": true
     },
     "typescript": {
-      "version": "3.4.5",
-      "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.4.5.tgz",
-      "integrity": "sha512-YycBxUb49UUhdNMU5aJ7z5Ej2XGmaIBL0x34vZ82fn3hGvD+bgrMrVDpatgz2f7YxUMJxMkbWxJZeAvDxVe7Vw==",
+      "version": "3.5.3",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.5.3.tgz",
+      "integrity": "sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==",
       "dev": true
     },
-    "ua-parser-js": {
-      "version": "0.7.21",
-      "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.21.tgz",
-      "integrity": "sha512-+O8/qh/Qj8CgC6eYBVBykMrNtp5Gebn4dlGD/kKXVkJNDwyrAwSIqwz8CDf+tsAIWVycKcku6gIXJ0qwx/ZXaQ=="
-    },
     "ultron": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz",
@@ -10432,15 +10437,15 @@
       }
     },
     "unicode-match-property-value-ecmascript": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.1.0.tgz",
-      "integrity": "sha512-hDTHvaBk3RmFzvSl0UVrUmC3PuW9wKVnpoUDYH0JDkSIovzw+J5viQmeYHxVSBptubnr7PbH2e0fnpDRQnQl5g==",
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz",
+      "integrity": "sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ==",
       "dev": true
     },
     "unicode-property-aliases-ecmascript": {
-      "version": "1.0.5",
-      "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.5.tgz",
-      "integrity": "sha512-L5RAqCfXqAwR3RriF8pM0lU0w4Ryf/GgzONwi6KnL1taJQa7x1TCxdJnILX59WIGOwR57IVxn7Nej0fz1Ny6fw==",
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz",
+      "integrity": "sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg==",
       "dev": true
     },
     "union-value": {
@@ -10492,12 +10497,6 @@
           "requires": {
             "ms": "^2.1.1"
           }
-        },
-        "ms": {
-          "version": "2.1.2",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-          "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
-          "dev": true
         }
       }
     },
@@ -10563,6 +10562,7 @@
       "version": "4.2.2",
       "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
       "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
+      "dev": true,
       "requires": {
         "punycode": "^2.1.0"
       }
@@ -10655,7 +10655,8 @@
     "util-deprecate": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
-      "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
+      "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
+      "dev": true
     },
     "util-promisify": {
       "version": "2.1.0",
@@ -10675,7 +10676,8 @@
     "uuid": {
       "version": "3.4.0",
       "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
-      "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
+      "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
+      "dev": true
     },
     "validate-npm-package-license": {
       "version": "3.0.4",
@@ -10706,6 +10708,7 @@
       "version": "1.10.0",
       "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
       "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
+      "dev": true,
       "requires": {
         "assert-plus": "^1.0.0",
         "core-util-is": "1.0.2",
@@ -11438,11 +11441,6 @@
         "minimalistic-assert": "^1.0.0"
       }
     },
-    "web-animations-js": {
-      "version": "2.3.2",
-      "resolved": "https://registry.npmjs.org/web-animations-js/-/web-animations-js-2.3.2.tgz",
-      "integrity": "sha512-TOMFWtQdxzjWp8qx4DAraTWTsdhxVSiWa6NkPFSaPtZ1diKUxTn4yTix73A1euG1WbSOMMPcY51cnjTIHrGtDA=="
-    },
     "webdriver-js-extender": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/webdriver-js-extender/-/webdriver-js-extender-2.1.0.tgz",
@@ -11638,15 +11636,6 @@
             "upath": "^1.1.1"
           }
         },
-        "debug": {
-          "version": "4.1.1",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
-          "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
-          "dev": true,
-          "requires": {
-            "ms": "^2.1.1"
-          }
-        },
         "extend-shallow": {
           "version": "2.0.1",
           "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
@@ -12253,12 +12242,6 @@
             "is-buffer": "^1.1.5"
           }
         },
-        "ms": {
-          "version": "2.1.2",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-          "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
-          "dev": true
-        },
         "readdirp": {
           "version": "2.2.1",
           "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz",
@@ -12434,7 +12417,8 @@
     "wrappy": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
-      "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
+      "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
+      "dev": true
     },
     "ws": {
       "version": "6.2.1",
@@ -12523,14 +12507,6 @@
         "decamelize": "^1.2.0"
       }
     },
-    "yauzl": {
-      "version": "2.4.1",
-      "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz",
-      "integrity": "sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU=",
-      "requires": {
-        "fd-slicer": "~1.0.1"
-      }
-    },
     "yeast": {
       "version": "0.1.2",
       "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz",
@@ -12538,9 +12514,9 @@
       "dev": true
     },
     "yn": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz",
-      "integrity": "sha1-5a2ryKz0CPY4X8dklWhMiOavaJo=",
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
+      "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
       "dev": true
     },
     "zone.js": {
diff --git a/package.json b/package.json
index 55c168b5fa11cec254601c2d582f0fa7ff9d7f1a..1f6188e3d4c7686aeaa577d4c40e969b23f47605 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "itc-ng",
-  "version": "1.5.3",
+  "version": "2.0.0-alpha",
   "scripts": {
     "ng": "ng",
     "start": "ng serve",
@@ -11,50 +11,46 @@
   },
   "private": true,
   "dependencies": {
-    "@angular/animations": "^8.0.0",
-    "@angular/cdk": "~8.0.0",
-    "@angular/common": "^8.0.0",
-    "@angular/compiler": "^8.0.0",
-    "@angular/core": "^8.0.0",
+    "@angular/animations": "~8.2.14",
+    "@angular/cdk": "~8.2.3",
+    "@angular/common": "~8.2.14",
+    "@angular/compiler": "~8.2.14",
+    "@angular/core": "~8.2.14",
     "@angular/flex-layout": "~8.0.0-beta.27",
-    "@angular/forms": "^8.0.0",
-    "@angular/material": "~8.0.0",
-    "@angular/platform-browser": "^8.0.0",
-    "@angular/platform-browser-dynamic": "^8.0.0",
-    "@angular/router": "^8.0.0",
-    "browserslist": "^4.8.6",
-    "caniuse-lite": "^1.0.30001027",
-    "chromedriver": "^79.0.3",
-    "classlist.js": "^1.1.20150312",
-    "core-js": "~2.6.11",
-    "iqb-components": "^1.6.4",
-    "material-design-icons": "~3.0.1",
-    "rxjs": "~6.4.0",
-    "tslib": "~1.9.0",
-    "ua-parser-js": "^0.7.21",
-    "web-animations-js": "^2.3.2",
+    "@angular/forms": "~8.2.14",
+    "@angular/material": "~8.2.3",
+    "@angular/platform-browser": "~8.2.14",
+    "@angular/platform-browser-dynamic": "~8.2.14",
+    "@angular/router": "~8.2.14",
+    "@types/file-saver": "^2.0.1",
+    "iqb-components": "1.6.x",
+    "core-js": "^3.6.4",
+    "file-saver": "^2.0.2",
+    "hammerjs": "^2.0.8",
+    "rxjs": "^6.5.4",
+    "tslib": "^1.10.0",
     "zone.js": "~0.9.1"
   },
   "devDependencies": {
-    "@angular-devkit/build-angular": "^0.803.25",
-    "@angular/cli": "^8.3.25",
-    "@angular/compiler-cli": "^8.0.0",
-    "@angular/language-service": "^8.0.0",
-    "@types/jasmine": "~2.8.8",
+    "@angular-devkit/build-angular": "~0.803.23",
+    "@angular/cli": "~8.3.23",
+    "@angular/compiler-cli": "~8.2.14",
+    "@angular/language-service": "~8.2.14",
+    "@types/jasmine": "^3.5.1",
     "@types/jasminewd2": "~2.0.8",
-    "@types/node": "~8.9.4",
-    "codelyzer": "~5.2.1",
-    "jasmine-core": "~3.3",
+    "@types/node": "^13.5.0",
+    "codelyzer": "^5.0.1",
+    "jasmine-core": "~3.5.0",
     "jasmine-spec-reporter": "~4.2.1",
-    "karma": "^4.4.1",
-    "karma-chrome-launcher": "~2.2.0",
+    "karma": "~4.4.1",
+    "karma-chrome-launcher": "~3.1.0",
     "karma-coverage-istanbul-reporter": "^2.1.1",
-    "karma-jasmine": "~2.0.1",
-    "karma-jasmine-html-reporter": "~1.4.2",
-    "protractor": "^5.4.3",
-    "ts-node": "~7.0.0  ",
-    "tslint": "~5.11.0",
-    "typescript": "~3.4.0-rc"
+    "karma-jasmine": "~3.1.0",
+    "karma-jasmine-html-reporter": "~1.5.1",
+    "protractor": "^5.4.2",
+    "ts-node": "~8.6.2",
+    "tslint": "~5.20.1",
+    "typescript": "~3.5.0"
   },
   "resolutions": {
     "tree-kill": "1.2.2"
diff --git a/src/app/about/about.component.css b/src/app/about/about.component.css
new file mode 100644
index 0000000000000000000000000000000000000000..5b0d7dccc5371ab0350d50bf7bfddadcc41c2715
--- /dev/null
+++ b/src/app/about/about.component.css
@@ -0,0 +1,7 @@
+.mat-card {
+  margin: 10px;
+}
+
+.status {
+  background-color: lightgrey;
+}
diff --git a/src/app/about/about.component.html.ADMIN b/src/app/about/about.component.html.ADMIN
new file mode 100644
index 0000000000000000000000000000000000000000..86c3a142ed6ac57a8879a60a34be0401993d50f0
--- /dev/null
+++ b/src/app/about/about.component.html.ADMIN
@@ -0,0 +1,49 @@
+<div class="logo">
+  <a [routerLink]="['/']">
+    <img src="assets/IQB-LogoA.png" matTooltip="Startseite"/>
+  </a>
+</div>
+<div class="page-body">
+  <div fxLayout="row wrap" fxLayoutAlign="center stretch" style="padding: 30px;">
+    <mat-card fxFlex="0 2 500px">
+      <mat-card-title>IQB-Testcenter Verwaltung - Impressum/Datenschutz</mat-card-title>
+
+      <!-- - - - - - - - - - - - - - - - - -->
+      <mat-card-content>
+        <p>Das <a href="http://www.iqb.hu-berlin.de" target="_blank">Institut zur Qualitätsentwicklung im Bildungswesen</a>
+        betreibt auf diesen Seiten eine Pilotanwendung für das computerbasierte Leistungstesten von
+        Schülerinnen und Schülern. Dies ist die Web-Anwendung zur Verwaltung der Testinhalte und -ergebnisse.
+        Der Zugang ist nur möglich, wenn Sie vom IQB
+        Zugangsdaten erhalten haben. Es sind keine weiteren Seiten öffentlich verfügbar.</p>
+
+        <ul>
+          <li>Programmname: {{ appName }}</li>
+          <li>Programmversion: {{ appVersion }}</li>
+          <li>Copyright: {{ appPublisher }}</li>
+        </ul>
+
+        <p>
+            <em>Postanschrift:</em><br/>
+            Humboldt-Universität zu Berlin<br/>
+            Institut zur Qualitätsentwicklung im Bildungswesen<br/>
+            Unter den Linden 6<br/>
+            10099 Berlin</p>
+        <p>
+            <em>Sitz:</em><br/>
+            Luisenstr. 56<br/>
+            10117 Berlin<br/>
+            Tel: +49 [30] 2093 - 46500 (Zentrale)<br/>
+            Fax: +49 [30] 2093 - 46599<br/>
+            E-Mail: <a href="mailto:iqboffice@iqb.hu-berlin.de">iqboffice@iqb.hu-berlin.de</a>
+        </p>
+        <p>
+            <em>Name und Anschrift der Datenschutzbeauftragten</em><br/>
+            Frau Gesine Hoffmann-Holland<br/>
+            Tel: +49 (30) 2093-2591<br/>
+            E-Mail: datenschutz@uv.hu-berlin.de<br/>
+            <a href="http://www.hu-berlin.de/de/datenschutz" target="_blank">www.hu-berlin.de/de/datenschutz</a>
+        </p>
+      </mat-card-content>
+    </mat-card>
+  </div>
+</div>
diff --git a/src/app/about/about.component.html b/src/app/about/about.component.html.TC
similarity index 100%
rename from src/app/about/about.component.html
rename to src/app/about/about.component.html.TC
diff --git a/src/app/about/about.component.ts.ADMIN b/src/app/about/about.component.ts.ADMIN
new file mode 100644
index 0000000000000000000000000000000000000000..6c45d5de93054072f89c091fc0d81a5fe643aa3d
--- /dev/null
+++ b/src/app/about/about.component.ts.ADMIN
@@ -0,0 +1,13 @@
+import { Component, Inject } from '@angular/core';
+
+@Component({
+  templateUrl: './about.component.html',
+  styleUrls: ['./about.component.css']
+})
+export class AboutComponent {
+  constructor(
+    @Inject('APP_NAME') public appName: string,
+    @Inject('APP_PUBLISHER') public appPublisher: string,
+    @Inject('APP_VERSION') public appVersion: string
+  ) { }
+}
diff --git a/src/app/about/about.component.ts b/src/app/about/about.component.ts.TC
similarity index 100%
rename from src/app/about/about.component.ts
rename to src/app/about/about.component.ts.TC
diff --git a/src/app/app-routing.module.ts.ADMIN b/src/app/app-routing.module.ts.ADMIN
new file mode 100644
index 0000000000000000000000000000000000000000..055813bfcfbafed9ff15ba133be39bdd1ca6d252
--- /dev/null
+++ b/src/app/app-routing.module.ts.ADMIN
@@ -0,0 +1,21 @@
+import { AboutComponent } from './about/about.component';
+import { StartComponent } from './start/start.component';
+import { NgModule } from '@angular/core';
+import { Routes, RouterModule } from '@angular/router';
+import { WorkspaceComponent } from './workspace';
+
+
+const routes: Routes = [
+  {path: '', redirectTo: 'start', pathMatch: 'full'},
+  {path: 'start', component: StartComponent},
+  {path: 'about', component: AboutComponent},
+  // {path: 'ws', loadChildren: './workspace/workspace.module#WorkspaceModule'},
+  {path: 'ws', component: WorkspaceComponent},
+  {path: 'superadmin', loadChildren: './superadmin/superadmin.module#SuperadminModule'}
+];
+
+@NgModule({
+  imports: [RouterModule.forRoot(routes, {onSameUrlNavigation: 'reload'})],
+  exports: [RouterModule]
+})
+export class AppRoutingModule { }
diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts.TC
similarity index 100%
rename from src/app/app-routing.module.ts
rename to src/app/app-routing.module.ts.TC
diff --git a/src/app/app.component.scss.ADMIN b/src/app/app.component.scss.ADMIN
new file mode 100644
index 0000000000000000000000000000000000000000..cc857e228cbb688b27fcf764f225a3172e695599
--- /dev/null
+++ b/src/app/app.component.scss.ADMIN
@@ -0,0 +1,37 @@
+@import '~@angular/material/theming';
+@import '../iqb-theme2.scss';
+
+.itp-fill-remaining-space {
+  flex: 1 1 auto;
+}
+
+.mat-toolbar {
+  overflow: auto;
+  position: absolute;
+  width: 100%;
+  height: 70px;
+  font-family: inherit;
+  /* background-color: #003333; */
+  background: linear-gradient(to left, #003333, #045659, #0d7b84, #1aa2b2, #2acae5);
+  color: white;
+}
+
+mat-toolbar > span {
+  text-overflow: ellipsis;
+  white-space: nowrap;
+  overflow: hidden;
+}
+
+.logo {
+  width: 80px;
+  margin-right: 20px;
+  margin-top: 12px;
+}
+
+.material-icons {
+  font-size: 2.0rem;
+}
+
+.mat-button {
+  text-align: right;
+}
diff --git a/src/app/app.component.scss b/src/app/app.component.scss.TC
similarity index 100%
rename from src/app/app.component.scss
rename to src/app/app.component.scss.TC
diff --git a/src/app/app.component.spec.ts.ADMIN b/src/app/app.component.spec.ts.ADMIN
new file mode 100644
index 0000000000000000000000000000000000000000..1bd39e806dcbb5d54e5864e713d07289f50abe45
--- /dev/null
+++ b/src/app/app.component.spec.ts.ADMIN
@@ -0,0 +1,31 @@
+import { TestBed, async } from '@angular/core/testing';
+import { RouterTestingModule } from '@angular/router/testing';
+import { AppComponent } from './app.component';
+describe('AppComponent', () => {
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      imports: [
+        RouterTestingModule
+      ],
+      declarations: [
+        AppComponent
+      ],
+    }).compileComponents();
+  }));
+  it('should create the app', async(() => {
+    const fixture = TestBed.createComponent(AppComponent);
+    const app = fixture.debugElement.componentInstance;
+    expect(app).toBeTruthy();
+  }));
+  it(`should have as title 'app'`, async(() => {
+    const fixture = TestBed.createComponent(AppComponent);
+    const app = fixture.debugElement.componentInstance;
+    expect(app.title).toEqual('app');
+  }));
+  it('should render title in a h1 tag', async(() => {
+    const fixture = TestBed.createComponent(AppComponent);
+    fixture.detectChanges();
+    const compiled = fixture.debugElement.nativeElement;
+    expect(compiled.querySelector('h1').textContent).toContain('Welcome to itc-ng-admin!');
+  }));
+});
diff --git a/src/app/app.component.spec.ts b/src/app/app.component.spec.ts.TC
similarity index 100%
rename from src/app/app.component.spec.ts
rename to src/app/app.component.spec.ts.TC
diff --git a/src/app/app.component.ts.ADMIN b/src/app/app.component.ts.ADMIN
new file mode 100644
index 0000000000000000000000000000000000000000..3a8614b65e365fca8386a504ede395333e7c5f3b
--- /dev/null
+++ b/src/app/app.component.ts.ADMIN
@@ -0,0 +1,40 @@
+import { LoginData } from './app.interfaces';
+import { BackendService } from './backend.service';
+import { ServerError } from 'iqb-components';
+import { Component, OnInit } from '@angular/core';
+import { MainDataService } from './maindata.service';
+
+@Component({
+  selector: 'app-root',
+  template: `<router-outlet></router-outlet>`,
+  styleUrls: ['./app.component.scss']
+})
+
+
+export class AppComponent implements OnInit {
+
+  constructor (
+    private mds: MainDataService,
+    private bs: BackendService) { }
+
+  ngOnInit() {
+    const adminToken = localStorage.getItem('at');
+    if (adminToken !== null) {
+      if (adminToken.length > 0) {
+        this.bs.getLoginData(adminToken).subscribe(
+          (admindata: LoginData) => {
+            this.mds.setNewLoginData(admindata);
+          }, (err: ServerError) => {
+            this.mds.setNewLoginData();
+            console.log(err);
+            this.mds.globalErrorMsg$.next(err);
+          }
+        );
+      } else {
+        this.mds.setNewLoginData();
+      }
+    } else {
+      this.mds.setNewLoginData();
+    }
+  }
+}
diff --git a/src/app/app.component.ts b/src/app/app.component.ts.TC
similarity index 100%
rename from src/app/app.component.ts
rename to src/app/app.component.ts.TC
diff --git a/src/app/app.interceptor.ts.ADMIN b/src/app/app.interceptor.ts.ADMIN
new file mode 100644
index 0000000000000000000000000000000000000000..2e8cf43af2fa2b39043a9fce57d554fe1db1d479
--- /dev/null
+++ b/src/app/app.interceptor.ts.ADMIN
@@ -0,0 +1,29 @@
+import { MainDataService } from './maindata.service';
+import { Injectable } from '@angular/core';
+import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http';
+import { Observable } from 'rxjs';
+
+@Injectable()
+
+export class AuthInterceptor implements HttpInterceptor {
+  constructor(public mds: MainDataService) {}
+
+  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
+    const loginData = this.mds.loginData$.getValue();
+    if (loginData !== null) {
+      const authDataStr = request.headers.get('AuthToken');
+      let authData = {};
+      if (authDataStr) {
+        authData = JSON.parse(authDataStr);
+      }
+      authData['at'] = loginData.admintoken;
+      return next.handle(request.clone({
+        setHeaders: {
+          AuthToken: JSON.stringify(authData)
+        }
+      }));
+    } else {
+      return next.handle(request);
+    }
+  }
+}
diff --git a/src/app/app.interceptor.ts b/src/app/app.interceptor.ts.TC
similarity index 100%
rename from src/app/app.interceptor.ts
rename to src/app/app.interceptor.ts.TC
diff --git a/src/app/app.interfaces.ts.ADMIN b/src/app/app.interfaces.ts.ADMIN
new file mode 100644
index 0000000000000000000000000000000000000000..2b1568e07e768d6139e7620a32d1c47f053bb274
--- /dev/null
+++ b/src/app/app.interfaces.ts.ADMIN
@@ -0,0 +1,12 @@
+export interface WorkspaceData {
+  id: number;
+  name: string;
+  role: string;
+}
+
+export interface LoginData {
+  admintoken: string;
+  name: string;
+  workspaces: WorkspaceData[];
+  is_superadmin: boolean;
+}
diff --git a/src/app/app.interfaces.ts b/src/app/app.interfaces.ts.TC
similarity index 100%
rename from src/app/app.interfaces.ts
rename to src/app/app.interfaces.ts.TC
diff --git a/src/app/app.module.ts.ADMIN b/src/app/app.module.ts.ADMIN
new file mode 100644
index 0000000000000000000000000000000000000000..f418079254ed4676d2dbc52feeaf8e3cdc16679a
--- /dev/null
+++ b/src/app/app.module.ts.ADMIN
@@ -0,0 +1,76 @@
+import { AboutComponent } from './about/about.component';
+import { BrowserModule } from '@angular/platform-browser';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';
+import { NgModule} from '@angular/core';
+import { LocationStrategy, HashLocationStrategy } from '@angular/common';
+import { ReactiveFormsModule } from '@angular/forms';
+import { BackendService } from './backend.service';
+
+import { MatButtonModule } from '@angular/material/button';
+import { MatCardModule } from '@angular/material/card';
+import { MatCheckboxModule } from '@angular/material/checkbox';
+import { MatDialogModule } from '@angular/material/dialog';
+import { MatFormFieldModule } from '@angular/material/form-field';
+import { MatIconModule } from '@angular/material/icon';
+import { MatInputModule } from '@angular/material/input';
+import { MatMenuModule } from '@angular/material/menu';
+import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
+import { MatTabsModule } from '@angular/material/tabs';
+import { MatToolbarModule } from '@angular/material/toolbar';
+import { MatTooltipModule } from '@angular/material/tooltip';
+
+import { AppComponent } from './app.component';
+import { AppRoutingModule } from './app-routing.module';
+
+import { StartComponent } from './start/start.component';
+import { FlexLayoutModule } from '@angular/flex-layout';
+import { IqbComponentsModule } from 'iqb-components';
+import { AuthInterceptor } from './app.interceptor';
+import { WorkspaceModule } from './workspace';
+
+@NgModule({
+  declarations: [
+    AppComponent,
+    StartComponent,
+    AboutComponent
+  ],
+  imports: [
+    BrowserModule,
+    BrowserAnimationsModule,
+    FlexLayoutModule,
+    MatButtonModule,
+    MatFormFieldModule,
+    MatMenuModule,
+    MatToolbarModule,
+    MatIconModule,
+    MatInputModule,
+    FlexLayoutModule,
+    MatCheckboxModule,
+    MatTooltipModule,
+    MatDialogModule,
+    MatTabsModule,
+    ReactiveFormsModule,
+    HttpClientModule,
+    AppRoutingModule,
+    IqbComponentsModule,
+    MatCardModule,
+    MatProgressSpinnerModule,
+    FlexLayoutModule,
+    WorkspaceModule
+  ],
+  providers: [
+    {
+      provide: LocationStrategy,
+      useClass: HashLocationStrategy
+    },
+    BackendService,
+    {
+      provide: HTTP_INTERCEPTORS,
+      useClass: AuthInterceptor,
+      multi: true
+    }
+  ],
+  bootstrap: [AppComponent]
+})
+export class AppModule { }
diff --git a/src/app/app.module.ts b/src/app/app.module.ts.TC
similarity index 100%
rename from src/app/app.module.ts
rename to src/app/app.module.ts.TC
diff --git a/src/app/backend.service.ts.ADMIN b/src/app/backend.service.ts.ADMIN
new file mode 100644
index 0000000000000000000000000000000000000000..8b23dd41e5fad8bebdc5756c0a5fde989fffff5d
--- /dev/null
+++ b/src/app/backend.service.ts.ADMIN
@@ -0,0 +1,34 @@
+import { LoginData } from './app.interfaces';
+import { Injectable, Inject } from '@angular/core';
+import { HttpClient } from '@angular/common/http';
+import { Observable } from 'rxjs';
+import { catchError } from 'rxjs/operators';
+import { ErrorHandler, ServerError } from 'iqb-components';
+
+
+@Injectable()
+export class BackendService {
+
+  constructor(
+      @Inject('SERVER_URL') private serverUrl: string,
+      private http: HttpClient) {
+
+    this.serverUrl = this.serverUrl + 'php/';
+  }
+
+  login(name: string, password: string): Observable<LoginData | ServerError> {
+    return this.http
+      .post<LoginData>(this.serverUrl + 'login.php/login', {n: name, p: password})
+        .pipe(
+          catchError(ErrorHandler.handle)
+        );
+  }
+
+  getLoginData(adminToken: string): Observable<LoginData | ServerError> {
+    return this.http
+      .post<LoginData>(this.serverUrl + 'login.php/login', {at: adminToken})
+        .pipe(
+          catchError(ErrorHandler.handle)
+        );
+  }
+}
diff --git a/src/app/backend.service.ts b/src/app/backend.service.ts.TC
similarity index 100%
rename from src/app/backend.service.ts
rename to src/app/backend.service.ts.TC
diff --git a/src/app/iqb-files/index.ts b/src/app/iqb-files/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b9095370f6a7600269b5a9319c12e14fb3df7392
--- /dev/null
+++ b/src/app/iqb-files/index.ts
@@ -0,0 +1,3 @@
+export { IqbFilesUploadQueueComponent } from './iqbFilesUploadQueue/iqbFilesUploadQueue.component';
+export { IqbFilesUploadInputForDirective } from  './iqbFilesUploadInputFor/iqbFilesUploadInputFor.directive';
+export { IqbFilesModule } from './iqb-files.module';
diff --git a/src/app/iqb-files/iqb-files.module.ts b/src/app/iqb-files/iqb-files.module.ts
new file mode 100644
index 0000000000000000000000000000000000000000..49b63fb587da935f2f22c2c03d8f1ecab090cb1a
--- /dev/null
+++ b/src/app/iqb-files/iqb-files.module.ts
@@ -0,0 +1,33 @@
+import { NgModule } from '@angular/core';
+import { IqbFilesUploadComponent } from './iqbFilesUpload/iqbFilesUpload.component';
+import { IqbFilesUploadQueueComponent } from './iqbFilesUploadQueue/iqbFilesUploadQueue.component';
+import { IqbFilesUploadInputForDirective } from './iqbFilesUploadInputFor/iqbFilesUploadInputFor.directive';
+
+import { MatButtonModule } from '@angular/material/button';
+import { MatCardModule } from '@angular/material/card';
+import { MatProgressBarModule } from '@angular/material/progress-bar';
+import { MatIconModule } from '@angular/material/icon';
+import { CommonModule } from '@angular/common';
+import { IqbComponentsModule } from 'iqb-components';
+
+
+@NgModule({
+  imports: [
+    MatButtonModule,
+    MatProgressBarModule,
+    MatIconModule,
+    MatCardModule,
+    IqbComponentsModule,
+    CommonModule
+  ],
+  declarations: [
+    IqbFilesUploadComponent,
+    IqbFilesUploadQueueComponent,
+    IqbFilesUploadInputForDirective
+  ],
+  exports: [
+    IqbFilesUploadQueueComponent,
+    IqbFilesUploadInputForDirective,
+  ]
+})
+export class IqbFilesModule { }
diff --git a/src/app/iqb-files/iqb-files.scss b/src/app/iqb-files/iqb-files.scss
new file mode 100644
index 0000000000000000000000000000000000000000..a7b1fc4369a18093f0532b9713b9a937046f13ff
--- /dev/null
+++ b/src/app/iqb-files/iqb-files.scss
@@ -0,0 +1,61 @@
+
+
+.dropzone {
+    background-color: brown;
+    width: 100px;
+    height: 100px;
+}
+
+
+mat-card {
+  padding: 15px;
+}
+
+.example-section {
+  display: flex;
+  align-content: center;
+  align-items: center;
+  height: 10px;
+}
+
+.file-info, .file-info-error {
+  font-size: .85rem;
+}
+
+.file-info-error {
+  color: red;
+}
+
+#drop_zone {
+  border: 5px solid blue;
+  width:  200px;
+  height: 100px;
+}
+
+.action {
+  cursor: pointer;
+  outline: none;
+}
+
+a.disabled {
+  pointer-events: none;
+}
+
+.upload-drop-zone {
+  height: 200px;
+  border-width: 2px;
+  margin-bottom: 20px;
+}
+
+/* skin.css Style*/
+.upload-drop-zone {
+  color: #ccc;
+  border-style: dashed;
+  border-color: #ccc;
+  line-height: 200px;
+  text-align: center
+}
+.upload-drop-zone.drop {
+  color: #222;
+  border-color: #222;
+}
diff --git a/src/app/iqb-files/iqbFilesUpload/iqbFilesUpload.component.html b/src/app/iqb-files/iqbFilesUpload/iqbFilesUpload.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..4307132f325359e92d09cc835d9ed9ce0a1c4953
--- /dev/null
+++ b/src/app/iqb-files/iqbFilesUpload/iqbFilesUpload.component.html
@@ -0,0 +1,13 @@
+<mat-card>
+    <span class="file-info">{{file.name}} ({{file.size | bytes}})</span>
+    <section *ngIf="status<=1" class="example-section">
+        <mat-progress-bar class="example-margin" [value]="progressPercentage"></mat-progress-bar>
+        <a *ngIf="status == 0"><mat-icon class="action" (click)="upload()">file_upload</mat-icon></a>
+        <mat-icon class="action" (click)="remove()">cancel</mat-icon>
+    </section>
+    <span *ngIf="status == 1" class="file-info">{{progressPercentage}} %</span><br/>
+    <span *ngIf="status != 1">
+      <span *ngIf="status == 3" class="file-info-error">{{statustext}}</span>
+      <span *ngIf="status != 3" class="file-info">{{statustext}}</span>
+    </span>
+</mat-card>
diff --git a/src/app/iqb-files/iqbFilesUpload/iqbFilesUpload.component.ts b/src/app/iqb-files/iqbFilesUpload/iqbFilesUpload.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..bafd647b1b5c404deef2324a774a3c943cf1c8ad
--- /dev/null
+++ b/src/app/iqb-files/iqbFilesUpload/iqbFilesUpload.component.ts
@@ -0,0 +1,190 @@
+import { Component, EventEmitter, Input, OnInit, Output, HostBinding } from '@angular/core';
+import { HttpClient, HttpEventType, HttpHeaders, HttpParams,
+  HttpErrorResponse, HttpEvent } from '@angular/common/http';
+
+
+@Component({
+    selector: 'iqb-files-upload',
+    templateUrl: `./iqbFilesUpload.component.html`,
+    exportAs: 'iqbFilesUpload',
+    styleUrls: ['./../iqb-files.scss'],
+  })
+
+  export class IqbFilesUploadComponent implements OnInit {
+    @HostBinding('class') myclass = 'iqb-files-upload';
+
+    constructor(
+      private myHttpClient: HttpClient) { }
+
+    // ''''''''''''''''''''''''
+    private _status: UploadStatus;
+    get status(): UploadStatus {
+      return this._status;
+    }
+
+    set status(newstatus: UploadStatus) {
+      this._status = newstatus;
+      this.statusChangedEvent.emit(this);
+    }
+
+    // ''''''''''''''''''''''''
+    private requestResponseText: string;
+    get statustext(): string {
+      let myreturn = '';
+      switch (this._status) {
+        case UploadStatus.busy: {
+          myreturn = 'Bitte warten';
+          break;
+        }
+        case UploadStatus.ready: {
+          myreturn = 'Bereit';
+          break;
+        }
+        default: {
+          myreturn = this.requestResponseText;
+          break;
+        }
+      }
+      return myreturn;
+    }
+
+    /* Http request input bindings */
+    @Input()
+    httpUrl = 'http://localhost:8080';
+
+    @Input()
+    httpRequestHeaders: HttpHeaders | {
+      [header: string]: string | string[];
+    } = new HttpHeaders().set('Content-Type', 'multipart/form-data');
+
+    @Input()
+    httpRequestParams: HttpParams | {
+      [param: string]: string | string[];
+    } = new HttpParams();
+
+    @Input()
+    fileAlias = 'file';
+
+    @Input()
+    tokenName = '';
+
+    @Input()
+    token = '';
+
+    @Input()
+    folderName = '';
+
+    @Input()
+    folder = '';
+
+    @Input()
+    get file(): any {
+      return this._file;
+    }
+    set file(file: any) {
+      this._file = file;
+      this._filedate = this._file.lastModified;
+      this.total = this._file.size;
+    }
+
+    @Input()
+    set id(id: number) {
+      this._id = id;
+    }
+
+    get id(): number {
+      return this._id;
+    }
+
+    @Output() removeFileRequestEvent = new EventEmitter<IqbFilesUploadComponent>();
+    @Output() statusChangedEvent = new EventEmitter<IqbFilesUploadComponent>();
+
+    private progressPercentage = 0;
+    public loaded = 0;
+    private total = 0;
+    private _file: any;
+    private _filedate = '';
+    private _id: number;
+    private fileUploadSubscription: any;
+
+
+    ngOnInit() {
+      this._status = UploadStatus.ready;
+      this.requestResponseText = '';
+      this.upload();
+    }
+
+    // ==================================================================
+    private upload(): void {
+      if (this.status === UploadStatus.ready) {
+
+        this.status = UploadStatus.busy;
+        const formData = new FormData();
+        formData.set(this.fileAlias, this._file, this._file.name);
+        if ((typeof this.tokenName !== 'undefined') && (typeof this.token !== 'undefined')) {
+          if (this.tokenName.length > 0) {
+            formData.append(this.tokenName, this.token);
+          }
+        }
+        if ((typeof this.folderName !== 'undefined') && (typeof this.folder !== 'undefined')) {
+          if (this.folderName.length > 0) {
+            formData.append(this.folderName, this.folder);
+          }
+        }
+        this.fileUploadSubscription = this.myHttpClient.post(this.httpUrl, formData, {
+        // headers: this.httpRequestHeaders,
+          observe: 'events',
+          params: this.httpRequestParams,
+          reportProgress: true,
+          responseType: 'json'
+        }).subscribe((event: HttpEvent<any>) => {
+          if (event.type === HttpEventType.UploadProgress) {
+            this.progressPercentage = Math.floor( event.loaded * 100 / event.total );
+            this.loaded = event.loaded;
+            this.total = event.total;
+            this.status = UploadStatus.busy;
+          } else if (event.type === HttpEventType.Response) {
+            this.requestResponseText = event.body;
+            if ((this.requestResponseText.length > 5) && (this.requestResponseText.substr(0, 2) === 'e:')) {
+              this.requestResponseText = this.requestResponseText.substr(2);
+              this.status = UploadStatus.error;
+            } else {
+              this.status = UploadStatus.ok;
+              this.remove();
+            }
+          }
+        }, (errorObj: HttpErrorResponse) => {
+          if (this.fileUploadSubscription) {
+            this.fileUploadSubscription.unsubscribe();
+          }
+
+          this.status = UploadStatus.error;
+          if (errorObj.status === 401) {
+            this.requestResponseText = 'Fehler: Zugriff verweigert - bitte (neu) anmelden!';
+          } else if (errorObj.status === 503) {
+            this.requestResponseText = 'Fehler: Server meldet Problem mit Datenbank oder Datei zu groß.';
+          } else if (errorObj.error instanceof ErrorEvent) {
+            this.requestResponseText = 'Fehler: ' + (<ErrorEvent>errorObj.error).message;
+          } else {
+            this.requestResponseText = 'Fehler: ' + errorObj.message;
+          }
+        });
+      }
+    }
+
+    // ==================================================================
+    public remove(): void {
+      if (this.fileUploadSubscription) {
+        this.fileUploadSubscription.unsubscribe();
+      }
+      this.removeFileRequestEvent.emit(this);
+    }
+
+}
+
+export enum UploadStatus {
+  ready,
+  busy,
+  ok,
+  error
+}
diff --git a/src/app/iqb-files/iqbFilesUploadInputFor/iqbFilesUploadInputFor.directive.ts b/src/app/iqb-files/iqbFilesUploadInputFor/iqbFilesUploadInputFor.directive.ts
new file mode 100644
index 0000000000000000000000000000000000000000..5f2bc7d5b0e10acb6a1241bc01654155edacb1cf
--- /dev/null
+++ b/src/app/iqb-files/iqbFilesUploadInputFor/iqbFilesUploadInputFor.directive.ts
@@ -0,0 +1,59 @@
+import { Component, Directive, ElementRef, EventEmitter, HostListener,
+    Input, OnDestroy, OnInit, Output } from '@angular/core';
+
+
+  @Directive({
+    selector: 'input[iqbFilesUploadInputFor], div[iqbFilesUploadInputFor]',
+  })
+  export class IqbFilesUploadInputForDirective  {
+
+
+    private _queue: any = null;
+    private _element: HTMLElement;
+
+    // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+    constructor(private element: ElementRef) {
+        this._element = this.element.nativeElement;
+    }
+
+
+    @Input('iqbFilesUploadInputFor')
+    set filesUploadQueue(value: any) {
+        if (value) {
+            this._queue = value;
+        }
+    }
+
+    // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+    @HostListener('change')
+    public onChange(): any {
+      const files = this.element.nativeElement.files;
+      // this.onFileSelected.emit(files);
+
+      for (let i = 0; i < files.length; i++) {
+        this._queue.add(files[i]);
+      }
+      this.element.nativeElement.value = '';
+    }
+
+    // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+    @HostListener('drop', [ '$event' ])
+    public onDrop(event: any): any {
+      const files = event.dataTransfer.files;
+      // this.onFileSelected.emit(files);
+
+      for (let i = 0; i < files.length; i++) {
+        this._queue.add(files[i]);
+      }
+      event.preventDefault();
+      event.stopPropagation();
+      this.element.nativeElement.value = '';
+    }
+
+    // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+    @HostListener('dragover', [ '$event' ])
+    public onDropOver(event: any): any {
+      event.preventDefault();
+    }
+
+  }
diff --git a/src/app/iqb-files/iqbFilesUploadQueue/iqbFilesUploadQueue.component.html b/src/app/iqb-files/iqbFilesUploadQueue/iqbFilesUploadQueue.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..e40725e94508c59fb46ba55841108853e8ecca03
--- /dev/null
+++ b/src/app/iqb-files/iqbFilesUploadQueue/iqbFilesUploadQueue.component.html
@@ -0,0 +1,17 @@
+<iqb-files-upload
+  [file]="file"
+  [id]="i"
+  *ngFor="let file of files; let i = index"
+  [httpUrl]="httpUrl"
+  [fileAlias]="fileAlias"
+  [tokenName]="tokenName"
+  [token]="token"
+  [folderName]="folderName"
+  [folder]="folder"
+
+  (removeFileRequestEvent)="removeFile($event)"
+  (statusChangedEvent)="analyseStatus()">
+</iqb-files-upload>
+<br/>
+<button mat-raised-button color="primary" *ngIf="files.length > 0" [disabled]="disableClearButton"
+  (click)="removeAll()">OK</button>
diff --git a/src/app/iqb-files/iqbFilesUploadQueue/iqbFilesUploadQueue.component.ts b/src/app/iqb-files/iqbFilesUploadQueue/iqbFilesUploadQueue.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..9bd7df6004e7c96e94dd6d21619f6d9e0f160c9e
--- /dev/null
+++ b/src/app/iqb-files/iqbFilesUploadQueue/iqbFilesUploadQueue.component.ts
@@ -0,0 +1,108 @@
+import { Component, EventEmitter, OnInit, OnDestroy, QueryList, ViewChildren, Input, Output } from '@angular/core';
+import { IqbFilesUploadComponent, UploadStatus } from '../iqbFilesUpload/iqbFilesUpload.component';
+import { HttpHeaders, HttpParams } from '@angular/common/http';
+
+
+/**
+ * A material design file upload queue component.
+ */
+@Component({
+    selector: 'iqb-files-upload-queue',
+    templateUrl: `iqbFilesUploadQueue.component.html`,
+    exportAs: 'iqbFilesUploadQueue',
+  })
+  export class IqbFilesUploadQueueComponent implements OnDestroy {
+
+    @ViewChildren(IqbFilesUploadComponent) fileUploads: QueryList<IqbFilesUploadComponent>;
+
+    public files: Array<any> = [];
+    private numberOfErrors = 0;
+    private numberOfUploads = 0;
+    private disableClearButton = true;
+
+    /* Http request input bindings */
+    @Input()
+    httpUrl: string;
+
+    @Input()
+    httpRequestHeaders: HttpHeaders | {
+      [header: string]: string | string[];
+    } = new HttpHeaders().set('Content-Type', 'multipart/form-data');
+
+    @Input()
+    httpRequestParams: HttpParams | {
+      [param: string]: string | string[];
+    } = new HttpParams();
+
+    @Input()
+    fileAlias: string;
+
+    @Input()
+    tokenName: string;
+
+    @Input()
+    token: string;
+
+    @Input()
+    folderName: string;
+
+    @Input()
+    folder: string;
+
+    @Output() uploadCompleteEvent = new EventEmitter<IqbFilesUploadQueueComponent>();
+
+    // +++++++++++++++++++++++++++++++++++++++++++++++++
+    add(file: any) {
+      this.files.push(file);
+    }
+
+    // +++++++++++++++++++++++++++++++++++++++++++++++++
+    public removeAll() {
+      this.files.splice(0, this.files.length);
+    }
+
+    // +++++++++++++++++++++++++++++++++++++++++++++++++
+    ngOnDestroy() {
+      if (this.files) {
+        this.removeAll();
+      }
+    }
+
+    // +++++++++++++++++++++++++++++++++++++++++++++++++
+    removeFile(fileToRemove: IqbFilesUploadComponent) {
+      this.files.splice(fileToRemove.id, 1);
+    }
+
+/*    // +++++++++++++++++++++++++++++++++++++++++++++++++
+    updateStatus() {
+      this.numberOfErrors = 0;
+      this.numberOfUploads = 0;
+
+      this.fileUploads.forEach((fileUpload) => {
+
+        fileUpload.upload();
+      });
+    } */
+
+    // +++++++++++++++++++++++++++++++++++++++++++++++++
+    analyseStatus() {
+      let someoneiscomplete = false;
+      let someoneisbusy = false;
+      let someoneisready = false;
+      this.fileUploads.forEach((fileUpload) => {
+        if ((fileUpload.status === UploadStatus.ok) || (fileUpload.status === UploadStatus.error)) {
+          someoneiscomplete = true;
+        } else if (fileUpload.status === UploadStatus.busy) {
+          someoneisbusy = true;
+          return; // forEach
+        } else if (fileUpload.status === UploadStatus.ready) {
+          someoneisready = true;
+        }
+      });
+
+      if (someoneiscomplete && !someoneisbusy) {
+        this.uploadCompleteEvent.emit();
+        this.disableClearButton = false;
+      }
+    }
+}
diff --git a/src/app/maindata.service.spec.ts.ADMIN b/src/app/maindata.service.spec.ts.ADMIN
new file mode 100644
index 0000000000000000000000000000000000000000..16e5e0e6d4e1d7660637c67c77a2cb8ff736d88c
--- /dev/null
+++ b/src/app/maindata.service.spec.ts.ADMIN
@@ -0,0 +1,12 @@
+import { TestBed } from '@angular/core/testing';
+
+import { MainDataService } from './maindata.service';
+
+describe('MaindataService', () => {
+  beforeEach(() => TestBed.configureTestingModule({}));
+
+  it('should be created', () => {
+    const service: MainDataService = TestBed.get(MainDataService);
+    expect(service).toBeTruthy();
+  });
+});
diff --git a/src/app/maindata.service.spec.ts b/src/app/maindata.service.spec.ts.TC
similarity index 100%
rename from src/app/maindata.service.spec.ts
rename to src/app/maindata.service.spec.ts.TC
diff --git a/src/app/maindata.service.ts.ADMIN b/src/app/maindata.service.ts.ADMIN
new file mode 100644
index 0000000000000000000000000000000000000000..7b011a327efb27a446991e175b28348077d56d9a
--- /dev/null
+++ b/src/app/maindata.service.ts.ADMIN
@@ -0,0 +1,88 @@
+import { BehaviorSubject } from 'rxjs';
+import { LoginData } from './app.interfaces';
+import { Injectable } from '@angular/core';
+import { ServerError } from 'iqb-components';
+
+@Injectable({
+  providedIn: 'root'
+})
+export class MainDataService {
+  private static defaultLoginData: LoginData = {
+    admintoken: '',
+    name: '',
+    workspaces: [],
+    is_superadmin: false
+  };
+
+  public get adminToken(): string {
+    const myLoginData = this.loginData$.getValue();
+    if (myLoginData) {
+      return myLoginData.admintoken;
+    } else {
+      return '';
+    }
+  }
+
+
+  public loginData$ = new BehaviorSubject<LoginData>(MainDataService.defaultLoginData);
+  public globalErrorMsg$ = new BehaviorSubject<ServerError>(null);
+
+
+  setNewLoginData(logindata?: LoginData) {
+    const myLoginData: LoginData = {
+      admintoken: MainDataService.defaultLoginData.admintoken,
+      name: MainDataService.defaultLoginData.name,
+      workspaces: MainDataService.defaultLoginData.workspaces,
+      is_superadmin: MainDataService.defaultLoginData.is_superadmin
+    };
+
+    if (logindata) {
+      if (
+        (logindata.admintoken.length > 0) &&
+        (logindata.name.length > 0)) {
+          myLoginData.admintoken = logindata.admintoken;
+          myLoginData.name = logindata.name;
+          myLoginData.workspaces = logindata.workspaces;
+          myLoginData.is_superadmin = logindata.is_superadmin;
+      }
+    }
+    this.loginData$.next(myLoginData);
+    localStorage.setItem('at', myLoginData.admintoken);
+  }
+
+  setNewErrorMsg(err: ServerError = null) {
+    this.globalErrorMsg$.next(err);
+  }
+
+  getWorkspaceName(ws: number): string {
+    let myreturn = '';
+    if (ws > 0) {
+      const myLoginData = this.loginData$.getValue();
+      if ((myLoginData !== null) && (myLoginData.workspaces.length > 0)) {
+        for (let i = 0; i < myLoginData.workspaces.length; i++) {
+          if (myLoginData.workspaces[i].id == ws) {
+            myreturn = myLoginData.workspaces[i].name;
+            break;
+          }
+        }
+      }
+    }
+    return myreturn;
+  }
+
+  getWorkspaceRole(ws: number): string {
+    let myreturn = '';
+    if (ws > 0) {
+      const myLoginData = this.loginData$.getValue();
+      if ((myLoginData !== null) && (myLoginData.workspaces.length > 0)) {
+        for (let i = 0; i < myLoginData.workspaces.length; i++) {
+          if (myLoginData.workspaces[i].id == ws) {
+            myreturn = myLoginData.workspaces[i].role;
+            break;
+          }
+        }
+      }
+    }
+    return myreturn;
+  }
+}
diff --git a/src/app/maindata.service.ts b/src/app/maindata.service.ts.TC
similarity index 100%
rename from src/app/maindata.service.ts
rename to src/app/maindata.service.ts.TC
diff --git a/src/app/start/start.component.css.ADMIN b/src/app/start/start.component.css.ADMIN
new file mode 100644
index 0000000000000000000000000000000000000000..5b0d7dccc5371ab0350d50bf7bfddadcc41c2715
--- /dev/null
+++ b/src/app/start/start.component.css.ADMIN
@@ -0,0 +1,7 @@
+.mat-card {
+  margin: 10px;
+}
+
+.status {
+  background-color: lightgrey;
+}
diff --git a/src/app/start/start.component.css b/src/app/start/start.component.css.TC
similarity index 100%
rename from src/app/start/start.component.css
rename to src/app/start/start.component.css.TC
diff --git a/src/app/start/start.component.html.ADMIN b/src/app/start/start.component.html.ADMIN
new file mode 100644
index 0000000000000000000000000000000000000000..269a124b4213bfc3bc0761e9bc480186e6769e88
--- /dev/null
+++ b/src/app/start/start.component.html.ADMIN
@@ -0,0 +1,74 @@
+<div class="logo">
+  <a [routerLink]="['/']">
+    <img src="assets/IQB-LogoA.png" matTooltip="Startseite"/>
+  </a>
+</div>
+<div class="page-body">
+  <div fxLayout="row wrap" fxLayoutAlign="center stretch" style="padding: 30px;">
+
+
+    <!-- XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX -->
+    <mat-card fxFlex="0 0 400px" fxLayout="column" *ngIf="showLogin">
+      <!-- - - - - - - - - - - - - - - - - -->
+      <form [formGroup]="adminloginform" (ngSubmit)="login()">
+        <mat-card-title>Anmelden</mat-card-title>
+        <mat-card-content fxLayout="column">
+          <mat-form-field>
+            <input matInput formControlName="testname" placeholder="Anmeldename" (keyup.enter)="pw.focus()">
+          </mat-form-field>
+          <mat-form-field>
+            <input matInput #pw type="password" formControlName="testpw" placeholder="Kennwort" (keyup.enter)="login()">
+          </mat-form-field>
+        </mat-card-content>
+        <mat-card-actions>
+          <button mat-raised-button type="submit" [disabled]="adminloginform.invalid" color="primary">Weiter</button>
+        </mat-card-actions>
+      </form>
+      <p class="error-msg">{{ (mds.globalErrorMsg$ | async)?.labelNice }}</p>
+    </mat-card>
+
+    <mat-card fxFlex="0 0 400px" fxLayout="column" *ngIf="!showLogin">
+      <mat-card-title>Studie wählen</mat-card-title>
+      <mat-card-content>
+        <div fxLayout="row" fxLayoutGap="10px" fxLayout="column">
+          <p *ngIf="(mds.loginData$ | async)?.workspaces.length === 0">
+            Für diese Anmeldung wurden keine Studien gefunden.
+          </p>
+          <button mat-raised-button color="primary" (click)="buttonGotoWorkspace(ws)"
+            *ngFor="let ws of (mds.loginData$ | async)?.workspaces">
+              {{ws.name}}
+          </button>
+        </div>
+      </mat-card-content>
+      <mat-card-actions>
+        <button mat-raised-button color="foreground" *ngIf="(mds.loginData$ | async)?.is_superadmin" [routerLink]="['/superadmin']">Nutzer/Arbeitsbereiche</button>
+        <button mat-raised-button color="foreground" (click)="mds.setNewLoginData()">Anmeldung ändern</button>
+      </mat-card-actions>
+    </mat-card>
+
+    <!-- XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX -->
+    <mat-card fxFlex="0 2 400px" fxLayout="column" class="status">
+      <mat-card-title>IQB-Testcenter Verwaltung</mat-card-title>
+
+      <!-- - - - - - - - - - - - - - - - - -->
+      <mat-card-content>
+        <div>
+          <p>Das <a href="http://www.iqb.hu-berlin.de" target="_blank">Institut zur Qualitätsentwicklung im Bildungswesen</a>
+            betreibt auf diesen Seiten eine Pilotanwendung für das computerbasierte Leistungstesten von
+            Schülerinnen und Schülern. Dies ist die Web-Anwendung zur Verwaltung der Testinhalte und -ergebnisse.
+            Der Zugang ist nur möglich, wenn Sie vom IQB
+            Zugangsdaten erhalten haben. Es sind keine weiteren Seiten öffentlich verfügbar.</p>
+        </div>
+        <div *ngIf="!showLogin">
+          <ul>
+            <li>angemeldet als: {{ (mds.loginData$ | async)?.name }}</li>
+            <li *ngIf="(mds.loginData$ | async)?.is_superadmin">zum Ändern von Nutzerrechten und Arbeitsbereichen berechtigt</li>
+          </ul>
+        </div>
+      </mat-card-content>
+      <mat-card-actions>
+        <button mat-raised-button color="foreground" [routerLink]="['/about']">Impressum/Datenschutz</button>
+      </mat-card-actions>
+    </mat-card>
+  </div>
+</div>
diff --git a/src/app/start/start.component.html b/src/app/start/start.component.html.TC
similarity index 100%
rename from src/app/start/start.component.html
rename to src/app/start/start.component.html.TC
diff --git a/src/app/start/start.component.spec.ts.ADMIN b/src/app/start/start.component.spec.ts.ADMIN
new file mode 100644
index 0000000000000000000000000000000000000000..10f012b9c1cdefa4501e30a907b3d4dbb54f24cc
--- /dev/null
+++ b/src/app/start/start.component.spec.ts.ADMIN
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { StartComponent } from './start.component';
+
+describe('HomeComponent', () => {
+  let component: StartComponent;
+  let fixture: ComponentFixture<StartComponent>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ StartComponent ]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(StartComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/src/app/start/start.component.spec.ts b/src/app/start/start.component.spec.ts.TC
similarity index 100%
rename from src/app/start/start.component.spec.ts
rename to src/app/start/start.component.spec.ts.TC
diff --git a/src/app/start/start.component.ts.ADMIN b/src/app/start/start.component.ts.ADMIN
new file mode 100644
index 0000000000000000000000000000000000000000..275c0388fd3bcc77dca2734bb4e9f34d7e9c92d9
--- /dev/null
+++ b/src/app/start/start.component.ts.ADMIN
@@ -0,0 +1,64 @@
+import { LoginData, WorkspaceData } from '../app.interfaces';
+import { BackendService } from '../backend.service';
+import { MainDataService } from '../maindata.service';
+import { Router } from '@angular/router';
+import { Component, OnInit, OnDestroy } from '@angular/core';
+import { FormGroup, FormBuilder, Validators } from '@angular/forms';
+import { Subscription } from 'rxjs';
+import { ServerError } from 'iqb-components';
+
+
+@Component({
+  templateUrl: './start.component.html',
+  styleUrls: ['./start.component.css']
+})
+export class StartComponent implements OnInit, OnDestroy {
+  adminloginform: FormGroup;
+  private loginDataSubscription: Subscription = null;
+  public showLogin = true;
+
+  constructor(private fb: FormBuilder,
+    private mds: MainDataService,
+    private bs: BackendService,
+    private router: Router) { }
+
+  ngOnInit() {
+    this.adminloginform = this.fb.group({
+      testname: this.fb.control('', [Validators.required, Validators.minLength(3)]),
+      testpw: this.fb.control('', [Validators.required, Validators.minLength(3)])
+    });
+    this.loginDataSubscription = this.mds.loginData$.subscribe(logindata => {
+      this.showLogin = logindata.admintoken.length === 0;
+    });
+  }
+
+  login() {
+    if (this.adminloginform.valid) {
+      this.bs.login(
+        this.adminloginform.get('testname').value, this.adminloginform.get('testpw').value
+      ).subscribe(admindata => {
+        if (admindata instanceof ServerError) {
+          this.mds.setNewLoginData();
+          this.mds.setNewErrorMsg(admindata as ServerError);
+        } else {
+          this.mds.setNewLoginData(admindata as LoginData);
+          this.mds.setNewErrorMsg();
+        }
+      });
+    }
+  }
+
+  buttonGotoWorkspace(ws: WorkspaceData) {
+    if (ws.role === 'MO') {
+      this.router.navigateByUrl('/ws/' + ws.id.toString() + '/monitor');
+    } else {
+      this.router.navigateByUrl('/ws/' + ws.id.toString() + '/files');
+    }
+  }
+
+  ngOnDestroy() {
+    if (this.loginDataSubscription !== null) {
+      this.loginDataSubscription.unsubscribe();
+    }
+  }
+}
diff --git a/src/app/start/start.component.ts b/src/app/start/start.component.ts.TC
similarity index 100%
rename from src/app/start/start.component.ts
rename to src/app/start/start.component.ts.TC
diff --git a/src/app/superadmin/backend.service.spec.ts b/src/app/superadmin/backend.service.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c31039d7e5bcc7bc70e7213ce06744a0dc6ed009
--- /dev/null
+++ b/src/app/superadmin/backend.service.spec.ts
@@ -0,0 +1,15 @@
+import { TestBed, inject } from '@angular/core/testing';
+
+import { BackendService } from './backend.service';
+
+describe('BackendService', () => {
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      providers: [BackendService]
+    });
+  });
+
+  it('should be created', inject([BackendService], (service: BackendService) => {
+    expect(service).toBeTruthy();
+  }));
+});
diff --git a/src/app/superadmin/backend.service.ts b/src/app/superadmin/backend.service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..750e14935b874b4765d939237f60c475746281ea
--- /dev/null
+++ b/src/app/superadmin/backend.service.ts
@@ -0,0 +1,134 @@
+import { Injectable, Inject } from '@angular/core';
+import { HttpClient } from '@angular/common/http';
+import { Observable, of } from 'rxjs';
+import { catchError } from 'rxjs/operators';
+
+
+@Injectable()
+
+export class BackendService {
+
+  constructor(
+    @Inject('SERVER_URL') private readonly serverUrl: string,
+    private http: HttpClient) {
+      this.serverUrl = this.serverUrl + 'php/sys.php/';
+    }
+
+  getUsers(): Observable<NameOnly[]> {
+    return this.http
+      .get<NameOnly[]>(this.serverUrl + 'users')
+        .pipe(
+          catchError(() => [])
+        );
+  }
+
+  addUser(name: string, password: string): Observable<Boolean> {
+    return this.http
+      .post<Boolean>(this.serverUrl + 'user/add', {n: name, p: password})
+        .pipe(
+          catchError(() => of(false))
+        );
+  }
+
+  changePassword(name: string, password: string): Observable<Boolean> {
+    return this.http
+      .post<Boolean>(this.serverUrl + 'user/pw', {n: name, p: password})
+        .pipe(
+          catchError(() => of(false))
+        );
+  }
+
+  deleteUsers(users: string[]): Observable<Boolean> {
+    return this.http
+      .post<Boolean>(this.serverUrl + 'users/delete', {u: users})
+        .pipe(
+          catchError(() => of(false))
+        );
+  }
+
+  getWorkspacesByUser(username: string): Observable<IdRoleData[]> {
+    return this.http
+      .get<IdLabelSelectedData[]>(this.serverUrl + 'workspaces?u=' + username)
+        .pipe(
+          catchError(() => [])
+        );
+  }
+
+  setWorkspacesByUser(user: string, accessTo: IdRoleData[]): Observable<Boolean> {
+    return this.http
+      .post<Boolean>(this.serverUrl + 'user/workspaces', {u: user, ws: accessTo})
+        .pipe(
+          catchError(() => of(false))
+        );
+  }
+
+  addWorkspace(name: string): Observable<Boolean> {
+    return this.http
+      .post<Boolean>(this.serverUrl + 'workspace/add', {n: name})
+        .pipe(
+          catchError(() => of(false))
+        );
+  }
+
+  renameWorkspace(wsId: number, wsName: string): Observable<Boolean> {
+    return this.http
+      .post<Boolean>(this.serverUrl + 'workspace/rename', {ws: wsId, n: wsName})
+        .pipe(
+          catchError(() => of(false))
+        );
+  }
+
+  deleteWorkspaces(workspaces: number[]): Observable<Boolean> {
+    return this.http
+      .post<Boolean>(this.serverUrl + 'workspaces/delete', {ws: workspaces})
+        .pipe(
+          catchError(() => of(false))
+        );
+  }
+
+  getUsersByWorkspace(workspaceId: number): Observable<IdRoleData[]> {
+    return this.http
+      .get<IdRoleData[]>(this.serverUrl + 'users?ws=' + workspaceId)
+        .pipe(
+          catchError(() => [])
+        );
+  }
+
+  setUsersByWorkspace(workspace: number, accessing: IdRoleData[]): Observable<Boolean> {
+    return this.http
+      .post<Boolean>(this.serverUrl + 'workspace/users', {ws: workspace, u: accessing})
+        .pipe(
+          catchError(() => of(false))
+        );
+  }
+
+  getWorkspaces(): Observable<IdAndName[]> {
+    return this.http
+      .get<IdAndName[]>(this.serverUrl + 'workspaces')
+        .pipe(
+          catchError(() => [])
+        );
+  }
+}
+
+
+export interface NameOnly {
+  name: string;
+}
+
+export interface IdAndName {
+  id: number;
+  name: string;
+}
+
+export interface IdLabelSelectedData {
+  id: number;
+  label: string;
+  selected: boolean;
+}
+
+export interface IdRoleData {
+  id: number;
+  label: string;
+  role: string;
+}
diff --git a/src/app/superadmin/index.ts b/src/app/superadmin/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..57d8e210df0fc7fe9ce1268af661b2209d740bcb
--- /dev/null
+++ b/src/app/superadmin/index.ts
@@ -0,0 +1,2 @@
+export { SuperadminComponent } from './superadmin.component';
+export { SuperadminModule } from './superadmin.module';
diff --git a/src/app/superadmin/superadmin-routing.module.ts.ADMIN b/src/app/superadmin/superadmin-routing.module.ts.ADMIN
new file mode 100644
index 0000000000000000000000000000000000000000..edbabde86edf28d79a64465db97d6530510f884c
--- /dev/null
+++ b/src/app/superadmin/superadmin-routing.module.ts.ADMIN
@@ -0,0 +1,26 @@
+import { NgModule } from '@angular/core';
+import { Routes, RouterModule } from '@angular/router';
+
+import { WorkspacesComponent } from './workspaces/workspaces.component';
+import { UsersComponent } from './users/users.component';
+import { SuperadminComponent } from './superadmin.component';
+
+
+const routes: Routes = [
+  {
+    path: '',
+    component: SuperadminComponent,
+    children: [
+      {path: '', redirectTo: 'users', pathMatch: 'full'},
+      {path: 'users', component: UsersComponent},
+      {path: 'workspaces', component: WorkspacesComponent},
+      {path: '**', component: UsersComponent}
+    ]
+  }
+];
+
+@NgModule({
+  imports: [RouterModule.forChild(routes)],
+  exports: [RouterModule]
+})
+export class SuperadminRoutingModule { }
diff --git a/src/app/superadmin/superadmin-routing.module.ts b/src/app/superadmin/superadmin-routing.module.ts.TC
similarity index 100%
rename from src/app/superadmin/superadmin-routing.module.ts
rename to src/app/superadmin/superadmin-routing.module.ts.TC
diff --git a/src/app/superadmin/superadmin.component.css.ADMIN b/src/app/superadmin/superadmin.component.css.ADMIN
new file mode 100644
index 0000000000000000000000000000000000000000..90fca5595686bed01fc1036a2b0dd8ca7bb1d92c
--- /dev/null
+++ b/src/app/superadmin/superadmin.component.css.ADMIN
@@ -0,0 +1,18 @@
+.adminbackground {
+  flex:  10 0 900px;
+  box-shadow: 5px 10px 20px black;
+  background-color: white;
+  min-height: 85%;
+  margin: 15px;
+  padding: 25px;
+}
+
+#buttonsContainer {
+  color: rgb(253, 249, 196);
+  padding: 0 10px 0 0;
+  font-weight: bold;
+}
+
+#buttonsContainer img {
+  width: 100px;
+}
diff --git a/src/app/superadmin/superadmin.component.css b/src/app/superadmin/superadmin.component.css.TC
similarity index 100%
rename from src/app/superadmin/superadmin.component.css
rename to src/app/superadmin/superadmin.component.css.TC
diff --git a/src/app/superadmin/superadmin.component.html.ADMIN b/src/app/superadmin/superadmin.component.html.ADMIN
new file mode 100644
index 0000000000000000000000000000000000000000..4f4fc3253f01570b92277d0b3bfc41964243889f
--- /dev/null
+++ b/src/app/superadmin/superadmin.component.html.ADMIN
@@ -0,0 +1,25 @@
+<div id="buttonsContainer" fxLayout="row" fxLayoutAlign="start center">
+  <a [routerLink]="['/']">
+    <img src="assets/IQB-LogoA.png" matTooltip="Startseite"/>
+  </a>
+  <div fxLayout="row wrap" fxLayoutAlign="space-between center" fxFlex>
+    <div class="error-msg">{{ (mds.globalErrorMsg$ | async)?.labelNice }}</div>
+    <div>IQB-Testcenter Systemverwaltung</div>
+  </div>
+</div>
+<div class="page-body">
+  <div class="adminbackground">
+
+    <nav mat-tab-nav-bar>
+      <a mat-tab-link
+          *ngFor="let link of navLinks"
+          [routerLink]="link.path"
+          routerLinkActive #rla="routerLinkActive"
+          [active]="rla.isActive">
+        {{link.label}}
+      </a>
+    </nav>
+
+    <router-outlet></router-outlet>
+  </div>
+</div>
diff --git a/src/app/superadmin/superadmin.component.html b/src/app/superadmin/superadmin.component.html.TC
similarity index 100%
rename from src/app/superadmin/superadmin.component.html
rename to src/app/superadmin/superadmin.component.html.TC
diff --git a/src/app/superadmin/superadmin.component.ts.ADMIN b/src/app/superadmin/superadmin.component.ts.ADMIN
new file mode 100644
index 0000000000000000000000000000000000000000..e06d11db00d1ad715dc76d3224db51307633552d
--- /dev/null
+++ b/src/app/superadmin/superadmin.component.ts.ADMIN
@@ -0,0 +1,19 @@
+import { Component, OnInit } from '@angular/core';
+import { MainDataService } from '../maindata.service';
+
+
+
+@Component({
+  templateUrl: './superadmin.component.html',
+  styleUrls: ['./superadmin.component.css']
+})
+export class SuperadminComponent {
+  constructor(
+    public mds: MainDataService
+  ) { }
+
+  public navLinks = [
+    {path: 'users', label: 'Users'},
+    {path: 'workspaces', label: 'Arbeitsbereiche'}
+  ];
+}
diff --git a/src/app/superadmin/superadmin.component.ts b/src/app/superadmin/superadmin.component.ts.TC
similarity index 100%
rename from src/app/superadmin/superadmin.component.ts
rename to src/app/superadmin/superadmin.component.ts.TC
diff --git a/src/app/superadmin/superadmin.module.spec.ts b/src/app/superadmin/superadmin.module.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d8404f336e02b67d87ec1acf4e839bc61b2deb80
--- /dev/null
+++ b/src/app/superadmin/superadmin.module.spec.ts
@@ -0,0 +1,13 @@
+import { SuperadminModule } from './superadmin.module';
+
+describe('SuperadminModule', () => {
+  let superadminModule: SuperadminModule;
+
+  beforeEach(() => {
+    superadminModule = new SuperadminModule();
+  });
+
+  it('should create an instance', () => {
+    expect(superadminModule).toBeTruthy();
+  });
+});
diff --git a/src/app/superadmin/superadmin.module.ts.ADMIN b/src/app/superadmin/superadmin.module.ts.ADMIN
new file mode 100644
index 0000000000000000000000000000000000000000..de70a8955d8ad136a5ace9689094e87a43e48cf1
--- /dev/null
+++ b/src/app/superadmin/superadmin.module.ts.ADMIN
@@ -0,0 +1,78 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { MatButtonModule } from '@angular/material/button';
+import { MatCheckboxModule } from '@angular/material/checkbox';
+import { MatDialogModule } from '@angular/material/dialog';
+import { MatFormFieldModule } from '@angular/material/form-field';
+import { MatIconModule } from '@angular/material/icon';
+import { MatInputModule } from '@angular/material/input';
+import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
+import { MatSelectModule } from '@angular/material/select';
+import { MatSnackBarModule } from '@angular/material/snack-bar';
+import { MatSortModule } from '@angular/material/sort';
+import { MatTableModule } from '@angular/material/table';
+import { MatTabsModule } from '@angular/material/tabs';
+import { MatToolbarModule } from '@angular/material/toolbar';
+import { MatTooltipModule } from '@angular/material/tooltip';
+import { FlexLayoutModule } from '@angular/flex-layout';
+import { ReactiveFormsModule } from '@angular/forms';
+
+import { SuperadminRoutingModule } from './superadmin-routing.module';
+import { WorkspacesComponent } from './workspaces/workspaces.component';
+import { UsersComponent } from './users/users.component';
+import { SuperadminComponent } from './superadmin.component';
+import { BackendService } from './backend.service';
+import { IqbFilesModule } from '../iqb-files';
+import { NewuserComponent } from './users/newuser/newuser.component';
+import { NewpasswordComponent } from './users/newpassword/newpassword.component';
+import { NewworkspaceComponent } from './workspaces/newworkspace/newworkspace.component';
+import { EditworkspaceComponent } from './workspaces/editworkspace/editworkspace.component';
+import { IqbComponentsModule } from 'iqb-components';
+
+
+@NgModule({
+  imports: [
+    CommonModule,
+    SuperadminRoutingModule,
+    IqbFilesModule,
+    IqbComponentsModule,
+    MatTableModule,
+    MatTabsModule,
+    MatIconModule,
+    MatSelectModule,
+    MatCheckboxModule,
+    MatSortModule,
+    ReactiveFormsModule,
+    MatProgressSpinnerModule,
+    MatDialogModule,
+    MatButtonModule,
+    MatTooltipModule,
+    MatFormFieldModule,
+    MatInputModule,
+    MatToolbarModule,
+    MatSnackBarModule,
+    FlexLayoutModule
+  ],
+  exports: [
+    SuperadminComponent,
+  ],
+  declarations: [
+    WorkspacesComponent,
+    UsersComponent,
+    SuperadminComponent,
+    NewuserComponent,
+    NewpasswordComponent,
+    NewworkspaceComponent,
+    EditworkspaceComponent
+  ],
+  providers: [
+    BackendService,
+  ],
+  entryComponents: [
+    NewuserComponent,
+    NewpasswordComponent,
+    NewworkspaceComponent,
+    EditworkspaceComponent
+  ]
+})
+export class SuperadminModule { }
diff --git a/src/app/superadmin/superadmin.module.ts b/src/app/superadmin/superadmin.module.ts.TC
similarity index 100%
rename from src/app/superadmin/superadmin.module.ts
rename to src/app/superadmin/superadmin.module.ts.TC
diff --git a/src/app/superadmin/users/newpassword/newpassword.component.css b/src/app/superadmin/users/newpassword/newpassword.component.css
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/app/superadmin/users/newpassword/newpassword.component.html b/src/app/superadmin/users/newpassword/newpassword.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..8685c172a39662b40f6a6734944552a13b17d09f
--- /dev/null
+++ b/src/app/superadmin/users/newpassword/newpassword.component.html
@@ -0,0 +1,20 @@
+<form [formGroup]="newpasswordform">
+    <h1 mat-dialog-title>Kennwort ändern</h1>
+
+    <mat-dialog-content>
+      <div class="infobox">
+        <p>Ändern des Kennwortes für Nutzer/in "{{ data.name }}".</p>
+      </div>
+      <p>
+        <mat-form-field class="full-width">
+          <input matInput type="password" formControlName="pw" placeholder="Kennwort">
+        </mat-form-field>
+      </p>
+    </mat-dialog-content>
+
+    <mat-dialog-actions>
+      <button mat-raised-button color="primary" type="submit" [mat-dialog-close]="newpasswordform" [disabled]="newpasswordform.invalid">Speichern</button>
+      <button mat-raised-button [mat-dialog-close]="false">Abbrechen</button>
+    </mat-dialog-actions>
+
+  </form>
diff --git a/src/app/superadmin/users/newpassword/newpassword.component.spec.ts b/src/app/superadmin/users/newpassword/newpassword.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8e945c2cdf5d97e56a0ba76bf977b2020c428596
--- /dev/null
+++ b/src/app/superadmin/users/newpassword/newpassword.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { NewpasswordComponent } from './newpassword.component';
+
+describe('NewpasswordComponent', () => {
+  let component: NewpasswordComponent;
+  let fixture: ComponentFixture<NewpasswordComponent>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ NewpasswordComponent ]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(NewpasswordComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/src/app/superadmin/users/newpassword/newpassword.component.ts b/src/app/superadmin/users/newpassword/newpassword.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..3a001265d18cae4a65cf5de623c1ebfddff7f91d
--- /dev/null
+++ b/src/app/superadmin/users/newpassword/newpassword.component.ts
@@ -0,0 +1,21 @@
+import { MAT_DIALOG_DATA } from '@angular/material/dialog';
+import { Component, OnInit, Inject } from '@angular/core';
+import { FormGroup, FormBuilder, Validators } from '@angular/forms';
+
+@Component({
+  templateUrl: './newpassword.component.html',
+  styleUrls: ['./newpassword.component.css']
+})
+
+export class NewpasswordComponent implements OnInit {
+  newpasswordform: FormGroup;
+
+  constructor(private fb: FormBuilder,
+    @Inject(MAT_DIALOG_DATA) public data: any) { }
+
+  ngOnInit() {
+    this.newpasswordform = this.fb.group({
+      pw: this.fb.control('', [Validators.required, Validators.minLength(3)])
+    });
+  }
+}
diff --git a/src/app/superadmin/users/newuser/newuser.component.css b/src/app/superadmin/users/newuser/newuser.component.css
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/app/superadmin/users/newuser/newuser.component.html b/src/app/superadmin/users/newuser/newuser.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..4a4d5c11f20c5873192f60bf454c5193b1785ece
--- /dev/null
+++ b/src/app/superadmin/users/newuser/newuser.component.html
@@ -0,0 +1,26 @@
+<form [formGroup]="newuserform">
+  <h1 mat-dialog-title>Neue/r Nutzer/in</h1>
+
+  <mat-dialog-content>
+    <p>
+      <mat-form-field class="full-width">
+        <input matInput formControlName="name" placeholder="Name" [value]="data.name">
+      </mat-form-field>
+    </p>
+    <p>
+      <mat-form-field class="full-width">
+        <input matInput type="password" formControlName="pw" placeholder="Kennwort">
+      </mat-form-field>
+    </p>
+    <div class="infobox">
+      <p>Nach dem Anlegen des Nutzers können Sie die Rechte zuweisen.
+      </p>
+    </div>
+  </mat-dialog-content>
+
+  <mat-dialog-actions>
+    <button mat-raised-button color="primary" type="submit" [mat-dialog-close]="newuserform" [disabled]="newuserform.invalid">Speichern</button>
+    <button mat-raised-button [mat-dialog-close]="false">Abbrechen</button>
+  </mat-dialog-actions>
+
+</form>
diff --git a/src/app/superadmin/users/newuser/newuser.component.spec.ts b/src/app/superadmin/users/newuser/newuser.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..fd37aa1b5db9f9dfc0a22a681ecb46ab7490302a
--- /dev/null
+++ b/src/app/superadmin/users/newuser/newuser.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { NewuserComponent } from './newuser.component';
+
+describe('NewuserComponent', () => {
+  let component: NewuserComponent;
+  let fixture: ComponentFixture<NewuserComponent>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ NewuserComponent ]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(NewuserComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/src/app/superadmin/users/newuser/newuser.component.ts b/src/app/superadmin/users/newuser/newuser.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..75ea8e3bfb23faf5dd77b480a98af7dde78c8b7a
--- /dev/null
+++ b/src/app/superadmin/users/newuser/newuser.component.ts
@@ -0,0 +1,21 @@
+import { MAT_DIALOG_DATA } from '@angular/material/dialog';
+import { Component, OnInit, Inject } from '@angular/core';
+import { FormGroup, FormBuilder, Validators } from '@angular/forms';
+
+@Component({
+  templateUrl: './newuser.component.html',
+  styleUrls: ['./newuser.component.css']
+})
+export class NewuserComponent implements OnInit {
+  newuserform: FormGroup;
+
+  constructor(private fb: FormBuilder,
+    @Inject(MAT_DIALOG_DATA) public data: any) { }
+
+  ngOnInit() {
+    this.newuserform = this.fb.group({
+      name: this.fb.control('', [Validators.required, Validators.minLength(3)]),
+      pw: this.fb.control('', [Validators.required, Validators.minLength(3)])
+    });
+  }
+}
diff --git a/src/app/superadmin/users/users.component.css b/src/app/superadmin/users/users.component.css
new file mode 100644
index 0000000000000000000000000000000000000000..4c24b03c812046310b0988dea942ef0cdb956850
--- /dev/null
+++ b/src/app/superadmin/users/users.component.css
@@ -0,0 +1,8 @@
+.mat-raised-button {
+    min-width: 100px;
+    margin: 2px;
+}
+
+.mat-checkbox {
+    margin: 0 3px;
+}
\ No newline at end of file
diff --git a/src/app/superadmin/users/users.component.html b/src/app/superadmin/users/users.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..e20f28032a86975a30ffc0b2a43dd28f8d1ab494
--- /dev/null
+++ b/src/app/superadmin/users/users.component.html
@@ -0,0 +1,85 @@
+<div class="columnhost" fxLayout="row" fxLayoutAlign="space-between start">
+  <div class="spinner-container" *ngIf="dataLoading">
+      <mat-spinner></mat-spinner>
+  </div>
+
+  <!-- ============================================= -->
+  <div class="objectlist" fxLayout="column" fxFlex="50">
+    <div fxLayout="row">
+        <button mat-raised-button (click)="addObject()" matTooltip="Nutzer hinzufügen" matTooltipPosition="above">
+            <mat-icon>add</mat-icon>
+          </button>
+        <button mat-raised-button (click)="deleteObject()" matTooltip="Markierte Nutzer löschen" matTooltipPosition="above">
+          <mat-icon>delete</mat-icon>
+        </button>
+        <button mat-raised-button (click)="changePassword()" matTooltip="Kennwort ändern" matTooltipPosition="above">
+          <mat-icon>edit</mat-icon>
+        </button>
+    </div>
+
+    <mat-table *ngIf="isSuperadmin" [dataSource]="objectsDatasource" matSort>
+      <ng-container matColumnDef="selectCheckbox">
+        <mat-header-cell *matHeaderCellDef fxFlex="70px">
+          <mat-checkbox (change)="$event ? masterToggle() : null"
+                        [checked]="tableselectionCheckbox.hasValue() && isAllSelected()"
+                        [indeterminate]="tableselectionCheckbox.hasValue() && !isAllSelected()">
+          </mat-checkbox>
+        </mat-header-cell>
+        <mat-cell *matCellDef="let row" fxFlex="70px">
+          <mat-checkbox (click)="$event.stopPropagation()"
+                        (change)="$event ? tableselectionCheckbox.toggle(row) : null"
+                        [checked]="tableselectionCheckbox.isSelected(row)">
+          </mat-checkbox>
+        </mat-cell>
+      </ng-container>
+
+      <ng-container matColumnDef="name">
+        <mat-header-cell *matHeaderCellDef mat-sort-header> Name </mat-header-cell>
+        <mat-cell *matCellDef="let element"> {{element.name}} </mat-cell>
+      </ng-container>
+
+      <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
+      <mat-row *matRowDef="let row; columns: displayedColumns;" (click)="selectRow(row)"
+        [style.background]="tableselectionRow.isSelected(row) ? 'lightblue' : ''"></mat-row>
+    </mat-table>
+  </div>
+
+  <!-- ============================================= -->
+  <div *ngIf="isSuperadmin" fxLayout="column" fxFlex="40">
+
+    <div *ngIf="selectedUser.length == 0">
+      <div>Zugriffsrechte für Arbeitsbereich(e):</div>
+      <div>Bitte links einen Nutzer wählen</div>
+    </div>
+
+    <div *ngIf="selectedUser.length > 0" fxLayout="row" fxLayoutAlign="space-between center">
+      <div>Zugriffsrechte für {{ selectedUser }}:</div>
+        <button mat-raised-button (click)="saveWorkspaces()" matTooltip="Speichern"
+            matTooltipPosition="above" [disabled]="!pendingWorkspaceChanges">
+          <mat-icon>save</mat-icon>
+        </button>
+    </div>
+
+    <mat-table [dataSource]="WorkspacelistDatasource" matSort>
+      <ng-container matColumnDef="selectCheckbox">
+        <mat-header-cell *matHeaderCellDef mat-sort-header>RO | RW | MO</mat-header-cell>
+        <mat-cell *matCellDef="let row" fxFlex="100px">
+          <mat-checkbox (change)="selectWorkspace(row, 'RO')" [checked]="row.role === 'RO'" matTooltip="RO">
+          </mat-checkbox>
+          <mat-checkbox (change)="selectWorkspace(row, 'RW')" [checked]="row.role === 'RW'" matTooltip="RW">
+          </mat-checkbox>
+          <mat-checkbox (change)="selectWorkspace(row, 'MO')" [checked]="row.role === 'MO'" matTooltip="MO">
+          </mat-checkbox>
+        </mat-cell>
+      </ng-container>
+
+      <ng-container matColumnDef="label">
+        <mat-header-cell *matHeaderCellDef mat-sort-header> Arbeitsbereich </mat-header-cell>
+        <mat-cell *matCellDef="let row"> {{row.name}} </mat-cell>
+      </ng-container>
+
+      <mat-header-row *matHeaderRowDef="displayedWorkspaceColumns"></mat-header-row>
+      <mat-row *matRowDef="let row; columns: displayedWorkspaceColumns;"></mat-row>
+    </mat-table>
+  </div>
+</div>
diff --git a/src/app/superadmin/users/users.component.spec.ts b/src/app/superadmin/users/users.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..909b5bafc36b01915898fbd0fe8b0d5568aba476
--- /dev/null
+++ b/src/app/superadmin/users/users.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { UsersComponent } from './users.component';
+
+describe('UsersComponent', () => {
+  let component: UsersComponent;
+  let fixture: ComponentFixture<UsersComponent>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ UsersComponent ]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(UsersComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/src/app/superadmin/users/users.component.ts b/src/app/superadmin/users/users.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..62dde2f2bde27fa094dc7499750094626353c974
--- /dev/null
+++ b/src/app/superadmin/users/users.component.ts
@@ -0,0 +1,268 @@
+import { NewpasswordComponent } from './newpassword/newpassword.component';
+import { NewuserComponent } from './newuser/newuser.component';
+import { BackendService, NameOnly, IdRoleData } from '../backend.service';
+import { MatTableDataSource } from '@angular/material/table';
+import { ViewChild, OnDestroy } from '@angular/core';
+
+import { Component, OnInit } from '@angular/core';
+import { MatDialog } from '@angular/material/dialog';
+import { MatSnackBar } from '@angular/material/snack-bar';
+import { MatSort } from '@angular/material/sort';
+import { FormGroup } from '@angular/forms';
+import { SelectionModel } from '@angular/cdk/collections';
+import {
+  ConfirmDialogComponent, ConfirmDialogData, MessageDialogComponent,
+  MessageDialogData, MessageType
+} from 'iqb-components';
+import { Subscription } from 'rxjs';
+import { MainDataService } from 'src/app/maindata.service';
+
+
+@Component({
+  templateUrl: './users.component.html',
+  styleUrls: ['./users.component.css']
+})
+export class UsersComponent implements OnInit, OnDestroy {
+  public isSuperadmin = false;
+  public dataLoading = false;
+  public objectsDatasource: MatTableDataSource<NameOnly>;
+  public displayedColumns = ['selectCheckbox', 'name'];
+  private tableselectionCheckbox = new SelectionModel <NameOnly>(true, []);
+  private tableselectionRow = new SelectionModel <NameOnly>(false, []);
+  private selectedUser = '';
+
+  private pendingWorkspaceChanges = false;
+  public WorkspacelistDatasource: MatTableDataSource<IdRoleData>;
+  public displayedWorkspaceColumns = ['selectCheckbox', 'label'];
+  private logindataSubscription: Subscription = null;
+
+  @ViewChild(MatSort, { static: false }) sort: MatSort;
+
+  constructor(
+    private bs: BackendService,
+    private mds: MainDataService,
+    private newuserDialog: MatDialog,
+    private newpasswordDialog: MatDialog,
+    private deleteConfirmDialog: MatDialog,
+    private messsageDialog: MatDialog,
+    private snackBar: MatSnackBar
+  ) {
+    this.tableselectionRow.changed.subscribe(
+      r => {
+        if (r.added.length > 0) {
+          this.selectedUser = r.added[0].name;
+        } else {
+          this.selectedUser = '';
+        }
+        this.updateWorkspaceList();
+      });
+  }
+
+  ngOnInit() {
+    this.logindataSubscription = this.mds.loginData$.subscribe(ld => {
+      this.isSuperadmin = ld.is_superadmin;
+      this.updateObjectList();
+    });
+  }
+
+  // ***********************************************************************************
+  addObject() {
+    const dialogRef = this.newuserDialog.open(NewuserComponent, {
+      width: '600px',
+      data: {
+        name: ''
+      }
+    });
+
+    dialogRef.afterClosed().subscribe(result => {
+      if (typeof result !== 'undefined') {
+        if (result !== false) {
+          this.bs.addUser((<FormGroup>result).get('name').value,
+              (<FormGroup>result).get('pw').value).subscribe(
+                respOk => {
+                  if (respOk) {
+                    this.snackBar.open('Nutzer hinzugefügt', '', {duration: 1000});
+                    this.updateObjectList();
+                  } else {
+                    this.snackBar.open('Konnte Nutzer nicht hinzufügen', 'Fehler', {duration: 1000});
+                  }
+                });
+        }
+      }
+    });
+  }
+
+  changePassword() {
+    let selectedRows = this.tableselectionRow.selected;
+    if (selectedRows.length === 0) {
+      selectedRows = this.tableselectionCheckbox.selected;
+    }
+    if (selectedRows.length === 0) {
+      this.messsageDialog.open(MessageDialogComponent, {
+        width: '400px',
+        data: <MessageDialogData>{
+          title: 'Kennwort ändern',
+          content: 'Bitte markieren Sie erst einen Nutzer!',
+          type: MessageType.error
+        }
+      });
+    } else {
+      const dialogRef = this.newpasswordDialog.open(NewpasswordComponent, {
+        width: '600px',
+        data: {
+          name: selectedRows[0]['name']
+        }
+      });
+
+      dialogRef.afterClosed().subscribe(result => {
+        if (typeof result !== 'undefined') {
+          if (result !== false) {
+            this.dataLoading = true;
+            this.bs.changePassword(selectedRows[0]['name'],
+                (<FormGroup>result).get('pw').value).subscribe(
+                  respOk => {
+                    if (respOk) {
+                      this.snackBar.open('Kennwort geändert', '', {duration: 1000});
+                    } else {
+                      this.snackBar.open('Konnte Kennwort nicht ändern', 'Fehler', {duration: 1000});
+                    }
+                    this.dataLoading = false;
+                  });
+          }
+        }
+      });
+    }
+  }
+
+  deleteObject() {
+    let selectedRows = this.tableselectionCheckbox.selected;
+    if (selectedRows.length === 0) {
+      selectedRows = this.tableselectionRow.selected;
+    }
+    if (selectedRows.length === 0) {
+      this.messsageDialog.open(MessageDialogComponent, {
+        width: '400px',
+        data: <MessageDialogData>{
+          title: 'Löschen von Nutzern',
+          content: 'Bitte markieren Sie erst Nutzer!',
+          type: MessageType.error
+        }
+      });
+    } else {
+      let prompt = 'Soll';
+      if (selectedRows.length > 1) {
+        prompt = prompt + 'en ' + selectedRows.length + ' Nutzer ';
+      } else {
+        prompt = prompt + ' Nutzer "' + selectedRows[0].name + '" ';
+      }
+      const dialogRef = this.deleteConfirmDialog.open(ConfirmDialogComponent, {
+        width: '400px',
+        data: <ConfirmDialogData>{
+          title: 'Löschen von Nutzern',
+          content: prompt + 'gelöscht werden?',
+          confirmbuttonlabel: 'Nutzer löschen',
+          showcancel: true
+        }
+      });
+
+      dialogRef.afterClosed().subscribe(result => {
+        if (result !== false) {
+          // =========================================================
+          this.dataLoading = true;
+          const usersToDelete = [];
+          selectedRows.forEach((r: NameOnly) => usersToDelete.push(r.name));
+          this.bs.deleteUsers(usersToDelete).subscribe(
+            respOk => {
+              if (respOk) {
+                this.snackBar.open('Nutzer gelöscht', '', {duration: 1000});
+                this.updateObjectList();
+                this.dataLoading = false;
+              } else {
+                this.snackBar.open('Konnte Nutzer nicht löschen', 'Fehler', {duration: 2000});
+                this.dataLoading = false;
+              }
+          });
+        }
+      });
+    }
+  }
+
+  // ***********************************************************************************
+  updateWorkspaceList() {
+    this.pendingWorkspaceChanges = false;
+    if (this.selectedUser.length > 0) {
+      this.dataLoading = true;
+      this.bs.getWorkspacesByUser(this.selectedUser).subscribe(dataresponse => {
+          this.WorkspacelistDatasource = new MatTableDataSource(dataresponse);
+          this.dataLoading = false;
+        });
+    } else {
+      this.WorkspacelistDatasource = null;
+    }
+  }
+
+  selectWorkspace(ws: IdRoleData, role: string) {
+    if (ws.role === role) {
+      ws.role = '';
+    } else {
+      ws.role = role;
+    }
+    this.pendingWorkspaceChanges = true;
+  }
+
+  saveWorkspaces() {
+    this.pendingWorkspaceChanges = false;
+    if (this.selectedUser.length > 0) {
+      this.dataLoading = true;
+      this.bs.setWorkspacesByUser(this.selectedUser, this.WorkspacelistDatasource.data).subscribe(
+        respOk => {
+          if (respOk) {
+            this.snackBar.open('Zugriffsrechte geändert', '', {duration: 1000});
+          } else {
+            this.snackBar.open('Konnte Zugriffsrechte nicht ändern', 'Fehler', {duration: 2000});
+          }
+          this.dataLoading = false;
+        });
+    } else {
+      this.WorkspacelistDatasource = null;
+    }
+  }
+
+  // ***********************************************************************************
+  updateObjectList() {
+    if (this.isSuperadmin) {
+      this.dataLoading = true;
+      this.tableselectionCheckbox.clear();
+      this.tableselectionRow.clear();
+      this.bs.getUsers().subscribe(dataresponse => {
+          this.objectsDatasource = new MatTableDataSource(dataresponse);
+          this.objectsDatasource.sort = this.sort;
+          this.dataLoading = false;
+        }
+      );
+    }
+  }
+
+  isAllSelected() {
+    const numSelected = this.tableselectionCheckbox.selected.length;
+    const numRows = this.objectsDatasource.data.length;
+    return numSelected === numRows;
+  }
+
+  masterToggle() {
+    this.isAllSelected() ?
+        this.tableselectionCheckbox.clear() :
+        this.objectsDatasource.data.forEach(row => this.tableselectionCheckbox.select(row));
+  }
+
+  selectRow(row) {
+    this.tableselectionRow.select(row);
+  }
+
+  // % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %
+  ngOnDestroy() {
+    if (this.logindataSubscription !== null) {
+      this.logindataSubscription.unsubscribe();
+    }
+  }
+}
diff --git a/src/app/superadmin/workspaces/editworkspace/editworkspace.component.css b/src/app/superadmin/workspaces/editworkspace/editworkspace.component.css
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/app/superadmin/workspaces/editworkspace/editworkspace.component.html b/src/app/superadmin/workspaces/editworkspace/editworkspace.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..ea8a177147f15f24e8abc97b062d00d6f756d950
--- /dev/null
+++ b/src/app/superadmin/workspaces/editworkspace/editworkspace.component.html
@@ -0,0 +1,17 @@
+<form [formGroup]="editworkspaceform">
+  <h1 mat-dialog-title>Arbeitsbereich "{{data.oldname}}" ändern</h1>
+
+  <mat-dialog-content>
+    <p>
+      <mat-form-field class="full-width">
+        <input matInput formControlName="name" placeholder="Name" [value]="data.name">
+      </mat-form-field>
+    </p>
+  </mat-dialog-content>
+
+  <mat-dialog-actions>
+    <button mat-raised-button color="primary" type="submit" [mat-dialog-close]="editworkspaceform" [disabled]="editworkspaceform.invalid">Speichern</button>
+    <button mat-raised-button [mat-dialog-close]="false">Abbrechen</button>
+  </mat-dialog-actions>
+
+</form>
diff --git a/src/app/superadmin/workspaces/editworkspace/editworkspace.component.spec.ts b/src/app/superadmin/workspaces/editworkspace/editworkspace.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8b464397d576671f928a425c97168ea1a556d723
--- /dev/null
+++ b/src/app/superadmin/workspaces/editworkspace/editworkspace.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { EditworkspaceComponent } from './editworkspace.component';
+
+describe('EditworkspaceComponent', () => {
+  let component: EditworkspaceComponent;
+  let fixture: ComponentFixture<EditworkspaceComponent>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ EditworkspaceComponent ]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(EditworkspaceComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/src/app/superadmin/workspaces/editworkspace/editworkspace.component.ts b/src/app/superadmin/workspaces/editworkspace/editworkspace.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..55013ca244f4916715a8f6c2baa906dc17fe08ed
--- /dev/null
+++ b/src/app/superadmin/workspaces/editworkspace/editworkspace.component.ts
@@ -0,0 +1,20 @@
+import { MAT_DIALOG_DATA } from '@angular/material/dialog';
+import { Component, OnInit, Inject } from '@angular/core';
+import { FormGroup, FormBuilder, Validators } from '@angular/forms';
+
+@Component({
+  templateUrl: './editworkspace.component.html',
+  styleUrls: ['./editworkspace.component.css']
+})
+export class EditworkspaceComponent implements OnInit {
+  editworkspaceform: FormGroup;
+
+  constructor(private fb: FormBuilder,
+    @Inject(MAT_DIALOG_DATA) public data: any) { }
+
+  ngOnInit() {
+    this.editworkspaceform = this.fb.group({
+      name: this.fb.control('', [Validators.required, Validators.minLength(3)])
+    });
+  }
+}
diff --git a/src/app/superadmin/workspaces/newworkspace/newworkspace.component.css b/src/app/superadmin/workspaces/newworkspace/newworkspace.component.css
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/app/superadmin/workspaces/newworkspace/newworkspace.component.html b/src/app/superadmin/workspaces/newworkspace/newworkspace.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..5f6e7c282656460604295e5c11967e1cdc23b421
--- /dev/null
+++ b/src/app/superadmin/workspaces/newworkspace/newworkspace.component.html
@@ -0,0 +1,21 @@
+<form [formGroup]="newworkspaceform">
+  <h1 mat-dialog-title>Neuer Arbeitsbereich</h1>
+
+  <mat-dialog-content>
+    <p>
+      <mat-form-field class="full-width">
+        <input matInput formControlName="name" placeholder="Name" [value]="data.name">
+      </mat-form-field>
+    </p>
+    <div class="infobox">
+      <p>Nach dem Anlegen des Arbeitsbereiches können Sie die Zugriffsrechte zuweisen.
+      </p>
+    </div>
+  </mat-dialog-content>
+
+  <mat-dialog-actions>
+    <button mat-raised-button color="primary" type="submit" [mat-dialog-close]="newworkspaceform" [disabled]="newworkspaceform.invalid">Speichern</button>
+    <button mat-raised-button [mat-dialog-close]="false">Abbrechen</button>
+  </mat-dialog-actions>
+
+</form>
diff --git a/src/app/superadmin/workspaces/newworkspace/newworkspace.component.spec.ts b/src/app/superadmin/workspaces/newworkspace/newworkspace.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..a2c645598677fe1b8f3ae62356d7f93912b3db31
--- /dev/null
+++ b/src/app/superadmin/workspaces/newworkspace/newworkspace.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { NewworkspaceComponent } from './newworkspace.component';
+
+describe('NewworkspaceComponent', () => {
+  let component: NewworkspaceComponent;
+  let fixture: ComponentFixture<NewworkspaceComponent>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ NewworkspaceComponent ]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(NewworkspaceComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/src/app/superadmin/workspaces/newworkspace/newworkspace.component.ts b/src/app/superadmin/workspaces/newworkspace/newworkspace.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..02cf6f563b7dd474d94a3fd2546591baf9aaef28
--- /dev/null
+++ b/src/app/superadmin/workspaces/newworkspace/newworkspace.component.ts
@@ -0,0 +1,20 @@
+import { MAT_DIALOG_DATA } from '@angular/material/dialog';
+import { Component, OnInit, Inject } from '@angular/core';
+import { FormGroup, FormBuilder, Validators } from '@angular/forms';
+
+@Component({
+  templateUrl: './newworkspace.component.html',
+  styleUrls: ['./newworkspace.component.css']
+})
+export class NewworkspaceComponent implements OnInit {
+  newworkspaceform: FormGroup;
+
+  constructor(private fb: FormBuilder,
+    @Inject(MAT_DIALOG_DATA) public data: any) { }
+
+  ngOnInit() {
+    this.newworkspaceform = this.fb.group({
+      name: this.fb.control('', [Validators.required, Validators.minLength(3)])
+    });
+  }
+}
diff --git a/src/app/superadmin/workspaces/workspaces.component.css b/src/app/superadmin/workspaces/workspaces.component.css
new file mode 100644
index 0000000000000000000000000000000000000000..4c24b03c812046310b0988dea942ef0cdb956850
--- /dev/null
+++ b/src/app/superadmin/workspaces/workspaces.component.css
@@ -0,0 +1,8 @@
+.mat-raised-button {
+    min-width: 100px;
+    margin: 2px;
+}
+
+.mat-checkbox {
+    margin: 0 3px;
+}
\ No newline at end of file
diff --git a/src/app/superadmin/workspaces/workspaces.component.html b/src/app/superadmin/workspaces/workspaces.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..289abc7259fb8fcbde429c7015c55bcfc0bbcc17
--- /dev/null
+++ b/src/app/superadmin/workspaces/workspaces.component.html
@@ -0,0 +1,85 @@
+<div class="columnhost" fxLayout="row" fxLayoutAlign="space-between start">
+  <div class="spinner-container" *ngIf="dataLoading">
+      <mat-spinner></mat-spinner>
+  </div>
+
+  <!-- ============================================= -->
+  <div class="objectlist" fxLayout="column" fxFlex="50">
+    <div fxLayout="row">
+        <button mat-raised-button (click)="addObject()" matTooltip="Arbeitsbereich hinzufügen" matTooltipPosition="above">
+            <mat-icon>add</mat-icon>
+          </button>
+        <button mat-raised-button (click)="deleteObject()" matTooltip="Markierte/n Arbeitsbereich/e löschen" matTooltipPosition="above">
+          <mat-icon>delete</mat-icon>
+        </button>
+        <button mat-raised-button (click)="changeObject()" matTooltip="Arbeitsbereich umbenennen" matTooltipPosition="above">
+          <mat-icon>edit</mat-icon>
+        </button>
+    </div>
+
+    <mat-table *ngIf="isSuperadmin" [dataSource]="objectsDatasource" matSort>
+      <ng-container matColumnDef="selectCheckbox">
+        <mat-header-cell *matHeaderCellDef fxFlex="70px">
+          <mat-checkbox (change)="$event ? masterToggle() : null"
+                        [checked]="tableselectionCheckbox.hasValue() && isAllSelected()"
+                        [indeterminate]="tableselectionCheckbox.hasValue() && !isAllSelected()">
+          </mat-checkbox>
+        </mat-header-cell>
+        <mat-cell *matCellDef="let row" fxFlex="70px">
+          <mat-checkbox (click)="$event.stopPropagation()"
+                        (change)="$event ? tableselectionCheckbox.toggle(row) : null"
+                        [checked]="tableselectionCheckbox.isSelected(row)">
+          </mat-checkbox>
+        </mat-cell>
+      </ng-container>
+
+      <ng-container matColumnDef="name">
+        <mat-header-cell *matHeaderCellDef mat-sort-header> Name </mat-header-cell>
+        <mat-cell *matCellDef="let element"> {{element.name}} </mat-cell>
+      </ng-container>
+
+      <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
+      <mat-row *matRowDef="let row; columns: displayedColumns;" (click)="selectRow(row)"
+        [style.background]="tableselectionRow.isSelected(row) ? 'lightblue' : ''"></mat-row>
+    </mat-table>
+  </div>
+
+  <!-- ============================================= -->
+  <div *ngIf="isSuperadmin" fxLayout="column" fxFlex="40">
+
+    <div *ngIf="selectedWorkspaceId == 0">
+      <div>Zugriffsberechtigte für Arbeitsbereich:</div>
+      <div>Bitte links einen Arbeitsbereich wählen</div>
+    </div>
+
+    <div *ngIf="selectedWorkspaceId > 0" fxLayout="row" fxLayoutAlign="space-between center">
+      <div>Zugriffsrechte für "{{ selectedWorkspaceName }}":</div>
+        <button mat-raised-button (click)="saveUsers()" matTooltip="Speichern"
+            matTooltipPosition="above" [disabled]="!pendingUserChanges">
+          <mat-icon>save</mat-icon>
+        </button>
+    </div>
+
+    <mat-table [dataSource]="UserlistDatasource" matSort>
+      <ng-container matColumnDef="selectCheckbox">
+        <mat-header-cell *matHeaderCellDef mat-sort-header>RO | RW | MO</mat-header-cell>
+        <mat-cell *matCellDef="let row" fxFlex="100px">
+          <mat-checkbox (change)="selectUser(row, 'RO')" [checked]="row.role === 'RO'" matTooltip="RO">
+          </mat-checkbox>
+          <mat-checkbox (change)="selectUser(row, 'RW')" [checked]="row.role === 'RW'" matTooltip="RW">
+          </mat-checkbox>
+          <mat-checkbox (change)="selectUser(row, 'MO')" [checked]="row.role === 'MO'" matTooltip="MO">
+          </mat-checkbox>
+        </mat-cell>
+      </ng-container>
+
+      <ng-container matColumnDef="name">
+        <mat-header-cell *matHeaderCellDef mat-sort-header> Nutzer </mat-header-cell>
+        <mat-cell *matCellDef="let row"> {{row.name}} </mat-cell>
+      </ng-container>
+
+      <mat-header-row *matHeaderRowDef="displayedUserColumns"></mat-header-row>
+      <mat-row *matRowDef="let row; columns: displayedUserColumns;"></mat-row>
+    </mat-table>
+  </div>
+</div>
diff --git a/src/app/superadmin/workspaces/workspaces.component.spec.ts b/src/app/superadmin/workspaces/workspaces.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..36be59aab54ec2b9163c8efa5870b62e2c9ea71d
--- /dev/null
+++ b/src/app/superadmin/workspaces/workspaces.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { WorkspacesComponent } from './workspaces.component';
+
+describe('WorkspacesComponent', () => {
+  let component: WorkspacesComponent;
+  let fixture: ComponentFixture<WorkspacesComponent>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ WorkspacesComponent ]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(WorkspacesComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/src/app/superadmin/workspaces/workspaces.component.ts b/src/app/superadmin/workspaces/workspaces.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..96dac73a4454595822233fffdb72c4fdc92503b3
--- /dev/null
+++ b/src/app/superadmin/workspaces/workspaces.component.ts
@@ -0,0 +1,273 @@
+import { EditworkspaceComponent } from './editworkspace/editworkspace.component';
+import { NewworkspaceComponent } from './newworkspace/newworkspace.component';
+import { BackendService, IdAndName, IdRoleData } from '../backend.service';
+import { MatTableDataSource } from '@angular/material/table';
+import { ViewChild, OnDestroy } from '@angular/core';
+
+import { Component, OnInit } from '@angular/core';
+import { MatDialog } from '@angular/material/dialog';
+import { MatSnackBar } from '@angular/material/snack-bar';
+import { MatSort } from '@angular/material/sort';
+import { FormGroup } from '@angular/forms';
+import { SelectionModel } from '@angular/cdk/collections';
+import {
+  ConfirmDialogComponent, ConfirmDialogData,
+  MessageDialogComponent, MessageDialogData, MessageType
+} from 'iqb-components';
+import { Subscription } from 'rxjs';
+import { MainDataService } from 'src/app/maindata.service';
+
+@Component({
+  templateUrl: './workspaces.component.html',
+  styleUrls: ['./workspaces.component.css']
+})
+export class WorkspacesComponent implements OnInit, OnDestroy {
+  public isSuperadmin = false;
+  public dataLoading = false;
+  public objectsDatasource: MatTableDataSource<IdAndName>;
+  public displayedColumns = ['selectCheckbox', 'name'];
+  private tableselectionCheckbox = new SelectionModel <IdAndName>(true, []);
+  private tableselectionRow = new SelectionModel <IdAndName>(false, []);
+  private selectedWorkspaceId = 0;
+  private selectedWorkspaceName = '';
+  private logindataSubscription: Subscription = null;
+
+  private pendingUserChanges = false;
+  public UserlistDatasource: MatTableDataSource<IdRoleData>;
+  public displayedUserColumns = ['selectCheckbox', 'name'];
+
+  @ViewChild(MatSort, { static: false }) sort: MatSort;
+
+  constructor(
+    private bs: BackendService,
+    private mds: MainDataService,
+    private newworkspaceDialog: MatDialog,
+    private editworkspaceDialog: MatDialog,
+    private deleteConfirmDialog: MatDialog,
+    private messsageDialog: MatDialog,
+    private snackBar: MatSnackBar
+  ) {
+    this.tableselectionRow.changed.subscribe(
+      r => {
+        if (r.added.length > 0) {
+          this.selectedWorkspaceId = r.added[0].id;
+          this.selectedWorkspaceName = r.added[0].name;
+        } else {
+          this.selectedWorkspaceId = 0;
+          this.selectedWorkspaceName = '';
+          }
+        this.updateUserList();
+      });
+  }
+
+  ngOnInit() {
+    this.logindataSubscription = this.mds.loginData$.subscribe(ld => {
+      this.isSuperadmin = ld.is_superadmin;
+      this.updateObjectList();
+    });
+  }
+
+  // ***********************************************************************************
+  addObject() {
+    const dialogRef = this.newworkspaceDialog.open(NewworkspaceComponent, {
+      width: '600px',
+      data: {
+        name: ''
+      }
+    });
+
+    dialogRef.afterClosed().subscribe(result => {
+      if (typeof result !== 'undefined') {
+        if (result !== false) {
+          this.dataLoading = true;
+          this.bs.addWorkspace((<FormGroup>result).get('name').value).subscribe(
+                respOk => {
+                  if (respOk) {
+                    this.snackBar.open('Arbeitsbereich hinzugefügt', '', {duration: 1000});
+                    this.updateObjectList();
+                  } else {
+                    this.snackBar.open('Konnte Arbeitsbereich nicht hinzufügen', 'Fehler', {duration: 1000});
+                  }
+                  this.dataLoading = false;
+                });
+        }
+      }
+    });
+  }
+
+  changeObject() {
+    let selectedRows = this.tableselectionRow.selected;
+    if (selectedRows.length === 0) {
+      selectedRows = this.tableselectionCheckbox.selected;
+    }
+    if (selectedRows.length === 0) {
+      this.messsageDialog.open(MessageDialogComponent, {
+        width: '400px',
+        data: <MessageDialogData>{
+          title: 'Arbeitsbereich ändern',
+          content: 'Bitte markieren Sie erst einen Arbeitsbereich!',
+          type: MessageType.error
+        }
+      });
+    } else {
+      const dialogRef = this.editworkspaceDialog.open(EditworkspaceComponent, {
+        width: '600px',
+        data: {
+          name: selectedRows[0].name,
+          oldname: selectedRows[0].name
+        }
+      });
+
+      dialogRef.afterClosed().subscribe(result => {
+        if (typeof result !== 'undefined') {
+          if (result !== false) {
+            this.dataLoading = true;
+            this.bs.renameWorkspace(selectedRows[0].id,
+                (<FormGroup>result).get('name').value).subscribe(
+                  respOk => {
+                    if (respOk) {
+                      this.snackBar.open('Arbeitsbereich geändert', '', {duration: 1000});
+                      this.updateObjectList();
+                    } else {
+                      this.snackBar.open('Konnte Arbeitsbereich nicht ändern', 'Fehler', {duration: 2000});
+                    }
+                    this.dataLoading = false;
+                  });
+          }
+        }
+      });
+    }
+  }
+
+  deleteObject() {
+    let selectedRows = this.tableselectionCheckbox.selected;
+    if (selectedRows.length === 0) {
+      selectedRows = this.tableselectionRow.selected;
+    }
+    if (selectedRows.length === 0) {
+      this.messsageDialog.open(MessageDialogComponent, {
+        width: '400px',
+        data: <MessageDialogData>{
+          title: 'Löschen von Arbeitsbereichen',
+          content: 'Bitte markieren Sie erst Arbeitsbereich/e!',
+          type: MessageType.error
+        }
+      });
+    } else {
+      let prompt = 'Soll';
+      if (selectedRows.length > 1) {
+        prompt = prompt + 'en ' + selectedRows.length + ' Arbeitsbereiche ';
+      } else {
+        prompt = prompt + ' Arbeitsbereich "' + selectedRows[0].name + '" ';
+      }
+      const dialogRef = this.deleteConfirmDialog.open(ConfirmDialogComponent, {
+        width: '400px',
+        data: <ConfirmDialogData>{
+          title: 'Löschen von Arbeitsbereichen',
+          content: prompt + 'gelöscht werden?',
+          confirmbuttonlabel: 'Arbeitsbereich/e löschen',
+          showcancel: true
+        }
+      });
+
+      dialogRef.afterClosed().subscribe(result => {
+        if (result !== false) {
+          // =========================================================
+          this.dataLoading = true;
+          const workspacesToDelete = [];
+          selectedRows.forEach((r: IdAndName) => workspacesToDelete.push(r.id));
+          this.bs.deleteWorkspaces(workspacesToDelete).subscribe(
+            respOk => {
+              if (respOk) {
+                this.snackBar.open('Arbeitsbereich/e gelöscht', '', {duration: 1000});
+                this.updateObjectList();
+                this.dataLoading = false;
+              } else {
+                this.snackBar.open('Konnte Arbeitsbereich/e nicht löschen', 'Fehler', {duration: 1000});
+                this.dataLoading = false;
+              }
+          });
+        }
+      });
+    }
+  }
+
+  // ***********************************************************************************
+  updateUserList() {
+    this.pendingUserChanges = false;
+    if (this.selectedWorkspaceId > 0) {
+      this.dataLoading = true;
+      this.bs.getUsersByWorkspace(this.selectedWorkspaceId).subscribe(dataresponse => {
+          this.UserlistDatasource = new MatTableDataSource(dataresponse);
+          this.dataLoading = false;
+        });
+    } else {
+      this.UserlistDatasource = null;
+    }
+  }
+
+  selectUser(ws: IdRoleData, role: string) {
+    if (ws.role === role) {
+      ws.role = '';
+    } else {
+      ws.role = role;
+    }
+    this.pendingUserChanges = true;
+  }
+
+  saveUsers() {
+    this.pendingUserChanges = false;
+    if (this.selectedWorkspaceId > 0) {
+      this.dataLoading = true;
+      this.bs.setUsersByWorkspace(this.selectedWorkspaceId, this.UserlistDatasource.data).subscribe(
+        respOk => {
+          if (respOk) {
+            this.snackBar.open('Zugriffsrechte geändert', '', {duration: 1000});
+          } else {
+            this.snackBar.open('Konnte Zugriffsrechte nicht ändern', 'Fehler', {duration: 2000});
+          }
+          this.dataLoading = false;
+        });
+    } else {
+      this.UserlistDatasource = null;
+    }
+  }
+
+  // ***********************************************************************************
+  updateObjectList() {
+    if (this.isSuperadmin) {
+      this.dataLoading = true;
+      this.bs.getWorkspaces().subscribe(dataresponse => {
+          this.objectsDatasource = new MatTableDataSource(dataresponse);
+          this.objectsDatasource.sort = this.sort;
+          this.tableselectionCheckbox.clear();
+          this.tableselectionRow.clear();
+          this.dataLoading = false;
+        }
+      );
+    }
+  }
+
+  isAllSelected() {
+    const numSelected = this.tableselectionCheckbox.selected.length;
+    const numRows = this.objectsDatasource.data.length;
+    return numSelected === numRows;
+  }
+
+  masterToggle() {
+    this.isAllSelected() ?
+        this.tableselectionCheckbox.clear() :
+        this.objectsDatasource.data.forEach(row => this.tableselectionCheckbox.select(row));
+  }
+
+  selectRow(row) {
+    this.tableselectionRow.select(row);
+  }
+
+  // % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %
+  ngOnDestroy() {
+    if (this.logindataSubscription !== null) {
+      this.logindataSubscription.unsubscribe();
+    }
+  }
+}
diff --git a/src/app/workspace/backend.service.spec.ts b/src/app/workspace/backend.service.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c31039d7e5bcc7bc70e7213ce06744a0dc6ed009
--- /dev/null
+++ b/src/app/workspace/backend.service.spec.ts
@@ -0,0 +1,15 @@
+import { TestBed, inject } from '@angular/core/testing';
+
+import { BackendService } from './backend.service';
+
+describe('BackendService', () => {
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      providers: [BackendService]
+    });
+  });
+
+  it('should be created', inject([BackendService], (service: BackendService) => {
+    expect(service).toBeTruthy();
+  }));
+});
diff --git a/src/app/workspace/backend.service.ts b/src/app/workspace/backend.service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..66d41e4ba047c4736204d46023d58b6f256873d5
--- /dev/null
+++ b/src/app/workspace/backend.service.ts
@@ -0,0 +1,154 @@
+import { GetFileResponseData, CheckWorkspaceResponseData, BookletsStarted, SysCheckStatistics,
+  ReviewData, LogData, UnitResponse, ResultData, MonitorData } from './workspace.interfaces';
+import {Injectable, Inject} from '@angular/core';
+import { HttpClient } from '@angular/common/http';
+import { Observable } from 'rxjs';
+import { catchError } from 'rxjs/operators';
+import {WorkspaceDataService} from "./workspacedata.service";
+import {MainDataService} from "../maindata.service";
+import { ErrorHandler, ServerError } from 'iqb-components';
+
+@Injectable()
+
+export class BackendService {
+  private serverUrlSlim = '';
+  private serverUrlSysCheck = '';
+
+  constructor(
+    @Inject('SERVER_URL') private readonly serverUrl: string,
+    private http: HttpClient,
+    private wds: WorkspaceDataService,
+    private mds: MainDataService) {
+
+    this.serverUrlSlim = this.serverUrl + 'php/ws.php/';
+    this.serverUrlSysCheck = this.serverUrl + 'php_admin/';
+    this.serverUrl = this.serverUrl + 'php/';
+  }
+
+
+  getFiles(): Observable<GetFileResponseData[] | ServerError> {
+    return this.http
+      .get<GetFileResponseData[]>(this.serverUrlSlim + 'filelist')
+        .pipe(
+          catchError(ErrorHandler.handle)
+        );
+  }
+
+  deleteFiles(filesToDelete: Array<string>): Observable<string | ServerError> {
+    return this.http
+      .post<string>(this.serverUrlSlim + 'delete', {f: filesToDelete})
+        .pipe(
+          catchError(ErrorHandler.handle)
+        );
+  }
+
+  checkWorkspace(): Observable<CheckWorkspaceResponseData | ServerError> {
+    return this.http
+      .post<CheckWorkspaceResponseData>(this.serverUrl + 'checkWorkspace.php', {})
+        .pipe(
+          catchError(ErrorHandler.handle)
+        );
+  }
+
+  getBookletsStarted(groups: string[]): Observable<BookletsStarted[] | ServerError> {
+    return this.http
+      .post<BookletsStarted[]>(this.serverUrl + 'getBookletsStarted.php', {g: groups})
+        .pipe(
+          catchError(ErrorHandler.handle)
+        );
+  }
+
+  lockBooklets(groups: string[]): Observable<boolean | ServerError> {
+    return this.http
+      .post<boolean>(this.serverUrlSlim + 'lock', {g: groups})
+        .pipe(
+          catchError(ErrorHandler.handle)
+        );
+  }
+
+  unlockBooklets(groups: string[]): Observable<boolean | ServerError> {
+    return this.http
+      .post<boolean>(this.serverUrlSlim + 'unlock', {g: groups})
+        .pipe(
+            catchError(ErrorHandler.handle)
+          );
+}
+
+  getMonitorData(): Observable<MonitorData[] | ServerError> {
+    return this.http
+      .post<MonitorData[]>(this.serverUrl + 'getMonitorData.php', {})
+        .pipe(
+          catchError(ErrorHandler.handle)
+        );
+}
+
+  getResultData(): Observable<ResultData[]> {
+    return this.http
+      .post<ResultData[]>(this.serverUrl + 'getResultData.php', {})
+        .pipe(
+          catchError(() => [])
+        );
+  }
+
+  getResponses(groups: string[]): Observable<UnitResponse[]> {
+    return this.http
+      .post<UnitResponse[]>(this.serverUrl + 'getResponses.php', {g: groups})
+        .pipe(
+          catchError(() => [])
+        );
+  }
+
+  getLogs(groups: string[]): Observable<LogData[]> {
+    return this.http
+      .post<LogData[]>(this.serverUrl + 'getLogs.php', {g: groups})
+        .pipe(
+          catchError(() => [])
+        );
+  }
+
+  getReviews(groups: string[]): Observable<ReviewData[]> {
+    return this.http
+      .post<ReviewData[]>(this.serverUrl + 'getReviews.php', {g: groups})
+        .pipe(
+          catchError(() => [])
+        );
+  }
+
+  deleteData(groups: string[]): Observable<boolean | ServerError> {
+    return this.http
+      .post<boolean>(this.serverUrl + 'deleteData.php', {g: groups})
+        .pipe(
+          catchError(ErrorHandler.handle)
+        );
+  }
+
+  getSysCheckReportList(): Observable<SysCheckStatistics[] | ServerError> {
+    const loginData = this.mds.loginData$.getValue();
+    return this.http
+      .post<SysCheckStatistics[]>(this.serverUrlSysCheck + 'getSysCheckReportList.php', {ws: this.wds.workspaceId$.getValue(), at: loginData.admintoken})
+        .pipe(
+          catchError(ErrorHandler.handle)
+        );
+  }
+
+  getSysCheckReport(reports: string[], columnDelimiter: string,
+                    quoteChar: string): Observable<string[] | ServerError> {
+    const loginData = this.mds.loginData$.getValue();
+    return this.http
+      .post<string[]>(this.serverUrlSysCheck + 'getSysCheckReport.php',
+        {r: reports, cd: columnDelimiter, q: quoteChar, ws: this.wds.workspaceId$.getValue(), at: loginData.admintoken})
+          .pipe(
+            catchError(ErrorHandler.handle)
+          );
+  }
+
+  deleteSysCheckReports(reports: string[]): Observable<boolean | ServerError> {
+    const loginData = this.mds.loginData$.getValue();
+    return this.http
+      .post<boolean>(this.serverUrlSysCheck + 'deleteSysCheckReports.php',
+        {r: reports, ws: this.wds.workspaceId$.getValue(), at: loginData.admintoken})
+          .pipe(
+            catchError(ErrorHandler.handle)
+          );
+  }
+}
diff --git a/src/app/workspace/files/files.component.css b/src/app/workspace/files/files.component.css
new file mode 100644
index 0000000000000000000000000000000000000000..58d6fe8541b8a2b32ef209f2b4299205905da969
--- /dev/null
+++ b/src/app/workspace/files/files.component.css
@@ -0,0 +1,50 @@
+.columnhost {
+  width: 100%;
+  display: flex;
+  flex-direction: row;
+  flex-wrap: wrap;
+  align-items: flex-start;
+  justify-content: left;
+}
+
+.filelist {
+  flex:  10 0 400px;
+}
+
+.checkboxcell {
+  overflow: visible;
+  flex: 0 0 30px;
+}
+
+.namecell {
+  flex: 3 3 60px;
+}
+
+.datecell {
+  flex: 1 1 5px;
+}
+
+.uploads {
+  flex:  10 0 200px;
+}
+
+
+.checkerror, .checkwarning, .checkinfo  {
+  margin: 20px;
+  font-size: 0.8em;
+}
+
+.checkerror {
+  color: brown;
+}
+.checkwarning {
+  color: goldenrod;
+}
+.checkinfo {
+  color: darkgreen;
+}
+
+.mat-raised-button {
+  min-width: 100px;
+  margin: 2px;
+}
\ No newline at end of file
diff --git a/src/app/workspace/files/files.component.html b/src/app/workspace/files/files.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..d611835af34b3f5ddbc5edd9702248b87f47c937
--- /dev/null
+++ b/src/app/workspace/files/files.component.html
@@ -0,0 +1,83 @@
+<div class="columnhost">
+  <div class="spinner-container" *ngIf="dataLoading">
+      <mat-spinner></mat-spinner>
+  </div>
+
+  <!-- ============================================= -->
+  <div class="filelist">
+    <mat-table #table [dataSource]="serverfiles" matSort>
+      <ng-container matColumnDef="checked">
+          <mat-header-cell *matHeaderCellDef class="checkboxcell">
+            <mat-checkbox (change)="checkAll($event.checked)"></mat-checkbox>
+          </mat-header-cell>
+          <mat-cell *matCellDef="let element" class="checkboxcell">
+            <mat-checkbox [checked]="element.isChecked" (change)="element.isChecked=$event.checked"></mat-checkbox>
+          </mat-cell>
+      </ng-container>
+
+      <ng-container matColumnDef="typelabel">
+        <mat-header-cell *matHeaderCellDef mat-sort-header> Typ </mat-header-cell>
+        <mat-cell *matCellDef="let element"> {{element.typelabel}} </mat-cell>
+      </ng-container>
+
+      <ng-container matColumnDef="filename">
+        <mat-header-cell *matHeaderCellDef mat-sort-header class="namecell"> Name </mat-header-cell>
+        <mat-cell *matCellDef="let element" class="namecell"><a target="_blank" [href]="getDownloadRef(element)">{{element.filename}}</a> </mat-cell>
+      </ng-container>
+
+      <ng-container matColumnDef="filedatetime">
+        <mat-header-cell *matHeaderCellDef mat-sort-header class="datecell"> Datum </mat-header-cell>
+        <mat-cell *matCellDef="let element" class="datecell"> {{element.filedatetimestr}} </mat-cell>
+      </ng-container>
+
+      <ng-container matColumnDef="filesize">
+        <mat-header-cell *matHeaderCellDef mat-sort-header> Größe </mat-header-cell>
+        <mat-cell *matCellDef="let element"> {{element.filesizestr}} </mat-cell>
+      </ng-container>
+
+
+      <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
+      <mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
+    </mat-table>
+  </div>
+
+  <!-- ============================================= -->
+  <div class="uploads">
+    <button mat-raised-button (click)="deleteFiles()" matTooltip="Markierte Dateien löschen" matTooltipPosition="above" [disabled]="wds.wsRole !== 'RW'">
+      <mat-icon>delete</mat-icon>
+    </button>
+    <button mat-raised-button (click)="hiddenfileinput.click()" matTooltip="Dateien hochladen/aktualisieren" matTooltipPosition="above" [disabled]="wds.wsRole !== 'RW'">
+      <mat-icon>cloud_upload</mat-icon>
+    </button>
+    <button mat-raised-button (click)="checkWorkspace()" matTooltip="Arbeitsbereich prüfen" matTooltipPosition="above">
+      <mat-icon>check</mat-icon>
+    </button>
+
+    <input #hiddenfileinput type="file" name="fileforvo" multiple [iqbFilesUploadInputFor]="fileUploadQueue" [hidden]="true"/>
+
+    <iqb-files-upload-queue #fileUploadQueue
+      [httpUrl]="uploadUrl"
+      [fileAlias]="fileNameAlias"
+      [tokenName]="'at'"
+      [token]="'kisduUjjw.;kiskw..9200'"
+      [folderName]="'ws'"
+      [folder]="'workspace'"
+      (uploadCompleteEvent)="updateFileList()">
+    </iqb-files-upload-queue>
+
+    <p *ngFor="let e of checkErrors" class="checkerror">
+      {{ e }}
+    </p>
+
+    <p *ngFor="let w of checkWarnings" class="checkwarning">
+      {{ w }}
+    </p>
+
+    <p *ngFor="let i of checkInfos" class="checkinfo">
+      {{ i }}
+    </p>
+
+    <br/>
+
+  </div>
+</div>
diff --git a/src/app/workspace/files/files.component.spec.ts b/src/app/workspace/files/files.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..da941cc1423eb4e0ccee04599f7a30827265304c
--- /dev/null
+++ b/src/app/workspace/files/files.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { FilesComponent } from './files.component';
+
+describe('FilesComponent', () => {
+  let component: FilesComponent;
+  let fixture: ComponentFixture<FilesComponent>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ FilesComponent ]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(FilesComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/src/app/workspace/files/files.component.ts b/src/app/workspace/files/files.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..45445a2ef5034daf47fa8652a99e1337c915478f
--- /dev/null
+++ b/src/app/workspace/files/files.component.ts
@@ -0,0 +1,186 @@
+import { MainDataService } from '../../maindata.service';
+import { WorkspaceDataService } from '../workspacedata.service';
+import { GetFileResponseData, CheckWorkspaceResponseData } from '../workspace.interfaces';
+import { ConfirmDialogComponent, ConfirmDialogData, MessageDialogComponent,
+  MessageDialogData, MessageType, ServerError } from 'iqb-components';
+import { Subscription } from 'rxjs';
+import { MatTableDataSource } from '@angular/material/table';
+import { MatSnackBar } from '@angular/material/snack-bar';
+import { BackendService } from '../backend.service';
+import { Component, OnInit, Inject, OnDestroy } from '@angular/core';
+import { ViewChild } from '@angular/core';
+import { MatDialog } from '@angular/material/dialog';
+import { MatSort } from '@angular/material/sort';
+
+@Component({
+  templateUrl: './files.component.html',
+  styleUrls: ['./files.component.css']
+})
+export class FilesComponent implements OnInit, OnDestroy {
+  public serverfiles: MatTableDataSource<GetFileResponseData>;
+  public displayedColumns = ['checked', 'filename', 'typelabel', 'filesize', 'filedatetime'];
+  public dataLoading = false;
+  private workspaceIdSubscription: Subscription = null;
+
+  // for fileupload
+  public uploadUrl = '';
+  public fileNameAlias = 'fileforvo';
+
+  // for workspace-check
+  public checkErrors = [];
+  public checkWarnings = [];
+  public checkInfos = [];
+
+  @ViewChild(MatSort, { static: true }) sort: MatSort;
+
+  constructor(
+    @Inject('SERVER_URL') private serverUrl: string,
+    private bs: BackendService,
+    private mds: MainDataService,
+    public wds: WorkspaceDataService,
+    public confirmDialog: MatDialog,
+    public messsageDialog: MatDialog,
+    public snackBar: MatSnackBar
+  ) {
+    this.uploadUrl = this.serverUrl + 'php/uploadFile.php';
+  }
+
+  ngOnInit() {
+    this.workspaceIdSubscription = this.wds.workspaceId$.subscribe(() => {
+      this.updateFileList((this.wds.ws <= 0) || (this.mds.adminToken.length === 0));
+    });
+  }
+
+  // ***********************************************************************************
+  checkAll(isChecked: boolean) {
+    this.serverfiles.data.forEach(element => {
+      element.isChecked = isChecked;
+    });
+  }
+
+  // ***********************************************************************************
+  deleteFiles() {
+    if (this.wds.wsRole === 'RW') {
+      this.checkErrors = [];
+      this.checkWarnings = [];
+      this.checkInfos = [];
+
+      const filesToDelete = [];
+      this.serverfiles.data.forEach(element => {
+        if (element.isChecked) {
+          filesToDelete.push(element.type + '::' + element.filename);
+        }
+      });
+
+      if (filesToDelete.length > 0) {
+        let prompt = 'Sie haben ';
+        if (filesToDelete.length > 1) {
+          prompt = prompt + filesToDelete.length + ' Dateien ausgewählt. Sollen';
+        } else {
+          prompt = prompt + ' eine Datei ausgewählt. Soll';
+        }
+        const dialogRef = this.confirmDialog.open(ConfirmDialogComponent, {
+          width: '400px',
+          data: <ConfirmDialogData>{
+            title: 'Löschen von Dateien',
+            content: prompt + ' diese gelöscht werden?',
+            confirmbuttonlabel: 'Löschen',
+            showcancel: true
+          }
+        });
+
+        dialogRef.afterClosed().subscribe(result => {
+          if (result !== false) {
+            // =========================================================
+            this.dataLoading = true;
+            this.bs.deleteFiles(filesToDelete).subscribe(deletefilesresponse => {
+              if (deletefilesresponse instanceof ServerError) {
+                this.wds.setNewErrorMsg(deletefilesresponse as ServerError);
+              } else {
+                const deletefilesresponseOk = deletefilesresponse as string;
+                if ((deletefilesresponseOk.length > 5) && (deletefilesresponseOk.substr(0, 2) === 'e:')) {
+                  this.snackBar.open(deletefilesresponseOk.substr(2), 'Fehler', {duration: 1000});
+                } else {
+                  this.snackBar.open(deletefilesresponseOk, '', {duration: 1000});
+                  this.updateFileList();
+                }
+                this.wds.setNewErrorMsg();
+              }
+            });
+            // =========================================================
+          }
+        });
+      } else {
+        this.messsageDialog.open(MessageDialogComponent, {
+          width: '400px',
+          data: <MessageDialogData>{
+            title: 'Löschen von Dateien',
+            content: 'Bitte markieren Sie erst Dateien!',
+            type: MessageType.error
+          }
+        });
+      }
+    }
+  }
+
+  // ***********************************************************************************
+  updateFileList(empty = false) {
+    this.checkErrors = [];
+    this.checkWarnings = [];
+    this.checkInfos = [];
+
+    if (empty || this.wds.wsRole === 'MO') {
+      this.serverfiles = new MatTableDataSource([]);
+    } else {
+      this.dataLoading = true;
+      this.bs.getFiles().subscribe(
+        (filedataresponse: GetFileResponseData[]) => {
+          this.serverfiles = new MatTableDataSource(filedataresponse);
+          this.serverfiles.sort = this.sort;
+          this.dataLoading = false;
+          this.wds.setNewErrorMsg();
+        }, (err: ServerError) => {
+          this.wds.setNewErrorMsg(err);
+          this.dataLoading = false;
+        }
+      );
+    }
+  }
+
+  // ***********************************************************************************
+  getDownloadRef(element: GetFileResponseData): string {
+    return this.serverUrl
+        + 'php/getFile.php?t=' + element.type
+        + '&fn=' + element.filename
+        + '&at=' + this.mds.adminToken
+        + '&ws=' + this.wds.ws.toString();
+  }
+
+  checkWorkspace() {
+    this.checkErrors = [];
+    this.checkWarnings = [];
+    this.checkInfos = [];
+
+    this.dataLoading = true;
+    this.bs.checkWorkspace().subscribe(
+      (checkResponse: CheckWorkspaceResponseData) => {
+        this.checkErrors = checkResponse.errors;
+        this.checkWarnings = checkResponse.warnings;
+        this.checkInfos = checkResponse.infos;
+        this.wds.setNewErrorMsg();
+
+        this.dataLoading = false;
+      }, (err: ServerError) => {
+        this.wds.setNewErrorMsg(err);
+        this.dataLoading = false;
+      }
+    );
+  }
+
+  // % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %
+  ngOnDestroy() {
+    if (this.workspaceIdSubscription !== null) {
+      this.workspaceIdSubscription.unsubscribe();
+    }
+  }
+}
diff --git a/src/app/workspace/index.ts b/src/app/workspace/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..30c7aa4c2daa6ada54bf85e7876130ae495ef6a5
--- /dev/null
+++ b/src/app/workspace/index.ts
@@ -0,0 +1,3 @@
+export { WorkspaceComponent } from './workspace.component';
+export { WorkspaceModule } from './workspace.module';
+export { WorkspaceDataService } from './workspacedata.service';
diff --git a/src/app/workspace/monitor/monitor.component.css b/src/app/workspace/monitor/monitor.component.css
new file mode 100644
index 0000000000000000000000000000000000000000..1c9da90e99d273d82175a86823b7ba97bbd0fc99
--- /dev/null
+++ b/src/app/workspace/monitor/monitor.component.css
@@ -0,0 +1,29 @@
+.columnhost {
+  width: 100%;
+  display: flex;
+  flex-direction: row;
+  flex-wrap: wrap;
+  align-items: flex-start;
+  justify-content: left;
+}
+/* .mat-card {
+  max-width: 50%;
+  margin-top: 20px;
+}
+
+.title {
+  margin-top: 2550px;
+} */
+
+/* table {
+  width: 100%;
+} */
+
+.cellstyle1 {
+  padding: 5px;
+}
+
+.mat-raised-button {
+  margin: 5px;
+  min-width: 100px;
+}
\ No newline at end of file
diff --git a/src/app/workspace/monitor/monitor.component.html b/src/app/workspace/monitor/monitor.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..6fbe2f3a22d222199e4a6ed986aa125fc889906e
--- /dev/null
+++ b/src/app/workspace/monitor/monitor.component.html
@@ -0,0 +1,75 @@
+<div class="columnhost" fxLayout="column">
+  <div class="spinner-container" *ngIf="dataLoading">
+    <mat-spinner></mat-spinner>
+  </div>
+  <div fxLayout="row">
+    <button mat-raised-button (click)="downloadCSV()" [disabled]="!tableselectionCheckbox.hasValue()"
+        matTooltip="Download markierte Gruppen als CSV für Excel" matTooltipPosition="above">
+      <mat-icon>cloud_download</mat-icon>
+    </button>
+    <button mat-raised-button (click)="lock()" [disabled]="!tableselectionCheckbox.hasValue() || (wds.wsRole !== 'RW')"
+        matTooltip="Sperre gestartete Testhefte für markierte Gruppen" matTooltipPosition="above">
+      <mat-icon>lock</mat-icon>
+    </button>
+
+    <button mat-raised-button (click)="unlock()" [disabled]="!tableselectionCheckbox.hasValue() || (wds.wsRole !== 'RW')"
+        matTooltip="Gesperrte Testhefte für markierte Gruppen freigeben" matTooltipPosition="above">
+      <mat-icon>lock_open</mat-icon>
+    </button>
+  </div>
+
+  <mat-table [dataSource]="monitorDataSource" matSort>
+    <ng-container matColumnDef="selectCheckbox">
+      <mat-header-cell *matHeaderCellDef fxFlex="70px">
+        <mat-checkbox (change)="$event ? masterToggle() : null"
+                      [checked]="tableselectionCheckbox.hasValue() && isAllSelected()"
+                      [indeterminate]="tableselectionCheckbox.hasValue() && !isAllSelected()">
+        </mat-checkbox>
+      </mat-header-cell>
+      <mat-cell *matCellDef="let row" fxFlex="70px">
+        <mat-checkbox (click)="$event.stopPropagation()"
+                      (change)="$event ? tableselectionCheckbox.toggle(row) : null"
+                      [checked]="tableselectionCheckbox.isSelected(row)">
+        </mat-checkbox>
+      </mat-cell>
+    </ng-container>
+
+    <ng-container matColumnDef="groupname">
+      <mat-header-cell *matHeaderCellDef mat-sort-header fxFlex="300px">Login-Gruppe</mat-header-cell>
+      <mat-cell *matCellDef="let element" fxFlex="300px">{{element.groupname}}</mat-cell>
+    </ng-container>
+
+    <ng-container matColumnDef="loginsPrepared">
+      <mat-header-cell *matHeaderCellDef mat-sort-header fxLayoutAlign="center center">Logins</mat-header-cell>
+      <mat-cell *matCellDef="let element" fxLayoutAlign="center center">{{element.loginsPrepared}} </mat-cell>
+    </ng-container>
+
+    <ng-container matColumnDef="personsPrepared">
+      <mat-header-cell *matHeaderCellDef mat-sort-header fxLayoutAlign="center center">Personen</mat-header-cell>
+      <mat-cell *matCellDef="let element" fxLayoutAlign="center center"> {{element.personsPrepared}} </mat-cell>
+    </ng-container>
+
+    <ng-container matColumnDef="bookletsPrepared">
+      <mat-header-cell *matHeaderCellDef mat-sort-header fxLayoutAlign="center center">Testhefte insges.</mat-header-cell>
+      <mat-cell *matCellDef="let element" fxLayoutAlign="center center"> {{element.bookletsPrepared}} </mat-cell>
+    </ng-container>
+
+    <ng-container matColumnDef="bookletsStarted">
+      <mat-header-cell *matHeaderCellDef mat-sort-header fxLayoutAlign="center center">Testhefte gestartet</mat-header-cell>
+      <mat-cell *matCellDef="let element" fxLayoutAlign="center center"> {{element.bookletsStarted}} </mat-cell>
+    </ng-container>
+
+    <ng-container matColumnDef="bookletsLocked">
+      <mat-header-cell *matHeaderCellDef mat-sort-header fxLayoutAlign="center center">gesperrte Testhefte</mat-header-cell>
+      <mat-cell *matCellDef="let element" fxLayoutAlign="center center"> {{ element.bookletsLocked }} </mat-cell>
+    </ng-container>
+
+    <ng-container matColumnDef="laststart">
+      <mat-header-cell *matHeaderCellDef mat-sort-header fxLayoutAlign="center center">Letzter Start</mat-header-cell>
+      <mat-cell *matCellDef="let element" fxLayoutAlign="center center"> {{ element.laststartStr }} </mat-cell>
+    </ng-container>
+
+    <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
+    <mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
+  </mat-table>
+</div>
diff --git a/src/app/workspace/monitor/monitor.component.spec.ts b/src/app/workspace/monitor/monitor.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..18aec0382cd2c882ebf8799916e54a679397476b
--- /dev/null
+++ b/src/app/workspace/monitor/monitor.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { MonitorComponent } from './monitor.component';
+
+describe('MonitorComponent', () => {
+  let component: MonitorComponent;
+  let fixture: ComponentFixture<MonitorComponent>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ MonitorComponent ]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(MonitorComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/src/app/workspace/monitor/monitor.component.ts b/src/app/workspace/monitor/monitor.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d8a28b07ba2276bd6bbf2dac76931e5c3e0a4581
--- /dev/null
+++ b/src/app/workspace/monitor/monitor.component.ts
@@ -0,0 +1,159 @@
+import { BookletsStarted } from '../workspace.interfaces';
+import { WorkspaceDataService } from '../workspacedata.service';
+import { BackendService } from '../backend.service';
+import { Component, OnInit, ViewChild, OnDestroy } from '@angular/core';
+import { MatSnackBar } from '@angular/material/snack-bar';
+import { MatSort } from '@angular/material/sort';
+import { MatTableDataSource } from '@angular/material/table';
+import { SelectionModel } from '@angular/cdk/collections';
+import { saveAs } from 'file-saver';
+import { MonitorData } from '../workspace.interfaces';
+import { Subscription } from 'rxjs';
+import { ServerError } from 'iqb-components';
+
+
+@Component({
+  templateUrl: './monitor.component.html',
+  styleUrls: ['./monitor.component.css']
+})
+export class MonitorComponent implements OnInit, OnDestroy {
+
+  displayedColumns: string[] = ['selectCheckbox', 'groupname', 'loginsPrepared',
+          'personsPrepared', 'bookletsPrepared', 'bookletsStarted', 'bookletsLocked', 'laststart'];
+  public monitorDataSource = new MatTableDataSource<MonitorData>([]);
+  public tableselectionCheckbox = new SelectionModel<MonitorData>(true, []);
+  private workspaceIdSubscription: Subscription = null;
+  public dataLoading = false;
+  @ViewChild(MatSort, { static: true }) sort: MatSort;
+
+  constructor(
+    private bs: BackendService,
+    public wds: WorkspaceDataService,
+    public snackBar: MatSnackBar
+  ) { }
+
+  ngOnInit() {
+    this.workspaceIdSubscription = this.wds.workspaceId$.subscribe(() => {
+      this.updateTable();
+    });
+  }
+
+  updateTable() {
+    this.dataLoading = true;
+    this.tableselectionCheckbox.clear();
+    this.bs.getMonitorData().subscribe(
+      (monitorData: MonitorData[]) => {
+        this.dataLoading = false;
+        this.monitorDataSource = new MatTableDataSource<MonitorData>(monitorData);
+        this.monitorDataSource.sort = this.sort;
+      }
+    );
+  }
+
+  isAllSelected() {
+    const numSelected = this.tableselectionCheckbox.selected.length;
+    const numRows = this.monitorDataSource.data.length;
+    return numSelected === numRows;
+  }
+
+  masterToggle() {
+    this.isAllSelected() ?
+        this.tableselectionCheckbox.clear() :
+        this.monitorDataSource.data.forEach(row => this.tableselectionCheckbox.select(row));
+  }
+
+  downloadCSV() {
+    if (this.tableselectionCheckbox.selected.length > 0) {
+      this.dataLoading = true;
+      const selectedGroups: string[] = [];
+      this.tableselectionCheckbox.selected.forEach(element => {
+        selectedGroups.push(element.groupname);
+      });
+      this.bs.getBookletsStarted(selectedGroups).subscribe(bData => {
+
+          const bookletList = bData as BookletsStarted[];
+          if (bookletList.length > 0) {
+            const columnDelimiter = ';';
+            const lineDelimiter = '\n';
+
+            let myCsvData = 'groupname' + columnDelimiter + 'loginname' + columnDelimiter + 'code' + columnDelimiter +
+                'bookletname' + columnDelimiter + 'locked' + columnDelimiter + 'laststart' + lineDelimiter;
+            bookletList.forEach((b: BookletsStarted) => {
+               myCsvData += '"'
+                 + b.groupname + '"' + columnDelimiter + '"'
+                 + b.loginname + '"' + columnDelimiter + '"'
+                 + b.code + '"' + columnDelimiter + '"'
+                 + b.bookletname + '"' + columnDelimiter
+                 + '"' + (b.locked ? 'X' : '-') + '"' + columnDelimiter + '"'
+                 + b.laststart + '"' + lineDelimiter;
+            });
+            const blob = new Blob([myCsvData], {type: 'text/csv;charset=utf-8'});
+            saveAs(blob, 'iqb-testcenter-bookletsStarted.csv');
+          } else {
+            this.snackBar.open('Keine Daten verfügbar.', 'Fehler', {duration: 3000});
+          }
+
+          this.tableselectionCheckbox.clear();
+          this.dataLoading = false;
+        }
+      );
+    }
+  }
+
+  lock() {
+    if (this.tableselectionCheckbox.selected.length > 0) {
+      this.dataLoading = true;
+      const selectedGroups: string[] = [];
+      this.tableselectionCheckbox.selected.forEach(element => {
+        selectedGroups.push(element.groupname);
+      });
+      this.bs.lockBooklets(selectedGroups).subscribe(success => {
+        if (success instanceof ServerError) {
+          this.wds.setNewErrorMsg(success as ServerError);
+          this.snackBar.open('Testhefte konnten nicht gesperrt werden.', 'Systemfehler', {duration: 3000});
+        } else {
+          const ok = success as boolean;
+          if (ok) {
+            this.snackBar.open('Testhefte wurden gesperrt.', 'Sperrung', {duration: 1000});
+          } else {
+            this.snackBar.open('Testhefte konnten nicht gesperrt werden.', 'Fehler', {duration: 3000});
+          }
+        }
+        this.dataLoading = false;
+        this.updateTable();
+      });
+    }
+  }
+
+  unlock() {
+    if (this.tableselectionCheckbox.selected.length > 0) {
+      this.dataLoading = true;
+      const selectedGroups: string[] = [];
+      this.tableselectionCheckbox.selected.forEach(element => {
+        selectedGroups.push(element.groupname);
+      });
+      this.bs.unlockBooklets(selectedGroups).subscribe(success => {
+        if (success instanceof ServerError) {
+          this.wds.setNewErrorMsg(success as ServerError);
+          this.snackBar.open('Testhefte konnten nicht freigegeben werden.', 'Systemfehler', {duration: 3000});
+        } else {
+          const ok = success as boolean;
+          if (ok) {
+            this.snackBar.open('Testhefte wurden freigegeben.', 'Sperrung', {duration: 1000});
+          } else {
+            this.snackBar.open('Testhefte konnten nicht freigegeben werden.', 'Fehler', {duration: 3000});
+          }
+        }
+        this.dataLoading = false;
+        this.updateTable();
+      });
+    }
+  }
+
+  // % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %
+  ngOnDestroy() {
+    if (this.workspaceIdSubscription !== null) {
+      this.workspaceIdSubscription.unsubscribe();
+    }
+  }
+}
diff --git a/src/app/workspace/results/results.component.css b/src/app/workspace/results/results.component.css
new file mode 100644
index 0000000000000000000000000000000000000000..e43a89f4bc4ed0d6e22ce350432e61e6fa1c5e8e
--- /dev/null
+++ b/src/app/workspace/results/results.component.css
@@ -0,0 +1,17 @@
+/* .columnhost {
+  width: 100%;
+  display: flex;
+  flex-direction: row;
+  flex-wrap: wrap;
+  align-items: flex-start;
+  justify-content: left;
+} */
+
+/* .mat-icon {
+  margin-right: 5px;
+} */
+
+.mat-raised-button {
+  min-width: 100px;
+  margin: 2px;
+}
\ No newline at end of file
diff --git a/src/app/workspace/results/results.component.html b/src/app/workspace/results/results.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..5ac0ebf46d395908c958eeef01f0cde816964f7d
--- /dev/null
+++ b/src/app/workspace/results/results.component.html
@@ -0,0 +1,73 @@
+<div class="columnhost" fxLayout="column">
+  <div class="spinner-container" *ngIf="dataLoading">
+    <mat-spinner></mat-spinner>
+  </div>
+  <div fxLayout="row">
+    <button mat-raised-button (click)="downloadResponsesCSV()" [disabled]="!tableselectionCheckbox.hasValue()"
+        matTooltip="Download markierte Gruppen als CSV für Excel" matTooltipPosition="above">
+      <mat-icon>cloud_download</mat-icon>Antworten
+    </button>
+    <button mat-raised-button (click)="downloadLogsCSV()" [disabled]="!tableselectionCheckbox.hasValue()"
+        matTooltip="Download markierte Gruppen als CSV für Excel" matTooltipPosition="above">
+      <mat-icon>cloud_download</mat-icon>Logs
+    </button>
+    <button mat-raised-button (click)="downloadReviewsCSV()" [disabled]="!tableselectionCheckbox.hasValue()"
+        matTooltip="Download markierte Gruppen als CSV für Excel" matTooltipPosition="above">
+      <mat-icon>cloud_download</mat-icon>Kommentare
+    </button>
+    <button mat-raised-button (click)="deleteData()" [disabled]="!tableselectionCheckbox.hasValue() || (wds.wsRole !== 'RW')"
+        matTooltip="Löschen Ergebnisdaten aus der Datenbank für markierte Gruppen" matTooltipPosition="above">
+      <mat-icon>delete</mat-icon>
+    </button>
+  </div>
+
+  <mat-table [dataSource]="resultDataSource" matSort>
+    <ng-container matColumnDef="selectCheckbox">
+      <mat-header-cell *matHeaderCellDef fxFlex="70px">
+        <mat-checkbox (change)="$event ? masterToggle() : null"
+                      [checked]="tableselectionCheckbox.hasValue() && isAllSelected()"
+                      [indeterminate]="tableselectionCheckbox.hasValue() && !isAllSelected()">
+        </mat-checkbox>
+      </mat-header-cell>
+      <mat-cell *matCellDef="let row" fxFlex="70px">
+        <mat-checkbox (click)="$event.stopPropagation()"
+                      (change)="$event ? tableselectionCheckbox.toggle(row) : null"
+                      [checked]="tableselectionCheckbox.isSelected(row)">
+        </mat-checkbox>
+      </mat-cell>
+    </ng-container>
+
+    <ng-container matColumnDef="groupname">
+      <mat-header-cell *matHeaderCellDef mat-sort-header fxFlex="300px">Login-Gruppe</mat-header-cell>
+      <mat-cell *matCellDef="let element" fxFlex="300px">{{element.groupname}}</mat-cell>
+    </ng-container>
+
+    <ng-container matColumnDef="bookletsStarted">
+      <mat-header-cell *matHeaderCellDef mat-sort-header fxLayoutAlign="center center">Testhefte gestartet</mat-header-cell>
+      <mat-cell *matCellDef="let element" fxLayoutAlign="center center"> {{element.bookletsStarted}} </mat-cell>
+    </ng-container>
+
+    <ng-container matColumnDef="num_units_min">
+      <mat-header-cell *matHeaderCellDef mat-sort-header fxLayoutAlign="center center">Aufgaben min</mat-header-cell>
+      <mat-cell *matCellDef="let element" fxLayoutAlign="center center">{{element.num_units_min}} </mat-cell>
+    </ng-container>
+
+    <ng-container matColumnDef="num_units_max">
+      <mat-header-cell *matHeaderCellDef mat-sort-header fxLayoutAlign="center center">Aufgaben max</mat-header-cell>
+      <mat-cell *matCellDef="let element" fxLayoutAlign="center center">{{element.num_units_max}} </mat-cell>
+    </ng-container>
+
+    <ng-container matColumnDef="num_units_mean">
+      <mat-header-cell *matHeaderCellDef mat-sort-header fxLayoutAlign="center center">Aufgaben Mittelwert</mat-header-cell>
+      <mat-cell *matCellDef="let element" fxLayoutAlign="center center">{{element.num_units_mean | number:'1.1-1'}} </mat-cell>
+    </ng-container>
+
+    <ng-container matColumnDef="lastchange">
+      <mat-header-cell *matHeaderCellDef mat-sort-header fxLayoutAlign="center center">Letzte Änderung</mat-header-cell>
+      <mat-cell *matCellDef="let element" fxLayoutAlign="center center">{{element.lastchange | date:'dd.MM.yyyy HH:mm'}} </mat-cell>
+    </ng-container>
+
+    <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
+    <mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
+  </mat-table>
+</div>
diff --git a/src/app/workspace/results/results.component.spec.ts b/src/app/workspace/results/results.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..23c08dfbd9069ff0c88a396817f452a838b0fd51
--- /dev/null
+++ b/src/app/workspace/results/results.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { ResultsComponent } from './results.component';
+
+describe('SharedFilesComponent', () => {
+  let component: ResultsComponent;
+  let fixture: ComponentFixture<ResultsComponent>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ ResultsComponent ]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(ResultsComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/src/app/workspace/results/results.component.ts b/src/app/workspace/results/results.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..4c4bfe54e7e65b7c3b2871b77ff782fbf0016f06
--- /dev/null
+++ b/src/app/workspace/results/results.component.ts
@@ -0,0 +1,273 @@
+import { LogData } from '../workspace.interfaces';
+import { WorkspaceDataService } from '../workspacedata.service';
+import { ConfirmDialogComponent, ConfirmDialogData } from 'iqb-components';
+import { Component, OnInit, ViewChild, OnDestroy } from '@angular/core';
+import { BackendService } from '../backend.service';
+import { MatDialog } from '@angular/material/dialog';
+import { MatSnackBar } from '@angular/material/snack-bar';
+import { MatSort } from '@angular/material/sort';
+import { MatTableDataSource } from '@angular/material/table';
+import { SelectionModel } from '@angular/cdk/collections';
+import { saveAs } from 'file-saver';
+import { ResultData, UnitResponse, ReviewData } from '../workspace.interfaces';
+import { Subscription } from 'rxjs';
+
+
+@Component({
+  templateUrl: './results.component.html',
+  styleUrls: ['./results.component.css']
+})
+export class ResultsComponent implements OnInit, OnDestroy {
+  displayedColumns: string[] = ['selectCheckbox', 'groupname', 'bookletsStarted', 'num_units_min', 'num_units_max', 'num_units_mean', 'lastchange'];
+  public resultDataSource = new MatTableDataSource<ResultData>([]);
+  // prepared for selection if needed sometime
+  public tableselectionCheckbox = new SelectionModel<ResultData>(true, []);
+  public dataLoading = false;
+  private workspaceIdSubscription: Subscription = null;
+
+  @ViewChild(MatSort, { static: true }) sort: MatSort;
+
+  constructor(
+    private bs: BackendService,
+    public wds: WorkspaceDataService,
+    private deleteConfirmDialog: MatDialog,
+    public snackBar: MatSnackBar
+  ) { }
+
+  ngOnInit() {
+    this.workspaceIdSubscription = this.wds.workspaceId$.subscribe(() => {
+      this.updateTable();
+    });
+  }
+
+  updateTable() {
+    this.tableselectionCheckbox.clear();
+    if (this.wds.wsRole === 'MO') {
+      this.resultDataSource = new MatTableDataSource<ResultData>([]);
+    } else {
+      this.dataLoading = true;
+      this.bs.getResultData().subscribe(
+        (resultData: ResultData[]) => {
+          this.dataLoading = false;
+          this.resultDataSource = new MatTableDataSource<ResultData>(resultData);
+          this.resultDataSource.sort = this.sort;
+        }
+      );
+    }
+  }
+
+  isAllSelected() {
+    const numSelected = this.tableselectionCheckbox.selected.length;
+    const numRows = this.resultDataSource.data.length;
+    return numSelected === numRows;
+  }
+
+  masterToggle() {
+    this.isAllSelected() ?
+        this.tableselectionCheckbox.clear() :
+        this.resultDataSource.data.forEach(row => this.tableselectionCheckbox.select(row));
+  }
+
+  // 444444444444444444444444444444444444444444444444444444444444444444444444444444444444444
+  downloadResponsesCSV() {
+    if (this.tableselectionCheckbox.selected.length > 0) {
+      this.dataLoading = true;
+      const selectedGroups: string[] = [];
+      this.tableselectionCheckbox.selected.forEach(element => {
+        selectedGroups.push(element.groupname);
+      });
+      this.bs.getResponses(selectedGroups).subscribe(
+      (responseData: UnitResponse[]) => {
+        if (responseData.length > 0) {
+          const columnDelimiter = ';';
+          const lineDelimiter = '\n';
+          let myCsvData = 'groupname' + columnDelimiter
+              + 'loginname' + columnDelimiter
+              + 'code' + columnDelimiter
+              + 'bookletname' + columnDelimiter
+              + 'unitname' + columnDelimiter
+              + 'responses' + columnDelimiter
+              + 'restorePoint' + columnDelimiter
+              + 'responseType' + columnDelimiter
+              + 'response-ts' + columnDelimiter
+              + 'restorePoint-ts' + columnDelimiter
+              + 'laststate' + lineDelimiter;
+          responseData.forEach((resp: UnitResponse) => {
+            myCsvData += '"' + resp.groupname + '"' + columnDelimiter
+                + '"' + resp.loginname + '"' + columnDelimiter
+                + '"' + resp.code + '"' + columnDelimiter
+                + '"' + resp.bookletname + '"' + columnDelimiter
+                + '"' + resp.unitname + '"' + columnDelimiter;
+            if ((resp.responses !== null) && (resp.responses.length > 0)) {
+              myCsvData += resp.responses.replace(/\\"/g, '""') + columnDelimiter;
+            } else {
+              myCsvData += columnDelimiter;
+            }
+            if ((resp.restorepoint !== null) && (resp.restorepoint.length > 0)) {
+              myCsvData += resp.restorepoint.replace(/\\"/g, '""') + columnDelimiter;
+            } else {
+              myCsvData += columnDelimiter;
+            }
+            if ((resp.responsetype !== null) && (resp.responsetype.length > 0)) {
+              myCsvData += '"' + resp.responsetype + '"' + columnDelimiter;
+            } else {
+              myCsvData += columnDelimiter;
+            }
+            myCsvData += resp.responses_ts + columnDelimiter + resp.restorepoint_ts + columnDelimiter;
+            if ((resp.laststate !== null) && (resp.laststate.length > 0)) {
+              myCsvData += '"' + resp.laststate + '"' + lineDelimiter;
+            } else {
+              myCsvData += lineDelimiter;
+            }
+          });
+          const blob = new Blob([myCsvData], {type: 'text/csv;charset=utf-8'});
+          saveAs(blob, 'iqb-testcenter-responses.csv');
+        } else {
+          this.snackBar.open('Keine Daten verfügbar.', 'Fehler', {duration: 3000});
+        }
+        this.tableselectionCheckbox.clear();
+        this.dataLoading = false;
+    });
+    }
+  }
+
+  // 444444444444444444444444444444444444444444444444444444444444444444444444444444444444444
+  downloadReviewsCSV() {
+    if (this.tableselectionCheckbox.selected.length > 0) {
+      this.dataLoading = true;
+      const selectedGroups: string[] = [];
+      this.tableselectionCheckbox.selected.forEach(element => {
+        selectedGroups.push(element.groupname);
+      });
+      this.bs.getReviews(selectedGroups).subscribe(
+      (responseData: ReviewData[]) => {
+        if (responseData.length > 0) {
+          // collect categories
+          const allCategories: string[] = [];
+          responseData.forEach((resp: ReviewData) => {
+            resp.categories.split(' ').forEach(s => {
+              const s_trimmed = s.trim();
+              if (s_trimmed.length > 0) {
+                if (!allCategories.includes(s_trimmed)) {
+                  allCategories.push(s_trimmed);
+                }
+              }
+            });
+          });
+
+          const columnDelimiter = ';';
+          const lineDelimiter = '\n';
+          let myCsvData = 'groupname' + columnDelimiter + 'loginname' + columnDelimiter + 'code' + columnDelimiter +
+              'bookletname' + columnDelimiter + 'unitname' + columnDelimiter +
+              'priority' + columnDelimiter;
+          allCategories.forEach(s => {
+            myCsvData += 'category: ' + s + columnDelimiter;
+          });
+          myCsvData += 'reviewtime' + columnDelimiter + 'entry' + lineDelimiter;
+
+          responseData.forEach((resp: ReviewData) => {
+            if ((resp.entry !== null) && (resp.entry.length > 0)) {
+              myCsvData += '"' + resp.groupname + '"' + columnDelimiter + '"' + resp.loginname + '"' +
+                columnDelimiter + '"' + resp.code + '"' + columnDelimiter + '"' + resp.bookletname + '"' +
+                columnDelimiter + '"' + resp.unitname + '"' + columnDelimiter  + '"' +
+                resp.priority  + '"' + columnDelimiter;
+              const resp_categories = resp.categories.split(' ');
+              allCategories.forEach(s => {
+                if (resp_categories.includes(s)) {
+                  myCsvData += '"X"' + columnDelimiter;
+                } else {
+                  myCsvData += columnDelimiter;
+                }
+              });
+              myCsvData += '"' + resp.reviewtime + '"' + columnDelimiter  + '"' +  resp.entry  + '"' + lineDelimiter;
+            }
+          });
+          const blob = new Blob([myCsvData], {type: 'text/csv;charset=utf-8'});
+          saveAs(blob, 'iqb-testcenter-reviews.csv');
+        } else {
+          this.snackBar.open('Keine Daten verfügbar.', 'Fehler', {duration: 3000});
+        }
+        this.tableselectionCheckbox.clear();
+        this.dataLoading = false;
+      });
+    }
+  }
+
+  // 444444444444444444444444444444444444444444444444444444444444444444444444444444444444444
+  downloadLogsCSV() {
+    if (this.tableselectionCheckbox.selected.length > 0) {
+      this.dataLoading = true;
+      const selectedGroups: string[] = [];
+      this.tableselectionCheckbox.selected.forEach(element => {
+        selectedGroups.push(element.groupname);
+      });
+      this.bs.getLogs(selectedGroups).subscribe(
+      (responseData: LogData[]) => {
+        if (responseData.length > 0) {
+          const columnDelimiter = ';';
+          const lineDelimiter = '\n';
+          let myCsvData = 'groupname' + columnDelimiter + 'loginname' + columnDelimiter + 'code' + columnDelimiter +
+              'bookletname' + columnDelimiter + 'unitname' + columnDelimiter +
+              'timestamp' + columnDelimiter + 'logentry' + lineDelimiter;
+          responseData.forEach((resp: LogData) => {
+            if ((resp.logentry !== null) && (resp.logentry.length > 0)) {
+             myCsvData += '"' + resp.groupname + '"' + columnDelimiter + '"' + resp.loginname + '"' + columnDelimiter + '"' + resp.code + '"' + columnDelimiter +
+              '"' + resp.bookletname + '"' + columnDelimiter + '"' + resp.unitname + '"' + columnDelimiter  + '"' +
+              resp.timestamp.toString() + '"' + columnDelimiter  + resp.logentry.replace(/\\"/g, '""')  + lineDelimiter;
+            }
+          });
+          const blob = new Blob([myCsvData], {type: 'text/csv;charset=utf-8'});
+          saveAs(blob, 'iqb-testcenter-logs.csv');
+        } else {
+          this.snackBar.open('Keine Daten verfügbar.', 'Fehler', {duration: 3000});
+        }
+        this.tableselectionCheckbox.clear();
+        this.dataLoading = false;
+      });
+    }
+  }
+
+  deleteData() {
+    if (this.tableselectionCheckbox.selected.length > 0) {
+      const selectedGroups: string[] = [];
+      this.tableselectionCheckbox.selected.forEach(element => {
+        selectedGroups.push(element.groupname);
+      });
+
+      let prompt = 'Es werden alle Antwort- und Logdaten in der Datenbank für diese ';
+      if (selectedGroups.length > 1) {
+        prompt = prompt + selectedGroups.length + ' Gruppen ';
+      } else {
+        prompt = prompt + ' Gruppe "' + selectedGroups[0] + '" ';
+      }
+
+      const dialogRef = this.deleteConfirmDialog.open(ConfirmDialogComponent, {
+        width: '400px',
+        data: <ConfirmDialogData>{
+          title: 'Löschen von Gruppendaten',
+          content: prompt + 'gelöscht. Fortsetzen?',
+          confirmbuttonlabel: 'Gruppendaten löschen',
+          showcancel: true
+        }
+      });
+
+      dialogRef.afterClosed().subscribe(result => {
+        if (result !== false) {
+          // =========================================================
+          this.dataLoading = true;
+          this.bs.deleteData(selectedGroups).subscribe(() => {
+                  this.tableselectionCheckbox.clear();
+                  this.dataLoading = false;
+                });
+          }
+        });
+    }
+  }
+
+  // % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %
+  ngOnDestroy() {
+    if (this.workspaceIdSubscription !== null) {
+      this.workspaceIdSubscription.unsubscribe();
+    }
+  }
+}
diff --git a/src/app/workspace/syscheck/syscheck.component.css b/src/app/workspace/syscheck/syscheck.component.css
new file mode 100644
index 0000000000000000000000000000000000000000..c495430b14a19cf4d0fe394fb8a7217058eff209
--- /dev/null
+++ b/src/app/workspace/syscheck/syscheck.component.css
@@ -0,0 +1,3 @@
+.mat-icon {
+  margin-right: 5px;
+}
diff --git a/src/app/workspace/syscheck/syscheck.component.html b/src/app/workspace/syscheck/syscheck.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..d059389ba3aa33478aaa029a72dd38111ad5f8e2
--- /dev/null
+++ b/src/app/workspace/syscheck/syscheck.component.html
@@ -0,0 +1,57 @@
+<div class="columnhost" fxLayout="column">
+  <div class="spinner-container" *ngIf="dataLoading">
+    <mat-spinner></mat-spinner>
+  </div>
+  <div fxLayout="row" fxLayoutGap="10px">
+    <button mat-raised-button (click)="downloadReportsCSV()" [disabled]="!tableselectionCheckbox.hasValue()"
+        matTooltip="Download Berichte als CSV für Excel" matTooltipPosition="above">
+      <mat-icon>cloud_download</mat-icon>Berichte
+    </button>
+    <button mat-raised-button (click)="deleteReports()" [disabled]="!tableselectionCheckbox.hasValue()"
+        matTooltip="Löschen Berichte für markierte System-Checks" matTooltipPosition="above">
+      <mat-icon>delete</mat-icon>
+    </button>
+  </div>
+
+  <mat-table [dataSource]="resultDataSource" matSort>
+    <ng-container matColumnDef="selectCheckbox">
+      <mat-header-cell *matHeaderCellDef fxFlex="70px">
+        <mat-checkbox (change)="$event ? masterToggle() : null"
+                      [checked]="tableselectionCheckbox.hasValue() && isAllSelected()"
+                      [indeterminate]="tableselectionCheckbox.hasValue() && !isAllSelected()">
+        </mat-checkbox>
+      </mat-header-cell>
+      <mat-cell *matCellDef="let row" fxFlex="70px">
+        <mat-checkbox (click)="$event.stopPropagation()"
+                      (change)="$event ? tableselectionCheckbox.toggle(row) : null"
+                      [checked]="tableselectionCheckbox.isSelected(row)">
+        </mat-checkbox>
+      </mat-cell>
+    </ng-container>
+
+    <ng-container matColumnDef="syscheckId">
+      <mat-header-cell *matHeaderCellDef mat-sort-header fxFlex="300px">System-Check Id</mat-header-cell>
+      <mat-cell *matCellDef="let element" fxFlex="300px">{{element.id}}</mat-cell>
+    </ng-container>
+
+    <ng-container matColumnDef="syscheckLabel">
+      <mat-header-cell *matHeaderCellDef mat-sort-header fxLayoutAlign="start center">System-Check Name</mat-header-cell>
+      <mat-cell *matCellDef="let element" fxLayoutAlign="start center"> {{element.label}} </mat-cell>
+    </ng-container>
+
+    <ng-container matColumnDef="number">
+      <mat-header-cell *matHeaderCellDef mat-sort-header fxLayoutAlign="center center">Anzahl Berichte</mat-header-cell>
+      <mat-cell *matCellDef="let element" fxLayoutAlign="center center">{{element.count}} </mat-cell>
+    </ng-container>
+
+    <ng-container matColumnDef="details">
+      <mat-header-cell *matHeaderCellDef mat-sort-header fxLayoutAlign="center center">Betriebssysteme und Browser</mat-header-cell>
+      <mat-cell *matCellDef="let element" fxLayout="column" fxLayoutAlign="center start">
+        <div *ngFor="let d of element.details">{{d}}</div>
+      </mat-cell>
+    </ng-container>
+
+    <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
+    <mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
+  </mat-table>
+</div>
diff --git a/src/app/workspace/syscheck/syscheck.component.spec.ts b/src/app/workspace/syscheck/syscheck.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b1210159f5a75b9fd205fab50fdd402ff2e2be8f
--- /dev/null
+++ b/src/app/workspace/syscheck/syscheck.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { SyscheckComponent } from './syscheck.component';
+
+describe('SyscheckComponent', () => {
+  let component: SyscheckComponent;
+  let fixture: ComponentFixture<SyscheckComponent>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ SyscheckComponent ]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(SyscheckComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/src/app/workspace/syscheck/syscheck.component.ts b/src/app/workspace/syscheck/syscheck.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..2cf19b77d82eaf298fa0d7bb12008801ad6c88d5
--- /dev/null
+++ b/src/app/workspace/syscheck/syscheck.component.ts
@@ -0,0 +1,124 @@
+import { ConfirmDialogComponent, ConfirmDialogData } from 'iqb-components';
+import { Component, OnInit, ViewChild } from '@angular/core';
+import { BackendService } from '../backend.service';
+import { MatDialog } from '@angular/material/dialog';
+import { MatSnackBar } from '@angular/material/snack-bar';
+import { MatSort } from '@angular/material/sort';
+import { MatTableDataSource } from '@angular/material/table';
+import { SelectionModel } from '@angular/cdk/collections';
+import { saveAs } from 'file-saver';
+import { SysCheckStatistics } from '../workspace.interfaces';
+
+
+@Component({
+  templateUrl: './syscheck.component.html',
+  styleUrls: ['./syscheck.component.css']
+})
+export class SyscheckComponent implements OnInit {
+  displayedColumns: string[] = ['selectCheckbox', 'syscheckLabel', 'number', 'details'];
+  public resultDataSource = new MatTableDataSource<SysCheckStatistics>([]);
+  // prepared for selection if needed sometime
+  public tableselectionCheckbox = new SelectionModel<SysCheckStatistics>(true, []);
+  public dataLoading = false;
+
+  @ViewChild(MatSort, { static: true }) sort: MatSort;
+
+  constructor(
+    private bs: BackendService,
+    private deleteConfirmDialog: MatDialog,
+    public snackBar: MatSnackBar
+  ) {
+  }
+
+  ngOnInit() {
+    this.updateTable();
+  }
+
+  updateTable() {
+    this.dataLoading = true;
+    this.tableselectionCheckbox.clear();
+    this.bs.getSysCheckReportList().subscribe(
+      (resultData: SysCheckStatistics[]) => {
+        this.dataLoading = false;
+        this.resultDataSource = new MatTableDataSource<SysCheckStatistics>(resultData);
+        this.resultDataSource.sort = this.sort;
+      }
+    );
+  }
+
+  isAllSelected() {
+    const numSelected = this.tableselectionCheckbox.selected.length;
+    const numRows = this.resultDataSource.data.length;
+    return numSelected === numRows;
+  }
+
+  masterToggle() {
+    this.isAllSelected() ?
+        this.tableselectionCheckbox.clear() :
+        this.resultDataSource.data.forEach(row => this.tableselectionCheckbox.select(row));
+  }
+
+  // 444444444444444444444444444444444444444444444444444444444444444444444444444444444444444
+  downloadReportsCSV() {
+    if (this.tableselectionCheckbox.selected.length > 0) {
+      this.dataLoading = true;
+      const selectedReports: string[] = [];
+      this.tableselectionCheckbox.selected.forEach(element => {
+        selectedReports.push(element.id);
+      });
+      this.bs.getSysCheckReport(selectedReports, ';', '"').subscribe(
+      (reportData: string[]) => {
+        if (reportData.length > 0) {
+          const lineDelimiter = '\n';
+          let myCsvData = '';
+          reportData.forEach((repLine: string) => {
+            myCsvData += repLine + lineDelimiter;
+          });
+          const blob = new Blob([myCsvData], {type: 'text/csv;charset=utf-8'});
+          saveAs(blob, 'iqb-testcenter-syscheckreports.csv');
+        } else {
+          this.snackBar.open('Keine Daten verfügbar.', 'Fehler', {duration: 3000});
+        }
+        this.tableselectionCheckbox.clear();
+        this.dataLoading = false;
+    });
+    }
+  }
+
+  deleteReports() {
+    if (this.tableselectionCheckbox.selected.length > 0) {
+      const selectedReports: string[] = [];
+      this.tableselectionCheckbox.selected.forEach(element => {
+        selectedReports.push(element.id);
+      });
+
+      let prompt = 'Es werden alle Berichte für diese';
+      if (selectedReports.length > 1) {
+        prompt = prompt + ' ' + selectedReports.length + ' System-Checks ';
+      } else {
+        prompt = prompt + 'n System-Check "' + selectedReports[0] + '" ';
+      }
+
+      const dialogRef = this.deleteConfirmDialog.open(ConfirmDialogComponent, {
+        width: '400px',
+        data: <ConfirmDialogData>{
+          title: 'Löschen von Berichten',
+          content: prompt + 'gelöscht. Fortsetzen?',
+          confirmbuttonlabel: 'Berichtsdaten löschen',
+          showcancel: true
+        }
+      });
+
+      dialogRef.afterClosed().subscribe(result => {
+        if (result !== false) {
+          // =========================================================
+          this.dataLoading = true;
+          this.bs.deleteSysCheckReports(selectedReports).subscribe(() => {
+                  this.tableselectionCheckbox.clear();
+                  this.dataLoading = false;
+                });
+          }
+        });
+    }
+  }
+}
diff --git a/src/app/workspace/workspace-routing.module.ts b/src/app/workspace/workspace-routing.module.ts
new file mode 100644
index 0000000000000000000000000000000000000000..7fefdd10e0c30cd3ba74e520778fcdd653ae6214
--- /dev/null
+++ b/src/app/workspace/workspace-routing.module.ts
@@ -0,0 +1,28 @@
+import { SyscheckComponent } from './syscheck/syscheck.component';
+import { MonitorComponent } from './monitor/monitor.component';
+import { ResultsComponent } from './results/results.component';
+import { NgModule } from '@angular/core';
+import { Routes, RouterModule } from '@angular/router';
+import { FilesComponent } from './files/files.component';
+import { WorkspaceComponent } from './workspace.component';
+
+const routes: Routes = [
+  {
+    path: 'ws/:ws',
+    component: WorkspaceComponent,
+    children: [
+      {path: '', redirectTo: 'monitor', pathMatch: 'full'},
+      {path: 'files', component: FilesComponent},
+      {path: 'syscheck', component: SyscheckComponent},
+      {path: 'monitor', component: MonitorComponent},
+      {path: 'results', component: ResultsComponent},
+      {path: '**', component: MonitorComponent}
+    ]
+  }];
+
+
+@NgModule({
+  imports: [RouterModule.forChild(routes)],
+  exports: [RouterModule]
+})
+export class WorkspaceRoutingModule { }
diff --git a/src/app/workspace/workspace.component.css b/src/app/workspace/workspace.component.css
new file mode 100644
index 0000000000000000000000000000000000000000..b6162710eeaea472d7054f155f74e142018bdcfd
--- /dev/null
+++ b/src/app/workspace/workspace.component.css
@@ -0,0 +1,35 @@
+/* --------------------------------------------- */
+#buttonsContainer {
+  color: white;
+  padding: 0 10px 0 0;
+}
+#buttonsContainer .material-icons {
+  font-size: 2.0rem;
+}
+#buttonsContainer img {
+  width: 100px;
+}
+
+/* --------------------------------------------- */
+mat-toolbar {
+  position: fixed;
+  z-index: 100;
+  top: 4px;
+  right: 90px;
+}
+
+#buttonsContainer .material-icons {
+  position: relative;
+  top: -8px;
+  font-size: 36px;
+  padding: 2px;
+}
+
+.adminbackground {
+  flex:  10 0 900px;
+  box-shadow: 5px 10px 20px black;
+  background-color: white;
+  min-height: 85%;
+  margin: 15px;
+  padding: 25px;
+}
diff --git a/src/app/workspace/workspace.component.html b/src/app/workspace/workspace.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..6f5cf00c4d26e4735c49e8b90d0cc25c25d8e7df
--- /dev/null
+++ b/src/app/workspace/workspace.component.html
@@ -0,0 +1,27 @@
+<div id="buttonsContainer" fxLayout="row" fxLayoutAlign="start center">
+  <a [routerLink]="['/']">
+    <img src="assets/IQB-LogoA.png" matTooltip="Startseite"/>
+  </a>
+  <div fxLayout="row wrap" fxLayoutAlign="space-between center" fxFlex>
+    <div class="error-msg">{{ (mds.globalErrorMsg$ | async)?.labelNice }}</div>
+    <div>IQB-Testcenter Verwaltung</div>
+    <div>{{ wds.wsName }} ({{ wds.wsRole }})</div>
+  </div>
+</div>
+<div class="page-body">
+  <div class="adminbackground">
+
+
+    <nav mat-tab-nav-bar>
+      <a mat-tab-link
+          *ngFor="let link of wds.navLinks"
+          [routerLink]="link.path"
+          routerLinkActive #rla="routerLinkActive"
+          [active]="rla.isActive">
+        {{link.label}}
+      </a>
+    </nav>
+
+    <router-outlet></router-outlet>
+  </div>
+</div>
diff --git a/src/app/workspace/workspace.component.spec.ts b/src/app/workspace/workspace.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..4ea31a8f29e3256b71a7d1772483fae203751971
--- /dev/null
+++ b/src/app/workspace/workspace.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { WorkspaceComponent } from './workspace.component';
+
+describe('WorkspaceComponent', () => {
+  let component: WorkspaceComponent;
+  let fixture: ComponentFixture<WorkspaceComponent>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ WorkspaceComponent ]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(WorkspaceComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/src/app/workspace/workspace.component.ts b/src/app/workspace/workspace.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..1b7ed70ce1e0312bc8581cceeefd5fee35e2f799
--- /dev/null
+++ b/src/app/workspace/workspace.component.ts
@@ -0,0 +1,42 @@
+import { WorkspaceDataService } from './workspacedata.service';
+import { MainDataService } from '../maindata.service';
+import { ActivatedRoute } from '@angular/router';
+import { Subscription } from 'rxjs';
+import { Component, OnInit, OnDestroy } from '@angular/core';
+
+
+@Component({
+  templateUrl: './workspace.component.html',
+  styleUrls: ['./workspace.component.css']
+})
+export class WorkspaceComponent implements OnInit, OnDestroy {
+  private routingSubscription: Subscription = null;
+  private logindataSubscription: Subscription = null;
+
+  constructor(
+    private route: ActivatedRoute,
+    public mds: MainDataService,
+    public wds: WorkspaceDataService
+  ) { }
+
+  ngOnInit() {
+    this.routingSubscription = this.route.params.subscribe(params => {
+      const ws = Number(params['ws']);
+      this.wds.setWorkspace(ws, this.mds.getWorkspaceRole(ws), this.mds.getWorkspaceName(ws));
+    });
+
+    this.logindataSubscription = this.mds.loginData$.subscribe(() => {
+      this.wds.setWorkspace(this.wds.ws, this.mds.getWorkspaceRole(this.wds.ws), this.mds.getWorkspaceName(this.wds.ws));
+    });
+  }
+
+
+  ngOnDestroy() {
+    if (this.routingSubscription !== null) {
+      this.routingSubscription.unsubscribe();
+    }
+    if (this.logindataSubscription !== null) {
+      this.logindataSubscription.unsubscribe();
+    }
+  }
+}
diff --git a/src/app/workspace/workspace.interceptor.ts b/src/app/workspace/workspace.interceptor.ts
new file mode 100644
index 0000000000000000000000000000000000000000..fa6ed54646e8f7fbba0f96a004289b2d89bdb77a
--- /dev/null
+++ b/src/app/workspace/workspace.interceptor.ts
@@ -0,0 +1,29 @@
+import { WorkspaceDataService } from './workspacedata.service';
+import { Injectable } from '@angular/core';
+import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http';
+import { Observable } from 'rxjs';
+
+@Injectable()
+
+export class WorkspaceInterceptor implements HttpInterceptor {
+  constructor(public wds: WorkspaceDataService) {}
+
+  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
+    const ws = this.wds.workspaceId$.getValue();
+    if (ws >= 0) {
+      const authDataStr = request.headers.get('AuthToken');
+      let authData = {};
+      if (authDataStr) {
+        authData = JSON.parse(authDataStr);
+      }
+      authData['ws'] = ws;
+      return next.handle(request.clone({
+        setHeaders: {
+          AuthToken: JSON.stringify(authData)
+        }
+      }));
+    } else {
+      return next.handle(request);
+    }
+  }
+}
diff --git a/src/app/workspace/workspace.interfaces.ts b/src/app/workspace/workspace.interfaces.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b53f17d1622617ce9b17a3e4f533e1666f7ee912
--- /dev/null
+++ b/src/app/workspace/workspace.interfaces.ts
@@ -0,0 +1,96 @@
+export interface GetFileResponseData {
+  filename: string;
+  filesize: number;
+  filesizestr: string;
+  filedatetime: string;
+  filedatetimestr: string;
+  type: string;
+  typelabel: string;
+  isChecked: boolean;
+}
+
+export interface CheckWorkspaceResponseData {
+  errors: string[];
+  infos: string[];
+  warnings: string[];
+}
+
+
+export interface GroupResponse {
+  name: string;
+  testsTotal: number;
+  testsStarted: number;
+  responsesGiven: number;
+}
+
+export interface BookletsStarted {
+  groupname: string;
+  loginname: string;
+  code: string;
+  bookletname: string;
+  locked: boolean;
+  laststart: Date;
+}
+
+export interface UnitResponse {
+  groupname: string;
+  loginname: string;
+  code: string;
+  bookletname: string;
+  unitname: string;
+  responses: string;
+  restorepoint:  string;
+  responsetype: string;
+  responses_ts: number;
+  restorepoint_ts: number;
+  laststate: string;
+}
+
+export interface MonitorData {
+  groupname: string;
+  loginsPrepared: number;
+  personsPrepared: number;
+  bookletsPrepared: number;
+  bookletsStarted: number;
+  bookletsLocked: number;
+  laststart: Date;
+  laststartStr: string;
+}
+
+export interface ResultData {
+  groupname: string;
+  bookletsStarted: number;
+  num_units_min: number;
+  num_units_max: number;
+  num_units_mean: number;
+  lastchange: number;
+}
+
+export interface LogData {
+  groupname: string;
+  loginname: string;
+  code: string;
+  bookletname: string;
+  unitname: string;
+  timestamp: number;
+  logentry: string;
+}
+
+export interface ReviewData {
+  groupname: string;
+  loginname: string;
+  code: string;
+  bookletname: string;
+  unitname: string;
+  priority: number;
+  categories: string;
+  reviewtime: Date;
+  entry: string;
+}
+
+export interface SysCheckStatistics {
+  id: string;
+  label: string;
+  count: number;
+  details: string[];
+}
diff --git a/src/app/workspace/workspace.module.ts b/src/app/workspace/workspace.module.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ead279306643a60d0285c5dca1baa6eaab3a7680
--- /dev/null
+++ b/src/app/workspace/workspace.module.ts
@@ -0,0 +1,88 @@
+import { FlexLayoutModule } from '@angular/flex-layout';
+import { BackendService } from './backend.service';
+import { IqbFilesModule } from '../iqb-files';
+import { ReactiveFormsModule } from '@angular/forms';
+import { NgModule} from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { WorkspaceDataService } from './workspacedata.service';
+
+import { WorkspaceRoutingModule } from './workspace-routing.module';
+import { WorkspaceComponent } from './workspace.component';
+import { FilesComponent } from './files/files.component';
+import { ResultsComponent } from './results/results.component';
+
+import { MatButtonModule } from '@angular/material/button';
+import { MatCardModule } from '@angular/material/card';
+import { MatCheckboxModule } from '@angular/material/checkbox';
+import { MatDialogModule } from '@angular/material/dialog';
+import { MatFormFieldModule } from '@angular/material/form-field';
+import { MatIconModule } from '@angular/material/icon';
+import { MatInputModule } from '@angular/material/input';
+import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
+import { MatSelectModule } from '@angular/material/select';
+import { MatSnackBarModule } from '@angular/material/snack-bar';
+import { MatSortModule } from '@angular/material/sort';
+import { MatTableModule } from '@angular/material/table';
+import { MatTabsModule } from '@angular/material/tabs';
+import { MatToolbarModule } from '@angular/material/toolbar';
+import { MatTooltipModule } from '@angular/material/tooltip';
+import { MonitorComponent } from './monitor/monitor.component';
+import { MatExpansionModule } from '@angular/material/expansion';
+import { MatGridListModule } from '@angular/material/grid-list';
+import { SyscheckComponent } from './syscheck/syscheck.component';
+import { IqbComponentsModule } from 'iqb-components';
+import { HTTP_INTERCEPTORS } from '@angular/common/http';
+import { WorkspaceInterceptor } from './workspace.interceptor';
+
+@NgModule({
+  imports: [
+    IqbFilesModule,
+    CommonModule,
+    WorkspaceRoutingModule,
+    MatTableModule,
+    MatTabsModule,
+    MatIconModule,
+    MatSelectModule,
+    MatCheckboxModule,
+    MatSortModule,
+    MatCardModule,
+    MatExpansionModule,
+    ReactiveFormsModule,
+    MatProgressSpinnerModule,
+    MatDialogModule,
+    MatButtonModule,
+    MatTooltipModule,
+    MatFormFieldModule,
+    MatInputModule,
+    MatToolbarModule,
+    MatSnackBarModule,
+    MatGridListModule,
+    IqbComponentsModule,
+    FlexLayoutModule,
+    MatCardModule,
+    FlexLayoutModule
+  ],
+  exports: [
+    WorkspaceComponent
+  ],
+  declarations: [
+    WorkspaceComponent,
+    FilesComponent,
+    ResultsComponent,
+    MonitorComponent,
+    SyscheckComponent
+  ],
+  providers: [
+    // interceptor adds ws to AuthToken
+    // not working when module is lazy loaded!
+    {
+      provide: HTTP_INTERCEPTORS,
+      useClass: WorkspaceInterceptor,
+      multi: true
+    },
+    BackendService,
+    WorkspaceDataService
+  ],
+})
+
+export class WorkspaceModule { }
diff --git a/src/app/workspace/workspacedata.service.spec.ts b/src/app/workspace/workspacedata.service.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..4efb2cb6ef585b014ba53d398f1defc114ef4ac8
--- /dev/null
+++ b/src/app/workspace/workspacedata.service.spec.ts
@@ -0,0 +1,15 @@
+import { TestBed, inject } from '@angular/core/testing';
+
+import { WorkspaceDataService } from './workspacedata.service';
+
+describe('WorkspaceDataService', () => {
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      providers: [WorkspaceDataService]
+    });
+  });
+
+  it('should be created', inject([WorkspaceDataService], (service: WorkspaceDataService) => {
+    expect(service).toBeTruthy();
+  }));
+});
diff --git a/src/app/workspace/workspacedata.service.ts b/src/app/workspace/workspacedata.service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..07fc24f00f71db2011b2a7a8bc50cc343dfd82b2
--- /dev/null
+++ b/src/app/workspace/workspacedata.service.ts
@@ -0,0 +1,71 @@
+import { BehaviorSubject } from 'rxjs';
+import { Injectable } from '@angular/core';
+import { ServerError } from 'iqb-components';
+
+@Injectable({
+  providedIn: 'root'
+})
+
+@Injectable()
+export class WorkspaceDataService {
+  public workspaceId$ = new BehaviorSubject<number>(-1);
+  public globalErrorMsg$ = new BehaviorSubject<ServerError>(null);
+
+  public get ws(): number {
+    return this.workspaceId$.getValue();
+  }
+  private _wsRole = '';
+  public get wsRole(): string {
+    return this._wsRole;
+  }
+  private _wsName = '';
+  public get wsName(): string {
+    return this._wsName;
+  }
+  public navLinks = [];
+
+
+  private navLinksRW = [
+    {path: 'files', label: 'Dateien'},
+    {path: 'syscheck', label: 'System-Check Berichte'},
+    {path: 'monitor', label: 'Monitor'},
+    {path: 'results', label: 'Ergebnisse'}
+  ];
+  private navLinksRO = [
+    {path: 'files', label: 'Dateien'},
+    {path: 'syscheck', label: 'System-Check Berichte'},
+    {path: 'monitor', label: 'Monitor'},
+    {path: 'results', label: 'Ergebnisse'}
+  ];
+  private navLinksMO = [
+    {path: 'monitor', label: 'Monitor'}
+  ];
+
+  setNewErrorMsg(err: ServerError = null) {
+    this.globalErrorMsg$.next(err);
+  }
+
+  setWorkspace(newId: number, newRole: string, newName: string) {
+    this._wsName = newName;
+    this._wsRole = newRole;
+    switch (newRole.toUpperCase()) {
+      case 'RW': {
+        this.navLinks = this.navLinksRW;
+        break;
+      }
+      case 'RO': {
+        this.navLinks = this.navLinksRO;
+        break;
+      }
+      case 'MO': {
+        this.navLinks = this.navLinksMO;
+        break;
+      }
+      default: {
+        this.navLinks = [];
+        break;
+      }
+    }
+    this.workspaceId$.next(newId);
+  }
+}
diff --git a/src/assets/browserslist b/src/assets/browserslist
new file mode 100644
index 0000000000000000000000000000000000000000..8e09ab492e26c2b2c0920a75dd795811f5815369
--- /dev/null
+++ b/src/assets/browserslist
@@ -0,0 +1,9 @@
+# This file is currently used by autoprefixer to adjust CSS to support the below specified browsers
+# For additional information regarding the format and rule options, please see:
+# https://github.com/browserslist/browserslist#queries
+# For IE 9-11 support, please uncomment the last line of the file and adjust as needed
+> 0.5%
+last 2 versions
+Firefox ESR
+not dead
+# IE 9-11
\ No newline at end of file
diff --git a/src/includes/FileSaver.js b/src/includes/FileSaver.js
new file mode 100644
index 0000000000000000000000000000000000000000..fb7149425dd186c380d618a99c1ccdffd9de409b
--- /dev/null
+++ b/src/includes/FileSaver.js
@@ -0,0 +1,188 @@
+/* FileSaver.js
+ * A saveAs() FileSaver implementation.
+ * 1.3.2
+ * 2016-06-16 18:25:19
+ *
+ * By Eli Grey, http://eligrey.com
+ * License: MIT
+ *   See https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md
+ */
+
+/*global self */
+/*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */
+
+/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */
+
+var saveAs = saveAs || (function(view) {
+	"use strict";
+	// IE <10 is explicitly unsupported
+	if (typeof view === "undefined" || typeof navigator !== "undefined" && /MSIE [1-9]\./.test(navigator.userAgent)) {
+		return;
+	}
+	var
+		  doc = view.document
+		  // only get URL when necessary in case Blob.js hasn't overridden it yet
+		, get_URL = function() {
+			return view.URL || view.webkitURL || view;
+		}
+		, save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a")
+		, can_use_save_link = "download" in save_link
+		, click = function(node) {
+			var event = new MouseEvent("click");
+			node.dispatchEvent(event);
+		}
+		, is_safari = /constructor/i.test(view.HTMLElement) || view.safari
+		, is_chrome_ios =/CriOS\/[\d]+/.test(navigator.userAgent)
+		, throw_outside = function(ex) {
+			(view.setImmediate || view.setTimeout)(function() {
+				throw ex;
+			}, 0);
+		}
+		, force_saveable_type = "application/octet-stream"
+		// the Blob API is fundamentally broken as there is no "downloadfinished" event to subscribe to
+		, arbitrary_revoke_timeout = 1000 * 40 // in ms
+		, revoke = function(file) {
+			var revoker = function() {
+				if (typeof file === "string") { // file is an object URL
+					get_URL().revokeObjectURL(file);
+				} else { // file is a File
+					file.remove();
+				}
+			};
+			setTimeout(revoker, arbitrary_revoke_timeout);
+		}
+		, dispatch = function(filesaver, event_types, event) {
+			event_types = [].concat(event_types);
+			var i = event_types.length;
+			while (i--) {
+				var listener = filesaver["on" + event_types[i]];
+				if (typeof listener === "function") {
+					try {
+						listener.call(filesaver, event || filesaver);
+					} catch (ex) {
+						throw_outside(ex);
+					}
+				}
+			}
+		}
+		, auto_bom = function(blob) {
+			// prepend BOM for UTF-8 XML and text/* types (including HTML)
+			// note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF
+			if (/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) {
+				return new Blob([String.fromCharCode(0xFEFF), blob], {type: blob.type});
+			}
+			return blob;
+		}
+		, FileSaver = function(blob, name, no_auto_bom) {
+			if (!no_auto_bom) {
+				blob = auto_bom(blob);
+			}
+			// First try a.download, then web filesystem, then object URLs
+			var
+				  filesaver = this
+				, type = blob.type
+				, force = type === force_saveable_type
+				, object_url
+				, dispatch_all = function() {
+					dispatch(filesaver, "writestart progress write writeend".split(" "));
+				}
+				// on any filesys errors revert to saving with object URLs
+				, fs_error = function() {
+					if ((is_chrome_ios || (force && is_safari)) && view.FileReader) {
+						// Safari doesn't allow downloading of blob urls
+						var reader = new FileReader();
+						reader.onloadend = function() {
+							var url = is_chrome_ios ? reader.result : reader.result.replace(/^data:[^;]*;/, 'data:attachment/file;');
+							var popup = view.open(url, '_blank');
+							if(!popup) view.location.href = url;
+							url=undefined; // release reference before dispatching
+							filesaver.readyState = filesaver.DONE;
+							dispatch_all();
+						};
+						reader.readAsDataURL(blob);
+						filesaver.readyState = filesaver.INIT;
+						return;
+					}
+					// don't create more object URLs than needed
+					if (!object_url) {
+						object_url = get_URL().createObjectURL(blob);
+					}
+					if (force) {
+						view.location.href = object_url;
+					} else {
+						var opened = view.open(object_url, "_blank");
+						if (!opened) {
+							// Apple does not allow window.open, see https://developer.apple.com/library/safari/documentation/Tools/Conceptual/SafariExtensionGuide/WorkingwithWindowsandTabs/WorkingwithWindowsandTabs.html
+							view.location.href = object_url;
+						}
+					}
+					filesaver.readyState = filesaver.DONE;
+					dispatch_all();
+					revoke(object_url);
+				}
+			;
+			filesaver.readyState = filesaver.INIT;
+
+			if (can_use_save_link) {
+				object_url = get_URL().createObjectURL(blob);
+				setTimeout(function() {
+					save_link.href = object_url;
+					save_link.download = name;
+					click(save_link);
+					dispatch_all();
+					revoke(object_url);
+					filesaver.readyState = filesaver.DONE;
+				});
+				return;
+			}
+
+			fs_error();
+		}
+		, FS_proto = FileSaver.prototype
+		, saveAs = function(blob, name, no_auto_bom) {
+			return new FileSaver(blob, name || blob.name || "download", no_auto_bom);
+		}
+	;
+	// IE 10+ (native saveAs)
+	if (typeof navigator !== "undefined" && navigator.msSaveOrOpenBlob) {
+		return function(blob, name, no_auto_bom) {
+			name = name || blob.name || "download";
+
+			if (!no_auto_bom) {
+				blob = auto_bom(blob);
+			}
+			return navigator.msSaveOrOpenBlob(blob, name);
+		};
+	}
+
+	FS_proto.abort = function(){};
+	FS_proto.readyState = FS_proto.INIT = 0;
+	FS_proto.WRITING = 1;
+	FS_proto.DONE = 2;
+
+	FS_proto.error =
+	FS_proto.onwritestart =
+	FS_proto.onprogress =
+	FS_proto.onwrite =
+	FS_proto.onabort =
+	FS_proto.onerror =
+	FS_proto.onwriteend =
+		null;
+
+	return saveAs;
+}(
+	   typeof self !== "undefined" && self
+	|| typeof window !== "undefined" && window
+	|| this.content
+));
+// `self` is undefined in Firefox for Android content script context
+// while `this` is nsIContentFrameMessageManager
+// with an attribute `content` that corresponds to the window
+
+if (typeof module !== "undefined" && module.exports) {
+  module.exports.saveAs = saveAs;
+} else if ((typeof define !== "undefined" && define !== null) && (define.amd !== null)) {
+  define("FileSaver.js", function() {
+    return saveAs;
+  });
+}
diff --git a/src/index.html.ADMIN b/src/index.html.ADMIN
new file mode 100644
index 0000000000000000000000000000000000000000..c6474ea70185a8d81cb39c03bb2fdadd7ed24546
--- /dev/null
+++ b/src/index.html.ADMIN
@@ -0,0 +1,25 @@
+<!doctype html>
+<html lang="en">
+<head>
+  <meta charset="utf-8">
+  <title>IQB-Testcenter Verwaltung</title>
+  <base href="/">
+
+  <meta name="viewport" content="width=device-width, initial-scale=1">
+  <link rel="apple-touch-icon" sizes="180x180" href="/assets/apple-touch-icon.png?v=Hujjik765gt">
+  <link rel="icon" type="image/png" sizes="32x32" href="/assets/favicon-32x32.png?v=Hujjik765gt">
+  <link rel="icon" type="image/png" sizes="16x16" href="/assets/favicon-16x16.png?v=Hujjik765gt">
+  <link rel="manifest" href="/assets/site.webmanifest?v=Hujjik765gt">
+  <link rel="mask-icon" href="/assets/safari-pinned-tab.svg?v=Hujjik765gt" color="#5bbad5">
+  <link rel="shortcut icon" href="/assets/favicon.ico?v=Hujjik765gt">
+  <meta name="msapplication-TileColor" content="#2d89ef">
+  <meta name="theme-color" content="#ffffff">
+
+  <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
+  <link href="https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic&subset=latin" rel="stylesheet">
+
+</head>
+<body>
+  <app-root></app-root>
+</body>
+</html>
diff --git a/src/index.html b/src/index.html.TC
similarity index 100%
rename from src/index.html
rename to src/index.html.TC
diff --git a/src/iqb-theme2.scss b/src/iqb-theme2.scss
new file mode 100644
index 0000000000000000000000000000000000000000..215f8b27c77f1f2d867bd7be5cd7a5ddf44db16b
--- /dev/null
+++ b/src/iqb-theme2.scss
@@ -0,0 +1,16 @@
+@import '~@angular/material/theming';
+@include mat-core();
+
+$iqb-primary: mat-palette($mat-cyan, 900);
+$iqb-accent: mat-palette($mat-light-green, A200);
+$iqb-app-theme: mat-light-theme($iqb-primary, $iqb-accent);
+@include angular-material-theme($iqb-app-theme);
+
+body {
+  overflow: hidden;
+  width: 100%;
+  height: 100%;
+  margin: 0;
+  font-family: "Orienta";
+  background: linear-gradient(to left, #003333, #045659, #0d7b84, #1aa2b2, #2acae5)
+}
diff --git a/src/polyfills.ts b/src/polyfills.ts
index 303ce7eb2bc7d19bc0670cc2e792fe5f67b56ece..32c599fd7e035be226e3c8dde2b019da139e6444 100644
--- a/src/polyfills.ts
+++ b/src/polyfills.ts
@@ -19,6 +19,7 @@
  */
 
 /** IE9, IE10 and IE11 requires all of the following polyfills. **/
+
 import 'core-js/es6/symbol';
 import 'core-js/es6/object';
 import 'core-js/es6/function';
@@ -42,6 +43,7 @@ import 'core-js/es6/reflect';
 // npm install git+https://github.com/jugglinmike/srcdoc-polyfill
 // import 'srcdoc-polyfill';
 
+
 /** Evergreen browsers require these. **/
 // Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove.
 import 'core-js/es7/reflect';
@@ -52,23 +54,29 @@ import 'core-js/es7/reflect';
  * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari.
  * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0).
  **/
+
 import 'web-animations-js';  // Run `npm install --save web-animations-js`.
 
+
 /**
  * By default, zone.js will patch all possible macroTask and DomEvents
  * user can disable parts of macroTask/DomEvents patch by setting following flags
  */
 
+
  (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
  (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
  (window as any).__zone_symbol__BLACK_LISTED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
 
+
  /*
  * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
  * with the following flag, it will bypass `zone.js` patch for IE/Edge
  */
+
 (window as any).__Zone_enable_cross_context_check = true;
 
+
 /***************************************************************************************************
  * Zone JS is required by default for Angular itself.
  */
@@ -79,3 +87,5 @@ import 'zone.js/dist/zone';  // Included with Angular CLI.
 /***************************************************************************************************
  * APPLICATION IMPORTS
  */
+
+import 'hammerjs';
diff --git a/src/styles.css.ADMIN b/src/styles.css.ADMIN
new file mode 100644
index 0000000000000000000000000000000000000000..a7578e00f336c912d31f0ff12604b768e84648b7
--- /dev/null
+++ b/src/styles.css.ADMIN
@@ -0,0 +1,39 @@
+/* orienta-regular - latin */
+@font-face {
+  font-family: 'Orienta';
+  font-style: normal;
+  font-weight: 400;
+  src: local('Orienta'), local('Orienta-Regular'),
+       url('assets/orienta-v5-latin-regular.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
+       url('assets/orienta-v5-latin-regular.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
+}
+
+.page-body {
+  overflow-x: auto;
+  position: absolute;
+  width: 100%;
+  top: 60px;
+  bottom: 0;
+}
+
+
+.spinner-container {
+  position: fixed;
+  z-index: 999;
+  height: 2em;
+  width: 2em;
+  overflow: show;
+  margin: auto;
+  top: 0;
+  left: 0;
+  bottom: 0;
+  right: 0;
+}
+
+.logo img {
+  width: 100px;
+}
+
+.error-msg {
+  color: brown;
+}
diff --git a/src/styles.css b/src/styles.css.TC
similarity index 100%
rename from src/styles.css
rename to src/styles.css.TC
diff --git a/src/tsconfig.app.json.ADMIN b/src/tsconfig.app.json.ADMIN
new file mode 100644
index 0000000000000000000000000000000000000000..8ea061ea1b88d9c0fa2e96ecc87dcfecbd182e80
--- /dev/null
+++ b/src/tsconfig.app.json.ADMIN
@@ -0,0 +1,11 @@
+{
+  "extends": "../tsconfig.json",
+  "compilerOptions": {
+    "outDir": "../out-tsc/app",
+    "types": []
+  },
+  "exclude": [
+    "src/test.ts",
+    "**/*.spec.ts"
+  ]
+}
diff --git a/src/tsconfig.app.json b/src/tsconfig.app.json.TC
similarity index 100%
rename from src/tsconfig.app.json
rename to src/tsconfig.app.json.TC
diff --git a/src/tsconfig.spec.json.ADMIN b/src/tsconfig.spec.json.ADMIN
new file mode 100644
index 0000000000000000000000000000000000000000..de7733630eb224b246854a20934f792051926e8f
--- /dev/null
+++ b/src/tsconfig.spec.json.ADMIN
@@ -0,0 +1,18 @@
+{
+  "extends": "../tsconfig.json",
+  "compilerOptions": {
+    "outDir": "../out-tsc/spec",
+    "types": [
+      "jasmine",
+      "node"
+    ]
+  },
+  "files": [
+    "test.ts",
+    "polyfills.ts"
+  ],
+  "include": [
+    "**/*.spec.ts",
+    "**/*.d.ts"
+  ]
+}
diff --git a/src/tsconfig.spec.json b/src/tsconfig.spec.json.TC
similarity index 100%
rename from src/tsconfig.spec.json
rename to src/tsconfig.spec.json.TC
diff --git a/src/tslint.json.ADMIN b/src/tslint.json.ADMIN
new file mode 100644
index 0000000000000000000000000000000000000000..52e2c1a5a74ce268bec92d34cd3bca751624adb3
--- /dev/null
+++ b/src/tslint.json.ADMIN
@@ -0,0 +1,17 @@
+{
+    "extends": "../tslint.json",
+    "rules": {
+        "directive-selector": [
+            true,
+            "attribute",
+            "app",
+            "camelCase"
+        ],
+        "component-selector": [
+            true,
+            "element",
+            "app",
+            "kebab-case"
+        ]
+    }
+}
diff --git a/src/tslint.json b/src/tslint.json.TC
similarity index 100%
rename from src/tslint.json
rename to src/tslint.json.TC
diff --git a/testcenter-iqb-ng.iml b/testcenter-iqb-ng.iml
new file mode 100644
index 0000000000000000000000000000000000000000..da8860ce3875d8d8e4c38f7707a847e8a2fd4a4f
--- /dev/null
+++ b/testcenter-iqb-ng.iml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="WEB_MODULE" version="4">
+  <component name="NewModuleRootManager" inherit-compiler-output="true">
+    <exclude-output />
+    <content url="file://$MODULE_DIR$">
+      <excludeFolder url="file://$MODULE_DIR$/dist" />
+      <excludeFolder url="file://$MODULE_DIR$/tmp" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+  </component>
+</module>
\ No newline at end of file
diff --git a/tsconfig.json.ADMIN b/tsconfig.json.ADMIN
new file mode 100644
index 0000000000000000000000000000000000000000..d47546887c691397afbe24aea3e0d2fbd5ccefc1
--- /dev/null
+++ b/tsconfig.json.ADMIN
@@ -0,0 +1,31 @@
+{
+  "compileOnSave": false,
+  "compilerOptions": {
+    "baseUrl": "./",
+    "downlevelIteration": true,
+    "importHelpers": true,
+    "module": "esnext",
+    "outDir": "./dist/out-tsc",
+    "sourceMap": true,
+    "declaration": false,
+    "moduleResolution": "node",
+    "emitDecoratorMetadata": true,
+    "experimentalDecorators": true,
+    "target": "es2015",
+    "typeRoots": [
+      "node_modules/@types"
+    ],
+    "lib": [
+      "es2017",
+      "dom"
+    ],
+    "paths": {
+      "core-js/es7/reflect": [
+        "node_modules/core-js/proposals/reflect-metadata"
+      ],
+      "core-js/es6/reflect": [
+        "node_modules/core-js/proposals/reflect-metadata"
+      ]
+    }
+  }
+}
diff --git a/tsconfig.json b/tsconfig.json.TC
similarity index 100%
rename from tsconfig.json
rename to tsconfig.json.TC
diff --git a/tslint.json.ADMIN b/tslint.json.ADMIN
new file mode 100644
index 0000000000000000000000000000000000000000..2da62c3d7286e9004679bfa18f9df48cb40471be
--- /dev/null
+++ b/tslint.json.ADMIN
@@ -0,0 +1,135 @@
+{
+  "rulesDirectory": [
+    "node_modules/codelyzer",
+    "node_modules/tslint"
+  ],
+  "rules": {
+    "arrow-return-shorthand": true,
+    "callable-types": true,
+    "class-name": true,
+    "comment-format": [
+      true,
+      "check-space"
+    ],
+    "curly": true,
+    "deprecation": {
+      "severity": "warn"
+    },
+    "eofline": true,
+    "forin": true,
+    "import-blacklist": [
+      true,
+      "rxjs/Rx"
+    ],
+    "import-spacing": true,
+    "indent": [
+      true,
+      "spaces"
+    ],
+    "interface-over-type-literal": true,
+    "label-position": true,
+    "max-line-length": [
+      true,
+      140
+    ],
+    "member-access": false,
+    "member-ordering": [
+      true,
+      {
+        "order": [
+          "static-field",
+          "instance-field",
+          "static-method",
+          "instance-method"
+        ]
+      }
+    ],
+    "no-arg": true,
+    "no-bitwise": true,
+    "no-console": [
+      true,
+      "debug",
+      "info",
+      "time",
+      "timeEnd",
+      "trace"
+    ],
+    "no-construct": true,
+    "no-debugger": true,
+    "no-duplicate-super": true,
+    "no-empty": false,
+    "no-empty-interface": true,
+    "no-eval": true,
+    "no-inferrable-types": [
+      true,
+      "ignore-params"
+    ],
+    "no-misused-new": true,
+    "no-non-null-assertion": true,
+    "no-shadowed-variable": true,
+    "no-string-literal": false,
+    "no-string-throw": true,
+    "no-switch-case-fall-through": true,
+    "no-trailing-whitespace": true,
+    "no-unnecessary-initializer": true,
+    "no-unused-expression": true,
+    "no-use-before-declare": true,
+    "no-var-keyword": true,
+    "object-literal-sort-keys": false,
+    "one-line": [
+      true,
+      "check-open-brace",
+      "check-catch",
+      "check-else",
+      "check-whitespace"
+    ],
+    "prefer-const": true,
+    "quotemark": [
+      true,
+      "single"
+    ],
+    "radix": true,
+    "rxjs-collapse-imports": true,
+    "rxjs-pipeable-operators-only": true,
+    "rxjs-no-static-observable-methods": true,
+    "rxjs-proper-imports": true,
+    "semicolon": [
+      true,
+      "always"
+    ],
+    "triple-equals": [
+      true,
+      "allow-null-check"
+    ],
+    "typedef-whitespace": [
+      true,
+      {
+        "call-signature": "nospace",
+        "index-signature": "nospace",
+        "parameter": "nospace",
+        "property-declaration": "nospace",
+        "variable-declaration": "nospace"
+      }
+    ],
+    "unified-signatures": true,
+    "variable-name": false,
+    "whitespace": [
+      true,
+      "check-branch",
+      "check-decl",
+      "check-operator",
+      "check-separator",
+      "check-type"
+    ],
+    "no-output-on-prefix": true,
+    "no-inputs-metadata-property": true,
+    "no-outputs-metadata-property": true,
+    "no-host-metadata-property": true,
+    "no-input-rename": true,
+    "no-output-rename": true,
+    "use-lifecycle-interface": true,
+    "use-pipe-transform-interface": true,
+    "component-class-suffix": true,
+    "directive-class-suffix": true
+  }
+}
diff --git a/tslint.json b/tslint.json.TC
similarity index 100%
rename from tslint.json
rename to tslint.json.TC